https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/176465
>From 0b50dabc60648c3211787d534dd14cea5279f9ac Mon Sep 17 00:00:00 2001 From: John Harrison <[email protected]> Date: Fri, 16 Jan 2026 11:31:17 -0800 Subject: [PATCH 1/4] [lldb-dap] Adding more details to 'exceptionInfo'. --- .../test/tools/lldb-dap/lldbdap_testcase.py | 48 ++++++---- .../TestDAP_setExceptionBreakpoints.py | 8 +- .../lldb-dap/exception/TestDAP_exception.py | 2 +- .../exception/cpp/TestDAP_exception_cpp.py | 5 +- .../exception/objc/TestDAP_exception_objc.py | 10 +-- .../exception/runtime-instruments/Makefile | 4 + .../TestDAP_runtime_instruments.py | 25 ++++++ .../exception/runtime-instruments/categories | 1 + .../exception/runtime-instruments/main.c | 5 ++ .../Handler/ExceptionInfoRequestHandler.cpp | 90 +++++++++++++------ 10 files changed, 144 insertions(+), 54 deletions(-) create mode 100644 lldb/test/API/tools/lldb-dap/exception/runtime-instruments/Makefile create mode 100644 lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py create mode 100644 lldb/test/API/tools/lldb-dap/exception/runtime-instruments/categories create mode 100644 lldb/test/API/tools/lldb-dap/exception/runtime-instruments/main.c 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 e4a3e1c786ffed..b2cac4dfb0e5bf 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 @@ -208,25 +208,40 @@ def verify_all_breakpoints_hit(self, breakpoint_ids): return self.assertTrue(False, f"breakpoints not hit, stopped_events={stopped_events}") - def verify_stop_exception_info(self, expected_description): + def verify_stop_exception_info( + self, expected_description: str, expected_text: Optional[str] = None + ) -> None: """Wait for the process we are debugging to stop, and verify the stop reason is 'exception' and that the description matches 'expected_description' """ stopped_events = self.dap_server.wait_for_stopped() + self.assertIsNotNone(stopped_events, "No stopped events detected") for stopped_event in stopped_events: - if "body" in stopped_event: - body = stopped_event["body"] - if "reason" not in body: - continue - if body["reason"] != "exception": - continue - if "description" not in body: - continue - description = body["description"] - if expected_description == description: - return True - return False + if ( + "body" not in stopped_event + or stopped_event["body"]["reason"] != "exception" + ): + continue + self.assertIn( + "description", + stopped_event["body"], + f"stopped event missing description {stopped_event}", + ) + description = stopped_event["body"]["description"] + self.assertRegex( + description, + expected_description, + f"for 'stopped' event {stopped_event!r}", + ) + if expected_text: + self.assertRegex( + stopped_event["body"]["text"], + expected_text, + f"for stopped event {stopped_event!r}", + ) + return + self.fail(f"No valid stop exception info detected in {stopped_events}") def verify_stop_on_entry(self) -> None: """Waits for the process to be stopped and then verifies at least one @@ -437,12 +452,9 @@ def continue_to_breakpoints(self, breakpoint_ids): self.do_continue() self.verify_breakpoint_hit(breakpoint_ids) - def continue_to_exception_breakpoint(self, filter_label): + def continue_to_exception_breakpoint(self, description, text=None): self.do_continue() - self.assertTrue( - self.verify_stop_exception_info(filter_label), - 'verify we got "%s"' % (filter_label), - ) + self.verify_stop_exception_info(description, text) def continue_to_exit(self, exitCode=0): self.do_continue() diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 4ca733a9a59cac..684726c927bc11 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -35,5 +35,9 @@ def test_functionality(self): if response: self.assertTrue(response["success"]) - self.continue_to_exception_breakpoint("C++ Throw") - self.continue_to_exception_breakpoint("C++ Catch") + self.continue_to_exception_breakpoint( + r"breakpoint \d+\.\d+", text=r"C\+\+ Throw" + ) + self.continue_to_exception_breakpoint( + r"breakpoint \d+\.\d+", text=r"C\+\+ Catch" + ) diff --git a/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py b/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py index f044bcae418921..b92c3290ceb4cb 100644 --- a/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py +++ b/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py @@ -18,7 +18,7 @@ def test_stopped_description(self): self.build_and_launch(program) self.do_continue() - self.assertTrue(self.verify_stop_exception_info("signal SIGABRT")) + self.verify_stop_exception_info("signal SIGABRT") exceptionInfo = self.get_exceptionInfo() self.assertEqual(exceptionInfo["breakMode"], "always") self.assertEqual(exceptionInfo["description"], "signal SIGABRT") diff --git a/lldb/test/API/tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py b/lldb/test/API/tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py index 6471e2b87251a7..4729cbef00c113 100644 --- a/lldb/test/API/tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py +++ b/lldb/test/API/tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py @@ -2,7 +2,6 @@ Test exception behavior in DAP with c++ throw. """ - from lldbsuite.test.decorators import * from lldbsuite.test.lldbtest import * import lldbdap_testcase @@ -18,9 +17,9 @@ def test_stopped_description(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program) self.dap_server.request_continue() - self.assertTrue(self.verify_stop_exception_info("signal SIGABRT")) + self.verify_stop_exception_info("signal SIGABRT") exceptionInfo = self.get_exceptionInfo() self.assertEqual(exceptionInfo["breakMode"], "always") - self.assertEqual(exceptionInfo["description"], "signal SIGABRT") + self.assertIn("signal SIGABRT", exceptionInfo["description"]) self.assertEqual(exceptionInfo["exceptionId"], "signal") self.assertIsNotNone(exceptionInfo["details"]) diff --git a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py index ddedf7a6de8c6c..40233af4b2bd6a 100644 --- a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py +++ b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py @@ -16,10 +16,10 @@ def test_stopped_description(self): program = self.getBuildArtifact("a.out") self.build_and_launch(program) self.dap_server.request_continue() - self.assertTrue(self.verify_stop_exception_info("signal SIGABRT")) + self.verify_stop_exception_info("signal SIGABRT") exception_info = self.get_exceptionInfo() self.assertEqual(exception_info["breakMode"], "always") - self.assertEqual(exception_info["description"], "signal SIGABRT") + self.assertIn("signal SIGABRT", exception_info["description"]) self.assertEqual(exception_info["exceptionId"], "signal") exception_details = exception_info["details"] self.assertRegex(exception_details["message"], "SomeReason") @@ -44,7 +44,7 @@ def test_break_on_throw_and_catch(self): if response: self.assertTrue(response["success"]) - self.continue_to_exception_breakpoint("Objective-C Throw") + self.continue_to_exception_breakpoint("hit Objective-C exception") # FIXME: Catching objc exceptions do not appear to be working. # Xcode appears to set a breakpoint on '__cxa_begin_catch' for objc @@ -54,10 +54,10 @@ def test_break_on_throw_and_catch(self): self.do_continue() - self.assertTrue(self.verify_stop_exception_info("signal SIGABRT")) + self.verify_stop_exception_info("signal SIGABRT") exception_info = self.get_exceptionInfo() self.assertEqual(exception_info["breakMode"], "always") - self.assertEqual(exception_info["description"], "signal SIGABRT") + self.assertIn("signal SIGABRT", exception_info["description"]) self.assertEqual(exception_info["exceptionId"], "signal") exception_details = exception_info["details"] self.assertRegex(exception_details["message"], "SomeReason") diff --git a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/Makefile b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/Makefile new file mode 100644 index 00000000000000..b27db90a40de2f --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/Makefile @@ -0,0 +1,4 @@ +C_SOURCES := main.c +CFLAGS_EXTRAS := -fsanitize=undefined -g + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py new file mode 100644 index 00000000000000..caff7dd1bedcd1 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py @@ -0,0 +1,25 @@ +""" +Test that we stop at runtime instrumentation locations. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import lldbdap_testcase + + +class TestDAP_runtime_instruments(lldbdap_testcase.DAPTestCaseBase): + @skipUnlessUndefinedBehaviorSanitizer + def test_ubsan(self): + """ + Test that we stop at ubsan. + """ + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + self.do_continue() + + self.verify_stop_exception_info("Out of bounds index") + exceptionInfo = self.get_exceptionInfo() + self.assertEqual(exceptionInfo["breakMode"], "always") + self.assertEqual("Out of bounds index", exceptionInfo["description"]) + self.assertEqual(exceptionInfo["exceptionId"], "runtime-instrumentation") + self.assertIn("main.c", exceptionInfo["details"]["stackTrace"]) diff --git a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/categories b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/categories new file mode 100644 index 00000000000000..c756cb12419455 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/categories @@ -0,0 +1 @@ +instrumentation-runtime diff --git a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/main.c b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/main.c new file mode 100644 index 00000000000000..9434b8e2d75833 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/main.c @@ -0,0 +1,5 @@ +int main(int argc, char const *argv[]) { + int data[4] = {0}; + int *p = data + 5; // ubsan + return *p; +} diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index ddf55e6fb382d0..c76fc83fa8cbee 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -8,15 +8,30 @@ #include "DAP.h" #include "DAPError.h" +#include "DAPLog.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBStream.h" +#include "lldb/API/SBStructuredData.h" +#include "lldb/API/SBThreadCollection.h" +#include "lldb/lldb-enumerations.h" +#include <utility> using namespace lldb_dap::protocol; namespace lldb_dap { +static std::string ThreadSummary(lldb::SBThread &thread) { + lldb::SBStream stream; + thread.GetDescription(stream); + for (uint32_t idx = 0; idx < thread.GetNumFrames(); idx++) { + lldb::SBFrame frame = thread.GetFrameAtIndex(idx); + frame.GetDescription(stream); + } + return {stream.GetData(), stream.GetSize()}; +} + /// Retrieves the details of the exception that caused this event to be raised. /// /// Clients should only call this request if the corresponding capability @@ -29,53 +44,78 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { return llvm::make_error<DAPError>( llvm::formatv("Invalid thread id: {}", args.threadId).str()); - ExceptionInfoResponseBody response; - response.breakMode = eExceptionBreakModeAlways; + ExceptionInfoResponseBody body; + body.breakMode = eExceptionBreakModeAlways; const lldb::StopReason stop_reason = thread.GetStopReason(); switch (stop_reason) { + case lldb::eStopReasonInstrumentation: + body.exceptionId = "runtime-instrumentation"; + break; case lldb::eStopReasonSignal: - response.exceptionId = "signal"; + body.exceptionId = "signal"; break; case lldb::eStopReasonBreakpoint: { const ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); if (exc_bp) { - response.exceptionId = exc_bp->GetFilter(); - response.description = exc_bp->GetLabel(); + body.exceptionId = exc_bp->GetFilter(); + body.description = exc_bp->GetLabel().str() + "\n"; } else { - response.exceptionId = "exception"; + body.exceptionId = "exception"; } } break; default: - response.exceptionId = "exception"; + body.exceptionId = "exception"; } lldb::SBStream stream; - if (response.description.empty()) { - if (thread.GetStopDescription(stream)) { - response.description = {stream.GetData(), stream.GetSize()}; - } - } + if (thread.GetStopDescription(stream)) + body.description += {stream.GetData(), stream.GetSize()}; if (lldb::SBValue exception = thread.GetCurrentException()) { + body.details = ExceptionDetails{}; + if (const char *name = exception.GetName()) + body.details->evaluateName = name; + if (const char *typeName = exception.GetDisplayTypeName()) + body.details->typeName = typeName; + stream.Clear(); - response.details = ExceptionDetails{}; - if (exception.GetDescription(stream)) { - response.details->message = {stream.GetData(), stream.GetSize()}; - } + if (exception.GetDescription(stream)) + body.details->message = {stream.GetData(), stream.GetSize()}; if (lldb::SBThread exception_backtrace = - thread.GetCurrentExceptionBacktrace()) { - stream.Clear(); - exception_backtrace.GetDescription(stream); + thread.GetCurrentExceptionBacktrace()) + body.details->stackTrace = ThreadSummary(exception_backtrace); + } - for (uint32_t idx = 0; idx < exception_backtrace.GetNumFrames(); idx++) { - lldb::SBFrame frame = exception_backtrace.GetFrameAtIndex(idx); - frame.GetDescription(stream); - } - response.details->stackTrace = {stream.GetData(), stream.GetSize()}; + lldb::SBStructuredData crash_info = + dap.target.GetProcess().GetExtendedCrashInformation(); + stream.Clear(); + if (crash_info.IsValid() && crash_info.GetDescription(stream)) + body.description += "\n\nExtended Crash Information:\n" + + std::string(stream.GetData(), stream.GetSize()); + + for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) { + lldb::InstrumentationRuntimeType type = + static_cast<lldb::InstrumentationRuntimeType>(idx); + if (!dap.target.GetProcess().IsInstrumentationRuntimePresent(type)) + continue; + lldb::SBThreadCollection threads = + thread.GetStopReasonExtendedBacktraces(type); + for (uint32_t tidx = 0; tidx < threads.GetSize(); tidx++) { + auto thread = threads.GetThreadAtIndex(tidx); + if (!thread) + continue; + ExceptionDetails details; + details.stackTrace = ThreadSummary(thread); + if (!body.details) + body.details = std::move(details); + else + body.details->innerException.emplace_back(std::move(details)); } } - return response; + + return body; } + } // namespace lldb_dap >From 4b209449608a5e394af5ee603c81f3539f756e8d Mon Sep 17 00:00:00 2001 From: John Harrison <[email protected]> Date: Fri, 16 Jan 2026 11:53:39 -0800 Subject: [PATCH 2/4] Fixing tests after splitting up the PR. --- .../breakpoint/TestDAP_setExceptionBreakpoints.py | 8 ++------ .../lldb-dap/exception/objc/TestDAP_exception_objc.py | 2 +- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py index 684726c927bc11..5ed7e13fd0b447 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint/TestDAP_setExceptionBreakpoints.py @@ -35,9 +35,5 @@ def test_functionality(self): if response: self.assertTrue(response["success"]) - self.continue_to_exception_breakpoint( - r"breakpoint \d+\.\d+", text=r"C\+\+ Throw" - ) - self.continue_to_exception_breakpoint( - r"breakpoint \d+\.\d+", text=r"C\+\+ Catch" - ) + self.continue_to_exception_breakpoint(r"C\+\+ Throw") + self.continue_to_exception_breakpoint(r"C\+\+ Catch") diff --git a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py index 40233af4b2bd6a..694cadb6ed2fed 100644 --- a/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py +++ b/lldb/test/API/tools/lldb-dap/exception/objc/TestDAP_exception_objc.py @@ -44,7 +44,7 @@ def test_break_on_throw_and_catch(self): if response: self.assertTrue(response["success"]) - self.continue_to_exception_breakpoint("hit Objective-C exception") + self.continue_to_exception_breakpoint("Objective-C Throw") # FIXME: Catching objc exceptions do not appear to be working. # Xcode appears to set a breakpoint on '__cxa_begin_catch' for objc >From 967c61afb52495e34e484eab4ae45bf0f82d1c40 Mon Sep 17 00:00:00 2001 From: John Harrison <[email protected]> Date: Tue, 20 Jan 2026 14:05:04 -0800 Subject: [PATCH 3/4] Using a variable to hold the SBProcess. --- .../lldb-dap/Handler/ExceptionInfoRequestHandler.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index c76fc83fa8cbee..f4168ade754482 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -88,8 +88,11 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { body.details->stackTrace = ThreadSummary(exception_backtrace); } - lldb::SBStructuredData crash_info = - dap.target.GetProcess().GetExtendedCrashInformation(); + lldb::SBProcess process = dap.target.GetProcess(); + if (!process) + return body; + + lldb::SBStructuredData crash_info = process.GetExtendedCrashInformation(); stream.Clear(); if (crash_info.IsValid() && crash_info.GetDescription(stream)) body.description += "\n\nExtended Crash Information:\n" + @@ -98,8 +101,9 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) { lldb::InstrumentationRuntimeType type = static_cast<lldb::InstrumentationRuntimeType>(idx); - if (!dap.target.GetProcess().IsInstrumentationRuntimePresent(type)) + if (!process.IsInstrumentationRuntimePresent(type)) continue; + lldb::SBThreadCollection threads = thread.GetStopReasonExtendedBacktraces(type); for (uint32_t tidx = 0; tidx < threads.GetSize(); tidx++) { >From 48886ce8ebc79af47e446e388d925f6cc34359c6 Mon Sep 17 00:00:00 2001 From: John Harrison <[email protected]> Date: Wed, 21 Jan 2026 15:53:57 -0800 Subject: [PATCH 4/4] Improving formatting by parsing extended stack trace json. --- .../TestDAP_runtime_instruments.py | 2 +- .../Handler/ExceptionInfoRequestHandler.cpp | 92 +++++++++++++++++-- lldb/tools/lldb-dap/JSONUtils.cpp | 2 +- 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py index caff7dd1bedcd1..3fa7aca91a926c 100644 --- a/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py +++ b/lldb/test/API/tools/lldb-dap/exception/runtime-instruments/TestDAP_runtime_instruments.py @@ -20,6 +20,6 @@ def test_ubsan(self): self.verify_stop_exception_info("Out of bounds index") exceptionInfo = self.get_exceptionInfo() self.assertEqual(exceptionInfo["breakMode"], "always") - self.assertEqual("Out of bounds index", exceptionInfo["description"]) + self.assertRegex(exceptionInfo["description"], r"Out of bounds index") self.assertEqual(exceptionInfo["exceptionId"], "runtime-instrumentation") self.assertIn("main.c", exceptionInfo["details"]["stackTrace"]) diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp index f4168ade754482..5ebe62d7d389c6 100644 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp @@ -8,14 +8,18 @@ #include "DAP.h" #include "DAPError.h" -#include "DAPLog.h" #include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStructuredData.h" #include "lldb/API/SBThreadCollection.h" +#include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" +#include "lldb/lldb-types.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/JSON.h" +#include <string> #include <utility> using namespace lldb_dap::protocol; @@ -32,19 +36,56 @@ static std::string ThreadSummary(lldb::SBThread &thread) { return {stream.GetData(), stream.GetSize()}; } +struct RuntimeInstrumentReport { + std::string description; + std::string instrument; + std::string summary; + + std::string filename; + uint32_t column = LLDB_INVALID_COLUMN_NUMBER; + uint32_t line = LLDB_INVALID_LINE_NUMBER; + + // keys found on UBSan + lldb::addr_t memory = LLDB_INVALID_ADDRESS; + lldb::tid_t tid = LLDB_INVALID_THREAD_ID; + std::vector<lldb::user_id_t> trace; + + // keys found on MainThreadChecker + std::string api_name; + std::string class_name; + std::string selector; + + // FIXME: TSan, ASan, BoundsSafety +}; + +static bool fromJSON(const llvm::json::Value &Params, + RuntimeInstrumentReport &RIR, llvm::json::Path Path) { + llvm::json::ObjectMapper O(Params, Path); + return O && O.mapOptional("description", RIR.description) && + O.mapOptional("instrumentation_class", RIR.instrument) && + O.mapOptional("summary", RIR.summary) && + O.mapOptional("filename", RIR.filename) && + O.mapOptional("col", RIR.column) && O.mapOptional("line", RIR.line) && + O.mapOptional("memory", RIR.memory) && O.mapOptional("tid", RIR.tid) && + O.mapOptional("trace", RIR.trace) && + O.mapOptional("api_name", RIR.api_name) && + O.mapOptional("class_name", RIR.class_name) && + O.mapOptional("selector", RIR.selector); +} + /// Retrieves the details of the exception that caused this event to be raised. /// /// Clients should only call this request if the corresponding capability /// `supportsExceptionInfoRequest` is true. llvm::Expected<ExceptionInfoResponseBody> ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { - lldb::SBThread thread = dap.GetLLDBThread(args.threadId); if (!thread.IsValid()) return llvm::make_error<DAPError>( llvm::formatv("Invalid thread id: {}", args.threadId).str()); ExceptionInfoResponseBody body; + llvm::raw_string_ostream OS(body.description); body.breakMode = eExceptionBreakModeAlways; const lldb::StopReason stop_reason = thread.GetStopReason(); switch (stop_reason) { @@ -59,7 +100,7 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { dap.GetExceptionBPFromStopReason(thread); if (exc_bp) { body.exceptionId = exc_bp->GetFilter(); - body.description = exc_bp->GetLabel().str() + "\n"; + OS << exc_bp->GetLabel().str(); } else { body.exceptionId = "exception"; } @@ -70,7 +111,46 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { lldb::SBStream stream; if (thread.GetStopDescription(stream)) - body.description += {stream.GetData(), stream.GetSize()}; + OS << std::string{stream.GetData(), stream.GetSize()}; + + stream.Clear(); + if (thread.GetStopReasonExtendedInfoAsJSON(stream)) { + OS << "\n"; + + llvm::Expected<RuntimeInstrumentReport> report = + llvm::json::parse<RuntimeInstrumentReport>( + {stream.GetData(), stream.GetSize()}); + // If we failed to parse the extended stop reason info, attach it + // unmodified. + if (!report) { + llvm::consumeError(report.takeError()); + OS << std::string(stream.GetData(), stream.GetSize()); + } else { + if (!report->filename.empty()) { + OS << report->filename; + if (report->line != LLDB_INVALID_LINE_NUMBER) { + OS << ":" << report->line; + if (report->column != LLDB_INVALID_COLUMN_NUMBER) + OS << ":" << report->column; + } + OS << " "; + } + + OS << report->instrument; + if (!report->description.empty()) + OS << ": " << report->description; + OS << "\n"; + if (!report->summary.empty()) + OS << report->summary << "\n"; + + if (!report->api_name.empty()) + OS << "API Name: " << report->api_name << "\n"; + if (!report->class_name.empty()) + OS << "Class Name: " << report->class_name << "\n"; + if (!report->selector.empty()) + OS << "Selector: " << report->selector << "\n"; + } + } if (lldb::SBValue exception = thread.GetCurrentException()) { body.details = ExceptionDetails{}; @@ -95,8 +175,8 @@ ExceptionInfoRequestHandler::Run(const ExceptionInfoArguments &args) const { lldb::SBStructuredData crash_info = process.GetExtendedCrashInformation(); stream.Clear(); if (crash_info.IsValid() && crash_info.GetDescription(stream)) - body.description += "\n\nExtended Crash Information:\n" + - std::string(stream.GetData(), stream.GetSize()); + OS << "\nExtended Crash Information:\n" + + std::string(stream.GetData(), stream.GetSize()); for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) { lldb::InstrumentationRuntimeType type = diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 5c33c6aa591a6a..f41f3e030e6a06 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -532,7 +532,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, llvm::formatv("data breakpoint {0}", bp_id).str()); } break; case lldb::eStopReasonInstrumentation: - body.try_emplace("reason", "breakpoint"); + body.try_emplace("reason", "exception"); break; case lldb::eStopReasonProcessorTrace: body.try_emplace("reason", "processor trace"); _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
