@@ -69,6 +69,7 @@
/emptyfile
/eu_search_cfi
/eu_search_macros
+/eu_search_lines
/fillfile
/find-prologues
/funcretval
@@ -65,7 +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 eu_search_macros \
+ eu_search_cfi eu_search_macros eu_search_lines \
$(asm_TESTS)
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
@@ -218,7 +218,8 @@ 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-eu-search-cfi.sh run-eu-search-macros.sh
+ run-sysroot.sh run-eu-search-cfi.sh run-eu-search-macros.sh \
+ run-eu-search-lines.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
@@ -690,7 +691,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile-dwp-cu-index-overflow.source \
testfile-define-file.bz2 \
testfile-sysroot.tar.bz2 run-sysroot.sh run-debuginfod-seekable.sh \
- run-eu-search-cfi.sh run-eu-search-macros.sh \
+ run-eu-search-cfi.sh run-eu-search-macros.sh run-eu-search-lines.sh \
thread-safety-subr.sh
@@ -877,8 +878,10 @@ elf_print_reloc_syms_LDADD = $(libelf)
cu_dwp_section_info_LDADD = $(libdw)
declfiles_LDADD = $(libdw)
eu_search_cfi_LDFLAGS = $(if $(filter undefined,$(origin USE_LOCKS)),-pthread) $(AM_LDFLAGS)
+eu_search_lines_LDFLAGS = $(if $(filter undefined,$(origin USE_LOCKS)),-pthread) $(AM_LDFLAGS)
eu_search_macros_LDFLAGS = $(if $(filter undefined,$(origin USE_LOCKS)),-pthread) $(AM_LDFLAGS)
eu_search_cfi_LDADD = $(libeu) $(libelf) $(libdw)
+eu_search_lines_LDADD = $(libdw) $(libelf)
eu_search_macros_LDADD = $(libdw)
# We want to test the libelf headers against the system elf.h header.
new file mode 100644
@@ -0,0 +1,211 @@
+/* Test program for eu_search_lines.
+ 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 <fcntl.h>
+#include <inttypes.h>
+#include <libelf.h>
+#include ELFUTILS_HEADER(dw)
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+static Dwarf *dbg;
+
+static void *thread_work (void *arg)
+{
+ int *res = (int *) arg;
+
+ *res = 0;
+ Dwarf_Off cuoff = 0;
+ Dwarf_Off old_cuoff = 0;
+ size_t hsize;
+ Dwarf_Off ao;
+ uint8_t asz;
+ uint8_t osz;
+ while (dwarf_nextcu (dbg, cuoff, &cuoff, &hsize, &ao, &asz, &osz) == 0)
+ {
+ printf ("cuhl = %zu, o = %llu, asz = %hhu, osz = %hhu, ncu = %llu\n",
+ hsize, (unsigned long long int) ao,
+ asz, osz, (unsigned long long int) cuoff);
+
+ // Get the DIE for the CU.
+ Dwarf_Die die;
+ if (dwarf_offdie (dbg, old_cuoff + hsize, &die) == NULL)
+ {
+ printf ("cannot get CU die\n");
+ *res = 1;
+ break;
+ }
+
+ old_cuoff = cuoff;
+
+ Dwarf_Lines *lb;
+ size_t nlb;
+ if (dwarf_getsrclines (&die, &lb, &nlb) != 0)
+ {
+ printf ("cannot get lines\n");
+ *res = 1;
+ break;
+ }
+
+ printf (" %zu lines\n", nlb);
+
+ for (size_t i = 0; i < nlb; ++i)
+ {
+ Dwarf_Line *l = dwarf_onesrcline (lb, i);
+ if (l == NULL)
+ {
+ printf ("cannot get individual line\n");
+ *res = 1;
+ break;
+ }
+
+ Dwarf_Addr addr;
+ if (dwarf_lineaddr (l, &addr) != 0)
+ addr = 0;
+
+ const char *file = dwarf_linesrc (l, NULL, NULL);
+ int line;
+
+ if (dwarf_lineno (l, &line) != 0)
+ line = 0;
+
+ printf ("%" PRIx64 ": %s:%d:", (uint64_t) addr, file ? : "???", line);
+
+ // Getting the file path through the Dwarf_Files should
+ // result in the same path.
+ Dwarf_Files *files;
+ size_t idx;
+ if (dwarf_line_file (l, &files, &idx) != 0)
+ {
+ printf ("cannot get file from line (%zd): %s\n",
+ i, dwarf_errmsg (-1));
+ *res = 1;
+ break;
+ }
+
+ const char *path = dwarf_filesrc (files, idx, NULL, NULL);
+ if ((path == NULL && file != NULL) ||
+ (path != NULL && file == NULL) ||
+ (strcmp (file, path) != 0))
+ {
+ printf ("line %zd srcline (%s) != file srcline (%s)\n",
+ i, file ? : "???", path ? : "???");
+ *res = 1;
+ break;
+ }
+
+ int column;
+
+ if (dwarf_linecol (l, &column) != 0)
+ column = 0;
+ if (column >= 0)
+ printf ("%d:", column);
+
+ bool is_stmt;
+ if (dwarf_linebeginstatement (l, &is_stmt) != 0)
+ is_stmt = false;
+ bool end_sequence;
+ if (dwarf_lineendsequence (l, &end_sequence) != 0)
+ end_sequence = false;
+ bool basic_block;
+ if (dwarf_lineblock (l, &basic_block) != 0)
+ basic_block = false;
+ bool prologue_end;
+ if (dwarf_lineprologueend (l, &prologue_end) != 0)
+ prologue_end = false;
+ bool epilogue_begin;
+ if (dwarf_lineepiloguebegin (l, &epilogue_begin) != 0)
+ epilogue_begin = false;
+
+ printf (" is_stmt:%s, end_seq:%s, bb:%s, prologue:%s, epilogue:%s\n",
+ is_stmt ? "yes" : "no", end_sequence ? "yes" : "no",
+ basic_block ? "yes" : "no", prologue_end ? "yes" : "no",
+ epilogue_begin ? "yes" : "no");
+ }
+ }
+
+ return NULL;
+}
+
+int main (int argc, char *argv[])
+{
+ if (argc != 2)
+ {
+ printf ("Usage: %s <filename>\n", argv[0]);
+ return 1;
+ }
+
+ char *name = argv[1];
+ int fd = open (name, O_RDONLY);
+ if (fd < 0)
+ {
+ printf ("%s not usable: %s\n", name, dwarf_errmsg (-1));
+ return 1;
+ }
+
+ dbg = dwarf_begin (fd, DWARF_C_READ);
+ if (dbg == NULL)
+ {
+ printf ("%s not usable: %s\n", name, dwarf_errmsg (-1));
+ close (fd);
+ return 1;
+ }
+
+ printf ("checking %s\n", name);
+
+ int num_threads = 4;
+ pthread_t threads[num_threads];
+ int thread_results[num_threads];
+
+ for (int i = 0; i < num_threads; ++i)
+ {
+ if (pthread_create (&threads[i], NULL, thread_work,
+ &thread_results[i]) != 0)
+ {
+ perror ("Failed to create thread");
+
+ for (int j = 0; j < i; j++)
+ pthread_cancel (threads[j]);
+
+ dwarf_end (dbg);
+ close (fd);
+ return 1;
+ }
+ }
+
+ int res = 0;
+ for (int i = 0; i < num_threads; ++i)
+ {
+ if (pthread_join (threads[i], NULL) != 0)
+ {
+ perror ("Failed to join thread");
+ res = 1;
+ break;
+ }
+
+ res |= thread_results[i];
+ }
+
+ dwarf_end (dbg);
+ close (fd);
+
+ return res;
+}
new file mode 100755
@@ -0,0 +1,31 @@
+#! /bin/sh
+# Data race test for parallelized get-lines
+# 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
+
+lines_testfiles=("testfile" "testfile2" "testfilenolines")
+
+testfiles "${lines_testfiles[@]}"
+
+for file in "${lines_testfiles[@]}"; do
+ testrun ${abs_builddir}/eu_search_lines $file
+done
+
+exit 0