https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/148061
>From c9fc191e93381b90b67d72799bab1b9ea19b8c42 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 17 May 2025 23:49:10 +0200 Subject: [PATCH 01/19] [lldb-dap] Support persistent assembly breakpoints --- lldb/tools/lldb-dap/CMakeLists.txt | 3 +- .../Handler/SetBreakpointsRequestHandler.cpp | 1 - lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 39 ++++++++++++++ lldb/tools/lldb-dap/Protocol/DAPTypes.h | 54 +++++++++++++++++++ .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 5 +- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 8 ++- 6 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 lldb/tools/lldb-dap/Protocol/DAPTypes.cpp create mode 100644 lldb/tools/lldb-dap/Protocol/DAPTypes.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 4cddfb1bea1c2..5e0ad53b82f89 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -66,7 +66,8 @@ add_lldb_library(lldbDAP Handler/ThreadsRequestHandler.cpp Handler/VariablesRequestHandler.cpp Handler/WriteMemoryRequestHandler.cpp - + + Protocol/DAPTypes.cpp Protocol/ProtocolBase.cpp Protocol/ProtocolEvents.cpp Protocol/ProtocolTypes.cpp diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp index 5d336af740c99..142351fd62179 100644 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp @@ -9,7 +9,6 @@ #include "DAP.h" #include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include <vector> namespace lldb_dap { diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp new file mode 100644 index 0000000000000..7fc77a5de2202 --- /dev/null +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp @@ -0,0 +1,39 @@ +#include "Protocol/DAPTypes.h" +// #include "llvm/Support/JSON.h" + +using namespace llvm; + +namespace lldb_dap::protocol { + +bool fromJSON(const llvm::json::Value &Params, AssemblyBreakpointData &ABD, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.mapOptional("module", ABD.module) && + O.mapOptional("symbol_mangled_name", ABD.symbol_mangled_name) && + O.mapOptional("offset", ABD.offset); +} + +llvm::json::Value toJSON(const AssemblyBreakpointData &ABD) { + json::Object result{ + {"module", ABD.module}, + {"symbol_mangled_name", ABD.symbol_mangled_name}, + {"offset", ABD.offset}, + }; + + return result; +} + +bool fromJSON(const llvm::json::Value &Params, SourceLLDBData &SLD, + llvm::json::Path P) { + json::ObjectMapper O(Params, P); + return O && O.mapOptional("assembly_breakpoint", SLD.assembly_breakpoint); +} + +llvm::json::Value toJSON(const SourceLLDBData &SLD) { + json::Object result; + if (SLD.assembly_breakpoint) + result.insert({"assembly_breakpoint", SLD.assembly_breakpoint}); + return result; +} + +} // namespace lldb_dap::protocol \ No newline at end of file diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h new file mode 100644 index 0000000000000..ff88deebc84bf --- /dev/null +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -0,0 +1,54 @@ +//===-- ProtocolTypes.h ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains private DAP types used in the protocol. +// +// Each struct has a toJSON and fromJSON function, that converts between +// the struct and a JSON representation. (See JSON.h) +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H +#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_DAP_TYPES_H + +#include "lldb/lldb-types.h" +#include "llvm/Support/JSON.h" +#include <optional> +#include <string> + +namespace lldb_dap::protocol { + +/// Data used to help lldb-dap resolve assembly breakpoints across different +/// sessions. +struct AssemblyBreakpointData { + /// The source module path. + std::string module; + + /// The symbol unique name. + std::string symbol_mangled_name; + + /// The breakpoint offset from the symbol resolved address. + lldb::addr_t offset; +}; +bool fromJSON(const llvm::json::Value &, AssemblyBreakpointData &, + llvm::json::Path); +llvm::json::Value toJSON(const AssemblyBreakpointData &); + +/// Custom source data used by lldb-dap. +/// This data should help lldb-dap identify sources correctly across different +/// sessions. +struct SourceLLDBData { + /// Assembly breakpoint data. + std::optional<AssemblyBreakpointData> assembly_breakpoint; +}; +bool fromJSON(const llvm::json::Value &, SourceLLDBData &, llvm::json::Path); +llvm::json::Value toJSON(const SourceLLDBData &); + +} // namespace lldb_dap::protocol + +#endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp index 785830c693104..78b3d407c82b1 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp @@ -46,7 +46,8 @@ bool fromJSON(const json::Value &Params, Source &S, json::Path P) { json::ObjectMapper O(Params, P); return O && O.map("name", S.name) && O.map("path", S.path) && O.map("presentationHint", S.presentationHint) && - O.map("sourceReference", S.sourceReference); + O.map("sourceReference", S.sourceReference) && + O.map("adapterData", S.adapterData); } llvm::json::Value toJSON(Source::PresentationHint hint) { @@ -71,6 +72,8 @@ llvm::json::Value toJSON(const Source &S) { result.insert({"sourceReference", *S.sourceReference}); if (S.presentationHint) result.insert({"presentationHint", *S.presentationHint}); + if (S.adapterData) + result.insert({"adapterData", *S.adapterData}); return result; } diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h index 89122c8f66307..c4be7911a662b 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 "Protocol/DAPTypes.h" #include "lldb/lldb-defines.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/JSON.h" @@ -336,7 +337,12 @@ struct Source { /// skipped on stepping. std::optional<PresentationHint> presentationHint; - // unsupported keys: origin, sources, adapterData, checksums + /// Additional 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. + std::optional<SourceLLDBData> adapterData; + + // unsupported keys: origin, sources, checksums }; bool fromJSON(const llvm::json::Value &, Source::PresentationHint &, llvm::json::Path); >From f48f313f04ee0877be91cce84a5135caac259fc3 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sat, 31 May 2025 16:51:10 +0200 Subject: [PATCH 02/19] save adapterData for assembly breakpoints --- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 3 ++- lldb/tools/lldb-dap/SourceBreakpoint.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 5fce9fe0ddbb3..580d126fd791a 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -10,6 +10,7 @@ #include "BreakpointBase.h" #include "DAP.h" #include "JSONUtils.h" +#include "ProtocolUtils.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" @@ -44,7 +45,7 @@ llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "Invalid line number."); - if (source.sourceReference) { + if (IsAssemblySource(source)) { // Breakpoint set by assembly source. std::optional<lldb::addr_t> raw_addr = m_dap.GetSourceReferenceAddress(*source.sourceReference); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 857ac4286d59d..0a053b5e4d6a6 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -50,6 +50,9 @@ class SourceBreakpoint : public Breakpoint { uint32_t GetColumn() const { return m_column; } protected: + llvm::Error SetAssemblyBreakpoint(const protocol::Source &source); + llvm::Error SetPathBreakpoint(const protocol::Source &source); + // logMessage part can be either a raw text or an expression. struct LogMessagePart { LogMessagePart(llvm::StringRef text, bool is_expr) >From 06170ea6ee33f786b11388c44c3986fd130937b0 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Mon, 2 Jun 2025 23:17:14 +0200 Subject: [PATCH 03/19] remove offset --- lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 20 +++--- lldb/tools/lldb-dap/Protocol/DAPTypes.h | 19 +++-- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 86 ++++++++++++++--------- lldb/tools/lldb-dap/SourceBreakpoint.h | 6 +- 4 files changed, 75 insertions(+), 56 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp index 7fc77a5de2202..994cef02cb63f 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp @@ -5,19 +5,17 @@ using namespace llvm; namespace lldb_dap::protocol { -bool fromJSON(const llvm::json::Value &Params, AssemblyBreakpointData &ABD, +bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD, llvm::json::Path P) { json::ObjectMapper O(Params, P); - return O && O.mapOptional("module", ABD.module) && - O.mapOptional("symbol_mangled_name", ABD.symbol_mangled_name) && - O.mapOptional("offset", ABD.offset); + return O && O.mapOptional("module", PD.module) && + O.mapOptional("symbol_mangled_name", PD.symbol_mangled_name); } -llvm::json::Value toJSON(const AssemblyBreakpointData &ABD) { +llvm::json::Value toJSON(const PersistenceData &PD) { json::Object result{ - {"module", ABD.module}, - {"symbol_mangled_name", ABD.symbol_mangled_name}, - {"offset", ABD.offset}, + {"module", PD.module}, + {"symbol_mangled_name", PD.symbol_mangled_name}, }; return result; @@ -26,13 +24,13 @@ llvm::json::Value toJSON(const AssemblyBreakpointData &ABD) { bool fromJSON(const llvm::json::Value &Params, SourceLLDBData &SLD, llvm::json::Path P) { json::ObjectMapper O(Params, P); - return O && O.mapOptional("assembly_breakpoint", SLD.assembly_breakpoint); + return O && O.mapOptional("persistence_data", SLD.persistence_data); } llvm::json::Value toJSON(const SourceLLDBData &SLD) { json::Object result; - if (SLD.assembly_breakpoint) - result.insert({"assembly_breakpoint", SLD.assembly_breakpoint}); + if (SLD.persistence_data) + result.insert({"persistence_data", SLD.persistence_data}); return result; } diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h index ff88deebc84bf..d853bd06e48ad 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -23,28 +23,27 @@ namespace lldb_dap::protocol { -/// Data used to help lldb-dap resolve assembly breakpoints across different -/// sessions. -struct AssemblyBreakpointData { +/// Data used to help lldb-dap resolve breakpoints persistently across different sessions. +/// This information is especially useful for assembly breakpoints, because `sourceReference` +/// can change across sessions. For regular source breakpoints the path and line are the same +/// For each session. +struct PersistenceData { /// The source module path. std::string module; /// The symbol unique name. std::string symbol_mangled_name; - - /// The breakpoint offset from the symbol resolved address. - lldb::addr_t offset; }; -bool fromJSON(const llvm::json::Value &, AssemblyBreakpointData &, +bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path); -llvm::json::Value toJSON(const AssemblyBreakpointData &); +llvm::json::Value toJSON(const PersistenceData &); /// Custom source data used by lldb-dap. /// This data should help lldb-dap identify sources correctly across different /// sessions. struct SourceLLDBData { - /// Assembly breakpoint data. - std::optional<AssemblyBreakpointData> assembly_breakpoint; + /// Data that helps lldb resolve this source persistently across different sessions. + std::optional<PersistenceData> persistence_data; }; bool fromJSON(const llvm::json::Value &, SourceLLDBData &, llvm::json::Path); llvm::json::Value toJSON(const SourceLLDBData &); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 580d126fd791a..a9129cfe02f19 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -47,41 +47,17 @@ llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { if (IsAssemblySource(source)) { // Breakpoint set by assembly source. - std::optional<lldb::addr_t> raw_addr = - m_dap.GetSourceReferenceAddress(*source.sourceReference); - if (!raw_addr) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid sourceReference."); - - lldb::SBAddress source_address(*raw_addr, m_dap.target); - if (!source_address.IsValid()) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid sourceReference."); - - lldb::SBSymbol symbol = source_address.GetSymbol(); - if (!symbol.IsValid()) { - // FIXME: Support assembly breakpoints without a valid symbol. - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Breakpoints in assembly without a valid " - "symbol are not supported yet."); + if (source.adapterData && source.adapterData->persistence_data) { + // Prefer use the adapter persitence data, because this could be a breakpoint + // from a previous session where the `sourceReference` is not valid anymore. + if (llvm::Error error = CreateAssemblyBreakpointWithPersistenceData(*source.adapterData->persistence_data)) + return error; + } else { + if (llvm::Error error = CreateAssemblyBreakpointWithSourceReference(*source.sourceReference)) + return error; } - - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid instruction list size."); - - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); - - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); } else { - // Breakpoint set by a regular source file. - const auto source_path = source.path.value_or(""); - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, - m_column, 0, module_list); + CreatePathBreakpoint(source); } if (!m_log_message.empty()) @@ -98,6 +74,50 @@ void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { BreakpointBase::UpdateBreakpoint(request_bp); } +void SourceBreakpoint::CreatePathBreakpoint(const protocol::Source &source) { + const auto source_path = source.path.value_or(""); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); +} + +llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference(int64_t source_reference) { + std::optional<lldb::addr_t> raw_addr = + m_dap.GetSourceReferenceAddress(source_reference); + if (!raw_addr) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid sourceReference."); + + lldb::SBAddress source_address(*raw_addr, m_dap.target); + if (!source_address.IsValid()) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid sourceReference."); + + lldb::SBSymbol symbol = source_address.GetSymbol(); + if (!symbol.IsValid()) { + // FIXME: Support assembly breakpoints without a valid symbol. + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Breakpoints in assembly without a valid " + "symbol are not supported yet."); + } + + lldb::SBInstructionList inst_list = + m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); + if (inst_list.GetSize() < m_line) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Invalid instruction list size."); + + lldb::SBAddress address = + inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); + + m_bp = m_dap.target.BreakpointCreateBySBAddress(address); + return llvm::Error::success(); +} + +llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data) { + return llvm::Error::success(); +} + lldb::SBError SourceBreakpoint::AppendLogMessagePart(llvm::StringRef part, bool is_expr) { if (is_expr) { diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index 0a053b5e4d6a6..b9086a0c8fbb7 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/DAPTypes.h" #include "Protocol/ProtocolTypes.h" #include "lldb/API/SBError.h" #include "llvm/ADT/StringRef.h" @@ -50,8 +51,9 @@ class SourceBreakpoint : public Breakpoint { uint32_t GetColumn() const { return m_column; } protected: - llvm::Error SetAssemblyBreakpoint(const protocol::Source &source); - llvm::Error SetPathBreakpoint(const protocol::Source &source); + void CreatePathBreakpoint(const protocol::Source &source); + llvm::Error CreateAssemblyBreakpointWithSourceReference(int64_t source_reference); + llvm::Error CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data); // logMessage part can be either a raw text or an expression. struct LogMessagePart { >From 26b7000e0ffe3ee82fab1a586dbe70e941947474 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 00:36:22 +0200 Subject: [PATCH 04/19] create persistent breakpoints --- lldb/include/lldb/API/SBTarget.h | 3 +++ lldb/include/lldb/Target/Target.h | 2 +- lldb/source/API/SBTarget.cpp | 14 ++++++++++++++ lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 4 ++-- lldb/tools/lldb-dap/Protocol/DAPTypes.h | 4 ++-- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 3 +++ 6 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 2776a8f9010fe..af64fc06a3b4a 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -737,6 +737,9 @@ class LLDB_API SBTarget { lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); + lldb::SBBreakpoint BreakpointCreateByFileAddress(const SBFileSpec &file_spec, + addr_t file_addr); + /// Create a breakpoint using a scripted resolver. /// /// \param[in] class_name diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 0d4e11b65339e..8716a9f81b734 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -723,7 +723,7 @@ class Target : public std::enable_shared_from_this<Target>, lldb::BreakpointSP CreateBreakpoint(lldb::addr_t load_addr, bool internal, bool request_hardware); - // Use this to create a breakpoint from a load address and a module file spec + // Use this to create a breakpoint from a file address and a module file spec lldb::BreakpointSP CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, const FileSpec &file_spec, diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index f26f7951edc6f..f21e0fb0f986e 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -66,6 +66,7 @@ #include "Commands/CommandObjectBreakpoint.h" #include "lldb/Interpreter/CommandReturnObject.h" +#include "lldb/lldb-types.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" @@ -949,6 +950,19 @@ SBBreakpoint SBTarget::BreakpointCreateBySBAddress(SBAddress &sb_address) { return sb_bp; } +SBBreakpoint SBTarget::BreakpointCreateByFileAddress(const SBFileSpec &file_spec, addr_t file_addr) { + LLDB_INSTRUMENT_VA(this, file_spec, file_addr); + + SBBreakpoint sb_bp; + if (TargetSP target_sp = GetSP()) { + std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex()); + const bool hardware = false; + sb_bp = target_sp->CreateAddressInModuleBreakpoint(file_addr, false, *file_spec.get(), hardware); + } + + return sb_bp; +} + lldb::SBBreakpoint SBTarget::BreakpointCreateBySourceRegex(const char *source_regex, const lldb::SBFileSpec &source_file, diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp index 994cef02cb63f..e45a4f30d9bcf 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp @@ -9,13 +9,13 @@ bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD, llvm::json::Path P) { json::ObjectMapper O(Params, P); return O && O.mapOptional("module", PD.module) && - O.mapOptional("symbol_mangled_name", PD.symbol_mangled_name); + O.mapOptional("file_addr", PD.file_addr); } llvm::json::Value toJSON(const PersistenceData &PD) { json::Object result{ {"module", PD.module}, - {"symbol_mangled_name", PD.symbol_mangled_name}, + {"file_addr", PD.file_addr}, }; return result; diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h index d853bd06e48ad..f87a9f3984711 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -31,8 +31,8 @@ struct PersistenceData { /// The source module path. std::string module; - /// The symbol unique name. - std::string symbol_mangled_name; + /// The file address inside the module. + lldb::addr_t file_addr; }; bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index a9129cfe02f19..683e3c3eb1ff1 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -12,6 +12,7 @@ #include "JSONUtils.h" #include "ProtocolUtils.h" #include "lldb/API/SBBreakpoint.h" +#include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBInstruction.h" @@ -115,6 +116,8 @@ llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference(int64_ } llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data) { + lldb::SBFileSpec file_spec(persistence_data.module.c_str()); + m_bp = m_dap.target.BreakpointCreateByFileAddress(file_spec, persistence_data.file_addr); return llvm::Error::success(); } >From 5ea62b2c72fb4824be15efea7b4d9c2437913128 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 16:34:53 +0200 Subject: [PATCH 05/19] add instructions_offset to breakppoint resolver --- lldb/include/lldb/API/SBTarget.h | 3 +- .../lldb/Breakpoint/BreakpointResolver.h | 6 +++- .../Breakpoint/BreakpointResolverAddress.h | 6 ++++ lldb/include/lldb/Core/Disassembler.h | 2 ++ lldb/include/lldb/Target/Target.h | 9 ++++- lldb/source/API/SBTarget.cpp | 29 +++------------ lldb/source/Breakpoint/BreakpointResolver.cpp | 14 ++++++-- .../Breakpoint/BreakpointResolverAddress.cpp | 6 ++++ lldb/source/Core/Disassembler.cpp | 10 ++++++ lldb/source/Target/Target.cpp | 36 +++++++++++++++++-- lldb/tools/lldb-dap/Protocol/DAPTypes.h | 2 +- 11 files changed, 89 insertions(+), 34 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index af64fc06a3b4a..06c1dc2ca08ca 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -23,6 +23,7 @@ #include "lldb/API/SBValue.h" #include "lldb/API/SBWatchpoint.h" #include "lldb/API/SBWatchpointOptions.h" +#include "lldb/lldb-types.h" namespace lldb_private { namespace python { @@ -738,7 +739,7 @@ class LLDB_API SBTarget { lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); lldb::SBBreakpoint BreakpointCreateByFileAddress(const SBFileSpec &file_spec, - addr_t file_addr); + addr_t file_addr, addr_t offset = 0, addr_t instructions_offset = 0); /// Create a breakpoint using a scripted resolver. /// diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/lldb/include/lldb/Breakpoint/BreakpointResolver.h index 52cd70e934e6d..c83f4d249e6d1 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolver.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolver.h @@ -16,6 +16,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/RegularExpression.h" #include "lldb/lldb-private.h" +#include "lldb/lldb-types.h" #include <optional> namespace lldb_private { @@ -47,7 +48,8 @@ class BreakpointResolver : public Searcher { /// The concrete breakpoint resolver type for this breakpoint. BreakpointResolver(const lldb::BreakpointSP &bkpt, unsigned char resolverType, - lldb::addr_t offset = 0); + lldb::addr_t offset = 0, + lldb::addr_t instructions_offset = 0); /// The Destructor is virtual, all significant breakpoint resolvers derive /// from this class. @@ -182,6 +184,7 @@ class BreakpointResolver : public Searcher { SearchDepth, SkipPrologue, SymbolNameArray, + InstructionsOffset, LastOptionName }; static const char @@ -220,6 +223,7 @@ class BreakpointResolver : public Searcher { lldb::BreakpointWP m_breakpoint; // This is the breakpoint we add locations to. lldb::addr_t m_offset; // A random offset the user asked us to add to any // breakpoints we set. + lldb::addr_t m_instructions_offset; // Number of instructions to add to the resolved breakpoint address. // Subclass identifier (for llvm isa/dyn_cast) const unsigned char SubclassID; diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h index 3a09892f3f194..bc6f057e366cb 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h @@ -28,6 +28,12 @@ class BreakpointResolverAddress : public BreakpointResolver { const Address &addr, const FileSpec &module_spec); + BreakpointResolverAddress(const lldb::BreakpointSP &bkpt, + const Address &addr, + const FileSpec &module_spec, + lldb::addr_t offset, + lldb::addr_t instructions_offset); + ~BreakpointResolverAddress() override = default; static lldb::BreakpointResolverSP diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h index 21bacb14f9b25..50a5d87835844 100644 --- a/lldb/include/lldb/Core/Disassembler.h +++ b/lldb/include/lldb/Core/Disassembler.h @@ -291,6 +291,8 @@ class InstructionList { size_t GetSize() const; + size_t GetTotalByteSize() const; + uint32_t GetMaxOpcocdeByteSize() const; lldb::InstructionSP GetInstructionAtIndex(size_t idx) const; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 8716a9f81b734..80c4898e957cf 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -18,6 +18,7 @@ #include "lldb/Breakpoint/BreakpointList.h" #include "lldb/Breakpoint/BreakpointName.h" #include "lldb/Breakpoint/WatchpointList.h" +#include "lldb/Core/Address.h" #include "lldb/Core/Architecture.h" #include "lldb/Core/Disassembler.h" #include "lldb/Core/ModuleList.h" @@ -727,7 +728,9 @@ class Target : public std::enable_shared_from_this<Target>, lldb::BreakpointSP CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, const FileSpec &file_spec, - bool request_hardware); + bool request_hardware, + lldb::addr_t offset = 0, + lldb::addr_t instructions_offset = 0); // Use this to create Address breakpoints: lldb::BreakpointSP CreateBreakpoint(const Address &addr, bool internal, @@ -1328,6 +1331,10 @@ class Target : public std::enable_shared_from_this<Target>, const lldb_private::RegisterFlags &flags, uint32_t byte_size); + lldb::DisassemblerSP ReadInstructions(const Address &start_addr, + uint32_t count, + const char *flavor_string = nullptr); + // Target Stop Hooks class StopHook : public UserID { public: diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index f21e0fb0f986e..116f527d9068c 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -950,14 +950,14 @@ SBBreakpoint SBTarget::BreakpointCreateBySBAddress(SBAddress &sb_address) { return sb_bp; } -SBBreakpoint SBTarget::BreakpointCreateByFileAddress(const SBFileSpec &file_spec, addr_t file_addr) { +SBBreakpoint SBTarget::BreakpointCreateByFileAddress(const SBFileSpec &file_spec, addr_t file_addr, addr_t offset, addr_t instructions_offset) { LLDB_INSTRUMENT_VA(this, file_spec, file_addr); SBBreakpoint sb_bp; if (TargetSP target_sp = GetSP()) { std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex()); const bool hardware = false; - sb_bp = target_sp->CreateAddressInModuleBreakpoint(file_addr, false, *file_spec.get(), hardware); + sb_bp = target_sp->CreateAddressInModuleBreakpoint(file_addr, false, *file_spec.get(), hardware, offset, instructions_offset); } return sb_bp; @@ -1969,29 +1969,8 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr, if (TargetSP target_sp = GetSP()) { if (Address *addr_ptr = base_addr.get()) { - DataBufferHeap data( - target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0); - bool force_live_memory = true; - lldb_private::Status error; - lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - const size_t bytes_read = - target_sp->ReadMemory(*addr_ptr, data.GetBytes(), data.GetByteSize(), - error, force_live_memory, &load_addr); - - const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; - if (!flavor_string || flavor_string[0] == '\0') { - // FIXME - we don't have the mechanism in place to do per-architecture - // settings. But since we know that for now we only support flavors on - // x86 & x86_64, - const llvm::Triple::ArchType arch = - target_sp->GetArchitecture().GetTriple().getArch(); - if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64) - flavor_string = target_sp->GetDisassemblyFlavor(); - } - sb_instructions.SetDisassembler(Disassembler::DisassembleBytes( - target_sp->GetArchitecture(), nullptr, flavor_string, - target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(), - *addr_ptr, data.GetBytes(), bytes_read, count, data_from_file)); + sb_instructions.SetDisassembler(target_sp->ReadInstructions( + *addr_ptr, count, flavor_string)); } } diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp index 91fdff4a455da..a5cd9372527ac 100644 --- a/lldb/source/Breakpoint/BreakpointResolver.cpp +++ b/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -29,6 +29,7 @@ #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" +#include "lldb/lldb-forward.h" #include <optional> using namespace lldb_private; @@ -45,7 +46,7 @@ const char *BreakpointResolver::g_option_names[static_cast<uint32_t>( "AddressOffset", "Exact", "FileName", "Inlines", "Language", "LineNumber", "Column", "ModuleName", "NameMask", "Offset", "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth", - "SkipPrologue", "SymbolNames"}; + "SkipPrologue", "SymbolNames", "InstructionsOffset"}; const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) { if (type > LastKnownResolverType) @@ -65,8 +66,9 @@ BreakpointResolver::NameToResolverTy(llvm::StringRef name) { BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt, const unsigned char resolverTy, - lldb::addr_t offset) - : m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {} + lldb::addr_t offset, + lldb::addr_t instructions_offset) + : m_breakpoint(bkpt), m_offset(offset), m_instructions_offset(instructions_offset), SubclassID(resolverTy) {} BreakpointResolver::~BreakpointResolver() = default; @@ -364,6 +366,12 @@ void BreakpointResolver::AddLocation(SearchFilter &filter, BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr, bool *new_location) { + if (m_instructions_offset != 0) { + Target &target = GetBreakpoint()->GetTarget(); + const DisassemblerSP instructions = target.ReadInstructions(loc_addr, m_instructions_offset); + loc_addr.Slide(instructions->GetInstructionList().GetTotalByteSize()); + } + loc_addr.Slide(m_offset); return GetBreakpoint()->AddLocation(loc_addr, new_location); } diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index 828647ceef637..5298cbc76dc1f 100644 --- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -30,6 +30,12 @@ BreakpointResolverAddress::BreakpointResolverAddress(const BreakpointSP &bkpt, : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver), m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS) {} +BreakpointResolverAddress::BreakpointResolverAddress( + const BreakpointSP &bkpt, const Address &addr, const FileSpec &module_spec, lldb::addr_t offset, lldb::addr_t instructions_offset) + : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver, offset, instructions_offset), + m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), + m_module_filespec(module_spec) {} + BreakpointResolverSP BreakpointResolverAddress::CreateFromStructuredData( const StructuredData::Dictionary &options_dict, Status &error) { llvm::StringRef module_name; diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp index 833e327579a29..90394cc9a5569 100644 --- a/lldb/source/Core/Disassembler.cpp +++ b/lldb/source/Core/Disassembler.cpp @@ -1014,6 +1014,16 @@ uint32_t InstructionList::GetMaxOpcocdeByteSize() const { return max_inst_size; } +size_t InstructionList::GetTotalByteSize() const { + size_t total_byte_size = 0; + collection::const_iterator pos, end; + for (pos = m_instructions.begin(), end = m_instructions.end(); pos != end; + ++pos) { + total_byte_size += (*pos)->GetOpcode().GetByteSize(); + } + return total_byte_size; +} + InstructionSP InstructionList::GetInstructionAtIndex(size_t idx) const { InstructionSP inst_sp; if (idx < m_instructions.size()) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 7f569173eba20..82f07829b05b3 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -65,6 +65,7 @@ #include "lldb/Utility/State.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/Timer.h" +#include "lldb/lldb-forward.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SetVector.h" @@ -567,11 +568,13 @@ BreakpointSP Target::CreateBreakpoint(const Address &addr, bool internal, lldb::BreakpointSP Target::CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, const FileSpec &file_spec, - bool request_hardware) { + bool request_hardware, + lldb::addr_t offset, + lldb::addr_t instructions_offset) { SearchFilterSP filter_sp( new SearchFilterForUnconstrainedSearches(shared_from_this())); BreakpointResolverSP resolver_sp(new BreakpointResolverAddress( - nullptr, file_addr, file_spec)); + nullptr, file_addr, file_spec, offset, instructions_offset)); return CreateBreakpoint(filter_sp, resolver_sp, internal, request_hardware, false); } @@ -2990,6 +2993,35 @@ lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { return arch_plugin ? arch_plugin->GetBreakableLoadAddress(addr, *this) : addr; } +lldb::DisassemblerSP Target::ReadInstructions(const Address &start_addr, uint32_t count, + const char *flavor_string) { + if (!m_process_sp) + return lldb::DisassemblerSP(); + + DataBufferHeap data(GetArchitecture().GetMaximumOpcodeByteSize() * count, 0); + bool force_live_memory = true; + lldb_private::Status error; + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; + const size_t bytes_read = ReadMemory(start_addr, data.GetBytes(), data.GetByteSize(), + error, force_live_memory, &load_addr); + + const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; + if (!flavor_string || flavor_string[0] == '\0') { + // FIXME - we don't have the mechanism in place to do per-architecture + // settings. But since we know that for now we only support flavors on + // x86 & x86_64, + const llvm::Triple::ArchType arch = + GetArchitecture().GetTriple().getArch(); + if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64) + flavor_string = GetDisassemblyFlavor(); + } + + return Disassembler::DisassembleBytes( + GetArchitecture(), nullptr, flavor_string, + GetDisassemblyCPU(), GetDisassemblyFeatures(), + start_addr, data.GetBytes(), bytes_read, count, data_from_file); +} + SourceManager &Target::GetSourceManager() { if (!m_source_manager_up) m_source_manager_up = std::make_unique<SourceManager>(shared_from_this()); diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h index f87a9f3984711..7f49a40853294 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -31,7 +31,7 @@ struct PersistenceData { /// The source module path. std::string module; - /// The file address inside the module. + /// The file address of the function. lldb::addr_t file_addr; }; bool fromJSON(const llvm::json::Value &, PersistenceData &, >From 189c308f229153320cda6886c407cb0f0ffb3838 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 16:35:40 +0200 Subject: [PATCH 06/19] format --- lldb/include/lldb/API/SBTarget.h | 6 ++-- .../lldb/Breakpoint/BreakpointResolver.h | 6 ++-- .../Breakpoint/BreakpointResolverAddress.h | 6 ++-- lldb/include/lldb/Target/Target.h | 10 +++---- lldb/source/API/SBTarget.cpp | 13 ++++++--- lldb/source/Breakpoint/BreakpointResolver.cpp | 14 +++++---- .../Breakpoint/BreakpointResolverAddress.cpp | 6 ++-- lldb/source/Target/Target.cpp | 29 +++++++++---------- 8 files changed, 49 insertions(+), 41 deletions(-) diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index 06c1dc2ca08ca..a135e3ce4db58 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -738,8 +738,10 @@ class LLDB_API SBTarget { lldb::SBBreakpoint BreakpointCreateBySBAddress(SBAddress &address); - lldb::SBBreakpoint BreakpointCreateByFileAddress(const SBFileSpec &file_spec, - addr_t file_addr, addr_t offset = 0, addr_t instructions_offset = 0); + lldb::SBBreakpoint + BreakpointCreateByFileAddress(const SBFileSpec &file_spec, addr_t file_addr, + addr_t offset = 0, + addr_t instructions_offset = 0); /// Create a breakpoint using a scripted resolver. /// diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolver.h b/lldb/include/lldb/Breakpoint/BreakpointResolver.h index c83f4d249e6d1..adb577e2600b9 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolver.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolver.h @@ -46,8 +46,7 @@ class BreakpointResolver : public Searcher { /// The breakpoint that owns this resolver. /// \param[in] resolverType /// The concrete breakpoint resolver type for this breakpoint. - BreakpointResolver(const lldb::BreakpointSP &bkpt, - unsigned char resolverType, + BreakpointResolver(const lldb::BreakpointSP &bkpt, unsigned char resolverType, lldb::addr_t offset = 0, lldb::addr_t instructions_offset = 0); @@ -223,7 +222,8 @@ class BreakpointResolver : public Searcher { lldb::BreakpointWP m_breakpoint; // This is the breakpoint we add locations to. lldb::addr_t m_offset; // A random offset the user asked us to add to any // breakpoints we set. - lldb::addr_t m_instructions_offset; // Number of instructions to add to the resolved breakpoint address. + lldb::addr_t m_instructions_offset; // Number of instructions to add to the + // resolved breakpoint address. // Subclass identifier (for llvm isa/dyn_cast) const unsigned char SubclassID; diff --git a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h index bc6f057e366cb..01318bbfe0d4a 100644 --- a/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h +++ b/lldb/include/lldb/Breakpoint/BreakpointResolverAddress.h @@ -28,10 +28,8 @@ class BreakpointResolverAddress : public BreakpointResolver { const Address &addr, const FileSpec &module_spec); - BreakpointResolverAddress(const lldb::BreakpointSP &bkpt, - const Address &addr, - const FileSpec &module_spec, - lldb::addr_t offset, + BreakpointResolverAddress(const lldb::BreakpointSP &bkpt, const Address &addr, + const FileSpec &module_spec, lldb::addr_t offset, lldb::addr_t instructions_offset); ~BreakpointResolverAddress() override = default; diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 80c4898e957cf..5730f7b369cd6 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -725,12 +725,10 @@ class Target : public std::enable_shared_from_this<Target>, bool request_hardware); // Use this to create a breakpoint from a file address and a module file spec - lldb::BreakpointSP CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, - bool internal, - const FileSpec &file_spec, - bool request_hardware, - lldb::addr_t offset = 0, - lldb::addr_t instructions_offset = 0); + lldb::BreakpointSP CreateAddressInModuleBreakpoint( + lldb::addr_t file_addr, bool internal, const FileSpec &file_spec, + bool request_hardware, lldb::addr_t offset = 0, + lldb::addr_t instructions_offset = 0); // Use this to create Address breakpoints: lldb::BreakpointSP CreateBreakpoint(const Address &addr, bool internal, diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index 116f527d9068c..ce502e453dcd9 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -950,14 +950,19 @@ SBBreakpoint SBTarget::BreakpointCreateBySBAddress(SBAddress &sb_address) { return sb_bp; } -SBBreakpoint SBTarget::BreakpointCreateByFileAddress(const SBFileSpec &file_spec, addr_t file_addr, addr_t offset, addr_t instructions_offset) { +SBBreakpoint +SBTarget::BreakpointCreateByFileAddress(const SBFileSpec &file_spec, + addr_t file_addr, addr_t offset, + addr_t instructions_offset) { LLDB_INSTRUMENT_VA(this, file_spec, file_addr); SBBreakpoint sb_bp; if (TargetSP target_sp = GetSP()) { std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex()); const bool hardware = false; - sb_bp = target_sp->CreateAddressInModuleBreakpoint(file_addr, false, *file_spec.get(), hardware, offset, instructions_offset); + sb_bp = target_sp->CreateAddressInModuleBreakpoint( + file_addr, false, *file_spec.get(), hardware, offset, + instructions_offset); } return sb_bp; @@ -1969,8 +1974,8 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr, if (TargetSP target_sp = GetSP()) { if (Address *addr_ptr = base_addr.get()) { - sb_instructions.SetDisassembler(target_sp->ReadInstructions( - *addr_ptr, count, flavor_string)); + sb_instructions.SetDisassembler( + target_sp->ReadInstructions(*addr_ptr, count, flavor_string)); } } diff --git a/lldb/source/Breakpoint/BreakpointResolver.cpp b/lldb/source/Breakpoint/BreakpointResolver.cpp index a5cd9372527ac..0bca1337e3cff 100644 --- a/lldb/source/Breakpoint/BreakpointResolver.cpp +++ b/lldb/source/Breakpoint/BreakpointResolver.cpp @@ -43,9 +43,11 @@ const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address", const char *BreakpointResolver::g_option_names[static_cast<uint32_t>( BreakpointResolver::OptionNames::LastOptionName)] = { - "AddressOffset", "Exact", "FileName", "Inlines", "Language", - "LineNumber", "Column", "ModuleName", "NameMask", "Offset", - "PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth", + "AddressOffset", "Exact", "FileName", + "Inlines", "Language", "LineNumber", + "Column", "ModuleName", "NameMask", + "Offset", "PythonClass", "Regex", + "ScriptArgs", "SectionName", "SearchDepth", "SkipPrologue", "SymbolNames", "InstructionsOffset"}; const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) { @@ -68,7 +70,8 @@ BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt, const unsigned char resolverTy, lldb::addr_t offset, lldb::addr_t instructions_offset) - : m_breakpoint(bkpt), m_offset(offset), m_instructions_offset(instructions_offset), SubclassID(resolverTy) {} + : m_breakpoint(bkpt), m_offset(offset), + m_instructions_offset(instructions_offset), SubclassID(resolverTy) {} BreakpointResolver::~BreakpointResolver() = default; @@ -368,7 +371,8 @@ BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr, bool *new_location) { if (m_instructions_offset != 0) { Target &target = GetBreakpoint()->GetTarget(); - const DisassemblerSP instructions = target.ReadInstructions(loc_addr, m_instructions_offset); + const DisassemblerSP instructions = + target.ReadInstructions(loc_addr, m_instructions_offset); loc_addr.Slide(instructions->GetInstructionList().GetTotalByteSize()); } diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index 5298cbc76dc1f..a0343e3957c2e 100644 --- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -31,8 +31,10 @@ BreakpointResolverAddress::BreakpointResolverAddress(const BreakpointSP &bkpt, m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS) {} BreakpointResolverAddress::BreakpointResolverAddress( - const BreakpointSP &bkpt, const Address &addr, const FileSpec &module_spec, lldb::addr_t offset, lldb::addr_t instructions_offset) - : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver, offset, instructions_offset), + const BreakpointSP &bkpt, const Address &addr, const FileSpec &module_spec, + lldb::addr_t offset, lldb::addr_t instructions_offset) + : BreakpointResolver(bkpt, BreakpointResolver::AddressResolver, offset, + instructions_offset), m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), m_module_filespec(module_spec) {} diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 82f07829b05b3..bb276c0a81795 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -565,12 +565,10 @@ BreakpointSP Target::CreateBreakpoint(const Address &addr, bool internal, return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, false); } -lldb::BreakpointSP -Target::CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, - const FileSpec &file_spec, - bool request_hardware, - lldb::addr_t offset, - lldb::addr_t instructions_offset) { +lldb::BreakpointSP Target::CreateAddressInModuleBreakpoint( + lldb::addr_t file_addr, bool internal, const FileSpec &file_spec, + bool request_hardware, lldb::addr_t offset, + lldb::addr_t instructions_offset) { SearchFilterSP filter_sp( new SearchFilterForUnconstrainedSearches(shared_from_this())); BreakpointResolverSP resolver_sp(new BreakpointResolverAddress( @@ -2993,8 +2991,9 @@ lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { return arch_plugin ? arch_plugin->GetBreakableLoadAddress(addr, *this) : addr; } -lldb::DisassemblerSP Target::ReadInstructions(const Address &start_addr, uint32_t count, - const char *flavor_string) { +lldb::DisassemblerSP Target::ReadInstructions(const Address &start_addr, + uint32_t count, + const char *flavor_string) { if (!m_process_sp) return lldb::DisassemblerSP(); @@ -3002,24 +3001,24 @@ lldb::DisassemblerSP Target::ReadInstructions(const Address &start_addr, uint32_ bool force_live_memory = true; lldb_private::Status error; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; - const size_t bytes_read = ReadMemory(start_addr, data.GetBytes(), data.GetByteSize(), - error, force_live_memory, &load_addr); + const size_t bytes_read = + ReadMemory(start_addr, data.GetBytes(), data.GetByteSize(), error, + force_live_memory, &load_addr); const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS; if (!flavor_string || flavor_string[0] == '\0') { // FIXME - we don't have the mechanism in place to do per-architecture // settings. But since we know that for now we only support flavors on // x86 & x86_64, - const llvm::Triple::ArchType arch = - GetArchitecture().GetTriple().getArch(); + const llvm::Triple::ArchType arch = GetArchitecture().GetTriple().getArch(); if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64) flavor_string = GetDisassemblyFlavor(); } return Disassembler::DisassembleBytes( - GetArchitecture(), nullptr, flavor_string, - GetDisassemblyCPU(), GetDisassemblyFeatures(), - start_addr, data.GetBytes(), bytes_read, count, data_from_file); + GetArchitecture(), nullptr, flavor_string, GetDisassemblyCPU(), + GetDisassemblyFeatures(), start_addr, data.GetBytes(), bytes_read, count, + data_from_file); } SourceManager &Target::GetSourceManager() { >From 543bc2af15e665fe0be31f2972f9db339ee8733d Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 16:42:47 +0200 Subject: [PATCH 07/19] instruction offset --- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 683e3c3eb1ff1..95c54fb18a29e 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -117,7 +117,8 @@ llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference(int64_ llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data) { lldb::SBFileSpec file_spec(persistence_data.module.c_str()); - m_bp = m_dap.target.BreakpointCreateByFileAddress(file_spec, persistence_data.file_addr); + m_bp = m_dap.target.BreakpointCreateByFileAddress( + file_spec, persistence_data.file_addr, 0, m_line - 1); return llvm::Error::success(); } >From 19127b99a42de3e010c601da77f26945f9309f94 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 16:43:14 +0200 Subject: [PATCH 08/19] format --- lldb/tools/lldb-dap/Protocol/DAPTypes.h | 14 +++++----- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 33 ++++++++++++++---------- lldb/tools/lldb-dap/SourceBreakpoint.h | 6 +++-- 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h index 7f49a40853294..f112b5af772e3 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -23,10 +23,10 @@ namespace lldb_dap::protocol { -/// Data used to help lldb-dap resolve breakpoints persistently across different sessions. -/// This information is especially useful for assembly breakpoints, because `sourceReference` -/// can change across sessions. For regular source breakpoints the path and line are the same -/// For each session. +/// Data used to help lldb-dap resolve breakpoints persistently across different +/// sessions. This information is especially useful for assembly breakpoints, +/// because `sourceReference` can change across sessions. For regular source +/// breakpoints the path and line are the same For each session. struct PersistenceData { /// The source module path. std::string module; @@ -34,15 +34,15 @@ struct PersistenceData { /// The file address of the function. lldb::addr_t file_addr; }; -bool fromJSON(const llvm::json::Value &, PersistenceData &, - llvm::json::Path); +bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path); llvm::json::Value toJSON(const PersistenceData &); /// Custom source data used by lldb-dap. /// This data should help lldb-dap identify sources correctly across different /// sessions. struct SourceLLDBData { - /// Data that helps lldb resolve this source persistently across different sessions. + /// Data that helps lldb resolve this source persistently across different + /// sessions. std::optional<PersistenceData> persistence_data; }; bool fromJSON(const llvm::json::Value &, SourceLLDBData &, llvm::json::Path); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 95c54fb18a29e..5d87409b45a96 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -49,12 +49,15 @@ llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { if (IsAssemblySource(source)) { // Breakpoint set by assembly source. if (source.adapterData && source.adapterData->persistence_data) { - // Prefer use the adapter persitence data, because this could be a breakpoint - // from a previous session where the `sourceReference` is not valid anymore. - if (llvm::Error error = CreateAssemblyBreakpointWithPersistenceData(*source.adapterData->persistence_data)) + // Prefer use the adapter persitence data, because this could be a + // breakpoint from a previous session where the `sourceReference` is not + // valid anymore. + if (llvm::Error error = CreateAssemblyBreakpointWithPersistenceData( + *source.adapterData->persistence_data)) return error; } else { - if (llvm::Error error = CreateAssemblyBreakpointWithSourceReference(*source.sourceReference)) + if (llvm::Error error = CreateAssemblyBreakpointWithSourceReference( + *source.sourceReference)) return error; } } else { @@ -77,36 +80,37 @@ void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { void SourceBreakpoint::CreatePathBreakpoint(const protocol::Source &source) { const auto source_path = source.path.value_or(""); - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, - m_column, 0, module_list); + lldb::SBFileSpecList module_list; + m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, + m_column, 0, module_list); } -llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference(int64_t source_reference) { +llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference( + int64_t source_reference) { std::optional<lldb::addr_t> raw_addr = m_dap.GetSourceReferenceAddress(source_reference); if (!raw_addr) return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid sourceReference."); + "Invalid sourceReference."); lldb::SBAddress source_address(*raw_addr, m_dap.target); if (!source_address.IsValid()) return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid sourceReference."); + "Invalid sourceReference."); lldb::SBSymbol symbol = source_address.GetSymbol(); if (!symbol.IsValid()) { // FIXME: Support assembly breakpoints without a valid symbol. return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Breakpoints in assembly without a valid " - "symbol are not supported yet."); + "Breakpoints in assembly without a valid " + "symbol are not supported yet."); } lldb::SBInstructionList inst_list = m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); if (inst_list.GetSize() < m_line) return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid instruction list size."); + "Invalid instruction list size."); lldb::SBAddress address = inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); @@ -115,7 +119,8 @@ llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithSourceReference(int64_ return llvm::Error::success(); } -llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data) { +llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData( + const protocol::PersistenceData &persistence_data) { lldb::SBFileSpec file_spec(persistence_data.module.c_str()); m_bp = m_dap.target.BreakpointCreateByFileAddress( file_spec, persistence_data.file_addr, 0, m_line - 1); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h index b9086a0c8fbb7..34054a8dcfd5f 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ b/lldb/tools/lldb-dap/SourceBreakpoint.h @@ -52,8 +52,10 @@ class SourceBreakpoint : public Breakpoint { protected: void CreatePathBreakpoint(const protocol::Source &source); - llvm::Error CreateAssemblyBreakpointWithSourceReference(int64_t source_reference); - llvm::Error CreateAssemblyBreakpointWithPersistenceData(const protocol::PersistenceData &persistence_data); + llvm::Error + CreateAssemblyBreakpointWithSourceReference(int64_t source_reference); + llvm::Error CreateAssemblyBreakpointWithPersistenceData( + const protocol::PersistenceData &persistence_data); // logMessage part can be either a raw text or an expression. struct LogMessagePart { >From 61c34695865ebdb910b0e067b8cea4e208ba0c48 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 17:17:51 +0200 Subject: [PATCH 09/19] add persistence data to response --- lldb/tools/lldb-dap/Breakpoint.cpp | 38 +++++++++++++++++++++++++----- lldb/tools/lldb-dap/DAP.cpp | 12 +++++++--- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index b4e593eb83d27..346a8037f6223 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -8,10 +8,13 @@ #include "Breakpoint.h" #include "DAP.h" +#include "Protocol/DAPTypes.h" #include "ProtocolUtils.h" #include "lldb/API/SBAddress.h" #include "lldb/API/SBBreakpointLocation.h" +#include "lldb/API/SBFileSpec.h" #include "lldb/API/SBLineEntry.h" +#include "lldb/API/SBModule.h" #include "lldb/API/SBMutex.h" #include "llvm/ADT/StringExtras.h" #include <cstddef> @@ -21,6 +24,22 @@ using namespace lldb_dap; +static std::optional<protocol::PersistenceData> +GetPersistenceDataForAddress(lldb::SBAddress &addr) { + protocol::PersistenceData persistence_data; + lldb::SBModule module = addr.GetModule(); + if (!module.IsValid()) + return std::nullopt; + + lldb::SBFileSpec file_spec = module.GetFileSpec(); + if (!file_spec.IsValid()) + return std::nullopt; + + persistence_data.module = file_spec.GetFilename(); + persistence_data.file_addr = addr.GetFileAddress(); + return persistence_data; +} + void Breakpoint::SetCondition() { m_bp.SetCondition(m_condition.c_str()); } void Breakpoint::SetHitCondition() { @@ -73,15 +92,22 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { const auto column = line_entry.GetColumn(); if (column != LLDB_INVALID_COLUMN_NUMBER) breakpoint.column = column; - } else { + } else if (source) { // Assembly breakpoint. auto symbol = bp_addr.GetSymbol(); if (symbol.IsValid()) { - breakpoint.line = - m_bp.GetTarget() - .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) - .GetSize() + - 1; + lldb::SBAddress start_address = symbol.GetStartAddress(); + breakpoint.line = m_bp.GetTarget() + .ReadInstructions(start_address, bp_addr, nullptr) + .GetSize() + + 1; + + // Add persistent data so that the breakpoint can be resolved + // in future sessions. + std::optional<protocol::PersistenceData> persistence_data = + GetPersistenceDataForAddress(start_address); + if (persistence_data) + source->adapterData->persistence_data = std::move(persistence_data); } } diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index fd89f52595ec6..d748200509643 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -31,6 +31,7 @@ #include "lldb/API/SBStream.h" #include "lldb/Utility/IOObject.h" #include "lldb/Utility/Status.h" +#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-types.h" @@ -1406,11 +1407,16 @@ 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 = bp.ToProtocolBreakpoint(); - source_bp.getAsObject()->erase("source"); + protocol::Breakpoint protocol_bp = bp.ToProtocolBreakpoint(); + llvm::json::Value protocol_bp_value = toJSON(protocol_bp); + + // "source" is not needed here, unless we add adapter data to be + // saved by the client. + if (protocol_bp.source && !protocol_bp.source->adapterData) + protocol_bp_value.getAsObject()->erase("source"); llvm::json::Object body; - body.try_emplace("breakpoint", source_bp); + body.try_emplace("breakpoint", protocol_bp); body.try_emplace("reason", "changed"); llvm::json::Object bp_event = CreateEventObject("breakpoint"); >From a493c4ced971048eb159337768f6141370d3ea2b Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Sun, 6 Jul 2025 17:52:27 +0200 Subject: [PATCH 10/19] fix --- lldb/tools/lldb-dap/Breakpoint.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 346a8037f6223..64590c1845e6d 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -106,8 +106,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { // in future sessions. std::optional<protocol::PersistenceData> persistence_data = GetPersistenceDataForAddress(start_address); - if (persistence_data) - source->adapterData->persistence_data = std::move(persistence_data); + if (persistence_data) { + source->adapterData = + protocol::SourceLLDBData{std::move(persistence_data)}; + } } } >From 6aaae350855df202ec468ac5640cd9c7679b91a0 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Tue, 8 Jul 2025 20:55:20 +0200 Subject: [PATCH 11/19] fix --- lldb/tools/lldb-dap/Breakpoint.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index 64590c1845e6d..ac47975c4e9d2 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -8,6 +8,7 @@ #include "Breakpoint.h" #include "DAP.h" +#include "LLDBUtils.h" #include "Protocol/DAPTypes.h" #include "ProtocolUtils.h" #include "lldb/API/SBAddress.h" @@ -35,7 +36,7 @@ GetPersistenceDataForAddress(lldb::SBAddress &addr) { if (!file_spec.IsValid()) return std::nullopt; - persistence_data.module = file_spec.GetFilename(); + persistence_data.module = GetSBFileSpecPath(file_spec); persistence_data.file_addr = addr.GetFileAddress(); return persistence_data; } >From 66510aa16cda65639665cdff205aa952fa440ad5 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Tue, 8 Jul 2025 22:46:48 +0200 Subject: [PATCH 12/19] fix address resolve of a module that is not loaded yet --- lldb/source/Breakpoint/BreakpointResolverAddress.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp index a0343e3957c2e..fae2022220ba3 100644 --- a/lldb/source/Breakpoint/BreakpointResolverAddress.cpp +++ b/lldb/source/Breakpoint/BreakpointResolverAddress.cpp @@ -141,6 +141,11 @@ Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback( Address tmp_address; if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address)) m_addr = tmp_address; + else + return Searcher::eCallbackReturnStop; + } else { + // If we didn't find the module, then we can't resolve the address. + return Searcher::eCallbackReturnStop; } } >From f528713000f0f2e65eb46c71a26852f4d95d02a5 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Wed, 9 Jul 2025 02:08:50 +0200 Subject: [PATCH 13/19] fix check --- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 5d87409b45a96..ffd28c9592fba 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -46,7 +46,7 @@ llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { return llvm::createStringError(llvm::inconvertibleErrorCode(), "Invalid line number."); - if (IsAssemblySource(source)) { + if (source.sourceReference) { // Breakpoint set by assembly source. if (source.adapterData && source.adapterData->persistence_data) { // Prefer use the adapter persitence data, because this could be a >From 0019d2cbbff17ba09402070d18db9c8aa2a81216 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Thu, 10 Jul 2025 22:21:38 +0200 Subject: [PATCH 14/19] conventions --- lldb/tools/lldb-dap/Breakpoint.cpp | 2 +- lldb/tools/lldb-dap/DAP.cpp | 3 ++- lldb/tools/lldb-dap/Protocol/DAPTypes.cpp | 10 +++++----- lldb/tools/lldb-dap/Protocol/DAPTypes.h | 4 ++-- lldb/tools/lldb-dap/SourceBreakpoint.cpp | 6 +++--- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp index ac47975c4e9d2..01d46c5a29553 100644 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ b/lldb/tools/lldb-dap/Breakpoint.cpp @@ -37,7 +37,7 @@ GetPersistenceDataForAddress(lldb::SBAddress &addr) { return std::nullopt; persistence_data.module = GetSBFileSpecPath(file_spec); - persistence_data.file_addr = addr.GetFileAddress(); + persistence_data.fileAddress = addr.GetFileAddress(); return persistence_data; } diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index d748200509643..e4fc182bf5fb4 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1497,8 +1497,9 @@ std::vector<protocol::Breakpoint> DAP::SetSourceBreakpoints( protocol::Breakpoint response_breakpoint = iv->second.ToProtocolBreakpoint(); - response_breakpoint.source = source; + if (!response_breakpoint.source) + response_breakpoint.source = source; if (!response_breakpoint.line && src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) response_breakpoint.line = src_bp.GetLine(); diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp index e45a4f30d9bcf..c4b20bb06f8dc 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.cpp @@ -9,13 +9,13 @@ bool fromJSON(const llvm::json::Value &Params, PersistenceData &PD, llvm::json::Path P) { json::ObjectMapper O(Params, P); return O && O.mapOptional("module", PD.module) && - O.mapOptional("file_addr", PD.file_addr); + O.mapOptional("fileAddress", PD.fileAddress); } llvm::json::Value toJSON(const PersistenceData &PD) { json::Object result{ {"module", PD.module}, - {"file_addr", PD.file_addr}, + {"fileAddress", PD.fileAddress}, }; return result; @@ -24,13 +24,13 @@ llvm::json::Value toJSON(const PersistenceData &PD) { bool fromJSON(const llvm::json::Value &Params, SourceLLDBData &SLD, llvm::json::Path P) { json::ObjectMapper O(Params, P); - return O && O.mapOptional("persistence_data", SLD.persistence_data); + return O && O.mapOptional("persistenceData", SLD.persistenceData); } llvm::json::Value toJSON(const SourceLLDBData &SLD) { json::Object result; - if (SLD.persistence_data) - result.insert({"persistence_data", SLD.persistence_data}); + if (SLD.persistenceData) + result.insert({"persistenceData", SLD.persistenceData}); return result; } diff --git a/lldb/tools/lldb-dap/Protocol/DAPTypes.h b/lldb/tools/lldb-dap/Protocol/DAPTypes.h index f112b5af772e3..be019122f2eb5 100644 --- a/lldb/tools/lldb-dap/Protocol/DAPTypes.h +++ b/lldb/tools/lldb-dap/Protocol/DAPTypes.h @@ -32,7 +32,7 @@ struct PersistenceData { std::string module; /// The file address of the function. - lldb::addr_t file_addr; + lldb::addr_t fileAddress; }; bool fromJSON(const llvm::json::Value &, PersistenceData &, llvm::json::Path); llvm::json::Value toJSON(const PersistenceData &); @@ -43,7 +43,7 @@ llvm::json::Value toJSON(const PersistenceData &); struct SourceLLDBData { /// Data that helps lldb resolve this source persistently across different /// sessions. - std::optional<PersistenceData> persistence_data; + std::optional<PersistenceData> persistenceData; }; bool fromJSON(const llvm::json::Value &, SourceLLDBData &, llvm::json::Path); llvm::json::Value toJSON(const SourceLLDBData &); diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index ffd28c9592fba..ffc38a24e82a7 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -48,12 +48,12 @@ llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { if (source.sourceReference) { // Breakpoint set by assembly source. - if (source.adapterData && source.adapterData->persistence_data) { + if (source.adapterData && source.adapterData->persistenceData) { // Prefer use the adapter persitence data, because this could be a // breakpoint from a previous session where the `sourceReference` is not // valid anymore. if (llvm::Error error = CreateAssemblyBreakpointWithPersistenceData( - *source.adapterData->persistence_data)) + *source.adapterData->persistenceData)) return error; } else { if (llvm::Error error = CreateAssemblyBreakpointWithSourceReference( @@ -123,7 +123,7 @@ llvm::Error SourceBreakpoint::CreateAssemblyBreakpointWithPersistenceData( const protocol::PersistenceData &persistence_data) { lldb::SBFileSpec file_spec(persistence_data.module.c_str()); m_bp = m_dap.target.BreakpointCreateByFileAddress( - file_spec, persistence_data.file_addr, 0, m_line - 1); + file_spec, persistence_data.fileAddress, 0, m_line - 1); return llvm::Error::success(); } >From 57459f9409bd2288408eb075843936eb2bb487f3 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Thu, 10 Jul 2025 22:42:53 +0200 Subject: [PATCH 15/19] add persistence assembly breakpoint test --- .../test/tools/lldb-dap/dap_server.py | 29 ++++++-- .../test/tools/lldb-dap/lldbdap_testcase.py | 22 +++--- .../TestDAP_breakpointAssembly.py | 69 +++++++++++++++++++ 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 68f58bf1349a7..5b39540d0b876 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -107,17 +107,20 @@ def dump_dap_log(log_file): class Source(object): def __init__( - self, path: Optional[str] = None, source_reference: Optional[int] = None + self, path: Optional[str] = None, source_reference: Optional[int] = None, raw_dict: Optional[dict[str, Any]] = None ): self._name = None self._path = None self._source_reference = None + self._raw_dict = None if path is not None: self._name = os.path.basename(path) self._path = path elif source_reference is not None: self._source_reference = source_reference + elif raw_dict is not None: + self._raw_dict = raw_dict else: raise ValueError("Either path or source_reference must be provided") @@ -125,6 +128,9 @@ def __str__(self): return f"Source(name={self.name}, path={self.path}), source_reference={self.source_reference})" def as_dict(self): + if self._raw_dict is not None: + return self._raw_dict + source_dict = {} if self._name is not None: source_dict["name"] = self._name @@ -135,6 +141,19 @@ def as_dict(self): return source_dict +class Breakpoint(object): + def __init__(self, obj): + self._breakpoint = obj + + def is_verified(self): + """Check if the breakpoint is verified.""" + return self._breakpoint.get("verified", False) + + def source(self): + """Get the source of the breakpoint.""" + return self._breakpoint.get("source", {}) + + class NotSupportedError(KeyError): """Raised if a feature is not supported due to its capabilities.""" @@ -170,7 +189,7 @@ def __init__( self.initialized = False self.frame_scopes = {} self.init_commands = init_commands - self.resolved_breakpoints = {} + self.resolved_breakpoints: dict[str, Breakpoint] = {} @classmethod def encode_content(cls, s: str) -> bytes: @@ -326,9 +345,7 @@ def _process_continued(self, all_threads_continued: bool): def _update_verified_breakpoints(self, breakpoints: list[Event]): for breakpoint in breakpoints: if "id" in breakpoint: - self.resolved_breakpoints[str(breakpoint["id"])] = breakpoint.get( - "verified", False - ) + self.resolved_breakpoints[str(breakpoint["id"])] = Breakpoint(breakpoint) def send_packet(self, command_dict: Request, set_sequence=True): """Take the "command_dict" python dictionary and encode it as a JSON @@ -484,7 +501,7 @@ def wait_for_breakpoints_to_be_verified( if breakpoint_event is None: break - return [id for id in breakpoint_ids if id not in self.resolved_breakpoints] + return [id for id in breakpoint_ids if (id not in self.resolved_breakpoints or not self.resolved_breakpoints[id].is_verified())] def wait_for_exited(self, timeout: Optional[float] = None): event_dict = self.wait_for_event("exited", timeout=timeout) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 00b01d4bdb1c5..57a580052557e 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -59,24 +59,22 @@ def set_source_breakpoints( Each object in data is 1:1 mapping with the entry in lines. It contains optional location/hitCondition/logMessage parameters. """ - response = self.dap_server.request_setBreakpoints( - Source(source_path), lines, data + return self.set_source_breakpoints_from_source( + Source(path=source_path), lines, data, wait_for_resolve ) - if response is None or not response["success"]: - return [] - breakpoints = response["body"]["breakpoints"] - breakpoint_ids = [] - for breakpoint in breakpoints: - breakpoint_ids.append("%i" % (breakpoint["id"])) - if wait_for_resolve: - self.wait_for_breakpoints_to_resolve(breakpoint_ids) - return breakpoint_ids def set_source_breakpoints_assembly( self, source_reference, lines, data=None, wait_for_resolve=True + ): + return self.set_source_breakpoints_from_source( + Source(source_reference=source_reference), lines, data, wait_for_resolve + ) + + def set_source_breakpoints_from_source( + self, source: Source, lines, data=None, wait_for_resolve=True ): response = self.dap_server.request_setBreakpoints( - Source(source_reference=source_reference), + source, lines, data, ) diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index 674bfe4199b4a..2ce928cef08e1 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -83,3 +83,72 @@ def test_break_on_invalid_source_reference(self): break_point["message"], "Invalid sourceReference.", ) + + @skipIfWindows + def test_persistent_assembly_breakpoint(self): + """Tests that assembly breakpoints are working persistently across sessions""" + self.build() + program = self.getBuildArtifact("a.out") + self.create_debug_adapter() + + # Run the first session and set a persistent assembly breakpoint + try: + self.dap_server.request_initialize() + self.dap_server.request_launch(program) + + assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"]) + self.continue_to_breakpoints(assmebly_func_breakpoints) + + assembly_func_frame = self.get_stackFrames()[0] + source_reference = assembly_func_frame["source"]["sourceReference"] + + # Set an assembly breakpoint in the middle of the assembly function + persistent_breakpoint_line = 4 + persistent_breakpoint_ids = self.set_source_breakpoints_assembly( + source_reference, [persistent_breakpoint_line] + ) + + self.assertEqual( + len(persistent_breakpoint_ids), 1, "Expected one assembly breakpoint to be set" + ) + + persistent_breakpoint_source = self.dap_server.resolved_breakpoints[persistent_breakpoint_ids[0]].source() + self.assertIn( + "adapterData", + persistent_breakpoint_source, + "Expected assembly breakpoint to have persistent information", + ) + self.assertIn( + "persistenceData", + persistent_breakpoint_source["adapterData"], + "Expected assembly breakpoint to have persistent information", + ) + + self.continue_to_breakpoints(persistent_breakpoint_ids) + finally: + self.dap_server.request_disconnect(terminateDebuggee=True) + self.dap_server.terminate() + + # Restart the session and verify the breakpoint is still there + self.create_debug_adapter() + try: + self.dap_server.request_initialize() + self.dap_server.request_launch(program) + new_session_breakpoints_ids = self.set_source_breakpoints_from_source( + Source(raw_dict=persistent_breakpoint_source), [persistent_breakpoint_line] + ) + + self.assertEqual( + len(new_session_breakpoints_ids), + 1, + "Expected one breakpoint to be set in the new session", + ) + + self.continue_to_breakpoints(new_session_breakpoints_ids) + current_line = self.get_stackFrames()[0]["line"] + self.assertEqual(current_line, persistent_breakpoint_line, + "Expected to hit the persistent assembly breakpoint at the same line") + finally: + self.dap_server.request_disconnect(terminateDebuggee=True) + self.dap_server.terminate() + >From 70d369e682f2bf74fe4e92660805ac93d0a73641 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Thu, 10 Jul 2025 23:15:45 +0200 Subject: [PATCH 16/19] fix --- lldb/source/API/SBTarget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp index ce502e453dcd9..84478ffe22601 100644 --- a/lldb/source/API/SBTarget.cpp +++ b/lldb/source/API/SBTarget.cpp @@ -66,7 +66,6 @@ #include "Commands/CommandObjectBreakpoint.h" #include "lldb/Interpreter/CommandReturnObject.h" -#include "lldb/lldb-types.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Regex.h" >From 4b3412ef5c26e61344088283ee95ba517b14b6b2 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Thu, 10 Jul 2025 23:19:11 +0200 Subject: [PATCH 17/19] fix --- lldb/source/Target/Target.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index bb276c0a81795..b1d6fdf8f7537 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -2994,9 +2994,6 @@ lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { lldb::DisassemblerSP Target::ReadInstructions(const Address &start_addr, uint32_t count, const char *flavor_string) { - if (!m_process_sp) - return lldb::DisassemblerSP(); - DataBufferHeap data(GetArchitecture().GetMaximumOpcodeByteSize() * count, 0); bool force_live_memory = true; lldb_private::Status error; >From b0e3865596985f5c6f8054e42b12494c8420ee07 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Thu, 10 Jul 2025 23:42:20 +0200 Subject: [PATCH 18/19] python format --- .../test/tools/lldb-dap/dap_server.py | 20 ++++++++++++---- .../test/tools/lldb-dap/lldbdap_testcase.py | 2 +- .../TestDAP_breakpointAssembly.py | 23 ++++++++++++------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 5b39540d0b876..6c6a674f664ad 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -107,7 +107,10 @@ def dump_dap_log(log_file): class Source(object): def __init__( - self, path: Optional[str] = None, source_reference: Optional[int] = None, raw_dict: Optional[dict[str, Any]] = None + self, + path: Optional[str] = None, + source_reference: Optional[int] = None, + raw_dict: Optional[dict[str, Any]] = None, ): self._name = None self._path = None @@ -148,7 +151,7 @@ def __init__(self, obj): def is_verified(self): """Check if the breakpoint is verified.""" return self._breakpoint.get("verified", False) - + def source(self): """Get the source of the breakpoint.""" return self._breakpoint.get("source", {}) @@ -345,7 +348,9 @@ def _process_continued(self, all_threads_continued: bool): def _update_verified_breakpoints(self, breakpoints: list[Event]): for breakpoint in breakpoints: if "id" in breakpoint: - self.resolved_breakpoints[str(breakpoint["id"])] = Breakpoint(breakpoint) + self.resolved_breakpoints[str(breakpoint["id"])] = Breakpoint( + breakpoint + ) def send_packet(self, command_dict: Request, set_sequence=True): """Take the "command_dict" python dictionary and encode it as a JSON @@ -501,7 +506,14 @@ def wait_for_breakpoints_to_be_verified( if breakpoint_event is None: break - return [id for id in breakpoint_ids if (id not in self.resolved_breakpoints or not self.resolved_breakpoints[id].is_verified())] + return [ + id + for id in breakpoint_ids + if ( + id not in self.resolved_breakpoints + or not self.resolved_breakpoints[id].is_verified() + ) + ] def wait_for_exited(self, timeout: Optional[float] = None): event_dict = self.wait_for_event("exited", timeout=timeout) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 57a580052557e..1cb885b149dfd 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -69,7 +69,7 @@ def set_source_breakpoints_assembly( return self.set_source_breakpoints_from_source( Source(source_reference=source_reference), lines, data, wait_for_resolve ) - + def set_source_breakpoints_from_source( self, source: Source, lines, data=None, wait_for_resolve=True ): diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py index 2ce928cef08e1..7552a77d2280a 100644 --- a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py +++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py @@ -107,12 +107,16 @@ def test_persistent_assembly_breakpoint(self): persistent_breakpoint_ids = self.set_source_breakpoints_assembly( source_reference, [persistent_breakpoint_line] ) - + self.assertEqual( - len(persistent_breakpoint_ids), 1, "Expected one assembly breakpoint to be set" + len(persistent_breakpoint_ids), + 1, + "Expected one assembly breakpoint to be set", ) - persistent_breakpoint_source = self.dap_server.resolved_breakpoints[persistent_breakpoint_ids[0]].source() + persistent_breakpoint_source = self.dap_server.resolved_breakpoints[ + persistent_breakpoint_ids[0] + ].source() self.assertIn( "adapterData", persistent_breakpoint_source, @@ -135,9 +139,10 @@ def test_persistent_assembly_breakpoint(self): self.dap_server.request_initialize() self.dap_server.request_launch(program) new_session_breakpoints_ids = self.set_source_breakpoints_from_source( - Source(raw_dict=persistent_breakpoint_source), [persistent_breakpoint_line] + Source(raw_dict=persistent_breakpoint_source), + [persistent_breakpoint_line], ) - + self.assertEqual( len(new_session_breakpoints_ids), 1, @@ -146,9 +151,11 @@ def test_persistent_assembly_breakpoint(self): self.continue_to_breakpoints(new_session_breakpoints_ids) current_line = self.get_stackFrames()[0]["line"] - self.assertEqual(current_line, persistent_breakpoint_line, - "Expected to hit the persistent assembly breakpoint at the same line") + self.assertEqual( + current_line, + persistent_breakpoint_line, + "Expected to hit the persistent assembly breakpoint at the same line", + ) finally: self.dap_server.request_disconnect(terminateDebuggee=True) self.dap_server.terminate() - >From 9c9052061aa4531a13f6fc4710b4758db8deebf7 Mon Sep 17 00:00:00 2001 From: Ely Ronnen <elyron...@gmail.com> Date: Fri, 11 Jul 2025 09:49:31 +0200 Subject: [PATCH 19/19] remove raw json usage --- lldb/tools/lldb-dap/DAP.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index e4fc182bf5fb4..399bf50244994 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -1408,12 +1408,11 @@ void DAP::EventThread() { // CreateBreakpoint doesn't apply source mapping and certain // implementation ignore the source part of this event anyway. protocol::Breakpoint protocol_bp = bp.ToProtocolBreakpoint(); - llvm::json::Value protocol_bp_value = toJSON(protocol_bp); // "source" is not needed here, unless we add adapter data to be // saved by the client. if (protocol_bp.source && !protocol_bp.source->adapterData) - protocol_bp_value.getAsObject()->erase("source"); + protocol_bp.source = std::nullopt; llvm::json::Object body; body.try_emplace("breakpoint", protocol_bp); _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits