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

View File

@@ -0,0 +1,214 @@
//===-- ABI.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/Target/ABI.h"
#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
ABISP
ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) {
ABISP abi_sp;
ABICreateInstance create_callback;
for (uint32_t idx = 0;
(create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
abi_sp = create_callback(process_sp, arch);
if (abi_sp)
return abi_sp;
}
abi_sp.reset();
return abi_sp;
}
ABI::~ABI() = default;
bool ABI::GetRegisterInfoByName(const ConstString &name, RegisterInfo &info) {
uint32_t count = 0;
const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
if (register_info_array) {
const char *unique_name_cstr = name.GetCString();
uint32_t i;
for (i = 0; i < count; ++i) {
if (register_info_array[i].name == unique_name_cstr) {
info = register_info_array[i];
return true;
}
}
for (i = 0; i < count; ++i) {
if (register_info_array[i].alt_name == unique_name_cstr) {
info = register_info_array[i];
return true;
}
}
}
return false;
}
bool ABI::GetRegisterInfoByKind(RegisterKind reg_kind, uint32_t reg_num,
RegisterInfo &info) {
if (reg_kind < eRegisterKindEHFrame || reg_kind >= kNumRegisterKinds)
return false;
uint32_t count = 0;
const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
if (register_info_array) {
for (uint32_t i = 0; i < count; ++i) {
if (register_info_array[i].kinds[reg_kind] == reg_num) {
info = register_info_array[i];
return true;
}
}
}
return false;
}
ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
bool persistent) const {
if (!ast_type.IsValid())
return ValueObjectSP();
ValueObjectSP return_valobj_sp;
return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
if (!return_valobj_sp)
return return_valobj_sp;
// Now turn this into a persistent variable.
// FIXME: This code is duplicated from Target::EvaluateExpression, and it is
// used in similar form in a couple
// of other places. Figure out the correct Create function to do all this
// work.
if (persistent) {
PersistentExpressionState *persistent_expression_state =
thread.CalculateTarget()->GetPersistentExpressionStateForLanguage(
ast_type.GetMinimumLanguage());
if (!persistent_expression_state)
return ValueObjectSP();
ConstString persistent_variable_name(
persistent_expression_state->GetNextPersistentVariableName());
lldb::ValueObjectSP const_valobj_sp;
// Check in case our value is already a constant value
if (return_valobj_sp->GetIsConstant()) {
const_valobj_sp = return_valobj_sp;
const_valobj_sp->SetName(persistent_variable_name);
} else
const_valobj_sp =
return_valobj_sp->CreateConstantValue(persistent_variable_name);
lldb::ValueObjectSP live_valobj_sp = return_valobj_sp;
return_valobj_sp = const_valobj_sp;
ExpressionVariableSP clang_expr_variable_sp(
persistent_expression_state->CreatePersistentVariable(
return_valobj_sp));
assert(clang_expr_variable_sp);
// Set flags and live data as appropriate
const Value &result_value = live_valobj_sp->GetValue();
switch (result_value.GetValueType()) {
case Value::eValueTypeHostAddress:
case Value::eValueTypeFileAddress:
// we don't do anything with these for now
break;
case Value::eValueTypeScalar:
case Value::eValueTypeVector:
clang_expr_variable_sp->m_flags |=
ClangExpressionVariable::EVIsFreezeDried;
clang_expr_variable_sp->m_flags |=
ClangExpressionVariable::EVIsLLDBAllocated;
clang_expr_variable_sp->m_flags |=
ClangExpressionVariable::EVNeedsAllocation;
break;
case Value::eValueTypeLoadAddress:
clang_expr_variable_sp->m_live_sp = live_valobj_sp;
clang_expr_variable_sp->m_flags |=
ClangExpressionVariable::EVIsProgramReference;
break;
}
return_valobj_sp = clang_expr_variable_sp->GetValueObject();
}
return return_valobj_sp;
}
ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type,
bool persistent) const {
ValueObjectSP return_valobj_sp;
return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
return return_valobj_sp;
}
// specialized to work with llvm IR types
//
// for now we will specify a default implementation so that we don't need to
// modify other ABIs
lldb::ValueObjectSP ABI::GetReturnValueObjectImpl(Thread &thread,
llvm::Type &ir_type) const {
ValueObjectSP return_valobj_sp;
/* this is a dummy and will only be called if an ABI does not override this */
return return_valobj_sp;
}
bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress, llvm::Type &returntype,
llvm::ArrayRef<ABI::CallArgument> args) const {
// dummy prepare trivial call
llvm_unreachable("Should never get here!");
}
bool ABI::GetFallbackRegisterLocation(
const RegisterInfo *reg_info,
UnwindPlan::Row::RegisterLocation &unwind_regloc) {
// Did the UnwindPlan fail to give us the caller's stack pointer?
// The stack pointer is defined to be the same as THIS frame's CFA, so return
// the CFA value as
// the caller's stack pointer. This is true on x86-32/x86-64 at least.
if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) {
unwind_regloc.SetIsCFAPlusOffset(0);
return true;
}
// If a volatile register is being requested, we don't want to forward the
// next frame's register contents
// up the stack -- the register is not retrievable at this frame.
if (RegisterIsVolatile(reg_info)) {
unwind_regloc.SetUndefined();
return true;
}
return false;
}

View File

@@ -0,0 +1,78 @@
include_directories(../Plugins/Process/Utility)
add_lldb_library(lldbTarget
ABI.cpp
CPPLanguageRuntime.cpp
ExecutionContext.cpp
FileAction.cpp
JITLoader.cpp
JITLoaderList.cpp
InstrumentationRuntime.cpp
InstrumentationRuntimeStopInfo.cpp
Language.cpp
LanguageRuntime.cpp
Memory.cpp
MemoryHistory.cpp
ModuleCache.cpp
ObjCLanguageRuntime.cpp
OperatingSystem.cpp
PathMappingList.cpp
Platform.cpp
Process.cpp
ProcessInfo.cpp
ProcessLaunchInfo.cpp
Queue.cpp
QueueItem.cpp
QueueList.cpp
RegisterContext.cpp
RegisterNumber.cpp
SectionLoadHistory.cpp
SectionLoadList.cpp
StackFrame.cpp
StackFrameList.cpp
StackID.cpp
StopInfo.cpp
StructuredDataPlugin.cpp
SystemRuntime.cpp
Target.cpp
TargetList.cpp
Thread.cpp
ThreadCollection.cpp
ThreadList.cpp
ThreadPlan.cpp
ThreadPlanBase.cpp
ThreadPlanCallFunction.cpp
ThreadPlanCallFunctionUsingABI.cpp
ThreadPlanCallOnFunctionExit.cpp
ThreadPlanCallUserExpression.cpp
ThreadPlanPython.cpp
ThreadPlanRunToAddress.cpp
ThreadPlanShouldStopHere.cpp
ThreadPlanStepInRange.cpp
ThreadPlanStepInstruction.cpp
ThreadPlanStepOut.cpp
ThreadPlanStepOverBreakpoint.cpp
ThreadPlanStepOverRange.cpp
ThreadPlanStepRange.cpp
ThreadPlanStepThrough.cpp
ThreadPlanStepUntil.cpp
ThreadPlanTracer.cpp
ThreadSpec.cpp
UnixSignals.cpp
UnwindAssembly.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbExpression
lldbHost
lldbInterpreter
lldbSymbol
lldbUtility
lldbPluginExpressionParserClang
lldbPluginObjCLanguage
lldbPluginProcessUtility
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,42 @@
//===-- CPPLanguageRuntime.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/Target/CPPLanguageRuntime.h"
#include <string.h>
#include "llvm/ADT/StringRef.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Target/ExecutionContext.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
CPPLanguageRuntime::~CPPLanguageRuntime() {}
CPPLanguageRuntime::CPPLanguageRuntime(Process *process)
: LanguageRuntime(process) {}
bool CPPLanguageRuntime::GetObjectDescription(Stream &str,
ValueObject &object) {
// C++ has no generic way to do this.
return false;
}
bool CPPLanguageRuntime::GetObjectDescription(
Stream &str, Value &value, ExecutionContextScope *exe_scope) {
// C++ has no generic way to do this.
return false;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
//===-- FileAction.cpp ------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <fcntl.h>
#include "lldb/Host/PosixApi.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Utility/Stream.h"
using namespace lldb_private;
//----------------------------------------------------------------------------
// FileAction member functions
//----------------------------------------------------------------------------
FileAction::FileAction()
: m_action(eFileActionNone), m_fd(-1), m_arg(-1), m_file_spec() {}
void FileAction::Clear() {
m_action = eFileActionNone;
m_fd = -1;
m_arg = -1;
m_file_spec.Clear();
}
llvm::StringRef FileAction::GetPath() const { return m_file_spec.GetCString(); }
const FileSpec &FileAction::GetFileSpec() const { return m_file_spec; }
bool FileAction::Open(int fd, const FileSpec &file_spec, bool read,
bool write) {
if ((read || write) && fd >= 0 && file_spec) {
m_action = eFileActionOpen;
m_fd = fd;
if (read && write)
m_arg = O_NOCTTY | O_CREAT | O_RDWR;
else if (read)
m_arg = O_NOCTTY | O_RDONLY;
else
m_arg = O_NOCTTY | O_CREAT | O_WRONLY;
m_file_spec = file_spec;
return true;
} else {
Clear();
}
return false;
}
bool FileAction::Close(int fd) {
Clear();
if (fd >= 0) {
m_action = eFileActionClose;
m_fd = fd;
}
return m_fd >= 0;
}
bool FileAction::Duplicate(int fd, int dup_fd) {
Clear();
if (fd >= 0 && dup_fd >= 0) {
m_action = eFileActionDuplicate;
m_fd = fd;
m_arg = dup_fd;
}
return m_fd >= 0;
}
void FileAction::Dump(Stream &stream) const {
stream.PutCString("file action: ");
switch (m_action) {
case eFileActionClose:
stream.Printf("close fd %d", m_fd);
break;
case eFileActionDuplicate:
stream.Printf("duplicate fd %d to %d", m_fd, m_arg);
break;
case eFileActionNone:
stream.PutCString("no action");
break;
case eFileActionOpen:
stream.Printf("open fd %d with '%s', OFLAGS = 0x%x", m_fd,
m_file_spec.GetCString(), m_arg);
break;
}
}

View File

@@ -0,0 +1,80 @@
//===-- InstrumentationRuntime.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/Target/InstrumentationRuntime.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
void InstrumentationRuntime::ModulesDidLoad(
lldb_private::ModuleList &module_list, lldb_private::Process *process,
InstrumentationRuntimeCollection &runtimes) {
InstrumentationRuntimeCreateInstance create_callback = nullptr;
InstrumentationRuntimeGetType get_type_callback;
for (uint32_t idx = 0;; ++idx) {
create_callback =
PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx);
if (create_callback == nullptr)
break;
get_type_callback =
PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx);
InstrumentationRuntimeType type = get_type_callback();
InstrumentationRuntimeCollection::iterator pos;
pos = runtimes.find(type);
if (pos == runtimes.end()) {
runtimes[type] = create_callback(process->shared_from_this());
}
}
}
void InstrumentationRuntime::ModulesDidLoad(
lldb_private::ModuleList &module_list) {
if (IsActive())
return;
if (GetRuntimeModuleSP()) {
Activate();
return;
}
module_list.ForEach([this](const lldb::ModuleSP module_sp) -> bool {
const FileSpec &file_spec = module_sp->GetFileSpec();
if (!file_spec)
return true; // Keep iterating.
const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary();
if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) ||
module_sp->IsExecutable()) {
if (CheckIfRuntimeIsValid(module_sp)) {
SetRuntimeModuleSP(module_sp);
Activate();
return false; // Stop iterating, we're done.
}
}
return true;
});
}
lldb::ThreadCollectionSP
InstrumentationRuntime::GetBacktracesFromExtendedStopInfo(
StructuredData::ObjectSP info) {
return ThreadCollectionSP(new ThreadCollection());
}

