Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,127 @@
//===-- BreakpointID.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
#include <stdio.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointID.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
BreakpointID::BreakpointID(break_id_t bp_id, break_id_t loc_id)
: m_break_id(bp_id), m_location_id(loc_id) {}
BreakpointID::~BreakpointID() = default;
static llvm::StringRef g_range_specifiers[] = {"-", "to", "To", "TO"};
// Tells whether or not STR is valid to use between two strings representing
// breakpoint IDs, to
// indicate a range of breakpoint IDs. This is broken out into a separate
// function so that we can
// easily change or add to the format for specifying ID ranges at a later date.
bool BreakpointID::IsRangeIdentifier(llvm::StringRef str) {
for (auto spec : g_range_specifiers) {
if (spec == str)
return true;
}
return false;
}
bool BreakpointID::IsValidIDExpression(llvm::StringRef str) {
return BreakpointID::ParseCanonicalReference(str).hasValue();
}
llvm::ArrayRef<llvm::StringRef> BreakpointID::GetRangeSpecifiers() {
return llvm::makeArrayRef(g_range_specifiers);
}
void BreakpointID::GetDescription(Stream *s, lldb::DescriptionLevel level) {
if (level == eDescriptionLevelVerbose)
s->Printf("%p BreakpointID:", static_cast<void *>(this));
if (m_break_id == LLDB_INVALID_BREAK_ID)
s->PutCString("<invalid>");
else if (m_location_id == LLDB_INVALID_BREAK_ID)
s->Printf("%i", m_break_id);
else
s->Printf("%i.%i", m_break_id, m_location_id);
}
void BreakpointID::GetCanonicalReference(Stream *s, break_id_t bp_id,
break_id_t loc_id) {
if (bp_id == LLDB_INVALID_BREAK_ID)
s->PutCString("<invalid>");
else if (loc_id == LLDB_INVALID_BREAK_ID)
s->Printf("%i", bp_id);
else
s->Printf("%i.%i", bp_id, loc_id);
}
llvm::Optional<BreakpointID>
BreakpointID::ParseCanonicalReference(llvm::StringRef input) {
break_id_t bp_id;
break_id_t loc_id = LLDB_INVALID_BREAK_ID;
if (input.empty())
return llvm::None;
// If it doesn't start with an integer, it's not valid.
if (input.consumeInteger(0, bp_id))
return llvm::None;
// period is optional, but if it exists, it must be followed by a number.
if (input.consume_front(".")) {
if (input.consumeInteger(0, loc_id))
return llvm::None;
}
// And at the end, the entire string must have been consumed.
if (!input.empty())
return llvm::None;
return BreakpointID(bp_id, loc_id);
}
bool BreakpointID::StringIsBreakpointName(llvm::StringRef str, Status &error) {
error.Clear();
if (str.empty())
{
error.SetErrorStringWithFormat("Empty breakpoint names are not allowed");
return false;
}
// First character must be a letter or _
if (!isalpha(str[0]) && str[0] != '_')
{
error.SetErrorStringWithFormat("Breakpoint names must start with a "
"character or underscore: %s",
str.str().c_str());
return false;
}
// Cannot contain ., -, or space.
if (str.find_first_of(".- ") != llvm::StringRef::npos) {
error.SetErrorStringWithFormat("Breakpoint names cannot contain "
"'.' or '-': \"%s\"",
str.str().c_str());
return false;
}
return true;
}

View File

@@ -0,0 +1,356 @@
//===-- BreakpointIDList.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-enumerations.h"
#include "lldb/Breakpoint/BreakpointIDList.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// class BreakpointIDList
//----------------------------------------------------------------------
BreakpointIDList::BreakpointIDList()
: m_invalid_id(LLDB_INVALID_BREAK_ID, LLDB_INVALID_BREAK_ID) {}
BreakpointIDList::~BreakpointIDList() = default;
size_t BreakpointIDList::GetSize() const { return m_breakpoint_ids.size(); }
const BreakpointID &
BreakpointIDList::GetBreakpointIDAtIndex(size_t index) const {
return ((index < m_breakpoint_ids.size()) ? m_breakpoint_ids[index]
: m_invalid_id);
}
bool BreakpointIDList::RemoveBreakpointIDAtIndex(size_t index) {
if (index >= m_breakpoint_ids.size())
return false;
m_breakpoint_ids.erase(m_breakpoint_ids.begin() + index);
return true;
}
void BreakpointIDList::Clear() { m_breakpoint_ids.clear(); }
bool BreakpointIDList::AddBreakpointID(BreakpointID bp_id) {
m_breakpoint_ids.push_back(bp_id);
return true; // We don't do any verification in this function, so always
// return true.
}
bool BreakpointIDList::AddBreakpointID(const char *bp_id_str) {
auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
if (!bp_id.hasValue())
return false;
m_breakpoint_ids.push_back(*bp_id);
return true;
}
bool BreakpointIDList::FindBreakpointID(BreakpointID &bp_id,
size_t *position) const {
for (size_t i = 0; i < m_breakpoint_ids.size(); ++i) {
BreakpointID tmp_id = m_breakpoint_ids[i];
if (tmp_id.GetBreakpointID() == bp_id.GetBreakpointID() &&
tmp_id.GetLocationID() == bp_id.GetLocationID()) {
*position = i;
return true;
}
}
return false;
}
bool BreakpointIDList::FindBreakpointID(const char *bp_id_str,
size_t *position) const {
auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
if (!bp_id.hasValue())
return false;
return FindBreakpointID(*bp_id, position);
}
void BreakpointIDList::InsertStringArray(const char **string_array,
size_t array_size,
CommandReturnObject &result) {
if (string_array == nullptr)
return;
for (uint32_t i = 0; i < array_size; ++i) {
auto bp_id = BreakpointID::ParseCanonicalReference(string_array[i]);
if (bp_id.hasValue())
m_breakpoint_ids.push_back(*bp_id);
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
// This function takes OLD_ARGS, which is usually the result of breaking the
// command string arguments into
// an array of space-separated strings, and searches through the arguments for
// any breakpoint ID range specifiers.
// Any string in the array that is not part of an ID range specifier is copied
// directly into NEW_ARGS. If any
// ID range specifiers are found, the range is interpreted and a list of
// canonical breakpoint IDs corresponding to
// all the current breakpoints and locations in the range are added to
// NEW_ARGS. When this function is done,
// NEW_ARGS should be a copy of OLD_ARGS, with and ID range specifiers replaced
// by the members of the range.
void BreakpointIDList::FindAndReplaceIDRanges(Args &old_args, Target *target,
bool allow_locations,
BreakpointName::Permissions
::PermissionKinds purpose,
CommandReturnObject &result,
Args &new_args) {
llvm::StringRef range_from;
llvm::StringRef range_to;
llvm::StringRef current_arg;
std::set<std::string> names_found;
for (size_t i = 0; i < old_args.size(); ++i) {
bool is_range = false;
current_arg = old_args[i].ref;
if (!allow_locations && current_arg.contains('.')) {
result.AppendErrorWithFormat(
"Breakpoint locations not allowed, saw location: %s.",
current_arg.str().c_str());
new_args.Clear();
return;
}
Status error;
std::tie(range_from, range_to) =
BreakpointIDList::SplitIDRangeExpression(current_arg);
if (!range_from.empty() && !range_to.empty()) {
is_range = true;
} else if (BreakpointID::StringIsBreakpointName(current_arg, error)) {
if (!error.Success()) {
new_args.Clear();
result.AppendError(error.AsCString());
result.SetStatus(eReturnStatusFailed);
return;
} else
names_found.insert(current_arg);
} else if ((i + 2 < old_args.size()) &&
BreakpointID::IsRangeIdentifier(old_args[i + 1].ref) &&
BreakpointID::IsValidIDExpression(current_arg) &&
BreakpointID::IsValidIDExpression(old_args[i + 2].ref)) {
range_from = current_arg;
range_to = old_args[i + 2].ref;
is_range = true;
i = i + 2;
} else {
// See if user has specified id.*
llvm::StringRef tmp_str = old_args[i].ref;
size_t pos = tmp_str.find('.');
if (pos != llvm::StringRef::npos) {
llvm::StringRef bp_id_str = tmp_str.substr(0, pos);
if (BreakpointID::IsValidIDExpression(bp_id_str) &&
tmp_str[pos + 1] == '*' && tmp_str.size() == (pos + 2)) {
BreakpointSP breakpoint_sp;
auto bp_id = BreakpointID::ParseCanonicalReference(bp_id_str);
if (bp_id.hasValue())
breakpoint_sp = target->GetBreakpointByID(bp_id->GetBreakpointID());
if (!breakpoint_sp) {
new_args.Clear();
result.AppendErrorWithFormat("'%d' is not a valid breakpoint ID.\n",
bp_id->GetBreakpointID());
result.SetStatus(eReturnStatusFailed);
return;
}
const size_t num_locations = breakpoint_sp->GetNumLocations();
for (size_t j = 0; j < num_locations; ++j) {
BreakpointLocation *bp_loc =
breakpoint_sp->GetLocationAtIndex(j).get();
StreamString canonical_id_str;
BreakpointID::GetCanonicalReference(
&canonical_id_str, bp_id->GetBreakpointID(), bp_loc->GetID());
new_args.AppendArgument(canonical_id_str.GetString());
}
}
}
}
if (!is_range) {
new_args.AppendArgument(current_arg);
continue;
}
auto start_bp = BreakpointID::ParseCanonicalReference(range_from);
auto end_bp = BreakpointID::ParseCanonicalReference(range_to);
if (!start_bp.hasValue() ||
!target->GetBreakpointByID(start_bp->GetBreakpointID())) {
new_args.Clear();
result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
range_from.str().c_str());
result.SetStatus(eReturnStatusFailed);
return;
}
if (!end_bp.hasValue() ||
!target->GetBreakpointByID(end_bp->GetBreakpointID())) {
new_args.Clear();
result.AppendErrorWithFormat("'%s' is not a valid breakpoint ID.\n",
range_to.str().c_str());
result.SetStatus(eReturnStatusFailed);
return;
}
break_id_t start_bp_id = start_bp->GetBreakpointID();
break_id_t start_loc_id = start_bp->GetLocationID();
break_id_t end_bp_id = end_bp->GetBreakpointID();
break_id_t end_loc_id = end_bp->GetLocationID();
if (((start_loc_id == LLDB_INVALID_BREAK_ID) &&
(end_loc_id != LLDB_INVALID_BREAK_ID)) ||
((start_loc_id != LLDB_INVALID_BREAK_ID) &&
(end_loc_id == LLDB_INVALID_BREAK_ID))) {
new_args.Clear();
result.AppendErrorWithFormat("Invalid breakpoint id range: Either "
"both ends of range must specify"
" a breakpoint location, or neither can "
"specify a breakpoint location.\n");
result.SetStatus(eReturnStatusFailed);
return;
}
// We have valid range starting & ending breakpoint IDs. Go through all
// the breakpoints in the target and find all the breakpoints that fit
// into this range, and add them to new_args.
// Next check to see if we have location id's. If so, make sure the
// start_bp_id and end_bp_id are for the same breakpoint; otherwise we
// have an illegal range: breakpoint id ranges that specify bp locations
// are NOT allowed to cross major bp id numbers.
if ((start_loc_id != LLDB_INVALID_BREAK_ID) ||
(end_loc_id != LLDB_INVALID_BREAK_ID)) {
if (start_bp_id != end_bp_id) {
new_args.Clear();
result.AppendErrorWithFormat(
"Invalid range: Ranges that specify particular breakpoint "
"locations"
" must be within the same major breakpoint; you specified two"
" different major breakpoints, %d and %d.\n",
start_bp_id, end_bp_id);
result.SetStatus(eReturnStatusFailed);
return;
}
}
const BreakpointList &breakpoints = target->GetBreakpointList();
const size_t num_breakpoints = breakpoints.GetSize();
for (size_t j = 0; j < num_breakpoints; ++j) {
Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(j).get();
break_id_t cur_bp_id = breakpoint->GetID();
if ((cur_bp_id < start_bp_id) || (cur_bp_id > end_bp_id))
continue;
const size_t num_locations = breakpoint->GetNumLocations();
if ((cur_bp_id == start_bp_id) &&
(start_loc_id != LLDB_INVALID_BREAK_ID)) {
for (size_t k = 0; k < num_locations; ++k) {
BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
if ((bp_loc->GetID() >= start_loc_id) &&
(bp_loc->GetID() <= end_loc_id)) {
StreamString canonical_id_str;
BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
bp_loc->GetID());
new_args.AppendArgument(canonical_id_str.GetString());
}
}
} else if ((cur_bp_id == end_bp_id) &&
(end_loc_id != LLDB_INVALID_BREAK_ID)) {
for (size_t k = 0; k < num_locations; ++k) {
BreakpointLocation *bp_loc = breakpoint->GetLocationAtIndex(k).get();
if (bp_loc->GetID() <= end_loc_id) {
StreamString canonical_id_str;
BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
bp_loc->GetID());
new_args.AppendArgument(canonical_id_str.GetString());
}
}
} else {
StreamString canonical_id_str;
BreakpointID::GetCanonicalReference(&canonical_id_str, cur_bp_id,
LLDB_INVALID_BREAK_ID);
new_args.AppendArgument(canonical_id_str.GetString());
}
}
}
// Okay, now see if we found any names, and if we did, add them:
if (target && !names_found.empty()) {
Status error;
// Remove any names that aren't visible for this purpose:
auto iter = names_found.begin();
while (iter != names_found.end()) {
BreakpointName *bp_name = target->FindBreakpointName(ConstString(*iter),
true,
error);
if (bp_name && !bp_name->GetPermission(purpose))
iter = names_found.erase(iter);
else
iter++;
}
if (!names_found.empty()) {
for (BreakpointSP bkpt_sp : target->GetBreakpointList().Breakpoints()) {
for (std::string name : names_found) {
if (bkpt_sp->MatchesName(name.c_str())) {
StreamString canonical_id_str;
BreakpointID::GetCanonicalReference(
&canonical_id_str, bkpt_sp->GetID(), LLDB_INVALID_BREAK_ID);
new_args.AppendArgument(canonical_id_str.GetString());
}
}
}
}
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
}
std::pair<llvm::StringRef, llvm::StringRef>
BreakpointIDList::SplitIDRangeExpression(llvm::StringRef in_string) {
for (auto specifier_str : BreakpointID::GetRangeSpecifiers()) {
size_t idx = in_string.find(specifier_str);
if (idx == llvm::StringRef::npos)
continue;
llvm::StringRef right1 = in_string.drop_front(idx);
llvm::StringRef from = in_string.take_front(idx);
llvm::StringRef to = right1.drop_front(specifier_str.size());
if (BreakpointID::IsValidIDExpression(from) &&
BreakpointID::IsValidIDExpression(to)) {
return std::make_pair(from, to);
}
}
return std::pair<llvm::StringRef, llvm::StringRef>();
}

