X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Ftracepoint.c;h=bd3e9d07732c4fc7d26054c53047c5d27730fabb;hb=3b7344d5ab495cd82b6c72ec5e00d018549837fb;hp=4b472820e51edf79cbef8472d8445cb26594c64b;hpb=f8de51293246a17166da9a2744c1eb5ab956d67b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 4b472820e5..bd3e9d0773 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -55,6 +55,8 @@ #include "probe.h" #include "ctf.h" #include "filestuff.h" +#include "rsp-low.h" +#include "tracefile.h" /* readline include files */ #include "readline/readline.h" @@ -65,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 @@ -188,9 +186,6 @@ static char *mem2hex (gdb_byte *, char *, int); static void add_register (struct collection_list *collection, unsigned int regno); -static void free_uploaded_tps (struct uploaded_tp **utpp); -static void free_uploaded_tsvs (struct uploaded_tsv **utsvp); - static struct command_line * all_tracepoint_actions_and_cleanup (struct breakpoint *t); @@ -198,7 +193,7 @@ extern void _initialize_tracepoint (void); static struct trace_status trace_status; -char *stop_reason_names[] = { +const char *stop_reason_names[] = { "tunknown", "tnotrun", "tstop", @@ -2706,7 +2701,7 @@ scope_info (char *args, int from_tty) { struct symtabs_and_lines sals; struct symbol *sym; - struct minimal_symbol *msym; + struct bound_minimal_symbol msym; struct block *block; const char *symname; char *save_args = args; @@ -2829,14 +2824,14 @@ scope_info (char *args, int from_tty) case LOC_UNRESOLVED: msym = lookup_minimal_symbol (SYMBOL_LINKAGE_NAME (sym), NULL, NULL); - if (msym == NULL) + if (msym.minsym == NULL) printf_filtered ("Unresolved Static"); else { printf_filtered ("static storage at address "); printf_filtered ("%s", paddress (gdbarch, - SYMBOL_VALUE_ADDRESS (msym))); + MSYMBOL_VALUE_ADDRESS (msym.minsym))); } break; case LOC_OPTIMIZED_OUT: @@ -3089,668 +3084,10 @@ encode_source_string (int tpnum, ULONGEST addr, srctype, 0, (int) strlen (src)); if (strlen (buf) + strlen (src) * 2 >= buf_size) error (_("Source string too long for buffer")); - bin2hex ((gdb_byte *) src, buf + strlen (buf), 0); + bin2hex ((gdb_byte *) src, buf + strlen (buf), strlen (src)); return -1; } -/* Free trace file writer. */ - -static void -trace_file_writer_xfree (void *arg) -{ - struct trace_file_writer *writer = arg; - - writer->ops->dtor (writer); - xfree (writer); -} - -/* TFILE trace writer. */ - -struct tfile_trace_file_writer -{ - struct trace_file_writer base; - - /* File pointer to tfile trace file. */ - FILE *fp; - /* Path name of the tfile trace file. */ - char *pathname; -}; - -/* This is the implementation of trace_file_write_ops method - target_save. We just call the generic target - target_save_trace_data to do target-side saving. */ - -static int -tfile_target_save (struct trace_file_writer *self, - const char *filename) -{ - int err = target_save_trace_data (filename); - - return (err >= 0); -} - -/* This is the implementation of trace_file_write_ops method - dtor. */ - -static void -tfile_dtor (struct trace_file_writer *self) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - xfree (writer->pathname); - - if (writer->fp != NULL) - fclose (writer->fp); -} - -/* This is the implementation of trace_file_write_ops method - start. It creates the trace file FILENAME and registers some - cleanups. */ - -static void -tfile_start (struct trace_file_writer *self, const char *filename) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - writer->pathname = tilde_expand (filename); - writer->fp = gdb_fopen_cloexec (writer->pathname, "wb"); - if (writer->fp == NULL) - error (_("Unable to open file '%s' for saving trace data (%s)"), - writer->pathname, safe_strerror (errno)); -} - -/* This is the implementation of trace_file_write_ops method - write_header. Write the TFILE header. */ - -static void -tfile_write_header (struct trace_file_writer *self) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - int written; - - /* Write a file header, with a high-bit-set char to indicate a - binary file, plus a hint as what this file is, and a version - number in case of future needs. */ - written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp); - if (written < 1) - perror_with_name (writer->pathname); -} - -/* This is the implementation of trace_file_write_ops method - write_regblock_type. Write the size of register block. */ - -static void -tfile_write_regblock_type (struct trace_file_writer *self, int size) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - fprintf (writer->fp, "R %x\n", size); -} - -/* This is the implementation of trace_file_write_ops method - write_status. */ - -static void -tfile_write_status (struct trace_file_writer *self, - struct trace_status *ts) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_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) - { - char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1); - - bin2hex ((gdb_byte *) ts->stop_desc, buf, 0); - fprintf (writer->fp, ":%s", buf); - } - fprintf (writer->fp, ":%x", ts->stopping_tracepoint); - if (ts->traceframe_count >= 0) - fprintf (writer->fp, ";tframes:%x", ts->traceframe_count); - if (ts->traceframes_created >= 0) - fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created); - if (ts->buffer_free >= 0) - fprintf (writer->fp, ";tfree:%x", ts->buffer_free); - if (ts->buffer_size >= 0) - fprintf (writer->fp, ";tsize:%x", ts->buffer_size); - if (ts->disconnected_tracing) - fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing); - if (ts->circular_buffer) - fprintf (writer->fp, ";circular:%x", ts->circular_buffer); - if (ts->start_time) - { - fprintf (writer->fp, ";starttime:%s", - phex_nz (ts->start_time, sizeof (ts->start_time))); - } - if (ts->stop_time) - { - fprintf (writer->fp, ";stoptime:%s", - phex_nz (ts->stop_time, sizeof (ts->stop_time))); - } - if (ts->notes != NULL) - { - char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1); - - bin2hex ((gdb_byte *) ts->notes, buf, 0); - fprintf (writer->fp, ";notes:%s", buf); - } - if (ts->user_name != NULL) - { - char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1); - - bin2hex ((gdb_byte *) ts->user_name, buf, 0); - fprintf (writer->fp, ";username:%s", buf); - } - fprintf (writer->fp, "\n"); -} - -/* This is the implementation of trace_file_write_ops method - write_uploaded_tsv. */ - -static void -tfile_write_uploaded_tsv (struct trace_file_writer *self, - struct uploaded_tsv *utsv) -{ - char *buf = ""; - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - if (utsv->name) - { - buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1); - bin2hex ((gdb_byte *) (utsv->name), buf, 0); - } - - fprintf (writer->fp, "tsv %x:%s:%x:%s\n", - utsv->number, phex_nz (utsv->initial_value, 8), - utsv->builtin, buf); - - if (utsv->name) - xfree (buf); -} - -#define MAX_TRACE_UPLOAD 2000 - -/* This is the implementation of trace_file_write_ops method - write_uploaded_tp. */ - -static void -tfile_write_uploaded_tp (struct trace_file_writer *self, - struct uploaded_tp *utp) -{ - 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", - utp->number, phex_nz (utp->addr, sizeof (utp->addr)), - (utp->enabled ? 'E' : 'D'), utp->step, utp->pass); - if (utp->type == bp_fast_tracepoint) - 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); - fprintf (writer->fp, "\n"); - for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a) - 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) - fprintf (writer->fp, "tp S%x:%s:%s\n", - utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act); - if (utp->at_string) - { - encode_source_string (utp->number, utp->addr, - "at", utp->at_string, 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, - 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) - { - encode_source_string (utp->number, utp->addr, "cmd", act, - buf, MAX_TRACE_UPLOAD); - fprintf (writer->fp, "tp Z%s\n", buf); - } - fprintf (writer->fp, "tp V%x:%s:%x:%s\n", - utp->number, phex_nz (utp->addr, sizeof (utp->addr)), - utp->hit_count, - phex_nz (utp->traceframe_usage, - sizeof (utp->traceframe_usage))); -} - -/* This is the implementation of trace_file_write_ops method - write_definition_end. */ - -static void -tfile_write_definition_end (struct trace_file_writer *self) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - fprintf (writer->fp, "\n"); -} - -/* This is the implementation of trace_file_write_ops method - write_raw_data. */ - -static void -tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf, - LONGEST len) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - - if (fwrite (buf, len, 1, writer->fp) < 1) - perror_with_name (writer->pathname); -} - -/* This is the implementation of trace_file_write_ops method - end. */ - -static void -tfile_end (struct trace_file_writer *self) -{ - struct tfile_trace_file_writer *writer - = (struct tfile_trace_file_writer *) self; - uint32_t gotten = 0; - - /* Mark the end of trace data. */ - if (fwrite (&gotten, 4, 1, writer->fp) < 1) - perror_with_name (writer->pathname); -} - -/* Operations to write trace buffers into TFILE format. */ - -static const struct trace_file_write_ops tfile_write_ops = -{ - tfile_dtor, - tfile_target_save, - tfile_start, - tfile_write_header, - tfile_write_regblock_type, - tfile_write_status, - tfile_write_uploaded_tsv, - tfile_write_uploaded_tp, - tfile_write_definition_end, - tfile_write_raw_data, - NULL, - tfile_end, -}; - -/* Helper macros. */ - -#define TRACE_WRITE_R_BLOCK(writer, buf, size) \ - writer->ops->frame_ops->write_r_block ((writer), (buf), (size)) -#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \ - writer->ops->frame_ops->write_m_block_header ((writer), (addr), \ - (size)) -#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \ - writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \ - (size)) -#define TRACE_WRITE_V_BLOCK(writer, num, val) \ - writer->ops->frame_ops->write_v_block ((writer), (num), (val)) - -/* Save tracepoint data to file named FILENAME through WRITER. WRITER - determines the trace file format. If TARGET_DOES_SAVE is non-zero, - the save is performed on the target, otherwise GDB obtains all trace - data and saves it locally. */ - -static void -trace_save (const char *filename, struct trace_file_writer *writer, - int target_does_save) -{ - struct trace_status *ts = current_trace_status (); - int status; - struct uploaded_tp *uploaded_tps = NULL, *utp; - struct uploaded_tsv *uploaded_tsvs = NULL, *utsv; - - ULONGEST offset = 0; - gdb_byte buf[MAX_TRACE_UPLOAD]; -#define MAX_TRACE_UPLOAD 2000 - int written; - enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ()); - - /* If the target is to save the data to a file on its own, then just - send the command and be done with it. */ - if (target_does_save) - { - if (!writer->ops->target_save (writer, filename)) - error (_("Target failed to save trace data to '%s'."), - filename); - return; - } - - /* Get the trace status first before opening the file, so if the - target is losing, we can get out without touching files. */ - status = target_get_trace_status (ts); - - writer->ops->start (writer, filename); - - writer->ops->write_header (writer); - - /* Write descriptive info. */ - - /* Write out the size of a register block. */ - writer->ops->write_regblock_type (writer, trace_regblock_size); - - /* Write out status of the tracing run (aka "tstatus" info). */ - writer->ops->write_status (writer, ts); - - /* Note that we want to upload tracepoints and save those, rather - than simply writing out the local ones, because the user may have - changed tracepoints in GDB in preparation for a future tracing - run, or maybe just mass-deleted all types of breakpoints as part - of cleaning up. So as not to contaminate the session, leave the - data in its uploaded form, don't make into real tracepoints. */ - - /* Get trace state variables first, they may be checked when parsing - uploaded commands. */ - - target_upload_trace_state_variables (&uploaded_tsvs); - - for (utsv = uploaded_tsvs; utsv; utsv = utsv->next) - writer->ops->write_uploaded_tsv (writer, utsv); - - free_uploaded_tsvs (&uploaded_tsvs); - - target_upload_tracepoints (&uploaded_tps); - - for (utp = uploaded_tps; utp; utp = utp->next) - target_get_tracepoint_status (NULL, utp); - - for (utp = uploaded_tps; utp; utp = utp->next) - writer->ops->write_uploaded_tp (writer, utp); - - free_uploaded_tps (&uploaded_tps); - - /* Mark the end of the definition section. */ - writer->ops->write_definition_end (writer); - - /* Get and write the trace data proper. */ - while (1) - { - LONGEST gotten = 0; - - /* The writer supports writing the contents of trace buffer - directly to trace file. Don't parse the contents of trace - buffer. */ - if (writer->ops->write_trace_buffer != NULL) - { - /* We ask for big blocks, in the hopes of efficiency, but - will take less if the target has packet size limitations - or some such. */ - gotten = target_get_raw_trace_data (buf, offset, - MAX_TRACE_UPLOAD); - if (gotten < 0) - error (_("Failure to get requested trace buffer data")); - /* No more data is forthcoming, we're done. */ - if (gotten == 0) - break; - - writer->ops->write_trace_buffer (writer, buf, gotten); - - offset += gotten; - } - else - { - uint16_t tp_num; - uint32_t tf_size; - /* Parse the trace buffers according to how data are stored - in trace buffer in GDBserver. */ - - gotten = target_get_raw_trace_data (buf, offset, 6); - - if (gotten == 0) - break; - - /* Read the first six bytes in, which is the tracepoint - number and trace frame size. */ - tp_num = (uint16_t) - extract_unsigned_integer (&buf[0], 2, byte_order); - - tf_size = (uint32_t) - extract_unsigned_integer (&buf[2], 4, byte_order); - - writer->ops->frame_ops->start (writer, tp_num); - gotten = 6; - - if (tf_size > 0) - { - unsigned int block; - - offset += 6; - - for (block = 0; block < tf_size; ) - { - gdb_byte block_type; - - /* We'll fetch one block each time, in order to - handle the extremely large 'M' block. We first - fetch one byte to get the type of the block. */ - gotten = target_get_raw_trace_data (buf, offset, 1); - if (gotten < 1) - error (_("Failure to get requested trace buffer data")); - - gotten = 1; - block += 1; - offset += 1; - - block_type = buf[0]; - switch (block_type) - { - case 'R': - gotten - = target_get_raw_trace_data (buf, offset, - trace_regblock_size); - if (gotten < trace_regblock_size) - error (_("Failure to get requested trace" - " buffer data")); - - TRACE_WRITE_R_BLOCK (writer, buf, - trace_regblock_size); - break; - case 'M': - { - unsigned short mlen; - ULONGEST addr; - LONGEST t; - int j; - - t = target_get_raw_trace_data (buf,offset, 10); - if (t < 10) - error (_("Failure to get requested trace" - " buffer data")); - - offset += 10; - block += 10; - - gotten = 0; - addr = (ULONGEST) - extract_unsigned_integer (buf, 8, - byte_order); - mlen = (unsigned short) - extract_unsigned_integer (&buf[8], 2, - byte_order); - - TRACE_WRITE_M_BLOCK_HEADER (writer, addr, - mlen); - - /* The memory contents in 'M' block may be - very large. Fetch the data from the target - and write them into file one by one. */ - for (j = 0; j < mlen; ) - { - unsigned int read_length; - - if (mlen - j > MAX_TRACE_UPLOAD) - read_length = MAX_TRACE_UPLOAD; - else - read_length = mlen - j; - - t = target_get_raw_trace_data (buf, - offset + j, - read_length); - if (t < read_length) - error (_("Failure to get requested" - " trace buffer data")); - - TRACE_WRITE_M_BLOCK_MEMORY (writer, buf, - read_length); - - j += read_length; - gotten += read_length; - } - - break; - } - case 'V': - { - int vnum; - LONGEST val; - - gotten - = target_get_raw_trace_data (buf, offset, - 12); - if (gotten < 12) - error (_("Failure to get requested" - " trace buffer data")); - - vnum = (int) extract_signed_integer (buf, - 4, - byte_order); - val - = extract_signed_integer (&buf[4], 8, - byte_order); - - TRACE_WRITE_V_BLOCK (writer, vnum, val); - } - break; - default: - error (_("Unknown block type '%c' (0x%x) in" - " trace frame"), - block_type, block_type); - } - - block += gotten; - offset += gotten; - } - } - else - offset += gotten; - - writer->ops->frame_ops->end (writer); - } - } - - writer->ops->end (writer); -} - -/* Return a trace writer for TFILE format. */ - -static struct trace_file_writer * -tfile_trace_file_writer_new (void) -{ - struct tfile_trace_file_writer *writer - = xmalloc (sizeof (struct tfile_trace_file_writer)); - - writer->base.ops = &tfile_write_ops; - writer->fp = NULL; - writer->pathname = NULL; - - return (struct trace_file_writer *) writer; -} - -static void -trace_save_command (char *args, int from_tty) -{ - int target_does_save = 0; - char **argv; - char *filename = NULL; - struct cleanup *back_to; - int generate_ctf = 0; - struct trace_file_writer *writer = NULL; - - if (args == NULL) - error_no_arg (_("file in which to save trace data")); - - argv = gdb_buildargv (args); - back_to = make_cleanup_freeargv (argv); - - for (; *argv; ++argv) - { - if (strcmp (*argv, "-r") == 0) - target_does_save = 1; - if (strcmp (*argv, "-ctf") == 0) - generate_ctf = 1; - else if (**argv == '-') - error (_("unknown option `%s'"), *argv); - else - filename = *argv; - } - - if (!filename) - error_no_arg (_("file in which to save trace data")); - - if (generate_ctf) - writer = ctf_trace_file_writer_new (); - else - writer = tfile_trace_file_writer_new (); - - make_cleanup (trace_file_writer_xfree, writer); - - trace_save (filename, writer, target_does_save); - - if (from_tty) - printf_filtered (_("Trace data saved to %s '%s'.\n"), - generate_ctf ? "directory" : "file", filename); - - do_cleanups (back_to); -} - -/* Save the trace data to file FILENAME of tfile format. */ - -void -trace_save_tfile (const char *filename, int target_does_save) -{ - struct trace_file_writer *writer; - struct cleanup *back_to; - - writer = tfile_trace_file_writer_new (); - back_to = make_cleanup (trace_file_writer_xfree, writer); - trace_save (filename, writer, target_does_save); - do_cleanups (back_to); -} - -/* Save the trace data to dir DIRNAME of ctf format. */ - -void -trace_save_ctf (const char *dirname, int target_does_save) -{ - struct trace_file_writer *writer; - struct cleanup *back_to; - - writer = ctf_trace_file_writer_new (); - back_to = make_cleanup (trace_file_writer_xfree, writer); - - trace_save (dirname, writer, target_does_save); - do_cleanups (back_to); -} - /* Tell the target what to do with an ongoing tracing run if GDB disconnects for some reason. */ @@ -3950,7 +3287,7 @@ get_uploaded_tp (int num, ULONGEST addr, struct uploaded_tp **utpp) return utp; } -static void +void free_uploaded_tps (struct uploaded_tp **utpp) { struct uploaded_tp *next_one; @@ -3982,7 +3319,7 @@ get_uploaded_tsv (int num, struct uploaded_tsv **utsvp) return utsv; } -static void +void free_uploaded_tsvs (struct uploaded_tsv **utsvp) { struct uploaded_tsv *next_one; @@ -4228,204 +3565,15 @@ 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. */ +/* Parse the part of trace status syntax that is shared between + the remote protocol and the trace file reader. */ -static void -tfile_read (gdb_byte *readbuf, int size) +void +parse_trace_status (char *line, struct trace_status *ts) { - 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); - } - - 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); -} - -/* 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. */ - -void -parse_trace_status (char *line, struct trace_status *ts) -{ - char *p = line, *p1, *p2, *p3, *p_temp; - int end; - ULONGEST val; + char *p = line, *p1, *p2, *p3, *p_temp; + int end; + ULONGEST val; ts->running_known = 1; ts->running = (*p++ == '1'); @@ -4744,601 +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 (void) -{ - int pid; - - if (trace_fd < 0) - return; - - close (trace_fd); - trace_fd = -1; - xfree (trace_filename); - trace_filename = NULL; - - trace_reset_local_state (); -} - -static void -tfile_files_info (struct target_ops *t) -{ - printf_filtered ("\t`%s'\n", trace_filename); -} - -/* The trace status for a file is that tracing can never be run. */ - -static int -tfile_get_trace_status (struct trace_status *ts) -{ - /* Other bits of trace status were collected as part of opening the - trace files, so nothing to do here. */ - - return -1; -} - -static void -tfile_get_tracepoint_status (struct breakpoint *tp, struct uploaded_tp *utp) -{ - /* Other bits of trace status were collected as part of opening the - trace files, so nothing to do here. */ -} - -/* Given the position of a traceframe in the file, figure out what - address the frame was collected at. This would normally be the - value of a collected PC register, but if not available, we - improvise. */ - -static CORE_ADDR -tfile_get_traceframe_address (off_t tframe_offset) -{ - CORE_ADDR addr = 0; - short tpnum; - struct tracepoint *tp; - off_t saved_offset = cur_offset; - - /* FIXME dig pc out of collected registers. */ - - /* Fall back to using tracepoint address. */ - lseek (trace_fd, tframe_offset, SEEK_SET); - tfile_read ((gdb_byte *) &tpnum, 2); - tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2, - gdbarch_byte_order - (target_gdbarch ())); - - tp = get_tracepoint_by_number_on_target (tpnum); - /* FIXME this is a poor heuristic if multiple locations. */ - if (tp && tp->base.loc) - addr = tp->base.loc->address; - - /* Restore our seek position. */ - cur_offset = saved_offset; - lseek (trace_fd, cur_offset, SEEK_SET); - return addr; -} - -/* Given a type of search and some parameters, scan the collection of - traceframes in the file looking for a match. When found, return - both the traceframe and tracepoint number, otherwise -1 for - each. */ - -static int -tfile_trace_find (enum trace_find_type type, int num, - CORE_ADDR addr1, CORE_ADDR addr2, int *tpp) -{ - short tpnum; - int tfnum = 0, found = 0; - unsigned int data_size; - struct tracepoint *tp; - off_t offset, tframe_offset; - CORE_ADDR tfaddr; - - if (num == -1) - { - if (tpp) - *tpp = -1; - return -1; - } - - lseek (trace_fd, trace_frames_offset, SEEK_SET); - offset = trace_frames_offset; - while (1) - { - tframe_offset = offset; - tfile_read ((gdb_byte *) &tpnum, 2); - tpnum = (short) extract_signed_integer ((gdb_byte *) &tpnum, 2, - gdbarch_byte_order - (target_gdbarch ())); - offset += 2; - if (tpnum == 0) - break; - tfile_read ((gdb_byte *) &data_size, 4); - data_size = (unsigned int) extract_unsigned_integer - ((gdb_byte *) &data_size, 4, - gdbarch_byte_order (target_gdbarch ())); - offset += 4; - - if (type == tfind_number) - { - /* Looking for a specific trace frame. */ - if (tfnum == num) - found = 1; - } - else - { - /* Start from the _next_ trace frame. */ - if (tfnum > traceframe_number) - { - switch (type) - { - case tfind_pc: - tfaddr = tfile_get_traceframe_address (tframe_offset); - if (tfaddr == addr1) - found = 1; - break; - case tfind_tp: - tp = get_tracepoint (num); - if (tp && tpnum == tp->number_on_target) - found = 1; - break; - case tfind_range: - tfaddr = tfile_get_traceframe_address (tframe_offset); - if (addr1 <= tfaddr && tfaddr <= addr2) - found = 1; - break; - case tfind_outside: - tfaddr = tfile_get_traceframe_address (tframe_offset); - if (!(addr1 <= tfaddr && tfaddr <= addr2)) - found = 1; - break; - default: - internal_error (__FILE__, __LINE__, _("unknown tfind type")); - } - } - } - - if (found) - { - if (tpp) - *tpp = tpnum; - cur_offset = offset; - cur_data_size = data_size; - - return tfnum; - } - /* Skip past the traceframe's data. */ - lseek (trace_fd, data_size, SEEK_CUR); - offset += data_size; - /* Update our own count of traceframes. */ - ++tfnum; - } - /* Did not find what we were looking for. */ - if (tpp) - *tpp = -1; - return -1; -} - -/* Prototype of the callback passed to tframe_walk_blocks. */ -typedef int (*walk_blocks_callback_func) (char blocktype, void *data); - -/* Callback for traceframe_walk_blocks, used to find a given block - type in a traceframe. */ - -static int -match_blocktype (char blocktype, void *data) -{ - char *wantedp = data; - - if (*wantedp == blocktype) - return 1; - - return 0; -} - -/* Walk over all traceframe block starting at POS offset from - CUR_OFFSET, and call CALLBACK for each block found, passing in DATA - unmodified. If CALLBACK returns true, this returns the position in - the traceframe where the block is found, relative to the start of - the traceframe (cur_offset). Returns -1 if no callback call - returned true, indicating that all blocks have been walked. */ - -static int -traceframe_walk_blocks (walk_blocks_callback_func callback, - int pos, void *data) -{ - /* Iterate through a traceframe's blocks, looking for a block of the - requested type. */ - - lseek (trace_fd, cur_offset + pos, SEEK_SET); - while (pos < cur_data_size) - { - unsigned short mlen; - char block_type; - - tfile_read ((gdb_byte *) &block_type, 1); - - ++pos; - - if ((*callback) (block_type, data)) - return pos; - - switch (block_type) - { - case 'R': - lseek (trace_fd, cur_offset + pos + trace_regblock_size, SEEK_SET); - pos += trace_regblock_size; - break; - case 'M': - lseek (trace_fd, cur_offset + pos + 8, SEEK_SET); - tfile_read ((gdb_byte *) &mlen, 2); - mlen = (unsigned short) - extract_unsigned_integer ((gdb_byte *) &mlen, 2, - gdbarch_byte_order - (target_gdbarch ())); - lseek (trace_fd, mlen, SEEK_CUR); - pos += (8 + 2 + mlen); - break; - case 'V': - lseek (trace_fd, cur_offset + pos + 4 + 8, SEEK_SET); - pos += (4 + 8); - break; - default: - error (_("Unknown block type '%c' (0x%x) in trace frame"), - block_type, block_type); - break; - } - } - - return -1; -} - -/* Convenience wrapper around traceframe_walk_blocks. Looks for the - position offset of a block of type TYPE_WANTED in the current trace - frame, starting at POS. Returns -1 if no such block was found. */ - -static int -traceframe_find_block_type (char type_wanted, int pos) -{ - return traceframe_walk_blocks (match_blocktype, pos, &type_wanted); -} - -/* Look for a block of saved registers in the traceframe, and get the - requested register from it. */ - -static void -tfile_fetch_registers (struct target_ops *ops, - struct regcache *regcache, int regno) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - int offset, regn, regsize, pc_regno; - gdb_byte *regs; - - /* An uninitialized reg size says we're not going to be - successful at getting register blocks. */ - if (!trace_regblock_size) - return; - - regs = alloca (trace_regblock_size); - - if (traceframe_find_block_type ('R', 0) >= 0) - { - tfile_read (regs, trace_regblock_size); - - /* Assume the block is laid out in GDB register number order, - each register with the size that it has in GDB. */ - offset = 0; - for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++) - { - regsize = register_size (gdbarch, regn); - /* Make sure we stay within block bounds. */ - if (offset + regsize >= trace_regblock_size) - break; - if (regcache_register_status (regcache, regn) == REG_UNKNOWN) - { - if (regno == regn) - { - regcache_raw_supply (regcache, regno, regs + offset); - break; - } - else if (regno == -1) - { - regcache_raw_supply (regcache, regn, regs + offset); - } - } - offset += regsize; - } - return; - } - - /* We get here if no register data has been found. Mark registers - as unavailable. */ - for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++) - regcache_raw_supply (regcache, regn, NULL); - - /* We can often usefully guess that the PC is going to be the same - as the address of the tracepoint. */ - pc_regno = gdbarch_pc_regnum (gdbarch); - - /* XXX This guessing code below only works if the PC register isn't - a pseudo-register. The value of a pseudo-register isn't stored - in the (non-readonly) regcache -- instead it's recomputed - (probably from some other cached raw register) whenever the - register is read. This guesswork should probably move to some - higher layer. */ - if (pc_regno < 0 || pc_regno >= gdbarch_num_regs (gdbarch)) - return; - - if (regno == -1 || regno == pc_regno) - { - struct tracepoint *tp = get_tracepoint (tracepoint_number); - - if (tp && tp->base.loc) - { - /* But don't try to guess if tracepoint is multi-location... */ - if (tp->base.loc->next) - { - warning (_("Tracepoint %d has multiple " - "locations, cannot infer $pc"), - tp->base.number); - return; - } - /* ... or does while-stepping. */ - if (tp->step_count > 0) - { - warning (_("Tracepoint %d does while-stepping, " - "cannot infer $pc"), - tp->base.number); - return; - } - - store_unsigned_integer (regs, register_size (gdbarch, pc_regno), - gdbarch_byte_order (gdbarch), - tp->base.loc->address); - regcache_raw_supply (regcache, pc_regno, regs); - } - } -} - -static LONGEST -tfile_xfer_partial (struct target_ops *ops, enum target_object object, - const char *annex, gdb_byte *readbuf, - const gdb_byte *writebuf, ULONGEST offset, LONGEST len) -{ - /* We're only doing regular memory for now. */ - if (object != TARGET_OBJECT_MEMORY) - return -1; - - 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); - return amt; - } - - /* 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; - - amt = bfd_get_section_contents (exec_bfd, s, - readbuf, offset - vma, amt); - return amt; - } - } - } - - /* Indicate failure to find the requested memory block. */ - return -1; -} - -/* Iterate through the blocks of a trace frame, looking for a 'V' - block with a matching tsv number. */ - -static int -tfile_get_trace_state_variable_value (int tsvnum, LONGEST *val) -{ - int pos; - int found = 0; - - /* Iterate over blocks in current frame and find the last 'V' - block in which tsv number is TSVNUM. In one trace frame, there - may be multiple 'V' blocks created for a given trace variable, - and the last matched 'V' block contains the updated value. */ - pos = 0; - while ((pos = traceframe_find_block_type ('V', pos)) >= 0) - { - int vnum; - - tfile_read ((gdb_byte *) &vnum, 4); - vnum = (int) extract_signed_integer ((gdb_byte *) &vnum, 4, - gdbarch_byte_order - (target_gdbarch ())); - if (tsvnum == vnum) - { - tfile_read ((gdb_byte *) val, 8); - *val = extract_signed_integer ((gdb_byte *) val, 8, - gdbarch_byte_order - (target_gdbarch ())); - found = 1; - } - pos += (4 + 8); - } - - return found; -} - -static int -tfile_has_all_memory (struct target_ops *ops) -{ - return 1; -} - -static int -tfile_has_memory (struct target_ops *ops) -{ - return 1; -} - -static int -tfile_has_stack (struct target_ops *ops) -{ - return traceframe_number != -1; -} - -static int -tfile_has_registers (struct target_ops *ops) -{ - return traceframe_number != -1; -} - -/* Callback for traceframe_walk_blocks. Builds a traceframe_info - object for the tfile target's current traceframe. */ - -static int -build_traceframe_info (char blocktype, void *data) -{ - struct traceframe_info *info = data; - - switch (blocktype) - { - case 'M': - { - struct mem_range *r; - ULONGEST maddr; - unsigned short mlen; - - tfile_read ((gdb_byte *) &maddr, 8); - maddr = extract_unsigned_integer ((gdb_byte *) &maddr, 8, - gdbarch_byte_order - (target_gdbarch ())); - tfile_read ((gdb_byte *) &mlen, 2); - mlen = (unsigned short) - extract_unsigned_integer ((gdb_byte *) &mlen, - 2, gdbarch_byte_order - (target_gdbarch ())); - - r = VEC_safe_push (mem_range_s, info->memory, NULL); - - r->start = maddr; - r->length = mlen; - break; - } - case 'V': - { - int vnum; - - tfile_read ((gdb_byte *) &vnum, 4); - VEC_safe_push (int, info->tvars, vnum); - } - case 'R': - case 'S': - { - break; - } - default: - warning (_("Unhandled trace block type (%d) '%c ' " - "while building trace frame info."), - blocktype, blocktype); - break; - } - - return 0; -} - -static struct traceframe_info * -tfile_traceframe_info (void) -{ - struct traceframe_info *info = XCNEW (struct traceframe_info); - - traceframe_walk_blocks (build_traceframe_info, 0, info); - return info; -} - -static void -init_tfile_ops (void) -{ - tfile_ops.to_shortname = "tfile"; - tfile_ops.to_longname = "Local trace dump file"; - tfile_ops.to_doc - = "Use a trace file as a target. Specify the filename of the trace file."; - tfile_ops.to_open = tfile_open; - tfile_ops.to_close = tfile_close; - tfile_ops.to_fetch_registers = tfile_fetch_registers; - tfile_ops.to_xfer_partial = tfile_xfer_partial; - tfile_ops.to_files_info = tfile_files_info; - tfile_ops.to_get_trace_status = tfile_get_trace_status; - tfile_ops.to_get_tracepoint_status = tfile_get_tracepoint_status; - tfile_ops.to_trace_find = tfile_trace_find; - tfile_ops.to_get_trace_state_variable_value - = tfile_get_trace_state_variable_value; - tfile_ops.to_stratum = process_stratum; - tfile_ops.to_has_all_memory = tfile_has_all_memory; - tfile_ops.to_has_memory = tfile_has_memory; - tfile_ops.to_has_stack = tfile_has_stack; - tfile_ops.to_has_registers = tfile_has_registers; - tfile_ops.to_traceframe_info = tfile_traceframe_info; - tfile_ops.to_magic = OPS_MAGIC; -} - void free_current_marker (void *arg) { @@ -5818,12 +4371,6 @@ _initialize_tracepoint (void) add_com ("tdump", class_trace, trace_dump_command, _("Print everything collected at the current tracepoint.")); - add_com ("tsave", class_trace, trace_save_command, _("\ -Save the trace data to a file.\n\ -Use the '-ctf' option to save the data to CTF format.\n\ -Use the '-r' option to direct the target to save directly to the file,\n\ -using its own filesystem.")); - c = add_com ("tvariable", class_trace, trace_variable_command,_("\ Define a trace state variable.\n\ Argument is a $-prefixed name, optionally followed\n\ @@ -6006,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); }