https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/137448
>From d0d8c7e24fd7ee37f4a3678537df1e28c8318d04 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 26 Apr 2025 10:25:21 +0200 Subject: [PATCH 1/4] adding breakpoints protocol types --- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 178 +++++++++++++++++++ llvm/include/llvm/Support/JSON.h | 8 + 2 files changed, 186 insertions(+) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 54941f24efbd9..8b193287acc19 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -322,6 +322,184 @@ enum SteppingGranularity : unsigned { bool fromJSON(const llvm::json::Value &, SteppingGranularity &, llvm::json::Path); +/// Information about a breakpoint created in `setBreakpoints`, `setFunctionBreakpoints`, `setInstructionBreakpoints`, or `setDataBreakpoints` requests. +struct Breakpoint { + /// A machine-readable explanation of why a breakpoint may not be verified. + enum class Reason : 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, + }; + + /// 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; + + /// 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<int64_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<Reason> 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; + + /// 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); + +/// 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<int64_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/llvm/include/llvm/Support/JSON.h b/llvm/include/llvm/Support/JSON.h index 7f7f5f6228763..f1f4f4db709dd 100644 --- a/llvm/include/llvm/Support/JSON.h +++ b/llvm/include/llvm/Support/JSON.h @@ -776,6 +776,14 @@ inline bool fromJSON(const Value &E, bool &Out, Path P) { P.report("expected boolean"); return false; } +inline bool fromJSON(const Value &E, unsigned int &Out, Path P) { + if (auto S = E.getAsInteger()) { + Out = *S; + return true; + } + P.report("expected integer"); + return false; +} inline bool fromJSON(const Value &E, uint64_t &Out, Path P) { if (auto S = E.getAsUINT64()) { Out = *S; >From 2c39c99082df8429f45258c1c9911a9c8f858e3a Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 26 Apr 2025 10:45:37 +0200 Subject: [PATCH 2/4] add all breakpoint requests JSON types --- .../lldb-dap/Protocol/ProtocolRequests.h | 85 +++++++++++++++++++ lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 60 +++++++++++++ 2 files changed, 145 insertions(+) diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 33f93cc38799a..ae515bd186c76 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -377,6 +377,91 @@ bool fromJSON(const llvm::json::Value &, StepOutArguments &, llvm::json::Path); /// body field is required. using StepOutResponse = VoidResponse; +/// 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 `setExceptionBreakpoints` request. +struct SetExceptionBreakpointsArguments { + /// Set of exception filters specified by their ID. The set of all possible + /// exception filters is defined by the `exceptionBreakpointFilters` + /// capability. The `filter` and `filterOptions` sets are additive. + std::vector<std::string> filters; + + /// Set of exception filters and their options. The set of all possible + /// exception filters is defined by the `exceptionBreakpointFilters` + /// capability. This attribute is only honored by a debug adapter if the + /// corresponding capability `supportsExceptionFilterOptions` is true. The + /// `filter` and `filterOptions` sets are additive. + std::optional<std::vector<ExceptionFilterOptions>> filterOptions; + + /// Configuration options for selected exceptions. + /// The attribute is only honored by a debug adapter if the corresponding + /// capability `supportsExceptionOptions` is true. + std::optional<std::vector<ExceptionOptions>> exceptionOptions; +}; + +/// 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 &); + } // namespace lldb_dap::protocol #endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 8b193287acc19..f10adbac9e41c 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -499,6 +499,66 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); +/// An ExceptionFilterOptions is used to specify an exception filter together with a condition for the `setExceptionBreakpoints` request. +struct ExceptionFilterOptions { + /// ID of an exception filter returned by the `exceptionBreakpointFilters` + /// capability. + std::string filterId; + + /// An expression for conditional exceptions. + /// The exception breaks into the debugger if the result of the condition is + /// true. + std::optional<std::string> condition; + + /// The mode of this exception 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 &, ExceptionFilterOptions &, + llvm::json::Path); + +/// This enumeration defines all possible conditions when a thrown exception +/// should result in a break. +enum ExceptionBreakMode : unsigned { + /// Never breaks. + eExceptionBreakModeNever, + /// Always breaks. + eExceptionBreakModeAlways, + /// Breaks when the exception is unhandled. + eExceptionBreakModeUnhandled, + /// Breaks if the exception is not handled by user code. + eExceptionBreakModeUserUnhandled +}; +bool fromJSON(const llvm::json::Value &, ExceptionBreakMode &, + llvm::json::Path); + +/// An ExceptionPathSegment represents a segment in a path that is used to +/// match leafs or nodes in a tree of exceptions. +struct ExceptionPathSegment { + /// If false or missing, this segment matches the names provided. Otherwise, + /// it matches anything except the names provided. + std::optional<bool> negate; + + /// Depending on the value of `negate`, the names that should match or not + /// match. + std::vector<std::string> names; +}; +bool fromJSON(const llvm::json::Value &, ExceptionPathSegment &, + llvm::json::Path); + +/// ExceptionOptions assigns configuration options to a set of exceptions. +struct ExceptionOptions { + /// A path that selects a single or multiple exceptions in a tree. If `path` + /// is missing, the whole tree is selected. + /// By convention, the first segment of the path is a category that is used + /// to group exceptions in the UI. + std::optional<std::vector<ExceptionPathSegment>> path; + + /// Condition when a thrown exception should result in a break. + ExceptionBreakMode breakMode; +}; +bool fromJSON(const llvm::json::Value &, ExceptionOptions &, + llvm::json::Path); } // namespace lldb_dap::protocol >From a18da83181ad303ef344f88f61ea00a3306c3b23 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 26 Apr 2025 11:12:31 +0200 Subject: [PATCH 3/4] decouple JSON from DAP Breakpoint classes --- lldb/tools/lldb-dap/Breakpoint.h | 4 ++- lldb/tools/lldb-dap/BreakpointBase.cpp | 10 +++--- lldb/tools/lldb-dap/BreakpointBase.h | 3 +- lldb/tools/lldb-dap/FunctionBreakpoint.cpp | 8 ++--- lldb/tools/lldb-dap/FunctionBreakpoint.h | 3 +- lldb/tools/lldb-dap/InstructionBreakpoint.cpp | 15 ++++---- lldb/tools/lldb-dap/InstructionBreakpoint.h | 4 ++- .../lldb-dap/Protocol/ProtocolRequests.h | 6 ++-- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 34 ++++++++++--------- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 13 ++++--- lldb/tools/lldb-dap/SourceBreakpoint.h | 3 +- 11 files changed, 55 insertions(+), 48 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h index 580017125af44..987dbeadd4659 100644 --- a/lldb/tools/lldb-dap/Breakpoint.h +++ b/lldb/tools/lldb-dap/Breakpoint.h @@ -17,7 +17,9 @@ 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(); } diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp index 331ce8efee9bc..960dc5fc5ee56 100644 --- a/lldb/tools/lldb-dap/BreakpointBase.cpp +++ b/lldb/tools/lldb-dap/BreakpointBase.cpp @@ -12,11 +12,11 @@ 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..e7aef44cc9d9a 100644 --- a/lldb/tools/lldb-dap/BreakpointBase.h +++ b/lldb/tools/lldb-dap/BreakpointBase.h @@ -18,7 +18,8 @@ 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; 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/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/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index ae515bd186c76..b1a395ec4ae3d 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -398,9 +398,9 @@ bool fromJSON(const llvm::json::Value &, SetBreakpointsArguments &, /// 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. +/// 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 diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index f10adbac9e41c..216dcd907ae15 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h @@ -322,7 +322,9 @@ enum SteppingGranularity : unsigned { bool fromJSON(const llvm::json::Value &, SteppingGranularity &, llvm::json::Path); -/// Information about a breakpoint created in `setBreakpoints`, `setFunctionBreakpoints`, `setInstructionBreakpoints`, or `setDataBreakpoints` requests. +/// Information about a breakpoint created in `setBreakpoints`, +/// `setFunctionBreakpoints`, `setInstructionBreakpoints`, or +/// `setDataBreakpoints` requests. struct Breakpoint { /// A machine-readable explanation of why a breakpoint may not be verified. enum class Reason : unsigned { @@ -343,8 +345,8 @@ struct Breakpoint { bool verified; /// 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. + /// 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. @@ -362,10 +364,9 @@ struct 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. + /// 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. @@ -373,7 +374,7 @@ struct Breakpoint { /// The offset from the instruction reference. /// This can be negative. - std::optional<int64_t> offset; + 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 @@ -382,7 +383,8 @@ struct Breakpoint { }; llvm::json::Value toJSON(const Breakpoint &); -/// Properties of a breakpoint or logpoint passed to the `setBreakpoints` request +/// Properties of a breakpoint or logpoint passed to the `setBreakpoints` +/// request struct SourceBreakpoint { /// The source line of the breakpoint or logpoint. uint32_t line; @@ -419,8 +421,7 @@ struct SourceBreakpoint { /// `breakpointModes` the debug adapter advertised in its `Capabilities`. std::optional<std::string> mode; }; -bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path); /// Properties of a breakpoint passed to the `setFunctionBreakpoints` request. struct FunctionBreakpoint { @@ -441,7 +442,8 @@ struct FunctionBreakpoint { bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &, llvm::json::Path); -/// This enumeration defines all possible access types for data breakpoints. Values: ‘read’, ‘write’, ‘readWrite’ +/// This enumeration defines all possible access types for data breakpoints. +/// Values: ‘read’, ‘write’, ‘readWrite’ enum DataBreakpointAccessType : unsigned { eDataBreakpointAccessTypeRead, eDataBreakpointAccessTypeWrite, @@ -479,7 +481,7 @@ struct InstructionBreakpoint { /// The offset from the instruction reference in bytes. /// This can be negative. - std::optional<int64_t> offset; + std::optional<int32_t> offset; /// An expression for conditional breakpoints. /// It is only honored by a debug adapter if the corresponding capability @@ -499,7 +501,8 @@ struct InstructionBreakpoint { bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, llvm::json::Path); -/// An ExceptionFilterOptions is used to specify an exception filter together with a condition for the `setExceptionBreakpoints` request. +/// An ExceptionFilterOptions is used to specify an exception filter together +/// with a condition for the `setExceptionBreakpoints` request. struct ExceptionFilterOptions { /// ID of an exception filter returned by the `exceptionBreakpointFilters` /// capability. @@ -557,8 +560,7 @@ struct ExceptionOptions { /// Condition when a thrown exception should result in a break. ExceptionBreakMode breakMode; }; -bool fromJSON(const llvm::json::Value &, ExceptionOptions &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, ExceptionOptions &, llvm::json::Path); } // namespace lldb_dap::protocol 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); >From b7b2454540a1b6f95c2b142768eaaa59bc6be68b Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 26 Apr 2025 11:23:51 +0200 Subject: [PATCH 4/4] forgor exception breakpoint response --- lldb/tools/lldb-dap/BreakpointBase.h | 2 +- .../lldb-dap/Protocol/ProtocolRequests.h | 110 ++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h index e7aef44cc9d9a..44f3bfa15afc3 100644 --- a/lldb/tools/lldb-dap/BreakpointBase.h +++ b/lldb/tools/lldb-dap/BreakpointBase.h @@ -10,7 +10,7 @@ #define LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H #include "DAPForward.h" -#include "llvm/ADT/StringRef.h" +#include <optional> #include <string> namespace lldb_dap { diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index b1a395ec4ae3d..7bcb8212575f4 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -445,6 +445,34 @@ struct SetExceptionBreakpointsArguments { /// capability `supportsExceptionOptions` is true. std::optional<std::vector<ExceptionOptions>> exceptionOptions; }; +bool fromJSON(const llvm::json::Value &, SetExceptionBreakpointsArguments &, + llvm::json::Path); + +/// Response to `setExceptionBreakpoints` request. +/// The response contains an array of Breakpoint objects with information about +/// each exception breakpoint or filter. The Breakpoint objects are in the same +/// order as the elements of the filters, filterOptions, exceptionOptions arrays +/// given as arguments. If both filters and filterOptions are given, the +/// returned array must start with filters information first, followed by +/// filterOptions information. +/// The verified property of a Breakpoint object signals whether the exception +/// breakpoint or filter could be successfully created and whether the condition +/// is valid. In case of an error the message property explains the problem. The +/// id property can be used to introduce a unique ID for the exception +/// breakpoint or filter so that it can be updated subsequently by sending +/// breakpoint events. For backward compatibility both the breakpoints array and +/// the enclosing body are optional. If these elements are missing a client is +/// not able to show problems for individual exception breakpoints or filters. +struct SetExceptionBreakpointsResponseBody { + /// Information about the exception breakpoints or filters. + /// The breakpoints returned are in the same order as the elements of the + /// `filters`, `filterOptions`, `exceptionOptions` arrays in the arguments. + /// If both `filters` and `filterOptions` are given, the returned array must + /// start with `filters` information first, followed by `filterOptions` + /// information. + std::vector<Breakpoint> breakpoints; +}; +llvm::json::Value toJSON(const SetExceptionBreakpointsResponseBody &); /// Arguments for `setInstructionBreakpoints` request. struct SetInstructionBreakpointsArguments { @@ -462,6 +490,88 @@ struct SetInstructionBreakpointsResponseBody { }; 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<int64_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 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits