[llvm] 8630c22 - [lldb-dap] migrate set breakpoint requests (#137448)
via llvm-commits
llvm-commits at lists.llvm.org
Fri May 9 15:06:02 PDT 2025
Author: Ely Ronnen
Date: 2025-05-10T00:05:59+02:00
New Revision: 8630c22083e3ebab5955c0c46caa89b59f283fdb
URL: https://github.com/llvm/llvm-project/commit/8630c22083e3ebab5955c0c46caa89b59f283fdb
DIFF: https://github.com/llvm/llvm-project/commit/8630c22083e3ebab5955c0c46caa89b59f283fdb.diff
LOG: [lldb-dap] migrate set breakpoint requests (#137448)
- Migrate set breakpoint requests to use typed RequestHandler
- `SetBreakpointsRequestHandler`
- `SetDataBreakpointsRequestHandler`
- `SetFunctionBreakpointsRequestHandler`
- `SetInstructionBreakpointsRequestHandler`
- `DataBreakpointInfoRequestHandler`
- Decouple JSON from lldb-dap `Breakpoint` classes
Added:
Modified:
lldb/tools/lldb-dap/Breakpoint.cpp
lldb/tools/lldb-dap/Breakpoint.h
lldb/tools/lldb-dap/BreakpointBase.cpp
lldb/tools/lldb-dap/BreakpointBase.h
lldb/tools/lldb-dap/DAP.cpp
lldb/tools/lldb-dap/DAP.h
lldb/tools/lldb-dap/FunctionBreakpoint.cpp
lldb/tools/lldb-dap/FunctionBreakpoint.h
lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
lldb/tools/lldb-dap/Handler/RequestHandler.h
lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp
lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp
lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp
lldb/tools/lldb-dap/InstructionBreakpoint.cpp
lldb/tools/lldb-dap/InstructionBreakpoint.h
lldb/tools/lldb-dap/JSONUtils.cpp
lldb/tools/lldb-dap/JSONUtils.h
lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
lldb/tools/lldb-dap/SourceBreakpoint.cpp
lldb/tools/lldb-dap/SourceBreakpoint.h
lldb/tools/lldb-dap/Watchpoint.cpp
lldb/tools/lldb-dap/Watchpoint.h
llvm/include/llvm/Support/JSON.h
Removed:
################################################################################
diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 5679fd545d53f..26d633d1d172e 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -14,7 +14,6 @@
#include "lldb/API/SBLineEntry.h"
#include "lldb/API/SBMutex.h"
#include "llvm/ADT/StringExtras.h"
-#include "llvm/Support/JSON.h"
#include <cstddef>
#include <cstdint>
#include <mutex>
@@ -30,13 +29,16 @@ void Breakpoint::SetHitCondition() {
m_bp.SetIgnoreCount(hitCount - 1);
}
-void Breakpoint::CreateJsonObject(llvm::json::Object &object) {
+protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
+ protocol::Breakpoint breakpoint;
+
// Each breakpoint location is treated as a separate breakpoint for VS code.
// They don't have the notion of a single breakpoint with multiple locations.
if (!m_bp.IsValid())
- return;
- object.try_emplace("verified", m_bp.GetNumResolvedLocations() > 0);
- object.try_emplace("id", m_bp.GetID());
+ return breakpoint;
+
+ breakpoint.verified = m_bp.GetNumResolvedLocations() > 0;
+ breakpoint.id = m_bp.GetID();
// VS Code DAP doesn't currently allow one breakpoint to have multiple
// locations so we just report the first one. If we report all locations
// then the IDE starts showing the wrong line numbers and locations for
@@ -60,16 +62,18 @@ void Breakpoint::CreateJsonObject(llvm::json::Object &object) {
if (bp_addr.IsValid()) {
std::string formatted_addr =
"0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));
- object.try_emplace("instructionReference", formatted_addr);
+ breakpoint.instructionReference = formatted_addr;
auto line_entry = bp_addr.GetLineEntry();
const auto line = line_entry.GetLine();
if (line != UINT32_MAX)
- object.try_emplace("line", line);
+ breakpoint.line = line;
const auto column = line_entry.GetColumn();
if (column != 0)
- object.try_emplace("column", column);
- object.try_emplace("source", CreateSource(line_entry));
+ breakpoint.column = column;
+ breakpoint.source = CreateSource(line_entry);
}
+
+ return breakpoint;
}
bool Breakpoint::MatchesName(const char *name) {
diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h
index 580017125af44..c4f1fa291f181 100644
--- a/lldb/tools/lldb-dap/Breakpoint.h
+++ b/lldb/tools/lldb-dap/Breakpoint.h
@@ -17,14 +17,16 @@ namespace lldb_dap {
class Breakpoint : public BreakpointBase {
public:
- Breakpoint(DAP &d, const llvm::json::Object &obj) : BreakpointBase(d, obj) {}
+ Breakpoint(DAP &d, const std::optional<std::string> &condition,
+ const std::optional<std::string> &hit_condition)
+ : BreakpointBase(d, condition, hit_condition) {}
Breakpoint(DAP &d, lldb::SBBreakpoint bp) : BreakpointBase(d), m_bp(bp) {}
lldb::break_id_t GetID() const { return m_bp.GetID(); }
void SetCondition() override;
void SetHitCondition() override;
- void CreateJsonObject(llvm::json::Object &object) override;
+ protocol::Breakpoint ToProtocolBreakpoint() override;
bool MatchesName(const char *name);
void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp
index 331ce8efee9bc..1a4da92e44d31 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.cpp
+++ b/lldb/tools/lldb-dap/BreakpointBase.cpp
@@ -7,16 +7,14 @@
//===----------------------------------------------------------------------===//
#include "BreakpointBase.h"
-#include "JSONUtils.h"
-#include "llvm/ADT/StringRef.h"
using namespace lldb_dap;
-BreakpointBase::BreakpointBase(DAP &d, const llvm::json::Object &obj)
- : m_dap(d),
- m_condition(std::string(GetString(obj, "condition").value_or(""))),
- m_hit_condition(
- std::string(GetString(obj, "hitCondition").value_or(""))) {}
+BreakpointBase::BreakpointBase(DAP &d,
+ const std::optional<std::string> &condition,
+ const std::optional<std::string> &hit_condition)
+ : m_dap(d), m_condition(condition.value_or("")),
+ m_hit_condition(hit_condition.value_or("")) {}
void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) {
if (m_condition != request_bp.m_condition) {
diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h
index 4c13326624831..e9cfc112675c3 100644
--- a/lldb/tools/lldb-dap/BreakpointBase.h
+++ b/lldb/tools/lldb-dap/BreakpointBase.h
@@ -10,7 +10,8 @@
#define LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H
#include "DAPForward.h"
-#include "llvm/ADT/StringRef.h"
+#include "Protocol/ProtocolTypes.h"
+#include <optional>
#include <string>
namespace lldb_dap {
@@ -18,12 +19,13 @@ namespace lldb_dap {
class BreakpointBase {
public:
explicit BreakpointBase(DAP &d) : m_dap(d) {}
- BreakpointBase(DAP &d, const llvm::json::Object &obj);
+ BreakpointBase(DAP &d, const std::optional<std::string> &condition,
+ const std::optional<std::string> &hit_condition);
virtual ~BreakpointBase() = default;
virtual void SetCondition() = 0;
virtual void SetHitCondition() = 0;
- virtual void CreateJsonObject(llvm::json::Object &object) = 0;
+ virtual protocol::Breakpoint ToProtocolBreakpoint() = 0;
void UpdateBreakpoint(const BreakpointBase &request_bp);
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index f6754b1f8d7a3..80c150018f0b3 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -47,6 +47,7 @@
#include <chrono>
#include <condition_variable>
#include <cstdarg>
+#include <cstdint>
#include <cstdio>
#include <fstream>
#include <future>
@@ -552,9 +553,7 @@ lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) {
return target.GetProcess().GetThreadByID(tid);
}
-lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
- const uint64_t frame_id =
- GetInteger<uint64_t>(arguments, "frameId").value_or(UINT64_MAX);
+lldb::SBFrame DAP::GetLLDBFrame(uint64_t frame_id) {
lldb::SBProcess process = target.GetProcess();
// Upper 32 bits is the thread index ID
lldb::SBThread thread =
@@ -563,6 +562,12 @@ lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id));
}
+lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) {
+ const auto frame_id =
+ GetInteger<uint64_t>(arguments, "frameId").value_or(UINT64_MAX);
+ return GetLLDBFrame(frame_id);
+}
+
llvm::json::Value DAP::CreateTopLevelScopes() {
llvm::json::Array scopes;
scopes.emplace_back(
@@ -1602,7 +1607,7 @@ void DAP::EventThread() {
// avoids sending paths that should be source mapped. Note that
// CreateBreakpoint doesn't apply source mapping and certain
// implementation ignore the source part of this event anyway.
- llvm::json::Value source_bp = CreateBreakpoint(&bp);
+ llvm::json::Value source_bp = bp.ToProtocolBreakpoint();
source_bp.getAsObject()->erase("source");
llvm::json::Object body;
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index afeda8d81efb0..ecde222c9263c 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -275,6 +275,7 @@ struct DAP {
lldb::SBThread GetLLDBThread(lldb::tid_t id);
lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments);
+ lldb::SBFrame GetLLDBFrame(uint64_t frame_id);
lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments);
llvm::json::Value CreateTopLevelScopes();
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
index d87723f7557bd..1ea9cddb9f689 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp
@@ -8,15 +8,15 @@
#include "FunctionBreakpoint.h"
#include "DAP.h"
-#include "JSONUtils.h"
#include "lldb/API/SBMutex.h"
#include <mutex>
namespace lldb_dap {
-FunctionBreakpoint::FunctionBreakpoint(DAP &d, const llvm::json::Object &obj)
- : Breakpoint(d, obj),
- m_function_name(std::string(GetString(obj, "name").value_or(""))) {}
+FunctionBreakpoint::FunctionBreakpoint(
+ DAP &d, const protocol::FunctionBreakpoint &breakpoint)
+ : Breakpoint(d, breakpoint.condition, breakpoint.hitCondition),
+ m_function_name(breakpoint.name) {}
void FunctionBreakpoint::SetBreakpoint() {
lldb::SBMutex lock = m_dap.GetAPIMutex();
diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.h b/lldb/tools/lldb-dap/FunctionBreakpoint.h
index 7100360cd7ec1..76fbdb3e886a4 100644
--- a/lldb/tools/lldb-dap/FunctionBreakpoint.h
+++ b/lldb/tools/lldb-dap/FunctionBreakpoint.h
@@ -11,12 +11,13 @@
#include "Breakpoint.h"
#include "DAPForward.h"
+#include "Protocol/ProtocolTypes.h"
namespace lldb_dap {
class FunctionBreakpoint : public Breakpoint {
public:
- FunctionBreakpoint(DAP &dap, const llvm::json::Object &obj);
+ FunctionBreakpoint(DAP &dap, const protocol::FunctionBreakpoint &breakpoint);
/// Set this breakpoint in LLDB as a new breakpoint.
void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
index 4d920f8556254..8cb25d0603449 100644
--- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp
@@ -8,144 +8,50 @@
#include "DAP.h"
#include "EventHelper.h"
-#include "JSONUtils.h"
+#include "Protocol/ProtocolTypes.h"
#include "RequestHandler.h"
#include "lldb/API/SBMemoryRegionInfo.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
namespace lldb_dap {
-// "DataBreakpointInfoRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Obtains information on a possible data breakpoint that
-// could be set on an expression or variable.\nClients should only call this
-// request if the corresponding capability `supportsDataBreakpoints` is
-// true.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "dataBreakpointInfo" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/DataBreakpointInfoArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "DataBreakpointInfoArguments": {
-// "type": "object",
-// "description": "Arguments for `dataBreakpointInfo` request.",
-// "properties": {
-// "variablesReference": {
-// "type": "integer",
-// "description": "Reference to the variable container if the data
-// breakpoint is requested for a child of the container. The
-// `variablesReference` must have been obtained in the current suspended
-// state. See 'Lifetime of Object References' in the Overview section for
-// details."
-// },
-// "name": {
-// "type": "string",
-// "description": "The name of the variable's child to obtain data
-// breakpoint information for.\nIf `variablesReference` isn't specified,
-// this can be an expression."
-// },
-// "frameId": {
-// "type": "integer",
-// "description": "When `name` is an expression, evaluate it in the scope
-// of this stack frame. If not specified, the expression is evaluated in
-// the global scope. When `variablesReference` is specified, this property
-// has no effect."
-// }
-// },
-// "required": [ "name" ]
-// },
-// "DataBreakpointInfoResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `dataBreakpointInfo` request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "dataId": {
-// "type": [ "string", "null" ],
-// "description": "An identifier for the data on which a data
-// breakpoint can be registered with the `setDataBreakpoints`
-// request or null if no data breakpoint is available. If a
-// `variablesReference` or `frameId` is passed, the `dataId` is
-// valid in the current suspended state, otherwise it's valid
-// indefinitely. See 'Lifetime of Object References' in the Overview
-// section for details. Breakpoints set using the `dataId` in the
-// `setDataBreakpoints` request may outlive the lifetime of the
-// associated `dataId`."
-// },
-// "description": {
-// "type": "string",
-// "description": "UI string that describes on what data the
-// breakpoint is set on or why a data breakpoint is not available."
-// },
-// "accessTypes": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/DataBreakpointAccessType"
-// },
-// "description": "Attribute lists the available access types for a
-// potential data breakpoint. A UI client could surface this
-// information."
-// },
-// "canPersist": {
-// "type": "boolean",
-// "description": "Attribute indicates that a potential data
-// breakpoint could be persisted across sessions."
-// }
-// },
-// "required": [ "dataId", "description" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// }
-void DataBreakpointInfoRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- FillResponse(request, response);
- llvm::json::Object body;
- lldb::SBError error;
- llvm::json::Array accessTypes{"read", "write", "readWrite"};
- const auto *arguments = request.getObject("arguments");
- const auto variablesReference =
- GetInteger<uint64_t>(arguments, "variablesReference").value_or(0);
- llvm::StringRef name = GetString(arguments, "name").value_or("");
- lldb::SBFrame frame = dap.GetLLDBFrame(*arguments);
- lldb::SBValue variable = dap.variables.FindVariable(variablesReference, name);
+/// Obtains information on a possible data breakpoint that could be set on an
+/// expression or variable. Clients should only call this request if the
+/// corresponding capability supportsDataBreakpoints is true.
+llvm::Expected<protocol::DataBreakpointInfoResponseBody>
+DataBreakpointInfoRequestHandler::Run(
+ const protocol::DataBreakpointInfoArguments &args) const {
+ protocol::DataBreakpointInfoResponseBody response;
+ lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId.value_or(UINT64_MAX));
+ lldb::SBValue variable = dap.variables.FindVariable(
+ args.variablesReference.value_or(0), args.name);
std::string addr, size;
+ bool is_data_ok = true;
if (variable.IsValid()) {
lldb::addr_t load_addr = variable.GetLoadAddress();
size_t byte_size = variable.GetByteSize();
if (load_addr == LLDB_INVALID_ADDRESS) {
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description",
- "does not exist in memory, its location is " +
- std::string(variable.GetLocation()));
+ is_data_ok = false;
+ response.description = "does not exist in memory, its location is " +
+ std::string(variable.GetLocation());
} else if (byte_size == 0) {
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description", "variable size is 0");
+ is_data_ok = false;
+ response.description = "variable size is 0";
} else {
addr = llvm::utohexstr(load_addr);
size = llvm::utostr(byte_size);
}
- } else if (variablesReference == 0 && frame.IsValid()) {
- lldb::SBValue value = frame.EvaluateExpression(name.data());
+ } else if (args.variablesReference.value_or(0) == 0 && frame.IsValid()) {
+ lldb::SBValue value = frame.EvaluateExpression(args.name.c_str());
if (value.GetError().Fail()) {
lldb::SBError error = value.GetError();
const char *error_cstr = error.GetCString();
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description", error_cstr && error_cstr[0]
- ? std::string(error_cstr)
- : "evaluation failed");
+ is_data_ok = false;
+ response.description = error_cstr && error_cstr[0]
+ ? std::string(error_cstr)
+ : "evaluation failed";
} else {
uint64_t load_addr = value.GetValueAsUnsigned();
lldb::SBData data = value.GetPointeeData();
@@ -159,32 +65,31 @@ void DataBreakpointInfoRequestHandler::operator()(
// request if SBProcess::GetMemoryRegionInfo returns error.
if (err.Success()) {
if (!(region.IsReadable() || region.IsWritable())) {
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description",
- "memory region for address " + addr +
- " has no read or write permissions");
+ is_data_ok = false;
+ response.description = "memory region for address " + addr +
+ " has no read or write permissions";
}
}
} else {
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description",
- "unable to get byte size for expression: " +
- name.str());
+ is_data_ok = false;
+ response.description =
+ "unable to get byte size for expression: " + args.name;
}
}
} else {
- body.try_emplace("dataId", nullptr);
- body.try_emplace("description", "variable not found: " + name.str());
+ is_data_ok = false;
+ response.description = "variable not found: " + args.name;
}
- if (!body.getObject("dataId")) {
- body.try_emplace("dataId", addr + "/" + size);
- body.try_emplace("accessTypes", std::move(accessTypes));
- body.try_emplace("description",
- size + " bytes at " + addr + " " + name.str());
+ if (is_data_ok) {
+ response.dataId = addr + "/" + size;
+ response.accessTypes = {protocol::eDataBreakpointAccessTypeRead,
+ protocol::eDataBreakpointAccessTypeWrite,
+ protocol::eDataBreakpointAccessTypeReadWrite};
+ response.description = size + " bytes at " + addr + " " + args.name;
}
- 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 db7f05cb1f113..b0002440cf72e 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -15,7 +15,6 @@
#include "Protocol/ProtocolBase.h"
#include "Protocol/ProtocolRequests.h"
#include "Protocol/ProtocolTypes.h"
-#include "lldb/API/SBError.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
@@ -349,15 +348,19 @@ class StepOutRequestHandler : public RequestHandler<protocol::StepOutArguments,
llvm::Error Run(const protocol::StepOutArguments &args) const override;
};
-class SetBreakpointsRequestHandler : public LegacyRequestHandler {
+class SetBreakpointsRequestHandler
+ : public RequestHandler<
+ protocol::SetBreakpointsArguments,
+ llvm::Expected<protocol::SetBreakpointsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "setBreakpoints"; }
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureConditionalBreakpoints,
protocol::eAdapterFeatureHitConditionalBreakpoints};
}
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Expected<protocol::SetBreakpointsResponseBody>
+ Run(const protocol::SetBreakpointsArguments &args) const override;
};
class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler {
@@ -370,43 +373,59 @@ class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler {
void operator()(const llvm::json::Object &request) const override;
};
-class SetFunctionBreakpointsRequestHandler : public LegacyRequestHandler {
+class SetFunctionBreakpointsRequestHandler
+ : public RequestHandler<
+ protocol::SetFunctionBreakpointsArguments,
+ llvm::Expected<protocol::SetFunctionBreakpointsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "setFunctionBreakpoints"; }
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureFunctionBreakpoints};
}
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Expected<protocol::SetFunctionBreakpointsResponseBody>
+ Run(const protocol::SetFunctionBreakpointsArguments &args) const override;
};
-class DataBreakpointInfoRequestHandler : public LegacyRequestHandler {
+class DataBreakpointInfoRequestHandler
+ : public RequestHandler<
+ protocol::DataBreakpointInfoArguments,
+ llvm::Expected<protocol::DataBreakpointInfoResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "dataBreakpointInfo"; }
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Expected<protocol::DataBreakpointInfoResponseBody>
+ Run(const protocol::DataBreakpointInfoArguments &args) const override;
};
-class SetDataBreakpointsRequestHandler : public LegacyRequestHandler {
+class SetDataBreakpointsRequestHandler
+ : public RequestHandler<
+ protocol::SetDataBreakpointsArguments,
+ llvm::Expected<protocol::SetDataBreakpointsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "setDataBreakpoints"; }
- void operator()(const llvm::json::Object &request) const override;
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureDataBreakpoints};
}
+ llvm::Expected<protocol::SetDataBreakpointsResponseBody>
+ Run(const protocol::SetDataBreakpointsArguments &args) const override;
};
-class SetInstructionBreakpointsRequestHandler : public LegacyRequestHandler {
+class SetInstructionBreakpointsRequestHandler
+ : public RequestHandler<
+ protocol::SetInstructionBreakpointsArguments,
+ llvm::Expected<protocol::SetInstructionBreakpointsResponseBody>> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() {
return "setInstructionBreakpoints";
}
- void operator()(const llvm::json::Object &request) const override;
FeatureSet GetSupportedFeatures() const override {
return {protocol::eAdapterFeatureInstructionBreakpoints};
}
+ llvm::Expected<protocol::SetInstructionBreakpointsResponseBody>
+ Run(const protocol::SetInstructionBreakpointsArguments &args) const override;
};
class CompileUnitsRequestHandler : public LegacyRequestHandler {
diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
index dc0368852101f..86e090b66afe9 100644
--- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
@@ -9,153 +9,52 @@
#include "DAP.h"
#include "EventHelper.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
#include "RequestHandler.h"
+#include <vector>
namespace lldb_dap {
-// "SetBreakpointsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "SetBreakpoints request; value of command field is
-// 'setBreakpoints'. Sets multiple breakpoints for a single source and
-// clears all previous breakpoints in that source. To clear all breakpoint
-// for a source, specify an empty array. When a breakpoint is hit, a
-// StoppedEvent (event type 'breakpoint') is generated.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "setBreakpoints" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/SetBreakpointsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "SetBreakpointsArguments": {
-// "type": "object",
-// "description": "Arguments for 'setBreakpoints' request.",
-// "properties": {
-// "source": {
-// "$ref": "#/definitions/Source",
-// "description": "The source location of the breakpoints; either
-// source.path or source.reference must be specified."
-// },
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/SourceBreakpoint"
-// },
-// "description": "The code locations of the breakpoints."
-// },
-// "lines": {
-// "type": "array",
-// "items": {
-// "type": "integer"
-// },
-// "description": "Deprecated: The code locations of the breakpoints."
-// },
-// "sourceModified": {
-// "type": "boolean",
-// "description": "A value of true indicates that the underlying source
-// has been modified which results in new breakpoint locations."
-// }
-// },
-// "required": [ "source" ]
-// },
-// "SetBreakpointsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'setBreakpoints' request. Returned is
-// information about each breakpoint created by this request. This includes
-// the actual code location and whether the breakpoint could be verified.
-// The breakpoints returned are in the same order as the elements of the
-// 'breakpoints' (or the deprecated 'lines') in the
-// SetBreakpointsArguments.", "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/Breakpoint"
-// },
-// "description": "Information about the breakpoints. The array
-// elements are in the same order as the elements of the
-// 'breakpoints' (or the deprecated 'lines') in the
-// SetBreakpointsArguments."
-// }
-// },
-// "required": [ "breakpoints" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// },
-// "SourceBreakpoint": {
-// "type": "object",
-// "description": "Properties of a breakpoint or logpoint passed to the
-// setBreakpoints request.", "properties": {
-// "line": {
-// "type": "integer",
-// "description": "The source line of the breakpoint or logpoint."
-// },
-// "column": {
-// "type": "integer",
-// "description": "An optional source column of the breakpoint."
-// },
-// "condition": {
-// "type": "string",
-// "description": "An optional expression for conditional breakpoints."
-// },
-// "hitCondition": {
-// "type": "string",
-// "description": "An optional expression that controls how many hits of
-// the breakpoint are ignored. The backend is expected to interpret the
-// expression as needed."
-// },
-// "logMessage": {
-// "type": "string",
-// "description": "If this attribute exists and is non-empty, the backend
-// must not 'break' (stop) but log the message instead. Expressions within
-// {} are interpolated."
-// }
-// },
-// "required": [ "line" ]
-// }
-void SetBreakpointsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- lldb::SBError error;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- const auto *source = arguments->getObject("source");
- const auto path = GetString(source, "path").value_or("");
- const auto *breakpoints = arguments->getArray("breakpoints");
- llvm::json::Array response_breakpoints;
+/// Sets multiple breakpoints for a single source and clears all previous
+/// breakpoints in that source. To clear all breakpoint for a source, specify an
+/// empty array. When a breakpoint is hit, a `stopped` event (with reason
+/// `breakpoint`) is generated.
+llvm::Expected<protocol::SetBreakpointsResponseBody>
+SetBreakpointsRequestHandler::Run(
+ const protocol::SetBreakpointsArguments &args) const {
+ const auto &source = args.source;
+ const auto path = source.path.value_or("");
+ std::vector<protocol::Breakpoint> response_breakpoints;
// Decode the source breakpoint infos for this "setBreakpoints" request
SourceBreakpointMap request_bps;
// "breakpoints" may be unset, in which case we treat it the same as being set
// to an empty array.
- if (breakpoints) {
- for (const auto &bp : *breakpoints) {
- const auto *bp_obj = bp.getAsObject();
- if (bp_obj) {
- SourceBreakpoint src_bp(dap, *bp_obj);
- std::pair<uint32_t, uint32_t> bp_pos(src_bp.GetLine(),
- src_bp.GetColumn());
- request_bps.try_emplace(bp_pos, src_bp);
- const auto [iv, inserted] =
- dap.source_breakpoints[path].try_emplace(bp_pos, src_bp);
- // We check if this breakpoint already exists to update it
- if (inserted)
- iv->getSecond().SetBreakpoint(path.data());
- else
- iv->getSecond().UpdateBreakpoint(src_bp);
- AppendBreakpoint(&iv->getSecond(), response_breakpoints, path,
- src_bp.GetLine());
- }
+ if (args.breakpoints) {
+ for (const auto &bp : *args.breakpoints) {
+ SourceBreakpoint src_bp(dap, bp);
+ std::pair<uint32_t, uint32_t> bp_pos(src_bp.GetLine(),
+ src_bp.GetColumn());
+ request_bps.try_emplace(bp_pos, src_bp);
+ const auto [iv, inserted] =
+ dap.source_breakpoints[path].try_emplace(bp_pos, src_bp);
+ // We check if this breakpoint already exists to update it
+ if (inserted)
+ iv->getSecond().SetBreakpoint(path.data());
+ else
+ iv->getSecond().UpdateBreakpoint(src_bp);
+
+ protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint();
+
+ // Use the path from the request if it is set
+ if (!path.empty())
+ response_bp.source = CreateSource(path);
+
+ if (!response_bp.line)
+ response_bp.line = src_bp.GetLine();
+ if (!response_bp.column)
+ response_bp.column = src_bp.GetColumn();
+ response_breakpoints.push_back(response_bp);
}
}
@@ -174,10 +73,7 @@ void SetBreakpointsRequestHandler::operator()(
}
}
- llvm::json::Object body;
- body.try_emplace("breakpoints", std::move(response_breakpoints));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
index 365c9f0d722d4..1caaa23bf06f6 100644
--- a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
@@ -8,90 +8,28 @@
#include "DAP.h"
#include "EventHelper.h"
-#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
#include "RequestHandler.h"
#include "Watchpoint.h"
#include <set>
namespace lldb_dap {
-// "SetDataBreakpointsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Replaces all existing data breakpoints with new data
-// breakpoints.\nTo clear all data breakpoints, specify an empty
-// array.\nWhen a data breakpoint is hit, a `stopped` event (with reason
-// `data breakpoint`) is generated.\nClients should only call this request
-// if the corresponding capability `supportsDataBreakpoints` is true.",
-// "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "setDataBreakpoints" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/SetDataBreakpointsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "SetDataBreakpointsArguments": {
-// "type": "object",
-// "description": "Arguments for `setDataBreakpoints` request.",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/DataBreakpoint"
-// },
-// "description": "The contents of this array replaces all existing data
-// breakpoints. An empty array clears all data breakpoints."
-// }
-// },
-// "required": [ "breakpoints" ]
-// },
-// "SetDataBreakpointsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `setDataBreakpoints` request.\nReturned is
-// information about each breakpoint created by this request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/Breakpoint"
-// },
-// "description": "Information about the data breakpoints. The array
-// elements correspond to the elements of the input argument
-// `breakpoints` array."
-// }
-// },
-// "required": [ "breakpoints" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// }
-void SetDataBreakpointsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- lldb::SBError error;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- const auto *breakpoints = arguments->getArray("breakpoints");
- llvm::json::Array response_breakpoints;
+/// Replaces all existing data breakpoints with new data breakpoints.
+/// To clear all data breakpoints, specify an empty array.
+/// When a data breakpoint is hit, a stopped event (with reason data breakpoint)
+/// is generated. Clients should only call this request if the corresponding
+/// capability supportsDataBreakpoints is true.
+llvm::Expected<protocol::SetDataBreakpointsResponseBody>
+SetDataBreakpointsRequestHandler::Run(
+ const protocol::SetDataBreakpointsArguments &args) const {
+ std::vector<protocol::Breakpoint> response_breakpoints;
+
dap.target.DeleteAllWatchpoints();
std::vector<Watchpoint> watchpoints;
- if (breakpoints) {
- for (const auto &bp : *breakpoints) {
- const auto *bp_obj = bp.getAsObject();
- if (bp_obj)
- watchpoints.emplace_back(dap, *bp_obj);
- }
- }
+ for (const auto &bp : args.breakpoints)
+ watchpoints.emplace_back(dap, bp);
+
// If two watchpoints start at the same address, the latter overwrite the
// former. So, we only enable those at first-seen addresses when iterating
// backward.
@@ -103,12 +41,10 @@ void SetDataBreakpointsRequestHandler::operator()(
}
}
for (auto wp : watchpoints)
- AppendBreakpoint(&wp, response_breakpoints);
+ response_breakpoints.push_back(wp.ToProtocolBreakpoint());
- llvm::json::Object body;
- body.try_emplace("breakpoints", std::move(response_breakpoints));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return protocol::SetDataBreakpointsResponseBody{
+ std::move(response_breakpoints)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp
index c45dc0d0d6553..1367aa3e864d9 100644
--- a/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp
@@ -8,116 +8,35 @@
#include "DAP.h"
#include "EventHelper.h"
-#include "JSONUtils.h"
#include "RequestHandler.h"
namespace lldb_dap {
-// "SetFunctionBreakpointsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "SetFunctionBreakpoints request; value of command field is
-// 'setFunctionBreakpoints'. Sets multiple function breakpoints and clears
-// all previous function breakpoints. To clear all function breakpoint,
-// specify an empty array. When a function breakpoint is hit, a StoppedEvent
-// (event type 'function breakpoint') is generated.", "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "setFunctionBreakpoints" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/SetFunctionBreakpointsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "SetFunctionBreakpointsArguments": {
-// "type": "object",
-// "description": "Arguments for 'setFunctionBreakpoints' request.",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/FunctionBreakpoint"
-// },
-// "description": "The function names of the breakpoints."
-// }
-// },
-// "required": [ "breakpoints" ]
-// },
-// "FunctionBreakpoint": {
-// "type": "object",
-// "description": "Properties of a breakpoint passed to the
-// setFunctionBreakpoints request.", "properties": {
-// "name": {
-// "type": "string",
-// "description": "The name of the function."
-// },
-// "condition": {
-// "type": "string",
-// "description": "An optional expression for conditional breakpoints."
-// },
-// "hitCondition": {
-// "type": "string",
-// "description": "An optional expression that controls how many hits of
-// the breakpoint are ignored. The backend is expected to interpret the
-// expression as needed."
-// }
-// },
-// "required": [ "name" ]
-// },
-// "SetFunctionBreakpointsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'setFunctionBreakpoints' request. Returned is
-// information about each breakpoint created by this request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/Breakpoint"
-// },
-// "description": "Information about the breakpoints. The array
-// elements correspond to the elements of the 'breakpoints' array."
-// }
-// },
-// "required": [ "breakpoints" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// }
-void SetFunctionBreakpointsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- lldb::SBError error;
- FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- const auto *breakpoints = arguments->getArray("breakpoints");
- llvm::json::Array response_breakpoints;
+/// Replaces all existing function breakpoints with new function breakpoints.
+/// To clear all function breakpoints, specify an empty array.
+/// When a function breakpoint is hit, a stopped event (with reason function
+/// breakpoint) is generated. Clients should only call this request if the
+/// corresponding capability supportsFunctionBreakpoints is true.
+llvm::Expected<protocol::SetFunctionBreakpointsResponseBody>
+SetFunctionBreakpointsRequestHandler::Run(
+ const protocol::SetFunctionBreakpointsArguments &args) const {
+ std::vector<protocol::Breakpoint> response_breakpoints;
// Disable any function breakpoints that aren't in this request.
// There is no call to remove function breakpoints other than calling this
// function with a smaller or empty "breakpoints" list.
const auto name_iter = dap.function_breakpoints.keys();
llvm::DenseSet<llvm::StringRef> seen(name_iter.begin(), name_iter.end());
- for (const auto &value : *breakpoints) {
- const auto *bp_obj = value.getAsObject();
- if (!bp_obj)
- continue;
- FunctionBreakpoint fn_bp(dap, *bp_obj);
- const auto [it, inserted] = dap.function_breakpoints.try_emplace(
- fn_bp.GetFunctionName(), dap, *bp_obj);
+ for (const auto &fb : args.breakpoints) {
+ FunctionBreakpoint fn_bp(dap, fb);
+ const auto [it, inserted] =
+ dap.function_breakpoints.try_emplace(fn_bp.GetFunctionName(), dap, fb);
if (inserted)
it->second.SetBreakpoint();
else
it->second.UpdateBreakpoint(fn_bp);
- AppendBreakpoint(&it->second, response_breakpoints);
+ response_breakpoints.push_back(it->second.ToProtocolBreakpoint());
seen.erase(fn_bp.GetFunctionName());
}
@@ -130,10 +49,8 @@ void SetFunctionBreakpointsRequestHandler::operator()(
dap.function_breakpoints.erase(name);
}
- llvm::json::Object body;
- body.try_emplace("breakpoints", std::move(response_breakpoints));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return protocol::SetFunctionBreakpointsResponseBody{
+ std::move(response_breakpoints)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp
index 4e555ad605a26..48b2ba5a25594 100644
--- a/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp
@@ -8,207 +8,20 @@
#include "DAP.h"
#include "EventHelper.h"
-#include "JSONUtils.h"
#include "RequestHandler.h"
namespace lldb_dap {
-// "SetInstructionBreakpointsRequest": {
-// "allOf": [
-// {"$ref": "#/definitions/Request"},
-// {
-// "type": "object",
-// "description" :
-// "Replaces all existing instruction breakpoints. Typically, "
-// "instruction breakpoints would be set from a disassembly window. "
-// "\nTo clear all instruction breakpoints, specify an empty "
-// "array.\nWhen an instruction breakpoint is hit, a `stopped` event "
-// "(with reason `instruction breakpoint`) is generated.\nClients "
-// "should only call this request if the corresponding capability "
-// "`supportsInstructionBreakpoints` is true.",
-// "properties": {
-// "command": { "type": "string", "enum": ["setInstructionBreakpoints"]
-// }, "arguments": {"$ref":
-// "#/definitions/SetInstructionBreakpointsArguments"}
-// },
-// "required": [ "command", "arguments" ]
-// }
-// ]
-// },
-// "SetInstructionBreakpointsArguments": {
-// "type": "object",
-// "description": "Arguments for `setInstructionBreakpoints` request",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {"$ref": "#/definitions/InstructionBreakpoint"},
-// "description": "The instruction references of the breakpoints"
-// }
-// },
-// "required": ["breakpoints"]
-// },
-// "SetInstructionBreakpointsResponse": {
-// "allOf": [
-// {"$ref": "#/definitions/Response"},
-// {
-// "type": "object",
-// "description": "Response to `setInstructionBreakpoints` request",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "breakpoints": {
-// "type": "array",
-// "items": {"$ref": "#/definitions/Breakpoint"},
-// "description":
-// "Information about the breakpoints. The array elements
-// " "correspond to the elements of the `breakpoints`
-// array."
-// }
-// },
-// "required": ["breakpoints"]
-// }
-// },
-// "required": ["body"]
-// }
-// ]
-// },
-// "InstructionBreakpoint": {
-// "type": "object",
-// "description": "Properties of a breakpoint passed to the "
-// "`setInstructionBreakpoints` request",
-// "properties": {
-// "instructionReference": {
-// "type": "string",
-// "description" :
-// "The instruction reference of the breakpoint.\nThis should be a "
-// "memory or instruction pointer reference from an
-// `EvaluateResponse`, "
-// "`Variable`, `StackFrame`, `GotoTarget`, or `Breakpoint`."
-// },
-// "offset": {
-// "type": "integer",
-// "description": "The offset from the instruction reference in "
-// "bytes.\nThis can be negative."
-// },
-// "condition": {
-// "type": "string",
-// "description": "An expression for conditional breakpoints.\nIt is only
-// "
-// "honored by a debug adapter if the corresponding "
-// "capability `supportsConditionalBreakpoints` is true."
-// },
-// "hitCondition": {
-// "type": "string",
-// "description": "An expression that controls how many hits of the "
-// "breakpoint are ignored.\nThe debug adapter is expected
-// " "to interpret the expression as needed.\nThe
-// attribute " "is only honored by a debug adapter if the
-// corresponding " "capability
-// `supportsHitConditionalBreakpoints` is true."
-// },
-// "mode": {
-// "type": "string",
-// "description": "The mode of this breakpoint. If defined, this must be
-// "
-// "one of the `breakpointModes` the debug adapter "
-// "advertised in its `Capabilities`."
-// }
-// },
-// "required": ["instructionReference"]
-// },
-// "Breakpoint": {
-// "type": "object",
-// "description" :
-// "Information about a breakpoint created in `setBreakpoints`, "
-// "`setFunctionBreakpoints`, `setInstructionBreakpoints`, or "
-// "`setDataBreakpoints` requests.",
-// "properties": {
-// "id": {
-// "type": "integer",
-// "description" :
-// "The identifier for the breakpoint. It is needed if breakpoint
-// " "events are used to update or remove breakpoints."
-// },
-// "verified": {
-// "type": "boolean",
-// "description": "If true, the breakpoint could be set (but not "
-// "necessarily at the desired location)."
-// },
-// "message": {
-// "type": "string",
-// "description": "A message about the state of the breakpoint.\nThis
-// "
-// "is shown to the user and can be used to explain
-// why " "a breakpoint could not be verified."
-// },
-// "source": {
-// "$ref": "#/definitions/Source",
-// "description": "The source where the breakpoint is located."
-// },
-// "line": {
-// "type": "integer",
-// "description" :
-// "The start line of the actual range covered by the breakpoint."
-// },
-// "column": {
-// "type": "integer",
-// "description" :
-// "Start position of the source range covered by the breakpoint.
-// " "It is measured in UTF-16 code units and the client
-// capability "
-// "`columnsStartAt1` determines whether it is 0- or 1-based."
-// },
-// "endLine": {
-// "type": "integer",
-// "description" :
-// "The end line of the actual range covered by the breakpoint."
-// },
-// "endColumn": {
-// "type": "integer",
-// "description" :
-// "End position of the source range covered by the breakpoint. It
-// " "is measured in UTF-16 code units and the client capability "
-// "`columnsStartAt1` determines whether it is 0- or 1-based.\nIf
-// " "no end line is given, then the end column is assumed to be
-// in " "the start line."
-// },
-// "instructionReference": {
-// "type": "string",
-// "description": "A memory reference to where the breakpoint is
-// set."
-// },
-// "offset": {
-// "type": "integer",
-// "description": "The offset from the instruction reference.\nThis "
-// "can be negative."
-// },
-// "reason": {
-// "type": "string",
-// "description" :
-// "A machine-readable explanation of why a breakpoint may not be
-// " "verified. If a breakpoint is verified or a specific reason
-// is " "not known, the adapter should omit this property.
-// Possible " "values include:\n\n- `pending`: Indicates a
-// breakpoint might be " "verified in the future, but the adapter
-// cannot verify it in the " "current state.\n - `failed`:
-// Indicates a breakpoint was not " "able to be verified, and the
-// adapter does not believe it can be " "verified without
-// intervention.",
-// "enum": [ "pending", "failed" ]
-// }
-// },
-// "required": ["verified"]
-// },
-void SetInstructionBreakpointsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- llvm::json::Array response_breakpoints;
- llvm::json::Object body;
- FillResponse(request, response);
-
- const auto *arguments = request.getObject("arguments");
- const auto *breakpoints = arguments->getArray("breakpoints");
+/// Replaces all existing instruction breakpoints. Typically, instruction
+/// breakpoints would be set from a disassembly window. To clear all instruction
+/// breakpoints, specify an empty array. When an instruction breakpoint is hit,
+/// a stopped event (with reason instruction breakpoint) is generated. Clients
+/// should only call this request if the corresponding capability
+/// supportsInstructionBreakpoints is true.
+llvm::Expected<protocol::SetInstructionBreakpointsResponseBody>
+SetInstructionBreakpointsRequestHandler::Run(
+ const protocol::SetInstructionBreakpointsArguments &args) const {
+ std::vector<protocol::Breakpoint> response_breakpoints;
// Disable any instruction breakpoints that aren't in this request.
// There is no call to remove instruction breakpoints other than calling this
@@ -216,19 +29,16 @@ void SetInstructionBreakpointsRequestHandler::operator()(
llvm::DenseSet<lldb::addr_t> seen(
llvm::from_range, llvm::make_first_range(dap.instruction_breakpoints));
- for (const auto &bp : *breakpoints) {
- const auto *bp_obj = bp.getAsObject();
- if (!bp_obj)
- continue;
+ for (const auto &bp : args.breakpoints) {
// Read instruction breakpoint request.
- InstructionBreakpoint inst_bp(dap, *bp_obj);
+ InstructionBreakpoint inst_bp(dap, bp);
const auto [iv, inserted] = dap.instruction_breakpoints.try_emplace(
- inst_bp.GetInstructionAddressReference(), dap, *bp_obj);
+ inst_bp.GetInstructionAddressReference(), dap, bp);
if (inserted)
iv->second.SetBreakpoint();
else
iv->second.UpdateBreakpoint(inst_bp);
- AppendBreakpoint(&iv->second, response_breakpoints);
+ response_breakpoints.push_back(iv->second.ToProtocolBreakpoint());
seen.erase(inst_bp.GetInstructionAddressReference());
}
@@ -240,9 +50,8 @@ void SetInstructionBreakpointsRequestHandler::operator()(
dap.instruction_breakpoints.erase(addr);
}
- body.try_emplace("breakpoints", std::move(response_breakpoints));
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return protocol::SetInstructionBreakpointsResponseBody{
+ std::move(response_breakpoints)};
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp
index 54c11cfa0b791..5f4f016f6a1ef 100644
--- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp
@@ -20,7 +20,7 @@ void TestGetTargetBreakpointsRequestHandler::operator()(
llvm::json::Array response_breakpoints;
for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) {
auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i));
- AppendBreakpoint(&bp, response_breakpoints);
+ response_breakpoints.push_back(bp.ToProtocolBreakpoint());
}
llvm::json::Object body;
body.try_emplace("breakpoints", std::move(response_breakpoints));
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
index dfdc6319ac9e8..ddae1a8b20243 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp
@@ -9,20 +9,19 @@
#include "InstructionBreakpoint.h"
#include "DAP.h"
-#include "JSONUtils.h"
#include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBTarget.h"
#include "llvm/ADT/StringRef.h"
namespace lldb_dap {
-InstructionBreakpoint::InstructionBreakpoint(DAP &d,
- const llvm::json::Object &obj)
- : Breakpoint(d, obj), m_instruction_address_reference(LLDB_INVALID_ADDRESS),
- m_offset(GetInteger<int64_t>(obj, "offset").value_or(0)) {
- GetString(obj, "instructionReference")
- .value_or("")
- .getAsInteger(0, m_instruction_address_reference);
+InstructionBreakpoint::InstructionBreakpoint(
+ DAP &d, const protocol::InstructionBreakpoint &breakpoint)
+ : Breakpoint(d, breakpoint.condition, breakpoint.hitCondition),
+ m_instruction_address_reference(LLDB_INVALID_ADDRESS),
+ m_offset(breakpoint.offset.value_or(0)) {
+ llvm::StringRef instruction_reference(breakpoint.instructionReference);
+ instruction_reference.getAsInteger(0, m_instruction_address_reference);
m_instruction_address_reference += m_offset;
}
diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.h b/lldb/tools/lldb-dap/InstructionBreakpoint.h
index 6ed980e00d038..a8c8f2113e5eb 100644
--- a/lldb/tools/lldb-dap/InstructionBreakpoint.h
+++ b/lldb/tools/lldb-dap/InstructionBreakpoint.h
@@ -12,6 +12,7 @@
#include "Breakpoint.h"
#include "DAPForward.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/lldb-types.h"
#include <cstdint>
@@ -20,7 +21,8 @@ namespace lldb_dap {
/// Instruction Breakpoint
class InstructionBreakpoint : public Breakpoint {
public:
- InstructionBreakpoint(DAP &d, const llvm::json::Object &obj);
+ InstructionBreakpoint(DAP &d,
+ const protocol::InstructionBreakpoint &breakpoint);
/// Set instruction breakpoint in LLDB as a new breakpoint.
void SetBreakpoint();
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 4409cf5b27e5b..e184e7602ef14 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "JSONUtils.h"
-#include "BreakpointBase.h"
#include "DAP.h"
#include "ExceptionBreakpoint.h"
#include "LLDBUtils.h"
@@ -354,70 +353,6 @@ llvm::json::Value CreateScope(const llvm::StringRef name,
return llvm::json::Value(std::move(object));
}
-// "Breakpoint": {
-// "type": "object",
-// "description": "Information about a Breakpoint created in setBreakpoints
-// or setFunctionBreakpoints.",
-// "properties": {
-// "id": {
-// "type": "integer",
-// "description": "An optional unique identifier for the breakpoint."
-// },
-// "verified": {
-// "type": "boolean",
-// "description": "If true breakpoint could be set (but not necessarily
-// at the desired location)."
-// },
-// "message": {
-// "type": "string",
-// "description": "An optional message about the state of the breakpoint.
-// This is shown to the user and can be used to explain
-// why a breakpoint could not be verified."
-// },
-// "source": {
-// "$ref": "#/definitions/Source",
-// "description": "The source where the breakpoint is located."
-// },
-// "line": {
-// "type": "integer",
-// "description": "The start line of the actual range covered by the
-// breakpoint."
-// },
-// "column": {
-// "type": "integer",
-// "description": "An optional start column of the actual range covered
-// by the breakpoint."
-// },
-// "endLine": {
-// "type": "integer",
-// "description": "An optional end line of the actual range covered by
-// the breakpoint."
-// },
-// "endColumn": {
-// "type": "integer",
-// "description": "An optional end column of the actual range covered by
-// the breakpoint. If no end line is given, then the end
-// column is assumed to be in the start line."
-// }
-// },
-// "required": [ "verified" ]
-// }
-llvm::json::Value CreateBreakpoint(BreakpointBase *bp,
- std::optional<llvm::StringRef> request_path,
- std::optional<uint32_t> request_line,
- std::optional<uint32_t> request_column) {
- llvm::json::Object object;
- if (request_path)
- object.try_emplace("source", CreateSource(*request_path));
- bp->CreateJsonObject(object);
- // We try to add request_line as a fallback
- if (request_line)
- object.try_emplace("line", *request_line);
- if (request_column)
- object.try_emplace("column", *request_column);
- return llvm::json::Value(std::move(object));
-}
-
static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) {
uint64_t debug_info_size = 0;
llvm::StringRef section_name(section.GetName());
@@ -506,12 +441,6 @@ llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module) {
return llvm::json::Value(std::move(object));
}
-void AppendBreakpoint(BreakpointBase *bp, llvm::json::Array &breakpoints,
- std::optional<llvm::StringRef> request_path,
- std::optional<uint32_t> request_line) {
- breakpoints.emplace_back(CreateBreakpoint(bp, request_path, request_line));
-}
-
// "Event": {
// "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, {
// "type": "object",
@@ -567,96 +496,30 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
return filter;
}
-// "Source": {
-// "type": "object",
-// "description": "A Source is a descriptor for source code. It is returned
-// from the debug adapter as part of a StackFrame and it is
-// used by clients when specifying breakpoints.",
-// "properties": {
-// "name": {
-// "type": "string",
-// "description": "The short name of the source. Every source returned
-// from the debug adapter has a name. When sending a
-// source to the debug adapter this name is optional."
-// },
-// "path": {
-// "type": "string",
-// "description": "The path of the source to be shown in the UI. It is
-// only used to locate and load the content of the
-// source if no sourceReference is specified (or its
-// value is 0)."
-// },
-// "sourceReference": {
-// "type": "number",
-// "description": "If sourceReference > 0 the contents of the source must
-// be retrieved through the SourceRequest (even if a path
-// is specified). A sourceReference is only valid for a
-// session, so it must not be used to persist a source."
-// },
-// "presentationHint": {
-// "type": "string",
-// "description": "An optional hint for how to present the source in the
-// UI. A value of 'deemphasize' can be used to indicate
-// that the source is not available or that it is
-// skipped on stepping.",
-// "enum": [ "normal", "emphasize", "deemphasize" ]
-// },
-// "origin": {
-// "type": "string",
-// "description": "The (optional) origin of this source: possible values
-// 'internal module', 'inlined content from source map',
-// etc."
-// },
-// "sources": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/Source"
-// },
-// "description": "An optional list of sources that are related to this
-// source. These may be the source that generated this
-// source."
-// },
-// "adapterData": {
-// "type":["array","boolean","integer","null","number","object","string"],
-// "description": "Optional data that a debug adapter might want to loop
-// through the client. The client should leave the data
-// intact and persist it across sessions. The client
-// should not interpret the data."
-// },
-// "checksums": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/Checksum"
-// },
-// "description": "The checksums associated with this file."
-// }
-// }
-// }
-llvm::json::Value CreateSource(const lldb::SBFileSpec &file) {
- llvm::json::Object object;
+protocol::Source CreateSource(const lldb::SBFileSpec &file) {
+ protocol::Source source;
if (file.IsValid()) {
const char *name = file.GetFilename();
if (name)
- EmplaceSafeString(object, "name", name);
+ source.name = name;
char path[PATH_MAX] = "";
if (file.GetPath(path, sizeof(path)) &&
- lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) {
- EmplaceSafeString(object, "path", std::string(path));
- }
+ lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
+ source.path = path;
}
- return llvm::json::Value(std::move(object));
+ return source;
}
-llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry) {
+protocol::Source CreateSource(const lldb::SBLineEntry &line_entry) {
return CreateSource(line_entry.GetFileSpec());
}
-llvm::json::Value CreateSource(llvm::StringRef source_path) {
- llvm::json::Object source;
+protocol::Source CreateSource(llvm::StringRef source_path) {
+ protocol::Source source;
llvm::StringRef name = llvm::sys::path::filename(source_path);
- EmplaceSafeString(source, "name", name);
- EmplaceSafeString(source, "path", source_path);
- return llvm::json::Value(std::move(source));
+ source.name = name;
+ source.path = source_path;
+ return source;
}
bool ShouldDisplayAssemblySource(
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index d0e20729f4ed9..7c7cf620f0c06 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -198,67 +198,6 @@ GetStringMap(const llvm::json::Object &obj, llvm::StringRef key);
void FillResponse(const llvm::json::Object &request,
llvm::json::Object &response);
-/// Converts \a bp to a JSON value and appends the first valid location to the
-/// \a breakpoints array.
-///
-/// \param[in] bp
-/// A LLDB breakpoint object which will get the first valid location
-/// extracted and converted into a JSON object in the \a breakpoints array
-///
-/// \param[in] breakpoints
-/// A JSON array that will get a llvm::json::Value for \a bp
-/// appended to it.
-///
-/// \param[in] request_path
-/// An optional source path to use when creating the "Source" object of this
-/// breakpoint. If not specified, the "Source" object is created from the
-/// breakpoint's address' LineEntry. It is useful to ensure the same source
-/// paths provided by the setBreakpoints request are returned to the IDE.
-///
-/// \param[in] request_line
-/// An optional line to use when creating the "Breakpoint" object to append.
-/// It is used if the breakpoint has no valid locations.
-/// It is useful to ensure the same line
-/// provided by the setBreakpoints request are returned to the IDE as a
-/// fallback.
-void AppendBreakpoint(
- BreakpointBase *bp, llvm::json::Array &breakpoints,
- std::optional<llvm::StringRef> request_path = std::nullopt,
- std::optional<uint32_t> request_line = std::nullopt);
-
-/// Converts breakpoint location to a debug adapter protocol "Breakpoint".
-///
-/// \param[in] bp
-/// A LLDB breakpoint object to convert into a JSON value
-///
-/// \param[in] request_path
-/// An optional source path to use when creating the "Source" object of this
-/// breakpoint. If not specified, the "Source" object is created from the
-/// breakpoint's address' LineEntry. It is useful to ensure the same source
-/// paths provided by the setBreakpoints request are returned to the IDE.
-///
-/// \param[in] request_line
-/// An optional line to use when creating the resulting "Breakpoint" object.
-/// It is used if the breakpoint has no valid locations.
-/// It is useful to ensure the same line
-/// provided by the setBreakpoints request are returned to the IDE as a
-/// fallback.
-///
-/// \param[in] request_column
-/// An optional column to use when creating the resulting "Breakpoint"
-/// object. It is used if the breakpoint has no valid locations. It is
-/// useful to ensure the same column provided by the setBreakpoints request
-/// are returned to the IDE as a fallback.
-///
-/// \return
-/// A "Breakpoint" JSON object with that follows the formal JSON
-/// definition outlined by Microsoft.
-llvm::json::Value
-CreateBreakpoint(BreakpointBase *bp,
- std::optional<llvm::StringRef> request_path = std::nullopt,
- std::optional<uint32_t> request_line = std::nullopt,
- std::optional<uint32_t> request_column = std::nullopt);
-
/// Converts a LLDB module to a VS Code DAP module for use in "modules" events.
///
/// \param[in] target
@@ -323,7 +262,7 @@ llvm::json::Value CreateScope(const llvm::StringRef name,
/// \return
/// A "Source" JSON object that follows the formal JSON
/// definition outlined by Microsoft.
-llvm::json::Value CreateSource(const lldb::SBFileSpec &file);
+protocol::Source CreateSource(const lldb::SBFileSpec &file);
/// Create a "Source" JSON object as described in the debug adapter definition.
///
@@ -334,7 +273,7 @@ llvm::json::Value CreateSource(const lldb::SBFileSpec &file);
/// \return
/// A "Source" JSON object that follows the formal JSON
/// definition outlined by Microsoft.
-llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry);
+protocol::Source CreateSource(const lldb::SBLineEntry &line_entry);
/// Create a "Source" object for a given source path.
///
@@ -344,7 +283,7 @@ llvm::json::Value CreateSource(const lldb::SBLineEntry &line_entry);
/// \return
/// A "Source" JSON object that follows the formal JSON
/// definition outlined by Microsoft.
-llvm::json::Value CreateSource(llvm::StringRef source_path);
+protocol::Source CreateSource(llvm::StringRef source_path);
/// Return true if the given line entry should be displayed as assembly.
///
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 4204ae7785e63..316e146d43a0f 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -376,4 +376,74 @@ bool fromJSON(const llvm::json::Value &Params, StepOutArguments &SOA,
OM.mapOptional("granularity", SOA.granularity);
}
+bool fromJSON(const llvm::json::Value &Params, SetBreakpointsArguments &SBA,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("source", SBA.source) &&
+ O.map("breakpoints", SBA.breakpoints) && O.map("lines", SBA.lines) &&
+ O.map("sourceModified", SBA.sourceModified);
+}
+
+llvm::json::Value toJSON(const SetBreakpointsResponseBody &SBR) {
+ json::Object result;
+ result["breakpoints"] = SBR.breakpoints;
+ return result;
+}
+
+bool fromJSON(const llvm::json::Value &Params,
+ SetFunctionBreakpointsArguments &SFBA, llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("breakpoints", SFBA.breakpoints);
+}
+
+llvm::json::Value toJSON(const SetFunctionBreakpointsResponseBody &SFBR) {
+ json::Object result;
+ result["breakpoints"] = SFBR.breakpoints;
+ return result;
+}
+
+bool fromJSON(const llvm::json::Value &Params,
+ SetInstructionBreakpointsArguments &SIBA, llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("breakpoints", SIBA.breakpoints);
+}
+
+llvm::json::Value toJSON(const SetInstructionBreakpointsResponseBody &SIBR) {
+ json::Object result;
+ result["breakpoints"] = SIBR.breakpoints;
+ return result;
+}
+
+bool fromJSON(const llvm::json::Value &Params,
+ DataBreakpointInfoArguments &DBIA, llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("variablesReference", DBIA.variablesReference) &&
+ O.map("name", DBIA.name) && O.map("frameId", DBIA.frameId) &&
+ O.map("bytes", DBIA.bytes) && O.map("asAddress", DBIA.asAddress) &&
+ O.map("mode", DBIA.mode);
+}
+
+llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &DBIRB) {
+ json::Object result;
+ result["dataId"] = DBIRB.dataId ? *DBIRB.dataId : llvm::json::Value(nullptr);
+ result["description"] = DBIRB.description;
+ if (DBIRB.accessTypes)
+ result["accessTypes"] = *DBIRB.accessTypes;
+ if (DBIRB.canPersist)
+ result["canPersist"] = *DBIRB.canPersist;
+ return result;
+}
+
+bool fromJSON(const llvm::json::Value &Params,
+ SetDataBreakpointsArguments &SDBA, llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("breakpoints", SDBA.breakpoints);
+}
+
+llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) {
+ json::Object result;
+ result["breakpoints"] = SDBR.breakpoints;
+ 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 4f17d6e79080d..c6456b4113320 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -559,6 +559,153 @@ struct BreakpointLocationsResponseBody {
};
llvm::json::Value toJSON(const BreakpointLocationsResponseBody &);
+/// Arguments for `setBreakpoints` request.
+struct SetBreakpointsArguments {
+ /// The source location of the breakpoints; either `source.path` or
+ /// `source.sourceReference` must be specified.
+ Source source;
+
+ /// The code locations of the breakpoints.
+ std::optional<std::vector<SourceBreakpoint>> breakpoints;
+
+ /// Deprecated: The code locations of the breakpoints.
+ std::optional<std::vector<uint32_t>> lines;
+
+ /// A value of true indicates that the underlying source has been modified
+ /// which results in new breakpoint locations.
+ std::optional<bool> sourceModified;
+};
+bool fromJSON(const llvm::json::Value &, SetBreakpointsArguments &,
+ llvm::json::Path);
+
+/// Response to `setBreakpoints` request.
+/// Returned is information about each breakpoint created by this request.
+/// This includes the actual code location and whether the breakpoint could be
+/// verified. The breakpoints returned are in the same order as the elements of
+/// the breakpoints (or the deprecated lines) array in the arguments.
+struct SetBreakpointsResponseBody {
+ /// Information about the breakpoints.
+ /// The array elements are in the same order as the elements of the
+ /// `breakpoints` (or the deprecated `lines`) array in the arguments.
+ std::vector<Breakpoint> breakpoints;
+};
+llvm::json::Value toJSON(const SetBreakpointsResponseBody &);
+
+/// Arguments for `setFunctionBreakpoints` request.
+struct SetFunctionBreakpointsArguments {
+ /// The function names of the breakpoints.
+ std::vector<FunctionBreakpoint> breakpoints;
+};
+bool fromJSON(const llvm::json::Value &, SetFunctionBreakpointsArguments &,
+ llvm::json::Path);
+
+/// Response to `setFunctionBreakpoints` request.
+/// Returned is information about each breakpoint created by this request.
+struct SetFunctionBreakpointsResponseBody {
+ /// Information about the breakpoints. The array elements correspond to the
+ /// elements of the `breakpoints` array.
+ std::vector<Breakpoint> breakpoints;
+};
+llvm::json::Value toJSON(const SetFunctionBreakpointsResponseBody &);
+
+/// Arguments for `setInstructionBreakpoints` request.
+struct SetInstructionBreakpointsArguments {
+ /// The instruction references of the breakpoints.
+ std::vector<InstructionBreakpoint> breakpoints;
+};
+bool fromJSON(const llvm::json::Value &, SetInstructionBreakpointsArguments &,
+ llvm::json::Path);
+
+/// Response to `setInstructionBreakpoints` request.
+struct SetInstructionBreakpointsResponseBody {
+ /// Information about the breakpoints. The array elements correspond to the
+ /// elements of the `breakpoints` array.
+ std::vector<Breakpoint> breakpoints;
+};
+llvm::json::Value toJSON(const SetInstructionBreakpointsResponseBody &);
+
+/// Arguments for `dataBreakpointInfo` request.
+struct DataBreakpointInfoArguments {
+ /// Reference to the variable container if the data breakpoint is requested
+ /// for a child of the container. The `variablesReference` must have been
+ /// obtained in the current suspended state.See 'Lifetime of Object
+ /// References' in the Overview section for details.
+ std::optional<int64_t> variablesReference;
+
+ /// The name of the variable's child to obtain data breakpoint information
+ /// for. If `variablesReference` isn't specified, this can be an expression,
+ /// or an address if `asAddress` is also true.
+ std::string name;
+
+ /// When `name` is an expression, evaluate it in the scope of this stack
+ /// frame. If not specified, the expression is evaluated in the global scope.
+ /// When `asAddress` is true, the `frameId` is ignored.
+ std::optional<uint64_t> frameId;
+
+ /// If specified, a debug adapter should return information for the range of
+ /// memory extending `bytes` number of bytes from the address or variable
+ /// specified by `name`. Breakpoints set using the resulting data ID should
+ /// pause on data access anywhere within that range.
+ /// Clients may set this property only if the `supportsDataBreakpointBytes`
+ /// capability is true.
+ std::optional<int64_t> bytes;
+
+ /// If `true`, the `name` is a memory address and the debugger should
+ /// interpret it as a decimal value, or hex value if it is prefixed with `0x`.
+ /// Clients may set this property only if the `supportsDataBreakpointBytes`
+ /// capability is true.
+ std::optional<bool> asAddress;
+
+ /// The mode of the desired breakpoint. If defined, this must be one of the
+ /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
+ std::optional<std::string> mode;
+};
+bool fromJSON(const llvm::json::Value &, DataBreakpointInfoArguments &,
+ llvm::json::Path);
+
+/// Response to `dataBreakpointInfo` request.
+struct DataBreakpointInfoResponseBody {
+ /// An identifier for the data on which a data breakpoint can be registered
+ /// with the `setDataBreakpoints` request or null if no data breakpoint is
+ /// available. If a `variablesReference` or `frameId` is passed, the `dataId`
+ /// is valid in the current suspended state, otherwise it's valid
+ /// indefinitely. See 'Lifetime of Object References' in the Overview section
+ /// for details. Breakpoints set using the `dataId` in the
+ /// `setDataBreakpoints` request may outlive the lifetime of the associated
+ /// `dataId`.
+ std::optional<std::string> dataId;
+
+ /// UI string that describes on what data the breakpoint is set on or why a
+ /// data breakpoint is not available.
+ std::string description;
+
+ /// Attribute lists the available access types for a potential data
+ /// breakpoint. A UI client could surface this information.
+ std::optional<std::vector<DataBreakpointAccessType>> accessTypes;
+
+ /// Attribute indicates that a potential data breakpoint could be persisted
+ /// across sessions.
+ std::optional<bool> canPersist;
+};
+llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &);
+
+/// Arguments for `setDataBreakpoints` request.
+struct SetDataBreakpointsArguments {
+ /// The contents of this array replaces all existing data breakpoints. An
+ /// empty array clears all data breakpoints.
+ std::vector<DataBreakpointInfo> breakpoints;
+};
+bool fromJSON(const llvm::json::Value &, SetDataBreakpointsArguments &,
+ llvm::json::Path);
+
+/// Response to `setDataBreakpoints` request.
+struct SetDataBreakpointsResponseBody {
+ /// Information about the data breakpoints. The array elements correspond to
+ /// the elements of the input argument `breakpoints` array.
+ std::vector<Breakpoint> breakpoints;
+};
+llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &);
+
} // namespace lldb_dap::protocol
#endif
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index 967c1d2321502..2b7419916268b 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -43,6 +43,32 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
O.map("sourceReference", S.sourceReference);
}
+llvm::json::Value toJSON(PresentationHint hint) {
+ switch (hint) {
+ case ePresentationHintNormal:
+ return "normal";
+ case ePresentationHintEmphasize:
+ return "emphasize";
+ case ePresentationHintDeemphasize:
+ return "deemphasize";
+ }
+ llvm_unreachable("unhandled presentation hint.");
+}
+
+llvm::json::Value toJSON(const Source &S) {
+ json::Object result;
+ if (S.name)
+ result.insert({"name", *S.name});
+ if (S.path)
+ result.insert({"path", *S.path});
+ if (S.sourceReference)
+ result.insert({"sourceReference", *S.sourceReference});
+ if (S.presentationHint)
+ result.insert({"presentationHint", *S.presentationHint});
+
+ return result;
+}
+
json::Value toJSON(const ExceptionBreakpointsFilter &EBF) {
json::Object result{{"filter", EBF.filter}, {"label", EBF.label}};
@@ -274,4 +300,108 @@ json::Value toJSON(const BreakpointLocation &B) {
return result;
}
+llvm::json::Value toJSON(const BreakpointReason &BR) {
+ switch (BR) {
+ case BreakpointReason::eBreakpointReasonPending:
+ return "pending";
+ case BreakpointReason::eBreakpointReasonFailed:
+ return "failed";
+ }
+ llvm_unreachable("unhandled breakpoint reason.");
+}
+
+json::Value toJSON(const Breakpoint &BP) {
+ json::Object result{{"verified", BP.verified}};
+
+ if (BP.id)
+ result.insert({"id", *BP.id});
+ if (BP.message)
+ result.insert({"message", *BP.message});
+ if (BP.source)
+ result.insert({"source", *BP.source});
+ if (BP.line)
+ result.insert({"line", *BP.line});
+ if (BP.column)
+ result.insert({"column", *BP.column});
+ if (BP.endLine)
+ result.insert({"endLine", *BP.endLine});
+ if (BP.endColumn)
+ result.insert({"endColumn", *BP.endColumn});
+ if (BP.instructionReference)
+ result.insert({"instructionReference", *BP.instructionReference});
+ if (BP.offset)
+ result.insert({"offset", *BP.offset});
+ if (BP.reason) {
+ result.insert({"reason", *BP.reason});
+ }
+
+ return result;
+}
+
+bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("line", SB.line) && O.map("column", SB.column) &&
+ O.map("condition", SB.condition) &&
+ O.map("hitCondition", SB.hitCondition) &&
+ O.map("logMessage", SB.logMessage) && O.map("mode", SB.mode);
+}
+
+bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("name", FB.name) && O.map("condition", FB.condition) &&
+ O.map("hitCondition", FB.hitCondition);
+}
+
+bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT,
+ llvm::json::Path P) {
+ auto rawAccessType = Params.getAsString();
+ if (!rawAccessType) {
+ P.report("expected a string");
+ return false;
+ }
+ std::optional<DataBreakpointAccessType> accessType =
+ StringSwitch<std::optional<DataBreakpointAccessType>>(*rawAccessType)
+ .Case("read", eDataBreakpointAccessTypeRead)
+ .Case("write", eDataBreakpointAccessTypeWrite)
+ .Case("readWrite", eDataBreakpointAccessTypeReadWrite)
+ .Default(std::nullopt);
+ if (!accessType) {
+ P.report("unexpected value, expected 'read', 'write', or 'readWrite'");
+ return false;
+ }
+ DBAT = *accessType;
+ return true;
+}
+
+llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) {
+ switch (DBAT) {
+ case eDataBreakpointAccessTypeRead:
+ return "read";
+ case eDataBreakpointAccessTypeWrite:
+ return "write";
+ case eDataBreakpointAccessTypeReadWrite:
+ return "readWrite";
+ }
+ llvm_unreachable("unhandled data breakpoint access type.");
+}
+
+bool fromJSON(const llvm::json::Value &Params, DataBreakpointInfo &DBI,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("dataId", DBI.dataId) &&
+ O.map("accessType", DBI.accessType) &&
+ O.map("condition", DBI.condition) &&
+ O.map("hitCondition", DBI.hitCondition);
+}
+
+bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("instructionReference", IB.instructionReference) &&
+ O.map("offset", IB.offset) && O.map("condition", IB.condition) &&
+ O.map("hitCondition", IB.hitCondition) && O.map("mode", IB.mode);
+}
+
} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index 8ea483d810e02..1f0cb1e0b2d41 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -20,6 +20,7 @@
#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H
+#include "lldb/lldb-defines.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/JSON.h"
#include <cstdint>
@@ -273,6 +274,7 @@ enum PresentationHint : unsigned {
ePresentationHintEmphasize,
ePresentationHintDeemphasize,
};
+llvm::json::Value toJSON(PresentationHint hint);
/// A `Source` is a descriptor for source code. It is returned from the debug
/// adapter as part of a `StackFrame` and it is used by clients when specifying
@@ -302,6 +304,7 @@ struct Source {
// unsupported keys: origin, sources, adapterData, checksums
};
bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path);
+llvm::json::Value toJSON(const Source &);
/// The granularity of one `step` in the stepping requests `next`, `stepIn`,
/// `stepOut` and `stepBack`.
@@ -350,6 +353,187 @@ struct BreakpointLocation {
};
llvm::json::Value toJSON(const BreakpointLocation &);
+/// A machine-readable explanation of why a breakpoint may not be verified.
+enum class BreakpointReason : unsigned {
+ /// Indicates a breakpoint might be verified in the future, but
+ /// the adapter cannot verify it in the current state.
+ eBreakpointReasonPending,
+ /// Indicates a breakpoint was not able to be verified, and the
+ /// adapter does not believe it can be verified without intervention.
+ eBreakpointReasonFailed,
+};
+llvm::json::Value toJSON(const BreakpointReason &);
+
+/// Information about a breakpoint created in `setBreakpoints`,
+/// `setFunctionBreakpoints`, `setInstructionBreakpoints`, or
+/// `setDataBreakpoints` requests.
+struct Breakpoint {
+ /// The identifier for the breakpoint. It is needed if breakpoint events are
+ /// used to update or remove breakpoints.
+ std::optional<int> id;
+
+ /// If true, the breakpoint could be set (but not necessarily at the desired
+ /// location).
+ bool verified = false;
+
+ /// A message about the state of the breakpoint.
+ /// This is shown to the user and can be used to explain why a breakpoint
+ /// could not be verified.
+ std::optional<std::string> message;
+
+ /// The source where the breakpoint is located.
+ std::optional<Source> source;
+
+ /// The start line of the actual range covered by the breakpoint.
+ std::optional<uint32_t> line;
+
+ /// Start position of the source range covered by the breakpoint. It is
+ /// measured in UTF-16 code units and the client capability `columnsStartAt1`
+ /// determines whether it is 0- or 1-based.
+ std::optional<uint32_t> column;
+
+ /// The end line of the actual range covered by the breakpoint.
+ std::optional<uint32_t> endLine;
+
+ /// End position of the source range covered by the breakpoint. It is measured
+ /// in UTF-16 code units and the client capability `columnsStartAt1`
+ /// determines whether it is 0- or 1-based. If no end line is given, then the
+ /// end column is assumed to be in the start line.
+ std::optional<uint32_t> endColumn;
+
+ /// A memory reference to where the breakpoint is set.
+ std::optional<std::string> instructionReference;
+
+ /// The offset from the instruction reference.
+ /// This can be negative.
+ std::optional<int32_t> offset;
+
+ /// A machine-readable explanation of why a breakpoint may not be verified. If
+ /// a breakpoint is verified or a specific reason is not known, the adapter
+ /// should omit this property.
+ std::optional<BreakpointReason> reason;
+};
+llvm::json::Value toJSON(const Breakpoint &);
+
+/// Properties of a breakpoint or logpoint passed to the `setBreakpoints`
+/// request
+struct SourceBreakpoint {
+ /// The source line of the breakpoint or logpoint.
+ uint32_t line = LLDB_INVALID_LINE_NUMBER;
+
+ /// Start position within source line of the breakpoint or logpoint. It is
+ /// measured in UTF-16 code units and the client capability `columnsStartAt1`
+ /// determines whether it is 0- or 1-based.
+ std::optional<uint32_t> column;
+
+ /// The expression for conditional breakpoints.
+ /// It is only honored by a debug adapter if the corresponding capability
+ /// `supportsConditionalBreakpoints` is true.
+ std::optional<std::string> condition;
+
+ /// The expression that controls how many hits of the breakpoint are ignored.
+ /// The debug adapter is expected to interpret the expression as needed.
+ /// The attribute is only honored by a debug adapter if the corresponding
+ /// capability `supportsHitConditionalBreakpoints` is true.
+ /// If both this property and `condition` are specified, `hitCondition` should
+ /// be evaluated only if the `condition` is met, and the debug adapter should
+ /// stop only if both conditions are met.
+ std::optional<std::string> hitCondition;
+
+ /// If this attribute exists and is non-empty, the debug adapter must not
+ /// 'break' (stop)
+ /// but log the message instead. Expressions within `{}` are interpolated.
+ /// The attribute is only honored by a debug adapter if the corresponding
+ /// capability `supportsLogPoints` is true.
+ /// If either `hitCondition` or `condition` is specified, then the message
+ /// should only be logged if those conditions are met.
+ std::optional<std::string> logMessage;
+
+ /// The mode of this breakpoint. If defined, this must be one of the
+ /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
+ std::optional<std::string> mode;
+};
+bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path);
+
+/// Properties of a breakpoint passed to the `setFunctionBreakpoints` request.
+struct FunctionBreakpoint {
+ /// The name of the function.
+ std::string name;
+
+ /// An expression for conditional breakpoints.
+ /// It is only honored by a debug adapter if the corresponding capability
+ /// `supportsConditionalBreakpoints` is true.
+ std::optional<std::string> condition;
+
+ /// An expression that controls how many hits of the breakpoint are ignored.
+ /// The debug adapter is expected to interpret the expression as needed.
+ /// The attribute is only honored by a debug adapter if the corresponding
+ /// capability `supportsHitConditionalBreakpoints` is true.
+ std::optional<std::string> hitCondition;
+};
+bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &,
+ llvm::json::Path);
+
+/// This enumeration defines all possible access types for data breakpoints.
+/// Values: ‘read’, ‘write’, ‘readWrite’
+enum DataBreakpointAccessType : unsigned {
+ eDataBreakpointAccessTypeRead,
+ eDataBreakpointAccessTypeWrite,
+ eDataBreakpointAccessTypeReadWrite
+};
+bool fromJSON(const llvm::json::Value &, DataBreakpointAccessType &,
+ llvm::json::Path);
+llvm::json::Value toJSON(const DataBreakpointAccessType &);
+
+/// Properties of a data breakpoint passed to the `setDataBreakpoints` request.
+struct DataBreakpointInfo {
+ /// An id representing the data. This id is returned from the
+ /// `dataBreakpointInfo` request.
+ std::string dataId;
+
+ /// The access type of the data.
+ std::optional<DataBreakpointAccessType> accessType;
+
+ /// An expression for conditional breakpoints.
+ std::optional<std::string> condition;
+
+ /// An expression that controls how many hits of the breakpoint are ignored.
+ /// The debug adapter is expected to interpret the expression as needed.
+ std::optional<std::string> hitCondition;
+};
+bool fromJSON(const llvm::json::Value &, DataBreakpointInfo &,
+ llvm::json::Path);
+
+/// Properties of a breakpoint passed to the `setInstructionBreakpoints` request
+struct InstructionBreakpoint {
+ /// The instruction reference of the breakpoint.
+ /// This should be a memory or instruction pointer reference from an
+ /// `EvaluateResponse`, `Variable`, `StackFrame`, `GotoTarget`, or
+ /// `Breakpoint`.
+ std::string instructionReference;
+
+ /// The offset from the instruction reference in bytes.
+ /// This can be negative.
+ std::optional<int32_t> offset;
+
+ /// An expression for conditional breakpoints.
+ /// It is only honored by a debug adapter if the corresponding capability
+ /// `supportsConditionalBreakpoints` is true.
+ std::optional<std::string> condition;
+
+ /// An expression that controls how many hits of the breakpoint are ignored.
+ /// The debug adapter is expected to interpret the expression as needed.
+ /// The attribute is only honored by a debug adapter if the corresponding
+ /// capability `supportsHitConditionalBreakpoints` is true.
+ std::optional<std::string> hitCondition;
+
+ /// The mode of this breakpoint. If defined, this must be one of the
+ /// `breakpointModes` the debug adapter advertised in its `Capabilities`.
+ std::optional<std::string> mode;
+};
+bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &,
+ llvm::json::Path);
+
} // namespace lldb_dap::protocol
#endif
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
index a7e00cae36fbc..4581c995b4260 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp
@@ -26,13 +26,12 @@
namespace lldb_dap {
-SourceBreakpoint::SourceBreakpoint(DAP &dap, const llvm::json::Object &obj)
- : Breakpoint(dap, obj),
- m_log_message(GetString(obj, "logMessage").value_or("").str()),
- m_line(
- GetInteger<uint64_t>(obj, "line").value_or(LLDB_INVALID_LINE_NUMBER)),
- m_column(GetInteger<uint64_t>(obj, "column")
- .value_or(LLDB_INVALID_COLUMN_NUMBER)) {}
+SourceBreakpoint::SourceBreakpoint(DAP &dap,
+ const protocol::SourceBreakpoint &breakpoint)
+ : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition),
+ m_log_message(breakpoint.logMessage.value_or("")),
+ m_line(breakpoint.line),
+ m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {}
void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
lldb::SBMutex lock = m_dap.GetAPIMutex();
diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h
index d01411547d12a..5b15296f861c5 100644
--- a/lldb/tools/lldb-dap/SourceBreakpoint.h
+++ b/lldb/tools/lldb-dap/SourceBreakpoint.h
@@ -11,6 +11,7 @@
#include "Breakpoint.h"
#include "DAPForward.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/API/SBError.h"
#include "llvm/ADT/StringRef.h"
#include <cstdint>
@@ -21,7 +22,7 @@ namespace lldb_dap {
class SourceBreakpoint : public Breakpoint {
public:
- SourceBreakpoint(DAP &d, const llvm::json::Object &obj);
+ SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint);
// Set this breakpoint in LLDB as a new breakpoint
void SetBreakpoint(const llvm::StringRef source_path);
diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp
index a94cbcdbc4122..73ed4fdbae1b8 100644
--- a/lldb/tools/lldb-dap/Watchpoint.cpp
+++ b/lldb/tools/lldb-dap/Watchpoint.cpp
@@ -8,25 +8,24 @@
#include "Watchpoint.h"
#include "DAP.h"
-#include "JSONUtils.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/API/SBTarget.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/JSON.h"
#include <cstdint>
#include <string>
namespace lldb_dap {
-Watchpoint::Watchpoint(DAP &d, const llvm::json::Object &obj)
- : BreakpointBase(d, obj) {
- llvm::StringRef dataId = GetString(obj, "dataId").value_or("");
- std::string accessType = GetString(obj, "accessType").value_or("").str();
+Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint)
+ : BreakpointBase(d, breakpoint.condition, breakpoint.hitCondition) {
+ llvm::StringRef dataId = breakpoint.dataId;
auto [addr_str, size_str] = dataId.split('/');
llvm::to_integer(addr_str, m_addr, 16);
llvm::to_integer(size_str, m_size);
- m_options.SetWatchpointTypeRead(accessType != "write");
- if (accessType != "read")
+ m_options.SetWatchpointTypeRead(breakpoint.accessType !=
+ protocol::eDataBreakpointAccessTypeWrite);
+ if (breakpoint.accessType != protocol::eDataBreakpointAccessTypeRead)
m_options.SetWatchpointTypeWrite(lldb::eWatchpointWriteTypeOnModify);
}
@@ -38,14 +37,17 @@ void Watchpoint::SetHitCondition() {
m_wp.SetIgnoreCount(hitCount - 1);
}
-void Watchpoint::CreateJsonObject(llvm::json::Object &object) {
+protocol::Breakpoint Watchpoint::ToProtocolBreakpoint() {
+ protocol::Breakpoint breakpoint;
if (!m_error.IsValid() || m_error.Fail()) {
- object.try_emplace("verified", false);
+ breakpoint.verified = false;
if (m_error.Fail())
- EmplaceSafeString(object, "message", m_error.GetCString());
+ breakpoint.message = m_error.GetCString();
} else {
- object.try_emplace("verified", true);
+ breakpoint.verified = true;
}
+
+ return breakpoint;
}
void Watchpoint::SetWatchpoint() {
diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h
index bf52b41281f29..b7fe58fe73501 100644
--- a/lldb/tools/lldb-dap/Watchpoint.h
+++ b/lldb/tools/lldb-dap/Watchpoint.h
@@ -11,6 +11,7 @@
#include "BreakpointBase.h"
#include "DAPForward.h"
+#include "Protocol/ProtocolTypes.h"
#include "lldb/API/SBError.h"
#include "lldb/API/SBWatchpoint.h"
#include "lldb/API/SBWatchpointOptions.h"
@@ -21,12 +22,13 @@ namespace lldb_dap {
class Watchpoint : public BreakpointBase {
public:
- Watchpoint(DAP &d, const llvm::json::Object &obj);
+ Watchpoint(DAP &d, const protocol::DataBreakpointInfo &breakpoint);
Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), m_wp(wp) {}
void SetCondition() override;
void SetHitCondition() override;
- void CreateJsonObject(llvm::json::Object &object) override;
+
+ protocol::Breakpoint ToProtocolBreakpoint() override;
void SetWatchpoint();
diff --git a/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h
index f1f4f4db709dd..0a6f3f2cb7755 100644
--- a/llvm/include/llvm/Support/JSON.h
+++ b/llvm/include/llvm/Support/JSON.h
@@ -781,7 +781,7 @@ inline bool fromJSON(const Value &E, unsigned int &Out, Path P) {
Out = *S;
return true;
}
- P.report("expected integer");
+ P.report("expected unsigned integer");
return false;
}
inline bool fromJSON(const Value &E, uint64_t &Out, Path P) {
More information about the llvm-commits
mailing list