mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-12-26 09:08:59 +00:00
[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.
This commit is contained in:
121
gdb/valprint.c
121
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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user