This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH v3 02/15] Save trace into CTF format


This patch is to teach GDB to save trace data into CTF format.  In
this patch, struct trace_frame_write_ops and struct
trace_file_write_ops are implemented, so that GDB is able to write
trace data in CTF format.

Note that we don't use ui-file to write trace file, because
ui_file_write doesn't handle error well.  We can migrate to ui-file
once ui_file_write starts to handle error.

gdb:

2013-03-08  Hui Zhu  <hui_zhu@mentor.com>
	    Yao Qi  <yao@codesourcery.com>

	* Makefile.in (REMOTE_OBS): Add ctf.o.
	(SFILES): Add ctf.c.
	(HFILES_NO_SRCDIR): Add ctf.h.
	* ctf.c, ctf.h: New files.
	* tracepoint.c : Include 'ctf.h'.
	(collect_pseudocommand): Remove static.
	(trace_save_command): Parse option "-ctf".
	Produce different trace file writers per option.
	Adjust output message.
	(trace_save_tfile, trace_save_ctf): New.
	* tracepoint.h (trace_save_tfile, trace_save_ctf): Declare.
	* mi/mi-main.c: Include 'ctf.h'.
	(mi_cmd_trace_save): Handle option '-ctf'.  Call either
	trace_save_tfile or trace_save_ctf.
---
 gdb/Makefile.in  |    6 +-
 gdb/ctf.c        |  648 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ctf.h        |   25 ++
 gdb/mi/mi-main.c |   47 +++-
 gdb/tracepoint.c |   28 +++-
 gdb/tracepoint.h |    2 +
 6 files changed, 738 insertions(+), 18 deletions(-)
 create mode 100644 gdb/ctf.c
 create mode 100644 gdb/ctf.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed30db5..5be6c77 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -510,7 +510,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
+	remote-notif.o ctf.o
 
 # This is remote-sim.o if a simulator is to be linked in.
 SIM_OBS = @SIM_OBS@
@@ -759,7 +759,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	regset.c sol-thread.c windows-termcap.c \
 	common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
 	common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
-	common/format.c
+	common/format.c ctf.c
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -835,7 +835,7 @@ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
 common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
 common/format.h common/host-defs.h utils.h common/queue.h \
 common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
-gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h
+gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h ctf.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
diff --git a/gdb/ctf.c b/gdb/ctf.c
new file mode 100644
index 0000000..909b769
--- /dev/null
+++ b/gdb/ctf.c
@@ -0,0 +1,648 @@
+/* CTF format support.
+
+   Copyright (C) 2012-2013 Free Software Foundation, Inc.
+   Contributed by Hui Zhu <hui_zhu@mentor.com>
+   Contributed by Yao Qi <yao@codesourcery.com>
+
+   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 "ctf.h"
+#include "tracepoint.h"
+#include "regcache.h"
+
+#include <ctype.h>
+
+/* GDB saves trace buffers and other information (such as trace
+   status) got from the remote target into Common Trace Format (CTF).
+   The following types of information are expected to save in CTF:
+
+   1. The length (in bytes) of register cache.  Event "register" will
+   be defined in metadata, which includes the length.
+
+   2. Trace status.  Not implemented yet in CTF writer.
+
+   3. Uploaded trace variables and tracepoints.  Not implemented yet
+   in CTF writer.
+
+   4. Trace frames.  Each trace frame is composed by several blocks
+   of different types ('R', 'M', 'V').  One trace frame is saved in
+   one CTF packet and the blocks of this frame are saved as events.
+   4.1: The trace frame related information (such as the number of
+   tracepoint associated with this frame) is saved in the packet
+   context.
+   4.2: The block 'M', 'R' and 'V' are saved in event "memory",
+   "register" and "tsv" respectively.
+   4.3: When iterating over events, babeltrace can't tell iterator
+   goes to a new packet, so we need a marker or anchor to tell GDB
+   that iterator goes into a new packet or frame.  We define event
+   "frame".  */
+
+#define CTF_MAGIC		0xC1FC1FC1
+#define CTF_SAVE_MAJOR		1
+#define CTF_SAVE_MINOR		8
+
+#define CTF_METADATA_NAME	"metadata"
+#define CTF_DATASTREAM_NAME	"datastream"
+
+/* Reserved event id.  */
+
+#define CTF_EVENT_ID_REGISTER 0
+#define CTF_EVENT_ID_TSV 1
+#define CTF_EVENT_ID_MEMORY 2
+#define CTF_EVENT_ID_FRAME 3
+
+/* The state kept while writing the CTF datastream file.  */
+
+struct trace_write_handler
+{
+  /* File descriptor of metadata.  */
+  FILE *metadata_fd;
+  /* File descriptor of traceframes.  */
+  FILE *datastream_fd;
+
+  /* This is the content size of the current packet.  */
+  size_t content_size;
+
+  /* This is the start offset of current packet.  */
+  long packet_start;
+};
+
+/* Write metadata in FORMAT.  */
+
+static void
+ctf_save_write_metadata (struct trace_write_handler *handler,
+			 const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  if (vfprintf (handler->metadata_fd, format, args) < 0)
+    error (_("Unable to write metadata file (%s)"),
+	     safe_strerror (errno));
+  va_end (args);
+}
+
+/* Write BUF of length SIZE to datastream file represented by
+   HANDLER.  */
+
+static int
+ctf_save_write (struct trace_write_handler *handler,
+		const gdb_byte *buf, size_t size)
+{
+  if (fwrite (buf, size, 1, handler->datastream_fd) != 1)
+    error (_("Unable to write file for saving trace data (%s)"),
+	   safe_strerror (errno));
+
+  handler->content_size += size;
+
+  return 0;
+}
+
+/* Write a unsigned 32-bit integer to datastream file represented by
+   HANDLER.  */
+
+#define ctf_save_write_uint32(HANDLER, U32) \
+  ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+
+/* Set datastream file position.  Update HANDLER->content_size
+   if WHENCE is SEEK_CUR.  */
+
+static int
+ctf_save_fseek (struct trace_write_handler *handler, long offset,
+		int whence)
+{
+  gdb_assert (whence != SEEK_END);
+  gdb_assert (whence != SEEK_SET
+	      || offset <= handler->content_size + handler->packet_start);
+
+  if (fseek (handler->datastream_fd, offset, whence))
+    error (_("Unable to seek file for saving trace data (%s)"),
+	   safe_strerror (errno));
+
+  if (whence == SEEK_CUR)
+    handler->content_size += offset;
+
+  return 0;
+}
+
+/* Change the datastream file position to align on ALIGN_SIZE,
+   and write BUF to datastream file.  The size of BUF is SIZE.  */
+
+static int
+ctf_save_align_write (struct trace_write_handler *handler,
+		      const gdb_byte *buf,
+		      size_t size, size_t align_size)
+{
+  long offset
+    = (align_up (handler->content_size, align_size)
+       - handler->content_size);
+
+  if (ctf_save_fseek (handler, offset, SEEK_CUR))
+    return -1;
+
+  if (ctf_save_write (handler, buf, size))
+    return -1;
+
+  return 0;
+}
+
+/* Write events to next new packet.  */
+
+static void
+ctf_save_next_packet (struct trace_write_handler *handler)
+{
+  handler->packet_start += (handler->content_size + 4);
+  ctf_save_fseek (handler, handler->packet_start, SEEK_SET);
+  handler->content_size = 0;
+}
+
+/* Write the CTF metadata header.  */
+
+static void
+ctf_save_metadata_header (struct trace_write_handler *handler)
+{
+  const char metadata_fmt[] =
+  "\ntrace {\n"
+  "	major = %u;\n"
+  "	minor = %u;\n"
+  "	byte_order = %s;\n"		/* be or le */
+  "	packet.header := struct {\n"
+  "		uint32_t magic;\n"
+  "	};\n"
+  "};\n"
+  "\n"
+  "stream {\n"
+  "	packet.context := struct {\n"
+  "		uint32_t content_size;\n"
+  "		uint32_t packet_size;\n"
+  "		uint16_t tpnum;\n"
+  "	};\n"
+  "	event.header := struct {\n"
+  "		uint32_t id;\n"
+  "	};\n"
+  "};\n";
+
+  ctf_save_write_metadata (handler, "/* CTF %d.%d */\n",
+			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 8; align = 8; "
+			   "signed = false; encoding = ascii;}"
+			   " := ascii;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 8; align = 8; "
+			   "signed = false; }"
+			   " := uint8_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 16; align = 16;"
+			   "signed = false; } := uint16_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 32; align = 32;"
+			   "signed = false; } := uint32_t;\n");
+  ctf_save_write_metadata (handler,
+			   "typealias integer { size = 64; align = 64;"
+			   "signed = false; base = hex;}"
+			   " := uint64_t;\n");
+  ctf_save_write_metadata (handler, "\n");
+
+  ctf_save_write_metadata (handler, metadata_fmt,
+			   CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
+			   BYTE_ORDER == LITTLE_ENDIAN ? "le" : "be");
+  ctf_save_write_metadata (handler, "\n");
+}
+
+/* Cleanup function.  */
+
+static void
+ctf_save_cleanup (void *p)
+{
+  struct trace_write_handler *handler = p;
+
+  if (handler->metadata_fd != NULL)
+    fclose (handler->metadata_fd);
+
+  if (handler->datastream_fd != NULL)
+    fclose (handler->datastream_fd);
+}
+
+/* CTF trace writer.  */
+
+struct ctf_trace_file_writer
+{
+  struct trace_file_writer base;
+
+  struct trace_write_handler tcs;
+
+  struct cleanup *cleanup;
+};
+
+/* This is the implementation of trace_file_write_ops method
+   target_save.  */
+
+static int
+ctf_target_save (struct trace_file_writer *self,
+		 const char *dirname)
+{
+  /* Don't support save trace file to CTF format in the target.  */
+  return 0;
+}
+
+/* This is the implementation of trace_file_write_ops method
+   start.  It creates the directory DIRNAME, metadata and datastream
+   in the directory.  */
+
+static void
+ctf_start (struct trace_file_writer *self, const char *dirname)
+{
+  char *file_name;
+  struct cleanup *old_chain;
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  int i;
+
+  /* Create DIRNAME.  */
+  if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+      && errno != EEXIST)
+    error (_("Unable to open directory '%s' for saving trace data (%s)"),
+	   dirname, safe_strerror (errno));
+
+  memset (&writer->tcs, '\0', sizeof (writer->tcs));
+
+  file_name = xstrprintf ("%s/%s", dirname, CTF_METADATA_NAME);
+  old_chain = make_cleanup (xfree, file_name);
+
+  writer->tcs.metadata_fd = fopen (file_name, "w");
+  if (writer->tcs.metadata_fd == NULL)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name, safe_strerror (errno));
+  do_cleanups (old_chain);
+
+  ctf_save_metadata_header (&writer->tcs);
+
+  file_name = xstrprintf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
+  old_chain = make_cleanup (xfree, file_name);
+  writer->tcs.datastream_fd = fopen (file_name, "w");
+  if (writer->tcs.datastream_fd == NULL)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name, safe_strerror (errno));
+  do_cleanups (old_chain);
+
+  writer->cleanup = make_cleanup (ctf_save_cleanup, &writer->tcs);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_header.  Write the types of events on trace variable and
+   frame.  */
+
+static void
+ctf_write_header (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"memory\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tuint64_t address;\n"
+			   "\t\tuint16_t length;\n"
+			   "\t\tuint8_t contents[length];\n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_MEMORY);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"tsv\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tuint64_t val;\n"
+			   "\t\tuint32_t num;\n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_TSV);
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"frame\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t};\n"
+			   "};\n", CTF_EVENT_ID_FRAME);
+
+  gdb_assert (writer->tcs.content_size == 0);
+  gdb_assert (writer->tcs.packet_start == 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_regblock_type.  Write the type of register event in
+   metadata.  */
+
+static void
+ctf_write_regblock_type (struct trace_file_writer *self, int size)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  ctf_save_write_metadata (&writer->tcs, "\n");
+
+  ctf_save_write_metadata (&writer->tcs,
+			   "event {\n\tname = \"register\";\n\tid = %u;\n"
+			   "\tfields := struct { \n"
+			   "\t\tascii contents[%d];\n"
+			   "\t};\n"
+			   "};\n",
+			   CTF_EVENT_ID_REGISTER, size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_status.  */
+
+static void
+ctf_write_status (struct trace_file_writer *self,
+		  struct trace_status *ts)
+{
+  /* It is not supported yet to write trace status into CTF trace
+     data.  */
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_uploaded_tsv.  */
+
+static void
+ctf_write_uploaded_tsv (struct trace_file_writer *self,
+			struct uploaded_tsv *tsv)
+{
+  /* It is not supported yet to write uploaded trace variables
+     into CTF trace data.  */
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_uploaded_tp.  */
+
+static void
+ctf_write_uploaded_tp (struct trace_file_writer *self,
+		       struct uploaded_tp *tp)
+{
+  /* It is not supported yet to write uploaded tracepoints
+     into CTF trace data.  */
+}
+
+/* This is the implementation of trace_file_write_ops method
+   write_definition_end.  */
+
+static void
+ctf_write_definition_end (struct trace_file_writer *self)
+{
+  /* Nothing to do for CTF.  */
+}
+
+/* The minimal file size of data stream.  It is required by
+   babeltrace.  */
+
+#define CTF_FILE_MIN_SIZE		4096
+
+/* This is the implementation of trace_file_write_ops method
+   end.  */
+
+static void
+ctf_end (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer = (struct ctf_trace_file_writer *) self;
+
+  gdb_assert (writer->tcs.content_size == 0);
+  /* The babeltrace requires or assumes that the size of datastream
+     file is greater than 4096 bytes.  If we don't generate enough
+     packets and events, create a fake packet which has zero event,
+      to use up the space.  */
+  if (writer->tcs.packet_start < CTF_FILE_MIN_SIZE)
+    {
+      uint32_t u32;
+
+      /* magic.  */
+      u32 = CTF_MAGIC;
+      ctf_save_write_uint32 (&writer->tcs, u32);
+
+      /* content_size.  */
+      u32 = 0;
+      ctf_save_write_uint32 (&writer->tcs, u32);
+
+      /* packet_size.  */
+      u32 = 12;
+      if (writer->tcs.packet_start + u32 < CTF_FILE_MIN_SIZE)
+	u32 = CTF_FILE_MIN_SIZE - writer->tcs.packet_start;
+
+      u32 *= TARGET_CHAR_BIT;
+      ctf_save_write_uint32 (&writer->tcs, u32);
+
+      /* tpnum.  */
+      u32 = 0;
+      ctf_save_write (&writer->tcs, (gdb_byte *) &u32, 2);
+
+      /* Enlarge the file to CTF_FILE_MIN_SIZE is it is still less
+	 than that.  */
+      if (CTF_FILE_MIN_SIZE
+	  > (writer->tcs.packet_start + writer->tcs.content_size))
+	{
+	  gdb_byte b = 0;
+
+	  /* Fake the content size to avoid assertion failure in
+	     ctf_save_fseek.  */
+	  writer->tcs.content_size = (CTF_FILE_MIN_SIZE
+				      - 1 - writer->tcs.packet_start);
+	  ctf_save_fseek (&writer->tcs, CTF_FILE_MIN_SIZE - 1,
+			  SEEK_SET);
+	  ctf_save_write (&writer->tcs, &b, 1);
+	}
+    }
+
+  do_cleanups (writer->cleanup);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   start.  */
+
+static void
+ctf_write_frame_start (struct trace_file_writer *self, uint16_t tpnum)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_FRAME;
+  uint32_t u32;
+
+  /* Step 1: Write packet context.  */
+  /* magic.  */
+  u32 = CTF_MAGIC;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+  /* content_size and packet_size..  We still don't know the value,
+     write it later.  */
+  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+  ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+  /* Tracepoint number.  */
+  ctf_save_write (&writer->tcs, (gdb_byte *) &tpnum, 2);
+
+  /* Step 2: Write event "frame".  */
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_r_block.  */
+
+static void
+ctf_write_frame_r_block (struct trace_file_writer *self,
+			 gdb_byte *buf, int32_t size)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_REGISTER;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  /* array contents.  */
+  ctf_save_align_write (&writer->tcs, buf, size, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_m_block_header.  */
+
+static void
+ctf_write_frame_m_block_header (struct trace_file_writer *self,
+				uint64_t addr, uint16_t length)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t event_id = CTF_EVENT_ID_MEMORY;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &event_id, 4, 4);
+
+  /* Address.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &addr, 8, 8);
+
+  /* Length.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &length, 2, 2);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_m_block_memory.  */
+
+static void
+ctf_write_frame_m_block_memory (struct trace_file_writer *self,
+				gdb_byte *buf, uint16_t length)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+
+  /* Contents.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) buf, length, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_v_block.  */
+
+static void
+ctf_write_frame_v_block (struct trace_file_writer *self,
+			 int32_t num, uint64_t val)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t id = CTF_EVENT_ID_TSV;
+
+  /* Event Id.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+  /* val.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &val, 8, 8);
+  /* num.  */
+  ctf_save_align_write (&writer->tcs, (gdb_byte *) &num, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   end.  */
+
+static void
+ctf_write_frame_end (struct trace_file_writer *self)
+{
+  struct ctf_trace_file_writer *writer
+    = (struct ctf_trace_file_writer *) self;
+  uint32_t u32;
+  uint32_t t;
+
+  /* Write the content size to packet header.  */
+  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + 4,
+		  SEEK_SET);
+  u32 = writer->tcs.content_size * TARGET_CHAR_BIT;
+
+  t = writer->tcs.content_size;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+
+  /* Write the packet size.  */
+  u32 += 4 * TARGET_CHAR_BIT;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+
+  writer->tcs.content_size = t;
+
+  /* Write zero at the end of the packet.  */
+  ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + t,
+		  SEEK_SET);
+  u32 = 0;
+  ctf_save_write_uint32 (&writer->tcs, u32);
+  writer->tcs.content_size = t;
+
+  ctf_save_next_packet (&writer->tcs);
+}
+
+/* Operations to write various types of trace frames into CTF
+   format.  */
+
+static const struct trace_frame_write_ops ctf_write_frame_ops =
+{
+  ctf_write_frame_start,
+  ctf_write_frame_r_block,
+  ctf_write_frame_m_block_header,
+  ctf_write_frame_m_block_memory,
+  ctf_write_frame_v_block,
+  ctf_write_frame_end,
+};
+
+/* Operations to write trace buffers into CTF format.  */
+
+static const struct trace_file_write_ops ctf_write_ops =
+{
+  ctf_target_save,
+  ctf_start,
+  ctf_write_header,
+  ctf_write_regblock_type,
+  ctf_write_status,
+  ctf_write_uploaded_tsv,
+  ctf_write_uploaded_tp,
+  ctf_write_definition_end,
+  NULL,
+  &ctf_write_frame_ops,
+  ctf_end,
+};
+
+/* Return a trace writer for CTF format.  */
+
+struct trace_file_writer *
+ctf_trace_file_writer_new (void)
+{
+  struct ctf_trace_file_writer *writer
+    = xmalloc (sizeof (struct ctf_trace_file_writer));
+
+  writer->base.ops = &ctf_write_ops;
+
+  return (struct trace_file_writer *) writer;
+}
diff --git a/gdb/ctf.h b/gdb/ctf.h
new file mode 100644
index 0000000..6a61cf3
--- /dev/null
+++ b/gdb/ctf.h
@@ -0,0 +1,25 @@
+/* CTF format support.
+
+   Copyright (C) 2012-2013 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/>.  */
+
+#ifndef CTF_H
+#define CTF_H
+
+extern struct trace_file_writer *ctf_trace_file_writer_new (void);
+
+#endif
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 206b626..5ee5cfa 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -49,6 +49,7 @@
 #include "osdata.h"
 #include "splay-tree.h"
 #include "tracepoint.h"
+#include "ctf.h"
 #include "ada-lang.h"
 #include "linespec.h"
 
@@ -2477,25 +2478,45 @@ void
 mi_cmd_trace_save (char *command, char **argv, int argc)
 {
   int target_saves = 0;
+  int generate_ctf = 0;
   char *filename;
+  int oind = 0;
+  char *oarg;
 
-  if (argc != 1 && argc != 2)
-    error (_("Usage: -trace-save [-r] filename"));
-
-  if (argc == 2)
+  enum opt
+  {
+    TARGET_SAVE_OPT, CTF_OPT
+  };
+  static const struct mi_opt opts[] =
     {
-      filename = argv[1];
-      if (strcmp (argv[0], "-r") == 0)
-	target_saves = 1;
-      else
-	error (_("Invalid option: %s"), argv[0]);
-    }
-  else
+      {"r", TARGET_SAVE_OPT, 0},
+      {"ctf", CTF_OPT, 0},
+      { 0, 0, 0 }
+    };
+
+  while (1)
     {
-      filename = argv[0];
+      int opt = mi_getopt ("-trace-save", argc, argv, opts,
+			   &oind, &oarg);
+
+      if (opt < 0)
+	break;
+      switch ((enum opt) opt)
+	{
+	case TARGET_SAVE_OPT:
+	  target_saves = 1;
+	  break;
+	case CTF_OPT:
+	  generate_ctf = 1;
+	  break;
+	}
     }
+  filename = argv[oind];
 
-  trace_save_tfile (filename, target_saves);
+  if (generate_ctf)
+    trace_save_ctf (filename, target_saves);
+  else
+    trace_save_tfile (filename, target_saves);
 }
 
 void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index e3a42e2..de59102 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -53,6 +53,7 @@
 #include "exceptions.h"
 #include "cli/cli-utils.h"
 #include "probe.h"
+#include "ctf.h"
 
 /* readline include files */
 #include "readline/readline.h"
@@ -3521,6 +3522,7 @@ trace_save_command (char *args, int from_tty)
   char **argv;
   char *filename = NULL;
   struct cleanup *back_to;
+  int generate_ctf = 0;
   struct trace_file_writer *writer = NULL;
 
   if (args == NULL)
@@ -3533,6 +3535,8 @@ trace_save_command (char *args, int from_tty)
     {
       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
@@ -3542,14 +3546,18 @@ trace_save_command (char *args, int from_tty)
   if (!filename)
     error_no_arg (_("file in which to save trace data"));
 
-  writer = tfile_trace_file_writer_new ();
+  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 file '%s'.\n"), filename);
+    printf_filtered (_("Trace data saved to %s '%s'.\n"),
+		     generate_ctf ? "directory" : "file", filename);
 
   do_cleanups (back_to);
 }
@@ -3568,6 +3576,21 @@ trace_save_tfile (const char *filename, int 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.  */
 
@@ -5623,6 +5646,7 @@ _initialize_tracepoint (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/tracepoint.h b/gdb/tracepoint.h
index d6664e7..ab11574 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -384,6 +384,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
 
 extern void trace_save_tfile (const char *filename,
 			      int target_does_save);
+extern void trace_save_ctf (const char *dirname,
+			    int target_does_save);
 
 extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
 
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]