From: Roland McGrath Date: Thu, 10 Sep 2009 19:39:09 +0000 (-0700) Subject: DW_OP_implicit_value support X-Git-Tag: elfutils-0.143~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f0371041995308d197447019eb2ac9285c96477b;p=thirdparty%2Felfutils.git DW_OP_implicit_value support --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 6f47fc769..2346ba32f 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,11 @@ +2009-09-10 Roland McGrath + + * 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 * dwarf_getcfi.c (dwarf_getcfi): Clear cfi->ebl. diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 1488203b9..c3b7f3dc8 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -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); diff --git a/libdw/libdw.h b/libdw/libdw.h index ec352b4d3..4cdc22080 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -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, diff --git a/libdw/libdw.map b/libdw/libdw.map index 6fc86b34a..b39db4816 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -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. diff --git a/libdw/libdwP.h b/libdw/libdwP.h index a8f392475..0284580f8 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -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 {