+2014-02-23 Yao Qi <yao@codesourcery.com>
+
+ * tracepoint.c (TFILE_PID): Move it to tracefile-tfile.c.
+ (O_LARGEFILE): Likewise.
+ (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.
+
2014-02-23 Yao Qi <yao@codesourcery.com>
* Makefile.in (REMOTE_OBS): Append tracefile.o and
#include "readline/tilde.h"
#include "filestuff.h"
#include "rsp-low.h" /* bin2hex */
+#include "regcache.h"
+#include "inferior.h"
+#include "gdbthread.h"
+#include "exec.h" /* exec_bfd */
+#include "completer.h"
+#include "filenames.h"
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
/* TFILE trace writer. */
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 (struct target_ops *self)
+{
+ 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 target_ops *self, 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 target_ops *self,
+ 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 (struct target_ops *self, 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 (struct target_ops *self,
+ 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 (struct target_ops *self)
+{
+ 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);
+}
#include <unistd.h>
-#ifndef O_LARGEFILE
-#define O_LARGEFILE 0
-#endif
-
/* Maximum length of an agent aexpression.
This accounts for the fact that packets are limited to 400 bytes
(which includes everything -- including the checksum), and assumes
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);
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. */
utsv->name = xstrdup (buf);
}
-/* Close the trace file and generally clean up. */
-
-static void
-tfile_close (struct target_ops *self)
-{
- 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 target_ops *self, 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 target_ops *self,
- 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 (struct target_ops *self, 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 (struct target_ops *self,
- 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 (struct target_ops *self)
-{
- 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)
{
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);
}