/* Print values for GNU debugger GDB.
- Copyright (C) 1986-2012 Free Software Foundation, Inc.
+ Copyright (C) 1986-2015 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
-#include "gdb_string.h"
#include "frame.h"
#include "symtab.h"
#include "gdbtypes.h"
#include "objfiles.h" /* ditto */
#include "completer.h" /* for completion functions */
#include "ui-out.h"
-#include "gdb_assert.h"
#include "block.h"
#include "disasm.h"
#include "dfp.h"
-#include "valprint.h"
-#include "exceptions.h"
#include "observer.h"
#include "solist.h"
#include "parser-defs.h"
#include "charset.h"
#include "arch-utils.h"
#include "cli/cli-utils.h"
+#include "format.h"
+#include "source.h"
#ifdef TUI
#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
-
-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 = 0;
So that we can disable it if we get a signal within it.
-1 when not doing one. */
-int current_display_number;
+static int current_display_number;
struct display
{
struct program_space *pspace;
/* Innermost block required by this expression when evaluated. */
- struct block *block;
+ const struct block *block;
/* Status of this display (enabled or disabled). */
int enabled_p;
/* Prototypes for exported functions. */
-void output_command (char *, int);
-
void _initialize_printcmd (void);
/* Prototypes for local functions. */
past the specification and past all whitespace following it. */
static struct format_data
-decode_format (char **string_ptr, int oformat, int osize)
+decode_format (const char **string_ptr, int oformat, int osize)
{
struct format_data val;
- char *p = *string_ptr;
+ const char *p = *string_ptr;
val.format = '?';
val.size = '?';
{
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;
supported at this level. */
void
-print_scalar_formatted (const void *valaddr, struct type *type,
+print_scalar_formatted (const gdb_byte *valaddr, struct type *type,
const struct value_print_options *options,
int size, struct ui_file *stream)
{
}
break;
+ case 'z':
+ print_hex_chars (stream, valaddr, len, byte_order);
+ break;
+
default:
error (_("Undefined output format \"%c\"."), options->format);
}
int *line, /* OUT */
int *unmapped) /* OUT */
{
- struct minimal_symbol *msymbol;
+ struct bound_minimal_symbol msymbol;
struct symbol *symbol;
CORE_ADDR name_location = 0;
struct obj_section *section = NULL;
name_temp = SYMBOL_LINKAGE_NAME (symbol);
}
- if (msymbol != NULL
- && 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.minsym != NULL
+ && MSYMBOL_HAS_SIZE (msymbol.minsym)
+ && MSYMBOL_SIZE (msymbol.minsym) == 0
+ && MSYMBOL_TYPE (msymbol.minsym) != mst_text
+ && MSYMBOL_TYPE (msymbol.minsym) != mst_text_gnu_ifunc
+ && MSYMBOL_TYPE (msymbol.minsym) != mst_file_text)
+ msymbol.minsym = NULL;
- if (msymbol != NULL)
+ if (msymbol.minsym != NULL)
{
- if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
+ if (BMSYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
{
+ /* 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. */
+ if (MSYMBOL_TYPE (msymbol.minsym) == mst_text
+ || MSYMBOL_TYPE (msymbol.minsym) == mst_text_gnu_ifunc
+ || MSYMBOL_TYPE (msymbol.minsym) == mst_file_text
+ || MSYMBOL_TYPE (msymbol.minsym) == mst_solib_trampoline)
+ addr = gdbarch_addr_bits_remove (gdbarch, addr);
+
/* The msymbol is closer to the address than the symbol;
use the msymbol instead. */
symbol = 0;
- name_location = SYMBOL_VALUE_ADDRESS (msymbol);
+ name_location = BMSYMBOL_VALUE_ADDRESS (msymbol);
if (do_demangle || asm_demangle)
- name_temp = SYMBOL_PRINT_NAME (msymbol);
+ name_temp = MSYMBOL_PRINT_NAME (msymbol.minsym);
else
- name_temp = SYMBOL_LINKAGE_NAME (msymbol);
+ name_temp = MSYMBOL_LINKAGE_NAME (msymbol.minsym);
}
}
- if (symbol == NULL && msymbol == NULL)
+ if (symbol == NULL && msymbol.minsym == NULL)
return 1;
/* If the nearest symbol is too far away, don't print anything symbolic. */
if (sal.symtab)
{
- *filename = xstrdup (sal.symtab->filename);
+ *filename = xstrdup (symtab_to_filename_for_display (sal.symtab));
*line = sal.line;
}
}
}
\f
static void
-validate_format (struct format_data fmt, char *cmdname)
+validate_format (struct format_data fmt, const char *cmdname)
{
if (fmt.size != 0)
error (_("Size letters are meaningless in \"%s\" command."), cmdname);
fmt.format, cmdname);
}
-/* Evaluate string EXP as an expression in the current language and
- print the resulting value. EXP may contain a format specifier as the
- first argument ("/x myvar" for example, to print myvar in hex). */
+/* Parse print command format string into *FMTP and update *EXPP.
+ CMDNAME should name the current command. */
-static void
-print_command_1 (char *exp, int inspect, int voidprint)
+void
+print_command_parse_format (const char **expp, const char *cmdname,
+ struct format_data *fmtp)
{
- struct expression *expr;
- struct cleanup *old_chain = 0;
- char format = 0;
- struct value *val;
- struct format_data fmt;
- int cleanup = 0;
+ const char *exp = *expp;
if (exp && *exp == '/')
{
exp++;
- fmt = decode_format (&exp, last_format, 0);
- validate_format (fmt, "print");
- last_format = format = fmt.format;
+ *fmtp = decode_format (&exp, last_format, 0);
+ validate_format (*fmtp, cmdname);
+ last_format = fmtp->format;
}
else
{
- fmt.count = 1;
- fmt.format = 0;
- fmt.size = 0;
- fmt.raw = 0;
+ fmtp->count = 1;
+ fmtp->format = 0;
+ fmtp->size = 0;
+ fmtp->raw = 0;
}
+ *expp = exp;
+}
+
+/* Print VAL to console according to *FMTP, including recording it to
+ the history. */
+
+void
+print_value (struct value *val, const struct format_data *fmtp)
+{
+ struct value_print_options opts;
+ int histindex = record_latest_value (val);
+
+ annotate_value_history_begin (histindex, value_type (val));
+
+ printf_filtered ("$%d = ", histindex);
+
+ annotate_value_history_value ();
+
+ get_formatted_print_options (&opts, fmtp->format);
+ opts.raw = fmtp->raw;
+
+ print_formatted (val, fmtp->size, &opts, gdb_stdout);
+ printf_filtered ("\n");
+
+ annotate_value_history_end ();
+}
+
+/* Evaluate string EXP as an expression in the current language and
+ print the resulting value. EXP may contain a format specifier as the
+ first argument ("/x myvar" for example, to print myvar in hex). */
+
+static void
+print_command_1 (const char *exp, int voidprint)
+{
+ struct expression *expr;
+ struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
+ struct value *val;
+ struct format_data fmt;
+
+ print_command_parse_format (&exp, "print", &fmt);
+
if (exp && *exp)
{
expr = parse_expression (exp);
- old_chain = make_cleanup (free_current_contents, &expr);
- cleanup = 1;
+ make_cleanup (free_current_contents, &expr);
val = evaluate_expression (expr);
}
else
if (voidprint || (val && value_type (val) &&
TYPE_CODE (value_type (val)) != TYPE_CODE_VOID))
- {
- struct value_print_options opts;
- int histindex = record_latest_value (val);
-
- if (histindex >= 0)
- annotate_value_history_begin (histindex, value_type (val));
- else
- annotate_value_begin (value_type (val));
-
- if (inspect)
- printf_unfiltered ("\031(gdb-makebuffer \"%s\" %d '(\"",
- exp, histindex);
- else if (histindex >= 0)
- printf_filtered ("$%d = ", histindex);
+ print_value (val, &fmt);
- if (histindex >= 0)
- annotate_value_history_value ();
-
- 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");
-
- if (histindex >= 0)
- annotate_value_history_end ();
- else
- annotate_value_end ();
-
- if (inspect)
- printf_unfiltered ("\") )\030");
- }
-
- if (cleanup)
- do_cleanups (old_chain);
+ do_cleanups (old_chain);
}
static void
print_command (char *exp, int from_tty)
{
- print_command_1 (exp, 0, 1);
+ print_command_1 (exp, 1);
}
-/* Same as print, except in epoch, it gets its own window. */
+/* Same as print, except it doesn't print void results. */
static void
-inspect_command (char *exp, int from_tty)
+call_command (char *exp, int from_tty)
{
- extern int epoch_interface;
-
- print_command_1 (exp, epoch_interface, 1);
+ print_command_1 (exp, 0);
}
-/* Same as print, except it doesn't print void results. */
+/* Implementation of the "output" command. */
+
static void
-call_command (char *exp, int from_tty)
+output_command (char *exp, int from_tty)
{
- print_command_1 (exp, 0, 0);
+ output_command_const (exp, from_tty);
}
+/* Like output_command, but takes a const string as argument. */
+
void
-output_command (char *exp, int from_tty)
+output_command_const (const char *exp, int from_tty)
{
struct expression *expr;
struct cleanup *old_chain;
if (obj_section_addr (osect) <= sect_addr
&& sect_addr < obj_section_endaddr (osect)
- && (msymbol = lookup_minimal_symbol_by_pc_section (sect_addr, osect)))
+ && (msymbol
+ = lookup_minimal_symbol_by_pc_section (sect_addr, osect).minsym))
{
const char *obj_name, *mapped, *sec_name, *msym_name;
char *loc_string;
struct cleanup *old_chain;
matches = 1;
- offset = sect_addr - SYMBOL_VALUE_ADDRESS (msymbol);
+ offset = sect_addr - MSYMBOL_VALUE_ADDRESS (objfile, msymbol);
mapped = section_is_mapped (osect) ? _("mapped") : _("unmapped");
sec_name = osect->the_bfd_section->name;
- msym_name = SYMBOL_PRINT_NAME (msymbol);
+ msym_name = MSYMBOL_PRINT_NAME (msymbol);
/* Don't print the offset if it is zero.
We assume there's no need to handle i18n of "sym + offset". */
a pagination request inside printf_filtered. */
old_chain = make_cleanup (xfree, loc_string);
- gdb_assert (osect->objfile && osect->objfile->name);
- obj_name = osect->objfile->name;
+ gdb_assert (osect->objfile && objfile_name (osect->objfile));
+ obj_name = objfile_name (osect->objfile);
if (MULTI_OBJFILE_P ())
if (pc_in_unmapped_range (addr, osect))
struct gdbarch *gdbarch;
int regno;
struct symbol *sym;
- struct minimal_symbol *msymbol;
+ struct bound_minimal_symbol msymbol;
long val;
struct obj_section *section;
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'. */
+ struct field_of_this_result is_a_field_of_this;
if (exp == 0)
error (_("Argument required."));
sym = lookup_symbol (exp, get_selected_block (&context_pc), VAR_DOMAIN,
- &is_a_field_of_this);
+ &is_a_field_of_this).symbol;
if (sym == NULL)
{
- if (is_a_field_of_this)
+ if (is_a_field_of_this.type != NULL)
{
printf_filtered ("Symbol \"");
fprintf_symbol_filtered (gdb_stdout, exp,
return;
}
- msymbol = lookup_minimal_symbol (exp, NULL, NULL);
+ msymbol = lookup_bound_minimal_symbol (exp);
- if (msymbol != NULL)
+ if (msymbol.minsym != NULL)
{
- gdbarch = get_objfile_arch (msymbol_objfile (msymbol));
- load_addr = SYMBOL_VALUE_ADDRESS (msymbol);
+ struct objfile *objfile = msymbol.objfile;
+
+ gdbarch = get_objfile_arch (objfile);
+ load_addr = BMSYMBOL_VALUE_ADDRESS (msymbol);
printf_filtered ("Symbol \"");
fprintf_symbol_filtered (gdb_stdout, exp,
printf_filtered ("\" is at ");
fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
printf_filtered (" in a file compiled without debugging");
- section = SYMBOL_OBJ_SECTION (msymbol);
+ section = MSYMBOL_OBJ_SECTION (objfile, msymbol.minsym);
if (section_is_overlay (section))
{
load_addr = overlay_unmapped_address (load_addr, section);
current_language->la_language, DMGL_ANSI);
printf_filtered ("\" is ");
val = SYMBOL_VALUE (sym);
- section = SYMBOL_OBJ_SECTION (sym);
- gdbarch = get_objfile_arch (SYMBOL_SYMTAB (sym)->objfile);
+ if (SYMBOL_OBJFILE_OWNED (sym))
+ section = SYMBOL_OBJ_SECTION (symbol_objfile (sym), sym);
+ else
+ section = NULL;
+ gdbarch = symbol_arch (sym);
+
+ if (SYMBOL_COMPUTED_OPS (sym) != NULL)
+ {
+ SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, context_pc,
+ gdb_stdout);
+ printf_filtered (".\n");
+ return;
+ }
switch (SYMBOL_CLASS (sym))
{
break;
case LOC_COMPUTED:
- /* FIXME: cagney/2004-01-26: It should be possible to
- 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_COMPUTED_OPS (sym)->describe_location (sym, context_pc,
- gdb_stdout);
- break;
+ gdb_assert_not_reached (_("LOC_COMPUTED variable missing a method"));
case LOC_REGISTER:
/* GDBARCH is the architecture associated with the objfile the symbol
case LOC_UNRESOLVED:
{
- struct minimal_symbol *msym;
+ struct bound_minimal_symbol msym;
- msym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym), NULL, NULL);
- if (msym == NULL)
+ msym = lookup_minimal_symbol_and_objfile (SYMBOL_LINKAGE_NAME (sym));
+ if (msym.minsym == NULL)
printf_filtered ("unresolved");
else
{
- section = SYMBOL_OBJ_SECTION (msym);
- load_addr = SYMBOL_VALUE_ADDRESS (msym);
+ section = MSYMBOL_OBJ_SECTION (msym.objfile, msym.minsym);
if (section
&& (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'"),
- paddress (gdbarch, load_addr),
- section->objfile->name);
+ {
+ load_addr = MSYMBOL_VALUE_RAW_ADDRESS (msym.minsym);
+ printf_filtered (_("a thread-local variable at offset %s "
+ "in the thread-local storage for `%s'"),
+ paddress (gdbarch, load_addr),
+ objfile_name (section->objfile));
+ }
else
{
+ load_addr = BMSYMBOL_VALUE_ADDRESS (msym);
printf_filtered (_("static storage at address "));
fputs_filtered (paddress (gdbarch, load_addr), gdb_stdout);
if (section_is_overlay (section))
if (exp && *exp == '/')
{
- exp++;
- fmt = decode_format (&exp, last_format, last_size);
+ const char *tmp = exp + 1;
+
+ fmt = decode_format (&tmp, last_format, last_size);
+ exp = (char *) tmp;
}
/* If we have an expression, evaluate it and use it as the address. */
Specify the expression. */
static void
-display_command (char *exp, int from_tty)
+display_command (char *arg, int from_tty)
{
struct format_data fmt;
struct expression *expr;
- struct display *new;
- int display_it = 1;
-
-#if defined(TUI)
- /* NOTE: cagney/2003-02-13 The `tui_active' was previously
- `tui_version'. */
- if (tui_active && exp != NULL && *exp == '$')
- display_it = (tui_set_layout_for_display_command (exp) == TUI_FAILURE);
-#endif
+ struct display *newobj;
+ const char *exp = arg;
- if (display_it)
+ if (exp == 0)
{
- if (exp == 0)
- {
- do_displays ();
- return;
- }
+ do_displays ();
+ return;
+ }
- if (*exp == '/')
- {
- exp++;
- fmt = decode_format (&exp, 0, 0);
- if (fmt.size && fmt.format == 0)
- fmt.format = 'x';
- if (fmt.format == 'i' || fmt.format == 's')
- fmt.size = 'b';
- }
- else
- {
- fmt.format = 0;
- fmt.size = 0;
- fmt.count = 0;
- fmt.raw = 0;
- }
+ if (*exp == '/')
+ {
+ exp++;
+ fmt = decode_format (&exp, 0, 0);
+ if (fmt.size && fmt.format == 0)
+ fmt.format = 'x';
+ if (fmt.format == 'i' || fmt.format == 's')
+ fmt.size = 'b';
+ }
+ else
+ {
+ fmt.format = 0;
+ fmt.size = 0;
+ fmt.count = 0;
+ fmt.raw = 0;
+ }
- innermost_block = NULL;
- expr = parse_expression (exp);
+ innermost_block = NULL;
+ expr = parse_expression (exp);
- new = (struct display *) xmalloc (sizeof (struct display));
+ newobj = XNEW (struct display);
- 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;
- new->enabled_p = 1;
- display_chain = new;
+ newobj->exp_string = xstrdup (exp);
+ newobj->exp = expr;
+ newobj->block = innermost_block;
+ newobj->pspace = current_program_space;
+ newobj->next = display_chain;
+ newobj->number = ++display_number;
+ newobj->format = fmt;
+ newobj->enabled_p = 1;
+ display_chain = newobj;
- if (from_tty && target_has_execution)
- do_one_display (new);
+ if (from_tty)
+ do_one_display (newobj);
- dont_repeat ();
- }
+ dont_repeat ();
}
static void
while (!state.finished)
{
- char *p = state.string;
+ const char *p = state.string;
num = get_number_or_range (&state);
if (num == 0)
if (d->exp == NULL)
{
- volatile struct gdb_exception ex;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
innermost_block = NULL;
d->exp = parse_expression (d->exp_string);
d->block = innermost_block;
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ALL)
{
/* Can't re-parse the expression. Disable this display item. */
d->enabled_p = 0;
d->exp_string, ex.message);
return;
}
+ END_CATCH
}
if (d->block)
printf_filtered (": ");
if (d->format.size)
{
- volatile struct gdb_exception ex;
annotate_display_format ();
annotate_display_value ();
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
struct value *val;
CORE_ADDR addr;
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);
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ fprintf_filtered (gdb_stdout, _("<error: %s>\n"), ex.message);
+ }
+ END_CATCH
}
else
{
struct value_print_options opts;
- volatile struct gdb_exception ex;
annotate_display_format ();
get_formatted_print_options (&opts, d->format.format);
opts.raw = d->format.raw;
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
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);
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ fprintf_filtered (gdb_stdout, _("<error: %s>"), ex.message);
+ }
+ END_CATCH
+
printf_filtered ("\n");
}
an item by re-parsing .exp_string field in the new execution context. */
static void
-clear_dangling_display_expressions (struct so_list *solib)
+clear_dangling_display_expressions (struct objfile *objfile)
{
- struct objfile *objfile = solib->objfile;
struct display *d;
+ struct program_space *pspace;
/* With no symbol file we cannot have a block or expression from it. */
if (objfile == NULL)
return;
+ pspace = objfile->pspace;
if (objfile->separate_debug_objfile_backlink)
- objfile = objfile->separate_debug_objfile_backlink;
- gdb_assert (objfile->pspace == solib->pspace);
+ {
+ objfile = objfile->separate_debug_objfile_backlink;
+ gdb_assert (objfile->pspace == pspace);
+ }
for (d = display_chain; d != NULL; d = d->next)
{
- if (d->pspace != solib->pspace)
+ if (d->pspace != pspace)
continue;
if (lookup_objfile_from_block (d->block) == objfile
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)
{
- 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)
+ TRY
{
struct value *val;
struct value_print_options opts;
- val = read_var_value (var, frame);
+ /* READ_VAR_VALUE needs a block in order to deal with non-local
+ references (i.e. to handle nested functions). In this context, we
+ print variables that are local to this frame, so we can avoid passing
+ a block to it. */
+ val = read_var_value (var, NULL, 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;
+ }
+ CATCH (except, RETURN_MASK_ERROR)
+ {
+ fprintf_filtered(stream, "<error reading variable %s (%s)>", name,
+ except.message);
}
- if (except.reason < 0)
- fprintf_filtered(stream, "<error reading variable %s (%s)>", name,
- except.message);
+ END_CATCH
+
fprintf_filtered (stream, "\n");
}
-/* printf "printf format string" ARG to STREAM. */
+/* Subroutine of ui_printf to simplify it.
+ Print VALUE to STREAM using FORMAT.
+ VALUE is a C-style string on the target. */
static void
-ui_printf (char *arg, struct ui_file *stream)
+printf_c_string (struct ui_file *stream, const char *format,
+ struct value *value)
{
- char *f = NULL;
- 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;
+ gdb_byte *str;
+ CORE_ADDR tem;
+ int j;
- val_args = xmalloc (allocated_args * sizeof (struct value *));
- old_cleanups = make_cleanup (free_current_contents, &val_args);
+ tem = value_as_address (value);
- if (s == 0)
- error_no_arg (_("format-control string and values to print"));
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0;; j++)
+ {
+ gdb_byte c;
- s = skip_spaces (s);
+ QUIT;
+ read_memory (tem + j, &c, 1);
+ if (c == 0)
+ break;
+ }
- /* A format string should follow, enveloped in double quotes. */
- if (*s++ != '"')
- error (_("Bad format string, missing '\"'."));
+ /* Copy the string contents into a string inside GDB. */
+ str = (gdb_byte *) alloca (j + 1);
+ if (j != 0)
+ read_memory (tem, str, j);
+ str[j] = 0;
+
+ fprintf_filtered (stream, format, (char *) str);
+}
- /* Parse the format-control string and copy it into the string STRING,
- processing some kinds of escape sequence. */
+/* Subroutine of ui_printf to simplify it.
+ Print VALUE to STREAM using FORMAT.
+ VALUE is a wide C-style string on the target. */
+
+static void
+printf_wide_c_string (struct ui_file *stream, const char *format,
+ struct value *value)
+{
+ gdb_byte *str;
+ CORE_ADDR tem;
+ int j;
+ struct gdbarch *gdbarch = get_type_arch (value_type (value));
+ 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 = (gdb_byte *) alloca (wcwidth);
+ struct obstack output;
+ struct cleanup *inner_cleanup;
- f = string = (char *) alloca (strlen (s) + 1);
+ tem = value_as_address (value);
- while (*s != '"')
+ /* This is a %s argument. Find the length of the string. */
+ for (j = 0;; j += wcwidth)
{
- int c = *s++;
- switch (c)
- {
- case '\0':
- error (_("Bad format string, non-terminated '\"'."));
+ QUIT;
+ read_memory (tem + j, buf, wcwidth);
+ if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
+ break;
+ }
- 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;
+ /* Copy the string contents into a string inside GDB. */
+ str = (gdb_byte *) alloca (j + wcwidth);
+ if (j != 0)
+ read_memory (tem, str, j);
+ memset (&str[j], 0, wcwidth);
- default:
- *f++ = c;
+ obstack_init (&output);
+ inner_cleanup = make_cleanup_obstack_free (&output);
+
+ convert_between_encodings (target_wide_charset (gdbarch),
+ host_charset (),
+ str, j, wcwidth,
+ &output, translit_char);
+ obstack_grow_str0 (&output, "");
+
+ fprintf_filtered (stream, format, obstack_base (&output));
+ do_cleanups (inner_cleanup);
+}
+
+/* Subroutine of ui_printf to simplify it.
+ Print VALUE, a decimal floating point value, to STREAM using FORMAT. */
+
+static void
+printf_decfloat (struct ui_file *stream, const char *format,
+ struct value *value)
+{
+ const gdb_byte *param_ptr = value_contents (value);
+
+#if defined (PRINTF_HAS_DECFLOAT)
+ /* If we have native support for Decimal floating
+ printing, handle it here. */
+ fprintf_filtered (stream, format, param_ptr);
+#else
+ /* As a workaround until vasprintf has native support for DFP
+ we convert the DFP values to string and print them using
+ the %s format specifier. */
+ const char *p;
+
+ /* Parameter data. */
+ struct type *param_type = value_type (value);
+ 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;
+ gdb_byte *dfp_ptr;
+ int dfp_len = 16;
+ gdb_byte dec[16];
+ struct type *dfp_type = NULL;
+ char decstr[MAX_DECIMAL_STRING];
+
+ /* Points to the end of the string so that we can go back
+ and check for DFP length modifiers. */
+ p = format + strlen (format);
+
+ /* Look for the float/double format specifier. */
+ while (*p != 'f' && *p != 'e' && *p != 'E'
+ && *p != 'g' && *p != 'G')
+ p--;
+
+ /* Search for the '%' char and extract the size and type of
+ the output decimal value based on its modifiers
+ (%Hf, %Df, %DDf). */
+ while (*--p != '%')
+ {
+ if (*p == 'H')
+ {
+ dfp_len = 4;
+ dfp_type = builtin_type (gdbarch)->builtin_decfloat;
+ }
+ else if (*p == 'D' && *(p - 1) == 'D')
+ {
+ dfp_len = 16;
+ dfp_type = builtin_type (gdbarch)->builtin_declong;
+ p--;
+ }
+ else
+ {
+ dfp_len = 8;
+ dfp_type = builtin_type (gdbarch)->builtin_decdouble;
}
}
- /* Skip over " and following space and comma. */
- s++;
- *f++ = '\0';
- s = skip_spaces (s);
+ /* Conversion between different DFP types. */
+ if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT)
+ 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, byte_order, "0");
- if (*s != ',' && *s != 0)
- error (_("Invalid argument syntax"));
+ dfp_value = value_from_decfloat (dfp_type, dec);
- if (*s == ',')
- s++;
- s = skip_spaces (s);
+ dfp_ptr = (gdb_byte *) value_contents (dfp_value);
- /* Need extra space for the '\0's. Doubling the size is sufficient. */
- substrings = alloca (strlen (string) * 2);
- current_substring = substrings;
+ decimal_to_string (dfp_ptr, dfp_len, byte_order, decstr);
- {
- /* 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. */
+ /* Print the DFP value. */
+ fprintf_filtered (stream, "%s", decstr);
+#endif
+}
- 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_wanted;
- int i;
+/* Subroutine of ui_printf to simplify it.
+ Print VALUE, a target pointer, to STREAM using FORMAT. */
- 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;
- }
+static void
+printf_pointer (struct ui_file *stream, const char *format,
+ struct value *value)
+{
+ /* We avoid the host's %p because pointers are too
+ likely to be the wrong size. The only interesting
+ modifier for %p is a width; extract that, and then
+ handle %p as glibc would: %#x or a literal "(nil)". */
+
+ const char *p;
+ char *fmt, *fmt_p;
+#ifdef PRINTF_HAS_LONG_LONG
+ long long val = value_as_long (value);
+#else
+ long val = value_as_long (value);
+#endif
- /* 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++;
- }
+ fmt = (char *) alloca (strlen (format) + 5);
- /* The next part of a format specifier is a width. */
- while (strchr ("0123456789", *f))
- f++;
+ /* Copy up to the leading %. */
+ p = format;
+ fmt_p = fmt;
+ while (*p)
+ {
+ int is_percent = (*p == '%');
- /* The next part of a format specifier is a precision. */
- if (*f == '.')
- {
- seen_prec = 1;
- f++;
- while (strchr ("0123456789", *f))
- f++;
- }
+ *fmt_p++ = *p++;
+ if (is_percent)
+ {
+ if (*p == '%')
+ *fmt_p++ = *p++;
+ else
+ break;
+ }
+ }
- /* 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;
- }
+ if (val != 0)
+ *fmt_p++ = '#';
- 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;
+ /* Copy any width. */
+ while (*p >= '0' && *p < '9')
+ *fmt_p++ = *p++;
- 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;
+ gdb_assert (*p == 'p' && *(p + 1) == '\0');
+ if (val != 0)
+ {
+#ifdef PRINTF_HAS_LONG_LONG
+ *fmt_p++ = 'l';
+#endif
+ *fmt_p++ = 'l';
+ *fmt_p++ = 'x';
+ *fmt_p++ = '\0';
+ fprintf_filtered (stream, fmt, val);
+ }
+ else
+ {
+ *fmt_p++ = 's';
+ *fmt_p++ = '\0';
+ fprintf_filtered (stream, fmt, "(nil)");
+ }
+}
- 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;
+/* printf "printf format string" ARG to STREAM. */
- 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;
+static void
+ui_printf (const char *arg, struct ui_file *stream)
+{
+ struct format_piece *fpieces;
+ const char *s = arg;
+ struct value **val_args;
+ int allocated_args = 20;
+ struct cleanup *old_cleanups;
- 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;
+ val_args = XNEWVEC (struct value *, allocated_args);
+ old_cleanups = make_cleanup (free_current_contents, &val_args);
- case '*':
- error (_("`*' not supported for precision or width in printf"));
+ if (s == 0)
+ error_no_arg (_("format-control string and values to print"));
- case 'n':
- error (_("Format specifier `n' not supported in printf"));
+ s = skip_spaces_const (s);
- case '\0':
- error (_("Incomplete format specifier at end of format string"));
+ /* A format string should follow, enveloped in double quotes. */
+ if (*s++ != '"')
+ error (_("Bad format string, missing '\"'."));
- default:
- error (_("Unrecognized format specifier '%c' in printf"), *f);
- }
+ fpieces = parse_format_string (&s);
- if (bad)
- error (_("Inappropriate modifiers to "
- "format specifier '%c' in printf"),
- *f);
+ make_cleanup (free_format_pieces_cleanup, &fpieces);
- f++;
+ if (*s++ != '"')
+ error (_("Bad format string, non-terminated '\"'."));
+
+ s = skip_spaces_const (s);
- 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;
+ if (*s != ',' && *s != 0)
+ error (_("Invalid argument syntax"));
- 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;
- }
+ if (*s == ',')
+ s++;
+ s = skip_spaces_const (s);
+
+ {
+ int nargs = 0;
+ int nargs_wanted;
+ int i, fr;
+ char *current_substring;
+
+ nargs_wanted = 0;
+ 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;
+ const char *s1;
if (nargs == allocated_args)
val_args = (struct value **) xrealloc ((char *) val_args,
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)
- break;
- }
-
- /* Copy the string contents into a string inside GDB. */
- str = (gdb_byte *) alloca (j + 1);
- if (j != 0)
- read_memory (tem, str, j);
- str[j] = 0;
-
- fprintf_filtered (stream, current_substring, (char *) str);
- }
+ printf_c_string (stream, current_substring, val_args[i]);
break;
case wide_string_arg:
- {
- gdb_byte *str;
- CORE_ADDR tem;
- int j;
- 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;
- struct cleanup *inner_cleanup;
-
- tem = value_as_address (val_args[i]);
-
- /* This is a %s argument. Find the length of the string. */
- for (j = 0;; j += wcwidth)
- {
- QUIT;
- read_memory (tem + j, buf, wcwidth);
- if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
- break;
- }
-
- /* Copy the string contents into a string inside GDB. */
- str = (gdb_byte *) alloca (j + wcwidth);
- if (j != 0)
- read_memory (tem, str, j);
- memset (&str[j], 0, wcwidth);
-
- obstack_init (&output);
- inner_cleanup = make_cleanup_obstack_free (&output);
-
- convert_between_encodings (target_wide_charset (gdbarch),
- host_charset (),
- str, j, wcwidth,
- &output, translit_char);
- obstack_grow_str0 (&output, "");
-
- fprintf_filtered (stream, current_substring,
- obstack_base (&output));
- do_cleanups (inner_cleanup);
- }
+ printf_wide_c_string (stream, current_substring, val_args[i]);
break;
case wide_char_arg:
{
error (_("long double not supported in printf"));
#endif
case long_long_arg:
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
+#ifdef PRINTF_HAS_LONG_LONG
{
long long val = value_as_long (val_args[i]);
fprintf_filtered (stream, current_substring, val);
break;
}
-
/* Handles decimal floating values. */
- 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. */
- fprintf_filtered (stream, current_substring, param_ptr);
-#else
-
- /* As a workaround until vasprintf has native support for DFP
- we convert the DFP values to string and print them using
- the %s format specifier. */
-
- char *eos, *sos;
- int nnull_chars = 0;
-
- /* 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;
- gdb_byte *dfp_ptr;
- int dfp_len = 16;
- gdb_byte dec[16];
- struct type *dfp_type = NULL;
- char decstr[MAX_DECIMAL_STRING];
-
- /* Points to the end of the string so that we can go back
- and check for DFP length modifiers. */
- eos = current_substring + strlen (current_substring);
-
- /* Look for the float/double format specifier. */
- while (*eos != 'f' && *eos != 'e' && *eos != 'E'
- && *eos != 'g' && *eos != 'G')
- eos--;
-
- sos = eos;
-
- /* Search for the '%' char and extract the size and type of
- the output decimal value based on its modifiers
- (%Hf, %Df, %DDf). */
- while (*--sos != '%')
- {
- if (*sos == 'H')
- {
- dfp_len = 4;
- dfp_type = builtin_type (gdbarch)->builtin_decfloat;
- }
- else if (*sos == 'D' && *(sos - 1) == 'D')
- {
- dfp_len = 16;
- dfp_type = builtin_type (gdbarch)->builtin_declong;
- sos--;
- }
- else
- {
- dfp_len = 8;
- dfp_type = builtin_type (gdbarch)->builtin_decdouble;
- }
- }
-
- /* Replace %Hf, %Df and %DDf with %s's. */
- *++sos = 's';
-
- /* Go through the whole format string and pull the correct
- number of chars back to compensate for the change in the
- format specifier. */
- while (nnull_chars < nargs - i)
- {
- if (*eos == '\0')
- nnull_chars++;
-
- *++sos = *++eos;
- }
-
- /* Conversion between different DFP types. */
- if (TYPE_CODE (param_type) == TYPE_CODE_DECFLOAT)
- decimal_convert (param_ptr, param_len, 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, 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, byte_order, decstr);
-
- /* Print the DFP value. */
- fprintf_filtered (stream, current_substring, decstr);
-
- break;
-#endif
- }
-
+ case decfloat_arg:
+ printf_decfloat (stream, current_substring, val_args[i]);
+ break;
case ptr_arg:
- {
- /* We avoid the host's %p because pointers are too
- likely to be the wrong size. The only interesting
- modifier for %p is a width; extract that, and then
- handle %p as glibc would: %#x or a literal "(nil)". */
-
- char *p, *fmt, *fmt_p;
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
- long long val = value_as_long (val_args[i]);
-#else
- long val = value_as_long (val_args[i]);
-#endif
-
- fmt = alloca (strlen (current_substring) + 5);
-
- /* Copy up to the leading %. */
- p = current_substring;
- fmt_p = fmt;
- while (*p)
- {
- int is_percent = (*p == '%');
-
- *fmt_p++ = *p++;
- if (is_percent)
- {
- if (*p == '%')
- *fmt_p++ = *p++;
- else
- break;
- }
- }
-
- if (val != 0)
- *fmt_p++ = '#';
-
- /* Copy any width. */
- while (*p >= '0' && *p < '9')
- *fmt_p++ = *p++;
-
- gdb_assert (*p == 'p' && *(p + 1) == '\0');
- if (val != 0)
- {
-#if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG)
- *fmt_p++ = 'l';
-#endif
- *fmt_p++ = 'l';
- *fmt_p++ = 'x';
- *fmt_p++ = '\0';
- fprintf_filtered (stream, fmt, val);
- }
- else
- {
- *fmt_p++ = 's';
- *fmt_p++ = '\0';
- fprintf_filtered (stream, fmt, "(nil)");
- }
-
- break;
- }
+ printf_pointer (stream, current_substring, val_args[i]);
+ 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.
- 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, last_arg, 0);
}
do_cleanups (old_cleanups);
}
printf_command (char *arg, int from_tty)
{
ui_printf (arg, gdb_stdout);
+ gdb_flush (gdb_stdout);
}
/* Implement the "eval" command. */
current_display_number = -1;
- observer_attach_solib_unloaded (clear_dangling_display_expressions);
+ observer_attach_free_objfile (clear_dangling_display_expressions);
add_info ("address", address_info,
_("Describe where symbol SYM is stored."));
ADDRESS is an expression for the memory address to examine.\n\
FMT is a repeat count followed by a format letter and a size letter.\n\
Format letters are o(octal), x(hex), d(decimal), u(unsigned decimal),\n\
- t(binary), f(float), a(address), i(instruction), c(char) and s(string).\n\
+ t(binary), f(float), a(address), i(instruction), c(char), s(string)\n\
+ and z(hex, zero padded on the left).\n\
Size letters are b(byte), h(halfword), w(word), g(giant, 8 bytes).\n\
The specified number of objects of the specified size are printed\n\
according to the format.\n\n\
but no count or size letter (see \"x\" command)."));
set_cmd_completer (c, expression_completer);
add_com_alias ("p", "print", class_vars, 1);
-
- c = add_com ("inspect", class_vars, inspect_command, _("\
-Same as \"print\" command, except that if you are running in the epoch\n\
-environment, the value is printed in its own window."));
- set_cmd_completer (c, expression_completer);
+ add_com_alias ("inspect", "print", class_vars, 1);
add_setshow_uinteger_cmd ("max-symbolic-offset", no_class,
&max_symbolic_offset, _("\
Set the largest offset that will be printed in <symbol+1234> form."), _("\
-Show the largest offset that will be printed in <symbol+1234> form."), NULL,
+Show the largest offset that will be printed in <symbol+1234> form."), _("\
+Tell GDB to only display the symbolic form of an address if the\n\
+offset between the closest earlier symbol and the address is less than\n\
+the specified maximum offset. The default is \"unlimited\", which tells GDB\n\
+to always print the symbolic form of an address if any symbol precedes\n\
+it. Zero is equivalent to \"unlimited\"."),
NULL,
show_max_symbolic_offset,
&setprintlist, &showprintlist);