12821f062265586b37241dea757a51550d33876d
[org.ibex.core.git] / src / org / xwt / mips / ELF.java
1 package org.xwt.mips;
2 import java.io.*;
3
4 public class ELF {
5
6     private DataInput fd;
7     private Object image;
8     private void seek(long l) throws IOException {
9         if (image instanceof RandomAccessFile) {
10             ((RandomAccessFile)image).seek(l);
11         } else if (image instanceof byte[]) {
12             ByteArrayInputStream bais = new ByteArrayInputStream((byte[])image);
13             bais.skip(l);
14             fd = new DataInputStream(bais);
15         }
16     }
17     
18     public ELFHeader header;
19     public PHeader[] pheaders;
20     public SHeader[] sheaders;
21     
22     private byte[] stringTable;
23     
24     private boolean sectionReaderActive;
25     
26     public class ELFHeader {
27         byte klass;
28         byte data;
29         byte osabi;
30         byte abiversion;
31         
32         public static final short ET_EXEC = 2;
33         public short type;
34         public static final short EM_MIPS = 8;
35         public short machine;
36         public int version;
37         public int entry;
38         public int phoff;
39         public int shoff;
40         public int flags;
41         public short ehsize;
42         public short phentsize;
43         public short phnum;
44         public short shentsize;
45         public short shnum;
46         public short shstrndx;
47
48         private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
49         ELFHeader() throws IOException {
50             if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
51             klass = fd.readByte();
52             data = fd.readByte();
53             fd.skipBytes(1); // version
54             osabi = fd.readByte();
55             abiversion = fd.readByte();
56             fd.skipBytes(7);
57             type = fd.readShort();
58             machine = fd.readShort();
59             version = fd.readInt();
60             entry = fd.readInt();
61             phoff = fd.readInt();
62             shoff = fd.readInt();
63             flags = fd.readInt();
64             ehsize = fd.readShort();
65             phentsize = fd.readShort();
66             phnum = fd.readShort();
67             shentsize = fd.readShort();
68             shnum = fd.readShort();
69             shstrndx = fd.readShort();
70         }
71     }
72     
73     public class PHeader {
74         public int type;
75         public int offset;
76         public int vaddr;
77         public int paddr;
78         public int filesz;
79         public int memsz;
80         public int flags;
81         public int align;
82         
83         public static final int PF_X = 0x1;
84         public static final int PF_W = 0x2;
85         public static final int PF_R = 0x4;
86         
87         public static final int PT_LOAD = 1;
88         
89         PHeader() throws IOException {
90             type = fd.readInt();
91             offset = fd.readInt();
92             vaddr = fd.readInt();
93             paddr = fd.readInt();
94             filesz = fd.readInt();
95             memsz = fd.readInt();
96             flags = fd.readInt();
97             align = fd.readInt();
98             if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
99         }
100         
101         public boolean writable() { return (flags & PF_W) != 0; }
102         
103         public InputStream getInputStream() throws IOException {
104                 return new BufferedInputStream(new SectionInputStream(
105                         offset,offset+filesz));
106         }
107     }
108     
109     public class SHeader {
110         int nameidx;
111         public String name;
112         public int type;
113         public int flags;
114         public int addr;
115         public int offset;
116         public int size;
117         public int link;
118         public int info;
119         public int addralign;
120         public int entsize;
121         
122         public static final int SHT_SYMTAB = 2;
123         public static final int SHT_STRTAB = 3;
124         public static final int SHT_NOBITS = 8;
125         
126         SHeader() throws IOException {
127             nameidx = fd.readInt();
128             type = fd.readInt();
129             flags = fd.readInt();
130             addr = fd.readInt();
131             offset = fd.readInt();
132             size = fd.readInt();
133             link = fd.readInt();
134             info = fd.readInt();
135             addralign = fd.readInt();
136             entsize = fd.readInt();
137         }
138         
139         public InputStream getInputStream() throws IOException {
140                 return new BufferedInputStream(new SectionInputStream(
141                         offset, type == SHT_NOBITS ? 0 : offset+size));
142         }
143     }
144     
145     public ELF(Object img) throws IOException, ELFException {
146         if (img instanceof String) image = new MyRandomAccessFile((String)img,"r");
147         image = img;
148         seek(0);
149         header = new ELFHeader();
150         pheaders = new PHeader[header.phnum];
151         for(int i=0;i<header.phnum;i++) {
152             seek(header.phoff+i*header.phentsize);
153             pheaders[i] = new PHeader();
154         }
155         sheaders = new SHeader[header.shnum];
156         for(int i=0;i<header.shnum;i++) {
157             seek(header.shoff+i*header.shentsize);
158             sheaders[i] = new SHeader();
159         }
160         if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
161         seek(sheaders[header.shstrndx].offset);
162         stringTable = new byte[sheaders[header.shstrndx].size];
163         fd.readFully(stringTable);
164         
165         for(int i=0;i<header.shnum;i++) {
166             SHeader s = sheaders[i];
167             s.name = getString(s.nameidx);
168         }
169     }
170     
171     private String getString(int off) { return getString(off,stringTable); }
172     private String getString(int off,byte[] strtab) {
173         StringBuffer sb = new StringBuffer();
174         while(off < strtab.length && strtab[off] != 0) sb.append((char)strtab[off++]);
175         return sb.toString();
176     }
177     
178     public SHeader sectionWithName(String name) {
179         for(int i=0;i<sheaders.length;i++)
180             if(sheaders[i].name.equals(name))
181                 return sheaders[i];
182         return null;
183     }
184     
185     public class ELFException extends IOException { ELFException(String s) { super(s); } }
186     
187     private class MyRandomAccessFile extends RandomAccessFile  {
188         MyRandomAccessFile(String f,String m) throws FileNotFoundException { super(f,m); }
189     }
190     
191     private class SectionInputStream extends InputStream {
192         private int pos;
193         private int maxpos;
194         SectionInputStream(int start, int end) throws IOException {
195             if(sectionReaderActive)
196                 throw new IOException("Section reader already active");
197             sectionReaderActive = true;
198             pos = start;
199             seek(pos);
200             maxpos = end;
201         }
202         
203         private int bytesLeft() { return maxpos - pos; }
204         public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.readByte(); if(b >= 0) pos++; return b; }
205         public int read(byte[] b, int off, int len) throws IOException {
206             fd.readFully(b,off,Math.min(len,bytesLeft())); return len;
207         }
208         public void close() { sectionReaderActive = false; }
209     }
210     
211     private Symtab _symtab;
212     public Symtab getSymtab() throws IOException {
213         if(_symtab != null) return _symtab;
214         
215         SHeader sh = sectionWithName(".symtab");
216         if(sh == null || sh.type != SHeader.SHT_SYMTAB) return null;
217         
218         SHeader sth = sectionWithName(".strtab");
219         if(sth == null || sth.type != SHeader.SHT_STRTAB) return null;
220         
221         byte[] strtab = new byte[sth.size];
222         DataInputStream dis = new DataInputStream(sth.getInputStream());
223         dis.readFully(strtab);
224         dis.close();
225         
226         return _symtab = new Symtab(sh.getInputStream(),sh.size,strtab);
227     }
228     
229     public class  Symtab {
230         public Symbol[] symbols;
231         
232         Symtab(InputStream is, int size, byte[] strtab) throws IOException {
233             DataInputStream dis = new DataInputStream(is);
234             int count = size/16;
235             symbols = new Symbol[count];
236             for(int i=0;i<count;i++) symbols[i] = new Symbol(dis,strtab);
237             dis.close();
238         }
239     }
240     
241     public class Symbol {
242         public String name;
243         public int addr;
244         public int size;
245         public byte info;
246         public byte type;
247         public byte other;
248         public SHeader sheader;
249         
250         public final static int STT_FUNC = 2;
251         
252         Symbol(DataInputStream dis, byte[] strtab) throws IOException {
253             name = getString(dis.readInt(),strtab);
254             addr = dis.readInt();
255             size = dis.readInt();
256             info = dis.readByte();
257             type = (byte)(info&0xf);
258             other = dis.readByte();
259             // FIXME: Find sheader entry
260             dis.readShort();
261         }
262     }
263     
264     private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
265     
266     public static void main(String[] args) throws IOException {
267         ELF elf = new ELF(args[0]);
268         System.out.println("Type: " + toHex(elf.header.type));
269         System.out.println("Machine: " + toHex(elf.header.machine));
270         System.out.println("Entry: " + toHex(elf.header.entry));
271         for(int i=0;i<elf.pheaders.length;i++) {
272             ELF.PHeader ph = elf.pheaders[i];
273             System.out.println("PHeader " + toHex(i));
274             System.out.println("\tOffset: " + ph.offset);
275             System.out.println("\tVaddr: " + toHex(ph.vaddr));
276             System.out.println("\tFile Size: " + ph.filesz);
277             System.out.println("\tMem Size: " + ph.memsz);
278         }
279         for(int i=0;i<elf.sheaders.length;i++) {
280             ELF.SHeader sh = elf.sheaders[i];
281             System.out.println("SHeader " + toHex(i));
282             System.out.println("\tName: " + sh.name);
283             System.out.println("\tOffset: " + sh.offset);
284             System.out.println("\tAddr: " + toHex(sh.addr));
285             System.out.println("\tSize: " + sh.size);
286             System.out.println("\tType: " + toHex(sh.type));
287         }
288         Symtab symtab = elf.getSymtab();
289     }
290 }