tatyana-krasnukha updated this revision to Diff 135387.
tatyana-krasnukha added a comment.

pass callbacks by const-reference


https://reviews.llvm.org/D39967

Files:
  include/lldb/Breakpoint/BreakpointSiteList.h
  source/Breakpoint/BreakpointSiteList.cpp
  source/Target/Process.cpp
  unittests/Process/CMakeLists.txt
  unittests/Process/common/
  unittests/Process/common/CMakeLists.txt
  unittests/Process/common/ProcessWriteMemoryTest.cpp

Index: unittests/Process/common/ProcessWriteMemoryTest.cpp
===================================================================
--- /dev/null
+++ unittests/Process/common/ProcessWriteMemoryTest.cpp
@@ -0,0 +1,287 @@
+//===-- ProcessorTraceMonitorTest.cpp ------------------------- -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Process.h"
+
+#include "gtest/gtest.h"
+
+#include <array>
+#include <cstring>
+#include <memory>
+#include <vector>
+
+using Status = lldb_private::Status;
+
+class FakeProcess : public lldb_private::Process {
+  using lldb_private::Process::Process;
+
+public:
+  static lldb_private::ConstString GetName() {
+    return lldb_private::ConstString("fake-process");
+  }
+
+  size_t ReadMemoryAsIs(lldb::addr_t addr, void *buf, size_t size,
+                        Status &error) {
+    return DoReadMemory(addr, buf, size, error);
+  }
+
+private:
+  lldb_private::ConstString GetPluginName() override { return GetName(); }
+
+  uint32_t GetPluginVersion() override { return 0; }
+
+  bool CanDebug(lldb::TargetSP, bool) override { return true; }
+  Status DoDestroy() override { return Status(); }
+  void RefreshStateAfterStop() override {}
+
+  size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
+                      Status &error) override {
+    auto mem_size = m_memory.size();
+    auto to_copy =
+        addr + size <= mem_size ? size : addr >= mem_size ? 0 : mem_size - addr;
+    memcpy(buf, m_memory.data() + addr, to_copy);
+    memset(static_cast<uint8_t *>(buf) + to_copy, 0, size - to_copy);
+    return size;
+  }
+
+  size_t DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size,
+                       Status &error) override {
+    auto mem_size = m_memory.size();
+    if (addr + size > mem_size)
+      m_memory.resize(addr + size);
+
+    memcpy(m_memory.data() + addr, buf, size);
+    return size;
+  }
+
+  Status EnableBreakpointSite(lldb_private::BreakpointSite *bp_site) override {
+    return EnableSoftwareBreakpoint(bp_site);
+  }
+
+  Status DisableBreakpointSite(lldb_private::BreakpointSite *bp_site) override {
+    return DisableSoftwareBreakpoint(bp_site);
+  }
+
+  bool UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+                        lldb_private::ThreadList &new_thread_list) override {
+    new_thread_list.Update(old_thread_list);
+    return true;
+  }
+
+  std::vector<uint8_t> m_memory;
+};
+
+using FakeProcessSP = std::shared_ptr<FakeProcess>;
+
+class FakePlatform : public lldb_private::Platform {
+public:
+  FakePlatform() : lldb_private::Platform(false) {}
+
+  using TrapOpcode = std::array<uint8_t, 4>;
+  static const TrapOpcode &GetTrapOpcode() {
+    static const TrapOpcode trap_opcode = {0x1, 0x2, 0x3, 0x4};
+    return trap_opcode;
+  }
+
+private:
+  size_t GetSoftwareBreakpointTrapOpcode(
+      lldb_private::Target &target,
+      lldb_private::BreakpointSite *bp_site) override {
+    assert(bp_site);
+    auto &trap_opcode = GetTrapOpcode();
+    return bp_site->SetTrapOpcode(trap_opcode.data(), trap_opcode.size())
+               ? trap_opcode.size()
+               : 0;
+  }
+  const char *GetDescription() override { return ""; }
+
+  lldb_private::ConstString GetPluginName() override {
+    return lldb_private::ConstString();
+  }
+
+  uint32_t GetPluginVersion() override { return 0; }
+
+  bool GetSupportedArchitectureAtIndex(uint32_t,
+                                       lldb_private::ArchSpec &) override {
+    return false;
+  }
+
+  lldb::ProcessSP Attach(lldb_private::ProcessAttachInfo &,
+                         lldb_private::Debugger &debugger,
+                         lldb_private::Target *target, Status &error) {
+    return lldb::ProcessSP();
+  }
+
+  void CalculateTrapHandlerSymbolNames() override {}
+};
+
+struct WriteMemoryTest : public ::testing::Test {
+  void SetUp() override {
+    lldb_private::HostInfo::Initialize();
+
+    lldb_private::PluginManager::RegisterPlugin(
+        FakeProcess::GetName(), nullptr,
+        [](lldb::TargetSP target, lldb::ListenerSP listener,
+           const lldb_private::FileSpec *) {
+          return lldb::ProcessSP(new FakeProcess(target, listener));
+        });
+
+    platform = std::make_shared<FakePlatform>();
+    lldb_private::Platform::SetHostPlatform(platform);
+
+    debugger = lldb_private::Debugger::CreateInstance(nullptr, nullptr);
+    debugger->GetPlatformList().SetSelectedPlatform(platform);
+    debugger->GetTargetList().CreateTarget(*debugger, llvm::StringRef(),
+                                           lldb_private::ArchSpec(), false,
+                                           platform, target);
+
+    ASSERT_TRUE(target);
+
+    process = std::static_pointer_cast<FakeProcess>(
+        target->CreateProcess(debugger->GetListener(),
+                              FakeProcess::GetName().GetStringRef(), nullptr));
+    ASSERT_TRUE(process);
+    InitializeBuffers();
+  }
+
+  void TearDown() override { lldb_private::HostInfo::Terminate(); }
+
+  void SetBreakpoint(lldb::addr_t addr) {
+    ASSERT_TRUE(
+        target->CreateBreakpoint(lldb_private::Address(addr), false, false));
+  }
+
+  void CheckSavedOpcodes();
+  void CheckTrapOpcode(lldb::addr_t addr);
+  void WriteAndCheckData(lldb::addr_t addr, size_t count);
+
+  void InitializeBuffers() {
+    wbuf.fill(0xffu);
+    rbuf.fill(0u);
+  }
+
+  lldb::DebuggerSP debugger;
+  lldb::PlatformSP platform;
+  lldb::TargetSP target;
+  FakeProcessSP process;
+  std::array<uint8_t, 16> wbuf, rbuf;
+  const FakePlatform::TrapOpcode &trap_opcode = FakePlatform::GetTrapOpcode();
+};
+
+void WriteMemoryTest::CheckSavedOpcodes() {
+  Status status;
+  process->GetBreakpointSiteList().ForEach(
+      [this](const lldb_private::BreakpointSite &bp_site) {
+        ASSERT_TRUE(0 == memcmp(bp_site.GetSavedOpcodeBytes(),
+                                wbuf.data() + bp_site.GetLoadAddress(),
+                                bp_site.GetByteSize()));
+      });
+}
+
+void WriteMemoryTest::CheckTrapOpcode(lldb::addr_t addr) {
+  Status status;
+  auto read =
+      process->ReadMemoryAsIs(addr, rbuf.data(), trap_opcode.size(), status);
+  ASSERT_TRUE(status.Success() && trap_opcode.size() == read);
+  ASSERT_TRUE(0 == memcmp(trap_opcode.data(), rbuf.data(), trap_opcode.size()));
+}
+
+void WriteMemoryTest::WriteAndCheckData(lldb::addr_t addr, size_t count) {
+  Status status;
+  auto written = process->WriteMemory(addr, wbuf.data() + addr, count, status);
+  ASSERT_TRUE(status.Success() && count == written);
+
+  auto read = process->ReadMemory(0, rbuf.data(), rbuf.size(), status);
+  ASSERT_TRUE(status.Success() && rbuf.size() == read);
+
+  ASSERT_TRUE(0 == memcmp(wbuf.data(), rbuf.data(), rbuf.size()));
+}
+
+TEST_F(WriteMemoryTest, NoBreakpointsInRange) {
+  // Without any breakpoints.
+  WriteAndCheckData(0, wbuf.size());
+
+  // Breakpoints are located beyond the area that will be re-written.
+  const size_t offset = trap_opcode.size();
+  const size_t count = wbuf.size() - 2 * offset;
+
+  const lldb::addr_t bp1_addr = 0;
+  SetBreakpoint(bp1_addr);
+  const lldb::addr_t bp2_addr = wbuf.size() - offset;
+  SetBreakpoint(bp2_addr);
+
+  // SetBreakpoint is not fake;)
+  ASSERT_EQ(2u, target->GetBreakpointList().GetSize());
+  ASSERT_EQ(2u, process->GetBreakpointSiteList().GetSize());
+
+  // Write and check memory between breakpoints.
+  for (size_t i = offset; i < count; ++i)
+    --wbuf[i];
+  WriteAndCheckData(offset, count);
+
+  // Breakpoints still here.
+  ASSERT_EQ(2u, process->GetBreakpointSiteList().GetSize());
+
+  // Breakpoint opcode before area is not damaged.
+  CheckTrapOpcode(bp1_addr);
+
+  // Breakpoint opcode after area is not damaged.
+  CheckTrapOpcode(bp2_addr);
+
+  // Saved opcodes are updated.
+  CheckSavedOpcodes();
+}
+
+TEST_F(WriteMemoryTest, BreakpointOverlapsLowerBound) {
+  WriteAndCheckData(0, wbuf.size());
+
+  const lldb::addr_t bp_addr = 0;
+  const lldb::addr_t bp_size = trap_opcode.size();
+  const lldb::addr_t offset = bp_addr + bp_size / 2;
+  SetBreakpoint(bp_addr);
+
+  // Write memory starting from middle of breakpoint.
+  for (size_t i = offset; i < bp_size + offset; ++i)
+    --wbuf[i];
+  WriteAndCheckData(offset, bp_size);
+
+  // Breakpoint still here.
+  ASSERT_EQ(1u, process->GetBreakpointSiteList().GetSize());
+
+  // Breakpoint opcode is not damaged.
+  CheckTrapOpcode(bp_addr);
+
+  // A half of saved opcode is updated. Quite absurd and dangerous situation...
+  CheckSavedOpcodes();
+}
+
+TEST_F(WriteMemoryTest, BreakpointInRange) {
+  WriteAndCheckData(0, wbuf.size());
+
+  const lldb::addr_t bp_addr = wbuf.size() / 2;
+  const lldb::addr_t bp_size = trap_opcode.size();
+  SetBreakpoint(bp_addr);
+
+  wbuf.fill(0u);
+  WriteAndCheckData(0, wbuf.size());
+
+  // Breakpoint still here.
+  ASSERT_EQ(1u, process->GetBreakpointSiteList().GetSize());
+
+  // Breakpoint opcode is not damaged.
+  CheckTrapOpcode(bp_addr);
+
+  // Saved opcode is updated.
+  CheckSavedOpcodes();
+}
Index: unittests/Process/common/CMakeLists.txt
===================================================================
--- /dev/null
+++ unittests/Process/common/CMakeLists.txt
@@ -0,0 +1,7 @@
+add_lldb_unittest(LLDBProcessTests
+  ProcessWriteMemoryTest.cpp
+
+  LINK_LIBS
+    lldbBreakpoint
+    lldbTarget
+  )
\ No newline at end of file
Index: unittests/Process/CMakeLists.txt
===================================================================
--- unittests/Process/CMakeLists.txt
+++ unittests/Process/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(common)
 add_subdirectory(gdb-remote)
 if (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
   add_subdirectory(Linux)
Index: source/Target/Process.cpp
===================================================================
--- source/Target/Process.cpp
+++ source/Target/Process.cpp
@@ -1813,9 +1813,9 @@
 }
 
 void Process::DisableAllBreakpointSites() {
-  m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void {
+  m_breakpoint_site_list.ForEach([this](BreakpointSite &bp_site) {
     //        bp_site->SetEnabled(true);
-    DisableBreakpointSite(bp_site);
+    DisableBreakpointSite(&bp_site);
   });
 }
 
@@ -1961,29 +1961,26 @@
 size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size,
                                                   uint8_t *buf) const {
   size_t bytes_removed = 0;
-  BreakpointSiteList bp_sites_in_range;
+  BreakpointSiteList::Range bp_sites_in_range;
 
-  if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size,
-                                         bp_sites_in_range)) {
-    bp_sites_in_range.ForEach([bp_addr, size,
-                               buf](BreakpointSite *bp_site) -> void {
-      if (bp_site->GetType() == BreakpointSite::eSoftware) {
-        addr_t intersect_addr;
-        size_t intersect_size;
-        size_t opcode_offset;
-        if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr,
-                                     &intersect_size, &opcode_offset)) {
-          assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
-          assert(bp_addr < intersect_addr + intersect_size &&
-                 intersect_addr + intersect_size <= bp_addr + size);
-          assert(opcode_offset + intersect_size <= bp_site->GetByteSize());
-          size_t buf_offset = intersect_addr - bp_addr;
-          ::memcpy(buf + buf_offset,
-                   bp_site->GetSavedOpcodeBytes() + opcode_offset,
-                   intersect_size);
-        }
-      }
-    });
+  auto optional_lock = m_breakpoint_site_list.FindInRange(
+      bp_addr, bp_addr + size, bp_sites_in_range,
+      [](const BreakpointSite &bp_site) { return bp_site.IsEnabled(); });
+
+  for (auto &bp_site : bp_sites_in_range) {
+    addr_t intersect_addr;
+    size_t intersect_size;
+    size_t opcode_offset;
+    if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr,
+                                 &intersect_size, &opcode_offset)) {
+      assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
+      assert(bp_addr < intersect_addr + intersect_size &&
+             intersect_addr + intersect_size <= bp_addr + size);
+      assert(opcode_offset + intersect_size <= bp_site->GetByteSize());
+      size_t buf_offset = intersect_addr - bp_addr;
+      ::memcpy(buf + buf_offset, bp_site->GetSavedOpcodeBytes() + opcode_offset,
+               intersect_size);
+    }
   }
   return bytes_removed;
 }
