https://github.com/charles-zablit updated 
https://github.com/llvm/llvm-project/pull/210076

>From 59f6e466cd01831e9ce2bafb5db427eba8a1c9b8 Mon Sep 17 00:00:00 2001
From: Charles Zablit <[email protected]>
Date: Thu, 16 Jul 2026 15:43:10 +0100
Subject: [PATCH 1/2] [lldb][Windows] Fix x86_64 default unwind plan; enable
 trampoline_stepping

---
 .../Plugins/ABI/X86/ABIWindows_x86_64.cpp     |  10 +-
 .../API/lang/c/trampoline_stepping/Makefile   |   3 +
 .../TestTrampolineStepping.py                 | 100 ++++++++++++++++++
 .../API/lang/c/trampoline_stepping/main.c     |  52 +++++++++
 4 files changed, 157 insertions(+), 8 deletions(-)
 create mode 100644 lldb/test/API/lang/c/trampoline_stepping/Makefile
 create mode 100644 
lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py
 create mode 100644 lldb/test/API/lang/c/trampoline_stepping/main.c

diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp 
b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
index 079b22a307602..be3c83880bd60 100644
--- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
+++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.cpp
@@ -751,21 +751,15 @@ UnwindPlanSP 
ABIWindows_x86_64::CreateFunctionEntryUnwindPlan() {
 
 // Windows-x86_64 doesn't use %rbp
 // No available Unwind information for Windows-x86_64 (section .pdata)
-// Let's use SysV-x86_64 one for now
 UnwindPlanSP ABIWindows_x86_64::CreateDefaultUnwindPlan() {
-  uint32_t fp_reg_num = dwarf_rbp;
   uint32_t sp_reg_num = dwarf_rsp;
   uint32_t pc_reg_num = dwarf_rip;
 
   UnwindPlan::Row row;
-
-  const int32_t ptr_size = 8;
-  row.GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size);
   row.SetOffset(0);
   row.SetUnspecifiedRegistersAreUndefined(true);
-
-  row.SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
-  row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+  row.GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 8);
+  row.SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
   row.SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
 
   auto plan_sp = std::make_shared<UnwindPlan>(eRegisterKindDWARF);
diff --git a/lldb/test/API/lang/c/trampoline_stepping/Makefile 
b/lldb/test/API/lang/c/trampoline_stepping/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/lang/c/trampoline_stepping/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py 
b/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py
new file mode 100644
index 0000000000000..bbf1dc8cb7fea
--- /dev/null
+++ b/lldb/test/API/lang/c/trampoline_stepping/TestTrampolineStepping.py
@@ -0,0 +1,100 @@
+"""Test that stepping in/out of trampolines works as expected."""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestTrampoline(TestBase):
+    def setup(self, bkpt_str):
+        self.build()
+
+        _, _, thread, _ = lldbutil.run_to_source_breakpoint(
+            self, bkpt_str, lldb.SBFileSpec("main.c")
+        )
+        return thread
+
+    def test_direct_call(self):
+        thread = self.setup("Break here for direct")
+
+        # Sanity check that we start out in the correct function.
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("direct_trampoline_call", name)
+
+        # Check that stepping in will take us directly to the trampoline 
target.
+        thread.StepInto()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("foo", name)
+
+        # Check that stepping out takes us back to the trampoline caller.
+        thread.StepOut()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("direct_trampoline_call", name)
+
+        # Check that stepping over the end of the trampoline target
+        # takes us back to the trampoline caller.
+        thread.StepInto()
+        thread.StepOver()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("direct_trampoline_call", name)
+
+    def test_chained_call(self):
+        thread = self.setup("Break here for chained")
+
+        # Sanity check that we start out in the correct function.
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("chained_trampoline_call", name)
+
+        # Check that stepping in will take us directly to the trampoline 
target.
+        thread.StepInto()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("foo", name)
+
+        # Check that stepping out takes us back to the trampoline caller.
+        thread.StepOut()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("chained_trampoline_call", name)
+
+        # Check that stepping over the end of the trampoline target
+        # takes us back to the trampoline caller.
+        thread.StepInto()
+        thread.StepOver()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("chained_trampoline_call", name)
+
+    def test_trampoline_after_nodebug(self):
+        thread = self.setup("Break here for nodebug then trampoline")
+
+        # Sanity check that we start out in the correct function.
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("trampoline_after_nodebug", name)
+
+        # Check that stepping in will take us directly to the trampoline 
target.
+        thread.StepInto()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("foo", name)
+
+        # Check that stepping out takes us back to the trampoline caller.
+        thread.StepOut()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("trampoline_after_nodebug", name)
+
+        # Check that stepping over the end of the trampoline target
+        # takes us back to the trampoline caller.
+        thread.StepInto()
+        thread.StepOver()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("trampoline_after_nodebug", name)
+
+    def test_unused_target(self):
+        thread = self.setup("Break here for unused")
+
+        # Sanity check that we start out in the correct function.
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("unused_target", name)
+
+        # Check that stepping into a trampoline that doesn't call its target
+        # jumps back to its caller.
+        thread.StepInto()
+        name = thread.frames[0].GetFunctionName()
+        self.assertIn("unused_target", name)
diff --git a/lldb/test/API/lang/c/trampoline_stepping/main.c 
b/lldb/test/API/lang/c/trampoline_stepping/main.c
new file mode 100644
index 0000000000000..cb98be00ca1f6
--- /dev/null
+++ b/lldb/test/API/lang/c/trampoline_stepping/main.c
@@ -0,0 +1,52 @@
+void foo(void) {}
+
+__attribute__((transparent_stepping))
+void bar(void) {
+  foo();
+}
+
+__attribute__((transparent_stepping))
+void baz(void) {
+  bar();
+}
+
+__attribute__((nodebug))
+void nodebug(void) {}
+
+__attribute__((transparent_stepping))
+void nodebug_then_trampoline(void) {
+  nodebug();
+  baz();
+}
+
+__attribute__((transparent_stepping))
+void doesnt_call_trampoline(void) {}
+
+void direct_trampoline_call(void) {
+  bar(); // Break here for direct 
+  bar();
+}
+
+void chained_trampoline_call(void) {
+  baz(); // Break here for chained
+  baz();
+}
+
+void trampoline_after_nodebug(void) {
+  nodebug_then_trampoline(); // Break here for nodebug then trampoline
+  nodebug_then_trampoline();
+}
+
+void unused_target(void) {
+  doesnt_call_trampoline(); // Break here for unused
+}
+
+
+int main(void) {
+  direct_trampoline_call();
+  chained_trampoline_call();
+  trampoline_after_nodebug();
+  unused_target();
+  return 0;
+}
+

