Add trace file support.

* tracepoint.h (enum trace_stop_reason): New enum.
	(struct trace_status): New struct.
	(parse_trace_status): Declare.
	(struct uploaded_tp): Move here from remote.c,
	add fields for actions.
	(struct uploaded_tsv): New struct.
	* tracepoint.c (tfile_ops): New target vector.
	(trace_fd): New global.
	(tfile_open): New function.
	(tfile_close): New function.
	(tfile_files_info): New function.
	(tfile_get_trace_status): New function.
	(tfile_get_traceframe_address): New function.
	(tfile_trace_find): New function.
	(tfile_fetch_registers): New function.
	(tfile_xfer_partial): New function.
	(tfile_get_trace_state_variable_value): New function.
	(init_tfile_ops): New function.
	(_initialize_tracepoint): Call it, add tfile target.
	(trace_status): New global.
	(current_trace_status): New function.
	(trace_running_p): Remove, change all users to get from
	current_trace_status()->running.
	(get_trace_status): Remove.
	(trace_status_command): Call target_get_trace_status directly,
	report more detail including tracing stop reasons.
	(trace_find_command): Always allow tfind on a file.
	(trace_find_pc_command): Ditto.
	(trace_find_tracepoint_command): Ditto.
	(trace_find_line_command): Ditto.
	(trace_find_range_command): Ditto.
	(trace_find_outside_command): Ditto.
	(trace_frames_offset, cur_offset): Declare as off_t.
	(trace_regblock_size): Rename from reg_size, update users.
	(parse_trace_status): New function.
	(tfile_interp_line): New function.
	(disconnect_or_stop_tracing): Ensure current trace
	status before asking what to do.
	(stop_reason_names): New global.
	(trace_save_command): New command.
	(get_uploaded_tp): Move here from remote.c.
	(find_matching_tracepoint): Ditto.
	(merge_uploaded_tracepoints): New function.
	(parse_trace_status): Use stop_reason_names.
	(_initialize_tracepoint): Define tsave command.
	* target.h (target_ops): New fields to_save_trace_data,
	to_upload_tracepoints, to_upload_trace_state_variables,
	to_get_raw_trace_data, change to_get_trace_status
	to take a pointer to a status struct.
	(target_save_trace_data): New macro.
	(target_upload_tracepoints): New macro.
	(target_upload_trace_state_variables): New macro.
	(target_get_raw_trace_data): New macro.
	* target.c (update_current_target): Add new methods, change
	signature of to_get_trace_status.
	* remote.c (hex2bin): Make globally visible.
	(bin2hex): Ditto.
	(remote_download_trace_state_variable): Download name also.
	(remote_get_trace_status): Update parameter, use
	parse_trace_status.
	(remote_save_trace_data): New function.
	(remote_upload_tracepoints): New function.
	(remote_upload_trace_state_variables): New function.
	(remote_get_raw_trace_data): New function.
	(remote_start_remote): Use them.
	(_initialize_remote_ops): Add operations.
	* ax-gdb.c: Include breakpoint.h.
	* breakpoint.c (create_tracepoint_from_upload): Use
	break_command_really, return tracepoint, warn about unimplemented
	parts.
	* NEWS: Mention trace file addition.

	* gdb.texinfo (Trace Files): New section.
	(Tracepoint Packets): Document QTSave and qTBuffer.
	(Trace File Format): New appendix.

	* generic/gdbtk-bp.c (gdb_trace_status): Use current_trace_status.

	* gdb.trace/tfile.c: New file.
	* gdb.trace/tfile.exp: New file.
This commit is contained in:
Stan Shebs 2010-01-15 22:37:20 +00:00
parent 6ec12636a7
commit 00bf0b8586
14 changed files with 1969 additions and 235 deletions

View file