View File

@@ -0,0 +1,37 @@
//===-- InstrumentationRuntimeStopInfo.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/Target/InstrumentationRuntimeStopInfo.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(
Thread &thread, std::string description,
StructuredData::ObjectSP additional_data)
: StopInfo(thread, 0) {
m_extended_info = additional_data;
m_description = description;
}
const char *InstrumentationRuntimeStopInfo::GetDescription() {
return m_description.c_str();
}
StopInfoSP
InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
Thread &thread, std::string description,
StructuredData::ObjectSP additionalData) {
return StopInfoSP(
new InstrumentationRuntimeStopInfo(thread, description, additionalData));
}

View File

@@ -0,0 +1,37 @@
//===-- JITLoader.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/Target/JITLoader.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/Process.h"
#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
void JITLoader::LoadPlugins(Process *process, JITLoaderList &list) {
JITLoaderCreateInstance create_callback = nullptr;
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != nullptr;
++idx) {
JITLoaderSP instance_sp(create_callback(process, false));
if (instance_sp)
list.Append(std::move(instance_sp));
}
}
JITLoader::JITLoader(Process *process) : m_process(process) {}
JITLoader::~JITLoader() = default;

View File

@@ -0,0 +1,56 @@
//===-- JITLoaderList.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/Target/JITLoader.h"
#include "lldb/Target/JITLoaderList.h"
#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
JITLoaderList::JITLoaderList() : m_jit_loaders_vec(), m_jit_loaders_mutex() {}
JITLoaderList::~JITLoaderList() {}
void JITLoaderList::Append(const JITLoaderSP &jit_loader_sp) {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
m_jit_loaders_vec.push_back(jit_loader_sp);
}
void JITLoaderList::Remove(const JITLoaderSP &jit_loader_sp) {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(),
m_jit_loaders_vec.end(), jit_loader_sp),
m_jit_loaders_vec.end());
}
size_t JITLoaderList::GetSize() const { return m_jit_loaders_vec.size(); }
JITLoaderSP JITLoaderList::GetLoaderAtIndex(size_t idx) {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
return m_jit_loaders_vec[idx];
}
void JITLoaderList::DidLaunch() {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
for (auto const &jit_loader : m_jit_loaders_vec)
jit_loader->DidLaunch();
}
void JITLoaderList::DidAttach() {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
for (auto const &jit_loader : m_jit_loaders_vec)
jit_loader->DidAttach();
}
void JITLoaderList::ModulesDidLoad(ModuleList &module_list) {
std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex);
for (auto const &jit_loader : m_jit_loaders_vec)
jit_loader->ModulesDidLoad(module_list);
}

View File

