@@ -17,6 +17,7 @@
#include "exec/gen-icount.h"
#include "exec/log.h"
#include "exec/translator.h"
+#include "sysemu/replay.h"
/* Pairs with tcg_clear_temp_count.
To be called by #TranslatorOps.{translate_insn,tb_stop} if
@@ -1104,9 +1104,17 @@ static bool cpu_can_run(CPUState *cpu)
static void cpu_handle_guest_debug(CPUState *cpu)
{
- gdb_set_stop_cpu(cpu);
- qemu_system_debug_request();
- cpu->stopped = true;
+ if (!replay_running_debug()) {
+ gdb_set_stop_cpu(cpu);
+ qemu_system_debug_request();
+ cpu->stopped = true;
+ } else {
+ if (!cpu->singlestep_enabled) {
+ cpu_single_step(cpu, SSTEP_ENABLE);
+ } else {
+ cpu_single_step(cpu, 0);
+ }
+ }
}
#ifdef CONFIG_LINUX
@@ -2772,6 +2772,13 @@ static void check_watchpoint(int offset, int len, MemTxAttrs attrs, int flags)
QTAILQ_FOREACH(wp, &cpu->watchpoints, entry) {
if (cpu_watchpoint_address_matches(wp, vaddr, len)
&& (wp->flags & flags)) {
+ if (replay_running_debug()) {
+ /*
+ * Don't process the watchpoints when we are
+ * in a reverse debugging operation.
+ */
+ return;
+ }
if (flags == BP_MEM_READ) {
wp->flags |= BP_WATCHPOINT_HIT_READ;
} else {
@@ -39,6 +39,7 @@
#include "sysemu/kvm.h"
#include "exec/semihost.h"
#include "exec/exec-all.h"
+#include "sysemu/replay.h"
#ifdef CONFIG_USER_ONLY
#define GDB_ATTACHED "0"
@@ -344,6 +345,20 @@ typedef struct GDBState {
*/
static int sstep_flags = SSTEP_ENABLE|SSTEP_NOIRQ|SSTEP_NOTIMER;
+/* Retrieves flags for single step mode. */
+static int get_sstep_flags(void)
+{
+ /*
+ * In replay mode all events written into the log should be replayed.
+ * That is why NOIRQ flag is removed in this mode.
+ */
+ if (replay_mode != REPLAY_MODE_NONE) {
+ return SSTEP_ENABLE;
+ } else {
+ return sstep_flags;
+ }
+}
+
static GDBState *gdbserver_state;
bool gdb_has_xml;
@@ -434,7 +449,7 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
CPU_FOREACH(cpu) {
if (newstates[cpu->cpu_index] == 's') {
trace_gdbstub_op_stepping(cpu->cpu_index);
- cpu_single_step(cpu, sstep_flags);
+ cpu_single_step(cpu, get_sstep_flags());
}
}
s->running_state = 1;
@@ -453,7 +468,7 @@ static int gdb_continue_partial(GDBState *s, char *newstates)
break; /* nothing to do here */
case 's':
trace_gdbstub_op_stepping(cpu->cpu_index);
- cpu_single_step(cpu, sstep_flags);
+ cpu_single_step(cpu, get_sstep_flags());
cpu_resume(cpu);
flag = 1;
break;
@@ -1424,9 +1439,28 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
addr = strtoull(p, (char **)&p, 16);
gdb_set_cpu_pc(s, addr);
}
- cpu_single_step(s->c_cpu, sstep_flags);
+ cpu_single_step(s->c_cpu, get_sstep_flags());
gdb_continue(s);
return RS_IDLE;
+ case 'b':
+ /* Backward debugging commands */
+ if (replay_mode == REPLAY_MODE_PLAY) {
+ switch (*p) {
+ case 's':
+ if (replay_reverse_step()) {
+ gdb_continue(s);
+ return RS_IDLE;
+ } else {
+ put_packet(s, "E14");
+ break;
+ }
+ default:
+ goto unknown_command;
+ }
+ } else {
+ put_packet(s, "E22");
+ }
+ goto unknown_command;
case 'F':
{
target_ulong ret;
@@ -1729,6 +1763,10 @@ static int gdb_handle_packet(GDBState *s, const char *line_buf)
}
pstrcat(buf, sizeof(buf), ";multiprocess+");
+ if (replay_mode == REPLAY_MODE_PLAY) {
+ pstrcat(buf, sizeof(buf), ";ReverseStep+");
+ }
+
put_packet(s, buf);
break;
}
@@ -73,6 +73,17 @@ void replay_finish(void);
void replay_add_blocker(Error *reason);
/* Returns name of the replay log file */
const char *replay_get_filename(void);
+/*
+ * Start making one step in backward direction.
+ * Used by gdbstub for backwards debugging.
+ * Returns true on success.
+ */
+bool replay_reverse_step(void);
+/*
+ * Returns true if replay module is processing
+ * reverse_continue or reverse_step request
+ */
+bool replay_running_debug(void);
/* Processing the instructions */
@@ -21,6 +21,13 @@
#include "block/snapshot.h"
#include "migration/snapshot.h"
+static bool replay_is_debugging;
+
+bool replay_running_debug(void)
+{
+ return replay_is_debugging;
+}
+
void hmp_info_replay(Monitor *mon, const QDict *qdict)
{
if (replay_mode == REPLAY_MODE_NONE) {
@@ -219,3 +226,29 @@ void hmp_replay_seek(Monitor *mon, const QDict *qdict)
return;
}
}
+
+static void replay_stop_vm_debug(void *opaque)
+{
+ replay_is_debugging = false;
+ vm_stop(RUN_STATE_DEBUG);
+ replay_delete_break();
+}
+
+bool replay_reverse_step(void)
+{
+ Error *err = NULL;
+
+ assert(replay_mode == REPLAY_MODE_PLAY);
+
+ if (replay_get_current_step() != 0) {
+ replay_seek(replay_get_current_step() - 1, replay_stop_vm_debug, &err);
+ if (err) {
+ error_free(err);
+ return false;
+ }
+ replay_is_debugging = true;
+ return true;
+ }
+
+ return false;
+}
@@ -80,3 +80,8 @@ void replay_mutex_lock(void)
void replay_mutex_unlock(void)
{
}
+
+bool replay_reverse_step(void)
+{
+ return false;
+}