[Lldb-commits] [lldb] 35ed1eb - [lldb-dap] Return raw stop info from exceptionInfo (#231760)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Oct 14 17:01:23 PDT 2026
Author: Jonas Devlieghere
Date: 2026-10-14T17:01:17-07:00
New Revision: 35ed1ebbf4c3a0b8771b6beb7674e22da71f4229
URL: https://github.com/llvm/llvm-project/commit/35ed1ebbf4c3a0b8771b6beb7674e22da71f4229
DIFF: https://github.com/llvm/llvm-project/commit/35ed1ebbf4c3a0b8771b6beb7674e22da71f4229.diff
LOG: [lldb-dap] Return raw stop info from exceptionInfo (#231760)
lldb-dap folds the thread's extended stop info and the process's
extended crash information into the exceptionInfo description as
formatted text. Clients that want interpret these themselves currently
have to parse them back out.
Return both as raw JSON in two new lldb-dap extension fields,
`$__lldb_stopReasonExtendedInfo` and `$__lldb_extendedCrashInformation`.
rdar://188761988
Added:
Modified:
lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
lldb/test/API/tools/lldb-dap/exception/asan/TestDAP_asan.py
lldb/test/API/tools/lldb-dap/exception/ubsan/TestDAP_ubsan.py
lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
lldb/unittests/DAP/ProtocolRequestsTest.cpp
Removed:
################################################################################
diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
index 24b33ae9381619..310a9f01131d5c 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb_dap/types.py
@@ -1731,6 +1731,12 @@ class Body:
breakMode: ExceptionBreakMode
description: Optional[str] = None
details: Optional[ExceptionDetails] = None
+ lldb_stop_reason_extended_info: Optional[Dict[str, Any]] = field(
+ metadata={"alias": "$__lldb_stopReasonExtendedInfo"}, default=None
+ )
+ lldb_extended_crash_information: Optional[Dict[str, Any]] = field(
+ metadata={"alias": "$__lldb_extendedCrashInformation"}, default=None
+ )
body: Body
diff --git a/lldb/test/API/tools/lldb-dap/exception/asan/TestDAP_asan.py b/lldb/test/API/tools/lldb-dap/exception/asan/TestDAP_asan.py
index 395cd68db25fe1..a9d479a5a7802b 100644
--- a/lldb/test/API/tools/lldb-dap/exception/asan/TestDAP_asan.py
+++ b/lldb/test/API/tools/lldb-dap/exception/asan/TestDAP_asan.py
@@ -28,3 +28,7 @@ def test_asan(self):
description = self.expect_not_none(exception_info.description)
self.assertRegex(description, r"fatal_error: heap-use-after-free")
self.assertEqual(exception_info.exceptionId, "runtime-instrumentation")
+
+ stop_info = self.expect_not_none(exception_info.lldb_stop_reason_extended_info)
+ self.assertEqual(stop_info["instrumentation_class"], "AddressSanitizer")
+ self.assertEqual(stop_info["description"], "heap-use-after-free")
diff --git a/lldb/test/API/tools/lldb-dap/exception/ubsan/TestDAP_ubsan.py b/lldb/test/API/tools/lldb-dap/exception/ubsan/TestDAP_ubsan.py
index 23ba0747311e95..d8e1f13ed791d2 100644
--- a/lldb/test/API/tools/lldb-dap/exception/ubsan/TestDAP_ubsan.py
+++ b/lldb/test/API/tools/lldb-dap/exception/ubsan/TestDAP_ubsan.py
@@ -30,6 +30,11 @@ def test_ubsan(self):
self.assertRegex(description, r"Out of bounds index")
self.assertEqual(exception_info.exceptionId, "runtime-instrumentation")
+ stop_info = self.expect_not_none(exception_info.lldb_stop_reason_extended_info)
+ self.assertEqual(
+ stop_info["instrumentation_class"], "UndefinedBehaviorSanitizer"
+ )
+
# FIXME: Check on non macOS platform the stop information location heuristic
# may be wrong. enable when we have updated Ubsan stopInfo heuristic.
if self.platformIsDarwin():
diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index f15d35f3954da6..bea427519126a8 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -271,6 +271,34 @@ static std::string FormatCrashReport(lldb::SBThread &thread) {
return report;
}
+static std::optional<json::Value> ParseJSON(DAP &dap, lldb::SBStream &stream) {
+ Expected<json::Value> value =
+ json::parse({stream.GetData(), stream.GetSize()});
+ if (!value) {
+ DAP_LOG_ERROR(dap.log, value.takeError(), "invalid JSON: {0}");
+ return std::nullopt;
+ }
+ return std::move(*value);
+}
+
+static std::optional<json::Value> GetExtendedStopInfo(DAP &dap,
+ lldb::SBThread &thread) {
+ lldb::SBStream stream;
+ if (!thread.GetStopReasonExtendedInfoAsJSON(stream))
+ return std::nullopt;
+ return ParseJSON(dap, stream);
+}
+
+static std::optional<json::Value>
+GetExtendedCrashInformation(DAP &dap, lldb::SBThread &thread) {
+ lldb::SBStructuredData crash_info =
+ thread.GetProcess().GetExtendedCrashInformation();
+ lldb::SBStream stream;
+ if (!crash_info || crash_info.GetAsJSON(stream).Fail())
+ return std::nullopt;
+ return ParseJSON(dap, stream);
+}
+
static std::string FormatStackTrace(lldb::SBThread &thread) {
std::string stack_trace;
raw_string_ostream OS(stack_trace);
@@ -348,6 +376,12 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const {
!crash_report.empty())
body.description += formatv("\n\n{0}", crash_report);
+ // Clients that interpret these themselves shouldn't have to parse them back
+ // out of the description.
+ body.lldbExtStopReasonExtendedInfo = GetExtendedStopInfo(dap, thread);
+ body.lldbExtExtendedCrashInformation =
+ GetExtendedCrashInformation(dap, thread);
+
lldb::SBProcess process = thread.GetProcess();
for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) {
auto type = static_cast<lldb::InstrumentationRuntimeType>(idx);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index c952c17512952c..6a7f4e57b243ab 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -695,6 +695,12 @@ json::Value toJSON(const ExceptionInfoResponseBody &ERB) {
result.insert({"description", ERB.description});
if (ERB.details.has_value())
result.insert({"details", *ERB.details});
+ if (ERB.lldbExtStopReasonExtendedInfo)
+ result.insert(
+ {"$__lldb_stopReasonExtendedInfo", *ERB.lldbExtStopReasonExtendedInfo});
+ if (ERB.lldbExtExtendedCrashInformation)
+ result.insert({"$__lldb_extendedCrashInformation",
+ *ERB.lldbExtExtendedCrashInformation});
return result;
}
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index d8cc9d4cad2233..169052183b110f 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -1071,6 +1071,19 @@ struct ExceptionInfoResponseBody {
/// Detailed information about the exception.
std::optional<ExceptionDetails> details;
+
+ /// lldb-dap Extensions
+ /// @{
+
+ /// The thread's stop reason extended info, as reported by
+ /// `SBThread::GetStopReasonExtendedInfoAsJSON`.
+ std::optional<llvm::json::Value> lldbExtStopReasonExtendedInfo;
+
+ /// The process's extended crash information, as reported by
+ /// `SBProcess::GetExtendedCrashInformation`.
+ std::optional<llvm::json::Value> lldbExtExtendedCrashInformation;
+
+ /// @}
};
llvm::json::Value toJSON(const ExceptionInfoResponseBody &);
diff --git a/lldb/unittests/DAP/ProtocolRequestsTest.cpp b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
index af0d69f3a9ac43..f0a71d25f21ddf 100644
--- a/lldb/unittests/DAP/ProtocolRequestsTest.cpp
+++ b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
@@ -55,6 +55,9 @@ TEST(ProtocolRequestsTest, ExceptionInfoResponseBody) {
body.breakMode = eExceptionBreakModeNever;
body.details = ExceptionDetails{};
body.details->message = "some message";
+ body.lldbExtStopReasonExtendedInfo =
+ json::Object{{"instrumentation_class", "AddressSanitizer"}};
+ body.lldbExtExtendedCrashInformation = json::Object{{"crash-info", "abort"}};
Expected<json::Value> expected_opt = parse(
R"({
@@ -63,6 +66,12 @@ TEST(ProtocolRequestsTest, ExceptionInfoResponseBody) {
"breakMode": "never",
"details": {
"message": "some message"
+ },
+ "$__lldb_stopReasonExtendedInfo": {
+ "instrumentation_class": "AddressSanitizer"
+ },
+ "$__lldb_extendedCrashInformation": {
+ "crash-info": "abort"
}
})");
More information about the lldb-commits
mailing list