[Lldb-commits] [lldb] [lldb-dap] Reuse source object logics (PR #141426)

Ely Ronnen via lldb-commits lldb-commits at lists.llvm.org
Fri May 30 14:53:04 PDT 2025


https://github.com/eronnen updated https://github.com/llvm/llvm-project/pull/141426

>From d57cd027fc66447651739fb8141c51d316999988 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Wed, 21 May 2025 23:39:56 +0200
Subject: [PATCH 1/8] Reuse creation of Source objects for assembly and normal
 sources

---
 lldb/tools/lldb-dap/Breakpoint.cpp            |  14 +-
 .../Handler/DisassembleRequestHandler.cpp     |  21 +--
 .../Handler/LocationsRequestHandler.cpp       |  10 +-
 .../Handler/StackTraceRequestHandler.cpp      |   6 +-
 lldb/tools/lldb-dap/JSONUtils.cpp             | 123 +++++++++---------
 lldb/tools/lldb-dap/JSONUtils.h               |  49 ++-----
 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h  |   2 +
 7 files changed, 100 insertions(+), 125 deletions(-)

diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 2d0fd9c9c3954..440d589b912fc 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -9,12 +9,10 @@
 #include "Breakpoint.h"
 #include "DAP.h"
 #include "JSONUtils.h"
-#include "LLDBUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBBreakpointLocation.h"
 #include "lldb/API/SBLineEntry.h"
 #include "lldb/API/SBMutex.h"
-#include "lldb/lldb-enumerations.h"
 #include "llvm/ADT/StringExtras.h"
 #include <cstddef>
 #include <cstdint>
@@ -66,17 +64,15 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
         "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));
     breakpoint.instructionReference = formatted_addr;
 
-    lldb::StopDisassemblyType stop_disassembly_display =
-        GetStopDisassemblyDisplay(m_dap.debugger);
-    auto line_entry = bp_addr.GetLineEntry();
-    if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) {
+    auto source = CreateSource(bp_addr, m_dap.debugger);
+    if (!source.IsAssemblySource()) {
+      auto line_entry = bp_addr.GetLineEntry();
       const auto line = line_entry.GetLine();
       if (line != LLDB_INVALID_LINE_NUMBER)
         breakpoint.line = line;
       const auto column = line_entry.GetColumn();
       if (column != LLDB_INVALID_COLUMN_NUMBER)
         breakpoint.column = column;
-      breakpoint.source = CreateSource(line_entry);
     } else {
       // Assembly breakpoint.
       auto symbol = bp_addr.GetSymbol();
@@ -86,10 +82,10 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
                 .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr)
                 .GetSize() +
             1;
-
-        breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr);
       }
     }
+
+    breakpoint.source = std::move(source);
   }
 
   return breakpoint;
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 1d110eac18126..49e7c788a7fb3 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -13,6 +13,7 @@
 #include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
+#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBInstruction.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/lldb-types.h"
@@ -81,12 +82,15 @@ static lldb::SBAddress GetDisassembleStartAddress(lldb::SBTarget target,
       .GetAddress();
 }
 
-static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
-    lldb::SBTarget &target, lldb::SBInstruction &inst, bool resolve_symbols) {
+static DisassembledInstruction
+ConvertSBInstructionToDisassembledInstruction(lldb::SBDebugger &debugger,
+                                              lldb::SBInstruction &inst,
+                                              bool resolve_symbols) {
   if (!inst.IsValid())
     return GetInvalidInstruction();
 
-  auto addr = inst.GetAddress();
+  lldb::SBTarget target = debugger.GetSelectedTarget();
+  lldb::SBAddress addr = inst.GetAddress();
   const auto inst_addr = addr.GetLoadAddress(target);
 
   // FIXME: This is a workaround - this address might come from
@@ -139,15 +143,14 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
 
   disassembled_inst.instruction = std::move(instruction);
 
+  auto source = CreateSource(addr, debugger);
   auto line_entry = addr.GetLineEntry();
-  // If the line number is 0 then the entry represents a compiler generated
-  // location.
 
-  if (line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
+  if (!source.IsAssemblySource() && line_entry.IsValid() &&
+      line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
       line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
-    auto source = CreateSource(line_entry);
-    disassembled_inst.location = std::move(source);
 
+    disassembled_inst.location = std::move(source);
     const auto line = line_entry.GetLine();
     if (line != 0 && line != LLDB_INVALID_LINE_NUMBER)
       disassembled_inst.line = line;
@@ -235,7 +238,7 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
       original_address_index = i;
 
     instructions.push_back(ConvertSBInstructionToDisassembledInstruction(
-        dap.target, inst, resolve_symbols));
+        dap.debugger, inst, resolve_symbols));
   }
 
   // Check if we miss instructions at the beginning.
diff --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
index 15109d4b8e589..29f7356f46e42 100644
--- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
@@ -10,7 +10,9 @@
 #include "EventHelper.h"
 #include "JSONUtils.h"
 #include "RequestHandler.h"
+#include "lldb/API/SBAddress.h"
 #include "lldb/API/SBDeclaration.h"
+#include "lldb/API/SBLineEntry.h"
 
 namespace lldb_dap {
 
@@ -122,9 +124,9 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    lldb::addr_t addr = variable.GetValueAsAddress();
-    lldb::SBLineEntry line_entry =
-        dap.target.ResolveLoadAddress(addr).GetLineEntry();
+    lldb::addr_t raw_addr = variable.GetValueAsAddress();
+    lldb::SBAddress addr = dap.target.ResolveLoadAddress(raw_addr);
+    lldb::SBLineEntry line_entry = addr.GetLineEntry();
 
     if (!line_entry.IsValid()) {
       response["success"] = false;
@@ -133,7 +135,7 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source", CreateSource(line_entry.GetFileSpec()));
+    body.try_emplace("source", CreateSource(addr, dap.debugger));
     if (int line = line_entry.GetLine())
       body.try_emplace("line", line);
     if (int column = line_entry.GetColumn())
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index ff326a47d9a48..1a4e87f8035ec 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -9,9 +9,7 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "JSONUtils.h"
-#include "LLDBUtils.h"
 #include "RequestHandler.h"
-#include "lldb/lldb-enumerations.h"
 
 namespace lldb_dap {
 
@@ -55,8 +53,6 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
                             llvm::json::Array &stack_frames, int64_t &offset,
                             const int64_t start_frame, const int64_t levels,
                             const bool include_all) {
-  lldb::StopDisassemblyType stop_disassembly_display =
-      GetStopDisassemblyDisplay(dap.debugger);
   bool reached_end_of_stack = false;
   for (int64_t i = start_frame;
        static_cast<int64_t>(stack_frames.size()) < levels; i++) {
@@ -74,7 +70,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
     }
 
     stack_frames.emplace_back(
-        CreateStackFrame(frame, frame_format, stop_disassembly_display));
+        CreateStackFrame(frame, frame_format, dap.debugger));
   }
 
   if (include_all && reached_end_of_stack) {
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index c9c6f4554c325..318f493f26e2f 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -497,34 +497,33 @@ static std::string GetLoadAddressString(const lldb::addr_t addr) {
   return result;
 }
 
-protocol::Source CreateSource(const lldb::SBFileSpec &file) {
-  protocol::Source source;
-  if (file.IsValid()) {
-    const char *name = file.GetFilename();
-    if (name)
-      source.name = name;
-    char path[PATH_MAX] = "";
-    if (file.GetPath(path, sizeof(path)) &&
-        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
-      source.path = path;
-  }
-  return source;
-}
+static bool ShouldDisplayAssemblySource(
+    lldb::SBAddress address,
+    lldb::StopDisassemblyType stop_disassembly_display) {
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever)
+    return false;
 
-protocol::Source CreateSource(const lldb::SBLineEntry &line_entry) {
-  return CreateSource(line_entry.GetFileSpec());
-}
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways)
+    return true;
 
-protocol::Source CreateSource(llvm::StringRef source_path) {
-  protocol::Source source;
-  llvm::StringRef name = llvm::sys::path::filename(source_path);
-  source.name = name;
-  source.path = source_path;
-  return source;
+  // A line entry of 0 indicates the line is compiler generated i.e. no source
+  // file is associated with the frame.
+  auto line_entry = address.GetLineEntry();
+  auto file_spec = line_entry.GetFileSpec();
+  if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
+      line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
+    return true;
+
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource &&
+      !file_spec.Exists()) {
+    return true;
+  }
+
+  return false;
 }
 
-protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
-                                      lldb::SBAddress &address) {
+static protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
+                                             lldb::SBAddress address) {
   protocol::Source source;
 
   auto symbol = address.GetSymbol();
@@ -558,28 +557,36 @@ protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
   return source;
 }
 
-bool ShouldDisplayAssemblySource(
-    const lldb::SBLineEntry &line_entry,
-    lldb::StopDisassemblyType stop_disassembly_display) {
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever)
-    return false;
-
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways)
-    return true;
+protocol::Source CreateSource(const lldb::SBFileSpec &file) {
+  protocol::Source source;
+  if (file.IsValid()) {
+    const char *name = file.GetFilename();
+    if (name)
+      source.name = name;
+    char path[PATH_MAX] = "";
+    if (file.GetPath(path, sizeof(path)) &&
+        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
+      source.path = path;
+  }
+  return source;
+}
 
-  // A line entry of 0 indicates the line is compiler generated i.e. no source
-  // file is associated with the frame.
-  auto file_spec = line_entry.GetFileSpec();
-  if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
-      line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
-    return true;
+protocol::Source CreateSource(lldb::SBAddress address,
+                              lldb::SBDebugger &debugger) {
+  lldb::StopDisassemblyType stop_disassembly_display =
+      GetStopDisassemblyDisplay(debugger);
+  if (!ShouldDisplayAssemblySource(address, stop_disassembly_display))
+    return CreateSource(address.GetLineEntry().GetFileSpec());
 
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource &&
-      !file_spec.Exists()) {
-    return true;
-  }
+  return CreateAssemblySource(debugger.GetSelectedTarget(), address);
+}
 