View File

@@ -0,0 +1,251 @@
//===-- BreakpointList.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointList.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
BreakpointList::BreakpointList(bool is_internal)
: m_mutex(), m_breakpoints(), m_next_break_id(0),
m_is_internal(is_internal) {}
BreakpointList::~BreakpointList() {}
break_id_t BreakpointList::Add(BreakpointSP &bp_sp, bool notify) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Internal breakpoint IDs are negative, normal ones are positive
bp_sp->SetID(m_is_internal ? --m_next_break_id : ++m_next_break_id);
m_breakpoints.push_back(bp_sp);
if (notify) {
if (bp_sp->GetTarget().EventTypeHasListeners(
Target::eBroadcastBitBreakpointChanged))
bp_sp->GetTarget().BroadcastEvent(Target::eBroadcastBitBreakpointChanged,
new Breakpoint::BreakpointEventData(
eBreakpointEventTypeAdded, bp_sp));
}
return bp_sp->GetID();
}
bool BreakpointList::Remove(break_id_t break_id, bool notify) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
bp_collection::iterator pos = GetBreakpointIDIterator(break_id); // Predicate
if (pos != m_breakpoints.end()) {
BreakpointSP bp_sp(*pos);
m_breakpoints.erase(pos);
if (notify) {
if (bp_sp->GetTarget().EventTypeHasListeners(
Target::eBroadcastBitBreakpointChanged))
bp_sp->GetTarget().BroadcastEvent(
Target::eBroadcastBitBreakpointChanged,
new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
bp_sp));
}
return true;
}
return false;
}
void BreakpointList::RemoveInvalidLocations(const ArchSpec &arch) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
bp_sp->RemoveInvalidLocations(arch);
}
void BreakpointList::SetEnabledAll(bool enabled) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
bp_sp->SetEnabled(enabled);
}
void BreakpointList::SetEnabledAllowed(bool enabled) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
if (bp_sp->AllowDisable())
bp_sp->SetEnabled(enabled);
}
void BreakpointList::RemoveAll(bool notify) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
ClearAllBreakpointSites();
if (notify) {
bp_collection::iterator pos, end = m_breakpoints.end();
for (pos = m_breakpoints.begin(); pos != end; ++pos) {
if ((*pos)->GetTarget().EventTypeHasListeners(
Target::eBroadcastBitBreakpointChanged)) {
(*pos)->GetTarget().BroadcastEvent(
Target::eBroadcastBitBreakpointChanged,
new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
*pos));
}
}
}
m_breakpoints.erase(m_breakpoints.begin(), m_breakpoints.end());
}
void BreakpointList::RemoveAllowed(bool notify) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
bp_collection::iterator pos, end = m_breakpoints.end();
if (notify) {
for (pos = m_breakpoints.begin(); pos != end; ++pos) {
if(!(*pos)->AllowDelete())
continue;
if ((*pos)->GetTarget().EventTypeHasListeners(
Target::eBroadcastBitBreakpointChanged)) {
(*pos)->GetTarget().BroadcastEvent(
Target::eBroadcastBitBreakpointChanged,
new Breakpoint::BreakpointEventData(eBreakpointEventTypeRemoved,
*pos));
}
}
}
pos = m_breakpoints.begin();
while ( pos != end) {
if((*pos)->AllowDelete())
pos = m_breakpoints.erase(pos);
else
pos++;
}
}
class BreakpointIDMatches {
public:
BreakpointIDMatches(break_id_t break_id) : m_break_id(break_id) {}
bool operator()(const BreakpointSP &bp) const {
return m_break_id == bp->GetID();
}
private:
const break_id_t m_break_id;
};
BreakpointList::bp_collection::iterator
BreakpointList::GetBreakpointIDIterator(break_id_t break_id) {
return std::find_if(m_breakpoints.begin(),
m_breakpoints.end(), // Search full range
BreakpointIDMatches(break_id)); // Predicate
}
BreakpointList::bp_collection::const_iterator
BreakpointList::GetBreakpointIDConstIterator(break_id_t break_id) const {
return std::find_if(m_breakpoints.begin(),
m_breakpoints.end(), // Search full range
BreakpointIDMatches(break_id)); // Predicate
}
BreakpointSP BreakpointList::FindBreakpointByID(break_id_t break_id) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSP stop_sp;
bp_collection::iterator pos = GetBreakpointIDIterator(break_id);
if (pos != m_breakpoints.end())
stop_sp = *pos;
return stop_sp;
}
const BreakpointSP
BreakpointList::FindBreakpointByID(break_id_t break_id) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSP stop_sp;
bp_collection::const_iterator pos = GetBreakpointIDConstIterator(break_id);
if (pos != m_breakpoints.end())
stop_sp = *pos;
return stop_sp;
}
bool BreakpointList::FindBreakpointsByName(const char *name,
BreakpointList &matching_bps) {
Status error;
if (!name)
return false;
if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(name), error))
return false;
for (BreakpointSP bkpt_sp : Breakpoints()) {
if (bkpt_sp->MatchesName(name)) {
matching_bps.Add(bkpt_sp, false);
}
}
return true;
}
void BreakpointList::Dump(Stream *s) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
s->Printf("%p: ", static_cast<const void *>(this));
s->Indent();
s->Printf("BreakpointList with %u Breakpoints:\n",
(uint32_t)m_breakpoints.size());
s->IndentMore();
for (const auto &bp_sp : m_breakpoints)
bp_sp->Dump(s);
s->IndentLess();
}
BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSP stop_sp;
bp_collection::iterator end = m_breakpoints.end();
bp_collection::iterator pos;
size_t curr_i = 0;
for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
if (curr_i == i)
stop_sp = *pos;
}
return stop_sp;
}
const BreakpointSP BreakpointList::GetBreakpointAtIndex(size_t i) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSP stop_sp;
bp_collection::const_iterator end = m_breakpoints.end();
bp_collection::const_iterator pos;
size_t curr_i = 0;
for (pos = m_breakpoints.begin(), curr_i = 0; pos != end; ++pos, ++curr_i) {
if (curr_i == i)
stop_sp = *pos;
}
return stop_sp;
}
void BreakpointList::UpdateBreakpoints(ModuleList &module_list, bool added,
bool delete_locations) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
bp_sp->ModulesChanged(module_list, added, delete_locations);
}
void BreakpointList::UpdateBreakpointsWhenModuleIsReplaced(
ModuleSP old_module_sp, ModuleSP new_module_sp) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
bp_sp->ModuleReplaced(old_module_sp, new_module_sp);
}
void BreakpointList::ClearAllBreakpointSites() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (const auto &bp_sp : m_breakpoints)
bp_sp->ClearAllBreakpointSites();
}
void BreakpointList::GetListMutex(
std::unique_lock<std::recursive_mutex> &lock) {
lock = std::unique_lock<std::recursive_mutex>(m_mutex);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,185 @@
//===-- BreakpointLocationCollection.cpp ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#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()
: m_break_loc_collection(), m_collection_mutex() {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
BreakpointLocationCollection::~BreakpointLocationCollection() {}
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 std::find_if(
m_break_loc_collection.begin(),
m_break_loc_collection.end(), // 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 std::find_if(
m_break_loc_collection.begin(),
m_break_loc_collection.end(), // 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) {
bool shouldStop = false;
size_t i = 0;
size_t prev_size = GetSize();
while (i < prev_size) {
// ShouldStop can remove the breakpoint from the list
if (GetByIndex(i)->ShouldStop(context))
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);
}
}

View File

@@ -0,0 +1,310 @@
//===-- BreakpointLocationList.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocationList.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
using namespace lldb;
using namespace lldb_private;
BreakpointLocationList::BreakpointLocationList(Breakpoint &owner)
: m_owner(owner), m_locations(), m_address_to_location(), m_mutex(),
m_next_id(0), m_new_location_recorder(nullptr) {}
BreakpointLocationList::~BreakpointLocationList() = default;
BreakpointLocationSP
BreakpointLocationList::Create(const Address &addr,
bool resolve_indirect_symbols) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// The location ID is just the size of the location list + 1
lldb::break_id_t bp_loc_id = ++m_next_id;
BreakpointLocationSP bp_loc_sp(
new BreakpointLocation(bp_loc_id, m_owner, addr, LLDB_INVALID_THREAD_ID,
m_owner.IsHardware(), resolve_indirect_symbols));
m_locations.push_back(bp_loc_sp);
m_address_to_location[addr] = bp_loc_sp;
return bp_loc_sp;
}
bool BreakpointLocationList::ShouldStop(StoppointCallbackContext *context,
lldb::break_id_t break_id) {
BreakpointLocationSP bp = FindByID(break_id);
if (bp) {
// Let the BreakpointLocation decide if it should stop here (could not have
// reached it's target hit count yet, or it could have a callback
// that decided it shouldn't stop (shared library loads/unloads).
return bp->ShouldStop(context);
}
// We should stop here since this BreakpointLocation isn't valid anymore or it
// doesn't exist.
return true;
}
lldb::break_id_t BreakpointLocationList::FindIDByAddress(const Address &addr) {
BreakpointLocationSP bp_loc_sp = FindByAddress(addr);
if (bp_loc_sp) {
return bp_loc_sp->GetID();
}
return LLDB_INVALID_BREAK_ID;
}
static bool Compare(BreakpointLocationSP lhs, lldb::break_id_t val) {
return lhs->GetID() < val;
}
BreakpointLocationSP
BreakpointLocationList::FindByID(lldb::break_id_t break_id) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::const_iterator end = m_locations.end();
collection::const_iterator pos =
std::lower_bound(m_locations.begin(), end, break_id, Compare);
if (pos != end && (*pos)->GetID() == break_id)
return *(pos);
else
return BreakpointLocationSP();
}
size_t BreakpointLocationList::FindInModule(
Module *module, BreakpointLocationCollection &bp_loc_list) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
const size_t orig_size = bp_loc_list.GetSize();
collection::iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos) {
BreakpointLocationSP break_loc = (*pos);
SectionSP section_sp(break_loc->GetAddress().GetSection());
if (section_sp && section_sp->GetModule().get() == module) {
bp_loc_list.Add(break_loc);
}
}
return bp_loc_list.GetSize() - orig_size;
}
const BreakpointLocationSP
BreakpointLocationList::FindByAddress(const Address &addr) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointLocationSP bp_loc_sp;
if (!m_locations.empty()) {
Address so_addr;
if (addr.IsSectionOffset()) {
so_addr = addr;
} else {
// Try and resolve as a load address if possible.
m_owner.GetTarget().GetSectionLoadList().ResolveLoadAddress(
addr.GetOffset(), so_addr);
if (!so_addr.IsValid()) {
// The address didn't resolve, so just set to passed in addr.
so_addr = addr;
}
}
addr_map::const_iterator pos = m_address_to_location.find(so_addr);
if (pos != m_address_to_location.end())
bp_loc_sp = pos->second;
}
return bp_loc_sp;
}
void BreakpointLocationList::Dump(Stream *s) const {
s->Printf("%p: ", static_cast<const void *>(this));
// s->Indent();
std::lock_guard<std::recursive_mutex> guard(m_mutex);
s->Printf("BreakpointLocationList with %" PRIu64 " BreakpointLocations:\n",
(uint64_t)m_locations.size());
s->IndentMore();
collection::const_iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos)
(*pos).get()->Dump(s);
s->IndentLess();
}
BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointLocationSP bp_loc_sp;
if (i < m_locations.size())
bp_loc_sp = m_locations[i];
return bp_loc_sp;
}
const BreakpointLocationSP BreakpointLocationList::GetByIndex(size_t i) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointLocationSP bp_loc_sp;
if (i < m_locations.size())
bp_loc_sp = m_locations[i];
return bp_loc_sp;
}
void BreakpointLocationList::ClearAllBreakpointSites() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos)
(*pos)->ClearBreakpointSite();
}
void BreakpointLocationList::ResolveAllBreakpointSites() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos) {
if ((*pos)->IsEnabled())
(*pos)->ResolveBreakpointSite();
}
}
uint32_t BreakpointLocationList::GetHitCount() const {
uint32_t hit_count = 0;
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::const_iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos)
hit_count += (*pos)->GetHitCount();
return hit_count;
}
size_t BreakpointLocationList::GetNumResolvedLocations() const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
size_t resolve_count = 0;
collection::const_iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos) {
if ((*pos)->IsResolved())
++resolve_count;
}
return resolve_count;
}
void BreakpointLocationList::GetDescription(Stream *s,
lldb::DescriptionLevel level) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos) {
s->Printf(" ");
(*pos)->GetDescription(s, level);
}
}
BreakpointLocationSP BreakpointLocationList::AddLocation(
const Address &addr, bool resolve_indirect_symbols, bool *new_location) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (new_location)
*new_location = false;
BreakpointLocationSP bp_loc_sp(FindByAddress(addr));
if (!bp_loc_sp) {
bp_loc_sp = Create(addr, resolve_indirect_symbols);
if (bp_loc_sp) {
bp_loc_sp->ResolveBreakpointSite();
if (new_location)
*new_location = true;
if (m_new_location_recorder) {
m_new_location_recorder->Add(bp_loc_sp);
}
}
}
return bp_loc_sp;
}
void BreakpointLocationList::SwapLocation(
BreakpointLocationSP to_location_sp,
BreakpointLocationSP from_location_sp) {
if (!from_location_sp || !to_location_sp)
return;
m_address_to_location.erase(to_location_sp->GetAddress());
to_location_sp->SwapLocation(from_location_sp);
RemoveLocation(from_location_sp);
m_address_to_location[to_location_sp->GetAddress()] = to_location_sp;
to_location_sp->ResolveBreakpointSite();
}
bool BreakpointLocationList::RemoveLocation(
const lldb::BreakpointLocationSP &bp_loc_sp) {
if (bp_loc_sp) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_address_to_location.erase(bp_loc_sp->GetAddress());
collection::iterator pos, end = m_locations.end();
for (pos = m_locations.begin(); pos != end; ++pos) {
if ((*pos).get() == bp_loc_sp.get()) {
m_locations.erase(pos);
return true;
}
}
}
return false;
}
void BreakpointLocationList::RemoveInvalidLocations(const ArchSpec &arch) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
size_t idx = 0;
// Don't cache m_location.size() as it will change since we might
// remove locations from our vector...
while (idx < m_locations.size()) {
BreakpointLocation *bp_loc = m_locations[idx].get();
if (bp_loc->GetAddress().SectionWasDeleted()) {
// Section was deleted which means this breakpoint comes from a module
// that is no longer valid, so we should remove it.
m_locations.erase(m_locations.begin() + idx);
continue;
}
if (arch.IsValid()) {
ModuleSP module_sp(bp_loc->GetAddress().GetModule());
if (module_sp) {
if (!arch.IsCompatibleMatch(module_sp->GetArchitecture())) {
// The breakpoint was in a module whose architecture is no longer
// compatible with "arch", so we need to remove it
m_locations.erase(m_locations.begin() + idx);
continue;
}
}
}
// Only increment the index if we didn't remove the locations at index "idx"
++idx;
}
}
void BreakpointLocationList::StartRecordingNewLocations(
BreakpointLocationCollection &new_locations) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
assert(m_new_location_recorder == nullptr);
m_new_location_recorder = &new_locations;
}
void BreakpointLocationList::StopRecordingNewLocations() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_new_location_recorder = nullptr;
}
void BreakpointLocationList::Compact() {
lldb::break_id_t highest_id = 0;
for (BreakpointLocationSP loc_sp : m_locations) {
lldb::break_id_t cur_id = loc_sp->GetID();
if (cur_id > highest_id)
highest_id = cur_id;
}
m_next_id = highest_id;
}

