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