1    package org.xwt.mips;
2    import java.io.*;
3    
4    public class ELF {
5    
6        private DataInput fd;
7        private Object image;
8        private void seek(long l) throws IOException {
9            if (image instanceof RandomAccessFile) {
10               ((RandomAccessFile)image).seek(l);
11           } else if (image instanceof byte[]) {
12               ByteArrayInputStream bais = new ByteArrayInputStream((byte[])image);
13               bais.skip(l);
14               fd = new DataInputStream(bais);
15           }
16       }
17       
18       public ELFHeader header;
19       public PHeader[] pheaders;
20       public SHeader[] sheaders;
21       
22       private byte[] stringTable;
23       
24       private boolean sectionReaderActive;
25       
26       public class ELFHeader {
27           byte klass;
28           byte data;
29           byte osabi;
30           byte abiversion;
31           
32           public static final short ET_EXEC = 2;
33           public short type;
34           public static final short EM_MIPS = 8;
35           public short machine;
36           public int version;
37           public int entry;
38           public int phoff;
39           public int shoff;
40           public int flags;
41           public short ehsize;
42           public short phentsize;
43           public short phnum;
44           public short shentsize;
45           public short shnum;
46           public short shstrndx;
47   
48           private static final int ELF_MAGIC = 0x7f454c46; // '\177', 'E', 'L', 'F'
49           ELFHeader() throws IOException {
50               if(fd.readInt() != ELF_MAGIC) throw new ELFException("Bad Magic (is: " );
51               klass = fd.readByte();
52               data = fd.readByte();
53               fd.skipBytes(1); // version
54               osabi = fd.readByte();
55               abiversion = fd.readByte();
56               fd.skipBytes(7);
57               type = fd.readShort();
58               machine = fd.readShort();
59               version = fd.readInt();
60               entry = fd.readInt();
61               phoff = fd.readInt();
62               shoff = fd.readInt();
63               flags = fd.readInt();
64               ehsize = fd.readShort();
65               phentsize = fd.readShort();
66               phnum = fd.readShort();
67               shentsize = fd.readShort();
68               shnum = fd.readShort();
69               shstrndx = fd.readShort();
70           }
71       }
72       
73       public class PHeader {
74           public int type;
75           public int offset;
76           public int vaddr;
77           public int paddr;
78           public int filesz;
79           public int memsz;
80           public int flags;
81           public int align;
82           
83           public static final int PF_X = 0x1;
84           public static final int PF_W = 0x2;
85           public static final int PF_R = 0x4;
86           
87           public static final int PT_LOAD = 1;
88           
89           PHeader() throws IOException {
90               type = fd.readInt();
91               offset = fd.readInt();
92               vaddr = fd.readInt();
93               paddr = fd.readInt();
94               filesz = fd.readInt();
95               memsz = fd.readInt();
96               flags = fd.readInt();
97               align = fd.readInt();
98               if(filesz > memsz) throw new ELFException("ELF inconsistency: filesz > memsz");
99           }
100          
101          public boolean writable() { return (flags & PF_W) != 0; }
102          
103          public InputStream getInputStream() throws IOException {
104                  return new BufferedInputStream(new SectionInputStream(
105                          offset,offset+filesz));
106          }
107      }
108      
109      public class SHeader {
110          int nameidx;
111          public String name;
112          public int type;
113          public int flags;
114          public int addr;
115          public int offset;
116          public int size;
117          public int link;
118          public int info;
119          public int addralign;
120          public int entsize;
121          
122          public static final int SHT_SYMTAB = 2;
123          public static final int SHT_STRTAB = 3;
124          public static final int SHT_NOBITS = 8;
125          
126          SHeader() throws IOException {
127              nameidx = fd.readInt();
128              type = fd.readInt();
129              flags = fd.readInt();
130              addr = fd.readInt();
131              offset = fd.readInt();
132              size = fd.readInt();
133              link = fd.readInt();
134              info = fd.readInt();
135              addralign = fd.readInt();
136              entsize = fd.readInt();
137          }
138          
139          public InputStream getInputStream() throws IOException {
140                  return new BufferedInputStream(new SectionInputStream(
141                          offset, type == SHT_NOBITS ? 0 : offset+size));
142          }
143      }
144      
145      public ELF(Object img) throws IOException, ELFException {
146          if (img instanceof String) {
147              image = fd = new MyRandomAccessFile((String)img, "r");
148          } else {
149              image = img;
150          }
151          seek(0);
152          header = new ELFHeader();
153          pheaders = new PHeader[header.phnum];
154          for(int i=0;i<header.phnum;i++) {
155              seek(header.phoff+i*header.phentsize);
156              pheaders[i] = new PHeader();
157          }
158          sheaders = new SHeader[header.shnum];
159          for(int i=0;i<header.shnum;i++) {
160              seek(header.shoff+i*header.shentsize);
161              sheaders[i] = new SHeader();
162          }
163          if(header.shstrndx < 0 || header.shstrndx >= header.shnum) throw new ELFException("Bad shstrndx");
164          seek(sheaders[header.shstrndx].offset);
165          stringTable = new byte[sheaders[header.shstrndx].size];
166          fd.readFully(stringTable);
167          
168          for(int i=0;i<header.shnum;i++) {
169              SHeader s = sheaders[i];
170              s.name = getString(s.nameidx);
171          }
172      }
173      
174      private String getString(int off) { return getString(off,stringTable); }
175      private String getString(int off,byte[] strtab) {
176          StringBuffer sb = new StringBuffer();
177          while(off < strtab.length && strtab[off] != 0) sb.append((char)strtab[off++]);
178          return sb.toString();
179      }
180      
181      public SHeader sectionWithName(String name) {
182          for(int i=0;i<sheaders.length;i++)
183              if(sheaders[i].name.equals(name))
184                  return sheaders[i];
185          return null;
186      }
187      
188      public class ELFException extends IOException { ELFException(String s) { super(s); } }
189      
190      private class MyRandomAccessFile extends RandomAccessFile  {
191          MyRandomAccessFile(String f,String m) throws IOException { super(f,m); }
192      }
193      
194      private class SectionInputStream extends InputStream {
195          private int pos;
196          private int maxpos;
197          SectionInputStream(int start, int end) throws IOException {
198              if(sectionReaderActive)
199                  throw new IOException("Section reader already active");
200              sectionReaderActive = true;
201              pos = start;
202              seek(pos);
203              maxpos = end;
204          }
205          
206          private int bytesLeft() { return maxpos - pos; }
207          public int read() throws IOException { if(bytesLeft()==0) return -1; int b = fd.readByte(); if(b >= 0) pos++; return b; }
208          public int read(byte[] b, int off, int len) throws IOException {
209              fd.readFully(b,off,Math.min(len,bytesLeft())); return len;
210          }
211          public void close() { sectionReaderActive = false; }
212      }
213      
214      private Symtab _symtab;
215      public Symtab getSymtab() throws IOException {
216          if(_symtab != null) return _symtab;
217          
218          SHeader sh = sectionWithName(".symtab");
219          if(sh == null || sh.type != SHeader.SHT_SYMTAB) return null;
220          
221          SHeader sth = sectionWithName(".strtab");
222          if(sth == null || sth.type != SHeader.SHT_STRTAB) return null;
223          
224          byte[] strtab = new byte[sth.size];
225          DataInputStream dis = new DataInputStream(sth.getInputStream());
226          dis.readFully(strtab);
227          dis.close();
228          
229          return _symtab = new Symtab(sh.getInputStream(),sh.size,strtab);
230      }
231      
232      public class  Symtab {
233          public Symbol[] symbols;
234          
235          Symtab(InputStream is, int size, byte[] strtab) throws IOException {
236              DataInputStream dis = new DataInputStream(is);
237              int count = size/16;
238              symbols = new Symbol[count];
239              for(int i=0;i<count;i++) symbols[i] = new Symbol(dis,strtab);
240              dis.close();
241          }
242      }
243      
244      public class Symbol {
245          public String name;
246          public int addr;
247          public int size;
248          public byte info;
249          public byte type;
250          public byte other;
251          public SHeader sheader;
252          
253          public final static int STT_FUNC = 2;
254          
255          Symbol(DataInputStream dis, byte[] strtab) throws IOException {
256              name = getString(dis.readInt(),strtab);
257              addr = dis.readInt();
258              size = dis.readInt();
259              info = dis.readByte();
260              type = (byte)(info&0xf);
261              other = dis.readByte();
262              // FIXME: Find sheader entry
263              dis.readShort();
264          }
265      }
266      
267      private static String toHex(int n) { return "0x" + Long.toString(n & 0xffffffffL, 16); }
268      
269      public static void main(String[] args) throws IOException {
270          ELF elf = new ELF(args[0]);
271          System.out.println("Type: " + toHex(elf.header.type));
272          System.out.println("Machine: " + toHex(elf.header.machine));
273          System.out.println("Entry: " + toHex(elf.header.entry));
274          for(int i=0;i<elf.pheaders.length;i++) {
275              ELF.PHeader ph = elf.pheaders[i];
276              System.out.println("PHeader " + toHex(i));
277              System.out.println("\tOffset: " + ph.offset);
278              System.out.println("\tVaddr: " + toHex(ph.vaddr));
279              System.out.println("\tFile Size: " + ph.filesz);
280              System.out.println("\tMem Size: " + ph.memsz);
281          }
282          for(int i=0;i<elf.sheaders.length;i++) {
283              ELF.SHeader sh = elf.sheaders[i];
284              System.out.println("SHeader " + toHex(i));
285              System.out.println("\tName: " + sh.name);
286              System.out.println("\tOffset: " + sh.offset);
287              System.out.println("\tAddr: " + toHex(sh.addr));
288              System.out.println("\tSize: " + sh.size);
289              System.out.println("\tType: " + toHex(sh.type));
290          }
291          Symtab symtab = elf.getSymtab();
292      }
293  }
294