LCOV - code coverage report
Current view: top level - libpkg - binfmt_macho.c (source / functions) Hit Total Coverage
Test: plop Lines: 175 235 74.5 %
Date: 2024-12-30 07:09:03 Functions: 12 13 92.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 73 164 44.5 %

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

Generated by: LCOV version 1.15