| #!/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 |