-  return false;
+protocol::Source CreateSource(llvm::StringRef source_path) {
+  protocol::Source source;
+  llvm::StringRef name = llvm::sys::path::filename(source_path);
+  source.name = name;
+  source.path = source_path;
+  return source;
 }
 
 // "StackFrame": {
@@ -643,9 +650,8 @@ bool ShouldDisplayAssemblySource(
 //   },
 //   "required": [ "id", "name", "line", "column" ]
 // }
-llvm::json::Value
-CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
-                 lldb::StopDisassemblyType stop_disassembly_display) {
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
+                                   lldb::SBDebugger &debugger) {
   llvm::json::Object object;
   int64_t frame_id = MakeDAPFrameID(frame);
   object.try_emplace("id", frame_id);
@@ -673,22 +679,17 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
 
   EmplaceSafeString(object, "name", frame_name);
 
-  auto line_entry = frame.GetLineEntry();
-  if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) {
-    object.try_emplace("source", CreateSource(line_entry));
+  auto source = CreateSource(frame.GetPCAddress(), debugger);
+  if (!source.IsAssemblySource()) {
+    // This is a normal source with valid line entry.
+    auto line_entry = frame.GetLineEntry();
     object.try_emplace("line", line_entry.GetLine());
     auto column = line_entry.GetColumn();
     object.try_emplace("column", column);
   } else if (frame.GetSymbol().IsValid()) {
-    // If no source is associated with the frame, use the DAPFrameID to track
-    // the 'source' and generate assembly.
-    auto frame_address = frame.GetPCAddress();
-    object.try_emplace("source", CreateAssemblySource(
-                                     frame.GetThread().GetProcess().GetTarget(),
-                                     frame_address));
-
-    // Calculate the line of the current PC from the start of the current
-    // symbol.
+    // This is a source where the disassembly is used, but there is a valid
+    // symbol. Calculate the line of the current PC from the start of the
+    // current symbol.
     lldb::SBTarget target = frame.GetThread().GetProcess().GetTarget();
     lldb::SBInstructionList inst_list = target.ReadInstructions(
         frame.GetSymbol().GetStartAddress(), frame.GetPCAddress(), nullptr);
@@ -699,14 +700,12 @@ CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
     object.try_emplace("column", 1);
   } else {
     // No valid line entry or symbol.
-    auto frame_address = frame.GetPCAddress();
-    object.try_emplace("source", CreateAssemblySource(
-                                     frame.GetThread().GetProcess().GetTarget(),
-                                     frame_address));
     object.try_emplace("line", 1);
     object.try_emplace("column", 1);
   }
 
+  object.try_emplace("source", std::move(source));
+
   const auto pc = frame.GetPC();
   if (pc != LLDB_INVALID_ADDRESS) {
     std::string formatted_addr = "0x" + llvm::utohexstr(pc);
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 5758c3d56ec90..74866cdf32840 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -11,7 +11,9 @@
 
 #include "DAPForward.h"
 #include "Protocol/ProtocolTypes.h"
+#include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBFileSpec.h"
 #include "lldb/API/SBFormat.h"
 #include "lldb/API/SBLineEntry.h"
@@ -250,14 +252,17 @@ protocol::Source CreateSource(const lldb::SBFileSpec &file);
 
 /// Create a "Source" JSON object as described in the debug adapter definition.
 ///
-/// \param[in] line_entry
-///     The LLDB line table to use when populating out the "Source"
-///     object
+/// \param[in] address
+///     The address to use when populating out the "Source" object.
+///
+/// \param[in] debugger
+///     The debugger, used to get relevant settings.
 ///
 /// \return
 ///     A "Source" JSON object that follows the formal JSON
 ///     definition outlined by Microsoft.
-protocol::Source CreateSource(const lldb::SBLineEntry &line_entry);
+protocol::Source CreateSource(lldb::SBAddress address,
+                              lldb::SBDebugger &debugger);
 
 /// Create a "Source" object for a given source path.
 ///
@@ -269,35 +274,6 @@ protocol::Source CreateSource(const lldb::SBLineEntry &line_entry);
 ///     definition outlined by Microsoft.
 protocol::Source CreateSource(llvm::StringRef source_path);
 
-/// Create a "Source" object for a given frame, using its assembly for source.
-///
-/// \param[in] target
-///     The relevant target.
-///
-/// \param[in] address
-///     The address to use when creating the "Source" object.
-///
-/// \return
-///     A "Source" JSON object that follows the formal JSON
-///     definition outlined by Microsoft.
-protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
-                                      lldb::SBAddress &address);
-
-/// Return true if the given line entry should be displayed as assembly.
-///
-/// \param[in] line_entry
-///     The LLDB line entry to check.
-///
-/// \param[in] stop_disassembly_display
-///     The value of the "stop-disassembly-display" setting.
-///
-/// \return
-///     True if the line entry should be displayed as assembly, false
-///     otherwise.
-bool ShouldDisplayAssemblySource(
-    const lldb::SBLineEntry &line_entry,
-    lldb::StopDisassemblyType stop_disassembly_display);
-
 /// Create a "StackFrame" object for a LLDB frame object.
 ///
 /// This function will fill in the following keys in the returned
@@ -316,14 +292,15 @@ bool ShouldDisplayAssemblySource(
 ///     The LLDB format to use when populating out the "StackFrame"
 ///     object.
 ///
-/// \param[in] stop_disassembly_display
-///     The value of the "stop-disassembly-display" setting.
+/// \param[in] debugger
+///     The LLDB debugger to use when populating out the "StackFrame"
+///     object.
 ///
 /// \return
 ///     A "StackFrame" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
 llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
-                                   lldb::StopDisassemblyType);
+                                   lldb::SBDebugger &debugger);
 
 /// Create a "StackFrame" label object for a LLDB thread.
 ///
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index f5e21c96fe17f..b05b02d7092ea 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -317,6 +317,8 @@ struct Source {
   std::optional<PresentationHint> presentationHint;
 
   // unsupported keys: origin, sources, adapterData, checksums
+
+  bool IsAssemblySource() const { return sourceReference.value_or(0) != 0; }
 };
 bool fromJSON(const llvm::json::Value &, Source::PresentationHint &,
               llvm::json::Path);

>From a2f9a1faa08d63433f784cfbb42cdc8e3271e0f5 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Sun, 25 May 2025 21:18:40 +0200
Subject: [PATCH 2/8] apply source mapping when getting line entry from an
 address

