Skip to content

Commit 1bf7efb

Browse files
authored
Merge pull request #1144 from sunnyzhu-learning/resume-before-step-develop
target/riscv:Perform single step before resume if necessary
2 parents f51900b + 215ecda commit 1bf7efb

File tree

2 files changed

+115
-12
lines changed

2 files changed

+115
-12
lines changed

src/target/riscv/riscv.c

+103-12
Original file line numberDiff line numberDiff line change
@@ -648,12 +648,12 @@ static int find_first_trigger_by_id(struct target *target, int unique_id)
648648

649649
static unsigned int count_trailing_ones(riscv_reg_t reg)
650650
{
651-
assert(sizeof(riscv_reg_t) * 8 == 64);
652-
for (unsigned int i = 0; i < 64; i++) {
651+
const unsigned int riscv_reg_bits = sizeof(riscv_reg_t) * CHAR_BIT;
652+
for (unsigned int i = 0; i < riscv_reg_bits; i++) {
653653
if ((1 & (reg >> i)) == 0)
654654
return i;
655655
}
656-
return 64;
656+
return riscv_reg_bits;
657657
}
658658

659659
static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2)
@@ -1586,21 +1586,75 @@ int riscv_remove_watchpoint(struct target *target,
15861586
return ERROR_OK;
15871587
}
15881588

1589+
typedef enum {
1590+
M6_HIT_ERROR,
1591+
M6_HIT_NOT_SUPPORTED,
1592+
M6_NOT_HIT,
1593+
M6_HIT_BEFORE,
1594+
M6_HIT_AFTER,
1595+
M6_HIT_IMM_AFTER
1596+
} mctrl6hitstatus;
1597+
1598+
static mctrl6hitstatus check_mcontrol6_hit_status(struct target *target,
1599+
riscv_reg_t tdata1, uint64_t hit_mask)
1600+
{
1601+
const uint32_t hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0);
1602+
const uint32_t hit1 = get_field(tdata1, CSR_MCONTROL6_HIT1);
1603+
const uint32_t hit_info = (hit1 << 1) | hit0;
1604+
if (hit_info == CSR_MCONTROL6_HIT0_BEFORE)
1605+
return M6_HIT_BEFORE;
1606+
1607+
if (hit_info == CSR_MCONTROL6_HIT0_AFTER)
1608+
return M6_HIT_AFTER;
1609+
1610+
if (hit_info == CSR_MCONTROL6_HIT0_IMMEDIATELY_AFTER)
1611+
return M6_HIT_IMM_AFTER;
1612+
1613+
if (hit_info == CSR_MCONTROL6_HIT0_FALSE) {
1614+
/* hit[1..0] equals 0, which can mean one of the following:
1615+
* - "hit" bits are supported and this trigger has not fired
1616+
* - "hit" bits are not supported on this trigger
1617+
* To distinguish these two cases, try writing all non-zero bit
1618+
* patterns to hit[1..0] to determine if the "hit" bits are supported:
1619+
*/
1620+
riscv_reg_t tdata1_tests[] = {
1621+
set_field(tdata1, CSR_MCONTROL6_HIT0, 1),
1622+
set_field(tdata1, CSR_MCONTROL6_HIT1, 1),
1623+
set_field(tdata1, CSR_MCONTROL6_HIT0, 1) | field_value(CSR_MCONTROL6_HIT1, 1)
1624+
};
1625+
riscv_reg_t tdata1_test_rb;
1626+
for (uint64_t i = 0; i < ARRAY_SIZE(tdata1_tests); ++i) {
1627+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_tests[i]) != ERROR_OK)
1628+
return M6_HIT_ERROR;
1629+
if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK)
1630+
return M6_HIT_ERROR;
1631+
if (tdata1_test_rb == tdata1_tests[i]) {
1632+
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK)
1633+
return M6_HIT_ERROR;
1634+
return M6_NOT_HIT;
1635+
}
1636+
}
1637+
}
1638+
return M6_HIT_NOT_SUPPORTED;
1639+
}
1640+
15891641
/**
15901642
* Look at the trigger hit bits to find out which trigger is the reason we're
15911643
* halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is
15921644
* RISCV_TRIGGER_HIT_NOT_FOUND, no match was found.
15931645
*/
15941646

