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