target-arm: Fix CPU breakpoint handling

A QEMU breakpoint match is not definitely an architectural breakpoint
match. If an exception is generated unconditionally during translation,
it is hardly possible to ignore it in the debug exception handler.

Generate a call to a helper to check CPU breakpoints and raise an
exception only if any breakpoint matches architecturally.

Backports commit 5d98bf8f38c17a348ab6e8af196088cd4953acd0 from qemu
This commit is contained in:
Sergey Fedorov 2018-02-16 14:54:32 -05:00 committed by Lioncash
parent 4706e10887
commit e4e0c75f0f
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
18 changed files with 66 additions and 26 deletions

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_aarch64 #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_aarch64
#define gen_helper_add_saturate gen_helper_add_saturate_aarch64 #define gen_helper_add_saturate gen_helper_add_saturate_aarch64
#define gen_helper_add_setq gen_helper_add_setq_aarch64 #define gen_helper_add_setq gen_helper_add_setq_aarch64
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_aarch64
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_aarch64 #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_aarch64
#define gen_helper_clz32 gen_helper_clz32_aarch64 #define gen_helper_clz32 gen_helper_clz32_aarch64
#define gen_helper_clz64 gen_helper_clz64_aarch64 #define gen_helper_clz64 gen_helper_clz64_aarch64

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_aarch64eb #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_aarch64eb
#define gen_helper_add_saturate gen_helper_add_saturate_aarch64eb #define gen_helper_add_saturate gen_helper_add_saturate_aarch64eb
#define gen_helper_add_setq gen_helper_add_setq_aarch64eb #define gen_helper_add_setq gen_helper_add_setq_aarch64eb
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_aarch64eb
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_aarch64eb #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_aarch64eb
#define gen_helper_clz32 gen_helper_clz32_aarch64eb #define gen_helper_clz32 gen_helper_clz32_aarch64eb
#define gen_helper_clz64 gen_helper_clz64_aarch64eb #define gen_helper_clz64 gen_helper_clz64_aarch64eb

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_arm #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_arm
#define gen_helper_add_saturate gen_helper_add_saturate_arm #define gen_helper_add_saturate gen_helper_add_saturate_arm
#define gen_helper_add_setq gen_helper_add_setq_arm #define gen_helper_add_setq gen_helper_add_setq_arm
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_arm
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_arm #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_arm
#define gen_helper_clz32 gen_helper_clz32_arm #define gen_helper_clz32 gen_helper_clz32_arm
#define gen_helper_clz64 gen_helper_clz64_arm #define gen_helper_clz64 gen_helper_clz64_arm

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_armeb #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_armeb
#define gen_helper_add_saturate gen_helper_add_saturate_armeb #define gen_helper_add_saturate gen_helper_add_saturate_armeb
#define gen_helper_add_setq gen_helper_add_setq_armeb #define gen_helper_add_setq gen_helper_add_setq_armeb
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_armeb
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_armeb #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_armeb
#define gen_helper_clz32 gen_helper_clz32_armeb #define gen_helper_clz32 gen_helper_clz32_armeb
#define gen_helper_clz64 gen_helper_clz64_armeb #define gen_helper_clz64 gen_helper_clz64_armeb

View file

