From: Heather McIntyre <h...@rice.edu> * tests/.gitignore: Add eu_search_cfi. * tests/Makefile.am: Add eu_search_cfi, run-eu-search-cfi.sh. * tests/eu_search_cfi.c: New file. * tests/run-eu-search-cfi.sh: New file.
Signed-off-by: Heather S. McIntyre <h...@rice.edu> Signed-off-by: Aaron Merey <ame...@redhat.com> Signed-off-by: Mark Wielaard <m...@klomp.org> --- v5 changes: pthread added to eu_search_cfi_LDFLAGS unconditionally. A review for this patch has already been posted by Mark: https://sourceware.org/pipermail/elfutils-devel/2025q1/007797.html tests/.gitignore | 1 + tests/Makefile.am | 8 +- tests/eu_search_cfi.c | 201 +++++++++++++++++++++++++++++++++++++ tests/run-eu-search-cfi.sh | 31 ++++++ 4 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 tests/eu_search_cfi.c create mode 100755 tests/run-eu-search-cfi.sh diff --git a/tests/.gitignore b/tests/.gitignore index 14620fc3..bf17d646 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -67,6 +67,7 @@ /elfstrtab /elf-print-reloc-syms /emptyfile +/eu_search_cfi /fillfile /find-prologues /funcretval diff --git a/tests/Makefile.am b/tests/Makefile.am index 9ca97b6f..3b37344d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -65,6 +65,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \ msg_tst system-elf-libelf-test system-elf-gelf-test \ nvidia_extended_linemap_libdw elf-print-reloc-syms \ cu-dwp-section-info declfiles \ + eu_search_cfi \ $(asm_TESTS) asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ @@ -217,7 +218,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ run-readelf-Dd.sh run-dwfl-core-noncontig.sh run-cu-dwp-section-info.sh \ run-declfiles.sh \ - run-sysroot.sh + run-sysroot.sh run-eu-search-cfi.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -688,7 +689,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \ testfile-dwp-4-cu-index-overflow.dwp.bz2 \ testfile-dwp-cu-index-overflow.source \ testfile-define-file.bz2 \ - testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh + testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh \ + run-eu-search-cfi.sh \ thread-safety-subr.sh @@ -874,6 +876,8 @@ nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw) elf_print_reloc_syms_LDADD = $(libelf) cu_dwp_section_info_LDADD = $(libdw) declfiles_LDADD = $(libdw) +eu_search_cfi_LDFLAGS = -pthread $(AM_LDFLAGS) +eu_search_cfi_LDADD = $(libeu) $(libelf) $(libdw) # We want to test the libelf headers against the system elf.h header. # Don't include any -I CPPFLAGS. Except when we install our own elf.h. diff --git a/tests/eu_search_cfi.c b/tests/eu_search_cfi.c new file mode 100644 index 00000000..4a46ab1c --- /dev/null +++ b/tests/eu_search_cfi.c @@ -0,0 +1,201 @@ +/* Test program for eu_search_cfi + Copyright (C) 2023 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see<http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <assert.h> +#include <inttypes.h> +#include ELFUTILS_HEADER(dw) +#include <dwarf.h> +#include <argp.h> +#include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "system.h" +#include <pthread.h> + +static void handle_section (char *name, const unsigned char e_ident[], + Elf_Scn *scn, const bool is_eh); +static void *thread_work (void *arg); + +typedef struct +{ + char *name; + const unsigned char *e_ident; + Elf_Scn * scn; + bool is_eh; +} +ThreadData; + +static void *thread_work (void *arg) +{ + ThreadData *data = (ThreadData *) arg; + handle_section (data->name, data->e_ident, data->scn, data->is_eh); + return NULL; +} + +static void handle_section (char *name, const unsigned char e_ident[], + Elf_Scn *scn, const bool is_eh) +{ + if (is_eh) + printf (".eh_frame\n"); + else + printf (".debug_frame\n"); + + GElf_Shdr mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &mem); + + if (shdr == NULL) + error (EXIT_FAILURE, 0, "Couldn't get section header: %s", + elf_errmsg (-1)); + + if ((shdr->sh_flags &SHF_COMPRESSED) != 0) + { + if (elf_compress (scn, 0, 0) < 0) + error (EXIT_FAILURE, 0, "Couldn't decompress section: %s", + elf_errmsg (-1)); + } + else if (name[0] == '.' && name[1] == 'z') + { + if (elf_compress_gnu (scn, 0, 0) < 0) + error (EXIT_FAILURE, 0, "Couldn't decompress section: %s", + elf_errmsg (-1)); + } + + Elf_Data *data = elf_getdata (scn, NULL); + if (data == NULL || data->d_buf == NULL) + error (EXIT_FAILURE, 0, "no section data"); + + int res; + Dwarf_Off off; + Dwarf_Off next_off = 0; + Dwarf_CFI_Entry entry; + while ((res = dwarf_next_cfi (e_ident, data, is_eh, off = next_off, + &next_off, &entry)) == 0) + { + printf ("[%" PRId64 "] ", off); + if (dwarf_cfi_cie_p (&entry)) + printf ("CIE augmentation=\"%s\"\n", entry.cie.augmentation); + else + { + printf ("FDE cie=[%" PRId64 "]\n", entry.fde.CIE_pointer); + + Dwarf_Off cie_off = entry.fde.CIE_pointer; + Dwarf_Off cie_off_next; + Dwarf_CFI_Entry cie_entry; + if (dwarf_next_cfi (e_ident, data, is_eh, cie_off, &cie_off_next, + &cie_entry) != 0 + || !dwarf_cfi_cie_p (&cie_entry)) + error (EXIT_FAILURE, 0, "FDE doesn't point to CIE"); + } + } + + if (res < 0) + error (EXIT_FAILURE, 0, "dwarf_next_cfi failed: %s\n", + dwarf_errmsg (-1)); +} + +int main (int argc, char *argv[]) +{ + if (argc != 2) + error (EXIT_FAILURE, 0, "need file name argument"); + + const char *file = argv[1]; + printf ("%s\n", file); + + int fd = open (file, O_RDONLY); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open input file `%s'", file); + + elf_version (EV_CURRENT); + + Elf *elf = elf_begin (fd, ELF_C_READ, NULL); + if (elf == NULL) + error (EXIT_FAILURE, 0, "cannot create ELF descriptor: %s", + elf_errmsg (-1)); + + size_t esize; + const unsigned char *ident + = (const unsigned char *) elf_getident (elf, &esize); + + if (ident == NULL || esize < EI_NIDENT) + error (EXIT_FAILURE, 0, "no, or too small, ELF ident"); + + GElf_Ehdr ehdr; + if (gelf_getehdr (elf, &ehdr) == NULL) + error (EXIT_FAILURE, 0, "cannot get the ELF header: %s\n", elf_errmsg (-1)); + + size_t strndx = ehdr.e_shstrndx; + + int num_threads = 4; + pthread_t threads[num_threads]; + ThreadData thread_data; + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) != NULL) + { + char *name = elf_strptr (elf, strndx, (size_t) shdr.sh_name); + if (name != NULL && shdr.sh_type == SHT_PROGBITS) + { + bool is_eh = false; + if (strcmp (name, ".eh_frame") == 0) + is_eh = true; + else if (strcmp (name, ".debug_frame") == 0 + || strcmp (name, ".zdebug_frame") == 0) + is_eh = false; + else + continue; + + thread_data.name = name; + thread_data.e_ident = ident; + thread_data.scn = scn; + thread_data.is_eh = is_eh; + + for (int i = 0; i < num_threads; i++) + if (pthread_create (&threads[i], NULL, thread_work, + &thread_data) != 0) + { + perror ("pthread_create"); + + for (int j = 0; j < i; j++) + pthread_cancel (threads[j]); + + elf_end (elf); + close (fd); + return 1; + } + + for (int i = 0; i < num_threads; i++) + if (pthread_join (threads[i], NULL) != 0) + perror ("pthread_join"); + } + } + } + + elf_end (elf); + close (fd); + + return 0; +} diff --git a/tests/run-eu-search-cfi.sh b/tests/run-eu-search-cfi.sh new file mode 100755 index 00000000..e86232cc --- /dev/null +++ b/tests/run-eu-search-cfi.sh @@ -0,0 +1,31 @@ +#! /bin/sh +# Data race test for parallelized next_cfi +# Copyright (C) 2015, 2018 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +. $srcdir/thread-safety-subr.sh + +check_thread_safety_enabled + +cfi_test_files=("testfile11" "testfile12" + "testfilearm" "testfileaarch64" + "testfileppc32" "testfileppc64") + +testfiles "${cfi_test_files[@]}" + +for file in "${cfi_test_files[@]}"; do + testrun ${abs_builddir}/eu_search_cfi $file +done -- 2.48.1