From: Tim Wiederhake Date: Mon, 25 Jul 2016 08:57:06 +0000 (+0200) Subject: btrace: Resume recording after disconnect. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c0272db5854a799a9f3bb3803c3d03d1a62b9ac2;p=binutils-gdb.git btrace: Resume recording after disconnect. This patch allows gdbserver to continue recording after disconnect. On reconnect, the recorded data is accessible to gdb as if no disconnect happened. A possible application for this feature is remotely examine bugs that occur at irregular intervals, where maintaining a gdb connection is inconvenient. This also fixes the issue mentioned here: https://sourceware.org/ml/gdb-patches/2015-11/msg00424.html Signed-off-by: Tim Wiederhake gdb/ChangeLog: * NEWS: Resume btrace on reconnect. * record-btrace.c: Added record-btrace.h include. (record_btrace_open): Split into this and ... (record_btrace_push_target): ... this. (record_btrace_disconnect): New function. (init_record_btrace_ops): Use record_btrace_disconnect. * record-btrace.h: New file. * remote.c: Added record-btrace.h include. (remote_start_remote): Check recording status. (remote_btrace_maybe_reopen): New function. gdb/doc/ChangeLog: * gdb.texinfo: Resume btrace on reconnect. gdb/testsuite/ChangeLog: * gdb.btrace/reconnect.c: New file. * gdb.btrace/reconnect.exp: New file. Change-Id: I95e8b0ab8a89e58591aba0e63818cee82fd211bc --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 005c3e976f3..fb8d89f39fa 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2016-07-25 Tim Wiederhake + + * NEWS: Resume btrace on reconnect. + * record-btrace.c: Added record-btrace.h include. + (record_btrace_open): Split into this and ... + (record_btrace_push_target): ... this. + (record_btrace_disconnect): New function. + (init_record_btrace_ops): Use record_btrace_disconnect. + * record-btrace.h: New file. + * remote.c: Added record-btrace.h include. + (remote_start_remote): Check recording status. + (remote_btrace_maybe_reopen): New function. + 2016-07-23 Gabriel Krisman Bertazi * xml-syscall.c (get_syscalls_by_group): New. diff --git a/gdb/NEWS b/gdb/NEWS index 17c762ccdcd..97e60e95ed8 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,9 @@ *** Changes since GDB 7.11 +* GDBserver now supports recording btrace without maintaining an active + GDB connection. + * GDB now supports a negative repeat count in the 'x' command to examine memory backward from the given address. For example: diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index 39eeab2bbfa..cc9bc70e3ad 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2016-07-25 Tim Wiederhake + + * gdb.texinfo: Resume btrace on reconnect. + 2016-07-23 Gabriel Krisman Bertazi * gdb.texinfo (Set Catchpoints): Add 'group' argument to catch diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index ae74ed44eaa..f5dde61325f 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -6657,7 +6657,9 @@ Hardware-supported instruction recording. This method does not record data. Further, the data is collected in a ring buffer so old data will be overwritten when the buffer is full. It allows limited reverse execution. Variables and registers are not available during reverse -execution. +execution. In remote debugging, recording continues on disconnect. +Recorded data can be inspected after reconnecting. The recording may +be stopped using @code{record stop}. The recording format can be specified as parameter. Without a parameter the command chooses the recording format. The following recording diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 24594a96cfc..4a51b8e11d0 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -21,6 +21,7 @@ #include "defs.h" #include "record.h" +#include "record-btrace.h" #include "gdbthread.h" #include "target.h" #include "gdbcmd.h" @@ -199,6 +200,26 @@ record_btrace_handle_async_inferior_event (gdb_client_data data) inferior_event_handler (INF_REG_EVENT, NULL); } +/* See record-btrace.h. */ + +void +record_btrace_push_target (void) +{ + const char *format; + + record_btrace_auto_enable (); + + push_target (&record_btrace_ops); + + record_btrace_async_inferior_event_handler + = create_async_event_handler (record_btrace_handle_async_inferior_event, + NULL); + record_btrace_generating_corefile = 0; + + format = btrace_format_short_string (record_btrace_conf.format); + observer_notify_record_changed (current_inferior (), 1, "btrace", format); +} + /* The to_open method of target record-btrace. */ static void @@ -206,7 +227,6 @@ record_btrace_open (const char *args, int from_tty) { struct cleanup *disable_chain; struct thread_info *tp; - const char *format; DEBUG ("open"); @@ -226,17 +246,7 @@ record_btrace_open (const char *args, int from_tty) make_cleanup (record_btrace_disable_callback, tp); } - record_btrace_auto_enable (); - - push_target (&record_btrace_ops); - - record_btrace_async_inferior_event_handler - = create_async_event_handler (record_btrace_handle_async_inferior_event, - NULL); - record_btrace_generating_corefile = 0; - - format = btrace_format_short_string (record_btrace_conf.format); - observer_notify_record_changed (current_inferior (), 1, "btrace", format); + record_btrace_push_target (); discard_cleanups (disable_chain); } @@ -257,6 +267,21 @@ record_btrace_stop_recording (struct target_ops *self) btrace_disable (tp); } +/* The to_disconnect method of target record-btrace. */ + +static void +record_btrace_disconnect (struct target_ops *self, const char *args, + int from_tty) +{ + struct target_ops *beneath = self->beneath; + + /* Do not stop recording, just clean up GDB side. */ + unpush_target (self); + + /* Forward disconnect. */ + beneath->to_disconnect (beneath, args, from_tty); +} + /* The to_close method of target record-btrace. */ static void @@ -2824,7 +2849,7 @@ init_record_btrace_ops (void) ops->to_close = record_btrace_close; ops->to_async = record_btrace_async; ops->to_detach = record_detach; - ops->to_disconnect = record_disconnect; + ops->to_disconnect = record_btrace_disconnect; ops->to_mourn_inferior = record_mourn_inferior; ops->to_kill = record_kill; ops->to_stop_recording = record_btrace_stop_recording; diff --git a/gdb/record-btrace.h b/gdb/record-btrace.h new file mode 100644 index 00000000000..d2062b8cde3 --- /dev/null +++ b/gdb/record-btrace.h @@ -0,0 +1,28 @@ +/* Branch trace support for GDB, the GNU debugger. + + Copyright (C) 2016 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + This file is part of GDB. + + 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 . */ + +#ifndef RECORD_BTRACE_H +#define RECORD_BTRACE_H + +/* Push the record_btrace target. */ +extern void record_btrace_push_target (void); + +#endif /* RECORD_BTRACE_H */ diff --git a/gdb/remote.c b/gdb/remote.c index 5568346688d..79449836307 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -70,6 +70,7 @@ #include "ax-gdb.h" #include "agent.h" #include "btrace.h" +#include "record-btrace.h" /* Temp hacks for tracepoint encoding migration. */ static char *target_buf; @@ -231,6 +232,8 @@ static int remote_can_run_breakpoint_commands (struct target_ops *self); static void remote_btrace_reset (void); +static void remote_btrace_maybe_reopen (void); + static int stop_reply_queue_length (void); static void readahead_cache_invalidate (void); @@ -4298,6 +4301,10 @@ remote_start_remote (int from_tty, struct target_ops *target, int extended_p) merge_uploaded_tracepoints (&uploaded_tps); } + /* Possibly the target has been engaged in a btrace record started + previously; find out where things are at. */ + remote_btrace_maybe_reopen (); + /* The thread and inferior lists are now synchronized with the target, our symbols have been relocated, and we're merged the target's tracepoints with ours. We're done with basic start @@ -12774,6 +12781,60 @@ btrace_read_config (struct btrace_config *conf) } } +/* Maybe reopen target btrace. */ + +static void +remote_btrace_maybe_reopen (void) +{ + struct remote_state *rs = get_remote_state (); + struct cleanup *cleanup; + struct thread_info *tp; + int btrace_target_pushed = 0; + int warned = 0; + + cleanup = make_cleanup_restore_current_thread (); + ALL_NON_EXITED_THREADS (tp) + { + set_general_thread (tp->ptid); + + memset (&rs->btrace_config, 0x00, sizeof (struct btrace_config)); + btrace_read_config (&rs->btrace_config); + + if (rs->btrace_config.format == BTRACE_FORMAT_NONE) + continue; + +#if !defined (HAVE_LIBIPT) + if (rs->btrace_config.format == BTRACE_FORMAT_PT) + { + if (!warned) + { + warned = 1; + warning (_("GDB does not support Intel Processor Trace. " + "\"record\" will not work in this session.")); + } + + continue; + } +#endif /* !defined (HAVE_LIBIPT) */ + + /* Push target, once, but before anything else happens. This way our + changes to the threads will be cleaned up by unpushing the target + in case btrace_read_config () throws. */ + if (!btrace_target_pushed) + { + btrace_target_pushed = 1; + record_btrace_push_target (); + printf_filtered (_("Target is recording using %s.\n"), + btrace_format_string (rs->btrace_config.format)); + } + + tp->btrace.target = XCNEW (struct btrace_target_info); + tp->btrace.target->ptid = tp->ptid; + tp->btrace.target->conf = rs->btrace_config; + } + do_cleanups (cleanup); +} + /* Enable branch tracing. */ static struct btrace_target_info * diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 1406201b53e..48e2eeba565 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-07-25 Tim Wiederhake + + * gdb.btrace/reconnect.c: New file. + * gdb.btrace/reconnect.exp: New file. + 2016-07-23 Gabriel Krisman Bertazi * gdb.base/catch-syscall.exp (do_syscall_tests): Add call diff --git a/gdb/testsuite/gdb.btrace/reconnect.c b/gdb/testsuite/gdb.btrace/reconnect.c new file mode 100644 index 00000000000..f2a9d35f5d5 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/reconnect.c @@ -0,0 +1,25 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2016 Free Software Foundation, Inc. + + Contributed by Intel Corp. + + 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 . */ + + +int +main (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.btrace/reconnect.exp b/gdb/testsuite/gdb.btrace/reconnect.exp new file mode 100644 index 00000000000..485a4df852c --- /dev/null +++ b/gdb/testsuite/gdb.btrace/reconnect.exp @@ -0,0 +1,79 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2016 Free Software Foundation, Inc. +# +# Contributed by Intel Corp. +# +# 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 gdbserver-support.exp + +if { [skip_btrace_tests] } { return -1 } +if { [skip_gdbserver_tests] } { return -1 } + +standard_testfile +if [prepare_for_testing $testfile.exp $testfile $srcfile] { + return -1 +} + +# Make sure we're disconnected and no recording is active, in case +# we're testing with an extended-remote board, therefore already +# connected. +with_test_prefix "preparation" { + gdb_test "record stop" ".*" + gdb_test "disconnect" ".*" +} + +# Start fresh gdbserver. +set gdbserver_reconnect_p 1 +set res [gdbserver_start "" $binfile] +set gdbserver_protocol [lindex $res 0] +set gdbserver_gdbport [lindex $res 1] +gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport + +# Create a record, check, reconnect +with_test_prefix "first" { + gdb_test_no_output "record btrace" "record btrace enable" + gdb_test "stepi 19" "0x.* in .* from target.*" + + gdb_test "info record" [multi_line \ + "Active record target: .*" \ + "Recorded 19 instructions in .+ functions \\(. gaps\\) for thread 1 \\(Thread .*\\)." + ] + + gdb_test "disconnect" "Ending remote debugging." + gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport +} + +# Test if we can access the recorded data from first connect. +# Note: BTS loses the first function call entry with its associated +# instructions for technical reasons. This is why we test for +# "a number between 10 and 19", so we catch at least the case where +# there are 0 instructions in the record. +with_test_prefix "second" { + gdb_test "info record" [multi_line \ + "Active record target: .*" \ + "Recorded 1. instructions in .+ functions \\(. gaps\\) for thread 1 \\(Thread .*\\)." + ] + + gdb_test "record stop" "Process record is stopped and all execution logs are deleted." + + gdb_test "disconnect" "Ending remote debugging." + gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport +} + +# Test that recording is now off. +with_test_prefix "third" { + gdb_test "info record" "No record target is currently active." +}