Skip to content

Commit

Permalink
debug: Add UnavailableHaltedTest
Browse files Browse the repository at this point in the history
Test behavior when a hart becomes unavailable while halted.
  • Loading branch information
timsifive committed Oct 13, 2023
1 parent c36c814 commit 3366371
Showing 1 changed file with 61 additions and 0 deletions.
61 changes: 61 additions & 0 deletions debug/gdbserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -1863,6 +1863,7 @@ def test(self):
self.gdb.p("$pc=_start")

self.exit()

class CeaseStepiTest(ProgramTest):
"""Test that we work correctly when the hart we're debugging ceases to
respond."""
Expand Down Expand Up @@ -1950,6 +1951,66 @@ def test(self):
self.gdb.interrupt()
self.gdb.p("$pc")

class UnavailableHaltedTest(ProgramTest):
"""Test behavior when the current hart becomes unavailable while halted."""
def early_applicable(self):
return self.target.support_unavailable_control

def test_resume(self, c_expect=None):
# Confirm things don't completely fall apart on `c`
self.gdb.c(wait=False)
if c_expect:
self.gdb.expect(c_expect)
else:
time.sleep(1)

# Now send a DMI command through OpenOCD to make the hart available
# again.
self.server.set_available(self.target.harts)

# The hart will show up as halted. That's just how spike behaves when we
# make a hart unavailable while it's halted.

self.gdb.expect("became available")
self.gdb.p("$minstret")

def test(self):
self.gdb.b("main")
output = self.gdb.c()
assertIn("Breakpoint", output)
assertIn("main", output)

self.server.set_available(
[h for h in self.target.harts if h != self.hart])
self.gdb.command(f"# disabled hart {self.hart.id}")
# gdb won't show that the hart became unavailable, because it thinks
# nothing can changed on a halted Linux thread.
try:
# We can't try this with something reasonable like $pc, because gdb
# has cached it, and it assumes the target can't change while it's
# halted.
self.gdb.p("$minstret")
assert False, ("Registers shouldn't be accessible when the hart is "
"unavailable.")
except testlib.CouldNotFetch:
pass

# There's a breakpoint set, so gdb will single step. You can't single
# step an unavailable target, so gdb should get a message to that
# effect.
self.test_resume(c_expect="unavailable")

# Delete breakpoints
self.gdb.command("delete")
self.server.set_available(
[h for h in self.target.harts if h != self.hart])

# Resume again. With breakpoints cleared, gdb will send vCont;c instead
# of step. There should be no error this time, since there is no
# observable difference between an unavailable thread and a running
# thread.
self.test_resume()

class FreeRtosTest(GdbTest):
def early_applicable(self):
return self.target.freertos_binary
Expand Down

0 comments on commit 3366371

Please sign in to comment.