diff options
author | Stan Shebs <shebs@codesourcery.com> | 2012-07-02 15:29:39 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 2012-07-02 15:29:39 +0000 |
commit | d3ce09f5bf7a7e8f97c3f1c9888e886ee267c2f2 (patch) | |
tree | 782811ca1df7a4f775823d1918d0b571fdac9b5a /gdb/printcmd.c | |
parent | a47edf2745dd6414d635e4b372d416035c7b8c12 (diff) | |
download | gdb-d3ce09f5bf7a7e8f97c3f1c9888e886ee267c2f2.zip gdb-d3ce09f5bf7a7e8f97c3f1c9888e886ee267c2f2.tar.gz gdb-d3ce09f5bf7a7e8f97c3f1c9888e886ee267c2f2.tar.bz2 |
Add target-side support for dynamic printf.
* NEWS: Mention the additional style.
* breakpoint.h (struct bp_target_info): New fields tcommands, persist.
(struct bp_location): New field cmd_bytecode.
* breakpoint.c: Include format.h.
(disconnected_dprintf): New global.
(parse_cmd_to_aexpr): New function.
(build_target_command_list): New function.
(insert_bp_location): Call it.
(remove_breakpoints_pid): Skip dprintf breakpoints.
(print_one_breakpoint_location): Ditto.
(dprintf_style_agent): New global.
(dprintf_style_enums): Add dprintf_style_agent.
(update_dprintf_command_list): Add agent case.
(agent_printf_command): New function.
(_initialize_breakpoint): Add new commands.
* common/ax.def (printf): New bytecode.
* ax.h (ax_string): Declare.
* ax-gdb.h (gen_printf): Declare.
* ax-gdb.c: Include cli-utils.h, format.h.
(gen_printf): New function.
(maint_agent_print_command): New function.
(_initialize_ax_gdb): Add maint agent-printf command.
* ax-general.c (ax_string): New function.
(ax_print): Add printf disassembly.
* Makefile.in (SFILES): Add format.c
(COMMON_OBS): Add format.o.
* common/format.h: New file.
* common/format.c: New file.
* printcmd.c: Include format.h.
(ui_printf): Call parse_format_string.
* remote.c (remote_state): New field breakpoint_commands.
(PACKET_BreakpointCommands): New enum.
(remote_breakpoint_commands_feature): New function.
(remote_protocol_features): Add new BreakpointCommands entry.
(remote_can_run_breakpoint_commands): New function.
(remote_add_target_side_commands): New function.
(remote_insert_breakpoint): Call it.
(remote_insert_hw_breakpoint): Ditto.
(_initialize_remote): Add new packet configuration for
target-side breakpoint commands.
* target.h (struct target_ops): New field
to_can_run_breakpoint_commands.
(target_can_run_breakpoint_commands): New macro.
* target.c (update_current_target): Handle
to_can_run_breakpoint_commands.
[gdbserver]
* Makefile.in (WARN_CFLAGS_NO_FORMAT): Define.
(ax.o): Add it to build rule.
(ax-ipa.o): Ditto.
(OBS): Add format.o.
(IPA_OBS): Add format.o.
* server.c (handle_query): Claim support for breakpoint commands.
(process_point_options): Add command case.
(process_serial_event): Leave running if there are printfs in
effect.
* mem-break.h (any_persistent_commands): Declare.
(add_breakpoint_commands): Declare.
(gdb_no_commands_at_breakpoint): Declare.
(run_breakpoint_commands): Declare.
* mem-break.c (struct point_command_list): New struct.
(struct breakpoint): New field command_list.
(any_persistent_commands): New function.
(add_commands_to_breakpoint): New function.
(add_breakpoint_commands): New function.
(gdb_no_commands_at_breakpoint): New function.
(run_breakpoint_commands): New function.
* linux-low.c (linux_wait_1): Test for and run breakpoint commands
locally.
* ax.c: Include format.h.
(ax_printf): New function.
(gdb_eval_agent_expr): Add printf opcode.
[doc]
* gdb.texinfo (Dynamic Printf): Mention agent style and
disconnected dprintf.
(Maintenance Commands): Describe maint agent-printf.
(General Query Packets): Mention BreakpointCommands feature.
(Packets): Document commands extension to Z0 packet.
* agentexpr.texi (Bytecode Descriptions): Document printf
bytecode.
[testsuite]
* gdb.base/dprintf.exp: Add agent style tests.
Diffstat (limited to 'gdb/printcmd.c')
-rw-r--r-- | gdb/printcmd.c | 341 |
1 files changed, 31 insertions, 310 deletions
diff --git a/gdb/printcmd.c b/gdb/printcmd.c index 030a4f2..2a0a886 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; @@ -2001,13 +1995,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; @@ -2023,64 +2013,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 '\"'.")); + 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; - - 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) @@ -2090,240 +2029,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. */ @@ -2349,10 +2064,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: { @@ -2687,20 +2403,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); } |