mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-20 03:53:42 -04:00
libdw: Add new functions dwarf_getlocation_attr and dwarf_getlocation_die.
Some location expression operations have a DIE associated with them. Examples are some of the new GNU typed DWARF extensions, DW_OP_GNU_convert, DW_OP_GNU_reinterpret, DW_OP_GNU_const_type, DW_OP_GNU_regval_type and DW_OP_GNU_deref_type. Others have (block) values associated with them, like DW_OP_GNU_entry_value and DW_OP_GNU_const_type. It is not always easy to access these values. The DIE offset is given in various formats either as global offset or CU relative offset. The (block) value might be constant or a location description. And the block might be encoded with a uleb128 or ubyte length. The new functions help to easily get at the DIE or attribute value. In theory dwarf_getlocation_attr could be used for all cases, since besides returning DW_AT_const_value or DW_AT_location, it could also return an attribute referencing a DIE. But at least one operation, DW_OP_GNU_const_type, has both a (type) DIE and a constant (block) value associated with it. And directly getting the DIE when needed is easier than first having to retrieve a (synthesized) attribute and then getting the actual (type) DIE. Expression operations that reference an actual DIE for the DW_AT_location or DW_AT_const_value, like DW_OP_call2, DW_OP_call4, DW_OP_callref and DW_OP_GNU_implicit_pointer can be used with both dwarf_getlocation_attr and dwarf_getlocation_die. DW_OP_implicit_value and DW_OP_GNU_implicit_pointer already had their own special accessors (dwarf_getlocation_implicit_value and dwarf_getlocation_implicit_pointer), but it seemed consistent to include them in the new more generic accessors too. Signed-off-by: Mark Wielaard <mjw@redhat.com>
This commit is contained in:
@@ -1,3 +1,22 @@
|
||||
2013-08-24 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* dwarf_getlocation.c (store_implicit_value): Don't take data
|
||||
as argument, get block data from op number2. Return false when
|
||||
block data length and op number don't match up.
|
||||
(__libdw_intern_expression): Store start of block for
|
||||
DW_OP_implicit_value and DW_OP_GNU_entry_value instead of
|
||||
relative data offset. Also store block start (including length)
|
||||
for DW_OP_GNU_const_type. Don't pass data to store_implicit_value.
|
||||
* dwarf_getlocation_attr.c: New file.
|
||||
* dwarf_getlocation_die.c: Likewise.
|
||||
* libdw.h (dwarf_getlocation_die): New function definition.
|
||||
(dwarf_getlocation_attr): Likewise.
|
||||
* libdwP.h: Declare internal dwarf_getlocation_die.
|
||||
* libdw.map (ELFUTILS_0.157): Add dwarf_getlocation_die and
|
||||
dwarf_getlocation_attr.
|
||||
* Makefile.am (libdw_a_SOURCES): Add dwarf_getlocation_die.c and
|
||||
dwarf_getlocation_attr.c.
|
||||
|
||||
2013-08-23 Mark Wielaard <mjw@redhat.com>
|
||||
|
||||
* dwarf_getlocation.c (attr_ok): Also accept DW_AT_segment.
|
||||
|
||||
+2
-1
@@ -87,7 +87,8 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
|
||||
dwarf_frame_info.c dwarf_frame_cfa.c dwarf_frame_register.c \
|
||||
dwarf_cfi_addrframe.c \
|
||||
dwarf_getcfi.c dwarf_getcfi_elf.c dwarf_cfi_end.c \
|
||||
dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c
|
||||
dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
|
||||
dwarf_getlocation_die.c dwarf_getlocation_attr.c
|
||||
|
||||
if MAINTAINER_MODE
|
||||
BUILT_SOURCES = $(srcdir)/known-dwarf.h
|
||||
|
||||
+21
-16
@@ -95,13 +95,15 @@ loc_compare (const void *p1, const void *p2)
|
||||
/* 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)
|
||||
store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
|
||||
{
|
||||
struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
|
||||
sizeof (struct loc_block_s), 1);
|
||||
const unsigned char *data = (const unsigned char *) op->number2;
|
||||
Dwarf_Word blength; // Ignored, equal to op->number.
|
||||
get_uleb128 (blength, data);
|
||||
block->addr = op;
|
||||
block->data = data + op->number2;
|
||||
block->data = (unsigned char *) data;
|
||||
block->length = op->number;
|
||||
(void) tsearch (block, cache, loc_compare);
|
||||
}
|
||||
@@ -412,11 +414,11 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
|
||||
if (unlikely (dbg == NULL))
|
||||
goto invalid;
|
||||
|
||||
newloc->number2 = (Dwarf_Word) data; /* start of block inc. len. */
|
||||
/* 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;
|
||||
|
||||
@@ -437,17 +439,20 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_const_type:
|
||||
/* XXX Check size. */
|
||||
get_uleb128 (newloc->number, data);
|
||||
if (unlikely (data >= end_data))
|
||||
goto invalid;
|
||||
newloc->number2 = *data++; /* Block length. */
|
||||
if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number2))
|
||||
goto invalid;
|
||||
/* The third operand is relative block offset:
|
||||
newloc->number3 = data - block->data;
|
||||
We don't support this at this point. */
|
||||
data += newloc->number2; /* Skip the block. */
|
||||
{
|
||||
size_t size;
|
||||
|
||||
/* XXX Check size. */
|
||||
get_uleb128 (newloc->number, data);
|
||||
if (unlikely (data >= end_data))
|
||||
goto invalid;
|
||||
|
||||
newloc->number2 = (Dwarf_Word) data; /* start of block inc. len. */
|
||||
size = *data++;
|
||||
if (unlikely ((Dwarf_Word) (end_data - data) < size))
|
||||
goto invalid;
|
||||
data += size; /* Skip the block. */
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -505,7 +510,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
|
||||
result[n].offset = loclist->offset;
|
||||
|
||||
if (result[n].atom == DW_OP_implicit_value)
|
||||
store_implicit_value (dbg, cache, &result[n], block->data);
|
||||
store_implicit_value (dbg, cache, &result[n]);
|
||||
|
||||
loclist = loclist->next;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
/* Return DWARF attribute associated with a location expression op.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <dwarf.h>
|
||||
#include <libdwP.h>
|
||||
|
||||
|
||||
int
|
||||
dwarf_getlocation_attr (attr, op, result)
|
||||
Dwarf_Attribute *attr;
|
||||
const Dwarf_Op *op;
|
||||
Dwarf_Attribute *result;
|
||||
{
|
||||
if (attr == NULL)
|
||||
return -1;
|
||||
|
||||
result->cu = attr->cu;
|
||||
|
||||
switch (op->atom)
|
||||
{
|
||||
case DW_OP_implicit_value:
|
||||
result->code = DW_AT_const_value;
|
||||
result->form = DW_FORM_block;
|
||||
result->valp = (unsigned char *) op->number2;
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_entry_value:
|
||||
result->code = DW_AT_location;
|
||||
result->form = DW_FORM_exprloc;
|
||||
result->valp = (unsigned char *) op->number2;
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_const_type:
|
||||
result->code = DW_AT_const_value;
|
||||
result->form = DW_FORM_block1;
|
||||
result->valp = (unsigned char *) op->number2;
|
||||
break;
|
||||
|
||||
case DW_OP_call2:
|
||||
case DW_OP_call4:
|
||||
case DW_OP_call_ref:
|
||||
{
|
||||
Dwarf_Die die;
|
||||
if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
|
||||
return -1;
|
||||
if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL)
|
||||
{
|
||||
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_implicit_pointer:
|
||||
{
|
||||
Dwarf_Die die;
|
||||
if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
|
||||
return -1;
|
||||
if (INTUSE(dwarf_attr) (&die, DW_AT_location, result) == NULL
|
||||
&& INTUSE(dwarf_attr) (&die, DW_AT_const_value, result) == NULL)
|
||||
{
|
||||
__libdw_seterrno (DWARF_E_INVALID_DWARF);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
__libdw_seterrno (DWARF_E_INVALID_ACCESS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/* Return DIE associated with a location expression op.
|
||||
Copyright (C) 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
|
||||
This file is free software; you can redistribute it and/or modify
|
||||
it under the terms of either
|
||||
|
||||
* the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or
|
||||
|
||||
* the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version
|
||||
|
||||
or both in parallel, as here.
|
||||
|
||||
elfutils is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received copies of the GNU General Public License and
|
||||
the GNU Lesser General Public License along with this program. If
|
||||
not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <dwarf.h>
|
||||
#include <libdwP.h>
|
||||
|
||||
int
|
||||
dwarf_getlocation_die (attr, op, result)
|
||||
Dwarf_Attribute *attr;
|
||||
const Dwarf_Op *op;
|
||||
Dwarf_Die *result;
|
||||
{
|
||||
if (attr == NULL)
|
||||
return -1;
|
||||
|
||||
Dwarf_Off dieoff;
|
||||
switch (op->atom)
|
||||
{
|
||||
case DW_OP_GNU_implicit_pointer:
|
||||
case DW_OP_call_ref:
|
||||
dieoff = op->number;
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_parameter_ref:
|
||||
case DW_OP_GNU_convert:
|
||||
case DW_OP_GNU_reinterpret:
|
||||
case DW_OP_GNU_const_type:
|
||||
case DW_OP_call2:
|
||||
case DW_OP_call4:
|
||||
dieoff = attr->cu->start + op->number;
|
||||
break;
|
||||
|
||||
case DW_OP_GNU_regval_type:
|
||||
case DW_OP_GNU_deref_type:
|
||||
dieoff = attr->cu->start + op->number2;
|
||||
break;
|
||||
|
||||
default:
|
||||
__libdw_seterrno (DWARF_E_INVALID_ACCESS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__libdw_offdie (attr->cu->dbg, dieoff, result,
|
||||
attr->cu->type_offset != 0) == NULL)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
INTDEF(dwarf_getlocation_die);
|
||||
@@ -664,6 +664,29 @@ extern int dwarf_getlocation_implicit_pointer (Dwarf_Attribute *attr,
|
||||
Dwarf_Attribute *result)
|
||||
__nonnull_attribute__ (2, 3);
|
||||
|
||||
/* Return the DIE associated with an operation such as
|
||||
DW_OP_GNU_implicit_pointer, DW_OP_GNU_parameter_ref, DW_OP_GNU_convert,
|
||||
DW_OP_GNU_reinterpret, DW_OP_GNU_const_type, DW_OP_GNU_regval_type or
|
||||
DW_OP_GNU_deref_type. The OP pointer must point into an expression that
|
||||
dwarf_getlocation or dwarf_getlocation_addr has returned given the same
|
||||
ATTR. The RESULT is a DIE that expresses a type or value needed by the
|
||||
given OP. */
|
||||
extern int dwarf_getlocation_die (Dwarf_Attribute *attr,
|
||||
const Dwarf_Op *op,
|
||||
Dwarf_Die *result)
|
||||
__nonnull_attribute__ (2, 3);
|
||||
|
||||
/* Return the attribute expressing a value associated with an operation such
|
||||
as DW_OP_implicit_value, DW_OP_GNU_entry_value or DW_OP_GNU_const_type.
|
||||
The OP pointer must point into an expression that dwarf_getlocation
|
||||
or dwarf_getlocation_addr has returned given the same ATTR.
|
||||
The RESULT is a value expressed by an attribute such as DW_AT_location
|
||||
or DW_AT_const_value. */
|
||||
extern int dwarf_getlocation_attr (Dwarf_Attribute *attr,
|
||||
const Dwarf_Op *op,
|
||||
Dwarf_Attribute *result)
|
||||
__nonnull_attribute__ (2, 3);
|
||||
|
||||
|
||||
/* Compute the byte-size of a type DIE according to DWARF rules.
|
||||
For most types, this is just DW_AT_byte_size.
|
||||
|
||||
@@ -264,4 +264,6 @@ ELFUTILS_0.156 {
|
||||
ELFUTILS_0.157 {
|
||||
global:
|
||||
dwarf_getlocations;
|
||||
dwarf_getlocation_die;
|
||||
dwarf_getlocation_attr;
|
||||
} ELFUTILS_0.156;
|
||||
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/* Internal definitions for libdwarf.
|
||||
Copyright (C) 2002-2011 Red Hat, Inc.
|
||||
Copyright (C) 2002-2011, 2013 Red Hat, Inc.
|
||||
This file is part of elfutils.
|
||||
Written by Ulrich Drepper <drepper@redhat.com>, 2002.
|
||||
|
||||
@@ -654,6 +654,7 @@ INTDECL (dwarf_formudata)
|
||||
INTDECL (dwarf_getarange_addr)
|
||||
INTDECL (dwarf_getarangeinfo)
|
||||
INTDECL (dwarf_getaranges)
|
||||
INTDECL (dwarf_getlocation_die)
|
||||
INTDECL (dwarf_getsrcfiles)
|
||||
INTDECL (dwarf_getsrclines)
|
||||
INTDECL (dwarf_hasattr)
|
||||
|
||||
Reference in New Issue
Block a user