From e7e0cddfb0d4c4823cc7ed48c727e12f0e11a600 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Mon, 14 May 2012 15:38:41 +0000 Subject: [PATCH] 2012-05-14 Stan Shebs Add dynamic printf. * breakpoint.h (enum bptype): New type bp_dprintf. (struct breakpoint): New field extra_string. (struct breakpoint_ops): Add arg to create_breakpoints_sal. (create_breakpoint): Add extra_string arg. * breakpoint.c (dprintf_breakpoint_ops): New. (is_breakpoint): Add bp_dprintf. (bpstat_what): Add dprintf case. (bptype_string): Ditto. (print_one_breakpoint_location): Ditto. (init_bp_location): Ditto. (bkpt_print_mention): Ditto. (dprintf_style_enums): New array. (dprintf_style): New global. (dprintf_function): New global. (dprintf_channel): New global. (update_dprintf_command_list): New function. (update_dprintf_commands): New function. (init_breakpoint_sal): Add extra_string argument, handle it. (create_breakpoint_sal): Add extra_string argument. (create_breakpoints_sal): Add extra_string argument, update callers. (find_condition_and_thread): Add extra argument. (create_breakpoint): Add extra_string argument, record it. (dprintf_command): New function. (break_command_1): Add arg to create_breakpoint call. (handle_gnu_v3_exceptions): Ditto. (trace_command): Ditto. (ftrace_command): Ditto. (strace_command): Ditto. (bkpt_print_mention): Add dprintf case. (create_breakpoint_sal_default): Add extra_string argument. (_initialize_breakpoint): Add new commands. * mi/mi-cmd-break.c (mi_cmd_break_insert): Add arg to call. * python/py-breakpoint.c (bppy_init): Ditto. * python/py-finishbreakpoint.c (bpfinishpy_init): Ditto. * gdb.texinfo (Dynamic Printf): New subsection. * gdb.base/dprintf.c: New file. * gdb.base/dprintf.exp: New file. --- gdb/ChangeLog | 38 ++++ gdb/NEWS | 18 ++ gdb/breakpoint.c | 295 +++++++++++++++++++++++++++-- gdb/breakpoint.h | 14 +- gdb/doc/ChangeLog | 4 + gdb/doc/gdb.texinfo | 84 ++++++++ gdb/mi/mi-cmd-break.c | 1 + gdb/python/py-breakpoint.c | 2 +- gdb/python/py-finishbreakpoint.c | 2 +- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.base/dprintf.c | 44 +++++ gdb/testsuite/gdb.base/dprintf.exp | 89 +++++++++ 12 files changed, 572 insertions(+), 24 deletions(-) create mode 100644 gdb/testsuite/gdb.base/dprintf.c create mode 100644 gdb/testsuite/gdb.base/dprintf.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2c31c3d61f..04ea09f96b 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,41 @@ +2012-05-14 Stan Shebs + + Add dynamic printf. + * breakpoint.h (enum bptype): New type bp_dprintf. + (struct breakpoint): New field extra_string. + (struct breakpoint_ops): Add arg to create_breakpoints_sal. + (create_breakpoint): Add extra_string arg. + * breakpoint.c (dprintf_breakpoint_ops): New. + (is_breakpoint): Add bp_dprintf. + (bpstat_what): Add dprintf case. + (bptype_string): Ditto. + (print_one_breakpoint_location): Ditto. + (init_bp_location): Ditto. + (bkpt_print_mention): Ditto. + (dprintf_style_enums): New array. + (dprintf_style): New global. + (dprintf_function): New global. + (dprintf_channel): New global. + (update_dprintf_command_list): New function. + (update_dprintf_commands): New function. + (init_breakpoint_sal): Add extra_string argument, handle it. + (create_breakpoint_sal): Add extra_string argument. + (create_breakpoints_sal): Add extra_string argument, update callers. + (find_condition_and_thread): Add extra argument. + (create_breakpoint): Add extra_string argument, record it. + (dprintf_command): New function. + (break_command_1): Add arg to create_breakpoint call. + (handle_gnu_v3_exceptions): Ditto. + (trace_command): Ditto. + (ftrace_command): Ditto. + (strace_command): Ditto. + (bkpt_print_mention): Add dprintf case. + (create_breakpoint_sal_default): Add extra_string argument. + (_initialize_breakpoint): Add new commands. + * mi/mi-cmd-break.c (mi_cmd_break_insert): Add arg to call. + * python/py-breakpoint.c (bppy_init): Ditto. + * python/py-finishbreakpoint.c (bpfinishpy_init): Ditto. + 2012-05-14 Maciej W. Rozycki * mips-tdep.c (mips_push_dummy_code): Correct description typo. diff --git a/gdb/NEWS b/gdb/NEWS index dd1ab24043..4ddd990d78 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -142,6 +142,11 @@ "info auto-load python-scripts", "set auto-load python-scripts on|off" and "show auto-load python-scripts" counterparts instead. + ** "dprintf location,format,args..." creates a dynamic printf, which + is basically a breakpoint that does a printf and immediately + resumes your program's execution, so it is like a printf that you + can insert dynamically at runtime instead of at compiletime. + * New targets Renesas RL78 rl78-*-elf @@ -200,6 +205,19 @@ set debug auto-load on|off show debug auto-load Control display of debugging info for auto-loading the files above. +set dprintf-style gdb|call +show dprintf-style + Control the way in which a dynamic printf is performed; "gdb" requests + a GDB printf command, while "call" causes dprintf to call a function + in the inferior. + +set dprintf-function +show dprintf-function +set dprintf-channel +show dprintf-channel + Set the function and optional first argument to the call when using + the "call" style of dynamic printf. + * New configure options --with-auto-load-dir diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index ab5f3240fb..b060e74d52 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -109,7 +109,7 @@ static void create_sals_from_address_default (char **, static void create_breakpoints_sal_default (struct gdbarch *, struct linespec_result *, struct linespec_sals *, - char *, enum bptype, + char *, char *, enum bptype, enum bpdisp, int, int, int, const struct breakpoint_ops *, @@ -294,6 +294,9 @@ struct breakpoint_ops bkpt_breakpoint_ops; /* Breakpoints set on probes. */ static struct breakpoint_ops bkpt_probe_breakpoint_ops; +/* Dynamic printf class type. */ +static struct breakpoint_ops dprintf_breakpoint_ops; + /* A reference-counted struct command_line. This lets multiple breakpoints share a single command list. */ struct counted_command_line @@ -1494,7 +1497,8 @@ int is_breakpoint (const struct breakpoint *bpt) { return (bpt->type == bp_breakpoint - || bpt->type == bp_hardware_breakpoint); + || bpt->type == bp_hardware_breakpoint + || bpt->type == bp_dprintf); } /* Return true if BPT is of any hardware watchpoint kind. */ @@ -5178,6 +5182,11 @@ bpstat_what (bpstat bs_head) PC of the former breakpoint. */ this_action = BPSTAT_WHAT_KEEP_CHECKING; break; + + case bp_dprintf: + this_action = BPSTAT_WHAT_STOP_SILENT; + break; + default: internal_error (__FILE__, __LINE__, _("bpstat_what: unhandled bptype %d"), (int) bptype); @@ -5442,6 +5451,7 @@ bptype_string (enum bptype type) {bp_tracepoint, "tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"}, {bp_static_tracepoint, "static tracepoint"}, + {bp_dprintf, "dprintf"}, {bp_jit_event, "jit events"}, {bp_gnu_ifunc_resolver, "STT_GNU_IFUNC resolver"}, {bp_gnu_ifunc_resolver_return, "STT_GNU_IFUNC resolver return"}, @@ -5582,6 +5592,7 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_tracepoint: case bp_fast_tracepoint: case bp_static_tracepoint: + case bp_dprintf: case bp_jit_event: case bp_gnu_ifunc_resolver: case bp_gnu_ifunc_resolver_return: @@ -6444,6 +6455,7 @@ init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops, case bp_exception_master: case bp_gnu_ifunc_resolver: case bp_gnu_ifunc_resolver_return: + case bp_dprintf: loc->loc_type = bp_loc_software_breakpoint; mark_breakpoint_location_modified (loc); break; @@ -8382,7 +8394,122 @@ bp_loc_is_permanent (struct bp_location *loc) return retval; } +/* The style in which to perform a dynamic printf. This is a user + option because different output options have different tradeoffs; + if GDB does the printing, there is better error handling if there + is a problem with any of the arguments, but using an inferior + function lets you have special-purpose printers and sending of + output to the same place as compiled-in print functions. (Future + styles may include the ability to do a target-side printf.) */ +static const char dprintf_style_gdb[] = "gdb"; +static const char dprintf_style_call[] = "call"; +static const char *const dprintf_style_enums[] = { + dprintf_style_gdb, + dprintf_style_call, + NULL +}; +static const char *dprintf_style = dprintf_style_gdb; + +/* The function to use for dynamic printf if the preferred style is to + call into the inferior. The value is simply a string that is + copied into the command, so it can be anything that GDB can + evaluate to a callable address, not necessarily a function name. */ + +static char *dprintf_function = ""; + +/* The channel to use for dynamic printf if the preferred style is to + call into the inferior; if a nonempty string, it will be passed to + the call as the first argument, with the format string as the + second. As with the dprintf function, this can be anything that + GDB knows how to evaluate, so in addition to common choices like + "stderr", this could be an app-specific expression like + "mystreams[curlogger]". */ + +static char *dprintf_channel = ""; + +/* Build a command list for the dprintf corresponding to the current + settings of the dprintf style options. */ + +static void +update_dprintf_command_list (struct breakpoint *b) +{ + char *dprintf_args = b->extra_string; + char *printf_line = NULL; + + if (!dprintf_args) + return; + + dprintf_args = skip_spaces (dprintf_args); + + /* Allow a comma, as it may have terminated a location, but don't + insist on it. */ + if (*dprintf_args == ',') + ++dprintf_args; + dprintf_args = skip_spaces (dprintf_args); + + if (*dprintf_args != '"') + error (_("Bad format string, missing '\"'.")); + + if (strcmp (dprintf_style, "gdb") == 0) + printf_line = xstrprintf ("printf %s", dprintf_args); + else if (strcmp (dprintf_style, "call") == 0) + { + if (!dprintf_function) + error (_("No function supplied for dprintf call")); + + if (dprintf_channel && strlen (dprintf_channel) > 0) + printf_line = xstrprintf ("call (void) %s (%s,%s)", + dprintf_function, + dprintf_channel, + dprintf_args); + else + printf_line = xstrprintf ("call (void) %s (%s)", + dprintf_function, + dprintf_args); + } + else + internal_error (__FILE__, __LINE__, + _("Invalid dprintf style.")); + + /* Manufacture a printf/continue sequence. */ + if (printf_line) + { + struct command_line *printf_cmd_line, *cont_cmd_line = NULL; + + cont_cmd_line = xmalloc (sizeof (struct command_line)); + cont_cmd_line->control_type = simple_control; + cont_cmd_line->body_count = 0; + cont_cmd_line->body_list = NULL; + cont_cmd_line->next = NULL; + cont_cmd_line->line = xstrdup ("continue"); + + printf_cmd_line = xmalloc (sizeof (struct command_line)); + printf_cmd_line->control_type = simple_control; + printf_cmd_line->body_count = 0; + printf_cmd_line->body_list = NULL; + printf_cmd_line->next = cont_cmd_line; + printf_cmd_line->line = printf_line; + + breakpoint_set_commands (b, printf_cmd_line); + } +} + +/* Update all dprintf commands, making their command lists reflect + current style settings. */ + +static void +update_dprintf_commands (char *args, int from_tty, + struct cmd_list_element *c) +{ + struct breakpoint *b; + + ALL_BREAKPOINTS (b) + { + if (b->type == bp_dprintf) + update_dprintf_command_list (b); + } +} /* Create a breakpoint with SAL as location. Use ADDR_STRING as textual description of the location, and COND_STRING @@ -8392,6 +8519,7 @@ static void init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, struct symtabs_and_lines sals, char *addr_string, char *filter, char *cond_string, + char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, @@ -8438,6 +8566,7 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, b->task = task; b->cond_string = cond_string; + b->extra_string = extra_string; b->ignore_count = ignore_count; b->enable_state = enabled ? bp_enabled : bp_disabled; b->disposition = disposition; @@ -8502,6 +8631,18 @@ init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch, if (*arg) error (_("Garbage %s follows condition"), arg); } + + /* Dynamic printf requires and uses additional arguments on the + command line, otherwise it's an error. */ + if (type == bp_dprintf) + { + if (b->extra_string) + update_dprintf_command_list (b); + else + error (_("Format string required")); + } + else if (b->extra_string) + error (_("Garbage %s at end of command"), b->extra_string); } b->display_canonical = display_canonical; @@ -8519,6 +8660,7 @@ static void create_breakpoint_sal (struct gdbarch *gdbarch, struct symtabs_and_lines sals, char *addr_string, char *filter, char *cond_string, + char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, @@ -8542,7 +8684,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, init_breakpoint_sal (b, gdbarch, sals, addr_string, - filter, cond_string, + filter, cond_string, extra_string, type, disposition, thread, task, ignore_count, ops, from_tty, @@ -8571,7 +8713,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch, static void create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *canonical, - char *cond_string, + char *cond_string, char *extra_string, enum bptype type, enum bpdisp disposition, int thread, int task, int ignore_count, const struct breakpoint_ops *ops, int from_tty, @@ -8597,7 +8739,8 @@ create_breakpoints_sal (struct gdbarch *gdbarch, create_breakpoint_sal (gdbarch, lsal->sals, addr_string, filter_string, - cond_string, type, disposition, + cond_string, extra_string, + type, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags, canonical->special_display); @@ -8734,7 +8877,8 @@ check_fast_tracepoint_sals (struct gdbarch *gdbarch, If no thread is found, *THREAD is set to -1. */ static void find_condition_and_thread (char *tok, CORE_ADDR pc, - char **cond_string, int *thread, int *task) + char **cond_string, int *thread, int *task, + char **rest) { *cond_string = NULL; *thread = -1; @@ -8746,7 +8890,13 @@ find_condition_and_thread (char *tok, CORE_ADDR pc, char *cond_end = NULL; tok = skip_spaces (tok); - + + if ((*tok == '"' || *tok == ',') && rest) + { + *rest = savestring (tok, strlen (tok)); + return; + } + end_tok = skip_to_space (tok); toklen = end_tok - tok; @@ -8786,6 +8936,11 @@ find_condition_and_thread (char *tok, CORE_ADDR pc, if (!valid_task_id (*task)) error (_("Unknown task %d."), *task); } + else if (rest) + { + *rest = savestring (tok, strlen (tok)); + tok += toklen; + } else error (_("Junk at end of arguments.")); } @@ -8853,7 +9008,8 @@ decode_static_tracepoint_spec (char **arg_p) int create_breakpoint (struct gdbarch *gdbarch, - char *arg, char *cond_string, int thread, + char *arg, char *cond_string, + int thread, char *extra_string, int parse_condition_and_thread, int tempflag, enum bptype type_wanted, int ignore_count, @@ -8975,16 +9131,22 @@ create_breakpoint (struct gdbarch *gdbarch, if (parse_condition_and_thread) { + char *rest; /* Here we only parse 'arg' to separate condition from thread number, so parsing in context of first sal is OK. When setting the breakpoint we'll re-parse it in context of each sal. */ cond_string = NULL; thread = -1; + rest = NULL; find_condition_and_thread (arg, lsal->sals.sals[0].pc, &cond_string, - &thread, &task); + &thread, &task, &rest); if (cond_string) make_cleanup (xfree, cond_string); + if (rest) + make_cleanup (xfree, rest); + if (rest) + extra_string = rest; } else { @@ -8994,10 +9156,16 @@ create_breakpoint (struct gdbarch *gdbarch, cond_string = xstrdup (cond_string); make_cleanup (xfree, cond_string); } + /* Create a private copy of any extra string. */ + if (extra_string) + { + extra_string = xstrdup (extra_string); + make_cleanup (xfree, extra_string); + } } ops->create_breakpoints_sal (gdbarch, &canonical, lsal, - cond_string, type_wanted, + cond_string, extra_string, type_wanted, tempflag ? disp_del : disp_donttouch, thread, task, ignore_count, ops, from_tty, enabled, internal, flags); @@ -9022,6 +9190,7 @@ create_breakpoint (struct gdbarch *gdbarch, b->addr_string = copy_arg; b->cond_string = NULL; + b->extra_string = NULL; b->ignore_count = ignore_count; b->disposition = tempflag ? disp_del : disp_donttouch; b->condition_not_parsed = 1; @@ -9077,7 +9246,7 @@ break_command_1 (char *arg, int flag, int from_tty) create_breakpoint (get_current_arch (), arg, - NULL, 0, 1 /* parse arg */, + NULL, 0, NULL, 1 /* parse arg */, tempflag, type_wanted, 0 /* Ignore count */, pending_break_support, @@ -9242,6 +9411,29 @@ stopat_command (char *arg, int from_tty) break_command_1 (arg, 0, from_tty); } +void dprintf_command (char *arg, int from_tty); + +/* The dynamic printf command is mostly like a regular breakpoint, but + with a prewired command list consisting of a single output command, + built from extra arguments supplied on the dprintf command + line. */ + +void +dprintf_command (char *arg, int from_tty) +{ + create_breakpoint (get_current_arch (), + arg, + NULL, 0, NULL, 1 /* parse arg */, + 0, bp_dprintf, + 0 /* Ignore count */, + pending_break_support, + &dprintf_breakpoint_ops, + from_tty, + 1 /* enabled */, + 0 /* internal */, + 0); +} + /* Implement the "breakpoint_hit" breakpoint_ops method for ranged breakpoints. */ @@ -10953,7 +11145,7 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string, trigger_func_name = "__cxa_throw"; create_breakpoint (get_current_arch (), - trigger_func_name, cond_string, -1, + trigger_func_name, cond_string, -1, NULL, 0 /* condition and thread are valid. */, tempflag, bp_breakpoint, 0, @@ -12182,6 +12374,7 @@ base_breakpoint_create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *c, struct linespec_sals *lsal, char *cond_string, + char *extra_string, enum bptype type_wanted, enum bpdisp disposition, int thread, @@ -12344,6 +12537,9 @@ bkpt_print_mention (struct breakpoint *b) case bp_hardware_breakpoint: printf_filtered (_("Hardware assisted breakpoint %d"), b->number); break; + case bp_dprintf: + printf_filtered (_("Dprintf %d"), b->number); + break; } say_where (b); @@ -12384,6 +12580,7 @@ bkpt_create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *canonical, struct linespec_sals *lsal, char *cond_string, + char *extra_string, enum bptype type_wanted, enum bpdisp disposition, int thread, @@ -12393,7 +12590,8 @@ bkpt_create_breakpoints_sal (struct gdbarch *gdbarch, int internal, unsigned flags) { create_breakpoints_sal_default (gdbarch, canonical, lsal, - cond_string, type_wanted, + cond_string, extra_string, + type_wanted, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags); @@ -12705,6 +12903,7 @@ tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *canonical, struct linespec_sals *lsal, char *cond_string, + char *extra_string, enum bptype type_wanted, enum bpdisp disposition, int thread, @@ -12714,7 +12913,8 @@ tracepoint_create_breakpoints_sal (struct gdbarch *gdbarch, int internal, unsigned flags) { create_breakpoints_sal_default (gdbarch, canonical, lsal, - cond_string, type_wanted, + cond_string, extra_string, + type_wanted, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags); @@ -12778,6 +12978,7 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch, struct linespec_result *canonical, struct linespec_sals *lsal, char *cond_string, + char *extra_string, enum bptype type_wanted, enum bpdisp disposition, int thread, @@ -12811,7 +13012,8 @@ strace_marker_create_breakpoints_sal (struct gdbarch *gdbarch, tp = XCNEW (struct tracepoint); init_breakpoint_sal (&tp->base, gdbarch, expanded, addr_string, NULL, - cond_string, type_wanted, disposition, + cond_string, extra_string, + type_wanted, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags, canonical->special_display); @@ -13438,13 +13640,17 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found) char *cond_string = 0; int thread = -1; int task = 0; + char *extra_string = NULL; find_condition_and_thread (s, sals.sals[0].pc, - &cond_string, &thread, &task); + &cond_string, &thread, &task, + &extra_string); if (cond_string) b->cond_string = cond_string; b->thread = thread; b->task = task; + if (extra_string) + b->extra_string = extra_string; b->condition_not_parsed = 0; } @@ -13512,6 +13718,7 @@ create_breakpoints_sal_default (struct gdbarch *gdbarch, struct linespec_result *canonical, struct linespec_sals *lsal, char *cond_string, + char *extra_string, enum bptype type_wanted, enum bpdisp disposition, int thread, @@ -13521,6 +13728,7 @@ create_breakpoints_sal_default (struct gdbarch *gdbarch, int internal, unsigned flags) { create_breakpoints_sal (gdbarch, canonical, cond_string, + extra_string, type_wanted, disposition, thread, task, ignore_count, ops, from_tty, enabled, internal, flags); @@ -14394,7 +14602,7 @@ trace_command (char *arg, int from_tty) if (create_breakpoint (get_current_arch (), arg, - NULL, 0, 1 /* parse arg */, + NULL, 0, NULL, 1 /* parse arg */, 0 /* tempflag */, bp_tracepoint /* type_wanted */, 0 /* Ignore count */, @@ -14411,7 +14619,7 @@ ftrace_command (char *arg, int from_tty) { if (create_breakpoint (get_current_arch (), arg, - NULL, 0, 1 /* parse arg */, + NULL, 0, NULL, 1 /* parse arg */, 0 /* tempflag */, bp_fast_tracepoint /* type_wanted */, 0 /* Ignore count */, @@ -14439,7 +14647,7 @@ strace_command (char *arg, int from_tty) if (create_breakpoint (get_current_arch (), arg, - NULL, 0, 1 /* parse arg */, + NULL, 0, NULL, 1 /* parse arg */, 0 /* tempflag */, bp_static_tracepoint /* type_wanted */, 0 /* Ignore count */, @@ -14504,7 +14712,8 @@ create_tracepoint_from_upload (struct uploaded_tp *utp) if (!create_breakpoint (get_current_arch (), addr_str, - utp->cond_string, -1, 0 /* parse cond/thread */, + utp->cond_string, -1, NULL, + 0 /* parse cond/thread */, 0 /* tempflag */, utp->type /* type_wanted */, 0 /* Ignore count */, @@ -15260,6 +15469,14 @@ initialize_breakpoint_ops (void) ops->print_one = print_one_catch_solib; ops->print_mention = print_mention_catch_solib; ops->print_recreate = print_recreate_catch_solib; + + ops = &dprintf_breakpoint_ops; + *ops = bkpt_base_breakpoint_ops; + ops->re_set = bkpt_re_set; + ops->resources_needed = bkpt_resources_needed; + ops->print_it = bkpt_print_it; + ops->print_mention = bkpt_print_mention; + ops->print_recreate = bkpt_print_recreate; } void @@ -15842,6 +16059,44 @@ The breakpoint will stop execution of the inferior whenever it executes\n\ an instruction at any address within the [START-LOCATION, END-LOCATION]\n\ range (including START-LOCATION and END-LOCATION).")); + c = add_com ("dprintf", class_breakpoint, dprintf_command, _("\ +Set a dynamic printf at specified line or function.\n\ +dprintf location,format string,arg1,arg2,...\n\ +location may be a line number, function name, or \"*\" and an address.\n\ +If a line number is specified, break at start of code for that line.\n\ +If a function is specified, break at start of code for that function.\n\ +")); + set_cmd_completer (c, location_completer); + + add_setshow_enum_cmd ("dprintf-style", class_support, + dprintf_style_enums, &dprintf_style, _("\ +Set the style of usage for dynamic printf."), _("\ +Show the style of usage for dynamic printf."), _("\ +This setting chooses how GDB will do a dynamic printf.\n\ +If the value is \"gdb\", then the printing is done by GDB to its own\n\ +console, as with the \"printf\" command.\n\ +If the value is \"call\", the print is done by calling a function in your\n\ +program; by default printf(), but you can choose a different function or\n\ +output stream by setting dprintf-function and dprintf-channel."), + update_dprintf_commands, NULL, + &setlist, &showlist); + + dprintf_function = xstrdup ("printf"); + add_setshow_string_cmd ("dprintf-function", class_support, + &dprintf_function, _("\ +Set the function to use for dynamic printf"), _("\ +Show the function to use for dynamic printf"), NULL, + update_dprintf_commands, NULL, + &setlist, &showlist); + + dprintf_channel = xstrdup (""); + add_setshow_string_cmd ("dprintf-channel", class_support, + &dprintf_channel, _("\ +Set the channel to use for dynamic printf"), _("\ +Show the channel to use for dynamic printf"), NULL, + update_dprintf_commands, NULL, + &setlist, &showlist); + automatic_hardware_breakpoints = 1; observer_attach_about_to_proceed (breakpoint_about_to_proceed); diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index d23561ab78..c81c080212 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -154,6 +154,13 @@ enum bptype bp_fast_tracepoint, bp_static_tracepoint, + /* A dynamic printf stops at the given location, does a formatted + print, then automatically continues. (Although this is sort of + like a macro packaging up standard breakpoint functionality, + GDB doesn't have a way to construct types of breakpoint from + elements of behavior.) */ + bp_dprintf, + /* Event for JIT compiled code generation or deletion. */ bp_jit_event, @@ -552,6 +559,7 @@ struct breakpoint_ops void (*create_breakpoints_sal) (struct gdbarch *, struct linespec_result *, struct linespec_sals *, char *, + char *, enum bptype, enum bpdisp, int, int, int, const struct breakpoint_ops *, int, int, int, unsigned); @@ -674,8 +682,9 @@ struct breakpoint /* String form of the breakpoint condition (malloc'd), or NULL if there is no condition. */ char *cond_string; - /* String form of exp to use for displaying to the user - (malloc'd), or NULL if none. */ + + /* String form of extra parameters, or NULL if there are none. */ + char *extra_string; /* Holds the address of the related watchpoint_scope breakpoint when using watchpoints on local variables (might the concept of @@ -1210,6 +1219,7 @@ enum breakpoint_create_flags extern int create_breakpoint (struct gdbarch *gdbarch, char *arg, char *cond_string, int thread, + char *extra_string, int parse_condition_and_thread, int tempflag, enum bptype wanted_type, int ignore_count, diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 8eef588260..4ee5c631a6 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2012-05-14 Stan Shebs + + * gdb.texinfo (Dynamic Printf): New subsection. + 2012-05-13 Siva Chandra Reddy * gdb.texinfo (Basic Python): Add description about the function diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index a5c6879e2a..7bfb9640a8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -3341,6 +3341,7 @@ all breakpoints in that range are operated on. * Disabling:: Disabling breakpoints * Conditions:: Break conditions * Break Commands:: Breakpoint command lists +* Dynamic Printf:: Dynamic printf * Save Breakpoints:: How to save breakpoints in a file * Static Probe Points:: Listing static probe points * Error in Breakpoints:: ``Cannot insert breakpoints'' @@ -4628,6 +4629,89 @@ cont end @end smallexample +@node Dynamic Printf +@subsection Dynamic Printf + +@cindex dynamic printf +@cindex dprintf +The dynamic printf command @code{dprintf} combines a breakpoint with +formatted printing of your program's data to give you the effect of +inserting @code{printf} calls into your program on-the-fly, without +having to recompile it. + +In its most basic form, the output goes to the GDB console. However, +you can set the variable @code{dprintf-style} for alternate handling. +For instance, you can ask to format the output by calling your +program's @code{printf} function. This has the advantage that the +characters go to the program's output device, so they can recorded in +redirects to files and so forth. + +@table @code +@kindex dprintf +@item dprintf @var{location},@var{template},@var{expression}[,@var{expression}@dots{}] +Whenever execution reaches @var{location}, print the values of one or +more @var{expressions} under the control of the string @var{template}. +To print several values, separate them with commas. + +@item set dprintf-style @var{style} +Set the dprintf output to be handled in one of several different +styles enumerated below. A change of style affects all existing +dynamic printfs immediately. (If you need individual control over the +print commands, simply define normal breakpoints with +explicitly-supplied command lists.) + +@item gdb +@kindex dprintf-style gdb +Handle the output using the @value{GDBN} @code{printf} command. + +@item call +@kindex dprintf-style call +Handle the output by calling a function in your program (normally +@code{printf}). + +@item set dprintf-function @var{function} +Set the function to call if the dprintf style is @code{call}. By +default its value is @code{printf}. You may set it to any expression. +that @value{GDBN} can evaluate to a function, as per the @code{call} +command. + +@item set dprintf-channel @var{channel} +Set a ``channel'' for dprintf. If set to a non-empty value, +@value{GDBN} will evaluate it as an expression and pass the result as +a first argument to the @code{dprintf-function}, in the manner of +@code{fprintf} and similar functions. Otherwise, the dprintf format +string will be the first argument, in the manner of @code{printf}. + +As an example, if you wanted @code{dprintf} output to go to a logfile +that is a standard I/O stream assigned to the variable @code{mylog}, +you could do the following: + +@example +(gdb) set dprintf-style call +(gdb) set dprintf-function fprintf +(gdb) set dprintf-channel mylog +(gdb) dprintf 25,"at line 25, glob=%d\n",glob +Dprintf 1 at 0x123456: file main.c, line 25. +(gdb) info break +1 dprintf keep y 0x00123456 in main at main.c:25 + call (void) fprintf (mylog,"at line 25, glob=%d\n",glob) + continue +(gdb) +@end example + +Note that the @code{info break} displays the dynamic printf commands +as normal breakpoint commands; you can thus easily see the effect of +the variable settings. + +@end table + +@value{GDBN} does not check the validity of function and channel, +relying on you to supply values that are meaningful for the contexts +in which they are being used. For instance, the function and channel +may be the values of local variables, but if that is the case, then +all enabled dynamic prints must be at locations within the scope of +those locals. If evaluation fails, @value{GDBN} will report an error. + @node Save Breakpoints @subsection How to save breakpoints to a file diff --git a/gdb/mi/mi-cmd-break.c b/gdb/mi/mi-cmd-break.c index 478527b3a0..5a64bf1d55 100644 --- a/gdb/mi/mi-cmd-break.c +++ b/gdb/mi/mi-cmd-break.c @@ -164,6 +164,7 @@ mi_cmd_break_insert (char *command, char **argv, int argc) : (hardware ? bp_hardware_breakpoint : bp_breakpoint)); create_breakpoint (get_current_arch (), address, condition, thread, + NULL, 0 /* condition and thread are valid. */, temp_p, type_wanted, ignore_count, diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c index b2c625f8e9..89ace99f25 100644 --- a/gdb/python/py-breakpoint.c +++ b/gdb/python/py-breakpoint.c @@ -622,7 +622,7 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) case bp_breakpoint: { create_breakpoint (python_gdbarch, - copy, NULL, -1, + copy, NULL, -1, NULL, 0, 0, bp_breakpoint, 0, diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c index b67b163152..3d598d71c7 100644 --- a/gdb/python/py-finishbreakpoint.c +++ b/gdb/python/py-finishbreakpoint.c @@ -281,7 +281,7 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) addr_str = small_buf; create_breakpoint (python_gdbarch, - addr_str, NULL, thread, + addr_str, NULL, thread, NULL, 0, 1 /*temp_flag*/, bp_breakpoint, diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 00bd6c87b0..fa10a4dd04 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2012-05-14 Stan Shebs + + * gdb.base/dprintf.c: New file. + * gdb.base/dprintf.exp: New file. + 2012-05-14 Hui Zhu * gdb.trace/Makefile.in (PROGS): Add disconnected-tracing. diff --git a/gdb/testsuite/gdb.base/dprintf.c b/gdb/testsuite/gdb.base/dprintf.c new file mode 100644 index 0000000000..283ff5803a --- /dev/null +++ b/gdb/testsuite/gdb.base/dprintf.c @@ -0,0 +1,44 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright (C) 2012 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +static int g; + +void +foo (int arg) +{ + g += arg; + g *= 2; /* set dprintf 1 here */ + g /= 2.5; /* set breakpoint 1 here */ +} + +int +main (int argc, char *argv[]) +{ + int loc = 1234; + + /* Ensure these functions are available. */ + printf ("kickoff\n"); + fprintf (stderr, "also to stderr\n"); + + foo (loc++); + foo (loc++); + foo (loc++); + return g; +} + diff --git a/gdb/testsuite/gdb.base/dprintf.exp b/gdb/testsuite/gdb.base/dprintf.exp new file mode 100644 index 0000000000..76f5fc5d36 --- /dev/null +++ b/gdb/testsuite/gdb.base/dprintf.exp @@ -0,0 +1,89 @@ +# Copyright (C) 2012 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +if { [prepare_for_testing dprintf.exp "dprintf" {} {debug}] } { + return -1 +} + +set srcfile dprintf.c + +set bp_location1 [gdb_get_line_number "set breakpoint 1 here"] +set dp_location1 [gdb_get_line_number "set dprintf 1 here"] + +gdb_breakpoint "main" +gdb_run_cmd + +gdb_test "dprintf" "Format string required" + +gdb_test "dprintf foo" "Format string required" + +gdb_test "dprintf 29" "Format string required" + +delete_breakpoints + +gdb_breakpoint "main" + +gdb_test "dprintf foo,\"At foo entry\\n\"" \ + "Dprintf .*" + +gdb_test "dprintf $dp_location1,\"arg=%d, g=%d\\n\", arg, g" \ + "Dprintf .*" + +gdb_test "break $bp_location1" \ + "Breakpoint .*" + +gdb_run_cmd + +gdb_test "" "Breakpoint" + +gdb_test "continue" "At foo entry.*arg=1234, g=1234.*" "1st dprintf, gdb" + +gdb_test "continue" "At foo entry.*arg=1235, g=2222.*" "2nd dprintf, gdb" + +# The "call" style depends on having I/O functions available, so test. + +if ![target_info exists gdb,noinferiorio] { + + # Now switch styles and rerun; in the absence of redirection the + # output should be the same. + + gdb_test_no_output "set dprintf-style call" "Set dprintf style to call" + + gdb_run_cmd + + gdb_test "" "Breakpoint" + + gdb_test "continue" "At foo entry.*arg=1234, g=1234.*" "1st dprintf, call" + + gdb_test "continue" "At foo entry.*arg=1235, g=2222.*" "2nd dprintf, call" + + gdb_test_no_output "set dprintf-function fprintf" "Set dprintf function" + gdb_test_no_output "set dprintf-channel stderr" "Set dprintf channel" + + gdb_run_cmd + + gdb_test "" "Breakpoint" + + gdb_test "continue" "At foo entry.*arg=1234, g=1234.*" \ + "1st dprintf, fprintf" + + gdb_test "continue" "At foo entry.*arg=1235, g=2222.*" \ + "2nd dprintf, fprintf" +} + +gdb_test "set dprintf-style foobar" "Undefined item: \"foobar\"." \ + "Set dprintf style to an unrecognized type" +