-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[lldb-dap] Support StackFrameFormat #137113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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
@llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) ChangesThe 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 Full diff: https://github.com/llvm/llvm-project/pull/137113.diff 4 Files Affected:
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));
|
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is maybe a different meaning than the spec meant for includeAll
.
It says:
Includes all stack frames, including those the debug adapter might otherwise hide.
Which to me, sounds like its about hiding frames that we might not find interesting (e.g. frames from system libraries).
I think if this is false
you could skip showing the extended backtraces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great observation, you're right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its worth noting that today I don't think we skip any frames, however we do use the 'presentationHint' to tweak the frames a little.
deemphasize
is used when we don't have the source info for a frameEmplaceSafeString(source, "presentationHint", "deemphasize"); subtle
is used if the frame is artificial or hiddenobject.try_emplace("presentationHint", "subtle");
@@ -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")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another thing I notice is the StackFrameFormat
inherits from ValueFormat
and thus includes the hex?: boolean;
field as well.
I'm not sure what that would mean in terms of a stack frame however, just thought I would note that for completeness.
✅ With the latest revision this PR passed the Python code formatter. |
@@ -180,44 +184,53 @@ void StackTraceRequestHandler::operator()( | |||
llvm::json::Object body; | |||
|
|||
lldb::SBFormat frame_format = dap.frame_format; | |||
bool include_all = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this default to dap.configuration.displayExtendedBacktrace
and then it simplifies line 75-77.
@@ -217,3 +216,30 @@ def test_functionNameWithArgs(self): | |||
self.continue_to_next_stop() | |||
frame = self.get_stackFrames()[0] | |||
self.assertEqual(frame["name"], "recurse(x=1)") | |||
|
|||
@skipIfWindows |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
But I could not see why this test is skipped on windows
there is a #include <unistd.h>
but it is not used any where
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. All the tests in this file are skipped on Windows for as far as the history goes back. I can try removing all of them in a followup and see what the Windows bot say.
lldb/test/API/tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py
Outdated
Show resolved
Hide resolved
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 Back-ported from commit 262158b
[lldb-dap] Support StackFrameFormat (llvm#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 llvm#137057
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
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
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
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