]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
DW_OP_implicit_value support
authorRoland McGrath <roland@redhat.com>
Thu, 10 Sep 2009 19:39:09 +0000 (12:39 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 10 Sep 2009 19:39:09 +0000 (12:39 -0700)
libdw/ChangeLog
libdw/dwarf_getlocation.c
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h

index 6f47fc769090d519811dd2f6b807af556b88ecd2..2346ba32f94cd2976375516044873b8c8904b25c 100644 (file)
@@ -1,3 +1,11 @@
+2009-09-10  Roland McGrath  <roland@redhat.com>
+
+       * dwarf_getlocation.c (store_implicit_value): New function.
+       (__libdw_intern_expression): Use it, handle DW_OP_implicit_value.
+       (dwarf_getlocation_implicit_value): New function.
+       * libdw.h: Declare it.
+       * libdw.map (ELFUTILS_0.143): Add it.
+
 2009-09-09  Mark Wielaard  <mjw@redhat.com>
 
        * dwarf_getcfi.c (dwarf_getcfi): Clear cfi->ebl.
index 1488203b9ff2c6a07ccf35d8e62d82cede6ea099..c3b7f3dc8a4559bbb357abd13d2c1b71a5e3c0af 100644 (file)
@@ -112,6 +112,42 @@ loc_compare (const void *p1, const void *p2)
   return 0;
 }
 
+/* For each DW_OP_implicit_value, we store a special entry in the cache.
+   This points us directly to the block data for later fetching.  */
+static void
+store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op,
+                     unsigned char *data)
+{
+  struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
+                                          sizeof (struct loc_block_s), 1);
+  block->addr = op;
+  block->data = data + op->number2;
+  block->length = op->number;
+  (void) tsearch (block, cache, loc_compare);
+}
+
+int
+dwarf_getlocation_implicit_value (attr, op, return_block)
+     Dwarf_Attribute *attr;
+     Dwarf_Op *op;
+     Dwarf_Block *return_block;
+{
+  if (attr == NULL)
+    return -1;
+
+  struct loc_block_s fake = { .addr = op };
+  struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
+  if (unlikely (found == NULL))
+    {
+      __libdw_seterrno (DWARF_E_NO_BLOCK);
+      return -1;
+    }
+
+  return_block->length = (*found)->length;
+  return_block->data = (*found)->data;
+  return 0;
+}
+
 /* DW_AT_data_member_location can be a constant as well as a loclistptr.
    Only data[48] indicate a loclistptr.  */
 static int
@@ -351,6 +387,19 @@ __libdw_intern_expression (Dwarf *dbg,
          get_uleb128 (newloc->number2, data);
          break;
 
+       case DW_OP_implicit_value:
+         /* This cannot be used in a CFI expression.  */
+         if (unlikely (dbg == NULL))
+           goto invalid;
+
+         /* XXX Check size.  */
+         get_uleb128 (newloc->number, data); /* Block length.  */
+         if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
+           goto invalid;
+         newloc->number2 = data - block->data; /* Relative block offset.  */
+         data += newloc->number;               /* Skip the block.  */
+         break;
+
        default:
          goto invalid;
        }
@@ -398,20 +447,21 @@ __libdw_intern_expression (Dwarf *dbg,
 
   do
     {
-      /* We populate the array from the back since the list is
-         backwards.  */
+      /* We populate the array from the back since the list is backwards.  */
       --n;
       result[n].atom = loclist->atom;
       result[n].number = loclist->number;
       result[n].number2 = loclist->number2;
       result[n].offset = loclist->offset;
 
+      if (result[n].atom == DW_OP_implicit_value)
+       store_implicit_value (dbg, cache, &result[n], block->data);
+
       loclist = loclist->next;
     }
   while (n > 0);
 
-  /* Insert a record in the search tree so that we can find it again
-     later.  */
+  /* Insert a record in the search tree so that we can find it again later.  */
   struct loc_s *newp;
   if (dbg != NULL)
     newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
index ec352b4d3ac6a02a03c03e5193b4d7caf8e44d43..4cdc220800c77f8119d799fccce12643e41be797 100644 (file)
@@ -623,6 +623,15 @@ extern int dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
                                   Dwarf_Op **exprs, size_t *exprlens,
                                   size_t nlocs);
 
+/* Return the block associated with a DW_OP_implicit_value operation.
+   The OP pointer must point into an expression that dwarf_getlocation
+   or dwarf_getlocation_addr has returned given the same ATTR.  */
+extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr,
+                                            Dwarf_Op *op,
+                                            Dwarf_Block *return_block)
+  __nonnull_attribute__ (2, 3);
+
+
 
 /* Return scope DIEs containing PC address.
    Sets *SCOPES to a malloc'd array of Dwarf_Die structures,
index 6fc86b34aecb74ad04ce5b8f240c2fdff0746f30..b39db4816a6796faa1b4f6c6f78bb244feb757c5 100644 (file)
@@ -212,6 +212,8 @@ ELFUTILS_0.142 {
 
 ELFUTILS_0.143 {
   global:
+    dwarf_getlocation_implicit_value;
+
     # Replaced ELFUTILS_0.122 versions.  Both versions point to the
     # same implementation, but users of the new symbol version can
     # presume that they use dwarf_attr_integrate properly.
index a8f392475051fa9e062d52af95349704e5670028..0284580f8351b8541028733c7ebede200555f6ab 100644 (file)
@@ -76,6 +76,16 @@ struct loc_s
   size_t nloc;
 };
 
+/* Known DW_OP_implicit_value blocks already decoded.
+   This overlaps struct loc_s exactly, but only the
+   first member really has to match.  */
+struct loc_block_s
+{
+  void *addr;
+  unsigned char *data;
+  size_t length;
+};
+
 /* Valid indeces for the section data.  */
 enum
   {