1#!/usr/bin/env python
2#===-- coff-dump.py - COFF object file dump utility-------------------------===#
3#
4#                     The LLVM Compiler Infrastructure
5#
6# This file is distributed under the University of Illinois Open Source
7# License. See LICENSE.TXT for details.
8#
9#===------------------------------------------------------------------------===#
10
11#
12# COFF File Definition
13#
14
15def string_table_entry (offset):
16  return ('ptr', '+ + PointerToSymbolTable * NumberOfSymbols 18 %s' % offset, ('scalar', 'cstr', '%s'))
17
18def secname(value):
19  if value[0] == '/':
20    return string_table_entry(value[1:].rstrip('\0'))
21  else:
22    return '%s'
23
24def symname(value):
25  parts = struct.unpack("<2L", value)
26  if parts[0] == 0:
27    return string_table_entry(parts[1])
28  else:
29    return '%s'
30
31file = ('struct', [
32  ('MachineType', ('enum', '<H', '0x%X', {
33    0x0:    'IMAGE_FILE_MACHINE_UNKNOWN',
34    0x1d3:  'IMAGE_FILE_MACHINE_AM33',
35    0x8664: 'IMAGE_FILE_MACHINE_AMD64',
36    0x1c0:  'IMAGE_FILE_MACHINE_ARM',
37    0xebc:  'IMAGE_FILE_MACHINE_EBC',
38    0x14c:  'IMAGE_FILE_MACHINE_I386',
39    0x200:  'IMAGE_FILE_MACHINE_IA64',
40    0x904:  'IMAGE_FILE_MACHINE_M32R',
41    0x266:  'IMAGE_FILE_MACHINE_MIPS16',
42    0x366:  'IMAGE_FILE_MACHINE_MIPSFPU',
43    0x466:  'IMAGE_FILE_MACHINE_MIPSFPU16',
44    0x1f0:  'IMAGE_FILE_MACHINE_POWERPC',
45    0x1f1:  'IMAGE_FILE_MACHINE_POWERPCFP',
46    0x166:  'IMAGE_FILE_MACHINE_R4000',
47    0x1a2:  'IMAGE_FILE_MACHINE_SH3',
48    0x1a3:  'IMAGE_FILE_MACHINE_SH3DSP',
49    0x1a6:  'IMAGE_FILE_MACHINE_SH4',
50    0x1a8:  'IMAGE_FILE_MACHINE_SH5',
51    0x1c2:  'IMAGE_FILE_MACHINE_THUMB',
52    0x169:  'IMAGE_FILE_MACHINE_WCEMIPSV2',
53  })),
54  ('NumberOfSections',     ('scalar',  '<H', '%d')),
55  ('TimeDateStamp',        ('scalar',  '<L', '%d')),
56  ('PointerToSymbolTable', ('scalar',  '<L', '0x%0X')),
57  ('NumberOfSymbols',      ('scalar',  '<L', '%d')),
58  ('SizeOfOptionalHeader', ('scalar',  '<H', '%d')),
59  ('Characteristics',      ('flags',   '<H', '0x%x', [
60    (0x0001,      'IMAGE_FILE_RELOCS_STRIPPED',         ),
61    (0x0002,      'IMAGE_FILE_EXECUTABLE_IMAGE',        ),
62    (0x0004,      'IMAGE_FILE_LINE_NUMS_STRIPPED',      ),
63    (0x0008,      'IMAGE_FILE_LOCAL_SYMS_STRIPPED',     ),
64    (0x0010,      'IMAGE_FILE_AGGRESSIVE_WS_TRIM',      ),
65    (0x0020,      'IMAGE_FILE_LARGE_ADDRESS_AWARE',     ),
66    (0x0080,      'IMAGE_FILE_BYTES_REVERSED_LO',       ),
67    (0x0100,      'IMAGE_FILE_32BIT_MACHINE',           ),
68    (0x0200,      'IMAGE_FILE_DEBUG_STRIPPED',          ),
69    (0x0400,      'IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP', ),
70    (0x0800,      'IMAGE_FILE_NET_RUN_FROM_SWAP',       ),
71    (0x1000,      'IMAGE_FILE_SYSTEM',                  ),
72    (0x2000,      'IMAGE_FILE_DLL',                     ),
73    (0x4000,      'IMAGE_FILE_UP_SYSTEM_ONLY',          ),
74    (0x8000,      'IMAGE_FILE_BYTES_REVERSED_HI',       ),
75  ])),
76  ('Sections', ('array', '1', 'NumberOfSections', ('struct', [
77    ('Name',                 ('scalar',  '<8s', secname)),
78    ('VirtualSize',          ('scalar',  '<L',  '%d'   )),
79    ('VirtualAddress',       ('scalar',  '<L',  '%d'   )),
80    ('SizeOfRawData',        ('scalar',  '<L',  '%d'   )),
81    ('PointerToRawData',     ('scalar',  '<L',  '0x%X' )),
82    ('PointerToRelocations', ('scalar',  '<L',  '0x%X' )),
83    ('PointerToLineNumbers', ('scalar',  '<L',  '0x%X' )),
84    ('NumberOfRelocations',  ('scalar',  '<H',  '%d'   )),
85    ('NumberOfLineNumbers',  ('scalar',  '<H',  '%d'   )),
86    ('Charateristics',       ('flags',   '<L',  '0x%X', [
87      (0x00000008, 'IMAGE_SCN_TYPE_NO_PAD'),
88      (0x00000020, 'IMAGE_SCN_CNT_CODE'),
89      (0x00000040, 'IMAGE_SCN_CNT_INITIALIZED_DATA'),
90      (0x00000080, 'IMAGE_SCN_CNT_UNINITIALIZED_DATA'),
91      (0x00000100, 'IMAGE_SCN_LNK_OTHER'),
92      (0x00000200, 'IMAGE_SCN_LNK_INFO'),
93      (0x00000800, 'IMAGE_SCN_LNK_REMOVE'),
94      (0x00001000, 'IMAGE_SCN_LNK_COMDAT'),
95      (0x00008000, 'IMAGE_SCN_GPREL'),
96      (0x00020000, 'IMAGE_SCN_MEM_PURGEABLE'),
97      (0x00020000, 'IMAGE_SCN_MEM_16BIT'),
98      (0x00040000, 'IMAGE_SCN_MEM_LOCKED'),
99      (0x00080000, 'IMAGE_SCN_MEM_PRELOAD'),
100      (0x00F00000, 'IMAGE_SCN_ALIGN', {
101        0x00100000: 'IMAGE_SCN_ALIGN_1BYTES',
102        0x00200000: 'IMAGE_SCN_ALIGN_2BYTES',
103        0x00300000: 'IMAGE_SCN_ALIGN_4BYTES',
104        0x00400000: 'IMAGE_SCN_ALIGN_8BYTES',
105        0x00500000: 'IMAGE_SCN_ALIGN_16BYTES',
106        0x00600000: 'IMAGE_SCN_ALIGN_32BYTES',
107        0x00700000: 'IMAGE_SCN_ALIGN_64BYTES',
108        0x00800000: 'IMAGE_SCN_ALIGN_128BYTES',
109        0x00900000: 'IMAGE_SCN_ALIGN_256BYTES',
110        0x00A00000: 'IMAGE_SCN_ALIGN_512BYTES',
111        0x00B00000: 'IMAGE_SCN_ALIGN_1024BYTES',
112        0x00C00000: 'IMAGE_SCN_ALIGN_2048BYTES',
113        0x00D00000: 'IMAGE_SCN_ALIGN_4096BYTES',
114        0x00E00000: 'IMAGE_SCN_ALIGN_8192BYTES',
115      }),
116      (0x01000000, 'IMAGE_SCN_LNK_NRELOC_OVFL'),
117      (0x02000000, 'IMAGE_SCN_MEM_DISCARDABLE'),
118      (0x04000000, 'IMAGE_SCN_MEM_NOT_CACHED'),
119      (0x08000000, 'IMAGE_SCN_MEM_NOT_PAGED'),
120      (0x10000000, 'IMAGE_SCN_MEM_SHARED'),
121      (0x20000000, 'IMAGE_SCN_MEM_EXECUTE'),
122      (0x40000000, 'IMAGE_SCN_MEM_READ'),
123      (0x80000000, 'IMAGE_SCN_MEM_WRITE'),
124    ])),
125    ('SectionData', ('ptr', 'PointerToRawData', ('blob', 'SizeOfRawData'))),
126    ('Relocations', ('ptr', 'PointerToRelocations', ('array', '0', 'NumberOfRelocations', ('struct', [
127      ('VirtualAddress',   ('scalar', '<L', '0x%X')),
128      ('SymbolTableIndex', ('scalar', '<L', '%d'  )),
129      ('Type',             ('enum', '<H', '%d', ('MachineType', {
130        0x14c: {
131          0x0000: 'IMAGE_REL_I386_ABSOLUTE',
132          0x0001: 'IMAGE_REL_I386_DIR16',
133          0x0002: 'IMAGE_REL_I386_REL16',
134          0x0006: 'IMAGE_REL_I386_DIR32',
135          0x0007: 'IMAGE_REL_I386_DIR32NB',
136          0x0009: 'IMAGE_REL_I386_SEG12',
137          0x000A: 'IMAGE_REL_I386_SECTION',
138          0x000B: 'IMAGE_REL_I386_SECREL',
139          0x000C: 'IMAGE_REL_I386_TOKEN',
140          0x000D: 'IMAGE_REL_I386_SECREL7',
141          0x0014: 'IMAGE_REL_I386_REL32',
142        },
143        0x8664: {
144          0x0000: 'IMAGE_REL_AMD64_ABSOLUTE',
145          0x0001: 'IMAGE_REL_AMD64_ADDR64',
146          0x0002: 'IMAGE_REL_AMD64_ADDR32',
147          0x0003: 'IMAGE_REL_AMD64_ADDR32NB',
148          0x0004: 'IMAGE_REL_AMD64_REL32',
149          0x0005: 'IMAGE_REL_AMD64_REL32_1',
150          0x0006: 'IMAGE_REL_AMD64_REL32_2',
151          0x0007: 'IMAGE_REL_AMD64_REL32_3',
152          0x0008: 'IMAGE_REL_AMD64_REL32_4',
153          0x0009: 'IMAGE_REL_AMD64_REL32_5',
154          0x000A: 'IMAGE_REL_AMD64_SECTION',
155          0x000B: 'IMAGE_REL_AMD64_SECREL',
156          0x000C: 'IMAGE_REL_AMD64_SECREL7',
157          0x000D: 'IMAGE_REL_AMD64_TOKEN',
158          0x000E: 'IMAGE_REL_AMD64_SREL32',
159          0x000F: 'IMAGE_REL_AMD64_PAIR',
160          0x0010: 'IMAGE_REL_AMD64_SSPAN32',
161        },
162      }))),
163      ('SymbolName',       ('ptr', '+ PointerToSymbolTable * SymbolTableIndex 18', ('scalar',  '<8s', symname)))
164    ])))),
165  ]))),
166  ('Symbols', ('ptr', 'PointerToSymbolTable', ('byte-array', '18', '* NumberOfSymbols 18',  ('struct', [
167    ('Name',                ('scalar',  '<8s', symname)),
168    ('Value',               ('scalar',  '<L',  '%d'   )),
169    ('SectionNumber',       ('scalar',  '<H',  '%d'   )),
170    ('_Type',               ('scalar',  '<H',  None   )),
171    ('SimpleType',          ('enum',    '& _Type 15',  '%d', {
172      0: 'IMAGE_SYM_TYPE_NULL',
173      1: 'IMAGE_SYM_TYPE_VOID',
174      2: 'IMAGE_SYM_TYPE_CHAR',
175      3: 'IMAGE_SYM_TYPE_SHORT',
176      4: 'IMAGE_SYM_TYPE_INT',
177      5: 'IMAGE_SYM_TYPE_LONG',
178      6: 'IMAGE_SYM_TYPE_FLOAT',
179      7: 'IMAGE_SYM_TYPE_DOUBLE',
180      8: 'IMAGE_SYM_TYPE_STRUCT',
181      9: 'IMAGE_SYM_TYPE_UNION',
182      10: 'IMAGE_SYM_TYPE_ENUM',
183      11: 'IMAGE_SYM_TYPE_MOE',
184      12: 'IMAGE_SYM_TYPE_BYTE',
185      13: 'IMAGE_SYM_TYPE_WORD',
186      14: 'IMAGE_SYM_TYPE_UINT',
187      15: 'IMAGE_SYM_TYPE_DWORD',
188    })),                                # (Type & 0xF0) >> 4
189    ('ComplexType',         ('enum',    '>> & _Type 240 4',  '%d', {
190      0: 'IMAGE_SYM_DTYPE_NULL',
191      1: 'IMAGE_SYM_DTYPE_POINTER',
192      2: 'IMAGE_SYM_DTYPE_FUNCTION',
193      3: 'IMAGE_SYM_DTYPE_ARRAY',
194    })),
195    ('StorageClass',        ('enum',    '<B',  '%d', {
196      -1:  'IMAGE_SYM_CLASS_END_OF_FUNCTION',
197      0: 'IMAGE_SYM_CLASS_NULL',
198      1: 'IMAGE_SYM_CLASS_AUTOMATIC',
199      2: 'IMAGE_SYM_CLASS_EXTERNAL',
200      3: 'IMAGE_SYM_CLASS_STATIC',
201      4: 'IMAGE_SYM_CLASS_REGISTER',
202      5: 'IMAGE_SYM_CLASS_EXTERNAL_DEF',
203      6: 'IMAGE_SYM_CLASS_LABEL',
204      7: 'IMAGE_SYM_CLASS_UNDEFINED_LABEL',
205      8: 'IMAGE_SYM_CLASS_MEMBER_OF_STRUCT',
206      9: 'IMAGE_SYM_CLASS_ARGUMENT',
207      10: 'IMAGE_SYM_CLASS_STRUCT_TAG',
208      11: 'IMAGE_SYM_CLASS_MEMBER_OF_UNION',
209      12: 'IMAGE_SYM_CLASS_UNION_TAG',
210      13: 'IMAGE_SYM_CLASS_TYPE_DEFINITION',
211      14: 'IMAGE_SYM_CLASS_UNDEFINED_STATIC',
212      15: 'IMAGE_SYM_CLASS_ENUM_TAG',
213      16: 'IMAGE_SYM_CLASS_MEMBER_OF_ENUM',
214      17: 'IMAGE_SYM_CLASS_REGISTER_PARAM',
215      18: 'IMAGE_SYM_CLASS_BIT_FIELD',
216      100: 'IMAGE_SYM_CLASS_BLOCK',
217      101: 'IMAGE_SYM_CLASS_FUNCTION',
218      102: 'IMAGE_SYM_CLASS_END_OF_STRUCT',
219      103: 'IMAGE_SYM_CLASS_FILE',
220      104: 'IMAGE_SYM_CLASS_SECTION',
221      105: 'IMAGE_SYM_CLASS_WEAK_EXTERNAL',
222      107: 'IMAGE_SYM_CLASS_CLR_TOKEN',
223    })),
224    ('NumberOfAuxSymbols',  ('scalar',  '<B',  '%d'  )),
225    ('AuxillaryData', ('blob', '* NumberOfAuxSymbols 18')),
226  ])))),
227])
228
229#
230# Definition Interpreter
231#
232
233import sys, types, struct, re
234
235Input = None
236Stack = []
237Fields = {}
238
239Indent = 0
240NewLine = True
241
242def indent():
243  global Indent
244  Indent += 1
245
246def dedent():
247  global Indent
248  Indent -= 1
249
250def write(input):
251  global NewLine
252  output = ""
253
254  for char in input:
255
256    if NewLine:
257      output += Indent * '  '
258      NewLine = False
259
260    output += char
261
262    if char == '\n':
263      NewLine = True
264
265  sys.stdout.write(output)
266
267def read(format):
268  return struct.unpack(format, Input.read(struct.calcsize(format)))
269
270def read_cstr():
271  output = ""
272  while True:
273    char = Input.read(1)
274    if len(char) == 0:
275      raise RuntimeError ("EOF while reading cstr")
276    if char == '\0':
277      break
278    output += char
279  return output
280
281def push_pos(seek_to = None):
282  Stack [0:0] = [Input.tell()]
283  if seek_to:
284    Input.seek(seek_to)
285
286def pop_pos():
287  assert(len(Stack) > 0)
288  Input.seek(Stack[0])
289  del Stack[0]
290
291def print_binary_data(size):
292  value = ""
293  while size > 0:
294    if size >= 16:
295      data = Input.read(16)
296      size -= 16
297    else:
298      data = Input.read(size)
299      size = 0
300    value += data
301    bytes = ""
302    text = ""
303    for index in xrange(16):
304      if index < len(data):
305        if index == 8:
306          bytes += "- "
307        ch = ord(data[index])
308        bytes += "%02X " % ch
309        if ch >= 0x20 and ch <= 0x7F:
310          text += data[index]
311        else:
312          text += "."
313      else:
314        if index == 8:
315          bytes += "  "
316        bytes += "   "
317
318    write("%s|%s|\n" % (bytes, text))
319  return value
320
321idlit = re.compile("[a-zA-Z_][a-zA-Z0-9_-]*")
322numlit = re.compile("[0-9]+")
323
324def read_value(expr):
325
326  input = iter(expr.split())
327
328  def eval():
329
330    token = input.next()
331
332    if expr == 'cstr':
333      return read_cstr()
334    if expr == 'true':
335      return True
336    if expr == 'false':
337      return False
338
339    if token == '+':
340      return eval() + eval()
341    if token == '-':
342      return eval() - eval()
343    if token == '*':
344      return eval() * eval()
345    if token == '/':
346      return eval() / eval()
347    if token == '&':
348      return eval() & eval()
349    if token == '|':
350      return eval() | eval()
351    if token == '>>':
352      return eval() >> eval()
353    if token == '<<':
354      return eval() << eval()
355
356    if len(token) > 1 and token[0] in ('=', '@', '<', '!', '>'):
357      val = read(expr)
358      assert(len(val) == 1)
359      return val[0]
360
361    if idlit.match(token):
362      return Fields[token]
363    if numlit.match(token):
364      return int(token)
365
366    raise RuntimeError("unexpected token %s" % repr(token))
367
368  value = eval()
369
370  try:
371    input.next()
372  except StopIteration:
373    return value
374  raise RuntimeError("unexpected input at end of expression")
375
376def write_value(format,value):
377  format_type = type(format)
378  if format_type is types.StringType:
379    write(format % value)
380  elif format_type is types.FunctionType:
381    write_value(format(value), value)
382  elif format_type is types.TupleType:
383    Fields['this'] = value
384    handle_element(format)
385  elif format_type is types.NoneType:
386    pass
387  else:
388    raise RuntimeError("unexpected type: %s" % repr(format_type))
389
390def handle_scalar(entry):
391  iformat = entry[1]
392  oformat = entry[2]
393
394  value = read_value(iformat)
395
396  write_value(oformat, value)
397
398  return value
399
400def handle_enum(entry):
401  iformat = entry[1]
402  oformat = entry[2]
403  definitions = entry[3]
404
405  value = read_value(iformat)
406
407  if type(definitions) is types.TupleType:
408    selector = read_value(definitions[0])
409    definitions = definitions[1][selector]
410
411  if value in definitions:
412    description = definitions[value]
413  else:
414    description = "unknown"
415
416  write("%s (" % description)
417  write_value(oformat, value)
418  write(")")
419
420  return value
421
422def handle_flags(entry):
423  iformat = entry[1]
424  oformat = entry[2]
425  definitions = entry[3]
426
427  value = read_value(iformat)
428
429  write_value(oformat, value)
430
431  indent()
432  for entry in definitions:
433    mask = entry[0]
434    name = entry[1]
435    if len (entry) == 3:
436      map = entry[2]
437      selection = value & mask
438      if selection in map:
439        write("\n%s" % map[selection])
440      else:
441        write("\n%s <%d>" % (name, selection))
442    elif len(entry) == 2:
443      if value & mask != 0:
444        write("\n%s" % name)
445  dedent()
446
447  return value
448
449def handle_struct(entry):
450  global Fields
451  members = entry[1]
452
453  newFields = {}
454
455  write("{\n");
456  indent()
457
458  for member in members:
459    name = member[0]
460    type = member[1]
461
462    if name[0] != "_":
463      write("%s = " % name.ljust(24))
464
465    value = handle_element(type)
466
467    if name[0] != "_":
468      write("\n")
469
470    Fields[name] = value
471    newFields[name] = value
472
473  dedent()
474  write("}")
475
476  return newFields
477
478def handle_array(entry):
479  start_index = entry[1]
480  length = entry[2]
481  element = entry[3]
482
483  newItems = []
484
485  write("[\n")
486  indent()
487
488  start_index = read_value(start_index)
489  value = read_value(length)
490
491  for index in xrange(value):
492    write("%d = " % (index + start_index))
493    value = handle_element(element)
494    write("\n")
495    newItems.append(value)
496
497  dedent()
498  write("]")
499
500  return newItems
501
502def handle_byte_array(entry):
503  ent_size = entry[1]
504  length = entry[2]
505  element = entry[3]
506
507  newItems = []
508
509  write("[\n")
510  indent()
511
512  item_size = read_value(ent_size)
513  value = read_value(length)
514  end_of_array = Input.tell() + value
515
516  prev_loc = Input.tell()
517  index = 0
518  while Input.tell() < end_of_array:
519    write("%d = " % index)
520    value = handle_element(element)
521    write("\n")
522    newItems.append(value)
523    index += (Input.tell() - prev_loc) / item_size
524    prev_loc = Input.tell()
525
526  dedent()
527  write("]")
528
529  return newItems
530
531def handle_ptr(entry):
532  offset = entry[1]
533  element = entry[2]
534
535  value = None
536  offset = read_value(offset)
537
538  if offset != 0:
539
540    push_pos(offset)
541
542    value = handle_element(element)
543
544    pop_pos()
545
546  else:
547    write("None")
548
549  return value
550
551def handle_blob(entry):
552  length = entry[1]
553
554  write("\n")
555  indent()
556
557  value = print_binary_data(read_value(length))
558
559  dedent()
560
561  return value
562
563def handle_element(entry):
564  handlers = {
565    'struct':      handle_struct,
566    'scalar':      handle_scalar,
567    'enum':        handle_enum,
568    'flags':       handle_flags,
569    'ptr':         handle_ptr,
570    'blob':        handle_blob,
571    'array':       handle_array,
572    'byte-array':  handle_byte_array,
573  }
574
575  if not entry[0] in handlers:
576    raise RuntimeError ("unexpected type '%s'" % str (entry[0]))
577
578  return handlers[entry[0]](entry)
579
580if len(sys.argv) <= 1 or sys.argv[1] == '-':
581  import StringIO
582  Input = StringIO.StringIO(sys.stdin.read())
583else:
584  Input = open (sys.argv[1], "rb")
585
586try:
587  handle_element(file)
588finally:
589  Input.close()
590  Input = None
591