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:
@@ -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",
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user