---
 lldb/include/lldb/API/SBAddress.h             |  7 ++++++
 lldb/source/API/SBAddress.cpp                 | 22 ++++++++++++++++---
 lldb/source/Core/Module.cpp                   |  3 +++
 lldb/tools/lldb-dap/Breakpoint.cpp            |  2 +-
 .../Handler/DisassembleRequestHandler.cpp     | 22 +++++++++----------
 .../Handler/LocationsRequestHandler.cpp       |  5 +++--
 .../Handler/StackTraceRequestHandler.cpp      |  3 +--
 lldb/tools/lldb-dap/JSONUtils.cpp             | 22 +++++++++++--------
 lldb/tools/lldb-dap/JSONUtils.h               | 15 +++++--------
 lldb/tools/lldb-dap/LLDBUtils.cpp             |  7 ++++++
 lldb/tools/lldb-dap/LLDBUtils.h               | 14 ++++++++++++
 11 files changed, 84 insertions(+), 38 deletions(-)

diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h
index 430dad4862dbf..c61f02702f1ca 100644
--- a/lldb/include/lldb/API/SBAddress.h
+++ b/lldb/include/lldb/API/SBAddress.h
@@ -11,6 +11,7 @@
 
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBModule.h"
+#include "lldb/API/SBTarget.h"
 
 namespace lldb {
 
@@ -58,6 +59,9 @@ class LLDB_API SBAddress {
   // "lldb::SBAddress SBTarget::ResolveLoadAddress (...)".
   lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope);
 
+  lldb::SBSymbolContext GetSymbolContext(const SBTarget &target,
+                                         uint32_t resolve_scope);
+
   // The following functions grab individual objects for a given address and
   // are less efficient if you want more than one symbol related objects. Use
   // one of the following when you want multiple debug symbol related objects
@@ -122,6 +126,9 @@ class LLDB_API SBAddress {
 
   void SetAddress(const lldb_private::Address &address);
 
+  void CalculateSymbolContext(lldb_private::SymbolContext &sc,
+                              uint32_t resolve_scope);
+
 private:
   std::unique_ptr<lldb_private::Address> m_opaque_up;
 };
diff --git a/lldb/source/API/SBAddress.cpp b/lldb/source/API/SBAddress.cpp
index e519f0bcc83c6..b6b9e238d3cbf 100644
--- a/lldb/source/API/SBAddress.cpp
+++ b/lldb/source/API/SBAddress.cpp
@@ -213,9 +213,18 @@ SBSymbolContext SBAddress::GetSymbolContext(uint32_t resolve_scope) {
   LLDB_INSTRUMENT_VA(this, resolve_scope);
 
   SBSymbolContext sb_sc;
-  SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
-  if (m_opaque_up->IsValid())
-    m_opaque_up->CalculateSymbolContext(&sb_sc.ref(), scope);
+  CalculateSymbolContext(sb_sc.ref(), resolve_scope);
+  return sb_sc;
+}
+
+SBSymbolContext SBAddress::GetSymbolContext(const SBTarget &target,
+                                            uint32_t resolve_scope) {
+  LLDB_INSTRUMENT_VA(this, target, resolve_scope);
+
+  SBSymbolContext sb_sc;
+  lldb_private::SymbolContext &sc = sb_sc.ref();
+  sc.target_sp = target.GetSP();
+  CalculateSymbolContext(sc, resolve_scope);
   return sb_sc;
 }
 
@@ -266,3 +275,10 @@ SBLineEntry SBAddress::GetLineEntry() {
   }
   return sb_line_entry;
 }
+
+void SBAddress::CalculateSymbolContext(lldb_private::SymbolContext &sc,
+                                       uint32_t resolve_scope) {
+  SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
+  if (m_opaque_up->IsValid())
+    m_opaque_up->CalculateSymbolContext(&sc, scope);
+}
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 625c14e4a2153..90997dada3666 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -483,6 +483,9 @@ uint32_t Module::ResolveSymbolContextForAddress(
       symfile->SetLoadDebugInfoEnabled();
       resolved_flags |=
           symfile->ResolveSymbolContext(so_addr, resolve_scope, sc);
+
+      if ((resolve_scope & eSymbolContextLineEntry) && sc.line_entry.IsValid())
+        sc.line_entry.ApplyFileMappings(sc.target_sp);
     }
 
     // Resolve the symbol if requested, but don't re-look it up if we've
diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 440d589b912fc..dea4dbadc0bda 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -64,7 +64,7 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
         "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));
     breakpoint.instructionReference = formatted_addr;
 
