From: Heather McIntyre <h...@rice.edu> Add new struct search_tree to hold tree root and lock. Add new eu_t* functions for ensuring synchronized tree access.
Replace tsearch, tfind, etc with eu_t* equivalents. Move the rwlock_* macros out of eu-config.h and into a new header file locks.h. This was done so that the rwlock_* macros can be included in libdwP.h without having to also include the rest of eu-config.h. 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> v2 changes: This patch replaces v1 03/16 and 14/16. --- lib/Makefile.am | 5 ++- lib/eu-config.h | 30 +------------ lib/eu-search.c | 85 +++++++++++++++++++++++++++++++++++ lib/eu-search.h | 64 ++++++++++++++++++++++++++ lib/locks.h | 62 +++++++++++++++++++++++++ libdw/cfi.h | 6 +-- libdw/cie.c | 10 +++-- libdw/dwarf_begin_elf.c | 7 +-- libdw/dwarf_end.c | 17 +++---- libdw/dwarf_getcfi.c | 5 ++- libdw/dwarf_getlocation.c | 24 +++++----- libdw/dwarf_getmacros.c | 6 +-- libdw/dwarf_getsrclines.c | 8 ++-- libdw/fde.c | 6 +-- libdw/frame-cache.c | 8 ++-- libdw/libdwP.h | 26 ++++++++--- libdw/libdw_find_split_unit.c | 10 ++--- libdw/libdw_findcu.c | 18 ++++---- libdwfl/cu.c | 8 ++-- libdwfl/dwfl_module.c | 4 +- libdwfl/libdwflP.h | 3 +- libelf/elf_begin.c | 2 + libelf/elf_end.c | 13 +++--- libelf/elf_getdata_rawchunk.c | 12 ++--- libelf/libelfP.h | 10 +++-- 25 files changed, 331 insertions(+), 118 deletions(-) create mode 100644 lib/eu-search.c create mode 100644 lib/eu-search.h create mode 100644 lib/locks.h diff --git a/lib/Makefile.am b/lib/Makefile.am index b3bb929f..e324c18d 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -34,10 +34,11 @@ 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 \ eu-config.h color.h printversion.h bpf.h \ - atomics.h stdatomic-fbsd.h dynamicsizehash_concurrent.h + atomics.h stdatomic-fbsd.h dynamicsizehash_concurrent.h \ + eu-search.h locks.h EXTRA_DIST = dynamicsizehash.c dynamicsizehash_concurrent.c diff --git a/lib/eu-config.h b/lib/eu-config.h index feb079db..a38d75da 100644 --- a/lib/eu-config.h +++ b/lib/eu-config.h @@ -29,35 +29,7 @@ #ifndef EU_CONFIG_H #define EU_CONFIG_H 1 -#ifdef USE_LOCKS -# include <pthread.h> -# include <assert.h> -# 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 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 once_define(class,name) -# define once(once_control, init_routine) init_routine() -#endif /* USE_LOCKS */ +#include <locks.h> #include <libintl.h> /* gettext helper macros. */ diff --git a/lib/eu-search.c b/lib/eu-search.c new file mode 100644 index 00000000..b7256eba --- /dev/null +++ b/lib/eu-search.c @@ -0,0 +1,85 @@ +/* Definitions for thread-safe tsearch/tfind + Copyright (C) 2023 Rice University + 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 <eu-search.h> + +void *eu_tsearch (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)) +{ + rwlock_wrlock (tree->lock); + void *ret = tsearch (key, &tree->root, compare); + rwlock_unlock (tree->lock); + + return ret; +} + +void *eu_tfind (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)) +{ + rwlock_rdlock (tree->lock); + void *ret = tfind (key, &tree->root, compare); + rwlock_unlock (tree->lock); + + return ret; +} + +void *eu_tdelete (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)) +{ + rwlock_wrlock (tree->lock); + void *ret = tdelete (key, &tree->root, compare); + rwlock_unlock (tree->lock); + + return ret; +} + +void eu_tdestroy (search_tree *tree, void (*free_node)(void *)) +{ + rwlock_wrlock (tree->lock); + + tdestroy (tree->root, free_node); + tree->root = NULL; + + rwlock_unlock (tree->lock); +} + +void eu_search_tree_init (search_tree *tree) +{ + tree->root = NULL; + rwlock_init (tree->lock); +} + +void eu_search_tree_fini (search_tree *tree, void (*free_node)(void *)) +{ + eu_tdestroy (tree, free_node); + rwlock_fini (tree->lock); +} diff --git a/lib/eu-search.h b/lib/eu-search.h new file mode 100644 index 00000000..67b54c18 --- /dev/null +++ b/lib/eu-search.h @@ -0,0 +1,64 @@ +/* Calls for thread-safe tsearch/tfind + Copyright (C) 2023 Rice University + 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 <stdlib.h> +#include <search.h> +#include <locks.h> + +typedef struct +{ + void *root; + rwlock_define (, lock); +} search_tree; + +/* Search TREE for KEY and add KEY if not found. Synchronized using + TREE's lock. */ +extern void *eu_tsearch (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)); + +/* Search TREE for KEY. Synchronized with TREE's lock. */ +extern void *eu_tfind (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)); + +/* Delete key from TREE. Synchronized with TREE's lock. */ +extern void *eu_tdelete (const void *key, search_tree *tree, + int (*compare)(const void *, const void *)); + +/* Free all nodes from TREE. */ +void eu_tdestroy (search_tree *tree, void (*free_node)(void *)); + +/* Initialize TREE's root and lock. */ +void eu_search_tree_init (search_tree *tree); + +/* Free all nodes from TREE as well as TREE's lock. */ +void eu_search_tree_fini (search_tree *tree, void (*free_node)(void *)); + +#endif diff --git a/lib/locks.h b/lib/locks.h new file mode 100644 index 00000000..90fe3f1b --- /dev/null +++ b/lib/locks.h @@ -0,0 +1,62 @@ +/* Configuration definitions. + Copyright (C) 2024 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 LOCKS_H +#define LOCKS_H 1 + +#ifdef USE_LOCKS +# include <pthread.h> +# include <assert.h> +# 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 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 once_define(class,name) +# define once(once_control, init_routine) init_routine() +#endif /* USE_LOCKS */ + +#endif /* locks.h */ diff --git a/libdw/cfi.h b/libdw/cfi.h index 1b0d712f..bb9dc0df 100644 --- a/libdw/cfi.h +++ b/libdw/cfi.h @@ -90,13 +90,13 @@ struct Dwarf_CFI_s Dwarf_Off next_offset; /* Search tree for the CIEs, indexed by CIE_pointer (section offset). */ - void *cie_tree; + search_tree cie_tree; /* Search tree for the FDEs, indexed by PC address. */ - void *fde_tree; + search_tree fde_tree; /* Search tree for parsed DWARF expressions, indexed by raw pointer. */ - void *expr_tree; + search_tree expr_tree; /* Backend hook. */ struct ebl *ebl; diff --git a/libdw/cie.c b/libdw/cie.c index 1b0aae7c..3d56b057 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,8 @@ 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 +190,8 @@ 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_begin_elf.c b/libdw/dwarf_begin_elf.c index ca2b7e2a..56abef6a 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -354,11 +354,11 @@ valid_p (Dwarf *result) result->fake_loc_cu->endp = (result->sectiondata[IDX_debug_loc]->d_buf + result->sectiondata[IDX_debug_loc]->d_size); - result->fake_loc_cu->locs = NULL; result->fake_loc_cu->address_size = elf_addr_size; result->fake_loc_cu->offset_size = 4; result->fake_loc_cu->version = 4; result->fake_loc_cu->split = NULL; + eu_search_tree_init (&result->fake_loc_cu->locs_tree); } } @@ -382,11 +382,11 @@ valid_p (Dwarf *result) result->fake_loclists_cu->endp = (result->sectiondata[IDX_debug_loclists]->d_buf + result->sectiondata[IDX_debug_loclists]->d_size); - result->fake_loclists_cu->locs = NULL; result->fake_loclists_cu->address_size = elf_addr_size; result->fake_loclists_cu->offset_size = 4; result->fake_loclists_cu->version = 5; result->fake_loclists_cu->split = NULL; + eu_search_tree_init (&result->fake_loclists_cu->locs_tree); } } @@ -415,11 +415,11 @@ valid_p (Dwarf *result) result->fake_addr_cu->endp = (result->sectiondata[IDX_debug_addr]->d_buf + result->sectiondata[IDX_debug_addr]->d_size); - result->fake_addr_cu->locs = NULL; result->fake_addr_cu->address_size = elf_addr_size; result->fake_addr_cu->offset_size = 4; result->fake_addr_cu->version = 5; result->fake_addr_cu->split = NULL; + eu_search_tree_init (&result->fake_addr_cu->locs_tree); } } @@ -579,6 +579,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp) __libdw_seterrno (DWARF_E_NOMEM); /* no memory. */ return NULL; } + rwlock_init(result->dwarf_lock); result->mem_stacks = 0; result->mem_tails = NULL; diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index ed8d27be..a593c881 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -61,14 +61,15 @@ static void cu_free (void *arg) { struct Dwarf_CU *p = (struct Dwarf_CU *) arg; - - tdestroy (p->locs, noop_free); + eu_search_tree_fini (&p->locs_tree, noop_free); /* Only free the CU internals if its not a fake CU. */ - if(p != p->dbg->fake_loc_cu && p != p->dbg->fake_loclists_cu + if (p != p->dbg->fake_loc_cu && p != p->dbg->fake_loclists_cu && p != p->dbg->fake_addr_cu) { Dwarf_Abbrev_Hash_free (&p->abbrev_hash); + rwlock_fini (p->abbrev_lock); + rwlock_fini (p->split_lock); /* Free split dwarf one way (from skeleton to split). */ if (p->unit_type == DW_UT_skeleton @@ -102,17 +103,17 @@ dwarf_end (Dwarf *dwarf) /* The search tree for the CUs. NB: the CU data itself is allocated separately, but the abbreviation hash tables need to be handled. */ - tdestroy (dwarf->cu_tree, cu_free); - tdestroy (dwarf->tu_tree, cu_free); + eu_search_tree_fini (&dwarf->cu_tree, cu_free); + eu_search_tree_fini (&dwarf->tu_tree, cu_free); /* Search tree for macro opcode tables. */ - tdestroy (dwarf->macro_ops, noop_free); + eu_search_tree_fini (&dwarf->macro_ops_tree, noop_free); /* Search tree for decoded .debug_lines units. */ - tdestroy (dwarf->files_lines, noop_free); + eu_search_tree_fini (&dwarf->files_lines_tree, noop_free); /* And the split Dwarf. */ - tdestroy (dwarf->split_tree, noop_free); + eu_search_tree_fini (&dwarf->split_tree, noop_free); /* Free the internally allocated memory. */ for (size_t i = 0; i < dwarf->mem_stacks; i++) diff --git a/libdw/dwarf_getcfi.c b/libdw/dwarf_getcfi.c index afa8a460..a4497152 100644 --- a/libdw/dwarf_getcfi.c +++ b/libdw/dwarf_getcfi.c @@ -66,7 +66,10 @@ dwarf_getcfi (Dwarf *dbg) cfi->default_same_value = false; cfi->next_offset = 0; - cfi->cie_tree = cfi->fde_tree = cfi->expr_tree = NULL; + + eu_search_tree_init (&cfi->cie_tree); + eu_search_tree_init (&cfi->fde_tree); + eu_search_tree_init (&cfi->expr_tree); cfi->ebl = NULL; diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 37b32fc1..409bda6f 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -31,10 +31,11 @@ #endif #include <dwarf.h> -#include <search.h> +#include <eu-search.h> #include <stdlib.h> #include <assert.h> +#include <cfi.h> #include <libdwP.h> @@ -137,9 +138,9 @@ 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) +store_implicit_value (Dwarf *dbg, search_tree *cache, Dwarf_Op *op) { if (dbg == NULL) return -1; @@ -154,7 +155,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 +168,8 @@ 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_tree, + loc_compare); if (unlikely (found == NULL)) { __libdw_seterrno (DWARF_E_NO_BLOCK); @@ -211,7 +213,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_tree, loc_compare); if (found == NULL) { @@ -235,7 +237,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_tree, loc_compare); } assert ((*found)->nloc == 1); @@ -253,7 +255,7 @@ int internal_function __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, unsigned int address_size, unsigned int ref_size, - void **cache, const Dwarf_Block *block, + search_tree *cache, const Dwarf_Block *block, bool cfap, bool valuep, Dwarf_Op **llbuf, size_t *listlen, int sec_index) { @@ -266,7 +268,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 +657,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); + eu_tsearch (newp, cache, loc_compare); /* We did it. */ return 0; @@ -677,7 +679,7 @@ getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, cu->address_size, (cu->version == 2 ? cu->address_size : cu->offset_size), - &cu->locs, block, + &cu->locs_tree, block, false, false, llbuf, listlen, sec_index); } diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c index 2667eb45..41d510a9 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> @@ -317,7 +317,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_tree, macro_op_compare); if (found != NULL) return *found; @@ -329,7 +329,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_tree, macro_op_compare); if (unlikely (ret == NULL)) { diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 987a86fd..759b9c7b 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" @@ -1320,8 +1320,8 @@ get_lines_or_files (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, - files_lines_compare); + struct files_lines_s **found = eu_tfind (&fake, &dbg->files_lines_tree, + files_lines_compare); if (found == NULL) { /* This .debug_line is being read for the first time. */ @@ -1354,7 +1354,7 @@ get_lines_or_files (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_tree, files_lines_compare); if (found == NULL) { __libdw_seterrno (DWARF_E_NOMEM); 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/frame-cache.c b/libdw/frame-cache.c index 683f7f17..6c89858a 100644 --- a/libdw/frame-cache.c +++ b/libdw/frame-cache.c @@ -60,10 +60,10 @@ void internal_function __libdw_destroy_frame_cache (Dwarf_CFI *cache) { - /* Most of the data is in our two search trees. */ - tdestroy (cache->fde_tree, free_fde); - tdestroy (cache->cie_tree, free_cie); - tdestroy (cache->expr_tree, free_expr); + /* Most of the data is in our three search trees. */ + eu_search_tree_fini (&cache->fde_tree, free_fde); + eu_search_tree_fini (&cache->cie_tree, free_cie); + eu_search_tree_fini (&cache->expr_tree, free_expr); if (cache->ebl != NULL && cache->ebl != (void *) -1l) ebl_closebackend (cache->ebl); diff --git a/libdw/libdwP.h b/libdw/libdwP.h index e55ff50a..a4f26b82 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -32,6 +32,7 @@ #include <stdbool.h> #include <pthread.h> +#include <eu-search.h> #include <libdw.h> #include <dwarf.h> @@ -215,22 +216,22 @@ struct Dwarf size_t pubnames_nsets; /* Search tree for the CUs. */ - void *cu_tree; + search_tree cu_tree; Dwarf_Off next_cu_offset; /* Search tree and sig8 hash table for .debug_types type units. */ - void *tu_tree; + search_tree tu_tree; Dwarf_Off next_tu_offset; Dwarf_Sig8_Hash sig8_hash; /* Search tree for split Dwarf associated with CUs in this debug. */ - void *split_tree; + search_tree split_tree; /* Search tree for .debug_macro operator tables. */ - void *macro_ops; + search_tree macro_ops_tree; /* Search tree for decoded .debug_line units. */ - void *files_lines; + search_tree files_lines_tree; /* Address ranges read from .debug_aranges. */ Dwarf_Aranges *aranges; @@ -263,6 +264,10 @@ struct Dwarf allocations for this Dwarf. */ pthread_rwlock_t mem_rwl; + /* The dwarf_lock is a read-write lock designed to ensure thread-safe access + and modification of Dwarf objects. */ + rwlock_define(, dwarf_lock); + /* Internal memory handling. This is basically a simplified thread-local reimplementation of obstacks. Unfortunately the standard obstack implementation is not usable in libraries. */ @@ -423,7 +428,7 @@ struct Dwarf_CU Dwarf_Files *files; /* Known location lists. */ - void *locs; + search_tree locs_tree; /* Base address for use with ranges and locs. Don't access directly, call __libdw_cu_base_address. */ @@ -446,6 +451,12 @@ struct Dwarf_CU Don't access directly, call __libdw_cu_locs_base. */ Dwarf_Off locs_base; + /* Synchronize Dwarf_Die abbrev access. */ + rwlock_define(, abbrev_lock); + + /* Synchronize split Dwarf access. */ + rwlock_define(, split_lock); + /* Memory boundaries of this CU. */ void *startp; void *endp; @@ -912,7 +923,8 @@ extern int __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, unsigned int address_size, unsigned int ref_size, - void **cache, const Dwarf_Block *block, + search_tree *cache, + const Dwarf_Block *block, bool cfap, bool valuep, Dwarf_Op **llbuf, size_t *listlen, int sec_index) diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c index 8426a925..67d31a9c 100644 --- a/libdw/libdw_find_split_unit.c +++ b/libdw/libdw_find_split_unit.c @@ -34,7 +34,7 @@ #include "libelfP.h" #include <limits.h> -#include <search.h> +#include <eu-search.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> @@ -57,8 +57,8 @@ 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, - __libdw_finddbg_cb) == NULL) + if (eu_tsearch (split->dbg, &cu->dbg->split_tree, + __libdw_finddbg_cb) == NULL) { /* Something went wrong. Don't link. */ __libdw_seterrno (DWARF_E_NOMEM); @@ -132,8 +132,8 @@ try_dwp_file (Dwarf_CU *cu) cu->unit_id8); if (split != NULL) { - if (tsearch (split->dbg, &cu->dbg->split_tree, - __libdw_finddbg_cb) == NULL) + if (eu_tsearch (split->dbg, &cu->dbg->split_tree, + __libdw_finddbg_cb) == NULL) { /* Something went wrong. Don't link. */ __libdw_seterrno (DWARF_E_NOMEM); diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c index 6c7dcfb5..72cf261c 100644 --- a/libdw/libdw_findcu.c +++ b/libdw/libdw_findcu.c @@ -32,7 +32,7 @@ #endif #include <assert.h> -#include <search.h> +#include <eu-search.h> #include "libdwP.h" static int @@ -101,7 +101,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) { Dwarf_Off *const offsetp = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; - void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree; + search_tree *tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree; Dwarf_Off oldoff = *offsetp; uint16_t version; @@ -167,7 +167,6 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset; newp->files = NULL; newp->lines = NULL; - newp->locs = NULL; newp->split = (Dwarf_CU *) -1; newp->base_address = (Dwarf_Addr) -1; newp->addr_base = (Dwarf_Off) -1; @@ -177,6 +176,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types) newp->startp = data->d_buf + newp->start; newp->endp = data->d_buf + newp->end; + eu_search_tree_init (&newp->locs_tree); /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */ if (debug_types) @@ -221,7 +221,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; @@ -236,13 +236,13 @@ struct Dwarf_CU * internal_function __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types) { - void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree; + search_tree *tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree; Dwarf_Off *next_offset = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset; /* Maybe we already know that CU. */ 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; @@ -270,7 +270,7 @@ struct Dwarf_CU * internal_function __libdw_findcu_addr (Dwarf *dbg, void *addr) { - void **tree; + search_tree *tree; Dwarf_Off start; if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf && addr < (dbg->sectiondata[IDX_debug_info]->d_buf @@ -291,7 +291,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; @@ -306,7 +306,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/cu.c b/libdwfl/cu.c index 06684357..d10c562a 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 * @@ -151,8 +151,7 @@ less_lazy (Dwfl_Module *mod) return; /* We know about all the CUs now, we don't need this table. */ - tdestroy (mod->lazy_cu_root, nofree); - mod->lazy_cu_root = NULL; + eu_tdestroy (&mod->lazy_cu_tree, nofree); } static inline Dwarf_Off @@ -198,7 +197,8 @@ 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_tree, + &compare_cukey); if (unlikely (found == NULL)) return DWFL_E_NOMEM; diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c index c4d872d4..b4ddf806 100644 --- a/libdwfl/dwfl_module.c +++ b/libdwfl/dwfl_module.c @@ -61,8 +61,7 @@ void internal_function __libdwfl_module_free (Dwfl_Module *mod) { - if (mod->lazy_cu_root != NULL) - tdestroy (mod->lazy_cu_root, nofree); + eu_search_tree_fini (&mod->lazy_cu_tree, nofree); if (mod->aranges != NULL) free (mod->aranges); @@ -200,6 +199,7 @@ dwfl_report_module (Dwfl *dwfl, const char *name, mod->low_addr = start; mod->high_addr = end; mod->dwfl = dwfl; + eu_search_tree_init (&mod->lazy_cu_tree); return use (mod, tailp, dwfl); } diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index d27bfdc2..395ab9c8 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -37,6 +37,7 @@ #include <stdbool.h> #include <stdlib.h> #include <string.h> +#include <eu-search.h> #include "libdwP.h" /* We need its INTDECLs. */ #include "libdwelfP.h" @@ -201,7 +202,7 @@ struct Dwfl_Module /* Known CU's in this module. */ struct dwfl_cu *first_cu, **cu; - void *lazy_cu_root; /* Table indexed by Dwarf_Off of CU. */ + search_tree lazy_cu_tree; /* Table indexed by Dwarf_Off of CU. */ struct dwfl_arange *aranges; /* Mapping of addresses in module to CUs. */ diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c index 8a49f351..2b3b465f 100644 --- a/libelf/elf_begin.c +++ b/libelf/elf_begin.c @@ -439,6 +439,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, /* So far only one block with sections. */ elf->state.elf32.scns_last = &elf->state.elf32.scns; + eu_search_tree_init (&elf->state.elf32.rawchunk_tree); } else { @@ -536,6 +537,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident, /* So far only one block with sections. */ elf->state.elf64.scns_last = &elf->state.elf64.scns; + eu_search_tree_init (&elf->state.elf64.rawchunk_tree); } return elf; diff --git a/libelf/elf_end.c b/libelf/elf_end.c index 80f4d13f..da8f3a20 100644 --- a/libelf/elf_end.c +++ b/libelf/elf_end.c @@ -126,13 +126,14 @@ elf_end (Elf *elf) case ELF_K_ELF: { - void *rawchunks + search_tree *rawchunk_tree = (elf->class == ELFCLASS32 - || (offsetof (struct Elf, state.elf32.rawchunks) - == offsetof (struct Elf, state.elf64.rawchunks)) - ? elf->state.elf32.rawchunks - : elf->state.elf64.rawchunks); - tdestroy (rawchunks, free_chunk); + || (offsetof (struct Elf, state.elf32.rawchunk_tree) + == offsetof (struct Elf, state.elf64.rawchunk_tree)) + ? &elf->state.elf32.rawchunk_tree + : &elf->state.elf64.rawchunk_tree); + + eu_search_tree_fini (rawchunk_tree, free_chunk); Elf_ScnList *list = (elf->class == ELFCLASS32 || (offsetof (struct Elf, state.elf32.scns) diff --git a/libelf/elf_getdata_rawchunk.c b/libelf/elf_getdata_rawchunk.c index 1751878d..3269dc6c 100644 --- a/libelf/elf_getdata_rawchunk.c +++ b/libelf/elf_getdata_rawchunk.c @@ -33,8 +33,7 @@ #include <assert.h> #include <errno.h> -#include <search.h> -#include <stdlib.h> +#include <eu-search.h> #include <string.h> #include "libelfP.h" @@ -95,8 +94,9 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) key.offset = offset; key.data.d.d_size = size; key.data.d.d_type = type; - Elf_Data_Chunk **found = tsearch (&key, &elf->state.elf.rawchunks, - &chunk_compare); + Elf_Data_Chunk **found + = eu_tsearch (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); + if (found == NULL) goto nomem; @@ -136,7 +136,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) if (rawchunk == NULL) { nomem: - tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare); + eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); __libelf_seterrno (ELF_E_NOMEM); goto out; } @@ -147,7 +147,7 @@ elf_getdata_rawchunk (Elf *elf, int64_t offset, size_t size, Elf_Type type) != size)) { /* Something went wrong. */ - tdelete (&key, &elf->state.elf.rawchunks, &chunk_compare); + eu_tdelete (&key, &elf->state.elf.rawchunk_tree, &chunk_compare); free (rawchunk); __libelf_seterrno (ELF_E_READ_ERROR); goto out; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index bdd2cc6a..3e4ab2f3 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -33,6 +33,7 @@ #include <ar.h> #include <gelf.h> +#include <eu-search.h> #include <errno.h> #include <stdbool.h> @@ -323,7 +324,8 @@ struct Elf Elf_ScnList *scns_last; /* Last element in the section list. If NULL the data has not yet been read from the file. */ - void *rawchunks; /* Tree of elf_getdata_rawchunk results. */ + search_tree rawchunk_tree; /* Tree and lock for elf_getdata_rawchunk + results. */ unsigned int scnincr; /* Number of sections allocate the last time. */ int ehdr_flags; /* Flags (dirty) for ELF header. */ @@ -342,7 +344,8 @@ struct Elf Elf_ScnList *scns_last; /* Last element in the section list. If NULL the data has not yet been read from the file. */ - void *rawchunks; /* Tree of elf_getdata_rawchunk results. */ + search_tree rawchunk_tree; /* Tree and lock for + elf_getdata_rawchunk results. */ unsigned int scnincr; /* Number of sections allocate the last time. */ int ehdr_flags; /* Flags (dirty) for ELF header. */ @@ -367,7 +370,8 @@ struct Elf Elf_ScnList *scns_last; /* Last element in the section list. If NULL the data has not yet been read from the file. */ - void *rawchunks; /* Tree of elf_getdata_rawchunk results. */ + search_tree rawchunk_tree; /* Tree and lock for + elf_getdata_rawchunk results. */ unsigned int scnincr; /* Number of sections allocate the last time. */ int ehdr_flags; /* Flags (dirty) for ELF header. */ -- 2.45.2