1//===-- BreakpointList.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Breakpoint/BreakpointList.h"
10
11#include "lldb/Target/Target.h"
12
13#include "llvm/Support/Errc.h"
14
15using namespace lldb;
16using namespace lldb_private;
17
18static void NotifyChange(const BreakpointSP &bp, BreakpointEventType event) {
19  Target &target = bp->GetTarget();
20  if (target.EventTypeHasListeners(Target::eBroadcastBitBreakpointChanged)) {
21    auto event_data_sp =
22        std::make_shared<Breakpoint::BreakpointEventData>(event, bp);
23    target.BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
24                          event_data_sp);
25  }
26}
27
28BreakpointList::BreakpointList(bool is_internal)
29    : m_next_break_id(0), m_is_internal(is_internal) {}
30
31BreakpointList::~BreakpointList() = default;
32
33break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
34  std::lock_guard<std::recursive_mutex> guard(m_mutex);
35
36  // Internal breakpoint IDs are negative, normal ones are positive
37  bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
38
39  m_breakpoints.push_back(bp_sp);
40
41  if (notify)
42    NotifyChange(bp_sp, eBreakpointEventTypeAdded);
43
44  return bp_sp->GetID();
45}
46
47bool BreakpointList::Remove(break_id_t break_id, bool notify) {
48  std::lock_guard<std::recursive_mutex> guard(m_mutex);
49
50  auto it = std::find_if(
51      m_breakpoints.begin(), m_breakpoints.end(),
52      [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
53
54  if (it == m_breakpoints.end())
55    return false;
56
57  if (notify)
58    NotifyChange(*it, eBreakpointEventTypeRemoved);
59
60  m_breakpoints.erase(it);
61
62  return true;
63}
64
65void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
66  std::lock_guard<std::recursive_mutex> guard(m_mutex);
67  for (const auto &bp_sp : m_breakpoints)
68    bp_sp->RemoveInvalidLocations(arch);
69}
70
71void BreakpointList::SetEnabledAll(bool enabled) {
72  std::lock_guard<std::recursive_mutex> guard(m_mutex);
73  for (const auto &bp_sp : m_breakpoints)
74    bp_sp->SetEnabled(enabled);
75}
76
77void BreakpointList::SetEnabledAllowed(bool enabled) {
78  std::lock_guard<std::recursive_mutex> guard(m_mutex);
79  for (const auto &bp_sp : m_breakpoints)
80    if (bp_sp->AllowDisable())
81      bp_sp->SetEnabled(enabled);
82}
83
84void BreakpointList::RemoveAll(bool notify) {
85  std::lock_guard<std::recursive_mutex> guard(m_mutex);
86  ClearAllBreakpointSites();
87
88  if (notify) {
89    for (const auto &bp_sp : m_breakpoints)
90      NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
91  }
92
93  m_breakpoints.clear();
94}
95
96void BreakpointList::RemoveAllowed(bool notify) {
97  std::lock_guard<std::recursive_mutex> guard(m_mutex);
98
99  for (const auto &bp_sp : m_breakpoints) {
100    if (bp_sp->AllowDelete())
101      bp_sp->ClearAllBreakpointSites();
102    if (notify)
103      NotifyChange(bp_sp, eBreakpointEventTypeRemoved);
104  }
105
106  llvm::erase_if(m_breakpoints,
107                 [&](const BreakpointSP &bp) { return bp->AllowDelete(); });
108}
109
110BreakpointList::bp_collection::iterator
111BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
112  return std::find_if(
113      m_breakpoints.begin(), m_breakpoints.end(),
114      [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
115}
116
117BreakpointList::bp_collection::const_iterator
118BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
119  return std::find_if(
120      m_breakpoints.begin(), m_breakpoints.end(),
121      [&](const BreakpointSP &bp) { return bp->GetID() == break_id; });
122}
123
124BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) const {
125  std::lock_guard<std::recursive_mutex> guard(m_mutex);
126
127  auto it = GetBreakpointIDConstIterator(break_id);
128  if (it != m_breakpoints.end())
129    return *it;
130  return {};
131}
132
133llvm::Expected<std::vector<lldb::BreakpointSP>>
134BreakpointList::FindBreakpointsByName(const char *name) {
135  if (!name)
136    return llvm::createStringError(llvm::errc::invalid_argument,
137                                   "FindBreakpointsByName requires a name");
138
139  Status error;
140  if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error))
141    return error.ToError();
142
143  std::vector<lldb::BreakpointSP> matching_bps;
144  for (BreakpointSP bkpt_sp : Breakpoints()) {
145    if (bkpt_sp->MatchesName(name)) {
146      matching_bps.push_back(bkpt_sp);
147    }
148  }
149
150  return matching_bps;
151}
152
153void BreakpointList::Dump(Stream *s) const {
154  std::lock_guard<std::recursive_mutex> guard(m_mutex);
155  s->Printf("%p: ", static_cast<const void *>(this));
156  s->Indent();
157  s->Printf("BreakpointList with %u Breakpoints:\n",
158            (uint32_t)m_breakpoints.size());
159  s->IndentMore();
160  for (const auto &bp_sp : m_breakpoints)
161    bp_sp->Dump(s);
162  s->IndentLess();
163}
164
165BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
166  std::lock_guard<std::recursive_mutex> guard(m_mutex);
167  if (i < m_breakpoints.size())
168    return m_breakpoints[i];
169  return {};
170}
171
172void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
173                                       bool delete_locations) {
174  std::lock_guard<std::recursive_mutex> guard(m_mutex);
175  for (const auto &bp_sp : m_breakpoints)
176    bp_sp->ModulesChanged(module_list, added, delete_locations);
177}
178
179void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
180    ModuleSP old_module_sp, ModuleSP new_module_sp) {
181  std::lock_guard<std::recursive_mutex> guard(m_mutex);
182  for (const auto &bp_sp : m_breakpoints)
183    bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
184}
185
186void BreakpointList::ClearAllBreakpointSites() {
187  std::lock_guard<std::recursive_mutex> guard(m_mutex);
188  for (const auto &bp_sp : m_breakpoints)
189    bp_sp->ClearAllBreakpointSites();
190}
191
192void BreakpointList::ResetHitCounts() {
193  std::lock_guard<std::recursive_mutex> guard(m_mutex);
194  for (const auto &bp_sp : m_breakpoints)
195    bp_sp->ResetHitCount();
196}
197
198void BreakpointList::GetListMutex(
199    std::unique_lock<std::recursive_mutex> &lock) {
200  lock = std::unique_lock<std::recursive_mutex>(m_mutex);
201}
202