public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] tracepoint: add new trace command "printf"[0] gdb
@ 2011-01-03 16:29 Hui Zhu
  2011-01-03 19:21 ` Doug Evans
  0 siblings, 1 reply; 16+ messages in thread
From: Hui Zhu @ 2011-01-03 16:29 UTC (permalink / raw)
  To: gdb-patches

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

Hi,

I add a new patch add new trace command "printf".
This printf is same with the simple gdb command, it can do formatted
output.  But it will happen in gdbserver part when it break by a
tracepoint.
Then the user can get the format value that he want in tracepint.  It
will be more easy and clear to handle the bug sometimes.

For example:
(gdb) trace 16
During symbol reading, DW_AT_name missing from DW_TAG_base_type.
Tracepoint 1 at 0x4004c3: file 1.c, line 16.
(gdb) tvariable $c
Trace state variable $c created, with initial value 0.
(gdb) actions
Enter actions for tracepoint 1, one per line.
End with a line saying just "end".
>printf "%d 0x%lx %d\n",$c=$c+1,$rax,argc
>end
(gdb) target remote localhost:1234
(gdb) tstart
(gdb) c

gdbserver/gdbserver  localhost:1234 ./a.out
Process ./a.out created; pid = 25804
Listening on port 1234
Remote debugging from host 127.0.0.1
1 0x7f2cb8711ec8 1
2 0x7f2cb8711ec8 2
3 0x7f2cb8711ec8 3
4 0x7f2cb8711ec8 4
5 0x7f2cb8711ec8 5
6 0x7f2cb8711ec8 6
7 0x7f2cb8711ec8 7


About the command part, I use the "printf" instead add a new commands
because the behavior of  this command is same with printf. They will
use the same function string_printf(update from ui_printf) to parse
the command arg.

To support the printf command, I add a new agent expression 0x31
printf, the format for it is:
0x31(op_printf) + arg(1/0) + format string with end by 0x0.
The arg is the number of argument of printf.  It will only be 1 (one
argument) or 0 (no argument).  I make it cannot have more than one
argument because I cannot found a good way to handle va_list that send
arguments to vprintf.
The format string with end by 0x0 is the simple format string.  It end
by 0x0 then the gdbserver can use it directly.

I didn't make the patch for doc because I am still not sure about
every part of this patch.  When this patch is OK.  I will make doc
patch for it.

Thanks,
Hui

2011-01-04  Hui Zhu  <teawater@gmail.com>

	* ax-gdb.c (gen_printf_expr_callback): New function.
	* ax-general.c (ax_memcpy): New function.
	(aop_map): Add new entry for "printf".
	(ax_print): Handle "printf".
	(ax_reqs): Ditto.
	* ax.h (agent_op): Add aop_printf.
	(ax_memcpy): Forward declare.
	* printcmd.c (printf_callback): New typedef.
	(string_printf): New function from ui_printf.
	(ui_printf): Call string_printf.
	(printf_command): Remove static.
	* tracepoint.c (printf_command, gen_printf_expr_callback,
	printf_callback, string_printf): Forward declares.
	(validate_actionline, encode_actions_1): handle printf_command.

[-- Attachment #2: tp_print.txt --]
[-- Type: text/plain, Size: 10249 bytes --]

---
 ax-gdb.c     |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-general.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h         |    3 +++
 printcmd.c   |   41 +++++++++++++++++++++++++++++++++++------
 tracepoint.c |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 189 insertions(+), 13 deletions(-)

--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -2435,6 +2435,63 @@ gen_eval_for_expr (CORE_ADDR scope, stru
   return ax;
 }
 
+void
+gen_printf_expr_callback (char *fbuf, char **expp, struct bp_location *loc,
+			  struct agent_expr *aexpr)
+{
+  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:
+	  {
+	    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-general.c
+++ b/ax-general.c
@@ -313,6 +313,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;
+}
 \f
 
 
@@ -370,6 +378,7 @@ struct aop_map aop_map[] =
   {"tracev", 2, 0, 0, 1},	/* 0x2e */
   {0, 0, 0, 0, 0},		/* 0x2f */
   {"trace16", 2, 0, 1, 1},	/* 0x30 */
+  {"printf", 0, 0, 0, 0},	/* 0x31 */
 };
 
 
@@ -395,6 +404,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)
@@ -403,7 +413,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);
@@ -411,15 +433,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);
     }
@@ -487,6 +509,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]));
 
@@ -494,7 +518,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])))
 	{
@@ -510,7 +534,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;
@@ -528,7 +568,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
@@ -204,6 +204,7 @@ enum agent_op
     aop_setv = 0x2d,
     aop_tracev = 0x2e,
     aop_trace16 = 0x30,
+    aop_printf = 0x31,
     aop_last
   };
 \f
@@ -260,6 +261,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);
 \f
 
 /* Functions for printing out expressions, and otherwise debugging
--- a/printcmd.c
+++ b/printcmd.c
@@ -1963,10 +1963,13 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
+typedef void (printf_callback) (char *fbuf, char **expp,
+				struct bp_location *loc,
+				struct agent_expr *aexpr);
 
-static void
-ui_printf (char *arg, struct ui_file *stream)
+void
+string_printf (char *arg, struct ui_file *stream, printf_callback callback,
+	       struct bp_location *loc, struct agent_expr *aexpr)
 {
   char *f = NULL;
   char *s = arg;
@@ -2298,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++)
@@ -2672,12 +2691,22 @@ 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.  */
+/* printf "printf format string" ARG to STREAM.  */
 
 static void
+ui_printf (char *arg, struct ui_file *stream)
+{
+  string_printf (arg, stream, NULL, NULL, NULL);
+}
+
+/* Implement the "printf" command.  */
+
+void
 printf_command (char *arg, int from_tty)
 {
   ui_printf (arg, gdb_stdout);
--- a/tracepoint.c
+++ b/tracepoint.c
@@ -187,6 +187,15 @@ extern void send_disconnected_tracing_va
 static void free_uploaded_tps (struct uploaded_tp **utpp);
 static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
 
+extern void printf_command (char *arg, int from_tty);
+extern void gen_printf_expr_callback (char **expp, struct bp_location *loc,
+				      struct agent_expr *aexpr);
+typedef void (printf_callback) (char **expp, struct bp_location *loc,
+				struct agent_expr *aexpr);
+extern void string_printf (char *arg, struct ui_file *stream,
+			   printf_callback callback, struct bp_location *loc,
+			   struct agent_expr *aexpr);
+
 
 extern void _initialize_tracepoint (void);
 
@@ -719,6 +728,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))
     ;
 
@@ -1430,6 +1461,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 */

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-03 16:29 [PATCH] tracepoint: add new trace command "printf"[0] gdb Hui Zhu
@ 2011-01-03 19:21 ` Doug Evans
  2011-01-04  4:34   ` Hui Zhu
  0 siblings, 1 reply; 16+ messages in thread
From: Doug Evans @ 2011-01-03 19:21 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches

On Mon, Jan 3, 2011 at 8:29 AM, Hui Zhu <teawater@gmail.com> wrote:
> Hi,
>
> I add a new patch add new trace command "printf".
> This printf is same with the simple gdb command, it can do formatted
> output.  But it will happen in gdbserver part when it break by a
> tracepoint.
> Then the user can get the format value that he want in tracepint.  It
> will be more easy and clear to handle the bug sometimes.

One could do this with a breakpoint and attaching commands to the
breakpoint too, right?
Or are they too cumbersome for the intended use case?
[Extending tracepoints like this doesn't seem justified yet, so I'm
just looking for more data.]

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-03 19:21 ` Doug Evans
@ 2011-01-04  4:34   ` Hui Zhu
  2011-01-04  6:19     ` Doug Evans
  0 siblings, 1 reply; 16+ messages in thread
