btrace: Resume recording after disconnect.
authorTim Wiederhake <tim.wiederhake@intel.com>
Mon, 25 Jul 2016 08:57:06 +0000 (10:57 +0200)
committerTim Wiederhake <tim.wiederhake@intel.com>
Mon, 25 Jul 2016 09:03:43 +0000 (11:03 +0200)
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

gdb/ChangeLog
gdb/NEWS
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/record-btrace.c
gdb/record-btrace.h [new file with mode: 0644]
gdb/remote.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.btrace/reconnect.c [new file with mode: 0644]
gdb/testsuite/gdb.btrace/reconnect.exp [new file with mode: 0644]

index 005c3e976f301e3d618323e7a9b9c693018b0f11..fb8d89f39fa3af1f8e7ebc78fe38f7476289879a 100644 (file)
@@ -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.
 2016-07-23  Gabriel Krisman Bertazi  <gabriel@krisman.be>
 
        * xml-syscall.c (get_syscalls_by_group): New.
index 17c762ccdcd0e79981433ca8684827607c1a0d43..97e60e95ed8908f3b578681baae480a3500e1bb1 100644 (file)
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,9 @@
 
 *** Changes since GDB 7.11
 
 
 *** 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:
 
 * GDB now supports a negative repeat count in the 'x' command to examine
   memory backward from the given address.  For example:
 
index 39eeab2bbfa14d0fd7a421865228cfb295ccd668..cc9bc70e3ad2865ca2dfdf09e02259ca0e8416df 100644 (file)
@@ -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
 2016-07-23  Gabriel Krisman Bertazi  <gabriel@krisman.be>
 
        * gdb.texinfo (Set Catchpoints): Add 'group' argument to catch
index ae74ed44eaa3b8dbc554715460b198ca77890d7a..f5dde61325fb1139ad177d0641149b68c7cfb2ef 100644 (file)
@@ -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
 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
 
 The recording format can be specified as parameter.  Without a parameter
 the command chooses the recording format.  The following recording
index 24594a96cfc1bf2f05b43adb365f820b7624a3d0..4a51b8e11d0994077e5fbf6f109142081219d197 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "defs.h"
 #include "record.h"
 
 #include "defs.h"
 #include "record.h"
+#include "record-btrace.h"
 #include "gdbthread.h"
 #include "target.h"
 #include "gdbcmd.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);
 }
 
   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
 /* 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;
 {
   struct cleanup *disable_chain;
   struct thread_info *tp;
-  const char *format;
 
   DEBUG ("open");
 
 
   DEBUG ("open");
 
@@ -226,17 +246,7 @@ record_btrace_open (const char *args, int from_tty)
        make_cleanup (record_btrace_disable_callback, tp);
       }
 
        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);
 }
 
   discard_cleanups (disable_chain);
 }
@@ -257,6 +267,21 @@ record_btrace_stop_recording (struct target_ops *self)
       btrace_disable (tp);
 }
 
       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
 /* 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_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;
   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 (file)
index 0000000..d2062b8
--- /dev/null
@@ -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 */
index 5568346688d1e8c388b93fa7f2ea652136e08c42..79449836307d1ae1e5395d9a5b696f7c0ddf0117 100644 (file)
@@ -70,6 +70,7 @@
 #include "ax-gdb.h"
 #include "agent.h"
 #include "btrace.h"
 #include "ax-gdb.h"
 #include "agent.h"
 #include "btrace.h"
+#include "record-btrace.h"
 
 /* Temp hacks for tracepoint encoding migration.  */
 static char *target_buf;
 
 /* 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_reset (void);
 
+static void remote_btrace_maybe_reopen (void);
+
 static int stop_reply_queue_length (void);
 
 static void readahead_cache_invalidate (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);
     }
 
       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
   /* 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 *
 /* Enable branch tracing.  */
 
 static struct btrace_target_info *
index 1406201b53e77c32a1b4a1219826eaa53de177f8..48e2eeba565db0d2fc18ba55bbf1a00d5b99db53 100644 (file)
@@ -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
 2016-07-23  Gabriel Krisman Bertazi  <gabriel@krisman.be>
 
        * 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 (file)
index 0000000..f2a9d35
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.btrace/reconnect.exp b/gdb/testsuite/gdb.btrace/reconnect.exp
new file mode 100644 (file)
index 0000000..485a4df
--- /dev/null
@@ -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."
+}
This page took 0.051685 seconds and 4 git commands to generate.