[PATCH 2/8] Move tfile target to tracefile-tfile.c

Yao Qi yao@codesourcery.com
Wed Feb 12 06:08:00 GMT 2014


This patch moves tfile target related code from tracepoint.c to
tracefile-tfile.c.

gdb:

2014-02-12  Yao Qi  <yao@codesourcery.com>

	* tracepoint.c (TFILE_PID): Move it to tracefile-tfile.c.
	(tfile_ops): Likewise.
	(TRACE_HEADER_SIZE): Likewise.
	(trace_fd, trace_frames_offset, cur_offset): Likewise.
	(cur_data_size): Likewise.
	(tfile_read, tfile_open, tfile_interp_line): Likewise.
	(tfile_close, tfile_files_info): Likewise.
	(tfile_get_trace_status): Likewise.
	(tfile_get_tracepoint_status): Likewise.
	(tfile_get_traceframe_address): Likewise.
	(tfile_trace_find, match_blocktype): Likewise.
	(traceframe_walk_blocks, traceframe_find_block_type): Likewise.
	(tfile_fetch_registers, tfile_xfer_partial): Likewise.
	(tfile_get_trace_state_variable_value): Likewise.
	(tfile_has_all_memory, tfile_has_memory): Likewise.
	(tfile_has_stack, tfile_has_registers): Likewise.
	(tfile_thread_alive, build_traceframe_info): Likewise.
	(tfile_traceframe_info, init_tfile_ops): Likewise.
	(_initialize_tracepoint): Don't call init_tfile_ops
	and add_target_with_completer.
	* tracefile-tfile.c: Include regcache.h, inferior.h, gdbthread.h,
	exec.h, completer.h and filenames.h.
	(_initialize_tracefile_tfile): New function.
---
 gdb/tracefile-tfile.c |  821 +++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/tracepoint.c      |  809 ------------------------------------------------
 2 files changed, 821 insertions(+), 809 deletions(-)

diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c
index 97e93fc..1310151 100644
--- a/gdb/tracefile-tfile.c
+++ b/gdb/tracefile-tfile.c
@@ -22,6 +22,12 @@
 #include "readline/tilde.h"
 #include "filestuff.h"
 #include "remote.h" /* bin2hex */
+#include "regcache.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "exec.h" /* exec_bfd */
+#include "completer.h"
+#include "filenames.h"
 
 /* TFILE trace writer.  */
 
@@ -325,3 +331,818 @@ tfile_trace_file_writer_new (void)
 
   return (struct trace_file_writer *) writer;
 }
