OLD | NEW |
| (Empty) |
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 self.is64Bit = None | |
16 | |
17 self.string_table = None | |
18 | |
19 def tell(self): | |
20 return self.file.tell() | |
21 | |
22 def seek(self, pos): | |
23 self.file.seek(pos) | |
24 | |
25 def read(self, N): | |
26 data = self.file.read(N) | |
27 if len(data) != N: | |
28 raise ValueError,"Out of data!" | |
29 return data | |
30 | |
31 def read8(self): | |
32 return ord(self.read(1)) | |
33 | |
34 def read16(self): | |
35 return struct.unpack('><'[self.isLSB] + 'H', self.read(2))[0] | |
36 | |
37 def read32(self): | |
38 # Force to 32-bit, if possible; otherwise these might be long ints on a | |
39 # big-endian platform. FIXME: Why??? | |
40 Value = struct.unpack('><'[self.isLSB] + 'I', self.read(4))[0] | |
41 return int(Value) | |
42 | |
43 def read64(self): | |
44 return struct.unpack('><'[self.isLSB] + 'Q', self.read(8))[0] | |
45 | |
46 def registerStringTable(self, strings): | |
47 if self.string_table is not None: | |
48 raise ValueError,"%s: warning: multiple string tables" % sys.argv[0] | |
49 | |
50 self.string_table = strings | |
51 | |
52 def getString(self, index): | |
53 if self.string_table is None: | |
54 raise ValueError,"%s: warning: no string table registered" % sys.argv[0
] | |
55 ······ | |
56 end = self.string_table.index('\x00', index) | |
57 return self.string_table[index:end] | |
58 | |
59 def dumpmacho(path, opts): | |
60 f = Reader(path) | |
61 | |
62 magic = f.read(4) | |
63 if magic == '\xFE\xED\xFA\xCE': | |
64 f.isLSB, f.is64Bit = False, False | |
65 elif magic == '\xCE\xFA\xED\xFE': | |
66 f.isLSB, f.is64Bit = True, False | |
67 elif magic == '\xFE\xED\xFA\xCF': | |
68 f.isLSB, f.is64Bit = False, True | |
69 elif magic == '\xCF\xFA\xED\xFE': | |
70 f.isLSB, f.is64Bit = True, True | |
71 else: | |
72 raise ValueError,"Not a Mach-O object file: %r (bad magic)" % path | |
73 | |
74 print "('cputype', %r)" % f.read32() | |
75 print "('cpusubtype', %r)" % f.read32() | |
76 filetype = f.read32() | |
77 print "('filetype', %r)" % filetype | |
78 ··· | |
79 numLoadCommands = f.read32() | |
80 print "('num_load_commands', %r)" % filetype | |
81 | |
82 loadCommandsSize = f.read32() | |
83 print "('load_commands_size', %r)" % loadCommandsSize | |
84 | |
85 print "('flag', %r)" % f.read32() | |
86 | |
87 if f.is64Bit: | |
88 print "('reserved', %r)" % f.read32() | |
89 | |
90 start = f.tell() | |
91 | |
92 print "('load_commands', [" | |
93 for i in range(numLoadCommands): | |
94 dumpLoadCommand(f, i, opts) | |
95 print "])" | |
96 | |
97 if f.tell() - start != loadCommandsSize: | |
98 raise ValueError,"%s: warning: invalid load commands size: %r" % ( | |
99 sys.argv[0], loadCommandsSize) | |
100 | |
101 def dumpLoadCommand(f, i, opts): | |
102 start = f.tell() | |
103 | |
104 print " # Load Command %r" % i | |
105 cmd = f.read32() | |
106 print " (('command', %r)" % cmd | |
107 cmdSize = f.read32() | |
108 print " ('size', %r)" % cmdSize | |
109 | |
110 if cmd == 1: | |
111 dumpSegmentLoadCommand(f, opts, False) | |
112 elif cmd == 2: | |
113 dumpSymtabCommand(f, opts) | |
114 elif cmd == 11: | |
115 dumpDysymtabCommand(f, opts) | |
116 elif cmd == 25: | |
117 dumpSegmentLoadCommand(f, opts, True) | |
118 elif cmd == 27: | |
119 import uuid | |
120 print " ('uuid', %s)" % uuid.UUID(bytes=f.read(16)) | |
121 else: | |
122 print >>sys.stderr,"%s: warning: unknown load command: %r" % ( | |
123 sys.argv[0], cmd) | |
124 f.read(cmdSize - 8) | |
125 print " )," | |
126 | |
127 if f.tell() - start != cmdSize: | |
128 raise ValueError,"%s: warning: invalid load command size: %r" % ( | |
129 sys.argv[0], cmdSize) | |
130 | |
131 def dumpSegmentLoadCommand(f, opts, is64Bit): | |
132 print " ('segment_name', %r)" % f.read(16)· | |
133 if is64Bit: | |
134 print " ('vm_addr', %r)" % f.read64() | |
135 print " ('vm_size', %r)" % f.read64() | |
136 print " ('file_offset', %r)" % f.read64() | |
137 print " ('file_size', %r)" % f.read64() | |
138 else: | |
139 print " ('vm_addr', %r)" % f.read32() | |
140 print " ('vm_size', %r)" % f.read32() | |
141 print " ('file_offset', %r)" % f.read32() | |
142 print " ('file_size', %r)" % f.read32() | |
143 print " ('maxprot', %r)" % f.read32() | |
144 print " ('initprot', %r)" % f.read32() | |
145 numSections = f.read32() | |
146 print " ('num_sections', %r)" % numSections | |
147 print " ('flags', %r)" % f.read32() | |
148 | |
149 print " ('sections', [" | |
150 for i in range(numSections): | |
151 dumpSection(f, i, opts, is64Bit) | |
152 print " ])" | |
153 | |
154 def dumpSymtabCommand(f, opts): | |
155 symoff = f.read32() | |
156 print " ('symoff', %r)" % symoff | |
157 nsyms = f.read32() | |
158 print " ('nsyms', %r)" % nsyms | |
159 stroff = f.read32() | |
160 print " ('stroff', %r)" % stroff | |
161 strsize = f.read32() | |
162 print " ('strsize', %r)" % strsize | |
163 | |
164 prev_pos = f.tell() | |
165 | |
166 f.seek(stroff) | |
167 string_data = f.read(strsize) | |
168 print " ('_string_data', %r)" % string_data | |
169 | |
170 f.registerStringTable(string_data) | |
171 | |
172 f.seek(symoff) | |
173 print " ('_symbols', [" | |
174 for i in range(nsyms): | |
175 dumpNlist32(f, i, opts) | |
176 print " ])" | |
177 ······ | |
178 f.seek(prev_pos) | |
179 | |
180 def dumpNlist32(f, i, opts): | |
181 print " # Symbol %r" % i | |
182 n_strx = f.read32() | |
183 print " (('n_strx', %r)" % n_strx | |
184 n_type = f.read8() | |
185 print " ('n_type', %#x)" % n_type | |
186 n_sect = f.read8() | |
187 print " ('n_sect', %r)" % n_sect | |
188 n_desc = f.read16() | |
189 print " ('n_desc', %r)" % n_desc | |
190 if f.is64Bit: | |
191 n_value = f.read64() | |
192 print " ('n_value', %r)" % n_value | |
193 else: | |
194 n_value = f.read32() | |
195 print " ('n_value', %r)" % n_value | |
196 print " ('_string', %r)" % f.getString(n_strx) | |
197 print " )," | |
198 | |
199 def dumpDysymtabCommand(f, opts):··· | |
200 print " ('ilocalsym', %r)" % f.read32() | |
201 print " ('nlocalsym', %r)" % f.read32() | |
202 print " ('iextdefsym', %r)" % f.read32() | |
203 print " ('nextdefsym', %r)" % f.read32() | |
204 print " ('iundefsym', %r)" % f.read32() | |
205 print " ('nundefsym', %r)" % f.read32() | |
206 print " ('tocoff', %r)" % f.read32() | |
207 print " ('ntoc', %r)" % f.read32() | |
208 print " ('modtaboff', %r)" % f.read32() | |
209 print " ('nmodtab', %r)" % f.read32() | |
210 print " ('extrefsymoff', %r)" % f.read32() | |
211 print " ('nextrefsyms', %r)" % f.read32() | |
212 indirectsymoff = f.read32() | |
213 print " ('indirectsymoff', %r)" % indirectsymoff | |
214 nindirectsyms = f.read32() | |
215 print " ('nindirectsyms', %r)" % nindirectsyms | |
216 print " ('extreloff', %r)" % f.read32() | |
217 print " ('nextrel', %r)" % f.read32() | |
218 print " ('locreloff', %r)" % f.read32() | |
219 print " ('nlocrel', %r)" % f.read32() | |
220 | |
221 prev_pos = f.tell() | |
222 | |
223 f.seek(indirectsymoff) | |
224 print " ('_indirect_symbols', [" | |
225 for i in range(nindirectsyms): | |
226 print " # Indirect Symbol %r" % i | |
227 print " (('symbol_index', %#x),)," % f.read32() | |
228 print " ])" | |
229 ······ | |
230 f.seek(prev_pos) | |
231 | |
232 def dumpSection(f, i, opts, is64Bit): | |
233 print " # Section %r" % i | |
234 print " (('section_name', %r)" % f.read(16) | |
235 print " ('segment_name', %r)" % f.read(16) | |
236 if is64Bit: | |
237 print " ('address', %r)" % f.read64() | |
238 size = f.read64() | |
239 print " ('size', %r)" % size | |
240 else: | |
241 print " ('address', %r)" % f.read32() | |
242 size = f.read32() | |
243 print " ('size', %r)" % size | |
244 offset = f.read32() | |
245 print " ('offset', %r)" % offset | |
246 print " ('alignment', %r)" % f.read32()··· | |
247 reloc_offset = f.read32() | |
248 print " ('reloc_offset', %r)" % reloc_offset | |
249 num_reloc = f.read32() | |
250 print " ('num_reloc', %r)" % num_reloc | |
251 print " ('flags', %#x)" % f.read32() | |
252 print " ('reserved1', %r)" % f.read32() | |
253 print " ('reserved2', %r)" % f.read32() | |
254 if is64Bit: | |
255 print " ('reserved3', %r)" % f.read32() | |
256 print " )," | |
257 | |
258 prev_pos = f.tell() | |
259 | |
260 f.seek(reloc_offset) | |
261 print " ('_relocations', [" | |
262 for i in range(num_reloc): | |
263 print " # Relocation %r" % i | |
264 print " (('word-0', %#x)," % f.read32() | |
265 print " ('word-1', %#x))," % f.read32() | |
266 print " ])" | |
267 | |
268 if opts.dumpSectionData: | |
269 f.seek(offset) | |
270 print " ('_section_data', %r)" % f.read(size) | |
271 ······ | |
272 f.seek(prev_pos) | |
273 ··· | |
274 def main(): | |
275 from optparse import OptionParser, OptionGroup | |
276 parser = OptionParser("usage: %prog [options] {files}") | |
277 parser.add_option("", "--dump-section-data", dest="dumpSectionData", | |
278 help="Dump the contents of sections", | |
279 action="store_true", default=False)···· | |
280 (opts, args) = parser.parse_args() | |
281 | |
282 if not args: | |
283 args.append('-') | |
284 | |
285 for arg in args: | |
286 dumpmacho(arg, opts) | |
287 | |
288 if __name__ == '__main__': | |
289 main() | |
OLD | NEW |