Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH v2] dynamic printf
@ 2012-05-08  6:27 Stan Shebs
  2012-05-08  7:50 ` Yao Qi
  0 siblings, 1 reply; 16+ messages in thread
From: Stan Shebs @ 2012-05-08  6:27 UTC (permalink / raw)
  To: gdb-patches

[-- 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" ""

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-08  6:27 [PATCH v2] dynamic printf Stan Shebs
@ 2012-05-08  7:50 ` Yao Qi
  2012-05-14 15:54   ` Stan Shebs
  0 siblings, 1 reply; 16+ messages in thread
From: Yao Qi @ 2012-05-08  7:50 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches

Stan,
See some comments on test case below,

On 05/08/2012 02:26 PM, Stan Shebs wrote:
> 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/>.
> +
> +

Some tests in this case reply on inferior io, so board setting
"gdb,noinferiorio" should be checked, and tests should be skipped when
`dprintf-style' is `call'.

> +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_test_no_output is better.

> +
> +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" ""
> +

and here.

> +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" ""

Better to check the output, event it is an error message.

-- 
Yao (齐尧)


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  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
                       ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Stan Shebs @ 2012-05-14 15:54 UTC (permalink / raw)
  To: Yao Qi; +Cc: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1954 bytes --]

On 5/8/12 12:50 AM, Yao Qi wrote:
> Stan,
> See some comments on test case below,
>
>
Thanks for the feedback!  Here's what I committed.

Stan

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.

     * gdb.texinfo (Dynamic Printf): New subsection.

     * gdb.base/dprintf.c: New file.
     * gdb.base/dprintf.exp: New file.