From: Hui Zhu @ 2011-01-04  4:34 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On Tue, Jan 4, 2011 at 03:21, Doug Evans <dje@google.com> wrote:
> On Mon, Jan 3, 2011 at 8:29 AM, Hui Zhu <teawater@gmail.com> wrote:
>> Hi,
>>
>> I add a new patch add new trace command "printf".
>> This printf is same with the simple gdb command, it can do formatted
>> output.  But it will happen in gdbserver part when it break by a
>> tracepoint.
>> Then the user can get the format value that he want in tracepint.  It
>> will be more easy and clear to handle the bug sometimes.
>
> One could do this with a breakpoint and attaching commands to the
> breakpoint too, right?
> Or are they too cumbersome for the intended use case?
> [Extending tracepoints like this doesn't seem justified yet, so I'm
> just looking for more data.]
>

Thanks Doug.

I agree with the tracepoint "printf" will be very close with add a
breakpoint commands "printf" if the gdb and gdbserver in same pc.

But I have some status need the tracepoint "printf" that breakpoint is
not very fit with.
1. The gdb and gdbserver connect through a low speed net.  Sometimes,
the debug target that I use is in the other side of the earth.
The breakpoint commands "printf" is too slow for that issue, because
each time the inferior is break by the breakpoint, gdbserver need send
the rsp package to gdb, and gdb will get the data that "printf" need
though low speed net from gdbsever.  And sometime, it will disconnect.
But if through tracepoint, I will not have this trouble.  I can "set
disconnected-tracing on" to handle the network disconnect issue.  I
still need to get the value from inferior through tfind and other
commands.  It is still be affect by the low speed network.  So I make
the tracepoint "printf" to handle it.

