Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[lldb-dap] assembly breakpoints #139969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
Loading
from

Conversation

eronnen
Copy link
Contributor

@eronnen eronnen commented May 14, 2025

  • Support assembly source breakpoints
  • Change sourceReference to be the load address for simplicity and consistency across threads/frames
Screencast.From.2025-05-17.23-57-30.webm

@eronnen eronnen changed the title Lldb dap assembly breakpoint [lldb-dap] assembly breakpoints May 14, 2025
@eronnen eronnen force-pushed the lldb-dap-assembly-breakpoint branch 2 times, most recently from 2263631 to 3807a12 Compare May 17, 2025 21:43
@eronnen eronnen force-pushed the lldb-dap-assembly-breakpoint branch from 0f2ed75 to f5fd76d Compare May 18, 2025 00:27
@eronnen eronnen marked this pull request as ready for review May 18, 2025 00:27
@eronnen eronnen requested a review from JDevlieghere as a code owner May 18, 2025 00:27
@eronnen eronnen requested a review from ashgti May 18, 2025 00:28
@llvmbot
Copy link
Member

llvmbot commented May 18, 2025

@llvm/pr-subscribers-lldb

Author: Ely Ronnen (eronnen)

Changes
  • Support assembly source breakpoints
  • Change sourceReference to be the load address for simplicity and consistency across threads/frames
Screencast.From.2025-05-17.23-57-30.webm

Patch is 29.52 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/139969.diff

