aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdebug/gdbserver.py61
1 files changed, 61 insertions, 0 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py
index 3a6f932..cb3ab43 100755
--- a/debug/gdbserver.py
+++ b/debug/gdbserver.py
@@ -1863,6 +1863,7 @@ class UnavailableMultiTest(GdbTest):
self.gdb.p("$pc=_start")
self.exit()
+
class CeaseStepiTest(ProgramTest):
"""Test that we work correctly when the hart we're debugging ceases to
respond."""
@@ -1950,6 +1951,66 @@ class UnavailableCycleTest(ProgramTest):
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