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