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


Reply via email to