gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / tracefile.c
index c26d8db986f0034984dd057e220822756e85a994..7f1a25a2cc29ef3db50fe3c428d6846df2c1ec7b 100644 (file)
@@ -1,6 +1,6 @@
 /* Trace file support in GDB.
 
-   Copyright (C) 1997-2015 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 "ctf.h"
+#include "tracectf.h"
 #include "exec.h"
 #include "regcache.h"
+#include "gdbsupport/byte-vector.h"
+#include "gdbarch.h"
 
 /* Helper macros.  */
 
 #define TRACE_WRITE_V_BLOCK(writer, num, val)  \
   writer->ops->frame_ops->write_v_block ((writer), (num), (val))
 
-/* Free trace file writer.  */
+/* A unique pointer policy class for trace_file_writer.  */
 
-static void
-trace_file_writer_xfree (void *arg)
+struct trace_file_writer_deleter
 {
-  struct trace_file_writer *writer = (struct trace_file_writer *) arg;
+  void operator() (struct trace_file_writer *writer)
+  {
+    writer->ops->dtor (writer);
+    xfree (writer);
+  }
+};
 
-  writer->ops->dtor (writer);
-  xfree (writer);
-}
+/* A unique_ptr specialization for trace_file_writer.  */
+
+typedef std::unique_ptr<trace_file_writer, trace_file_writer_deleter>
+    trace_file_writer_up;
 
 /* Save tracepoint data to file named FILENAME through WRITER.  WRITER
    determines the trace file format.  If TARGET_DOES_SAVE is non-zero,
@@ -57,14 +64,12 @@ 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;
+  gdb::byte_vector buf (std::max (MAX_TRACE_UPLOAD, trace_regblock_size));
   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
@@ -78,8 +83,10 @@ trace_save (const char *filename, struct trace_file_writer *writer,
     }
 
   /* 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);
+     target is losing, we can get out without touching files.  Since
+     we're just calling this for side effects, we ignore the
+     result.  */
+  target_get_trace_status (ts);
 
   writer->ops->start (writer, filename);
 
