diff --git a/.gitignore b/.gitignore index 111c1c304d..6a60095541 100644 --- a/.gitignore +++ b/.gitignore @@ -63,7 +63,6 @@ scripts/sbin/pkg2ng /external/libucl/autom4te.cache /external/yxml/Makefile /external/liblua/Makefile -/external/libmachista/Makefile /external/libfetch/Makefile /external/libelf/Makefile /external/sqlite/Makefile diff --git a/auto.def b/auto.def index be7eea190f..5302a598d1 100644 --- a/auto.def +++ b/auto.def @@ -102,7 +102,7 @@ cc-with { -libs { -llzma }} { } } if {[string match *-freebsd* [get-define host]]} { - define pkg_freebsd + define pkgos_freebsd cc-with { -libs { -lmd }} { if {![cc-check-functions SHA256_Data]} { user-error "Unable to find libmd" @@ -213,14 +213,6 @@ if {![cc-check-functions dlclose]} { } } -if {![cc-check-functions __res_query]} { - cc-with { -libs { -lresolv }} { - if {[cc-check-functions __res_query]} { - define-feature LIBRESOLV - } - } -} - cc-check-includes link.h machine/endian.h osreldate.h readpassphrase.h \ sys/procctl.h sys/statfs.h sys/statvfs.h libutil.h @@ -228,7 +220,7 @@ cc-check-includes link.h machine/endian.h osreldate.h readpassphrase.h \ cc-check-includes dirent.h sys/sockio.h #endian stuff -foreach header [list endian.h sys/endian.h] { +foreach header [list endian.h sys/endian.h machine/endian.h] { if {[cc-check-includes $header]} { cc-with [list -includes $header] { cc-check-decls be16dec be16enc be32dec be32enc be64dec be64enc \ @@ -238,9 +230,10 @@ foreach header [list endian.h sys/endian.h] { } if {[string match *-darwin* [get-define host]]} { - define libmachista + define pkgos_darwin define waflags "" define nowaflags "" + define libelf-internal } else { # libelf define waflags "-Wl,-whole-archive" @@ -394,7 +387,7 @@ make-template Makefile.autosetup Makefile foreach dir [list external/blake2 external/picosat \ external/linenoise external/sqlite \ external compat libpkg libpkg/repo libpkg/repo/binary src \ - external/libucl external/libelf external/libmachista tests docs \ + external/libucl external/libelf tests docs \ external/liblua external/yxml scripts external/libcurl external/libder \ external/libecc] { make-template $dir/Makefile.autosetup $dir/Makefile diff --git a/external/Makefile.autosetup b/external/Makefile.autosetup index ee62e0d3c3..5b1385388c 100644 --- a/external/Makefile.autosetup +++ b/external/Makefile.autosetup @@ -1,8 +1,5 @@ include @builddir@/mk/defs.mk DIRS= blake2 picosat linenoise sqlite libucl liblua yxml libder libecc -@if libmachista -DIRS+= libmachista -@endif @if libelf-internal DIRS+= libelf @endif diff --git a/external/libelf/_libelf_config.h b/external/libelf/_libelf_config.h index 82a6bc8995..e73dffcf20 100644 --- a/external/libelf/_libelf_config.h +++ b/external/libelf/_libelf_config.h @@ -36,6 +36,10 @@ #define LIBELF_ARCH EM_386 #define LIBELF_BYTEORDER ELFDATA2LSB #define LIBELF_CLASS ELFCLASS32 +#elif defined(__aarch64__) +#define LIBELF_ARCH EM_AARCH64 +#define LIBELF_BYTEORDER ELFDATA2LSB +#define LIBELF_CLASS ELFCLASS64 #endif #endif /* __DragonFly__ */ diff --git a/external/libmachista/LICENSE b/external/libmachista/LICENSE deleted file mode 100644 index 8252093186..0000000000 --- a/external/libmachista/LICENSE +++ /dev/null @@ -1,52 +0,0 @@ -Copyright (c) 2011 Clemens Lang -Copyright (c) 2011 - 2014 Landon Fuller -Copyright (c) 2004 - 2014, The MacPorts Project. -Copyright (c) 2002 - 2003, Apple Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. Neither the name of Apple Inc., The MacPorts Project nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -hashmap.c is subject to the following license: - -Copyright (c) 2011 Christoph Erhardt. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/external/libmachista/Makefile.autosetup b/external/libmachista/Makefile.autosetup deleted file mode 100644 index 50e8ce019d..0000000000 --- a/external/libmachista/Makefile.autosetup +++ /dev/null @@ -1,8 +0,0 @@ -include @builddir@/mk/defs.mk -LIB= machista -SRCS= libmachista.c \ - hashmap.c - -VPATH= $(top_srcdir)/external/libmachista - -include $(MK)/static-lib.mk diff --git a/external/libmachista/hashmap.c b/external/libmachista/hashmap.c deleted file mode 100644 index 0ad08ad7d3..0000000000 --- a/external/libmachista/hashmap.c +++ /dev/null @@ -1,295 +0,0 @@ -/* vim:expandtab:tw=80:ts=2:sts=2:sw=2 - */ -/*- - * Copyright (c) 2011 Christoph Erhardt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Modified by Clemens Lang to accept values of arbitrary type. - */ - - -#ifndef _BSD_SOURCE - #define _BSD_SOURCE -#endif -#ifndef _CRT_NONSTDC_NO_DEPRECATE - #define _CRT_NONSTDC_NO_DEPRECATE -#endif - -#include "hashmap.h" -#include -#include -#include - - -static const size_t INITIAL_CAPACITY = 16; /* Must be a power of 2 */ -static const size_t MAXIMUM_CAPACITY = (1U << 31); -static const float LOAD_FACTOR = 0.75; - - -typedef struct HashMapEntry { - char *key; - const void *value; - struct HashMapEntry *next; - uint32_t hash; -} HashMapEntry; - -struct HashMap { - HashMapEntry **table; - size_t capacity; - size_t size; - size_t threshold; - void (*freeFunc)(const void *); -}; - - -static void setTable(HashMap *map, HashMapEntry **table, size_t capacity) { - map->table = table; - map->capacity = capacity; - map->threshold = (size_t) (capacity * LOAD_FACTOR); -} - - -static uint32_t doHash(const char key[]) { - size_t length; - size_t i; - uint32_t h = 0; - if (key == NULL) - return 0; - length = strlen(key); - for (i = 0; i < length; ++i) { - h = (31 * h) + key[i]; - } - h ^= (h >> 20) ^ (h >> 12); - return h ^ (h >> 7) ^ (h >> 4); -} - - -static size_t indexFor(uint32_t hash, size_t length) { - return hash & (length - 1); -} - - -static int isHit(HashMapEntry *e, const char key[], uint32_t hash) { - return (e->hash == hash - && (e->key == key || (key != NULL && strcmp(e->key, key) == 0))); -} - - -static void copyOrFree(void (*freeFunc)(const void *), - const void *value, const void **valPtr) { - if (valPtr != NULL) - *valPtr = value; - else - freeFunc(value); -} - - -static int updateValue(HashMap *map, HashMapEntry *e, const void *newVal, - const void **oldValPtr) { - copyOrFree(map->freeFunc, e->value, oldValPtr); - e->value = newVal; - return 1; -} - - -/* Creates a hash map. */ -HashMap *hashMapCreate(void (*freeFunc)(const void *)) { - HashMapEntry **table; - HashMap *map = malloc(sizeof(*map)); - if (map == NULL) - return NULL; - table = calloc(INITIAL_CAPACITY, sizeof(*map->table)); - if (table == NULL) { - free(map); - return NULL; - } - setTable(map, table, INITIAL_CAPACITY); - map->size = 0; - map->freeFunc = freeFunc; - return map; -} - - -/* Inserts a key-value pair into a hash map. */ -int hashMapPut(HashMap *map, const char key[], const void * const value, - const void **oldValPtr) { - - HashMapEntry *e; - size_t newCapacity; - HashMapEntry **newTable; - size_t i; - - /* If an entry with the same key exists, update it */ - uint32_t hash = doHash(key); - size_t index = indexFor(hash, map->capacity); - for (e = map->table[index]; e != NULL; e = e->next) { - if (isHit(e, key, hash) == 0) - continue; - return updateValue(map, e, value, oldValPtr); - } - - /* Create a new entry */ - e = calloc(1, sizeof(HashMapEntry)); /* Must be zeroed */ - if (e == NULL) - return 0; - - /* Copy key and value into the entry */ - if (key != NULL) { - e->key = strdup(key); - if (e->key == NULL) { - free(e); - return 0; - } - } - if (updateValue(map, e, value, oldValPtr) == 0) { - free(e->key); - free(e); - return 0; - } - - /* Insert entry into the table */ - e->hash = hash; - e->next = map->table[index]; - map->table[index] = e; - if (map->size++ < map->threshold) - return 1; - - /* If the size exceeds the threshold, double the table's capacity */ - newCapacity = 2 * map->capacity; - if (map->capacity == MAXIMUM_CAPACITY) { - map->threshold = UINT_MAX; - return 1; - } - newTable = calloc(newCapacity, sizeof(*newTable)); - if (newTable == NULL) - return 0; - - /* Copy entries from the old table into the new one */ - for (i = 0; i < map->capacity; ++i) { - HashMapEntry *next; - for (e = map->table[i]; e != NULL; e = next) { - index = indexFor(e->hash, newCapacity); - next = e->next; - e->next = newTable[index]; - newTable[index] = e; - } - } - - /* Release the old table and set the new one */ - free(map->table); - setTable(map, newTable, newCapacity); - return 1; -} - - -/* Performs a hash map lookup. */ -const void *hashMapGet(HashMap *map, const char key[]) { - HashMapEntry *e; - uint32_t hash = doHash(key); - size_t index = indexFor(hash, map->capacity); - for (e = map->table[index]; e != NULL; e = e->next) { - if (isHit(e, key, hash)) - return e->value; - } - return NULL; -} - - -/* Checks whether a hash map contains an entry with a certain key. */ -int hashMapContainsKey(HashMap *map, const char key[]) { - HashMapEntry *e; - uint32_t hash = doHash(key); - size_t index = indexFor(hash, map->capacity); - for (e = map->table[index]; e != NULL; e = e->next) { - if (isHit(e, key, hash)) - return 1; - } - return 0; -} - - -/* Removes a key-value pair from a hash map. */ -void hashMapRemove(HashMap *map, const char key[], const void **valPtr) { - uint32_t hash = doHash(key); - size_t index = indexFor(hash, map->capacity); - HashMapEntry *prev = map->table[index]; - HashMapEntry *e = prev; - while (e != NULL) { - HashMapEntry *next = e->next; - if (isHit(e, key, hash)) { - map->size--; - if (prev == e) - map->table[index] = next; - else - prev->next = next; - break; - } - prev = e; - e = next; - } - if (e == NULL) { - copyOrFree(map->freeFunc, NULL, valPtr); - return; - } - free(e->key); - copyOrFree(map->freeFunc, e->value, valPtr); - free(e); -} - - -/* Returns the number of elements stored in a hash map. */ -size_t hashMapSize(const HashMap *map) { - return map->size; -} - - -/* Checks whether a hash map is empty. */ -int hashMapIsEmpty(const HashMap *map) { - return (map->size == 0); -} - - -/* Removes all entries from a hash map. */ -void hashMapClear(HashMap *map) { - size_t i; - for (i = 0; i < map->capacity; ++i) { - HashMapEntry *e; - HashMapEntry *next; - for (e = map->table[i]; e != NULL; e = next) { - free(e->key); - map->freeFunc(e->value); - next = e->next; - free(e); - } - map->table[i] = NULL; - } -} - - -/* Destroys a hash map. */ -void hashMapDestroy(HashMap *map) { - if (map == NULL) - return; - hashMapClear(map); - free(map->table); - free(map); -} diff --git a/external/libmachista/hashmap.h b/external/libmachista/hashmap.h deleted file mode 100644 index 9ec6606691..0000000000 --- a/external/libmachista/hashmap.h +++ /dev/null @@ -1,135 +0,0 @@ -/* vim:tw=80:expandtab - */ -/** - * @file hashmap.h - * @brief A hash map implementation in C. - * @author Christoph Erhardt - */ - -/*- - * Copyright (c) 2011 Christoph Erhardt. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY CHRISTOPH ERHARDT ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL CHRISTOPH ERHARDT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -/*- - * Modified by Clemens Lang to accept values of arbitrary type. - */ - - -#ifndef HASHMAP_H -#define HASHMAP_H - - -#include - - -/** Hash map type. */ -typedef struct HashMap HashMap; - - -/** - * @brief Creates a hash map. - * - * The keys and values managed in the map can be arbitrary C strings. - * @param freeFunc Function to call in order to free a stored value - * @return Pointer to the newly created hash map, or @c NULL on error. - */ -HashMap *hashMapCreate(void (*freeFunc)(const void *)); - -/** - * @brief Inserts a key-value pair into a hash map. - * - * Both key and value are copied internally, so the caller can reuse the - * original variables. - * If oldValPtr is @c NULL, the previously stored value corresponding to the key - * is freed. Otherwise it is written into @c *valPtr and the caller is - * responsible for freeing it. - * @param map Hash map. - * @param key Key. - * @param value Value. - * @param oldValPtr Output parameter receiving the previously stored value - * corresponding to the key (@c NULL if no mapping existed - * before). - * @return Nonzero on success, 0 on error. - */ -int hashMapPut(HashMap *map, const char key[], const void * const value, - const void **oldValPtr); - -/** - * @brief Performs a hash map lookup. - * - * The returned value must not be freed or otherwise manipulated by the caller. - * @param map Hash map. - * @param key Key. - * @return Value corresponding to the key on success, @c NULL if no matching - * entry was found. - */ -const void *hashMapGet(HashMap *map, const char key[]); - -/** - * @brief Checks whether a hash map contains an entry with a certain key. - * @param map Hash map. - * @param key Key. - * @return Nonzero if the map contains an entry with the given key, 0 if it does - * not. - */ -int hashMapContainsKey(HashMap *map, const char key[]); - -/** - * @brief Removes a key-value pair from a hash map and frees the stored key. - * - * If @c valPtr is @c NULL, the internally stored value corresponding to the key - * is freed. Otherwise it is written into @c *valPtr and the caller is - * responsible for freeing it. - * @param map Hash map. - * @param key Key. - * @param valPtr Output parameter receiving the internally stored value - * corresponding to the key. - */ -void hashMapRemove(HashMap *map, const char key[], const void **valPtr); - -/** - * @brief Returns the number of elements stored in a hash map. - * @param map Hash map. - * @return Number of elements stored in the map. - */ -size_t hashMapSize(const HashMap *map); - -/** - * @brief Checks whether a hash map is empty. - * @param map Hash map. - * @return Nonzero if the map contains no entries, 0 otherwise. - */ -int hashMapIsEmpty(const HashMap *map); - -/** - * @brief Removes all entries from a hash map. - * @param map Hash map. - */ -void hashMapClear(HashMap *map); - -/** - * @brief Destroys a hash map. - * @param map Hash map to be destroyed. - */ -void hashMapDestroy(HashMap *map); - - -#endif /* HASHMAP_H */ diff --git a/external/libmachista/libmachista.c b/external/libmachista/libmachista.c deleted file mode 100644 index bdd18388d1..0000000000 --- a/external/libmachista/libmachista.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100 - * libmachista.c - * $Id: libmachista.c 120067 2014-05-14 22:18:53Z cal@macports.org $ - * - * Copyright (c) 2011 The MacPorts Project - * Copyright (c) 2011 Landon Fuller - * Copyright (c) 2011 Clemens Lang - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -/* required for asprintf(3) on OS X */ -#define _DARWIN_C_SOURCE -/* required for asprintf(3) on Linux */ -#define _GNU_SOURCE - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#ifdef __MACH__ -#include -#include - -#include -#endif - -#include "libmachista.h" -#include "hashmap.h" - -#ifdef __MACH__ -/* Tiger compatibility */ -#ifndef LC_RPATH -#define LC_RPATH (0x1c | LC_REQ_DYLD) /* runpath additions */ -/* - * The rpath_command contains a path which at runtime should be added to - * the current run path used to find @rpath prefixed dylibs. - */ -struct rpath_command { - uint32_t cmd; /* LC_RPATH */ - uint32_t cmdsize; /* includes string */ - union lc_str path; /* path to add to run path */ -}; -#endif -#ifndef LC_REEXPORT_DYLIB -#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */ -#endif -#endif /* __MACH__ */ - -typedef struct macho_input { - const void *data; - size_t length; -} macho_input_t; - -/* This is macho_handle_t. The corresponding typedef is in the header */ -struct macho_handle { - HashMap *result_map; -}; - -#ifdef __MACH__ -/* Verify that the given range is within bounds. */ -static const void *macho_read (macho_input_t *input, const void *address, size_t length) { - if ((((uint8_t *) address) - ((uint8_t *) input->data)) + length > input->length) { - // warnx("Short read parsing Mach-O input"); - return NULL; - } - - return address; -} - -/* Verify that address + offset + length is within bounds. */ -static const void *macho_offset (macho_input_t *input, const void *address, size_t offset, size_t length) { - void *result = ((uint8_t *) address) + offset; - return macho_read(input, result, length); -} -#endif - -/* return a human readable formatted version number. the result must be free()'d. */ -char *macho_format_dylib_version (uint32_t version) { - char *result; - asprintf(&result, "%"PRIu32".%"PRIu32".%"PRIu32, (version >> 16) & 0xFFFF, (version >> 8) & 0xFF, version & 0xFF); - return result; -} - -#ifdef __MACH__ -const char *macho_get_arch_name (cpu_type_t cputype) { - const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, CPU_SUBTYPE_MULTIPLE); - if (!archInfo) { - return NULL; - } - return archInfo->name; -#else -const char *macho_get_arch_name (cpu_type_t cputype UNUSED) { - return NULL; -#endif -} - -#ifdef __MACH__ -/* Some byteswap wrappers */ -static uint32_t macho_swap32 (uint32_t input) { - return OSSwapInt32(input); -} - -static uint32_t macho_nswap32(uint32_t input) { - return input; -} - -/* Creates a new macho_t. - * Returns NULL on failure or a pointer to a 0-initialized macho_t on success */ -static macho_t *create_macho_t (void) { - macho_t *mt = malloc(sizeof(macho_t)); - if (mt == NULL) - return NULL; - - memset(mt, 0, sizeof(macho_t)); - return mt; -} - -/* Creates a new macho_arch_t. - * Returns NULL on failure or a pointer to a 0-initialized macho_arch_t on success */ -static macho_arch_t *create_macho_arch_t (void) { - macho_arch_t *mat = malloc(sizeof(macho_arch_t)); - if (mat == NULL) - return NULL; - - memset(mat, 0, sizeof(macho_arch_t)); - return mat; -} - -/* Creates a new macho_loadcmd_t. - * Returns NULL on failure or a pointer to a 0-initialized macho_loadcmd_t on success */ -static macho_loadcmd_t *create_macho_loadcmd_t (void) { - macho_loadcmd_t *mlt = malloc(sizeof(macho_loadcmd_t)); - if (mlt == NULL) - return NULL; - - memset(mlt, 0, sizeof(macho_loadcmd_t)); - return mlt; -} -#endif - -/* Frees a previously allocated macho_loadcmd_t and all it's associated resources */ -static void free_macho_loadcmd_t (macho_loadcmd_t *mlt) { - if (mlt == NULL) - return; - - free(mlt->mlt_install_name); - free(mlt); -} - -/* Frees a previously allocated macho_arch_t and all it's associated resources */ -static void free_macho_arch_t (macho_arch_t *mat) { - if (mat == NULL) - return; - - macho_loadcmd_t *current = mat->mat_loadcmds; - while (current != NULL) { - macho_loadcmd_t *freeme = current; - current = current->next; - free_macho_loadcmd_t(freeme); - } - - free(mat->mat_install_name); - free(mat->mat_rpath); - free(mat); -} - -/* Frees a previously allocated macho_t and all it's associated resources */ -static void free_macho_t (macho_t *mt) { - if (mt == NULL) - return; - - macho_arch_t *current = mt->mt_archs; - while (current != NULL) { - macho_arch_t *freeme = current; - current = current->next; - free_macho_arch_t(freeme); - } - - free(mt); -} - -#ifdef __MACH__ -/* Creates a new element in the architecture list of a macho_t (mt_archs), increases the counter of - * architectures (mt_arch_count) and returns a pointer to the newly allocated element or NULL on - * error */ -static macho_arch_t *macho_archlist_append (macho_t *mt) { - macho_arch_t *old_head = mt->mt_archs; - - macho_arch_t *new_head = create_macho_arch_t(); - if (new_head == NULL) - return NULL; - new_head->next = old_head; - mt->mt_archs = new_head; - - return mt->mt_archs; -} - -/* Creates a new element in the load command list of a macho_arch_t (mat_loadcmds), increases the - * counter of load commands (mat_loadcmd_count) and returns a pointer to the newly allocated element - * or NULL on error */ -static macho_loadcmd_t *macho_loadcmdlist_append (macho_arch_t *mat) { - macho_loadcmd_t *old_head = mat->mat_loadcmds; - - macho_loadcmd_t *new_head = create_macho_loadcmd_t(); - if (new_head == NULL) - return NULL; - new_head->next = old_head; - mat->mat_loadcmds = new_head; - - return mat->mat_loadcmds; -} -#endif - -/* Parse a Mach-O header */ -#ifdef __MACH__ -static int parse_macho (macho_t *mt, macho_input_t *input) { - /* Read the file type. */ - const uint32_t *magic = macho_read(input, input->data, sizeof(uint32_t)); - if (magic == NULL) - return MACHO_ERANGE; - - /* Parse the Mach-O header */ - bool universal = false; - uint32_t (*swap32)(uint32_t) = macho_nswap32; - - const struct mach_header *header; - const struct mach_header_64 *header64; - size_t header_size; - const struct fat_header *fat_header; - - macho_arch_t *mat = NULL; - switch (*magic) { - case MH_CIGAM: - swap32 = macho_swap32; - // Fall-through - - case MH_MAGIC: - - header_size = sizeof(*header); - header = macho_read(input, input->data, header_size); - if (header == NULL) - return MACHO_ERANGE; - mat = macho_archlist_append(mt); - if (mat == NULL) - return MACHO_EMEM; - - /* 32-bit Mach-O */ - mat->mat_cputype = swap32(header->cputype); - mat->mat_cpusubtype = swap32(header->cpusubtype); - break; - - - case MH_CIGAM_64: - swap32 = macho_swap32; - // Fall-through - - case MH_MAGIC_64: - header_size = sizeof(*header64); - header64 = macho_read(input, input->data, sizeof(*header64)); - if (header64 == NULL) - return MACHO_ERANGE; - mat = macho_archlist_append(mt); - if (mat == NULL) - return MACHO_EMEM; - - /* The 64-bit header is a direct superset of the 32-bit header */ - header = (struct mach_header *) header64; - - /* 64-bit Macho-O */ - mat->mat_cputype = swap32(header->cputype); - mat->mat_cpusubtype = swap32(header->cpusubtype); - break; - - case FAT_CIGAM: - case FAT_MAGIC: - fat_header = macho_read(input, input->data, sizeof(*fat_header)); - universal = true; - /* Universal binary */ - break; - - default: - /* Unknown binary type */ - //warnx("Unknown Mach-O magic: 0x%" PRIx32 "", *magic); - return MACHO_EMAGIC; - } - - /* Parse universal file. */ - if (universal) { - uint32_t nfat = OSSwapBigToHostInt32(fat_header->nfat_arch); - const struct fat_arch *archs = macho_offset(input, fat_header, sizeof(struct fat_header), sizeof(struct fat_arch)); - if (archs == NULL) - return MACHO_ERANGE; - - for (uint32_t i = 0; i < nfat; i++) { // foreach architecture - const struct fat_arch *arch = macho_read(input, archs + i, sizeof(struct fat_arch)); - if (arch == NULL) - return MACHO_ERANGE; - - /* Fetch a pointer to the architecture's Mach-O header. */ - macho_input_t arch_input; - arch_input.length = OSSwapBigToHostInt32(arch->size); - arch_input.data = macho_offset(input, input->data, OSSwapBigToHostInt32(arch->offset), arch_input.length); - if (arch_input.data == NULL) - return MACHO_ERANGE; - - /* Parse the architecture's Mach-O header */ - int res = parse_macho(mt, &arch_input); - if (res != MACHO_SUCCESS) - return res; - } - - return MACHO_SUCCESS; - } - - /* Copy the architecture */ - mat->mat_cputype = swap32(header->cputype); - mat->mat_cpusubtype = swap32(header->cpusubtype); - - /* Parse the Mach-O load commands */ - uint32_t ncmds = swap32(header->ncmds); - - /* Setup to jump over the header on the first pass through instead of the previous command */ - const struct load_command *cmd = (void *)header; - uint32_t cmdsize = header_size; - - /* Iterate over the load commands */ - for (uint32_t i = 0; i < ncmds; i++) { - /* Load the next command */ - cmd = macho_offset(input, cmd, cmdsize, sizeof(struct load_command)); - if (cmd == NULL) - return MACHO_ERANGE; - - /* Load the full command */ - cmdsize = swap32(cmd->cmdsize); - cmd = macho_read(input, cmd, cmdsize); - if (cmd == NULL) - return MACHO_ERANGE; - - /* Handle known types */ - uint32_t cmd_type = swap32(cmd->cmd); - switch (cmd_type) { - case LC_RPATH: { - /* Copy the rpath */ - if (cmdsize < sizeof(struct rpath_command)) { - //warnx("Incorrect cmd size"); - return MACHO_ERANGE; - } - - size_t pathlen = cmdsize - sizeof(struct rpath_command); - const void *pathptr = macho_offset(input, cmd, sizeof(struct rpath_command), pathlen); - if (pathptr == NULL) - return MACHO_ERANGE; - - mat->mat_rpath = malloc(pathlen); - if (mat->mat_rpath == NULL) - return MACHO_EMEM; - strlcpy(mat->mat_rpath, pathptr, pathlen); - break; - } - - case LC_ID_DYLIB: - case LC_LOAD_WEAK_DYLIB: - case LC_REEXPORT_DYLIB: - case LC_LOAD_DYLIB: { - const struct dylib_command *dylib_cmd = (const struct dylib_command *) cmd; - - /* Extract the install name */ - if (cmdsize < sizeof(struct dylib_command)) { - //warnx("Incorrect name size"); - return MACHO_ERANGE; - } - - size_t namelen = cmdsize - sizeof(struct dylib_command); - const void *nameptr = macho_offset(input, cmd, sizeof(struct dylib_command), namelen); - if (nameptr == NULL) - return MACHO_ERANGE; - - if (cmd_type == LC_ID_DYLIB) { - /* Copy install name */ - mat->mat_install_name = malloc(namelen); - if (mat->mat_install_name == NULL) - return MACHO_EMEM; - strlcpy(mat->mat_install_name, nameptr, namelen); - - /* Copy version numbers (raw, for easier comparison) */ - mat->mat_version = swap32(dylib_cmd->dylib.current_version); - mat->mat_comp_version = swap32(dylib_cmd->dylib.compatibility_version); - } else { - /* Append loadcmd to list of loadcommands */ - macho_loadcmd_t *mlt = macho_loadcmdlist_append(mat); - if (mlt == NULL) - return MACHO_EMEM; - - /* Copy install name */ - mlt->mlt_install_name = malloc(namelen); - if (mlt->mlt_install_name == NULL) - return MACHO_EMEM; - strlcpy(mlt->mlt_install_name, nameptr, namelen); - - /* Copy version numbers (raw, for easier comparison) */ - mlt->mlt_version = swap32(dylib_cmd->dylib.current_version); - mlt->mlt_comp_version = swap32(dylib_cmd->dylib.compatibility_version); - - /* Copy command type */ - mlt->mlt_type = cmd_type; - } - break; - } - - default: - break; - } - } - - return MACHO_SUCCESS; -} -#endif - -/* Parse a (possible Mach-O) file. For a more detailed description, see the header */ -#ifdef __MACH__ -int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res) { - int fd; - struct stat st; - void *data; - macho_input_t input_file; - - /* Check hashmap for precomputed results */ - const macho_t *cached_res = hashMapGet(handle->result_map, filepath); - if (cached_res != NULL) { - *res = cached_res; - return MACHO_SUCCESS; - } - - - /* Open input file */ - if ((fd = open(filepath, O_RDONLY)) < 0) { - return MACHO_EFILE; - } - - /* Get file length */ - if (fstat(fd, &st) != 0) { - close(fd); - return MACHO_EFILE; - } - - /* Map file into address space */ - if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) { - close(fd); - return MACHO_EMMAP; - } - - /* Parse file */ - input_file.data = data; - input_file.length = st.st_size; - - *res = create_macho_t(); - if (*res == NULL) - return MACHO_EMEM; - - /* The output parameter *res should be read-only for the user of the lib only, but writable for - * us */ - int ret = parse_macho((macho_t *)*res, &input_file); - if (ret == MACHO_SUCCESS) { - /* Insert into hashmap for caching */ - if (0 == hashMapPut(handle->result_map, filepath, *res, NULL)) { - free_macho_t((macho_t *)*res); - *res = NULL; - ret = MACHO_EMEM; - } - } else { - /* An error occured, free mt */ - free_macho_t((macho_t *)*res); - *res = NULL; - } - - /* Cleanup */ - munmap(data, st.st_size); - close(fd); - - return ret; -#else -int macho_parse_file(macho_handle_t *handle UNUSED, const char *filepath UNUSED, const macho_t **res UNUSED) { - return 0; -#endif -} - -/* Create a new macho_handle_t. More information on this function is available in the header */ -macho_handle_t *macho_create_handle (void) { - macho_handle_t *mht = malloc(sizeof(macho_handle_t)); - if (mht == NULL) - return NULL; - mht->result_map = hashMapCreate((void (*)(const void *))free_macho_t); - if (mht->result_map == NULL) { - free(mht); - return NULL; - } - return mht; -} - -/* Release a macho_handle_t. For more documentation, see the header */ -void macho_destroy_handle(macho_handle_t *handle) { - if (handle == NULL) - return; - - hashMapDestroy(handle->result_map); - - free(handle); -} - -/* Returns string representation of the MACHO_* error code constants */ -const char *macho_strerror(int err) { - int num; -#ifdef HAVE_FLS - num = fls(err); -#else - /* Tiger compatibility, see #42186 */ - num = 0; - while (err > 0) { - err >>= 1; - num++; - } -#endif - - static char *errors[] = { - /* 0x00 */ "Success", - /* 0x01 */ "Error opening or reading file", - /* 0x02 */ "Error mapping file into memory", - /* 0x04 */ "Error allocating memory", - /* 0x08 */ "Premature end of data, possibly corrupt file", - /* 0x10 */ "Not a Mach-O file", - }; - return errors[num]; -} - diff --git a/external/libmachista/libmachista.h b/external/libmachista/libmachista.h deleted file mode 100644 index a026754e9d..0000000000 --- a/external/libmachista/libmachista.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100 - * libmachista.h - * $Id$ - * - * Copyright (c) 2011 The MacPorts Project - * Copyright (c) 2011 Clemens Lang - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __LIBMACHISTA_H__ -#define __LIBMACHISTA_H__ - -/* - * This is a library to parse Mach-O files in single architecture _and_ universal variant and return - * a list of architectures and their load commands and properties - * The name a pun: machista is the spanish translation of "macho". - */ - -#ifdef __MACH__ -#include -#else -typedef int cpu_type_t; -#endif -#include - -#define MACHO_SUCCESS (0x00) -#define MACHO_EFILE (0x01) -#define MACHO_EMMAP (0x02) -#define MACHO_EMEM (0x04) -#define MACHO_ERANGE (0x08) -#define MACHO_EMAGIC (0x10) - -/* Blind structure; this essentially contains the hash map used to cache - * entries, but users should not have to look into this structure. struct - * macho_handle is defined in libmachista.c */ -typedef struct macho_handle macho_handle_t; - -/** Structure describing a load command within a Mach-O file */ -typedef struct macho_loadcmd { - char *mlt_install_name; /* install name of the library to be loaded by this load command */ - uint32_t mlt_type; /* type of the load command; see mach-o/loader.h for possible - values */ - uint32_t mlt_comp_version; /* compatibility version of the file to be loaded by this - command (at build time of this file) */ - uint32_t mlt_version; /* version of the library to be loaded by this command (at build - time of this file) */ - struct macho_loadcmd *next; /* pointer to the next entry in the linked list of - macho_loadcmd_t's (NULL if there's no further element) */ -} macho_loadcmd_t; - -/** Stucture describing an architecture within a Mach-O file */ -typedef struct macho_arch { - char *mat_install_name; /* install name of the library or NULL if none */ - char *mat_rpath; /* rpath of the binary of NULL if none */ - cpu_type_t mat_cputype; /* cpu_type_t describing the CPU this part of the binary is - intended for */ - cpu_type_t mat_cpusubtype; /* cpu_subtype_t describing the CPU subtype this part of the - binary is intended for */ - uint32_t mat_comp_version; /* compatibility version of this part of the binary */ - uint32_t mat_version; /* current version of this part of the binary */ - macho_loadcmd_t *mat_loadcmds; /* array of macho_loadcmd_t's describing the different load - commands */ - struct macho_arch *next; /* pointer to the next entry in the linked list of - macho_arch_t's (NULL if there's no further element) */ -} macho_arch_t; - -/** Structure describing a Mach-O file */ -typedef struct macho { - macho_arch_t *mt_archs; /* linked list of macho_arch_t's describing the different - architectures */ -} macho_t; - -/** - * Creates and returns a macho_handle_t to be passed to subsequent calls to macho_parse_file. No - * assumptions should be made about the contents of a macho_handle_t; it is declared to be a blind - * structure. - * - * Returns either a pointer to a valid macho_handle_t or NULL on failure. errno will be set on - * failure. The resources associated with a macho_handle_t must be freed by passing it to - * macho_destroy_handle. - */ -macho_handle_t *macho_create_handle(void); - -/** - * Frees resources associated with a macho_handle_t and invalidates all results returned by - * macho_parse_file called with this handle. - */ -void macho_destroy_handle(macho_handle_t *handle); - -/** - * Formats a dylib version number given by an uint32_t into a human-readable format and returns a - * Pointer to the beginning of that string. The result is either a valid pointer or NULL on error - * (in which case the errno is set to indicate the error). The pointer must be free()'d after use. - */ -char *macho_format_dylib_version(uint32_t version); - -/** - * Returns a readable version of any cpu_type_t constant. Returns a valid pointer to the first - * character in a 0-terminated string or NULL on error. The pointer must not be free()'d after use. - */ -const char *macho_get_arch_name(cpu_type_t cputype); - -/** - * Parses the Mach-O file indicated by filepath and writes a pointer to a macho_t describing the - * Mach-O file into the location idicated by res. Returns MACHO_SUCCESS on success or any of the - * following error codes on error: - * - * code description errno set? - * MACHO_EFILE error stat()'ing, opening or reading the file yes - * MACHO_EMMAP error mmap()'ing the file yes - * MACHO_EMEM error allocating memory yes - * MACHO_ERANGE unexpected end of file no - * MACHO_EMAGIC unknown magic number/not a Mach-O file no - * - * On error, the contents of res are undefined and should not be used. The memory associated with - * the result *res will be free()'d and should thus not be used after calling macho_destroy_handle - * on the macho_handle_t used for the call. *res should also never be modified or otherwise - * free()'d. - */ -int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res); - -/** - * Returns a string representation of the MACHO_* error code constants - */ -const char *macho_strerror(int err); - -#endif - diff --git a/libpkg/Makefile.autosetup b/libpkg/Makefile.autosetup index ef3eee4977..f89b6cf392 100644 --- a/libpkg/Makefile.autosetup +++ b/libpkg/Makefile.autosetup @@ -32,6 +32,10 @@ SRCS= backup_lib.c \ pkg_jobs_conflicts.c pkg_ports.c \ pkg_solve.c \ pkgdb.c \ + pkg_abi.c \ + pkg_elf.c \ + pkg_abi_macho.c \ + binfmt_macho.c \ ssh.c elfhints.c \ pkg_arch.c \ pkg_cudf.c \ @@ -117,22 +121,14 @@ LOCAL_LDFLAGS+= -lfts @if HAVE_LIBDL LOCAL_LDFLAGS+= -ldl @endif -@if HAVE_LIBRESOLV -LOCAL_LDFLAGS+= -lresolv -@endif -@if libmachista -LOCAL_CFLAGS+= -I$(top_srcdir)/external/libmachista -STATIC_LIBS+= $(top_builddir)/external/libmachista/libmachista.a -LOCAL_LDFLAGS+= -L$(top_builddir)/external/libmachista -lmachista_pic \ - -larchive -lresolv -SRCS+= pkg_macho.c -@else -SRCS+= pkg_elf.c -@if pkg_freebsd +@if pkgos_darwin +LOCAL_LDFLAGS+= -lresolv +@else +@if pkgos_freebsd LOCAL_LDFLAGS+= -Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver,--undefined-version @else -# --undefined-version is a FreeBSD ld option +### --undefined-version is a FreeBSD ld option LOCAL_LDFLAGS+= -Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver @endif @endif @@ -185,7 +181,7 @@ all: lib$(LIB)_flat.a lib$(LIB)$(LIBSOEXT): $(STATIC_LIBS) -@if libmachista +@if pkgos_darwin lib$(LIB)_flat.a: $(STATIC_LIBS) libtool -static -o lib$(LIB)_flat.a $(STATIC_LIBS) @else diff --git a/libpkg/binfmt_macho.c b/libpkg/binfmt_macho.c new file mode 100644 index 0000000000..d85820b0d1 --- /dev/null +++ b/libpkg/binfmt_macho.c @@ -0,0 +1,665 @@ +/*- + * Copyright (c) 2024 Keve Müller + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "private/binfmt_macho.h" + +/** + * Minimal Mach-O binary file parser for both FAT as well as plain binaries with + * sufficient functionality to handle architecture, OS, file type, library + * dependencies. + * As well as utility functions to convert data into different formats. + */ + +/**** Readers ****/ + +static ssize_t +read_fully(const int fd, const size_t len, void *dest) +{ + unsigned char *p = dest; + size_t n = len; + ssize_t x; + while (n > 0) { + if ((x = read(fd, p, n)) < 0) { + return x; + } + n -= x; + p += x; + } + return len; +} + +ssize_t +read_u32(const int fd, const bool swap, uint32_t *dest) +{ + unsigned char buf[4]; + ssize_t x; + if ((x = read_fully(fd, sizeof(buf), buf)) < 0) { + return x; + } + if (swap) { + *dest = le32dec(buf); + } else { + *dest = be32dec(buf); + } + return x; +} + +static ssize_t +read_u64(const int fd, const bool swap, uint64_t *dest) +{ + unsigned char buf[8]; + ssize_t x; + if ((x = read_fully(fd, sizeof(buf), buf)) < 0) { + return x; + } + if (swap) { + *dest = le64dec(buf); + } else { + *dest = be64dec(buf); + } + return x; +} + +static ssize_t +read_cpu_type(const int fd, const bool swap, cpu_type_subtype_t *dest) +{ + ssize_t n = 0, x; + uint32_t cputype; + uint32_t cpusubtype; + + READ(u32, cputype); + READ(u32, cpusubtype); + dest->type = cputype & ~CPU_ARCH_MASK; + dest->type_is64 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64; + dest->type_is64_32 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64_32; + dest->subtype_islib64 = (cpusubtype & CPU_SUBTYPE_MASK) == + CPU_SUBTYPE_LIB64; + switch (dest->type) { + case CPU_TYPE_ARM: + dest->subtype_arm = cpusubtype & ~CPU_SUBTYPE_MASK; + break; + case CPU_TYPE_X86: + dest->subtype_x86 = cpusubtype & ~CPU_SUBTYPE_MASK; + break; + case CPU_TYPE_POWERPC: + dest->subtype_ppc = cpusubtype & ~CPU_SUBTYPE_MASK; + break; + default: + errno = EINVAL; + return -1; + } + return n; +} + +static ssize_t +read_fat_arch(const int fd, const uint32_t magic, fat_arch_t *dest) +{ + ssize_t n = 0, x; + const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64; + + READ(cpu_type, dest->cpu); + uint32_t align; + uint32_t reserved; + + switch (magic) { + case FAT_MAGIC: + case FAT_CIGAM:; + uint32_t offset32; + uint32_t size32; + READ(u32, offset32); + READ(u32, size32); + READ(u32, align); // bits + + dest->offset = offset32; + dest->size = size32; + dest->align = align; + break; + case FAT_MAGIC_64: + case FAT_CIGAM_64: + READ(u64, dest->offset); + READ(u64, dest->size); + READ(u32, align); + READ(u32, reserved); + dest->align = align; + break; + default: + errno = EINVAL; + return -1; + } + return n; +} + +static ssize_t +read_version(const int fd, const bool swap, macho_version_t *dest) +{ + ssize_t n = 0, x; + + uint32_t version; + READ(u32, version); + dest->major = (version >> 16) & 0xffff; + dest->minor = (version >> 8) & 0xff; + dest->patch = version & 0xff; + return n; +} + +ssize_t +read_min_version(const int fd, const bool swap, const uint32_t loadcmd, + build_version_t **dest) +{ + ssize_t n = 0, x; + + *dest = malloc(sizeof(build_version_t)); + (*dest)->ntools = 0; + switch (loadcmd) { + case LC_VERSION_MIN_IPHONEOS: + (*dest)->platform = PLATFORM_IOS; + break; + case LC_VERSION_MIN_MACOSX: + (*dest)->platform = PLATFORM_MACOS; + break; + case LC_VERSION_MIN_TVOS: + (*dest)->platform = PLATFORM_TVOS; + break; + case LC_VERSION_MIN_WATCHOS: + (*dest)->platform = PLATFORM_WATCHOS; + break; + default: + return -1; + } + READ(version, (*dest)->minos); + READ(version, (*dest)->sdk); + return n; +} + +static ssize_t +read_path(const int fd, const bool swap, const uint32_t loadcmdsize, + char **dest) +{ + ssize_t n = 0, x; + + uint32_t name_ofs; + READ(u32, name_ofs); + if (-1 == (x = lseek(fd, name_ofs - 12, SEEK_CUR))) { + return x; + } + n += name_ofs - 12; + *dest = malloc(loadcmdsize - name_ofs + 1); + if ((x = read_fully(fd, loadcmdsize - name_ofs, *dest)) < 0) { + free(*dest); + *dest = 0; + return x; + } + n += x; + (*dest)[loadcmdsize - name_ofs] = '\0'; + return n; +} + +static ssize_t +read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize, + dylib_t **dest) +{ + ssize_t n = 0, x; + + uint32_t name_ofs; + uint32_t timestamp; + macho_version_t current_version; + macho_version_t compatibility_version; + + READ(u32, name_ofs); + READ(u32, timestamp); + READ(version, current_version); + READ(version, compatibility_version); + + if (-1 == (x = lseek(fd, name_ofs - 24, SEEK_CUR))) { + return x; + } + n += name_ofs - 24; + + *dest = malloc(sizeof(dylib_t) + loadcmdsize - name_ofs + 1); + (*dest)->timestamp = timestamp; + (*dest)->current_version = current_version; + (*dest)->compatibility_version = compatibility_version; + if ((x = read_fully(fd, loadcmdsize - name_ofs, (*dest)->path)) < 0) { + free(*dest); + *dest = 0; + return x; + } + n += x; + (*dest)->path[loadcmdsize - name_ofs] = '\0'; + return n; +} + +ssize_t +read_build_version(const int fd, const bool swap, build_version_t **dest) +{ + ssize_t n = 0, x; + + uint32_t platform; + macho_version_t minos; + macho_version_t sdk; + uint32_t ntools; + + READ(u32, platform); + READ(version, minos); + READ(version, sdk); + READ(u32, ntools); + + *dest = malloc( + sizeof(build_version_t) + ntools * sizeof(tool_version_t)); + (*dest)->platform = platform; + (*dest)->minos = minos; + (*dest)->sdk = sdk; + (*dest)->ntools = ntools; + tool_version_t *p = (*dest)->tools; + + for (; ntools-- > 0; p++) { + uint32_t tool; + READ(u32, tool); + p->tool = tool; + READ(version, p->version); + } + return n; +} + +ssize_t +read_macho_header(const int fd, macho_header_t *dest) +{ + ssize_t n = 0, x; + uint32_t reserved; + + if ((x = read_u32(fd, false, &dest->magic) < 0)) { + return x; + } + n += x; + + const bool swap = dest->swap = dest->magic == MH_CIGAM || + dest->magic == MH_CIGAM_64; + + READ(cpu_type, dest->cpu); + READ(u32, dest->filetype); + READ(u32, dest->ncmds); + READ(u32, dest->sizeofcmds); + READ(u32, dest->flags); + switch (dest->magic) { + case MH_MAGIC_64: + case MH_CIGAM_64: + READ(u32, reserved); + break; + default: + break; + } + return n; +} + +ssize_t +read_macho_file(const int fd, macho_file_t **dest) +{ + ssize_t n = 0, x; + + uint32_t magic; + if ((x = read_u32(fd, false, &magic)) < 0) { + return x; + } + n += x; + + const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64 || + magic == MH_CIGAM || magic == MH_CIGAM_64; + + uint32_t nfat_arch; + fat_arch_t *p; + switch (magic) { + case FAT_MAGIC: + case FAT_MAGIC_64: + case FAT_CIGAM: + case FAT_CIGAM_64: + READ(u32, nfat_arch); + *dest = malloc( + sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t)); + (*dest)->magic = magic; + (*dest)->narch = nfat_arch; + p = (*dest)->arch; + + while (nfat_arch-- > 0) { + if ((x = read_fat_arch(fd, magic, p)) < 0) { + free(*dest); + *dest = 0; + return x; + } + n += x; + p++; + } + break; + + case MH_MAGIC: + case MH_MAGIC_64: + case MH_CIGAM: + case MH_CIGAM_64: + nfat_arch = 1; + *dest = malloc( + sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t)); + (*dest)->magic = magic; + (*dest)->narch = nfat_arch; + p = (*dest)->arch; + READ(cpu_type, p->cpu); + off_t xo; + if (-1 == (xo = lseek(fd, 0, SEEK_END))) { + free(*dest); + *dest = 0; + return xo; + } + p->offset = 0; + p->size = xo; + p->align = 0; // number of trailing zero bits in size; + n = xo; + break; + default: + errno = EINVAL; + return -1; + } + return n; +} + +/**** OS -> Kernel conversion ****/ + +static macho_version_t macos_to_darwin[][2] = { + // macOS Sequoia + { { 15, 2, 0 }, { 24, 2, 0 } }, + { { 15, 1, 0 }, { 24, 1, 0 } }, + { { 15, 0, 0 }, { 24, 0, 0 } }, + // macOS Sonoma + { { 14, 6, 0 }, { 23, 6, 0 } }, + { { 14, 5, 0 }, { 23, 4, 0 } }, + { { 14, 4, 0 }, { 23, 5, 0 } }, + { { 14, 3, 0 }, { 23, 3, 0 } }, + { { 14, 2, 0 }, { 23, 2, 0 } }, + { { 14, 1, 0 }, { 23, 1, 0 } }, + { { 14, 0, 0 }, { 23, 0, 0 } }, + // macOS Ventura + { { 13, 5, 0 }, { 22, 6, 0 } }, + { { 13, 4, 0 }, { 22, 5, 0 } }, + { { 13, 3, 0 }, { 22, 4, 0 } }, + { { 13, 2, 0 }, { 22, 3, 0 } }, + { { 13, 1, 0 }, { 22, 2, 0 } }, + { { 13, 0, 0 }, { 22, 1, 0 } }, + // macOS Monterey + { { 12, 5, 0 }, { 21, 6, 0 } }, + { { 12, 4, 0 }, { 21, 5, 0 } }, + { { 12, 3, 0 }, { 21, 4, 0 } }, + { { 12, 2, 0 }, { 21, 3, 0 } }, + { { 12, 1, 0 }, { 21, 2, 0 } }, + { { 12, 0, 1 }, { 21, 1, 0 } }, + { { 12, 0, 0 }, { 21, 0, 1 } }, + // macOS Big Sur + { { 11, 5, 0 }, { 20, 6, 0 } }, + { { 11, 4, 0 }, { 20, 5, 0 } }, + { { 11, 3, 0 }, { 20, 4, 0 } }, + { { 11, 2, 0 }, { 20, 3, 0 } }, + { { 11, 1, 0 }, { 20, 2, 0 } }, + { { 11, 0, 0 }, { 20, 1, 0 } }, + // macOS Catalina + { { 10, 15, 6 }, { 19, 6, 0 } }, + { { 10, 15, 5 }, { 19, 5, 0 } }, + { { 10, 15, 4 }, { 19, 4, 0 } }, + { { 10, 15, 3 }, { 19, 3, 0 } }, + { { 10, 15, 2 }, { 19, 2, 0 } }, + { { 10, 15, 0 }, { 19, 0, 0 } }, + // macOS Mojave + { { 10, 14, 6 }, { 18, 7, 0 } }, + { { 10, 14, 5 }, { 18, 6, 0 } }, + { { 10, 14, 4 }, { 18, 5, 0 } }, + { { 10, 14, 1 }, { 18, 2, 0 } }, + { { 10, 14, 0 }, { 18, 0, 0 } }, + // macOS High Sierra + { { 10, 13, 6 }, { 17, 7, 0 } }, + { { 10, 13, 5 }, { 17, 6, 0 } }, + { { 10, 13, 4 }, { 17, 5, 0 } }, + { { 10, 13, 3 }, { 17, 4, 0 } }, + { { 10, 13, 2 }, { 17, 3, 0 } }, + { { 10, 13, 1 }, { 17, 2, 0 } }, + { { 10, 13, 0 }, { 17, 0, 0 } }, + // macOS Sierra + { { 10, 12, 6 }, { 16, 7, 0 } }, + { { 10, 12, 5 }, { 16, 6, 0 } }, + { { 10, 12, 4 }, { 16, 5, 0 } }, + { { 10, 12, 3 }, { 16, 4, 0 } }, + { { 10, 12, 2 }, { 16, 3, 0 } }, + { { 10, 12, 1 }, { 16, 1, 0 } }, + { { 10, 12, 0 }, { 16, 0, 0 } }, + // OS X El Capitan + { { 10, 11, 6 }, { 15, 6, 0 } }, + { { 10, 11, 5 }, { 15, 5, 0 } }, + { { 10, 11, 4 }, { 15, 4, 0 } }, + { { 10, 11, 3 }, { 15, 3, 0 } }, + { { 10, 11, 2 }, { 15, 2, 0 } }, + { { 10, 11, 0 }, { 15, 0, 0 } }, + // OS X Yosemite + { { 10, 10, 5 }, { 14, 5, 0 } }, + { { 10, 10, 4 }, { 14, 4, 0 } }, + { { 10, 10, 3 }, { 14, 3, 0 } }, + { { 10, 10, 2 }, { 14, 1, 0 } }, + { { 10, 10, 0 }, { 14, 0, 0 } }, + // OS X Mavericks + { { 10, 9, 5 }, { 13, 4, 0 } }, + { { 10, 9, 4 }, { 13, 3, 0 } }, + { { 10, 9, 3 }, { 13, 2, 0 } }, + { { 10, 9, 2 }, { 13, 1, 0 } }, + { { 10, 9, 0 }, { 13, 0, 0 } }, + // OS X Mountain Lion + { { 10, 8, 5 }, { 12, 5, 0 } }, // Build 12F45 switched to 12.6 + { { 10, 8, 4 }, { 12, 4, 0 } }, + { { 10, 8, 3 }, { 12, 3, 0 } }, + { { 10, 8, 2 }, { 12, 2, 0 } }, + { { 10, 8, 1 }, { 12, 1, 0 } }, + { { 10, 8, 0 }, { 12, 0, 0 } }, + // OS X Lion + { { 10, 7, 5 }, { 11, 4, 2 } }, + { { 10, 7, 4 }, { 11, 4, 0 } }, + { { 10, 7, 3 }, { 11, 3, 0 } }, + { { 10, 7, 2 }, { 11, 2, 0 } }, + { { 10, 7, 1 }, { 11, 1, 0 } }, + { { 10, 7, 0 }, { 11, 0, 0 } }, + // Mac OS X Snow Leopard + { { 10, 6, 8 }, { 10, 8, 0 } }, + { { 10, 6, 7 }, { 10, 7, 0 } }, + { { 10, 6, 6 }, { 10, 6, 0 } }, + { { 10, 6, 5 }, { 10, 5, 0 } }, + { { 10, 6, 4 }, { 10, 4, 0 } }, + { { 10, 6, 3 }, { 10, 3, 0 } }, + { { 10, 6, 2 }, { 10, 2, 0 } }, + { { 10, 6, 1 }, { 10, 1, 0 } }, + { { 10, 6, 0 }, { 10, 0, 0 } }, + // Mac OS X Leopard + { { 10, 5, 8 }, { 9, 8, 0 } }, + { { 10, 5, 7 }, { 9, 7, 0 } }, + { { 10, 5, 6 }, { 9, 6, 0 } }, + { { 10, 5, 5 }, { 9, 5, 0 } }, + { { 10, 5, 4 }, { 9, 4, 0 } }, + { { 10, 5, 3 }, { 9, 3, 0 } }, + { { 10, 5, 2 }, { 9, 2, 0 } }, + { { 10, 5, 1 }, { 9, 1, 0 } }, // Build 9B2117 switched to 9.1.1 + { { 10, 5, 0 }, { 9, 0, 0 } }, + // Mac OS X Tiger + { { 10, 4, 11 }, { 8, 11, 0 } }, + { { 10, 4, 10 }, { 8, 10, 0 } }, + { { 10, 4, 9 }, { 8, 9, 0 } }, + { { 10, 4, 8 }, { 8, 8, 0 } }, + { { 10, 4, 7 }, { 8, 7, 0 } }, + { { 10, 4, 6 }, { 8, 6, 0 } }, + { { 10, 4, 5 }, { 8, 5, 0 } }, + { { 10, 4, 4 }, { 8, 4, 0 } }, + { { 10, 4, 3 }, { 8, 3, 0 } }, + { { 10, 4, 2 }, { 8, 2, 0 } }, + { { 10, 4, 1 }, { 8, 1, 0 } }, + { { 10, 4, 0 }, { 8, 0, 0 } }, + // Mac OS X Panther + { { 10, 3, 9 }, { 7, 9, 0 } }, + { { 10, 3, 8 }, { 7, 8, 0 } }, + { { 10, 3, 7 }, { 7, 7, 0 } }, + { { 10, 3, 6 }, { 7, 6, 0 } }, + { { 10, 3, 5 }, { 7, 5, 0 } }, + { { 10, 3, 4 }, { 7, 4, 0 } }, + { { 10, 3, 3 }, { 7, 3, 0 } }, + { { 10, 3, 2 }, { 7, 2, 0 } }, + { { 10, 3, 1 }, { 7, 1, 0 } }, + { { 10, 3, 0 }, { 7, 0, 0 } }, + // Mac OS X Jaguar + { { 10, 2, 8 }, { 6, 8, 0 } }, + { { 10, 2, 7 }, { 6, 7, 0 } }, + { { 10, 2, 6 }, { 6, 6, 0 } }, + { { 10, 2, 5 }, { 6, 5, 0 } }, + { { 10, 2, 4 }, { 6, 4, 0 } }, + { { 10, 2, 3 }, { 6, 3, 0 } }, + { { 10, 2, 2 }, { 6, 2, 0 } }, + { { 10, 2, 1 }, { 6, 1, 0 } }, + { { 10, 2, 0 }, { 6, 0, 0 } }, + // Mac OS X 10.1 Puma + { { 10, 1, 5 }, { 5, 5, 0 } }, + { { 10, 1, 4 }, { 5, 4, 0 } }, + { { 10, 1, 3 }, { 5, 3, 0 } }, + { { 10, 1, 2 }, { 5, 2, 0 } }, + { { 10, 1, 1 }, { 5, 1, 0 } }, + { { 10, 1, 0 }, { 1, 4, 1 } }, + // Mac OS X 10.0 Cheetah + { { 10, 0, 1 }, { 1, 3, 1 } }, + { { 10, 0, 0 }, { 1, 3, 0 } }, + // Mac OS X Public Beta + // {{x,y,z}}, {1,2,1}}, + // Mac OS X Server 1.0 + { { 1, 0, 2 }, { 0, 3, 0 } }, + { { 1, 0, 1 }, { 0, 2, 0 } }, + { { 1, 0, 0 }, { 0, 1, 0 } }, + // EOA + { { 0, 0, 0 }, { 0, 0, 0 } }, +}; + +static macho_version_t ios_to_darwin[][2] = { + // iOS 18, iPadOS 18, tvOS 18 + { { 18, 0, 0 }, { 24, 0, 0 } }, + // iOS 17, iPadOS 17, tvOS 17 + { { 17, 5, 0 }, { 23, 5, 0 } }, + { { 17, 4, 0 }, { 23, 4, 0 } }, + { { 17, 3, 0 }, { 23, 3, 0 } }, + { { 17, 2, 0 }, { 23, 2, 0 } }, + { { 17, 1, 0 }, { 23, 1, 0 } }, + { { 17, 0, 0 }, { 23, 0, 0 } }, + // iOS 16, iPadOS 16, tvOS 16 + { { 16, 6, 0 }, { 22, 6, 0 } }, + { { 16, 5, 0 }, { 22, 5, 0 } }, + { { 16, 4, 0 }, { 22, 4, 0 } }, + { { 16, 3, 0 }, { 22, 3, 0 } }, + { { 16, 2, 0 }, { 22, 2, 0 } }, + { { 16, 1, 0 }, { 22, 1, 0 } }, + { { 16, 0, 0 }, { 22, 0, 0 } }, + // iOS 15, iPadOS 15, tvOS 15 + { { 15, 6, 0 }, { 21, 6, 0 } }, + { { 15, 5, 0 }, { 21, 5, 0 } }, + { { 15, 4, 0 }, { 21, 4, 0 } }, + { { 15, 3, 0 }, { 21, 3, 0 } }, + { { 15, 2, 0 }, { 21, 2, 0 } }, + { { 15, 0, 0 }, { 21, 1, 0 } }, + // iOS 15.0 beta 1 -> 21.0.0 + // iOS 14, iPadOS 14, tvOS 14 + { { 14, 7, 0 }, { 20, 6, 0 } }, + { { 14, 6, 0 }, { 20, 5, 0 } }, + { { 14, 5, 0 }, { 20, 4, 0 } }, + { { 14, 4, 0 }, { 20, 3, 0 } }, + { { 14, 3, 0 }, { 20, 2, 0 } }, + { { 14, 0, 0 }, { 20, 0, 0 } }, + // iOS 13 + { { 13, 6, 0 }, { 19, 6, 0 } }, + { { 13, 5, 0 }, { 19, 5, 0 } }, + { { 13, 3, 1 }, { 19, 3, 0 } }, + { { 13, 3, 0 }, { 19, 2, 0 } }, + // iOS 12 + { { 12, 1, 0 }, { 18, 2, 0 } }, + // iOS 11 + { { 11, 4, 1 }, { 17, 7, 0 } }, + // iOS 10 + { { 10, 3, 3 }, { 16, 6, 0 } }, + { { 10, 3, 0 }, { 16, 3, 0 } }, + { { 10, 0, 1 }, { 16, 0, 0 } }, + // iOS 9 + { { 9, 3, 3 }, { 15, 6, 0 } }, + { { 9, 0, 0 }, { 15, 0, 0 } }, + // iOS 7, iOS 8 + { { 7, 0, 0 }, { 14, 0, 0 } }, + // iOS 6 + { { 6, 0, 0 }, { 13, 0, 0 } }, + // iOS 4.3 + { { 4, 3, 0 }, { 11, 0, 0 } }, + // iPhone OS 3 + { { 3, 0, 0 }, { 10, 0, 0 } }, + // iPhone OS 1 + { { 1, 0, 0 }, { 9, 0, 0 } }, + // EOA + { { 0, 0, 0 }, { 0, 0, 0 } }, +}; + +int +map_platform_to_darwin(macho_version_t *darwin, + const enum MachoPlatform platform, const macho_version_t version) +{ + macho_version_t *p; + switch (platform) { + case PLATFORM_MACOS: + p = macos_to_darwin[0]; + break; + + case PLATFORM_IOS: + case PLATFORM_IOSSIMULATOR: + case PLATFORM_TVOS: + case PLATFORM_TVOSSIMULATOR: + p = ios_to_darwin[0]; + break; + + case PLATFORM_WATCHOS: + case PLATFORM_WATCHOSSIMULATOR: + darwin->major = version.major + 13; + darwin->minor = version.minor; + darwin->patch = 0; + return 0; + + default: + return -1; + } + while (p->major > version.major || p->minor > version.minor || + p->patch > version.patch) { + p += 2; + } + p++; + if (0 == p->major && 0 == p->minor && 0 == p->patch) { + return -1; + } + *darwin = *p; + return 0; +} diff --git a/libpkg/pkg_abi.c b/libpkg/pkg_abi.c new file mode 100644 index 0000000000..fe947a993b --- /dev/null +++ b/libpkg/pkg_abi.c @@ -0,0 +1,327 @@ +/*- + * Copyright (c) 2011-2012 Baptiste Daroussin + * Copyright (c) 2012-2013 Matthew Seaman + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifdef HAVE_CONFIG_H +#include "pkg_config.h" +#endif + +#include +#include +#include + +#include "pkg.h" + +#include "private/pkg.h" +#include "private/event.h" + +#define _PATH_UNAME "/usr/bin/uname" + +int pkg_get_myarch_elfparse(int fd, char *dest, size_t sz, struct os_info *oi); +int pkg_analyse_init_elf(const char* stage); +int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath); +int pkg_analyse_close_elf(); + +int pkg_get_myarch_macho(int fd, char *dest, size_t sz, struct os_info *oi); +int pkg_analyse_init_macho(const char* stage); +int pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fpath); +int pkg_analyse_close_macho(); + + +/* All possibilities on FreeBSD as of 5/26/2014 */ +struct arch_trans { + const char *elftype; + const char *archid; +}; + +static struct arch_trans machine_arch_translation[] = { + { "x86:32", "i386" }, + { "x86:64", "amd64" }, + { "powerpc:32:eb", "powerpc" }, + { "powerpc:64:eb", "powerpc64" }, + { "powerpc:64:el", "powerpc64le" }, + { "sparc64:64", "sparc64" }, + { "ia64:64", "ia64" }, + /* All the ARM stuff */ + { "armv6:32:el:eabi:hardfp", "armv6" }, + { "armv7:32:el:eabi:hardfp", "armv7" }, + { "aarch64:64", "aarch64" }, + /* And now MIPS */ + { "mips:32:el:o32", "mipsel" }, + { "mips:32:el:n32", "mipsn32el" }, + { "mips:32:eb:o32", "mips" }, + { "mips:32:eb:n32", "mipsn32" }, + { "mips:64:el:n64", "mips64el" }, + { "mips:64:eb:n64", "mips64" }, + /* And RISC-V */ + { "riscv:32:hf", "riscv32" }, + { "riscv:32:sf", "riscv32sf" }, + { "riscv:64:hf", "riscv64" }, + { "riscv:64:sf", "riscv64sf" }, + + { NULL, NULL } +}; + +static int +pkg_get_myarch_fromfile(char *dest, size_t sz, struct os_info *oi) +{ + char rooted_abi_file[PATH_MAX]; + const char *abi_files[] = { + getenv("ABI_FILE"), + _PATH_UNAME, + _PATH_BSHELL, + }; + struct os_info loi; + int i, fd; + + if (oi == NULL) { + memset(&loi, 0, sizeof(loi)); + oi = &loi; + } + + /* + * Perhaps not yet needed, but it may be in the future that there's no + * need to check root under some conditions where there is a rootdir. + * This also helps alleviate some excessive wrapping later. + */ + bool checkroot = ctx.pkg_rootdir != NULL; + for (fd = -1, i = 0; i < NELEM(abi_files); i++) { + if (abi_files[i] == NULL) + continue; + /* + * Try prepending rootdir and using that if it exists. If + * ABI_FILE is specified, assume that the consumer didn't want + * it mangled by rootdir. + */ + if (i > 0 && checkroot && snprintf(rooted_abi_file, PATH_MAX, + "%s/%s", ctx.pkg_rootdir, abi_files[i]) < PATH_MAX) { + if ((fd = open(rooted_abi_file, O_RDONLY)) >= 0) + break; + } + if ((fd = open(abi_files[i], O_RDONLY)) >= 0) + break; + /* if the ABI_FILE was provided we only care about it */ + if (i == 0) + break; + } + if (fd == -1) { + pkg_emit_error("Unable to determine the ABI\n"); + return (EPKG_FATAL); + } + + int ret = pkg_get_myarch_elfparse(fd, dest, sz, oi); + if (EPKG_OK != ret) { + lseek(fd, 0, SEEK_SET); + ret = pkg_get_myarch_macho(fd, dest, sz, oi); + } + + if (oi == &loi) { + free(oi->name); + free(oi->version); + free(oi->version_major); + free(oi->version_minor); + free(oi->arch); + } + close(fd); + return ret; +} + +int +pkg_get_myarch_with_legacy(char *dest, char* dest_legacy, size_t sz, struct os_info *oi) +{ + int err = pkg_get_myarch_fromfile(dest_legacy, sz, oi); + if (err) { + if (oi) { + free(oi->name); + } + return (err); + } + strlcpy(dest, dest_legacy, sz); + + for(char *p = dest_legacy; *p; ++p) { + *p = tolower(*p); + } + +// TODO: When dealing with DragonFly, not only on DragonFly +#ifdef __DragonFly__ + size_t dsz; + + dsz = strlen(dest); + if (strncasecmp(dest, "DragonFly", 9) == 0) { + for (int i = 0; i < dsz; i++) + dest[i] = tolower(dest[i]); + return (0); + } +#endif + + /* Translate architecture string back to regular OS one */ + char *arch_tweak = strchr(dest, ':'); + if (arch_tweak == NULL) + return (0); + arch_tweak++; + arch_tweak = strchr(arch_tweak, ':'); + if (arch_tweak == NULL) + return (0); + arch_tweak++; + for (struct arch_trans *arch_trans = machine_arch_translation; arch_trans->elftype != NULL; + arch_trans++) { + if (STREQ(arch_tweak, arch_trans->elftype)) { + strlcpy(arch_tweak, arch_trans->archid, + sz - (arch_tweak - dest)); + oi->arch = xstrdup(arch_tweak); + break; + } + } + + return (0); +} + +int +pkg_arch_to_legacy(const char *arch, char *dest, size_t sz) +{ + int i = 0; + struct arch_trans *arch_trans; + + memset(dest, '\0', sz); + /* Lower case the OS */ + while (arch[i] != ':' && arch[i] != '\0') { + dest[i] = tolower(arch[i]); + i++; + } + if (arch[i] == '\0') + return (0); + + dest[i++] = ':'; + + /* Copy the version */ + while (arch[i] != ':' && arch[i] != '\0') { + dest[i] = arch[i]; + i++; + } + if (arch[i] == '\0') + return (0); + + dest[i++] = ':'; + + for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL; + arch_trans++) { + if (STREQ(arch + i, arch_trans->archid)) { + strlcpy(dest + i, arch_trans->elftype, + sz - (arch + i - dest)); + return (0); + } + } + strlcpy(dest + i, arch + i, sz - (arch + i - dest)); + + return (0); +} + +int +pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage) +{ + struct pkg_file *file = NULL; + int ret = EPKG_OK; + char fpath[MAXPATHLEN +1]; + const char *lib; + bool failures = false; + + int (*pkg_analyse_init)(const char* stage) = pkg_analyse_init_elf; + int (*pkg_analyse)(const bool developer_mode, struct pkg *pkg, const char *fpath) = pkg_analyse_elf; + int (*pkg_analyse_close)() = pkg_analyse_close_elf; + + if (tll_length(pkg->shlibs_required) != 0) { + tll_free_and_free(pkg->shlibs_required, free); + } + + if (tll_length(pkg->shlibs_provided) != 0) { + tll_free_and_free(pkg->shlibs_provided, free); + } + + ret = pkg_analyse_init(stage); + if (ret != EPKG_OK) { + goto cleanup; + } + + /* Assume no architecture dependence, for contradiction */ + if (ctx.developer_mode) + pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS | + PKG_CONTAINS_STATIC_LIBS | + PKG_CONTAINS_LA); + + while (pkg_files(pkg, &file) == EPKG_OK) { + if (stage != NULL) + snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path); + else + strlcpy(fpath, file->path, sizeof(fpath)); + + ret = pkg_analyse(ctx.developer_mode, pkg, fpath); + if (EPKG_WARN == ret) { + failures = true; + } + } + + /* + * Do not depend on libraries that a package provides itself + */ + tll_foreach(pkg->shlibs_required, s) { + if (stringlist_contains(&pkg->shlibs_provided, s->item)) { + pkg_debug(2, "remove %s from required shlibs as the " + "package %s provides this library itself", + s->item, pkg->name); + tll_remove_and_free(pkg->shlibs_required, s, free); + continue; + } + file = NULL; + while (pkg_files(pkg, &file) == EPKG_OK) { + if ((lib = strstr(file->path, s->item)) != NULL && + strlen(lib) == strlen(s->item) && lib[-1] == '/') { + pkg_debug(2, "remove %s from required shlibs as " + "the package %s provides this file itself", + s->item, pkg->name); + + tll_remove_and_free(pkg->shlibs_required, s, free); + break; + } + } + } + + /* + * if the package is not supposed to provide share libraries then + * drop the provided one + */ + if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) { + tll_free_and_free(pkg->shlibs_provided, free); + } + + if (failures) + goto cleanup; + + ret = EPKG_OK; + +cleanup: + ret = pkg_analyse_close(); + + return (ret); +} \ No newline at end of file diff --git a/libpkg/pkg_abi_macho.c b/libpkg/pkg_abi_macho.c new file mode 100644 index 0000000000..cc6d738a40 --- /dev/null +++ b/libpkg/pkg_abi_macho.c @@ -0,0 +1,266 @@ +/*- + * Copyright (c) 2024 Keve Müller + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "private/binfmt_macho.h" + +#include "private/pkg.h" +#include "private/event.h" + + +/** + * Routines to support pkg_abi.c functions when dealing with Mach-O files. + * Supports getting ABI and ALTABI from the binary's load commands. Cave: picks first binary in FAT collection. + * Supports getting shared libary information. Picks right binary in FAT collection based on ABI. + * Supports FreeBSD naming of architectures. + */ + +/**** CPU -> FreeBSD MACHINE_ARCH conversion ****/ + +static const char * +cputype_to_freebsd_machine_arch(const cpu_type_subtype_t cpu) +{ + switch (cpu.type) { + case CPU_TYPE_ARM: + if (cpu.type_is64_32) { + return "aarch64-x32"; + } else if (cpu.type_is64) { + return "aarch64"; + } else { + switch (cpu.subtype_arm) { + case CPU_SUBTYPE_ARM_V7: + case CPU_SUBTYPE_ARM_V7S: + case CPU_SUBTYPE_ARM_V7K: + case CPU_SUBTYPE_ARM_V7M: + case CPU_SUBTYPE_ARM_V7EM: + return "armv7"; + case CPU_SUBTYPE_ARM_V6: + case CPU_SUBTYPE_ARM_V6M: + return "armv6"; + case CPU_SUBTYPE_ARM_XSCALE: + case CPU_SUBTYPE_ARM_V5: + case CPU_SUBTYPE_ARM_V4T: + return "armeb"; + case CPU_SUBTYPE_ARM_ALL: + default: + return "arm"; + } + } + case CPU_TYPE_POWERPC: + if (cpu.type_is64_32) { + return "powerpc64-x32"; + } else if (cpu.type_is64) { + return "powerpc64"; + } else { + return "powerpc"; + } + case CPU_TYPE_X86: + if (cpu.type_is64_32) { + return "amd64-x32"; + } else if (cpu.type_is64) { + return "amd64"; + } else { + return "i386"; + } + default: + return "unknown"; + } +} + +static const char * +cputype_to_elfname(const cpu_type_subtype_t cpu) +{ + switch (cpu.type) { + case CPU_TYPE_ARM: + if (cpu.type_is64) { + return "aarch64:64"; + } else { + switch(cpu.subtype_arm) { + case CPU_SUBTYPE_ARM_V7: + case CPU_SUBTYPE_ARM_V7S: + case CPU_SUBTYPE_ARM_V7K: + case CPU_SUBTYPE_ARM_V7M: + case CPU_SUBTYPE_ARM_V7EM: + return "armv7:32:el:eabi:hardfp"; + case CPU_SUBTYPE_ARM_V6: + case CPU_SUBTYPE_ARM_V6M: + return "armv6:32:el:eabi:hardfp"; + default: + return "arm:32"; + } + } + case CPU_TYPE_POWERPC: + if (cpu.type_is64) { + return "powerpc:64:eb"; + } else { + return "powerpc:32:eb"; + } + case CPU_TYPE_X86: + if (cpu.type_is64) { + return "x86:64"; + } else { + return "x86:32"; + } + default: + return "other"; + } +} + + +int +pkg_get_myarch_macho(int fd, char *dest, size_t sz, struct os_info *oi) +{ + ssize_t x; + + macho_file_t *mf = 0; + build_version_t *bv = 0; + + if ((x = read_macho_file(fd, &mf)) < 0) { + goto cleanup; + } + + if (0 == mf->narch) { + goto cleanup; + } + if (mf->narch > 1) { + pkg_debug(1, "Found %d entries, picking first", mf->narch); + } + fat_arch_t *p = mf->arch; + + if (-1 == (x = lseek(fd, p->offset, SEEK_SET))) { + goto cleanup; + } + size_t n = 0; + macho_header_t mh; + if ((x = read_macho_header(fd, &mh)) < 0) { + goto cleanup; + } + const bool swap = mh.swap; + n = 0; + for (uint32_t ui = mh.ncmds; ui-- > 0;) { + size_t n0 = n; + uint32_t loadcmdtype; + uint32_t loadcmdsize; + READ(u32, loadcmdtype); + READ(u32, loadcmdsize); + enum MachOLoadCommand loadcmd = loadcmdtype & + ~LC_REQ_DYLD; + switch (loadcmd) { + case LC_BUILD_VERSION: + if (bv) { // overwrite previous LC_VERSION_MIN_X + // values + free(bv); + bv = 0; + } + READ(build_version, bv); + break; + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_WATCHOS: + if (!bv) { + if ((x = read_min_version(fd, swap, + loadcmd, &bv)) < 0) { + goto cleanup; + } + n += x; + break; + } + // have seen the more precise + // LC_BUILD_VERSION already + // fall through and disregard this + default: + if (-1 == + (x = lseek(fd, loadcmdsize - 8, + SEEK_CUR))) { + goto cleanup; + } + n += loadcmdsize - 8; + break; + } + if (n - n0 != loadcmdsize) { + printf("unprecise read %u != %u", n - n0, + loadcmdsize); + errno = EINVAL; + goto cleanup; + } + if (n > mh.sizeofcmds) { + printf("long read %u > %u", n, mh.sizeofcmds); + errno = EINVAL; + goto cleanup; + } + } + + if (bv) { + macho_version_t darwin; + map_platform_to_darwin(&darwin, bv->platform, bv->minos); + snprintf(dest, sz, "Darwin:%d:%s", darwin.major, cputype_to_elfname(mh.cpu)); + if (oi) { + oi->name = xstrdup("Darwin"); + oi->osversion = darwin.major * 100000 + darwin.minor * 1000 + darwin.patch; + if (darwin.patch) { + xasprintf(&oi->version, "%d.%d.%d", darwin.major, darwin.minor, darwin.patch); + } else { + xasprintf(&oi->version, "%d.%d", darwin.major, darwin.minor); + } + xasprintf(&oi->version_major, "%d", darwin.major); + xasprintf(&oi->version_minor, "%d", darwin.minor); + oi->arch = xstrdup(cputype_to_freebsd_machine_arch( + mh.cpu)); + } + return EPKG_OK; + } + + +cleanup: + if (bv) { + free(bv); + } + if (mf) { + free(mf); + } + return EPKG_FATAL; +} + + +int pkg_analyse_init_macho(__unused const char* stage) { + return EPKG_OK; +} + +int pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fpath) { + int ret = EPKG_OK; + // int ret = analyse_macho(pkg, fpath); + if (developer_mode) { + if (ret != EPKG_OK && ret != EPKG_END) { + return EPKG_WARN; + } + } + return ret; +} + +int pkg_analyse_close_macho() { + return EPKG_OK; +} \ No newline at end of file diff --git a/libpkg/pkg_config.c b/libpkg/pkg_config.c index 69b3ebcb34..4875d50f33 100644 --- a/libpkg/pkg_config.c +++ b/libpkg/pkg_config.c @@ -1114,8 +1114,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags) memset(&oi, 0, sizeof(oi)); envabi = getenv("ABI"); if (envabi == NULL) { - pkg_get_myarch(myabi, BUFSIZ, &oi); - pkg_get_myarch_legacy(myabi_legacy, BUFSIZ); + pkg_get_myarch_with_legacy(myabi, myabi_legacy, BUFSIZ, &oi); } else { strlcpy(myabi, envabi, sizeof(myabi)); pkg_arch_to_legacy(myabi, myabi_legacy, BUFSIZ); diff --git a/libpkg/pkg_elf.c b/libpkg/pkg_elf.c index 2b33aeb68c..161de04799 100644 --- a/libpkg/pkg_elf.c +++ b/libpkg/pkg_elf.c @@ -71,7 +71,6 @@ #define NT_ABI_TAG 1 #endif -#define _PATH_UNAME "/usr/bin/uname" /* FFR: when we support installing a 32bit package on a 64bit host */ #define _PATH_ELF32_HINTS "/var/run/ld-elf32.so.hints" @@ -301,8 +300,8 @@ analyse_elf(struct pkg *pkg, const char *fpath) pkg->flags |= PKG_CONTAINS_ELF_OBJECTS; if (gelf_getehdr(e, &elfhdr) == NULL) { - ret = EPKG_FATAL; - pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1)); + ret = EPKG_WARN; + pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } @@ -464,103 +463,6 @@ analyse_fpath(struct pkg *pkg, const char *fpath) return (EPKG_OK); } -int -pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage) -{ - struct pkg_file *file = NULL; - int ret = EPKG_OK; - char fpath[MAXPATHLEN +1]; - const char *lib; - bool failures = false; - - if (tll_length(pkg->shlibs_required) != 0) { - tll_free_and_free(pkg->shlibs_required, free); - } - - if (tll_length(pkg->shlibs_provided) != 0) { - tll_free_and_free(pkg->shlibs_provided, free); - } - - if (elf_version(EV_CURRENT) == EV_NONE) - return (EPKG_FATAL); - - shlib_list_init(); - - if (stage != NULL && pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) { - /* Do not check the return */ - shlib_list_from_stage(stage); - } - - ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS); - if (ret != EPKG_OK) - goto cleanup; - - /* Assume no architecture dependence, for contradiction */ - if (ctx.developer_mode) - pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS | - PKG_CONTAINS_STATIC_LIBS | - PKG_CONTAINS_LA); - - while (pkg_files(pkg, &file) == EPKG_OK) { - if (stage != NULL) - snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path); - else - strlcpy(fpath, file->path, sizeof(fpath)); - - ret = analyse_elf(pkg, fpath); - if (ctx.developer_mode) { - if (ret != EPKG_OK && ret != EPKG_END) { - failures = true; - continue; - } - analyse_fpath(pkg, fpath); - } - } - - /* - * Do not depend on libraries that a package provides itself - */ - tll_foreach(pkg->shlibs_required, s) { - if (stringlist_contains(&pkg->shlibs_provided, s->item)) { - pkg_debug(2, "remove %s from required shlibs as the " - "package %s provides this library itself", - s->item, pkg->name); - tll_remove_and_free(pkg->shlibs_required, s, free); - continue; - } - file = NULL; - while (pkg_files(pkg, &file) == EPKG_OK) { - if ((lib = strstr(file->path, s->item)) != NULL && - strlen(lib) == strlen(s->item) && lib[-1] == '/') { - pkg_debug(2, "remove %s from required shlibs as " - "the package %s provides this file itself", - s->item, pkg->name); - - tll_remove_and_free(pkg->shlibs_required, s, free); - break; - } - } - } - - /* - * if the package is not supposed to provide share libraries then - * drop the provided one - */ - if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) { - tll_free_and_free(pkg->shlibs_provided, free); - } - - if (failures) - goto cleanup; - - ret = EPKG_OK; - -cleanup: - shlib_list_free(); - - return (ret); -} - static const char * elf_corres_to_string(const struct _elf_corres* m, int e) { @@ -815,71 +717,26 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi) } -static int -pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi) +int +pkg_get_myarch_elfparse(int fd, char *dest, size_t sz, struct os_info *oi) { - char rooted_abi_file[PATH_MAX]; Elf *elf = NULL; GElf_Ehdr elfhdr; GElf_Shdr shdr; Elf_Data *data; Elf_Scn *scn = NULL; - int fd, i; int ret = EPKG_OK; - const char *arch, *abi, *endian_corres_str, *wordsize_corres_str, *fpu; - bool checkroot; - struct os_info loi; + const char *arch,*abi, *endian_corres_str, *wordsize_corres_str, *fpu; size_t dsz; - const char *abi_files[] = { - getenv("ABI_FILE"), - _PATH_UNAME, - _PATH_BSHELL, - }; - arch = NULL; - if (oi == NULL) { - memset(&loi, 0, sizeof(loi)); - oi = &loi; - } - if (elf_version(EV_CURRENT) == EV_NONE) { pkg_emit_error("ELF library initialization failed: %s", elf_errmsg(-1)); return (EPKG_FATAL); } - /* - * Perhaps not yet needed, but it may be in the future that there's no - * need to check root under some conditions where there is a rootdir. - * This also helps alleviate some excessive wrapping later. - */ - checkroot = ctx.pkg_rootdir != NULL; - for (fd = -1, i = 0; i < NELEM(abi_files); i++) { - if (abi_files[i] == NULL) - continue; - /* - * Try prepending rootdir and using that if it exists. If - * ABI_FILE is specified, assume that the consumer didn't want - * it mangled by rootdir. - */ - if (i > 0 && checkroot && snprintf(rooted_abi_file, PATH_MAX, - "%s/%s", ctx.pkg_rootdir, abi_files[i]) < PATH_MAX) { - if ((fd = open(rooted_abi_file, O_RDONLY)) >= 0) - break; - } - if ((fd = open(abi_files[i], O_RDONLY)) >= 0) - break; - /* if the ABI_FILE was provided we only care about it */ - if (i == 0) - break; - } - if (fd == -1) { - pkg_emit_error("Unable to determine the ABI\n"); - return (EPKG_FATAL); - } - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { ret = EPKG_FATAL; pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1)); @@ -887,12 +744,11 @@ pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi) } if (gelf_getehdr(elf, &elfhdr) == NULL) { - ret = EPKG_FATAL; - pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1)); + ret = EPKG_WARN; + pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1)); goto cleanup; } - while ((scn = elf_nextscn(elf, scn)) != NULL) { if (gelf_getshdr(scn, &shdr) != &shdr) { ret = EPKG_FATAL; @@ -1073,119 +929,36 @@ pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi) cleanup: if (elf != NULL) elf_end(elf); - if (oi == &loi) { - free(oi->name); - free(oi->version); - free(oi->version_major); - free(oi->version_minor); - free(oi->arch); - } - close(fd); return (ret); } -int -pkg_arch_to_legacy(const char *arch, char *dest, size_t sz) -{ - int i = 0; - struct arch_trans *arch_trans; - - memset(dest, '\0', sz); - /* Lower case the OS */ - while (arch[i] != ':' && arch[i] != '\0') { - dest[i] = tolower(arch[i]); - i++; - } - if (arch[i] == '\0') - return (0); - - dest[i++] = ':'; - - /* Copy the version */ - while (arch[i] != ':' && arch[i] != '\0') { - dest[i] = arch[i]; - i++; - } - if (arch[i] == '\0') - return (0); +int pkg_analyse_init_elf(const char* stage) { + if (elf_version(EV_CURRENT) == EV_NONE) + return (EPKG_FATAL); - dest[i++] = ':'; + shlib_list_init(); - for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL; - arch_trans++) { - if (STREQ(arch + i, arch_trans->archid)) { - strlcpy(dest + i, arch_trans->elftype, - sz - (arch + i - dest)); - return (0); - } + if (stage != NULL && pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) { + /* Do not check the return */ + shlib_list_from_stage(stage); } - strlcpy(dest + i, arch + i, sz - (arch + i - dest)); - return (0); + int ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS); + return ret; } -int -pkg_get_myarch_legacy(char *dest, size_t sz) -{ - int i, err; - size_t dsz; - - err = pkg_get_myarch_elfparse(dest, sz, NULL); - if (err) - return (err); - - dsz = strlen(dest); - for (i = 0; i < dsz; i++) - dest[i] = tolower(dest[i]); - - return (0); -} - -int -pkg_get_myarch(char *dest, size_t sz, struct os_info *oi) -{ - struct arch_trans *arch_trans; - char *arch_tweak; - int err; - - err = pkg_get_myarch_elfparse(dest, sz, oi); - if (err) { - if (oi) { - free(oi->name); - } - return (err); - } - -#ifdef __DragonFly__ - size_t dsz; - - dsz = strlen(dest); - if (strncasecmp(dest, "DragonFly", 9) == 0) { - for (int i = 0; i < dsz; i++) - dest[i] = tolower(dest[i]); - return (0); - } -#endif - - /* Translate architecture string back to regular OS one */ - arch_tweak = strchr(dest, ':'); - if (arch_tweak == NULL) - return (0); - arch_tweak++; - arch_tweak = strchr(arch_tweak, ':'); - if (arch_tweak == NULL) - return (0); - arch_tweak++; - for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL; - arch_trans++) { - if (STREQ(arch_tweak, arch_trans->elftype)) { - strlcpy(arch_tweak, arch_trans->archid, - sz - (arch_tweak - dest)); - oi->arch = xstrdup(arch_tweak); - break; +int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath) { + int ret = analyse_elf(pkg, fpath); + if (developer_mode) { + if (ret != EPKG_OK && ret != EPKG_END) { + return EPKG_WARN; + } + analyse_fpath(pkg, fpath); } - } - - return (0); + return ret; } +int pkg_analyse_close_elf() { + shlib_list_free(); + return EPKG_OK; +} \ No newline at end of file diff --git a/libpkg/private/binfmt_macho.h b/libpkg/private/binfmt_macho.h new file mode 100644 index 0000000000..9997ce1a42 --- /dev/null +++ b/libpkg/private/binfmt_macho.h @@ -0,0 +1,324 @@ +/*- + * Copyright (c) 2024 Keve Müller + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PKG_BINFMT_MACHO_H +#define _PKG_BINFMT_MACHO_H + +#include + +#include +#include + +/**** Magic numbers & constants ****/ + +// Constants for magic (big&little endian) +#define MH_MAGIC 0xFEEDFACEu +#define MH_CIGAM 0xCEFAEDFEu +#define MH_MAGIC_64 0xFEEDFACFu +#define MH_CIGAM_64 0xCFFAEDFEu +#define FAT_MAGIC 0xCAFEBABEu +#define FAT_CIGAM 0xBEBAFECAu +#define FAT_MAGIC_64 0xCAFEBABFu +#define FAT_CIGAM_64 0xBFBAFECAu + +// Masks for CPUType capability bits +static const uint32_t CPU_ARCH_MASK = 0xff000000u; +static const uint32_t CPU_ARCH_ABI64 = 0x01000000u; // 64 bit ABI +static const uint32_t CPU_ARCH_ABI64_32 = + 0x02000000u; // ILP32 ABI on 64-bit hardware + +// Masks for the CPUSubType +static const uint32_t CPU_SUBTYPE_MASK = + 0xff000000u; // Mask for architecture bits +static const uint32_t CPU_SUBTYPE_LIB64 = 0x80000000u; // 64 bit libraries +// static const uint32_t CPU_SUBTYPE_MULTIPLE = ~0u; + +// // arm64e uses the capability bits to encode ptrauth ABI information. +// // Bit 63 marks the binary as Versioned. +// CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK = 0x80000000U, +// // Bit 62 marks the binary as using a kernel ABI. +// CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK = 0x40000000U, +// // Bits [59:56] hold the 4-bit ptrauth ABI version. +// CPU_SUBTYPE_ARM64E_PTRAUTH_MASK = 0x0f000000U, + +enum CPUType { + CPU_TYPE_ANY = -1, + CPU_TYPE_VAX = 1, + CPU_TYPE_ROMP, + CPU_TYPE_NS32032 = 4, + CPU_TYPE_NS32332, + CPU_TYPE_MC680x0, + CPU_TYPE_X86, + CPU_TYPE_MIPS, + CPU_TYPE_NS32352, + CPU_TYPE_MC98000, + CPU_TYPE_HPPA, + CPU_TYPE_ARM, + CPU_TYPE_MC88000, + CPU_TYPE_SPARC, + CPU_TYPE_I860BE, + CPU_TYPE_I860LE, + CPU_TYPE_RS6000, + CPU_TYPE_POWERPC +}; + +enum CPUSubTypeX86 { + CPU_SUBTYPE_X86_INVALID = -1, + CPU_SUBTYPE_X86_ALL = 3, + CPU_SUBTYPE_486 = 4, + CPU_SUBTYPE_486SX = 0x84, + CPU_SUBTYPE_586 = 5, + CPU_SUBTYPE_PENTPRO = 0x16, + CPU_SUBTYPE_PENTII_M3 = 0x36, + CPU_SUBTYPE_PENTII_M5 = 0x56, + CPU_SUBTYPE_CELERON = 0x67, + CPU_SUBTYPE_CELERON_MOBILE = 0x77, + CPU_SUBTYPE_PENTIUM_3 = 0x08, + CPU_SUBTYPE_PENTIUM_3_M = 0x18, + CPU_SUBTYPE_PENTIUM_3_XEON = 0x28, + CPU_SUBTYPE_PENTIUM_M = 0x09, + CPU_SUBTYPE_PENTIUM_4 = 0x0a, + CPU_SUBTYPE_PENTIUM_4_M = 0x1a, + CPU_SUBTYPE_ITANIUM = 0x0b, + CPU_SUBTYPE_ITANIUM_2 = 0x1b, + CPU_SUBTYPE_XEON = 0x0c, + CPU_SUBTYPE_XEON_MP = 0x1c +}; + +enum CPUSubTypeARM { + CPU_SUBTYPE_ARM_INVALID = -1, + CPU_SUBTYPE_ARM_ALL, + CPU_SUBTYPE_ARM64_V8, + CPU_SUBTYPE_ARM64E, + CPU_SUBTYPE_ARM_V4T = 5, + CPU_SUBTYPE_ARM_V6, + CPU_SUBTYPE_ARM_V5, + CPU_SUBTYPE_ARM_V5TEJ = CPU_SUBTYPE_ARM_V5, + CPU_SUBTYPE_ARM_XSCALE, + CPU_SUBTYPE_ARM_V7, + CPU_SUBTYPE_ARM_V7S = 11, + CPU_SUBTYPE_ARM_V7K, + CPU_SUBTYPE_ARM_V6M = 14, + CPU_SUBTYPE_ARM_V7M, + CPU_SUBTYPE_ARM_V7EM +}; + +enum CPUSubTypePPC { + CPU_SUBTYPE_POWERPC_ALL = 0, + CPU_SUBTYPE_POWERPC_601, + CPU_SUBTYPE_POWERPC_602, + CPU_SUBTYPE_POWERPC_603, + CPU_SUBTYPE_POWERPC_603e, + CPU_SUBTYPE_POWERPC_603ev, + CPU_SUBTYPE_POWERPC_604, + CPU_SUBTYPE_POWERPC_604e, + CPU_SUBTYPE_POWERPC_620, + CPU_SUBTYPE_POWERPC_750, + CPU_SUBTYPE_POWERPC_7400, + CPU_SUBTYPE_POWERPC_7450, + CPU_SUBTYPE_POWERPC_970 = 100, + + CPU_SUBTYPE_MC980000_ALL = CPU_SUBTYPE_POWERPC_ALL, + CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601 +}; + +enum MachOFileType { + MH_OBJECT = 0x1, + MH_EXECUTE = 0x2, + MH_FVMLIB = 0x3, + MH_CORE = 0x4, + MH_PRELOAD = 0x5, + MH_DYLIB = 0x6, + MH_DYLINKER = 0x7, + MH_BUNDLE = 0x8, + MH_DYLIB_STUB = 0x9, + MH_DSYM = 0xA, + MH_KEXT_BUNDLE = 0xB, + MH_FILESET = 0xC +}; + +static const uint32_t LC_REQ_DYLD = 0x80000000u; // required load command flag + +enum MachOLoadCommand { + LC_SEGMENT = 1, + LC_SYMTAB, + LC_SYMSEG, + LC_THREAD, + LC_UNIXTHREAD, + LC_LOADFVMLIB, + LC_IDFVMLIB, + LC_IDENT, + LC_FVMFILE, + LC_PREPAGE, + LC_DYSYMTAB, + LC_LOAD_DYLIB, + LC_ID_DYLIB, + LC_LOAD_DYLINKER, + LC_ID_DYLINKER, + LC_PREBOUND_DYLIB, + LC_ROUTINES, + LC_SUB_FRAMEWORK, + LC_SUB_UMBRELLA, + LC_SUB_CLIENT, + LC_SUB_LIBRARY, + LC_TWOLEVEL_HINTS, + LC_PREBIND_CKSUM, + LC_LOAD_WEAK_DYLIB, + LC_SEGMENT_64, + LC_ROUTINES_64, + LC_UUID, + LC_RPATH, + LC_CODE_SIGNATURE, + LC_SEGMENT_SPLIT_INFO, + LC_REEXPORT_DYLIB, + LC_LAZY_LOAD_DYLIB, + LC_ENCRYPTION_INFO, + LC_DYLD_INFO, + LC_DYLD_INFO_ONLY = LC_DYLD_INFO, + LC_LOAD_UPWARD_DYLIB, + LC_VERSION_MIN_MACOSX, + LC_VERSION_MIN_IPHONEOS, + LC_FUNCTION_STARTS, + LC_DYLD_ENVIRONMENT, + LC_MAIN, + LC_DATA_IN_CODE, + LC_SOURCE_VERSION, + LC_DYLIB_CODE_SIGN_DRS, + LC_ENCRYPTION_INFO_64, + LC_LINKER_OPTION, + LC_LINKER_OPTIMIZATION_HINT, + LC_VERSION_MIN_TVOS, + LC_VERSION_MIN_WATCHOS, + LC_NOTE, + LC_BUILD_VERSION, + LC_DYLD_EXPORTS_TRIE, + LC_DYLD_CHAINED_FIXUPS, + LC_FILESET_ENTRY, + LC_ATOM_INFO +}; + +enum MachoPlatform { + PLATFORM_UNKNOWN = 0, + PLATFORM_MACOS, + PLATFORM_IOS, + PLATFORM_TVOS, + PLATFORM_WATCHOS, + PLATFORM_BRIDGEOS, + PLATFORM_MACCATALYST, + PLATFORM_IOSSIMULATOR, + PLATFORM_TVOSSIMULATOR, + PLATFORM_WATCHOSSIMULATOR, + PLATFORM_DRIVERKIT, + PLATFORM_XROS, + PLATFORM_XROS_SIMULATOR +}; + +enum MachoTool { TOOL_CLANG = 1, TOOL_SWIFT, TOOL_LD, TOOL_LLD }; + +/**** Unpacked structures ****/ + +typedef struct cpu_type_subtype { + enum CPUType type; + bool type_is64; + bool type_is64_32; + union { + enum CPUSubTypeX86 subtype_x86; + enum CPUSubTypeARM subtype_arm; + enum CPUSubTypePPC subtype_ppc; + }; + bool subtype_islib64; +} cpu_type_subtype_t; + +typedef struct fat_arch { + struct cpu_type_subtype cpu; + uint64_t offset; + uint64_t size; + uint_fast8_t align; +} fat_arch_t; + +typedef struct macho_file { + uint32_t magic; + uint32_t narch; + fat_arch_t arch[]; +} macho_file_t; + +typedef struct macho_header { + uint32_t magic; + bool swap; + cpu_type_subtype_t cpu; + enum MachOFileType filetype; + uint32_t ncmds; + uint32_t sizeofcmds; + uint32_t flags; +} macho_header_t; + +typedef struct macho_version { + uint_fast16_t major; + uint_fast16_t minor; + uint_fast16_t patch; +} macho_version_t; + +typedef struct tool_version { + enum MachoTool tool; + macho_version_t version; +} tool_version_t; + +typedef struct build_version { + enum MachoPlatform platform; + macho_version_t minos; + macho_version_t sdk; + uint32_t ntools; + tool_version_t tools[]; +} build_version_t; + +typedef struct dylib { + uint32_t timestamp; + macho_version_t current_version; + macho_version_t compatibility_version; + char path[]; +} dylib_t; + +/**** Function prototypes ****/ + +/* utility */ +int map_platform_to_darwin(macho_version_t *darwin, + const enum MachoPlatform platform, const macho_version_t version); + +/* readers */ +ssize_t read_macho_file(const int fd, macho_file_t **dest); +ssize_t read_macho_header(const int fd, macho_header_t *dest); +ssize_t read_build_version(const int fd, const bool swap, + build_version_t **dest); +ssize_t read_min_version(const int fd, const bool swap, const uint32_t loadcmd, + build_version_t **dest); + +#define READ(f, var) \ + if ((x = read_##f(fd, swap, &var)) < 0) { \ + return x; \ + } \ + n += x +ssize_t read_u32(const int fd, const bool swap, uint32_t *dest); + +#endif \ No newline at end of file diff --git a/libpkg/private/elf_tables.h b/libpkg/private/elf_tables.h index a1e2499bc4..640c6556ce 100644 --- a/libpkg/private/elf_tables.h +++ b/libpkg/private/elf_tables.h @@ -74,38 +74,6 @@ static const struct _elf_corres os_corres[] = { #define NT_ARCH 2 #define NT_GNU_ABI_TAG 1 -/* All possibilities on FreeBSD as of 5/26/2014 */ -struct arch_trans { - const char *elftype; - const char *archid; -}; - -static struct arch_trans machine_arch_translation[] = { - { "x86:32", "i386" }, - { "x86:64", "amd64" }, - { "powerpc:32:eb", "powerpc" }, - { "powerpc:64:eb", "powerpc64" }, - { "powerpc:64:el", "powerpc64le" }, - { "sparc64:64", "sparc64" }, - { "ia64:64", "ia64" }, - /* All the ARM stuff */ - { "armv6:32:el:eabi:hardfp", "armv6" }, - { "armv7:32:el:eabi:hardfp", "armv7" }, - { "aarch64:64", "aarch64" }, - /* And now MIPS */ - { "mips:32:el:o32", "mipsel" }, - { "mips:32:el:n32", "mipsn32el" }, - { "mips:32:eb:o32", "mips" }, - { "mips:32:eb:n32", "mipsn32" }, - { "mips:64:el:n64", "mips64el" }, - { "mips:64:eb:n64", "mips64" }, - /* And RISC-V */ - { "riscv:32:hf", "riscv32" }, - { "riscv:32:sf", "riscv32sf" }, - { "riscv:64:hf", "riscv64" }, - { "riscv:64:sf", "riscv64sf" }, - { NULL, NULL } -}; #endif /* ELF_TABLES_H_ */ diff --git a/libpkg/private/pkg.h b/libpkg/private/pkg.h index 19a9ad476e..48894f54dc 100644 --- a/libpkg/private/pkg.h +++ b/libpkg/private/pkg.h @@ -640,8 +640,7 @@ struct os_info { char *arch; }; -int pkg_get_myarch(char *pkgarch, size_t sz, struct os_info *); -int pkg_get_myarch_legacy(char *pkgarch, size_t sz); +int pkg_get_myarch_with_legacy(char *pkgarch, char* legacy, size_t sz, struct os_info *); /** * Remove and unregister the package. diff --git a/src/Makefile.autosetup b/src/Makefile.autosetup index fc02d835fd..651d8cefa0 100644 --- a/src/Makefile.autosetup +++ b/src/Makefile.autosetup @@ -69,10 +69,6 @@ OTHER_LIBS+= -lfts OTHER_LIBS+= -ldl @endif -@if HAVE_LIBRESOLV -OTHER_LIBS+= -lresolv -@endif - @if HAVE_LIBMD OTHER_LIBS+= -lmd @endif @@ -89,7 +85,7 @@ LOCAL_CFLAGS+= @PKG_LIBCURL_CFLAGS@ OTHER_LIBS+= @PKG_LIBCURL_LDFLAGS@ @PKG_LIBCURL_LIBS@ @endif -@if libmachista +@if pkgos_darwin LOCAL_LDFLAGS= $(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv STATIC_LDFLAGS= $(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv # OSX doesn't support static binaries, sigh diff --git a/tests/Makefile.autosetup b/tests/Makefile.autosetup index 5b1939fba2..aee5d73e9e 100644 --- a/tests/Makefile.autosetup +++ b/tests/Makefile.autosetup @@ -134,9 +134,6 @@ OTHER_LIBS+= -lfts @if HAVE_LIBDL OTHER_LIBS+= -ldl @endif -@if HAVE_LIBRESOLV -OTHER_LIBS+= -lresolv -@endif @if PKG_LIBCURL_LIBS CFLAGS+= @PKG_LIBCURL_CFLAGS@ LIBS+= @PKG_LIBCURL_LDFLAGS@ @PKG_LIBCURL_LIBS@ @@ -150,7 +147,7 @@ OTHER_LIBS+= -lssl -lcrypto # Hack to determine we are on osx -@if libmachista +@if pkgos_darwin OTHER_LIBS+= -lresolv @endif diff --git a/tests/cocci/README.md b/tests/cocci/README.md index bbe1f793e3..f6ded73bd9 100644 --- a/tests/cocci/README.md +++ b/tests/cocci/README.md @@ -23,7 +23,7 @@ From the pkg's source root (use _libpkg_ or _src_ as `$DIR`): % spatch -I . -I /usr/include -I /usr/local/include -I libpkg -I src \ -I external/blake2 -I external/yxml -I external/include \ - -I external/libelf -I external/libfetch -I external/libmachista \ + -I external/libelf -I external/libfetch \ -I external/libsbuf -I external/libucl/include -I external/linenoise \ -I external/picosat -I external/sqlite \ -in_place -sp_file ./tests/cocci/$TESTFILE.cocci -dir $DIR diff --git a/tests/frontend/abi.sh b/tests/frontend/abi.sh index a7b5f5be81..c75f5969f6 100644 --- a/tests/frontend/abi.sh +++ b/tests/frontend/abi.sh @@ -2,23 +2,53 @@ . $(atf_get_srcdir)/test_environment.sh tests_init \ - basic + elfparse \ + native \ + override -basic_body() { - _uname_s="$(uname -s)" - _expected="TODO: implement me" - if [ "${_uname_s}" = "Darwin" ]; then - # The FreeBSD ELF ABI_FILE should is ignored on non-ELF platforms: - _expected="${_uname_s}:$(uname -r | cut -d. -f1):$(uname -p)\n" - else - # Otherwise the ABI should be parsed from the ELF file. - _expected="FreeBSD:13:amd64\n" - fi +native_body() { + _expected="$(uname -s):$(uname -r | cut -d. -f1):$(uname -p | sed s/x86_64/amd64/)\n" + atf_check \ + -o inline:"${_expected}" \ + pkg config abi + + _expected="$(uname -s | tolower):$(uname -r | cut -d. -f1):$(uname -p | sed s/x86_64/x86:64/)\n" + atf_check \ + -o inline:"${_expected}" \ + pkg config altabi +} + +override_body() { + _expected="FreeBSD:12:powerpc\n" + atf_check \ + -o inline:"${_expected}" \ + pkg -o ABI=FreeBSD:12:powerpc config abi + + _expected="freebsd:12:powerpc:32:eb\n" + atf_check \ + -o inline:"${_expected}" \ + pkg -o ABI=FreeBSD:12:powerpc config altabi +} + +elfparse_body() { + # ELF parsing now works across platforms + _expected="FreeBSD:13:amd64\n" atf_check \ -o inline:"${_expected}" \ pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config abi -# atf_check \ -# -o inline:"dragonfly:5.10:x86:64\n" \ -# pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/dfly.bin config abi + _expected="freebsd:13:x86:64\n" + atf_check \ + -o inline:"${_expected}" \ + pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config altabi + + _expected="DragonFly:5:amd64\n" + atf_check \ + -o inline:"${_expected}" \ + pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/dfly.bin config abi + + _expected="dragonfly:5:x86:64\n" + atf_check \ + -o inline:"${_expected}" \ + pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/dfly.bin config altabi }