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 17b9c1b51eSKate Stone BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {} 1830fdc8d8SChris Lattner 19*fd2433e1SJonas 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 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 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 } 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 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 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: 85b9c1b51eSKate Stone BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {} 8630fdc8d8SChris Lattner 87b9c1b51eSKate 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 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 104b9c1b51eSKate 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 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 122b9c1b51eSKate 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 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 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 151b9c1b51eSKate 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 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 171b9c1b51eSKate 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