Extend trigger-hit tracking to CPU watchpoints so load and store triggers preserve the exact matching trigger index across exception delivery.
This simplifies the watchpoint hit path for the same reason as the breakpoint case: the trigger programming code has already expanded the load/store bits, size, and address into the concrete QEMU watchpoint object stored in env->cpu_watchpoint[i]. When QEMU reports a watchpoint hit, matching that object back to the trigger slot is enough; there is no need to repeat the address and access-type comparisons in the debug exception handler. The remaining dynamic privilege and textra conditions are still revalidated before the trigger action is taken. This gives watchpoint-based debug entry the same precise trigger information that breakpoint triggers now carry in CPU state. Signed-off-by: Chao Liu <[email protected]> --- target/riscv/debug.c | 103 +++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 63 deletions(-) diff --git a/target/riscv/debug.c b/target/riscv/debug.c index ef2fafcbef..eb03f306b1 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -586,6 +586,29 @@ static int riscv_debug_find_breakpoint_trigger(CPUState *cs) return -1; } +static int riscv_debug_find_watchpoint_trigger(CPUState *cs, CPUWatchpoint *wp) +{ + RISCVCPU *cpu = RISCV_CPU(cs); + CPURISCVState *env = &cpu->env; + + for (int i = 0; i < RV_MAX_TRIGGERS; i++) { + int trigger_type = get_trigger_type(env, i); + + if (!trigger_common_match(env, trigger_type, i)) { + continue; + } + + if (wp != env->cpu_watchpoint[i]) { + continue; + } + + env->badaddr = wp->hitaddr; + return i; + } + + return -1; +} + static void type2_reg_write(CPURISCVState *env, target_ulong index, int tdata_index, target_ulong val) { @@ -1012,17 +1035,21 @@ void riscv_cpu_debug_excp_handler(CPUState *cs) return; } - if (cs->watchpoint_hit) { - if (cs->watchpoint_hit->flags & BP_CPU) { - do_trigger_action(env, DBG_ACTION_BP); - } - } else { - if (hit < 0) { - hit = riscv_debug_find_breakpoint_trigger(cs); - } - if (hit >= 0) { - do_trigger_action(env, hit); - } + if (hit < 0 && cs->watchpoint_hit && (cs->watchpoint_hit->flags & BP_CPU)) { + hit = riscv_debug_find_watchpoint_trigger(cs, cs->watchpoint_hit); + } + + if (cs->watchpoint_hit && + (hit >= 0 || (cs->watchpoint_hit->flags & BP_CPU))) { + cs->watchpoint_hit = NULL; + } + + if (hit < 0) { + hit = riscv_debug_find_breakpoint_trigger(cs); + } + + if (hit >= 0) { + do_trigger_action(env, hit); } } @@ -1039,59 +1066,9 @@ bool riscv_cpu_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) { RISCVCPU *cpu = RISCV_CPU(cs); CPURISCVState *env = &cpu->env; - target_ulong ctrl; - target_ulong addr; - int trigger_type; - int flags; - int i; - - for (i = 0; i < RV_MAX_TRIGGERS; i++) { - trigger_type = get_trigger_type(env, i); - - if (!trigger_common_match(env, trigger_type, i)) { - continue; - } - - switch (trigger_type) { - case TRIGGER_TYPE_AD_MATCH: - ctrl = env->tdata1[i]; - addr = env->tdata2[i]; - flags = 0; - - if (ctrl & TYPE2_LOAD) { - flags |= BP_MEM_READ; - } - if (ctrl & TYPE2_STORE) { - flags |= BP_MEM_WRITE; - } - if ((wp->flags & flags) && (wp->vaddr == addr)) { - return true; - } - break; - case TRIGGER_TYPE_AD_MATCH6: - ctrl = env->tdata1[i]; - addr = env->tdata2[i]; - flags = 0; - - if (ctrl & TYPE6_LOAD) { - flags |= BP_MEM_READ; - } - if (ctrl & TYPE6_STORE) { - flags |= BP_MEM_WRITE; - } - - if ((wp->flags & flags) && (wp->vaddr == addr)) { - return true; - } - break; - default: - /* other trigger types are not supported */ - break; - } - } - - return false; + env->pending_trigger_hit = riscv_debug_find_watchpoint_trigger(cs, wp); + return env->pending_trigger_hit >= 0; } void riscv_trigger_realize(CPURISCVState *env) -- 2.53.0