-    auto source = CreateSource(bp_addr, m_dap.debugger);
+    auto source = CreateSource(bp_addr, m_dap.target);
     if (!source.IsAssemblySource()) {
       auto line_entry = bp_addr.GetLineEntry();
       const auto line = line_entry.GetLine();
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 49e7c788a7fb3..fd0d5de7911fb 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -9,11 +9,11 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "JSONUtils.h"
+#include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
-#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBInstruction.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/lldb-types.h"
@@ -82,15 +82,12 @@ static lldb::SBAddress GetDisassembleStartAddress(lldb::SBTarget target,
       .GetAddress();
 }
 
-static DisassembledInstruction
-ConvertSBInstructionToDisassembledInstruction(lldb::SBDebugger &debugger,
-                                              lldb::SBInstruction &inst,
-                                              bool resolve_symbols) {
+static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
+    lldb::SBTarget &target, lldb::SBInstruction &inst, bool resolve_symbols) {
   if (!inst.IsValid())
     return GetInvalidInstruction();
 
-  lldb::SBTarget target = debugger.GetSelectedTarget();
-  lldb::SBAddress addr = inst.GetAddress();
+  auto addr = inst.GetAddress();
   const auto inst_addr = addr.GetLoadAddress(target);
 
   // FIXME: This is a workaround - this address might come from
@@ -143,9 +140,11 @@ ConvertSBInstructionToDisassembledInstruction(lldb::SBDebugger &debugger,
 
   disassembled_inst.instruction = std::move(instruction);
 
-  auto source = CreateSource(addr, debugger);
-  auto line_entry = addr.GetLineEntry();
+  auto source = CreateSource(addr, target);
+  auto line_entry = GetLineEntryForAddress(target, addr);
 
+  // If the line number is 0 then the entry represents a compiler generated
+  // location.
   if (!source.IsAssemblySource() && line_entry.IsValid() &&
       line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
       line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
@@ -159,7 +158,8 @@ ConvertSBInstructionToDisassembledInstruction(lldb::SBDebugger &debugger,
     if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER)
       disassembled_inst.column = column;
 
-    auto end_line_entry = line_entry.GetEndAddress().GetLineEntry();
+    lldb::SBAddress end_addr = line_entry.GetEndAddress();
+    auto end_line_entry = GetLineEntryForAddress(target, end_addr);
     if (end_line_entry.IsValid() &&
         end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) {
       const auto end_line = end_line_entry.GetLine();
@@ -238,7 +238,7 @@ DisassembleRequestHandler::Run(const DisassembleArguments &args) const {
       original_address_index = i;
 
     instructions.push_back(ConvertSBInstructionToDisassembledInstruction(
-        dap.debugger, inst, resolve_symbols));
+        dap.target, inst, resolve_symbols));
   }
 
   // Check if we miss instructions at the beginning.
diff --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
index 29f7356f46e42..39ad6949990c7 100644
--- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
@@ -9,6 +9,7 @@
 #include "DAP.h"
 #include "EventHelper.h"
 #include "JSONUtils.h"
+#include "LLDBUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBDeclaration.h"
@@ -126,7 +127,7 @@ void LocationsRequestHandler::operator()(
 
     lldb::addr_t raw_addr = variable.GetValueAsAddress();
     lldb::SBAddress addr = dap.target.ResolveLoadAddress(raw_addr);
-    lldb::SBLineEntry line_entry = addr.GetLineEntry();
+    lldb::SBLineEntry line_entry = GetLineEntryForAddress(dap.target, addr);
 
     if (!line_entry.IsValid()) {
       response["success"] = false;
@@ -135,7 +136,7 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source", CreateSource(addr, dap.debugger));
+    body.try_emplace("source", CreateSource(line_entry.GetFileSpec()));
     if (int line = line_entry.GetLine())
       body.try_emplace("line", line);
     if (int column = line_entry.GetColumn())
diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
index 1a4e87f8035ec..4ea4cd1e517d4 100644
--- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp
@@ -69,8 +69,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread,
       break;
     }
 
-    stack_frames.emplace_back(
-        CreateStackFrame(frame, frame_format, dap.debugger));
+    stack_frames.emplace_back(CreateStackFrame(frame, frame_format));
   }
 
   if (include_all && reached_end_of_stack) {
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 318f493f26e2f..e0c6e19863896 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -12,6 +12,7 @@
 #include "LLDBUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
+#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBDeclaration.h"
 #include "lldb/API/SBEnvironment.h"
 #include "lldb/API/SBError.h"
@@ -571,14 +572,16 @@ protocol::Source CreateSource(const lldb::SBFileSpec &file) {
   return source;
 }
 
-protocol::Source CreateSource(lldb::SBAddress address,
-                              lldb::SBDebugger &debugger) {
+protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) {
+  lldb::SBDebugger debugger = target.GetDebugger();
   lldb::StopDisassemblyType stop_disassembly_display =
       GetStopDisassemblyDisplay(debugger);
-  if (!ShouldDisplayAssemblySource(address, stop_disassembly_display))
-    return CreateSource(address.GetLineEntry().GetFileSpec());
+  if (!ShouldDisplayAssemblySource(address, stop_disassembly_display)) {
+    lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address);
+    return CreateSource(line_entry.GetFileSpec());
+  }
 
-  return CreateAssemblySource(debugger.GetSelectedTarget(), address);
+  return CreateAssemblySource(target, address);
 }
 
 protocol::Source CreateSource(llvm::StringRef source_path) {
@@ -650,8 +653,8 @@ protocol::Source CreateSource(llvm::StringRef source_path) {
 //   },
 //   "required": [ "id", "name", "line", "column" ]
 // }
-llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
-                                   lldb::SBDebugger &debugger) {
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
+                                   lldb::SBFormat &format) {
   llvm::json::Object object;
   int64_t frame_id = MakeDAPFrameID(frame);
   object.try_emplace("id", frame_id);
@@ -679,9 +682,10 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
 
   EmplaceSafeString(object, "name", frame_name);
 
-  auto source = CreateSource(frame.GetPCAddress(), debugger);
+  auto target = frame.GetThread().GetProcess().GetTarget();
+  auto source = CreateSource(frame.GetPCAddress(), target);
   if (!source.IsAssemblySource()) {
-    // This is a normal source with valid line entry.
+    // This is a normal source with a valid line entry.
     auto line_entry = frame.GetLineEntry();
     object.try_emplace("line", line_entry.GetLine());
     auto column = line_entry.GetColumn();
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 74866cdf32840..3f9b3162ad027 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -255,14 +255,13 @@ protocol::Source CreateSource(const lldb::SBFileSpec &file);
 /// \param[in] address
 ///     The address to use when populating out the "Source" object.
 ///
-/// \param[in] debugger
-///     The debugger, used to get relevant settings.
+/// \param[in] target
+///     The target that has the address.
 ///
 /// \return
 ///     A "Source" JSON object that follows the formal JSON
 ///     definition outlined by Microsoft.
-protocol::Source CreateSource(lldb::SBAddress address,
-                              lldb::SBDebugger &debugger);
+protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target);
 
 /// Create a "Source" object for a given source path.
 ///
@@ -292,15 +291,11 @@ protocol::Source CreateSource(llvm::StringRef source_path);
 ///     The LLDB format to use when populating out the "StackFrame"
 ///     object.
 ///
-/// \param[in] debugger
-///     The LLDB debugger to use when populating out the "StackFrame"
-///     object.
-///
 /// \return
 ///     A "StackFrame" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, lldb::SBFormat &format,
-                                   lldb::SBDebugger &debugger);
+llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
+                                   lldb::SBFormat &format);
 
 /// Create a "StackFrame" label object for a LLDB thread.
 ///
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index fe0bcda19b4cd..eb23a89be78da 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -252,4 +252,11 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) {
   return path;
 }
 
+lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
+                                         lldb::SBAddress &address) {
+  lldb::SBSymbolContext sc =
+      address.GetSymbolContext(target, lldb::eSymbolContextLineEntry);
+  return sc.GetLineEntry();
+}
+
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index 7fdf4b859ee61..74c10befdca67 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -14,6 +14,8 @@
 #include "lldb/API/SBEnvironment.h"
 #include "lldb/API/SBError.h"
 #include "lldb/API/SBFileSpec.h"
+#include "lldb/API/SBLineEntry.h"
+#include "lldb/API/SBTarget.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
@@ -171,6 +173,18 @@ GetEnvironmentFromArguments(const llvm::json::Object &arguments);
 ///     The file path as a string.
 std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec);
 