View File

@@ -0,0 +1,91 @@
//===-- Breakpoint.cpp ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details->
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "llvm/Support/Casting.h"
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Breakpoint/BreakpointLocationCollection.h"
#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
const Flags::ValueType BreakpointName::Permissions::permissions_mask
[BreakpointName::Permissions::PermissionKinds::allPerms + 1] = {
(1u << 0),
(1u << 1),
(1u << 2),
(0x5u)
};
BreakpointName::BreakpointName(const ConstString &name, const Breakpoint &bkpt,
const char *help) :
m_name(name), m_options(bkpt.GetOptions())
{
SetHelp(help);
}
bool BreakpointName::Permissions::GetDescription(Stream *s,
lldb::DescriptionLevel level) {
if (!AnySet())
return false;
s->IndentMore();
s->Indent();
if (IsSet(listPerm))
s->Printf("list: %s", GetAllowList() ? "allowed" : "disallowed");
if (IsSet(disablePerm))
s->Printf("disable: %s", GetAllowDisable() ? "allowed" : "disallowed");
if (IsSet(deletePerm))
s->Printf("delete: %s", GetAllowDelete() ? "allowed" : "disallowed");
s->IndentLess();
return true;
}
bool BreakpointName::GetDescription(Stream *s, lldb::DescriptionLevel level) {
bool printed_any = false;
if (!m_help.empty())
s->Printf("Help: %s\n", m_help.c_str());
if (GetOptions().AnySet())
{
s->PutCString("Options: \n");
s->IndentMore();
s->Indent();
GetOptions().GetDescription(s, level);
printed_any = true;
s->IndentLess();
}
if (GetPermissions().AnySet())
{
s->PutCString("Permissions: \n");
s->IndentMore();
s->Indent();
GetPermissions().GetDescription(s, level);
printed_any = true;
s->IndentLess();
}
return printed_any;
}
void BreakpointName::ConfigureBreakpoint(lldb::BreakpointSP bp_sp)
{
bp_sp->GetOptions()->CopyOverSetOptions(GetOptions());
bp_sp->GetPermissions().MergeInto(GetPermissions());
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,323 @@
//===-- BreakpointResolver.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointResolver.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
// Have to include the other breakpoint resolver types here so the static create
// from StructuredData can call them.
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
#include "lldb/Breakpoint/BreakpointResolverName.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb_private;
using namespace lldb;
//----------------------------------------------------------------------
// BreakpointResolver:
//----------------------------------------------------------------------
const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
"SymbolName", "SourceRegex",
"Exception", "Unknown"};
const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
BreakpointResolver::OptionNames::LastOptionName)] = {
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
"LineNumber", "ModuleName", "NameMask", "Offset", "Regex",
"SectionName", "SkipPrologue", "SymbolNames"};
const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
if (type > LastKnownResolverType)
return g_ty_to_name[UnknownResolver];
return g_ty_to_name[type];
}
BreakpointResolver::ResolverTy
BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
for (size_t i = 0; i < LastKnownResolverType; i++) {
if (name == g_ty_to_name[i])
return (ResolverTy)i;
}
return UnknownResolver;
}
BreakpointResolver::BreakpointResolver(Breakpoint *bkpt,
const unsigned char resolverTy,
lldb::addr_t offset)
: m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
BreakpointResolver::~BreakpointResolver() {}
BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
const StructuredData::Dictionary &resolver_dict, Status &error) {
BreakpointResolverSP result_sp;
if (!resolver_dict.IsValid()) {
error.SetErrorString("Can't deserialize from an invalid data object.");
return result_sp;
}
llvm::StringRef subclass_name;
bool success = resolver_dict.GetValueForKeyAsString(
GetSerializationSubclassKey(), subclass_name);
if (!success) {
error.SetErrorStringWithFormat(
"Resolver data missing subclass resolver key");
return result_sp;
}
ResolverTy resolver_type = NameToResolverTy(subclass_name);
if (resolver_type == UnknownResolver) {
error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
subclass_name);
return result_sp;
}
StructuredData::Dictionary *subclass_options = nullptr;
success = resolver_dict.GetValueForKeyAsDictionary(
GetSerializationSubclassOptionsKey(), subclass_options);
if (!success || !subclass_options || !subclass_options->IsValid()) {
error.SetErrorString("Resolver data missing subclass options key.");
return result_sp;
}
lldb::addr_t offset;
success = subclass_options->GetValueForKeyAsInteger(
GetKey(OptionNames::Offset), offset);
if (!success) {
error.SetErrorString("Resolver data missing offset options key.");
return result_sp;
}
BreakpointResolver *resolver;
switch (resolver_type) {
case FileLineResolver:
resolver = BreakpointResolverFileLine::CreateFromStructuredData(
nullptr, *subclass_options, error);
break;
case AddressResolver:
resolver = BreakpointResolverAddress::CreateFromStructuredData(
nullptr, *subclass_options, error);
break;
case NameResolver:
resolver = BreakpointResolverName::CreateFromStructuredData(
nullptr, *subclass_options, error);
break;
case FileRegexResolver:
resolver = BreakpointResolverFileRegex::CreateFromStructuredData(
nullptr, *subclass_options, error);
break;
case ExceptionResolver:
error.SetErrorString("Exception resolvers are hard.");
break;
default:
llvm_unreachable("Should never get an unresolvable resolver type.");
}
if (!error.Success()) {
return result_sp;
} else {
// Add on the global offset option:
resolver->SetOffset(offset);
return BreakpointResolverSP(resolver);
}
}
StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
StructuredData::DictionarySP options_dict_sp) {
if (!options_dict_sp || !options_dict_sp->IsValid())
return StructuredData::DictionarySP();
StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
// Add the m_offset to the dictionary:
options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
return type_dict_sp;
}
void BreakpointResolver::SetBreakpoint(Breakpoint *bkpt) {
m_breakpoint = bkpt;
}
void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
ModuleList &modules) {
filter.SearchInModuleList(*this, modules);
}
void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
filter.Search(*this);
}
void BreakpointResolver::SetSCMatchesByLine(SearchFilter &filter,
SymbolContextList &sc_list,
bool skip_prologue,
llvm::StringRef log_ident) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
while (sc_list.GetSize() > 0) {
SymbolContextList tmp_sc_list;
unsigned current_idx = 0;
SymbolContext sc;
bool first_entry = true;
FileSpec match_file_spec;
FileSpec match_original_file_spec;
uint32_t closest_line_number = UINT32_MAX;
// Pull out the first entry, and all the others that match its file spec,
// and stuff them in the tmp list.
while (current_idx < sc_list.GetSize()) {
bool matches;
sc_list.GetContextAtIndex(current_idx, sc);
if (first_entry) {
match_file_spec = sc.line_entry.file;
match_original_file_spec = sc.line_entry.original_file;
matches = true;
first_entry = false;
} else
matches = ((sc.line_entry.file == match_file_spec) ||
(sc.line_entry.original_file == match_original_file_spec));
if (matches) {
tmp_sc_list.Append(sc);
sc_list.RemoveContextAtIndex(current_idx);
// ResolveSymbolContext will always return a number that is >= the line
// number you pass in.
// So the smaller line number is always better.
if (sc.line_entry.line < closest_line_number)
closest_line_number = sc.line_entry.line;
} else
current_idx++;
}
// Okay, we've found the closest line number match, now throw away all the
// others:
current_idx = 0;
while (current_idx < tmp_sc_list.GetSize()) {
if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
if (sc.line_entry.line != closest_line_number)
tmp_sc_list.RemoveContextAtIndex(current_idx);
else
current_idx++;
}
}
// Next go through and see if there are line table entries that are
// contiguous, and if so keep only the
// first of the contiguous range:
current_idx = 0;
std::map<Block *, lldb::addr_t> blocks_with_breakpoints;
while (current_idx < tmp_sc_list.GetSize()) {
if (tmp_sc_list.GetContextAtIndex(current_idx, sc)) {
if (blocks_with_breakpoints.find(sc.block) !=
blocks_with_breakpoints.end())
tmp_sc_list.RemoveContextAtIndex(current_idx);
else {
blocks_with_breakpoints.insert(std::pair<Block *, lldb::addr_t>(
sc.block, sc.line_entry.range.GetBaseAddress().GetFileAddress()));
current_idx++;
}
}
}
// and make breakpoints out of the closest line number match.
uint32_t tmp_sc_list_size = tmp_sc_list.GetSize();
for (uint32_t i = 0; i < tmp_sc_list_size; i++) {
if (tmp_sc_list.GetContextAtIndex(i, sc)) {
Address line_start = sc.line_entry.range.GetBaseAddress();
if (line_start.IsValid()) {
if (filter.AddressPasses(line_start)) {
// If the line number is before the prologue end, move it there...
bool skipped_prologue = false;
if (skip_prologue) {
if (sc.function) {
Address prologue_addr(
sc.function->GetAddressRange().GetBaseAddress());
if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
const uint32_t prologue_byte_size =
sc.function->GetPrologueByteSize();
if (prologue_byte_size) {
prologue_addr.Slide(prologue_byte_size);
if (filter.AddressPasses(prologue_addr)) {
skipped_prologue = true;
line_start = prologue_addr;
}
}
}
}
}
BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
if (log && bp_loc_sp && !m_breakpoint->IsInternal()) {
StreamString s;
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
log->Printf("Added location (skipped prologue: %s): %s \n",
skipped_prologue ? "yes" : "no", s.GetData());
}
} else if (log) {
log->Printf("Breakpoint %s at file address 0x%" PRIx64
" didn't pass the filter.\n",
log_ident.str().c_str(), line_start.GetFileAddress());
}
} else {
if (log)
log->Printf(
"error: Unable to set breakpoint %s at file address 0x%" PRIx64
"\n",
log_ident.str().c_str(), line_start.GetFileAddress());
}
}
}
}
}
BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
bool *new_location) {
loc_addr.Slide(m_offset);
return m_breakpoint->AddLocation(loc_addr, new_location);
}
void BreakpointResolver::SetOffset(lldb::addr_t offset) {
// There may already be an offset, so we are actually adjusting location
// addresses by the difference.
// lldb::addr_t slide = offset - m_offset;
// FIXME: We should go fix up all the already set locations for the new slide.
m_offset = offset;
}

