From 11395323794268a9945dd31eb46905e975d87b3d Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Mon, 10 Feb 2014 14:38:26 +0800 Subject: [PATCH] Move tfile target to tracefile-tfile.c This patch moves tfile target related code from tracepoint.c to tracefile-tfile.c. gdb: 2014-02-23 Yao Qi * 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. --- gdb/ChangeLog | 27 ++ gdb/tracefile-tfile.c | 827 ++++++++++++++++++++++++++++++++++++++++++ gdb/tracepoint.c | 815 ----------------------------------------- 3 files changed, 854 insertions(+), 815 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2004167c53d..4db4f2fb772 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +2014-02-23 Yao Qi + + * 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 * Makefile.in (REMOTE_OBS): Append tracefile.o and diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c index 8a53e9d6eb7..0f4aa93a662 100644 --- a/gdb/tracefile-tfile.c +++ b/gdb/tracefile-tfile.c @@ -22,6 +22,16 @@ #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. */ @@ -325,3 +335,820 @@ 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 (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); +} diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 2b4c13778d3..23eba323b1c 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -67,10 +67,6 @@ #include -#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 @@ -81,8 +77,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); @@ -3571,201 +3565,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. */ @@ -4093,616 +3892,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 (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) { @@ -5364,8 +4553,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); } -- 2.30.2