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

The debug adapter protocol supports an option to provide formatting information 
for a stack frames as part of the StackTrace request. lldb-dap incorrectly 
advertises it supports this, but until this PR that support wasn't actually 
implemented.

Fixes #137057

>From 21681616560eceb9b46ef4c370817099fe149701 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jo...@devlieghere.com>
Date: Wed, 23 Apr 2025 20:05:19 -0700
Subject: [PATCH] [lldb-dap] Support StackFrameFormat

The debug adapter protocol supports an option to provide formatting
information for a stack frames as part of the StackTrace request.
lldb-dap incorrectly advertises it supports this, but until this PR that
support wasn't actually implemented.

Fixes #137057
---
 .../test/tools/lldb-dap/dap_server.py         |  4 +-
 .../test/tools/lldb-dap/lldbdap_testcase.py   | 18 ++++++--
 .../lldb-dap/stackTrace/TestDAP_stackTrace.py | 30 +++++++++++++
 .../Handler/StackTraceRequestHandler.cpp      | 42 ++++++++++++++++---
 4 files changed, 84 insertions(+), 10 deletions(-)

diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
index a9915ba2f6de6..dadf6b1f8774c 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py
@@ -1046,7 +1046,7 @@ def request_modules(self):
         return self.send_recv({"command": "modules", "type": "request"})
 
     def request_stackTrace(
-        self, threadId=None, startFrame=None, levels=None, dump=False
+        self, threadId=None, startFrame=None, levels=None, format=None, 
dump=False
     ):
         if threadId is None:
             threadId = self.get_thread_id()