19 Files Affected:

  • (modified) lldb/include/lldb/API/SBFileSpec.h (+3)
  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py (+7)
  • (modified) lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py (+10)
  • (modified) lldb/source/API/SBFileSpec.cpp (+8)
  • (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile (+3)
  • (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py (+42)
  • (added) lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c (+14)
  • (modified) lldb/tools/lldb-dap/Breakpoint.cpp (+26-7)
  • (modified) lldb/tools/lldb-dap/DAP.h (+5)
  • (modified) lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp (+51-17)
  • (modified) lldb/tools/lldb-dap/Handler/RequestHandler.h (+20)
  • (modified) lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp (+75-4)
  • (modified) lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp (+9-11)
  • (modified) lldb/tools/lldb-dap/JSONUtils.cpp (+54-21)
  • (modified) lldb/tools/lldb-dap/JSONUtils.h (+14)
  • (modified) lldb/tools/lldb-dap/SourceBreakpoint.cpp (+22)
  • (modified) lldb/tools/lldb-dap/SourceBreakpoint.h (+1)
  • (modified) lldb/tools/lldb-dap/package-lock.json (+2-2)
  • (modified) lldb/tools/lldb-dap/package.json (+4-1)
diff --git a/lldb/include/lldb/API/SBFileSpec.h b/lldb/include/lldb/API/SBFileSpec.h
index 36641843aabeb..303cb7d712cbf 100644
--- a/lldb/include/lldb/API/SBFileSpec.h
+++ b/lldb/include/lldb/API/SBFileSpec.h
@@ -10,6 +10,7 @@
 #define LLDB_API_SBFILESPEC_H
 
 #include "lldb/API/SBDefines.h"
+#include "lldb/API/SBStream.h"
 
 namespace lldb {
 
@@ -53,6 +54,8 @@ class LLDB_API SBFileSpec {
 
   uint32_t GetPath(char *dst_path, size_t dst_len) const;
 
+  bool GetPath(lldb::SBStream &dst_path) const;
+
   static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len);
 
   bool GetDescription(lldb::SBStream &description) const;
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 70fd0b0c419db..4a907a5e36901 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
@@ -955,6 +955,13 @@ def request_setBreakpoints(self, file_path, line_array, data=None):
         """
         (dir, base) = os.path.split(file_path)
         source_dict = {"name": base, "path": file_path}
+        return self.request_setBreakpoints_with_source(source_dict, line_array, data)
+
+    def request_setBreakpointsAssembly(self, sourceReference, line_array, data=None):
+        source_dict = {"sourceReference": sourceReference}
+        return self.request_setBreakpoints_with_source(source_dict, line_array, data)
+
+    def request_setBreakpoints_with_source(self, source_dict, line_array, data=None):
         args_dict = {
             "source": source_dict,
             "sourceModified": False,
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 afdc746ed0d0d..427f66a7da0c8 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
@@ -63,6 +63,16 @@ def set_source_breakpoints(self, source_path, lines, data=None):
         for breakpoint in breakpoints:
             breakpoint_ids.append("%i" % (breakpoint["id"]))
         return breakpoint_ids
+    
+    def set_source_breakpoints_assembly(self, source_reference, lines, data=None):
+        response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data)
+        if response is None:
+            return []
+        breakpoints = response["body"]["breakpoints"]
+        breakpoint_ids = []
+        for breakpoint in breakpoints:
+            breakpoint_ids.append("%i" % (breakpoint["id"]))
+        return breakpoint_ids
 
     def set_function_breakpoints(self, functions, condition=None, hitCondition=None):
         """Sets breakpoints by function name given an array of function names
diff --git a/lldb/source/API/SBFileSpec.cpp b/lldb/source/API/SBFileSpec.cpp
index a7df9afc4b8eb..cb44dac1d4fcc 100644
--- a/lldb/source/API/SBFileSpec.cpp
+++ b/lldb/source/API/SBFileSpec.cpp
@@ -19,6 +19,7 @@
 
 #include <cinttypes>
 #include <climits>
+#include <string>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -147,6 +148,13 @@ uint32_t SBFileSpec::GetPath(char *dst_path, size_t dst_len) const {
   return result;
 }
 
+bool SBFileSpec::GetPath(SBStream &dst_path) const {
+  LLDB_INSTRUMENT_VA(this, dst_path);
+
+  std::string path = m_opaque_up->GetPath();
+  return dst_path->PutCString(path.c_str()) > 0;
+}
+
 const lldb_private::FileSpec *SBFileSpec::operator->() const {
   return m_opaque_up.get();
 }
diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
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
new file mode 100644
index 0000000000000..ba9df3a18590b
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py
@@ -0,0 +1,42 @@
+"""
+Test lldb-dap setBreakpoints request
+"""
+
+
+import dap_server
+import shutil
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lldbdap_testcase
+import os
+
+
+class TestDAP_setBreakpointsAssembly(lldbdap_testcase.DAPTestCaseBase):
+    # @skipIfWindows
+    def test_functionality(self):
+        """Tests hitting assembly source breakpoints"""
+        program = self.getBuildArtifact("a.out")
+        self.build_and_launch(program)
+
+        self.dap_server.request_evaluate(
+            "`settings set stop-disassembly-display no-debuginfo", context="repl"
+        )
+
+        assmebly_func_breakpoints = self.set_function_breakpoints(["assembly_func"])
+        self.continue_to_breakpoints(assmebly_func_breakpoints)
+
+        assembly_func_frame = self.get_stackFrames()[0]
+        self.assertIn(
+            "sourceReference",
+            assembly_func_frame.get("source"),
+            "Expected assembly source frame",
+        )
+
+        line = assembly_func_frame["line"]
+
+        # Set an assembly breakpoint in the next line and check that it's hit
+        assembly_breakpoint_ids = self.set_source_breakpoints_assembly(
+            assembly_func_frame["source"]["sourceReference"], [line + 1]
+        )
+        self.continue_to_breakpoints(assembly_breakpoint_ids)
diff --git a/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c
new file mode 100644
index 0000000000000..350739006f903
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/breakpoint-assembly/main.c
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+__attribute__((nodebug)) int assembly_func(int n) {
+  n += 1;
+  n += 2;
+  n += 3;
+
+  return n;
+}
+
+int main(int argc, char const *argv[]) {
+  assembly_func(10);
+  return 0;
+}
diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp
index 26d633d1d172e..a54a34e0f936d 100644
--- a/lldb/tools/lldb-dap/Breakpoint.cpp
+++ b/lldb/tools/lldb-dap/Breakpoint.cpp
@@ -9,10 +9,12 @@
 #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>
@@ -63,14 +65,31 @@ protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {
     std::string formatted_addr =
         "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();
-    const auto line = line_entry.GetLine();
-    if (line != UINT32_MAX)
-      breakpoint.line = line;
-    const auto column = line_entry.GetColumn();
-    if (column != 0)
-      breakpoint.column = column;
-    breakpoint.source = CreateSource(line_entry);
+    if (!ShouldDisplayAssemblySource(line_entry, stop_disassembly_display)) {
+      const auto line = line_entry.GetLine();
+      if (line != UINT32_MAX)
+        breakpoint.line = line;
+      const auto column = line_entry.GetColumn();
+      if (column != 0)
+        breakpoint.column = column;
+      breakpoint.source = CreateSource(line_entry);
+    } else {
+      // Breakpoint made by assembly
+      auto symbol = bp_addr.GetSymbol();
+      if (symbol.IsValid()) {
+        breakpoint.line =
+            m_bp.GetTarget()
+                .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr)
+                .GetSize() +
+            1;
+
+        breakpoint.source = CreateAssemblySource(m_dap.target, bp_addr);
+      }
+    }
   }
 
   return breakpoint;
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 8f24c6cf82924..b0fe265b7bca1 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -169,6 +169,8 @@ struct DAP {
   Variables variables;
   lldb::SBBroadcaster broadcaster;
   llvm::StringMap<SourceBreakpointMap> source_breakpoints;
+  llvm::DenseMap<int64_t, llvm::DenseMap<uint32_t, SourceBreakpoint>>
+      assembly_breakpoints;
   FunctionBreakpointMap function_breakpoints;
   InstructionBreakpointMap instruction_breakpoints;
   std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints;
@@ -219,6 +221,9 @@ struct DAP {
   llvm::StringSet<> modules;
   /// @}
 
+  /// Number of lines of assembly code to show when no debug info is available.
+  uint32_t number_of_assembly_lines_for_nodebug = 32;
+
   /// Creates a new DAP sessions.
   ///
   /// \param[in] log
diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp
index 2ac886c3a5d2c..c4d658caeee2d 100644
--- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "DAP.h"
-#include "JSONUtils.h"
 #include "RequestHandler.h"
 #include <vector>
 
@@ -19,19 +18,50 @@ namespace lldb_dap {
 llvm::Expected<protocol::BreakpointLocationsResponseBody>
 BreakpointLocationsRequestHandler::Run(
     const protocol::BreakpointLocationsArguments &args) const {
-  std::string path = args.source.path.value_or("");
   uint32_t start_line = args.line;
   uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER);
   uint32_t end_line = args.endLine.value_or(start_line);
   uint32_t end_column =
       args.endColumn.value_or(std::numeric_limits<uint32_t>::max());
 
+  // Find all relevant lines & columns
+  llvm::SmallVector<std::pair<uint32_t, uint32_t>, 8> locations;
+  if (args.source.sourceReference) {
+    AddAssemblyBreakpointLocations(locations, *args.source.sourceReference,
+                                   start_line, end_line);
+  } else {
+    std::string path = args.source.path.value_or("");
+    AddSourceBreakpointLocations(locations, std::move(path), start_line,
+                                 start_column, end_line, end_column);
+  }
+
+  // The line entries are sorted by addresses, but we must return the list
+  // ordered by line / column position.
+  std::sort(locations.begin(), locations.end());
+  locations.erase(llvm::unique(locations), locations.end());
+
+  std::vector<protocol::BreakpointLocation> breakpoint_locations;
+  for (auto &l : locations) {
+    protocol::BreakpointLocation lc;
+    lc.line = l.first;
+    lc.column = l.second;
+    breakpoint_locations.push_back(std::move(lc));
+  }
+
+  return protocol::BreakpointLocationsResponseBody{
+      /*breakpoints=*/std::move(breakpoint_locations)};
+}
+
+template <unsigned N>
+void BreakpointLocationsRequestHandler::AddSourceBreakpointLocations(
+    llvm::SmallVector<std::pair<uint32_t, uint32_t>, N> &locations,
+    std::string path, uint32_t start_line, uint32_t start_column,
+    uint32_t end_line, uint32_t end_column) const {
+
   lldb::SBFileSpec file_spec(path.c_str(), true);
   lldb::SBSymbolContextList compile_units =
       dap.target.FindCompileUnits(file_spec);
 
-  // Find all relevant lines & columns
-  llvm::SmallVector<std::pair<uint32_t, uint32_t>, 8> locations;
   for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit;
        ++c_idx) {
     const lldb::SBCompileUnit &compile_unit =
@@ -71,22 +101,26 @@ BreakpointLocationsRequestHandler::Run(
       locations.emplace_back(line, column);
     }
   }
+}
 
-  // The line entries are sorted by addresses, but we must return the list
-  // ordered by line / column position.
-  std::sort(locations.begin(), locations.end());
-  locations.erase(llvm::unique(locations), locations.end());
+template <unsigned N>
+void BreakpointLocationsRequestHandler::AddAssemblyBreakpointLocations(
+    llvm::SmallVector<std::pair<uint32_t, uint32_t>, N> &locations,
+    int64_t sourceReference, uint32_t start_line, uint32_t end_line) const {
+  lldb::SBAddress address(sourceReference, dap.target);
+  if (!address.IsValid())
+    return;
 
-  std::vector<protocol::BreakpointLocation> breakpoint_locations;
-  for (auto &l : locations) {
-    protocol::BreakpointLocation lc;
-    lc.line = l.first;
-    lc.column = l.second;
-    breakpoint_locations.push_back(std::move(lc));
-  }
+  lldb::SBSymbol symbol = address.GetSymbol();
+  if (!symbol.IsValid())
+    return;
 
-  return protocol::BreakpointLocationsResponseBody{
-      /*breakpoints=*/std::move(breakpoint_locations)};
+  // start_line is relative to the symbol's start address
+  lldb::SBInstructionList insts = symbol.GetInstructions(dap.target);
+  for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1);
+       ++i) {
+    locations.emplace_back(i, 1);
+  }
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index e6bccfe12f402..80898d1ee5ef1 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -16,6 +16,7 @@
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/JSON.h"
@@ -232,6 +233,16 @@ class BreakpointLocationsRequestHandler
   }
   llvm::Expected<protocol::BreakpointLocationsResponseBody>
   Run(const protocol::BreakpointLocationsArguments &args) const override;
