aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2013-05-06 19:44:04 +0000
committerTom Tromey <tromey@redhat.com>2013-05-06 19:44:04 +0000
commitb6807d988a28dc2718bae1abba1f28779bc0c3c3 (patch)
treebb4adece022138ab739318623eec8dce672a03b8
parent3aef2284c6976e2b497d5e712cf0cedcc14bed58 (diff)
downloadgdb-b6807d988a28dc2718bae1abba1f28779bc0c3c3.zip
gdb-b6807d988a28dc2718bae1abba1f28779bc0c3c3.tar.gz
gdb-b6807d988a28dc2718bae1abba1f28779bc0c3c3.tar.bz2
* 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/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.
-rw-r--r--gdb/ChangeLog9
-rw-r--r--gdb/dwarf2loc.c54
-rw-r--r--gdb/dwarf2loc.h5
-rw-r--r--gdb/dwarf2read.c144
-rw-r--r--gdb/testsuite/ChangeLog8
-rw-r--r--gdb/testsuite/gdb.dwarf2/implptrconst.c22
-rw-r--r--gdb/testsuite/gdb.dwarf2/implptrconst.exp103
-rw-r--r--gdb/testsuite/lib/dwarf.exp30
8 files changed, 359 insertions, 16 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index e350609..f3a755d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,14 @@
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
parameters.
(dwarf2_const_value_attr): Update.
diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
index ab4ecee..9e44096 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 1154b11..2a5acf0 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -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. */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 7100b34..0530e79 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -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
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 5b3a1ac..2e5a3f7 100644
--- a/gdb/testsuite/lib/dwarf.exp
+++ b/gdb/testsuite/lib/dwarf.exp
@@ -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"