[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