Skip to content

Commit

Permalink
libpkg: fix regressions in ELF arch parsing
Browse files Browse the repository at this point in the history
Since c2fe22b, most non-amd64 architectures are parsed inadequately
from ELF files. This commit fixes the regression for architectures
supported by FreeBSD 14.x.

It also adds tests for these architectures to prevent possible
regressions in the future.

Note that not all regressions in architecture parsing from c2fe22b have
been fixed. The mips variants for example remain broken even with this
commit due to lack of test binaries.

Sponsored by:	The FreeBSD Foundation
  • Loading branch information
ifreund authored and bapt committed Nov 25, 2024
1 parent d5eb29f commit 76df8dc
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 41 deletions.
88 changes: 73 additions & 15 deletions libpkg/pkg_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,71 @@ aeabi_parse_arm_attributes(void *data, size_t length)
#undef MOVE
}

static const char *
elf_parse_arch(os_type_t ostype, Elf *elf, GElf_Ehdr *ehdr)
{
switch (ehdr->e_machine) {
case EM_386:
return ("i386");
case EM_X86_64:
switch (ostype) {
case OS_FREEBSD:
return ("amd64");
case OS_DRAGONFLY:
return ("x86:64");
default:
return ("x86_64");
}
case EM_AARCH64:
return ("aarch64");
case EM_ARM:
/* Only support EABI */
if ((ehdr->e_flags & EF_ARM_EABIMASK) == 0) {
return (NULL);
}

size_t shstrndx;
elf_getshdrstrndx(elf, &shstrndx);

GElf_Shdr shdr;
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn(elf, scn)) != NULL) {
if (gelf_getshdr(scn, &shdr) != &shdr) {
break;
}
const char *sh_name = elf_strptr(elf, shstrndx, shdr.sh_name);
if (sh_name == NULL) {
continue;
}
if (STREQ(".ARM.attributes", sh_name)) {
Elf_Data *data = elf_getdata(scn, NULL);
return (aeabi_parse_arm_attributes(data->d_buf, data->d_size));
}
}
break;
case EM_PPC:
return ("powerpc");
case EM_PPC64:
switch (ehdr->e_ident[EI_DATA]) {
case ELFDATA2MSB:
return ("powerpc64");
case ELFDATA2LSB:
return ("powerpc64le");
}
break;
case EM_RISCV:
switch (ehdr->e_ident[EI_CLASS]) {
case ELFCLASS32:
return ("riscv32");
case ELFCLASS64:
return ("riscv64");
}
break;
}

return (NULL);
}

static bool
elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
{
Expand Down Expand Up @@ -731,10 +796,8 @@ pkg_get_myarch_elfparse(int fd, struct os_info *oi)
Elf_Data *data;
Elf_Scn *scn = NULL;
int ret = EPKG_OK;
const char *arch,*abi, *endian_corres_str, *wordsize_corres_str, *fpu;
char *dest = oi->abi;
size_t sz = sizeof(oi->abi);
size_t dsz;

if (elf_version(EV_CURRENT) == EV_NONE) {
pkg_emit_error("ELF library initialization failed: %s",
Expand Down Expand Up @@ -777,20 +840,15 @@ pkg_get_myarch_elfparse(int fd, struct os_info *oi)
goto cleanup;
}

snprintf(dest, sz, "%s:%s", oi->name, oi->version);

wordsize_corres_str = elf_corres_to_string(wordsize_corres,
(int)elfhdr.e_ident[EI_CLASS]);

if (oi->ostype == OS_FREEBSD && elfhdr.e_machine == EM_X86_64)
oi->arch = xstrdup("amd64");
else if (oi->ostype == OS_DRAGONFLY && elfhdr.e_machine == EM_X86_64)
oi->arch = xstrdup("x86:64");
else
oi->arch = xstrdup(elf_corres_to_string(mach_corres, (int) elfhdr.e_machine));
const char *arch = elf_parse_arch(oi->ostype, elf, &elfhdr);
if (arch == NULL) {
ret = EPKG_FATAL;
pkg_emit_error("failed to determine the architecture");
goto cleanup;
}
oi->arch = xstrdup(arch);

dsz = strlen(dest);
snprintf(dest + dsz, sz - dsz, ":%s", oi->arch);
snprintf(dest, sz, "%s:%s:%s", oi->name, oi->version, oi->arch);

cleanup:
if (elf != NULL)
Expand Down
20 changes: 0 additions & 20 deletions libpkg/private/elf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,6 @@ static const struct _elf_corres wordsize_corres[] = {
{ -1, NULL},
};

static const struct _elf_corres endian_corres[] = {
{ ELFDATA2MSB, "eb" },
{ ELFDATA2LSB, "el" },
{ -1, NULL}
};

static const struct _elf_corres os_corres[] = {
{ ELFOSABI_FREEBSD, "freebsd" },
{ -1, NULL }
};

#ifndef EF_MIPS_ABI
#define EF_MIPS_ABI 0x0000F000
#endif
#ifndef EF_ARM_VFP_FLOAT
#define EF_ARM_VFP_FLOAT 0x00000400
#endif
#define E_MIPS_ABI_O32 0x00001000
#define E_MIPS_ABI_N32 0x00000020

#define NT_VERSION 1
#define NT_ARCH 2
#define NT_GNU_ABI_TAG 1
Expand Down
15 changes: 13 additions & 2 deletions tests/Makefile.autosetup
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,24 @@ TESTS_SH= \
frontend/triggers.sh

#
# Those files simple binaries obtained from
# These files are mostly simple binaries obtained from
# int main(void) { return 0; }
#
# The freebsd-*.bin files are copies of /usr/bin/uname from official
# 14.1 release artifacts for the given architecture.


TESTS_SHELL_BINS= \
frontend/dfly.bin \
frontend/fbsd.bin \
frontend/freebsd-aarch64.bin \
frontend/freebsd-amd64.bin \
frontend/freebsd-armv6.bin \
frontend/freebsd-armv7.bin \
frontend/freebsd-i386.bin \
frontend/freebsd-powerpc.bin \
frontend/freebsd-powerpc64.bin \
frontend/freebsd-powerpc64le.bin \
frontend/freebsd-riscv64.bin \
frontend/linux.bin \
frontend/macos.bin \
frontend/macos106.bin \
Expand Down
89 changes: 85 additions & 4 deletions tests/frontend/abi.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,96 @@ override_body() {

elfparse_body() {
# ELF parsing now works across platforms
_expected="FreeBSD:13:amd64\n"

_expected="FreeBSD:14:aarch64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-aarch64.bin config abi

_expected="freebsd:14:aarch64:64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-aarch64.bin config altabi

_expected="FreeBSD:14:amd64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-amd64.bin config abi

_expected="freebsd:14:x86:64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-amd64.bin config altabi

_expected="FreeBSD:13:armv6\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv6.bin config abi

_expected="freebsd:13:armv6:32:el:eabi:hardfp\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv6.bin config altabi

_expected="FreeBSD:14:armv7\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv7.bin config abi

_expected="freebsd:14:armv7:32:el:eabi:hardfp\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv7.bin config altabi

_expected="FreeBSD:14:i386\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-i386.bin config abi

_expected="freebsd:14:x86:32\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-i386.bin config altabi

_expected="FreeBSD:14:powerpc\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc.bin config abi

_expected="freebsd:14:powerpc:32:eb\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc.bin config altabi

_expected="FreeBSD:14:powerpc64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64.bin config abi

_expected="freebsd:14:powerpc:64:eb\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64.bin config altabi

_expected="FreeBSD:14:powerpc64le\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64le.bin config abi

_expected="freebsd:14:powerpc:64:el\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64le.bin config altabi

_expected="FreeBSD:14:riscv64\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config abi
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-riscv64.bin config abi

_expected="freebsd:13:x86:64\n"
_expected="freebsd:14:riscv:64:hf\n"
atf_check \
-o inline:"${_expected}" \
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config altabi
pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-riscv64.bin config altabi

_expected="dragonfly:5.10:x86:64\n"
atf_check \
Expand Down
Binary file removed tests/frontend/fbsd.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-aarch64.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-amd64.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-armv6.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-armv7.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-i386.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-powerpc.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-powerpc64.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-powerpc64le.binin
Binary file not shown.
Binary file added tests/frontend/freebsd-riscv64.binin
Binary file not shown.

0 comments on commit 76df8dc

Please sign in to comment.