| /* Support for printing C++ values for GDB, the GNU debugger. | 
 |  | 
 |    Copyright (C) 1986-2025 Free Software Foundation, Inc. | 
 |  | 
 |    This file is part of GDB. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include "event-top.h" | 
 | #include "extract-store-integer.h" | 
 | #include "gdbsupport/gdb_obstack.h" | 
 | #include "symtab.h" | 
 | #include "gdbtypes.h" | 
 | #include "expression.h" | 
 | #include "value.h" | 
 | #include "command.h" | 
 | #include "cli/cli-cmds.h" | 
 | #include "demangle.h" | 
 | #include "annotate.h" | 
 | #include "c-lang.h" | 
 | #include "target.h" | 
 | #include "cp-abi.h" | 
 | #include "valprint.h" | 
 | #include "cp-support.h" | 
 | #include "language.h" | 
 | #include "extension.h" | 
 | #include "typeprint.h" | 
 | #include "gdbsupport/byte-vector.h" | 
 | #include "gdbarch.h" | 
 | #include "cli/cli-style.h" | 
 | #include "gdbsupport/selftest.h" | 
 | #include "selftest-arch.h" | 
 |  | 
 | static struct obstack dont_print_vb_obstack; | 
 | static struct obstack dont_print_statmem_obstack; | 
 | static struct obstack dont_print_stat_array_obstack; | 
 |  | 
 | static void cp_print_static_field (struct type *, struct value *, | 
 | 				   struct ui_file *, int, | 
 | 				   const struct value_print_options *); | 
 |  | 
 | 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"; | 
 |  | 
 | /* Return truth value for assertion that TYPE is of the type | 
 |    "pointer to virtual function".  */ | 
 |  | 
 | int | 
 | cp_is_vtbl_ptr_type (struct type *type) | 
 | { | 
 |   const char *type_name = type->name (); | 
 |  | 
 |   return (type_name != NULL && !strcmp (type_name, vtbl_ptr_name)); | 
 | } | 
 |  | 
 | /* Return truth value for the assertion that TYPE is of the type | 
 |    "pointer to virtual function table".  */ | 
 |  | 
 | int | 
 | cp_is_vtbl_member (struct type *type) | 
 | { | 
 |   /* With older versions of g++, the vtbl field pointed to an array of | 
 |      structures.  Nowadays it points directly to the structure.  */ | 
 |   if (type->code () == TYPE_CODE_PTR) | 
 |     { | 
 |       type = type->target_type (); | 
 |       if (type->code () == TYPE_CODE_ARRAY) | 
 | 	{ | 
 | 	  type = type->target_type (); | 
 | 	  if (type->code () == TYPE_CODE_STRUCT    /* if not using thunks */ | 
 | 	      || type->code () == TYPE_CODE_PTR)   /* if using thunks */ | 
 | 	    { | 
 | 	      /* Virtual functions tables are full of pointers | 
 | 		 to virtual functions.  */ | 
 | 	      return cp_is_vtbl_ptr_type (type); | 
 | 	    } | 
 | 	} | 
 |       else if (type->code () == TYPE_CODE_STRUCT)  /* if not using thunks */ | 
 | 	{ | 
 | 	  return cp_is_vtbl_ptr_type (type); | 
 | 	} | 
 |       else if (type->code () == TYPE_CODE_PTR)     /* if using thunks */ | 
 | 	{ | 
 | 	  /* The type name of the thunk pointer is NULL when using | 
 | 	     dwarf2.  We could test for a pointer to a function, but | 
 | 	     there is no type info for the virtual table either, so it | 
 | 	     won't help.  */ | 
 | 	  return cp_is_vtbl_ptr_type (type); | 
 | 	} | 
 |     } | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Mutually recursive subroutines of cp_print_value and c_val_print to | 
 |    print out a structure's fields: cp_print_value_fields and | 
 |    cp_print_value. | 
 |  | 
 |    TYPE, VALADDR, ADDRESS, STREAM, RECURSE, and OPTIONS have the same | 
 |    meanings as in cp_print_value and c_val_print. | 
 |  | 
 |    2nd argument REAL_TYPE is used to carry over the type of the | 
 |    derived class across the recursion to base classes. | 
 |  | 
 |    DONT_PRINT is an array of baseclass types that we should not print, | 
 |    or zero if called from top level.  */ | 
 |  | 
 | void | 
 | cp_print_value_fields (struct value *val, struct ui_file *stream, | 
 | 		       int recurse, const struct value_print_options *options, | 
 | 		       struct type **dont_print_vb, | 
 | 		       int dont_print_statmem) | 
 | { | 
 |   int i, len, n_baseclasses; | 
 |   int fields_seen = 0; | 
 |   static int last_set_recurse = -1; | 
 |  | 
 |   struct type *type = check_typedef (val->type ()); | 
 |  | 
 |   if (recurse == 0) | 
 |     { | 
 |       /* Any object can be left on obstacks only during an unexpected | 
 | 	 error.  */ | 
 |  | 
 |       if (obstack_object_size (&dont_print_statmem_obstack) > 0) | 
 | 	{ | 
 | 	  obstack_free (&dont_print_statmem_obstack, NULL); | 
 | 	  obstack_begin (&dont_print_statmem_obstack, | 
 | 			 32 * sizeof (CORE_ADDR)); | 
 | 	} | 
 |       if (obstack_object_size (&dont_print_stat_array_obstack) > 0) | 
 | 	{ | 
 | 	  obstack_free (&dont_print_stat_array_obstack, NULL); | 
 | 	  obstack_begin (&dont_print_stat_array_obstack, | 
 | 			 32 * sizeof (struct type *)); | 
 | 	} | 
 |     } | 
 |  | 
 |   gdb_printf (stream, "{"); | 
 |   len = type->num_fields (); | 
 |   n_baseclasses = TYPE_N_BASECLASSES (type); | 
 |  | 
 |   /* First, print out baseclasses such that we don't print | 
 |      duplicates of virtual baseclasses.  */ | 
 |  | 
 |   if (n_baseclasses > 0) | 
 |     cp_print_value (val, stream, recurse + 1, options, dont_print_vb); | 
 |  | 
 |   /* Second, print out data fields */ | 
 |  | 
 |   /* If there are no data fields, skip this part */ | 
 |   if (len == n_baseclasses || !len) | 
 |     fprintf_styled (stream, metadata_style.style (), "<No data fields>"); | 
 |   else | 
 |     { | 
 |       size_t statmem_obstack_initial_size = 0; | 
 |       size_t stat_array_obstack_initial_size = 0; | 
 |       struct type *vptr_basetype = NULL; | 
 |       int vptr_fieldno; | 
 |  | 
 |       if (dont_print_statmem == 0) | 
 | 	{ | 
 | 	  statmem_obstack_initial_size = | 
 | 	    obstack_object_size (&dont_print_statmem_obstack); | 
 |  | 
 | 	  if (last_set_recurse != recurse) | 
 | 	    { | 
 | 	      stat_array_obstack_initial_size = | 
 | 		obstack_object_size (&dont_print_stat_array_obstack); | 
 |  | 
 | 	      last_set_recurse = recurse; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       vptr_fieldno = get_vptr_fieldno (type, &vptr_basetype); | 
 |       for (i = n_baseclasses; i < len; i++) | 
 | 	{ | 
 | 	  const gdb_byte *valaddr = val->contents_for_printing ().data (); | 
 |  | 
 | 	  /* If requested, skip printing of static fields.  */ | 
 | 	  if (!options->static_field_print | 
 | 	      && type->field (i).is_static ()) | 
 | 	    continue; | 
 |  | 
 | 	  if (fields_seen) | 
 | 	    { | 
 | 	      gdb_puts (",", stream); | 
 | 	      if (!options->prettyformat) | 
 | 		gdb_puts (" ", stream); | 
 | 	    } | 
 | 	  else if (n_baseclasses > 0) | 
 | 	    { | 
 | 	      if (options->prettyformat) | 
 | 		{ | 
 | 		  gdb_printf (stream, "\n"); | 
 | 		  print_spaces (2 + 2 * recurse, stream); | 
 | 		  gdb_puts ("members of ", stream); | 
 | 		  gdb_puts (type->name (), stream); | 
 | 		  gdb_puts (":", stream); | 
 | 		} | 
 | 	    } | 
 | 	  fields_seen = 1; | 
 |  | 
 | 	  if (options->prettyformat) | 
 | 	    { | 
 | 	      gdb_printf (stream, "\n"); | 
 | 	      print_spaces (2 + 2 * recurse, stream); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      stream->wrap_here (2 + 2 * recurse); | 
 | 	    } | 
 |  | 
 | 	  annotate_field_begin (type->field (i).type ()); | 
 |  | 
 | 	  if (type->field (i).is_static ()) | 
 | 	    { | 
 | 	      gdb_puts ("static ", stream); | 
 | 	      fprintf_symbol (stream, | 
 | 			      type->field (i).name (), | 
 | 			      current_language->la_language, | 
 | 			      DMGL_PARAMS | DMGL_ANSI); | 
 | 	    } | 
 | 	  else | 
 | 	    fputs_styled (type->field (i).name (), | 
 | 			  variable_name_style.style (), stream); | 
 | 	  annotate_field_name_end (); | 
 |  | 
 | 	  /* We tweak various options in a few cases below.  */ | 
 | 	  value_print_options options_copy = *options; | 
 | 	  value_print_options *opts = &options_copy; | 
 |  | 
 | 	  /* Do not print leading '=' in case of anonymous | 
 | 	     unions.  */ | 
 | 	  if (strcmp (type->field (i).name (), "")) | 
 | 	    gdb_puts (" = ", stream); | 
 | 	  else | 
 | 	    { | 
 | 	      /* If this is an anonymous field then we want to consider it | 
 | 		 as though it is at its parent's depth when it comes to the | 
 | 		 max print depth.  */ | 
 | 	      if (opts->max_depth != -1 && opts->max_depth < INT_MAX) | 
 | 		++opts->max_depth; | 
 | 	    } | 
 | 	  annotate_field_value (); | 
 |  | 
 | 	  if (!type->field (i).is_static () | 
 | 	      && type->field (i).is_packed ()) | 
 | 	    { | 
 | 	      struct value *v; | 
 |  | 
 | 	      /* Bitfields require special handling, especially due to | 
 | 		 byte order problems.  */ | 
 | 	      if (type->field (i).is_ignored ()) | 
 | 		{ | 
 | 		  fputs_styled ("<optimized out or zero length>", | 
 | 				metadata_style.style (), stream); | 
 | 		} | 
 | 	      else if (val->bits_synthetic_pointer | 
 | 		       (type->field (i).loc_bitpos (), | 
 | 			type->field (i).bitsize ())) | 
 | 		{ | 
 | 		  fputs_styled (_("<synthetic pointer>"), | 
 | 				metadata_style.style (), stream); | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  opts->deref_ref = false; | 
 |  | 
 | 		  v = value_field_bitfield (type, i, valaddr, | 
 | 					    val->embedded_offset (), val); | 
 |  | 
 | 		  common_val_print (v, stream, recurse + 1, | 
 | 				    opts, current_language); | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      if (type->field (i).is_ignored ()) | 
 | 		{ | 
 | 		  fputs_styled ("<optimized out or zero length>", | 
 | 				metadata_style.style (), stream); | 
 | 		} | 
 | 	      else if (type->field (i).is_static ()) | 
 | 		{ | 
 | 		  try | 
 | 		    { | 
 | 		      struct value *v = value_static_field (type, i); | 
 |  | 
 | 		      cp_print_static_field (type->field (i).type (), | 
 | 					     v, stream, recurse + 1, | 
 | 					     opts); | 
 | 		    } | 
 | 		  catch (const gdb_exception_error &ex) | 
 | 		    { | 
 | 		      fprintf_styled (stream, metadata_style.style (), | 
 | 				      _("<error reading variable: %s>"), | 
 | 				      ex.what ()); | 
 | 		    } | 
 | 		} | 
 | 	      else if (i == vptr_fieldno && type == vptr_basetype) | 
 | 		{ | 
 | 		  int i_offset = type->field (i).loc_bitpos () / 8; | 
 | 		  struct type *i_type = type->field (i).type (); | 
 |  | 
 | 		  if (valprint_check_validity (stream, i_type, i_offset, val)) | 
 | 		    { | 
 | 		      CORE_ADDR addr; | 
 |  | 
 | 		      i_offset += val->embedded_offset (); | 
 | 		      addr = extract_typed_address (valaddr + i_offset, i_type); | 
 | 		      print_function_pointer_address (opts, | 
 | 						      type->arch (), | 
 | 						      addr, stream); | 
 | 		    } | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  struct value *v = val->primitive_field (0, i, type); | 
 | 		  opts->deref_ref = false; | 
 | 		  common_val_print (v, stream, recurse + 1, opts, | 
 | 				    current_language); | 
 | 		} | 
 | 	    } | 
 | 	  annotate_field_end (); | 
 | 	} | 
 |  | 
 |       if (dont_print_statmem == 0) | 
 | 	{ | 
 | 	  size_t obstack_final_size = | 
 | 	   obstack_object_size (&dont_print_statmem_obstack); | 
 |  | 
 | 	  if (obstack_final_size > statmem_obstack_initial_size) | 
 | 	    { | 
 | 	      /* In effect, a pop of the printed-statics stack.  */ | 
 | 	      size_t shrink_bytes | 
 | 		= statmem_obstack_initial_size - obstack_final_size; | 
 | 	      obstack_blank_fast (&dont_print_statmem_obstack, shrink_bytes); | 
 | 	    } | 
 |  | 
 | 	  if (last_set_recurse != recurse) | 
 | 	    { | 
 | 	      obstack_final_size = | 
 | 		obstack_object_size (&dont_print_stat_array_obstack); | 
 |  | 
 | 	      if (obstack_final_size > stat_array_obstack_initial_size) | 
 | 		{ | 
 | 		  void *free_to_ptr = | 
 | 		    (char *) obstack_next_free (&dont_print_stat_array_obstack) | 
 | 		    - (obstack_final_size | 
 | 		       - stat_array_obstack_initial_size); | 
 |  | 
 | 		  obstack_free (&dont_print_stat_array_obstack, | 
 | 				free_to_ptr); | 
 | 		} | 
 | 	      last_set_recurse = -1; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (options->prettyformat) | 
 | 	{ | 
 | 	  gdb_printf (stream, "\n"); | 
 | 	  print_spaces (2 * recurse, stream); | 
 | 	} | 
 |     }				/* if there are data fields */ | 
 |  | 
 |   gdb_printf (stream, "}"); | 
 | } | 
 |  | 
 | /* A wrapper for cp_print_value_fields that tries to apply a | 
 |    pretty-printer first.  */ | 
 |  | 
 | static void | 
 | cp_print_value_fields_pp (struct value *val, | 
 | 			  struct ui_file *stream, | 
 | 			  int recurse, | 
 | 			  const struct value_print_options *options, | 
 | 			  struct type **dont_print_vb, | 
 | 			  int dont_print_statmem) | 
 | { | 
 |   int result = 0; | 
 |  | 
 |   /* Attempt to run an extension language pretty-printer if | 
 |      possible.  */ | 
 |   if (!options->raw) | 
 |     result | 
 |       = apply_ext_lang_val_pretty_printer (val, stream, | 
 | 					   recurse, options, | 
 | 					   current_language); | 
 |  | 
 |   if (!result) | 
 |     cp_print_value_fields (val, stream, recurse, options, dont_print_vb, | 
 | 			   dont_print_statmem); | 
 | } | 
 |  | 
 | /* 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 (val->type ()); | 
 |   CORE_ADDR address = val->address (); | 
 |   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 = val->contents_for_printing ().data (); | 
 |  | 
 |   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 = baseclass->name (); | 
 |       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, | 
 | 				      val->embedded_offset (), | 
 | 				      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 ()) | 
 | 		{ | 
 | 		  gdb::byte_vector buf (baseclass->length ()); | 
 |  | 
 | 		  if (target_read_memory (address + boffset, buf.data (), | 
 | 					  baseclass->length ()) != 0) | 
 | 		    skip = 1; | 
 | 		  base_val = value_from_contents_and_address (baseclass, | 
 | 							      buf.data (), | 
 | 							      address + boffset); | 
 | 		  baseclass = base_val->type (); | 
 | 		  boffset = 0; | 
 | 		} | 
 | 	      else | 
 | 		{ | 
 | 		  base_val = val; | 
 | 		} | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      base_val = val; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       /* Now do the printing.  */ | 
 |       if (options->prettyformat) | 
 | 	{ | 
 | 	  gdb_printf (stream, "\n"); | 
 | 	  print_spaces (2 * recurse, stream); | 
 | 	} | 
 |       gdb_puts ("<", stream); | 
 |       /* Not sure what the best notation is in the case where there is | 
 | 	 no baseclass name.  */ | 
 |       gdb_puts (basename ? basename : "", stream); | 
 |       gdb_puts ("> = ", stream); | 
 |  | 
 |       if (skip < 0) | 
 | 	val_print_unavailable (stream); | 
 |       else if (skip > 0) | 
 | 	val_print_invalid_address (stream); | 
 |       else | 
 | 	{ | 
 | 	  if (!val_print_check_max_depth (stream, recurse, options, | 
 | 					  current_language)) | 
 | 	    { | 
 | 	      struct value *baseclass_val = val->primitive_field (0, | 
 | 								  i, type); | 
 |  | 
 | 	      cp_print_value_fields_pp | 
 | 		(baseclass_val, stream, recurse, options, | 
 | 		 (struct type **) obstack_base (&dont_print_vb_obstack), | 
 | 		 0); | 
 | 	    } | 
 | 	} | 
 |       gdb_puts (", ", 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 | 
 |    obstack and refuse to print them more than once. | 
 |  | 
 |    VAL contains the value to print, TYPE, STREAM, RECURSE, and OPTIONS | 
 |    have the same meanings as in c_val_print.  */ | 
 |  | 
 | static void | 
 | cp_print_static_field (struct type *type, | 
 | 		       struct value *val, | 
 | 		       struct ui_file *stream, | 
 | 		       int recurse, | 
 | 		       const struct value_print_options *options) | 
 | { | 
 |   struct value_print_options opts; | 
 |  | 
 |   if (val->entirely_optimized_out ()) | 
 |     { | 
 |       val_print_optimized_out (val, stream); | 
 |       return; | 
 |     } | 
 |  | 
 |   struct type *real_type = check_typedef (type); | 
 |   if (real_type->code () == TYPE_CODE_STRUCT) | 
 |     { | 
 |       CORE_ADDR *first_dont_print; | 
 |       CORE_ADDR addr = val->address (); | 
 |       int i; | 
 |  | 
 |       first_dont_print | 
 | 	= (CORE_ADDR *) obstack_base (&dont_print_statmem_obstack); | 
 |       i = obstack_object_size (&dont_print_statmem_obstack) | 
 | 	/ sizeof (CORE_ADDR); | 
 |  | 
 |       while (--i >= 0) | 
 | 	{ | 
 | 	  if (addr == first_dont_print[i]) | 
 | 	    { | 
 | 	      fputs_styled (_("<same as static member of an already" | 
 | 			      " seen type>"), | 
 | 			    metadata_style.style (), stream); | 
 | 	      return; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       obstack_grow (&dont_print_statmem_obstack, (char *) &addr, | 
 | 		    sizeof (CORE_ADDR)); | 
 |       cp_print_value_fields_pp (val, stream, recurse, options, nullptr, 1); | 
 |       return; | 
 |     } | 
 |  | 
 |   if (real_type->code () == TYPE_CODE_ARRAY) | 
 |     { | 
 |       struct type **first_dont_print; | 
 |       int i; | 
 |       struct type *target_type = type->target_type (); | 
 |  | 
 |       first_dont_print | 
 | 	= (struct type **) obstack_base (&dont_print_stat_array_obstack); | 
 |       i = obstack_object_size (&dont_print_stat_array_obstack) | 
 | 	/ sizeof (struct type *); | 
 |  | 
 |       while (--i >= 0) | 
 | 	{ | 
 | 	  if (target_type == first_dont_print[i]) | 
 | 	    { | 
 | 	      fputs_styled (_("<same as static member of an already" | 
 | 			      " seen type>"), | 
 | 			    metadata_style.style (), stream); | 
 | 	      return; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       obstack_grow (&dont_print_stat_array_obstack, | 
 | 		    (char *) &target_type, | 
 | 		    sizeof (struct type *)); | 
 |     } | 
 |  | 
 |   opts = *options; | 
 |   opts.deref_ref = false; | 
 |   common_val_print (val, stream, recurse, &opts, current_language); | 
 | } | 
 |  | 
 | /* Find the field in *SELF, or its non-virtual base classes, with | 
 |    bit offset OFFSET.  Set *SELF to the containing type and *FIELDNO | 
 |    to the containing field number.  If OFFSET is not exactly at the | 
 |    start of some field, set *SELF to NULL.  */ | 
 |  | 
 | static void | 
 | cp_find_class_member (struct type **self_p, int *fieldno, | 
 | 		      LONGEST offset) | 
 | { | 
 |   struct type *self; | 
 |   unsigned int i; | 
 |   unsigned len; | 
 |  | 
 |   *self_p = check_typedef (*self_p); | 
 |   self = *self_p; | 
 |   len = self->num_fields (); | 
 |  | 
 |   for (i = TYPE_N_BASECLASSES (self); i < len; i++) | 
 |     { | 
 |       field &f = self->field (i); | 
 |       if (f.is_static ()) | 
 | 	continue; | 
 |       LONGEST bitpos = f.loc_bitpos (); | 
 |  | 
 |       QUIT; | 
 |       if (offset == bitpos) | 
 | 	{ | 
 | 	  *fieldno = i; | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |  | 
 |   for (i = 0; i < TYPE_N_BASECLASSES (self); i++) | 
 |     { | 
 |       LONGEST bitpos = self->field (i).loc_bitpos (); | 
 |       LONGEST bitsize = 8 * self->field (i).type ()->length (); | 
 |  | 
 |       if (offset >= bitpos && offset < bitpos + bitsize) | 
 | 	{ | 
 | 	  *self_p = self->field (i).type (); | 
 | 	  cp_find_class_member (self_p, fieldno, offset - bitpos); | 
 | 	  return; | 
 | 	} | 
 |     } | 
 |  | 
 |   *self_p = NULL; | 
 | } | 
 |  | 
 | void | 
 | cp_print_class_member (const gdb_byte *valaddr, struct type *type, | 
 | 		       struct ui_file *stream, const char *prefix) | 
 | { | 
 |   enum bfd_endian byte_order = type_byte_order (type); | 
 |  | 
 |   /* VAL is a byte offset into the structure type SELF_TYPE. | 
 |      Find the name of the field for that offset and | 
 |      print it.  */ | 
 |   struct type *self_type = TYPE_SELF_TYPE (type); | 
 |   LONGEST val; | 
 |   int fieldno; | 
 |  | 
 |   val = extract_signed_integer (valaddr, | 
 | 				type->length (), | 
 | 				byte_order); | 
 |  | 
 |   /* Pointers to data members are usually byte offsets into an object. | 
 |      Because a data member can have offset zero, and a NULL pointer to | 
 |      member must be distinct from any valid non-NULL pointer to | 
 |      member, either the value is biased or the NULL value has a | 
 |      special representation; both are permitted by ISO C++.  HP aCC | 
 |      used a bias of 0x20000000; HP cfront used a bias of 1; g++ 3.x | 
 |      and other compilers which use the Itanium ABI use -1 as the NULL | 
 |      value.  GDB only supports that last form; to add support for | 
 |      another form, make this into a cp-abi hook.  */ | 
 |  | 
 |   if (val == -1) | 
 |     { | 
 |       gdb_printf (stream, "NULL"); | 
 |       return; | 
 |     } | 
 |  | 
 |   cp_find_class_member (&self_type, &fieldno, val << 3); | 
 |  | 
 |   if (self_type != NULL) | 
 |     { | 
 |       const char *name; | 
 |  | 
 |       gdb_puts (prefix, stream); | 
 |       name = self_type->name (); | 
 |       if (name) | 
 | 	gdb_puts (name, stream); | 
 |       else | 
 | 	c_type_print_base (self_type, stream, 0, 0, &type_print_raw_options); | 
 |       gdb_printf (stream, "::"); | 
 |       fputs_styled (self_type->field (fieldno).name (), | 
 | 		    variable_name_style.style (), stream); | 
 |     } | 
 |   else | 
 |     gdb_printf (stream, "%ld", (long) val); | 
 | } | 
 |  | 
 | #if GDB_SELF_TEST | 
 |  | 
 | /* Test printing of TYPE_CODE_STRUCT values.  */ | 
 |  | 
 | static void | 
 | test_print_fields (gdbarch *arch) | 
 | { | 
 |   struct field *f; | 
 |   type *uint8_type = builtin_type (arch)->builtin_uint8; | 
 |   type *bool_type = builtin_type (arch)->builtin_bool; | 
 |   type *the_struct = arch_composite_type (arch, NULL, TYPE_CODE_STRUCT); | 
 |   the_struct->set_length (4); | 
 |  | 
 |   /* Value:  1110 1001 | 
 |      Fields: C-BB B-A- */ | 
 |   if (gdbarch_byte_order (arch) == BFD_ENDIAN_LITTLE) | 
 |     { | 
 |       f = append_composite_type_field_raw (the_struct, "A", bool_type); | 
 |       f->set_loc_bitpos (1); | 
 |       f->set_bitsize (1); | 
 |       f = append_composite_type_field_raw (the_struct, "B", uint8_type); | 
 |       f->set_loc_bitpos (3); | 
 |       f->set_bitsize (3); | 
 |       f = append_composite_type_field_raw (the_struct, "C", bool_type); | 
 |       f->set_loc_bitpos (7); | 
 |       f->set_bitsize (1); | 
 |     } | 
 |   /* According to the logic commented in "make_gdb_type_struct ()" of | 
 |    * target-descriptions.c, bit positions are numbered differently for | 
 |    * little and big endians.  */ | 
 |   else | 
 |     { | 
 |       f = append_composite_type_field_raw (the_struct, "A", bool_type); | 
 |       f->set_loc_bitpos (30); | 
 |       f->set_bitsize (1); | 
 |       f = append_composite_type_field_raw (the_struct, "B", uint8_type); | 
 |       f->set_loc_bitpos (26); | 
 |       f->set_bitsize (3); | 
 |       f = append_composite_type_field_raw (the_struct, "C", bool_type); | 
 |       f->set_loc_bitpos (24); | 
 |       f->set_bitsize (1); | 
 |     } | 
 |  | 
 |   value *val = value::allocate (the_struct); | 
 |   gdb_byte *contents = val->contents_writeable ().data (); | 
 |   store_unsigned_integer (contents, val->enclosing_type ()->length (), | 
 | 			  gdbarch_byte_order (arch), 0xe9); | 
 |  | 
 |   string_file out; | 
 |   struct value_print_options opts; | 
 |   get_no_prettyformat_print_options (&opts); | 
 |   cp_print_value_fields(val, &out, 0, &opts, NULL, 0); | 
 |   SELF_CHECK (out.string () == "{A = false, B = 5, C = true}"); | 
 |  | 
 |   out.clear(); | 
 |   opts.format = 'x'; | 
 |   cp_print_value_fields(val, &out, 0, &opts, NULL, 0); | 
 |   SELF_CHECK (out.string () == "{A = 0x0, B = 0x5, C = 0x1}"); | 
 | } | 
 |  | 
 | #endif | 
 |  | 
 |  | 
 | INIT_GDB_FILE (cp_valprint) | 
 | { | 
 | #if GDB_SELF_TEST | 
 |   selftests::register_test_foreach_arch ("print-fields", test_print_fields); | 
 | #endif | 
 |  | 
 |   obstack_begin (&dont_print_stat_array_obstack, | 
 | 		 32 * sizeof (struct type *)); | 
 |   obstack_begin (&dont_print_statmem_obstack, | 
 | 		 32 * sizeof (CORE_ADDR)); | 
 |   obstack_begin (&dont_print_vb_obstack, | 
 | 		 32 * sizeof (struct type *)); | 
 | } |