summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2008-12-15 15:27:01 +0100
committerPetr Machata <pmachata@redhat.com>2008-12-15 15:27:01 +0100
commitd62eda6e2cd2862fadad971a1ce14e7c4075f5d6 (patch)
tree2cebc98c9d54489f538fb56c795bba428f941a42
parent468fe4d81a3e92157f4c0446675487dc230b2ec6 (diff)
downloadelfutils-pmachata/threads.tar.gz
Dump com.redhat.elfutils.pmachata.threads from monotone.pmachata/threads
-rw-r--r--libdw/ChangeLog174
-rw-r--r--libdw/dwarf_attr.c47
-rw-r--r--libdw/dwarf_begin.c3
-rw-r--r--libdw/dwarf_child.c92
-rw-r--r--libdw/dwarf_cuoffset.c15
-rw-r--r--libdw/dwarf_decl_file.c30
-rw-r--r--libdw/dwarf_diecu.c4
-rw-r--r--libdw/dwarf_dieoffset.c14
-rw-r--r--libdw/dwarf_end.c5
-rw-r--r--libdw/dwarf_entry_breakpoints.c46
-rw-r--r--libdw/dwarf_entrypc.c23
-rw-r--r--libdw/dwarf_filesrc.c14
-rw-r--r--libdw/dwarf_formaddr.c18
-rw-r--r--libdw/dwarf_formblock.c26
-rw-r--r--libdw/dwarf_formflag.c13
-rw-r--r--libdw/dwarf_formref.c8
-rw-r--r--libdw/dwarf_formref_die.c27
-rw-r--r--libdw/dwarf_formsdata.c17
-rw-r--r--libdw/dwarf_formstring.c22
-rw-r--r--libdw/dwarf_formudata.c17
-rw-r--r--libdw/dwarf_func_inline.c25
-rw-r--r--libdw/dwarf_getabbrev.c55
-rw-r--r--libdw/dwarf_getattrs.c43
-rw-r--r--libdw/dwarf_getfuncs.c30
-rw-r--r--libdw/dwarf_getmacros.c33
-rw-r--r--libdw/dwarf_getpubnames.c40
-rw-r--r--libdw/dwarf_getscopes.c21
-rw-r--r--libdw/dwarf_getscopes_die.c3
-rw-r--r--libdw/dwarf_getsrclines.c1072
-rw-r--r--libdw/dwarf_hasattr.c19
-rw-r--r--libdw/dwarf_haschildren.c18
-rw-r--r--libdw/dwarf_haspc.c19
-rw-r--r--libdw/dwarf_highpc.c18
-rw-r--r--libdw/dwarf_lowpc.c19
-rw-r--r--libdw/dwarf_nextcu.c28
-rw-r--r--libdw/dwarf_offabbrev.c2
-rw-r--r--libdw/dwarf_offdie.c21
-rw-r--r--libdw/dwarf_ranges.c41
-rw-r--r--libdw/dwarf_siblingof.c28
-rw-r--r--libdw/dwarf_tag.c38
-rw-r--r--libdw/libdwP.h164
-rw-r--r--libdw/libdw_findcu.c33
-rw-r--r--libdw/libdw_form.c6
-rw-r--r--libdw/libdw_visit_scopes.c27
44 files changed, 1688 insertions, 730 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 235fac01..40b1d630 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,177 @@
+2008-12-04 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_getattrs.c (dwarf_getattrs): Unlock before handing the
+ control over to the callback.
+ * dwarf_getfuncs.c (dwarf_getfuncs): Lock around the function
+ body, unlock before handing the control over to the callback.
+ * dwarf_getmacros.c (dwarf_getmacros): Likewise.
+ * TODO.threads: new file with temporary notes
+
+2008-12-03 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_child.c (find_attr): Replace one call with its _rdlock
+ equivalent.
+ * dwarf_offdie.c (dwarf_offdie): Likewise.
+ * dwarf_func_inline.c (scope_visitor): Replace calls with their
+ _rdlock equivalents. Unlock before handing the control over to
+ callback, relock when it returns. Document that potential relock
+ in __libdw_tag_rdlock is not a problem.
+ (dwarf_func_inline_instances): Lock around the body.
+ * dwarf_getabbrev.c (static getabbrev): New function with guts
+ from __libdw_getabbrev. Take extra argument WRLOCKED. Relock if
+ necessary before writing to cache.
+ (__libdw_getabbrev, __libdw_getabbrev_rdlock): Make them wrappers
+ of static getabbrev.
+ (dwarf_getabbrev): Lock around the body.
+ * dwarf_getpubnames.c (dwarf_getpubnames): Document that we can
+ take wrlock in advance only in this special case.
+ * dwarf_getscopes.c (pc_match): Replace calls with their _rdlock
+ equivalents. Document that we don't mind the potential relocks.
+ (pc_record): Likewise.
+ (dwarf_getscopes): Lock around the body.
+ * dwarf_getscopes_die.c (dwarf_getscopes_die): Lock around the body
+ * dwarf_hasattr.c (dwarf_hasattr): Split into
+ __libdw_hasattr_rdlock.
+ * dwarf_haschildren.c (dwarf_haschildren): Split into
+ __libdw_haschildren_rdlock, lock around the body.
+ * dwarf_haspc.c (dwarf_haspc): Split into __libdw_haspc_rdlock,
+ lock around the body.
+ * dwarf_nextcu.c (dwarf_nextcu): Split into __libdw_nextcu_rdlock.
+ * dwarf_offabbrev.c (dwarf_offabbrev): Lock around the body.
+ * dwarf_siblingof.c (dwarf_siblingof): Split into
+ __libdw_siblingof_rdlock.
+ * dwarf_tag.c (static findabbrev): New function with guts from
+ __libdw_findabbrev. Take extra argument WRLOCKED. Replace calls
+ with their _rdlock and _wrlock equivalents.
+ (__libdw_findabbrev, __libdw_findabbrev_wrlock): Make them
+ wrappers of static findabbrev.
+ (dwarf_tag): Split into __libdw_tag_rdlock. Lock around the body.
+ * libdw_findcu.c: Same as dwarf_tag.c, but for __libdw_findcu.
+ * libdw_visit_scopes.c (libdw_visit_scopes): Replace calls with
+ their _rdlock equivalents. Document that potential relocks are
+ not a problem.
+ * libdwP.h: Document all the changes described above. Document
+ which functions may relock.
+
+
+2008-11-28 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_filesrc.c (dwarf_filesrc): rdlock around the body.
+ * dwarf_formblock.c (dwarf_formblock): Split into
+ __libdw_formblock_rdlock.
+ * dwarf_formref_die.c (dwarf_formref_die): Split into
+ __libdw_formref_die_rdlock.
+ * dwarf_child.c (dwarf_child): Split into
+ __libdw_child_rdlock and __libdw_child_wrlock.
+
+2008-11-27 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_ranges.c (dwarf_ranges): Split into __libdw_ranges_rdlock.
+ * dwarf_entry_breakpoints.c (dwarf_entry_breakpoints): Lock around
+ the body, replace calls with _rdlock equivalents.
+
+2008-11-27 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_entrypc.c (dwarf_entrypc): Split into
+ __libdw_entrypc_rdlock.
+ * dwarf_highpc.c (dwarf_highpc): Split into
+ __libdw_highpc_rdlock.
+ * dwarf_lowpc.c (dwarf_lowpc): Split into
+ __libdw_lowpc_rdlock.
+
+2008-11-27 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formaddr.c (dwarf_formaddr): Split into
+ __libdw_formaddr_rdlock.
+
+2008-11-26 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_diecu.c (dwarf_diecu): rdlock around the body.
+ * dwarf_dieoffset (dwarf_dieoffset): Likewise.
+
+2008-11-25 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_decl_file.c (dwarf_decl_file): rdlock or wrlock around the
+ body. Replace various internal calls with _rdlock/_wrlock calls.
+
+2008-11-25 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_getsrclines.c (dwarf_getsrclines): Split into
+ __libdw_getsrclines_rdlock, __libdw_getsrclines_wrlock, and static
+ getsrclines. Replace various internal calls with _rdlock/_wrlock
+ calls.
+
+2008-11-25 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formstring.c (dwarf_formstring): Split into
+ __libdw_formstring_rdlock.
+
+2008-11-25 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formudata.c (dwarf_formudata): Split into
+ __libdw_formudata_rdlock.
+
+2008-11-24 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formsdata.c (dwarf_formsdata): Split into
+ __libdw_formsdata_rdlock.
+
+2008-11-21 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_attr.c (dwarf_attr): rdlock around the body, split into
+ __libdw_attr_rdlock and __libdw_attr_wrlock.
+
+2008-11-21 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_cuoffset.c (dwarf_cuoffset): rdlock around the body.
+
+2008-11-11 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_getpubnames.c (dwarf_getpubnames): Lock around the body.
+
+2008-11-11 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_nextcu.c (dwarf_nextcu): rdlock around the body.
+
+2008-11-11 Petr Machata <pmachata@redhat.com>
+
+ * dwarf_formaddr.c (dwarf_formaddr): rdlock around the body.
+ * dwarf_formblock.c (dwarf_formblock): Likewise.
+ * dwarf_formflag.c (dwarf_formflag): Likewise.
+ * dwarf_formsdata.c (dwarf_formsdata): Likewise.
+ * dwarf_formudata.c (dwarf_formudata): Likewise.
+ * dwarf_formref.c (dwarf_formref): Likewise.
+ (__libdw_formref): Rename to __libdw_formref_rdlock.
+ * dwarf_offdie.c (dwarf_offdie): Rename to __libdw_offdie_rdlock.
+ (dwarf_offdie): New function that's thin locking wrapper of above.
+ * dwarf_formref_die.c (dwarf_formref_die): rdlock around the body.
+ Call __libdw_formref_rdlock, __libdw_offdie_rdlock.
+ * dwarf_siblingof.c (dwarf_siblingof): Call __libdw_formref_rdlock.
+ * libdwP.h: Reflect above changes.
+
+2008-11-07 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (__libdw_form_val_len): Rename to _rdlock.
+ (__libdw_find_attr): Likewise.
+ * dwarf_attr.c (dwarf_attr),
+ * dwarf_child.c (dwarf_child),
+ * dwarf_getattrs.c (warf_getattrs),
+ * dwarf_hasattr.c (dwarf_hasattr),
+ * dwarf_siblingof.c (dwarf_siblingof) Lock around bodies of
+ functions. Call appropriate _rdlock functions per the renaming
+ above. Replace returns with `goto out'.
+ * libdw_form.c (__libdw_form_val_len): Rename per the above. Call
+ __libdw_form_val_len_rdlock.
+ * dwarf_child.c (__libdw_find_attr): Split into
+ __libdw_find_attr_rdlock and __libdw_find_attr_wrlock. Upgrade
+ the lock to wrlock if necessary to initialize the cache.
+
+2008-11-05 Petr Machata <pmachata@redhat.com>
+
+ * libdwP.h (struct Dwarf): Add lock.
+ * dwarf_begin.c (dwarf_begin): Initialize it.
+ * dwarf_end.c (dwarf_end): Destroy it.
+
2008-08-15 Roland McGrath <roland@redhat.com>
* libdw.map (ELFUTILS_0.136): New version set, inherits from
diff --git a/libdw/dwarf_attr.c b/libdw/dwarf_attr.c
index d3b03244..26ace6c4 100644
--- a/libdw/dwarf_attr.c
+++ b/libdw/dwarf_attr.c
@@ -56,6 +56,43 @@
#include "libdwP.h"
+static Dwarf_Attribute *
+attr (die, search_name, result, wrlocked)
+ Dwarf_Die *die;
+ unsigned int search_name;
+ Dwarf_Attribute *result;
+ int wrlocked;
+{
+ /* Search for the attribute with the given name. */
+ result->valp = (wrlocked
+ ? __libdw_find_attr_wrlock
+ : __libdw_find_attr_rdlock)
+ (die, search_name, &result->code, &result->form);
+
+ /* Always fill in the CU information. */
+ result->cu = die->cu;
+
+ return result->code == search_name ? result : NULL;
+}
+
+Dwarf_Attribute *
+__libdw_attr_rdlock (die, search_name, result)
+ Dwarf_Die *die;
+ unsigned int search_name;
+ Dwarf_Attribute *result;
+{
+ return attr (die, search_name, result, 0);
+}
+
+Dwarf_Attribute *
+__libdw_attr_wrlock (die, search_name, result)
+ Dwarf_Die *die;
+ unsigned int search_name;
+ Dwarf_Attribute *result;
+{
+ return attr (die, search_name, result, 1);
+}
+
Dwarf_Attribute *
dwarf_attr (die, search_name, result)
Dwarf_Die *die;
@@ -65,12 +102,10 @@ dwarf_attr (die, search_name, result)
if (die == NULL)
return NULL;
- /* Search for the attribute with the given name. */
- result->valp = __libdw_find_attr (die, search_name, &result->code,
- &result->form);
- /* Always fill in the CU information. */
- result->cu = die->cu;
+ rwlock_rdlock (die->cu->dbg->lock);
+ Dwarf_Attribute *retval = __libdw_attr_rdlock (die, search_name, result);
+ rwlock_unlock (die->cu->dbg->lock);
- return result->code == search_name ? result : NULL;
+ return retval;
}
INTDEF(dwarf_attr)
diff --git a/libdw/dwarf_begin.c b/libdw/dwarf_begin.c
index 69935a40..9f38ea7e 100644
--- a/libdw/dwarf_begin.c
+++ b/libdw/dwarf_begin.c
@@ -117,5 +117,8 @@ dwarf_begin (fd, cmd)
result->free_elf = true;
}
+ if (result != NULL)
+ rwlock_init (result->lock);
+
return result;
}
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 0080cf9d..2431296b 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -59,10 +59,10 @@
#define INVALID 0xffffe444
-unsigned char *
-internal_function
-__libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
- unsigned int *codep, unsigned int *formp)
+static unsigned char *
+find_attr (Dwarf_Die *die, unsigned int search_name,
+ unsigned int *codep, unsigned int *formp,
+ int wrlocked)
{
Dwarf *dbg = die->cu->dbg;
const unsigned char *readp = (unsigned char *) die->addr;
@@ -76,8 +76,19 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
Dwarf_Abbrev *abbrevp = die->abbrev;
if (abbrevp == NULL)
{
- abbrevp = __libdw_findabbrev (die->cu, abbrev_code);
- die->abbrev = abbrevp ?: DWARF_END_ABBREV;
+ /* Relock for cache update. */
+ if (!wrlocked)
+ {
+ rwlock_unlock (dbg->lock);
+ rwlock_wrlock (dbg->lock);
+ }
+
+ /* Still no data? */
+ if ((abbrevp = die->abbrev) == NULL)
+ {
+ abbrevp = __libdw_findabbrev_wrlock (die->cu, abbrev_code);
+ die->abbrev = abbrevp ?: DWARF_END_ABBREV;
+ }
}
if (unlikely (die->abbrev == DWARF_END_ABBREV))
{
@@ -125,7 +136,8 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
/* Skip over the rest of this attribute (if there is any). */
if (attr_form != 0)
{
- size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp);
+ size_t len = __libdw_form_val_len_rdlock (dbg, die->cu,
+ attr_form, readp);
if (unlikely (len == (size_t) -1l))
{
@@ -148,10 +160,28 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
}
-int
-dwarf_child (die, result)
+unsigned char *
+internal_function
+__libdw_find_attr_rdlock (Dwarf_Die *die, unsigned int search_name,
+ unsigned int *codep, unsigned int *formp)
+{
+ return find_attr (die, search_name, codep, formp, 0);
+}
+
+unsigned char *
+internal_function
+__libdw_find_attr_wrlock (Dwarf_Die *die, unsigned int search_name,
+ unsigned int *codep, unsigned int *formp)
+{
+ return find_attr (die, search_name, codep, formp, 1);
+}
+
+
+static int
+child (die, result, wrlocked)
Dwarf_Die *die;
Dwarf_Die *result;
+ int wrlocked;
{
/* Ignore previous errors. */
if (die == NULL)
@@ -160,10 +190,15 @@ dwarf_child (die, result)
/* Skip past the last attribute. */
void *addr = NULL;
+ /* RESULT can be the same as DIE. So preserve what we need. */
+ struct Dwarf_CU *cu = die->cu;
+
/* If we already know there are no children do not search. */
if (die->abbrev != DWARF_END_ABBREV
&& (die->abbrev == NULL || die->abbrev->has_children))
- addr = __libdw_find_attr (die, INVALID, NULL, NULL);
+ addr = (wrlocked
+ ? __libdw_find_attr_wrlock
+ : __libdw_find_attr_rdlock) (die, INVALID, NULL, NULL);
if (unlikely (die->abbrev == (Dwarf_Abbrev *) -1l))
return -1;
@@ -184,9 +219,6 @@ dwarf_child (die, result)
if (unlikely (*code == '\0'))
return 1;
- /* RESULT can be the same as DIE. So preserve what we need. */
- struct Dwarf_CU *cu = die->cu;
-
/* Clear the entire DIE structure. This signals we have not yet
determined any of the information. */
memset (result, '\0', sizeof (Dwarf_Die));
@@ -199,4 +231,38 @@ dwarf_child (die, result)
return 0;
}
+
+int
+__libdw_child_rdlock (die, result)
+ Dwarf_Die *die;
+ Dwarf_Die *result;
+{
+ return child (die, result, 0);
+}
+
+int
+__libdw_child_wrlock (die, result)
+ Dwarf_Die *die;
+ Dwarf_Die *result;
+{
+ return child (die, result, 1);
+}
+
+int
+dwarf_child (die, result)
+ Dwarf_Die *die;
+ Dwarf_Die *result;
+{
+ if (die == NULL)
+ return -1;
+
+ /* RESULT can be the same as DIE. So preserve what we need. */
+ struct Dwarf_CU *cu = die->cu;
+
+ rwlock_rdlock (cu->dbg->lock);
+ int retval = __libdw_child_rdlock (die, result);
+ rwlock_unlock (cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_child)
diff --git a/libdw/dwarf_cuoffset.c b/libdw/dwarf_cuoffset.c
index 10238b43..cd211aab 100644
--- a/libdw/dwarf_cuoffset.c
+++ b/libdw/dwarf_cuoffset.c
@@ -60,9 +60,14 @@ Dwarf_Off
dwarf_cuoffset (die)
Dwarf_Die *die;
{
- return (die == NULL
- ? (Dwarf_Off) -1l
- : (die->addr
- - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
- - die->cu->start));
+ if (die == NULL)
+ return (Dwarf_Off) -1l;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ Dwarf_Off retval = (die->addr
+ - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ - die->cu->start);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
}
diff --git a/libdw/dwarf_decl_file.c b/libdw/dwarf_decl_file.c
index b1d62df2..254c4e7c 100644
--- a/libdw/dwarf_decl_file.c
+++ b/libdw/dwarf_decl_file.c
@@ -63,19 +63,26 @@ dwarf_decl_file (Dwarf_Die *die)
Dwarf_Attribute attr_mem;
Dwarf_Sword idx = 0;
- if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr) (die, DW_AT_decl_file,
- &attr_mem), &idx) != 0)
- return NULL;
+ const char *retval = NULL;
+ struct Dwarf_CU *cu = die->cu;
+
+ if (cu->lines == NULL)
+ rwlock_wrlock (cu->dbg->lock);
+ else
+ rwlock_rdlock (cu->dbg->lock);
+
+ if (__libdw_formsdata_rdlock (__libdw_attr_rdlock (die, DW_AT_decl_file,
+ &attr_mem), &idx) != 0)
+ goto out;
/* Zero means no source file information available. */
if (idx == 0)
{
__libdw_seterrno (DWARF_E_NO_ENTRY);
- return NULL;
+ goto out;
}
/* Get the array of source files for the CU. */
- struct Dwarf_CU *cu = die->cu;
if (cu->lines == NULL)
{
Dwarf_Lines *lines;
@@ -83,7 +90,8 @@ dwarf_decl_file (Dwarf_Die *die)
/* Let the more generic function do the work. It'll create more
data but that will be needed in an real program anyway. */
- (void) INTUSE(dwarf_getsrclines) (&CUDIE (cu), &lines, &nlines);
+ /* We have the strongest lock necessary, so just call _wrlock. */
+ (void) __libdw_getsrclines_wrlock (&CUDIE (cu), &lines, &nlines);
assert (cu->lines != NULL);
}
@@ -92,7 +100,7 @@ dwarf_decl_file (Dwarf_Die *die)
/* If the file index is not zero, there must be file information
available. */
__libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
+ goto out;
}
assert (cu->files != NULL && cu->files != (void *) -1l);
@@ -100,8 +108,12 @@ dwarf_decl_file (Dwarf_Die *die)
if (idx >= cu->files->nfiles)
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
- return NULL;
+ goto out;
}
- return cu->files->info[idx].name;
+ retval = cu->files->info[idx].name;
+
+ out:
+ rwlock_unlock (cu->dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_diecu.c b/libdw/dwarf_diecu.c
index a62b8222..544d1a32 100644
--- a/libdw/dwarf_diecu.c
+++ b/libdw/dwarf_diecu.c
@@ -69,6 +69,8 @@ dwarf_diecu (die, result, address_sizep, offset_sizep)
determined any of the information. */
memset (result, '\0', sizeof (Dwarf_Die));
+ rwlock_rdlock (die->cu->dbg->lock);
+
result->addr = ((char *) die->cu->dbg->sectiondata[IDX_debug_info]->d_buf
+ DIE_OFFSET_FROM_CU_OFFSET (die->cu->start,
die->cu->offset_size));
@@ -79,5 +81,7 @@ dwarf_diecu (die, result, address_sizep, offset_sizep)
if (offset_sizep != NULL)
*offset_sizep = die->cu->offset_size;
+ rwlock_rdlock (die->cu->dbg->lock);
+
return result;
}
diff --git a/libdw/dwarf_dieoffset.c b/libdw/dwarf_dieoffset.c
index 4d712f7f..0f0acf77 100644
--- a/libdw/dwarf_dieoffset.c
+++ b/libdw/dwarf_dieoffset.c
@@ -60,9 +60,15 @@ Dwarf_Off
dwarf_dieoffset (die)
Dwarf_Die *die;
{
- return (die == NULL
- ? ~0ul
- : (Dwarf_Off) (die->addr
- - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf));
+ if (die == NULL)
+ return ~0ul;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ Dwarf_Off retval
+ = (Dwarf_Off) (die->addr
+ - die->cu->dbg->sectiondata[IDX_debug_info]->d_buf);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
}
INTDEF(dwarf_dieoffset)
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 60c9716e..4cc192c8 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -82,6 +82,8 @@ dwarf_end (dwarf)
{
if (dwarf != NULL)
{
+ rwlock_wrlock (dwarf->lock);
+
/* The search tree for the CUs. NB: the CU data itself is
allocated separately, but the abbreviation hash tables need
to be handled. */
@@ -103,6 +105,9 @@ dwarf_end (dwarf)
if (dwarf->free_elf)
elf_end (dwarf->elf);
+ /* Free the lock. */
+ rwlock_fini (dwarf->lock);
+
/* Free the context descriptor. */
free (dwarf);
}
diff --git a/libdw/dwarf_entry_breakpoints.c b/libdw/dwarf_entry_breakpoints.c
index 578464f3..c5e3fb63 100644
--- a/libdw/dwarf_entry_breakpoints.c
+++ b/libdw/dwarf_entry_breakpoints.c
@@ -83,20 +83,29 @@ dwarf_entry_breakpoints (die, bkpts)
inline int entrypc_bkpt (void)
{
Dwarf_Addr pc;
- return INTUSE(dwarf_entrypc) (die, &pc) < 0 ? -1 : add_bkpt (pc);
+ return __libdw_entrypc_rdlock (die, &pc) < 0 ? -1 : add_bkpt (pc);
}
+ rwlock_rdlock (die->cu->dbg->lock);
+
/* Fetch the CU's line records to look for this DIE's addresses. */
Dwarf_Die cudie = CUDIE (die->cu);
Dwarf_Lines *lines;
size_t nlines;
- if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0)
+ int retval = -1;
+
+ /* getsrclines may upgrade the lock to wrlock, but we don't mind. */
+ if (__libdw_getsrclines_rdlock (&cudie, &lines, &nlines) < 0)
{
int error = INTUSE (dwarf_errno) ();
if (error == DWARF_E_NO_DEBUG_LINE)
- return entrypc_bkpt ();
- __libdw_seterrno (error);
- return -1;
+ retval = entrypc_bkpt ();
+ else
+ {
+ __libdw_seterrno (error);
+ retval = -1;
+ }
+ goto out;
}
/* Search a contiguous PC range for prologue-end markers.
@@ -143,13 +152,18 @@ dwarf_entry_breakpoints (die, bkpts)
Dwarf_Addr base;
Dwarf_Addr begin;
Dwarf_Addr end;
- ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end);
+ /* If this could upgrade to wrlock, it would already have happened
+ above in the getsrclines call. */
+ ptrdiff_t offset = __libdw_ranges_rdlock (die, 0, &base, &begin, &end);
if (offset < 0)
- return -1;
+ goto out;
/* Most often there is a single contiguous PC range for the DIE. */
if (offset == 1)
- return search_range (begin, end, true, true) ?: entrypc_bkpt ();
+ {
+ retval = search_range (begin, end, true, true) ?: entrypc_bkpt ();
+ goto out;
+ }
Dwarf_Addr lowpc = (Dwarf_Addr) -1l;
Dwarf_Addr highpc = (Dwarf_Addr) -1l;
@@ -157,7 +171,7 @@ dwarf_entry_breakpoints (die, bkpts)
{
/* We have an address range entry. */
if (search_range (begin, end, true, false) < 0)
- return -1;
+ goto out;
if (begin < lowpc)
{
@@ -165,14 +179,18 @@ dwarf_entry_breakpoints (die, bkpts)
highpc = end;
}
- offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end);
+ offset = __libdw_ranges_rdlock (die, offset, &base, &begin, &end);
}
/* If we didn't find any proper DWARF markers, then look in the
lowest-addressed range for an ad hoc marker. Failing that,
fall back to just using the entrypc value. */
- return (nbkpts
- ?: (lowpc == (Dwarf_Addr) -1l ? 0
- : search_range (lowpc, highpc, false, true))
- ?: entrypc_bkpt ());
+ retval = (nbkpts
+ ?: (lowpc == (Dwarf_Addr) -1l ? 0
+ : search_range (lowpc, highpc, false, true))
+ ?: entrypc_bkpt ());
+
+ out:
+ rwlock_unlock (die->cu->dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_entrypc.c b/libdw/dwarf_entrypc.c
index 1719be27..2a590c4b 100644
--- a/libdw/dwarf_entrypc.c
+++ b/libdw/dwarf_entrypc.c
@@ -56,16 +56,27 @@
int
-dwarf_entrypc (die, return_addr)
+__libdw_entrypc_rdlock (die, return_addr)
Dwarf_Die *die;
Dwarf_Addr *return_addr;
{
Dwarf_Attribute attr_mem;
+ return __libdw_formaddr_rdlock (__libdw_attr_rdlock (die, DW_AT_entry_pc,
+ &attr_mem)
+ ?: __libdw_attr_rdlock (die, DW_AT_low_pc,
+ &attr_mem),
+ return_addr);
+}
+
+int
+dwarf_entrypc (die, return_addr)
+ Dwarf_Die *die;
+ Dwarf_Addr *return_addr;
+{
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_entrypc_rdlock (die, return_addr);
+ rwlock_unlock (die->cu->dbg->lock);
- return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_entry_pc,
- &attr_mem)
- ?: INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_mem),
- return_addr);
+ return retval;
}
INTDEF(dwarf_entrypc)
diff --git a/libdw/dwarf_filesrc.c b/libdw/dwarf_filesrc.c
index b48340d4..74b3cf16 100644
--- a/libdw/dwarf_filesrc.c
+++ b/libdw/dwarf_filesrc.c
@@ -59,14 +59,24 @@ const char *
dwarf_filesrc (Dwarf_Files *file, size_t idx, Dwarf_Word *mtime,
Dwarf_Word *length)
{
- if (file == NULL || idx >= file->nfiles)
+ if (file == NULL)
return NULL;
+ const char *retval = NULL;
+ rwlock_rdlock (file->dbg->lock);
+
+ if (idx >= file->nfiles)
+ goto out;
+
if (mtime != NULL)
*mtime = file->info[idx].mtime;
if (length != NULL)
*length = file->info[idx].length;
- return file->info[idx].name;
+ retval = file->info[idx].name;
+
+ out:
+ rwlock_unlock (file->dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_formaddr.c b/libdw/dwarf_formaddr.c
index dcb58d43..1f1eaa1a 100644
--- a/libdw/dwarf_formaddr.c
+++ b/libdw/dwarf_formaddr.c
@@ -55,9 +55,8 @@
#include <dwarf.h>
#include "libdwP.h"
-
int
-dwarf_formaddr (attr, return_addr)
+__libdw_formaddr_rdlock (attr, return_addr)
Dwarf_Attribute *attr;
Dwarf_Addr *return_addr;
{
@@ -77,4 +76,19 @@ dwarf_formaddr (attr, return_addr)
return 0;
}
+
+int
+dwarf_formaddr (attr, return_addr)
+ Dwarf_Attribute *attr;
+ Dwarf_Addr *return_addr;
+{
+ if (attr == NULL)
+ return -1;
+
+ rwlock_rdlock (attr->cu->dbg->lock);
+ int retval = __libdw_formaddr_rdlock (attr, return_addr);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_formaddr)
diff --git a/libdw/dwarf_formblock.c b/libdw/dwarf_formblock.c
index 51396d47..c6019b81 100644
--- a/libdw/dwarf_formblock.c
+++ b/libdw/dwarf_formblock.c
@@ -57,13 +57,14 @@
int
-dwarf_formblock (attr, return_block)
+__libdw_formblock_rdlock (attr, return_block)
Dwarf_Attribute *attr;
Dwarf_Block *return_block;
{
if (attr == NULL)
return -1;
+ Dwarf *dbg = attr->cu->dbg;
const unsigned char *datap;
switch (attr->form)
@@ -74,12 +75,12 @@ dwarf_formblock (attr, return_block)
break;
case DW_FORM_block2:
- return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
+ return_block->length = read_2ubyte_unaligned (dbg, attr->valp);
return_block->data = attr->valp + 2;
break;
case DW_FORM_block4:
- return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ return_block->length = read_4ubyte_unaligned (dbg, attr->valp);
return_block->data = attr->valp + 4;
break;
@@ -95,8 +96,8 @@ dwarf_formblock (attr, return_block)
}
if (return_block->data + return_block->length
- > ((unsigned char *) attr->cu->dbg->sectiondata[IDX_debug_info]->d_buf
- + attr->cu->dbg->sectiondata[IDX_debug_info]->d_size))
+ > ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf
+ + dbg->sectiondata[IDX_debug_info]->d_size))
{
/* Block does not fit. */
__libdw_seterrno (DWARF_E_INVALID_DWARF);
@@ -105,4 +106,19 @@ dwarf_formblock (attr, return_block)
return 0;
}
+
+int
+dwarf_formblock (attr, return_block)
+ Dwarf_Attribute *attr;
+ Dwarf_Block *return_block;
+{
+ if (attr == NULL)
+ return -1;
+
+ rwlock_rdlock (attr->cu->dbg->lock);
+ int retval = __libdw_formblock_rdlock (attr, return_block);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_formblock)
diff --git a/libdw/dwarf_formflag.c b/libdw/dwarf_formflag.c
index 4e57c3af..bb0879be 100644
--- a/libdw/dwarf_formflag.c
+++ b/libdw/dwarf_formflag.c
@@ -64,13 +64,18 @@ dwarf_formflag (attr, return_bool)
if (attr == NULL)
return -1;
+ Dwarf *dbg = attr->cu->dbg;
+ rwlock_rdlock (dbg->lock);
+ int retval = 0;
+
if (unlikely (attr->form != DW_FORM_flag))
{
__libdw_seterrno (DWARF_E_NO_FLAG);
- return -1;
+ retval = -1;
}
+ else
+ *return_bool = *attr->valp != 0;
- *return_bool = *attr->valp != 0;
-
- return 0;
+ rwlock_unlock (dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
index b8463b70..a70f89aa 100644
--- a/libdw/dwarf_formref.c
+++ b/libdw/dwarf_formref.c
@@ -56,7 +56,7 @@
#include "libdwP.h"
int
-__libdw_formref (attr, return_offset)
+__libdw_formref_rdlock (attr, return_offset)
Dwarf_Attribute *attr;
Dwarf_Off *return_offset;
{
@@ -113,5 +113,9 @@ dwarf_formref (attr, return_offset)
if (attr == NULL)
return -1;
- return __libdw_formref (attr, return_offset);
+ rwlock_rdlock (attr->cu->dbg->lock);
+ int retval = __libdw_formref_rdlock (attr, return_offset);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 90a4b2d3..6926c1a8 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -56,13 +56,15 @@
Dwarf_Die *
-dwarf_formref_die (attr, die_mem)
+__libdw_formref_die_rdlock (attr, die_mem)
Dwarf_Attribute *attr;
Dwarf_Die *die_mem;
{
if (attr == NULL)
return NULL;
+ Dwarf *dbg = attr->cu->dbg;
+
Dwarf_Off offset;
if (attr->form == DW_FORM_ref_addr)
{
@@ -73,18 +75,33 @@ dwarf_formref_die (attr, die_mem)
: attr->cu->offset_size);
if (ref_size == 8)
- offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+ offset = read_8ubyte_unaligned (dbg, attr->valp);
else
- offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ offset = read_4ubyte_unaligned (dbg, attr->valp);
}
else
{
/* Other forms produce an offset from the CU. */
- if (unlikely (__libdw_formref (attr, &offset) != 0))
+ if (unlikely (__libdw_formref_rdlock (attr, &offset) != 0))
return NULL;
offset += attr->cu->start;
}
- return INTUSE(dwarf_offdie) (attr->cu->dbg, offset, die_mem);
+ return __libdw_offdie_rdlock (dbg, offset, die_mem);
+}
+
+Dwarf_Die *
+dwarf_formref_die (attr, die_mem)
+ Dwarf_Attribute *attr;
+ Dwarf_Die *die_mem;
+{
+ if (attr == NULL)
+ return NULL;
+
+ rwlock_rdlock (attr->cu->dbg->lock);
+ Dwarf_Die *retval = __libdw_formref_die_rdlock (attr, die_mem);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
}
INTDEF (dwarf_formref_die)
diff --git a/libdw/dwarf_formsdata.c b/libdw/dwarf_formsdata.c
index ab7249d1..418675e2 100644
--- a/libdw/dwarf_formsdata.c
+++ b/libdw/dwarf_formsdata.c
@@ -57,7 +57,7 @@
int
-dwarf_formsdata (attr, return_sval)
+__libdw_formsdata_rdlock (attr, return_sval)
Dwarf_Attribute *attr;
Dwarf_Sword *return_sval;
{
@@ -101,4 +101,19 @@ dwarf_formsdata (attr, return_sval)
return 0;
}
+
+int
+dwarf_formsdata (attr, return_sval)
+ Dwarf_Attribute *attr;
+ Dwarf_Sword *return_sval;
+{
+ if (attr == NULL)
+ return -1;
+
+ rwlock_rdlock (attr->cu->dbg->lock);
+ int retval = __libdw_formsdata_rdlock (attr, return_sval);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_formsdata)
diff --git a/libdw/dwarf_formstring.c b/libdw/dwarf_formstring.c
index 790831ea..b7558efd 100644
--- a/libdw/dwarf_formstring.c
+++ b/libdw/dwarf_formstring.c
@@ -57,20 +57,20 @@
const char *
-dwarf_formstring (attrp)
+__libdw_formstring_rdlock (attrp)
Dwarf_Attribute *attrp;
{
/* Ignore earlier errors. */
if (attrp == NULL)
return NULL;
+ Dwarf *dbg = attrp->cu->dbg;
+
/* We found it. Now determine where the string is stored. */
if (attrp->form == DW_FORM_string)
/* A simple inlined string. */
return (const char *) attrp->valp;
- Dwarf *dbg = attrp->cu->dbg;
-
if (unlikely (attrp->form != DW_FORM_strp)
|| dbg->sectiondata[IDX_debug_str] == NULL)
{
@@ -91,4 +91,20 @@ dwarf_formstring (attrp)
return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off;
}
+
+const char *
+dwarf_formstring (attrp)
+ Dwarf_Attribute *attrp;
+{
+ /* Ignore earlier errors. */
+ if (attrp == NULL)
+ return NULL;
+
+ Dwarf *dbg = attrp->cu->dbg;
+ rwlock_rdlock (dbg->lock);
+ const char *retval = __libdw_formstring_rdlock (attrp);
+ rwlock_unlock (dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_formstring)
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index b5c40bb5..571588ff 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -57,7 +57,7 @@
int
-dwarf_formudata (attr, return_uval)
+__libdw_formudata_rdlock (attr, return_uval)
Dwarf_Attribute *attr;
Dwarf_Word *return_uval;
{
@@ -101,4 +101,19 @@ dwarf_formudata (attr, return_uval)
return 0;
}
+
+int
+dwarf_formudata (attr, return_uval)
+ Dwarf_Attribute *attr;
+ Dwarf_Word *return_uval;
+{
+ if (attr == NULL)
+ return -1;
+
+ rwlock_rdlock (attr->cu->dbg->lock);
+ int retval = __libdw_formudata_rdlock (attr, return_uval);
+ rwlock_unlock (attr->cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_formudata)
diff --git a/libdw/dwarf_func_inline.c b/libdw/dwarf_func_inline.c
index 6018691a..ffe25d89 100644
--- a/libdw/dwarf_func_inline.c
+++ b/libdw/dwarf_func_inline.c
@@ -66,24 +66,33 @@ scope_visitor (unsigned int depth __attribute__ ((unused)),
{
struct visitor_info *const v = arg;
- if (INTUSE(dwarf_tag) (&die->die) != DW_TAG_inlined_subroutine)
+ /* This may relock for cache update. But we give up the lock before
+ handing over to a callback anyway, so it's not a big deal,
+ performance-wise, that a couple functions that follow may do the
+ relock again unnecessarily. Correctness-wise, we cache no
+ volatile data that would go invalid while the lock is not ours.
+ (__libdw_visit_scopes assumes the visitor may relock.) */
+ if (__libdw_tag_rdlock (&die->die) != DW_TAG_inlined_subroutine)
return DWARF_CB_OK;
Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&die->die, DW_AT_abstract_origin,
- &attr_mem);
+ Dwarf_Attribute *attr = __libdw_attr_rdlock (&die->die, DW_AT_abstract_origin,
+ &attr_mem);
if (attr == NULL)
return DWARF_CB_OK;
Dwarf_Die origin_mem;
- Dwarf_Die *origin = INTUSE(dwarf_formref_die) (attr, &origin_mem);
+ Dwarf_Die *origin = __libdw_formref_die_rdlock (attr, &origin_mem);
if (origin == NULL)
return DWARF_CB_ABORT;
if (origin->addr != v->die_addr)
return DWARF_CB_OK;
- return (*v->callback) (&die->die, v->arg);
+ rwlock_unlock (die->die.cu->dbg->lock);
+ int retval = (*v->callback) (&die->die, v->arg);
+ rwlock_rdlock (die->die.cu->dbg->lock);
+ return retval;
}
int
@@ -115,7 +124,11 @@ dwarf_func_inline_instances (Dwarf_Die *func,
int (*callback) (Dwarf_Die *, void *),
void *arg)
{
+ rwlock_rdlock (func->cu->dbg->lock);
struct visitor_info v = { func->addr, callback, arg };
struct Dwarf_Die_Chain cu = { .die = CUDIE (func->cu), .parent = NULL };
- return __libdw_visit_scopes (0, &cu, &scope_visitor, NULL, &v);
+ int retval = __libdw_visit_scopes (0, &cu, &scope_visitor, NULL, &v);
+ rwlock_unlock (func->cu->dbg->lock);
+
+ return retval;
}
diff --git a/libdw/dwarf_getabbrev.c b/libdw/dwarf_getabbrev.c
index 07bf6dfc..5797a9fc 100644
--- a/libdw/dwarf_getabbrev.c
+++ b/libdw/dwarf_getabbrev.c
@@ -57,14 +57,14 @@
#include "libdwP.h"
-Dwarf_Abbrev *
-internal_function
-__libdw_getabbrev (dbg, cu, offset, lengthp, result)
+static Dwarf_Abbrev *
+getabbrev (dbg, cu, offset, lengthp, result, wrlocked)
Dwarf *dbg;
struct Dwarf_CU *cu;
Dwarf_Off offset;
size_t *lengthp;
Dwarf_Abbrev *result;
+ int wrlocked;
{
/* Don't fail if there is not .debug_abbrev section. */
if (dbg->sectiondata[IDX_debug_abbrev] == NULL)
@@ -103,12 +103,24 @@ __libdw_getabbrev (dbg, cu, offset, lengthp, result)
unsigned int code;
get_uleb128 (code, abbrevp);
+ inline void relock (void)
+ {
+ if (!wrlocked)
+ {
+ rwlock_unlock (dbg->lock);
+ rwlock_wrlock (dbg->lock);
+ }
+ }
+
/* Check whether this code is already in the hash table. */
bool foundit = false;
Dwarf_Abbrev *abb = NULL;
if (cu == NULL
|| (abb = Dwarf_Abbrev_Hash_find (&cu->abbrev_hash, code, NULL)) == NULL)
{
+ /* Relock here, we will need write lock eventually even if the
+ user passed the result pointer. */
+ relock ();
if (result == NULL)
abb = libdw_typed_alloc (dbg, Dwarf_Abbrev);
else
@@ -123,6 +135,9 @@ __libdw_getabbrev (dbg, cu, offset, lengthp, result)
/* If the caller doesn't need the length we are done. */
if (lengthp == NULL)
goto out;
+
+ /* We will need to update the hash table. */
+ relock ();
}
/* If there is already a value in the hash table we are going to
@@ -157,6 +172,29 @@ __libdw_getabbrev (dbg, cu, offset, lengthp, result)
return abb;
}
+Dwarf_Abbrev *
+internal_function
+__libdw_getabbrev (dbg, cu, offset, lengthp, result)
+ Dwarf *dbg;
+ struct Dwarf_CU *cu;
+ Dwarf_Off offset;
+ size_t *lengthp;
+ Dwarf_Abbrev *result;
+{
+ return getabbrev (dbg, cu, offset, lengthp, result, 0);
+}
+
+Dwarf_Abbrev *
+internal_function
+__libdw_getabbrev_wrlock (dbg, cu, offset, lengthp, result)
+ Dwarf *dbg;
+ struct Dwarf_CU *cu;
+ Dwarf_Off offset;
+ size_t *lengthp;
+ Dwarf_Abbrev *result;
+{
+ return getabbrev (dbg, cu, offset, lengthp, result, 1);
+}
Dwarf_Abbrev *
dwarf_getabbrev (die, offset, lengthp)
@@ -164,7 +202,12 @@ dwarf_getabbrev (die, offset, lengthp)
Dwarf_Off offset;
size_t *lengthp;
{
- return __libdw_getabbrev (die->cu->dbg, die->cu,
- die->cu->orig_abbrev_offset + offset, lengthp,
- NULL);
+ rwlock_rdlock (die->cu->dbg->lock);
+ Dwarf_Abbrev *retval
+ = __libdw_getabbrev (die->cu->dbg, die->cu,
+ die->cu->orig_abbrev_offset + offset,
+ lengthp, NULL);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
}
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
index 42f25ca0..0d0d4b32 100644
--- a/libdw/dwarf_getattrs.c
+++ b/libdw/dwarf_getattrs.c
@@ -62,6 +62,14 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
if (die == NULL)
return -1l;
+ /* Do not return 0 on success - there would be no way to distinguish
+ this value from the attribute at offset 0. Instead we return +1
+ which would never be a valid offset of an attribute. */
+ ptrdiff_t retval = 1l;
+
+ Dwarf *dbg = die->cu->dbg;
+ rwlock_rdlock (dbg->lock);
+
const unsigned char *die_addr = die->addr;
/* Get the abbreviation code. */
@@ -73,17 +81,12 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
die->abbrev = __libdw_findabbrev (die->cu, u128);
if (unlikely (die->abbrev == DWARF_END_ABBREV))
- {
- invalid_dwarf:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1l;
- }
+ goto invalid_dwarf;
/* This is where the attributes start. */
const unsigned char *attrp = die->abbrev->attrp + offset;
/* Go over the list of attributes. */
- Dwarf *dbg = die->cu->dbg;
while (1)
{
/* Are we still in bounds? */
@@ -102,36 +105,46 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
/* We can stop if we found the attribute with value zero. */
if (attr.code == 0 && attr.form == 0)
- /* Do not return 0 here - there would be no way to
- distinguish this value from the attribute at offset 0.
- Instead we return +1 which would never be a valid
- offset of an attribute. */
- return 1l;
+ goto out;
/* Fill in the rest. */
attr.valp = (unsigned char *) die_addr;
attr.cu = die->cu;
+ /* Unlock so that the callback can use official API. */
+ rwlock_unlock (dbg->lock);
/* Now call the callback function. */
if (callback (&attr, arg) != DWARF_CB_OK)
/* Return the offset of the start of the attribute, so that
dwarf_getattrs() can be restarted from this point if the
caller so desires. */
return remembered_attrp - die->abbrev->attrp;
+ rwlock_rdlock (dbg->lock);
/* Skip over the rest of this attribute (if there is any). */
if (attr.form != 0)
{
- size_t len = __libdw_form_val_len (dbg, die->cu, attr.form,
- die_addr);
+ size_t len = __libdw_form_val_len_rdlock (dbg, die->cu, attr.form,
+ die_addr);
if (unlikely (len == (size_t) -1l))
- /* Something wrong with the file. */
- return -1l;
+ {
+ /* Something wrong with the file. */
+ // XXX Shouldn't this be invalid_dwarf?
+ retval = -1l;
+ goto out;
+ }
// XXX We need better boundary checks.
die_addr += len;
}
}
/* NOTREACHED */
+
+ invalid_dwarf:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ retval = -1l;
+ out:
+ rwlock_unlock (dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_getfuncs.c b/libdw/dwarf_getfuncs.c
index c0352fbf..f6421331 100644
--- a/libdw/dwarf_getfuncs.c
+++ b/libdw/dwarf_getfuncs.c
@@ -60,35 +60,49 @@ ptrdiff_t
dwarf_getfuncs (Dwarf_Die *cudie, int (*callback) (Dwarf_Die *, void *),
void *arg, ptrdiff_t offset)
{
- if (unlikely (cudie == NULL
- || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
+ if (unlikely (cudie == NULL))
return -1;
+ ptrdiff_t retval = 0;
+
+ rwlock_rdlock (cudie->cu->dbg->lock);
+
+ if (unlikely (__libdw_tag_rdlock (cudie) != DW_TAG_compile_unit))
+ {
+ retval = -1;
+ goto out;
+ }
+
Dwarf_Die die_mem;
Dwarf_Die *die;
int res;
if (offset == 0)
- res = INTUSE(dwarf_child) (cudie, &die_mem);
+ res = __libdw_child_rdlock (cudie, &die_mem);
else
{
- die = INTUSE(dwarf_offdie) (cudie->cu->dbg, offset, &die_mem);
- res = INTUSE(dwarf_siblingof) (die, &die_mem);
+ die = __libdw_offdie_rdlock (cudie->cu->dbg, offset, &die_mem);
+ res = __libdw_siblingof_rdlock (die, &die_mem);
}
die = res != 0 ? NULL : &die_mem;
while (die != NULL)
{
- if (INTUSE(dwarf_tag) (die) == DW_TAG_subprogram)
+ if (__libdw_tag_rdlock (die) == DW_TAG_subprogram)
{
+ /* Relock so that the callback can use the official API. */
+ rwlock_unlock (cudie->cu->dbg->lock);
if (callback (die, arg) != DWARF_CB_OK)
return INTUSE(dwarf_dieoffset) (die);
+ rwlock_rdlock (cudie->cu->dbg->lock);
}
- if (INTUSE(dwarf_siblingof) (die, &die_mem) != 0)
+ if (__libdw_siblingof_rdlock (die, &die_mem) != 0)
break;
}
/* That's all. */
- return 0;
+ out:
+ rwlock_unlock (cudie->cu->dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index 743ade3b..4dc51a72 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -65,15 +65,25 @@ dwarf_getmacros (die, callback, arg, offset)
void *arg;
ptrdiff_t offset;
{
- /* Get the appropriate attribute. */
+ ptrdiff_t retval = 0;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+
+ /* Get the appropriate attribute. This may upgrade the lock to wrlock. */
Dwarf_Attribute attr;
- if (INTUSE(dwarf_attr) (die, DW_AT_macro_info, &attr) == NULL)
- return -1;
+ if (__libdw_attr_rdlock (die, DW_AT_macro_info, &attr) == NULL)
+ {
+ retval = -1;
+ goto out;
+ }
/* Offset into the .debug_macinfo section. */
Dwarf_Word macoff;
- if (INTUSE(dwarf_formudata) (&attr, &macoff) != 0)
- return -1;
+ if (__libdw_formudata_rdlock (&attr, &macoff) != 0)
+ {
+ retval = -1;
+ goto out;
+ }
const unsigned char *readp
= die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf + offset;
@@ -81,7 +91,7 @@ dwarf_getmacros (die, callback, arg, offset)
= readp + die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_size;
if (readp == readendp)
- return 0;
+ goto out;
if (*readp != DW_MACINFO_start_file)
goto invalid;
@@ -127,7 +137,7 @@ dwarf_getmacros (die, callback, arg, offset)
case 0:
/* Nothing more to do. */
- return 0;
+ goto out;
default:
goto invalid;
@@ -141,15 +151,22 @@ dwarf_getmacros (die, callback, arg, offset)
else
mac.param2.s = str;
+ /* Relock so that the callback can use the official API. */
+ rwlock_unlock (die->cu->dbg->lock);
if (callback (&mac, arg) != DWARF_CB_OK)
return (readp
- ((unsigned char *) die->cu->dbg->sectiondata[IDX_debug_macinfo]->d_buf
+ offset));
+ rwlock_rdlock (die->cu->dbg->lock);
}
/* If we come here the termination of the data for the CU is not
present. */
invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
+ retval = -1;
+
+ out:
+ rwlock_rdlock (die->cu->dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_getpubnames.c b/libdw/dwarf_getpubnames.c
index 1b054e26..a0ac6fba 100644
--- a/libdw/dwarf_getpubnames.c
+++ b/libdw/dwarf_getpubnames.c
@@ -179,16 +179,34 @@ dwarf_getpubnames (dbg, callback, arg, offset)
return -1l;
}
+ /* If we are going to call get_offsets, we will likely need write
+ lock. Take it right away so that we don't have to go through the
+ fuss of lock upgrading later. That means we need to read from
+ dbg before having locked, but we need to do that for dbg->lock
+ anyway. The worst that can happen is we accidentally take wrlock
+ where rdlock would have sufficed.
+
+ Note that we can do so specifically in this case, where we don't
+ call anything that would downgrade the lock back to rdlock. */
+ if (dbg->pubnames_nsets == 0)
+ rwlock_wrlock (dbg->lock);
+ else
+ rwlock_rdlock (dbg->lock);
+ ptrdiff_t retval = 0l;
+
/* Make sure it is a valid offset. */
if (unlikely (dbg->sectiondata[IDX_debug_pubnames] == NULL
|| ((size_t) offset
>= dbg->sectiondata[IDX_debug_pubnames]->d_size)))
/* No (more) entry. */
- return 0;
+ goto out;
/* If necessary read the set information. */
if (dbg->pubnames_nsets == 0 && unlikely (get_offsets (dbg) != 0))
- return -1l;
+ {
+ retval = -1l;
+ goto out;
+ }
/* Find the place where to start. */
size_t cnt;
@@ -238,12 +256,16 @@ dwarf_getpubnames (dbg, callback, arg, offset)
readp = (unsigned char *) rawmemchr (gl.name, '\0') + 1;
/* We found name and DIE offset. Report it. */
+ /* Give up the lock, so that the callback can use official
+ (locking) API. We can afford to do that: references
+ above are to write-once caches. */
+ rwlock_unlock (dbg->lock);
if (callback (dbg, &gl, arg) != DWARF_CB_OK)
- {
- /* The user wants us to stop. Return the offset of the
- next entry. */
- return readp - startp;
- }
+ /* The user wants us to stop. Return the offset of the
+ next entry. */
+ return readp - startp;
+ /* rdlock is enough at this point. */
+ rwlock_rdlock (dbg->lock);
}
if (++cnt == dbg->pubnames_nsets)
@@ -255,5 +277,7 @@ dwarf_getpubnames (dbg, callback, arg, offset)
}
/* We are done. No more entries. */
- return 0;
+ out:
+ rwlock_unlock (dbg->lock);
+ return retval;
}
diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c
index 73431ba7..8c0565af 100644
--- a/libdw/dwarf_getscopes.c
+++ b/libdw/dwarf_getscopes.c
@@ -78,8 +78,11 @@ pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
/* dwarf_haspc returns an error if there are no appropriate attributes.
But we use it indiscriminantly instead of presuming which tags can
have PC attributes. So when it fails for that reason, treat it just
- as a nonmatching return. */
- int result = INTUSE(dwarf_haspc) (&die->die, a->pc);
+ as a nonmatching return.
+
+ This call can relock, but we don't mind that here.
+ visit_scopes assumes that callbacks may relock. */
+ int result = __libdw_haspc_rdlock (&die->die, a->pc);
if (result < 0)
{
int error = INTUSE(dwarf_errno) ();
@@ -94,7 +97,7 @@ pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
die->prune = true;
if (!die->prune
- && INTUSE (dwarf_tag) (&die->die) == DW_TAG_inlined_subroutine)
+ && __libdw_tag_rdlock (&die->die) == DW_TAG_inlined_subroutine)
a->inlined = depth;
}
@@ -172,12 +175,15 @@ pc_record (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
Record its abstract_origin pointer. */
Dwarf_Die *const inlinedie = &a->scopes[depth - a->inlined];
- assert (INTUSE (dwarf_tag) (inlinedie) == DW_TAG_inlined_subroutine);
+ /* This may relock, but if it would, it would already have
+ happened during the __libdw_child_rdlock called from
+ __libdw_visit_scopes. */
+ assert (__libdw_tag_rdlock (inlinedie) == DW_TAG_inlined_subroutine);
Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = INTUSE (dwarf_attr) (inlinedie,
+ Dwarf_Attribute *attr = __libdw_attr_rdlock (inlinedie,
DW_AT_abstract_origin,
&attr_mem);
- if (INTUSE (dwarf_formref_die) (attr, &a->inlined_origin) == NULL)
+ if (__libdw_formref_die_rdlock (attr, &a->inlined_origin) == NULL)
return -1;
return 0;
}
@@ -210,6 +216,7 @@ dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
struct Dwarf_Die_Chain cu = { .parent = NULL, .die = *cudie };
struct args a = { .pc = pc };
+ rwlock_rdlock (cudie->cu->dbg->lock);
int result = __libdw_visit_scopes (0, &cu, &pc_match, &pc_record, &a);
if (result == 0 && a.scopes != NULL)
@@ -218,5 +225,7 @@ dwarf_getscopes (Dwarf_Die *cudie, Dwarf_Addr pc, Dwarf_Die **scopes)
if (result > 0)
*scopes = a.scopes;
+ rwlock_unlock (cudie->cu->dbg->lock);
+
return result;
}
diff --git a/libdw/dwarf_getscopes_die.c b/libdw/dwarf_getscopes_die.c
index 07fb9b00..3262670e 100644
--- a/libdw/dwarf_getscopes_die.c
+++ b/libdw/dwarf_getscopes_die.c
@@ -86,10 +86,13 @@ dwarf_getscopes_die (Dwarf_Die *die, Dwarf_Die **scopes)
if (die == NULL)
return -1;
+ rwlock_rdlock (die->cu->dbg->lock);
struct Dwarf_Die_Chain cu = { .die = CUDIE (die->cu), .parent = NULL };
void *info = die->addr;
int result = __libdw_visit_scopes (1, &cu, &scope_visitor, NULL, &info);
if (result > 0)
*scopes = info;
+ rwlock_unlock (die->cu->dbg->lock);
+
return result;
}
diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c
index 9b3c97af..30c9ee5e 100644
--- a/libdw/dwarf_getsrclines.c
+++ b/libdw/dwarf_getsrclines.c
@@ -111,575 +111,579 @@ compare_lines (const void *a, const void *b)
} while (0)
-int
-dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
+static int
+getsrclines (Dwarf_Die *cudie)
{
- if (unlikely (cudie == NULL
- || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
+ struct Dwarf_CU *const cu = cudie->cu;
+ if (cu->lines != NULL)
+ return 0;
+
+ /* Failsafe mode: no data found. */
+ cu->lines = (void *) -1l;
+ cu->files = (void *) -1l;
+
+ /* The die must have a statement list associated. */
+ Dwarf_Attribute stmt_list_mem;
+ Dwarf_Attribute *stmt_list = __libdw_attr_wrlock (cudie, DW_AT_stmt_list,
+ &stmt_list_mem);
+
+ /* Get the offset into the .debug_line section. NB: this call
+ also checks whether the previous dwarf_attr call failed. */
+ Dwarf_Word offset;
+ if (__libdw_formudata_rdlock (stmt_list, &offset) != 0)
return -1;
- int res = -1;
+ Dwarf *dbg = cu->dbg;
+ if (dbg->sectiondata[IDX_debug_line] == NULL)
+ {
+ __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
+ return -1;
+ }
+ const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset;
+ const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf
+ + dbg->sectiondata[IDX_debug_line]->d_size);
+
+ /* Get the compilation directory. */
+ Dwarf_Attribute compdir_attr_mem;
+ Dwarf_Attribute *compdir_attr = __libdw_attr_wrlock (cudie,
+ DW_AT_comp_dir,
+ &compdir_attr_mem);
+ const char *comp_dir = __libdw_formstring_rdlock (compdir_attr);
+
+ if (unlikely (linep + 4 > lineendp))
+ {
+ invalid_data:
+ __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
+ return -1;
+ }
+ Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
+ unsigned int length = 4;
+ if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
+ {
+ if (unlikely (linep + 8 > lineendp))
+ goto invalid_data;
+ unit_length = read_8ubyte_unaligned_inc (dbg, linep);
+ length = 8;
+ }
- /* Get the information if it is not already known. */
- struct Dwarf_CU *const cu = cudie->cu;
- if (cu->lines == NULL)
+ /* Check whether we have enough room in the section. */
+ if (unit_length < 2 + length + 5 * 1
+ || unlikely (linep + unit_length > lineendp))
+ goto invalid_data;
+ lineendp = linep + unit_length;
+
+ /* The next element of the header is the version identifier. */
+ uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
+ if (unlikely (version > DWARF_VERSION))
{
- /* Failsafe mode: no data found. */
- cu->lines = (void *) -1l;
- cu->files = (void *) -1l;
-
- /* The die must have a statement list associated. */
- Dwarf_Attribute stmt_list_mem;
- Dwarf_Attribute *stmt_list = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list,
- &stmt_list_mem);
-
- /* Get the offset into the .debug_line section. NB: this call
- also checks whether the previous dwarf_attr call failed. */
- Dwarf_Word offset;
- if (INTUSE(dwarf_formudata) (stmt_list, &offset) != 0)
- goto out;
-
- Dwarf *dbg = cu->dbg;
- if (dbg->sectiondata[IDX_debug_line] == NULL)
- {
- __libdw_seterrno (DWARF_E_NO_DEBUG_LINE);
- goto out;
- }
- const uint8_t *linep = dbg->sectiondata[IDX_debug_line]->d_buf + offset;
- const uint8_t *lineendp = (dbg->sectiondata[IDX_debug_line]->d_buf
- + dbg->sectiondata[IDX_debug_line]->d_size);
-
- /* Get the compilation directory. */
- Dwarf_Attribute compdir_attr_mem;
- Dwarf_Attribute *compdir_attr = INTUSE(dwarf_attr) (cudie,
- DW_AT_comp_dir,
- &compdir_attr_mem);
- const char *comp_dir = INTUSE(dwarf_formstring) (compdir_attr);
-
- if (unlikely (linep + 4 > lineendp))
- {
- invalid_data:
- __libdw_seterrno (DWARF_E_INVALID_DEBUG_LINE);
- goto out;
- }
- Dwarf_Word unit_length = read_4ubyte_unaligned_inc (dbg, linep);
- unsigned int length = 4;
- if (unlikely (unit_length == DWARF3_LENGTH_64_BIT))
- {
- if (unlikely (linep + 8 > lineendp))
- goto invalid_data;
- unit_length = read_8ubyte_unaligned_inc (dbg, linep);
- length = 8;
- }
+ __libdw_seterrno (DWARF_E_VERSION);
+ return -1;
+ }
+
+ /* Next comes the header length. */
+ Dwarf_Word header_length;
+ if (length == 4)
+ header_length = read_4ubyte_unaligned_inc (dbg, linep);
+ else
+ header_length = read_8ubyte_unaligned_inc (dbg, linep);
+ const unsigned char *header_start = linep;
+
+ /* Next the minimum instruction length. */
+ uint_fast8_t minimum_instr_len = *linep++;
+
+ /* Then the flag determining the default value of the is_stmt
+ register. */
+ uint_fast8_t default_is_stmt = *linep++;
+
+ /* Now the line base. */
+ int_fast8_t line_base = *((int_fast8_t *) linep);
+ ++linep;
+
+ /* And the line range. */
+ uint_fast8_t line_range = *linep++;
+
+ /* The opcode base. */
+ uint_fast8_t opcode_base = *linep++;
+
+ /* Remember array with the standard opcode length (-1 to account for
+ the opcode with value zero not being mentioned). */
+ const uint8_t *standard_opcode_lengths = linep - 1;
+ linep += opcode_base - 1;
+ if (unlikely (linep >= lineendp))
+ goto invalid_data;
+
+ /* First comes the list of directories. Add the compilation
+ directory first since the index zero is used for it. */
+ struct dirlist
+ {
+ const char *dir;
+ size_t len;
+ struct dirlist *next;
+ } comp_dir_elem =
+ {
+ .dir = comp_dir,
+ .len = comp_dir ? strlen (comp_dir) : 0,
+ .next = NULL
+ };
+ struct dirlist *dirlist = &comp_dir_elem;
+ unsigned int ndirlist = 1;
+
+ // XXX Directly construct array to conserve memory?
+ while (*linep != 0)
+ {
+ struct dirlist *new_dir =
+ (struct dirlist *) alloca (sizeof (*new_dir));
- /* Check whether we have enough room in the section. */
- if (unit_length < 2 + length + 5 * 1
- || unlikely (linep + unit_length > lineendp))
+ new_dir->dir = (char *) linep;
+ uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+ if (endp == NULL)
goto invalid_data;
- lineendp = linep + unit_length;
+ new_dir->len = endp - linep;
+ new_dir->next = dirlist;
+ dirlist = new_dir;
+ ++ndirlist;
+ linep = endp + 1;
+ }
+ /* Skip the final NUL byte. */
+ ++linep;
+
+ /* Rearrange the list in array form. */
+ struct dirlist **dirarray
+ = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray));
+ for (unsigned int n = ndirlist; n-- > 0; dirlist = dirlist->next)
+ dirarray[n] = dirlist;
- /* The next element of the header is the version identifier. */
- uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, linep);
- if (unlikely (version > DWARF_VERSION))
+ /* Now read the files. */
+ struct filelist null_file =
+ {
+ .info =
+ {
+ .name = "???",
+ .mtime = 0,
+ .length = 0
+ },
+ .next = NULL
+ };
+ struct filelist *filelist = &null_file;
+ unsigned int nfilelist = 1;
+
+ if (unlikely (linep >= lineendp))
+ goto invalid_data;
+ while (*linep != 0)
+ {
+ struct filelist *new_file =
+ (struct filelist *) alloca (sizeof (*new_file));
+
+ /* First comes the file name. */
+ char *fname = (char *) linep;
+ uint8_t *endp = memchr (fname, '\0', lineendp - linep);
+ if (endp == NULL)
+ goto invalid_data;
+ size_t fnamelen = endp - (uint8_t *) fname;
+ linep = endp + 1;
+
+ /* Then the index. */
+ Dwarf_Word diridx;
+ get_uleb128 (diridx, linep);
+ if (unlikely (diridx >= ndirlist))
{
- __libdw_seterrno (DWARF_E_VERSION);
- goto out;
+ __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
+ return -1;
}
- /* Next comes the header length. */
- Dwarf_Word header_length;
- if (length == 4)
- header_length = read_4ubyte_unaligned_inc (dbg, linep);
+ if (*fname == '/')
+ /* It's an absolute path. */
+ new_file->info.name = fname;
else
- header_length = read_8ubyte_unaligned_inc (dbg, linep);
- const unsigned char *header_start = linep;
+ {
+ new_file->info.name = libdw_alloc (dbg, char, 1,
+ dirarray[diridx]->len + 1
+ + fnamelen + 1);
+ char *cp = new_file->info.name;
- /* Next the minimum instruction length. */
- uint_fast8_t minimum_instr_len = *linep++;
+ if (dirarray[diridx]->dir != NULL)
+ {
+ /* This value could be NULL in case the DW_AT_comp_dir
+ was not present. We cannot do much in this case.
+ The easiest thing is to convert the path in an
+ absolute path. */
+ cp = stpcpy (cp, dirarray[diridx]->dir);
+ }
+ *cp++ = '/';
+ strcpy (cp, fname);
+ assert (strlen (new_file->info.name)
+ < dirarray[diridx]->len + 1 + fnamelen + 1);
+ }
- /* Then the flag determining the default value of the is_stmt
- register. */
- uint_fast8_t default_is_stmt = *linep++;
+ /* Next comes the modification time. */
+ get_uleb128 (new_file->info.mtime, linep);
- /* Now the line base. */
- int_fast8_t line_base = *((int_fast8_t *) linep);
- ++linep;
+ /* Finally the length of the file. */
+ get_uleb128 (new_file->info.length, linep);
+
+ new_file->next = filelist;
+ filelist = new_file;
+ ++nfilelist;
+ }
+ /* Skip the final NUL byte. */
+ ++linep;
- /* And the line range. */
- uint_fast8_t line_range = *linep++;
+ /* Consistency check. */
+ if (unlikely (linep != header_start + header_length))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
- /* The opcode base. */
- uint_fast8_t opcode_base = *linep++;
+ /* We are about to process the statement program. Initialize the
+ state machine registers (see 6.2.2 in the v2.1 specification). */
+ Dwarf_Word address = 0;
+ size_t file = 1;
+ size_t line = 1;
+ size_t column = 0;
+ uint_fast8_t is_stmt = default_is_stmt;
+ int basic_block = 0;
+ int prologue_end = 0;
+ int epilogue_begin = 0;
+
+ /* Process the instructions. */
+ struct linelist *linelist = NULL;
+ unsigned int nlinelist = 0;
+ while (linep < lineendp)
+ {
+ struct linelist *new_line;
+ unsigned int opcode;
+ unsigned int u128;
+ int s128;
- /* Remember array with the standard opcode length (-1 to account for
- the opcode with value zero not being mentioned). */
- const uint8_t *standard_opcode_lengths = linep - 1;
- linep += opcode_base - 1;
- if (unlikely (linep >= lineendp))
- goto invalid_data;
+ /* Read the opcode. */
+ opcode = *linep++;
- /* First comes the list of directories. Add the compilation
- directory first since the index zero is used for it. */
- struct dirlist
- {
- const char *dir;
- size_t len;
- struct dirlist *next;
- } comp_dir_elem =
+ /* Is this a special opcode? */
+ if (likely (opcode >= opcode_base))
{
- .dir = comp_dir,
- .len = comp_dir ? strlen (comp_dir) : 0,
- .next = NULL
- };
- struct dirlist *dirlist = &comp_dir_elem;
- unsigned int ndirlist = 1;
-
- // XXX Directly construct array to conserve memory?
- while (*linep != 0)
+ /* Yes. Handling this is quite easy since the opcode value
+ is computed with
+
+ opcode = (desired line increment - line_base)
+ + (line_range * address advance) + opcode_base
+ */
+ int line_increment = (line_base
+ + (opcode - opcode_base) % line_range);
+ unsigned int address_increment = (minimum_instr_len
+ * ((opcode - opcode_base)
+ / line_range));
+
+ /* Perform the increments. */
+ line += line_increment;
+ address += address_increment;
+
+ /* Add a new line with the current state machine values. */
+ NEW_LINE (0);
+
+ /* Reset the flags. */
+ basic_block = 0;
+ prologue_end = 0;
+ epilogue_begin = 0;
+ }
+ else if (opcode == 0)
{
- struct dirlist *new_dir =
- (struct dirlist *) alloca (sizeof (*new_dir));
-
- new_dir->dir = (char *) linep;
- uint8_t *endp = memchr (linep, '\0', lineendp - linep);
- if (endp == NULL)
+ /* This an extended opcode. */
+ if (unlikely (linep + 2 > lineendp))
goto invalid_data;
- new_dir->len = endp - linep;
- new_dir->next = dirlist;
- dirlist = new_dir;
- ++ndirlist;
- linep = endp + 1;
- }
- /* Skip the final NUL byte. */
- ++linep;
- /* Rearrange the list in array form. */
- struct dirlist **dirarray
- = (struct dirlist **) alloca (ndirlist * sizeof (*dirarray));
- for (unsigned int n = ndirlist; n-- > 0; dirlist = dirlist->next)
- dirarray[n] = dirlist;
+ /* The length. */
+ unsigned int len = *linep++;
- /* Now read the files. */
- struct filelist null_file =
- {
- .info =
- {
- .name = "???",
- .mtime = 0,
- .length = 0
- },
- .next = NULL
- };
- struct filelist *filelist = &null_file;
- unsigned int nfilelist = 1;
-
- if (unlikely (linep >= lineendp))
- goto invalid_data;
- while (*linep != 0)
- {
- struct filelist *new_file =
- (struct filelist *) alloca (sizeof (*new_file));
-
- /* First comes the file name. */
- char *fname = (char *) linep;
- uint8_t *endp = memchr (fname, '\0', lineendp - linep);
- if (endp == NULL)
+ if (unlikely (linep + len > lineendp))
goto invalid_data;
- size_t fnamelen = endp - (uint8_t *) fname;
- linep = endp + 1;
- /* Then the index. */
- Dwarf_Word diridx;
- get_uleb128 (diridx, linep);
- if (unlikely (diridx >= ndirlist))
- {
- __libdw_seterrno (DWARF_E_INVALID_DIR_IDX);
- goto out;
- }
+ /* The sub-opcode. */
+ opcode = *linep++;
- if (*fname == '/')
- /* It's an absolute path. */
- new_file->info.name = fname;
- else
+ switch (opcode)
{
- new_file->info.name = libdw_alloc (dbg, char, 1,
- dirarray[diridx]->len + 1
- + fnamelen + 1);
- char *cp = new_file->info.name;
-
- if (dirarray[diridx]->dir != NULL)
- {
- /* This value could be NULL in case the DW_AT_comp_dir
- was not present. We cannot do much in this case.
- The easiest thing is to convert the path in an
- absolute path. */
- cp = stpcpy (cp, dirarray[diridx]->dir);
- }
- *cp++ = '/';
- strcpy (cp, fname);
- assert (strlen (new_file->info.name)
- < dirarray[diridx]->len + 1 + fnamelen + 1);
- }
-
- /* Next comes the modification time. */
- get_uleb128 (new_file->info.mtime, linep);
-
- /* Finally the length of the file. */
- get_uleb128 (new_file->info.length, linep);
-
- new_file->next = filelist;
- filelist = new_file;
- ++nfilelist;
- }
- /* Skip the final NUL byte. */
- ++linep;
+ case DW_LNE_end_sequence:
+ /* Add a new line with the current state machine values.
+ The is the end of the sequence. */
+ NEW_LINE (1);
+
+ /* Reset the registers. */
+ address = 0;
+ file = 1;
+ line = 1;
+ column = 0;
+ is_stmt = default_is_stmt;
+ basic_block = 0;
+ prologue_end = 0;
+ epilogue_begin = 0;
+ break;
+
+ case DW_LNE_set_address:
+ /* The value is an address. The size is defined as
+ apporiate for the target machine. We use the
+ address size field from the CU header. */
+ if (cu->address_size == 4)
+ address = read_4ubyte_unaligned_inc (dbg, linep);
+ else
+ address = read_8ubyte_unaligned_inc (dbg, linep);
+ break;
+
+ case DW_LNE_define_file:
+ {
+ char *fname = (char *) linep;
+ uint8_t *endp = memchr (linep, '\0', lineendp - linep);
+ if (endp == NULL)
+ goto invalid_data;
+ size_t fnamelen = endp - linep;
+ linep = endp + 1;
+
+ unsigned int diridx;
+ get_uleb128 (diridx, linep);
+ Dwarf_Word mtime;
+ get_uleb128 (mtime, linep);
+ Dwarf_Word filelength;
+ get_uleb128 (filelength, linep);
+
+ struct filelist *new_file =
+ (struct filelist *) alloca (sizeof (*new_file));
+ if (fname[0] == '/')
+ new_file->info.name = fname;
+ else
+ {
+ new_file->info.name =
+ libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1
+ + fnamelen + 1));
+ char *cp = new_file->info.name;
+
+ if (dirarray[diridx]->dir != NULL)
+ /* This value could be NULL in case the
+ DW_AT_comp_dir was not present. We
+ cannot do much in this case. The easiest
+ thing is to convert the path in an
+ absolute path. */
+ cp = stpcpy (cp, dirarray[diridx]->dir);
+ *cp++ = '/';
+ strcpy (cp, fname);
+ }
- /* Consistency check. */
- if (unlikely (linep != header_start + header_length))
- {
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- goto out;
+ new_file->info.mtime = mtime;
+ new_file->info.length = filelength;
+ new_file->next = filelist;
+ filelist = new_file;
+ ++nfilelist;
+ }
+ break;
+
+ default:
+ /* Unknown, ignore it. */
+ linep += len - 1;
+ break;
+ }
}
-
- /* We are about to process the statement program. Initialize the
- state machine registers (see 6.2.2 in the v2.1 specification). */
- Dwarf_Word address = 0;
- size_t file = 1;
- size_t line = 1;
- size_t column = 0;
- uint_fast8_t is_stmt = default_is_stmt;
- int basic_block = 0;
- int prologue_end = 0;
- int epilogue_begin = 0;
-
- /* Process the instructions. */
- struct linelist *linelist = NULL;
- unsigned int nlinelist = 0;
- while (linep < lineendp)
+ else if (opcode <= DW_LNS_set_epilogue_begin)
{
- struct linelist *new_line;
- unsigned int opcode;
- unsigned int u128;
- int s128;
-
- /* Read the opcode. */
- opcode = *linep++;
-
- /* Is this a special opcode? */
- if (likely (opcode >= opcode_base))
+ /* This is a known standard opcode. */
+ switch (opcode)
{
- /* Yes. Handling this is quite easy since the opcode value
- is computed with
-
- opcode = (desired line increment - line_base)
- + (line_range * address advance) + opcode_base
- */
- int line_increment = (line_base
- + (opcode - opcode_base) % line_range);
- unsigned int address_increment = (minimum_instr_len
- * ((opcode - opcode_base)
- / line_range));
-
- /* Perform the increments. */
- line += line_increment;
- address += address_increment;
+ case DW_LNS_copy:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
/* Add a new line with the current state machine values. */
NEW_LINE (0);
/* Reset the flags. */
basic_block = 0;
+ /* XXX Whether the following two lines are necessary is
+ unclear. I guess the current v2.1 specification has
+ a bug in that it says clearing these two registers is
+ not necessary. */
prologue_end = 0;
epilogue_begin = 0;
- }
- else if (opcode == 0)
- {
- /* This an extended opcode. */
- if (unlikely (linep + 2 > lineendp))
+ break;
+
+ case DW_LNS_advance_pc:
+ /* Takes one uleb128 parameter which is added to the
+ address. */
+ if (unlikely (standard_opcode_lengths[opcode] != 1))
goto invalid_data;
- /* The length. */
- unsigned int len = *linep++;
+ get_uleb128 (u128, linep);
+ address += minimum_instr_len * u128;
+ break;
- if (unlikely (linep + len > lineendp))
+ case DW_LNS_advance_line:
+ /* Takes one sleb128 parameter which is added to the
+ line. */
+ if (unlikely (standard_opcode_lengths[opcode] != 1))
goto invalid_data;
- /* The sub-opcode. */
- opcode = *linep++;
-
- switch (opcode)
- {
- case DW_LNE_end_sequence:
- /* Add a new line with the current state machine values.
- The is the end of the sequence. */
- NEW_LINE (1);
-
- /* Reset the registers. */
- address = 0;
- file = 1;
- line = 1;
- column = 0;
- is_stmt = default_is_stmt;
- basic_block = 0;
- prologue_end = 0;
- epilogue_begin = 0;
- break;
-
- case DW_LNE_set_address:
- /* The value is an address. The size is defined as
- apporiate for the target machine. We use the
- address size field from the CU header. */
- if (cu->address_size == 4)
- address = read_4ubyte_unaligned_inc (dbg, linep);
- else
- address = read_8ubyte_unaligned_inc (dbg, linep);
- break;
-
- case DW_LNE_define_file:
- {
- char *fname = (char *) linep;
- uint8_t *endp = memchr (linep, '\0', lineendp - linep);
- if (endp == NULL)
- goto invalid_data;
- size_t fnamelen = endp - linep;
- linep = endp + 1;
-
- unsigned int diridx;
- get_uleb128 (diridx, linep);
- Dwarf_Word mtime;
- get_uleb128 (mtime, linep);
- Dwarf_Word filelength;
- get_uleb128 (filelength, linep);
-
- struct filelist *new_file =
- (struct filelist *) alloca (sizeof (*new_file));
- if (fname[0] == '/')
- new_file->info.name = fname;
- else
- {
- new_file->info.name =
- libdw_alloc (dbg, char, 1, (dirarray[diridx]->len + 1
- + fnamelen + 1));
- char *cp = new_file->info.name;
-
- if (dirarray[diridx]->dir != NULL)
- /* This value could be NULL in case the
- DW_AT_comp_dir was not present. We
- cannot do much in this case. The easiest
- thing is to convert the path in an
- absolute path. */
- cp = stpcpy (cp, dirarray[diridx]->dir);
- *cp++ = '/';
- strcpy (cp, fname);
- }
-
- new_file->info.mtime = mtime;
- new_file->info.length = filelength;
- new_file->next = filelist;
- filelist = new_file;
- ++nfilelist;
- }
- break;
+ get_sleb128 (s128, linep);
+ line += s128;
+ break;
- default:
- /* Unknown, ignore it. */
- linep += len - 1;
- break;
- }
- }
- else if (opcode <= DW_LNS_set_epilogue_begin)
- {
- /* This is a known standard opcode. */
- switch (opcode)
- {
- case DW_LNS_copy:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- /* Add a new line with the current state machine values. */
- NEW_LINE (0);
-
- /* Reset the flags. */
- basic_block = 0;
- /* XXX Whether the following two lines are necessary is
- unclear. I guess the current v2.1 specification has
- a bug in that it says clearing these two registers is
- not necessary. */
- prologue_end = 0;
- epilogue_begin = 0;
- break;
-
- case DW_LNS_advance_pc:
- /* Takes one uleb128 parameter which is added to the
- address. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
-
- get_uleb128 (u128, linep);
- address += minimum_instr_len * u128;
- break;
-
- case DW_LNS_advance_line:
- /* Takes one sleb128 parameter which is added to the
- line. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
-
- get_sleb128 (s128, linep);
- line += s128;
- break;
-
- case DW_LNS_set_file:
- /* Takes one uleb128 parameter which is stored in file. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
-
- get_uleb128 (u128, linep);
- file = u128;
- break;
-
- case DW_LNS_set_column:
- /* Takes one uleb128 parameter which is stored in column. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
-
- get_uleb128 (u128, linep);
- column = u128;
- break;
-
- case DW_LNS_negate_stmt:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- is_stmt = 1 - is_stmt;
- break;
-
- case DW_LNS_set_basic_block:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- basic_block = 1;
- break;
-
- case DW_LNS_const_add_pc:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- address += (minimum_instr_len
- * ((255 - opcode_base) / line_range));
- break;
-
- case DW_LNS_fixed_advance_pc:
- /* Takes one 16 bit parameter which is added to the
- address. */
- if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
-
- address += read_2ubyte_unaligned_inc (dbg, linep);
- break;
-
- case DW_LNS_set_prologue_end:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- prologue_end = 1;
- break;
-
- case DW_LNS_set_epilogue_begin:
- /* Takes no argument. */
- if (unlikely (standard_opcode_lengths[opcode] != 0))
- goto invalid_data;
-
- epilogue_begin = 1;
- break;
- }
- }
- else
- {
- /* This is a new opcode the generator but not we know about.
- Read the parameters associated with it but then discard
- everything. Read all the parameters for this opcode. */
- for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
- get_uleb128 (u128, linep);
-
- /* Next round, ignore this opcode. */
- continue;
- }
- }
+ case DW_LNS_set_file:
+ /* Takes one uleb128 parameter which is stored in file. */
+ if (unlikely (standard_opcode_lengths[opcode] != 1))
+ goto invalid_data;
- /* Put all the files in an array. */
- Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
- sizeof (Dwarf_Files)
- + nfilelist * sizeof (Dwarf_Fileinfo)
- + (ndirlist + 1) * sizeof (char *),
- 1);
- const char **dirs = (void *) &files->info[nfilelist];
+ get_uleb128 (u128, linep);
+ file = u128;
+ break;
- files->nfiles = nfilelist;
- while (nfilelist-- > 0)
- {
- files->info[nfilelist] = filelist->info;
- filelist = filelist->next;
+ case DW_LNS_set_column:
+ /* Takes one uleb128 parameter which is stored in column. */
+ if (unlikely (standard_opcode_lengths[opcode] != 1))
+ goto invalid_data;
+
+ get_uleb128 (u128, linep);
+ column = u128;
+ break;
+
+ case DW_LNS_negate_stmt:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
+
+ is_stmt = 1 - is_stmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
+
+ basic_block = 1;
+ break;
+
+ case DW_LNS_const_add_pc:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
+
+ address += (minimum_instr_len
+ * ((255 - opcode_base) / line_range));
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ /* Takes one 16 bit parameter which is added to the
+ address. */
+ if (unlikely (standard_opcode_lengths[opcode] != 1))
+ goto invalid_data;
+
+ address += read_2ubyte_unaligned_inc (dbg, linep);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
+
+ prologue_end = 1;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ /* Takes no argument. */
+ if (unlikely (standard_opcode_lengths[opcode] != 0))
+ goto invalid_data;
+
+ epilogue_begin = 1;
+ break;
+ }
}
- assert (filelist == NULL);
-
- /* Put all the directory strings in an array. */
- files->ndirs = ndirlist;
- for (unsigned int i = 0; i < ndirlist; ++i)
- dirs[i] = dirarray[i]->dir;
- dirs[ndirlist] = NULL;
-
- /* Remember the debugging descriptor. */
- files->dbg = dbg;
-
- /* Make the file data structure available through the CU. */
- cu->files = files;
-
- void *buf = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines)
- + (sizeof (Dwarf_Line)
- * nlinelist)), 1);
-
- /* First use the buffer for the pointers, and sort the entries.
- We'll write the pointers in the end of the buffer, and then
- copy into the buffer from the beginning so the overlap works. */
- assert (sizeof (Dwarf_Line) >= sizeof (Dwarf_Line *));
- Dwarf_Line **sortlines = (buf + sizeof (Dwarf_Lines)
- + ((sizeof (Dwarf_Line)
- - sizeof (Dwarf_Line *)) * nlinelist));
-
- /* The list is in LIFO order and usually they come in clumps with
- ascending addresses. So fill from the back to probably start with
- runs already in order before we sort. */
- unsigned int i = nlinelist;
- while (i-- > 0)
+ else
{
- sortlines[i] = &linelist->line;
- linelist = linelist->next;
+ /* This is a new opcode the generator but not we know about.
+ Read the parameters associated with it but then discard
+ everything. Read all the parameters for this opcode. */
+ for (int n = standard_opcode_lengths[opcode]; n > 0; --n)
+ get_uleb128 (u128, linep);
+
+ /* Next round, ignore this opcode. */
+ continue;
}
- assert (linelist == NULL);
+ }
- /* Sort by ascending address. */
- qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines);
+ /* Put all the files in an array. */
+ Dwarf_Files *files = libdw_alloc (dbg, Dwarf_Files,
+ sizeof (Dwarf_Files)
+ + nfilelist * sizeof (Dwarf_Fileinfo)
+ + (ndirlist + 1) * sizeof (char *),
+ 1);
+ const char **dirs = (void *) &files->info[nfilelist];
- /* Now that they are sorted, put them in the final array.
- The buffers overlap, so we've clobbered the early elements
- of SORTLINES by the time we're reading the later ones. */
- cu->lines = buf;
- cu->lines->nlines = nlinelist;
- for (i = 0; i < nlinelist; ++i)
- {
- cu->lines->info[i] = *sortlines[i];
- cu->lines->info[i].files = files;
- }
+ files->nfiles = nfilelist;
+ while (nfilelist-- > 0)
+ {
+ files->info[nfilelist] = filelist->info;
+ filelist = filelist->next;
+ }
+ assert (filelist == NULL);
+
+ /* Put all the directory strings in an array. */
+ files->ndirs = ndirlist;
+ for (unsigned int i = 0; i < ndirlist; ++i)
+ dirs[i] = dirarray[i]->dir;
+ dirs[ndirlist] = NULL;
+
+ /* Remember the debugging descriptor. */
+ files->dbg = dbg;
+
+ /* Make the file data structure available through the CU. */
+ cu->files = files;
+
+ void *buf = libdw_alloc (dbg, Dwarf_Lines, (sizeof (Dwarf_Lines)
+ + (sizeof (Dwarf_Line)
+ * nlinelist)), 1);
+
+ /* First use the buffer for the pointers, and sort the entries.
+ We'll write the pointers in the end of the buffer, and then
+ copy into the buffer from the beginning so the overlap works. */
+ assert (sizeof (Dwarf_Line) >= sizeof (Dwarf_Line *));
+ Dwarf_Line **sortlines = (buf + sizeof (Dwarf_Lines)
+ + ((sizeof (Dwarf_Line)
+ - sizeof (Dwarf_Line *)) * nlinelist));
+
+ /* The list is in LIFO order and usually they come in clumps with
+ ascending addresses. So fill from the back to probably start with
+ runs already in order before we sort. */
+ unsigned int i = nlinelist;
+ while (i-- > 0)
+ {
+ sortlines[i] = &linelist->line;
+ linelist = linelist->next;
+ }
+ assert (linelist == NULL);
+
+ /* Sort by ascending address. */
+ qsort (sortlines, nlinelist, sizeof sortlines[0], &compare_lines);
- /* Success. */
- res = 0;
+ /* Now that they are sorted, put them in the final array.
+ The buffers overlap, so we've clobbered the early elements
+ of SORTLINES by the time we're reading the later ones. */
+ cu->lines = buf;
+ cu->lines->nlines = nlinelist;
+ for (i = 0; i < nlinelist; ++i)
+ {
+ cu->lines->info[i] = *sortlines[i];
+ cu->lines->info[i].files = files;
}
+
+ /* Success. */
+ return 0;
+}
+
+int internal_function
+__libdw_getsrclines_wrlock (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
+{
+ int res = -1;
+ struct Dwarf_CU *const cu = cudie->cu;
+
+ /* Get the information if it is not already known. */
+ if (cu->lines == NULL)
+ res = getsrclines (cudie);
else if (cu->lines != (void *) -1l)
/* We already have the information. */
res = 0;
@@ -689,10 +693,44 @@ dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
*lines = cu->lines;
*nlines = cu->lines->nlines;
}
- out:
-
- // XXX Eventually: unlocking here.
return res;
}
+
+int internal_function
+__libdw_getsrclines_rdlock (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
+{
+ struct Dwarf_CU *const cu = cudie->cu;
+
+ if (cu->lines == NULL)
+ {
+ rwlock_unlock (cu->dbg->lock);
+ rwlock_wrlock (cu->dbg->lock);
+ }
+
+ return __libdw_getsrclines_wrlock (cudie, lines, nlines);
+}
+
+int
+dwarf_getsrclines (Dwarf_Die *cudie, Dwarf_Lines **lines, size_t *nlines)
+{
+ if (unlikely (cudie == NULL
+ || INTUSE(dwarf_tag) (cudie) != DW_TAG_compile_unit))
+ return -1;
+
+ struct Dwarf_CU *const cu = cudie->cu;
+
+ /* Get write lock if we didn't (attempt to) load the lines yet. */
+ if (cu->lines == NULL)
+ rwlock_wrlock (cu->dbg->lock);
+ else
+ rwlock_rdlock (cu->dbg->lock);
+
+ /* We have the strongest lock necessary, so just call _wrlock. */
+ int retval = __libdw_getsrclines_wrlock (cudie, lines, nlines);
+
+ rwlock_unlock (cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_getsrclines)
diff --git a/libdw/dwarf_hasattr.c b/libdw/dwarf_hasattr.c
index b1c4292a..1ea0d526 100644
--- a/libdw/dwarf_hasattr.c
+++ b/libdw/dwarf_hasattr.c
@@ -57,7 +57,7 @@
int
-dwarf_hasattr (die, search_name)
+__libdw_hasattr_rdlock (die, search_name)
Dwarf_Die *die;
unsigned int search_name;
{
@@ -66,8 +66,23 @@ dwarf_hasattr (die, search_name)
/* Search for the attribute with the given name. */
unsigned int code;
- (void) __libdw_find_attr (die, search_name, &code, NULL);
+ (void) __libdw_find_attr_rdlock (die, search_name, &code, NULL);
return code == search_name;
}
+
+int
+dwarf_hasattr (die, search_name)
+ Dwarf_Die *die;
+ unsigned int search_name;
+{
+ if (die == NULL)
+ return 0;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_hasattr_rdlock (die, search_name);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
+}
INTDEF (dwarf_hasattr)
diff --git a/libdw/dwarf_haschildren.c b/libdw/dwarf_haschildren.c
index fe431955..fa9892f4 100644
--- a/libdw/dwarf_haschildren.c
+++ b/libdw/dwarf_haschildren.c
@@ -57,12 +57,11 @@
int
-dwarf_haschildren (die)
+__libdw_haschildren_rdlock (die)
Dwarf_Die *die;
{
/* Find the abbreviation entry. */
- Dwarf_Abbrev *abbrevp = die->abbrev;
- if (abbrevp != DWARF_END_ABBREV)
+ if (die->abbrev != DWARF_END_ABBREV)
{
const unsigned char *readp = (unsigned char *) die->addr;
@@ -71,7 +70,7 @@ dwarf_haschildren (die)
unsigned int abbrev_code;
get_uleb128 (abbrev_code, readp);
- abbrevp = __libdw_findabbrev (die->cu, abbrev_code);
+ Dwarf_Abbrev *abbrevp = __libdw_findabbrev (die->cu, abbrev_code);
die->abbrev = abbrevp ?: DWARF_END_ABBREV;
}
if (unlikely (die->abbrev == DWARF_END_ABBREV))
@@ -82,4 +81,15 @@ dwarf_haschildren (die)
return die->abbrev->has_children;
}
+
+int
+dwarf_haschildren (die)
+ Dwarf_Die *die;
+{
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_haschildren_rdlock (die);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
+}
INTDEF (dwarf_haschildren)
diff --git a/libdw/dwarf_haspc.c b/libdw/dwarf_haspc.c
index 58b87b65..599631f2 100644
--- a/libdw/dwarf_haspc.c
+++ b/libdw/dwarf_haspc.c
@@ -56,7 +56,7 @@
int
-dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc)
+__libdw_haspc_rdlock (Dwarf_Die *die, Dwarf_Addr pc)
{
if (die == NULL)
return -1;
@@ -65,11 +65,24 @@ dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc)
Dwarf_Addr begin;
Dwarf_Addr end;
ptrdiff_t offset = 0;
- while ((offset = INTUSE(dwarf_ranges) (die, offset, &base,
- &begin, &end)) > 0)
+ while ((offset = __libdw_ranges_rdlock (die, offset, &base,
+ &begin, &end)) > 0)
if (pc >= begin && pc < end)
return 1;
return offset;
}
+
+int
+dwarf_haspc (Dwarf_Die *die, Dwarf_Addr pc)
+{
+ if (die == NULL)
+ return -1;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_haspc_rdlock (die, pc);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
+}
INTDEF (dwarf_haspc)
diff --git a/libdw/dwarf_highpc.c b/libdw/dwarf_highpc.c
index c88e0721..28ca119b 100644
--- a/libdw/dwarf_highpc.c
+++ b/libdw/dwarf_highpc.c
@@ -55,16 +55,26 @@
#include <dwarf.h>
#include "libdwP.h"
+int
+__libdw_highpc_rdlock (die, return_addr)
+ Dwarf_Die *die;
+ Dwarf_Addr *return_addr;
+{
+ Dwarf_Attribute attr_mem;
+ return __libdw_formaddr_rdlock (__libdw_attr_rdlock (die, DW_AT_high_pc,
+ &attr_mem),
+ return_addr);
+}
int
dwarf_highpc (die, return_addr)
Dwarf_Die *die;
Dwarf_Addr *return_addr;
{
- Dwarf_Attribute attr_mem;
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_highpc_rdlock (die, return_addr);
+ rwlock_unlock (die->cu->dbg->lock);
- return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_high_pc,
- &attr_mem),
- return_addr);
+ return retval;
}
INTDEF(dwarf_highpc)
diff --git a/libdw/dwarf_lowpc.c b/libdw/dwarf_lowpc.c
index 97ece031..0f8d6884 100644
--- a/libdw/dwarf_lowpc.c
+++ b/libdw/dwarf_lowpc.c
@@ -57,14 +57,25 @@
int
-dwarf_lowpc (die, return_addr)
+__libdw_lowpc_rdlock (die, return_addr)
Dwarf_Die *die;
Dwarf_Addr *return_addr;
{
Dwarf_Attribute attr_mem;
+ return __libdw_formaddr_rdlock (__libdw_attr_rdlock (die, DW_AT_low_pc,
+ &attr_mem),
+ return_addr);
+}
+
+int
+dwarf_lowpc (die, return_addr)
+ Dwarf_Die *die;
+ Dwarf_Addr *return_addr;
+{
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_lowpc_rdlock (die, return_addr);
+ rwlock_unlock (die->cu->dbg->lock);
- return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_mem),
- return_addr);
+ return retval;
}
INTDEF(dwarf_lowpc)
diff --git a/libdw/dwarf_nextcu.c b/libdw/dwarf_nextcu.c
index 9e5a96bc..3383c8fd 100644
--- a/libdw/dwarf_nextcu.c
+++ b/libdw/dwarf_nextcu.c
@@ -57,8 +57,8 @@
int
-dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
- address_sizep, offset_sizep)
+__libdw_nextcu_rdlock (dwarf, off, next_off, header_sizep, abbrev_offsetp,
+ address_sizep, offset_sizep)
Dwarf *dwarf;
Dwarf_Off off;
Dwarf_Off *next_off;
@@ -172,4 +172,28 @@ dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
return 0;
}
+
+int
+dwarf_nextcu (dwarf, off, next_off, header_sizep, abbrev_offsetp,
+ address_sizep, offset_sizep)
+ Dwarf *dwarf;
+ Dwarf_Off off;
+ Dwarf_Off *next_off;
+ size_t *header_sizep;
+ Dwarf_Off *abbrev_offsetp;
+ uint8_t *address_sizep;
+ uint8_t *offset_sizep;
+{
+ /* Maybe there has been an error before. */
+ if (dwarf == NULL)
+ return -1;
+
+ rwlock_rdlock (dwarf->lock);
+ int retval = __libdw_nextcu_rdlock (dwarf, off, next_off, header_sizep,
+ abbrev_offsetp, address_sizep,
+ offset_sizep);
+ rwlock_unlock (dwarf->lock);
+
+ return retval;
+}
INTDEF(dwarf_nextcu)
diff --git a/libdw/dwarf_offabbrev.c b/libdw/dwarf_offabbrev.c
index 2cac2794..953c40e2 100644
--- a/libdw/dwarf_offabbrev.c
+++ b/libdw/dwarf_offabbrev.c
@@ -62,8 +62,10 @@ dwarf_offabbrev (Dwarf *dbg, Dwarf_Off offset, size_t *lengthp,
if (dbg == NULL)
return -1;
+ rwlock_rdlock (dbg->lock);
Dwarf_Abbrev *abbrev = __libdw_getabbrev (dbg, NULL, offset, lengthp,
abbrevp);
+ rwlock_unlock (dbg->lock);
if (abbrev == NULL)
return -1;
diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c
index a9886f2c..f08c09a0 100644
--- a/libdw/dwarf_offdie.c
+++ b/libdw/dwarf_offdie.c
@@ -57,7 +57,7 @@
Dwarf_Die *
-dwarf_offdie (dbg, offset, result)
+__libdw_offdie_rdlock (dbg, offset, result)
Dwarf *dbg;
Dwarf_Off offset;
Dwarf_Die *result;
@@ -78,7 +78,7 @@ dwarf_offdie (dbg, offset, result)
result->addr = (char *) dbg->sectiondata[IDX_debug_info]->d_buf + offset;
/* Get the CU. */
- result->cu = __libdw_findcu (dbg, offset);
+ result->cu = __libdw_findcu_rdlock (dbg, offset);
if (result->cu == NULL)
{
/* This should never happen. The input file is malformed. */
@@ -88,4 +88,21 @@ dwarf_offdie (dbg, offset, result)
return result;
}
+
+Dwarf_Die *
+dwarf_offdie (dbg, offset, result)
+ Dwarf *dbg;
+ Dwarf_Off offset;
+ Dwarf_Die *result;
+{
+ if (dbg == NULL)
+ return NULL;
+
+ rwlock_rdlock (dbg->lock);
+ Dwarf_Die *retval = __libdw_offdie_rdlock (dbg, offset, result);
+ rwlock_unlock (dbg->lock);
+
+ return retval;
+}
+
INTDEF(dwarf_offdie)
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index 89da0af4..d1ca91a6 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -57,16 +57,16 @@
ptrdiff_t
-dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
- Dwarf_Addr *startp, Dwarf_Addr *endp)
+__libdw_ranges_rdlock (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
+ Dwarf_Addr *startp, Dwarf_Addr *endp)
{
if (die == NULL)
return -1;
if (offset == 0
/* Usually there is a single contiguous range. */
- && INTUSE(dwarf_highpc) (die, endp) == 0
- && INTUSE(dwarf_lowpc) (die, startp) == 0)
+ && __libdw_highpc_rdlock (die, endp) == 0
+ && __libdw_lowpc_rdlock (die, startp) == 0)
/* A offset into .debug_ranges will never be 1, it must be at least a
multiple of 4. So we can return 1 as a special case value to mark
there are no ranges to look for on the next call. */
@@ -86,15 +86,17 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
if (offset == 0)
{
+ /* If this could upgrade to wrlock, it would already have
+ happened above after the initial check for offset == 0. */
Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
- &attr_mem);
+ Dwarf_Attribute *attr = __libdw_attr_rdlock (die, DW_AT_ranges,
+ &attr_mem);
if (attr == NULL)
return -1;
/* Must have the form data4 or data8 which act as an offset. */
Dwarf_Word start_offset;
- if (INTUSE(dwarf_formudata) (attr, &start_offset) != 0)
+ if (__libdw_formudata_rdlock (attr, &start_offset) != 0)
return -1;
offset = start_offset;
@@ -108,11 +110,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
the base address could be overridden by DW_AT_entry_pc. It's
been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
for compilation units with discontinuous ranges. */
- if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
- && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
- DW_AT_entry_pc,
- &attr_mem),
- basep) != 0)
+ if (unlikely (__libdw_lowpc_rdlock (&cudie, basep) != 0)
+ && __libdw_formaddr_rdlock (__libdw_attr_rdlock (&cudie,
+ DW_AT_entry_pc,
+ &attr_mem),
+ basep) != 0)
{
if (INTUSE(dwarf_errno) () == 0)
{
@@ -166,4 +168,19 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
*endp = *basep + end;
return readp - (unsigned char *) d->d_buf;
}
+
+
+ptrdiff_t
+dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
+ Dwarf_Addr *startp, Dwarf_Addr *endp)
+{
+ if (die == NULL)
+ return -1;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ ptrdiff_t retval = __libdw_ranges_rdlock (die, offset, basep, startp, endp);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
+}
INTDEF (dwarf_ranges)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index 0d427175..b2ab5326 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -58,7 +58,7 @@
int
-dwarf_siblingof (die, result)
+__libdw_siblingof_rdlock (die, result)
Dwarf_Die *die;
Dwarf_Die *result;
{
@@ -76,6 +76,7 @@ dwarf_siblingof (die, result)
/* Copy of the current DIE. */
Dwarf_Die this_die = *die;
+
/* Temporary attributes we create. */
Dwarf_Attribute sibattr;
/* Copy of the CU in the request. */
@@ -92,13 +93,13 @@ dwarf_siblingof (die, result)
do
{
/* Find the end of the DIE or the sibling attribute. */
- addr = __libdw_find_attr (&this_die, DW_AT_sibling, &sibattr.code,
- &sibattr.form);
+ addr = __libdw_find_attr_rdlock (&this_die, DW_AT_sibling, &sibattr.code,
+ &sibattr.form);
if (sibattr.code == DW_AT_sibling)
{
Dwarf_Off offset;
sibattr.valp = addr;
- if (unlikely (__libdw_formref (&sibattr, &offset) != 0))
+ if (unlikely (__libdw_formref_rdlock (&sibattr, &offset) != 0))
/* Something went wrong. */
return -1;
@@ -158,4 +159,23 @@ dwarf_siblingof (die, result)
return 0;
}
+
+
+int
+dwarf_siblingof (die, result)
+ Dwarf_Die *die;
+ Dwarf_Die *result;
+{
+ /* Ignore previous errors. */
+ if (die == NULL)
+ return -1;
+
+ if (result == NULL)
+ return -1;
+
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_siblingof_rdlock (die, result);
+ rwlock_unlock (die->cu->dbg->lock);
+ return retval;
+}
INTDEF(dwarf_siblingof)
diff --git a/libdw/dwarf_tag.c b/libdw/dwarf_tag.c
index 15183d2d..a721f3d1 100644
--- a/libdw/dwarf_tag.c
+++ b/libdw/dwarf_tag.c
@@ -55,9 +55,8 @@
#include "libdwP.h"
-Dwarf_Abbrev *
-internal_function
-__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
+static Dwarf_Abbrev *
+findabbrev (struct Dwarf_CU *cu, unsigned int code, int wrlocked)
{
Dwarf_Abbrev *abb;
@@ -70,8 +69,10 @@ __libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
/* Find the next entry. It gets automatically added to the
hash table. */
- abb = __libdw_getabbrev (cu->dbg, cu, cu->last_abbrev_offset, &length,
- NULL);
+ abb = (wrlocked
+ ? __libdw_getabbrev_wrlock
+ : __libdw_getabbrev) (cu->dbg, cu, cu->last_abbrev_offset,
+ &length, NULL);
if (abb == NULL || abb == DWARF_END_ABBREV)
{
/* Make sure we do not try to search for it again. */
@@ -89,9 +90,22 @@ __libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
return abb;
}
+Dwarf_Abbrev *
+internal_function
+__libdw_findabbrev_wrlock (struct Dwarf_CU *cu, unsigned int code)
+{
+ return findabbrev (cu, code, 1);
+}
+
+Dwarf_Abbrev *
+internal_function
+__libdw_findabbrev (struct Dwarf_CU *cu, unsigned int code)
+{
+ return findabbrev (cu, code, 0);
+}
int
-dwarf_tag (die)
+__libdw_tag_rdlock (die)
Dwarf_Die *die;
{
/* Do we already know the abbreviation? */
@@ -114,4 +128,16 @@ dwarf_tag (die)
return die->abbrev->tag;
}
+
+
+int
+dwarf_tag (die)
+ Dwarf_Die *die;
+{
+ rwlock_rdlock (die->cu->dbg->lock);
+ int retval = __libdw_tag_rdlock (die);
+ rwlock_unlock (die->cu->dbg->lock);
+
+ return retval;
+}
INTDEF(dwarf_tag)
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index f805295f..6d8c6d80 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -188,6 +188,9 @@ struct Dwarf
/* Registered OOM handler. */
Dwarf_OOM oom_handler;
+
+ /* Lock to handle multithreaded programs. */
+ rwlock_define (,lock);
};
@@ -330,7 +333,8 @@ struct Dwarf_Macro_s
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.
+ Callers need to hold a write lock. */
#define libdw_alloc(dbg, type, tsize, cnt) \
({ struct libdw_memblock *_tail = (dbg)->mem_tail; \
size_t _required = (tsize) * (cnt); \
@@ -348,6 +352,7 @@ extern void __libdw_seterrno (int value) internal_function;
} \
_result; })
+/* Callers need to hold a write lock. */
#define libdw_typed_alloc(dbg, type) \
libdw_alloc (dbg, type, sizeof (type), 1)
@@ -359,36 +364,95 @@ extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden")));
/* Find CU for given offset. */
-extern struct Dwarf_CU *__libdw_findcu (Dwarf *dbg, Dwarf_Off offset)
+extern struct Dwarf_CU *__libdw_findcu_rdlock (Dwarf *dbg, Dwarf_Off offset)
+ __nonnull_attribute__ (1) internal_function;
+
+// XXX Maybe not useful and should be ditched.
+extern struct Dwarf_CU *__libdw_findcu_wrlock (Dwarf *dbg, Dwarf_Off offset)
__nonnull_attribute__ (1) internal_function;
+extern int __libdw_nextcu_rdlock (Dwarf *dwarf, Dwarf_Off off,
+ Dwarf_Off *next_off,
+ size_t *header_sizep,
+ Dwarf_Off *abbrev_offsetp,
+ uint8_t *address_sizep,
+ uint8_t *offset_sizep)
+ __nonnull_attribute__ (3) internal_function;
+
/* Return tag of given DIE. */
+/* May relock via getabbrev. */
extern Dwarf_Abbrev *__libdw_findabbrev (struct Dwarf_CU *cu,
unsigned int code)
__nonnull_attribute__ (1) internal_function;
+extern Dwarf_Abbrev *__libdw_findabbrev_wrlock (struct Dwarf_CU *cu,
+ unsigned int code)
+ __nonnull_attribute__ (1) internal_function;
/* Get abbreviation at given offset. */
+/* XXX perhaps rename to __libdw_getabbrev_rdlock. */
+/* May relock. */
extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
Dwarf_Off offset, size_t *lengthp,
Dwarf_Abbrev *result)
__nonnull_attribute__ (1) internal_function;
+extern Dwarf_Abbrev *__libdw_getabbrev_wrlock (Dwarf *dbg, struct Dwarf_CU *cu,
+ Dwarf_Off offset,
+ size_t *lengthp,
+ Dwarf_Abbrev *result)
+ __nonnull_attribute__ (1) internal_function;
+
/* Helper functions for form handling. */
-extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
- unsigned int form,
- const unsigned char *valp)
+extern size_t __libdw_form_val_len_rdlock (Dwarf *dbg, struct Dwarf_CU *cu,
+ unsigned int form,
+ const unsigned char *valp)
__nonnull_attribute__ (1, 2, 4) internal_function;
-/* Helper function for DW_FORM_ref* handling. */
-extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
- __nonnull_attribute__ (1, 2) internal_function;
-
-
-/* Helper function to locate attribute. */
-extern unsigned char *__libdw_find_attr (Dwarf_Die *die,
- unsigned int search_name,
- unsigned int *codep,
- unsigned int *formp)
+/* Helper function for DW_FORM_* handling. */
+extern int __libdw_formaddr_rdlock (Dwarf_Attribute *attr,
+ Dwarf_Addr *return_addr)
+ __nonnull_attribute__ (2) internal_function;
+
+extern int __libdw_formref_rdlock (Dwarf_Attribute *attr,
+ Dwarf_Off *return_offset)
+ __nonnull_attribute__ (2) internal_function;
+
+extern Dwarf_Die *__libdw_formref_die_rdlock (Dwarf_Attribute *attr,
+ Dwarf_Die *die_mem)
+ __nonnull_attribute__ (2) internal_function;
+
+extern int __libdw_formsdata_rdlock (Dwarf_Attribute *attr,
+ Dwarf_Sword *return_sval)
+ __nonnull_attribute__ (2) internal_function;
+extern int __libdw_formudata_rdlock (Dwarf_Attribute *attr,
+ Dwarf_Word *return_uval)
+ __nonnull_attribute__ (2) internal_function;
+extern const char * __libdw_formstring_rdlock (Dwarf_Attribute *attrp)
+ internal_function;
+
+
+/* Variants of dwarf_attr for cases where caller holds the right lock.
+ Note that _rdlock may need to relock to initialize the cache. */
+extern Dwarf_Attribute *__libdw_attr_rdlock (Dwarf_Die *die,
+ unsigned int search_name,
+ Dwarf_Attribute *result)
+ __nonnull_attribute__ (3) internal_function;
+extern Dwarf_Attribute *__libdw_attr_wrlock (Dwarf_Die *die,
+ unsigned int search_name,
+ Dwarf_Attribute *result)
+
+/* Helper functions to locate attribute.
+ Note that _rdlock may need to relock to initialize the cache. */
+ __nonnull_attribute__ (3) internal_function;
+extern unsigned char *__libdw_find_attr_rdlock (Dwarf_Die *die,
+ unsigned int search_name,
+ unsigned int *codep,
+ unsigned int *formp)
+ __nonnull_attribute__ (1) internal_function;
+extern unsigned char *__libdw_find_attr_wrlock (Dwarf_Die *die,
+ unsigned int search_name,
+ unsigned int *codep,
+ unsigned int *formp)
__nonnull_attribute__ (1) internal_function;
/* Helper function to access integer attribute. */
@@ -402,6 +466,15 @@ struct Dwarf_Die_Chain
struct Dwarf_Die_Chain *parent;
bool prune; /* The PREVISIT function can set this. */
};
+
+/* PREVISIT and POSTVISIT are assumed to relock. Some of them also
+ unlock to hand the control over to external callbacks, and then
+ relock to rdlock (i.e. may actually downgrade the lock). The
+ caller of functions that call visit_scopens have to take this into
+ account, and assume that their wrlock might have been lost, and
+ need to be regained.
+
+ XXX document the above at callers. */
extern int __libdw_visit_scopes (unsigned int depth,
struct Dwarf_Die_Chain *root,
int (*previsit) (unsigned int depth,
@@ -413,6 +486,67 @@ extern int __libdw_visit_scopes (unsigned int depth,
void *arg)
__nonnull_attribute__ (2, 3) internal_function;
+/* Helper function to return DIE at given offset. */
+extern Dwarf_Die *__libdw_offdie_rdlock (Dwarf *dbg, Dwarf_Off offset,
+ Dwarf_Die *result)
+ __nonnull_attribute__ (3) internal_function;
+
+/* Variants of getsrclines if the caller holds the right lock. Note
+ that _rdlock may need to relock to initialize the cache. */
+extern int __libdw_getsrclines_rdlock (Dwarf_Die *cudie,
+ Dwarf_Lines **lines,
+ size_t *nlines)
+ __nonnull_attribute__ (2, 3) internal_function;
+extern int __libdw_getsrclines_wrlock (Dwarf_Die *cudie,
+ Dwarf_Lines **lines,
+ size_t *nlines)
+ __nonnull_attribute__ (2, 3) internal_function;
+
+/* The following three may relock to wrlock via __libdw_attr. */
+extern int __libdw_entrypc_rdlock (Dwarf_Die *die, Dwarf_Addr *return_addr)
+ __nonnull_attribute__ (2) internal_function;
+extern int __libdw_highpc_rdlock (Dwarf_Die *die, Dwarf_Addr *return_addr)
+ __nonnull_attribute__ (2) internal_function;
+extern int __libdw_lowpc_rdlock (Dwarf_Die *die, Dwarf_Addr *return_addr)
+ __nonnull_attribute__ (2) internal_function;
+
+extern int __libdw_formblock_rdlock (Dwarf_Attribute *attr, Dwarf_Block *return_block)
+ __nonnull_attribute__ (2) internal_function;
+
+/* May upgrade lock to _wrlock via dwarf_attr call. */
+extern ptrdiff_t __libdw_ranges_rdlock (Dwarf_Die *die, ptrdiff_t offset,
+ Dwarf_Addr *basep,
+ Dwarf_Addr *startp, Dwarf_Addr *endp)
+ internal_function;
+
+/* May upgrade lock to _wrlock via dwarf_attr call. */
+extern int __libdw_child_rdlock (Dwarf_Die *die, Dwarf_Die *result)
+ __nonnull_attribute__ (2) internal_function;
+
+extern int __libdw_child_wrlock (Dwarf_Die *die, Dwarf_Die *result)
+ __nonnull_attribute__ (2) internal_function;
+
+/* May relock due to find_attr. */
+extern int __libdw_siblingof_rdlock (Dwarf_Die *die, Dwarf_Die *result)
+ __nonnull_attribute__ (2) internal_function;
+
+/* May upgrade lock to _wrlock via dwarf_ranges call. */
+extern int __libdw_haspc_rdlock (Dwarf_Die *die, Dwarf_Addr pc)
+ internal_function;
+
+/* May relock to wrlock via find_attr. */
+extern int __libdw_hasattr_rdlock (Dwarf_Die *die, unsigned int search_name)
+ internal_function;
+
+/* May relock via findabbrev */
+extern int __libdw_haschildren_rdlock (Dwarf_Die *die)
+ internal_function;
+
+/* May relock via findabbrev. */
+extern int __libdw_tag_rdlock (Dwarf_Die *die)
+ __nonnull_attribute__ (1) internal_function;
+
+
/* Return error code of last failing function call. This value is kept
separately for each thread. */
extern int __dwarf_errno_internal (void);
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index afff6d3a..d01beaa8 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -84,10 +84,11 @@ findcu_cb (const void *arg1, const void *arg2)
}
-struct Dwarf_CU *
-__libdw_findcu (dbg, start)
+static struct Dwarf_CU *
+findcu (dbg, start, wrlocked)
Dwarf *dbg;
Dwarf_Off start;
+ int wrlocked;
{
/* Maybe we already know that CU. */
struct Dwarf_CU fake = { .start = start, .end = 0 };
@@ -110,8 +111,8 @@ __libdw_findcu (dbg, start)
uint8_t offset_size;
Dwarf_Off abbrev_offset;
- if (INTUSE(dwarf_nextcu) (dbg, oldoff, &dbg->next_cu_offset, NULL,
- &abbrev_offset, &address_size, &offset_size)
+ if (__libdw_nextcu_rdlock (dbg, oldoff, &dbg->next_cu_offset, NULL,
+ &abbrev_offset, &address_size, &offset_size)
!= 0)
/* No more entries. */
return NULL;
@@ -125,6 +126,14 @@ __libdw_findcu (dbg, start)
if (unlikely (version != 2) && unlikely (version != 3))
goto invalid;
+ /* Relock for memory alloc, if necessary. */
+ if (!wrlocked)
+ {
+ rwlock_unlock (dbg->lock);
+ rwlock_wrlock (dbg->lock);
+ wrlocked = 1;
+ }
+
/* Create an entry for this CU. */
struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
@@ -155,3 +164,19 @@ __libdw_findcu (dbg, start)
}
/* NOTREACHED */
}
+
+struct Dwarf_CU *
+__libdw_findcu_rdlock (dbg, start)
+ Dwarf *dbg;
+ Dwarf_Off start;
+{
+ return findcu (dbg, start, 0);
+}
+
+struct Dwarf_CU *
+__libdw_findcu_wrlock (dbg, start)
+ Dwarf *dbg;
+ Dwarf_Off start;
+{
+ return findcu (dbg, start, 1);
+}
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index ad78f4b4..643af8e0 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -60,8 +60,8 @@
size_t
internal_function
-__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
- const unsigned char *valp)
+__libdw_form_val_len_rdlock (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
+ const unsigned char *valp)
{
const unsigned char *saved;
Dwarf_Word u128;
@@ -136,7 +136,7 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
saved = valp;
get_uleb128 (u128, valp);
// XXX Is this really correct?
- result = __libdw_form_val_len (dbg, cu, u128, valp);
+ result = __libdw_form_val_len_rdlock (dbg, cu, u128, valp);
if (result != (size_t) -1)
result += valp - saved;
break;
diff --git a/libdw/libdw_visit_scopes.c b/libdw/libdw_visit_scopes.c
index 9c7c3789..3e0ce349 100644
--- a/libdw/libdw_visit_scopes.c
+++ b/libdw/libdw_visit_scopes.c
@@ -58,7 +58,7 @@ enum die_class { ignore, match, match_inline, walk, imported };
static enum die_class
classify_die (Dwarf_Die *die)
{
- switch (INTUSE(dwarf_tag) (die))
+ switch (__libdw_tag_rdlock (die))
{
/* DIEs with addresses we can try to match. */
case DW_TAG_compile_unit:
@@ -75,7 +75,9 @@ classify_die (Dwarf_Die *die)
/* This might be a concrete out-of-line instance of an inline, in
which case it is not guaranteed to be owned by the right scope and
we will search for its origin as for DW_TAG_inlined_subroutine. */
- return (INTUSE(dwarf_hasattr) (die, DW_AT_abstract_origin)
+ /* This may relock, but if it would, it would already have
+ happened in __libdw_child call from __libdw_visit_scopes. */
+ return (__libdw_hasattr_rdlock (die, DW_AT_abstract_origin)
? match_inline : match);
/* DIEs without addresses that can own DIEs with addresses. */
@@ -106,7 +108,13 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
struct Dwarf_Die_Chain child;
child.parent = root;
- if (INTUSE(dwarf_child) (&root->die, &child.die) != 0)
+
+ /* This function doesn't have any real state itself. So while some
+ of the following functions may need to relock to upgrade the
+ cache (e.g. __libdw_child_rdlock), or to hand the control over to
+ external callback (e.g. PREVISIT and POSTVISIT), we don't really
+ care. */
+ if (__libdw_child_rdlock (&root->die, &child.die) != 0)
return -1;
inline int recurse (void)
@@ -132,7 +140,9 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
case match:
case match_inline:
case walk:
- if (INTUSE(dwarf_haschildren) (&child.die))
+ /* This may relock, but if it would, it would already have
+ happened above in __libdw_child call. */
+ if (__libdw_haschildren_rdlock (&child.die))
{
int result = recurse ();
if (result != DWARF_CB_OK)
@@ -148,10 +158,9 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
recording it as an inner scoping level. */
Dwarf_Attribute attr_mem;
- Dwarf_Attribute *attr = INTUSE(dwarf_attr) (&child.die,
- DW_AT_import,
- &attr_mem);
- if (INTUSE(dwarf_formref_die) (attr, &child.die) != NULL)
+ Dwarf_Attribute *attr
+ = __libdw_attr_rdlock (&child.die, DW_AT_import, &attr_mem);
+ if (__libdw_formref_die_rdlock (attr, &child.die) != NULL)
{
int result = recurse ();
if (result != DWARF_CB_OK)
@@ -171,7 +180,7 @@ __libdw_visit_scopes (depth, root, previsit, postvisit, arg)
return result;
}
}
- while (INTUSE(dwarf_siblingof) (&child.die, &child.die) == 0);
+ while (__libdw_siblingof_rdlock (&child.die, &child.die) == 0);
return 0;
}