public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value.
@ 2017-11-04 23:31 Mark Wielaard
  2017-11-04 23:31 ` [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation Mark Wielaard
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Mark Wielaard @ 2017-11-04 23:31 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Mark Wielaard

Also format both DW_OP_call_ref and DW_OP_GNU_variable_value argument
as a normal DIE reference.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog | 4 ++++
 libdw/dwarf.h   | 1 +
 src/ChangeLog   | 5 +++++
 src/readelf.c   | 5 +++--
 4 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index e6e7f3b..7085649 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,7 @@
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* dwarf.h: Add DW_OP_GNU_variable_value.
+
 2017-10-03  Mark Wielaard  <mark@klomp.org>
 
 	* libdw.h: Define LIBDW_CIE_ID and use it in dwarf_cfi_cie_p.
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 902d261..8edf719 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -545,6 +545,7 @@ enum
     DW_OP_GNU_convert = 0xf7,
     DW_OP_GNU_reinterpret = 0xf9,
     DW_OP_GNU_parameter_ref = 0xfa,
+    DW_OP_GNU_variable_value = 0xfd,
 
     DW_OP_lo_user = 0xe0,	/* Implementation-defined range start.  */
     DW_OP_hi_user = 0xff	/* Implementation-defined range end.  */
diff --git a/src/ChangeLog b/src/ChangeLog
index 0d3bfc1..3b886a7 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* readelf.c (print_ops): Handle DW_OP_GNU_variable_value. Print
+	referenced DIE as offset.
+
 2017-09-10  Mark Wielaard  <mark@klomp.org>
 
 	* ar.c (do_oper_delete): Remove DEBUG conditional check.
diff --git a/src/readelf.c b/src/readelf.c
index 5e2f3fc..833884b 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4160,6 +4160,7 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	  break;
 
 	case DW_OP_call_ref:
+	case DW_OP_GNU_variable_value:
 	  /* Offset operand.  */
 	  if (ref_size != 4 && ref_size != 8)
 	    goto invalid; /* Cannot be used in CFA.  */
@@ -4170,8 +4171,8 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
 	    addr = read_8ubyte_unaligned (dbg, data);
 	  data += ref_size;
 	  CONSUME (ref_size);
-
-	  printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
+	  /* addr is a DIE offset, so format it as one.  */
+	  printf ("%*s[%4" PRIuMAX "] %s [%6" PRIxMAX "]\n",
 		  indent, "", (uintmax_t) offset,
 		  op_name, (uintmax_t) addr);
 	  offset += 1 + ref_size;
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation.
  2017-11-04 23:31 [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value Mark Wielaard
@ 2017-11-04 23:31 ` Mark Wielaard
  2017-11-10 15:38   ` Mark Wielaard
  2017-11-04 23:31 ` [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value Mark Wielaard
  2017-11-10 15:38 ` [PATCH 1/3] readelf: " Mark Wielaard
  2 siblings, 1 reply; 6+ messages in thread
From: Mark Wielaard @ 2017-11-04 23:31 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Mark Wielaard

dwarf_getlocation has to know which attributes can contain a DWARF
expression or location list because the form alone might be ambiguous.

Since DWARF4 there is DW_FORM_exprloc so always accept that. But for older
DWARF or location lists we cannot just check for DW_FORM_sec_offset since
that could be a reference to diffent kinds of sections (based on attribute).

Update the attribute list based on the latest DWARF5 encodings table.
Note that DW_AT_call_origin wasn't added because that seems to be a
typo in the DWARF5 spec. http://dwarfstd.org/ShowIssue.php?issue=171103.1

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog           |  5 +++++
 libdw/dwarf_getlocation.c | 26 +++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 7085649..bb9e849 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,10 @@
 2017-11-03  Mark Wielaard  <mark@klomp.org>
 
+	* dwarf_getlocation.c (attr_ok): Always accept DW_FORM_exprloc.
+	Update list of acceptable attribute codes based on DWARF5.
+
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
 	* dwarf.h: Add DW_OP_GNU_variable_value.
 
 2017-10-03  Mark Wielaard  <mark@klomp.org>
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index a4a2761..c59546e 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -45,10 +45,34 @@ attr_ok (Dwarf_Attribute *attr)
   if (attr == NULL)
     return false;
 
-  /* Must be one of the attributes listed below.  */
+  /* If it is an exprloc, it is obviously OK.  */
+  if (dwarf_whatform (attr) == DW_FORM_exprloc)
+    return true;
+
+  /* Otherwise must be one of the attributes listed below.  Older
+     DWARF versions might have encoded the exprloc as block, and we
+     cannot easily distinquish attributes in the loclist class because
+     the same forms are used for different classes.  */
   switch (attr->code)
     {
     case DW_AT_location:
+    case DW_AT_byte_size:
+    case DW_AT_bit_offset:
+    case DW_AT_bit_size:
+    case DW_AT_lower_bound:
+    case DW_AT_bit_stride:
+    case DW_AT_upper_bound:
+    case DW_AT_count:
+    case DW_AT_allocated:
+    case DW_AT_associated:
+    case DW_AT_data_location:
+    case DW_AT_byte_stride:
+    case DW_AT_rank:
+    case DW_AT_call_value:
+    case DW_AT_call_target:
+    case DW_AT_call_target_clobbered:
+    case DW_AT_call_data_location:
+    case DW_AT_call_data_value:
     case DW_AT_data_member_location:
     case DW_AT_vtable_elem_location:
     case DW_AT_string_length:
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value.
  2017-11-04 23:31 [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value Mark Wielaard
  2017-11-04 23:31 ` [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation Mark Wielaard
@ 2017-11-04 23:31 ` Mark Wielaard
  2017-11-10 15:38   ` Mark Wielaard
  2017-11-10 15:38 ` [PATCH 1/3] readelf: " Mark Wielaard
  2 siblings, 1 reply; 6+ messages in thread
From: Mark Wielaard @ 2017-11-04 23:31 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Mark Wielaard

Handle DW_OP_GNU_variable_value in dwarf_getlocation[_attr,_die].
DW_OP_GNU_variable_value takes one argument a DIE reference that
describes a value given by a location of const_value attribute.

To test handling of the new operand the varlocs test is adapted
to print out all DIEs and attributes with expressions or location
lists (the original varlocs test only prints out variables and
arguments of function DIEs).

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog                |   7 ++
 libdw/dwarf_getlocation.c      |   1 +
 libdw/dwarf_getlocation_attr.c |   1 +
 libdw/dwarf_getlocation_die.c  |   1 +
 tests/ChangeLog                |  16 +++
 tests/Makefile.am              |   4 +-
 tests/run-exprlocs.sh          | 180 ++++++++++++++++++++++++++++++++
 tests/testfile-stridex.bz2     | Bin 0 -> 4009 bytes
 tests/varlocs.c                | 228 ++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 431 insertions(+), 7 deletions(-)
 create mode 100755 tests/run-exprlocs.sh
 create mode 100755 tests/testfile-stridex.bz2

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index bb9e849..4375244 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,12 @@
 2017-11-03  Mark Wielaard  <mark@klomp.org>
 
+	* dwarf_getlocation.c (__libdw_intern_expression): Handle
+	DW_OP_GNU_variable_value.
+	* dwarf_getlocation_attr.c (dwarf_getlocation_attr): Likewise.
+	* dwarf_getlocation_die.c (dwarf_getlocation_die): Likewise.
+
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
 	* dwarf_getlocation.c (attr_ok): Always accept DW_FORM_exprloc.
 	Update list of acceptable attribute codes based on DWARF5.
 
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index c59546e..86a9ae7 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -323,6 +323,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 	  break;
 
 	case DW_OP_call_ref:
+	case DW_OP_GNU_variable_value:
 	  /* DW_FORM_ref_addr, depends on offset size of CU.  */
 	  if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
 						      ref_size,
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index 8b6a4af..e4dd708 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -97,6 +97,7 @@ dwarf_getlocation_attr (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Attribu
 	break;
 
       case DW_OP_GNU_implicit_pointer:
+      case DW_OP_GNU_variable_value:
 	{
 	  Dwarf_Die die;
 	  if (INTUSE(dwarf_getlocation_die) (attr, op, &die) != 0)
diff --git a/libdw/dwarf_getlocation_die.c b/libdw/dwarf_getlocation_die.c
index b4908d2..21b4365 100644
--- a/libdw/dwarf_getlocation_die.c
+++ b/libdw/dwarf_getlocation_die.c
@@ -45,6 +45,7 @@ dwarf_getlocation_die (Dwarf_Attribute *attr, const Dwarf_Op *op,
     {
     case DW_OP_GNU_implicit_pointer:
     case DW_OP_call_ref:
+    case DW_OP_GNU_variable_value:
       dieoff = op->number;
       break;
 
diff --git a/tests/ChangeLog b/tests/ChangeLog
index beac0e2..f39a027 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,19 @@
+2017-11-03  Mark Wielaard  <mark@klomp.org>
+
+	* run-exprlocs.sh: New test.
+	* testfile-stridex.bz2: New testfile.
+	* Makefile.am (TESTS): Add run-exprlocs.sh.
+	(EXTRA_DIST): Add run-exprlocs.sh and testfile-stridex.bz2.
+	* varlocs.c (dwarf_tag_string): New function.
+	(dwarf_attr_string): Likewise.
+	(dwarf_form_string): Likewise.
+	(print_expr): Fix typo in error message.r
+	Handle DW_OP_GNU_variable_value.
+	(attr_arg): New struct.
+	(handle_attr): New function.
+	(handle_die): Likewise.
+	(main): Handle --exprlocs argument. Call handle_die.
+
 2017-10-16  Mark Wielaard  <mark@klomp.org>
 
 	* md5-sha1-test.c: Removed.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ec42b80..f992b12 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -112,7 +112,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
 	run-dwfl-report-elf-align.sh run-addr2line-test.sh \
 	run-addr2line-i-test.sh run-addr2line-i-lex-test.sh \
 	run-addr2line-i-demangle-test.sh run-addr2line-alt-debugpath.sh \
-	run-varlocs.sh run-funcretval.sh \
+	run-varlocs.sh run-exprlocs.sh run-funcretval.sh \
 	run-backtrace-native.sh run-backtrace-data.sh run-backtrace-dwarf.sh \
 	run-backtrace-native-biarch.sh run-backtrace-native-core.sh \
 	run-backtrace-native-core-biarch.sh run-backtrace-core-x86_64.sh \
@@ -284,7 +284,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
 	     testfileppc32.bz2 testfileppc64.bz2 \
 	     testfiles390.bz2 testfiles390x.bz2 \
 	     testfilearm.bz2 testfileaarch64.bz2 \
-	     run-varlocs.sh \
+	     run-varlocs.sh run-exprlocs.sh testfile-stridex.bz2 \
 	     testfile_const_type.c testfile_const_type.bz2 \
 	     testfile_implicit_pointer.c testfile_implicit_pointer.bz2 \
 	     testfile_parameter_ref.c testfile_parameter_ref.bz2 \
diff --git a/tests/run-exprlocs.sh b/tests/run-exprlocs.sh
new file mode 100755
index 0000000..379ca52
--- /dev/null
+++ b/tests/run-exprlocs.sh
@@ -0,0 +1,180 @@
+#! /bin/sh
+# Copyright (C) 2017 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 the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77589
+#
+# program repro
+#   type small_stride
+#      character*40 long_string
+#      integer      small_pad
+#   end type small_stride
+#   type(small_stride), dimension (20), target :: unpleasant
+#   character*40, pointer, dimension(:):: c40pt
+#   integer i
+#   do i = 0,19
+#      unpleasant(i+1)%small_pad = i+1
+#      unpleasant(i+1)%long_string = char (ichar('0') + i) // '-hello'
+#   end do
+#   c40pt => unpleasant%long_string
+#   print *, c40pt  ! break-here
+# end program repro
+#
+# Needs GCC7+
+# gfortran -o testfile-stridex dwarf-stridex.f90 -Wall -g
+
+testfiles testfile-stridex
+
+testrun_compare ${abs_top_builddir}/tests/varlocs --exprlocs -e testfile-stridex <<\EOF
+module 'testfile-stridex'
+[b] CU 'dwarf-stridex.f90'@400717
+  producer (strp)
+  language (data1)
+  identifier_case (data1)
+  name (strp)
+  comp_dir (strp)
+  low_pc (addr)
+  high_pc (data8)
+  stmt_list (sec_offset)
+  [2e] base_type "integer(kind=8)"
+    byte_size (data1)
+    encoding (data1)
+    name (strp)
+  [35] structure_type "small_stride"
+    name (strp)
+    byte_size (data1)
+    decl_file (data1)
+    decl_line (data1)
+    sibling (ref4)
+    [41] member "long_string"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      data_member_location (data1) {plus_uconst(0)}
+    [4d] member "small_pad"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      data_member_location (data1) {plus_uconst(40)}
+  [5a] string_type
+    byte_size (data1)
+  [5c] base_type "integer(kind=4)"
+    byte_size (data1)
+    encoding (data1)
+    name (strp)
+  [63] const_type
+    type (ref4)
+  [68] subprogram "main"
+    external (flag_present)
+    name (strp)
+    decl_file (data1)
+    decl_line (data1)
+    type (ref4)
+    low_pc (addr)
+    high_pc (data8)
+    frame_base (exprloc) {call_frame_cfa {bregx(7,8)}}
+    GNU_all_tail_call_sites (flag_present)
+    sibling (ref4)
+    [89] formal_parameter "argc"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      location (exprloc) {fbreg(-20)}
+    [97] formal_parameter "argv"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      location (exprloc) {fbreg(-32), deref}
+  [a7] pointer_type
+    byte_size (data1)
+    type (ref4)
+  [ad] base_type "character(kind=1)"
+    byte_size (data1)
+    encoding (data1)
+    name (strp)
+  [b4] subprogram "repro"
+    name (strp)
+    decl_file (data1)
+    decl_line (data1)
+    main_subprogram (flag_present)
+    calling_convention (data1)
+    low_pc (addr)
+    high_pc (data8)
+    frame_base (exprloc) {call_frame_cfa {bregx(7,8)}}
+    GNU_all_tail_call_sites (flag_present)
+    sibling (ref4)
+    [d2] variable "c40pt"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      location (exprloc) {fbreg(-128)}
+    [e1] variable "span.0"
+      name (strp)
+      type (ref4)
+      artificial (flag_present)
+      location (exprloc) {fbreg(-80)}
+    [ee] variable "i"
+      name (string)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      location (exprloc) {fbreg(-68)}
+    [fb] variable "unpleasant"
+      name (strp)
+      decl_file (data1)
+      decl_line (data1)
+      type (ref4)
+      location (exprloc) {fbreg(-1008)}
+    [10a] lexical_block
+      low_pc (addr)
+      high_pc (data8)
+      sibling (ref4)
+      [11f] lexical_block
+        low_pc (addr)
+        high_pc (data8)
+    [131] lexical_block
+      low_pc (addr)
+      high_pc (data8)
+      [142] lexical_block
+        low_pc (addr)
+        high_pc (data8)
+        [153] lexical_block
+          low_pc (addr)
+          high_pc (data8)
+  [167] array_type
+    data_location (exprloc) {push_object_address, deref}
+    associated (exprloc) {push_object_address, deref, lit0, ne}
+    type (ref4)
+    sibling (ref4)
+    [178] subrange_type
+      lower_bound (exprloc) {push_object_address, plus_uconst(32), deref}
+      upper_bound (exprloc) {push_object_address, plus_uconst(40), deref}
+      byte_stride (exprloc) {push_object_address, plus_uconst(24), deref, GNU_variable_value([e1]) {fbreg(-80)}, mul}
+  [18f] array_type
+    type (ref4)
+    [194] subrange_type
+      type (ref4)
+      upper_bound (sdata)
+EOF
+
+exit 0
diff --git a/tests/testfile-stridex.bz2 b/tests/testfile-stridex.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..ff909f4a9d0fa7b32776efabd1e0db6c076732ca
GIT binary patch
literal 4009
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
PfAM!DQ-ui&r9mdp$sABy

literal 0
HcmV?d00001

diff --git a/tests/varlocs.c b/tests/varlocs.c
index c3fba89..cc77559 100644
--- a/tests/varlocs.c
+++ b/tests/varlocs.c
@@ -75,6 +75,45 @@ dwarf_encoding_string (unsigned int code)
   return NULL;
 }
 
+static const char *
+dwarf_tag_string (unsigned int tag)
+{
+  switch (tag)
+    {
+#define DWARF_ONE_KNOWN_DW_TAG(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_TAG
+#undef DWARF_ONE_KNOWN_DW_TAG
+    default:
+      return NULL;
+    }
+}
+
+static const char *
+dwarf_attr_string (unsigned int attrnum)
+{
+  switch (attrnum)
+    {
+#define DWARF_ONE_KNOWN_DW_AT(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_AT
+#undef DWARF_ONE_KNOWN_DW_AT
+    default:
+      return NULL;
+    }
+}
+
+static const char *
+dwarf_form_string (unsigned int form)
+{
+  switch (form)
+    {
+#define DWARF_ONE_KNOWN_DW_FORM(NAME, CODE) case CODE: return #NAME;
+      DWARF_ALL_KNOWN_DW_FORM
+#undef DWARF_ONE_KNOWN_DW_FORM
+    default:
+      return NULL;
+    }
+}
+
 /* BASE must be a base type DIE referenced by a typed DWARF expression op.  */
 static void
 print_base_type (Dwarf_Die *base)
@@ -386,7 +425,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
 
 	Dwarf_Die impl_die;
 	if (dwarf_getlocation_die (attr, expr, &impl_die) != 0)
-	  error (EXIT_FAILURE, 0, "dwarf_getlocation_due: %s",
+	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
 		 dwarf_errmsg (-1));
 
 	printf ("%s([%" PRIx64 "],%" PRId64 ") ", opname,
@@ -413,6 +452,46 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
       }
       break;
 
+    case DW_OP_GNU_variable_value:
+      /* Special, DIE offset. Referenced DIE has a location or const_value
+	 attribute. */
+      {
+	if (attr == NULL)
+	  error (EXIT_FAILURE, 0, "%s used in CFI", opname);
+
+	Dwarf_Attribute attrval;
+	if (dwarf_getlocation_attr (attr, expr, &attrval) != 0)
+	  error (EXIT_FAILURE, 0, "dwarf_getlocation_attr: %s",
+		 dwarf_errmsg (-1));
+
+	Dwarf_Die impl_die;
+	if (dwarf_getlocation_die (attr, expr, &impl_die) != 0)
+	  error (EXIT_FAILURE, 0, "dwarf_getlocation_die: %s",
+		 dwarf_errmsg (-1));
+
+	printf ("%s([%" PRIx64 "]) ", opname, dwarf_dieoffset (&impl_die));
+
+	if (dwarf_whatattr (&attrval) == DW_AT_const_value)
+	  printf ("<constant value>"); // Lookup type...
+	else
+	  {
+	    // Lookup the location description at the current address.
+	    Dwarf_Op *exprval;
+	    size_t exprval_len;
+	    int locs = dwarf_getlocation_addr (&attrval, addr,
+					       &exprval, &exprval_len, 1);
+	    if (locs == 0)
+	      printf ("<no location>"); // This means "optimized out".
+	    else if (locs == 1)
+	      print_expr_block (&attrval, exprval, exprval_len, addr);
+	    else
+	      error (EXIT_FAILURE, 0,
+		     "dwarf_getlocation_addr attrval at addr 0x%" PRIx64
+		     ", locs (%d): %s", addr, locs, dwarf_errmsg (-1));
+	  }
+      }
+      break;
+
     case DW_OP_GNU_entry_value:
       /* Special, unsigned size plus expression block. All registers
 	 inside the block should be interpreted as they had on
@@ -759,9 +838,133 @@ handle_function (Dwarf_Die *funcdie, void *arg __attribute__((unused)))
   return DWARF_CB_OK;
 }
 
+struct attr_arg
+{
+  int depth;
+  Dwarf_Addr entrypc;
+};
+
+static int
+handle_attr (Dwarf_Attribute *attr, void *arg)
+{
+  int depth = ((struct attr_arg *) arg)->depth;
+  Dwarf_Addr entrypc = ((struct attr_arg *) arg)->entrypc;
+
+  unsigned int code = dwarf_whatattr (attr);
+  unsigned int form = dwarf_whatform (attr);
+
+  printf ("%*s%s (%s)", depth * 2, "",
+	  dwarf_attr_string (code), dwarf_form_string (form));
+
+  /* If we can get an DWARF expression (or location lists) from this
+     attribute we'll print it, otherwise we'll ignore it.  But if
+     there is an error while the attribute has the "correct" form then
+     we'll report an error (we can only really check DW_FORM_exprloc
+     other forms can be ambiguous).  */
+  Dwarf_Op *expr;
+  size_t exprlen;
+  bool printed = false;
+  int res = dwarf_getlocation (attr, &expr, &exprlen);
+  if (res == 0)
+    {
+      printf (" ");
+      print_expr_block (attr, expr, exprlen, entrypc);
+      printf ("\n");
+      printed = true;
+    }
+  else if (form == DW_FORM_exprloc)
+    {
+      error (0, 0, "%s dwarf_getlocation failed: %s",
+	     dwarf_attr_string (code), dwarf_errmsg (-1));
+      return DWARF_CB_ABORT;
+    }
+  else
+    {
+      Dwarf_Addr base, begin, end;
+      ptrdiff_t offset = 0;
+      while ((offset = dwarf_getlocations (attr, offset,
+					   &base, &begin, &end,
+					   &expr, &exprlen)) > 0)
+	{
+	  if (! printed)
+	    printf ("\n");
+	  printf ("%*s", depth * 2, "");
+	  print_expr_block_addrs (attr, begin, end, expr, exprlen);
+	  printed = true;
+	}
+    }
+
+  if (! printed)
+    printf ("\n");
+
+  return DWARF_CB_OK;
+}
+
+static void
+handle_die (Dwarf_Die *die, int depth, bool outer_has_frame_base,
+	    Dwarf_Addr outer_entrypc)
+{
+  /* CU DIE already printed.  */
+  if (depth > 0)
+    {
+      const char *name = dwarf_diename (die);
+      if (name != NULL)
+	printf ("%*s[%" PRIx64 "] %s \"%s\"\n", depth * 2, "",
+		dwarf_dieoffset (die), dwarf_tag_string (dwarf_tag (die)),
+		name);
+      else
+	printf ("%*s[%" PRIx64 "] %s\n", depth * 2, "",
+		dwarf_dieoffset (die), dwarf_tag_string (dwarf_tag (die)));
+    }
+
+  struct attr_arg arg;
+  arg.depth = depth + 1;
+
+  /* The (lowest) address to use for (looking up) operands that depend
+     on address.  */
+  Dwarf_Addr die_entrypc;
+  if (dwarf_entrypc (die, &die_entrypc) != 0 || die_entrypc == 0)
+    die_entrypc = outer_entrypc;
+  arg.entrypc = die_entrypc;
+
+  /* Whether this or the any outer DIE has a frame base. Used as
+     sanity check when printing experssions that use DW_OP_fbreg.  */
+  bool die_has_frame_base = dwarf_hasattr (die, DW_AT_frame_base);
+  die_has_frame_base |= outer_has_frame_base;
+  has_frame_base = die_has_frame_base;
+
+  /* Look through all attributes to find those that contain DWARF
+     expressions and print those.  We expect to handle all attributes,
+     anything else is an error.  */
+  if (dwarf_getattrs (die, handle_attr, &arg, 0) != 1)
+    error (EXIT_FAILURE, 0, "Couldn't get all attributes: %s",
+	   dwarf_errmsg (-1));
+
+  /* Handle children and siblings recursively depth first.  */
+  Dwarf_Die child;
+  if (dwarf_haschildren (die) != 0 && dwarf_child (die, &child) == 0)
+    handle_die (&child, depth + 1, die_has_frame_base, die_entrypc);
+
+  Dwarf_Die sibling;
+  if (dwarf_siblingof (die, &sibling) == 0)
+    handle_die (&sibling, depth, outer_has_frame_base, outer_entrypc);
+}
+
 int
 main (int argc, char *argv[])
 {
+  /* With --exprlocs we process all DIEs looking for any attribute
+     which contains an DWARF expression (but not location lists) and
+     print those.  Otherwise we process all function DIEs and print
+     all DWARF expressions and location lists associated with
+     parameters and variables). */
+  bool exprlocs = false;
+  if (argc > 1 && strcmp ("--exprlocs", argv[1]) == 0)
+    {
+      exprlocs = true;
+      argv[1] = "";
+    }
+
   int remaining;
   Dwfl *dwfl;
   (void) argp_parse (dwfl_standard_argp (), argc, argv, 0, &remaining,
@@ -773,10 +976,11 @@ main (int argc, char *argv[])
   while ((cu = dwfl_nextcu (dwfl, cu, &dwbias)) != NULL)
     {
       /* Only walk actual compile units (not partial units) that
-	 contain code.  */
+	 contain code if we are only interested in the function variable
+	 locations.  */
       Dwarf_Addr cubase;
       if (dwarf_tag (cu) == DW_TAG_compile_unit
-	  && dwarf_lowpc (cu, &cubase) == 0)
+	  && (exprlocs || dwarf_lowpc (cu, &cubase) == 0))
 	{
 	  Dwfl_Module *mod = dwfl_cumodule (cu);
 	  Dwarf_Addr modbias;
@@ -806,14 +1010,28 @@ main (int argc, char *argv[])
 	  cfi_eh = dwarf_getcfi_elf (elf);
 	  cfi_eh_bias = dwbias - elfbias;
 
-	  // Get the actual CU DIE and walk all functions inside it.
+	  // Get the actual CU DIE and walk all all DIEs (or just the
+	  // functions) inside it.
 	  Dwarf_Die cudie;
 	  uint8_t offsize;
 	  uint8_t addrsize;
 	  if (dwarf_diecu (cu, &cudie, &addrsize, &offsize) == NULL)
 	    error (EXIT_FAILURE, 0, "dwarf_diecu %s", dwarf_errmsg (-1));
 
-	  if (dwarf_getfuncs (cu, handle_function, NULL, 0) != 0)
+	  if (exprlocs)
+	    {
+	      Dwarf_Addr entrypc;
+	      if (dwarf_entrypc (cu, &entrypc) != 0)
+		entrypc = 0;
+
+	      /* XXX - Passing true for has_frame_base is not really true.
+		 We do it because we want to resolve all DIEs and all
+		 attributes. Technically we should check that the DIE
+		 (types) are referenced from variables that are defined in
+		 a context (function) that has a frame base.  */
+	      handle_die (cu, 0, true /* Should be false */, entrypc);
+	    }
+	  else if (dwarf_getfuncs (cu, handle_function, NULL, 0) != 0)
 	    error (EXIT_FAILURE, 0, "dwarf_getfuncs %s",
 		   dwarf_errmsg (-1));
 	}
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value.
  2017-11-04 23:31 [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value Mark Wielaard
  2017-11-04 23:31 ` [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation Mark Wielaard
  2017-11-04 23:31 ` [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value Mark Wielaard
@ 2017-11-10 15:38 ` Mark Wielaard
  2 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2017-11-10 15:38 UTC (permalink / raw)
  To: elfutils-devel

On Sun, 2017-11-05 at 00:31 +0100, Mark Wielaard wrote:
> Also format both DW_OP_call_ref and DW_OP_GNU_variable_value argument
> as a normal DIE reference.

Pushed to master.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation.
  2017-11-04 23:31 ` [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation Mark Wielaard
@ 2017-11-10 15:38   ` Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2017-11-10 15:38 UTC (permalink / raw)
  To: elfutils-devel

On Sun, 2017-11-05 at 00:31 +0100, Mark Wielaard wrote:
> dwarf_getlocation has to know which attributes can contain a DWARF
> expression or location list because the form alone might be ambiguous.
> 
> Since DWARF4 there is DW_FORM_exprloc so always accept that. But for older
> DWARF or location lists we cannot just check for DW_FORM_sec_offset since
> that could be a reference to diffent kinds of sections (based on attribute).
> 
> Update the attribute list based on the latest DWARF5 encodings table.
> Note that DW_AT_call_origin wasn't added because that seems to be a
> typo in the DWARF5 spec. http://dwarfstd.org/ShowIssue.php?issue=171103.1

Pushed to master.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value.
  2017-11-04 23:31 ` [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value Mark Wielaard
@ 2017-11-10 15:38   ` Mark Wielaard
  0 siblings, 0 replies; 6+ messages in thread
From: Mark Wielaard @ 2017-11-10 15:38 UTC (permalink / raw)
  To: elfutils-devel

On Sun, 2017-11-05 at 00:31 +0100, Mark Wielaard wrote:
> Handle DW_OP_GNU_variable_value in dwarf_getlocation[_attr,_die].
> DW_OP_GNU_variable_value takes one argument a DIE reference that
> describes a value given by a location of const_value attribute.
> 
> To test handling of the new operand the varlocs test is adapted
> to print out all DIEs and attributes with expressions or location
> lists (the original varlocs test only prints out variables and
> arguments of function DIEs).

Pushed to master.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2017-11-10 15:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-04 23:31 [PATCH 1/3] readelf: Handle DW_OP_GNU_variable_value Mark Wielaard
2017-11-04 23:31 ` [PATCH 2/3] libdw: Update acceptable forms and attributes for dwarf_getlocation Mark Wielaard
2017-11-10 15:38   ` Mark Wielaard
2017-11-04 23:31 ` [PATCH 3/3] libdw: Handle DW_OP_GNU_variable_value Mark Wielaard
2017-11-10 15:38   ` Mark Wielaard
2017-11-10 15:38 ` [PATCH 1/3] readelf: " Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).