[-- Attachment #2: dprintf-patch-3 --]
[-- Type: text/plain, Size: 35291 bytes --]

Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.518
diff -u -p -r1.518 NEWS
--- NEWS	13 May 2012 11:33:42 -0000	1.518
+++ NEWS	14 May 2012 15:26:53 -0000
@@ -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 <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: 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	14 May 2012 15:26:53 -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	14 May 2012 15:26:53 -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.963
diff -u -p -r1.963 gdb.texinfo
--- doc/gdb.texinfo	13 May 2012 11:33:43 -0000	1.963
+++ doc/gdb.texinfo	14 May 2012 15:26:54 -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: 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	14 May 2012 15:26:54 -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	14 May 2012 15:26:54 -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: 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	14 May 2012 15:26:54 -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: 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	14 May 2012 15:26:54 -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	14 May 2012 15:26:54 -0000
@@ -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"
+

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [commit] Fix spu-tdep.c build regression  [Re: [PATCH v2] dynamic printf]
  2012-05-14 15:54   ` Stan Shebs
@ 2012-05-15  4:10     ` 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-16 20:17     ` [PATCH v2] dynamic printf Tom Tromey
  2 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2012-05-15  4:10 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Yao Qi, gdb-patches

On Mon, 14 May 2012 17:53:50 +0200, Stan Shebs wrote:
> Thanks for the feedback!  Here's what I committed.

with --enable-targets=all:

spu-tdep.c: In function ‘spu_catch_start’:
spu-tdep.c:1950:8: error: incompatible type for argument 10 of ‘create_breakpoint’
In file included from inferior.h:37:0,
                 from spu-tdep.c:36:
breakpoint.h:1220:12: note: expected ‘enum auto_boolean’ but argument is of type ‘struct breakpoint_ops *’
spu-tdep.c:1950:8: error: too few arguments to function ‘create_breakpoint’
In file included from inferior.h:37:0,
                 from spu-tdep.c:36:
breakpoint.h:1220:12: note: declared here


BTW sourceware GIT still displays you as:
	Author: Stan Shebs <shebs@apple.com>


Regards,
Jan


http://sourceware.org/ml/gdb-cvs/2012-05/msg00105.html

--- src/gdb/ChangeLog	2012/05/14 18:56:39	1.14249
+++ src/gdb/ChangeLog	2012/05/15 04:08:44	1.14250
@@ -1,3 +1,8 @@
+2012-05-15  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	* spu-tdep.c (spu_catch_start): Update create_breakpoint caller
+	parameters.
+
 2012-05-14  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* amd64-tdep.c: Include features/i386/x32.c and
--- src/gdb/spu-tdep.c	2012/03/13 13:30:42	1.78
+++ src/gdb/spu-tdep.c	2012/05/15 04:08:47	1.79
@@ -1942,6 +1942,7 @@
   xsnprintf (buf, sizeof buf, "*%s", core_addr_to_string (pc));
   create_breakpoint (get_objfile_arch (objfile), buf /* arg */,
 		     NULL /* cond_string */, -1 /* thread */,
+		     NULL /* extra_string */,
 		     0 /* parse_condition_and_thread */, 1 /* tempflag */,
 		     bp_breakpoint /* type_wanted */,
 		     0 /* ignore_count */,


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [commit] Fix spu-tdep.c build regression  [Re: [PATCH v2] dynamic printf]
  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
  0 siblings, 0 replies; 16+ messages in thread
From: Jim Meyering @ 2012-05-15 10:24 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Stan Shebs, Yao Qi, gdb-patches

Jan Kratochvil wrote:
> On Mon, 14 May 2012 17:53:50 +0200, Stan Shebs wrote:
>> Thanks for the feedback!  Here's what I committed.
>
> with --enable-targets=all:
>
> spu-tdep.c: In function ‘spu_catch_start’:
> spu-tdep.c:1950:8: error: incompatible type for argument 10 of ‘create_breakpoint’
> In file included from inferior.h:37:0,
>                  from spu-tdep.c:36:
> breakpoint.h:1220:12: note: expected ‘enum auto_boolean’ but argument is of type ‘struct breakpoint_ops *’
> spu-tdep.c:1950:8: error: too few arguments to function ‘create_breakpoint’
> In file included from inferior.h:37:0,
>                  from spu-tdep.c:36:
> breakpoint.h:1220:12: note: declared here
>
>
> BTW sourceware GIT still displays you as:
> 	Author: Stan Shebs <shebs@apple.com>

Hi Stan,

The cvs-to-git process uses a cvs username-to-git-NAME+email mapping that
appeared reasonable back when I first automated the conversion process.
If anyone would like to have their name/email (as displayed in the
converted git commits) updated, just let me know.


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [commit] testsuite: gdb.base/dprintf.exp PR 12649 race  [Re: [PATCH v2] dynamic printf]
  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 13:10     ` Jan Kratochvil
  2012-05-15 13:34       ` Joel Brobecker
  2012-05-16 20:17     ` [PATCH v2] dynamic printf Tom Tromey
  2 siblings, 1 reply; 16+ messages in thread
From: Jan Kratochvil @ 2012-05-15 13:10 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Yao Qi, gdb-patches

On Mon, 14 May 2012 17:53:50 +0200, Stan Shebs wrote:
> Thanks for the feedback!  Here's what I committed.

seeing racy results
	+Running gdb/testsuite/gdb.base/dprintf.exp ...
	+FAIL: gdb.base/dprintf.exp: dprintf
	+PASS: gdb.base/dprintf.exp: dprintf foo
	+PASS: gdb.base/dprintf.exp: dprintf 29
	+ERROR: breakpoints not deleted
	+UNRESOLVED: gdb.base/dprintf.exp: dprintf foo,"At foo entry\n"

with the read1 reproducer from
	http://sourceware.org/bugzilla/show_bug.cgi?id=12649

it shows:

(gdb) run ^M
Starting program: /home/jkratoch/redhat/gdb-clean/gdb/testsuite/gdb.base/dprintf ^M
dprintf^M
warning: Skipping deprecated .gdb_index section in /usr/lib/debug/lib64/ld-2.15.so.debug, pass --use-deprecated-index-sections to use them anyway^M
^M
Breakpoint 1, main (argc=1, argv=0x7fffffffdb98) at ./gdb.base/dprintf.c:33^M
33        int loc = 1234;^M
(gdb) FAIL: gdb.base/dprintf.exp: dprintf

Checked in the fix.


Regards,
Jan


http://sourceware.org/ml/gdb-cvs/2012-05/msg00107.html

--- src/gdb/testsuite/ChangeLog	2012/05/14 20:33:16	1.3189
+++ src/gdb/testsuite/ChangeLog	2012/05/15 13:08:57	1.3190
@@ -1,3 +1,8 @@
+2012-05-15  Jan Kratochvil  <jan.kratochvil@redhat.com>
+
+	PR testsuite/12649
+	* gdb.base/dprintf.exp: Replace gdb_run_cmd by runto main.
+
 2012-05-14  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* gdb.base/stap-probe.exp (stap_test): Remove calls to
--- src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/14 15:38:41	1.1
+++ src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/15 13:08:58	1.2
@@ -24,7 +24,9 @@
 set dp_location1 [gdb_get_line_number "set dprintf 1 here"]
 
 gdb_breakpoint "main"
-gdb_run_cmd
+if ![runto main] {
+    return -1
+}
 
 gdb_test "dprintf" "Format string required"
 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [commit] testsuite: gdb.base/dprintf.exp PR 12649 race  [Re: [PATCH v2] dynamic printf]
  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
  0 siblings, 1 reply; 16+ messages in thread
From: Joel Brobecker @ 2012-05-15 13:34 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: Stan Shebs, Yao Qi, gdb-patches

> --- src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/14 15:38:41	1.1
> +++ src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/15 13:08:58	1.2
> @@ -24,7 +24,9 @@
>  set dp_location1 [gdb_get_line_number "set dprintf 1 here"]
>  
>  gdb_breakpoint "main"
> -gdb_run_cmd
> +if ![runto main] {
> +    return -1
> +}

I think you can also remove the breakpoint on "main", since
"runto" deletes all breakpoints and inserts a new one.

-- 
Joel


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [commit#2] testsuite: gdb.base/dprintf.exp PR 12649 race  [Re: [PATCH v2] dynamic printf]
  2012-05-15 13:34       ` Joel Brobecker
@ 2012-05-15 13:37         ` Jan Kratochvil
  0 siblings, 0 replies; 16+ messages in thread
From: Jan Kratochvil @ 2012-05-15 13:37 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: Stan Shebs, Yao Qi, gdb-patches

On Tue, 15 May 2012 15:33:40 +0200, Joel Brobecker wrote:
> I think you can also remove the breakpoint on "main", since
> "runto" deletes all breakpoints and inserts a new one.

yes:

http://sourceware.org/ml/gdb-cvs/2012-05/msg00108.html

--- src/gdb/testsuite/ChangeLog	2012/05/15 13:08:57	1.3190
+++ src/gdb/testsuite/ChangeLog	2012/05/15 13:36:17	1.3191
@@ -3,6 +3,8 @@
 	PR testsuite/12649
 	* gdb.base/dprintf.exp: Replace gdb_run_cmd by runto main.
 
+	* gdb.base/dprintf.exp: Remove now redundant breakpoint for main.
+
 2012-05-14  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* gdb.base/stap-probe.exp (stap_test): Remove calls to
--- src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/15 13:08:58	1.2
+++ src/gdb/testsuite/gdb.base/dprintf.exp	2012/05/15 13:36:18	1.3
@@ -23,7 +23,6 @@
 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"
 if ![runto main] {
     return -1
 }


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  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 13:10     ` [commit] testsuite: gdb.base/dprintf.exp PR 12649 race " Jan Kratochvil
@ 2012-05-16 20:17     ` Tom Tromey
  2012-05-16 20:46       ` Stan Shebs
  2 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2012-05-16 20:17 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Yao Qi, gdb-patches

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Sorry about the delay on this.

Stan> +  /* Manufacture a printf/continue sequence.  */
Stan> +  if (printf_line)
Stan> +    {
Stan> +      struct command_line *printf_cmd_line, *cont_cmd_line = NULL;
Stan> +
Stan> +      cont_cmd_line = xmalloc (sizeof (struct command_line));
Stan> +      cont_cmd_line->control_type = simple_control;
Stan> +      cont_cmd_line->body_count = 0;
Stan> +      cont_cmd_line->body_list = NULL;
Stan> +      cont_cmd_line->next = NULL;
Stan> +      cont_cmd_line->line = xstrdup ("continue");
Stan> +
Stan> +      printf_cmd_line = xmalloc (sizeof (struct command_line));
Stan> +      printf_cmd_line->control_type = simple_control;
Stan> +      printf_cmd_line->body_count = 0;
Stan> +      printf_cmd_line->body_list = NULL;
Stan> +      printf_cmd_line->next = cont_cmd_line;
Stan> +      printf_cmd_line->line = printf_line;
Stan> +
Stan> +      breakpoint_set_commands (b, printf_cmd_line);

I thought this approach would break "next"ing over a dprintf location.

Stan> +void dprintf_command (char *arg, int from_tty);
Stan> +
Stan> +/* The dynamic printf command is mostly like a regular breakpoint, but
Stan> +   with a prewired command list consisting of a single output command,
Stan> +   built from extra arguments supplied on the dprintf command
Stan> +   line.  */
Stan> +
Stan> +void
Stan> +dprintf_command (char *arg, int from_tty)

I think this could be static.

Tom


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  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
                           ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Stan Shebs @ 2012-05-16 20:46 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 5/16/12 1:17 PM, Tom Tromey wrote:
>>>>>> "Stan" == Stan Shebs<stanshebs@earthlink.net>  writes:
> Sorry about the delay on this.
>
> Stan>  +  /* Manufacture a printf/continue sequence.  */
> Stan>  +  if (printf_line)
> Stan>  +    {
> Stan>  +      struct command_line *printf_cmd_line, *cont_cmd_line = NULL;
> Stan>  +
> Stan>  +      cont_cmd_line = xmalloc (sizeof (struct command_line));
> Stan>  +      cont_cmd_line->control_type = simple_control;
> Stan>  +      cont_cmd_line->body_count = 0;
> Stan>  +      cont_cmd_line->body_list = NULL;
> Stan>  +      cont_cmd_line->next = NULL;
> Stan>  +      cont_cmd_line->line = xstrdup ("continue");
> Stan>  +
> Stan>  +      printf_cmd_line = xmalloc (sizeof (struct command_line));
> Stan>  +      printf_cmd_line->control_type = simple_control;
> Stan>  +      printf_cmd_line->body_count = 0;
> Stan>  +      printf_cmd_line->body_list = NULL;
> Stan>  +      printf_cmd_line->next = cont_cmd_line;
> Stan>  +      printf_cmd_line->line = printf_line;
> Stan>  +
> Stan>  +      breakpoint_set_commands (b, printf_cmd_line);
>
> I thought this approach would break "next"ing over a dprintf location.

Indeed, thus this part of the introduction to this patch: :-)

"... 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 nobody comes up with a good idea here, it should probably be 
documented as a limitation.  I wonder if some relatively recent infrun 
tinkering changed the breakpoint command behavior - you'd think 
*somebody* would have bumped into it sometime in the past 20 years...

Ironically, the agent version doesn't have this problem, because the 
resume happens automatically inside GDBserver, and GDB is oblivious.


> Stan>  +void
> Stan>  +dprintf_command (char *arg, int from_tty)
>
> I think this could be static.
>

Good point, I tweaked it for the agent patch.

Stan


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-16 20:46       ` Stan Shebs
@ 2012-05-16 20:52         ` Pedro Alves
  2012-05-16 22:25           ` Stan Shebs
  2012-05-16 20:53         ` Pedro Alves
  2012-05-16 21:06         ` Tom Tromey
  2 siblings, 1 reply; 16+ messages in thread
From: Pedro Alves @ 2012-05-16 20:52 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Tom Tromey, gdb-patches

On 05/16/2012 09:46 PM, Stan Shebs wrote:

>> I thought this approach would break "next"ing over a dprintf location.
> 
> Indeed, thus this part of the introduction to this patch: :-)
> 
> "... 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.

This is normally handled by the bpstat saying "don't stop".    Doesn't that work
for this?  Why?


> Ironically, the agent version doesn't have this problem, because the resume happens automatically inside GDBserver, and GDB is oblivious.

That's sort of what happens when the bpstat returns "don't stop for this".

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-16 20:46       ` Stan Shebs
  2012-05-16 20:52         ` Pedro Alves
@ 2012-05-16 20:53         ` Pedro Alves
  2012-05-16 21:06         ` Tom Tromey
  2 siblings, 0 replies; 16+ messages in thread
From: Pedro Alves @ 2012-05-16 20:53 UTC (permalink / raw)
  To: Stan Shebs; +Cc: Tom Tromey, gdb-patches

On 05/16/2012 09:46 PM, Stan Shebs wrote:

> 
>> Stan>  +void
>> Stan>  +dprintf_command (char *arg, int from_tty)
>>
>> I think this could be static.
>>
> 
> Good point, I tweaked it for the agent patch.


Please don't mix changes.  Keep logical changes separate patches.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-16 20:46       ` Stan Shebs
  2012-05-16 20:52         ` Pedro Alves
  2012-05-16 20:53         ` Pedro Alves
@ 2012-05-16 21:06         ` Tom Tromey
  2 siblings, 0 replies; 16+ messages in thread
From: Tom Tromey @ 2012-05-16 21:06 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Tom> I thought this approach would break "next"ing over a dprintf location.

Stan> Indeed, thus this part of the introduction to this patch: :-)

I you read the binutils list today you'll see I'm quite off my game.
Sorry about the poor reading comprehension.

Stan> "... Joel previously noted a problem with the "continue" in the
Stan> command list, which is that stepping/nexting over a dprintf becomes a
Stan> continue instead (this is a problem for general breakpoint command
Stan> lists as well).  I tinkered with bpstats a bit, but didn't come up
Stan> with a good solution.  One possibility might be a new pseudo-command
Stan> for breakpoint command lists, that resumes the program using the same
Stan> proceed() arguments as the command that caused the breakpoint hit."

Yeah, we added the 'stop' machinery to Python to let us deal with this.

One idea would be "continue -hey-dont-break-next"

Stan> If nobody comes up with a good idea here, it should probably be
Stan> documented as a limitation.  I wonder if some relatively recent infrun
Stan> tinkering changed the breakpoint command behavior - you'd think
Stan> *somebody* would have bumped into it sometime in the past 20 years...

I've known about it for a long time, I think we all just worked around
it.

Tom


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-16 20:52         ` Pedro Alves
@ 2012-05-16 22:25           ` Stan Shebs
  2012-05-17  1:56             ` Tom Tromey
  0 siblings, 1 reply; 16+ messages in thread
From: Stan Shebs @ 2012-05-16 22:25 UTC (permalink / raw)
  To: gdb-patches

On 5/16/12 1:52 PM, Pedro Alves wrote:
> On 05/16/2012 09:46 PM, Stan Shebs wrote:
>
>>> I thought this approach would break "next"ing over a dprintf location.
>> Indeed, thus this part of the introduction to this patch: :-)
>>
>> "... 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.
> This is normally handled by the bpstat saying "don't stop".    Doesn't that work
> for this?  Why?
>

