summaryrefslogtreecommitdiffstats
path: root/libdw
diff options
context:
space:
mode:
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog60
-rw-r--r--libdw/Makefile.am51
-rw-r--r--libdw/dwarf_abbrev_hash.c2
-rw-r--r--libdw/dwarf_abbrev_hash.h3
-rw-r--r--libdw/dwarf_begin_elf.c36
-rw-r--r--libdw/dwarf_end.c45
-rw-r--r--libdw/dwarf_formref_die.c2
-rw-r--r--libdw/dwarf_getabbrev.c12
-rw-r--r--libdw/dwarf_getcfi.c1
-rw-r--r--libdw/dwarf_sig8_hash.c2
-rw-r--r--libdw/dwarf_sig8_hash.h9
-rw-r--r--libdw/dwarf_tag.c2
-rw-r--r--libdw/libdwP.h33
-rw-r--r--libdw/libdw_alloc.c78
14 files changed, 260 insertions, 76 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index bf1f4857..59f33f9e 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,63 @@
+2019-10-28 Aaron Merey <[email protected]>
+
+ * Makefile.am (libdw_so_LDLIBS): Add -ldl for libdebuginfod.so dlopen.
+
+2019-11-10 Mark Wielaard <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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ć <[email protected]@rice.edu>
+
+ * dwarf_abbrev_hash.{c,h}: Use the *_concurrent hash table.
+
+2019-11-01 Jonathon Anderson <[email protected]>
+
+ * dwarf_begin_elf.c (valid_p): Switch calloc for malloc for fake CUs.
+ Add explicit initialization of some fields.
+ * dwarf_end.c (cu_free): Add clause to limit freeing of CU internals.
+
+2019-08-26 Jonathon Anderson <[email protected]>
+
+ * libdw_alloc.c (__libdw_allocate): Added thread-safe stack allocator.
+ * libdwP.h (Dwarf): Likewise.
+ * dwarf_begin_elf.c (dwarf_begin_elf): Support for above.
+ * dwarf_end.c (dwarf_end): Likewise.
+ * Makefile.am: Use -pthread to provide rwlocks.
+
+2019-07-05 Omar Sandoval <[email protected]>
+
+ * Makefile.am (libdw_so_LIBS): Replace libebl.a with libebl_pic.a.
+ Move libebl_pic.a to the beginning so that libdw symbols are resolved.
+ (libdw_so_LDLIBS): Remove -ldl.
+ (libdw.so): Remove -rpath.
+ (libdw_a_LIBADD): Add libebl, libebl_backends, and libcpu objects.
+
+2019-08-25 Jonathon Anderson <[email protected]>
+
+ * dwarf_getcfi.c (dwarf_getcfi): Set default_same_value to false.
+
2019-08-12 Mark Wielaard <[email protected]>
* libdw.map (ELFUTILS_0.177): Add new version of dwelf_elf_begin.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 166e37cf..ef566399 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -31,17 +31,17 @@ include $(top_srcdir)/config/eu.am
if BUILD_STATIC
AM_CFLAGS += $(fpic_CFLAGS)
endif
-AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf
+AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libdwelf -pthread
VERSION = 1
lib_LIBRARIES = libdw.a
-noinst_LIBRARIES = libdw_pic.a libdw_static_pic.a
-noinst_PROGRAMS = libdw.so
+noinst_LIBRARIES = libdw_pic.a
+noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
include_HEADERS = dwarf.h
pkginclude_HEADERS = libdw.h known-dwarf.h
-libdw_a_CFLAGS = -fPIC -fvisibility=hidden $(AM_CFLAGS)
+libdw_a_CFLAGS = -fPIC $(AM_CFLAGS)
libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
dwarf_error.c dwarf_nextcu.c dwarf_diename.c dwarf_offdie.c \
@@ -95,25 +95,6 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
libdw_find_split_unit.c dwarf_cu_info.c \
dwarf_next_lines.c
-# Minimal library with symbols needed by those libebl backends that we
-# ship statically. This is so that e.g. strip doesn't end up bringing
-# in the whole of libdw, and depending on libbz2, liblzma, etc.
-libdw_static_pic_a_SOURCES = libdw_form.c dwarf_child.c dwarf_attr.c \
- dwarf_attr_integrate.c dwarf_formref_die.c dwarf_error.c \
- dwarf_tag.c dwarf_formref.c \
- dwarf_abbrev_hash.c dwarf_sig8_hash.c \
- dwarf_formudata.c libdw_findcu.c dwarf_offdie.c \
- dwarf_getabbrev.c dwarf_nextcu.c libdw_alloc.c \
- dwarf_hasattr_integrate.c dwarf_hasattr.c \
- dwarf_aggregate_size.c dwarf_siblingof.c dwarf_formsdata.c \
- dwarf_srclang.c dwarf_formflag.c dwarf_diecu.c \
- dwarf_bytesize.c dwarf_bitsize.c dwarf_peel_type.c \
- dwarf_default_lower_bound.c libdw_find_split_unit.c \
- dwarf_getalt.c dwarf_haschildren.c \
- dwarf_begin.c dwarf_begin_elf.c dwarf_end.c frame-cache.c \
- dwarf_get_units.c dwarf_formstring.c \
- ../libdwelf/dwelf_dwarf_gnu_debugaltlink.c
-
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
MAINTAINERCLEANFILES = $(srcdir)/known-dwarf.h
@@ -124,21 +105,16 @@ endif
libdw_pic_a_SOURCES =
am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os)
-am_libdw_static_pic_a_OBJECTS = $(libdw_static_pic_a_SOURCES:.c=.os)
-libdw_so_LIBS = libdw_pic.a ../libdwelf/libdwelf_pic.a \
- ../libdwfl/libdwfl_pic.a ../libebl/libebl.a \
- ../backends/libebl_static_pic.a \
- ../libcpu/libcpu_static_pic.a
+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) -ldl -lz $(argp_LDADD) $(zip_LIBS)
+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)
-# The rpath is necessary for libebl because its $ORIGIN use will
-# not fly in a setuid executable that links in libdw.
$(AM_V_CCLD)$(LINK) $(dso_LDFLAGS) -o $@ \
- -Wl,--soname,$@.$(VERSION) \
- -Wl,--enable-new-dtags,-rpath,$(pkglibdir) \
+ -Wl,--soname,$@.$(VERSION),--enable-new-dtags \
-Wl,--version-script,$<,--no-undefined \
-Wl,--whole-archive $(libdw_so_LIBS) -Wl,--no-whole-archive \
$(libdw_so_LDLIBS)
@@ -163,6 +139,15 @@ libdw_a_LIBADD = $(addprefix ../libdwfl/,$(libdwfl_objects))
libdwelf_objects = $(shell $(AR) t ../libdwelf/libdwelf.a)
libdw_a_LIBADD += $(addprefix ../libdwelf/,$(libdwelf_objects))
+libebl_objects = $(shell $(AR) t ../libebl/libebl.a)
+libdw_a_LIBADD += $(addprefix ../libebl/,$(libebl_objects))
+
+backends_objects = $(shell $(AR) t ../backends/libebl_backends.a)
+libdw_a_LIBADD += $(addprefix ../backends/,$(backends_objects))
+
+libcpu_objects = $(shell $(AR) t ../libcpu/libcpu.a)
+libdw_a_LIBADD += $(addprefix ../libcpu/,$(libcpu_objects))
+
noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
dwarf_sig8_hash.h cfi.h encoded-value.h
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 38c8f5c6..85343088 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -223,7 +223,7 @@ valid_p (Dwarf *result)
inside the .debug_loc or .debug_loclists section. */
if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
{
- result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_loc_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_loc_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -240,12 +240,16 @@ 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 = 0;
+ result->fake_loc_cu->version = 0;
+ result->fake_loc_cu->split = NULL;
}
}
if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
{
- result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_loclists_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_loclists_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -263,6 +267,10 @@ 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 = 0;
+ result->fake_loclists_cu->version = 0;
+ result->fake_loclists_cu->split = NULL;
}
}
@@ -272,7 +280,7 @@ valid_p (Dwarf *result)
inside the .debug_addr section, if it exists. */
if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL)
{
- result->fake_addr_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ result->fake_addr_cu = (Dwarf_CU *) malloc (sizeof (Dwarf_CU));
if (unlikely (result->fake_addr_cu == NULL))
{
Dwarf_Sig8_Hash_free (&result->sig8_hash);
@@ -291,6 +299,10 @@ 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 = 0;
+ result->fake_addr_cu->version = 0;
+ result->fake_addr_cu->split = NULL;
}
}
@@ -397,7 +409,7 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
assert (sizeof (struct Dwarf) < mem_default_size);
/* Allocate the data structure. */
- Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf) + mem_default_size);
+ Dwarf *result = (Dwarf *) calloc (1, sizeof (Dwarf));
if (unlikely (result == NULL)
|| unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0))
{
@@ -414,14 +426,18 @@ dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp)
result->elf = elf;
result->alt_fd = -1;
- /* Initialize the memory handling. */
+ /* Initialize the memory handling. Initial blocks are allocated on first
+ actual allocation. */
result->mem_default_size = mem_default_size;
result->oom_handler = __libdw_oom;
- result->mem_tail = (struct libdw_memblock *) (result + 1);
- result->mem_tail->size = (result->mem_default_size
- - offsetof (struct libdw_memblock, mem));
- result->mem_tail->remaining = result->mem_tail->size;
- result->mem_tail->prev = NULL;
+ if (pthread_rwlock_init(&result->mem_rwl, NULL) != 0)
+ {
+ free (result);
+ __libdw_seterrno (DWARF_E_NOMEM); /* no memory. */
+ return 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 29795c10..77f537a7 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -52,18 +52,23 @@ cu_free (void *arg)
{
struct Dwarf_CU *p = (struct Dwarf_CU *) arg;
- Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
-
tdestroy (p->locs, noop_free);
- /* Free split dwarf one way (from skeleton to split). */
- if (p->unit_type == DW_UT_skeleton
- && p->split != NULL && p->split != (void *)-1)
+ /* Only free the CU internals if its not a fake CU. */
+ if(p != p->dbg->fake_loc_cu && p != p->dbg->fake_loclists_cu
+ && p != p->dbg->fake_addr_cu)
{
- /* The fake_addr_cu might be shared, only release one. */
- if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
- p->split->dbg->fake_addr_cu = NULL;
- INTUSE(dwarf_end) (p->split->dbg);
+ Dwarf_Abbrev_Hash_free (&p->abbrev_hash);
+
+ /* Free split dwarf one way (from skeleton to split). */
+ if (p->unit_type == DW_UT_skeleton
+ && p->split != NULL && p->split != (void *)-1)
+ {
+ /* The fake_addr_cu might be shared, only release one. */
+ if (p->dbg->fake_addr_cu == p->split->dbg->fake_addr_cu)
+ p->split->dbg->fake_addr_cu = NULL;
+ INTUSE(dwarf_end) (p->split->dbg);
+ }
}
}
@@ -94,14 +99,20 @@ dwarf_end (Dwarf *dwarf)
/* And the split Dwarf. */
tdestroy (dwarf->split_tree, noop_free);
- struct libdw_memblock *memp = dwarf->mem_tail;
- /* The first block is allocated together with the Dwarf object. */
- while (memp->prev != NULL)
- {
- struct libdw_memblock *prevp = memp->prev;
- free (memp);
- memp = prevp;
- }
+ /* Free the internally allocated memory. */
+ 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_getcfi.c b/libdw/dwarf_getcfi.c
index 9aed403e..51932cd9 100644
--- a/libdw/dwarf_getcfi.c
+++ b/libdw/dwarf_getcfi.c
@@ -58,6 +58,7 @@ dwarf_getcfi (Dwarf *dbg)
cfi->e_ident = (unsigned char *) elf_getident (dbg->elf, NULL);
cfi->other_byte_order = dbg->other_byte_order;
+ cfi->default_same_value = false;
cfi->next_offset = 0;
cfi->cie_tree = cfi->fde_tree = cfi->expr_tree = NULL;
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 eebb7d12..36c2acd9 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -31,9 +31,11 @@
#include <libintl.h>
#include <stdbool.h>
+#include <pthread.h>
#include <libdw.h>
#include <dwarf.h>
+#include "atomics.h"
/* gettext helper macros. */
@@ -218,16 +220,22 @@ struct Dwarf
/* Similar for addrx/constx, which will come from .debug_addr section. */
struct Dwarf_CU *fake_addr_cu;
- /* Internal memory handling. This is basically a simplified
+ /* 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_tail;
+ } **mem_tails;
/* Default size of allocated memory blocks. */
size_t mem_default_size;
@@ -570,9 +578,9 @@ libdw_valid_user_form (int form)
extern void __libdw_seterrno (int value) internal_function;
-/* Memory handling, the easy parts. This macro does not do any locking. */
+/* Memory handling, the easy parts. */
#define libdw_alloc(dbg, type, tsize, cnt) \
- ({ struct libdw_memblock *_tail = (dbg)->mem_tail; \
+ ({ 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) \
@@ -591,6 +599,23 @@ extern void __libdw_seterrno (int value) internal_function;
#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 f1e08714..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,8 +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 = dbg->mem_tail;
- dbg->mem_tail = newp;
+ 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;
}