| #!/usr/bin/env python |
| #===-- coff-dump.py - COFF object file dump utility-------------------------===# |
| # |
| # The LLVM Compiler Infrastructure |
| # |
| # This file is distributed under the University of Illinois Open Source |
| # License. See LICENSE.TXT for details. |
| # |
| #===------------------------------------------------------------------------===# |
| |
| # |
| # COFF File Definition |
| # |
| |
| def string_table_entry (offset): |
| return ('ptr', '+ + PointerToSymbolTable * NumberOfSymbols 18 %s' % offset, ('scalar', 'cstr', '%s')) |
| |
| def secname(value): |
| if value[0] == '/': |
| return string_table_entry(value[1:].rstrip('\0')) |
| else: |
| return '%s' |
| |
| def symname(value): |
| parts = struct.unpack("<2L", value) |
| if parts[0] == 0: |
| return string_table_entry(parts[1]) |
| else: |
| return '%s' |
| |
| file = ('struct', [ |
| ('MachineType', ('enum', '<H', '0x%X', { |
| 0x0: 'IMAGE_FILE_MACHINE_UNKNOWN', |
| 0x1d3: 'IMAGE_FILE_MACHINE_AM33', |
| 0x8664: 'IMAGE_FILE_MACHINE_AMD64', |
| 0x1c0: 'IMAGE_FILE_MACHINE_ARM', |
| 0xebc: 'IMAGE_FILE_MACHINE_EBC', |
| 0x14c: 'IMAGE_FILE_MACHINE_I386', |
| 0x200: 'IMAGE_FILE_MACHINE_IA64', |
| 0x904: 'IMAGE_FILE_MACHINE_M32R', |
| 0x266: 'IMAGE_FILE_MACHINE_MIPS16', |
| 0x366: 'IMAGE_FILE_MACHINE_MIPSFPU', |
| 0x466: 'IMAGE_FILE_MACHINE_MIPSFPU16', |
| 0x1f0: 'IMAGE_FILE_MACHINE_POWERPC', |
| 0x1f1: 'IMAGE_FILE_MACHINE_POWERPCFP', |
| 0x166: 'IMAGE_FILE_MACHINE_R4000', |
| 0x1a2: 'IMAGE_FILE_MACHINE_SH3', |
| 0x1a3: 'IMAGE_FILE_MACHINE_SH3DSP', |
| 0x1a6: 'IMAGE_FILE_MACHINE_SH4', |
| 0x1a8: 'IMAGE_FILE_MACHINE_SH5', |
| 0x1c2: 'IMAGE_FILE_MACHINE_THUMB', |
| 0x169: 'IMAGE_FILE_MACHINE_WCEMIPSV2', |
| })), |
| ('NumberOfSections', ('scalar', '<H', '%d')), |
| ('TimeDateStamp', ('scalar', '<L', '%d')), |
| ('PointerToSymbolTable', ('scalar', '<L', '0x%0X')), |
| ('NumberOfSymbols', ('scalar', '<L', '%d')), |
| ('SizeOfOptionalHeader', ('scalar', '<H', '%d')), |
| ('Characteristics', ('flags', '<H', '0x%x', [ |
| (0x0001, 'IMAGE_FILE_RELOCS_STRIPPED', ), |
| (0x0002, 'IMAGE_FILE_EXECUTABLE_IMAGE', ), |
| (0x0004, 'IMAGE_FILE_LINE_NUMS_STRIPPED', ), |
| (0x0008, 'IMAGE_FILE_LOCAL_SYMS_STRIPPED', ), |
| (0x0010, 'IMAGE_FILE_AGGRESSIVE_WS_TRIM', ), |
| (0x0020, 'IMAGE_FILE_LARGE_ADDRESS_AWARE', ), |
| (0x0080, 'IMAGE_FILE_BYTES_REVERSED_LO', ), |
| (0x0100, 'IMAGE_FILE_32BIT_MACHINE', ), |
| (0x0200, 'IMAGE_FILE_DEBUG_STRIPPED', ), |
| (0x0400, 'IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP', ), |
| (0x0800, 'IMAGE_FILE_NET_RUN_FROM_SWAP', ), |
| (0x1000, 'IMAGE_FILE_SYSTEM', ), |
| (0x2000, 'IMAGE_FILE_DLL', ), |
| (0x4000, 'IMAGE_FILE_UP_SYSTEM_ONLY', ), |
| (0x8000, 'IMAGE_FILE_BYTES_REVERSED_HI', ), |
| ])), |
| ('Sections', ('array', '1', 'NumberOfSections', ('struct', [ |
| ('Name', ('scalar', '<8s', secname)), |
| ('VirtualSize', ('scalar', '<L', '%d' )), |
| ('VirtualAddress', ('scalar', '<L', '%d' )), |
| ('SizeOfRawData', ('scalar', '<L', '%d' )), |
| ('PointerToRawData', ('scalar', '<L', '0x%X' )), |
| ('PointerToRelocations', ('scalar', '<L', '0x%X' )), |
| ('PointerToLineNumbers', ('scalar', '<L', '0x%X' )), |
| ('NumberOfRelocations', ('scalar', '<H', '%d' )), |
| ('NumberOfLineNumbers', ('scalar', '<H', '%d' )), |
| ('Charateristics', ('flags', '<L', '0x%X', [ |
| (0x00000008, 'IMAGE_SCN_TYPE_NO_PAD'), |
| (0x00000020, 'IMAGE_SCN_CNT_CODE'), |
| (0x00000040, 'IMAGE_SCN_CNT_INITIALIZED_DATA'), |
| (0x00000080, 'IMAGE_SCN_CNT_UNINITIALIZED_DATA'), |
| (0x00000100, 'IMAGE_SCN_LNK_OTHER'), |
| (0x00000200, 'IMAGE_SCN_LNK_INFO'), |
| (0x00000800, 'IMAGE_SCN_LNK_REMOVE'), |
| (0x00001000, 'IMAGE_SCN_LNK_COMDAT'), |
| (0x00008000, 'IMAGE_SCN_GPREL'), |
| (0x00020000, 'IMAGE_SCN_MEM_PURGEABLE'), |
| (0x00020000, 'IMAGE_SCN_MEM_16BIT'), |
| (0x00040000, 'IMAGE_SCN_MEM_LOCKED'), |
| (0x00080000, 'IMAGE_SCN_MEM_PRELOAD'), |
| (0x00F00000, 'IMAGE_SCN_ALIGN', { |
| 0x00100000: 'IMAGE_SCN_ALIGN_1BYTES', |
| 0x00200000: 'IMAGE_SCN_ALIGN_2BYTES', |
| 0x00300000: 'IMAGE_SCN_ALIGN_4BYTES', |
| 0x00400000: 'IMAGE_SCN_ALIGN_8BYTES', |
| 0x00500000: 'IMAGE_SCN_ALIGN_16BYTES', |
| 0x00600000: 'IMAGE_SCN_ALIGN_32BYTES', |
| 0x00700000: 'IMAGE_SCN_ALIGN_64BYTES', |
| 0x00800000: 'IMAGE_SCN_ALIGN_128BYTES', |
| 0x00900000: 'IMAGE_SCN_ALIGN_256BYTES', |
| 0x00A00000: 'IMAGE_SCN_ALIGN_512BYTES', |
| 0x00B00000: 'IMAGE_SCN_ALIGN_1024BYTES', |
| 0x00C00000: 'IMAGE_SCN_ALIGN_2048BYTES', |
| 0x00D00000: 'IMAGE_SCN_ALIGN_4096BYTES', |
| 0x00E00000: 'IMAGE_SCN_ALIGN_8192BYTES', |
| }), |
| (0x01000000, 'IMAGE_SCN_LNK_NRELOC_OVFL'), |
| (0x02000000, 'IMAGE_SCN_MEM_DISCARDABLE'), |
| (0x04000000, 'IMAGE_SCN_MEM_NOT_CACHED'), |
| (0x08000000, 'IMAGE_SCN_MEM_NOT_PAGED'), |
| (0x10000000, 'IMAGE_SCN_MEM_SHARED'), |
| (0x20000000, 'IMAGE_SCN_MEM_EXECUTE'), |
| (0x40000000, 'IMAGE_SCN_MEM_READ'), |
| (0x80000000, 'IMAGE_SCN_MEM_WRITE'), |
| ])), |
| ('SectionData', ('ptr', 'PointerToRawData', ('blob', 'SizeOfRawData'))), |
| ('Relocations', ('ptr', 'PointerToRelocations', ('array', '0', 'NumberOfRelocations', ('struct', [ |
| ('VirtualAddress', ('scalar', '<L', '0x%X')), |
| ('SymbolTableIndex', ('scalar', '<L', '%d' )), |
| ('Type', ('enum', '<H', '%d', ('MachineType', { |
| 0x14c: { |
| 0x0000: 'IMAGE_REL_I386_ABSOLUTE', |
| 0x0001: 'IMAGE_REL_I386_DIR16', |
| 0x0002: 'IMAGE_REL_I386_REL16', |
| 0x0006: 'IMAGE_REL_I386_DIR32', |
| 0x0007: 'IMAGE_REL_I386_DIR32NB', |
| 0x0009: 'IMAGE_REL_I386_SEG12', |
| 0x000A: 'IMAGE_REL_I386_SECTION', |
| 0x000B: 'IMAGE_REL_I386_SECREL', |
| 0x000C: 'IMAGE_REL_I386_TOKEN', |
| 0x000D: 'IMAGE_REL_I386_SECREL7', |
| 0x0014: 'IMAGE_REL_I386_REL32', |
| }, |
| 0x8664: { |
| 0x0000: 'IMAGE_REL_AMD64_ABSOLUTE', |
| 0x0001: 'IMAGE_REL_AMD64_ADDR64', |
| 0x0002: 'IMAGE_REL_AMD64_ADDR32', |
| 0x0003: 'IMAGE_REL_AMD64_ADDR32NB', |
| 0x0004: 'IMAGE_REL_AMD64_REL32', |
| 0x0005: 'IMAGE_REL_AMD64_REL32_1', |
| 0x0006: 'IMAGE_REL_AMD64_REL32_2', |
| 0x0007: 'IMAGE_REL_AMD64_REL32_3', |
| 0x0008: 'IMAGE_REL_AMD64_REL32_4', |
| 0x0009: 'IMAGE_REL_AMD64_REL32_5', |
| 0x000A: 'IMAGE_REL_AMD64_SECTION', |
| 0x000B: 'IMAGE_REL_AMD64_SECREL', |
| 0x000C: 'IMAGE_REL_AMD64_SECREL7', |
| 0x000D: 'IMAGE_REL_AMD64_TOKEN', |
| 0x000E: 'IMAGE_REL_AMD64_SREL32', |
| 0x000F: 'IMAGE_REL_AMD64_PAIR', |
| 0x0010: 'IMAGE_REL_AMD64_SSPAN32', |
| }, |
| }))), |
| ('SymbolName', ('ptr', '+ PointerToSymbolTable * SymbolTableIndex 18', ('scalar', '<8s', symname))) |
| ])))), |
| ]))), |
| ('Symbols', ('ptr', 'PointerToSymbolTable', ('byte-array', '18', '* NumberOfSymbols 18', ('struct', [ |
| ('Name', ('scalar', '<8s', symname)), |
| ('Value', ('scalar', '<L', '%d' )), |
| ('SectionNumber', ('scalar', '<H', '%d' )), |
| ('_Type', ('scalar', '<H', None )), |
| ('SimpleType', ('enum', '& _Type 15', '%d', { |
| 0: 'IMAGE_SYM_TYPE_NULL', |
| 1: 'IMAGE_SYM_TYPE_VOID', |
| 2: 'IMAGE_SYM_TYPE_CHAR', |
| 3: 'IMAGE_SYM_TYPE_SHORT', |
| 4: 'IMAGE_SYM_TYPE_INT', |
| 5: 'IMAGE_SYM_TYPE_LONG', |
| 6: 'IMAGE_SYM_TYPE_FLOAT', |
| 7: 'IMAGE_SYM_TYPE_DOUBLE', |
| 8: 'IMAGE_SYM_TYPE_STRUCT', |
| 9: 'IMAGE_SYM_TYPE_UNION', |
| 10: 'IMAGE_SYM_TYPE_ENUM', |
| 11: 'IMAGE_SYM_TYPE_MOE', |
| 12: 'IMAGE_SYM_TYPE_BYTE', |
| 13: 'IMAGE_SYM_TYPE_WORD', |
| 14: 'IMAGE_SYM_TYPE_UINT', |
| 15: 'IMAGE_SYM_TYPE_DWORD', |
| })), # (Type & 0xF0) >> 4 |
| ('ComplexType', ('enum', '>> & _Type 240 4', '%d', { |
| 0: 'IMAGE_SYM_DTYPE_NULL', |
| 1: 'IMAGE_SYM_DTYPE_POINTER', |
| 2: 'IMAGE_SYM_DTYPE_FUNCTION', |
| 3: 'IMAGE_SYM_DTYPE_ARRAY', |
| })), |
| ('StorageClass', ('enum', '<B', '%d', { |
| -1: 'IMAGE_SYM_CLASS_END_OF_FUNCTION', |
| 0: 'IMAGE_SYM_CLASS_NULL', |
| 1: 'IMAGE_SYM_CLASS_AUTOMATIC', |
| 2: 'IMAGE_SYM_CLASS_EXTERNAL', |
| 3: 'IMAGE_SYM_CLASS_STATIC', |
| 4: 'IMAGE_SYM_CLASS_REGISTER', |
| 5: 'IMAGE_SYM_CLASS_EXTERNAL_DEF', |
| 6: 'IMAGE_SYM_CLASS_LABEL', |
| 7: 'IMAGE_SYM_CLASS_UNDEFINED_LABEL', |
| 8: 'IMAGE_SYM_CLASS_MEMBER_OF_STRUCT', |
| 9: 'IMAGE_SYM_CLASS_ARGUMENT', |
| 10: 'IMAGE_SYM_CLASS_STRUCT_TAG', |
| 11: 'IMAGE_SYM_CLASS_MEMBER_OF_UNION', |
| 12: 'IMAGE_SYM_CLASS_UNION_TAG', |
| 13: 'IMAGE_SYM_CLASS_TYPE_DEFINITION', |
| 14: 'IMAGE_SYM_CLASS_UNDEFINED_STATIC', |
| 15: 'IMAGE_SYM_CLASS_ENUM_TAG', |
| 16: 'IMAGE_SYM_CLASS_MEMBER_OF_ENUM', |
| 17: 'IMAGE_SYM_CLASS_REGISTER_PARAM', |
| 18: 'IMAGE_SYM_CLASS_BIT_FIELD', |
| 100: 'IMAGE_SYM_CLASS_BLOCK', |
| 101: 'IMAGE_SYM_CLASS_FUNCTION', |
| 102: 'IMAGE_SYM_CLASS_END_OF_STRUCT', |
| 103: 'IMAGE_SYM_CLASS_FILE', |
| 104: 'IMAGE_SYM_CLASS_SECTION', |
| 105: 'IMAGE_SYM_CLASS_WEAK_EXTERNAL', |
| 107: 'IMAGE_SYM_CLASS_CLR_TOKEN', |
| })), |
| ('NumberOfAuxSymbols', ('scalar', '<B', '%d' )), |
| ('AuxillaryData', ('blob', '* NumberOfAuxSymbols 18')), |
| ])))), |
| ]) |
| |
| # |
| # Definition Interpreter |
| # |
| |
| import sys, types, struct, re |
| |
| Input = None |
| Stack = [] |
| Fields = {} |
| |
| Indent = 0 |
| NewLine = True |
| |
| def indent(): |
| global Indent |
| Indent += 1 |
| |
| def dedent(): |
| global Indent |
| Indent -= 1 |
| |
| def write(input): |
| global NewLine |
| output = "" |
| |
| for char in input: |
| |
| if NewLine: |
| output += Indent * ' ' |
| NewLine = False |
| |
| output += char |
| |
| if char == '\n': |
| NewLine = True |
| |
| sys.stdout.write(output) |
| |
| def read(format): |
| return struct.unpack(format, Input.read(struct.calcsize(format))) |
| |
| def read_cstr(): |
| output = "" |
| while True: |
| char = Input.read(1) |
| if len(char) == 0: |
| raise RuntimeError ("EOF while reading cstr") |
| if char == '\0': |
| break |
| output += char |
| return output |
| |
| def push_pos(seek_to = None): |
| Stack [0:0] = [Input.tell()] |
| if seek_to: |
| Input.seek(seek_to) |
| |
| def pop_pos(): |
| assert(len(Stack) > 0) |
| Input.seek(Stack[0]) |
| del Stack[0] |
| |
| def print_binary_data(size): |
| value = "" |
| while size > 0: |
| if size >= 16: |
| data = Input.read(16) |
| size -= 16 |
| else: |
| data = Input.read(size) |
| size = 0 |
| value += data |
| bytes = "" |
| text = "" |
| for index in xrange(16): |
| if index < len(data): |
| if index == 8: |
| bytes += "- " |
| ch = ord(data[index]) |
| bytes += "%02X " % ch |
| if ch >= 0x20 and ch <= 0x7F: |
| text += data[index] |
| else: |
| text += "." |
| else: |
| if index == 8: |
| bytes += " " |
| bytes += " " |
| |
| write("%s|%s|\n" % (bytes, text)) |
| return value |
| |
| idlit = re.compile("[a-zA-Z_][a-zA-Z0-9_-]*") |
| numlit = re.compile("[0-9]+") |
| |
| def read_value(expr): |
| |
| input = iter(expr.split()) |
| |
| def eval(): |
| |
| token = input.next() |
| |
| if expr == 'cstr': |
| return read_cstr() |
| if expr == 'true': |
| return True |
| if expr == 'false': |
| return False |
| |
| if token == '+': |
| return eval() + eval() |
| if token == '-': |
| return eval() - eval() |
| if token == '*': |
| return eval() * eval() |
| if token == '/': |
| return eval() / eval() |
| if token == '&': |
| return eval() & eval() |
| if token == '|': |
| return eval() | eval() |
| if token == '>>': |
| return eval() >> eval() |
| if token == '<<': |
| return eval() << eval() |
| |
| if len(token) > 1 and token[0] in ('=', '@', '<', '!', '>'): |
| val = read(expr) |
| assert(len(val) == 1) |
| return val[0] |
| |
| if idlit.match(token): |
| return Fields[token] |
| if numlit.match(token): |
| return int(token) |
| |
| raise RuntimeError("unexpected token %s" % repr(token)) |
| |
| value = eval() |
| |
| try: |
| input.next() |
| except StopIteration: |
| return value |
| raise RuntimeError("unexpected input at end of expression") |
| |
| def write_value(format,value): |
| format_type = type(format) |
| if format_type is types.StringType: |
| write(format % value) |
| elif format_type is types.FunctionType: |
| write_value(format(value), value) |
| elif format_type is types.TupleType: |
| Fields['this'] = value |
| handle_element(format) |
| elif format_type is types.NoneType: |
| pass |
| else: |
| raise RuntimeError("unexpected type: %s" % repr(format_type)) |
| |
| def handle_scalar(entry): |
| iformat = entry[1] |
| oformat = entry[2] |
| |
| value = read_value(iformat) |
| |
| write_value(oformat, value) |
| |
| return value |
| |
| def handle_enum(entry): |
| iformat = entry[1] |
| oformat = entry[2] |
| definitions = entry[3] |
| |
| value = read_value(iformat) |
| |
| if type(definitions) is types.TupleType: |
| selector = read_value(definitions[0]) |
| definitions = definitions[1][selector] |
| |
| if value in definitions: |
| description = definitions[value] |
| else: |
| description = "unknown" |
| |
| write("%s (" % description) |
| write_value(oformat, value) |
| write(")") |
| |
| return value |
| |
| def handle_flags(entry): |
| iformat = entry[1] |
| oformat = entry[2] |
| definitions = entry[3] |
| |
| value = read_value(iformat) |
| |
| write_value(oformat, value) |
| |
| indent() |
| for entry in definitions: |
| mask = entry[0] |
| name = entry[1] |
| if len (entry) == 3: |
| map = entry[2] |
| selection = value & mask |
| if selection in map: |
| write("\n%s" % map[selection]) |
| else: |
| write("\n%s <%d>" % (name, selection)) |
| elif len(entry) == 2: |
| if value & mask != 0: |
| write("\n%s" % name) |
| dedent() |
| |
| return value |
| |
| def handle_struct(entry): |
| global Fields |
| members = entry[1] |
| |
| newFields = {} |
| |
| write("{\n"); |
| indent() |
| |
| for member in members: |
| name = member[0] |
| type = member[1] |
| |
| if name[0] != "_": |
| write("%s = " % name.ljust(24)) |
| |
| value = handle_element(type) |
| |
| if name[0] != "_": |
| write("\n") |
| |
| Fields[name] = value |
| newFields[name] = value |
| |
| dedent() |
| write("}") |
| |
| return newFields |
| |
| def handle_array(entry): |
| start_index = entry[1] |
| length = entry[2] |
| element = entry[3] |
| |
| newItems = [] |
| |
| write("[\n") |
| indent() |
| |
| start_index = read_value(start_index) |
| value = read_value(length) |
| |
| for index in xrange(value): |
| write("%d = " % (index + start_index)) |
| value = handle_element(element) |
| write("\n") |
| newItems.append(value) |
| |
| dedent() |
| write("]") |
| |
| return newItems |
| |
| def handle_byte_array(entry): |
| ent_size = entry[1] |
| length = entry[2] |
| element = entry[3] |
| |
| newItems = [] |
| |
| write("[\n") |
| indent() |
| |
| item_size = read_value(ent_size) |
| value = read_value(length) |
| end_of_array = Input.tell() + value |
| |
| prev_loc = Input.tell() |
| index = 0 |
| while Input.tell() < end_of_array: |
| write("%d = " % index) |
| value = handle_element(element) |
| write("\n") |
| newItems.append(value) |
| index += (Input.tell() - prev_loc) / item_size |
| prev_loc = Input.tell() |
| |
| dedent() |
| write("]") |
| |
| return newItems |
| |
| def handle_ptr(entry): |
| offset = entry[1] |
| element = entry[2] |
| |
| value = None |
| offset = read_value(offset) |
| |
| if offset != 0: |
| |
| push_pos(offset) |
| |
| value = handle_element(element) |
| |
| pop_pos() |
| |
| else: |
| write("None") |
| |
| return value |
| |
| def handle_blob(entry): |
| length = entry[1] |
| |
| write("\n") |
| indent() |
| |
| value = print_binary_data(read_value(length)) |
| |
| dedent() |
| |
| return value |
| |
| def handle_element(entry): |
| handlers = { |
| 'struct': handle_struct, |
| 'scalar': handle_scalar, |
| 'enum': handle_enum, |
| 'flags': handle_flags, |
| 'ptr': handle_ptr, |
| 'blob': handle_blob, |
| 'array': handle_array, |
| 'byte-array': handle_byte_array, |
| } |
| |
| if not entry[0] in handlers: |
| raise RuntimeError ("unexpected type '%s'" % str (entry[0])) |
| |
| return handlers[entry[0]](entry) |
| |
| if len(sys.argv) <= 1 or sys.argv[1] == '-': |
| import StringIO |
| Input = StringIO.StringIO(sys.stdin.read()) |
| else: |
| Input = open (sys.argv[1], "rb") |
| |
| try: |
| handle_element(file) |
| finally: |
| Input.close() |
| Input = None |