diff options
author | Stan Shebs <shebs@codesourcery.com> | 2010-01-15 22:37:20 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 2010-01-15 22:37:20 +0000 |
commit | 00bf0b8586eece6ef4e508343e9896d309c2004e (patch) | |
tree | 53202654ea4c6e5c41252c0d74790e03becc6dc8 /gdb/remote.c | |
parent | 6ec12636a713f947bf37b8f355a0e53c94f4a8e9 (diff) | |
download | gdb-00bf0b8586eece6ef4e508343e9896d309c2004e.zip gdb-00bf0b8586eece6ef4e508343e9896d309c2004e.tar.gz gdb-00bf0b8586eece6ef4e508343e9896d309c2004e.tar.bz2 |
Add trace file support.
* tracepoint.h (enum trace_stop_reason): New enum.
(struct trace_status): New struct.
(parse_trace_status): Declare.
(struct uploaded_tp): Move here from remote.c,
add fields for actions.
(struct uploaded_tsv): New struct.
* tracepoint.c (tfile_ops): New target vector.
(trace_fd): New global.
(tfile_open): New function.
(tfile_close): New function.
(tfile_files_info): New function.
(tfile_get_trace_status): New function.
(tfile_get_traceframe_address): New function.
(tfile_trace_find): New function.
(tfile_fetch_registers): New function.
(tfile_xfer_partial): New function.
(tfile_get_trace_state_variable_value): New function.
(init_tfile_ops): New function.
(_initialize_tracepoint): Call it, add tfile target.
(trace_status): New global.
(current_trace_status): New function.
(trace_running_p): Remove, change all users to get from
current_trace_status()->running.
(get_trace_status): Remove.
(trace_status_command): Call target_get_trace_status directly,
report more detail including tracing stop reasons.
(trace_find_command): Always allow tfind on a file.
(trace_find_pc_command): Ditto.
(trace_find_tracepoint_command): Ditto.
(trace_find_line_command): Ditto.
(trace_find_range_command): Ditto.
(trace_find_outside_command): Ditto.
(trace_frames_offset, cur_offset): Declare as off_t.
(trace_regblock_size): Rename from reg_size, update users.
(parse_trace_status): New function.
(tfile_interp_line): New function.
(disconnect_or_stop_tracing): Ensure current trace
status before asking what to do.
(stop_reason_names): New global.
(trace_save_command): New command.
(get_uploaded_tp): Move here from remote.c.
(find_matching_tracepoint): Ditto.
(merge_uploaded_tracepoints): New function.
(parse_trace_status): Use stop_reason_names.
(_initialize_tracepoint): Define tsave command.
* target.h (target_ops): New fields to_save_trace_data,
to_upload_tracepoints, to_upload_trace_state_variables,
to_get_raw_trace_data, change to_get_trace_status
to take a pointer to a status struct.
(target_save_trace_data): New macro.
(target_upload_tracepoints): New macro.
(target_upload_trace_state_variables): New macro.
(target_get_raw_trace_data): New macro.
* target.c (update_current_target): Add new methods, change
signature of to_get_trace_status.
* remote.c (hex2bin): Make globally visible.
(bin2hex): Ditto.
(remote_download_trace_state_variable): Download name also.
(remote_get_trace_status): Update parameter, use
parse_trace_status.
(remote_save_trace_data): New function.
(remote_upload_tracepoints): New function.
(remote_upload_trace_state_variables): New function.
(remote_get_raw_trace_data): New function.
(remote_start_remote): Use them.
(_initialize_remote_ops): Add operations.
* ax-gdb.c: Include breakpoint.h.
* breakpoint.c (create_tracepoint_from_upload): Use
break_command_really, return tracepoint, warn about unimplemented
parts.
* NEWS: Mention trace file addition.
* gdb.texinfo (Trace Files): New section.
(Tracepoint Packets): Document QTSave and qTBuffer.
(Trace File Format): New appendix.
* generic/gdbtk-bp.c (gdb_trace_status): Use current_trace_status.
* gdb.trace/tfile.c: New file.
* gdb.trace/tfile.exp: New file.
Diffstat (limited to 'gdb/remote.c')
-rw-r--r-- | gdb/remote.c | 338 |
1 files changed, 161 insertions, 177 deletions
diff --git a/gdb/remote.c b/gdb/remote.c index f492082..2cee1b0 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -189,9 +189,9 @@ static void record_currthread (ptid_t currthread); static int fromhex (int a); -static int hex2bin (const char *hex, gdb_byte *bin, int count); +extern int hex2bin (const char *hex, gdb_byte *bin, int count); -static int bin2hex (const gdb_byte *bin, char *hex, int count); +extern int bin2hex (const gdb_byte *bin, char *hex, int count); static int putpkt_binary (char *buf, int cnt); @@ -215,8 +215,12 @@ static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid); static ptid_t read_ptid (char *buf, char **obuf); struct remote_state; -static void remote_get_tracing_state (struct remote_state *); +static int remote_get_trace_status (struct trace_status *ts); +static int remote_upload_tracepoints (struct uploaded_tp **utpp); + +static int remote_upload_trace_state_variables (struct uploaded_tsv **utsvp); + static void remote_query_supported (void); static void remote_check_symbols (struct objfile *objfile); @@ -3158,7 +3162,23 @@ remote_start_remote (struct ui_out *uiout, void *opaque) previously; find out where things are at. */ if (rs->disconnected_tracing) { - remote_get_tracing_state (rs); + struct uploaded_tp *uploaded_tps = NULL; + struct uploaded_tsv *uploaded_tsvs = NULL; + + remote_get_trace_status (current_trace_status ()); + if (current_trace_status ()->running) + printf_filtered (_("Trace is already running on the target.\n")); + + /* Get trace state variables first, they may be checked when + parsing uploaded commands. */ + + remote_upload_trace_state_variables (&uploaded_tsvs); + + merge_uploaded_trace_state_variables (&uploaded_tsvs); + + remote_upload_tracepoints (&uploaded_tps); + + merge_uploaded_tracepoints (&uploaded_tps); } /* If breakpoints are global, insert them now. */ @@ -3948,7 +3968,7 @@ fromhex (int a) error (_("Reply contains invalid hex digit %d"), a); } -static int +int hex2bin (const char *hex, gdb_byte *bin, int count) { int i; @@ -3978,7 +3998,7 @@ tohex (int nib) return 'a' + nib - 10; } -static int +int bin2hex (const gdb_byte *bin, char *hex, int count) { int i; @@ -8034,7 +8054,7 @@ remote_rcmd (char *command, { char *buf; - /* XXX - see also tracepoint.c:remote_get_noisy_reply(). */ + /* XXX - see also remote_get_noisy_reply(). */ rs->buf[0] = '\0'; getpkt (&rs->buf, &rs->buf_size, 0); buf = rs->buf; @@ -9342,9 +9362,15 @@ static void remote_download_trace_state_variable (struct trace_state_variable *tsv) { struct remote_state *rs = get_remote_state (); + char *p; - sprintf (rs->buf, "QTDV:%x:%s", - tsv->number, phex ((ULONGEST) tsv->initial_value, 8)); + sprintf (rs->buf, "QTDV:%x:%s:%x:", + tsv->number, phex ((ULONGEST) tsv->initial_value, 8), tsv->builtin); + p = rs->buf + strlen (rs->buf); + if ((p - rs->buf) + strlen (tsv->name) * 2 >= get_remote_packet_size ()) + error (_("Trace state variable name too long for tsv definition packet")); + p += 2 * bin2hex ((gdb_byte *) (tsv->name), p, 0); + *p++ = '\0'; putpkt (rs->buf); remote_get_noisy_reply (&target_buf, &target_buf_size); } @@ -9395,16 +9421,39 @@ remote_trace_start () } static int -remote_get_trace_status (int *stop_reason) +remote_get_trace_status (struct trace_status *ts) { + char *p, *p1, *p_temp; + ULONGEST val; + /* FIXME we need to get register block size some other way */ + extern int trace_regblock_size; + trace_regblock_size = get_remote_arch_state ()->sizeof_g_packet; + putpkt ("qTStatus"); - remote_get_noisy_reply (&target_buf, &target_buf_size); + getpkt (&target_buf, &target_buf_size, 0); + /* FIXME should handle more variety of replies */ + + p = target_buf; + + /* If the remote target doesn't do tracing, flag it. */ + if (*p == '\0') + return -1; - if (target_buf[0] != 'T' || - (target_buf[1] != '0' && target_buf[1] != '1')) + /* We're working with a live target. */ + ts->from_file = 0; + + /* Set some defaults. */ + ts->running_known = 0; + ts->stop_reason = trace_stop_reason_unknown; + ts->traceframe_count = -1; + ts->buffer_free = 0; + + if (*p++ != 'T') error (_("Bogus trace status reply from target: %s"), target_buf); - return (target_buf[1] == '1'); + parse_trace_status (p, ts); + + return ts->running; } static void @@ -9434,16 +9483,16 @@ remote_trace_find (enum trace_find_type type, int num, sprintf (p, "%x", num); break; case tfind_pc: - sprintf (p, "pc:%s", paddress (target_gdbarch, addr1)); + sprintf (p, "pc:%s", phex_nz (addr1, 0)); break; case tfind_tp: sprintf (p, "tdp:%x", num); break; case tfind_range: - sprintf (p, "range:%s:%s", paddress (target_gdbarch, addr1), paddress (target_gdbarch, addr2)); + sprintf (p, "range:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0)); break; case tfind_outside: - sprintf (p, "outside:%s:%s", paddress (target_gdbarch, addr1), paddress (target_gdbarch, addr2)); + sprintf (p, "outside:%s:%s", phex_nz (addr1, 0), phex_nz (addr2, 0)); break; default: error ("Unknown trace find type %d", type); @@ -9499,6 +9548,67 @@ remote_get_trace_state_variable_value (int tsvnum, LONGEST *val) return 0; } +static int +remote_save_trace_data (char *filename) +{ + struct remote_state *rs = get_remote_state (); + char *p, *reply; + + p = rs->buf; + strcpy (p, "QTSave:"); + p += strlen (p); + if ((p - rs->buf) + strlen (filename) * 2 >= get_remote_packet_size ()) + error (_("Remote file name too long for trace save packet")); + p += 2 * bin2hex ((gdb_byte *) filename, p, 0); + *p++ = '\0'; + putpkt (rs->buf); + remote_get_noisy_reply (&target_buf, &target_buf_size); + return 0; +} + +/* This is basically a memory transfer, but needs to be its own packet + because we don't know how the target actually organizes its trace + memory, plus we want to be able to ask for as much as possible, but + not be unhappy if we don't get as much as we ask for. */ + +static LONGEST +remote_get_raw_trace_data (gdb_byte *buf, ULONGEST offset, LONGEST len) +{ + struct remote_state *rs = get_remote_state (); + char *reply; + char *p; + int rslt; + + p = rs->buf; + strcpy (p, "qTBuffer:"); + p += strlen (p); + p += hexnumstr (p, offset); + *p++ = ','; + p += hexnumstr (p, len); + *p++ = '\0'; + + putpkt (rs->buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (reply && *reply) + { + /* 'l' by itself means we're at the end of the buffer and + there is nothing more to get. */ + if (*reply == 'l') + return 0; + + /* Convert the reply into binary. Limit the number of bytes to + convert according to our passed-in buffer size, rather than + what was returned in the packet; if the target is + unexpectedly generous and gives us a bigger reply than we + asked for, we don't want to crash. */ + rslt = hex2bin (target_buf, buf, len); + return rslt; + } + + /* Something went wrong, flag as an error. */ + return -1; +} + static void remote_set_disconnected_tracing (int val) { @@ -9592,6 +9702,10 @@ Specify the serial device it is connected to\n\ remote_ops.to_trace_stop = remote_trace_stop; remote_ops.to_trace_find = remote_trace_find; remote_ops.to_get_trace_state_variable_value = remote_get_trace_state_variable_value; + remote_ops.to_save_trace_data = remote_save_trace_data; + remote_ops.to_upload_tracepoints = remote_upload_tracepoints; + remote_ops.to_upload_trace_state_variables = remote_upload_trace_state_variables; + remote_ops.to_get_raw_trace_data = remote_get_raw_trace_data; remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing; remote_ops.to_core_of_thread = remote_core_of_thread; } @@ -9744,181 +9858,51 @@ remote_new_objfile (struct objfile *objfile) remote_check_symbols (objfile); } -/* Struct to collect random info about tracepoints on the target. */ - -struct uploaded_tp { - int number; - enum bptype type; - ULONGEST addr; - int enabled; - int step; - int pass; - int orig_size; - char *cond; - int cond_len; - struct uploaded_tp *next; -}; - -struct uploaded_tp *uploaded_tps; - -struct uploaded_tp * -get_uploaded_tp (int num) -{ - struct uploaded_tp *utp; - - for (utp = uploaded_tps; utp; utp = utp->next) - if (utp->number == num) - return utp; - utp = (struct uploaded_tp *) xmalloc (sizeof (struct uploaded_tp)); - utp->number = num; - utp->next = uploaded_tps; - uploaded_tps = utp; - return utp; -} - -/* Look for an existing tracepoint that seems similar enough to the - uploaded one. Enablement isn't checked, because the user can - toggle that freely, and may have done so in anticipation of the - next trace run. */ - -struct breakpoint * -find_matching_tracepoint (struct uploaded_tp *utp) +/* Pull all the tracepoints defined on the target and create local + data structures representing them. We don't want to create real + tracepoints yet, we don't want to mess up the user's existing + collection. */ + +static int +remote_upload_tracepoints (struct uploaded_tp **utpp) { - VEC(breakpoint_p) *tp_vec = all_tracepoints (); - int ix; - struct breakpoint *t; + struct remote_state *rs = get_remote_state (); + char *p; - for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) + /* Ask for a first packet of tracepoint definition. */ + putpkt ("qTfP"); + getpkt (&rs->buf, &rs->buf_size, 0); + p = rs->buf; + while (*p && *p != 'l') { - if (t->type == utp->type - && (t->loc && t->loc->address == utp->addr) - && t->step_count == utp->step - && t->pass_count == utp->pass - /* FIXME also test conditionals and actions */ - ) - return t; + parse_tracepoint_definition (p, utpp); + /* Ask for another packet of tracepoint definition. */ + putpkt ("qTsP"); + getpkt (&rs->buf, &rs->buf_size, 0); + p = rs->buf; } - return NULL; + return 0; } -/* Find out everything we can about the trace run that was already - happening on the target. This includes both running/stopped, and - the tracepoints that were in use. */ - -static void -remote_get_tracing_state (struct remote_state *rs) +static int +remote_upload_trace_state_variables (struct uploaded_tsv **utsvp) { + struct remote_state *rs = get_remote_state (); char *p; - ULONGEST num, addr, step, pass, orig_size, xlen; - int enabled, i; - enum bptype type; - char *cond; - struct uploaded_tp *utp; - struct breakpoint *t; - extern void get_trace_status (); - - get_trace_status (); - if (trace_running_p) - printf_filtered (_("Trace is running on the target.\n")); - putpkt ("qTfP"); + /* Ask for a first packet of variable definition. */ + putpkt ("qTfV"); getpkt (&rs->buf, &rs->buf_size, 0); p = rs->buf; - while (*p != '\0') + while (*p && *p != 'l') { - if (*p == 'T') - { - p++; - p = unpack_varlen_hex (p, &num); - p++; - p = unpack_varlen_hex (p, &addr); - p++; - enabled = (*p++ == 'E'); - p++; - p = unpack_varlen_hex (p, &step); - p++; - p = unpack_varlen_hex (p, &pass); - p++; - type = bp_tracepoint; - cond = NULL; - while (*p) - { - if (*p == 'F') - { - type = bp_fast_tracepoint; - p++; - p = unpack_varlen_hex (p, &orig_size); - } - else if (*p == 'X') - { - p++; - p = unpack_varlen_hex (p, &xlen); - p++; /* skip the comma */ - cond = (char *) xmalloc (xlen); - hex2bin (p, cond, xlen); - p += 2 * xlen; - } - else - /* Silently skip over anything else. */ - p++; - } - utp = get_uploaded_tp (num); - utp->type = type; - utp->addr = addr; - utp->enabled = enabled; - utp->step = step; - utp->pass = pass; - utp->cond = cond; - utp->cond_len = xlen; - } - else if (*p == 'A') - { - p++; - p = unpack_varlen_hex (p, &num); - p++; - p = unpack_varlen_hex (p, &addr); - p++; - utp = get_uploaded_tp (num); - /* FIXME save the action */ - } - else if (*p == 'S') - { - p++; - p = unpack_varlen_hex (p, &num); - p++; - p = unpack_varlen_hex (p, &addr); - p++; - utp = get_uploaded_tp (num); - /* FIXME save the action */ - } - else if (*p == 'l') - { - /* No more tracepoint info, get out of the loop. */ - break; - } - putpkt ("qTsP"); + parse_tsv_definition (p, utsvp); + /* Ask for another packet of variable definition. */ + putpkt ("qTsV"); getpkt (&rs->buf, &rs->buf_size, 0); p = rs->buf; } - /* Got all the tracepoint info, now look for matches among what we - already have in GDB. */ - for (utp = uploaded_tps; utp; utp = utp->next) - { - t = find_matching_tracepoint (utp); - if (t) - { - printf_filtered (_("Assuming tracepoint %d is same as target's tracepoint %d.\n"), - t->number, utp->number); - t->number_on_target = utp->number; - } - else - { - extern void create_tracepoint_from_upload (int num, ULONGEST addr); - create_tracepoint_from_upload (utp->number, utp->addr); - } - } - /* FIXME free all the space */ - uploaded_tps = NULL; + return 0; } void |