[Lldb-commits] [lldb] SBThread::StepInstruction shouldn't discard other plans (PR #97493)

via lldb-commits lldb-commits at lists.llvm.org
Tue Jul 2 17:16:32 PDT 2024


https://github.com/jimingham created https://github.com/llvm/llvm-project/pull/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.

>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] 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;



More information about the lldb-commits mailing list