@@ -2407,7 +2404,7 @@
 }
 
 size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
-                            Status &error) {
+                            Status &status) {
 #if defined(ENABLE_MEMORY_CACHING)
   m_memory_cache.Flush(addr, size);
 #endif
@@ -2417,72 +2414,36 @@
 
   m_mod_id.BumpMemoryID();
 
-  // We need to write any data that would go where any current software traps
-  // (enabled software breakpoints) any software traps (breakpoints) that we
-  // may have placed in our tasks memory.
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+  auto update_status = [&status, log, this](const Status &op_status) {
+    if (op_status.Fail()) {
+      if (log)
+        log->Printf("Process pid %" PRIu64 ": %s", GetID(),
+                    op_status.AsCString());
 
-  BreakpointSiteList bp_sites_in_range;
+      if (!status.Fail())
+        status.SetErrorString(
+            "failed to re-enable one or more breakpoints in range");
+    }
+  };
 
-  if (m_breakpoint_site_list.FindInRange(addr, addr + size,
-                                         bp_sites_in_range)) {
-    // No breakpoint sites overlap
-    if (bp_sites_in_range.IsEmpty())
-      return WriteMemoryPrivate(addr, buf, size, error);
-    else {
-      const uint8_t *ubuf = (const uint8_t *)buf;
-      uint64_t bytes_written = 0;
+  BreakpointSiteList::Range enabled_bp_sites_in_range;
 
-      bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf,
-                                 &error](BreakpointSite *bp) -> void {
+  auto optional_lock = m_breakpoint_site_list.FindInRange(
+      addr, addr + size, enabled_bp_sites_in_range,
+      [](const BreakpointSite &bp_site) { return bp_site.IsEnabled(); });
 
-        if (error.Success()) {
-          addr_t intersect_addr;
-          size_t intersect_size;
-          size_t opcode_offset;
-          const bool intersects = bp->IntersectsRange(
-              addr, size, &intersect_addr, &intersect_size, &opcode_offset);
-          UNUSED_IF_ASSERT_DISABLED(intersects);
-          assert(intersects);
-          assert(addr <= intersect_addr && intersect_addr < addr + size);
-          assert(addr < intersect_addr + intersect_size &&
-                 intersect_addr + intersect_size <= addr + size);
-          assert(opcode_offset + intersect_size <= bp->GetByteSize());
+  for (auto &bp_site : enabled_bp_sites_in_range)
+    update_status(DisableSoftwareBreakpoint(bp_site.get()));
 
-          // Check for bytes before this breakpoint
-          const addr_t curr_addr = addr + bytes_written;
-          if (intersect_addr > curr_addr) {
-            // There are some bytes before this breakpoint that we need to
-            // just write to memory
-            size_t curr_size = intersect_addr - curr_addr;
-            size_t curr_bytes_written = WriteMemoryPrivate(
-                curr_addr, ubuf + bytes_written, curr_size, error);
-            bytes_written += curr_bytes_written;
-            if (curr_bytes_written != curr_size) {
-              // We weren't able to write all of the requested bytes, we
-              // are done looping and will return the number of bytes that
-              // we have written so far.
-              if (error.Success())
-                error.SetErrorToGenericError();
-            }
-          }
-          // Now write any bytes that would cover up any software breakpoints
-          // directly into the breakpoint opcode buffer
-          ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset,
-                   ubuf + bytes_written, intersect_size);
-          bytes_written += intersect_size;
-        }
-      });
+  size_t written = WriteMemoryPrivate(addr, buf, size, status);
 
