]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Dump com.redhat.elfutils.pmachata.threads from monotone. pmachata/threads
authorPetr Machata <pmachata@redhat.com>
Mon, 15 Dec 2008 14:27:01 +0000 (15:27 +0100)
committerPetr Machata <pmachata@redhat.com>
Mon, 15 Dec 2008 14:27:01 +0000 (15:27 +0100)
44 files changed:
libdw/ChangeLog
libdw/dwarf_attr.c
libdw/dwarf_begin.c
libdw/dwarf_child.c
libdw/dwarf_cuoffset.c
libdw/dwarf_decl_file.c
libdw/dwarf_diecu.c
libdw/dwarf_dieoffset.c
libdw/dwarf_end.c
libdw/dwarf_entry_breakpoints.c
libdw/dwarf_entrypc.c
libdw/dwarf_filesrc.c
libdw/dwarf_formaddr.c
libdw/dwarf_formblock.c
libdw/dwarf_formflag.c
libdw/dwarf_formref.c
libdw/dwarf_formref_die.c
libdw/dwarf_formsdata.c
libdw/dwarf_formstring.c
libdw/dwarf_formudata.c
libdw/dwarf_func_inline.c
libdw/dwarf_getabbrev.c
libdw/dwarf_getattrs.c
libdw/dwarf_getfuncs.c
libdw/dwarf_getmacros.c
libdw/dwarf_getpubnames.c
libdw/dwarf_getscopes.c
libdw/dwarf_getscopes_die.c
libdw/dwarf_getsrclines.c
libdw/dwarf_hasattr.c
libdw/dwarf_haschildren.c
libdw/dwarf_haspc.c
libdw/dwarf_highpc.c
libdw/dwarf_lowpc.c
libdw/dwarf_nextcu.c
libdw/dwarf_offabbrev.c
libdw/dwarf_offdie.c
libdw/dwarf_ranges.c
libdw/dwarf_siblingof.c
libdw/dwarf_tag.c
libdw/libdwP.h
libdw/libdw_findcu.c
libdw/libdw_form.c
libdw/libdw_visit_scopes.c

index 235fac0130e467186d5ead3cd175260d9bef593d..40b1d63044c320711569462c0a947fda33339c23 100644 (file)
@@ -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
index d3b0324481da3877e73c8484422136e26584a6cd..26ace6c4c742b9ee13ddaab0f7eb1e4269897f59 100644 (file)
 #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)
index 69935a40ee9086715cd3e6e61d927340f5ac4fed..9f38ea7e4e32efaccce2ec1e45a7a6c5b10486c8 100644 (file)
@@ -117,5 +117,8 @@ dwarf_begin (fd, cmd)
        result->free_elf = true;
     }
 
+  if (result != NULL)
+    rwlock_init (result->lock);
+
   return result;
 }
index 0080cf9d9291a7acb9e8affd32647ad33537078b..2431296bbff098af27762be4c2bb5aedf2cafcc0 100644 (file)
 #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)
index 10238b430d39bde018dc010e04dda1824b5410fd..cd211aab1b0585daabfcceaf35c6e313069f8bc6 100644 (file)
@@ -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;
 }
index b1d62df2cb54eb87c3b237322279b21779beab68..254c4e7c8f98b2534b6ff00393ed780fe8817507 100644 (file)
@@ -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;
 }
index a62b82229c4060b7b66861d9926b6e8ea73e76d9..544d1a327db94ca6ab3c9b7c4abd1ba60c98bd5b 100644 (file)
@@ -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;
 }
index 4d712f7f53ec0fd1958f7abc87273fafde21afc0..0f0acf77f7ce3f53e9200bd0113c0512e7384db8 100644 (file)
@@ -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)
index 60c9716e47df7237890b9f1b27f9cd8ced3dae15..4cc192c81fecc5d11821e69d9aa8b26e7ade65bb 100644 (file)
@@ -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);
     }
index 578464f3f9144c1f7f63c02fb9c05494154f9c4c..c5e3fb6387afcf0eb4f8d5d1ae79fb6814c7a23d 100644 (file)
@@ -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;
 }
index 1719be27a70409acecbfe11ded8a1770f9e8908a..2a590c4b9534cf73c82a503f84b631603b226bb3 100644 (file)
 
 
 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)
index b48340d4666e1feff592ec5c6ecf5ebca681aed0..74b3cf160dd084e59639596c9d02b9daf3c5c35d 100644 (file)
@@ -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;
 }
index dcb58d43348c79babc83b044754f9dcbe449594d..1f1eaa1a565eca6b7bc77966ba681880ab152da4 100644 (file)
@@ -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)
index 51396d47078a0f347d10f49226553581d14686ab..c6019b81efde40677a0b8f60a2284b3d3de3b7bb 100644 (file)
 
 
 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)
index 4e57c3af36e14e8e0762bbbd24de60b509fafbb1..bb0879beb9c5fb110d14728f56d4104d3ab844d5 100644 (file)
@@ -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;
 }
index b8463b70b16e82b90ce5331babc75c0ad00080c2..a70f89aaad16c494b200eba2dcd639383c2e5c54 100644 (file)
@@ -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;
 }
