gdb/
authorStan Shebs <shebs@codesourcery.com>
Tue, 14 Jul 2009 21:40:34 +0000 (21:40 +0000)
committerStan Shebs <shebs@codesourcery.com>
Tue, 14 Jul 2009 21:40:34 +0000 (21:40 +0000)
Conditional tracepoints.
* ax-gdb.h (gen_eval_for_expr): Declare.
* ax-gdb.c (gen_expr): Generate bytecodes for BINOP_EQUAL
and other comparisons.
(gen_eval_for_expr): New function.
(agent_eval_command): New maintenance command.
(_initialize_ax_gdb): Define the command.
* remote.c (struct remote_state): New field cond_tracepoints.
(PACKET_ConditionalTracepoints): New packet config type.
(remote_cond_tracepoint_feature): New function.
(remote_protocol_features): Add ConditionalTracepoints.
(remote_supports_cond_tracepoints): New function.
(_initialize_remote): Add ConditionalTracepoints.
* tracepoint.c (download_tracepoint): Add conditional.
* NEWS: Mention conditional tracepoints.

gdb/doc/
* gdb.texinfo (Tracepoint Conditions): New section.
(General Query Packets): Describe ConditionalTracepoints.
(Tracepoint Packets): Describe condition field.
(Maintenance Commands): Describe maint agent-eval.
* agentexpr.texi (Using Agent Expressions): Mention eval usage.

gdb/testsuite/
* gdb.trace/tracecmd.exp: Add basic test of tracepoint conditions.

gdb/ChangeLog
gdb/NEWS
gdb/ax-gdb.c
gdb/ax-gdb.h
gdb/doc/ChangeLog
gdb/doc/agentexpr.texi
gdb/doc/gdb.texinfo
gdb/remote.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.trace/tracecmd.exp
gdb/tracepoint.c

index 690f76a..11e2241 100644 (file)
@@ -1,3 +1,21 @@
+2009-07-14  Stan Shebs  <stan@codesourcery.com>
+
+       Conditional tracepoints.
+       * ax-gdb.h (gen_eval_for_expr): Declare.
+       * ax-gdb.c (gen_expr): Generate bytecodes for BINOP_EQUAL
+       and other comparisons.
+       (gen_eval_for_expr): New function.
+       (agent_eval_command): New maintenance command.
+       (_initialize_ax_gdb): Define the command.
+       * remote.c (struct remote_state): New field cond_tracepoints.
+       (PACKET_ConditionalTracepoints): New packet config type.
+       (remote_cond_tracepoint_feature): New function.
+       (remote_protocol_features): Add ConditionalTracepoints.
+       (remote_supports_cond_tracepoints): New function.
+       (_initialize_remote): Add ConditionalTracepoints.
+       * tracepoint.c (download_tracepoint): Add conditional.
+       * NEWS: Mention conditional tracepoints.
+
 2009-07-14  Ulrich Weigand  <uweigand@de.ibm.com>
 
        * objfiles.c (objfile_relocate): Do not relocate the same
index b444f74..22757d9 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,12 @@
 
 *** Changes since GDB 6.8
 
+* Tracepoints may now be conditional.  The syntax is as for
+breakpoints; either an "if" clause appended to the "trace" command,
+or the "condition" command is available.  GDB sends the condition to
+the target for evaluation using the same bytecode format as is used
+for tracepoint actions.
+
 * "disassemble" command with a /r modifier, print the raw instructions
 in hex as well as in symbolic form."
 
