[Lldb-commits] [lldb] SBThread::StepInstruction shouldn't discard other plans (PR #97493)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Jul 3 10:44:51 PDT 2024
https://github.com/jimingham updated https://github.com/llvm/llvm-project/pull/97493
>From 3fba16eaee25b1d63907640b79019309e9c019a7 Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Tue, 2 Jul 2024 16:42:00 -0700
Subject: [PATCH 1/2] SBThread::StepInstruction shouldn't discard other plans
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.
---
lldb/source/API/SBThread.cpp | 2 +-
.../API/python_api/thread/TestThreadAPI.py | 28 +++++++++++++++++++
lldb/test/API/python_api/thread/main.cpp | 10 +++++++
3 files changed, 39 insertions(+), 1 deletion(-)
diff --git a/lldb/source/API/SBThread.cpp b/lldb/source/API/SBThread.cpp
index ac3e2cd25daa9..53643362421d4 100644
--- a/lldb/source/API/SBThread.cpp
+++ b/lldb/source/API/SBThread.cpp
@@ -722,7 +722,7 @@ void SBThread::StepInstruction(bool step_over, SBError &error) {
Thread *thread = exe_ctx.GetThreadPtr();
Status new_plan_status;
ThreadPlanSP new_plan_sp(thread->QueueThreadPlanForStepSingleInstruction(
- step_over, true, true, new_plan_status));
+ step_over, false, true, new_plan_status));
if (new_plan_status.Success())
error = ResumeNewPlan(exe_ctx, new_plan_sp.get());
diff --git a/lldb/test/API/python_api/thread/TestThreadAPI.py b/lldb/test/API/python_api/thread/TestThreadAPI.py
index 0fe91c88c325e..05ae3c8d36cf0 100644
--- a/lldb/test/API/python_api/thread/TestThreadAPI.py
+++ b/lldb/test/API/python_api/thread/TestThreadAPI.py
@@ -52,6 +52,11 @@ def test_negative_indexing(self):
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,26 @@ def validate_negative_indexing(self):
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")
diff --git a/lldb/test/API/python_api/thread/main.cpp b/lldb/test/API/python_api/thread/main.cpp
index dde740a1b6bf6..d4b0ad2372c3d 100644
--- a/lldb/test/API/python_api/thread/main.cpp
+++ b/lldb/test/API/python_api/thread/main.cpp
@@ -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;
>From 55c7e741dcedfce7473e5990570cc4340fde650e Mon Sep 17 00:00:00 2001
From: Jim Ingham <jingham at apple.com>
Date: Wed, 3 Jul 2024 10:44:27 -0700
Subject: [PATCH 2/2] Make it uglier
---
.../API/python_api/thread/TestThreadAPI.py | 43 ++++++++++++++-----
1 file changed, 33 insertions(+), 10 deletions(-)
diff --git a/lldb/test/API/python_api/thread/TestThreadAPI.py b/lldb/test/API/python_api/thread/TestThreadAPI.py
index 05ae3c8d36cf0..d5fc77532d859 100644
--- a/lldb/test/API/python_api/thread/TestThreadAPI.py
+++ b/lldb/test/API/python_api/thread/TestThreadAPI.py
@@ -311,23 +311,46 @@ def validate_negative_indexing(self):
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)
+ 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")
+ 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)
+ 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)")
+ 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")
+ 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")
+ 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")
+ 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")
+ self.assertEqual(
+ thread.frames[0].name,
+ "call_me(bool)",
+ "Still in call_me(bool) after StepOver",
+ )
More information about the lldb-commits
mailing list