Tom
>From 1b85426f7a1fa39cfb9ff83b864e825072115847 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey(a)redhat.com>
Date: Mon, 19 Mar 2012 11:46:45 -0600
Subject: [PATCH] Fix bug using dwarf_next_unit to iterate over .debug_types
* libdw_findcu.c (findcu_cb): Move earlier.
(__libdw_intern_next_unit): Add new CU to search tree here...
(__libdw_findcu): ... not here.
If you call dwarf_next_unit to iterate over .debug_types, then call
dwarf_offdie_types, you can see a failure if some earlier call
happened to call __libdw_intern_next_unit via dwarf_formref_die.
What happens is that __libdw_intern_next_unit updates the Dwarf's
next_tu_offset, but does not add the TU to the TU search tree. So,
the call to dwarf_offdie_types does not find the TU in the tree, and
will not search any more, causing a failure.
This fix changes __libdw_intern_next_unit to add the TU to the search
tree, rather than relying on __libdw_findcu to do it.
---
libdw/ChangeLog | 6 ++++
libdw/libdw_findcu.c | 68 ++++++++++++++++++++++++-------------------------
2 files changed, 39 insertions(+), 35 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 98b67f4..f96c0d1 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2012-03-19 Tom Tromey <tromey(a)redhat.com>
+
+ * libdw_findcu.c (findcu_cb): Move earlier.
+ (__libdw_intern_next_unit): Add new CU to search tree here...
+ (__libdw_findcu): ... not here.
+
2012-01-31 Mark Wielaard <mjw(a)redhat.com>
* dwarf_formudata.c (dwarf_formudata): Handle DW_FORM_sec_offset.
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index 8e5f9e9..83c96ba 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -56,6 +56,31 @@
#include <search.h>
#include "libdwP.h"
+static int
+findcu_cb (const void *arg1, const void *arg2)
+{
+ struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
+ struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
+
+ /* Find out which of the two arguments is the search value. It has
+ end offset 0. */
+ if (cu1->end == 0)
+ {
+ if (cu1->start < cu2->start)
+ return -1;
+ if (cu1->start >= cu2->end)
+ return 1;
+ }
+ else
+ {
+ if (cu2->start < cu1->start)
+ return 1;
+ if (cu2->start >= cu1->end)
+ return -1;
+ }
+
+ return 0;
+}
struct Dwarf_CU *
internal_function
@@ -65,6 +90,7 @@ __libdw_intern_next_unit (dbg, debug_types)
{
Dwarf_Off *const offsetp
= debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
+ void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
Dwarf_Off oldoff = *offsetp;
uint16_t version;
@@ -105,34 +131,16 @@ __libdw_intern_next_unit (dbg, debug_types)
newp->lines = NULL;
newp->locs = NULL;
- return newp;
-}
-
-
-static int
-findcu_cb (const void *arg1, const void *arg2)
-{
- struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
- struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
-
- /* Find out which of the two arguments is the search value. It has
- end offset 0. */
- if (cu1->end == 0)
+ /* Add the new entry to the search tree. */
+ if (tsearch (newp, tree, findcu_cb) == NULL)
{
- if (cu1->start < cu2->start)
- return -1;
- if (cu1->start >= cu2->end)
- return 1;
- }
- else
- {
- if (cu2->start < cu1->start)
- return 1;
- if (cu2->start >= cu1->end)
- return -1;
+ /* Something went wrong. Undo the operation. */
+ *offsetp = oldoff;
+ __libdw_seterrno (DWARF_E_NOMEM);
+ return NULL;
}
- return 0;
+ return newp;
}
struct Dwarf_CU *
@@ -160,20 +168,10 @@ __libdw_findcu (dbg, start, debug_types)
/* No. Then read more CUs. */
while (1)
{
- Dwarf_Off oldoff = *next_offset;
struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, debug_types);
if (newp == NULL)
return NULL;
- /* Add the new entry to the search tree. */
- if (tsearch (newp, tree, findcu_cb) == NULL)
- {
- /* Something went wrong. Undo the operation. */
- *next_offset = oldoff;
- __libdw_seterrno (DWARF_E_NOMEM);
- return NULL;
- }
-
/* Is this the one we are looking for? */
if (start < *next_offset)
// XXX Match exact offset.
--
1.7.7.6