xref: /openbsd-src/gnu/llvm/lldb/examples/python/mach_o.py (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1*be691f3bSpatrick#!/usr/bin/env python
2061da546Spatrick
3061da546Spatrickimport cmd
4061da546Spatrickimport dict_utils
5061da546Spatrickimport file_extract
6061da546Spatrickimport optparse
7061da546Spatrickimport re
8061da546Spatrickimport struct
9061da546Spatrickimport string
10061da546Spatrickimport io
11061da546Spatrickimport sys
12061da546Spatrickimport uuid
13061da546Spatrick
14061da546Spatrick# Mach header "magic" constants
15061da546SpatrickMH_MAGIC = 0xfeedface
16061da546SpatrickMH_CIGAM = 0xcefaedfe
17061da546SpatrickMH_MAGIC_64 = 0xfeedfacf
18061da546SpatrickMH_CIGAM_64 = 0xcffaedfe
19061da546SpatrickFAT_MAGIC = 0xcafebabe
20061da546SpatrickFAT_CIGAM = 0xbebafeca
21061da546Spatrick
22061da546Spatrick# Mach haeder "filetype" constants
23061da546SpatrickMH_OBJECT = 0x00000001
24061da546SpatrickMH_EXECUTE = 0x00000002
25061da546SpatrickMH_FVMLIB = 0x00000003
26061da546SpatrickMH_CORE = 0x00000004
27061da546SpatrickMH_PRELOAD = 0x00000005
28061da546SpatrickMH_DYLIB = 0x00000006
29061da546SpatrickMH_DYLINKER = 0x00000007
30061da546SpatrickMH_BUNDLE = 0x00000008
31061da546SpatrickMH_DYLIB_STUB = 0x00000009
32061da546SpatrickMH_DSYM = 0x0000000a
33061da546SpatrickMH_KEXT_BUNDLE = 0x0000000b
34061da546Spatrick
35061da546Spatrick# Mach haeder "flag" constant bits
36061da546SpatrickMH_NOUNDEFS = 0x00000001
37061da546SpatrickMH_INCRLINK = 0x00000002
38061da546SpatrickMH_DYLDLINK = 0x00000004
39061da546SpatrickMH_BINDATLOAD = 0x00000008
40061da546SpatrickMH_PREBOUND = 0x00000010
41061da546SpatrickMH_SPLIT_SEGS = 0x00000020
42061da546SpatrickMH_LAZY_INIT = 0x00000040
43061da546SpatrickMH_TWOLEVEL = 0x00000080
44061da546SpatrickMH_FORCE_FLAT = 0x00000100
45061da546SpatrickMH_NOMULTIDEFS = 0x00000200
46061da546SpatrickMH_NOFIXPREBINDING = 0x00000400
47061da546SpatrickMH_PREBINDABLE = 0x00000800
48061da546SpatrickMH_ALLMODSBOUND = 0x00001000
49061da546SpatrickMH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000
50061da546SpatrickMH_CANONICAL = 0x00004000
51061da546SpatrickMH_WEAK_DEFINES = 0x00008000
52061da546SpatrickMH_BINDS_TO_WEAK = 0x00010000
53061da546SpatrickMH_ALLOW_STACK_EXECUTION = 0x00020000
54061da546SpatrickMH_ROOT_SAFE = 0x00040000
55061da546SpatrickMH_SETUID_SAFE = 0x00080000
56061da546SpatrickMH_NO_REEXPORTED_DYLIBS = 0x00100000
57061da546SpatrickMH_PIE = 0x00200000
58061da546SpatrickMH_DEAD_STRIPPABLE_DYLIB = 0x00400000
59061da546SpatrickMH_HAS_TLV_DESCRIPTORS = 0x00800000
60061da546SpatrickMH_NO_HEAP_EXECUTION = 0x01000000
61061da546Spatrick
62061da546Spatrick# Mach load command constants
63061da546SpatrickLC_REQ_DYLD = 0x80000000
64061da546SpatrickLC_SEGMENT = 0x00000001
65061da546SpatrickLC_SYMTAB = 0x00000002
66061da546SpatrickLC_SYMSEG = 0x00000003
67061da546SpatrickLC_THREAD = 0x00000004
68061da546SpatrickLC_UNIXTHREAD = 0x00000005
69061da546SpatrickLC_LOADFVMLIB = 0x00000006
70061da546SpatrickLC_IDFVMLIB = 0x00000007
71061da546SpatrickLC_IDENT = 0x00000008
72061da546SpatrickLC_FVMFILE = 0x00000009
73061da546SpatrickLC_PREPAGE = 0x0000000a
74061da546SpatrickLC_DYSYMTAB = 0x0000000b
75061da546SpatrickLC_LOAD_DYLIB = 0x0000000c
76061da546SpatrickLC_ID_DYLIB = 0x0000000d
77061da546SpatrickLC_LOAD_DYLINKER = 0x0000000e
78061da546SpatrickLC_ID_DYLINKER = 0x0000000f
79061da546SpatrickLC_PREBOUND_DYLIB = 0x00000010
80061da546SpatrickLC_ROUTINES = 0x00000011
81061da546SpatrickLC_SUB_FRAMEWORK = 0x00000012
82061da546SpatrickLC_SUB_UMBRELLA = 0x00000013
83061da546SpatrickLC_SUB_CLIENT = 0x00000014
84061da546SpatrickLC_SUB_LIBRARY = 0x00000015
85061da546SpatrickLC_TWOLEVEL_HINTS = 0x00000016
86061da546SpatrickLC_PREBIND_CKSUM = 0x00000017
87061da546SpatrickLC_LOAD_WEAK_DYLIB = 0x00000018 | LC_REQ_DYLD
88061da546SpatrickLC_SEGMENT_64 = 0x00000019
89061da546SpatrickLC_ROUTINES_64 = 0x0000001a
90061da546SpatrickLC_UUID = 0x0000001b
91061da546SpatrickLC_RPATH = 0x0000001c | LC_REQ_DYLD
92061da546SpatrickLC_CODE_SIGNATURE = 0x0000001d
93061da546SpatrickLC_SEGMENT_SPLIT_INFO = 0x0000001e
94061da546SpatrickLC_REEXPORT_DYLIB = 0x0000001f | LC_REQ_DYLD
95061da546SpatrickLC_LAZY_LOAD_DYLIB = 0x00000020
96061da546SpatrickLC_ENCRYPTION_INFO = 0x00000021
97061da546SpatrickLC_DYLD_INFO = 0x00000022
98061da546SpatrickLC_DYLD_INFO_ONLY = 0x00000022 | LC_REQ_DYLD
99061da546SpatrickLC_LOAD_UPWARD_DYLIB = 0x00000023 | LC_REQ_DYLD
100061da546SpatrickLC_VERSION_MIN_MACOSX = 0x00000024
101061da546SpatrickLC_VERSION_MIN_IPHONEOS = 0x00000025
102061da546SpatrickLC_FUNCTION_STARTS = 0x00000026
103061da546SpatrickLC_DYLD_ENVIRONMENT = 0x00000027
104061da546Spatrick
105061da546Spatrick# Mach CPU constants
106061da546SpatrickCPU_ARCH_MASK = 0xff000000
107061da546SpatrickCPU_ARCH_ABI64 = 0x01000000
108061da546SpatrickCPU_TYPE_ANY = 0xffffffff
109061da546SpatrickCPU_TYPE_VAX = 1
110061da546SpatrickCPU_TYPE_MC680x0 = 6
111061da546SpatrickCPU_TYPE_I386 = 7
112061da546SpatrickCPU_TYPE_X86_64 = CPU_TYPE_I386 | CPU_ARCH_ABI64
113061da546SpatrickCPU_TYPE_MIPS = 8
114061da546SpatrickCPU_TYPE_MC98000 = 10
115061da546SpatrickCPU_TYPE_HPPA = 11
116061da546SpatrickCPU_TYPE_ARM = 12
117061da546SpatrickCPU_TYPE_MC88000 = 13
118061da546SpatrickCPU_TYPE_SPARC = 14
119061da546SpatrickCPU_TYPE_I860 = 15
120061da546SpatrickCPU_TYPE_ALPHA = 16
121061da546SpatrickCPU_TYPE_POWERPC = 18
122061da546SpatrickCPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64
123061da546Spatrick
124061da546Spatrick# VM protection constants
125061da546SpatrickVM_PROT_READ = 1
126061da546SpatrickVM_PROT_WRITE = 2
127061da546SpatrickVM_PROT_EXECUTE = 4
128061da546Spatrick
129061da546Spatrick# VM protection constants
130061da546SpatrickN_STAB = 0xe0
131061da546SpatrickN_PEXT = 0x10
132061da546SpatrickN_TYPE = 0x0e
133061da546SpatrickN_EXT = 0x01
134061da546Spatrick
135061da546Spatrick# Values for nlist N_TYPE bits of the "Mach.NList.type" field.
136061da546SpatrickN_UNDF = 0x0
137061da546SpatrickN_ABS = 0x2
138061da546SpatrickN_SECT = 0xe
139061da546SpatrickN_PBUD = 0xc
140061da546SpatrickN_INDR = 0xa
141061da546Spatrick
142061da546Spatrick# Section indexes for the "Mach.NList.sect_idx" fields
143061da546SpatrickNO_SECT = 0
144061da546SpatrickMAX_SECT = 255
145061da546Spatrick
146061da546Spatrick# Stab defines
147061da546SpatrickN_GSYM = 0x20
148061da546SpatrickN_FNAME = 0x22
149061da546SpatrickN_FUN = 0x24
150061da546SpatrickN_STSYM = 0x26
151061da546SpatrickN_LCSYM = 0x28
152061da546SpatrickN_BNSYM = 0x2e
153061da546SpatrickN_OPT = 0x3c
154061da546SpatrickN_RSYM = 0x40
155061da546SpatrickN_SLINE = 0x44
156061da546SpatrickN_ENSYM = 0x4e
157061da546SpatrickN_SSYM = 0x60
158061da546SpatrickN_SO = 0x64
159061da546SpatrickN_OSO = 0x66
160061da546SpatrickN_LSYM = 0x80
161061da546SpatrickN_BINCL = 0x82
162061da546SpatrickN_SOL = 0x84
163061da546SpatrickN_PARAMS = 0x86
164061da546SpatrickN_VERSION = 0x88
165061da546SpatrickN_OLEVEL = 0x8A
166061da546SpatrickN_PSYM = 0xa0
167061da546SpatrickN_EINCL = 0xa2
168061da546SpatrickN_ENTRY = 0xa4
169061da546SpatrickN_LBRAC = 0xc0
170061da546SpatrickN_EXCL = 0xc2
171061da546SpatrickN_RBRAC = 0xe0
172061da546SpatrickN_BCOMM = 0xe2
173061da546SpatrickN_ECOMM = 0xe4
174061da546SpatrickN_ECOML = 0xe8
175061da546SpatrickN_LENG = 0xfe
176061da546Spatrick
177061da546Spatrickvm_prot_names = ['---', 'r--', '-w-', 'rw-', '--x', 'r-x', '-wx', 'rwx']
178061da546Spatrick
179061da546Spatrick
180061da546Spatrickdef dump_memory(base_addr, data, hex_bytes_len, num_per_line):
181061da546Spatrick    hex_bytes = data.encode('hex')
182061da546Spatrick    if hex_bytes_len == -1:
183061da546Spatrick        hex_bytes_len = len(hex_bytes)
184061da546Spatrick    addr = base_addr
185061da546Spatrick    ascii_str = ''
186061da546Spatrick    i = 0
187061da546Spatrick    while i < hex_bytes_len:
188061da546Spatrick        if ((i / 2) % num_per_line) == 0:
189061da546Spatrick            if i > 0:
190061da546Spatrick                print(' %s' % (ascii_str))
191061da546Spatrick                ascii_str = ''
192061da546Spatrick            print('0x%8.8x:' % (addr + i), end=' ')
193061da546Spatrick        hex_byte = hex_bytes[i:i + 2]
194061da546Spatrick        print(hex_byte, end=' ')
195061da546Spatrick        int_byte = int(hex_byte, 16)
196061da546Spatrick        ascii_char = '%c' % (int_byte)
197061da546Spatrick        if int_byte >= 32 and int_byte < 127:
198061da546Spatrick            ascii_str += ascii_char
199061da546Spatrick        else:
200061da546Spatrick            ascii_str += '.'
201061da546Spatrick        i = i + 2
202061da546Spatrick    if ascii_str:
203061da546Spatrick        if (i / 2) % num_per_line:
204061da546Spatrick            padding = num_per_line - ((i / 2) % num_per_line)
205061da546Spatrick        else:
206061da546Spatrick            padding = 0
207061da546Spatrick        print('%*s%s' % (padding * 3 + 1, '', ascii_str))
208061da546Spatrick    print()
209061da546Spatrick
210061da546Spatrick
211061da546Spatrickclass TerminalColors:
212061da546Spatrick    '''Simple terminal colors class'''
213061da546Spatrick
214061da546Spatrick    def __init__(self, enabled=True):
215061da546Spatrick        # TODO: discover terminal type from "file" and disable if
216061da546Spatrick        # it can't handle the color codes
217061da546Spatrick        self.enabled = enabled
218061da546Spatrick
219061da546Spatrick    def reset(self):
220061da546Spatrick        '''Reset all terminal colors and formatting.'''
221061da546Spatrick        if self.enabled:
222061da546Spatrick            return "\x1b[0m"
223061da546Spatrick        return ''
224061da546Spatrick
225061da546Spatrick    def bold(self, on=True):
226061da546Spatrick        '''Enable or disable bold depending on the "on" parameter.'''
227061da546Spatrick        if self.enabled:
228061da546Spatrick            if on:
229061da546Spatrick                return "\x1b[1m"
230061da546Spatrick            else:
231061da546Spatrick                return "\x1b[22m"
232061da546Spatrick        return ''
233061da546Spatrick
234061da546Spatrick    def italics(self, on=True):
235061da546Spatrick        '''Enable or disable italics depending on the "on" parameter.'''
236061da546Spatrick        if self.enabled:
237061da546Spatrick            if on:
238061da546Spatrick                return "\x1b[3m"
239061da546Spatrick            else:
240061da546Spatrick                return "\x1b[23m"
241061da546Spatrick        return ''
242061da546Spatrick
243061da546Spatrick    def underline(self, on=True):
244061da546Spatrick        '''Enable or disable underline depending on the "on" parameter.'''
245061da546Spatrick        if self.enabled:
246061da546Spatrick            if on:
247061da546Spatrick                return "\x1b[4m"
248061da546Spatrick            else:
249061da546Spatrick                return "\x1b[24m"
250061da546Spatrick        return ''
251061da546Spatrick
252061da546Spatrick    def inverse(self, on=True):
253061da546Spatrick        '''Enable or disable inverse depending on the "on" parameter.'''
254061da546Spatrick        if self.enabled:
255061da546Spatrick            if on:
256061da546Spatrick                return "\x1b[7m"
257061da546Spatrick            else:
258061da546Spatrick                return "\x1b[27m"
259061da546Spatrick        return ''
260061da546Spatrick
261061da546Spatrick    def strike(self, on=True):
262061da546Spatrick        '''Enable or disable strike through depending on the "on" parameter.'''
263061da546Spatrick        if self.enabled:
264061da546Spatrick            if on:
265061da546Spatrick                return "\x1b[9m"
266061da546Spatrick            else:
267061da546Spatrick                return "\x1b[29m"
268061da546Spatrick        return ''
269061da546Spatrick
270061da546Spatrick    def black(self, fg=True):
271061da546Spatrick        '''Set the foreground or background color to black.
272061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
273061da546Spatrick        if self.enabled:
274061da546Spatrick            if fg:
275061da546Spatrick                return "\x1b[30m"
276061da546Spatrick            else:
277061da546Spatrick                return "\x1b[40m"
278061da546Spatrick        return ''
279061da546Spatrick
280061da546Spatrick    def red(self, fg=True):
281061da546Spatrick        '''Set the foreground or background color to red.
282061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
283061da546Spatrick        if self.enabled:
284061da546Spatrick            if fg:
285061da546Spatrick                return "\x1b[31m"
286061da546Spatrick            else:
287061da546Spatrick                return "\x1b[41m"
288061da546Spatrick        return ''
289061da546Spatrick
290061da546Spatrick    def green(self, fg=True):
291061da546Spatrick        '''Set the foreground or background color to green.
292061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
293061da546Spatrick        if self.enabled:
294061da546Spatrick            if fg:
295061da546Spatrick                return "\x1b[32m"
296061da546Spatrick            else:
297061da546Spatrick                return "\x1b[42m"
298061da546Spatrick        return ''
299061da546Spatrick
300061da546Spatrick    def yellow(self, fg=True):
301061da546Spatrick        '''Set the foreground or background color to yellow.
302061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
303061da546Spatrick        if self.enabled:
304061da546Spatrick            if fg:
305061da546Spatrick                return "\x1b[43m"
306061da546Spatrick            else:
307061da546Spatrick                return "\x1b[33m"
308061da546Spatrick        return ''
309061da546Spatrick
310061da546Spatrick    def blue(self, fg=True):
311061da546Spatrick        '''Set the foreground or background color to blue.
312061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
313061da546Spatrick        if self.enabled:
314061da546Spatrick            if fg:
315061da546Spatrick                return "\x1b[34m"
316061da546Spatrick            else:
317061da546Spatrick                return "\x1b[44m"
318061da546Spatrick        return ''
319061da546Spatrick
320061da546Spatrick    def magenta(self, fg=True):
321061da546Spatrick        '''Set the foreground or background color to magenta.
322061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
323061da546Spatrick        if self.enabled:
324061da546Spatrick            if fg:
325061da546Spatrick                return "\x1b[35m"
326061da546Spatrick            else:
327061da546Spatrick                return "\x1b[45m"
328061da546Spatrick        return ''
329061da546Spatrick
330061da546Spatrick    def cyan(self, fg=True):
331061da546Spatrick        '''Set the foreground or background color to cyan.
332061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
333061da546Spatrick        if self.enabled:
334061da546Spatrick            if fg:
335061da546Spatrick                return "\x1b[36m"
336061da546Spatrick            else:
337061da546Spatrick                return "\x1b[46m"
338061da546Spatrick        return ''
339061da546Spatrick
340061da546Spatrick    def white(self, fg=True):
341061da546Spatrick        '''Set the foreground or background color to white.
342061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
343061da546Spatrick        if self.enabled:
344061da546Spatrick            if fg:
345061da546Spatrick                return "\x1b[37m"
346061da546Spatrick            else:
347061da546Spatrick                return "\x1b[47m"
348061da546Spatrick        return ''
349061da546Spatrick
350061da546Spatrick    def default(self, fg=True):
351061da546Spatrick        '''Set the foreground or background color to the default.
352061da546Spatrick        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
353061da546Spatrick        if self.enabled:
354061da546Spatrick            if fg:
355061da546Spatrick                return "\x1b[39m"
356061da546Spatrick            else:
357061da546Spatrick                return "\x1b[49m"
358061da546Spatrick        return ''
359061da546Spatrick
360061da546Spatrick
361061da546Spatrickdef swap_unpack_char():
362061da546Spatrick    """Returns the unpack prefix that will for non-native endian-ness."""
363061da546Spatrick    if struct.pack('H', 1).startswith("\x00"):
364061da546Spatrick        return '<'
365061da546Spatrick    return '>'
366061da546Spatrick
367061da546Spatrick
368061da546Spatrickdef dump_hex_bytes(addr, s, bytes_per_line=16):
369061da546Spatrick    i = 0
370061da546Spatrick    line = ''
371061da546Spatrick    for ch in s:
372061da546Spatrick        if (i % bytes_per_line) == 0:
373061da546Spatrick            if line:
374061da546Spatrick                print(line)
375061da546Spatrick            line = '%#8.8x: ' % (addr + i)
376061da546Spatrick        line += "%02X " % ord(ch)
377061da546Spatrick        i += 1
378061da546Spatrick    print(line)
379061da546Spatrick
380061da546Spatrick
381061da546Spatrickdef dump_hex_byte_string_diff(addr, a, b, bytes_per_line=16):
382061da546Spatrick    i = 0
383061da546Spatrick    line = ''
384061da546Spatrick    a_len = len(a)
385061da546Spatrick    b_len = len(b)
386061da546Spatrick    if a_len < b_len:
387061da546Spatrick        max_len = b_len
388061da546Spatrick    else:
389061da546Spatrick        max_len = a_len
390061da546Spatrick    tty_colors = TerminalColors(True)
391061da546Spatrick    for i in range(max_len):
392061da546Spatrick        ch = None
393061da546Spatrick        if i < a_len:
394061da546Spatrick            ch_a = a[i]
395061da546Spatrick            ch = ch_a
396061da546Spatrick        else:
397061da546Spatrick            ch_a = None
398061da546Spatrick        if i < b_len:
399061da546Spatrick            ch_b = b[i]
400061da546Spatrick            if not ch:
401061da546Spatrick                ch = ch_b
402061da546Spatrick        else:
403061da546Spatrick            ch_b = None
404061da546Spatrick        mismatch = ch_a != ch_b
405061da546Spatrick        if (i % bytes_per_line) == 0:
406061da546Spatrick            if line:
407061da546Spatrick                print(line)
408061da546Spatrick            line = '%#8.8x: ' % (addr + i)
409061da546Spatrick        if mismatch:
410061da546Spatrick            line += tty_colors.red()
411061da546Spatrick        line += "%02X " % ord(ch)
412061da546Spatrick        if mismatch:
413061da546Spatrick            line += tty_colors.default()
414061da546Spatrick        i += 1
415061da546Spatrick
416061da546Spatrick    print(line)
417061da546Spatrick
418061da546Spatrick
419061da546Spatrickclass Mach:
420061da546Spatrick    """Class that does everything mach-o related"""
421061da546Spatrick
422061da546Spatrick    class Arch:
423061da546Spatrick        """Class that implements mach-o architectures"""
424061da546Spatrick
425061da546Spatrick        def __init__(self, c=0, s=0):
426061da546Spatrick            self.cpu = c
427061da546Spatrick            self.sub = s
428061da546Spatrick
429061da546Spatrick        def set_cpu_type(self, c):
430061da546Spatrick            self.cpu = c
431061da546Spatrick
432061da546Spatrick        def set_cpu_subtype(self, s):
433061da546Spatrick            self.sub = s
434061da546Spatrick
435061da546Spatrick        def set_arch(self, c, s):
436061da546Spatrick            self.cpu = c
437061da546Spatrick            self.sub = s
438061da546Spatrick
439061da546Spatrick        def is_64_bit(self):
440061da546Spatrick            return (self.cpu & CPU_ARCH_ABI64) != 0
441061da546Spatrick
442061da546Spatrick        cpu_infos = [
443061da546Spatrick            ["arm", CPU_TYPE_ARM, CPU_TYPE_ANY],
444061da546Spatrick            ["arm", CPU_TYPE_ARM, 0],
445061da546Spatrick            ["armv4", CPU_TYPE_ARM, 5],
446061da546Spatrick            ["armv6", CPU_TYPE_ARM, 6],
447061da546Spatrick            ["armv5", CPU_TYPE_ARM, 7],
448061da546Spatrick            ["xscale", CPU_TYPE_ARM, 8],
449061da546Spatrick            ["armv7", CPU_TYPE_ARM, 9],
450061da546Spatrick            ["armv7f", CPU_TYPE_ARM, 10],
451061da546Spatrick            ["armv7s", CPU_TYPE_ARM, 11],
452061da546Spatrick            ["armv7k", CPU_TYPE_ARM, 12],
453061da546Spatrick            ["armv7m", CPU_TYPE_ARM, 15],
454061da546Spatrick            ["armv7em", CPU_TYPE_ARM, 16],
455061da546Spatrick            ["ppc", CPU_TYPE_POWERPC, CPU_TYPE_ANY],
456061da546Spatrick            ["ppc", CPU_TYPE_POWERPC, 0],
457061da546Spatrick            ["ppc601", CPU_TYPE_POWERPC, 1],
458061da546Spatrick            ["ppc602", CPU_TYPE_POWERPC, 2],
459061da546Spatrick            ["ppc603", CPU_TYPE_POWERPC, 3],
460061da546Spatrick            ["ppc603e", CPU_TYPE_POWERPC, 4],
461061da546Spatrick            ["ppc603ev", CPU_TYPE_POWERPC, 5],
462061da546Spatrick            ["ppc604", CPU_TYPE_POWERPC, 6],
463061da546Spatrick            ["ppc604e", CPU_TYPE_POWERPC, 7],
464061da546Spatrick            ["ppc620", CPU_TYPE_POWERPC, 8],
465061da546Spatrick            ["ppc750", CPU_TYPE_POWERPC, 9],
466061da546Spatrick            ["ppc7400", CPU_TYPE_POWERPC, 10],
467061da546Spatrick            ["ppc7450", CPU_TYPE_POWERPC, 11],
468061da546Spatrick            ["ppc970", CPU_TYPE_POWERPC, 100],
469061da546Spatrick            ["ppc64", CPU_TYPE_POWERPC64, 0],
470061da546Spatrick            ["ppc970-64", CPU_TYPE_POWERPC64, 100],
471061da546Spatrick            ["i386", CPU_TYPE_I386, 3],
472061da546Spatrick            ["i486", CPU_TYPE_I386, 4],
473061da546Spatrick            ["i486sx", CPU_TYPE_I386, 0x84],
474061da546Spatrick            ["i386", CPU_TYPE_I386, CPU_TYPE_ANY],
475061da546Spatrick            ["x86_64", CPU_TYPE_X86_64, 3],
476061da546Spatrick            ["x86_64", CPU_TYPE_X86_64, CPU_TYPE_ANY],
477061da546Spatrick        ]
478061da546Spatrick
479061da546Spatrick        def __str__(self):
480061da546Spatrick            for info in self.cpu_infos:
481061da546Spatrick                if self.cpu == info[1] and (self.sub & 0x00ffffff) == info[2]:
482061da546Spatrick                    return info[0]
483061da546Spatrick            return "{0}.{1}".format(self.cpu, self.sub)
484061da546Spatrick
485061da546Spatrick    class Magic(dict_utils.Enum):
486061da546Spatrick
487061da546Spatrick        enum = {
488061da546Spatrick            'MH_MAGIC': MH_MAGIC,
489061da546Spatrick            'MH_CIGAM': MH_CIGAM,
490061da546Spatrick            'MH_MAGIC_64': MH_MAGIC_64,
491061da546Spatrick            'MH_CIGAM_64': MH_CIGAM_64,
492061da546Spatrick            'FAT_MAGIC': FAT_MAGIC,
493061da546Spatrick            'FAT_CIGAM': FAT_CIGAM
494061da546Spatrick        }
495061da546Spatrick
496061da546Spatrick        def __init__(self, initial_value=0):
497061da546Spatrick            dict_utils.Enum.__init__(self, initial_value, self.enum)
498061da546Spatrick
499061da546Spatrick        def is_skinny_mach_file(self):
500061da546Spatrick            return self.value == MH_MAGIC or self.value == MH_CIGAM or self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
501061da546Spatrick
502061da546Spatrick        def is_universal_mach_file(self):
503061da546Spatrick            return self.value == FAT_MAGIC or self.value == FAT_CIGAM
504061da546Spatrick
505061da546Spatrick        def unpack(self, data):
506061da546Spatrick            data.set_byte_order('native')
507061da546Spatrick            self.value = data.get_uint32()
508061da546Spatrick
509061da546Spatrick        def get_byte_order(self):
510061da546Spatrick            if self.value == MH_CIGAM or self.value == MH_CIGAM_64 or self.value == FAT_CIGAM:
511061da546Spatrick                return swap_unpack_char()
512061da546Spatrick            else:
513061da546Spatrick                return '='
514061da546Spatrick
515061da546Spatrick        def is_64_bit(self):
516061da546Spatrick            return self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
517061da546Spatrick
518061da546Spatrick    def __init__(self):
519061da546Spatrick        self.magic = Mach.Magic()
520061da546Spatrick        self.content = None
521061da546Spatrick        self.path = None
522061da546Spatrick
523061da546Spatrick    def extract(self, path, extractor):
524061da546Spatrick        self.path = path
525061da546Spatrick        self.unpack(extractor)
526061da546Spatrick
527061da546Spatrick    def parse(self, path):
528061da546Spatrick        self.path = path
529061da546Spatrick        try:
530061da546Spatrick            f = open(self.path)
531061da546Spatrick            file_extractor = file_extract.FileExtract(f, '=')
532061da546Spatrick            self.unpack(file_extractor)
533061da546Spatrick            # f.close()
534061da546Spatrick        except IOError as xxx_todo_changeme:
535061da546Spatrick            (errno, strerror) = xxx_todo_changeme.args
536061da546Spatrick            print("I/O error({0}): {1}".format(errno, strerror))
537061da546Spatrick        except ValueError:
538061da546Spatrick            print("Could not convert data to an integer.")
539061da546Spatrick        except:
540061da546Spatrick            print("Unexpected error:", sys.exc_info()[0])
541061da546Spatrick            raise
542061da546Spatrick
543061da546Spatrick    def compare(self, rhs):
544061da546Spatrick        self.content.compare(rhs.content)
545061da546Spatrick
546061da546Spatrick    def dump(self, options=None):
547061da546Spatrick        self.content.dump(options)
548061da546Spatrick
549061da546Spatrick    def dump_header(self, dump_description=True, options=None):
550061da546Spatrick        self.content.dump_header(dump_description, options)
551061da546Spatrick
552061da546Spatrick    def dump_load_commands(self, dump_description=True, options=None):
553061da546Spatrick        self.content.dump_load_commands(dump_description, options)
554061da546Spatrick
555061da546Spatrick    def dump_sections(self, dump_description=True, options=None):
556061da546Spatrick        self.content.dump_sections(dump_description, options)
557061da546Spatrick
558061da546Spatrick    def dump_section_contents(self, options):
559061da546Spatrick        self.content.dump_section_contents(options)
560061da546Spatrick
561061da546Spatrick    def dump_symtab(self, dump_description=True, options=None):
562061da546Spatrick        self.content.dump_symtab(dump_description, options)
563061da546Spatrick
564061da546Spatrick    def dump_symbol_names_matching_regex(self, regex, file=None):
565061da546Spatrick        self.content.dump_symbol_names_matching_regex(regex, file)
566061da546Spatrick
567061da546Spatrick    def description(self):
568061da546Spatrick        return self.content.description()
569061da546Spatrick
570061da546Spatrick    def unpack(self, data):
571061da546Spatrick        self.magic.unpack(data)
572061da546Spatrick        if self.magic.is_skinny_mach_file():
573061da546Spatrick            self.content = Mach.Skinny(self.path)
574061da546Spatrick        elif self.magic.is_universal_mach_file():
575061da546Spatrick            self.content = Mach.Universal(self.path)
576061da546Spatrick        else:
577061da546Spatrick            self.content = None
578061da546Spatrick
579061da546Spatrick        if self.content is not None:
580061da546Spatrick            self.content.unpack(data, self.magic)
581061da546Spatrick
582061da546Spatrick    def is_valid(self):
583061da546Spatrick        return self.content is not None
584061da546Spatrick
585061da546Spatrick    class Universal:
586061da546Spatrick
587061da546Spatrick        def __init__(self, path):
588061da546Spatrick            self.path = path
589061da546Spatrick            self.type = 'universal'
590061da546Spatrick            self.file_off = 0
591061da546Spatrick            self.magic = None
592061da546Spatrick            self.nfat_arch = 0
593061da546Spatrick            self.archs = list()
594061da546Spatrick
595061da546Spatrick        def description(self):
596061da546Spatrick            s = '%#8.8x: %s (' % (self.file_off, self.path)
597061da546Spatrick            archs_string = ''
598061da546Spatrick            for arch in self.archs:
599061da546Spatrick                if len(archs_string):
600061da546Spatrick                    archs_string += ', '
601061da546Spatrick                archs_string += '%s' % arch.arch
602061da546Spatrick            s += archs_string
603061da546Spatrick            s += ')'
604061da546Spatrick            return s
605061da546Spatrick
606061da546Spatrick        def unpack(self, data, magic=None):
607061da546Spatrick            self.file_off = data.tell()
608061da546Spatrick            if magic is None:
609061da546Spatrick                self.magic = Mach.Magic()
610061da546Spatrick                self.magic.unpack(data)
611061da546Spatrick            else:
612061da546Spatrick                self.magic = magic
613061da546Spatrick                self.file_off = self.file_off - 4
614061da546Spatrick            # Universal headers are always in big endian
615061da546Spatrick            data.set_byte_order('big')
616061da546Spatrick            self.nfat_arch = data.get_uint32()
617061da546Spatrick            for i in range(self.nfat_arch):
618061da546Spatrick                self.archs.append(Mach.Universal.ArchInfo())
619061da546Spatrick                self.archs[i].unpack(data)
620061da546Spatrick            for i in range(self.nfat_arch):
621061da546Spatrick                self.archs[i].mach = Mach.Skinny(self.path)
622061da546Spatrick                data.seek(self.archs[i].offset, 0)
623061da546Spatrick                skinny_magic = Mach.Magic()
624061da546Spatrick                skinny_magic.unpack(data)
625061da546Spatrick                self.archs[i].mach.unpack(data, skinny_magic)
626061da546Spatrick
627061da546Spatrick        def compare(self, rhs):
628061da546Spatrick            print('error: comparing two universal files is not supported yet')
629061da546Spatrick            return False
630061da546Spatrick
631061da546Spatrick        def dump(self, options):
632061da546Spatrick            if options.dump_header:
633061da546Spatrick                print()
634061da546Spatrick                print("Universal Mach File: magic = %s, nfat_arch = %u" % (self.magic, self.nfat_arch))
635061da546Spatrick                print()
636061da546Spatrick            if self.nfat_arch > 0:
637061da546Spatrick                if options.dump_header:
638061da546Spatrick                    self.archs[0].dump_header(True, options)
639061da546Spatrick                    for i in range(self.nfat_arch):
640061da546Spatrick                        self.archs[i].dump_flat(options)
641061da546Spatrick                if options.dump_header:
642061da546Spatrick                    print()
643061da546Spatrick                for i in range(self.nfat_arch):
644061da546Spatrick                    self.archs[i].mach.dump(options)
645061da546Spatrick
646061da546Spatrick        def dump_header(self, dump_description=True, options=None):
647061da546Spatrick            if dump_description:
648061da546Spatrick                print(self.description())
649061da546Spatrick            for i in range(self.nfat_arch):
650061da546Spatrick                self.archs[i].mach.dump_header(True, options)
651061da546Spatrick                print()
652061da546Spatrick
653061da546Spatrick        def dump_load_commands(self, dump_description=True, options=None):
654061da546Spatrick            if dump_description:
655061da546Spatrick                print(self.description())
656061da546Spatrick            for i in range(self.nfat_arch):
657061da546Spatrick                self.archs[i].mach.dump_load_commands(True, options)
658061da546Spatrick                print()
659061da546Spatrick
660061da546Spatrick        def dump_sections(self, dump_description=True, options=None):
661061da546Spatrick            if dump_description:
662061da546Spatrick                print(self.description())
663061da546Spatrick            for i in range(self.nfat_arch):
664061da546Spatrick                self.archs[i].mach.dump_sections(True, options)
665061da546Spatrick                print()
666061da546Spatrick
667061da546Spatrick        def dump_section_contents(self, options):
668061da546Spatrick            for i in range(self.nfat_arch):
669061da546Spatrick                self.archs[i].mach.dump_section_contents(options)
670061da546Spatrick                print()
671061da546Spatrick
672061da546Spatrick        def dump_symtab(self, dump_description=True, options=None):
673061da546Spatrick            if dump_description:
674061da546Spatrick                print(self.description())
675061da546Spatrick            for i in range(self.nfat_arch):
676061da546Spatrick                self.archs[i].mach.dump_symtab(True, options)
677061da546Spatrick                print()
678061da546Spatrick
679061da546Spatrick        def dump_symbol_names_matching_regex(self, regex, file=None):
680061da546Spatrick            for i in range(self.nfat_arch):
681061da546Spatrick                self.archs[i].mach.dump_symbol_names_matching_regex(
682061da546Spatrick                    regex, file)
683061da546Spatrick
684061da546Spatrick        class ArchInfo:
685061da546Spatrick
686061da546Spatrick            def __init__(self):
687061da546Spatrick                self.arch = Mach.Arch(0, 0)
688061da546Spatrick                self.offset = 0
689061da546Spatrick                self.size = 0
690061da546Spatrick                self.align = 0
691061da546Spatrick                self.mach = None
692061da546Spatrick
693061da546Spatrick            def unpack(self, data):
694061da546Spatrick                # Universal headers are always in big endian
695061da546Spatrick                data.set_byte_order('big')
696061da546Spatrick                self.arch.cpu, self.arch.sub, self.offset, self.size, self.align = data.get_n_uint32(
697061da546Spatrick                    5)
698061da546Spatrick
699061da546Spatrick            def dump_header(self, dump_description=True, options=None):
700061da546Spatrick                if options.verbose:
701061da546Spatrick                    print("CPU        SUBTYPE    OFFSET     SIZE       ALIGN")
702061da546Spatrick                    print("---------- ---------- ---------- ---------- ----------")
703061da546Spatrick                else:
704061da546Spatrick                    print("ARCH       FILEOFFSET FILESIZE   ALIGN")
705061da546Spatrick                    print("---------- ---------- ---------- ----------")
706061da546Spatrick
707061da546Spatrick            def dump_flat(self, options):
708061da546Spatrick                if options.verbose:
709061da546Spatrick                    print("%#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align))
710061da546Spatrick                else:
711061da546Spatrick                    print("%-10s %#8.8x %#8.8x %#8.8x" % (self.arch, self.offset, self.size, self.align))
712061da546Spatrick
713061da546Spatrick            def dump(self):
714061da546Spatrick                print("   cputype: %#8.8x" % self.arch.cpu)
715061da546Spatrick                print("cpusubtype: %#8.8x" % self.arch.sub)
716061da546Spatrick                print("    offset: %#8.8x" % self.offset)
717061da546Spatrick                print("      size: %#8.8x" % self.size)
718061da546Spatrick                print("     align: %#8.8x" % self.align)
719061da546Spatrick
720061da546Spatrick            def __str__(self):
721061da546Spatrick                return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (
722061da546Spatrick                    self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
723061da546Spatrick
724061da546Spatrick            def __repr__(self):
725061da546Spatrick                return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (
726061da546Spatrick                    self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
727061da546Spatrick
728061da546Spatrick    class Flags:
729061da546Spatrick
730061da546Spatrick        def __init__(self, b):
731061da546Spatrick            self.bits = b
732061da546Spatrick
733061da546Spatrick        def __str__(self):
734061da546Spatrick            s = ''
735061da546Spatrick            if self.bits & MH_NOUNDEFS:
736061da546Spatrick                s += 'MH_NOUNDEFS | '
737061da546Spatrick            if self.bits & MH_INCRLINK:
738061da546Spatrick                s += 'MH_INCRLINK | '
739061da546Spatrick            if self.bits & MH_DYLDLINK:
740061da546Spatrick                s += 'MH_DYLDLINK | '
741061da546Spatrick            if self.bits & MH_BINDATLOAD:
742061da546Spatrick                s += 'MH_BINDATLOAD | '
743061da546Spatrick            if self.bits & MH_PREBOUND:
744061da546Spatrick                s += 'MH_PREBOUND | '
745061da546Spatrick            if self.bits & MH_SPLIT_SEGS:
746061da546Spatrick                s += 'MH_SPLIT_SEGS | '
747061da546Spatrick            if self.bits & MH_LAZY_INIT:
748061da546Spatrick                s += 'MH_LAZY_INIT | '
749061da546Spatrick            if self.bits & MH_TWOLEVEL:
750061da546Spatrick                s += 'MH_TWOLEVEL | '
751061da546Spatrick            if self.bits & MH_FORCE_FLAT:
752061da546Spatrick                s += 'MH_FORCE_FLAT | '
753061da546Spatrick            if self.bits & MH_NOMULTIDEFS:
754061da546Spatrick                s += 'MH_NOMULTIDEFS | '
755061da546Spatrick            if self.bits & MH_NOFIXPREBINDING:
756061da546Spatrick                s += 'MH_NOFIXPREBINDING | '
757061da546Spatrick            if self.bits & MH_PREBINDABLE:
758061da546Spatrick                s += 'MH_PREBINDABLE | '
759061da546Spatrick            if self.bits & MH_ALLMODSBOUND:
760061da546Spatrick                s += 'MH_ALLMODSBOUND | '
761061da546Spatrick            if self.bits & MH_SUBSECTIONS_VIA_SYMBOLS:
762061da546Spatrick                s += 'MH_SUBSECTIONS_VIA_SYMBOLS | '
763061da546Spatrick            if self.bits & MH_CANONICAL:
764061da546Spatrick                s += 'MH_CANONICAL | '
765061da546Spatrick            if self.bits & MH_WEAK_DEFINES:
766061da546Spatrick                s += 'MH_WEAK_DEFINES | '
767061da546Spatrick            if self.bits & MH_BINDS_TO_WEAK:
768061da546Spatrick                s += 'MH_BINDS_TO_WEAK | '
769061da546Spatrick            if self.bits & MH_ALLOW_STACK_EXECUTION:
770061da546Spatrick                s += 'MH_ALLOW_STACK_EXECUTION | '
771061da546Spatrick            if self.bits & MH_ROOT_SAFE:
772061da546Spatrick                s += 'MH_ROOT_SAFE | '
773061da546Spatrick            if self.bits & MH_SETUID_SAFE:
774061da546Spatrick                s += 'MH_SETUID_SAFE | '
775061da546Spatrick            if self.bits & MH_NO_REEXPORTED_DYLIBS:
776061da546Spatrick                s += 'MH_NO_REEXPORTED_DYLIBS | '
777061da546Spatrick            if self.bits & MH_PIE:
778061da546Spatrick                s += 'MH_PIE | '
779061da546Spatrick            if self.bits & MH_DEAD_STRIPPABLE_DYLIB:
780061da546Spatrick                s += 'MH_DEAD_STRIPPABLE_DYLIB | '
781061da546Spatrick            if self.bits & MH_HAS_TLV_DESCRIPTORS:
782061da546Spatrick                s += 'MH_HAS_TLV_DESCRIPTORS | '
783061da546Spatrick            if self.bits & MH_NO_HEAP_EXECUTION:
784061da546Spatrick                s += 'MH_NO_HEAP_EXECUTION | '
785061da546Spatrick            # Strip the trailing " |" if we have any flags
786061da546Spatrick            if len(s) > 0:
787061da546Spatrick                s = s[0:-2]
788061da546Spatrick            return s
789061da546Spatrick
790061da546Spatrick    class FileType(dict_utils.Enum):
791061da546Spatrick
792061da546Spatrick        enum = {
793061da546Spatrick            'MH_OBJECT': MH_OBJECT,
794061da546Spatrick            'MH_EXECUTE': MH_EXECUTE,
795061da546Spatrick            'MH_FVMLIB': MH_FVMLIB,
796061da546Spatrick            'MH_CORE': MH_CORE,
797061da546Spatrick            'MH_PRELOAD': MH_PRELOAD,
798061da546Spatrick            'MH_DYLIB': MH_DYLIB,
799061da546Spatrick            'MH_DYLINKER': MH_DYLINKER,
800061da546Spatrick            'MH_BUNDLE': MH_BUNDLE,
801061da546Spatrick            'MH_DYLIB_STUB': MH_DYLIB_STUB,
802061da546Spatrick            'MH_DSYM': MH_DSYM,
803061da546Spatrick            'MH_KEXT_BUNDLE': MH_KEXT_BUNDLE
804061da546Spatrick        }
805061da546Spatrick
806061da546Spatrick        def __init__(self, initial_value=0):
807061da546Spatrick            dict_utils.Enum.__init__(self, initial_value, self.enum)
808061da546Spatrick
809061da546Spatrick    class Skinny:
810061da546Spatrick
811061da546Spatrick        def __init__(self, path):
812061da546Spatrick            self.path = path
813061da546Spatrick            self.type = 'skinny'
814061da546Spatrick            self.data = None
815061da546Spatrick            self.file_off = 0
816061da546Spatrick            self.magic = 0
817061da546Spatrick            self.arch = Mach.Arch(0, 0)
818061da546Spatrick            self.filetype = Mach.FileType(0)
819061da546Spatrick            self.ncmds = 0
820061da546Spatrick            self.sizeofcmds = 0
821061da546Spatrick            self.flags = Mach.Flags(0)
822061da546Spatrick            self.uuid = None
823061da546Spatrick            self.commands = list()
824061da546Spatrick            self.segments = list()
825061da546Spatrick            self.sections = list()
826061da546Spatrick            self.symbols = list()
827061da546Spatrick            self.sections.append(Mach.Section())
828061da546Spatrick
829061da546Spatrick        def description(self):
830061da546Spatrick            return '%#8.8x: %s (%s)' % (self.file_off, self.path, self.arch)
831061da546Spatrick
832061da546Spatrick        def unpack(self, data, magic=None):
833061da546Spatrick            self.data = data
834061da546Spatrick            self.file_off = data.tell()
835061da546Spatrick            if magic is None:
836061da546Spatrick                self.magic = Mach.Magic()
837061da546Spatrick                self.magic.unpack(data)
838061da546Spatrick            else:
839061da546Spatrick                self.magic = magic
840061da546Spatrick                self.file_off = self.file_off - 4
841061da546Spatrick            data.set_byte_order(self.magic.get_byte_order())
842061da546Spatrick            self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, bits = data.get_n_uint32(
843061da546Spatrick                6)
844061da546Spatrick            self.flags.bits = bits
845061da546Spatrick
846061da546Spatrick            if self.is_64_bit():
847061da546Spatrick                data.get_uint32()  # Skip reserved word in mach_header_64
848061da546Spatrick
849061da546Spatrick            for i in range(0, self.ncmds):
850061da546Spatrick                lc = self.unpack_load_command(data)
851061da546Spatrick                self.commands.append(lc)
852061da546Spatrick
853061da546Spatrick        def get_data(self):
854061da546Spatrick            if self.data:
855061da546Spatrick                self.data.set_byte_order(self.magic.get_byte_order())
856061da546Spatrick                return self.data
857061da546Spatrick            return None
858061da546Spatrick
859061da546Spatrick        def unpack_load_command(self, data):
860061da546Spatrick            lc = Mach.LoadCommand()
861061da546Spatrick            lc.unpack(self, data)
862061da546Spatrick            lc_command = lc.command.get_enum_value()
863061da546Spatrick            if (lc_command == LC_SEGMENT or
864061da546Spatrick                    lc_command == LC_SEGMENT_64):
865061da546Spatrick                lc = Mach.SegmentLoadCommand(lc)
866061da546Spatrick                lc.unpack(self, data)
867061da546Spatrick            elif (lc_command == LC_LOAD_DYLIB or
868061da546Spatrick                  lc_command == LC_ID_DYLIB or
869061da546Spatrick                  lc_command == LC_LOAD_WEAK_DYLIB or
870061da546Spatrick                  lc_command == LC_REEXPORT_DYLIB):
871061da546Spatrick                lc = Mach.DylibLoadCommand(lc)
872061da546Spatrick                lc.unpack(self, data)
873061da546Spatrick            elif (lc_command == LC_LOAD_DYLINKER or
874061da546Spatrick                  lc_command == LC_SUB_FRAMEWORK or
875061da546Spatrick                  lc_command == LC_SUB_CLIENT or
876061da546Spatrick                  lc_command == LC_SUB_UMBRELLA or
877061da546Spatrick                  lc_command == LC_SUB_LIBRARY or
878061da546Spatrick                  lc_command == LC_ID_DYLINKER or
879061da546Spatrick                  lc_command == LC_RPATH):
880061da546Spatrick                lc = Mach.LoadDYLDLoadCommand(lc)
881061da546Spatrick                lc.unpack(self, data)
882061da546Spatrick            elif (lc_command == LC_DYLD_INFO_ONLY):
883061da546Spatrick                lc = Mach.DYLDInfoOnlyLoadCommand(lc)
884061da546Spatrick                lc.unpack(self, data)
885061da546Spatrick            elif (lc_command == LC_SYMTAB):
886061da546Spatrick                lc = Mach.SymtabLoadCommand(lc)
887061da546Spatrick                lc.unpack(self, data)
888061da546Spatrick            elif (lc_command == LC_DYSYMTAB):
889061da546Spatrick                lc = Mach.DYLDSymtabLoadCommand(lc)
890061da546Spatrick                lc.unpack(self, data)
891061da546Spatrick            elif (lc_command == LC_UUID):
892061da546Spatrick                lc = Mach.UUIDLoadCommand(lc)
893061da546Spatrick                lc.unpack(self, data)
894061da546Spatrick            elif (lc_command == LC_CODE_SIGNATURE or
895061da546Spatrick                  lc_command == LC_SEGMENT_SPLIT_INFO or
896061da546Spatrick                  lc_command == LC_FUNCTION_STARTS):
897061da546Spatrick                lc = Mach.DataBlobLoadCommand(lc)
898061da546Spatrick                lc.unpack(self, data)
899061da546Spatrick            elif (lc_command == LC_UNIXTHREAD):
900061da546Spatrick                lc = Mach.UnixThreadLoadCommand(lc)
901061da546Spatrick                lc.unpack(self, data)
902061da546Spatrick            elif (lc_command == LC_ENCRYPTION_INFO):
903061da546Spatrick                lc = Mach.EncryptionInfoLoadCommand(lc)
904061da546Spatrick                lc.unpack(self, data)
905061da546Spatrick            lc.skip(data)
906061da546Spatrick            return lc
907061da546Spatrick
908061da546Spatrick        def compare(self, rhs):
909061da546Spatrick            print("\nComparing:")
910061da546Spatrick            print("a) %s %s" % (self.arch, self.path))
911061da546Spatrick            print("b) %s %s" % (rhs.arch, rhs.path))
912061da546Spatrick            result = True
913061da546Spatrick            if self.type == rhs.type:
914061da546Spatrick                for lhs_section in self.sections[1:]:
915061da546Spatrick                    rhs_section = rhs.get_section_by_section(lhs_section)
916061da546Spatrick                    if rhs_section:
917061da546Spatrick                        print('comparing %s.%s...' % (lhs_section.segname, lhs_section.sectname), end=' ')
918061da546Spatrick                        sys.stdout.flush()
919061da546Spatrick                        lhs_data = lhs_section.get_contents(self)
920061da546Spatrick                        rhs_data = rhs_section.get_contents(rhs)
921061da546Spatrick                        if lhs_data and rhs_data:
922061da546Spatrick                            if lhs_data == rhs_data:
923061da546Spatrick                                print('ok')
924061da546Spatrick                            else:
925061da546Spatrick                                lhs_data_len = len(lhs_data)
926061da546Spatrick                                rhs_data_len = len(rhs_data)
927061da546Spatrick                                # if lhs_data_len < rhs_data_len:
928061da546Spatrick                                #     if lhs_data == rhs_data[0:lhs_data_len]:
929061da546Spatrick                                #         print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
930061da546Spatrick                                #     else:
931061da546Spatrick                                #         # TODO: check padding
932061da546Spatrick                                #         result = False
933061da546Spatrick                                # elif lhs_data_len > rhs_data_len:
934061da546Spatrick                                #     if lhs_data[0:rhs_data_len] == rhs_data:
935061da546Spatrick                                #         print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
936061da546Spatrick                                #     else:
937061da546Spatrick                                #         # TODO: check padding
938061da546Spatrick                                #         result = False
939061da546Spatrick                                # else:
940061da546Spatrick                                result = False
941061da546Spatrick                                print('error: sections differ')
942061da546Spatrick                                # print 'a) %s' % (lhs_section)
943061da546Spatrick                                # dump_hex_byte_string_diff(0, lhs_data, rhs_data)
944061da546Spatrick                                # print 'b) %s' % (rhs_section)
945061da546Spatrick                                # dump_hex_byte_string_diff(0, rhs_data, lhs_data)
946061da546Spatrick                        elif lhs_data and not rhs_data:
947061da546Spatrick                            print('error: section data missing from b:')
948061da546Spatrick                            print('a) %s' % (lhs_section))
949061da546Spatrick                            print('b) %s' % (rhs_section))
950061da546Spatrick                            result = False
951061da546Spatrick                        elif not lhs_data and rhs_data:
952061da546Spatrick                            print('error: section data missing from a:')
953061da546Spatrick                            print('a) %s' % (lhs_section))
954061da546Spatrick                            print('b) %s' % (rhs_section))
955061da546Spatrick                            result = False
956061da546Spatrick                        elif lhs_section.offset or rhs_section.offset:
957061da546Spatrick                            print('error: section data missing for both a and b:')
958061da546Spatrick                            print('a) %s' % (lhs_section))
959061da546Spatrick                            print('b) %s' % (rhs_section))
960061da546Spatrick                            result = False
961061da546Spatrick                        else:
962061da546Spatrick                            print('ok')
963061da546Spatrick                    else:
964061da546Spatrick                        result = False
965061da546Spatrick                        print('error: section %s is missing in %s' % (lhs_section.sectname, rhs.path))
966061da546Spatrick            else:
967dda28197Spatrick                print('error: comparing a %s mach-o file with a %s mach-o file is not supported' % (self.type, rhs.type))
968061da546Spatrick                result = False
969061da546Spatrick            if not result:
970061da546Spatrick                print('error: mach files differ')
971061da546Spatrick            return result
972061da546Spatrick
973061da546Spatrick        def dump_header(self, dump_description=True, options=None):
974061da546Spatrick            if options.verbose:
975061da546Spatrick                print("MAGIC      CPU        SUBTYPE    FILETYPE   NUM CMDS SIZE CMDS  FLAGS")
976061da546Spatrick                print("---------- ---------- ---------- ---------- -------- ---------- ----------")
977061da546Spatrick            else:
978061da546Spatrick                print("MAGIC        ARCH       FILETYPE       NUM CMDS SIZE CMDS  FLAGS")
979061da546Spatrick                print("------------ ---------- -------------- -------- ---------- ----------")
980061da546Spatrick
981061da546Spatrick        def dump_flat(self, options):
982061da546Spatrick            if options.verbose:
983061da546Spatrick                print("%#8.8x %#8.8x %#8.8x %#8.8x %#8u %#8.8x %#8.8x" % (self.magic, self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, self.flags.bits))
984061da546Spatrick            else:
985061da546Spatrick                print("%-12s %-10s %-14s %#8u %#8.8x %s" % (self.magic, self.arch, self.filetype, self.ncmds, self.sizeofcmds, self.flags))
986061da546Spatrick
987061da546Spatrick        def dump(self, options):
988061da546Spatrick            if options.dump_header:
989061da546Spatrick                self.dump_header(True, options)
990061da546Spatrick            if options.dump_load_commands:
991061da546Spatrick                self.dump_load_commands(False, options)
992061da546Spatrick            if options.dump_sections:
993061da546Spatrick                self.dump_sections(False, options)
994061da546Spatrick            if options.section_names:
995061da546Spatrick                self.dump_section_contents(options)
996061da546Spatrick            if options.dump_symtab:
997061da546Spatrick                self.get_symtab()
998061da546Spatrick                if len(self.symbols):
999061da546Spatrick                    self.dump_sections(False, options)
1000061da546Spatrick                else:
1001061da546Spatrick                    print("No symbols")
1002061da546Spatrick            if options.find_mangled:
1003061da546Spatrick                self.dump_symbol_names_matching_regex(re.compile('^_?_Z'))
1004061da546Spatrick
1005061da546Spatrick        def dump_header(self, dump_description=True, options=None):
1006061da546Spatrick            if dump_description:
1007061da546Spatrick                print(self.description())
1008061da546Spatrick            print("Mach Header")
1009061da546Spatrick            print("       magic: %#8.8x %s" % (self.magic.value, self.magic))
1010061da546Spatrick            print("     cputype: %#8.8x %s" % (self.arch.cpu, self.arch))
1011061da546Spatrick            print("  cpusubtype: %#8.8x" % self.arch.sub)
1012061da546Spatrick            print("    filetype: %#8.8x %s" % (self.filetype.get_enum_value(), self.filetype.get_enum_name()))
1013061da546Spatrick            print("       ncmds: %#8.8x %u" % (self.ncmds, self.ncmds))
1014061da546Spatrick            print("  sizeofcmds: %#8.8x" % self.sizeofcmds)
1015061da546Spatrick            print("       flags: %#8.8x %s" % (self.flags.bits, self.flags))
1016061da546Spatrick
1017061da546Spatrick        def dump_load_commands(self, dump_description=True, options=None):
1018061da546Spatrick            if dump_description:
1019061da546Spatrick                print(self.description())
1020061da546Spatrick            for lc in self.commands:
1021061da546Spatrick                print(lc)
1022061da546Spatrick
1023061da546Spatrick        def get_section_by_name(self, name):
1024061da546Spatrick            for section in self.sections:
1025061da546Spatrick                if section.sectname and section.sectname == name:
1026061da546Spatrick                    return section
1027061da546Spatrick            return None
1028061da546Spatrick
1029061da546Spatrick        def get_section_by_section(self, other_section):
1030061da546Spatrick            for section in self.sections:
1031061da546Spatrick                if section.sectname == other_section.sectname and section.segname == other_section.segname:
1032061da546Spatrick                    return section
1033061da546Spatrick            return None
1034061da546Spatrick
1035061da546Spatrick        def dump_sections(self, dump_description=True, options=None):
1036061da546Spatrick            if dump_description:
1037061da546Spatrick                print(self.description())
1038061da546Spatrick            num_sections = len(self.sections)
1039061da546Spatrick            if num_sections > 1:
1040061da546Spatrick                self.sections[1].dump_header()
1041061da546Spatrick                for sect_idx in range(1, num_sections):
1042061da546Spatrick                    print("%s" % self.sections[sect_idx])
1043061da546Spatrick
1044061da546Spatrick        def dump_section_contents(self, options):
1045061da546Spatrick            saved_section_to_disk = False
1046061da546Spatrick            for sectname in options.section_names:
1047061da546Spatrick                section = self.get_section_by_name(sectname)
1048061da546Spatrick                if section:
1049061da546Spatrick                    sect_bytes = section.get_contents(self)
1050061da546Spatrick                    if options.outfile:
1051061da546Spatrick                        if not saved_section_to_disk:
1052061da546Spatrick                            outfile = open(options.outfile, 'w')
1053061da546Spatrick                            if options.extract_modules:
1054061da546Spatrick                                # print "Extracting modules from mach file..."
1055061da546Spatrick                                data = file_extract.FileExtract(
1056061da546Spatrick                                    io.BytesIO(sect_bytes), self.data.byte_order)
1057061da546Spatrick                                version = data.get_uint32()
1058061da546Spatrick                                num_modules = data.get_uint32()
1059061da546Spatrick                                # print "version = %u, num_modules = %u" %
1060061da546Spatrick                                # (version, num_modules)
1061061da546Spatrick                                for i in range(num_modules):
1062061da546Spatrick                                    data_offset = data.get_uint64()
1063061da546Spatrick                                    data_size = data.get_uint64()
1064061da546Spatrick                                    name_offset = data.get_uint32()
1065061da546Spatrick                                    language = data.get_uint32()
1066061da546Spatrick                                    flags = data.get_uint32()
1067061da546Spatrick                                    data.seek(name_offset)
1068061da546Spatrick                                    module_name = data.get_c_string()
1069061da546Spatrick                                    # print "module[%u] data_offset = %#16.16x,
1070061da546Spatrick                                    # data_size = %#16.16x, name_offset =
1071061da546Spatrick                                    # %#16.16x (%s), language = %u, flags =
1072061da546Spatrick                                    # %#x" % (i, data_offset, data_size,
1073061da546Spatrick                                    # name_offset, module_name, language,
1074061da546Spatrick                                    # flags)
1075061da546Spatrick                                    data.seek(data_offset)
1076061da546Spatrick                                    outfile.write(data.read_size(data_size))
1077061da546Spatrick                            else:
1078061da546Spatrick                                print("Saving section %s to '%s'" % (sectname, options.outfile))
1079061da546Spatrick                                outfile.write(sect_bytes)
1080061da546Spatrick                            outfile.close()
1081061da546Spatrick                            saved_section_to_disk = True
1082061da546Spatrick                        else:
1083061da546Spatrick                            print("error: you can only save a single section to disk at a time, skipping section '%s'" % (sectname))
1084061da546Spatrick                    else:
1085061da546Spatrick                        print('section %s:\n' % (sectname))
1086061da546Spatrick                        section.dump_header()
1087061da546Spatrick                        print('%s\n' % (section))
1088061da546Spatrick                        dump_memory(0, sect_bytes, options.max_count, 16)
1089061da546Spatrick                else:
1090061da546Spatrick                    print('error: no section named "%s" was found' % (sectname))
1091061da546Spatrick
1092061da546Spatrick        def get_segment(self, segname):
1093061da546Spatrick            if len(self.segments) == 1 and self.segments[0].segname == '':
1094061da546Spatrick                return self.segments[0]
1095061da546Spatrick            for segment in self.segments:
1096061da546Spatrick                if segment.segname == segname:
1097061da546Spatrick                    return segment
1098061da546Spatrick            return None
1099061da546Spatrick
1100061da546Spatrick        def get_first_load_command(self, lc_enum_value):
1101061da546Spatrick            for lc in self.commands:
1102061da546Spatrick                if lc.command.value == lc_enum_value:
1103061da546Spatrick                    return lc
1104061da546Spatrick            return None
1105061da546Spatrick
1106061da546Spatrick        def get_symtab(self):
1107061da546Spatrick            if self.data and not self.symbols:
1108061da546Spatrick                lc_symtab = self.get_first_load_command(LC_SYMTAB)
1109061da546Spatrick                if lc_symtab:
1110061da546Spatrick                    symtab_offset = self.file_off
1111061da546Spatrick                    if self.data.is_in_memory():
1112061da546Spatrick                        linkedit_segment = self.get_segment('__LINKEDIT')
1113061da546Spatrick                        if linkedit_segment:
1114061da546Spatrick                            linkedit_vmaddr = linkedit_segment.vmaddr
1115061da546Spatrick                            linkedit_fileoff = linkedit_segment.fileoff
1116061da546Spatrick                            symtab_offset = linkedit_vmaddr + lc_symtab.symoff - linkedit_fileoff
1117061da546Spatrick                            symtab_offset = linkedit_vmaddr + lc_symtab.stroff - linkedit_fileoff
1118061da546Spatrick                    else:
1119061da546Spatrick                        symtab_offset += lc_symtab.symoff
1120061da546Spatrick
1121061da546Spatrick                    self.data.seek(symtab_offset)
1122061da546Spatrick                    is_64 = self.is_64_bit()
1123061da546Spatrick                    for i in range(lc_symtab.nsyms):
1124061da546Spatrick                        nlist = Mach.NList()
1125061da546Spatrick                        nlist.unpack(self, self.data, lc_symtab)
1126061da546Spatrick                        self.symbols.append(nlist)
1127061da546Spatrick                else:
1128061da546Spatrick                    print("no LC_SYMTAB")
1129061da546Spatrick
1130061da546Spatrick        def dump_symtab(self, dump_description=True, options=None):
1131061da546Spatrick            self.get_symtab()
1132061da546Spatrick            if dump_description:
1133061da546Spatrick                print(self.description())
1134061da546Spatrick            for i, symbol in enumerate(self.symbols):
1135061da546Spatrick                print('[%5u] %s' % (i, symbol))
1136061da546Spatrick
1137061da546Spatrick        def dump_symbol_names_matching_regex(self, regex, file=None):
1138061da546Spatrick            self.get_symtab()
1139061da546Spatrick            for symbol in self.symbols:
1140061da546Spatrick                if symbol.name and regex.search(symbol.name):
1141061da546Spatrick                    print(symbol.name)
1142061da546Spatrick                    if file:
1143061da546Spatrick                        file.write('%s\n' % (symbol.name))
1144061da546Spatrick
1145061da546Spatrick        def is_64_bit(self):
1146061da546Spatrick            return self.magic.is_64_bit()
1147061da546Spatrick
1148061da546Spatrick    class LoadCommand:
1149061da546Spatrick
1150061da546Spatrick        class Command(dict_utils.Enum):
1151061da546Spatrick            enum = {
1152061da546Spatrick                'LC_SEGMENT': LC_SEGMENT,
1153061da546Spatrick                'LC_SYMTAB': LC_SYMTAB,
1154061da546Spatrick                'LC_SYMSEG': LC_SYMSEG,
1155061da546Spatrick                'LC_THREAD': LC_THREAD,
1156061da546Spatrick                'LC_UNIXTHREAD': LC_UNIXTHREAD,
1157061da546Spatrick                'LC_LOADFVMLIB': LC_LOADFVMLIB,
1158061da546Spatrick                'LC_IDFVMLIB': LC_IDFVMLIB,
1159061da546Spatrick                'LC_IDENT': LC_IDENT,
1160061da546Spatrick                'LC_FVMFILE': LC_FVMFILE,
1161061da546Spatrick                'LC_PREPAGE': LC_PREPAGE,
1162061da546Spatrick                'LC_DYSYMTAB': LC_DYSYMTAB,
1163061da546Spatrick                'LC_LOAD_DYLIB': LC_LOAD_DYLIB,
1164061da546Spatrick                'LC_ID_DYLIB': LC_ID_DYLIB,
1165061da546Spatrick                'LC_LOAD_DYLINKER': LC_LOAD_DYLINKER,
1166061da546Spatrick                'LC_ID_DYLINKER': LC_ID_DYLINKER,
1167061da546Spatrick                'LC_PREBOUND_DYLIB': LC_PREBOUND_DYLIB,
1168061da546Spatrick                'LC_ROUTINES': LC_ROUTINES,
1169061da546Spatrick                'LC_SUB_FRAMEWORK': LC_SUB_FRAMEWORK,
1170061da546Spatrick                'LC_SUB_UMBRELLA': LC_SUB_UMBRELLA,
1171061da546Spatrick                'LC_SUB_CLIENT': LC_SUB_CLIENT,
1172061da546Spatrick                'LC_SUB_LIBRARY': LC_SUB_LIBRARY,
1173061da546Spatrick                'LC_TWOLEVEL_HINTS': LC_TWOLEVEL_HINTS,
1174061da546Spatrick                'LC_PREBIND_CKSUM': LC_PREBIND_CKSUM,
1175061da546Spatrick                'LC_LOAD_WEAK_DYLIB': LC_LOAD_WEAK_DYLIB,
1176061da546Spatrick                'LC_SEGMENT_64': LC_SEGMENT_64,
1177061da546Spatrick                'LC_ROUTINES_64': LC_ROUTINES_64,
1178061da546Spatrick                'LC_UUID': LC_UUID,
1179061da546Spatrick                'LC_RPATH': LC_RPATH,
1180061da546Spatrick                'LC_CODE_SIGNATURE': LC_CODE_SIGNATURE,
1181061da546Spatrick                'LC_SEGMENT_SPLIT_INFO': LC_SEGMENT_SPLIT_INFO,
1182061da546Spatrick                'LC_REEXPORT_DYLIB': LC_REEXPORT_DYLIB,
1183061da546Spatrick                'LC_LAZY_LOAD_DYLIB': LC_LAZY_LOAD_DYLIB,
1184061da546Spatrick                'LC_ENCRYPTION_INFO': LC_ENCRYPTION_INFO,
1185061da546Spatrick                'LC_DYLD_INFO': LC_DYLD_INFO,
1186061da546Spatrick                'LC_DYLD_INFO_ONLY': LC_DYLD_INFO_ONLY,
1187061da546Spatrick                'LC_LOAD_UPWARD_DYLIB': LC_LOAD_UPWARD_DYLIB,
1188061da546Spatrick                'LC_VERSION_MIN_MACOSX': LC_VERSION_MIN_MACOSX,
1189061da546Spatrick                'LC_VERSION_MIN_IPHONEOS': LC_VERSION_MIN_IPHONEOS,
1190061da546Spatrick                'LC_FUNCTION_STARTS': LC_FUNCTION_STARTS,
1191061da546Spatrick                'LC_DYLD_ENVIRONMENT': LC_DYLD_ENVIRONMENT
1192061da546Spatrick            }
1193061da546Spatrick
1194061da546Spatrick            def __init__(self, initial_value=0):
1195061da546Spatrick                dict_utils.Enum.__init__(self, initial_value, self.enum)
1196061da546Spatrick
1197061da546Spatrick        def __init__(self, c=None, l=0, o=0):
1198061da546Spatrick            if c is not None:
1199061da546Spatrick                self.command = c
1200061da546Spatrick            else:
1201061da546Spatrick                self.command = Mach.LoadCommand.Command(0)
1202061da546Spatrick            self.length = l
1203061da546Spatrick            self.file_off = o
1204061da546Spatrick
1205061da546Spatrick        def unpack(self, mach_file, data):
1206061da546Spatrick            self.file_off = data.tell()
1207061da546Spatrick            self.command.value, self.length = data.get_n_uint32(2)
1208061da546Spatrick
1209061da546Spatrick        def skip(self, data):
1210061da546Spatrick            data.seek(self.file_off + self.length, 0)
1211061da546Spatrick
1212061da546Spatrick        def __str__(self):
1213061da546Spatrick            lc_name = self.command.get_enum_name()
1214061da546Spatrick            return '%#8.8x: <%#4.4x> %-24s' % (self.file_off,
1215061da546Spatrick                                               self.length, lc_name)
1216061da546Spatrick
1217061da546Spatrick    class Section:
1218061da546Spatrick
1219061da546Spatrick        def __init__(self):
1220061da546Spatrick            self.index = 0
1221061da546Spatrick            self.is_64 = False
1222061da546Spatrick            self.sectname = None
1223061da546Spatrick            self.segname = None
1224061da546Spatrick            self.addr = 0
1225061da546Spatrick            self.size = 0
1226061da546Spatrick            self.offset = 0
1227061da546Spatrick            self.align = 0
1228061da546Spatrick            self.reloff = 0
1229061da546Spatrick            self.nreloc = 0
1230061da546Spatrick            self.flags = 0
1231061da546Spatrick            self.reserved1 = 0
1232061da546Spatrick            self.reserved2 = 0
1233061da546Spatrick            self.reserved3 = 0
1234061da546Spatrick
1235061da546Spatrick        def unpack(self, is_64, data):
1236061da546Spatrick            self.is_64 = is_64
1237061da546Spatrick            self.sectname = data.get_fixed_length_c_string(16, '', True)
1238061da546Spatrick            self.segname = data.get_fixed_length_c_string(16, '', True)
1239061da546Spatrick            if self.is_64:
1240061da546Spatrick                self.addr, self.size = data.get_n_uint64(2)
1241061da546Spatrick                self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3 = data.get_n_uint32(
1242061da546Spatrick                    8)
1243061da546Spatrick            else:
1244061da546Spatrick                self.addr, self.size = data.get_n_uint32(2)
1245061da546Spatrick                self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2 = data.get_n_uint32(
1246061da546Spatrick                    7)
1247061da546Spatrick
1248061da546Spatrick        def dump_header(self):
1249061da546Spatrick            if self.is_64:
1250061da546Spatrick                print("INDEX ADDRESS            SIZE               OFFSET     ALIGN      RELOFF     NRELOC     FLAGS      RESERVED1  RESERVED2  RESERVED3  NAME")
1251061da546Spatrick                print("===== ------------------ ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------")
1252061da546Spatrick            else:
1253061da546Spatrick                print("INDEX ADDRESS    SIZE       OFFSET     ALIGN      RELOFF     NRELOC     FLAGS      RESERVED1  RESERVED2  NAME")
1254061da546Spatrick                print("===== ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------")
1255061da546Spatrick
1256061da546Spatrick        def __str__(self):
1257061da546Spatrick            if self.is_64:
1258061da546Spatrick                return "[%3u] %#16.16x %#16.16x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (
1259061da546Spatrick                    self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3, self.segname, self.sectname)
1260061da546Spatrick            else:
1261061da546Spatrick                return "[%3u] %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (
1262061da546Spatrick                    self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.segname, self.sectname)
1263061da546Spatrick
1264061da546Spatrick        def get_contents(self, mach_file):
1265061da546Spatrick            '''Get the section contents as a python string'''
1266061da546Spatrick            if self.size > 0 and mach_file.get_segment(
1267061da546Spatrick                    self.segname).filesize > 0:
1268061da546Spatrick                data = mach_file.get_data()
1269061da546Spatrick                if data:
1270061da546Spatrick                    section_data_offset = mach_file.file_off + self.offset
1271061da546Spatrick                    # print '%s.%s is at offset 0x%x with size 0x%x' %
1272061da546Spatrick                    # (self.segname, self.sectname, section_data_offset,
1273061da546Spatrick                    # self.size)
1274061da546Spatrick                    data.push_offset_and_seek(section_data_offset)
1275061da546Spatrick                    bytes = data.read_size(self.size)
1276061da546Spatrick                    data.pop_offset_and_seek()
1277061da546Spatrick                    return bytes
1278061da546Spatrick            return None
1279061da546Spatrick
1280061da546Spatrick    class DylibLoadCommand(LoadCommand):
1281061da546Spatrick
1282061da546Spatrick        def __init__(self, lc):
1283061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1284061da546Spatrick            self.name = None
1285061da546Spatrick            self.timestamp = 0
1286061da546Spatrick            self.current_version = 0
1287061da546Spatrick            self.compatibility_version = 0
1288061da546Spatrick
1289061da546Spatrick        def unpack(self, mach_file, data):
1290061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1291061da546Spatrick            name_offset, self.timestamp, self.current_version, self.compatibility_version = data.get_n_uint32(
1292061da546Spatrick                4)
1293061da546Spatrick            data.seek(self.file_off + name_offset, 0)
1294061da546Spatrick            self.name = data.get_fixed_length_c_string(self.length - 24)
1295061da546Spatrick
1296061da546Spatrick        def __str__(self):
1297061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1298061da546Spatrick            s += "%#8.8x %#8.8x %#8.8x " % (self.timestamp,
1299061da546Spatrick                                            self.current_version,
1300061da546Spatrick                                            self.compatibility_version)
1301061da546Spatrick            s += self.name
1302061da546Spatrick            return s
1303061da546Spatrick
1304061da546Spatrick    class LoadDYLDLoadCommand(LoadCommand):
1305061da546Spatrick
1306061da546Spatrick        def __init__(self, lc):
1307061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1308061da546Spatrick            self.name = None
1309061da546Spatrick
1310061da546Spatrick        def unpack(self, mach_file, data):
1311061da546Spatrick            data.get_uint32()
1312061da546Spatrick            self.name = data.get_fixed_length_c_string(self.length - 12)
1313061da546Spatrick
1314061da546Spatrick        def __str__(self):
1315061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1316061da546Spatrick            s += "%s" % self.name
1317061da546Spatrick            return s
1318061da546Spatrick
1319061da546Spatrick    class UnixThreadLoadCommand(LoadCommand):
1320061da546Spatrick
1321061da546Spatrick        class ThreadState:
1322061da546Spatrick
1323061da546Spatrick            def __init__(self):
1324061da546Spatrick                self.flavor = 0
1325061da546Spatrick                self.count = 0
1326061da546Spatrick                self.register_values = list()
1327061da546Spatrick
1328061da546Spatrick            def unpack(self, data):
1329061da546Spatrick                self.flavor, self.count = data.get_n_uint32(2)
1330061da546Spatrick                self.register_values = data.get_n_uint32(self.count)
1331061da546Spatrick
1332061da546Spatrick            def __str__(self):
1333061da546Spatrick                s = "flavor = %u, count = %u, regs =" % (
1334061da546Spatrick                    self.flavor, self.count)
1335061da546Spatrick                i = 0
1336061da546Spatrick                for register_value in self.register_values:
1337061da546Spatrick                    if i % 8 == 0:
1338061da546Spatrick                        s += "\n                                            "
1339061da546Spatrick                    s += " %#8.8x" % register_value
1340061da546Spatrick                    i += 1
1341061da546Spatrick                return s
1342061da546Spatrick
1343061da546Spatrick        def __init__(self, lc):
1344061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1345061da546Spatrick            self.reg_sets = list()
1346061da546Spatrick
1347061da546Spatrick        def unpack(self, mach_file, data):
1348061da546Spatrick            reg_set = Mach.UnixThreadLoadCommand.ThreadState()
1349061da546Spatrick            reg_set.unpack(data)
1350061da546Spatrick            self.reg_sets.append(reg_set)
1351061da546Spatrick
1352061da546Spatrick        def __str__(self):
1353061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1354061da546Spatrick            for reg_set in self.reg_sets:
1355061da546Spatrick                s += "%s" % reg_set
1356061da546Spatrick            return s
1357061da546Spatrick
1358061da546Spatrick    class DYLDInfoOnlyLoadCommand(LoadCommand):
1359061da546Spatrick
1360061da546Spatrick        def __init__(self, lc):
1361061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1362061da546Spatrick            self.rebase_off = 0
1363061da546Spatrick            self.rebase_size = 0
1364061da546Spatrick            self.bind_off = 0
1365061da546Spatrick            self.bind_size = 0
1366061da546Spatrick            self.weak_bind_off = 0
1367061da546Spatrick            self.weak_bind_size = 0
1368061da546Spatrick            self.lazy_bind_off = 0
1369061da546Spatrick            self.lazy_bind_size = 0
1370061da546Spatrick            self.export_off = 0
1371061da546Spatrick            self.export_size = 0
1372061da546Spatrick
1373061da546Spatrick        def unpack(self, mach_file, data):
1374061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1375061da546Spatrick            self.rebase_off, self.rebase_size, self.bind_off, self.bind_size, self.weak_bind_off, self.weak_bind_size, self.lazy_bind_off, self.lazy_bind_size, self.export_off, self.export_size = data.get_n_uint32(
1376061da546Spatrick                10)
1377061da546Spatrick
1378061da546Spatrick        def __str__(self):
1379061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1380061da546Spatrick            s += "rebase_off = %#8.8x, rebase_size = %u, " % (
1381061da546Spatrick                self.rebase_off, self.rebase_size)
1382061da546Spatrick            s += "bind_off = %#8.8x, bind_size = %u, " % (
1383061da546Spatrick                self.bind_off, self.bind_size)
1384061da546Spatrick            s += "weak_bind_off = %#8.8x, weak_bind_size = %u, " % (
1385061da546Spatrick                self.weak_bind_off, self.weak_bind_size)
1386061da546Spatrick            s += "lazy_bind_off = %#8.8x, lazy_bind_size = %u, " % (
1387061da546Spatrick                self.lazy_bind_off, self.lazy_bind_size)
1388061da546Spatrick            s += "export_off = %#8.8x, export_size = %u, " % (
1389061da546Spatrick                self.export_off, self.export_size)
1390061da546Spatrick            return s
1391061da546Spatrick
1392061da546Spatrick    class DYLDSymtabLoadCommand(LoadCommand):
1393061da546Spatrick
1394061da546Spatrick        def __init__(self, lc):
1395061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1396061da546Spatrick            self.ilocalsym = 0
1397061da546Spatrick            self.nlocalsym = 0
1398061da546Spatrick            self.iextdefsym = 0
1399061da546Spatrick            self.nextdefsym = 0
1400061da546Spatrick            self.iundefsym = 0
1401061da546Spatrick            self.nundefsym = 0
1402061da546Spatrick            self.tocoff = 0
1403061da546Spatrick            self.ntoc = 0
1404061da546Spatrick            self.modtaboff = 0
1405061da546Spatrick            self.nmodtab = 0
1406061da546Spatrick            self.extrefsymoff = 0
1407061da546Spatrick            self.nextrefsyms = 0
1408061da546Spatrick            self.indirectsymoff = 0
1409061da546Spatrick            self.nindirectsyms = 0
1410061da546Spatrick            self.extreloff = 0
1411061da546Spatrick            self.nextrel = 0
1412061da546Spatrick            self.locreloff = 0
1413061da546Spatrick            self.nlocrel = 0
1414061da546Spatrick
1415061da546Spatrick        def unpack(self, mach_file, data):
1416061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1417061da546Spatrick            self.ilocalsym, self.nlocalsym, self.iextdefsym, self.nextdefsym, self.iundefsym, self.nundefsym, self.tocoff, self.ntoc, self.modtaboff, self.nmodtab, self.extrefsymoff, self.nextrefsyms, self.indirectsymoff, self.nindirectsyms, self.extreloff, self.nextrel, self.locreloff, self.nlocrel = data.get_n_uint32(
1418061da546Spatrick                18)
1419061da546Spatrick
1420061da546Spatrick        def __str__(self):
1421061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1422061da546Spatrick            # s += "ilocalsym = %u, nlocalsym = %u, " % (self.ilocalsym, self.nlocalsym)
1423061da546Spatrick            # s += "iextdefsym = %u, nextdefsym = %u, " % (self.iextdefsym, self.nextdefsym)
1424061da546Spatrick            # s += "iundefsym %u, nundefsym = %u, " % (self.iundefsym, self.nundefsym)
1425061da546Spatrick            # s += "tocoff = %#8.8x, ntoc = %u, " % (self.tocoff, self.ntoc)
1426061da546Spatrick            # s += "modtaboff = %#8.8x, nmodtab = %u, " % (self.modtaboff, self.nmodtab)
1427061da546Spatrick            # s += "extrefsymoff = %#8.8x, nextrefsyms = %u, " % (self.extrefsymoff, self.nextrefsyms)
1428061da546Spatrick            # s += "indirectsymoff = %#8.8x, nindirectsyms = %u, " % (self.indirectsymoff, self.nindirectsyms)
1429061da546Spatrick            # s += "extreloff = %#8.8x, nextrel = %u, " % (self.extreloff, self.nextrel)
1430061da546Spatrick            # s += "locreloff = %#8.8x, nlocrel = %u" % (self.locreloff,
1431061da546Spatrick            # self.nlocrel)
1432061da546Spatrick            s += "ilocalsym      = %-10u, nlocalsym     = %u\n" % (
1433061da546Spatrick                self.ilocalsym, self.nlocalsym)
1434061da546Spatrick            s += "                                             iextdefsym     = %-10u, nextdefsym    = %u\n" % (
1435061da546Spatrick                self.iextdefsym, self.nextdefsym)
1436061da546Spatrick            s += "                                             iundefsym      = %-10u, nundefsym     = %u\n" % (
1437061da546Spatrick                self.iundefsym, self.nundefsym)
1438061da546Spatrick            s += "                                             tocoff         = %#8.8x, ntoc          = %u\n" % (
1439061da546Spatrick                self.tocoff, self.ntoc)
1440061da546Spatrick            s += "                                             modtaboff      = %#8.8x, nmodtab       = %u\n" % (
1441061da546Spatrick                self.modtaboff, self.nmodtab)
1442061da546Spatrick            s += "                                             extrefsymoff   = %#8.8x, nextrefsyms   = %u\n" % (
1443061da546Spatrick                self.extrefsymoff, self.nextrefsyms)
1444061da546Spatrick            s += "                                             indirectsymoff = %#8.8x, nindirectsyms = %u\n" % (
1445061da546Spatrick                self.indirectsymoff, self.nindirectsyms)
1446061da546Spatrick            s += "                                             extreloff      = %#8.8x, nextrel       = %u\n" % (
1447061da546Spatrick                self.extreloff, self.nextrel)
1448061da546Spatrick            s += "                                             locreloff      = %#8.8x, nlocrel       = %u" % (
1449061da546Spatrick                self.locreloff, self.nlocrel)
1450061da546Spatrick            return s
1451061da546Spatrick
1452061da546Spatrick    class SymtabLoadCommand(LoadCommand):
1453061da546Spatrick
1454061da546Spatrick        def __init__(self, lc):
1455061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1456061da546Spatrick            self.symoff = 0
1457061da546Spatrick            self.nsyms = 0
1458061da546Spatrick            self.stroff = 0
1459061da546Spatrick            self.strsize = 0
1460061da546Spatrick
1461061da546Spatrick        def unpack(self, mach_file, data):
1462061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1463061da546Spatrick            self.symoff, self.nsyms, self.stroff, self.strsize = data.get_n_uint32(
1464061da546Spatrick                4)
1465061da546Spatrick
1466061da546Spatrick        def __str__(self):
1467061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1468061da546Spatrick            s += "symoff = %#8.8x, nsyms = %u, stroff = %#8.8x, strsize = %u" % (
1469061da546Spatrick                self.symoff, self.nsyms, self.stroff, self.strsize)
1470061da546Spatrick            return s
1471061da546Spatrick
1472061da546Spatrick    class UUIDLoadCommand(LoadCommand):
1473061da546Spatrick
1474061da546Spatrick        def __init__(self, lc):
1475061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1476061da546Spatrick            self.uuid = None
1477061da546Spatrick
1478061da546Spatrick        def unpack(self, mach_file, data):
1479061da546Spatrick            uuid_data = data.get_n_uint8(16)
1480061da546Spatrick            uuid_str = ''
1481061da546Spatrick            for byte in uuid_data:
1482061da546Spatrick                uuid_str += '%2.2x' % byte
1483061da546Spatrick            self.uuid = uuid.UUID(uuid_str)
1484061da546Spatrick            mach_file.uuid = self.uuid
1485061da546Spatrick
1486061da546Spatrick        def __str__(self):
1487061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1488061da546Spatrick            s += self.uuid.__str__()
1489061da546Spatrick            return s
1490061da546Spatrick
1491061da546Spatrick    class DataBlobLoadCommand(LoadCommand):
1492061da546Spatrick
1493061da546Spatrick        def __init__(self, lc):
1494061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1495061da546Spatrick            self.dataoff = 0
1496061da546Spatrick            self.datasize = 0
1497061da546Spatrick
1498061da546Spatrick        def unpack(self, mach_file, data):
1499061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1500061da546Spatrick            self.dataoff, self.datasize = data.get_n_uint32(2)
1501061da546Spatrick
1502061da546Spatrick        def __str__(self):
1503061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1504061da546Spatrick            s += "dataoff = %#8.8x, datasize = %u" % (
1505061da546Spatrick                self.dataoff, self.datasize)
1506061da546Spatrick            return s
1507061da546Spatrick
1508061da546Spatrick    class EncryptionInfoLoadCommand(LoadCommand):
1509061da546Spatrick
1510061da546Spatrick        def __init__(self, lc):
1511061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1512061da546Spatrick            self.cryptoff = 0
1513061da546Spatrick            self.cryptsize = 0
1514061da546Spatrick            self.cryptid = 0
1515061da546Spatrick
1516061da546Spatrick        def unpack(self, mach_file, data):
1517061da546Spatrick            byte_order_char = mach_file.magic.get_byte_order()
1518061da546Spatrick            self.cryptoff, self.cryptsize, self.cryptid = data.get_n_uint32(3)
1519061da546Spatrick
1520061da546Spatrick        def __str__(self):
1521061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1522061da546Spatrick            s += "file-range = [%#8.8x - %#8.8x), cryptsize = %u, cryptid = %u" % (
1523061da546Spatrick                self.cryptoff, self.cryptoff + self.cryptsize, self.cryptsize, self.cryptid)
1524061da546Spatrick            return s
1525061da546Spatrick
1526061da546Spatrick    class SegmentLoadCommand(LoadCommand):
1527061da546Spatrick
1528061da546Spatrick        def __init__(self, lc):
1529061da546Spatrick            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
1530061da546Spatrick            self.segname = None
1531061da546Spatrick            self.vmaddr = 0
1532061da546Spatrick            self.vmsize = 0
1533061da546Spatrick            self.fileoff = 0
1534061da546Spatrick            self.filesize = 0
1535061da546Spatrick            self.maxprot = 0
1536061da546Spatrick            self.initprot = 0
1537061da546Spatrick            self.nsects = 0
1538061da546Spatrick            self.flags = 0
1539061da546Spatrick
1540061da546Spatrick        def unpack(self, mach_file, data):
1541061da546Spatrick            is_64 = self.command.get_enum_value() == LC_SEGMENT_64
1542061da546Spatrick            self.segname = data.get_fixed_length_c_string(16, '', True)
1543061da546Spatrick            if is_64:
1544061da546Spatrick                self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint64(
1545061da546Spatrick                    4)
1546061da546Spatrick            else:
1547061da546Spatrick                self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint32(
1548061da546Spatrick                    4)
1549061da546Spatrick            self.maxprot, self.initprot, self.nsects, self.flags = data.get_n_uint32(
1550061da546Spatrick                4)
1551061da546Spatrick            mach_file.segments.append(self)
1552061da546Spatrick            for i in range(self.nsects):
1553061da546Spatrick                section = Mach.Section()
1554061da546Spatrick                section.unpack(is_64, data)
1555061da546Spatrick                section.index = len(mach_file.sections)
1556061da546Spatrick                mach_file.sections.append(section)
1557061da546Spatrick
1558061da546Spatrick        def __str__(self):
1559061da546Spatrick            s = Mach.LoadCommand.__str__(self)
1560061da546Spatrick            if self.command.get_enum_value() == LC_SEGMENT:
1561061da546Spatrick                s += "%#8.8x %#8.8x %#8.8x %#8.8x " % (
1562061da546Spatrick                    self.vmaddr, self.vmsize, self.fileoff, self.filesize)
1563061da546Spatrick            else:
1564061da546Spatrick                s += "%#16.16x %#16.16x %#16.16x %#16.16x " % (
1565061da546Spatrick                    self.vmaddr, self.vmsize, self.fileoff, self.filesize)
1566061da546Spatrick            s += "%s %s %3u %#8.8x" % (vm_prot_names[self.maxprot], vm_prot_names[
1567061da546Spatrick                                       self.initprot], self.nsects, self.flags)
1568061da546Spatrick            s += ' ' + self.segname
1569061da546Spatrick            return s
1570061da546Spatrick
1571061da546Spatrick    class NList:
1572061da546Spatrick
1573061da546Spatrick        class Type:
1574061da546Spatrick
1575061da546Spatrick            class Stab(dict_utils.Enum):
1576061da546Spatrick                enum = {
1577061da546Spatrick                    'N_GSYM': N_GSYM,
1578061da546Spatrick                    'N_FNAME': N_FNAME,
1579061da546Spatrick                    'N_FUN': N_FUN,
1580061da546Spatrick                    'N_STSYM': N_STSYM,
1581061da546Spatrick                    'N_LCSYM': N_LCSYM,
1582061da546Spatrick                    'N_BNSYM': N_BNSYM,
1583061da546Spatrick                    'N_OPT': N_OPT,
1584061da546Spatrick                    'N_RSYM': N_RSYM,
1585061da546Spatrick                    'N_SLINE': N_SLINE,
1586061da546Spatrick                    'N_ENSYM': N_ENSYM,
1587061da546Spatrick                    'N_SSYM': N_SSYM,
1588061da546Spatrick                    'N_SO': N_SO,
1589061da546Spatrick                    'N_OSO': N_OSO,
1590061da546Spatrick                    'N_LSYM': N_LSYM,
1591061da546Spatrick                    'N_BINCL': N_BINCL,
1592061da546Spatrick                    'N_SOL': N_SOL,
1593061da546Spatrick                    'N_PARAMS': N_PARAMS,
1594061da546Spatrick                    'N_VERSION': N_VERSION,
1595061da546Spatrick                    'N_OLEVEL': N_OLEVEL,
1596061da546Spatrick                    'N_PSYM': N_PSYM,
1597061da546Spatrick                    'N_EINCL': N_EINCL,
1598061da546Spatrick                    'N_ENTRY': N_ENTRY,
1599061da546Spatrick                    'N_LBRAC': N_LBRAC,
1600061da546Spatrick                    'N_EXCL': N_EXCL,
1601061da546Spatrick                    'N_RBRAC': N_RBRAC,
1602061da546Spatrick                    'N_BCOMM': N_BCOMM,
1603061da546Spatrick                    'N_ECOMM': N_ECOMM,
1604061da546Spatrick                    'N_ECOML': N_ECOML,
1605061da546Spatrick                    'N_LENG': N_LENG
1606061da546Spatrick                }
1607061da546Spatrick
1608061da546Spatrick                def __init__(self, magic=0):
1609061da546Spatrick                    dict_utils.Enum.__init__(self, magic, self.enum)
1610061da546Spatrick
1611061da546Spatrick            def __init__(self, t=0):
1612061da546Spatrick                self.value = t
1613061da546Spatrick
1614061da546Spatrick            def __str__(self):
1615061da546Spatrick                n_type = self.value
1616061da546Spatrick                if n_type & N_STAB:
1617061da546Spatrick                    stab = Mach.NList.Type.Stab(self.value)
1618061da546Spatrick                    return '%s' % stab
1619061da546Spatrick                else:
1620061da546Spatrick                    type = self.value & N_TYPE
1621061da546Spatrick                    type_str = ''
1622061da546Spatrick                    if type == N_UNDF:
1623061da546Spatrick                        type_str = 'N_UNDF'
1624061da546Spatrick                    elif type == N_ABS:
1625061da546Spatrick                        type_str = 'N_ABS '
1626061da546Spatrick                    elif type == N_SECT:
1627061da546Spatrick                        type_str = 'N_SECT'
1628061da546Spatrick                    elif type == N_PBUD:
1629061da546Spatrick                        type_str = 'N_PBUD'
1630061da546Spatrick                    elif type == N_INDR:
1631061da546Spatrick                        type_str = 'N_INDR'
1632061da546Spatrick                    else:
1633061da546Spatrick                        type_str = "??? (%#2.2x)" % type
1634061da546Spatrick                    if n_type & N_PEXT:
1635061da546Spatrick                        type_str += ' | PEXT'
1636061da546Spatrick                    if n_type & N_EXT:
1637061da546Spatrick                        type_str += ' | EXT '
1638061da546Spatrick                    return type_str
1639061da546Spatrick
1640061da546Spatrick        def __init__(self):
1641061da546Spatrick            self.index = 0
1642061da546Spatrick            self.name_offset = 0
1643061da546Spatrick            self.name = 0
1644061da546Spatrick            self.type = Mach.NList.Type()
1645061da546Spatrick            self.sect_idx = 0
1646061da546Spatrick            self.desc = 0
1647061da546Spatrick            self.value = 0
1648061da546Spatrick
1649061da546Spatrick        def unpack(self, mach_file, data, symtab_lc):
1650061da546Spatrick            self.index = len(mach_file.symbols)
1651061da546Spatrick            self.name_offset = data.get_uint32()
1652061da546Spatrick            self.type.value, self.sect_idx = data.get_n_uint8(2)
1653061da546Spatrick            self.desc = data.get_uint16()
1654061da546Spatrick            if mach_file.is_64_bit():
1655061da546Spatrick                self.value = data.get_uint64()
1656061da546Spatrick            else:
1657061da546Spatrick                self.value = data.get_uint32()
1658061da546Spatrick            data.push_offset_and_seek(
1659061da546Spatrick                mach_file.file_off +
1660061da546Spatrick                symtab_lc.stroff +
1661061da546Spatrick                self.name_offset)
1662061da546Spatrick            # print "get string for symbol[%u]" % self.index
1663061da546Spatrick            self.name = data.get_c_string()
1664061da546Spatrick            data.pop_offset_and_seek()
1665061da546Spatrick
1666061da546Spatrick        def __str__(self):
1667061da546Spatrick            name_display = ''
1668061da546Spatrick            if len(self.name):
1669061da546Spatrick                name_display = ' "%s"' % self.name
1670061da546Spatrick            return '%#8.8x %#2.2x (%-20s) %#2.2x %#4.4x %16.16x%s' % (self.name_offset,
1671061da546Spatrick                                                                      self.type.value, self.type, self.sect_idx, self.desc, self.value, name_display)
1672061da546Spatrick
1673061da546Spatrick    class Interactive(cmd.Cmd):
1674061da546Spatrick        '''Interactive command interpreter to mach-o files.'''
1675061da546Spatrick
1676061da546Spatrick        def __init__(self, mach, options):
1677061da546Spatrick            cmd.Cmd.__init__(self)
1678061da546Spatrick            self.intro = 'Interactive mach-o command interpreter'
1679061da546Spatrick            self.prompt = 'mach-o: %s %% ' % mach.path
1680061da546Spatrick            self.mach = mach
1681061da546Spatrick            self.options = options
1682061da546Spatrick
1683061da546Spatrick        def default(self, line):
1684061da546Spatrick            '''Catch all for unknown command, which will exit the interpreter.'''
1685061da546Spatrick            print("uknown command: %s" % line)
1686061da546Spatrick            return True
1687061da546Spatrick
1688061da546Spatrick        def do_q(self, line):
1689061da546Spatrick            '''Quit command'''
1690061da546Spatrick            return True
1691061da546Spatrick
1692061da546Spatrick        def do_quit(self, line):
1693061da546Spatrick            '''Quit command'''
1694061da546Spatrick            return True
1695061da546Spatrick
1696061da546Spatrick        def do_header(self, line):
1697061da546Spatrick            '''Dump mach-o file headers'''
1698061da546Spatrick            self.mach.dump_header(True, self.options)
1699061da546Spatrick            return False
1700061da546Spatrick
1701061da546Spatrick        def do_load(self, line):
1702061da546Spatrick            '''Dump all mach-o load commands'''
1703061da546Spatrick            self.mach.dump_load_commands(True, self.options)
1704061da546Spatrick            return False
1705061da546Spatrick
1706061da546Spatrick        def do_sections(self, line):
1707061da546Spatrick            '''Dump all mach-o sections'''
1708061da546Spatrick            self.mach.dump_sections(True, self.options)
1709061da546Spatrick            return False
1710061da546Spatrick
1711061da546Spatrick        def do_symtab(self, line):
1712061da546Spatrick            '''Dump all mach-o symbols in the symbol table'''
1713061da546Spatrick            self.mach.dump_symtab(True, self.options)
1714061da546Spatrick            return False
1715061da546Spatrick
1716061da546Spatrickif __name__ == '__main__':
1717061da546Spatrick    parser = optparse.OptionParser(
1718061da546Spatrick        description='A script that parses skinny and universal mach-o files.')
1719061da546Spatrick    parser.add_option(
1720061da546Spatrick        '--arch',
1721061da546Spatrick        '-a',
1722061da546Spatrick        type='string',
1723061da546Spatrick        metavar='arch',
1724061da546Spatrick        dest='archs',
1725061da546Spatrick        action='append',
1726061da546Spatrick        help='specify one or more architectures by name')
1727061da546Spatrick    parser.add_option(
1728061da546Spatrick        '-v',
1729061da546Spatrick        '--verbose',
1730061da546Spatrick        action='store_true',
1731061da546Spatrick        dest='verbose',
1732061da546Spatrick        help='display verbose debug info',
1733061da546Spatrick        default=False)
1734061da546Spatrick    parser.add_option(
1735061da546Spatrick        '-H',
1736061da546Spatrick        '--header',
1737061da546Spatrick        action='store_true',
1738061da546Spatrick        dest='dump_header',
1739061da546Spatrick        help='dump the mach-o file header',
1740061da546Spatrick        default=False)
1741061da546Spatrick    parser.add_option(
1742061da546Spatrick        '-l',
1743061da546Spatrick        '--load-commands',
1744061da546Spatrick        action='store_true',
1745061da546Spatrick        dest='dump_load_commands',
1746061da546Spatrick        help='dump the mach-o load commands',
1747061da546Spatrick        default=False)
1748061da546Spatrick    parser.add_option(
1749061da546Spatrick        '-s',
1750061da546Spatrick        '--symtab',
1751061da546Spatrick        action='store_true',
1752061da546Spatrick        dest='dump_symtab',
1753061da546Spatrick        help='dump the mach-o symbol table',
1754061da546Spatrick        default=False)
1755061da546Spatrick    parser.add_option(
1756061da546Spatrick        '-S',
1757061da546Spatrick        '--sections',
1758061da546Spatrick        action='store_true',
1759061da546Spatrick        dest='dump_sections',
1760061da546Spatrick        help='dump the mach-o sections',
1761061da546Spatrick        default=False)
1762061da546Spatrick    parser.add_option(
1763061da546Spatrick        '--section',
1764061da546Spatrick        type='string',
1765061da546Spatrick        metavar='sectname',
1766061da546Spatrick        dest='section_names',
1767061da546Spatrick        action='append',
1768061da546Spatrick        help='Specify one or more section names to dump',
1769061da546Spatrick        default=[])
1770061da546Spatrick    parser.add_option(
1771061da546Spatrick        '-o',
1772061da546Spatrick        '--out',
1773061da546Spatrick        type='string',
1774061da546Spatrick        dest='outfile',
1775061da546Spatrick        help='Used in conjunction with the --section=NAME option to save a single section\'s data to disk.',
1776061da546Spatrick        default=False)
1777061da546Spatrick    parser.add_option(
1778061da546Spatrick        '-i',
1779061da546Spatrick        '--interactive',
1780061da546Spatrick        action='store_true',
1781061da546Spatrick        dest='interactive',
1782061da546Spatrick        help='enable interactive mode',
1783061da546Spatrick        default=False)
1784061da546Spatrick    parser.add_option(
1785061da546Spatrick        '-m',
1786061da546Spatrick        '--mangled',
1787061da546Spatrick        action='store_true',
1788061da546Spatrick        dest='find_mangled',
1789061da546Spatrick        help='dump all mangled names in a mach file',
1790061da546Spatrick        default=False)
1791061da546Spatrick    parser.add_option(
1792061da546Spatrick        '-c',
1793061da546Spatrick        '--compare',
1794061da546Spatrick        action='store_true',
1795061da546Spatrick        dest='compare',
1796061da546Spatrick        help='compare two mach files',
1797061da546Spatrick        default=False)
1798061da546Spatrick    parser.add_option(
1799061da546Spatrick        '-M',
1800061da546Spatrick        '--extract-modules',
1801061da546Spatrick        action='store_true',
1802061da546Spatrick        dest='extract_modules',
1803061da546Spatrick        help='Extract modules from file',
1804061da546Spatrick        default=False)
1805061da546Spatrick    parser.add_option(
1806061da546Spatrick        '-C',
1807061da546Spatrick        '--count',
1808061da546Spatrick        type='int',
1809061da546Spatrick        dest='max_count',
1810061da546Spatrick        help='Sets the max byte count when dumping section data',
1811061da546Spatrick        default=-1)
1812061da546Spatrick
1813061da546Spatrick    (options, mach_files) = parser.parse_args()
1814061da546Spatrick    if options.extract_modules:
1815061da546Spatrick        if options.section_names:
1816061da546Spatrick            print("error: can't use --section option with the --extract-modules option")
1817061da546Spatrick            exit(1)
1818061da546Spatrick        if not options.outfile:
1819061da546Spatrick            print("error: the --output=FILE option must be specified with the --extract-modules option")
1820061da546Spatrick            exit(1)
1821061da546Spatrick        options.section_names.append("__apple_ast")
1822061da546Spatrick    if options.compare:
1823061da546Spatrick        if len(mach_files) == 2:
1824061da546Spatrick            mach_a = Mach()
1825061da546Spatrick            mach_b = Mach()
1826061da546Spatrick            mach_a.parse(mach_files[0])
1827061da546Spatrick            mach_b.parse(mach_files[1])
1828061da546Spatrick            mach_a.compare(mach_b)
1829061da546Spatrick        else:
1830061da546Spatrick            print('error: --compare takes two mach files as arguments')
1831061da546Spatrick    else:
1832061da546Spatrick        if not (options.dump_header or options.dump_load_commands or options.dump_symtab or options.dump_sections or options.find_mangled or options.section_names):
1833061da546Spatrick            options.dump_header = True
1834061da546Spatrick            options.dump_load_commands = True
1835061da546Spatrick        if options.verbose:
1836061da546Spatrick            print('options', options)
1837061da546Spatrick            print('mach_files', mach_files)
1838061da546Spatrick        for path in mach_files:
1839061da546Spatrick            mach = Mach()
1840061da546Spatrick            mach.parse(path)
1841061da546Spatrick            if options.interactive:
1842061da546Spatrick                interpreter = Mach.Interactive(mach, options)
1843061da546Spatrick                interpreter.cmdloop()
1844061da546Spatrick            else:
1845061da546Spatrick                mach.dump(options)
1846