old-cross-binutils/gdb/cp-valprint.c
Thomas Lord 199b2450f6 Change the stream argument to _filtered to GDB_FILE *.
Change all references to stdout/stderr to gdb_stdout/gdb_stderr.

Replace all calls to stdio output functions with calls to
corresponding _unfiltered functions (`fprintf_unfiltered')

Replaced calls to fopen for output to gdb_fopen.

Added sufficient goo to utils.c and defs.h to make the above work.

The net effect is that stdio output functions are only directly used
in utils.c.  Elsewhere, the _unfiltered and _filtered functions and
GDB_FILE type are used.

In the near future, GDB_FILE will stop being equivalant to FILE.

The semantics of some commands has changed in a very subtle way:
called in the right context, they may cause new occurences of
prompt_for_continue() behavior.  The testsuite doesn't notice anything
like this, though.

Please respect this change by not reintroducing stdio output
dependencies in the main body of gdb code.  All output from commands
should go to a GDB_FILE.

Target-specific code can still use stdio directly to communicate with
targets.
1993-11-01 22:25:23 +00:00

484 lines
13 KiB
C

/* Support for printing C++ values for GDB, the GNU debugger.
Copyright 1986, 1988, 1989, 1991 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., 675 Mass Ave, Cambridge, MA 02139, 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"
int vtblprint; /* Controls printing of vtbl's */
int objectprint; /* Controls looking up an object's derived type
using what we find in its vtables. */
struct obstack dont_print_obstack;
static void
cplus_print_value PARAMS ((struct type *, char *, GDB_FILE *, int, int,
enum val_prettyprint, struct type **));
/* BEGIN-FIXME: Hooks into typeprint.c, find a better home for prototypes. */
extern void
c_type_print_base PARAMS ((struct type *, GDB_FILE *, int, int));
extern void
c_type_print_varspec_prefix PARAMS ((struct type *, GDB_FILE *, int, int));
extern void
cp_type_print_method_args PARAMS ((struct type **, char *, char *, int,
GDB_FILE *));
extern struct obstack dont_print_obstack;
/* END-FIXME */
/* BEGIN-FIXME: Hooks into c-valprint.c */
extern int
c_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int, int,
enum val_prettyprint));
/* END-FIXME */
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;
check_stub_type (TYPE_TARGET_TYPE (type));
domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (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] == '_'
&& TYPE_FN_FIELD_PHYSNAME (f, j)[1] == CPLUS_MARKER)
{
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);
}
}
/* 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);
/* 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. */
static const char vtbl_ptr_name[] =
{ '_','_','v','t','b','l','_','p','t','r','_','t','y','p','e', 0 };
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);
else
return 0;
if (TYPE_CODE (type) == TYPE_CODE_ARRAY
&& TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_STRUCT)
/* Virtual functions tables are full of pointers to virtual functions. */
return cp_is_vtbl_ptr_type (TYPE_TARGET_TYPE (type));
return 0;
}
/* Mutually recursive subroutines of cplus_print_value and c_val_print to
print out a structure's fields: cp_print_value_fields and cplus_print_value.
TYPE, VALADDR, STREAM, RECURSE, and PRETTY have the
same meanings as in cplus_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, stream, format, recurse, pretty,
dont_print)
struct type *type;
char *valaddr;
GDB_FILE *stream;
int format;
int recurse;
enum val_prettyprint pretty;
struct type **dont_print;
{
int i, len, n_baseclasses;
check_stub_type (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)
cplus_print_value (type, valaddr, stream, format, recurse+1, pretty,
dont_print);
if (!len && n_baseclasses == 1)
fprintf_filtered (stream, "<No data fields>");
else
{
extern int inspect_it;
int fields_seen = 0;
for (i = n_baseclasses; i < len; i++)
{
/* Check if static field */
if (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);
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
{
fprintf_symbol_filtered (stream, TYPE_FIELD_NAME (type, i),
language_cplus,
DMGL_PARAMS | DMGL_ANSI);
fputs_filtered (" = ", stream);
}
if (TYPE_FIELD_PACKED (type, i))
{
value v;
/* Bitfields require special handling, especially due to byte
order problems. */
v = value_from_longest (TYPE_FIELD_TYPE (type, i),
unpack_field_as_long (type, valaddr, i));
c_val_print (TYPE_FIELD_TYPE (type, i), VALUE_CONTENTS (v), 0,
stream, format, 0, recurse + 1, pretty);
}
else
{
c_val_print (TYPE_FIELD_TYPE (type, i),
valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
0, stream, format, 0, recurse + 1, pretty);
}
}
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
cplus_print_value (type, valaddr, stream, format, recurse, pretty, dont_print)
struct type *type;
char *valaddr;
GDB_FILE *stream;
int format;
int recurse;
enum val_prettyprint pretty;
struct type **dont_print;
{
struct obstack tmp_obstack;
struct type **last_dont_print
= (struct type **)obstack_next_free (&dont_print_obstack);
int i, n_baseclasses = TYPE_N_BASECLASSES (type);
if (dont_print == 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_obstack;
/* Bump up the high-water mark. Now alpha is omega. */
obstack_finish (&dont_print_obstack);
}
for (i = 0; i < n_baseclasses; i++)
{
char *baddr;
int err;
char *basename = TYPE_NAME (TYPE_BASECLASS (type, i));
if (BASETYPE_VIA_VIRTUAL (type, i))
{
struct type **first_dont_print
= (struct type **)obstack_base (&dont_print_obstack);
int j = (struct type **)obstack_next_free (&dont_print_obstack)
- first_dont_print;
while (--j >= 0)
if (TYPE_BASECLASS (type, i) == first_dont_print[j])
goto flush_it;
obstack_ptr_grow (&dont_print_obstack, TYPE_BASECLASS (type, i));
}
/* Fix to use baseclass_offset instead. FIXME */
baddr = baseclass_addr (type, i, valaddr, 0, &err);
if (err == 0 && baddr == 0)
error ("could not find virtual baseclass %s\n",
basename ? basename : "");
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);
if (err != 0)
fprintf_filtered (stream,
"<invalid address 0x%lx>", (unsigned long) baddr);
else
cp_print_value_fields (TYPE_BASECLASS (type, i), baddr, stream, format,
recurse, pretty,
(struct type **) obstack_base (&dont_print_obstack));
fputs_filtered (", ", stream);
flush_it:
;
}
if (dont_print == 0)
{
/* Free the space used to deal with the printing
of this type from top level. */
obstack_free (&dont_print_obstack, last_dont_print);
/* Reset watermark so that we can continue protecting
ourselves from whatever we were protecting ourselves. */
dont_print_obstack = tmp_obstack;
}
}
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 ("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_obstack, 32 * sizeof (struct type *));
}