180814287SRaphael Isemann //===-- BreakpointSiteList.cpp --------------------------------------------===//
230fdc8d8SChris Lattner //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
930fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointSiteList.h"
1030fdc8d8SChris Lattner 
11bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
12ebb81bebSEli Friedman #include <algorithm>
1330fdc8d8SChris Lattner 
1430fdc8d8SChris Lattner using namespace lldb;
1530fdc8d8SChris Lattner using namespace lldb_private;
1630fdc8d8SChris Lattner 
17*ee4b6cf5SKazu Hirata BreakpointSiteList::BreakpointSiteList() = default;
1830fdc8d8SChris Lattner 
19fd2433e1SJonas Devlieghere BreakpointSiteList::~BreakpointSiteList() = default;
2030fdc8d8SChris Lattner 
21b9c1b51eSKate Stone // Add breakpoint site to the list.  However, if the element already exists in
2205097246SAdrian Prantl // the list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
2330fdc8d8SChris Lattner 
Add(const BreakpointSiteSP & bp)24b9c1b51eSKate Stone lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
2530fdc8d8SChris Lattner   lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
2616ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
2730fdc8d8SChris Lattner   collection::iterator iter = m_bp_site_list.find(bp_site_load_addr);
2830fdc8d8SChris Lattner 
29b9c1b51eSKate Stone   if (iter == m_bp_site_list.end()) {
3030fdc8d8SChris Lattner     m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp));
3130fdc8d8SChris Lattner     return bp->GetID();
32b9c1b51eSKate Stone   } else {
3330fdc8d8SChris Lattner     return LLDB_INVALID_BREAK_ID;
3430fdc8d8SChris Lattner   }
3530fdc8d8SChris Lattner }
3630fdc8d8SChris Lattner 
ShouldStop(StoppointCallbackContext * context,lldb::break_id_t site_id)37b9c1b51eSKate Stone bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context,
38b9c1b51eSKate Stone                                     lldb::break_id_t site_id) {
39f4b47e15SGreg Clayton   BreakpointSiteSP site_sp(FindByID(site_id));
40b9c1b51eSKate Stone   if (site_sp) {
4130fdc8d8SChris Lattner     // Let the BreakpointSite decide if it should stop here (could not have
4205097246SAdrian Prantl     // reached it's target hit count yet, or it could have a callback that
4305097246SAdrian Prantl     // decided it shouldn't stop (shared library loads/unloads).
44f4b47e15SGreg Clayton     return site_sp->ShouldStop(context);
4530fdc8d8SChris Lattner   }
4630fdc8d8SChris Lattner   // We should stop here since this BreakpointSite isn't valid anymore or it
4730fdc8d8SChris Lattner   // doesn't exist.
4830fdc8d8SChris Lattner   return true;
4930fdc8d8SChris Lattner }
FindIDByAddress(lldb::addr_t addr)50b9c1b51eSKate Stone lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) {
5130fdc8d8SChris Lattner   BreakpointSiteSP bp = FindByAddress(addr);
52b9c1b51eSKate Stone   if (bp) {
53b9c1b51eSKate Stone     // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
54b9c1b51eSKate Stone     // PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
5530fdc8d8SChris Lattner     return bp.get()->GetID();
5630fdc8d8SChris Lattner   }
5705097246SAdrian Prantl   // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
5805097246SAdrian Prantl   // PRIx64
59b9c1b51eSKate Stone   // " ) => NONE", __FUNCTION__, (uint64_t)addr);
6030fdc8d8SChris Lattner   return LLDB_INVALID_BREAK_ID;
6130fdc8d8SChris Lattner }
6230fdc8d8SChris Lattner 
Remove(lldb::break_id_t break_id)63b9c1b51eSKate Stone bool BreakpointSiteList::Remove(lldb::break_id_t break_id) {
6416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
6530fdc8d8SChris Lattner   collection::iterator pos = GetIDIterator(break_id); // Predicate
66b9c1b51eSKate Stone   if (pos != m_bp_site_list.end()) {
6730fdc8d8SChris Lattner     m_bp_site_list.erase(pos);
6830fdc8d8SChris Lattner     return true;
6930fdc8d8SChris Lattner   }
7030fdc8d8SChris Lattner   return false;
7130fdc8d8SChris Lattner }
7230fdc8d8SChris Lattner 
RemoveByAddress(lldb::addr_t address)73b9c1b51eSKate Stone bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) {
7416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
7530fdc8d8SChris Lattner   collection::iterator pos = m_bp_site_list.find(address);
76b9c1b51eSKate Stone   if (pos != m_bp_site_list.end()) {
7730fdc8d8SChris Lattner     m_bp_site_list.erase(pos);
7830fdc8d8SChris Lattner     return true;
7930fdc8d8SChris Lattner   }
8030fdc8d8SChris Lattner   return false;
8130fdc8d8SChris Lattner }
8230fdc8d8SChris Lattner 
83b9c1b51eSKate Stone class BreakpointSiteIDMatches {
8430fdc8d8SChris Lattner public:
BreakpointSiteIDMatches(lldb::break_id_t break_id)85b9c1b51eSKate Stone   BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {}
8630fdc8d8SChris Lattner 
operator ()(std::pair<lldb::addr_t,BreakpointSiteSP> val_pair) const87b9c1b51eSKate Stone   bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const {
8870355aceSJonas Devlieghere     return m_break_id == val_pair.second->GetID();
8930fdc8d8SChris Lattner   }
9030fdc8d8SChris Lattner 
9130fdc8d8SChris Lattner private:
92c982c768SGreg Clayton   const lldb::break_id_t m_break_id;
9330fdc8d8SChris Lattner };
9430fdc8d8SChris Lattner 
9530fdc8d8SChris Lattner BreakpointSiteList::collection::iterator
GetIDIterator(lldb::break_id_t break_id)96b9c1b51eSKate Stone BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) {
9716ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
98b9c1b51eSKate Stone   return std::find_if(m_bp_site_list.begin(),
99b9c1b51eSKate Stone                       m_bp_site_list.end(),               // Search full range
10030fdc8d8SChris Lattner                       BreakpointSiteIDMatches(break_id)); // Predicate
10130fdc8d8SChris Lattner }
10230fdc8d8SChris Lattner 
10330fdc8d8SChris Lattner BreakpointSiteList::collection::const_iterator
GetIDConstIterator(lldb::break_id_t break_id) const104b9c1b51eSKate Stone BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const {
10516ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
106b9c1b51eSKate Stone   return std::find_if(m_bp_site_list.begin(),
107b9c1b51eSKate Stone                       m_bp_site_list.end(),               // Search full range
10830fdc8d8SChris Lattner                       BreakpointSiteIDMatches(break_id)); // Predicate
10930fdc8d8SChris Lattner }
11030fdc8d8SChris Lattner 
FindByID(lldb::break_id_t break_id)111b9c1b51eSKate Stone BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) {
11216ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
11330fdc8d8SChris Lattner   BreakpointSiteSP stop_sp;
11430fdc8d8SChris Lattner   collection::iterator pos = GetIDIterator(break_id);
11530fdc8d8SChris Lattner   if (pos != m_bp_site_list.end())
11630fdc8d8SChris Lattner     stop_sp = pos->second;
11730fdc8d8SChris Lattner 
11830fdc8d8SChris Lattner   return stop_sp;
11930fdc8d8SChris Lattner }
12030fdc8d8SChris Lattner 
12130fdc8d8SChris Lattner const BreakpointSiteSP
FindByID(lldb::break_id_t break_id) const122b9c1b51eSKate Stone BreakpointSiteList::FindByID(lldb::break_id_t break_id) const {
12316ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
12430fdc8d8SChris Lattner   BreakpointSiteSP stop_sp;
12530fdc8d8SChris Lattner   collection::const_iterator pos = GetIDConstIterator(break_id);
12630fdc8d8SChris Lattner   if (pos != m_bp_site_list.end())
12730fdc8d8SChris Lattner     stop_sp = pos->second;
12830fdc8d8SChris Lattner 
12930fdc8d8SChris Lattner   return stop_sp;
13030fdc8d8SChris Lattner }
13130fdc8d8SChris Lattner 
FindByAddress(lldb::addr_t addr)132b9c1b51eSKate Stone BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) {
13330fdc8d8SChris Lattner   BreakpointSiteSP found_sp;
13416ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
13530fdc8d8SChris Lattner   collection::iterator iter = m_bp_site_list.find(addr);
13630fdc8d8SChris Lattner   if (iter != m_bp_site_list.end())
13730fdc8d8SChris Lattner     found_sp = iter->second;
13830fdc8d8SChris Lattner   return found_sp;
13930fdc8d8SChris Lattner }
14030fdc8d8SChris Lattner 
BreakpointSiteContainsBreakpoint(lldb::break_id_t bp_site_id,lldb::break_id_t bp_id)141b9c1b51eSKate Stone bool BreakpointSiteList::BreakpointSiteContainsBreakpoint(
142b9c1b51eSKate Stone     lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) {
14316ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
144564d8bc2SJim Ingham   collection::const_iterator pos = GetIDConstIterator(bp_site_id);
145564d8bc2SJim Ingham   if (pos != m_bp_site_list.end())
146367efe7dSJim Ingham     return pos->second->IsBreakpointAtThisSite(bp_id);
147564d8bc2SJim Ingham 
148564d8bc2SJim Ingham   return false;
149564d8bc2SJim Ingham }
150564d8bc2SJim Ingham 
Dump(Stream * s) const151b9c1b51eSKate Stone void BreakpointSiteList::Dump(Stream *s) const {
152324a1036SSaleem Abdulrasool   s->Printf("%p: ", static_cast<const void *>(this));
153ded470d3SGreg Clayton   // s->Indent();
154b9c1b51eSKate Stone   s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
155b9c1b51eSKate Stone             (uint32_t)m_bp_site_list.size());
15630fdc8d8SChris Lattner   s->IndentMore();
15730fdc8d8SChris Lattner   collection::const_iterator pos;
15830fdc8d8SChris Lattner   collection::const_iterator end = m_bp_site_list.end();
15930fdc8d8SChris Lattner   for (pos = m_bp_site_list.begin(); pos != end; ++pos)
16070355aceSJonas Devlieghere     pos->second->Dump(s);
16130fdc8d8SChris Lattner   s->IndentLess();
16230fdc8d8SChris Lattner }
16330fdc8d8SChris Lattner 
ForEach(std::function<void (BreakpointSite *)> const & callback)164b9c1b51eSKate Stone void BreakpointSiteList::ForEach(
165b9c1b51eSKate Stone     std::function<void(BreakpointSite *)> const &callback) {
16616ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
167d8cf1a11SGreg Clayton   for (auto pair : m_bp_site_list)
168d8cf1a11SGreg Clayton     callback(pair.second.get());
16930fdc8d8SChris Lattner }
17030fdc8d8SChris Lattner 
FindInRange(lldb::addr_t lower_bound,lldb::addr_t upper_bound,BreakpointSiteList & bp_site_list) const171b9c1b51eSKate Stone bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
172b9c1b51eSKate Stone                                      lldb::addr_t upper_bound,
173b9c1b51eSKate Stone                                      BreakpointSiteList &bp_site_list) const {
17420c77199SJim Ingham   if (lower_bound > upper_bound)
17520c77199SJim Ingham     return false;
17620c77199SJim Ingham 
17716ff8604SSaleem Abdulrasool   std::lock_guard<std::recursive_mutex> guard(m_mutex);
17820c77199SJim Ingham   collection::const_iterator lower, upper, pos;
17920c77199SJim Ingham   lower = m_bp_site_list.lower_bound(lower_bound);
180b9c1b51eSKate Stone   if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
18120c77199SJim Ingham     return false;
18220c77199SJim Ingham 
18305097246SAdrian Prantl   // This is one tricky bit.  The breakpoint might overlap the bottom end of
18405097246SAdrian Prantl   // the range.  So we grab the breakpoint prior to the lower bound, and check
18505097246SAdrian Prantl   // that that + its byte size isn't in our range.
186b9c1b51eSKate Stone   if (lower != m_bp_site_list.begin()) {
18720c77199SJim Ingham     collection::const_iterator prev_pos = lower;
18820c77199SJim Ingham     prev_pos--;
18920c77199SJim Ingham     const BreakpointSiteSP &prev_bp = (*prev_pos).second;
19020c77199SJim Ingham     if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
19120c77199SJim Ingham       bp_site_list.Add(prev_bp);
19220c77199SJim Ingham   }
19320c77199SJim Ingham 
19420c77199SJim Ingham   upper = m_bp_site_list.upper_bound(upper_bound);
19520c77199SJim Ingham 
196b9c1b51eSKate Stone   for (pos = lower; pos != upper; pos++) {
19720c77199SJim Ingham     bp_site_list.Add((*pos).second);
19820c77199SJim Ingham   }
19920c77199SJim Ingham   return true;
20020c77199SJim Ingham }
201