Move trace file writer out of tracepoint.c

This patch is a refactor which moves trace file writer related code
out of tracepoint.c, which has 6k LOC.  It moves general trace file
writer to a new file tracefile.c and moves tfile specific writer to
tracefile-tfile.c.

gdb:

2014-02-23  Yao Qi  <yao@codesourcery.com>

	* Makefile.in (REMOTE_OBS): Append tracefile.o and
	tracefile-tfile.o.
	(HFILES_NO_SRCDIR): Add tracefile.h.
	* ctf.c: Include "tracefile.h".
	* tracefile.h: New file.
	* tracefile.c: New file
	* tracefile-tfile.c: New file.
	* tracepoint.c: Include "tracefile.h".
	(free_uploaded_tps, free_uploaded_tsvs): Remove declarations.
	(stop_reason_names): Add const.
	(trace_file_writer_xfree): Move it to tracefile.c.
	(trace_save, trace_save_command, trace_save_tfile): Likewise.
	(trace_save_ctf): Likewise.
	(struct tfile_trace_file_writer): Move it to tracefile-tfile.c.
	(tfile_target_save, tfile_dtor, tfile_start): Likewise.
	(tfile_write_header, tfile_write_regblock_type): Likewise.
	(tfile_write_status, tfile_write_uploaded_tsv): Likewise.
	(tfile_write_uploaded_tp, tfile_write_definition_end): Likewise.
	(tfile_write_raw_data, tfile_end): Likewise.
	(tfile_trace_file_writer_new): Likewise.
	(free_uploaded_tp): Make it extern.
	(free_uploaded_tsv): Make it extern.
	(_initialize_tracepoint): Move code to register command 'tsave'
	to tracefile.c.
	* tracepoint.h (stop_reason_names): Declare.
	(struct trace_frame_write_ops): Move it to tracefile.h.
	(struct trace_file_write_ops): Likewise.
	(struct trace_file_writer): Likewise.
	(free_uploaded_tsvs, free_uploaded_tps): Declare.
This commit is contained in:
Yao Qi 2014-02-10 13:31:12 +08:00
parent cb5111bcea
commit 7951c4eb08
8 changed files with 874 additions and 777 deletions

View File

@ -1,3 +1,35 @@
2014-02-23 Yao Qi <yao@codesourcery.com>
* Makefile.in (REMOTE_OBS): Append tracefile.o and
tracefile-tfile.o.
(HFILES_NO_SRCDIR): Add tracefile.h.
* ctf.c: Include "tracefile.h".
* tracefile.h: New file.
* tracefile.c: New file
* tracefile-tfile.c: New file.
* tracepoint.c: Include "tracefile.h".
(free_uploaded_tps, free_uploaded_tsvs): Remove declarations.
(stop_reason_names): Add const.
(trace_file_writer_xfree): Move it to tracefile.c.
(trace_save, trace_save_command, trace_save_tfile): Likewise.
(trace_save_ctf): Likewise.
(struct tfile_trace_file_writer): Move it to tracefile-tfile.c.
(tfile_target_save, tfile_dtor, tfile_start): Likewise.
(tfile_write_header, tfile_write_regblock_type): Likewise.
(tfile_write_status, tfile_write_uploaded_tsv): Likewise.
(tfile_write_uploaded_tp, tfile_write_definition_end): Likewise.
(tfile_write_raw_data, tfile_end): Likewise.
(tfile_trace_file_writer_new): Likewise.
(free_uploaded_tp): Make it extern.
(free_uploaded_tsv): Make it extern.
(_initialize_tracepoint): Move code to register command 'tsave'
to tracefile.c.
* tracepoint.h (stop_reason_names): Declare.
(struct trace_frame_write_ops): Move it to tracefile.h.
(struct trace_file_write_ops): Likewise.
(struct trace_file_writer): Likewise.
(free_uploaded_tsvs, free_uploaded_tps): Declare.
2014-02-21 Jan Kratochvil <jan.kratochvil@redhat.com>
PR gdb/16594

View File

@ -584,7 +584,7 @@ SER_HARDWIRE = @SER_HARDWIRE@
# The `remote' debugging target is supported for most architectures,
# but not all (e.g. 960)
REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o \
remote-notif.o ctf.o
remote-notif.o ctf.o tracefile.o tracefile-tfile.o
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
@ -894,7 +894,7 @@ doublest.h regset.h hppa-tdep.h ppc-linux-tdep.h ppc64-tdep.h \
rs6000-tdep.h rs6000-aix-tdep.h \
common/gdb_locale.h arch-utils.h trad-frame.h gnu-nat.h \
language.h nbsd-tdep.h solib-svr4.h \
macroexp.h ui-file.h regcache.h tracepoint.h i386-tdep.h \
macroexp.h ui-file.h regcache.h tracepoint.h tracefile.h i386-tdep.h \
inf-child.h p-lang.h event-top.h gdbtypes.h user-regs.h \
regformats/regdef.h config/alpha/nm-osf3.h config/i386/nm-i386gnu.h \
config/i386/nm-fbsd.h \

View File

@ -28,6 +28,7 @@
#include "completer.h"
#include "inferior.h"
#include "gdbthread.h"
#include "tracefile.h"
#include <ctype.h>

327
gdb/tracefile-tfile.c Normal file
View File

