aboutsummaryrefslogtreecommitdiff
path: root/gdb/valprint.c
diff options
context:
space:
mode:
authorMartin Galvan <martin.galvan@tallertechnologies.com>2016-05-31 15:54:01 -0300
committerMartin Galvan <martin.galvan@tallertechnologies.com>2016-05-31 15:56:34 -0300
commit3326303bf5ae4c92f2fbbff387ce231a16c1c8bf (patch)
tree6003faaf0747941817afc8d62f9f2a0bffcd3802 /gdb/valprint.c
parentf7433f011ef27838551aded73b8666a86d26b8ec (diff)
downloadgdb-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.c121
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);
}