@ -1,3 +1,78 @@
2010-01-15 Stan Shebs <stan@codesourcery.com>
Add trace file support.
* tracepoint.h (enum trace_stop_reason): New enum.
(struct trace_status): New struct.
(parse_trace_status): Declare.
(struct uploaded_tp): Move here from remote.c,
add fields for actions.
(struct uploaded_tsv): New struct.
* tracepoint.c (tfile_ops): New target vector.
(trace_fd): New global.
(tfile_open): New function.
(tfile_close): New function.
(tfile_files_info): New function.
(tfile_get_trace_status): New function.
(tfile_get_traceframe_address): New function.
(tfile_trace_find): New function.
(tfile_fetch_registers): New function.
(tfile_xfer_partial): New function.
(tfile_get_trace_state_variable_value): New function.
(init_tfile_ops): New function.
(_initialize_tracepoint): Call it, add tfile target.
(trace_status): New global.
(current_trace_status): New function.
(trace_running_p): Remove, change all users to get from
current_trace_status()->running.
(get_trace_status): Remove.
(trace_status_command): Call target_get_trace_status directly,
report more detail including tracing stop reasons.
(trace_find_command): Always allow tfind on a file.
(trace_find_pc_command): Ditto.
(trace_find_tracepoint_command): Ditto.
(trace_find_line_command): Ditto.
(trace_find_range_command): Ditto.
(trace_find_outside_command): Ditto.
(trace_frames_offset, cur_offset): Declare as off_t.
(trace_regblock_size): Rename from reg_size, update users.
(parse_trace_status): New function.
(tfile_interp_line): New function.
(disconnect_or_stop_tracing): Ensure current trace
status before asking what to do.
(stop_reason_names): New global.
(trace_save_command): New command.
(get_uploaded_tp): Move here from remote.c.
(find_matching_tracepoint): Ditto.
(merge_uploaded_tracepoints): New function.
(parse_trace_status): Use stop_reason_names.
(_initialize_tracepoint): Define tsave command.
* target.h (target_ops): New fields to_save_trace_data,
to_upload_tracepoints, to_upload_trace_state_variables,
to_get_raw_trace_data, change to_get_trace_status
to take a pointer to a status struct.
(target_save_trace_data): New macro.
(target_upload_tracepoints): New macro.
(target_upload_trace_state_variables): New macro.
(target_get_raw_trace_data): New macro.
* target.c (update_current_target): Add new methods, change
signature of to_get_trace_status.
* remote.c (hex2bin): Make globally visible.
(bin2hex): Ditto.
(remote_download_trace_state_variable): Download name also.
(remote_get_trace_status): Update parameter, use
parse_trace_status.
(remote_save_trace_data): New function.
(remote_upload_tracepoints): New function.
(remote_upload_trace_state_variables): New function.
(remote_get_raw_trace_data): New function.
(remote_start_remote): Use them.
(_initialize_remote_ops): Add operations.
* ax-gdb.c: Include breakpoint.h.
* breakpoint.c (create_tracepoint_from_upload): Use
break_command_really, return tracepoint, warn about unimplemented
parts.
* NEWS: Mention trace file addition.
2010-01-15 Jan Kratochvil <jan.kratochvil@redhat.com>
Fix compilation warning on gcc-3.4.
@ -164,7 +239,6 @@
(SUBDIR_PYTHON_SRCS): Likewise.
(py-lazy-string.o): New rule.
2010-01-13 Doug Evans <dje@google.com>
* mi/mi-main.c (list_available_thread_groups): Avoid "may be used

View file

@ -61,6 +61,16 @@ Renesas RX rx
tell the target agent whether to continue running a trace if the
connection is lost unexpectedly.
** Trace files
GDB now has the ability to save the trace buffer into a file, and
then use that file as a target, similarly to you can do with
corefiles. You can select trace frames, print data that was
collected in them, and use tstatus to display the state of the
tracing run at the moment that it was saved. To create a trace
file, use "tsave <filename>", and to use it, do "target tfile
<name>".
* Changed commands
disassemble

View file

@ -37,6 +37,7 @@
#include "user-regs.h"
#include "language.h"
#include "dictionary.h"
#include "breakpoint.h"
#include "tracepoint.h"
/* To make sense of this file, you should read doc/agentexpr.texi.

View file

@ -9847,27 +9847,61 @@ ftrace_command (char *arg, int from_tty)
set_tracepoint_count (breakpoint_count);
}
extern void create_tracepoint_from_upload (int num, enum bptype type,
ULONGEST addr);
void
create_tracepoint_from_upload (int num, enum bptype type, ULONGEST addr)
/* Given information about a tracepoint as recorded on a target (which
can be either a live system or a trace file), attempt to create an
equivalent GDB tracepoint. This is not a reliable process, since
the target does not necessarily have all the information used when
the tracepoint was originally defined. */
struct breakpoint *
create_tracepoint_from_upload (struct uploaded_tp *utp)
{
char buf[100];
struct breakpoint *tp;
/* In the absence of a source location, fall back to raw address. */
sprintf (buf, "*%s", paddress (get_current_arch(), utp->addr));
sprintf (buf, "*0x%s", paddress (get_current_arch (), addr));
if (type == bp_fast_tracepoint)
ftrace_command (buf, 0);
else
trace_command (buf, 0);
break_command_really (get_current_arch (),
buf,
NULL, 0, 1 /* parse arg */,
0 /* tempflag */,
(utp->type == bp_fast_tracepoint) /* hardwareflag */,
1 /* traceflag */,
0 /* Ignore count */,
pending_break_support,
NULL,
0 /* from_tty */,
utp->enabled /* enabled */);
set_tracepoint_count (breakpoint_count);
tp = get_tracepoint (tracepoint_count);
/* Record that this tracepoint is numbered differently on host and
target. */
tp = get_tracepoint (tracepoint_count);
tp->number_on_target = num;
}
if (utp->pass > 0)
{
sprintf (buf, "%d %d", utp->pass, tp->number);
trace_pass_command (buf, 0);
}
if (utp->cond)
{
printf_filtered ("Want to restore a condition\n");
}
if (utp->numactions > 0)
{
printf_filtered ("Want to restore action list\n");
}
if (utp->num_step_actions > 0)
{
printf_filtered ("Want to restore action list\n");
}
return tp;
}
/* Print information on tracepoint number TPNUM_EXP, or all if
omitted. */

View file

@ -1,3 +1,9 @@
2010-01-15 Stan Shebs <stan@codesourcery.com>
* gdb.texinfo (Trace Files): New section.
(Tracepoint Packets): Document QTSave and qTBuffer.
(Trace File Format): New appendix.
2010-01-13 Phil Muldoon <pmuldoon@redhat.com>
* gdb.texinfo (Values From Inferior): Document lazy_string value

View file

@ -174,6 +174,7 @@ software in general. We will miss him.
@value{GDBN}
* Operating System Information:: Getting additional information from
the operating system
* Trace File Format:: GDB trace file format
* Copying:: GNU General Public License says
how you can copy and share GDB
* GNU Free Documentation License:: The license for this documentation
@ -9292,12 +9293,17 @@ support tracepoints as of this writing. The format of the remote
packets used to implement tracepoints are described in @ref{Tracepoint
Packets}.
It is also possible to get trace data from a file, in a manner reminiscent
of corefiles; you specify the filename, and use @code{tfind} to search
through the file. @xref{Trace Files}, for more details.
This chapter describes the tracepoint commands and features.
@menu
* Set Tracepoints::
* Analyze Collected Data::
* Tracepoint Variables::
* Trace Files::
@end menu
@node Set Tracepoints
@ -10081,6 +10087,41 @@ which are managed by the target.
> end
@end smallexample
@node Trace Files
@section Using Trace Files
@cindex trace files
In some situations, the target running a trace experiment may no
longer be available; perhaps it crashed, or the hardware was needed
for a different activity. To handle these cases, you can arrange to
dump the trace data into a file, and later use that file as a source
of trace data, via the @code{target tfile} command.
@table @code
@kindex tsave
@item tsave [ -r ] @var{filename}
Save the trace data to @var{filename}. By default, this command
assumes that @var{filename} refers to the host filesystem, so if
necessary @value{GDBN} will copy raw trace data up from the target and
then save it. If the target supports it, you can also supply the
optional argument @code{-r} (``remote'') to direct the target to save
the data directly into @var{filename} in its own filesystem, which may be
more efficient if the trace buffer is very large. (Note, however, that
@code{target tfile} can only read from files accessible to the host.)
@kindex target tfile
@kindex tfile
@item target tfile @var{filename}
Use the file named @var{filename} as a source of trace data. Commands
that examine data work as they do with a live target, but it is not
possible to run any new trace experiments. @code{tstatus} will report
the state of the trace run at the moment the data was saved, as well
as the current trace frame you are examining. @var{filename} must be
on a filesystem accessible to the host.
@end table
@node Overlays
@chapter Debugging Programs That Use Overlays
@cindex overlays
@ -29964,10 +30005,12 @@ encoded). @value{GDBN} will continue to supply the values of symbols
(if available), until the target ceases to request them.
@end table
@item qTBuffer
@item QTDisconnected
@itemx QTDP
@itemx QTDV
@itemx QTfP
@itemx qTfP
@itemx qTfV
@itemx QTFrame
@xref{Tracepoint Packets}.
@ -29996,7 +30039,9 @@ 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 QTsP
@item QTSave
@item qTsP
@item qTsV
@itemx QTStart
@itemx QTStop
@itemx QTinit
@ -30455,6 +30500,29 @@ of data, and multiple @code{qTsP} to get additional pieces. Replies
to these packets generally take the form of the @code{QTDP} packets
that define tracepoints. (FIXME add detailed syntax)
@item qTfV
@itemx qTsV
These packets request data about trace state variables that are on the
target. @value{GDBN} sends @code{qTfV} to get the first vari of data,
and multiple @code{qTsV} to get additional variables. Replies to
these packets follow the syntax of the @code{QTDV} packets that define
trace state variables.
@item QTSave:@var{filename}
This packet directs the target to save trace data to the file name
@var{filename} in the target's filesystem. @var{filename} is encoded
as a hex string; the interpretation of the file name (relative vs
absolute, wild cards, etc) is up to the target.
@item qTBuffer:@var{offset},@var{len}
Return up to @var{len} bytes of the current contents of trace buffer,
starting at @var{offset}. The trace buffer is treated as if it were
a contiguous collection of traceframes, as per the trace file format.
The reply consists as many hex-encoded bytes as the target can deliver
in a packet; it is not an error to return fewer than were asked for.
A reply consisting of just @code{l} indicates that no bytes are
available.
@end table
@node Host I/O Packets
@ -32146,6 +32214,59 @@ element is interpreted as human-readable auxilliary information.
@include agentexpr.texi
@node Trace File Format
@appendix Trace File Format
@cindex trace file format
The trace file comes in three parts: a header, a textual description
section, and a trace frame section with binary data.
The header has the form @code{\x7fTRACE0\n}. The first byte is
@code{0x7f} so as to indicate that the file contains binary data,
while the @code{0} is a version number that may have different values
in the future.
The description section consists of multiple lines of @sc{ascii} text
separated by newline characters (@code{0xa}). The lines may include a
variety of optional descriptive or context-setting information, such
as tracepoint definitions or register set size. @value{GDBN} will
ignore any line that it does not recognize. An empty line marks the end
of this section.
@c FIXME add some specific types of data
The trace frame section consists of a number of consecutive frames.
Each frame begins with a two-byte tracepoint number, followed by a
four-byte size giving the amount of data in the frame. The data in
the frame consists of a number of blocks, each introduced by a
character indicating its type (at least register, memory, and trace
state variable). The data in this section is raw binary, not a
hexadecimal or other encoding; its endianness matches the target's
endianness.
@c FIXME bi-arch may require endianness/arch info in description section
@table @code
@item R @var{bytes}
Register block. The number and ordering of bytes matches that of a
@code{g} packet in the remote protocol. Note that these are the
actual bytes, in target order and @value{GDBN} register order, not a
hexadecimal encoding.
@item M @var{address} @var{length} @var{bytes}...
Memory block. This is a contiguous block of memory, at the 8-byte
address @var{address}, with a 2-byte length @var{length}, followed by
@var{length} bytes.
@item V @var{number} @var{value}
Trace state variable block. This records the 8-byte signed value
@var{value} of trace state variable numbered @var{number}.
@end table
Future enhancements of the trace file format may include additional types
of blocks.
@node Target Descriptions
@appendix Target Descriptions
@cindex target descriptions