-      if (bytes_written < size)
-        WriteMemoryPrivate(addr + bytes_written, ubuf + bytes_written,
-                           size - bytes_written, error);
-    }
-  } else {
-    return WriteMemoryPrivate(addr, buf, size, error);
+  if (status.Success()) {
+    for (auto &bp_site : enabled_bp_sites_in_range)
+      update_status(EnableSoftwareBreakpoint(bp_site.get()));
   }
 
-  // Write any remaining bytes after the last breakpoint if we have any left
-  return 0; // bytes_written;
+  return written;
 }
 
 size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar,
Index: source/Breakpoint/BreakpointSiteList.cpp
===================================================================
--- source/Breakpoint/BreakpointSiteList.cpp
+++ source/Breakpoint/BreakpointSiteList.cpp
@@ -11,21 +11,17 @@
 
 // C Includes
 // C++ Includes
+#include <algorithm>
+#include <iterator>
 // Other libraries and framework includes
 // Project includes
 #include "lldb/Utility/Stream.h"
-#include <algorithm>
 
 using namespace lldb;
 using namespace lldb_private;
 
-BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {}
-
-BreakpointSiteList::~BreakpointSiteList() {}
-
 // Add breakpoint site to the list.  However, if the element already exists in
-// the
-// list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
+// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
 
 lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
   lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
