Skip to content

Conversation

@da-viper
Copy link
Contributor

It also separates the ProtocolRequestsTests from ProtocolTypesTests as I did not want to increase the work in #144595

@llvmbot
Copy link
Member

llvmbot commented Oct 20, 2025

@llvm/pr-subscribers-lldb

Author: Ebuka Ezike (da-viper)

Changes

It also separates the ProtocolRequestsTests from ProtocolTypesTests as I did not want to increase the work in #144595


Patch is 20.28 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/164318.diff

11 Files Affected:

  • (modified) lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp (+59-151)
  • (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+7-3)
  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp (+18)
  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolRequests.h (+22)
  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp (+33)
  • (modified) lldb/tools/lldb-dap/Protocol/ProtocolTypes.h (+30)
  • (modified) lldb/unittests/DAP/CMakeLists.txt (+1)
  • (added) lldb/unittests/DAP/ProtocolRequestsTest.cpp (+69)
  • (modified) lldb/unittests/DAP/ProtocolTypesTest.cpp (+48)
  • (modified) lldb/unittests/TestingSupport/TestUtilities.cpp (+5)
  • (modified) lldb/unittests/TestingSupport/TestUtilities.h (+4)
diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
index c1c2adb32a510..a1aa3865617f0 100644
--- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp
@@ -7,168 +7,76 @@
 //===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "EventHelper.h"
-#include "JSONUtils.h"
+#include "DAPError.h"
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBStream.h"
 
