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 or MSR_BE on a branch instruction. Signed-off-by: Jason Wessel --- target-ppc/translate.c | 60 +++++++++++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 21 deletions(-) --- a/target-ppc/translate.c +++ b/target-ppc/translate.c @@ -29,6 +29,10 @@ #include "tcg-op.h" #include "qemu-common.h" +#define CPU_SINGLE_STEP 0x1 +#define CPU_BRANCH_STEP 0x2 +#define GDBSTUB_SINGLE_STEP 0x4 + /* Include definitions for instructions classes and implementations flags */ //#define DO_SINGLE_STEP //#define PPC_DEBUG_DISAS @@ -2785,7 +2789,7 @@ static always_inline void gen_goto_tb (D TranslationBlock *tb; tb = ctx->tb; if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && - !ctx->singlestep_enabled) { + likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); gen_set_T1(dest); #if defined(TARGET_PPC64) @@ -2803,8 +2807,20 @@ 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 & + (CPU_BRANCH_STEP | CPU_SINGLE_STEP)) && + ctx->exception == POWERPC_EXCP_BRANCH) { + target_ulong tmp = ctx->nip; + ctx->nip = dest; + GEN_EXCP(ctx, POWERPC_EXCP_TRACE, 0); + ctx->nip = tmp; + } + if (ctx->singlestep_enabled & GDBSTUB_SINGLE_STEP) { + gen_update_nip(ctx, dest); + gen_op_debug(); + } + } tcg_gen_exit_tb(0); } } @@ -2824,6 +2840,7 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000 { target_ulong li, target; + ctx->exception = POWERPC_EXCP_BRANCH; /* sign extend LI */ #if defined(TARGET_PPC64) if (ctx->sf_mode) @@ -2842,7 +2859,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000 if (LK(ctx->opcode)) gen_setlr(ctx, ctx->nip); gen_goto_tb(ctx, 0, target); - ctx->exception = POWERPC_EXCP_BRANCH; } #define BCOND_IM 0 @@ -2857,6 +2873,7 @@ static always_inline void gen_bcond (Dis uint32_t bi = BI(ctx->opcode); uint32_t mask; + ctx->exception = POWERPC_EXCP_BRANCH; if ((bo & 0x4) == 0) gen_op_dec_ctr(); switch(type) { @@ -2985,12 +3002,14 @@ 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: - ctx->exception = POWERPC_EXCP_BRANCH; + return; } GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW) @@ -6150,7 +6169,6 @@ 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 j, lj = -1; pc_start = tb->pc; @@ -6184,14 +6202,13 @@ 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; + ctx.singlestep_enabled |= CPU_BRANCH_STEP; + if (unlikely(env->singlestep_enabled)) + ctx.singlestep_enabled |= GDBSTUB_SINGLE_STEP; #if defined (DO_SINGLE_STEP) && 0 /* Single step trace mode */ msr_se = 1; @@ -6284,14 +6301,11 @@ static always_inline int gen_intermediat handler->count++; #endif /* Check trace mode exceptions */ - 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) && - ctx.exception != POWERPC_SYSCALL && - ctx.exception != POWERPC_EXCP_TRAP)) { + 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_BRANCH)) { GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0); } else if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) || (env->singlestep_enabled))) { @@ -6307,6 +6321,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(env->singlestep_enabled)) { + gen_update_nip(&ctx, ctx.nip); + gen_op_debug(); + } /* Generate the return instruction */ tcg_gen_exit_tb(0); }