* dwarf2loc.c (invalid_synthetic_pointer): Move earlier.
authorTom Tromey <tromey@redhat.com>
Mon, 6 May 2013 19:44:04 +0000 (19:44 +0000)
committerTom Tromey <tromey@redhat.com>
Mon, 6 May 2013 19:44:04 +0000 (19:44 +0000)
(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/testsuite
* 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/ChangeLog
gdb/dwarf2loc.c
gdb/dwarf2loc.h
gdb/dwarf2read.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.dwarf2/implptrconst.c [new file with mode: 0644]
gdb/testsuite/gdb.dwarf2/implptrconst.exp [new file with mode: 0644]
gdb/testsuite/lib/dwarf.exp

index e350609809b5fcfaf95201e9c2b974aaa7a178c6..f3a755d9cf4db1e7d9c240d17cefc0e49673e7ea 100644 (file)
@@ -1,3 +1,12 @@
+2013-05-06  Tom Tromey  <tromey@redhat.com>
+
+       * 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.
+
 2013-05-06  Tom Tromey  <tromey@redhat.com>
 
        * dwarf2read.c (dwarf2_const_value_data): Remove unused
index ab4ecee8244edbb9e0b48bd625d612d9e2cf75d1..9e44096f575a521e61fd6b928b80f104dfe05312 100644 (file)
@@ -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 =
index 78448e6ebafb018600a7d3dfc44e3f9aa87223c5..9bc8ca5d8fa78946b7a1c42ae04fdc339d4d4cb8 100644 (file)
@@ -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);
 
index 1154b115eee4b0c1e24077feb7c5c31687886f6a..2a5acf0df77330f93f3879fbdbcfb4c09ca9dd92 100644 (file)
@@ -17765,6 +17765,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.  */
 
index 7100b34ecaf85668a8c799c735ca484e34f95f39..0530e79bfb0824f307b807ddbff2c1843fa07e6b 100644 (file)
@@ -1,3 +1,11 @@
+2013-05-06  Tom Tromey  <tromey@redhat.com>
+
+       * 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.
+
 2013-05-03  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
 
        * gdb.base/catch-sig.c (main): Raise SIGINT.
diff --git a/gdb/testsuite/gdb.dwarf2/implptrconst.c b/gdb/testsuite/gdb.dwarf2/implptrconst.c
new file mode 100644 (file)
index 0000000..a6eef1f
--- /dev/null
@@ -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 (file)
index 0000000..4ce1713
--- /dev/null
@@ -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'"
index 5b3a1ac1ff4e2fb2b94270a69e66303bbbe17bed..2e5a3f74431d4c1c4cd2f346b115ee6d0d92c523 100644 (file)
@@ -241,6 +241,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  {
@@ -326,11 +331,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 -
@@ -591,6 +604,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] == ""} {
@@ -601,8 +616,6 @@ namespace eval Dwarf {
 
            switch -exact -- $opcode {
                DW_OP_addr {
-                   variable _cu_addr_size
-
                    _op .${_cu_addr_size}byte [lindex $line 1]
                }
 
@@ -633,6 +646,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"