/* Trace file TFILE format support in GDB.
- Copyright (C) 1997-2017 Free Software Foundation, Inc.
+ Copyright (C) 1997-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "tracefile.h"
#include "readline/tilde.h"
-#include "filestuff.h"
-#include "rsp-low.h" /* bin2hex */
+#include "gdbsupport/filestuff.h"
+#include "gdbsupport/rsp-low.h" /* bin2hex */
#include "regcache.h"
#include "inferior.h"
#include "gdbthread.h"
#include "remote.h"
#include "xml-tdesc.h"
#include "target-descriptions.h"
-#include "buffer.h"
+#include "gdbsupport/buffer.h"
+#include "gdbsupport/pathstuff.h"
#include <algorithm>
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
+/* The tfile target. */
+
+static const target_info tfile_target_info = {
+ "tfile",
+ N_("Local trace dump file"),
+ N_("Use a trace file as a target.\n\
+Specify the filename of the trace file.")
+};
+
+class tfile_target final : public tracefile_target
+{
+ public:
+ const target_info &info () const override
+ { return tfile_target_info; }
+
+ void close () override;
+ void fetch_registers (struct regcache *, int) override;
+ enum target_xfer_status xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len) override;
+ void files_info () override;
+ int trace_find (enum trace_find_type type, int num,
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override;
+ bool get_trace_state_variable_value (int tsv, LONGEST *val) override;
+ traceframe_info_up traceframe_info () override;
+
+ void get_tracepoint_status (struct breakpoint *tp,
+ struct uploaded_tp *utp) override;
+};
+
/* TFILE trace writer. */
struct tfile_trace_file_writer
= (struct tfile_trace_file_writer *) self;
writer->pathname = tilde_expand (filename);
- writer->fp = gdb_fopen_cloexec (writer->pathname, "wb");
+ writer->fp = gdb_fopen_cloexec (writer->pathname, "wb").release ();
if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
writer->pathname, safe_strerror (errno));
{
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",
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);
+ ":X%x,%s", (unsigned int) strlen (utp->cond.get ()) / 2,
+ utp->cond.get ());
fprintf (writer->fp, "\n");
- for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
+ for (const auto &act : utp->actions)
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)
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
+ for (const auto &act : utp->step_actions)
fprintf (writer->fp, "tp S%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ());
if (utp->at_string)
{
encode_source_string (utp->number, utp->addr,
- "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ "at", utp->at_string.get (),
+ 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,
+ "cond", utp->cond_string.get (),
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)
+ for (const auto &act : utp->cmd_strings)
{
- encode_source_string (utp->number, utp->addr, "cmd", act,
+ encode_source_string (utp->number, utp->addr, "cmd", act.get (),
buf, MAX_TRACE_UPLOAD);
fprintf (writer->fp, "tp Z%s\n", buf);
}
= (struct tfile_trace_file_writer *) self;
gdb::optional<std::string> tdesc
- = target_fetch_description_xml (¤t_target);
+ = target_fetch_description_xml (current_top_target ());
if (!tdesc)
return;
/* target tfile command */
-static struct target_ops tfile_ops;
-
-/* Fill in tfile_ops with its defined operations and properties. */
+static tfile_target tfile_ops;
#define TRACE_HEADER_SIZE 8
error (_("Premature end of file while reading trace file"));
}
+/* Open the tfile target. */
+
static void
-tfile_open (const char *arg, int from_tty)
+tfile_target_open (const char *arg, int from_tty)
{
- char *temp;
- struct cleanup *old_chain;
int flags;
int scratch_chan;
char header[TRACE_HEADER_SIZE];
struct trace_status *ts;
struct uploaded_tp *uploaded_tps = NULL;
struct uploaded_tsv *uploaded_tsvs = NULL;
- char *filename;
target_preopen (from_tty);
if (!arg)
error (_("No trace file specified."));
- filename = tilde_expand (arg);
- if (!IS_ABSOLUTE_PATH(filename))
- {
- temp = concat (current_directory, "/", filename, (char *) NULL);
- xfree (filename);
- filename = temp;
- }
-
- old_chain = make_cleanup (xfree, filename);
+ gdb::unique_xmalloc_ptr<char> filename (tilde_expand (arg));
+ if (!IS_ABSOLUTE_PATH (filename.get ()))
+ filename = gdb_abspath (filename.get ());
flags = O_BINARY | O_LARGEFILE;
flags |= O_RDONLY;
- scratch_chan = gdb_open_cloexec (filename, flags, 0);
+ scratch_chan = gdb_open_cloexec (filename.get (), flags, 0);
if (scratch_chan < 0)
- perror_with_name (filename);
+ perror_with_name (filename.get ());
/* Looks semi-reasonable. Toss the old trace file and work on the new. */
- discard_cleanups (old_chain); /* Don't free filename any more. */
unpush_target (&tfile_ops);
- trace_filename = xstrdup (filename);
+ trace_filename = filename.release ();
trace_fd = scratch_chan;
/* Make sure this is clear. */
ts->disconnected_tracing = 0;
ts->circular_buffer = 0;
- TRY
+ try
{
/* Read through a section of newline-terminated lines that
define things like tracepoints. */
if (trace_regblock_size == 0)
error (_("No register block size recorded in trace file"));
}
- CATCH (ex, RETURN_MASK_ALL)
+ catch (const gdb_exception &ex)
{
/* Remove the partially set up target. */
unpush_target (&tfile_ops);
- throw_exception (ex);
+ throw;
}
- END_CATCH
inferior_appeared (current_inferior (), TFILE_PID);
- inferior_ptid = pid_to_ptid (TFILE_PID);
- add_thread_silent (inferior_ptid);
+
+ thread_info *thr = add_thread_silent (&tfile_ops, ptid_t (TFILE_PID));
+ switch_to_thread (thr);
if (ts->traceframe_count <= 0)
warning (_("No traceframes present in this file."));
/* Close the trace file and generally clean up. */
-static void
-tfile_close (struct target_ops *self)
+void
+tfile_target::close ()
{
- int pid;
-
- if (trace_fd < 0)
- return;
+ gdb_assert (trace_fd != -1);
- pid = ptid_get_pid (inferior_ptid);
- inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */
- exit_inferior_silent (pid);
+ switch_to_no_thread (); /* Avoid confusion from thread stuff. */
+ exit_inferior_silent (current_inferior ());
- close (trace_fd);
+ ::close (trace_fd);
trace_fd = -1;
xfree (trace_filename);
trace_filename = NULL;
trace_reset_local_state ();
}
-static void
-tfile_files_info (struct target_ops *t)
+void
+tfile_target::files_info ()
{
printf_filtered ("\t`%s'\n", trace_filename);
}
-static void
-tfile_get_tracepoint_status (struct target_ops *self,
- struct breakpoint *tp, struct uploaded_tp *utp)
+void
+tfile_target::get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp)
{
/* Other bits of trace status were collected as part of opening the
trace files, so nothing to do here. */
both the traceframe and tracepoint number, otherwise -1 for
each. */
-static int
-tfile_trace_find (struct target_ops *self, enum trace_find_type type, int num,
- CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+int
+tfile_target::trace_find (enum trace_find_type type, int num,
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
{
short tpnum;
int tfnum = 0, found = 0;
/* Look for a block of saved registers in the traceframe, and get the
requested register from it. */
-static void
-tfile_fetch_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
+void
+tfile_target::fetch_registers (struct regcache *regcache, int regno)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
int offset, regn, regsize, dummy;
/* An uninitialized reg size says we're not going to be
for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
{
- if (!remote_register_number_and_offset (get_regcache_arch (regcache),
+ if (!remote_register_number_and_offset (regcache->arch (),
regn, &dummy, &offset))
continue;
/* Make sure we stay within block bounds. */
if (offset + regsize > trace_regblock_size)
break;
- if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ if (regcache->get_register_status (regn) == REG_UNKNOWN)
{
if (regno == regn)
{
- regcache_raw_supply (regcache, regno, regs + offset);
+ regcache->raw_supply (regno, regs + offset);
break;
}
else if (regno == -1)
{
- regcache_raw_supply (regcache, regn, regs + offset);
+ regcache->raw_supply (regn, regs + offset);
}
}
}
}
static enum target_xfer_status
-tfile_xfer_partial_features (struct target_ops *ops, const char *annex,
+tfile_xfer_partial_features (const char *annex,
gdb_byte *readbuf, const gdb_byte *writebuf,
ULONGEST offset, ULONGEST len,
ULONGEST *xfered_len)
return TARGET_XFER_OK;
}
-static enum target_xfer_status
-tfile_xfer_partial (struct target_ops *ops, enum target_object object,
- const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
- ULONGEST *xfered_len)
+enum target_xfer_status
+tfile_target::xfer_partial (enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len)
{
/* We're only doing regular memory and tdesc for now. */
if (object == TARGET_OBJECT_AVAILABLE_FEATURES)
- return tfile_xfer_partial_features (ops, annex, readbuf, writebuf,
+ return tfile_xfer_partial_features (annex, readbuf, writebuf,
offset, len, xfered_len);
if (object != TARGET_OBJECT_MEMORY)
return TARGET_XFER_E_IO;
/* Iterate through the blocks of a trace frame, looking for a 'V'
block with a matching tsv number. */
-static int
-tfile_get_trace_state_variable_value (struct target_ops *self,
- int tsvnum, LONGEST *val)
+bool
+tfile_target::get_trace_state_variable_value (int tsvnum, LONGEST *val)
{
int pos;
- int found = 0;
+ bool found = false;
/* Iterate over blocks in current frame and find the last 'V'
block in which tsv number is TSVNUM. In one trace frame, there
*val = extract_signed_integer ((gdb_byte *) val, 8,
gdbarch_byte_order
(target_gdbarch ()));
- found = 1;
+ found = true;
}
pos += (4 + 8);
}
{
case 'M':
{
- struct mem_range *r;
ULONGEST maddr;
unsigned short mlen;
2, gdbarch_byte_order
(target_gdbarch ()));
- r = VEC_safe_push (mem_range_s, info->memory, NULL);
-
- r->start = maddr;
- r->length = mlen;
+ info->memory.emplace_back (maddr, mlen);
break;
}
case 'V':
int vnum;
tfile_read ((gdb_byte *) &vnum, 4);
- VEC_safe_push (int, info->tvars, vnum);
+ info->tvars.push_back (vnum);
}
case 'R':
case 'S':
return 0;
}
-static struct traceframe_info *
-tfile_traceframe_info (struct target_ops *self)
+traceframe_info_up
+tfile_target::traceframe_info ()
{
- struct traceframe_info *info = XCNEW (struct traceframe_info);
+ traceframe_info_up info (new struct traceframe_info);
+
+ traceframe_walk_blocks (build_traceframe_info, 0, info.get ());
- traceframe_walk_blocks (build_traceframe_info, 0, info);
return info;
}
buffer_grow_str (&trace_tdesc, "\n");
}
-static void
-init_tfile_ops (void)
-{
- init_tracefile_ops (&tfile_ops);
-
- tfile_ops.to_shortname = "tfile";
- tfile_ops.to_longname = "Local trace dump file";
- tfile_ops.to_doc
- = "Use a trace file as a target. Specify the filename of the trace file.";
- tfile_ops.to_open = tfile_open;
- tfile_ops.to_close = tfile_close;
- tfile_ops.to_fetch_registers = tfile_fetch_registers;
- tfile_ops.to_xfer_partial = tfile_xfer_partial;
- tfile_ops.to_files_info = tfile_files_info;
- tfile_ops.to_get_tracepoint_status = tfile_get_tracepoint_status;
- tfile_ops.to_trace_find = tfile_trace_find;
- tfile_ops.to_get_trace_state_variable_value
- = tfile_get_trace_state_variable_value;
- tfile_ops.to_traceframe_info = tfile_traceframe_info;
-}
-
-extern initialize_file_ftype _initialize_tracefile_tfile;
-
+void _initialize_tracefile_tfile ();
void
-_initialize_tracefile_tfile (void)
+_initialize_tracefile_tfile ()
{
- init_tfile_ops ();
-
- add_target_with_completer (&tfile_ops, filename_completer);
+ add_target (tfile_target_info, tfile_target_open, filename_completer);
}