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.
5 package org.ibex.nestedvm.util;
10 private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
12 public static final int ELFCLASSNONE = 0;
13 public static final int ELFCLASS32 = 1;
14 public static final int ELFCLASS64 = 2;
16 public static final int ELFDATANONE = 0;
17 public static final int ELFDATA2LSB = 1;
18 public static final int ELFDATA2MSB = 2;
20 public static final int SHT_SYMTAB = 2;
21 public static final int SHT_STRTAB = 3;
22 public static final int SHT_NOBITS = 8;
24 public static final int SHF_WRITE = 1;
25 public static final int SHF_ALLOC = 2;
26 public static final int SHF_EXECINSTR = 4;
28 public static final int PF_X = 0x1;
29 public static final int PF_W = 0x2;
30 public static final int PF_R = 0x4;
32 public static final int PT_LOAD = 1;
34 public static final short ET_EXEC = 2;
35 public static final short EM_MIPS = 8;
38 private Seekable data;
40 public ELFIdent ident;
41 public ELFHeader header;
42 public PHeader[] pheaders;
43 public SHeader[] sheaders;
45 private byte[] stringTable;
47 private boolean sectionReaderActive;
50 private void readFully(byte[] buf) throws IOException {
54 int n = data.read(buf,pos,len);
55 if(n == -1) throw new IOException("EOF");
61 private int readIntBE() throws IOException {
62 byte[] buf = new byte[4];
64 return ((buf[0]&0xff)<<24)|((buf[1]&0xff)<<16)|((buf[2]&0xff)<<8)|((buf[3]&0xff)<<0);
66 private int readInt() throws IOException {
68 if(ident!=null && ident.data == ELFDATA2LSB)
69 x = ((x<<24)&0xff000000) | ((x<<8)&0xff0000) | ((x>>>8)&0xff00) | ((x>>24)&0xff);
73 private short readShortBE() throws IOException {
74 byte[] buf = new byte[2];
76 return (short)(((buf[0]&0xff)<<8)|((buf[1]&0xff)<<0));
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);
85 private byte readByte() throws IOException {
86 byte[] buf = new byte[1];
91 public class ELFIdent {
95 public byte abiversion;
97 ELFIdent() throws IOException {
98 if(readIntBE() != ELF_MAGIC) throw new ELFException("Bad Magic");
101 if(klass != ELFCLASS32) throw new ELFException("org.ibex.nestedvm.util.ELF does not suport 64-bit binaries");
104 if(data != ELFDATA2LSB && data != ELFDATA2MSB) throw new ELFException("Unknown byte order");
106 readByte(); // version
108 abiversion = readByte();
109 for(int i=0;i<7;i++) readByte(); // padding
113 public class ELFHeader {
115 public short machine;
122 public short phentsize;
124 public short shentsize;
126 public short shstrndx;
128 ELFHeader() throws IOException {
130 machine = readShort();
132 if(version != 1) throw new ELFException("version != 1");
137 ehsize = readShort();
138 phentsize = readShort();
140 shentsize = readShort();
142 shstrndx = readShort();
146 public class PHeader {
156 PHeader() throws IOException {
165 if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz (" + toHex(filesz) + " > " + toHex(memsz) + ")");
168 public boolean writable() { return (flags & PF_W) != 0; }
170 public InputStream getInputStream() throws IOException {
171 return new BufferedInputStream(new SectionInputStream(
172 offset,offset+filesz));
176 public class SHeader {
186 public int addralign;
189 SHeader() throws IOException {
198 addralign = readInt();
202 public InputStream getInputStream() throws IOException {
203 return new BufferedInputStream(new SectionInputStream(
204 offset, type == SHT_NOBITS ? 0 : offset+size));
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"); }
212 public ELF(String file) throws IOException, ELFException { this(new Seekable.File(file,false)); }
213 public ELF(Seekable data) throws IOException, ELFException {
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();
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();
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);
232 for(int i=0;i<header.shnum;i++) {
233 SHeader s = sheaders[i];
234 s.name = getString(s.nameidx);
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();
246 public SHeader sectionWithName(String name) {
247 for(int i=0;i<sheaders.length;i++)
248 if(sheaders[i].name.equals(name))
253 public class ELFException extends IOException { ELFException(String s) { super(s); } }
255 private class SectionInputStream extends InputStream {
258 SectionInputStream(int start, int end) throws IOException {
259 if(sectionReaderActive)
260 throw new IOException("Section reader already active");
261 sectionReaderActive = true;
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);
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;
275 public void close() { sectionReaderActive = false; }
278 private Symtab _symtab;
279 public Symtab getSymtab() throws IOException {
280 if(_symtab != null) return _symtab;
282 if(sectionReaderActive) throw new ELFException("Can't read the symtab while a section reader is active");
284 SHeader sh = sectionWithName(".symtab");
285 if(sh == null || sh.type != SHT_SYMTAB) return null;
287 SHeader sth = sectionWithName(".strtab");
288 if(sth == null || sth.type != SHT_STRTAB) return null;
290 byte[] strtab = new byte[sth.size];
291 DataInputStream dis = new DataInputStream(sth.getInputStream());
292 dis.readFully(strtab);
295 return _symtab = new Symtab(sh.offset, sh.size,strtab);
298 public class Symtab {
299 public Symbol[] symbols;
301 Symtab(int off, int size, byte[] strtab) throws IOException {
304 symbols = new Symbol[count];
305 for(int i=0;i<count;i++) symbols[i] = new Symbol(strtab);
308 public Symbol getSymbol(String name) {
310 for(int i=0;i<symbols.length;i++) {
311 if(symbols[i].name.equals(name)) {
315 System.err.println("WARNING: Multiple symbol matches for " + name);
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))
329 public class Symbol {
338 public SHeader sheader;
340 public final static int STT_FUNC = 2;
341 public final static int STB_GLOBAL = 1;
343 Symbol(byte[] strtab) throws IOException {
344 name = getString(readInt(),strtab);
348 type = (byte)(info&0xf);
349 binding = (byte)(info>>4);
355 private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
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);
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));
379 Symtab symtab = elf.getSymtab();
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));
385 System.out.println("Symbol table: None");