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