index 4edf8f2..999b27c 100644 (file)
@@ -1468,6 +1468,12 @@ gen_expr (struct expression *exp, union exp_element **pc,
     case BINOP_BITWISE_AND:
     case BINOP_BITWISE_IOR:
     case BINOP_BITWISE_XOR:
+    case BINOP_EQUAL:
+    case BINOP_NOTEQUAL:
+    case BINOP_LESS:
+    case BINOP_GTR:
+    case BINOP_LEQ:
+    case BINOP_GEQ:
       (*pc)++;
       gen_expr (exp, pc, ax, &value1);
       gen_usual_unary (exp, ax, &value1);
@@ -1537,6 +1543,47 @@ gen_expr (struct expression *exp, union exp_element **pc,
                     aop_bit_xor, aop_bit_xor, 0, "bitwise exclusive-or");
          break;
 
+       case BINOP_EQUAL:
+         gen_binop (ax, value, &value1, &value2,
+                    aop_equal, aop_equal, 0, "equal");
+         break;
+
+       case BINOP_NOTEQUAL:
+         gen_binop (ax, value, &value1, &value2,
+                    aop_equal, aop_equal, 0, "equal");
+         gen_logical_not (ax, value,
+                          language_bool_type (exp->language_defn,
+                                              exp->gdbarch));
+         break;
+
+       case BINOP_LESS:
+         gen_binop (ax, value, &value1, &value2,
+                    aop_less_signed, aop_less_unsigned, 0, "less than");
+         break;
+
+       case BINOP_GTR:
+         ax_simple (ax, aop_swap);
+         gen_binop (ax, value, &value1, &value2,
+                    aop_less_signed, aop_less_unsigned, 0, "less than");
+         break;
+
+       case BINOP_LEQ:
+         ax_simple (ax, aop_swap);
+         gen_binop (ax, value, &value1, &value2,
+                    aop_less_signed, aop_less_unsigned, 0, "less than");
+         gen_logical_not (ax, value,
+                          language_bool_type (exp->language_defn,
+                                              exp->gdbarch));
+         break;
+
+       case BINOP_GEQ:
+         gen_binop (ax, value, &value1, &value2,
+                    aop_less_signed, aop_less_unsigned, 0, "less than");
+         gen_logical_not (ax, value,
+                          language_bool_type (exp->language_defn,
+                                              exp->gdbarch));
+         break;
+
        default:
          /* We should only list operators in the outer case statement
             that we actually handle in the inner case statement.  */
@@ -1756,6 +1803,37 @@ gen_trace_for_expr (CORE_ADDR scope, struct expression *expr)
   return ax;
 }
 
+/* Given a GDB expression EXPR, return a bytecode sequence that will
+   evaluate and return a result.  The bytecodes will do a direct
+   evaluation, using the current data on the target, rather than
+   recording blocks of memory and registers for later use, as
+   gen_trace_for_expr does.  The generated bytecode sequence leaves
+   the result of expression evaluation on the top of the stack.  */
+
+struct agent_expr *
+gen_eval_for_expr (CORE_ADDR scope, struct expression *expr)
+{
+  struct cleanup *old_chain = 0;
+  struct agent_expr *ax = new_agent_expr (scope);
+  union exp_element *pc;
+  struct axs_value value;
+
+  old_chain = make_cleanup_free_agent_expr (ax);
+
+  pc = expr->elts;
+  trace_kludge = 0;
+  gen_expr (expr, &pc, ax, &value);
+
+  /* Oh, and terminate.  */
+  ax_simple (ax, aop_end);
+
+  /* We have successfully built the agent expr, so cancel the cleanup
+     request.  If we add more cleanups that we always want done, this
+     will have to get more complicated.  */
+  discard_cleanups (old_chain);
+  return ax;
+}
+
 static void
 agent_command (char *exp, int from_tty)
 {
@@ -1786,6 +1864,41 @@ agent_command (char *exp, int from_tty)
   do_cleanups (old_chain);
   dont_repeat ();
 }
+
+/* Parse the given expression, compile it into an agent expression
+   that does direct evaluation, and display the resulting
+   expression.  */
+
+static void
+agent_eval_command (char *exp, int from_tty)
+{
+  struct cleanup *old_chain = 0;
+  struct expression *expr;
+  struct agent_expr *agent;
+  struct frame_info *fi = get_current_frame ();        /* need current scope */
+
+  /* We don't deal with overlay debugging at the moment.  We need to
+     think more carefully about this.  If you copy this code into
+     another command, change the error message; the user shouldn't
+     have to know anything about agent expressions.  */
+  if (overlay_debugging)
+    error (_("GDB can't do agent expression translation with overlays."));
+
+  if (exp == 0)
+    error_no_arg (_("expression to translate"));
+
+  expr = parse_expression (exp);
+  old_chain = make_cleanup (free_current_contents, &expr);
+  agent = gen_eval_for_expr (get_frame_pc (fi), expr);
+  make_cleanup_free_agent_expr (agent);
+  ax_print (gdb_stdout, agent);
+
+  /* It would be nice to call ax_reqs here to gather some general info
+     about the expression, and then print out the result.  */
+
+  do_cleanups (old_chain);
+  dont_repeat ();
+}
 \f
 
 /* Initialization code.  */
