[45/55] Introduce cp_print_value

Message ID 20191208182958.10181-46-tom@tromey.com
State New, archived
Headers

Commit Message

Tom Tromey Dec. 8, 2019, 6:29 p.m. UTC
  This adds cp_print_value, a value-based analogue of cp_print_val, and
changes cp_print_value_fields to use it.

gdb/ChangeLog
2019-12-08  Tom Tromey  <tom@tromey.com>

	* cp-valprint.c (cp_print_value_fields): Update.
	(cp_print_value): New function.

Change-Id: I8902ff3702eddd2ac2bfbfbd6a485b94b56eaba6
---
 gdb/ChangeLog     |   5 ++
 gdb/cp-valprint.c | 168 ++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 169 insertions(+), 4 deletions(-)
  

Patch

diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c
index 77dbaae891f..143d77cb223 100644
--- a/gdb/cp-valprint.c
+++ b/gdb/cp-valprint.c
@@ -54,6 +54,10 @@  static void cp_print_value (struct type *, struct type *,
 			    const struct value_print_options *,
 			    struct type **);
 
+static void cp_print_value (struct value *, struct ui_file *,
+			    int, const struct value_print_options *,
+			    struct type **);
+
 
 /* GCC versions after 2.4.5 use this.  */
 const char vtbl_ptr_name[] = "__vtbl_ptr_type";
@@ -410,7 +414,6 @@  cp_print_value_fields (struct value *val, struct ui_file *stream,
   static int last_set_recurse = -1;
 
   struct type *type = check_typedef (value_type (val));
-  CORE_ADDR address = value_address (val);
   
   if (recurse == 0)
     {
@@ -439,9 +442,7 @@  cp_print_value_fields (struct value *val, struct ui_file *stream,
      duplicates of virtual baseclasses.  */
 
   if (n_baseclasses > 0)
-    cp_print_value (type, type, 0, address, stream,
-		    recurse + 1, val, options,
-		    dont_print_vb);
+    cp_print_value (val, stream, recurse + 1, options, dont_print_vb);
 
   /* Second, print out data fields */
 
@@ -601,6 +602,7 @@  cp_print_value_fields (struct value *val, struct ui_file *stream,
 		    {
 		      CORE_ADDR addr;
 		      
+		      i_offset += value_embedded_offset (val);
 		      addr = extract_typed_address (valaddr + i_offset, i_type);
 		      print_function_pointer_address (opts,
 						      get_type_arch (type),
@@ -874,6 +876,164 @@  cp_print_value (struct type *type, struct type *real_type,
     }
 }
 
+/* Special val_print routine to avoid printing multiple copies of
+   virtual baseclasses.  */
+
+static void
+cp_print_value (struct value *val, struct ui_file *stream,
+		int recurse, const struct value_print_options *options,
+		struct type **dont_print_vb)
+{
+  struct type *type = check_typedef (value_type (val));
+  CORE_ADDR address = value_address (val);
+  struct type **last_dont_print
+    = (struct type **) obstack_next_free (&dont_print_vb_obstack);
+  struct obstack tmp_obstack = dont_print_vb_obstack;
+  int i, n_baseclasses = TYPE_N_BASECLASSES (type);
+  const gdb_byte *valaddr = value_contents_for_printing (val);
+
+  if (dont_print_vb == 0)
+    {
+      /* If we're at top level, carve out a completely fresh chunk of
+         the obstack and use that until this particular invocation
+         returns.  */
+      /* Bump up the high-water mark.  Now alpha is omega.  */
+      obstack_finish (&dont_print_vb_obstack);
+    }
+
+  for (i = 0; i < n_baseclasses; i++)
+    {
+      LONGEST boffset = 0;
+      int skip = 0;
+      struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
+      const char *basename = TYPE_NAME (baseclass);
+      struct value *base_val = NULL;
+
+      if (BASETYPE_VIA_VIRTUAL (type, i))
+	{
+	  struct type **first_dont_print
+	    = (struct type **) obstack_base (&dont_print_vb_obstack);
+
+	  int j = (struct type **)
+	    obstack_next_free (&dont_print_vb_obstack) - first_dont_print;
+
+	  while (--j >= 0)
+	    if (baseclass == first_dont_print[j])
+	      goto flush_it;
+
+	  obstack_ptr_grow (&dont_print_vb_obstack, baseclass);
+	}
+
+      try
+	{
+	  boffset = baseclass_offset (type, i, valaddr,
+				      value_embedded_offset (val),
+				      address, val);
+	}
+      catch (const gdb_exception_error &ex)
+	{
+	  if (ex.error == NOT_AVAILABLE_ERROR)
+	    skip = -1;
+	  else
+	    skip = 1;
+	}
+
+      if (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 < 0 || boffset >= TYPE_LENGTH (type))
+		{
+		  gdb::byte_vector buf (TYPE_LENGTH (baseclass));
+
+		  if (target_read_memory (address + boffset, buf.data (),
+					  TYPE_LENGTH (baseclass)) != 0)
+		    skip = 1;
+		  base_val = value_from_contents_and_address (baseclass,
+							      buf.data (),
+							      address + boffset);
+		  baseclass = value_type (base_val);
+		  boffset = 0;
+		}
+	      else
+		{
+		  base_val = val;
+		}
+	    }
+	  else
+	    {
+	      base_val = val;
+	    }
+	}
+
+      /* Now do the printing.  */
+      if (options->prettyformat)
+	{
+	  fprintf_filtered (stream, "\n");
+	  print_spaces_filtered (2 * recurse, stream);
+	}
+      fputs_filtered ("<", stream);
+      /* Not sure what the best notation is in the case where there is
+         no baseclass name.  */
+      fputs_filtered (basename ? basename : "", stream);
+      fputs_filtered ("> = ", stream);
+
+      if (skip < 0)
+	val_print_unavailable (stream);
+      else if (skip > 0)
+	val_print_invalid_address (stream);
+      else
+	{
+	  int result = 0;
+
+	  if (options->max_depth > -1
+	      && recurse >= options->max_depth)
+	    {
+	      const struct language_defn *language = current_language;
+	      gdb_assert (language->la_struct_too_deep_ellipsis != NULL);
+	      fputs_filtered (language->la_struct_too_deep_ellipsis, stream);
+	    }
+	  else
+	    {
+	      /* Attempt to run an extension language pretty-printer on the
+		 baseclass if possible.  */
+	      if (!options->raw)
+		result
+		  = apply_ext_lang_val_pretty_printer (baseclass, boffset,
+						       value_address (base_val),
+						       stream, recurse,
+						       base_val, options,
+						       current_language);
+
+	      if (!result)
+		cp_print_value_fields (value_primitive_field (val, 0, i, type),
+				       stream, recurse, options,
+				       ((struct type **)
+					obstack_base (&dont_print_vb_obstack)),
+				       0);
+	    }
+	}
+      fputs_filtered (", ", stream);
+
+    flush_it:
+      ;
+    }
+
+  if (dont_print_vb == 0)
+    {
+      /* Free the space used to deal with the printing
+         of this type from top level.  */
+      obstack_free (&dont_print_vb_obstack, last_dont_print);
+      /* Reset watermark so that we can continue protecting
+         ourselves from whatever we were protecting ourselves.  */
+      dont_print_vb_obstack = tmp_obstack;
+    }
+}
+
 /* Print value of a static member.  To avoid infinite recursion when
    printing a class that contains a static instance of the class, we
    keep the addresses of all printed static member classes in an