@@ -1863,6 +1863,7 @@ def test(self):
18631863 self .gdb .p ("$pc=_start" )
18641864
18651865 self .exit ()
1866+
18661867class 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+
19532014class FreeRtosTest (GdbTest ):
19542015 def early_applicable (self ):
19552016 return self .target .freertos_binary
0 commit comments