@@ -0,0 +1,424 @@
//===-- Language.cpp -------------------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <functional>
#include <map>
#include <mutex>
#include "lldb/Target/Language.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Stream.h"
#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
typedef std::unique_ptr<Language> LanguageUP;
typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap;
static LanguagesMap &GetLanguagesMap() {
static LanguagesMap *g_map = nullptr;
static llvm::once_flag g_initialize;
llvm::call_once(g_initialize, [] {
g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global
// destructor chain
});
return *g_map;
}
static std::mutex &GetLanguagesMutex() {
static std::mutex *g_mutex = nullptr;
static llvm::once_flag g_initialize;
llvm::call_once(g_initialize, [] {
g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global
// destructor chain
});
return *g_mutex;
}
Language *Language::FindPlugin(lldb::LanguageType language) {
std::lock_guard<std::mutex> guard(GetLanguagesMutex());
LanguagesMap &map(GetLanguagesMap());
auto iter = map.find(language), end = map.end();
if (iter != end)
return iter->second.get();
Language *language_ptr = nullptr;
LanguageCreateInstance create_callback;
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr;
++idx) {
language_ptr = create_callback(language);
if (language_ptr) {
map[language] = std::unique_ptr<Language>(language_ptr);
return language_ptr;
}
}
return nullptr;
}
void Language::ForEach(std::function<bool(Language *)> callback) {
std::lock_guard<std::mutex> guard(GetLanguagesMutex());
LanguagesMap &map(GetLanguagesMap());
for (const auto &entry : map) {
if (!callback(entry.second.get()))
break;
}
}
bool Language::IsTopLevelFunction(Function &function) { return false; }
lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
return {};
}
HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
return {};
}
HardcodedFormatters::HardcodedSyntheticFinder
Language::GetHardcodedSynthetics() {
return {};
}
HardcodedFormatters::HardcodedValidatorFinder
Language::GetHardcodedValidators() {
return {};
}
std::vector<ConstString>
Language::GetPossibleFormattersMatches(ValueObject &valobj,
lldb::DynamicValueType use_dynamic) {
return {};
}
lldb_private::formatters::StringPrinter::EscapingHelper
Language::GetStringPrinterEscapingHelper(
lldb_private::formatters::StringPrinter::GetPrintableElementType
elem_type) {
return StringPrinter::GetDefaultEscapingHelper(elem_type);
}
struct language_name_pair {
const char *name;
LanguageType type;
};
struct language_name_pair language_names[] = {
// To allow GetNameForLanguageType to be a simple array lookup, the first
// part of this array must follow enum LanguageType exactly.
{"unknown", eLanguageTypeUnknown},
{"c89", eLanguageTypeC89},
{"c", eLanguageTypeC},
{"ada83", eLanguageTypeAda83},
{"c++", eLanguageTypeC_plus_plus},
{"cobol74", eLanguageTypeCobol74},
{"cobol85", eLanguageTypeCobol85},
{"fortran77", eLanguageTypeFortran77},
{"fortran90", eLanguageTypeFortran90},
{"pascal83", eLanguageTypePascal83},
{"modula2", eLanguageTypeModula2},
{"java", eLanguageTypeJava},
{"c99", eLanguageTypeC99},
{"ada95", eLanguageTypeAda95},
{"fortran95", eLanguageTypeFortran95},
{"pli", eLanguageTypePLI},
{"objective-c", eLanguageTypeObjC},
{"objective-c++", eLanguageTypeObjC_plus_plus},
{"upc", eLanguageTypeUPC},
{"d", eLanguageTypeD},
{"python", eLanguageTypePython},
{"opencl", eLanguageTypeOpenCL},
{"go", eLanguageTypeGo},
{"modula3", eLanguageTypeModula3},
{"haskell", eLanguageTypeHaskell},
{"c++03", eLanguageTypeC_plus_plus_03},
{"c++11", eLanguageTypeC_plus_plus_11},
{"ocaml", eLanguageTypeOCaml},
{"rust", eLanguageTypeRust},
{"c11", eLanguageTypeC11},
{"swift", eLanguageTypeSwift},
{"julia", eLanguageTypeJulia},
{"dylan", eLanguageTypeDylan},
{"c++14", eLanguageTypeC_plus_plus_14},
{"fortran03", eLanguageTypeFortran03},
{"fortran08", eLanguageTypeFortran08},
// Vendor Extensions
{"mipsassem", eLanguageTypeMipsAssembler},
{"renderscript", eLanguageTypeExtRenderScript},
// Now synonyms, in arbitrary order
{"objc", eLanguageTypeObjC},
{"objc++", eLanguageTypeObjC_plus_plus},
{"pascal", eLanguageTypePascal83}};
static uint32_t num_languages =
sizeof(language_names) / sizeof(struct language_name_pair);
LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
for (const auto &L : language_names) {
if (string.equals_lower(L.name))
return static_cast<LanguageType>(L.type);
}
return eLanguageTypeUnknown;
}
const char *Language::GetNameForLanguageType(LanguageType language) {
if (language < num_languages)
return language_names[language].name;
else
return language_names[eLanguageTypeUnknown].name;
}
void Language::PrintAllLanguages(Stream &s, const char *prefix,
const char *suffix) {
for (uint32_t i = 1; i < num_languages; i++) {
s.Printf("%s%s%s", prefix, language_names[i].name, suffix);
}
}
void Language::ForAllLanguages(
std::function<bool(lldb::LanguageType)> callback) {
for (uint32_t i = 1; i < num_languages; i++) {
if (!callback(language_names[i].type))
break;
}
}
bool Language::LanguageIsCPlusPlus(LanguageType language) {
switch (language) {
case eLanguageTypeC_plus_plus:
case eLanguageTypeC_plus_plus_03:
case eLanguageTypeC_plus_plus_11:
case eLanguageTypeC_plus_plus_14:
case eLanguageTypeObjC_plus_plus:
return true;
default:
return false;
}
}
bool Language::LanguageIsObjC(LanguageType language) {
switch (language) {
case eLanguageTypeObjC:
case eLanguageTypeObjC_plus_plus:
return true;
default:
return false;
}
}
bool Language::LanguageIsC(LanguageType language) {
switch (language) {
case eLanguageTypeC:
case eLanguageTypeC89:
case eLanguageTypeC99:
case eLanguageTypeC11:
return true;
default:
return false;
}
}
bool Language::LanguageIsPascal(LanguageType language) {
switch (language) {
case eLanguageTypePascal83:
return true;
default:
return false;
}
}
LanguageType Language::GetPrimaryLanguage(LanguageType language) {
switch (language) {
case eLanguageTypeC_plus_plus:
case eLanguageTypeC_plus_plus_03:
case eLanguageTypeC_plus_plus_11:
case eLanguageTypeC_plus_plus_14:
return eLanguageTypeC_plus_plus;
case eLanguageTypeC:
case eLanguageTypeC89:
case eLanguageTypeC99:
case eLanguageTypeC11:
return eLanguageTypeC;
case eLanguageTypeObjC:
case eLanguageTypeObjC_plus_plus:
return eLanguageTypeObjC;
case eLanguageTypePascal83:
case eLanguageTypeCobol74:
case eLanguageTypeCobol85:
case eLanguageTypeFortran77:
case eLanguageTypeFortran90:
case eLanguageTypeFortran95:
case eLanguageTypeFortran03:
case eLanguageTypeFortran08:
case eLanguageTypeAda83:
case eLanguageTypeAda95:
case eLanguageTypeModula2:
case eLanguageTypeJava:
case eLanguageTypePLI:
case eLanguageTypeUPC:
case eLanguageTypeD:
case eLanguageTypePython:
case eLanguageTypeOpenCL:
case eLanguageTypeGo:
case eLanguageTypeModula3:
case eLanguageTypeHaskell:
case eLanguageTypeOCaml:
case eLanguageTypeRust:
case eLanguageTypeSwift:
case eLanguageTypeJulia:
case eLanguageTypeDylan:
case eLanguageTypeMipsAssembler:
case eLanguageTypeExtRenderScript:
case eLanguageTypeUnknown:
default:
return language;
}
}
void Language::GetLanguagesSupportingTypeSystems(
std::set<lldb::LanguageType> &languages,
std::set<lldb::LanguageType> &languages_for_expressions) {
uint32_t idx = 0;
while (TypeSystemEnumerateSupportedLanguages enumerate = PluginManager::
GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(idx++)) {
(*enumerate)(languages, languages_for_expressions);
}
}
void Language::GetLanguagesSupportingREPLs(
std::set<lldb::LanguageType> &languages) {
uint32_t idx = 0;
while (REPLEnumerateSupportedLanguages enumerate =
PluginManager::GetREPLEnumerateSupportedLanguagesCallbackAtIndex(
idx++)) {
(*enumerate)(languages);
}
}
std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
return nullptr;
}
const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
const char *key, ResultSet &results,
bool append) {
if (!exe_scope || !exe_scope->CalculateTarget().get())
return false;
if (!key || !key[0])
return false;
if (!append)
results.clear();
size_t old_size = results.size();
if (this->Find_Impl(exe_scope, key, results))
return results.size() - old_size;
return 0;
}
bool Language::ImageListTypeScavenger::Find_Impl(
ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
bool result = false;
Target *target = exe_scope->CalculateTarget().get();
if (target) {
const auto &images(target->GetImages());
SymbolContext null_sc;
ConstString cs_key(key);
llvm::DenseSet<SymbolFile *> searched_sym_files;
TypeList matches;
images.FindTypes(null_sc, cs_key, false, UINT32_MAX, searched_sym_files,
matches);
for (const auto &match : matches.Types()) {
if (match.get()) {
CompilerType compiler_type(match->GetFullCompilerType());
compiler_type = AdjustForInclusion(compiler_type);
if (!compiler_type)
continue;
std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
new Result(compiler_type));
results.insert(std::move(scavengeresult));
result = true;
}
}
}
return result;
}
bool Language::GetFormatterPrefixSuffix(ValueObject &valobj,
ConstString type_hint,
std::string &prefix,
std::string &suffix) {
return false;
}
DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
return nullptr;
}
LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
return eLazyBoolCalculate;
}
bool Language::IsNilReference(ValueObject &valobj) { return false; }
bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
bool Language::GetFunctionDisplayName(const SymbolContext *sc,
const ExecutionContext *exe_ctx,
FunctionNameRepresentation representation,
Stream &s) {
return false;
}
void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
Stream &s) {
GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
}
void Language::GetDefaultExceptionResolverDescription(bool catch_on,
bool throw_on,
Stream &s) {
s.Printf("Exception breakpoint (catch: %s throw: %s)",
catch_on ? "on" : "off", throw_on ? "on" : "off");
}
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------
Language::Language() {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
Language::~Language() {}

View File

@@ -0,0 +1,301 @@
//===-- LanguageRuntime.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/Target/LanguageRuntime.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
ExceptionSearchFilter::ExceptionSearchFilter(const lldb::TargetSP &target_sp,
lldb::LanguageType language,
bool update_module_list)
: SearchFilter(target_sp, FilterTy::Exception), m_language(language),
m_language_runtime(nullptr), m_filter_sp() {
if (update_module_list)
UpdateModuleListIfNeeded();
}
bool ExceptionSearchFilter::ModulePasses(const lldb::ModuleSP &module_sp) {
UpdateModuleListIfNeeded();
if (m_filter_sp)
return m_filter_sp->ModulePasses(module_sp);
return false;
}
bool ExceptionSearchFilter::ModulePasses(const FileSpec &spec) {
UpdateModuleListIfNeeded();
if (m_filter_sp)
return m_filter_sp->ModulePasses(spec);
return false;
}
void ExceptionSearchFilter::Search(Searcher &searcher) {
UpdateModuleListIfNeeded();
if (m_filter_sp)
m_filter_sp->Search(searcher);
}
void ExceptionSearchFilter::GetDescription(Stream *s) {
UpdateModuleListIfNeeded();
if (m_filter_sp)
m_filter_sp->GetDescription(s);
}
void ExceptionSearchFilter::UpdateModuleListIfNeeded() {
ProcessSP process_sp(m_target_sp->GetProcessSP());
if (process_sp) {
bool refreash_filter = !m_filter_sp;
if (m_language_runtime == nullptr) {
m_language_runtime = process_sp->GetLanguageRuntime(m_language);
refreash_filter = true;
} else {
LanguageRuntime *language_runtime =
process_sp->GetLanguageRuntime(m_language);
if (m_language_runtime != language_runtime) {
m_language_runtime = language_runtime;
refreash_filter = true;
}
}
if (refreash_filter && m_language_runtime) {
m_filter_sp = m_language_runtime->CreateExceptionSearchFilter();
}
} else {
m_filter_sp.reset();
m_language_runtime = nullptr;
}
}
SearchFilterSP
ExceptionSearchFilter::DoCopyForBreakpoint(Breakpoint &breakpoint) {
return SearchFilterSP(
new ExceptionSearchFilter(TargetSP(), m_language, false));
}
SearchFilter *ExceptionSearchFilter::CreateFromStructuredData(
Target &target, const StructuredData::Dictionary &data_dict,
Status &error) {
SearchFilter *result = nullptr;
return result;
}
StructuredData::ObjectSP ExceptionSearchFilter::SerializeToStructuredData() {
StructuredData::ObjectSP result_sp;
return result_sp;
}
// The Target is the one that knows how to create breakpoints, so this function
// is meant to be used either by the target or internally in
// Set/ClearExceptionBreakpoints.
class ExceptionBreakpointResolver : public BreakpointResolver {
public:
ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp,
bool throw_bp)
: BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver),
m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp),
m_throw_bp(throw_bp) {}
~ExceptionBreakpointResolver() override = default;
Searcher::CallbackReturn SearchCallback(SearchFilter &filter,
SymbolContext &context, Address *addr,
bool containing) override {
if (SetActualResolver())
return m_actual_resolver_sp->SearchCallback(filter, context, addr,
containing);
else
return eCallbackReturnStop;
}
Searcher::Depth GetDepth() override {
if (SetActualResolver())
return m_actual_resolver_sp->GetDepth();
else
return eDepthTarget;
}
void GetDescription(Stream *s) override {
Language *language_plugin = Language::FindPlugin(m_language);
if (language_plugin)
language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp,
*s);
else
Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp,
*s);
SetActualResolver();
if (m_actual_resolver_sp) {
s->Printf(" using: ");
m_actual_resolver_sp->GetDescription(s);
} else
s->Printf(" the correct runtime exception handler will be determined "
"when you run");
}
void Dump(Stream *s) const override {}
/// Methods for support type inquiry through isa, cast, and dyn_cast:
static inline bool classof(const BreakpointResolverName *) { return true; }
static inline bool classof(const BreakpointResolver *V) {
return V->getResolverID() == BreakpointResolver::ExceptionResolver;
}
protected:
BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override {
return BreakpointResolverSP(
new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
}
bool SetActualResolver() {
ProcessSP process_sp;
if (m_breakpoint) {
process_sp = m_breakpoint->GetTarget().GetProcessSP();
if (process_sp) {
bool refreash_resolver = !m_actual_resolver_sp;
if (m_language_runtime == nullptr) {
m_language_runtime = process_sp->GetLanguageRuntime(m_language);
refreash_resolver = true;
} else {
LanguageRuntime *language_runtime =
process_sp->GetLanguageRuntime(m_language);
if (m_language_runtime != language_runtime) {
m_language_runtime = language_runtime;
refreash_resolver = true;
}
}
if (refreash_resolver && m_language_runtime) {
m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver(
m_breakpoint, m_catch_bp, m_throw_bp);
}
} else {
m_actual_resolver_sp.reset();
m_language_runtime = nullptr;
}
} else {
m_actual_resolver_sp.reset();
m_language_runtime = nullptr;
}
return (bool)m_actual_resolver_sp;
}
lldb::BreakpointResolverSP m_actual_resolver_sp;
lldb::LanguageType m_language;
LanguageRuntime *m_language_runtime;
bool m_catch_bp;
bool m_throw_bp;
};
LanguageRuntime *LanguageRuntime::FindPlugin(Process *process,
lldb::LanguageType language) {
std::unique_ptr<LanguageRuntime> language_runtime_ap;
LanguageRuntimeCreateInstance create_callback;
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
language_runtime_ap.reset(create_callback(process, language));
if (language_runtime_ap)
return language_runtime_ap.release();
}
return nullptr;
}
LanguageRuntime::LanguageRuntime(Process *process) : m_process(process) {}
LanguageRuntime::~LanguageRuntime() = default;
Breakpoint::BreakpointPreconditionSP
LanguageRuntime::CreateExceptionPrecondition(lldb::LanguageType language,
bool catch_bp, bool throw_bp) {
switch (language) {
case eLanguageTypeObjC:
if (throw_bp)
return Breakpoint::BreakpointPreconditionSP(
new ObjCLanguageRuntime::ObjCExceptionPrecondition());
break;
default:
break;
}
return Breakpoint::BreakpointPreconditionSP();
}
BreakpointSP LanguageRuntime::CreateExceptionBreakpoint(
Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp,
bool is_internal) {
BreakpointResolverSP resolver_sp(
new ExceptionBreakpointResolver(language, catch_bp, throw_bp));
SearchFilterSP filter_sp(
new ExceptionSearchFilter(target.shared_from_this(), language));
bool hardware = false;
bool resolve_indirect_functions = false;
BreakpointSP exc_breakpt_sp(
target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware,
resolve_indirect_functions));
if (exc_breakpt_sp) {
Breakpoint::BreakpointPreconditionSP precondition_sp =
CreateExceptionPrecondition(language, catch_bp, throw_bp);
if (precondition_sp)
exc_breakpt_sp->SetPrecondition(precondition_sp);
if (is_internal)
exc_breakpt_sp->SetBreakpointKind("exception");
}
return exc_breakpt_sp;
}
void LanguageRuntime::InitializeCommands(CommandObject *parent) {
if (!parent)
return;
if (!parent->IsMultiwordObject())
return;
LanguageRuntimeCreateInstance create_callback;
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
if (LanguageRuntimeGetCommandObject command_callback =
PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) {
CommandObjectSP command =
command_callback(parent->GetCommandInterpreter());
if (command) {
// the CommandObject vended by a Language plugin cannot be created once
// and cached because we may create multiple debuggers and need one
// instance of the command each - the implementing function is meant to
// create a new instance of the command each time it is invoked.
parent->LoadSubCommand(command->GetCommandName().str().c_str(), command);
}
}
}
}
lldb::SearchFilterSP LanguageRuntime::CreateExceptionSearchFilter() {
return m_process->GetTarget().GetSearchFilterForModule(nullptr);
}

