This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[3/4] fix DW_OP_GNU_implicit_pointer pointing to a constant


Jakub pointed out that DW_OP_GNU_implicit_pointer can refer to a DIE
that uses DW_AT_const_value, but gdb did not handle this case.

This patch fixes the bug.  I looked at a few different approaches to
this fix, and decided on this one -- although it copies a bit of code it
turned out to be the simplest of the alternatives I looked at.

Built and regtested on x86-64 Fedora 18.
New test case included.  The new test required a minor upgrade in the
DWARF assembler.

Tom

	* dwarf2loc.c (invalid_synthetic_pointer): Move earlier.
	(indirect_pieced_value): Call dwarf2_fetch_constant_bytes
	if needed.
	* dwarf2loc.h (dwarf2_fetch_constant_bytes): Declare.
	* dwarf2read.c (write_constant_as_bytes)
	(dwarf2_fetch_constant_bytes): New functions.

	* gdb.dwarf2/implptrconst.c: New file.
	* gdb.dwarf2/implptrconst.exp: New file.
	* lib/dwarf.exp (Dwarf::_nz_quote): New proc.
	(Dwarf::_handle_DW_FORM): Handle DW_FORM_block1.
	(Dwarf::_location): Handle DW_OP_GNU_implicit_pointer.
---
 gdb/dwarf2loc.c                           |  54 ++++++++---
 gdb/dwarf2loc.h                           |   5 ++
 gdb/dwarf2read.c                          | 144 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/implptrconst.c   |  22 +++++
 gdb/testsuite/gdb.dwarf2/implptrconst.exp | 103 +++++++++++++++++++++
 gdb/testsuite/lib/dwarf.exp               |  30 ++++++-
 6 files changed, 342 insertions(+), 16 deletions(-)
 create mode 100644 gdb/testsuite/gdb.dwarf2/implptrconst.c
 create mode 100644 gdb/testsuite/gdb.dwarf2/implptrconst.exp

diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index 71220c6..90b91cc 100644
--- a/gdb/dwarf2loc.c
+++ b/gdb/dwarf2loc.c
@@ -90,6 +90,16 @@ enum debug_loc_kind
   DEBUG_LOC_INVALID_ENTRY = -2
 };
 
+/* Helper function which throws an error if a synthetic pointer is
+   invalid.  */
+
+static void
+invalid_synthetic_pointer (void)
+{
+  error (_("access outside bounds of object "
+	   "referenced via synthetic pointer"));
+}
+
 /* Decode the addresses in a non-dwo .debug_loc entry.
    A pointer to the next byte to examine is returned in *NEW_PTR.
    The encoded low,high addresses are return in *LOW,*HIGH.
@@ -2086,9 +2096,37 @@ indirect_pieced_value (struct value *value)
 				     get_frame_address_in_block_wrapper,
 				     frame);
 
-  return dwarf2_evaluate_loc_desc_full (TYPE_TARGET_TYPE (type), frame,
-					baton.data, baton.size, baton.per_cu,
-					piece->v.ptr.offset + byte_offset);
+  if (baton.data != NULL)
+    return dwarf2_evaluate_loc_desc_full (TYPE_TARGET_TYPE (type), frame,
+					  baton.data, baton.size, baton.per_cu,
+					  piece->v.ptr.offset + byte_offset);
+
+  {
+    struct obstack temp_obstack;
+    struct cleanup *cleanup;
+    const gdb_byte *bytes;
+    LONGEST len;
+    struct value *result;
+
+    obstack_init (&temp_obstack);
+    cleanup = make_cleanup_obstack_free (&temp_obstack);
+
+    bytes = dwarf2_fetch_constant_bytes (piece->v.ptr.die, c->per_cu,
+					 &temp_obstack, &len);
+    if (bytes == NULL)
+      result = allocate_optimized_out_value (TYPE_TARGET_TYPE (type));
+    else
+      {
+	if (byte_offset < 0
+	    || byte_offset + TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > len)
+	  invalid_synthetic_pointer ();
+	bytes += byte_offset;
+	result = value_from_contents (TYPE_TARGET_TYPE (type), bytes);
+      }
+
+    do_cleanups (cleanup);
+    return result;
+  }
 }
 
 static void *
@@ -2134,16 +2172,6 @@ static const struct lval_funcs pieced_value_funcs = {
   free_pieced_value_closure
 };
 
-/* Helper function which throws an error if a synthetic pointer is
-   invalid.  */
-
-static void
-invalid_synthetic_pointer (void)
-{
-  error (_("access outside bounds of object "
-	   "referenced via synthetic pointer"));
-}
-
 /* Virtual method table for dwarf2_evaluate_loc_desc_full below.  */
 
 static const struct dwarf_expr_context_funcs dwarf_expr_ctx_funcs =
diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
index 78448e6..9bc8ca5 100644
--- a/gdb/dwarf2loc.h
+++ b/gdb/dwarf2loc.h
@@ -72,6 +72,11 @@ struct dwarf2_locexpr_baton dwarf2_fetch_die_loc_cu_off
    CORE_ADDR (*get_frame_pc) (void *baton),
    void *baton);
 
+extern const gdb_byte *dwarf2_fetch_constant_bytes (sect_offset,
+						    struct dwarf2_per_cu_data *,
+						    struct obstack *,
+						    LONGEST *);
+
 struct type *dwarf2_get_die_type (cu_offset die_offset,
 				  struct dwarf2_per_cu_data *per_cu);
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 1acd6de..2108fd5 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -17751,6 +17751,150 @@ dwarf2_fetch_die_loc_cu_off (cu_offset offset_in_cu,
   return dwarf2_fetch_die_loc_sect_off (offset, per_cu, get_frame_pc, baton);
 }
 
+/* Write a constant of a given type as target-ordered bytes into
+   OBSTACK.  */
+
+static const gdb_byte *
+write_constant_as_bytes (struct obstack *obstack,
+			 enum bfd_endian byte_order,
+			 struct type *type,
+			 ULONGEST value,
+			 LONGEST *len)
+{
+  gdb_byte *result;
+
+  *len = TYPE_LENGTH (type);
+  result = obstack_alloc (obstack, *len);
+  store_unsigned_integer (result, *len, byte_order, value);
+
+  return result;
+}
+
+/* If the DIE at OFFSET in PER_CU has a DW_AT_const_value, return a
+   pointer to the constant bytes and set LEN to the length of the
+   data.  If memory is needed, allocate it on OBSTACK.  If the DIE
+   does not have a DW_AT_const_value, return NULL.  */
+
+const gdb_byte *
+dwarf2_fetch_constant_bytes (sect_offset offset,
+			     struct dwarf2_per_cu_data *per_cu,
+			     struct obstack *obstack,
+			     LONGEST *len)
+{
+  struct dwarf2_cu *cu;
+  struct die_info *die;
+  struct attribute *attr;
+  const gdb_byte *result = NULL;
+  struct type *type;
+  LONGEST value;
+  enum bfd_endian byte_order;
+
+  dw2_setup (per_cu->objfile);
+
+  if (per_cu->cu == NULL)
+    load_cu (per_cu);
+  cu = per_cu->cu;
+
+  die = follow_die_offset (offset, per_cu->is_dwz, &cu);
+  if (!die)
+    error (_("Dwarf Error: Cannot find DIE at 0x%x referenced in module %s"),
+	   offset.sect_off, per_cu->objfile->name);
+
+
+  attr = dwarf2_attr (die, DW_AT_const_value, cu);
+  if (attr == NULL)
+    return NULL;
+
+  byte_order = (bfd_big_endian (per_cu->objfile->obfd)
+		? BFD_ENDIAN_BIG : BFD_ENDIAN_LITTLE);
+
+  switch (attr->form)
+    {
+    case DW_FORM_addr:
+    case DW_FORM_GNU_addr_index:
+      {
+	gdb_byte *tem;
+
+	*len = cu->header.addr_size;
+	tem = obstack_alloc (obstack, *len);
+	store_unsigned_integer (tem, *len, byte_order, DW_ADDR (attr));
+	result = tem;
+      }
+      break;
+    case DW_FORM_string:
+    case DW_FORM_strp:
+    case DW_FORM_GNU_str_index:
+    case DW_FORM_GNU_strp_alt:
+      /* DW_STRING is already allocated on the objfile obstack, point
+	 directly to it.  */
+      result = (const gdb_byte *) DW_STRING (attr);
+      *len = strlen (DW_STRING (attr));
+      break;
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+    case DW_FORM_block:
+    case DW_FORM_exprloc:
+      result = DW_BLOCK (attr)->data;
+      *len = DW_BLOCK (attr)->size;
+      break;
+
+      /* The DW_AT_const_value attributes are supposed to carry the
+	 symbol's value "represented as it would be on the target
+	 architecture."  By the time we get here, it's already been
+	 converted to host endianness, so we just need to sign- or
+	 zero-extend it as appropriate.  */
+    case DW_FORM_data1:
+      type = die_type (die, cu);
+      result = dwarf2_const_value_data (attr, obstack, cu, &value, 8);
+      if (result == NULL)
+	result = write_constant_as_bytes (obstack, byte_order,
+					  type, value, len);
+      break;
+    case DW_FORM_data2:
+      type = die_type (die, cu);
+      result = dwarf2_const_value_data (attr, obstack, cu, &value, 16);
+      if (result == NULL)
+	result = write_constant_as_bytes (obstack, byte_order,
+					  type, value, len);
+      break;
+    case DW_FORM_data4:
+      type = die_type (die, cu);
+      result = dwarf2_const_value_data (attr, obstack, cu, &value, 32);
+      if (result == NULL)
+	result = write_constant_as_bytes (obstack, byte_order,
+					  type, value, len);
+      break;
+    case DW_FORM_data8:
+      type = die_type (die, cu);
+      result = dwarf2_const_value_data (attr, obstack, cu, &value, 64);
+      if (result == NULL)
+	result = write_constant_as_bytes (obstack, byte_order,
+					  type, value, len);
+      break;
+
+    case DW_FORM_sdata:
+      type = die_type (die, cu);
+      result = write_constant_as_bytes (obstack, byte_order,
+					type, DW_SND (attr), len);
+      break;
+
+    case DW_FORM_udata:
+      type = die_type (die, cu);
+      result = write_constant_as_bytes (obstack, byte_order,
+					type, DW_UNSND (attr), len);
+      break;
+
+    default:
+      complaint (&symfile_complaints,
+		 _("unsupported const value attribute form: '%s'"),
+		 dwarf_form_name (attr->form));
+      break;
+    }
+
+  return result;
+}
+
 /* Return the type of the DIE at DIE_OFFSET in the CU named by
    PER_CU.  */
 
