From: Heather McIntyre <hsm2@rice.edu>
To: elfutils-devel@sourceware.org
Cc: John Mellor-Crummey <johnmc@rice.edu>
Subject: [PATCH] Fix thread-safety for elfutils
Date: Tue, 8 Aug 2023 12:07:39 -0500 [thread overview]
Message-ID: <CAK-+vz0guN1=D5-EcuRTQAF0ZnL+aGYFg4n7pguuMkwNiOmW1Q@mail.gmail.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 699 bytes --]
Hello all,
This patch was created to address thread-safety issues reported in bug 26921
<https://sourceware.org/bugzilla/show_bug.cgi?id=26921> and bug 26930
<https://sourceware.org/bugzilla/show_bug.cgi?id=26930>.
Additionally, other thread-safety fixes were applied during the process.
Brief Description:
Locking was implemented for tsearch and tfind.
Changes to multiple files within the libelf library were made such that
USE_LOCKS no longer causes tests to fail when enabled.
New tests were added to confirm thread-safety.
Please review the attached patch file and feel free to provide feedback. I
am available for any clarifications or modifications needed.
Best regards,
Heather McIntyre
[-- Attachment #2: 0001-Fix-thread-safety-for-elfutils.patch --]
[-- Type: application/octet-stream, Size: 83636 bytes --]
From ee7bf3f07a3fe99cf6e6152803271a1b77445350 Mon Sep 17 00:00:00 2001
From: "Heather S. McIntyre" <hsm2@rice.edu>
Date: Tue, 8 Aug 2023 11:24:01 -0500
Subject: [PATCH] Fix thread-safety for elfutils
Signed-off-by: Heather S. McIntyre <hsm2@rice.edu>
---
ChangeLog | 5 +
configure.ac | 6 +-
lib/ChangeLog | 10 ++
lib/Makefile.am | 2 +-
lib/eu-config.h | 33 +++--
lib/eu-search.c | 58 ++++++++
lib/eu-search.h | 37 +++++
libcpu/ChangeLog | 6 +
libcpu/Makefile.am | 3 +
libcpu/i386_parse.y | 48 +++----
libdw/ChangeLog | 19 +++
libdw/cie.c | 8 +-
libdw/dwarf_getalt.c | 44 ++++--
libdw/dwarf_getlocation.c | 16 +--
libdw/dwarf_getmacros.c | 6 +-
libdw/dwarf_getsrclines.c | 6 +-
libdw/dwarf_hasattr.c | 9 ++
libdw/fde.c | 6 +-
libdw/libdw_find_split_unit.c | 66 ++++++---
libdw/libdw_findcu.c | 52 ++++---
libdwfl/ChangeLog | 5 +
libdwfl/cu.c | 4 +-
libelf/ChangeLog | 15 +-
libelf/elf32_getchdr.c | 46 +-----
libelf/elf32_getchdr.h | 61 ++++++++
libelf/elf32_updatenull.c | 2 +-
libelf/elf_cntl.c | 11 +-
libelf/elf_end.c | 6 +-
libelf/elf_getdata.c | 14 ++
libelf/elf_readall.c | 5 +-
libelf/elf_version.c | 11 +-
libelf/libelfP.h | 4 +
src/ChangeLog | 7 +
src/Makefile.am | 3 +
src/findtextrel.c | 10 +-
src/nm.c | 10 +-
tests/ChangeLog | 21 +++
tests/Makefile.am | 16 ++-
tests/eu_search_cfi.c | 234 ++++++++++++++++++++++++++++++
tests/eu_search_die.c | 262 ++++++++++++++++++++++++++++++++++
tests/eu_search_lines.c | 228 +++++++++++++++++++++++++++++
tests/eu_search_macros.c | 216 ++++++++++++++++++++++++++++
tests/run-eu-search-tests.sh | 168 ++++++++++++++++++++++
43 files changed, 1618 insertions(+), 181 deletions(-)
create mode 100644 lib/eu-search.c
create mode 100644 lib/eu-search.h
create mode 100644 libelf/elf32_getchdr.h
create mode 100644 tests/eu_search_cfi.c
create mode 100644 tests/eu_search_die.c
create mode 100644 tests/eu_search_lines.c
create mode 100644 tests/eu_search_macros.c
create mode 100644 tests/run-eu-search-tests.sh
diff --git a/ChangeLog b/ChangeLog
index 6aed95b6..c555c986 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * NEWS: Changes implemented to support thread-safety.
+ * configure.ac (--enable-thread-safety): Remove experimental warning.
+
2023-03-27 Di Chen <dichen@redhat.com>
* NEWS: Support readelf -Ds for using dynamic segment to
diff --git a/configure.ac b/configure.ac
index 4b67c844..f86f6492 100644
--- a/configure.ac
+++ b/configure.ac
@@ -79,12 +79,10 @@ AC_DEFINE_UNQUOTED(DEFAULT_AR_DETERMINISTIC, $default_ar_deterministic,
AC_ARG_ENABLE([thread-safety],
AS_HELP_STRING([--enable-thread-safety],
- [enable thread safety of libraries EXPERIMENTAL]),
+ [enable thread safety of libraries]),
use_locks=$enableval, use_locks=no)
AM_CONDITIONAL(USE_LOCKS, test "$use_locks" = yes)
AS_IF([test "$use_locks" = yes], [AC_DEFINE(USE_LOCKS)])
-AS_IF([test "$use_locks" = yes],
- [AC_MSG_WARN([thread-safety is EXPERIMENTAL tests might fail.])])
AH_TEMPLATE([USE_LOCKS], [Defined if libraries should be thread-safe.])
@@ -906,10 +904,10 @@ AC_MSG_NOTICE([
Symbol versioning : ${enable_symbol_versioning}
NOT RECOMMENDED FEATURES (should all be no)
- Experimental thread safety : ${use_locks}
install elf.h : ${install_elfh}
OTHER FEATURES
+ Enable thread safety : ${use_locks}
Deterministic archives by default : ${default_ar_deterministic}
Native language support : ${USE_NLS}
Extra Valgrind annotations : ${use_vg_annotations}
diff --git a/lib/ChangeLog b/lib/ChangeLog
index 5ab9477e..7f0533cc 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,13 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * eu-search.h: New file.
+ Declarations for read/write locked eu_tsearch/eu_tfind.
+ * eu-search.c: New file.
+ Definitions for read/write locked eu_tsearch/eu_tfind.
+ * eu-config.h New macros.
+ [USE_LOCKS] (ONCE_CALL): (once_define, once)
+ * Makefile.am (libeu_a_SOURCES): Add eu-search.c.
+
2022-12-20 Mark Wielaard <mark@klomp.org>
* Makefile.am (xmalloc_CFLAGS): Remove.
diff --git a/lib/Makefile.am b/lib/Makefile.am
index b3bb929f..ce8f3e1b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -34,7 +34,7 @@ AM_CPPFLAGS += -I$(srcdir)/../libelf
noinst_LIBRARIES = libeu.a
libeu_a_SOURCES = xasprintf.c xstrdup.c xstrndup.c xmalloc.c next_prime.c \
- crc32.c crc32_file.c \
+ crc32.c crc32_file.c eu-search.c \
color.c error.c printversion.c
noinst_HEADERS = fixedsizehash.h libeu.h system.h dynamicsizehash.h list.h \
diff --git a/lib/eu-config.h b/lib/eu-config.h
index 78a5c4fe..d43a8f78 100644
--- a/lib/eu-config.h
+++ b/lib/eu-config.h
@@ -32,24 +32,27 @@
#ifdef USE_LOCKS
# include <pthread.h>
# include <assert.h>
-# define rwlock_define(class,name) class pthread_rwlock_t name
-# define RWLOCK_CALL(call) \
+# define rwlock_define(class,name) class pthread_rwlock_t name
+# define once_define(class,name) class pthread_once_t name = PTHREAD_ONCE_INIT
+# define RWLOCK_CALL(call) \
({ int _err = pthread_rwlock_ ## call; assert_perror (_err); })
-# define rwlock_init(lock) RWLOCK_CALL (init (&lock, NULL))
-# define rwlock_fini(lock) RWLOCK_CALL (destroy (&lock))
-# define rwlock_rdlock(lock) RWLOCK_CALL (rdlock (&lock))
-# define rwlock_wrlock(lock) RWLOCK_CALL (wrlock (&lock))
-# define rwlock_unlock(lock) RWLOCK_CALL (unlock (&lock))
+# define ONCE_CALL(call) \
+ ({ int _err = pthread_ ## call; assert_perror (_err); })
+# define rwlock_init(lock) RWLOCK_CALL (init (&lock, NULL))
+# define rwlock_fini(lock) RWLOCK_CALL (destroy (&lock))
+# define rwlock_rdlock(lock) RWLOCK_CALL (rdlock (&lock))
+# define rwlock_wrlock(lock) RWLOCK_CALL (wrlock (&lock))
+# define rwlock_unlock(lock) RWLOCK_CALL (unlock (&lock))
+# define once(once_control, init_routine) ONCE_CALL (once (&once_control, init_routine))
#else
-/* Eventually we will allow multi-threaded applications to use the
- libraries. Therefore we will add the necessary locking although
- the macros used expand to nothing for now. */
# define rwlock_define(class,name) class int name
-# define rwlock_init(lock) ((void) (lock))
-# define rwlock_fini(lock) ((void) (lock))
-# define rwlock_rdlock(lock) ((void) (lock))
-# define rwlock_wrlock(lock) ((void) (lock))
-# define rwlock_unlock(lock) ((void) (lock))
+# define rwlock_init(lock) ((void) (lock))
+# define rwlock_fini(lock) ((void) (lock))
+# define rwlock_rdlock(lock) ((void) (lock))
+# define rwlock_wrlock(lock) ((void) (lock))
+# define rwlock_unlock(lock) ((void) (lock))
+# define once_define(class,name)
+# define once(once_control, init_routine) init_routine()
#endif /* USE_LOCKS */
#include <libintl.h>
diff --git a/lib/eu-search.c b/lib/eu-search.c
new file mode 100644
index 00000000..b15d61b9
--- /dev/null
+++ b/lib/eu-search.c
@@ -0,0 +1,58 @@
+/* Definitions for thread-safe tsearch/tfind
+ 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 either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include "eu-search.h"
+
+rwlock_define(static, search_find_lock);
+
+void *eu_tsearch(const void *key, void **rootp, int (*compar)(const void *, const void *))
+{
+ void *ret = NULL;
+ rwlock_wrlock(search_find_lock);
+
+ ret = tsearch(key, rootp, compar);
+
+ rwlock_unlock(search_find_lock);
+ return ret;
+}
+
+void *eu_tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *))
+{
+ void *ret = NULL;
+ rwlock_rdlock(search_find_lock);
+
+ ret = tfind(key, rootp, compar);
+
+ rwlock_unlock(search_find_lock);
+ return ret;
+}
\ No newline at end of file
diff --git a/lib/eu-search.h b/lib/eu-search.h
new file mode 100644
index 00000000..5fb335f2
--- /dev/null
+++ b/lib/eu-search.h
@@ -0,0 +1,37 @@
+/* Calls for thread-safe tsearch/tfind
+ 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 either
+
+ * the GNU Lesser General Public License as published by the Free
+ Software Foundation; either version 3 of the License, or (at
+ your option) any later version
+
+ or
+
+ * the GNU General Public License as published by the Free
+ Software Foundation; either version 2 of the License, or (at
+ your option) any later version
+
+ or both in parallel, as here.
+
+ 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 copies of the GNU General Public License and
+ the GNU Lesser General Public License along with this program. If
+ not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef EU_SEARCH_H
+#define EU_SEARCH_H 1
+
+#include <search.h>
+
+extern void *eu_tsearch(const void *key, void **rootp, int (*compar)(const void *, const void *));
+extern void *eu_tfind(const void *key, void *const *rootp, int (*compar)(const void *, const void *));
+
+#endif
\ No newline at end of file
diff --git a/libcpu/ChangeLog b/libcpu/ChangeLog
index d14cd237..8c6cfd68 100644
--- a/libcpu/ChangeLog
+++ b/libcpu/ChangeLog
@@ -1,3 +1,9 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * Makefile.am: Add USE_LOCKS condition for -pthread.
+ * i386_parse.y: Add eu-search.h and remove search.h.
+ Change calls for tsearch/tfind to eu_tsearch/eu_tfind.
+
2022-12-18 Yonggang Luo <luoyonggang@gmail.com>
* i386_mne.h: New file, extracted from i386_disasm.c.
diff --git a/libcpu/Makefile.am b/libcpu/Makefile.am
index 4ba1be56..a51334b5 100644
--- a/libcpu/Makefile.am
+++ b/libcpu/Makefile.am
@@ -33,6 +33,9 @@ AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
if BUILD_STATIC
AM_CFLAGS += $(fpic_CFLAGS)
endif
+if USE_LOCKS
+ AM_CFLAGS += -pthread
+endif
AM_CFLAGS += -fdollars-in-identifiers
LEXCOMPILE = $(LEX) $(LFLAGS) $(AM_LFLAGS) -P$(<F:lex.l=)
LEX_OUTPUT_ROOT = lex.$(<F:lex.l=)
diff --git a/libcpu/i386_parse.y b/libcpu/i386_parse.y
index 459684c6..3d7cb89e 100644
--- a/libcpu/i386_parse.y
+++ b/libcpu/i386_parse.y
@@ -37,7 +37,7 @@
#include <inttypes.h>
#include <math.h>
#include <obstack.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -269,12 +269,12 @@ mask: kMASK kBITFIELD kNUMBER
struct synonym *newp = xmalloc (sizeof (*newp));
newp->from = $2;
newp->to = $3;
- if (tfind (newp, &synonyms, compare_syn) != NULL)
+ if (eu_tfind (newp, &synonyms, compare_syn) != NULL)
error (0, 0,
"%d: duplicate definition for synonym '%s'",
i386_lineno, $2);
- else if (tsearch ( newp, &synonyms, compare_syn) == NULL)
- error (EXIT_FAILURE, 0, "tsearch");
+ else if (eu_tsearch ( newp, &synonyms, compare_syn) == NULL)
+ error (EXIT_FAILURE, 0, "eu_tsearch");
}
|
;
@@ -308,12 +308,12 @@ instr: bytes ':' bitfieldopt kID bitfieldopt optargs
newp->bytes = $1;
newp->mnemonic = $4;
if (newp->mnemonic != (void *) -1l
- && tfind ($4, &mnemonics,
+ && eu_tfind ($4, &mnemonics,
(int (*)(const void *, const void *)) strcmp) == NULL)
{
- if (tsearch ($4, &mnemonics,
+ if (eu_tsearch ($4, &mnemonics,
(int (*)(const void *, const void *)) strcmp) == NULL)
- error (EXIT_FAILURE, errno, "tsearch");
+ error (EXIT_FAILURE, errno, "eu_tsearch");
++nmnemonics;
}
@@ -339,15 +339,15 @@ instr: bytes ':' bitfieldopt kID bitfieldopt optargs
infname, i386_lineno - 1, $5->name);
struct suffix search = { .name = $5->name };
- if (tfind (&search, &suffixes, compare_suf)
+ if (eu_tfind (&search, &suffixes, compare_suf)
== NULL)
{
struct suffix *ns = xmalloc (sizeof (*ns));
ns->name = $5->name;
ns->idx = ++nsuffixes;
- if (tsearch (ns, &suffixes, compare_suf)
+ if (eu_tsearch (ns, &suffixes, compare_suf)
== NULL)
- error (EXIT_FAILURE, errno, "tsearch");
+ error (EXIT_FAILURE, errno, "eu_tsearch");
}
}
@@ -374,7 +374,7 @@ bitfieldopt: kBITFIELD
struct known_bitfield search;
search.name = $1;
struct known_bitfield **res;
- res = tfind (&search, &bitfields, bitfield_compare);
+ res = eu_tfind (&search, &bitfields, bitfield_compare);
if (res == NULL)
{
error (0, 0, "%d: unknown bitfield '%s'",
@@ -437,7 +437,7 @@ bit: '0'
struct known_bitfield search;
search.name = $1;
struct known_bitfield **res;
- res = tfind (&search, &bitfields, bitfield_compare);
+ res = eu_tfind (&search, &bitfields, bitfield_compare);
if (res == NULL)
{
error (0, 0, "%d: unknown bitfield '%s'",
@@ -497,7 +497,7 @@ argcomp: kBITFIELD
struct known_bitfield search;
search.name = $1;
struct known_bitfield **res;
- res = tfind (&search, &bitfields, bitfield_compare);
+ res = eu_tfind (&search, &bitfields, bitfield_compare);
if (res == NULL)
{
if (strcmp ($1, "ax") == 0)
@@ -575,7 +575,7 @@ new_bitfield (char *name, unsigned long int num)
newp->bits = num;
newp->tmp = 0;
- if (tfind (newp, &bitfields, bitfield_compare) != NULL)
+ if (eu_tfind (newp, &bitfields, bitfield_compare) != NULL)
{
error (0, 0, "%d: duplicated definition of bitfield '%s'",
i386_lineno, name);
@@ -584,7 +584,7 @@ new_bitfield (char *name, unsigned long int num)
return;
}
- if (tsearch (newp, &bitfields, bitfield_compare) == NULL)
+ if (eu_tsearch (newp, &bitfields, bitfield_compare) == NULL)
error (EXIT_FAILURE, errno, "%d: cannot insert new bitfield '%s'",
i386_lineno, name);
}
@@ -813,7 +813,7 @@ fillin_arg (struct bitvalue *bytes, struct argname *name,
struct synonym search = { .from = fieldname };
- struct synonym **res = tfind (&search, &synonyms, compare_syn);
+ struct synonym **res = eu_tfind (&search, &synonyms, compare_syn);
if (res != NULL)
fieldname = (*res)->to;
@@ -914,26 +914,26 @@ find_numbers (void)
if (runp->operands[i].fct != NULL)
{
struct argstring search = { .str = runp->operands[i].fct };
- if (tfind (&search, &fct_names[i], compare_argstring) == NULL)
+ if (eu_tfind (&search, &fct_names[i], compare_argstring) == NULL)
{
struct argstring *newp = xmalloc (sizeof (*newp));
newp->str = runp->operands[i].fct;
newp->idx = 0;
- if (tsearch (newp, &fct_names[i], compare_argstring) == NULL)
- error (EXIT_FAILURE, errno, "tsearch");
+ if (eu_tsearch (newp, &fct_names[i], compare_argstring) == NULL)
+ error (EXIT_FAILURE, errno, "eu_tsearch");
++nfct_names[i];
}
if (runp->operands[i].str != NULL)
{
search.str = runp->operands[i].str;
- if (tfind (&search, &strs[i], compare_argstring) == NULL)
+ if (eu_tfind (&search, &strs[i], compare_argstring) == NULL)
{
struct argstring *newp = xmalloc (sizeof (*newp));
newp->str = runp->operands[i].str;
newp->idx = 0;
- if (tsearch (newp, &strs[i], compare_argstring) == NULL)
- error (EXIT_FAILURE, errno, "tsearch");
+ if (eu_tsearch (newp, &strs[i], compare_argstring) == NULL)
+ error (EXIT_FAILURE, errno, "eu_tsearch");
++nstrs[i];
}
}
@@ -1206,7 +1206,7 @@ instrtable_out (void)
if (instr->operands[i].fct != NULL)
{
struct argstring search = { .str = instr->operands[i].fct };
- struct argstring **res = tfind (&search, &fct_names[i],
+ struct argstring **res = eu_tfind (&search, &fct_names[i],
compare_argstring);
assert (res != NULL);
idx = (*res)->idx;
@@ -1217,7 +1217,7 @@ instrtable_out (void)
if (instr->operands[i].str != NULL)
{
struct argstring search = { .str = instr->operands[i].str };
- struct argstring **res = tfind (&search, &strs[i],
+ struct argstring **res = eu_tfind (&search, &strs[i],
compare_argstring);
assert (res != NULL);
idx = (*res)->idx;
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 406310ef..3efbbfee 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * cie.c: Add eu-search.h and remove search.h.
+ Change calls of tsearch/tfind to eu_tsearch/eu_tfind.
+ * dwarf_getlocation.c: Likewise.
+ * dwarf_getmacros.c: Likewise.
+ * dwarf_getsrclines.c: :Likewise.
+ * fde.c: Likewise.
+ * libdw_find_split_unit.c: Likewise.
+ * libdw_findcu.c: Likewise.
+ Add lock for next_tu_offset/next_cu_offset.
+ Reduce return statements in __libdw_findcu().
+ * dwarf_getalt.c: Likewise.
+ Add lock for dbg->alt_dwarf/main->alt_dwarf.
+ * dwarf_hasattr.c: Likewise.
+ Add lock for __libdw_dieabbrev().
+ * libdw_find_split_unit.c: Likewise.
+ Add lock for cu->split.
+
2023-02-22 Mark Wielaard <mark@klomp.org>
* dwarf_getscopes.c (origin_match): Don't free a->scopes.
diff --git a/libdw/cie.c b/libdw/cie.c
index 1b0aae7c..758daef5 100644
--- a/libdw/cie.c
+++ b/libdw/cie.c
@@ -33,7 +33,7 @@
#include "cfi.h"
#include "encoded-value.h"
#include <assert.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdlib.h>
@@ -144,7 +144,7 @@ intern_new_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
cie->initial_state = NULL;
/* Add the new entry to the search tree. */
- if (tsearch (cie, &cache->cie_tree, &compare_cie) == NULL)
+ if (eu_tsearch (cie, &cache->cie_tree, &compare_cie) == NULL)
{
free (cie);
__libdw_seterrno (DWARF_E_NOMEM);
@@ -160,7 +160,7 @@ internal_function
__libdw_find_cie (Dwarf_CFI *cache, Dwarf_Off offset)
{
const struct dwarf_cie cie_key = { .offset = offset };
- struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
+ struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree, &compare_cie);
if (found != NULL)
return *found;
@@ -189,7 +189,7 @@ internal_function
__libdw_intern_cie (Dwarf_CFI *cache, Dwarf_Off offset, const Dwarf_CIE *info)
{
const struct dwarf_cie cie_key = { .offset = offset };
- struct dwarf_cie **found = tfind (&cie_key, &cache->cie_tree, &compare_cie);
+ struct dwarf_cie **found = eu_tfind (&cie_key, &cache->cie_tree, &compare_cie);
if (found == NULL)
/* We have not read this CIE yet. Enter it. */
(void) intern_new_cie (cache, offset, info);
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index 0a12dfae..f0bc7b56 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -44,6 +44,10 @@
#include <sys/types.h>
#include <sys/stat.h>
+/* find_debug_altlink() modifies "dbg->alt_dwarf".
+ dwarf_getalt() reads "main->alt_dwarf".
+ Mutual exclusion is enforced to prevent a race. */
+rwlock_define(static, alt_dwarf_lock);
char *
internal_function
@@ -151,34 +155,52 @@ find_debug_altlink (Dwarf *dbg)
{
Dwarf *alt = dwarf_begin (fd, O_RDONLY);
if (alt != NULL)
- {
- dbg->alt_dwarf = alt;
- dbg->alt_fd = fd;
- }
+ {
+ rwlock_wrlock(alt_dwarf_lock);
+ dbg->alt_dwarf = alt;
+ rwlock_unlock(alt_dwarf_lock);
+
+ dbg->alt_fd = fd;
+ }
else
- close (fd);
- }
+ close (fd);
+ }
}
Dwarf *
dwarf_getalt (Dwarf *main)
{
+ rwlock_rdlock(alt_dwarf_lock);
+ Dwarf *alt_dwarf_local = main->alt_dwarf;
+ rwlock_unlock(alt_dwarf_lock);
+
/* Only try once. */
- if (main == NULL || main->alt_dwarf == (void *) -1)
+ if (main == NULL || alt_dwarf_local == (void *) -1)
+ {
return NULL;
+ }
- if (main->alt_dwarf != NULL)
- return main->alt_dwarf;
+ if (alt_dwarf_local != NULL)
+ {
+ return alt_dwarf_local;
+ }
find_debug_altlink (main);
+ rwlock_rdlock(alt_dwarf_lock);
+ alt_dwarf_local = main->alt_dwarf;
+ rwlock_unlock(alt_dwarf_lock);
+
/* If we found nothing, make sure we don't try again. */
- if (main->alt_dwarf == NULL)
+ if (alt_dwarf_local == NULL)
{
+ rwlock_wrlock(alt_dwarf_lock);
main->alt_dwarf = (void *) -1;
+ rwlock_unlock(alt_dwarf_lock);
+
return NULL;
}
- return main->alt_dwarf;
+ return alt_dwarf_local;
}
INTDEF (dwarf_getalt)
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index 553fdc98..e26afe37 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -31,7 +31,7 @@
#endif
#include <dwarf.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdlib.h>
#include <assert.h>
@@ -137,7 +137,7 @@ loc_compare (const void *p1, const void *p2)
/* For each DW_OP_implicit_value, we store a special entry in the cache.
This points us directly to the block data for later fetching.
- Returns zero on success, -1 on bad DWARF or 1 if tsearch failed. */
+ Returns zero on success, -1 on bad DWARF or 1 if eu_tsearch failed. */
static int
store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
{
@@ -154,7 +154,7 @@ store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
block->addr = op;
block->data = (unsigned char *) data;
block->length = op->number;
- if (unlikely (tsearch (block, cache, loc_compare) == NULL))
+ if (unlikely (eu_tsearch (block, cache, loc_compare) == NULL))
return 1;
return 0;
}
@@ -167,7 +167,7 @@ dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op,
return -1;
struct loc_block_s fake = { .addr = (void *) op };
- struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
+ struct loc_block_s **found = eu_tfind (&fake, &attr->cu->locs, loc_compare);
if (unlikely (found == NULL))
{
__libdw_seterrno (DWARF_E_NO_BLOCK);
@@ -211,7 +211,7 @@ is_constant_offset (Dwarf_Attribute *attr,
/* Check whether we already cached this location. */
struct loc_s fake = { .addr = attr->valp };
- struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
+ struct loc_s **found = eu_tfind (&fake, &attr->cu->locs, loc_compare);
if (found == NULL)
{
@@ -235,7 +235,7 @@ is_constant_offset (Dwarf_Attribute *attr,
newp->loc = result;
newp->nloc = 1;
- found = tsearch (newp, &attr->cu->locs, loc_compare);
+ found = eu_tsearch (newp, &attr->cu->locs, loc_compare);
}
assert ((*found)->nloc == 1);
@@ -266,7 +266,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
/* Check whether we already looked at this list. */
struct loc_s fake = { .addr = block->data };
- struct loc_s **found = tfind (&fake, cache, loc_compare);
+ struct loc_s **found = eu_tfind (&fake, cache, loc_compare);
if (found != NULL)
{
/* We already saw it. */
@@ -655,7 +655,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
newp->addr = block->data;
newp->loc = result;
newp->nloc = *listlen;
- (void) tsearch (newp, cache, loc_compare);
+ (void) eu_tsearch (newp, cache, loc_compare);
/* We did it. */
return 0;
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index fd929669..1ac5e402 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -32,7 +32,7 @@
#include <assert.h>
#include <dwarf.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdlib.h>
#include <string.h>
@@ -275,7 +275,7 @@ cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
Dwarf_Die *cudie)
{
Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
- Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
+ Dwarf_Macro_Op_Table **found = eu_tfind (&fake, &dbg->macro_ops,
macro_op_compare);
if (found != NULL)
return *found;
@@ -287,7 +287,7 @@ cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
if (table == NULL)
return NULL;
- Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
+ Dwarf_Macro_Op_Table **ret = eu_tsearch (table, &dbg->macro_ops,
macro_op_compare);
if (unlikely (ret == NULL))
{
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index df003c5f..356284a0 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -33,7 +33,7 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include <search.h>
+#include <eu-search.h>
#include "dwarf.h"
#include "libdwP.h"
@@ -1138,7 +1138,7 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
Dwarf_Lines **linesp, Dwarf_Files **filesp)
{
struct files_lines_s fake = { .debug_line_offset = debug_line_offset };
- struct files_lines_s **found = tfind (&fake, &dbg->files_lines,
+ struct files_lines_s **found = eu_tfind (&fake, &dbg->files_lines,
files_lines_compare);
if (found == NULL)
{
@@ -1160,7 +1160,7 @@ __libdw_getsrclines (Dwarf *dbg, Dwarf_Off debug_line_offset,
node->debug_line_offset = debug_line_offset;
- found = tsearch (node, &dbg->files_lines, files_lines_compare);
+ found = eu_tsearch (node, &dbg->files_lines, files_lines_compare);
if (found == NULL)
{
__libdw_seterrno (DWARF_E_NOMEM);
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
index eca08394..92f8de68 100644
--- a/libdw/dwarf_hasattr.c
+++ b/libdw/dwarf_hasattr.c
@@ -34,6 +34,10 @@
#include <dwarf.h>
#include "libdwP.h"
+/* dwarf_hasattr() calls __libdw_dieabbrev() in libdwP.h.
+ __libdw_dieabbrev() reads/writes "die->abbrev".
+ Mutual exclusion is enforced around the call to __libdw_dieabbrev to prevent a race. */
+rwlock_define(static, die_abbrev_lock);
int
dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
@@ -41,8 +45,13 @@ dwarf_hasattr (Dwarf_Die *die, unsigned int search_name)
if (die == NULL)
return 0;
+ rwlock_wrlock(die_abbrev_lock);
+
/* Find the abbreviation entry. */
Dwarf_Abbrev *abbrevp = __libdw_dieabbrev (die, NULL);
+
+ rwlock_unlock(die_abbrev_lock);
+
if (unlikely (abbrevp == DWARF_END_ABBREV))
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
diff --git a/libdw/fde.c b/libdw/fde.c
index 73d551b6..55065528 100644
--- a/libdw/fde.c
+++ b/libdw/fde.c
@@ -31,7 +31,7 @@
#endif
#include "cfi.h"
-#include <search.h>
+#include <eu-search.h>
#include <stdlib.h>
#include "encoded-value.h"
@@ -122,7 +122,7 @@ intern_fde (Dwarf_CFI *cache, const Dwarf_FDE *entry)
fde->instructions += cie->fde_augmentation_data_size;
/* Add the new entry to the search tree. */
- struct dwarf_fde **tres = tsearch (fde, &cache->fde_tree, &compare_fde);
+ struct dwarf_fde **tres = eu_tsearch (fde, &cache->fde_tree, &compare_fde);
if (tres == NULL)
{
free (fde);
@@ -252,7 +252,7 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
/* Look for a cached FDE covering this address. */
const struct dwarf_fde fde_key = { .start = address, .end = 0 };
- struct dwarf_fde **found = tfind (&fde_key, &cache->fde_tree, &compare_fde);
+ struct dwarf_fde **found = eu_tfind (&fde_key, &cache->fde_tree, &compare_fde);
if (found != NULL)
return *found;
diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
index a22e7bc9..4da78be4 100644
--- a/libdw/libdw_find_split_unit.c
+++ b/libdw/libdw_find_split_unit.c
@@ -34,13 +34,18 @@
#include "libelfP.h"
#include <limits.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+/* __libdw_link_skel_split() modifies "skel->split = split" and "split->split = skel".
+ "cu->split" is read at multiple locations and conditionally updated.
+ Mutual exclusion is enforced to prevent a race. */
+rwlock_define(static, cu_split_lock);
+
void
try_split_file (Dwarf_CU *cu, const char *dwo_path)
{
@@ -57,7 +62,7 @@ try_split_file (Dwarf_CU *cu, const char *dwo_path)
if (split->unit_type == DW_UT_split_compile
&& cu->unit_id8 == split->unit_id8)
{
- if (tsearch (split->dbg, &cu->dbg->split_tree,
+ if (eu_tsearch (split->dbg, &cu->dbg->split_tree,
__libdw_finddbg_cb) == NULL)
{
/* Something went wrong. Don't link. */
@@ -65,8 +70,12 @@ try_split_file (Dwarf_CU *cu, const char *dwo_path)
break;
}
- /* Link skeleton and split compile units. */
- __libdw_link_skel_split (cu, split);
+ rwlock_wrlock(cu_split_lock);
+
+ /* Link skeleton and split compile units. */
+ __libdw_link_skel_split (cu, split);
+
+ rwlock_unlock(cu_split_lock);
/* We have everything we need from this ELF
file. And we are going to close the fd to
@@ -75,8 +84,13 @@ try_split_file (Dwarf_CU *cu, const char *dwo_path)
break;
}
}
- if (cu->split == (Dwarf_CU *) -1)
- dwarf_end (split_dwarf);
+
+ rwlock_rdlock(cu_split_lock);
+
+ if (cu->split == (Dwarf_CU *) -1)
+ dwarf_end (split_dwarf);
+
+ rwlock_unlock(cu_split_lock);
}
/* Always close, because we don't want to run out of file
descriptors. See also the elf_fcntl ELF_C_FDDONE call
@@ -89,20 +103,26 @@ Dwarf_CU *
internal_function
__libdw_find_split_unit (Dwarf_CU *cu)
{
- /* Only try once. */
- if (cu->split != (Dwarf_CU *) -1)
- return cu->split;
+ rwlock_rdlock(cu_split_lock);
+ Dwarf_CU *cu_split_local = cu->split;
+ rwlock_unlock(cu_split_lock);
- /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
+ /* Only try once. */
+ if (cu_split_local != (Dwarf_CU *) -1)
+ {
+ return cu_split_local;
+ }
+
+ /* We need a skeleton unit with a comp_dir and [GNU_]dwo_name attributes.
The split unit will be the first in the dwo file and should have the
same id as the skeleton. */
- if (cu->unit_type == DW_UT_skeleton)
+ if (cu->unit_type == DW_UT_skeleton)
{
Dwarf_Die cudie = CUDIE (cu);
Dwarf_Attribute dwo_name;
/* It is fine if dwo_dir doesn't exists, but then dwo_name needs
to be an absolute path. */
- if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
+ if (dwarf_attr (&cudie, DW_AT_dwo_name, &dwo_name) != NULL
|| dwarf_attr (&cudie, DW_AT_GNU_dwo_name, &dwo_name) != NULL)
{
/* First try the dwo file name in the same directory
@@ -110,13 +130,17 @@ __libdw_find_split_unit (Dwarf_CU *cu)
const char *dwo_file = dwarf_formstring (&dwo_name);
const char *debugdir = cu->dbg->debugdir;
char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
- if (dwo_path != NULL)
+ if (dwo_path != NULL)
{
try_split_file (cu, dwo_path);
free (dwo_path);
}
- if (cu->split == (Dwarf_CU *) -1)
+ rwlock_rdlock(cu_split_lock);
+ cu_split_local = cu->split;
+ rwlock_unlock(cu_split_lock);
+
+ if (cu_split_local == (Dwarf_CU *) -1)
{
/* Try compdir plus dwo_name. */
Dwarf_Attribute compdir;
@@ -138,9 +162,15 @@ __libdw_find_split_unit (Dwarf_CU *cu)
}
}
- /* If we found nothing, make sure we don't try again. */
- if (cu->split == (Dwarf_CU *) -1)
- cu->split = NULL;
+ rwlock_wrlock(cu_split_lock);
+
+ /* If we found nothing, make sure we don't try again. */
+ if (cu->split == (Dwarf_CU *) -1)
+ {
+ cu->split = NULL;
+ cu_split_local = cu->split;
+ }
- return cu->split;
+ rwlock_unlock(cu_split_lock);
+ return cu_split_local;
}
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index ed744231..97fcf812 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -32,9 +32,13 @@
#endif
#include <assert.h>
-#include <search.h>
+#include <eu-search.h>
#include "libdwP.h"
+/* __libdw_findcu modifies "&dbg->next_tu_offset : &dbg->next_cu_offset".
+ May read or write, so mutual exclusion is enforced to prevent a race. */
+rwlock_define(static, next_tucu_offset_lock);
+
static int
findcu_cb (const void *arg1, const void *arg2)
{
@@ -213,7 +217,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
/* Add the new entry to the search tree. */
- if (tsearch (newp, tree, findcu_cb) == NULL)
+ if (eu_tsearch (newp, tree, findcu_cb) == NULL)
{
/* Something went wrong. Undo the operation. */
*offsetp = oldoff;
@@ -234,28 +238,40 @@ __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
/* Maybe we already know that CU. */
struct Dwarf_CU fake = { .start = start, .end = 0 };
- struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
- if (found != NULL)
+ struct Dwarf_CU **found = eu_tfind (&fake, tree, findcu_cb);
+ struct Dwarf_CU *result = NULL;
+
+ if (found != NULL){
return *found;
+ }
- if (start < *next_offset)
- {
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
- }
+ rwlock_wrlock(next_tucu_offset_lock);
- /* No. Then read more CUs. */
- while (1)
+ if (start < *next_offset)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ }
+ else
+ {
+ /* No. Then read more CUs. */
+ while (1)
{
struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
- if (newp == NULL)
- return NULL;
+ if (newp == NULL){
+ result = NULL;
+ break;
+ }
/* Is this the one we are looking for? */
- if (start < *next_offset || start == newp->start)
- return newp;
+ if (start < *next_offset || start == newp->start){
+ result = newp;
+ break;
+ }
}
- /* NOTREACHED */
+ }
+
+ rwlock_unlock(next_tucu_offset_lock);
+ return result;
}
struct Dwarf_CU *
@@ -283,7 +299,7 @@ __libdw_findcu_addr (Dwarf *dbg, void *addr)
return NULL;
struct Dwarf_CU fake = { .start = start, .end = 0 };
- struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
+ struct Dwarf_CU **found = eu_tfind (&fake, tree, findcu_cb);
if (found != NULL)
return *found;
@@ -298,7 +314,7 @@ __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
/* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
- Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
+ Dwarf **found = eu_tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
if (found != NULL)
return *found;
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 54d85921..b90920ac 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,8 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * cu.c: Add eu-search.h and remove search.h.
+ Change call of tsearch to eu_tsearch.
+
2023-04-24 John Gallagher <john@gllghr.com>
* gzip.c: Fix memory leak in unzip()
diff --git a/libdwfl/cu.c b/libdwfl/cu.c
index b1afb19a..71838011 100644
--- a/libdwfl/cu.c
+++ b/libdwfl/cu.c
@@ -33,7 +33,7 @@
#include "libdwflP.h"
#include "libdwP.h"
#include "memory-access.h"
-#include <search.h>
+#include <eu-search.h>
static inline Dwarf_Arange *
@@ -198,7 +198,7 @@ intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
struct dwfl_cu key;
key.die.cu = die->cu;
- struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
+ struct dwfl_cu **found = eu_tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
if (unlikely (found == NULL))
return DWFL_E_NOMEM;
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 1d5178ca..4a1ece30 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,6 +1,15 @@
-2023-04-01 Youling Tang <tangyouling@loongson.cn>
-
- * elf.h: Update from glibc.
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * elf32_getchdr.c: Move getchdr function to elf32_getchdr.h
+ * elf32_getchdr.h: New file.
+ Add macro to create getchdr_wrlock.
+ * elf32_updatenull.c: Change call from getchdr to getchdr_wrlock.
+ * elf_getdata.c: Add elf_getdata_wrlock.
+ * libelfP.h: Add internal function declarations.
+ * elf_cntl.c: Adjust locks to prevent deadlock.
+ * elf_end.c: Likewise.
+ * elf_readall.c: Likewise.
+ * elf_version.c: Likewise.
2023-03-03 Mark Wielaard <mark@klomp.org>
diff --git a/libelf/elf32_getchdr.c b/libelf/elf32_getchdr.c
index 982a614c..41591300 100644
--- a/libelf/elf32_getchdr.c
+++ b/libelf/elf32_getchdr.c
@@ -38,46 +38,8 @@
# define LIBELFBITS 32
#endif
+#define ELF_WRLOCK_HELD 1
+#include "elf32_getchdr.h"
-ElfW2(LIBELFBITS,Chdr) *
-elfw2(LIBELFBITS,getchdr) (Elf_Scn *scn)
-{
- ElfW2(LIBELFBITS,Shdr) *shdr = elfw2(LIBELFBITS,getshdr) (scn);
- if (shdr == NULL)
- return NULL;
-
- /* Must have SHF_COMPRESSED flag set. Allocated or no bits sections
- can never be compressed. */
- if ((shdr->sh_flags & SHF_ALLOC) != 0)
- {
- __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
- return NULL;
- }
-
- if (shdr->sh_type == SHT_NULL
- || shdr->sh_type == SHT_NOBITS)
- {
- __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
- return NULL;
- }
-
- if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
- {
- __libelf_seterrno (ELF_E_NOT_COMPRESSED);
- return NULL;
- }
-
- /* This makes sure the data is in the correct format, so we don't
- need to swap fields. */
- Elf_Data *d = elf_getdata (scn, NULL);
- if (d == NULL)
- return NULL;
-
- if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
- {
- __libelf_seterrno (ELF_E_INVALID_DATA);
- return NULL;
- }
-
- return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
-}
+#define ELF_WRLOCK_HELD 0
+#include "elf32_getchdr.h"
\ No newline at end of file
diff --git a/libelf/elf32_getchdr.h b/libelf/elf32_getchdr.h
new file mode 100644
index 00000000..04d47e7a
--- /dev/null
+++ b/libelf/elf32_getchdr.h
@@ -0,0 +1,61 @@
+#undef ADD_ROUTINE_PREFIX
+#undef ADD_ROUTINE_SUFFIX
+
+#if ELF_WRLOCK_HELD
+#define CONCAT(x,y) x##y
+#define ADD_ROUTINE_PREFIX(y) CONCAT(__,y)
+#define ADD_ROUTINE_SUFFIX(x) x ## _wrlock
+#define INTERNAL internal_function
+#else
+#define ADD_ROUTINE_PREFIX(y) y
+#define ADD_ROUTINE_SUFFIX(x) x
+#define INTERNAL
+#endif
+
+ElfW2(LIBELFBITS,Chdr) *
+INTERNAL
+ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, ADD_ROUTINE_SUFFIX(getchdr))) (Elf_Scn *scn)
+{
+
+ ElfW2(LIBELFBITS,Shdr) *shdr = ADD_ROUTINE_PREFIX(elfw2(LIBELFBITS, ADD_ROUTINE_SUFFIX(getshdr)))(scn);
+
+ if (shdr == NULL)
+ return NULL;
+
+ /* Must have SHF_COMPRESSED flag set. Allocated or no bits sections
+ can never be compressed. */
+ if ((shdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
+ return NULL;
+ }
+
+ if (shdr->sh_type == SHT_NULL
+ || shdr->sh_type == SHT_NOBITS)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
+ return NULL;
+ }
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
+ {
+ __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+ return NULL;
+ }
+
+ /* This makes sure the data is in the correct format, so we don't
+ need to swap fields. */
+ Elf_Data *d = ADD_ROUTINE_PREFIX(ADD_ROUTINE_SUFFIX(elf_getdata)) (scn, NULL);
+ if (d == NULL)
+ return NULL;
+
+ if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ return NULL;
+ }
+
+ return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
+}
+#undef INTERNAL
+#undef ELF_WRLOCK_HELD
\ No newline at end of file
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
index 6c06e5e4..04bec8d4 100644
--- a/libelf/elf32_updatenull.c
+++ b/libelf/elf32_updatenull.c
@@ -404,7 +404,7 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
else
{
ElfW2(LIBELFBITS,Chdr) *chdr;
- chdr = elfw2(LIBELFBITS,getchdr) (scn);
+ chdr = __elfw2(LIBELFBITS,getchdr_wrlock) (scn);
if (unlikely (chdr == NULL))
return -1;
sh_size = chdr->ch_size;
diff --git a/libelf/elf_cntl.c b/libelf/elf_cntl.c
index 04aa9132..64087c7d 100644
--- a/libelf/elf_cntl.c
+++ b/libelf/elf_cntl.c
@@ -48,13 +48,16 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
return -1;
}
- rwlock_wrlock (elf->lock);
+
switch (cmd)
{
case ELF_C_FDREAD:
+ rwlock_rdlock (elf->lock);
+ int addr_isnull = elf->map_address == NULL;
+ rwlock_unlock(elf->lock);
/* If not all of the file is in the memory read it now. */
- if (elf->map_address == NULL && __libelf_readall (elf) == NULL)
+ if (addr_isnull && __libelf_readall (elf) == NULL)
{
/* We were not able to read everything. */
result = -1;
@@ -64,7 +67,9 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
case ELF_C_FDDONE:
/* Mark the file descriptor as not usable. */
+ rwlock_wrlock (elf->lock);
elf->fildes = -1;
+ rwlock_unlock (elf->lock);
break;
default:
@@ -73,7 +78,5 @@ elf_cntl (Elf *elf, Elf_Cmd cmd)
break;
}
- rwlock_unlock (elf->lock);
-
return result;
}
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
index 3e5d4c86..afe52c19 100644
--- a/libelf/elf_end.c
+++ b/libelf/elf_end.c
@@ -81,8 +81,10 @@ elf_end (Elf *elf)
free (elf->state.ar.ar_sym);
elf->state.ar.ar_sym = NULL;
- if (elf->state.ar.children != NULL)
- return 0;
+ if (elf->state.ar.children != NULL){
+ rwlock_unlock(elf->lock);
+ return 0;
+ }
}
/* Remove this structure from the children list. */
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index 5ebd270f..7c3ac043 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -582,4 +582,18 @@ elf_getdata (Elf_Scn *scn, Elf_Data *data)
return result;
}
+
+Elf_Data *
+internal_function
+__elf_getdata_wrlock (Elf_Scn *scn, Elf_Data *data)
+{
+ Elf_Data *result;
+
+ if (scn == NULL)
+ return NULL;
+
+ result = __elf_getdata_rdlock (scn, data);
+
+ return result;
+}
INTDEF(elf_getdata)
diff --git a/libelf/elf_readall.c b/libelf/elf_readall.c
index d0f9a28c..1af98417 100644
--- a/libelf/elf_readall.c
+++ b/libelf/elf_readall.c
@@ -84,6 +84,7 @@ __libelf_readall (Elf *elf)
/* If this is an archive and we have derived descriptors get the
locks for all of them. */
+ rwlock_unlock(elf->lock); // lock will be reacquired next line
libelf_acquire_all (elf);
if (elf->maximum_size == ~((size_t) 0))
@@ -141,10 +142,8 @@ __libelf_readall (Elf *elf)
__libelf_seterrno (ELF_E_NOMEM);
/* Free the locks on the children. */
- libelf_release_all (elf);
+ libelf_release_all (elf); // lock is released
}
- rwlock_unlock (elf->lock);
-
return (char *) elf->map_address;
}
diff --git a/libelf/elf_version.c b/libelf/elf_version.c
index 6ec534ab..8296bb65 100644
--- a/libelf/elf_version.c
+++ b/libelf/elf_version.c
@@ -32,12 +32,21 @@
#endif
#include <libelfP.h>
+#include <pthread.h>
+/* Multiple threads may initialize __libelf_version.
+ pthread_once() ensures that __libelf_version is initialized only once. */
+once_define(static, version_once);
/* Currently selected version. Should be EV_CURRENT.
Will be EV_NONE if elf_version () has not been called yet. */
unsigned int __libelf_version = EV_NONE;
+static void initialize_version(void)
+{
+ __libelf_version = EV_CURRENT;
+}
+
unsigned int
elf_version (unsigned int version)
{
@@ -49,7 +58,7 @@ elf_version (unsigned int version)
/* Phew, we know this version. */
/* Signal that the version is now initialized. */
- __libelf_version = EV_CURRENT;
+ once(version_once, initialize_version);
/* And return the last (or initial) version. */
return EV_CURRENT;
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index d3c241e5..5e5df589 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -512,6 +512,8 @@ extern Elf32_Shdr *__elf32_getshdr_rdlock (Elf_Scn *__scn) internal_function;
extern Elf64_Shdr *__elf64_getshdr_rdlock (Elf_Scn *__scn) internal_function;
extern Elf32_Shdr *__elf32_getshdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf64_Shdr *__elf64_getshdr_wrlock (Elf_Scn *__scn) internal_function;
+extern Elf32_Chdr *__elf32_getchdr_wrlock (Elf_Scn *__scn) internal_function;
+extern Elf64_Chdr *__elf64_getchdr_wrlock (Elf_Scn *__scn) internal_function;
extern Elf_Scn *__elf_getscn_internal (Elf *__elf, size_t __index)
attribute_hidden;
extern Elf_Scn *__elf_nextscn_internal (Elf *__elf, Elf_Scn *__scn)
@@ -521,6 +523,8 @@ extern Elf_Data *__elf_getdata_internal (Elf_Scn *__scn, Elf_Data *__data)
attribute_hidden;
extern Elf_Data *__elf_getdata_rdlock (Elf_Scn *__scn, Elf_Data *__data)
internal_function;
+extern Elf_Data *__elf_getdata_wrlock (Elf_Scn *__scn, Elf_Data *__data)
+ internal_function;
extern Elf_Data *__elf_rawdata_internal (Elf_Scn *__scn, Elf_Data *__data)
attribute_hidden;
/* Should be called to setup first section data element if
diff --git a/src/ChangeLog b/src/ChangeLog
index ae62f4ed..55a2887a 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,10 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * Makefile.am: Add USE_LOCKS condition for -pthread.
+ * findtextrel.c: Add eu-search.h and remove search.h.
+ Change calls of tsearch/tfind to eu_tsearch/eu_tfind.
+ * nm.c: Likewise.
+
2023-03-27 Di Chen <dichen@redhat.com>
* readelf.c (options): Support dynamic symtab print with '-Ds'.
diff --git a/src/Makefile.am b/src/Makefile.am
index 10d59a48..fea5d43e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,9 @@ DEFS += $(YYDEBUG) -DDEBUGPRED=@DEBUGPRED@ \
AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
-I$(srcdir)/../libdw -I$(srcdir)/../libdwelf \
-I$(srcdir)/../libdwfl -I$(srcdir)/../libasm
+if USE_LOCKS
+ AM_CFLAGS += -pthread
+endif
AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw $(STACK_USAGE_NO_ERROR)
diff --git a/src/findtextrel.c b/src/findtextrel.c
index d3021a3a..5ac4c29a 100644
--- a/src/findtextrel.c
+++ b/src/findtextrel.c
@@ -27,7 +27,7 @@
#include <gelf.h>
#include <libdw.h>
#include <locale.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@@ -501,10 +501,10 @@ check_rel (size_t nsegments, struct segments segments[nsegments],
/* There can be more than one relocation against one file.
Try to avoid multiple messages. And yes, the code uses
pointer comparison. */
- if (tfind (src, knownsrcs, ptrcompare) == NULL)
+ if (eu_tfind (src, knownsrcs, ptrcompare) == NULL)
{
printf (_("%s not compiled with -fpic/-fPIC\n"), src);
- tsearch (src, knownsrcs, ptrcompare);
+ eu_tsearch (src, knownsrcs, ptrcompare);
}
return;
}
@@ -555,12 +555,12 @@ check_rel (size_t nsegments, struct segments segments[nsegments],
if (sym->st_value + sym->st_size > addr)
{
/* It is this function. */
- if (tfind (lowstr, knownsrcs, ptrcompare) == NULL)
+ if (eu_tfind (lowstr, knownsrcs, ptrcompare) == NULL)
{
printf (_("\
the file containing the function '%s' is not compiled with -fpic/-fPIC\n"),
lowstr);
- tsearch (lowstr, knownsrcs, ptrcompare);
+ eu_tsearch (lowstr, knownsrcs, ptrcompare);
}
}
else if (highidx == -1)
diff --git a/src/nm.c b/src/nm.c
index fbdee8e1..44c20fb2 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -32,7 +32,7 @@
#include <libdw.h>
#include <locale.h>
#include <obstack.h>
-#include <search.h>
+#include <eu-search.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdio_ext.h>
@@ -537,7 +537,7 @@ static int
get_global (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
void *arg __attribute__ ((unused)))
{
- tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
+ eu_tsearch (memcpy (xmalloc (sizeof (Dwarf_Global)), global,
sizeof (Dwarf_Global)),
&global_root, global_compare);
@@ -696,7 +696,7 @@ get_local_names (Dwarf *dbg)
/* Check whether a similar local_name is already in the
cache. That should not happen. But if it does, we
don't want to leak memory. */
- struct local_name **tres = tsearch (newp, &local_root,
+ struct local_name **tres = eu_tsearch (newp, &local_root,
local_compare);
if (tres == NULL)
error_exit (errno, _("cannot create search tree"));
@@ -1387,7 +1387,7 @@ show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
&& global_root != NULL)
{
Dwarf_Global fake = { .name = symstr };
- Dwarf_Global **found = tfind (&fake, &global_root,
+ Dwarf_Global **found = eu_tfind (&fake, &global_root,
global_compare);
if (found != NULL)
{
@@ -1442,7 +1442,7 @@ show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr,
.lowpc = sym->st_value,
.highpc = sym->st_value,
};
- struct local_name **found = tfind (&fake, &local_root,
+ struct local_name **found = eu_tfind (&fake, &local_root,
local_compare);
if (found != NULL)
{
diff --git a/tests/ChangeLog b/tests/ChangeLog
index d816873c..116876f9 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,24 @@
+2023-08-08 Heather McIntyre <hsm2@rice.edu>
+
+ * eu_search_cfi.c: New file.
+ * eu_search_die.c: New file.
+ * eu_search_lines.c: New file.
+ * eu_search_macros.c: New file.
+ * run-eu-search-tests.sh: New test.
+ * Makefile.am: Add USE_LOCKS condition for -pthread.
+ * Makefile.am (check_PROGRAMS): Add eu_search_cfi, eu_search_die,
+ eu_search_lines, and eu_search_macros.
+ (TESTS): Add run-eu-search-tests.sh
+ (eu_search_cfi_LDADD): New variable.
+ (eu_search_die_LDADD): New variable.
+ (eu_search_lines_LDADD): New variable.
+ (eu_search_macros_LDADD): New variable.
+ (eu_search_cfi_LDFLAGS): New variable.
+ Add -pthread if USE_LOCKS is not defined.
+ (eu_search_die_LDFLAGS): Likewise.
+ (eu_search_lines_LDFLAGS): Likewise.
+ (eu_search_macros_LDFLAGS): Likewise.
+
2023-04-21 Frank Ch. Eigler <fche@redhat.com>
* run-debuginfod-IXr.sh: New test.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0c77f658..961e282d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -32,6 +32,10 @@ else
tests_rpath = no
endif
+if USE_LOCKS
+ AM_CFLAGS += -pthread
+endif
+
check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
showptable update1 update2 update3 update4 test-nlist \
show-die-info get-files next-files get-lines next-lines \
@@ -63,6 +67,7 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
getphdrnum leb128 read_unaligned \
msg_tst system-elf-libelf-test \
nvidia_extended_linemap_libdw \
+ eu_search_cfi eu_search_die eu_search_lines eu_search_macros \
$(asm_TESTS)
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
@@ -211,7 +216,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
$(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \
run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \
run-readelf-dw-form-indirect.sh run-strip-largealign.sh \
- run-readelf-Dd.sh
+ run-readelf-Dd.sh \
+ run-eu-search-tests.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
@@ -804,6 +810,14 @@ getphdrnum_LDADD = $(libelf) $(libdw)
leb128_LDADD = $(libelf) $(libdw)
read_unaligned_LDADD = $(libelf) $(libdw)
nvidia_extended_linemap_libdw_LDADD = $(libelf) $(libdw)
+eu_search_cfi_LDFLAGS = $(if $(filter undefined,$(origin USE_LOCKS)),-pthread) $(AM_LDFLAGS)
+eu_search_die_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_die_LDADD = $(libdw)
+eu_search_lines_LDADD = $(libdw) $(libelf)
+eu_search_macros_LDADD = $(libdw)
# We want to test the libelf header 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..0b63b213
--- /dev/null
+++ b/tests/eu_search_cfi.c
@@ -0,0 +1,234 @@
+/*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);
+ free(data);
+ 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 = (pthread_t*) malloc(num_threads * sizeof(pthread_t));
+ ThreadData **thread_data = (ThreadData**) malloc(num_threads * sizeof(ThreadData*));
+ int thread_count = 0;
+
+ if (!threads || !thread_data)
+ {
+ fprintf(stderr, "Failed to allocate memory for threads.\n");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+
+ 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;
+ }
+
+ if (thread_count >= num_threads)
+ {
+ num_threads *= 2;
+ threads = realloc(threads, num_threads * sizeof(pthread_t));
+ thread_data = realloc(thread_data, num_threads * sizeof(ThreadData*));
+ }
+
+ thread_data[thread_count] = malloc(sizeof(ThreadData));
+ thread_data[thread_count]->name = name;
+ thread_data[thread_count]->e_ident = ident;
+ thread_data[thread_count]->scn = scn;
+ thread_data[thread_count]->is_eh = is_eh;
+
+ if (pthread_create(&threads[thread_count], NULL, thread_work, thread_data[thread_count]) != 0)
+ {
+ perror("Failed to create thread");
+ for (int j = 0; j < thread_count; j++)
+ {
+ pthread_cancel(threads[j]);
+ }
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ else
+ {
+ thread_count++;
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < thread_count; i++)
+ {
+ if (pthread_join(threads[i], NULL) != 0)
+ {
+ perror("Failed to join thread");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < thread_count; i++)
+ {
+ free(thread_data[i]);
+ }
+
+ free(threads);
+ free(thread_data);
+
+ elf_end(elf);
+ close(fd);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/eu_search_die.c b/tests/eu_search_die.c
new file mode 100644
index 00000000..a7f75521
--- /dev/null
+++ b/tests/eu_search_die.c
@@ -0,0 +1,262 @@
+/*Test program for eu_search_die.
+ 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 ELFUTILS_HEADER(dw)
+#include <dwarf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+
+static void *thread_work(void *arg);
+static int check_die(Dwarf_Die *die);
+static int check_dbg(Dwarf *dbg);
+
+/*The main Dwarf file. */
+static Dwarf * dwarf;
+
+typedef struct
+{
+ Dwarf * dbg;
+ Dwarf_Off start_offset;
+ Dwarf_Off end_offset;
+ int result;
+}
+
+ThreadData;
+
+static void *thread_work(void *arg)
+{
+ ThreadData *data = (ThreadData*) arg;
+ data->result = check_dbg(data->dbg);
+ return NULL;
+}
+
+static int check_die(Dwarf_Die *die)
+{
+ if (dwarf_tag(die) == DW_TAG_invalid)
+ {
+ printf("Invalid die\n");
+ return -1;
+ }
+
+ int res = 0;
+ void *addr = die->addr;
+ Dwarf_Die die2;
+ if (dwarf_die_addr_die(dwarf, addr, &die2) == NULL)
+ {
+ printf("Bad die addr die at offset %" PRIx64 "\n", dwarf_dieoffset(die));
+ res = -1;
+ }
+
+ if (dwarf_tag(die) != dwarf_tag(&die2))
+ {
+ printf("Tags differ for die at offset %" PRIx64 "\n", dwarf_dieoffset(die));
+ res = -1;
+ }
+
+ if (dwarf_cuoffset(die) != dwarf_cuoffset(&die2))
+ {
+ printf("CU offsets differ for die at offset %" PRIx64 "\n", dwarf_dieoffset(die));
+ res = -1;
+ }
+
+ Dwarf_Die child;
+ if (dwarf_child(die, &child) == 0)
+ res |= check_die(&child);
+
+ Dwarf_Die sibling;
+ if (dwarf_siblingof(die, &sibling) == 0)
+ res |= check_die(&sibling);
+
+ return res;
+}
+
+static int check_dbg(Dwarf *dbg)
+{
+ int res = 0;
+ Dwarf_Off off = 0;
+ Dwarf_Off old_off = 0;
+ size_t hsize;
+ Dwarf_Off abbrev;
+ uint8_t addresssize;
+ uint8_t offsetsize;
+
+ while (dwarf_nextcu(dbg, off, &off, &hsize, &abbrev, &addresssize, &offsetsize) == 0)
+ {
+ Dwarf_Die die;
+ if (dwarf_offdie(dbg, old_off + hsize, &die) != NULL)
+ {
+ printf("checking CU at %" PRIx64 "\n", old_off);
+ res |= check_die(&die);
+ }
+
+ old_off = off;
+ }
+
+ // Same for type...
+ Dwarf_Half version;
+ uint64_t typesig;
+ Dwarf_Off typeoff;
+ off = 0;
+ old_off = 0;
+
+ while (dwarf_next_unit(dbg, off, &off, &hsize, &version, &abbrev, &addresssize, &offsetsize, &typesig, &typeoff) == 0)
+ {
+ Dwarf_Die die;
+ if (dwarf_offdie_types(dbg, old_off + hsize, &die) != NULL)
+ {
+ printf("checking TU at %" PRIx64 "\n", old_off);
+ res |= check_die(&die);
+ }
+
+ // We should have seen this already, but double check...
+ if (dwarf_offdie_types(dbg, old_off + typeoff, &die) != NULL)
+ {
+ printf("checking Type DIE at %" PRIx64 "\n", old_off + hsize + typeoff);
+ res |= check_die(&die);
+ }
+
+ old_off = off;
+ }
+
+ Dwarf *alt = dwarf_getalt(dbg);
+
+ if (alt != NULL)
+ {
+ printf("checking alt debug\n");
+ res |= check_dbg(alt);
+ }
+
+ // Split or Type Dwarf_Dies gotten through dwarf_get_units.
+ Dwarf_CU *cu = NULL;
+ Dwarf_Die subdie;
+ uint8_t unit_type;
+ while (dwarf_get_units(dbg, cu, &cu, NULL, &unit_type, NULL, &subdie) == 0)
+ {
+ if (dwarf_tag(&subdie) != DW_TAG_invalid)
+ {
+ printf("checking %"
+ PRIx8 " subdie\n", unit_type);
+ res |= check_die(&subdie);
+ }
+ }
+
+ return res;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2)
+ {
+ printf("No file given.\n");
+ return -1;
+ }
+
+ const char *name = argv[1];
+ int fd = open(name, O_RDONLY);
+ if (fd < 0)
+ {
+ printf("Cannot open '%s': %s\n", name, strerror(errno));
+ return -1;
+ }
+
+ dwarf = dwarf_begin(fd, DWARF_C_READ);
+ if (dwarf == NULL)
+ {
+ printf("Not a Dwarf file '%s': %s\n", name, dwarf_errmsg(-1));
+ close(fd);
+ return -1;
+ }
+
+ printf("checking %s\n", name);
+
+ int num_threads = 4;
+ pthread_t *threads = (pthread_t*) malloc(num_threads* sizeof(pthread_t));
+ ThreadData *thread_data = (ThreadData*) malloc(num_threads* sizeof(ThreadData));
+
+ if (!threads || !thread_data)
+ {
+ fprintf(stderr, "Failed to allocate memory for threads.\n");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+
+ Dwarf_Off total_off = 0;
+ Dwarf_Off unit_off = 0;
+ size_t hsize;
+ Dwarf_Off abbrev;
+ uint8_t addresssize;
+ uint8_t offsetsize;
+
+ while (dwarf_nextcu(dwarf, unit_off, &unit_off, &hsize, &abbrev, &addresssize, &offsetsize) == 0)
+ {
+ thread_data[total_off % num_threads].start_offset = unit_off;
+ thread_data[total_off % num_threads].end_offset = unit_off + hsize;
+ total_off++;
+ }
+
+ for (int i = 0; i < num_threads; i++)
+ {
+ thread_data[i].dbg = dwarf;
+ if (pthread_create(&threads[i], NULL, thread_work, (void*) &thread_data[i]) != 0)
+ {
+ perror("Failed to create thread");
+ for (int j = 0; j < i; j++)
+ {
+ pthread_cancel(threads[j]);
+ }
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < num_threads; i++)
+ {
+ if (pthread_join(threads[i], NULL) != 0)
+ {
+ perror("Failed to join thread");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ int res = 0;
+ for (int i = 0; i < num_threads; i++)
+ {
+ res |= thread_data[i].result;
+ }
+
+ free(threads);
+ free(thread_data);
+
+ dwarf_end(dwarf);
+ close(fd);
+
+ return res;
+}
\ No newline at end of file
diff --git a/tests/eu_search_lines.c b/tests/eu_search_lines.c
new file mode 100644
index 00000000..b7a875d8
--- /dev/null
+++ b/tests/eu_search_lines.c
@@ -0,0 +1,228 @@
+/*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>
+
+typedef struct
+{
+ const char *filename;
+ int result;
+}
+
+ThreadData;
+
+static void *thread_work(void *arg)
+{
+ ThreadData *data = (ThreadData*) arg;
+
+ int fd = open(data->filename, O_RDONLY);
+
+ Dwarf *dbg = dwarf_begin(fd, DWARF_C_READ);
+ if (dbg == NULL)
+ {
+ printf("%s not usable: %s\n", data->filename, dwarf_errmsg(-1));
+ close(fd);
+ free(data);
+ pthread_exit(NULL);
+ }
+
+ 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("%s: cannot get CU die\n", data->filename);
+ data->result = 1;
+ break;
+ }
+
+ old_cuoff = cuoff;
+
+ Dwarf_Lines * lb;
+ size_t nlb;
+ if (dwarf_getsrclines(&die, &lb, &nlb) != 0)
+ {
+ printf("%s: cannot get lines\n", data->filename);
+ data->result = 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("%s: cannot get individual line\n", data->filename);
+ data->result = 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("%s: cannot get file from line (%zd): %s\n",
+ data->filename, i, dwarf_errmsg(-1));
+ data->result = 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("%s: line %zd srcline (%s) != file srcline (%s)\n",
+ data->filename, i, file ? : "???", path ? : "???");
+ data->result = 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");
+ }
+ }
+
+ dwarf_end(dbg);
+ close(fd);
+ free(data);
+
+ pthread_exit(NULL);
+}
+
+int main(int argc, char *argv[])
+{
+ int result = 0;
+ int cnt;
+
+ if (argc < 2)
+ {
+ printf("Usage: %s<filename1>[<filename2> ...]\n", argv[0]);
+ return 1;
+ }
+
+ pthread_t *threads = (pthread_t*) malloc((argc - 1) *sizeof(pthread_t));
+ ThreadData **thread_data = (ThreadData **) malloc((argc - 1) *sizeof(ThreadData*));
+
+ if (!threads || !thread_data)
+ {
+ fprintf(stderr, "Failed to allocate memory for threads.\n");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+
+ for (cnt = 1; cnt < argc; ++cnt)
+ {
+ thread_data[cnt - 1] = (ThreadData*) malloc(sizeof(ThreadData));
+ thread_data[cnt - 1]->filename = argv[cnt];
+ thread_data[cnt - 1]->result = 0;
+
+ if (pthread_create(&threads[cnt - 1], NULL, thread_work, thread_data[cnt - 1]) != 0)
+ {
+ perror("Failed to create thread");
+ for (int j = 0; j < cnt; j++)
+ {
+ pthread_cancel(threads[j]);
+ }
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ for (cnt = 0; cnt < argc - 1; ++cnt)
+ {
+ if (pthread_join(threads[cnt], NULL) != 0)
+ {
+ perror("Failed to join thread");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+
+ if (thread_data[cnt]->result != 0)
+ {
+ result = 1;
+ }
+
+ free(thread_data[cnt]);
+ }
+
+ free(threads);
+ free(thread_data);
+
+ return result;
+}
\ No newline at end of file
diff --git a/tests/eu_search_macros.c b/tests/eu_search_macros.c
new file mode 100644
index 00000000..3dca828e
--- /dev/null
+++ b/tests/eu_search_macros.c
@@ -0,0 +1,216 @@
+/*Test program for eu_search_macros
+ 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 ELFUTILS_HEADER(dw)
+#include <dwarf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+#include <stdatomic.h>
+#include <pthread.h>
+
+static void *thread_work(void *arg);
+static int mac(Dwarf_Macro *macro, void *dbg);
+static void include(Dwarf *dbg, Dwarf_Off macoff, ptrdiff_t token);
+
+typedef struct
+{
+ Dwarf * dbg;
+ Dwarf_Die * cudie;
+ bool new_style;
+}
+
+ThreadData;
+
+static void *thread_work(void *arg)
+{
+ ThreadData *data = (ThreadData*) arg;
+ Dwarf *dbg = data->dbg;
+ Dwarf_Die *cudie = data->cudie;
+ bool new_style = data->new_style;
+
+ for (ptrdiff_t off = new_style ? DWARF_GETMACROS_START : 0;
+ (off = dwarf_getmacros(cudie, mac, dbg, off));)
+ {
+ if (off == -1)
+ {
+ puts(dwarf_errmsg(dwarf_errno()));
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static void include(Dwarf *dbg, Dwarf_Off macoff, ptrdiff_t token)
+{
+ while ((token = dwarf_getmacros_off(dbg, macoff, mac, dbg, token)) != 0)
+ {
+ if (token == -1)
+ {
+ puts(dwarf_errmsg(dwarf_errno()));
+ break;
+ }
+ }
+}
+
+static int
+mac(Dwarf_Macro *macro, void *dbg)
+{
+ static atomic_int level = 0;
+
+ unsigned int opcode;
+ dwarf_macro_opcode(macro, &opcode);
+ switch (opcode)
+ {
+ case DW_MACRO_import:
+ {
+ Dwarf_Attribute at;
+ int r = dwarf_macro_param(macro, 0, &at);
+ assert(r == 0);
+
+ Dwarf_Word w;
+ r = dwarf_formudata(&at, &w);
+ assert(r == 0);
+
+ printf ("%*sinclude %#" PRIx64 "\n", level, "", w);
+
+ atomic_fetch_add(&level, 1);
+
+ include(dbg, w, DWARF_GETMACROS_START);
+
+ atomic_fetch_sub(&level, 1);
+
+ printf ("%*s/include\n", level, "");
+ break;
+ }
+
+ case DW_MACRO_start_file:
+ {
+ Dwarf_Files * files;
+ size_t nfiles;
+ if (dwarf_macro_getsrcfiles(dbg, macro, &files, &nfiles) < 0)
+ printf("dwarf_macro_getsrcfiles: %s\n", dwarf_errmsg(dwarf_errno()));
+
+ Dwarf_Word w = 0;
+ dwarf_macro_param2(macro, &w, NULL);
+
+ const char *name = dwarf_filesrc (files, (size_t) w, NULL, NULL);
+ printf ("%*sfile %s\n", level, "", name);
+ atomic_fetch_add(&level, 1);
+ break;
+ }
+
+ case DW_MACRO_end_file:
+ {
+ atomic_fetch_sub(&level, 1);
+ printf ("%*s/file\n", level, "");
+ break;
+ }
+
+ case DW_MACINFO_define:
+ case DW_MACRO_define_strp:
+ {
+ const char *value;
+ dwarf_macro_param2(macro, NULL, &value);
+ printf ("%*s%s\n", level, "", value);
+ break;
+ }
+
+ case DW_MACINFO_undef:
+ case DW_MACRO_undef_strp:
+ break;
+
+ default:
+ {
+ size_t paramcnt;
+ dwarf_macro_getparamcnt(macro, ¶mcnt);
+ printf ("%*sopcode %u with %zd arguments\n", level, "", opcode, paramcnt);
+ break;
+ }
+ }
+
+ return DWARF_CB_ABORT;
+}
+
+int main(int argc, char *argv[])
+{
+ assert(argc >= 3);
+ const char *name = argv[1];
+ ptrdiff_t cuoff = strtol(argv[2], NULL, 0);
+ bool new_style = argc > 3;
+
+ int fd = open(name, O_RDONLY);
+ Dwarf *dbg = dwarf_begin(fd, DWARF_C_READ);
+
+ Dwarf_Die cudie_mem, *cudie = dwarf_offdie(dbg, cuoff, &cudie_mem);
+
+ int num_threads = 4;
+ pthread_t *threads = malloc(num_threads* sizeof(pthread_t));
+ ThreadData *thread_data = malloc(num_threads* sizeof(ThreadData));
+
+ if (!threads || !thread_data)
+ {
+ fprintf(stderr, "Failed to allocate memory for threads.\n");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+
+ for (int i = 0; i < num_threads; i++)
+ {
+ thread_data[i].dbg = dbg;
+ thread_data[i].cudie = cudie;
+ thread_data[i].new_style = new_style;
+
+ if (pthread_create(&threads[i], NULL, thread_work, (void*) &thread_data[i]) != 0)
+ {
+ perror("Failed to create thread");
+ for (int j = 0; j < i; j++)
+ {
+ pthread_cancel(threads[j]);
+ }
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ for (int i = 0; i < num_threads; i++)
+ {
+ if (pthread_join(threads[i], NULL) != 0)
+ {
+ perror("Failed to join thread");
+ free(threads);
+ free(thread_data);
+ return 1;
+ }
+ }
+
+ free(threads);
+ free(thread_data);
+
+ dwarf_end(dbg);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/run-eu-search-tests.sh b/tests/run-eu-search-tests.sh
new file mode 100644
index 00000000..84edc234
--- /dev/null
+++ b/tests/run-eu-search-tests.sh
@@ -0,0 +1,168 @@
+#! /bin/sh
+# 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/test-subr.sh
+
+# Extract the value of USE_ADDRESS_SANITIZER_TRUE from config.status
+# Cannot use Helgrind and Address Sanitizer together.
+# Test will be skipped if Address Sanitizer is enabled.
+USE_ADDRESS_SANITIZER=$(grep 'USE_ADDRESS_SANITIZER_TRUE' ${abs_builddir}/../config.status | awk -F'=' '{print $2}')
+
+if [[ "$USE_ADDRESS_SANITIZER" == "\"#\"" ]]; then
+ echo "Address Sanitizer is disabled."
+else
+ echo "Address Sanitizer is enabled. Skipping test."
+ exit 77
+fi
+
+# Extract the value of USE_MEMORY_SANITIZER_TRUE from config.status
+# Cannot use Helgrind and Memory Sanitizer together.
+# Test will be skipped if Memory Sanitizer is enabled.
+USE_MEMORY_SANITIZER=$(grep 'USE_MEMORY_SANITIZER_TRUE' ${abs_builddir}/../config.status | awk -F'=' '{print $2}')
+
+if [[ "$USE_MEMORY_SANITIZER" == "\"#\"" ]]; then
+ echo "Memory Sanitizer is disabled."
+else
+ echo "Memory Sanitizer is enabled. Skipping test."
+ exit 77
+fi
+
+# Extract the value of USE_LOCKS from config.h
+# Test will only be run if USE_LOCKS is defined. Otherwise, skip.
+USE_LOCKS=$(grep '^#define USE_LOCKS' ${abs_builddir}/../config.h | awk '{print $3}')
+
+if [[ "$USE_LOCKS" -eq 1 ]]; then
+ echo "USE_LOCKS is defined."
+else
+ echo "USE_LOCKS is not defined. Skipping test."
+ exit 77
+fi
+
+# Disable valgrind if configured, since we are already using it here.
+SAVED_VALGRIND_CMD="$VALGRIND_CMD"
+unset VALGRIND_CMD
+
+echo "Begin tests..."
+
+# Begin data race test for parallelized dwarf-die-addr-die
+# Tests thread safety for updated libdw_findcu.c and libdw_find_split_unit.c
+testfiles testfile-debug-types
+testfiles testfile_multi_main testfile_multi.dwz
+testfiles testfilebazdbgppc64.debug
+testfiles testfile-dwarf-4 testfile-dwarf-5
+testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo
+testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo
+
+die_test_files=("testfile-debug-types"
+ "testfile_multi_main" "testfile_multi.dwz"
+ "testfilebazdbgppc64.debug"
+ "testfile-dwarf-4" "testfile-dwarf-5"
+ "testfile-splitdwarf-4" "testfile-hello4.dwo" "testfile-world4.dwo"
+ "testfile-splitdwarf-5" "testfile-hello5.dwo" "testfile-world5.dwo")
+
+echo -e "\nStarting data race test for dwarf-die-addr-die"
+
+for file in "${die_test_files[@]}"; do
+ helgrind_output=$(valgrind --tool=helgrind "${abs_builddir}/eu_search_die" "$file" 2>&1)
+
+ if grep -q "ERROR SUMMARY: 0 errors" <<< "$helgrind_output"; then
+ echo "No data races found for $file. Test passed."
+ else
+ echo "Data races found for $file. Test failed."
+ echo "$helgrind_output"
+ exit 1
+ fi
+done
+
+# Begin data race test for parallelized next_cfi
+# Tests thread safety for updated cie.c and fde.c
+testfiles testfile11 testfile12
+testfiles testfilearm testfileaarch64
+testfiles testfileppc32 testfileppc64
+
+cfi_test_files=("testfile11" "testfile12"
+ "testfilearm" "testfileaarch64"
+ "testfileppc32" "testfileppc64")
+
+echo -e "\nStarting data race test for next_cfi"
+
+for file in "${cfi_test_files[@]}"; do
+
+ helgrind_output=$(valgrind --tool=helgrind "${abs_builddir}/eu_search_cfi" $file 2>&1)
+
+ if grep -q "ERROR SUMMARY: 0 errors" <<< "$helgrind_output"; then
+ echo "No data races found for $file. Test passed."
+ else
+ echo "Data races found for $file. Test failed."
+ echo "$helgrind_output"
+ exit 1
+ fi
+
+done
+
+# Begin data race test for parallelizd dwarf-getmacros
+# Tests thread safety for updated dwarf_getmacros.c
+testfiles testfile51
+testfiles testfile-macros
+testfiles testfile-macros-0xff
+
+macro_test_files=("testfile51 0xb"
+ "testfile51 0x84"
+ "testfile-macrosm 0xb"
+ "testfile-macros-0xff 0xb")
+
+echo -e "\nStarting data race test for dwarf-getmacros"
+
+for file in "${macro_test_files[@]}"; do
+
+ helgrind_output=$(valgrind --tool=helgrind "${abs_builddir}/eu_search_macros" $file 2>&1)
+
+ if grep -q "ERROR SUMMARY: 0 errors" <<< "$helgrind_output"; then
+ echo "No data races found for $file. Test passed."
+ else
+ echo "Data races found for $file. Test failed."
+ echo "$helgrind_output"
+ exit 1
+ fi
+
+done
+
+# Begin data race test for parallelized get-lines
+# Tests thread safety for updated dwarf_getsrclines.c
+testfiles testfile testfile2 testfilenolines
+
+lines_test_files=("testfile" "testfile2" "testfilenolines")
+
+echo -e "\nStarting data race test for get-lines"
+
+for file in "${lines_test_files[@]}"; do
+
+ helgrind_output=$(valgrind --tool=helgrind "${abs_builddir}/eu_search_lines" $file 2>&1)
+
+ if grep -q "ERROR SUMMARY: 0 errors" <<< "$helgrind_output"; then
+ echo "No data races found for $file. Test passed."
+ else
+ echo -e "$helgrind_output"
+ echo "Data races found for $file. Test failed."
+ exit 1
+ fi
+
+done
+
+# This line is reached only if no data races were found in any test
+# Exit with success status.
+exit 0
\ No newline at end of file
--
2.39.3
next reply other threads:[~2023-08-08 17:07 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-08-08 17:07 Heather McIntyre [this message]
2023-08-21 22:08 ` John Mellor-Crummey
2023-08-25 14:10 ` Mark Wielaard
2023-10-10 13:40 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 01/16] lib: Add new once_define and once macros to eu-config.h Mark Wielaard
2023-10-10 13:42 ` [PATCH 02/16] libelf: Make elf_version thread-safe Mark Wielaard
2023-10-10 14:00 ` Mark Wielaard
2023-10-17 19:05 ` Heather McIntyre
2023-10-19 21:00 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 03/16] libelf: Fix deadlock in __libelf_readall Mark Wielaard
2023-10-10 15:06 ` Mark Wielaard
2023-10-17 19:11 ` Heather McIntyre
2023-11-09 13:26 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 04/16] libelf: Fix deadlock in elf_cntl Mark Wielaard
2023-10-10 15:23 ` Mark Wielaard
2023-10-17 19:14 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 05/16] libelf: Fix elf_end deadlock Mark Wielaard
2023-10-10 15:28 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 06/16] libelf: Make elf32_getchdr and elf64_getchdr thread-safe Mark Wielaard
2023-10-10 16:28 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 07/16] lib: Add eu_tsearch and eu_tfind Mark Wielaard
2023-10-10 16:51 ` Mark Wielaard
2023-10-17 20:52 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 08/16] libcpu: Change calls for tsearch/tfind to eu_tsearch/eu_tfind Mark Wielaard
2023-10-10 21:10 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 09/16] src: Use eu-search in nm and findtextrel Mark Wielaard
2023-10-10 21:25 ` Mark Wielaard
2023-10-17 19:20 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 10/16] libdw: make dwarf_getalt thread-safe Mark Wielaard
2023-10-10 22:02 ` Mark Wielaard
2023-10-17 19:25 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 11/16] libdw: Add locking around __libdw_dieabbrev for dwarf_hasattr Mark Wielaard
2023-10-11 15:10 ` Mark Wielaard
2023-10-17 19:57 ` Heather McIntyre
2023-10-19 22:06 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 12/16] libdw: Make libdw_find_split_unit thread-safe Mark Wielaard
2023-10-11 17:17 ` Mark Wielaard
2023-10-17 20:01 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 13/16] libdw: Make libdw_findcu thread-safe Mark Wielaard
2023-10-12 22:02 ` Mark Wielaard
2023-10-17 20:10 ` Heather McIntyre
2023-10-10 13:42 ` [PATCH 14/16] libdw,libdwfl: Use eu-search for thread-safety Mark Wielaard
2023-10-12 22:05 ` Mark Wielaard
2023-10-10 13:42 ` [PATCH 15/16] tests: Add eu-search tests Mark Wielaard
2023-10-13 14:38 ` Mark Wielaard
2023-10-10 13:43 ` [PATCH 16/16] configure: No longer mark --enable-thread-safety as EXPERIMENTAL Mark Wielaard
2023-10-12 22:09 ` Mark Wielaard
2023-10-10 13:54 ` [PATCH 01/16] lib: Add new once_define and once macros to eu-config.h Mark Wielaard
2023-10-14 15:39 ` [PATCH] Fix thread-safety for elfutils Mark Wielaard
2023-10-14 18:29 ` Heather McIntyre
2023-10-17 15:04 ` Mark Wielaard
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAK-+vz0guN1=D5-EcuRTQAF0ZnL+aGYFg4n7pguuMkwNiOmW1Q@mail.gmail.com' \
--to=hsm2@rice.edu \
--cc=elfutils-devel@sourceware.org \
--cc=johnmc@rice.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).