Handle DW_AT_data_member_location of class constant magically in dwarf_getlocation...
authorRoland McGrath <roland@redhat.com>
Wed, 8 Jul 2009 20:15:07 +0000 (13:15 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 8 Jul 2009 20:16:21 +0000 (13:16 -0700)
libdw/ChangeLog
libdw/dwarf_getlocation.c

index 6ae3154..600f6dc 100644 (file)
@@ -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.
index 504db37..62106ce 100644 (file)
@@ -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);