From b6807d988a28dc2718bae1abba1f28779bc0c3c3 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 6 May 2013 19:44:04 +0000 Subject: [PATCH] * 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. --- gdb/ChangeLog | 9 ++ gdb/dwarf2loc.c | 54 ++++++-- gdb/dwarf2loc.h | 5 + gdb/dwarf2read.c | 144 ++++++++++++++++++++++ gdb/testsuite/ChangeLog | 8 ++ gdb/testsuite/gdb.dwarf2/implptrconst.c | 22 ++++ gdb/testsuite/gdb.dwarf2/implptrconst.exp | 103 ++++++++++++++++ gdb/testsuite/lib/dwarf.exp | 30 ++++- 8 files changed, 359 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/ChangeLog b/gdb/ChangeLog index e350609809..f3a755d9cf 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,12 @@ +2013-05-06 Tom Tromey + + * 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 * dwarf2read.c (dwarf2_const_value_data): Remove unused diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index ab4ecee824..9e44096f57 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 78448e6eba..9bc8ca5d8f 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 1154b115ee..2a5acf0df7 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 7100b34eca..0530e79bfb 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2013-05-06 Tom Tromey + + * 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 * 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 0000000000..a6eef1f568 --- /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 . */ + +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 0000000000..4ce1713503 --- /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 . + +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 5b3a1ac1ff..2e5a3f7443 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" -- 2.34.1