+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
# 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@
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 \
#include "completer.h"
#include "inferior.h"
#include "gdbthread.h"
+#include "tracefile.h"
#include <ctype.h>
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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."));
+}
--- /dev/null
+#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 */
#include "ctf.h"
#include "filestuff.h"
#include "rsp-low.h"
+#include "tracefile.h"
/* readline include files */
#include "readline/readline.h"
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);
static struct trace_status trace_status;
-char *stop_reason_names[] = {
+const char *stop_reason_names[] = {
"tunknown",
"tnotrun",
"tstop",
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. */
return utp;
}
-static void
+void
free_uploaded_tps (struct uploaded_tp **utpp)
{
struct uploaded_tp *next_one;
return utsv;
}
-static void
+void
free_uploaded_tsvs (struct uploaded_tsv **utsvp)
{
struct uploaded_tsv *next_one;
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\
extern int trace_regblock_size;
+extern const char *stop_reason_names[];
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
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
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);