Index: ax-gdb.c =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.c,v retrieving revision 1.89 diff -p -r1.89 ax-gdb.c *** ax-gdb.c 27 Sep 2011 13:09:34 -0000 1.89 --- ax-gdb.c 3 Oct 2011 15:34:16 -0000 *************** *** 42,47 **** --- 42,50 ---- #include "cp-support.h" #include "arch-utils.h" + #include "valprint.h" + #include "c-lang.h" + /* To make sense of this file, you should read doc/agentexpr.texi. Then look at the types and enums in ax-gdb.h. For the code itself, look at gen_expr, towards the bottom; that's the main function that *************** maybe_const_expr (union exp_element **pc *** 335,340 **** --- 338,348 ---- emits the trace bytecodes at the appropriate points. */ int trace_kludge; + /* Inspired by trace_kludge, this indicates that pointers to chars + should get an added tracenz bytecode to record nonzero bytes, up to + a length that is the value of string_kludge. */ + int string_kludge; + /* Scan for all static fields in the given class, including any base classes, and generate tracing bytecodes for each. */ *************** static void *** 393,411 **** gen_traced_pop (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value) { if (trace_kludge) switch (value->kind) { case axs_rvalue: ! /* We don't trace rvalues, just the lvalues necessary to ! produce them. So just dispose of this value. */ ! ax_simple (ax, aop_pop); break; case axs_lvalue_memory: { int length = TYPE_LENGTH (check_typedef (value->type)); /* There's no point in trying to use a trace_quick bytecode here, since "trace_quick SIZE pop" is three bytes, whereas "const8 SIZE trace" is also three bytes, does the same --- 401,435 ---- gen_traced_pop (struct gdbarch *gdbarch, struct agent_expr *ax, struct axs_value *value) { + int string_trace = 0; + if (string_kludge + && TYPE_CODE (value->type) == TYPE_CODE_PTR + && c_textual_element_type (check_typedef (TYPE_TARGET_TYPE (value->type)), + 's')) + string_trace = 1; + if (trace_kludge) switch (value->kind) { case axs_rvalue: ! if (string_trace) ! { ! ax_const_l (ax, string_kludge); ! ax_simple (ax, aop_tracenz); ! } ! else ! /* We don't trace rvalues, just the lvalues necessary to ! produce them. So just dispose of this value. */ ! ax_simple (ax, aop_pop); break; case axs_lvalue_memory: { int length = TYPE_LENGTH (check_typedef (value->type)); + if (string_trace) + ax_simple (ax, aop_dup); + /* There's no point in trying to use a trace_quick bytecode here, since "trace_quick SIZE pop" is three bytes, whereas "const8 SIZE trace" is also three bytes, does the same *************** gen_traced_pop (struct gdbarch *gdbarch, *** 413,418 **** --- 437,449 ---- work correctly for objects with large sizes. */ ax_const_l (ax, length); ax_simple (ax, aop_trace); + + if (string_trace) + { + ax_simple (ax, aop_ref32); + ax_const_l (ax, string_kludge); + ax_simple (ax, aop_tracenz); + } } break; *************** gen_traced_pop (struct gdbarch *gdbarch, *** 422,427 **** --- 453,467 ---- larger than will fit in a stack, so just mark it for collection and be done with it. */ ax_reg_mask (ax, value->u.reg); + + /* But if the register points to a string, assume the value + will fit on the stack and push it anyway. */ + if (string_trace) + { + ax_reg (ax, value->u.reg); + ax_const_l (ax, string_kludge); + ax_simple (ax, aop_tracenz); + } break; } else *************** agent_command (char *exp, int from_tty) *** 2489,2494 **** --- 2529,2538 ---- if (exp == 0) error_no_arg (_("expression to translate")); + string_kludge = 0; + if (*exp == '/') + exp = decode_agent_options (exp); + /* Recognize the return address collection directive specially. Note that it is not really an expression of any sort. */ if (strcmp (exp, "$_ret") == 0) Index: ax-gdb.h =================================================================== RCS file: /cvs/src/src/gdb/ax-gdb.h,v retrieving revision 1.21 diff -p -r1.21 ax-gdb.h *** ax-gdb.h 27 Sep 2011 13:09:35 -0000 1.21 --- ax-gdb.h 3 Oct 2011 15:34:16 -0000 *************** extern struct agent_expr *gen_trace_for_ *** 112,116 **** --- 112,117 ---- extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *); extern int trace_kludge; + extern int string_kludge; #endif /* AX_GDB_H */ Index: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.463 diff -p -r1.463 remote.c *** remote.c 14 Sep 2011 12:26:29 -0000 1.463 --- remote.c 3 Oct 2011 15:34:16 -0000 *************** struct remote_state *** 331,336 **** --- 331,339 ---- tracepoints while a trace experiment is running. */ int enable_disable_tracepoints; + /* True if the stub can collect strings using tracenz bytecode. */ + int string_tracing; + /* Nonzero if the user has pressed Ctrl-C, but the target hasn't responded to that. */ int ctrlc_pending_p; *************** remote_enable_disable_tracepoint_feature *** 3711,3716 **** --- 3714,3729 ---- rs->enable_disable_tracepoints = (support == PACKET_ENABLE); } + static void + remote_string_tracing_feature (const struct protocol_feature *feature, + enum packet_support support, + const char *value) + { + struct remote_state *rs = get_remote_state (); + + rs->string_tracing = (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 *** 3761,3766 **** --- 3774,3781 ---- remote_enable_disable_tracepoint_feature, -1 }, { "qXfer:fdpic:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_fdpic }, + { "tracenz", PACKET_DISABLE, + remote_string_tracing_feature, -1 }, }; static char *remote_support_xml; *************** remote_supports_enable_disable_tracepoin *** 9704,9709 **** --- 9719,9732 ---- return rs->enable_disable_tracepoints; } + static int + remote_supports_string_tracing (void) + { + struct remote_state *rs = get_remote_state (); + + return rs->string_tracing; + } + static void remote_trace_init (void) { *************** Specify the serial device it is connecte *** 10421,10426 **** --- 10444,10450 ---- remote_ops.to_supports_non_stop = remote_supports_non_stop; remote_ops.to_supports_multi_process = remote_supports_multi_process; remote_ops.to_supports_enable_disable_tracepoint = remote_supports_enable_disable_tracepoint; + remote_ops.to_supports_string_tracing = remote_supports_string_tracing; remote_ops.to_trace_init = remote_trace_init; remote_ops.to_download_tracepoint = remote_download_tracepoint; remote_ops.to_download_trace_state_variable Index: target.c =================================================================== RCS file: /cvs/src/src/gdb/target.c,v retrieving revision 1.285 diff -p -r1.285 target.c *** target.c 6 Jun 2011 12:47:07 -0000 1.285 --- target.c 3 Oct 2011 15:34:17 -0000 *************** update_current_target (void) *** 672,677 **** --- 672,678 ---- /* Do not inherit to_search_memory. */ INHERIT (to_supports_multi_process, t); INHERIT (to_supports_enable_disable_tracepoint, t); + INHERIT (to_supports_string_tracing, t); INHERIT (to_trace_init, t); INHERIT (to_download_tracepoint, t); INHERIT (to_download_trace_state_variable, t); *************** update_current_target (void) *** 840,845 **** --- 841,849 ---- de_fault (to_supports_enable_disable_tracepoint, (int (*) (void)) return_zero); + de_fault (to_supports_string_tracing, + (int (*) (void)) + return_zero); de_fault (to_trace_init, (void (*) (void)) tcomplain); Index: target.h =================================================================== RCS file: /cvs/src/src/gdb/target.h,v retrieving revision 1.212 diff -p -r1.212 target.h *** target.h 27 Sep 2011 15:30:18 -0000 1.212 --- target.h 3 Oct 2011 15:34:17 -0000 *************** struct target_ops *** 653,658 **** --- 653,661 ---- experiment is running? */ int (*to_supports_enable_disable_tracepoint) (void); + /* Does this target support the tracenz bytecode for string collection? */ + int (*to_supports_string_tracing) (void); + /* Determine current architecture of thread PTID. The target is supposed to determine the architecture of the code where *************** struct address_space *target_thread_addr *** 894,899 **** --- 897,905 ---- #define target_supports_enable_disable_tracepoint() \ (*current_target.to_supports_enable_disable_tracepoint) () + #define target_supports_string_tracing() \ + (*current_target.to_supports_string_tracing) () + /* Invalidate all target dcaches. */ extern void target_dcache_invalidate (void); Index: tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.c,v retrieving revision 1.232 diff -p -r1.232 tracepoint.c *** tracepoint.c 27 Sep 2011 13:09:36 -0000 1.232 --- tracepoint.c 3 Oct 2011 15:34:17 -0000 *************** teval_pseudocommand (char *args, int fro *** 574,579 **** --- 574,620 ---- error (_("This command can only be used in a tracepoint actions list.")); } + /* Parse any collection options, such as /s for strings. */ + + char * + decode_agent_options (char *exp) + { + struct value_print_options opts; + + if (*exp != '/') + return exp; + + /* Call this to borrow the print elements default for collection + size. */ + get_user_print_options (&opts); + + exp++; + if (*exp == 's') + { + if (target_supports_string_tracing ()) + { + /* Allow an optional decimal number giving an explicit maximum + string length, defaulting it to the "print elements" value; + so "collect/s80 mystr" gets at most 80 bytes of string. */ + string_kludge = opts.print_max; + exp++; + if (*exp >= '0' && *exp <= '9') + string_kludge = atoi (exp); + while (*exp >= '0' && *exp <= '9') + exp++; + } + else + error (_("Target does not support \"/s\" option for string tracing.")); + } + else + error (_("Undefined collection format \"%c\"."), *exp); + + while (*exp == ' ' || *exp == '\t') + exp++; + + return exp; + } + /* Enter a list of actions for a tracepoint. */ static void trace_actions_command (char *args, int from_tty) *************** validate_actionline (char **line, struct *** 656,661 **** --- 697,706 ---- if (cmd_cfunc_eq (c, collect_pseudocommand)) { + string_kludge = 0; + if (*p == '/') + p = decode_agent_options (p); + do { /* Repeat over a comma-separated list. */ QUIT; /* Allow user to bail out with ^C. */ *************** encode_actions_1 (struct command_line *a *** 1313,1318 **** --- 1358,1367 ---- if (cmd_cfunc_eq (cmd, collect_pseudocommand)) { + string_kludge = 0; + if (*action_exp == '/') + action_exp = decode_agent_options (action_exp); + do { /* Repeat over a comma-separated list. */ QUIT; /* Allow user to bail out with ^C. */ *************** trace_dump_actions (struct command_line *** 2581,2586 **** --- 2630,2638 ---- STEPPING_ACTIONS should be equal. */ if (stepping_frame == stepping_actions) { + if (*action_exp == '/') + action_exp = decode_agent_options (action_exp); + do { /* Repeat over a comma-separated list. */ QUIT; /* Allow user to bail out with ^C. */ Index: tracepoint.h =================================================================== RCS file: /cvs/src/src/gdb/tracepoint.h,v retrieving revision 1.43 diff -p -r1.43 tracepoint.h *** tracepoint.h 25 Jul 2011 11:24:44 -0000 1.43 --- tracepoint.h 3 Oct 2011 15:34:17 -0000 *************** struct cleanup *make_cleanup_restore_cur *** 212,217 **** --- 212,220 ---- struct cleanup *make_cleanup_restore_traceframe_number (void); void free_actions (struct breakpoint *); + + extern char *decode_agent_options (char *exp); + extern void validate_actionline (char **, struct breakpoint *); extern void end_actions_pseudocommand (char *args, int from_tty); Index: gdbserver/server.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.c,v retrieving revision 1.148 diff -p -r1.148 server.c *** gdbserver/server.c 1 Sep 2011 03:14:10 -0000 1.148 --- gdbserver/server.c 3 Oct 2011 15:34:17 -0000 *************** handle_query (char *own_buf, int packet_ *** 1559,1565 **** strcat (own_buf, ";qXfer:statictrace:read+"); strcat (own_buf, ";qXfer:traceframe-info:read+"); strcat (own_buf, ";EnableDisableTracepoints+"); ! } return; } --- 1559,1566 ---- strcat (own_buf, ";qXfer:statictrace:read+"); strcat (own_buf, ";qXfer:traceframe-info:read+"); strcat (own_buf, ";EnableDisableTracepoints+"); ! strcat (own_buf, ";tracenz+"); ! } return; } Index: gdbserver/tracepoint.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/tracepoint.c,v retrieving revision 1.27 diff -p -r1.27 tracepoint.c *** gdbserver/tracepoint.c 15 Sep 2011 22:54:13 -0000 1.27 --- gdbserver/tracepoint.c 3 Oct 2011 15:34:17 -0000 *************** static enum eval_result_type eval_agent_ *** 1209,1214 **** --- 1209,1217 ---- static int agent_mem_read (struct traceframe *tframe, unsigned char *to, CORE_ADDR from, ULONGEST len); + static int agent_mem_read_string (struct traceframe *tframe, + unsigned char *to, CORE_ADDR from, + ULONGEST len); static int agent_tsv_read (struct traceframe *tframe, int n); #ifndef IN_PROCESS_AGENT *************** eval_agent_expr (struct tracepoint_hit_c *** 4651,4656 **** --- 4654,4666 ---- agent_tsv_read (tframe, arg); break; + case gdb_agent_op_tracenz: + agent_mem_read_string (tframe, NULL, (CORE_ADDR) stack[--sp], + (ULONGEST) top); + if (--sp >= 0) + top = stack[sp]; + break; + /* GDB never (currently) generates any of these ops. */ case gdb_agent_op_float: case gdb_agent_op_ref_float: *************** agent_mem_read (struct traceframe *tfram *** 4734,4739 **** --- 4744,4809 ---- return 0; } + static int + agent_mem_read_string (struct traceframe *tframe, + unsigned char *to, CORE_ADDR from, ULONGEST len) + { + unsigned char *buf, *mspace; + ULONGEST remaining = len; + unsigned short blocklen, i; + + /* To save a bit of space, block lengths are 16-bit, so break large + requests into multiple blocks. Bordering on overkill for strings, + but it could happen that someone specifies a large max length. */ + while (remaining > 0) + { + size_t sp; + + blocklen = (remaining > 65535 ? 65535 : remaining); + /* We want working space to accumulate nonzero bytes, since + traceframes must have a predecided size (otherwise it gets + harder to wrap correctly for the circular case, etc). */ + buf = (unsigned char *) xmalloc (blocklen + 1); + for (i = 0; i < blocklen; ++i) + { + /* Read the string one byte at a time, in case the string is + at the end of a valid memory area - we don't want a + correctly-terminated string to engender segvio + complaints. */ + read_inferior_memory (from + i, buf + i, 1); + + if (buf[i] == '\0') + { + blocklen = i + 1; + /* Make sure outer loop stops now too. */ + remaining = blocklen; + break; + } + } + sp = 1 + sizeof (from) + sizeof (blocklen) + blocklen; + mspace = add_traceframe_block (tframe, sp); + if (mspace == NULL) + { + xfree (buf); + return 1; + } + /* Identify block as a memory block. */ + *mspace = 'M'; + ++mspace; + /* Record address and size. */ + memcpy ((void *) mspace, (void *) &from, sizeof (from)); + mspace += sizeof (from); + memcpy ((void *) mspace, (void *) &blocklen, sizeof (blocklen)); + mspace += sizeof (blocklen); + /* Copy the string contents. */ + memcpy ((void *) mspace, (void *) buf, blocklen); + remaining -= blocklen; + from += blocklen; + xfree (buf); + } + return 0; + } + /* Record the value of a trace state variable. */ static int Index: doc/agentexpr.texi =================================================================== RCS file: /cvs/src/src/gdb/doc/agentexpr.texi,v retrieving revision 1.15 diff -p -r1.15 agentexpr.texi *** doc/agentexpr.texi 24 Feb 2011 07:38:00 -0000 1.15 --- doc/agentexpr.texi 3 Oct 2011 15:34:17 -0000 *************** named @code{trace_quick16}, for consiste *** 489,494 **** --- 489,499 ---- Record the value of trace state variable number @var{n} in the trace buffer. The handling of @var{n} is as described for @code{getv}. + @item @code{tracenz} (0x2f) @var{addr} @var{size} @result{} + Record the bytes at @var{addr} in a trace buffer, for later retrieval + by GDB. Stop at either the first zero byte, or when @var{size} bytes + have been recorded, whichever occurs first. + @item @code{end} (0x27): @result{} Stop executing bytecode; the result should be the top element of the stack. If the purpose of the expression was to compute an lvalue or a Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.865 diff -p -r1.865 gdb.texinfo *** doc/gdb.texinfo 29 Sep 2011 02:25:49 -0000 1.865 --- doc/gdb.texinfo 3 Oct 2011 15:34:18 -0000 *************** end *** 10268,10274 **** @end smallexample @kindex collect @r{(tracepoints)} ! @item collect @var{expr1}, @var{expr2}, @dots{} Collect values of the given expressions when the tracepoint is hit. This command accepts a comma-separated list of any valid expressions. In addition to global, static, or local variables, the following --- 10268,10274 ---- @end smallexample @kindex collect @r{(tracepoints)} ! @item collect@r{[}/@var{mods}@r{]} @var{expr1}, @var{expr2}, @dots{} Collect values of the given expressions when the tracepoint is hit. This command accepts a comma-separated list of any valid expressions. In addition to global, static, or local variables, the following *************** You can give several consecutive @code{c *** 10314,10319 **** --- 10314,10328 ---- with a single argument, or one @code{collect} command with several arguments separated by commas; the effect is the same. + The optional @var{mods} changes the usual handling of the arguments. + @code{s} requests that pointers to chars be handled as strings, in + particular collecting the contents of the memory being pointed at, up + to the first zero. The upper bound is by default the value of the + @code{print elements} variable; if @code{s} is followed by a decimal + number, that is the upper bound instead. So for instance + @samp{collect/s25 mystr} collects as many as 25 characters at + @samp{mystr}. + The command @code{info scope} (@pxref{Symbols, info scope}) is particularly useful for figuring out what data to collect. Index: common/ax.def =================================================================== RCS file: /cvs/src/src/gdb/common/ax.def,v retrieving revision 1.4 diff -p -r1.4 ax.def *** common/ax.def 25 Feb 2011 14:21:05 -0000 1.4 --- common/ax.def 3 Oct 2011 15:34:19 -0000 *************** DEFOP (swap, 0, 0, 2, 2, 0x2b) *** 86,93 **** DEFOP (getv, 2, 0, 0, 1, 0x2c) DEFOP (setv, 2, 0, 0, 1, 0x2d) DEFOP (tracev, 2, 0, 0, 1, 0x2e) ! /* We need something here just to make the tables come out ok. */ ! DEFOP (invalid, 0, 0, 0, 0, 0x2f) DEFOP (trace16, 2, 0, 1, 1, 0x30) /* We need something here just to make the tables come out ok. */ DEFOP (invalid2, 0, 0, 0, 0, 0x31) --- 86,92 ---- DEFOP (getv, 2, 0, 0, 1, 0x2c) DEFOP (setv, 2, 0, 0, 1, 0x2d) DEFOP (tracev, 2, 0, 0, 1, 0x2e) ! DEFOP (tracenz, 0, 0, 2, 0, 0x2f) DEFOP (trace16, 2, 0, 1, 1, 0x30) /* We need something here just to make the tables come out ok. */ DEFOP (invalid2, 0, 0, 0, 0, 0x31)