@ -0,0 +1,327 @@
/* Trace file TFILE format support in GDB.
Copyright (C) 1997-2014 Free Software Foundation, Inc.
This file is part of GDB.
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/>. */
#include "defs.h"
#include "tracefile.h"
#include "readline/tilde.h"
#include "filestuff.h"
#include "rsp-low.h" /* bin2hex */
/* TFILE trace writer. */
struct tfile_trace_file_writer
{
struct trace_file_writer base;
/* File pointer to tfile trace file. */
FILE *fp;
/* Path name of the tfile trace file. */
char *pathname;
};
/* This is the implementation of trace_file_write_ops method
target_save. We just call the generic target
target_save_trace_data to do target-side saving. */
static int
tfile_target_save (struct trace_file_writer *self,
const char *filename)
{
int err = target_save_trace_data (filename);
return (err >= 0);
}
/* This is the implementation of trace_file_write_ops method
dtor. */
static void
tfile_dtor (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
xfree (writer->pathname);
if (writer->fp != NULL)
fclose (writer->fp);
}
/* This is the implementation of trace_file_write_ops method
start. It creates the trace file FILENAME and registers some
cleanups. */
static void
tfile_start (struct trace_file_writer *self, const char *filename)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
writer->pathname = tilde_expand (filename);
writer->fp = gdb_fopen_cloexec (writer->pathname, "wb");
if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
writer->pathname, safe_strerror (errno));
}
/* This is the implementation of trace_file_write_ops method
write_header. Write the TFILE header. */
static void
tfile_write_header (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
int written;
/* 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. */
written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
if (written < 1)
perror_with_name (writer->pathname);
}
/* This is the implementation of trace_file_write_ops method
write_regblock_type. Write the size of register block. */
static void
tfile_write_regblock_type (struct trace_file_writer *self, int size)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "R %x\n", size);
}
/* This is the implementation of trace_file_write_ops method
write_status. */
static void
tfile_write_status (struct trace_file_writer *self,
struct trace_status *ts)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error
|| ts->stop_reason == tstop_command)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->stop_desc, buf, strlen (ts->stop_desc));
fprintf (writer->fp, ":%s", buf);
}
fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
if (ts->traceframe_count >= 0)
fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
if (ts->traceframes_created >= 0)
fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
if (ts->buffer_free >= 0)
fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
if (ts->buffer_size >= 0)
fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
if (ts->disconnected_tracing)
fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
if (ts->start_time)
{
fprintf (writer->fp, ";starttime:%s",
phex_nz (ts->start_time, sizeof (ts->start_time)));
}
if (ts->stop_time)
{
fprintf (writer->fp, ";stoptime:%s",
phex_nz (ts->stop_time, sizeof (ts->stop_time)));
}
if (ts->notes != NULL)
{
char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
bin2hex ((gdb_byte *) ts->notes, buf, strlen (ts->notes));
fprintf (writer->fp, ";notes:%s", buf);
}
if (ts->user_name != NULL)
{
char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
bin2hex ((gdb_byte *) ts->user_name, buf, strlen (ts->user_name));
fprintf (writer->fp, ";username:%s", buf);
}
fprintf (writer->fp, "\n");
}
/* This is the implementation of trace_file_write_ops method
write_uploaded_tsv. */
static void
tfile_write_uploaded_tsv (struct trace_file_writer *self,
struct uploaded_tsv *utsv)
{
char *buf = "";
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
if (utsv->name)
{
buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
bin2hex ((gdb_byte *) (utsv->name), buf, strlen (utsv->name));
}
fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
utsv->number, phex_nz (utsv->initial_value, 8),
utsv->builtin, buf);
if (utsv->name)
xfree (buf);
}
#define MAX_TRACE_UPLOAD 2000
/* This is the implementation of trace_file_write_ops method
write_uploaded_tp. */
static void
tfile_write_uploaded_tp (struct trace_file_writer *self,
struct uploaded_tp *utp)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
int a;
char *act;
char buf[MAX_TRACE_UPLOAD];
fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
(utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
if (utp->type == bp_fast_tracepoint)
fprintf (writer->fp, ":F%x", utp->orig_size);
if (utp->cond)
fprintf (writer->fp,
":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
utp->cond);
fprintf (writer->fp, "\n");
for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
fprintf (writer->fp, "tp A%x:%s:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
fprintf (writer->fp, "tp S%x:%s:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
if (utp->at_string)
{
encode_source_string (utp->number, utp->addr,
"at", utp->at_string, buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
if (utp->cond_string)
{
encode_source_string (utp->number, utp->addr,
"cond", utp->cond_string,
buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
{
encode_source_string (utp->number, utp->addr, "cmd", act,
buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
fprintf (writer->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)));
}
/* This is the implementation of trace_file_write_ops method
write_definition_end. */
static void
tfile_write_definition_end (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "\n");
}
/* This is the implementation of trace_file_write_ops method
write_raw_data. */
static void
tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
LONGEST len)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
if (fwrite (buf, len, 1, writer->fp) < 1)
perror_with_name (writer->pathname);
}
/* This is the implementation of trace_file_write_ops method
end. */
static void
tfile_end (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
uint32_t gotten = 0;
/* Mark the end of trace data. */
if (fwrite (&gotten, 4, 1, writer->fp) < 1)
perror_with_name (writer->pathname);
}
/* Operations to write trace buffers into TFILE format. */
static const struct trace_file_write_ops tfile_write_ops =
{
tfile_dtor,
tfile_target_save,
tfile_start,
tfile_write_header,
tfile_write_regblock_type,
tfile_write_status,
tfile_write_uploaded_tsv,
tfile_write_uploaded_tp,
tfile_write_definition_end,
tfile_write_raw_data,
NULL,
tfile_end,
};
/* Return a trace writer for TFILE format. */
struct trace_file_writer *
tfile_trace_file_writer_new (void)
{
struct tfile_trace_file_writer *writer
= xmalloc (sizeof (struct tfile_trace_file_writer));
writer->base.ops = &tfile_write_ops;
writer->fp = NULL;
writer->pathname = NULL;
return (struct trace_file_writer *) writer;
}

389
gdb/tracefile.c Normal file
View File

@ -0,0 +1,389 @@
/* Trace file support in GDB.
Copyright (C) 1997-2014 Free Software Foundation, Inc.
This file is part of GDB.
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/>. */
#include "defs.h"
#include "tracefile.h"
#include "ctf.h"
/* Helper macros. */
#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
(size))
#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
(size))
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
/* Free trace file writer. */
static void
trace_file_writer_xfree (void *arg)
{
struct trace_file_writer *writer = arg;
writer->ops->dtor (writer);
xfree (writer);
}
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
data and saves it locally. */
static void
trace_save (const char *filename, struct trace_file_writer *writer,
int target_does_save)
{
struct trace_status *ts = current_trace_status ();
int status;
struct uploaded_tp *uploaded_tps = NULL, *utp;
struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
ULONGEST offset = 0;
#define MAX_TRACE_UPLOAD 2000
gdb_byte buf[MAX_TRACE_UPLOAD];
int written;
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
/* If the target is to save the data to a file on its own, then just
send the command and be done with it. */
if (target_does_save)
{
if (!writer->ops->target_save (writer, filename))
error (_("Target failed to save trace data to '%s'."),
filename);
return;
}
/* Get the trace status first before opening the file, so if the
target is losing, we can get out without touching files. */
status = target_get_trace_status (ts);
writer->ops->start (writer, filename);
writer->ops->write_header (writer);
/* Write descriptive info. */
/* Write out the size of a register block. */
writer->ops->write_regblock_type (writer, trace_regblock_size);
/* Write out status of the tracing run (aka "tstatus" info). */
writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
changed tracepoints in GDB in preparation for a future tracing
run, or maybe just mass-deleted all types of breakpoints as part
of cleaning up. So as not to contaminate the session, leave the
data in its uploaded form, don't make into real tracepoints. */
/* Get trace state variables first, they may be checked when parsing
uploaded commands. */
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
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)
writer->ops->write_uploaded_tp (writer, utp);
free_uploaded_tps (&uploaded_tps);
/* Mark the end of the definition section. */
writer->ops->write_definition_end (writer);
/* Get and write the trace data proper. */
while (1)
{
LONGEST gotten = 0;
/* The writer supports writing the contents of trace buffer
directly to trace file. Don't parse the contents of trace
buffer. */
if (writer->ops->write_trace_buffer != NULL)
{
/* We ask for big blocks, in the hopes of efficiency, but
will take less if the target has packet size limitations
or some such. */
gotten = target_get_raw_trace_data (buf, offset,
MAX_TRACE_UPLOAD);
if (gotten < 0)
error (_("Failure to get requested trace buffer data"));
/* No more data is forthcoming, we're done. */
if (gotten == 0)
break;
writer->ops->write_trace_buffer (writer, buf, gotten);
offset += gotten;
}
else
{
uint16_t tp_num;
uint32_t tf_size;
/* Parse the trace buffers according to how data are stored
in trace buffer in GDBserver. */
gotten = target_get_raw_trace_data (buf, offset, 6);
if (gotten == 0)
break;
/* Read the first six bytes in, which is the tracepoint
number and trace frame size. */
tp_num = (uint16_t)
extract_unsigned_integer (&buf[0], 2, byte_order);
tf_size = (uint32_t)
extract_unsigned_integer (&buf[2], 4, byte_order);
writer->ops->frame_ops->start (writer, tp_num);
gotten = 6;
if (tf_size > 0)
{
unsigned int block;
offset += 6;
for (block = 0; block < tf_size; )
{
gdb_byte block_type;
/* We'll fetch one block each time, in order to
handle the extremely large 'M' block. We first
fetch one byte to get the type of the block. */
gotten = target_get_raw_trace_data (buf, offset, 1);
if (gotten < 1)
error (_("Failure to get requested trace buffer data"));
gotten = 1;
block += 1;
offset += 1;
block_type = buf[0];
switch (block_type)
{
case 'R':
gotten
= target_get_raw_trace_data (buf, offset,
trace_regblock_size);
if (gotten < trace_regblock_size)
error (_("Failure to get requested trace"
" buffer data"));
TRACE_WRITE_R_BLOCK (writer, buf,
trace_regblock_size);
break;
case 'M':
{
unsigned short mlen;
ULONGEST addr;
LONGEST t;
int j;
t = target_get_raw_trace_data (buf,offset, 10);
if (t < 10)
error (_("Failure to get requested trace"
" buffer data"));
offset += 10;
block += 10;
gotten = 0;
addr = (ULONGEST)
extract_unsigned_integer (buf, 8,
byte_order);
mlen = (unsigned short)
extract_unsigned_integer (&buf[8], 2,
byte_order);
TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
mlen);
/* The memory contents in 'M' block may be
very large. Fetch the data from the target
and write them into file one by one. */
for (j = 0; j < mlen; )
{
unsigned int read_length;
if (mlen - j > MAX_TRACE_UPLOAD)
read_length = MAX_TRACE_UPLOAD;
else
read_length = mlen - j;
t = target_get_raw_trace_data (buf,
offset + j,
read_length);
if (t < read_length)
error (_("Failure to get requested"
" trace buffer data"));
TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
read_length);
j += read_length;
gotten += read_length;
}
break;
}
case 'V':
{
int vnum;
LONGEST val;
gotten
= target_get_raw_trace_data (buf, offset,
12);
if (gotten < 12)
error (_("Failure to get requested"
" trace buffer data"));
vnum = (int) extract_signed_integer (buf,
4,
byte_order);
val
= extract_signed_integer (&buf[4], 8,
byte_order);
TRACE_WRITE_V_BLOCK (writer, vnum, val);
}
break;
default:
error (_("Unknown block type '%c' (0x%x) in"
" trace frame"),
block_type, block_type);
}
block += gotten;
offset += gotten;
}
}
else
offset += gotten;
writer->ops->frame_ops->end (writer);
}
}
writer->ops->end (writer);
}
static void
trace_save_command (char *args, int from_tty)
{
int target_does_save = 0;
char **argv;
char *filename = NULL;
struct cleanup *back_to;
int generate_ctf = 0;
struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
for (; *argv; ++argv)
{
if (strcmp (*argv, "-r") == 0)
target_does_save = 1;
if (strcmp (*argv, "-ctf") == 0)
generate_ctf = 1;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
filename = *argv;
}
if (!filename)
error_no_arg (_("file in which to save trace data"));
if (generate_ctf)
writer = ctf_trace_file_writer_new ();
else
writer = tfile_trace_file_writer_new ();
make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
if (from_tty)
printf_filtered (_("Trace data saved to %s '%s'.\n"),
generate_ctf ? "directory" : "file", filename);
do_cleanups (back_to);
}
/* Save the trace data to file FILENAME of tfile format. */
void
trace_save_tfile (const char *filename, int target_does_save)
{
struct trace_file_writer *writer;
struct cleanup *back_to;
writer = tfile_trace_file_writer_new ();
back_to = make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
do_cleanups (back_to);
}
/* Save the trace data to dir DIRNAME of ctf format. */
void
trace_save_ctf (const char *dirname, int target_does_save)
{
struct trace_file_writer *writer;
struct cleanup *back_to;
writer = ctf_trace_file_writer_new ();
back_to = make_cleanup (trace_file_writer_xfree, writer);
trace_save (dirname, writer, target_does_save);
do_cleanups (back_to);
}
extern initialize_file_ftype _initialize_tracefile;
void
_initialize_tracefile (void)
{
add_com ("tsave", class_trace, trace_save_command, _("\
Save the trace data to a file.\n\
Use the '-ctf' option to save the data to CTF format.\n\
Use the '-r' option to direct the target to save directly to the file,\n\
using its own filesystem."));
}

