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.
+ 2008, 2009, 2010 Free Software Foundation, Inc.
This file is part of GDB.
#include "exceptions.h"
#include "observer.h"
#include "solist.h"
-#include "solib.h"
#include "parser-defs.h"
#include "charset.h"
+#include "arch-utils.h"
#ifdef TUI
#include "tui/tui.h" /* For tui_active et.al. */
{
/* 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;
+
+ /* 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) */
int enabled_p;
};
/* 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;
case 's':
{
struct type *elttype = value_type (val);
+
next_address = (value_address (val)
+ val_print_string (elttype,
value_address (val), -1,
- stream, options));
+ stream, options) * len);
}
return;
/* We often wrap here if there are long symbolic names. */
wrap_here (" ");
next_address = (value_address (val)
- + gdb_print_insn (value_address (val), stream,
+ + gdb_print_insn (get_type_arch (type),
+ value_address (val), stream,
&branch_delay_insns));
return;
}
/* 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);
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
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
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;
settings of the demangle and asm_demangle variables. */
void
-print_address_symbolic (CORE_ADDR addr, struct ui_file *stream,
+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);
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 */
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);
<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, " ");
+}
+
+/* Return a prefix for instruction address:
+ "=> " for current instruction, else " ". */
+
+const char *
+pc_prefix (CORE_ADDR addr)
+{
+ if (has_stack_frames ())
+ {
+ struct frame_info *frame;
+ CORE_ADDR pc;
+
+ frame = get_selected_frame (NULL);
+ pc = get_frame_pc (frame);
+
+ if (pc == addr)
+ return "=> ";
+ }
+ return " ";
}
/* Print address ADDR symbolically on STREAM. Parameter DEMANGLE
or not. */
void
-print_address_demangle (CORE_ADDR addr, struct ui_file *stream,
- int do_demangle)
+print_address_demangle (struct gdbarch *gdbarch, CORE_ADDR addr,
+ struct ui_file *stream, int do_demangle)
{
struct value_print_options opts;
+
get_user_print_options (&opts);
if (addr == 0)
{
}
else 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, "");
+ print_address_symbolic (gdbarch, addr, stream, do_demangle, "");
}
}
\f
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 (size == 'a')
}
if (size == 'b')
- val_type = builtin_type_int8;
+ val_type = builtin_type (next_gdbarch)->builtin_int8;
else if (size == 'h')
- val_type = builtin_type_int16;
+ val_type = builtin_type (next_gdbarch)->builtin_int16;
else if (size == 'w')
- val_type = builtin_type_int32;
+ val_type = builtin_type (next_gdbarch)->builtin_int32;
else if (size == 'g')
- val_type = builtin_type_int64;
+ 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;
if (exp && *exp)
{
- struct type *type;
expr = parse_expression (exp);
old_chain = make_cleanup (free_current_contents, &expr);
cleanup = 1;
struct expression *expr = parse_expression (exp);
struct cleanup *old_chain =
make_cleanup (free_current_contents, &expr);
+
evaluate_expression (expr);
do_cleanups (old_chain);
}
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 == 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);
}
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);
}
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, gdb_stdout);
+ SYMBOL_COMPUTED_OPS (sym)->describe_location (sym, context_pc, gdb_stdout);
break;
case LOC_REGISTER:
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);
}
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);
}
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' && */
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. */
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;
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 1 if D uses SOLIB (and will become dangling when SOLIB
- is unloaded), otherwise return 0. */
-
-static int
-display_uses_solib_p (const struct display *d,
- const struct so_list *solib)
-{
- 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;
-
- if (section && section->objfile == solib->objfile)
- return 1;
- }
- endpos -= oplen;
- }
-
- return 0;
-}
-
/* display_chain items point to blocks and expressions. Some expressions in
turn may point to symbols.
Both symbols and blocks are obstack_alloc'd on objfile_stack, and are
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
/* 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] =
{
/* 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;
while (*s != '\0')
{
char *s1;
+
if (nargs == allocated_args)
val_args = (struct value **) xrealloc ((char *) val_args,
(allocated_args *= 2)
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)
gdb_byte *str;
CORE_ADDR tem;
int j;
- struct type *wctype = lookup_typename (current_language,
- current_gdbarch,
+ 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);
{
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);
break;
case wide_char_arg:
{
- struct type *wctype = lookup_typename (current_language,
- current_gdbarch,
+ 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;
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),
/* 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."));
/* 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."));
#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);
break;
}
case int_arg:
{
int val = value_as_long (val_args[i]);
+
printf_filtered (current_substring, val);
break;
}
case long_arg:
{
long val = value_as_long (val_args[i]);
+
printf_filtered (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. */
/* 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, 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, "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);
while (*p)
{
int is_percent = (*p == '%');
+
*fmt_p++ = *p++;
if (is_percent)
{
/* Skip to the next substring. */
current_substring += strlen (current_substring) + 1;
}
- /* Print the portion of the format string after the last argument. */
- puts_filtered (last_arg);
+ /* 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. */
+ printf_filtered (last_arg, 0);
}
do_cleanups (old_cleanups);
}