+
+  template <unsigned N>
+  void AddSourceBreakpointLocations(
+      llvm::SmallVector<std::pair<uint32_t, uint32_t>, N> &locations,
+      std::string path, uint32_t start_line, uint32_t start_column,
+      uint32_t end_line, uint32_t end_column) const;
+  template <unsigned N>
+  void AddAssemblyBreakpointLocations(
+      llvm::SmallVector<std::pair<uint32_t, uint32_t>, N> &locations,
+      int64_t sourceReference, uint32_t start_line, uint32_t end_line) const;
 };
 
 class CompletionsRequestHandler : public LegacyRequestHandler {
@@ -378,6 +389,15 @@ class SetBreakpointsRequestHandler
   }
   llvm::Expected<protocol::SetBreakpointsResponseBody>
   Run(const protocol::SetBreakpointsArguments &args) const override;
+
+  std::vector<protocol::Breakpoint> SetSourceBreakpoints(
+      const protocol::Source &source,
+      const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints)
+      const;
+  std::vector<protocol::Breakpoint> SetAssemblyBreakpoints(
+      const protocol::Source &source,
+      const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints)
+      const;
 };
 
 class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler {
diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
index 86e090b66afe9..7b401f06e9a85 100644
--- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp
@@ -23,15 +23,29 @@ llvm::Expected<protocol::SetBreakpointsResponseBody>
 SetBreakpointsRequestHandler::Run(
     const protocol::SetBreakpointsArguments &args) const {
   const auto &source = args.source;
-  const auto path = source.path.value_or("");
   std::vector<protocol::Breakpoint> response_breakpoints;
+  if (source.sourceReference)
+    response_breakpoints = SetAssemblyBreakpoints(source, args.breakpoints);
+  else if (source.path)
+    response_breakpoints = SetSourceBreakpoints(source, args.breakpoints);
+
+  return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)};
+}
+
+std::vector<protocol::Breakpoint>
+SetBreakpointsRequestHandler::SetSourceBreakpoints(
+    const protocol::Source &source,
+    const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints)
+    const {
+  std::vector<protocol::Breakpoint> response_breakpoints;
+  std::string path = source.path.value_or("");
 
   // Decode the source breakpoint infos for this "setBreakpoints" request
   SourceBreakpointMap request_bps;
   // "breakpoints" may be unset, in which case we treat it the same as being set
   // to an empty array.
-  if (args.breakpoints) {
-    for (const auto &bp : *args.breakpoints) {
+  if (breakpoints) {
+    for (const auto &bp : *breakpoints) {
       SourceBreakpoint src_bp(dap, bp);
       std::pair<uint32_t, uint32_t> bp_pos(src_bp.GetLine(),
                                            src_bp.GetColumn());
@@ -73,7 +87,64 @@ SetBreakpointsRequestHandler::Run(
     }
   }
 
-  return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)};
+  return response_breakpoints;
+}
+
+std::vector<protocol::Breakpoint>
+SetBreakpointsRequestHandler::SetAssemblyBreakpoints(
+    const protocol::Source &source,
+    const std::optional<std::vector<protocol::SourceBreakpoint>> &breakpoints)
+    const {
+  std::vector<protocol::Breakpoint> response_breakpoints;
+  int64_t sourceReference = source.sourceReference.value_or(0);
+
+  lldb::SBAddress address(sourceReference, dap.target);
+  if (!address.IsValid())
+    return response_breakpoints;
+
+  lldb::SBSymbol symbol = address.GetSymbol();
+  if (!symbol.IsValid())
+    return response_breakpoints; // Not yet supporting breakpoints in assembly
+                                 // without a valid symbol
+
+  llvm::DenseMap<uint32_t, SourceBreakpoint> request_bps;
+  if (breakpoints) {
+    for (const auto &bp : *breakpoints) {
+      SourceBreakpoint src_bp(dap, bp);
+      request_bps.try_emplace(src_bp.GetLine(), src_bp);
+      const auto [iv, inserted] =
+          dap.assembly_breakpoints[sourceReference].try_emplace(
+              src_bp.GetLine(), src_bp);
+      // We check if this breakpoint already exists to update it
+      if (inserted)
+        iv->getSecond().SetBreakpoint(symbol);
+      else
+        iv->getSecond().UpdateBreakpoint(src_bp);
+
+      protocol::Breakpoint response_bp = iv->getSecond().ToProtocolBreakpoint();
+      response_bp.source = source;
+      if (!response_bp.line)
+        response_bp.line = src_bp.GetLine();
+      if (bp.column)
+        response_bp.column = *bp.column;
+      response_breakpoints.push_back(response_bp);
+    }
+  }
+
+  // Delete existing breakpoints for this sourceReference that are not in the
+  // request_bps set.
+  auto old_src_bp_pos = dap.assembly_breakpoints.find(sourceReference);
+  if (old_src_bp_pos != dap.assembly_breakpoints.end()) {
+    for (auto &old_bp : old_src_bp_pos->second) {
+      auto request_pos = request_bps.find(old_bp.first);
+      if (request_pos == request_bps.end()) {
+        dap.target.BreakpointDelete(old_bp.second.GetID());
+        old_src_bp_pos->second.erase(old_bp.first);
+      }
+    }
+  }
+
+  return response_breakpoints;
 }
 
 } // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