+/// Gets the line entry for a given address.
+/// \param[in] target
+///     The target that has the address.
+///
+/// \param[in] address
+///     The address for which to get the line entry.
+///
+/// \return
+///     The line entry for the given address.
+lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
+                                         lldb::SBAddress &address);
+
 /// Helper for sending telemetry to lldb server, if client-telemetry is enabled.
 class TelemetryDispatcher {
 public:

>From e649d583f4ee39e0d4f3216ee452397ab9d9abb3 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Wed, 28 May 2025 08:57:55 +0200
Subject: [PATCH 3/8] remove dead CreateSource version, move IsAssemblySource
 to ProtocolUtils.cpp

---
 lldb/tools/lldb-dap/Breakpoint.cpp            |  3 ++-
 lldb/tools/lldb-dap/CMakeLists.txt            |  1 +
 .../Handler/DisassembleRequestHandler.cpp     |  3 ++-
 lldb/tools/lldb-dap/JSONUtils.cpp             | 11 ++-------
 lldb/tools/lldb-dap/JSONUtils.h               | 10 --------
 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h  |  2 --
 .../tools/lldb-dap/Protocol/ProtocolUtils.cpp | 17 +++++++++++++
 lldb/tools/lldb-dap/Protocol/ProtocolUtils.h  | 24 +++++++++++++++++++
 8 files changed, 48 insertions(+), 23 deletions(-)
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
 create mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolUtils.h

diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index dea4dbadc0bda..ef9333713e940 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -9,6 +9,7 @@
 #include "Breakpoint.h"
 #include "DAP.h"
 #include "JSONUtils.h"
+#include "Protocol/ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBBreakpointLocation.h"
 #include "lldb/API/SBLineEntry.h"
@@ -65,7 +66,7 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
     breakpoint.instructionReference = formatted_addr;
 
     auto source = CreateSource(bp_addr, m_dap.target);
-    if (!source.IsAssemblySource()) {
+    if (!IsAssemblySource(source)) {
       auto line_entry = bp_addr.GetLineEntry();
       const auto line = line_entry.GetLine();
       if (line != LLDB_INVALID_LINE_NUMBER)
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 490aa4710af1a..401e0672b5375 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -68,6 +68,7 @@ add_lldb_library(lldbDAP
   Protocol/ProtocolBase.cpp
   Protocol/ProtocolTypes.cpp
   Protocol/ProtocolRequests.cpp
+  Protocol/ProtocolUtils.cpp
 
   LINK_LIBS
     liblldb
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index fd0d5de7911fb..abde452b3d1d3 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -12,6 +12,7 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
+#include "Protocol/ProtocolUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBInstruction.h"
@@ -145,7 +146,7 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
 
   // If the line number is 0 then the entry represents a compiler generated
   // location.
-  if (!source.IsAssemblySource() && line_entry.IsValid() &&
+  if (!IsAssemblySource(source) && line_entry.IsValid() &&
       line_entry.GetStartAddress() == addr && line_entry.IsValid() &&
       line_entry.GetFileSpec().IsValid() && line_entry.GetLine() != 0) {
 
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index e0c6e19863896..26bc13ef6759d 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -10,6 +10,7 @@
 #include "DAP.h"
 #include "ExceptionBreakpoint.h"
 #include "LLDBUtils.h"
+#include "Protocol/ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
 #include "lldb/API/SBDebugger.h"
@@ -584,14 +585,6 @@ protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) {
   return CreateAssemblySource(target, address);
 }
 
-protocol::Source CreateSource(llvm::StringRef source_path) {
-  protocol::Source source;
-  llvm::StringRef name = llvm::sys::path::filename(source_path);
-  source.name = name;
-  source.path = source_path;
-  return source;
-}
-
 // "StackFrame": {
 //   "type": "object",
 //   "description": "A Stackframe contains the source location.",
@@ -684,7 +677,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
 
   auto target = frame.GetThread().GetProcess().GetTarget();
   auto source = CreateSource(frame.GetPCAddress(), target);
-  if (!source.IsAssemblySource()) {
+  if (!IsAssemblySource(source)) {
     // This is a normal source with a valid line entry.
     auto line_entry = frame.GetLineEntry();
     object.try_emplace("line", line_entry.GetLine());
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index 3f9b3162ad027..f2a7c20c4e711 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -263,16 +263,6 @@ protocol::Source CreateSource(const lldb::SBFileSpec &file);
 ///     definition outlined by Microsoft.
 protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target);
 
-/// Create a "Source" object for a given source path.
-///
-/// \param[in] source_path
-///     The path to the source to use when creating the "Source" object.
-///
-/// \return
-///     A "Source" JSON object that follows the formal JSON
-///     definition outlined by Microsoft.
-protocol::Source CreateSource(llvm::StringRef source_path);
-
 /// Create a "StackFrame" object for a LLDB frame object.
 ///
 /// This function will fill in the following keys in the returned
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index b05b02d7092ea..f5e21c96fe17f 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -317,8 +317,6 @@ struct Source {
   std::optional<PresentationHint> presentationHint;
 
   // unsupported keys: origin, sources, adapterData, checksums
-
-  bool IsAssemblySource() const { return sourceReference.value_or(0) != 0; }
 };
 bool fromJSON(const llvm::json::Value &, Source::PresentationHint &,
               llvm::json::Path);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
new file mode 100644
index 0000000000000..63f16a1a927f3
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
@@ -0,0 +1,17 @@
+//===-- ProtocolUtils.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Protocol/ProtocolUtils.h"
+
+namespace lldb_dap::protocol {
+
+bool IsAssemblySource(const protocol::Source &source) {
+  return source.sourceReference.value_or(0) != 0;
+}
+
+} // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
new file mode 100644
index 0000000000000..a78a0a9ca392b
--- /dev/null
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
@@ -0,0 +1,24 @@
+//===-- ProtocolUtils.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 Utility function for protocol objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_UTILS_H
+#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_UTILS_H
+
+#include "Protocol/ProtocolTypes.h"
+
+namespace lldb_dap::protocol {
+
+bool IsAssemblySource(const protocol::Source &source);
+
+} // namespace lldb_dap::protocol
+
+#endif

>From 50c19ba6369b5ed2da4283bef9a0199c45d5a0b4 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Wed, 28 May 2025 21:51:42 +0200
Subject: [PATCH 4/8] add small GetSymbolContext comment

---
 lldb/include/lldb/API/SBAddress.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h
index c61f02702f1ca..6a1b9b9d40a50 100644
--- a/lldb/include/lldb/API/SBAddress.h
+++ b/lldb/include/lldb/API/SBAddress.h
@@ -59,6 +59,9 @@ class LLDB_API SBAddress {
   // "lldb::SBAddress SBTarget::ResolveLoadAddress (...)".
   lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope);
 
+  /// Same as the previous function, but uses the given target in the symbol
+  /// context. This can help to resolve things that require the target,
+  // for example it's necessary in order to apply source map on SBLineEntry.
   lldb::SBSymbolContext GetSymbolContext(const SBTarget &target,
                                          uint32_t resolve_scope);
 

>From e44a0e33fdb37480d73a9ad8b21f72869ae2743b Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Thu, 29 May 2025 23:55:12 +0200
Subject: [PATCH 5/8] use existing SBTarget::ResolveSymbolContextForAddress
 instead of adding new API

---
 lldb/include/lldb/API/SBAddress.h | 10 ----------
 lldb/source/API/SBAddress.cpp     | 22 +++-------------------
 lldb/source/API/SBTarget.cpp      | 11 +++++++----
 lldb/tools/lldb-dap/LLDBUtils.cpp |  2 +-
 4 files changed, 11 insertions(+), 34 deletions(-)

diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h
index 6a1b9b9d40a50..430dad4862dbf 100644
--- a/lldb/include/lldb/API/SBAddress.h
+++ b/lldb/include/lldb/API/SBAddress.h
@@ -11,7 +11,6 @@
 
 #include "lldb/API/SBDefines.h"
 #include "lldb/API/SBModule.h"
-#include "lldb/API/SBTarget.h"
 
 namespace lldb {
 
@@ -59,12 +58,6 @@ class LLDB_API SBAddress {
   // "lldb::SBAddress SBTarget::ResolveLoadAddress (...)".
   lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope);
 
-  /// Same as the previous function, but uses the given target in the symbol
-  /// context. This can help to resolve things that require the target,
-  // for example it's necessary in order to apply source map on SBLineEntry.
-  lldb::SBSymbolContext GetSymbolContext(const SBTarget &target,
-                                         uint32_t resolve_scope);
-
   // The following functions grab individual objects for a given address and
   // are less efficient if you want more than one symbol related objects. Use
   // one of the following when you want multiple debug symbol related objects
@@ -129,9 +122,6 @@ class LLDB_API SBAddress {
 
   void SetAddress(const lldb_private::Address &address);
 
-  void CalculateSymbolContext(lldb_private::SymbolContext &sc,
-                              uint32_t resolve_scope);
-
 private:
   std::unique_ptr<lldb_private::Address> m_opaque_up;
 };
diff --git a/lldb/source/API/SBAddress.cpp b/lldb/source/API/SBAddress.cpp
index b6b9e238d3cbf..e519f0bcc83c6 100644
--- a/lldb/source/API/SBAddress.cpp
+++ b/lldb/source/API/SBAddress.cpp
@@ -213,18 +213,9 @@ SBSymbolContext SBAddress::GetSymbolContext(uint32_t resolve_scope) {
   LLDB_INSTRUMENT_VA(this, resolve_scope);
 
   SBSymbolContext sb_sc;
-  CalculateSymbolContext(sb_sc.ref(), resolve_scope);
-  return sb_sc;
-}
-
-SBSymbolContext SBAddress::GetSymbolContext(const SBTarget &target,
-                                            uint32_t resolve_scope) {
-  LLDB_INSTRUMENT_VA(this, target, resolve_scope);
-
-  SBSymbolContext sb_sc;
-  lldb_private::SymbolContext &sc = sb_sc.ref();
-  sc.target_sp = target.GetSP();
-  CalculateSymbolContext(sc, resolve_scope);
+  SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
+  if (m_opaque_up->IsValid())
+    m_opaque_up->CalculateSymbolContext(&sb_sc.ref(), scope);
   return sb_sc;
 }
 
@@ -275,10 +266,3 @@ SBLineEntry SBAddress::GetLineEntry() {
   }
   return sb_line_entry;
 }
-
-void SBAddress::CalculateSymbolContext(lldb_private::SymbolContext &sc,
-                                       uint32_t resolve_scope) {
-  SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
-  if (m_opaque_up->IsValid())
-    m_opaque_up->CalculateSymbolContext(&sc, scope);
-}
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 813e8f2c6ec00..f46462089cffe 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -636,14 +636,17 @@ SBTarget::ResolveSymbolContextForAddress(const SBAddress &addr,
                                          uint32_t resolve_scope) {
   LLDB_INSTRUMENT_VA(this, addr, resolve_scope);
 
-  SBSymbolContext sc;
+  SBSymbolContext sb_sc;
   SymbolContextItem scope = static_cast<SymbolContextItem>(resolve_scope);
   if (addr.IsValid()) {
-    if (TargetSP target_sp = GetSP())
+    if (TargetSP target_sp = GetSP()) {
+      lldb_private::SymbolContext &sc = sb_sc.ref();
+      sc.target_sp = target_sp;
       target_sp->GetImages().ResolveSymbolContextForAddress(addr.ref(), scope,
-                                                            sc.ref());
+                                                            sc);
+    }
   }
-  return sc;
+  return sb_sc;
 }
 
 size_t SBTarget::ReadMemory(const SBAddress addr, void *buf, size_t size,
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index eb23a89be78da..bcd3308ffbccf 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -255,7 +255,7 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) {
 lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
                                          lldb::SBAddress &address) {
   lldb::SBSymbolContext sc =
-      address.GetSymbolContext(target, lldb::eSymbolContextLineEntry);
+      target.ResolveSymbolContextForAddress(address, lldb::eSymbolContextLineEntry);
   return sc.GetLineEntry();
 }
 

>From 19be799098d1af078241fafc34d2c50e0e8af2f2 Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Fri, 30 May 2025 00:05:49 +0200
Subject: [PATCH 6/8] format

---
 lldb/tools/lldb-dap/LLDBUtils.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index bcd3308ffbccf..3d3fc433a946b 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -254,8 +254,8 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) {
 
 lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
                                          lldb::SBAddress &address) {
-  lldb::SBSymbolContext sc =
-      target.ResolveSymbolContextForAddress(address, lldb::eSymbolContextLineEntry);
+  lldb::SBSymbolContext sc = target.ResolveSymbolContextForAddress(
+      address, lldb::eSymbolContextLineEntry);
   return sc.GetLineEntry();
 }
 

>From 0527e48266c7b1eab24335881d19799afc86dbfc Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Fri, 30 May 2025 21:55:52 +0200
Subject: [PATCH 7/8] move CreaetSource function to ProtocolUtils instead of
 JSONUtils

---
 lldb/tools/lldb-dap/Breakpoint.cpp            |  3 +-
 .../Handler/DisassembleRequestHandler.cpp     |  5 +-
 .../Handler/LocationsRequestHandler.cpp       |  6 +-
 lldb/tools/lldb-dap/JSONUtils.cpp             | 98 +------------------
 lldb/tools/lldb-dap/JSONUtils.h               | 27 -----
 .../tools/lldb-dap/Protocol/ProtocolUtils.cpp | 98 +++++++++++++++++++
 lldb/tools/lldb-dap/Protocol/ProtocolUtils.h  | 29 ++++++
 7 files changed, 137 insertions(+), 129 deletions(-)

diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index ef9333713e940..1ee4805ec2c8a 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -8,7 +8,6 @@
 
 #include "Breakpoint.h"
 #include "DAP.h"
-#include "JSONUtils.h"
 #include "Protocol/ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBBreakpointLocation.h"
@@ -65,7 +64,7 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
         "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));
     breakpoint.instructionReference = formatted_addr;
 
-    auto source = CreateSource(bp_addr, m_dap.target);
+    auto source = protocol::CreateSource(bp_addr, m_dap.target);
     if (!IsAssemblySource(source)) {
       auto line_entry = bp_addr.GetLineEntry();
       const auto line = line_entry.GetLine();
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index abde452b3d1d3..5291c3074dfcb 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -16,6 +16,7 @@
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBInstruction.h"
+#include "lldb/API/SBLineEntry.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/lldb-types.h"
 #include "llvm/ADT/StringExtras.h"
@@ -141,8 +142,8 @@ static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction(
 
   disassembled_inst.instruction = std::move(instruction);
 
-  auto source = CreateSource(addr, target);
-  auto line_entry = GetLineEntryForAddress(target, addr);
+  protocol::Source source = CreateSource(addr, target);
+  lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, addr);
 
   // If the line number is 0 then the entry represents a compiler generated
   // location.
diff --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
index 39ad6949990c7..2b2762f7580f4 100644
--- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
@@ -10,6 +10,7 @@
 #include "EventHelper.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
+#include "Protocol/ProtocolUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBDeclaration.h"
@@ -136,7 +137,8 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source", CreateSource(line_entry.GetFileSpec()));
+    body.try_emplace("source",
+                     protocol::CreateSource(line_entry.GetFileSpec()));
     if (int line = line_entry.GetLine())
       body.try_emplace("line", line);
     if (int column = line_entry.GetColumn())
@@ -151,7 +153,7 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source", CreateSource(decl.GetFileSpec()));
+    body.try_emplace("source", protocol::CreateSource(decl.GetFileSpec()));
     if (int line = decl.GetLine())
       body.try_emplace("line", line);
     if (int column = decl.GetColumn())
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 26bc13ef6759d..18b8a157847ee 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -13,7 +13,6 @@
 #include "Protocol/ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
-#include "lldb/API/SBDebugger.h"
 #include "lldb/API/SBDeclaration.h"
 #include "lldb/API/SBEnvironment.h"
 #include "lldb/API/SBError.h"
@@ -492,99 +491,6 @@ CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) {
   return filter;
 }
 
-static std::string GetLoadAddressString(const lldb::addr_t addr) {
-  std::string result;
-  llvm::raw_string_ostream os(result);
-  os << llvm::format_hex(addr, 18);
-  return result;
-}
-
-static bool ShouldDisplayAssemblySource(
-    lldb::SBAddress address,
-    lldb::StopDisassemblyType stop_disassembly_display) {
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever)
-    return false;
-
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways)
-    return true;
-
-  // A line entry of 0 indicates the line is compiler generated i.e. no source
-  // file is associated with the frame.
-  auto line_entry = address.GetLineEntry();
-  auto file_spec = line_entry.GetFileSpec();
-  if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
-      line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
-    return true;
-
-  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource &&
-      !file_spec.Exists()) {
-    return true;
-  }
-
-  return false;
-}
-
-static protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
-                                             lldb::SBAddress address) {
-  protocol::Source source;
-
-  auto symbol = address.GetSymbol();
-  std::string name;
-  if (symbol.IsValid()) {
-    source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target);
-    name = symbol.GetName();
-  } else {
-    const auto load_addr = address.GetLoadAddress(target);
-    source.sourceReference = load_addr;
-    name = GetLoadAddressString(load_addr);
-  }
-
-  lldb::SBModule module = address.GetModule();
-  if (module.IsValid()) {
-    lldb::SBFileSpec file_spec = module.GetFileSpec();
-    if (file_spec.IsValid()) {
-      std::string path = GetSBFileSpecPath(file_spec);
-      if (!path.empty())
-        source.path = path + '`' + name;
-    }
-  }
-
-  source.name = std::move(name);
-
-  // Mark the source as deemphasized since users will only be able to view
-  // assembly for these frames.
-  source.presentationHint =
-      protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize;
-
-  return source;
-}
-
-protocol::Source CreateSource(const lldb::SBFileSpec &file) {
-  protocol::Source source;
-  if (file.IsValid()) {
-    const char *name = file.GetFilename();
-    if (name)
-      source.name = name;
-    char path[PATH_MAX] = "";
-    if (file.GetPath(path, sizeof(path)) &&
-        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
-      source.path = path;
-  }
-  return source;
-}
-
-protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) {
-  lldb::SBDebugger debugger = target.GetDebugger();
-  lldb::StopDisassemblyType stop_disassembly_display =
-      GetStopDisassemblyDisplay(debugger);
-  if (!ShouldDisplayAssemblySource(address, stop_disassembly_display)) {
-    lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address);
-    return CreateSource(line_entry.GetFileSpec());
-  }
-
-  return CreateAssemblySource(target, address);
-}
-
 // "StackFrame": {
 //   "type": "object",
 //   "description": "A Stackframe contains the source location.",
