1//===-- BreakpointLocationCollection.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/BreakpointLocationCollection.h"
10#include "lldb/Breakpoint/Breakpoint.h"
11#include "lldb/Breakpoint/BreakpointLocation.h"
12#include "lldb/Core/ModuleList.h"
13#include "lldb/Target/Thread.h"
14#include "lldb/Target/ThreadSpec.h"
15
16using namespace lldb;
17using namespace lldb_private;
18
19// BreakpointLocationCollection constructor
20BreakpointLocationCollection::BreakpointLocationCollection() = default;
21
22// Destructor
23BreakpointLocationCollection::~BreakpointLocationCollection() = default;
24
25void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {
26  std::lock_guard<std::mutex> guard(m_collection_mutex);
27  BreakpointLocationSP old_bp_loc =
28      FindByIDPair(bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
29  if (!old_bp_loc.get())
30    m_break_loc_collection.push_back(bp_loc);
31}
32
33bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id,
34                                          lldb::break_id_t bp_loc_id) {
35  std::lock_guard<std::mutex> guard(m_collection_mutex);
36  collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
37  if (pos != m_break_loc_collection.end()) {
38    m_break_loc_collection.erase(pos);
39    return true;
40  }
41  return false;
42}
43
44class BreakpointIDPairMatches {
45public:
46  BreakpointIDPairMatches(lldb::break_id_t break_id,
47                          lldb::break_id_t break_loc_id)
48      : m_break_id(break_id), m_break_loc_id(break_loc_id) {}
49
50  bool operator()(const BreakpointLocationSP &bp_loc) const {
51    return m_break_id == bp_loc->GetBreakpoint().GetID() &&
52           m_break_loc_id == bp_loc->GetID();
53  }
54
55private:
56  const lldb::break_id_t m_break_id;
57  const lldb::break_id_t m_break_loc_id;
58};
59
60BreakpointLocationCollection::collection::iterator
61BreakpointLocationCollection::GetIDPairIterator(lldb::break_id_t break_id,
62                                                lldb::break_id_t break_loc_id) {
63  return std::find_if(
64      m_break_loc_collection.begin(),
65      m_break_loc_collection.end(),                     // Search full range
66      BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
67}
68
69BreakpointLocationCollection::collection::const_iterator
70BreakpointLocationCollection::GetIDPairConstIterator(
71    lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
72  return std::find_if(
73      m_break_loc_collection.begin(),
74      m_break_loc_collection.end(),                     // Search full range
75      BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
76}
77
78BreakpointLocationSP
79BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id,
80                                           lldb::break_id_t break_loc_id) {
81  BreakpointLocationSP stop_sp;
82  collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
83  if (pos != m_break_loc_collection.end())
84    stop_sp = *pos;
85
86  return stop_sp;
87}
88
89const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(
90    lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
91  BreakpointLocationSP stop_sp;
92  collection::const_iterator pos =
93      GetIDPairConstIterator(break_id, break_loc_id);
94  if (pos != m_break_loc_collection.end())
95    stop_sp = *pos;
96
97  return stop_sp;
98}
99
100BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
101  std::lock_guard<std::mutex> guard(m_collection_mutex);
102  BreakpointLocationSP stop_sp;
103  if (i < m_break_loc_collection.size())
104    stop_sp = m_break_loc_collection[i];
105
106  return stop_sp;
107}
108
109const BreakpointLocationSP
110BreakpointLocationCollection::GetByIndex(size_t i) const {
111  std::lock_guard<std::mutex> guard(m_collection_mutex);
112  BreakpointLocationSP stop_sp;
113  if (i < m_break_loc_collection.size())
114    stop_sp = m_break_loc_collection[i];
115
116  return stop_sp;
117}
118
119bool BreakpointLocationCollection::ShouldStop(
120    StoppointCallbackContext *context) {
121  bool shouldStop = false;
122  size_t i = 0;
123  size_t prev_size = GetSize();
124  while (i < prev_size) {
125    // ShouldStop can remove the breakpoint from the list, or even delete
126    // it, so we should
127    BreakpointLocationSP cur_loc_sp = GetByIndex(i);
128    BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this();
129    if (cur_loc_sp->ShouldStop(context))
130      shouldStop = true;
131
132    if (prev_size == GetSize())
133      i++;
134    prev_size = GetSize();
135  }
136  return shouldStop;
137}
138
139bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {
140  std::lock_guard<std::mutex> guard(m_collection_mutex);
141  collection::iterator pos, begin = m_break_loc_collection.begin(),
142                            end = m_break_loc_collection.end();
143
144  for (pos = begin; pos != end; ++pos) {
145    if ((*pos)->ValidForThisThread(thread))
146      return true;
147  }
148  return false;
149}
150
151bool BreakpointLocationCollection::IsInternal() const {
152  std::lock_guard<std::mutex> guard(m_collection_mutex);
153  collection::const_iterator pos, begin = m_break_loc_collection.begin(),
154                                  end = m_break_loc_collection.end();
155
156  bool is_internal = true;
157
158  for (pos = begin; pos != end; ++pos) {
159    if (!(*pos)->GetBreakpoint().IsInternal()) {
160      is_internal = false;
161      break;
162    }
163  }
164  return is_internal;
165}
166
167void BreakpointLocationCollection::GetDescription(
168    Stream *s, lldb::DescriptionLevel level) {
169  std::lock_guard<std::mutex> guard(m_collection_mutex);
170  collection::iterator pos, begin = m_break_loc_collection.begin(),
171                            end = m_break_loc_collection.end();
172
173  for (pos = begin; pos != end; ++pos) {
174    if (pos != begin)
175      s->PutChar(' ');
176    (*pos)->GetDescription(s, level);
177  }
178}
179
180BreakpointLocationCollection &BreakpointLocationCollection::operator=(
181    const BreakpointLocationCollection &rhs) {
182  if (this != &rhs) {
183      std::lock(m_collection_mutex, rhs.m_collection_mutex);
184      std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
185      std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock);
186      m_break_loc_collection = rhs.m_break_loc_collection;
187  }
188  return *this;
189}
190