View File

@@ -0,0 +1,421 @@
//===-- Memory.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/Target/Memory.h"
// C Includes
#include <inttypes.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/RangeMap.h"
#include "lldb/Core/State.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/DataBufferHeap.h"
#include "lldb/Utility/Log.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// MemoryCache constructor
//----------------------------------------------------------------------
MemoryCache::MemoryCache(Process &process)
: m_mutex(), m_L1_cache(), m_L2_cache(), m_invalid_ranges(),
m_process(process),
m_L2_cache_line_byte_size(process.GetMemoryCacheLineSize()) {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
MemoryCache::~MemoryCache() {}
void MemoryCache::Clear(bool clear_invalid_ranges) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_L1_cache.clear();
m_L2_cache.clear();
if (clear_invalid_ranges)
m_invalid_ranges.Clear();
m_L2_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
}
void MemoryCache::AddL1CacheData(lldb::addr_t addr, const void *src,
size_t src_len) {
AddL1CacheData(
addr, DataBufferSP(new DataBufferHeap(DataBufferHeap(src, src_len))));
}
void MemoryCache::AddL1CacheData(lldb::addr_t addr,
const DataBufferSP &data_buffer_sp) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_L1_cache[addr] = data_buffer_sp;
}
void MemoryCache::Flush(addr_t addr, size_t size) {
if (size == 0)
return;
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Erase any blocks from the L1 cache that intersect with the flush range
if (!m_L1_cache.empty()) {
AddrRange flush_range(addr, size);
BlockMap::iterator pos = m_L1_cache.upper_bound(addr);
if (pos != m_L1_cache.begin()) {
--pos;
}
while (pos != m_L1_cache.end()) {
AddrRange chunk_range(pos->first, pos->second->GetByteSize());
if (!chunk_range.DoesIntersect(flush_range))
break;
pos = m_L1_cache.erase(pos);
}
}
if (!m_L2_cache.empty()) {
const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
const addr_t end_addr = (addr + size - 1);
const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size);
const addr_t last_cache_line_addr =
end_addr - (end_addr % cache_line_byte_size);
// Watch for overflow where size will cause us to go off the end of the
// 64 bit address space
uint32_t num_cache_lines;
if (last_cache_line_addr >= first_cache_line_addr)
num_cache_lines = ((last_cache_line_addr - first_cache_line_addr) /
cache_line_byte_size) +
1;
else
num_cache_lines =
(UINT64_MAX - first_cache_line_addr + 1) / cache_line_byte_size;
uint32_t cache_idx = 0;
for (addr_t curr_addr = first_cache_line_addr; cache_idx < num_cache_lines;
curr_addr += cache_line_byte_size, ++cache_idx) {
BlockMap::iterator pos = m_L2_cache.find(curr_addr);
if (pos != m_L2_cache.end())
m_L2_cache.erase(pos);
}
}
}
void MemoryCache::AddInvalidRange(lldb::addr_t base_addr,
lldb::addr_t byte_size) {
if (byte_size > 0) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
InvalidRanges::Entry range(base_addr, byte_size);
m_invalid_ranges.Append(range);
m_invalid_ranges.Sort();
}
}
bool MemoryCache::RemoveInvalidRange(lldb::addr_t base_addr,
lldb::addr_t byte_size) {
if (byte_size > 0) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr);
if (idx != UINT32_MAX) {
const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex(idx);
if (entry->GetRangeBase() == base_addr &&
entry->GetByteSize() == byte_size)
return m_invalid_ranges.RemoveEntrtAtIndex(idx);
}
}
return false;
}
size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len,
Status &error) {
size_t bytes_left = dst_len;
// Check the L1 cache for a range that contain the entire memory read.
// If we find a range in the L1 cache that does, we use it. Else we fall
// back to reading memory in m_L2_cache_line_byte_size byte sized chunks.
// The L1 cache contains chunks of memory that are not required to be
// m_L2_cache_line_byte_size bytes in size, so we don't try anything
// tricky when reading from them (no partial reads from the L1 cache).
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (!m_L1_cache.empty()) {
AddrRange read_range(addr, dst_len);
BlockMap::iterator pos = m_L1_cache.upper_bound(addr);
if (pos != m_L1_cache.begin()) {
--pos;
}
AddrRange chunk_range(pos->first, pos->second->GetByteSize());
if (chunk_range.Contains(read_range)) {
memcpy(dst, pos->second->GetBytes() + addr - chunk_range.GetRangeBase(),
dst_len);
return dst_len;
}
}
// If this memory read request is larger than the cache line size, then
// we (1) try to read as much of it at once as possible, and (2) don't
// add the data to the memory cache. We don't want to split a big read
// up into more separate reads than necessary, and with a large memory read
// request, it is unlikely that the caller function will ask for the next
// 4 bytes after the large memory read - so there's little benefit to saving
// it in the cache.
if (dst && dst_len > m_L2_cache_line_byte_size) {
size_t bytes_read =
m_process.ReadMemoryFromInferior(addr, dst, dst_len, error);
// Add this non block sized range to the L1 cache if we actually read
// anything
if (bytes_read > 0)
AddL1CacheData(addr, dst, bytes_read);
return bytes_read;
}
if (dst && bytes_left > 0) {
const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size;
uint8_t *dst_buf = (uint8_t *)dst;
addr_t curr_addr = addr - (addr % cache_line_byte_size);
addr_t cache_offset = addr - curr_addr;
while (bytes_left > 0) {
if (m_invalid_ranges.FindEntryThatContains(curr_addr)) {
error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64,
curr_addr);
return dst_len - bytes_left;
}
BlockMap::const_iterator pos = m_L2_cache.find(curr_addr);
BlockMap::const_iterator end = m_L2_cache.end();
if (pos != end) {
size_t curr_read_size = cache_line_byte_size - cache_offset;
if (curr_read_size > bytes_left)
curr_read_size = bytes_left;
memcpy(dst_buf + dst_len - bytes_left,
pos->second->GetBytes() + cache_offset, curr_read_size);
bytes_left -= curr_read_size;
curr_addr += curr_read_size + cache_offset;
cache_offset = 0;
if (bytes_left > 0) {
// Get sequential cache page hits
for (++pos; (pos != end) && (bytes_left > 0); ++pos) {
assert((curr_addr % cache_line_byte_size) == 0);
if (pos->first != curr_addr)
break;
curr_read_size = pos->second->GetByteSize();
if (curr_read_size > bytes_left)
curr_read_size = bytes_left;
memcpy(dst_buf + dst_len - bytes_left, pos->second->GetBytes(),
curr_read_size);
bytes_left -= curr_read_size;
curr_addr += curr_read_size;
// We have a cache page that succeeded to read some bytes
// but not an entire page. If this happens, we must cap
// off how much data we are able to read...
if (pos->second->GetByteSize() != cache_line_byte_size)
return dst_len - bytes_left;
}
}
}
// We need to read from the process
if (bytes_left > 0) {
assert((curr_addr % cache_line_byte_size) == 0);
std::unique_ptr<DataBufferHeap> data_buffer_heap_ap(
new DataBufferHeap(cache_line_byte_size, 0));
size_t process_bytes_read = m_process.ReadMemoryFromInferior(
curr_addr, data_buffer_heap_ap->GetBytes(),
data_buffer_heap_ap->GetByteSize(), error);
if (process_bytes_read == 0)
return dst_len - bytes_left;
if (process_bytes_read != cache_line_byte_size)
data_buffer_heap_ap->SetByteSize(process_bytes_read);
m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_ap.release());
// We have read data and put it into the cache, continue through the
// loop again to get the data out of the cache...
}
}
}
return dst_len - bytes_left;
}
AllocatedBlock::AllocatedBlock(lldb::addr_t addr, uint32_t byte_size,
uint32_t permissions, uint32_t chunk_size)
: m_range(addr, byte_size), m_permissions(permissions),
m_chunk_size(chunk_size)
{
// The entire address range is free to start with.
m_free_blocks.Append(m_range);
assert(byte_size > chunk_size);
}
AllocatedBlock::~AllocatedBlock() {}
lldb::addr_t AllocatedBlock::ReserveBlock(uint32_t size) {
// We must return something valid for zero bytes.
if (size == 0)
size = 1;
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
const size_t free_count = m_free_blocks.GetSize();
for (size_t i=0; i<free_count; ++i)
{
auto &free_block = m_free_blocks.GetEntryRef(i);
const lldb::addr_t range_size = free_block.GetByteSize();
if (range_size >= size)
{
// We found a free block that is big enough for our data. Figure out how
// many chunks we will need and calculate the resulting block size we will
// reserve.
addr_t addr = free_block.GetRangeBase();
size_t num_chunks = CalculateChunksNeededForSize(size);
lldb::addr_t block_size = num_chunks * m_chunk_size;
lldb::addr_t bytes_left = range_size - block_size;
if (bytes_left == 0)
{
// The newly allocated block will take all of the bytes in this
// available block, so we can just add it to the allocated ranges and
// remove the range from the free ranges.
m_reserved_blocks.Insert(free_block, false);
m_free_blocks.RemoveEntryAtIndex(i);
}
else
{
// Make the new allocated range and add it to the allocated ranges.
Range<lldb::addr_t, uint32_t> reserved_block(free_block);
reserved_block.SetByteSize(block_size);
// Insert the reserved range and don't combine it with other blocks
// in the reserved blocks list.
m_reserved_blocks.Insert(reserved_block, false);
// Adjust the free range in place since we won't change the sorted
// ordering of the m_free_blocks list.
free_block.SetRangeBase(reserved_block.GetRangeEnd());
free_block.SetByteSize(bytes_left);
}
LLDB_LOGV(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size, addr);
return addr;
}
}
LLDB_LOGV(log, "({0}) (size = {1} ({1:x})) => {2:x}", this, size,
LLDB_INVALID_ADDRESS);
return LLDB_INVALID_ADDRESS;
}
bool AllocatedBlock::FreeBlock(addr_t addr) {
bool success = false;
auto entry_idx = m_reserved_blocks.FindEntryIndexThatContains(addr);
if (entry_idx != UINT32_MAX)
{
m_free_blocks.Insert(m_reserved_blocks.GetEntryRef(entry_idx), true);
m_reserved_blocks.RemoveEntryAtIndex(entry_idx);
success = true;
}
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
LLDB_LOGV(log, "({0}) (addr = {1:x}) => {2}", this, addr, success);
return success;
}
AllocatedMemoryCache::AllocatedMemoryCache(Process &process)
: m_process(process), m_mutex(), m_memory_map() {}
AllocatedMemoryCache::~AllocatedMemoryCache() {}
void AllocatedMemoryCache::Clear() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
if (m_process.IsAlive()) {
PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
for (pos = m_memory_map.begin(); pos != end; ++pos)
m_process.DoDeallocateMemory(pos->second->GetBaseAddress());
}
m_memory_map.clear();
}
AllocatedMemoryCache::AllocatedBlockSP
AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions,
uint32_t chunk_size, Status &error) {
AllocatedBlockSP block_sp;
const size_t page_size = 4096;
const size_t num_pages = (byte_size + page_size - 1) / page_size;
const size_t page_byte_size = num_pages * page_size;
addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error);
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log) {
log->Printf("Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32
", permissions = %s) => 0x%16.16" PRIx64,
(uint32_t)page_byte_size, GetPermissionsAsCString(permissions),
(uint64_t)addr);
}
if (addr != LLDB_INVALID_ADDRESS) {
block_sp.reset(
new AllocatedBlock(addr, page_byte_size, permissions, chunk_size));
m_memory_map.insert(std::make_pair(permissions, block_sp));
}
return block_sp;
}
lldb::addr_t AllocatedMemoryCache::AllocateMemory(size_t byte_size,
uint32_t permissions,
Status &error) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
addr_t addr = LLDB_INVALID_ADDRESS;
std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator>
range = m_memory_map.equal_range(permissions);
for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second;
++pos) {
addr = (*pos).second->ReserveBlock(byte_size);
if (addr != LLDB_INVALID_ADDRESS)
break;
}
if (addr == LLDB_INVALID_ADDRESS) {
AllocatedBlockSP block_sp(AllocatePage(byte_size, permissions, 16, error));
if (block_sp)
addr = block_sp->ReserveBlock(byte_size);
}
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf(
"AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32
", permissions = %s) => 0x%16.16" PRIx64,
(uint32_t)byte_size, GetPermissionsAsCString(permissions),
(uint64_t)addr);
return addr;
}
bool AllocatedMemoryCache::DeallocateMemory(lldb::addr_t addr) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
PermissionsToBlockMap::iterator pos, end = m_memory_map.end();
bool success = false;
for (pos = m_memory_map.begin(); pos != end; ++pos) {
if (pos->second->Contains(addr)) {
success = pos->second->FreeBlock(addr);
break;
}
}
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64
") => %i",
(uint64_t)addr, success);
return success;
}