>From a1d435a5f9accefbb2a5f969e153b07cf50ef3b0 Mon Sep 17 00:00:00 2001
From: Charles Zablit <[email protected]>
Date: Thu, 16 Jul 2026 15:53:58 +0100
Subject: [PATCH 2/2] fixup! [lldb][Windows] Fix x86_64 default unwind plan;
 enable trampoline_stepping

---
 .../API/lang/c/trampoline_stepping/main.c     | 23 +++++--------------
 1 file changed, 6 insertions(+), 17 deletions(-)

diff --git a/lldb/test/API/lang/c/trampoline_stepping/main.c 
b/lldb/test/API/lang/c/trampoline_stepping/main.c
index cb98be00ca1f6..25f41e2bad0ad 100644
--- a/lldb/test/API/lang/c/trampoline_stepping/main.c
+++ b/lldb/test/API/lang/c/trampoline_stepping/main.c
@@ -1,29 +1,20 @@
 void foo(void) {}
 
-__attribute__((transparent_stepping))
-void bar(void) {
-  foo();
-}
+__attribute__((transparent_stepping)) void bar(void) { foo(); }
 
-__attribute__((transparent_stepping))
-void baz(void) {
-  bar();
-}
+__attribute__((transparent_stepping)) void baz(void) { bar(); }
 
-__attribute__((nodebug))
-void nodebug(void) {}
+__attribute__((nodebug)) void nodebug(void) {}
 
-__attribute__((transparent_stepping))
-void nodebug_then_trampoline(void) {
+__attribute__((transparent_stepping)) void nodebug_then_trampoline(void) {
   nodebug();
   baz();
 }
 
-__attribute__((transparent_stepping))
-void doesnt_call_trampoline(void) {}
+__attribute__((transparent_stepping)) void doesnt_call_trampoline(void) {}
 
 void direct_trampoline_call(void) {
-  bar(); // Break here for direct 
+  bar(); // Break here for direct
   bar();
 }
 
@@ -41,7 +32,6 @@ void unused_target(void) {
   doesnt_call_trampoline(); // Break here for unused
 }
 
-
 int main(void) {
   direct_trampoline_call();
   chained_trampoline_call();
@@ -49,4 +39,3 @@ int main(void) {
   unused_target();
   return 0;
 }
-

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to