2.  KGTP(https://code.google.com/p/kgtp/) just support the gdb
tracepoint rsp commands.  For not stop the Linux the Kernel.  It
doesn't support the breakpoint.
So if it want directly show the Kernel val value, it need "printf".
This printf will be very powerful that can set most part of Kernel and
we can set condition for it.
And in https://code.google.com/p/kgtp/wiki/HOWTO#Offline_debug,  we
can dump the gdbrsp package to a file and send to Kernel.  Then kernel
can be debug without a local gdb or a remote connect.   But user still
need copy the trace file to pc that have GDB.  But if support
tracepoint "printf", we will not need do that.


Thanks,
Hui

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-04  4:34   ` Hui Zhu
@ 2011-01-04  6:19     ` Doug Evans
  2011-01-04 12:07       ` Hui Zhu
                         ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Doug Evans @ 2011-01-04  6:19 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches

On Mon, Jan 3, 2011 at 8:33 PM, Hui Zhu <teawater@gmail.com> wrote:
> On Tue, Jan 4, 2011 at 03:21, Doug Evans <dje@google.com> wrote:
>> On Mon, Jan 3, 2011 at 8:29 AM, Hui Zhu <teawater@gmail.com> wrote:
>>> Hi,
>>>
>>> I add a new patch add new trace command "printf".
>>> This printf is same with the simple gdb command, it can do formatted
>>> output.  But it will happen in gdbserver part when it break by a
>>> tracepoint.
>>> Then the user can get the format value that he want in tracepint.  It
>>> will be more easy and clear to handle the bug sometimes.
>>
>> One could do this with a breakpoint and attaching commands to the
>> breakpoint too, right?
>> Or are they too cumbersome for the intended use case?
>> [Extending tracepoints like this doesn't seem justified yet, so I'm
>> just looking for more data.]
>>
>
> Thanks Doug.
>
> I agree with the tracepoint "printf" will be very close with add a
> breakpoint commands "printf" if the gdb and gdbserver in same pc.
>
> But I have some status need the tracepoint "printf" that breakpoint is
> not very fit with.
> 1. The gdb and gdbserver connect through a low speed net.  Sometimes,
> the debug target that I use is in the other side of the earth.
> The breakpoint commands "printf" is too slow for that issue, because
> each time the inferior is break by the breakpoint, gdbserver need send
> the rsp package to gdb, and gdb will get the data that "printf" need
> though low speed net from gdbsever.  And sometime, it will disconnect.
> But if through tracepoint, I will not have this trouble.  I can "set
> disconnected-tracing on" to handle the network disconnect issue.  I
> still need to get the value from inferior through tfind and other
> commands.  It is still be affect by the low speed network.  So I make
> the tracepoint "printf" to handle it.
>
> 2.  KGTP(https://code.google.com/p/kgtp/) just support the gdb
> tracepoint rsp commands.  For not stop the Linux the Kernel.  It
> doesn't support the breakpoint.
> So if it want directly show the Kernel val value, it need "printf".
> This printf will be very powerful that can set most part of Kernel and
> we can set condition for it.
> And in https://code.google.com/p/kgtp/wiki/HOWTO#Offline_debug,  we
> can dump the gdbrsp package to a file and send to Kernel.  Then kernel
> can be debug without a local gdb or a remote connect.   But user still
> need copy the trace file to pc that have GDB.  But if support
> tracepoint "printf", we will not need do that.

Thanks for the additional info.
I still think this is kinda orthogonal to tracepoint functionality,
and thus implementing it on top of tracepoints is a hack, but I
understand better why you want it.

[for reference sake]
To me this is a subset of a bigger feature set that is missing:
partitioning of the things that can be accomplished by gdbserver from
the setup that is needed (IOW separate the heavy lifting of parsing
debug info and translating a user query into, for example, an agent
expression (the gdb side) from the processing of that query when the
breakpoint(/tracepoint) is hit (the gdbserver side).
Plus it might be useful to not require a gdb/gdbserver connection to
get things started, e.g., convey the tracepoint info (and anything
else) to gdbserver from a local source.
[I'm using "query" loosely here.  I'm using "gdbserver" loosely too:
anything that looks like gdbserver to gdb will do.]

AIUI, agent expressions are currently only used for tracepoints (I
thought they might be used for fast conditional breakpoints but I
can't find it).  [If I'm wrong and agent exprs are used for other
things, great, we're already down this path.]  Are they useful for
more things?  [I don't know what, but if printf is useful, I can
imagine there being more things that are useful too.]
Thus it might be useful to take a step back before adding printf to tracepoints.
E.g. Another way to go would be to have a new kind of command list
that can be attached to breakpoints, commands that are executed on the
gdbserver side.

[One might think why not just add printf (and whatever else) to
tracepoints and leave it at that.  Tracepoints to me convey a specific
use-case and I'm not sure we should muddy that up.  But for now I
suppose printf could be sufficiently useful, so I'm not opposed to the
patch (pragmatic hacks are sometimes useful enough to justify their
existence).  This is not an approval though.   I can see the patch
needs at least a few changes, but before reviewing it I'd like to make
sure there is general agreement on this approach.  Someone else is
free to review and approve it of course.]

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-04  6:19     ` Doug Evans
@ 2011-01-04 12:07       ` Hui Zhu
  2011-01-05 17:24       ` Doug Evans
  2011-01-05 20:51       ` Stan Shebs
  2 siblings, 0 replies; 16+ messages in thread
From: Hui Zhu @ 2011-01-04 12:07 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches

On Tue, Jan 4, 2011 at 14:18, Doug Evans <dje@google.com> wrote:
> On Mon, Jan 3, 2011 at 8:33 PM, Hui Zhu <teawater@gmail.com> wrote:
>> On Tue, Jan 4, 2011 at 03:21, Doug Evans <dje@google.com> wrote:
>>> On Mon, Jan 3, 2011 at 8:29 AM, Hui Zhu <teawater@gmail.com> wrote:
>>>> Hi,
>>>>
>>>> I add a new patch add new trace command "printf".
>>>> This printf is same with the simple gdb command, it can do formatted
>>>> output.  But it will happen in gdbserver part when it break by a
>>>> tracepoint.
>>>> Then the user can get the format value that he want in tracepint.  It
>>>> will be more easy and clear to handle the bug sometimes.
>>>
>>> One could do this with a breakpoint and attaching commands to the
>>> breakpoint too, right?
>>> Or are they too cumbersome for the intended use case?
>>> [Extending tracepoints like this doesn't seem justified yet, so I'm
>>> just looking for more data.]
>>>
>>
>> Thanks Doug.
>>
>> I agree with the tracepoint "printf" will be very close with add a
>> breakpoint commands "printf" if the gdb and gdbserver in same pc.
>>
>> But I have some status need the tracepoint "printf" that breakpoint is
>> not very fit with.
>> 1. The gdb and gdbserver connect through a low speed net.  Sometimes,
>> the debug target that I use is in the other side of the earth.
>> The breakpoint commands "printf" is too slow for that issue, because
>> each time the inferior is break by the breakpoint, gdbserver need send
>> the rsp package to gdb, and gdb will get the data that "printf" need
>> though low speed net from gdbsever.  And sometime, it will disconnect.
>> But if through tracepoint, I will not have this trouble.  I can "set
>> disconnected-tracing on" to handle the network disconnect issue.  I
>> still need to get the value from inferior through tfind and other
>> commands.  It is still be affect by the low speed network.  So I make
>> the tracepoint "printf" to handle it.
>>
>> 2.  KGTP(https://code.google.com/p/kgtp/) just support the gdb
>> tracepoint rsp commands.  For not stop the Linux the Kernel.  It
>> doesn't support the breakpoint.
>> So if it want directly show the Kernel val value, it need "printf".
>> This printf will be very powerful that can set most part of Kernel and
>> we can set condition for it.
>> And in https://code.google.com/p/kgtp/wiki/HOWTO#Offline_debug,  we
>> can dump the gdbrsp package to a file and send to Kernel.  Then kernel
>> can be debug without a local gdb or a remote connect.   But user still
>> need copy the trace file to pc that have GDB.  But if support
>> tracepoint "printf", we will not need do that.
>
> Thanks for the additional info.
> I still think this is kinda orthogonal to tracepoint functionality,
> and thus implementing it on top of tracepoints is a hack, but I
> understand better why you want it.
>
> [for reference sake]
> To me this is a subset of a bigger feature set that is missing:
> partitioning of the things that can be accomplished by gdbserver from
> the setup that is needed (IOW separate the heavy lifting of parsing
> debug info and translating a user query into, for example, an agent
> expression (the gdb side) from the processing of that query when the
> breakpoint(/tracepoint) is hit (the gdbserver side).
> Plus it might be useful to not require a gdb/gdbserver connection to
> get things started, e.g., convey the tracepoint info (and anything
> else) to gdbserver from a local source.
> [I'm using "query" loosely here.  I'm using "gdbserver" loosely too:
> anything that looks like gdbserver to gdb will do.]
>
> AIUI, agent expressions are currently only used for tracepoints (I
> thought they might be used for fast conditional breakpoints but I
> can't find it).  [If I'm wrong and agent exprs are used for other
> things, great, we're already down this path.]  Are they useful for
> more things?  [I don't know what, but if printf is useful, I can
> imagine there being more things that are useful too.]
> Thus it might be useful to take a step back before adding printf to tracepoints.
> E.g. Another way to go would be to have a new kind of command list
> that can be attached to breakpoints, commands that are executed on the
> gdbserver side.
>
> [One might think why not just add printf (and whatever else) to
> tracepoints and leave it at that.  Tracepoints to me convey a specific
> use-case and I'm not sure we should muddy that up.  But for now I
> suppose printf could be sufficiently useful, so I'm not opposed to the
> patch (pragmatic hacks are sometimes useful enough to justify their
> existence).  This is not an approval though.   I can see the patch
> needs at least a few changes, but before reviewing it I'd like to make
> sure there is general agreement on this approach.  Someone else is
> free to review and approve it of course.]
>

That is great.  Thanks Doug.,

Best,
Hui

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-04  6:19     ` Doug Evans
  2011-01-04 12:07       ` Hui Zhu
@ 2011-01-05 17:24       ` Doug Evans
  2011-01-05 18:18         ` Michael Snyder
  2011-01-05 20:51       ` Stan Shebs
  2 siblings, 1 reply; 16+ messages in thread
From: Doug Evans @ 2011-01-05 17:24 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches

On Mon, Jan 3, 2011 at 10:18 PM, Doug Evans <dje@google.com> wrote:
> [One might think why not just add printf (and whatever else) to
> tracepoints and leave it at that.  Tracepoints to me convey a specific
> use-case and I'm not sure we should muddy that up.  But for now I
> suppose printf could be sufficiently useful, so I'm not opposed to the
> patch (pragmatic hacks are sometimes useful enough to justify their
> existence).  This is not an approval though.   I can see the patch
> needs at least a few changes, but before reviewing it I'd like to make
> sure there is general agreement on this approach.  Someone else is
> free to review and approve it of course.]

I haven't heard comments from any other GMs.
Does anyone have a problem with adding some kind of printf to tracepoints?
Or does anyone have a problem with adding a new kind of command list
to breakpoints that is executed on the target?
[P.S. If you respond, IWBN to include your thoughts on why.]
I'm inclined to go with having some kind of printf in tracepoints for now.

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-05 17:24       ` Doug Evans
@ 2011-01-05 18:18         ` Michael Snyder
  2011-01-06  6:42           ` Hui Zhu
  0 siblings, 1 reply; 16+ messages in thread
From: Michael Snyder @ 2011-01-05 18:18 UTC (permalink / raw)
  To: Doug Evans; +Cc: Hui Zhu, gdb-patches

Doug Evans wrote:
> On Mon, Jan 3, 2011 at 10:18 PM, Doug Evans <dje@google.com> wrote:
>> [One might think why not just add printf (and whatever else) to
>> tracepoints and leave it at that.  Tracepoints to me convey a specific
>> use-case and I'm not sure we should muddy that up.  But for now I
>> suppose printf could be sufficiently useful, so I'm not opposed to the
>> patch (pragmatic hacks are sometimes useful enough to justify their
>> existence).  This is not an approval though.   I can see the patch
>> needs at least a few changes, but before reviewing it I'd like to make
>> sure there is general agreement on this approach.  Someone else is
>> free to review and approve it of course.]
> 
> I haven't heard comments from any other GMs.
> Does anyone have a problem with adding some kind of printf to tracepoints?
> Or does anyone have a problem with adding a new kind of command list
> to breakpoints that is executed on the target?
> [P.S. If you respond, IWBN to include your thoughts on why.]
> I'm inclined to go with having some kind of printf in tracepoints for now.

I don't quite understand the "use case" for printf in tracepoints.

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-04  6:19     ` Doug Evans
  2011-01-04 12:07       ` Hui Zhu
  2011-01-05 17:24       ` Doug Evans
@ 2011-01-05 20:51       ` Stan Shebs
  2011-01-06  6:43         ` Hui Zhu
  2 siblings, 1 reply; 16+ messages in thread
From: Stan Shebs @ 2011-01-05 20:51 UTC (permalink / raw)
  To: gdb-patches

On 1/3/11 10:18 PM, Doug Evans wrote:
> [for reference sake]
> To me this is a subset of a bigger feature set that is missing:
> partitioning of the things that can be accomplished by gdbserver from
> the setup that is needed (IOW separate the heavy lifting of parsing
> debug info and translating a user query into, for example, an agent
> expression (the gdb side) from the processing of that query when the
> breakpoint(/tracepoint) is hit (the gdbserver side).
> Plus it might be useful to not require a gdb/gdbserver connection to
> get things started, e.g., convey the tracepoint info (and anything
> else) to gdbserver from a local source.
> [I'm using "query" loosely here.  I'm using "gdbserver" loosely too:
> anything that looks like gdbserver to gdb will do.]

I'm actually working on a contract proposal to do a bunch of work in 
this area.

One of the specific ideas is to introduce a "dynamic printf" that works 
somewhat like what I think Hui Zhu was wanting; it stops the program at 
a location, runs the printf in gdbserver, and then continues.

Another one of the ideas is to use agent expressions to do target-side 
conditional breakpoints.  This is especially compelling for many-core 
targets, where we don't want 100 threads on 100 cores to be trying to 
get GDB to do 100 conditional expression evaluations all at once.

I didn't specifically propose to go beyond that, into general 
partitioning of command lists between host and target, although it's a 
very interesting direction.  The idea gets me to thinking about whether 
we should keep the command list form, or raise it to the level of a real 
language, or maybe support several - Mentor's EDGE debugger for instance 
uses a C syntax for its "codelets" ( 
http://www.mentor.com/embedded-software/resources/overview/codelets-15b9eaed-8e4b-43a2-aad5-c189cd7f2d68 
) even though they run on the host, and whether the language is C or 
Python, it seems useful to be able to inject real code bits into the 
target system.

Anyway, if we get the contract (fingers crossed!) then I expect we'll be 
putting up some proposals for discussion within the next couple of months.

I'll comment on the patch in a different message.

Stan

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-05 18:18         ` Michael Snyder
@ 2011-01-06  6:42           ` Hui Zhu
  0 siblings, 0 replies; 16+ messages in thread
From: Hui Zhu @ 2011-01-06  6:42 UTC (permalink / raw)
  To: Michael Snyder; +Cc: Doug Evans, gdb-patches

On Thu, Jan 6, 2011 at 02:17, Michael Snyder <msnyder@vmware.com> wrote:
> Doug Evans wrote:
>>
>> On Mon, Jan 3, 2011 at 10:18 PM, Doug Evans <dje@google.com> wrote:
>>>
>>> [One might think why not just add printf (and whatever else) to
>>> tracepoints and leave it at that.  Tracepoints to me convey a specific
>>> use-case and I'm not sure we should muddy that up.  But for now I
>>> suppose printf could be sufficiently useful, so I'm not opposed to the
>>> patch (pragmatic hacks are sometimes useful enough to justify their
>>> existence).  This is not an approval though.   I can see the patch
>>> needs at least a few changes, but before reviewing it I'd like to make
>>> sure there is general agreement on this approach.  Someone else is
>>> free to review and approve it of course.]
>>
>> I haven't heard comments from any other GMs.
>> Does anyone have a problem with adding some kind of printf to tracepoints?
>> Or does anyone have a problem with adding a new kind of command list
>> to breakpoints that is executed on the target?
>> [P.S. If you respond, IWBN to include your thoughts on why.]
>> I'm inclined to go with having some kind of printf in tracepoints for now.
>
> I don't quite understand the "use case" for printf in tracepoints.
>
>

http://sourceware.org/ml/gdb-patches/2011-01/msg00052.html

Wish this link can be helpful.  :)

Thanks,
Hui

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-05 20:51       ` Stan Shebs
@ 2011-01-06  6:43         ` Hui Zhu
  2011-01-28  5:54           ` Hui Zhu
  0 siblings, 1 reply; 16+ messages in thread
From: Hui Zhu @ 2011-01-06  6:43 UTC (permalink / raw)
  To: Stan Shebs; +Cc: gdb-patches

On Thu, Jan 6, 2011 at 04:51, Stan Shebs <stan@codesourcery.com> wrote:
> On 1/3/11 10:18 PM, Doug Evans wrote:
>>
>> [for reference sake]
>> To me this is a subset of a bigger feature set that is missing:
>> partitioning of the things that can be accomplished by gdbserver from
>> the setup that is needed (IOW separate the heavy lifting of parsing
>> debug info and translating a user query into, for example, an agent
>> expression (the gdb side) from the processing of that query when the
>> breakpoint(/tracepoint) is hit (the gdbserver side).
>> Plus it might be useful to not require a gdb/gdbserver connection to
>> get things started, e.g., convey the tracepoint info (and anything
>> else) to gdbserver from a local source.
>> [I'm using "query" loosely here.  I'm using "gdbserver" loosely too:
>> anything that looks like gdbserver to gdb will do.]
>
> I'm actually working on a contract proposal to do a bunch of work in this
> area.
>
> One of the specific ideas is to introduce a "dynamic printf" that works
> somewhat like what I think Hui Zhu was wanting; it stops the program at a
> location, runs the printf in gdbserver, and then continues.
>
> Another one of the ideas is to use agent expressions to do target-side
> conditional breakpoints.  This is especially compelling for many-core
> targets, where we don't want 100 threads on 100 cores to be trying to get
> GDB to do 100 conditional expression evaluations all at once.
>
> I didn't specifically propose to go beyond that, into general partitioning
> of command lists between host and target, although it's a very interesting
> direction.  The idea gets me to thinking about whether we should keep the
> command list form, or raise it to the level of a real language, or maybe
> support several - Mentor's EDGE debugger for instance uses a C syntax for
> its "codelets" (
> http://www.mentor.com/embedded-software/resources/overview/codelets-15b9eaed-8e4b-43a2-aad5-c189cd7f2d68
> ) even though they run on the host, and whether the language is C or Python,
> it seems useful to be able to inject real code bits into the target system.
>
> Anyway, if we get the contract (fingers crossed!) then I expect we'll be
> putting up some proposals for discussion within the next couple of months.
>
> I'll comment on the patch in a different message.
>
> Stan
>
>

That will be great!  Thanks Stan.

Hui

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-06  6:43         ` Hui Zhu
@ 2011-01-28  5:54           ` Hui Zhu
  2011-02-04 15:59             ` Hui Zhu
  0 siblings, 1 reply; 16+ messages in thread
From: Hui Zhu @ 2011-01-28  5:54 UTC (permalink / raw)
  To: gdb-patches ml; +Cc: Stan Shebs

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

On Thu, Jan 6, 2011 at 14:43, Hui Zhu <teawater@gmail.com> wrote:
> On Thu, Jan 6, 2011 at 04:51, Stan Shebs <stan@codesourcery.com> wrote:
>> On 1/3/11 10:18 PM, Doug Evans wrote:
>>>
>>> [for reference sake]
>>> To me this is a subset of a bigger feature set that is missing:
>>> partitioning of the things that can be accomplished by gdbserver from
>>> the setup that is needed (IOW separate the heavy lifting of parsing
>>> debug info and translating a user query into, for example, an agent
>>> expression (the gdb side) from the processing of that query when the
>>> breakpoint(/tracepoint) is hit (the gdbserver side).
>>> Plus it might be useful to not require a gdb/gdbserver connection to
>>> get things started, e.g., convey the tracepoint info (and anything
>>> else) to gdbserver from a local source.
>>> [I'm using "query" loosely here.  I'm using "gdbserver" loosely too:
>>> anything that looks like gdbserver to gdb will do.]
>>
>> I'm actually working on a contract proposal to do a bunch of work in this
>> area.
>>
>> One of the specific ideas is to introduce a "dynamic printf" that works
>> somewhat like what I think Hui Zhu was wanting; it stops the program at a
>> location, runs the printf in gdbserver, and then continues.
>>
>> Another one of the ideas is to use agent expressions to do target-side
>> conditional breakpoints.  This is especially compelling for many-core
>> targets, where we don't want 100 threads on 100 cores to be trying to get
>> GDB to do 100 conditional expression evaluations all at once.
>>
>> I didn't specifically propose to go beyond that, into general partitioning
>> of command lists between host and target, although it's a very interesting
>> direction.  The idea gets me to thinking about whether we should keep the
>> command list form, or raise it to the level of a real language, or maybe
>> support several - Mentor's EDGE debugger for instance uses a C syntax for
>> its "codelets" (
>> http://www.mentor.com/embedded-software/resources/overview/codelets-15b9eaed-8e4b-43a2-aad5-c189cd7f2d68
>> ) even though they run on the host, and whether the language is C or Python,
>> it seems useful to be able to inject real code bits into the target system.
>>
>> Anyway, if we get the contract (fingers crossed!) then I expect we'll be
>> putting up some proposals for discussion within the next couple of months.
>>
>> I'll comment on the patch in a different message.
>>
>> Stan
>>
>>
>
> That will be great!  Thanks Stan.
>
> Hui
>

Update follow the trunk.

Thanks,
Hui

2011-01-28  Hui Zhu  <teawater@gmail.com>

	* ax-gdb.c (gen_printf_expr_callback): New function.
	* ax-general.c (ax_memcpy): New function.
	(aop_map): Add new entry for "printf".
	(ax_print): Handle "printf".
	(ax_reqs): Ditto.
	* ax.h (agent_op): Add aop_printf.
	(ax_memcpy): Forward declare.
	* printcmd.c (printf_callback): New typedef.
	(string_printf): New function from ui_printf.
	(ui_printf): Call string_printf.
	(printf_command): Remove static.
	* tracepoint.c (printf_command, gen_printf_expr_callback,
	printf_callback, string_printf): Forward declares.
	(validate_actionline, encode_actions_1): handle printf_command.

[-- Attachment #2: tp_print.txt --]
[-- Type: text/plain, Size: 10249 bytes --]

---
 ax-gdb.c     |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-general.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h         |    3 +++
 printcmd.c   |   41 +++++++++++++++++++++++++++++++++++------
 tracepoint.c |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 189 insertions(+), 13 deletions(-)

--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -2446,6 +2446,63 @@ gen_eval_for_expr (CORE_ADDR scope, stru
   return ax;
 }
 
+void
+gen_printf_expr_callback (char *fbuf, char **expp, struct bp_location *loc,
+			  struct agent_expr *aexpr)
+{
+  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:
+	  {
+	    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-general.c
+++ b/ax-general.c
@@ -319,6 +319,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;
+}
 \f
 
 
@@ -376,6 +384,7 @@ struct aop_map aop_map[] =
   {"tracev", 2, 0, 0, 1},	/* 0x2e */
   {0, 0, 0, 0, 0},		/* 0x2f */
   {"trace16", 2, 0, 1, 1},	/* 0x30 */
+  {"printf", 0, 0, 0, 0},	/* 0x31 */
 };
 
 
@@ -401,6 +410,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)
@@ -409,7 +419,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);
@@ -417,15 +439,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);
     }
