Skip to content

Commit

Permalink
Merge pull request riscv-software-src#581 from en-sc/en-sc/reserve-tr…
Browse files Browse the repository at this point in the history
…igger-fix-propper

[debug] Reserve triggers propperly in HwbpManual
  • Loading branch information
en-sc authored Sep 6, 2024
2 parents 3c5b5e8 + 1839696 commit 51de008
Showing 1 changed file with 59 additions and 21 deletions.
80 changes: 59 additions & 21 deletions debug/gdbserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,47 @@ def early_applicable(self):
return self.target.support_manual_hwbp and \
self.hart.instruction_hardware_breakpoint_count >= 1

# TODO: This can be removed once
# https://github.com/riscv-collab/riscv-openocd/pull/1111
# is merged.
def check_reserve_trigger_support(self):
not_supp_msg = "RESERVE_TRIGGER_NOT_SUPPORTED"
if not_supp_msg in self.gdb.command(
"monitor if [catch {riscv reserve_trigger 0 on} e] {echo " +
not_supp_msg + "}").splitlines():
raise TestNotApplicable

def set_manual_trigger(self, tdata1, tdata2):
for tselect in itertools.count(0):
self.gdb.p(f"$tselect={tselect}")
if self.gdb.p("$tselect") != tselect:
raise TestNotApplicable

self.gdb.command(
f"monitor riscv reserve_trigger {tselect} on")

# Need to disable the trigger before writing tdata2
self.gdb.p("$tdata1=0")
# Need to write a valid value to tdata2 before writing tdata1
self.gdb.p(f"$tdata2=0x{tdata2:x}")
self.gdb.p(f"$tdata1=0x{tdata1:x}")

tdata2_rb = self.gdb.p("$tdata2")
tdata1_rb = self.gdb.p("$tdata1")
if tdata1_rb == tdata1 and tdata2_rb == tdata2:
return tselect

type_rb = tdata1_rb & MCONTROL_TYPE(self.hart.xlen)
type_none = set_field(0, MCONTROL_TYPE(self.hart.xlen),
MCONTROL_TYPE_NONE)
if type_rb == type_none:
raise TestNotApplicable

self.gdb.p("$tdata1=0")
self.gdb.command(
f"monitor riscv reserve_trigger {tselect} off")
assert False

def test(self):
if not self.hart.honors_tdata1_hmode:
# Run to main before setting the breakpoint, because startup code
Expand All @@ -684,6 +725,12 @@ def test(self):
self.gdb.c()

self.gdb.command("delete")

# TODO: This can be removed once
# https://github.com/riscv-collab/riscv-openocd/pull/1111
# is merged.
self.check_reserve_trigger_support()

#self.gdb.hbreak("rot13")
tdata1 = MCONTROL_DMODE(self.hart.xlen)
tdata1 = set_field(tdata1, MCONTROL_TYPE(self.hart.xlen),
Expand All @@ -692,26 +739,9 @@ def test(self):
tdata1 = set_field(tdata1, MCONTROL_MATCH, MCONTROL_MATCH_EQUAL)
tdata1 |= MCONTROL_M | MCONTROL_S | MCONTROL_U | MCONTROL_EXECUTE

tselect = 0
while True:
self.gdb.p(f"$tselect={tselect}")
value = self.gdb.p("$tselect")
if value != tselect:
raise TestNotApplicable
# Need to disable the trigger before writing tdata2
self.gdb.p("$tdata1=0")
# Need to write a valid value to tdata2 before writing tdata1
self.gdb.p("$tdata2=&rot13")
self.gdb.p(f"$tdata1=0x{tdata1:x}")
value = self.gdb.p("$tdata1")
if value == tdata1:
break
if value & MCONTROL_TYPE(self.hart.xlen) == MCONTROL_TYPE_NONE:
raise TestNotApplicable
self.gdb.p("$tdata1=0")
tselect += 1
tdata2 = self.gdb.p("&rot13")

self.gdb.command(f"monitor riscv reserve_trigger {tselect} on")
tselect = self.set_manual_trigger(tdata1, tdata2)

# The breakpoint should be hit exactly 2 times.
for _ in range(2):
Expand All @@ -728,14 +758,22 @@ def test(self):
self.gdb.c()
before = self.gdb.p("$pc")
assertEqual(before, self.gdb.p("&crc32a"))

self.gdb.stepi()
after = self.gdb.p("$pc")
assertNotEqual(before, after)
assertEqual(before, self.gdb.p("$pc"),
"OpenOCD shouldn't disable a reserved trigger.")

# Remove the manual HW breakpoint.
assertEqual(tselect, self.gdb.p("$tselect"))
self.gdb.p("$tdata1=0")

self.gdb.stepi()
assertNotEqual(before, self.gdb.p("$pc"),
"OpenOCD should be able to step from a removed BP.")

self.gdb.command(
f"monitor riscv reserve_trigger {tselect} off")

self.gdb.b("_exit")
self.exit()

Expand Down

0 comments on commit 51de008

Please sign in to comment.