[PATCH v2] tracepoint: add new trace command "printf" and agent expression "printf" [1] gdb

Hui Zhu teawater@gmail.com
Thu Aug 11 06:50:00 GMT 2011


Hi,

This patches is for trunk and 7.3.

All this patches will available in https://lkml.org/lkml/2011/6/4/65

Best,
Hui
-------------- next part --------------
---
 Makefile.in   |    1 
 ax-gdb.c      |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-gdb.h      |    2 +
 ax-general.c  |   53 +++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h          |    2 +
 common/ax.def |    6 -----
 printcmd.c    |   38 ++++++++++++++++++++++++++++---------
 printcmd.h    |   30 +++++++++++++++++++++++++++++
 tracepoint.c  |   39 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 209 insertions(+), 21 deletions(-)

--- a/Makefile.in
+++ b/Makefile.in
@@ -817,6 +817,7 @@ i386-darwin-tdep.h i386-nat.h linux-reco
 osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
+printcmd.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
 gnulib/stddef.in.h inline-frame.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -2444,6 +2444,65 @@ gen_eval_for_expr (CORE_ADDR scope, stru
   return ax;
 }
 
+void
+gen_printf_expr_callback (char *fbuf, char **expp, void *loc_v, void *aexpr_v)
+{
+  struct bp_location	*loc = loc_v;
+  struct agent_expr	*aexpr = aexpr_v;
+
+  if (expp)
+    {
+      struct cleanup *old_chain = NULL;
+      struct expression *expr = NULL;
+      union exp_element *pc;
+      struct axs_value value;
+
+      expr = parse_exp_1 (expp, block_for_pc (loc->address), 1);
+      old_chain = make_cleanup (free_current_contents, &expr);
+
+      pc = expr->elts;
+      trace_kludge = 0;
+      value.optimized_out = 0;
+      gen_expr (expr, &pc, aexpr, &value);
+
+      if (value.optimized_out)
+        error (_("value has been optimized out"));
+      switch (value.kind)
+        {
+	case axs_lvalue_memory:
+	  if (TYPE_CODE (value.type) != TYPE_CODE_ARRAY)
+	    {
+	      int length = TYPE_LENGTH (check_typedef (value.type));
+	      switch (length)
+		{
+		case 4:
+		  ax_simple (aexpr, aop_ref32);
+		  break;
+		case 8:
+		  ax_simple (aexpr, aop_ref64);
+		  break;
+		default:
+		  error (_("Size of value is not OK."));
+		  break;
+		}
+	    }
+	  break;
+	case axs_lvalue_register:
+	  ax_reg (aexpr, value.u.reg);
+	  break;
+        }
+
+      do_cleanups (old_chain);
+    }
+
+  ax_simple (aexpr, aop_printf);
+  if (expp)
+    ax_simple (aexpr, 1);
+  else
+    ax_simple (aexpr, 0);
+  ax_memcpy (aexpr, fbuf, strlen (fbuf) + 1);
+}
+
 static void
 agent_command (char *exp, int from_tty)
 {
--- a/ax-gdb.h
+++ b/ax-gdb.h
@@ -108,6 +108,8 @@ extern struct agent_expr *gen_trace_for_
 
 extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
 
+extern void gen_printf_expr_callback (char *, char **, void *, void *);
+
 extern int trace_kludge;
 
 #endif /* AX_GDB_H */
--- a/ax-general.c
+++ b/ax-general.c
@@ -331,6 +331,14 @@ ax_tsv (struct agent_expr *x, enum agent
   x->buf[x->len + 2] = (num) & 0xff;
   x->len += 3;
 }
+
+void
+ax_memcpy (struct agent_expr *x, const void *src, size_t n)
+{
+  grow_expr (x, n);
+  memcpy (x->buf + x->len, src, n);
+  x->len += n;
+}
 

 
 
@@ -369,6 +377,7 @@ ax_print (struct ui_file *f, struct agen
   for (i = 0; i < x->len;)
     {
       enum agent_op op = x->buf[i];
+      int op_size;
 
       if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
 	  || !aop_map[op].name)
@@ -377,7 +386,19 @@ ax_print (struct ui_file *f, struct agen
 	  i++;
 	  continue;
 	}
-      if (i + 1 + aop_map[op].op_size > x->len)
+      if (op == aop_printf)
+        {
+	  if (i + 2 >= x->len)
+	    {
+	      fprintf_filtered (f, _("%3d  <bad opcode %02x>\n"), i, op);
+	      i++;
+	      continue;
+	    }
+	  op_size = 1 + strlen (x->buf + i + 2) + 1;
+	}
+      else
+	op_size = aop_map[op].op_size;
+      if (i + 1 + op_size > x->len)
 	{
 	  fprintf_filtered (f, _("%3d  <incomplete opcode %s>\n"),
 			    i, aop_map[op].name);
@@ -385,15 +406,15 @@ ax_print (struct ui_file *f, struct agen
 	}
 
       fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
-      if (aop_map[op].op_size > 0)
+      if (op_size > 0)
 	{
 	  fputs_filtered (" ", f);
 
 	  print_longest (f, 'd', 0,
-			 read_const (x, i + 1, aop_map[op].op_size));
+			 read_const (x, i + 1, op_size));
 	}
       fprintf_filtered (f, "\n");
-      i += 1 + aop_map[op].op_size;
+      i += 1 + op_size;
 
       is_float = (op == aop_float);
     }
@@ -461,6 +482,8 @@ ax_reqs (struct agent_expr *ax)
   /* Pointer to a description of the present op.  */
   struct aop_map *op;
 
+  int op_size = 0, consumed = 0;
+
   memset (targets, 0, ax->len * sizeof (targets[0]));
   memset (boundary, 0, ax->len * sizeof (boundary[0]));
 
@@ -468,7 +491,7 @@ ax_reqs (struct agent_expr *ax)
   ax->flaw = agent_flaw_none;
   ax->max_data_size = 0;
 
-  for (i = 0; i < ax->len; i += 1 + op->op_size)
+  for (i = 0; i < ax->len; i += 1 + op_size)
     {
       if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
 	{
@@ -484,7 +507,23 @@ ax_reqs (struct agent_expr *ax)
 	  return;
 	}
 
-      if (i + 1 + op->op_size > ax->len)
+      if (ax->buf[i] == aop_printf)
+        {
+	  if (i + 2 >= ax->len)
+	    {
+	      ax->flaw = agent_flaw_incomplete_instruction;
+	      return;
+	    }
+	  consumed = ax->buf[i + 1];
+	  op_size = 1 + strlen (ax->buf + i + 2) + 1;
+	}
+      else
+        {
+	  op_size = op->op_size;
+	  consumed = op->consumed;
+        }
+
+      if (i + 1 + op_size > ax->len)
 	{
 	  ax->flaw = agent_flaw_incomplete_instruction;
 	  return;
@@ -502,7 +541,7 @@ ax_reqs (struct agent_expr *ax)
       boundary[i] = 1;
       heights[i] = height;
 
-      height -= op->consumed;
+      height -= consumed;
       if (height < ax->min_height)
 	ax->min_height = height;
       height += op->produced;
--- a/ax.h
+++ b/ax.h
@@ -213,6 +213,8 @@ extern void ax_reg_mask (struct agent_ex
 
 /* Assemble code to operate on a trace state variable.  */
 extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num);
+
+extern void ax_memcpy (struct agent_expr *x, const void *src, size_t n);
 

 
 /* Functions for printing out expressions, and otherwise debugging
--- a/common/ax.def
+++ b/common/ax.def
@@ -86,12 +86,8 @@ DEFOP (swap, 0, 0, 2, 2, 0x2b)
 DEFOP (getv, 2, 0, 0, 1, 0x2c)
 DEFOP (setv, 2, 0, 0, 1, 0x2d)
 DEFOP (tracev, 2, 0, 0, 1, 0x2e)
-/* We need something here just to make the tables come out ok.  */
 DEFOP (invalid, 0, 0, 0, 0, 0x2f)
 DEFOP (trace16, 2, 0, 1, 1, 0x30)
-/* We need something here just to make the tables come out ok.  */
-DEFOP (invalid2, 0, 0, 0, 0, 0x31)
-/* The "consumed" number for pick is wrong, but there's no way to
-   express the right thing.  */
+DEFOP (printf, 0, 0, 0, 0, 0x31)
 DEFOP (pick, 1, 0, 0, 1, 0x32)
 DEFOP (rot, 0, 0, 3, 3, 0x33)
--- a/printcmd.c
+++ b/printcmd.c
@@ -50,6 +50,7 @@
 #include "charset.h"
 #include "arch-utils.h"
 #include "cli/cli-utils.h"
+#include "printcmd.h"
 
 #ifdef TUI
 #include "tui/tui.h"		/* For tui_active et al.   */
@@ -1984,10 +1985,9 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
-
-static void
-ui_printf (char *arg, struct ui_file *stream)
+void
+string_printf (char *arg, struct ui_file *stream, printf_callback callback,
+	       void *loc_v, void *aexpr_v)
 {
   char *f = NULL;
   char *s = arg;
@@ -1998,6 +1998,8 @@ ui_printf (char *arg, struct ui_file *st
   int nargs = 0;
   int allocated_args = 20;
   struct cleanup *old_cleanups;
+  struct bp_location *loc = loc_v;
+  struct agent_expr *aexpr = aexpr_v;
 
   val_args = xmalloc (allocated_args * sizeof (struct value *));
   old_cleanups = make_cleanup (free_current_contents, &val_args);
@@ -2316,26 +2318,42 @@ ui_printf (char *arg, struct ui_file *st
     /* Now, parse all arguments and evaluate them.
        Store the VALUEs in VAL_ARGS.  */
 
+    if (callback)
+      current_substring = substrings;
     while (*s != '\0')
       {
 	char *s1;
 
+	s1 = s;
 	if (nargs == allocated_args)
 	  val_args = (struct value **) xrealloc ((char *) val_args,
 						 (allocated_args *= 2)
 						 * sizeof (struct value *));
-	s1 = s;
-	val_args[nargs] = parse_to_comma_and_eval (&s1);
+	if (callback)
+	  {
+	    if (nargs >= nargs_wanted)
+	      error (_("Wrong number of arguments for specified "
+		       "format-string"));
+	    callback (current_substring, &s1, loc, aexpr);
+	    current_substring += strlen (current_substring) + 1;
+	  }
+	else
+	  val_args[nargs] = parse_to_comma_and_eval (&s1);
 
 	nargs++;
 	s = s1;
 	if (*s == ',')
 	  s++;
       }
+    if (callback)
+      callback (last_arg, NULL, loc, aexpr);
 
     if (nargs != nargs_wanted)
       error (_("Wrong number of arguments for specified format-string"));
 
+    if (!stream)
+      goto after_print;
+
     /* Now actually print them.  */
     current_substring = substrings;
     for (i = 0; i < nargs; i++)
@@ -2690,15 +2708,17 @@ ui_printf (char *arg, struct ui_file *st
        by default, which will warn here if there is no argument.  */
     fprintf_filtered (stream, last_arg, 0);
   }
+
+after_print:
   do_cleanups (old_cleanups);
 }
 
 /* Implement the "printf" command.  */
 
-static void
+void
 printf_command (char *arg, int from_tty)
 {
-  ui_printf (arg, gdb_stdout);
+  string_printf (arg, gdb_stdout, NULL, NULL, NULL);
 }
 
 /* Implement the "eval" command.  */
@@ -2710,7 +2730,7 @@ eval_command (char *arg, int from_tty)
   struct cleanup *cleanups = make_cleanup_ui_file_delete (ui_out);
   char *expanded;
 
-  ui_printf (arg, ui_out);
+  string_printf (arg, ui_out, NULL, NULL, NULL);
 
   expanded = ui_file_xstrdup (ui_out, NULL);
   make_cleanup (xfree, expanded);
--- /dev/null
+++ b/printcmd.h
@@ -0,0 +1,30 @@
+/* Print values for GNU debugger GDB.
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef _PRINTCMD_H_
+#define _PRINTCMD_H_
+
+extern void printf_command (char *arg, int from_tty);
+typedef void (printf_callback) (char *fbuf, char **expp, void *loc_v,
+				void *aexpr_v);
+extern void string_printf (char *arg, struct ui_file *stream,
+			   printf_callback callback, void *loc_v,
+			   void *aexpr_v);
+
+#endif /* _PRINTCMD_H_ */
--- a/tracepoint.c
+++ b/tracepoint.c
@@ -52,6 +52,7 @@
 #include "ax-gdb.h"
 #include "memrange.h"
 #include "exceptions.h"
+#include "printcmd.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -764,6 +765,28 @@ validate_actionline (char **line, struct
 	error (_("while-stepping step count `%s' is malformed."), *line);
     }
 
+  else if (cmd_cfunc_eq (c, printf_command))
+    {
+      char fbuf[101];
+
+      for (loc = t->base.loc; loc; loc = loc->next)
+	{
+	  int nargs;
+	  aexpr = new_agent_expr (loc->gdbarch, loc->address);
+	  old_chain = make_cleanup_free_agent_expr (aexpr);
+	  string_printf (p, NULL, gen_printf_expr_callback,
+			 loc, aexpr);
+	  ax_simple (aexpr, aop_end);
+	  /* The agent expr include expr for arguments, format string, 1 byte
+	     for aop_printf, 1 byte for the number of arguments, 1 byte for
+	     size of format string, 1 byte for blank after format string
+	     and 1 byte for aop_end.  */
+	  if (aexpr->len > MAX_AGENT_EXPR_LEN)
+	    error (_("Expression is too complicated."));
+	  do_cleanups (old_chain);
+	}
+    }
+
   else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
     ;
 
@@ -1475,6 +1498,22 @@ encode_actions_1 (struct command_line *a
 	  encode_actions_1 (action->body_list[0], t, tloc, frame_reg,
 			    frame_offset, stepping_list, NULL);
 	}
+      else if (cmd_cfunc_eq (cmd, printf_command))
+	{
+          char fbuf[101];
+	  struct cleanup *old_chain = NULL;
+
+	  aexpr = new_agent_expr (tloc->gdbarch, tloc->address);
+	  old_chain = make_cleanup_free_agent_expr (aexpr);
+	  string_printf (action_exp, NULL, gen_printf_expr_callback,
+			 tloc, aexpr);
+	  ax_simple (aexpr, aop_end);
+
+	  ax_reqs (aexpr);
+	  report_agent_reqs_errors (aexpr);
+	  discard_cleanups (old_chain);
+	  add_aexpr (collect, aexpr);
+	}
       else
 	error (_("Invalid tracepoint command '%s'"), action->line);
     }				/* for */
-------------- next part --------------
---
 Makefile.in   |    1 
 ax-gdb.c      |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-gdb.h      |    2 +
 ax-general.c  |   53 +++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h          |    2 +
 common/ax.def |    6 -----
 printcmd.c    |   38 ++++++++++++++++++++++++++++---------
 printcmd.h    |   30 +++++++++++++++++++++++++++++
 tracepoint.c  |   39 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 209 insertions(+), 21 deletions(-)

--- a/Makefile.in
+++ b/Makefile.in
@@ -813,6 +813,7 @@ i386-darwin-tdep.h i386-nat.h linux-reco
 osdata.h procfs.h python/py-event.h python/py-events.h python/py-stopevent.h \
 python/python-internal.h python/python.h ravenscar-thread.h record.h \
 solib-darwin.h solib-ia64-hpux.h solib-spu.h windows-nat.h xcoffread.h \
+printcmd.h \
 gnulib/extra/arg-nonnull.h gnulib/extra/c++defs.h gnulib/extra/warn-on-use.h \
 gnulib/stddef.in.h inline-frame.h
 
--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -2445,6 +2445,65 @@ gen_eval_for_expr (CORE_ADDR scope, stru
   return ax;
 }
 
+void
+gen_printf_expr_callback (char *fbuf, char **expp, void *loc_v, void *aexpr_v)
+{
+  struct bp_location	*loc = loc_v;
+  struct agent_expr	*aexpr = aexpr_v;
+
+  if (expp)
+    {
+      struct cleanup *old_chain = NULL;
+      struct expression *expr = NULL;
+      union exp_element *pc;
+      struct axs_value value;
+
+      expr = parse_exp_1 (expp, block_for_pc (loc->address), 1);
+      old_chain = make_cleanup (free_current_contents, &expr);
+
+      pc = expr->elts;
+      trace_kludge = 0;
+      value.optimized_out = 0;
+      gen_expr (expr, &pc, aexpr, &value);
+
+      if (value.optimized_out)
+        error (_("value has been optimized out"));
+      switch (value.kind)
+        {
+	case axs_lvalue_memory:
+	  if (TYPE_CODE (value.type) != TYPE_CODE_ARRAY)
+	    {
+	      int length = TYPE_LENGTH (check_typedef (value.type));
+	      switch (length)
+		{
+		case 4:
+		  ax_simple (aexpr, aop_ref32);
+		  break;
+		case 8:
+		  ax_simple (aexpr, aop_ref64);
+		  break;
+		default:
+		  error (_("Size of value is not OK."));
+		  break;
+		}
+	    }
+	  break;
+	case axs_lvalue_register:
+	  ax_reg (aexpr, value.u.reg);
+	  break;
+        }
+
+      do_cleanups (old_chain);
+    }
+
+  ax_simple (aexpr, aop_printf);
+  if (expp)
+    ax_simple (aexpr, 1);
+  else
+    ax_simple (aexpr, 0);
+  ax_memcpy (aexpr, fbuf, strlen (fbuf) + 1);
+}
+
 static void
 agent_command (char *exp, int from_tty)
 {
--- a/ax-gdb.h
+++ b/ax-gdb.h
@@ -108,6 +108,8 @@ extern struct agent_expr *gen_trace_for_
 
 extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
 
+extern void gen_printf_expr_callback (char *, char **, void *, void *);
+
 extern int trace_kludge;
 
 #endif /* AX_GDB_H */
--- a/ax-general.c
+++ b/ax-general.c
@@ -331,6 +331,14 @@ ax_tsv (struct agent_expr *x, enum agent
   x->buf[x->len + 2] = (num) & 0xff;
   x->len += 3;
 }
+
+void
+ax_memcpy (struct agent_expr *x, const void *src, size_t n)
+{
+  grow_expr (x, n);
+  memcpy (x->buf + x->len, src, n);
+  x->len += n;
+}
 

 
 
@@ -369,6 +377,7 @@ ax_print (struct ui_file *f, struct agen
   for (i = 0; i < x->len;)
     {
       enum agent_op op = x->buf[i];
+      int op_size;
 
       if (op >= (sizeof (aop_map) / sizeof (aop_map[0]))
 	  || !aop_map[op].name)
@@ -377,7 +386,19 @@ ax_print (struct ui_file *f, struct agen
 	  i++;
 	  continue;
 	}
-      if (i + 1 + aop_map[op].op_size > x->len)
+      if (op == aop_printf)
+        {
+	  if (i + 2 >= x->len)
+	    {
+	      fprintf_filtered (f, _("%3d  <bad opcode %02x>\n"), i, op);
+	      i++;
+	      continue;
+	    }
+	  op_size = 1 + strlen (x->buf + i + 2) + 1;
+	}
+      else
+	op_size = aop_map[op].op_size;
+      if (i + 1 + op_size > x->len)
 	{
 	  fprintf_filtered (f, _("%3d  <incomplete opcode %s>\n"),
 			    i, aop_map[op].name);
@@ -385,15 +406,15 @@ ax_print (struct ui_file *f, struct agen
 	}
 
       fprintf_filtered (f, "%3d  %s", i, aop_map[op].name);
-      if (aop_map[op].op_size > 0)
+      if (op_size > 0)
 	{
 	  fputs_filtered (" ", f);
 
 	  print_longest (f, 'd', 0,
-			 read_const (x, i + 1, aop_map[op].op_size));
+			 read_const (x, i + 1, op_size));
 	}
       fprintf_filtered (f, "\n");
-      i += 1 + aop_map[op].op_size;
+      i += 1 + op_size;
 
       is_float = (op == aop_float);
     }
@@ -461,6 +482,8 @@ ax_reqs (struct agent_expr *ax)
   /* Pointer to a description of the present op.  */
   struct aop_map *op;
 
+  int op_size = 0, consumed = 0;
+
   memset (targets, 0, ax->len * sizeof (targets[0]));
   memset (boundary, 0, ax->len * sizeof (boundary[0]));
 
@@ -468,7 +491,7 @@ ax_reqs (struct agent_expr *ax)
   ax->flaw = agent_flaw_none;
   ax->max_data_size = 0;
 
-  for (i = 0; i < ax->len; i += 1 + op->op_size)
+  for (i = 0; i < ax->len; i += 1 + op_size)
     {
       if (ax->buf[i] > (sizeof (aop_map) / sizeof (aop_map[0])))
 	{
@@ -484,7 +507,23 @@ ax_reqs (struct agent_expr *ax)
 	  return;
 	}
 
-      if (i + 1 + op->op_size > ax->len)
+      if (ax->buf[i] == aop_printf)
+        {
+	  if (i + 2 >= ax->len)
+	    {
+	      ax->flaw = agent_flaw_incomplete_instruction;
+	      return;
+	    }
+	  consumed = ax->buf[i + 1];
+	  op_size = 1 + strlen (ax->buf + i + 2) + 1;
+	}
+      else
+        {
+	  op_size = op->op_size;
+	  consumed = op->consumed;
+        }
+
+      if (i + 1 + op_size > ax->len)
 	{
 	  ax->flaw = agent_flaw_incomplete_instruction;
 	  return;
@@ -502,7 +541,7 @@ ax_reqs (struct agent_expr *ax)
       boundary[i] = 1;
       heights[i] = height;
 
-      height -= op->consumed;
+      height -= consumed;
       if (height < ax->min_height)
 	ax->min_height = height;
       height += op->produced;
--- a/ax.h
+++ b/ax.h
@@ -213,6 +213,8 @@ extern void ax_reg_mask (struct agent_ex
 
 /* Assemble code to operate on a trace state variable.  */
 extern void ax_tsv (struct agent_expr *expr, enum agent_op op, int num);
+
+extern void ax_memcpy (struct agent_expr *x, const void *src, size_t n);
 

 
 /* Functions for printing out expressions, and otherwise debugging
--- a/common/ax.def
+++ b/common/ax.def
@@ -86,12 +86,8 @@ DEFOP (swap, 0, 0, 2, 2, 0x2b)
 DEFOP (getv, 2, 0, 0, 1, 0x2c)
 DEFOP (setv, 2, 0, 0, 1, 0x2d)
 DEFOP (tracev, 2, 0, 0, 1, 0x2e)
-/* We need something here just to make the tables come out ok.  */
 DEFOP (invalid, 0, 0, 0, 0, 0x2f)
 DEFOP (trace16, 2, 0, 1, 1, 0x30)
-/* We need something here just to make the tables come out ok.  */
-DEFOP (invalid2, 0, 0, 0, 0, 0x31)
-/* The "consumed" number for pick is wrong, but there's no way to
-   express the right thing.  */
+DEFOP (printf, 0, 0, 0, 0, 0x31)
 DEFOP (pick, 1, 0, 0, 1, 0x32)
 DEFOP (rot, 0, 0, 3, 3, 0x33)
--- a/printcmd.c
+++ b/printcmd.c
@@ -50,6 +50,7 @@
 #include "charset.h"
 #include "arch-utils.h"
 #include "cli/cli-utils.h"
+#include "printcmd.h"
 
 #ifdef TUI
 #include "tui/tui.h"		/* For tui_active et al.   */
@@ -1967,10 +1968,9 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
-
-static void
-ui_printf (char *arg, struct ui_file *stream)
+void
+string_printf (char *arg, struct ui_file *stream, printf_callback callback,
+	       void *loc_v, void *aexpr_v)
 {
   char *f = NULL;
   char *s = arg;
@@ -1981,6 +1981,8 @@ ui_printf (char *arg, struct ui_file *st
   int nargs = 0;
   int allocated_args = 20;
   struct cleanup *old_cleanups;
+  struct bp_location *loc = loc_v;
+  struct agent_expr *aexpr = aexpr_v;
 
   val_args = xmalloc (allocated_args * sizeof (struct value *));
   old_cleanups = make_cleanup (free_current_contents, &val_args);
@@ -2299,26 +2301,42 @@ ui_printf (char *arg, struct ui_file *st
     /* Now, parse all arguments and evaluate them.
        Store the VALUEs in VAL_ARGS.  */
 
+    if (callback)
+      current_substring = substrings;
     while (*s != '\0')
       {
 	char *s1;
 
+	s1 = s;
 	if (nargs == allocated_args)
 	  val_args = (struct value **) xrealloc ((char *) val_args,
 						 (allocated_args *= 2)
 						 * sizeof (struct value *));
-	s1 = s;
-	val_args[nargs] = parse_to_comma_and_eval (&s1);
+	if (callback)
+	  {
+	    if (nargs >= nargs_wanted)
+	      error (_("Wrong number of arguments for specified "
+		       "format-string"));
+	    callback (current_substring, &s1, loc, aexpr);
+	    current_substring += strlen (current_substring) + 1;
+	  }
+	else
+	  val_args[nargs] = parse_to_comma_and_eval (&s1);
 
 	nargs++;
 	s = s1;
 	if (*s == ',')
 	  s++;
       }
+    if (callback)
+      callback (last_arg, NULL, loc, aexpr);
 
     if (nargs != nargs_wanted)
       error (_("Wrong number of arguments for specified format-string"));
 
+    if (!stream)
+      goto after_print;
+
     /* Now actually print them.  */
     current_substring = substrings;
     for (i = 0; i < nargs; i++)
@@ -2673,15 +2691,17 @@ ui_printf (char *arg, struct ui_file *st
        by default, which will warn here if there is no argument.  */
     fprintf_filtered (stream, last_arg, 0);
   }
+
+after_print:
   do_cleanups (old_cleanups);
 }
 
 /* Implement the "printf" command.  */
 
-static void
+void
 printf_command (char *arg, int from_tty)
 {
-  ui_printf (arg, gdb_stdout);
+  string_printf (arg, gdb_stdout, NULL, NULL, NULL);
 }
 
 /* Implement the "eval" command.  */
@@ -2693,7 +2713,7 @@ eval_command (char *arg, int from_tty)
   struct cleanup *cleanups = make_cleanup_ui_file_delete (ui_out);
   char *expanded;
 
-  ui_printf (arg, ui_out);
+  string_printf (arg, ui_out, NULL, NULL, NULL);
 
   expanded = ui_file_xstrdup (ui_out, NULL);
   make_cleanup (xfree, expanded);
--- /dev/null
+++ b/printcmd.h
@@ -0,0 +1,30 @@
+/* Print values for GNU debugger GDB.
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   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/>.  */
+
+#ifndef _PRINTCMD_H_
+#define _PRINTCMD_H_
+
+extern void printf_command (char *arg, int from_tty);
+typedef void (printf_callback) (char *fbuf, char **expp, void *loc_v,
+				void *aexpr_v);
+extern void string_printf (char *arg, struct ui_file *stream,
+			   printf_callback callback, void *loc_v,
+			   void *aexpr_v);
+
+#endif /* _PRINTCMD_H_ */
--- a/tracepoint.c
+++ b/tracepoint.c
@@ -52,6 +52,7 @@
 #include "ax-gdb.h"
 #include "memrange.h"
 #include "exceptions.h"
+#include "printcmd.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -762,6 +763,28 @@ validate_actionline (char **line, struct
 	error (_("while-stepping step count `%s' is malformed."), *line);
     }
 
+  else if (cmd_cfunc_eq (c, printf_command))
+    {
+      char fbuf[101];
+
+      for (loc = t->loc; loc; loc = loc->next)
+	{
+	  int nargs;
+	  aexpr = new_agent_expr (loc->gdbarch, loc->address);
+	  old_chain = make_cleanup_free_agent_expr (aexpr);
+	  string_printf (p, NULL, gen_printf_expr_callback,
+			 loc, aexpr);
+	  ax_simple (aexpr, aop_end);
+	  /* The agent expr include expr for arguments, format string, 1 byte
+	     for aop_printf, 1 byte for the number of arguments, 1 byte for
+	     size of format string, 1 byte for blank after format string
+	     and 1 byte for aop_end.  */
+	  if (aexpr->len > MAX_AGENT_EXPR_LEN)
+	    error (_("Expression is too complicated."));
+	  do_cleanups (old_chain);
+	}
+    }
+
   else if (cmd_cfunc_eq (c, end_actions_pseudocommand))
     ;
 
@@ -1473,6 +1496,22 @@ encode_actions_1 (struct command_line *a
 	  encode_actions_1 (action->body_list[0], t, tloc, frame_reg,
 			    frame_offset, stepping_list, NULL);
 	}
+      else if (cmd_cfunc_eq (cmd, printf_command))
+	{
+          char fbuf[101];
+	  struct cleanup *old_chain = NULL;
+
+	  aexpr = new_agent_expr (tloc->gdbarch, tloc->address);
+	  old_chain = make_cleanup_free_agent_expr (aexpr);
+	  string_printf (action_exp, NULL, gen_printf_expr_callback,
+			 tloc, aexpr);
+	  ax_simple (aexpr, aop_end);
+
+	  ax_reqs (aexpr);
+	  report_agent_reqs_errors (aexpr);
+	  discard_cleanups (old_chain);
+	  add_aexpr (collect, aexpr);
+	}
       else
 	error (_("Invalid tracepoint command '%s'"), action->line);
     }				/* for */


More information about the Gdb-patches mailing list