1 #!/usr/bin/env python 2 3 import struct 4 import sys 5 import StringIO 6 7 import common_dump 8 9 class Reader: 10 def __init__(self, path): 11 if path == "-": 12 # Snarf all the data so we can seek. 13 self.file = StringIO.StringIO(sys.stdin.read()) 14 else: 15 self.file = open(path, "rb") 16 self.isLSB = None 17 self.is64Bit = None 18 self.isN64 = False 19 20 def seek(self, pos): 21 self.file.seek(pos) 22 23 def read(self, N): 24 data = self.file.read(N) 25 if len(data) != N: 26 raise ValueError, "Out of data!" 27 return data 28 29 def read8(self): 30 return (ord(self.read(1)), 8) 31 32 def read16(self): 33 return (struct.unpack('><'[self.isLSB] + 'H', self.read(2))[0], 16) 34 35 def read32(self): 36 return (struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0], 32) 37 38 def read64(self): 39 return (struct.unpack('><'[self.isLSB] + 'Q', self.read(8))[0], 64) 40 41 def readWord(self): 42 if self.is64Bit: 43 return self.read64() 44 else: 45 return self.read32() 46 47 class StringTable: 48 def __init__(self, strings): 49 self.string_table = strings 50 51 def __getitem__(self, index): 52 end = self.string_table.index('\x00', index) 53 return self.string_table[index:end] 54 55 class ProgramHeader: 56 def __init__(self, f): 57 self.p_type = f.read32() 58 if f.is64Bit: 59 self.p_flags = f.read32() 60 self.p_offset = f.readWord() 61 self.p_vaddr = f.readWord() 62 self.p_paddr = f.readWord() 63 self.p_filesz = f.readWord() 64 self.p_memsz = f.readWord() 65 if not f.is64Bit: 66 self.p_flags = f.read32() 67 self.p_align = f.readWord() 68 69 def dump(self): 70 print " (('p_type', %s)" % common_dump.HexDump(self.p_type) 71 print " ('p_flags', %s)" % common_dump.HexDump(self.p_flags) 72 print " ('p_offset', %s)" % common_dump.HexDump(self.p_offset) 73 print " ('p_vaddr', %s)" % common_dump.HexDump(self.p_vaddr) 74 print " ('p_paddr', %s)" % common_dump.HexDump(self.p_paddr) 75 print " ('p_filesz', %s)" % common_dump.HexDump(self.p_filesz) 76 print " ('p_memsz', %s)" % common_dump.HexDump(self.p_memsz) 77 print " ('p_align', %s)" % common_dump.HexDump(self.p_align) 78 print " )," 79 80 class Section: 81 def __init__(self, f): 82 self.sh_name = f.read32() 83 self.sh_type = f.read32() 84 self.sh_flags = f.readWord() 85 self.sh_addr = f.readWord() 86 self.sh_offset = f.readWord() 87 self.sh_size = f.readWord() 88 self.sh_link = f.read32() 89 self.sh_info = f.read32() 90 self.sh_addralign = f.readWord() 91 self.sh_entsize = f.readWord() 92 93 def dump(self, shstrtab, f, strtab, dumpdata): 94 print " (('sh_name', %s)" % common_dump.HexDump(self.sh_name), "# %r" % shstrtab[self.sh_name[0]] 95 print " ('sh_type', %s)" % common_dump.HexDump(self.sh_type) 96 print " ('sh_flags', %s)" % common_dump.HexDump(self.sh_flags) 97 print " ('sh_addr', %s)" % common_dump.HexDump(self.sh_addr) 98 print " ('sh_offset', %s)" % common_dump.HexDump(self.sh_offset) 99 print " ('sh_size', %s)" % common_dump.HexDump(self.sh_size) 100 print " ('sh_link', %s)" % common_dump.HexDump(self.sh_link) 101 print " ('sh_info', %s)" % common_dump.HexDump(self.sh_info) 102 print " ('sh_addralign', %s)" % common_dump.HexDump(self.sh_addralign) 103 print " ('sh_entsize', %s)" % common_dump.HexDump(self.sh_entsize) 104 if self.sh_type[0] == 2: # SHT_SYMTAB 105 print " ('_symbols', [" 106 dumpSymtab(f, self, strtab) 107 print " ])" 108 elif self.sh_type[0] == 4 or self.sh_type[0] == 9: # SHT_RELA / SHT_REL 109 print " ('_relocations', [" 110 dumpRel(f, self, self.sh_type[0] == 4) 111 print " ])" 112 elif dumpdata: 113 f.seek(self.sh_offset[0]) 114 if self.sh_type != 8: # != SHT_NOBITS 115 data = f.read(self.sh_size[0]) 116 print " ('_section_data', '%s')" % common_dump.dataToHex(data) 117 else: 118 print " ('_section_data', '')" 119 print " )," 120 121 def dumpSymtab(f, section, strtab): 122 entries = section.sh_size[0] // section.sh_entsize[0] 123 124 for index in range(entries): 125 f.seek(section.sh_offset[0] + index * section.sh_entsize[0]) 126 print " # Symbol %s" % index 127 name = f.read32() 128 print " (('st_name', %s)" % common_dump.HexDump(name), "# %r" % strtab[name[0]] 129 if not f.is64Bit: 130 print " ('st_value', %s)" % common_dump.HexDump(f.read32()) 131 print " ('st_size', %s)" % common_dump.HexDump(f.read32()) 132 st_info = f.read8()[0] 133 st_bind = (st_info >> 4, 4) 134 st_type = (st_info & 0xf, 4) 135 print " ('st_bind', %s)" % common_dump.HexDump(st_bind) 136 print " ('st_type', %s)" % common_dump.HexDump(st_type) 137 print " ('st_other', %s)" % common_dump.HexDump(f.read8()) 138 print " ('st_shndx', %s)" % common_dump.HexDump(f.read16()) 139 if f.is64Bit: 140 print " ('st_value', %s)" % common_dump.HexDump(f.read64()) 141 print " ('st_size', %s)" % common_dump.HexDump(f.read64()) 142 print " )," 143 144 def dumpRel(f, section, dumprela = False): 145 entries = section.sh_size[0] // section.sh_entsize[0] 146 147 for index in range(entries): 148 f.seek(section.sh_offset[0] + index * section.sh_entsize[0]) 149 print " # Relocation %s" % index 150 print " (('r_offset', %s)" % common_dump.HexDump(f.readWord()) 151 152 if f.isN64: 153 r_sym = f.read32() 154 r_ssym = f.read8() 155 r_type3 = f.read8() 156 r_type2 = f.read8() 157 r_type = f.read8() 158 print " ('r_sym', %s)" % common_dump.HexDump(r_sym) 159 print " ('r_ssym', %s)" % common_dump.HexDump(r_ssym) 160 print " ('r_type3', %s)" % common_dump.HexDump(r_type3) 161 print " ('r_type2', %s)" % common_dump.HexDump(r_type2) 162 print " ('r_type', %s)" % common_dump.HexDump(r_type) 163 else: 164 r_info = f.readWord()[0] 165 if f.is64Bit: 166 r_sym = (r_info >> 32, 32) 167 r_type = (r_info & 0xffffffff, 32) 168 else: 169 r_sym = (r_info >> 8, 24) 170 r_type = (r_info & 0xff, 8) 171 print " ('r_sym', %s)" % common_dump.HexDump(r_sym) 172 print " ('r_type', %s)" % common_dump.HexDump(r_type) 173 if dumprela: 174 print " ('r_addend', %s)" % common_dump.HexDump(f.readWord()) 175 print " )," 176 177 def dumpELF(path, opts): 178 f = Reader(path) 179 180 magic = f.read(4) 181 assert magic == '\x7FELF' 182 183 fileclass = f.read8() 184 if fileclass[0] == 1: # ELFCLASS32 185 f.is64Bit = False 186 elif fileclass[0] == 2: # ELFCLASS64 187 f.is64Bit = True 188 else: 189 raise ValueError, "Unknown file class %s" % common_dump.HexDump(fileclass) 190 print "('e_indent[EI_CLASS]', %s)" % common_dump.HexDump(fileclass) 191 192 byteordering = f.read8() 193 if byteordering[0] == 1: # ELFDATA2LSB 194 f.isLSB = True 195 elif byteordering[0] == 2: # ELFDATA2MSB 196 f.isLSB = False 197 else: 198 raise ValueError, "Unknown byte ordering %s" % common_dump.HexDump(byteordering) 199 print "('e_indent[EI_DATA]', %s)" % common_dump.HexDump(byteordering) 200 201 print "('e_indent[EI_VERSION]', %s)" % common_dump.HexDump(f.read8()) 202 print "('e_indent[EI_OSABI]', %s)" % common_dump.HexDump(f.read8()) 203 print "('e_indent[EI_ABIVERSION]', %s)" % common_dump.HexDump(f.read8()) 204 205 f.seek(16) # Seek to end of e_ident. 206 207 print "('e_type', %s)" % common_dump.HexDump(f.read16()) 208 209 # Does any other architecture use N64? 210 e_machine = f.read16() 211 if e_machine[0] == 0x0008 and f.is64Bit: # EM_MIPS && 64 bit 212 f.isN64 = True 213 214 print "('e_machine', %s)" % common_dump.HexDump(e_machine) 215 print "('e_version', %s)" % common_dump.HexDump(f.read32()) 216 print "('e_entry', %s)" % common_dump.HexDump(f.readWord()) 217 e_phoff = f.readWord() 218 print "('e_phoff', %s)" % common_dump.HexDump(e_phoff) 219 e_shoff = f.readWord() 220 print "('e_shoff', %s)" % common_dump.HexDump(e_shoff) 221 print "('e_flags', %s)" % common_dump.HexDump(f.read32()) 222 print "('e_ehsize', %s)" % common_dump.HexDump(f.read16()) 223 e_phentsize = f.read16() 224 print "('e_phentsize', %s)" % common_dump.HexDump(e_phentsize) 225 e_phnum = f.read16() 226 print "('e_phnum', %s)" % common_dump.HexDump(e_phnum) 227 e_shentsize = f.read16() 228 print "('e_shentsize', %s)" % common_dump.HexDump(e_shentsize) 229 e_shnum = f.read16() 230 print "('e_shnum', %s)" % common_dump.HexDump(e_shnum) 231 e_shstrndx = f.read16() 232 print "('e_shstrndx', %s)" % common_dump.HexDump(e_shstrndx) 233 234 235 # Read all section headers 236 sections = [] 237 for index in range(e_shnum[0]): 238 f.seek(e_shoff[0] + index * e_shentsize[0]) 239 s = Section(f) 240 sections.append(s) 241 242 # Read .shstrtab so we can resolve section names 243 f.seek(sections[e_shstrndx[0]].sh_offset[0]) 244 shstrtab = StringTable(f.read(sections[e_shstrndx[0]].sh_size[0])) 245 246 # Get the symbol string table 247 strtab = None 248 for section in sections: 249 if shstrtab[section.sh_name[0]] == ".strtab": 250 f.seek(section.sh_offset[0]) 251 strtab = StringTable(f.read(section.sh_size[0])) 252 break 253 254 print "('_sections', [" 255 for index in range(e_shnum[0]): 256 print " # Section %s" % index 257 sections[index].dump(shstrtab, f, strtab, opts.dumpSectionData) 258 print "])" 259 260 # Read all program headers 261 headers = [] 262 for index in range(e_phnum[0]): 263 f.seek(e_phoff[0] + index * e_phentsize[0]) 264 h = ProgramHeader(f) 265 headers.append(h) 266 267 print "('_ProgramHeaders', [" 268 for index in range(e_phnum[0]): 269 print " # Program Header %s" % index 270 headers[index].dump() 271 print "])" 272 273 if __name__ == "__main__": 274 from optparse import OptionParser, OptionGroup 275 parser = OptionParser("usage: %prog [options] {files}") 276 parser.add_option("", "--dump-section-data", dest="dumpSectionData", 277 help="Dump the contents of sections", 278 action="store_true", default=False) 279 (opts, args) = parser.parse_args() 280 281 if not args: 282 args.append('-') 283 284 for arg in args: 285 dumpELF(arg, opts) 286