View File

@@ -0,0 +1,33 @@
//===-- MemoryHistory.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/Target/MemoryHistory.h"
#include "lldb/Core/PluginManager.h"
using namespace lldb;
using namespace lldb_private;
lldb::MemoryHistorySP MemoryHistory::FindPlugin(const ProcessSP process) {
MemoryHistoryCreateInstance create_callback = nullptr;
for (uint32_t idx = 0;
(create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex(
idx)) != nullptr;
++idx) {
MemoryHistorySP memory_history_sp(create_callback(process));
if (memory_history_sp)
return memory_history_sp;
}
return MemoryHistorySP();
}

View File

@@ -0,0 +1,332 @@
//===--------------------- ModuleCache.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/Target/ModuleCache.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/File.h"
#include "lldb/Host/LockFile.h"
#include "lldb/Utility/Log.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FileUtilities.h"
#include <assert.h>
#include <cstdio>
using namespace lldb;
using namespace lldb_private;
namespace {
const char *kModulesSubdir = ".cache";
const char *kLockDirName = ".lock";
const char *kTempFileName = ".temp";
const char *kTempSymFileName = ".symtemp";
const char *kSymFileExtension = ".sym";
const char *kFSIllegalChars = "\\/:*?\"<>|";
std::string GetEscapedHostname(const char *hostname) {
if (hostname == nullptr)
hostname = "unknown";
std::string result(hostname);
size_t size = result.size();
for (size_t i = 0; i < size; ++i) {
if ((result[i] >= 1 && result[i] <= 31) ||
strchr(kFSIllegalChars, result[i]) != nullptr)
result[i] = '_';
}
return result;
}
class ModuleLock {
private:
File m_file;
std::unique_ptr<lldb_private::LockFile> m_lock;
FileSpec m_file_spec;
public:
ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid, Status &error);
void Delete();
};
static FileSpec JoinPath(const FileSpec &path1, const char *path2) {
FileSpec result_spec(path1);
result_spec.AppendPathComponent(path2);
return result_spec;
}
static Status MakeDirectory(const FileSpec &dir_path) {
namespace fs = llvm::sys::fs;
return fs::create_directories(dir_path.GetPath(), true, fs::perms::owner_all);
}
FileSpec GetModuleDirectory(const FileSpec &root_dir_spec, const UUID &uuid) {
const auto modules_dir_spec = JoinPath(root_dir_spec, kModulesSubdir);
return JoinPath(modules_dir_spec, uuid.GetAsString().c_str());
}
FileSpec GetSymbolFileSpec(const FileSpec &module_file_spec) {
return FileSpec(module_file_spec.GetPath() + kSymFileExtension, false);
}
void DeleteExistingModule(const FileSpec &root_dir_spec,
const FileSpec &sysroot_module_path_spec) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_MODULES));
UUID module_uuid;
{
auto module_sp =
std::make_shared<Module>(ModuleSpec(sysroot_module_path_spec));
module_uuid = module_sp->GetUUID();
}
if (!module_uuid.IsValid())
return;
Status error;
ModuleLock lock(root_dir_spec, module_uuid, error);
if (error.Fail()) {
if (log)
log->Printf("Failed to lock module %s: %s",
module_uuid.GetAsString().c_str(), error.AsCString());
}
namespace fs = llvm::sys::fs;
fs::file_status st;
if (status(sysroot_module_path_spec.GetPath(), st))
return;
if (st.getLinkCount() > 2) // module is referred by other hosts.
return;
const auto module_spec_dir = GetModuleDirectory(root_dir_spec, module_uuid);
llvm::sys::fs::remove_directories(module_spec_dir.GetPath());
lock.Delete();
}
void DecrementRefExistingModule(const FileSpec &root_dir_spec,
const FileSpec &sysroot_module_path_spec) {
// Remove $platform/.cache/$uuid folder if nobody else references it.
DeleteExistingModule(root_dir_spec, sysroot_module_path_spec);
// Remove sysroot link.
llvm::sys::fs::remove(sysroot_module_path_spec.GetPath());
FileSpec symfile_spec = GetSymbolFileSpec(sysroot_module_path_spec);
llvm::sys::fs::remove(symfile_spec.GetPath());
}
Status CreateHostSysRootModuleLink(const FileSpec &root_dir_spec,
const char *hostname,
const FileSpec &platform_module_spec,
const FileSpec &local_module_spec,
bool delete_existing) {
const auto sysroot_module_path_spec =
JoinPath(JoinPath(root_dir_spec, hostname),
platform_module_spec.GetPath().c_str());
if (sysroot_module_path_spec.Exists()) {
if (!delete_existing)
return Status();
DecrementRefExistingModule(root_dir_spec, sysroot_module_path_spec);
}
const auto error = MakeDirectory(
FileSpec(sysroot_module_path_spec.GetDirectory().AsCString(), false));
if (error.Fail())
return error;
return llvm::sys::fs::create_hard_link(local_module_spec.GetPath(),
sysroot_module_path_spec.GetPath());
}
} // namespace
ModuleLock::ModuleLock(const FileSpec &root_dir_spec, const UUID &uuid,
Status &error) {
const auto lock_dir_spec = JoinPath(root_dir_spec, kLockDirName);
error = MakeDirectory(lock_dir_spec);
if (error.Fail())
return;
m_file_spec = JoinPath(lock_dir_spec, uuid.GetAsString().c_str());
m_file.Open(m_file_spec.GetCString(), File::eOpenOptionWrite |
File::eOpenOptionCanCreate |
File::eOpenOptionCloseOnExec);
if (!m_file) {
error.SetErrorToErrno();
return;
}
m_lock.reset(new lldb_private::LockFile(m_file.GetDescriptor()));
error = m_lock->WriteLock(0, 1);
if (error.Fail())
error.SetErrorStringWithFormat("Failed to lock file: %s",
error.AsCString());
}
void ModuleLock::Delete() {
if (!m_file)
return;
m_file.Close();
llvm::sys::fs::remove(m_file_spec.GetPath());
}
/////////////////////////////////////////////////////////////////////////
Status ModuleCache::Put(const FileSpec &root_dir_spec, const char *hostname,
const ModuleSpec &module_spec, const FileSpec &tmp_file,
const FileSpec &target_file) {
const auto module_spec_dir =
GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
const auto module_file_path =
JoinPath(module_spec_dir, target_file.GetFilename().AsCString());
const auto tmp_file_path = tmp_file.GetPath();
const auto err_code =
llvm::sys::fs::rename(tmp_file_path, module_file_path.GetPath());
if (err_code)
return Status("Failed to rename file %s to %s: %s", tmp_file_path.c_str(),
module_file_path.GetPath().c_str(),
err_code.message().c_str());
const auto error = CreateHostSysRootModuleLink(
root_dir_spec, hostname, target_file, module_file_path, true);
if (error.Fail())
return Status("Failed to create link to %s: %s",
module_file_path.GetPath().c_str(), error.AsCString());
return Status();
}
Status ModuleCache::Get(const FileSpec &root_dir_spec, const char *hostname,
const ModuleSpec &module_spec,
ModuleSP &cached_module_sp, bool *did_create_ptr) {
const auto find_it =
m_loaded_modules.find(module_spec.GetUUID().GetAsString());
if (find_it != m_loaded_modules.end()) {
cached_module_sp = (*find_it).second.lock();
if (cached_module_sp)
return Status();
m_loaded_modules.erase(find_it);
}
const auto module_spec_dir =
GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
const auto module_file_path = JoinPath(
module_spec_dir, module_spec.GetFileSpec().GetFilename().AsCString());
if (!module_file_path.Exists())
return Status("Module %s not found", module_file_path.GetPath().c_str());
if (module_file_path.GetByteSize() != module_spec.GetObjectSize())
return Status("Module %s has invalid file size",
module_file_path.GetPath().c_str());
// We may have already cached module but downloaded from an another host - in
// this case let's create a link to it.
auto error = CreateHostSysRootModuleLink(root_dir_spec, hostname,
module_spec.GetFileSpec(),
module_file_path, false);
if (error.Fail())
return Status("Failed to create link to %s: %s",
module_file_path.GetPath().c_str(), error.AsCString());
auto cached_module_spec(module_spec);
cached_module_spec.GetUUID().Clear(); // Clear UUID since it may contain md5
// content hash instead of real UUID.
cached_module_spec.GetFileSpec() = module_file_path;
cached_module_spec.GetPlatformFileSpec() = module_spec.GetFileSpec();
error = ModuleList::GetSharedModule(cached_module_spec, cached_module_sp,
nullptr, nullptr, did_create_ptr, false);
if (error.Fail())
return error;
FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
if (symfile_spec.Exists())
cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
m_loaded_modules.insert(
std::make_pair(module_spec.GetUUID().GetAsString(), cached_module_sp));
return Status();
}
Status ModuleCache::GetAndPut(const FileSpec &root_dir_spec,
const char *hostname,
const ModuleSpec &module_spec,
const ModuleDownloader &module_downloader,
const SymfileDownloader &symfile_downloader,
lldb::ModuleSP &cached_module_sp,
bool *did_create_ptr) {
const auto module_spec_dir =
GetModuleDirectory(root_dir_spec, module_spec.GetUUID());
auto error = MakeDirectory(module_spec_dir);
if (error.Fail())
return error;
ModuleLock lock(root_dir_spec, module_spec.GetUUID(), error);
if (error.Fail())
return Status("Failed to lock module %s: %s",
module_spec.GetUUID().GetAsString().c_str(),
error.AsCString());
const auto escaped_hostname(GetEscapedHostname(hostname));
// Check local cache for a module.
error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
cached_module_sp, did_create_ptr);
if (error.Success())
return error;
const auto tmp_download_file_spec = JoinPath(module_spec_dir, kTempFileName);
error = module_downloader(module_spec, tmp_download_file_spec);
llvm::FileRemover tmp_file_remover(tmp_download_file_spec.GetPath());
if (error.Fail())
return Status("Failed to download module: %s", error.AsCString());
// Put downloaded file into local module cache.
error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
tmp_download_file_spec, module_spec.GetFileSpec());
if (error.Fail())
return Status("Failed to put module into cache: %s", error.AsCString());
tmp_file_remover.releaseFile();
error = Get(root_dir_spec, escaped_hostname.c_str(), module_spec,
cached_module_sp, did_create_ptr);
if (error.Fail())
return error;
// Fetching a symbol file for the module
const auto tmp_download_sym_file_spec =
JoinPath(module_spec_dir, kTempSymFileName);
error = symfile_downloader(cached_module_sp, tmp_download_sym_file_spec);
llvm::FileRemover tmp_symfile_remover(tmp_download_sym_file_spec.GetPath());
if (error.Fail())
// Failed to download a symfile but fetching the module was successful. The
// module might
// contain the necessary symbols and the debugging is also possible without
// a symfile.
return Status();
error = Put(root_dir_spec, escaped_hostname.c_str(), module_spec,
tmp_download_sym_file_spec,
GetSymbolFileSpec(module_spec.GetFileSpec()));
if (error.Fail())
return Status("Failed to put symbol file into cache: %s",
error.AsCString());
tmp_symfile_remover.releaseFile();
FileSpec symfile_spec = GetSymbolFileSpec(cached_module_sp->GetFileSpec());
cached_module_sp->SetSymbolFileFileSpec(symfile_spec);
return Status();
}