View File

@@ -0,0 +1,195 @@
//===-- BreakpointResolverAddress.cpp ---------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Section.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// BreakpointResolverAddress:
//----------------------------------------------------------------------
BreakpointResolverAddress::BreakpointResolverAddress(
Breakpoint *bkpt, const Address &addr, const FileSpec &module_spec)
: BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS),
m_module_filespec(module_spec) {}
BreakpointResolverAddress::BreakpointResolverAddress(Breakpoint *bkpt,
const Address &addr)
: BreakpointResolver(bkpt, BreakpointResolver::AddressResolver),
m_addr(addr), m_resolved_addr(LLDB_INVALID_ADDRESS), m_module_filespec() {
}
BreakpointResolverAddress::~BreakpointResolverAddress() {}
BreakpointResolver *BreakpointResolverAddress::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
Status &error) {
llvm::StringRef module_name;
lldb::addr_t addr_offset;
FileSpec module_filespec;
bool success;
success = options_dict.GetValueForKeyAsInteger(
GetKey(OptionNames::AddressOffset), addr_offset);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find address offset entry.");
return nullptr;
}
Address address(addr_offset);
success = options_dict.HasKey(GetKey(OptionNames::ModuleName));
if (success) {
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::ModuleName), module_name);
if (!success) {
error.SetErrorString("BRA::CFSD: Couldn't read module name entry.");
return nullptr;
}
module_filespec.SetFile(module_name, false);
}
return new BreakpointResolverAddress(bkpt, address, module_filespec);
}
StructuredData::ObjectSP
BreakpointResolverAddress::SerializeToStructuredData() {
StructuredData::DictionarySP options_dict_sp(
new StructuredData::Dictionary());
SectionSP section_sp = m_addr.GetSection();
if (section_sp) {
ModuleSP module_sp = section_sp->GetModule();
ConstString module_name;
if (module_sp)
module_name.SetCString(module_name.GetCString());
options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
module_name.GetCString());
options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
m_addr.GetOffset());
} else {
options_dict_sp->AddIntegerItem(GetKey(OptionNames::AddressOffset),
m_addr.GetOffset());
if (m_module_filespec) {
options_dict_sp->AddStringItem(GetKey(OptionNames::ModuleName),
m_module_filespec.GetPath());
}
}
return WrapOptionsDict(options_dict_sp);
return StructuredData::ObjectSP();
}
void BreakpointResolverAddress::ResolveBreakpoint(SearchFilter &filter) {
// If the address is not section relative, then we should not try to
// re-resolve it, it is just some
// random address and we wouldn't know what to do on reload. But if it is
// section relative, we need to
// re-resolve it since the section it's in may have shifted on re-run.
bool re_resolve = false;
if (m_addr.GetSection() || m_module_filespec)
re_resolve = true;
else if (m_breakpoint->GetNumLocations() == 0)
re_resolve = true;
if (re_resolve)
BreakpointResolver::ResolveBreakpoint(filter);
}
void BreakpointResolverAddress::ResolveBreakpointInModules(
SearchFilter &filter, ModuleList &modules) {
// See comment in ResolveBreakpoint.
bool re_resolve = false;
if (m_addr.GetSection())
re_resolve = true;
else if (m_breakpoint->GetNumLocations() == 0)
re_resolve = true;
if (re_resolve)
BreakpointResolver::ResolveBreakpointInModules(filter, modules);
}
Searcher::CallbackReturn
BreakpointResolverAddress::SearchCallback(SearchFilter &filter,
SymbolContext &context, Address *addr,
bool containing) {
assert(m_breakpoint != NULL);
if (filter.AddressPasses(m_addr)) {
if (m_breakpoint->GetNumLocations() == 0) {
// If the address is just an offset, and we're given a module, see if we
// can find the appropriate module
// loaded in the binary, and fix up m_addr to use that.
if (!m_addr.IsSectionOffset() && m_module_filespec) {
Target &target = m_breakpoint->GetTarget();
ModuleSpec module_spec(m_module_filespec);
ModuleSP module_sp = target.GetImages().FindFirstModule(module_spec);
if (module_sp) {
Address tmp_address;
if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address))
m_addr = tmp_address;
}
}
m_resolved_addr = m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
BreakpointLocationSP bp_loc_sp(AddLocation(m_addr));
if (bp_loc_sp && !m_breakpoint->IsInternal()) {
StreamString s;
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
Log *log(
lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("Added location: %s\n", s.GetData());
}
} else {
BreakpointLocationSP loc_sp = m_breakpoint->GetLocationAtIndex(0);
lldb::addr_t cur_load_location =
m_addr.GetLoadAddress(&m_breakpoint->GetTarget());
if (cur_load_location != m_resolved_addr) {
m_resolved_addr = cur_load_location;
loc_sp->ClearBreakpointSite();
loc_sp->ResolveBreakpointSite();
}
}
}
return Searcher::eCallbackReturnStop;
}
Searcher::Depth BreakpointResolverAddress::GetDepth() {
return Searcher::eDepthTarget;
}
void BreakpointResolverAddress::GetDescription(Stream *s) {
s->PutCString("address = ");
m_addr.Dump(s, m_breakpoint->GetTarget().GetProcessSP().get(),
Address::DumpStyleModuleWithFileAddress,
Address::DumpStyleLoadAddress);
}
void BreakpointResolverAddress::Dump(Stream *s) const {}
lldb::BreakpointResolverSP
BreakpointResolverAddress::CopyForBreakpoint(Breakpoint &breakpoint) {
lldb::BreakpointResolverSP ret_sp(
new BreakpointResolverAddress(&breakpoint, m_addr));
return ret_sp;
}

