[Lldb-commits] [lldb] 9cb227f - Stop emitting a breakpoint for each location in a breakpoint when responding to breakpoint commands.

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Thu Feb 13 08:23:35 PST 2020


Author: Greg Clayton
Date: 2020-02-13T08:23:19-08:00
New Revision: 9cb227f561f4e5491840694580abbe7c0123b358

URL: https://github.com/llvm/llvm-project/commit/9cb227f561f4e5491840694580abbe7c0123b358
DIFF: https://github.com/llvm/llvm-project/commit/9cb227f561f4e5491840694580abbe7c0123b358.diff

LOG: Stop emitting a breakpoint for each location in a breakpoint when responding to breakpoint commands.

Summary: The VS Code DAP expects on response for each breakpoint that was requested. If we responsd with multiple entries for one breakpoint the VS Code UI gets out of date. Currently the VS code DAP doesn't handle one breakpoint with multiple locations. If this ever gets fixed we can modify our code.

Reviewers: labath

Subscribers: lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D73665

Added: 
    lldb/test/API/tools/lldb-vscode/breakpoint-events/Makefile
    lldb/test/API/tools/lldb-vscode/breakpoint-events/TestVSCode_breakpointEvents.py
    lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.cpp
    lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.h
    lldb/test/API/tools/lldb-vscode/breakpoint-events/main.cpp

Modified: 
    lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
    lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
    lldb/tools/lldb-vscode/BreakpointBase.cpp
    lldb/tools/lldb-vscode/BreakpointBase.h
    lldb/tools/lldb-vscode/ExceptionBreakpoint.cpp
    lldb/tools/lldb-vscode/FunctionBreakpoint.cpp
    lldb/tools/lldb-vscode/JSONUtils.cpp
    lldb/tools/lldb-vscode/JSONUtils.h
    lldb/tools/lldb-vscode/LLDBUtils.cpp
    lldb/tools/lldb-vscode/LLDBUtils.h
    lldb/tools/lldb-vscode/SourceBreakpoint.cpp
    lldb/tools/lldb-vscode/lldb-vscode.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
index 199b80c8f6fa..35ce7f893fd4 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/lldbvscode_testcase.py
@@ -22,8 +22,7 @@ def build_and_create_debug_adaptor(self):
     def set_source_breakpoints(self, source_path, lines, condition=None,
                                hitCondition=None):
         '''Sets source breakpoints and returns an array of strings containing
-           the breakpoint location IDs ("1.1", "1.2") for each breakpoint
-           that was set.
+           the breakpoint IDs ("1", "2") for each breakpoint that was set.
         '''
         response = self.vscode.request_setBreakpoints(
             source_path, lines, condition=condition, hitCondition=hitCondition)
@@ -32,17 +31,14 @@ def set_source_breakpoints(self, source_path, lines, condition=None,
         breakpoints = response['body']['breakpoints']
         breakpoint_ids = []
         for breakpoint in breakpoints:
-            response_id = breakpoint['id']
-            bp_id = response_id >> 32
-            bp_loc_id = response_id & 0xffffffff
-            breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id))
+            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
-           and returns an array of strings containing the breakpoint location
-           IDs ("1.1", "1.2") for each breakpoint that was set.
+           and returns an array of strings containing the breakpoint IDs
+           ("1", "2") for each breakpoint that was set.
         '''
         response = self.vscode.request_setFunctionBreakpoints(
             functions, condition=condition, hitCondition=hitCondition)
@@ -51,18 +47,15 @@ def set_function_breakpoints(self, functions, condition=None,
         breakpoints = response['body']['breakpoints']
         breakpoint_ids = []
         for breakpoint in breakpoints:
-            response_id = breakpoint['id']
-            bp_id = response_id >> 32
-            bp_loc_id = response_id & 0xffffffff
-            breakpoint_ids.append('%i.%i' % (bp_id, bp_loc_id))
+            breakpoint_ids.append('%i' % (breakpoint['id']))
         return breakpoint_ids
 
     def verify_breakpoint_hit(self, breakpoint_ids):
         '''Wait for the process we are debugging to stop, and verify we hit
            any breakpoint location in the "breakpoint_ids" array.