@@ -493,6 +515,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]));
 
@@ -500,7 +524,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])))
 	{
@@ -516,7 +540,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;
@@ -534,7 +574,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
@@ -204,6 +204,7 @@ enum agent_op
     aop_setv = 0x2d,
     aop_tracev = 0x2e,
     aop_trace16 = 0x30,
+    aop_printf = 0x31,
     aop_last
   };
 \f
@@ -260,6 +261,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);
 \f
 
 /* Functions for printing out expressions, and otherwise debugging
--- a/printcmd.c
+++ b/printcmd.c
@@ -1958,10 +1958,13 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
+typedef void (printf_callback) (char *fbuf, char **expp,
+				struct bp_location *loc,
+				struct agent_expr *aexpr);
 
-static void
-ui_printf (char *arg, struct ui_file *stream)
+void
+string_printf (char *arg, struct ui_file *stream, printf_callback callback,
+	       struct bp_location *loc, struct agent_expr *aexpr)
 {
   char *f = NULL;
   char *s = arg;
@@ -2294,26 +2297,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++)
@@ -2668,12 +2687,22 @@ 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.  */
+/* printf "printf format string" ARG to STREAM.  */
 
 static void
+ui_printf (char *arg, struct ui_file *stream)
+{
+  string_printf (arg, stream, NULL, NULL, NULL);
+}
+
+/* Implement the "printf" command.  */
+
+void
 printf_command (char *arg, int from_tty)
 {
   ui_printf (arg, gdb_stdout);
--- a/tracepoint.c
+++ b/tracepoint.c
@@ -187,6 +187,15 @@ extern void send_disconnected_tracing_va
 static void free_uploaded_tps (struct uploaded_tp **utpp);
 static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
 
+extern void printf_command (char *arg, int from_tty);
+extern void gen_printf_expr_callback (char **expp, struct bp_location *loc,
+				      struct agent_expr *aexpr);
+typedef void (printf_callback) (char **expp, struct bp_location *loc,
+				struct agent_expr *aexpr);
+extern void string_printf (char *arg, struct ui_file *stream,
+			   printf_callback callback, struct bp_location *loc,
+			   struct agent_expr *aexpr);
+
 
 extern void _initialize_tracepoint (void);
 
@@ -725,6 +734,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))
     ;
 
