X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Ftracefile-tfile.c;h=c1a4a49337246e34d9586e4a2a8d8db836002d92;hb=5b6d1e4fa4fc6827c7b3f0e99ff120dfa14d65d2;hp=9747036b871421bc7d722337a1e13651e6f47dca;hpb=492d29ea1c9a8b2c7d5193908119a4e27c045687;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/tracefile-tfile.c b/gdb/tracefile-tfile.c index 9747036b87..c1a4a49337 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-2015 Free Software Foundation, Inc. + Copyright (C) 1997-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -20,19 +20,58 @@ #include "defs.h" #include "tracefile.h" #include "readline/tilde.h" -#include "filestuff.h" -#include "rsp-low.h" /* bin2hex */ +#include "gdbsupport/filestuff.h" +#include "gdbsupport/rsp-low.h" /* bin2hex */ #include "regcache.h" #include "inferior.h" #include "gdbthread.h" #include "exec.h" /* exec_bfd */ #include "completer.h" #include "filenames.h" +#include "remote.h" +#include "xml-tdesc.h" +#include "target-descriptions.h" +#include "gdbsupport/buffer.h" +#include "gdbsupport/pathstuff.h" +#include #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif +/* The tfile target. */ + +static const target_info tfile_target_info = { + "tfile", + N_("Local trace dump file"), + N_("Use a trace file as a target.\n\ +Specify the filename of the trace file.") +}; + +class tfile_target final : public tracefile_target +{ + public: + const target_info &info () const override + { return tfile_target_info; } + + void close () override; + void fetch_registers (struct regcache *, int) override; + enum target_xfer_status xfer_partial (enum target_object object, + const char *annex, + gdb_byte *readbuf, + const gdb_byte *writebuf, + ULONGEST offset, ULONGEST len, + ULONGEST *xfered_len) override; + void files_info () override; + int trace_find (enum trace_find_type type, int num, + CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) override; + bool get_trace_state_variable_value (int tsv, LONGEST *val) override; + traceframe_info_up traceframe_info () override; + + void get_tracepoint_status (struct breakpoint *tp, + struct uploaded_tp *utp) override; +}; + /* TFILE trace writer. */ struct tfile_trace_file_writer @@ -84,7 +123,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 +172,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 +226,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 +238,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); @@ -216,8 +255,6 @@ tfile_write_uploaded_tp (struct trace_file_writer *self, { struct tfile_trace_file_writer *writer = (struct tfile_trace_file_writer *) self; - int a; - char *act; char buf[MAX_TRACE_UPLOAD]; fprintf (writer->fp, "tp T%x:%s:%c:%x:%x", @@ -227,31 +264,32 @@ tfile_write_uploaded_tp (struct trace_file_writer *self, fprintf (writer->fp, ":F%x", utp->orig_size); if (utp->cond) fprintf (writer->fp, - ":X%x,%s", (unsigned int) strlen (utp->cond) / 2, - utp->cond); + ":X%x,%s", (unsigned int) strlen (utp->cond.get ()) / 2, + utp->cond.get ()); fprintf (writer->fp, "\n"); - for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a) + for (const auto &act : utp->actions) fprintf (writer->fp, "tp A%x:%s:%s\n", - utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act); - for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a) + utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ()); + for (const auto &act : utp->step_actions) fprintf (writer->fp, "tp S%x:%s:%s\n", - utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act); + utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act.get ()); if (utp->at_string) { encode_source_string (utp->number, utp->addr, - "at", utp->at_string, buf, MAX_TRACE_UPLOAD); + "at", utp->at_string.get (), + buf, MAX_TRACE_UPLOAD); fprintf (writer->fp, "tp Z%s\n", buf); } if (utp->cond_string) { encode_source_string (utp->number, utp->addr, - "cond", utp->cond_string, + "cond", utp->cond_string.get (), buf, MAX_TRACE_UPLOAD); fprintf (writer->fp, "tp Z%s\n", buf); } - for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a) + for (const auto &act : utp->cmd_strings) { - encode_source_string (utp->number, utp->addr, "cmd", act, + encode_source_string (utp->number, utp->addr, "cmd", act.get (), buf, MAX_TRACE_UPLOAD); fprintf (writer->fp, "tp Z%s\n", buf); } @@ -262,6 +300,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 (current_top_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 +389,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 +402,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; @@ -338,9 +413,7 @@ tfile_trace_file_writer_new (void) /* target tfile command */ -static struct target_ops tfile_ops; - -/* Fill in tfile_ops with its defined operations and properties. */ +static tfile_target tfile_ops; #define TRACE_HEADER_SIZE 8 @@ -352,7 +425,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); @@ -375,11 +450,11 @@ tfile_read (gdb_byte *readbuf, int size) error (_("Premature end of file while reading trace file")); } +/* Open the tfile target. */ + static void -tfile_open (const char *arg, int from_tty) +tfile_target_open (const char *arg, int from_tty) { - char *temp; - struct cleanup *old_chain; int flags; int scratch_chan; char header[TRACE_HEADER_SIZE]; @@ -389,36 +464,31 @@ tfile_open (const char *arg, int from_tty) struct trace_status *ts; struct uploaded_tp *uploaded_tps = NULL; struct uploaded_tsv *uploaded_tsvs = NULL; - char *filename; target_preopen (from_tty); if (!arg) error (_("No trace file specified.")); - filename = tilde_expand (arg); - 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 = gdb_abspath (filename.get ()); 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); @@ -442,7 +512,7 @@ tfile_open (const char *arg, int from_tty) ts->disconnected_tracing = 0; ts->circular_buffer = 0; - TRY + try { /* Read through a section of newline-terminated lines that define things like tracepoints. */ @@ -467,6 +537,9 @@ tfile_open (const char *arg, 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,17 +548,16 @@ tfile_open (const char *arg, int from_tty) if (trace_regblock_size == 0) error (_("No register block size recorded in trace file")); } - CATCH (ex, RETURN_MASK_ALL) + catch (const gdb_exception &ex) { /* Remove the partially set up target. */ unpush_target (&tfile_ops); - throw_exception (ex); + throw; } - END_CATCH inferior_appeared (current_inferior (), TFILE_PID); - inferior_ptid = pid_to_ptid (TFILE_PID); - add_thread_silent (inferior_ptid); + inferior_ptid = ptid_t (TFILE_PID); + add_thread_silent (&tfile_ops, inferior_ptid); if (ts->traceframe_count <= 0) warning (_("No traceframes present in this file.")); @@ -530,41 +602,42 @@ tfile_interp_line (char *line, struct uploaded_tp **utpp, 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); } /* Close the trace file and generally clean up. */ -static void -tfile_close (struct target_ops *self) +void +tfile_target::close () { - int pid; + gdb_assert (trace_fd != -1); - if (trace_fd < 0) - return; - - pid = ptid_get_pid (inferior_ptid); inferior_ptid = null_ptid; /* Avoid confusion from thread stuff. */ - exit_inferior_silent (pid); + exit_inferior_silent (current_inferior ()); - close (trace_fd); + ::close (trace_fd); trace_fd = -1; xfree (trace_filename); trace_filename = NULL; + buffer_free (&trace_tdesc); trace_reset_local_state (); } -static void -tfile_files_info (struct target_ops *t) +void +tfile_target::files_info () { printf_filtered ("\t`%s'\n", trace_filename); } -static void -tfile_get_tracepoint_status (struct target_ops *self, - struct breakpoint *tp, struct uploaded_tp *utp) +void +tfile_target::get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp) { /* Other bits of trace status were collected as part of opening the trace files, so nothing to do here. */ @@ -594,8 +667,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; @@ -608,9 +681,9 @@ tfile_get_traceframe_address (off_t tframe_offset) 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) +int +tfile_target::trace_find (enum trace_find_type type, int num, + CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) { short tpnum; int tfnum = 0, found = 0; @@ -713,7 +786,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; @@ -791,12 +864,11 @@ traceframe_find_block_type (char type_wanted, int pos) /* 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) +void +tfile_target::fetch_registers (struct regcache *regcache, int regno) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); - int offset, regn, regsize; + struct gdbarch *gdbarch = regcache->arch (); + int offset, regn, regsize, dummy; /* An uninitialized reg size says we're not going to be successful at getting register blocks. */ @@ -805,32 +877,32 @@ tfile_fetch_registers (struct target_ops *ops, if (traceframe_find_block_type ('R', 0) >= 0) { - gdb_byte *regs = alloca (trace_regblock_size); + 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 (regcache->arch (), + 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) + if (regcache->get_register_status (regn) == REG_UNKNOWN) { if (regno == regn) { - regcache_raw_supply (regcache, regno, regs + offset); + regcache->raw_supply (regno, regs + offset); break; } else if (regno == -1) { - regcache_raw_supply (regcache, regn, regs + offset); + regcache->raw_supply (regn, regs + offset); } } - offset += regsize; } } else @@ -838,12 +910,42 @@ tfile_fetch_registers (struct target_ops *ops, } 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) +tfile_xfer_partial_features (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 (readbuf == NULL) + error (_("tfile_xfer_partial: tdesc is read-only")); + + if (trace_tdesc.used_size == 0) + return TARGET_XFER_E_IO; + + 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; +} + +enum target_xfer_status +tfile_target::xfer_partial (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. */ + /* We're only doing regular memory and tdesc for now. */ + if (object == TARGET_OBJECT_AVAILABLE_FEATURES) + return tfile_xfer_partial_features (annex, readbuf, writebuf, + offset, len, xfered_len); if (object != TARGET_OBJECT_MEMORY) return TARGET_XFER_E_IO; @@ -902,7 +1004,7 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, 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 = min (len, low_addr_available - offset); + len = std::min (len, low_addr_available - offset); res = exec_read_partial_read_only (readbuf, offset, len, xfered_len); if (res == TARGET_XFER_OK) @@ -926,12 +1028,11 @@ tfile_xfer_partial (struct target_ops *ops, enum target_object object, /* 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) +bool +tfile_target::get_trace_state_variable_value (int tsvnum, LONGEST *val) { int pos; - int found = 0; + bool found = false; /* Iterate over blocks in current frame and find the last 'V' block in which tsv number is TSVNUM. In one trace frame, there @@ -952,7 +1053,7 @@ tfile_get_trace_state_variable_value (struct target_ops *self, *val = extract_signed_integer ((gdb_byte *) val, 8, gdbarch_byte_order (target_gdbarch ())); - found = 1; + found = true; } pos += (4 + 8); } @@ -966,13 +1067,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; @@ -986,10 +1086,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': @@ -997,7 +1094,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': @@ -1014,42 +1111,28 @@ build_traceframe_info (char blocktype, void *data) return 0; } -static struct traceframe_info * -tfile_traceframe_info (struct target_ops *self) +traceframe_info_up +tfile_target::traceframe_info () { - struct traceframe_info *info = XCNEW (struct traceframe_info); + traceframe_info_up info (new struct traceframe_info); + + traceframe_walk_blocks (build_traceframe_info, 0, info.get ()); - 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 -init_tfile_ops (void) +tfile_append_tdesc_line (const char *line) { - init_tracefile_ops (&tfile_ops); - - 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_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_traceframe_info = tfile_traceframe_info; + buffer_grow_str (&trace_tdesc, line); + buffer_grow_str (&trace_tdesc, "\n"); } -extern initialize_file_ftype _initialize_tracefile_tfile; - void _initialize_tracefile_tfile (void) { - init_tfile_ops (); - - add_target_with_completer (&tfile_ops, filename_completer); + add_target (tfile_target_info, tfile_target_open, filename_completer); }