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 
Add(const BreakpointLocationSP & bp_loc)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 
Remove(lldb::break_id_t bp_id,lldb::break_id_t bp_loc_id)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:
BreakpointIDPairMatches(lldb::break_id_t break_id,lldb::break_id_t break_loc_id)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 
operator ()(const BreakpointLocationSP & bp_loc) const50   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
GetIDPairIterator(lldb::break_id_t break_id,lldb::break_id_t break_loc_id)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
GetIDPairConstIterator(lldb::break_id_t break_id,lldb::break_id_t break_loc_id) const70 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
FindByIDPair(lldb::break_id_t break_id,lldb::break_id_t break_loc_id)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 
FindByIDPair(lldb::break_id_t break_id,lldb::break_id_t break_loc_id) const89 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 
GetByIndex(size_t i)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
GetByIndex(size_t i) const110 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 
ShouldStop(StoppointCallbackContext * context)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, 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 
ValidForThisThread(Thread & thread)139 bool 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 
IsInternal() const151 bool 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 
GetDescription(Stream * s,lldb::DescriptionLevel level)167 void 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 
operator =(const BreakpointLocationCollection & rhs)180 BreakpointLocationCollection &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