@@ -1436,6 +1467,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 */

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-01-28  5:54           ` Hui Zhu
@ 2011-02-04 15:59             ` Hui Zhu
  2011-02-11  3:49               ` Hui Zhu
  2011-02-11 18:45               ` Tom Tromey
  0 siblings, 2 replies; 16+ messages in thread
From: Hui Zhu @ 2011-02-04 15:59 UTC (permalink / raw)
  To: gdb-patches ml; +Cc: Stan Shebs

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

The prev version cannot support %s.  So make a new version to support it.

And I think current way to handle printf is too much hack way.  Maybe
I need find out a more better way to handle the printf.

Thanks,
Hui

2011-02-04  Hui Zhu  <teawater@gmail.com>

	* ax-gdb.c (gen_printf_expr_callback): New function.
	* ax-general.c (ax_memcpy): New function.
	(aop_map): Add new entry for "printf".
	(ax_print): Handle "printf".
	(ax_reqs): Ditto.
	* ax.h (agent_op): Add aop_printf.
	(ax_memcpy): Forward declare.
	* printcmd.c (printf_callback): New typedef.
	(string_printf): New function from ui_printf.
	(ui_printf): Call string_printf.
	(printf_command): Remove static.
	* tracepoint.c (printf_command, gen_printf_expr_callback,
	printf_callback, string_printf): Forward declares.
	(validate_actionline, encode_actions_1): handle printf_command.