+
+/* target tfile command */
+
+static struct target_ops tfile_ops;
+
+/* Fill in tfile_ops with its defined operations and properties.  */
+
+#define TRACE_HEADER_SIZE 8
+
+#define TFILE_PID (1)
+
+static char *trace_filename;
+static int trace_fd = -1;
+static off_t trace_frames_offset;
+static off_t cur_offset;
+static int cur_data_size;
+int trace_regblock_size;
+
+static void tfile_interp_line (char *line,
+			       struct uploaded_tp **utpp,
+			       struct uploaded_tsv **utsvp);
+
+/* Read SIZE bytes into READBUF from the trace frame, starting at
+   TRACE_FD's current position.  Note that this call `read'
+   underneath, hence it advances the file's seek position.  Throws an
+   error if the `read' syscall fails, or less than SIZE bytes are
+   read.  */
+
+static void
+tfile_read (gdb_byte *readbuf, int size)
+{
+  int gotten;
+
+  gotten = read (trace_fd, readbuf, size);
+  if (gotten < 0)
+    perror_with_name (trace_filename);
+  else if (gotten < size)
+    error (_("Premature end of file while reading trace file"));
+}
+
+static void
+tfile_open (char *filename, int from_tty)
+{
+  volatile struct gdb_exception ex;
+  char *temp;
+  struct cleanup *old_chain;
+  int flags;
+  int scratch_chan;
+  char header[TRACE_HEADER_SIZE];
+  char linebuf[1000]; /* Should be max remote packet size or so.  */
+  gdb_byte byte;
+  int bytes, i;
+  struct trace_status *ts;
+  struct uploaded_tp *uploaded_tps = NULL;
+  struct uploaded_tsv *uploaded_tsvs = NULL;
+
+  target_preopen (from_tty);
+  if (!filename)
+    error (_("No trace file specified."));
+
+  filename = tilde_expand (filename);
+  if (!IS_ABSOLUTE_PATH(filename))
+    {
+      temp = concat (current_directory, "/", filename, (char *) NULL);
+      xfree (filename);
+      filename = temp;
+    }
+
+  old_chain = make_cleanup (xfree, filename);
+
+  flags = O_BINARY | O_LARGEFILE;
+  flags |= O_RDONLY;
+  scratch_chan = gdb_open_cloexec (filename, flags, 0);
+  if (scratch_chan < 0)
+    perror_with_name (filename);
+
+  /* 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_fd = scratch_chan;
+
+  bytes = 0;
+  /* Read the file header and test for validity.  */
+  tfile_read ((gdb_byte *) &header, TRACE_HEADER_SIZE);
+
+  bytes += TRACE_HEADER_SIZE;
+  if (!(header[0] == 0x7f
+	&& (strncmp (header + 1, "TRACE0\n", 7) == 0)))
+    error (_("File is not a valid trace file."));
+
+  push_target (&tfile_ops);
+
+  trace_regblock_size = 0;
+  ts = current_trace_status ();
+  /* We know we're working with a file.  Record its name.  */
+  ts->filename = trace_filename;
+  /* Set defaults in case there is no status line.  */
+  ts->running_known = 0;
+  ts->stop_reason = trace_stop_reason_unknown;
+  ts->traceframe_count = -1;
+  ts->buffer_free = 0;
+  ts->disconnected_tracing = 0;
+  ts->circular_buffer = 0;
+
+  TRY_CATCH (ex, RETURN_MASK_ALL)
+    {
+      /* Read through a section of newline-terminated lines that
+	 define things like tracepoints.  */
+      i = 0;
+      while (1)
+	{
+	  tfile_read (&byte, 1);
+
+	  ++bytes;
+	  if (byte == '\n')
+	    {
+	      /* Empty line marks end of the definition section.  */
+	      if (i == 0)
+		break;
+	      linebuf[i] = '\0';
+	      i = 0;
+	      tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
+	    }
+	  else
+	    linebuf[i++] = byte;
+	  if (i >= 1000)
+	    error (_("Excessively long lines in trace file"));
+	}
+
+      /* Record the starting offset of the binary trace data.  */
+      trace_frames_offset = bytes;
+
+      /* If we don't have a blocksize, we can't interpret the
+	 traceframes.  */
+      if (trace_regblock_size == 0)
+	error (_("No register block size recorded in trace file"));
+    }
+  if (ex.reason < 0)
+    {
+      /* Remove the partially set up target.  */
+      unpush_target (&tfile_ops);
+      throw_exception (ex);
+    }
+
+  inferior_appeared (current_inferior (), TFILE_PID);
+  inferior_ptid = pid_to_ptid (TFILE_PID);
+  add_thread_silent (inferior_ptid);
+
+  if (ts->traceframe_count <= 0)
+    warning (_("No traceframes present in this file."));
+
+  /* Add the file's tracepoints and variables into the current mix.  */
+
+  /* Get trace state variables first, they may be checked when parsing
+     uploaded commands.  */
+  merge_uploaded_trace_state_variables (&uploaded_tsvs);
+
+  merge_uploaded_tracepoints (&uploaded_tps);
+
+  post_create_inferior (&tfile_ops, from_tty);
+}
+
+/* Interpret the given line from the definitions part of the trace
+   file.  */
+
+static void
+tfile_interp_line (char *line, struct uploaded_tp **utpp,
+		   struct uploaded_tsv **utsvp)
+{
+  char *p = line;
+
+  if (strncmp (p, "R ", strlen ("R ")) == 0)
+    {
+      p += strlen ("R ");
+      trace_regblock_size = strtol (p, &p, 16);
+    }
+  else if (strncmp (p, "status ", strlen ("status ")) == 0)
+    {
+      p += strlen ("status ");
+      parse_trace_status (p, current_trace_status ());
+    }
+  else if (strncmp (p, "tp ", strlen ("tp ")) == 0)
+    {
+      p += strlen ("tp ");
+      parse_tracepoint_definition (p, utpp);
+    }
+  else if (strncmp (p, "tsv ", strlen ("tsv ")) == 0)
+    {
+      p += strlen ("tsv ");
+      parse_tsv_definition (p, utsvp);
+    }
+  else
+    warning (_("Ignoring trace file definition \"%s\""), line);
+}
+
+/* Close the trace file and generally clean up.  */
+
+static void
+tfile_close (void)
+{
+  int pid;
+
+  if (trace_fd < 0)
+    return;
+
+  pid = ptid_get_pid (inferior_ptid);
+  inferior_ptid = null_ptid;	/* Avoid confusion from thread stuff.  */
+  exit_inferior_silent (pid);
+
+  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)
+{
+  printf_filtered ("\t`%s'\n", trace_filename);
+}
+
+/* The trace status for a file is that tracing can never be run.  */
+
+static int
+tfile_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.  */
+
+  return -1;
+}
+
+static void
+tfile_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.  */
+}
+
+/* Given the position of a traceframe in the file, figure out what
+   address the frame was collected at.  This would normally be the
+   value of a collected PC register, but if not available, we
+   improvise.  */
+
+static CORE_ADDR
+tfile_get_traceframe_address (off_t tframe_offset)
+{
+  CORE_ADDR addr = 0;
+  short tpnum;
+  struct tracepoint *tp;
+  off_t saved_offset = cur_offset;
+
+  /* FIXME dig pc out of collected registers.  */
+
+  /* Fall back to using tracepoint address.  */
+  lseek (trace_fd, tframe_offset, SEEK_SET);
+  tfile_read ((gdb_byte *) &tpnum, 2);
+  tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
+					  gdbarch_byte_order
+					      (target_gdbarch ()));
+
+  tp = get_tracepoint_by_number_on_target (tpnum);
+  /* FIXME this is a poor heuristic if multiple locations.  */
+  if (tp && tp->base.loc)
+    addr = tp->base.loc->address;
+
+  /* Restore our seek position.  */
+  cur_offset = saved_offset;
+  lseek (trace_fd, cur_offset, SEEK_SET);
+  return addr;
+}
+
+/* Given a type of search and some parameters, scan the collection of
+   traceframes in the file looking for a match.  When found, return
+   both the traceframe and tracepoint number, otherwise -1 for
+   each.  */
+
+static int
+tfile_trace_find (enum trace_find_type type, int num,
+		  CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+  short tpnum;
+  int tfnum = 0, found = 0;
+  unsigned int data_size;
+  struct tracepoint *tp;
+  off_t offset, tframe_offset;
+  CORE_ADDR tfaddr;
+
+  if (num == -1)
+    {
+      if (tpp)
+        *tpp = -1;
+      return -1;
+    }
+
+  lseek (trace_fd, trace_frames_offset, SEEK_SET);
+  offset = trace_frames_offset;
+  while (1)
+    {
+      tframe_offset = offset;
+      tfile_read ((gdb_byte *) &tpnum, 2);
+      tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
+					      gdbarch_byte_order
+						  (target_gdbarch ()));
+      offset += 2;
+      if (tpnum == 0)
+	break;
+      tfile_read ((gdb_byte *) &data_size, 4);
+      data_size = (unsigned int) extract_unsigned_integer
+                                     ((gdb_byte *) &data_size, 4,
+				      gdbarch_byte_order (target_gdbarch ()));
+      offset += 4;
+
+      if (type == tfind_number)
+	{
+	  /* Looking for a specific trace frame.  */
+	  if (tfnum == num)
+	    found = 1;
+	}
+      else
+	{
+	  /* Start from the _next_ trace frame.  */
+	  if (tfnum > get_traceframe_number ())
+	    {
+	      switch (type)
+		{
+		case tfind_pc:
+		  tfaddr = tfile_get_traceframe_address (tframe_offset);
+		  if (tfaddr == addr1)
+		    found = 1;
+		  break;
+		case tfind_tp:
+		  tp = get_tracepoint (num);
+		  if (tp && tpnum == tp->number_on_target)
+		    found = 1;
+		  break;
+		case tfind_range:
+		  tfaddr = tfile_get_traceframe_address (tframe_offset);
+		  if (addr1 <= tfaddr && tfaddr <= addr2)
+		    found = 1;
+		  break;
+		case tfind_outside:
+		  tfaddr = tfile_get_traceframe_address (tframe_offset);
+		  if (!(addr1 <= tfaddr && tfaddr <= addr2))
+		    found = 1;
+		  break;
+		default:
+		  internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+		}
+	    }
+	}
+
+      if (found)
+	{
+	  if (tpp)
+	    *tpp = tpnum;
+	  cur_offset = offset;
+	  cur_data_size = data_size;
+
+	  return tfnum;
+	}
+      /* Skip past the traceframe's data.  */
+      lseek (trace_fd, data_size, SEEK_CUR);
+      offset += data_size;
+      /* Update our own count of traceframes.  */
+      ++tfnum;
+    }
+  /* Did not find what we were looking for.  */
+  if (tpp)
+    *tpp = -1;
+  return -1;
+}
+
+/* Prototype of the callback passed to tframe_walk_blocks.  */
+typedef int (*walk_blocks_callback_func) (char blocktype, void *data);
+
+/* Callback for traceframe_walk_blocks, used to find a given block
+   type in a traceframe.  */
+
+static int
+match_blocktype (char blocktype, void *data)
+{
+  char *wantedp = data;
+
+  if (*wantedp == blocktype)
+    return 1;
+
+  return 0;
+}
+
+/* Walk over all traceframe block starting at POS offset from
+   CUR_OFFSET, and call CALLBACK for each block found, passing in DATA
+   unmodified.  If CALLBACK returns true, this returns the position in
+   the traceframe where the block is found, relative to the start of
+   the traceframe (cur_offset).  Returns -1 if no callback call
+   returned true, indicating that all blocks have been walked.  */
+
+static int
+traceframe_walk_blocks (walk_blocks_callback_func callback,
+			int pos, void *data)
+{
+  /* Iterate through a traceframe's blocks, looking for a block of the
+     requested type.  */
+
+  lseek (trace_fd, cur_offset + pos, SEEK_SET);
+  while (pos < cur_data_size)
+    {
+      unsigned short mlen;
+      char block_type;
+
+      tfile_read ((gdb_byte *) &block_type, 1);
+
+      ++pos;
+
+      if ((*callback) (block_type, data))
+	return pos;
+
+      switch (block_type)
+	{
+	case 'R':
+	  lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
+	  pos += trace_regblock_size;
+	  break;
+	case 'M':
+	  lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
+	  tfile_read ((gdb_byte *) &mlen, 2);
+          mlen = (unsigned short)
+                extract_unsigned_integer ((gdb_byte *) &mlen, 2,
+                                          gdbarch_byte_order
+                                              (target_gdbarch ()));
+	  lseek (trace_fd, mlen, SEEK_CUR);
+	  pos += (8 + 2 + mlen);
+	  break;
+	case 'V':
+	  lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
+	  pos += (4 + 8);
+	  break;
+	default:
+	  error (_("Unknown block type '%c' (0x%x) in trace frame"),
+		 block_type, block_type);
+	  break;
+	}
+    }
+
+  return -1;
+}
+
+/* Convenience wrapper around traceframe_walk_blocks.  Looks for the
+   position offset of a block of type TYPE_WANTED in the current trace
+   frame, starting at POS.  Returns -1 if no such block was found.  */
+
+static int
+traceframe_find_block_type (char type_wanted, int pos)
+{
+  return traceframe_walk_blocks (match_blocktype, pos, &type_wanted);
+}
+
+/* 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)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  int offset, regn, regsize, pc_regno;
+  gdb_byte *regs;
+
+  /* An uninitialized reg size says we're not going to be
+     successful at getting register blocks.  */
+  if (!trace_regblock_size)
+    return;
+
+  regs = alloca (trace_regblock_size);
+
+  if (traceframe_find_block_type ('R', 0) >= 0)
+    {
+      tfile_read (regs, trace_regblock_size);
+
+      /* Assume the block is laid out in GDB register number order,
+	 each register with the size that it has in GDB.  */
+      offset = 0;
+      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+	{
+	  regsize = register_size (gdbarch, regn);
+	  /* Make sure we stay within block bounds.  */
+	  if (offset + regsize >= trace_regblock_size)
+	    break;
+	  if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+	    {
+	      if (regno == regn)
+		{
+		  regcache_raw_supply (regcache, regno, regs + offset);
+		  break;
+		}
+	      else if (regno == -1)
+		{
+		  regcache_raw_supply (regcache, regn, regs + offset);
+		}
+	    }
+	  offset += regsize;
+	}
+      return;
+    }
+
+  /* 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);
+
+  /* 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))
+    return;
+
+  if (regno == -1 || regno == pc_regno)
+    {
+      struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+      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;
+	    }
+
+	  store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+				  gdbarch_byte_order (gdbarch),
+				  tp->base.loc->address);
+	  regcache_raw_supply (regcache, pc_regno, regs);
+	}
+    }
+}
+
+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)
+{
+  /* We're only doing regular memory for now.  */
+  if (object != TARGET_OBJECT_MEMORY)
+    return TARGET_XFER_E_IO;
+
+  if (readbuf == NULL)
+    error (_("tfile_xfer_partial: trace file is read-only"));
+
+  if (get_traceframe_number () != -1)
+    {
+      int pos = 0;
+
+      /* Iterate through the traceframe's blocks, looking for
+	 memory.  */
+      while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
+	{
+	  ULONGEST maddr, amt;
+	  unsigned short mlen;
+	  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+	  tfile_read ((gdb_byte *) &maddr, 8);
+	  maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
+					    byte_order);
+	  tfile_read ((gdb_byte *) &mlen, 2);
+	  mlen = (unsigned short)
+	    extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
+
+	  /* If the block includes the first part of the desired
+	     range, return as much it has; GDB will re-request the
+	     remainder, which might be in a different block of this
+	     trace frame.  */
+	  if (maddr <= offset && offset < (maddr + mlen))
+	    {
+	      amt = (maddr + mlen) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      if (maddr != offset)
+	        lseek (trace_fd, offset - maddr, SEEK_CUR);
+	      tfile_read (readbuf, amt);
+	      *xfered_len = amt;
+	      return TARGET_XFER_OK;
+	    }
+
+	  /* Skip over this block.  */
+	  pos += (8 + 2 + mlen);
+	}
+    }
+
+  /* It's unduly pedantic to refuse to look at the executable for
+     read-only pieces; so do the equivalent of readonly regions aka
+     QTro packet.  */
+  /* FIXME account for relocation at some point.  */
+  if (exec_bfd)
+    {
+      asection *s;
+      bfd_size_type size;
+      bfd_vma vma;
+
+      for (s = exec_bfd->sections; s; s = s->next)
+	{
+	  if ((s->flags & SEC_LOAD) == 0
+	      || (s->flags & SEC_READONLY) == 0)
+	    continue;
+
+	  vma = s->vma;
+	  size = bfd_get_section_size (s);
+	  if (vma <= offset && offset < (vma + size))
+	    {
+	      ULONGEST amt;
+
+	      amt = (vma + size) - offset;
+	      if (amt > len)
+		amt = len;
+
+	      *xfered_len = bfd_get_section_contents (exec_bfd, s,
+						      readbuf, offset - vma, amt);
+	      return TARGET_XFER_OK;
+	    }
+	}
+    }
+
+  /* Indicate failure to find the requested memory block.  */
+  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 (int tsvnum, LONGEST *val)
+{
+  int pos;
+  int found = 0;
+
+  /* Iterate over blocks in current frame and find the last 'V'
+     block in which tsv number is TSVNUM.  In one trace frame, there
+     may be multiple 'V' blocks created for a given trace variable,
+     and the last matched 'V' block contains the updated value.  */
+  pos = 0;
+  while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
+    {
+      int vnum;
+
+      tfile_read ((gdb_byte *) &vnum, 4);
+      vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
+					   gdbarch_byte_order
+					   (target_gdbarch ()));
+      if (tsvnum == vnum)
+	{
+	  tfile_read ((gdb_byte *) val, 8);
+	  *val = extract_signed_integer ((gdb_byte *) val, 8,
+					 gdbarch_byte_order
+					 (target_gdbarch ()));
+	  found = 1;
+	}
+      pos += (4 + 8);
+    }
+
+  return found;
+}
+
+static int
+tfile_has_all_memory (struct target_ops *ops)
+{
+  return 1;
+}
+
+static int
+tfile_has_memory (struct target_ops *ops)
+{
+  return 1;
+}
+
+static int
+tfile_has_stack (struct target_ops *ops)
+{
+  return get_traceframe_number () != -1;
+}
+
+static int
+tfile_has_registers (struct target_ops *ops)
+{
+  return get_traceframe_number () != -1;
+}
+
+static int
+tfile_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+  return 1;
+}
+
+/* Callback for traceframe_walk_blocks.  Builds a traceframe_info
+   object for the tfile target's current traceframe.  */
+
+static int
+build_traceframe_info (char blocktype, void *data)
+{
+  struct traceframe_info *info = data;
+
+  switch (blocktype)
+    {
+    case 'M':
+      {
+	struct mem_range *r;
+	ULONGEST maddr;
+	unsigned short mlen;
+
+	tfile_read ((gdb_byte *) &maddr, 8);
+	maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
+					  gdbarch_byte_order
+					  (target_gdbarch ()));
+	tfile_read ((gdb_byte *) &mlen, 2);
+	mlen = (unsigned short)
+		extract_unsigned_integer ((gdb_byte *) &mlen,
+					  2, gdbarch_byte_order
+					  (target_gdbarch ()));
+
+	r = VEC_safe_push (mem_range_s, info->memory, NULL);
+
+	r->start = maddr;
+	r->length = mlen;
+	break;
+      }
+    case 'V':
+      {
+	int vnum;
+
+	tfile_read ((gdb_byte *) &vnum, 4);
+	VEC_safe_push (int, info->tvars, vnum);
+      }
+    case 'R':
+    case 'S':
+      {
+	break;
+      }
+    default:
+      warning (_("Unhandled trace block type (%d) '%c ' "
+		 "while building trace frame info."),
+	       blocktype, blocktype);
+      break;
+    }
+
+  return 0;
+}
+
+static struct traceframe_info *
+tfile_traceframe_info (void)
+{
+  struct traceframe_info *info = XCNEW (struct traceframe_info);
+
+  traceframe_walk_blocks (build_traceframe_info, 0, info);
+  return info;
+}
+
+static void
+init_tfile_ops (void)
+{
+  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_trace_status = tfile_get_trace_status;
+  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_stratum = process_stratum;
+  tfile_ops.to_has_all_memory = tfile_has_all_memory;
+  tfile_ops.to_has_memory = tfile_has_memory;
+  tfile_ops.to_has_stack = tfile_has_stack;
+  tfile_ops.to_has_registers = tfile_has_registers;
+  tfile_ops.to_traceframe_info = tfile_traceframe_info;
+  tfile_ops.to_thread_alive = tfile_thread_alive;
+  tfile_ops.to_magic = OPS_MAGIC;
+}
+
+extern initialize_file_ftype _initialize_tracefile_tfile;
+
+void
+_initialize_tracefile_tfile (void)
+{
+  init_tfile_ops ();
+
+  add_target_with_completer (&tfile_ops, filename_completer);
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 45a7fd4..c1dcb1e 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -80,8 +80,6 @@
    large.  (400 - 31)/2 == 184 */
 #define MAX_AGENT_EXPR_LEN	184
 
-#define TFILE_PID (1)
-
 /* A hook used to notify the UI of tracepoint operations.  */
 
 void (*deprecated_trace_find_hook) (char *arg, int from_tty);
@@ -3570,201 +3568,6 @@ merge_uploaded_trace_state_variables (struct uploaded_tsv **uploaded_tsvs)
   free_uploaded_tsvs (uploaded_tsvs);
 }
 
