| Index: gdb/printcmd.c
|
| diff --git a/gdb/printcmd.c b/gdb/printcmd.c
|
| index bee8a85090439e9738d78e5db98a49cac24e6d17..d5b5b63122a7d99f7c53e8cf187544eb3927aee0 100644
|
| --- a/gdb/printcmd.c
|
| +++ b/gdb/printcmd.c
|
| @@ -49,18 +49,12 @@
|
| #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. */
|
| #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;
|
| @@ -568,9 +562,10 @@ set_next_address (struct gdbarch *gdbarch, CORE_ADDR addr)
|
| 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
|
| +int
|
| print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
| struct ui_file *stream,
|
| int do_demangle, char *leadin)
|
| @@ -589,7 +584,7 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
| &filename, &line, &unmapped))
|
| {
|
| do_cleanups (cleanup_chain);
|
| - return;
|
| + return 0;
|
| }
|
|
|
| fputs_filtered (leadin, stream);
|
| @@ -616,6 +611,7 @@ print_address_symbolic (struct gdbarch *gdbarch, CORE_ADDR addr,
|
| fputs_filtered (">", stream);
|
|
|
| do_cleanups (cleanup_chain);
|
| + return 1;
|
| }
|
|
|
| /* Given an address ADDR return all the elements needed to print the
|
| @@ -638,7 +634,7 @@ build_address_symbolic (struct gdbarch *gdbarch,
|
| 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;
|
| @@ -683,6 +679,13 @@ build_address_symbolic (struct gdbarch *gdbarch,
|
| 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 != NULL)
|
| {
|
| if (SYMBOL_VALUE_ADDRESS (msymbol) > name_location || symbol == NULL)
|
| @@ -763,29 +766,23 @@ pc_prefix (CORE_ADDR addr)
|
|
|
| /* 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 non-zero if anything was printed; zero otherwise. */
|
|
|
| -void
|
| -print_address_demangle (struct gdbarch *gdbarch, CORE_ADDR addr,
|
| +int
|
| +print_address_demangle (const struct value_print_options *opts,
|
| + 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)
|
| - {
|
| - fprintf_filtered (stream, "0");
|
| - }
|
| - else if (opts.addressprint)
|
| + if (opts->addressprint)
|
| {
|
| fputs_filtered (paddress (gdbarch, addr), stream);
|
| print_address_symbolic (gdbarch, addr, stream, do_demangle, " ");
|
| }
|
| else
|
| {
|
| - print_address_symbolic (gdbarch, addr, stream, do_demangle, "");
|
| + return print_address_symbolic (gdbarch, addr, stream, do_demangle, "");
|
| }
|
| + return 1;
|
| }
|
|
|
|
|
| @@ -1080,6 +1077,22 @@ set_command (char *exp, int from_tty)
|
| 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);
|
| }
|
| @@ -1594,7 +1607,6 @@ map_display_numbers (char *args,
|
| void *data)
|
| {
|
| struct get_number_or_range_state state;
|
| - struct display *b, *tmp;
|
| int num;
|
|
|
| if (args == NULL)
|
| @@ -1637,9 +1649,6 @@ do_delete_display (struct display *d, void *data)
|
| static void
|
| undisplay_command (char *args, int from_tty)
|
| {
|
| - int num;
|
| - struct get_number_or_range_state state;
|
| -
|
| if (args == NULL)
|
| {
|
| if (query (_("Delete all auto-display expressions? ")))
|
| @@ -1952,7 +1961,9 @@ clear_dangling_display_expressions (struct so_list *solib)
|
| 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,
|
| @@ -1974,6 +1985,10 @@ print_variable_and_value (const char *name, struct symbol *var,
|
| 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,
|
| @@ -1986,13 +2001,9 @@ print_variable_and_value (const char *name, struct symbol *var,
|
| static void
|
| 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;
|
|
|
| @@ -2008,64 +2019,13 @@ ui_printf (char *arg, struct ui_file *stream)
|
| 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 '\"'."));
|
| -
|
| - 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;
|
| + fpieces = parse_format_string (&s);
|
|
|
| - default:
|
| - *f++ = c;
|
| - }
|
| - }
|
| + make_cleanup (free_format_pieces_cleanup, &fpieces);
|
|
|
| - /* Skip over " and following space and comma. */
|
| - s++;
|
| - *f++ = '\0';
|
| + if (*s++ != '"')
|
| + error (_("Bad format string, non-terminated '\"'."));
|
| +
|
| s = skip_spaces (s);
|
|
|
| if (*s != ',' && *s != 0)
|
| @@ -2075,240 +2035,16 @@ ui_printf (char *arg, struct ui_file *stream)
|
| s++;
|
| s = skip_spaces (s);
|
|
|
| - /* Need extra space for the '\0's. Doubling the size is sufficient. */
|
| - substrings = alloca (strlen (string) * 2);
|
| - current_substring = substrings;
|
| -
|
| {
|
| - /* 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. */
|
| @@ -2334,10 +2070,11 @@ ui_printf (char *arg, struct ui_file *stream)
|
| 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:
|
| {
|
| @@ -2672,20 +2409,25 @@ ui_printf (char *arg, struct ui_file *stream)
|
|
|
| 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);
|
| }
|
|
|