* NEWS: Mention tracepoint additions.

* breakpoint.h (struct tracepoint): New field traceframe_usage.
	* breakpoint.c (print_one_breakpoint_location): Identify
	tracepoints as such when reporting hit counts, report
	trace buffer usage.
	(create_tracepoint_from_upload): Copy status info.
	* tracepoint.h (struct trace_status): Rename error_desc to stop_desc,
	add fields user_name, notes, start_time, stop_time.
	(struct uploaded_tp): Add fields hit_count, traceframe_usage.
	* tracepoint.c (trace_user): New global.
	(trace_notes): New global.
	(trace_stop_notes): New global.
	(start_tracing): Add argument and trace note handling.
	(stop_tracing): Ditto.
	(trace_start_command): Add notes argument.
	(trace_stop_command): Ditto.
	(trace_status_command): Report additional status info.
	(trace_status_mi): Similarly.
	(trace_save): Update, record tracepoint status.
	(set_disconnected_tracing): Call target method directly.
	(send_disconnected_tracing_value): Remove.
	(set_trace_user): New function.
	(set_trace_notes): New function.
	(set_trace_stop_notes): New function.
	(parse_trace_status): Handle additional status.
	(parse_tracepoint_status): New function.
	(parse_tracepoint_definition): Call it.
	(tfile_get_tracepoint_status): New function.
	(init_tfile_ops): Use it.
	(_initialize_tracepoint): Add new setshows.
	* target.h (struct target_ops): New methods to_get_tracepoint_status
	and to_set_trace_notes.
	(target_get_tracepoint_status): New macro.
	(target_set_trace_notes): New macro.
	* target.c (update_current_target): Add new methods.
	* remote.c (remote_get_tracepoint_status): New function.
	(remote_set_trace_notes): New function.
	(init_remote_ops): Add them.
	* mi/mi-main.c (mi_cmd_trace_start): Add argument to call.
	(mi_cmd_trace_stop): Ditto.

	* tracepoint.c (struct tracepoint): New field traceframe_usage.
	(tracing_start_time): New global.
	(tracing_stop_time): New global.
	(tracing_user_name): New global.
	(tracing_notes): New global.
	(tracing_stop_note): New global.
	(cmd_qtstart): Set traceframe_usage, start_time.
	(stop_tracing): Set stop_time.
	(cmd_qtstatus): Report additional status.
	(cmd_qtp): New function.
	(handle_tracepoint_query): Call it.
	(cmd_qtnotes): New function.
	(handle_tracepoint_general_set): Call it.
	(get_timestamp): Rename from tsv_get_timestamp.

	* gdb.texinfo (Starting and Stopping Trace Experiments): Document
	note-related options and variables.
	(Tracepoint Packets): Document packet changes.

	* gdb.trace/tstatus.exp: New.
	* gdb.trace/actions.c: Include string.h.
This commit is contained in:
Stan Shebs 2011-11-20 23:59:49 +00:00
parent 9866a1803a
commit f196051f5e
18 changed files with 961 additions and 64 deletions

View File

@ -1,3 +1,46 @@
2011-11-20 Stan Shebs <stan@codesourcery.com>
* NEWS: Mention tracepoint additions.
* breakpoint.h (struct tracepoint): New field traceframe_usage.
* breakpoint.c (print_one_breakpoint_location): Identify
tracepoints as such when reporting hit counts, report
trace buffer usage.
(create_tracepoint_from_upload): Copy status info.
* tracepoint.h (struct trace_status): Rename error_desc to stop_desc,
add fields user_name, notes, start_time, stop_time.
(struct uploaded_tp): Add fields hit_count, traceframe_usage.
* tracepoint.c (trace_user): New global.
(trace_notes): New global.
(trace_stop_notes): New global.
(start_tracing): Add argument and trace note handling.
(stop_tracing): Ditto.
(trace_start_command): Add notes argument.
(trace_stop_command): Ditto.
(trace_status_command): Report additional status info.
(trace_status_mi): Similarly.
(trace_save): Update, record tracepoint status.
(set_disconnected_tracing): Call target method directly.
(send_disconnected_tracing_value): Remove.
(set_trace_user): New function.
(set_trace_notes): New function.
(set_trace_stop_notes): New function.
(parse_trace_status): Handle additional status.
(parse_tracepoint_status): New function.
(parse_tracepoint_definition): Call it.
(tfile_get_tracepoint_status): New function.
(init_tfile_ops): Use it.
(_initialize_tracepoint): Add new setshows.
* target.h (struct target_ops): New methods to_get_tracepoint_status
and to_set_trace_notes.
(target_get_tracepoint_status): New macro.
(target_set_trace_notes): New macro.
* target.c (update_current_target): Add new methods.
* remote.c (remote_get_tracepoint_status): New function.
(remote_set_trace_notes): New function.
(init_remote_ops): Add them.
* mi/mi-main.c (mi_cmd_trace_start): Add argument to call.
(mi_cmd_trace_stop): Ditto.
2011-11-20 Sanjoy Das <sdas@igalia.com>
* jit.c: Include regcache.h.

View File

@ -133,6 +133,17 @@ collect[/s] EXPRESSIONS
string. An optional integer following the "/s" sets a bound on the
number of bytes that will be collected.
tstart [NOTES]
The trace start command now interprets any supplied arguments as a
note to be recorded with the trace run, with an effect similar to
setting the variable trace-notes.
tstop [NOTES]
The trace stop command now interprets any arguments as a note to be
mentioned along with the tstatus report that the trace was stopped
with a command. The effect is similar to setting the variable
trace-stop-notes.
* 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
@ -176,6 +187,22 @@ show basenames-may-differ
If not set (the default), all source files are assumed to have just
one base name, and gdb will do file name comparisons more efficiently.
set trace-user
show trace-user
set trace-notes
show trace-notes
Set a user name and notes for the current and any future trace runs.
This is useful for long-running and/or disconnected traces, to
inform others (or yourself) as to who is running the trace, supply
contact information, or otherwise explain what is going on.
set trace-stop-notes
show trace-stop-notes
Set a note attached to the trace run, that is displayed when the
trace has been stopped by a tstop command. This is useful for
instance as an explanation, if you are stopping a trace run that was
started by someone else.
* New remote packets
QTEnable
@ -186,6 +213,14 @@ QTDisable
Dynamically disable a tracepoint in a started trace experiment.
QTNotes
Set the user and notes of the trace run.
qTP
Query the current status of a tracepoint.
qTMinFTPILen
Query the minimum length of instruction at which a fast tracepoint may

View File

