diff options
Diffstat (limited to 'target-mips')
-rw-r--r-- | target-mips/translate.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/target-mips/translate.c b/target-mips/translate.c index fb3c980c18..72692efe08 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -463,6 +463,7 @@ typedef struct DisasContext { struct TranslationBlock *tb; target_ulong pc, saved_pc; uint32_t opcode; + int singlestep_enabled; /* Routine used to access memory */ int mem_idx; uint32_t hflags, saved_hflags; @@ -2459,12 +2460,17 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) { TranslationBlock *tb; tb = ctx->tb; - if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) && + likely(!ctx->singlestep_enabled)) { tcg_gen_goto_tb(n); gen_save_pc(dest); tcg_gen_exit_tb((long)tb + n); } else { gen_save_pc(dest); + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); + gen_helper_0i(raise_exception, EXCP_DEBUG); + } tcg_gen_exit_tb(0); } } @@ -8263,6 +8269,10 @@ static void decode_opc (CPUState *env, DisasContext *ctx) /* unconditional branch to register */ MIPS_DEBUG("branch to register"); tcg_gen_mov_tl(cpu_PC, btarget); + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); + gen_helper_0i(raise_exception, EXCP_DEBUG); + } tcg_gen_exit_tb(0); break; default: @@ -8292,6 +8302,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, gen_opc_end = gen_opc_buf + OPC_MAX_SIZE - 16; ctx.pc = pc_start; ctx.saved_pc = -1; + ctx.singlestep_enabled = env->singlestep_enabled; ctx.tb = tb; ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ @@ -8347,7 +8358,11 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, ctx.pc += 4; num_insns++; - if (env->singlestep_enabled) + /* Execute a branch and its delay slot as a single instruction. + This is what GDB expects and is consistent with what the + hardware does (e.g. if a delay slot instruction faults, the + reported PC is the PC of the branch). */ + if (env->singlestep_enabled && (ctx.hflags & MIPS_HFLAG_BMASK) == 0) break; if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) @@ -8364,7 +8379,7 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, } if (tb->cflags & CF_LAST_IO) gen_io_end(); - if (env->singlestep_enabled) { + if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) { save_cpu_state(&ctx, ctx.bstate == BS_NONE); gen_helper_0i(raise_exception, EXCP_DEBUG); } else { |