SBThread::StepInstruction shouldn't discard other plans (#97493)

This was just a typo, none of the external execution control functions
should discard other plans. In particular, it means if you stop in a
hand-called function and step an instruction, the function call thread
plan gets unshipped, popping all the function call frames.

I also added a test that asserts the correct behavior. I tested all the
stepping operations even though only StepInstruction was wrong.
This commit is contained in:
jimingham
2024-07-03 10:45:20 -07:00
committed by GitHub
parent 77d131eddb
commit 845dee36ba
3 changed files with 62 additions and 1 deletions

View File

@@ -52,6 +52,11 @@ class ThreadAPITestCase(TestBase):
self.build()
self.validate_negative_indexing()
def test_StepInstruction(self):
"""Test that StepInstruction preserves the plan stack."""
self.build()
self.step_instruction_in_called_function()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
@@ -303,3 +308,49 @@ class ThreadAPITestCase(TestBase):
neg_range = range(thread.num_frames, 0, -1)
for pos, neg in zip(pos_range, neg_range):
self.assertEqual(thread.frame[pos].idx, thread.frame[-neg].idx)
def step_instruction_in_called_function(self):
main_file_spec = lldb.SBFileSpec("main.cpp")
target, process, thread, bkpt = lldbutil.run_to_source_breakpoint(
self, "Set break point at this line", main_file_spec
)
options = lldb.SBExpressionOptions()
options.SetIgnoreBreakpoints(False)
call_me_bkpt = target.BreakpointCreateBySourceRegex(
"Set a breakpoint in call_me", main_file_spec
)
self.assertGreater(
call_me_bkpt.GetNumLocations(), 0, "Got at least one location in call_me"
)
# Now run the expression, this will fail because we stopped at a breakpoint:
self.runCmd("expr -i 0 -- call_me(true)", check=False)
# Now we should be stopped in call_me:
self.assertEqual(
thread.frames[0].name, "call_me(bool)", "Stopped in call_me(bool)"
)
# Now do a various API steps. These should not cause the expression context to get unshipped:
thread.StepInstruction(False)
self.assertEqual(
thread.frames[0].name,
"call_me(bool)",
"Still in call_me(bool) after StepInstruction",
)
thread.StepInstruction(True)
self.assertEqual(
thread.frames[0].name,
"call_me(bool)",
"Still in call_me(bool) after NextInstruction",
)
thread.StepInto()
self.assertEqual(
thread.frames[0].name,
"call_me(bool)",
"Still in call_me(bool) after StepInto",
)
thread.StepOver(False)
self.assertEqual(
thread.frames[0].name,
"call_me(bool)",
"Still in call_me(bool) after StepOver",
)

View File

@@ -5,8 +5,18 @@
char my_char = 'u';
int my_int = 0;
void
call_me(bool should_spin) {
int counter = 0;
if (should_spin) {
while (1)
counter++; // Set a breakpoint in call_me
}
}
int main (int argc, char const *argv[])
{
call_me(false);
for (int i = 0; i < 3; ++i) {
printf("my_char='%c'\n", my_char);
++my_char;