View File

@@ -0,0 +1,237 @@
//===-- BreakpointResolverFileLine.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// BreakpointResolverFileLine:
//----------------------------------------------------------------------
BreakpointResolverFileLine::BreakpointResolverFileLine(
Breakpoint *bkpt, const FileSpec &file_spec, uint32_t line_no,
lldb::addr_t offset, bool check_inlines, bool skip_prologue,
bool exact_match)
: BreakpointResolver(bkpt, BreakpointResolver::FileLineResolver, offset),
m_file_spec(file_spec), m_line_number(line_no), m_inlines(check_inlines),
m_skip_prologue(skip_prologue), m_exact_match(exact_match) {}
BreakpointResolverFileLine::~BreakpointResolverFileLine() {}
BreakpointResolver *BreakpointResolverFileLine::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
Status &error) {
llvm::StringRef filename;
uint32_t line_no;
bool check_inlines;
bool skip_prologue;
bool exact_match;
bool success;
lldb::addr_t offset = 0;
success = options_dict.GetValueForKeyAsString(GetKey(OptionNames::FileName),
filename);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find filename entry.");
return nullptr;
}
success = options_dict.GetValueForKeyAsInteger(
GetKey(OptionNames::LineNumber), line_no);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find line number entry.");
return nullptr;
}
success = options_dict.GetValueForKeyAsBoolean(GetKey(OptionNames::Inlines),
check_inlines);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find check inlines entry.");
return nullptr;
}
success = options_dict.GetValueForKeyAsBoolean(
GetKey(OptionNames::SkipPrologue), skip_prologue);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find skip prologue entry.");
return nullptr;
}
success = options_dict.GetValueForKeyAsBoolean(
GetKey(OptionNames::ExactMatch), exact_match);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
return nullptr;
}
FileSpec file_spec(filename, false);
return new BreakpointResolverFileLine(bkpt, file_spec, line_no, offset,
check_inlines, skip_prologue,
exact_match);
}
StructuredData::ObjectSP
BreakpointResolverFileLine::SerializeToStructuredData() {
StructuredData::DictionarySP options_dict_sp(
new StructuredData::Dictionary());
options_dict_sp->AddStringItem(GetKey(OptionNames::FileName),
m_file_spec.GetPath());
options_dict_sp->AddIntegerItem(GetKey(OptionNames::LineNumber),
m_line_number);
options_dict_sp->AddBooleanItem(GetKey(OptionNames::Inlines), m_inlines);
options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
m_skip_prologue);
options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
m_exact_match);
return WrapOptionsDict(options_dict_sp);
}
// Filter the symbol context list to remove contexts where the line number was
// moved into a new function. We do this conservatively, so if e.g. we cannot
// resolve the function in the context (which can happen in case of
// line-table-only debug info), we leave the context as is. The trickiest part
// here is handling inlined functions -- in this case we need to make sure we
// look at the declaration line of the inlined function, NOT the function it was
// inlined into.
void BreakpointResolverFileLine::FilterContexts(SymbolContextList &sc_list) {
if (m_exact_match)
return; // Nothing to do. Contexts are precise.
Log * log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS);
for(uint32_t i = 0; i < sc_list.GetSize(); ++i) {
SymbolContext sc;
sc_list.GetContextAtIndex(i, sc);
if (! sc.block)
continue;
FileSpec file;
uint32_t line;
const Block *inline_block = sc.block->GetContainingInlinedBlock();
if (inline_block) {
const Declaration &inline_declaration = inline_block->GetInlinedFunctionInfo()->GetDeclaration();
if (!inline_declaration.IsValid())
continue;
file = inline_declaration.GetFile();
line = inline_declaration.GetLine();
} else if (sc.function)
sc.function->GetStartLineSourceInfo(file, line);
else
continue;
if (file != sc.line_entry.file) {
LLDB_LOG(log, "unexpected symbol context file {0}", sc.line_entry.file);
continue;
}
// Compare the requested line number with the line of the function
// declaration. In case of a function declared as:
//
// int
// foo()
// {
// ...
//
// the compiler will set the declaration line to the "foo" line, which is
// the reason why we have -1 here. This can fail in case of two inline
// functions defined back-to-back:
//
// inline int foo1() { ... }
// inline int foo2() { ... }
//
// but that's the best we can do for now.
const int decl_line_is_too_late_fudge = 1;
if (m_line_number < line - decl_line_is_too_late_fudge) {
LLDB_LOG(log, "removing symbol context at {0}:{1}", file, line);
sc_list.RemoveContextAtIndex(i);
--i;
}
}
}
Searcher::CallbackReturn
BreakpointResolverFileLine::SearchCallback(SearchFilter &filter,
SymbolContext &context,
Address *addr, bool containing) {
SymbolContextList sc_list;
assert(m_breakpoint != NULL);
// There is a tricky bit here. You can have two compilation units that
// #include the same file, and in one of them the function at m_line_number is
// used (and so code and a line entry for it is generated) but in the other it
// isn't. If we considered the CU's independently, then in the second
// inclusion, we'd move the breakpoint to the next function that actually
// generated code in the header file. That would end up being confusing. So
// instead, we do the CU iterations by hand here, then scan through the
// complete list of matches, and figure out the closest line number match, and
// only set breakpoints on that match.
// Note also that if file_spec only had a file name and not a directory, there
// may be many different file spec's in the resultant list. The closest line
// match for one will not be right for some totally different file. So we go
// through the match list and pull out the sets that have the same file spec
// in their line_entry and treat each set separately.
const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
for (size_t i = 0; i < num_comp_units; i++) {
CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
if (cu_sp) {
if (filter.CompUnitPasses(*cu_sp))
cu_sp->ResolveSymbolContext(m_file_spec, m_line_number, m_inlines,
m_exact_match, eSymbolContextEverything,
sc_list);
}
}
FilterContexts(sc_list);
StreamString s;
s.Printf("for %s:%d ", m_file_spec.GetFilename().AsCString("<Unknown>"),
m_line_number);
SetSCMatchesByLine(filter, sc_list, m_skip_prologue, s.GetString());
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth BreakpointResolverFileLine::GetDepth() {
return Searcher::eDepthModule;
}
void BreakpointResolverFileLine::GetDescription(Stream *s) {
s->Printf("file = '%s', line = %u, exact_match = %d",
m_file_spec.GetPath().c_str(), m_line_number, m_exact_match);
}
void BreakpointResolverFileLine::Dump(Stream *s) const {}
lldb::BreakpointResolverSP
BreakpointResolverFileLine::CopyForBreakpoint(Breakpoint &breakpoint) {
lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileLine(
&breakpoint, m_file_spec, m_line_number, m_offset, m_inlines,
m_skip_prologue, m_exact_match));
return ret_sp;
}

View File

@@ -0,0 +1,180 @@
//===-- BreakpointResolverFileRegex.cpp -------------------------*- C++-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// BreakpointResolverFileRegex:
//----------------------------------------------------------------------
BreakpointResolverFileRegex::BreakpointResolverFileRegex(
Breakpoint *bkpt, RegularExpression &regex,
const std::unordered_set<std::string> &func_names, bool exact_match)
: BreakpointResolver(bkpt, BreakpointResolver::FileRegexResolver),
m_regex(regex), m_exact_match(exact_match), m_function_names(func_names) {
}
BreakpointResolverFileRegex::~BreakpointResolverFileRegex() {}
BreakpointResolver *BreakpointResolverFileRegex::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
Status &error) {
bool success;
llvm::StringRef regex_string;
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::RegexString), regex_string);
if (!success) {
error.SetErrorString("BRFR::CFSD: Couldn't find regex entry.");
return nullptr;
}
RegularExpression regex(regex_string);
bool exact_match;
success = options_dict.GetValueForKeyAsBoolean(
GetKey(OptionNames::ExactMatch), exact_match);
if (!success) {
error.SetErrorString("BRFL::CFSD: Couldn't find exact match entry.");
return nullptr;
}
// The names array is optional:
std::unordered_set<std::string> names_set;
StructuredData::Array *names_array;
success = options_dict.GetValueForKeyAsArray(
GetKey(OptionNames::SymbolNameArray), names_array);
if (success && names_array) {
size_t num_names = names_array->GetSize();
for (size_t i = 0; i < num_names; i++) {
llvm::StringRef name;
success = names_array->GetItemAtIndexAsString(i, name);
if (!success) {
error.SetErrorStringWithFormat(
"BRFR::CFSD: Malformed element %zu in the names array.", i);
return nullptr;
}
names_set.insert(name);
}
}
return new BreakpointResolverFileRegex(bkpt, regex, names_set, exact_match);
}
StructuredData::ObjectSP
BreakpointResolverFileRegex::SerializeToStructuredData() {
StructuredData::DictionarySP options_dict_sp(
new StructuredData::Dictionary());
options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
m_regex.GetText());
options_dict_sp->AddBooleanItem(GetKey(OptionNames::ExactMatch),
m_exact_match);
if (!m_function_names.empty()) {
StructuredData::ArraySP names_array_sp(new StructuredData::Array());
for (std::string name : m_function_names) {
StructuredData::StringSP item(new StructuredData::String(name));
names_array_sp->AddItem(item);
}
options_dict_sp->AddItem(GetKey(OptionNames::LineNumber), names_array_sp);
}
return WrapOptionsDict(options_dict_sp);
}
Searcher::CallbackReturn
BreakpointResolverFileRegex::SearchCallback(SearchFilter &filter,
SymbolContext &context,
Address *addr, bool containing) {
assert(m_breakpoint != NULL);
if (!context.target_sp)
return eCallbackReturnContinue;
CompileUnit *cu = context.comp_unit;
FileSpec cu_file_spec = *(static_cast<FileSpec *>(cu));
std::vector<uint32_t> line_matches;
context.target_sp->GetSourceManager().FindLinesMatchingRegex(
cu_file_spec, m_regex, 1, UINT32_MAX, line_matches);
uint32_t num_matches = line_matches.size();
for (uint32_t i = 0; i < num_matches; i++) {
SymbolContextList sc_list;
const bool search_inlines = false;
cu->ResolveSymbolContext(cu_file_spec, line_matches[i], search_inlines,
m_exact_match, eSymbolContextEverything, sc_list);
// Find all the function names:
if (!m_function_names.empty()) {
std::vector<size_t> sc_to_remove;
for (size_t i = 0; i < sc_list.GetSize(); i++) {
SymbolContext sc_ctx;
sc_list.GetContextAtIndex(i, sc_ctx);
std::string name(
sc_ctx
.GetFunctionName(
Mangled::NamePreference::ePreferDemangledWithoutArguments)
.AsCString());
if (!m_function_names.count(name)) {
sc_to_remove.push_back(i);
}
}
if (!sc_to_remove.empty()) {
std::vector<size_t>::reverse_iterator iter;
std::vector<size_t>::reverse_iterator rend = sc_to_remove.rend();
for (iter = sc_to_remove.rbegin(); iter != rend; iter++) {
sc_list.RemoveContextAtIndex(*iter);
}
}
}
const bool skip_prologue = true;
BreakpointResolver::SetSCMatchesByLine(filter, sc_list, skip_prologue,
m_regex.GetText());
}
assert(m_breakpoint != NULL);
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth BreakpointResolverFileRegex::GetDepth() {
return Searcher::eDepthCompUnit;
}
void BreakpointResolverFileRegex::GetDescription(Stream *s) {
s->Printf("source regex = \"%s\", exact_match = %d",
m_regex.GetText().str().c_str(), m_exact_match);
}
void BreakpointResolverFileRegex::Dump(Stream *s) const {}
lldb::BreakpointResolverSP
BreakpointResolverFileRegex::CopyForBreakpoint(Breakpoint &breakpoint) {
lldb::BreakpointResolverSP ret_sp(new BreakpointResolverFileRegex(
&breakpoint, m_regex, m_function_names, m_exact_match));
return ret_sp;
}
void BreakpointResolverFileRegex::AddFunctionName(const char *func_name) {
m_function_names.insert(func_name);
}

View File

@@ -0,0 +1,424 @@
//===-- BreakpointResolverName.cpp ------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointResolverName.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
using namespace lldb;
using namespace lldb_private;
BreakpointResolverName::BreakpointResolverName(
Breakpoint *bkpt, const char *name_cstr, uint32_t name_type_mask,
LanguageType language, Breakpoint::MatchType type, lldb::addr_t offset,
bool skip_prologue)
: BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
m_class_name(), m_regex(), m_match_type(type), m_language(language),
m_skip_prologue(skip_prologue) {
if (m_match_type == Breakpoint::Regexp) {
if (!m_regex.Compile(llvm::StringRef::withNullAsEmpty(name_cstr))) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Warning("function name regexp: \"%s\" did not compile.",
name_cstr);
}
} else {
AddNameLookup(ConstString(name_cstr), name_type_mask);
}
}
BreakpointResolverName::BreakpointResolverName(
Breakpoint *bkpt, const char *names[], size_t num_names,
uint32_t name_type_mask, LanguageType language, lldb::addr_t offset,
bool skip_prologue)
: BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
m_match_type(Breakpoint::Exact), m_language(language),
m_skip_prologue(skip_prologue) {
for (size_t i = 0; i < num_names; i++) {
AddNameLookup(ConstString(names[i]), name_type_mask);
}
}
BreakpointResolverName::BreakpointResolverName(
Breakpoint *bkpt, std::vector<std::string> names, uint32_t name_type_mask,
LanguageType language, lldb::addr_t offset, bool skip_prologue)
: BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
m_match_type(Breakpoint::Exact), m_language(language),
m_skip_prologue(skip_prologue) {
for (const std::string &name : names) {
AddNameLookup(ConstString(name.c_str(), name.size()), name_type_mask);
}
}
BreakpointResolverName::BreakpointResolverName(Breakpoint *bkpt,
RegularExpression &func_regex,
lldb::LanguageType language,
lldb::addr_t offset,
bool skip_prologue)
: BreakpointResolver(bkpt, BreakpointResolver::NameResolver, offset),
m_class_name(nullptr), m_regex(func_regex),
m_match_type(Breakpoint::Regexp), m_language(language),
m_skip_prologue(skip_prologue) {}
BreakpointResolverName::~BreakpointResolverName() = default;
BreakpointResolverName::BreakpointResolverName(
const BreakpointResolverName &rhs)
: BreakpointResolver(rhs.m_breakpoint, BreakpointResolver::NameResolver,
rhs.m_offset),
m_lookups(rhs.m_lookups), m_class_name(rhs.m_class_name),
m_regex(rhs.m_regex), m_match_type(rhs.m_match_type),
m_language(rhs.m_language), m_skip_prologue(rhs.m_skip_prologue) {}
BreakpointResolver *BreakpointResolverName::CreateFromStructuredData(
Breakpoint *bkpt, const StructuredData::Dictionary &options_dict,
Status &error) {
LanguageType language = eLanguageTypeUnknown;
llvm::StringRef language_name;
bool success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::LanguageName), language_name);
if (success) {
language = Language::GetLanguageTypeFromString(language_name);
if (language == eLanguageTypeUnknown) {
error.SetErrorStringWithFormatv("BRN::CFSD: Unknown language: {0}.",
language_name);
return nullptr;
}
}
lldb::addr_t offset = 0;
success =
options_dict.GetValueForKeyAsInteger(GetKey(OptionNames::Offset), offset);
if (!success) {
error.SetErrorStringWithFormat("BRN::CFSD: Missing offset entry.");
return nullptr;
}
bool skip_prologue;
success = options_dict.GetValueForKeyAsBoolean(
GetKey(OptionNames::SkipPrologue), skip_prologue);
if (!success) {
error.SetErrorStringWithFormat("BRN::CFSD: Missing Skip prologue entry.");
return nullptr;
}
llvm::StringRef regex_text;
success = options_dict.GetValueForKeyAsString(
GetKey(OptionNames::RegexString), regex_text);
if (success) {
RegularExpression regex(regex_text);
return new BreakpointResolverName(bkpt, regex, language, offset,
skip_prologue);
} else {
StructuredData::Array *names_array;
success = options_dict.GetValueForKeyAsArray(
GetKey(OptionNames::SymbolNameArray), names_array);
if (!success) {
error.SetErrorStringWithFormat("BRN::CFSD: Missing symbol names entry.");
return nullptr;
}
StructuredData::Array *names_mask_array;
success = options_dict.GetValueForKeyAsArray(
GetKey(OptionNames::NameMaskArray), names_mask_array);
if (!success) {
error.SetErrorStringWithFormat(
"BRN::CFSD: Missing symbol names mask entry.");
return nullptr;
}
size_t num_elem = names_array->GetSize();
if (num_elem != names_mask_array->GetSize()) {
error.SetErrorString(
"BRN::CFSD: names and names mask arrays have different sizes.");
return nullptr;
}
if (num_elem == 0) {
error.SetErrorString(
"BRN::CFSD: no name entry in a breakpoint by name breakpoint.");
return nullptr;
}
std::vector<std::string> names;
std::vector<uint32_t> name_masks;
for (size_t i = 0; i < num_elem; i++) {
uint32_t name_mask;
llvm::StringRef name;
success = names_array->GetItemAtIndexAsString(i, name);
if (!success) {
error.SetErrorString("BRN::CFSD: name entry is not a string.");
return nullptr;
}
success = names_mask_array->GetItemAtIndexAsInteger(i, name_mask);
if (!success) {
error.SetErrorString("BRN::CFSD: name mask entry is not an integer.");
return nullptr;
}
names.push_back(name);
name_masks.push_back(name_mask);
}
BreakpointResolverName *resolver = new BreakpointResolverName(
bkpt, names[0].c_str(), name_masks[0], language,
Breakpoint::MatchType::Exact, offset, skip_prologue);
for (size_t i = 1; i < num_elem; i++) {
resolver->AddNameLookup(ConstString(names[i]), name_masks[i]);
}
return resolver;
}
}
StructuredData::ObjectSP BreakpointResolverName::SerializeToStructuredData() {
StructuredData::DictionarySP options_dict_sp(
new StructuredData::Dictionary());
if (m_regex.IsValid()) {
options_dict_sp->AddStringItem(GetKey(OptionNames::RegexString),
m_regex.GetText());
} else {
StructuredData::ArraySP names_sp(new StructuredData::Array());
StructuredData::ArraySP name_masks_sp(new StructuredData::Array());
for (auto lookup : m_lookups) {
names_sp->AddItem(StructuredData::StringSP(
new StructuredData::String(lookup.GetName().AsCString())));
name_masks_sp->AddItem(StructuredData::IntegerSP(
new StructuredData::Integer(lookup.GetNameTypeMask())));
}
options_dict_sp->AddItem(GetKey(OptionNames::SymbolNameArray), names_sp);
options_dict_sp->AddItem(GetKey(OptionNames::NameMaskArray), name_masks_sp);
}
if (m_language != eLanguageTypeUnknown)
options_dict_sp->AddStringItem(
GetKey(OptionNames::LanguageName),
Language::GetNameForLanguageType(m_language));
options_dict_sp->AddBooleanItem(GetKey(OptionNames::SkipPrologue),
m_skip_prologue);
return WrapOptionsDict(options_dict_sp);
}
void BreakpointResolverName::AddNameLookup(const ConstString &name,
uint32_t name_type_mask) {
ObjCLanguage::MethodName objc_method(name.GetCString(), false);
if (objc_method.IsValid(false)) {
std::vector<ConstString> objc_names;
objc_method.GetFullNames(objc_names, true);
for (ConstString objc_name : objc_names) {
Module::LookupInfo lookup;
lookup.SetName(name);
lookup.SetLookupName(objc_name);
lookup.SetNameTypeMask(eFunctionNameTypeFull);
m_lookups.push_back(lookup);
}
} else {
Module::LookupInfo lookup(name, name_type_mask, m_language);
m_lookups.push_back(lookup);
}
}
// FIXME: Right now we look at the module level, and call the module's
// "FindFunctions".
// Greg says he will add function tables, maybe at the CompileUnit level to
// accelerate function
// lookup. At that point, we should switch the depth to CompileUnit, and look
// in these tables.
Searcher::CallbackReturn
BreakpointResolverName::SearchCallback(SearchFilter &filter,
SymbolContext &context, Address *addr,
bool containing) {
SymbolContextList func_list;
// SymbolContextList sym_list;
uint32_t i;
bool new_location;
Address break_addr;
assert(m_breakpoint != nullptr);
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (m_class_name) {
if (log)
log->Warning("Class/method function specification not supported yet.\n");
return Searcher::eCallbackReturnStop;
}
bool filter_by_cu =
(filter.GetFilterRequiredItems() & eSymbolContextCompUnit) != 0;
bool filter_by_language = (m_language != eLanguageTypeUnknown);
const bool include_symbols = !filter_by_cu;
const bool include_inlines = true;
const bool append = true;
switch (m_match_type) {
case Breakpoint::Exact:
if (context.module_sp) {
for (const auto &lookup : m_lookups) {
const size_t start_func_idx = func_list.GetSize();
context.module_sp->FindFunctions(
lookup.GetLookupName(), nullptr, lookup.GetNameTypeMask(),
include_symbols, include_inlines, append, func_list);
const size_t end_func_idx = func_list.GetSize();
if (start_func_idx < end_func_idx)
lookup.Prune(func_list, start_func_idx);
}
}
break;
case Breakpoint::Regexp:
if (context.module_sp) {
context.module_sp->FindFunctions(
m_regex,
!filter_by_cu, // include symbols only if we aren't filtering by CU
include_inlines, append, func_list);
}
break;
case Breakpoint::Glob:
if (log)
log->Warning("glob is not supported yet.");
break;
}
// If the filter specifies a Compilation Unit, remove the ones that don't pass
// at this point.
if (filter_by_cu || filter_by_language) {
uint32_t num_functions = func_list.GetSize();
for (size_t idx = 0; idx < num_functions; idx++) {
bool remove_it = false;
SymbolContext sc;
func_list.GetContextAtIndex(idx, sc);
if (filter_by_cu) {
if (!sc.comp_unit || !filter.CompUnitPasses(*sc.comp_unit))
remove_it = true;
}
if (filter_by_language) {
LanguageType sym_language = sc.GetLanguage();
if ((Language::GetPrimaryLanguage(sym_language) !=
Language::GetPrimaryLanguage(m_language)) &&
(sym_language != eLanguageTypeUnknown)) {
remove_it = true;
}
}
if (remove_it) {
func_list.RemoveContextAtIndex(idx);
num_functions--;
idx--;
}
}
}
// Remove any duplicates between the function list and the symbol list
SymbolContext sc;
if (func_list.GetSize()) {
for (i = 0; i < func_list.GetSize(); i++) {
if (func_list.GetContextAtIndex(i, sc)) {
bool is_reexported = false;
if (sc.block && sc.block->GetInlinedFunctionInfo()) {
if (!sc.block->GetStartAddress(break_addr))
break_addr.Clear();
} else if (sc.function) {
break_addr = sc.function->GetAddressRange().GetBaseAddress();
if (m_skip_prologue && break_addr.IsValid()) {
const uint32_t prologue_byte_size =
sc.function->GetPrologueByteSize();
if (prologue_byte_size)
break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
}
} else if (sc.symbol) {
if (sc.symbol->GetType() == eSymbolTypeReExported) {
const Symbol *actual_symbol =
sc.symbol->ResolveReExportedSymbol(m_breakpoint->GetTarget());
if (actual_symbol) {
is_reexported = true;
break_addr = actual_symbol->GetAddress();
}
} else {
break_addr = sc.symbol->GetAddress();
}
if (m_skip_prologue && break_addr.IsValid()) {
const uint32_t prologue_byte_size =
sc.symbol->GetPrologueByteSize();
if (prologue_byte_size)
break_addr.SetOffset(break_addr.GetOffset() + prologue_byte_size);
}
}
if (break_addr.IsValid()) {
if (filter.AddressPasses(break_addr)) {
BreakpointLocationSP bp_loc_sp(
AddLocation(break_addr, &new_location));
bp_loc_sp->SetIsReExported(is_reexported);
if (bp_loc_sp && new_location && !m_breakpoint->IsInternal()) {
if (log) {
StreamString s;
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
log->Printf("Added location: %s\n", s.GetData());
}
}
}
}
}
}
}
return Searcher::eCallbackReturnContinue;
}
Searcher::Depth BreakpointResolverName::GetDepth() {
return Searcher::eDepthModule;
}
void BreakpointResolverName::GetDescription(Stream *s) {
if (m_match_type == Breakpoint::Regexp)
s->Printf("regex = '%s'", m_regex.GetText().str().c_str());
else {
size_t num_names = m_lookups.size();
if (num_names == 1)
s->Printf("name = '%s'", m_lookups[0].GetName().GetCString());
else {
s->Printf("names = {");
for (size_t i = 0; i < num_names; i++) {
s->Printf("%s'%s'", (i == 0 ? "" : ", "),
m_lookups[i].GetName().GetCString());
}
s->Printf("}");
}
}
if (m_language != eLanguageTypeUnknown) {
s->Printf(", language = %s", Language::GetNameForLanguageType(m_language));
}
}
void BreakpointResolverName::Dump(Stream *s) const {}
lldb::BreakpointResolverSP
BreakpointResolverName::CopyForBreakpoint(Breakpoint &breakpoint) {
lldb::BreakpointResolverSP ret_sp(new BreakpointResolverName(*this));
ret_sp->SetBreakpoint(&breakpoint);
return ret_sp;
}

