/ libpkg / private / binfmt_macho.h
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