View File

@@ -0,0 +1,387 @@
//===-- ObjCLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/Type.h"
#include "lldb/Core/MappedHash.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Timer.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ObjCLanguageRuntime::~ObjCLanguageRuntime() {}
ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process)
: LanguageRuntime(process), m_impl_cache(),
m_has_new_literals_and_indexing(eLazyBoolCalculate),
m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(),
m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(),
m_negative_complete_class_cache() {}
bool ObjCLanguageRuntime::AddClass(ObjCISA isa,
const ClassDescriptorSP &descriptor_sp,
const char *class_name) {
if (isa != 0) {
m_isa_to_descriptor[isa] = descriptor_sp;
// class_name is assumed to be valid
m_hash_to_isa_map.insert(
std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa));
return true;
}
return false;
}
void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr,
lldb::addr_t selector,
lldb::addr_t impl_addr) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
if (log) {
log->Printf("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64
" implementation 0x%" PRIx64 ".",
class_addr, selector, impl_addr);
}
m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>(
ClassAndSel(class_addr, selector), impl_addr));
}
lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr,
lldb::addr_t selector) {
MsgImplMap::iterator pos, end = m_impl_cache.end();
pos = m_impl_cache.find(ClassAndSel(class_addr, selector));
if (pos != end)
return (*pos).second;
return LLDB_INVALID_ADDRESS;
}
lldb::TypeSP
ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) {
CompleteClassMap::iterator complete_class_iter =
m_complete_class_cache.find(name);
if (complete_class_iter != m_complete_class_cache.end()) {
// Check the weak pointer to make sure the type hasn't been unloaded
TypeSP complete_type_sp(complete_class_iter->second.lock());
if (complete_type_sp)
return complete_type_sp;
else
m_complete_class_cache.erase(name);
}
if (m_negative_complete_class_cache.count(name) > 0)
return TypeSP();
const ModuleList &modules = m_process->GetTarget().GetImages();
SymbolContextList sc_list;
const size_t matching_symbols =
modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list);
if (matching_symbols) {
SymbolContext sc;
sc_list.GetContextAtIndex(0, sc);
ModuleSP module_sp(sc.module_sp);
if (!module_sp)
return TypeSP();
const SymbolContext null_sc;
const bool exact_match = true;
const uint32_t max_matches = UINT32_MAX;
TypeList types;
llvm::DenseSet<SymbolFile *> searched_symbol_files;
const uint32_t num_types = module_sp->FindTypes(
null_sc, name, exact_match, max_matches, searched_symbol_files, types);
if (num_types) {
uint32_t i;
for (i = 0; i < num_types; ++i) {
TypeSP type_sp(types.GetTypeAtIndex(i));
if (ClangASTContext::IsObjCObjectOrInterfaceType(
type_sp->GetForwardCompilerType())) {
if (type_sp->IsCompleteObjCClass()) {
m_complete_class_cache[name] = type_sp;
return type_sp;
}
}
}
}
}
m_negative_complete_class_cache.insert(name);
return TypeSP();
}
size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type,
const char *ivar_name) {
return LLDB_INVALID_IVAR_OFFSET;
}
bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid(
lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged,
bool check_version_specific) const {
if (!value)
return allow_NULLs;
if ((value % 2) == 1 && allow_tagged)
return true;
if ((value % ptr_size) == 0)
return (check_version_specific ? CheckPointer(value, ptr_size) : true);
else
return false;
}
ObjCLanguageRuntime::ObjCISA
ObjCLanguageRuntime::GetISA(const ConstString &name) {
ISAToDescriptorIterator pos = GetDescriptorIterator(name);
if (pos != m_isa_to_descriptor.end())
return pos->first;
return 0;
}
ObjCLanguageRuntime::ISAToDescriptorIterator
ObjCLanguageRuntime::GetDescriptorIterator(const ConstString &name) {
ISAToDescriptorIterator end = m_isa_to_descriptor.end();
if (name) {
UpdateISAToDescriptorMap();
if (m_hash_to_isa_map.empty()) {
// No name hashes were provided, we need to just linearly power through
// the
// names and find a match
for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin();
pos != end; ++pos) {
if (pos->second->GetClassName() == name)
return pos;
}
} else {
// Name hashes were provided, so use them to efficiently lookup name to
// isa/descriptor
const uint32_t name_hash =
MappedHash::HashStringUsingDJB(name.GetCString());
std::pair<HashToISAIterator, HashToISAIterator> range =
m_hash_to_isa_map.equal_range(name_hash);
for (HashToISAIterator range_pos = range.first; range_pos != range.second;
++range_pos) {
ISAToDescriptorIterator pos =
m_isa_to_descriptor.find(range_pos->second);
if (pos != m_isa_to_descriptor.end()) {
if (pos->second->GetClassName() == name)
return pos;
}
}
}
}
return end;
}
std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
ObjCLanguageRuntime::ISAToDescriptorIterator>
ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) {
if (update_if_needed)
UpdateISAToDescriptorMapIfNeeded();
return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,
ObjCLanguageRuntime::ISAToDescriptorIterator>(
m_isa_to_descriptor.begin(), m_isa_to_descriptor.end());
}
ObjCLanguageRuntime::ObjCISA
ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) {
ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa));
if (objc_class_sp) {
ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass());
if (objc_super_class_sp)
return objc_super_class_sp->GetISA();
}
return 0;
}
ConstString
ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) {
ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(isa));
if (objc_class_sp)
return objc_class_sp->GetClassName();
return ConstString();
}
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetClassDescriptorFromClassName(
const ConstString &class_name) {
ISAToDescriptorIterator pos = GetDescriptorIterator(class_name);
if (pos != m_isa_to_descriptor.end())
return pos->second;
return ClassDescriptorSP();
}
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) {
ClassDescriptorSP objc_class_sp;
// if we get an invalid VO (which might still happen when playing around
// with pointers returned by the expression parser, don't consider this
// a valid ObjC object)
if (valobj.GetCompilerType().IsValid()) {
addr_t isa_pointer = valobj.GetPointerValue();
if (isa_pointer != LLDB_INVALID_ADDRESS) {
ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
Process *process = exe_ctx.GetProcessPtr();
if (process) {
Status error;
ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
if (isa != LLDB_INVALID_ADDRESS)
objc_class_sp = GetClassDescriptorFromISA(isa);
}
}
}
return objc_class_sp;
}
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) {
ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp(
GetClassDescriptor(valobj));
if (objc_class_sp) {
if (!objc_class_sp->IsKVO())
return objc_class_sp;
ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
return non_kvo_objc_class_sp;
}
return ClassDescriptorSP();
}
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) {
if (isa) {
UpdateISAToDescriptorMap();
ObjCLanguageRuntime::ISAToDescriptorIterator pos =
m_isa_to_descriptor.find(isa);
if (pos != m_isa_to_descriptor.end())
return pos->second;
}
return ClassDescriptorSP();
}
ObjCLanguageRuntime::ClassDescriptorSP
ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) {
if (isa) {
ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa);
if (objc_class_sp && objc_class_sp->IsValid()) {
if (!objc_class_sp->IsKVO())
return objc_class_sp;
ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass());
if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid())
return non_kvo_objc_class_sp;
}
}
return ClassDescriptorSP();
}
CompilerType
ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name,
bool for_expression) {
if (m_scratch_ast_ctx_ap)
return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression);
return CompilerType();
}
CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType(
ClangASTContext &ast_ctx, const char *name, bool for_expression) {
clang::ASTContext *clang_ast = ast_ctx.getASTContext();
if (!clang_ast)
return CompilerType();
return RealizeType(*clang_ast, name, for_expression);
}
ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() {
return nullptr;
}
bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type,
uint64_t &size) {
void *opaque_ptr = compiler_type.GetOpaqueQualType();
size = m_type_size_cache.Lookup(opaque_ptr);
// an ObjC object will at least have an ISA, so 0 is definitely not OK
if (size > 0)
return true;
ClassDescriptorSP class_descriptor_sp =
GetClassDescriptorFromClassName(compiler_type.GetTypeName());
if (!class_descriptor_sp)
return false;
int32_t max_offset = INT32_MIN;
uint64_t sizeof_max = 0;
bool found = false;
for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) {
const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx);
int32_t cur_offset = ivar.m_offset;
if (cur_offset > max_offset) {
max_offset = cur_offset;
sizeof_max = ivar.m_size;
found = true;
}
}
size = 8 * (max_offset + sizeof_max);
if (found)
m_type_size_cache.Insert(opaque_ptr, size);
return found;
}
//------------------------------------------------------------------
// Exception breakpoint Precondition class for ObjC:
//------------------------------------------------------------------
void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(
const char *class_name) {
m_class_names.insert(class_name);
}
ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {}
bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(
StoppointCallbackContext &context) {
return true;
}
void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(
Stream &stream, lldb::DescriptionLevel level) {}
Status ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(
Args &args) {
Status error;
if (args.GetArgumentCount() > 0)
error.SetErrorString(
"The ObjC Exception breakpoint doesn't support extra options.");
return error;
}

