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