index 90a4b2d358d5301fc4ca7232ed34898c841b148e..6926c1a842018c3c61474b842286272450e351ba 100644 (file)
 
 
 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)
index ab7249d1c7afd6bdd7808962b34108faf08f3af4..418675e2e221512d9c0f6b6109a999f775c5be4f 100644 (file)
@@ -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)
index 790831ea3e7bca5401dfcc3792f8e3d1320ec7e3..b7558efd21cb0870458b40cac0b4dde29d0f864f 100644 (file)
 
 
 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)
index b5c40bb5da5fac76262b2b1cc87bbee06364eb75..571588ff0e015117c65ef4cec9f5b0f43bfd87b5 100644 (file)
@@ -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)
index 6018691a5783f6302f08ec931035989a556c7169..ffe25d899681b2a623a60dd7ac6de47019bd8a73 100644 (file)
@@ -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;
 }
index 07bf6dfc4a9aa16c7b3852f631d3845d59dff73a..5797a9fcf540c28d753f17cc3c830ec90085ed5e 100644 (file)
 #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;
 }
index 42f25ca06ba427c79bb21a71d0690f5a8d24c872..0d0d4b32d333626c72c5c43a446420360915fb41 100644 (file)
@@ -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;
 }
index c0352fbf0a74a53ca5eaf6fe554125877812c6e6..f6421331c64ca815dffb59108c4f4b68a10f5bd3 100644 (file)
@@ -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;
 }
index 743ade3bb4aa6000a1a59cbe178574e2928917b9..4dc51a72c5159f79c40eefb93e03570a1c70deb1 100644 (file)
@@ -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;
 }
index 1b054e26d9756a9a7e768442efc74472c82df3d1..a0ac6fba82a31974f034753396110c45fe23e7d3 100644 (file)
@@ -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;
 }
index 73431ba7ffd6390de076763917aa407b7105f7c5..8c0565aff790586d87600960709b910a15e6b116 100644 (file)
@@ -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;
 }
index 07fb9b001f46ec4781ca5bf59935109d74e58709..3262670e0d5ad400bd9f825de7b1da068da12985 100644 (file)
@@ -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;
 }
index 9b3c97af4ea96c333a26b5cd400bb8f9bfda9d9d..30c9ee5eb90af9a54a3b3a1f0e220d1b825f762d 100644 (file)
@@ -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)
index b1c4292a4792212a8209a1810d9e31ab2306b21e..1ea0d5260fb4e63f2247df8bca9a550879250570 100644 (file)
@@ -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)
index fe4319559561b901b3f78bad6c4ff2fa1a4fb660..fa9892f4f17ebb905f07e03511684e7c453e06a9 100644 (file)
 
 
 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)
index 58b87b653d4e08326266055052064dc9be20cb9d..599631f2bd2f69aa3af9609c04f302e785843fcf 100644 (file)
@@ -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)
index c88e0721fd219a280ccd9cf940a83b727dbae55a..28ca119bfbc4cd2b2fbadd17530391866b67340e 100644 (file)
 #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)
index 97ece03190dbc1ea2cfb48385d745133029e8773..0f8d6884ec926ec52b4dd4eee2e8b14ba8c87c92 100644 (file)
 
 
 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)
index 9e5a96bc64c1eb8a1742e96b4800d253fef2aa40..3383c8fdd23584f7c4c9187b51119dd6f25bc160 100644 (file)
@@ -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)
index 2cac27941222e8bf3efc7888c934a2cf4b98bdf9..953c40e29705fef046152f7ec8439c2dea0dd3a0 100644 (file)
@@ -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;
index a9886f2c8193f1d700247414a7df51fa2a72b438..f08c09a004ebdfaad5347a7a26de351d485e7cfe 100644 (file)
@@ -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)
index 89da0af4d95a3e044588c5a01ec28bdf5c790d47..d1ca91a61521b44bc2e7336913c9535bbbeefc2e 100644 (file)
 
 
 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)
index 0d42717514cab8851a7c9216a2b661d82ccc73ce..b2ab5326737f71d983dc60557866df05d2ab4f41 100644 (file)
@@ -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)
index 15183d2db04db2a93aef8fa19819359b37798a1c..a721f3d18dde53ff9f421cbdda4b75e90cd08653 100644 (file)
@@ -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)
index f805295ff26962f1541bc945a901a4a118b1ce08..6d8c6d806d7af3e7c75699568d3569390071829e 100644 (file)
@@ -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);
index afff6d3a5208fc387feac2281523befb6cf07c51..d01beaa824ec26c28ba66ed5458b4877af5b9176 100644 (file)
@@ -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);
+}
index ad78f4b4fc97295affe43a05698d86c68bd00a7e..643af8e0d1c4b2f62671234c92a96927409dbbe9 100644 (file)
@@ -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;
index 9c7c37891c0e2c9d6fd38e15bdfac4784adfb7e4..3e0ce349278b875d10d5b88c356e18116483fe13 100644 (file)
@@ -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;
 }