diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/btrace.c | 34 | ||||
-rw-r--r-- | gdb/record-btrace.c | 4 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/enable-running.c | 48 | ||||
-rw-r--r-- | gdb/testsuite/gdb.btrace/enable-running.exp | 95 |
6 files changed, 190 insertions, 4 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 5ce89125cb4..b2f7d73005a 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,13 @@ 2017-02-01 Markus Metzger <markus.t.metzger@intel.com> + * btrace.c (btrace_enable): Do not call btrace_add_pc for + BTRACE_FORMAT_PT or if can_access_registers_ptid returns false. + (btrace_fetch): Assert can_access_registers_ptid. + * record-btrace.c (require_btrace_thread, record_btrace_info): Call + validate_registers_access. + +2017-02-01 Markus Metzger <markus.t.metzger@intel.com> + * gdbthread.h (can_access_registers_ptid): New. * thread.c (can_access_registers_ptid): New. diff --git a/gdb/btrace.c b/gdb/btrace.c index d266af7d3ab..6d621e4ecf4 100644 --- a/gdb/btrace.c +++ b/gdb/btrace.c @@ -1472,10 +1472,33 @@ btrace_enable (struct thread_info *tp, const struct btrace_config *conf) tp->btrace.target = target_enable_btrace (tp->ptid, conf); - /* Add an entry for the current PC so we start tracing from where we - enabled it. */ - if (tp->btrace.target != NULL) - btrace_add_pc (tp); + /* We're done if we failed to enable tracing. */ + if (tp->btrace.target == NULL) + return; + + /* We need to undo the enable in case of errors. */ + TRY + { + /* Add an entry for the current PC so we start tracing from where we + enabled it. + + If we can't access TP's registers, TP is most likely running. In this + case, we can't really say where tracing was enabled so it should be + safe to simply skip this step. + + This is not relevant for BTRACE_FORMAT_PT since the trace will already + start at the PC at which tracing was enabled. */ + if (conf->format != BTRACE_FORMAT_PT + && can_access_registers_ptid (tp->ptid)) + btrace_add_pc (tp); + } + CATCH (exception, RETURN_MASK_ALL) + { + btrace_disable (tp); + + throw_exception (exception); + } + END_CATCH } /* See btrace.h. */ @@ -1709,6 +1732,9 @@ btrace_fetch (struct thread_info *tp) if (btinfo->replay != NULL) return; + /* We should not be called on running or exited threads. */ + gdb_assert (can_access_registers_ptid (tp->ptid)); + btrace_data_init (&btrace); cleanup = make_cleanup_btrace_data (&btrace); diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 8896241d88b..ee0d22c375c 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -117,6 +117,8 @@ require_btrace_thread (void) if (tp == NULL) error (_("No thread.")); + validate_registers_access (); + btrace_fetch (tp); if (btrace_is_empty (tp)) @@ -417,6 +419,8 @@ record_btrace_info (struct target_ops *self) if (tp == NULL) error (_("No thread.")); + validate_registers_access (); + btinfo = &tp->btrace; conf = btrace_conf (btinfo); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 949e80b8603..429f33dad41 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2017-02-01 Markus Metzger <markus.t.metzger@intel.com> + + * gdb.btrace/enable-running.c: New. + * gdb.btrace/enable-running.exp: New. + 2017-01-27 Walfred Tedeschi <walfred.tedeschi@intel.com> * gdb.arch/amd64-gs_base.c: New file. diff --git a/gdb/testsuite/gdb.btrace/enable-running.c b/gdb/testsuite/gdb.btrace/enable-running.c new file mode 100644 index 00000000000..c2edf1e6062 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/enable-running.c @@ -0,0 +1,48 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2017 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 <http://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <unistd.h> + +#define NTHREADS 3 + +static void * +test (void *arg) +{ + /* Let's hope this is long enough for GDB to enable tracing and check that + everything is working as expected. */ + sleep (10); + + return arg; +} + +int +main (void) +{ + pthread_t th[NTHREADS]; + int i; + + for (i = 0; i < NTHREADS; ++i) + pthread_create (&th[i], NULL, test, NULL); + + test (NULL); /* bp.1 */ + + for (i = 0; i < NTHREADS; ++i) + pthread_join (th[i], NULL); + + return 0; +} diff --git a/gdb/testsuite/gdb.btrace/enable-running.exp b/gdb/testsuite/gdb.btrace/enable-running.exp new file mode 100644 index 00000000000..d549a4075c7 --- /dev/null +++ b/gdb/testsuite/gdb.btrace/enable-running.exp @@ -0,0 +1,95 @@ +# This testcase is part of GDB, the GNU debugger. +# +# Copyright 2017 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 <http://www.gnu.org/licenses/>. + +if { [skip_btrace_tests] } { return -1 } + +standard_testfile +if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } { + return -1 +} + +# We need to enable non-stop mode for the remote case. +save_vars { GDBFLAGS } { + append GDBFLAGS " -ex \"set non-stop on\"" + clean_restart $testfile +} + +if ![runto_main] { + return -1 +} + +set bp_1 [gdb_get_line_number "bp.1" $srcfile] + +gdb_breakpoint $bp_1 +gdb_continue_to_breakpoint "cont to $bp_1" ".*$bp_1\r\n.*" +gdb_test "cont&" "Continuing\." + +# All threads are running. Let's start recording. +gdb_test_no_output "record btrace" + +proc check_tracing_enabled { thread } { + global gdb_prompt + + with_test_prefix "thread $thread" { + gdb_test "thread $thread" "(running).*" "is running" + + # We can't read the trace while the thread is running. + gdb_test "info record" "Selected thread is running\." \ + "info record while running" + + # Try various commands that try to read trace. + gdb_test "record instruction-history" "Selected thread is running\." + gdb_test "record function-call-history" "Selected thread is running\." + + # Including reverse-stepping commands. + gdb_test "reverse-continue" "\[Ss\]elected thread is running\." + gdb_test "reverse-step" "\[Ss\]elected thread is running\." + gdb_test "reverse-next" "\[Ss\]elected thread is running\." + gdb_test "reverse-finish" "\[Ss\]elected thread is running\." + + # Stop the thread before reading the trace. + gdb_test_multiple "interrupt" "interrupt" { + -re "interrupt\r\n$gdb_prompt " { + pass "interrupt" + } + } + # Wait until the thread actually stopped. + gdb_test_multiple "" "stopped" { + -re "Thread $thread.*stopped\." { + pass "stopped" + } + } + # We will consume the thread's current location as part of the + # "info record" output. + gdb_test "info record" [multi_line \ + "Active record target: record-btrace" \ + "Recording format: .*" \ + "Recorded \[0-9\]+ instructions \[^\\\r\\\n\]*" \ + ] + + # Continue the thread again. + gdb_test "cont&" "Continuing\." + } +} + +# Check that recording was started on each thread. +foreach thread {1 2 3 4} { + check_tracing_enabled $thread +} + +# Stop recording while all threads are running. +gdb_test "record stop" "Process record is stopped \[^\\\r\\\n\]*" |