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