@@ -1795,6 +1908,10 @@ void
 _initialize_ax_gdb (void)
 {
   add_cmd ("agent", class_maintenance, agent_command,
-          _("Translate an expression into remote agent bytecode."),
+          _("Translate an expression into remote agent bytecode for tracing."),
+          &maintenancelist);
+
+  add_cmd ("agent-eval", class_maintenance, agent_eval_command,
+          _("Translate an expression into remote agent bytecode for evaluation."),
           &maintenancelist);
 }
index 57e889e..5d03c18 100644 (file)
@@ -99,4 +99,6 @@ struct axs_value
    function to discover which registers the expression uses.  */
 extern struct agent_expr *gen_trace_for_expr (CORE_ADDR, struct expression *);
 
+extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
+
 #endif /* AX_GDB_H */
index cea168c..01fb199 100644 (file)
@@ -1,3 +1,11 @@
+2009-07-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.texinfo (Tracepoint Conditions): New section.
+       (General Query Packets): Describe ConditionalTracepoints.
+       (Tracepoint Packets): Describe condition field.
+       (Maintenance Commands): Describe maint agent-eval.
+       * agentexpr.texi (Using Agent Expressions): Mention eval usage.
+
 2009-07-11  Hui Zhu  <teawater@gmail.com>
 
        * gdb.texinfo (disassemble): Add a new modifier /r
index 1b893d5..3066319 100644 (file)
@@ -7,13 +7,11 @@
 
 @c This file is part of the GDB manual.
 @c
-@c Copyright (C) 2003, 2004, 2005, 2006
+@c Copyright (C) 2003, 2004, 2005, 2006, 2009
 @c               Free Software Foundation, Inc.
 @c
 @c See the file gdb.texinfo for copying conditions.
 
-@c Revision: $Id$
-
 @node Agent Expressions
 @appendix The GDB Agent Expression Mechanism
 
@@ -473,8 +471,20 @@ address, and the top of the stack is the lvalue's size, in bytes.
 @node Using Agent Expressions
 @section Using Agent Expressions
 
-Here is a sketch of a full non-stop debugging cycle, showing how agent
-expressions fit into the process.
+Agent expressions can be used in several different ways by @value{GDBN},
+and the debugger can generate different bytecode sequences as appropriate.
+
+One possibility is to do expression evaluation on the target rather
+than the host, such as for the conditional of a conditional
+tracepoint.  In such a case, @value{GDBN} compiles the source
+expression into a bytecode sequence that simply gets values from
+registers or memory, does arithmetic, and returns a result.
+
+Another way to use agent expressions is for tracepoint data
+collection.  @value{GDBN} generates a different bytecode sequence for
+collection; in addition to bytecodes that do the calculation,
+@value{GDBN} adds @code{trace} bytecodes to save the pieces of
+memory that were used.
 
 @itemize @bullet
 
index fc5e60f..71ae4b5 100644 (file)
@@ -8932,6 +8932,7 @@ conditions and actions.
 * Create and Delete Tracepoints::
 * Enable and Disable Tracepoints::
 * Tracepoint Passcounts::
+* Tracepoint Conditions::
 * Tracepoint Actions::
 * Listing Tracepoints::
 * Starting and Stopping Trace Experiments::
@@ -8971,6 +8972,13 @@ Here are some examples of using the @code{trace} command:
 @noindent
 You can abbreviate @code{trace} as @code{tr}.
 
+@item trace @var{location} if @var{cond}
+Set a tracepoint with condition @var{cond}; evaluate the expression
+@var{cond} each time the tracepoint is reached, and collect data only
+if the value is nonzero---that is, if @var{cond} evaluates as true.
+@xref{Tracepoint Conditions, ,Tracepoint Conditions}, for more
+information on tracepoint conditions.
+
 @vindex $tpnum
 @cindex last tracepoint number
 @cindex recent tracepoint number
@@ -9053,6 +9061,44 @@ Examples:
 @end smallexample
 @end table
 