+using namespace lldb_dap::protocol;
+
 namespace lldb_dap {
 
-// "ExceptionInfoRequest": {
-//   "allOf": [ { "$ref": "#/definitions/Request" }, {
-//     "type": "object",
-//     "description": "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.",
-//     "properties": {
-//       "command": {
-//         "type": "string",
-//         "enum": [ "exceptionInfo" ]
-//       },
-//       "arguments": {
-//         "$ref": "#/definitions/ExceptionInfoArguments"
-//       }
-//     },
-//     "required": [ "command", "arguments"  ]
-//   }]
-// },
-// "ExceptionInfoArguments": {
-//   "type": "object",
-//   "description": "Arguments for `exceptionInfo` request.",
-//   "properties": {
-//     "threadId": {
-//       "type": "integer",
-//       "description": "Thread for which exception information should be
-//       retrieved."
-//     }
-//   },
-//   "required": [ "threadId" ]
-// },
-// "ExceptionInfoResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to `exceptionInfo` request.",
-//     "properties": {
-//       "body": {
-//         "type": "object",
-//         "properties": {
-//           "exceptionId": {
-//             "type": "string",
-//             "description": "ID of the exception that was thrown."
-//           },
-//           "description": {
-//             "type": "string",
-//             "description": "Descriptive text for the exception."
-//           },
-//           "breakMode": {
-//          "$ref": "#/definitions/ExceptionBreakMode",
-//            "description": "Mode that caused the exception notification to
-//            be raised."
-//           },
-//           "details": {
-//             "$ref": "#/definitions/ExceptionDetails",
-//            "description": "Detailed information about the exception."
-//           }
-//         },
-//         "required": [ "exceptionId", "breakMode" ]
-//       }
-//     },
-//     "required": [ "body" ]
-//   }]
-// }
-// "ExceptionDetails": {
-//   "type": "object",
-//   "description": "Detailed information about an exception that has
-//   occurred.", "properties": {
-//     "message": {
-//       "type": "string",
-//       "description": "Message contained in the exception."
-//     },
-//     "typeName": {
-//       "type": "string",
-//       "description": "Short type name of the exception object."
-//     },
-//     "fullTypeName": {
-//       "type": "string",
-//       "description": "Fully-qualified type name of the exception object."
-//     },
-//     "evaluateName": {
-//       "type": "string",
-//       "description": "An expression that can be evaluated in the current
-//       scope to obtain the exception object."
-//     },
-//     "stackTrace": {
-//       "type": "string",
-//       "description": "Stack trace at the time the exception was thrown."
-//     },
-//     "innerException": {
-//       "type": "array",
-//       "items": {
-//         "$ref": "#/definitions/ExceptionDetails"
-//       },
-//       "description": "Details of the exception contained by this exception,
-//       if any."
-//     }
-//   }
-// },
-void ExceptionInfoRequestHandler::operator()(
-    const llvm::json::Object &request) const {
-  llvm::json::Object response;
-  FillResponse(request, response);
-  const auto *arguments = request.getObject("arguments");
-  llvm::json::Object body;
-  lldb::SBThread thread = dap.GetLLDBThread(*arguments);
-  if (thread.IsValid()) {
-    auto stopReason = thread.GetStopReason();
-    if (stopReason == lldb::eStopReasonSignal)
-      body.try_emplace("exceptionId", "signal");
-    else if (stopReason == lldb::eStopReasonBreakpoint) {
-      ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
-      if (exc_bp) {
-        EmplaceSafeString(body, "exceptionId", exc_bp->GetFilter());
-        EmplaceSafeString(body, "description", exc_bp->GetLabel());
-      } else {
-        body.try_emplace("exceptionId", "exception");
-      }
+/// 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 response;
+  response.breakMode = eExceptionBreakModeAlways;
+  lldb::StopReason stop_reason = thread.GetStopReason();
+  switch (stop_reason) {
+  case lldb::eStopReasonSignal:
+    response.exceptionId = "signal";
+    break;
+  case lldb::eStopReasonBreakpoint: {
+    ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
+    if (exc_bp) {
+      response.exceptionId = exc_bp->GetFilter();
+      response.description = exc_bp->GetLabel();
     } else {
-      body.try_emplace("exceptionId", "exception");
+      response.exceptionId = "exception";
     }
-    if (!ObjectContainsKey(body, "description")) {
-      char description[1024];
-      if (thread.GetStopDescription(description, sizeof(description))) {
-        EmplaceSafeString(body, "description", description);
-      }
+  } break;
+  default:
+    response.exceptionId = "exception";
+  }
+
+  if (response.description.empty()) {
+    const size_t buffer_size = thread.GetStopDescription(nullptr, 0);
+    if (buffer_size > 0) {
+      std::string &buffer = response.description;
+      buffer.resize(buffer_size);
+      thread.GetStopDescription(buffer.data(), buffer.size());
     }
-    body.try_emplace("breakMode", "always");
-    auto exception = thread.GetCurrentException();
-    if (exception.IsValid()) {
-      llvm::json::Object details;
-      lldb::SBStream stream;
-      if (exception.GetDescription(stream)) {
-        EmplaceSafeString(details, "message", stream.GetData());
-      }
+  }
 
-      auto exceptionBacktrace = thread.GetCurrentExceptionBacktrace();
-      if (exceptionBacktrace.IsValid()) {
-        lldb::SBStream stream;
-        exceptionBacktrace.GetDescription(stream);
-        for (uint32_t i = 0; i < exceptionBacktrace.GetNumFrames(); i++) {
-          lldb::SBFrame frame = exceptionBacktrace.GetFrameAtIndex(i);
-          frame.GetDescription(stream);
-        }
-        EmplaceSafeString(details, "stackTrace", stream.GetData());
-      }
+  if (lldb::SBValue exception = thread.GetCurrentException()) {
+    lldb::SBStream stream;
+    response.details = ExceptionDetails{};
+    if (exception.GetDescription(stream)) {
+      response.details->message = stream.GetData();
+    }
+
+    if (lldb::SBThread exception_backtrace =
+            thread.GetCurrentExceptionBacktrace()) {
+      stream.Clear();
+      exception_backtrace.GetDescription(stream);
 
-      body.try_emplace("details", std::move(details));
+      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();
     }
-    // auto excInfoCount = thread.GetStopReasonDataCount();
-    // for (auto i=0; i<excInfoCount; ++i) {
-    //   uint64_t exc_data = thread.GetStopReasonDataAtIndex(i);
-    // }
-  } else {
-    response["success"] = llvm::json::Value(false);
   }
-  response.try_emplace("body", std::move(body));
-  dap.SendJSON(llvm::json::Value(std::move(response)));
+  return response;
 }
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 977a247996750..7a7e1263c66f4 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -302,14 +302,18 @@ class EvaluateRequestHandler : public LegacyRequestHandler {
   }
 };
 
-class ExceptionInfoRequestHandler : public LegacyRequestHandler {
+class ExceptionInfoRequestHandler
+    : public RequestHandler<
+          protocol::ExceptionInfoArguments,
+          llvm::Expected<protocol::ExceptionInfoResponseBody>> {
 public:
-  using LegacyRequestHandler::LegacyRequestHandler;
+  using RequestHandler::RequestHandler;
   static llvm::StringLiteral GetCommand() { return "exceptionInfo"; }
   FeatureSet GetSupportedFeatures() const override {
     return {protocol::eAdapterFeatureExceptionInfoRequest};
   }
-  void operator()(const llvm::json::Object &request) const override;
+  llvm::Expected<protocol::ExceptionInfoResponseBody>
+  Run(const protocol::ExceptionInfoArguments &args) const override;
 };
 
 class InitializeRequestHandler
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index b9393356b4e01..e207aad2167d6 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -625,4 +625,22 @@ llvm::json::Value toJSON(const ModuleSymbolsResponseBody &DGMSR) {
   return result;
 }
 
+bool fromJSON(const json::Value &Params, ExceptionInfoArguments &Args,
+              json::Path Path) {
+  json::ObjectMapper O(Params, Path);
+  return O && O.map("threadId", Args.threadId);
+}
+
+json::Value toJSON(const ExceptionInfoResponseBody &ERB) {
+  json::Object result{{"exceptionId", ERB.exceptionId},
+                      {"breakMode", ERB.breakMode}};
+
+  if (!ERB.description.empty())
+    result.insert({"description", ERB.description.c_str()});
+  if (ERB.details.has_value())
+    result.insert({"details", *ERB.details});
+
+  return result;
+}
+
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index a85a68b87014c..53e551ac2ec64 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -1039,6 +1039,28 @@ struct ModuleSymbolsResponseBody {
 };
 llvm::json::Value toJSON(const ModuleSymbolsResponseBody &);
 
+struct ExceptionInfoArguments {
+  /// Thread for which exception information should be retrieved.
+  lldb::tid_t threadId = LLDB_INVALID_THREAD_ID;
+};
+bool fromJSON(const llvm::json::Value &, ExceptionInfoArguments &,
+              llvm::json::Path);
+
+struct ExceptionInfoResponseBody {
+  /// ID of the exception that was thrown.
+  std::string exceptionId;
+
+  /// Descriptive text for the exception.
+  std::string description;
+
+  /// Mode that caused the exception notification to be raised.
+  ExceptionBreakMode breakMode;
+
+  /// Detailed information about the exception.
+  std::optional<ExceptionDetails> details;
+};
+llvm::json::Value toJSON(const ExceptionInfoResponseBody &);
+
 } // namespace lldb_dap::protocol
 
 #endif
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index dc8edaadcd9bb..95007013742a0 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -1136,4 +1136,37 @@ bool fromJSON(const json::Value &Param, Variable &V, json::Path Path) {
                                Path, /*required=*/false);
 }
 
+json::Value toJSON(const ExceptionBreakMode Mode) {
+  switch (Mode) {
+  case eExceptionBreakModeNever:
+    return "never";
+  case eExceptionBreakModeAlways:
+    return "always";
+  case eExceptionBreakModeUnhandled:
+    return "unhandled";
+  case eExceptionBreakModeUserUnhandled:
+    return "userUnhandled";
+  }
+  llvm_unreachable("unhandled exception breakMode.");
+}
+
+json::Value toJSON(const ExceptionDetails &ED) {
+  json::Object result;
+
+  if (!ED.message.empty())
+    result.insert({"message", ED.message});
+  if (!ED.typeName.empty())
+    result.insert({"typeName", ED.typeName});
+  if (!ED.fullTypeName.empty())
+    result.insert({"fullTypeName", ED.fullTypeName});
+  if (!ED.evaluateName.empty())
+    result.insert({"evaluateName", ED.evaluateName});
+  if (!ED.stackTrace.empty())
+    result.insert({"stackTrace", ED.stackTrace});
+  if (!ED.innerException.empty())
+    result.insert({"innerException", ED.innerException});
+
+  return result;
+}
+
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 7077df90a85b5..6d85c74377bd3 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -1007,6 +1007,36 @@ struct Variable {
 llvm::json::Value toJSON(const Variable &);
 bool fromJSON(const llvm::json::Value &, Variable &, llvm::json::Path);
 
+enum ExceptionBreakMode : unsigned {
+  eExceptionBreakModeNever,
+  eExceptionBreakModeAlways,
+  eExceptionBreakModeUnhandled,
+  eExceptionBreakModeUserUnhandled,
+};
+llvm::json::Value toJSON(ExceptionBreakMode);
+
+struct ExceptionDetails {
+  /// Message contained in the exception.
+  std::string message;
+
+  /// Short type name of the exception object.
+  std::string typeName;
+
+  /// Fully-qualified type name of the exception object.
+  std::string fullTypeName;
+
+  /// An expression that can be evaluated in the current scope to obtain the
+  /// exception object.
+  std::string evaluateName;
+
+  /// Stack trace at the time the exception was thrown.
+  std::string stackTrace;
+
+  /// Details of the exception contained by this exception, if any.
+  std::vector<ExceptionDetails> innerException;
+};
+llvm::json::Value toJSON(const ExceptionDetails &);
+
 } // namespace lldb_dap::protocol
 
 #endif
diff --git a/lldb/unittests/DAP/CMakeLists.txt b/lldb/unittests/DAP/CMakeLists.txt
index a08414c30e6cd..434f5280a97a0 100644
--- a/lldb/unittests/DAP/CMakeLists.txt
+++ b/lldb/unittests/DAP/CMakeLists.txt
@@ -7,6 +7,7 @@ add_lldb_unittest(DAPTests
   Handler/ContinueTest.cpp
   JSONUtilsTest.cpp
   LLDBUtilsTest.cpp
+  ProtocolRequestsTest.cpp
   ProtocolTypesTest.cpp
   ProtocolUtilsTest.cpp
   TestBase.cpp
diff --git a/lldb/unittests/DAP/ProtocolRequestsTest.cpp b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
new file mode 100644
index 0000000000000..6b0a794ad72f2
--- /dev/null
+++ b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
@@ -0,0 +1,69 @@
+//===-- ProtocolRequestsTest.cpp ------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "Protocol/ProtocolRequests.h"
+#include "Protocol/ProtocolTypes.h"
+#include "TestingSupport/TestUtilities.h"
+#include "llvm/Testing/Support/Error.h"
+#include <gtest/gtest.h>
+
+using namespace llvm;
+using namespace lldb_dap::protocol;
+using lldb_private::pprint;
+using llvm::json::parse;
+
+TEST(ProtocolRequestsTest, ExceptionInfoArguments) {
+  llvm::Expected<ExceptionInfoArguments> expected =
+      parse<ExceptionInfoArguments>(R"({
+        "threadId": 3434
+        })");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_EQ(expected->threadId, 3434U);
+
+  // Check required keys;
+  EXPECT_THAT_EXPECTED(parse<ExceptionInfoArguments>(R"({})"),
+                       FailedWithMessage("missing value at (root).threadId"));
+
+  EXPECT_THAT_EXPECTED(parse<ExceptionInfoArguments>(R"({"id": 10})"),
+                       FailedWithMessage("missing value at (root).threadId"));
+}
+
+TEST(ProtocolRequestsTest, ExceptionInfoResponseBody) {
+  ExceptionInfoResponseBody body;
+  body.exceptionId = "signal";
+  body.breakMode = eExceptionBreakModeAlways;
+
+  // Check required keys.
+  Expected<json::Value> expected = parse(
+      R"({
+    "exceptionId": "signal",
+    "breakMode": "always"
+    })");
+
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_EQ(pprint(*expected), pprint(body));
+
+  // Check optional keys.
+  body.description = "SIGNAL SIGWINCH";
+  body.breakMode = eExceptionBreakModeNever;
+  body.details = ExceptionDetails{};
+  body.details->message = "some message";
+
+  Expected<json::Value> expected_opt = parse(
+      R"({
+    "exceptionId": "signal",
+    "description": "SIGNAL SIGWINCH",
+    "breakMode": "never",
+    "details": {
+      "message": "some message"
+    }
+  })");
+
+  ASSERT_THAT_EXPECTED(expected_opt, llvm::Succeeded());
+  EXPECT_EQ(pprint(*expected_opt), pprint(body));
+}
diff --git a/lldb/unittests/DAP/ProtocolTypesTest.cpp b/lldb/unittests/DAP/ProtocolTypesTest.cpp
index a5ae856a185b7..ee638f8f18cf3 100644
--- a/lldb/unittests/DAP/ProtocolTypesTest.cpp
+++ b/lldb/unittests/DAP/ProtocolTypesTest.cpp
@@ -1126,3 +1126,51 @@ TEST(ProtocolTypesTest, DataBreakpointInfoArguments) {
   EXPECT_THAT_EXPECTED(parse<DataBreakpointInfoArguments>(R"({"name":"data"})"),
                        llvm::Succeeded());
 }
+
+TEST(ProtocolTypesTest, ExceptionBreakMode) {
+  const std::vector<std::pair<ExceptionBreakMode, llvm::StringRef>> test_cases =
+      {{ExceptionBreakMode::eExceptionBreakModeAlways, "always"},
+       {ExceptionBreakMode::eExceptionBreakModeNever, "never"},
+       {ExceptionBreakMode::eExceptionBreakModeUnhandled, "unhandled"},
+       {ExceptionBreakMode::eExceptionBreakModeUserUnhandled, "userUnhandled"}};
+
+  for (const auto [value, expected] : test_cases) {
+    json::Value const serialized = toJSON(value);
+    ASSERT_EQ(serialized.kind(), llvm::json::Value::Kind::String);
+    EXPECT_EQ(serialized.getAsString(), expected);
+
+  }
+}
+
+TEST(ProtocolTypesTest, ExceptionDetails) {
+  ExceptionDetails details;
+
+  // Check required keys.
+  Expected<json::Value> expected = parse(R"({})");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_EQ(pp(*expected), pp(details));
+
+  // Check optional keys.
+  details.message = "SIGABRT exception";
+  details.typeName = "signal";
+  details.fullTypeName = "SIGABRT";
+  details.evaluateName = "process handle SIGABRT";
+  details.stackTrace = "some stacktrace";
+  ExceptionDetails inner_details;
+  inner_details.message = "inner message";
+  details.innerException = {std::move(inner_details)};
+
+  Expected<json::Value> expected_opt = parse(R"({
+    "message": "SIGABRT exception",
+    "typeName": "signal",
+    "fullTypeName": "SIGABRT",
+    "evaluateName": "process handle SIGABRT",
+    "stackTrace": "some stacktrace",
+    "innerException": [{
+      "message": "inner message"
+    }]
+    })");
+
+  ASSERT_THAT_EXPECTED(expected_opt, llvm::Succeeded());
+  EXPECT_EQ(pp(*expected_opt), pp(details));
+}
diff --git a/lldb/unittests/TestingSupport/TestUtilities.cpp b/lldb/unittests/TestingSupport/TestUtilities.cpp
index b53822e38324b..040ad1f8cab54 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.cpp
+++ b/lldb/unittests/TestingSupport/TestUtilities.cpp
@@ -20,6 +20,11 @@ using namespace lldb_private;
 extern const char *TestMainArgv0;
 
 std::once_flag TestUtilities::g_debugger_initialize_flag;