View File

@@ -0,0 +1,59 @@
//===-- OperatingSystem.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/Target/OperatingSystem.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
OperatingSystem *OperatingSystem::FindPlugin(Process *process,
const char *plugin_name) {
OperatingSystemCreateInstance create_callback = nullptr;
if (plugin_name) {
ConstString const_plugin_name(plugin_name);
create_callback =
PluginManager::GetOperatingSystemCreateCallbackForPluginName(
const_plugin_name);
if (create_callback) {
std::unique_ptr<OperatingSystem> instance_ap(
create_callback(process, true));
if (instance_ap)
return instance_ap.release();
}
} else {
for (uint32_t idx = 0;
(create_callback =
PluginManager::GetOperatingSystemCreateCallbackAtIndex(idx)) !=
nullptr;
++idx) {
std::unique_ptr<OperatingSystem> instance_ap(
create_callback(process, false));
if (instance_ap)
return instance_ap.release();
}
}
return nullptr;
}
OperatingSystem::OperatingSystem(Process *process) : m_process(process) {}
OperatingSystem::~OperatingSystem() = default;
bool OperatingSystem::IsOperatingSystemPluginThread(
const lldb::ThreadSP &thread_sp) {
if (thread_sp)
return thread_sp->IsOperatingSystemPluginThread();
return false;
}

View File