+@node Tracepoint Conditions
+@subsection Tracepoint Conditions
+@cindex conditional tracepoints
+@cindex tracepoint conditions
+
+The simplest sort of tracepoint collects data every time your program
+reaches a specified place.  You can also specify a @dfn{condition} for
+a tracepoint.  A condition is just a Boolean expression in your
+programming language (@pxref{Expressions, ,Expressions}).  A
+tracepoint with a condition evaluates the expression each time your
+program reaches it, and data collection happens only if the condition
+is true.
+
+Tracepoint conditions can be specified when a tracepoint is set, by
+using @samp{if} in the arguments to the @code{trace} command.
+@xref{Create and Delete Tracepoints, ,Setting Tracepoints}.  They can
+also be set or changed at any time with the @code{condition} command,
+just as with breakpoints.
+
+Unlike breakpoint conditions, @value{GDBN} does not actually evaluate
+the conditional expression itself.  Instead, @value{GDBN} encodes the
+expression into an agent expression (@pxref{Agent Expressions}
+suitable for execution on the target, independently of @value{GDBN}.
+Global variables become raw memory locations, locals become stack
+accesses, and so forth.
+
+For instance, suppose you have a function that is usually called
+frequently, but should not be called after an error has occurred.  You
+could use the following tracepoint command to collect data about calls
+of that function that happen while the error code is propagating
+through the program; an unconditional tracepoint could end up
+collecting thousands of useless trace frames that you would have to
+search through.
+
+@smallexample
+(@value{GDBP}) @kbd{trace normal_operation if errcode > 0}
+@end smallexample
+
 @node Tracepoint Actions
 @subsection Tracepoint Action Lists
 
@@ -26534,10 +26580,19 @@ messages, see @ref{Debugging Output}.)
 
 @table @code
 @kindex maint agent
+@kindex maint agent-eval
 @item maint agent @var{expression}
+@itemx maint agent-eval @var{expression}
 Translate the given @var{expression} into remote agent bytecodes.
 This command is useful for debugging the Agent Expression mechanism
-(@pxref{Agent Expressions}).
+(@pxref{Agent Expressions}).  The @samp{agent} version produces an
+expression useful for data collection, such as by tracepoints, while
+@samp{maint agent-eval} produces an expression that evaluates directly
+to a result.  For instance, a collection expression for @code{globa +
+globb} will include bytecodes to record four bytes of memory at each
+of the addresses of @code{globa} and @code{globb}, while discarding
+the result of the addition, while an evaluation expression will do the
+addition and return the sum.
 
 @kindex maint info breakpoints
 @item @anchor{maint info breakpoints}maint info breakpoints
@@ -28415,6 +28470,11 @@ These are the currently defined stub features and their properties:
 @tab @samp{-}
 @tab No
 
+@item @samp{ConditionalTracepoints}
+@tab No
+@tab @samp{-}
+@tab No
+
 @end multitable
 
 These are the currently defined stub features, in more detail:
@@ -28492,6 +28552,10 @@ indicated it supports them in its @samp{qSupported} request.
 The remote stub understands the @samp{qXfer:osdata:read} packet
 ((@pxref{qXfer osdata read}).
 
+@item ConditionalTracepoints
+The remote stub accepts and implements conditional expressions defined
+for tracepoints (@pxref{Tracepoint Conditions}).
+
 @end table
 
 @item qSymbol::
@@ -28804,11 +28868,14 @@ tracepoints (@pxref{Tracepoints}).
 
 @table @samp
 
-@item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}@r{[}-@r{]}
+@item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}[:X@var{len},@var{bytes}]@r{[}-@r{]}
 Create a new tracepoint, number @var{n}, at @var{addr}.  If @var{ena}
 is @samp{E}, then the tracepoint is enabled; if it is @samp{D}, then
 the tracepoint is disabled.  @var{step} is the tracepoint's step
-count, and @var{pass} is its pass count.  If the trailing @samp{-} is
+count, and @var{pass} is its pass count.  If an @samp{X} is present,
+it introduces a tracepoint condition, which consists of a hexadecimal
+length, followed by a comma and hex-encoded bytes, in a manner similar
+to action encodings as described below.  If the trailing @samp{-} is
 present, further @samp{QTDP} packets will follow to specify this
 tracepoint's actions.
 
index 0a03fc7..ba5c346 100644 (file)
@@ -294,6 +294,9 @@ struct remote_state
 
   /* True if the stub reports support for vCont;t.  */
   int support_vCont_t;
+
+  /* True if the stub reports support for conditional tracepoints.  */
+  int cond_tracepoints;
 };
 
 /* Returns true if the multi-process extensions are in effect.  */
@@ -993,6 +996,7 @@ enum {
   PACKET_qXfer_siginfo_read,
   PACKET_qXfer_siginfo_write,
   PACKET_qAttached,
+  PACKET_ConditionalTracepoints,
   PACKET_MAX
 };
 
@@ -3015,6 +3019,15 @@ remote_non_stop_feature (const struct protocol_feature *feature,
   rs->non_stop_aware = (support == PACKET_ENABLE);
 }
 
