summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog6
-rw-r--r--libdw/dwarf_getlocation.c60
2 files changed, 66 insertions, 0 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 6ae3154a..600f6dc3 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,9 @@
+2009-07-08 Roland McGrath <roland@redhat.com>
+
+ * dwarf_getlocation.c (check_constant_offset): New function.
+ (dwarf_getlocation, dwarf_getlocation_addr): Call it to
+ handle DW_AT_data_member_location of data[48] as constant offset.
+
2009-06-18 Roland McGrath <roland@redhat.com>
* libdwP.h (__libdw_read_address_inc): Constify.
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index 504db376..62106ce3 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -55,6 +55,7 @@
#include <dwarf.h>
#include <search.h>
#include <stdlib.h>
+#include <assert.h>
#include <libdwP.h>
@@ -111,6 +112,57 @@ loc_compare (const void *p1, const void *p2)
return 0;
}
+/* DW_AT_data_member_location can be a constant as well as a loclistptr.
+ Only data[48] indicate a loclistptr. */
+static int
+check_constant_offset (Dwarf_Attribute *attr,
+ Dwarf_Op **llbuf, size_t *listlen)
+{
+ if (attr->code != DW_AT_data_member_location
+ || attr->form == DW_FORM_data4
+ || attr->form == DW_FORM_data8)
+ return 1;
+
+ /* Check whether we already cached this location. */
+ struct loc_s fake = { .addr = attr->valp };
+ struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
+
+ if (found == NULL)
+ {
+ Dwarf_Word offset;
+ if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
+ return -1;
+
+ Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
+ Dwarf_Op, sizeof (Dwarf_Op), 1);
+
+ result->atom = DW_OP_plus_uconst;
+ result->number = offset;
+ result->number2 = 0;
+ result->offset = 0;
+
+ /* Insert a record in the search tree so we can find it again later. */
+ struct loc_s *newp = libdw_alloc (attr->cu->dbg,
+ struct loc_s, sizeof (struct loc_s),
+ 1);
+ newp->addr = attr->valp;
+ newp->loc = result;
+ newp->nloc = 1;
+
+ found = tsearch (newp, &attr->cu->locs, loc_compare);
+ }
+
+ assert ((*found)->nloc == 1);
+
+ if (llbuf != NULL)
+ {
+ *llbuf = (*found)->loc;
+ *listlen = 1;
+ }
+
+ return 0;
+}
+
static int
getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
Dwarf_Op **llbuf, size_t *listlen, int sec_index)
@@ -333,6 +385,10 @@ dwarf_getlocation (attr, llbuf, listlen)
Dwarf_Op **llbuf;
size_t *listlen;
{
+ int result = check_constant_offset (attr, llbuf, listlen);
+ if (result != 1)
+ return result;
+
if (! attr_ok (attr))
return -1;
@@ -378,6 +434,10 @@ dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
return -1;
}
+ int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
+ if (result != 1)
+ return result ?: 1;
+
unsigned char *endp;
unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc,
DWARF_E_NO_LOCLIST, &endp, NULL);