[-- Attachment #2: tp_print.txt --]
[-- Type: text/plain, Size: 10296 bytes --]

---
 ax-gdb.c     |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-general.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h         |    3 +++
 printcmd.c   |   41 +++++++++++++++++++++++++++++++++++------
 tracepoint.c |   47 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 190 insertions(+), 13 deletions(-)

--- a/ax-gdb.c
+++ b/ax-gdb.c
@@ -2446,6 +2446,64 @@ gen_eval_for_expr (CORE_ADDR scope, stru
   return ax;
 }
 
+void
+gen_printf_expr_callback (char *fbuf, char **expp, struct bp_location *loc,
+			  struct agent_expr *aexpr)
+{
+  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-general.c
+++ b/ax-general.c
@@ -319,6 +319,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;
+}
 \f
 
 
@@ -376,6 +384,7 @@ struct aop_map aop_map[] =
   {"tracev", 2, 0, 0, 1},	/* 0x2e */
   {0, 0, 0, 0, 0},		/* 0x2f */
   {"trace16", 2, 0, 1, 1},	/* 0x30 */
+  {"printf", 0, 0, 0, 0},	/* 0x31 */
 };
 
 
@@ -401,6 +410,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)
@@ -409,7 +419,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);
@@ -417,15 +439,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);
     }
@@ -493,6 +515,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]));
 
@@ -500,7 +524,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])))
 	{
@@ -516,7 +540,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;
@@ -534,7 +574,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
@@ -204,6 +204,7 @@ enum agent_op
     aop_setv = 0x2d,
     aop_tracev = 0x2e,
     aop_trace16 = 0x30,
+    aop_printf = 0x31,
     aop_last
   };
 \f
@@ -260,6 +261,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);
 \f
 
 /* Functions for printing out expressions, and otherwise debugging
--- a/printcmd.c
+++ b/printcmd.c
@@ -1958,10 +1958,13 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
+typedef void (printf_callback) (char *fbuf, char **expp,
+				struct bp_location *loc,
+				struct agent_expr *aexpr);
 
-static void
-ui_printf (char *arg, struct ui_file *stream)
+void
+string_printf (char *arg, struct ui_file *stream, printf_callback callback,
+	       struct bp_location *loc, struct agent_expr *aexpr)
 {
   char *f = NULL;
   char *s = arg;
@@ -2294,26 +2297,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++)
@@ -2668,12 +2687,22 @@ 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.  */
+/* printf "printf format string" ARG to STREAM.  */
 
 static void
+ui_printf (char *arg, struct ui_file *stream)
+{
+  string_printf (arg, stream, NULL, NULL, NULL);
+}
+
+/* Implement the "printf" command.  */
+
+void
 printf_command (char *arg, int from_tty)
 {
   ui_printf (arg, gdb_stdout);
--- a/tracepoint.c
+++ b/tracepoint.c
@@ -187,6 +187,15 @@ extern void send_disconnected_tracing_va
 static void free_uploaded_tps (struct uploaded_tp **utpp);
 static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
 
+extern void printf_command (char *arg, int from_tty);
+extern void gen_printf_expr_callback (char **expp, struct bp_location *loc,
+				      struct agent_expr *aexpr);
+typedef void (printf_callback) (char **expp, struct bp_location *loc,
+				struct agent_expr *aexpr);
+extern void string_printf (char *arg, struct ui_file *stream,
+			   printf_callback callback, struct bp_location *loc,
+			   struct agent_expr *aexpr);
+
 
 extern void _initialize_tracepoint (void);
 
@@ -725,6 +734,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))
     ;
 
@@ -1436,6 +1467,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 */

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-02-04 15:59             ` Hui Zhu
@ 2011-02-11  3:49               ` Hui Zhu
  2011-02-11 18:45               ` Tom Tromey
  1 sibling, 0 replies; 16+ messages in thread
From: Hui Zhu @ 2011-02-11  3:49 UTC (permalink / raw)
  To: Doug Evans, Stan Shebs, Michael Snyder; +Cc: gdb-patches ml

Hi all,

I sent the first version patch has been more than a month.  And I have
done with the support in the KGTP for the support.

But I am still not get a code review or something.  Are you reviewing
or have plan to review this patch?

Thanks,
Hui

On Fri, Feb 4, 2011 at 23:59, Hui Zhu <teawater@gmail.com> wrote:
> The prev version cannot support %s.  So make a new version to support it.
>
> And I think current way to handle printf is too much hack way.  Maybe
> I need find out a more better way to handle the printf.
>
> Thanks,
> Hui
>
> 2011-02-04  Hui Zhu  <teawater@gmail.com>
>
>        * ax-gdb.c (gen_printf_expr_callback): New function.
>        * ax-general.c (ax_memcpy): New function.
>        (aop_map): Add new entry for "printf".
>        (ax_print): Handle "printf".
>        (ax_reqs): Ditto.
>        * ax.h (agent_op): Add aop_printf.
>        (ax_memcpy): Forward declare.
>        * printcmd.c (printf_callback): New typedef.
>        (string_printf): New function from ui_printf.
>        (ui_printf): Call string_printf.
>        (printf_command): Remove static.
>        * tracepoint.c (printf_command, gen_printf_expr_callback,
>        printf_callback, string_printf): Forward declares.
>        (validate_actionline, encode_actions_1): handle printf_command.
>

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-02-04 15:59             ` Hui Zhu
  2011-02-11  3:49               ` Hui Zhu
@ 2011-02-11 18:45               ` Tom Tromey
  2011-02-17  8:16                 ` Hui Zhu
  1 sibling, 1 reply; 16+ messages in thread
From: Tom Tromey @ 2011-02-11 18:45 UTC (permalink / raw)
  To: Hui Zhu; +Cc: gdb-patches ml, Stan Shebs

>>>>> ">" == Hui Zhu <teawater@gmail.com> writes:

>> +      gen_expr (expr, &pc, aexpr, &value);
>> +
>> +
>> +      if (value.optimized_out)

There's no need to have 2 blank lines here.

This function and some other new ones have no documentation.

>> +  {"printf", 0, 0, 0, 0},	/* 0x31 */
[...]
>> +    aop_printf = 0x31,

If you add a new AX expression, you must update agentexpr.texi.

I think any AX addition should also require a corresponding addition to
gdbserver.

>> +typedef void (printf_callback) (char *fbuf, char **expp,
>> +				struct bp_location *loc,
>> +				struct agent_expr *aexpr);

From what I can see, the `loc' and `aexpr' arguments are passed through
string_printf without interpretation.

