Move trace file writer out of tracepoint.c
authorYao Qi <yao@codesourcery.com>
Mon, 10 Feb 2014 05:31:12 +0000 (13:31 +0800)
committerYao Qi <yao@codesourcery.com>
Sun, 23 Feb 2014 03:44:26 +0000 (11:44 +0800)
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.

gdb/ChangeLog
gdb/Makefile.in
gdb/ctf.c
gdb/tracefile-tfile.c [new file with mode: 0644]
gdb/tracefile.c [new file with mode: 0644]
gdb/tracefile.h [new file with mode: 0644]
gdb/tracepoint.c
gdb/tracepoint.h

index f97c5fe7dbeb0f47f64ede118f0d8901ea05ba8c..2004167c53d9173eed431e4d4a81e18ab4183b9c 100644 (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
index 28847251b254147474a6226ea3d2366d24074a2a..fe069883c399cfac48684cff1567feaabad5b0af 100644 (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 \
index 8777014e220fa9d991bf8665cae6ad4081fc8e9a..ae075f92e35b9101fb32e8d55d990681aa6d71b3 100644 (file)
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -28,6 +28,7 @@
 #include "completer.h"
 #include "inferior.h"
 #include "gdbthread.h"
+#include "tracefile.h"
 
 #include <ctype.h>
 
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
new file mode 100644 (file)
index 0000000..8a53e9d
--- /dev/null
@@ -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;
+}
diff --git a/gdb/tracefile.c b/gdb/tracefile.c
new file mode 100644 (file)
index 0000000..9945ae5
--- /dev/null
@@ -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."));
+}
diff --git a/gdb/tracefile.h b/gdb/tracefile.h
new file mode 100644 (file)
index 0000000..833de5c
--- /dev/null
@@ -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 */
index de4f6af2524c6ca849c8af8275525046343526cc..2b4c13778d3847cad5999a244cbeec9d21b442b2 100644 (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\
index dd9b48bf379d6e4fcfacef00d17e6d8abd097384..6b00b3085422d844cf03a3582c63b7337b3c274d 100644 (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);