X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftracefile-tfile.c;h=cc77b6c610846db16e44667f007ccec09018fb6c;hb=4cdd21a8d3fd943d6993e9d053edf09583802744;hp=3ef109eb158469aaef381501a1823175cf50d9ef;hpb=a283690eb7320dfe4074301c673f6cc3dd21fb11;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c index 3ef109eb15..cc77b6c610 100644 --- a/gdb/tracefile-tfile.c +++ b/gdb/tracefile-tfile.c @@ -1,6 +1,6 @@ /* Trace file TFILE format support in GDB. - Copyright (C) 1997-2014 Free Software Foundation, Inc. + Copyright (C) 1997-2017 Free Software Foundation, Inc. This file is part of GDB. @@ -28,6 +28,11 @@ #include "exec.h" /* exec_bfd */ #include "completer.h" #include "filenames.h" +#include "remote.h" +#include "xml-tdesc.h" +#include "target-descriptions.h" +#include "buffer.h" +#include #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -84,7 +89,7 @@ tfile_start (struct trace_file_writer *self, const char *filename) = (struct tfile_trace_file_writer *) self; writer->pathname = tilde_expand (filename); - writer->fp = gdb_fopen_cloexec (writer->pathname, "wb"); + writer->fp = gdb_fopen_cloexec (writer->pathname, "wb").release (); if (writer->fp == NULL) error (_("Unable to open file '%s' for saving trace data (%s)"), writer->pathname, safe_strerror (errno)); @@ -133,7 +138,7 @@ tfile_write_status (struct trace_file_writer *self, fprintf (writer->fp, "status %c;%s", (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]); if (ts->stop_reason == tracepoint_error - || ts->stop_reason == tstop_command) + || ts->stop_reason == trace_stop_command) { char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1); @@ -187,7 +192,7 @@ static void tfile_write_uploaded_tsv (struct trace_file_writer *self, struct uploaded_tsv *utsv) { - char *buf = ""; + char *buf = NULL; struct tfile_trace_file_writer *writer = (struct tfile_trace_file_writer *) self; @@ -199,7 +204,7 @@ tfile_write_uploaded_tsv (struct trace_file_writer *self, fprintf (writer->fp, "tsv %x:%s:%x:%s\n", utsv->number, phex_nz (utsv->initial_value, 8), - utsv->builtin, buf); + utsv->builtin, buf != NULL ? buf : ""); if (utsv->name) xfree (buf); @@ -262,6 +267,42 @@ tfile_write_uploaded_tp (struct trace_file_writer *self, sizeof (utp->traceframe_usage))); } +/* This is the implementation of trace_file_write_ops method + write_tdesc. */ + +static void +tfile_write_tdesc (struct trace_file_writer *self) +{ + struct tfile_trace_file_writer *writer + = (struct tfile_trace_file_writer *) self; + + gdb::optional tdesc + = target_fetch_description_xml (¤t_target); + + if (!tdesc) + return; + + const char *ptr = tdesc->c_str (); + + /* Write tdesc line by line, prefixing each line with "tdesc ". */ + while (ptr != NULL) + { + const char *next = strchr (ptr, '\n'); + if (next != NULL) + { + fprintf (writer->fp, "tdesc %.*s\n", (int) (next - ptr), ptr); + /* Skip the \n. */ + next++; + } + else if (*ptr != '\0') + { + /* Last line, doesn't have a newline. */ + fprintf (writer->fp, "tdesc %s\n", ptr); + } + ptr = next; + } +} + /* This is the implementation of trace_file_write_ops method write_definition_end. */ @@ -315,6 +356,7 @@ static const struct trace_file_write_ops tfile_write_ops = tfile_write_status, tfile_write_uploaded_tsv, tfile_write_uploaded_tp, + tfile_write_tdesc, tfile_write_definition_end, tfile_write_raw_data, NULL, @@ -327,7 +369,7 @@ struct trace_file_writer * tfile_trace_file_writer_new (void) { struct tfile_trace_file_writer *writer - = xmalloc (sizeof (struct tfile_trace_file_writer)); + = XNEW (struct tfile_trace_file_writer); writer->base.ops = &tfile_write_ops; writer->fp = NULL; @@ -352,7 +394,9 @@ static off_t trace_frames_offset; static off_t cur_offset; static int cur_data_size; int trace_regblock_size; +static struct buffer trace_tdesc; +static void tfile_append_tdesc_line (const char *line); static void tfile_interp_line (char *line, struct uploaded_tp **utpp, struct uploaded_tsv **utsvp); @@ -376,11 +420,9 @@ tfile_read (gdb_byte *readbuf, int size) } static void -tfile_open (char *filename, int from_tty) +tfile_open (const char *arg, int from_tty) { - volatile struct gdb_exception ex; char *temp; - struct cleanup *old_chain; int flags; int scratch_chan; char header[TRACE_HEADER_SIZE]; @@ -392,40 +434,37 @@ tfile_open (char *filename, int from_tty) struct uploaded_tsv *uploaded_tsvs = NULL; target_preopen (from_tty); - if (!filename) + if (!arg) 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); + gdb::unique_xmalloc_ptr filename (tilde_expand (arg)); + if (!IS_ABSOLUTE_PATH (filename.get ())) + filename.reset (concat (current_directory, "/", filename.get (), + (char *) NULL)); flags = O_BINARY | O_LARGEFILE; flags |= O_RDONLY; - scratch_chan = gdb_open_cloexec (filename, flags, 0); + scratch_chan = gdb_open_cloexec (filename.get (), flags, 0); if (scratch_chan < 0) - perror_with_name (filename); + perror_with_name (filename.get ()); /* Looks semi-reasonable. Toss the old trace file and work on the new. */ - discard_cleanups (old_chain); /* Don't free filename any more. */ unpush_target (&tfile_ops); - trace_filename = xstrdup (filename); + trace_filename = filename.release (); trace_fd = scratch_chan; + /* Make sure this is clear. */ + buffer_free (&trace_tdesc); + 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))) + && (startswith (header + 1, "TRACE0\n")))) error (_("File is not a valid trace file.")); push_target (&tfile_ops); @@ -442,7 +481,7 @@ tfile_open (char *filename, int from_tty) ts->disconnected_tracing = 0; ts->circular_buffer = 0; - TRY_CATCH (ex, RETURN_MASK_ALL) + TRY { /* Read through a section of newline-terminated lines that define things like tracepoints. */ @@ -467,6 +506,9 @@ tfile_open (char *filename, int from_tty) error (_("Excessively long lines in trace file")); } + /* By now, tdesc lines have been read from tfile - let's parse them. */ + target_find_description (); + /* Record the starting offset of the binary trace data. */ trace_frames_offset = bytes; @@ -475,12 +517,13 @@ tfile_open (char *filename, int from_tty) if (trace_regblock_size == 0) error (_("No register block size recorded in trace file")); } - if (ex.reason < 0) + CATCH (ex, RETURN_MASK_ALL) { /* Remove the partially set up target. */ unpush_target (&tfile_ops); throw_exception (ex); } + END_CATCH inferior_appeared (current_inferior (), TFILE_PID); inferior_ptid = pid_to_ptid (TFILE_PID); @@ -509,26 +552,31 @@ tfile_interp_line (char *line, struct uploaded_tp **utpp, { char *p = line; - if (strncmp (p, "R ", strlen ("R ")) == 0) + if (startswith (p, "R ")) { p += strlen ("R "); trace_regblock_size = strtol (p, &p, 16); } - else if (strncmp (p, "status ", strlen ("status ")) == 0) + else if (startswith (p, "status ")) { p += strlen ("status "); parse_trace_status (p, current_trace_status ()); } - else if (strncmp (p, "tp ", strlen ("tp ")) == 0) + else if (startswith (p, "tp ")) { p += strlen ("tp "); parse_tracepoint_definition (p, utpp); } - else if (strncmp (p, "tsv ", strlen ("tsv ")) == 0) + else if (startswith (p, "tsv ")) { p += strlen ("tsv "); parse_tsv_definition (p, utsvp); } + else if (startswith (p, "tdesc ")) + { + p += strlen ("tdesc "); + tfile_append_tdesc_line (p); + } else warning (_("Ignoring trace file definition \"%s\""), line); } @@ -551,6 +599,7 @@ tfile_close (struct target_ops *self) trace_fd = -1; xfree (trace_filename); trace_filename = NULL; + buffer_free (&trace_tdesc); trace_reset_local_state (); } @@ -593,8 +642,8 @@ tfile_get_traceframe_address (off_t tframe_offset) 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; + if (tp && tp->loc) + addr = tp->loc->address; /* Restore our seek position. */ cur_offset = saved_offset; @@ -712,7 +761,7 @@ typedef int (*walk_blocks_callback_func) (char blocktype, void *data); static int match_blocktype (char blocktype, void *data) { - char *wantedp = data; + char *wantedp = (char *) data; if (*wantedp == blocktype) return 1; @@ -795,28 +844,28 @@ 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; + int offset, regn, regsize, dummy; /* 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) { + gdb_byte *regs = (gdb_byte *) alloca (trace_regblock_size); + 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++) { + if (!remote_register_number_and_offset (get_regcache_arch (regcache), + regn, &dummy, &offset)) + continue; + regsize = register_size (gdbarch, regn); /* Make sure we stay within block bounds. */ - if (offset + regsize >= trace_regblock_size) + if (offset + regsize > trace_regblock_size) break; if (regcache_register_status (regcache, regn) == REG_UNKNOWN) { @@ -830,58 +879,37 @@ tfile_fetch_registers (struct target_ops *ops, regcache_raw_supply (regcache, regn, regs + offset); } } - offset += regsize; } - return; } + else + tracefile_fetch_registers (regcache, regno); +} - /* 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; +static enum target_xfer_status +tfile_xfer_partial_features (struct target_ops *ops, const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) +{ + if (strcmp (annex, "target.xml")) + return TARGET_XFER_E_IO; - if (regno == -1 || regno == pc_regno) - { - struct tracepoint *tp = get_tracepoint (get_tracepoint_number ()); + if (readbuf == NULL) + error (_("tfile_xfer_partial: tdesc is read-only")); - 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; - } + if (trace_tdesc.used_size == 0) + return TARGET_XFER_E_IO; - store_unsigned_integer (regs, register_size (gdbarch, pc_regno), - gdbarch_byte_order (gdbarch), - tp->base.loc->address); - regcache_raw_supply (regcache, pc_regno, regs); - } - } + if (offset >= trace_tdesc.used_size) + return TARGET_XFER_EOF; + + if (len > trace_tdesc.used_size - offset) + len = trace_tdesc.used_size - offset; + + memcpy (readbuf, trace_tdesc.buffer + offset, len); + *xfered_len = len; + + return TARGET_XFER_OK; } static enum target_xfer_status @@ -890,7 +918,10 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, const gdb_byte *writebuf, ULONGEST offset, ULONGEST len, ULONGEST *xfered_len) { - /* We're only doing regular memory for now. */ + /* We're only doing regular memory and tdesc for now. */ + if (object == TARGET_OBJECT_AVAILABLE_FEATURES) + return tfile_xfer_partial_features (ops, annex, readbuf, writebuf, + offset, len, xfered_len); if (object != TARGET_OBJECT_MEMORY) return TARGET_XFER_E_IO; @@ -900,6 +931,10 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, if (get_traceframe_number () != -1) { int pos = 0; + enum target_xfer_status res; + /* Records the lowest available address of all blocks that + intersects the requested range. */ + ULONGEST low_addr_available = 0; /* Iterate through the traceframe's blocks, looking for memory. */ @@ -933,46 +968,37 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, return TARGET_XFER_OK; } + if (offset < maddr && maddr < (offset + len)) + if (low_addr_available == 0 || low_addr_available > maddr) + low_addr_available = maddr; + /* 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; + /* Requested memory is unavailable in the context of traceframes, + and this address falls within a read-only section, fallback + to reading from executable, up to LOW_ADDR_AVAILABLE. */ + if (offset < low_addr_available) + len = std::min (len, low_addr_available - offset); + res = exec_read_partial_read_only (readbuf, offset, len, xfered_len); - for (s = exec_bfd->sections; s; s = s->next) + if (res == TARGET_XFER_OK) + return TARGET_XFER_OK; + else { - 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; - } + /* No use trying further, we know some memory starting + at MEMADDR isn't available. */ + *xfered_len = len; + return TARGET_XFER_UNAVAILABLE; } } - - /* Indicate failure to find the requested memory block. */ - return TARGET_XFER_E_IO; + else + { + /* Fallback to reading from read-only sections. */ + return section_table_read_available_memory (readbuf, offset, len, + xfered_len); + } } /* Iterate through the blocks of a trace frame, looking for a 'V' @@ -1018,13 +1044,12 @@ tfile_get_trace_state_variable_value (struct target_ops *self, static int build_traceframe_info (char blocktype, void *data) { - struct traceframe_info *info = data; + struct traceframe_info *info = (struct traceframe_info *) data; switch (blocktype) { case 'M': { - struct mem_range *r; ULONGEST maddr; unsigned short mlen; @@ -1038,10 +1063,7 @@ build_traceframe_info (char blocktype, void *data) 2, gdbarch_byte_order (target_gdbarch ())); - r = VEC_safe_push (mem_range_s, info->memory, NULL); - - r->start = maddr; - r->length = mlen; + info->memory.emplace_back (maddr, mlen); break; } case 'V': @@ -1049,7 +1071,7 @@ build_traceframe_info (char blocktype, void *data) int vnum; tfile_read ((gdb_byte *) &vnum, 4); - VEC_safe_push (int, info->tvars, vnum); + info->tvars.push_back (vnum); } case 'R': case 'S': @@ -1069,12 +1091,22 @@ build_traceframe_info (char blocktype, void *data) static struct traceframe_info * tfile_traceframe_info (struct target_ops *self) { - struct traceframe_info *info = XCNEW (struct traceframe_info); + traceframe_info *info = new traceframe_info; traceframe_walk_blocks (build_traceframe_info, 0, info); return info; } +/* Handles tdesc lines from tfile by appending the payload to + a global trace_tdesc variable. */ + +static void +tfile_append_tdesc_line (const char *line) +{ + buffer_grow_str (&trace_tdesc, line); + buffer_grow_str (&trace_tdesc, "\n"); +} + static void init_tfile_ops (void) { @@ -1096,8 +1128,6 @@ init_tfile_ops (void) tfile_ops.to_traceframe_info = tfile_traceframe_info; } -extern initialize_file_ftype _initialize_tracefile_tfile; - void _initialize_tracefile_tfile (void) {