mirror of
https://github.com/intel/llvm.git
synced 2026-01-13 19:08:21 +08:00
This patch adds the notion of "Facade" locations which can be reported from a ScriptedResolver instead of the actual underlying breakpoint location for the breakpoint. Also add a "was_hit" method to the scripted resolver that allows the breakpoint to say which of these "Facade" locations was hit, and "get_location_description" to provide a description for the facade locations. I apologize in advance for the size of the patch. Almost all of what's here was necessary to (a) make the feature testable and (b) not break any of the current behavior. The motivation for this feature is given in the "Providing Facade Locations" section that I added to the python-reference.rst so I won't repeat it here. rdar://152112327
200 lines
6.7 KiB
C++
200 lines
6.7 KiB
C++
//===-- BreakpointLocationCollection.cpp ----------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Breakpoint/BreakpointLocationCollection.h"
|
|
#include "lldb/Breakpoint/Breakpoint.h"
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
|
#include "lldb/Core/ModuleList.h"
|
|
#include "lldb/Target/Thread.h"
|
|
#include "lldb/Target/ThreadSpec.h"
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
// BreakpointLocationCollection constructor
|
|
BreakpointLocationCollection::BreakpointLocationCollection() = default;
|
|
|
|
// Destructor
|
|
BreakpointLocationCollection::~BreakpointLocationCollection() = default;
|
|
|
|
void BreakpointLocationCollection::Add(const BreakpointLocationSP &bp_loc) {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
BreakpointLocationSP old_bp_loc =
|
|
FindByIDPair(bp_loc->GetBreakpoint().GetID(), bp_loc->GetID());
|
|
if (!old_bp_loc.get())
|
|
m_break_loc_collection.push_back(bp_loc);
|
|
}
|
|
|
|
bool BreakpointLocationCollection::Remove(lldb::break_id_t bp_id,
|
|
lldb::break_id_t bp_loc_id) {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
collection::iterator pos = GetIDPairIterator(bp_id, bp_loc_id); // Predicate
|
|
if (pos != m_break_loc_collection.end()) {
|
|
m_break_loc_collection.erase(pos);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
class BreakpointIDPairMatches {
|
|
public:
|
|
BreakpointIDPairMatches(lldb::break_id_t break_id,
|
|
lldb::break_id_t break_loc_id)
|
|
: m_break_id(break_id), m_break_loc_id(break_loc_id) {}
|
|
|
|
bool operator()(const BreakpointLocationSP &bp_loc) const {
|
|
return m_break_id == bp_loc->GetBreakpoint().GetID() &&
|
|
m_break_loc_id == bp_loc->GetID();
|
|
}
|
|
|
|
private:
|
|
const lldb::break_id_t m_break_id;
|
|
const lldb::break_id_t m_break_loc_id;
|
|
};
|
|
|
|
BreakpointLocationCollection::collection::iterator
|
|
BreakpointLocationCollection::GetIDPairIterator(lldb::break_id_t break_id,
|
|
lldb::break_id_t break_loc_id) {
|
|
return llvm::find_if(
|
|
m_break_loc_collection, // Search full range
|
|
BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
|
|
}
|
|
|
|
BreakpointLocationCollection::collection::const_iterator
|
|
BreakpointLocationCollection::GetIDPairConstIterator(
|
|
lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
|
|
return llvm::find_if(
|
|
m_break_loc_collection, // Search full range
|
|
BreakpointIDPairMatches(break_id, break_loc_id)); // Predicate
|
|
}
|
|
|
|
BreakpointLocationSP
|
|
BreakpointLocationCollection::FindByIDPair(lldb::break_id_t break_id,
|
|
lldb::break_id_t break_loc_id) {
|
|
BreakpointLocationSP stop_sp;
|
|
collection::iterator pos = GetIDPairIterator(break_id, break_loc_id);
|
|
if (pos != m_break_loc_collection.end())
|
|
stop_sp = *pos;
|
|
|
|
return stop_sp;
|
|
}
|
|
|
|
const BreakpointLocationSP BreakpointLocationCollection::FindByIDPair(
|
|
lldb::break_id_t break_id, lldb::break_id_t break_loc_id) const {
|
|
BreakpointLocationSP stop_sp;
|
|
collection::const_iterator pos =
|
|
GetIDPairConstIterator(break_id, break_loc_id);
|
|
if (pos != m_break_loc_collection.end())
|
|
stop_sp = *pos;
|
|
|
|
return stop_sp;
|
|
}
|
|
|
|
BreakpointLocationSP BreakpointLocationCollection::GetByIndex(size_t i) {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
BreakpointLocationSP stop_sp;
|
|
if (i < m_break_loc_collection.size())
|
|
stop_sp = m_break_loc_collection[i];
|
|
|
|
return stop_sp;
|
|
}
|
|
|
|
const BreakpointLocationSP
|
|
BreakpointLocationCollection::GetByIndex(size_t i) const {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
BreakpointLocationSP stop_sp;
|
|
if (i < m_break_loc_collection.size())
|
|
stop_sp = m_break_loc_collection[i];
|
|
|
|
return stop_sp;
|
|
}
|
|
|
|
bool BreakpointLocationCollection::ShouldStop(
|
|
StoppointCallbackContext *context,
|
|
BreakpointLocationCollection &stopped_bp_locs) {
|
|
bool shouldStop = false;
|
|
size_t i = 0;
|
|
size_t prev_size = GetSize();
|
|
while (i < prev_size) {
|
|
// ShouldStop can remove the breakpoint from the list, or even delete
|
|
// it, so we should
|
|
BreakpointLocationSP cur_loc_sp = GetByIndex(i);
|
|
BreakpointLocationSP reported_loc_sp;
|
|
BreakpointSP keep_bkpt_alive_sp = cur_loc_sp->GetBreakpoint().shared_from_this();
|
|
// We're building up the list or which locations claim responsibility for
|
|
// this stop. If the location's ShouldStop defers to a facade location by
|
|
// returning a non-null reported location, we want to use that. Otherwise
|
|
// use the original location.
|
|
if (cur_loc_sp->ShouldStop(context, reported_loc_sp)) {
|
|
if (reported_loc_sp)
|
|
stopped_bp_locs.Add(reported_loc_sp);
|
|
else
|
|
stopped_bp_locs.Add(cur_loc_sp);
|
|
|
|
shouldStop = true;
|
|
}
|
|
|
|
if (prev_size == GetSize())
|
|
i++;
|
|
prev_size = GetSize();
|
|
}
|
|
return shouldStop;
|
|
}
|
|
|
|
bool BreakpointLocationCollection::ValidForThisThread(Thread &thread) {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
collection::iterator pos, begin = m_break_loc_collection.begin(),
|
|
end = m_break_loc_collection.end();
|
|
|
|
for (pos = begin; pos != end; ++pos) {
|
|
if ((*pos)->ValidForThisThread(thread))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool BreakpointLocationCollection::IsInternal() const {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
collection::const_iterator pos, begin = m_break_loc_collection.begin(),
|
|
end = m_break_loc_collection.end();
|
|
|
|
bool is_internal = true;
|
|
|
|
for (pos = begin; pos != end; ++pos) {
|
|
if (!(*pos)->GetBreakpoint().IsInternal()) {
|
|
is_internal = false;
|
|
break;
|
|
}
|
|
}
|
|
return is_internal;
|
|
}
|
|
|
|
void BreakpointLocationCollection::GetDescription(
|
|
Stream *s, lldb::DescriptionLevel level) {
|
|
std::lock_guard<std::mutex> guard(m_collection_mutex);
|
|
collection::iterator pos, begin = m_break_loc_collection.begin(),
|
|
end = m_break_loc_collection.end();
|
|
|
|
for (pos = begin; pos != end; ++pos) {
|
|
if (pos != begin)
|
|
s->PutChar(' ');
|
|
(*pos)->GetDescription(s, level);
|
|
}
|
|
}
|
|
|
|
BreakpointLocationCollection &BreakpointLocationCollection::operator=(
|
|
const BreakpointLocationCollection &rhs) {
|
|
if (this != &rhs) {
|
|
std::lock(m_collection_mutex, rhs.m_collection_mutex);
|
|
std::lock_guard<std::mutex> lhs_guard(m_collection_mutex, std::adopt_lock);
|
|
std::lock_guard<std::mutex> rhs_guard(rhs.m_collection_mutex, std::adopt_lock);
|
|
m_break_loc_collection = rhs.m_break_loc_collection;
|
|
}
|
|
return *this;
|
|
}
|