binfmt_macho.c
1 /*- 2 * Copyright (c) 2024 Keve Müller <kevemueller@users.github.com> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer 9 * in this position and unchanged. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifdef HAVE_CONFIG_H 27 #include "pkg_config.h" 28 #endif 29 30 #if __has_include(<sys/endian.h>) 31 #include <sys/endian.h> 32 #elif __has_include(<endian.h>) 33 #include <endian.h> 34 #elif __has_include(<machine/endian.h>) 35 #include <machine/endian.h> 36 #endif 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <bsd_compat.h> 45 #include <xmalloc.h> 46 #include "private/binfmt_macho.h" 47 48 /** 49 * Minimal Mach-O binary file parser for both FAT as well as plain binaries with 50 * sufficient functionality to handle architecture, OS, file type, library 51 * dependencies. 52 * As well as utility functions to convert data into different formats. 53 */ 54 55 /**** Readers ****/ 56 57 static ssize_t 58 read_fully(const int fd, const size_t len, void *dest) 59 { 60 unsigned char *p = dest; 61 size_t n = len; 62 ssize_t x; 63 while (n > 0) { 64 if ((x = read(fd, p, n)) < 0) { 65 if ( EAGAIN == errno) { 66 continue; 67 } 68 return x; 69 } 70 if ( 0 == x) { 71 return -1; 72 } 73 n -= x; 74 p += x; 75 } 76 return len; 77 } 78 79 ssize_t 80 read_u32(const int fd, const bool swap, uint32_t *dest) 81 { 82 unsigned char buf[4]; 83 ssize_t x; 84 if ((x = read_fully(fd, sizeof(buf), buf)) < 0) { 85 return x; 86 } 87 if (swap) { 88 *dest = le32dec(buf); 89 } else { 90 *dest = be32dec(buf); 91 } 92 return x; 93 } 94 95 static ssize_t 96 read_u64(const int fd, const bool swap, uint64_t *dest) 97 { 98 unsigned char buf[8]; 99 ssize_t x; 100 if ((x = read_fully(fd, sizeof(buf), buf)) < 0) { 101 return x; 102 } 103 if (swap) { 104 *dest = le64dec(buf); 105 } else { 106 *dest = be64dec(buf); 107 } 108 return x; 109 } 110 111 static ssize_t 112 read_cpu_type(const int fd, const bool swap, cpu_type_subtype_t *dest) 113 { 114 ssize_t n = 0, x; 115 uint32_t cputype; 116 uint32_t cpusubtype; 117 118 READ(u32, cputype); 119 READ(u32, cpusubtype); 120 dest->type = cputype & ~CPU_ARCH_MASK; 121 dest->type_is64 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64; 122 dest->type_is64_32 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64_32; 123 dest->subtype_islib64 = (cpusubtype & CPU_SUBTYPE_MASK) == 124 CPU_SUBTYPE_LIB64; 125 switch (dest->type) { 126 case CPU_TYPE_ARM: 127 dest->subtype_arm = cpusubtype & ~CPU_SUBTYPE_MASK; 128 break; 129 case CPU_TYPE_X86: 130 dest->subtype_x86 = cpusubtype & ~CPU_SUBTYPE_MASK; 131 break; 132 case CPU_TYPE_POWERPC: 133 dest->subtype_ppc = cpusubtype & ~CPU_SUBTYPE_MASK; 134 break; 135 default: 136 errno = EINVAL; 137 return -1; 138 } 139 return n; 140 } 141 142 static ssize_t 143 read_fat_arch(const int fd, const uint32_t magic, fat_arch_t *dest) 144 { 145 ssize_t n = 0, x; 146 const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64; 147 148 READ(cpu_type, dest->cpu); 149 uint32_t align; 150 uint32_t reserved; 151 152 switch (magic) { 153 case FAT_MAGIC: 154 case FAT_CIGAM:; 155 uint32_t offset32; 156 uint32_t size32; 157 READ(u32, offset32); 158 READ(u32, size32); 159 READ(u32, align); // bits 160 161 dest->offset = offset32; 162 dest->size = size32; 163 dest->align = align; 164 break; 165 case FAT_MAGIC_64: 166 case FAT_CIGAM_64: 167 READ(u64, dest->offset); 168 READ(u64, dest->size); 169 READ(u32, align); 170 READ(u32, reserved); 171 dest->align = align; 172 break; 173 default: 174 errno = EINVAL; 175 return -1; 176 } 177 return n; 178 } 179 180 static ssize_t 181 read_version(const int fd, const bool swap, macho_version_t *dest) 182 { 183 ssize_t n = 0, x; 184 185 uint32_t version; 186 READ(u32, version); 187 dest->major = (version >> 16) & 0xffff; 188 dest->minor = (version >> 8) & 0xff; 189 dest->patch = version & 0xff; 190 return n; 191 } 192 193 ssize_t 194 read_min_version(const int fd, const bool swap, const uint32_t loadcmd, 195 build_version_t **dest) 196 { 197 ssize_t n = 0, x; 198 199 *dest = xmalloc(sizeof(build_version_t)); 200 (*dest)->ntools = 0; 201 switch (loadcmd) { 202 case LC_VERSION_MIN_IPHONEOS: 203 (*dest)->platform = PLATFORM_IOS; 204 break; 205 case LC_VERSION_MIN_MACOSX: 206 (*dest)->platform = PLATFORM_MACOS; 207 break; 208 case LC_VERSION_MIN_TVOS: 209 (*dest)->platform = PLATFORM_TVOS; 210 break; 211 case LC_VERSION_MIN_WATCHOS: 212 (*dest)->platform = PLATFORM_WATCHOS; 213 break; 214 default: 215 return -1; 216 } 217 READ(version, (*dest)->minos); 218 READ(version, (*dest)->sdk); 219 return n; 220 } 221 222 ssize_t 223 read_path(const int fd, const bool swap, const uint32_t loadcmdsize, 224 char **dest) 225 { 226 ssize_t n = 0, x; 227 228 uint32_t name_ofs; 229 READ(u32, name_ofs); 230 if (-1 == (x = lseek(fd, name_ofs - 12, SEEK_CUR))) { 231 return x; 232 } 233 n += name_ofs - 12; 234 *dest = xmalloc(loadcmdsize - name_ofs + 1); 235 if ((x = read_fully(fd, loadcmdsize - name_ofs, *dest)) < 0) { 236 free(*dest); 237 *dest = 0; 238 return x; 239 } 240 n += x; 241 (*dest)[loadcmdsize - name_ofs] = '\0'; 242 return n; 243 } 244 245 ssize_t 246 read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize, 247 dylib_t **dest) 248 { 249 ssize_t n = 0, x; 250 251 uint32_t name_ofs; 252 uint32_t timestamp; 253 macho_version_t current_version; 254 macho_version_t compatibility_version; 255 256 READ(u32, name_ofs); 257 READ(u32, timestamp); 258 READ(version, current_version); 259 READ(version, compatibility_version); 260 261 if (-1 == (x = lseek(fd, name_ofs - 24, SEEK_CUR))) { 262 return x; 263 } 264 n += name_ofs - 24; 265 266 *dest = xmalloc(sizeof(dylib_t) + loadcmdsize - name_ofs + 1); 267 (*dest)->timestamp = timestamp; 268 (*dest)->current_version = current_version; 269 (*dest)->compatibility_version = compatibility_version; 270 if ((x = read_fully(fd, loadcmdsize - name_ofs, (*dest)->path)) < 0) { 271 free(*dest); 272 *dest = 0; 273 return x; 274 } 275 n += x; 276 (*dest)->path[loadcmdsize - name_ofs] = '\0'; 277 return n; 278 } 279 280 ssize_t 281 read_build_version(const int fd, const bool swap, build_version_t **dest) 282 { 283 ssize_t n = 0, x; 284 285 uint32_t platform; 286 macho_version_t minos; 287 macho_version_t sdk; 288 uint32_t ntools; 289 290 READ(u32, platform); 291 READ(version, minos); 292 READ(version, sdk); 293 READ(u32, ntools); 294 295 *dest = xmalloc( 296 sizeof(build_version_t) + ntools * sizeof(tool_version_t)); 297 (*dest)->platform = platform; 298 (*dest)->minos = minos; 299 (*dest)->sdk = sdk; 300 (*dest)->ntools = ntools; 301 tool_version_t *p = (*dest)->tools; 302 303 for (; ntools-- > 0; p++) { 304 uint32_t tool; 305 READ(u32, tool); 306 p->tool = tool; 307 READ(version, p->version); 308 } 309 return n; 310 } 311 312 ssize_t 313 read_macho_header(const int fd, macho_header_t *dest) 314 { 315 ssize_t n = 0, x; 316 uint32_t reserved; 317 318 if ((x = read_u32(fd, false, &dest->magic)) < 0) { 319 return x; 320 } 321 n += x; 322 323 const bool swap = dest->swap = dest->magic == MH_CIGAM || 324 dest->magic == MH_CIGAM_64; 325 326 READ(cpu_type, dest->cpu); 327 READ(u32, dest->filetype); 328 READ(u32, dest->ncmds); 329 READ(u32, dest->sizeofcmds); 330 READ(u32, dest->flags); 331 switch (dest->magic) { 332 case MH_MAGIC_64: 333 case MH_CIGAM_64: 334 READ(u32, reserved); 335 break; 336 default: 337 break; 338 } 339 return n; 340 } 341 342 ssize_t 343 read_macho_file(const int fd, macho_file_t **dest) 344 { 345 ssize_t n = 0, x; 346 347 uint32_t magic; 348 if ((x = read_u32(fd, false, &magic)) < 0) { 349 return x; 350 } 351 n += x; 352 353 const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64 || 354 magic == MH_CIGAM || magic == MH_CIGAM_64; 355 356 uint32_t nfat_arch; 357 fat_arch_t *p; 358 switch (magic) { 359 case FAT_MAGIC: 360 case FAT_MAGIC_64: 361 case FAT_CIGAM: 362 case FAT_CIGAM_64: 363 READ(u32, nfat_arch); 364 *dest = xmalloc( 365 sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t)); 366 (*dest)->magic = magic; 367 (*dest)->narch = nfat_arch; 368 p = (*dest)->arch; 369 370 while (nfat_arch-- > 0) { 371 if ((x = read_fat_arch(fd, magic, p)) < 0) { 372 free(*dest); 373 *dest = 0; 374 return x; 375 } 376 n += x; 377 p++; 378 } 379 break; 380 381 case MH_MAGIC: 382 case MH_MAGIC_64: 383 case MH_CIGAM: 384 case MH_CIGAM_64: 385 nfat_arch = 1; 386 *dest = xmalloc( 387 sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t)); 388 (*dest)->magic = magic; 389 (*dest)->narch = nfat_arch; 390 p = (*dest)->arch; 391 READ(cpu_type, p->cpu); 392 off_t xo; 393 if (-1 == (xo = lseek(fd, 0, SEEK_END))) { 394 free(*dest); 395 *dest = 0; 396 return xo; 397 } 398 p->offset = 0; 399 p->size = xo; 400 p->align = 0; // number of trailing zero bits in size; 401 n = xo; 402 break; 403 default: 404 errno = EINVAL; 405 return -1; 406 } 407 return n; 408 } 409 410 /**** OS -> Kernel conversion ****/ 411 412 static macho_version_t macos_to_darwin[][2] = { 413 // macOS Sequoia 414 { { 15, 2, 0 }, { 24, 2, 0 } }, 415 { { 15, 1, 0 }, { 24, 1, 0 } }, 416 { { 15, 0, 0 }, { 24, 0, 0 } }, 417 // macOS Sonoma 418 { { 14, 6, 0 }, { 23, 6, 0 } }, 419 { { 14, 5, 0 }, { 23, 4, 0 } }, 420 { { 14, 4, 0 }, { 23, 5, 0 } }, 421 { { 14, 3, 0 }, { 23, 3, 0 } }, 422 { { 14, 2, 0 }, { 23, 2, 0 } }, 423 { { 14, 1, 0 }, { 23, 1, 0 } }, 424 { { 14, 0, 0 }, { 23, 0, 0 } }, 425 // macOS Ventura 426 { { 13, 5, 0 }, { 22, 6, 0 } }, 427 { { 13, 4, 0 }, { 22, 5, 0 } }, 428 { { 13, 3, 0 }, { 22, 4, 0 } }, 429 { { 13, 2, 0 }, { 22, 3, 0 } }, 430 { { 13, 1, 0 }, { 22, 2, 0 } }, 431 { { 13, 0, 0 }, { 22, 1, 0 } }, 432 // macOS Monterey 433 { { 12, 5, 0 }, { 21, 6, 0 } }, 434 { { 12, 4, 0 }, { 21, 5, 0 } }, 435 { { 12, 3, 0 }, { 21, 4, 0 } }, 436 { { 12, 2, 0 }, { 21, 3, 0 } }, 437 { { 12, 1, 0 }, { 21, 2, 0 } }, 438 { { 12, 0, 1 }, { 21, 1, 0 } }, 439 { { 12, 0, 0 }, { 21, 0, 1 } }, 440 // macOS Big Sur 441 { { 11, 5, 0 }, { 20, 6, 0 } }, 442 { { 11, 4, 0 }, { 20, 5, 0 } }, 443 { { 11, 3, 0 }, { 20, 4, 0 } }, 444 { { 11, 2, 0 }, { 20, 3, 0 } }, 445 { { 11, 1, 0 }, { 20, 2, 0 } }, 446 { { 11, 0, 0 }, { 20, 1, 0 } }, 447 // macOS Catalina 448 { { 10, 15, 6 }, { 19, 6, 0 } }, 449 { { 10, 15, 5 }, { 19, 5, 0 } }, 450 { { 10, 15, 4 }, { 19, 4, 0 } }, 451 { { 10, 15, 3 }, { 19, 3, 0 } }, 452 { { 10, 15, 2 }, { 19, 2, 0 } }, 453 { { 10, 15, 0 }, { 19, 0, 0 } }, 454 // macOS Mojave 455 { { 10, 14, 6 }, { 18, 7, 0 } }, 456 { { 10, 14, 5 }, { 18, 6, 0 } }, 457 { { 10, 14, 4 }, { 18, 5, 0 } }, 458 { { 10, 14, 1 }, { 18, 2, 0 } }, 459 { { 10, 14, 0 }, { 18, 0, 0 } }, 460 // macOS High Sierra 461 { { 10, 13, 6 }, { 17, 7, 0 } }, 462 { { 10, 13, 5 }, { 17, 6, 0 } }, 463 { { 10, 13, 4 }, { 17, 5, 0 } }, 464 { { 10, 13, 3 }, { 17, 4, 0 } }, 465 { { 10, 13, 2 }, { 17, 3, 0 } }, 466 { { 10, 13, 1 }, { 17, 2, 0 } }, 467 { { 10, 13, 0 }, { 17, 0, 0 } }, 468 // macOS Sierra 469 { { 10, 12, 6 }, { 16, 7, 0 } }, 470 { { 10, 12, 5 }, { 16, 6, 0 } }, 471 { { 10, 12, 4 }, { 16, 5, 0 } }, 472 { { 10, 12, 3 }, { 16, 4, 0 } }, 473 { { 10, 12, 2 }, { 16, 3, 0 } }, 474 { { 10, 12, 1 }, { 16, 1, 0 } }, 475 { { 10, 12, 0 }, { 16, 0, 0 } }, 476 // OS X El Capitan 477 { { 10, 11, 6 }, { 15, 6, 0 } }, 478 { { 10, 11, 5 }, { 15, 5, 0 } }, 479 { { 10, 11, 4 }, { 15, 4, 0 } }, 480 { { 10, 11, 3 }, { 15, 3, 0 } }, 481 { { 10, 11, 2 }, { 15, 2, 0 } }, 482 { { 10, 11, 0 }, { 15, 0, 0 } }, 483 // OS X Yosemite 484 { { 10, 10, 5 }, { 14, 5, 0 } }, 485 { { 10, 10, 4 }, { 14, 4, 0 } }, 486 { { 10, 10, 3 }, { 14, 3, 0 } }, 487 { { 10, 10, 2 }, { 14, 1, 0 } }, 488 { { 10, 10, 0 }, { 14, 0, 0 } }, 489 // OS X Mavericks 490 { { 10, 9, 5 }, { 13, 4, 0 } }, 491 { { 10, 9, 4 }, { 13, 3, 0 } }, 492 { { 10, 9, 3 }, { 13, 2, 0 } }, 493 { { 10, 9, 2 }, { 13, 1, 0 } }, 494 { { 10, 9, 0 }, { 13, 0, 0 } }, 495 // OS X Mountain Lion 496 { { 10, 8, 5 }, { 12, 5, 0 } }, // Build 12F45 switched to 12.6 497 { { 10, 8, 4 }, { 12, 4, 0 } }, 498 { { 10, 8, 3 }, { 12, 3, 0 } }, 499 { { 10, 8, 2 }, { 12, 2, 0 } }, 500 { { 10, 8, 1 }, { 12, 1, 0 } }, 501 { { 10, 8, 0 }, { 12, 0, 0 } }, 502 // OS X Lion 503 { { 10, 7, 5 }, { 11, 4, 2 } }, 504 { { 10, 7, 4 }, { 11, 4, 0 } }, 505 { { 10, 7, 3 }, { 11, 3, 0 } }, 506 { { 10, 7, 2 }, { 11, 2, 0 } }, 507 { { 10, 7, 1 }, { 11, 1, 0 } }, 508 { { 10, 7, 0 }, { 11, 0, 0 } }, 509 // Mac OS X Snow Leopard 510 { { 10, 6, 8 }, { 10, 8, 0 } }, 511 { { 10, 6, 7 }, { 10, 7, 0 } }, 512 { { 10, 6, 6 }, { 10, 6, 0 } }, 513 { { 10, 6, 5 }, { 10, 5, 0 } }, 514 { { 10, 6, 4 }, { 10, 4, 0 } }, 515 { { 10, 6, 3 }, { 10, 3, 0 } }, 516 { { 10, 6, 2 }, { 10, 2, 0 } }, 517 { { 10, 6, 1 }, { 10, 1, 0 } }, 518 { { 10, 6, 0 }, { 10, 0, 0 } }, 519 // Mac OS X Leopard 520 { { 10, 5, 8 }, { 9, 8, 0 } }, 521 { { 10, 5, 7 }, { 9, 7, 0 } }, 522 { { 10, 5, 6 }, { 9, 6, 0 } }, 523 { { 10, 5, 5 }, { 9, 5, 0 } }, 524 { { 10, 5, 4 }, { 9, 4, 0 } }, 525 { { 10, 5, 3 }, { 9, 3, 0 } }, 526 { { 10, 5, 2 }, { 9, 2, 0 } }, 527 { { 10, 5, 1 }, { 9, 1, 0 } }, // Build 9B2117 switched to 9.1.1 528 { { 10, 5, 0 }, { 9, 0, 0 } }, 529 // Mac OS X Tiger 530 { { 10, 4, 11 }, { 8, 11, 0 } }, 531 { { 10, 4, 10 }, { 8, 10, 0 } }, 532 { { 10, 4, 9 }, { 8, 9, 0 } }, 533 { { 10, 4, 8 }, { 8, 8, 0 } }, 534 { { 10, 4, 7 }, { 8, 7, 0 } }, 535 { { 10, 4, 6 }, { 8, 6, 0 } }, 536 { { 10, 4, 5 }, { 8, 5, 0 } }, 537 { { 10, 4, 4 }, { 8, 4, 0 } }, 538 { { 10, 4, 3 }, { 8, 3, 0 } }, 539 { { 10, 4, 2 }, { 8, 2, 0 } }, 540 { { 10, 4, 1 }, { 8, 1, 0 } }, 541 { { 10, 4, 0 }, { 8, 0, 0 } }, 542 // Mac OS X Panther 543 { { 10, 3, 9 }, { 7, 9, 0 } }, 544 { { 10, 3, 8 }, { 7, 8, 0 } }, 545 { { 10, 3, 7 }, { 7, 7, 0 } }, 546 { { 10, 3, 6 }, { 7, 6, 0 } }, 547 { { 10, 3, 5 }, { 7, 5, 0 } }, 548 { { 10, 3, 4 }, { 7, 4, 0 } }, 549 { { 10, 3, 3 }, { 7, 3, 0 } }, 550 { { 10, 3, 2 }, { 7, 2, 0 } }, 551 { { 10, 3, 1 }, { 7, 1, 0 } }, 552 { { 10, 3, 0 }, { 7, 0, 0 } }, 553 // Mac OS X Jaguar 554 { { 10, 2, 8 }, { 6, 8, 0 } }, 555 { { 10, 2, 7 }, { 6, 7, 0 } }, 556 { { 10, 2, 6 }, { 6, 6, 0 } }, 557 { { 10, 2, 5 }, { 6, 5, 0 } }, 558 { { 10, 2, 4 }, { 6, 4, 0 } }, 559 { { 10, 2, 3 }, { 6, 3, 0 } }, 560 { { 10, 2, 2 }, { 6, 2, 0 } }, 561 { { 10, 2, 1 }, { 6, 1, 0 } }, 562 { { 10, 2, 0 }, { 6, 0, 0 } }, 563 // Mac OS X 10.1 Puma 564 { { 10, 1, 5 }, { 5, 5, 0 } }, 565 { { 10, 1, 4 }, { 5, 4, 0 } }, 566 { { 10, 1, 3 }, { 5, 3, 0 } }, 567 { { 10, 1, 2 }, { 5, 2, 0 } }, 568 { { 10, 1, 1 }, { 5, 1, 0 } }, 569 { { 10, 1, 0 }, { 1, 4, 1 } }, 570 // Mac OS X 10.0 Cheetah 571 { { 10, 0, 1 }, { 1, 3, 1 } }, 572 { { 10, 0, 0 }, { 1, 3, 0 } }, 573 // Mac OS X Public Beta 574 // {{x,y,z}}, {1,2,1}}, 575 // Mac OS X Server 1.0 576 { { 1, 0, 2 }, { 0, 3, 0 } }, 577 { { 1, 0, 1 }, { 0, 2, 0 } }, 578 { { 1, 0, 0 }, { 0, 1, 0 } }, 579 // EOA 580 { { 0, 0, 0 }, { 0, 0, 0 } }, 581 }; 582 583 static macho_version_t ios_to_darwin[][2] = { 584 // iOS 18, iPadOS 18, tvOS 18 585 { { 18, 0, 0 }, { 24, 0, 0 } }, 586 // iOS 17, iPadOS 17, tvOS 17 587 { { 17, 5, 0 }, { 23, 5, 0 } }, 588 { { 17, 4, 0 }, { 23, 4, 0 } }, 589 { { 17, 3, 0 }, { 23, 3, 0 } }, 590 { { 17, 2, 0 }, { 23, 2, 0 } }, 591 { { 17, 1, 0 }, { 23, 1, 0 } }, 592 { { 17, 0, 0 }, { 23, 0, 0 } }, 593 // iOS 16, iPadOS 16, tvOS 16 594 { { 16, 6, 0 }, { 22, 6, 0 } }, 595 { { 16, 5, 0 }, { 22, 5, 0 } }, 596 { { 16, 4, 0 }, { 22, 4, 0 } }, 597 { { 16, 3, 0 }, { 22, 3, 0 } }, 598 { { 16, 2, 0 }, { 22, 2, 0 } }, 599 { { 16, 1, 0 }, { 22, 1, 0 } }, 600 { { 16, 0, 0 }, { 22, 0, 0 } }, 601 // iOS 15, iPadOS 15, tvOS 15 602 { { 15, 6, 0 }, { 21, 6, 0 } }, 603 { { 15, 5, 0 }, { 21, 5, 0 } }, 604 { { 15, 4, 0 }, { 21, 4, 0 } }, 605 { { 15, 3, 0 }, { 21, 3, 0 } }, 606 { { 15, 2, 0 }, { 21, 2, 0 } }, 607 { { 15, 0, 0 }, { 21, 1, 0 } }, 608 // iOS 15.0 beta 1 -> 21.0.0 609 // iOS 14, iPadOS 14, tvOS 14 610 { { 14, 7, 0 }, { 20, 6, 0 } }, 611 { { 14, 6, 0 }, { 20, 5, 0 } }, 612 { { 14, 5, 0 }, { 20, 4, 0 } }, 613 { { 14, 4, 0 }, { 20, 3, 0 } }, 614 { { 14, 3, 0 }, { 20, 2, 0 } }, 615 { { 14, 0, 0 }, { 20, 0, 0 } }, 616 // iOS 13 617 { { 13, 6, 0 }, { 19, 6, 0 } }, 618 { { 13, 5, 0 }, { 19, 5, 0 } }, 619 { { 13, 3, 1 }, { 19, 3, 0 } }, 620 { { 13, 3, 0 }, { 19, 2, 0 } }, 621 // iOS 12 622 { { 12, 1, 0 }, { 18, 2, 0 } }, 623 // iOS 11 624 { { 11, 4, 1 }, { 17, 7, 0 } }, 625 // iOS 10 626 { { 10, 3, 3 }, { 16, 6, 0 } }, 627 { { 10, 3, 0 }, { 16, 3, 0 } }, 628 { { 10, 0, 1 }, { 16, 0, 0 } }, 629 // iOS 9 630 { { 9, 3, 3 }, { 15, 6, 0 } }, 631 { { 9, 0, 0 }, { 15, 0, 0 } }, 632 // iOS 7, iOS 8 633 { { 7, 0, 0 }, { 14, 0, 0 } }, 634 // iOS 6 635 { { 6, 0, 0 }, { 13, 0, 0 } }, 636 // iOS 4.3 637 { { 4, 3, 0 }, { 11, 0, 0 } }, 638 // iPhone OS 3 639 { { 3, 0, 0 }, { 10, 0, 0 } }, 640 // iPhone OS 1 641 { { 1, 0, 0 }, { 9, 0, 0 } }, 642 // EOA 643 { { 0, 0, 0 }, { 0, 0, 0 } }, 644 }; 645 646 int 647 map_platform_to_darwin(macho_version_t *darwin, 648 const enum MachoPlatform platform, const macho_version_t version) 649 { 650 macho_version_t *p; 651 switch (platform) { 652 case PLATFORM_MACOS: 653 p = macos_to_darwin[0]; 654 break; 655 656 case PLATFORM_IOS: 657 case PLATFORM_IOSSIMULATOR: 658 case PLATFORM_TVOS: 659 case PLATFORM_TVOSSIMULATOR: 660 p = ios_to_darwin[0]; 661 break; 662 663 case PLATFORM_WATCHOS: 664 case PLATFORM_WATCHOSSIMULATOR: 665 darwin->major = version.major + 13; 666 darwin->minor = version.minor; 667 darwin->patch = 0; 668 return 0; 669 670 default: 671 return -1; 672 } 673 while (p->major > version.major || p->minor > version.minor || 674 p->patch > version.patch) { 675 p += 2; 676 } 677 p++; 678 if (0 == p->major && 0 == p->minor && 0 == p->patch) { 679 return -1; 680 } 681 *darwin = *p; 682 return 0; 683 }