@@ -666,7 +572,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
   if (frame_name.empty()) {
     // If the function name is unavailable, display the pc address as a 16-digit
     // hex string, e.g. "0x0000000000012345"
-    frame_name = GetLoadAddressString(frame.GetPC());
+    frame_name = protocol::GetLoadAddressString(frame.GetPC());
   }
 
   // We only include `[opt]` if a custom frame format is not specified.
@@ -676,7 +582,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
   EmplaceSafeString(object, "name", frame_name);
 
   auto target = frame.GetThread().GetProcess().GetTarget();
-  auto source = CreateSource(frame.GetPCAddress(), target);
+  auto source = protocol::CreateSource(frame.GetPCAddress(), target);
   if (!IsAssemblySource(source)) {
     // This is a normal source with a valid line entry.
     auto line_entry = frame.GetLineEntry();
diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h
index f2a7c20c4e711..08699a94bbd87 100644
--- a/lldb/tools/lldb-dap/JSONUtils.h
+++ b/lldb/tools/lldb-dap/JSONUtils.h
@@ -11,12 +11,8 @@
 
 #include "DAPForward.h"
 #include "Protocol/ProtocolTypes.h"
-#include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
-#include "lldb/API/SBDebugger.h"
-#include "lldb/API/SBFileSpec.h"
 #include "lldb/API/SBFormat.h"
-#include "lldb/API/SBLineEntry.h"
 #include "lldb/API/SBType.h"
 #include "lldb/API/SBValue.h"
 #include "lldb/lldb-types.h"
@@ -240,29 +236,6 @@ llvm::json::Object CreateEventObject(const llvm::StringRef event_name);
 protocol::ExceptionBreakpointsFilter
 CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp);
 
