Skip to content

Commit c205676

Browse files
authored
Merge pull request #10571 from swiftlang/StackFrameFormat-backport
[lldb-dap] Support StackFrameFormat (llvm#137113)
2 parents bbd867f + 98cee24 commit c205676

File tree

5 files changed

+122
-22
lines changed

5 files changed

+122
-22
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
@@ -1040,7 +1040,7 @@ def request_modules(self):
10401040
return self.send_recv({"command": "modules", "type": "request"})
10411041

10421042
def request_stackTrace(
1043-
self, threadId=None, startFrame=None, levels=None, dump=False
1043+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
10441044
):
10451045
if threadId is None:
10461046
threadId = self.get_thread_id()
@@ -1049,6 +1049,8 @@ def request_stackTrace(
10491049
args_dict["startFrame"] = startFrame
10501050
if levels is not None:
10511051
args_dict["levels"] = levels
1052+
if format is not None:
1053+
args_dict["format"] = format
10521054
command_dict = {
10531055
"command": "stackTrace",
10541056
"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
@@ -159,10 +159,14 @@ def get_dict_value(self, d, key_path):
159159
return value
160160

161161
def get_stackFrames_and_totalFramesCount(
162-
self, threadId=None, startFrame=None, levels=None, dump=False
162+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
163163
):
164164
response = self.dap_server.request_stackTrace(
165-
threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
165+
threadId=threadId,
166+
startFrame=startFrame,
167+
levels=levels,
168+
format=format,
169+
dump=dump,
166170
)
167171
if response:
168172
stackFrames = self.get_dict_value(response, ["body", "stackFrames"])
@@ -175,9 +179,15 @@ def get_stackFrames_and_totalFramesCount(
175179
return (stackFrames, totalFrames)
176180
return (None, 0)
177181

178-
def get_stackFrames(self, threadId=None, startFrame=None, levels=None, dump=False):
182+
def get_stackFrames(
183+
self, threadId=None, startFrame=None, levels=None, format=None, dump=False
184+
):
179185
(stackFrames, totalFrames) = self.get_stackFrames_and_totalFramesCount(
180-
threadId=threadId, startFrame=startFrame, levels=levels, dump=dump
186+
threadId=threadId,
187+
startFrame=startFrame,
188+
levels=levels,
189+
format=format,
190+
dump=dump,
181191
)
182192
return stackFrames
183193

lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
Test lldb-dap stackTrace request with an extended backtrace thread.
33
"""
44

5-
65
import os
76

87
import lldbdap_testcase
@@ -12,11 +11,7 @@
1211

1312

1413
class TestDAP_extendedStackTrace(lldbdap_testcase.DAPTestCaseBase):
15-
@skipUnlessDarwin
16-
def test_stackTrace(self):
17-
"""
18-
Tests the 'stackTrace' packet on a thread with an extended backtrace.
19-
"""
14+
def build_and_run(self, displayExtendedBacktrace=True):
2015
backtrace_recording_lib = findBacktraceRecordingDylib()
2116
if not backtrace_recording_lib:
2217
self.skipTest(
@@ -36,7 +31,7 @@ def test_stackTrace(self):
3631
"DYLD_LIBRARY_PATH=/usr/lib/system/introspection",
3732
"DYLD_INSERT_LIBRARIES=" + backtrace_recording_lib,
3833
],
39-
displayExtendedBacktrace=True,
34+
displayExtendedBacktrace=displayExtendedBacktrace,
4035
)
4136
source = "main.m"
4237
breakpoint = line_number(source, "breakpoint 1")
@@ -47,6 +42,12 @@ def test_stackTrace(self):
4742
len(breakpoint_ids), len(lines), "expect correct number of breakpoints"
4843
)
4944

45+
@skipUnlessDarwin
46+
def test_stackTrace(self):
47+
"""
48+
Tests the 'stackTrace' packet on a thread with an extended backtrace.
49+
"""
50+
self.build_and_run()
5051
events = self.continue_to_next_stop()
5152

5253
stackFrames, totalFrames = self.get_stackFrames_and_totalFramesCount(
@@ -102,3 +103,23 @@ def test_stackTrace(self):
102103
self.assertGreaterEqual(
103104
totalFrames, i, "total frames should include a pagination offset"
104105
)
106+
107+
@skipUnlessDarwin
108+
def test_stackTraceWithFormat(self):
109+
"""
110+
Tests the 'stackTrace' packet on a thread with an extended backtrace using stack trace formats.
111+
"""
112+
self.build_and_run(displayExtendedBacktrace=False)
113+
events = self.continue_to_next_stop()
114+
115+
stackFrames, _ = self.get_stackFrames_and_totalFramesCount(
116+
threadId=events[0]["body"]["threadId"], format={"includeAll": True}
117+
)
118+
119+
stackLabels = [
120+
(i, frame)
121+
for i, frame in enumerate(stackFrames)
122+
if frame.get("presentationHint", "") == "label"
123+
]
124+
125+
self.assertEqual(len(stackLabels), 2, "expected two label stack frames")

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
Test lldb-dap stackTrace request
33
"""
44

5-
65
import os
76

87
import lldbdap_testcase
@@ -217,3 +216,30 @@ def test_functionNameWithArgs(self):
217216
self.continue_to_next_stop()
218217
frame = self.get_stackFrames()[0]
219218
self.assertEqual(frame["name"], "recurse(x=1)")
219+
220+
@skipIfWindows
221+
def test_StackFrameFormat(self):
222+
"""
223+
Test the StackFrameFormat.
224+
"""
225+
program = self.getBuildArtifact("a.out")
226+
self.build_and_launch(program)
227+
source = "main.c"
228+
229+
self.set_source_breakpoints(source, [line_number(source, "recurse end")])
230+
231+
self.continue_to_next_stop()
232+
frame = self.get_stackFrames(format={"parameters": True})[0]
233+
self.assertEqual(frame["name"], "recurse(x=1)")
234+
235+
frame = self.get_stackFrames(format={"parameterNames": True})[0]
236+
self.assertEqual(frame["name"], "recurse(x=1)")
237+
238+
frame = self.get_stackFrames(format={"parameterValues": True})[0]
239+
self.assertEqual(frame["name"], "recurse(x=1)")
240+
241+
frame = self.get_stackFrames(format={"parameters": False, "line": True})[0]
242+
self.assertEqual(frame["name"], "main.c:6:5 recurse")
243+
244+
frame = self.get_stackFrames(format={"parameters": False, "module": True})[0]
245+
self.assertEqual(frame["name"], "a.out recurse")

lldb/tools/lldb-dap/lldb-dap.cpp

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -683,14 +683,16 @@ void SetSourceMapFromArguments(DAP &dap, const llvm::json::Object &arguments) {
683683
//
684684
// s=3,l=3 = [th0->s3, label1, th1->s0]
685685
bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
686+
lldb::SBFormat &frame_format,
686687
llvm::json::Array &stack_frames, int64_t &offset,
687-
const int64_t start_frame, const int64_t levels) {
688+
const int64_t start_frame, const int64_t levels,
689+
const bool include_all) {
688690
bool reached_end_of_stack = false;
689691
for (int64_t i = start_frame;
690692
static_cast<int64_t>(stack_frames.size()) < levels; i++) {
691693
if (i == -1) {
692694
stack_frames.emplace_back(
693-
CreateExtendedStackFrameLabel(thread, dap.frame_format));
695+
CreateExtendedStackFrameLabel(thread, frame_format));
694696
continue;
695697
}
696698

@@ -701,10 +703,10 @@ bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
701703
break;
702704
}
703705

704-
stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format));
706+
stack_frames.emplace_back(CreateStackFrame(frame, frame_format));
705707
}
706708

707-
if (dap.display_extended_backtrace && reached_end_of_stack) {
709+
if (include_all && reached_end_of_stack) {
708710
// Check for any extended backtraces.
709711
for (uint32_t bt = 0;
710712
bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) {
@@ -714,8 +716,9 @@ bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
714716
continue;
715717

716718
reached_end_of_stack = FillStackFrames(
717-
dap, backtrace, stack_frames, offset,
718-
(start_frame - offset) > 0 ? start_frame - offset : -1, levels);
719+
dap, backtrace, frame_format, stack_frames, offset,
720+
(start_frame - offset) > 0 ? start_frame - offset : -1, levels,
721+
include_all);
719722
if (static_cast<int64_t>(stack_frames.size()) >= levels)
720723
break;
721724
}
@@ -3579,13 +3582,51 @@ void request_stackTrace(DAP &dap, const llvm::json::Object &request) {
35793582
llvm::json::Array stack_frames;
35803583
llvm::json::Object body;
35813584

3585+
lldb::SBFormat frame_format = dap.frame_format;
3586+
bool include_all = dap.display_extended_backtrace;
3587+
3588+
if (const auto *format = arguments->getObject("format")) {
3589+
// Indicates that all stack frames should be included, even those the debug
3590+
// adapter might otherwise hide.
3591+
include_all = GetBoolean(format, "includeAll", false);
3592+
3593+
// Parse the properties that have a corresponding format string.
3594+
// FIXME: Support "parameterTypes" and "hex".
3595+
const bool module = GetBoolean(format, "module", false);
3596+
const bool line = GetBoolean(format, "line", false);
3597+
const bool parameters = GetBoolean(format, "parameters", false);
3598+
const bool parameter_names = GetBoolean(format, "parameterNames", false);
3599+
const bool parameter_values = GetBoolean(format, "parameterValues", false);
3600+
3601+
// Only change the format string if we have to.
3602+
if (module || line || parameters || parameter_names || parameter_values) {
3603+
std::string format_str;
3604+
llvm::raw_string_ostream os(format_str);
3605+
3606+
if (module)
3607+
os << "{${module.file.basename} }";
3608+
3609+
if (line)
3610+
os << "{${line.file.basename}:${line.number}:${line.column} }";
3611+
3612+
if (parameters || parameter_names || parameter_values)
3613+
os << "{${function.name-with-args}}";
3614+
else
3615+
os << "{${function.name-without-args}}";
3616+
3617+
lldb::SBError error;
3618+
frame_format = lldb::SBFormat(format_str.c_str(), error);
3619+
assert(error.Success());
3620+
}
3621+
}
3622+
35823623
if (thread.IsValid()) {
35833624
const auto start_frame = GetUnsigned(arguments, "startFrame", 0);
35843625
const auto levels = GetUnsigned(arguments, "levels", 0);
35853626
int64_t offset = 0;
3586-
bool reached_end_of_stack =
3587-
FillStackFrames(dap, thread, stack_frames, offset, start_frame,
3588-
levels == 0 ? INT64_MAX : levels);
3627+
bool reached_end_of_stack = FillStackFrames(
3628+
dap, thread, frame_format, stack_frames, offset, start_frame,
3629+
levels == 0 ? INT64_MAX : levels, include_all);
35893630
body.try_emplace("totalFrames",
35903631
start_frame + stack_frames.size() +
35913632
(reached_end_of_stack ? 0 : StackPageSize));

0 commit comments

Comments
 (0)