View File

@@ -0,0 +1,203 @@
//===-- BreakpointSite.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
#include <inttypes.h>
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointSite.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/BreakpointSiteList.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
BreakpointSite::BreakpointSite(BreakpointSiteList *list,
const BreakpointLocationSP &owner,
lldb::addr_t addr, bool use_hardware)
: StoppointLocation(GetNextID(), addr, 0, use_hardware),
m_type(eSoftware), // Process subclasses need to set this correctly using
// SetType()
m_saved_opcode(), m_trap_opcode(),
m_enabled(false), // Need to create it disabled, so the first enable turns
// it on.
m_owners(), m_owners_mutex() {
m_owners.Add(owner);
}
BreakpointSite::~BreakpointSite() {
BreakpointLocationSP bp_loc_sp;
const size_t owner_count = m_owners.GetSize();
for (size_t i = 0; i < owner_count; i++) {
m_owners.GetByIndex(i)->ClearBreakpointSite();
}
}
break_id_t BreakpointSite::GetNextID() {
static break_id_t g_next_id = 0;
return ++g_next_id;
}
// RETURNS - true if we should stop at this breakpoint, false if we
// should continue.
bool BreakpointSite::ShouldStop(StoppointCallbackContext *context) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
IncrementHitCount();
return m_owners.ShouldStop(context);
}
bool BreakpointSite::IsBreakpointAtThisSite(lldb::break_id_t bp_id) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
const size_t owner_count = m_owners.GetSize();
for (size_t i = 0; i < owner_count; i++) {
if (m_owners.GetByIndex(i)->GetBreakpoint().GetID() == bp_id)
return true;
}
return false;
}
void BreakpointSite::Dump(Stream *s) const {
if (s == nullptr)
return;
s->Printf("BreakpointSite %u: addr = 0x%8.8" PRIx64
" type = %s breakpoint hw_index = %i hit_count = %-4u",
GetID(), (uint64_t)m_addr, IsHardware() ? "hardware" : "software",
GetHardwareIndex(), GetHitCount());
}
void BreakpointSite::GetDescription(Stream *s, lldb::DescriptionLevel level) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
if (level != lldb::eDescriptionLevelBrief)
s->Printf("breakpoint site: %d at 0x%8.8" PRIx64, GetID(),
GetLoadAddress());
m_owners.GetDescription(s, level);
}
bool BreakpointSite::IsInternal() const { return m_owners.IsInternal(); }
uint8_t *BreakpointSite::GetTrapOpcodeBytes() { return &m_trap_opcode[0]; }
const uint8_t *BreakpointSite::GetTrapOpcodeBytes() const {
return &m_trap_opcode[0];
}
size_t BreakpointSite::GetTrapOpcodeMaxByteSize() const {
return sizeof(m_trap_opcode);
}
bool BreakpointSite::SetTrapOpcode(const uint8_t *trap_opcode,
uint32_t trap_opcode_size) {
if (trap_opcode_size > 0 && trap_opcode_size <= sizeof(m_trap_opcode)) {
m_byte_size = trap_opcode_size;
::memcpy(m_trap_opcode, trap_opcode, trap_opcode_size);
return true;
}
m_byte_size = 0;
return false;
}
uint8_t *BreakpointSite::GetSavedOpcodeBytes() { return &m_saved_opcode[0]; }
const uint8_t *BreakpointSite::GetSavedOpcodeBytes() const {
return &m_saved_opcode[0];
}
bool BreakpointSite::IsEnabled() const { return m_enabled; }
void BreakpointSite::SetEnabled(bool enabled) { m_enabled = enabled; }
void BreakpointSite::AddOwner(const BreakpointLocationSP &owner) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
m_owners.Add(owner);
}
size_t BreakpointSite::RemoveOwner(lldb::break_id_t break_id,
lldb::break_id_t break_loc_id) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
m_owners.Remove(break_id, break_loc_id);
return m_owners.GetSize();
}
size_t BreakpointSite::GetNumberOfOwners() {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
return m_owners.GetSize();
}
BreakpointLocationSP BreakpointSite::GetOwnerAtIndex(size_t index) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
return m_owners.GetByIndex(index);
}
bool BreakpointSite::ValidForThisThread(Thread *thread) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
return m_owners.ValidForThisThread(thread);
}
void BreakpointSite::BumpHitCounts() {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
loc_sp->BumpHitCount();
}
}
bool BreakpointSite::IntersectsRange(lldb::addr_t addr, size_t size,
lldb::addr_t *intersect_addr,
size_t *intersect_size,
size_t *opcode_offset) const {
// We only use software traps for software breakpoints
if (!IsHardware()) {
if (m_byte_size > 0) {
const lldb::addr_t bp_end_addr = m_addr + m_byte_size;
const lldb::addr_t end_addr = addr + size;
// Is the breakpoint end address before the passed in start address?
if (bp_end_addr <= addr)
return false;
// Is the breakpoint start address after passed in end address?
if (end_addr <= m_addr)
return false;
if (intersect_addr || intersect_size || opcode_offset) {
if (m_addr < addr) {
if (intersect_addr)
*intersect_addr = addr;
if (intersect_size)
*intersect_size =
std::min<lldb::addr_t>(bp_end_addr, end_addr) - addr;
if (opcode_offset)
*opcode_offset = addr - m_addr;
} else {
if (intersect_addr)
*intersect_addr = m_addr;
if (intersect_size)
*intersect_size =
std::min<lldb::addr_t>(bp_end_addr, end_addr) - m_addr;
if (opcode_offset)
*opcode_offset = 0;
}
}
return true;
}
}
return false;
}
size_t
BreakpointSite::CopyOwnersList(BreakpointLocationCollection &out_collection) {
std::lock_guard<std::recursive_mutex> guard(m_owners_mutex);
for (BreakpointLocationSP loc_sp : m_owners.BreakpointLocations()) {
out_collection.Add(loc_sp);
}
return out_collection.GetSize();
}

