diff --git a/cpu-all.h b/cpu-all.h index 787a054a48..cde8451dd0 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -315,6 +315,7 @@ void cpu_interrupt(CPUState *s, int mask); int cpu_breakpoint_insert(CPUState *env, uint32_t pc); int cpu_breakpoint_remove(CPUState *env, uint32_t pc); +void cpu_single_step(CPUState *env, int enabled); /* gdb stub API */ extern int gdbstub_fd; diff --git a/exec.c b/exec.c index fc0a0cf7af..5ea2163258 100644 --- a/exec.c +++ b/exec.c @@ -617,7 +617,8 @@ static void tb_reset_jump_recursive(TranslationBlock *tb) tb_reset_jump_recursive2(tb, 1); } -/* add a breakpoint */ +/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a + breakpoint is reached */ int cpu_breakpoint_insert(CPUState *env, uint32_t pc) { #if defined(TARGET_I386) @@ -659,6 +660,20 @@ int cpu_breakpoint_remove(CPUState *env, uint32_t pc) #endif } +/* enable or disable single step mode. EXCP_DEBUG is returned by the + CPU loop after each instruction */ +void cpu_single_step(CPUState *env, int enabled) +{ +#if defined(TARGET_I386) + if (env->singlestep_enabled != enabled) { + env->singlestep_enabled = enabled; + /* must flush all the translated code to avoid inconsistancies */ + tb_flush(); + } +#endif +} + + /* mask must never be zero */ void cpu_interrupt(CPUState *env, int mask) { diff --git a/gdbstub.c b/gdbstub.c index d255eab6d5..61cb6b1ab5 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -324,6 +324,24 @@ int cpu_gdbstub(void *opaque, int (*main_loop)(void *opaque), int port) snprintf(buf, sizeof(buf), "S%02x", ret); put_packet(buf); break; + case 's': + env = cpu_gdbstub_get_env(opaque); + if (*p != '\0') { + addr = strtoul(p, (char **)&p, 16); +#if defined(TARGET_I386) + env->eip = addr; +#endif + } + cpu_single_step(env, 1); + ret = main_loop(opaque); + cpu_single_step(env, 0); + if (ret == EXCP_DEBUG) + ret = SIGTRAP; + else + ret = 0; + snprintf(buf, sizeof(buf), "S%02x", ret); + put_packet(buf); + break; case 'g': env = cpu_gdbstub_get_env(opaque); registers = (void *)mem_buf;