2011-11-02 Stan Shebs <stan@codesourcery.com>

String collection for tracepoints.
	* NEWS: Mention string collection.
	* common/ax.def (tracenz): New bytecode.
	* ax-gdb.h (trace_string_kludge): Declare.
	* ax-gdb.c: Include valprint.h and c-lang.h.
	(trace_string_kludge): New global.
	(gen_traced_pop): Add string case.
	(agent_command): Add string case.
	* tracepoint.h (decode_agent_options): Declare.
	* tracepoint.c: Include cli-utils.h.
	(decode_agent_options): New function.
	(validate_actionline): Call it.
	(encode_actions_1): Ditto.
	* target.h (struct target_ops): New method to_supports_string_tracing.
	(target_supports_string_tracing): New macro.
	* target.c (update_current_target): Add to_supports_string_tracing.
	* remote.c (struct remote_state): New field string_tracing.
	(remote_string_tracing_feature): New function.
	(remote_protocol_features): New feature tracenz.
	(remote_supports_string_tracing): New function.
	(init_remote_ops): Set to_supports_string_tracing.

	* tracepoint.c (agent_mem_read_string): New function.
	(eval_agent_expr): Call it for tracenz.
	* server.c (handle_query): Report support for tracenz.

	* gdb.texinfo (Tracepoint Action Lists): Document collect/s.
	(General Query Packets): Describe tracenz feature.
	* agentexpr.texi (Bytecode Descriptions): Describe tracenz.

	* gdb.trace/collection.c: Add code using strings.
	* gdb.trace/collection.exp: Add tests of string collection.
This commit is contained in:
Stan Shebs 2011-11-02 23:44:21 +00:00
parent 39f4f51d8b
commit 3065dfb6b4
19 changed files with 349 additions and 6 deletions

View File

@ -1,3 +1,27 @@
2011-11-02 Stan Shebs <stan@codesourcery.com>
String collection for tracepoints.
* NEWS: Mention string collection.
* common/ax.def (tracenz): New bytecode.
* ax-gdb.h (trace_string_kludge): Declare.
* ax-gdb.c: Include valprint.h and c-lang.h.
(trace_string_kludge): New global.
(gen_traced_pop): Add string case.
(agent_command): Add string case.
* tracepoint.h (decode_agent_options): Declare.
* tracepoint.c: Include cli-utils.h.
(decode_agent_options): New function.
(validate_actionline): Call it.
(encode_actions_1): Ditto.
* target.h (struct target_ops): New method to_supports_string_tracing.
(target_supports_string_tracing): New macro.
* target.c (update_current_target): Add to_supports_string_tracing.
* remote.c (struct remote_state): New field string_tracing.
(remote_string_tracing_feature): New function.
(remote_protocol_features): New feature tracenz.
(remote_supports_string_tracing): New function.
(init_remote_ops): Set to_supports_string_tracing.
2011-11-02 Pedro Alves <pedro@codesourcery.com>
Jan Kratochvil <jan.kratochvil@redhat.com>

View File

@ -114,6 +114,14 @@ info auto-load-scripts [REGEXP]
This command was formerly named "maintenance print section-scripts".
It is now generally useful and is no longer a maintenance-only command.
collect[/s] EXPRESSIONS
The tracepoint collect command now takes an optional modifier "/s"
that directs it to dereference pointer-to-character types and
collect the bytes of memory up to a zero byte. The behavior is
similar to what you see when you use the regular print command on a
string. An optional integer following the "/s" sets a bound on the
number of bytes that will be collected.
* Tracepoints can now be enabled and disabled at any time after a trace
experiment has been started using the standard "enable" and "disable"
commands. It is now possible to start a trace experiment with no enabled

View File

@ -42,6 +42,9 @@
#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
@ -335,6 +338,11 @@ maybe_const_expr (union exp_element **pc)
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 trace_string_kludge. */
int trace_string_kludge;
/* Scan for all static fields in the given class, including any base
classes, and generate tracing bytecodes for each. */
@ -393,19 +401,35 @@ static void
gen_traced_pop (struct gdbarch *gdbarch,
struct agent_expr *ax, struct axs_value *value)
{
int string_trace = 0;
if (trace_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:
/* We don't trace rvalues, just the lvalues necessary to
produce them. So just dispose of this value. */
ax_simple (ax, aop_pop);
if (string_trace)
{
ax_const_l (ax, trace_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
@ -413,6 +437,13 @@ gen_traced_pop (struct gdbarch *gdbarch,
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, trace_string_kludge);
ax_simple (ax, aop_tracenz);
}
}
break;
@ -422,6 +453,15 @@ gen_traced_pop (struct gdbarch *gdbarch,
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, trace_string_kludge);
ax_simple (ax, aop_tracenz);
}
break;
}
else
@ -2489,6 +2529,10 @@ agent_command (char *exp, int from_tty)
if (exp == 0)
error_no_arg (_("expression to translate"));
trace_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)

