public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Hui Zhu <teawater@gmail.com>
To: gdb-patches <gdb-patches@sourceware.org>
Subject: [PATCH] tracepoint: add new trace command "printf"[0] gdb
Date: Mon, 03 Jan 2011 16:29:00 -0000	[thread overview]
Message-ID: <AANLkTimhMH+qUE1NmQ+f6+L8BcEU+k07eU+M9B-gLsrk@mail.gmail.com> (raw)

[-- 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 */

             reply	other threads:[~2011-01-03 16:29 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-01-03 16:29 Hui Zhu [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=AANLkTimhMH+qUE1NmQ+f6+L8BcEU+k07eU+M9B-gLsrk@mail.gmail.com \
    --to=teawater@gmail.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).