15ffd83dbSDimitry Andric //===-- BreakpointLocationList.cpp ----------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocationList.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
120b57cec5SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
130b57cec5SDimitry Andric #include "lldb/Core/Module.h"
140b57cec5SDimitry Andric #include "lldb/Core/Section.h"
150b57cec5SDimitry Andric #include "lldb/Target/SectionLoadList.h"
160b57cec5SDimitry Andric #include "lldb/Target/Target.h"
170b57cec5SDimitry Andric #include "lldb/Utility/ArchSpec.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric using namespace lldb;
200b57cec5SDimitry Andric using namespace lldb_private;
210b57cec5SDimitry Andric 
BreakpointLocationList(Breakpoint & owner)220b57cec5SDimitry Andric BreakpointLocationList::BreakpointLocationList(Breakpoint &owner)
2381ad6265SDimitry Andric     : m_owner(owner), m_next_id(0), m_new_location_recorder(nullptr) {}
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric BreakpointLocationList::~BreakpointLocationList() = default;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric BreakpointLocationSP
Create(const Address & addr,bool resolve_indirect_symbols)280b57cec5SDimitry Andric BreakpointLocationList::Create(const Address &addr,
290b57cec5SDimitry Andric                                bool resolve_indirect_symbols) {
300b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
310b57cec5SDimitry Andric   // The location ID is just the size of the location list + 1
320b57cec5SDimitry Andric   lldb::break_id_t bp_loc_id = ++m_next_id;
330b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp(
340b57cec5SDimitry Andric       new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
350b57cec5SDimitry Andric                              m_owner.IsHardware(), resolve_indirect_symbols));
360b57cec5SDimitry Andric   m_locations.push_back(bp_loc_sp);
370b57cec5SDimitry Andric   m_address_to_location[addr] = bp_loc_sp;
380b57cec5SDimitry Andric   return bp_loc_sp;
390b57cec5SDimitry Andric }
400b57cec5SDimitry Andric 
ShouldStop(StoppointCallbackContext * context,lldb::break_id_t break_id)410b57cec5SDimitry Andric bool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
420b57cec5SDimitry Andric                                         lldb::break_id_t break_id) {
430b57cec5SDimitry Andric   BreakpointLocationSP bp = FindByID(break_id);
440b57cec5SDimitry Andric   if (bp) {
450b57cec5SDimitry Andric     // Let the BreakpointLocation decide if it should stop here (could not have
460b57cec5SDimitry Andric     // reached it's target hit count yet, or it could have a callback that
470b57cec5SDimitry Andric     // decided it shouldn't stop (shared library loads/unloads).
480b57cec5SDimitry Andric     return bp->ShouldStop(context);
490b57cec5SDimitry Andric   }
500b57cec5SDimitry Andric   // We should stop here since this BreakpointLocation isn't valid anymore or
510b57cec5SDimitry Andric   // it doesn't exist.
520b57cec5SDimitry Andric   return true;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric 
FindIDByAddress(const Address & addr)550b57cec5SDimitry Andric lldb::break_id_t BreakpointLocationList::FindIDByAddress(const Address &addr) {
560b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp = FindByAddress(addr);
570b57cec5SDimitry Andric   if (bp_loc_sp) {
580b57cec5SDimitry Andric     return bp_loc_sp->GetID();
590b57cec5SDimitry Andric   }
600b57cec5SDimitry Andric   return LLDB_INVALID_BREAK_ID;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric 
Compare(BreakpointLocationSP lhs,lldb::break_id_t val)630b57cec5SDimitry Andric static bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
640b57cec5SDimitry Andric   return lhs->GetID() < val;
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric BreakpointLocationSP
FindByID(lldb::break_id_t break_id) const680b57cec5SDimitry Andric BreakpointLocationList::FindByID(lldb::break_id_t break_id) const {
690b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
700b57cec5SDimitry Andric   collection::const_iterator end = m_locations.end();
710b57cec5SDimitry Andric   collection::const_iterator pos =
72bdd1243dSDimitry Andric       llvm::lower_bound(m_locations, break_id, Compare);
730b57cec5SDimitry Andric   if (pos != end && (*pos)->GetID() == break_id)
740b57cec5SDimitry Andric     return *(pos);
750b57cec5SDimitry Andric   else
760b57cec5SDimitry Andric     return BreakpointLocationSP();
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
FindInModule(Module * module,BreakpointLocationCollection & bp_loc_list)790b57cec5SDimitry Andric size_t BreakpointLocationList::FindInModule(
800b57cec5SDimitry Andric     Module *module, BreakpointLocationCollection &bp_loc_list) {
810b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
820b57cec5SDimitry Andric   const size_t orig_size = bp_loc_list.GetSize();
830b57cec5SDimitry Andric   collection::iterator pos, end = m_locations.end();
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos) {
860b57cec5SDimitry Andric     BreakpointLocationSP break_loc = (*pos);
870b57cec5SDimitry Andric     SectionSP section_sp(break_loc->GetAddress().GetSection());
880b57cec5SDimitry Andric     if (section_sp && section_sp->GetModule().get() == module) {
890b57cec5SDimitry Andric       bp_loc_list.Add(break_loc);
900b57cec5SDimitry Andric     }
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   return bp_loc_list.GetSize() - orig_size;
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric const BreakpointLocationSP
FindByAddress(const Address & addr) const960b57cec5SDimitry Andric BreakpointLocationList::FindByAddress(const Address &addr) const {
970b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
980b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp;
990b57cec5SDimitry Andric   if (!m_locations.empty()) {
1000b57cec5SDimitry Andric     Address so_addr;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric     if (addr.IsSectionOffset()) {
1030b57cec5SDimitry Andric       so_addr = addr;
1040b57cec5SDimitry Andric     } else {
1050b57cec5SDimitry Andric       // Try and resolve as a load address if possible.
1060b57cec5SDimitry Andric       m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress(
1070b57cec5SDimitry Andric           addr.GetOffset(), so_addr);
1080b57cec5SDimitry Andric       if (!so_addr.IsValid()) {
1090b57cec5SDimitry Andric         // The address didn't resolve, so just set to passed in addr.
1100b57cec5SDimitry Andric         so_addr = addr;
1110b57cec5SDimitry Andric       }
1120b57cec5SDimitry Andric     }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric     addr_map::const_iterator pos = m_address_to_location.find(so_addr);
1150b57cec5SDimitry Andric     if (pos != m_address_to_location.end())
1160b57cec5SDimitry Andric       bp_loc_sp = pos->second;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   return bp_loc_sp;
1200b57cec5SDimitry Andric }
1210b57cec5SDimitry Andric 
Dump(Stream * s) const1220b57cec5SDimitry Andric void BreakpointLocationList::Dump(Stream *s) const {
1230b57cec5SDimitry Andric   s->Printf("%p: ", static_cast<const void *>(this));
1240b57cec5SDimitry Andric   // s->Indent();
1250b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1260b57cec5SDimitry Andric   s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
1270b57cec5SDimitry Andric             (uint64_t)m_locations.size());
1280b57cec5SDimitry Andric   s->IndentMore();
1290b57cec5SDimitry Andric   collection::const_iterator pos, end = m_locations.end();
1300b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos)
1310b57cec5SDimitry Andric     (*pos)->Dump(s);
1320b57cec5SDimitry Andric   s->IndentLess();
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric 
GetByIndex(size_t i)1350b57cec5SDimitry Andric BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
1360b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1370b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp;
1380b57cec5SDimitry Andric   if (i < m_locations.size())
1390b57cec5SDimitry Andric     bp_loc_sp = m_locations[i];
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   return bp_loc_sp;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
GetByIndex(size_t i) const1440b57cec5SDimitry Andric const BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
1450b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1460b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp;
1470b57cec5SDimitry Andric   if (i < m_locations.size())
1480b57cec5SDimitry Andric     bp_loc_sp = m_locations[i];
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   return bp_loc_sp;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
ClearAllBreakpointSites()1530b57cec5SDimitry Andric void BreakpointLocationList::ClearAllBreakpointSites() {
1540b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1550b57cec5SDimitry Andric   collection::iterator pos, end = m_locations.end();
1560b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos)
1570b57cec5SDimitry Andric     (*pos)->ClearBreakpointSite();
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
ResolveAllBreakpointSites()1600b57cec5SDimitry Andric void BreakpointLocationList::ResolveAllBreakpointSites() {
1610b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1620b57cec5SDimitry Andric   collection::iterator pos, end = m_locations.end();
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos) {
1650b57cec5SDimitry Andric     if ((*pos)->IsEnabled())
1660b57cec5SDimitry Andric       (*pos)->ResolveBreakpointSite();
1670b57cec5SDimitry Andric   }
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric 
GetHitCount() const1700b57cec5SDimitry Andric uint32_t BreakpointLocationList::GetHitCount() const {
1710b57cec5SDimitry Andric   uint32_t hit_count = 0;
1720b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1730b57cec5SDimitry Andric   collection::const_iterator pos, end = m_locations.end();
1740b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos)
1750b57cec5SDimitry Andric     hit_count += (*pos)->GetHitCount();
1760b57cec5SDimitry Andric   return hit_count;
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
ResetHitCount()179bdd1243dSDimitry Andric void BreakpointLocationList::ResetHitCount() {
180bdd1243dSDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
181bdd1243dSDimitry Andric   for (auto &loc : m_locations)
182bdd1243dSDimitry Andric     loc->ResetHitCount();
183bdd1243dSDimitry Andric }
184bdd1243dSDimitry Andric 
GetNumResolvedLocations() const1850b57cec5SDimitry Andric size_t BreakpointLocationList::GetNumResolvedLocations() const {
1860b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1870b57cec5SDimitry Andric   size_t resolve_count = 0;
1880b57cec5SDimitry Andric   collection::const_iterator pos, end = m_locations.end();
1890b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos) {
1900b57cec5SDimitry Andric     if ((*pos)->IsResolved())
1910b57cec5SDimitry Andric       ++resolve_count;
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric   return resolve_count;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
GetDescription(Stream * s,lldb::DescriptionLevel level)1960b57cec5SDimitry Andric void BreakpointLocationList::GetDescription(Stream *s,
1970b57cec5SDimitry Andric                                             lldb::DescriptionLevel level) {
1980b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
1990b57cec5SDimitry Andric   collection::iterator pos, end = m_locations.end();
2000b57cec5SDimitry Andric 
2010b57cec5SDimitry Andric   for (pos = m_locations.begin(); pos != end; ++pos) {
2020b57cec5SDimitry Andric     s->Printf(" ");
2030b57cec5SDimitry Andric     (*pos)->GetDescription(s, level);
2040b57cec5SDimitry Andric   }
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric 
AddLocation(const Address & addr,bool resolve_indirect_symbols,bool * new_location)2070b57cec5SDimitry Andric BreakpointLocationSP BreakpointLocationList::AddLocation(
2080b57cec5SDimitry Andric     const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
2090b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric   if (new_location)
2120b57cec5SDimitry Andric     *new_location = false;
2130b57cec5SDimitry Andric   BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
2140b57cec5SDimitry Andric   if (!bp_loc_sp) {
2150b57cec5SDimitry Andric     bp_loc_sp = Create(addr, resolve_indirect_symbols);
2160b57cec5SDimitry Andric     if (bp_loc_sp) {
2170b57cec5SDimitry Andric       bp_loc_sp->ResolveBreakpointSite();
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric       if (new_location)
2200b57cec5SDimitry Andric         *new_location = true;
2210b57cec5SDimitry Andric       if (m_new_location_recorder) {
2220b57cec5SDimitry Andric         m_new_location_recorder->Add(bp_loc_sp);
2230b57cec5SDimitry Andric       }
2240b57cec5SDimitry Andric     }
2250b57cec5SDimitry Andric   }
2260b57cec5SDimitry Andric   return bp_loc_sp;
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric 
SwapLocation(BreakpointLocationSP to_location_sp,BreakpointLocationSP from_location_sp)2290b57cec5SDimitry Andric void BreakpointLocationList::SwapLocation(
2300b57cec5SDimitry Andric     BreakpointLocationSP to_location_sp,
2310b57cec5SDimitry Andric     BreakpointLocationSP from_location_sp) {
2320b57cec5SDimitry Andric   if (!from_location_sp || !to_location_sp)
2330b57cec5SDimitry Andric     return;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   m_address_to_location.erase(to_location_sp->GetAddress());
2360b57cec5SDimitry Andric   to_location_sp->SwapLocation(from_location_sp);
2370b57cec5SDimitry Andric   RemoveLocation(from_location_sp);
2380b57cec5SDimitry Andric   m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
2390b57cec5SDimitry Andric   to_location_sp->ResolveBreakpointSite();
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric 
RemoveLocation(const lldb::BreakpointLocationSP & bp_loc_sp)2420b57cec5SDimitry Andric bool BreakpointLocationList::RemoveLocation(
2430b57cec5SDimitry Andric     const lldb::BreakpointLocationSP &bp_loc_sp) {
2440b57cec5SDimitry Andric   if (bp_loc_sp) {
2450b57cec5SDimitry Andric     std::lock_guard<std::recursive_mutex> guard(m_mutex);
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric     m_address_to_location.erase(bp_loc_sp->GetAddress());
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric     size_t num_locations = m_locations.size();
2500b57cec5SDimitry Andric     for (size_t idx = 0; idx < num_locations; idx++) {
2510b57cec5SDimitry Andric       if (m_locations[idx].get() == bp_loc_sp.get()) {
2520b57cec5SDimitry Andric         RemoveLocationByIndex(idx);
2530b57cec5SDimitry Andric         return true;
2540b57cec5SDimitry Andric       }
2550b57cec5SDimitry Andric     }
2560b57cec5SDimitry Andric   }
2570b57cec5SDimitry Andric   return false;
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric 
RemoveLocationByIndex(size_t idx)2600b57cec5SDimitry Andric void BreakpointLocationList::RemoveLocationByIndex(size_t idx) {
2610b57cec5SDimitry Andric   assert (idx < m_locations.size());
2620b57cec5SDimitry Andric   m_address_to_location.erase(m_locations[idx]->GetAddress());
2630b57cec5SDimitry Andric   m_locations.erase(m_locations.begin() + idx);
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric 
RemoveInvalidLocations(const ArchSpec & arch)2660b57cec5SDimitry Andric void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
2670b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
2680b57cec5SDimitry Andric   size_t idx = 0;
2690b57cec5SDimitry Andric   // Don't cache m_location.size() as it will change since we might remove
2700b57cec5SDimitry Andric   // locations from our vector...
2710b57cec5SDimitry Andric   while (idx < m_locations.size()) {
2720b57cec5SDimitry Andric     BreakpointLocation *bp_loc = m_locations[idx].get();
2730b57cec5SDimitry Andric     if (bp_loc->GetAddress().SectionWasDeleted()) {
2740b57cec5SDimitry Andric       // Section was deleted which means this breakpoint comes from a module
2750b57cec5SDimitry Andric       // that is no longer valid, so we should remove it.
2760b57cec5SDimitry Andric       RemoveLocationByIndex(idx);
2770b57cec5SDimitry Andric       continue;
2780b57cec5SDimitry Andric     }
2790b57cec5SDimitry Andric     if (arch.IsValid()) {
2800b57cec5SDimitry Andric       ModuleSP module_sp(bp_loc->GetAddress().GetModule());
2810b57cec5SDimitry Andric       if (module_sp) {
2820b57cec5SDimitry Andric         if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
2830b57cec5SDimitry Andric           // The breakpoint was in a module whose architecture is no longer
2840b57cec5SDimitry Andric           // compatible with "arch", so we need to remove it
2850b57cec5SDimitry Andric           RemoveLocationByIndex(idx);
2860b57cec5SDimitry Andric           continue;
2870b57cec5SDimitry Andric         }
2880b57cec5SDimitry Andric       }
2890b57cec5SDimitry Andric     }
2900b57cec5SDimitry Andric     // Only increment the index if we didn't remove the locations at index
2910b57cec5SDimitry Andric     // "idx"
2920b57cec5SDimitry Andric     ++idx;
2930b57cec5SDimitry Andric   }
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric 
StartRecordingNewLocations(BreakpointLocationCollection & new_locations)2960b57cec5SDimitry Andric void BreakpointLocationList::StartRecordingNewLocations(
2970b57cec5SDimitry Andric     BreakpointLocationCollection &new_locations) {
2980b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
2990b57cec5SDimitry Andric   assert(m_new_location_recorder == nullptr);
3000b57cec5SDimitry Andric   m_new_location_recorder = &new_locations;
3010b57cec5SDimitry Andric }
3020b57cec5SDimitry Andric 
StopRecordingNewLocations()3030b57cec5SDimitry Andric void BreakpointLocationList::StopRecordingNewLocations() {
3040b57cec5SDimitry Andric   std::lock_guard<std::recursive_mutex> guard(m_mutex);
3050b57cec5SDimitry Andric   m_new_location_recorder = nullptr;
3060b57cec5SDimitry Andric }
3070b57cec5SDimitry Andric 
Compact()3080b57cec5SDimitry Andric void BreakpointLocationList::Compact() {
3090b57cec5SDimitry Andric   lldb::break_id_t highest_id = 0;
3100b57cec5SDimitry Andric 
3110b57cec5SDimitry Andric   for (BreakpointLocationSP loc_sp : m_locations) {
3120b57cec5SDimitry Andric     lldb::break_id_t cur_id = loc_sp->GetID();
3130b57cec5SDimitry Andric     if (cur_id > highest_id)
3140b57cec5SDimitry Andric       highest_id = cur_id;
3150b57cec5SDimitry Andric   }
3160b57cec5SDimitry Andric   m_next_id = highest_id;
3170b57cec5SDimitry Andric }
318