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 01/10] [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 e4a3e1c786ffe..b2cac4dfb0e5b 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 4ca733a9a59ca..684726c927bc1 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 f044bcae41892..b92c3290ceb4c 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 6471e2b87251a..4729cbef00c11 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 ddedf7a6de8c6..40233af4b2bd6 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 0000000000000..b27db90a40de2
--- /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 0000000000000..caff7dd1bedcd
--- /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 0000000000000..c756cb1241945
--- /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 0000000000000..9434b8e2d7583
--- /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 ddf55e6fb382d..c76fc83fa8cbe 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 02/10] 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 684726c927bc1..5ed7e13fd0b44 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 40233af4b2bd6..694cadb6ed2fe 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 03/10] 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 c76fc83fa8cbe..f4168ade75448 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 04/10] 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 caff7dd1bedcd..3fa7aca91a926 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 f4168ade75448..5ebe62d7d389c 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 5c33c6aa591a6..f41f3e030e6a0 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");

>From 902f3ae8885c70f26bd579d221299821c14d7352 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Wed, 21 Jan 2026 16:39:11 -0800
Subject: [PATCH 05/10] Update
 lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp

Co-authored-by: Ebuka Ezike <[email protected]>
---
 lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index 5ebe62d7d389c..cc0b8bd88bef4 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -100,7 +100,7 @@ ExceptionInfoRequestHandler::Run(const 
ExceptionInfoArguments &args) const {
         dap.GetExceptionBPFromStopReason(thread);
     if (exc_bp) {
       body.exceptionId = exc_bp->GetFilter();
-      OS << exc_bp->GetLabel().str();
+      OS << exc_bp->GetLabel();
     } else {
       body.exceptionId = "exception";
     }

>From d24fee2a31d92c82944d625037e07ad2bac55f31 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Wed, 21 Jan 2026 17:00:20 -0800
Subject: [PATCH 06/10] Using some static helpers to isolate different
 formatting operations.

---
 .../Handler/ExceptionInfoRequestHandler.cpp   | 243 ++++++++++--------
 1 file changed, 141 insertions(+), 102 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index cc0b8bd88bef4..156842adfe66c 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -13,12 +13,14 @@
 #include "RequestHandler.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/API/SBStructuredData.h"
+#include "lldb/API/SBThread.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 "llvm/Support/raw_ostream.h"
 #include <string>
 #include <utility>
 
@@ -26,16 +28,6 @@ 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()};
-}
-
 struct RuntimeInstrumentReport {
   std::string description;
   std::string instrument;
@@ -73,130 +65,177 @@ static bool fromJSON(const llvm::json::Value &Params,
          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;
+static std::string FormatExceptionId(DAP &dap, llvm::raw_ostream &OS,
+                                     lldb::SBThread &thread) {
   const lldb::StopReason stop_reason = thread.GetStopReason();
   switch (stop_reason) {
   case lldb::eStopReasonInstrumentation:
-    body.exceptionId = "runtime-instrumentation";
-    break;
+    return "runtime-instrumentation";
   case lldb::eStopReasonSignal:
-    body.exceptionId = "signal";
-    break;
+    return "signal";
   case lldb::eStopReasonBreakpoint: {
     const ExceptionBreakpoint *exc_bp =
         dap.GetExceptionBPFromStopReason(thread);
     if (exc_bp) {
-      body.exceptionId = exc_bp->GetFilter();
       OS << exc_bp->GetLabel();
-    } else {
-      body.exceptionId = "exception";
+      return exc_bp->GetFilter().str();
     }
-  } break;
+  }
+    LLVM_FALLTHROUGH;
   default:
-    body.exceptionId = "exception";
+    return "exception";
   }
+}
 
+static void FormatDescription(llvm::raw_ostream &OS, lldb::SBThread &thread) {
   lldb::SBStream stream;
   if (thread.GetStopDescription(stream))
     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";
+static void FormatExtendedStopInfo(llvm::raw_ostream &OS,
+                                   lldb::SBThread &thread) {
+  lldb::SBStream stream;
+  if (!thread.GetStopReasonExtendedInfoAsJSON(stream))
+    return;
+
+  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());
+    return;
+  }
+
+  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";
+
+  // MainThreadChecker instrument details
+  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";
+}
+
+static void FormatCrashReport(llvm::raw_ostream &OS, lldb::SBThread &thread) {
+  lldb::SBProcess process = thread.GetProcess();
+  if (!process)
+    return;
+
+  lldb::SBStructuredData crash_info = process.GetExtendedCrashInformation();
+  if (!crash_info)
+    return;
+
+  lldb::SBStream stream;
+  if (!crash_info.GetDescription(stream))
+    return;
+
+  OS << "\nExtended Crash Information:\n"
+     << std::string(stream.GetData(), stream.GetSize());
+}
+
+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()};
+}
+
+static std::optional<ExceptionDetails> FormatException(lldb::SBThread &thread) 
{
+  lldb::SBValue exception = thread.GetCurrentException();
+  if (!exception)
+    return {};
+
+  ExceptionDetails details;
+  if (const char *name = exception.GetName())
+    details.evaluateName = name;
+  if (const char *typeName = exception.GetDisplayTypeName())
+    details.typeName = typeName;
+
+  lldb::SBStream stream;
+  if (exception.GetDescription(stream))
+    details.message = {stream.GetData(), stream.GetSize()};
+
+  if (lldb::SBThread exception_backtrace =
+          thread.GetCurrentExceptionBacktrace())
+    details.stackTrace = ThreadSummary(exception_backtrace);
+
+  return details;
+}
 
-  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;
+static void
+FormatRuntimeInstrumentStackTrace(lldb::SBThread &thread,
+                                  lldb::InstrumentationRuntimeType type,
+                                  std::optional<ExceptionDetails> &details) {
+  lldb::SBThreadCollection threads =
+      thread.GetStopReasonExtendedBacktraces(type);
+  for (uint32_t tidx = 0; tidx < threads.GetSize(); tidx++) {
+    auto thread = threads.GetThreadAtIndex(tidx);
+    if (!thread)
+      continue;
 
-    stream.Clear();
-    if (exception.GetDescription(stream))
-      body.details->message = {stream.GetData(), stream.GetSize()};
+    ExceptionDetails current_details;
+    current_details.stackTrace = ThreadSummary(thread);
 
-    if (lldb::SBThread exception_backtrace =
-            thread.GetCurrentExceptionBacktrace())
-      body.details->stackTrace = ThreadSummary(exception_backtrace);
+    if (!details)
+      details = std::move(current_details);
+    else
+      details->innerException.emplace_back(std::move(current_details));
   }
+}
+/// 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());
 
-  lldb::SBProcess process = dap.target.GetProcess();
-  if (!process)
-    return body;
+  ExceptionInfoResponseBody body;
+  llvm::raw_string_ostream OS(body.description);
 
-  lldb::SBStructuredData crash_info = process.GetExtendedCrashInformation();
-  stream.Clear();
-  if (crash_info.IsValid() && crash_info.GetDescription(stream))
-    OS << "\nExtended Crash Information:\n" +
-              std::string(stream.GetData(), stream.GetSize());
+  body.exceptionId = FormatExceptionId(dap, OS, thread);
+  body.breakMode = eExceptionBreakModeAlways;
+  body.details = FormatException(thread);
 
+  FormatDescription(OS, thread);
+  FormatExtendedStopInfo(OS, thread);
+  FormatCrashReport(OS, thread);
+
+  lldb::SBProcess process = thread.GetProcess();
   for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) {
     lldb::InstrumentationRuntimeType type =
         static_cast<lldb::InstrumentationRuntimeType>(idx);
     if (!process.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));
-    }
+    FormatRuntimeInstrumentStackTrace(thread, type, body.details);
   }
 
   return body;

>From 9b9de19a0f67106cd871af402c526c7dcec596a1 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Wed, 21 Jan 2026 17:26:48 -0800
Subject: [PATCH 07/10] Apply suggestions from code review