In a case like this it is customary to just add a single `void *data'
argument and have the caller and callback agree on the type.  Here, that
type would be an instance of a struct wrapping the two values.

This definition should not be here.

>>  static void
>> +ui_printf (char *arg, struct ui_file *stream)
>> +{
>> +  string_printf (arg, stream, NULL, NULL, NULL);
>> +}

There's no reason to keep ui_printf around, just inline this into the 2
callers.

>> +extern void printf_command (char *arg, int from_tty);
>> +typedef void (printf_callback) (char **expp, struct bp_location *loc,
>> +				struct agent_expr *aexpr);
>> +extern void string_printf (char *arg, struct ui_file *stream,
>> +			   printf_callback callback, struct bp_location *loc,
>> +			   struct agent_expr *aexpr);

These should be in some appropriate header, not tracepoint.c.

>> +	  /* 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.  */

Wrong comment format, no leading "*"s.


This new feature needs a documentation patch and probably also a patch
to NEWS.

From what I can tell from the patch, the idea here is to add a printf to
a tracepoint's actions, with the printf evaluated on the remote side.  I
guess that is an ok idea, though I don't use this stuff enough to really
have an opinion.

I think it would be good for other maintainers to speak up now.  If it
is left to me, I will allow this if you fix up the problems and write
the documentation.

Tom

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-02-11 18:45               ` Tom Tromey
@ 2011-02-17  8:16                 ` Hui Zhu
  2011-02-21  8:18                   ` Hui Zhu
  0 siblings, 1 reply; 16+ messages in thread
From: Hui Zhu @ 2011-02-17  8:16 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches ml, Stan Shebs

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

On Sat, Feb 12, 2011 at 02:45, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> ">" == Hui Zhu <teawater@gmail.com> writes:
>
>>> +      gen_expr (expr, &pc, aexpr, &value);
>>> +
>>> +
>>> +      if (value.optimized_out)
>
> There's no need to have 2 blank lines here.
>
> This function and some other new ones have no documentation.
>
>>> +  {"printf", 0, 0, 0, 0},   /* 0x31 */
> [...]
>>> +    aop_printf = 0x31,
>
> If you add a new AX expression, you must update agentexpr.texi.
>
> I think any AX addition should also require a corresponding addition to
> gdbserver.
>
>>> +typedef void (printf_callback) (char *fbuf, char **expp,
>>> +                            struct bp_location *loc,
>>> +                            struct agent_expr *aexpr);
>
> From what I can see, the `loc' and `aexpr' arguments are passed through
> string_printf without interpretation.
>
> In a case like this it is customary to just add a single `void *data'
> argument and have the caller and callback agree on the type.  Here, that
> type would be an instance of a struct wrapping the two values.
>
> This definition should not be here.
>
>>>  static void
>>> +ui_printf (char *arg, struct ui_file *stream)
>>> +{
>>> +  string_printf (arg, stream, NULL, NULL, NULL);
>>> +}
>
> There's no reason to keep ui_printf around, just inline this into the 2
> callers.
>
>>> +extern void printf_command (char *arg, int from_tty);
>>> +typedef void (printf_callback) (char **expp, struct bp_location *loc,
>>> +                            struct agent_expr *aexpr);
>>> +extern void string_printf (char *arg, struct ui_file *stream,
>>> +                       printf_callback callback, struct bp_location *loc,
>>> +                       struct agent_expr *aexpr);
>
> These should be in some appropriate header, not tracepoint.c.
>
>>> +      /* 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.  */
>
> Wrong comment format, no leading "*"s.
>
>
> This new feature needs a documentation patch and probably also a patch
> to NEWS.
>
> From what I can tell from the patch, the idea here is to add a printf to
> a tracepoint's actions, with the printf evaluated on the remote side.  I
> guess that is an ok idea, though I don't use this stuff enough to really
> have an opinion.
>
> I think it would be good for other maintainers to speak up now.  If it
> is left to me, I will allow this if you fix up the problems and write
> the documentation.
>
> Tom
>

Thanks for your help Tom.

I make a new patch according to your comments.  And I have send the
patch for doc in prev mail.

Best,
Hui

2011-02-17  Hui Zhu  <teawater@gmail.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add printcmd.h.
	* ax-gdb.c (gen_printf_expr_callback): New function.
	* ax-general.c (ax_memcpy): New function.
	(aop_map): Add new entry for "printf".
	(ax_print): Handle "printf".
	(ax_reqs): Ditto.
	* ax.h (agent_op): Add aop_printf.
	(ax_memcpy): Forward declare.
	* printcmd.c (printf_callback): New typedef.
	(string_printf): New function from ui_printf.
	(ui_printf): Call string_printf.
	(printf_command): Remove static.
	* printcmd.h: New file.
	* tracepoint.c (printf_command, gen_printf_expr_callback,
	printf_callback, string_printf): Forward declares.
	(validate_actionline, encode_actions_1): handle printf_command.

[-- Attachment #2: tp_print.txt --]
[-- Type: text/plain, Size: 12472 bytes --]

---
 Makefile.in  |    2 +-
 ax-gdb.c     |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ax-gdb.h     |    2 ++
 ax-general.c |   54 +++++++++++++++++++++++++++++++++++++++++++++++-------
 ax.h         |    3 +++
 printcmd.c   |   39 +++++++++++++++++++++++++++++++--------
 printcmd.h   |   30 ++++++++++++++++++++++++++++++
 tracepoint.c |   39 +++++++++++++++++++++++++++++++++++++++
 8 files changed, 212 insertions(+), 16 deletions(-)

--- a/Makefile.in
+++ b/Makefile.in
@@ -813,7 +813,7 @@ annotate.h sim-regno.h dictionary.h dfp.
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h ada-operator.inc microblaze-tdep.h \
-psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h
+psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h printcmd.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
--- 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
@@ -319,6 +319,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;
+}
 \f
 
 
@@ -376,6 +384,7 @@ struct aop_map aop_map[] =
   {"tracev", 2, 0, 0, 1},	/* 0x2e */
   {0, 0, 0, 0, 0},		/* 0x2f */
   {"trace16", 2, 0, 1, 1},	/* 0x30 */
+  {"printf", 0, 0, 0, 0},	/* 0x31 */
 };
 
 
@@ -401,6 +410,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)
@@ -409,7 +419,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);
@@ -417,15 +439,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);
     }
@@ -493,6 +515,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]));
 
@@ -500,7 +524,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])))
 	{
@@ -516,7 +540,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;
@@ -534,7 +574,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
@@ -204,6 +204,7 @@ enum agent_op
     aop_setv = 0x2d,
     aop_tracev = 0x2e,
     aop_trace16 = 0x30,
+    aop_printf = 0x31,
     aop_last
   };
 \f
@@ -260,6 +261,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);
 \f
 
 /* Functions for printing out expressions, and otherwise debugging
--- a/printcmd.c
+++ b/printcmd.c
@@ -1958,10 +1958,13 @@ print_variable_and_value (const char *na
   fprintf_filtered (stream, "\n");
 }
 
-/* printf "printf format string" ARG to STREAM.  */
+typedef void (printf_callback) (char *fbuf, char **expp,
+				struct bp_location *loc,
+				struct agent_expr *aexpr);
 
-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;
@@ -1972,6 +1975,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);
@@ -2294,26 +2299,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++)
@@ -2668,15 +2689,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.  */
@@ -2688,7 +2711,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
@@ -51,6 +51,7 @@
 #include "ax.h"
 #include "ax-gdb.h"
 #include "memrange.h"
+#include "printcmd.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -763,6 +764,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))
     ;
 
@@ -1474,6 +1497,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 */

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

* Re: [PATCH] tracepoint: add new trace command "printf"[0] gdb
  2011-02-17  8:16                 ` Hui Zhu