Basically if you set bs->stop to 0, command lists don't get run.  It's a 
little convoluted, because the code does go into bpstat_do_actions, but 
nothing happens there because the copy of b->commands to bs->commands in 
bpstat_stop_status only happens if bs->stop.

That's why I'm thinking of a special command / pseudo-command for the 
command list; we don't necessarily want to say that we haven't stopped, 
because that meaning is typically reserved for "yes we hit the trap, but 
pretend it never happened".  Instead, we want the effect of hitting the 
breakpoint, and then go back to making progress on whichever command we 
were doing.  An alternative is to make bs->stop a three-state, but that 
seems like a really bad idea for an area of code that is already rather 
funky.

Stan


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-16 22:25           ` Stan Shebs
@ 2012-05-17  1:56             ` Tom Tromey
  2012-05-18 15:38               ` Pedro Alves
  0 siblings, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2012-05-17  1:56 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches

>>>>> "Stan" == Stan Shebs <stanshebs@earthlink.net> writes:

Stan> Basically if you set bs->stop to 0, command lists don't get run.  It's
Stan> a little convoluted, because the code does go into bpstat_do_actions,
Stan> but nothing happens there because the copy of b->commands to
Stan> bs-> commands in bpstat_stop_status only happens if bs->stop.

Stan> That's why I'm thinking of a special command / pseudo-command for the
Stan> command list; we don't necessarily want to say that we haven't
Stan> stopped, because that meaning is typically reserved for "yes we hit
Stan> the trap, but pretend it never happened".

I think this would be a good idea in the context of a wider examination
of other changes like this that are desirable or needed.  It seems to me
that there are some other ones in bugzilla.

In this particular case, though, I think you could do it by just having
the 'printf' invocation not be 'commands' stuck onto a breakpoint, but
instead a per-dprintf method that is run at the appropriate moment, a la
the Python 'Breakpoint.stop' method.

Tom


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] dynamic printf
  2012-05-17  1:56             ` Tom Tromey
