1//===-- BreakpointSiteList.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/BreakpointSiteList.h" 10 11#include "lldb/Utility/Stream.h" 12#include <algorithm> 13 14using namespace lldb; 15using namespace lldb_private; 16 17BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {} 18 19BreakpointSiteList::~BreakpointSiteList() {} 20 21// Add breakpoint site to the list. However, if the element already exists in 22// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID. 23 24lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) { 25 lldb::addr_t bp_site_load_addr = bp->GetLoadAddress(); 26 std::lock_guard<std::recursive_mutex> guard(m_mutex); 27 collection::iterator iter = m_bp_site_list.find(bp_site_load_addr); 28 29 if (iter == m_bp_site_list.end()) { 30 m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp)); 31 return bp->GetID(); 32 } else { 33 return LLDB_INVALID_BREAK_ID; 34 } 35} 36 37bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context, 38 lldb::break_id_t site_id) { 39 BreakpointSiteSP site_sp(FindByID(site_id)); 40 if (site_sp) { 41 // Let the BreakpointSite decide if it should stop here (could not have 42 // reached it's target hit count yet, or it could have a callback that 43 // decided it shouldn't stop (shared library loads/unloads). 44 return site_sp->ShouldStop(context); 45 } 46 // We should stop here since this BreakpointSite isn't valid anymore or it 47 // doesn't exist. 48 return true; 49} 50lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) { 51 BreakpointSiteSP bp = FindByAddress(addr); 52 if (bp) { 53 // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" 54 // PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); 55 return bp.get()->GetID(); 56 } 57 // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" 58 // PRIx64 59 // " ) => NONE", __FUNCTION__, (uint64_t)addr); 60 return LLDB_INVALID_BREAK_ID; 61} 62 63bool BreakpointSiteList::Remove(lldb::break_id_t break_id) { 64 std::lock_guard<std::recursive_mutex> guard(m_mutex); 65 collection::iterator pos = GetIDIterator(break_id); // Predicate 66 if (pos != m_bp_site_list.end()) { 67 m_bp_site_list.erase(pos); 68 return true; 69 } 70 return false; 71} 72 73bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) { 74 std::lock_guard<std::recursive_mutex> guard(m_mutex); 75 collection::iterator pos = m_bp_site_list.find(address); 76 if (pos != m_bp_site_list.end()) { 77 m_bp_site_list.erase(pos); 78 return true; 79 } 80 return false; 81} 82 83class BreakpointSiteIDMatches { 84public: 85 BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {} 86 87 bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const { 88 return m_break_id == val_pair.second->GetID(); 89 } 90 91private: 92 const lldb::break_id_t m_break_id; 93}; 94 95BreakpointSiteList::collection::iterator 96BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) { 97 std::lock_guard<std::recursive_mutex> guard(m_mutex); 98 return std::find_if(m_bp_site_list.begin(), 99 m_bp_site_list.end(), // Search full range 100 BreakpointSiteIDMatches(break_id)); // Predicate 101} 102 103BreakpointSiteList::collection::const_iterator 104BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const { 105 std::lock_guard<std::recursive_mutex> guard(m_mutex); 106 return std::find_if(m_bp_site_list.begin(), 107 m_bp_site_list.end(), // Search full range 108 BreakpointSiteIDMatches(break_id)); // Predicate 109} 110 111BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) { 112 std::lock_guard<std::recursive_mutex> guard(m_mutex); 113 BreakpointSiteSP stop_sp; 114 collection::iterator pos = GetIDIterator(break_id); 115 if (pos != m_bp_site_list.end()) 116 stop_sp = pos->second; 117 118 return stop_sp; 119} 120 121const BreakpointSiteSP 122BreakpointSiteList::FindByID(lldb::break_id_t break_id) const { 123 std::lock_guard<std::recursive_mutex> guard(m_mutex); 124 BreakpointSiteSP stop_sp; 125 collection::const_iterator pos = GetIDConstIterator(break_id); 126 if (pos != m_bp_site_list.end()) 127 stop_sp = pos->second; 128 129 return stop_sp; 130} 131 132BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) { 133 BreakpointSiteSP found_sp; 134 std::lock_guard<std::recursive_mutex> guard(m_mutex); 135 collection::iterator iter = m_bp_site_list.find(addr); 136 if (iter != m_bp_site_list.end()) 137 found_sp = iter->second; 138 return found_sp; 139} 140 141bool BreakpointSiteList::BreakpointSiteContainsBreakpoint( 142 lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) { 143 std::lock_guard<std::recursive_mutex> guard(m_mutex); 144 collection::const_iterator pos = GetIDConstIterator(bp_site_id); 145 if (pos != m_bp_site_list.end()) 146 return pos->second->IsBreakpointAtThisSite(bp_id); 147 148 return false; 149} 150 151void BreakpointSiteList::Dump(Stream *s) const { 152 s->Printf("%p: ", static_cast<const void *>(this)); 153 // s->Indent(); 154 s->Printf("BreakpointSiteList with %u BreakpointSites:\n", 155 (uint32_t)m_bp_site_list.size()); 156 s->IndentMore(); 157 collection::const_iterator pos; 158 collection::const_iterator end = m_bp_site_list.end(); 159 for (pos = m_bp_site_list.begin(); pos != end; ++pos) 160 pos->second->Dump(s); 161 s->IndentLess(); 162} 163 164void BreakpointSiteList::ForEach( 165 std::function<void(BreakpointSite *)> const &callback) { 166 std::lock_guard<std::recursive_mutex> guard(m_mutex); 167 for (auto pair : m_bp_site_list) 168 callback(pair.second.get()); 169} 170 171bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound, 172 lldb::addr_t upper_bound, 173 BreakpointSiteList &bp_site_list) const { 174 if (lower_bound > upper_bound) 175 return false; 176 177 std::lock_guard<std::recursive_mutex> guard(m_mutex); 178 collection::const_iterator lower, upper, pos; 179 lower = m_bp_site_list.lower_bound(lower_bound); 180 if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound) 181 return false; 182 183 // This is one tricky bit. The breakpoint might overlap the bottom end of 184 // the range. So we grab the breakpoint prior to the lower bound, and check 185 // that that + its byte size isn't in our range. 186 if (lower != m_bp_site_list.begin()) { 187 collection::const_iterator prev_pos = lower; 188 prev_pos--; 189 const BreakpointSiteSP &prev_bp = (*prev_pos).second; 190 if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound) 191 bp_site_list.Add(prev_bp); 192 } 193 194 upper = m_bp_site_list.upper_bound(upper_bound); 195 196 for (pos = lower; pos != upper; pos++) { 197 bp_site_list.Add((*pos).second); 198 } 199 return true; 200} 201