index 0ddd87881a164..9249e2aa6fef7 100644
--- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp
@@ -11,6 +11,7 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "Protocol/ProtocolTypes.h"
+#include "lldb/API/SBAddress.h"
 #include "lldb/API/SBExecutionContext.h"
 #include "lldb/API/SBFrame.h"
 #include "lldb/API/SBInstructionList.h"
@@ -19,6 +20,7 @@
 #include "lldb/API/SBSymbol.h"
 #include "lldb/API/SBTarget.h"
 #include "lldb/API/SBThread.h"
+#include "lldb/lldb-types.h"
 #include "llvm/Support/Error.h"
 
 namespace lldb_dap {
@@ -34,26 +36,22 @@ SourceRequestHandler::Run(const protocol::SourceArguments &args) const {
     return llvm::make_error<DAPError>(
         "invalid arguments, expected source.sourceReference to be set");
 
-  lldb::SBProcess process = dap.target.GetProcess();
-  // Upper 32 bits is the thread index ID
-  lldb::SBThread thread =
-      process.GetThreadByIndexID(GetLLDBThreadIndexID(source));
- ...
[truncated]

@eronnen eronnen requested a review from da-viper May 18, 2025 00:28
Copy link

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r HEAD~1...HEAD lldb/test/API/tools/lldb-dap/breakpoint-assembly/TestDAP_breakpointAssembly.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py
View the diff from darker here.
--- packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py	2025-05-18 00:26:37.000000 +0000
+++ packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py	2025-05-18 00:30:17.199504 +0000
@@ -61,13 +61,15 @@
         breakpoints = response["body"]["breakpoints"]
         breakpoint_ids = []
         for breakpoint in breakpoints:
             breakpoint_ids.append("%i" % (breakpoint["id"]))
         return breakpoint_ids
-    
+
     def set_source_breakpoints_assembly(self, source_reference, lines, data=None):
-        response = self.dap_server.request_setBreakpointsAssembly(source_reference, lines, data)
+        response = self.dap_server.request_setBreakpointsAssembly(
+            source_reference, lines, data
+        )
         if response is None:
             return []
         breakpoints = response["body"]["breakpoints"]
         breakpoint_ids = []
         for breakpoint in breakpoints:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.