aboutsummaryrefslogtreecommitdiff
path: root/gdb/tracefile-tfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/tracefile-tfile.c')
-rw-r--r--gdb/tracefile-tfile.c327
1 files changed, 327 insertions, 0 deletions
diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
new file mode 100644
index 0000000..8a53e9d
--- /dev/null
+++ b/gdb/tracefile-tfile.c
@@ -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;
+}