Skip to content

Commit 5b4100c

Browse files
authored
[lldb-dap] Improve stackTrace and exceptionInfo DAP request handlers (#105905)
Refactoring `stackTrace` to perform frame look ups in a more on-demand fashion to improve overall performance. Additionally adding additional information to the `exceptionInfo` request to report exception stacks there instead of merging the exception stack into the stack trace. The `exceptionInfo` request is only called if a stop event occurs with `reason='exception'`, which should mitigate the performance of `SBThread::GetCurrentException` calls. Adding unit tests for exception handling and stack trace supporting.
1 parent 5537ae8 commit 5b4100c

File tree

23 files changed

+571
-100
lines changed

23 files changed

+571
-100
lines changed

lldb/packages/Python/lldbsuite/test/lldbplatformutil.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,22 @@ def findMainThreadCheckerDylib():
181181
return ""
182182

183183

184+
def findBacktraceRecordingDylib():
185+
if not platformIsDarwin():
186+
return ""
187+
188+
if getPlatform() in lldbplatform.translate(lldbplatform.darwin_embedded):
189+
return "/Developer/usr/lib/libBacktraceRecording.dylib"
190+
191+
with os.popen("xcode-select -p") as output:
192+
xcode_developer_path = output.read().strip()
193+
mtc_dylib_path = "%s/usr/lib/libBacktraceRecording.dylib" % xcode_developer_path
194+
if os.path.isfile(mtc_dylib_path):
195+
return mtc_dylib_path
196+
197+
return ""
198+
199+
184200
class _PlatformContext(object):
185201
"""Value object class which contains platform-specific options."""
186202

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,17 @@ def request_evaluate(self, expression, frameIndex=0, threadId=None, context=None
707707
}
708708
return self.send_recv(command_dict)
709709

710+
def request_exceptionInfo(self, threadId=None):
711+
if threadId is None:
712+
threadId = self.get_thread_id()
713+
args_dict = {"threadId": threadId}
714+
command_dict = {
715+
"command": "exceptionInfo",
716+
"type": "request",
717+
"arguments": args_dict,
718+
}
719+
return self.send_recv(command_dict)
720+
710721
def request_initialize(self, sourceInitFile):
711722
command_dict = {
712723
"command": "initialize",
@@ -754,6 +765,7 @@ def request_launch(
754765
runInTerminal=False,
755766
postRunCommands=None,
756767
enableAutoVariableSummaries=False,
768+
enableDisplayExtendedBacktrace=False,
757769
enableSyntheticChildDebugging=False,
758770
commandEscapePrefix=None,
759771
customFrameFormat=None,
@@ -806,6 +818,7 @@ def request_launch(
806818

807819
args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries
808820
args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging
821+
args_dict["enableDisplayExtendedBacktrace"] = enableDisplayExtendedBacktrace
809822
args_dict["commandEscapePrefix"] = commandEscapePrefix
810823
command_dict = {"command": "launch", "type": "request", "arguments": args_dict}
811824
response = self.send_recv(command_dict)

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,14 @@ def verify_breakpoint_hit(self, breakpoint_ids):
103103
return
104104
self.assertTrue(False, "breakpoint not hit")
105105

106-
def verify_stop_exception_info(self, expected_description):
106+
def verify_stop_exception_info(self, expected_description, timeout=timeoutval):
107107
"""Wait for the process we are debugging to stop, and verify the stop
108108
reason is 'exception' and that the description matches
109109
'expected_description'
110110
"""
111-
stopped_events = self.dap_server.wait_for_stopped()
111+
stopped_events = self.dap_server.wait_for_stopped(timeout=timeout)
112112
for stopped_event in stopped_events:
113+
print("stopped_event", stopped_event)
113114
if "body" in stopped_event:
114115
body = stopped_event["body"]
115116
if "reason" not in body:
@@ -180,6 +181,10 @@ def get_stackFrames(self, threadId=None, startFrame=None, levels=None, dump=Fals
180181
)
181182
return stackFrames
182183

184+
def get_exceptionInfo(self, threadId=None):
185+
response = self.dap_server.request_exceptionInfo(threadId=threadId)
186+
return self.get_dict_value(response, ["body"])
187+
183188
def get_source_and_line(self, threadId=None, frameIndex=0):
184189
stackFrames = self.get_stackFrames(
185190
threadId=threadId, startFrame=frameIndex, levels=1
@@ -381,6 +386,7 @@ def launch(
381386
expectFailure=False,
382387
postRunCommands=None,
383388
enableAutoVariableSummaries=False,
389+
enableDisplayExtendedBacktrace=False,
384390
enableSyntheticChildDebugging=False,
385391
commandEscapePrefix=None,
386392
customFrameFormat=None,
@@ -422,6 +428,7 @@ def cleanup():
422428
runInTerminal=runInTerminal,
423429
postRunCommands=postRunCommands,
424430
enableAutoVariableSummaries=enableAutoVariableSummaries,
431+
enableDisplayExtendedBacktrace=enableDisplayExtendedBacktrace,
425432
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
426433
commandEscapePrefix=commandEscapePrefix,
427434
customFrameFormat=customFrameFormat,
@@ -461,6 +468,7 @@ def build_and_launch(
461468
postRunCommands=None,
462469
lldbDAPEnv=None,
463470
enableAutoVariableSummaries=False,
471+
enableDisplayExtendedBacktrace=False,
464472
enableSyntheticChildDebugging=False,
465473
commandEscapePrefix=None,
466474
customFrameFormat=None,
@@ -497,6 +505,7 @@ def build_and_launch(
497505
postRunCommands=postRunCommands,
498506
enableAutoVariableSummaries=enableAutoVariableSummaries,
499507
enableSyntheticChildDebugging=enableSyntheticChildDebugging,
508+
enableDisplayExtendedBacktrace=enableDisplayExtendedBacktrace,
500509
commandEscapePrefix=commandEscapePrefix,
501510
customFrameFormat=customFrameFormat,
502511
customThreadFormat=customThreadFormat,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
CXX_SOURCES := main.cpp
1+
C_SOURCES := main.c
22

33
include Makefile.rules

lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
Test exception behavior in DAP
2+
Test exception behavior in DAP with signal.
33
"""
44

55

@@ -16,8 +16,10 @@ def test_stopped_description(self):
1616
event.
1717
"""
1818
program = self.getBuildArtifact("a.out")
19-
print("test_stopped_description called", flush=True)
2019
self.build_and_launch(program)
21-
2220
self.dap_server.request_continue()
2321
self.assertTrue(self.verify_stop_exception_info("signal SIGABRT"))
22+
exceptionInfo = self.get_exceptionInfo()
23+
self.assertEqual(exceptionInfo["breakMode"], "always")
24+
self.assertEqual(exceptionInfo["description"], "signal SIGABRT")
25+
self.assertEqual(exceptionInfo["exceptionId"], "signal")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
CXX_SOURCES := main.cpp
2+
3+
include Makefile.rules
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
Test exception behavior in DAP with c++ throw.
3+
"""
4+
5+
6+
from lldbsuite.test.decorators import *
7+
from lldbsuite.test.lldbtest import *
8+
import lldbdap_testcase
9+
10+
11+
class TestDAP_exception_cpp(lldbdap_testcase.DAPTestCaseBase):
12+
@skipIfWindows
13+
def test_stopped_description(self):
14+
"""
15+
Test that exception description is shown correctly in stopped
16+
event.
17+
"""
18+
program = self.getBuildArtifact("a.out")
19+
self.build_and_launch(program)
20+
self.dap_server.request_continue()
21+
self.assertTrue(self.verify_stop_exception_info("signal SIGABRT"))
22+
exceptionInfo = self.get_exceptionInfo()
23+
self.assertEqual(exceptionInfo["breakMode"], "always")
24+
self.assertEqual(exceptionInfo["description"], "signal SIGABRT")
25+
self.assertEqual(exceptionInfo["exceptionId"], "signal")
26+
self.assertIsNotNone(exceptionInfo["details"])
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include <stdexcept>
2+
3+
int main(int argc, char const *argv[]) {
4+
throw std::invalid_argument("throwing exception for testing");
5+
return 0;
6+
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <signal.h>
22

3-
int main() {
3+
int main(int argc, char const *argv[]) {
44
raise(SIGABRT);
55
return 0;
66
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
OBJC_SOURCES := main.m
2+
3+
CFLAGS_EXTRAS := -w
4+
5+
USE_SYSTEM_STDLIB := 1
6+
7+
LD_EXTRAS := -framework Foundation
8+
9+
include Makefile.rules

0 commit comments

Comments
 (0)