[Lldb-commits] [lldb] [lldb-dap] Adding a DAPError for showing users error messages. (PR #132255)
John Harrison via lldb-commits
lldb-commits at lists.llvm.org
Thu Mar 20 12:27:03 PDT 2025
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/132255
>From a696c1c3ce5cf0f652e0a016c5d5d422b2ae24d3 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 20 Mar 2025 10:08:53 -0700
Subject: [PATCH 1/3] [lldb-dap] Adding a DAPError for showing users error
messages.
The `DAPError` can be used to craft an error message that is displayed to a user (with showUser=true).
Any request handler implementation using subclassing `RequestHandler<>` should be able to use this.
I updated SourceRequestHandler to report DAPError's specifically.
---
lldb/tools/lldb-dap/CMakeLists.txt | 1 +
lldb/tools/lldb-dap/DAPError.cpp | 26 +++++++++++++++
lldb/tools/lldb-dap/DAPError.h | 33 +++++++++++++++++++
lldb/tools/lldb-dap/Handler/RequestHandler.h | 28 ++++++++++++----
.../lldb-dap/Handler/SourceRequestHandler.cpp | 4 +--
5 files changed, 83 insertions(+), 9 deletions(-)
create mode 100644 lldb/tools/lldb-dap/DAPError.cpp
create mode 100644 lldb/tools/lldb-dap/DAPError.h
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 93c5ee4426783..e9773db7586e6 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -18,6 +18,7 @@ add_lldb_tool(lldb-dap
Breakpoint.cpp
BreakpointBase.cpp
DAP.cpp
+ DAPError.cpp
DAPLog.cpp
EventHelper.cpp
ExceptionBreakpoint.cpp
diff --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp
new file mode 100644
index 0000000000000..044c9b48d61c6
--- /dev/null
+++ b/lldb/tools/lldb-dap/DAPError.cpp
@@ -0,0 +1,26 @@
+//===-- DAPError.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 "DAPError.h"
+#include "llvm/Support/Error.h"
+#include <system_error>
+
+namespace lldb_dap {
+
+char DAPError::ID;
+
+DAPError::DAPError(std::string message, bool show_user)
+ : m_message(message), m_show_user(show_user) {}
+
+void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; }
+
+std::error_code DAPError::convertToErrorCode() const {
+ return llvm::inconvertibleErrorCode();
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h
new file mode 100644
index 0000000000000..b990bcdb5ceb0
--- /dev/null
+++ b/lldb/tools/lldb-dap/DAPError.h
@@ -0,0 +1,33 @@
+//===-- DAPError.h --------------------------------------------------------===//
+//
+// 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 "llvm/Support/Error.h"
+#include <string>
+
+namespace lldb_dap {
+
+/// An Error that is reported as a DAP Error Message, which may be presented to
+/// the user.
+class DAPError : public llvm::ErrorInfo<DAPError> {
+public:
+ static char ID;
+
+ DAPError(std::string message, bool show_user = false);
+
+ void log(llvm::raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+
+ const std::string &getMessage() const { return m_message; }
+ bool getShowUser() const { return m_show_user; }
+
+private:
+ std::string m_message;
+ bool m_show_user;
+};
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index d327820224a30..01eaf3a6cfe65 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -10,11 +10,13 @@
#define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H
#include "DAP.h"
+#include "DAPError.h"
#include "DAPLog.h"
#include "Protocol/ProtocolBase.h"
#include "Protocol/ProtocolRequests.h"
#include "lldb/API/SBError.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/JSON.h"
#include <optional>
#include <type_traits>
@@ -118,20 +120,32 @@ class RequestHandler : public BaseRequestHandler {
std::string parse_failure;
llvm::raw_string_ostream OS(parse_failure);
root.printErrorContext(request.arguments, OS);
+
+ protocol::ErrorMessage error;
+ error.format = parse_failure;
+
response.success = false;
- response.message = parse_failure;
+ response.body = std::move(error);
+
dap.Send(response);
return;
}
- auto body = Run(arguments);
- // FIXME: Add a dedicated DAPError for enhanced errors that are
- // user-visibile.
+ llvm::Expected<Body> body = Run(arguments);
if (auto Err = body.takeError()) {
+ protocol::ErrorMessage error;
+ if (llvm::Error unhandled = llvm::handleErrors(
+ std::move(Err), [&](const DAPError &E) -> llvm::Error {
+ error.format = E.getMessage();
+ error.showUser = E.getShowUser();
+ error.id = E.convertToErrorCode().value();
+ // TODO: We could add url/urlLabel to the error message for more
+ // information for users.
+ return llvm::Error::success();
+ }))
+ error.format = llvm::toString(std::move(unhandled));
response.success = false;
- // FIXME: Build ErrorMessage based on error details instead of using the
- // 'message' field.
- response.message = llvm::toString(std::move(Err));
+ response.body = std::move(error);
} else {
response.success = true;
if constexpr (!std::is_same_v<Body, std::monostate>)
diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 57cfb09692990..1a7a13d9f267a 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -29,7 +29,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
args.source->sourceReference.value_or(args.sourceReference);
if (!source)
- return llvm::createStringError(
+ return llvm::make_error<DAPError>(
"invalid arguments, expected source.sourceReference to be set");
lldb::SBProcess process = dap.target.GetProcess();
@@ -39,7 +39,7 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
// Lower 32 bits is the frame index
lldb::SBFrame frame = thread.GetFrameAtIndex(GetLLDBFrameID(source));
if (!frame.IsValid())
- return llvm::createStringError("source not found");
+ return llvm::make_error<DAPError>("source not found");
lldb::SBInstructionList insts = frame.GetSymbol().GetInstructions(dap.target);
lldb::SBStream stream;
>From b437151b9dd51429abfbca255752d1d3b561a9d3 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 20 Mar 2025 12:15:30 -0700
Subject: [PATCH 2/3] Adjusting 'showUser' to default to true for a DAPError
and adding a missing ErrorResponseBody.
---
lldb/tools/lldb-dap/Handler/RequestHandler.h | 24 ++++++++++++-------
lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 9 +++++++
lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 13 +++++++---
3 files changed, 34 insertions(+), 12 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 01eaf3a6cfe65..47bf9e178e5b4 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -121,11 +121,14 @@ class RequestHandler : public BaseRequestHandler {
llvm::raw_string_ostream OS(parse_failure);
root.printErrorContext(request.arguments, OS);
- protocol::ErrorMessage error;
- error.format = parse_failure;
+ protocol::ErrorMessage error_message;
+ error_message.format = parse_failure;
+
+ protocol::ErrorResponseBody body;
+ body.error = error_message;
response.success = false;
- response.body = std::move(error);
+ response.body = std::move(body);
dap.Send(response);
return;
@@ -133,19 +136,22 @@ class RequestHandler : public BaseRequestHandler {
llvm::Expected<Body> body = Run(arguments);
if (auto Err = body.takeError()) {
- protocol::ErrorMessage error;
+ protocol::ErrorMessage error_message;
+ error_message.sendTelemetry = false;
if (llvm::Error unhandled = llvm::handleErrors(
std::move(Err), [&](const DAPError &E) -> llvm::Error {
- error.format = E.getMessage();
- error.showUser = E.getShowUser();
- error.id = E.convertToErrorCode().value();
+ error_message.format = E.getMessage();
+ error_message.showUser = E.getShowUser();
+ error_message.id = E.convertToErrorCode().value();
// TODO: We could add url/urlLabel to the error message for more
// information for users.
return llvm::Error::success();
}))
- error.format = llvm::toString(std::move(unhandled));
+ error_message.format = llvm::toString(std::move(unhandled));
+ protocol::ErrorResponseBody body;
+ body.error = error_message;
response.success = false;
- response.body = std::move(error);
+ response.body = std::move(body);
} else {
response.success = true;
if constexpr (!std::is_same_v<Body, std::monostate>)
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
index f30517715194f..0ef90eb7d76bd 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp
@@ -286,4 +286,13 @@ json::Value toJSON(const Message &M) {
return std::visit([](auto &M) { return toJSON(M); }, M);
}
+json::Value toJSON(const ErrorResponseBody &E) {
+ json::Object result{};
+
+ if (E.error)
+ result.insert({"error", *E.error});
+
+ return result;
+}
+
} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
index e10a903b80aaa..baf5f8f165183 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h
@@ -109,7 +109,7 @@ struct ErrorMessage {
/// requirement that every user visible error message needs a corresponding
/// error number, so that users or customer support can find information about
/// the specific error more easily.
- uint64_t id;
+ uint64_t id = 0;
/// A format string for the message. Embedded variables have the form
/// `{name}`. If variable name starts with an underscore character, the
@@ -122,10 +122,10 @@ struct ErrorMessage {
std::optional<std::map<std::string, std::string>> variables;
/// If true send to telemetry.
- bool sendTelemetry;
+ bool sendTelemetry = false;
/// If true show user.
- bool showUser;
+ bool showUser = false;
/// A url where additional information about this message can be found.
std::optional<std::string> url;
@@ -141,6 +141,13 @@ using Message = std::variant<Request, Response, Event>;
bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path);
llvm::json::Value toJSON(const Message &);
+/// On error (whenever `success` is false), the body can provide more details.
+struct ErrorResponseBody {
+ /// A structured error message.
+ std::optional<ErrorMessage> error;
+};
+llvm::json::Value toJSON(const ErrorResponseBody &);
+
/// This is just an acknowledgement, so no body field is required.
using VoidResponse = std::monostate;
>From d0e353594381af9974b17c5a6ee04b23c55aeb6e Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 20 Mar 2025 12:26:51 -0700
Subject: [PATCH 3/3] Also allowing the url and urlLabel to be configured in
the DAPError.
---
lldb/tools/lldb-dap/DAPError.cpp | 7 +++++--
lldb/tools/lldb-dap/DAPError.h | 12 +++++++++++-
lldb/tools/lldb-dap/Handler/RequestHandler.h | 4 ++--
3 files changed, 18 insertions(+), 5 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp
index 044c9b48d61c6..dcb955af0345f 100644
--- a/lldb/tools/lldb-dap/DAPError.cpp
+++ b/lldb/tools/lldb-dap/DAPError.cpp
@@ -14,8 +14,11 @@ namespace lldb_dap {
char DAPError::ID;
-DAPError::DAPError(std::string message, bool show_user)
- : m_message(message), m_show_user(show_user) {}
+DAPError::DAPError(std::string message, std::error_code EC, bool show_user,
+ std::optional<std::string> url,
+ std::optional<std::string> url_label)
+ : m_message(message), m_ec(EC), m_show_user(show_user), m_url(url),
+ m_url_label(url_label) {}
void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; }
diff --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h
index b990bcdb5ceb0..564651b1f587d 100644
--- a/lldb/tools/lldb-dap/DAPError.h
+++ b/lldb/tools/lldb-dap/DAPError.h
@@ -7,7 +7,9 @@
//===----------------------------------------------------------------------===//
#include "llvm/Support/Error.h"
+#include <optional>
#include <string>
+#include <system_error>
namespace lldb_dap {
@@ -17,17 +19,25 @@ class DAPError : public llvm::ErrorInfo<DAPError> {
public:
static char ID;
- DAPError(std::string message, bool show_user = false);
+ DAPError(std::string message,
+ std::error_code EC = llvm::inconvertibleErrorCode(),
+ bool show_user = true, std::optional<std::string> url = std::nullopt,
+ std::optional<std::string> url_label = std::nullopt);
void log(llvm::raw_ostream &OS) const override;
std::error_code convertToErrorCode() const override;
const std::string &getMessage() const { return m_message; }
bool getShowUser() const { return m_show_user; }
+ const std::optional<std::string> &getURL() const { return m_url; }
+ const std::optional<std::string> &getURLLabel() const { return m_url; }
private:
std::string m_message;
+ std::error_code m_ec;
bool m_show_user;
+ std::optional<std::string> m_url;
+ std::optional<std::string> m_url_label;
};
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 47bf9e178e5b4..8971b02fcb92e 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -143,8 +143,8 @@ class RequestHandler : public BaseRequestHandler {
error_message.format = E.getMessage();
error_message.showUser = E.getShowUser();
error_message.id = E.convertToErrorCode().value();
- // TODO: We could add url/urlLabel to the error message for more
- // information for users.
+ error_message.url = E.getURL();
+ error_message.urlLabel = E.getURLLabel();
return llvm::Error::success();
}))
error_message.format = llvm::toString(std::move(unhandled));
More information about the lldb-commits
mailing list