Co-authored-by: Jonas Devlieghere <[email protected]>
---
 lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index 156842adfe66c..da80ed56842f3 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -37,17 +37,17 @@ struct RuntimeInstrumentReport {
   uint32_t column = LLDB_INVALID_COLUMN_NUMBER;
   uint32_t line = LLDB_INVALID_LINE_NUMBER;
 
-  // keys found on UBSan
+  // Keys used by 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
+  // Keys used by MainThreadChecker.
   std::string api_name;
   std::string class_name;
   std::string selector;
 
-  // FIXME: TSan, ASan, BoundsSafety
+  // FIXME: Support TSan, ASan, BoundsSafety.
 };
 
 static bool fromJSON(const llvm::json::Value &Params,

>From 130bc5c1fd3a601159233936faf5e3d909727233 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Thu, 22 Jan 2026 12:41:53 -0800
Subject: [PATCH 08/10] Refactoring to have more specific formatters and
 creating a set of SBAPI helpers.

---
 .../Handler/ExceptionInfoRequestHandler.cpp   | 269 +++++++++++-------
 lldb/tools/lldb-dap/SBAPIExtras.h             |  78 +++++
 2 files changed, 240 insertions(+), 107 deletions(-)
 create mode 100644 lldb/tools/lldb-dap/SBAPIExtras.h

diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index da80ed56842f3..2a49248e42f45 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -11,62 +11,139 @@
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
+#include "SBAPIExtras.h"
 #include "lldb/API/SBStream.h"
 #include "lldb/API/SBStructuredData.h"
 #include "lldb/API/SBThread.h"
 #include "lldb/API/SBThreadCollection.h"
+#include "lldb/API/SBValue.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BranchProbability.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 #include <string>
-#include <utility>
 
+using namespace llvm;
+using namespace lldb_dap;
 using namespace lldb_dap::protocol;
 
-namespace lldb_dap {
+namespace {
 
-struct RuntimeInstrumentReport {
+// See `InstrumentationRuntimeUBSan::RetrieveReportData`.
+struct UBSanReport {
   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 used by UBSan.
   lldb::addr_t memory = LLDB_INVALID_ADDRESS;
   lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
   std::vector<lldb::user_id_t> trace;
+};
 
-  // Keys used by MainThreadChecker.
+// See `InstrumentationRuntimeMainThreadChecker::RetrieveReportData`.
+struct MainThreadCheckerReport {
+  std::string description;
   std::string api_name;
   std::string class_name;
   std::string selector;
-
-  // FIXME: Support TSan, ASan, BoundsSafety.
+  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
+  std::vector<lldb::addr_t> trace;
 };
 
-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);
+// FIXME: Support TSan, ASan, BoundsSafety formatting.
+
+using RuntimeInstrumentReport =
+    std::variant<UBSanReport, MainThreadCheckerReport>;
+
+static bool fromJSON(const json::Value &params, UBSanReport &report,
+                     json::Path path) {
+  json::ObjectMapper O(params, path);
+  return O.mapOptional("description", report.description) &&
+         O.mapOptional("summary", report.summary) &&
+         O.mapOptional("filename", report.filename) &&
+         O.mapOptional("col", report.column) &&
+         O.mapOptional("line", report.line) &&
+         O.mapOptional("memory_address", report.memory);
+}
+
+static bool fromJSON(const json::Value &params, MainThreadCheckerReport 
&report,
+                     json::Path path) {
+  json::ObjectMapper O(params, path);
+  return O.mapOptional("description", report.description) &&
+         O.mapOptional("api_name", report.api_name) &&
+         O.mapOptional("class_name", report.class_name) &&
+         O.mapOptional("selector", report.selector);
+}
+
+static bool fromJSON(const json::Value &params, RuntimeInstrumentReport 
&report,
+                     json::Path path) {
+  json::ObjectMapper O(params, path);
+  std::string instrumentation_class;
+  if (!O || !O.map("instrumentation_class", instrumentation_class))
+    return false;
+
+  if (instrumentation_class == "UndefinedBehaviorSanitizer") {
+    UBSanReport inner_report;
+    if (fromJSON(params, inner_report, path))
+      report = inner_report;
+    return true;
+  }
+  if (instrumentation_class == "MainThreadChecker") {
+    MainThreadCheckerReport inner_report;
+    if (fromJSON(params, inner_report, path))
+      report = inner_report;
+    return true;
+  }
+
+  // FIXME: Support additional runtime instruments with specific formatters.
+  return false;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS, UBSanReport &report) {
+  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 << " ";
+  }
+
+  if (!report.description.empty())
+    OS << report.description << "\n";
+
+  if (!report.summary.empty())
+    OS << report.summary;
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               MainThreadCheckerReport &report) {
+  if (!report.description.empty())
+    OS << report.description << "\n";
+
+  if (!report.class_name.empty())
+    OS << "Class Name: " << report.class_name << "\n";
+  if (!report.selector.empty())
+    OS << "Selector: " << report.selector << "\n";
+
+  return OS;
 }
 
-static std::string FormatExceptionId(DAP &dap, llvm::raw_ostream &OS,
-                                     lldb::SBThread &thread) {
+static raw_ostream &operator<<(raw_ostream &OS,
+                               RuntimeInstrumentReport &report) {
+  std::visit([&](auto &r) { OS << r; }, report);
+  return OS;
+}
+
+static std::string FormatExceptionId(DAP &dap, lldb::SBThread &thread) {
   const lldb::StopReason stop_reason = thread.GetStopReason();
   switch (stop_reason) {
   case lldb::eStopReasonInstrumentation:
@@ -76,10 +153,8 @@ static std::string FormatExceptionId(DAP &dap, 
llvm::raw_ostream &OS,
   case lldb::eStopReasonBreakpoint: {
     const ExceptionBreakpoint *exc_bp =
         dap.GetExceptionBPFromStopReason(thread);
-    if (exc_bp) {
-      OS << exc_bp->GetLabel();
+    if (exc_bp)
       return exc_bp->GetFilter().str();
-    }
   }
     LLVM_FALLTHROUGH;
   default:
@@ -87,81 +162,59 @@ static std::string FormatExceptionId(DAP &dap, 
llvm::raw_ostream &OS,
   }
 }
 
-static void FormatDescription(llvm::raw_ostream &OS, lldb::SBThread &thread) {
+static std::string FormatStopDescription(lldb::SBThread &thread) {
   lldb::SBStream stream;
-  if (thread.GetStopDescription(stream))
-    OS << std::string{stream.GetData(), stream.GetSize()};
+  if (!thread.GetStopDescription(stream))
+    return "";
+  std::string desc;
+  raw_string_ostream OS(desc);
+  OS << stream;
+  return desc;
 }
 
-static void FormatExtendedStopInfo(llvm::raw_ostream &OS,
-                                   lldb::SBThread &thread) {
+static std::string FormatExtendedStopInfo(lldb::SBThread &thread) {
   lldb::SBStream stream;
   if (!thread.GetStopReasonExtendedInfoAsJSON(stream))
-    return;
-
-  OS << "\n";
+    return "";
 
-  llvm::Expected<RuntimeInstrumentReport> report =
-      llvm::json::parse<RuntimeInstrumentReport>(
+  std::string stop_info;
+  raw_string_ostream OS(stop_info);
+  Expected<RuntimeInstrumentReport> report =
+      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());
-    return;
-  }
 
-  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 << " ";
+  // Check if we can improve the formatting of the raw JSON report.
+  if (report) {
+    OS << *report;
+  } else {
+    consumeError(report.takeError());
+    OS << stream;
   }
 
-  OS << report->instrument;
-  if (!report->description.empty())
-    OS << ": " << report->description;
-  OS << "\n";
-  if (!report->summary.empty())
-    OS << report->summary << "\n";
-
-  // MainThreadChecker instrument details
-  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";
+  return stop_info;
 }
 
-static void FormatCrashReport(llvm::raw_ostream &OS, lldb::SBThread &thread) {
-  lldb::SBProcess process = thread.GetProcess();
-  if (!process)
-    return;
-
-  lldb::SBStructuredData crash_info = process.GetExtendedCrashInformation();
+static std::string FormatCrashReport(lldb::SBThread &thread) {
+  lldb::SBStructuredData crash_info =
+      thread.GetProcess().GetExtendedCrashInformation();
   if (!crash_info)
-    return;
+    return "";
 
-  lldb::SBStream stream;
-  if (!crash_info.GetDescription(stream))
-    return;
+  std::string report;
+  raw_string_ostream OS(report);
+  OS << "Extended Crash Information:\n" << crash_info;
 
-  OS << "\nExtended Crash Information:\n"
-     << std::string(stream.GetData(), stream.GetSize());
+  return report;
 }
 
-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()};
+static std::string FormatStackTrace(lldb::SBThread &thread) {
+  std::string stack_trace;
+  raw_string_ostream OS(stack_trace);
+
+  for (auto frame : thread)
+    OS << frame;
+
+  return stack_trace;
 }
 
 static std::optional<ExceptionDetails> FormatException(lldb::SBThread &thread) 
{
@@ -170,18 +223,18 @@ static std::optional<ExceptionDetails> 
FormatException(lldb::SBThread &thread) {
     return {};
 
   ExceptionDetails details;
+  raw_string_ostream OS(details.message);
+
   if (const char *name = exception.GetName())
     details.evaluateName = name;
   if (const char *typeName = exception.GetDisplayTypeName())
     details.typeName = typeName;
 
-  lldb::SBStream stream;
-  if (exception.GetDescription(stream))
-    details.message = {stream.GetData(), stream.GetSize()};
+  OS << exception;
 
   if (lldb::SBThread exception_backtrace =
           thread.GetCurrentExceptionBacktrace())
-    details.stackTrace = ThreadSummary(exception_backtrace);
+    details.stackTrace = FormatStackTrace(exception_backtrace);
 
   return details;
 }
@@ -192,13 +245,9 @@ FormatRuntimeInstrumentStackTrace(lldb::SBThread &thread,
                                   std::optional<ExceptionDetails> &details) {
   lldb::SBThreadCollection threads =
       thread.GetStopReasonExtendedBacktraces(type);
-  for (uint32_t tidx = 0; tidx < threads.GetSize(); tidx++) {
-    auto thread = threads.GetThreadAtIndex(tidx);
-    if (!thread)
-      continue;
-
+  for (auto thread : threads) {
     ExceptionDetails current_details;
-    current_details.stackTrace = ThreadSummary(thread);
+    current_details.stackTrace = FormatStackTrace(thread);
 
     if (!details)
       details = std::move(current_details);
@@ -206,27 +255,35 @@ FormatRuntimeInstrumentStackTrace(lldb::SBThread &thread,
       details->innerException.emplace_back(std::move(current_details));
   }
 }
+
+} // end namespace
+
 /// 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>
+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());
+    return make_error<DAPError>(
+        formatv("Invalid thread id: {}", args.threadId).str());
 
   ExceptionInfoResponseBody body;
-  llvm::raw_string_ostream OS(body.description);
-
-  body.exceptionId = FormatExceptionId(dap, OS, thread);
   body.breakMode = eExceptionBreakModeAlways;
+  body.exceptionId = FormatExceptionId(dap, thread);
   body.details = FormatException(thread);
 
-  FormatDescription(OS, thread);
-  FormatExtendedStopInfo(OS, thread);
-  FormatCrashReport(OS, thread);
+  llvm::raw_string_ostream OS(body.description);
+  OS << FormatStopDescription(thread);
+
+  if (std::string stop_info = FormatExtendedStopInfo(thread);
+      !stop_info.empty())
+    OS << "\n\n" << stop_info;
+
+  if (std::string crash_report = FormatCrashReport(thread);
+      !crash_report.empty())
+    OS << "\n\n" << crash_report;
 
   lldb::SBProcess process = thread.GetProcess();
   for (uint32_t idx = 0; idx < lldb::eNumInstrumentationRuntimeTypes; idx++) {
@@ -240,5 +297,3 @@ ExceptionInfoRequestHandler::Run(const 
ExceptionInfoArguments &args) const {
 
   return body;
 }
-
-} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/SBAPIExtras.h 
b/lldb/tools/lldb-dap/SBAPIExtras.h
new file mode 100644
index 0000000000000..0745b2e043c21
--- /dev/null
+++ b/lldb/tools/lldb-dap/SBAPIExtras.h
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+// Extensions on SB API.
+//===----------------------------------------------------------------------===//
+
+#include "lldb/API/SBStream.h"
+#include "lldb/API/SBStructuredData.h"
+#include "lldb/API/SBThread.h"
+#include "lldb/API/SBThreadCollection.h"
+#include "lldb/API/SBValue.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <functional>
+
+namespace lldb {
+
+/// An iterator helper for iterating over various SB API containers.
+template <typename Container, typename Item, typename Index,
+          Item (Container::*Get)(Index)>
+struct iter {
+  using difference_type = Index;
+  using value_type = Item;
+
+  Container container;
+  Index index;
+
+  Item operator*() { return std::invoke(Get, container, index); }
+  void operator++() { index++; }
+  bool operator!=(const iter &other) { return index != other.index; }
+};
+
+/// SBThreadCollection thread iterator.
+using thread_iter = iter<SBThreadCollection, SBThread, size_t,
+                         &SBThreadCollection::GetThreadAtIndex>;
+inline thread_iter begin(SBThreadCollection TC) { return {TC, 0}; }
+inline thread_iter end(SBThreadCollection TC) { return {TC, TC.GetSize()}; }
+
+/// SBThread frame iterator.
+using frame_iter =
+    iter<SBThread, SBFrame, uint32_t, &SBThread::GetFrameAtIndex>;
+inline frame_iter begin(SBThread T) { return {T, 0}; }
+inline frame_iter end(SBThread T) { return {T, T.GetNumFrames()}; }
+
+// llvm::raw_ostream print helpers.
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SBStream &stream) {
+  OS << llvm::StringRef{stream.GetData(), stream.GetSize()};
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SBFrame &frame) {
+  SBStream stream;
+  if (frame.GetDescription(stream))
+    OS << stream;
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, SBValue &value) {
+  SBStream stream;
+  if (value.GetDescription(stream))
+    OS << stream;
+  return OS;
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
+                                     const SBStructuredData &data) {
+  SBStream stream;
+  if (data.GetDescription(stream))
+    OS << stream;
+  return OS;
+}
+
+} // namespace lldb

>From 6c19be9e3fd332362ee9cf3dcac2aaaf35dce938 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Fri, 23 Jan 2026 10:38:48 -0800
Subject: [PATCH 09/10] Addressing reviewer feedback.

---
 .../test/tools/lldb-dap/dap_server.py         | 10 ++++----
 .../test/tools/lldb-dap/lldbdap_testcase.py   | 20 +++++++---------
 .../Handler/ExceptionInfoRequestHandler.cpp   | 23 ++++++++-----------
 3 files changed, 21 insertions(+), 32 deletions(-)

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 d1b91f06f84aa..9ccc32f952c8d 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
@@ -41,13 +41,13 @@
 # timeout by a factor of 10 if ASAN is enabled.
 DEFAULT_TIMEOUT: Final[float] = 50 * (10 if ("ASAN_OPTIONS" in os.environ) 
else 1)
 
+
 # See lldbtest.Base.spawnSubprocess, which should help ensure any processes
 # created by the DAP client are terminated correctly when the test ends.
 class SpawnHelperCallback(Protocol):
     def __call__(
         self, executable: str, args: List[str], extra_env: List[str], **kwargs
-    ) -> subprocess.Popen:
-        ...
+    ) -> subprocess.Popen: ...
 
 
 ## DAP type references
@@ -633,7 +633,7 @@ def predicate(p: ProtocolMessage):
             self._recv_packet(predicate=predicate),
         )
 
-    def wait_for_stopped(self) -> Optional[List[Event]]:
+    def wait_for_stopped(self) -> List[Event]:
         stopped_events = []
         stopped_event = self.wait_for_event(filter=["stopped", "exited"])
         while stopped_event:
@@ -2063,9 +2063,7 @@ def main():
         level=(
             logging.DEBUG
             if opts.verbose > 1
-            else logging.INFO
-            if opts.verbose > 0
-            else logging.WARNING
+            else logging.INFO if opts.verbose > 0 else logging.WARNING
         ),
     )
 
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 b2cac4dfb0e5b..05df045be2e3e 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
@@ -211,24 +211,20 @@ def verify_all_breakpoints_hit(self, breakpoint_ids):
     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'
-        """
+        """Wait for the debuggee to stop, and verify the stop reason is
+        'exception' with the description matching 'expected_description' and
+        text match 'expected_text', if specified."""
         stopped_events = self.dap_server.wait_for_stopped()
-        self.assertIsNotNone(stopped_events, "No stopped events detected")
         for stopped_event in stopped_events:
-            if (
-                "body" not in stopped_event
-                or stopped_event["body"]["reason"] != "exception"
-            ):
+            body = stopped_event["body"]
+            if body["reason"] != "exception":
                 continue
             self.assertIn(
                 "description",
-                stopped_event["body"],
+                body,
                 f"stopped event missing description {stopped_event}",
             )
-            description = stopped_event["body"]["description"]
+            description = body["description"]
             self.assertRegex(
                 description,
                 expected_description,
@@ -236,7 +232,7 @@ def verify_stop_exception_info(
             )
             if expected_text:
                 self.assertRegex(
-                    stopped_event["body"]["text"],
+                    body["text"],
                     expected_text,
                     f"for stopped event {stopped_event!r}",
                 )
diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index 2a49248e42f45..ab171ed44f590 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -19,7 +19,6 @@
 #include "lldb/API/SBValue.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-enumerations.h"
-#include "lldb/lldb-types.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/BranchProbability.h"
 #include "llvm/Support/Error.h"
@@ -40,9 +39,6 @@ struct UBSanReport {
   std::string filename;
   uint32_t column = LLDB_INVALID_COLUMN_NUMBER;
   uint32_t line = LLDB_INVALID_LINE_NUMBER;
-  lldb::addr_t memory = LLDB_INVALID_ADDRESS;
-  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
-  std::vector<lldb::user_id_t> trace;
 };
 
 // See `InstrumentationRuntimeMainThreadChecker::RetrieveReportData`.
@@ -51,8 +47,6 @@ struct MainThreadCheckerReport {
   std::string api_name;
   std::string class_name;
   std::string selector;
-  lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
-  std::vector<lldb::addr_t> trace;
 };
 
 // FIXME: Support TSan, ASan, BoundsSafety formatting.
@@ -67,8 +61,7 @@ static bool fromJSON(const json::Value &params, UBSanReport 
&report,
          O.mapOptional("summary", report.summary) &&
          O.mapOptional("filename", report.filename) &&
          O.mapOptional("col", report.column) &&
-         O.mapOptional("line", report.line) &&
-         O.mapOptional("memory_address", report.memory);
+         O.mapOptional("line", report.line);
 }
 
 static bool fromJSON(const json::Value &params, MainThreadCheckerReport 
&report,
@@ -89,15 +82,17 @@ static bool fromJSON(const json::Value &params, 
RuntimeInstrumentReport &report,
 
   if (instrumentation_class == "UndefinedBehaviorSanitizer") {
     UBSanReport inner_report;
-    if (fromJSON(params, inner_report, path))
-      report = inner_report;
-    return true;
+    bool success = fromJSON(params, inner_report, path);
+    if (success)
+      report = std::move(inner_report);
+    return success;
   }
   if (instrumentation_class == "MainThreadChecker") {
     MainThreadCheckerReport inner_report;
-    if (fromJSON(params, inner_report, path))
-      report = inner_report;
-    return true;
+    bool success = fromJSON(params, inner_report, path);
+    if (success)
+      report = std::move(inner_report);
+    return success;
   }
 
   // FIXME: Support additional runtime instruments with specific formatters.

>From 76b2094b90e10baf80606a8fe82d001434d1e520 Mon Sep 17 00:00:00 2001
From: John Harrison <[email protected]>
Date: Fri, 23 Jan 2026 10:42:57 -0800
Subject: [PATCH 10/10] Applying python formatting.

---
 .../Python/lldbsuite/test/tools/lldb-dap/dap_server.py     | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

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 9ccc32f952c8d..30409252e2c92 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
@@ -47,7 +47,8 @@
 class SpawnHelperCallback(Protocol):
     def __call__(
         self, executable: str, args: List[str], extra_env: List[str], **kwargs
-    ) -> subprocess.Popen: ...
+    ) -> subprocess.Popen:
+        ...
 
 
 ## DAP type references
@@ -2063,7 +2064,9 @@ def main():
         level=(
             logging.DEBUG
             if opts.verbose > 1
-            else logging.INFO if opts.verbose > 0 else logging.WARNING
+            else logging.INFO
+            if opts.verbose > 0 
+            else logging.WARNING
         ),
     )
 

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to