View File

@ -112,5 +112,6 @@ extern struct agent_expr *gen_trace_for_return_address (CORE_ADDR,
extern struct agent_expr *gen_eval_for_expr (CORE_ADDR, struct expression *);
extern int trace_kludge;
extern int trace_string_kludge;
#endif /* AX_GDB_H */

View File

@ -86,8 +86,7 @@ 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 (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)

View File

@ -1,3 +1,9 @@
2011-11-02 Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Tracepoint Action Lists): Document collect/s.
(General Query Packets): Describe tracenz feature.
* agentexpr.texi (Bytecode Descriptions): Describe tracenz.
2011-10-28 Paul Koning <paul_koning@dell.com>
* gdb.texinfo (gdb.types): Rename deepitems to deep_items.

View File

@ -489,6 +489,11 @@ named @code{trace_quick16}, for consistency.
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

View File

@ -10666,7 +10666,7 @@ end
@end smallexample
@kindex collect @r{(tracepoints)}
@item collect @var{expr1}, @var{expr2}, @dots{}
@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
@ -10712,6 +10712,15 @@ You can give several consecutive @code{collect} commands, each one
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.
@ -34707,6 +34716,11 @@ These are the currently defined stub features and their properties:
@tab @samp{-}
@tab No
@item @samp{tracenz}
@tab No
@tab @samp{-}
@tab No
@end multitable
These are the currently defined stub features, in more detail:
@ -34831,6 +34845,11 @@ The remote stub supports the @samp{QTEnable} (@pxref{QTEnable}) and
@samp{QTDisable} (@pxref{QTDisable}) packets that allow tracepoints
to be enabled and disabled while a trace experiment is running.
@item tracenz
@cindex string tracing, in remote protocol
The remote stub supports the @samp{tracenz} bytecode for collecting strings.
See @ref{Bytecode Descriptions} for details about the bytecode.
@end table
@item qSymbol::

View File

@ -1,3 +1,9 @@
2011-11-02 Stan Shebs <stan@codesourcery.com>
* tracepoint.c (agent_mem_read_string): New function.
(eval_agent_expr): Call it for tracenz.
* server.c (handle_query): Report support for tracenz.
2011-11-02 Yao Qi <yao@codesourcery.com>
* tracepoint.c (cmd_qtstart): Remove unused local variables.

View File

@ -1587,6 +1587,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
strcat (own_buf, ";qXfer:statictrace:read+");
strcat (own_buf, ";qXfer:traceframe-info:read+");
strcat (own_buf, ";EnableDisableTracepoints+");
strcat (own_buf, ";tracenz+");
}
return;

View File

