aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--exec.c1
-rw-r--r--gdbstub.c10
-rw-r--r--include/sysemu/replay.h8
-rw-r--r--replay/replay-debugging.c72
-rw-r--r--softmmu/cpus.c5
-rw-r--r--stubs/replay.c5
6 files changed, 100 insertions, 1 deletions
diff --git a/exec.c b/exec.c
index d8072668ea..ec68f4a9ca 100644
--- a/exec.c
+++ b/exec.c
@@ -2753,6 +2753,7 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
* Don't process the watchpoints when we are
* in a reverse debugging operation.
*/
+ replay_breakpoint();
return;
}
if (flags == BP_MEM_READ) {
diff --git a/gdbstub.c b/gdbstub.c
index 79e8ccc050..ac92273018 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1907,6 +1907,13 @@ static void handle_backward(GdbCmdContext *gdb_ctx, void *user_ctx)
put_packet("E14");
}
return;
+ case 'c':
+ if (replay_reverse_continue()) {
+ gdb_continue();
+ } else {
+ put_packet("E14");
+ }
+ return;
}
}
@@ -2161,7 +2168,8 @@ static void handle_query_supported(GdbCmdContext *gdb_ctx, void *user_ctx)
}
if (replay_mode == REPLAY_MODE_PLAY) {
- g_string_append(gdbserver_state.str_buf, ";ReverseStep+");
+ g_string_append(gdbserver_state.str_buf,
+ ";ReverseStep+;ReverseContinue+");
}
if (gdb_ctx->num_params &&
diff --git a/include/sysemu/replay.h b/include/sysemu/replay.h
index 90bbb5d825..172b20c60c 100644
--- a/include/sysemu/replay.h
+++ b/include/sysemu/replay.h
@@ -82,10 +82,18 @@ const char *replay_get_filename(void);
*/
bool replay_reverse_step(void);
/*
+ * Start searching the last breakpoint/watchpoint.
+ * Used by gdbstub for backwards debugging.
+ * Returns true if the process successfully started.
+ */
+bool replay_reverse_continue(void);
+/*
* Returns true if replay module is processing
* reverse_continue or reverse_step request
*/
bool replay_running_debug(void);
+/* Called in reverse debugging mode to collect breakpoint information */
+void replay_breakpoint(void);
/* Processing the instructions */
diff --git a/replay/replay-debugging.c b/replay/replay-debugging.c
index 1e1dec0295..30ca38e5dd 100644
--- a/replay/replay-debugging.c
+++ b/replay/replay-debugging.c
@@ -23,6 +23,8 @@
#include "migration/snapshot.h"
static bool replay_is_debugging;
+static int64_t replay_last_breakpoint;
+static int64_t replay_last_snapshot;
bool replay_running_debug(void)
{
@@ -246,3 +248,73 @@ bool replay_reverse_step(void)
return false;
}
+
+static void replay_continue_end(void)
+{
+ replay_is_debugging = false;
+ vm_stop(RUN_STATE_DEBUG);
+ replay_delete_break();
+}
+
+static void replay_continue_stop(void *opaque)
+{
+ Error *err = NULL;
+ if (replay_last_breakpoint != -1LL) {
+ replay_seek(replay_last_breakpoint, replay_stop_vm_debug, &err);
+ if (err) {
+ error_free(err);
+ replay_continue_end();
+ }
+ return;
+ }
+ /*
+ * No breakpoints since the last snapshot.
+ * Find previous snapshot and try again.
+ */
+ if (replay_last_snapshot != 0) {
+ replay_seek(replay_last_snapshot - 1, replay_continue_stop, &err);
+ if (err) {
+ error_free(err);
+ replay_continue_end();
+ }
+ replay_last_snapshot = replay_get_current_icount();
+ return;
+ } else {
+ /* Seek to the very first step */
+ replay_seek(0, replay_stop_vm_debug, &err);
+ if (err) {
+ error_free(err);
+ replay_continue_end();
+ }
+ return;
+ }
+ replay_continue_end();
+}
+
+bool replay_reverse_continue(void)
+{
+ Error *err = NULL;
+
+ assert(replay_mode == REPLAY_MODE_PLAY);
+
+ if (replay_get_current_icount() != 0) {
+ replay_seek(replay_get_current_icount() - 1,
+ replay_continue_stop, &err);
+ if (err) {
+ error_free(err);
+ return false;
+ }
+ replay_last_breakpoint = -1LL;
+ replay_is_debugging = true;
+ replay_last_snapshot = replay_get_current_icount();
+ return true;
+ }
+
+ return false;
+}
+
+void replay_breakpoint(void)
+{
+ assert(replay_mode == REPLAY_MODE_PLAY);
+ replay_last_breakpoint = replay_get_current_icount();
+}
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 95c557fac5..9e33416b4d 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -286,6 +286,11 @@ void cpu_handle_guest_debug(CPUState *cpu)
{
if (replay_running_debug()) {
if (!cpu->singlestep_enabled) {
+ /*
+ * Report about the breakpoint and
+ * make a single step to skip it
+ */
+ replay_breakpoint();
cpu_single_step(cpu, SSTEP_ENABLE);
} else {
cpu_single_step(cpu, 0);
diff --git a/stubs/replay.c b/stubs/replay.c
index d5b52302e9..45ebe77fb9 100644
--- a/stubs/replay.c
+++ b/stubs/replay.c
@@ -98,3 +98,8 @@ bool replay_reverse_step(void)
{
return false;
}
+
+bool replay_reverse_continue(void)
+{
+ return false;
+}