diff --git a/gdb/testsuite/gdb.dwarf2/implptrconst.c b/gdb/testsuite/gdb.dwarf2/implptrconst.c
new file mode 100644
index 0000000..a6eef1f
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/implptrconst.c
@@ -0,0 +1,22 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2013 Free Software Foundation, Inc.
+
+   This program 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.
+
+   This program 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/>.  */
+
+int
+main ()
+{
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.dwarf2/implptrconst.exp b/gdb/testsuite/gdb.dwarf2/implptrconst.exp
new file mode 100644
index 0000000..4ce1713
--- /dev/null
+++ b/gdb/testsuite/gdb.dwarf2/implptrconst.exp
@@ -0,0 +1,103 @@
+# Copyright 2013 Free Software Foundation, Inc.
+
+# This program 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.
+#
+# This program 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/>.
+
+load_lib dwarf.exp
+
+# This test can only be run on targets which support DWARF-2 and use gas.
+if {![dwarf2_support]} {
+    return 0  
+}
+
+if { [skip_cplus_tests] } { continue }
+
+standard_testfile .c implptrconst-dw.S
+
+# Make some DWARF for the test.
+set asm_file [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file {
+    cu 0 2 8 {
+ 	compile_unit {} {
+	    declare_labels byte_label size_type_label array_label
+	    declare_labels var_label ptr_label
+
+	    byte_label: base_type {
+		{name byte}
+		{encoding @DW_ATE_signed}
+		{byte_size 1 DW_FORM_sdata}
+	    }
+
+	    size_type_label: base_type {
+		{name sizetype}
+		{encoding @DW_ATE_unsigned}
+		{byte_size 8 DW_FORM_sdata}
+	    }
+
+	    array_label: array_type {
+		{type :$byte_label}
+	    } {
+		subrange_type {
+		    {type :$size_type_label}
+		    {upper_bound 7 DW_FORM_data1}
+		}
+	    }
+
+	    var_label: DW_TAG_variable {
+		{name b}
+		{type :$array_label}
+		{const_value rstuvwxy DW_FORM_block1}
+	    }
+
+	    ptr_label: pointer_type {
+		{byte_size 8 DW_FORM_sdata}
+		{type :$byte_label}
+	    }
+
+	    DW_TAG_variable {
+		{name c}
+		{type :$ptr_label}
+		{location {
+		    GNU_implicit_pointer $var_label 0
+		} SPECIAL_expr}
+	    }
+	}
+    }
+}
+
+if  {[gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \
+	  object {nodebug}] != ""} {
+    return -1
+}
+
+if  {[gdb_compile $asm_file ${binfile}2.o object {nodebug}] != ""} {
+    return -1
+}
+
+if  {[gdb_compile [list ${binfile}1.o ${binfile}2.o] \
+	  "${binfile}" executable {}] != ""} {
+    return -1
+}
+
+# We need --readnow because otherwise we never read in the CU we
+# created above.
+set saved_gdbflags $GDBFLAGS
+set GDBFLAGS "$GDBFLAGS -readnow"
+clean_restart ${testfile}
+set GDBFLAGS $saved_gdbflags
+
+if ![runto_main] {
+    return -1
+}
+
+gdb_test "print *c" " = 114 'r'"
diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp
index bb58997..9272f9c 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -238,6 +238,11 @@ namespace eval Dwarf {
 	return "\"${string}\\0\""
     }
 
+    proc _nz_quote {string} {
+	# For now, no quoting is done.
+	return "\"${string}\""
+    }
+
     proc _handle_DW_FORM {form value} {
 	switch -exact -- $form {
 	    DW_FORM_string  {
@@ -323,11 +328,19 @@ namespace eval Dwarf {
 		define_label $l2
 	    }
 
+	    DW_FORM_block1 {
+		set len [string length $value]
+		if {$len > 255} {
+		    error "DW_FORM_block1 length too long"
+		}
+		_op .byte $len
+		_op .ascii [_nz_quote $value]
+	    }
+
 	    DW_FORM_block2 -
 	    DW_FORM_block4 -
 
 	    DW_FORM_block -
-	    DW_FORM_block1 -
 
 	    DW_FORM_ref2 -
 	    DW_FORM_indirect -
@@ -588,6 +601,8 @@ namespace eval Dwarf {
     # FIXME move docs
     proc _location {body} {
 	variable _constants
+	variable _cu_label
+	variable _cu_addr_size
 
 	foreach line [split $body \n] {
 	    if {[lindex $line 0] == ""} {
@@ -598,8 +613,6 @@ namespace eval Dwarf {
 
 	    switch -exact -- $opcode {
 		DW_OP_addr {
-		    variable _cu_addr_size
-
 		    _op .${_cu_addr_size}byte [lindex $line 1]
 		}
 
@@ -630,6 +643,17 @@ namespace eval Dwarf {
 		    _op .sleb128 [lindex $line 1]
 		}
 
+		DW_OP_GNU_implicit_pointer {
+		    if {[llength $line] != 3} {
+			error "usage: DW_OP_GNU_implicit_pointer LABEL OFFSET"
+		    }
+
+		    # Here label is a section offset.
+		    set label [lindex $line 1]
+		    _op .${_cu_addr_size}byte $label
+		    _op .sleb128 [lindex $line 2]
+		}
+
 		default {
 		    if {[llength $line] > 1} {
 			error "Unimplemented: operands in location for $opcode"
-- 
1.8.1.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]