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 <tim.wiederhake@intel.com> 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
This commit is contained in:
parent
95804507f2
commit
c0272db585
10 changed files with 259 additions and 14 deletions
|
@ -1,3 +1,16 @@
|
|||
2016-07-25 Tim Wiederhake <tim.wiederhake@intel.com>
|
||||
|
||||
* 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 <gabriel@krisman.be>
|
||||
|
||||
* xml-syscall.c (get_syscalls_by_group): New.
|
||||
|
|
3
gdb/NEWS
3
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:
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2016-07-25 Tim Wiederhake <tim.wiederhake@intel.com>
|
||||
|
||||
* gdb.texinfo: Resume btrace on reconnect.
|
||||
|
||||
2016-07-23 Gabriel Krisman Bertazi <gabriel@krisman.be>
|
||||
|
||||
* gdb.texinfo (Set Catchpoints): Add 'group' argument to catch
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
28
gdb/record-btrace.h
Normal file
28
gdb/record-btrace.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
/* Branch trace support for GDB, the GNU debugger.
|
||||
|
||||
Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Intel Corp. <tim.wiederhake@intel.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>. */
|
||||
|
||||
#ifndef RECORD_BTRACE_H
|
||||
#define RECORD_BTRACE_H
|
||||
|
||||
/* Push the record_btrace target. */
|
||||
extern void record_btrace_push_target (void);
|
||||
|
||||
#endif /* RECORD_BTRACE_H */
|
61
gdb/remote.c
61
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 *
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2016-07-25 Tim Wiederhake <tim.wiederhake@intel.com>
|
||||
|
||||
* gdb.btrace/reconnect.c: New file.
|
||||
* gdb.btrace/reconnect.exp: New file.
|
||||
|
||||
2016-07-23 Gabriel Krisman Bertazi <gabriel@krisman.be>
|
||||
|
||||
* gdb.base/catch-syscall.exp (do_syscall_tests): Add call
|
||||
|
|
25
gdb/testsuite/gdb.btrace/reconnect.c
Normal file
25
gdb/testsuite/gdb.btrace/reconnect.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2016 Free Software Foundation, Inc.
|
||||
|
||||
Contributed by Intel Corp. <tim.wiederhake@intel.com>
|
||||
|
||||
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/>. */
|
||||
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
79
gdb/testsuite/gdb.btrace/reconnect.exp
Normal file
79
gdb/testsuite/gdb.btrace/reconnect.exp
Normal file
|
@ -0,0 +1,79 @@
|
|||
# This testcase is part of GDB, the GNU debugger.
|
||||
#
|
||||
# Copyright 2016 Free Software Foundation, Inc.
|
||||
#
|
||||
# Contributed by Intel Corp. <tim.wiederhake@intel.com>
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
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."
|
||||
}
|
Loading…
Reference in a new issue