From 4daf5ac07eb7f8cd187f7800785b2e5a465fc38a Mon Sep 17 00:00:00 2001 From: Stan Shebs Date: Thu, 18 Mar 2010 21:23:35 +0000 Subject: [PATCH] 2010-03-18 Stan Shebs Pedro Alves * target.h (struct target_ops): New method to_set_circular_trace_buffer. (target_set_circular_trace_buffer): New macro. * target.c (update_current_target): Add to_set_circular_trace_buffer, fix to_set_disconnected_tracing default behavior. * remote.c (remote_set_circular_trace_buffer): New function. (init_remote_ops): Add it to vector. * tracepoint.h (struct trace_status): New field traceframes_created, change buffer_size and buffer_free to int. * tracepoint.c (circular_trace_buffer): New global. (start_tracing): Send values of disconnected tracing and circular trace buffer settings. (set_circular_trace_buffer): New function. (parse_trace_state): Handle total space and frames created. (trace_status_command): Display total space and total frames created. (trace_save): Write out new status values. (parse_trace_status): Set traceframe_count, traceframes_created, buffer_free and buffer_size to -1 by default. (_initialize_tracepoint): New setshow for circular-trace-buffer. * NEWS: Mention the circular trace buffer option. * gdb.texinfo (Starting and Stopping Trace Experiments): Describe circular-trace-buffer. (Tracepoint Packets): Describe QTBuffer, and details of the qTStatus reply. * gdb.trace/circ.exp: Test circular-trace-buffer. * gdb.trace/tfile.exp: Update tstatus test. --- gdb/ChangeLog | 26 +++++++++ gdb/NEWS | 19 +++++- gdb/doc/ChangeLog | 7 +++ gdb/doc/gdb.texinfo | 96 +++++++++++++++++++++++++++++-- gdb/remote.c | 13 +++++ gdb/target.c | 6 +- gdb/target.h | 4 ++ gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.trace/circ.exp | 9 +++ gdb/testsuite/gdb.trace/tfile.exp | 4 +- gdb/tracepoint.c | 86 ++++++++++++++++++++++++--- gdb/tracepoint.h | 14 ++++- 12 files changed, 269 insertions(+), 20 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 2cf42aa614..55462bb474 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,29 @@ +2010-03-18 Stan Shebs + Pedro Alves + + * target.h (struct target_ops): New method + to_set_circular_trace_buffer. + (target_set_circular_trace_buffer): New macro. + * target.c (update_current_target): Add + to_set_circular_trace_buffer, fix to_set_disconnected_tracing + default behavior. + * remote.c (remote_set_circular_trace_buffer): New function. + (init_remote_ops): Add it to vector. + * tracepoint.h (struct trace_status): New field traceframes_created, + change buffer_size and buffer_free to int. + * tracepoint.c (circular_trace_buffer): New global. + (start_tracing): Send values of disconnected tracing and circular + trace buffer settings. + (set_circular_trace_buffer): New function. + (parse_trace_state): Handle total space and frames created. + (trace_status_command): Display total space and total frames + created. + (trace_save): Write out new status values. + (parse_trace_status): Set traceframe_count, traceframes_created, + buffer_free and buffer_size to -1 by default. + (_initialize_tracepoint): New setshow for circular-trace-buffer. + * NEWS: Mention the circular trace buffer option. + 2010-03-18 Tom Tromey * infcmd.c (finish_command_continuation): Wrap print_return_value diff --git a/gdb/NEWS b/gdb/NEWS index 64c48f6378..ff4e4afce9 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -114,7 +114,14 @@ Renesas RX rx tracing run at the moment that it was saved. To create a trace file, use "tsave ", and to use it, do "target tfile ". - + + ** Circular trace buffer + + You can ask the target agent to handle the trace buffer as a + circular buffer, discarding the oldest trace frames to make room for + newer ones, by setting circular-trace-buffer to on. This feature may + not be available for all target agents. + * Changed commands disassemble @@ -215,6 +222,13 @@ show disconnected-tracing loses its connection to GDB. If 0, the target is to stop tracing upon disconnection. +set circular-trace-buffer +show circular-trace-buffer + If set to on, the target is instructed to use a circular trace buffer + and discard the oldest trace frames instead of stopping the trace due + to a full trace buffer. If set to off, the trace stops when the buffer + fills up. Some targets may not support this. + set script-extension off|soft|strict show script-extension If set to "off", the debugger does not perform any script language @@ -258,6 +272,9 @@ qTV QTDisconnected Set desired tracing behavior upon disconnection. +QTBuffer:circular + Set the trace buffer to be linear or circular. + qTfP, qTsP Get data about the tracepoints currently in use. diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 7a9590ef54..e85827becc 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,10 @@ +2010-03-16 Stan Shebs + + * gdb.texinfo (Starting and Stopping Trace Experiments): Describe + circular-trace-buffer. + (Tracepoint Packets): Describe QTBuffer, and details of the + qTStatus reply. + 2010-03-12 Stan Shebs Nathan Sidwell diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 53989bb9b3..92a1237491 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -9836,6 +9836,37 @@ which to specify that tracepoint. This matching-up process is necessarily heuristic, and it may result in useless tracepoints being created; you may simply delete them if they are of no use. +@cindex circular trace buffer +If your target agent supports a @dfn{circular trace buffer}, then you +can run a trace experiment indefinitely without filling the trace +buffer; when space runs out, the agent deletes already-collected trace +frames, oldest first, until there is enough room to continue +collecting. This is especially useful if your tracepoints are being +hit too often, and your trace gets terminated prematurely because the +buffer is full. To ask for a circular trace buffer, simply set +@samp{circular_trace_buffer} to on. You can set this at any time, +including during tracing; if the agent can do it, it will change +buffer handling on the fly, otherwise it will not take effect until +the next run. + +@table @code +@item set circular-trace-buffer on +@itemx set circular-trace-buffer off +@kindex set circular-trace-buffer +Choose whether a tracing run should use a linear or circular buffer +for trace data. A linear buffer will not lose any trace data, but may +fill up prematurely, while a circular buffer will discard old trace +data, but it will have always room for the latest tracepoint hits. + +@item show circular-trace-buffer +@kindex show circular-trace-buffer +Show the current choice for the trace buffer. Note that this may not +match the agent's current buffer handling, nor is it guaranteed to +match the setting that might have been in effect during a past run, +for instance if you are looking at frames from a trace file. + +@end table + @node Tracepoint Restrictions @subsection Tracepoint Restrictions @@ -30603,6 +30634,7 @@ encoded). @value{GDBN} will continue to supply the values of symbols @end table @item qTBuffer +@item QTBuffer @item QTDisconnected @itemx QTDP @itemx QTDV @@ -31087,12 +31119,62 @@ continue the tracing run, while 0 tells the target to stop tracing if @item qTStatus Ask the stub if there is a trace experiment running right now. -Replies: +The reply has the form: + +@table @samp + +@item T@var{running}@r{[};@var{field}@r{]}@dots{} +@var{running} is a single digit @code{1} if the trace is presently +running, or @code{0} if not. It is followed by semicolon-separated +optional fields that an agent may use to report additional status. + +@end table + +If the trace is not running, the agent may report any of several +explanations as one of the optional fields: + +@table @samp + +@item tnotrun:0 +No trace has been run yet. + +@item tstop:0 +The trace was stopped by a user-originated stop command. + +@item tfull:0 +The trace stopped because the trace buffer filled up. + +@item tdisconnected:0 +The trace stopped because @value{GDBN} disconnected from the target. + +@item tpasscount:@var{tpnum} +The trace stopped because tracepoint @var{tpnum} exceeded its pass count. + +@item tunknown:0 +The trace stopped for some other reason. + +@end table + +Additional optional fields supply statistical information. Although +not required, they are extremely useful for users monitoring the +progress of a trace run. If a trace has stopped, and these numbers +are reported, they must reflect the state of the just-stopped trace. + @table @samp -@item T0 -There is no trace experiment running. -@item T1 -There is a trace experiment running. + +@item tframes:@var{n} +The number of trace frames in the buffer. + +@item tcreated:@var{n} +The total number of trace frames created during the run. This may +be larger than the trace frame count, if the buffer is circular. + +@item tsize:@var{n} +The total size of the trace buffer, in bytes. + +@item tfree:@var{n} +The number of bytes still unused in the buffer. + @end table @item qTV:@var{var} @@ -31147,6 +31229,10 @@ in a packet; it is not an error to return fewer than were asked for. A reply consisting of just @code{l} indicates that no bytes are available. +@item QTBuffer:circular:@var{value} +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. + @end table @node Host I/O Packets diff --git a/gdb/remote.c b/gdb/remote.c index 01d558cb32..024b6296dc 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -9658,6 +9658,18 @@ remote_core_of_thread (struct target_ops *ops, ptid_t ptid) return -1; } +static void +remote_set_circular_trace_buffer (int val) +{ + struct remote_state *rs = get_remote_state (); + + sprintf (rs->buf, "QTBuffer:circular:%x", val); + putpkt (rs->buf); + remote_get_noisy_reply (&target_buf, &target_buf_size); + if (strcmp (target_buf, "OK")) + error (_("Target does not support this command.")); +} + static void init_remote_ops (void) { @@ -9736,6 +9748,7 @@ Specify the serial device it is connected to\n\ 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_set_circular_trace_buffer = remote_set_circular_trace_buffer; remote_ops.to_core_of_thread = remote_core_of_thread; } diff --git a/gdb/target.c b/gdb/target.c index f253ee0713..bd5711f19a 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -659,6 +659,7 @@ update_current_target (void) INHERIT (to_upload_trace_state_variables, t); INHERIT (to_get_raw_trace_data, t); INHERIT (to_set_disconnected_tracing, t); + INHERIT (to_set_circular_trace_buffer, t); INHERIT (to_magic, t); /* Do not inherit to_memory_map. */ /* Do not inherit to_flash_erase. */ @@ -848,7 +849,10 @@ update_current_target (void) tcomplain); de_fault (to_set_disconnected_tracing, (void (*) (int)) - tcomplain); + target_ignore); + de_fault (to_set_circular_trace_buffer, + (void (*) (int)) + target_ignore); #undef de_fault /* Finally, position the target-stack beneath the squashed diff --git a/gdb/target.h b/gdb/target.h index 7fd9badaca..2b21f0f734 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -664,6 +664,7 @@ struct target_ops /* Set the target's tracing behavior in response to unexpected disconnection - set VAL to 1 to keep tracing, 0 to stop. */ void (*to_set_disconnected_tracing) (int val); + void (*to_set_circular_trace_buffer) (int val); /* Return the processor core that thread PTID was last seen on. This information is updated only when: @@ -1359,6 +1360,9 @@ extern int target_search_memory (CORE_ADDR start_addr, #define target_set_disconnected_tracing(val) \ (*current_target.to_set_disconnected_tracing) (val) +#define target_set_circular_trace_buffer(val) \ + (*current_target.to_set_circular_trace_buffer) (val) + /* Command logging facility. */ #define target_log_command(p) \ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 8c60bdcc84..6dd14d51f0 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2010-03-18 Stan Shebs + + * gdb.trace/circ.exp: Test circular-trace-buffer. + * gdb.trace/tfile.exp: Update tstatus test. + 2010-03-18 Joel Brobecker * gdb.dwarf2/dw2-anonymous-func.S: New file. diff --git a/gdb/testsuite/gdb.trace/circ.exp b/gdb/testsuite/gdb.trace/circ.exp index d18e7eb0d6..bb3dcd3dc5 100644 --- a/gdb/testsuite/gdb.trace/circ.exp +++ b/gdb/testsuite/gdb.trace/circ.exp @@ -197,6 +197,15 @@ gdb_load $binfile if [target_info exists gdb_stub] { gdb_step_for_stub; } + +gdb_test "set circular-trace-buffer on" "" "set circular-trace-buffer on" + +gdb_test "show circular-trace-buffer" "Target's use of circular trace buffer is on." "show circular-trace-buffer (on)" + +gdb_test "set circular-trace-buffer off" "" "set circular-trace-buffer off" + +gdb_test "show circular-trace-buffer" "Target's use of circular trace buffer is off." "show circular-trace-buffer (off)" + # Body of test encased in a proc so we can return prematurely. if { ![gdb_trace_circular_tests] } then { # Set trace buffer attributes back to normal diff --git a/gdb/testsuite/gdb.trace/tfile.exp b/gdb/testsuite/gdb.trace/tfile.exp index 398b5efe65..f1d86df27a 100644 --- a/gdb/testsuite/gdb.trace/tfile.exp +++ b/gdb/testsuite/gdb.trace/tfile.exp @@ -78,8 +78,8 @@ gdb_test "tfind" "Target failed to find requested trace frame." \ gdb_test "tstatus" \ "Using a trace file.* Trace stopped by a tstop command.* -Collected 1 trace frames.* -Trace buffer has 256 bytes free.* +Collected 1 trace frame.* +Trace buffer has 256 bytes of 4096 bytes free \\(93% full\\).* Looking at trace frame 0, tracepoint .*" \ "tstatus on trace file" diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index b6213345d6..8af3a9b4b7 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -153,6 +153,11 @@ char *default_collect = ""; static int disconnected_tracing; +/* This variable controls whether we ask the target for a linear or + circular trace buffer. */ + +static int circular_trace_buffer; + /* ======= Important command functions: ======= */ static void trace_actions_command (char *, int); static void trace_start_command (char *, int); @@ -1579,6 +1584,9 @@ trace_start_command (char *args, int from_tty) /* Tell target to treat text-like sections as transparent. */ target_trace_set_readonly_regions (); + /* Set some mode flags. */ + target_set_disconnected_tracing (disconnected_tracing); + target_set_circular_trace_buffer (circular_trace_buffer); /* Now insert traps and begin collecting data. */ target_trace_start (); @@ -1668,16 +1676,34 @@ trace_status_command (char *args, int from_tty) } } - if (ts->traceframe_count >= 0) + if (ts->traceframes_created >= 0 + && ts->traceframe_count != ts->traceframes_created) + { + printf_filtered (_("Buffer contains %d trace frames (of %d created total).\n"), + ts->traceframe_count, ts->traceframes_created); + } + else if (ts->traceframe_count >= 0) { printf_filtered (_("Collected %d trace frames.\n"), ts->traceframe_count); } - if (ts->buffer_free) + if (ts->buffer_free >= 0) { - printf_filtered (_("Trace buffer has %llu bytes free.\n"), - ts->buffer_free); + if (ts->buffer_size >= 0) + { + printf_filtered (_("Trace buffer has %d bytes of %d bytes free"), + ts->buffer_free, ts->buffer_size); + if (ts->buffer_size > 0) + printf_filtered (_(" (%d%% full)"), + ((int) ((((long long) (ts->buffer_size + - ts->buffer_free)) * 100) + / ts->buffer_size))); + printf_filtered (_(".\n")); + } + else + printf_filtered (_("Trace buffer has %d bytes free.\n"), + ts->buffer_free); } /* Now report on what we're doing with tfind. */ @@ -2438,10 +2464,18 @@ trace_save_command (char *args, int from_tty) fprintf (fp, "R %x\n", trace_regblock_size); /* Write out status of the tracing run (aka "tstatus" info). */ - fprintf (fp, "status %c;%s:%x;tframes:%x;tfree:%llx\n", + fprintf (fp, "status %c;%s:%x", (ts->running ? '1' : '0'), - stop_reason_names[ts->stop_reason], ts->stopping_tracepoint, - ts->traceframe_count, ts->buffer_free); + stop_reason_names[ts->stop_reason], ts->stopping_tracepoint); + if (ts->traceframe_count >= 0) + fprintf (fp, ";tframes:%x", ts->traceframe_count); + if (ts->traceframes_created >= 0) + fprintf (fp, ";tcreated:%x", ts->traceframes_created); + if (ts->buffer_free >= 0) + fprintf (fp, ";tfree:%x", ts->buffer_free); + if (ts->buffer_size >= 0) + fprintf (fp, ";tsize:%x", ts->buffer_size); + fprintf (fp, "\n"); /* Note that we want to upload tracepoints and save those, rather than simply writing out the local ones, because the user may have @@ -2546,6 +2580,13 @@ set_disconnected_tracing (char *args, int from_tty, send_disconnected_tracing_value (disconnected_tracing); } +static void +set_circular_trace_buffer (char *args, int from_tty, + struct cmd_list_element *c) +{ + target_set_circular_trace_buffer (circular_trace_buffer); +} + /* 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 @@ -3059,6 +3100,11 @@ parse_trace_status (char *line, struct trace_status *ts) ts->running_known = 1; ts->running = (*p++ == '1'); ts->stop_reason = trace_stop_reason_unknown; + ts->traceframe_count = -1; + ts->traceframes_created = -1; + ts->buffer_free = -1; + ts->buffer_size = -1; + while (*p++) { p1 = strchr (p, ':'); @@ -3086,16 +3132,26 @@ Status line: '%s'\n"), p, line); p = unpack_varlen_hex (++p1, &val); ts->stop_reason = tstop_command; } - if (strncmp (p, "tframes", p1 - p) == 0) + else if (strncmp (p, "tframes", p1 - p) == 0) { p = unpack_varlen_hex (++p1, &val); ts->traceframe_count = val; } - if (strncmp (p, "tfree", p1 - p) == 0) + else if (strncmp (p, "tcreated", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->traceframes_created = val; + } + else if (strncmp (p, "tfree", p1 - p) == 0) { p = unpack_varlen_hex (++p1, &val); ts->buffer_free = val; } + else if (strncmp (p, "tsize", p1 - p) == 0) + { + p = unpack_varlen_hex (++p1, &val); + ts->buffer_size = val; + } else { /* Silently skip unknown optional info. */ @@ -3819,6 +3875,18 @@ trace data collected in the meantime."), &setlist, &showlist); + add_setshow_boolean_cmd ("circular-trace-buffer", no_class, + &circular_trace_buffer, _("\ +Set target's use of circular trace buffer."), _("\ +Show target's use of circular trace buffer."), _("\ +Use this to make the trace buffer into a circular buffer,\n\ +which will discard traceframes (oldest first) instead of filling\n\ +up and stopping the trace run."), + set_circular_trace_buffer, + NULL, + &setlist, + &showlist); + init_tfile_ops (); add_target (&tfile_ops); diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index c273f25a9b..1ae5c6cbe1 100644 --- a/gdb/tracepoint.h +++ b/gdb/tracepoint.h @@ -95,11 +95,21 @@ struct trace_status int stopping_tracepoint; + /* Number of traceframes currently in the buffer. */ + int traceframe_count; - unsigned long long buffer_size; + /* Number of traceframes created since start of run. */ + + int traceframes_created; + + /* Total size of the target's trace buffer. */ + + int buffer_size; + + /* Unused bytes left in the target's trace buffer. */ - unsigned long long buffer_free; + int buffer_free; }; struct trace_status *current_trace_status (void); -- 2.34.1