View file

@ -189,9 +189,9 @@ static void record_currthread (ptid_t currthread);
static int fromhex (int a);
static int hex2bin (const char *hex, gdb_byte *bin, int count);
extern int hex2bin (const char *hex, gdb_byte *bin, int count);
static int bin2hex (const gdb_byte *bin, char *hex, int count);
extern int bin2hex (const gdb_byte *bin, char *hex, int count);
static int putpkt_binary (char *buf, int cnt);
@ -215,8 +215,12 @@ static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
static ptid_t read_ptid (char *buf, char **obuf);
struct remote_state;
static void remote_get_tracing_state (struct remote_state *);
static int remote_get_trace_status (struct trace_status *ts);
static int remote_upload_tracepoints (struct uploaded_tp **utpp);
static int remote_upload_trace_state_variables (struct uploaded_tsv **utsvp);
static void remote_query_supported (void);
static void remote_check_symbols (struct objfile *objfile);
@ -3158,7 +3162,23 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
previously; find out where things are at. */
if (rs->disconnected_tracing)
{
remote_get_tracing_state (rs);
struct uploaded_tp *uploaded_tps = NULL;
struct uploaded_tsv *uploaded_tsvs = NULL;
remote_get_trace_status (current_trace_status ());
if (current_trace_status ()->running)
printf_filtered (_("Trace is already running on the target.\n"));
/* Get trace state variables first, they may be checked when
parsing uploaded commands. */
remote_upload_trace_state_variables (&uploaded_tsvs);
merge_uploaded_trace_state_variables (&uploaded_tsvs);
remote_upload_tracepoints (&uploaded_tps);
merge_uploaded_tracepoints (&uploaded_tps);
}
/* If breakpoints are global, insert them now. */
@ -3948,7 +3968,7 @@ fromhex (int a)
error (_("Reply contains invalid hex digit %d"), a);
}
static int
int
hex2bin (const char *hex, gdb_byte *bin, int count)
{
int i;
@ -3978,7 +3998,7 @@ tohex (int nib)
return 'a' + nib - 10;
}
static int
int
bin2hex (const gdb_byte *bin, char *hex, int count)
{
int i;
@ -8034,7 +8054,7 @@ remote_rcmd (char *command,
{
char *buf;
/* XXX - see also tracepoint.c:remote_get_noisy_reply(). */
/* XXX - see also remote_get_noisy_reply(). */
rs->buf[0] = '\0';
getpkt (&rs->buf, &rs->buf_size, 0);
buf = rs->buf;
@ -9342,9 +9362,15 @@ static void
remote_download_trace_state_variable (struct trace_state_variable *tsv)
{
struct remote_state *rs = get_remote_state ();
char *p;
sprintf (rs->buf, "QTDV:%x:%s",
tsv->number, phex ((ULONGEST) tsv->initial_value, 8));
sprintf (rs->buf, "QTDV:%x:%s:%x:",
tsv->number, phex ((ULONGEST) tsv->initial_value, 8), tsv->builtin);
p = rs->buf + strlen (rs->buf);
if ((p - rs->buf) + strlen (tsv->name) * 2 >= get_remote_packet_size ())
error (_("Trace state variable name too long for tsv definition packet"));
p += 2 * bin2hex ((gdb_byte *) (tsv->name), p, 0);
*p++ = '\0';
putpkt (rs->buf);
remote_get_noisy_reply (&target_buf, &target_buf_size);
}
@ -9395,16 +9421,39 @@ remote_trace_start ()
}
static int
remote_get_trace_status (int *stop_reason)
remote_get_trace_status (struct trace_status *ts)
{
putpkt ("qTStatus");
remote_get_noisy_reply (&target_buf, &target_buf_size);
char *p, *p1, *p_temp;
ULONGEST val;
/* FIXME we need to get register block size some other way */
extern int trace_regblock_size;
trace_regblock_size = get_remote_arch_state ()->sizeof_g_packet;
if (target_buf[0] != 'T' ||
(target_buf[1] != '0' && target_buf[1] != '1'))
putpkt ("qTStatus");
getpkt (&target_buf, &target_buf_size, 0);
/* FIXME should handle more variety of replies */
p = target_buf;
/* If the remote target doesn't do tracing, flag it. */
if (*p == '\0')
return -1;
/* We're working with a live target. */
ts->from_file = 0;
/* Set some defaults. */
ts->running_known = 0;
ts->stop_reason = trace_stop_reason_unknown;
ts->traceframe_count = -1;
ts->buffer_free = 0;
if (*p++ != 'T')
error (_("Bogus trace status reply from target: %s"), target_buf);
return (target_buf[1] == '1');
parse_trace_status (p, ts);
return ts->running;
}
static void
@ -9434,16 +9483,16 @@ remote_trace_find (enum trace_find_type type, int num,
sprintf (p, "%x", num);
break;
case tfind_pc:
sprintf (p, "pc:%s", paddress (target_gdbarch, addr1));
sprintf (p, "pc:%s", phex_nz (addr1, 0));
break;
case tfind_tp:
sprintf (p, "tdp:%x", num);
break;
case tfind_range:
sprintf (p, "range:%s:%s", paddress (target_gdbarch, addr1), paddress (target_gdbarch, addr2));
sprintf (p, "range:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0));
break;
case tfind_outside:
sprintf (p, "outside:%s:%s", paddress (target_gdbarch, addr1), paddress (target_gdbarch, addr2));
sprintf (p, "outside:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0));
break;
default:
error ("Unknown trace find type %d", type);
@ -9499,6 +9548,67 @@ remote_get_trace_state_variable_value (int tsvnum, LONGEST *val)
return 0;
}
static int
remote_save_trace_data (char *filename)
{
struct remote_state *rs = get_remote_state ();
char *p, *reply;
p = rs->buf;
strcpy (p, "QTSave:");
p += strlen (p);
if ((p - rs->buf) + strlen (filename) * 2 >= get_remote_packet_size ())
error (_("Remote file name too long for trace save packet"));
p += 2 * bin2hex ((gdb_byte *) filename, p, 0);
*p++ = '\0';
putpkt (rs->buf);
remote_get_noisy_reply (&target_buf, &target_buf_size);
return 0;
}
/* This is basically a memory transfer, but needs to be its own packet
because we don't know how the target actually organizes its trace
memory, plus we want to be able to ask for as much as possible, but
not be unhappy if we don't get as much as we ask for. */
static LONGEST
remote_get_raw_trace_data (gdb_byte *buf, ULONGEST offset, LONGEST len)
{
struct remote_state *rs = get_remote_state ();
char *reply;
char *p;
int rslt;
p = rs->buf;
strcpy (p, "qTBuffer:");
p += strlen (p);
p += hexnumstr (p, offset);
*p++ = ',';
p += hexnumstr (p, len);
*p++ = '\0';
putpkt (rs->buf);
reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
if (reply && *reply)
{
/* 'l' by itself means we're at the end of the buffer and
there is nothing more to get. */
if (*reply == 'l')
return 0;
/* Convert the reply into binary. Limit the number of bytes to
convert according to our passed-in buffer size, rather than
what was returned in the packet; if the target is
unexpectedly generous and gives us a bigger reply than we
asked for, we don't want to crash. */
rslt = hex2bin (target_buf, buf, len);
return rslt;
}
/* Something went wrong, flag as an error. */
return -1;
}
static void
remote_set_disconnected_tracing (int val)
{
@ -9592,6 +9702,10 @@ Specify the serial device it is connected to\n\
remote_ops.to_trace_stop = remote_trace_stop;
remote_ops.to_trace_find = remote_trace_find;
remote_ops.to_get_trace_state_variable_value = remote_get_trace_state_variable_value;
remote_ops.to_save_trace_data = remote_save_trace_data;
remote_ops.to_upload_tracepoints = remote_upload_tracepoints;
remote_ops.to_upload_trace_state_variables = remote_upload_trace_state_variables;
remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data;
remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
remote_ops.to_core_of_thread = remote_core_of_thread;
}
@ -9744,181 +9858,51 @@ remote_new_objfile (struct objfile *objfile)
remote_check_symbols (objfile);
}
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp {
int number;
enum bptype type;
ULONGEST addr;
int enabled;
int step;
int pass;
int orig_size;
char *cond;
int cond_len;
struct uploaded_tp *next;
};
struct uploaded_tp *uploaded_tps;
struct uploaded_tp *
get_uploaded_tp (int num)
{
struct uploaded_tp *utp;
for (utp = uploaded_tps; utp; utp = utp->next)
if (utp->number == num)
return utp;
utp = (struct uploaded_tp *) xmalloc (sizeof (struct uploaded_tp));
utp->number = num;
utp->next = uploaded_tps;
uploaded_tps = utp;
return utp;
}
/* Look for an existing tracepoint that seems similar enough to the
uploaded one. Enablement isn't checked, because the user can
toggle that freely, and may have done so in anticipation of the
next trace run. */
struct breakpoint *
find_matching_tracepoint (struct uploaded_tp *utp)
{
VEC(breakpoint_p) *tp_vec = all_tracepoints ();
int ix;
struct breakpoint *t;
for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++)
{
if (t->type == utp->type
&& (t->loc && t->loc->address == utp->addr)
&& t->step_count == utp->step
&& t->pass_count == utp->pass
/* FIXME also test conditionals and actions */
)
return t;
}
return NULL;
}
/* Find out everything we can about the trace run that was already
happening on the target. This includes both running/stopped, and
the tracepoints that were in use. */
static void
remote_get_tracing_state (struct remote_state *rs)
/* Pull all the tracepoints defined on the target and create local
data structures representing them. We don't want to create real
tracepoints yet, we don't want to mess up the user's existing
collection. */
static int
remote_upload_tracepoints (struct uploaded_tp **utpp)
{
struct remote_state *rs = get_remote_state ();
char *p;
ULONGEST num, addr, step, pass, orig_size, xlen;
int enabled, i;
enum bptype type;
char *cond;
struct uploaded_tp *utp;
struct breakpoint *t;
extern void get_trace_status ();
get_trace_status ();
if (trace_running_p)
printf_filtered (_("Trace is running on the target.\n"));
/* Ask for a first packet of tracepoint definition. */
putpkt ("qTfP");
getpkt (&rs->buf, &rs->buf_size, 0);
p = rs->buf;
while (*p != '\0')
while (*p && *p != 'l')
{
if (*p == 'T')
{
p++;
p = unpack_varlen_hex (p, &num);
p++;
p = unpack_varlen_hex (p, &addr);
p++;
enabled = (*p++ == 'E');
p++;
p = unpack_varlen_hex (p, &step);
p++;
p = unpack_varlen_hex (p, &pass);
p++;
type = bp_tracepoint;
cond = NULL;
while (*p)
{
if (*p == 'F')
{
type = bp_fast_tracepoint;
p++;
p = unpack_varlen_hex (p, &orig_size);
}
else if (*p == 'X')
{
p++;
p = unpack_varlen_hex (p, &xlen);
p++; /* skip the comma */
cond = (char *) xmalloc (xlen);
hex2bin (p, cond, xlen);
p += 2 * xlen;
}
else
/* Silently skip over anything else. */
p++;
}
utp = get_uploaded_tp (num);
utp->type = type;
utp->addr = addr;
utp->enabled = enabled;
utp->step = step;
utp->pass = pass;
utp->cond = cond;
utp->cond_len = xlen;
}
else if (*p == 'A')
{
p++;
p = unpack_varlen_hex (p, &num);
p++;
p = unpack_varlen_hex (p, &addr);
p++;
utp = get_uploaded_tp (num);
/* FIXME save the action */
}
else if (*p == 'S')
{
p++;
p = unpack_varlen_hex (p, &num);
p++;
p = unpack_varlen_hex (p, &addr);
p++;
utp = get_uploaded_tp (num);
/* FIXME save the action */
}
else if (*p == 'l')
{
/* No more tracepoint info, get out of the loop. */
break;
}
parse_tracepoint_definition (p, utpp);
/* Ask for another packet of tracepoint definition. */
putpkt ("qTsP");
getpkt (&rs->buf, &rs->buf_size, 0);
p = rs->buf;
}
/* Got all the tracepoint info, now look for matches among what we
already have in GDB. */
for (utp = uploaded_tps; utp; utp = utp->next)
return 0;
}
static int
remote_upload_trace_state_variables (struct uploaded_tsv **utsvp)
{
struct remote_state *rs = get_remote_state ();
char *p;
/* Ask for a first packet of variable definition. */
putpkt ("qTfV");
getpkt (&rs->buf, &rs->buf_size, 0);
p = rs->buf;
while (*p && *p != 'l')
{
t = find_matching_tracepoint (utp);
if (t)
{
printf_filtered (_("Assuming tracepoint %d is same as target's tracepoint %d.\n"),
t->number, utp->number);
t->number_on_target = utp->number;
}
else
{
extern void create_tracepoint_from_upload (int num, ULONGEST addr);
create_tracepoint_from_upload (utp->number, utp->addr);
}
parse_tsv_definition (p, utsvp);
/* Ask for another packet of variable definition. */
putpkt ("qTsV");
getpkt (&rs->buf, &rs->buf_size, 0);
p = rs->buf;
}
/* FIXME free all the space */
uploaded_tps = NULL;
return 0;
}
void

View file

@ -694,6 +694,10 @@ update_current_target (void)
INHERIT (to_trace_stop, t);
INHERIT (to_trace_find, t);
INHERIT (to_get_trace_state_variable_value, t);
INHERIT (to_save_trace_data, t);
INHERIT (to_upload_tracepoints, t);
INHERIT (to_upload_trace_state_variables, t);
INHERIT (to_get_raw_trace_data, t);
INHERIT (to_set_disconnected_tracing, t);
INHERIT (to_magic, t);
/* Do not inherit to_memory_map. */
@ -859,7 +863,7 @@ update_current_target (void)
(void (*) (void))
tcomplain);
de_fault (to_get_trace_status,
(int (*) (int *))
(int (*) (struct trace_status *))
return_minus_one);
de_fault (to_trace_stop,
(void (*) (void))
@ -870,6 +874,18 @@ update_current_target (void)
de_fault (to_get_trace_state_variable_value,
(int (*) (int, LONGEST *))
return_zero);
de_fault (to_save_trace_data,
(int (*) (char *))
tcomplain);
de_fault (to_upload_tracepoints,
(int (*) (struct uploaded_tp **))
return_zero);
de_fault (to_upload_trace_state_variables,
(int (*) (struct uploaded_tsv **))
return_zero);
de_fault (to_get_raw_trace_data,
(LONGEST (*) (gdb_byte *, ULONGEST, LONGEST))
tcomplain);
de_fault (to_set_disconnected_tracing,
(void (*) (int))
tcomplain);

View file

@ -32,6 +32,9 @@ struct bp_target_info;
struct regcache;
struct target_section_table;
struct trace_state_variable;
struct trace_status;
struct uploaded_tsv;
struct uploaded_tp;
/* This include file defines the interface between the main part
of the debugger, and the part which is target-specific, or
@ -632,7 +635,7 @@ struct target_ops
void (*to_trace_start) (void);
/* Get the current status of a tracing run. */
int (*to_get_trace_status) (int *stop_reason);
int (*to_get_trace_status) (struct trace_status *ts);
/* Stop a trace run. */
void (*to_trace_stop) (void);
@ -649,6 +652,15 @@ struct target_ops
location pointed to by VAL, else returning 0. */
int (*to_get_trace_state_variable_value) (int tsv, LONGEST *val);
int (*to_save_trace_data) (char *filename);
int (*to_upload_tracepoints) (struct uploaded_tp **utpp);
int (*to_upload_trace_state_variables) (struct uploaded_tsv **utsvp);
LONGEST (*to_get_raw_trace_data) (gdb_byte *buf,
ULONGEST offset, LONGEST len);
/* Set the target's tracing behavior in response to unexpected
disconnection - set VAL to 1 to keep tracing, 0 to stop. */
void (*to_set_disconnected_tracing) (int val);
@ -1319,8 +1331,8 @@ extern int target_search_memory (CORE_ADDR start_addr,
#define target_trace_set_readonly_regions() \
(*current_target.to_trace_set_readonly_regions) ()
#define target_get_trace_status(stop_reason) \
(*current_target.to_get_trace_status) (stop_reason)
#define target_get_trace_status(ts) \
(*current_target.to_get_trace_status) (ts)
#define target_trace_stop() \
(*current_target.to_trace_stop) ()
@ -1331,6 +1343,18 @@ extern int target_search_memory (CORE_ADDR start_addr,
#define target_get_trace_state_variable_value(tsv,val) \
(*current_target.to_get_trace_state_variable_value) ((tsv), (val))
#define target_save_trace_data(filename) \
(*current_target.to_save_trace_data) (filename)
#define target_upload_tracepoints(utpp) \
(*current_target.to_upload_tracepoints) (utpp)
#define target_upload_trace_state_variables(utsvp) \
(*current_target.to_upload_trace_state_variables) (utsvp)
#define target_get_raw_trace_data(buf,offset,len) \
(*current_target.to_get_raw_trace_data) ((buf), (offset), (len))
#define target_set_disconnected_tracing(val) \
(*current_target.to_set_disconnected_tracing) (val)

View file

@ -1,3 +1,8 @@
2010-01-15 Stan Shebs <stan@codesourcery.com>
* gdb.trace/tfile.c: New file.
* gdb.trace/tfile.exp: New file.
2010-01-14 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.base/pie-support.exp, gdb.base/pie-support.c: Remove.

View file

@ -0,0 +1,116 @@
/* This program does two things; it generates valid trace files, and
it can also be traced so as to test trace file creation from
GDB. */
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
char spbuf[200];
char trbuf[1000];
char *trptr;
char *tfsizeptr;
int testglob = 31415;
int
start_trace_file (char *filename)
{
int fd;
fd = open (filename, O_WRONLY|O_CREAT|O_APPEND,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if (fd < 0)
return fd;
/* Write a file header, with a high-bit-set char to indicate a
binary file, plus a hint as what this file is, and a version
number in case of future needs. */
write (fd, "\x7fTRACE0\n", 8);
return fd;
}
void
finish_trace_file (int fd)
{
close (fd);
}
void
write_basic_trace_file ()
{
int fd;
fd = start_trace_file ("basic.tf");
/* The next part of the file consists of newline-separated lines
defining status, tracepoints, etc. The section is terminated by
an empty line. */
/* Dump the size of the R (register) blocks in traceframes. */
snprintf (spbuf, sizeof spbuf, "R %x\n", 500 /* FIXME get from arch */);
write (fd, spbuf, strlen (spbuf));
/* Dump trace status, in the general form of the qTstatus reply. */
snprintf (spbuf, sizeof spbuf, "status 0;tstop:0;tframes:1;tcreated:1;tfree:100;tsize:1000\n");
write (fd, spbuf, strlen (spbuf));
/* Dump tracepoint definitions, in syntax similar to that used
for reconnection uploads. */
snprintf (spbuf, sizeof spbuf, "tp T1:%lx:E:0:0\n",
(long) &write_basic_trace_file);
write (fd, spbuf, strlen (spbuf));
/* (Note that we would only need actions defined if we wanted to
test tdump.) */
/* Empty line marks the end of the definition section. */
write (fd, "\n", 1);
/* Make up a simulated trace buffer. */
/* (Encapsulate better if we're going to do lots of this.) */
trptr = trbuf;
*((short *) trptr) = 1;
trptr += sizeof (short);
tfsizeptr = trptr;
trptr += sizeof (int);
*((char *) trptr) = 'M';
trptr += 1;
*((long long *) trptr) = (long) &testglob;
trptr += sizeof (long long);
*((short *) trptr) = sizeof (testglob);
trptr += sizeof (short);
*((int *) trptr) = testglob;
trptr += sizeof (testglob);
/* Go back and patch in the frame size. */
*((int *) tfsizeptr) = trptr - tfsizeptr - sizeof (int);
/* Write end of tracebuffer marker. */
*((short *) trptr) = 0;
trptr += sizeof (short);
*((int *) trptr) = 0;
trptr += sizeof (int);
write (fd, trbuf, trptr - trbuf);
finish_trace_file (fd);
}
void
done_making_trace_files (void)
{
}
int
main (int argc, char **argv, char **envp)
{
write_basic_trace_file ();
done_making_trace_files ();
return 0;
}

View file

@ -0,0 +1,89 @@
# Copyright 2010 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/>.
# Test of trace file support.
# Note that unlike most of the tracing tests, this can be run on
# targets lacking tracepoint support; the program tfile.c has the
# ability to generate synthetic trace files directly, and the tfile
# target is available to all GDB configs.
load_lib "trace-support.exp";
if [target_info exists gdb,nofileio] {
verbose "Skipping tfile.exp because of no fileio capabilities."
continue
}
if $tracelevel then {
strace $tracelevel
}
set prms_id 0
set bug_id 0
gdb_exit
gdb_start
set testfile "tfile"
set srcfile ${testfile}.c
set binfile $objdir/$subdir/$testfile
if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \
executable {debug nowarnings}] != "" } {
untested file.exp
return -1
}
gdb_reinitialize_dir $srcdir/$subdir
# Make sure we are starting fresh.
remote_exec build {sh -xc rm\ -f\ basic.tf}
gdb_load $binfile
runto_main
gdb_test "break done_making_trace_files" "" ""
gdb_test "continue" "" ""
# tsave command would be tested here...
gdb_test "continue" "" ""
# Program has presumably exited, now target a trace file it created.
gdb_test "target tfile basic.tf" "Created tracepoint.*" "target tfile"
gdb_test "info trace" ".*tracepoint.*in write_basic_trace_file.*" \
"info tracepoints on trace file"
gdb_test "tfind 0" "Found traceframe 0.*" "tfind 0 on trace file"
gdb_test "print testglob" " = 31415" "print testglob on trace file"
gdb_test "tfind" "Target failed to find requested trace frame." \
"tfind does not find a second frame in trace file"
gdb_test "tstatus" \
"Using a trace file.*
Trace stopped by a tstop command.*
Collected 1 trace frames.*
Trace buffer has 256 bytes free.*
Looking at trace frame 0, tracepoint .*" \
"tstatus on trace file"

File diff suppressed because it is too large Load diff

View file

@ -61,12 +61,79 @@ struct trace_state_variable
/* The value of a variable is a 64-bit signed integer. */
LONGEST value;
/* This is true for variables that are predefined and built into
the target. */
int builtin;
};
/* The trace status encompasses various info about the general state
of the tracing run. */
enum trace_stop_reason
{
trace_stop_reason_unknown,
trace_never_run,
tstop_command,
trace_buffer_full,
trace_disconnected,
tracepoint_passcount
};
extern unsigned long trace_running_p;
struct trace_status
{
/* This is true if the status is coming from a file rather
than a live target. */
int from_file;
/* This is true if the value of the running field is known. */
int running_known;
int running;
enum trace_stop_reason stop_reason;
int stopping_tracepoint;
int traceframe_count;
size_t buffer_size;
size_t buffer_free;
};
struct trace_status *current_trace_status (void);
extern char *default_collect;
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp {
int number;
enum bptype type;
ULONGEST addr;
int enabled;
int step;
int pass;
int orig_size;
char *cond;
int numactions;
char *actions[100];
int num_step_actions;
char *step_actions[100];
struct uploaded_tp *next;
};
/* Struct recording info about trace state variables on the target. */
struct uploaded_tsv {
const char *name;
int number;
LONGEST initial_value;
int builtin;
struct uploaded_tsv *next;
};
/* A hook used to notify the UI of tracepoint operations. */
extern void (*deprecated_trace_find_hook) (char *arg, int from_tty);
@ -81,4 +148,15 @@ extern void while_stepping_pseudocommand (char *args, int from_tty);
extern struct trace_state_variable *find_trace_state_variable (const char *name);
extern void parse_trace_status (char *line, struct trace_status *ts);
extern void parse_tracepoint_definition (char *line, struct uploaded_tp **utpp);
extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp);
extern struct uploaded_tp *get_uploaded_tp (int num, ULONGEST addr,
struct uploaded_tp **utpp);
extern struct breakpoint *create_tracepoint_from_upload (struct uploaded_tp *utp);
extern void merge_uploaded_tracepoints (struct uploaded_tp **utpp);
extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp);
#endif /* TRACEPOINT_H */