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