+static void
+remote_cond_tracepoint_feature (const struct protocol_feature *feature,
+                                      enum packet_support support,
+                                      const char *value)
+{
+  struct remote_state *rs = get_remote_state ();
+  rs->cond_tracepoints = (support == PACKET_ENABLE);
+}
+
 static struct protocol_feature remote_protocol_features[] = {
   { "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
   { "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
@@ -3041,6 +3054,8 @@ static struct protocol_feature remote_protocol_features[] = {
     PACKET_qXfer_siginfo_read },
   { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_siginfo_write },
+  { "ConditionalTracepoints", PACKET_DISABLE, remote_cond_tracepoint_feature,
+    PACKET_ConditionalTracepoints },
 };
 
 static void
@@ -8740,6 +8755,13 @@ remote_supports_multi_process (void)
   return remote_multi_process_p (rs);
 }
 
+int
+remote_supports_cond_tracepoints (void)
+{
+  struct remote_state *rs = get_remote_state ();
+  return rs->cond_tracepoints;
+}
+
 static void
 init_remote_ops (void)
 {
@@ -9183,6 +9205,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qAttached],
                         "qAttached", "query-attached", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_ConditionalTracepoints],
+                        "ConditionalTracepoints", "conditional-tracepoints", 0);
+
   /* Keep the old ``set remote Z-packet ...'' working.  Each individual
      Z sub-packet has its own set and show commands, but users may
      have sets to this variable in their .gdbinit files (or in their
index 763a12f..ad57d81 100644 (file)
@@ -1,3 +1,7 @@
+2009-07-14  Stan Shebs  <stan@codesourcery.com>
+
+       * gdb.trace/tracecmd.exp: Add basic test of tracepoint conditions.
+
 2009-07-14  Michael Snyder  <msnyder@vmware.com>
 
        * gdb.reverse/step-reverse.exp (stepi into function call):
index edfc1e2..968088b 100644 (file)
@@ -153,7 +153,12 @@ gdb_test "trace" "No default breakpoint address now." \
 # deferred to limits test module
 
 # 1.11 tracepoint conditions
-# conditions on tracepoints not implemented
+gdb_delete_tracepoints
+gdb_test "trace gdb_recursion_test if q1 > 0" \
+       "Tracepoint $decimal at $hex: file.*$srcfile, line $testline1." \
+       "1.11a: conditional tracepoint"
+gdb_test "info trace" "in gdb_recursion_test.*$srcfile:$testline1.*trace only if q1 > 0" \
+       "1.11b: verify conditional tracepoint"
 
 # 1.12 set tracepoint in prologue
 # [see tfind.exp]
index 232c9e9..0d439ef 100644 (file)
@@ -33,6 +33,7 @@
 #include "breakpoint.h"
 #include "tracepoint.h"
 #include "remote.h"
+extern int remote_supports_cond_tracepoints (void);
 #include "linespec.h"
 #include "regcache.h"
 #include "completer.h"
@@ -1311,12 +1312,31 @@ download_tracepoint (struct breakpoint *t)
   char **stepping_actions;
   int ndx;
   struct cleanup *old_chain = NULL;
+  struct agent_expr *aexpr;
+  struct cleanup *aexpr_chain = NULL;
 
   sprintf_vma (tmp, (t->loc ? t->loc->address : 0));
   sprintf (buf, "QTDP:%x:%s:%c:%lx:%x", t->number, 
           tmp, /* address */
           (t->enable_state == bp_enabled ? 'E' : 'D'),
           t->step_count, t->pass_count);
+  /* If the tracepoint has a conditional, make it into an agent
+     expression and append to the definition.  */
+  if (t->loc->cond)
+    {
+      /* Only test support at download time, we may not know target
+        capabilities at definition time.  */
+      if (remote_supports_cond_tracepoints ())
+       {
+         aexpr = gen_eval_for_expr (t->loc->address, t->loc->cond);
+         aexpr_chain = make_cleanup_free_agent_expr (aexpr);
+         sprintf (buf + strlen (buf), ":X%x,", aexpr->len);
+         mem2hex (aexpr->buf, buf + strlen (buf), aexpr->len);
+         do_cleanups (aexpr_chain);
+       }
+      else
+       warning (_("Target does not support conditional tracepoints, ignoring tp %d cond"), t->number);
+    }
 
   if (t->actions)
     strcat (buf, "-");