@ 2012-05-18 15:38               ` Pedro Alves
  0 siblings, 0 replies; 16+ messages in thread
From: Pedro Alves @ 2012-05-18 15:38 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Stan Shebs, gdb-patches

On 05/17/2012 02:56 AM, Tom Tromey wrote:

> In this particular case, though, I think you could do it by just having
> the 'printf' invocation not be 'commands' stuck onto a breakpoint, but
> instead a per-dprintf method that is run at the appropriate moment, a la
> the Python 'Breakpoint.stop' method.


I agree.

I can't be within bkpt_ops->check_status (even though that'd be hacky),
as I think you'd want to support conditions on dprintf, and those are
checked after check_status is consulted.

Another question is, is the user supposed to set commands on dprintf?  Currently
you get:

(gdb) dprintf 36, "hello"
Dprintf 2 at 0x4005e0: file ../../../src/gdb/testsuite/gdb.base/dprintf.c, line 36.
(gdb) info breakpoints
2       dprintf        keep y   0x00000000004005e0 in main at ../../../src/gdb/testsuite/gdb.base/dprintf.c:36
        printf "hello"
        continue

(gdb) commands 2
Type commands for breakpoint(s) 2, one per line.
End with a line saying just "end".
>echo "world"
>end
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       dprintf        keep y   0x00000000004005e0 in main at ../../../src/gdb/testsuite/gdb.base/dprintf.c:36
        breakpoint already hit 1 time
        echo "world"


Another related weekness of the current implementation is that a regular
breakpoint that should cause a stop set at the same address as a dprintf
no longer works correctly, due to the forced "continue".  E.g.,

(gdb) dprintf 36, "hello"
Dprintf 2 at 0x4005e0: file ../../../src/gdb/testsuite/gdb.base/dprintf.c, line 36.
(gdb) b 36
Note: breakpoint 2 also set at pc 0x4005e0.
Breakpoint 3 at 0x4005e0: file ../../../src/gdb/testsuite/gdb.base/dprintf.c, line 36.
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       dprintf        keep y   0x00000000004005e0 in main at ../../../src/gdb/testsuite/gdb.base/dprintf.c:36
        printf "hello"
        continue
3       breakpoint     keep y   0x00000000004005e0 in main at ../../../src/gdb/testsuite/gdb.base/dprintf.c:36
(gdb) b 39
Breakpoint 4 at 0x40060e: file ../../../src/gdb/testsuite/gdb.base/dprintf.c, line 39.
(gdb) c
Continuing.

Breakpoint 2, main (argc=1, argv=0x7fffffffdd48) at ../../../src/gdb/testsuite/gdb.base/dprintf.c:36
36        printf ("kickoff\n");
hellokickoff
also to stderr

Breakpoint 4, main (argc=1, argv=0x7fffffffdd48) at ../../../src/gdb/testsuite/gdb.base/dprintf.c:39
39        foo (loc++);
(gdb)


Breakpoint 3 causes a stop, but GDB starts by running the commands of breakpoint 2 (the dprintf),
just because it has a lower number, and that includes the "continue", so breakpoint 3 is lost.

A similar issue happens with more than one dprintf installed on the same location -- only one
would run.  Multiple dprintfs on the same location would be useful when you set different
conditions on each (like with multiple breakpoints on the same location).

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2012-05-18 15:38 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-08  6:27 [PATCH v2] dynamic printf Stan Shebs
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox