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 2/5] 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-02-27  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        |  680 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ctf.h        |   24 ++
 gdb/mi/mi-main.c |   11 +-
 gdb/tracepoint.c |   36 +++-
 gdb/tracepoint.h |    2 +
 6 files changed, 750 insertions(+), 9 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..c4809d8
--- /dev/null
+++ b/gdb/ctf.c
@@ -0,0 +1,680 @@
+/* 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 'R' and 'V' are saved in event "register" and "tsv"
+   respectively.  They are fixed in length, so there is only one event
+   type for each of them.
+   4.3: The block 'M' is variable on length.  Each event type is
+   defined for a specific length of block 'M', so there are multiple
+   event types "memory_$LENGTH" in metadata file.  $LENGTH is a
+   decimal.
+   4.4: 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_FRAME 2
+#define CTF_EVENT_ID_LAST 3
+
+/* Handler of writing trace of CTF format.  */
+
+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 contents in BUF to file FD.  SIZE is the size of BUF.  */
+
+static void
+ctf_save_fwrite (FILE *fd, const gdb_byte *buf, size_t size)
+{
+  if (fwrite (buf, size, 1, fd) != 1)
+    error (_("Unable to write file for saving trace data (%s)"),
+	   safe_strerror (errno));
+}
+
+static void
+ctf_save_fwrite_format_1 (FILE *fd, const char *format, va_list args)
+{
+  char *linebuffer;
+  struct cleanup *old_cleanups;
+
+  linebuffer = xstrvprintf (format, args);
+  old_cleanups = make_cleanup (xfree, linebuffer);
+  ctf_save_fwrite (fd, linebuffer, strlen (linebuffer));
+  do_cleanups (old_cleanups);
+}
+
+/* Write data in FORMAT to FD.  */
+
+static void
+ctf_save_fwrite_format (FILE *fd, const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
+  ctf_save_fwrite_format_1 (fd, format, args);
+  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)
+{
+  ctf_save_fwrite (handler->datastream_fd, buf, size);
+
+  handler->content_size += size;
+
+  return 0;
+}
+
+/* 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)
+{
+  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;
+}
+
+/* Move to next 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_fwrite_format (handler->metadata_fd, "/* CTF %d.%d */\n",
+			  CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
+  ctf_save_fwrite_format (handler->metadata_fd,
+			  "typealias integer { size = 8; align = 8; "
+			  "signed = false; encoding = ascii; }"
+			  " := uint8_t;\n");
+  ctf_save_fwrite_format (handler->metadata_fd,
+			  "typealias integer { size = 16; align = 16;"
+			  "signed = false; } := uint16_t;\n");
+  ctf_save_fwrite_format (handler->metadata_fd,
+			  "typealias integer { size = 32; align = 32;"
+			  "signed = false; } := uint32_t;\n");
+  ctf_save_fwrite_format (handler->metadata_fd,
+			  "typealias integer { size = 64; align = 64;"
+			  "signed = false; base = hex;}"
+			  " := uint64_t;\n");
+  ctf_save_fwrite_format (handler->metadata_fd, "\n");
+
+  ctf_save_fwrite_format (handler->metadata_fd, metadata_fmt,
+			  CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
+			  BYTE_ORDER == LITTLE_ENDIAN ? "le" : "be");
+  ctf_save_fwrite_format (handler->metadata_fd, "\n");
+}
+
+/* Cleanup function.  */
+
+static void
+ctf_save_cleanup (void *p)
+{
+  struct trace_write_handler *handler = p;
+
+  if (handler->metadata_fd)
+    fclose (handler->metadata_fd);
+
+  if (handler->datastream_fd)
+    fclose (handler->datastream_fd);
+}
+
+/* Data specific to CTF trace writer.  */
+
+struct ctf_writer_data
+{
+  struct trace_write_handler tcs;
+
+  /* Event id 0 1 and 2 are reserved:
+      - 0 for register block
+      - 1 for trace variable block.
+      - 2 for frame start marker.  */
+  unsigned int event_id;
+
+  /* The value of element of index I is the size of 'M' block, whose
+     event id is I.  */
+  unsigned int *m_block_size;
+  /* Length of M_BLOCK_SIZE.  */
+  unsigned int length;
+
+  struct cleanup *cleanup;
+};
+
+/* This is the implementation of trace_file_write_ops method
+   can_target_save.  */
+
+static int
+ctf_can_target_save (struct trace_file_writer *self,
+		     const char *filename)
+{
+  /* 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_writer_data *data = self->data;
+  int i;
+
+  data->event_id = CTF_EVENT_ID_LAST;
+  data->length = 8;
+  data->m_block_size = xmalloc (data->length * sizeof (int));
+  memset (data->m_block_size, 0, data->length * sizeof (int));
+
+  /* Create DIRNAME.  */
+  file_name = alloca (strlen (dirname) + 1
+		      + strlen (CTF_DATASTREAM_NAME) + 1);
+  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 (&data->tcs, '\0', sizeof (data->tcs));
+
+  file_name = xstrprintf ("%s/%s", dirname, CTF_METADATA_NAME);
+  old_chain = make_cleanup (xfree, file_name);
+
+  data->tcs.metadata_fd = fopen (file_name, "w");
+  if (!data->tcs.metadata_fd)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name, safe_strerror (errno));
+  do_cleanups (old_chain);
+
+  ctf_save_metadata_header (&data->tcs);
+
+  file_name = xstrprintf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
+  old_chain = make_cleanup (xfree, file_name);
+  data->tcs.datastream_fd = fopen (file_name, "w");
+  if (!data->tcs.datastream_fd)
+    error (_("Unable to open file '%s' for saving trace data (%s)"),
+	   file_name, safe_strerror (errno));
+  do_cleanups (old_chain);
+
+  data->cleanup = make_cleanup (ctf_save_cleanup, &data->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_writer_data *data = self->data;
+
+  ctf_save_fwrite_format (data->tcs.metadata_fd, "\n");
+  ctf_save_fwrite_format (data->tcs.metadata_fd,
+			  "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_fwrite_format (data->tcs.metadata_fd, "\n");
+  ctf_save_fwrite_format (data->tcs.metadata_fd,
+			  "event {\n\tname = \"frame\";\n\tid = %u;\n"
+			  "\tfields := struct { \n"
+			  "\t};\n"
+			  "};\n", CTF_EVENT_ID_FRAME);
+
+  gdb_assert (data->tcs.content_size == 0);
+  gdb_assert (data->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_writer_data *data = self->data;
+
+  ctf_save_fwrite_format (data->tcs.metadata_fd, "\n");
+
+  ctf_save_fwrite_format (data->tcs.metadata_fd,
+			  "event {\n\tname = \"register\";\n\tid = %u;\n"
+			  "\tfields := struct { \n"
+			  "\t\tuint8_t 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_writer_data *data = self->data;
+
+  gdb_assert (data->tcs.content_size == 0);
+  /* The babeltrace requires or assumes that the datastream file
+     is larger than 4096.  If we don't generate enough packets and
+     events, create a fake packet which has zero event, to use up
+     the space.  */
+  if (data->tcs.packet_start < CTF_FILE_MIN_SIZE)
+    {
+      uint32_t u32;
+
+      /* magic.  */
+      u32 = CTF_MAGIC;
+      ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+
+      /* content_size.  */
+      u32 = 0;
+      ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+
+      /* packet_size.  */
+      u32 = 12;
+      if (data->tcs.packet_start + u32 < 4096)
+	u32 = 4096 - data->tcs.packet_start;
+
+      u32 *= TARGET_CHAR_BIT;
+      ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+
+      /* tpnum.  */
+      u32 = 0;
+      ctf_save_write (&data->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
+	  > (data->tcs.packet_start + data->tcs.content_size))
+	{
+	  gdb_byte b = 0;
+
+	  ctf_save_fseek (&data->tcs, CTF_FILE_MIN_SIZE - 1,
+			  SEEK_SET);
+	  ctf_save_write (&data->tcs, &b, 1);
+	}
+    }
+
+  do_cleanups (data->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_writer_data *data = self->data;
+  int two = 2;
+  uint32_t u32;
+
+  /* Step 1: Write packet context.  */
+  /* magic.  */
+  u32 = CTF_MAGIC;
+  ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+  /* content_size and packet_size..  We still don't know the value,
+     write it later.  */
+  ctf_save_fseek (&data->tcs, 4, SEEK_CUR);
+  ctf_save_fseek (&data->tcs, 4, SEEK_CUR);
+  /* Tracepoint number.  */
+  ctf_save_write (&data->tcs, (gdb_byte *) &tpnum, 2);
+
+  /* Step 2: Write event "frame".  */
+  /* Event Id.  */
+  ctf_save_align_write (&data->tcs, (void *) &two, 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, int size)
+{
+  struct ctf_writer_data *data = self->data;
+  int zero = 0;
+
+  /* Event Id.  */
+  ctf_save_align_write (&data->tcs, (void *) &zero, 4, 4);
+
+  /* array contents.  */
+  ctf_save_align_write (&data->tcs, buf, size, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+   write_m_block.  */
+
+static void
+ctf_write_frame_m_block (struct trace_file_writer *self,
+			 ULONGEST addr, gdb_byte *buf,
+			 uint16_t length)
+{
+  struct ctf_writer_data *data = self->data;
+  int i;
+  int event_id = 0;
+
+  /* Check we've seen the 'M' block of length LENGTH before.  */
+  for (i = 0; i < data->length; i++)
+    {
+      if (length == data->m_block_size[i])
+	{
+	  event_id = i + CTF_EVENT_ID_LAST;
+	  break;
+	}
+    }
+
+  /* Record it.  */
+  if (event_id == 0)
+    {
+      event_id = data->event_id++;
+
+      if (event_id - CTF_EVENT_ID_LAST >= data->length)
+	{
+	  data->m_block_size
+	    = xrealloc (data->m_block_size,
+			sizeof (int) * data->length * 2);
+	  memset (&data->m_block_size[data->length], 0,
+		  data->length * sizeof (int));
+	  data->length *= 2;
+	}
+
+      data->m_block_size[event_id - CTF_EVENT_ID_LAST] = length;
+
+      /* Save the type of 'M' block into metadata.  */
+      ctf_save_fwrite_format (data->tcs.metadata_fd, "\n");
+      ctf_save_fwrite_format (data->tcs.metadata_fd,
+			      "event {\n\tname = \"memory_%d\";\n\tid = %u;\n"
+			      "\tfields := struct { \n"
+			      "\t\tuint64_t address;\n"
+			      "\t\tuint16_t length;\n"
+			      "\t\tuint8_t contents[%d];\n"
+			      "\t};\n"
+			      "};\n",
+			      length, event_id, length);
+    }
+
+  /* Save 'M' block into datastream.  */
+  /* Event Id.  */
+  ctf_save_align_write (&data->tcs, (void *) &event_id, 4, 4);
+
+  /* Address.  */
+  ctf_save_align_write (&data->tcs, (void *) &addr, 8, 8);
+
+  /* Length.  */
+  ctf_save_align_write (&data->tcs, (void *) &length, 2, 2);
+
+  /* Contents.  */
+  ctf_save_align_write (&data->tcs, (void *) 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,
+			 int num, LONGEST val)
+{
+  struct ctf_writer_data *data = self->data;
+  int one = 1;
+
+  /* Event Id.  */
+  ctf_save_align_write (&data->tcs, (void *) &one, 4, 4);
+
+  /* val.  */
+  ctf_save_align_write (&data->tcs, (void *) &val, 8, 8);
+  /* num.  */
+  ctf_save_align_write (&data->tcs, (void *) &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_writer_data *data = self->data;
+  uint32_t u32;
+  uint32_t t;
+
+  /* Write the content size to packet header.  */
+  ctf_save_fseek (&data->tcs, data->tcs.packet_start + 4, SEEK_SET);
+  u32 = data->tcs.content_size * TARGET_CHAR_BIT;
+
+  t = data->tcs.content_size;
+  ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+
+  /* Write the packet size.  */
+  u32 += 4 * TARGET_CHAR_BIT;
+  ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+
+  data->tcs.content_size = t;
+
+  /* Write zero at the end of the packet.  */
+  ctf_save_fseek (&data->tcs, data->tcs.packet_start + t, SEEK_SET);
+  u32 = 0;
+  ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4);
+  data->tcs.content_size = t;
+
+  ctf_save_next_packet (&data->tcs);
+}
+
+/* Operations to write various types of trace frames into CTF
+   format.  */
+
+static struct trace_frame_write_ops ctf_write_frame_ops =
+{
+  ctf_write_frame_start,
+  ctf_write_frame_r_block,
+  ctf_write_frame_m_block,
+  ctf_write_frame_v_block,
+  ctf_write_frame_end,
+};
+
+/* Operations to write trace buffers into CTF format.  */
+
+static struct trace_file_write_ops ctf_write_ops =
+{
+  ctf_can_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 (void)
+{
+  struct trace_file_writer *writer
+    = xmalloc (sizeof (struct trace_file_writer));
+
+  writer->ops = &ctf_write_ops;
+  writer->data = xmalloc (sizeof (struct ctf_writer_data));
+
+  return writer;
+}
diff --git a/gdb/ctf.h b/gdb/ctf.h
new file mode 100644
index 0000000..d2fccaf
--- /dev/null
+++ b/gdb/ctf.h
@@ -0,0 +1,24 @@
+/* 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 (void);
+#endif
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 206b626..a950b34 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,16 +2478,19 @@ void
 mi_cmd_trace_save (char *command, char **argv, int argc)
 {
   int target_saves = 0;
+  int generate_ctf = 0;
   char *filename;
 
   if (argc != 1 && argc != 2)
-    error (_("Usage: -trace-save [-r] filename"));
+    error (_("Usage: -trace-save [-r] [-ctf] filename"));
 
   if (argc == 2)
     {
       filename = argv[1];
       if (strcmp (argv[0], "-r") == 0)
 	target_saves = 1;
+      if (strcmp (argv[0], "-ctf") == 0)
+	generate_ctf = 1;
       else
 	error (_("Invalid option: %s"), argv[0]);
     }
@@ -2495,7 +2499,10 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
       filename = argv[0];
     }
 
-  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 43bd80f..7434df7 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"
@@ -3451,6 +3452,7 @@ static void
 trace_save_command (char *args, int from_tty)
 {
   int target_does_save = 0;
+  int generate_ctf = 0;
   char **argv;
   char *filename = NULL;
   struct cleanup *back_to;
@@ -3466,6 +3468,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
@@ -3475,15 +3479,22 @@ trace_save_command (char *args, int from_tty)
   if (!filename)
     error_no_arg (_("file in which to save trace data"));
 
-  writer = xmalloc (sizeof (struct trace_file_writer));
-  writer->ops = &tfile_write_ops;
-  writer->data = xmalloc (sizeof (struct tfile_writer_data));
+  if (generate_ctf)
+    writer = ctf_trace_file_writer ();
+  else
+    {
+      writer = xmalloc (sizeof (struct trace_file_writer));
+      writer->ops = &tfile_write_ops;
+      writer->data = xmalloc (sizeof (struct tfile_writer_data));
+    }
+
   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);
 }
@@ -3499,6 +3510,22 @@ trace_save_tfile (const char *filename, int target_does_save)
   writer->ops = &tfile_write_ops;
   writer->data = xmalloc (sizeof (struct tfile_writer_data));
 
+  trace_save (filename, writer, target_does_save);
+
+  back_to = make_cleanup (trace_file_writer_xfree, writer);
+  do_cleanups (back_to);
+}
+
+/* Save the trace data to dir DIRENAME 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 ();
+  trace_save (dirname, writer, target_does_save);
   back_to = make_cleanup (trace_file_writer_xfree, writer);
   do_cleanups (back_to);
 }
@@ -5553,6 +5580,7 @@ _initialize_tracepoint (void)
   add_com ("tsave", class_trace, trace_save_command, _("\
 Save the trace data to a file.\n\
 Use the '-r' option to direct the target to save directly to the file,\n\
+Use the '-ctf' option to save the data to CTF format,\n\
 using its own filesystem."));
 
   c = add_com ("tvariable", class_trace, trace_variable_command,_("\
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 1db6b69..44ff2de 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -372,6 +372,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]