/// Mach-O format. /// /// Sources: /// - https://github.com/opensource-apple/cctools/blob/master/include/mach/machine.h /// - https://github.com/opensource-apple/cctools/blob/master/include/mach-o/loader.h /// /// Authors: dd86k <dd@dax.moe> /// Copyright: © dd86k <dd@dax.moe> /// License: BSD-3-Clause-Clear module adbg.object.format.macho; import adbg.error; import adbg.object.server : adbg_object_t, AdbgObject; import adbg.machines : AdbgMachine; import adbg.utils.bit; import core.stdc.stdlib : calloc; /// Smallest Mach-O size. // https://codegolf.stackexchange.com/a/154685 private enum MINIMUM_SIZE = 0x1000; // Due to paging private enum LIMIT_FAT_ARCH = 200; private enum LIMIT_COMMANDS = 2000; enum MACHO_MAGIC = 0xFEEDFACEu; /// Mach-O BE magic enum MACHO_MAGIC64 = 0xFEEDFACFu; /// Mach-O BE x64 magic enum MACHO_CIGAM = 0xCEFAEDFEu; /// Mach-O LE magic enum MACHO_CIGAM64 = 0xCFFAEDFEu; /// Mach-O LE x64 magic enum MACHO_FATMAGIC = 0xCAFEBABEu; /// Mach-O FAT BE magic enum MACHO_FATCIGAM = 0xBEBAFECAu; /// Mach-O FAT LE magic // 64-bit version just adds a 32-bit reserved field at the end. struct macho_header { uint magic; /// Mach magic number identifier uint cputype; /// Cpu specifier uint subtype; /// Machine specifier uint filetype; /// Type of file uint ncmds; /// Number of load commands uint sizeofcmds; /// The size of all the load commands uint flags; /// Flags } struct macho_fatmach_header { uint magic; /// Magic uint nfat_arch; /// Number of architectures (structs) in binary } struct macho_fat_arch { uint cputype; /// uint subtype; /// uint offset; /// File offset to first segment or command? uint size; /// Segments size? uint alignment; /// Page alignment? } struct macho_load_command { uint cmd; /// type of load command uint cmdsize; /// total size of command in bytes } alias int vm_prot_t; struct macho_segment_command { /* for 32-bit architectures */ uint cmd; /// LC_SEGMENT uint cmdsize; /// includes sizeof section structs char[16] segname; /// segment name uint vmaddr; /// memory address of this segment uint vmsize; /// memory size of this segment uint fileoff; /// file offset of this segment uint filesize; /// amount to map from the file vm_prot_t maxprot; /// maximum VM protection vm_prot_t initprot; /// initial VM protection uint nsects; /// number of sections in segment uint flags; /// flags } struct macho_segment_command_64 { /* for 64-bit architectures */ uint cmd; /// LC_SEGMENT_64 uint cmdsize; /// includes sizeof section_64 structs char[16] segname; /// segment name ulong vmaddr; /// memory address of this segment ulong vmsize; /// memory size of this segment ulong fileoff; /// file offset of this segment ulong filesize; /// amount to map from the file vm_prot_t maxprot; /// maximum VM protection vm_prot_t initprot; /// initial VM protection uint nsects; /// number of sections in segment uint flags; /// flags } alias cpu_type_t = int; enum { MACHO_CPUTYPE_ANY = -1, /// Used as a bitmask to mark cputype as 64-bit MACHO_CPUTYPE_ABI64 = 0x100_0000, MACHO_CPUTYPE_VAX = 1, MACHO_CPUTYPE_ROMP = 2, MACHO_CPUTYPE_NS32032 = 4, MACHO_CPUTYPE_NS32332 = 5, MACHO_CPUTYPE_MC680x0 = 6, MACHO_CPUTYPE_I386 = 7, MACHO_CPUTYPE_X86_64 = MACHO_CPUTYPE_I386 | MACHO_CPUTYPE_ABI64, MACHO_CPUTYPE_MIPS = 8, MACHO_CPUTYPE_NS32532 = 9, MACHO_CPUTYPE_HPPA = 11, MACHO_CPUTYPE_ARM = 12, MACHO_CPUTYPE_ARM64 = MACHO_CPUTYPE_ARM | MACHO_CPUTYPE_ABI64, MACHO_CPUTYPE_MC88000 = 13, MACHO_CPUTYPE_SPARC = 14, MACHO_CPUTYPE_I860 = 15, // big-endian MACHO_CPUTYPE_I860_LITTLE = 16, // little-endian MACHO_CPUTYPE_RS6000 = 17, MACHO_CPUTYPE_MC98000 = 18, MACHO_CPUTYPE_POWERPC = 18, MACHO_CPUTYPE_POWERPC64 = MACHO_CPUTYPE_POWERPC | MACHO_CPUTYPE_ABI64, MACHO_CPUTYPE_VEO = 255 } // ============================= // cpu_subtype_t - CPU Subtypes, int // ============================= // VAX subtypes enum { // SUBTYPE_VAX MACHO_SUBTYPE_VAX_ALL = 0, MACHO_SUBTYPE_VAX780 = 1, MACHO_SUBTYPE_VAX785 = 2, MACHO_SUBTYPE_VAX750 = 3, MACHO_SUBTYPE_VAX730 = 4, MACHO_SUBTYPE_UVAXI = 5, MACHO_SUBTYPE_UVAXII = 6, MACHO_SUBTYPE_VAX8200 = 7, MACHO_SUBTYPE_VAX8500 = 8, MACHO_SUBTYPE_VAX8600 = 9, MACHO_SUBTYPE_VAX8650 = 10, MACHO_SUBTYPE_VAX8800 = 11, MACHO_SUBTYPE_UVAXIII = 12 } // ROMP subtypes enum { // SUBTYPE_ROMP MACHO_SUBTYPE_RT_ALL = 0, MACHO_SUBTYPE_RT_PC = 1, MACHO_SUBTYPE_RT_APC = 2, MACHO_SUBTYPE_RT_135 = 3 } // 32032/32332/32532 subtypes enum { // SUBTYPE_32032 MACHO_SUBTYPE_MMAX_ALL = 0, MACHO_SUBTYPE_MMAX_DPC = 1, /* 032 CPU */ MACHO_SUBTYPE_SQT = 2, MACHO_SUBTYPE_MMAX_APC_FPU = 3, /* 32081 FPU */ MACHO_SUBTYPE_MMAX_APC_FPA = 4, /* Weitek FPA */ MACHO_SUBTYPE_MMAX_XPC = 5, /* 532 CPU */ } private template SUBTYPE_INTEL(short f, short m) { enum SUBTYPE_INTEL = f + (m << 4); } // x86 subtypes enum { // SUBTYPE_I386 MACHO_SUBTYPE_I386_ALL = 3, MACHO_SUBTYPE_X86_64_ALL = MACHO_SUBTYPE_I386_ALL, MACHO_SUBTYPE_i386 = 3, MACHO_SUBTYPE_i486 = 4, MACHO_SUBTYPE_i486SX = 4 + 128, // "4 + 128" MACHO_SUBTYPE_i586 = 5, MACHO_SUBTYPE_PENT = SUBTYPE_INTEL!(5, 0), MACHO_SUBTYPE_PENPRO = SUBTYPE_INTEL!(6, 1), MACHO_SUBTYPE_PENTII_M3 = SUBTYPE_INTEL!(6, 3), MACHO_SUBTYPE_PENTII_M5 = SUBTYPE_INTEL!(6, 5), MACHO_SUBTYPE_PENTIUM_4 = SUBTYPE_INTEL!(10, 0), } // MIPS subty enum { // SUBTYPE_MIPS MACHO_SUBTYPE_MIPS_ALL = 0, MACHO_SUBTYPE_R2300 = 1, MACHO_SUBTYPE_R2600 = 2, MACHO_SUBTYPE_R2800 = 3, MACHO_SUBTYPE_R2800a = 4 } // 680x0 subtypes (m68k) enum { // SUBTYPE_680x0 MACHO_SUBTYPE_MC680x0_ALL = 1, MACHO_SUBTYPE_MC68030 = 1, MACHO_SUBTYPE_MC68040 = 2, MACHO_SUBTYPE_MC68030_ONLY = 3, } // HPPA subtypes enum { // SUBTYPE_HPPA MACHO_SUBTYPE_HPPA7100 = 0, MACHO_SUBTYPE_HPPA7100LC = 1, MACHO_SUBTYPE_HPPA_ALL = 0, } // Acorn subtypes enum { // SUBTYPE_ARM MACHO_SUBTYPE_ACORN_ALL = 0, MACHO_SUBTYPE_A500_ARCH = 1, MACHO_SUBTYPE_A500 = 2, MACHO_SUBTYPE_A440 = 3, MACHO_SUBTYPE_M4 = 4, MACHO_SUBTYPE_V4T = 5, MACHO_SUBTYPE_V6 = 6, MACHO_SUBTYPE_V5TEJ = 7, MACHO_SUBTYPE_XSCALE = 8, MACHO_SUBTYPE_V7 = 9, MACHO_SUBTYPE_V8 = 13, } // MC88000 subtypes enum { // SUBTYPE_MC88000 MACHO_SUBTYPE_MC88000_ALL = 0, MACHO_SUBTYPE_MMAX_JPC = 1, MACHO_SUBTYPE_MC88100 = 1, MACHO_SUBTYPE_MC88110 = 2, } // MC98000 (PowerPC) subtypes enum { // SUBTYPE_MC98000 MACHO_SUBTYPE_MC98000_ALL = 0, MACHO_SUBTYPE_MC98601 = 1, } // I860 subtypes enum { // SUBTYPE_I860 MACHO_SUBTYPE_I860_ALL = 0, MACHO_SUBTYPE_I860 = 1, } // I860_LITTLE subtypes enum { // SUBTYPE_I860_LITTLE MACHO_SUBTYPE_I860_LITTLE_ALL = 0, MACHO_SUBTYPE_I860_LITTLE = 1 } // RS6000 subtypes enum { // SUBTYPE_RS6000 MACHO_SUBTYPE_RS6000_ALL = 0, MACHO_SUBTYPE_RS6000 = 1, } // Sun4 subtypes (port done at CMU (?)) enum { // SUBTYPE_Sun4 MACHO_SUBTYPE_SUN4_ALL = 0, MACHO_SUBTYPE_SUN4_260 = 1, MACHO_SUBTYPE_SUN4_110 = 2, } // SPARC subtypes /*enum { // SUBTYPE_SPARC ALL = 0 };*/ // PowerPC subtypes enum { // SUBTYPE_PowerPC MACHO_SUBTYPE_POWERPC_ALL = 0, MACHO_SUBTYPE_POWERPC_601 = 1, MACHO_SUBTYPE_POWERPC_602 = 2, MACHO_SUBTYPE_POWERPC_603 = 3, MACHO_SUBTYPE_POWERPC_603e = 4, MACHO_SUBTYPE_POWERPC_603ev = 5, MACHO_SUBTYPE_POWERPC_604 = 6, MACHO_SUBTYPE_POWERPC_604e = 7, MACHO_SUBTYPE_POWERPC_620 = 8, MACHO_SUBTYPE_POWERPC_750 = 9, MACHO_SUBTYPE_POWERPC_7400 = 10, MACHO_SUBTYPE_POWERPC_7450 = 11, MACHO_SUBTYPE_POWERPC_970 = 100, } // VEO subtypes enum { // SUBTYPE_VEO MACHO_SUBTYPE_VEO_1 = 1, MACHO_SUBTYPE_VEO_2 = 2, MACHO_SUBTYPE_VEO_3 = 3, MACHO_SUBTYPE_VEO_4 = 4, //VEO_ALL = VEO_2, } // ======================== /// File types // ======================== alias macho_filetype_t = int; enum { MACHO_FILETYPE_UNKNOWN = 0, MACHO_FILETYPE_OBJECT = 0x1, MACHO_FILETYPE_EXECUTE = 0x2, MACHO_FILETYPE_FVMLIB = 0x3, MACHO_FILETYPE_CORE = 0x4, MACHO_FILETYPE_PRELOAD = 0x5, MACHO_FILETYPE_DYLIB = 0x6, MACHO_FILETYPE_DYLINKER = 0x7, MACHO_FILETYPE_BUNDLE = 0x8, MACHO_FILETYPE_DYLIB_STUB = 0x9, MACHO_FILETYPE_DSYM = 0xA, MACHO_FILETYPE_KEXT_BUNDLE = 0xB, } // Flags alias macho_flag_t = int; enum { MACHO_FLAG_NOUNDEFS = 0x00000001, MACHO_FLAG_INCRLINK = 0x00000002, MACHO_FLAG_DYLDLINK = 0x00000004, MACHO_FLAG_BINDATLOAD = 0x00000008, MACHO_FLAG_PREBOUND = 0x00000010, MACHO_FLAG_SPLIT_SEGS = 0x00000020, MACHO_FLAG_LAZY_INIT = 0x00000040, MACHO_FLAG_TWOLEVEL = 0x00000080, MACHO_FLAG_FORCE_FLAT = 0x00000100, MACHO_FLAG_NOMULTIDEFS = 0x00000200, MACHO_FLAG_NOFIXPREBINDING = 0x00000400, MACHO_FLAG_PREBINDABLE = 0x00000800, MACHO_FLAG_ALLMODSBOUND = 0x00001000, MACHO_FLAG_SUBSECTIONS_VIA_SYMBOLS = 0x00002000, MACHO_FLAG_CANONICAL = 0x00004000, MACHO_FLAG_WEAK_DEFINES = 0x00008000, MACHO_FLAG_BINDS_TO_WEAK = 0x00010000, MACHO_FLAG_ALLOW_STACK_EXECUTION = 0x00020000, MACHO_FLAG_ROOT_SAFE = 0x00040000, MACHO_FLAG_SETUID_SAFE = 0x00080000, MACHO_FLAG_NO_REEXPORTED_DYLIBS = 0x00100000, MACHO_FLAG_PIE = 0x00200000, MACHO_FLAG_DEAD_STRIPPABLE_DYLIB = 0x00400000, MACHO_FLAG_HAS_TLV_DESCRIPTORS = 0x00800000, MACHO_FLAG_NO_HEAP_EXECUTION = 0x01000000, MACHO_FLAG_APP_EXTENSION_SAFE = 0x02000000 } // Commands enum { MACHO_LC_REQ_DYLD = 0x80000000, /// Requires dynamic linker MACHO_LC_SEGMENT = 0x1, /// Segment of this file to be mapped MACHO_LC_SYMTAB = 0x2, /// Link-edit stab symbol table info MACHO_LC_SYMSEG = 0x3, /// Link-edit gdb symbol table info (obsolete) MACHO_LC_THREAD = 0x4, /// Thread MACHO_LC_UNIXTHREAD = 0x5, /// Unix thread (includes a stack) MACHO_LC_LOADFVMLIB = 0x6, /// Load a specified fixed VM shared library MACHO_LC_IDFVMLIB = 0x7, /// Fixed VM shared library identification MACHO_LC_IDENT = 0x8, /// Object identification info (obsolete) MACHO_LC_FVMFILE = 0x9, /// Fixed VM file inclusion (internal use) MACHO_LC_PREPAGE = 0xa, /// Prepage command (internal use) MACHO_LC_DYSYMTAB = 0xb, /// Dynamic link-edit symbol table info MACHO_LC_LOAD_DYLIB = 0xc, /// Load a dynamically linked shared library MACHO_LC_ID_DYLIB = 0xd, /// Dynamically linked shared lib ident MACHO_LC_LOAD_DYLINKER = 0xe, /// Load a dynamic linker MACHO_LC_ID_DYLINKER = 0xf, /// Dynamic linker identification MACHO_LC_PREBOUND_DYLIB = 0x10, /// Modules prebound for a dynamically linked shared library MACHO_LC_ROUTINES = 0x11, /// Image routines MACHO_LC_SUB_FRAMEWORK = 0x12, /// Sub framework MACHO_LC_SUB_UMBRELLA = 0x13, /// Sub umbrella MACHO_LC_SUB_CLIENT = 0x14, /// Sub client MACHO_LC_SUB_LIBRARY = 0x15, /// Sub library MACHO_LC_TWOLEVEL_HINTS = 0x16, /// Two-level namespace lookup hints MACHO_LC_PREBIND_CKSUM = 0x17, /// Prebind checksum MACHO_LC_SEGMENT_64 = 0x19, /// 64-bit segment of this file to be mapped MACHO_LC_ROUTINES_64 = 0x1a, /// 64-bit image routines MACHO_LC_UUID = 0x1b, /// The uuid MACHO_LC_RPATH = 0x1c | MACHO_LC_REQ_DYLD, /// Runpath additions MACHO_LC_CODE_SIGNATURE = 0x1d, /// Local of code signature MACHO_LC_SEGMENT_SPLIT_INFO = 0x1e, /// Local of info to split segments MACHO_LC_REEXPORT_DYLIB = 0x1f | MACHO_LC_REQ_DYLD, /// Load and re-export dylib MACHO_LC_LAZY_LOAD_DYLIB = 0x20, /// Delay load of dylib until first use MACHO_LC_ENCRYPTION_INFO = 0x21, /// Encrypted segment information MACHO_LC_DYLD_INFO = 0x22, /// Compressed dyld information MACHO_LC_DYLD_INFO_ONLY = 0x22 | MACHO_LC_REQ_DYLD, /// Compressed dyld information only MACHO_LC_LOAD_UPWARD_DYLIB = 0x23 | MACHO_LC_REQ_DYLD, /// Load upward dylib MACHO_LC_VERSION_MIN_MACOSX = 0x24, /// Build for MacOSX min OS version MACHO_LC_VERSION_MIN_IPHONEOS = 0x25, /// Build for iPhoneOS min OS version MACHO_LC_FUNCTION_STARTS = 0x26, /// Compressed table of function start addresses MACHO_LC_DYLD_ENVIRONMENT = 0x27, /// String for dyld to treat like environment variable MACHO_LC_MAIN = 0x28 | MACHO_LC_REQ_DYLD, /// Replacement for LC_UNIXTHREAD MACHO_LC_DATA_IN_CODE = 0x29, /// Table of non-instructions in __text MACHO_LC_SOURCE_VERSION = 0x2a, /// Source version used to build binary MACHO_LC_DYLIB_CODE_SIGN_DRS = 0x2b, /// Code signing DRs copied from linked dylibs MACHO_LC_ENCRYPTION_INFO_64 = 0x2c, /// 64-bit encrypted segment information MACHO_LC_LINKER_OPTION = 0x2D, /// linker options in MH_OBJECT files MACHO_LC_LINKER_OPTIMIZATION_HINT = 0x2e, /// Optimization hints in MH_OBJECT files MACHO_LC_VERSION_MIN_WATCHOS = 0x30, /// Build for Watch min OS version } int adbg_object_macho_load(adbg_object_t *o) { if (o.file_size < MINIMUM_SIZE) return adbg_oops(AdbgError.objectTooSmall); o.format = AdbgObject.macho; o.i.macho.header = cast(macho_header*)o.buffer; // NOTE: Internals are set to zero. // Unless I change that, and this snippet leads to a crash. with (o.i) switch (macho.header.magic) { case MACHO_MAGIC: // 32-bit LE break; case MACHO_MAGIC64: // 64-bit LE macho.is64 = true; break; case MACHO_CIGAM: // 32-bit BE o.p.reversed = true; break; case MACHO_CIGAM64: // 64-bit BE o.p.reversed = true; macho.is64 = true; break; case MACHO_FATMAGIC: // Fat LE macho.fat = true; break; case MACHO_FATCIGAM: // Fat BE macho.fat = true; o.p.reversed = true; break; default: return adbg_oops(AdbgError.assertion); } version (Trace) trace("64=%d reversed=%d fat=%d", o.i.macho.is64, o.p.reversed, o.i.macho.fat); with (o.i) if (o.p.reversed) { if (macho.fat) { macho.fat_header.nfat_arch = adbg_bswap32(macho.fat_header.nfat_arch); macho.fat_arch.cputype = adbg_bswap32(macho.fat_arch.cputype); macho.fat_arch.subtype = adbg_bswap32(macho.fat_arch.subtype); macho.fat_arch.offset = adbg_bswap32(macho.fat_arch.offset); macho.fat_arch.size = adbg_bswap32(macho.fat_arch.size); macho.fat_arch.alignment = adbg_bswap32(macho.fat_arch.alignment); } else { macho.header.cputype = adbg_bswap32(macho.header.cputype); macho.header.subtype = adbg_bswap32(macho.header.subtype); macho.header.filetype = adbg_bswap32(macho.header.filetype); macho.header.ncmds = adbg_bswap32(macho.header.ncmds); macho.header.sizeofcmds = adbg_bswap32(macho.header.sizeofcmds); macho.header.flags = adbg_bswap32(macho.header.flags); } } with (o.i) if (macho.fat) { macho.fat_arch = cast(macho_fat_arch*)(o.buffer + macho_fatmach_header.sizeof); macho.reversed_fat_arch = cast(bool*)calloc(macho.fat_header.nfat_arch, bool.sizeof); if (macho.reversed_fat_arch == null) return adbg_oops(AdbgError.crt); } else if (macho.header.ncmds) { macho.reversed_commands = cast(bool*)calloc(macho.header.ncmds, bool.sizeof); if (macho.reversed_commands == null) return adbg_oops(AdbgError.crt); size_t cl = macho.is64 ? macho_header.sizeof + uint.sizeof : macho_header.sizeof; version (Trace) trace("cl=%zx 64=%d", cl, macho.is64); macho.commands = cast(macho_load_command*)(o.buffer + cl); } return 0; } //TODO: Consider adbg_object_macho_isfat macho_header* adbg_object_macho_header(adbg_object_t *o) { if (o == null) { adbg_oops(AdbgError.invalidArgument); return null; } // NOTE: pre-swapped return o.i.macho.header; } macho_fatmach_header* adbg_object_macho_header_fat(adbg_object_t *o) { if (o == null) { adbg_oops(AdbgError.invalidArgument); return null; } // NOTE: pre-swapped return o.i.macho.fat_header; } macho_fat_arch* adbg_object_macho_fat_arch(adbg_object_t *o, size_t index) { if (o == null) { adbg_oops(AdbgError.invalidArgument); return null; } if (o.i.macho.fat_header == null) { adbg_oops(AdbgError.uninitiated); return null; // not loaded } if (o.i.macho.fat == false) { adbg_oops(AdbgError.unavailable); return null; } if (index >= LIMIT_FAT_ARCH) { adbg_oops(AdbgError.indexBounds); return null; } if (index >= o.i.macho.fat_header.nfat_arch) { adbg_oops(AdbgError.indexBounds); return null; } macho_fat_arch* fat_arch = &o.i.macho.fat_arch[index]; if (o.p.reversed && o.i.macho.reversed_fat_arch[index] == false) { fat_arch.cputype = adbg_bswap32(fat_arch.cputype); fat_arch.subtype = adbg_bswap32(fat_arch.subtype); fat_arch.offset = adbg_bswap32(fat_arch.offset); fat_arch.size = adbg_bswap32(fat_arch.size); fat_arch.alignment = adbg_bswap32(fat_arch.alignment); o.i.macho.reversed_fat_arch[index] = true; } return fat_arch; } // Load commands have a type and size. // Size includes type (4 bytes), size (4 bytes), and anything that follows it // until next command. macho_load_command* adbg_object_macho_load_command(adbg_object_t *o, size_t index) { if (o == null) { adbg_oops(AdbgError.invalidArgument); return null; } if (o.i.macho.header == null) { adbg_oops(AdbgError.uninitiated); return null; // not loaded } if (o.i.macho.fat) { adbg_oops(AdbgError.unavailable); return null; } if (index >= LIMIT_COMMANDS) { adbg_oops(AdbgError.indexBounds); return null; } if (index >= o.i.macho.header.ncmds) { adbg_oops(AdbgError.indexBounds); return null; } //TODO: Consider "caching" positions (calloc array) for faster lookup macho_load_command* command = void; size_t next; for (size_t i; i <= index; ++i) { command = cast(macho_load_command*)(cast(void*)o.i.macho.commands + next); if (o.p.reversed && o.i.macho.reversed_commands[i] == false) { version (Trace) trace("Reversing %u", cast(uint)i); command.cmd = adbg_bswap32(command.cmd); command.cmdsize = adbg_bswap32(command.cmdsize); o.i.macho.reversed_commands[i] = true; } version (Trace) trace("command cmd=%x size=0x%x", command.cmd, command.cmdsize); next += command.cmdsize; if (next >= o.file_size) return null; } return command; } const(char) *adbg_object_macho_magic_string(uint signature) { switch (signature) { case MACHO_MAGIC: return "MACHO_MAGIC"; case MACHO_MAGIC64: return "MACHO_MAGIC_64"; case MACHO_CIGAM: return "MACHO_CIGAM"; case MACHO_CIGAM64: return "MACHO_CIGAM_64"; case MACHO_FATMAGIC: return "MACHO_FAT_MAGIC"; case MACHO_FATCIGAM: return "MACHO_FAT_CIGAM"; default: return "?"; } } const(char) *adbg_object_macho_filetype_string(uint type) { // NOTE: FAT files have no filetypes switch (type) { case MACHO_FILETYPE_OBJECT: return "Object"; case MACHO_FILETYPE_EXECUTE: return "Executable"; case MACHO_FILETYPE_FVMLIB: return "Fixed VM Library"; case MACHO_FILETYPE_CORE: return "Core"; case MACHO_FILETYPE_PRELOAD: return "Preload"; case MACHO_FILETYPE_DYLIB: return "Dynamic library"; case MACHO_FILETYPE_DYLINKER: return "Dynamic linker"; case MACHO_FILETYPE_BUNDLE: return "Bundle"; case MACHO_FILETYPE_DYLIB_STUB: return "Dynamic library stub"; case MACHO_FILETYPE_DSYM: return "Companion file (debug)"; case MACHO_FILETYPE_KEXT_BUNDLE: return "Kext bundle"; default: return "?"; } } AdbgMachine adbg_object_macho_machine(uint type) { switch (type) { case MACHO_CPUTYPE_VAX: return AdbgMachine.vax; case MACHO_CPUTYPE_ROMP: return AdbgMachine.romp; case MACHO_CPUTYPE_NS32032: case MACHO_CPUTYPE_NS32332: case MACHO_CPUTYPE_NS32532: return AdbgMachine.ns32k; case MACHO_CPUTYPE_I386: return AdbgMachine.i386; case MACHO_CPUTYPE_X86_64: return AdbgMachine.amd64; case MACHO_CPUTYPE_MIPS: return AdbgMachine.mips; case MACHO_CPUTYPE_HPPA: return AdbgMachine.parisc; case MACHO_CPUTYPE_MC680x0: return AdbgMachine.m68k; case MACHO_CPUTYPE_MC88000: return AdbgMachine.m88k; case MACHO_CPUTYPE_ARM: return AdbgMachine.arm; case MACHO_CPUTYPE_ARM64: return AdbgMachine.aarch64; case MACHO_CPUTYPE_SPARC: return AdbgMachine.sparc; case MACHO_CPUTYPE_I860_LITTLE: case MACHO_CPUTYPE_I860: return AdbgMachine.i860; case MACHO_CPUTYPE_RS6000: return AdbgMachine.rs6000; case MACHO_CPUTYPE_POWERPC64: return AdbgMachine.ppc64; case MACHO_CPUTYPE_POWERPC: return AdbgMachine.ppc; case MACHO_CPUTYPE_VEO: return AdbgMachine.veo; default: return AdbgMachine.unknown; } } const(char) *adbg_object_macho_cputype_string(uint type) { switch (type) { case MACHO_CPUTYPE_VAX: return "VAX"; case MACHO_CPUTYPE_ROMP: return "ROMP"; case MACHO_CPUTYPE_NS32032: return "NS32032"; case MACHO_CPUTYPE_NS32332: return "NS32332"; case MACHO_CPUTYPE_NS32532: return "NS32532"; case MACHO_CPUTYPE_I386: return "x86"; case MACHO_CPUTYPE_X86_64: return "x86-64"; case MACHO_CPUTYPE_MIPS: return "MIPS"; case MACHO_CPUTYPE_MC680x0: return "MC68000"; case MACHO_CPUTYPE_HPPA: return "HPPA"; case MACHO_CPUTYPE_ARM: return "ARM"; case MACHO_CPUTYPE_ARM64: return "ARM64"; case MACHO_CPUTYPE_MC88000: return "MC88000"; case MACHO_CPUTYPE_I860, MACHO_CPUTYPE_I860_LITTLE: return "i860"; case MACHO_CPUTYPE_RS6000: return "RS6000"; case MACHO_CPUTYPE_POWERPC64: return "PowerPC64"; case MACHO_CPUTYPE_POWERPC: return "PowerPC"; case MACHO_CPUTYPE_VEO: return "VEO"; default: return "?"; } } const(char) *adbg_object_macho_subtype_string(uint type, uint subtype) { switch (type) { case MACHO_CPUTYPE_VAX: switch (subtype) { case MACHO_SUBTYPE_VAX780: return "VAX780"; case MACHO_SUBTYPE_VAX785: return "VAX785"; case MACHO_SUBTYPE_VAX750: return "VAX750"; case MACHO_SUBTYPE_VAX730: return "VAX730"; case MACHO_SUBTYPE_UVAXI: return "UVAXI"; case MACHO_SUBTYPE_UVAXII: return "UVAXII"; case MACHO_SUBTYPE_VAX8200: return "VAX8200"; case MACHO_SUBTYPE_VAX8500: return "VAX8500"; case MACHO_SUBTYPE_VAX8600: return "VAX8600"; case MACHO_SUBTYPE_VAX8650: return "VAX8650"; case MACHO_SUBTYPE_VAX8800: return "VAX8800"; case MACHO_SUBTYPE_UVAXIII: return "UVAXIII"; default: return "VAX"; } case MACHO_CPUTYPE_ROMP: switch (subtype) { case MACHO_SUBTYPE_RT_PC: return "ROMP RT_PC"; case MACHO_SUBTYPE_RT_APC: return "ROMP RT_APC"; case MACHO_SUBTYPE_RT_135: return "ROMP RT_135"; default: return "ROMP"; } case MACHO_CPUTYPE_NS32032: return "NS32032"; case MACHO_CPUTYPE_NS32332: return "NS32332"; case MACHO_CPUTYPE_NS32532: return "NS32532"; case MACHO_CPUTYPE_I386: switch (subtype) { case MACHO_SUBTYPE_i386: return "i386"; case MACHO_SUBTYPE_i486: return "i486"; case MACHO_SUBTYPE_i486SX: return "i486SX"; case MACHO_SUBTYPE_PENT: return "Pentium"; case MACHO_SUBTYPE_PENPRO: return "Pentium Pro"; case MACHO_SUBTYPE_PENTII_M3: return "Pentium III (M3)"; case MACHO_SUBTYPE_PENTII_M5: return "Pentium III (M5)"; case MACHO_SUBTYPE_PENTIUM_4: return "Pentium 4"; default: return "x86"; } case MACHO_CPUTYPE_X86_64: return "x86-64"; case MACHO_CPUTYPE_MIPS: switch (subtype) { case MACHO_SUBTYPE_R2300: return "MIPS R2300"; case MACHO_SUBTYPE_R2600: return "MIPS R2600"; case MACHO_SUBTYPE_R2800: return "MIPS R2800"; case MACHO_SUBTYPE_R2800a: return "MIPS R2800a"; default: return "MIPS"; } case MACHO_CPUTYPE_MC680x0: switch (subtype) { case MACHO_SUBTYPE_MC68030: return "MC68030"; case MACHO_SUBTYPE_MC68040: return "MC68040"; case MACHO_SUBTYPE_MC68030_ONLY: return "MC68030-only"; default: return "MC68000"; } case MACHO_CPUTYPE_HPPA: switch (subtype) { case MACHO_SUBTYPE_HPPA7100LC: return "HPPA7100LC"; default: return "HPPA7100"; } case MACHO_CPUTYPE_ARM: switch (subtype) { case MACHO_SUBTYPE_A500_ARCH: return "ARM A500"; case MACHO_SUBTYPE_A500: return "ARM A500"; case MACHO_SUBTYPE_A440: return "ARM A440"; case MACHO_SUBTYPE_M4: return "ARM M4"; case MACHO_SUBTYPE_V4T: return "ARM V4T"; case MACHO_SUBTYPE_V6: return "ARM V6"; case MACHO_SUBTYPE_V5TEJ: return "ARM V5TEJ"; case MACHO_SUBTYPE_XSCALE: return "ARM XSCALE"; case MACHO_SUBTYPE_V7: return "ARM V7"; case MACHO_SUBTYPE_V8: return "ARM V8"; default: return "ARM"; } case MACHO_CPUTYPE_ARM64: return "ARM64 V8"; case MACHO_CPUTYPE_MC88000: switch (subtype) { case MACHO_SUBTYPE_MC88100: return "MC88100"; case MACHO_SUBTYPE_MC88110: return "MC88110"; default: return "MC88000"; } case MACHO_CPUTYPE_I860: return "i860"; case MACHO_CPUTYPE_I860_LITTLE: return "i860 (little-endian)"; case MACHO_CPUTYPE_RS6000: return "IBM RS6000"; case MACHO_CPUTYPE_POWERPC64: switch (subtype) { case MACHO_SUBTYPE_POWERPC_601: return "PowerPC64 601"; case MACHO_SUBTYPE_POWERPC_602: return "PowerPC64 602"; case MACHO_SUBTYPE_POWERPC_603: return "PowerPC64 603"; case MACHO_SUBTYPE_POWERPC_603e: return "PowerPC64 603e"; case MACHO_SUBTYPE_POWERPC_603ev: return "PowerPC64 603ev"; case MACHO_SUBTYPE_POWERPC_604: return "PowerPC64 604"; case MACHO_SUBTYPE_POWERPC_604e: return "PowerPC64 604e"; case MACHO_SUBTYPE_POWERPC_620: return "PowerPC64 620"; case MACHO_SUBTYPE_POWERPC_750: return "PowerPC64 750"; case MACHO_SUBTYPE_POWERPC_7400: return "PowerPC64 7400"; case MACHO_SUBTYPE_POWERPC_7450: return "PowerPC64 7450"; case MACHO_SUBTYPE_POWERPC_970: return "PowerPC64 970"; default: return "PowerPC64"; } case MACHO_CPUTYPE_POWERPC: switch (subtype) { case MACHO_SUBTYPE_POWERPC_601: return "PowerPC 601"; case MACHO_SUBTYPE_POWERPC_602: return "PowerPC 602"; case MACHO_SUBTYPE_POWERPC_603: return "PowerPC 603"; case MACHO_SUBTYPE_POWERPC_603e: return "PowerPC 603e"; case MACHO_SUBTYPE_POWERPC_603ev: return "PowerPC 603ev"; case MACHO_SUBTYPE_POWERPC_604: return "PowerPC 604"; case MACHO_SUBTYPE_POWERPC_604e: return "PowerPC 604e"; case MACHO_SUBTYPE_POWERPC_620: return "PowerPC 620"; case MACHO_SUBTYPE_POWERPC_750: return "PowerPC 750"; case MACHO_SUBTYPE_POWERPC_7400: return "PowerPC 7400"; case MACHO_SUBTYPE_POWERPC_7450: return "PowerPC 7450"; case MACHO_SUBTYPE_POWERPC_970: return "PowerPC 970"; default: return "PowerPC"; } case MACHO_CPUTYPE_VEO: return "VEO"; default: return "?"; } } const(char)* adbg_object_macho_command_string(uint command) { switch (command) { case MACHO_LC_REQ_DYLD: return "LC_REQ_DYLD"; case MACHO_LC_SEGMENT: return "LC_SEGMENT"; case MACHO_LC_SYMTAB: return "LC_SYMTAB"; case MACHO_LC_SYMSEG: return "LC_SYMSEG"; case MACHO_LC_THREAD: return "LC_THREAD"; case MACHO_LC_UNIXTHREAD: return "LC_UNIXTHREAD"; case MACHO_LC_LOADFVMLIB: return "LC_LOADFVMLIB"; case MACHO_LC_IDFVMLIB: return "LC_IDFVMLIB"; case MACHO_LC_IDENT: return "LC_IDENT"; case MACHO_LC_FVMFILE: return "LC_FVMFILE"; case MACHO_LC_PREPAGE: return "LC_PREPAGE"; case MACHO_LC_DYSYMTAB: return "LC_DYSYMTAB"; case MACHO_LC_LOAD_DYLIB: return "LC_LOAD_DYLIB"; case MACHO_LC_ID_DYLIB: return "LC_ID_DYLIB"; case MACHO_LC_LOAD_DYLINKER: return "LC_LOAD_DYLINKER"; case MACHO_LC_ID_DYLINKER: return "LC_ID_DYLINKER"; case MACHO_LC_PREBOUND_DYLIB: return "LC_PREBOUND_DYLIB"; case MACHO_LC_ROUTINES: return "LC_ROUTINES"; case MACHO_LC_SUB_FRAMEWORK: return "LC_SUB_FRAMEWORK"; case MACHO_LC_SUB_UMBRELLA: return "LC_SUB_UMBRELLA"; case MACHO_LC_SUB_CLIENT: return "LC_SUB_CLIENT"; case MACHO_LC_SUB_LIBRARY: return "LC_SUB_LIBRARY"; case MACHO_LC_TWOLEVEL_HINTS: return "LC_TWOLEVEL_HINTS"; case MACHO_LC_PREBIND_CKSUM: return "LC_PREBIND_CKSUM"; case MACHO_LC_SEGMENT_64: return "LC_SEGMENT_64"; case MACHO_LC_ROUTINES_64: return "LC_ROUTINES_64"; case MACHO_LC_UUID: return "LC_UUID"; case MACHO_LC_RPATH: return "LC_RPATH"; case MACHO_LC_CODE_SIGNATURE: return "LC_CODE_SIGNATURE"; case MACHO_LC_SEGMENT_SPLIT_INFO: return "LC_SEGMENT_SPLIT_INFO"; case MACHO_LC_REEXPORT_DYLIB: return "LC_REEXPORT_DYLIB"; case MACHO_LC_LAZY_LOAD_DYLIB: return "LC_LAZY_LOAD_DYLIB"; case MACHO_LC_ENCRYPTION_INFO: return "LC_ENCRYPTION_INFO"; case MACHO_LC_DYLD_INFO: return "LC_DYLD_INFO"; case MACHO_LC_DYLD_INFO_ONLY: return "LC_DYLD_INFO_ONLY"; case MACHO_LC_LOAD_UPWARD_DYLIB: return "LC_LOAD_UPWARD_DYLIB"; case MACHO_LC_VERSION_MIN_MACOSX: return "LC_VERSION_MIN_MACOSX"; case MACHO_LC_VERSION_MIN_IPHONEOS: return "LC_VERSION_MIN_IPHONEOS"; case MACHO_LC_FUNCTION_STARTS: return "LC_FUNCTION_STARTS"; case MACHO_LC_DYLD_ENVIRONMENT: return "LC_DYLD_ENVIRONMENT"; case MACHO_LC_MAIN: return "LC_MAIN"; case MACHO_LC_DATA_IN_CODE: return "LC_DATA_IN_CODE"; case MACHO_LC_SOURCE_VERSION: return "LC_SOURCE_VERSION"; case MACHO_LC_DYLIB_CODE_SIGN_DRS: return "LC_DYLIB_CODE_SIGN_DRS"; case MACHO_LC_ENCRYPTION_INFO_64: return "LC_ENCRYPTION_INFO_64"; case MACHO_LC_LINKER_OPTION: return "LC_LINKER_OPTION"; case MACHO_LC_LINKER_OPTIMIZATION_HINT: return "LC_LINKER_OPTIMIZATION_HINT"; case MACHO_LC_VERSION_MIN_WATCHOS: return "LC_VERSION_MIN_WATCHOS"; default: return "?"; } }