From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28378 invoked by alias); 7 Feb 2011 14:36:20 -0000 Received: (qmail 27996 invoked by uid 22791); 7 Feb 2011 14:36:14 -0000 X-SWARE-Spam-Status: No, hits=-1.9 required=5.0 tests=AWL,BAYES_00,TW_VP,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (38.113.113.100) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 07 Feb 2011 14:36:01 +0000 Received: (qmail 28001 invoked from network); 7 Feb 2011 14:35:59 -0000 Received: from unknown (HELO scottsdale.localnet) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 7 Feb 2011 14:35:59 -0000 To: gdb-patches@sourceware.org Subject: [unavailable values part 1, 17/17] unavailable vptr / virtual base offset From: Pedro Alves Date: Mon, 07 Feb 2011 14:36:00 -0000 MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Message-Id: <201102071435.55786.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-02/txt/msg00148.txt.bz2 Before: set print object on, object not collected at all: print derived_unavail $41 = { set print object on, only vptr collected: print derived_partial $42 = (Derived) { = { set print object off, object not collected at all: print derived_unavail $45 = { set print object off, only vptr collected: print derived_partial $46 = { = { The patch adds a new ERROR_NOT_AVAILABLE error, thrown whenever something wants to get at a value's contents with value_contents() and makes baseclass_offset callers that care to handle errors getting at the base class offset gracefully catch the error. This is because there are multiple ways an unavailable value may be required, and forwarding an error using return codes all across many layers would be cumbersome. Future patches will add several more uses for this new error --- basically, high-level code will not want to handle unavailability using return codes across many layers, as that's not practical. There was already some inconsistency in baseclass_offset's return, which the gnuv2 implementation returning -1 to signalling failure to extract the base class offset, while the gnuv3 version always threw an error. The patch makes it so that the gnuv2 also throws an error on failure (and thus has a better chance of being more descriptive than the infamous "virtual baseclass botch"), changes the semantics of the function and adjusts callers so they never expect a -1 result signaling an error. The other changes in the patch relate to passing a value down to whoever needs it, and while doing so, we need to pass the correct embedded_offset, and no longer adjust valaddr, similarly to the valprint routines' interfaces. After the patch, the above examples show: set print object on, object not collected at all: print derived_unavail $41 = { = , _vptr.Derived = , z = } set print object on, only vptr collected: print derived_partial $42 = (Derived) { = { = , _vptr.Middle = , y = }, _vptr.Derived = 0x400e60, z = } set print object off, object not collected at all: print derived_unavail $45 = { = , _vptr.Derived = , z = } set print object off, only vptr collected: print derived_partial $46 = { = { = , _vptr.Middle = , y = }, _vptr.Derived = 0x400e60, z = } -- Pedro Alves 2011-02-07 Pedro Alves 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/cp-abi.c | 32 ++++++++--- gdb/cp-abi.h | 28 +++++----- gdb/cp-valprint.c | 87 ++++++++++++++++++-------------- 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/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 - 14 files changed, 327 insertions(+), 151 deletions(-) Index: src/gdb/exceptions.h =================================================================== --- src.orig/gdb/exceptions.h 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/exceptions.h 2011-02-07 13:33:00.326706000 +0000 @@ -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 }; Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c 2011-02-07 13:24:23.766706003 +0000 +++ src/gdb/value.c 2011-02-07 13:33:00.326706000 +0000 @@ -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" @@ -690,7 +690,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 * Index: src/gdb/cp-abi.c =================================================================== --- src.orig/gdb/cp-abi.c 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/cp-abi.c 2011-02-07 13:33:00.326706000 +0000 @@ -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 * Index: src/gdb/cp-abi.h =================================================================== --- src.orig/gdb/cp-abi.h 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/cp-abi.h 2011-02-07 13:33:00.326706000 +0000 @@ -139,18 +139,18 @@ extern struct type *value_rtti_type (str 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); Index: src/gdb/cp-valprint.c =================================================================== --- src.orig/gdb/cp-valprint.c 2011-02-07 13:17:33.696706002 +0000 +++ src/gdb/cp-valprint.c 2011-02-07 13:33:00.326706000 +0000 @@ -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, struc 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, struc 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. */ - - if (boffset != -1 - && ((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); + 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 (BASETYPE_VIA_VIRTUAL (type, i)) + { + /* 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, struc 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, struc 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; Index: src/gdb/gdbtypes.c =================================================================== --- src.orig/gdb/gdbtypes.c 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/gdbtypes.c 2011-02-07 13:33:00.326706000 +0000 @@ -2101,7 +2101,8 @@ is_public_ancestor (struct type *base, s 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 * 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 * } 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, s 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; } Index: src/gdb/gnu-v2-abi.c =================================================================== --- src.orig/gdb/gnu-v2-abi.c 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/gnu-v2-abi.c 2011-02-07 13:33:00.326706000 +0000 @@ -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, 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 *typ { 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")); + + addr = unpack_pointer (field_type, + valaddr + embedded_offset + field_offset); - return addr - (LONGEST) address; + 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. */ Index: src/gdb/gnu-v3-abi.c =================================================================== --- src.orig/gdb/gnu-v3-abi.c 2011-02-07 11:19:38.176706003 +0000 +++ src/gdb/gnu-v3-abi.c 2011-02-07 13:33:00.326706000 +0000 @@ -411,8 +411,9 @@ gnuv3_virtual_fn_field (struct value **v -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 *typ 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)); Index: src/gdb/p-valprint.c =================================================================== --- src.orig/gdb/p-valprint.c 2011-02-07 13:17:33.696706002 +0000 +++ src/gdb/p-valprint.c 2011-02-07 13:33:00.336706001 +0000 @@ -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 * 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 * 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 * 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, Index: src/gdb/valops.c =================================================================== --- src.orig/gdb/valops.c 2011-02-07 13:22:15.776706000 +0000 +++ src/gdb/valops.c 2011-02-07 13:33:00.336706001 +0000 @@ -652,8 +652,10 @@ value_reinterpret_cast (struct type *typ 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 *desir 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 *desir 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 *desir 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, s 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, s 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, struc 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, s 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, 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, 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, c 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. */ Index: src/gdb/valprint.c =================================================================== --- src.orig/gdb/valprint.c 2011-02-07 13:17:29.666706001 +0000 +++ src/gdb/valprint.c 2011-02-07 13:33:00.336706001 +0000 @@ -305,6 +305,12 @@ val_print_unavailable (struct ui_file *s 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 Index: src/gdb/valprint.h =================================================================== --- src.orig/gdb/valprint.h 2011-02-07 12:16:49.076706003 +0000 +++ src/gdb/valprint.h 2011-02-07 13:33:00.346706002 +0000 @@ -156,4 +156,6 @@ extern void val_print_optimized_out (str extern void val_print_unavailable (struct ui_file *stream); +extern void val_print_invalid_address (struct ui_file *stream); + #endif Index: src/gdb/testsuite/gdb.trace/unavailable.cc =================================================================== --- src.orig/gdb/testsuite/gdb.trace/unavailable.cc 2011-02-07 13:27:53.276706002 +0000 +++ src/gdb/testsuite/gdb.trace/unavailable.cc 2011-02-07 13:33:00.346706002 +0000 @@ -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. */ Index: src/gdb/testsuite/gdb.trace/unavailable.exp =================================================================== --- src.orig/gdb/testsuite/gdb.trace/unavailable.exp 2011-02-07 13:27:53.276706002 +0000 +++ src/gdb/testsuite/gdb.trace/unavailable.exp 2011-02-07 13:33:00.346706002 +0000 @@ -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"