diff options
author | Daniel Jacobowitz <drow@false.org> | 2006-02-02 02:26:48 +0000 |
---|---|---|
committer | Daniel Jacobowitz <drow@false.org> | 2006-02-02 02:26:48 +0000 |
commit | 46e9880c625972c3a9ac7c0b53bc1a30c2989b7c (patch) | |
tree | da4dba64cb6e03010ca03d7e31029700d0f9ff35 /gdb/printcmd.c | |
parent | 37a105a123de409e6d33eacc1030d1bebe5b1637 (diff) | |
download | gdb-46e9880c625972c3a9ac7c0b53bc1a30c2989b7c.zip gdb-46e9880c625972c3a9ac7c0b53bc1a30c2989b7c.tar.gz gdb-46e9880c625972c3a9ac7c0b53bc1a30c2989b7c.tar.bz2 |
* printcmd.c (printf_command): Make format string checking
stricter. Add separate cases for long_arg, ptr_arg, and
long_double_arg.
* utils.c (xstrvprintf): Improve the error message issued
for a bad format string.
* Makefile.in (GDB_WARN_CFLAGS_NO_FORMAT, INTERNAL_CFLAGS_BASE):
New variables.
(gnu-v3-abi.o, monitor.o, procfs.o, linux-thread-db.o): Remove
$(NO_WERROR_CFLAGS).
(printcmd.o): Likewise. Use $(GDB_WARN_CFLAGS_NO_FORMAT) and
enable -Werror.
Diffstat (limited to 'gdb/printcmd.c')
-rw-r--r-- | gdb/printcmd.c | 173 |
1 files changed, 149 insertions, 24 deletions
diff --git a/gdb/printcmd.c b/gdb/printcmd.c index b6f3a7d..962c269 100644 --- a/gdb/printcmd.c +++ b/gdb/printcmd.c @@ -1836,13 +1836,13 @@ printf_command (char *arg, int from_tty) enum argclass { - no_arg, int_arg, string_arg, double_arg, long_long_arg + int_arg, long_arg, long_long_arg, ptr_arg, string_arg, + double_arg, long_double_arg }; enum argclass *argclass; enum argclass this_argclass; char *last_arg; int nargs_wanted; - int lcount; int i; argclass = (enum argclass *) alloca (strlen (s) * sizeof *argclass); @@ -1852,23 +1852,136 @@ printf_command (char *arg, int from_tty) while (*f) if (*f++ == '%') { - lcount = 0; - while (strchr ("0123456789.hlL-+ #", *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; + 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 == '%') { - if (*f == 'l' || *f == 'L') - lcount++; 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++; + } + 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 = int_arg; + if (lcount || 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 = string_arg; + if (lcount || seen_h || seen_big_l) + bad = 1; + if (seen_zero || seen_space || seen_plus) + bad = 1; break; case 'e': case 'f': case 'g': - this_argclass = double_arg; + case 'E': + case 'G': + if (seen_big_l) + this_argclass = long_double_arg; + else + this_argclass = double_arg; + + if (lcount || seen_h) + bad = 1; break; case '*': @@ -1877,26 +1990,23 @@ printf_command (char *arg, int from_tty) case 'n': error (_("Format specifier `n' not supported in printf")); - case '%': - this_argclass = no_arg; - break; + case '\0': + error (_("Incomplete format specifier at end of format string")); default: - if (lcount > 1) - this_argclass = long_long_arg; - else - this_argclass = int_arg; - break; + error (_("Unrecognized format specifier '%c' in printf"), *f); } + + if (bad) + error (_("Inappropriate modifiers to format specifier '%c' in printf"), + *f); + f++; - if (this_argclass != no_arg) - { - strncpy (current_substring, last_arg, f - last_arg); - current_substring += f - last_arg; - *current_substring++ = '\0'; - last_arg = f; - argclass[nargs_wanted++] = this_argclass; - } + strncpy (current_substring, last_arg, f - last_arg); + current_substring += f - last_arg; + *current_substring++ = '\0'; + last_arg = f; + argclass[nargs_wanted++] = this_argclass; } /* Now, parse all arguments and evaluate them. @@ -1970,6 +2080,16 @@ printf_command (char *arg, int from_tty) printf_filtered (current_substring, val); break; } + case long_double_arg: +#ifdef HAVE_LONG_DOUBLE + { + long double val = value_as_double (val_args[i]); + printf_filtered (current_substring, val); + break; + } +#else + error (_("long double not supported in printf")); +#endif case long_long_arg: #if defined (CC_HAS_LONG_LONG) && defined (PRINTF_HAS_LONG_LONG) { @@ -1982,7 +2102,12 @@ printf_command (char *arg, int from_tty) #endif case int_arg: { - /* FIXME: there should be separate int_arg and long_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; |