1595-
static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_id)
1647+
static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_id,
1648+
bool *need_single_step)
15961649
{
15971650
/* FIXME: this function assumes that we have only one trigger that can
15981651
* have hit bit set. Debug spec allows hit bit to bit set if a trigger has
15991652
* matched but did not fire. Such targets will receive erroneous results.
16001653
*/
16011654

1602-
// FIXME: Add hit bits support detection and caching
16031655
RISCV_INFO(r);
1656+
assert(need_single_step);
1657+
*need_single_step = false;
16041658

16051659
riscv_reg_t tselect;
16061660
if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
@@ -1626,9 +1680,21 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
16261680
break;
16271681
case CSR_TDATA1_TYPE_MCONTROL:
16281682
hit_mask = CSR_MCONTROL_HIT;
1683+
*need_single_step = true;
16291684
break;
16301685
case CSR_TDATA1_TYPE_MCONTROL6:
16311686
hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1;
1687+
if (r->tinfo_version == CSR_TINFO_VERSION_0) {
1688+
*need_single_step = true;
1689+
} else if (r->tinfo_version == RISCV_TINFO_VERSION_UNKNOWN
1690+
|| r->tinfo_version == CSR_TINFO_VERSION_1) {
1691+
mctrl6hitstatus hits_status = check_mcontrol6_hit_status(target,
1692+
tdata1, hit_mask);
1693+
if (hits_status == M6_HIT_ERROR)
1694+
return ERROR_FAIL;
1695+
if (hits_status == M6_HIT_BEFORE || hits_status == M6_HIT_NOT_SUPPORTED)
1696+
*need_single_step = true;
1697+
}
16321698
break;
16331699
case CSR_TDATA1_TYPE_ICOUNT:
16341700
hit_mask = CSR_ICOUNT_HIT;
@@ -1647,8 +1713,9 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
16471713
/* FIXME: this logic needs to be changed to ignore triggers that are not
16481714
* the last one in the chain. */
16491715
if (tdata1 & hit_mask) {
1650-
LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64 ") has hit bit set.",
1651-
i, r->trigger_unique_id[i]);
1716+
LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64
1717+
") has hit bit set. (need_single_step=%s)",
1718+
i, r->trigger_unique_id[i], (*need_single_step) ? "yes" : "no");
16521719
if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK)
16531720
return ERROR_FAIL;
16541721

@@ -2310,13 +2377,15 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r
23102377
{
23112378
RISCV_INFO(r);
23122379
r->trigger_hit = -1;
2380+
r->need_single_step = false;
23132381
switch (halt_reason) {
23142382
case RISCV_HALT_EBREAK:
23152383
target->debug_reason = DBG_REASON_BREAKPOINT;
23162384
break;
23172385
case RISCV_HALT_TRIGGER:
23182386
target->debug_reason = DBG_REASON_UNDEFINED;
2319-
if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit) != ERROR_OK)
2387+
if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit,
2388+
&r->need_single_step) != ERROR_OK)
23202389
return ERROR_FAIL;
23212390
// FIXME: handle multiple hit bits
23222391
if (r->trigger_hit != RISCV_TRIGGER_HIT_NOT_FOUND) {
@@ -2578,10 +2647,19 @@ static int resume_prep(struct target *target, int current,
25782647
if (handle_breakpoints) {
25792648
/* To be able to run off a trigger, we perform a step operation and then
25802649
* resume. If handle_breakpoints is true then step temporarily disables
2581-
* pending breakpoints so we can safely perform the step. */
2582-
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2583-
false /* callbacks are not called */) != ERROR_OK)
2584-
return ERROR_FAIL;
2650+
* pending breakpoints so we can safely perform the step.
2651+
*
2652+
* Two cases where single step is needed before resuming:
2653+
* 1. ebreak used in software breakpoint;
2654+
* 2. a trigger that is taken just before the instruction that triggered it is retired.
2655+
*/
2656+
if (target->debug_reason == DBG_REASON_BREAKPOINT
2657+
|| (target->debug_reason == DBG_REASON_WATCHPOINT
2658+
&& r->need_single_step)) {
2659+
if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints,
2660+
false /* callbacks are not called */) != ERROR_OK)
2661+
return ERROR_FAIL;
2662+
}
25852663
}
25862664

25872665
if (r->get_hart_state) {
@@ -5848,6 +5926,19 @@ int riscv_enumerate_triggers(struct target *target)
58485926
return ERROR_OK;
58495927
}
58505928

5929+
/* Obtaining tinfo.version value once.
5930+
* No need to enumerate per-trigger.
5931+
* See https://github.com/riscv/riscv-debug-spec/pull/1081.
5932+
*/
5933+
riscv_reg_t tinfo;
5934+
if (riscv_reg_get(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) {
5935+
r->tinfo_version = get_field(tinfo, CSR_TINFO_VERSION);
5936+
LOG_TARGET_DEBUG(target, "Trigger tinfo.version = %d.", r->tinfo_version);
5937+
} else {
5938+
r->tinfo_version = RISCV_TINFO_VERSION_UNKNOWN;
5939+
LOG_TARGET_DEBUG(target, "Trigger tinfo.version is unknown.");
5940+
}
5941+
58515942
unsigned int t = 0;
58525943
for (; t < ARRAY_SIZE(r->trigger_tinfo); ++t) {
58535944
result = check_if_trigger_exists(target, t);

src/target/riscv/riscv.h

+12
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ typedef struct {
123123
} range_list_t;
124124

125125
#define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1)
126+
#define RISCV_TINFO_VERSION_UNKNOWN (-1)
126127

127128
struct reg_name_table {
128129
unsigned int num_entries;
@@ -163,6 +164,17 @@ struct riscv_info {
163164
/* record the tinfo of each trigger */
164165
unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS];
165166

167+
/* Version of the implemented Sdtrig extension */
168+
int tinfo_version;
169+
170+
/* Record if single-step is needed prior to resuming
171+
* from a software breakpoint or trigger.
172+
* Single-step is needed if the instruction that
173+
* caused the halt was not retired. That is,
174+
* when we halted "before" that instruction.
175+
*/
176+
bool need_single_step;
177+
166178
/* For each physical trigger contains:
167179
* -1: the hwbp is available
168180
* -4: The trigger is used by the itrigger command

0 commit comments

Comments
 (0)