@ -4879,6 +4879,8 @@ print_one_breakpoint_location (struct breakpoint *b,
/* FIXME should make an annotation for this. */
if (ep_is_catchpoint (b))
ui_out_text (uiout, "\tcatchpoint");
else if (is_tracepoint (b))
ui_out_text (uiout, "\ttracepoint");
else
ui_out_text (uiout, "\tbreakpoint");
ui_out_text (uiout, " already hit ");
@ -4903,6 +4905,18 @@ print_one_breakpoint_location (struct breakpoint *b,
ui_out_text (uiout, " hits\n");
}
if (!part_of_multiple && is_tracepoint (b))
{
struct tracepoint *tp = (struct tracepoint *) b;
if (tp->traceframe_usage)
{
ui_out_text (uiout, "\ttrace buffer usage ");
ui_out_field_int (uiout, "traceframe-usage", tp->traceframe_usage);
ui_out_text (uiout, " bytes\n");
}
}
l = b->commands ? b->commands->commands : NULL;
if (!part_of_multiple && l)
{
@ -12904,6 +12918,10 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
"have no source form, ignoring them"),
utp->number);
/* Copy any status information that might be available. */
tp->base.hit_count = utp->hit_count;
tp->traceframe_usage = utp->traceframe_usage;
return tp;
}

View File

@ -710,6 +710,10 @@ struct tracepoint
/* The number of the tracepoint on the target. */
int number_on_target;
/* The total space taken by all the trace frames for this
tracepoint. */
ULONGEST traceframe_usage;
/* The static tracepoint marker id, if known. */
char *static_trace_marker_id;

View File

@ -1,3 +1,9 @@
2011-11-20 Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Starting and Stopping Trace Experiments): Document
note-related options and variables.
(Tracepoint Packets): Document packet changes.
2011-11-20 Sanjoy Das <sdas@igalia.com>
* gdb.texinfo (JIT Interface): Add documentation on writing and

View File

@ -10902,20 +10902,27 @@ Cnt ID Enb Address What
@subsection Starting and Stopping Trace Experiments
@table @code
@kindex tstart
@kindex tstart [ @var{notes} ]
@cindex start a new trace experiment
@cindex collected data discarded
@item tstart
This command takes no arguments. It starts the trace experiment, and
begins collecting data. This has the side effect of discarding all
the data collected in the trace buffer during the previous trace
experiment.
This command starts the trace experiment, and begins collecting data.
It has the side effect of discarding all the data collected in the
trace buffer during the previous trace experiment. If any arguments
are supplied, they are taken as a note and stored with the trace
experiment's state. The notes may be arbitrary text, and are
especially useful with disconnected tracing in a multi-user context;
the notes can explain what the trace is doing, supply user contact
information, and so forth.
@kindex tstop
@kindex tstop [ @var{notes} ]
@cindex stop a running trace experiment
@item tstop
This command takes no arguments. It ends the trace experiment, and
stops collecting data.
This command stops the trace experiment. If any arguments are
supplied, they are recorded with the experiment as a note. This is
useful if you are stopping a trace started by someone else, for
instance if the trace is interfering with the system's behavior and
needs to be stopped quickly.
@strong{Note}: a trace experiment and data collection may stop
automatically if any tracepoint's passcount is reached
@ -11019,6 +11026,33 @@ for instance if you are looking at frames from a trace file.
@end table
@table @code
@item set trace-user @var{text}
@kindex set trace-user
@item show trace-user
@kindex show trace-user
@item set trace-notes @var{text}
@kindex set trace-notes
Set the trace run's notes.
@item show trace-notes
@kindex show trace-notes
Show the trace run's notes.
@item set trace-stop-notes @var{text}
@kindex set trace-stop-notes
Set the trace run's stop notes. The handling of the note is as for
@code{tstop} arguments; the set command is convenient way to fix a
stop note that is mistaken or incomplete.
@item show trace-stop-notes
@kindex show trace-stop-notes
Show the trace run's stop notes.
@end table
@node Tracepoint Restrictions
@subsection Tracepoint Restrictions
@ -35115,6 +35149,8 @@ the command by a @samp{,}, not a @samp{:}, contrary to the naming
conventions above. Please don't use this packet as a model for new
packets.)
@item QTNotes
@item qTP
@item QTSave
@item qTsP
@item qTsV
@ -35697,8 +35733,11 @@ explanations as one of the optional fields:
@item tnotrun:0
No trace has been run yet.
@item tstop:0
The trace was stopped by a user-originated stop command.
@item tstop[:@var{text}]:0
The trace was stopped by a user-originated stop command. The optional
@var{text} field is a user-supplied string supplied as part of the
stop command (for instance, an explanation of why the trace was
stopped manually). It is hex-encoded.
@item tfull:0
The trace stopped because the trace buffer filled up.
@ -35754,6 +35793,22 @@ that the trace run will stop.
@end table
@item qTP:@var{tp}:@var{addr}
@cindex tracepoint status, remote request
@cindex @samp{qTP} packet
Ask the stub for the current state of tracepoint number @var{tp} at
address @var{addr}.
Replies:
@table @samp
@item V@var{hits}:@var{usage}
The tracepoint has been hit @var{hits} times so far during the trace
run, and accounts for @var{usage} in the trace buffer. Note that
@code{while-stepping} steps are not counted as separate hits, but the
steps' space consumption is added into the usage number.
@end table
@item qTV:@var{var}
@cindex trace state variable value, remote request
@cindex @samp{qTV} packet
@ -35847,6 +35902,11 @@ available.
This packet directs the target to use a circular trace buffer if
@var{value} is 1, or a linear buffer if the value is 0.
@item QTNotes:@r{[}@var{type}:@var{text}@r{]}@r{[};@var{type}:@var{text}@r{]}@dots{}
This packet adds optional textual notes to the trace run. Allowable
types include @code{user}, @code{notes}, and @code{tstop}, the
@var{text} fields are arbitrary strings, hex-encoded.
@end table
@subsection Relocate instruction reply packet

View File

@ -1,3 +1,20 @@
2011-11-17 Stan Shebs <stan@codesourcery.com>
* tracepoint.c (struct tracepoint): New field traceframe_usage.
(tracing_start_time): New global.
(tracing_stop_time): New global.
(tracing_user_name): New global.
(tracing_notes): New global.
(tracing_stop_note): New global.
(cmd_qtstart): Set traceframe_usage, start_time.
(stop_tracing): Set stop_time.
(cmd_qtstatus): Report additional status.
(cmd_qtp): New function.
(handle_tracepoint_query): Call it.
(cmd_qtnotes): New function.
(handle_tracepoint_general_set): Call it.
(get_timestamp): Rename from tsv_get_timestamp.
2011-11-14 Stan Shebs <stan@codesourcery.com>
Kwok Cheung Yeung <kcy@codesourcery.com>

