/* Print values for GNU debugger GDB.
- Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1986-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "target.h"
#include "breakpoint.h"
#include "demangle.h"
+#include "gdb-demangle.h"
#include "valprint.h"
#include "annotate.h"
#include "symfile.h" /* for overlay functions */
#include "exceptions.h"
#include "observer.h"
#include "solist.h"
-#include "solib.h"
#include "parser-defs.h"
#include "charset.h"
+#include "arch-utils.h"
+#include "cli/cli-utils.h"
+#include "format.h"
#ifdef TUI
-#include "tui/tui.h" /* For tui_active et.al. */
+#include "tui/tui.h" /* For tui_active et al. */
#endif
-#if defined(__MINGW32__) && !defined(PRINTF_HAS_LONG_LONG)
-# define USE_PRINTF_I64 1
-# define PRINTF_HAS_LONG_LONG
-#else
-# define USE_PRINTF_I64 0
-#endif
-
-extern int asm_demangle; /* Whether to demangle syms in asm printouts */
-
struct format_data
{
int count;
char format;
char size;
+
+ /* True if the value should be printed raw -- that is, bypassing
+ python-based formatters. */
+ unsigned char raw;
};
/* Last specified output format. */
-static char last_format = 'x';
+static char last_format = 0;
/* Last specified examination size. 'b', 'h', 'w' or `q'. */
static char last_size = 'w';
-/* Default address to examine next. */
+/* Default address to examine next, and associated architecture. */
+static struct gdbarch *next_gdbarch;
static CORE_ADDR next_address;
/* Number of delay instructions following current disassembled insn. */
show_max_symbolic_offset (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-The largest offset that will be printed in <symbol+1234> form is %s.\n"),
+ fprintf_filtered (file,
+ _("The largest offset that will be "
+ "printed in <symbol+1234> form is %s.\n"),
value);
}
show_print_symbol_filename (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
- fprintf_filtered (file, _("\
-Printing of source filename and line number with <symbol> is %s.\n"),
+ fprintf_filtered (file, _("Printing of source filename and "
+ "line number with <symbol> is %s.\n"),
value);
}
/* Number of auto-display expression currently being displayed.
- So that we can disable it if we get an error or a signal within it.
+ So that we can disable it if we get a signal within it.
-1 when not doing one. */
int current_display_number;
{
/* Chain link to next auto-display item. */
struct display *next;
+
/* The expression as the user typed it. */
char *exp_string;
+
/* Expression to be evaluated and displayed. */
struct expression *exp;
+
/* Item number of this auto-display item. */
int number;
+
/* Display format specified. */
struct format_data format;
- /* Innermost block required by this expression when evaluated */
+
+ /* Program space associated with `block'. */
+ struct program_space *pspace;
+
+ /* Innermost block required by this expression when evaluated. */
struct block *block;
- /* Status of this display (enabled or disabled) */
+
+ /* Status of this display (enabled or disabled). */
int enabled_p;
};
static int display_number;
-/* Prototypes for exported functions. */
+/* Walk the following statement or block through all displays.
+ ALL_DISPLAYS_SAFE does so even if the statement deletes the current
+ display. */
+
+#define ALL_DISPLAYS(B) \
+ for (B = display_chain; B; B = B->next)
+
+#define ALL_DISPLAYS_SAFE(B,TMP) \
+ for (B = display_chain; \
+ B ? (TMP = B->next, 1): 0; \
+ B = TMP)
+
+/* Prototypes for exported functions. */
void output_command (char *, int);
void _initialize_printcmd (void);
-/* Prototypes for local functions. */
+/* Prototypes for local functions. */
static void do_one_display (struct display *);
\f
val.format = '?';
val.size = '?';
val.count = 1;
+ val.raw = 0;
if (*p >= '0' && *p <= '9')
val.count = atoi (p);
{
if (*p == 'b' || *p == 'h' || *p == 'w' || *p == 'g')
val.size = *p++;
+ else if (*p == 'r')
+ {
+ val.raw = 1;
+ p++;
+ }
else if (*p >= 'a' && *p <= 'z')
val.format = *p++;
else
switch (val.format)
{
case 'a':
- case 's':
- /* Pick the appropriate size for an address. */
- if (gdbarch_ptr_bit (current_gdbarch) == 64)
- val.size = osize ? 'g' : osize;
- else if (gdbarch_ptr_bit (current_gdbarch) == 32)
- val.size = osize ? 'w' : osize;
- else if (gdbarch_ptr_bit (current_gdbarch) == 16)
- val.size = osize ? 'h' : osize;
- else
- /* Bad value for gdbarch_ptr_bit. */
- internal_error (__FILE__, __LINE__,
- _("failed internal consistency check"));
+ /* Pick the appropriate size for an address. This is deferred
+ until do_examine when we know the actual architecture to use.
+ A special size value of 'a' is used to indicate this case. */
+ val.size = osize ? 'a' : osize;
break;
case 'f':
/* Floating point has to be word or giantword. */
/* Characters default to one byte. */
val.size = osize ? 'b' : osize;
break;
+ case 's':
+ /* Display strings with byte size chars unless explicitly
+ specified. */
+ val.size = '\0';
+ break;
+
default:
/* The default is the size most recently specified. */
val.size = osize;
int len = TYPE_LENGTH (type);
if (VALUE_LVAL (val) == lval_memory)
- next_address = VALUE_ADDRESS (val) + len;
+ next_address = value_address (val) + len;
if (size)
{
case 's':
{
struct type *elttype = value_type (val);
- next_address = (VALUE_ADDRESS (val)
- + val_print_string (elttype,
- VALUE_ADDRESS (val), -1,
- stream, options));
+
+ next_address = (value_address (val)
+ + val_print_string (elttype, NULL,
+ value_address (val), -1,
+ stream, options) * len);
}
return;
case 'i':
/* We often wrap here if there are long symbolic names. */
wrap_here (" ");
- next_address = (VALUE_ADDRESS (val)
- + gdb_print_insn (VALUE_ADDRESS (val), stream,
+ next_address = (value_address (val)
+ + gdb_print_insn (get_type_arch (type),
+ value_address (val), stream,
&branch_delay_insns));
return;
}
|| TYPE_CODE (type) == TYPE_CODE_NAMESPACE)
value_print (val, stream, options);
else
- /* User specified format, so don't look to the the type to
- tell us what to do. */
- print_scalar_formatted (value_contents (val), type,
- options, size, stream);
+ /* User specified format, so don't look to the type to tell us
+ what to do. */
+ val_print_scalar_formatted (type,
+ value_contents_for_printing (val),
+ value_embedded_offset (val),
+ val,
+ options, size, stream);
}
/* Return builtin floating point type of same length as TYPE.
If no such type is found, return TYPE itself. */
static struct type *
-float_type_from_length (struct gdbarch *gdbarch, struct type *type)
+float_type_from_length (struct type *type)
{
+ struct gdbarch *gdbarch = get_type_arch (type);
const struct builtin_type *builtin = builtin_type (gdbarch);
- unsigned int len = TYPE_LENGTH (type);
- if (len == TYPE_LENGTH (builtin->builtin_float))
+ if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_float))
type = builtin->builtin_float;
- else if (len == TYPE_LENGTH (builtin->builtin_double))
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_double))
type = builtin->builtin_double;
- else if (len == TYPE_LENGTH (builtin->builtin_long_double))
+ else if (TYPE_LENGTH (type) == TYPE_LENGTH (builtin->builtin_long_double))
type = builtin->builtin_long_double;
return type;
}
/* Print a scalar of data of type TYPE, pointed to in GDB by VALADDR,
- according to OPTIONS and SIZE on STREAM.
- Formats s and i are not supported at this level.
-
- This is how the elements of an array or structure are printed
- with a format. */
+ according to OPTIONS and SIZE on STREAM. Formats s and i are not
+ supported at this level. */
void
print_scalar_formatted (const void *valaddr, struct type *type,
const struct value_print_options *options,
int size, struct ui_file *stream)
{
+ struct gdbarch *gdbarch = get_type_arch (type);
LONGEST val_long = 0;
unsigned int len = TYPE_LENGTH (type);
- enum bfd_endian byte_order = gdbarch_byte_order (current_gdbarch);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- /* If we get here with a string format, try again without it. Go
- all the way back to the language printers, which may call us
- again. */
- if (options->format == 's')
- {
- struct value_print_options opts = *options;
- opts.format = 0;
- opts.deref_ref = 0;
- val_print (type, valaddr, 0, 0, stream, 0, &opts,
- current_language);
- return;
- }
+ /* String printing should go through val_print_scalar_formatted. */
+ gdb_assert (options->format != 's');
if (len > sizeof(LONGEST) &&
(TYPE_CODE (type) == TYPE_CODE_INT
same, then at this point, the value's length (in target bytes) is
gdbarch_addr_bit/TARGET_CHAR_BIT, not TYPE_LENGTH (type). */
if (TYPE_CODE (type) == TYPE_CODE_PTR)
- len = gdbarch_addr_bit (current_gdbarch) / TARGET_CHAR_BIT;
+ len = gdbarch_addr_bit (gdbarch) / TARGET_CHAR_BIT;
/* If we are printing it as unsigned, truncate it in case it is actually
a negative signed value (e.g. "print/u (short)-1" should print 65535
(if shorts are 16 bits) instead of 4294967295). */
- if (options->format != 'd')
+ if (options->format != 'd' || TYPE_UNSIGNED (type))
{
if (len < sizeof (LONGEST))
val_long &= ((LONGEST) 1 << HOST_CHAR_BIT * len) - 1;
case 'a':
{
CORE_ADDR addr = unpack_pointer (type, valaddr);
- print_address (addr, stream);
+
+ print_address (gdbarch, addr, stream);
}
break;
case 'c':
{
struct value_print_options opts = *options;
+
opts.format = 0;
if (TYPE_UNSIGNED (type))
- value_print (value_from_longest (builtin_type_true_unsigned_char,
- val_long),
- stream, &opts);
- else
- value_print (value_from_longest (builtin_type_true_char, val_long),
- stream, &opts);
+ type = builtin_type (gdbarch)->builtin_true_unsigned_char;
+ else
+ type = builtin_type (gdbarch)->builtin_true_char;
+
+ value_print (value_from_longest (type, val_long), stream, &opts);
}
break;
case 'f':
- type = float_type_from_length (current_gdbarch, type);
+ type = float_type_from_length (type);
print_floating (valaddr, type, stream);
break;
if (*cp == '\0')
cp--;
}
- strcpy (buf, cp);
+ strncpy (buf, cp, sizeof (bits));
fputs_filtered (buf, stream);
}
break;
{
struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ next_gdbarch = gdbarch;
next_address = addr;
/* Make address available to the user as $_. */
DO_DEMANGLE controls whether to print a symbol in its native "raw" form,
or to interpret it as a possible C++ name and convert it back to source
form. However note that DO_DEMANGLE can be overridden by the specific
- settings of the demangle and asm_demangle variables. */
+ settings of the demangle and asm_demangle variables. Returns
+ non-zero if anything was printed; zero otherwise. */
-void
-print_address_symbolic (CORE_ADDR addr, struct ui_file *stream,
+int
+print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct ui_file *stream,
int do_demangle, char *leadin)
{
char *name = NULL;
struct cleanup *cleanup_chain = make_cleanup (free_current_contents, &name);
make_cleanup (free_current_contents, &filename);
- if (build_address_symbolic (addr, do_demangle, &name, &offset,
+ if (build_address_symbolic (gdbarch, addr, do_demangle, &name, &offset,
&filename, &line, &unmapped))
{
do_cleanups (cleanup_chain);
- return;
+ return 0;
}
fputs_filtered (leadin, stream);
fputs_filtered (">", stream);
do_cleanups (cleanup_chain);
+ return 1;
}
/* Given an address ADDR return all the elements needed to print the
- address in a symbolic form. NAME can be mangled or not depending
+ address in a symbolic form. NAME can be mangled or not depending
on DO_DEMANGLE (and also on the asm_demangle global variable,
- manipulated via ''set print asm-demangle''). Return 0 in case of
- success, when all the info in the OUT paramters is valid. Return 1
- otherwise. */
+ manipulated via ''set print asm-demangle''). Return 0 in case of
+ success, when all the info in the OUT paramters is valid. Return 1
+ otherwise. */
int
-build_address_symbolic (CORE_ADDR addr, /* IN */
+build_address_symbolic (struct gdbarch *gdbarch,
+ CORE_ADDR addr, /* IN */
int do_demangle, /* IN */
char **name, /* OUT */
int *offset, /* OUT */
struct symbol *symbol;
CORE_ADDR name_location = 0;
struct obj_section *section = NULL;
- char *name_temp = "";
+ const char *name_temp = "";
/* Let's say it is mapped (not unmapped). */
*unmapped = 0;
if (symbol)
{
+ /* If this is a function (i.e. a code address), strip out any
+ non-address bits. For instance, display a pointer to the
+ first instruction of a Thumb function as <function>; the
+ second instruction will be <function+2>, even though the
+ pointer is <function+3>. This matches the ISA behavior. */
+ addr = gdbarch_addr_bits_remove (gdbarch, addr);
+
name_location = BLOCK_START (SYMBOL_BLOCK_VALUE (symbol));
if (do_demangle || asm_demangle)
name_temp = SYMBOL_PRINT_NAME (symbol);
name_temp = SYMBOL_LINKAGE_NAME (symbol);
}
+ if (msymbol != NULL
+ && MSYMBOL_HAS_SIZE (msymbol)
+ && MSYMBOL_SIZE (msymbol) == 0
+ && MSYMBOL_TYPE (msymbol) != mst_text
+ && MSYMBOL_TYPE (msymbol) != mst_text_gnu_ifunc
+ && MSYMBOL_TYPE (msymbol) != mst_file_text)
+ msymbol = NULL;
+
if (msymbol != NULL)
{
if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
<SYMBOL + OFFSET> after the number. */
void
-print_address (CORE_ADDR addr, struct ui_file *stream)
+print_address (struct gdbarch *gdbarch,
+ CORE_ADDR addr, struct ui_file *stream)
{
- fputs_filtered (paddress (addr), stream);
- print_address_symbolic (addr, stream, asm_demangle, " ");
+ fputs_filtered (paddress (gdbarch, addr), stream);
+ print_address_symbolic (gdbarch, addr, stream, asm_demangle, " ");
}
-/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE
- controls whether to print the symbolic name "raw" or demangled.
- Global setting "addressprint" controls whether to print hex address
- or not. */
+/* Return a prefix for instruction address:
+ "=> " for current instruction, else " ". */
-void
-print_address_demangle (CORE_ADDR addr, struct ui_file *stream,
- int do_demangle)
+const char *
+pc_prefix (CORE_ADDR addr)
{
- struct value_print_options opts;
- get_user_print_options (&opts);
- if (addr == 0)
+ if (has_stack_frames ())
{
- fprintf_filtered (stream, "0");
+ struct frame_info *frame;
+ CORE_ADDR pc;
+
+ frame = get_selected_frame (NULL);
+ if (get_frame_pc_if_available (frame, &pc) && pc == addr)
+ return "=> ";
}
- else if (opts.addressprint)
+ return " ";
+}
+
+/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE
+ controls whether to print the symbolic name "raw" or demangled.
+ Return non-zero if anything was printed; zero otherwise. */
+
+int
+print_address_demangle (const struct value_print_options *opts,
+ struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct ui_file *stream, int do_demangle)
+{
+ if (opts->addressprint)
{
- fputs_filtered (paddress (addr), stream);
- print_address_symbolic (addr, stream, do_demangle, " ");
+ fputs_filtered (paddress (gdbarch, addr), stream);
+ print_address_symbolic (gdbarch, addr, stream, do_demangle, " ");
}
else
{
- print_address_symbolic (addr, stream, do_demangle, "");
+ return print_address_symbolic (gdbarch, addr, stream, do_demangle, "");
}
+ return 1;
}
\f
-/* These are the types that $__ will get after an examine command of one
- of these sizes. */
-
-static struct type *examine_i_type;
-
-static struct type *examine_b_type;
-static struct type *examine_h_type;
-static struct type *examine_w_type;
-static struct type *examine_g_type;
-
/* Examine data at address ADDR in format FMT.
Fetch it from memory and print on gdb_stdout. */
static void
-do_examine (struct format_data fmt, CORE_ADDR addr)
+do_examine (struct format_data fmt, struct gdbarch *gdbarch, CORE_ADDR addr)
{
char format = 0;
char size;
format = fmt.format;
size = fmt.size;
count = fmt.count;
+ next_gdbarch = gdbarch;
next_address = addr;
- /* String or instruction format implies fetch single bytes
- regardless of the specified size. */
- if (format == 's' || format == 'i')
+ /* Instruction format implies fetch single bytes
+ regardless of the specified size.
+ The case of strings is handled in decode_format, only explicit
+ size operator are not changed to 'b'. */
+ if (format == 'i')
size = 'b';
- if (format == 'i')
- val_type = examine_i_type;
- else if (size == 'b')
- val_type = examine_b_type;
+ if (size == 'a')
+ {
+ /* Pick the appropriate size for an address. */
+ if (gdbarch_ptr_bit (next_gdbarch) == 64)
+ size = 'g';
+ else if (gdbarch_ptr_bit (next_gdbarch) == 32)
+ size = 'w';
+ else if (gdbarch_ptr_bit (next_gdbarch) == 16)
+ size = 'h';
+ else
+ /* Bad value for gdbarch_ptr_bit. */
+ internal_error (__FILE__, __LINE__,
+ _("failed internal consistency check"));
+ }
+
+ if (size == 'b')
+ val_type = builtin_type (next_gdbarch)->builtin_int8;
else if (size == 'h')
- val_type = examine_h_type;
+ val_type = builtin_type (next_gdbarch)->builtin_int16;
else if (size == 'w')
- val_type = examine_w_type;
+ val_type = builtin_type (next_gdbarch)->builtin_int32;
else if (size == 'g')
- val_type = examine_g_type;
+ val_type = builtin_type (next_gdbarch)->builtin_int64;
+
+ if (format == 's')
+ {
+ struct type *char_type = NULL;
+
+ /* Search for "char16_t" or "char32_t" types or fall back to 8-bit char
+ if type is not found. */
+ if (size == 'h')
+ char_type = builtin_type (next_gdbarch)->builtin_char16;
+ else if (size == 'w')
+ char_type = builtin_type (next_gdbarch)->builtin_char32;
+ if (char_type)
+ val_type = char_type;
+ else
+ {
+ if (size != '\0' && size != 'b')
+ warning (_("Unable to display strings with "
+ "size '%c', using 'b' instead."), size);
+ size = 'b';
+ val_type = builtin_type (next_gdbarch)->builtin_int8;
+ }
+ }
maxelts = 8;
if (size == 'w')
while (count > 0)
{
QUIT;
- print_address (next_address, gdb_stdout);
+ if (format == 'i')
+ fputs_filtered (pc_prefix (next_address), gdb_stdout);
+ print_address (next_gdbarch, next_address, gdb_stdout);
printf_filtered (":");
for (i = maxelts;
i > 0 && count > 0;
the address stored in LAST_EXAMINE_VALUE. FIXME: Should
the disassembler be modified so that LAST_EXAMINE_VALUE
is left with the byte sequence from the last complete
- instruction fetched from memory? */
+ instruction fetched from memory? */
last_examine_value = value_at_lazy (val_type, next_address);
if (last_examine_value)
fmt.count = 1;
fmt.format = 0;
fmt.size = 0;
+ fmt.raw = 0;
}
if (exp && *exp)
{
- struct type *type;
expr = parse_expression (exp);
old_chain = make_cleanup (free_current_contents, &expr);
cleanup = 1;
get_formatted_print_options (&opts, format);
opts.inspect_it = inspect;
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
printf_filtered ("\n");
struct value_print_options opts;
fmt.size = 0;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
annotate_value_begin (value_type (val));
get_formatted_print_options (&opts, format);
+ opts.raw = fmt.raw;
print_formatted (val, fmt.size, &opts, gdb_stdout);
annotate_value_end ();
struct expression *expr = parse_expression (exp);
struct cleanup *old_chain =
make_cleanup (free_current_contents, &expr);
+
+ if (expr->nelts >= 1)
+ switch (expr->elts[0].opcode)
+ {
+ case UNOP_PREINCREMENT:
+ case UNOP_POSTINCREMENT:
+ case UNOP_PREDECREMENT:
+ case UNOP_POSTDECREMENT:
+ case BINOP_ASSIGN:
+ case BINOP_ASSIGN_MODIFY:
+ case BINOP_COMMA:
+ break;
+ default:
+ warning
+ (_("Expression is not an assignment (and might have no effect)"));
+ }
+
evaluate_expression (expr);
do_cleanups (old_chain);
}
static void
address_info (char *exp, int from_tty)
{
+ struct gdbarch *gdbarch;
+ int regno;
struct symbol *sym;
struct minimal_symbol *msymbol;
long val;
struct obj_section *section;
- CORE_ADDR load_addr;
+ CORE_ADDR load_addr, context_pc = 0;
int is_a_field_of_this; /* C++: lookup_symbol sets this to nonzero
- if exp is a field of `this'. */
+ if exp is a field of `this'. */
if (exp == 0)
error (_("Argument required."));
- sym = lookup_symbol (exp, get_selected_block (0), VAR_DOMAIN,
+ sym = lookup_symbol (exp, get_selected_block (&context_pc), VAR_DOMAIN,
&is_a_field_of_this);
if (sym == NULL)
{
if (msymbol != NULL)
{
+ gdbarch = get_objfile_arch (msymbol_objfile (msymbol));
load_addr = SYMBOL_VALUE_ADDRESS (msymbol);
printf_filtered ("Symbol \"");
fprintf_symbol_filtered (gdb_stdout, exp,
current_language->la_language, DMGL_ANSI);
printf_filtered ("\" is at ");
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (" in a file compiled without debugging");
section = SYMBOL_OBJ_SECTION (msymbol);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (",\n -- loaded at ");
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (" in overlay section %s",
section->the_bfd_section->name);
}
printf_filtered ("\" is ");
val = SYMBOL_VALUE (sym);
section = SYMBOL_OBJ_SECTION (sym);
+ gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile);
switch (SYMBOL_CLASS (sym))
{
case LOC_LABEL:
printf_filtered ("a label at address ");
- fputs_filtered (paddress (load_addr = SYMBOL_VALUE_ADDRESS (sym)),
- gdb_stdout);
+ load_addr = SYMBOL_VALUE_ADDRESS (sym);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (",\n -- loaded at ");
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (" in overlay section %s",
section->the_bfd_section->name);
}
case LOC_COMPUTED:
/* FIXME: cagney/2004-01-26: It should be possible to
- unconditionally call the SYMBOL_OPS method when available.
+ unconditionally call the SYMBOL_COMPUTED_OPS method when available.
Unfortunately DWARF 2 stores the frame-base (instead of the
function) location in a function's symbol. Oops! For the
moment enable this when/where applicable. */
- SYMBOL_OPS (sym)->describe_location (sym, gdb_stdout);
+ SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, context_pc,
+ gdb_stdout);
break;
case LOC_REGISTER:
+ /* GDBARCH is the architecture associated with the objfile the symbol
+ is defined in; the target architecture may be different, and may
+ provide additional registers. However, we do not know the target
+ architecture at this point. We assume the objfile architecture
+ will contain all the standard registers that occur in debug info
+ in that objfile. */
+ regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch);
+
if (SYMBOL_IS_ARGUMENT (sym))
printf_filtered (_("an argument in register %s"),
- gdbarch_register_name (current_gdbarch, val));
+ gdbarch_register_name (gdbarch, regno));
else
printf_filtered (_("a variable in register %s"),
- gdbarch_register_name (current_gdbarch, val));
+ gdbarch_register_name (gdbarch, regno));
break;
case LOC_STATIC:
printf_filtered (_("static storage at address "));
- fputs_filtered (paddress (load_addr = SYMBOL_VALUE_ADDRESS (sym)),
- gdb_stdout);
+ load_addr = SYMBOL_VALUE_ADDRESS (sym);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
break;
case LOC_REGPARM_ADDR:
+ /* Note comment at LOC_REGISTER. */
+ regno = SYMBOL_REGISTER_OPS (sym)->register_number (sym, gdbarch);
printf_filtered (_("address of an argument in register %s"),
- gdbarch_register_name (current_gdbarch, val));
+ gdbarch_register_name (gdbarch, regno));
break;
case LOC_ARG:
case LOC_BLOCK:
printf_filtered (_("a function at address "));
load_addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
&& (section->the_bfd_section->flags & SEC_THREAD_LOCAL) != 0)
printf_filtered (_("a thread-local variable at offset %s "
"in the thread-local storage for `%s'"),
- paddr_nz (load_addr), section->objfile->name);
+ paddress (gdbarch, load_addr),
+ section->objfile->name);
else
{
printf_filtered (_("static storage at address "));
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
printf_filtered (_(",\n -- loaded at "));
- fputs_filtered (paddress (load_addr), gdb_stdout);
+ fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (_(" in overlay section %s"),
section->the_bfd_section->name);
}
struct cleanup *old_chain;
struct value *val;
- fmt.format = last_format;
+ fmt.format = last_format ? last_format : 'x';
fmt.size = last_size;
fmt.count = 1;
+ fmt.raw = 0;
if (exp && *exp == '/')
{
old_chain = make_cleanup (free_current_contents, &expr);
val = evaluate_expression (expr);
if (TYPE_CODE (value_type (val)) == TYPE_CODE_REF)
- val = value_ind (val);
+ val = coerce_ref (val);
/* In rvalue contexts, such as this, functions are coerced into
pointers to functions. This makes "x/i main" work. */
if (/* last_format == 'i' && */
TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC
&& VALUE_LVAL (val) == lval_memory)
- next_address = VALUE_ADDRESS (val);
+ next_address = value_address (val);
else
next_address = value_as_address (val);
+
+ next_gdbarch = expr->gdbarch;
do_cleanups (old_chain);
}
- do_examine (fmt, next_address);
+ if (!next_gdbarch)
+ error_no_arg (_("starting display address"));
+
+ do_examine (fmt, next_gdbarch, next_address);
/* If the examine succeeds, we remember its size and format for next
- time. */
- last_size = fmt.size;
+ time. Set last_size to 'b' for strings. */
+ if (fmt.format == 's')
+ last_size = 'b';
+ else
+ last_size = fmt.size;
last_format = fmt.format;
- /* Set a couple of internal variables if appropriate. */
+ /* Set a couple of internal variables if appropriate. */
if (last_examine_value)
{
/* Make last address examined available to the user as $_. Use
then don't fetch it now; instead mark it by voiding the $__
variable. */
if (value_lazy (last_examine_value))
- set_internalvar (lookup_internalvar ("__"),
- allocate_value (builtin_type_void));
+ clear_internalvar (lookup_internalvar ("__"));
else
set_internalvar (lookup_internalvar ("__"), last_examine_value);
}
fmt.format = 0;
fmt.size = 0;
fmt.count = 0;
+ fmt.raw = 0;
}
innermost_block = NULL;
new->exp_string = xstrdup (exp);
new->exp = expr;
new->block = innermost_block;
+ new->pspace = current_program_space;
new->next = display_chain;
new->number = ++display_number;
new->format = fmt;
}
}
-/* Delete the auto-display number NUM. */
+/* Delete the auto-display DISPLAY. */
static void
-delete_display (int num)
+delete_display (struct display *display)
{
- struct display *d1, *d;
+ struct display *d;
- if (!display_chain)
- error (_("No display number %d."), num);
+ gdb_assert (display != NULL);
- if (display_chain->number == num)
- {
- d1 = display_chain;
- display_chain = d1->next;
- free_display (d1);
- }
- else
- for (d = display_chain;; d = d->next)
+ if (display_chain == display)
+ display_chain = display->next;
+
+ ALL_DISPLAYS (d)
+ if (d->next == display)
{
- if (d->next == 0)
- error (_("No display number %d."), num);
- if (d->next->number == num)
- {
- d1 = d->next;
- d->next = d1->next;
- free_display (d1);
- break;
- }
+ d->next = display->next;
+ break;
}
+
+ free_display (display);
}
-/* Delete some values from the auto-display chain.
- Specify the element numbers. */
+/* Call FUNCTION on each of the displays whose numbers are given in
+ ARGS. DATA is passed unmodified to FUNCTION. */
static void
-undisplay_command (char *args, int from_tty)
+map_display_numbers (char *args,
+ void (*function) (struct display *,
+ void *),
+ void *data)
{
- char *p = args;
- char *p1;
+ struct get_number_or_range_state state;
int num;
- if (args == 0)
+ if (args == NULL)
+ error_no_arg (_("one or more display numbers"));
+
+ init_number_or_range (&state, args);
+
+ while (!state.finished)
{
- if (query (_("Delete all auto-display expressions? ")))
- clear_displays ();
- dont_repeat ();
- return;
+ char *p = state.string;
+
+ num = get_number_or_range (&state);
+ if (num == 0)
+ warning (_("bad display number at or near '%s'"), p);
+ else
+ {
+ struct display *d, *tmp;
+
+ ALL_DISPLAYS_SAFE (d, tmp)
+ if (d->number == num)
+ break;
+ if (d == NULL)
+ printf_unfiltered (_("No display number %d.\n"), num);
+ else
+ function (d, data);
+ }
}
+}
- while (*p)
- {
- p1 = p;
- while (*p1 >= '0' && *p1 <= '9')
- p1++;
- if (*p1 && *p1 != ' ' && *p1 != '\t')
- error (_("Arguments must be display numbers."));
+/* Callback for map_display_numbers, that deletes a display. */
- num = atoi (p);
+static void
+do_delete_display (struct display *d, void *data)
+{
+ delete_display (d);
+}
- delete_display (num);
+/* "undisplay" command. */
- p = p1;
- while (*p == ' ' || *p == '\t')
- p++;
+static void
+undisplay_command (char *args, int from_tty)
+{
+ if (args == NULL)
+ {
+ if (query (_("Delete all auto-display expressions? ")))
+ clear_displays ();
+ dont_repeat ();
+ return;
}
+
+ map_display_numbers (args, do_delete_display, NULL);
dont_repeat ();
}
/* Display a single auto-display.
Do nothing if the display cannot be printed in the current context,
- or if the display is disabled. */
+ or if the display is disabled. */
static void
do_one_display (struct display *d)
{
+ struct cleanup *old_chain;
int within_current_scope;
if (d->enabled_p == 0)
return;
+ /* The expression carries the architecture that was used at parse time.
+ This is a problem if the expression depends on architecture features
+ (e.g. register numbers), and the current architecture is now different.
+ For example, a display statement like "display/i $pc" is expected to
+ display the PC register of the current architecture, not the arch at
+ the time the display command was given. Therefore, we re-parse the
+ expression if the current architecture has changed. */
+ if (d->exp != NULL && d->exp->gdbarch != get_current_arch ())
+ {
+ xfree (d->exp);
+ d->exp = NULL;
+ d->block = NULL;
+ }
+
if (d->exp == NULL)
{
volatile struct gdb_exception ex;
+
TRY_CATCH (ex, RETURN_MASK_ALL)
{
innermost_block = NULL;
}
if (d->block)
- within_current_scope = contained_in (get_selected_block (0), d->block);
+ {
+ if (d->pspace == current_program_space)
+ within_current_scope = contained_in (get_selected_block (0), d->block);
+ else
+ within_current_scope = 0;
+ }
else
within_current_scope = 1;
if (!within_current_scope)
return;
+ old_chain = make_cleanup_restore_integer (¤t_display_number);
current_display_number = d->number;
annotate_display_begin ();
printf_filtered (": ");
if (d->format.size)
{
- CORE_ADDR addr;
- struct value *val;
+ volatile struct gdb_exception ex;
annotate_display_format ();
else
printf_filtered (" ");
- val = evaluate_expression (d->exp);
- addr = value_as_address (val);
- if (d->format.format == 'i')
- addr = gdbarch_addr_bits_remove (current_gdbarch, addr);
-
annotate_display_value ();
- do_examine (d->format, addr);
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ struct value *val;
+ CORE_ADDR addr;
+
+ val = evaluate_expression (d->exp);
+ addr = value_as_address (val);
+ if (d->format.format == 'i')
+ addr = gdbarch_addr_bits_remove (d->exp->gdbarch, addr);
+ do_examine (d->format, d->exp->gdbarch, addr);
+ }
+ if (ex.reason < 0)
+ fprintf_filtered (gdb_stdout, _("<error: %s>\n"), ex.message);
}
else
{
struct value_print_options opts;
+ volatile struct gdb_exception ex;
annotate_display_format ();
annotate_display_expression ();
get_formatted_print_options (&opts, d->format.format);
- print_formatted (evaluate_expression (d->exp),
- d->format.size, &opts, gdb_stdout);
+ opts.raw = d->format.raw;
+
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ struct value *val;
+
+ val = evaluate_expression (d->exp);
+ print_formatted (val, d->format.size, &opts, gdb_stdout);
+ }
+ if (ex.reason < 0)
+ fprintf_filtered (gdb_stdout, _("<error: %s>"), ex.message);
printf_filtered ("\n");
}
annotate_display_end ();
gdb_flush (gdb_stdout);
- current_display_number = -1;
+ do_cleanups (old_chain);
}
/* Display all of the values on the auto-display chain which can be
if (current_display_number >= 0)
{
disable_display (current_display_number);
- fprintf_unfiltered (gdb_stderr, _("\
-Disabling display %d to avoid infinite recursion.\n"),
+ fprintf_unfiltered (gdb_stderr,
+ _("Disabling display %d to "
+ "avoid infinite recursion.\n"),
current_display_number);
}
current_display_number = -1;
}
}
+/* Callback fo map_display_numbers, that enables or disables the
+ passed in display D. */
+
static void
-enable_display (char *args, int from_tty)
+do_enable_disable_display (struct display *d, void *data)
{
- char *p = args;
- char *p1;
- int num;
- struct display *d;
-
- if (p == 0)
- {
- for (d = display_chain; d; d = d->next)
- d->enabled_p = 1;
- }
- else
- while (*p)
- {
- p1 = p;
- while (*p1 >= '0' && *p1 <= '9')
- p1++;
- if (*p1 && *p1 != ' ' && *p1 != '\t')
- error (_("Arguments must be display numbers."));
-
- num = atoi (p);
-
- for (d = display_chain; d; d = d->next)
- if (d->number == num)
- {
- d->enabled_p = 1;
- goto win;
- }
- printf_unfiltered (_("No display number %d.\n"), num);
- win:
- p = p1;
- while (*p == ' ' || *p == '\t')
- p++;
- }
+ d->enabled_p = *(int *) data;
}
+/* Implamentation of both the "disable display" and "enable display"
+ commands. ENABLE decides what to do. */
+
static void
-disable_display_command (char *args, int from_tty)
+enable_disable_display_command (char *args, int from_tty, int enable)
{
- char *p = args;
- char *p1;
- struct display *d;
-
- if (p == 0)
+ if (args == NULL)
{
- for (d = display_chain; d; d = d->next)
- d->enabled_p = 0;
- }
- else
- while (*p)
- {
- p1 = p;
- while (*p1 >= '0' && *p1 <= '9')
- p1++;
- if (*p1 && *p1 != ' ' && *p1 != '\t')
- error (_("Arguments must be display numbers."));
+ struct display *d;
- disable_display (atoi (p));
+ ALL_DISPLAYS (d)
+ d->enabled_p = enable;
+ return;
+ }
- p = p1;
- while (*p == ' ' || *p == '\t')
- p++;
- }
+ map_display_numbers (args, do_enable_disable_display, &enable);
}
-/* Return 1 if D uses SOLIB (and will become dangling when SOLIB
- is unloaded), otherwise return 0. */
+/* The "enable display" command. */
-static int
-display_uses_solib_p (const struct display *d,
- const struct so_list *solib)
+static void
+enable_display_command (char *args, int from_tty)
{
- int endpos;
- struct expression *const exp = d->exp;
- const union exp_element *const elts = exp->elts;
-
- if (d->block != NULL
- && solib_contains_address_p (solib, d->block->startaddr))
- return 1;
-
- for (endpos = exp->nelts; endpos > 0; )
- {
- int i, args, oplen = 0;
-
- exp->language_defn->la_exp_desc->operator_length (exp, endpos,
- &oplen, &args);
- gdb_assert (oplen > 0);
-
- i = endpos - oplen;
- if (elts[i].opcode == OP_VAR_VALUE)
- {
- const struct block *const block = elts[i + 1].block;
- const struct symbol *const symbol = elts[i + 2].symbol;
- const struct obj_section *const section =
- SYMBOL_OBJ_SECTION (symbol);
-
- if (block != NULL
- && solib_contains_address_p (solib, block->startaddr))
- return 1;
+ enable_disable_display_command (args, from_tty, 1);
+}
- if (section && section->objfile == solib->objfile)
- return 1;
- }
- endpos -= oplen;
- }
+/* The "disable display" command. */
- return 0;
+static void
+disable_display_command (char *args, int from_tty)
+{
+ enable_disable_display_command (args, from_tty, 0);
}
/* display_chain items point to blocks and expressions. Some expressions in
static void
clear_dangling_display_expressions (struct so_list *solib)
{
+ struct objfile *objfile = solib->objfile;
struct display *d;
- struct objfile *objfile = NULL;
- for (d = display_chain; d; d = d->next)
+ /* With no symbol file we cannot have a block or expression from it. */
+ if (objfile == NULL)
+ return;
+ if (objfile->separate_debug_objfile_backlink)
+ objfile = objfile->separate_debug_objfile_backlink;
+ gdb_assert (objfile->pspace == solib->pspace);
+
+ for (d = display_chain; d != NULL; d = d->next)
{
- if (d->exp && display_uses_solib_p (d, solib))
- {
- xfree (d->exp);
- d->exp = NULL;
- d->block = NULL;
- }
+ if (d->pspace != solib->pspace)
+ continue;
+
+ if (lookup_objfile_from_block (d->block) == objfile
+ || (d->exp && exp_uses_objfile (d->exp, objfile)))
+ {
+ xfree (d->exp);
+ d->exp = NULL;
+ d->block = NULL;
+ }
}
}
\f
struct symbol. NAME is the name to print; if NULL then VAR's print
name will be used. STREAM is the ui_file on which to print the
value. INDENT specifies the number of indent levels to print
- before printing the variable name. */
+ before printing the variable name.
+
+ This function invalidates FRAME. */
void
print_variable_and_value (const char *name, struct symbol *var,
struct frame_info *frame,
struct ui_file *stream, int indent)
{
- struct value *val;
- struct value_print_options opts;
+ volatile struct gdb_exception except;
if (!name)
name = SYMBOL_PRINT_NAME (var);
fprintf_filtered (stream, "%s%s = ", n_spaces (2 * indent), name);
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ struct value *val;
+ struct value_print_options opts;
- val = read_var_value (var, frame);
- get_user_print_options (&opts);
- common_val_print (val, stream, indent, &opts, current_language);
+ val = read_var_value (var, frame);
+ get_user_print_options (&opts);
+ opts.deref_ref = 1;
+ common_val_print (val, stream, indent, &opts, current_language);
+
+ /* common_val_print invalidates FRAME when a pretty printer calls inferior
+ function. */
+ frame = NULL;
+ }
+ if (except.reason < 0)
+ fprintf_filtered(stream, "<error reading variable %s (%s)>", name,
+ except.message);
fprintf_filtered (stream, "\n");
}
+/* printf "printf format string" ARG to STREAM. */
+
static void
-printf_command (char *arg, int from_tty)
+ui_printf (char *arg, struct ui_file *stream)
{
- char *f = NULL;
+ struct format_piece *fpieces;
char *s = arg;
- char *string = NULL;
struct value **val_args;
- char *substrings;
- char *current_substring;
- int nargs = 0;
int allocated_args = 20;
struct cleanup *old_cleanups;
if (s == 0)
error_no_arg (_("format-control string and values to print"));
- /* Skip white space before format string */
- while (*s == ' ' || *s == '\t')
- s++;
+ s = skip_spaces (s);
/* A format string should follow, enveloped in double quotes. */
if (*s++ != '"')
error (_("Bad format string, missing '\"'."));
- /* Parse the format-control string and copy it into the string STRING,
- processing some kinds of escape sequence. */
-
- f = string = (char *) alloca (strlen (s) + 1);
-
- while (*s != '"')
- {
- int c = *s++;
- switch (c)
- {
- case '\0':
- error (_("Bad format string, non-terminated '\"'."));
+ fpieces = parse_format_string (&s);
- case '\\':
- switch (c = *s++)
- {
- case '\\':
- *f++ = '\\';
- break;
- case 'a':
- *f++ = '\a';
- break;
- case 'b':
- *f++ = '\b';
- break;
- case 'f':
- *f++ = '\f';
- break;
- case 'n':
- *f++ = '\n';
- break;
- case 'r':
- *f++ = '\r';
- break;
- case 't':
- *f++ = '\t';
- break;
- case 'v':
- *f++ = '\v';
- break;
- case '"':
- *f++ = '"';
- break;
- default:
- /* ??? TODO: handle other escape sequences */
- error (_("Unrecognized escape character \\%c in format string."),
- c);
- }
- break;
+ make_cleanup (free_format_pieces_cleanup, &fpieces);
- default:
- *f++ = c;
- }
- }
-
- /* Skip over " and following space and comma. */
- s++;
- *f++ = '\0';
- while (*s == ' ' || *s == '\t')
- s++;
+ if (*s++ != '"')
+ error (_("Bad format string, non-terminated '\"'."));
+
+ s = skip_spaces (s);
if (*s != ',' && *s != 0)
error (_("Invalid argument syntax"));
if (*s == ',')
s++;
- while (*s == ' ' || *s == '\t')
- s++;
-
- /* Need extra space for the '\0's. Doubling the size is sufficient. */
- substrings = alloca (strlen (string) * 2);
- current_substring = substrings;
+ s = skip_spaces (s);
{
- /* Now scan the string for %-specs and see what kinds of args they want.
- argclass[I] classifies the %-specs so we can give printf_filtered
- something of the right size. */
-
- enum argclass
- {
- int_arg, long_arg, long_long_arg, ptr_arg,
- string_arg, wide_string_arg, wide_char_arg,
- double_arg, long_double_arg, decfloat_arg
- };
- enum argclass *argclass;
- enum argclass this_argclass;
- char *last_arg;
+ int nargs = 0;
int nargs_wanted;
- int i;
+ int i, fr;
+ char *current_substring;
- argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass);
nargs_wanted = 0;
- f = string;
- last_arg = string;
- while (*f)
- if (*f++ == '%')
- {
- int seen_hash = 0, seen_zero = 0, lcount = 0, seen_prec = 0;
- int seen_space = 0, seen_plus = 0;
- int seen_big_l = 0, seen_h = 0, seen_big_h = 0;
- int seen_big_d = 0, seen_double_big_d = 0;
- int bad = 0;
-
- /* Check the validity of the format specifier, and work
- out what argument it expects. We only accept C89
- format strings, with the exception of long long (which
- we autoconf for). */
-
- /* Skip over "%%". */
- if (*f == '%')
- {
- f++;
- continue;
- }
-
- /* The first part of a format specifier is a set of flag
- characters. */
- while (strchr ("0-+ #", *f))
- {
- if (*f == '#')
- seen_hash = 1;
- else if (*f == '0')
- seen_zero = 1;
- else if (*f == ' ')
- seen_space = 1;
- else if (*f == '+')
- seen_plus = 1;
- f++;
- }
-
- /* The next part of a format specifier is a width. */
- while (strchr ("0123456789", *f))
- f++;
-
- /* The next part of a format specifier is a precision. */
- if (*f == '.')
- {
- seen_prec = 1;
- f++;
- while (strchr ("0123456789", *f))
- f++;
- }
-
- /* The next part of a format specifier is a length modifier. */
- if (*f == 'h')
- {
- seen_h = 1;
- f++;
- }
- else if (*f == 'l')
- {
- f++;
- lcount++;
- if (*f == 'l')
- {
- f++;
- lcount++;
- }
- }
- else if (*f == 'L')
- {
- seen_big_l = 1;
- f++;
- }
- /* Decimal32 modifier. */
- else if (*f == 'H')
- {
- seen_big_h = 1;
- f++;
- }
- /* Decimal64 and Decimal128 modifiers. */
- else if (*f == 'D')
- {
- f++;
-
- /* Check for a Decimal128. */
- if (*f == 'D')
- {
- f++;
- seen_double_big_d = 1;
- }
- else
- seen_big_d = 1;
- }
-
- switch (*f)
- {
- case 'u':
- if (seen_hash)
- bad = 1;
- /* FALLTHROUGH */
-
- case 'o':
- case 'x':
- case 'X':
- if (seen_space || seen_plus)
- bad = 1;
- /* FALLTHROUGH */
-
- case 'd':
- case 'i':
- if (lcount == 0)
- this_argclass = int_arg;
- else if (lcount == 1)
- this_argclass = long_arg;
- else
- this_argclass = long_long_arg;
-
- if (seen_big_l)
- bad = 1;
- break;
-
- case 'c':
- this_argclass = lcount == 0 ? int_arg : wide_char_arg;
- if (lcount > 1 || seen_h || seen_big_l)
- bad = 1;
- if (seen_prec || seen_zero || seen_space || seen_plus)
- bad = 1;
- break;
-
- case 'p':
- this_argclass = ptr_arg;
- if (lcount || seen_h || seen_big_l)
- bad = 1;
- if (seen_prec || seen_zero || seen_space || seen_plus)
- bad = 1;
- break;
-
- case 's':
- this_argclass = lcount == 0 ? string_arg : wide_string_arg;
- if (lcount > 1 || seen_h || seen_big_l)
- bad = 1;
- if (seen_zero || seen_space || seen_plus)
- bad = 1;
- break;
-
- case 'e':
- case 'f':
- case 'g':
- case 'E':
- case 'G':
- if (seen_big_h || seen_big_d || seen_double_big_d)
- this_argclass = decfloat_arg;
- else if (seen_big_l)
- this_argclass = long_double_arg;
- else
- this_argclass = double_arg;
-
- if (lcount || seen_h)
- bad = 1;
- break;
-
- case '*':
- error (_("`*' not supported for precision or width in printf"));
-
- case 'n':
- error (_("Format specifier `n' not supported in printf"));
-
- case '\0':
- error (_("Incomplete format specifier at end of format string"));
-
- default:
- error (_("Unrecognized format specifier '%c' in printf"), *f);
- }
-
- if (bad)
- error (_("Inappropriate modifiers to format specifier '%c' in printf"),
- *f);
-
- f++;
-
- if (lcount > 1 && USE_PRINTF_I64)
- {
- /* Windows' printf does support long long, but not the usual way.
- Convert %lld to %I64d. */
- int length_before_ll = f - last_arg - 1 - lcount;
- strncpy (current_substring, last_arg, length_before_ll);
- strcpy (current_substring + length_before_ll, "I64");
- current_substring[length_before_ll + 3] =
- last_arg[length_before_ll + lcount];
- current_substring += length_before_ll + 4;
- }
- else if (this_argclass == wide_string_arg
- || this_argclass == wide_char_arg)
- {
- /* Convert %ls or %lc to %s. */
- int length_before_ls = f - last_arg - 2;
- strncpy (current_substring, last_arg, length_before_ls);
- strcpy (current_substring + length_before_ls, "s");
- current_substring += length_before_ls + 2;
- }
- else
- {
- strncpy (current_substring, last_arg, f - last_arg);
- current_substring += f - last_arg;
- }
- *current_substring++ = '\0';
- last_arg = f;
- argclass[nargs_wanted++] = this_argclass;
- }
+ for (fr = 0; fpieces[fr].string != NULL; fr++)
+ if (fpieces[fr].argclass != literal_piece)
+ ++nargs_wanted;
/* Now, parse all arguments and evaluate them.
Store the VALUEs in VAL_ARGS. */
while (*s != '\0')
{
char *s1;
+
if (nargs == allocated_args)
val_args = (struct value **) xrealloc ((char *) val_args,
(allocated_args *= 2)
error (_("Wrong number of arguments for specified format-string"));
/* Now actually print them. */
- current_substring = substrings;
- for (i = 0; i < nargs; i++)
+ i = 0;
+ for (fr = 0; fpieces[fr].string != NULL; fr++)
{
- switch (argclass[i])
+ current_substring = fpieces[fr].string;
+ switch (fpieces[fr].argclass)
{
case string_arg:
{
gdb_byte *str;
CORE_ADDR tem;
int j;
+
tem = value_as_address (val_args[i]);
/* This is a %s argument. Find the length of the string. */
for (j = 0;; j++)
{
gdb_byte c;
+
QUIT;
read_memory (tem + j, &c, 1);
if (c == 0)
read_memory (tem, str, j);
str[j] = 0;
- printf_filtered (current_substring, (char *) str);
+ fprintf_filtered (stream, current_substring, (char *) str);
}
break;
case wide_string_arg:
gdb_byte *str;
CORE_ADDR tem;
int j;
- struct type *wctype = lookup_typename ("wchar_t", NULL, 0);
+ struct gdbarch *gdbarch
+ = get_type_arch (value_type (val_args[i]));
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct type *wctype = lookup_typename (current_language, gdbarch,
+ "wchar_t", NULL, 0);
int wcwidth = TYPE_LENGTH (wctype);
gdb_byte *buf = alloca (wcwidth);
struct obstack output;
{
QUIT;
read_memory (tem + j, buf, wcwidth);
- if (extract_unsigned_integer (buf, wcwidth) == 0)
+ if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
break;
}
obstack_init (&output);
inner_cleanup = make_cleanup_obstack_free (&output);
- convert_between_encodings (target_wide_charset (),
+ convert_between_encodings (target_wide_charset (gdbarch),
host_charset (),
str, j, wcwidth,
&output, translit_char);
obstack_grow_str0 (&output, "");
- printf_filtered (current_substring, obstack_base (&output));
+ fprintf_filtered (stream, current_substring,
+ obstack_base (&output));
do_cleanups (inner_cleanup);
}
break;
case wide_char_arg:
{
- struct type *wctype = lookup_typename ("wchar_t", NULL, 0);
+ struct gdbarch *gdbarch
+ = get_type_arch (value_type (val_args[i]));
+ struct type *wctype = lookup_typename (current_language, gdbarch,
+ "wchar_t", NULL, 0);
struct type *valtype;
struct obstack output;
struct cleanup *inner_cleanup;
obstack_init (&output);
inner_cleanup = make_cleanup_obstack_free (&output);
- convert_between_encodings (target_wide_charset (),
+ convert_between_encodings (target_wide_charset (gdbarch),
host_charset (),
bytes, TYPE_LENGTH (valtype),
TYPE_LENGTH (valtype),
&output, translit_char);
obstack_grow_str0 (&output, "");
- printf_filtered (current_substring, obstack_base (&output));
+ fprintf_filtered (stream, current_substring,
+ obstack_base (&output));
do_cleanups (inner_cleanup);
}
break;
/* If format string wants a float, unchecked-convert the value
to floating point of the same size. */
- type = float_type_from_length (current_gdbarch, type);
+ type = float_type_from_length (type);
val = unpack_double (type, value_contents (val_args[i]), &inv);
if (inv)
error (_("Invalid floating value found in program."));
- printf_filtered (current_substring, (double) val);
+ fprintf_filtered (stream, current_substring, (double) val);
break;
}
case long_double_arg:
/* If format string wants a float, unchecked-convert the value
to floating point of the same size. */
- type = float_type_from_length (current_gdbarch, type);
+ type = float_type_from_length (type);
val = unpack_double (type, value_contents (val_args[i]), &inv);
if (inv)
error (_("Invalid floating value found in program."));
- printf_filtered (current_substring, (long double) val);
+ fprintf_filtered (stream, current_substring,
+ (long double) val);
break;
}
#else
#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
{
long long val = value_as_long (val_args[i]);
- printf_filtered (current_substring, val);
+
+ fprintf_filtered (stream, current_substring, val);
break;
}
#else
case int_arg:
{
int val = value_as_long (val_args[i]);
- printf_filtered (current_substring, val);
+
+ fprintf_filtered (stream, current_substring, val);
break;
}
case long_arg:
{
long val = value_as_long (val_args[i]);
- printf_filtered (current_substring, val);
+
+ fprintf_filtered (stream, current_substring, val);
break;
}
case decfloat_arg:
{
const gdb_byte *param_ptr = value_contents (val_args[i]);
+
#if defined (PRINTF_HAS_DECFLOAT)
/* If we have native support for Decimal floating
printing, handle it here. */
- printf_filtered (current_substring, param_ptr);
+ fprintf_filtered (stream, current_substring, param_ptr);
#else
/* As a workaround until vasprintf has native support for DFP
/* Parameter data. */
struct type *param_type = value_type (val_args[i]);
- unsigned int param_len = TYPE_LENGTH (param_type);
+ struct gdbarch *gdbarch = get_type_arch (param_type);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
/* DFP output data. */
struct value *dfp_value = NULL;
if (*sos == 'H')
{
dfp_len = 4;
- dfp_type = builtin_type (current_gdbarch)->builtin_decfloat;
+ dfp_type = builtin_type (gdbarch)->builtin_decfloat;
}
else if (*sos == 'D' && *(sos - 1) == 'D')
{
dfp_len = 16;
- dfp_type = builtin_type (current_gdbarch)->builtin_declong;
+ dfp_type = builtin_type (gdbarch)->builtin_declong;
sos--;
}
else
{
dfp_len = 8;
- dfp_type = builtin_type (current_gdbarch)->builtin_decdouble;
+ dfp_type = builtin_type (gdbarch)->builtin_decdouble;
}
}
/* Conversion between different DFP types. */
if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT)
- decimal_convert (param_ptr, param_len, dec, dfp_len);
+ decimal_convert (param_ptr, TYPE_LENGTH (param_type),
+ byte_order, dec, dfp_len, byte_order);
else
/* If this is a non-trivial conversion, just output 0.
A correct converted value can be displayed by explicitly
casting to a DFP type. */
- decimal_from_string (dec, dfp_len, "0");
+ decimal_from_string (dec, dfp_len, byte_order, "0");
dfp_value = value_from_decfloat (dfp_type, dec);
dfp_ptr = (gdb_byte *) value_contents (dfp_value);
- decimal_to_string (dfp_ptr, dfp_len, decstr);
+ decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr);
/* Print the DFP value. */
- printf_filtered (current_substring, decstr);
+ fprintf_filtered (stream, current_substring, decstr);
break;
#endif
while (*p)
{
int is_percent = (*p == '%');
+
*fmt_p++ = *p++;
if (is_percent)
{
*fmt_p++ = 'l';
*fmt_p++ = 'x';
*fmt_p++ = '\0';
- printf_filtered (fmt, val);
+ fprintf_filtered (stream, fmt, val);
}
else
{
*fmt_p++ = 's';
*fmt_p++ = '\0';
- printf_filtered (fmt, "(nil)");
+ fprintf_filtered (stream, fmt, "(nil)");
}
break;
}
+ case literal_piece:
+ /* Print a portion of the format string that has no
+ directives. Note that this will not include any
+ ordinary %-specs, but it might include "%%". That is
+ why we use printf_filtered and not puts_filtered here.
+ Also, we pass a dummy argument because some platforms
+ have modified GCC to include -Wformat-security by
+ default, which will warn here if there is no
+ argument. */
+ fprintf_filtered (stream, current_substring, 0);
+ break;
default:
internal_error (__FILE__, __LINE__,
_("failed internal consistency check"));
}
- /* Skip to the next substring. */
- current_substring += strlen (current_substring) + 1;
+ /* Maybe advance to the next argument. */
+ if (fpieces[fr].argclass != literal_piece)
+ ++i;
}
- /* Print the portion of the format string after the last argument. */
- puts_filtered (last_arg);
}
do_cleanups (old_cleanups);
}
+/* Implement the "printf" command. */
+
+static void
+printf_command (char *arg, int from_tty)
+{
+ ui_printf (arg, gdb_stdout);
+}
+
+/* Implement the "eval" command. */
+
+static void
+eval_command (char *arg, int from_tty)
+{
+ struct ui_file *ui_out = mem_fileopen ();
+ struct cleanup *cleanups = make_cleanup_ui_file_delete (ui_out);
+ char *expanded;
+
+ ui_printf (arg, ui_out);
+
+ expanded = ui_file_xstrdup (ui_out, NULL);
+ make_cleanup (xfree, expanded);
+
+ execute_command (expanded, from_tty);
+
+ do_cleanups (cleanups);
+}
+
void
_initialize_printcmd (void)
{
With no argument, display all currently requested auto-display expressions.\n\
Use \"undisplay\" to cancel display requests previously made."));
- add_cmd ("display", class_vars, enable_display, _("\
+ add_cmd ("display", class_vars, enable_display_command, _("\
Enable some expressions to be displayed when program stops.\n\
Arguments are the code numbers of the expressions to resume displaying.\n\
No argument means enable all automatic-display expressions.\n\
\nWith a subcommand, this command modifies parts of the gdb environment.\n\
You can see these environment settings with the \"show\" command."));
- /* "call" is the same as "set", but handy for dbx users to call fns. */
+ /* "call" is the same as "set", but handy for dbx users to call fns. */
c = add_com ("call", class_vars, call_command, _("\
Call a function in the program.\n\
The argument is the function name and arguments, in the notation of the\n\
show_print_symbol_filename,
&setprintlist, &showprintlist);
- /* For examine/instruction a single byte quantity is specified as
- the data. This avoids problems with value_at_lazy() requiring a
- valid data type (and rejecting VOID). */
- examine_i_type = init_type (TYPE_CODE_INT, 1, 0, "examine_i_type", NULL);
-
- examine_b_type = init_type (TYPE_CODE_INT, 1, 0, "examine_b_type", NULL);
- examine_h_type = init_type (TYPE_CODE_INT, 2, 0, "examine_h_type", NULL);
- examine_w_type = init_type (TYPE_CODE_INT, 4, 0, "examine_w_type", NULL);
- examine_g_type = init_type (TYPE_CODE_INT, 8, 0, "examine_g_type", NULL);
-
+ add_com ("eval", no_class, eval_command, _("\
+Convert \"printf format string\", arg1, arg2, arg3, ..., argn to\n\
+a command line, and call it."));
}