-           "breakpoint_ids" should be a list of breakpoint location ID strings
-           (["1.1", "2.1"]). The return value from
-           self.set_source_breakpoints() can be passed to this function'''
+           "breakpoint_ids" should be a list of breakpoint ID strings
+           (["1", "2"]). The return value from self.set_source_breakpoints()
+           or self.set_function_breakpoints() can be passed to this function'''
         stopped_events = self.vscode.wait_for_stopped()
         for stopped_event in stopped_events:
             if 'body' in stopped_event:
@@ -73,14 +66,21 @@ def verify_breakpoint_hit(self, breakpoint_ids):
                     continue
                 if 'description' not in body:
                     continue
-                # Description is "breakpoint 1.1", so look for any location id
-                # ("1.1") in the description field as verification that one of
-                # the breakpoint locations was hit
+                # Descriptions for breakpoints will be in the form
+                # "breakpoint 1.1", so look for any description that matches
+                # ("breakpoint 1.") in the description field as verification
+                # that one of the breakpoint locations was hit. VSCode doesn't
+                # allow breakpoints to have multiple locations, but LLDB does.
+                # So when looking at the description we just want to make sure
+                # the right breakpoint matches and not worry about the actual
+                # location.
                 description = body['description']
+                print("description: %s" % (description))
                 for breakpoint_id in breakpoint_ids:
-                    if breakpoint_id in description:
-                        return True
-        return False
+                    match_desc = 'breakpoint %s.' % (breakpoint_id)
+                    if match_desc in description:
+                        return
+        self.assertTrue(False, "breakpoint not hit")
 
     def verify_exception_breakpoint_hit(self, filter_label):
         '''Wait for the process we are debugging to stop, and verify the stop

diff  --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
index 1110ad36c0fd..cdb3dc115769 100644
--- a/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
+++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-vscode/vscode.py
@@ -111,6 +111,7 @@ def __init__(self, recv, send, init_commands):
         self.exit_status = None
         self.initialize_body = None
         self.thread_stop_reasons = {}
+        self.breakpoint_events = []
         self.sequence = 1
         self.threads = None
         self.recv_thread.start()
@@ -186,7 +187,7 @@ def handle_recv_packet(self, packet):
                     self.output[category] = output
                 self.output_condition.notify()
                 self.output_condition.release()
-                # no need to add 'output' packets to our packets list
+                # no need to add 'output' event packets to our packets list
                 return keepGoing
             elif event == 'process':
                 # When a new process is attached or launched, remember the
@@ -200,6 +201,13 @@ def handle_recv_packet(self, packet):
                 self._process_stopped()
                 tid = body['threadId']
                 self.thread_stop_reasons[tid] = body
+            elif event == 'breakpoint':
+                # Breakpoint events come in when a breakpoint has locations
+                # added or removed. Keep track of them so we can look for them
+                # in tests.
+                self.breakpoint_events.append(packet)
+                # no need to add 'breakpoint' event packets to our packets list
+                return keepGoing
         elif packet_type == 'response':
             if packet['command'] == 'disconnect':
                 keepGoing = False

diff  --git a/lldb/test/API/tools/lldb-vscode/breakpoint-events/Makefile b/lldb/test/API/tools/lldb-vscode/breakpoint-events/Makefile
new file mode 100644
index 000000000000..032f9cda29cd
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/breakpoint-events/Makefile
@@ -0,0 +1,4 @@
+DYLIB_NAME := unlikely_name
+DYLIB_CXX_SOURCES := foo.cpp
+CXX_SOURCES := main.cpp
+include Makefile.rules

diff  --git a/lldb/test/API/tools/lldb-vscode/breakpoint-events/TestVSCode_breakpointEvents.py b/lldb/test/API/tools/lldb-vscode/breakpoint-events/TestVSCode_breakpointEvents.py
new file mode 100644
index 000000000000..e519075923d3
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/breakpoint-events/TestVSCode_breakpointEvents.py
@@ -0,0 +1,121 @@
+"""
+Test lldb-vscode setBreakpoints request
+"""
+
+
+import unittest2
+import vscode
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lldbvscode_testcase
+import os
+
+
+class TestVSCode_breakpointEvents(lldbvscode_testcase.VSCodeTestCaseBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipIfWindows
+    def test_breakpoint_events(self):
+        '''
+            This test sets a breakpoint in a shared library and runs and stops
+            at the entry point of a program. When we stop at the entry point,
+            the shared library won't be loaded yet. At this point the
+            breakpoint should set itself, but not be verified because no
+            locations are resolved. We will then continue and expect to get a
+            breakpoint event that informs us that the breakpoint in the shared
+            library is "changed" and the correct line number should be
+            supplied. We also set a breakpoint using a LLDB command using the
+            "preRunCommands" when launching our program. Any breapoints set via
+            the command interpreter should not be have breakpoint events sent
+            back to VS Code as the UI isn't able to add new breakpoints to
+            their UI. Code has been added that tags breakpoints set from VS Code
+            DAP packets so we know the IDE knows about them. If VS Code is ever
+            able to register breakpoints that aren't initially set in the GUI,
+            then we will need to revise this.
+        '''
+        main_source_basename = 'main.cpp'
+        main_source_path = os.path.join(os.getcwd(), main_source_basename)
+        foo_source_basename = 'foo.cpp'
+        foo_source_path = os.path.join(os.getcwd(), foo_source_basename)
+        main_bp_line = line_number('main.cpp', 'main breakpoint 1')
+        foo_bp1_line = line_number('foo.cpp', 'foo breakpoint 1')
+        foo_bp2_line = line_number('foo.cpp', 'foo breakpoint 2')
+
+        # Visual Studio Code Debug Adaptors have no way to specify the file
+        # without launching or attaching to a process, so we must start a
+        # process in order to be able to set breakpoints.
+        program = self.getBuildArtifact("a.out")
+
+        # Set a breakpoint after creating the target by running a command line
+        # command. It will eventually resolve and cause a breakpoint changed
+        # event to be sent to lldb-vscode. We want to make sure we don't send a
+        # breakpoint any breakpoints that were set from the command line.
+        # Breakpoints that are set via the VS code DAP packets will be
+        # registered and marked with a special keyword to ensure we deliver
+        # breakpoint events for these breakpoints but not for ones that are not
+        # set via the command interpreter.
+        bp_command = 'breakpoint set --file foo.cpp --line %u' % (foo_bp2_line)
+        self.build_and_launch(program, stopOnEntry=True,
+                              preRunCommands=[bp_command])
+        main_bp_id = 0
+        foo_bp_id = 0
+        # Set breakoints and verify that they got set correctly
+        vscode_breakpoint_ids = []
+        response = self.vscode.request_setBreakpoints(main_source_path,
+                                                      [main_bp_line])
+        if response:
+            breakpoints = response['body']['breakpoints']
+            for breakpoint in breakpoints:
+                main_bp_id = breakpoint['id']
+                vscode_breakpoint_ids.append("%i" % (main_bp_id))
+                # line = breakpoint['line']
+                self.assertTrue(breakpoint['verified'],
+                                "expect main breakpoint to be verified")
+
+        response = self.vscode.request_setBreakpoints(foo_source_path,
+                                                      [foo_bp1_line])
+        if response:
+            breakpoints = response['body']['breakpoints']
+            for breakpoint in breakpoints:
+                foo_bp_id = breakpoint['id']
+                vscode_breakpoint_ids.append("%i" % (foo_bp_id))
+                self.assertFalse(breakpoint['verified'],
+                                 "expect foo breakpoint to not be verified")
+
+        # Get the stop at the entry point
+        self.continue_to_next_stop()
+
+        # We are now stopped at the entry point to the program. Shared
+        # libraries are not loaded yet (at least on macOS they aren't) and any
+        # breakpoints set in foo.cpp should not be resolved.
+        self.assertTrue(len(self.vscode.breakpoint_events) == 0,
+                        "no breakpoint events when stopped at entry point")
+
+        # Continue to the breakpoint
+        self.continue_to_breakpoints(vscode_breakpoint_ids)
+
+        # Make sure we only get an event for the breakpoint we set via a call
+        # to self.vscode.request_setBreakpoints(...), not the breakpoint
+        # we set with with a LLDB command in preRunCommands.
+        self.assertTrue(len(self.vscode.breakpoint_events) == 1,
+                        "make sure we got a breakpoint event")
+        event = self.vscode.breakpoint_events[0]
+        # Verify the details of the breakpoint changed notification.
+        body = event['body']
+        self.assertTrue(body['reason'] == 'changed',
+                "breakpoint event is says breakpoint is changed")
+        breakpoint = body['breakpoint']
+        self.assertTrue(breakpoint['verified'] == True,
+                "breakpoint event is says it is verified")
+        self.assertTrue(breakpoint['id'] == foo_bp_id,
+                "breakpoint event is for breakpoint %i" % (foo_bp_id))
+        self.assertTrue('line' in breakpoint and breakpoint['line'] > 0,
+                "breakpoint event is has a line number")
+        self.assertTrue("foo.cpp" in breakpoint['source']['path'],
+                "breakpoint event path contains foo.cpp")
+
+        output = self.get_console() # REMOVE PRIOR TO CHECKIN
+        with open("/tmp/b", "w") as f:
+            f.write(output)

diff  --git a/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.cpp b/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.cpp
new file mode 100644
index 000000000000..fa4f5657e69b
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.cpp
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+static void unique_function_name() {
+  puts(__PRETTY_FUNCTION__); // foo breakpoint 2
+}
+
+int foo(int x) {
+  // foo breakpoint 1
+  unique_function_name();
+  return x+42;
+}

diff  --git a/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.h b/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.h
new file mode 100644
index 000000000000..9e89fb356874
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/breakpoint-events/foo.h
@@ -0,0 +1,2 @@
+
+int foo(int);

diff  --git a/lldb/test/API/tools/lldb-vscode/breakpoint-events/main.cpp b/lldb/test/API/tools/lldb-vscode/breakpoint-events/main.cpp
new file mode 100644
index 000000000000..d8fc63c10b7f
--- /dev/null
+++ b/lldb/test/API/tools/lldb-vscode/breakpoint-events/main.cpp
@@ -0,0 +1,7 @@
+
+#include "foo.h"
+
+int main(int argc, char const *argv[]) {
+  int f = foo(argc);
+  return 0; // main breakpoint 1
+}

diff  --git a/lldb/tools/lldb-vscode/BreakpointBase.cpp b/lldb/tools/lldb-vscode/BreakpointBase.cpp
index 5d70c81e8868..5013fcbb7927 100644
--- a/lldb/tools/lldb-vscode/BreakpointBase.cpp
+++ b/lldb/tools/lldb-vscode/BreakpointBase.cpp
@@ -18,7 +18,7 @@ BreakpointBase::BreakpointBase(const llvm::json::Object &obj)
 
 void BreakpointBase::SetCondition() { bp.SetCondition(condition.c_str()); }
 
-void BreakpointBase::SetHitCondition() {  
+void BreakpointBase::SetHitCondition() {
   uint64_t hitCount = 0;
   if (llvm::to_integer(hitCondition, hitCount))
     bp.SetIgnoreCount(hitCount - 1);
@@ -34,3 +34,19 @@ void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) {
     SetHitCondition();
   }
 }
+
+const char *BreakpointBase::GetBreakpointLabel() {
+  // Breakpoints in LLDB can have names added to them which are kind of like
+  // labels or categories. All breakpoints that are set through the IDE UI get
+  // sent through the various VS code DAP set*Breakpoint packets, and these
+  // breakpoints will be labeled with this name so if breakpoint update events
+  // come in for breakpoints that the IDE doesn't know about, like if a
+  // breakpoint is set manually using the debugger console, we won't report any
+  // updates on them and confused the IDE. This function gets called by all of
+  // the breakpoint classes after they set breakpoints to mark a breakpoint as
+  // a UI breakpoint. We can later check a lldb::SBBreakpoint object that comes
+  // in via LLDB breakpoint changed events and check the breakpoint by calling
+  // "bool lldb::SBBreakpoint::MatchesName(const char *)" to check if a
+  // breakpoint in one of the UI breakpoints that we should report changes for.
+  return "vscode";
+}

diff  --git a/lldb/tools/lldb-vscode/BreakpointBase.h b/lldb/tools/lldb-vscode/BreakpointBase.h
index ee241a9713af..47808efeaefb 100644
--- a/lldb/tools/lldb-vscode/BreakpointBase.h
+++ b/lldb/tools/lldb-vscode/BreakpointBase.h
@@ -15,7 +15,7 @@
 #include <string>
 
 namespace lldb_vscode {
-  
+
 struct BreakpointBase {
 
   // An optional expression for conditional breakpoints.
@@ -36,6 +36,7 @@ struct BreakpointBase {
   void SetCondition();
   void SetHitCondition();
   void UpdateBreakpoint(const BreakpointBase &request_bp);
+  static const char *GetBreakpointLabel();
 };
 
 } // namespace lldb_vscode

diff  --git a/lldb/tools/lldb-vscode/ExceptionBreakpoint.cpp b/lldb/tools/lldb-vscode/ExceptionBreakpoint.cpp
index 090463ff60c1..9324e66d8bd7 100644
--- a/lldb/tools/lldb-vscode/ExceptionBreakpoint.cpp
+++ b/lldb/tools/lldb-vscode/ExceptionBreakpoint.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ExceptionBreakpoint.h"
+#include "BreakpointBase.h"
 #include "VSCode.h"
 
 namespace lldb_vscode {
@@ -18,6 +19,9 @@ void ExceptionBreakpoint::SetBreakpoint() {
   bool throw_value = filter.find("_throw") != std::string::npos;
   bp = g_vsc.target.BreakpointCreateForException(language, catch_value,
                                                  throw_value);
+  // See comments in BreakpointBase::GetBreakpointLabel() for details of why
+  // we add a label to our breakpoints.
+  bp.AddName(BreakpointBase::GetBreakpointLabel());
 }
 
 void ExceptionBreakpoint::ClearBreakpoint() {
@@ -28,4 +32,3 @@ void ExceptionBreakpoint::ClearBreakpoint() {
 }
 
 } // namespace lldb_vscode
-

diff  --git a/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp b/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp
index 2eae62ca754a..9dd97e7b79e0 100644
--- a/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp
+++ b/lldb/tools/lldb-vscode/FunctionBreakpoint.cpp
@@ -18,6 +18,9 @@ void FunctionBreakpoint::SetBreakpoint() {
   if (functionName.empty())
     return;
   bp = g_vsc.target.BreakpointCreateByName(functionName.c_str());
+  // See comments in BreakpointBase::GetBreakpointLabel() for details of why
+  // we add a label to our breakpoints.
+  bp.AddName(GetBreakpointLabel());
   if (!condition.empty())
     SetCondition();
   if (!hitCondition.empty())

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.cpp b/lldb/tools/lldb-vscode/JSONUtils.cpp
index b83f56445e22..95add5af5d33 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.cpp
+++ b/lldb/tools/lldb-vscode/JSONUtils.cpp
@@ -281,16 +281,33 @@ llvm::json::Value CreateScope(const llvm::StringRef name,
 //   },
 //   "required": [ "verified" ]
 // }
-llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc) {
+llvm::json::Value CreateBreakpoint(lldb::SBBreakpoint &bp) {
   // Each breakpoint location is treated as a separate breakpoint for VS code.
   // They don't have the notion of a single breakpoint with multiple locations.
   llvm::json::Object object;
-  if (!bp_loc.IsValid())
+  if (!bp.IsValid())
     return llvm::json::Value(std::move(object));
 
-  object.try_emplace("verified", true);
-  const auto vs_id = MakeVSCodeBreakpointID(bp_loc);
-  object.try_emplace("id", vs_id);
+  object.try_emplace("verified", bp.GetNumResolvedLocations() > 0);
+  object.try_emplace("id", bp.GetID());
+  // VS Code DAP doesn't currently allow one breakpoint to have multiple
+  // locations so we just report the first one. If we report all locations
+  // then the IDE starts showing the wrong line numbers and locations for
+  // other source file and line breakpoints in the same file.
+
+  // Below we search for the first resolved location in a breakpoint and report
+  // this as the breakpoint location since it will have a complete location
+  // that is at least loaded in the current process.
+  lldb::SBBreakpointLocation bp_loc;
+  const auto num_locs = bp.GetNumLocations();
+  for (size_t i=0; i<num_locs; ++i) {
+    bp_loc = bp.GetLocationAtIndex(i);
+    if (bp_loc.IsResolved())
+      break;
+  }
+  // If not locations are resolved, use the first location.
+  if (!bp_loc.IsResolved())
+    bp_loc = bp.GetLocationAtIndex(0);
   auto bp_addr = bp_loc.GetAddress();
   if (bp_addr.IsValid()) {
     auto line_entry = bp_addr.GetLineEntry();
@@ -303,15 +320,7 @@ llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc) {
 }
 
 void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints) {
-  if (!bp.IsValid())
-    return;
-  const auto num_locations = bp.GetNumLocations();
-  if (num_locations == 0)
-    return;
-  for (size_t i = 0; i < num_locations; ++i) {
-    auto bp_loc = bp.GetLocationAtIndex(i);
-    breakpoints.emplace_back(CreateBreakpoint(bp_loc));
-  }
+  breakpoints.emplace_back(CreateBreakpoint(bp));
 }
 
 // "Event": {
@@ -741,6 +750,12 @@ llvm::json::Value CreateThreadStopped(lldb::SBThread &thread,
       EmplaceSafeString(body, "description", exc_bp->label);
     } else {
       body.try_emplace("reason", "breakpoint");
+      char desc_str[64];
+      uint64_t bp_id = thread.GetStopReasonDataAtIndex(0);
+      uint64_t bp_loc_id = thread.GetStopReasonDataAtIndex(1);
+      snprintf(desc_str, sizeof(desc_str), "breakpoint %" PRIu64 ".%" PRIu64,
+               bp_id, bp_loc_id);
+      EmplaceSafeString(body, "description", desc_str);
     }
   } break;
   case lldb::eStopReasonWatchpoint:
@@ -870,4 +885,3 @@ llvm::json::Value CreateVariable(lldb::SBValue v, int64_t variablesReference,
 }
 
 } // namespace lldb_vscode
-

diff  --git a/lldb/tools/lldb-vscode/JSONUtils.h b/lldb/tools/lldb-vscode/JSONUtils.h
index 2391ac32b5c0..265af621e941 100644
--- a/lldb/tools/lldb-vscode/JSONUtils.h
+++ b/lldb/tools/lldb-vscode/JSONUtils.h
@@ -199,13 +199,13 @@ void AppendBreakpoint(lldb::SBBreakpoint &bp, llvm::json::Array &breakpoints);
 /// Converts breakpoint location to a Visual Studio Code "Breakpoint"
 /// JSON object and appends it to the \a breakpoints array.
 ///
-/// \param[in] bp_loc
-///     A LLDB breakpoint location object to convert into a JSON value
+/// \param[in] bp
+///     A LLDB breakpoint object to convert into a JSON value
 ///
 /// \return
 ///     A "Breakpoint" JSON object with that follows the formal JSON
 ///     definition outlined by Microsoft.
-llvm::json::Value CreateBreakpoint(lldb::SBBreakpointLocation &bp_loc);
+llvm::json::Value CreateBreakpoint(lldb::SBBreakpoint &bp);
 
 /// Create a "Event" JSON object using \a event_name as the event name
 ///

diff  --git a/lldb/tools/lldb-vscode/LLDBUtils.cpp b/lldb/tools/lldb-vscode/LLDBUtils.cpp
index 5be293dab4e6..81b5a789d1da 100644
--- a/lldb/tools/lldb-vscode/LLDBUtils.cpp
+++ b/lldb/tools/lldb-vscode/LLDBUtils.cpp
@@ -79,19 +79,4 @@ int64_t MakeVSCodeFrameID(lldb::SBFrame &frame) {
                    frame.GetFrameID());
 }
 
-static uint32_t constexpr BREAKPOINT_ID_SHIFT = 22;
-
-uint32_t GetLLDBBreakpointID(uint64_t dap_breakpoint_id) {
-  return dap_breakpoint_id >> BREAKPOINT_ID_SHIFT;
-}
-
-uint32_t GetLLDBBreakpointLocationID(uint64_t dap_breakpoint_id) {
-  return dap_breakpoint_id & ((1u << BREAKPOINT_ID_SHIFT) - 1);
-}
-
-int64_t MakeVSCodeBreakpointID(lldb::SBBreakpointLocation &bp_loc) {
-  return (int64_t)(bp_loc.GetBreakpoint().GetID() << BREAKPOINT_ID_SHIFT |
-                   bp_loc.GetID());
-}
-
 } // namespace lldb_vscode

diff  --git a/lldb/tools/lldb-vscode/LLDBUtils.h b/lldb/tools/lldb-vscode/LLDBUtils.h
index 82c17eb3cdc6..e4e56e71bd83 100644
--- a/lldb/tools/lldb-vscode/LLDBUtils.h
+++ b/lldb/tools/lldb-vscode/LLDBUtils.h
@@ -106,46 +106,6 @@ uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id);
 ///     The LLDB frame index ID.
 uint32_t GetLLDBFrameID(uint64_t dap_frame_id);
 
-/// Given a LLDB breakpoint, make a breakpoint ID that is unique to a
-/// specific breakpoint and breakpoint location.
-///
-/// VSCode requires a Breakpoint "id" to be unique, so we use the
-/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
-/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
-///
-/// \param[in] bp_loc
-///     The LLDB break point location.
-///
-/// \return
-///     A unique integer that allows us to easily find the right
-///     stack frame within a thread on subsequent VS code requests.
-int64_t MakeVSCodeBreakpointID(lldb::SBBreakpointLocation &bp_loc);
-
-/// Given a VSCode breakpoint ID, convert to a LLDB breakpoint ID.
-///
-/// VSCode requires a Breakpoint "id" to be unique, so we use the
-/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
-/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
-///
-/// \param[in] dap_breakpoint_id
-///     The VSCode breakpoint ID to convert to an LLDB breakpoint ID.
-///
-/// \return
-///     The LLDB breakpoint ID.
-uint32_t GetLLDBBreakpointID(uint64_t dap_breakpoint_id);
-
-/// Given a VSCode breakpoint ID, convert to a LLDB breakpoint location ID.
-///
-/// VSCode requires a Breakpoint "id" to be unique, so we use the
-/// breakpoint ID in the lower BREAKPOINT_ID_SHIFT bits and the
-/// breakpoint location ID in the upper BREAKPOINT_ID_SHIFT bits.
-///
-/// \param[in] dap_breakpoint_id
-///     The VSCode frame ID to convert to a breakpoint location ID.
-///
-/// \return
-///     The LLDB breakpoint location ID.
-uint32_t GetLLDBBreakpointLocationID(uint64_t dap_breakpoint_id);
 } // namespace lldb_vscode
 
 #endif

diff  --git a/lldb/tools/lldb-vscode/SourceBreakpoint.cpp b/lldb/tools/lldb-vscode/SourceBreakpoint.cpp
index 91d1ad70ecd6..be93c2e21ea4 100644
--- a/lldb/tools/lldb-vscode/SourceBreakpoint.cpp
+++ b/lldb/tools/lldb-vscode/SourceBreakpoint.cpp
@@ -17,6 +17,9 @@ SourceBreakpoint::SourceBreakpoint(const llvm::json::Object &obj)
 
 void SourceBreakpoint::SetBreakpoint(const llvm::StringRef source_path) {
   bp = g_vsc.target.BreakpointCreateByLocation(source_path.str().c_str(), line);
+  // See comments in BreakpointBase::GetBreakpointLabel() for details of why
+  // we add a label to our breakpoints.
+  bp.AddName(GetBreakpointLabel());
   if (!condition.empty())
     SetCondition();
   if (!hitCondition.empty())

diff  --git a/lldb/tools/lldb-vscode/lldb-vscode.cpp b/lldb/tools/lldb-vscode/lldb-vscode.cpp
index 94c8495d2b3e..e6b934038624 100644
--- a/lldb/tools/lldb-vscode/lldb-vscode.cpp
+++ b/lldb/tools/lldb-vscode/lldb-vscode.cpp
@@ -379,27 +379,20 @@ void EventThreadFunction() {
         if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) {
           auto event_type =
               lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event);
-          const auto num_locs =
-              lldb::SBBreakpoint::GetNumBreakpointLocationsFromEvent(event);
           auto bp = lldb::SBBreakpoint::GetBreakpointFromEvent(event);
-          bool added = event_type & lldb::eBreakpointEventTypeLocationsAdded;
-          bool removed =
-              event_type & lldb::eBreakpointEventTypeLocationsRemoved;
-          if (added || removed) {
-            for (size_t i = 0; i < num_locs; ++i) {
-              auto bp_loc =
-                  lldb::SBBreakpoint::GetBreakpointLocationAtIndexFromEvent(
-                      event, i);
-              auto bp_event = CreateEventObject("breakpoint");
-              llvm::json::Object body;
-              body.try_emplace("breakpoint", CreateBreakpoint(bp_loc));
-              if (added)
-                body.try_emplace("reason", "new");
-              else
-                body.try_emplace("reason", "removed");
-              bp_event.try_emplace("body", std::move(body));
-              g_vsc.SendJSON(llvm::json::Value(std::move(bp_event)));
-            }
+          // If the breakpoint was originated from the IDE, it will have the
+          // BreakpointBase::GetBreakpointLabel() label attached. Regardless
+          // of wether the locations were added or removed, the breakpoint
+          // ins't going away, so we the reason is always "changed".
+          if ((event_type & lldb::eBreakpointEventTypeLocationsAdded ||
+               event_type & lldb::eBreakpointEventTypeLocationsRemoved) &&
+              bp.MatchesName(BreakpointBase::GetBreakpointLabel())) {
+            auto bp_event = CreateEventObject("breakpoint");
+            llvm::json::Object body;
+            body.try_emplace("breakpoint", CreateBreakpoint(bp));
+            body.try_emplace("reason", "changed");
+            bp_event.try_emplace("body", std::move(body));
+            g_vsc.SendJSON(llvm::json::Value(std::move(bp_event)));
           }
         }
       } else if (event.BroadcasterMatchesRef(g_vsc.broadcaster)) {


        


More information about the lldb-commits mailing list