From: Jason Wessel Subject: [PATCH] Fix ppc user space single stepping User space OS single stepping will hang a qemu instance because the instruction translation executes an internal debug exception that is meant for the qemu backend debugger. The test case is to use any program which executes a ptrace attach to a process and then "ptrace(PTRACE_SINGLESTEP,pid,0,0);". In general you could simply use gdb on the target and request it to "instruction step" a process with "si", so long as gdb is setup to not emulate single stepping with breakpoints. This patch splits the run-time single stepping from the debugger stub single stepping such that each type of single stepping gets the correct exception generation. This patch also fixes the defect where branches were incorrectly calculated for the update to the env->nip when setting MSR_SE on a branch instruction. Signed-off-by: Jason Wessel --- target-ppc/translate.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -29,6 +29,9 @@ #include "tcg-op.h" #include "qemu-common.h" +#define CPU_SINGLE_STEP 0x1 +#define GDBSTUB_SINGLE_STEP 0x2 + /* Include definitions for instructions classes and implementations flags */ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS @@ -2803,8 +2806,17 @@ static always_inline void gen_goto_tb (D else #endif gen_op_b_T1(); - if (ctx->singlestep_enabled) - gen_op_debug(); + if (unlikely(ctx->singlestep_enabled)) { + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, dest); + gen_op_debug(); + } else { + target_ulong tmp = ctx->nip; + ctx->nip = dest; + GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0); + ctx->nip = tmp; + } + } tcg_gen_exit_tb(0); } } @@ -2985,8 +2997,10 @@ static always_inline void gen_bcond (Dis #endif gen_op_btest_T1(ctx->nip); no_test: - if (ctx->singlestep_enabled) + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, ctx->nip); gen_op_debug(); + } tcg_gen_exit_tb(0); } out: @@ -6150,7 +6164,7 @@ static always_inline int gen_intermediat target_ulong pc_start; uint16_t *gen_opc_end; int supervisor, little_endian; - int single_step, branch_step; + int branch_step; int j, lj = -1; pc_start = tb->pc; @@ -6184,14 +6198,15 @@ static always_inline int gen_intermediat else ctx.altivec_enabled = 0; if ((env->flags & POWERPC_FLAG_SE) && msr_se) - single_step = 1; + ctx.singlestep_enabled = CPU_SINGLE_STEP; else - single_step = 0; + ctx.singlestep_enabled = 0; if ((env->flags & POWERPC_FLAG_BE) && msr_be) branch_step = 1; else branch_step = 0; - ctx.singlestep_enabled = env->singlestep_enabled || single_step == 1; + if (unlikely(env->singlestep_enabled)) + ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; @@ -6287,11 +6302,11 @@ static always_inline int gen_intermediat if (unlikely(branch_step != 0 && ctx.exception == POWERPC_EXCP_BRANCH)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); - } else if (unlikely(single_step != 0 && - (ctx.nip <= 0x100 || ctx.nip > 0xF00 || - (ctx.nip & 0xFC) != 0x04) && + } else if (unlikely(ctx.singlestep_enabled & CPU_SINGLE_STEP && + (ctx.nip <= 0x100 || ctx.nip > 0xF00) && ctx.exception != POWERPC_SYSCALL && - ctx.exception != POWERPC_EXCP_TRAP)) { + ctx.exception != POWERPC_EXCP_TRAP && + ctx.exception != POWERPC_EXCP_BRANCH)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (env->singlestep_enabled))) { @@ -6307,6 +6322,10 @@ static always_inline int gen_intermediat if (ctx.exception == POWERPC_EXCP_NONE) { gen_goto_tb(&ctx, 0, ctx.nip); } else if (ctx.exception != POWERPC_EXCP_BRANCH) { + if (unlikely(ctx.singlestep_enabled & GDBSTUB_SINGLE_STEP)) { + gen_update_nip(&ctx, ctx.nip); + gen_op_debug(); + } /* Generate the return instruction */ tcg_gen_exit_tb(0); }