xref: /freebsd/contrib/llvm-project/lldb/source/Breakpoint/BreakpointLocationCollection.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 llvm::find_if(
64       m_break_loc_collection,                           // Search full range
65       BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
66 }
67 
68 BreakpointLocationCollection::collection::const_iterator
GetIDPairConstIterator(lldb::break_id_t break_id,lldb::break_id_t break_loc_id) const69 BreakpointLocationCollection::GetIDPairConstIterator(
70     lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
71   return llvm::find_if(
72       m_break_loc_collection,                           // Search full range
73       BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
74 }
75 
76 BreakpointLocationSP
FindByIDPair(lldb::break_id_t break_id,lldb::break_id_t break_loc_id)77 BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id,
78                                            lldb::break_id_t break_loc_id) {
79   BreakpointLocationSP stop_sp;
80   collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
81   if (pos != m_break_loc_collection.end())
82     stop_sp = *pos;
83 
84   return stop_sp;
85 }
86 
FindByIDPair(lldb::break_id_t break_id,lldb::break_id_t break_loc_id) const87 const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(
88     lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
89   BreakpointLocationSP stop_sp;
90   collection::const_iterator pos =
91       GetIDPairConstIterator(break_id, break_loc_id);
92   if (pos != m_break_loc_collection.end())
93     stop_sp = *pos;
94 
95   return stop_sp;
96 }
97 
GetByIndex(size_t i)98 BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
99   std::lock_guard<std::mutex> guard(m_collection_mutex);
100   BreakpointLocationSP stop_sp;
101   if (i < m_break_loc_collection.size())
102     stop_sp = m_break_loc_collection[i];
103 
104   return stop_sp;
105 }
106 
107 const BreakpointLocationSP
GetByIndex(size_t i) const108 BreakpointLocationCollection::GetByIndex(size_t i) const {
109   std::lock_guard<std::mutex> guard(m_collection_mutex);
110   BreakpointLocationSP stop_sp;
111   if (i < m_break_loc_collection.size())
112     stop_sp = m_break_loc_collection[i];
113 
114   return stop_sp;
115 }
116 
ShouldStop(StoppointCallbackContext * context)117 bool BreakpointLocationCollection::ShouldStop(
118     StoppointCallbackContext *context) {
119   bool shouldStop = false;
120   size_t i = 0;
121   size_t prev_size = GetSize();
122   while (i < prev_size) {
123     // ShouldStop can remove the breakpoint from the list, or even delete
124     // it, so we should
125     BreakpointLocationSP cur_loc_sp = GetByIndex(i);
126     BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this();
127     if (cur_loc_sp->ShouldStop(context))
128       shouldStop = true;
129 
130     if (prev_size == GetSize())
131       i++;
132     prev_size = GetSize();
133   }
134   return shouldStop;
135 }
136 
ValidForThisThread(Thread & thread)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 
IsInternal() const149 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 
GetDescription(Stream * s,lldb::DescriptionLevel level)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 
operator =(const BreakpointLocationCollection & rhs)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