114
gdb/tracefile.h Normal file
View File

@ -0,0 +1,114 @@
#ifndef TRACEFILE_H
#define TRACEFILE_H 1
#include "defs.h"
#include "tracepoint.h"
struct trace_file_writer;
/* Operations to write trace frames to a specific trace format. */
struct trace_frame_write_ops
{
/* Write a new trace frame. The tracepoint number of this trace
frame is TPNUM. */
void (*start) (struct trace_file_writer *self, uint16_t tpnum);
/* Write an 'R' block. Buffer BUF contains its contents and SIZE is
its size. */
void (*write_r_block) (struct trace_file_writer *self,
gdb_byte *buf, int32_t size);
/* Write an 'M' block, the header and memory contents respectively.
The header of 'M' block is composed of the start address and the
length of memory collection, and the memory contents contain
the collected memory contents in tracing.
For extremely large M block, GDB is unable to get its contents
and write them into trace file in one go, due to the limitation
of the remote target or the size of internal buffer, we split
the operation to 'M' block to two operations. */
/* Write the head of 'M' block. ADDR is the start address of
collected memory and LENGTH is the length of memory contents. */
void (*write_m_block_header) (struct trace_file_writer *self,
uint64_t addr, uint16_t length);
/* Write the memory contents of 'M' block. Buffer BUF contains
its contents and LENGTH is its length. This method can be called
multiple times to write large memory contents of a single 'M'
block. */
void (*write_m_block_memory) (struct trace_file_writer *self,
gdb_byte *buf, uint16_t length);
/* Write a 'V' block. NUM is the trace variable number and VAL is
the value of the trace variable. */
void (*write_v_block) (struct trace_file_writer *self, int32_t num,
uint64_t val);
/* The end of the trace frame. */
void (*end) (struct trace_file_writer *self);
};
/* Operations to write trace buffers to a specific trace format. */
struct trace_file_write_ops
{
/* Destructor. Releases everything from SELF (but not SELF
itself). */
void (*dtor) (struct trace_file_writer *self);
/* Save the data to file or directory NAME of desired format in
target side. Return true for success, otherwise return
false. */
int (*target_save) (struct trace_file_writer *self,
const char *name);
/* Write the trace buffers to file or directory NAME. */
void (*start) (struct trace_file_writer *self,
const char *name);
/* Write the trace header. */
void (*write_header) (struct trace_file_writer *self);
/* Write the type of block about registers. SIZE is the size of
all registers on the target. */
void (*write_regblock_type) (struct trace_file_writer *self,
int size);
/* Write trace status TS. */
void (*write_status) (struct trace_file_writer *self,
struct trace_status *ts);
/* Write the uploaded TSV. */
void (*write_uploaded_tsv) (struct trace_file_writer *self,
struct uploaded_tsv *tsv);
/* Write the uploaded tracepoint TP. */
void (*write_uploaded_tp) (struct trace_file_writer *self,
struct uploaded_tp *tp);
/* Write to mark the end of the definition part. */
void (*write_definition_end) (struct trace_file_writer *self);
/* Write the data of trace buffer without parsing. The content is
in BUF and length is LEN. */
void (*write_trace_buffer) (struct trace_file_writer *self,
gdb_byte *buf, LONGEST len);
/* Operations to write trace frames. The user of this field is
responsible to parse the data of trace buffer. Either field
'write_trace_buffer' or field ' frame_ops' is NULL. */
const struct trace_frame_write_ops *frame_ops;
/* The end of writing trace buffers. */
void (*end) (struct trace_file_writer *self);
};
/* Trace file writer for a given format. */
struct trace_file_writer
{
const struct trace_file_write_ops *ops;
};
extern struct trace_file_writer *tfile_trace_file_writer_new (void);
#endif /* TRACEFILE_H */

