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()
21     : m_break_loc_collection(), m_collection_mutex() {}
22 
23 // Destructor
24 BreakpointLocationCollection::~BreakpointLocationCollection() = default;
25 
26 void 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 
34 bool 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 
45 class BreakpointIDPairMatches {
46 public:
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 
56 private:
57   const lldb::break_id_t m_break_id;
58   const lldb::break_id_t m_break_loc_id;
59 };
60 
61 BreakpointLocationCollection::collection::iterator
62 BreakpointLocationCollection::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 
70 BreakpointLocationCollection::collection::const_iterator
71 BreakpointLocationCollection::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 
79 BreakpointLocationSP
80 BreakpointLocationCollection::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 
90 const 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 
101 BreakpointLocationSP 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 
110 const BreakpointLocationSP
111 BreakpointLocationCollection::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 
120 bool 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 
137 bool 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 
149 bool 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 
165 void 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 
178 BreakpointLocationCollection &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