From 33663712bd8943fb360f4f5b730949ca11f3fc17 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 18 Jul 2023 09:41:35 -0700 Subject: debug: Add UnavailableHaltedTest Test behavior when a hart becomes unavailable while halted. --- debug/gdbserver.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) 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 -- cgit v1.1