Skip to content

Commit ec2818a

Browse files
author
zhusonghe
committed
target/riscv:Perform single step before resume if necessary
Two cases where single step is needed before resume: 1. ebreak used in software breakpoint; 2. a trigger that is taken just before the instruction that triggered it is retired. Signed-off-by: Songhe Zhu <[email protected]> Co-developed-by: Fei Gao <[email protected]> Co-developed-by: xiatianyi <[email protected]>
1 parent a4020f1 commit ec2818a

File tree

2 files changed

+83
-7
lines changed

2 files changed

+83
-7
lines changed

src/target/riscv/riscv.c

+80-7
Original file line numberDiff line numberDiff line change
@@ -623,12 +623,12 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
623623

624624
static unsigned int count_trailing_ones(riscv_reg_t reg)
625625
{
626-
assert(sizeof(riscv_reg_t) * 8 == 64);
627-
for (unsigned int i = 0; i < 64; i++) {
626+
const unsigned int riscv_reg_bits = sizeof(riscv_reg_t) * CHAR_BIT;
627+
for (unsigned int i = 0; i < riscv_reg_bits; i++) {
628628
if ((1 & (reg >> i)) == 0)
629629
return i;
630630
}
631-
return 64;
631+
return riscv_reg_bits;
632632
}
633633

634634
static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2)
@@ -1576,6 +1576,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
15761576

15771577
// FIXME: Add hit bits support detection and caching
15781578
RISCV_INFO(r);
1579+
r->need_single_step = false;
15791580

15801581
riscv_reg_t tselect;
15811582
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
@@ -2278,6 +2279,67 @@ derive_debug_reason_without_hitbit(const struct target *target, riscv_reg_t dpc)
22782279
}
22792280
return DBG_REASON_WATCHPOINT;
22802281
}
2282+
2283+
static bool check_single_step_needed_in_hit_supported_case(struct target *target,
2284+
uint32_t unique_id)
2285+
{
2286+
RISCV_INFO(r);
2287+
riscv_reg_t tselect;
2288+
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
2289+
return ERROR_FAIL;
2290+
if (riscv_reg_set(target, GDB_REGNO_TSELECT, unique_id) != ERROR_OK)
2291+
return ERROR_FAIL;
2292+
riscv_reg_t tdata1;
2293+
if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
2294+
return ERROR_FAIL;
2295+
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
2296+
if (type == CSR_TDATA1_TYPE_MCONTROL) {
2297+
if (get_field(tdata1, CSR_MCONTROL_TIMING) == CSR_MCONTROL_TIMING_BEFORE)
2298+
r->need_single_step = true;
2299+
} else if (type == CSR_TDATA1_TYPE_MCONTROL6) {
2300+
int hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0);
2301+
int hit1 = get_field(tdata1, CSR_MCONTROL6_HIT1);
2302+
int trigger_retired_info = (hit1 << 1) | hit0;
2303+
if (trigger_retired_info == CSR_MCONTROL6_HIT0_BEFORE)
2304+
r->need_single_step = true;
2305+
} else {
2306+
r->need_single_step = false;
2307+
}
2308+
if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
2309+
return ERROR_FAIL;
2310+
return r->need_single_step;
2311+
}
2312+
2313+
static bool check_single_step_needed_in_hit_unsupported_case(struct target *target)
2314+
{
2315+
RISCV_INFO(r);
2316+
r->need_single_step = false;
2317+
riscv_reg_t tselect;
2318+
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
2319+
return ERROR_FAIL;
2320+
2321+
for (unsigned int i = 0; i < r->trigger_count; i++) {
2322+
if (riscv_reg_set(target, GDB_REGNO_TSELECT, i) != ERROR_OK)
2323+
return ERROR_FAIL;
2324+
2325+
uint64_t tdata1;
2326+
if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
2327+
return ERROR_FAIL;
2328+
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
2329+
if (type == CSR_TDATA1_TYPE_MCONTROL) {
2330+
if (get_field(tdata1, CSR_MCONTROL_TIMING) == CSR_MCONTROL_TIMING_BEFORE)
2331+
r->need_single_step = true;
2332+
} else if (type == CSR_TDATA1_TYPE_MCONTROL6) {
2333+
r->need_single_step = true;
2334+
}
2335+
}
2336+
if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
2337+
return ERROR_FAIL;
2338+
2339+
return r->need_single_step;
2340+
}
2341+
2342+
22812343
/**
22822344
* Set OpenOCD's generic debug reason from the RISC-V halt reason.
22832345
*/
@@ -2319,6 +2381,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r
23192381
LOG_TARGET_DEBUG(target,
23202382
"Watchpoint with unique_id = %" PRIu32 " owns the trigger.",
23212383
wp->unique_id);
2384+
r->need_single_step = check_single_step_needed_in_hit_supported_case(target, wp->unique_id);
23222385
}
23232386
}
23242387
}
@@ -2336,6 +2399,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r
23362399
* breakpoints and hope for the best)
23372400
*/
23382401
target->debug_reason = derive_debug_reason_without_hitbit(target, dpc);
2402+
r->need_single_step = check_single_step_needed_in_hit_unsupported_case(target);
23392403
}
23402404
break;
23412405
case RISCV_HALT_INTERRUPT:
@@ -2553,10 +2617,19 @@ static int resume_prep(struct target *target, int current,
25532617
if (handle_breakpoints) {
25542618
/* To be able to run off a trigger, we perform a step operation and then
25552619
* resume. If handle_breakpoints is true then step temporarily disables
2556-
* pending breakpoints so we can safely perform the step. */
2557-
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2558-
false /* callbacks are not called */) != ERROR_OK)
2559-
return ERROR_FAIL;
2620+
* pending breakpoints so we can safely perform the step.
2621+
*
2622+
* Two cases where single step is needed before resuming:
2623+
* 1. ebreak used in software breakpoint;
2624+
* 2. a trigger that is taken just before the instruction that triggered it is retired.
2625+
*/
2626+
if (target->debug_reason == DBG_REASON_BREAKPOINT
2627+
|| (target->debug_reason == DBG_REASON_WATCHPOINT
2628+
&& r->need_single_step)) {
2629+
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2630+
false /* callbacks are not called */) != ERROR_OK)
2631+
return ERROR_FAIL;
2632+
}
25602633
}
25612634

25622635
if (r->get_hart_state) {

src/target/riscv/riscv.h

+3
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ struct riscv_info {
152152
/* record the tinfo of each trigger */
153153
unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS];
154154

155+
/* record the dpc that triggered it is retired. */
156+
bool need_single_step;
157+
155158
/* For each physical trigger contains:
156159
* -1: the hwbp is available
157160
* -4: The trigger is used by the itrigger command

0 commit comments

Comments
 (0)