@ -673,6 +673,7 @@ symbols = (
'gen_helper_access_check_cp_reg', 'gen_helper_access_check_cp_reg',
'gen_helper_add_saturate', 'gen_helper_add_saturate',
'gen_helper_add_setq', 'gen_helper_add_setq',
'gen_helper_check_breakpoints',
'gen_helper_clear_pstate_ss', 'gen_helper_clear_pstate_ss',
'gen_helper_clz32', 'gen_helper_clz32',
'gen_helper_clz64', 'gen_helper_clz64',

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_m68k #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_m68k
#define gen_helper_add_saturate gen_helper_add_saturate_m68k #define gen_helper_add_saturate gen_helper_add_saturate_m68k
#define gen_helper_add_setq gen_helper_add_setq_m68k #define gen_helper_add_setq gen_helper_add_setq_m68k
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_m68k
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_m68k #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_m68k
#define gen_helper_clz32 gen_helper_clz32_m68k #define gen_helper_clz32 gen_helper_clz32_m68k
#define gen_helper_clz64 gen_helper_clz64_m68k #define gen_helper_clz64 gen_helper_clz64_m68k

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips
#define gen_helper_add_saturate gen_helper_add_saturate_mips #define gen_helper_add_saturate gen_helper_add_saturate_mips
#define gen_helper_add_setq gen_helper_add_setq_mips #define gen_helper_add_setq gen_helper_add_setq_mips
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_mips
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips
#define gen_helper_clz32 gen_helper_clz32_mips #define gen_helper_clz32 gen_helper_clz32_mips
#define gen_helper_clz64 gen_helper_clz64_mips #define gen_helper_clz64 gen_helper_clz64_mips

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips64 #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips64
#define gen_helper_add_saturate gen_helper_add_saturate_mips64 #define gen_helper_add_saturate gen_helper_add_saturate_mips64
#define gen_helper_add_setq gen_helper_add_setq_mips64 #define gen_helper_add_setq gen_helper_add_setq_mips64
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_mips64
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips64 #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips64
#define gen_helper_clz32 gen_helper_clz32_mips64 #define gen_helper_clz32 gen_helper_clz32_mips64
#define gen_helper_clz64 gen_helper_clz64_mips64 #define gen_helper_clz64 gen_helper_clz64_mips64

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips64el #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mips64el
#define gen_helper_add_saturate gen_helper_add_saturate_mips64el #define gen_helper_add_saturate gen_helper_add_saturate_mips64el
#define gen_helper_add_setq gen_helper_add_setq_mips64el #define gen_helper_add_setq gen_helper_add_setq_mips64el
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_mips64el
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips64el #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mips64el
#define gen_helper_clz32 gen_helper_clz32_mips64el #define gen_helper_clz32 gen_helper_clz32_mips64el
#define gen_helper_clz64 gen_helper_clz64_mips64el #define gen_helper_clz64 gen_helper_clz64_mips64el

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mipsel #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_mipsel
#define gen_helper_add_saturate gen_helper_add_saturate_mipsel #define gen_helper_add_saturate gen_helper_add_saturate_mipsel
#define gen_helper_add_setq gen_helper_add_setq_mipsel #define gen_helper_add_setq gen_helper_add_setq_mipsel
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_mipsel
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mipsel #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_mipsel
#define gen_helper_clz32 gen_helper_clz32_mipsel #define gen_helper_clz32 gen_helper_clz32_mipsel
#define gen_helper_clz64 gen_helper_clz64_mipsel #define gen_helper_clz64 gen_helper_clz64_mipsel

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_powerpc #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_powerpc
#define gen_helper_add_saturate gen_helper_add_saturate_powerpc #define gen_helper_add_saturate gen_helper_add_saturate_powerpc
#define gen_helper_add_setq gen_helper_add_setq_powerpc #define gen_helper_add_setq gen_helper_add_setq_powerpc
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_powerpc
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_powerpc #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_powerpc
#define gen_helper_clz32 gen_helper_clz32_powerpc #define gen_helper_clz32 gen_helper_clz32_powerpc
#define gen_helper_clz64 gen_helper_clz64_powerpc #define gen_helper_clz64 gen_helper_clz64_powerpc

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_sparc #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_sparc
#define gen_helper_add_saturate gen_helper_add_saturate_sparc #define gen_helper_add_saturate gen_helper_add_saturate_sparc
#define gen_helper_add_setq gen_helper_add_setq_sparc #define gen_helper_add_setq gen_helper_add_setq_sparc
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_sparc
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_sparc #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_sparc
#define gen_helper_clz32 gen_helper_clz32_sparc #define gen_helper_clz32 gen_helper_clz32_sparc
#define gen_helper_clz64 gen_helper_clz64_sparc #define gen_helper_clz64 gen_helper_clz64_sparc

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_sparc64 #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_sparc64
#define gen_helper_add_saturate gen_helper_add_saturate_sparc64 #define gen_helper_add_saturate gen_helper_add_saturate_sparc64
#define gen_helper_add_setq gen_helper_add_setq_sparc64 #define gen_helper_add_setq gen_helper_add_setq_sparc64
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_sparc64
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_sparc64 #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_sparc64
#define gen_helper_clz32 gen_helper_clz32_sparc64 #define gen_helper_clz32 gen_helper_clz32_sparc64
#define gen_helper_clz64 gen_helper_clz64_sparc64 #define gen_helper_clz64 gen_helper_clz64_sparc64

View file

@ -57,6 +57,8 @@ DEF_HELPER_1(yield, void, env)
DEF_HELPER_1(pre_hvc, void, env) DEF_HELPER_1(pre_hvc, void, env)
DEF_HELPER_2(pre_smc, void, env, i32) DEF_HELPER_2(pre_smc, void, env, i32)
DEF_HELPER_1(check_breakpoints, void, env)
DEF_HELPER_3(cpsr_write, void, env, i32, i32) DEF_HELPER_3(cpsr_write, void, env, i32, i32)
DEF_HELPER_1(cpsr_read, i32, env) DEF_HELPER_1(cpsr_read, i32, env)

View file

@ -864,6 +864,15 @@ static bool check_breakpoints(ARMCPU *cpu)
return false; return false;
} }
void HELPER(check_breakpoints)(CPUARMState *env)
{
ARMCPU *cpu = arm_env_get_cpu(env);
if (check_breakpoints(cpu)) {
HELPER(exception_internal(env, EXCP_DEBUG));
}
}
void arm_debug_excp_handler(CPUState *cs) void arm_debug_excp_handler(CPUState *cs)
{ {
/* Called by core code when a watchpoint or breakpoint fires; /* Called by core code when a watchpoint or breakpoint fires;
@ -894,25 +903,24 @@ void arm_debug_excp_handler(CPUState *cs)
} }
} }
} else { } else {
/* Unicorn: commented out // Unicorn: commented out
uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; //uint64_t pc = is_a64(env) ? env->pc : env->regs[15];
bool same_el = (arm_debug_target_el(env) == arm_current_el(env));
if (cpu_breakpoint_test(cs, pc, BP_GDB)) { // Unicorn: commented out
return; //if (cpu_breakpoint_test(cs, pc, BP_GDB)) {
}*/ // return;
//}
if (check_breakpoints(cpu)) { if (extended_addresses_enabled(env)) {
bool same_el = (arm_debug_target_el(env) == arm_current_el(env)); env->exception.fsr = (1 << 9) | 0x22;
if (extended_addresses_enabled(env)) { } else {
env->exception.fsr = (1 << 9) | 0x22; env->exception.fsr = 0x2;
} else {
env->exception.fsr = 0x2;
}
/* FAR is UNKNOWN, so doesn't need setting */
raise_exception(env, EXCP_PREFETCH_ABORT,
syn_breakpoint(same_el),
arm_debug_target_el(env));
} }
/* FAR is UNKNOWN, so doesn't need setting */
raise_exception(env, EXCP_PREFETCH_ABORT,
syn_breakpoint(same_el),
arm_debug_target_el(env));
} }
} }