@@ -159,48 +155,54 @@
   s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
             (uint32_t)m_bp_site_list.size());
   s->IndentMore();
-  collection::const_iterator pos;
-  collection::const_iterator end = m_bp_site_list.end();
-  for (pos = m_bp_site_list.begin(); pos != end; ++pos)
-    pos->second.get()->Dump(s);
+
+  for (const auto &pair : m_bp_site_list)
+    pair.second->Dump(s);
   s->IndentLess();
 }
 
-void BreakpointSiteList::ForEach(
-    std::function<void(BreakpointSite *)> const &callback) {
+void BreakpointSiteList::ForEach(const ModifyingCallback &callback) {
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  for (auto pair : m_bp_site_list)
-    callback(pair.second.get());
+  for (auto &pair : m_bp_site_list)
+    callback(*pair.second);
 }
 
-bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
-                                     lldb::addr_t upper_bound,
-                                     BreakpointSiteList &bp_site_list) const {
+void BreakpointSiteList::ForEach(const Callback &callback) const {
+  std::lock_guard<std::recursive_mutex> guard(m_mutex);
+  for (const auto &pair : m_bp_site_list)
+    callback(*pair.second);
+}
+
+llvm::Optional<BreakpointSiteList::Guard>
+BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
+                                lldb::addr_t upper_bound,
+                                BreakpointSiteList::Range &bp_site_list,
+                                BreakpointSiteList::Filter filter) const {
   if (lower_bound > upper_bound)
-    return false;
+    return llvm::None;
 
   std::lock_guard<std::recursive_mutex> guard(m_mutex);
-  collection::const_iterator lower, upper, pos;
-  lower = m_bp_site_list.lower_bound(lower_bound);
-  if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
-    return false;
+  auto lower = m_bp_site_list.lower_bound(lower_bound);
 
   // This is one tricky bit.  The breakpoint might overlap the bottom end of the
-  // range.  So we grab the
-  // breakpoint prior to the lower bound, and check that that + its byte size
-  // isn't in our range.
+  // range.  So we grab the breakpoint prior to the lower bound,
+  // and check that that + its byte size isn't in our range.
   if (lower != m_bp_site_list.begin()) {
-    collection::const_iterator prev_pos = lower;
-    prev_pos--;
+    auto prev_pos = std::prev(lower);
     const BreakpointSiteSP &prev_bp = (*prev_pos).second;
     if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
-      bp_site_list.Add(prev_bp);
+      lower = prev_pos;
   }
 
-  upper = m_bp_site_list.upper_bound(upper_bound);
+  if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
+    return llvm::None;
 
-  for (pos = lower; pos != upper; pos++) {
-    bp_site_list.Add((*pos).second);
+  auto upper = m_bp_site_list.upper_bound(upper_bound);
+
+  for (auto pos = lower; pos != upper; ++pos) {
+    if (nullptr == filter || filter(*(*pos).second))
+      bp_site_list.push_back((*pos).second);
   }
-  return true;
+
+  return BreakpointSiteList::Guard(m_mutex);
 }
Index: include/lldb/Breakpoint/BreakpointSiteList.h
===================================================================
--- include/lldb/Breakpoint/BreakpointSiteList.h
+++ include/lldb/Breakpoint/BreakpointSiteList.h
@@ -15,6 +15,7 @@
 #include <functional>
 #include <map>
 #include <mutex>
+#include <type_traits>
 
 // Other libraries and framework includes
 // Project includes
@@ -21,7 +22,6 @@
 #include "lldb/Breakpoint/BreakpointSite.h"
 
 namespace lldb_private {
-
 //----------------------------------------------------------------------
 /// @class BreakpointSiteList BreakpointSiteList.h
 /// "lldb/Breakpoint/BreakpointSiteList.h"
@@ -28,21 +28,16 @@
 /// @brief Class that manages lists of BreakpointSite shared pointers.
 //----------------------------------------------------------------------
 class BreakpointSiteList {
-  // At present Process directly accesses the map of BreakpointSites so it can
-  // do quick lookups into the map (using GetMap).
-  // FIXME: Find a better interface for this.
-  friend class Process;
-
 public:
   //------------------------------------------------------------------
   /// Default constructor makes an empty list.
   //------------------------------------------------------------------
-  BreakpointSiteList();
+  BreakpointSiteList() = default;
 
   //------------------------------------------------------------------
   /// Destructor, currently does nothing.
   //------------------------------------------------------------------
-  ~BreakpointSiteList();
+  ~BreakpointSiteList() = default;
 
   //------------------------------------------------------------------
   /// Add a BreakpointSite to the list.
@@ -130,8 +125,12 @@
   bool BreakpointSiteContainsBreakpoint(lldb::break_id_t bp_site_id,
                                         lldb::break_id_t bp_id);
 
-  void ForEach(std::function<void(BreakpointSite *)> const &callback);
+  using ModifyingCallback = std::function<void(BreakpointSite &)>;
+  void ForEach(const ModifyingCallback &callback);
 
+  using Callback = std::function<void(const BreakpointSite &)>;
+  void ForEach(const Callback &callback) const;
+
   //------------------------------------------------------------------
   /// Removes the breakpoint site given by \b breakID from this list.
   ///
@@ -154,12 +153,30 @@
   //------------------------------------------------------------------
   bool RemoveByAddress(lldb::addr_t addr);
 
-  bool FindInRange(lldb::addr_t lower_bound, lldb::addr_t upper_bound,
-                   BreakpointSiteList &bp_site_list) const;
+  using Range = std::list<lldb::BreakpointSiteSP>;
+  using Filter = std::add_pointer<bool(const BreakpointSite &)>::type;
+  class Guard final {
+    std::recursive_mutex *m_mutex;
 
-  typedef void (*BreakpointSiteSPMapFunc)(lldb::BreakpointSiteSP &bp,
-                                          void *baton);
+  public:
+    explicit Guard(std::recursive_mutex &mutex) : m_mutex(&mutex) {
+      m_mutex->lock();
+    }
 
+    Guard(Guard &&guard) : m_mutex(guard.m_mutex) { guard.m_mutex = nullptr; }
+    Guard(const Guard &) = delete;
+    Guard &operator=(const Guard &) = delete;
+
+    ~Guard() {
+      if (nullptr != m_mutex)
+        m_mutex->unlock();
+    }
+  };
+
+  llvm::Optional<Guard> FindInRange(lldb::addr_t lower_bound,
+                                    lldb::addr_t upper_bound,
+                                    Range &bp_site_list,
+                                    Filter filter = nullptr) const;
   //------------------------------------------------------------------
   /// Enquires of the breakpoint site on in this list with ID \a breakID whether
   /// we should stop for the breakpoint or not.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to