diff options
author | Martin Galvan <martin.galvan@tallertechnologies.com> | 2016-05-31 15:54:01 -0300 |
---|---|---|
committer | Martin Galvan <martin.galvan@tallertechnologies.com> | 2016-05-31 15:56:34 -0300 |
commit | 3326303bf5ae4c92f2fbbff387ce231a16c1c8bf (patch) | |
tree | 6003faaf0747941817afc8d62f9f2a0bffcd3802 /gdb/valprint.c | |
parent | f7433f011ef27838551aded73b8666a86d26b8ec (diff) | |
download | gdb-3326303bf5ae4c92f2fbbff387ce231a16c1c8bf.zip gdb-3326303bf5ae4c92f2fbbff387ce231a16c1c8bf.tar.gz gdb-3326303bf5ae4c92f2fbbff387ce231a16c1c8bf.tar.bz2 |
[PR gdb/19893] Fix handling of synthetic C++ references
https://sourceware.org/bugzilla/show_bug.cgi?id=19893
I've traced the main source of the problem to pieced_value_funcs.coerce_ref not being
implemented. Since gdb always assumes references are implemented as pointers, this
causes it to think that it's dealing with a NULL pointer, thus breaking any operations
involving synthetic references.
What I did here was implementing pieced_value_funcs.coerce_ref using some of the synthetic
pointer handling code from indirect_pieced_value, as Pedro suggested. I also made a few
adjustments to the reference printing code so that it correctly shows either the address
of the referenced value or (if it's non-addressable) the "<synthetic pointer>" string.
I also wrote some unit tests based on Dwarf::assemble; these took a while to make
because in most cases I needed a synthetic reference to a physical variable. Additionally,
I started working on a unit test for classes that have a vtable, but ran into a few issues
so that'll probably go in a future patch. One thing that should definitely be fixed is that
proc function_range (called for MACRO_AT_func) will always try to compile/link using gcc
with the default options instead of g++, thus breaking C++ compilations that require e.g. libstdc++.
gdb/ChangeLog:
* dwarf2loc.c (coerce_pieced_ref, indirect_synthetic_pointer,
fetch_const_value_from_synthetic_pointer): New functions.
(indirect_pieced_value): Move lower half to indirect_synthetic_pointer.
(pieced_value_funcs): Implement coerce_ref.
* valops.c (value_addr): Call coerce_ref for synthetic references.
* valprint.c (valprint_check_validity): Return true for synthetic
references. Also, don't show "<synthetic pointer>" if they reference
addressable values.
(generic_val_print_ref): Handle synthetic references. Also move some
code to print_ref_address.
(print_ref_address, get_value_addr_contents): New functions.
gdb/testsuite/ChangeLog:
* gdb.dwarf2/implref.exp: Rename to...
* gdb.dwarf2/implref-const.exp: ...this. Also add more test statements.
* gdb.dwarf2/implref-array.c: New file.
* gdb.dwarf2/implref-array.exp: Likewise.
* gdb.dwarf2/implref-global.c: Likewise.
* gdb.dwarf2/implref-global.exp: Likewise.
* gdb.dwarf2/implref-struct.c: Likewise.
* gdb.dwarf2/implref-struct.exp: Likewise.
Diffstat (limited to 'gdb/valprint.c')
-rw-r--r-- | gdb/valprint.c | 121 |
1 files changed, 94 insertions, 27 deletions
diff --git a/gdb/valprint.c b/gdb/valprint.c index cea69f3..64407e8 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -335,8 +335,22 @@ valprint_check_validity (struct ui_file *stream, if (value_bits_synthetic_pointer (val, TARGET_CHAR_BIT * embedded_offset, TARGET_CHAR_BIT * TYPE_LENGTH (type))) { - fputs_filtered (_("<synthetic pointer>"), stream); - return 0; + const int is_ref = TYPE_CODE (type) == TYPE_CODE_REF; + int ref_is_addressable = 0; + + if (is_ref) + { + const struct value *deref_val = coerce_ref_if_computed (val); + + if (deref_val != NULL) + ref_is_addressable = value_lval_const (deref_val) == lval_memory; + } + + if (!is_ref || !ref_is_addressable) + fputs_filtered (_("<synthetic pointer>"), stream); + + /* C++ references should be valid even if they're synthetic. */ + return is_ref; } if (!value_bytes_available (val, embedded_offset, TYPE_LENGTH (type))) @@ -484,6 +498,42 @@ generic_val_print_memberptr (struct type *type, const gdb_byte *valaddr, original_value, options, 0, stream); } +/* Print '@' followed by the address contained in ADDRESS_BUFFER. */ + +static void +print_ref_address (struct type *type, const gdb_byte *address_buffer, + int embedded_offset, struct ui_file *stream) +{ + struct gdbarch *gdbarch = get_type_arch (type); + + if (address_buffer != NULL) + { + CORE_ADDR address + = extract_typed_address (address_buffer + embedded_offset, type); + + fprintf_filtered (stream, "@"); + fputs_filtered (paddress (gdbarch, address), stream); + } + /* Else: we have a non-addressable value, such as a DW_AT_const_value. */ +} + +/* If VAL is addressable, return the value contents buffer of a value that + represents a pointer to VAL. Otherwise return NULL. */ + +static const gdb_byte * +get_value_addr_contents (struct value *deref_val) +{ + gdb_assert (deref_val != NULL); + + if (value_lval_const (deref_val) == lval_memory) + return value_contents_for_printing_const (value_addr (deref_val)); + else + { + /* We have a non-addressable value, such as a DW_AT_const_value. */ + return NULL; + } +} + /* generic_val_print helper for TYPE_CODE_REF. */ static void @@ -492,41 +542,58 @@ generic_val_print_ref (struct type *type, const gdb_byte *valaddr, const struct value *original_value, const struct value_print_options *options) { - struct gdbarch *gdbarch = get_type_arch (type); struct type *elttype = check_typedef (TYPE_TARGET_TYPE (type)); + struct value *deref_val = NULL; + const int value_is_synthetic + = value_bits_synthetic_pointer (original_value, + TARGET_CHAR_BIT * embedded_offset, + TARGET_CHAR_BIT * TYPE_LENGTH (type)); + const int must_coerce_ref = ((options->addressprint && value_is_synthetic) + || options->deref_ref); + const int type_is_defined = TYPE_CODE (elttype) != TYPE_CODE_UNDEF; + + if (must_coerce_ref && type_is_defined) + { + deref_val = coerce_ref_if_computed (original_value); + + if (deref_val != NULL) + { + /* More complicated computed references are not supported. */ + gdb_assert (embedded_offset == 0); + } + else + deref_val = value_at (TYPE_TARGET_TYPE (type), + unpack_pointer (type, valaddr + embedded_offset)); + } + /* Else, original_value isn't a synthetic reference or we don't have to print + the reference's contents. + + Notice that for references to TYPE_CODE_STRUCT, 'set print object on' will + cause original_value to be a not_lval instead of an lval_computed, + which will make value_bits_synthetic_pointer return false. + This happens because if options->objectprint is true, c_value_print will + overwrite original_value's contents with the result of coercing + the reference through value_addr, and then set its type back to + TYPE_CODE_REF. In that case we don't have to coerce the reference again; + we can simply treat it as non-synthetic and move on. */ if (options->addressprint) { - CORE_ADDR addr - = extract_typed_address (valaddr + embedded_offset, type); + const gdb_byte *address = (value_is_synthetic && type_is_defined + ? get_value_addr_contents (deref_val) + : valaddr); + + print_ref_address (type, address, embedded_offset, stream); - fprintf_filtered (stream, "@"); - fputs_filtered (paddress (gdbarch, addr), stream); if (options->deref_ref) fputs_filtered (": ", stream); } - /* De-reference the reference. */ + if (options->deref_ref) { - if (TYPE_CODE (elttype) != TYPE_CODE_UNDEF) - { - struct value *deref_val; - - deref_val = coerce_ref_if_computed (original_value); - if (deref_val != NULL) - { - /* More complicated computed references are not supported. */ - gdb_assert (embedded_offset == 0); - } - else - deref_val = value_at (TYPE_TARGET_TYPE (type), - unpack_pointer (type, - (valaddr - + embedded_offset))); - - common_val_print (deref_val, stream, recurse, options, - current_language); - } + if (type_is_defined) + common_val_print (deref_val, stream, recurse, options, + current_language); else fputs_filtered ("???", stream); } |