binutils-gdb/gdb/cp-valprint.c
Peter Schauer 0db3fe94c3 Add support for Irix 6.2 native O32 and N32 ABI.
* config.in, configure.in, configure:  Check for <objlist.h>.
	* configure.tgt:  Handle mips*-sgi-irix6* like irix5 for now.

	* cp-valprint.c (cp_print_value_fields):  Use SYMBOL_VALUE_ADDRESS
	instead of SYMBOL_BLOCK_VALUE to get the address of a static member.

	* dwarf2read.c:  Turn warnings and recoverable errors into complaints,
	add new complaints where appropriate.
	gcc -Wall cleanup.
	(struct line_head):  Change line_base from char to int to avoid
	problems with compilers whose plain char is represented by an
	unsigned char.
	(struct partial_die_info):  Add is_declaration field.
	(dwarf2_tmp_obstack):  New obstack for allocating temporary storage
	used during symbol reading.
	(cu_header_offset):  New variable for resolving relative reference
	dies.
	(optimized_out, basereg, islocal, frame_base_reg, frame_base_offset):
	New interface variables for decode_locdesc.
	(struct dwarf2_pinfo):  New structure for communication between
	psymtab and symtab reading, passed via pst->read_symtab_private.
	(dwarf2_has_info, dwarf2_build_psymtabs):  Accept objects files
	without line number sections.
	(dwarf2_build_psymtabs_hard):  Initialize temporary obstack
	for symbol reading.
	Allocate and initialize pst->read_symtab_private.
	Relocate pst->textlow and pst->texthigh with baseaddr.
	(scan_partial_symbols):  Do not add DW_AT_declaration symbols
	to the partial symbol table.
	Add file scope enumerator symbols to the partial symbol table.
	Fix typo in highpc computation.
	If we didn't find a lowpc, set it to highpc to avoid complaints
	from `maint check.
	(add_partial_symbol):  Relocate symbol values with baseaddr.
	Add static DW_TAG_subprogram and DW_TAG_variable symbols to the
	minimal symbol table.
        Obtain symbol values for DW_TAG_variable symbols from the location
	descriptor, skip symbols with missing location desciptors.
	Skip symbols for aggregate types without children.
	Handle enumerator symbols.
	(dwarf2_psymtab_to_symtab):  Issue symbol reading message if verbose.
	(psymtab_to_symtab_1):  Set local variables from
	pst->read_symtab_private, set cu_header_offset and baseaddr.
	Initialize temporary obstack for symbol reading, initialize
	buildsym and add a cleanup to really_free_pendings.
	Relocate highpc with baseaddr when calling end_symtab.
	If the compilation is from a C file generated by language
	preprocessors, do not set the symtab language if it was already
	deduced by start_subfile.
	Removed verbose sorting symbol table message.
	(process_die):  Handle DW_TAG_ptr_to_member_type and
	DW_TAG_reference_type.
	Use read_subroutine_type to get the function type for
	DW_TAG_subprogram before calling read_func_scope.
	(read_file_scope):  Initialize file name to <unknown>, start_subfile
	expects a non-NULL name.
	If we didn't find a lowpc, set it to highpc to avoid complaints
	from finish_symbol.
	Relocate lowpc and highpc with baseaddr.
	Get rid of Irix6.2 native cc compile machine prefix in comp_dir.
	Zero out ftypes for each new compilation unit (may be different
	language or different objfile).
	Accept compilation units without line number information, pass
	comp_dir to decode_lines.
	(read_func_scope):  Initialize function name to <unknown> to avoid
	core dumps when DW_AT_name is missing.
	Relocate lowpc and highpc with baseaddr.
	Handle DW_AT_frame_base, keep result for DW_OP_fbreg operations.
	Pass function type to new_symbol.
	(read_lexical_block_scope):  Relocate lowpc and highpc with baseaddr.
	(read_structure_scope):  Set TYPE_TAG_NAME, not TYPE_NAME.
	Handle DW_TAG_class_type.
	Copy fields to type_obstack, release temporary storage for fields.
	Don't add symbol if die is a stub die and has no children.
	Handle C++ static member fields.
	(read_enumeration):  Set TYPE_TAG_NAME, not TYPE_NAME.
	Copy fields to type_obstack, release temporary storage for fields.
	Let new_symbol handle the symbol creation for enumerators
	instead of handcrafting a symbol.
	Determine signedness of enum type from enumerators.
	(dwarf_read_array_type):  Handle variable length arrays.
	Use lookup_pointer_type instead of handcrafting a type.
	Create array type only if a DW_TAG_subrange_type was found.
	(read_tag_pointer_type, read_tag_reference_type):
	Use lookup_pointer_type and lookup_reference_type instead
	of handcrafting a type.
	(read_tag_ptr_to_member_type):  New function to handle
	DW_TAG_ptr_to_member_type.
	(read_subroutine_type):  Handle parameter dies.
	Use lookup_function_type instead of handcrafting a type.
	(read_typedef):  Allocate a TYPE_CODE_TYPEDEF type for the typedef.
	(read_base_type):  If the type has a name, use init_type to create
	a new type instead of second guessing a fundamental type.
	(read_comp_unit):  Reset die reference table before building
	a new one.
	(dwarf2_read_section):  Read section contents into psymbol_obstack.
	(dwarf2_read_abbrevs):  Handle unterminated abbreviations
	for a compile unit gracefully.
	(read_partial_die):  Zero partial die before reading its info.
	Handle DW_AT_declaration.
	Fix typo in handling of DW_FORM_block4.
	(read_full_die):  Fix typo in handling of DW_FORM_block4.
	(read_1_signed_byte, read_2_signed_bytes, read_4_signed_bytes):
	New routines to get signed values from a buffer.
	(read_n_bytes, read_string):  Allocate storage from the temporary
	obstack. If the host char size permits it, return pointer
	to buffer instead of allocating storage.
	(set_cu_language):  Handle DW_LANG_Mips_Assembler.
	(dwarf_attr):  Return NULL if reference die for DW_AT_specification
	or DW_AT_abstract_origin die is not found.
	(record_minimal_symbol):  Removed, replaced with a direct call to
	prim_record_minimal_symbol, it now handles saving the string itself.
	(convert_locdesc):  Removed, partial symtab reading now uses
	decode_locdesc.
	(dwarf_attr):  Use dwarf2_get_ref_die_offset to get the absolute
	offset for the die reference.
	(dwarf_decode_lines):  Complain if the line section info is missing.
	Use read_1_signed_byte to extract lh.line_base to avoid
        problems with compilers whose plain char is represented by an
        unsigned char.
	Add cleanups for allocated temporary storage.
	Start a subfile for the first file in the state machine.
	Fix off by one problem with dirs.dirs access.
	Use comp_dir when directory index is 0.
	Support multiple sequences (from Jason Merrill <jason@cygnus.com>).
	(dwarf2_start_subfile):  Try to keep line numbers from identical
	absolute and relative file names in a common subfile.
	(new_symbol):  Allocate symbol and symbol name on the symbol_obstack.
	Set SYMBOL_LINE from DW_AT_decl_line if present.
	Set SYMBOL_TYPE from passed type if not NULL.
	Change DW_TAG_variable symbol types with missing type entries
	to a sensible type.
	Handle optimized_out, offreg and islocal storage classes.
	Add external symbols with type information whose address isn't
	known as LOC_UNRESOLVED symbols.
	Synthesize typedefs for C++ classes, structs, unions and enumerations.
	Handle DW_TAG_enumerator symbols, complain for unrecognized
	symbol tags.
	(die_type):  A missing DW_AT_type represents a void type.
	Use dwarf2_get_ref_die_offset to get the absolute offset for
	the die reference.
	(die_containing_type):  New function to build type from
	DW_AT_containing_type attribut.
	(read_type_die):  Handle DW_TAG_ptr_to_member_type.
	Treat DW_TAG_subprogram like DW_TAG_subroutine_type.
	(dwarf_base_type):  Fix typo with creation of FT_UNSIGNED_SHORT
	fundamental type.
	(create_name):  Removed, symbol name allocation is now done
	in new_symbol.
	(dump_die):  Use print_address_numeric to print a CORE_ADDR.
	(dwarf2_empty_die_ref_table):  New function to clear the die
	reference table.
	(dwarf2_get_ref_die_offset):  New function to get the absolute
	die offset from a die reference attribute.
	(decode_locdesc):  Complete rewrite using a stack, code mostly
	borrowed from dwarfread.c:locval.
	(dwarf_alloc_type):  Removed, replaced by direct calls to alloc_type.
	(dwarf_alloc_block):  Allocate block on temporary obstack.

	* elfread.c (elf_symtab_read):  When handling Irix dynamic symbols,
	skip section name symbols and relocate all others.
	(elf_symfile_read):  Build dwarf2 psymtab even if offset is non-zero.

	* irix5-nat.c (fetch_core_registers):  Handle core_reg_sect
	from N32 executables. Call registers_fetched after extracting
	the registers.
	(obj_list_variant, struct link_map, LM_OFFSET, LM_ADDR):  New
	definitions to enable support of O32 and N32 format objlists.
	(struct so_list):  New members offset, so_name and lmstart to
	eliminate dependencies from the objlist format used.
	(solib_map_sections, symbol_add_stub, solib_add,
	info_sharedlibrary_command, solib_address, clear_solib):  Use
	so_name and LM_OFFSET.
	(first_link_map_member):  Rewrite to enable support of O32 and N32
	format objlists.
	(next_link_map_member, xfer_link_map_member):  New functions to
	support O32 and N32 format objlists.
	(find_solib):  Use first_link_map_member, next_link_map_member and
	xfer_link_map_member.
	(solib_create_inferior_hook):  Use TARGET_SIGNAL_* instead of
	host signal numbers.

	* mdebugread.c (parse_partial_symbols, handle_psymbol_enumerators):
	Pass CORE_ADDR variant to add_psymbol_to_list.

	* mips-tdep.c (heuristic_proc_desc):  Stop examining the prologue
	if we encounter a positive stack adjustment. Handle `move $30,$sp'.
	Handle `sd reg,offset($sp)' for 32 bit ABIs.

	* symmisc.c (dump_msymbols, print_partial_symbols):  Use
	print_address_numeric to print a SYMBOL_VALUE_ADDRESS.
	(dump_symtab):  Print compilation directory if it is not NULL.

	* valops.c (search_struct_field, value_struct_elt_for_reference):
	Use SYMBOL_VALUE_ADDRESS instead of SYMBOL_BLOCK_VALUE to get the
	address of a static member.
1996-12-01 08:33:39 +00:00

619 lines
17 KiB
C

/* Support for printing C++ values for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991, 1994, 1995, 1996
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include "defs.h"
#include "obstack.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "expression.h"
#include "value.h"
#include "command.h"
#include "gdbcmd.h"
#include "demangle.h"
#include "annotate.h"
#include "gdb_string.h"
#include "c-lang.h"
#include "target.h"
int vtblprint; /* Controls printing of vtbl's */
int objectprint; /* Controls looking up an object's derived type
using what we find in its vtables. */
static int static_field_print; /* Controls printing of static fields. */
static struct obstack dont_print_vb_obstack;
static struct obstack dont_print_statmem_obstack;
static void
cp_print_static_field PARAMS ((struct type *, value_ptr, GDB_FILE *, int, int,
enum val_prettyprint));
static void
cp_print_value PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *,
int, int, enum val_prettyprint, struct type **));
void
cp_print_class_method (valaddr, type, stream)
char *valaddr;
struct type *type;
GDB_FILE *stream;
{
struct type *domain;
struct fn_field *f = NULL;
int j = 0;
int len2;
int offset;
char *kind = "";
CORE_ADDR addr;
struct symbol *sym;
unsigned len;
unsigned int i;
struct type *target_type = check_typedef (TYPE_TARGET_TYPE (type));
domain = TYPE_DOMAIN_TYPE (target_type);
if (domain == (struct type *)NULL)
{
fprintf_filtered (stream, "<unknown>");
return;
}
addr = unpack_pointer (lookup_pointer_type (builtin_type_void), valaddr);
if (METHOD_PTR_IS_VIRTUAL (addr))
{
offset = METHOD_PTR_TO_VOFFSET (addr);
len = TYPE_NFN_FIELDS (domain);
for (i = 0; i < len; i++)
{
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_VOFFSET (f, j) == offset)
{
kind = "virtual ";
goto common;
}
}
}
}
else
{
sym = find_pc_function (addr);
if (sym == 0)
{
error ("invalid pointer to member function");
}
len = TYPE_NFN_FIELDS (domain);
for (i = 0; i < len; i++)
{
f = TYPE_FN_FIELDLIST1 (domain, i);
len2 = TYPE_FN_FIELDLIST_LENGTH (domain, i);
for (j = 0; j < len2; j++)
{
QUIT;
if (TYPE_FN_FIELD_STUB (f, j))
check_stub_method (domain, i, j);
if (STREQ (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
{
goto common;
}
}
}
}
common:
if (i < len)
{
fprintf_filtered (stream, "&");
c_type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
fprintf_unfiltered (stream, kind);
if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
&& is_cplus_marker (TYPE_FN_FIELD_PHYSNAME (f, j)[1]))
{
cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
TYPE_FN_FIELDLIST_NAME (domain, i),
0, stream);
}
else
{
cp_type_print_method_args (TYPE_FN_FIELD_ARGS (f, j), "",
TYPE_FN_FIELDLIST_NAME (domain, i),
0, stream);
}
}
else
{
fprintf_filtered (stream, "(");
type_print (type, "", stream, -1);
fprintf_filtered (stream, ") %d", (int) addr >> 3);
}
}
/* This was what it was for gcc 2.4.5 and earlier. */
static const char vtbl_ptr_name_old[] =
{ CPLUS_MARKER,'v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
/* It was changed to this after 2.4.5. */
const char vtbl_ptr_name[] =
{ '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
/* Return truth value for assertion that TYPE is of the type
"pointer to virtual function". */
int
cp_is_vtbl_ptr_type(type)
struct type *type;
{
char *typename = type_name_no_tag (type);
return (typename != NULL
&& (STREQ (typename, vtbl_ptr_name)
|| STREQ (typename, vtbl_ptr_name_old)));
}
/* Return truth value for the assertion that TYPE is of the type
"pointer to virtual function table". */
int
cp_is_vtbl_member(type)
struct type *type;
{
if (TYPE_CODE (type) == TYPE_CODE_PTR)
{
type = TYPE_TARGET_TYPE (type);
if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
{
type = TYPE_TARGET_TYPE (type);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT /* if not using thunks */
|| TYPE_CODE (type) == TYPE_CODE_PTR) /* if using thunks */
{
/* Virtual functions tables are full of pointers
to virtual functions. */
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 PRETTY have the
same meanings as in cp_print_value and c_val_print.
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 (type, valaddr, address, stream, format, recurse, pretty,
dont_print_vb, dont_print_statmem)
struct type *type;
char *valaddr;
CORE_ADDR address;
GDB_FILE *stream;
int format;
int recurse;
enum val_prettyprint pretty;
struct type **dont_print_vb;
int dont_print_statmem;
{
int i, len, n_baseclasses;
struct obstack tmp_obstack;
char *last_dont_print = obstack_next_free (&dont_print_statmem_obstack);
CHECK_TYPEDEF (type);
fprintf_filtered (stream, "{");
len = TYPE_NFIELDS (type);
n_baseclasses = TYPE_N_BASECLASSES (type);
/* Print out baseclasses such that we don't print
duplicates of virtual baseclasses. */
if (n_baseclasses > 0)
cp_print_value (type, valaddr, address, stream,
format, recurse+1, pretty, dont_print_vb);
if (!len && n_baseclasses == 1)
fprintf_filtered (stream, "<No data fields>");
else
{
extern int inspect_it;
int fields_seen = 0;
if (dont_print_statmem == 0)
{
/* If we're at top level, carve out a completely fresh
chunk of the obstack and use that until this particular
invocation returns. */
tmp_obstack = dont_print_statmem_obstack;
obstack_finish (&dont_print_statmem_obstack);
}
for (i = n_baseclasses; i < len; i++)
{
/* If requested, skip printing of static fields. */
if (!static_field_print && TYPE_FIELD_STATIC (type, i))
continue;
if (fields_seen)
fprintf_filtered (stream, ", ");
else if (n_baseclasses > 0)
{
if (pretty)
{
fprintf_filtered (stream, "\n");
print_spaces_filtered (2 + 2 * recurse, stream);
fputs_filtered ("members of ", stream);
fputs_filtered (type_name_no_tag (type), stream);
fputs_filtered (": ", stream);
}
}
fields_seen = 1;
if (pretty)
{
fprintf_filtered (stream, "\n");
print_spaces_filtered (2 + 2 * recurse, stream);
}
else
{
wrap_here (n_spaces (2 + 2 * recurse));
}
if (inspect_it)
{
if (TYPE_CODE (TYPE_FIELD_TYPE (type, i)) == TYPE_CODE_PTR)
fputs_filtered ("\"( ptr \"", stream);
else
fputs_filtered ("\"( nodef \"", stream);
if (TYPE_FIELD_STATIC (type, i))
fputs_filtered ("static ", stream);
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus,
DMGL_PARAMS | DMGL_ANSI);
fputs_filtered ("\" \"", stream);
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus,
DMGL_PARAMS | DMGL_ANSI);
fputs_filtered ("\") \"", stream);
}
else
{
annotate_field_begin (TYPE_FIELD_TYPE (type, i));
if (TYPE_FIELD_STATIC (type, i))
fputs_filtered ("static ", stream);
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus,
DMGL_PARAMS | DMGL_ANSI);
annotate_field_name_end ();
fputs_filtered (" = ", stream);
annotate_field_value ();
}
if (!TYPE_FIELD_STATIC (type, i) && TYPE_FIELD_PACKED (type, i))
{
value_ptr v;
/* Bitfields require special handling, especially due to byte
order problems. */
if (TYPE_FIELD_IGNORE (type, i))
{
fputs_filtered ("<optimized out or zero length>", stream);
}
else
{
v = value_from_longest (TYPE_FIELD_TYPE (type, i),
unpack_field_as_long (type, valaddr, i));
val_print (TYPE_FIELD_TYPE(type, i), VALUE_CONTENTS (v), 0,
stream, format, 0, recurse + 1, pretty);
}
}
else
{
if (TYPE_FIELD_IGNORE (type, i))
{
fputs_filtered ("<optimized out or zero length>", stream);
}
else if (TYPE_FIELD_STATIC (type, i))
{
value_ptr v;
char *phys_name = TYPE_FIELD_STATIC_PHYSNAME (type, i);
struct symbol *sym =
lookup_symbol (phys_name, 0, VAR_NAMESPACE, 0, NULL);
if (sym == NULL)
fputs_filtered ("<optimized out>", stream);
else
{
v = value_at (TYPE_FIELD_TYPE (type, i),
SYMBOL_VALUE_ADDRESS (sym));
cp_print_static_field (TYPE_FIELD_TYPE (type, i), v,
stream, format, recurse + 1,
pretty);
}
}
else
{
val_print (TYPE_FIELD_TYPE (type, i),
valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
address + TYPE_FIELD_BITPOS (type, i) / 8,
stream, format, 0, recurse + 1, pretty);
}
}
annotate_field_end ();
}
if (dont_print_statmem == 0)
{
/* Free the space used to deal with the printing
of the members from top level. */
obstack_free (&dont_print_statmem_obstack, last_dont_print);
dont_print_statmem_obstack = tmp_obstack;
}
if (pretty)
{
fprintf_filtered (stream, "\n");
print_spaces_filtered (2 * recurse, stream);
}
}
fprintf_filtered (stream, "}");
}
/* Special val_print routine to avoid printing multiple copies of virtual
baseclasses. */
static void
cp_print_value (type, valaddr, address, stream, format, recurse, pretty,
dont_print_vb)
struct type *type;
char *valaddr;
CORE_ADDR address;
GDB_FILE *stream;
int format;
int recurse;
enum val_prettyprint pretty;
struct type **dont_print_vb;
{
struct obstack tmp_obstack;
struct type **last_dont_print
= (struct type **)obstack_next_free (&dont_print_vb_obstack);
int i, n_baseclasses = TYPE_N_BASECLASSES (type);
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. */
tmp_obstack = dont_print_vb_obstack;
/* Bump up the high-water mark. Now alpha is omega. */
obstack_finish (&dont_print_vb_obstack);
}
for (i = 0; i < n_baseclasses; i++)
{
int boffset;
struct type *baseclass = check_typedef (TYPE_BASECLASS (type, i));
char *basename = TYPE_NAME (baseclass);
char *base_valaddr;
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);
}
boffset = baseclass_offset (type, i , valaddr, address);
if (pretty)
{
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);
/* 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)))
{
base_valaddr = (char *) alloca (TYPE_LENGTH (baseclass));
if (target_read_memory (address + boffset, base_valaddr,
TYPE_LENGTH (baseclass)) != 0)
boffset = -1;
}
else
base_valaddr = valaddr + boffset;
if (boffset == -1)
fprintf_filtered (stream, "<invalid address>");
else
cp_print_value_fields (baseclass, base_valaddr, address + boffset,
stream, format, recurse, pretty,
(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 obstack and refuse to print them more
than once.
VAL contains the value to print, TYPE, STREAM, RECURSE, and PRETTY
have the same meanings as in c_val_print. */
static void
cp_print_static_field (type, val, stream, format, recurse, pretty)
struct type *type;
value_ptr val;
GDB_FILE *stream;
int format;
int recurse;
enum val_prettyprint pretty;
{
if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
{
CORE_ADDR *first_dont_print;
int i;
first_dont_print
= (CORE_ADDR *)obstack_base (&dont_print_statmem_obstack);
i = (CORE_ADDR *)obstack_next_free (&dont_print_statmem_obstack)
- first_dont_print;
while (--i >= 0)
{
if (VALUE_ADDRESS (val) == first_dont_print[i])
{
fputs_filtered ("<same as static member of an already seen type>",
stream);
return;
}
}
obstack_grow (&dont_print_statmem_obstack, (char *) &VALUE_ADDRESS (val),
sizeof (CORE_ADDR));
CHECK_TYPEDEF (type);
cp_print_value_fields (type, VALUE_CONTENTS (val), VALUE_ADDRESS (val),
stream, format, recurse, pretty, NULL, 1);
return;
}
val_print (type, VALUE_CONTENTS (val), VALUE_ADDRESS (val),
stream, format, 0, recurse, pretty);
}
void
cp_print_class_member (valaddr, domain, stream, prefix)
char *valaddr;
struct type *domain;
GDB_FILE *stream;
char *prefix;
{
/* VAL is a byte offset into the structure type DOMAIN.
Find the name of the field for that offset and
print it. */
int extra = 0;
int bits = 0;
register unsigned int i;
unsigned len = TYPE_NFIELDS (domain);
/* @@ Make VAL into bit offset */
LONGEST val = unpack_long (builtin_type_int, valaddr) << 3;
for (i = TYPE_N_BASECLASSES (domain); i < len; i++)
{
int bitpos = TYPE_FIELD_BITPOS (domain, i);
QUIT;
if (val == bitpos)
break;
if (val < bitpos && i != 0)
{
/* Somehow pointing into a field. */
i -= 1;
extra = (val - TYPE_FIELD_BITPOS (domain, i));
if (extra & 0x7)
bits = 1;
else
extra >>= 3;
break;
}
}
if (i < len)
{
char *name;
fprintf_filtered (stream, prefix);
name = type_name_no_tag (domain);
if (name)
fputs_filtered (name, stream);
else
c_type_print_base (domain, stream, 0, 0);
fprintf_filtered (stream, "::");
fputs_filtered (TYPE_FIELD_NAME (domain, i), stream);
if (extra)
fprintf_filtered (stream, " + %d bytes", extra);
if (bits)
fprintf_filtered (stream, " (offset in bits)");
}
else
fprintf_filtered (stream, "%d", val >> 3);
}
void
_initialize_cp_valprint ()
{
add_show_from_set
(add_set_cmd ("static-members", class_support, var_boolean,
(char *)&static_field_print,
"Set printing of C++ static members.",
&setprintlist),
&showprintlist);
/* Turn on printing of static fields. */
static_field_print = 1;
add_show_from_set
(add_set_cmd ("vtbl", class_support, var_boolean, (char *)&vtblprint,
"Set printing of C++ virtual function tables.",
&setprintlist),
&showprintlist);
add_show_from_set
(add_set_cmd ("object", class_support, var_boolean, (char *)&objectprint,
"Set printing of object's derived type based on vtable info.",
&setprintlist),
&showprintlist);
/* Give people the defaults which they are used to. */
objectprint = 0;
vtblprint = 0;
obstack_begin (&dont_print_vb_obstack, 32 * sizeof (struct type *));
obstack_specify_allocation (&dont_print_statmem_obstack,
32 * sizeof (CORE_ADDR), sizeof (CORE_ADDR),
xmalloc, free);
}