From 932585d2385c9d4e5686e4ddc9ba30c68172d7f3 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Sat, 8 May 2010 04:01:14 -0700 Subject: [PATCH] Handle DW_OP_GNU_implicit_pointer. --- NEWS | 3 ++ libdw/ChangeLog | 15 ++++++ libdw/Makefile.am | 2 +- libdw/dwarf.h | 1 + libdw/dwarf_getlocation.c | 9 ++++ libdw/dwarf_getlocation_implicit_pointer.c | 86 ++++++++++++++++++++++++++++++ libdw/dwarf_offdie.c | 10 ++-- libdw/libdw.h | 10 ++++ libdw/libdw.map | 2 + libdw/libdwP.h | 4 ++ src/ChangeLog | 5 ++ src/readelf.c | 23 ++++++++ 12 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 libdw/dwarf_getlocation_implicit_pointer.c diff --git a/NEWS b/NEWS index 599ea32..898cb81 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,8 @@ Version 0.149: +libdw: Decode new DW_OP_GNU_implicit_pointer operation; + new function dwarf_getlocation_implicit_pointer. + libdwfl: New function dwfl_dwarf_line. addr2line: New flag -F/--flags to print DWARF more line information details. diff --git a/libdw/ChangeLog b/libdw/ChangeLog index dc1a7f3..da6ed05 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,18 @@ +2010-07-26 Roland McGrath + + * dwarf_getlocation_implicit_pointer.c: New file. + * Makefile.am (libdw_a_SOURCES): Add it. + * libdw.map (ELFUTILS_0.149): New set. + Add dwarf_getlocation_implicit_pointer. + * libdw.h: Declare it. + + * dwarf_offdie.c (do_offdie): Renamed to __libdw_offdie, made global. + (dwarf_offdie, dwarf_offdie_types): Update callers. + * libdwP.h: Declare it. + + * dwarf.h: Add DW_OP_GNU_implicit_pointer. + * dwarf_getlocation.c (__libdw_intern_expression): Handle it. + 2010-08-24 Roland McGrath * libdw.map (ELFUTILS_0.149): New set. Add dwfl_dwarf_line. diff --git a/libdw/Makefile.am b/libdw/Makefile.am index 530cbf4..598bdd1 100644 --- a/libdw/Makefile.am +++ b/libdw/Makefile.am @@ -84,7 +84,7 @@ 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_aggregate_size.c dwarf_getlocation_implicit_pointer.c if MAINTAINER_MODE BUILT_SOURCES = $(srcdir)/known-dwarf.h diff --git a/libdw/dwarf.h b/libdw/dwarf.h index dbf56e9..edf57b4 100644 --- a/libdw/dwarf.h +++ b/libdw/dwarf.h @@ -475,6 +475,7 @@ enum DW_OP_GNU_push_tls_address = 0xe0, DW_OP_GNU_uninit = 0xf0, DW_OP_GNU_encoded_addr = 0xf1, + DW_OP_GNU_implicit_pointer = 0xf2, DW_OP_lo_user = 0xe0, /* Implementation-defined range start. */ DW_OP_hi_user = 0xff /* Implementation-defined range end. */ diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index e960ef9..f7a60f9 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -420,6 +420,15 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, data += newloc->number; /* Skip the block. */ break; + case DW_OP_GNU_implicit_pointer: + /* DW_FORM_ref_addr, depends on offset size of CU. */ + if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, + &newloc->number, IDX_debug_info, 0)) + return -1; + /* XXX Check size. */ + get_uleb128 (newloc->number2, data); /* Byte offset. */ + break; + default: goto invalid; } diff --git a/libdw/dwarf_getlocation_implicit_pointer.c b/libdw/dwarf_getlocation_implicit_pointer.c new file mode 100644 index 0000000..4d9f6b9 --- /dev/null +++ b/libdw/dwarf_getlocation_implicit_pointer.c @@ -0,0 +1,86 @@ +/* Return associated attribute for DW_OP_GNU_implicit_pointer. + Copyright (C) 2010 Red Hat, Inc. + This file is part of Red Hat elfutils. + + Red Hat elfutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by the + Free Software Foundation; version 2 of the License. + + Red Hat 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 a copy of the GNU General Public License along + with Red Hat elfutils; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. + + In addition, as a special exception, Red Hat, Inc. gives You the + additional right to link the code of Red Hat elfutils with code licensed + under any Open Source Initiative certified open source license + (http://www.opensource.org/licenses/index.php) which requires the + distribution of source code with any binary distribution and to + distribute linked combinations of the two. Non-GPL Code permitted under + this exception must only link to the code of Red Hat elfutils through + those well defined interfaces identified in the file named EXCEPTION + found in the source code files (the "Approved Interfaces"). The files + of Non-GPL Code may instantiate templates or use macros or inline + functions from the Approved Interfaces without causing the resulting + work to be covered by the GNU General Public License. Only Red Hat, + Inc. may make changes or additions to the list of Approved Interfaces. + Red Hat's grant of this exception is conditioned upon your not adding + any new exceptions. If you wish to add a new Approved Interface or + exception, please contact Red Hat. You must obey the GNU General Public + License in all respects for all of the Red Hat elfutils code and other + code used in conjunction with Red Hat elfutils except the Non-GPL Code + covered by this exception. If you modify this file, you may extend this + exception to your version of the file, but you are not obligated to do + so. If you do not wish to provide this exception without modification, + you must delete this exception statement from your version and license + this file solely under the GPL without exception. + + Red Hat elfutils is an included package of the Open Invention Network. + An included package of the Open Invention Network is a package for which + Open Invention Network licensees cross-license their patents. No patent + license is granted, either expressly or impliedly, by designation as an + included package. Should you wish to participate in the Open Invention + Network licensing program, please visit www.openinventionnetwork.com + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "libdwP.h" +#include + + +int +dwarf_getlocation_implicit_pointer (attr, op, result) + Dwarf_Attribute *attr; + const Dwarf_Op *op; + Dwarf_Attribute *result; +{ + if (attr == NULL) + return -1; + + if (unlikely (op->atom != DW_OP_GNU_implicit_pointer)) + { + __libdw_seterrno (DWARF_E_INVALID_ACCESS); + return -1; + } + + Dwarf_Die die; + if (__libdw_offdie (attr->cu->dbg, op->number, &die, + attr->cu->type_offset != 0) == NULL) + 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; + } + + return 0; +} diff --git a/libdw/dwarf_offdie.c b/libdw/dwarf_offdie.c index 925fe51..4c650cf 100644 --- a/libdw/dwarf_offdie.c +++ b/libdw/dwarf_offdie.c @@ -56,8 +56,10 @@ #include "libdwP.h" -static Dwarf_Die * -do_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result, bool debug_types) +Dwarf_Die * +internal_function +__libdw_offdie (Dwarf *dbg, Dwarf_Off offset, Dwarf_Die *result, + bool debug_types) { if (dbg == NULL) return NULL; @@ -95,7 +97,7 @@ dwarf_offdie (dbg, offset, result) Dwarf_Off offset; Dwarf_Die *result; { - return do_offdie (dbg, offset, result, false); + return __libdw_offdie (dbg, offset, result, false); } INTDEF(dwarf_offdie) @@ -105,5 +107,5 @@ dwarf_offdie_types (dbg, offset, result) Dwarf_Off offset; Dwarf_Die *result; { - return do_offdie (dbg, offset, result, true); + return __libdw_offdie (dbg, offset, result, true); } diff --git a/libdw/libdw.h b/libdw/libdw.h index 9202136..d36238e 100644 --- a/libdw/libdw.h +++ b/libdw/libdw.h @@ -659,6 +659,16 @@ extern int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, Dwarf_Block *return_block) __nonnull_attribute__ (2, 3); +/* Return the attribute indicated by a DW_OP_GNU_implicit_pointer operation. + The OP pointer must point into an expression that dwarf_getlocation + or dwarf_getlocation_addr has returned given the same ATTR. + The result is the DW_AT_location or DW_AT_const_value attribute + of the OP->number DIE. */ +extern int dwarf_getlocation_implicit_pointer (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. diff --git a/libdw/libdw.map b/libdw/libdw.map index 6d6b365..1f71d03 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -250,5 +250,7 @@ ELFUTILS_0.148 { ELFUTILS_0.149 { global: + dwarf_getlocation_implicit_pointer; + dwfl_dwarf_line; } ELFUTILS_0.148; diff --git a/libdw/libdwP.h b/libdw/libdwP.h index bb0ae1d..da6efc5 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -456,6 +456,10 @@ extern int __libdw_intern_expression (Dwarf *dbg, int sec_index) __nonnull_attribute__ (5, 6, 9, 10) internal_function; +extern Dwarf_Die *__libdw_offdie (Dwarf *dbg, Dwarf_Off offset, + Dwarf_Die *result, bool debug_types) + internal_function; + /* Return error code of last failing function call. This value is kept separately for each thread. */ diff --git a/src/ChangeLog b/src/ChangeLog index 3010ce5..4fff276 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,7 @@ +2010-07-26 Roland McGrath + + * readelf.c (print_ops): Handle DW_OP_GNU_implicit_pointer. + 2010-08-30 Roland McGrath * readelf.c (print_debug_loc_section): Check for bogus length @@ -97,6 +101,7 @@ (struct attrcb_args): Add offset_size field. (attr_callback): Use it for print_ops call. (print_debug_info_section): Initialize it. + (print_ops): Likewise. 2010-04-14 Roland McGrath diff --git a/src/readelf.c b/src/readelf.c index fd9f9a5..8c5e815 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -3969,6 +3969,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, [DW_OP_bit_piece] = "bit_piece", [DW_OP_implicit_value] = "implicit_value", [DW_OP_stack_value] = "stack_value", + [DW_OP_GNU_implicit_pointer] = "GNU_implicit_pointer", }; if (len == 0) @@ -4211,6 +4212,28 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, offset += 1 + (data - start); break; + case DW_OP_GNU_implicit_pointer: + /* DIE offset operand. */ + start = data; + NEED (ref_size + 1); + if (ref_size == 4) + addr = read_4ubyte_unaligned (dbg, data); + else + { + assert (ref_size == 8); + addr = read_8ubyte_unaligned (dbg, data); + } + data += ref_size; + /* Byte offset operand. */ + get_sleb128 (sleb, data); /* XXX check overrun */ + + printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX ", %+" PRId64 "\n", + indent, "", (intmax_t) offset, + known[op], (uintmax_t) addr, sleb); + CONSUME (data - start); + offset += 1 + (data - start); + break; + default: /* No Operand. */ if (op < sizeof known / sizeof known[0] && known[op] != NULL) -- 2.7.4