Skip to content

Commit 2168161

Browse files
committed
[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 llvm#137057
1 parent 2397180 commit 2168161

File tree

4 files changed

+84
-10
lines changed

4 files changed

+84
-10
lines changed

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1046,7 +1046,7 @@ def request_modules(self):
10461046
return self.send_recv({"command": "modules", "type": "request"})
10471047

10481048
def request_stackTrace(
1049-
self, threadId=None, startFrame=None, levels=None, dump=False
1049+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
10501050
):
10511051
if threadId is None:
10521052
threadId = self.get_thread_id()
@@ -1055,6 +1055,8 @@ def request_stackTrace(
10551055
args_dict["startFrame"] = startFrame
10561056
if levels is not None:
10571057
args_dict["levels"] = levels
1058+
if format is not None:
1059+
args_dict["format"] = format
10581060
command_dict = {
10591061
"command": "stackTrace",
10601062
"type": "request",

lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,14 @@ def get_dict_value(self, d, key_path):
161161
return value
162162

163163
def get_stackFrames_and_totalFramesCount(
164-
self, threadId=None, startFrame=None, levels=None, dump=False
164+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
165165
):
166166
response = self.dap_server.request_stackTrace(
167-
threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
167+
threadId=threadId,
168+
startFrame=startFrame,
169+
levels=levels,
170+
format=format,
171+
dump=dump,
168172
)
169173
if response:
170174
stackFrames = self.get_dict_value(response, ["body", "stackFrames"])
@@ -177,9 +181,15 @@ def get_stackFrames_and_totalFramesCount(
177181
return (stackFrames, totalFrames)
178182
return (None, 0)
179183

180-
def get_stackFrames(self, threadId=None, startFrame=None, levels=None, dump=False):
184+
def get_stackFrames(
185+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
186+
):
181187
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
182-
threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
188+
threadId=threadId,
189+
startFrame=startFrame,
190+
levels=levels,
191+
format=format,
192+
dump=dump,
183193
)
184194
return stackFrames
185195

lldb/test/API/tools/lldb-dap/stackTrace/TestDAP_stackTrace.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,3 +217,33 @@ def test_functionNameWithArgs(self):
217217
self.continue_to_next_stop()
218218
frame = self.get_stackFrames()[0]
219219
self.assertEqual(frame["name"], "recurse(x=1)")
220+
221+
@skipIfWindows
222+
def test_StackFrameFormat(self):
223+
"""
224+
Test the StackFrameFormat.
225+
"""
226+
program = self.getBuildArtifact("a.out")
227+
self.build_and_launch(program)
228+
source = "main.c"
229+
230+
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
231+
232+
self.continue_to_next_stop()
233+
frame = self.get_stackFrames(format={"includeAll": True})[0]
234+
self.assertEqual(frame["name"], "a.out main.c:6:5 recurse(x=1)")
235+
236+
frame = self.get_stackFrames(format={"parameters": True})[0]
237+
self.assertEqual(frame["name"], "recurse(x=1)")
238+
239+
frame = self.get_stackFrames(format={"parameterNames": True})[0]
240+
self.assertEqual(frame["name"], "recurse(x=1)")
241+
242+
frame = self.get_stackFrames(format={"parameterValues": True})[0]
243+
self.assertEqual(frame["name"], "recurse(x=1)")
244+
245+
frame = self.get_stackFrames(format={"parameters": False, "line": True})[0]
246+
self.assertEqual(frame["name"], "main.c:6:5 recurse")
247+
248+
frame = self.get_stackFrames(format={"parameters": False, "module": True})[0]
249+
self.assertEqual(frame["name"], "a.out recurse")

lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,15 @@ static constexpr int StackPageSize = 20;
4949
//
5050
// s=3,l=3 = [th0->s3, label1, th1->s0]
5151
static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
52+
lldb::SBFormat &frame_format,
5253
llvm::json::Array &stack_frames, int64_t &offset,
5354
const int64_t start_frame, const int64_t levels) {
5455
bool reached_end_of_stack = false;
5556
for (int64_t i = start_frame;
5657
static_cast<int64_t>(stack_frames.size()) < levels; i++) {
5758
if (i == -1) {
5859
stack_frames.emplace_back(
59-
CreateExtendedStackFrameLabel(thread, dap.frame_format));
60+
CreateExtendedStackFrameLabel(thread, frame_format));
6061
continue;
6162
}
6263

@@ -67,7 +68,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
6768
break;
6869
}
6970

70-
stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format));
71+
stack_frames.emplace_back(CreateStackFrame(frame, frame_format));
7172
}
7273

7374
if (dap.configuration.displayExtendedBacktrace && reached_end_of_stack) {
@@ -80,7 +81,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
8081
continue;
8182

8283
reached_end_of_stack = FillStackFrames(
83-
dap, backtrace, stack_frames, offset,
84+
dap, backtrace, frame_format, stack_frames, offset,
8485
(start_frame - offset) > 0 ? start_frame - offset : -1, levels);
8586
if (static_cast<int64_t>(stack_frames.size()) >= levels)
8687
break;
@@ -178,14 +179,45 @@ void StackTraceRequestHandler::operator()(
178179
llvm::json::Array stack_frames;
179180
llvm::json::Object body;
180181

182+
lldb::SBFormat frame_format = dap.frame_format;
183+
184+
if (const auto *format = arguments->getObject("format")) {
185+
const bool parameters = GetBoolean(format, "parameters").value_or(false);
186+
const bool parameter_names =
187+
GetBoolean(format, "parameterNames").value_or(false);
188+
const bool parameter_values =
189+
GetBoolean(format, "parameterValues").value_or(false);
190+
const bool line = GetBoolean(format, "line").value_or(false);
191+
const bool module = GetBoolean(format, "module").value_or(false);
192+
const bool include_all = GetBoolean(format, "includeAll").value_or(false);
193+
194+
std::string format_str;
195+
llvm::raw_string_ostream os(format_str);
196+
197+
if (include_all || module)
198+
os << "{${module.file.basename} }";
199+
200+
if (include_all || line)
201+
os << "{${line.file.basename}:${line.number}:${line.column} }";
202+
203+
if (include_all || parameters || parameter_names || parameter_values)
204+
os << "{${function.name-with-args}}";
205+
else
206+
os << "{${function.name-without-args}}";
207+
208+
lldb::SBError error;
209+
frame_format = lldb::SBFormat(format_str.c_str(), error);
210+
assert(error.Success());
211+
}
212+
181213
if (thread.IsValid()) {
182214
const auto start_frame =
183215
GetInteger<uint64_t>(arguments, "startFrame").value_or(0);
184216
const auto levels = GetInteger<uint64_t>(arguments, "levels").value_or(0);
185217
int64_t offset = 0;
186218
bool reached_end_of_stack =
187-
FillStackFrames(dap, thread, stack_frames, offset, start_frame,
188-
levels == 0 ? INT64_MAX : levels);
219+
FillStackFrames(dap, thread, frame_format, stack_frames, offset,
220+
start_frame, levels == 0 ? INT64_MAX : levels);
189221
body.try_emplace("totalFrames",
190222
start_frame + stack_frames.size() +
191223
(reached_end_of_stack ? 0 : StackPageSize));

0 commit comments

Comments
 (0)