View File

@ -56,6 +56,7 @@
#include "ctf.h"
#include "filestuff.h"
#include "rsp-low.h"
#include "tracefile.h"
/* readline include files */
#include "readline/readline.h"
@ -191,9 +192,6 @@ static char *mem2hex (gdb_byte *, char *, int);
static void add_register (struct collection_list *collection,
unsigned int regno);
static void free_uploaded_tps (struct uploaded_tp **utpp);
static void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
static struct command_line *
all_tracepoint_actions_and_cleanup (struct breakpoint *t);
@ -201,7 +199,7 @@ extern void _initialize_tracepoint (void);
static struct trace_status trace_status;
char *stop_reason_names[] = {
const char *stop_reason_names[] = {
"tunknown",
"tnotrun",
"tstop",
@ -3096,664 +3094,6 @@ encode_source_string (int tpnum, ULONGEST addr,
return -1;
}
/* Free trace file writer. */
static void
trace_file_writer_xfree (void *arg)
{
struct trace_file_writer *writer = arg;
writer->ops->dtor (writer);
xfree (writer);
}
/* TFILE trace writer. */
struct tfile_trace_file_writer
{
struct trace_file_writer base;
/* File pointer to tfile trace file. */
FILE *fp;
/* Path name of the tfile trace file. */
char *pathname;
};
/* This is the implementation of trace_file_write_ops method
target_save. We just call the generic target
target_save_trace_data to do target-side saving. */
static int
tfile_target_save (struct trace_file_writer *self,
const char *filename)
{
int err = target_save_trace_data (filename);
return (err >= 0);
}
/* This is the implementation of trace_file_write_ops method
dtor. */
static void
tfile_dtor (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
xfree (writer->pathname);
if (writer->fp != NULL)
fclose (writer->fp);
}
/* This is the implementation of trace_file_write_ops method
start. It creates the trace file FILENAME and registers some
cleanups. */
static void
tfile_start (struct trace_file_writer *self, const char *filename)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
writer->pathname = tilde_expand (filename);
writer->fp = gdb_fopen_cloexec (writer->pathname, "wb");
if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
writer->pathname, safe_strerror (errno));
}
/* This is the implementation of trace_file_write_ops method
write_header. Write the TFILE header. */
static void
tfile_write_header (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
int written;
/* 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. */
written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
if (written < 1)
perror_with_name (writer->pathname);
}
/* This is the implementation of trace_file_write_ops method
write_regblock_type. Write the size of register block. */
static void
tfile_write_regblock_type (struct trace_file_writer *self, int size)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "R %x\n", size);
}
/* This is the implementation of trace_file_write_ops method
write_status. */
static void
tfile_write_status (struct trace_file_writer *self,
struct trace_status *ts)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error
|| ts->stop_reason == tstop_command)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->stop_desc, buf, strlen (ts->stop_desc));
fprintf (writer->fp, ":%s", buf);
}
fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
if (ts->traceframe_count >= 0)
fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
if (ts->traceframes_created >= 0)
fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
if (ts->buffer_free >= 0)
fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
if (ts->buffer_size >= 0)
fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
if (ts->disconnected_tracing)
fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
if (ts->start_time)
{
fprintf (writer->fp, ";starttime:%s",
phex_nz (ts->start_time, sizeof (ts->start_time)));
}
if (ts->stop_time)
{
fprintf (writer->fp, ";stoptime:%s",
phex_nz (ts->stop_time, sizeof (ts->stop_time)));
}
if (ts->notes != NULL)
{
char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
bin2hex ((gdb_byte *) ts->notes, buf, strlen (ts->notes));
fprintf (writer->fp, ";notes:%s", buf);
}
if (ts->user_name != NULL)
{
char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
bin2hex ((gdb_byte *) ts->user_name, buf, strlen (ts->user_name));
fprintf (writer->fp, ";username:%s", buf);
}
fprintf (writer->fp, "\n");
}
/* This is the implementation of trace_file_write_ops method
write_uploaded_tsv. */
static void
tfile_write_uploaded_tsv (struct trace_file_writer *self,
struct uploaded_tsv *utsv)
{
char *buf = "";
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
if (utsv->name)
{
buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
bin2hex ((gdb_byte *) (utsv->name), buf, strlen (utsv->name));
}
fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
utsv->number, phex_nz (utsv->initial_value, 8),
utsv->builtin, buf);
if (utsv->name)
xfree (buf);
}
#define MAX_TRACE_UPLOAD 2000
/* This is the implementation of trace_file_write_ops method
write_uploaded_tp. */
static void
tfile_write_uploaded_tp (struct trace_file_writer *self,
struct uploaded_tp *utp)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
int a;
char *act;
char buf[MAX_TRACE_UPLOAD];
fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
(utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
if (utp->type == bp_fast_tracepoint)
fprintf (writer->fp, ":F%x", utp->orig_size);
if (utp->cond)
fprintf (writer->fp,
":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
utp->cond);
fprintf (writer->fp, "\n");
for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
fprintf (writer->fp, "tp A%x:%s:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
fprintf (writer->fp, "tp S%x:%s:%s\n",
utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
if (utp->at_string)
{
encode_source_string (utp->number, utp->addr,
"at", utp->at_string, buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
if (utp->cond_string)
{
encode_source_string (utp->number, utp->addr,
"cond", utp->cond_string,
buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
{
encode_source_string (utp->number, utp->addr, "cmd", act,
buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
fprintf (writer->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)));
}
/* This is the implementation of trace_file_write_ops method
write_definition_end. */
static void
tfile_write_definition_end (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
fprintf (writer->fp, "\n");
}
/* This is the implementation of trace_file_write_ops method
write_raw_data. */
static void
tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
LONGEST len)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
if (fwrite (buf, len, 1, writer->fp) < 1)
perror_with_name (writer->pathname);
}
/* This is the implementation of trace_file_write_ops method
end. */
static void
tfile_end (struct trace_file_writer *self)
{
struct tfile_trace_file_writer *writer
= (struct tfile_trace_file_writer *) self;
uint32_t gotten = 0;
/* Mark the end of trace data. */
if (fwrite (&gotten, 4, 1, writer->fp) < 1)
perror_with_name (writer->pathname);
}
/* Operations to write trace buffers into TFILE format. */
static const struct trace_file_write_ops tfile_write_ops =
{
tfile_dtor,
tfile_target_save,
tfile_start,
tfile_write_header,
tfile_write_regblock_type,
tfile_write_status,
tfile_write_uploaded_tsv,
tfile_write_uploaded_tp,
tfile_write_definition_end,
tfile_write_raw_data,
NULL,
tfile_end,
};
/* Helper macros. */
#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
(size))
#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
(size))
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
data and saves it locally. */
static void
trace_save (const char *filename, struct trace_file_writer *writer,
int target_does_save)
{
struct trace_status *ts = current_trace_status ();
int status;
struct uploaded_tp *uploaded_tps = NULL, *utp;
struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
ULONGEST offset = 0;
gdb_byte buf[MAX_TRACE_UPLOAD];
#define MAX_TRACE_UPLOAD 2000
int written;
enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
/* If the target is to save the data to a file on its own, then just
send the command and be done with it. */
if (target_does_save)
{
if (!writer->ops->target_save (writer, filename))
error (_("Target failed to save trace data to '%s'."),
filename);
return;
}
/* Get the trace status first before opening the file, so if the
target is losing, we can get out without touching files. */
status = target_get_trace_status (ts);
writer->ops->start (writer, filename);
writer->ops->write_header (writer);
/* Write descriptive info. */
/* Write out the size of a register block. */
writer->ops->write_regblock_type (writer, trace_regblock_size);
/* Write out status of the tracing run (aka "tstatus" info). */
writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
changed tracepoints in GDB in preparation for a future tracing
run, or maybe just mass-deleted all types of breakpoints as part
of cleaning up. So as not to contaminate the session, leave the
data in its uploaded form, don't make into real tracepoints. */
/* Get trace state variables first, they may be checked when parsing
uploaded commands. */
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
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)
writer->ops->write_uploaded_tp (writer, utp);
free_uploaded_tps (&uploaded_tps);
/* Mark the end of the definition section. */
writer->ops->write_definition_end (writer);
/* Get and write the trace data proper. */
while (1)
{
LONGEST gotten = 0;
/* The writer supports writing the contents of trace buffer
directly to trace file. Don't parse the contents of trace
buffer. */
if (writer->ops->write_trace_buffer != NULL)
{
/* We ask for big blocks, in the hopes of efficiency, but
will take less if the target has packet size limitations
or some such. */
gotten = target_get_raw_trace_data (buf, offset,
MAX_TRACE_UPLOAD);
if (gotten < 0)
error (_("Failure to get requested trace buffer data"));
/* No more data is forthcoming, we're done. */
if (gotten == 0)
break;
writer->ops->write_trace_buffer (writer, buf, gotten);
offset += gotten;
}
else
{
uint16_t tp_num;
uint32_t tf_size;
/* Parse the trace buffers according to how data are stored
in trace buffer in GDBserver. */
gotten = target_get_raw_trace_data (buf, offset, 6);
if (gotten == 0)
break;
/* Read the first six bytes in, which is the tracepoint
number and trace frame size. */
tp_num = (uint16_t)
extract_unsigned_integer (&buf[0], 2, byte_order);
tf_size = (uint32_t)
extract_unsigned_integer (&buf[2], 4, byte_order);
writer->ops->frame_ops->start (writer, tp_num);
gotten = 6;
if (tf_size > 0)
{
unsigned int block;
offset += 6;
for (block = 0; block < tf_size; )
{
gdb_byte block_type;
/* We'll fetch one block each time, in order to
handle the extremely large 'M' block. We first
fetch one byte to get the type of the block. */
gotten = target_get_raw_trace_data (buf, offset, 1);
if (gotten < 1)
error (_("Failure to get requested trace buffer data"));
gotten = 1;
block += 1;
offset += 1;
block_type = buf[0];
switch (block_type)
{
case 'R':
gotten
= target_get_raw_trace_data (buf, offset,
trace_regblock_size);
if (gotten < trace_regblock_size)
error (_("Failure to get requested trace"
" buffer data"));
TRACE_WRITE_R_BLOCK (writer, buf,
trace_regblock_size);
break;
case 'M':
{
unsigned short mlen;
ULONGEST addr;
LONGEST t;
int j;
t = target_get_raw_trace_data (buf,offset, 10);
if (t < 10)
error (_("Failure to get requested trace"
" buffer data"));
offset += 10;
block += 10;
gotten = 0;
addr = (ULONGEST)
extract_unsigned_integer (buf, 8,
byte_order);
mlen = (unsigned short)
extract_unsigned_integer (&buf[8], 2,
byte_order);
TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
mlen);
/* The memory contents in 'M' block may be
very large. Fetch the data from the target
and write them into file one by one. */
for (j = 0; j < mlen; )
{
unsigned int read_length;
if (mlen - j > MAX_TRACE_UPLOAD)
read_length = MAX_TRACE_UPLOAD;
else
read_length = mlen - j;
t = target_get_raw_trace_data (buf,
offset + j,
read_length);
if (t < read_length)
error (_("Failure to get requested"
" trace buffer data"));
TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
read_length);
j += read_length;
gotten += read_length;
}
break;
}
case 'V':
{
int vnum;
LONGEST val;
gotten
= target_get_raw_trace_data (buf, offset,
12);
if (gotten < 12)
error (_("Failure to get requested"
" trace buffer data"));
vnum = (int) extract_signed_integer (buf,
4,
byte_order);
val
= extract_signed_integer (&buf[4], 8,
byte_order);
TRACE_WRITE_V_BLOCK (writer, vnum, val);
}
break;
default:
error (_("Unknown block type '%c' (0x%x) in"
" trace frame"),
block_type, block_type);
}
block += gotten;
offset += gotten;
}
}
else
offset += gotten;
writer->ops->frame_ops->end (writer);
}
}
writer->ops->end (writer);
}
/* Return a trace writer for TFILE format. */
static struct trace_file_writer *
tfile_trace_file_writer_new (void)
{
struct tfile_trace_file_writer *writer
= xmalloc (sizeof (struct tfile_trace_file_writer));
writer->base.ops = &tfile_write_ops;
writer->fp = NULL;
writer->pathname = NULL;
return (struct trace_file_writer *) writer;
}
static void
trace_save_command (char *args, int from_tty)
{
int target_does_save = 0;
char **argv;
char *filename = NULL;
struct cleanup *back_to;
int generate_ctf = 0;
struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
argv = gdb_buildargv (args);
back_to = make_cleanup_freeargv (argv);
for (; *argv; ++argv)
{
if (strcmp (*argv, "-r") == 0)
target_does_save = 1;
if (strcmp (*argv, "-ctf") == 0)
generate_ctf = 1;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
filename = *argv;
}
if (!filename)
error_no_arg (_("file in which to save trace data"));
if (generate_ctf)
writer = ctf_trace_file_writer_new ();
else
writer = tfile_trace_file_writer_new ();
make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
if (from_tty)
printf_filtered (_("Trace data saved to %s '%s'.\n"),
generate_ctf ? "directory" : "file", filename);
do_cleanups (back_to);
}
/* Save the trace data to file FILENAME of tfile format. */
void
trace_save_tfile (const char *filename, int target_does_save)
{
struct trace_file_writer *writer;
struct cleanup *back_to;
writer = tfile_trace_file_writer_new ();
back_to = make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
do_cleanups (back_to);
}
/* Save the trace data to dir DIRNAME of ctf format. */
void
trace_save_ctf (const char *dirname, int target_does_save)
{
struct trace_file_writer *writer;
struct cleanup *back_to;
writer = ctf_trace_file_writer_new ();
back_to = make_cleanup (trace_file_writer_xfree, writer);
trace_save (dirname, writer, target_does_save);
do_cleanups (back_to);
}
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
@ -3953,7 +3293,7 @@ get_uploaded_tp (int num, ULONGEST addr, struct uploaded_tp **utpp)
return utp;
}
static void
void
free_uploaded_tps (struct uploaded_tp **utpp)
{
struct uploaded_tp *next_one;
@ -3985,7 +3325,7 @@ get_uploaded_tsv (int num, struct uploaded_tsv **utsvp)
return utsv;
}
static void
void
free_uploaded_tsvs (struct uploaded_tsv **utsvp)
{
struct uploaded_tsv *next_one;
@ -5842,12 +5182,6 @@ _initialize_tracepoint (void)
add_com ("tdump", class_trace, trace_dump_command,
_("Print everything collected at the current tracepoint."));
add_com ("tsave", class_trace, trace_save_command, _("\
Save the trace data to a file.\n\
Use the '-ctf' option to save the data to CTF format.\n\
Use the '-r' option to direct the target to save directly to the file,\n\
using its own filesystem."));
c = add_com ("tvariable", class_trace, trace_variable_command,_("\
Define a trace state variable.\n\
Argument is a $-prefixed name, optionally followed\n\

View File

@ -155,6 +155,8 @@ extern char *default_collect;
extern int trace_regblock_size;
extern const char *stop_reason_names[];
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@ -218,111 +220,6 @@ struct static_tracepoint_marker
char *extra;
};
struct trace_file_writer;
/* Operations to write trace frames to a specific trace format. */
struct trace_frame_write_ops
{
/* Write a new trace frame. The tracepoint number of this trace
frame is TPNUM. */
void (*start) (struct trace_file_writer *self, uint16_t tpnum);
/* Write an 'R' block. Buffer BUF contains its contents and SIZE is
its size. */
void (*write_r_block) (struct trace_file_writer *self,
gdb_byte *buf, int32_t size);
/* Write an 'M' block, the header and memory contents respectively.
The header of 'M' block is composed of the start address and the
length of memory collection, and the memory contents contain
the collected memory contents in tracing.
For extremely large M block, GDB is unable to get its contents
and write them into trace file in one go, due to the limitation
of the remote target or the size of internal buffer, we split
the operation to 'M' block to two operations. */
/* Write the head of 'M' block. ADDR is the start address of
collected memory and LENGTH is the length of memory contents. */
void (*write_m_block_header) (struct trace_file_writer *self,
uint64_t addr, uint16_t length);
/* Write the memory contents of 'M' block. Buffer BUF contains
its contents and LENGTH is its length. This method can be called
multiple times to write large memory contents of a single 'M'
block. */
void (*write_m_block_memory) (struct trace_file_writer *self,
gdb_byte *buf, uint16_t length);
/* Write a 'V' block. NUM is the trace variable number and VAL is
the value of the trace variable. */
void (*write_v_block) (struct trace_file_writer *self, int32_t num,
uint64_t val);
/* The end of the trace frame. */
void (*end) (struct trace_file_writer *self);
};
/* Operations to write trace buffers to a specific trace format. */
struct trace_file_write_ops
{
/* Destructor. Releases everything from SELF (but not SELF
itself). */
void (*dtor) (struct trace_file_writer *self);
/* Save the data to file or directory NAME of desired format in
target side. Return true for success, otherwise return
false. */
int (*target_save) (struct trace_file_writer *self,
const char *name);
/* Write the trace buffers to file or directory NAME. */
void (*start) (struct trace_file_writer *self,
const char *name);
/* Write the trace header. */
void (*write_header) (struct trace_file_writer *self);
/* Write the type of block about registers. SIZE is the size of
all registers on the target. */
void (*write_regblock_type) (struct trace_file_writer *self,
int size);
/* Write trace status TS. */
void (*write_status) (struct trace_file_writer *self,
struct trace_status *ts);
/* Write the uploaded TSV. */
void (*write_uploaded_tsv) (struct trace_file_writer *self,
struct uploaded_tsv *tsv);
/* Write the uploaded tracepoint TP. */
void (*write_uploaded_tp) (struct trace_file_writer *self,
struct uploaded_tp *tp);
/* Write to mark the end of the definition part. */
void (*write_definition_end) (struct trace_file_writer *self);
/* Write the data of trace buffer without parsing. The content is
in BUF and length is LEN. */
void (*write_trace_buffer) (struct trace_file_writer *self,
gdb_byte *buf, LONGEST len);
/* Operations to write trace frames. The user of this field is
responsible to parse the data of trace buffer. Either field
'write_trace_buffer' or field ' frame_ops' is NULL. */
const struct trace_frame_write_ops *frame_ops;
/* The end of writing trace buffers. */
void (*end) (struct trace_file_writer *self);
};
/* Trace file writer for a given format. */
struct trace_file_writer
{
const struct trace_file_write_ops *ops;
};
struct memrange
{
/* memrange_absolute for absolute memory range, else basereg
@ -424,8 +321,11 @@ 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 void free_uploaded_tps (struct uploaded_tp **utpp);
extern struct uploaded_tsv *get_uploaded_tsv (int num,
struct uploaded_tsv **utsvp);
extern void free_uploaded_tsvs (struct uploaded_tsv **utsvp);
extern struct tracepoint *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);