2012-05-14 Stan Shebs <stan@codesourcery.com>
authorStan Shebs <shebs@codesourcery.com>
Mon, 14 May 2012 15:38:41 +0000 (15:38 +0000)
committerStan Shebs <shebs@codesourcery.com>
Mon, 14 May 2012 15:38:41 +0000 (15:38 +0000)
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.

12 files changed:
gdb/ChangeLog
gdb/NEWS
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/mi/mi-cmd-break.c
gdb/python/py-breakpoint.c
gdb/python/py-finishbreakpoint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/dprintf.c [new file with mode: 0644]
gdb/testsuite/gdb.base/dprintf.exp [new file with mode: 0644]

index 2c31c3d..04ea09f 100644 (file)
@@ -1,3 +1,41 @@
+2012-05-14  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.
+
 2012-05-14  Maciej W. Rozycki  <macro@codesourcery.com>
 
        * mips-tdep.c (mips_push_dummy_code): Correct description typo.
index dd1ab24..4ddd990 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
      "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 <expr>
+show dprintf-function
+set dprintf-channel <expr>
+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
index ab5f324..b060e74 100644 (file)
@@ -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);
index d23561a..c81c080 100644 (file)
@@ -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 8eef588..4ee5c63 100644 (file)
@@ -1,3 +1,7 @@
+2012-05-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Dynamic Printf): New subsection.
+
 2012-05-13  Siva Chandra Reddy  <sivachandra@google.com>
 
        * gdb.texinfo (Basic Python): Add description about the function
index a5c6879..7bfb964 100644 (file)
@@ -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
 
index 478527b..5a64bf1 100644 (file)
@@ -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,
index b2c625f..89ace99 100644 (file)
@@ -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,
index b67b163..3d598d7 100644 (file)
@@ -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,
index 00bd6c8..fa10a4d 100644 (file)
@@ -1,3 +1,8 @@
+2012-05-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.base/dprintf.c: New file.
+       * gdb.base/dprintf.exp: New file.
+
 2012-05-14  Hui Zhu  <hui_zhu@mentor.com>
 
        * 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 (file)
index 0000000..283ff58
--- /dev/null
@@ -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;
+}
+
diff --git a/gdb/testsuite/gdb.base/dprintf.exp b/gdb/testsuite/gdb.base/dprintf.exp
new file mode 100644 (file)
index 0000000..76f5fc5
--- /dev/null
@@ -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 <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"
+
+# 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"
+