Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
ifreund committed Nov 25, 2024
1 parent 0b60265 commit 504fbc0
Show file tree
Hide file tree
Showing 12 changed files with 673 additions and 531 deletions.
3 changes: 2 additions & 1 deletion libpkg/elfhints.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
*/

#include <bsd_compat.h>
#include "private/pkg_abi.h"
#include <sys/mman.h>
#include <sys/stat.h>
#ifdef HAVE_SYS_ENDIAN_H
Expand Down Expand Up @@ -315,7 +316,7 @@ int shlib_list_from_rpath(const char *rpath_str, const char *dirpath)
int
shlib_list_from_elf_hints(const char *hintsfile)
{
if (ctx.oi->ostype == OS_FREEBSD || ctx.oi->ostype == OS_DRAGONFLY)
if (ctx.abi.os == PKG_OS_FREEBSD || ctx.abi.os == PKG_OS_DRAGONFLY)
read_elf_hints(hintsfile, 1);

return (scan_dirs_for_shlibs(&shlibs, ndirs, dirs, true));
Expand Down
301 changes: 247 additions & 54 deletions libpkg/pkg_abi.c
Original file line number Diff line number Diff line change
@@ -1,41 +1,28 @@
/*-
* Copyright (c) 2011-2012 Baptiste Daroussin <[email protected]>
* Copyright (c) 2012-2013 Matthew Seaman <[email protected]>
* All rights reserved.
* Copyright (c) 2024 The FreeBSD Foundation
*
* 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 was developed in part by Isaac Freund <[email protected]>
* under sponsorship from the FreeBSD Foundation.
*
* 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.
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifdef HAVE_CONFIG_H
#include "pkg_config.h"
#endif

#include <ctype.h>
#include <paths.h>
#include <string.h>
#include <unistd.h>

#include "pkg.h"
#include "private/pkg_abi.h"
#include "private/binfmt.h"
#include "private/event.h"
#include "private/pkg.h"
#include "xmalloc.h"

#define _PATH_UNAME "/usr/bin/uname"

Expand All @@ -62,8 +49,229 @@ static struct arch_trans machine_arch_translation[] = { { "x86:32", "i386" },

{ NULL, NULL } };

static int
pkg_get_myarch_fromfile(struct os_info *oi)
static struct {
enum pkg_os os;
const char *string;
} os_string_table[] = {
{ PKG_OS_UNKNOWN, "Unknown" },
{ PKG_OS_FREEBSD, "FreeBSD" },
{ PKG_OS_NETBSD, "NetBSD" },
{ PKG_OS_DRAGONFLY, "DragonFly" },
{ PKG_OS_LINUX, "Linux" },
{ PKG_OS_MACOS, "Darwin" },
{ -1, NULL },
};

/* This table does not include PKG_ARCH_AMD64 as the string translation of
that arch is os-dependent. */
static struct {
enum pkg_arch arch;
const char *string;
} arch_string_table[] = {
{ PKG_ARCH_UNKNOWN, "unknown"},
{ PKG_ARCH_I386, "i386"},
{ PKG_ARCH_ARMV6, "armv6"},
{ PKG_ARCH_ARMV7, "armv7"},
{ PKG_ARCH_AARCH64, "aarch64"},
{ PKG_ARCH_POWERPC, "powerpc"},
{ PKG_ARCH_POWERPC64, "powerpc64"},
{ PKG_ARCH_POWERPC64LE, "powerpc64le"},
{ PKG_ARCH_RISCV32, "riscv32"},
{ PKG_ARCH_RISCV64, "riscv64"},
{ -1, NULL },
};

const char *
pkg_os_to_string(enum pkg_os os)
{
for (size_t i = 0; os_string_table[i].string != NULL; i++) {
if (os == os_string_table[i].os) {
return os_string_table[i].string;
}
}
assert(0);
}

enum pkg_os
pkg_os_from_string(const char *string)
{
for (size_t i = 0; os_string_table[i].string != NULL; i++) {
if (STREQ(string, os_string_table[i].string)) {
return os_string_table[i].os;
}
}
return (PKG_OS_UNKNOWN);
}

const char *
pkg_arch_to_string(enum pkg_os os, enum pkg_arch arch)
{
if (arch == PKG_ARCH_AMD64) {
if (os == PKG_OS_FREEBSD || os == PKG_OS_MACOS) {
return ("amd64");
} else {
return ("x86_64");
}
}

for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
if (arch == arch_string_table[i].arch) {
return arch_string_table[i].string;
}
}

assert(0);
}

enum pkg_arch
pkg_arch_from_string(enum pkg_os os, const char *string)
{

if (os == PKG_OS_FREEBSD) {
if (STREQ(string, "amd64")) {
return (PKG_ARCH_AMD64);
}
} else {
if (STREQ(string, "x86_64")) {
return (PKG_ARCH_AMD64);
}
}

for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
if (STREQ(string, arch_string_table[i].string)) {
return arch_string_table[i].arch;
}
}

return (PKG_ARCH_UNKNOWN);
}

bool
pkg_abi_string_only_major_version(enum pkg_os os)
{
switch (os) {
case PKG_OS_FREEBSD:
case PKG_OS_NETBSD:
case PKG_OS_MACOS:
return (true);
case PKG_OS_DRAGONFLY:
case PKG_OS_LINUX:
return (false);
case PKG_OS_UNKNOWN:
default:
assert (0);
}
}

char *
pkg_abi_to_string(const struct pkg_abi *abi)
{
char *ret;
if (pkg_abi_string_only_major_version(abi->os)) {
xasprintf(&ret, "%s:%d:%s", pkg_os_to_string(abi->os),
abi->major, pkg_arch_to_string(abi->os, abi->arch));
} else {
xasprintf(&ret, "%s:%d.%d:%s", pkg_os_to_string(abi->os),
abi->major, abi->minor,
pkg_arch_to_string(abi->os, abi->arch));
}
return (ret);
}

bool
pkg_abi_from_string(struct pkg_abi *abi, const char *string)
{
*abi = (struct pkg_abi){0};

bool ret = false;

char *copy = xstrdup(string);

char *iter = copy;
char *os = strsep(&iter, ":");
char *version = strsep(&iter, ":");
char *arch = strsep(&iter, ":");

assert(os != NULL);
if (version == NULL) {
pkg_emit_error("Invalid ABI string '%s', "
"missing version and architecture", string);
goto out;
}
if (arch == NULL) {
pkg_emit_error("Invalid ABI string '%s', "
"missing architecture", string);
goto out;
}
if (iter != NULL) {
pkg_emit_error("Invalid ABI string '%s', "
"too many colon separators", string);
goto out;
}

abi->os = pkg_os_from_string(os);
if (abi->os == PKG_OS_UNKNOWN) {
pkg_emit_error("Unknown OS '%s' in ABI string", os);
goto out;
}

const char *errstr = NULL;
if (pkg_abi_string_only_major_version(abi->os)) {
abi->major = strtonum(version, 1, INT_MAX, &errstr);
} else {
/* XXX add tests for this */
char *major = strsep(&version, ".");
char *minor = strsep(&version, ".");

assert(major != NULL);
if (minor == NULL) {
pkg_emit_error("Invalid ABI string %s, "
"missing minor OS version", string);
goto out;
}

abi->major = strtonum(major, 1, INT_MAX, &errstr);
if (errstr != NULL) {
abi->minor = strtonum(minor, 1, INT_MAX, &errstr);
}
}

if (errstr != NULL) {
pkg_emit_error("Invalid version in ABI string '%s'", string);
goto out;
}

abi->arch = pkg_arch_from_string(abi->os, arch);
if (abi->arch == PKG_ARCH_UNKNOWN) {
pkg_emit_error("Unknown architecture '%s' in ABI string", arch);
goto out;
}

ret = true;

out:
free(copy);
return (ret);
}

void pkg_abi_set_freebsd_osversion(struct pkg_abi *abi, int osversion)
{
assert(abi->os == PKG_OS_FREEBSD);

abi->major = osversion / 100000;
abi->minor = (osversion / 1000) % 100;
abi->patch = osversion % 1000;
}

int pkg_abi_get_freebsd_osversion(struct pkg_abi *abi)
{
assert(abi->os == PKG_OS_FREEBSD);

return (abi->major * 100000) + (abi->minor * 1000) + abi->patch;
}

int
pkg_abi_from_file(struct pkg_abi *abi)
{
char rooted_abi_file[PATH_MAX];
const char *abi_files[] = {
Expand Down Expand Up @@ -125,59 +333,44 @@ pkg_get_myarch_fromfile(struct os_info *oi)
return EPKG_FATAL;
}

if (work_arch_hint[0]) {
snprintf(oi->abi, sizeof(oi->abi), "::%s",
work_arch_hint);
}

int ret = pkg_get_myarch_elfparse(fd, oi);
int ret = pkg_elf_abi_from_fd(fd, abi);
if (EPKG_OK != ret) {
if (-1 == lseek(fd, 0, SEEK_SET)) {
pkg_emit_errno("Error seeking file", work_abi_file);
ret = EPKG_FATAL;
goto close_out;
}

enum pkg_arch arch_hint = PKG_ARCH_UNKNOWN;
if (work_arch_hint[0]) {
pkg_arch_from_string(PKG_OS_MACOS, work_arch_hint);
if (arch_hint == PKG_ARCH_UNKNOWN) {
pkg_emit_error("Invalid ABI_FILE architecture hint %s",
work_arch_hint);
ret = EPKG_FATAL;
goto close_out;
}
}
ret = pkg_get_myarch_macho(fd, oi);

ret = pkg_macho_abi_from_fd(fd, abi, arch_hint);
if (EPKG_OK != ret) {
pkg_emit_error(
"Unable to determine the ABI, %s cannot be parsed.",
work_abi_file);
ret = EPKG_FATAL;
goto close_out;
}
}

close_out:
if (close(fd)) {
pkg_emit_errno("Error closing file", work_abi_file);
ret = EPKG_FATAL;
}
return ret;
}

int
pkg_get_myarch_with_legacy(struct os_info *oi)
{
if (oi == NULL)
return (EPKG_FATAL);
int err = pkg_get_myarch_fromfile(oi);
if (err) {
pkg_debug(1, "Error %d when trying to determine myarch.", err);
free(oi->name);
return (err);
}

pkg_arch_to_legacy(oi->abi, oi->altabi, sizeof(oi->abi));

if (oi->ostype == OS_DRAGONFLY) {
size_t dsz;

dsz = strlen(oi->abi);
for (int i = 0; i < dsz; i++)
oi->abi[i] = tolower(oi->abi[i]);
return (0);
}

return (0);
}

int
pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
{
Expand Down
Loading

0 comments on commit 504fbc0

Please sign in to comment.