@ 2011-02-21  8:18                   ` Hui Zhu
  0 siblings, 0 replies; 16+ messages in thread
From: Hui Zhu @ 2011-02-21  8:18 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches ml, Stan Shebs

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

On Thu, Feb 17, 2011 at 16:15, Hui Zhu <teawater@gmail.com> wrote:
> On Sat, Feb 12, 2011 at 02:45, Tom Tromey <tromey@redhat.com> wrote:
>>>>>>> ">" == Hui Zhu <teawater@gmail.com> writes:
>>
>>>> +      gen_expr (expr, &pc, aexpr, &value);
>>>> +
>>>> +
>>>> +      if (value.optimized_out)
>>
>> There's no need to have 2 blank lines here.
>>
>> This function and some other new ones have no documentation.
>>
>>>> +  {"printf", 0, 0, 0, 0},   /* 0x31 */
>> [...]
>>>> +    aop_printf = 0x31,
>>
>> If you add a new AX expression, you must update agentexpr.texi.
>>
>> I think any AX addition should also require a corresponding addition to
>> gdbserver.
>>
>>>> +typedef void (printf_callback) (char *fbuf, char **expp,
>>>> +                            struct bp_location *loc,
>>>> +                            struct agent_expr *aexpr);
>>
>> From what I can see, the `loc' and `aexpr' arguments are passed through
>> string_printf without interpretation.
>>
>> In a case like this it is customary to just add a single `void *data'
>> argument and have the caller and callback agree on the type.  Here, that
>> type would be an instance of a struct wrapping the two values.
>>
>> This definition should not be here.
>>
>>>>  static void
>>>> +ui_printf (char *arg, struct ui_file *stream)
>>>> +{
>>>> +  string_printf (arg, stream, NULL, NULL, NULL);
>>>> +}
>>
>> There's no reason to keep ui_printf around, just inline this into the 2
>> callers.
>>
>>>> +extern void printf_command (char *arg, int from_tty);
>>>> +typedef void (printf_callback) (char **expp, struct bp_location *loc,
>>>> +                            struct agent_expr *aexpr);
>>>> +extern void string_printf (char *arg, struct ui_file *stream,
>>>> +                       printf_callback callback, struct bp_location *loc,
>>>> +                       struct agent_expr *aexpr);
>>
>> These should be in some appropriate header, not tracepoint.c.
>>
>>>> +      /* 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.  */
>>
>> Wrong comment format, no leading "*"s.
>>
>>
>> This new feature needs a documentation patch and probably also a patch
>> to NEWS.
>>
>> From what I can tell from the patch, the idea here is to add a printf to
>> a tracepoint's actions, with the printf evaluated on the remote side.  I
>> guess that is an ok idea, though I don't use this stuff enough to really
>> have an opinion.
>>
>> I think it would be good for other maintainers to speak up now.  If it
>> is left to me, I will allow this if you fix up the problems and write
>> the documentation.
>>
>> Tom
>>
>
> Thanks for your help Tom.
>
> I make a new patch according to your comments.  And I have send the
> patch for doc in prev mail.
>
> Best,
> Hui
>
> 2011-02-17  Hui Zhu  <teawater@gmail.com>
>
>        * Makefile.in (HFILES_NO_SRCDIR): Add printcmd.h.
>        * ax-gdb.c (gen_printf_expr_callback): New function.
>        * ax-general.c (ax_memcpy): New function.
>        (aop_map): Add new entry for "printf".
>        (ax_print): Handle "printf".
>        (ax_reqs): Ditto.
>        * ax.h (agent_op): Add aop_printf.
>        (ax_memcpy): Forward declare.
>        * printcmd.c (printf_callback): New typedef.
>        (string_printf): New function from ui_printf.
>        (ui_printf): Call string_printf.
>        (printf_command): Remove static.
>        * printcmd.h: New file.
>        * tracepoint.c (printf_command, gen_printf_expr_callback,
>        printf_callback, string_printf): Forward declares.
>        (validate_actionline, encode_actions_1): handle printf_command.
>

Hi guys,

Patch in attachment checked in.

Thanks,
Hui

2011-02-17  Hui Zhu  <teawater@gmail.com>

	* Makefile.in (HFILES_NO_SRCDIR): Add printcmd.h.
	* ax-gdb.c (gen_printf_expr_callback): New function.
	* ax-gdb.h (gen_printf_expr_callback): Forward declare.
	* ax-general.c (ax_memcpy): New function.
	(aop_map): Add new entry for "printf".
	(ax_print): Handle "printf".
	(ax_reqs): Ditto.
	* ax.h (ax_memcpy): Forward declare.
	* common/ax.def (invalid2): Removed.
	(printf): New entry.
	* printcmd.c (printcmd.h): New include.
	(string_printf): New function.
	(ui_printf): Removed.
	(printf_command): Remove static.  Call string_printf.
	(eval_command): Call string_printf.
	* printcmd.h: New file.
	* tracepoint.c (printf_command, gen_printf_expr_callback,
	printf_callback, string_printf): Forward declares.
	(validate_actionline, encode_actions_1): handle printf_command.

[-- Attachment #2: tp_print.txt --]
[-- Type: text/plain, Size: 12813 bytes --]

---
 Makefile.in   |    2 -
 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(+), 22 deletions(-)

--- a/Makefile.in
+++ b/Makefile.in
@@ -813,7 +813,7 @@ annotate.h sim-regno.h dictionary.h dfp.
 remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
 sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
 gdb_usleep.h jit.h xml-syscall.h microblaze-tdep.h \
-psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h
+psymtab.h psympriv.h progspace.h bfin-tdep.h ia64-hpux-tdep.h printcmd.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
--- 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
@@ -330,6 +330,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;
+}
 \f
 
 
@@ -368,6 +376,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)
@@ -376,7 +385,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);
@@ -384,15 +405,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);
     }
@@ -460,6 +481,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]));
 
@@ -467,7 +490,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])))
 	{
@@ -483,7 +506,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;
@@ -501,7 +540,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);
 \f
 
 /* 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, 0x2f)
-/* 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
@@ -49,6 +49,7 @@
 #include "parser-defs.h"
 #include "charset.h"
 #include "arch-utils.h"
+#include "printcmd.h"
 
 #ifdef TUI
 #include "tui/tui.h"		/* For tui_active et al.   */
@@ -1960,10 +1961,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;
@@ -1974,6 +1974,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);
@@ -2296,26 +2298,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++)
@@ -2670,15 +2688,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.  */
@@ -2690,7 +2710,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
@@ -51,6 +51,7 @@
 #include "ax.h"
 #include "ax-gdb.h"
 #include "memrange.h"
+#include "printcmd.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -763,6 +764,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))
     ;
 
@@ -1474,6 +1497,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 */

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

end of thread, other threads:[~2011-02-21  8:17 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-03 16:29 [PATCH] tracepoint: add new trace command "printf"[0] gdb Hui Zhu
2011-01-03 19:21 ` Doug Evans
2011-01-04  4:34   ` Hui Zhu
2011-01-04  6:19     ` Doug Evans
2011-01-04 12:07       ` Hui Zhu
2011-01-05 17:24       ` Doug Evans
2011-01-05 18:18         ` Michael Snyder
2011-01-06  6:42           ` Hui Zhu
2011-01-05 20:51       ` Stan Shebs
2011-01-06  6:43         ` Hui Zhu
2011-01-28  5:54           ` Hui Zhu
2011-02-04 15:59             ` Hui Zhu
2011-02-11  3:49               ` Hui Zhu
2011-02-11 18:45               ` Tom Tromey
2011-02-17  8:16                 ` Hui Zhu
2011-02-21  8:18                   ` Hui Zhu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).