Files
clang-p2996/lldb/source/Breakpoint/BreakpointResolver.cpp
Zachary Turner bf9a77305f Move classes from Core -> Utility.
This moves the following classes from Core -> Utility.

ConstString
Error
RegularExpression
Stream
StreamString

The goal here is to get lldbUtility into a state where it has
no dependendencies except on itself and LLVM, so it can be the
starting point at which to start untangling LLDB's dependencies.
These are all low level and very widely used classes, and
previously lldbUtility had dependencies up to lldbCore in order
to use these classes.  So moving then down to lldbUtility makes
sense from both the short term and long term perspective in
solving this problem.

Differential Revision: https://reviews.llvm.org/D29427

llvm-svn: 293941
2017-02-02 21:39:50 +00:00

324 lines
11 KiB
C++

//===-- 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/Log.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/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(const char *name) {
for (size_t i = 0; i < LastKnownResolverType; i++) {
if (strcmp(name, g_ty_to_name[i]) == 0)
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, Error &error) {
BreakpointResolverSP result_sp;
if (!resolver_dict.IsValid()) {
error.SetErrorString("Can't deserialize from an invalid data object.");
return result_sp;
}
std::string 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.c_str());
if (resolver_type == UnknownResolver) {
error.SetErrorStringWithFormat("Unknown resolver type: %s.",
subclass_name.c_str());
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;
}