This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[unavailable values part 1, 17/17] unavailable vptr / virtual base offset


Before:

 set print object on, object not collected at all:

  print derived_unavail
  $41 = {<error reading variable>

 set print object on, only vptr collected:

  print derived_partial
  $42 = (Derived) {<Middle> = {<error reading variable>

 set print object off, object not collected at all:

  print derived_unavail
  $45 = {<error reading variable>
  
 set print object off, only vptr collected:

  print derived_partial
  $46 = {<Middle> = {<error reading variable>

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 = {<Middle> = <unavailable>, _vptr.Derived = <unavailable>, z = <unavailable>}

 set print object on, only vptr collected:

  print derived_partial
  $42 = (Derived) {<Middle> = {<Base> = <unavailable>, _vptr.Middle = <unavailable>, y = <unavailable>}, _vptr.Derived = 0x400e60, z = <unavailable>}

 set print object off, object not collected at all:

  print derived_unavail
  $45 = {<Middle> = <unavailable>, _vptr.Derived = <unavailable>, z = <unavailable>}

 set print object off, only vptr collected:

  print derived_partial
  $46 = {<Middle> = {<Base> = <unavailable>, _vptr.Middle = <unavailable>, y = <unavailable>}, _vptr.Derived = 0x400e60, z = <unavailable>}

-- 
Pedro Alves

2011-02-07  Pedro Alves  <pedro@codesourcery.com>

	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.

---
 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, "<invalid address>");
+      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 <ctype.h>
 
@@ -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, "<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,
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, _("<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
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 \\*\\) <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"


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]