@@ -1055,6 +1055,8 @@ def request_stackTrace(
             args_dict["startFrame"] = startFrame
         if levels is not None:
             args_dict["levels"] = levels
+        if format is not None:
+            args_dict["format"] = format
         command_dict = {
             "command": "stackTrace",
             "type": "request",
diff --git 
a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py 
b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
index 70b04b051e0ec..b5b55b336d535 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
@@ -161,10 +161,14 @@ def get_dict_value(self, d, key_path):
         return value
 
     def get_stackFrames_and_totalFramesCount(
-        self, threadId=None, startFrame=None, levels=None, dump=False
+        self, threadId=None, startFrame=None, levels=None, format=None, 
dump=False
     ):
         response = self.dap_server.request_stackTrace(
-            threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
+            threadId=threadId,
+            startFrame=startFrame,
+            levels=levels,
+            format=format,
+            dump=dump,
         )
         if response:
             stackFrames = self.get_dict_value(response, ["body", 
"stackFrames"])
@@ -177,9 +181,15 @@ def get_stackFrames_and_totalFramesCount(
             return (stackFrames, totalFrames)
         return (None, 0)
 
-    def get_stackFrames(self, threadId=None, startFrame=None, levels=None, 
dump=False):
+    def get_stackFrames(
+        self, threadId=None, startFrame=None, levels=None, format=None, 
dump=False
+    ):
         (stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
-            threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
+            threadId=threadId,
+            startFrame=startFrame,
+            levels=levels,
+            format=format,
+            dump=dump,
         )
         return stackFrames
 
diff --git a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py 
b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
index 56ed1ebdf7ab4..713b5d841cfcd 100644
--- a/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
+++ b/lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py
@@ -217,3 +217,33 @@ def test_functionNameWithArgs(self):
         self.continue_to_next_stop()
         frame = self.get_stackFrames()[0]
         self.assertEqual(frame["name"], "recurse(x=1)")
+
+    @skipIfWindows
+    def test_StackFrameFormat(self):
+        """
+        Test the StackFrameFormat.
+        """
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program)
+        source = "main.c"
+
+        self.set_source_breakpoints(source, [line_number(source, "recurse 
end")])
+
+        self.continue_to_next_stop()
+        frame = self.get_stackFrames(format={"includeAll": True})[0]
+        self.assertEqual(frame["name"], "a.out main.c:6:5 recurse(x=1)")
+
+        frame = self.get_stackFrames(format={"parameters": True})[0]
+        self.assertEqual(frame["name"], "recurse(x=1)")
+
+        frame = self.get_stackFrames(format={"parameterNames": True})[0]
+        self.assertEqual(frame["name"], "recurse(x=1)")
+
+        frame = self.get_stackFrames(format={"parameterValues": True})[0]
+        self.assertEqual(frame["name"], "recurse(x=1)")
+
+        frame = self.get_stackFrames(format={"parameters": False, "line": 
True})[0]
+        self.assertEqual(frame["name"], "main.c:6:5 recurse")
+
+        frame = self.get_stackFrames(format={"parameters": False, "module": 
True})[0]
+        self.assertEqual(frame["name"], "a.out recurse")
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index a58e3325af100..359237f1db0b4 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -49,6 +49,7 @@ static constexpr int StackPageSize = 20;
 //
 // s=3,l=3 = [th0->s3, label1, th1->s0]
 static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
+                            lldb::SBFormat &frame_format,
                             llvm::json::Array &stack_frames, int64_t &offset,
                             const int64_t start_frame, const int64_t levels) {
   bool reached_end_of_stack = false;
@@ -56,7 +57,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
        static_cast<int64_t>(stack_frames.size()) < levels; i++) {
     if (i == -1) {
       stack_frames.emplace_back(
-          CreateExtendedStackFrameLabel(thread, dap.frame_format));
+          CreateExtendedStackFrameLabel(thread, frame_format));
       continue;
     }
 
@@ -67,7 +68,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
       break;
     }
 
-    stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format));
+    stack_frames.emplace_back(CreateStackFrame(frame, frame_format));
   }
 
   if (dap.configuration.displayExtendedBacktrace && reached_end_of_stack) {
@@ -80,7 +81,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
         continue;
 
       reached_end_of_stack = FillStackFrames(
-          dap, backtrace, stack_frames, offset,
+          dap, backtrace, frame_format, stack_frames, offset,
           (start_frame - offset) > 0 ? start_frame - offset : -1, levels);
       if (static_cast<int64_t>(stack_frames.size()) >= levels)
         break;
@@ -178,14 +179,45 @@ void StackTraceRequestHandler::operator()(
   llvm::json::Array stack_frames;
   llvm::json::Object body;
 
+  lldb::SBFormat frame_format = dap.frame_format;
+
+  if (const auto *format = arguments->getObject("format")) {
+    const bool parameters = GetBoolean(format, "parameters").value_or(false);
+    const bool parameter_names =
+        GetBoolean(format, "parameterNames").value_or(false);
+    const bool parameter_values =
+        GetBoolean(format, "parameterValues").value_or(false);
+    const bool line = GetBoolean(format, "line").value_or(false);
+    const bool module = GetBoolean(format, "module").value_or(false);
+    const bool include_all = GetBoolean(format, "includeAll").value_or(false);
+
+    std::string format_str;
+    llvm::raw_string_ostream os(format_str);
+
+    if (include_all || module)
+      os << "{${module.file.basename} }";
+
+    if (include_all || line)
+      os << "{${line.file.basename}:${line.number}:${line.column} }";
+
+    if (include_all || parameters || parameter_names || parameter_values)
+      os << "{${function.name-with-args}}";
+    else
+      os << "{${function.name-without-args}}";
+
+    lldb::SBError error;
+    frame_format = lldb::SBFormat(format_str.c_str(), error);
+    assert(error.Success());
+  }
+
   if (thread.IsValid()) {
     const auto start_frame =
         GetInteger<uint64_t>(arguments, "startFrame").value_or(0);
     const auto levels = GetInteger<uint64_t>(arguments, "levels").value_or(0);
     int64_t offset = 0;
     bool reached_end_of_stack =
-        FillStackFrames(dap, thread, stack_frames, offset, start_frame,
-                        levels == 0 ? INT64_MAX : levels);
+        FillStackFrames(dap, thread, frame_format, stack_frames, offset,
+                        start_frame, levels == 0 ? INT64_MAX : levels);
     body.try_emplace("totalFrames",
                      start_frame + stack_frames.size() +
                          (reached_end_of_stack ? 0 : StackPageSize));

_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to