diff options
| author | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2019-12-11 00:19:33 +0000 |
|---|---|---|
| committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2019-12-11 00:19:33 +0000 |
| commit | 5f92182e496a66149ba09c92fe497135643663f5 (patch) | |
| tree | e321e3c2a0fb6041f52ae87327be6e3bc2472f52 /libdw | |
| parent | 8269b3eca35d0af18be5dbd4d61ae342c52b9754 (diff) | |
| parent | 32a815b23c7d76d1e34980bb1a2a6a6887a47a81 (diff) | |
| download | platform_external_elfutils-android11-mainline-release.tar.gz platform_external_elfutils-android11-mainline-release.tar.bz2 platform_external_elfutils-android11-mainline-release.zip | |
Merge "Upgrade elfutils to elfutils-0.178" am: 2fdc74b3a8 am: 480a142ccd am: 32a815b23candroid-mainline-11.0.0_r1android11-mainline-releaseandroid11-dev
Change-Id: I0f10f5d002f504a07da6d20b6c87e1363095c193
Diffstat (limited to 'libdw')
| -rw-r--r-- | libdw/ChangeLog | 34 | ||||
| -rw-r--r-- | libdw/Makefile.am | 2 | ||||
| -rw-r--r-- | libdw/dwarf_abbrev_hash.c | 2 | ||||
| -rw-r--r-- | libdw/dwarf_abbrev_hash.h | 3 | ||||
| -rw-r--r-- | libdw/dwarf_begin_elf.c | 7 | ||||
| -rw-r--r-- | libdw/dwarf_end.c | 24 | ||||
| -rw-r--r-- | libdw/dwarf_formref_die.c | 2 | ||||
| -rw-r--r-- | libdw/dwarf_getabbrev.c | 12 | ||||
| -rw-r--r-- | libdw/dwarf_sig8_hash.c | 2 | ||||
| -rw-r--r-- | libdw/dwarf_sig8_hash.h | 9 | ||||
| -rw-r--r-- | libdw/dwarf_tag.c | 2 | ||||
| -rw-r--r-- | libdw/libdwP.h | 80 | ||||
| -rw-r--r-- | libdw/libdw_alloc.c | 80 |
13 files changed, 195 insertions, 64 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index b1f73bc8..59f33f9e 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,37 @@ +2019-10-28 Aaron Merey <amerey@redhat.com> + + * Makefile.am (libdw_so_LDLIBS): Add -ldl for libdebuginfod.so dlopen. + +2019-11-10 Mark Wielaard <mark@klomp.org> + + * libdwP.h (libdw_unalloc): New define. + (libdw_typed_unalloc): Likewise. + (__libdw_thread_tail): New function declaration. + * libdw_alloc.c (__libdw_thread_tail): New function. + * dwarf_getabbrev.c (__libdw_getabbrev): Call libdw_typed_unalloc + when reading invalid data or when hash collission detected. + +2019-10-28 Jonathon Anderson <jma14@rice.edu> + + * libdw_alloc.c: Added __libdw_alloc_tail. + (__libdw_allocate): Switch to use the mem_tails array. + * libdwP.h (Dwarf): Likewise. + * dwarf_begin_elf.c (dwarf_begin_elf): Support for above. + * dwarf_end.c (dwarf_end): Likewise. + * atomics.h: Add support for thread_local. + +2019-10-28 Mark Wielaard <mark@klomp.org> + + * dwarf_sig8_hash.h: Include libdw.h. Remove COMPARE. Include + dynamicsizehash_concurrent.h. + * dwarf_sig8_hash.c: Include dynamicsizehash_concurrent.c. + * dwarf_formref_die.c (dwarf_formref_die): Drop NULL argument to + Dwarf_Sig8_Hash_find. + +2019-08-26 Srđan Milaković <sm108@rice.edu@rice.edu> + + * dwarf_abbrev_hash.{c,h}: Use the *_concurrent hash table. + 2019-11-01 Jonathon Anderson <jma14@rice.edu> * dwarf_begin_elf.c (valid_p): Switch calloc for malloc for fake CUs. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index ce793e90..33b5838d 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -109,7 +109,7 @@ libdw_so_LIBS = ../libebl/libebl_pic.a ../backends/libebl_backends_pic.a \ ../libcpu/libcpu_pic.a libdw_pic.a ../libdwelf/libdwelf_pic.a \ ../libdwfl/libdwfl_pic.a libdw_so_DEPS = ../lib/libeu.a ../libelf/libelf.so -libdw_so_LDLIBS = $(libdw_so_DEPS) -lz $(argp_LDADD) $(zip_LIBS) -pthread +libdw_so_LDLIBS = $(libdw_so_DEPS) -ldl -lz $(argp_LDADD) $(zip_LIBS) -pthread libdw_so_SOURCES = libdw.so$(EXEEXT): $(srcdir)/libdw.map $(libdw_so_LIBS) $(libdw_so_DEPS) $(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \ diff --git a/libdw/dwarf_abbrev_hash.c b/libdw/dwarf_abbrev_hash.c index f52f5ad5..c2548140 100644 --- a/libdw/dwarf_abbrev_hash.c +++ b/libdw/dwarf_abbrev_hash.c @@ -38,7 +38,7 @@ #define next_prime __libdwarf_next_prime extern size_t next_prime (size_t) attribute_hidden; -#include <dynamicsizehash.c> +#include <dynamicsizehash_concurrent.c> #undef next_prime #define next_prime attribute_hidden __libdwarf_next_prime diff --git a/libdw/dwarf_abbrev_hash.h b/libdw/dwarf_abbrev_hash.h index d2f02ccc..a368c598 100644 --- a/libdw/dwarf_abbrev_hash.h +++ b/libdw/dwarf_abbrev_hash.h @@ -32,8 +32,7 @@ #define NAME Dwarf_Abbrev_Hash #define TYPE Dwarf_Abbrev * -#define COMPARE(a, b) (0) -#include <dynamicsizehash.h> +#include <dynamicsizehash_concurrent.h> #endif /* dwarf_abbrev_hash.h */ diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 8c116847..85343088 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -430,13 +430,14 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp) actual allocation. */ result->mem_default_size = mem_default_size; result->oom_handler = __libdw_oom; - if (pthread_key_create (&result->mem_key, NULL) != 0) + if (pthread_rwlock_init(&result->mem_rwl, NULL) != 0) { free (result); - __libdw_seterrno (DWARF_E_NOMEM); /* no memory or max pthread keys. */ + __libdw_seterrno (DWARF_E_NOMEM); /* no memory. */ return NULL; } - atomic_init (&result->mem_tail, (uintptr_t)NULL); + result->mem_stacks = 0; + result->mem_tails = NULL; if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) { diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c index 7e194a55..77f537a7 100644 --- a/libdw/dwarf_end.c +++ b/libdw/dwarf_end.c @@ -100,17 +100,19 @@ dwarf_end (Dwarf *dwarf) tdestroy (dwarf->split_tree, noop_free); /* Free the internally allocated memory. */ - struct libdw_memblock *memp; - memp = (struct libdw_memblock *) (atomic_load_explicit - (&dwarf->mem_tail, - memory_order_relaxed)); - while (memp != NULL) - { - struct libdw_memblock *prevp = memp->prev; - free (memp); - memp = prevp; - } - pthread_key_delete (dwarf->mem_key); + for (size_t i = 0; i < dwarf->mem_stacks; i++) + { + struct libdw_memblock *memp = dwarf->mem_tails[i]; + while (memp != NULL) + { + struct libdw_memblock *prevp = memp->prev; + free (memp); + memp = prevp; + } + } + if (dwarf->mem_tails != NULL) + free (dwarf->mem_tails); + pthread_rwlock_destroy (&dwarf->mem_rwl); /* Free the pubnames helper structure. */ free (dwarf->pubnames_sets); diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c index f196331a..48ba8194 100644 --- a/libdw/dwarf_formref_die.c +++ b/libdw/dwarf_formref_die.c @@ -83,7 +83,7 @@ dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *result) have to match in the type unit headers. */ uint64_t sig = read_8ubyte_unaligned (cu->dbg, attr->valp); - cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig, NULL); + cu = Dwarf_Sig8_Hash_find (&cu->dbg->sig8_hash, sig); if (cu == NULL) { /* Not seen before. We have to scan through the type units. diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c index 6a7e981b..13bee493 100644 --- a/libdw/dwarf_getabbrev.c +++ b/libdw/dwarf_getabbrev.c @@ -83,7 +83,7 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset, bool foundit = false; Dwarf_Abbrev *abb = NULL; if (cu == NULL - || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL) + || (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code)) == NULL) { if (result == NULL) abb = libdw_typed_alloc (dbg, Dwarf_Abbrev); @@ -99,6 +99,8 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset, /* A duplicate abbrev code at a different offset, that should never happen. */ invalid: + if (! foundit) + libdw_typed_unalloc (dbg, Dwarf_Abbrev); __libdw_seterrno (DWARF_E_INVALID_DWARF); return NULL; } @@ -148,7 +150,13 @@ __libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu, Dwarf_Off offset, /* Add the entry to the hash table. */ if (cu != NULL && ! foundit) - (void) Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb); + if (Dwarf_Abbrev_Hash_insert (&cu->abbrev_hash, abb->code, abb) == -1) + { + /* The entry was already in the table, remove the one we just + created and get the one already inserted. */ + libdw_typed_unalloc (dbg, Dwarf_Abbrev); + abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code); + } out: return abb; diff --git a/libdw/dwarf_sig8_hash.c b/libdw/dwarf_sig8_hash.c index 043cac78..777f9ebc 100644 --- a/libdw/dwarf_sig8_hash.c +++ b/libdw/dwarf_sig8_hash.c @@ -38,4 +38,4 @@ #define next_prime __libdwarf_next_prime extern size_t next_prime (size_t) attribute_hidden; -#include <dynamicsizehash.c> +#include <dynamicsizehash_concurrent.c> diff --git a/libdw/dwarf_sig8_hash.h b/libdw/dwarf_sig8_hash.h index 705ffbcd..c399919a 100644 --- a/libdw/dwarf_sig8_hash.h +++ b/libdw/dwarf_sig8_hash.h @@ -29,10 +29,15 @@ #ifndef _DWARF_SIG8_HASH_H #define _DWARF_SIG8_HASH_H 1 +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "libdw.h" + #define NAME Dwarf_Sig8_Hash #define TYPE struct Dwarf_CU * -#define COMPARE(a, b) (0) -#include <dynamicsizehash.h> +#include <dynamicsizehash_concurrent.h> #endif /* dwarf_sig8_hash.h */ diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c index 331eaa0d..d784970c 100644 --- a/libdw/dwarf_tag.c +++ b/libdw/dwarf_tag.c @@ -45,7 +45,7 @@ __libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code) return DWARF_END_ABBREV; /* See whether the entry is already in the hash table. */ - abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL); + abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code); if (abb == NULL) while (cu->last_abbrev_offset != (size_t) -1l) { diff --git a/libdw/libdwP.h b/libdw/libdwP.h index ad2599eb..36c2acd9 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -149,17 +149,6 @@ enum #include "dwarf_sig8_hash.h" -/* Structure for internal memory handling. This is basically a simplified - reimplementation of obstacks. Unfortunately the standard obstack - implementation is not usable in libraries. */ -struct libdw_memblock -{ - size_t size; - size_t remaining; - struct libdw_memblock *prev; - char mem[0]; -}; - /* This is the structure representing the debugging state. */ struct Dwarf { @@ -231,11 +220,22 @@ struct Dwarf /* Similar for addrx/constx, which will come from .debug_addr section. */ struct Dwarf_CU *fake_addr_cu; - /* Internal memory handling. Each thread allocates separately and only - allocates from its own blocks, while all the blocks are pushed atomically - onto a unified stack for easy deallocation. */ - pthread_key_t mem_key; - atomic_uintptr_t mem_tail; + /* Supporting lock for internal memory handling. Ensures threads that have + an entry in the mem_tails array are not disturbed by new threads doing + allocations for this Dwarf. */ + pthread_rwlock_t mem_rwl; + + /* Internal memory handling. This is basically a simplified thread-local + reimplementation of obstacks. Unfortunately the standard obstack + implementation is not usable in libraries. */ + size_t mem_stacks; + struct libdw_memblock + { + size_t size; + size_t remaining; + struct libdw_memblock *prev; + char mem[0]; + } **mem_tails; /* Default size of allocated memory blocks. */ size_t mem_default_size; @@ -578,34 +578,44 @@ libdw_valid_user_form (int form) extern void __libdw_seterrno (int value) internal_function; -/* Memory handling, the easy parts. This macro does not do nor need to do any - locking for proper concurrent operation. */ +/* Memory handling, the easy parts. */ #define libdw_alloc(dbg, type, tsize, cnt) \ - ({ struct libdw_memblock *_tail = pthread_getspecific (dbg->mem_key); \ - size_t _req = (tsize) * (cnt); \ - type *_result; \ - if (unlikely (_tail == NULL)) \ - _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \ + ({ struct libdw_memblock *_tail = __libdw_alloc_tail(dbg); \ + size_t _required = (tsize) * (cnt); \ + type *_result = (type *) (_tail->mem + (_tail->size - _tail->remaining));\ + size_t _padding = ((__alignof (type) \ + - ((uintptr_t) _result & (__alignof (type) - 1))) \ + & (__alignof (type) - 1)); \ + if (unlikely (_tail->remaining < _required + _padding)) \ + _result = (type *) __libdw_allocate (dbg, _required, __alignof (type));\ else \ { \ - _result = (type *) (_tail->mem + (_tail->size - _tail->remaining)); \ - size_t _padding = ((__alignof (type) \ - - ((uintptr_t) _result & (__alignof (type) - 1))) \ - & (__alignof (type) - 1)); \ - if (unlikely (_tail->remaining < _req + _padding)) \ - _result = (type *) __libdw_allocate (dbg, _req, __alignof (type)); \ - else \ - { \ - _req += _padding; \ - _result = (type *) ((char *) _result + _padding); \ - _tail->remaining -= _req; \ - } \ + _required += _padding; \ + _result = (type *) ((char *) _result + _padding); \ + _tail->remaining -= _required; \ } \ _result; }) #define libdw_typed_alloc(dbg, type) \ libdw_alloc (dbg, type, sizeof (type), 1) +/* Can only be used to undo the last libdw_alloc. */ +#define libdw_unalloc(dbg, type, tsize, cnt) \ + ({ struct libdw_memblock *_tail = __libdw_thread_tail (dbg); \ + size_t _required = (tsize) * (cnt); \ + /* We cannot know the padding, it is lost. */ \ + _tail->remaining += _required; }) \ + +#define libdw_typed_unalloc(dbg, type) \ + libdw_unalloc (dbg, type, sizeof (type), 1) + +/* Callback to choose a thread-local memory allocation stack. */ +extern struct libdw_memblock *__libdw_alloc_tail (Dwarf* dbg) + __nonnull_attribute__ (1); + +extern struct libdw_memblock *__libdw_thread_tail (Dwarf* dbg) + __nonnull_attribute__ (1); + /* Callback to allocate more. */ extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) __attribute__ ((__malloc__)) __nonnull_attribute__ (1); diff --git a/libdw/libdw_alloc.c b/libdw/libdw_alloc.c index f2e74d18..e0281a3d 100644 --- a/libdw/libdw_alloc.c +++ b/libdw/libdw_alloc.c @@ -35,7 +35,79 @@ #include <stdlib.h> #include "libdwP.h" #include "system.h" +#include "atomics.h" +#if USE_VG_ANNOTATIONS == 1 +#include <helgrind.h> +#else +#define ANNOTATE_HAPPENS_BEFORE(X) +#define ANNOTATE_HAPPENS_AFTER(X) +#endif + +#define THREAD_ID_UNSET ((size_t) -1) +static __thread size_t thread_id = THREAD_ID_UNSET; +static atomic_size_t next_id = ATOMIC_VAR_INIT(0); + +struct libdw_memblock * +__libdw_alloc_tail (Dwarf *dbg) +{ + if (thread_id == THREAD_ID_UNSET) + thread_id = atomic_fetch_add (&next_id, 1); + + pthread_rwlock_rdlock (&dbg->mem_rwl); + if (thread_id >= dbg->mem_stacks) + { + pthread_rwlock_unlock (&dbg->mem_rwl); + pthread_rwlock_wrlock (&dbg->mem_rwl); + + /* Another thread may have already reallocated. In theory using an + atomic would be faster, but given that this only happens once per + thread per Dwarf, some minor slowdown should be fine. */ + if (thread_id >= dbg->mem_stacks) + { + dbg->mem_tails = realloc (dbg->mem_tails, (thread_id+1) + * sizeof (struct libdw_memblock *)); + if (dbg->mem_tails == NULL) + { + pthread_rwlock_unlock (&dbg->mem_rwl); + dbg->oom_handler(); + } + for (size_t i = dbg->mem_stacks; i <= thread_id; i++) + dbg->mem_tails[i] = NULL; + dbg->mem_stacks = thread_id + 1; + ANNOTATE_HAPPENS_BEFORE (&dbg->mem_tails); + } + + pthread_rwlock_unlock (&dbg->mem_rwl); + pthread_rwlock_rdlock (&dbg->mem_rwl); + } + + /* At this point, we have an entry in the tail array. */ + ANNOTATE_HAPPENS_AFTER (&dbg->mem_tails); + struct libdw_memblock *result = dbg->mem_tails[thread_id]; + if (result == NULL) + { + result = malloc (dbg->mem_default_size); + result->size = dbg->mem_default_size + - offsetof (struct libdw_memblock, mem); + result->remaining = result->size; + result->prev = NULL; + dbg->mem_tails[thread_id] = result; + } + pthread_rwlock_unlock (&dbg->mem_rwl); + return result; +} +/* Can only be called after a allocation for this thread has already + been done, to possibly undo it. */ +struct libdw_memblock * +__libdw_thread_tail (Dwarf *dbg) +{ + struct libdw_memblock *result; + pthread_rwlock_rdlock (&dbg->mem_rwl); + result = dbg->mem_tails[thread_id]; + pthread_rwlock_unlock (&dbg->mem_rwl); + return result; +} void * __libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) @@ -52,10 +124,10 @@ __libdw_allocate (Dwarf *dbg, size_t minsize, size_t align) newp->size = size - offsetof (struct libdw_memblock, mem); newp->remaining = (uintptr_t) newp + size - (result + minsize); - newp->prev = (struct libdw_memblock*)atomic_exchange_explicit( - &dbg->mem_tail, (uintptr_t)newp, memory_order_relaxed); - if (pthread_setspecific (dbg->mem_key, newp) != 0) - dbg->oom_handler (); + pthread_rwlock_rdlock (&dbg->mem_rwl); + newp->prev = dbg->mem_tails[thread_id]; + dbg->mem_tails[thread_id] = newp; + pthread_rwlock_unlock (&dbg->mem_rwl); return (void *) result; } |
