1254721Semaste//===-- BreakpointSiteList.cpp ----------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9254721Semaste#include "lldb/Breakpoint/BreakpointSiteList.h" 10254721Semaste 11321369Sdim#include "lldb/Utility/Stream.h" 12254721Semaste#include <algorithm> 13254721Semaste 14254721Semasteusing namespace lldb; 15254721Semasteusing namespace lldb_private; 16254721Semaste 17314564SdimBreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {} 18254721Semaste 19314564SdimBreakpointSiteList::~BreakpointSiteList() {} 20254721Semaste 21314564Sdim// Add breakpoint site to the list. However, if the element already exists in 22341825Sdim// the list, then we don't add it, and return LLDB_INVALID_BREAK_ID. 23254721Semaste 24314564Sdimlldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) { 25314564Sdim lldb::addr_t bp_site_load_addr = bp->GetLoadAddress(); 26314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 27314564Sdim collection::iterator iter = m_bp_site_list.find(bp_site_load_addr); 28254721Semaste 29314564Sdim if (iter == m_bp_site_list.end()) { 30314564Sdim m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp)); 31314564Sdim return bp->GetID(); 32314564Sdim } else { 33314564Sdim return LLDB_INVALID_BREAK_ID; 34314564Sdim } 35254721Semaste} 36254721Semaste 37314564Sdimbool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context, 38314564Sdim lldb::break_id_t site_id) { 39314564Sdim BreakpointSiteSP site_sp(FindByID(site_id)); 40314564Sdim if (site_sp) { 41314564Sdim // Let the BreakpointSite decide if it should stop here (could not have 42341825Sdim // reached it's target hit count yet, or it could have a callback that 43341825Sdim // decided it shouldn't stop (shared library loads/unloads). 44314564Sdim return site_sp->ShouldStop(context); 45314564Sdim } 46314564Sdim // We should stop here since this BreakpointSite isn't valid anymore or it 47314564Sdim // doesn't exist. 48314564Sdim return true; 49254721Semaste} 50314564Sdimlldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) { 51314564Sdim BreakpointSiteSP bp = FindByAddress(addr); 52314564Sdim if (bp) { 53314564Sdim // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" 54314564Sdim // PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID()); 55314564Sdim return bp.get()->GetID(); 56314564Sdim } 57341825Sdim // DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" 58341825Sdim // PRIx64 59314564Sdim // " ) => NONE", __FUNCTION__, (uint64_t)addr); 60314564Sdim return LLDB_INVALID_BREAK_ID; 61254721Semaste} 62254721Semaste 63314564Sdimbool BreakpointSiteList::Remove(lldb::break_id_t break_id) { 64314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 65314564Sdim collection::iterator pos = GetIDIterator(break_id); // Predicate 66314564Sdim if (pos != m_bp_site_list.end()) { 67314564Sdim m_bp_site_list.erase(pos); 68314564Sdim return true; 69314564Sdim } 70314564Sdim return false; 71254721Semaste} 72254721Semaste 73314564Sdimbool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) { 74314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 75314564Sdim collection::iterator pos = m_bp_site_list.find(address); 76314564Sdim if (pos != m_bp_site_list.end()) { 77314564Sdim m_bp_site_list.erase(pos); 78314564Sdim return true; 79314564Sdim } 80314564Sdim return false; 81254721Semaste} 82254721Semaste 83314564Sdimclass BreakpointSiteIDMatches { 84254721Semastepublic: 85314564Sdim BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {} 86254721Semaste 87314564Sdim bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const { 88353358Sdim return m_break_id == val_pair.second->GetID(); 89314564Sdim } 90254721Semaste 91254721Semasteprivate: 92314564Sdim const lldb::break_id_t m_break_id; 93254721Semaste}; 94254721Semaste 95254721SemasteBreakpointSiteList::collection::iterator 96314564SdimBreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) { 97314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 98314564Sdim return std::find_if(m_bp_site_list.begin(), 99314564Sdim m_bp_site_list.end(), // Search full range 100314564Sdim BreakpointSiteIDMatches(break_id)); // Predicate 101254721Semaste} 102254721Semaste 103254721SemasteBreakpointSiteList::collection::const_iterator 104314564SdimBreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const { 105314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 106314564Sdim return std::find_if(m_bp_site_list.begin(), 107314564Sdim m_bp_site_list.end(), // Search full range 108314564Sdim BreakpointSiteIDMatches(break_id)); // Predicate 109254721Semaste} 110254721Semaste 111314564SdimBreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) { 112314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 113314564Sdim BreakpointSiteSP stop_sp; 114314564Sdim collection::iterator pos = GetIDIterator(break_id); 115314564Sdim if (pos != m_bp_site_list.end()) 116314564Sdim stop_sp = pos->second; 117254721Semaste 118314564Sdim return stop_sp; 119254721Semaste} 120254721Semaste 121254721Semasteconst BreakpointSiteSP 122314564SdimBreakpointSiteList::FindByID(lldb::break_id_t break_id) const { 123314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 124314564Sdim BreakpointSiteSP stop_sp; 125314564Sdim collection::const_iterator pos = GetIDConstIterator(break_id); 126314564Sdim if (pos != m_bp_site_list.end()) 127314564Sdim stop_sp = pos->second; 128254721Semaste 129314564Sdim return stop_sp; 130254721Semaste} 131254721Semaste 132314564SdimBreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) { 133314564Sdim BreakpointSiteSP found_sp; 134314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 135314564Sdim collection::iterator iter = m_bp_site_list.find(addr); 136314564Sdim if (iter != m_bp_site_list.end()) 137314564Sdim found_sp = iter->second; 138314564Sdim return found_sp; 139254721Semaste} 140254721Semaste 141314564Sdimbool BreakpointSiteList::BreakpointSiteContainsBreakpoint( 142314564Sdim lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) { 143314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 144314564Sdim collection::const_iterator pos = GetIDConstIterator(bp_site_id); 145314564Sdim if (pos != m_bp_site_list.end()) 146314564Sdim return pos->second->IsBreakpointAtThisSite(bp_id); 147254721Semaste 148314564Sdim return false; 149254721Semaste} 150254721Semaste 151314564Sdimvoid BreakpointSiteList::Dump(Stream *s) const { 152314564Sdim s->Printf("%p: ", static_cast<const void *>(this)); 153314564Sdim // s->Indent(); 154314564Sdim s->Printf("BreakpointSiteList with %u BreakpointSites:\n", 155314564Sdim (uint32_t)m_bp_site_list.size()); 156314564Sdim s->IndentMore(); 157314564Sdim collection::const_iterator pos; 158314564Sdim collection::const_iterator end = m_bp_site_list.end(); 159314564Sdim for (pos = m_bp_site_list.begin(); pos != end; ++pos) 160353358Sdim pos->second->Dump(s); 161314564Sdim s->IndentLess(); 162254721Semaste} 163254721Semaste 164314564Sdimvoid BreakpointSiteList::ForEach( 165314564Sdim std::function<void(BreakpointSite *)> const &callback) { 166314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 167314564Sdim for (auto pair : m_bp_site_list) 168314564Sdim callback(pair.second.get()); 169254721Semaste} 170254721Semaste 171314564Sdimbool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound, 172314564Sdim lldb::addr_t upper_bound, 173314564Sdim BreakpointSiteList &bp_site_list) const { 174314564Sdim if (lower_bound > upper_bound) 175314564Sdim return false; 176309124Sdim 177314564Sdim std::lock_guard<std::recursive_mutex> guard(m_mutex); 178314564Sdim collection::const_iterator lower, upper, pos; 179314564Sdim lower = m_bp_site_list.lower_bound(lower_bound); 180314564Sdim if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound) 181314564Sdim return false; 182314564Sdim 183341825Sdim // This is one tricky bit. The breakpoint might overlap the bottom end of 184341825Sdim // the range. So we grab the breakpoint prior to the lower bound, and check 185341825Sdim // that that + its byte size isn't in our range. 186314564Sdim if (lower != m_bp_site_list.begin()) { 187314564Sdim collection::const_iterator prev_pos = lower; 188314564Sdim prev_pos--; 189314564Sdim const BreakpointSiteSP &prev_bp = (*prev_pos).second; 190314564Sdim if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound) 191314564Sdim bp_site_list.Add(prev_bp); 192314564Sdim } 193314564Sdim 194314564Sdim upper = m_bp_site_list.upper_bound(upper_bound); 195314564Sdim 196314564Sdim for (pos = lower; pos != upper; pos++) { 197314564Sdim bp_site_list.Add((*pos).second); 198314564Sdim } 199314564Sdim return true; 200254721Semaste} 201