View File

@ -632,6 +632,9 @@ struct tracepoint
Note that while-stepping steps are not counted as "hits". */
long hit_count;
/* Cached sum of the sizes of traceframes created by this point. */
long traceframe_usage;
CORE_ADDR compiled_cond;
/* Link to the next tracepoint in the list. */
@ -1144,6 +1147,27 @@ static const char *tracing_stop_reason = "tnotrun";
static int tracing_stop_tpnum;
/* 64-bit timestamps for the trace run's start and finish, expressed
in microseconds from the Unix epoch. */
LONGEST tracing_start_time;
LONGEST tracing_stop_time;
/* The (optional) user-supplied name of the user that started the run.
This is an arbitrary string, and may be NULL. */
char *tracing_user_name;
/* Optional user-supplied text describing the run. This is
an arbitrary string, and may be NULL. */
char *tracing_notes;
/* Optional user-supplied text explaining a tstop command. This is an
arbitrary string, and may be NULL. */
char *tracing_stop_note;
#endif
/* Functions local to this file. */
@ -1266,6 +1290,8 @@ static void download_tracepoint (struct tracepoint *);
static int install_fast_tracepoint (struct tracepoint *, char *errbuf);
#endif
static LONGEST get_timestamp (void);
#if defined(__GNUC__)
# define memory_barrier() asm volatile ("" : : : "memory")
#else
@ -3027,6 +3053,7 @@ cmd_qtstart (char *packet)
{
/* Ensure all the hit counts start at zero. */
tpoint->hit_count = 0;
tpoint->traceframe_usage = 0;
if (tpoint->type == trap_tracepoint)
{
@ -3103,6 +3130,7 @@ cmd_qtstart (char *packet)
trace_buffer_is_full = 0;
expr_eval_result = expr_eval_no_error;
error_tracepoint = NULL;
tracing_start_time = get_timestamp ();
/* Tracing is now active, hits will now start being logged. */
tracing = 1;
@ -3172,6 +3200,7 @@ stop_tracing (void)
fatal ("Error clearing tracing variable in lib");
}
tracing_stop_time = get_timestamp ();
tracing_stop_reason = "t???";
tracing_stop_tpnum = 0;
if (stopping_tracepoint)
@ -3352,6 +3381,26 @@ static void
cmd_qtstatus (char *packet)
{
char *stop_reason_rsp = NULL;
char *buf1, *buf2, *buf3, *str;
int slen;
/* Translate the plain text of the notes back into hex for
transmission. */
str = (tracing_user_name ? tracing_user_name : "");
slen = strlen (str);
buf1 = (char *) alloca (slen * 2 + 1);
hexify (buf1, str, slen);
str = (tracing_notes ? tracing_notes : "");
slen = strlen (str);
buf2 = (char *) alloca (slen * 2 + 1);
hexify (buf2, str, slen);
str = (tracing_stop_note ? tracing_stop_note : "");
slen = strlen (str);
buf3 = (char *) alloca (slen * 2 + 1);
hexify (buf3, str, slen);
trace_debug ("Returning trace status as %d, stop reason %s",
tracing, tracing_stop_reason);
@ -3368,7 +3417,7 @@ cmd_qtstatus (char *packet)
stop_reason_rsp = (char *) tracing_stop_reason;
/* The user visible error string in terror needs to be hex encoded.
We leave it as plain string in `tracepoint_stop_reason' to ease
We leave it as plain string in `tracing_stop_reason' to ease
debugging. */
if (strncmp (stop_reason_rsp, "terror:", strlen ("terror:")) == 0)
{
@ -3384,19 +3433,58 @@ cmd_qtstatus (char *packet)
convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name));
}
/* If this was a forced stop, include any stop note that was supplied. */
if (strcmp (stop_reason_rsp, "tstop") == 0)
{
stop_reason_rsp = alloca (strlen ("tstop:") + strlen (buf3) + 1);
strcpy (stop_reason_rsp, "tstop:");
strcat (stop_reason_rsp, buf3);
}
sprintf (packet,
"T%d;"
"%s:%x;"
"tframes:%x;tcreated:%x;"
"tfree:%x;tsize:%s;"
"circular:%d;"
"disconn:%d",
"disconn:%d;"
"starttime:%llx;stoptime:%llx;"
"username:%s:;notes:%s:",
tracing ? 1 : 0,
stop_reason_rsp, tracing_stop_tpnum,
traceframe_count, traceframes_created,
free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0),
circular_trace_buffer,
disconnected_tracing);
disconnected_tracing,
tracing_start_time, tracing_stop_time,
buf1, buf2);
}
static void
cmd_qtp (char *own_buf)
{
ULONGEST num, addr;
struct tracepoint *tpoint;
char *packet = own_buf;
packet += strlen ("qTP:");
packet = unpack_varlen_hex (packet, &num);
++packet; /* skip a colon */
packet = unpack_varlen_hex (packet, &addr);
/* See if we already have this tracepoint. */
tpoint = find_tracepoint (num, addr);
if (!tpoint)
{
trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found",
(int) num, paddress (addr));
write_enn (own_buf);
return;
}
sprintf (own_buf, "V%lx:%lx", tpoint->hit_count, tpoint->traceframe_usage);
}
/* State variables to help return all the tracepoint bits. */
@ -3710,6 +3798,63 @@ cmd_bigqtbuffer (char *own_buf)
write_enn (own_buf);
}
static void
cmd_qtnotes (char *own_buf)
{
size_t nbytes;
char *saved, *user, *notes, *stopnote;
char *packet = own_buf;
packet += strlen ("QTNotes:");
while (*packet)
{
if (strncmp ("user:", packet, strlen ("user:")) == 0)
{
packet += strlen ("user:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
user = xmalloc (nbytes + 1);
nbytes = unhexify (user, saved, nbytes);
user[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("User is '%s'", user);
tracing_user_name = user;
}
else if (strncmp ("notes:", packet, strlen ("notes:")) == 0)
{
packet += strlen ("notes:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
notes = xmalloc (nbytes + 1);
nbytes = unhexify (notes, saved, nbytes);
notes[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("Notes is '%s'", notes);
tracing_notes = notes;
}
else if (strncmp ("tstop:", packet, strlen ("tstop:")) == 0)
{
packet += strlen ("tstop:");
saved = packet;
packet = strchr (packet, ';');
nbytes = (packet - saved) / 2;
stopnote = xmalloc (nbytes + 1);
nbytes = unhexify (stopnote, saved, nbytes);
stopnote[nbytes] = '\0';
++packet; /* skip the semicolon */
trace_debug ("tstop note is '%s'", stopnote);
tracing_stop_note = stopnote;
}
else
break;
}
write_ok (own_buf);
}
int
handle_tracepoint_general_set (char *packet)
{
@ -3774,6 +3919,11 @@ handle_tracepoint_general_set (char *packet)
cmd_bigqtbuffer (packet);
return 1;
}
else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0)
{
cmd_qtnotes (packet);
return 1;
}
return 0;
}
@ -3786,6 +3936,11 @@ handle_tracepoint_query (char *packet)
cmd_qtstatus (packet);
return 1;
}
else if (strncmp ("qTP:", packet, strlen ("qTP:")) == 0)
{
cmd_qtp (packet);
return 1;
}
else if (strcmp ("qTfP", packet) == 0)
{
cmd_qtfp (packet);
@ -8049,8 +8204,12 @@ initialize_tracepoint_ftlib (void)
#endif /* IN_PROCESS_AGENT */
/* Return a timestamp, expressed as microseconds of the usual Unix
time. (As the result is a 64-bit number, it will not overflow any
time soon.) */
static LONGEST
tsv_get_timestamp (void)
get_timestamp (void)
{
struct timeval tv;
@ -8074,7 +8233,7 @@ initialize_tracepoint (void)
variable numbered 1, it will be renumbered.) */
create_trace_state_variable (1, 0);
set_trace_state_variable_name (1, "trace_timestamp");
set_trace_state_variable_getter (1, tsv_get_timestamp);
set_trace_state_variable_getter (1, get_timestamp);
#ifdef IN_PROCESS_AGENT
{

View File

@ -2490,7 +2490,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
void
mi_cmd_trace_start (char *command, char **argv, int argc)
{
start_tracing ();
start_tracing (NULL);
}
void
@ -2502,7 +2502,7 @@ mi_cmd_trace_status (char *command, char **argv, int argc)
void
mi_cmd_trace_stop (char *command, char **argv, int argc)
{
stop_tracing ();
stop_tracing (NULL);
trace_status_mi (1);
}

View File

@ -10214,6 +10214,53 @@ remote_get_trace_status (struct trace_status *ts)
return ts->running;
}
void
remote_get_tracepoint_status (struct breakpoint *bp,
struct uploaded_tp *utp)
{
struct remote_state *rs = get_remote_state ();
char addrbuf[40];
char *reply;
struct bp_location *loc;
struct tracepoint *tp = (struct tracepoint *) bp;
if (tp)
{
tp->base.hit_count = 0;
tp->traceframe_usage = 0;
for (loc = tp->base.loc; loc; loc = loc->next)
{
/* If the tracepoint was never downloaded, don't go asking for
any status. */
if (tp->number_on_target == 0)
continue;
sprintf_vma (addrbuf, loc->address);
sprintf (rs->buf, "qTP:%x:%s", tp->number_on_target, addrbuf);
putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
if (reply && *reply)
{
if (*reply == 'V')
parse_tracepoint_status (reply + 1, bp, utp);
}
}
}
else if (utp)
{
utp->hit_count = 0;
utp->traceframe_usage = 0;
sprintf_vma (addrbuf, (long unsigned int) utp->addr);
sprintf (rs->buf, "qTP:%x:%s", utp->number, addrbuf);
putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
if (reply && *reply)
{
if (*reply == 'V')
parse_tracepoint_status (reply + 1, bp, utp);
}
}
}
static void
remote_trace_stop (void)
{
@ -10485,6 +10532,51 @@ remote_get_min_fast_tracepoint_insn_len (void)
}
}
static int
remote_set_trace_notes (char *user, char *notes, char *stop_notes)
{
struct remote_state *rs = get_remote_state ();
char *reply;
char *buf = rs->buf;
char *endbuf = rs->buf + get_remote_packet_size ();
int nbytes;
buf += xsnprintf (buf, endbuf - buf, "QTNotes:");
if (user)
{
buf += xsnprintf (buf, endbuf - buf, "user:");
nbytes = bin2hex (user, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
if (notes)
{
buf += xsnprintf (buf, endbuf - buf, "notes:");
nbytes = bin2hex (notes, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
if (stop_notes)
{
buf += xsnprintf (buf, endbuf - buf, "tstop:");
nbytes = bin2hex (stop_notes, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
/* Ensure the buffer is terminated. */
*buf = '\0';
putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
if (*reply == '\0')
return 0;
if (strcmp (reply, "OK") != 0)
error (_("Bogus reply from target: %s"), reply);
return 1;
}
static void
init_remote_ops (void)
{
@ -10565,6 +10657,7 @@ Specify the serial device it is connected to\n\
remote_ops.to_trace_set_readonly_regions = remote_trace_set_readonly_regions;
remote_ops.to_trace_start = remote_trace_start;
remote_ops.to_get_trace_status = remote_get_trace_status;
remote_ops.to_get_tracepoint_status = remote_get_tracepoint_status;
remote_ops.to_trace_stop = remote_trace_stop;
remote_ops.to_trace_find = remote_trace_find;
remote_ops.to_get_trace_state_variable_value
@ -10577,6 +10670,7 @@ Specify the serial device it is connected to\n\
remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len;
remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
remote_ops.to_set_trace_notes = remote_set_trace_notes;
remote_ops.to_core_of_thread = remote_core_of_thread;
remote_ops.to_verify_memory = remote_verify_memory;
remote_ops.to_get_tib_address = remote_get_tib_address;

View File

@ -682,6 +682,7 @@ update_current_target (void)
INHERIT (to_trace_set_readonly_regions, t);
INHERIT (to_trace_start, t);
INHERIT (to_get_trace_status, t);
INHERIT (to_get_tracepoint_status, t);
INHERIT (to_trace_stop, t);
INHERIT (to_trace_find, t);
INHERIT (to_get_trace_state_variable_value, t);
@ -692,6 +693,7 @@ update_current_target (void)
INHERIT (to_get_min_fast_tracepoint_insn_len, t);
INHERIT (to_set_disconnected_tracing, t);
INHERIT (to_set_circular_trace_buffer, t);
INHERIT (to_set_trace_notes, t);
INHERIT (to_get_tib_address, t);
INHERIT (to_set_permissions, t);
INHERIT (to_static_tracepoint_marker_at, t);
@ -873,6 +875,9 @@ update_current_target (void)
de_fault (to_get_trace_status,
(int (*) (struct trace_status *))
return_minus_one);
de_fault (to_get_tracepoint_status,
(void (*) (struct breakpoint *, struct uploaded_tp *))
tcomplain);
de_fault (to_trace_stop,
(void (*) (void))
tcomplain);
@ -903,6 +908,9 @@ update_current_target (void)
de_fault (to_set_circular_trace_buffer,
(void (*) (int))
target_ignore);
de_fault (to_set_trace_notes,
(int (*) (char *, char *, char *))
return_zero);
de_fault (to_get_tib_address,
(int (*) (ptid_t, CORE_ADDR *))
tcomplain);

View File

@ -713,6 +713,9 @@ struct target_ops
/* Get the current status of a tracing run. */
int (*to_get_trace_status) (struct trace_status *ts);
void (*to_get_tracepoint_status) (struct breakpoint *tp,
struct uploaded_tp *utp);
/* Stop a trace run. */
void (*to_trace_stop) (void);
@ -749,6 +752,10 @@ struct target_ops
void (*to_set_disconnected_tracing) (int val);
void (*to_set_circular_trace_buffer) (int val);
/* Add/change textual notes about the trace run, returning 1 if
successful, 0 otherwise. */
int (*to_set_trace_notes) (char *user, char *notes, char* stopnotes);
/* Return the processor core that thread PTID was last seen on.
This information is updated only when:
- update_thread_list is called
@ -1508,6 +1515,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
#define target_get_trace_status(ts) \
(*current_target.to_get_trace_status) (ts)
#define target_get_tracepoint_status(tp,utp) \
(*current_target.to_get_tracepoint_status) (tp, utp)
#define target_trace_stop() \
(*current_target.to_trace_stop) ()
@ -1538,6 +1548,9 @@ extern int target_search_memory (CORE_ADDR start_addr,
#define target_set_circular_trace_buffer(val) \
(*current_target.to_set_circular_trace_buffer) (val)
#define target_set_trace_notes(user,notes,stopnotes) \
(*current_target.to_set_trace_notes) ((user), (notes), (stopnotes))
#define target_get_tib_address(ptid, addr) \
(*current_target.to_get_tib_address) ((ptid), (addr))

View File

@ -1,3 +1,8 @@
2011-11-20 Stan Shebs <stan@codesourcery.com>
* gdb.trace/tstatus.exp: New.
* gdb.trace/actions.c: Include string.h.
2011-11-18 Yao Qi <yao@codesourcery.com>
* gdb.trace/pending.exp: New.

View File

@ -2,6 +2,8 @@
* Test program for trace action commands
*/
#include <string.h>
static char gdb_char_test;
static short gdb_short_test;
static long gdb_long_test;

View File

@ -0,0 +1,172 @@
# Copyright 2011 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
load_lib "trace-support.exp"
set testfile "actions"
set executable $testfile
set srcfile $testfile.c
set binfile $objdir/$subdir/$testfile
set expfile tstatus.exp
if [prepare_for_testing $expfile $executable $srcfile \
[list debug]] {
untested "failed to prepare for trace tests"
return -1
}
if ![runto_main] {
fail "Can't run to main to check for trace support"
return -1
}
if ![gdb_target_supports_trace] {
unsupported "target does not support trace"
return -1
}
set libipa $objdir/../gdbserver/libinproctrace.so
gdb_load_shlibs $libipa
# Can't use prepare_for_testing, because that splits compiling into
# building objects and then linking, and we'd fail with "linker input
# file unused because linking not done" when building the object.
if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
executable [list debug shlib=$libipa] ] != "" } {
untested "failed to compile ftrace tests"
return -1
}
clean_restart ${executable}
if ![runto_main] {
fail "Can't run to main for ftrace tests"
return 0
}
proc run_trace_experiment {} {
# gdb_test_no_output "set debug remote 1" ""
gdb_test "continue" \
".*Breakpoint \[0-9\]+, begin .*" \
"advance to trace begin"
gdb_test_no_output "tstart my tracing note" "start trace experiment"
gdb_test "continue" \
".*Breakpoint \[0-9\]+, end .*" \
"advance through tracing"
# Now play with tstatus a bit.
# Since note support is optional, we need to match both with and without
# cases.
gdb_test_multiple "tstatus" "check on trace status" {
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: my tracing note\.\[\r\n\]+Not looking at any trace frame\..*" {
pass "tstatus reports trace note"
}
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
pass "tstatus does not report any trace note"
}
}
gdb_test "set trace-notes different note" "" "change tracing note"
gdb_test_multiple "tstatus" "check on trace status with diff note" {
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
pass "tstatus reports different trace note"
}
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
pass "tstatus does not report any different trace note"
}
}
gdb_test "set trace-user me me me" "" "change tracing user"
gdb_test_multiple "tstatus" "check on trace status with diff note" {
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
pass "tstatus reports trace user"
}
-re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" {
pass "tstatus does not report trace user"
}
}
gdb_test_no_output "tstop because I can" "trace stopped with note"
gdb_test_multiple "tstatus" "check on trace status after stop" {
-re "Trace stopped by a tstop command (because I can)\..*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" {
pass "tstatus reports trace stop reason"
}
-re "Trace stopped by a tstop command\..*" {
pass "tstatus does not report trace stop reason"
}
}
# Tracepoint hit count is optional, so pass it either way.
gdb_test_multiple "info trace" "show tracepoint state" {
-re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+tracepoint already hit 1 time\[\r\n\]+\[\t ]+collect parm" {
pass "info trace reports tracepoint hit count"
}
-re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+collect parm" {
pass "info trace does not report tracepoint hit count"
}
}
}
proc test_tracepoints {} {
gdb_test "break begin" ".*" ""
gdb_test "break end" ".*" ""
gdb_test "trace gdb_c_test" "Tracepoint .*" \
"tracepoint at gdb_c_test"
gdb_trace_setactions "collect at set_point: define actions" \
"" \
"collect parm" "^$"
set fastgood 0
gdb_test_multiple "ftrace gdb_recursion_test" "set fast tracepoint" {
-re "May not have a fast tracepoint at .*" {
pass "4-byte fast tracepoint could not be set"
}
-re "Fast tracepoint .*" {
pass "4-byte fast tracepoint is set"
set fastgood 1
}
}
if { $fastgood } {
gdb_trace_setactions "collect at four_byter: define actions" \
"" \
"collect globvar, anarg" "^$"
}
run_trace_experiment
}
gdb_reinitialize_dir $srcdir/$subdir
if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0 } {
untested "Could not find IPA lib loaded"
return 1
}
test_tracepoints

