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 
16 using namespace lldb;
17 using namespace lldb_private;
18 
19 // BreakpointLocationCollection constructor
20 BreakpointLocationCollection::BreakpointLocationCollection() = default;
21 
22 // Destructor
23 BreakpointLocationCollection::~BreakpointLocationCollection() = default;
24 
25 void 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 
33 bool 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 
44 class BreakpointIDPairMatches {
45 public:
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 
55 private:
56   const lldb::break_id_t m_break_id;
57   const lldb::break_id_t m_break_loc_id;
58 };
59 
60 BreakpointLocationCollection::collection::iterator
61 BreakpointLocationCollection::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 
69 BreakpointLocationCollection::collection::const_iterator
70 BreakpointLocationCollection::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 
78 BreakpointLocationSP
79 BreakpointLocationCollection::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 
89 const 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 
100 BreakpointLocationSP 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 
109 const BreakpointLocationSP
110 BreakpointLocationCollection::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 
119 bool 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
126     if (GetByIndex(i)->ShouldStop(context))
127       shouldStop = true;
128 
129     if (prev_size == GetSize())
130       i++;
131     prev_size = GetSize();
132   }
133   return shouldStop;
134 }
135 
136 bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {
137   std::lock_guard<std::mutex> guard(m_collection_mutex);
138   collection::iterator pos, begin = m_break_loc_collection.begin(),
139                             end = m_break_loc_collection.end();
140 
141   for (pos = begin; pos != end; ++pos) {
142     if ((*pos)->ValidForThisThread(thread))
143       return true;
144   }
145   return false;
146 }
147 
148 bool BreakpointLocationCollection::IsInternal() const {
149   std::lock_guard<std::mutex> guard(m_collection_mutex);
150   collection::const_iterator pos, begin = m_break_loc_collection.begin(),
151                                   end = m_break_loc_collection.end();
152 
153   bool is_internal = true;
154 
155   for (pos = begin; pos != end; ++pos) {
156     if (!(*pos)->GetBreakpoint().IsInternal()) {
157       is_internal = false;
158       break;
159     }
160   }
161   return is_internal;
162 }
163 
164 void BreakpointLocationCollection::GetDescription(
165     Stream *s, lldb::DescriptionLevel level) {
166   std::lock_guard<std::mutex> guard(m_collection_mutex);
167   collection::iterator pos, begin = m_break_loc_collection.begin(),
168                             end = m_break_loc_collection.end();
169 
170   for (pos = begin; pos != end; ++pos) {
171     if (pos != begin)
172       s->PutChar(' ');
173     (*pos)->GetDescription(s, level);
174   }
175 }
176 
177 BreakpointLocationCollection &BreakpointLocationCollection::operator=(
178     const BreakpointLocationCollection &rhs) {
179   if (this != &rhs) {
180       std::lock(m_collection_mutex, rhs.m_collection_mutex);
181       std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
182       std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock);
183       m_break_loc_collection = rhs.m_break_loc_collection;
184   }
185   return *this;
186 }
187