-/* target tfile command */
-
-static struct target_ops tfile_ops;
-
-/* Fill in tfile_ops with its defined operations and properties.  */
-
-#define TRACE_HEADER_SIZE 8
-
-static char *trace_filename;
-static int trace_fd = -1;
-static off_t trace_frames_offset;
-static off_t cur_offset;
-static int cur_data_size;
-int trace_regblock_size;
-
-static void tfile_interp_line (char *line,
-			       struct uploaded_tp **utpp,
-			       struct uploaded_tsv **utsvp);
-
-/* Read SIZE bytes into READBUF from the trace frame, starting at
-   TRACE_FD's current position.  Note that this call `read'
-   underneath, hence it advances the file's seek position.  Throws an
-   error if the `read' syscall fails, or less than SIZE bytes are
-   read.  */
-
-static void
-tfile_read (gdb_byte *readbuf, int size)
-{
-  int gotten;
-
-  gotten = read (trace_fd, readbuf, size);
-  if (gotten < 0)
-    perror_with_name (trace_filename);
-  else if (gotten < size)
-    error (_("Premature end of file while reading trace file"));
-}
-
-static void
-tfile_open (char *filename, int from_tty)
-{
-  volatile struct gdb_exception ex;
-  char *temp;
-  struct cleanup *old_chain;
-  int flags;
-  int scratch_chan;
-  char header[TRACE_HEADER_SIZE];
-  char linebuf[1000]; /* Should be max remote packet size or so.  */
-  gdb_byte byte;
-  int bytes, i;
-  struct trace_status *ts;
-  struct uploaded_tp *uploaded_tps = NULL;
-  struct uploaded_tsv *uploaded_tsvs = NULL;
-
-  target_preopen (from_tty);
-  if (!filename)
-    error (_("No trace file specified."));
-
-  filename = tilde_expand (filename);
-  if (!IS_ABSOLUTE_PATH(filename))
-    {
-      temp = concat (current_directory, "/", filename, (char *) NULL);
-      xfree (filename);
-      filename = temp;
-    }
-
-  old_chain = make_cleanup (xfree, filename);
-
-  flags = O_BINARY | O_LARGEFILE;
-  flags |= O_RDONLY;
-  scratch_chan = gdb_open_cloexec (filename, flags, 0);
-  if (scratch_chan < 0)
-    perror_with_name (filename);
-
-  /* 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_fd = scratch_chan;
-
-  bytes = 0;
-  /* Read the file header and test for validity.  */
-  tfile_read ((gdb_byte *) &header, TRACE_HEADER_SIZE);
-
-  bytes += TRACE_HEADER_SIZE;
-  if (!(header[0] == 0x7f
-	&& (strncmp (header + 1, "TRACE0\n", 7) == 0)))
-    error (_("File is not a valid trace file."));
-
-  push_target (&tfile_ops);
-
-  trace_regblock_size = 0;
-  ts = current_trace_status ();
-  /* We know we're working with a file.  Record its name.  */
-  ts->filename = trace_filename;
-  /* Set defaults in case there is no status line.  */
-  ts->running_known = 0;
-  ts->stop_reason = trace_stop_reason_unknown;
-  ts->traceframe_count = -1;
-  ts->buffer_free = 0;
-  ts->disconnected_tracing = 0;
-  ts->circular_buffer = 0;
-
-  TRY_CATCH (ex, RETURN_MASK_ALL)
-    {
-      /* Read through a section of newline-terminated lines that
-	 define things like tracepoints.  */
-      i = 0;
-      while (1)
-	{
-	  tfile_read (&byte, 1);
-
-	  ++bytes;
-	  if (byte == '\n')
-	    {
-	      /* Empty line marks end of the definition section.  */
-	      if (i == 0)
-		break;
-	      linebuf[i] = '\0';
-	      i = 0;
-	      tfile_interp_line (linebuf, &uploaded_tps, &uploaded_tsvs);
-	    }
-	  else
-	    linebuf[i++] = byte;
-	  if (i >= 1000)
-	    error (_("Excessively long lines in trace file"));
-	}
-
-      /* Record the starting offset of the binary trace data.  */
-      trace_frames_offset = bytes;
-
-      /* If we don't have a blocksize, we can't interpret the
-	 traceframes.  */
-      if (trace_regblock_size == 0)
-	error (_("No register block size recorded in trace file"));
-    }
-  if (ex.reason < 0)
-    {
-      /* Remove the partially set up target.  */
-      unpush_target (&tfile_ops);
-      throw_exception (ex);
-    }
-
-  inferior_appeared (current_inferior (), TFILE_PID);
-  inferior_ptid = pid_to_ptid (TFILE_PID);
-  add_thread_silent (inferior_ptid);
-
-  if (ts->traceframe_count <= 0)
-    warning (_("No traceframes present in this file."));
-
-  /* Add the file's tracepoints and variables into the current mix.  */
-
-  /* Get trace state variables first, they may be checked when parsing
-     uploaded commands.  */
-  merge_uploaded_trace_state_variables (&uploaded_tsvs);
-
-  merge_uploaded_tracepoints (&uploaded_tps);
-
-  post_create_inferior (&tfile_ops, from_tty);
-}
-
-/* Interpret the given line from the definitions part of the trace
-   file.  */
-
-static void
-tfile_interp_line (char *line, struct uploaded_tp **utpp,
-		   struct uploaded_tsv **utsvp)
-{
-  char *p = line;
-
-  if (strncmp (p, "R ", strlen ("R ")) == 0)
-    {
-      p += strlen ("R ");
-      trace_regblock_size = strtol (p, &p, 16);
-    }
-  else if (strncmp (p, "status ", strlen ("status ")) == 0)
-    {
-      p += strlen ("status ");
-      parse_trace_status (p, current_trace_status ());
-    }
-  else if (strncmp (p, "tp ", strlen ("tp ")) == 0)
-    {
-      p += strlen ("tp ");
-      parse_tracepoint_definition (p, utpp);
-    }
-  else if (strncmp (p, "tsv ", strlen ("tsv ")) == 0)
-    {
-      p += strlen ("tsv ");
-      parse_tsv_definition (p, utsvp);
-    }
-  else
-    warning (_("Ignoring trace file definition \"%s\""), line);
-}
-
 /* Parse the part of trace status syntax that is shared between
    the remote protocol and the trace file reader.  */
 
