summaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2011-02-14 11:35:44 +0000
committerPedro Alves <pedro@codesourcery.com>2011-02-14 11:35:44 +0000
commit088fb8bccdbcbec081d5cea7814416f2fa224877 (patch)
tree207e105e59b9060952e7688c3bb307a45b33661a /gdb
parent999294cfd150f1ed4393d349027f76ca77791761 (diff)
downloadgdb-088fb8bccdbcbec081d5cea7814416f2fa224877.tar.gz
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.
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog53
-rw-r--r--gdb/cp-abi.c32
-rw-r--r--gdb/cp-abi.h28
-rw-r--r--gdb/cp-valprint.c83
-rw-r--r--gdb/exceptions.h7
-rw-r--r--gdb/gdbtypes.c23
-rw-r--r--gdb/gnu-v2-abi.c46
-rw-r--r--gdb/gnu-v3-abi.c7
-rw-r--r--gdb/p-valprint.c66
-rw-r--r--gdb/testsuite/ChangeLog10
-rw-r--r--gdb/testsuite/gdb.trace/unavailable.cc33
-rw-r--r--gdb/testsuite/gdb.trace/unavailable.exp50
-rw-r--r--gdb/valops.c87
-rw-r--r--gdb/valprint.c6
-rw-r--r--gdb/valprint.h2
-rw-r--r--gdb/value.c4
16 files changed, 388 insertions, 149 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f7099b43871..bfef2e24c1d 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,58 @@
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
almost but not quite adjacent.
diff --git a/gdb/cp-abi.c b/gdb/cp-abi.c
index 0c21f910a2d..040962eba2c 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 53c8f93c43b..9bfa1b0356f 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 1a171ea20ce..255e9ce2236 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, "<invalid address>");
+ 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 81f3f4b7772..b1c45878c15 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 2cf1b4d686b..91fafa21524 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 effac401c27..3d49a06645d 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 <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;
+
+ 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 0b80571194b..25a437b3497 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 7031a771108..fc50e2a3140 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, "<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,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 0fab27496cc..eb00301dcd4 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,15 @@
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.
(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 7b4a2b20be3..36b74556677 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 8ec6343344c..ab8fe97b132 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 \\*\\) <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"
diff --git a/gdb/valops.c b/gdb/valops.c
index 1f25a32720a..5465abaac90 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 fd573c255e7..286ef9e74cd 100644
--- a/gdb/valprint.c
+++ b/gdb/valprint.c
@@ -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
diff --git a/gdb/valprint.h b/gdb/valprint.h
index 542a13aba98..b6ea7a99894 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 236b42f12a5..3b4d23a7374 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 *