1*515bc8c1Sserge-sans-paille#!/usr/bin/env python
2525cd59fSSerge Gueltonfrom __future__ import print_function
36a23d212SGreg Clayton
46a23d212SGreg Claytonimport cmd
56a23d212SGreg Claytonimport dict_utils
66a23d212SGreg Claytonimport file_extract
76a23d212SGreg Claytonimport optparse
86a23d212SGreg Claytonimport re
96a23d212SGreg Claytonimport struct
106a23d212SGreg Claytonimport string
113a22c3ccSSerge Gueltonimport io
126a23d212SGreg Claytonimport sys
136a23d212SGreg Claytonimport uuid
146a23d212SGreg Clayton
156a23d212SGreg Clayton# Mach header "magic" constants
166a23d212SGreg ClaytonMH_MAGIC = 0xfeedface
176a23d212SGreg ClaytonMH_CIGAM = 0xcefaedfe
186a23d212SGreg ClaytonMH_MAGIC_64 = 0xfeedfacf
196a23d212SGreg ClaytonMH_CIGAM_64 = 0xcffaedfe
206a23d212SGreg ClaytonFAT_MAGIC = 0xcafebabe
216a23d212SGreg ClaytonFAT_CIGAM = 0xbebafeca
226a23d212SGreg Clayton
236a23d212SGreg Clayton# Mach haeder "filetype" constants
246a23d212SGreg ClaytonMH_OBJECT = 0x00000001
256a23d212SGreg ClaytonMH_EXECUTE = 0x00000002
266a23d212SGreg ClaytonMH_FVMLIB = 0x00000003
276a23d212SGreg ClaytonMH_CORE = 0x00000004
286a23d212SGreg ClaytonMH_PRELOAD = 0x00000005
296a23d212SGreg ClaytonMH_DYLIB = 0x00000006
306a23d212SGreg ClaytonMH_DYLINKER = 0x00000007
316a23d212SGreg ClaytonMH_BUNDLE = 0x00000008
326a23d212SGreg ClaytonMH_DYLIB_STUB = 0x00000009
336a23d212SGreg ClaytonMH_DSYM = 0x0000000a
346a23d212SGreg ClaytonMH_KEXT_BUNDLE = 0x0000000b
356a23d212SGreg Clayton
366a23d212SGreg Clayton# Mach haeder "flag" constant bits
376a23d212SGreg ClaytonMH_NOUNDEFS = 0x00000001
386a23d212SGreg ClaytonMH_INCRLINK = 0x00000002
396a23d212SGreg ClaytonMH_DYLDLINK = 0x00000004
406a23d212SGreg ClaytonMH_BINDATLOAD = 0x00000008
416a23d212SGreg ClaytonMH_PREBOUND = 0x00000010
426a23d212SGreg ClaytonMH_SPLIT_SEGS = 0x00000020
436a23d212SGreg ClaytonMH_LAZY_INIT = 0x00000040
446a23d212SGreg ClaytonMH_TWOLEVEL = 0x00000080
456a23d212SGreg ClaytonMH_FORCE_FLAT = 0x00000100
466a23d212SGreg ClaytonMH_NOMULTIDEFS = 0x00000200
476a23d212SGreg ClaytonMH_NOFIXPREBINDING = 0x00000400
486a23d212SGreg ClaytonMH_PREBINDABLE = 0x00000800
496a23d212SGreg ClaytonMH_ALLMODSBOUND = 0x00001000
506a23d212SGreg ClaytonMH_SUBSECTIONS_VIA_SYMBOLS = 0x00002000
516a23d212SGreg ClaytonMH_CANONICAL = 0x00004000
526a23d212SGreg ClaytonMH_WEAK_DEFINES = 0x00008000
536a23d212SGreg ClaytonMH_BINDS_TO_WEAK = 0x00010000
546a23d212SGreg ClaytonMH_ALLOW_STACK_EXECUTION = 0x00020000
556a23d212SGreg ClaytonMH_ROOT_SAFE = 0x00040000
566a23d212SGreg ClaytonMH_SETUID_SAFE = 0x00080000
576a23d212SGreg ClaytonMH_NO_REEXPORTED_DYLIBS = 0x00100000
586a23d212SGreg ClaytonMH_PIE = 0x00200000
596a23d212SGreg ClaytonMH_DEAD_STRIPPABLE_DYLIB = 0x00400000
606a23d212SGreg ClaytonMH_HAS_TLV_DESCRIPTORS = 0x00800000
616a23d212SGreg ClaytonMH_NO_HEAP_EXECUTION = 0x01000000
626a23d212SGreg Clayton
636a23d212SGreg Clayton# Mach load command constants
646a23d212SGreg ClaytonLC_REQ_DYLD = 0x80000000
656a23d212SGreg ClaytonLC_SEGMENT = 0x00000001
666a23d212SGreg ClaytonLC_SYMTAB = 0x00000002
676a23d212SGreg ClaytonLC_SYMSEG = 0x00000003
686a23d212SGreg ClaytonLC_THREAD = 0x00000004
696a23d212SGreg ClaytonLC_UNIXTHREAD = 0x00000005
706a23d212SGreg ClaytonLC_LOADFVMLIB = 0x00000006
716a23d212SGreg ClaytonLC_IDFVMLIB = 0x00000007
726a23d212SGreg ClaytonLC_IDENT = 0x00000008
736a23d212SGreg ClaytonLC_FVMFILE = 0x00000009
746a23d212SGreg ClaytonLC_PREPAGE = 0x0000000a
756a23d212SGreg ClaytonLC_DYSYMTAB = 0x0000000b
766a23d212SGreg ClaytonLC_LOAD_DYLIB = 0x0000000c
776a23d212SGreg ClaytonLC_ID_DYLIB = 0x0000000d
786a23d212SGreg ClaytonLC_LOAD_DYLINKER = 0x0000000e
796a23d212SGreg ClaytonLC_ID_DYLINKER = 0x0000000f
806a23d212SGreg ClaytonLC_PREBOUND_DYLIB = 0x00000010
816a23d212SGreg ClaytonLC_ROUTINES = 0x00000011
826a23d212SGreg ClaytonLC_SUB_FRAMEWORK = 0x00000012
836a23d212SGreg ClaytonLC_SUB_UMBRELLA = 0x00000013
846a23d212SGreg ClaytonLC_SUB_CLIENT = 0x00000014
856a23d212SGreg ClaytonLC_SUB_LIBRARY = 0x00000015
866a23d212SGreg ClaytonLC_TWOLEVEL_HINTS = 0x00000016
876a23d212SGreg ClaytonLC_PREBIND_CKSUM = 0x00000017
886a23d212SGreg ClaytonLC_LOAD_WEAK_DYLIB = 0x00000018 | LC_REQ_DYLD
896a23d212SGreg ClaytonLC_SEGMENT_64 = 0x00000019
906a23d212SGreg ClaytonLC_ROUTINES_64 = 0x0000001a
916a23d212SGreg ClaytonLC_UUID = 0x0000001b
926a23d212SGreg ClaytonLC_RPATH = 0x0000001c | LC_REQ_DYLD
936a23d212SGreg ClaytonLC_CODE_SIGNATURE = 0x0000001d
946a23d212SGreg ClaytonLC_SEGMENT_SPLIT_INFO = 0x0000001e
956a23d212SGreg ClaytonLC_REEXPORT_DYLIB = 0x0000001f | LC_REQ_DYLD
966a23d212SGreg ClaytonLC_LAZY_LOAD_DYLIB = 0x00000020
976a23d212SGreg ClaytonLC_ENCRYPTION_INFO = 0x00000021
986a23d212SGreg ClaytonLC_DYLD_INFO = 0x00000022
996a23d212SGreg ClaytonLC_DYLD_INFO_ONLY = 0x00000022 | LC_REQ_DYLD
1006a23d212SGreg ClaytonLC_LOAD_UPWARD_DYLIB = 0x00000023 | LC_REQ_DYLD
1016a23d212SGreg ClaytonLC_VERSION_MIN_MACOSX = 0x00000024
1026a23d212SGreg ClaytonLC_VERSION_MIN_IPHONEOS = 0x00000025
1036a23d212SGreg ClaytonLC_FUNCTION_STARTS = 0x00000026
1046a23d212SGreg ClaytonLC_DYLD_ENVIRONMENT = 0x00000027
1056a23d212SGreg Clayton
1066a23d212SGreg Clayton# Mach CPU constants
1076a23d212SGreg ClaytonCPU_ARCH_MASK = 0xff000000
1086a23d212SGreg ClaytonCPU_ARCH_ABI64 = 0x01000000
1096a23d212SGreg ClaytonCPU_TYPE_ANY = 0xffffffff
1106a23d212SGreg ClaytonCPU_TYPE_VAX = 1
1116a23d212SGreg ClaytonCPU_TYPE_MC680x0 = 6
1126a23d212SGreg ClaytonCPU_TYPE_I386 = 7
1136a23d212SGreg ClaytonCPU_TYPE_X86_64 = CPU_TYPE_I386 | CPU_ARCH_ABI64
1146a23d212SGreg ClaytonCPU_TYPE_MIPS = 8
1156a23d212SGreg ClaytonCPU_TYPE_MC98000 = 10
1166a23d212SGreg ClaytonCPU_TYPE_HPPA = 11
1176a23d212SGreg ClaytonCPU_TYPE_ARM = 12
1186a23d212SGreg ClaytonCPU_TYPE_MC88000 = 13
1196a23d212SGreg ClaytonCPU_TYPE_SPARC = 14
1206a23d212SGreg ClaytonCPU_TYPE_I860 = 15
1216a23d212SGreg ClaytonCPU_TYPE_ALPHA = 16
1226a23d212SGreg ClaytonCPU_TYPE_POWERPC = 18
1236a23d212SGreg ClaytonCPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64
1246a23d212SGreg Clayton
1256a23d212SGreg Clayton# VM protection constants
1266a23d212SGreg ClaytonVM_PROT_READ = 1
1276a23d212SGreg ClaytonVM_PROT_WRITE = 2
1286a23d212SGreg ClaytonVM_PROT_EXECUTE = 4
1296a23d212SGreg Clayton
1306a23d212SGreg Clayton# VM protection constants
1316a23d212SGreg ClaytonN_STAB = 0xe0
1326a23d212SGreg ClaytonN_PEXT = 0x10
1336a23d212SGreg ClaytonN_TYPE = 0x0e
1346a23d212SGreg ClaytonN_EXT = 0x01
1356a23d212SGreg Clayton
1366a23d212SGreg Clayton# Values for nlist N_TYPE bits of the "Mach.NList.type" field.
1376a23d212SGreg ClaytonN_UNDF = 0x0
1386a23d212SGreg ClaytonN_ABS = 0x2
1396a23d212SGreg ClaytonN_SECT = 0xe
1406a23d212SGreg ClaytonN_PBUD = 0xc
1416a23d212SGreg ClaytonN_INDR = 0xa
1426a23d212SGreg Clayton
1436a23d212SGreg Clayton# Section indexes for the "Mach.NList.sect_idx" fields
1446a23d212SGreg ClaytonNO_SECT = 0
1456a23d212SGreg ClaytonMAX_SECT = 255
1466a23d212SGreg Clayton
1476a23d212SGreg Clayton# Stab defines
1486a23d212SGreg ClaytonN_GSYM = 0x20
1496a23d212SGreg ClaytonN_FNAME = 0x22
1506a23d212SGreg ClaytonN_FUN = 0x24
1516a23d212SGreg ClaytonN_STSYM = 0x26
1526a23d212SGreg ClaytonN_LCSYM = 0x28
1536a23d212SGreg ClaytonN_BNSYM = 0x2e
1546a23d212SGreg ClaytonN_OPT = 0x3c
1556a23d212SGreg ClaytonN_RSYM = 0x40
1566a23d212SGreg ClaytonN_SLINE = 0x44
1576a23d212SGreg ClaytonN_ENSYM = 0x4e
1586a23d212SGreg ClaytonN_SSYM = 0x60
1596a23d212SGreg ClaytonN_SO = 0x64
1606a23d212SGreg ClaytonN_OSO = 0x66
1616a23d212SGreg ClaytonN_LSYM = 0x80
1626a23d212SGreg ClaytonN_BINCL = 0x82
1636a23d212SGreg ClaytonN_SOL = 0x84
1646a23d212SGreg ClaytonN_PARAMS = 0x86
1656a23d212SGreg ClaytonN_VERSION = 0x88
1666a23d212SGreg ClaytonN_OLEVEL = 0x8A
1676a23d212SGreg ClaytonN_PSYM = 0xa0
1686a23d212SGreg ClaytonN_EINCL = 0xa2
1696a23d212SGreg ClaytonN_ENTRY = 0xa4
1706a23d212SGreg ClaytonN_LBRAC = 0xc0
1716a23d212SGreg ClaytonN_EXCL = 0xc2
1726a23d212SGreg ClaytonN_RBRAC = 0xe0
1736a23d212SGreg ClaytonN_BCOMM = 0xe2
1746a23d212SGreg ClaytonN_ECOMM = 0xe4
1756a23d212SGreg ClaytonN_ECOML = 0xe8
1766a23d212SGreg ClaytonN_LENG = 0xfe
1776a23d212SGreg Clayton
1786a23d212SGreg Claytonvm_prot_names = ['---', 'r--', '-w-', 'rw-', '--x', 'r-x', '-wx', 'rwx']
1796a23d212SGreg Clayton
180b9c1b51eSKate Stone
1816a23d212SGreg Claytondef dump_memory(base_addr, data, hex_bytes_len, num_per_line):
1826a23d212SGreg Clayton    hex_bytes = data.encode('hex')
1836a23d212SGreg Clayton    if hex_bytes_len == -1:
1846a23d212SGreg Clayton        hex_bytes_len = len(hex_bytes)
1856a23d212SGreg Clayton    addr = base_addr
1866a23d212SGreg Clayton    ascii_str = ''
1876a23d212SGreg Clayton    i = 0
1886a23d212SGreg Clayton    while i < hex_bytes_len:
1896a23d212SGreg Clayton        if ((i / 2) % num_per_line) == 0:
1906a23d212SGreg Clayton            if i > 0:
191525cd59fSSerge Guelton                print(' %s' % (ascii_str))
1926a23d212SGreg Clayton                ascii_str = ''
193525cd59fSSerge Guelton            print('0x%8.8x:' % (addr + i), end=' ')
1946a23d212SGreg Clayton        hex_byte = hex_bytes[i:i + 2]
195525cd59fSSerge Guelton        print(hex_byte, end=' ')
1966a23d212SGreg Clayton        int_byte = int(hex_byte, 16)
1976a23d212SGreg Clayton        ascii_char = '%c' % (int_byte)
1986a23d212SGreg Clayton        if int_byte >= 32 and int_byte < 127:
1996a23d212SGreg Clayton            ascii_str += ascii_char
2006a23d212SGreg Clayton        else:
2016a23d212SGreg Clayton            ascii_str += '.'
2026a23d212SGreg Clayton        i = i + 2
2036a23d212SGreg Clayton    if ascii_str:
2046a23d212SGreg Clayton        if (i / 2) % num_per_line:
2056a23d212SGreg Clayton            padding = num_per_line - ((i / 2) % num_per_line)
2066a23d212SGreg Clayton        else:
2076a23d212SGreg Clayton            padding = 0
208525cd59fSSerge Guelton        print('%*s%s' % (padding * 3 + 1, '', ascii_str))
209525cd59fSSerge Guelton    print()
2106a23d212SGreg Clayton
2116a23d212SGreg Clayton
2126a23d212SGreg Claytonclass TerminalColors:
2136a23d212SGreg Clayton    '''Simple terminal colors class'''
214b9c1b51eSKate Stone
2156a23d212SGreg Clayton    def __init__(self, enabled=True):
2166a23d212SGreg Clayton        # TODO: discover terminal type from "file" and disable if
2176a23d212SGreg Clayton        # it can't handle the color codes
2186a23d212SGreg Clayton        self.enabled = enabled
2196a23d212SGreg Clayton
2206a23d212SGreg Clayton    def reset(self):
2216a23d212SGreg Clayton        '''Reset all terminal colors and formatting.'''
2226a23d212SGreg Clayton        if self.enabled:
223b9c1b51eSKate Stone            return "\x1b[0m"
2246a23d212SGreg Clayton        return ''
2256a23d212SGreg Clayton
2266a23d212SGreg Clayton    def bold(self, on=True):
227d93c4a33SBruce Mitchener        '''Enable or disable bold depending on the "on" parameter.'''
2286a23d212SGreg Clayton        if self.enabled:
2296a23d212SGreg Clayton            if on:
230b9c1b51eSKate Stone                return "\x1b[1m"
2316a23d212SGreg Clayton            else:
232b9c1b51eSKate Stone                return "\x1b[22m"
2336a23d212SGreg Clayton        return ''
2346a23d212SGreg Clayton
2356a23d212SGreg Clayton    def italics(self, on=True):
236d93c4a33SBruce Mitchener        '''Enable or disable italics depending on the "on" parameter.'''
2376a23d212SGreg Clayton        if self.enabled:
2386a23d212SGreg Clayton            if on:
239b9c1b51eSKate Stone                return "\x1b[3m"
2406a23d212SGreg Clayton            else:
241b9c1b51eSKate Stone                return "\x1b[23m"
2426a23d212SGreg Clayton        return ''
2436a23d212SGreg Clayton
2446a23d212SGreg Clayton    def underline(self, on=True):
245d93c4a33SBruce Mitchener        '''Enable or disable underline depending on the "on" parameter.'''
2466a23d212SGreg Clayton        if self.enabled:
2476a23d212SGreg Clayton            if on:
248b9c1b51eSKate Stone                return "\x1b[4m"
2496a23d212SGreg Clayton            else:
250b9c1b51eSKate Stone                return "\x1b[24m"
2516a23d212SGreg Clayton        return ''
2526a23d212SGreg Clayton
2536a23d212SGreg Clayton    def inverse(self, on=True):
254d93c4a33SBruce Mitchener        '''Enable or disable inverse depending on the "on" parameter.'''
2556a23d212SGreg Clayton        if self.enabled:
2566a23d212SGreg Clayton            if on:
257b9c1b51eSKate Stone                return "\x1b[7m"
2586a23d212SGreg Clayton            else:
259b9c1b51eSKate Stone                return "\x1b[27m"
2606a23d212SGreg Clayton        return ''
2616a23d212SGreg Clayton
2626a23d212SGreg Clayton    def strike(self, on=True):
263d93c4a33SBruce Mitchener        '''Enable or disable strike through depending on the "on" parameter.'''
2646a23d212SGreg Clayton        if self.enabled:
2656a23d212SGreg Clayton            if on:
266b9c1b51eSKate Stone                return "\x1b[9m"
2676a23d212SGreg Clayton            else:
268b9c1b51eSKate Stone                return "\x1b[29m"
2696a23d212SGreg Clayton        return ''
2706a23d212SGreg Clayton
2716a23d212SGreg Clayton    def black(self, fg=True):
2726a23d212SGreg Clayton        '''Set the foreground or background color to black.
2736a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
2746a23d212SGreg Clayton        if self.enabled:
2756a23d212SGreg Clayton            if fg:
276b9c1b51eSKate Stone                return "\x1b[30m"
2776a23d212SGreg Clayton            else:
278b9c1b51eSKate Stone                return "\x1b[40m"
2796a23d212SGreg Clayton        return ''
2806a23d212SGreg Clayton
2816a23d212SGreg Clayton    def red(self, fg=True):
2826a23d212SGreg Clayton        '''Set the foreground or background color to red.
2836a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
2846a23d212SGreg Clayton        if self.enabled:
2856a23d212SGreg Clayton            if fg:
286b9c1b51eSKate Stone                return "\x1b[31m"
2876a23d212SGreg Clayton            else:
288b9c1b51eSKate Stone                return "\x1b[41m"
2896a23d212SGreg Clayton        return ''
2906a23d212SGreg Clayton
2916a23d212SGreg Clayton    def green(self, fg=True):
2926a23d212SGreg Clayton        '''Set the foreground or background color to green.
2936a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
2946a23d212SGreg Clayton        if self.enabled:
2956a23d212SGreg Clayton            if fg:
296b9c1b51eSKate Stone                return "\x1b[32m"
2976a23d212SGreg Clayton            else:
298b9c1b51eSKate Stone                return "\x1b[42m"
2996a23d212SGreg Clayton        return ''
3006a23d212SGreg Clayton
3016a23d212SGreg Clayton    def yellow(self, fg=True):
3026a23d212SGreg Clayton        '''Set the foreground or background color to yellow.
3036a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3046a23d212SGreg Clayton        if self.enabled:
3056a23d212SGreg Clayton            if fg:
306b9c1b51eSKate Stone                return "\x1b[43m"
3076a23d212SGreg Clayton            else:
308b9c1b51eSKate Stone                return "\x1b[33m"
3096a23d212SGreg Clayton        return ''
3106a23d212SGreg Clayton
3116a23d212SGreg Clayton    def blue(self, fg=True):
3126a23d212SGreg Clayton        '''Set the foreground or background color to blue.
3136a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3146a23d212SGreg Clayton        if self.enabled:
3156a23d212SGreg Clayton            if fg:
316b9c1b51eSKate Stone                return "\x1b[34m"
3176a23d212SGreg Clayton            else:
318b9c1b51eSKate Stone                return "\x1b[44m"
3196a23d212SGreg Clayton        return ''
3206a23d212SGreg Clayton
3216a23d212SGreg Clayton    def magenta(self, fg=True):
3226a23d212SGreg Clayton        '''Set the foreground or background color to magenta.
3236a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3246a23d212SGreg Clayton        if self.enabled:
3256a23d212SGreg Clayton            if fg:
326b9c1b51eSKate Stone                return "\x1b[35m"
3276a23d212SGreg Clayton            else:
328b9c1b51eSKate Stone                return "\x1b[45m"
3296a23d212SGreg Clayton        return ''
3306a23d212SGreg Clayton
3316a23d212SGreg Clayton    def cyan(self, fg=True):
3326a23d212SGreg Clayton        '''Set the foreground or background color to cyan.
3336a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3346a23d212SGreg Clayton        if self.enabled:
3356a23d212SGreg Clayton            if fg:
336b9c1b51eSKate Stone                return "\x1b[36m"
3376a23d212SGreg Clayton            else:
338b9c1b51eSKate Stone                return "\x1b[46m"
3396a23d212SGreg Clayton        return ''
3406a23d212SGreg Clayton
3416a23d212SGreg Clayton    def white(self, fg=True):
3426a23d212SGreg Clayton        '''Set the foreground or background color to white.
3436a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3446a23d212SGreg Clayton        if self.enabled:
3456a23d212SGreg Clayton            if fg:
346b9c1b51eSKate Stone                return "\x1b[37m"
3476a23d212SGreg Clayton            else:
348b9c1b51eSKate Stone                return "\x1b[47m"
3496a23d212SGreg Clayton        return ''
3506a23d212SGreg Clayton
3516a23d212SGreg Clayton    def default(self, fg=True):
3526a23d212SGreg Clayton        '''Set the foreground or background color to the default.
3536a23d212SGreg Clayton        The foreground color will be set if "fg" tests True. The background color will be set if "fg" tests False.'''
3546a23d212SGreg Clayton        if self.enabled:
3556a23d212SGreg Clayton            if fg:
356b9c1b51eSKate Stone                return "\x1b[39m"
3576a23d212SGreg Clayton            else:
358b9c1b51eSKate Stone                return "\x1b[49m"
3596a23d212SGreg Clayton        return ''
3606a23d212SGreg Clayton
361b9c1b51eSKate Stone
3626a23d212SGreg Claytondef swap_unpack_char():
3636a23d212SGreg Clayton    """Returns the unpack prefix that will for non-native endian-ness."""
3646a23d212SGreg Clayton    if struct.pack('H', 1).startswith("\x00"):
3656a23d212SGreg Clayton        return '<'
3666a23d212SGreg Clayton    return '>'
3676a23d212SGreg Clayton
3686a23d212SGreg Clayton
3696a23d212SGreg Claytondef dump_hex_bytes(addr, s, bytes_per_line=16):
3706a23d212SGreg Clayton    i = 0
3716a23d212SGreg Clayton    line = ''
3726a23d212SGreg Clayton    for ch in s:
3736a23d212SGreg Clayton        if (i % bytes_per_line) == 0:
3746a23d212SGreg Clayton            if line:
375525cd59fSSerge Guelton                print(line)
3766a23d212SGreg Clayton            line = '%#8.8x: ' % (addr + i)
3776a23d212SGreg Clayton        line += "%02X " % ord(ch)
3786a23d212SGreg Clayton        i += 1
379525cd59fSSerge Guelton    print(line)
3806a23d212SGreg Clayton
381b9c1b51eSKate Stone
3826a23d212SGreg Claytondef dump_hex_byte_string_diff(addr, a, b, bytes_per_line=16):
3836a23d212SGreg Clayton    i = 0
3846a23d212SGreg Clayton    line = ''
3856a23d212SGreg Clayton    a_len = len(a)
3866a23d212SGreg Clayton    b_len = len(b)
3876a23d212SGreg Clayton    if a_len < b_len:
3886a23d212SGreg Clayton        max_len = b_len
3896a23d212SGreg Clayton    else:
3906a23d212SGreg Clayton        max_len = a_len
3916a23d212SGreg Clayton    tty_colors = TerminalColors(True)
3926a23d212SGreg Clayton    for i in range(max_len):
3936a23d212SGreg Clayton        ch = None
3946a23d212SGreg Clayton        if i < a_len:
3956a23d212SGreg Clayton            ch_a = a[i]
3966a23d212SGreg Clayton            ch = ch_a
3976a23d212SGreg Clayton        else:
3986a23d212SGreg Clayton            ch_a = None
3996a23d212SGreg Clayton        if i < b_len:
4006a23d212SGreg Clayton            ch_b = b[i]
4016a23d212SGreg Clayton            if not ch:
4026a23d212SGreg Clayton                ch = ch_b
4036a23d212SGreg Clayton        else:
4046a23d212SGreg Clayton            ch_b = None
4056a23d212SGreg Clayton        mismatch = ch_a != ch_b
4066a23d212SGreg Clayton        if (i % bytes_per_line) == 0:
4076a23d212SGreg Clayton            if line:
408525cd59fSSerge Guelton                print(line)
4096a23d212SGreg Clayton            line = '%#8.8x: ' % (addr + i)
410b9c1b51eSKate Stone        if mismatch:
411b9c1b51eSKate Stone            line += tty_colors.red()
4126a23d212SGreg Clayton        line += "%02X " % ord(ch)
413b9c1b51eSKate Stone        if mismatch:
414b9c1b51eSKate Stone            line += tty_colors.default()
4156a23d212SGreg Clayton        i += 1
4166a23d212SGreg Clayton
417525cd59fSSerge Guelton    print(line)
4186a23d212SGreg Clayton
419b9c1b51eSKate Stone
4206a23d212SGreg Claytonclass Mach:
4216a23d212SGreg Clayton    """Class that does everything mach-o related"""
4226a23d212SGreg Clayton
4236a23d212SGreg Clayton    class Arch:
4246a23d212SGreg Clayton        """Class that implements mach-o architectures"""
4256a23d212SGreg Clayton
4266a23d212SGreg Clayton        def __init__(self, c=0, s=0):
4276a23d212SGreg Clayton            self.cpu = c
4286a23d212SGreg Clayton            self.sub = s
4296a23d212SGreg Clayton
4306a23d212SGreg Clayton        def set_cpu_type(self, c):
4316a23d212SGreg Clayton            self.cpu = c
432b9c1b51eSKate Stone
4336a23d212SGreg Clayton        def set_cpu_subtype(self, s):
4346a23d212SGreg Clayton            self.sub = s
435b9c1b51eSKate Stone
4366a23d212SGreg Clayton        def set_arch(self, c, s):
4376a23d212SGreg Clayton            self.cpu = c
4386a23d212SGreg Clayton            self.sub = s
439b9c1b51eSKate Stone
4406a23d212SGreg Clayton        def is_64_bit(self):
4416a23d212SGreg Clayton            return (self.cpu & CPU_ARCH_ABI64) != 0
4426a23d212SGreg Clayton
4436a23d212SGreg Clayton        cpu_infos = [
4446a23d212SGreg Clayton            ["arm", CPU_TYPE_ARM, CPU_TYPE_ANY],
4456a23d212SGreg Clayton            ["arm", CPU_TYPE_ARM, 0],
4466a23d212SGreg Clayton            ["armv4", CPU_TYPE_ARM, 5],
4476a23d212SGreg Clayton            ["armv6", CPU_TYPE_ARM, 6],
4486a23d212SGreg Clayton            ["armv5", CPU_TYPE_ARM, 7],
4496a23d212SGreg Clayton            ["xscale", CPU_TYPE_ARM, 8],
4506a23d212SGreg Clayton            ["armv7", CPU_TYPE_ARM, 9],
4516a23d212SGreg Clayton            ["armv7f", CPU_TYPE_ARM, 10],
4526a23d212SGreg Clayton            ["armv7s", CPU_TYPE_ARM, 11],
4536a23d212SGreg Clayton            ["armv7k", CPU_TYPE_ARM, 12],
4546a23d212SGreg Clayton            ["armv7m", CPU_TYPE_ARM, 15],
4556a23d212SGreg Clayton            ["armv7em", CPU_TYPE_ARM, 16],
4566a23d212SGreg Clayton            ["ppc", CPU_TYPE_POWERPC, CPU_TYPE_ANY],
4576a23d212SGreg Clayton            ["ppc", CPU_TYPE_POWERPC, 0],
4586a23d212SGreg Clayton            ["ppc601", CPU_TYPE_POWERPC, 1],
4596a23d212SGreg Clayton            ["ppc602", CPU_TYPE_POWERPC, 2],
4606a23d212SGreg Clayton            ["ppc603", CPU_TYPE_POWERPC, 3],
4616a23d212SGreg Clayton            ["ppc603e", CPU_TYPE_POWERPC, 4],
4626a23d212SGreg Clayton            ["ppc603ev", CPU_TYPE_POWERPC, 5],
4636a23d212SGreg Clayton            ["ppc604", CPU_TYPE_POWERPC, 6],
4646a23d212SGreg Clayton            ["ppc604e", CPU_TYPE_POWERPC, 7],
4656a23d212SGreg Clayton            ["ppc620", CPU_TYPE_POWERPC, 8],
4666a23d212SGreg Clayton            ["ppc750", CPU_TYPE_POWERPC, 9],
4676a23d212SGreg Clayton            ["ppc7400", CPU_TYPE_POWERPC, 10],
4686a23d212SGreg Clayton            ["ppc7450", CPU_TYPE_POWERPC, 11],
4696a23d212SGreg Clayton            ["ppc970", CPU_TYPE_POWERPC, 100],
4706a23d212SGreg Clayton            ["ppc64", CPU_TYPE_POWERPC64, 0],
4716a23d212SGreg Clayton            ["ppc970-64", CPU_TYPE_POWERPC64, 100],
4726a23d212SGreg Clayton            ["i386", CPU_TYPE_I386, 3],
4736a23d212SGreg Clayton            ["i486", CPU_TYPE_I386, 4],
4746a23d212SGreg Clayton            ["i486sx", CPU_TYPE_I386, 0x84],
4756a23d212SGreg Clayton            ["i386", CPU_TYPE_I386, CPU_TYPE_ANY],
4766a23d212SGreg Clayton            ["x86_64", CPU_TYPE_X86_64, 3],
4776a23d212SGreg Clayton            ["x86_64", CPU_TYPE_X86_64, CPU_TYPE_ANY],
4786a23d212SGreg Clayton        ]
4796a23d212SGreg Clayton
4806a23d212SGreg Clayton        def __str__(self):
4816a23d212SGreg Clayton            for info in self.cpu_infos:
4826a23d212SGreg Clayton                if self.cpu == info[1] and (self.sub & 0x00ffffff) == info[2]:
4836a23d212SGreg Clayton                    return info[0]
4846a23d212SGreg Clayton            return "{0}.{1}".format(self.cpu, self.sub)
4856a23d212SGreg Clayton
4866a23d212SGreg Clayton    class Magic(dict_utils.Enum):
4876a23d212SGreg Clayton
4886a23d212SGreg Clayton        enum = {
4896a23d212SGreg Clayton            'MH_MAGIC': MH_MAGIC,
4906a23d212SGreg Clayton            'MH_CIGAM': MH_CIGAM,
4916a23d212SGreg Clayton            'MH_MAGIC_64': MH_MAGIC_64,
4926a23d212SGreg Clayton            'MH_CIGAM_64': MH_CIGAM_64,
4936a23d212SGreg Clayton            'FAT_MAGIC': FAT_MAGIC,
4946a23d212SGreg Clayton            'FAT_CIGAM': FAT_CIGAM
4956a23d212SGreg Clayton        }
4966a23d212SGreg Clayton
4976a23d212SGreg Clayton        def __init__(self, initial_value=0):
4986a23d212SGreg Clayton            dict_utils.Enum.__init__(self, initial_value, self.enum)
4996a23d212SGreg Clayton
5006a23d212SGreg Clayton        def is_skinny_mach_file(self):
5016a23d212SGreg Clayton            return self.value == MH_MAGIC or self.value == MH_CIGAM or self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
5026a23d212SGreg Clayton
5036a23d212SGreg Clayton        def is_universal_mach_file(self):
5046a23d212SGreg Clayton            return self.value == FAT_MAGIC or self.value == FAT_CIGAM
5056a23d212SGreg Clayton
5066a23d212SGreg Clayton        def unpack(self, data):
5076a23d212SGreg Clayton            data.set_byte_order('native')
508b9c1b51eSKate Stone            self.value = data.get_uint32()
5096a23d212SGreg Clayton
5106a23d212SGreg Clayton        def get_byte_order(self):
5116a23d212SGreg Clayton            if self.value == MH_CIGAM or self.value == MH_CIGAM_64 or self.value == FAT_CIGAM:
5126a23d212SGreg Clayton                return swap_unpack_char()
5136a23d212SGreg Clayton            else:
5146a23d212SGreg Clayton                return '='
5156a23d212SGreg Clayton
5166a23d212SGreg Clayton        def is_64_bit(self):
5176a23d212SGreg Clayton            return self.value == MH_MAGIC_64 or self.value == MH_CIGAM_64
5186a23d212SGreg Clayton
5196a23d212SGreg Clayton    def __init__(self):
5206a23d212SGreg Clayton        self.magic = Mach.Magic()
5216a23d212SGreg Clayton        self.content = None
5226a23d212SGreg Clayton        self.path = None
5236a23d212SGreg Clayton
5246a23d212SGreg Clayton    def extract(self, path, extractor):
525b9c1b51eSKate Stone        self.path = path
5266a23d212SGreg Clayton        self.unpack(extractor)
5276a23d212SGreg Clayton
5286a23d212SGreg Clayton    def parse(self, path):
529b9c1b51eSKate Stone        self.path = path
5306a23d212SGreg Clayton        try:
5316a23d212SGreg Clayton            f = open(self.path)
5326a23d212SGreg Clayton            file_extractor = file_extract.FileExtract(f, '=')
5336a23d212SGreg Clayton            self.unpack(file_extractor)
5346a23d212SGreg Clayton            # f.close()
535b9c1b51eSKate Stone        except IOError as xxx_todo_changeme:
536b9c1b51eSKate Stone            (errno, strerror) = xxx_todo_changeme.args
537525cd59fSSerge Guelton            print("I/O error({0}): {1}".format(errno, strerror))
5386a23d212SGreg Clayton        except ValueError:
539525cd59fSSerge Guelton            print("Could not convert data to an integer.")
5406a23d212SGreg Clayton        except:
541525cd59fSSerge Guelton            print("Unexpected error:", sys.exc_info()[0])
5426a23d212SGreg Clayton            raise
5436a23d212SGreg Clayton
5446a23d212SGreg Clayton    def compare(self, rhs):
5456a23d212SGreg Clayton        self.content.compare(rhs.content)
5466a23d212SGreg Clayton
5476a23d212SGreg Clayton    def dump(self, options=None):
5486a23d212SGreg Clayton        self.content.dump(options)
5496a23d212SGreg Clayton
5506a23d212SGreg Clayton    def dump_header(self, dump_description=True, options=None):
5516a23d212SGreg Clayton        self.content.dump_header(dump_description, options)
5526a23d212SGreg Clayton
5536a23d212SGreg Clayton    def dump_load_commands(self, dump_description=True, options=None):
5546a23d212SGreg Clayton        self.content.dump_load_commands(dump_description, options)
5556a23d212SGreg Clayton
5566a23d212SGreg Clayton    def dump_sections(self, dump_description=True, options=None):
5576a23d212SGreg Clayton        self.content.dump_sections(dump_description, options)
5586a23d212SGreg Clayton
5596a23d212SGreg Clayton    def dump_section_contents(self, options):
5606a23d212SGreg Clayton        self.content.dump_section_contents(options)
5616a23d212SGreg Clayton
5626a23d212SGreg Clayton    def dump_symtab(self, dump_description=True, options=None):
5636a23d212SGreg Clayton        self.content.dump_symtab(dump_description, options)
5646a23d212SGreg Clayton
5656a23d212SGreg Clayton    def dump_symbol_names_matching_regex(self, regex, file=None):
5666a23d212SGreg Clayton        self.content.dump_symbol_names_matching_regex(regex, file)
5676a23d212SGreg Clayton
5686a23d212SGreg Clayton    def description(self):
5696a23d212SGreg Clayton        return self.content.description()
5706a23d212SGreg Clayton
5716a23d212SGreg Clayton    def unpack(self, data):
5726a23d212SGreg Clayton        self.magic.unpack(data)
5736a23d212SGreg Clayton        if self.magic.is_skinny_mach_file():
5746a23d212SGreg Clayton            self.content = Mach.Skinny(self.path)
5756a23d212SGreg Clayton        elif self.magic.is_universal_mach_file():
5766a23d212SGreg Clayton            self.content = Mach.Universal(self.path)
5776a23d212SGreg Clayton        else:
5786a23d212SGreg Clayton            self.content = None
5796a23d212SGreg Clayton
580b9c1b51eSKate Stone        if self.content is not None:
5816a23d212SGreg Clayton            self.content.unpack(data, self.magic)
5826a23d212SGreg Clayton
5836a23d212SGreg Clayton    def is_valid(self):
584b9c1b51eSKate Stone        return self.content is not None
5856a23d212SGreg Clayton
5866a23d212SGreg Clayton    class Universal:
5876a23d212SGreg Clayton
5886a23d212SGreg Clayton        def __init__(self, path):
5896a23d212SGreg Clayton            self.path = path
5906a23d212SGreg Clayton            self.type = 'universal'
5916a23d212SGreg Clayton            self.file_off = 0
5926a23d212SGreg Clayton            self.magic = None
5936a23d212SGreg Clayton            self.nfat_arch = 0
5946a23d212SGreg Clayton            self.archs = list()
5956a23d212SGreg Clayton
5966a23d212SGreg Clayton        def description(self):
5976a23d212SGreg Clayton            s = '%#8.8x: %s (' % (self.file_off, self.path)
5986a23d212SGreg Clayton            archs_string = ''
5996a23d212SGreg Clayton            for arch in self.archs:
6006a23d212SGreg Clayton                if len(archs_string):
6016a23d212SGreg Clayton                    archs_string += ', '
6026a23d212SGreg Clayton                archs_string += '%s' % arch.arch
6036a23d212SGreg Clayton            s += archs_string
6046a23d212SGreg Clayton            s += ')'
6056a23d212SGreg Clayton            return s
6066a23d212SGreg Clayton
6076a23d212SGreg Clayton        def unpack(self, data, magic=None):
6086a23d212SGreg Clayton            self.file_off = data.tell()
6096a23d212SGreg Clayton            if magic is None:
6106a23d212SGreg Clayton                self.magic = Mach.Magic()
6116a23d212SGreg Clayton                self.magic.unpack(data)
6126a23d212SGreg Clayton            else:
6136a23d212SGreg Clayton                self.magic = magic
6146a23d212SGreg Clayton                self.file_off = self.file_off - 4
6156a23d212SGreg Clayton            # Universal headers are always in big endian
6166a23d212SGreg Clayton            data.set_byte_order('big')
6176a23d212SGreg Clayton            self.nfat_arch = data.get_uint32()
6186a23d212SGreg Clayton            for i in range(self.nfat_arch):
6196a23d212SGreg Clayton                self.archs.append(Mach.Universal.ArchInfo())
6206a23d212SGreg Clayton                self.archs[i].unpack(data)
6216a23d212SGreg Clayton            for i in range(self.nfat_arch):
6226a23d212SGreg Clayton                self.archs[i].mach = Mach.Skinny(self.path)
6236a23d212SGreg Clayton                data.seek(self.archs[i].offset, 0)
6246a23d212SGreg Clayton                skinny_magic = Mach.Magic()
6256a23d212SGreg Clayton                skinny_magic.unpack(data)
6266a23d212SGreg Clayton                self.archs[i].mach.unpack(data, skinny_magic)
6276a23d212SGreg Clayton
6286a23d212SGreg Clayton        def compare(self, rhs):
629525cd59fSSerge Guelton            print('error: comparing two universal files is not supported yet')
6306a23d212SGreg Clayton            return False
6316a23d212SGreg Clayton
6326a23d212SGreg Clayton        def dump(self, options):
6336a23d212SGreg Clayton            if options.dump_header:
634525cd59fSSerge Guelton                print()
635525cd59fSSerge Guelton                print("Universal Mach File: magic = %s, nfat_arch = %u" % (self.magic, self.nfat_arch))
636525cd59fSSerge Guelton                print()
6376a23d212SGreg Clayton            if self.nfat_arch > 0:
6386a23d212SGreg Clayton                if options.dump_header:
6396a23d212SGreg Clayton                    self.archs[0].dump_header(True, options)
6406a23d212SGreg Clayton                    for i in range(self.nfat_arch):
6416a23d212SGreg Clayton                        self.archs[i].dump_flat(options)
6426a23d212SGreg Clayton                if options.dump_header:
643525cd59fSSerge Guelton                    print()
6446a23d212SGreg Clayton                for i in range(self.nfat_arch):
6456a23d212SGreg Clayton                    self.archs[i].mach.dump(options)
6466a23d212SGreg Clayton
6476a23d212SGreg Clayton        def dump_header(self, dump_description=True, options=None):
6486a23d212SGreg Clayton            if dump_description:
649525cd59fSSerge Guelton                print(self.description())
6506a23d212SGreg Clayton            for i in range(self.nfat_arch):
6516a23d212SGreg Clayton                self.archs[i].mach.dump_header(True, options)
652525cd59fSSerge Guelton                print()
6536a23d212SGreg Clayton
6546a23d212SGreg Clayton        def dump_load_commands(self, dump_description=True, options=None):
6556a23d212SGreg Clayton            if dump_description:
656525cd59fSSerge Guelton                print(self.description())
6576a23d212SGreg Clayton            for i in range(self.nfat_arch):
6586a23d212SGreg Clayton                self.archs[i].mach.dump_load_commands(True, options)
659525cd59fSSerge Guelton                print()
6606a23d212SGreg Clayton
6616a23d212SGreg Clayton        def dump_sections(self, dump_description=True, options=None):
6626a23d212SGreg Clayton            if dump_description:
663525cd59fSSerge Guelton                print(self.description())
6646a23d212SGreg Clayton            for i in range(self.nfat_arch):
6656a23d212SGreg Clayton                self.archs[i].mach.dump_sections(True, options)
666525cd59fSSerge Guelton                print()
6676a23d212SGreg Clayton
6686a23d212SGreg Clayton        def dump_section_contents(self, options):
6696a23d212SGreg Clayton            for i in range(self.nfat_arch):
6706a23d212SGreg Clayton                self.archs[i].mach.dump_section_contents(options)
671525cd59fSSerge Guelton                print()
6726a23d212SGreg Clayton
6736a23d212SGreg Clayton        def dump_symtab(self, dump_description=True, options=None):
6746a23d212SGreg Clayton            if dump_description:
675525cd59fSSerge Guelton                print(self.description())
6766a23d212SGreg Clayton            for i in range(self.nfat_arch):
6776a23d212SGreg Clayton                self.archs[i].mach.dump_symtab(True, options)
678525cd59fSSerge Guelton                print()
6796a23d212SGreg Clayton
6806a23d212SGreg Clayton        def dump_symbol_names_matching_regex(self, regex, file=None):
6816a23d212SGreg Clayton            for i in range(self.nfat_arch):
682b9c1b51eSKate Stone                self.archs[i].mach.dump_symbol_names_matching_regex(
683b9c1b51eSKate Stone                    regex, file)
6846a23d212SGreg Clayton
6856a23d212SGreg Clayton        class ArchInfo:
6866a23d212SGreg Clayton
6876a23d212SGreg Clayton            def __init__(self):
6886a23d212SGreg Clayton                self.arch = Mach.Arch(0, 0)
6896a23d212SGreg Clayton                self.offset = 0
6906a23d212SGreg Clayton                self.size = 0
6916a23d212SGreg Clayton                self.align = 0
6926a23d212SGreg Clayton                self.mach = None
6936a23d212SGreg Clayton
6946a23d212SGreg Clayton            def unpack(self, data):
6956a23d212SGreg Clayton                # Universal headers are always in big endian
6966a23d212SGreg Clayton                data.set_byte_order('big')
697b9c1b51eSKate Stone                self.arch.cpu, self.arch.sub, self.offset, self.size, self.align = data.get_n_uint32(
698b9c1b51eSKate Stone                    5)
6996a23d212SGreg Clayton
7006a23d212SGreg Clayton            def dump_header(self, dump_description=True, options=None):
7016a23d212SGreg Clayton                if options.verbose:
702525cd59fSSerge Guelton                    print("CPU        SUBTYPE    OFFSET     SIZE       ALIGN")
703525cd59fSSerge Guelton                    print("---------- ---------- ---------- ---------- ----------")
7046a23d212SGreg Clayton                else:
705525cd59fSSerge Guelton                    print("ARCH       FILEOFFSET FILESIZE   ALIGN")
706525cd59fSSerge Guelton                    print("---------- ---------- ---------- ----------")
707b9c1b51eSKate Stone
7086a23d212SGreg Clayton            def dump_flat(self, options):
7096a23d212SGreg Clayton                if options.verbose:
710525cd59fSSerge Guelton                    print("%#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (self.arch.cpu, self.arch.sub, self.offset, self.size, self.align))
7116a23d212SGreg Clayton                else:
712525cd59fSSerge Guelton                    print("%-10s %#8.8x %#8.8x %#8.8x" % (self.arch, self.offset, self.size, self.align))
713b9c1b51eSKate Stone
7146a23d212SGreg Clayton            def dump(self):
715525cd59fSSerge Guelton                print("   cputype: %#8.8x" % self.arch.cpu)
716525cd59fSSerge Guelton                print("cpusubtype: %#8.8x" % self.arch.sub)
717525cd59fSSerge Guelton                print("    offset: %#8.8x" % self.offset)
718525cd59fSSerge Guelton                print("      size: %#8.8x" % self.size)
719525cd59fSSerge Guelton                print("     align: %#8.8x" % self.align)
720b9c1b51eSKate Stone
7216a23d212SGreg Clayton            def __str__(self):
722b9c1b51eSKate Stone                return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (
723b9c1b51eSKate Stone                    self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
724b9c1b51eSKate Stone
7256a23d212SGreg Clayton            def __repr__(self):
726b9c1b51eSKate Stone                return "Mach.Universal.ArchInfo: %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x" % (
727b9c1b51eSKate Stone                    self.arch.cpu, self.arch.sub, self.offset, self.size, self.align)
7286a23d212SGreg Clayton
7296a23d212SGreg Clayton    class Flags:
7306a23d212SGreg Clayton
7316a23d212SGreg Clayton        def __init__(self, b):
7326a23d212SGreg Clayton            self.bits = b
7336a23d212SGreg Clayton
7346a23d212SGreg Clayton        def __str__(self):
7356a23d212SGreg Clayton            s = ''
7366a23d212SGreg Clayton            if self.bits & MH_NOUNDEFS:
7376a23d212SGreg Clayton                s += 'MH_NOUNDEFS | '
7386a23d212SGreg Clayton            if self.bits & MH_INCRLINK:
7396a23d212SGreg Clayton                s += 'MH_INCRLINK | '
7406a23d212SGreg Clayton            if self.bits & MH_DYLDLINK:
7416a23d212SGreg Clayton                s += 'MH_DYLDLINK | '
7426a23d212SGreg Clayton            if self.bits & MH_BINDATLOAD:
7436a23d212SGreg Clayton                s += 'MH_BINDATLOAD | '
7446a23d212SGreg Clayton            if self.bits & MH_PREBOUND:
7456a23d212SGreg Clayton                s += 'MH_PREBOUND | '
7466a23d212SGreg Clayton            if self.bits & MH_SPLIT_SEGS:
7476a23d212SGreg Clayton                s += 'MH_SPLIT_SEGS | '
7486a23d212SGreg Clayton            if self.bits & MH_LAZY_INIT:
7496a23d212SGreg Clayton                s += 'MH_LAZY_INIT | '
7506a23d212SGreg Clayton            if self.bits & MH_TWOLEVEL:
7516a23d212SGreg Clayton                s += 'MH_TWOLEVEL | '
7526a23d212SGreg Clayton            if self.bits & MH_FORCE_FLAT:
7536a23d212SGreg Clayton                s += 'MH_FORCE_FLAT | '
7546a23d212SGreg Clayton            if self.bits & MH_NOMULTIDEFS:
7556a23d212SGreg Clayton                s += 'MH_NOMULTIDEFS | '
7566a23d212SGreg Clayton            if self.bits & MH_NOFIXPREBINDING:
7576a23d212SGreg Clayton                s += 'MH_NOFIXPREBINDING | '
7586a23d212SGreg Clayton            if self.bits & MH_PREBINDABLE:
7596a23d212SGreg Clayton                s += 'MH_PREBINDABLE | '
7606a23d212SGreg Clayton            if self.bits & MH_ALLMODSBOUND:
7616a23d212SGreg Clayton                s += 'MH_ALLMODSBOUND | '
7626a23d212SGreg Clayton            if self.bits & MH_SUBSECTIONS_VIA_SYMBOLS:
7636a23d212SGreg Clayton                s += 'MH_SUBSECTIONS_VIA_SYMBOLS | '
7646a23d212SGreg Clayton            if self.bits & MH_CANONICAL:
7656a23d212SGreg Clayton                s += 'MH_CANONICAL | '
7666a23d212SGreg Clayton            if self.bits & MH_WEAK_DEFINES:
7676a23d212SGreg Clayton                s += 'MH_WEAK_DEFINES | '
7686a23d212SGreg Clayton            if self.bits & MH_BINDS_TO_WEAK:
7696a23d212SGreg Clayton                s += 'MH_BINDS_TO_WEAK | '
7706a23d212SGreg Clayton            if self.bits & MH_ALLOW_STACK_EXECUTION:
7716a23d212SGreg Clayton                s += 'MH_ALLOW_STACK_EXECUTION | '
7726a23d212SGreg Clayton            if self.bits & MH_ROOT_SAFE:
7736a23d212SGreg Clayton                s += 'MH_ROOT_SAFE | '
7746a23d212SGreg Clayton            if self.bits & MH_SETUID_SAFE:
7756a23d212SGreg Clayton                s += 'MH_SETUID_SAFE | '
7766a23d212SGreg Clayton            if self.bits & MH_NO_REEXPORTED_DYLIBS:
7776a23d212SGreg Clayton                s += 'MH_NO_REEXPORTED_DYLIBS | '
7786a23d212SGreg Clayton            if self.bits & MH_PIE:
7796a23d212SGreg Clayton                s += 'MH_PIE | '
7806a23d212SGreg Clayton            if self.bits & MH_DEAD_STRIPPABLE_DYLIB:
7816a23d212SGreg Clayton                s += 'MH_DEAD_STRIPPABLE_DYLIB | '
7826a23d212SGreg Clayton            if self.bits & MH_HAS_TLV_DESCRIPTORS:
7836a23d212SGreg Clayton                s += 'MH_HAS_TLV_DESCRIPTORS | '
7846a23d212SGreg Clayton            if self.bits & MH_NO_HEAP_EXECUTION:
7856a23d212SGreg Clayton                s += 'MH_NO_HEAP_EXECUTION | '
7866a23d212SGreg Clayton            # Strip the trailing " |" if we have any flags
7876a23d212SGreg Clayton            if len(s) > 0:
7886a23d212SGreg Clayton                s = s[0:-2]
7896a23d212SGreg Clayton            return s
7906a23d212SGreg Clayton
7916a23d212SGreg Clayton    class FileType(dict_utils.Enum):
7926a23d212SGreg Clayton
7936a23d212SGreg Clayton        enum = {
7946a23d212SGreg Clayton            'MH_OBJECT': MH_OBJECT,
7956a23d212SGreg Clayton            'MH_EXECUTE': MH_EXECUTE,
7966a23d212SGreg Clayton            'MH_FVMLIB': MH_FVMLIB,
7976a23d212SGreg Clayton            'MH_CORE': MH_CORE,
7986a23d212SGreg Clayton            'MH_PRELOAD': MH_PRELOAD,
7996a23d212SGreg Clayton            'MH_DYLIB': MH_DYLIB,
8006a23d212SGreg Clayton            'MH_DYLINKER': MH_DYLINKER,
8016a23d212SGreg Clayton            'MH_BUNDLE': MH_BUNDLE,
8026a23d212SGreg Clayton            'MH_DYLIB_STUB': MH_DYLIB_STUB,
8036a23d212SGreg Clayton            'MH_DSYM': MH_DSYM,
8046a23d212SGreg Clayton            'MH_KEXT_BUNDLE': MH_KEXT_BUNDLE
8056a23d212SGreg Clayton        }
8066a23d212SGreg Clayton
8076a23d212SGreg Clayton        def __init__(self, initial_value=0):
8086a23d212SGreg Clayton            dict_utils.Enum.__init__(self, initial_value, self.enum)
8096a23d212SGreg Clayton
8106a23d212SGreg Clayton    class Skinny:
8116a23d212SGreg Clayton
8126a23d212SGreg Clayton        def __init__(self, path):
8136a23d212SGreg Clayton            self.path = path
8146a23d212SGreg Clayton            self.type = 'skinny'
8156a23d212SGreg Clayton            self.data = None
8166a23d212SGreg Clayton            self.file_off = 0
8176a23d212SGreg Clayton            self.magic = 0
8186a23d212SGreg Clayton            self.arch = Mach.Arch(0, 0)
8196a23d212SGreg Clayton            self.filetype = Mach.FileType(0)
8206a23d212SGreg Clayton            self.ncmds = 0
8216a23d212SGreg Clayton            self.sizeofcmds = 0
8226a23d212SGreg Clayton            self.flags = Mach.Flags(0)
8236a23d212SGreg Clayton            self.uuid = None
8246a23d212SGreg Clayton            self.commands = list()
8256a23d212SGreg Clayton            self.segments = list()
8266a23d212SGreg Clayton            self.sections = list()
8276a23d212SGreg Clayton            self.symbols = list()
8286a23d212SGreg Clayton            self.sections.append(Mach.Section())
8296a23d212SGreg Clayton
8306a23d212SGreg Clayton        def description(self):
8316a23d212SGreg Clayton            return '%#8.8x: %s (%s)' % (self.file_off, self.path, self.arch)
8326a23d212SGreg Clayton
8336a23d212SGreg Clayton        def unpack(self, data, magic=None):
8346a23d212SGreg Clayton            self.data = data
8356a23d212SGreg Clayton            self.file_off = data.tell()
8366a23d212SGreg Clayton            if magic is None:
8376a23d212SGreg Clayton                self.magic = Mach.Magic()
8386a23d212SGreg Clayton                self.magic.unpack(data)
8396a23d212SGreg Clayton            else:
8406a23d212SGreg Clayton                self.magic = magic
8416a23d212SGreg Clayton                self.file_off = self.file_off - 4
8426a23d212SGreg Clayton            data.set_byte_order(self.magic.get_byte_order())
843b9c1b51eSKate Stone            self.arch.cpu, self.arch.sub, self.filetype.value, self.ncmds, self.sizeofcmds, bits = data.get_n_uint32(
844b9c1b51eSKate Stone                6)
8456a23d212SGreg Clayton            self.flags.bits = bits
8466a23d212SGreg Clayton
8476a23d212SGreg Clayton            if self.is_64_bit():
8486a23d212SGreg Clayton                data.get_uint32()  # Skip reserved word in mach_header_64
8496a23d212SGreg Clayton
8506a23d212SGreg Clayton            for i in range(0, self.ncmds):
8516a23d212SGreg Clayton                lc = self.unpack_load_command(data)
8526a23d212SGreg Clayton                self.commands.append(lc)
8536a23d212SGreg Clayton
8546a23d212SGreg Clayton        def get_data(self):
8556a23d212SGreg Clayton            if self.data:
8566a23d212SGreg Clayton                self.data.set_byte_order(self.magic.get_byte_order())
8576a23d212SGreg Clayton                return self.data
8586a23d212SGreg Clayton            return None
8596a23d212SGreg Clayton
8606a23d212SGreg Clayton        def unpack_load_command(self, data):
8616a23d212SGreg Clayton            lc = Mach.LoadCommand()
8626a23d212SGreg Clayton            lc.unpack(self, data)
863b9c1b51eSKate Stone            lc_command = lc.command.get_enum_value()
8646a23d212SGreg Clayton            if (lc_command == LC_SEGMENT or
8656a23d212SGreg Clayton                    lc_command == LC_SEGMENT_64):
8666a23d212SGreg Clayton                lc = Mach.SegmentLoadCommand(lc)
8676a23d212SGreg Clayton                lc.unpack(self, data)
8686a23d212SGreg Clayton            elif (lc_command == LC_LOAD_DYLIB or
8696a23d212SGreg Clayton                  lc_command == LC_ID_DYLIB or
8706a23d212SGreg Clayton                  lc_command == LC_LOAD_WEAK_DYLIB or
8716a23d212SGreg Clayton                  lc_command == LC_REEXPORT_DYLIB):
8726a23d212SGreg Clayton                lc = Mach.DylibLoadCommand(lc)
8736a23d212SGreg Clayton                lc.unpack(self, data)
8746a23d212SGreg Clayton            elif (lc_command == LC_LOAD_DYLINKER or
8756a23d212SGreg Clayton                  lc_command == LC_SUB_FRAMEWORK or
8766a23d212SGreg Clayton                  lc_command == LC_SUB_CLIENT or
8776a23d212SGreg Clayton                  lc_command == LC_SUB_UMBRELLA or
8786a23d212SGreg Clayton                  lc_command == LC_SUB_LIBRARY or
8796a23d212SGreg Clayton                  lc_command == LC_ID_DYLINKER or
8806a23d212SGreg Clayton                  lc_command == LC_RPATH):
8816a23d212SGreg Clayton                lc = Mach.LoadDYLDLoadCommand(lc)
8826a23d212SGreg Clayton                lc.unpack(self, data)
8836a23d212SGreg Clayton            elif (lc_command == LC_DYLD_INFO_ONLY):
8846a23d212SGreg Clayton                lc = Mach.DYLDInfoOnlyLoadCommand(lc)
8856a23d212SGreg Clayton                lc.unpack(self, data)
8866a23d212SGreg Clayton            elif (lc_command == LC_SYMTAB):
8876a23d212SGreg Clayton                lc = Mach.SymtabLoadCommand(lc)
8886a23d212SGreg Clayton                lc.unpack(self, data)
8896a23d212SGreg Clayton            elif (lc_command == LC_DYSYMTAB):
8906a23d212SGreg Clayton                lc = Mach.DYLDSymtabLoadCommand(lc)
8916a23d212SGreg Clayton                lc.unpack(self, data)
8926a23d212SGreg Clayton            elif (lc_command == LC_UUID):
8936a23d212SGreg Clayton                lc = Mach.UUIDLoadCommand(lc)
8946a23d212SGreg Clayton                lc.unpack(self, data)
8956a23d212SGreg Clayton            elif (lc_command == LC_CODE_SIGNATURE or
8966a23d212SGreg Clayton                  lc_command == LC_SEGMENT_SPLIT_INFO or
8976a23d212SGreg Clayton                  lc_command == LC_FUNCTION_STARTS):
8986a23d212SGreg Clayton                lc = Mach.DataBlobLoadCommand(lc)
8996a23d212SGreg Clayton                lc.unpack(self, data)
9006a23d212SGreg Clayton            elif (lc_command == LC_UNIXTHREAD):
9016a23d212SGreg Clayton                lc = Mach.UnixThreadLoadCommand(lc)
9026a23d212SGreg Clayton                lc.unpack(self, data)
9036a23d212SGreg Clayton            elif (lc_command == LC_ENCRYPTION_INFO):
9046a23d212SGreg Clayton                lc = Mach.EncryptionInfoLoadCommand(lc)
9056a23d212SGreg Clayton                lc.unpack(self, data)
9066a23d212SGreg Clayton            lc.skip(data)
9076a23d212SGreg Clayton            return lc
9086a23d212SGreg Clayton
9096a23d212SGreg Clayton        def compare(self, rhs):
910525cd59fSSerge Guelton            print("\nComparing:")
911525cd59fSSerge Guelton            print("a) %s %s" % (self.arch, self.path))
912525cd59fSSerge Guelton            print("b) %s %s" % (rhs.arch, rhs.path))
9136a23d212SGreg Clayton            result = True
9146a23d212SGreg Clayton            if self.type == rhs.type:
9156a23d212SGreg Clayton                for lhs_section in self.sections[1:]:
9166a23d212SGreg Clayton                    rhs_section = rhs.get_section_by_section(lhs_section)
9176a23d212SGreg Clayton                    if rhs_section:
918525cd59fSSerge Guelton                        print('comparing %s.%s...' % (lhs_section.segname, lhs_section.sectname), end=' ')
9196a23d212SGreg Clayton                        sys.stdout.flush()
9206a23d212SGreg Clayton                        lhs_data = lhs_section.get_contents(self)
9216a23d212SGreg Clayton                        rhs_data = rhs_section.get_contents(rhs)
9226a23d212SGreg Clayton                        if lhs_data and rhs_data:
9236a23d212SGreg Clayton                            if lhs_data == rhs_data:
924525cd59fSSerge Guelton                                print('ok')
9256a23d212SGreg Clayton                            else:
9266a23d212SGreg Clayton                                lhs_data_len = len(lhs_data)
9276a23d212SGreg Clayton                                rhs_data_len = len(rhs_data)
9286a23d212SGreg Clayton                                # if lhs_data_len < rhs_data_len:
9296a23d212SGreg Clayton                                #     if lhs_data == rhs_data[0:lhs_data_len]:
9306a23d212SGreg Clayton                                #         print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
9316a23d212SGreg Clayton                                #     else:
9326a23d212SGreg Clayton                                #         # TODO: check padding
9336a23d212SGreg Clayton                                #         result = False
9346a23d212SGreg Clayton                                # elif lhs_data_len > rhs_data_len:
9356a23d212SGreg Clayton                                #     if lhs_data[0:rhs_data_len] == rhs_data:
9366a23d212SGreg Clayton                                #         print 'section data for %s matches the first %u bytes' % (lhs_section.sectname, lhs_data_len)
9376a23d212SGreg Clayton                                #     else:
9386a23d212SGreg Clayton                                #         # TODO: check padding
9396a23d212SGreg Clayton                                #         result = False
9406a23d212SGreg Clayton                                # else:
9416a23d212SGreg Clayton                                result = False
942525cd59fSSerge Guelton                                print('error: sections differ')
9436a23d212SGreg Clayton                                # print 'a) %s' % (lhs_section)
9446a23d212SGreg Clayton                                # dump_hex_byte_string_diff(0, lhs_data, rhs_data)
9456a23d212SGreg Clayton                                # print 'b) %s' % (rhs_section)
9466a23d212SGreg Clayton                                # dump_hex_byte_string_diff(0, rhs_data, lhs_data)
9476a23d212SGreg Clayton                        elif lhs_data and not rhs_data:
948525cd59fSSerge Guelton                            print('error: section data missing from b:')
949525cd59fSSerge Guelton                            print('a) %s' % (lhs_section))
950525cd59fSSerge Guelton                            print('b) %s' % (rhs_section))
9516a23d212SGreg Clayton                            result = False
9526a23d212SGreg Clayton                        elif not lhs_data and rhs_data:
953525cd59fSSerge Guelton                            print('error: section data missing from a:')
954525cd59fSSerge Guelton                            print('a) %s' % (lhs_section))
955525cd59fSSerge Guelton                            print('b) %s' % (rhs_section))
9566a23d212SGreg Clayton                            result = False
9576a23d212SGreg Clayton                        elif lhs_section.offset or rhs_section.offset:
958525cd59fSSerge Guelton                            print('error: section data missing for both a and b:')
959525cd59fSSerge Guelton                            print('a) %s' % (lhs_section))
960525cd59fSSerge Guelton                            print('b) %s' % (rhs_section))
9616a23d212SGreg Clayton                            result = False
9626a23d212SGreg Clayton                        else:
963525cd59fSSerge Guelton                            print('ok')
9646a23d212SGreg Clayton                    else:
9656a23d212SGreg Clayton                        result = False
966525cd59fSSerge Guelton                        print('error: section %s is missing in %s' % (lhs_section.sectname, rhs.path))
9676a23d212SGreg Clayton            else:
968e9264b74SKazuaki Ishizaki                print('error: comparing a %s mach-o file with a %s mach-o file is not supported' % (self.type, rhs.type))
9696a23d212SGreg Clayton                result = False
9706a23d212SGreg Clayton            if not result:
971525cd59fSSerge Guelton                print('error: mach files differ')
9726a23d212SGreg Clayton            return result
973b9c1b51eSKate Stone
9746a23d212SGreg Clayton        def dump_header(self, dump_description=True, options=None):
9756a23d212SGreg Clayton            if options.verbose:
976525cd59fSSerge Guelton                print("MAGIC      CPU        SUBTYPE    FILETYPE   NUM CMDS SIZE CMDS  FLAGS")
977525cd59fSSerge Guelton                print("---------- ---------- ---------- ---------- -------- ---------- ----------")
9786a23d212SGreg Clayton            else:
979525cd59fSSerge Guelton                print("MAGIC        ARCH       FILETYPE       NUM CMDS SIZE CMDS  FLAGS")
980525cd59fSSerge Guelton                print("------------ ---------- -------------- -------- ---------- ----------")
9816a23d212SGreg Clayton
9826a23d212SGreg Clayton        def dump_flat(self, options):
9836a23d212SGreg Clayton            if options.verbose:
984525cd59fSSerge Guelton                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))
9856a23d212SGreg Clayton            else:
986525cd59fSSerge Guelton                print("%-12s %-10s %-14s %#8u %#8.8x %s" % (self.magic, self.arch, self.filetype, self.ncmds, self.sizeofcmds, self.flags))
9876a23d212SGreg Clayton
9886a23d212SGreg Clayton        def dump(self, options):
9896a23d212SGreg Clayton            if options.dump_header:
9906a23d212SGreg Clayton                self.dump_header(True, options)
9916a23d212SGreg Clayton            if options.dump_load_commands:
9926a23d212SGreg Clayton                self.dump_load_commands(False, options)
9936a23d212SGreg Clayton            if options.dump_sections:
9946a23d212SGreg Clayton                self.dump_sections(False, options)
9956a23d212SGreg Clayton            if options.section_names:
9966a23d212SGreg Clayton                self.dump_section_contents(options)
9976a23d212SGreg Clayton            if options.dump_symtab:
9986a23d212SGreg Clayton                self.get_symtab()
9996a23d212SGreg Clayton                if len(self.symbols):
10006a23d212SGreg Clayton                    self.dump_sections(False, options)
10016a23d212SGreg Clayton                else:
1002525cd59fSSerge Guelton                    print("No symbols")
10036a23d212SGreg Clayton            if options.find_mangled:
10046a23d212SGreg Clayton                self.dump_symbol_names_matching_regex(re.compile('^_?_Z'))
10056a23d212SGreg Clayton
10066a23d212SGreg Clayton        def dump_header(self, dump_description=True, options=None):
10076a23d212SGreg Clayton            if dump_description:
1008525cd59fSSerge Guelton                print(self.description())
1009525cd59fSSerge Guelton            print("Mach Header")
1010525cd59fSSerge Guelton            print("       magic: %#8.8x %s" % (self.magic.value, self.magic))
1011525cd59fSSerge Guelton            print("     cputype: %#8.8x %s" % (self.arch.cpu, self.arch))
1012525cd59fSSerge Guelton            print("  cpusubtype: %#8.8x" % self.arch.sub)
1013525cd59fSSerge Guelton            print("    filetype: %#8.8x %s" % (self.filetype.get_enum_value(), self.filetype.get_enum_name()))
1014525cd59fSSerge Guelton            print("       ncmds: %#8.8x %u" % (self.ncmds, self.ncmds))
1015525cd59fSSerge Guelton            print("  sizeofcmds: %#8.8x" % self.sizeofcmds)
1016525cd59fSSerge Guelton            print("       flags: %#8.8x %s" % (self.flags.bits, self.flags))
10176a23d212SGreg Clayton
10186a23d212SGreg Clayton        def dump_load_commands(self, dump_description=True, options=None):
10196a23d212SGreg Clayton            if dump_description:
1020525cd59fSSerge Guelton                print(self.description())
10216a23d212SGreg Clayton            for lc in self.commands:
1022525cd59fSSerge Guelton                print(lc)
10236a23d212SGreg Clayton
10246a23d212SGreg Clayton        def get_section_by_name(self, name):
10256a23d212SGreg Clayton            for section in self.sections:
10266a23d212SGreg Clayton                if section.sectname and section.sectname == name:
10276a23d212SGreg Clayton                    return section
10286a23d212SGreg Clayton            return None
10296a23d212SGreg Clayton
10306a23d212SGreg Clayton        def get_section_by_section(self, other_section):
10316a23d212SGreg Clayton            for section in self.sections:
10326a23d212SGreg Clayton                if section.sectname == other_section.sectname and section.segname == other_section.segname:
10336a23d212SGreg Clayton                    return section
10346a23d212SGreg Clayton            return None
10356a23d212SGreg Clayton
10366a23d212SGreg Clayton        def dump_sections(self, dump_description=True, options=None):
10376a23d212SGreg Clayton            if dump_description:
1038525cd59fSSerge Guelton                print(self.description())
10396a23d212SGreg Clayton            num_sections = len(self.sections)
10406a23d212SGreg Clayton            if num_sections > 1:
10416a23d212SGreg Clayton                self.sections[1].dump_header()
10426a23d212SGreg Clayton                for sect_idx in range(1, num_sections):
1043525cd59fSSerge Guelton                    print("%s" % self.sections[sect_idx])
10446a23d212SGreg Clayton
10456a23d212SGreg Clayton        def dump_section_contents(self, options):
10466a23d212SGreg Clayton            saved_section_to_disk = False
10476a23d212SGreg Clayton            for sectname in options.section_names:
10486a23d212SGreg Clayton                section = self.get_section_by_name(sectname)
10496a23d212SGreg Clayton                if section:
10506a23d212SGreg Clayton                    sect_bytes = section.get_contents(self)
10516a23d212SGreg Clayton                    if options.outfile:
10526a23d212SGreg Clayton                        if not saved_section_to_disk:
10536a23d212SGreg Clayton                            outfile = open(options.outfile, 'w')
10546a23d212SGreg Clayton                            if options.extract_modules:
10556a23d212SGreg Clayton                                # print "Extracting modules from mach file..."
1056b9c1b51eSKate Stone                                data = file_extract.FileExtract(
10573a22c3ccSSerge Guelton                                    io.BytesIO(sect_bytes), self.data.byte_order)
10586a23d212SGreg Clayton                                version = data.get_uint32()
10596a23d212SGreg Clayton                                num_modules = data.get_uint32()
1060b9c1b51eSKate Stone                                # print "version = %u, num_modules = %u" %
1061b9c1b51eSKate Stone                                # (version, num_modules)
10626a23d212SGreg Clayton                                for i in range(num_modules):
10636a23d212SGreg Clayton                                    data_offset = data.get_uint64()
10646a23d212SGreg Clayton                                    data_size = data.get_uint64()
10656a23d212SGreg Clayton                                    name_offset = data.get_uint32()
10666a23d212SGreg Clayton                                    language = data.get_uint32()
10676a23d212SGreg Clayton                                    flags = data.get_uint32()
10686a23d212SGreg Clayton                                    data.seek(name_offset)
10696a23d212SGreg Clayton                                    module_name = data.get_c_string()
1070b9c1b51eSKate Stone                                    # print "module[%u] data_offset = %#16.16x,
1071b9c1b51eSKate Stone                                    # data_size = %#16.16x, name_offset =
1072b9c1b51eSKate Stone                                    # %#16.16x (%s), language = %u, flags =
1073b9c1b51eSKate Stone                                    # %#x" % (i, data_offset, data_size,
1074b9c1b51eSKate Stone                                    # name_offset, module_name, language,
1075b9c1b51eSKate Stone                                    # flags)
10766a23d212SGreg Clayton                                    data.seek(data_offset)
10776a23d212SGreg Clayton                                    outfile.write(data.read_size(data_size))
10786a23d212SGreg Clayton                            else:
1079525cd59fSSerge Guelton                                print("Saving section %s to '%s'" % (sectname, options.outfile))
10806a23d212SGreg Clayton                                outfile.write(sect_bytes)
10816a23d212SGreg Clayton                            outfile.close()
10826a23d212SGreg Clayton                            saved_section_to_disk = True
10836a23d212SGreg Clayton                        else:
1084525cd59fSSerge Guelton                            print("error: you can only save a single section to disk at a time, skipping section '%s'" % (sectname))
10856a23d212SGreg Clayton                    else:
1086525cd59fSSerge Guelton                        print('section %s:\n' % (sectname))
10876a23d212SGreg Clayton                        section.dump_header()
1088525cd59fSSerge Guelton                        print('%s\n' % (section))
10896a23d212SGreg Clayton                        dump_memory(0, sect_bytes, options.max_count, 16)
10906a23d212SGreg Clayton                else:
1091525cd59fSSerge Guelton                    print('error: no section named "%s" was found' % (sectname))
10926a23d212SGreg Clayton
10936a23d212SGreg Clayton        def get_segment(self, segname):
10946a23d212SGreg Clayton            if len(self.segments) == 1 and self.segments[0].segname == '':
10956a23d212SGreg Clayton                return self.segments[0]
10966a23d212SGreg Clayton            for segment in self.segments:
10976a23d212SGreg Clayton                if segment.segname == segname:
10986a23d212SGreg Clayton                    return segment
10996a23d212SGreg Clayton            return None
11006a23d212SGreg Clayton
11016a23d212SGreg Clayton        def get_first_load_command(self, lc_enum_value):
11026a23d212SGreg Clayton            for lc in self.commands:
11036a23d212SGreg Clayton                if lc.command.value == lc_enum_value:
11046a23d212SGreg Clayton                    return lc
11056a23d212SGreg Clayton            return None
11066a23d212SGreg Clayton
11076a23d212SGreg Clayton        def get_symtab(self):
11086a23d212SGreg Clayton            if self.data and not self.symbols:
11096a23d212SGreg Clayton                lc_symtab = self.get_first_load_command(LC_SYMTAB)
11106a23d212SGreg Clayton                if lc_symtab:
11116a23d212SGreg Clayton                    symtab_offset = self.file_off
11126a23d212SGreg Clayton                    if self.data.is_in_memory():
11136a23d212SGreg Clayton                        linkedit_segment = self.get_segment('__LINKEDIT')
11146a23d212SGreg Clayton                        if linkedit_segment:
11156a23d212SGreg Clayton                            linkedit_vmaddr = linkedit_segment.vmaddr
11166a23d212SGreg Clayton                            linkedit_fileoff = linkedit_segment.fileoff
11176a23d212SGreg Clayton                            symtab_offset = linkedit_vmaddr + lc_symtab.symoff - linkedit_fileoff
11186a23d212SGreg Clayton                            symtab_offset = linkedit_vmaddr + lc_symtab.stroff - linkedit_fileoff
11196a23d212SGreg Clayton                    else:
11206a23d212SGreg Clayton                        symtab_offset += lc_symtab.symoff
11216a23d212SGreg Clayton
11226a23d212SGreg Clayton                    self.data.seek(symtab_offset)
11236a23d212SGreg Clayton                    is_64 = self.is_64_bit()
11246a23d212SGreg Clayton                    for i in range(lc_symtab.nsyms):
11256a23d212SGreg Clayton                        nlist = Mach.NList()
11266a23d212SGreg Clayton                        nlist.unpack(self, self.data, lc_symtab)
11276a23d212SGreg Clayton                        self.symbols.append(nlist)
11286a23d212SGreg Clayton                else:
1129525cd59fSSerge Guelton                    print("no LC_SYMTAB")
11306a23d212SGreg Clayton
11316a23d212SGreg Clayton        def dump_symtab(self, dump_description=True, options=None):
11326a23d212SGreg Clayton            self.get_symtab()
11336a23d212SGreg Clayton            if dump_description:
1134525cd59fSSerge Guelton                print(self.description())
11356a23d212SGreg Clayton            for i, symbol in enumerate(self.symbols):
1136525cd59fSSerge Guelton                print('[%5u] %s' % (i, symbol))
11376a23d212SGreg Clayton
11386a23d212SGreg Clayton        def dump_symbol_names_matching_regex(self, regex, file=None):
11396a23d212SGreg Clayton            self.get_symtab()
11406a23d212SGreg Clayton            for symbol in self.symbols:
11416a23d212SGreg Clayton                if symbol.name and regex.search(symbol.name):
1142525cd59fSSerge Guelton                    print(symbol.name)
11436a23d212SGreg Clayton                    if file:
11446a23d212SGreg Clayton                        file.write('%s\n' % (symbol.name))
11456a23d212SGreg Clayton
11466a23d212SGreg Clayton        def is_64_bit(self):
11476a23d212SGreg Clayton            return self.magic.is_64_bit()
11486a23d212SGreg Clayton
11496a23d212SGreg Clayton    class LoadCommand:
1150b9c1b51eSKate Stone
11516a23d212SGreg Clayton        class Command(dict_utils.Enum):
11526a23d212SGreg Clayton            enum = {
11536a23d212SGreg Clayton                'LC_SEGMENT': LC_SEGMENT,
11546a23d212SGreg Clayton                'LC_SYMTAB': LC_SYMTAB,
11556a23d212SGreg Clayton                'LC_SYMSEG': LC_SYMSEG,
11566a23d212SGreg Clayton                'LC_THREAD': LC_THREAD,
11576a23d212SGreg Clayton                'LC_UNIXTHREAD': LC_UNIXTHREAD,
11586a23d212SGreg Clayton                'LC_LOADFVMLIB': LC_LOADFVMLIB,
11596a23d212SGreg Clayton                'LC_IDFVMLIB': LC_IDFVMLIB,
11606a23d212SGreg Clayton                'LC_IDENT': LC_IDENT,
11616a23d212SGreg Clayton                'LC_FVMFILE': LC_FVMFILE,
11626a23d212SGreg Clayton                'LC_PREPAGE': LC_PREPAGE,
11636a23d212SGreg Clayton                'LC_DYSYMTAB': LC_DYSYMTAB,
11646a23d212SGreg Clayton                'LC_LOAD_DYLIB': LC_LOAD_DYLIB,
11656a23d212SGreg Clayton                'LC_ID_DYLIB': LC_ID_DYLIB,
11666a23d212SGreg Clayton                'LC_LOAD_DYLINKER': LC_LOAD_DYLINKER,
11676a23d212SGreg Clayton                'LC_ID_DYLINKER': LC_ID_DYLINKER,
11686a23d212SGreg Clayton                'LC_PREBOUND_DYLIB': LC_PREBOUND_DYLIB,
11696a23d212SGreg Clayton                'LC_ROUTINES': LC_ROUTINES,
11706a23d212SGreg Clayton                'LC_SUB_FRAMEWORK': LC_SUB_FRAMEWORK,
11716a23d212SGreg Clayton                'LC_SUB_UMBRELLA': LC_SUB_UMBRELLA,
11726a23d212SGreg Clayton                'LC_SUB_CLIENT': LC_SUB_CLIENT,
11736a23d212SGreg Clayton                'LC_SUB_LIBRARY': LC_SUB_LIBRARY,
11746a23d212SGreg Clayton                'LC_TWOLEVEL_HINTS': LC_TWOLEVEL_HINTS,
11756a23d212SGreg Clayton                'LC_PREBIND_CKSUM': LC_PREBIND_CKSUM,
11766a23d212SGreg Clayton                'LC_LOAD_WEAK_DYLIB': LC_LOAD_WEAK_DYLIB,
11776a23d212SGreg Clayton                'LC_SEGMENT_64': LC_SEGMENT_64,
11786a23d212SGreg Clayton                'LC_ROUTINES_64': LC_ROUTINES_64,
11796a23d212SGreg Clayton                'LC_UUID': LC_UUID,
11806a23d212SGreg Clayton                'LC_RPATH': LC_RPATH,
11816a23d212SGreg Clayton                'LC_CODE_SIGNATURE': LC_CODE_SIGNATURE,
11826a23d212SGreg Clayton                'LC_SEGMENT_SPLIT_INFO': LC_SEGMENT_SPLIT_INFO,
11836a23d212SGreg Clayton                'LC_REEXPORT_DYLIB': LC_REEXPORT_DYLIB,
11846a23d212SGreg Clayton                'LC_LAZY_LOAD_DYLIB': LC_LAZY_LOAD_DYLIB,
11856a23d212SGreg Clayton                'LC_ENCRYPTION_INFO': LC_ENCRYPTION_INFO,
11866a23d212SGreg Clayton                'LC_DYLD_INFO': LC_DYLD_INFO,
11876a23d212SGreg Clayton                'LC_DYLD_INFO_ONLY': LC_DYLD_INFO_ONLY,
11886a23d212SGreg Clayton                'LC_LOAD_UPWARD_DYLIB': LC_LOAD_UPWARD_DYLIB,
11896a23d212SGreg Clayton                'LC_VERSION_MIN_MACOSX': LC_VERSION_MIN_MACOSX,
11906a23d212SGreg Clayton                'LC_VERSION_MIN_IPHONEOS': LC_VERSION_MIN_IPHONEOS,
11916a23d212SGreg Clayton                'LC_FUNCTION_STARTS': LC_FUNCTION_STARTS,
11926a23d212SGreg Clayton                'LC_DYLD_ENVIRONMENT': LC_DYLD_ENVIRONMENT
11936a23d212SGreg Clayton            }
11946a23d212SGreg Clayton
11956a23d212SGreg Clayton            def __init__(self, initial_value=0):
11966a23d212SGreg Clayton                dict_utils.Enum.__init__(self, initial_value, self.enum)
11976a23d212SGreg Clayton
11986a23d212SGreg Clayton        def __init__(self, c=None, l=0, o=0):
1199b9c1b51eSKate Stone            if c is not None:
12006a23d212SGreg Clayton                self.command = c
12016a23d212SGreg Clayton            else:
12026a23d212SGreg Clayton                self.command = Mach.LoadCommand.Command(0)
12036a23d212SGreg Clayton            self.length = l
12046a23d212SGreg Clayton            self.file_off = o
12056a23d212SGreg Clayton
12066a23d212SGreg Clayton        def unpack(self, mach_file, data):
12076a23d212SGreg Clayton            self.file_off = data.tell()
12086a23d212SGreg Clayton            self.command.value, self.length = data.get_n_uint32(2)
12096a23d212SGreg Clayton
12106a23d212SGreg Clayton        def skip(self, data):
12116a23d212SGreg Clayton            data.seek(self.file_off + self.length, 0)
12126a23d212SGreg Clayton
12136a23d212SGreg Clayton        def __str__(self):
12146a23d212SGreg Clayton            lc_name = self.command.get_enum_name()
1215b9c1b51eSKate Stone            return '%#8.8x: <%#4.4x> %-24s' % (self.file_off,
1216b9c1b51eSKate Stone                                               self.length, lc_name)
12176a23d212SGreg Clayton
12186a23d212SGreg Clayton    class Section:
12196a23d212SGreg Clayton
12206a23d212SGreg Clayton        def __init__(self):
12216a23d212SGreg Clayton            self.index = 0
12226a23d212SGreg Clayton            self.is_64 = False
12236a23d212SGreg Clayton            self.sectname = None
12246a23d212SGreg Clayton            self.segname = None
12256a23d212SGreg Clayton            self.addr = 0
12266a23d212SGreg Clayton            self.size = 0
12276a23d212SGreg Clayton            self.offset = 0
12286a23d212SGreg Clayton            self.align = 0
12296a23d212SGreg Clayton            self.reloff = 0
12306a23d212SGreg Clayton            self.nreloc = 0
12316a23d212SGreg Clayton            self.flags = 0
12326a23d212SGreg Clayton            self.reserved1 = 0
12336a23d212SGreg Clayton            self.reserved2 = 0
12346a23d212SGreg Clayton            self.reserved3 = 0
12356a23d212SGreg Clayton
12366a23d212SGreg Clayton        def unpack(self, is_64, data):
12376a23d212SGreg Clayton            self.is_64 = is_64
12386a23d212SGreg Clayton            self.sectname = data.get_fixed_length_c_string(16, '', True)
12396a23d212SGreg Clayton            self.segname = data.get_fixed_length_c_string(16, '', True)
12406a23d212SGreg Clayton            if self.is_64:
12416a23d212SGreg Clayton                self.addr, self.size = data.get_n_uint64(2)
1242b9c1b51eSKate Stone                self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.reserved3 = data.get_n_uint32(
1243b9c1b51eSKate Stone                    8)
12446a23d212SGreg Clayton            else:
12456a23d212SGreg Clayton                self.addr, self.size = data.get_n_uint32(2)
1246b9c1b51eSKate Stone                self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2 = data.get_n_uint32(
1247b9c1b51eSKate Stone                    7)
12486a23d212SGreg Clayton
12496a23d212SGreg Clayton        def dump_header(self):
12506a23d212SGreg Clayton            if self.is_64:
1251525cd59fSSerge Guelton                print("INDEX ADDRESS            SIZE               OFFSET     ALIGN      RELOFF     NRELOC     FLAGS      RESERVED1  RESERVED2  RESERVED3  NAME")
1252525cd59fSSerge Guelton                print("===== ------------------ ------------------ ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------")
12536a23d212SGreg Clayton            else:
1254525cd59fSSerge Guelton                print("INDEX ADDRESS    SIZE       OFFSET     ALIGN      RELOFF     NRELOC     FLAGS      RESERVED1  RESERVED2  NAME")
1255525cd59fSSerge Guelton                print("===== ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ----------------------")
12566a23d212SGreg Clayton
12576a23d212SGreg Clayton        def __str__(self):
12586a23d212SGreg Clayton            if self.is_64:
1259b9c1b51eSKate Stone                return "[%3u] %#16.16x %#16.16x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (
1260b9c1b51eSKate Stone                    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)
12616a23d212SGreg Clayton            else:
1262b9c1b51eSKate Stone                return "[%3u] %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %#8.8x %s.%s" % (
1263b9c1b51eSKate Stone                    self.index, self.addr, self.size, self.offset, self.align, self.reloff, self.nreloc, self.flags, self.reserved1, self.reserved2, self.segname, self.sectname)
12646a23d212SGreg Clayton
12656a23d212SGreg Clayton        def get_contents(self, mach_file):
12666a23d212SGreg Clayton            '''Get the section contents as a python string'''
1267b9c1b51eSKate Stone            if self.size > 0 and mach_file.get_segment(
1268b9c1b51eSKate Stone                    self.segname).filesize > 0:
12696a23d212SGreg Clayton                data = mach_file.get_data()
12706a23d212SGreg Clayton                if data:
12716a23d212SGreg Clayton                    section_data_offset = mach_file.file_off + self.offset
1272b9c1b51eSKate Stone                    # print '%s.%s is at offset 0x%x with size 0x%x' %
1273b9c1b51eSKate Stone                    # (self.segname, self.sectname, section_data_offset,
1274b9c1b51eSKate Stone                    # self.size)
12756a23d212SGreg Clayton                    data.push_offset_and_seek(section_data_offset)
12766a23d212SGreg Clayton                    bytes = data.read_size(self.size)
12776a23d212SGreg Clayton                    data.pop_offset_and_seek()
12786a23d212SGreg Clayton                    return bytes
12796a23d212SGreg Clayton            return None
12806a23d212SGreg Clayton
12816a23d212SGreg Clayton    class DylibLoadCommand(LoadCommand):
1282b9c1b51eSKate Stone
12836a23d212SGreg Clayton        def __init__(self, lc):
12846a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
12856a23d212SGreg Clayton            self.name = None
12866a23d212SGreg Clayton            self.timestamp = 0
12876a23d212SGreg Clayton            self.current_version = 0
12886a23d212SGreg Clayton            self.compatibility_version = 0
12896a23d212SGreg Clayton
12906a23d212SGreg Clayton        def unpack(self, mach_file, data):
12916a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
1292b9c1b51eSKate Stone            name_offset, self.timestamp, self.current_version, self.compatibility_version = data.get_n_uint32(
1293b9c1b51eSKate Stone                4)
12946a23d212SGreg Clayton            data.seek(self.file_off + name_offset, 0)
12956a23d212SGreg Clayton            self.name = data.get_fixed_length_c_string(self.length - 24)
12966a23d212SGreg Clayton
12976a23d212SGreg Clayton        def __str__(self):
1298b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
1299b9c1b51eSKate Stone            s += "%#8.8x %#8.8x %#8.8x " % (self.timestamp,
1300b9c1b51eSKate Stone                                            self.current_version,
1301b9c1b51eSKate Stone                                            self.compatibility_version)
13026a23d212SGreg Clayton            s += self.name
13036a23d212SGreg Clayton            return s
13046a23d212SGreg Clayton
13056a23d212SGreg Clayton    class LoadDYLDLoadCommand(LoadCommand):
1306b9c1b51eSKate Stone
13076a23d212SGreg Clayton        def __init__(self, lc):
13086a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
13096a23d212SGreg Clayton            self.name = None
13106a23d212SGreg Clayton
13116a23d212SGreg Clayton        def unpack(self, mach_file, data):
13126a23d212SGreg Clayton            data.get_uint32()
13136a23d212SGreg Clayton            self.name = data.get_fixed_length_c_string(self.length - 12)
13146a23d212SGreg Clayton
13156a23d212SGreg Clayton        def __str__(self):
1316b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
13176a23d212SGreg Clayton            s += "%s" % self.name
13186a23d212SGreg Clayton            return s
13196a23d212SGreg Clayton
13206a23d212SGreg Clayton    class UnixThreadLoadCommand(LoadCommand):
1321b9c1b51eSKate Stone
13226a23d212SGreg Clayton        class ThreadState:
1323b9c1b51eSKate Stone
13246a23d212SGreg Clayton            def __init__(self):
13256a23d212SGreg Clayton                self.flavor = 0
13266a23d212SGreg Clayton                self.count = 0
13276a23d212SGreg Clayton                self.register_values = list()
13286a23d212SGreg Clayton
13296a23d212SGreg Clayton            def unpack(self, data):
13306a23d212SGreg Clayton                self.flavor, self.count = data.get_n_uint32(2)
13316a23d212SGreg Clayton                self.register_values = data.get_n_uint32(self.count)
13326a23d212SGreg Clayton
13336a23d212SGreg Clayton            def __str__(self):
1334b9c1b51eSKate Stone                s = "flavor = %u, count = %u, regs =" % (
1335b9c1b51eSKate Stone                    self.flavor, self.count)
13366a23d212SGreg Clayton                i = 0
13376a23d212SGreg Clayton                for register_value in self.register_values:
13386a23d212SGreg Clayton                    if i % 8 == 0:
13396a23d212SGreg Clayton                        s += "\n                                            "
13406a23d212SGreg Clayton                    s += " %#8.8x" % register_value
13416a23d212SGreg Clayton                    i += 1
13426a23d212SGreg Clayton                return s
13436a23d212SGreg Clayton
13446a23d212SGreg Clayton        def __init__(self, lc):
13456a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
13466a23d212SGreg Clayton            self.reg_sets = list()
13476a23d212SGreg Clayton
13486a23d212SGreg Clayton        def unpack(self, mach_file, data):
13496a23d212SGreg Clayton            reg_set = Mach.UnixThreadLoadCommand.ThreadState()
13506a23d212SGreg Clayton            reg_set.unpack(data)
13516a23d212SGreg Clayton            self.reg_sets.append(reg_set)
13526a23d212SGreg Clayton
13536a23d212SGreg Clayton        def __str__(self):
1354b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
13556a23d212SGreg Clayton            for reg_set in self.reg_sets:
13566a23d212SGreg Clayton                s += "%s" % reg_set
13576a23d212SGreg Clayton            return s
13586a23d212SGreg Clayton
13596a23d212SGreg Clayton    class DYLDInfoOnlyLoadCommand(LoadCommand):
1360b9c1b51eSKate Stone
13616a23d212SGreg Clayton        def __init__(self, lc):
13626a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
13636a23d212SGreg Clayton            self.rebase_off = 0
13646a23d212SGreg Clayton            self.rebase_size = 0
13656a23d212SGreg Clayton            self.bind_off = 0
13666a23d212SGreg Clayton            self.bind_size = 0
13676a23d212SGreg Clayton            self.weak_bind_off = 0
13686a23d212SGreg Clayton            self.weak_bind_size = 0
13696a23d212SGreg Clayton            self.lazy_bind_off = 0
13706a23d212SGreg Clayton            self.lazy_bind_size = 0
13716a23d212SGreg Clayton            self.export_off = 0
13726a23d212SGreg Clayton            self.export_size = 0
13736a23d212SGreg Clayton
13746a23d212SGreg Clayton        def unpack(self, mach_file, data):
13756a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
1376b9c1b51eSKate Stone            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(
1377b9c1b51eSKate Stone                10)
13786a23d212SGreg Clayton
13796a23d212SGreg Clayton        def __str__(self):
1380b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
1381b9c1b51eSKate Stone            s += "rebase_off = %#8.8x, rebase_size = %u, " % (
1382b9c1b51eSKate Stone                self.rebase_off, self.rebase_size)
1383b9c1b51eSKate Stone            s += "bind_off = %#8.8x, bind_size = %u, " % (
1384b9c1b51eSKate Stone                self.bind_off, self.bind_size)
1385b9c1b51eSKate Stone            s += "weak_bind_off = %#8.8x, weak_bind_size = %u, " % (
1386b9c1b51eSKate Stone                self.weak_bind_off, self.weak_bind_size)
1387b9c1b51eSKate Stone            s += "lazy_bind_off = %#8.8x, lazy_bind_size = %u, " % (
1388b9c1b51eSKate Stone                self.lazy_bind_off, self.lazy_bind_size)
1389b9c1b51eSKate Stone            s += "export_off = %#8.8x, export_size = %u, " % (
1390b9c1b51eSKate Stone                self.export_off, self.export_size)
13916a23d212SGreg Clayton            return s
13926a23d212SGreg Clayton
13936a23d212SGreg Clayton    class DYLDSymtabLoadCommand(LoadCommand):
1394b9c1b51eSKate Stone
13956a23d212SGreg Clayton        def __init__(self, lc):
13966a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
13976a23d212SGreg Clayton            self.ilocalsym = 0
13986a23d212SGreg Clayton            self.nlocalsym = 0
13996a23d212SGreg Clayton            self.iextdefsym = 0
14006a23d212SGreg Clayton            self.nextdefsym = 0
14016a23d212SGreg Clayton            self.iundefsym = 0
14026a23d212SGreg Clayton            self.nundefsym = 0
14036a23d212SGreg Clayton            self.tocoff = 0
14046a23d212SGreg Clayton            self.ntoc = 0
14056a23d212SGreg Clayton            self.modtaboff = 0
14066a23d212SGreg Clayton            self.nmodtab = 0
14076a23d212SGreg Clayton            self.extrefsymoff = 0
14086a23d212SGreg Clayton            self.nextrefsyms = 0
14096a23d212SGreg Clayton            self.indirectsymoff = 0
14106a23d212SGreg Clayton            self.nindirectsyms = 0
14116a23d212SGreg Clayton            self.extreloff = 0
14126a23d212SGreg Clayton            self.nextrel = 0
14136a23d212SGreg Clayton            self.locreloff = 0
14146a23d212SGreg Clayton            self.nlocrel = 0
14156a23d212SGreg Clayton
14166a23d212SGreg Clayton        def unpack(self, mach_file, data):
14176a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
1418b9c1b51eSKate Stone            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(
1419b9c1b51eSKate Stone                18)
14206a23d212SGreg Clayton
14216a23d212SGreg Clayton        def __str__(self):
1422b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
14236a23d212SGreg Clayton            # s += "ilocalsym = %u, nlocalsym = %u, " % (self.ilocalsym, self.nlocalsym)
14246a23d212SGreg Clayton            # s += "iextdefsym = %u, nextdefsym = %u, " % (self.iextdefsym, self.nextdefsym)
14256a23d212SGreg Clayton            # s += "iundefsym %u, nundefsym = %u, " % (self.iundefsym, self.nundefsym)
14266a23d212SGreg Clayton            # s += "tocoff = %#8.8x, ntoc = %u, " % (self.tocoff, self.ntoc)
14276a23d212SGreg Clayton            # s += "modtaboff = %#8.8x, nmodtab = %u, " % (self.modtaboff, self.nmodtab)
14286a23d212SGreg Clayton            # s += "extrefsymoff = %#8.8x, nextrefsyms = %u, " % (self.extrefsymoff, self.nextrefsyms)
14296a23d212SGreg Clayton            # s += "indirectsymoff = %#8.8x, nindirectsyms = %u, " % (self.indirectsymoff, self.nindirectsyms)
14306a23d212SGreg Clayton            # s += "extreloff = %#8.8x, nextrel = %u, " % (self.extreloff, self.nextrel)
1431b9c1b51eSKate Stone            # s += "locreloff = %#8.8x, nlocrel = %u" % (self.locreloff,
1432b9c1b51eSKate Stone            # self.nlocrel)
1433b9c1b51eSKate Stone            s += "ilocalsym      = %-10u, nlocalsym     = %u\n" % (
1434b9c1b51eSKate Stone                self.ilocalsym, self.nlocalsym)
1435b9c1b51eSKate Stone            s += "                                             iextdefsym     = %-10u, nextdefsym    = %u\n" % (
1436b9c1b51eSKate Stone                self.iextdefsym, self.nextdefsym)
1437b9c1b51eSKate Stone            s += "                                             iundefsym      = %-10u, nundefsym     = %u\n" % (
1438b9c1b51eSKate Stone                self.iundefsym, self.nundefsym)
1439b9c1b51eSKate Stone            s += "                                             tocoff         = %#8.8x, ntoc          = %u\n" % (
1440b9c1b51eSKate Stone                self.tocoff, self.ntoc)
1441b9c1b51eSKate Stone            s += "                                             modtaboff      = %#8.8x, nmodtab       = %u\n" % (
1442b9c1b51eSKate Stone                self.modtaboff, self.nmodtab)
1443b9c1b51eSKate Stone            s += "                                             extrefsymoff   = %#8.8x, nextrefsyms   = %u\n" % (
1444b9c1b51eSKate Stone                self.extrefsymoff, self.nextrefsyms)
1445b9c1b51eSKate Stone            s += "                                             indirectsymoff = %#8.8x, nindirectsyms = %u\n" % (
1446b9c1b51eSKate Stone                self.indirectsymoff, self.nindirectsyms)
1447b9c1b51eSKate Stone            s += "                                             extreloff      = %#8.8x, nextrel       = %u\n" % (
1448b9c1b51eSKate Stone                self.extreloff, self.nextrel)
1449b9c1b51eSKate Stone            s += "                                             locreloff      = %#8.8x, nlocrel       = %u" % (
1450b9c1b51eSKate Stone                self.locreloff, self.nlocrel)
14516a23d212SGreg Clayton            return s
14526a23d212SGreg Clayton
14536a23d212SGreg Clayton    class SymtabLoadCommand(LoadCommand):
1454b9c1b51eSKate Stone
14556a23d212SGreg Clayton        def __init__(self, lc):
14566a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
14576a23d212SGreg Clayton            self.symoff = 0
14586a23d212SGreg Clayton            self.nsyms = 0
14596a23d212SGreg Clayton            self.stroff = 0
14606a23d212SGreg Clayton            self.strsize = 0
14616a23d212SGreg Clayton
14626a23d212SGreg Clayton        def unpack(self, mach_file, data):
14636a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
1464b9c1b51eSKate Stone            self.symoff, self.nsyms, self.stroff, self.strsize = data.get_n_uint32(
1465b9c1b51eSKate Stone                4)
14666a23d212SGreg Clayton
14676a23d212SGreg Clayton        def __str__(self):
1468b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
1469b9c1b51eSKate Stone            s += "symoff = %#8.8x, nsyms = %u, stroff = %#8.8x, strsize = %u" % (
1470b9c1b51eSKate Stone                self.symoff, self.nsyms, self.stroff, self.strsize)
14716a23d212SGreg Clayton            return s
14726a23d212SGreg Clayton
14736a23d212SGreg Clayton    class UUIDLoadCommand(LoadCommand):
1474b9c1b51eSKate Stone
14756a23d212SGreg Clayton        def __init__(self, lc):
14766a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
14776a23d212SGreg Clayton            self.uuid = None
14786a23d212SGreg Clayton
14796a23d212SGreg Clayton        def unpack(self, mach_file, data):
14806a23d212SGreg Clayton            uuid_data = data.get_n_uint8(16)
14816a23d212SGreg Clayton            uuid_str = ''
14826a23d212SGreg Clayton            for byte in uuid_data:
14836a23d212SGreg Clayton                uuid_str += '%2.2x' % byte
14846a23d212SGreg Clayton            self.uuid = uuid.UUID(uuid_str)
14856a23d212SGreg Clayton            mach_file.uuid = self.uuid
14866a23d212SGreg Clayton
14876a23d212SGreg Clayton        def __str__(self):
1488b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
14896a23d212SGreg Clayton            s += self.uuid.__str__()
14906a23d212SGreg Clayton            return s
14916a23d212SGreg Clayton
14926a23d212SGreg Clayton    class DataBlobLoadCommand(LoadCommand):
1493b9c1b51eSKate Stone
14946a23d212SGreg Clayton        def __init__(self, lc):
14956a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
14966a23d212SGreg Clayton            self.dataoff = 0
14976a23d212SGreg Clayton            self.datasize = 0
14986a23d212SGreg Clayton
14996a23d212SGreg Clayton        def unpack(self, mach_file, data):
15006a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
15016a23d212SGreg Clayton            self.dataoff, self.datasize = data.get_n_uint32(2)
15026a23d212SGreg Clayton
15036a23d212SGreg Clayton        def __str__(self):
1504b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
1505b9c1b51eSKate Stone            s += "dataoff = %#8.8x, datasize = %u" % (
1506b9c1b51eSKate Stone                self.dataoff, self.datasize)
15076a23d212SGreg Clayton            return s
15086a23d212SGreg Clayton
15096a23d212SGreg Clayton    class EncryptionInfoLoadCommand(LoadCommand):
1510b9c1b51eSKate Stone
15116a23d212SGreg Clayton        def __init__(self, lc):
15126a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
15136a23d212SGreg Clayton            self.cryptoff = 0
15146a23d212SGreg Clayton            self.cryptsize = 0
15156a23d212SGreg Clayton            self.cryptid = 0
15166a23d212SGreg Clayton
15176a23d212SGreg Clayton        def unpack(self, mach_file, data):
15186a23d212SGreg Clayton            byte_order_char = mach_file.magic.get_byte_order()
15196a23d212SGreg Clayton            self.cryptoff, self.cryptsize, self.cryptid = data.get_n_uint32(3)
15206a23d212SGreg Clayton
15216a23d212SGreg Clayton        def __str__(self):
1522b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
1523b9c1b51eSKate Stone            s += "file-range = [%#8.8x - %#8.8x), cryptsize = %u, cryptid = %u" % (
1524b9c1b51eSKate Stone                self.cryptoff, self.cryptoff + self.cryptsize, self.cryptsize, self.cryptid)
15256a23d212SGreg Clayton            return s
15266a23d212SGreg Clayton
15276a23d212SGreg Clayton    class SegmentLoadCommand(LoadCommand):
15286a23d212SGreg Clayton
15296a23d212SGreg Clayton        def __init__(self, lc):
15306a23d212SGreg Clayton            Mach.LoadCommand.__init__(self, lc.command, lc.length, lc.file_off)
15316a23d212SGreg Clayton            self.segname = None
15326a23d212SGreg Clayton            self.vmaddr = 0
15336a23d212SGreg Clayton            self.vmsize = 0
15346a23d212SGreg Clayton            self.fileoff = 0
15356a23d212SGreg Clayton            self.filesize = 0
15366a23d212SGreg Clayton            self.maxprot = 0
15376a23d212SGreg Clayton            self.initprot = 0
15386a23d212SGreg Clayton            self.nsects = 0
15396a23d212SGreg Clayton            self.flags = 0
15406a23d212SGreg Clayton
15416a23d212SGreg Clayton        def unpack(self, mach_file, data):
1542b9c1b51eSKate Stone            is_64 = self.command.get_enum_value() == LC_SEGMENT_64
15436a23d212SGreg Clayton            self.segname = data.get_fixed_length_c_string(16, '', True)
15446a23d212SGreg Clayton            if is_64:
1545b9c1b51eSKate Stone                self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint64(
1546b9c1b51eSKate Stone                    4)
15476a23d212SGreg Clayton            else:
1548b9c1b51eSKate Stone                self.vmaddr, self.vmsize, self.fileoff, self.filesize = data.get_n_uint32(
1549b9c1b51eSKate Stone                    4)
1550b9c1b51eSKate Stone            self.maxprot, self.initprot, self.nsects, self.flags = data.get_n_uint32(
1551b9c1b51eSKate Stone                4)
15526a23d212SGreg Clayton            mach_file.segments.append(self)
15536a23d212SGreg Clayton            for i in range(self.nsects):
15546a23d212SGreg Clayton                section = Mach.Section()
15556a23d212SGreg Clayton                section.unpack(is_64, data)
15566a23d212SGreg Clayton                section.index = len(mach_file.sections)
15576a23d212SGreg Clayton                mach_file.sections.append(section)
15586a23d212SGreg Clayton
15596a23d212SGreg Clayton        def __str__(self):
1560b9c1b51eSKate Stone            s = Mach.LoadCommand.__str__(self)
15616a23d212SGreg Clayton            if self.command.get_enum_value() == LC_SEGMENT:
1562b9c1b51eSKate Stone                s += "%#8.8x %#8.8x %#8.8x %#8.8x " % (
1563b9c1b51eSKate Stone                    self.vmaddr, self.vmsize, self.fileoff, self.filesize)
15646a23d212SGreg Clayton            else:
1565b9c1b51eSKate Stone                s += "%#16.16x %#16.16x %#16.16x %#16.16x " % (
1566b9c1b51eSKate Stone                    self.vmaddr, self.vmsize, self.fileoff, self.filesize)
1567b9c1b51eSKate Stone            s += "%s %s %3u %#8.8x" % (vm_prot_names[self.maxprot], vm_prot_names[
1568b9c1b51eSKate Stone                                       self.initprot], self.nsects, self.flags)
15696a23d212SGreg Clayton            s += ' ' + self.segname
15706a23d212SGreg Clayton            return s
15716a23d212SGreg Clayton
15726a23d212SGreg Clayton    class NList:
1573b9c1b51eSKate Stone
15746a23d212SGreg Clayton        class Type:
1575b9c1b51eSKate Stone
15766a23d212SGreg Clayton            class Stab(dict_utils.Enum):
15776a23d212SGreg Clayton                enum = {
15786a23d212SGreg Clayton                    'N_GSYM': N_GSYM,
15796a23d212SGreg Clayton                    'N_FNAME': N_FNAME,
15806a23d212SGreg Clayton                    'N_FUN': N_FUN,
15816a23d212SGreg Clayton                    'N_STSYM': N_STSYM,
15826a23d212SGreg Clayton                    'N_LCSYM': N_LCSYM,
15836a23d212SGreg Clayton                    'N_BNSYM': N_BNSYM,
15846a23d212SGreg Clayton                    'N_OPT': N_OPT,
15856a23d212SGreg Clayton                    'N_RSYM': N_RSYM,
15866a23d212SGreg Clayton                    'N_SLINE': N_SLINE,
15876a23d212SGreg Clayton                    'N_ENSYM': N_ENSYM,
15886a23d212SGreg Clayton                    'N_SSYM': N_SSYM,
15896a23d212SGreg Clayton                    'N_SO': N_SO,
15906a23d212SGreg Clayton                    'N_OSO': N_OSO,
15916a23d212SGreg Clayton                    'N_LSYM': N_LSYM,
15926a23d212SGreg Clayton                    'N_BINCL': N_BINCL,
15936a23d212SGreg Clayton                    'N_SOL': N_SOL,
15946a23d212SGreg Clayton                    'N_PARAMS': N_PARAMS,
15956a23d212SGreg Clayton                    'N_VERSION': N_VERSION,
15966a23d212SGreg Clayton                    'N_OLEVEL': N_OLEVEL,
15976a23d212SGreg Clayton                    'N_PSYM': N_PSYM,
15986a23d212SGreg Clayton                    'N_EINCL': N_EINCL,
15996a23d212SGreg Clayton                    'N_ENTRY': N_ENTRY,
16006a23d212SGreg Clayton                    'N_LBRAC': N_LBRAC,
16016a23d212SGreg Clayton                    'N_EXCL': N_EXCL,
16026a23d212SGreg Clayton                    'N_RBRAC': N_RBRAC,
16036a23d212SGreg Clayton                    'N_BCOMM': N_BCOMM,
16046a23d212SGreg Clayton                    'N_ECOMM': N_ECOMM,
16056a23d212SGreg Clayton                    'N_ECOML': N_ECOML,
16066a23d212SGreg Clayton                    'N_LENG': N_LENG
16076a23d212SGreg Clayton                }
16086a23d212SGreg Clayton
16096a23d212SGreg Clayton                def __init__(self, magic=0):
16106a23d212SGreg Clayton                    dict_utils.Enum.__init__(self, magic, self.enum)
16116a23d212SGreg Clayton
16126a23d212SGreg Clayton            def __init__(self, t=0):
16136a23d212SGreg Clayton                self.value = t
16146a23d212SGreg Clayton
16156a23d212SGreg Clayton            def __str__(self):
16166a23d212SGreg Clayton                n_type = self.value
16176a23d212SGreg Clayton                if n_type & N_STAB:
16186a23d212SGreg Clayton                    stab = Mach.NList.Type.Stab(self.value)
16196a23d212SGreg Clayton                    return '%s' % stab
16206a23d212SGreg Clayton                else:
16216a23d212SGreg Clayton                    type = self.value & N_TYPE
16226a23d212SGreg Clayton                    type_str = ''
16236a23d212SGreg Clayton                    if type == N_UNDF:
16246a23d212SGreg Clayton                        type_str = 'N_UNDF'
16256a23d212SGreg Clayton                    elif type == N_ABS:
16266a23d212SGreg Clayton                        type_str = 'N_ABS '
16276a23d212SGreg Clayton                    elif type == N_SECT:
16286a23d212SGreg Clayton                        type_str = 'N_SECT'
16296a23d212SGreg Clayton                    elif type == N_PBUD:
16306a23d212SGreg Clayton                        type_str = 'N_PBUD'
16316a23d212SGreg Clayton                    elif type == N_INDR:
16326a23d212SGreg Clayton                        type_str = 'N_INDR'
16336a23d212SGreg Clayton                    else:
16346a23d212SGreg Clayton                        type_str = "??? (%#2.2x)" % type
16356a23d212SGreg Clayton                    if n_type & N_PEXT:
16366a23d212SGreg Clayton                        type_str += ' | PEXT'
16376a23d212SGreg Clayton                    if n_type & N_EXT:
16386a23d212SGreg Clayton                        type_str += ' | EXT '
16396a23d212SGreg Clayton                    return type_str
16406a23d212SGreg Clayton
16416a23d212SGreg Clayton        def __init__(self):
16426a23d212SGreg Clayton            self.index = 0
16436a23d212SGreg Clayton            self.name_offset = 0
16446a23d212SGreg Clayton            self.name = 0
16456a23d212SGreg Clayton            self.type = Mach.NList.Type()
16466a23d212SGreg Clayton            self.sect_idx = 0
16476a23d212SGreg Clayton            self.desc = 0
16486a23d212SGreg Clayton            self.value = 0
16496a23d212SGreg Clayton
16506a23d212SGreg Clayton        def unpack(self, mach_file, data, symtab_lc):
16516a23d212SGreg Clayton            self.index = len(mach_file.symbols)
16526a23d212SGreg Clayton            self.name_offset = data.get_uint32()
16536a23d212SGreg Clayton            self.type.value, self.sect_idx = data.get_n_uint8(2)
16546a23d212SGreg Clayton            self.desc = data.get_uint16()
16556a23d212SGreg Clayton            if mach_file.is_64_bit():
16566a23d212SGreg Clayton                self.value = data.get_uint64()
16576a23d212SGreg Clayton            else:
16586a23d212SGreg Clayton                self.value = data.get_uint32()
1659b9c1b51eSKate Stone            data.push_offset_and_seek(
1660b9c1b51eSKate Stone                mach_file.file_off +
1661b9c1b51eSKate Stone                symtab_lc.stroff +
1662b9c1b51eSKate Stone                self.name_offset)
16636a23d212SGreg Clayton            # print "get string for symbol[%u]" % self.index
16646a23d212SGreg Clayton            self.name = data.get_c_string()
16656a23d212SGreg Clayton            data.pop_offset_and_seek()
16666a23d212SGreg Clayton
16676a23d212SGreg Clayton        def __str__(self):
16686a23d212SGreg Clayton            name_display = ''
16696a23d212SGreg Clayton            if len(self.name):
16706a23d212SGreg Clayton                name_display = ' "%s"' % self.name
1671b9c1b51eSKate Stone            return '%#8.8x %#2.2x (%-20s) %#2.2x %#4.4x %16.16x%s' % (self.name_offset,
1672b9c1b51eSKate Stone                                                                      self.type.value, self.type, self.sect_idx, self.desc, self.value, name_display)
16736a23d212SGreg Clayton
16746a23d212SGreg Clayton    class Interactive(cmd.Cmd):
16756a23d212SGreg Clayton        '''Interactive command interpreter to mach-o files.'''
16766a23d212SGreg Clayton
16776a23d212SGreg Clayton        def __init__(self, mach, options):
16786a23d212SGreg Clayton            cmd.Cmd.__init__(self)
16796a23d212SGreg Clayton            self.intro = 'Interactive mach-o command interpreter'
16806a23d212SGreg Clayton            self.prompt = 'mach-o: %s %% ' % mach.path
16816a23d212SGreg Clayton            self.mach = mach
16826a23d212SGreg Clayton            self.options = options
16836a23d212SGreg Clayton
16846a23d212SGreg Clayton        def default(self, line):
16856a23d212SGreg Clayton            '''Catch all for unknown command, which will exit the interpreter.'''
1686525cd59fSSerge Guelton            print("uknown command: %s" % line)
16876a23d212SGreg Clayton            return True
16886a23d212SGreg Clayton
16896a23d212SGreg Clayton        def do_q(self, line):
16906a23d212SGreg Clayton            '''Quit command'''
16916a23d212SGreg Clayton            return True
16926a23d212SGreg Clayton
16936a23d212SGreg Clayton        def do_quit(self, line):
16946a23d212SGreg Clayton            '''Quit command'''
16956a23d212SGreg Clayton            return True
16966a23d212SGreg Clayton
16976a23d212SGreg Clayton        def do_header(self, line):
16986a23d212SGreg Clayton            '''Dump mach-o file headers'''
16996a23d212SGreg Clayton            self.mach.dump_header(True, self.options)
17006a23d212SGreg Clayton            return False
17016a23d212SGreg Clayton
17026a23d212SGreg Clayton        def do_load(self, line):
17036a23d212SGreg Clayton            '''Dump all mach-o load commands'''
17046a23d212SGreg Clayton            self.mach.dump_load_commands(True, self.options)
17056a23d212SGreg Clayton            return False
17066a23d212SGreg Clayton
17076a23d212SGreg Clayton        def do_sections(self, line):
17086a23d212SGreg Clayton            '''Dump all mach-o sections'''
17096a23d212SGreg Clayton            self.mach.dump_sections(True, self.options)
17106a23d212SGreg Clayton            return False
17116a23d212SGreg Clayton
17126a23d212SGreg Clayton        def do_symtab(self, line):
17136a23d212SGreg Clayton            '''Dump all mach-o symbols in the symbol table'''
17146a23d212SGreg Clayton            self.mach.dump_symtab(True, self.options)
17156a23d212SGreg Clayton            return False
17166a23d212SGreg Clayton
17176a23d212SGreg Claytonif __name__ == '__main__':
1718b9c1b51eSKate Stone    parser = optparse.OptionParser(
1719b9c1b51eSKate Stone        description='A script that parses skinny and universal mach-o files.')
1720b9c1b51eSKate Stone    parser.add_option(
1721b9c1b51eSKate Stone        '--arch',
1722b9c1b51eSKate Stone        '-a',
1723b9c1b51eSKate Stone        type='string',
1724b9c1b51eSKate Stone        metavar='arch',
1725b9c1b51eSKate Stone        dest='archs',
1726b9c1b51eSKate Stone        action='append',
1727b9c1b51eSKate Stone        help='specify one or more architectures by name')
1728b9c1b51eSKate Stone    parser.add_option(
1729b9c1b51eSKate Stone        '-v',
1730b9c1b51eSKate Stone        '--verbose',
1731b9c1b51eSKate Stone        action='store_true',
1732b9c1b51eSKate Stone        dest='verbose',
1733b9c1b51eSKate Stone        help='display verbose debug info',
1734b9c1b51eSKate Stone        default=False)
1735b9c1b51eSKate Stone    parser.add_option(
1736b9c1b51eSKate Stone        '-H',
1737b9c1b51eSKate Stone        '--header',
1738b9c1b51eSKate Stone        action='store_true',
1739b9c1b51eSKate Stone        dest='dump_header',
1740b9c1b51eSKate Stone        help='dump the mach-o file header',
1741b9c1b51eSKate Stone        default=False)
1742b9c1b51eSKate Stone    parser.add_option(
1743b9c1b51eSKate Stone        '-l',
1744b9c1b51eSKate Stone        '--load-commands',
1745b9c1b51eSKate Stone        action='store_true',
1746b9c1b51eSKate Stone        dest='dump_load_commands',
1747b9c1b51eSKate Stone        help='dump the mach-o load commands',
1748b9c1b51eSKate Stone        default=False)
1749b9c1b51eSKate Stone    parser.add_option(
1750b9c1b51eSKate Stone        '-s',
1751b9c1b51eSKate Stone        '--symtab',
1752b9c1b51eSKate Stone        action='store_true',
1753b9c1b51eSKate Stone        dest='dump_symtab',
1754b9c1b51eSKate Stone        help='dump the mach-o symbol table',
1755b9c1b51eSKate Stone        default=False)
1756b9c1b51eSKate Stone    parser.add_option(
1757b9c1b51eSKate Stone        '-S',
1758b9c1b51eSKate Stone        '--sections',
1759b9c1b51eSKate Stone        action='store_true',
1760b9c1b51eSKate Stone        dest='dump_sections',
1761b9c1b51eSKate Stone        help='dump the mach-o sections',
1762b9c1b51eSKate Stone        default=False)
1763b9c1b51eSKate Stone    parser.add_option(
1764b9c1b51eSKate Stone        '--section',
1765b9c1b51eSKate Stone        type='string',
1766b9c1b51eSKate Stone        metavar='sectname',
1767b9c1b51eSKate Stone        dest='section_names',
1768b9c1b51eSKate Stone        action='append',
1769b9c1b51eSKate Stone        help='Specify one or more section names to dump',
1770b9c1b51eSKate Stone        default=[])
1771b9c1b51eSKate Stone    parser.add_option(
1772b9c1b51eSKate Stone        '-o',
1773b9c1b51eSKate Stone        '--out',
1774b9c1b51eSKate Stone        type='string',
1775b9c1b51eSKate Stone        dest='outfile',
1776b9c1b51eSKate Stone        help='Used in conjunction with the --section=NAME option to save a single section\'s data to disk.',
1777b9c1b51eSKate Stone        default=False)
1778b9c1b51eSKate Stone    parser.add_option(
1779b9c1b51eSKate Stone        '-i',
1780b9c1b51eSKate Stone        '--interactive',
1781b9c1b51eSKate Stone        action='store_true',
1782b9c1b51eSKate Stone        dest='interactive',
1783b9c1b51eSKate Stone        help='enable interactive mode',
1784b9c1b51eSKate Stone        default=False)
1785b9c1b51eSKate Stone    parser.add_option(
1786b9c1b51eSKate Stone        '-m',
1787b9c1b51eSKate Stone        '--mangled',
1788b9c1b51eSKate Stone        action='store_true',
1789b9c1b51eSKate Stone        dest='find_mangled',
1790b9c1b51eSKate Stone        help='dump all mangled names in a mach file',
1791b9c1b51eSKate Stone        default=False)
1792b9c1b51eSKate Stone    parser.add_option(
1793b9c1b51eSKate Stone        '-c',
1794b9c1b51eSKate Stone        '--compare',
1795b9c1b51eSKate Stone        action='store_true',
1796b9c1b51eSKate Stone        dest='compare',
1797b9c1b51eSKate Stone        help='compare two mach files',
1798b9c1b51eSKate Stone        default=False)
1799b9c1b51eSKate Stone    parser.add_option(
1800b9c1b51eSKate Stone        '-M',
1801b9c1b51eSKate Stone        '--extract-modules',
1802b9c1b51eSKate Stone        action='store_true',
1803b9c1b51eSKate Stone        dest='extract_modules',
1804b9c1b51eSKate Stone        help='Extract modules from file',
1805b9c1b51eSKate Stone        default=False)
1806b9c1b51eSKate Stone    parser.add_option(
1807b9c1b51eSKate Stone        '-C',
1808b9c1b51eSKate Stone        '--count',
1809b9c1b51eSKate Stone        type='int',
1810b9c1b51eSKate Stone        dest='max_count',
1811b9c1b51eSKate Stone        help='Sets the max byte count when dumping section data',
1812b9c1b51eSKate Stone        default=-1)
18136a23d212SGreg Clayton
18146a23d212SGreg Clayton    (options, mach_files) = parser.parse_args()
18156a23d212SGreg Clayton    if options.extract_modules:
18166a23d212SGreg Clayton        if options.section_names:
1817525cd59fSSerge Guelton            print("error: can't use --section option with the --extract-modules option")
18186a23d212SGreg Clayton            exit(1)
18196a23d212SGreg Clayton        if not options.outfile:
1820525cd59fSSerge Guelton            print("error: the --output=FILE option must be specified with the --extract-modules option")
18216a23d212SGreg Clayton            exit(1)
18226a23d212SGreg Clayton        options.section_names.append("__apple_ast")
18236a23d212SGreg Clayton    if options.compare:
18246a23d212SGreg Clayton        if len(mach_files) == 2:
18256a23d212SGreg Clayton            mach_a = Mach()
18266a23d212SGreg Clayton            mach_b = Mach()
18276a23d212SGreg Clayton            mach_a.parse(mach_files[0])
18286a23d212SGreg Clayton            mach_b.parse(mach_files[1])
18296a23d212SGreg Clayton            mach_a.compare(mach_b)
18306a23d212SGreg Clayton        else:
1831525cd59fSSerge Guelton            print('error: --compare takes two mach files as arguments')
18326a23d212SGreg Clayton    else:
18336a23d212SGreg Clayton        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):
18346a23d212SGreg Clayton            options.dump_header = True
18356a23d212SGreg Clayton            options.dump_load_commands = True
18366a23d212SGreg Clayton        if options.verbose:
1837525cd59fSSerge Guelton            print('options', options)
1838525cd59fSSerge Guelton            print('mach_files', mach_files)
18396a23d212SGreg Clayton        for path in mach_files:
18406a23d212SGreg Clayton            mach = Mach()
18416a23d212SGreg Clayton            mach.parse(path)
18426a23d212SGreg Clayton            if options.interactive:
18436a23d212SGreg Clayton                interpreter = Mach.Interactive(mach, options)
18446a23d212SGreg Clayton                interpreter.cmdloop()
18456a23d212SGreg Clayton            else:
18466a23d212SGreg Clayton                mach.dump(options)
1847