@ -1209,6 +1209,9 @@ static enum eval_result_type eval_agent_expr (struct tracepoint_hit_ctx *ctx,
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
@ -4644,6 +4647,13 @@ eval_agent_expr (struct tracepoint_hit_ctx *ctx,
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:
@ -4727,6 +4737,66 @@ agent_mem_read (struct traceframe *tframe,
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

View File

@ -331,6 +331,9 @@ struct remote_state
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;
@ -3712,6 +3715,16 @@ remote_enable_disable_tracepoint_feature (const struct protocol_feature *feature
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,
@ -3764,6 +3777,8 @@ static struct protocol_feature remote_protocol_features[] = {
PACKET_qXfer_fdpic },
{ "QDisableRandomization", PACKET_DISABLE, remote_supported_packet,
PACKET_QDisableRandomization },
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
};
static char *remote_support_xml;
@ -9740,6 +9755,14 @@ remote_supports_enable_disable_tracepoint (void)
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)
{
@ -10459,6 +10482,7 @@ Specify the serial device it is connected to\n\
remote_ops.to_supports_disable_randomization
= remote_supports_disable_randomization;
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

View File

@ -672,6 +672,7 @@ update_current_target (void)
/* 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);
@ -840,6 +841,9 @@ update_current_target (void)
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);

View File

@ -659,6 +659,9 @@ struct target_ops
/* Does this target support disabling address space randomization? */
int (*to_supports_disable_randomization) (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
@ -904,6 +907,9 @@ int target_supports_disable_randomization (void);
#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);

View File

@ -1,3 +1,8 @@
2011-11-02 Stan Shebs <stan@codesourcery.com>
* gdb.trace/collection.c: Add code using strings.
* gdb.trace/collection.exp: Add tests of string collection.
2011-11-02 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/skip-solib.exp (executable_main): New variable.

View File

@ -201,6 +201,21 @@ int globals_test_func ()
return i; /* Set_Tracepoint_Here */
}
int strings_test_func ()
{
int i = 0;
char *locstr, *longloc;
locstr = "abcdef";
longloc = malloc(500);
strcpy(longloc, "how now brown cow spam spam spam wonderful wonderful spam");
i += strlen (locstr);
i += strlen (longloc);
return i; /* Set_Tracepoint_Here */
}
int
main (argc, argv, envp)
int argc;
@ -263,6 +278,7 @@ main (argc, argv, envp)
i += reglocal_test_func ();
i += statlocal_test_func ();
i += globals_test_func ();
i += strings_test_func ();
/* Values of globals at end of test should be different from
values that they had when trace data was captured. */

View File

@ -619,6 +619,49 @@ proc gdb_collect_return_test { } {
"collect \$_ret: cease trace debugging"
}
proc gdb_collect_strings_test { func mystr myrslt mylim msg } {
global hex
global cr
global gdb_prompt
prepare_for_trace_test
# Find the comment-identified line for setting this tracepoint.
set testline 0
gdb_test_multiple "list $func, +30" "collect $msg: find tracepoint line" {
-re "\[\r\n\](\[0-9\]+)\[^\r\n\]+ Set_Tracepoint_Here .*$gdb_prompt" {
set testline $expect_out(1,string)
pass "collect $msg: find tracepoint line"
}
-re ".*$gdb_prompt " {
fail "collect $msg: find tracepoint line (skipping strings test)"
return
}
timeout {
fail "collect $msg: find tracepoint line (skipping strings test)"
return
}
}
gdb_test "trace $testline" \
"Tracepoint \[0-9\]+ at .*" \
"collect $msg: set tracepoint"
gdb_trace_setactions "collect $msg: define actions" \
"" \
"collect/s$mylim $mystr" "^$"
# Begin the test.
run_trace_experiment $msg $func
gdb_test "print $mystr" \
"\\$\[0-9\]+ = $hex \"$myrslt\".*$cr" \
"collect $msg: collected local string"
gdb_test "tfind none" \
"#0 end .*" \
"collect $msg: cease trace debugging"
}
proc gdb_trace_collection_test {} {
global fpreg
global spreg
@ -728,6 +771,13 @@ proc gdb_trace_collection_test {} {
"globalarr\[\(l6, l7\)\]" "7" "a\[\(b, c\)\]"
gdb_collect_return_test
gdb_collect_strings_test strings_test_func "locstr" "abcdef" "" \
"local string"
gdb_collect_strings_test strings_test_func "longloc" "how now brown c" 15 \
"long local string"
}
clean_restart $executable

View File

@ -52,6 +52,7 @@
#include "ax-gdb.h"
#include "memrange.h"
#include "exceptions.h"
#include "cli/cli-utils.h"
/* readline include files */
#include "readline/readline.h"
@ -574,6 +575,46 @@ teval_pseudocommand (char *args, int from_tty)
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. */
trace_string_kludge = opts.print_max;
exp++;
if (*exp >= '0' && *exp <= '9')
trace_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);
exp = skip_spaces (exp);
return exp;
}
/* Enter a list of actions for a tracepoint. */
static void
trace_actions_command (char *args, int from_tty)
@ -656,6 +697,10 @@ validate_actionline (char **line, struct breakpoint *b)
if (cmd_cfunc_eq (c, collect_pseudocommand))
{
trace_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. */
@ -1313,6 +1358,10 @@ encode_actions_1 (struct command_line *action,
if (cmd_cfunc_eq (cmd, collect_pseudocommand))
{
trace_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. */
@ -2581,6 +2630,9 @@ trace_dump_actions (struct command_line *action,
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. */

View File

@ -212,6 +212,9 @@ struct cleanup *make_cleanup_restore_current_traceframe (void);
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);