@@ -4092,614 +3895,6 @@ parse_tsv_definition (char *line, struct uploaded_tsv **utsvp)
   utsv->name = xstrdup (buf);
 }
 
-/* Close the trace file and generally clean up.  */
-
-static void
-tfile_close (void)
-{
-  int pid;
-
-  if (trace_fd < 0)
-    return;
-
-  pid = ptid_get_pid (inferior_ptid);
-  inferior_ptid = null_ptid;	/* Avoid confusion from thread stuff.  */
-  exit_inferior_silent (pid);
-
-  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)
-{
-  printf_filtered ("\t`%s'\n", trace_filename);
-}
-
-/* The trace status for a file is that tracing can never be run.  */
-
-static int
-tfile_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.  */
-
-  return -1;
-}
-
-static void
-tfile_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.  */
-}
-
-/* Given the position of a traceframe in the file, figure out what
-   address the frame was collected at.  This would normally be the
-   value of a collected PC register, but if not available, we
-   improvise.  */
-
-static CORE_ADDR
-tfile_get_traceframe_address (off_t tframe_offset)
-{
-  CORE_ADDR addr = 0;
-  short tpnum;
-  struct tracepoint *tp;
-  off_t saved_offset = cur_offset;
-
-  /* FIXME dig pc out of collected registers.  */
-
-  /* Fall back to using tracepoint address.  */
-  lseek (trace_fd, tframe_offset, SEEK_SET);
-  tfile_read ((gdb_byte *) &tpnum, 2);
-  tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
-					  gdbarch_byte_order
-					      (target_gdbarch ()));
-
-  tp = get_tracepoint_by_number_on_target (tpnum);
-  /* FIXME this is a poor heuristic if multiple locations.  */
-  if (tp && tp->base.loc)
-    addr = tp->base.loc->address;
-
-  /* Restore our seek position.  */
-  cur_offset = saved_offset;
-  lseek (trace_fd, cur_offset, SEEK_SET);
-  return addr;
-}
-
-/* Given a type of search and some parameters, scan the collection of
-   traceframes in the file looking for a match.  When found, return
-   both the traceframe and tracepoint number, otherwise -1 for
-   each.  */
-
-static int
-tfile_trace_find (enum trace_find_type type, int num,
-		  CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
-{
-  short tpnum;
-  int tfnum = 0, found = 0;
-  unsigned int data_size;
-  struct tracepoint *tp;
-  off_t offset, tframe_offset;
-  CORE_ADDR tfaddr;
-
-  if (num == -1)
-    {
-      if (tpp)
-        *tpp = -1;
-      return -1;
-    }
-
-  lseek (trace_fd, trace_frames_offset, SEEK_SET);
-  offset = trace_frames_offset;
-  while (1)
-    {
-      tframe_offset = offset;
-      tfile_read ((gdb_byte *) &tpnum, 2);
-      tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2,
-					      gdbarch_byte_order
-						  (target_gdbarch ()));
-      offset += 2;
-      if (tpnum == 0)
-	break;
-      tfile_read ((gdb_byte *) &data_size, 4);
-      data_size = (unsigned int) extract_unsigned_integer
-                                     ((gdb_byte *) &data_size, 4,
-				      gdbarch_byte_order (target_gdbarch ()));
-      offset += 4;
-
-      if (type == tfind_number)
-	{
-	  /* Looking for a specific trace frame.  */
-	  if (tfnum == num)
-	    found = 1;
-	}
-      else
-	{
-	  /* Start from the _next_ trace frame.  */
-	  if (tfnum > traceframe_number)
-	    {
-	      switch (type)
-		{
-		case tfind_pc:
-		  tfaddr = tfile_get_traceframe_address (tframe_offset);
-		  if (tfaddr == addr1)
-		    found = 1;
-		  break;
-		case tfind_tp:
-		  tp = get_tracepoint (num);
-		  if (tp && tpnum == tp->number_on_target)
-		    found = 1;
-		  break;
-		case tfind_range:
-		  tfaddr = tfile_get_traceframe_address (tframe_offset);
-		  if (addr1 <= tfaddr && tfaddr <= addr2)
-		    found = 1;
-		  break;
-		case tfind_outside:
-		  tfaddr = tfile_get_traceframe_address (tframe_offset);
-		  if (!(addr1 <= tfaddr && tfaddr <= addr2))
-		    found = 1;
-		  break;
-		default:
-		  internal_error (__FILE__, __LINE__, _("unknown tfind type"));
-		}
-	    }
-	}
-
-      if (found)
-	{
-	  if (tpp)
-	    *tpp = tpnum;
-	  cur_offset = offset;
-	  cur_data_size = data_size;
-
-	  return tfnum;
-	}
-      /* Skip past the traceframe's data.  */
-      lseek (trace_fd, data_size, SEEK_CUR);
-      offset += data_size;
-      /* Update our own count of traceframes.  */
-      ++tfnum;
-    }
-  /* Did not find what we were looking for.  */
-  if (tpp)
-    *tpp = -1;
-  return -1;
-}
-
-/* Prototype of the callback passed to tframe_walk_blocks.  */
-typedef int (*walk_blocks_callback_func) (char blocktype, void *data);
-
-/* Callback for traceframe_walk_blocks, used to find a given block
-   type in a traceframe.  */
-
-static int
-match_blocktype (char blocktype, void *data)
-{
-  char *wantedp = data;
-
-  if (*wantedp == blocktype)
-    return 1;
-
-  return 0;
-}
-
-/* Walk over all traceframe block starting at POS offset from
-   CUR_OFFSET, and call CALLBACK for each block found, passing in DATA
-   unmodified.  If CALLBACK returns true, this returns the position in
-   the traceframe where the block is found, relative to the start of
-   the traceframe (cur_offset).  Returns -1 if no callback call
-   returned true, indicating that all blocks have been walked.  */
-
-static int
-traceframe_walk_blocks (walk_blocks_callback_func callback,
-			int pos, void *data)
-{
-  /* Iterate through a traceframe's blocks, looking for a block of the
-     requested type.  */
-
-  lseek (trace_fd, cur_offset + pos, SEEK_SET);
-  while (pos < cur_data_size)
-    {
-      unsigned short mlen;
-      char block_type;
-
-      tfile_read ((gdb_byte *) &block_type, 1);
-
-      ++pos;
-
-      if ((*callback) (block_type, data))
-	return pos;
-
-      switch (block_type)
-	{
-	case 'R':
-	  lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET);
-	  pos += trace_regblock_size;
-	  break;
-	case 'M':
-	  lseek (trace_fd, cur_offset + pos + 8, SEEK_SET);
-	  tfile_read ((gdb_byte *) &mlen, 2);
-          mlen = (unsigned short)
-                extract_unsigned_integer ((gdb_byte *) &mlen, 2,
-                                          gdbarch_byte_order
-                                              (target_gdbarch ()));
-	  lseek (trace_fd, mlen, SEEK_CUR);
-	  pos += (8 + 2 + mlen);
-	  break;
-	case 'V':
-	  lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET);
-	  pos += (4 + 8);
-	  break;
-	default:
-	  error (_("Unknown block type '%c' (0x%x) in trace frame"),
-		 block_type, block_type);
-	  break;
-	}
-    }
-
-  return -1;
-}
-
-/* Convenience wrapper around traceframe_walk_blocks.  Looks for the
-   position offset of a block of type TYPE_WANTED in the current trace
-   frame, starting at POS.  Returns -1 if no such block was found.  */
-
-static int
-traceframe_find_block_type (char type_wanted, int pos)
-{
-  return traceframe_walk_blocks (match_blocktype, pos, &type_wanted);
-}
-
-/* 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)
-{
-  struct gdbarch *gdbarch = get_regcache_arch (regcache);
-  int offset, regn, regsize, pc_regno;
-  gdb_byte *regs;
-
-  /* An uninitialized reg size says we're not going to be
-     successful at getting register blocks.  */
-  if (!trace_regblock_size)
-    return;
-
-  regs = alloca (trace_regblock_size);
-
-  if (traceframe_find_block_type ('R', 0) >= 0)
-    {
-      tfile_read (regs, trace_regblock_size);
-
-      /* Assume the block is laid out in GDB register number order,
-	 each register with the size that it has in GDB.  */
-      offset = 0;
-      for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
-	{
-	  regsize = register_size (gdbarch, regn);
-	  /* Make sure we stay within block bounds.  */
-	  if (offset + regsize >= trace_regblock_size)
-	    break;
-	  if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
-	    {
-	      if (regno == regn)
-		{
-		  regcache_raw_supply (regcache, regno, regs + offset);
-		  break;
-		}
-	      else if (regno == -1)
-		{
-		  regcache_raw_supply (regcache, regn, regs + offset);
-		}
-	    }
-	  offset += regsize;
-	}
-      return;
-    }
-
-  /* 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);
-
-  /* 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))
-    return;
-
-  if (regno == -1 || regno == pc_regno)
-    {
-      struct tracepoint *tp = get_tracepoint (tracepoint_number);
-
-      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;
-	    }
-
-	  store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
-				  gdbarch_byte_order (gdbarch),
-				  tp->base.loc->address);
-	  regcache_raw_supply (regcache, pc_regno, regs);
-	}
-    }
-}
-
-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)
-{
-  /* We're only doing regular memory for now.  */
-  if (object != TARGET_OBJECT_MEMORY)
-    return TARGET_XFER_E_IO;
-
-  if (readbuf == NULL)
-    error (_("tfile_xfer_partial: trace file is read-only"));
-
- if (traceframe_number != -1)
-    {
-      int pos = 0;
-
-      /* Iterate through the traceframe's blocks, looking for
-	 memory.  */
-      while ((pos = traceframe_find_block_type ('M', pos)) >= 0)
-	{
-	  ULONGEST maddr, amt;
-	  unsigned short mlen;
-	  enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
-
-	  tfile_read ((gdb_byte *) &maddr, 8);
-	  maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
-					    byte_order);
-	  tfile_read ((gdb_byte *) &mlen, 2);
-	  mlen = (unsigned short)
-	    extract_unsigned_integer ((gdb_byte *) &mlen, 2, byte_order);
-
-	  /* If the block includes the first part of the desired
-	     range, return as much it has; GDB will re-request the
-	     remainder, which might be in a different block of this
-	     trace frame.  */
-	  if (maddr <= offset && offset < (maddr + mlen))
-	    {
-	      amt = (maddr + mlen) - offset;
-	      if (amt > len)
-		amt = len;
-
-	      if (maddr != offset)
-	        lseek (trace_fd, offset - maddr, SEEK_CUR);
-	      tfile_read (readbuf, amt);
-	      *xfered_len = amt;
-	      return TARGET_XFER_OK;
-	    }
-
-	  /* Skip over this block.  */
-	  pos += (8 + 2 + mlen);
-	}
-    }
-
-  /* It's unduly pedantic to refuse to look at the executable for
-     read-only pieces; so do the equivalent of readonly regions aka
-     QTro packet.  */
-  /* FIXME account for relocation at some point.  */
-  if (exec_bfd)
-    {
-      asection *s;
-      bfd_size_type size;
-      bfd_vma vma;
-
-      for (s = exec_bfd->sections; s; s = s->next)
-	{
-	  if ((s->flags & SEC_LOAD) == 0
-	      || (s->flags & SEC_READONLY) == 0)
-	    continue;
-
-	  vma = s->vma;
-	  size = bfd_get_section_size (s);
-	  if (vma <= offset && offset < (vma + size))
-	    {
-	      ULONGEST amt;
-
-	      amt = (vma + size) - offset;
-	      if (amt > len)
-		amt = len;
-
-	      *xfered_len = bfd_get_section_contents (exec_bfd, s,
-						      readbuf, offset - vma, amt);
-	      return TARGET_XFER_OK;
-	    }
-	}
-    }
-
-  /* Indicate failure to find the requested memory block.  */
-  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 (int tsvnum, LONGEST *val)
-{
-  int pos;
-  int found = 0;
-
-  /* Iterate over blocks in current frame and find the last 'V'
-     block in which tsv number is TSVNUM.  In one trace frame, there
-     may be multiple 'V' blocks created for a given trace variable,
-     and the last matched 'V' block contains the updated value.  */
-  pos = 0;
-  while ((pos = traceframe_find_block_type ('V', pos)) >= 0)
-    {
-      int vnum;
-
-      tfile_read ((gdb_byte *) &vnum, 4);
-      vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4,
-					   gdbarch_byte_order
-					   (target_gdbarch ()));
-      if (tsvnum == vnum)
-	{
-	  tfile_read ((gdb_byte *) val, 8);
-	  *val = extract_signed_integer ((gdb_byte *) val, 8,
-					 gdbarch_byte_order
-					 (target_gdbarch ()));
-	  found = 1;
-	}
-      pos += (4 + 8);
-    }
-
-  return found;
-}
-
-static int
-tfile_has_all_memory (struct target_ops *ops)
-{
-  return 1;
-}
-
-static int
-tfile_has_memory (struct target_ops *ops)
-{
-  return 1;
-}
-
-static int
-tfile_has_stack (struct target_ops *ops)
-{
-  return traceframe_number != -1;
-}
-
-static int
-tfile_has_registers (struct target_ops *ops)
-{
-  return traceframe_number != -1;
-}
-
-static int
-tfile_thread_alive (struct target_ops *ops, ptid_t ptid)
-{
-  return 1;
-}
-
-/* Callback for traceframe_walk_blocks.  Builds a traceframe_info
-   object for the tfile target's current traceframe.  */
-
-static int
-build_traceframe_info (char blocktype, void *data)
-{
-  struct traceframe_info *info = data;
-
-  switch (blocktype)
-    {
-    case 'M':
-      {
-	struct mem_range *r;
-	ULONGEST maddr;
-	unsigned short mlen;
-
-	tfile_read ((gdb_byte *) &maddr, 8);
-	maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8,
-					  gdbarch_byte_order
-					  (target_gdbarch ()));
-	tfile_read ((gdb_byte *) &mlen, 2);
-	mlen = (unsigned short)
-		extract_unsigned_integer ((gdb_byte *) &mlen,
-					  2, gdbarch_byte_order
-					  (target_gdbarch ()));
-
-	r = VEC_safe_push (mem_range_s, info->memory, NULL);
-
-	r->start = maddr;
-	r->length = mlen;
-	break;
-      }
-    case 'V':
-      {
-	int vnum;
-
-	tfile_read ((gdb_byte *) &vnum, 4);
-	VEC_safe_push (int, info->tvars, vnum);
-      }
-    case 'R':
-    case 'S':
-      {
-	break;
-      }
-    default:
-      warning (_("Unhandled trace block type (%d) '%c ' "
-		 "while building trace frame info."),
-	       blocktype, blocktype);
-      break;
-    }
-
-  return 0;
-}
-
-static struct traceframe_info *
-tfile_traceframe_info (void)
-{
-  struct traceframe_info *info = XCNEW (struct traceframe_info);
-
-  traceframe_walk_blocks (build_traceframe_info, 0, info);
-  return info;
-}
-
-static void
-init_tfile_ops (void)
-{
-  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_trace_status = tfile_get_trace_status;
-  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_stratum = process_stratum;
-  tfile_ops.to_has_all_memory = tfile_has_all_memory;
-  tfile_ops.to_has_memory = tfile_has_memory;
-  tfile_ops.to_has_stack = tfile_has_stack;
-  tfile_ops.to_has_registers = tfile_has_registers;
-  tfile_ops.to_traceframe_info = tfile_traceframe_info;
-  tfile_ops.to_thread_alive = tfile_thread_alive;
-  tfile_ops.to_magic = OPS_MAGIC;
-}
-
 void
 free_current_marker (void *arg)
 {
@@ -5361,8 +4556,4 @@ Set notes string to use for future tstop commands"), _("\
 Show the notes string to use for future tstop commands"), NULL,
 			  set_trace_stop_notes, NULL,
 			  &setlist, &showlist);
-
-  init_tfile_ops ();
-
-  add_target_with_completer (&tfile_ops, filename_completer);
 }
-- 
1.7.7.6



More information about the Gdb-patches mailing list