1431 lines
37 KiB
C
1431 lines
37 KiB
C
|
/*-
|
|||
|
* This code is derived from software copyrighted by the Free Software
|
|||
|
* Foundation.
|
|||
|
*
|
|||
|
* Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
|
|||
|
* Modified 1990 by Van Jacobson at Lawrence Berkeley Laboratory.
|
|||
|
*/
|
|||
|
|
|||
|
#ifndef lint
|
|||
|
static char sccsid[] = "@(#)valprint.c 6.5 (Berkeley) 5/8/91";
|
|||
|
#endif /* not lint */
|
|||
|
|
|||
|
/* Print values for GNU debugger gdb.
|
|||
|
Copyright (C) 1986, 1988, 1989 Free Software Foundation, Inc.
|
|||
|
|
|||
|
This file is part of GDB.
|
|||
|
|
|||
|
GDB 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 1, or (at your option)
|
|||
|
any later version.
|
|||
|
|
|||
|
GDB 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 GDB; see the file COPYING. If not, write to
|
|||
|
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
|
|
|||
|
#include <stdio.h>
|
|||
|
#include "defs.h"
|
|||
|
#include "param.h"
|
|||
|
#include "symtab.h"
|
|||
|
#include "value.h"
|
|||
|
|
|||
|
/* GNU software is only expected to run on systems with 32-bit integers. */
|
|||
|
#define UINT_MAX 0xffffffff
|
|||
|
|
|||
|
/* Maximum number of chars to print for a string pointer value
|
|||
|
or vector contents, or UINT_MAX for no limit. */
|
|||
|
|
|||
|
static unsigned int print_max;
|
|||
|
|
|||
|
static void type_print_varspec_suffix ();
|
|||
|
static void type_print_varspec_prefix ();
|
|||
|
static void type_print_base ();
|
|||
|
static void type_print_method_args ();
|
|||
|
|
|||
|
|
|||
|
char **unsigned_type_table;
|
|||
|
char **signed_type_table;
|
|||
|
char **float_type_table;
|
|||
|
|
|||
|
|
|||
|
/* Print repeat counts if there are more than this
|
|||
|
many repetitions of an element in an array. */
|
|||
|
#define REPEAT_COUNT_THRESHOLD 10
|
|||
|
|
|||
|
/* Print the character string STRING, printing at most LENGTH characters.
|
|||
|
Printing stops early if the number hits print_max; repeat counts
|
|||
|
are printed as appropriate. Print ellipses at the end if we
|
|||
|
had to stop before printing LENGTH characters, or if FORCE_ELLIPSES. */
|
|||
|
|
|||
|
void
|
|||
|
print_string (stream, string, length, force_ellipses)
|
|||
|
FILE *stream;
|
|||
|
char *string;
|
|||
|
unsigned int length;
|
|||
|
int force_ellipses;
|
|||
|
{
|
|||
|
register unsigned int i;
|
|||
|
unsigned int things_printed = 0;
|
|||
|
int in_quotes = 0;
|
|||
|
int need_comma = 0;
|
|||
|
|
|||
|
if (length == 0)
|
|||
|
{
|
|||
|
fputs_filtered ("\"\"", stdout);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
for (i = 0; i < length && things_printed < print_max; ++i)
|
|||
|
{
|
|||
|
/* Position of the character we are examining
|
|||
|
to see whether it is repeated. */
|
|||
|
unsigned int rep1;
|
|||
|
/* Number of repititions we have detected so far. */
|
|||
|
unsigned int reps;
|
|||
|
|
|||
|
QUIT;
|
|||
|
|
|||
|
if (need_comma)
|
|||
|
{
|
|||
|
fputs_filtered (", ", stream);
|
|||
|
need_comma = 0;
|
|||
|
}
|
|||
|
|
|||
|
rep1 = i + 1;
|
|||
|
reps = 1;
|
|||
|
while (rep1 < length && string[rep1] == string[i])
|
|||
|
{
|
|||
|
++rep1;
|
|||
|
++reps;
|
|||
|
}
|
|||
|
|
|||
|
if (reps > REPEAT_COUNT_THRESHOLD)
|
|||
|
{
|
|||
|
if (in_quotes)
|
|||
|
{
|
|||
|
fputs_filtered ("\", ", stream);
|
|||
|
in_quotes = 0;
|
|||
|
}
|
|||
|
fputs_filtered ("'", stream);
|
|||
|
printchar (string[i], stream, '\'');
|
|||
|
fprintf_filtered (stream, "' <repeats %u times>", reps);
|
|||
|
i = rep1 - 1;
|
|||
|
things_printed += REPEAT_COUNT_THRESHOLD;
|
|||
|
need_comma = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!in_quotes)
|
|||
|
{
|
|||
|
fputs_filtered ("\"", stream);
|
|||
|
in_quotes = 1;
|
|||
|
}
|
|||
|
printchar (string[i], stream, '"');
|
|||
|
++things_printed;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Terminate the quotes if necessary. */
|
|||
|
if (in_quotes)
|
|||
|
fputs_filtered ("\"", stream);
|
|||
|
|
|||
|
if (force_ellipses || i < length)
|
|||
|
fputs_filtered ("...", stream);
|
|||
|
}
|
|||
|
|
|||
|
/* Print the value VAL in C-ish syntax on stream STREAM.
|
|||
|
FORMAT is a format-letter, or 0 for print in natural format of data type.
|
|||
|
If the object printed is a string pointer, returns
|
|||
|
the number of string bytes printed. */
|
|||
|
|
|||
|
int
|
|||
|
value_print (val, stream, format, pretty)
|
|||
|
value val;
|
|||
|
FILE *stream;
|
|||
|
char format;
|
|||
|
enum val_prettyprint pretty;
|
|||
|
{
|
|||
|
register unsigned int i, n, typelen;
|
|||
|
|
|||
|
/* A "repeated" value really contains several values in a row.
|
|||
|
They are made by the @ operator.
|
|||
|
Print such values as if they were arrays. */
|
|||
|
|
|||
|
if (VALUE_REPEATED (val))
|
|||
|
{
|
|||
|
n = VALUE_REPETITIONS (val);
|
|||
|
typelen = TYPE_LENGTH (VALUE_TYPE (val));
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
/* Print arrays of characters using string syntax. */
|
|||
|
if (typelen == 1 && TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT
|
|||
|
&& format == 0)
|
|||
|
print_string (stream, VALUE_CONTENTS (val), n, 0);
|
|||
|
else
|
|||
|
{
|
|||
|
unsigned int things_printed = 0;
|
|||
|
|
|||
|
for (i = 0; i < n && things_printed < print_max; i++)
|
|||
|
{
|
|||
|
/* Position of the array element we are examining to see
|
|||
|
whether it is repeated. */
|
|||
|
unsigned int rep1;
|
|||
|
/* Number of repititions we have detected so far. */
|
|||
|
unsigned int reps;
|
|||
|
|
|||
|
if (i != 0)
|
|||
|
fprintf_filtered (stream, ", ");
|
|||
|
|
|||
|
rep1 = i + 1;
|
|||
|
reps = 1;
|
|||
|
while (rep1 < n
|
|||
|
&& !bcmp (VALUE_CONTENTS (val) + typelen * i,
|
|||
|
VALUE_CONTENTS (val) + typelen * rep1, typelen))
|
|||
|
{
|
|||
|
++reps;
|
|||
|
++rep1;
|
|||
|
}
|
|||
|
|
|||
|
if (reps > REPEAT_COUNT_THRESHOLD)
|
|||
|
{
|
|||
|
val_print (VALUE_TYPE (val),
|
|||
|
VALUE_CONTENTS (val) + typelen * i,
|
|||
|
VALUE_ADDRESS (val) + typelen * i,
|
|||
|
stream, format, 1, 0, pretty);
|
|||
|
fprintf (stream, " <repeats %u times>", reps);
|
|||
|
i = rep1 - 1;
|
|||
|
things_printed += REPEAT_COUNT_THRESHOLD;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
val_print (VALUE_TYPE (val),
|
|||
|
VALUE_CONTENTS (val) + typelen * i,
|
|||
|
VALUE_ADDRESS (val) + typelen * i,
|
|||
|
stream, format, 1, 0, pretty);
|
|||
|
things_printed++;
|
|||
|
}
|
|||
|
}
|
|||
|
if (i < n)
|
|||
|
fprintf_filtered (stream, "...");
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "}");
|
|||
|
return n * typelen;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* If it is a pointer, indicate what it points to.
|
|||
|
|
|||
|
Print type also if it is a reference.
|
|||
|
|
|||
|
C++: if it is a member pointer, we will take care
|
|||
|
of that when we print it. */
|
|||
|
if (TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_PTR
|
|||
|
|| TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_REF)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
type_print (VALUE_TYPE (val), "", stream, -1);
|
|||
|
fprintf_filtered (stream, ") ");
|
|||
|
|
|||
|
/* If this is a function pointer, try to print what
|
|||
|
function it is pointing to by name. */
|
|||
|
if (TYPE_CODE (TYPE_TARGET_TYPE (VALUE_TYPE (val)))
|
|||
|
== TYPE_CODE_FUNC)
|
|||
|
{
|
|||
|
print_address (((int *) VALUE_CONTENTS (val))[0], stream);
|
|||
|
/* Return value is irrelevant except for string pointers. */
|
|||
|
return 0;
|
|||
|
}
|
|||
|
}
|
|||
|
return val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
|
|||
|
VALUE_ADDRESS (val), stream, format, 1, 0, pretty);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static int prettyprint; /* Controls prettyprinting of structures. */
|
|||
|
int unionprint; /* Controls printing of nested unions. */
|
|||
|
static void scalar_print_hack();
|
|||
|
void (*default_scalar_print)() = scalar_print_hack;
|
|||
|
|
|||
|
/* Print data of type TYPE located at VALADDR (within GDB),
|
|||
|
which came from the inferior at address ADDRESS,
|
|||
|
onto stdio stream STREAM according to FORMAT
|
|||
|
(a letter or 0 for natural format).
|
|||
|
|
|||
|
If the data are a string pointer, returns the number of
|
|||
|
sting characters printed.
|
|||
|
|
|||
|
if DEREF_REF is nonzero, then dereference references,
|
|||
|
otherwise just print them like pointers.
|
|||
|
|
|||
|
The PRETTY parameter controls prettyprinting. */
|
|||
|
|
|||
|
int
|
|||
|
val_print (type, valaddr, address, stream, format,
|
|||
|
deref_ref, recurse, pretty)
|
|||
|
struct type *type;
|
|||
|
char *valaddr;
|
|||
|
CORE_ADDR address;
|
|||
|
FILE *stream;
|
|||
|
char format;
|
|||
|
int deref_ref;
|
|||
|
int recurse;
|
|||
|
enum val_prettyprint pretty;
|
|||
|
{
|
|||
|
register unsigned int i;
|
|||
|
int len, n_baseclasses;
|
|||
|
struct type *elttype;
|
|||
|
int eltlen;
|
|||
|
LONGEST val;
|
|||
|
unsigned char c;
|
|||
|
|
|||
|
if (pretty == Val_pretty_default)
|
|||
|
{
|
|||
|
pretty = prettyprint ? Val_prettyprint : Val_no_prettyprint;
|
|||
|
}
|
|||
|
|
|||
|
QUIT;
|
|||
|
|
|||
|
if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "<Type not defined in this context>");
|
|||
|
fflush (stream);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
switch (TYPE_CODE (type))
|
|||
|
{
|
|||
|
case TYPE_CODE_ARRAY:
|
|||
|
if (TYPE_LENGTH (type) >= 0
|
|||
|
&& TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
|
|||
|
{
|
|||
|
elttype = TYPE_TARGET_TYPE (type);
|
|||
|
eltlen = TYPE_LENGTH (elttype);
|
|||
|
len = TYPE_LENGTH (type) / eltlen;
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
/* For an array of chars, print with string syntax. */
|
|||
|
if (eltlen == 1 && TYPE_CODE (elttype) == TYPE_CODE_INT
|
|||
|
&& format == 0)
|
|||
|
print_string (stream, valaddr, len, 0);
|
|||
|
else
|
|||
|
{
|
|||
|
unsigned int things_printed = 0;
|
|||
|
|
|||
|
for (i = 0; i < len && things_printed < print_max; i++)
|
|||
|
{
|
|||
|
/* Position of the array element we are examining to see
|
|||
|
whether it is repeated. */
|
|||
|
unsigned int rep1;
|
|||
|
/* Number of repititions we have detected so far. */
|
|||
|
unsigned int reps;
|
|||
|
|
|||
|
if (i > 0)
|
|||
|
fprintf_filtered (stream, ", ");
|
|||
|
|
|||
|
rep1 = i + 1;
|
|||
|
reps = 1;
|
|||
|
while (rep1 < len
|
|||
|
&& !bcmp (valaddr + i * eltlen,
|
|||
|
valaddr + rep1 * eltlen, eltlen))
|
|||
|
{
|
|||
|
++reps;
|
|||
|
++rep1;
|
|||
|
}
|
|||
|
|
|||
|
if (reps > REPEAT_COUNT_THRESHOLD)
|
|||
|
{
|
|||
|
val_print (elttype, valaddr + i * eltlen,
|
|||
|
0, stream, format, deref_ref,
|
|||
|
recurse + 1, pretty);
|
|||
|
fprintf_filtered (stream, " <repeats %u times>", reps);
|
|||
|
i = rep1 - 1;
|
|||
|
things_printed += REPEAT_COUNT_THRESHOLD;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
val_print (elttype, valaddr + i * eltlen,
|
|||
|
0, stream, format, deref_ref,
|
|||
|
recurse + 1, pretty);
|
|||
|
things_printed++;
|
|||
|
}
|
|||
|
}
|
|||
|
if (i < len)
|
|||
|
fprintf_filtered (stream, "...");
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "}");
|
|||
|
break;
|
|||
|
}
|
|||
|
/* Array of unspecified length: treat like pointer to first elt. */
|
|||
|
valaddr = (char *) &address;
|
|||
|
|
|||
|
case TYPE_CODE_PTR:
|
|||
|
if (format)
|
|||
|
{
|
|||
|
print_scalar_formatted (valaddr, type, format, 0, stream);
|
|||
|
break;
|
|||
|
}
|
|||
|
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_METHOD)
|
|||
|
{
|
|||
|
struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
|
|||
|
struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
|
|||
|
struct fn_field *f;
|
|||
|
int j, len2;
|
|||
|
char *kind = "";
|
|||
|
|
|||
|
val = unpack_long (builtin_type_int, valaddr);
|
|||
|
if (val < 128)
|
|||
|
{
|
|||
|
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) == val)
|
|||
|
{
|
|||
|
kind = "virtual";
|
|||
|
goto common;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
struct symbol *sym = find_pc_function ((CORE_ADDR) val);
|
|||
|
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 (!strcmp (SYMBOL_NAME (sym), TYPE_FN_FIELD_PHYSNAME (f, j)))
|
|||
|
goto common;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
common:
|
|||
|
if (i < len)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "&");
|
|||
|
type_print_varspec_prefix (TYPE_FN_FIELD_TYPE (f, j), stream, 0, 0);
|
|||
|
fprintf (stream, kind);
|
|||
|
if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
|
|||
|
&& TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
|
|||
|
type_print_method_args
|
|||
|
(TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
|
|||
|
TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
|
|||
|
else
|
|||
|
type_print_method_args
|
|||
|
(TYPE_FN_FIELD_ARGS (f, j), "",
|
|||
|
TYPE_FN_FIELDLIST_NAME (domain, i), 0, stream);
|
|||
|
break;
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
type_print (type, "", stream, -1);
|
|||
|
fprintf_filtered (stream, ") %d", (int) val >> 3);
|
|||
|
}
|
|||
|
else if (TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_MEMBER)
|
|||
|
{
|
|||
|
struct type *domain = TYPE_DOMAIN_TYPE (TYPE_TARGET_TYPE (type));
|
|||
|
struct type *target = TYPE_TARGET_TYPE (TYPE_TARGET_TYPE (type));
|
|||
|
char *kind = "";
|
|||
|
|
|||
|
/* 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;
|
|||
|
len = TYPE_NFIELDS (domain);
|
|||
|
/* @@ Make VAL into bit offset */
|
|||
|
val = unpack_long (builtin_type_int, valaddr) << 3;
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
{
|
|||
|
int bitpos = TYPE_FIELD_BITPOS (domain, i);
|
|||
|
QUIT;
|
|||
|
if (val == bitpos)
|
|||
|
break;
|
|||
|
if (val < bitpos && i > 0)
|
|||
|
{
|
|||
|
int ptrsize = (TYPE_LENGTH (builtin_type_char) * TYPE_LENGTH (target));
|
|||
|
/* Somehow pointing into a field. */
|
|||
|
i -= 1;
|
|||
|
extra = (val - TYPE_FIELD_BITPOS (domain, i));
|
|||
|
if (extra & 0x3)
|
|||
|
bits = 1;
|
|||
|
else
|
|||
|
extra >>= 3;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (i < len)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "&");
|
|||
|
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)");
|
|||
|
break;
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "%d", val >> 3);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "0x%x", * (int *) valaddr);
|
|||
|
/* For a pointer to char or unsigned char,
|
|||
|
also print the string pointed to, unless pointer is null. */
|
|||
|
|
|||
|
/* For an array of chars, print with string syntax. */
|
|||
|
elttype = TYPE_TARGET_TYPE (type);
|
|||
|
i = 0; /* Number of characters printed. */
|
|||
|
if (TYPE_LENGTH (elttype) == 1
|
|||
|
&& TYPE_CODE (elttype) == TYPE_CODE_INT
|
|||
|
&& format == 0
|
|||
|
&& unpack_long (type, valaddr) != 0
|
|||
|
/* If print_max is UINT_MAX, the alloca below will fail.
|
|||
|
In that case don't try to print the string. */
|
|||
|
&& print_max < UINT_MAX)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, " ");
|
|||
|
|
|||
|
/* Get first character. */
|
|||
|
if (read_memory ( (CORE_ADDR) unpack_long (type, valaddr),
|
|||
|
&c, 1))
|
|||
|
{
|
|||
|
/* First address out of bounds. */
|
|||
|
fprintf_filtered (stream, "<Address 0x%x out of bounds>",
|
|||
|
(* (int *) valaddr));
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/* A real string. */
|
|||
|
int out_of_bounds = 0;
|
|||
|
char *string = (char *) alloca (print_max);
|
|||
|
|
|||
|
/* If the loop ends by us hitting print_max characters,
|
|||
|
we need to have elipses at the end. */
|
|||
|
int force_ellipses = 1;
|
|||
|
|
|||
|
/* This loop only fetches print_max characters, even
|
|||
|
though print_string might want to print more
|
|||
|
(with repeated characters). This is so that
|
|||
|
we don't spend forever fetching if we print
|
|||
|
a long string consisting of the same character
|
|||
|
repeated. */
|
|||
|
while (i < print_max)
|
|||
|
{
|
|||
|
QUIT;
|
|||
|
if (read_memory ((CORE_ADDR) unpack_long (type, valaddr)
|
|||
|
+ i, &c, 1))
|
|||
|
{
|
|||
|
out_of_bounds = 1;
|
|||
|
force_ellipses = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (c == '\0')
|
|||
|
{
|
|||
|
force_ellipses = 0;
|
|||
|
break;
|
|||
|
}
|
|||
|
else
|
|||
|
string[i++] = c;
|
|||
|
}
|
|||
|
|
|||
|
if (i != 0)
|
|||
|
print_string (stream, string, i, force_ellipses);
|
|||
|
if (out_of_bounds)
|
|||
|
fprintf_filtered (stream,
|
|||
|
" <Address 0x%x out of bounds>",
|
|||
|
(*(int *) valaddr) + i);
|
|||
|
}
|
|||
|
|
|||
|
fflush (stream);
|
|||
|
}
|
|||
|
/* Return number of characters printed, plus one for the
|
|||
|
terminating null if we have "reached the end". */
|
|||
|
return i + (print_max && i != print_max);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_MEMBER:
|
|||
|
error ("not implemented: member type in val_print");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_REF:
|
|||
|
fprintf_filtered (stream, "(0x%x &) = ", * (int *) valaddr);
|
|||
|
/* De-reference the reference. */
|
|||
|
if (deref_ref)
|
|||
|
{
|
|||
|
if (TYPE_CODE (TYPE_TARGET_TYPE (type)) != TYPE_CODE_UNDEF)
|
|||
|
{
|
|||
|
value val = value_at (TYPE_TARGET_TYPE (type), * (int *) valaddr);
|
|||
|
val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
|
|||
|
VALUE_ADDRESS (val), stream, format,
|
|||
|
deref_ref, recurse + 1, pretty);
|
|||
|
}
|
|||
|
else
|
|||
|
fprintf_filtered (stream, "???");
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_UNION:
|
|||
|
if (recurse && !unionprint)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "{...}");
|
|||
|
break;
|
|||
|
}
|
|||
|
/* Fall through. */
|
|||
|
case TYPE_CODE_STRUCT:
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
len = TYPE_NFIELDS (type);
|
|||
|
n_baseclasses = TYPE_N_BASECLASSES (type);
|
|||
|
for (i = 1; i <= n_baseclasses; i++)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "\n");
|
|||
|
if (pretty)
|
|||
|
print_spaces_filtered (2 + 2 * recurse, stream);
|
|||
|
fputs_filtered ("<", stream);
|
|||
|
fputs_filtered (TYPE_NAME (TYPE_BASECLASS (type, i)), stream);
|
|||
|
fputs_filtered ("> = ", stream);
|
|||
|
val_print (TYPE_FIELD_TYPE (type, 0),
|
|||
|
valaddr + TYPE_FIELD_BITPOS (type, i-1) / 8,
|
|||
|
0, stream, 0, 0, recurse + 1, pretty);
|
|||
|
}
|
|||
|
if (i > 1) {
|
|||
|
fprintf_filtered (stream, "\n");
|
|||
|
print_spaces_filtered (2 + 2 * recurse, stream);
|
|||
|
fputs_filtered ("members of ", stream);
|
|||
|
fputs_filtered (TYPE_NAME (type), stream);
|
|||
|
fputs_filtered (": ", stream);
|
|||
|
}
|
|||
|
if (!len && i == 1)
|
|||
|
fprintf_filtered (stream, "<No data fields>");
|
|||
|
else
|
|||
|
{
|
|||
|
for (i -= 1; i < len; i++)
|
|||
|
{
|
|||
|
if (i > n_baseclasses) fprintf_filtered (stream, ", ");
|
|||
|
if (pretty)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "\n");
|
|||
|
print_spaces_filtered (2 + 2 * recurse, stream);
|
|||
|
}
|
|||
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|||
|
fputs_filtered (" = ", stream);
|
|||
|
/* check if static field */
|
|||
|
if (TYPE_FIELD_STATIC (type, i))
|
|||
|
{
|
|||
|
value v;
|
|||
|
|
|||
|
v = value_static_field (type, TYPE_FIELD_NAME (type, i), i);
|
|||
|
val_print (TYPE_FIELD_TYPE (type, i),
|
|||
|
VALUE_CONTENTS (v), 0, stream, format,
|
|||
|
deref_ref, recurse + 1, pretty);
|
|||
|
}
|
|||
|
else if (TYPE_FIELD_PACKED (type, i))
|
|||
|
{
|
|||
|
char *valp = (char *) & val;
|
|||
|
union {int i; char c;} test;
|
|||
|
test.i = 1;
|
|||
|
if (test.c != 1)
|
|||
|
valp += sizeof val - TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
|
|||
|
val = unpack_field_as_long (type, valaddr, i);
|
|||
|
val_print (TYPE_FIELD_TYPE (type, i), valp, 0,
|
|||
|
stream, format, deref_ref, recurse + 1, pretty);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
val_print (TYPE_FIELD_TYPE (type, i),
|
|||
|
valaddr + TYPE_FIELD_BITPOS (type, i) / 8,
|
|||
|
0, stream, format, deref_ref,
|
|||
|
recurse + 1, pretty);
|
|||
|
}
|
|||
|
}
|
|||
|
if (pretty)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "\n");
|
|||
|
print_spaces_filtered (2 * recurse, stream);
|
|||
|
}
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "}");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_ENUM:
|
|||
|
if (format)
|
|||
|
{
|
|||
|
print_scalar_formatted (valaddr, type, format, 0, stream);
|
|||
|
break;
|
|||
|
}
|
|||
|
len = TYPE_NFIELDS (type);
|
|||
|
val = unpack_long (builtin_type_int, valaddr);
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
{
|
|||
|
QUIT;
|
|||
|
if (val == TYPE_FIELD_BITPOS (type, i))
|
|||
|
break;
|
|||
|
}
|
|||
|
if (i < len)
|
|||
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|||
|
else
|
|||
|
fprintf_filtered (stream, "%d", (int) val);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_FUNC:
|
|||
|
if (format)
|
|||
|
{
|
|||
|
print_scalar_formatted (valaddr, type, format, 0, stream);
|
|||
|
break;
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
type_print (type, "", stream, -1);
|
|||
|
fprintf_filtered (stream, "} ");
|
|||
|
fprintf_filtered (stream, "0x%x", address);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_INT:
|
|||
|
if (format)
|
|||
|
print_scalar_formatted (valaddr, type, format, 0, stream);
|
|||
|
else
|
|||
|
{
|
|||
|
(*default_scalar_print)(stream, type, unpack_long(type, valaddr));
|
|||
|
#ifdef notdef
|
|||
|
if (TYPE_LENGTH (type) == 1)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, " '");
|
|||
|
printchar ((unsigned char) unpack_long (type, valaddr),
|
|||
|
stream, '\'');
|
|||
|
fprintf_filtered (stream, "'");
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_FLT:
|
|||
|
if (format)
|
|||
|
print_scalar_formatted (valaddr, type, format, 0, stream);
|
|||
|
else
|
|||
|
print_floating (valaddr, type, stream);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_VOID:
|
|||
|
fprintf_filtered (stream, "void");
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error ("Invalid type code in symbol table.");
|
|||
|
}
|
|||
|
fflush (stream);
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/* Print a description of a type TYPE
|
|||
|
in the form of a declaration of a variable named VARSTRING.
|
|||
|
Output goes to STREAM (via stdio).
|
|||
|
If SHOW is positive, we show the contents of the outermost level
|
|||
|
of structure even if there is a type name that could be used instead.
|
|||
|
If SHOW is negative, we never show the details of elements' types. */
|
|||
|
|
|||
|
void
|
|||
|
type_print (type, varstring, stream, show)
|
|||
|
struct type *type;
|
|||
|
char *varstring;
|
|||
|
FILE *stream;
|
|||
|
int show;
|
|||
|
{
|
|||
|
type_print_1 (type, varstring, stream, show, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* LEVEL is the depth to indent lines by. */
|
|||
|
|
|||
|
void
|
|||
|
type_print_1 (type, varstring, stream, show, level)
|
|||
|
struct type *type;
|
|||
|
char *varstring;
|
|||
|
FILE *stream;
|
|||
|
int show;
|
|||
|
int level;
|
|||
|
{
|
|||
|
register enum type_code code;
|
|||
|
type_print_base (type, stream, show, level);
|
|||
|
code = TYPE_CODE (type);
|
|||
|
if ((varstring && *varstring)
|
|||
|
||
|
|||
|
/* Need a space if going to print stars or brackets;
|
|||
|
but not if we will print just a type name. */
|
|||
|
((show > 0 || TYPE_NAME (type) == 0)
|
|||
|
&&
|
|||
|
(code == TYPE_CODE_PTR || code == TYPE_CODE_FUNC
|
|||
|
|| code == TYPE_CODE_METHOD
|
|||
|
|| code == TYPE_CODE_ARRAY
|
|||
|
|| code == TYPE_CODE_MEMBER
|
|||
|
|| code == TYPE_CODE_REF)))
|
|||
|
fprintf_filtered (stream, " ");
|
|||
|
type_print_varspec_prefix (type, stream, show, 0);
|
|||
|
fputs_filtered (varstring, stream);
|
|||
|
type_print_varspec_suffix (type, stream, show, 0);
|
|||
|
}
|
|||
|
|
|||
|
/* Print the method arguments ARGS to the file STREAM. */
|
|||
|
static void
|
|||
|
type_print_method_args (args, prefix, varstring, staticp, stream)
|
|||
|
struct type **args;
|
|||
|
char *prefix, *varstring;
|
|||
|
int staticp;
|
|||
|
FILE *stream;
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
fputs_filtered (" ", stream);
|
|||
|
fputs_filtered (prefix, stream);
|
|||
|
fputs_filtered (varstring, stream);
|
|||
|
fputs_filtered (" (", stream);
|
|||
|
if (args && args[!staticp] && args[!staticp]->code != TYPE_CODE_VOID)
|
|||
|
{
|
|||
|
i = !staticp; /* skip the class variable */
|
|||
|
while (1)
|
|||
|
{
|
|||
|
type_print (args[i++], "", stream, 0);
|
|||
|
if (!args[i])
|
|||
|
{
|
|||
|
fprintf_filtered (stream, " ...");
|
|||
|
break;
|
|||
|
}
|
|||
|
else if (args[i]->code != TYPE_CODE_VOID)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, ", ");
|
|||
|
}
|
|||
|
else break;
|
|||
|
}
|
|||
|
}
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
}
|
|||
|
|
|||
|
/* If TYPE is a derived type, then print out derivation
|
|||
|
information. Print out all layers of the type heirarchy
|
|||
|
until we encounter one with multiple inheritance.
|
|||
|
At that point, print out that ply, and return. */
|
|||
|
static void
|
|||
|
type_print_derivation_info (stream, type)
|
|||
|
FILE *stream;
|
|||
|
struct type *type;
|
|||
|
{
|
|||
|
char *name;
|
|||
|
int i, n_baseclasses = TYPE_N_BASECLASSES (type);
|
|||
|
struct type *basetype = 0;
|
|||
|
|
|||
|
while (type && n_baseclasses == 1)
|
|||
|
{
|
|||
|
basetype = TYPE_BASECLASS (type, 1);
|
|||
|
if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
|
|||
|
{
|
|||
|
while (*name != ' ') name++;
|
|||
|
fprintf_filtered (stream, ": %s%s ",
|
|||
|
TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
|
|||
|
TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "");
|
|||
|
fputs_filtered (name + 1, stream);
|
|||
|
fputs_filtered (" ", stream);
|
|||
|
}
|
|||
|
n_baseclasses = TYPE_N_BASECLASSES (basetype);
|
|||
|
type = basetype;
|
|||
|
}
|
|||
|
|
|||
|
if (type)
|
|||
|
{
|
|||
|
if (n_baseclasses != 0)
|
|||
|
fprintf_filtered (stream, ": ");
|
|||
|
for (i = 1; i <= n_baseclasses; i++)
|
|||
|
{
|
|||
|
basetype = TYPE_BASECLASS (type, i);
|
|||
|
if (TYPE_NAME (basetype) && (name = TYPE_NAME (basetype)))
|
|||
|
{
|
|||
|
while (*name != ' ') name++;
|
|||
|
fprintf_filtered (stream, "%s%s ",
|
|||
|
TYPE_VIA_PUBLIC (basetype) ? "public" : "private",
|
|||
|
TYPE_VIA_VIRTUAL (basetype) ? " virtual" : "");
|
|||
|
fputs_filtered (name + 1, stream);
|
|||
|
}
|
|||
|
if (i < n_baseclasses)
|
|||
|
fprintf_filtered (stream, ", ");
|
|||
|
}
|
|||
|
fprintf_filtered (stream, " ");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Print any asterisks or open-parentheses needed before the
|
|||
|
variable name (to describe its type).
|
|||
|
|
|||
|
On outermost call, pass 0 for PASSED_A_PTR.
|
|||
|
On outermost call, SHOW > 0 means should ignore
|
|||
|
any typename for TYPE and show its details.
|
|||
|
SHOW is always zero on recursive calls. */
|
|||
|
|
|||
|
static void
|
|||
|
type_print_varspec_prefix (type, stream, show, passed_a_ptr)
|
|||
|
struct type *type;
|
|||
|
FILE *stream;
|
|||
|
int show;
|
|||
|
int passed_a_ptr;
|
|||
|
{
|
|||
|
if (type == 0)
|
|||
|
return;
|
|||
|
|
|||
|
if (TYPE_NAME (type) && show <= 0)
|
|||
|
return;
|
|||
|
|
|||
|
QUIT;
|
|||
|
|
|||
|
switch (TYPE_CODE (type))
|
|||
|
{
|
|||
|
case TYPE_CODE_PTR:
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
|
|||
|
fprintf_filtered (stream, "*");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_MEMBER:
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
0);
|
|||
|
fprintf_filtered (stream, " ");
|
|||
|
type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
|
|||
|
passed_a_ptr);
|
|||
|
fprintf_filtered (stream, "::");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_METHOD:
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf (stream, "(");
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
0);
|
|||
|
fprintf_filtered (stream, " ");
|
|||
|
type_print_base (TYPE_DOMAIN_TYPE (type), stream, 0,
|
|||
|
passed_a_ptr);
|
|||
|
fprintf_filtered (stream, "::");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_REF:
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0, 1);
|
|||
|
fprintf_filtered (stream, "&");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_FUNC:
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
0);
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_ARRAY:
|
|||
|
type_print_varspec_prefix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
0);
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Print any array sizes, function arguments or close parentheses
|
|||
|
needed after the variable name (to describe its type).
|
|||
|
Args work like type_print_varspec_prefix. */
|
|||
|
|
|||
|
static void
|
|||
|
type_print_varspec_suffix (type, stream, show, passed_a_ptr)
|
|||
|
struct type *type;
|
|||
|
FILE *stream;
|
|||
|
int show;
|
|||
|
int passed_a_ptr;
|
|||
|
{
|
|||
|
if (type == 0)
|
|||
|
return;
|
|||
|
|
|||
|
if (TYPE_NAME (type) && show <= 0)
|
|||
|
return;
|
|||
|
|
|||
|
QUIT;
|
|||
|
|
|||
|
switch (TYPE_CODE (type))
|
|||
|
{
|
|||
|
case TYPE_CODE_ARRAY:
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
|
|||
|
fprintf_filtered (stream, "[");
|
|||
|
if (TYPE_LENGTH (type) >= 0
|
|||
|
&& TYPE_LENGTH (TYPE_TARGET_TYPE (type)) > 0)
|
|||
|
fprintf_filtered (stream, "%d",
|
|||
|
(TYPE_LENGTH (type)
|
|||
|
/ TYPE_LENGTH (TYPE_TARGET_TYPE (type))));
|
|||
|
fprintf_filtered (stream, "]");
|
|||
|
|
|||
|
type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
0);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_MEMBER:
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_METHOD:
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 0);
|
|||
|
if (passed_a_ptr)
|
|||
|
{
|
|||
|
int i;
|
|||
|
struct type **args = TYPE_ARG_TYPES (type);
|
|||
|
|
|||
|
fprintf_filtered (stream, "(");
|
|||
|
if (args[1] == 0)
|
|||
|
fprintf_filtered (stream, "...");
|
|||
|
else for (i = 1; args[i] != 0 && args[i]->code != TYPE_CODE_VOID; i++)
|
|||
|
{
|
|||
|
type_print_1 (args[i], "", stream, -1, 0);
|
|||
|
if (args[i+1] == 0)
|
|||
|
fprintf_filtered (stream, "...");
|
|||
|
else if (args[i+1]->code != TYPE_CODE_VOID)
|
|||
|
fprintf_filtered (stream, ",");
|
|||
|
}
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_PTR:
|
|||
|
case TYPE_CODE_REF:
|
|||
|
type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0, 1);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_FUNC:
|
|||
|
type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream, 0,
|
|||
|
passed_a_ptr);
|
|||
|
if (passed_a_ptr)
|
|||
|
fprintf_filtered (stream, ")");
|
|||
|
fprintf_filtered (stream, "()");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* Print the name of the type (or the ultimate pointer target,
|
|||
|
function value or array element), or the description of a
|
|||
|
structure or union.
|
|||
|
|
|||
|
SHOW nonzero means don't print this type as just its name;
|
|||
|
show its real definition even if it has a name.
|
|||
|
SHOW zero means print just typename or struct tag if there is one
|
|||
|
SHOW negative means abbreviate structure elements.
|
|||
|
SHOW is decremented for printing of structure elements.
|
|||
|
|
|||
|
LEVEL is the depth to indent by.
|
|||
|
We increase it for some recursive calls. */
|
|||
|
|
|||
|
static void
|
|||
|
type_print_base (type, stream, show, level)
|
|||
|
struct type *type;
|
|||
|
FILE *stream;
|
|||
|
int show;
|
|||
|
int level;
|
|||
|
{
|
|||
|
char *name;
|
|||
|
register int i;
|
|||
|
register int len;
|
|||
|
register int lastval;
|
|||
|
|
|||
|
QUIT;
|
|||
|
|
|||
|
if (type == 0)
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "type unknown");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (TYPE_NAME (type) && show <= 0)
|
|||
|
{
|
|||
|
fputs_filtered (TYPE_NAME (type), stream);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
switch (TYPE_CODE (type))
|
|||
|
{
|
|||
|
case TYPE_CODE_ARRAY:
|
|||
|
case TYPE_CODE_PTR:
|
|||
|
case TYPE_CODE_MEMBER:
|
|||
|
case TYPE_CODE_REF:
|
|||
|
case TYPE_CODE_FUNC:
|
|||
|
case TYPE_CODE_METHOD:
|
|||
|
type_print_base (TYPE_TARGET_TYPE (type), stream, show, level);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_STRUCT:
|
|||
|
fprintf_filtered (stream, "struct ");
|
|||
|
goto struct_union;
|
|||
|
|
|||
|
case TYPE_CODE_UNION:
|
|||
|
fprintf_filtered (stream, "union ");
|
|||
|
struct_union:
|
|||
|
if (TYPE_NAME (type) && (name = TYPE_NAME (type)))
|
|||
|
{
|
|||
|
while (*name != ' ') name++;
|
|||
|
fputs_filtered (name + 1, stream);
|
|||
|
fputs_filtered (" ", stream);
|
|||
|
}
|
|||
|
if (show < 0)
|
|||
|
fprintf_filtered (stream, "{...}");
|
|||
|
else
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
type_print_derivation_info (stream, type);
|
|||
|
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
len = TYPE_NFIELDS (type);
|
|||
|
if (len)
|
|||
|
fprintf_filtered (stream, "\n");
|
|||
|
else
|
|||
|
{
|
|||
|
if (TYPE_FLAGS (type) & TYPE_FLAG_STUB)
|
|||
|
fprintf_filtered (stream, "<incomplete type>\n");
|
|||
|
else
|
|||
|
fprintf_filtered (stream, "<no data fields>\n");
|
|||
|
}
|
|||
|
|
|||
|
/* If there is a base class for this type,
|
|||
|
do not print the field that it occupies. */
|
|||
|
for (i = TYPE_N_BASECLASSES (type); i < len; i++)
|
|||
|
{
|
|||
|
QUIT;
|
|||
|
/* Don't print out virtual function table. */
|
|||
|
if (! strncmp (TYPE_FIELD_NAME (type, i),
|
|||
|
"_vptr$", 6))
|
|||
|
continue;
|
|||
|
|
|||
|
print_spaces_filtered (level + 4, stream);
|
|||
|
if (TYPE_FIELD_STATIC (type, i))
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "static ");
|
|||
|
}
|
|||
|
type_print_1 (TYPE_FIELD_TYPE (type, i),
|
|||
|
TYPE_FIELD_NAME (type, i),
|
|||
|
stream, show - 1, level + 4);
|
|||
|
if (!TYPE_FIELD_STATIC (type, i)
|
|||
|
&& TYPE_FIELD_PACKED (type, i))
|
|||
|
{
|
|||
|
/* It is a bitfield. This code does not attempt
|
|||
|
to look at the bitpos and reconstruct filler,
|
|||
|
unnamed fields. This would lead to misleading
|
|||
|
results if the compiler does not put out fields
|
|||
|
for such things (I don't know what it does). */
|
|||
|
fprintf_filtered (stream, " : %d",
|
|||
|
TYPE_FIELD_BITSIZE (type, i));
|
|||
|
}
|
|||
|
fprintf_filtered (stream, ";\n");
|
|||
|
}
|
|||
|
|
|||
|
/* C++: print out the methods */
|
|||
|
len = TYPE_NFN_FIELDS (type);
|
|||
|
if (len) fprintf_filtered (stream, "\n");
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
{
|
|||
|
struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
|
|||
|
int j, len2 = TYPE_FN_FIELDLIST_LENGTH (type, i);
|
|||
|
|
|||
|
for (j = 0; j < len2; j++)
|
|||
|
{
|
|||
|
QUIT;
|
|||
|
print_spaces_filtered (level + 4, stream);
|
|||
|
if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
|
|||
|
fprintf_filtered (stream, "virtual ");
|
|||
|
else if (TYPE_FN_FIELD_STATIC_P (f, j))
|
|||
|
fprintf_filtered (stream, "static ");
|
|||
|
type_print (TYPE_TARGET_TYPE (TYPE_FN_FIELD_TYPE (f, j)), "", stream, 0);
|
|||
|
if (TYPE_FN_FIELD_PHYSNAME (f, j)[0] == '_'
|
|||
|
&& TYPE_FN_FIELD_PHYSNAME (f, j)[1] == '$')
|
|||
|
type_print_method_args
|
|||
|
(TYPE_FN_FIELD_ARGS (f, j) + 1, "~",
|
|||
|
TYPE_FN_FIELDLIST_NAME (type, i), 0, stream);
|
|||
|
else
|
|||
|
type_print_method_args
|
|||
|
(TYPE_FN_FIELD_ARGS (f, j), "",
|
|||
|
TYPE_FN_FIELDLIST_NAME (type, i),
|
|||
|
TYPE_FN_FIELD_STATIC_P (f, j), stream);
|
|||
|
|
|||
|
fprintf_filtered (stream, ";\n");
|
|||
|
}
|
|||
|
if (len2) fprintf_filtered (stream, "\n");
|
|||
|
}
|
|||
|
|
|||
|
print_spaces_filtered (level, stream);
|
|||
|
fprintf_filtered (stream, "}");
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_ENUM:
|
|||
|
fprintf_filtered (stream, "enum ");
|
|||
|
if (TYPE_NAME (type))
|
|||
|
{
|
|||
|
name = TYPE_NAME (type);
|
|||
|
while (*name != ' ') name++;
|
|||
|
fputs_filtered (name + 1, stream);
|
|||
|
fputs_filtered (" ", stream);
|
|||
|
}
|
|||
|
if (show < 0)
|
|||
|
fprintf_filtered (stream, "{...}");
|
|||
|
else
|
|||
|
{
|
|||
|
fprintf_filtered (stream, "{");
|
|||
|
len = TYPE_NFIELDS (type);
|
|||
|
lastval = 0;
|
|||
|
for (i = 0; i < len; i++)
|
|||
|
{
|
|||
|
QUIT;
|
|||
|
if (i) fprintf_filtered (stream, ", ");
|
|||
|
fputs_filtered (TYPE_FIELD_NAME (type, i), stream);
|
|||
|
if (lastval != TYPE_FIELD_BITPOS (type, i))
|
|||
|
{
|
|||
|
fprintf_filtered (stream, " : %d", TYPE_FIELD_BITPOS (type, i));
|
|||
|
lastval = TYPE_FIELD_BITPOS (type, i);
|
|||
|
}
|
|||
|
lastval++;
|
|||
|
}
|
|||
|
fprintf_filtered (stream, "}");
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_INT:
|
|||
|
if (TYPE_UNSIGNED (type))
|
|||
|
name = unsigned_type_table[TYPE_LENGTH (type)];
|
|||
|
else
|
|||
|
name = signed_type_table[TYPE_LENGTH (type)];
|
|||
|
fputs_filtered (name, stream);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_FLT:
|
|||
|
name = float_type_table[TYPE_LENGTH (type)];
|
|||
|
fputs_filtered (name, stream);
|
|||
|
break;
|
|||
|
|
|||
|
case TYPE_CODE_VOID:
|
|||
|
fprintf_filtered (stream, "void");
|
|||
|
break;
|
|||
|
|
|||
|
case 0:
|
|||
|
fprintf_filtered (stream, "struct unknown");
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error ("Invalid type code in symbol table.");
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
scalar_print_decimal(stream, type, val)
|
|||
|
FILE *stream;
|
|||
|
struct type *type;
|
|||
|
LONGEST val;
|
|||
|
{
|
|||
|
fprintf_filtered(stream, TYPE_UNSIGNED(type)? "%lu":"%ld", val);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
scalar_print_hex(stream, type, val)
|
|||
|
FILE *stream;
|
|||
|
struct type *type;
|
|||
|
LONGEST val;
|
|||
|
{
|
|||
|
switch (TYPE_LENGTH(type)) {
|
|||
|
case 1:
|
|||
|
fprintf_filtered (stream, "0x%02lx", val);
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
fprintf_filtered (stream, "0x%04lx", val);
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
fprintf_filtered (stream, "0x%08lx", val);
|
|||
|
break;
|
|||
|
default:
|
|||
|
fprintf_filtered (stream, "0x%lx", val);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
scalar_print_octal(stream, type, val)
|
|||
|
FILE *stream;
|
|||
|
struct type *type;
|
|||
|
LONGEST val;
|
|||
|
{
|
|||
|
switch (TYPE_LENGTH(type)) {
|
|||
|
case 1:
|
|||
|
fprintf_filtered (stream, "0%03lo", val);
|
|||
|
break;
|
|||
|
case 2:
|
|||
|
fprintf_filtered (stream, "0%06lo", val);
|
|||
|
break;
|
|||
|
case 4:
|
|||
|
fprintf_filtered (stream, "0%012lo", val);
|
|||
|
break;
|
|||
|
default:
|
|||
|
fprintf_filtered (stream, "0%lo", val);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
scalar_print_hack(stream, type, val)
|
|||
|
FILE *stream;
|
|||
|
struct type *type;
|
|||
|
LONGEST val;
|
|||
|
{
|
|||
|
if (TYPE_UNSIGNED(type))
|
|||
|
scalar_print_hex(stream, type, val);
|
|||
|
else
|
|||
|
scalar_print_decimal(stream, type, val);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
set_maximum_command (arg)
|
|||
|
char *arg;
|
|||
|
{
|
|||
|
if (!arg) error_no_arg ("value for maximum elements to print");
|
|||
|
print_max = parse_and_eval_address (arg);
|
|||
|
if (print_max == 0)
|
|||
|
print_max = UINT_MAX;
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
set_base_command(arg)
|
|||
|
char *arg;
|
|||
|
{
|
|||
|
int base;
|
|||
|
|
|||
|
if (!arg)
|
|||
|
base = 0;
|
|||
|
else
|
|||
|
base = parse_and_eval_address (arg);
|
|||
|
switch (base) {
|
|||
|
default:
|
|||
|
default_scalar_print = scalar_print_hack;
|
|||
|
break;
|
|||
|
case 8:
|
|||
|
default_scalar_print = scalar_print_octal;
|
|||
|
break;
|
|||
|
case 10:
|
|||
|
default_scalar_print = scalar_print_decimal;
|
|||
|
break;
|
|||
|
case 16:
|
|||
|
default_scalar_print = scalar_print_hex;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
set_prettyprint_command (arg, from_tty)
|
|||
|
char *arg;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
prettyprint = parse_binary_operation ("set prettyprint", arg);
|
|||
|
}
|
|||
|
|
|||
|
static void
|
|||
|
set_unionprint_command (arg, from_tty)
|
|||
|
char *arg;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
unionprint = parse_binary_operation ("set unionprint", arg);
|
|||
|
}
|
|||
|
|
|||
|
format_info (arg, from_tty)
|
|||
|
char *arg;
|
|||
|
int from_tty;
|
|||
|
{
|
|||
|
if (arg)
|
|||
|
error ("\"info format\" does not take any arguments.");
|
|||
|
printf ("Prettyprinting of structures is %s.\n",
|
|||
|
prettyprint ? "on" : "off");
|
|||
|
printf ("Printing of unions interior to structures is %s.\n",
|
|||
|
unionprint ? "on" : "off");
|
|||
|
if (print_max == UINT_MAX)
|
|||
|
printf_filtered
|
|||
|
("There is no maximum number of array elements printed.\n");
|
|||
|
else
|
|||
|
printf_filtered
|
|||
|
("The maximum number of array elements printed is %d.\n", print_max);
|
|||
|
}
|
|||
|
|
|||
|
extern struct cmd_list_element *setlist;
|
|||
|
|
|||
|
void
|
|||
|
_initialize_valprint ()
|
|||
|
{
|
|||
|
add_cmd ("base", class_support, set_base_command,
|
|||
|
"Change default integer print radix to 8, 10 or 16\n\
|
|||
|
No args returns to the ad-hoc default of `16' for unsigned values\n\
|
|||
|
and `10' otherwise.",
|
|||
|
&setlist);
|
|||
|
add_cmd ("array-max", class_vars, set_maximum_command,
|
|||
|
"Set NUMBER as limit on string chars or array elements to print.\n\
|
|||
|
\"set array-max 0\" causes there to be no limit.",
|
|||
|
&setlist);
|
|||
|
|
|||
|
add_cmd ("prettyprint", class_support, set_prettyprint_command,
|
|||
|
"Turn prettyprinting of structures on and off.",
|
|||
|
&setlist);
|
|||
|
add_alias_cmd ("pp", "prettyprint", class_support, 1, &setlist);
|
|||
|
|
|||
|
add_cmd ("unionprint", class_support, set_unionprint_command,
|
|||
|
"Turn printing of unions interior to structures on and off.",
|
|||
|
&setlist);
|
|||
|
|
|||
|
add_info ("format", format_info,
|
|||
|
"Show current settings of data formatting options.");
|
|||
|
|
|||
|
/* Give people the defaults which they are used to. */
|
|||
|
prettyprint = 0;
|
|||
|
unionprint = 1;
|
|||
|
|
|||
|
print_max = 200;
|
|||
|
|
|||
|
unsigned_type_table
|
|||
|
= (char **) xmalloc ((1 + sizeof (unsigned LONGEST)) * sizeof (char *));
|
|||
|
bzero (unsigned_type_table, (1 + sizeof (unsigned LONGEST)));
|
|||
|
unsigned_type_table[sizeof (unsigned char)] = "unsigned char";
|
|||
|
unsigned_type_table[sizeof (unsigned short)] = "unsigned short";
|
|||
|
unsigned_type_table[sizeof (unsigned long)] = "unsigned long";
|
|||
|
unsigned_type_table[sizeof (unsigned int)] = "unsigned int";
|
|||
|
#ifdef LONG_LONG
|
|||
|
unsigned_type_table[sizeof (unsigned long long)] = "unsigned long long";
|
|||
|
#endif
|
|||
|
|
|||
|
signed_type_table
|
|||
|
= (char **) xmalloc ((1 + sizeof (LONGEST)) * sizeof (char *));
|
|||
|
bzero (signed_type_table, (1 + sizeof (LONGEST)));
|
|||
|
signed_type_table[sizeof (char)] = "char";
|
|||
|
signed_type_table[sizeof (short)] = "short";
|
|||
|
signed_type_table[sizeof (long)] = "long";
|
|||
|
signed_type_table[sizeof (int)] = "int";
|
|||
|
#ifdef LONG_LONG
|
|||
|
signed_type_table[sizeof (long long)] = "long long";
|
|||
|
#endif
|
|||
|
|
|||
|
float_type_table
|
|||
|
= (char **) xmalloc ((1 + sizeof (double)) * sizeof (char *));
|
|||
|
bzero (float_type_table, (1 + sizeof (double)));
|
|||
|
float_type_table[sizeof (float)] = "float";
|
|||
|
float_type_table[sizeof (double)] = "double";
|
|||
|
}
|
|||
|
|