From 763b1d5a9c13a4521cac67b5bde671245becc6b6 Mon Sep 17 00:00:00 2001 From: palves Date: Mon, 14 Feb 2011 20:35:44 +0000 Subject: [PATCH] gdb/ * exceptions.h (NOT_AVAILABLE_ERROR): New error. * value.c: Include "exceptions.h". (require_available): Throw NOT_AVAILABLE_ERROR instead of a generic error. * cp-abi.c: Include gdb_assert.h. (baseclass_offset): Add `embedded_offset' and `val' parameters. Assert the method is implemented. Wrap NOT_AVAILABLE_ERROR errors. * cp-abi.h (baseclass_offset): Add `embedded_offset' and `val' parameters. No longer returns -1 on error. (struct cp_abi_ops) : Add `embedded_offset' and `val' parameters. * cp-valprint.c: Include exceptions.h. (cp_print_value): Handle NOT_AVAILABLE_ERROR errors when fetching the baseclass_offset. Handle unavailable base classes. Use val_print_invalid_address. * p-valprint.c: Include exceptions.h. (pascal_object_print_value): Handle NOT_AVAILABLE_ERROR errors when fetching the baseclass_offset. No longer expect baseclass_offset returning -1. Handle unavailable base classes. Use val_print_invalid_address. * valops.c (dynamic_cast_check_1): Rename `contents' parameter to `valaddr' parameter, and change its type to gdb_byte pointer. Add `embedded_offset' and `val' parameters. Adjust. (dynamic_cast_check_2): Rename `contents' parameter to `valaddr' parameter, and change its type to gdb_byte pointer. Add `embedded_offset' and `val' parameters. Adjust. No longer expect baseclass_offset returning -1. (value_dynamic_cast): Use value_contents_for_printing rather than value_contents. Adjust. (search_struct_field): No longer expect baseclass_offset returning -1. (search_struct_method): If reading memory from the target is necessary, wrap it in a new value to pass to baseclass_offset. No longer expect baseclass_offset returning -1. (find_method_list): No longer expect baseclass_offset returning -1. Use value_contents_for_printing rather than value_contents. * valprint.c (val_print_invalid_address): New function. * valprint.h (val_print_invalid_address): Declare. * gdbtypes.c (is_unique_ancestor_worker): New `embedded_offset' and `val' parameters. No longer expect baseclass_offset returning -1. Adjust. * gnu-v2-abi.c: Include "exceptions.h". (gnuv2_baseclass_offset): Add `embedded_offset' and `val' parameters. Handle unavailable memory. Recurse through gnuv2_baseclass_offset directly, rather than through baseclass_offset. No longer returns -1 on not found, instead throw an error. * gnu-v3-abi.c (gnuv3_baseclass_offset): Add `embedded_offset' and `val' parameters. Adjust. gdb/testsuite/ * gdb.trace/unavailable.cc (class Base, class Middle, class Derived): New types. (derived_unavail, derived_partial, derived_whole): New globals. (virtual_partial): New global. (virtualp): Point at virtual_partial. * gdb.trace/unavailable.exp (gdb_collect_globals_test): Add tests related to unavailable vptr. --- gdb/ChangeLog | 53 ++++++++++++++++++++ gdb/cp-abi.c | 32 +++++++++--- gdb/cp-abi.h | 28 +++++------ gdb/cp-valprint.c | 83 +++++++++++++++++-------------- gdb/exceptions.h | 7 +++ gdb/gdbtypes.c | 23 +++++---- gdb/gnu-v2-abi.c | 46 +++++++++++------ gdb/gnu-v3-abi.c | 7 +-- gdb/p-valprint.c | 66 +++++++++++++++---------- gdb/testsuite/ChangeLog | 10 ++++ gdb/testsuite/gdb.trace/unavailable.cc | 33 ++++++++++++- gdb/testsuite/gdb.trace/unavailable.exp | 50 ++++++++++++++++++- gdb/valops.c | 87 ++++++++++++++++++++------------- gdb/valprint.c | 6 +++ gdb/valprint.h | 2 + gdb/value.c | 4 +- 16 files changed, 388 insertions(+), 149 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index f7099b4387..bfef2e24c1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,58 @@ 2011-02-14 Pedro Alves + * exceptions.h (NOT_AVAILABLE_ERROR): New error. + * value.c: Include "exceptions.h". + (require_available): Throw NOT_AVAILABLE_ERROR instead of a + generic error. + * cp-abi.c: Include gdb_assert.h. + (baseclass_offset): Add `embedded_offset' and `val' parameters. + Assert the method is implemented. Wrap NOT_AVAILABLE_ERROR + errors. + * cp-abi.h (baseclass_offset): Add `embedded_offset' and `val' + parameters. No longer returns -1 on error. + (struct cp_abi_ops) : Add `embedded_offset' and + `val' parameters. + * cp-valprint.c: Include exceptions.h. + (cp_print_value): Handle NOT_AVAILABLE_ERROR errors when fetching + the baseclass_offset. Handle unavailable base classes. Use + val_print_invalid_address. + * p-valprint.c: Include exceptions.h. + (pascal_object_print_value): Handle NOT_AVAILABLE_ERROR errors + when fetching the baseclass_offset. No longer expect + baseclass_offset returning -1. Handle unavailable base classes. + Use val_print_invalid_address. + * valops.c (dynamic_cast_check_1): Rename `contents' parameter to + `valaddr' parameter, and change its type to gdb_byte pointer. Add + `embedded_offset' and `val' parameters. Adjust. + (dynamic_cast_check_2): Rename `contents' parameter to `valaddr' + parameter, and change its type to gdb_byte pointer. Add + `embedded_offset' and `val' parameters. Adjust. No longer expect + baseclass_offset returning -1. + (value_dynamic_cast): Use value_contents_for_printing rather than + value_contents. Adjust. + (search_struct_field): No longer expect baseclass_offset returning + -1. + (search_struct_method): If reading memory from the target is + necessary, wrap it in a new value to pass to baseclass_offset. No + longer expect baseclass_offset returning -1. + (find_method_list): No longer expect baseclass_offset returning + -1. Use value_contents_for_printing rather than value_contents. + * valprint.c (val_print_invalid_address): New function. + * valprint.h (val_print_invalid_address): Declare. + * gdbtypes.c (is_unique_ancestor_worker): New `embedded_offset' + and `val' parameters. No longer expect baseclass_offset returning + -1. Adjust. + * gnu-v2-abi.c: Include "exceptions.h". + (gnuv2_baseclass_offset): Add `embedded_offset' and `val' + parameters. Handle unavailable memory. Recurse through + gnuv2_baseclass_offset directly, rather than through + baseclass_offset. No longer returns -1 on not found, instead + throw an error. + * gnu-v3-abi.c (gnuv3_baseclass_offset): Add `embedded_offset' and + `val' parameters. Adjust. + +2011-02-14 Pedro Alves + * tracepoint.c (memrange_sortmerge): Don't merge ranges that are almost but not quite adjacent. diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c index 0c21f910a2..040962eba2 100644 --- a/gdb/cp-abi.c +++ b/gdb/cp-abi.c @@ -25,7 +25,7 @@ #include "exceptions.h" #include "gdbcmd.h" #include "ui-out.h" - +#include "gdb_assert.h" #include "gdb_string.h" static struct cp_abi_ops *find_cp_abi (const char *short_name); @@ -70,14 +70,30 @@ is_operator_name (const char *name) } int -baseclass_offset (struct type *type, int index, - const bfd_byte *valaddr, - CORE_ADDR address) +baseclass_offset (struct type *type, int index, const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + const struct value *val) { - if (current_cp_abi.baseclass_offset == NULL) - error (_("ABI doesn't define required function baseclass_offset")); - return (*current_cp_abi.baseclass_offset) (type, index, - valaddr, address); + volatile struct gdb_exception ex; + int res = 0; + + gdb_assert (current_cp_abi.baseclass_offset != NULL); + + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + res = (*current_cp_abi.baseclass_offset) (type, index, valaddr, + embedded_offset, + address, val); + } + + if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) + throw_error (NOT_AVAILABLE_ERROR, + _("Cannot determine virtual baseclass offset " + "of incomplete object")); + else if (ex.reason < 0) + throw_exception (ex); + else + return res; } struct value * diff --git a/gdb/cp-abi.h b/gdb/cp-abi.h index 53c8f93c43..9bfa1b0356 100644 --- a/gdb/cp-abi.h +++ b/gdb/cp-abi.h @@ -139,18 +139,18 @@ extern struct type *value_rtti_type (struct value *value, int *full, int *top, int *using_enc); -/* Compute the offset of the baseclass which is - the INDEXth baseclass of class TYPE, - for value at VALADDR (in host) at ADDRESS (in target). - The result is the offset of the baseclass value relative - to (the address of)(ARG) + OFFSET. - - -1 is returned on error. */ - -extern int baseclass_offset (struct type *type, int index, - const bfd_byte *valaddr, - CORE_ADDR address); - +/* Compute the offset of the baseclass which is the INDEXth baseclass + of class TYPE, for value at VALADDR (in host) at ADDRESS (in + target), offset by EMBEDDED_OFFSET. VALADDR points to the raw + contents of VAL. The result is the offset of the baseclass value + relative to (the address of)(ARG) + OFFSET. */ + +extern int baseclass_offset (struct type *type, + int index, const gdb_byte *valaddr, + int embedded_offset, + CORE_ADDR address, + const struct value *val); + /* Describe the target of a pointer to method. CONTENTS is the byte pattern representing the pointer to method. TYPE is the pointer to method type. STREAM is the stream to print it to. */ @@ -204,8 +204,8 @@ struct cp_abi_ops struct type *(*rtti_type) (struct value *v, int *full, int *top, int *using_enc); int (*baseclass_offset) (struct type *type, int index, - const bfd_byte *valaddr, - CORE_ADDR address); + const bfd_byte *valaddr, int embedded_offset, + CORE_ADDR address, const struct value *val); void (*print_method_ptr) (const gdb_byte *contents, struct type *type, struct ui_file *stream); diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index 1a171ea20c..255e9ce223 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -37,6 +37,7 @@ #include "cp-support.h" #include "language.h" #include "python/python.h" +#include "exceptions.h" /* Controls printing of vtbl's. */ static void @@ -482,12 +483,13 @@ cp_print_value (struct type *type, struct type *real_type, for (i = 0; i < n_baseclasses; i++) { - int boffset; + int boffset = 0; int skip; struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); char *basename = TYPE_NAME (baseclass); - const gdb_byte *base_valaddr; - const struct value *base_val; + const gdb_byte *base_valaddr = NULL; + const struct value *base_val = NULL; + volatile struct gdb_exception ex; if (BASETYPE_VIA_VIRTUAL (type, i)) { @@ -507,34 +509,47 @@ cp_print_value (struct type *type, struct type *real_type, thisoffset = offset; thistype = real_type; - boffset = baseclass_offset (type, i, valaddr + offset, - address + offset); - skip = ((boffset == -1) || (boffset + offset) < 0); - - if (BASETYPE_VIA_VIRTUAL (type, i)) + TRY_CATCH (ex, RETURN_MASK_ERROR) { - /* The virtual base class pointer might have been clobbered - by the user program. Make sure that it still points to a - valid memory location. */ + boffset = baseclass_offset (type, i, valaddr, offset, address, val); + } + if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) + skip = -1; + else if (ex.reason < 0) + skip = 1; + else + { + skip = 0; - if (boffset != -1 - && ((boffset + offset) < 0 - || (boffset + offset) >= TYPE_LENGTH (real_type))) + if (BASETYPE_VIA_VIRTUAL (type, i)) { - /* FIXME (alloca): unsafe if baseclass is really really - large. */ - gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); - - if (target_read_memory (address + boffset, buf, - TYPE_LENGTH (baseclass)) != 0) - skip = 1; - base_val = value_from_contents_and_address (baseclass, - buf, - address + boffset); - thisoffset = 0; - boffset = 0; - thistype = baseclass; - base_valaddr = value_contents_for_printing_const (base_val); + /* The virtual base class pointer might have been + clobbered by the user program. Make sure that it + still points to a valid memory location. */ + + if ((boffset + offset) < 0 + || (boffset + offset) >= TYPE_LENGTH (real_type)) + { + /* FIXME (alloca): unsafe if baseclass is really + really large. */ + gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); + + if (target_read_memory (address + boffset, buf, + TYPE_LENGTH (baseclass)) != 0) + skip = 1; + base_val = value_from_contents_and_address (baseclass, + buf, + address + boffset); + thisoffset = 0; + boffset = 0; + thistype = baseclass; + base_valaddr = value_contents_for_printing_const (base_val); + } + else + { + base_valaddr = valaddr; + base_val = val; + } } else { @@ -542,11 +557,6 @@ cp_print_value (struct type *type, struct type *real_type, base_val = val; } } - else - { - base_valaddr = valaddr; - base_val = val; - } /* Now do the printing. */ if (options->pretty) @@ -560,9 +570,10 @@ cp_print_value (struct type *type, struct type *real_type, fputs_filtered (basename ? basename : "", stream); fputs_filtered ("> = ", stream); - - if (skip) - fprintf_filtered (stream, ""); + if (skip < 0) + val_print_unavailable (stream); + else if (skip > 0) + val_print_invalid_address (stream); else { int result = 0; diff --git a/gdb/exceptions.h b/gdb/exceptions.h index 81f3f4b777..b1c45878c1 100644 --- a/gdb/exceptions.h +++ b/gdb/exceptions.h @@ -49,9 +49,12 @@ typedef int return_mask; enum errors { GDB_NO_ERROR, + /* Any generic error, the corresponding text is in exception.message. */ GENERIC_ERROR, + + /* Something requested was not found. */ NOT_FOUND_ERROR, /* Thread library lacks support necessary for finding thread local @@ -78,6 +81,10 @@ enum errors { /* Feature is not supported in this copy of GDB. */ UNSUPPORTED_ERROR, + /* Value not available. E.g., a register was not collected in a + traceframe. */ + NOT_AVAILABLE_ERROR, + /* Add more errors here. */ NR_ERRORS }; diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c index 2cf1b4d686..91fafa2152 100644 --- a/gdb/gdbtypes.c +++ b/gdb/gdbtypes.c @@ -2101,7 +2101,8 @@ is_public_ancestor (struct type *base, struct type *dclass) static int is_unique_ancestor_worker (struct type *base, struct type *dclass, int *offset, - const bfd_byte *contents, CORE_ADDR address) + const gdb_byte *valaddr, int embedded_offset, + CORE_ADDR address, struct value *val) { int i, count = 0; @@ -2110,11 +2111,13 @@ is_unique_ancestor_worker (struct type *base, struct type *dclass, for (i = 0; i < TYPE_N_BASECLASSES (dclass) && count < 2; ++i) { - struct type *iter = check_typedef (TYPE_BASECLASS (dclass, i)); - int this_offset = baseclass_offset (dclass, i, contents, address); + struct type *iter; + int this_offset; - if (this_offset == -1) - error (_("virtual baseclass botch")); + iter = check_typedef (TYPE_BASECLASS (dclass, i)); + + this_offset = baseclass_offset (dclass, i, valaddr, embedded_offset, + address, val); if (class_types_same_p (base, iter)) { @@ -2136,8 +2139,9 @@ is_unique_ancestor_worker (struct type *base, struct type *dclass, } else count += is_unique_ancestor_worker (base, iter, offset, - contents + this_offset, - address + this_offset); + valaddr, + embedded_offset + this_offset, + address, val); } return count; @@ -2152,8 +2156,9 @@ is_unique_ancestor (struct type *base, struct value *val) int offset = -1; return is_unique_ancestor_worker (base, value_type (val), &offset, - value_contents (val), - value_address (val)) == 1; + value_contents_for_printing (val), + value_embedded_offset (val), + value_address (val), val) == 1; } diff --git a/gdb/gnu-v2-abi.c b/gdb/gnu-v2-abi.c index effac401c2..3d49a06645 100644 --- a/gdb/gnu-v2-abi.c +++ b/gdb/gnu-v2-abi.c @@ -28,6 +28,7 @@ #include "demangle.h" #include "cp-abi.h" #include "cp-support.h" +#include "exceptions.h" #include @@ -334,17 +335,15 @@ vb_match (struct type *type, int index, struct type *basetype) return 0; } -/* Compute the offset of the baseclass which is - the INDEXth baseclass of class TYPE, - for value at VALADDR (in host) at ADDRESS (in target). - The result is the offset of the baseclass value relative - to (the address of)(ARG) + OFFSET. - - -1 is returned on error. */ +/* Compute the offset of the baseclass which is the INDEXth baseclass + of class TYPE, for value at VALADDR (in host) at ADDRESS (in + target). The result is the offset of the baseclass value relative + to (the address of)(ARG) + OFFSET. */ static int gnuv2_baseclass_offset (struct type *type, int index, - const bfd_byte *valaddr, CORE_ADDR address) + const bfd_byte *valaddr, int embedded_offset, + CORE_ADDR address, const struct value *val) { struct type *basetype = TYPE_BASECLASS (type, index); @@ -360,24 +359,41 @@ gnuv2_baseclass_offset (struct type *type, int index, { if (vb_match (type, i, basetype)) { - CORE_ADDR addr - = unpack_pointer (TYPE_FIELD_TYPE (type, i), - valaddr + (TYPE_FIELD_BITPOS (type, i) / 8)); + struct type *field_type; + int field_offset; + int field_length; + CORE_ADDR addr; + + field_type = check_typedef (TYPE_FIELD_TYPE (type, i)); + field_offset = TYPE_FIELD_BITPOS (type, i) / 8; + field_length = TYPE_LENGTH (field_type); + + if (!value_bytes_available (val, embedded_offset + field_offset, + field_length)) + throw_error (NOT_AVAILABLE_ERROR, + _("Virtual baseclass pointer is not available")); - return addr - (LONGEST) address; + addr = unpack_pointer (field_type, + valaddr + embedded_offset + field_offset); + + return addr - (LONGEST) address + embedded_offset; } } /* Not in the fields, so try looking through the baseclasses. */ for (i = index + 1; i < n_baseclasses; i++) { + /* Don't go through baseclass_offset, as that wraps + exceptions, thus, inner exceptions would be wrapped more + than once. */ int boffset = - baseclass_offset (type, i, valaddr, address); + gnuv2_baseclass_offset (type, i, valaddr, + embedded_offset, address, val); if (boffset) return boffset; } - /* Not found. */ - return -1; + + error (_("Baseclass offset not found")); } /* Baseclass is easily computed. */ diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c index 0b80571194..25a437b349 100644 --- a/gdb/gnu-v3-abi.c +++ b/gdb/gnu-v3-abi.c @@ -411,8 +411,9 @@ gnuv3_virtual_fn_field (struct value **value_p, -1 is returned on error. */ static int -gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, - CORE_ADDR address) +gnuv3_baseclass_offset (struct type *type, int index, + const bfd_byte *valaddr, int embedded_offset, + CORE_ADDR address, const struct value *val) { struct gdbarch *gdbarch; struct type *ptr_type; @@ -443,7 +444,7 @@ gnuv3_baseclass_offset (struct type *type, int index, const bfd_byte *valaddr, error (_("Misaligned vbase offset.")); cur_base_offset = cur_base_offset / ((int) TYPE_LENGTH (ptr_type)); - vtable = gnuv3_get_vtable (gdbarch, type, address); + vtable = gnuv3_get_vtable (gdbarch, type, address + embedded_offset); gdb_assert (vtable != NULL); vbase_array = value_field (vtable, vtable_field_vcall_and_vbase_offsets); base_offset = value_as_long (value_subscript (vbase_array, cur_base_offset)); diff --git a/gdb/p-valprint.c b/gdb/p-valprint.c index 7031a77110..fc50e2a314 100644 --- a/gdb/p-valprint.c +++ b/gdb/p-valprint.c @@ -38,6 +38,7 @@ #include "p-lang.h" #include "cp-abi.h" #include "cp-support.h" +#include "exceptions.h" /* See val_print for a description of the various parameters of this @@ -900,11 +901,13 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, for (i = 0; i < n_baseclasses; i++) { - int boffset; + int boffset = 0; struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); char *basename = type_name_no_tag (baseclass); - const gdb_byte *base_valaddr; + const gdb_byte *base_valaddr = NULL; int thisoffset; + volatile struct gdb_exception ex; + int skip = 0; if (BASETYPE_VIA_VIRTUAL (type, i)) { @@ -923,7 +926,38 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, thisoffset = offset; - boffset = baseclass_offset (type, i, valaddr + offset, address + offset); + TRY_CATCH (ex, RETURN_MASK_ERROR) + { + boffset = baseclass_offset (type, i, valaddr, offset, address, val); + } + if (ex.reason < 0 && ex.error == NOT_AVAILABLE_ERROR) + skip = -1; + else if (ex.reason < 0) + skip = 1; + else + { + skip = 0; + + /* The virtual base class pointer might have been clobbered by the + user program. Make sure that it still points to a valid memory + location. */ + + if (boffset < 0 || boffset >= TYPE_LENGTH (type)) + { + /* FIXME (alloc): not safe is baseclass is really really big. */ + gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); + + base_valaddr = buf; + if (target_read_memory (address + boffset, buf, + TYPE_LENGTH (baseclass)) != 0) + skip = 1; + address = address + boffset; + thisoffset = 0; + boffset = 0; + } + else + base_valaddr = valaddr; + } if (options->pretty) { @@ -937,28 +971,10 @@ pascal_object_print_value (struct type *type, const gdb_byte *valaddr, fputs_filtered (basename ? basename : "", stream); fputs_filtered ("> = ", stream); - /* The virtual base class pointer might have been clobbered by the - user program. Make sure that it still points to a valid memory - location. */ - - if (boffset != -1 && (boffset < 0 || boffset >= TYPE_LENGTH (type))) - { - /* FIXME (alloc): not safe is baseclass is really really big. */ - gdb_byte *buf = alloca (TYPE_LENGTH (baseclass)); - - base_valaddr = buf; - if (target_read_memory (address + boffset, buf, - TYPE_LENGTH (baseclass)) != 0) - boffset = -1; - address = address + boffset; - thisoffset = 0; - boffset = 0; - } - else - base_valaddr = valaddr; - - if (boffset == -1) - fprintf_filtered (stream, ""); + if (skip < 0) + val_print_unavailable (stream); + else if (skip > 0) + val_print_invalid_address (stream); else pascal_object_print_value_fields (baseclass, base_valaddr, thisoffset + boffset, address, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 0fab27496c..eb00301dcd 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,5 +1,15 @@ 2011-02-14 Pedro Alves + * gdb.trace/unavailable.cc (class Base, class Middle, class + Derived): New types. + (derived_unavail, derived_partial, derived_whole): New globals. + (virtual_partial): New global. + (virtualp): Point at virtual_partial. + * gdb.trace/unavailable.exp (gdb_collect_globals_test): Add tests + related to unavailable vptr. + +2011-02-14 Pedro Alves + * gdb.trace/unavailable.cc (a, b, c): New globals. (main): Set and clear them. * gdb.trace/unavailable.exp (gdb_collect_globals_test): Collect diff --git a/gdb/testsuite/gdb.trace/unavailable.cc b/gdb/testsuite/gdb.trace/unavailable.cc index 7b4a2b20be..36b7455667 100644 --- a/gdb/testsuite/gdb.trace/unavailable.cc +++ b/gdb/testsuite/gdb.trace/unavailable.cc @@ -133,13 +133,44 @@ struct StructA StructB::static_struct_a; StructRef g_structref(0x12345678); StructRef *g_structref_p = &g_structref; +class Base +{ +protected: + int x; + +public: + Base(void) { x = 2; }; +}; + +class Middle: public virtual Base +{ +protected: + int y; + +public: + Middle(void): Base() { y = 3; }; +}; + +class Derived: public virtual Middle { +protected: + int z; + +public: + Derived(void): Middle() { z = 4; }; +}; + +Derived derived_unavail; +Derived derived_partial; +Derived derived_whole; + struct Virtual { int z; virtual ~Virtual() {} }; -Virtual *virtualp; +Virtual virtual_partial; +Virtual *virtualp = &virtual_partial; /* Test functions. */ diff --git a/gdb/testsuite/gdb.trace/unavailable.exp b/gdb/testsuite/gdb.trace/unavailable.exp index 8ec6343344..ab8fe97b13 100644 --- a/gdb/testsuite/gdb.trace/unavailable.exp +++ b/gdb/testsuite/gdb.trace/unavailable.exp @@ -87,6 +87,9 @@ proc gdb_collect_globals_test { } { "Tracepoint \[0-9\]+ at .*" \ "set tracepoint" + # We collect the initial sizeof(pointer) bytes of derived_partial + # in an attempt of collecting the vptr. Not portable, but should + # work everywhere we need to care. gdb_trace_setactions "define actions" \ "" \ "collect struct_b.struct_a.array\[2\]" "^$" \ @@ -106,7 +109,12 @@ proc gdb_collect_globals_test { } { "collect g_string_partial\[1\]" "^$" \ "collect g_string_partial\[2\]" "^$" \ \ - "collect g_structref_p" "^$" + "collect g_structref_p" "^$" \ + \ + "collect *((char *)&derived_partial)@sizeof\(void *\)" "^$" \ + "collect derived_whole" "^$" \ + \ + "collect virtual_partial.z" "^$" # Begin the test. run_trace_experiment globals_test_func @@ -256,14 +264,54 @@ proc gdb_collect_globals_test { } { gdb_test_no_output "set print object on" + set old_pf_prefix_2 $pf_prefix + set pf_prefix "$pf_prefix print object on:" + # With print object on, printing a pointer may need to fetch the # pointed-to object, to check its run-time type. Make sure that # fails gracefully and transparently when the pointer itself is # unavailable. gdb_test "print virtualp" " = \\(Virtual \\*\\) " + # no vtable pointer available + gdb_test "print derived_unavail" \ + " = { = , _vptr.Derived = , z = }" + + # vtable pointer available, but nothing else + gdb_test "print derived_partial" \ + " = \\(Derived\\) { = { = , _vptr.Middle = , y = }, _vptr.Derived = $hex, z = }" + + # whole object available + gdb_test "print derived_whole" \ + " = \\(Derived\\) { = { = {x = 2}, _vptr.Middle = $hex, y = 3}, _vptr.Derived = $hex, z = 4}" + + set pf_prefix $old_pf_prefix_2 + gdb_test_no_output "set print object off" + set pf_prefix "$pf_prefix print object off:" + + gdb_test "print virtualp" " = \\(Virtual \\*\\) " + + # no vtable pointer available + gdb_test "print derived_unavail" \ + " = { = , _vptr.Derived = , z = }" + + # vtable pointer available, but nothing else + gdb_test "print derived_partial" \ + " = { = { = , _vptr.Middle = , y = }, _vptr.Derived = $hex, z = }" + + # whole object available + gdb_test "print derived_whole" \ + " = { = { = {x = 2}, _vptr.Middle = $hex, y = 3}, _vptr.Derived = $hex, z = 4}" + + set pf_prefix $old_pf_prefix_2 + + # An instance of a virtual class where we collected everything but + # the vptr. + gdb_test "print virtual_partial" \ + " = {_vptr.Virtual = , z = 0}" + gdb_test "tfind none" \ "#0 end .*" \ "cease trace debugging" diff --git a/gdb/valops.c b/gdb/valops.c index 1f25a32720..5465abaac9 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -652,8 +652,10 @@ value_reinterpret_cast (struct type *type, struct value *arg) static int dynamic_cast_check_1 (struct type *desired_type, - const bfd_byte *contents, + const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct value *val, struct type *search_type, CORE_ADDR arg_addr, struct type *arg_type, @@ -663,25 +665,25 @@ dynamic_cast_check_1 (struct type *desired_type, for (i = 0; i < TYPE_N_BASECLASSES (search_type) && result_count < 2; ++i) { - int offset = baseclass_offset (search_type, i, contents, address); + int offset = baseclass_offset (search_type, i, valaddr, embedded_offset, + address, val); - if (offset == -1) - error (_("virtual baseclass botch")); if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i))) { - if (address + offset >= arg_addr - && address + offset < arg_addr + TYPE_LENGTH (arg_type)) + if (address + embedded_offset + offset >= arg_addr + && address + embedded_offset + offset < arg_addr + TYPE_LENGTH (arg_type)) { ++result_count; if (!*result) *result = value_at_lazy (TYPE_BASECLASS (search_type, i), - address + offset); + address + embedded_offset + offset); } } else result_count += dynamic_cast_check_1 (desired_type, - contents + offset, - address + offset, + valaddr, + embedded_offset + offset, + address, val, TYPE_BASECLASS (search_type, i), arg_addr, arg_type, @@ -697,8 +699,10 @@ dynamic_cast_check_1 (struct type *desired_type, static int dynamic_cast_check_2 (struct type *desired_type, - const bfd_byte *contents, + const gdb_byte *valaddr, + int embedded_offset, CORE_ADDR address, + struct value *val, struct type *search_type, struct value **result) { @@ -711,20 +715,20 @@ dynamic_cast_check_2 (struct type *desired_type, if (! BASETYPE_VIA_PUBLIC (search_type, i)) continue; - offset = baseclass_offset (search_type, i, contents, address); - if (offset == -1) - error (_("virtual baseclass botch")); + offset = baseclass_offset (search_type, i, valaddr, embedded_offset, + address, val); if (class_types_same_p (desired_type, TYPE_BASECLASS (search_type, i))) { ++result_count; if (*result == NULL) *result = value_at_lazy (TYPE_BASECLASS (search_type, i), - address + offset); + address + embedded_offset + offset); } else result_count += dynamic_cast_check_2 (desired_type, - contents + offset, - address + offset, + valaddr, + embedded_offset + offset, + address, val, TYPE_BASECLASS (search_type, i), result); } @@ -822,7 +826,9 @@ value_dynamic_cast (struct type *type, struct value *arg) return tem; result = NULL; if (dynamic_cast_check_1 (TYPE_TARGET_TYPE (resolved_type), - value_contents (tem), value_address (tem), + value_contents_for_printing (tem), + value_embedded_offset (tem), + value_address (tem), tem, rtti_type, addr, arg_type, &result) == 1) @@ -834,7 +840,9 @@ value_dynamic_cast (struct type *type, struct value *arg) result = NULL; if (is_public_ancestor (arg_type, rtti_type) && dynamic_cast_check_2 (TYPE_TARGET_TYPE (resolved_type), - value_contents (tem), value_address (tem), + value_contents_for_printing (tem), + value_embedded_offset (tem), + value_address (tem), tem, rtti_type, &result) == 1) return value_cast (type, is_ref ? value_ref (result) : value_addr (result)); @@ -1323,6 +1331,7 @@ value_assign (struct value *toval, struct value *fromval) int offset = value_offset (parent) + value_offset (toval); int changed_len; gdb_byte buffer[sizeof (LONGEST)]; + int optim, unavail; changed_len = (value_bitpos (toval) + value_bitsize (toval) @@ -2075,12 +2084,10 @@ search_struct_field (const char *name, struct value *arg1, int offset, struct value *v2; boffset = baseclass_offset (type, i, - value_contents (arg1) + offset, - value_address (arg1) - + value_embedded_offset (arg1) - + offset); - if (boffset == -1) - error (_("virtual baseclass botch")); + value_contents_for_printing (arg1), + value_embedded_offset (arg1) + offset, + value_address (arg1), + arg1); /* The virtual base class pointer might have been clobbered by the user program. Make sure that it still points to a @@ -2202,10 +2209,13 @@ search_struct_method (const char *name, struct value **arg1p, for (i = TYPE_N_BASECLASSES (type) - 1; i >= 0; i--) { int base_offset; + int skip = 0; + int this_offset; if (BASETYPE_VIA_VIRTUAL (type, i)) { struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i)); + struct value *base_val; const gdb_byte *base_valaddr; /* The virtual base class pointer might have been @@ -2215,19 +2225,28 @@ search_struct_method (const char *name, struct value **arg1p, if (offset < 0 || offset >= TYPE_LENGTH (type)) { gdb_byte *tmp = alloca (TYPE_LENGTH (baseclass)); + CORE_ADDR address = value_address (*arg1p); - if (target_read_memory (value_address (*arg1p) + offset, + if (target_read_memory (address + offset, tmp, TYPE_LENGTH (baseclass)) != 0) error (_("virtual baseclass botch")); - base_valaddr = tmp; + + base_val = value_from_contents_and_address (baseclass, + tmp, + address + offset); + base_valaddr = value_contents_for_printing (base_val); + this_offset = 0; } else - base_valaddr = value_contents (*arg1p) + offset; + { + base_val = *arg1p; + base_valaddr = value_contents_for_printing (*arg1p); + this_offset = offset; + } base_offset = baseclass_offset (type, i, base_valaddr, - value_address (*arg1p) + offset); - if (base_offset == -1) - error (_("virtual baseclass botch")); + this_offset, value_address (base_val), + base_val); } else { @@ -2405,12 +2424,10 @@ find_method_list (struct value **argp, const char *method, if (BASETYPE_VIA_VIRTUAL (type, i)) { - base_offset = value_offset (*argp) + offset; base_offset = baseclass_offset (type, i, - value_contents (*argp) + base_offset, - value_address (*argp) + base_offset); - if (base_offset == -1) - error (_("virtual baseclass botch")); + value_contents_for_printing (*argp), + value_offset (*argp) + offset, + value_address (*argp), *argp); } else /* Non-virtual base, simply use bit position from debug info. */ diff --git a/gdb/valprint.c b/gdb/valprint.c index fd573c255e..286ef9e74c 100644 --- a/gdb/valprint.c +++ b/gdb/valprint.c @@ -305,6 +305,12 @@ val_print_unavailable (struct ui_file *stream) fprintf_filtered (stream, _("")); } +void +val_print_invalid_address (struct ui_file *stream) +{ + fprintf_filtered (stream, _("")); +} + /* Print using the given LANGUAGE the data of type TYPE located at VALADDR + EMBEDDED_OFFSET (within GDB), which came from the inferior at address ADDRESS + EMBEDDED_OFFSET, onto stdio stream diff --git a/gdb/valprint.h b/gdb/valprint.h index 542a13aba9..b6ea7a9989 100644 --- a/gdb/valprint.h +++ b/gdb/valprint.h @@ -156,4 +156,6 @@ extern void val_print_optimized_out (struct ui_file *stream); extern void val_print_unavailable (struct ui_file *stream); +extern void val_print_invalid_address (struct ui_file *stream); + #endif diff --git a/gdb/value.c b/gdb/value.c index 236b42f12a..3b4d23a737 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -39,7 +39,7 @@ #include "objfiles.h" #include "valprint.h" #include "cli/cli-decode.h" - +#include "exceptions.h" #include "python/python.h" #include "tracepoint.h" @@ -826,7 +826,7 @@ static void require_available (const struct value *value) { if (!VEC_empty (range_s, value->unavailable)) - error (_("value is not available")); + throw_error (NOT_AVAILABLE_ERROR, _("value is not available")); } const gdb_byte * -- 2.11.0