View file

@ -11319,11 +11319,18 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG); if (bp->flags & BP_CPU) {
/* Advance PC so that clearing the breakpoint will gen_helper_check_breakpoints(tcg_ctx, tcg_ctx->cpu_env);
invalidate this TB. */ /* End the TB early; it likely won't be executed */
dc->pc += 2; dc->is_jmp = DISAS_UPDATE;
goto done_generating; } else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* Advance PC so that clearing the breakpoint will
invalidate this TB. */
dc->pc += 4;
goto done_generating;
}
break;
} }
} }
} }

View file

@ -11534,11 +11534,20 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
if (bp->pc == dc->pc) { if (bp->pc == dc->pc) {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG); if (bp->flags & BP_CPU) {
/* Advance PC so that clearing the breakpoint will gen_helper_check_breakpoints(tcg_ctx, tcg_ctx->cpu_env);
invalidate this TB. */ /* End the TB early; it's likely not going to be executed */
dc->pc += 2; dc->is_jmp = DISAS_UPDATE;
goto done_generating; } else {
gen_exception_internal_insn(dc, 0, EXCP_DEBUG);
/* Advance PC so that clearing the breakpoint will
invalidate this TB. */
/* TODO: Advance PC by correct instruction length to
* avoid disassembler error messages */
dc->pc += 2;
goto done_generating;
}
break;
} }
} }
} }

View file

@ -667,6 +667,7 @@
#define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_x86_64 #define gen_helper_access_check_cp_reg gen_helper_access_check_cp_reg_x86_64
#define gen_helper_add_saturate gen_helper_add_saturate_x86_64 #define gen_helper_add_saturate gen_helper_add_saturate_x86_64
#define gen_helper_add_setq gen_helper_add_setq_x86_64 #define gen_helper_add_setq gen_helper_add_setq_x86_64
#define gen_helper_check_breakpoints gen_helper_check_breakpoints_x86_64
#define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_x86_64 #define gen_helper_clear_pstate_ss gen_helper_clear_pstate_ss_x86_64
#define gen_helper_clz32 gen_helper_clz32_x86_64 #define gen_helper_clz32 gen_helper_clz32_x86_64
#define gen_helper_clz64 gen_helper_clz64_x86_64 #define gen_helper_clz64 gen_helper_clz64_x86_64