-/// Create a "Source" JSON object as described in the debug adapter definition.
-///
-/// \param[in] file
-///     The SBFileSpec to use when populating out the "Source" object
-///
-/// \return
-///     A "Source" JSON object that follows the formal JSON
-///     definition outlined by Microsoft.
-protocol::Source CreateSource(const lldb::SBFileSpec &file);
-
-/// Create a "Source" JSON object as described in the debug adapter definition.
-///
-/// \param[in] address
-///     The address to use when populating out the "Source" object.
-///
-/// \param[in] target
-///     The target that has the address.
-///
-/// \return
-///     A "Source" JSON object that follows the formal JSON
-///     definition outlined by Microsoft.
-protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target);
-
 /// Create a "StackFrame" object for a LLDB frame object.
 ///
 /// This function will fill in the following keys in the returned
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
index 63f16a1a927f3..bcaf666f97eec 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
@@ -7,11 +7,109 @@
 //===----------------------------------------------------------------------===//
 
 #include "Protocol/ProtocolUtils.h"
+#include "LLDBUtils.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBTarget.h"
 
 namespace lldb_dap::protocol {
 
+static bool ShouldDisplayAssemblySource(
+    lldb::SBAddress address,
+    lldb::StopDisassemblyType stop_disassembly_display) {
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever)
+    return false;
+
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways)
+    return true;
+
+  // A line entry of 0 indicates the line is compiler generated i.e. no source
+  // file is associated with the frame.
+  auto line_entry = address.GetLineEntry();
+  auto file_spec = line_entry.GetFileSpec();
+  if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
+      line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
+    return true;
+
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource &&
+      !file_spec.Exists()) {
+    return true;
+  }
+
+  return false;
+}
+
+static protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
+                                             lldb::SBAddress address) {
+  protocol::Source source;
+
+  auto symbol = address.GetSymbol();
+  std::string name;
+  if (symbol.IsValid()) {
+    source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target);
+    name = symbol.GetName();
+  } else {
+    const auto load_addr = address.GetLoadAddress(target);
+    source.sourceReference = load_addr;
+    name = GetLoadAddressString(load_addr);
+  }
+
+  lldb::SBModule module = address.GetModule();
+  if (module.IsValid()) {
+    lldb::SBFileSpec file_spec = module.GetFileSpec();
+    if (file_spec.IsValid()) {
+      std::string path = GetSBFileSpecPath(file_spec);
+      if (!path.empty())
+        source.path = path + '`' + name;
+    }
+  }
+
+  source.name = std::move(name);
+
+  // Mark the source as deemphasized since users will only be able to view
+  // assembly for these frames.
+  source.presentationHint =
+      protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize;
+
+  return source;
+}
+
+protocol::Source CreateSource(const lldb::SBFileSpec &file) {
+  protocol::Source source;
+  if (file.IsValid()) {
+    if (const char *name = file.GetFilename())
+      source.name = name;
+    char path[PATH_MAX] = "";
+    if (file.GetPath(path, sizeof(path)) &&
+        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
+      source.path = path;
+  }
+  return source;
+}
+
+protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) {
+  lldb::SBDebugger debugger = target.GetDebugger();
+  lldb::StopDisassemblyType stop_disassembly_display =
+      GetStopDisassemblyDisplay(debugger);
+  if (ShouldDisplayAssemblySource(address, stop_disassembly_display))
+    return CreateAssemblySource(target, address);
+
+  lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address);
+  return CreateSource(line_entry.GetFileSpec());
+}
+
 bool IsAssemblySource(const protocol::Source &source) {
+  // According to the specification, a source must have either `path` or
+  // `sourceReference` specified. We use `path` for sources with known source
+  // code, and `sourceReferences` when falling back to assembly.
   return source.sourceReference.value_or(0) != 0;
 }
 
+std::string GetLoadAddressString(const lldb::addr_t addr) {
+  std::string result;
+  llvm::raw_string_ostream os(result);
+  os << llvm::format_hex(addr, 18);
+  return result;
+}
+
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
index a78a0a9ca392b..c66d0f1f3a11c 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
@@ -15,10 +15,39 @@
 
 #include "Protocol/ProtocolTypes.h"
 
+#include "lldb/API/SBAddress.h"
+
 namespace lldb_dap::protocol {
 
+/// Create a "Source" JSON object as described in the debug adapter definition.
+///
+/// \param[in] file
+///     The SBFileSpec to use when populating out the "Source" object
+///
+/// \return
+///     A "Source" JSON object that follows the formal JSON
+///     definition outlined by Microsoft.
+protocol::Source CreateSource(const lldb::SBFileSpec &file);
+
+/// Create a "Source" JSON object as described in the debug adapter definition.
+///
+/// \param[in] address
+///     The address to use when populating out the "Source" object.
+///
+/// \param[in] target
+///     The target that has the address.
+///
+/// \return
+///     A "Source" JSON object that follows the formal JSON
+///     definition outlined by Microsoft.
+protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target);
+
+/// Checks if the given source is for assembly code.
 bool IsAssemblySource(const protocol::Source &source);
 
+/// Get the address as a 16-digit hex string, e.g. "0x0000000000012345"
+std::string GetLoadAddressString(const lldb::addr_t addr);
+
 } // namespace lldb_dap::protocol
 
 #endif

>From c0f1d3c165ab295aa357c5ca30d28f30b2717cfd Mon Sep 17 00:00:00 2001
From: Ely Ronnen <elyronnen at gmail.com>
Date: Fri, 30 May 2025 23:44:15 +0200
Subject: [PATCH 8/8] use reference, move ProtocolUtils.h

---
 lldb/tools/lldb-dap/Breakpoint.cpp            |   4 +-
 lldb/tools/lldb-dap/CMakeLists.txt            |   2 +-
 .../Handler/DisassembleRequestHandler.cpp     |   2 +-
 .../Handler/LocationsRequestHandler.cpp       |   7 +-
 lldb/tools/lldb-dap/JSONUtils.cpp             |   6 +-
 lldb/tools/lldb-dap/LLDBUtils.cpp             |   2 +-
 lldb/tools/lldb-dap/LLDBUtils.h               |   2 +-
 .../tools/lldb-dap/Protocol/ProtocolUtils.cpp |   7 +-
 lldb/tools/lldb-dap/ProtocolUtils.cpp         | 112 ++++++++++++++++++
 .../lldb-dap/{Protocol => }/ProtocolUtils.h   |   4 +-
 10 files changed, 128 insertions(+), 20 deletions(-)
 create mode 100644 lldb/tools/lldb-dap/ProtocolUtils.cpp
 rename lldb/tools/lldb-dap/{Protocol => }/ProtocolUtils.h (96%)

diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 1ee4805ec2c8a..ef5646c4c3d16 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -8,7 +8,7 @@
 
 #include "Breakpoint.h"
 #include "DAP.h"
-#include "Protocol/ProtocolUtils.h"
+#include "ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBBreakpointLocation.h"
 #include "lldb/API/SBLineEntry.h"
@@ -64,7 +64,7 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
         "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));
     breakpoint.instructionReference = formatted_addr;
 