View File

@@ -0,0 +1,206 @@
//===-- BreakpointSiteList.cpp ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/BreakpointSiteList.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Utility/Stream.h"
#include <algorithm>
using namespace lldb;
using namespace lldb_private;
BreakpointSiteList::BreakpointSiteList() : m_mutex(), m_bp_site_list() {}
BreakpointSiteList::~BreakpointSiteList() {}
// Add breakpoint site to the list. However, if the element already exists in
// the
// list, then we don't add it, and return LLDB_INVALID_BREAK_ID.
lldb::break_id_t BreakpointSiteList::Add(const BreakpointSiteSP &bp) {
lldb::addr_t bp_site_load_addr = bp->GetLoadAddress();
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator iter = m_bp_site_list.find(bp_site_load_addr);
if (iter == m_bp_site_list.end()) {
m_bp_site_list.insert(iter, collection::value_type(bp_site_load_addr, bp));
return bp->GetID();
} else {
return LLDB_INVALID_BREAK_ID;
}
}
bool BreakpointSiteList::ShouldStop(StoppointCallbackContext *context,
lldb::break_id_t site_id) {
BreakpointSiteSP site_sp(FindByID(site_id));
if (site_sp) {
// Let the BreakpointSite decide if it should stop here (could not have
// reached it's target hit count yet, or it could have a callback
// that decided it shouldn't stop (shared library loads/unloads).
return site_sp->ShouldStop(context);
}
// We should stop here since this BreakpointSite isn't valid anymore or it
// doesn't exist.
return true;
}
lldb::break_id_t BreakpointSiteList::FindIDByAddress(lldb::addr_t addr) {
BreakpointSiteSP bp = FindByAddress(addr);
if (bp) {
// DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8"
// PRIx64 " ) => %u", __FUNCTION__, (uint64_t)addr, bp->GetID());
return bp.get()->GetID();
}
// DBLogIf(PD_LOG_BREAKPOINTS, "BreakpointSiteList::%s ( addr = 0x%8.8" PRIx64
// " ) => NONE", __FUNCTION__, (uint64_t)addr);
return LLDB_INVALID_BREAK_ID;
}
bool BreakpointSiteList::Remove(lldb::break_id_t break_id) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator pos = GetIDIterator(break_id); // Predicate
if (pos != m_bp_site_list.end()) {
m_bp_site_list.erase(pos);
return true;
}
return false;
}
bool BreakpointSiteList::RemoveByAddress(lldb::addr_t address) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator pos = m_bp_site_list.find(address);
if (pos != m_bp_site_list.end()) {
m_bp_site_list.erase(pos);
return true;
}
return false;
}
class BreakpointSiteIDMatches {
public:
BreakpointSiteIDMatches(lldb::break_id_t break_id) : m_break_id(break_id) {}
bool operator()(std::pair<lldb::addr_t, BreakpointSiteSP> val_pair) const {
return m_break_id == val_pair.second.get()->GetID();
}
private:
const lldb::break_id_t m_break_id;
};
BreakpointSiteList::collection::iterator
BreakpointSiteList::GetIDIterator(lldb::break_id_t break_id) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
return std::find_if(m_bp_site_list.begin(),
m_bp_site_list.end(), // Search full range
BreakpointSiteIDMatches(break_id)); // Predicate
}
BreakpointSiteList::collection::const_iterator
BreakpointSiteList::GetIDConstIterator(lldb::break_id_t break_id) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
return std::find_if(m_bp_site_list.begin(),
m_bp_site_list.end(), // Search full range
BreakpointSiteIDMatches(break_id)); // Predicate
}
BreakpointSiteSP BreakpointSiteList::FindByID(lldb::break_id_t break_id) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSiteSP stop_sp;
collection::iterator pos = GetIDIterator(break_id);
if (pos != m_bp_site_list.end())
stop_sp = pos->second;
return stop_sp;
}
const BreakpointSiteSP
BreakpointSiteList::FindByID(lldb::break_id_t break_id) const {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
BreakpointSiteSP stop_sp;
collection::const_iterator pos = GetIDConstIterator(break_id);
if (pos != m_bp_site_list.end())
stop_sp = pos->second;
return stop_sp;
}
BreakpointSiteSP BreakpointSiteList::FindByAddress(lldb::addr_t addr) {
BreakpointSiteSP found_sp;
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::iterator iter = m_bp_site_list.find(addr);
if (iter != m_bp_site_list.end())
found_sp = iter->second;
return found_sp;
}
bool BreakpointSiteList::BreakpointSiteContainsBreakpoint(
lldb::break_id_t bp_site_id, lldb::break_id_t bp_id) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::const_iterator pos = GetIDConstIterator(bp_site_id);
if (pos != m_bp_site_list.end())
return pos->second->IsBreakpointAtThisSite(bp_id);
return false;
}
void BreakpointSiteList::Dump(Stream *s) const {
s->Printf("%p: ", static_cast<const void *>(this));
// s->Indent();
s->Printf("BreakpointSiteList with %u BreakpointSites:\n",
(uint32_t)m_bp_site_list.size());
s->IndentMore();
collection::const_iterator pos;
collection::const_iterator end = m_bp_site_list.end();
for (pos = m_bp_site_list.begin(); pos != end; ++pos)
pos->second.get()->Dump(s);
s->IndentLess();
}
void BreakpointSiteList::ForEach(
std::function<void(BreakpointSite *)> const &callback) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
for (auto pair : m_bp_site_list)
callback(pair.second.get());
}
bool BreakpointSiteList::FindInRange(lldb::addr_t lower_bound,
lldb::addr_t upper_bound,
BreakpointSiteList &bp_site_list) const {
if (lower_bound > upper_bound)
return false;
std::lock_guard<std::recursive_mutex> guard(m_mutex);
collection::const_iterator lower, upper, pos;
lower = m_bp_site_list.lower_bound(lower_bound);
if (lower == m_bp_site_list.end() || (*lower).first >= upper_bound)
return false;
// This is one tricky bit. The breakpoint might overlap the bottom end of the
// range. So we grab the
// breakpoint prior to the lower bound, and check that that + its byte size
// isn't in our range.
if (lower != m_bp_site_list.begin()) {
collection::const_iterator prev_pos = lower;
prev_pos--;
const BreakpointSiteSP &prev_bp = (*prev_pos).second;
if (prev_bp->GetLoadAddress() + prev_bp->GetByteSize() > lower_bound)
bp_site_list.Add(prev_bp);
}
upper = m_bp_site_list.upper_bound(upper_bound);
for (pos = lower; pos != upper; pos++) {
bp_site_list.Add((*pos).second);
}
return true;
}

View File

@@ -0,0 +1,37 @@
add_lldb_library(lldbBreakpoint
Breakpoint.cpp
BreakpointID.cpp
BreakpointIDList.cpp
BreakpointList.cpp
BreakpointLocation.cpp
BreakpointLocationCollection.cpp
BreakpointLocationList.cpp
BreakpointName.cpp
BreakpointOptions.cpp
BreakpointResolver.cpp
BreakpointResolverAddress.cpp
BreakpointResolverFileLine.cpp
BreakpointResolverFileRegex.cpp
BreakpointResolverName.cpp
BreakpointSite.cpp
BreakpointSiteList.cpp
Stoppoint.cpp
StoppointCallbackContext.cpp
StoppointLocation.cpp
Watchpoint.cpp
WatchpointList.cpp
WatchpointOptions.cpp
LINK_LIBS
lldbCore
lldbExpression
lldbInterpreter
lldbSymbol
lldbTarget
lldbUtility
lldbPluginCPlusPlusLanguage
lldbPluginObjCLanguage
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,33 @@
//===-- Stoppoint.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/Stoppoint.h"
#include "lldb/lldb-private.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Stoppoint constructor
//----------------------------------------------------------------------
Stoppoint::Stoppoint() : m_bid(LLDB_INVALID_BREAK_ID) {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Stoppoint::~Stoppoint() {}
break_id_t Stoppoint::GetID() const { return m_bid; }
void Stoppoint::SetID(break_id_t bid) { m_bid = bid; }

View File

@@ -0,0 +1,29 @@
//===-- StoppointCallbackContext.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/StoppointCallbackContext.h"
using namespace lldb_private;
StoppointCallbackContext::StoppointCallbackContext()
: event(nullptr), exe_ctx_ref(), is_synchronous(false) {}
StoppointCallbackContext::StoppointCallbackContext(
Event *e, const ExecutionContext &exe_ctx, bool synchronously)
: event(e), exe_ctx_ref(exe_ctx), is_synchronous(synchronously) {}
void StoppointCallbackContext::Clear() {
event = nullptr;
exe_ctx_ref.Clear();
is_synchronous = false;
}

View File

@@ -0,0 +1,41 @@
//===-- StoppointLocation.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Breakpoint/StoppointLocation.h"
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// StoppointLocation constructor
//----------------------------------------------------------------------
StoppointLocation::StoppointLocation(break_id_t bid, addr_t addr, bool hardware)
: m_loc_id(bid), m_addr(addr), m_hardware(hardware),
m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(0), m_hit_count(0) {}
StoppointLocation::StoppointLocation(break_id_t bid, addr_t addr,
uint32_t byte_size, bool hardware)
: m_loc_id(bid), m_addr(addr), m_hardware(hardware),
m_hardware_index(LLDB_INVALID_INDEX32), m_byte_size(byte_size),
m_hit_count(0) {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
StoppointLocation::~StoppointLocation() {}
void StoppointLocation::DecrementHitCount() {
assert(m_hit_count > 0);
--m_hit_count;
}

Some files were not shown because too many files have changed in this diff Show More