From: Stan Shebs <stanshebs@earthlink.net>
To: gdb-patches@sourceware.org
Subject: [PATCH v2] dynamic printf
Date: Tue, 08 May 2012 06:27:00 -0000 [thread overview]
Message-ID: <4FA8BC97.2000801@earthlink.net> (raw)
[-- Attachment #1: Type: text/plain, Size: 3056 bytes --]
Here is a revised patch for the dynamic printf originally posted in
http://sourceware.org/ml/gdb-patches/2012-02/msg00689.html .
This patch does not include the agent version of dprintf, which I plan
to add later as an additional dprintf style. For the "call" style,
there are
now user-settable dprintf-function and dprintf-channel (aka first
argument to fprintf-type functions).
The patch is messified by having to add an extra_string argument to many
breakpoint functions; it would still make sense to encapsulate 4-5 args
in a parse-results struct, but I didn't want to get bogged down in that
just yet.
Joel previously noted a problem with the "continue" in the command list,
which is that stepping/nexting over a dprintf becomes a continue instead
(this is a problem for general breakpoint command lists as well). I
tinkered with bpstats a bit, but didn't come up with a good solution.
One possibility might be a new pseudo-command for breakpoint command
lists, that resumes the program using the same proceed() arguments as
the command that caused the breakpoint hit.
If people are satisfied with the general form of this, I'll push it in
so it can get some tryout before 7.5 and then work on the agent version.
Stan
2012-05-07 Stan Shebs <stan@codesourcery.com>
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.
[-- Attachment #2: dprintf-patch-2 --]
[-- Type: text/plain, Size: 34267 bytes --]
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.514
diff -u -p -r1.514 NEWS
--- NEWS 3 May 2012 07:07:24 -0000 1.514
+++ NEWS 8 May 2012 04:54:23 -0000
@@ -3,6 +3,10 @@
*** Changes since GDB 7.4
+* You can now do dynamic printfs, which are like printf calls that you
+ can set at a source location, as you do with breakpoints. Syntax is
+ "dprintf location,format,args,..."
+
* GDB now has support for SDT (Static Defined Tracing) probes. Currently,
the only implemented backend is for SystemTap probes (<sys/sdt.h>). You
can set a breakpoint using the new "-probe, "-pstap" or "-probe-stap"
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.670
diff -u -p -r1.670 breakpoint.c
--- breakpoint.c 27 Apr 2012 20:48:55 -0000 1.670
+++ breakpoint.c 8 May 2012 04:54:23 -0000
@@ -109,7 +109,7 @@ static void create_sals_from_address_def
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_op
/* 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 br
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 *lo
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
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->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 *
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 *g
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 *g
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 *
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 gdbar
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, CO
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, CO
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 **ar
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 *gdbar
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 *gdbar
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 *gdbar
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, in
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,
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 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 gdba
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 gdba
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 (struc
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 (struc
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 (st
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 (st
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 *
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 g
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 g
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 up
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 th
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);
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.181
diff -u -p -r1.181 breakpoint.h
--- breakpoint.h 27 Apr 2012 20:47:51 -0000 1.181
+++ breakpoint.h 8 May 2012 04:54:23 -0000
@@ -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,
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.955
diff -u -p -r1.955 gdb.texinfo
--- doc/gdb.texinfo 6 May 2012 15:31:04 -0000 1.955
+++ doc/gdb.texinfo 8 May 2012 04:54:25 -0000
@@ -3341,6 +3341,7 @@ all breakpoints in that range are operat
* 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
Index: mi/mi-cmd-break.c
===================================================================
RCS file: /cvs/src/src/gdb/mi/mi-cmd-break.c,v
retrieving revision 1.51
diff -u -p -r1.51 mi-cmd-break.c
--- mi/mi-cmd-break.c 13 Mar 2012 13:30:42 -0000 1.51
+++ mi/mi-cmd-break.c 8 May 2012 04:54:25 -0000
@@ -164,6 +164,7 @@ mi_cmd_break_insert (char *command, char
: (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,
Index: python/py-breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-breakpoint.c,v
retrieving revision 1.33
diff -u -p -r1.33 py-breakpoint.c
--- python/py-breakpoint.c 13 Mar 2012 13:30:42 -0000 1.33
+++ python/py-breakpoint.c 8 May 2012 04:54:25 -0000
@@ -622,7 +622,7 @@ bppy_init (PyObject *self, PyObject *arg
case bp_breakpoint:
{
create_breakpoint (python_gdbarch,
- copy, NULL, -1,
+ copy, NULL, -1, NULL,
0,
0, bp_breakpoint,
0,
Index: python/py-finishbreakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/python/py-finishbreakpoint.c,v
retrieving revision 1.4
diff -u -p -r1.4 py-finishbreakpoint.c
--- python/py-finishbreakpoint.c 13 Mar 2012 13:30:42 -0000 1.4
+++ python/py-finishbreakpoint.c 8 May 2012 04:54:25 -0000
@@ -281,7 +281,7 @@ bpfinishpy_init (PyObject *self, PyObjec
addr_str = small_buf;
create_breakpoint (python_gdbarch,
- addr_str, NULL, thread,
+ addr_str, NULL, thread, NULL,
0,
1 /*temp_flag*/,
bp_breakpoint,
Index: testsuite/gdb.base/dprintf.c
===================================================================
RCS file: testsuite/gdb.base/dprintf.c
diff -N testsuite/gdb.base/dprintf.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/dprintf.c 8 May 2012 04:54:25 -0000
@@ -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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+
+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;
+}
+
Index: testsuite/gdb.base/dprintf.exp
===================================================================
RCS file: testsuite/gdb.base/dprintf.exp
diff -N testsuite/gdb.base/dprintf.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.base/dprintf.exp 8 May 2012 04:54:25 -0000
@@ -0,0 +1,79 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+
+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"
+
+# Now switch styles and rerun; in the absence of redirection the
+# output should be the same.
+
+gdb_test "set dprintf-style 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 "set dprintf-function fprintf" ""
+gdb_test "set dprintf-channel stderr" ""
+
+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" ""
next reply other threads:[~2012-05-08 6:27 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-08 6:27 Stan Shebs [this message]
2012-05-08 7:50 ` Yao Qi
2012-05-14 15:54 ` Stan Shebs
2012-05-15 4:10 ` [commit] Fix spu-tdep.c build regression [Re: [PATCH v2] dynamic printf] Jan Kratochvil
2012-05-15 10:24 ` Jim Meyering
2012-05-15 13:10 ` [commit] testsuite: gdb.base/dprintf.exp PR 12649 race " Jan Kratochvil
2012-05-15 13:34 ` Joel Brobecker
2012-05-15 13:37 ` [commit#2] " Jan Kratochvil
2012-05-16 20:17 ` [PATCH v2] dynamic printf Tom Tromey
2012-05-16 20:46 ` Stan Shebs
2012-05-16 20:52 ` Pedro Alves
2012-05-16 22:25 ` Stan Shebs
2012-05-17 1:56 ` Tom Tromey
2012-05-18 15:38 ` Pedro Alves
2012-05-16 20:53 ` Pedro Alves
2012-05-16 21:06 ` Tom Tromey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4FA8BC97.2000801@earthlink.net \
--to=stanshebs@earthlink.net \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox