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