-    auto source = protocol::CreateSource(bp_addr, m_dap.target);
+    auto source = CreateSource(bp_addr, m_dap.target);
     if (!IsAssemblySource(source)) {
       auto line_entry = bp_addr.GetLineEntry();
       const auto line = line_entry.GetLine();
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 401e0672b5375..40cba16c141f0 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -21,6 +21,7 @@ add_lldb_library(lldbDAP
   LLDBUtils.cpp
   OutputRedirector.cpp
   ProgressEvent.cpp
+  ProtocolUtils.cpp
   RunInTerminal.cpp
   SourceBreakpoint.cpp
   Transport.cpp
@@ -68,7 +69,6 @@ add_lldb_library(lldbDAP
   Protocol/ProtocolBase.cpp
   Protocol/ProtocolTypes.cpp
   Protocol/ProtocolRequests.cpp
-  Protocol/ProtocolUtils.cpp
 
   LINK_LIBS
     liblldb
diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
index 5291c3074dfcb..a76244ff74822 100644
--- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp
@@ -12,7 +12,7 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
-#include "Protocol/ProtocolUtils.h"
+#include "ProtocolUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBInstruction.h"
diff --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
index 2b2762f7580f4..804bdcd622a2b 100644
--- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp
@@ -10,7 +10,7 @@
 #include "EventHelper.h"
 #include "JSONUtils.h"
 #include "LLDBUtils.h"
-#include "Protocol/ProtocolUtils.h"
+#include "ProtocolUtils.h"
 #include "RequestHandler.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBDeclaration.h"
@@ -137,8 +137,7 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source",
-                     protocol::CreateSource(line_entry.GetFileSpec()));
+    body.try_emplace("source", CreateSource(line_entry.GetFileSpec()));
     if (int line = line_entry.GetLine())
       body.try_emplace("line", line);
     if (int column = line_entry.GetColumn())
@@ -153,7 +152,7 @@ void LocationsRequestHandler::operator()(
       return;
     }
 
-    body.try_emplace("source", protocol::CreateSource(decl.GetFileSpec()));
+    body.try_emplace("source", CreateSource(decl.GetFileSpec()));
     if (int line = decl.GetLine())
       body.try_emplace("line", line);
     if (int column = decl.GetColumn())
diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp
index 18b8a157847ee..78809aa45830a 100644
--- a/lldb/tools/lldb-dap/JSONUtils.cpp
+++ b/lldb/tools/lldb-dap/JSONUtils.cpp
@@ -10,7 +10,7 @@
 #include "DAP.h"
 #include "ExceptionBreakpoint.h"
 #include "LLDBUtils.h"
-#include "Protocol/ProtocolUtils.h"
+#include "ProtocolUtils.h"
 #include "lldb/API/SBAddress.h"
 #include "lldb/API/SBCompileUnit.h"
 #include "lldb/API/SBDeclaration.h"
@@ -572,7 +572,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
   if (frame_name.empty()) {
     // If the function name is unavailable, display the pc address as a 16-digit
     // hex string, e.g. "0x0000000000012345"
-    frame_name = protocol::GetLoadAddressString(frame.GetPC());
+    frame_name = GetLoadAddressString(frame.GetPC());
   }
 
   // We only include `[opt]` if a custom frame format is not specified.
@@ -582,7 +582,7 @@ llvm::json::Value CreateStackFrame(lldb::SBFrame &frame,
   EmplaceSafeString(object, "name", frame_name);
 
   auto target = frame.GetThread().GetProcess().GetTarget();
-  auto source = protocol::CreateSource(frame.GetPCAddress(), target);
+  auto source = CreateSource(frame.GetPCAddress(), target);
   if (!IsAssemblySource(source)) {
     // This is a normal source with a valid line entry.
     auto line_entry = frame.GetLineEntry();
diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp
index 3d3fc433a946b..4db6caa1af38b 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.cpp
+++ b/lldb/tools/lldb-dap/LLDBUtils.cpp
@@ -253,7 +253,7 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) {
 }
 
 lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
-                                         lldb::SBAddress &address) {
+                                         const lldb::SBAddress &address) {
   lldb::SBSymbolContext sc = target.ResolveSymbolContextForAddress(
       address, lldb::eSymbolContextLineEntry);
   return sc.GetLineEntry();
diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h
index 74c10befdca67..9db721a47ccf7 100644
--- a/lldb/tools/lldb-dap/LLDBUtils.h
+++ b/lldb/tools/lldb-dap/LLDBUtils.h
@@ -183,7 +183,7 @@ std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec);
 /// \return
 ///     The line entry for the given address.
 lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target,
-                                         lldb::SBAddress &address);
+                                         const lldb::SBAddress &address);
 
 /// Helper for sending telemetry to lldb server, if client-telemetry is enabled.
 class TelemetryDispatcher {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
index bcaf666f97eec..143c7416bfccd 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolUtils.cpp
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "Protocol/ProtocolUtils.h"
+#include "ProtocolUtils.h"
 #include "LLDBUtils.h"
 
 #include "lldb/API/SBDebugger.h"
@@ -106,10 +106,7 @@ bool IsAssemblySource(const protocol::Source &source) {
 }
 
 std::string GetLoadAddressString(const lldb::addr_t addr) {
-  std::string result;
-  llvm::raw_string_ostream os(result);
-  os << llvm::format_hex(addr, 18);
-  return result;
+  return "0x" + llvm::utohexstr(addr);
 }
 
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp
new file mode 100644
index 0000000000000..9a9f8ba47aa33
--- /dev/null
+++ b/lldb/tools/lldb-dap/ProtocolUtils.cpp
@@ -0,0 +1,112 @@
+//===-- ProtocolUtils.cpp -------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProtocolUtils.h"
+#include "LLDBUtils.h"
+
+#include "lldb/API/SBDebugger.h"
+#include "lldb/API/SBTarget.h"
+
+namespace lldb_dap {
+
+static bool ShouldDisplayAssemblySource(
+    lldb::SBAddress address,
+    lldb::StopDisassemblyType stop_disassembly_display) {
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever)
+    return false;
+
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways)
+    return true;
+
+  // A line entry of 0 indicates the line is compiler generated i.e. no source
+  // file is associated with the frame.
+  auto line_entry = address.GetLineEntry();
+  auto file_spec = line_entry.GetFileSpec();
+  if (!file_spec.IsValid() || line_entry.GetLine() == 0 ||
+      line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER)
+    return true;
+
+  if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource &&
+      !file_spec.Exists()) {
+    return true;
+  }
+
+  return false;
+}
+
+static protocol::Source CreateAssemblySource(const lldb::SBTarget &target,
+                                             lldb::SBAddress address) {
+  protocol::Source source;
+
+  auto symbol = address.GetSymbol();
+  std::string name;
+  if (symbol.IsValid()) {
+    source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target);
+    name = symbol.GetName();
+  } else {
+    const auto load_addr = address.GetLoadAddress(target);
+    source.sourceReference = load_addr;
+    name = GetLoadAddressString(load_addr);
+  }
+
+  lldb::SBModule module = address.GetModule();
+  if (module.IsValid()) {
+    lldb::SBFileSpec file_spec = module.GetFileSpec();
+    if (file_spec.IsValid()) {
+      std::string path = GetSBFileSpecPath(file_spec);
+      if (!path.empty())
+        source.path = path + '`' + name;
+    }
+  }
+
+  source.name = std::move(name);
+
+  // Mark the source as deemphasized since users will only be able to view
+  // assembly for these frames.
+  source.presentationHint =
+      protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize;
+
+  return source;
+}
+
+protocol::Source CreateSource(const lldb::SBFileSpec &file) {
+  protocol::Source source;
+  if (file.IsValid()) {
+    if (const char *name = file.GetFilename())
+      source.name = name;
+    char path[PATH_MAX] = "";
+    if (file.GetPath(path, sizeof(path)) &&
+        lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX))
+      source.path = path;
+  }
+  return source;
+}
+
+protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) {
+  lldb::SBDebugger debugger = target.GetDebugger();
+  lldb::StopDisassemblyType stop_disassembly_display =
+      GetStopDisassemblyDisplay(debugger);
+  if (ShouldDisplayAssemblySource(address, stop_disassembly_display))
+    return CreateAssemblySource(target, address);
+
+  lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address);
+  return CreateSource(line_entry.GetFileSpec());
+}
+
+bool IsAssemblySource(const protocol::Source &source) {
+  // According to the specification, a source must have either `path` or
+  // `sourceReference` specified. We use `path` for sources with known source
+  // code, and `sourceReferences` when falling back to assembly.
+  return source.sourceReference.value_or(0) != 0;
+}
+
+std::string GetLoadAddressString(const lldb::addr_t addr) {
+  return "0x" + llvm::utohexstr(addr);
+}
+
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h b/lldb/tools/lldb-dap/ProtocolUtils.h
similarity index 96%
rename from lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
rename to lldb/tools/lldb-dap/ProtocolUtils.h
index c66d0f1f3a11c..6e4f07d6e3470 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolUtils.h
+++ b/lldb/tools/lldb-dap/ProtocolUtils.h
@@ -17,7 +17,7 @@
 
 #include "lldb/API/SBAddress.h"
 
-namespace lldb_dap::protocol {
+namespace lldb_dap {
 
 /// Create a "Source" JSON object as described in the debug adapter definition.
 ///
@@ -48,6 +48,6 @@ bool IsAssemblySource(const protocol::Source &source);
 /// Get the address as a 16-digit hex string, e.g. "0x0000000000012345"
 std::string GetLoadAddressString(const lldb::addr_t addr);
 
-} // namespace lldb_dap::protocol
+} // namespace lldb_dap
 
 #endif



More information about the lldb-commits mailing list