|  | #!/usr/bin/env python | 
|  |  | 
|  | import struct | 
|  | import sys | 
|  | import StringIO | 
|  |  | 
|  | import common_dump | 
|  |  | 
|  | class Reader: | 
|  | def __init__(self, path): | 
|  | if path == "-": | 
|  | # Snarf all the data so we can seek. | 
|  | self.file = StringIO.StringIO(sys.stdin.read()) | 
|  | else: | 
|  | self.file = open(path, "rb") | 
|  | self.isLSB = None | 
|  | self.is64Bit = None | 
|  |  | 
|  | def seek(self, pos): | 
|  | self.file.seek(pos) | 
|  |  | 
|  | def read(self, N): | 
|  | data = self.file.read(N) | 
|  | if len(data) != N: | 
|  | raise ValueError, "Out of data!" | 
|  | return data | 
|  |  | 
|  | def read8(self): | 
|  | return (ord(self.read(1)), 8) | 
|  |  | 
|  | def read16(self): | 
|  | return (struct.unpack('><'[self.isLSB] + 'H', self.read(2))[0], 16) | 
|  |  | 
|  | def read32(self): | 
|  | return (struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0], 32) | 
|  |  | 
|  | def read64(self): | 
|  | return (struct.unpack('><'[self.isLSB] + 'Q', self.read(8))[0], 64) | 
|  |  | 
|  | def readWord(self): | 
|  | if self.is64Bit: | 
|  | return self.read64() | 
|  | else: | 
|  | return self.read32() | 
|  |  | 
|  | class StringTable: | 
|  | def __init__(self, strings): | 
|  | self.string_table = strings | 
|  |  | 
|  | def __getitem__(self, index): | 
|  | end = self.string_table.index('\x00', index) | 
|  | return self.string_table[index:end] | 
|  |  | 
|  | class Section: | 
|  | def __init__(self, f): | 
|  | self.sh_name = f.read32() | 
|  | self.sh_type = f.read32() | 
|  | self.sh_flags = f.readWord() | 
|  | self.sh_addr = f.readWord() | 
|  | self.sh_offset = f.readWord() | 
|  | self.sh_size = f.readWord() | 
|  | self.sh_link = f.read32() | 
|  | self.sh_info = f.read32() | 
|  | self.sh_addralign = f.readWord() | 
|  | self.sh_entsize = f.readWord() | 
|  |  | 
|  | def dump(self, shstrtab, f, strtab, dumpdata): | 
|  | print "  (('sh_name', %s)" % common_dump.HexDump(self.sh_name), "# %r" % shstrtab[self.sh_name[0]] | 
|  | print "   ('sh_type', %s)" % common_dump.HexDump(self.sh_type) | 
|  | print "   ('sh_flags', %s)" % common_dump.HexDump(self.sh_flags) | 
|  | print "   ('sh_addr', %s)" % common_dump.HexDump(self.sh_addr) | 
|  | print "   ('sh_offset', %s)" % common_dump.HexDump(self.sh_offset) | 
|  | print "   ('sh_size', %s)" % common_dump.HexDump(self.sh_size) | 
|  | print "   ('sh_link', %s)" % common_dump.HexDump(self.sh_link) | 
|  | print "   ('sh_info', %s)" % common_dump.HexDump(self.sh_info) | 
|  | print "   ('sh_addralign', %s)" % common_dump.HexDump(self.sh_addralign) | 
|  | print "   ('sh_entsize', %s)" % common_dump.HexDump(self.sh_entsize) | 
|  | if self.sh_type[0] == 2: # SHT_SYMTAB | 
|  | print "   ('_symbols', [" | 
|  | dumpSymtab(f, self, strtab) | 
|  | print "   ])" | 
|  | elif self.sh_type[0] == 4 or self.sh_type[0] == 9: # SHT_RELA / SHT_REL | 
|  | print "   ('_relocations', [" | 
|  | dumpRel(f, self, self.sh_type[0] == 4) | 
|  | print "   ])" | 
|  | elif dumpdata: | 
|  | f.seek(self.sh_offset[0]) | 
|  | if self.sh_type != 8: # != SHT_NOBITS | 
|  | data = f.read(self.sh_size[0]) | 
|  | print "   ('_section_data', '%s')" % common_dump.dataToHex(data) | 
|  | else: | 
|  | print "   ('_section_data', '')" | 
|  | print "  )," | 
|  |  | 
|  | def dumpSymtab(f, section, strtab): | 
|  | entries = section.sh_size[0] // section.sh_entsize[0] | 
|  |  | 
|  | for index in range(entries): | 
|  | f.seek(section.sh_offset[0] + index * section.sh_entsize[0]) | 
|  | print "    # Symbol %s" % index | 
|  | name = f.read32() | 
|  | print "    (('st_name', %s)" % common_dump.HexDump(name), "# %r" % strtab[name[0]] | 
|  | if not f.is64Bit: | 
|  | print "     ('st_value', %s)" % common_dump.HexDump(f.read32()) | 
|  | print "     ('st_size', %s)" % common_dump.HexDump(f.read32()) | 
|  | st_info = f.read8()[0] | 
|  | st_bind = (st_info >> 4, 4) | 
|  | st_type = (st_info & 0xf, 4) | 
|  | print "     ('st_bind', %s)" % common_dump.HexDump(st_bind) | 
|  | print "     ('st_type', %s)" % common_dump.HexDump(st_type) | 
|  | print "     ('st_other', %s)" % common_dump.HexDump(f.read8()) | 
|  | print "     ('st_shndx', %s)" % common_dump.HexDump(f.read16()) | 
|  | if f.is64Bit: | 
|  | print "     ('st_value', %s)" % common_dump.HexDump(f.read64()) | 
|  | print "     ('st_size', %s)" % common_dump.HexDump(f.read64()) | 
|  | print "    )," | 
|  |  | 
|  | def dumpRel(f, section, dumprela = False): | 
|  | entries = section.sh_size[0] // section.sh_entsize[0] | 
|  |  | 
|  | for index in range(entries): | 
|  | f.seek(section.sh_offset[0] + index * section.sh_entsize[0]) | 
|  | print "    # Relocation %s" % index | 
|  | print "    (('r_offset', %s)" % common_dump.HexDump(f.readWord()) | 
|  | r_info = f.readWord()[0] | 
|  | if f.is64Bit: | 
|  | r_sym = (r_info >> 32, 32) | 
|  | r_type = (r_info & 0xffffffff, 32) | 
|  | else: | 
|  | r_sym = (r_info >> 8, 24) | 
|  | r_type = (r_info & 0xff, 8) | 
|  | print "     ('r_sym', %s)" % common_dump.HexDump(r_sym) | 
|  | print "     ('r_type', %s)" % common_dump.HexDump(r_type) | 
|  | if dumprela: | 
|  | print "     ('r_addend', %s)" % common_dump.HexDump(f.readWord()) | 
|  | print "    )," | 
|  |  | 
|  | def dumpELF(path, opts): | 
|  | f = Reader(path) | 
|  |  | 
|  | magic = f.read(4) | 
|  | assert magic == '\x7FELF' | 
|  |  | 
|  | fileclass = f.read8() | 
|  | if fileclass[0] == 1: # ELFCLASS32 | 
|  | f.is64Bit = False | 
|  | elif fileclass[0] == 2: # ELFCLASS64 | 
|  | f.is64Bit = True | 
|  | else: | 
|  | raise ValueError, "Unknown file class %s" % common_dump.HexDump(fileclass) | 
|  | print "('e_indent[EI_CLASS]', %s)" % common_dump.HexDump(fileclass) | 
|  |  | 
|  | byteordering = f.read8() | 
|  | if byteordering[0] == 1: # ELFDATA2LSB | 
|  | f.isLSB = True | 
|  | elif byteordering[0] == 2: # ELFDATA2MSB | 
|  | f.isLSB = False | 
|  | else: | 
|  | raise ValueError, "Unknown byte ordering %s" % common_dump.HexDump(byteordering) | 
|  | print "('e_indent[EI_DATA]', %s)" % common_dump.HexDump(byteordering) | 
|  |  | 
|  | print "('e_indent[EI_VERSION]', %s)" % common_dump.HexDump(f.read8()) | 
|  | print "('e_indent[EI_OSABI]', %s)" % common_dump.HexDump(f.read8()) | 
|  | print "('e_indent[EI_ABIVERSION]', %s)" % common_dump.HexDump(f.read8()) | 
|  |  | 
|  | f.seek(16) # Seek to end of e_ident. | 
|  |  | 
|  | print "('e_type', %s)" % common_dump.HexDump(f.read16()) | 
|  | print "('e_machine', %s)" % common_dump.HexDump(f.read16()) | 
|  | print "('e_version', %s)" % common_dump.HexDump(f.read32()) | 
|  | print "('e_entry', %s)" % common_dump.HexDump(f.readWord()) | 
|  | print "('e_phoff', %s)" % common_dump.HexDump(f.readWord()) | 
|  | e_shoff = f.readWord() | 
|  | print "('e_shoff', %s)" % common_dump.HexDump(e_shoff) | 
|  | print "('e_flags', %s)" % common_dump.HexDump(f.read32()) | 
|  | print "('e_ehsize', %s)" % common_dump.HexDump(f.read16()) | 
|  | print "('e_phentsize', %s)" % common_dump.HexDump(f.read16()) | 
|  | print "('e_phnum', %s)" % common_dump.HexDump(f.read16()) | 
|  | e_shentsize = f.read16() | 
|  | print "('e_shentsize', %s)" % common_dump.HexDump(e_shentsize) | 
|  | e_shnum = f.read16() | 
|  | print "('e_shnum', %s)" % common_dump.HexDump(e_shnum) | 
|  | e_shstrndx = f.read16() | 
|  | print "('e_shstrndx', %s)" % common_dump.HexDump(e_shstrndx) | 
|  |  | 
|  | # Read all section headers | 
|  | sections = [] | 
|  | for index in range(e_shnum[0]): | 
|  | f.seek(e_shoff[0] + index * e_shentsize[0]) | 
|  | s = Section(f) | 
|  | sections.append(s) | 
|  |  | 
|  | # Read .shstrtab so we can resolve section names | 
|  | f.seek(sections[e_shstrndx[0]].sh_offset[0]) | 
|  | shstrtab = StringTable(f.read(sections[e_shstrndx[0]].sh_size[0])) | 
|  |  | 
|  | # Get the symbol string table | 
|  | strtab = None | 
|  | for section in sections: | 
|  | if shstrtab[section.sh_name[0]] == ".strtab": | 
|  | f.seek(section.sh_offset[0]) | 
|  | strtab = StringTable(f.read(section.sh_size[0])) | 
|  | break | 
|  |  | 
|  | print "('_sections', [" | 
|  | for index in range(e_shnum[0]): | 
|  | print "  # Section %s" % index | 
|  | sections[index].dump(shstrtab, f, strtab, opts.dumpSectionData) | 
|  | print "])" | 
|  |  | 
|  | if __name__ == "__main__": | 
|  | from optparse import OptionParser, OptionGroup | 
|  | parser = OptionParser("usage: %prog [options] {files}") | 
|  | parser.add_option("", "--dump-section-data", dest="dumpSectionData", | 
|  | help="Dump the contents of sections", | 
|  | action="store_true", default=False) | 
|  | (opts, args) = parser.parse_args() | 
|  |  | 
|  | if not args: | 
|  | args.append('-') | 
|  |  | 
|  | for arg in args: | 
|  | dumpELF(arg, opts) |