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) <baseclass_offset>: 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.
This commit is contained in:
parent
1b28d0b3be
commit
8af8e3bc81
16 changed files with 385 additions and 146 deletions
|
@ -1,3 +1,56 @@
|
|||
2011-02-14 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* 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) <baseclass_offset>: 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 <pedro@codesourcery.com>
|
||||
|
||||
* tracepoint.c (memrange_sortmerge): Don't merge ranges that are
|
||||
|
|
32
gdb/cp-abi.c
32
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 *
|
||||
|
|
24
gdb/cp-abi.h
24
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.
|
||||
/* 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. */
|
||||
|
||||
-1 is returned on error. */
|
||||
extern int baseclass_offset (struct type *type,
|
||||
int index, const gdb_byte *valaddr,
|
||||
int embedded_offset,
|
||||
CORE_ADDR address,
|
||||
const struct value *val);
|
||||
|
||||
extern int baseclass_offset (struct type *type, int index,
|
||||
const bfd_byte *valaddr,
|
||||
CORE_ADDR address);
|
||||
|
||||
/* 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);
|
||||
|
|
|
@ -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));
|
||||
/* 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 (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);
|
||||
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, "<invalid address>");
|
||||
if (skip < 0)
|
||||
val_print_unavailable (stream);
|
||||
else if (skip > 0)
|
||||
val_print_invalid_address (stream);
|
||||
else
|
||||
{
|
||||
int result = 0;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "demangle.h"
|
||||
#include "cp-abi.h"
|
||||
#include "cp-support.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
return addr - (LONGEST) address;
|
||||
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 + 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. */
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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, "<invalid address>");
|
||||
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,
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
2011-02-14 Pedro Alves <pedro@codesourcery.com>
|
||||
|
||||
* 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 <pedro@codesourcery.com>
|
||||
|
||||
* gdb.trace/unavailable.cc (a, b, c): New globals.
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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 \\*\\) <unavailable>"
|
||||
|
||||
# no vtable pointer available
|
||||
gdb_test "print derived_unavail" \
|
||||
" = {<Middle> = <unavailable>, _vptr.Derived = <unavailable>, z = <unavailable>}"
|
||||
|
||||
# vtable pointer available, but nothing else
|
||||
gdb_test "print derived_partial" \
|
||||
" = \\(Derived\\) {<Middle> = {<Base> = <unavailable>, _vptr.Middle = <unavailable>, y = <unavailable>}, _vptr.Derived = $hex, z = <unavailable>}"
|
||||
|
||||
# whole object available
|
||||
gdb_test "print derived_whole" \
|
||||
" = \\(Derived\\) {<Middle> = {<Base> = {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 \\*\\) <unavailable>"
|
||||
|
||||
# no vtable pointer available
|
||||
gdb_test "print derived_unavail" \
|
||||
" = {<Middle> = <unavailable>, _vptr.Derived = <unavailable>, z = <unavailable>}"
|
||||
|
||||
# vtable pointer available, but nothing else
|
||||
gdb_test "print derived_partial" \
|
||||
" = {<Middle> = {<Base> = <unavailable>, _vptr.Middle = <unavailable>, y = <unavailable>}, _vptr.Derived = $hex, z = <unavailable>}"
|
||||
|
||||
# whole object available
|
||||
gdb_test "print derived_whole" \
|
||||
" = {<Middle> = {<Base> = {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 = <unavailable>, z = 0}"
|
||||
|
||||
gdb_test "tfind none" \
|
||||
"#0 end .*" \
|
||||
"cease trace debugging"
|
||||
|
|
87
gdb/valops.c
87
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. */
|
||||
|
|
|
@ -305,6 +305,12 @@ val_print_unavailable (struct ui_file *stream)
|
|||
fprintf_filtered (stream, _("<unavailable>"));
|
||||
}
|
||||
|
||||
void
|
||||
val_print_invalid_address (struct ui_file *stream)
|
||||
{
|
||||
fprintf_filtered (stream, _("<invalid address>"));
|
||||
}
|
||||
|
||||
/* 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 *
|
||||
|
|
Loading…
Reference in a new issue