From f196051f5ee7f3aa3f417611a488ba773878a429 Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Sun, 20 Nov 2011 23:59:49 +0000 Subject: [PATCH] * NEWS: Mention tracepoint additions. * breakpoint.h (struct tracepoint): New field traceframe_usage. * breakpoint.c (print_one_breakpoint_location): Identify tracepoints as such when reporting hit counts, report trace buffer usage. (create_tracepoint_from_upload): Copy status info. * tracepoint.h (struct trace_status): Rename error_desc to stop_desc, add fields user_name, notes, start_time, stop_time. (struct uploaded_tp): Add fields hit_count, traceframe_usage. * tracepoint.c (trace_user): New global. (trace_notes): New global. (trace_stop_notes): New global. (start_tracing): Add argument and trace note handling. (stop_tracing): Ditto. (trace_start_command): Add notes argument. (trace_stop_command): Ditto. (trace_status_command): Report additional status info. (trace_status_mi): Similarly. (trace_save): Update, record tracepoint status. (set_disconnected_tracing): Call target method directly. (send_disconnected_tracing_value): Remove. (set_trace_user): New function. (set_trace_notes): New function. (set_trace_stop_notes): New function. (parse_trace_status): Handle additional status. (parse_tracepoint_status): New function. (parse_tracepoint_definition): Call it. (tfile_get_tracepoint_status): New function. (init_tfile_ops): Use it. (_initialize_tracepoint): Add new setshows. * target.h (struct target_ops): New methods to_get_tracepoint_status and to_set_trace_notes. (target_get_tracepoint_status): New macro. (target_set_trace_notes): New macro. * target.c (update_current_target): Add new methods. * remote.c (remote_get_tracepoint_status): New function. (remote_set_trace_notes): New function. (init_remote_ops): Add them. * mi/mi-main.c (mi_cmd_trace_start): Add argument to call. (mi_cmd_trace_stop): Ditto. * tracepoint.c (struct tracepoint): New field traceframe_usage. (tracing_start_time): New global. (tracing_stop_time): New global. (tracing_user_name): New global. (tracing_notes): New global. (tracing_stop_note): New global. (cmd_qtstart): Set traceframe_usage, start_time. (stop_tracing): Set stop_time. (cmd_qtstatus): Report additional status. (cmd_qtp): New function. (handle_tracepoint_query): Call it. (cmd_qtnotes): New function. (handle_tracepoint_general_set): Call it. (get_timestamp): Rename from tsv_get_timestamp. * gdb.texinfo (Starting and Stopping Trace Experiments): Document note-related options and variables. (Tracepoint Packets): Document packet changes. * gdb.trace/tstatus.exp: New. * gdb.trace/actions.c: Include string.h. --- gdb/ChangeLog | 43 ++++ gdb/NEWS | 35 +++ gdb/breakpoint.c | 18 ++ gdb/breakpoint.h | 4 + gdb/doc/ChangeLog | 6 + gdb/doc/gdb.texinfo | 80 +++++- gdb/gdbserver/ChangeLog | 17 ++ gdb/gdbserver/tracepoint.c | 169 ++++++++++++- gdb/mi/mi-main.c | 4 +- gdb/remote.c | 94 +++++++ gdb/target.c | 8 + gdb/target.h | 13 + gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.trace/actions.c | 2 + gdb/testsuite/gdb.trace/tstatus.exp | 172 +++++++++++++ gdb/testsuite/lib/gdbserver-support.exp | 1 + gdb/tracepoint.c | 316 ++++++++++++++++++++---- gdb/tracepoint.h | 38 ++- 18 files changed, 961 insertions(+), 64 deletions(-) create mode 100644 gdb/testsuite/gdb.trace/tstatus.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 400423598a..cda1411acf 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,46 @@ +2011-11-20 Stan Shebs + + * NEWS: Mention tracepoint additions. + * breakpoint.h (struct tracepoint): New field traceframe_usage. + * breakpoint.c (print_one_breakpoint_location): Identify + tracepoints as such when reporting hit counts, report + trace buffer usage. + (create_tracepoint_from_upload): Copy status info. + * tracepoint.h (struct trace_status): Rename error_desc to stop_desc, + add fields user_name, notes, start_time, stop_time. + (struct uploaded_tp): Add fields hit_count, traceframe_usage. + * tracepoint.c (trace_user): New global. + (trace_notes): New global. + (trace_stop_notes): New global. + (start_tracing): Add argument and trace note handling. + (stop_tracing): Ditto. + (trace_start_command): Add notes argument. + (trace_stop_command): Ditto. + (trace_status_command): Report additional status info. + (trace_status_mi): Similarly. + (trace_save): Update, record tracepoint status. + (set_disconnected_tracing): Call target method directly. + (send_disconnected_tracing_value): Remove. + (set_trace_user): New function. + (set_trace_notes): New function. + (set_trace_stop_notes): New function. + (parse_trace_status): Handle additional status. + (parse_tracepoint_status): New function. + (parse_tracepoint_definition): Call it. + (tfile_get_tracepoint_status): New function. + (init_tfile_ops): Use it. + (_initialize_tracepoint): Add new setshows. + * target.h (struct target_ops): New methods to_get_tracepoint_status + and to_set_trace_notes. + (target_get_tracepoint_status): New macro. + (target_set_trace_notes): New macro. + * target.c (update_current_target): Add new methods. + * remote.c (remote_get_tracepoint_status): New function. + (remote_set_trace_notes): New function. + (init_remote_ops): Add them. + * mi/mi-main.c (mi_cmd_trace_start): Add argument to call. + (mi_cmd_trace_stop): Ditto. + 2011-11-20 Sanjoy Das * jit.c: Include regcache.h. diff --git a/gdb/NEWS b/gdb/NEWS index c4e59c4f14..93a799bb23 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -133,6 +133,17 @@ collect[/s] EXPRESSIONS string. An optional integer following the "/s" sets a bound on the number of bytes that will be collected. +tstart [NOTES] + The trace start command now interprets any supplied arguments as a + note to be recorded with the trace run, with an effect similar to + setting the variable trace-notes. + +tstop [NOTES] + The trace stop command now interprets any arguments as a note to be + mentioned along with the tstatus report that the trace was stopped + with a command. The effect is similar to setting the variable + trace-stop-notes. + * Tracepoints can now be enabled and disabled at any time after a trace experiment has been started using the standard "enable" and "disable" commands. It is now possible to start a trace experiment with no enabled @@ -176,6 +187,22 @@ show basenames-may-differ If not set (the default), all source files are assumed to have just one base name, and gdb will do file name comparisons more efficiently. +set trace-user +show trace-user +set trace-notes +show trace-notes + Set a user name and notes for the current and any future trace runs. + This is useful for long-running and/or disconnected traces, to + inform others (or yourself) as to who is running the trace, supply + contact information, or otherwise explain what is going on. + +set trace-stop-notes +show trace-stop-notes + Set a note attached to the trace run, that is displayed when the + trace has been stopped by a tstop command. This is useful for + instance as an explanation, if you are stopping a trace run that was + started by someone else. + * New remote packets QTEnable @@ -186,6 +213,14 @@ QTDisable Dynamically disable a tracepoint in a started trace experiment. +QTNotes + + Set the user and notes of the trace run. + +qTP + + Query the current status of a tracepoint. + qTMinFTPILen Query the minimum length of instruction at which a fast tracepoint may diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index dc891c0c93..ab0d4020ac 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -4879,6 +4879,8 @@ print_one_breakpoint_location (struct breakpoint *b, /* FIXME should make an annotation for this. */ if (ep_is_catchpoint (b)) ui_out_text (uiout, "\tcatchpoint"); + else if (is_tracepoint (b)) + ui_out_text (uiout, "\ttracepoint"); else ui_out_text (uiout, "\tbreakpoint"); ui_out_text (uiout, " already hit "); @@ -4903,6 +4905,18 @@ print_one_breakpoint_location (struct breakpoint *b, ui_out_text (uiout, " hits\n"); } + if (!part_of_multiple && is_tracepoint (b)) + { + struct tracepoint *tp = (struct tracepoint *) b; + + if (tp->traceframe_usage) + { + ui_out_text (uiout, "\ttrace buffer usage "); + ui_out_field_int (uiout, "traceframe-usage", tp->traceframe_usage); + ui_out_text (uiout, " bytes\n"); + } + } + l = b->commands ? b->commands->commands : NULL; if (!part_of_multiple && l) { @@ -12904,6 +12918,10 @@ create_tracepoint_from_upload (struct uploaded_tp *utp) "have no source form, ignoring them"), utp->number); + /* Copy any status information that might be available. */ + tp->base.hit_count = utp->hit_count; + tp->traceframe_usage = utp->traceframe_usage; + return tp; } diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 8e03264c38..96cc96aa5a 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -710,6 +710,10 @@ struct tracepoint /* The number of the tracepoint on the target. */ int number_on_target; + /* The total space taken by all the trace frames for this + tracepoint. */ + ULONGEST traceframe_usage; + /* The static tracepoint marker id, if known. */ char *static_trace_marker_id; diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index f915110c77..4b3a99fbb5 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,9 @@ +2011-11-20 Stan Shebs + + * gdb.texinfo (Starting and Stopping Trace Experiments): Document + note-related options and variables. + (Tracepoint Packets): Document packet changes. + 2011-11-20 Sanjoy Das * gdb.texinfo (JIT Interface): Add documentation on writing and diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 13e01bc5cf..f4f68a344d 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -10902,20 +10902,27 @@ Cnt ID Enb Address What @subsection Starting and Stopping Trace Experiments @table @code -@kindex tstart +@kindex tstart [ @var{notes} ] @cindex start a new trace experiment @cindex collected data discarded @item tstart -This command takes no arguments. It starts the trace experiment, and -begins collecting data. This has the side effect of discarding all -the data collected in the trace buffer during the previous trace -experiment. +This command starts the trace experiment, and begins collecting data. +It has the side effect of discarding all the data collected in the +trace buffer during the previous trace experiment. If any arguments +are supplied, they are taken as a note and stored with the trace +experiment's state. The notes may be arbitrary text, and are +especially useful with disconnected tracing in a multi-user context; +the notes can explain what the trace is doing, supply user contact +information, and so forth. -@kindex tstop +@kindex tstop [ @var{notes} ] @cindex stop a running trace experiment @item tstop -This command takes no arguments. It ends the trace experiment, and -stops collecting data. +This command stops the trace experiment. If any arguments are +supplied, they are recorded with the experiment as a note. This is +useful if you are stopping a trace started by someone else, for +instance if the trace is interfering with the system's behavior and +needs to be stopped quickly. @strong{Note}: a trace experiment and data collection may stop automatically if any tracepoint's passcount is reached @@ -11019,6 +11026,33 @@ for instance if you are looking at frames from a trace file. @end table +@table @code +@item set trace-user @var{text} +@kindex set trace-user + +@item show trace-user +@kindex show trace-user + +@item set trace-notes @var{text} +@kindex set trace-notes +Set the trace run's notes. + +@item show trace-notes +@kindex show trace-notes +Show the trace run's notes. + +@item set trace-stop-notes @var{text} +@kindex set trace-stop-notes +Set the trace run's stop notes. The handling of the note is as for +@code{tstop} arguments; the set command is convenient way to fix a +stop note that is mistaken or incomplete. + +@item show trace-stop-notes +@kindex show trace-stop-notes +Show the trace run's stop notes. + +@end table + @node Tracepoint Restrictions @subsection Tracepoint Restrictions @@ -35115,6 +35149,8 @@ the command by a @samp{,}, not a @samp{:}, contrary to the naming conventions above. Please don't use this packet as a model for new packets.) +@item QTNotes +@item qTP @item QTSave @item qTsP @item qTsV @@ -35697,8 +35733,11 @@ explanations as one of the optional fields: @item tnotrun:0 No trace has been run yet. -@item tstop:0 -The trace was stopped by a user-originated stop command. +@item tstop[:@var{text}]:0 +The trace was stopped by a user-originated stop command. The optional +@var{text} field is a user-supplied string supplied as part of the +stop command (for instance, an explanation of why the trace was +stopped manually). It is hex-encoded. @item tfull:0 The trace stopped because the trace buffer filled up. @@ -35754,6 +35793,22 @@ that the trace run will stop. @end table +@item qTP:@var{tp}:@var{addr} +@cindex tracepoint status, remote request +@cindex @samp{qTP} packet +Ask the stub for the current state of tracepoint number @var{tp} at +address @var{addr}. + +Replies: +@table @samp +@item V@var{hits}:@var{usage} +The tracepoint has been hit @var{hits} times so far during the trace +run, and accounts for @var{usage} in the trace buffer. Note that +@code{while-stepping} steps are not counted as separate hits, but the +steps' space consumption is added into the usage number. + +@end table + @item qTV:@var{var} @cindex trace state variable value, remote request @cindex @samp{qTV} packet @@ -35847,6 +35902,11 @@ available. This packet directs the target to use a circular trace buffer if @var{value} is 1, or a linear buffer if the value is 0. +@item QTNotes:@r{[}@var{type}:@var{text}@r{]}@r{[};@var{type}:@var{text}@r{]}@dots{} +This packet adds optional textual notes to the trace run. Allowable +types include @code{user}, @code{notes}, and @code{tstop}, the +@var{text} fields are arbitrary strings, hex-encoded. + @end table @subsection Relocate instruction reply packet diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 844fb1836d..c556eeb309 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,20 @@ +2011-11-17 Stan Shebs + + * tracepoint.c (struct tracepoint): New field traceframe_usage. + (tracing_start_time): New global. + (tracing_stop_time): New global. + (tracing_user_name): New global. + (tracing_notes): New global. + (tracing_stop_note): New global. + (cmd_qtstart): Set traceframe_usage, start_time. + (stop_tracing): Set stop_time. + (cmd_qtstatus): Report additional status. + (cmd_qtp): New function. + (handle_tracepoint_query): Call it. + (cmd_qtnotes): New function. + (handle_tracepoint_general_set): Call it. + (get_timestamp): Rename from tsv_get_timestamp. + 2011-11-14 Stan Shebs Kwok Cheung Yeung diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index b00df0575c..e6a5bbc193 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -632,6 +632,9 @@ struct tracepoint Note that while-stepping steps are not counted as "hits". */ long hit_count; + /* Cached sum of the sizes of traceframes created by this point. */ + long traceframe_usage; + CORE_ADDR compiled_cond; /* Link to the next tracepoint in the list. */ @@ -1144,6 +1147,27 @@ static const char *tracing_stop_reason = "tnotrun"; static int tracing_stop_tpnum; +/* 64-bit timestamps for the trace run's start and finish, expressed + in microseconds from the Unix epoch. */ + +LONGEST tracing_start_time; +LONGEST tracing_stop_time; + +/* The (optional) user-supplied name of the user that started the run. + This is an arbitrary string, and may be NULL. */ + +char *tracing_user_name; + +/* Optional user-supplied text describing the run. This is + an arbitrary string, and may be NULL. */ + +char *tracing_notes; + +/* Optional user-supplied text explaining a tstop command. This is an + arbitrary string, and may be NULL. */ + +char *tracing_stop_note; + #endif /* Functions local to this file. */ @@ -1266,6 +1290,8 @@ static void download_tracepoint (struct tracepoint *); static int install_fast_tracepoint (struct tracepoint *, char *errbuf); #endif +static LONGEST get_timestamp (void); + #if defined(__GNUC__) # define memory_barrier() asm volatile ("" : : : "memory") #else @@ -3027,6 +3053,7 @@ cmd_qtstart (char *packet) { /* Ensure all the hit counts start at zero. */ tpoint->hit_count = 0; + tpoint->traceframe_usage = 0; if (tpoint->type == trap_tracepoint) { @@ -3103,6 +3130,7 @@ cmd_qtstart (char *packet) trace_buffer_is_full = 0; expr_eval_result = expr_eval_no_error; error_tracepoint = NULL; + tracing_start_time = get_timestamp (); /* Tracing is now active, hits will now start being logged. */ tracing = 1; @@ -3172,6 +3200,7 @@ stop_tracing (void) fatal ("Error clearing tracing variable in lib"); } + tracing_stop_time = get_timestamp (); tracing_stop_reason = "t???"; tracing_stop_tpnum = 0; if (stopping_tracepoint) @@ -3352,6 +3381,26 @@ static void cmd_qtstatus (char *packet) { char *stop_reason_rsp = NULL; + char *buf1, *buf2, *buf3, *str; + int slen; + + /* Translate the plain text of the notes back into hex for + transmission. */ + + str = (tracing_user_name ? tracing_user_name : ""); + slen = strlen (str); + buf1 = (char *) alloca (slen * 2 + 1); + hexify (buf1, str, slen); + + str = (tracing_notes ? tracing_notes : ""); + slen = strlen (str); + buf2 = (char *) alloca (slen * 2 + 1); + hexify (buf2, str, slen); + + str = (tracing_stop_note ? tracing_stop_note : ""); + slen = strlen (str); + buf3 = (char *) alloca (slen * 2 + 1); + hexify (buf3, str, slen); trace_debug ("Returning trace status as %d, stop reason %s", tracing, tracing_stop_reason); @@ -3368,7 +3417,7 @@ cmd_qtstatus (char *packet) stop_reason_rsp = (char *) tracing_stop_reason; /* The user visible error string in terror needs to be hex encoded. - We leave it as plain string in `tracepoint_stop_reason' to ease + We leave it as plain string in `tracing_stop_reason' to ease debugging. */ if (strncmp (stop_reason_rsp, "terror:", strlen ("terror:")) == 0) { @@ -3384,19 +3433,58 @@ cmd_qtstatus (char *packet) convert_int_to_ascii ((gdb_byte *) result_name, p, strlen (result_name)); } + /* If this was a forced stop, include any stop note that was supplied. */ + if (strcmp (stop_reason_rsp, "tstop") == 0) + { + stop_reason_rsp = alloca (strlen ("tstop:") + strlen (buf3) + 1); + strcpy (stop_reason_rsp, "tstop:"); + strcat (stop_reason_rsp, buf3); + } + sprintf (packet, "T%d;" "%s:%x;" "tframes:%x;tcreated:%x;" "tfree:%x;tsize:%s;" "circular:%d;" - "disconn:%d", + "disconn:%d;" + "starttime:%llx;stoptime:%llx;" + "username:%s:;notes:%s:", tracing ? 1 : 0, stop_reason_rsp, tracing_stop_tpnum, traceframe_count, traceframes_created, free_space (), phex_nz (trace_buffer_hi - trace_buffer_lo, 0), circular_trace_buffer, - disconnected_tracing); + disconnected_tracing, + tracing_start_time, tracing_stop_time, + buf1, buf2); +} + +static void +cmd_qtp (char *own_buf) +{ + ULONGEST num, addr; + struct tracepoint *tpoint; + char *packet = own_buf; + + packet += strlen ("qTP:"); + + packet = unpack_varlen_hex (packet, &num); + ++packet; /* skip a colon */ + packet = unpack_varlen_hex (packet, &addr); + + /* See if we already have this tracepoint. */ + tpoint = find_tracepoint (num, addr); + + if (!tpoint) + { + trace_debug ("Tracepoint error: tracepoint %d at 0x%s not found", + (int) num, paddress (addr)); + write_enn (own_buf); + return; + } + + sprintf (own_buf, "V%lx:%lx", tpoint->hit_count, tpoint->traceframe_usage); } /* State variables to help return all the tracepoint bits. */ @@ -3710,6 +3798,63 @@ cmd_bigqtbuffer (char *own_buf) write_enn (own_buf); } +static void +cmd_qtnotes (char *own_buf) +{ + size_t nbytes; + char *saved, *user, *notes, *stopnote; + char *packet = own_buf; + + packet += strlen ("QTNotes:"); + + while (*packet) + { + if (strncmp ("user:", packet, strlen ("user:")) == 0) + { + packet += strlen ("user:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + user = xmalloc (nbytes + 1); + nbytes = unhexify (user, saved, nbytes); + user[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("User is '%s'", user); + tracing_user_name = user; + } + else if (strncmp ("notes:", packet, strlen ("notes:")) == 0) + { + packet += strlen ("notes:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + notes = xmalloc (nbytes + 1); + nbytes = unhexify (notes, saved, nbytes); + notes[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("Notes is '%s'", notes); + tracing_notes = notes; + } + else if (strncmp ("tstop:", packet, strlen ("tstop:")) == 0) + { + packet += strlen ("tstop:"); + saved = packet; + packet = strchr (packet, ';'); + nbytes = (packet - saved) / 2; + stopnote = xmalloc (nbytes + 1); + nbytes = unhexify (stopnote, saved, nbytes); + stopnote[nbytes] = '\0'; + ++packet; /* skip the semicolon */ + trace_debug ("tstop note is '%s'", stopnote); + tracing_stop_note = stopnote; + } + else + break; + } + + write_ok (own_buf); +} + int handle_tracepoint_general_set (char *packet) { @@ -3774,6 +3919,11 @@ handle_tracepoint_general_set (char *packet) cmd_bigqtbuffer (packet); return 1; } + else if (strncmp ("QTNotes:", packet, strlen ("QTNotes:")) == 0) + { + cmd_qtnotes (packet); + return 1; + } return 0; } @@ -3786,6 +3936,11 @@ handle_tracepoint_query (char *packet) cmd_qtstatus (packet); return 1; } + else if (strncmp ("qTP:", packet, strlen ("qTP:")) == 0) + { + cmd_qtp (packet); + return 1; + } else if (strcmp ("qTfP", packet) == 0) { cmd_qtfp (packet); @@ -8049,8 +8204,12 @@ initialize_tracepoint_ftlib (void) #endif /* IN_PROCESS_AGENT */ +/* Return a timestamp, expressed as microseconds of the usual Unix + time. (As the result is a 64-bit number, it will not overflow any + time soon.) */ + static LONGEST -tsv_get_timestamp (void) +get_timestamp (void) { struct timeval tv; @@ -8074,7 +8233,7 @@ initialize_tracepoint (void) variable numbered 1, it will be renumbered.) */ create_trace_state_variable (1, 0); set_trace_state_variable_name (1, "trace_timestamp"); - set_trace_state_variable_getter (1, tsv_get_timestamp); + set_trace_state_variable_getter (1, get_timestamp); #ifdef IN_PROCESS_AGENT { diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index a9c7652b0c..5270fe49ef 100644 --- a/gdb/mi/mi-main.c +++ b/gdb/mi/mi-main.c @@ -2490,7 +2490,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc) void mi_cmd_trace_start (char *command, char **argv, int argc) { - start_tracing (); + start_tracing (NULL); } void @@ -2502,7 +2502,7 @@ mi_cmd_trace_status (char *command, char **argv, int argc) void mi_cmd_trace_stop (char *command, char **argv, int argc) { - stop_tracing (); + stop_tracing (NULL); trace_status_mi (1); } diff --git a/gdb/remote.c b/gdb/remote.c index 6ac5fc0449..8fa5c1abff 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -10214,6 +10214,53 @@ remote_get_trace_status (struct trace_status *ts) return ts->running; } +void +remote_get_tracepoint_status (struct breakpoint *bp, + struct uploaded_tp *utp) +{ + struct remote_state *rs = get_remote_state (); + char addrbuf[40]; + char *reply; + struct bp_location *loc; + struct tracepoint *tp = (struct tracepoint *) bp; + + if (tp) + { + tp->base.hit_count = 0; + tp->traceframe_usage = 0; + for (loc = tp->base.loc; loc; loc = loc->next) + { + /* If the tracepoint was never downloaded, don't go asking for + any status. */ + if (tp->number_on_target == 0) + continue; + sprintf_vma (addrbuf, loc->address); + sprintf (rs->buf, "qTP:%x:%s", tp->number_on_target, addrbuf); + putpkt (rs->buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (reply && *reply) + { + if (*reply == 'V') + parse_tracepoint_status (reply + 1, bp, utp); + } + } + } + else if (utp) + { + utp->hit_count = 0; + utp->traceframe_usage = 0; + sprintf_vma (addrbuf, (long unsigned int) utp->addr); + sprintf (rs->buf, "qTP:%x:%s", utp->number, addrbuf); + putpkt (rs->buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (reply && *reply) + { + if (*reply == 'V') + parse_tracepoint_status (reply + 1, bp, utp); + } + } +} + static void remote_trace_stop (void) { @@ -10485,6 +10532,51 @@ remote_get_min_fast_tracepoint_insn_len (void) } } +static int +remote_set_trace_notes (char *user, char *notes, char *stop_notes) +{ + struct remote_state *rs = get_remote_state (); + char *reply; + char *buf = rs->buf; + char *endbuf = rs->buf + get_remote_packet_size (); + int nbytes; + + buf += xsnprintf (buf, endbuf - buf, "QTNotes:"); + if (user) + { + buf += xsnprintf (buf, endbuf - buf, "user:"); + nbytes = bin2hex (user, buf, 0); + buf += 2 * nbytes; + *buf++ = ';'; + } + if (notes) + { + buf += xsnprintf (buf, endbuf - buf, "notes:"); + nbytes = bin2hex (notes, buf, 0); + buf += 2 * nbytes; + *buf++ = ';'; + } + if (stop_notes) + { + buf += xsnprintf (buf, endbuf - buf, "tstop:"); + nbytes = bin2hex (stop_notes, buf, 0); + buf += 2 * nbytes; + *buf++ = ';'; + } + /* Ensure the buffer is terminated. */ + *buf = '\0'; + + putpkt (rs->buf); + reply = remote_get_noisy_reply (&target_buf, &target_buf_size); + if (*reply == '\0') + return 0; + + if (strcmp (reply, "OK") != 0) + error (_("Bogus reply from target: %s"), reply); + + return 1; +} + static void init_remote_ops (void) { @@ -10565,6 +10657,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_trace_set_readonly_regions = remote_trace_set_readonly_regions; remote_ops.to_trace_start = remote_trace_start; remote_ops.to_get_trace_status = remote_get_trace_status; + remote_ops.to_get_tracepoint_status = remote_get_tracepoint_status; remote_ops.to_trace_stop = remote_trace_stop; remote_ops.to_trace_find = remote_trace_find; remote_ops.to_get_trace_state_variable_value @@ -10577,6 +10670,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len; remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing; remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer; + remote_ops.to_set_trace_notes = remote_set_trace_notes; remote_ops.to_core_of_thread = remote_core_of_thread; remote_ops.to_verify_memory = remote_verify_memory; remote_ops.to_get_tib_address = remote_get_tib_address; diff --git a/gdb/target.c b/gdb/target.c index 09be1ba266..6358b00f48 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -682,6 +682,7 @@ update_current_target (void) INHERIT (to_trace_set_readonly_regions, t); INHERIT (to_trace_start, t); INHERIT (to_get_trace_status, t); + INHERIT (to_get_tracepoint_status, t); INHERIT (to_trace_stop, t); INHERIT (to_trace_find, t); INHERIT (to_get_trace_state_variable_value, t); @@ -692,6 +693,7 @@ update_current_target (void) INHERIT (to_get_min_fast_tracepoint_insn_len, t); INHERIT (to_set_disconnected_tracing, t); INHERIT (to_set_circular_trace_buffer, t); + INHERIT (to_set_trace_notes, t); INHERIT (to_get_tib_address, t); INHERIT (to_set_permissions, t); INHERIT (to_static_tracepoint_marker_at, t); @@ -873,6 +875,9 @@ update_current_target (void) de_fault (to_get_trace_status, (int (*) (struct trace_status *)) return_minus_one); + de_fault (to_get_tracepoint_status, + (void (*) (struct breakpoint *, struct uploaded_tp *)) + tcomplain); de_fault (to_trace_stop, (void (*) (void)) tcomplain); @@ -903,6 +908,9 @@ update_current_target (void) de_fault (to_set_circular_trace_buffer, (void (*) (int)) target_ignore); + de_fault (to_set_trace_notes, + (int (*) (char *, char *, char *)) + return_zero); de_fault (to_get_tib_address, (int (*) (ptid_t, CORE_ADDR *)) tcomplain); diff --git a/gdb/target.h b/gdb/target.h index 87f0bb9d89..73c8f7ca30 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -713,6 +713,9 @@ struct target_ops /* Get the current status of a tracing run. */ int (*to_get_trace_status) (struct trace_status *ts); + void (*to_get_tracepoint_status) (struct breakpoint *tp, + struct uploaded_tp *utp); + /* Stop a trace run. */ void (*to_trace_stop) (void); @@ -749,6 +752,10 @@ struct target_ops void (*to_set_disconnected_tracing) (int val); void (*to_set_circular_trace_buffer) (int val); + /* Add/change textual notes about the trace run, returning 1 if + successful, 0 otherwise. */ + int (*to_set_trace_notes) (char *user, char *notes, char* stopnotes); + /* Return the processor core that thread PTID was last seen on. This information is updated only when: - update_thread_list is called @@ -1508,6 +1515,9 @@ extern int target_search_memory (CORE_ADDR start_addr, #define target_get_trace_status(ts) \ (*current_target.to_get_trace_status) (ts) +#define target_get_tracepoint_status(tp,utp) \ + (*current_target.to_get_tracepoint_status) (tp, utp) + #define target_trace_stop() \ (*current_target.to_trace_stop) () @@ -1538,6 +1548,9 @@ extern int target_search_memory (CORE_ADDR start_addr, #define target_set_circular_trace_buffer(val) \ (*current_target.to_set_circular_trace_buffer) (val) +#define target_set_trace_notes(user,notes,stopnotes) \ + (*current_target.to_set_trace_notes) ((user), (notes), (stopnotes)) + #define target_get_tib_address(ptid, addr) \ (*current_target.to_get_tib_address) ((ptid), (addr)) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 86aecc2fb1..d407158020 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2011-11-20 Stan Shebs + + * gdb.trace/tstatus.exp: New. + * gdb.trace/actions.c: Include string.h. + 2011-11-18 Yao Qi * gdb.trace/pending.exp: New. diff --git a/gdb/testsuite/gdb.trace/actions.c b/gdb/testsuite/gdb.trace/actions.c index ae3c1c38c1..270e1e100f 100644 --- a/gdb/testsuite/gdb.trace/actions.c +++ b/gdb/testsuite/gdb.trace/actions.c @@ -2,6 +2,8 @@ * Test program for trace action commands */ +#include + static char gdb_char_test; static short gdb_short_test; static long gdb_long_test; diff --git a/gdb/testsuite/gdb.trace/tstatus.exp b/gdb/testsuite/gdb.trace/tstatus.exp new file mode 100644 index 0000000000..36f925d3e5 --- /dev/null +++ b/gdb/testsuite/gdb.trace/tstatus.exp @@ -0,0 +1,172 @@ +# Copyright 2011 Free Software Foundation, Inc. +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +load_lib "trace-support.exp" + +set testfile "actions" +set executable $testfile +set srcfile $testfile.c +set binfile $objdir/$subdir/$testfile +set expfile tstatus.exp + +if [prepare_for_testing $expfile $executable $srcfile \ + [list debug]] { + untested "failed to prepare for trace tests" + return -1 +} + +if ![runto_main] { + fail "Can't run to main to check for trace support" + return -1 +} + +if ![gdb_target_supports_trace] { + unsupported "target does not support trace" + return -1 +} + +set libipa $objdir/../gdbserver/libinproctrace.so +gdb_load_shlibs $libipa + +# Can't use prepare_for_testing, because that splits compiling into +# building objects and then linking, and we'd fail with "linker input +# file unused because linking not done" when building the object. + +if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile \ + executable [list debug shlib=$libipa] ] != "" } { + untested "failed to compile ftrace tests" + return -1 +} +clean_restart ${executable} + +if ![runto_main] { + fail "Can't run to main for ftrace tests" + return 0 +} + +proc run_trace_experiment {} { + +# gdb_test_no_output "set debug remote 1" "" + + gdb_test "continue" \ + ".*Breakpoint \[0-9\]+, begin .*" \ + "advance to trace begin" + + gdb_test_no_output "tstart my tracing note" "start trace experiment" + + gdb_test "continue" \ + ".*Breakpoint \[0-9\]+, end .*" \ + "advance through tracing" + + # Now play with tstatus a bit. + # Since note support is optional, we need to match both with and without + # cases. + + gdb_test_multiple "tstatus" "check on trace status" { + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: my tracing note\.\[\r\n\]+Not looking at any trace frame\..*" { + pass "tstatus reports trace note" + } + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" { + pass "tstatus does not report any trace note" + } + } + + gdb_test "set trace-notes different note" "" "change tracing note" + + gdb_test_multiple "tstatus" "check on trace status with diff note" { + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" { + pass "tstatus reports different trace note" + } + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" { + pass "tstatus does not report any different trace note" + } + } + + gdb_test "set trace-user me me me" "" "change tracing user" + + gdb_test_multiple "tstatus" "check on trace status with diff note" { + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" { + pass "tstatus reports trace user" + } + -re "Trace is running.*Trace will stop if GDB disconnects\.\[\r\n\]+Not looking at any trace frame.*" { + pass "tstatus does not report trace user" + } + } + + gdb_test_no_output "tstop because I can" "trace stopped with note" + + gdb_test_multiple "tstatus" "check on trace status after stop" { + -re "Trace stopped by a tstop command (because I can)\..*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*" { + pass "tstatus reports trace stop reason" + } + -re "Trace stopped by a tstop command\..*" { + pass "tstatus does not report trace stop reason" + } + } + + # Tracepoint hit count is optional, so pass it either way. + + gdb_test_multiple "info trace" "show tracepoint state" { + -re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+tracepoint already hit 1 time\[\r\n\]+\[\t ]+collect parm" { + pass "info trace reports tracepoint hit count" + } + -re "actions\.c:\[0-9\]+\[\r\n\]+\[\t ]+collect parm" { + pass "info trace does not report tracepoint hit count" + } + } +} + +proc test_tracepoints {} { + + gdb_test "break begin" ".*" "" + + gdb_test "break end" ".*" "" + + gdb_test "trace gdb_c_test" "Tracepoint .*" \ + "tracepoint at gdb_c_test" + + gdb_trace_setactions "collect at set_point: define actions" \ + "" \ + "collect parm" "^$" + set fastgood 0 + + gdb_test_multiple "ftrace gdb_recursion_test" "set fast tracepoint" { + -re "May not have a fast tracepoint at .*" { + pass "4-byte fast tracepoint could not be set" + } + -re "Fast tracepoint .*" { + pass "4-byte fast tracepoint is set" + set fastgood 1 + } + } + + if { $fastgood } { + + gdb_trace_setactions "collect at four_byter: define actions" \ + "" \ + "collect globvar, anarg" "^$" + } + + run_trace_experiment + +} + +gdb_reinitialize_dir $srcdir/$subdir + +if { [gdb_test "info sharedlibrary" ".*libinproctrace\.so.*" "IPA loaded"] != 0 } { + untested "Could not find IPA lib loaded" + return 1 +} + +test_tracepoints diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp index aeeb585eaf..ec88b66a57 100644 --- a/gdb/testsuite/lib/gdbserver-support.exp +++ b/gdb/testsuite/lib/gdbserver-support.exp @@ -224,6 +224,7 @@ proc gdbserver_start { options arguments } { global gdbserver_reconnect_p if {![info exists gdbserver_reconnect_p] || !$gdbserver_reconnect_p} { # GDB client could accidentally connect to a stale server. + # append gdbserver_command " --debug --once" append gdbserver_command " --once" } diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index 97ab633b50..9b0738e2ff 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -178,6 +178,18 @@ static int disconnected_tracing; static int circular_trace_buffer; +/* Textual notes applying to the current and/or future trace runs. */ + +char *trace_user = NULL; + +/* Textual notes applying to the current and/or future trace runs. */ + +char *trace_notes = NULL; + +/* Textual notes applying to the stopping of a trace. */ + +char *trace_stop_notes = NULL; + /* ======= Important command functions: ======= */ static void trace_actions_command (char *, int); static void trace_start_command (char *, int); @@ -199,8 +211,6 @@ static char *mem2hex (gdb_byte *, char *, int); static void add_register (struct collection_list *collection, unsigned int regno); -extern void send_disconnected_tracing_value (int value); - static void free_uploaded_tps (struct uploaded_tp **utpp); static void free_uploaded_tsvs (struct uploaded_tsv **utsvp); @@ -1686,14 +1696,15 @@ process_tracepoint_on_disconnect (void) void -start_tracing (void) +start_tracing (char *notes) { VEC(breakpoint_p) *tp_vec = NULL; int ix; struct breakpoint *b; struct trace_state_variable *tsv; int any_enabled = 0, num_to_download = 0; - + int ret; + tp_vec = all_tracepoints (); /* No point in tracing without any tracepoints... */ @@ -1779,6 +1790,13 @@ start_tracing (void) target_set_disconnected_tracing (disconnected_tracing); target_set_circular_trace_buffer (circular_trace_buffer); + if (!notes) + notes = trace_notes; + ret = target_set_trace_notes (trace_user, notes, NULL); + + if (!ret && (trace_user || notes)) + warning ("Target does not support trace user/notes, info ignored"); + /* Now insert traps and begin collecting data. */ target_trace_start (); @@ -1790,12 +1808,11 @@ start_tracing (void) clear_traceframe_info (); } -/* tstart command: - - Tell target to clear any previous trace experiment. - Walk the list of tracepoints, and send them (and their actions) - to the target. If no errors, - Tell target to start a new trace experiment. */ +/* The tstart command requests the target to start a new trace run. + The command passes any arguments it has to the target verbatim, as + an optional "trace note". This is useful as for instance a warning + to other users if the trace runs disconnected, and you don't want + anybody else messing with the target. */ static void trace_start_command (char *args, int from_tty) @@ -1809,23 +1826,37 @@ trace_start_command (char *args, int from_tty) error (_("New trace run not started.")); } - start_tracing (); + start_tracing (args); } -/* tstop command */ +/* The tstop command stops the tracing run. The command passes any + supplied arguments to the target verbatim as a "stop note"; if the + target supports trace notes, then it will be reported back as part + of the trace run's status. */ + static void trace_stop_command (char *args, int from_tty) { if (!current_trace_status ()->running) error (_("Trace is not running.")); - stop_tracing (); + stop_tracing (args); } void -stop_tracing (void) +stop_tracing (char *note) { + int ret; + target_trace_stop (); + + if (!note) + note = trace_stop_notes; + ret = target_set_trace_notes (NULL, NULL, note); + + if (!ret && note) + warning ("Target does not support trace notes, note ignored"); + /* Should change in response to reply? */ current_trace_status ()->running = 0; } @@ -1835,7 +1866,9 @@ static void trace_status_command (char *args, int from_tty) { struct trace_status *ts = current_trace_status (); - int status; + int status, ix; + VEC(breakpoint_p) *tp_vec = NULL; + struct breakpoint *t; status = target_get_trace_status (ts); @@ -1866,7 +1899,11 @@ trace_status_command (char *args, int from_tty) printf_filtered (_("No trace has been run on the target.\n")); break; case tstop_command: - printf_filtered (_("Trace stopped by a tstop command.\n")); + if (ts->stop_desc) + printf_filtered (_("Trace stopped by a tstop command (%s).\n"), + ts->stop_desc); + else + printf_filtered (_("Trace stopped by a tstop command.\n")); break; case trace_buffer_full: printf_filtered (_("Trace stopped because the buffer was full.\n")); @@ -1882,10 +1919,10 @@ trace_status_command (char *args, int from_tty) if (ts->stopping_tracepoint) printf_filtered (_("Trace stopped by an " "error (%s, tracepoint %d).\n"), - ts->error_desc, ts->stopping_tracepoint); + ts->stop_desc, ts->stopping_tracepoint); else printf_filtered (_("Trace stopped by an error (%s).\n"), - ts->error_desc); + ts->stop_desc); break; case trace_stop_reason_unknown: printf_filtered (_("Trace stopped for an unknown reason.\n")); @@ -1936,12 +1973,46 @@ trace_status_command (char *args, int from_tty) if (ts->circular_buffer) printf_filtered (_("Trace buffer is circular.\n")); + if (ts->user_name && strlen (ts->user_name) > 0) + printf_filtered (_("Trace user is %s.\n"), ts->user_name); + + if (ts->notes && strlen (ts->notes) > 0) + printf_filtered (_("Trace notes: %s.\n"), ts->notes); + /* Now report on what we're doing with tfind. */ if (traceframe_number >= 0) printf_filtered (_("Looking at trace frame %d, tracepoint %d.\n"), traceframe_number, tracepoint_number); else printf_filtered (_("Not looking at any trace frame.\n")); + + /* Report start/stop times if supplied. */ + if (ts->start_time) + { + if (ts->stop_time) + { + LONGEST run_time = ts->stop_time - ts->start_time; + + /* Reporting a run time is more readable than two long numbers. */ + printf_filtered (_("Trace started at %ld.%06ld secs, stopped %ld.%06ld secs later.\n"), + ts->start_time / 1000000, ts->start_time % 1000000, + run_time / 1000000, run_time % 1000000); + } + else + printf_filtered (_("Trace started at %ld.%06ld secs.\n"), + ts->start_time / 1000000, ts->start_time % 1000000); + } + else if (ts->stop_time) + printf_filtered (_("Trace stopped at %ld.%06ld secs.\n"), + ts->stop_time / 1000000, ts->stop_time % 1000000); + + /* Now report any per-tracepoint status available. */ + tp_vec = all_tracepoints (); + + for (ix = 0; VEC_iterate (breakpoint_p, tp_vec, ix, t); ix++) + target_get_tracepoint_status (t, NULL); + + VEC_free (breakpoint_p, tp_vec); } /* Report the trace status to uiout, in a way suitable for MI, and not @@ -2024,7 +2095,7 @@ trace_status_mi (int on_stop) stopping_tracepoint); if (ts->stop_reason == tracepoint_error) ui_out_field_string (uiout, "error-description", - ts->error_desc); + ts->stop_desc); } } } @@ -2040,6 +2111,20 @@ trace_status_mi (int on_stop) ui_out_field_int (uiout, "disconnected", ts->disconnected_tracing); ui_out_field_int (uiout, "circular", ts->circular_buffer); + + ui_out_field_string (uiout, "user-name", ts->user_name); + ui_out_field_string (uiout, "notes", ts->notes); + + { + char buf[100]; + + xsnprintf (buf, sizeof buf, "%ld.%06ld", + ts->start_time / 1000000, ts->start_time % 1000000); + ui_out_field_string (uiout, "start-time", buf); + xsnprintf (buf, sizeof buf, "%ld.%06ld", + ts->stop_time / 1000000, ts->stop_time % 1000000); + ui_out_field_string (uiout, "stop-time", buf); + } } /* This function handles the details of what to do about an ongoing @@ -2881,9 +2966,9 @@ trace_save (const char *filename, int target_does_save) (ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]); if (ts->stop_reason == tracepoint_error) { - char *buf = (char *) alloca (strlen (ts->error_desc) * 2 + 1); + char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1); - bin2hex ((gdb_byte *) ts->error_desc, buf, 0); + bin2hex ((gdb_byte *) ts->stop_desc, buf, 0); fprintf (fp, ":%s", buf); } fprintf (fp, ":%x", ts->stopping_tracepoint); @@ -2935,6 +3020,9 @@ trace_save (const char *filename, int target_does_save) 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) { fprintf (fp, "tp T%x:%s:%c:%x:%x", @@ -2971,6 +3059,11 @@ trace_save (const char *filename, int target_does_save) buf, MAX_TRACE_UPLOAD); fprintf (fp, "tp Z%s\n", buf); } + fprintf (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))); } free_uploaded_tps (&uploaded_tps); @@ -3041,17 +3134,11 @@ trace_save_command (char *args, int from_tty) /* Tell the target what to do with an ongoing tracing run if GDB disconnects for some reason. */ -void -send_disconnected_tracing_value (int value) -{ - target_set_disconnected_tracing (value); -} - static void set_disconnected_tracing (char *args, int from_tty, struct cmd_list_element *c) { - send_disconnected_tracing_value (disconnected_tracing); + target_set_disconnected_tracing (disconnected_tracing); } static void @@ -3061,6 +3148,42 @@ set_circular_trace_buffer (char *args, int from_tty, target_set_circular_trace_buffer (circular_trace_buffer); } +static void +set_trace_user (char *args, int from_tty, + struct cmd_list_element *c) +{ + int ret; + + ret = target_set_trace_notes (trace_user, NULL, NULL); + + if (!ret) + warning ("Target does not support trace notes, user ignored"); +} + +static void +set_trace_notes (char *args, int from_tty, + struct cmd_list_element *c) +{ + int ret; + + ret = target_set_trace_notes (NULL, trace_notes, NULL); + + if (!ret) + warning ("Target does not support trace notes, note ignored"); +} + +static void +set_trace_stop_notes (char *args, int from_tty, + struct cmd_list_element *c) +{ + int ret; + + ret = target_set_trace_notes (NULL, NULL, trace_stop_notes); + + if (!ret) + warning ("Target does not support trace notes, stop note ignored"); +} + /* Convert the memory pointed to by mem into hex, placing result in buf. * Return a pointer to the last char put in buf (null) * "stolen" from sparc-stub.c @@ -3638,20 +3761,26 @@ tfile_interp_line (char *line, void parse_trace_status (char *line, struct trace_status *ts) { - char *p = line, *p1, *p2, *p_temp; + char *p = line, *p1, *p2, *p3, *p_temp; + int end; ULONGEST val; ts->running_known = 1; ts->running = (*p++ == '1'); ts->stop_reason = trace_stop_reason_unknown; - xfree (ts->error_desc); - ts->error_desc = NULL; + xfree (ts->stop_desc); + ts->stop_desc = NULL; ts->traceframe_count = -1; ts->traceframes_created = -1; ts->buffer_free = -1; ts->buffer_size = -1; ts->disconnected_tracing = 0; ts->circular_buffer = 0; + xfree (ts->user_name); + ts->user_name = NULL; + xfree (ts->notes); + ts->notes = NULL; + ts->start_time = ts->stop_time = 0; while (*p++) { @@ -3659,6 +3788,9 @@ parse_trace_status (char *line, struct trace_status *ts) if (p1 == NULL) error (_("Malformed trace status, at %s\n\ Status line: '%s'\n"), p, line); + p3 = strchr (p, ';'); + if (p3 == NULL) + p3 = p + strlen (p); if (strncmp (p, stop_reason_names[trace_buffer_full], p1 - p) == 0) { p = unpack_varlen_hex (++p1, &val); @@ -3678,7 +3810,22 @@ Status line: '%s'\n"), p, line); } else if (strncmp (p, stop_reason_names[tstop_command], p1 - p) == 0) { - p = unpack_varlen_hex (++p1, &val); + p2 = strchr (++p1, ':'); + if (!p2 || p2 > p3) + { + /*older style*/ + p2 = p1; + } + else if (p2 != p1) + { + ts->stop_desc = xmalloc (strlen (line)); + end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2); + ts->stop_desc[end] = '\0'; + } + else + ts->stop_desc = xstrdup (""); + + p = unpack_varlen_hex (++p2, &val); ts->stop_reason = tstop_command; } else if (strncmp (p, stop_reason_names[trace_disconnected], p1 - p) == 0) @@ -3691,14 +3838,12 @@ Status line: '%s'\n"), p, line); p2 = strchr (++p1, ':'); if (p2 != p1) { - int end; - - ts->error_desc = xmalloc ((p2 - p1) / 2 + 1); - end = hex2bin (p1, ts->error_desc, (p2 - p1) / 2); - ts->error_desc[end] = '\0'; + ts->stop_desc = xmalloc ((p2 - p1) / 2 + 1); + end = hex2bin (p1, ts->stop_desc, (p2 - p1) / 2); + ts->stop_desc[end] = '\0'; } else - ts->error_desc = xstrdup (""); + ts->stop_desc = xstrdup (""); p = unpack_varlen_hex (++p2, &val); ts->stopping_tracepoint = val; @@ -3734,6 +3879,32 @@ Status line: '%s'\n"), p, line); p = unpack_varlen_hex (++p1, &val); ts->circular_buffer = val; } + else if (strncmp (p, "starttime", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->start_time = val; + } + else if (strncmp (p, "stoptime", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->stop_time = val; + } + else if (strncmp (p, "username", p1 - p) == 0) + { + ++p1; + ts->user_name = xmalloc (strlen (p) / 2); + end = hex2bin (p1, ts->user_name, (p3 - p1) / 2); + ts->user_name[end] = '\0'; + p = p3; + } + else if (strncmp (p, "notes", p1 - p) == 0) + { + ++p1; + ts->notes = xmalloc (strlen (p) / 2); + end = hex2bin (p1, ts->notes, (p3 - p1) / 2); + ts->notes[end] = '\0'; + p = p3; + } else { /* Silently skip unknown optional info. */ @@ -3747,6 +3918,26 @@ Status line: '%s'\n"), p, line); } } +void +parse_tracepoint_status (char *p, struct breakpoint *bp, + struct uploaded_tp *utp) +{ + ULONGEST uval; + struct tracepoint *tp = (struct tracepoint *) bp; + + p = unpack_varlen_hex (p, &uval); + if (tp) + tp->base.hit_count += uval; + else + utp->hit_count += uval; + p = unpack_varlen_hex (p + 1, &uval); + if (tp) + tp->traceframe_usage += uval; + else + utp->traceframe_usage += uval; + /* Ignore any extra, allowing for future extensions. */ +} + /* Given a line of text defining a part of a tracepoint, parse it into an "uploaded tracepoint". */ @@ -3848,6 +4039,12 @@ parse_tracepoint_definition (char *line, struct uploaded_tp **utpp) else if (strncmp (srctype, "cmd:", strlen ("cmd:")) == 0) VEC_safe_push (char_ptr, utp->cmd_strings, xstrdup (buf)); } + else if (piece == 'V') + { + utp = get_uploaded_tp (num, addr, utpp); + + parse_tracepoint_status (p, NULL, utp); + } else { /* Don't error out, the target might be sending us optional @@ -3923,6 +4120,13 @@ tfile_get_trace_status (struct trace_status *ts) 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 @@ -4464,6 +4668,7 @@ init_tfile_ops (void) 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; @@ -5008,11 +5213,17 @@ De-select any trace frame and resume 'live' debugging."), add_com ("tstatus", class_trace, trace_status_command, _("Display the status of the current trace data collection.")); - add_com ("tstop", class_trace, trace_stop_command, - _("Stop trace data collection.")); + add_com ("tstop", class_trace, trace_stop_command, _("\ +Stop trace data collection.\n\ +Usage: tstop [ ... ]\n\ +Any arguments supplied are recorded with the trace as a stop reason and\n\ +reported by tstatus (if the target supports trace notes).")); - add_com ("tstart", class_trace, trace_start_command, - _("Start trace data collection.")); + add_com ("tstart", class_trace, trace_start_command, _("\ +Start trace data collection.\n\ +Usage: tstart [ ... ]\n\ +Any arguments supplied are recorded with the trace as a note and\n\ +reported by tstatus (if the target supports trace notes).")); add_com ("end", class_trace, end_actions_pseudocommand, _("\ Ends a list of commands or actions.\n\ @@ -5087,6 +5298,27 @@ up and stopping the trace run."), &setlist, &showlist); + add_setshow_string_cmd ("trace-user", class_trace, + &trace_user, _("\ +Set the user name to use for current and future trace runs"), _("\ +Show the user name to use for current and future trace runs"), NULL, + set_trace_user, NULL, + &setlist, &showlist); + + add_setshow_string_cmd ("trace-notes", class_trace, + &trace_notes, _("\ +Set notes string to use for current and future trace runs"), _("\ +Show the notes string to use for current and future trace runs"), NULL, + set_trace_notes, NULL, + &setlist, &showlist); + + add_setshow_string_cmd ("trace-stop-notes", class_trace, + &trace_stop_notes, _("\ +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 (&tfile_ops); diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index bf8fa443b4..b112352bbd 100644 --- a/gdb/tracepoint.h +++ b/gdb/tracepoint.h @@ -79,6 +79,7 @@ struct trace_status /* This is true if the value of the running field is known. */ int running_known; + /* This is true when the trace experiment is actually running. */ int running; enum trace_stop_reason stop_reason; @@ -88,9 +89,11 @@ struct trace_status stop. */ int stopping_tracepoint; - /* If stop_reason is tracepoint_error, this is a human-readable - string that describes the error that happened on the target. */ - char *error_desc; + /* If stop_reason is tstop_command or tracepoint_error, this is an + arbitrary string that may describe the reason for the stop in + more detail. */ + + char *stop_desc; /* Number of traceframes currently in the buffer. */ @@ -117,6 +120,22 @@ struct trace_status target does not report a value, assume 0. */ int circular_buffer; + + /* The "name" of the person running the trace. This is an + arbitrary string. */ + + char *user_name; + + /* "Notes" about the trace. This is an arbitrary string not + interpreted by GDBserver in any special way. */ + + char *notes; + + /* The calendar times at which the trace run started and stopped, + both expressed in microseconds of Unix time. */ + + LONGEST start_time; + LONGEST stop_time; }; struct trace_status *current_trace_status (void); @@ -154,6 +173,12 @@ struct uploaded_tp /* List of original strings defining the tracepoint's actions. */ VEC(char_ptr) *cmd_strings; + /* The tracepoint's current hit count. */ + int hit_count; + + /* The tracepoint's current traceframe usage. */ + ULONGEST traceframe_usage; + struct uploaded_tp *next; }; @@ -229,6 +254,9 @@ extern int encode_source_string (int num, ULONGEST addr, extern void parse_trace_status (char *line, struct trace_status *ts); +extern void parse_tracepoint_status (char *p, struct breakpoint *tp, + struct uploaded_tp *utp); + extern void parse_tracepoint_definition (char *line, struct uploaded_tp **utpp); extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp); @@ -241,8 +269,8 @@ extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp); extern void disconnect_tracing (int from_tty); -extern void start_tracing (void); -extern void stop_tracing (void); +extern void start_tracing (char *notes); +extern void stop_tracing (char *notes); extern void trace_status_mi (int on_stop);