fixed more fixmes/features
[nestedvm.git] / src / org / ibex / nestedvm / util / ELF.java
1 package org.ibex.nestedvm.util;
2
3 import java.io.*;
4
5 public class ELF {
6     private Seekable data;
7     
8     public ELFIdent ident;
9     public ELFHeader header;
10     public PHeader[] pheaders;
11     public SHeader[] sheaders;
12     
13     private byte[] stringTable;
14     
15     private boolean sectionReaderActive;
16     
17     
18     private void readFully(byte[] buf) throws IOException {
19         int len = buf.length;
20         int pos = 0;
21         while(len > 0) {
22             int n = data.read(buf,pos,len);
23             if(n == -1) throw new IOException("EOF");
24             pos += n;
25             len -= n;
26         }
27     }
28     
29     private int readIntBE() throws IOException {
30         byte[] buf = new byte[4];
31         readFully(buf);
32         return ((buf[0]&0xff)<<24)|((buf[1]&0xff)<<16)|((buf[2]&0xff)<<8)|((buf[3]&0xff)<<0);
33     }
34     private int readInt() throws IOException {
35         int x = readIntBE();
36         if(ident!=null && ident.data == ELFIdent.ELFDATA2LSB) 
37             x = ((x<<24)&0xff000000) | ((x<<8)&0xff0000) | ((x>>>8)&0xff00) | ((x>>24)&0xff);
38         return x;
39     }
40     
41     private short readShortBE() throws IOException {
42         byte[] buf = new byte[2];
43         readFully(buf);
44         return (short)(((buf[0]&0xff)<<8)|((buf[1]&0xff)<<0));
45     }
46     private short readShort() throws IOException {
47         short x = readShortBE();
48         if(ident!=null && ident.data == ELFIdent.ELFDATA2LSB) 
49             x = (short)((((x<<8)&0xff00) | ((x>>8)&0xff))&0xffff);
50         return x;
51     }
52     
53     private byte readByte() throws IOException {
54         byte[] buf = new byte[1];
55         readFully(buf);
56         return buf[0];
57     }
58         
59     public class ELFIdent {
60         private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
61
62         public static final int ELFCLASSNONE = 0;
63         public static final int ELFCLASS32 = 1;
64         public static final int ELFCLASS64 = 2;
65         public byte klass;
66
67
68         public static final int ELFDATANONE = 0;
69         public static final int ELFDATA2LSB = 1;
70         public static final int ELFDATA2MSB = 2;        
71         public byte data;
72         public byte osabi;
73         public byte abiversion;
74                 
75         ELFIdent() throws IOException {
76             if(readIntBE() != ELF_MAGIC) throw new ELFException("Bad Magic");
77             
78             klass = readByte();
79             if(klass != ELFCLASS32) throw new ELFException("org.ibex.nestedvm.util.ELF does not suport 64-bit binaries");
80             
81             data = readByte();
82             if(data != ELFDATA2LSB && data != ELFDATA2MSB) throw new ELFException("Unknown byte order");
83             
84             readByte(); // version
85             osabi = readByte();
86             abiversion = readByte();
87             for(int i=0;i<7;i++) readByte(); // padding
88         }
89     }
90     
91     public class ELFHeader {
92         public static final short ET_EXEC = 2;
93         public short type;
94         
95         public static final short EM_MIPS = 8;
96         public short machine;
97         
98         public int version;
99         public int entry;
100         public int phoff;
101         public int shoff;
102         public int flags;
103         public short ehsize;
104         public short phentsize;
105         public short phnum;
106         public short shentsize;
107         public short shnum;
108         public short shstrndx;
109
110         ELFHeader() throws IOException {
111             type = readShort();
112             machine = readShort();
113             version = readInt();
114             if(version != 1) throw new ELFException("version != 1");
115             entry = readInt();
116             phoff = readInt();
117             shoff = readInt();
118             flags = readInt();
119             ehsize = readShort();
120             phentsize = readShort();
121             phnum = readShort();
122             shentsize = readShort();
123             shnum = readShort();
124             shstrndx = readShort();
125         }
126     }
127     
128     public class PHeader {
129         public int type;
130         public int offset;
131         public int vaddr;
132         public int paddr;
133         public int filesz;
134         public int memsz;
135         public int flags;
136         public int align;
137         
138         public static final int PF_X = 0x1;
139         public static final int PF_W = 0x2;
140         public static final int PF_R = 0x4;
141         
142         public static final int PT_LOAD = 1;
143         
144         PHeader() throws IOException {
145             type = readInt();
146             offset = readInt();
147             vaddr = readInt();
148             paddr = readInt();
149             filesz = readInt();
150             memsz = readInt();
151             flags = readInt();
152             align = readInt();
153             if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz (" + toHex(filesz) + " > " + toHex(memsz) + ")");
154         }
155         
156         public boolean writable() { return (flags & PF_W) != 0; }
157         
158         public InputStream getInputStream() throws IOException {
159             return new BufferedInputStream(new SectionInputStream(
160                 offset,offset+filesz));
161         }
162     }
163     
164     public class SHeader {
165         int nameidx;
166         public String name;
167         public int type;
168         public int flags;
169         public int addr;
170         public int offset;
171         public int size;
172         public int link;
173         public int info;
174         public int addralign;
175         public int entsize;
176         
177         public static final int SHT_SYMTAB = 2;
178         public static final int SHT_STRTAB = 3;
179         public static final int SHT_NOBITS = 8;
180         
181         SHeader() throws IOException {
182             nameidx = readInt();
183             type = readInt();
184             flags = readInt();
185             addr = readInt();
186             offset = readInt();
187             size = readInt();
188             link = readInt();
189             info = readInt();
190             addralign = readInt();
191             entsize = readInt();
192         }
193         
194         public InputStream getInputStream() throws IOException {
195             return new BufferedInputStream(new SectionInputStream(
196                 offset, type == SHT_NOBITS ? 0 : offset+size));
197         }
198         
199         public boolean isText() { return name.equals(".text"); }
200         public boolean isData() { return name.equals(".data") || name.equals(".sdata") || name.equals(".rodata") || name.equals(".ctors") || name.equals(".dtors"); }
201         public boolean isBSS() { return name.equals(".bss") || name.equals(".sbss"); }
202     }
203     
204     public ELF(String file) throws IOException, ELFException { this(new Seekable.File(file,false)); }
205     public ELF(Seekable data) throws IOException, ELFException {
206         this.data = data;
207         ident = new ELFIdent();
208         header = new ELFHeader();
209         pheaders = new PHeader[header.phnum];
210         for(int i=0;i<header.phnum;i++) {
211             data.seek(header.phoff+i*header.phentsize);
212             pheaders[i] = new PHeader();
213         }
214         sheaders = new SHeader[header.shnum];
215         for(int i=0;i<header.shnum;i++) {
216             data.seek(header.shoff+i*header.shentsize);
217             sheaders[i] = new SHeader();
218         }
219         if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
220         data.seek(sheaders[header.shstrndx].offset);
221         stringTable = new byte[sheaders[header.shstrndx].size];
222         readFully(stringTable);
223         
224         for(int i=0;i<header.shnum;i++) {
225             SHeader s = sheaders[i];
226             s.name = getString(s.nameidx);
227         }
228     }
229     
230     private String getString(int off) { return getString(off,stringTable); }
231     private String getString(int off,byte[] strtab) {
232         StringBuffer sb = new StringBuffer();
233         if(off < 0 || off >= strtab.length) return "<invalid strtab entry>";
234         while(off >= 0 && off < strtab.length && strtab[off] != 0) sb.append((char)strtab[off++]);
235         return sb.toString();
236     }
237     
238     public SHeader sectionWithName(String name) {
239         for(int i=0;i<sheaders.length;i++)
240             if(sheaders[i].name.equals(name))
241                 return sheaders[i];
242         return null;
243     }
244     
245     public class ELFException extends IOException { ELFException(String s) { super(s); } }
246     
247     private class SectionInputStream extends InputStream {
248         private int pos;
249         private int maxpos;
250         SectionInputStream(int start, int end) throws IOException {
251             if(sectionReaderActive)
252                 throw new IOException("Section reader already active");
253             sectionReaderActive = true;
254             pos = start;
255             data.seek(pos);
256             maxpos = end;
257         }
258         
259         private int bytesLeft() { return maxpos - pos; }
260         public int read() throws IOException {
261             byte[] buf = new byte[1];
262             return read(buf,0,1) == -1 ? -1 : (buf[0]&0xff);
263         }
264         public int read(byte[] b, int off, int len) throws IOException {
265             int n = data.read(b,off,Math.min(len,bytesLeft())); if(n > 0) pos += n; return n;
266         }
267         public void close() { sectionReaderActive = false; }
268     }
269     
270     private Symtab _symtab;
271     public Symtab getSymtab() throws IOException {
272         if(_symtab != null) return _symtab;
273         
274         if(sectionReaderActive) throw new ELFException("Can't read the symtab while a section reader is active");
275         
276         SHeader sh = sectionWithName(".symtab");
277         if(sh == null || sh.type != SHeader.SHT_SYMTAB) return null;
278         
279         SHeader sth = sectionWithName(".strtab");
280         if(sth == null || sth.type != SHeader.SHT_STRTAB) return null;
281         
282         byte[] strtab = new byte[sth.size];
283         DataInputStream dis = new DataInputStream(sth.getInputStream());
284         dis.readFully(strtab);
285         dis.close();
286         
287         return _symtab = new Symtab(sh.offset, sh.size,strtab);
288     }
289     
290     public class  Symtab {
291         public Symbol[] symbols;
292         
293         Symtab(int off, int size, byte[] strtab) throws IOException {
294             data.seek(off);
295             int count = size/16;
296             symbols = new Symbol[count];
297             for(int i=0;i<count;i++) symbols[i] = new Symbol(strtab);
298         }
299         
300         public Symbol getSymbol(String name) {
301             Symbol sym = null;
302             for(int i=0;i<symbols.length;i++) {
303                 if(symbols[i].name.equals(name)) {
304                     if(sym == null)
305                         sym = symbols[i];
306                     else
307                         System.err.println("WARNING: Multiple symbol matches for " + name);
308                 }
309             }
310             return sym;
311         }
312         
313         public Symbol getGlobalSymbol(String name) {
314             for(int i=0;i<symbols.length;i++) 
315                 if(symbols[i].binding == Symbol.STB_GLOBAL && symbols[i].name.equals(name))
316                     return symbols[i];
317             return null;
318         }
319     }
320     
321     public class Symbol {
322         public String name;
323         public int addr;
324         public int size;
325         public byte info;
326         public byte type;
327         public byte binding;
328         public byte other;
329         public short shndx;
330         public SHeader sheader;
331         
332         public final static int STT_FUNC = 2;
333         public final static int STB_GLOBAL = 1;
334         
335         Symbol(byte[] strtab) throws IOException {
336             name = getString(readInt(),strtab);
337             addr = readInt();
338             size = readInt();
339             info = readByte();
340             type = (byte)(info&0xf);
341             binding = (byte)(info>>4);
342             other = readByte();
343             shndx = readShort();
344         }
345     }
346     
347     private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
348     
349     public static void main(String[] args) throws IOException {
350         ELF elf = new ELF(new Seekable.InputStream(new FileInputStream(args[0])));
351         System.out.println("Type: " + toHex(elf.header.type));
352         System.out.println("Machine: " + toHex(elf.header.machine));
353         System.out.println("Entry: " + toHex(elf.header.entry));
354         for(int i=0;i<elf.pheaders.length;i++) {
355             ELF.PHeader ph = elf.pheaders[i];
356             System.out.println("PHeader " + toHex(i));
357             System.out.println("\tOffset: " + ph.offset);
358             System.out.println("\tVaddr: " + toHex(ph.vaddr));
359             System.out.println("\tFile Size: " + ph.filesz);
360             System.out.println("\tMem Size: " + ph.memsz);
361         }
362         for(int i=0;i<elf.sheaders.length;i++) {
363             ELF.SHeader sh = elf.sheaders[i];
364             System.out.println("SHeader " + toHex(i));
365             System.out.println("\tName: " + sh.name);
366             System.out.println("\tOffset: " + sh.offset);
367             System.out.println("\tAddr: " + toHex(sh.addr));
368             System.out.println("\tSize: " + sh.size);
369             System.out.println("\tType: " + toHex(sh.type));
370         }
371         Symtab symtab = elf.getSymtab();
372         if(symtab != null) {
373             System.out.println("Symbol table:");
374             for(int i=0;i<symtab.symbols.length;i++)
375                 System.out.println("\t" + symtab.symbols[i].name + " -> " + toHex(symtab.symbols[i].addr));
376         } else {
377             System.out.println("Symbol table: None");
378         }
379     }
380 }