@@ -90,6 +97,9 @@ trace_save (const char *filename, struct trace_file_writer *writer,
   /* Write out the size of a register block.  */
   writer->ops->write_regblock_type (writer, trace_regblock_size);
 
+  /* Write out the target description info.  */
+  writer->ops->write_tdesc (writer);
+
   /* Write out status of the tracing run (aka "tstatus" info).  */
   writer->ops->write_status (writer, ts);
 
@@ -136,7 +146,7 @@ trace_save (const char *filename, struct trace_file_writer *writer,
          /* 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,
+         gotten = target_get_raw_trace_data (buf.data (), offset,
                                              MAX_TRACE_UPLOAD);
          if (gotten < 0)
            error (_("Failure to get requested trace buffer data"));
@@ -144,7 +154,7 @@ trace_save (const char *filename, struct trace_file_writer *writer,
          if (gotten == 0)
            break;
 
-         writer->ops->write_trace_buffer (writer, buf, gotten);
+         writer->ops->write_trace_buffer (writer, buf.data (), gotten);
 
          offset += gotten;
        }
@@ -155,7 +165,7 @@ trace_save (const char *filename, struct trace_file_writer *writer,
          /* Parse the trace buffers according to how data are stored
             in trace buffer in GDBserver.  */
 
-         gotten = target_get_raw_trace_data (buf, offset, 6);
+         gotten = target_get_raw_trace_data (buf.data (), offset, 6);
 
          if (gotten == 0)
            break;
@@ -163,10 +173,10 @@ trace_save (const char *filename, struct trace_file_writer *writer,
          /* 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);
+           extract_unsigned_integer (&((buf.data ())[0]), 2, byte_order);
 
          tf_size = (uint32_t)
-           extract_unsigned_integer (&buf[2], 4, byte_order);
+           extract_unsigned_integer (&((buf.data ())[2]), 4, byte_order);
 
          writer->ops->frame_ops->start (writer, tp_num);
          gotten = 6;
@@ -184,7 +194,8 @@ trace_save (const char *filename, struct trace_file_writer *writer,
                  /* 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);
+                 gotten = target_get_raw_trace_data (buf.data (),
+                                                     offset, 1);
                  if (gotten < 1)
                    error (_("Failure to get requested trace buffer data"));
 
@@ -197,13 +208,13 @@ trace_save (const char *filename, struct trace_file_writer *writer,
                    {
                    case 'R':
                      gotten
-                       = target_get_raw_trace_data (buf, offset,
+                       = target_get_raw_trace_data (buf.data (), offset,
                                                     trace_regblock_size);
                      if (gotten < trace_regblock_size)
                        error (_("Failure to get requested trace"
                                 " buffer data"));
 
-                     TRACE_WRITE_R_BLOCK (writer, buf,
+                     TRACE_WRITE_R_BLOCK (writer, buf.data (),
                                           trace_regblock_size);
                      break;
                    case 'M':
@@ -213,7 +224,8 @@ trace_save (const char *filename, struct trace_file_writer *writer,
                        LONGEST t;
                        int j;
 
-                       t = target_get_raw_trace_data (buf,offset, 10);
+                       t = target_get_raw_trace_data (buf.data (),
+                                                      offset, 10);
                        if (t < 10)
                          error (_("Failure to get requested trace"
                                   " buffer data"));
@@ -223,10 +235,10 @@ trace_save (const char *filename, struct trace_file_writer *writer,
 
                        gotten = 0;
                        addr = (ULONGEST)
-                         extract_unsigned_integer (buf, 8,
+                         extract_unsigned_integer (buf.data (), 8,
                                                    byte_order);
                        mlen = (unsigned short)
-                         extract_unsigned_integer (&buf[8], 2,
+                         extract_unsigned_integer (&((buf.data ())[8]), 2,
                                                    byte_order);
 
                        TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
@@ -244,14 +256,15 @@ trace_save (const char *filename, struct trace_file_writer *writer,
                            else
                              read_length = mlen - j;
 
-                           t = target_get_raw_trace_data (buf,
+                           t = target_get_raw_trace_data (buf.data (),
                                                           offset + j,
                                                           read_length);
                            if (t < read_length)
                              error (_("Failure to get requested"
                                       " trace buffer data"));
 
-                           TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
+                           TRACE_WRITE_M_BLOCK_MEMORY (writer,
+                                                       buf.data (),
                                                        read_length);
 
                            j += read_length;
@@ -266,18 +279,18 @@ trace_save (const char *filename, struct trace_file_writer *writer,
                        LONGEST val;
 
                        gotten
-                         = target_get_raw_trace_data (buf, offset,
-                                                      12);
+                         = target_get_raw_trace_data (buf.data (),
+                                                      offset, 12);
                        if (gotten < 12)
                          error (_("Failure to get requested"
                                   " trace buffer data"));
 
-                       vnum  = (int) extract_signed_integer (buf,
+                       vnum  = (int) extract_signed_integer (buf.data (),
                                                              4,
                                                              byte_order);
                        val
-                         = extract_signed_integer (&buf[4], 8,
-                                                   byte_order);
+                         = extract_signed_integer (&((buf.data ())[4]),
+                                                   8, byte_order);
 
                        TRACE_WRITE_V_BLOCK (writer, vnum, val);
                      }
@@ -303,26 +316,24 @@ trace_save (const char *filename, struct trace_file_writer *writer,
 }
 
 static void
-trace_save_command (char *args, int from_tty)
+tsave_command (const 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);
+  gdb_argv built_argv (args);
+  argv = built_argv.get ();
 
   for (; *argv; ++argv)
     {
       if (strcmp (*argv, "-r") == 0)
        target_does_save = 1;
-      if (strcmp (*argv, "-ctf") == 0)
+      else if (strcmp (*argv, "-ctf") == 0)
        generate_ctf = 1;
       else if (**argv == '-')
        error (_("unknown option `%s'"), *argv);
@@ -334,19 +345,13 @@ trace_save_command (char *args, int from_tty)
     error_no_arg (_("file in which to save trace data"));
 
   if (generate_ctf)
-    writer = ctf_trace_file_writer_new ();
+    trace_save_ctf (filename, target_does_save);
   else
-    writer = tfile_trace_file_writer_new ();
-
-  make_cleanup (trace_file_writer_xfree, writer);
-
-  trace_save (filename, writer, target_does_save);
+    trace_save_tfile (filename, 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.  */
@@ -354,13 +359,8 @@ trace_save_command (char *args, int from_tty)
 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);
+  trace_file_writer_up writer (tfile_trace_file_writer_new ());
+  trace_save (filename, writer.get (), target_does_save);
 }
 
 /* Save the trace data to dir DIRNAME of ctf format.  */
@@ -368,14 +368,8 @@ trace_save_tfile (const char *filename, int target_does_save)
 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);
+  trace_file_writer_up writer (ctf_trace_file_writer_new ());
+  trace_save (dirname, writer.get (), target_does_save);
 }
 
 /* Fetch register data from tracefile, shared for both tfile and
@@ -384,72 +378,54 @@ trace_save_ctf (const char *dirname, int target_does_save)
 void
 tracefile_fetch_registers (struct regcache *regcache, int regno)
 {
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  int regn, pc_regno;
+  struct gdbarch *gdbarch = regcache->arch ();
+  struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+  int regn;
 
   /* We get here if no register data has been found.  Mark registers
      as unavailable.  */
   for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
-    regcache_raw_supply (regcache, regn, NULL);
+    regcache->raw_supply (regn, NULL);
 
   /* We can often usefully guess that the PC is going to be the same
      as the address of the tracepoint.  */
