text: """
  Other than changing the load commands in such a way that they do not
  contain the load command itself, this is largely a by-hand conversion
  of the C headers.  Hopefully everything in here should be at least as
  obvious as the C headers, and you should be using the C headers as a real
  reference because the documentation didn't come along for the ride.
  
  Doing much of anything with the symbol tables or segments is really
  not covered at this point.
  
  See /usr/include/mach-o and friends.
  """
  
  import time
  
  from macholib.ptypes import p_uint32, p_uint64, Structure, p_long, pypackable
  from macholib.ptypes import p_int64, p_short, p_uint8, p_int32, p_ulong
  
  _CPU_ARCH_ABI64 = 0x01000000
  
  CPU_TYPE_NAMES = {
      -1:     'ANY',
      1:      'VAX',
      6:      'MC680x0',
      7:      'i386',
      _CPU_ARCH_ABI64 | 7:    'x86_64',
      8:      'MIPS',
      10:     'MC98000',
      11:     'HPPA',
      12:     'ARM',
      _CPU_ARCH_ABI64 | 12:     'ARM64',
      13:     'MC88000',
      14:     'SPARC',
      15:     'i860',
      16:     'Alpha',
      18:     'PowerPC',
      _CPU_ARCH_ABI64 | 18:    'PowerPC64',
  }
  
  INTEL64_SUBTYPE = {
      3: "CPU_SUBTYPE_X86_64_ALL",
      4: "CPU_SUBTYPE_X86_ARCH1",
      8: "CPU_SUBTYPE_X86_64_H",
  }
  
  # define CPU_SUBTYPE_INTEL(f, m) ((cpu_subtype_t) (f) + ((m) << 4))
  INTEL_SUBTYPE = {
      0: "CPU_SUBTYPE_INTEL_MODEL_ALL",
      1: "CPU_THREADTYPE_INTEL_HTT",
      3: "CPU_SUBTYPE_I386_ALL",
      4: "CPU_SUBTYPE_486",
      5: "CPU_SUBTYPE_586",
      8: "CPU_SUBTYPE_PENTIUM_3",
      9: "CPU_SUBTYPE_PENTIUM_M",
      10: "CPU_SUBTYPE_PENTIUM_4",
      11: "CPU_SUBTYPE_ITANIUM",
      12: "CPU_SUBTYPE_XEON",
      34: "CPU_SUBTYPE_XEON_MP",
      42: "CPU_SUBTYPE_PENTIUM_4_M",
      43: "CPU_SUBTYPE_ITANIUM_2",
      38: "CPU_SUBTYPE_PENTPRO",
      40: "CPU_SUBTYPE_PENTIUM_3_M",
      52: "CPU_SUBTYPE_PENTIUM_3_XEON",
      102: "CPU_SUBTYPE_PENTII_M3",
      132: "CPU_SUBTYPE_486SX",
      166: "CPU_SUBTYPE_PENTII_M5",
      199: "CPU_SUBTYPE_CELERON",
      231: "CPU_SUBTYPE_CELERON_MOBILE"
  }
  
  MC680_SUBTYPE = {
      1: "CPU_SUBTYPE_MC680x0_ALL",
      2: "CPU_SUBTYPE_MC68040",
      3: "CPU_SUBTYPE_MC68030_ONLY"
  }
  
  MIPS_SUBTYPE = {
      0: "CPU_SUBTYPE_MIPS_ALL",
      1: "CPU_SUBTYPE_MIPS_R2300",
      2: "CPU_SUBTYPE_MIPS_R2600",
      3: "CPU_SUBTYPE_MIPS_R2800",
      4: "CPU_SUBTYPE_MIPS_R2000a",
      5: "CPU_SUBTYPE_MIPS_R2000",
      6: "CPU_SUBTYPE_MIPS_R3000a",
      7: "CPU_SUBTYPE_MIPS_R3000"
  }
  
  MC98000_SUBTYPE = {
      0: "CPU_SUBTYPE_MC98000_ALL",
      1: "CPU_SUBTYPE_MC98601"
  }
  
  HPPA_SUBTYPE = {
      0: "CPU_SUBTYPE_HPPA_7100",
      1: "CPU_SUBTYPE_HPPA_7100LC"
  }
  
  MC88_SUBTYPE = {
      0: "CPU_SUBTYPE_MC88000_ALL",
      1: "CPU_SUBTYPE_MC88100",
      2: "CPU_SUBTYPE_MC88110"
  }
  
  SPARC_SUBTYPE = {
      0: "CPU_SUBTYPE_SPARC_ALL"
  }
  
  I860_SUBTYPE = {
      0: "CPU_SUBTYPE_I860_ALL",
      1: "CPU_SUBTYPE_I860_860"
  }
  
  POWERPC_SUBTYPE = {
      0: "CPU_SUBTYPE_POWERPC_ALL",
      1: "CPU_SUBTYPE_POWERPC_601",
      2: "CPU_SUBTYPE_POWERPC_602",
      3: "CPU_SUBTYPE_POWERPC_603",
      4: "CPU_SUBTYPE_POWERPC_603e",
      5: "CPU_SUBTYPE_POWERPC_603ev",
      6: "CPU_SUBTYPE_POWERPC_604",
      7: "CPU_SUBTYPE_POWERPC_604e",
      8: "CPU_SUBTYPE_POWERPC_620",
      9: "CPU_SUBTYPE_POWERPC_750",
      10: "CPU_SUBTYPE_POWERPC_7400",
      11: "CPU_SUBTYPE_POWERPC_7450",
      100: "CPU_SUBTYPE_POWERPC_970"
  }
  
  ARM_SUBTYPE = {
      0: "CPU_SUBTYPE_ARM_ALL12",
      5: "CPU_SUBTYPE_ARM_V4T",
      6: "CPU_SUBTYPE_ARM_V6",
      7: "CPU_SUBTYPE_ARM_V5TEJ",
      8: "CPU_SUBTYPE_ARM_XSCALE",
      9: "CPU_SUBTYPE_ARM_V7",
      10: "CPU_SUBTYPE_ARM_V7F",
      11: "CPU_SUBTYPE_ARM_V7S",
      12: "CPU_SUBTYPE_ARM_V7K",
      13: "CPU_SUBTYPE_ARM_V8",
      14: "CPU_SUBTYPE_ARM_V6M",
      15: "CPU_SUBTYPE_ARM_V7M",
      16: "CPU_SUBTYPE_ARM_V7EM",
  }
  
  ARM64_SUBTYPE = {
      0: "CPU_SUBTYPE_ARM64_ALL",
      1: "CPU_SUBTYPE_ARM64_V8",
  }
  
  VAX_SUBTYPE = {
      0: "CPU_SUBTYPE_VAX_ALL",
      1: "CPU_SUBTYPE_VAX780",
      2: "CPU_SUBTYPE_VAX785",
      3: "CPU_SUBTYPE_VAX750",
      4: "CPU_SUBTYPE_VAX730",
      5: "CPU_SUBTYPE_UVAXI",
      6: "CPU_SUBTYPE_UVAXII",
      7: "CPU_SUBTYPE_VAX8200",
      8: "CPU_SUBTYPE_VAX8500",
      9: "CPU_SUBTYPE_VAX8600",
      10: "CPU_SUBTYPE_VAX8650",
      11: "CPU_SUBTYPE_VAX8800",
      12: "CPU_SUBTYPE_UVAXIII",
  }
  
  
  def get_cpu_subtype(cpu_type, cpu_subtype):
      st = cpu_subtype & 0x0fffffff
  
      if cpu_type == 1:
          subtype = VAX_SUBTYPE.get(st, st)
      elif cpu_type == 6:
          subtype = MC680_SUBTYPE.get(st, st)
      elif cpu_type == 7:
          subtype = INTEL_SUBTYPE.get(st, st)
      elif cpu_type == 7 | _CPU_ARCH_ABI64:
          subtype = INTEL64_SUBTYPE.get(st, st)
      elif cpu_type == 8:
          subtype = MIPS_SUBTYPE.get(st, st)
      elif cpu_type == 10:
          subtype = MC98000_SUBTYPE.get(st, st)
      elif cpu_type == 11:
          subtype = HPPA_SUBTYPE.get(st, st)
      elif cpu_type == 12:
          subtype = ARM_SUBTYPE.get(st, st)
      elif cpu_type == 12 | _CPU_ARCH_ABI64:
          subtype = ARM64_SUBTYPE.get(st, st)
      elif cpu_type == 13:
          subtype = MC88_SUBTYPE.get(st, st)
      elif cpu_type == 14:
          subtype = SPARC_SUBTYPE.get(st, st)
      elif cpu_type == 15:
          subtype = I860_SUBTYPE.get(st, st)
      elif cpu_type == 16:
          subtype = MIPS_SUBTYPE.get(st, st)
      elif cpu_type == 18:
          subtype = POWERPC_SUBTYPE.get(st, st)
      elif cpu_type == 18 | _CPU_ARCH_ABI64:
          subtype = POWERPC_SUBTYPE.get(st, st)
      else:
          subtype = str(st)
  
      return subtype
  
  
  _MH_EXECUTE_SYM = "__mh_execute_header"
  MH_EXECUTE_SYM = "_mh_execute_header"
  _MH_BUNDLE_SYM = "__mh_bundle_header"
  MH_BUNDLE_SYM = "_mh_bundle_header"
  _MH_DYLIB_SYM = "__mh_dylib_header"
  MH_DYLIB_SYM = "_mh_dylib_header"
  _MH_DYLINKER_SYM = "__mh_dylinker_header"
  MH_DYLINKER_SYM = "_mh_dylinker_header"
  
  (
      MH_OBJECT, MH_EXECUTE, MH_FVMLIB, MH_CORE, MH_PRELOAD, MH_DYLIB,
      MH_DYLINKER, MH_BUNDLE, MH_DYLIB_STUB, MH_DSYM
  ) = range(0x1, 0xb)
  
  (
      MH_NOUNDEFS, MH_INCRLINK, MH_DYLDLINK, MH_BINDATLOAD, MH_PREBOUND,
      MH_SPLIT_SEGS, MH_LAZY_INIT, MH_TWOLEVEL, MH_FORCE_FLAT, MH_NOMULTIDEFS,
      MH_NOFIXPREBINDING, MH_PREBINDABLE, MH_ALLMODSBOUND,
      MH_SUBSECTIONS_VIA_SYMBOLS, MH_CANONICAL, MH_WEAK_DEFINES,
      MH_BINDS_TO_WEAK, MH_ALLOW_STACK_EXECUTION,
      MH_ROOT_SAFE, MH_SETUID_SAFE, MH_NO_REEXPORTED_DYLIBS, MH_PIE,
      MH_DEAD_STRIPPABLE_DYLIB, MH_HAS_TLV_DESCRIPTORS, MH_NO_HEAP_EXECUTION,
      MH_APP_EXTENSION_SAFE
  ) = map((1).__lshift__, range(26))
  
  MH_MAGIC = 0xfeedface
  MH_CIGAM = 0xcefaedfe
  MH_MAGIC_64 = 0xfeedfacf
  MH_CIGAM_64 = 0xcffaedfe
  
  integer_t = p_int32
  cpu_type_t = integer_t
  cpu_subtype_t = p_uint32
  
  MH_FILETYPE_NAMES = {
      MH_OBJECT: 'relocatable object',
      MH_EXECUTE: 'demand paged executable',
      MH_FVMLIB: 'fixed vm shared library',
      MH_CORE: 'core',
      MH_PRELOAD: 'preloaded executable',
      MH_DYLIB: 'dynamically bound shared library',
      MH_DYLINKER: 'dynamic link editor',
      MH_BUNDLE: 'dynamically bound bundle',
      MH_DYLIB_STUB: 'shared library stub for static linking',
      MH_DSYM: 'symbol information',
  }
  
  MH_FILETYPE_SHORTNAMES = {
      MH_OBJECT: 'object',
      MH_EXECUTE: 'execute',
      MH_FVMLIB: 'fvmlib',
      MH_CORE: 'core',
      MH_PRELOAD: 'preload',
      MH_DYLIB: 'dylib',
      MH_DYLINKER: 'dylinker',
      MH_BUNDLE: 'bundle',
      MH_DYLIB_STUB: 'dylib_stub',
      MH_DSYM: 'dsym',
  }
  
  MH_FLAGS_NAMES = {
      MH_NOUNDEFS: 'MH_NOUNDEFS',
      MH_INCRLINK: 'MH_INCRLINK',
      MH_DYLDLINK: 'MH_DYLDLINK',
      MH_BINDATLOAD: 'MH_BINDATLOAD',
      MH_PREBOUND: 'MH_PREBOUND',
      MH_SPLIT_SEGS: 'MH_SPLIT_SEGS',
      MH_LAZY_INIT: 'MH_LAZY_INIT',
      MH_TWOLEVEL: 'MH_TWOLEVEL',
      MH_FORCE_FLAT: 'MH_FORCE_FLAT',
      MH_NOMULTIDEFS: 'MH_NOMULTIDEFS',
      MH_NOFIXPREBINDING: 'MH_NOFIXPREBINDING',
      MH_PREBINDABLE: 'MH_PREBINDABLE',
      MH_ALLMODSBOUND: 'MH_ALLMODSBOUND',
      MH_SUBSECTIONS_VIA_SYMBOLS: 'MH_SUBSECTIONS_VIA_SYMBOLS',
      MH_CANONICAL: 'MH_CANONICAL',
      MH_WEAK_DEFINES: 'MH_WEAK_DEFINES',
      MH_BINDS_TO_WEAK: 'MH_BINDS_TO_WEAK',
      MH_ALLOW_STACK_EXECUTION: 'MH_ALLOW_STACK_EXECUTION',
      MH_ROOT_SAFE: 'MH_ROOT_SAFE',
      MH_SETUID_SAFE: 'MH_SETUID_SAFE',
      MH_NO_REEXPORTED_DYLIBS: 'MH_NO_REEXPORTED_DYLIBS',
      MH_PIE: 'MH_PIE',
      MH_DEAD_STRIPPABLE_DYLIB: 'MH_DEAD_STRIPPABLE_DYLIB',
      MH_HAS_TLV_DESCRIPTORS: 'MH_HAS_TLV_DESCRIPTORS',
      MH_NO_HEAP_EXECUTION: 'MH_NO_HEAP_EXECUTION',
      MH_APP_EXTENSION_SAFE: 'MH_APP_EXTENSION_SAFE',
  }
  
  MH_FLAGS_DESCRIPTIONS = {
      MH_NOUNDEFS: 'no undefined references',
      MH_INCRLINK: 'output of an incremental link',
      MH_DYLDLINK: 'input for the dynamic linker',
      MH_BINDATLOAD: 'undefined references bound dynamically when loaded',
      MH_PREBOUND: 'dynamic undefined references prebound',
      MH_SPLIT_SEGS: 'split read-only and read-write segments',
      MH_LAZY_INIT: '(obsolete)',
      MH_TWOLEVEL: 'using two-level name space bindings',
      MH_FORCE_FLAT: 'forcing all imagges to use flat name space bindings',
      MH_NOMULTIDEFS: 'umbrella guarantees no multiple definitions',
      MH_NOFIXPREBINDING: 'do not notify prebinding agent about this executable',
      MH_PREBINDABLE:
          'the binary is not prebound but can have its prebinding redone',
      MH_ALLMODSBOUND:
          'indicates that this binary binds to all two-level namespace modules '
          'of its dependent libraries',
      MH_SUBSECTIONS_VIA_SYMBOLS:
          'safe to divide up the sections into sub-sections via symbols for '
          'dead code stripping',
      MH_CANONICAL:
          'the binary has been canonicalized via the unprebind operation',
      MH_WEAK_DEFINES: 'the final linked image contains external weak symbols',
      MH_BINDS_TO_WEAK: 'the final linked image uses weak symbols',
      MH_ALLOW_STACK_EXECUTION:
          'all stacks in the task will be given stack execution privilege',
      MH_ROOT_SAFE:
          'the binary declares it is safe for use in processes with uid zero',
      MH_SETUID_SAFE:
          'the binary declares it is safe for use in processes when issetugid() '
          'is true',
      MH_NO_REEXPORTED_DYLIBS:
          'the static linker does not need to examine dependent dylibs to see '
          'if any are re-exported',
      MH_PIE: 'the OS will load the main executable at a random address',
      MH_DEAD_STRIPPABLE_DYLIB:
          'the static linker will automatically not create a LC_LOAD_DYLIB load '
          'command to the dylib if no symbols are being referenced from the '
          'dylib',
      MH_HAS_TLV_DESCRIPTORS:
          'contains a section of type S_THREAD_LOCAL_VARIABLES',
      MH_NO_HEAP_EXECUTION:
          'the OS will run the main executable with a non-executable heap '
          'even on platforms that don\'t require it',
      MH_APP_EXTENSION_SAFE:
          'the code was linked for use in an application extension.',
  }
  
  
  class mach_version_helper(Structure):
      _fields_ = (
          ('_version', p_uint32),
      )
  
      @property
      def major(self):
          return self._version >> 16 & 0xffff
  
      @major.setter
      def major(self, v):
          self._version = (self._version & 0xffff) | (v << 16)
  
      @property
      def minor(self):
          return self._version >> 8 & 0xff
  
      @minor.setter
      def minor(self, v):
          self._version = (self._version & 0xffff00ff) | (v << 8)
  
      @property
      def rev(self):
          return self._version & 0xff
  
      @rev.setter
      def rev(self, v):
          return (self._version & 0xffffff00) | v
  
      def __str__(self):
          return '%s.%s.%s' % (self.major, self.minor, self.rev)
  
  
  class mach_timestamp_helper(p_uint32):
      def __str__(self):
          return time.ctime(self)
  
  
  def read_struct(f, s, **kw):
      return s.from_fileobj(f, **kw)
  
  
  class mach_header(Structure):
      _fields_ = (
          ('magic', p_uint32),
          ('cputype', cpu_type_t),
          ('cpusubtype', cpu_subtype_t),
          ('filetype', p_uint32),
          ('ncmds', p_uint32),
          ('sizeofcmds', p_uint32),
          ('flags', p_uint32),
      )
  
      def _describe(self):
          bit = 1
          flags = self.flags
          dflags = []
          while flags and bit < (1 << 32):
              if flags & bit:
                  dflags.append({
                      'name': MH_FLAGS_NAMES.get(bit, str(bit)),
                      'description': MH_FLAGS_DESCRIPTIONS.get(bit, str(bit))
                  })
                  flags = flags ^ bit
              bit <<= 1
          return (
              ('magic', int(self.magic)),
              ('cputype_string', CPU_TYPE_NAMES.get(self.cputype, self.cputype)),
              ('cputype', int(self.cputype)),
              ('cpusubtype_string',
                  get_cpu_subtype(self.cputype, self.cpusubtype)),
              ('cpusubtype', int(self.cpusubtype)),
              ('filetype_string',
                  MH_FILETYPE_NAMES.get(self.filetype, self.filetype)),
              ('filetype', int(self.filetype)),
              ('ncmds', self.ncmds),
              ('sizeofcmds', self.sizeofcmds),
              ('flags', dflags),
              ('raw_flags', int(self.flags))
          )
  
  
  class mach_header_64(mach_header):
      _fields_ = mach_header._fields_ + (('reserved', p_uint32),)
  
  
  class load_command(Structure):
      _fields_ = (
          ('cmd', p_uint32),
          ('cmdsize', p_uint32),
      )
  
      def get_cmd_name(self):
          return LC_NAMES.get(self.cmd, self.cmd)
      
      def __hash__(self):
          return hash(self.cmd)
  
      def __eq__(self, other):
          return self is other
  
  
  LC_REQ_DYLD = 0x80000000
  
  (
      LC_SEGMENT, LC_SYMTAB, LC_SYMSEG, LC_THREAD, LC_UNIXTHREAD, LC_LOADFVMLIB,
      LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_DYSYMTAB, LC_LOAD_DYLIB,
      LC_ID_DYLIB, LC_LOAD_DYLINKER, LC_ID_DYLINKER, LC_PREBOUND_DYLIB,
      LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT,
      LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM
  ) = range(0x1, 0x18)
  
  LC_LOAD_WEAK_DYLIB = LC_REQ_DYLD | 0x18
  
  LC_SEGMENT_64 = 0x19
  LC_ROUTINES_64 = 0x1a
  LC_UUID = 0x1b
  LC_RPATH = (0x1c | LC_REQ_DYLD)
  LC_CODE_SIGNATURE = 0x1d
  LC_CODE_SEGMENT_SPLIT_INFO = 0x1e
  LC_REEXPORT_DYLIB = 0x1f | LC_REQ_DYLD
  LC_LAZY_LOAD_DYLIB = 0x20
  LC_ENCRYPTION_INFO = 0x21
  LC_DYLD_INFO = 0x22
  LC_DYLD_INFO_ONLY = 0x22 | LC_REQ_DYLD
  LC_LOAD_UPWARD_DYLIB = 0x23 | LC_REQ_DYLD
  LC_VERSION_MIN_MACOSX = 0x24
  LC_VERSION_MIN_IPHONEOS = 0x25
  LC_FUNCTION_STARTS = 0x26
  LC_DYLD_ENVIRONMENT = 0x27
  LC_MAIN = 0x28 | LC_REQ_DYLD
  LC_DATA_IN_CODE = 0x29
  LC_SOURCE_VERSION = 0x2a
  LC_DYLIB_CODE_SIGN_DRS = 0x2b
  LC_ENCRYPTION_INFO_64 = 0x2c
  LC_LINKER_OPTION = 0x2d
  LC_LINKER_OPTIMIZATION_HINT = 0x2e
  LC_VERSION_MIN_TVOS = 0x2f
  LC_VERSION_MIN_WATCHOS = 0x30
  LC_NOTE = 0x31
  LC_BUILD_VERSION = 0x32
  
  
  # this is really a union.. but whatever
  class lc_str(p_uint32):
      pass
  
  
  p_str16 = pypackable('p_str16', bytes, '16s')
  
  vm_prot_t = p_int32
  
  
  class segment_command(Structure):
      _fields_ = (
          ('segname', p_str16),
          ('vmaddr', p_uint32),
          ('vmsize', p_uint32),
          ('fileoff', p_uint32),
          ('filesize', p_uint32),
          ('maxprot', vm_prot_t),
          ('initprot', vm_prot_t),
          ('nsects', p_uint32),  # read the section structures ?
          ('flags', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['segname'] = self.segname.rstrip('\x00')
          s['vmaddr'] = int(self.vmaddr)
          s['vmsize'] = int(self.vmsize)
          s['fileoff'] = int(self.fileoff)
          s['filesize'] = int(self.filesize)
          s['initprot'] = self.get_initial_virtual_memory_protections()
          s['initprot_raw'] = int(self.initprot)
          s['maxprot'] = self.get_max_virtual_memory_protections()
          s['maxprot_raw'] = int(self.maxprot)
          s['nsects'] = int(self.nsects)
          s['flags'] = self.flags
          return s
  
      def get_initial_virtual_memory_protections(self):
          vm = []
          if self.initprot == 0:
              vm.append("VM_PROT_NONE")
          if self.initprot & 1:
              vm.append("VM_PROT_READ")
          if self.initprot & 2:
              vm.append("VM_PROT_WRITE")
          if self.initprot & 4:
              vm.append("VM_PROT_EXECUTE")
          return vm
  
      def get_max_virtual_memory_protections(self):
          vm = []
          if self.maxprot == 0:
              vm.append("VM_PROT_NONE")
          if self.maxprot & 1:
              vm.append("VM_PROT_READ")
          if self.maxprot & 2:
              vm.append("VM_PROT_WRITE")
          if self.maxprot & 4:
              vm.append("VM_PROT_EXECUTE")
          return vm
  
  
  class segment_command_64(Structure):
      _fields_ = (
          ('segname', p_str16),
          ('vmaddr', p_uint64),
          ('vmsize', p_uint64),
          ('fileoff', p_uint64),
          ('filesize', p_uint64),
          ('maxprot', vm_prot_t),
          ('initprot', vm_prot_t),
          ('nsects', p_uint32),  # read the section structures ?
          ('flags', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['segname'] = self.segname.rstrip('\x00')
          s['vmaddr'] = int(self.vmaddr)
          s['vmsize'] = int(self.vmsize)
          s['fileoff'] = int(self.fileoff)
          s['filesize'] = int(self.filesize)
          s['initprot'] = self.get_initial_virtual_memory_protections()
          s['initprot_raw'] = int(self.initprot)
          s['maxprot'] = self.get_max_virtual_memory_protections()
          s['maxprot_raw'] = int(self.maxprot)
          s['nsects'] = int(self.nsects)
          s['flags'] = self.flags
          return s
  
      def get_initial_virtual_memory_protections(self):
          vm = []
          if self.initprot == 0:
              vm.append("VM_PROT_NONE")
          if self.initprot & 1:
              vm.append("VM_PROT_READ")
          if self.initprot & 2:
              vm.append("VM_PROT_WRITE")
          if self.initprot & 4:
              vm.append("VM_PROT_EXECUTE")
          return vm
  
      def get_max_virtual_memory_protections(self):
          vm = []
          if self.maxprot == 0:
              vm.append("VM_PROT_NONE")
          if self.maxprot & 1:
              vm.append("VM_PROT_READ")
          if self.maxprot & 2:
              vm.append("VM_PROT_WRITE")
          if self.maxprot & 4:
              vm.append("VM_PROT_EXECUTE")
          return vm
  
  
  SG_HIGHVM = 0x1
  SG_FVMLIB = 0x2
  SG_NORELOC = 0x4
  SG_PROTECTED_VERSION_1 = 0x8
  
  
  class section(Structure):
      _fields_ = (
          ('sectname', p_str16),
          ('segname', p_str16),
          ('addr', p_uint32),
          ('size', p_uint32),
          ('offset', p_uint32),
          ('align', p_uint32),
          ('reloff', p_uint32),
          ('nreloc', p_uint32),
          ('flags', p_uint32),
          ('reserved1', p_uint32),
          ('reserved2', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['sectname'] = self.sectname.rstrip('\x00')
          s['segname'] = self.segname.rstrip('\x00')
          s['addr'] = int(self.addr)
          s['size'] = int(self.size)
          s['offset'] = int(self.offset)
          s['align'] = int(self.align)
          s['reloff'] = int(self.reloff)
          s['nreloc'] = int(self.nreloc)
          f = {}
          f['type'] = FLAG_SECTION_TYPES[int(self.flags) & 0xff]
          f['attributes'] = []
          for k in FLAG_SECTION_ATTRIBUTES:
              if k & self.flags:
                  f['attributes'].append(FLAG_SECTION_ATTRIBUTES[k])
          if not f['attributes']:
              del f['attributes']
          s['flags'] = f
          s['reserved1'] = int(self.reserved1)
          s['reserved2'] = int(self.reserved2)
          return s
  
      def add_section_data(self, data):
          self.section_data = data
  
  
  class section_64(Structure):
      _fields_ = (
          ('sectname', p_str16),
          ('segname', p_str16),
          ('addr', p_uint64),
          ('size', p_uint64),
          ('offset', p_uint32),
          ('align', p_uint32),
          ('reloff', p_uint32),
          ('nreloc', p_uint32),
          ('flags', p_uint32),
          ('reserved1', p_uint32),
          ('reserved2', p_uint32),
          ('reserved3', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['sectname'] = self.sectname.rstrip('\x00')
          s['segname'] = self.segname.rstrip('\x00')
          s['addr'] = int(self.addr)
          s['size'] = int(self.size)
          s['offset'] = int(self.offset)
          s['align'] = int(self.align)
          s['reloff'] = int(self.reloff)
          s['nreloc'] = int(self.nreloc)
          f = {}
          f['type'] = FLAG_SECTION_TYPES[int(self.flags) & 0xff]
          f['attributes'] = []
          for k in FLAG_SECTION_ATTRIBUTES:
              if k & self.flags:
                  f['attributes'].append(FLAG_SECTION_ATTRIBUTES[k])
          if not f['attributes']:
              del f['attributes']
          s['flags'] = f
          s['reserved1'] = int(self.reserved1)
          s['reserved2'] = int(self.reserved2)
          s['reserved3'] = int(self.reserved3)
          return s
  
      def add_section_data(self, data):
          self.section_data = data
  
  
  SECTION_TYPE = 0xff
  SECTION_ATTRIBUTES = 0xffffff00
  S_REGULAR = 0x0
  S_ZEROFILL = 0x1
  S_CSTRING_LITERALS = 0x2
  S_4BYTE_LITERALS = 0x3
  S_8BYTE_LITERALS = 0x4
  S_LITERAL_POINTERS = 0x5
  S_NON_LAZY_SYMBOL_POINTERS = 0x6
  S_LAZY_SYMBOL_POINTERS = 0x7
  S_SYMBOL_STUBS = 0x8
  S_MOD_INIT_FUNC_POINTERS = 0x9
  S_MOD_TERM_FUNC_POINTERS = 0xa
  S_COALESCED = 0xb
  S_GB_ZEROFILL = 0xc
  S_INTERPOSING = 0xd
  S_16BYTE_LITERALS = 0xe
  S_DTRACE_DOF = 0xf
  S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10
  S_THREAD_LOCAL_REGULAR = 0x11
  S_THREAD_LOCAL_ZEROFILL = 0x12
  S_THREAD_LOCAL_VARIABLES = 0x13
  S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14
  S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15
  
  FLAG_SECTION_TYPES = {
      S_REGULAR: "S_REGULAR",
      S_ZEROFILL: "S_ZEROFILL",
      S_CSTRING_LITERALS: "S_CSTRING_LITERALS",
      S_4BYTE_LITERALS: "S_4BYTE_LITERALS",
      S_8BYTE_LITERALS: "S_8BYTE_LITERALS",
      S_LITERAL_POINTERS: "S_LITERAL_POINTERS",
      S_NON_LAZY_SYMBOL_POINTERS: "S_NON_LAZY_SYMBOL_POINTERS",
      S_LAZY_SYMBOL_POINTERS: "S_LAZY_SYMBOL_POINTERS",
      S_SYMBOL_STUBS: "S_SYMBOL_STUBS",
      S_MOD_INIT_FUNC_POINTERS: "S_MOD_INIT_FUNC_POINTERS",
      S_MOD_TERM_FUNC_POINTERS: "S_MOD_TERM_FUNC_POINTERS",
      S_COALESCED: "S_COALESCED",
      S_GB_ZEROFILL: "S_GB_ZEROFILL",
      S_INTERPOSING: "S_INTERPOSING",
      S_16BYTE_LITERALS: "S_16BYTE_LITERALS",
      S_DTRACE_DOF: "S_DTRACE_DOF",
      S_LAZY_DYLIB_SYMBOL_POINTERS: "S_LAZY_DYLIB_SYMBOL_POINTERS",
      S_THREAD_LOCAL_REGULAR: "S_THREAD_LOCAL_REGULAR",
      S_THREAD_LOCAL_ZEROFILL: "S_THREAD_LOCAL_ZEROFILL",
      S_THREAD_LOCAL_VARIABLES: "S_THREAD_LOCAL_VARIABLES",
      S_THREAD_LOCAL_VARIABLE_POINTERS: "S_THREAD_LOCAL_VARIABLE_POINTERS",
      S_THREAD_LOCAL_INIT_FUNCTION_POINTERS:
          "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS"
  }
  
  SECTION_ATTRIBUTES_USR = 0xff000000
  S_ATTR_PURE_INSTRUCTIONS = 0x80000000
  S_ATTR_NO_TOC = 0x40000000
  S_ATTR_STRIP_STATIC_SYMS = 0x20000000
  S_ATTR_NO_DEAD_STRIP = 0x10000000
  S_ATTR_LIVE_SUPPORT = 0x08000000
  S_ATTR_SELF_MODIFYING_CODE = 0x04000000
  S_ATTR_DEBUG = 0x02000000
  
  SECTION_ATTRIBUTES_SYS = 0x00ffff00
  S_ATTR_SOME_INSTRUCTIONS = 0x00000400
  S_ATTR_EXT_RELOC = 0x00000200
  S_ATTR_LOC_RELOC = 0x00000100
  
  FLAG_SECTION_ATTRIBUTES = {
      S_ATTR_PURE_INSTRUCTIONS: "S_ATTR_PURE_INSTRUCTIONS",
      S_ATTR_NO_TOC: "S_ATTR_NO_TOC",
      S_ATTR_STRIP_STATIC_SYMS: "S_ATTR_STRIP_STATIC_SYMS",
      S_ATTR_NO_DEAD_STRIP: "S_ATTR_NO_DEAD_STRIP",
      S_ATTR_LIVE_SUPPORT: "S_ATTR_LIVE_SUPPORT",
      S_ATTR_SELF_MODIFYING_CODE: "S_ATTR_SELF_MODIFYING_CODE",
      S_ATTR_DEBUG: "S_ATTR_DEBUG",
      S_ATTR_SOME_INSTRUCTIONS: "S_ATTR_SOME_INSTRUCTIONS",
      S_ATTR_EXT_RELOC: "S_ATTR_EXT_RELOC",
      S_ATTR_LOC_RELOC: "S_ATTR_LOC_RELOC"
  }
  
  SEG_PAGEZERO = "__PAGEZERO"
  SEG_TEXT = "__TEXT"
  SECT_TEXT = "__text"
  SECT_FVMLIB_INIT0 = "__fvmlib_init0"
  SECT_FVMLIB_INIT1 = "__fvmlib_init1"
  SEG_DATA = "__DATA"
  SECT_DATA = "__data"
  SECT_BSS = "__bss"
  SECT_COMMON = "__common"
  SEG_OBJC = "__OBJC"
  SECT_OBJC_SYMBOLS = "__symbol_table"
  SECT_OBJC_MODULES = "__module_info"
  SECT_OBJC_STRINGS = "__selector_strs"
  SECT_OBJC_REFS = "__selector_refs"
  SEG_ICON = "__ICON"
  SECT_ICON_HEADER = "__header"
  SECT_ICON_TIFF = "__tiff"
  SEG_LINKEDIT = "__LINKEDIT"
  SEG_UNIXSTACK = "__UNIXSTACK"
  SEG_IMPORT = "__IMPORT"
  
  #
  #  I really should remove all these _command classes because they
  #  are no different.  I decided to keep the load commands separate,
  #  so classes like fvmlib and fvmlib_command are equivalent.
  #
  
  
  class fvmlib(Structure):
      _fields_ = (
          ('name', lc_str),
          ('minor_version', mach_version_helper),
          ('header_addr', p_uint32),
      )
  
  
  class fvmlib_command(Structure):
      _fields_ = fvmlib._fields_
  
      def describe(self):
          s = {}
          s['header_addr'] = int(self.header_addr)
          return s
  
  
  class dylib(Structure):
      _fields_ = (
          ('name', lc_str),
          ('timestamp', mach_timestamp_helper),
          ('current_version', mach_version_helper),
          ('compatibility_version', mach_version_helper),
      )
  
  
  # merged dylib structure
  class dylib_command(Structure):
      _fields_ = dylib._fields_
  
      def describe(self):
          s = {}
          s['timestamp'] = str(self.timestamp)
          s['current_version'] = str(self.current_version)
          s['compatibility_version'] = str(self.compatibility_version)
          return s
  
  
  class sub_framework_command(Structure):
      _fields_ = (
          ('umbrella', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class sub_client_command(Structure):
      _fields_ = (
          ('client', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class sub_umbrella_command(Structure):
      _fields_ = (
          ('sub_umbrella', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class sub_library_command(Structure):
      _fields_ = (
          ('sub_library', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class prebound_dylib_command(Structure):
      _fields_ = (
          ('name', lc_str),
          ('nmodules', p_uint32),
          ('linked_modules', lc_str),
      )
  
      def describe(self):
          return {'nmodules': int(self.nmodules)}
  
  
  class dylinker_command(Structure):
      _fields_ = (
          ('name', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class thread_command(Structure):
      _fields_ = (
          ('flavor', p_uint32),
          ('count', p_uint32)
      )
  
      def describe(self):
          s = {}
          s['flavor'] = int(self.flavor)
          s['count'] = int(self.count)
          return s
  
  
  class entry_point_command(Structure):
      _fields_ = (
          ('entryoff', p_uint64),
          ('stacksize', p_uint64),
      )
  
      def describe(self):
          s = {}
          s['entryoff'] = int(self.entryoff)
          s['stacksize'] = int(self.stacksize)
          return s
  
  
  class routines_command(Structure):
      _fields_ = (
          ('init_address', p_uint32),
          ('init_module', p_uint32),
          ('reserved1', p_uint32),
          ('reserved2', p_uint32),
          ('reserved3', p_uint32),
          ('reserved4', p_uint32),
          ('reserved5', p_uint32),
          ('reserved6', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['init_address'] = int(self.init_address)
          s['init_module'] = int(self.init_module)
          s['reserved1'] = int(self.reserved1)
          s['reserved2'] = int(self.reserved2)
          s['reserved3'] = int(self.reserved3)
          s['reserved4'] = int(self.reserved4)
          s['reserved5'] = int(self.reserved5)
          s['reserved6'] = int(self.reserved6)
          return s
  
  
  class routines_command_64(Structure):
      _fields_ = (
          ('init_address', p_uint64),
          ('init_module', p_uint64),
          ('reserved1', p_uint64),
          ('reserved2', p_uint64),
          ('reserved3', p_uint64),
          ('reserved4', p_uint64),
          ('reserved5', p_uint64),
          ('reserved6', p_uint64),
      )
  
      def describe(self):
          s = {}
          s['init_address'] = int(self.init_address)
          s['init_module'] = int(self.init_module)
          s['reserved1'] = int(self.reserved1)
          s['reserved2'] = int(self.reserved2)
          s['reserved3'] = int(self.reserved3)
          s['reserved4'] = int(self.reserved4)
          s['reserved5'] = int(self.reserved5)
          s['reserved6'] = int(self.reserved6)
          return s
  
  
  class symtab_command(Structure):
      _fields_ = (
          ('symoff', p_uint32),
          ('nsyms', p_uint32),
          ('stroff', p_uint32),
          ('strsize', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['symoff'] = int(self.symoff)
          s['nsyms'] = int(self.nsyms)
          s['stroff'] = int(self.stroff)
          s['strsize'] = int(self.strsize)
          return s
  
  
  class dysymtab_command(Structure):
      _fields_ = (
          ('ilocalsym', p_uint32),
          ('nlocalsym', p_uint32),
          ('iextdefsym', p_uint32),
          ('nextdefsym', p_uint32),
          ('iundefsym', p_uint32),
          ('nundefsym', p_uint32),
          ('tocoff', p_uint32),
          ('ntoc', p_uint32),
          ('modtaboff', p_uint32),
          ('nmodtab', p_uint32),
          ('extrefsymoff', p_uint32),
          ('nextrefsyms', p_uint32),
          ('indirectsymoff', p_uint32),
          ('nindirectsyms', p_uint32),
          ('extreloff', p_uint32),
          ('nextrel', p_uint32),
          ('locreloff', p_uint32),
          ('nlocrel', p_uint32),
      )
  
      def describe(self):
          dys = {}
          dys['ilocalsym'] = int(self.ilocalsym)
          dys['nlocalsym'] = int(self.nlocalsym)
          dys['iextdefsym'] = int(self.iextdefsym)
          dys['nextdefsym'] = int(self.nextdefsym)
          dys['iundefsym'] = int(self.iundefsym)
          dys['nundefsym'] = int(self.nundefsym)
          dys['tocoff'] = int(self.tocoff)
          dys['ntoc'] = int(self.ntoc)
          dys['modtaboff'] = int(self.modtaboff)
          dys['nmodtab'] = int(self.nmodtab)
          dys['extrefsymoff'] = int(self.extrefsymoff)
          dys['nextrefsyms'] = int(self.nextrefsyms)
          dys['indirectsymoff'] = int(self.indirectsymoff)
          dys['nindirectsyms'] = int(self.nindirectsyms)
          dys['extreloff'] = int(self.extreloff)
          dys['nextrel'] = int(self.nextrel)
          dys['locreloff'] = int(self.locreloff)
          dys['nlocrel'] = int(self.nlocrel)
          return dys
  
  
  INDIRECT_SYMBOL_LOCAL = 0x80000000
  INDIRECT_SYMBOL_ABS = 0x40000000
  
  
  class dylib_table_of_contents(Structure):
      _fields_ = (
          ('symbol_index', p_uint32),
          ('module_index', p_uint32),
      )
  
  
  class dylib_module(Structure):
      _fields_ = (
          ('module_name', p_uint32),
          ('iextdefsym', p_uint32),
          ('nextdefsym', p_uint32),
          ('irefsym', p_uint32),
          ('nrefsym', p_uint32),
          ('ilocalsym', p_uint32),
          ('nlocalsym', p_uint32),
          ('iextrel', p_uint32),
          ('nextrel', p_uint32),
          ('iinit_iterm', p_uint32),
          ('ninit_nterm', p_uint32),
          ('objc_module_info_addr', p_uint32),
          ('objc_module_info_size', p_uint32),
      )
  
  
  class dylib_module_64(Structure):
      _fields_ = (
          ('module_name', p_uint32),
          ('iextdefsym', p_uint32),
          ('nextdefsym', p_uint32),
          ('irefsym', p_uint32),
          ('nrefsym', p_uint32),
          ('ilocalsym', p_uint32),
          ('nlocalsym', p_uint32),
          ('iextrel', p_uint32),
          ('nextrel', p_uint32),
          ('iinit_iterm', p_uint32),
          ('ninit_nterm', p_uint32),
          ('objc_module_info_size', p_uint32),
          ('objc_module_info_addr', p_uint64),
      )
  
  
  class dylib_reference(Structure):
      _fields_ = (
          # XXX - ick, fix
          ('isym_flags', p_uint32),
          # ('isym', p_uint8 * 3),
          # ('flags', p_uint8),
      )
  
  
  class twolevel_hints_command(Structure):
      _fields_ = (
          ('offset', p_uint32),
          ('nhints', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['offset'] = int(self.offset)
          s['nhints'] = int(self.nhints)
          return s
  
  
  class twolevel_hint(Structure):
      _fields_ = (
        # XXX - ick, fix
        ('isub_image_itoc', p_uint32),
        # ('isub_image', p_uint8),
        # ('itoc', p_uint8 * 3),
      )
  
  
  class prebind_cksum_command(Structure):
      _fields_ = (
          ('cksum', p_uint32),
      )
  
      def describe(self):
          return {'cksum': int(self.cksum)}
  
  
  class symseg_command(Structure):
      _fields_ = (
          ('offset', p_uint32),
          ('size', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['offset'] = int(self.offset)
          s['size'] = int(self.size)
  
  
  class ident_command(Structure):
      _fields_ = (
      )
  
      def describe(self):
          return {}
  
  
  class fvmfile_command(Structure):
      _fields_ = (
          ('name', lc_str),
          ('header_addr', p_uint32),
      )
  
      def describe(self):
          return {'header_addr': int(self.header_addr)}
  
  
  class uuid_command (Structure):
      _fields_ = (
          ('uuid', p_str16),
      )
  
      def describe(self):
          return {'uuid': self.uuid.rstrip('\x00')}
  
  
  class rpath_command (Structure):
      _fields_ = (
          ('path', lc_str),
      )
  
      def describe(self):
          return {}
  
  
  class linkedit_data_command (Structure):
      _fields_ = (
          ('dataoff',   p_uint32),
          ('datasize', p_uint32),
      )
  
      def describe(self):
          s = {}
          s['dataoff'] = int(self.dataoff)
          s['datasize'] = int(self.datasize)
          return s
  
  
  class version_min_command (Structure):
      _fields_ = (
          ('version', p_uint32),  # X.Y.Z is encoded in nibbles xxxx.yy.zz
          ('sdk', p_uint32),
      )
  
      def describe(self):
          v = int(self.version)
          v3 = v & 0xFF
          v = v >> 8
          v2 = v & 0xFF
          v = v >> 8
          v1 = v & 0xFFFF
          s = int(self.sdk)
          s3 = s & 0xFF
          s = s >> 8
          s2 = s & 0xFF
          s = s >> 8
          s1 = s & 0xFFFF
          return {
              'version': str(int(v1)) + "." + str(int(v2)) + "." + str(int(v3)),
              'sdk': str(int(s1)) + "." + str(int(s2)) + "." + str(int(s3))
          }
  
  
  class source_version_command (Structure):
      _fields_ = (
          ('version',   p_uint64),
      )
  
      def describe(self):
          v = int(self.version)
          a = v >> 40
          b = (v >> 30) & 0x3ff
          c = (v >> 20) & 0x3ff
          d = (v >> 10) & 0x3ff
          e = v & 0x3ff
          r = str(a)+'.'+str(b)+'.'+str(c)+'.'+str(d)+'.'+str(e)
          return {'version': r}
  
  
  class note_command (Structure):
      _fields_ = (
         ('data_owner', p_str16),
         ('offset', p_uint64),
         ('size', p_uint64),
      )
  
  
  class build_version_command (Structure):
      _fields_ = (
        ('platform', p_uint32),
        ('minos', p_uint32),
        ('sdk', p_uint32),
        ('ntools', p_uint32),
      )
  
      def describe(self):
          return {}
  
      # XXX: Add computed field for accessing 'tools' array
  
  
  class build_tool_version (Structure):
      _fields_ = (
          ('tool', p_uint32),
          ('version', p_uint32),
      )
  
  
  class data_in_code_entry (Structure):
      _fields_ = (
          ('offset', p_uint32),
          ('length', p_uint32),
          ('kind', p_uint32),
      )
  
      def describe(self):
          return {
              'offset': self.offset, 'length': self.length, 'kind': self.kind}
  
  
  DICE_KIND_DATA = 0x0001
  DICE_KIND_JUMP_TABLE8 = 0x0002
  DICE_KIND_JUMP_TABLE16 = 0x0003
  DICE_KIND_JUMP_TABLE32 = 0x0004
  DICE_KIND_ABS_JUMP_TABLE32 = 0x0005
  
  DATA_IN_CODE_KINDS = {
      DICE_KIND_DATA: 'DICE_KIND_DATA',
      DICE_KIND_JUMP_TABLE8: 'DICE_KIND_JUMP_TABLE8',
      DICE_KIND_JUMP_TABLE16: 'DICE_KIND_JUMP_TABLE16',
      DICE_KIND_JUMP_TABLE32: 'DICE_KIND_JUMP_TABLE32',
      DICE_KIND_ABS_JUMP_TABLE32: 'DICE_KIND_ABS_JUMP_TABLE32',
  }
  
  
  class tlv_descriptor (Structure):
      _fields_ = (
          ('thunk', p_long),  # Actually a pointer to a function
          ('key', p_ulong),
          ('offset', p_ulong),
      )
  
      def describe(self):
          return {'thunk': self.thunk, 'key': self.key, 'offset': self.offset}
  
  
  class encryption_info_command (Structure):
      _fields_ = (
          ('cryptoff',    p_uint32),
          ('cryptsize',   p_uint32),
          ('cryptid',     p_uint32),
      )
  
      def describe(self):
          s = {}
          s['cryptoff'] = int(self.cryptoff)
          s['cryptsize'] = int(self.cryptsize)
          s['cryptid'] = int(self.cryptid)
          return s
  
  
  class encryption_info_command_64 (Structure):
      _fields_ = (
          ('cryptoff',    p_uint32),
          ('cryptsize',   p_uint32),
          ('cryptid',     p_uint32),
          ('pad',         p_uint32),
      )
  
      def describe(self):
          s = {}
          s['cryptoff'] = int(self.cryptoff)
          s['cryptsize'] = int(self.cryptsize)
          s['cryptid'] = int(self.cryptid)
          s['pad'] = int(self.pad)
          return s
  
  
  class dyld_info_command (Structure):
      _fields_ = (
          ('rebase_off',     p_uint32),
          ('rebase_size',    p_uint32),
          ('bind_off',       p_uint32),
          ('bind_size',      p_uint32),
          ('weak_bind_off',  p_uint32),
          ('weak_bind_size', p_uint32),
          ('lazy_bind_off',  p_uint32),
          ('lazy_bind_size', p_uint32),
          ('export_off',     p_uint32),
          ('export_size',    p_uint32),
      )
  
      def describe(self):
          dyld = {}
          dyld['rebase_off'] = int(self.rebase_off)
          dyld['rebase_size'] = int(self.rebase_size)
          dyld['bind_off'] = int(self.bind_off)
          dyld['bind_size'] = int(self.bind_size)
          dyld['weak_bind_off'] = int(self.weak_bind_off)
          dyld['weak_bind_size'] = int(self.weak_bind_size)
          dyld['lazy_bind_off'] = int(self.lazy_bind_off)
          dyld['lazy_bind_size'] = int(self.lazy_bind_size)
          dyld['export_off'] = int(self.export_off)
          dyld['export_size'] = int(self.export_size)
          return dyld
  
  
  class linker_option_command (Structure):
      _fields_ = (
          ('count',         p_uint32),
      )
  
      def describe(self):
          return {'count': int(self.count)}
  
  
  LC_REGISTRY = {
      LC_SEGMENT:         segment_command,
      LC_IDFVMLIB:        fvmlib_command,
      LC_LOADFVMLIB:      fvmlib_command,
      LC_ID_DYLIB:        dylib_command,
      LC_LOAD_DYLIB:      dylib_command,
      LC_LOAD_WEAK_DYLIB: dylib_command,
      LC_SUB_FRAMEWORK:   sub_framework_command,
      LC_SUB_CLIENT:      sub_client_command,
      LC_SUB_UMBRELLA:    sub_umbrella_command,
      LC_SUB_LIBRARY:     sub_library_command,
      LC_PREBOUND_DYLIB:  prebound_dylib_command,
      LC_ID_DYLINKER:     dylinker_command,
      LC_LOAD_DYLINKER:   dylinker_command,
      LC_THREAD:          thread_command,
      LC_UNIXTHREAD:      thread_command,
      LC_ROUTINES:        routines_command,
      LC_SYMTAB:          symtab_command,
      LC_DYSYMTAB:        dysymtab_command,
      LC_TWOLEVEL_HINTS:  twolevel_hints_command,
      LC_PREBIND_CKSUM:   prebind_cksum_command,
      LC_SYMSEG:          symseg_command,
      LC_IDENT:           ident_command,
      LC_FVMFILE:         fvmfile_command,
      LC_SEGMENT_64:      segment_command_64,
      LC_ROUTINES_64:     routines_command_64,
      LC_UUID:            uuid_command,
      LC_RPATH:           rpath_command,
      LC_CODE_SIGNATURE:  linkedit_data_command,
      LC_CODE_SEGMENT_SPLIT_INFO:  linkedit_data_command,
      LC_REEXPORT_DYLIB:  dylib_command,
      LC_LAZY_LOAD_DYLIB: dylib_command,
      LC_ENCRYPTION_INFO: encryption_info_command,
      LC_DYLD_INFO:       dyld_info_command,
      LC_DYLD_INFO_ONLY:  dyld_info_command,
      LC_LOAD_UPWARD_DYLIB: dylib_command,
      LC_VERSION_MIN_MACOSX: version_min_command,
      LC_VERSION_MIN_IPHONEOS: version_min_command,
      LC_FUNCTION_STARTS:  linkedit_data_command,
      LC_DYLD_ENVIRONMENT: dylinker_command,
      LC_MAIN: entry_point_command,
      LC_DATA_IN_CODE: linkedit_data_command,
      LC_SOURCE_VERSION: source_version_command,
      LC_DYLIB_CODE_SIGN_DRS:  linkedit_data_command,
      LC_ENCRYPTION_INFO_64: encryption_info_command_64,
      LC_LINKER_OPTION:  linker_option_command,
      LC_LINKER_OPTIMIZATION_HINT:  linkedit_data_command,
      LC_VERSION_MIN_TVOS: version_min_command,
      LC_VERSION_MIN_WATCHOS: version_min_command,
      LC_NOTE: note_command,
      LC_BUILD_VERSION: build_version_command,
  }
  
  LC_NAMES = {
      LC_SEGMENT:                     'LC_SEGMENT',
      LC_IDFVMLIB:                    'LC_IDFVMLIB',
      LC_LOADFVMLIB:                  'LC_LOADFVMLIB',
      LC_ID_DYLIB:                    'LC_ID_DYLIB',
      LC_LOAD_DYLIB:                  'LC_LOAD_DYLIB',
      LC_LOAD_WEAK_DYLIB:             'LC_LOAD_WEAK_DYLIB',
      LC_SUB_FRAMEWORK:               'LC_SUB_FRAMEWORK',
      LC_SUB_CLIENT:                  'LC_SUB_CLIENT',
      LC_SUB_UMBRELLA:                'LC_SUB_UMBRELLA',
      LC_SUB_LIBRARY:                 'LC_SUB_LIBRARY',
      LC_PREBOUND_DYLIB:              'LC_PREBOUND_DYLIB',
      LC_ID_DYLINKER:                 'LC_ID_DYLINKER',
      LC_LOAD_DYLINKER:               'LC_LOAD_DYLINKER',
      LC_THREAD:                      'LC_THREAD',
      LC_UNIXTHREAD:                  'LC_UNIXTHREAD',
      LC_ROUTINES:                    'LC_ROUTINES',
      LC_SYMTAB:                      'LC_SYMTAB',
      LC_DYSYMTAB:                    'LC_DYSYMTAB',
      LC_TWOLEVEL_HINTS:              'LC_TWOLEVEL_HINTS',
      LC_PREBIND_CKSUM:               'LC_PREBIND_CKSUM',
      LC_SYMSEG:                      'LC_SYMSEG',
      LC_IDENT:                       'LC_IDENT',
      LC_FVMFILE:                     'LC_FVMFILE',
      LC_SEGMENT_64:                  'LC_SEGMENT_64',
      LC_ROUTINES_64:                 'LC_ROUTINES_64',
      LC_UUID:                        'LC_UUID',
      LC_RPATH:                       'LC_RPATH',
      LC_CODE_SIGNATURE:              'LC_CODE_SIGNATURE',
      LC_CODE_SEGMENT_SPLIT_INFO:     'LC_CODE_SEGMENT_SPLIT_INFO',
      LC_REEXPORT_DYLIB:              'LC_REEXPORT_DYLIB',
      LC_LAZY_LOAD_DYLIB:             'LC_LAZY_LOAD_DYLIB',
      LC_ENCRYPTION_INFO:             'LC_ENCRYPTION_INFO',
      LC_DYLD_INFO:                   'LC_DYLD_INFO',
      LC_DYLD_INFO_ONLY:              'LC_DYLD_INFO_ONLY',
      LC_LOAD_UPWARD_DYLIB:           'LC_LOAD_UPWARD_DYLIB',
      LC_VERSION_MIN_MACOSX:          'LC_VERSION_MIN_MACOSX',
      LC_VERSION_MIN_IPHONEOS:        'LC_VERSION_MIN_IPHONEOS',
      LC_FUNCTION_STARTS:             'LC_FUNCTION_STARTS',
      LC_DYLD_ENVIRONMENT:            'LC_DYLD_ENVIRONMENT',
      LC_MAIN:                        'LC_MAIN',
      LC_DATA_IN_CODE:                'LC_DATA_IN_CODE',
      LC_SOURCE_VERSION:              'LC_SOURCE_VERSION',
      LC_DYLIB_CODE_SIGN_DRS:         'LC_DYLIB_CODE_SIGN_DRS',
      LC_LINKER_OPTIMIZATION_HINT:    'LC_LINKER_OPTIMIZATION_HINT',
      LC_VERSION_MIN_TVOS:            'LC_VERSION_MIN_TVOS',
      LC_VERSION_MIN_WATCHOS:         'LC_VERSION_MIN_WATCHOS',
      LC_NOTE:                        'LC_NOTE',
      LC_BUILD_VERSION:               'LC_BUILD_VERSION',
  }
  
  
  # this is another union.
  class n_un(p_int32):
      pass
  
  
  class nlist(Structure):
      _fields_ = (
          ('n_un', n_un),
          ('n_type', p_uint8),
          ('n_sect', p_uint8),
          ('n_desc', p_short),
          ('n_value', p_uint32),
      )
  
  
  class nlist_64(Structure):
      _fields_ = [
          ('n_un',    n_un),
          ('n_type', p_uint8),
          ('n_sect', p_uint8),
          ('n_desc', p_short),
          ('n_value', p_int64),
      ]
  
  
  N_STAB = 0xe0
  N_PEXT = 0x10
  N_TYPE = 0x0e
  N_EXT = 0x01
  
  N_UNDF = 0x0
  N_ABS = 0x2
  N_SECT = 0xe
  N_PBUD = 0xc
  N_INDR = 0xa
  
  NO_SECT = 0
  MAX_SECT = 255
  
  
  class relocation_info(Structure):
      # XXX: Need to add code for decoding the bitfield!
      _fields_ = (
          ('r_address', p_uint32),
          ('_r_bitfield', p_uint32),
      )
  
      def _describe(self):
          return (
              ('r_address', self.r_address),
              ('_r_bitfield', self._r_bitfield),
          )
  
  
  def GET_COMM_ALIGN(n_desc):
      return (n_desc >> 8) & 0x0f
  
  
  def SET_COMM_ALIGN(n_desc, align):
      return (n_desc & 0xf0ff) | ((align & 0x0f) << 8)
  
  
  REFERENCE_TYPE = 0xf
  REFERENCE_FLAG_UNDEFINED_NON_LAZY = 0
  REFERENCE_FLAG_UNDEFINED_LAZY = 1
  REFERENCE_FLAG_DEFINED = 2
  REFERENCE_FLAG_PRIVATE_DEFINED = 3
  REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4
  REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY = 5
  
  REFERENCED_DYNAMICALLY = 0x0010
  
  
  def GET_LIBRARY_ORDINAL(n_desc):
      return (((n_desc) >> 8) & 0xff)
  
  
  def SET_LIBRARY_ORDINAL(n_desc, ordinal):
      return (((n_desc) & 0x00ff) | (((ordinal & 0xff) << 8)))
  
  
  SELF_LIBRARY_ORDINAL = 0x0
  MAX_LIBRARY_ORDINAL = 0xfd
  DYNAMIC_LOOKUP_ORDINAL = 0xfe
  EXECUTABLE_ORDINAL = 0xff
  
  N_NO_DEAD_STRIP = 0x0020
  N_DESC_DISCARDED = 0x0020
  N_WEAK_REF = 0x0040
  N_WEAK_DEF = 0x0080
  N_REF_TO_WEAK = 0x0080
  N_ARM_THUMB_DEF = 0x0008
  N_SYMBOL_RESOLVER = 0x0100
  N_ALT_ENTRY = 0x0200
  
  # /usr/include/mach-o/fat.h
  FAT_MAGIC = 0xcafebabe
  FAT_CIGAM = 0xbebafeca
  FAT_MAGIC_64 = 0xcafebabf
  FAT_CIGAM_64 = 0xbfbafeca
  
  
  class fat_header(Structure):
      _fields_ = (
          ('magic', p_uint32),
          ('nfat_arch', p_uint32),
      )
  
  
  class fat_arch(Structure):
      _fields_ = (
          ('cputype', cpu_type_t),
          ('cpusubtype', cpu_subtype_t),
          ('offset', p_uint32),
          ('size', p_uint32),
          ('align', p_uint32),
      )
  
  
  class fat_arch64(Structure):
      _fields_ = (
          ('cputype', cpu_type_t),
          ('cpusubtype', cpu_subtype_t),
          ('offset', p_uint64),
          ('size', p_uint64),
          ('align', p_uint32),
          ('reserved', p_uint32),
      )
  
  
  REBASE_TYPE_POINTER                                     = 1  # noqa: E221
  REBASE_TYPE_TEXT_ABSOLUTE32                             = 2  # noqa: E221
  REBASE_TYPE_TEXT_PCREL32                                = 3  # noqa: E221
  
  REBASE_OPCODE_MASK                                      = 0xF0  # noqa: E221
  REBASE_IMMEDIATE_MASK                                   = 0x0F  # noqa: E221
  REBASE_OPCODE_DONE                                      = 0x00  # noqa: E221
  REBASE_OPCODE_SET_TYPE_IMM                              = 0x10  # noqa: E221
  REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB               = 0x20  # noqa: E221
  REBASE_OPCODE_ADD_ADDR_ULEB                             = 0x30  # noqa: E221
  REBASE_OPCODE_ADD_ADDR_IMM_SCALED                       = 0x40  # noqa: E221
  REBASE_OPCODE_DO_REBASE_IMM_TIMES                       = 0x50  # noqa: E221
  REBASE_OPCODE_DO_REBASE_ULEB_TIMES                      = 0x60  # noqa: E221
  REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB                   = 0x70  # noqa: E221
  REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB        = 0x80  # noqa: E221
  
  BIND_TYPE_POINTER                                       = 1  # noqa: E221
  BIND_TYPE_TEXT_ABSOLUTE32                               = 2  # noqa: E221
  BIND_TYPE_TEXT_PCREL32                                  = 3  # noqa: E221
  
  BIND_SPECIAL_DYLIB_SELF                                 = 0  # noqa: E221
  BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE                      = -1  # noqa: E221
  BIND_SPECIAL_DYLIB_FLAT_LOOKUP                          = -2  # noqa: E221
  
  BIND_SYMBOL_FLAGS_WEAK_IMPORT                           = 0x1  # noqa: E221
  BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION                   = 0x8  # noqa: E221
  
  BIND_OPCODE_MASK                                        = 0xF0  # noqa: E221
  BIND_IMMEDIATE_MASK                                     = 0x0F  # noqa: E221
  BIND_OPCODE_DONE                                        = 0x00  # noqa: E221
  BIND_OPCODE_SET_DYLIB_ORDINAL_IMM                       = 0x10  # noqa: E221
  BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB                      = 0x20  # noqa: E221
  BIND_OPCODE_SET_DYLIB_SPECIAL_IMM                       = 0x30  # noqa: E221
  BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM               = 0x40  # noqa: E221
  BIND_OPCODE_SET_TYPE_IMM                                = 0x50  # noqa: E221
  BIND_OPCODE_SET_ADDEND_SLEB                             = 0x60  # noqa: E221
  BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB                 = 0x70  # noqa: E221
  BIND_OPCODE_ADD_ADDR_ULEB                               = 0x80  # noqa: E221
  BIND_OPCODE_DO_BIND                                     = 0x90  # noqa: E221
  BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB                       = 0xA0  # noqa: E221
  BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED                 = 0xB0  # noqa: E221
  BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB            = 0xC0  # noqa: E221
  
  EXPORT_SYMBOL_FLAGS_KIND_MASK                           = 0x03  # noqa: E221
  EXPORT_SYMBOL_FLAGS_KIND_REGULAR                        = 0x00  # noqa: E221
  EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL                   = 0x01  # noqa: E221
  EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION                     = 0x04  # noqa: E221
  EXPORT_SYMBOL_FLAGS_REEXPORT                            = 0x08  # noqa: E221
  EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER                   = 0x10  # noqa: E221
  
  PLATFORM_MACOS = 1
  PLATFORM_IOS = 2
  PLATFORM_TVOS = 3
  PLATFORM_WATCHOS = 4
  PLATFORM_BRIDGEOS = 5
  PLATFORM_IOSMAC = 6
  PLATFORM_IOSSIMULATOR = 7
  PLATFORM_TVOSSIMULATOR = 8
  PLATFORM_WATCHOSSIMULATOR = 9
  
  PLATFORM_NAMES = {
      PLATFORM_MACOS: 'macOS',
      PLATFORM_IOS: 'iOS',
      PLATFORM_TVOS: 'tvOS',
      PLATFORM_WATCHOS: 'watchOS',
      PLATFORM_BRIDGEOS: 'bridgeOS',
      PLATFORM_IOSMAC: 'ios-on-mac',
      PLATFORM_IOSSIMULATOR: 'iOS simulator',
      PLATFORM_TVOSSIMULATOR: 'tvOS simulator',
      PLATFORM_WATCHOSSIMULATOR: 'watchOS simulator',
  }
  
  TOOL_CLANG = 1
  TOOL_SWIFT = 2
  TOOL_LD = 3
  
  TOOL_NAMES = {
      TOOL_CLANG: 'clang',
      TOOL_SWIFT: 'swift',
      TOOL_LD: 'ld',
  }
  