@@ -0,0 +1,290 @@
//===-- PathMappingList.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 <climits>
#include <cstring>
// Other libraries and framework includes
// Project includes
#include "lldb/Host/PosixApi.h"
#include "lldb/Target/PathMappingList.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// PathMappingList constructor
//----------------------------------------------------------------------
PathMappingList::PathMappingList()
: m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {}
PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton)
: m_pairs(), m_callback(callback), m_callback_baton(callback_baton),
m_mod_id(0) {}
PathMappingList::PathMappingList(const PathMappingList &rhs)
: m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr),
m_mod_id(0) {}
const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) {
if (this != &rhs) {
m_pairs = rhs.m_pairs;
m_callback = nullptr;
m_callback_baton = nullptr;
m_mod_id = rhs.m_mod_id;
}
return *this;
}
PathMappingList::~PathMappingList() = default;
void PathMappingList::Append(const ConstString &path,
const ConstString &replacement, bool notify) {
++m_mod_id;
m_pairs.push_back(pair(path, replacement));
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
void PathMappingList::Append(const PathMappingList &rhs, bool notify) {
++m_mod_id;
if (!rhs.m_pairs.empty()) {
const_iterator pos, end = rhs.m_pairs.end();
for (pos = rhs.m_pairs.begin(); pos != end; ++pos)
m_pairs.push_back(*pos);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
}
void PathMappingList::Insert(const ConstString &path,
const ConstString &replacement, uint32_t index,
bool notify) {
++m_mod_id;
iterator insert_iter;
if (index >= m_pairs.size())
insert_iter = m_pairs.end();
else
insert_iter = m_pairs.begin() + index;
m_pairs.insert(insert_iter, pair(path, replacement));
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
bool PathMappingList::Replace(const ConstString &path,
const ConstString &replacement, uint32_t index,
bool notify) {
if (index >= m_pairs.size())
return false;
++m_mod_id;
m_pairs[index] = pair(path, replacement);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
bool PathMappingList::Remove(size_t index, bool notify) {
if (index >= m_pairs.size())
return false;
++m_mod_id;
iterator iter = m_pairs.begin() + index;
m_pairs.erase(iter);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
// For clients which do not need the pair index dumped, pass a pair_index >= 0
// to only dump the indicated pair.
void PathMappingList::Dump(Stream *s, int pair_index) {
unsigned int numPairs = m_pairs.size();
if (pair_index < 0) {
unsigned int index;
for (index = 0; index < numPairs; ++index)
s->Printf("[%d] \"%s\" -> \"%s\"\n", index,
m_pairs[index].first.GetCString(),
m_pairs[index].second.GetCString());
} else {
if (static_cast<unsigned int>(pair_index) < numPairs)
s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(),
m_pairs[pair_index].second.GetCString());
}
}
void PathMappingList::Clear(bool notify) {
if (!m_pairs.empty())
++m_mod_id;
m_pairs.clear();
if (notify && m_callback)
m_callback(*this, m_callback_baton);
}
bool PathMappingList::RemapPath(const ConstString &path,
ConstString &new_path) const {
const char *path_cstr = path.GetCString();
// CLEANUP: Convert this function to use StringRefs internally instead
// of raw c-strings.
if (!path_cstr)
return false;
const_iterator pos, end = m_pairs.end();
for (pos = m_pairs.begin(); pos != end; ++pos) {
const size_t prefixLen = pos->first.GetLength();
if (::strncmp(pos->first.GetCString(), path_cstr, prefixLen) == 0) {
std::string new_path_str(pos->second.GetCString());
new_path_str.append(path.GetCString() + prefixLen);
new_path.SetCString(new_path_str.c_str());
return true;
}
}
return false;
}
bool PathMappingList::RemapPath(llvm::StringRef path,
std::string &new_path) const {
if (m_pairs.empty() || path.empty())
return false;
const_iterator pos, end = m_pairs.end();
for (pos = m_pairs.begin(); pos != end; ++pos) {
if (!path.consume_front(pos->first.GetStringRef()))
continue;
new_path = pos->second.GetStringRef();
new_path.append(path);
return true;
}
return false;
}
bool PathMappingList::ReverseRemapPath(const ConstString &path,
ConstString &new_path) const {
const char *path_cstr = path.GetCString();
if (!path_cstr)
return false;
for (const auto &it : m_pairs) {
// FIXME: This should be using FileSpec API's to do the path appending.
const size_t prefixLen = it.second.GetLength();
if (::strncmp(it.second.GetCString(), path_cstr, prefixLen) == 0) {
std::string new_path_str(it.first.GetCString());
new_path_str.append(path.GetCString() + prefixLen);
new_path.SetCString(new_path_str.c_str());
return true;
}
}
return false;
}
bool PathMappingList::FindFile(const FileSpec &orig_spec,
FileSpec &new_spec) const {
if (!m_pairs.empty()) {
char orig_path[PATH_MAX];
const size_t orig_path_len =
orig_spec.GetPath(orig_path, sizeof(orig_path));
if (orig_path_len > 0) {
const_iterator pos, end = m_pairs.end();
for (pos = m_pairs.begin(); pos != end; ++pos) {
const size_t prefix_len = pos->first.GetLength();
if (orig_path_len >= prefix_len) {
if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) {
new_spec.SetFile(pos->second.GetCString(), false);
new_spec.AppendPathComponent(orig_path + prefix_len);
if (new_spec.Exists())
return true;
}
}
}
}
}
new_spec.Clear();
return false;
}
bool PathMappingList::Replace(const ConstString &path,
const ConstString &new_path, bool notify) {
uint32_t idx = FindIndexForPath(path);
if (idx < m_pairs.size()) {
++m_mod_id;
m_pairs[idx].second = new_path;
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
return false;
}
bool PathMappingList::Remove(const ConstString &path, bool notify) {
iterator pos = FindIteratorForPath(path);
if (pos != m_pairs.end()) {
++m_mod_id;
m_pairs.erase(pos);
if (notify && m_callback)
m_callback(*this, m_callback_baton);
return true;
}
return false;
}
PathMappingList::const_iterator
PathMappingList::FindIteratorForPath(const ConstString &path) const {
const_iterator pos;
const_iterator begin = m_pairs.begin();
const_iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
break;
}
return pos;
}
PathMappingList::iterator
PathMappingList::FindIteratorForPath(const ConstString &path) {
iterator pos;
iterator begin = m_pairs.begin();
iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
break;
}
return pos;
}
bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path,
ConstString &new_path) const {
if (idx < m_pairs.size()) {
path = m_pairs[idx].first;
new_path = m_pairs[idx].second;
return true;
}
return false;
}
uint32_t PathMappingList::FindIndexForPath(const ConstString &path) const {
const_iterator pos;
const_iterator begin = m_pairs.begin();
const_iterator end = m_pairs.end();
for (pos = begin; pos != end; ++pos) {
if (pos->first == path)
return std::distance(begin, pos);
}
return UINT32_MAX;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1 @@
8fb149fab063373a56fb7bc5b82aa06ab7dbcfbf

View File

@@ -0,0 +1,121 @@
//===-- ProcessInfo.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/Target/ProcessInfo.h"
// C Includes
// C++ Includes
#include <climits>
// Other libraries and framework includes
// Project includes
#include "lldb/Host/PosixApi.h"
#include "lldb/Utility/Stream.h"
#include "llvm/ADT/SmallString.h"
using namespace lldb;
using namespace lldb_private;
ProcessInfo::ProcessInfo()
: m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX),
m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {}
ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
lldb::pid_t pid)
: m_executable(name, false), m_arguments(), m_environment(),
m_uid(UINT32_MAX), m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {}
void ProcessInfo::Clear() {
m_executable.Clear();
m_arguments.Clear();
m_environment.Clear();
m_uid = UINT32_MAX;
m_gid = UINT32_MAX;
m_arch.Clear();
m_pid = LLDB_INVALID_PROCESS_ID;
}
const char *ProcessInfo::GetName() const {
return m_executable.GetFilename().GetCString();
}
size_t ProcessInfo::GetNameLength() const {
return m_executable.GetFilename().GetLength();
}
void ProcessInfo::Dump(Stream &s, Platform *platform) const {
s << "Executable: " << GetName() << "\n";
s << "Triple: ";
m_arch.DumpTriple(s);
s << "\n";
s << "Arguments:\n";
m_arguments.Dump(s);
s << "Environment:\n";
m_environment.Dump(s, "env");
}
void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
bool add_exe_file_as_first_arg) {
if (exe_file) {
m_executable = exe_file;
if (add_exe_file_as_first_arg) {
llvm::SmallString<PATH_MAX> filename;
exe_file.GetPath(filename);
if (!filename.empty())
m_arguments.InsertArgumentAtIndex(0, filename);
}
} else {
m_executable.Clear();
}
}
llvm::StringRef ProcessInfo::GetArg0() const {
return m_arg0;
}
void ProcessInfo::SetArg0(llvm::StringRef arg) {
m_arg0 = arg;
}
void ProcessInfo::SetArguments(char const **argv,
bool first_arg_is_executable) {
m_arguments.SetArguments(argv);
// Is the first argument the executable?
if (first_arg_is_executable) {
const char *first_arg = m_arguments.GetArgumentAtIndex(0);
if (first_arg) {
// Yes the first argument is an executable, set it as the executable
// in the launch options. Don't resolve the file path as the path
// could be a remote platform path
const bool resolve = false;
m_executable.SetFile(first_arg, resolve);
}
}
}
void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
// Copy all arguments
m_arguments = args;
// Is the first argument the executable?
if (first_arg_is_executable) {
const char *first_arg = m_arguments.GetArgumentAtIndex(0);
if (first_arg) {
// Yes the first argument is an executable, set it as the executable
// in the launch options. Don't resolve the file path as the path
// could be a remote platform path
const bool resolve = false;
m_executable.SetFile(first_arg, resolve);
}
}
}

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