llvm-mc: Clean up some handling of symbol/section association to be more correct
[oota-llvm.git] / test / Scripts / macho-dump
1 #!/usr/bin/env python
2
3 import struct
4 import sys
5 import StringIO
6
7 class Reader:
8    def __init__(self, path):
9       if path == '-':
10          # Snarf all the data so we can seek.
11          self.file = StringIO.StringIO(sys.stdin.read())
12       else:
13          self.file = open(path,'rb')
14       self.isLSB = None
15
16       self.string_table = None
17
18    def setLSB(self, isLSB):
19       self.isLSB = bool(isLSB)
20
21    def tell(self):
22       return self.file.tell()
23
24    def seek(self, pos):
25       self.file.seek(pos)
26
27    def read(self, N):
28       data = self.file.read(N)
29       if len(data) != N:
30          raise ValueError,"Out of data!"
31       return data
32
33    def read8(self):
34       return ord(self.read(1))
35
36    def read16(self):
37       return struct.unpack('><'[self.isLSB] + 'H', self.read(2))[0]
38
39    def read32(self):
40       return struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0]
41
42    def registerStringTable(self, strings):
43       if self.string_table is not None:
44          raise ValueError,"%s: warning: multiple string tables" % sys.argv[0]
45
46       self.string_table = strings
47
48    def getString(self, index):
49       if self.string_table is None:
50          raise ValueError,"%s: warning: no string table registered" % sys.argv[0]
51       
52       end = self.string_table.index('\x00', index)
53       return self.string_table[index:end]
54
55 def dumpmacho(path, opts):
56    f = Reader(path)
57
58    magic = f.read(4)
59    if magic == '\xFE\xED\xFA\xCE':
60       f.setLSB(False)
61    elif magic == '\xCE\xFA\xED\xFE':
62       f.setLSB(True)
63    else:
64       raise ValueError,"Not a Mach-O object file: %r (bad magic)" % path
65
66    print "('cputype', %r)" % f.read32()
67    print "('cpusubtype', %r)" % f.read32()
68    filetype = f.read32()
69    print "('filetype', %r)" % filetype
70    
71    numLoadCommands = f.read32()
72    print "('num_load_commands', %r)" % filetype
73
74    loadCommandsSize = f.read32()
75    print "('load_commands_size', %r)" % loadCommandsSize
76
77    print "('flag', %r)" % f.read32()
78
79    start = f.tell()
80
81    print "('load_commands', ["
82    for i in range(numLoadCommands):
83       dumpLoadCommand(f, i, opts)
84    print "])"
85
86    if f.tell() - start != loadCommandsSize:
87       raise ValueError,"%s: warning: invalid load commands size: %r" % (sys.argv[0], loadCommandsSize)
88
89 def dumpLoadCommand(f, i, opts):
90    start = f.tell()
91
92    print "  # Load Command %r" % i
93    cmd = f.read32()
94    print " (('command', %r)" % cmd
95    cmdSize = f.read32()
96    print "  ('size', %r)" % cmdSize
97
98    if cmd == 1:
99       dumpSegmentLoadCommand32(f, opts)
100    elif cmd == 2:
101       dumpSymtabCommand(f, opts)
102    elif cmd == 11:
103       dumpDysymtabCommand(f, opts)
104    else:
105       print >>sys.stderr,"%s: warning: unknown load command: %r" % (sys.argv[0], cmd)
106       f.read(cmdSize - 8)
107    print " ),"
108
109    if f.tell() - start != cmdSize:
110       raise ValueError,"%s: warning: invalid load command size: %r" % (sys.argv[0], cmdSize)
111
112 def dumpSegmentLoadCommand32(f, opts):
113    print "  ('segment_name', %r)" % f.read(16) 
114    print "  ('vm_addr', %r)" % f.read32()
115    print "  ('vm_size', %r)" % f.read32()
116    print "  ('file_offset', %r)" % f.read32()
117    print "  ('file_size', %r)" % f.read32()
118    print "  ('maxprot', %r)" % f.read32()
119    print "  ('initprot', %r)" % f.read32()
120    numSections = f.read32()
121    print "  ('num_sections', %r)" % numSections
122    print "  ('flags', %r)" % f.read32()
123
124    print "  ('sections', ["
125    for i in range(numSections):
126       dumpSection32(f, i, opts)
127    print "  ])"
128
129 def dumpSymtabCommand(f, opts):
130    symoff = f.read32()
131    print "  ('symoff', %r)" % symoff
132    nsyms = f.read32()
133    print "  ('nsyms', %r)" % nsyms
134    stroff = f.read32()
135    print "  ('stroff', %r)" % stroff
136    strsize = f.read32()
137    print "  ('strsize', %r)" % strsize
138
139    prev_pos = f.tell()
140
141    f.seek(stroff)
142    string_data = f.read(strsize)
143    print "  ('_string_data', %r)" % string_data
144
145    f.registerStringTable(string_data)
146
147    f.seek(symoff)
148    print "  ('_symbols', ["
149    for i in range(nsyms):
150       dumpNlist32(f, i, opts)
151    print "  ])"
152       
153    f.seek(prev_pos)
154
155 def dumpNlist32(f, i, opts):
156    print "    # Symbol %r" % i
157    n_strx = f.read32()
158    print "   (('n_strx', %r)" % n_strx
159    n_type = f.read8()
160    print "    ('n_type', %#x)" % n_type
161    n_sect = f.read8()
162    print "    ('n_type', %r)" % n_sect
163    n_desc = f.read16()
164    print "    ('n_desc', %r)" % n_desc
165    n_value = f.read32()
166    print "    ('n_value', %r)" % n_value
167    print "    ('_string', %r)" % f.getString(n_strx)
168    print "   ),"
169
170 def dumpDysymtabCommand(f, opts):   
171    print "  ('ilocalsym', %r)" % f.read32()
172    print "  ('nlocalsym', %r)" % f.read32()
173    print "  ('iextdefsym', %r)" % f.read32()
174    print "  ('nextdefsym', %r)" % f.read32()
175    print "  ('iundefsym', %r)" % f.read32()
176    print "  ('nundefsym', %r)" % f.read32()
177    print "  ('tocoff', %r)" % f.read32()
178    print "  ('ntoc', %r)" % f.read32()
179    print "  ('modtaboff', %r)" % f.read32()
180    print "  ('nmodtab', %r)" % f.read32()
181    print "  ('extrefsymoff', %r)" % f.read32()
182    print "  ('nextrefsyms', %r)" % f.read32()
183    indirectsymoff = f.read32()
184    print "  ('indirectsymoff', %r)" % indirectsymoff
185    nindirectsyms = f.read32()
186    print "  ('nindirectsyms', %r)" % nindirectsyms
187    print "  ('extreloff', %r)" % f.read32()
188    print "  ('nextrel', %r)" % f.read32()
189    print "  ('locreloff', %r)" % f.read32()
190    print "  ('nlocrel', %r)" % f.read32()
191
192    prev_pos = f.tell()
193
194    f.seek(indirectsymoff)
195    print "  ('_indirect_symbols', ["
196    for i in range(nindirectsyms):
197       print "    # Indirect Symbol %r" % i
198       print "    (('symbol_index', %r),)," % f.read32()
199    print "  ])"
200       
201    f.seek(prev_pos)
202
203 def dumpSection32(f, i, opts):
204    print "    # Section %r" % i
205    print "   (('section_name', %r)" % f.read(16)
206    print "    ('segment_name', %r)" % f.read(16)
207    print "    ('address', %r)" % f.read32()
208    print "    ('size', %r)" % f.read32()
209    print "    ('offset', %r)" % f.read32()
210    print "    ('alignment', %r)" % f.read32()
211    print "    ('reloc_offset', %r)" % f.read32()
212    print "    ('num_reloc', %r)" % f.read32()
213    print "    ('flags', %#x)" % f.read32()
214    print "    ('reserved1', %r)" % f.read32()
215    print "    ('reserved2', %r)" % f.read32()
216    print "   ),"
217    
218 def main():
219     from optparse import OptionParser, OptionGroup
220     parser = OptionParser("usage: %prog [options] {files}")
221
222     (opts, args) = parser.parse_args()
223
224     if not args:
225        args.append('-')
226
227     for arg in args:
228        dumpmacho(arg, opts)
229
230 if __name__ == '__main__':
231    main()