binfmt_macho.h
1 /*- 2 * Copyright (c) 2024 Keve Müller <kevemueller@users.github.com> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7 #ifndef _PKG_BINFMT_MACHO_H 8 #define _PKG_BINFMT_MACHO_H 9 10 #include <sys/types.h> 11 12 #include <stdbool.h> 13 #include <stdint.h> 14 15 /**** Magic numbers & constants ****/ 16 17 // Constants for magic (big&little endian) 18 #define MH_MAGIC 0xFEEDFACEu 19 #define MH_CIGAM 0xCEFAEDFEu 20 #define MH_MAGIC_64 0xFEEDFACFu 21 #define MH_CIGAM_64 0xCFFAEDFEu 22 #define FAT_MAGIC 0xCAFEBABEu 23 #define FAT_CIGAM 0xBEBAFECAu 24 #define FAT_MAGIC_64 0xCAFEBABFu 25 #define FAT_CIGAM_64 0xBFBAFECAu 26 27 // Masks for CPUType capability bits 28 static const uint32_t CPU_ARCH_MASK = 0xff000000u; 29 static const uint32_t CPU_ARCH_ABI64 = 0x01000000u; // 64 bit ABI 30 static const uint32_t CPU_ARCH_ABI64_32 = 31 0x02000000u; // ILP32 ABI on 64-bit hardware 32 33 // Masks for the CPUSubType 34 static const uint32_t CPU_SUBTYPE_MASK = 35 0xff000000u; // Mask for architecture bits 36 static const uint32_t CPU_SUBTYPE_LIB64 = 0x80000000u; // 64 bit libraries 37 // static const uint32_t CPU_SUBTYPE_MULTIPLE = ~0u; 38 39 // // arm64e uses the capability bits to encode ptrauth ABI information. 40 // // Bit 63 marks the binary as Versioned. 41 // CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK = 0x80000000U, 42 // // Bit 62 marks the binary as using a kernel ABI. 43 // CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK = 0x40000000U, 44 // // Bits [59:56] hold the 4-bit ptrauth ABI version. 45 // CPU_SUBTYPE_ARM64E_PTRAUTH_MASK = 0x0f000000U, 46 47 enum CPUType { 48 CPU_TYPE_ANY = -1, 49 CPU_TYPE_VAX = 1, 50 CPU_TYPE_ROMP, 51 CPU_TYPE_NS32032 = 4, 52 CPU_TYPE_NS32332, 53 CPU_TYPE_MC680x0, 54 CPU_TYPE_X86, 55 CPU_TYPE_MIPS, 56 CPU_TYPE_NS32352, 57 CPU_TYPE_MC98000, 58 CPU_TYPE_HPPA, 59 CPU_TYPE_ARM, 60 CPU_TYPE_MC88000, 61 CPU_TYPE_SPARC, 62 CPU_TYPE_I860BE, 63 CPU_TYPE_I860LE, 64 CPU_TYPE_RS6000, 65 CPU_TYPE_POWERPC 66 }; 67 68 enum CPUSubTypeX86 { 69 CPU_SUBTYPE_X86_INVALID = -1, 70 CPU_SUBTYPE_X86_ALL = 3, 71 CPU_SUBTYPE_486 = 4, 72 CPU_SUBTYPE_486SX = 0x84, 73 CPU_SUBTYPE_586 = 5, 74 CPU_SUBTYPE_PENTPRO = 0x16, 75 CPU_SUBTYPE_PENTII_M3 = 0x36, 76 CPU_SUBTYPE_PENTII_M5 = 0x56, 77 CPU_SUBTYPE_CELERON = 0x67, 78 CPU_SUBTYPE_CELERON_MOBILE = 0x77, 79 CPU_SUBTYPE_PENTIUM_3 = 0x08, 80 CPU_SUBTYPE_PENTIUM_3_M = 0x18, 81 CPU_SUBTYPE_PENTIUM_3_XEON = 0x28, 82 CPU_SUBTYPE_PENTIUM_M = 0x09, 83 CPU_SUBTYPE_PENTIUM_4 = 0x0a, 84 CPU_SUBTYPE_PENTIUM_4_M = 0x1a, 85 CPU_SUBTYPE_ITANIUM = 0x0b, 86 CPU_SUBTYPE_ITANIUM_2 = 0x1b, 87 CPU_SUBTYPE_XEON = 0x0c, 88 CPU_SUBTYPE_XEON_MP = 0x1c 89 }; 90 91 enum CPUSubTypeARM { 92 CPU_SUBTYPE_ARM_INVALID = -1, 93 CPU_SUBTYPE_ARM_ALL, 94 CPU_SUBTYPE_ARM64_V8, 95 CPU_SUBTYPE_ARM64E, 96 CPU_SUBTYPE_ARM_V4T = 5, 97 CPU_SUBTYPE_ARM_V6, 98 CPU_SUBTYPE_ARM_V5, 99 CPU_SUBTYPE_ARM_V5TEJ = CPU_SUBTYPE_ARM_V5, 100 CPU_SUBTYPE_ARM_XSCALE, 101 CPU_SUBTYPE_ARM_V7, 102 CPU_SUBTYPE_ARM_V7S = 11, 103 CPU_SUBTYPE_ARM_V7K, 104 CPU_SUBTYPE_ARM_V6M = 14, 105 CPU_SUBTYPE_ARM_V7M, 106 CPU_SUBTYPE_ARM_V7EM 107 }; 108 109 enum CPUSubTypePPC { 110 CPU_SUBTYPE_POWERPC_ALL = 0, 111 CPU_SUBTYPE_POWERPC_601, 112 CPU_SUBTYPE_POWERPC_602, 113 CPU_SUBTYPE_POWERPC_603, 114 CPU_SUBTYPE_POWERPC_603e, 115 CPU_SUBTYPE_POWERPC_603ev, 116 CPU_SUBTYPE_POWERPC_604, 117 CPU_SUBTYPE_POWERPC_604e, 118 CPU_SUBTYPE_POWERPC_620, 119 CPU_SUBTYPE_POWERPC_750, 120 CPU_SUBTYPE_POWERPC_7400, 121 CPU_SUBTYPE_POWERPC_7450, 122 CPU_SUBTYPE_POWERPC_970 = 100, 123 124 CPU_SUBTYPE_MC980000_ALL = CPU_SUBTYPE_POWERPC_ALL, 125 CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601 126 }; 127 128 enum MachOFileType { 129 MH_OBJECT = 0x1, 130 MH_EXECUTE = 0x2, 131 MH_FVMLIB = 0x3, 132 MH_CORE = 0x4, 133 MH_PRELOAD = 0x5, 134 MH_DYLIB = 0x6, 135 MH_DYLINKER = 0x7, 136 MH_BUNDLE = 0x8, 137 MH_DYLIB_STUB = 0x9, 138 MH_DSYM = 0xA, 139 MH_KEXT_BUNDLE = 0xB, 140 MH_FILESET = 0xC 141 }; 142 143 static const uint32_t LC_REQ_DYLD = 0x80000000u; // required load command flag 144 145 enum MachOLoadCommand { 146 LC_SEGMENT = 1, 147 LC_SYMTAB, 148 LC_SYMSEG, 149 LC_THREAD, 150 LC_UNIXTHREAD, 151 LC_LOADFVMLIB, 152 LC_IDFVMLIB, 153 LC_IDENT, 154 LC_FVMFILE, 155 LC_PREPAGE, 156 LC_DYSYMTAB, 157 LC_LOAD_DYLIB, 158 LC_ID_DYLIB, 159 LC_LOAD_DYLINKER, 160 LC_ID_DYLINKER, 161 LC_PREBOUND_DYLIB, 162 LC_ROUTINES, 163 LC_SUB_FRAMEWORK, 164 LC_SUB_UMBRELLA, 165 LC_SUB_CLIENT, 166 LC_SUB_LIBRARY, 167 LC_TWOLEVEL_HINTS, 168 LC_PREBIND_CKSUM, 169 LC_LOAD_WEAK_DYLIB, 170 LC_SEGMENT_64, 171 LC_ROUTINES_64, 172 LC_UUID, 173 LC_RPATH, 174 LC_CODE_SIGNATURE, 175 LC_SEGMENT_SPLIT_INFO, 176 LC_REEXPORT_DYLIB, 177 LC_LAZY_LOAD_DYLIB, 178 LC_ENCRYPTION_INFO, 179 LC_DYLD_INFO, 180 LC_DYLD_INFO_ONLY = LC_DYLD_INFO, 181 LC_LOAD_UPWARD_DYLIB, 182 LC_VERSION_MIN_MACOSX, 183 LC_VERSION_MIN_IPHONEOS, 184 LC_FUNCTION_STARTS, 185 LC_DYLD_ENVIRONMENT, 186 LC_MAIN, 187 LC_DATA_IN_CODE, 188 LC_SOURCE_VERSION, 189 LC_DYLIB_CODE_SIGN_DRS, 190 LC_ENCRYPTION_INFO_64, 191 LC_LINKER_OPTION, 192 LC_LINKER_OPTIMIZATION_HINT, 193 LC_VERSION_MIN_TVOS, 194 LC_VERSION_MIN_WATCHOS, 195 LC_NOTE, 196 LC_BUILD_VERSION, 197 LC_DYLD_EXPORTS_TRIE, 198 LC_DYLD_CHAINED_FIXUPS, 199 LC_FILESET_ENTRY, 200 LC_ATOM_INFO 201 }; 202 203 enum MachoPlatform { 204 PLATFORM_UNKNOWN = 0, 205 PLATFORM_MACOS, 206 PLATFORM_IOS, 207 PLATFORM_TVOS, 208 PLATFORM_WATCHOS, 209 PLATFORM_BRIDGEOS, 210 PLATFORM_MACCATALYST, 211 PLATFORM_IOSSIMULATOR, 212 PLATFORM_TVOSSIMULATOR, 213 PLATFORM_WATCHOSSIMULATOR, 214 PLATFORM_DRIVERKIT, 215 PLATFORM_XROS, 216 PLATFORM_XROS_SIMULATOR 217 }; 218 219 enum MachoTool { TOOL_CLANG = 1, TOOL_SWIFT, TOOL_LD, TOOL_LLD }; 220 221 /**** Unpacked structures ****/ 222 223 typedef struct cpu_type_subtype { 224 enum CPUType type; 225 bool type_is64; 226 bool type_is64_32; 227 union { 228 enum CPUSubTypeX86 subtype_x86; 229 enum CPUSubTypeARM subtype_arm; 230 enum CPUSubTypePPC subtype_ppc; 231 }; 232 bool subtype_islib64; 233 } cpu_type_subtype_t; 234 235 typedef struct fat_arch { 236 struct cpu_type_subtype cpu; 237 uint64_t offset; 238 uint64_t size; 239 uint_fast8_t align; 240 } fat_arch_t; 241 242 typedef struct macho_file { 243 uint32_t magic; 244 uint32_t narch; 245 fat_arch_t arch[]; 246 } macho_file_t; 247 248 typedef struct macho_header { 249 uint32_t magic; 250 bool swap; 251 cpu_type_subtype_t cpu; 252 enum MachOFileType filetype; 253 uint32_t ncmds; 254 uint32_t sizeofcmds; 255 uint32_t flags; 256 } macho_header_t; 257 258 typedef struct macho_version { 259 uint_fast16_t major; 260 uint_fast16_t minor; 261 uint_fast16_t patch; 262 } macho_version_t; 263 264 typedef struct tool_version { 265 enum MachoTool tool; 266 macho_version_t version; 267 } tool_version_t; 268 269 typedef struct build_version { 270 enum MachoPlatform platform; 271 macho_version_t minos; 272 macho_version_t sdk; 273 uint32_t ntools; 274 tool_version_t tools[]; 275 } build_version_t; 276 277 typedef struct dylib { 278 uint32_t timestamp; 279 macho_version_t current_version; 280 macho_version_t compatibility_version; 281 char path[]; 282 } dylib_t; 283 284 /**** Function prototypes ****/ 285 286 /* utility */ 287 int map_platform_to_darwin(macho_version_t *darwin, 288 const enum MachoPlatform platform, const macho_version_t version); 289 290 /* readers */ 291 ssize_t read_macho_file(const int fd, macho_file_t **dest); 292 ssize_t read_macho_header(const int fd, macho_header_t *dest); 293 ssize_t read_build_version(const int fd, const bool swap, 294 build_version_t **dest); 295 ssize_t read_min_version(const int fd, const bool swap, const uint32_t loadcmd, 296 build_version_t **dest); 297 ssize_t read_path(const int fd, const bool swap, const uint32_t loadcmdsize, 298 char **dest); 299 ssize_t read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize, 300 dylib_t **dest); 301 302 #define READ(f, var) \ 303 if ((x = read_##f(fd, swap, &var)) < 0) { \ 304 return x; \ 305 } \ 306 n += x 307 ssize_t read_u32(const int fd, const bool swap, uint32_t *dest); 308 309 #endif