diff --git a/bsd-user/main.c b/bsd-user/main.c index 0dc9b996e0..34a6b0762b 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -33,6 +33,8 @@ #define DEBUG_LOGFILE "/tmp/qemu.log" +int singlestep; + static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; extern char **environ; @@ -378,6 +380,7 @@ static void usage(void) "Debug options:\n" "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" + "-singlestep always run in singlestep mode\n" "-strace log system calls\n" "\n" "Environment variables:\n" @@ -500,6 +503,8 @@ int main(int argc, char **argv) usage(); } optind++; + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; } else diff --git a/darwin-user/main.c b/darwin-user/main.c index 9b8a3dccca..51c6aa0f4d 100644 --- a/darwin-user/main.c +++ b/darwin-user/main.c @@ -41,6 +41,8 @@ #include #include +int singlestep; + const char *interp_prefix = ""; asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000"); @@ -751,6 +753,7 @@ void usage(void) "-d options activate log (logfile='%s')\n" "-g wait for gdb on port 1234\n" "-p pagesize set the host page size to 'pagesize'\n", + "-singlestep always run in singlestep mode\n" TARGET_ARCH, TARGET_ARCH, interp_prefix, @@ -842,6 +845,8 @@ int main(int argc, char **argv) #endif exit(1); } + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else { usage(); diff --git a/exec-all.h b/exec-all.h index 143aca184f..33ccb7b445 100644 --- a/exec-all.h +++ b/exec-all.h @@ -384,4 +384,8 @@ static inline int kqemu_is_ok(CPUState *env) typedef void (CPUDebugExcpHandler)(CPUState *env); CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); + +/* vl.c */ +extern int singlestep; + #endif diff --git a/linux-user/main.c b/linux-user/main.c index feb3036170..3b9dfc7673 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -39,6 +39,8 @@ char *exec_path; +int singlestep; + static const char *interp_prefix = CONFIG_QEMU_PREFIX; const char *qemu_uname_release = CONFIG_UNAME_RELEASE; @@ -2217,6 +2219,7 @@ static void usage(void) "Debug options:\n" "-d options activate log (logfile=%s)\n" "-p pagesize set the host page size to 'pagesize'\n" + "-singlestep always run in singlestep mode\n" "-strace log system calls\n" "\n" "Environment variables:\n" @@ -2359,6 +2362,8 @@ int main(int argc, char **argv, char **envp) } } else if (!strcmp(r, "drop-ld-preload")) { (void) envlist_unsetenv(envlist, "LD_PRELOAD"); + } else if (!strcmp(r, "singlestep")) { + singlestep = 1; } else if (!strcmp(r, "strace")) { do_strace = 1; } else diff --git a/monitor.c b/monitor.c index 75c8663a1e..ca1c11c478 100644 --- a/monitor.c +++ b/monitor.c @@ -527,6 +527,17 @@ static void do_log(Monitor *mon, const char *items) cpu_set_log(mask); } +static void do_singlestep(Monitor *mon, const char *option) +{ + if (!option || !strcmp(option, "on")) { + singlestep = 1; + } else if (!strcmp(option, "off")) { + singlestep = 0; + } else { + monitor_printf(mon, "unexpected option %s\n", option); + } +} + static void do_stop(Monitor *mon) { vm_stop(EXCP_INTERRUPT); @@ -1511,9 +1522,13 @@ static void do_inject_nmi(Monitor *mon, int cpu_index) static void do_info_status(Monitor *mon) { - if (vm_running) - monitor_printf(mon, "VM status: running\n"); - else + if (vm_running) { + if (singlestep) { + monitor_printf(mon, "VM status: running (single step mode)\n"); + } else { + monitor_printf(mon, "VM status: running\n"); + } + } else monitor_printf(mon, "VM status: paused\n"); } @@ -1644,6 +1659,8 @@ static const mon_cmd_t mon_cmds[] = { "tag|id", "restore a VM snapshot from its tag or id" }, { "delvm", "s", do_delvm, "tag|id", "delete a VM snapshot from its tag or id" }, + { "singlestep", "s?", do_singlestep, + "[on|off]", "run emulation in singlestep mode or switch to normal mode", }, { "stop", "", do_stop, "", "stop emulation", }, { "c|cont", "", do_cont, diff --git a/qemu-doc.texi b/qemu-doc.texi index 61a08eeae9..3742b45987 100644 --- a/qemu-doc.texi +++ b/qemu-doc.texi @@ -490,6 +490,10 @@ Set the whole virtual machine to the snapshot identified by the tag @item delvm @var{tag}|@var{id} Delete the snapshot identified by @var{tag} or @var{id}. +@item singlestep [off] +Run the emulation in single step mode. +If called with option off, the emulation returns to normal mode. + @item stop Stop emulation. @@ -2370,6 +2374,8 @@ Activate log (logfile=/tmp/qemu.log) Act as if the host page size was 'pagesize' bytes @item -g port Wait gdb connection to port +@item -singlestep +Run the emulation in single step mode. @end table Environment variables: @@ -2488,6 +2494,8 @@ Debug options: Activate log (logfile=/tmp/qemu.log) @item -p pagesize Act as if the host page size was 'pagesize' bytes +@item -singlestep +Run the emulation in single step mode. @end table @node BSD User space emulator @@ -2550,6 +2558,8 @@ Debug options: Activate log (logfile=/tmp/qemu.log) @item -p pagesize Act as if the host page size was 'pagesize' bytes +@item -singlestep +Run the emulation in single step mode. @end table @node compilation diff --git a/qemu-options.hx b/qemu-options.hx index 51593a3987..4c7012eee6 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1209,6 +1209,13 @@ Store the QEMU process PID in @var{file}. It is useful if you launch QEMU from a script. ETEXI +DEF("singlestep", 0, QEMU_OPTION_singlestep, \ + "-singlestep always run in singlestep mode\n") +STEXI +@item -singlestep +Run the emulation in single step mode. +ETEXI + DEF("S", 0, QEMU_OPTION_S, \ "-S freeze CPU at startup (use 'c' to start execution)\n") STEXI diff --git a/target-alpha/translate.c b/target-alpha/translate.c index 6156fb5d0d..1e1da542d0 100644 --- a/target-alpha/translate.c +++ b/target-alpha/translate.c @@ -2412,11 +2412,11 @@ static always_inline void gen_intermediate_code_internal (CPUState *env, if (env->singlestep_enabled) { gen_excp(&ctx, EXCP_DEBUG, 0); break; - } + } -#if defined (DO_SINGLE_STEP) - break; -#endif + if (singlestep) { + break; + } } if (ret != 1 && ret != 3) { tcg_gen_movi_i64(cpu_pc, ctx.pc); diff --git a/target-arm/translate.c b/target-arm/translate.c index f7f2a8d6f4..9aff6197cd 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -8791,6 +8791,7 @@ static inline void gen_intermediate_code_internal(CPUState *env, num_insns ++; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && + !singlestep && dc->pc < next_page_start && num_insns < max_insns); diff --git a/target-cris/translate.c b/target-cris/translate.c index d5fcb9e636..d9256ca423 100644 --- a/target-cris/translate.c +++ b/target-cris/translate.c @@ -3272,6 +3272,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, break; } while (!dc->is_jmp && !dc->cpustate_changed && gen_opc_ptr < gen_opc_end + && !singlestep && (dc->pc < next_page_start) && num_insns < max_insns); diff --git a/target-i386/translate.c b/target-i386/translate.c index cd2e3263e1..8df3ea439c 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -7733,6 +7733,11 @@ static inline void gen_intermediate_code_internal(CPUState *env, gen_eob(dc); break; } + if (singlestep) { + gen_jmp_im(pc_ptr - dc->cs_base); + gen_eob(dc); + break; + } } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-m68k/translate.c b/target-m68k/translate.c index 4e3cf4aa2e..f9b36c9630 100644 --- a/target-m68k/translate.c +++ b/target-m68k/translate.c @@ -3031,6 +3031,7 @@ gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, num_insns++; } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && !env->singlestep_enabled && + !singlestep && (pc_offset) < (TARGET_PAGE_SIZE - 32) && num_insns < max_insns); diff --git a/target-mips/translate.c b/target-mips/translate.c index 8adc89cffa..47a3062f86 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -38,7 +38,6 @@ //#define MIPS_DEBUG_DISAS //#define MIPS_DEBUG_SIGN_EXTENSIONS -//#define MIPS_SINGLE_STEP /* MIPS major opcodes */ #define MASK_OP_MAJOR(op) (op & (0x3F << 26)) @@ -8140,9 +8139,9 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, if (num_insns >= max_insns) break; -#if defined (MIPS_SINGLE_STEP) - break; -#endif + + if (singlestep) + break; } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-ppc/translate.c b/target-ppc/translate.c index 870aec5ec1..9ba4937498 100644 --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -39,7 +39,6 @@ #define GDBSTUB_SINGLE_STEP 0x4 /* Include definitions for instructions classes and implementations flags */ -//#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS //#define DO_PPC_STATISTICS @@ -8288,15 +8287,13 @@ static always_inline void gen_intermediate_code_internal (CPUState *env, gen_exception(ctxp, POWERPC_EXCP_TRACE); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (env->singlestep_enabled) || + singlestep || num_insns >= max_insns)) { /* if we reach a page boundary or are single stepping, stop * generation */ break; } -#if defined (DO_SINGLE_STEP) - break; -#endif } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-sh4/translate.c b/target-sh4/translate.c index 4ced176b3a..aa3b9d4396 100644 --- a/target-sh4/translate.c +++ b/target-sh4/translate.c @@ -1967,9 +1967,8 @@ gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb, break; if (num_insns >= max_insns) break; -#ifdef SH4_SINGLE_STEP - break; -#endif + if (singlestep) + break; } if (tb->cflags & CF_LAST_IO) gen_io_end(); diff --git a/target-sparc/translate.c b/target-sparc/translate.c index d059408ba1..86319a704b 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -4838,7 +4838,7 @@ static inline void gen_intermediate_code_internal(TranslationBlock * tb, break; /* if single step mode, we generate only one instruction and generate an exception */ - if (env->singlestep_enabled) { + if (env->singlestep_enabled || singlestep) { tcg_gen_movi_tl(cpu_pc, dc->pc); tcg_gen_exit_tb(0); break; diff --git a/vl.c b/vl.c index b294380a4f..4bd173f689 100644 --- a/vl.c +++ b/vl.c @@ -236,6 +236,7 @@ int win2k_install_hack = 0; int rtc_td_hack = 0; #endif int usb_enabled = 0; +int singlestep = 0; int smp_cpus = 1; const char *vnc_display; int acpi_enabled = 1; @@ -4660,6 +4661,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_bios: bios_name = optarg; break; + case QEMU_OPTION_singlestep: + singlestep = 1; + break; case QEMU_OPTION_S: autostart = 0; break;