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