From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 29863 invoked by alias); 14 Jul 2009 22:19:54 -0000 Received: (qmail 29851 invoked by uid 22791); 14 Jul 2009 22:19:51 -0000 X-SWARE-Spam-Status: No, hits=-1.4 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_37,J_CHICKENPOX_51,J_CHICKENPOX_83,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 14 Jul 2009 22:19:45 +0000 Received: (qmail 12106 invoked from network); 14 Jul 2009 22:19:40 -0000 Received: from unknown (HELO macbook-2.local) (stan@127.0.0.2) by mail.codesourcery.com with ESMTPA; 14 Jul 2009 22:19:40 -0000 Message-ID: <4A5D0469.5060301@codesourcery.com> Date: Tue, 14 Jul 2009 23:29:00 -0000 From: Stan Shebs User-Agent: Thunderbird 2.0.0.22 (Macintosh/20090605) MIME-Version: 1.0 To: gdb-patches@sourceware.org Subject: Re: [PATCH] Conditional tracepoints References: <4A45AE9B.9020400@codesourcery.com> In-Reply-To: <4A45AE9B.9020400@codesourcery.com> Content-Type: multipart/mixed; boundary="------------010003070409080800030604" Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-07/txt/msg00384.txt.bz2 This is a multi-part message in MIME format. --------------010003070409080800030604 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-length: 1249 Here's what I committed for conditional tracepoints. On to the next piece! Stan 2009-07-14 Stan Shebs 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.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.trace/tracecmd.exp: Add basic test of tracepoint conditions. --------------010003070409080800030604 Content-Type: text/plain; x-mac-type="0"; x-mac-creator="0"; name="cond-tp-patch-4" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="cond-tp-patch-4" Content-length: 20963 Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.317 diff -p -r1.317 NEWS *** NEWS 11 Jul 2009 14:04:23 -0000 1.317 --- NEWS 14 Jul 2009 21:14:15 -0000 *************** *** 3,8 **** --- 3,14 ---- *** 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: ax-gdb.c =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.c,v retrieving revision 1.52 diff -p -r1.52 ax-gdb.c *** ax-gdb.c 2 Jul 2009 12:20:17 -0000 1.52 --- ax-gdb.c 14 Jul 2009 21:14:15 -0000 *************** gen_expr (struct expression *exp, union *** 1468,1473 **** --- 1468,1479 ---- 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); *************** gen_expr (struct expression *exp, union *** 1537,1542 **** --- 1543,1589 ---- 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. */ *************** gen_trace_for_expr (CORE_ADDR scope, str *** 1756,1761 **** --- 1803,1839 ---- 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) { *************** agent_command (char *exp, int from_tty) *** 1786,1791 **** --- 1864,1904 ---- 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 (); + } /* Initialization code. */ *************** void *** 1795,1800 **** _initialize_ax_gdb (void) { add_cmd ("agent", class_maintenance, agent_command, ! _("Translate an expression into remote agent bytecode."), &maintenancelist); } --- 1908,1917 ---- _initialize_ax_gdb (void) { add_cmd ("agent", class_maintenance, agent_command, ! _("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: ax-gdb.h =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.h,v retrieving revision 1.11 diff -p -r1.11 ax-gdb.h *** ax-gdb.h 3 Jan 2009 05:57:50 -0000 1.11 --- ax-gdb.h 14 Jul 2009 21:14:15 -0000 *************** struct axs_value *** 99,102 **** --- 99,104 ---- 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: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.363 diff -p -r1.363 remote.c *** remote.c 14 Jul 2009 14:53:41 -0000 1.363 --- remote.c 14 Jul 2009 21:14:16 -0000 *************** struct remote_state *** 294,299 **** --- 294,302 ---- /* 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. */ *************** enum { *** 993,998 **** --- 996,1002 ---- PACKET_qXfer_siginfo_read, PACKET_qXfer_siginfo_write, PACKET_qAttached, + PACKET_ConditionalTracepoints, PACKET_MAX }; *************** remote_non_stop_feature (const struct pr *** 3015,3020 **** --- 3019,3033 ---- 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, *************** static struct protocol_feature remote_pr *** 3041,3046 **** --- 3054,3061 ---- 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 *************** remote_supports_multi_process (void) *** 8740,8745 **** --- 8755,8767 ---- 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) { *************** Show the maximum size of the address (in *** 9183,9188 **** --- 9205,9213 ---- 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: tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.c,v retrieving revision 1.125 diff -p -r1.125 tracepoint.c *** tracepoint.c 2 Jul 2009 17:21:07 -0000 1.125 --- tracepoint.c 14 Jul 2009 21:14:16 -0000 *************** *** 33,38 **** --- 33,39 ---- #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" *************** download_tracepoint (struct breakpoint * *** 1311,1322 **** --- 1312,1342 ---- 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, "-"); Index: doc/agentexpr.texi =================================================================== RCS file: /cvs/src/src/gdb/doc/agentexpr.texi,v retrieving revision 1.7 diff -p -r1.7 agentexpr.texi *** doc/agentexpr.texi 20 Jan 2007 16:51:56 -0000 1.7 --- doc/agentexpr.texi 14 Jul 2009 21:14:17 -0000 *************** *** 7,19 **** @c This file is part of the GDB manual. @c ! @c Copyright (C) 2003, 2004, 2005, 2006 @c Free Software Foundation, Inc. @c @c See the file gdb.texinfo for copying conditions. - @c Revision: $Id: agentexpr.texi,v 1.2 1998/12/09 21:23:46 jimb Exp $ - @node Agent Expressions @appendix The GDB Agent Expression Mechanism --- 7,17 ---- @c This file is part of the GDB manual. @c ! @c Copyright (C) 2003, 2004, 2005, 2006, 2009 @c Free Software Foundation, Inc. @c @c See the file gdb.texinfo for copying conditions. @node Agent Expressions @appendix The GDB Agent Expression Mechanism *************** address, and the top of the stack is the *** 473,480 **** @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. @itemize @bullet --- 471,490 ---- @node Using Agent Expressions @section Using Agent Expressions ! 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: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.606 diff -p -r1.606 gdb.texinfo *** doc/gdb.texinfo 11 Jul 2009 14:09:16 -0000 1.606 --- doc/gdb.texinfo 14 Jul 2009 21:14:21 -0000 *************** conditions and actions. *** 8932,8937 **** --- 8932,8938 ---- * Create and Delete Tracepoints:: * Enable and Disable Tracepoints:: * Tracepoint Passcounts:: + * Tracepoint Conditions:: * Tracepoint Actions:: * Listing Tracepoints:: * Starting and Stopping Trace Experiments:: *************** Here are some examples of using the @cod *** 8971,8976 **** --- 8972,8984 ---- @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 *************** Examples: *** 9053,9058 **** --- 9061,9104 ---- @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 *************** messages, see @ref{Debugging Output}.) *** 26534,26543 **** @table @code @kindex maint agent @item maint agent @var{expression} Translate the given @var{expression} into remote agent bytecodes. This command is useful for debugging the Agent Expression mechanism ! (@pxref{Agent Expressions}). @kindex maint info breakpoints @item @anchor{maint info breakpoints}maint info breakpoints --- 26580,26598 ---- @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}). 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 *************** These are the currently defined stub fea *** 28415,28420 **** --- 28470,28480 ---- @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: *************** indicated it supports them in its @samp{ *** 28492,28497 **** --- 28552,28561 ---- 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:: *************** tracepoints (@pxref{Tracepoints}). *** 28804,28814 **** @table @samp ! @item QTDP:@var{n}:@var{addr}:@var{ena}:@var{step}:@var{pass}@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 present, further @samp{QTDP} packets will follow to specify this tracepoint's actions. --- 28868,28881 ---- @table @samp ! @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 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: testsuite/gdb.trace/tracecmd.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.trace/tracecmd.exp,v retrieving revision 1.12 diff -p -r1.12 tracecmd.exp *** testsuite/gdb.trace/tracecmd.exp 9 Jun 2009 17:12:43 -0000 1.12 --- testsuite/gdb.trace/tracecmd.exp 14 Jul 2009 21:14:23 -0000 *************** gdb_test "trace" "No default breakpoint *** 153,159 **** # deferred to limits test module # 1.11 tracepoint conditions ! # conditions on tracepoints not implemented # 1.12 set tracepoint in prologue # [see tfind.exp] --- 153,164 ---- # deferred to limits test module # 1.11 tracepoint conditions ! 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] --------------010003070409080800030604--