https://github.com/JDevlieghere created 
https://github.com/llvm/llvm-project/pull/213397

Only UnwindLLDB honored target.process.thread.max-backtrace-depth, so 
UnwindWasm reported every frame the stub sent and a stack that recursed without 
end was walked to its end.

Bound the frame count by the depth on every query rather than dropping the 
frames that exceed it. A Wasm call stack arrives whole on the first query, so a 
depth lowered after that has to still apply, which is when a user reaches for 
it. The synthetic call frame addresses stay derived from the whole stack, so 
the order of the frames does not depend on the depth.

>From 07700f613de448ec6b56f366c6aa5f0c9aac9c9a Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Fri, 31 Jul 2026 18:41:30 -0700
Subject: [PATCH] [lldb] Bound a WebAssembly backtrace by the target's maximum
 depth

Only UnwindLLDB honored target.process.thread.max-backtrace-depth, so
UnwindWasm reported every frame the stub sent and a stack that recursed
without end was walked to its end.

Bound the frame count by the depth on every query rather than dropping
the frames that exceed it. A Wasm call stack arrives whole on the first
query, so a depth lowered after that has to still apply, which is when
a user reaches for it. The synthetic call frame addresses stay derived
from the whole stack, so the order of the frames does not depend on the
depth.
---
 .../Plugins/Process/wasm/UnwindWasm.cpp       | 15 +++++--
 lldb/source/Plugins/Process/wasm/UnwindWasm.h |  4 ++
 .../gdb_remote_client/TestWasm.py             | 39 +++++++++++++++++++
 3 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp 
b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
index 39b784315a9c1..df3b146efca14 100644
--- a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
@@ -41,7 +41,7 @@ 
UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
 
 uint32_t UnwindWasm::DoGetFrameCount() {
   if (m_unwind_complete)
-    return m_frames.size();
+    return GetVisibleFrameCount();
 
   m_unwind_complete = true;
   m_frames.clear();
@@ -57,7 +57,16 @@ uint32_t UnwindWasm::DoGetFrameCount() {
   }
 
   m_frames = *call_stack_pcs;
-  return m_frames.size();
+  return GetVisibleFrameCount();
+}
+
+uint32_t UnwindWasm::GetVisibleFrameCount() {
+  // A backtrace goes no deeper than the target asks for, which is what bounds
+  // the walk of a stack that recurses without end. The depth bounds what a
+  // caller is told rather than what is kept, because it can be raised after a
+  // stack has been fetched.
+  return std::min<uint64_t>(m_frames.size(),
+                            GetThread().GetMaxBacktraceDepth());
 }
 
 bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
@@ -66,7 +75,7 @@ bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, 
lldb::addr_t &cfa,
   if (m_frames.size() == 0)
     DoGetFrameCount();
 
-  if (frame_idx >= m_frames.size())
+  if (frame_idx >= GetVisibleFrameCount())
     return false;
 
   behaves_like_zeroth_frame = (frame_idx == 0);
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h 
b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
index ff5e06d23d960..03c7f9643f1f4 100644
--- a/lldb/source/Plugins/Process/wasm/UnwindWasm.h
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
@@ -38,6 +38,10 @@ class UnwindWasm : public lldb_private::Unwind {
   DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
 
 private:
+  /// The number of fetched frames a caller is told about, which the target's
+  /// maximum backtrace depth bounds.
+  uint32_t GetVisibleFrameCount();
+
   std::vector<lldb::addr_t> m_frames;
   bool m_unwind_complete = false;
 
diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py 
b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
index 861691f5b3ddc..114ddd7adce5a 100644
--- a/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
+++ b/lldb/test/API/functionalities/gdb_remote_client/TestWasm.py
@@ -406,6 +406,45 @@ def test_simple_wasm_debugging_session(self):
         self.assertTrue(b.IsValid())
         self.assertEqual(b.GetValueAsUnsigned(), 2)
 
+    @skipIfAsan
+    @skipIfXmlSupportMissing
+    def test_max_backtrace_depth(self):
+        """Test that a Wasm backtrace stops at the depth the target sets, so
+        that a stack recursing without end is not walked to its end."""
+
+        yaml_path = "simple.yaml"
+        yaml_base, _ = os.path.splitext(yaml_path)
+        obj_path = self.getBuildArtifact(yaml_base)
+        self.yaml2obj(yaml_path, obj_path)
+
+        call_stacks = [
+            WasmCallStack(
+                [WasmStackFrame(0x019C), WasmStackFrame(0x01E5), 
WasmStackFrame(0x01FE)]
+            ),
+        ]
+        self.server.responder = MyResponder(obj_path, "test_wasm", call_stacks)
+
+        target = self.dbg.CreateTarget("")
+        process = self.connect(target, "wasm")
+        lldbutil.expect_state_changes(
+            self, self.dbg.GetListener(), process, [lldb.eStateStopped]
+        )
+
+        thread = process.GetThreadAtIndex(0)
+        self.assertTrue(thread.IsValid())
+        self.assertTrue(thread.GetFrameAtIndex(0).IsValid())
+
+        # A depth set after a stop still applies to the frames a backtrace has
+        # not reported yet, which is when a user lowers it.
+        self.runCmd("settings set target.process.thread.max-backtrace-depth 2")
+
+        # The stub reported three frames, and the innermost two are the ones
+        # kept.
+        self.assertEqual(2, thread.GetNumFrames())
+        self.assertEqual(thread.GetFrameAtIndex(0).GetPC(), LOAD_ADDRESS | 
0x019C)
+        self.assertEqual(thread.GetFrameAtIndex(1).GetPC(), LOAD_ADDRESS | 
0x01E5)
+        self.assertFalse(thread.GetFrameAtIndex(2).IsValid())
+
     @skipIfAsan
     @skipIfXmlSupportMissing
     def test_read_global(self):

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

Reply via email to