View File

@ -224,6 +224,7 @@ proc gdbserver_start { options arguments } {
global gdbserver_reconnect_p
if {![info exists gdbserver_reconnect_p] || !$gdbserver_reconnect_p} {
# GDB client could accidentally connect to a stale server.
# append gdbserver_command " --debug --once"
append gdbserver_command " --once"
}

View File

@ -178,6 +178,18 @@ static int disconnected_tracing;
static int circular_trace_buffer;
/* Textual notes applying to the current and/or future trace runs. */
char *trace_user = NULL;
/* Textual notes applying to the current and/or future trace runs. */
char *trace_notes = NULL;
/* Textual notes applying to the stopping of a trace. */
char *trace_stop_notes = NULL;
/* ======= Important command functions: ======= */
static void trace_actions_command (char *, int);
static void trace_start_command (char *, int);
@ -199,8 +211,6 @@ static char *mem2hex (gdb_byte *, char *, int);
static void add_register (struct collection_list *collection,
unsigned int regno);
extern void send_disconnected_tracing_value (int value);
static void free_uploaded_tps (struct uploaded_tp **utpp);
static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
@ -1686,14 +1696,15 @@ process_tracepoint_on_disconnect (void)
void
start_tracing (void)
start_tracing (char *notes)
{
VEC(breakpoint_p) *tp_vec = NULL;
int ix;
struct breakpoint *b;
struct trace_state_variable *tsv;
int any_enabled = 0, num_to_download = 0;
int ret;
tp_vec = all_tracepoints ();
/* No point in tracing without any tracepoints... */
@ -1779,6 +1790,13 @@ start_tracing (void)
target_set_disconnected_tracing (disconnected_tracing);
target_set_circular_trace_buffer (circular_trace_buffer);
if (!notes)
notes = trace_notes;
ret = target_set_trace_notes (trace_user, notes, NULL);
if (!ret && (trace_user || notes))
warning ("Target does not support trace user/notes, info ignored");
/* Now insert traps and begin collecting data. */
target_trace_start ();
@ -1790,12 +1808,11 @@ start_tracing (void)
clear_traceframe_info ();
}
/* tstart command:
Tell target to clear any previous trace experiment.
Walk the list of tracepoints, and send them (and their actions)
to the target. If no errors,
Tell target to start a new trace experiment. */
/* The tstart command requests the target to start a new trace run.
The command passes any arguments it has to the target verbatim, as
an optional "trace note". This is useful as for instance a warning
to other users if the trace runs disconnected, and you don't want
anybody else messing with the target. */
static void
trace_start_command (char *args, int from_tty)
@ -1809,23 +1826,37 @@ trace_start_command (char *args, int from_tty)
error (_("New trace run not started."));
}
start_tracing ();
start_tracing (args);
}
/* tstop command */
/* The tstop command stops the tracing run. The command passes any
supplied arguments to the target verbatim as a "stop note"; if the
target supports trace notes, then it will be reported back as part
of the trace run's status. */
static void
trace_stop_command (char *args, int from_tty)
{
if (!current_trace_status ()->running)
error (_("Trace is not running."));
stop_tracing ();
stop_tracing (args);
}
void
stop_tracing (void)
stop_tracing (char *note)
{
int ret;
target_trace_stop ();
if (!note)
note = trace_stop_notes;
ret = target_set_trace_notes (NULL, NULL, note);
if (!ret && note)
warning ("Target does not support trace notes, note ignored");
/* Should change in response to reply? */
current_trace_status ()->running = 0;
}
@ -1835,7 +1866,9 @@ static void
trace_status_command (char *args, int from_tty)
{
struct trace_status *ts = current_trace_status ();
int status;
int status, ix;
VEC(breakpoint_p) *tp_vec = NULL;
struct breakpoint *t;
status = target_get_trace_status (ts);
@ -1866,7 +1899,11 @@ trace_status_command (char *args, int from_tty)
printf_filtered (_("No trace has been run on the target.\n"));
break;
case tstop_command:
printf_filtered (_("Trace stopped by a tstop command.\n"));
if (ts->stop_desc)
printf_filtered (_("Trace stopped by a tstop command (%s).\n"),
ts->stop_desc);
else
printf_filtered (_("Trace stopped by a tstop command.\n"));
break;
case trace_buffer_full:
printf_filtered (_("Trace stopped because the buffer was full.\n"));
@ -1882,10 +1919,10 @@ trace_status_command (char *args, int from_tty)
if (ts->stopping_tracepoint)
printf_filtered (_("Trace stopped by an "
"error (%s, tracepoint %d).\n"),
ts->error_desc, ts->stopping_tracepoint);
ts->stop_desc, ts->stopping_tracepoint);
else
printf_filtered (_("Trace stopped by an error (%s).\n"),
ts->error_desc);
ts->stop_desc);
break;
case trace_stop_reason_unknown:
printf_filtered (_("Trace stopped for an unknown reason.\n"));
@ -1936,12 +1973,46 @@ trace_status_command (char *args, int from_tty)
if (ts->circular_buffer)
printf_filtered (_("Trace buffer is circular.\n"));
if (ts->user_name && strlen (ts->user_name) > 0)
printf_filtered (_("Trace user is %s.\n"), ts->user_name);
if (ts->notes && strlen (ts->notes) > 0)
printf_filtered (_("Trace notes: %s.\n"), ts->notes);
/* Now report on what we're doing with tfind. */
if (traceframe_number >= 0)
printf_filtered (_("Looking at trace frame %d, tracepoint %d.\n"),
traceframe_number, tracepoint_number);
else
printf_filtered (_("Not looking at any trace frame.\n"));
/* Report start/stop times if supplied. */
if (ts->start_time)
{
if (ts->stop_time)
{
LONGEST run_time = ts->stop_time - ts->start_time;
/* Reporting a run time is more readable than two long numbers. */
printf_filtered (_("Trace started at %ld.%06ld secs, stopped %ld.%06ld secs later.\n"),
ts->start_time / 1000000, ts->start_time % 1000000,
run_time / 1000000, run_time % 1000000);
}
else
printf_filtered (_("Trace started at %ld.%06ld secs.\n"),
ts->start_time / 1000000, ts->start_time % 1000000);
}
else if (ts->stop_time)
printf_filtered (_("Trace stopped at %ld.%06ld secs.\n"),
ts->stop_time / 1000000, ts->stop_time % 1000000);
/* Now report any per-tracepoint status available. */
tp_vec = all_tracepoints ();
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
target_get_tracepoint_status (t, NULL);
VEC_free (breakpoint_p, tp_vec);
}
/* Report the trace status to uiout, in a way suitable for MI, and not
@ -2024,7 +2095,7 @@ trace_status_mi (int on_stop)
stopping_tracepoint);
if (ts->stop_reason == tracepoint_error)
ui_out_field_string (uiout, "error-description",
ts->error_desc);
ts->stop_desc);
}
}
}
@ -2040,6 +2111,20 @@ trace_status_mi (int on_stop)
ui_out_field_int (uiout, "disconnected", ts->disconnected_tracing);
ui_out_field_int (uiout, "circular", ts->circular_buffer);
ui_out_field_string (uiout, "user-name", ts->user_name);
ui_out_field_string (uiout, "notes", ts->notes);
{
char buf[100];
xsnprintf (buf, sizeof buf, "%ld.%06ld",
ts->start_time / 1000000, ts->start_time % 1000000);
ui_out_field_string (uiout, "start-time", buf);
xsnprintf (buf, sizeof buf, "%ld.%06ld",
ts->stop_time / 1000000, ts->stop_time % 1000000);
ui_out_field_string (uiout, "stop-time", buf);
}
}
/* This function handles the details of what to do about an ongoing
@ -2881,9 +2966,9 @@ trace_save (const char *filename, int target_does_save)
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error)
{
char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1);
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->error_desc, buf, 0);
bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
fprintf (fp, ":%s", buf);
}
fprintf (fp, ":%x", ts->stopping_tracepoint);
@ -2935,6 +3020,9 @@ trace_save (const char *filename, int target_does_save)
target_upload_tracepoints (&uploaded_tps);
for (utp = uploaded_tps; utp; utp = utp->next)
target_get_tracepoint_status (NULL, utp);
for (utp = uploaded_tps; utp; utp = utp->next)
{
fprintf (fp, "tp T%x:%s:%c:%x:%x",
@ -2971,6 +3059,11 @@ trace_save (const char *filename, int target_does_save)
buf, MAX_TRACE_UPLOAD);
fprintf (fp, "tp Z%s\n", buf);
}
fprintf (fp, "tp V%x:%s:%x:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
utp->hit_count,
phex_nz (utp->traceframe_usage,
sizeof (utp->traceframe_usage)));
}
free_uploaded_tps (&uploaded_tps);
@ -3041,17 +3134,11 @@ trace_save_command (char *args, int from_tty)
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
void
send_disconnected_tracing_value (int value)
{
target_set_disconnected_tracing (value);
}
static void
set_disconnected_tracing (char *args, int from_tty,
struct cmd_list_element *c)
{
send_disconnected_tracing_value (disconnected_tracing);
target_set_disconnected_tracing (disconnected_tracing);
}
static void
@ -3061,6 +3148,42 @@ set_circular_trace_buffer (char *args, int from_tty,
target_set_circular_trace_buffer (circular_trace_buffer);
}
static void
set_trace_user (char *args, int from_tty,
struct cmd_list_element *c)
{
int ret;
ret = target_set_trace_notes (trace_user, NULL, NULL);
if (!ret)
warning ("Target does not support trace notes, user ignored");
}
static void
set_trace_notes (char *args, int from_tty,
struct cmd_list_element *c)
{
int ret;
ret = target_set_trace_notes (NULL, trace_notes, NULL);
if (!ret)
warning ("Target does not support trace notes, note ignored");
}
static void
set_trace_stop_notes (char *args, int from_tty,
struct cmd_list_element *c)
{
int ret;
ret = target_set_trace_notes (NULL, NULL, trace_stop_notes);
if (!ret)
warning ("Target does not support trace notes, stop note ignored");
}
/* Convert the memory pointed to by mem into hex, placing result in buf.
* Return a pointer to the last char put in buf (null)
* "stolen" from sparc-stub.c
@ -3638,20 +3761,26 @@ tfile_interp_line (char *line,
void
parse_trace_status (char *line, struct trace_status *ts)
{
char *p = line, *p1, *p2, *p_temp;
char *p = line, *p1, *p2, *p3, *p_temp;
int end;
ULONGEST val;
ts->running_known = 1;
ts->running = (*p++ == '1');
ts->stop_reason = trace_stop_reason_unknown;
xfree (ts->error_desc);
ts->error_desc = NULL;
xfree (ts->stop_desc);
ts->stop_desc = NULL;
ts->traceframe_count = -1;
ts->traceframes_created = -1;
ts->buffer_free = -1;
ts->buffer_size = -1;
ts->disconnected_tracing = 0;
ts->circular_buffer = 0;
xfree (ts->user_name);
ts->user_name = NULL;
xfree (ts->notes);
ts->notes = NULL;
ts->start_time = ts->stop_time = 0;
while (*p++)
{
@ -3659,6 +3788,9 @@ parse_trace_status (char *line, struct trace_status *ts)
if (p1 == NULL)
error (_("Malformed trace status, at %s\n\
Status line: '%s'\n"), p, line);
p3 = strchr (p, ';');
if (p3 == NULL)
p3 = p + strlen (p);
if (strncmp (p, stop_reason_names[trace_buffer_full], p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
@ -3678,7 +3810,22 @@ Status line: '%s'\n"), p, line);
}
else if (strncmp (p, stop_reason_names[tstop_command], p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
p2 = strchr (++p1, ':');
if (!p2 || p2 > p3)
{
/*older style*/
p2 = p1;
}
else if (p2 != p1)
{
ts->stop_desc = xmalloc (strlen (line));
end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2);
ts->stop_desc[end] = '\0';
}
else
ts->stop_desc = xstrdup ("");
p = unpack_varlen_hex (++p2, &val);
ts->stop_reason = tstop_command;
}
else if (strncmp (p, stop_reason_names[trace_disconnected], p1 - p) == 0)
@ -3691,14 +3838,12 @@ Status line: '%s'\n"), p, line);
p2 = strchr (++p1, ':');
if (p2 != p1)
{
int end;
ts->error_desc = xmalloc ((p2 - p1) / 2 + 1);
end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2);
ts->error_desc[end] = '\0';
ts->stop_desc = xmalloc ((p2 - p1) / 2 + 1);
end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2);
ts->stop_desc[end] = '\0';
}
else
ts->error_desc = xstrdup ("");
ts->stop_desc = xstrdup ("");
p = unpack_varlen_hex (++p2, &val);
ts->stopping_tracepoint = val;
@ -3734,6 +3879,32 @@ Status line: '%s'\n"), p, line);
p = unpack_varlen_hex (++p1, &val);
ts->circular_buffer = val;
}
else if (strncmp (p, "starttime", p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
ts->start_time = val;
}
else if (strncmp (p, "stoptime", p1 - p) == 0)
{
p = unpack_varlen_hex (++p1, &val);
ts->stop_time = val;
}
else if (strncmp (p, "username", p1 - p) == 0)
{
++p1;
ts->user_name = xmalloc (strlen (p) / 2);
end = hex2bin (p1, ts->user_name, (p3 - p1) / 2);
ts->user_name[end] = '\0';
p = p3;
}
else if (strncmp (p, "notes", p1 - p) == 0)
{
++p1;
ts->notes = xmalloc (strlen (p) / 2);
end = hex2bin (p1, ts->notes, (p3 - p1) / 2);
ts->notes[end] = '\0';
p = p3;
}
else
{
/* Silently skip unknown optional info. */
@ -3747,6 +3918,26 @@ Status line: '%s'\n"), p, line);
}
}
void
parse_tracepoint_status (char *p, struct breakpoint *bp,
struct uploaded_tp *utp)
{
ULONGEST uval;
struct tracepoint *tp = (struct tracepoint *) bp;
p = unpack_varlen_hex (p, &uval);
if (tp)
tp->base.hit_count += uval;
else
utp->hit_count += uval;
p = unpack_varlen_hex (p + 1, &uval);
if (tp)
tp->traceframe_usage += uval;
else
utp->traceframe_usage += uval;
/* Ignore any extra, allowing for future extensions. */
}
/* Given a line of text defining a part of a tracepoint, parse it into
an "uploaded tracepoint". */
@ -3848,6 +4039,12 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp)
else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0)
VEC_safe_push (char_ptr, utp->cmd_strings, xstrdup (buf));
}
else if (piece == 'V')
{
utp = get_uploaded_tp (num, addr, utpp);
parse_tracepoint_status (p, NULL, utp);
}
else
{
/* Don't error out, the target might be sending us optional
@ -3923,6 +4120,13 @@ tfile_get_trace_status (struct trace_status *ts)
return -1;
}
static void
tfile_get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp)
{
/* Other bits of trace status were collected as part of opening the
trace files, so nothing to do here. */
}
/* Given the position of a traceframe in the file, figure out what
address the frame was collected at. This would normally be the
value of a collected PC register, but if not available, we
@ -4464,6 +4668,7 @@ init_tfile_ops (void)
tfile_ops.to_xfer_partial = tfile_xfer_partial;
tfile_ops.to_files_info = tfile_files_info;
tfile_ops.to_get_trace_status = tfile_get_trace_status;
tfile_ops.to_get_tracepoint_status = tfile_get_tracepoint_status;
tfile_ops.to_trace_find = tfile_trace_find;
tfile_ops.to_get_trace_state_variable_value
= tfile_get_trace_state_variable_value;
@ -5008,11 +5213,17 @@ De-select any trace frame and resume 'live' debugging."),
add_com ("tstatus", class_trace, trace_status_command,
_("Display the status of the current trace data collection."));
add_com ("tstop", class_trace, trace_stop_command,
_("Stop trace data collection."));
add_com ("tstop", class_trace, trace_stop_command, _("\
Stop trace data collection.\n\
Usage: tstop [ <notes> ... ]\n\
Any arguments supplied are recorded with the trace as a stop reason and\n\
reported by tstatus (if the target supports trace notes)."));
add_com ("tstart", class_trace, trace_start_command,
_("Start trace data collection."));
add_com ("tstart", class_trace, trace_start_command, _("\
Start trace data collection.\n\
Usage: tstart [ <notes> ... ]\n\
Any arguments supplied are recorded with the trace as a note and\n\
reported by tstatus (if the target supports trace notes)."));
add_com ("end", class_trace, end_actions_pseudocommand, _("\
Ends a list of commands or actions.\n\
@ -5087,6 +5298,27 @@ up and stopping the trace run."),
&setlist,
&showlist);
add_setshow_string_cmd ("trace-user", class_trace,
&trace_user, _("\
Set the user name to use for current and future trace runs"), _("\
Show the user name to use for current and future trace runs"), NULL,
set_trace_user, NULL,
&setlist, &showlist);
add_setshow_string_cmd ("trace-notes", class_trace,
&trace_notes, _("\
Set notes string to use for current and future trace runs"), _("\
Show the notes string to use for current and future trace runs"), NULL,
set_trace_notes, NULL,
&setlist, &showlist);
add_setshow_string_cmd ("trace-stop-notes", class_trace,
&trace_stop_notes, _("\
Set notes string to use for future tstop commands"), _("\
Show the notes string to use for future tstop commands"), NULL,
set_trace_stop_notes, NULL,
&setlist, &showlist);
init_tfile_ops ();
add_target (&tfile_ops);

View File

@ -79,6 +79,7 @@ struct trace_status
/* This is true if the value of the running field is known. */
int running_known;
/* This is true when the trace experiment is actually running. */
int running;
enum trace_stop_reason stop_reason;
@ -88,9 +89,11 @@ struct trace_status
stop. */
int stopping_tracepoint;
/* If stop_reason is tracepoint_error, this is a human-readable
string that describes the error that happened on the target. */
char *error_desc;
/* If stop_reason is tstop_command or tracepoint_error, this is an
arbitrary string that may describe the reason for the stop in
more detail. */
char *stop_desc;
/* Number of traceframes currently in the buffer. */
@ -117,6 +120,22 @@ struct trace_status
target does not report a value, assume 0. */
int circular_buffer;
/* The "name" of the person running the trace. This is an
arbitrary string. */
char *user_name;
/* "Notes" about the trace. This is an arbitrary string not
interpreted by GDBserver in any special way. */
char *notes;
/* The calendar times at which the trace run started and stopped,
both expressed in microseconds of Unix time. */
LONGEST start_time;
LONGEST stop_time;
};
struct trace_status *current_trace_status (void);
@ -154,6 +173,12 @@ struct uploaded_tp
/* List of original strings defining the tracepoint's actions. */
VEC(char_ptr) *cmd_strings;
/* The tracepoint's current hit count. */
int hit_count;
/* The tracepoint's current traceframe usage. */
ULONGEST traceframe_usage;
struct uploaded_tp *next;
};
@ -229,6 +254,9 @@ extern int encode_source_string (int num, ULONGEST addr,
extern void parse_trace_status (char *line, struct trace_status *ts);
extern void parse_tracepoint_status (char *p, struct breakpoint *tp,
struct uploaded_tp *utp);
extern void parse_tracepoint_definition (char *line,
struct uploaded_tp **utpp);
extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp);
@ -241,8 +269,8 @@ extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp);
extern void disconnect_tracing (int from_tty);
extern void start_tracing (void);
extern void stop_tracing (void);
extern void start_tracing (char *notes);
extern void stop_tracing (char *notes);
extern void trace_status_mi (int on_stop);