+
+std::string lldb_private::pprint(const llvm::json::Value &value) {
+  return llvm::formatv("{0:2}", value).str();
+}
+
 std::string lldb_private::GetInputFilePath(const llvm::Twine &name) {
   llvm::SmallString<128> result = llvm::sys::path::parent_path(TestMainArgv0);
   llvm::sys::fs::make_absolute(result);
diff --git a/lldb/unittests/TestingSupport/TestUtilities.h b/lldb/unittests/TestingSupport/TestUtilities.h
index cc93a68a6a431..751fa415c9a94 100644
--- a/lldb/unittests/TestingSupport/TestUtilities.h
+++ b/lldb/unittes...
[truncated]

@github-actions
Copy link

github-actions bot commented Oct 20, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Member

@JDevlieghere JDevlieghere left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

namespace lldb_private {

/// Returns a pretty printed json string of a `llvm::json::Value`.
std::string pprint(const llvm::json::Value &E);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd call this PrettyPrint, makes it immediately obvious what it does.

Suggested change
std::string pprint(const llvm::json::Value &E);
std::string PrettyPrint(const llvm::json::Value &E);

@da-viper da-viper merged commit b8062f8 into llvm:main Oct 22, 2025
10 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Oct 22, 2025

LLVM Buildbot has detected a new failure on builder lldb-arm-ubuntu running on linaro-lldb-arm-ubuntu while building lldb at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/18/builds/22154

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: tools/lldb-dap/breakpoint/TestDAP_setBreakpoints.py (1211 of 3741)
PASS: lldb-api :: tools/lldb-dap/commands/TestDAP_commands.py (1212 of 3741)
PASS: lldb-api :: tools/lldb-dap/cancel/TestDAP_cancel.py (1213 of 3741)
PASS: lldb-api :: tools/lldb-dap/completions/TestDAP_completions.py (1214 of 3741)
PASS: lldb-api :: terminal/TestEditlineCompletions.py (1215 of 3741)
PASS: lldb-api :: tools/lldb-dap/console/TestDAP_redirection_to_console.py (1216 of 3741)
PASS: lldb-api :: tools/lldb-dap/coreFile/TestDAP_coreFile.py (1217 of 3741)
PASS: lldb-api :: tools/lldb-dap/disassemble/TestDAP_disassemble.py (1218 of 3741)
PASS: lldb-api :: tools/lldb-dap/console/TestDAP_console.py (1219 of 3741)
PASS: lldb-api :: tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py (1220 of 3741)
FAIL: lldb-api :: tools/lldb-dap/exception/TestDAP_exception.py (1221 of 3741)
******************** TEST 'lldb-api :: tools/lldb-dap/exception/TestDAP_exception.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --arch armv8l --build-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/./lib --cmake-build-type Release /home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/exception -p TestDAP_exception.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f)
  clang revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f
  llvm revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f
Skipping the following test categories: ['libc++', 'msvcstl', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
/home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py:388: UserWarning: received a malformed packet, expected 'seq != 0' for {'body': {'$__lldb_version': 'lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f)\n  clang revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f\n  llvm revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f', 'completionTriggerCharacters': ['.', ' ', '\t'], 'exceptionBreakpointFilters': [{'description': 'C++ Catch', 'filter': 'cpp_catch', 'label': 'C++ Catch', 'supportsCondition': True}, {'description': 'C++ Throw', 'filter': 'cpp_throw', 'label': 'C++ Throw', 'supportsCondition': True}, {'description': 'Objective-C Catch', 'filter': 'objc_catch', 'label': 'Objective-C Catch', 'supportsCondition': True}, {'description': 'Objective-C Throw', 'filter': 'objc_throw', 'label': 'Objective-C Throw', 'supportsCondition': True}], 'supportTerminateDebuggee': True, 'supportsBreakpointLocationsRequest': True, 'supportsCancelRequest': True, 'supportsCompletionsRequest': True, 'supportsConditionalBreakpoints': True, 'supportsConfigurationDoneRequest': True, 'supportsDataBreakpoints': True, 'supportsDelayedStackTraceLoading': True, 'supportsDisassembleRequest': True, 'supportsEvaluateForHovers': True, 'supportsExceptionFilterOptions': True, 'supportsExceptionInfoRequest': True, 'supportsFunctionBreakpoints': True, 'supportsHitConditionalBreakpoints': True, 'supportsInstructionBreakpoints': True, 'supportsLogPoints': True, 'supportsModuleSymbolsRequest': True, 'supportsModulesRequest': True, 'supportsReadMemoryRequest': True, 'supportsSetVariable': True, 'supportsSteppingGranularity': True, 'supportsValueFormattingOptions': True, 'supportsWriteMemoryRequest': True}, 'command': 'initialize', 'request_seq': 1, 'seq': 0, 'success': True, 'type': 'response'}
  warnings.warn(
========= DEBUG ADAPTER PROTOCOL LOGS =========
1761138647.373938799 (stdio) --> {"command":"initialize","type":"request","arguments":{"adapterID":"lldb-native","clientID":"vscode","columnsStartAt1":true,"linesStartAt1":true,"locale":"en-us","pathFormat":"path","supportsRunInTerminalRequest":true,"supportsVariablePaging":true,"supportsVariableType":true,"supportsStartDebuggingRequest":true,"supportsProgressReporting":true,"supportsInvalidatedEvent":true,"supportsMemoryEvent":true,"$__lldb_sourceInitFile":false},"seq":1}
1761138647.374234200 (stdio) queued (command=initialize seq=1)
1761138647.380488396 (stdio) <-- {"body":{"$__lldb_version":"lldb version 22.0.0git (https://github.com/llvm/llvm-project.git revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f)\n  clang revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f\n  llvm revision b8062f85dd3612f2b5c0c5cfc14bdc5c0eae641f","completionTriggerCharacters":["."," ","\t"],"exceptionBreakpointFilters":[{"description":"C++ Catch","filter":"cpp_catch","label":"C++ Catch","supportsCondition":true},{"description":"C++ Throw","filter":"cpp_throw","label":"C++ Throw","supportsCondition":true},{"description":"Objective-C Catch","filter":"objc_catch","label":"Objective-C Catch","supportsCondition":true},{"description":"Objective-C Throw","filter":"objc_throw","label":"Objective-C Throw","supportsCondition":true}],"supportTerminateDebuggee":true,"supportsBreakpointLocationsRequest":true,"supportsCancelRequest":true,"supportsCompletionsRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsDataBreakpoints":true,"supportsDelayedStackTraceLoading":true,"supportsDisassembleRequest":true,"supportsEvaluateForHovers":true,"supportsExceptionFilterOptions":true,"supportsExceptionInfoRequest":true,"supportsFunctionBreakpoints":true,"supportsHitConditionalBreakpoints":true,"supportsInstructionBreakpoints":true,"supportsLogPoints":true,"supportsModuleSymbolsRequest":true,"supportsModulesRequest":true,"supportsReadMemoryRequest":true,"supportsSetVariable":true,"supportsSteppingGranularity":true,"supportsValueFormattingOptions":true,"supportsWriteMemoryRequest":true},"command":"initialize","request_seq":1,"seq":0,"success":true,"type":"response"}
1761138647.383680344 (stdio) --> {"command":"launch","type":"request","arguments":{"program":"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/exception/TestDAP_exception.test_stopped_description/a.out","initCommands":["settings clear --all","settings set symbols.enable-external-lookup false","settings set target.inherit-tcc true","settings set target.disable-aslr false","settings set target.detach-on-error false","settings set target.auto-apply-fixits false","settings set plugin.process.gdb-remote.packet-timeout 60","settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"","settings set use-color false","settings set show-statusline false"],"disableASLR":false,"enableAutoVariableSummaries":false,"enableSyntheticChildDebugging":false,"displayExtendedBacktrace":false},"seq":2}
1761138647.384313583 (stdio) queued (command=launch seq=2)
1761138647.385146856 (stdio) <-- {"body":{"category":"console","output":"Running initCommands:\n"},"event":"output","seq":1,"type":"event"}
1761138647.385210276 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings clear --all\n"},"event":"output","seq":2,"type":"event"}
1761138647.385227442 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set symbols.enable-external-lookup false\n"},"event":"output","seq":3,"type":"event"}
1761138647.385246277 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.inherit-tcc true\n"},"event":"output","seq":4,"type":"event"}
1761138647.385260105 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.disable-aslr false\n"},"event":"output","seq":5,"type":"event"}
1761138647.385273695 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.detach-on-error false\n"},"event":"output","seq":6,"type":"event"}
1761138647.385309696 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set target.auto-apply-fixits false\n"},"event":"output","seq":7,"type":"event"}
1761138647.385324478 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set plugin.process.gdb-remote.packet-timeout 60\n"},"event":"output","seq":8,"type":"event"}
1761138647.385341644 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"\n"},"event":"output","seq":9,"type":"event"}
1761138647.385361671 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set use-color false\n"},"event":"output","seq":10,"type":"event"}
1761138647.385374784 (stdio) <-- {"body":{"category":"console","output":"(lldb) settings set show-statusline false\n"},"event":"output","seq":11,"type":"event"}
1761138647.738399267 (stdio) <-- {"command":"launch","request_seq":2,"seq":12,"success":true,"type":"response"}
1761138647.738563061 (stdio) <-- {"event":"initialized","seq":13,"type":"event"}

googlewalt added a commit that referenced this pull request Oct 22, 2025
googlewalt added a commit that referenced this pull request Oct 22, 2025
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Oct 22, 2025
@DavidSpickett
Copy link
Collaborator

The important part of the Arm 32-bit failure:

========= END =========
FAIL: LLDB (/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/clang-arm) :: test_stopped_description (TestDAP_exception.TestDAP_exception)
======================================================================
FAIL: test_stopped_description (TestDAP_exception.TestDAP_exception)
   Test that exception description is shown correctly in stopped
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py", line 24, in test_stopped_description
    self.assertEqual(exceptionInfo["description"], "signal SIGABRT")
AssertionError: '\x01ignal SIGABRT' != 'signal SIGABRT'
- �ignal SIGABRT
? ^
+ signal SIGABRT
? ^

Config=arm-/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/clang
----------------------------------------------------------------------
Ran 1 test in 1.452s

And:

========= END =========
FAIL: LLDB (/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/clang-arm) :: test_stopped_description (TestDAP_exception_cpp.TestDAP_exception_cpp)
======================================================================
FAIL: test_stopped_description (TestDAP_exception_cpp.TestDAP_exception_cpp)
   Test that exception description is shown correctly in stopped
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-arm-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py", line 24, in test_stopped_description
    self.assertEqual(exceptionInfo["description"], "signal SIGABRT")
AssertionError: '\x01ignal SIGABRT' != 'signal SIGABRT'
- �ignal SIGABRT
? ^
+ signal SIGABRT
? ^

Config=arm-/home/tcwg-buildbot/worker/lldb-arm-ubuntu/build/bin/clang
----------------------------------------------------------------------
Ran 1 test in 1.909s

@Michael137
Copy link
Member

Also failing on x86_64 macOS: https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake/16126/execution/node/111/log/

12:58:04  Failed Tests (3):
12:58:04    lldb-api :: tools/lldb-dap/exception/TestDAP_exception.py
12:58:04    lldb-api :: tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py
12:58:04    lldb-api :: tools/lldb-dap/exception/objc/TestDAP_exception_objc.py

Example failure:

12:43:17  ========= END =========
12:43:17  FAIL: LLDB (/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/bin/clang-x86_64) :: test_stopped_description (TestDAP_exception.TestDAP_exception)
12:43:17  Restore dir to: /Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/lldb-build/tools/lldb/test
12:43:17  ======================================================================
12:43:17  FAIL: test_stopped_description (TestDAP_exception.TestDAP_exception)
12:43:17     Test that exception description is shown correctly in stopped
12:43:17  ----------------------------------------------------------------------
12:43:17  Traceback (most recent call last):
12:43:17    File "/Users/ec2-user/jenkins/workspace/llvm.org/lldb-cmake/llvm-project/lldb/test/API/tools/lldb-dap/exception/TestDAP_exception.py", line 24, in test_stopped_description
12:43:17      self.assertEqual(exceptionInfo["description"], "signal SIGABRT")
12:43:17  AssertionError: '\x00\x00\x00\x00\x00\x00\x00\x01IGABRT' != 'signal SIGABRT'
12:43:17  - �IGABRT
12:43:17  + signal SIGABRT

Possibly also on arm64, but those bots aren't working atm.

@da-viper
Copy link
Contributor Author

It has been reverted, It seems to be something specific to how GetDescription works on arm, will test it in a container.

@DavidSpickett
Copy link
Collaborator

Does feel like an alignment assumption, which is weird for what looks like a high level change.

It passed on AArch64 Linux https://lab.llvm.org/buildbot/#/builders/59/builds/26153.

UNSUPPORTED: lldb-api :: tools/lldb-dap/exception/objc/TestDAP_exception_objc.py (1218 of 2347)
PASS: lldb-api :: tools/lldb-dap/exception/TestDAP_exception.py (1219 of 2347)
UNSUPPORTED: lldb-api :: tools/lldb-dap/extendedStackTrace/TestDAP_extendedStackTrace.py (1220 of 2347)
PASS: lldb-api :: tools/lldb-dap/exception/cpp/TestDAP_exception_cpp.py (1221 of 2347)

@Michael137
Copy link
Member

Michael137 commented Oct 22, 2025

It has been reverted, It seems to be something specific to how GetDescription works on arm, will test it in a container.

Note, the failure is on our x86_64 bot: https://green.lab.llvm.org/job/llvm.org/view/LLDB/job/lldb-cmake/16126/execution/node/111/log/

But yea could be some odd platform-specific behaviour

dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
It also separates the `ProtocolRequestsTests` from `ProtocolTypesTests`
as I did not want to increase the work in
llvm#144595
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
It also separates the `ProtocolRequestsTests` from `ProtocolTypesTests`
as I did not want to increase the work in
llvm#144595
Lukacma pushed a commit to Lukacma/llvm-project that referenced this pull request Oct 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants