Skip to content

Commit 7453fe9

Browse files
authored
Merge pull request #515 from riscv-software-src/unavailable_halted2
debug: Add UnavailableHaltedTest
2 parents c36c814 + 3366371 commit 7453fe9

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

debug/gdbserver.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,6 +1863,7 @@ def test(self):
18631863
self.gdb.p("$pc=_start")
18641864

18651865
self.exit()
1866+
18661867
class CeaseStepiTest(ProgramTest):
18671868
"""Test that we work correctly when the hart we're debugging ceases to
18681869
respond."""
@@ -1950,6 +1951,66 @@ def test(self):
19501951
self.gdb.interrupt()
19511952
self.gdb.p("$pc")
19521953

1954+
class UnavailableHaltedTest(ProgramTest):
1955+
"""Test behavior when the current hart becomes unavailable while halted."""
1956+
def early_applicable(self):
1957+
return self.target.support_unavailable_control
1958+
1959+
def test_resume(self, c_expect=None):
1960+
# Confirm things don't completely fall apart on `c`
1961+
self.gdb.c(wait=False)
1962+
if c_expect:
1963+
self.gdb.expect(c_expect)
1964+
else:
1965+
time.sleep(1)
1966+
1967+
# Now send a DMI command through OpenOCD to make the hart available
1968+
# again.
1969+
self.server.set_available(self.target.harts)
1970+
1971+
# The hart will show up as halted. That's just how spike behaves when we
1972+
# make a hart unavailable while it's halted.
1973+
1974+
self.gdb.expect("became available")
1975+
self.gdb.p("$minstret")
1976+
1977+
def test(self):
1978+
self.gdb.b("main")
1979+
output = self.gdb.c()
1980+
assertIn("Breakpoint", output)
1981+
assertIn("main", output)
1982+
1983+
self.server.set_available(
1984+
[h for h in self.target.harts if h != self.hart])
1985+
self.gdb.command(f"# disabled hart {self.hart.id}")
1986+
# gdb won't show that the hart became unavailable, because it thinks
1987+
# nothing can changed on a halted Linux thread.
1988+
try:
1989+
# We can't try this with something reasonable like $pc, because gdb
1990+
# has cached it, and it assumes the target can't change while it's
1991+
# halted.
1992+
self.gdb.p("$minstret")
1993+
assert False, ("Registers shouldn't be accessible when the hart is "
1994+
"unavailable.")
1995+
except testlib.CouldNotFetch:
1996+
pass
1997+
1998+
# There's a breakpoint set, so gdb will single step. You can't single
1999+
# step an unavailable target, so gdb should get a message to that
2000+
# effect.
2001+
self.test_resume(c_expect="unavailable")
2002+
2003+
# Delete breakpoints
2004+
self.gdb.command("delete")
2005+
self.server.set_available(
2006+
[h for h in self.target.harts if h != self.hart])
2007+
2008+
# Resume again. With breakpoints cleared, gdb will send vCont;c instead
2009+
# of step. There should be no error this time, since there is no
2010+
# observable difference between an unavailable thread and a running
2011+
# thread.
2012+
self.test_resume()
2013+
19532014
class FreeRtosTest(GdbTest):
19542015
def early_applicable(self):
19552016
return self.target.freertos_binary

0 commit comments

Comments
 (0)