-  pc_regno = gdbarch_pc_regnum (gdbarch);
-
-  /* XXX This guessing code below only works if the PC register isn't
-     a pseudo-register.  The value of a pseudo-register isn't stored
-     in the (non-readonly) regcache -- instead it's recomputed
-     (probably from some other cached raw register) whenever the
-     register is read.  This guesswork should probably move to some
-     higher layer.  */
-  if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch))
+  if (tp == NULL || tp->loc == NULL)
     return;
 
-  if (regno == -1 || regno == pc_regno)
+  /* But don't try to guess if tracepoint is multi-location...  */
+  if (tp->loc->next)
     {
-      struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
-      gdb_byte *regs;
-
-      if (tp && tp->base.loc)
-       {
-         /* But don't try to guess if tracepoint is multi-location...  */
-         if (tp->base.loc->next)
-           {
-             warning (_("Tracepoint %d has multiple "
-                        "locations, cannot infer $pc"),
-                      tp->base.number);
-             return;
-           }
-         /* ... or does while-stepping.  */
-         if (tp->step_count > 0)
-           {
-             warning (_("Tracepoint %d does while-stepping, "
-                        "cannot infer $pc"),
-                      tp->base.number);
-             return;
-           }
-
-         regs = (gdb_byte *) alloca (register_size (gdbarch, pc_regno));
-         store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
-                                 gdbarch_byte_order (gdbarch),
-                                 tp->base.loc->address);
-         regcache_raw_supply (regcache, pc_regno, regs);
-       }
+      warning (_("Tracepoint %d has multiple "
+                "locations, cannot infer $pc"),
+              tp->number);
+      return;
+    }
+  /* ... or does while-stepping.  */
+  else if (tp->step_count > 0)
+    {
+      warning (_("Tracepoint %d does while-stepping, "
+                "cannot infer $pc"),
+              tp->number);
+      return;
     }
+
+  /* Guess what we can from the tracepoint location.  */
+  gdbarch_guess_tracepoint_registers (gdbarch, regcache,
+                                     tp->loc->address);
 }
 
 /* This is the implementation of target_ops method to_has_all_memory.  */
 
-static int
-tracefile_has_all_memory (struct target_ops *ops)
+bool
+tracefile_target::has_all_memory ()
 {
   return 1;
 }
 
 /* This is the implementation of target_ops method to_has_memory.  */
 
-static int
-tracefile_has_memory (struct target_ops *ops)
+bool
+tracefile_target::has_memory ()
 {
   return 1;
 }
@@ -458,8 +434,8 @@ tracefile_has_memory (struct target_ops *ops)
    The target has a stack when GDB has already selected one trace
    frame.  */
 
-static int
-tracefile_has_stack (struct target_ops *ops)
+bool
+tracefile_target::has_stack ()
 {
   return get_traceframe_number () != -1;
 }
@@ -468,8 +444,8 @@ tracefile_has_stack (struct target_ops *ops)
    The target has registers when GDB has already selected one trace
    frame.  */
 
-static int
-tracefile_has_registers (struct target_ops *ops)
+bool
+tracefile_target::has_registers ()
 {
   return get_traceframe_number () != -1;
 }
@@ -477,8 +453,8 @@ tracefile_has_registers (struct target_ops *ops)
 /* This is the implementation of target_ops method to_thread_alive.
    tracefile has one thread faked by GDB.  */
 
-static int
-tracefile_thread_alive (struct target_ops *ops, ptid_t ptid)
+bool
+tracefile_target::thread_alive (ptid_t ptid)
 {
   return 1;
 }
@@ -486,8 +462,8 @@ tracefile_thread_alive (struct target_ops *ops, ptid_t ptid)
 /* This is the implementation of target_ops method to_get_trace_status.
    The trace status for a file is that tracing can never be run.  */
 
-static int
-tracefile_get_trace_status (struct target_ops *self, struct trace_status *ts)
+int
+tracefile_target::get_trace_status (struct trace_status *ts)
 {
   /* Other bits of trace status were collected as part of opening the
      trace files, so nothing to do here.  */
@@ -495,27 +471,11 @@ tracefile_get_trace_status (struct target_ops *self, struct trace_status *ts)
   return -1;
 }
 
-/* Initialize OPS for tracefile related targets.  */
-
-void
-init_tracefile_ops (struct target_ops *ops)
-{
-  ops->to_stratum = process_stratum;
-  ops->to_get_trace_status = tracefile_get_trace_status;
-  ops->to_has_all_memory = tracefile_has_all_memory;
-  ops->to_has_memory = tracefile_has_memory;
-  ops->to_has_stack = tracefile_has_stack;
-  ops->to_has_registers = tracefile_has_registers;
-  ops->to_thread_alive = tracefile_thread_alive;
-  ops->to_magic = OPS_MAGIC;
-}
-
-extern initialize_file_ftype _initialize_tracefile;
-
+void _initialize_tracefile ();
 void
-_initialize_tracefile (void)
+_initialize_tracefile ()
 {
-  add_com ("tsave", class_trace, trace_save_command, _("\
+  add_com ("tsave", class_trace, tsave_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\
This page took 0.030545 seconds and 4 git commands to generate.