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 19 def seek(self, pos): 20 self.file.seek(pos) 21 22 def read(self, N): 23 data = self.file.read(N) 24 if len(data) != N: 25 raise ValueError, "Out of data!" 26 return data 27 28 def read8(self): 29 return ord(self.read(1)) 30 31 def read16(self): 32 return struct.unpack('><'[self.isLSB] + 'H', self.read(2))[0] 33 34 def read32(self): 35 return struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0] 36 37 def read32S(self): 38 return struct.unpack('><'[self.isLSB] + 'i', self.read(4))[0] 39 40 def read64(self): 41 return struct.unpack('><'[self.isLSB] + 'Q', self.read(8))[0] 42 43 def read64S(self): 44 return struct.unpack('><'[self.isLSB] + 'q', self.read(8))[0] 45 46 def readWord(self): 47 if self.is64Bit: 48 return self.read64() 49 else: 50 return self.read32() 51 52 def readWordS(self): 53 if self.is64Bit: 54 return self.read64S() 55 else: 56 return self.read32S() 57 58 class StringTable: 59 def __init__(self, strings): 60 self.string_table = strings 61 62 def __getitem__(self, index): 63 end = self.string_table.index('\x00', index) 64 return self.string_table[index:end] 65 66 class Section: 67 def __init__(self, f): 68 self.sh_name = f.read32() 69 self.sh_type = f.read32() 70 self.sh_flags = f.readWord() 71 self.sh_addr = f.readWord() 72 self.sh_offset = f.readWord() 73 self.sh_size = f.readWord() 74 self.sh_link = f.read32() 75 self.sh_info = f.read32() 76 self.sh_addralign = f.readWord() 77 self.sh_entsize = f.readWord() 78 79 def dump(self, shstrtab, f, strtab, dumpdata): 80 print " (('sh_name', %s)" % common_dump.HexDump(self.sh_name), "# %r" % shstrtab[self.sh_name] 81 print " ('sh_type', %s)" % common_dump.HexDump(self.sh_type) 82 print " ('sh_flags', %s)" % common_dump.HexDump(self.sh_flags) 83 print " ('sh_addr', %s)" % common_dump.HexDump(self.sh_addr) 84 print " ('sh_offset', %s)" % common_dump.HexDump(self.sh_offset) 85 print " ('sh_size', %s)" % common_dump.HexDump(self.sh_size) 86 print " ('sh_link', %s)" % common_dump.HexDump(self.sh_link) 87 print " ('sh_info', %s)" % common_dump.HexDump(self.sh_info) 88 print " ('sh_addralign', %s)" % common_dump.HexDump(self.sh_addralign) 89 print " ('sh_entsize', %s)" % common_dump.HexDump(self.sh_entsize) 90 if self.sh_type == 2: # SHT_SYMTAB 91 print " ('_symbols', [" 92 dumpSymtab(f, self, strtab) 93 print " ])" 94 elif self.sh_type == 4 or self.sh_type == 9: # SHT_RELA / SHT_REL 95 print " ('_relocations', [" 96 dumpRel(f, self, self.sh_type == 4) 97 print " ])" 98 elif dumpdata: 99 f.seek(self.sh_offset) 100 if self.sh_type != 8: # != SHT_NOBITS 101 data = f.read(self.sh_size) 102 print " ('_section_data', '%s')" % common_dump.dataToHex(data) 103 else: 104 print " ('_section_data', '')" 105 print " )," 106 107 def dumpSymtab(f, section, strtab): 108 entries = section.sh_size // section.sh_entsize 109 110 for index in range(entries): 111 f.seek(section.sh_offset + index * section.sh_entsize) 112 print " # Symbol %s" % common_dump.HexDump(index) 113 name = f.read32() 114 print " (('st_name', %s)" % common_dump.HexDump(name), "# %r" % strtab[name] 115 if not f.is64Bit: 116 print " ('st_value', %s)" % common_dump.HexDump(f.read32()) 117 print " ('st_size', %s)" % common_dump.HexDump(f.read32()) 118 st_info = f.read8() 119 print " ('st_bind', %s)" % common_dump.HexDump((st_info >> 4)) 120 print " ('st_type', %s)" % common_dump.HexDump((st_info & 0xf)) 121 print " ('st_other', %s)" % common_dump.HexDump(f.read8()) 122 print " ('st_shndx', %s)" % common_dump.HexDump(f.read16()) 123 if f.is64Bit: 124 print " ('st_value', %s)" % common_dump.HexDump(f.read64(), 64) 125 print " ('st_size', %s)" % common_dump.HexDump(f.read64(), 64) 126 print " )," 127 128 def dumpRel(f, section, dumprela = False): 129 entries = section.sh_size // section.sh_entsize 130 131 for index in range(entries): 132 f.seek(section.sh_offset + index * section.sh_entsize) 133 print " # Relocation %s" % common_dump.HexDump(index) 134 print " (('r_offset', %s)" % common_dump.HexDump(f.readWord()) 135 r_info = f.readWord() 136 if f.is64Bit: 137 print " ('r_sym', %s)" % common_dump.HexDump((r_info >> 32)) 138 print " ('r_type', %s)" % common_dump.HexDump((r_info & 0xffffffff)) 139 else: 140 print " ('r_sym', %s)" % common_dump.HexDump((r_info >> 8)) 141 print " ('r_type', %s)" % common_dump.HexDump((r_info & 0xff)) 142 if dumprela: 143 print " ('r_addend', %s)" % common_dump.HexDump(f.readWordS()) 144 print " )," 145 146 def dumpELF(path, opts): 147 f = Reader(path) 148 149 magic = f.read(4) 150 assert magic == '\x7FELF' 151 152 fileclass = f.read8() 153 if fileclass == 1: # ELFCLASS32 154 f.is64Bit = False 155 elif fileclass == 2: # ELFCLASS64 156 f.is64Bit = True 157 else: 158 raise ValueError, "Unknown file class %s" % common_dump.HexDump(fileclass) 159 print "('e_indent[EI_CLASS]', %s)" % common_dump.HexDump(fileclass) 160 161 byteordering = f.read8() 162 if byteordering == 1: # ELFDATA2LSB 163 f.isLSB = True 164 elif byteordering == 2: # ELFDATA2MSB 165 f.isLSB = False 166 else: 167 raise ValueError, "Unknown byte ordering %s" % common_dump.HexDump(byteordering) 168 print "('e_indent[EI_DATA]', %s)" % common_dump.HexDump(byteordering) 169 170 print "('e_indent[EI_VERSION]', %s)" % common_dump.HexDump(f.read8()) 171 print "('e_indent[EI_OSABI]', %s)" % common_dump.HexDump(f.read8()) 172 print "('e_indent[EI_ABIVERSION]', %s)" % common_dump.HexDump(f.read8()) 173 174 f.seek(16) # Seek to end of e_ident. 175 176 print "('e_type', %s)" % common_dump.HexDump(f.read16()) 177 print "('e_machine', %s)" % common_dump.HexDump(f.read16()) 178 print "('e_version', %s)" % common_dump.HexDump(f.read32()) 179 print "('e_entry', %s)" % common_dump.HexDump(f.readWord()) 180 print "('e_phoff', %s)" % common_dump.HexDump(f.readWord()) 181 e_shoff = f.readWord() 182 print "('e_shoff', %s)" % common_dump.HexDump(e_shoff) 183 print "('e_flags', %s)" % common_dump.HexDump(f.read32()) 184 print "('e_ehsize', %s)" % common_dump.HexDump(f.read16()) 185 print "('e_phentsize', %s)" % common_dump.HexDump(f.read16()) 186 print "('e_phnum', %s)" % common_dump.HexDump(f.read16()) 187 e_shentsize = f.read16() 188 print "('e_shentsize', %s)" % common_dump.HexDump(e_shentsize) 189 e_shnum = f.read16() 190 print "('e_shnum', %s)" % common_dump.HexDump(e_shnum) 191 e_shstrndx = f.read16() 192 print "('e_shstrndx', %s)" % common_dump.HexDump(e_shstrndx) 193 194 # Read all section headers 195 sections = [] 196 for index in range(e_shnum): 197 f.seek(e_shoff + index * e_shentsize) 198 s = Section(f) 199 sections.append(s) 200 201 # Read .shstrtab so we can resolve section names 202 f.seek(sections[e_shstrndx].sh_offset) 203 shstrtab = StringTable(f.read(sections[e_shstrndx].sh_size)) 204 205 # Get the symbol string table 206 strtab = None 207 for section in sections: 208 if shstrtab[section.sh_name] == ".strtab": 209 f.seek(section.sh_offset) 210 strtab = StringTable(f.read(section.sh_size)) 211 break 212 213 print "('_sections', [" 214 for index in range(e_shnum): 215 print " # Section %s" % common_dump.HexDump(index) 216 sections[index].dump(shstrtab, f, strtab, opts.dumpSectionData) 217 print "])" 218 219 if __name__ == "__main__": 220 from optparse import OptionParser, OptionGroup 221 parser = OptionParser("usage: %prog [options] {files}") 222 parser.add_option("", "--dump-section-data", dest="dumpSectionData", 223 help="Dump the contents of sections", 224 action="store_true", default=False) 225 (opts, args) = parser.parse_args() 226 227 if not args: 228 args.append('-') 229 230 for arg in args: 231 dumpELF(arg, opts) 232