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,5 @@
add_subdirectory(CPlusPlus)
add_subdirectory(ObjC)
add_subdirectory(Go)
add_subdirectory(Java)
add_subdirectory(RenderScript)

View File

@@ -0,0 +1,2 @@
add_subdirectory(ItaniumABI)
#add_subdirectory(MicrosoftABI)

View File

@@ -0,0 +1,10 @@
add_lldb_library(lldbPluginCXXItaniumABI PLUGIN
ItaniumABILanguageRuntime.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbInterpreter
lldbSymbol
lldbTarget
)

View File

@@ -0,0 +1,115 @@
//===-- ItaniumABILanguageRuntime.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ItaniumABILanguageRuntime_h_
#define liblldb_ItaniumABILanguageRuntime_h_
// C Includes
// C++ Includes
#include <map>
#include <mutex>
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Core/Value.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/CPPLanguageRuntime.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ItaniumABILanguageRuntime : public lldb_private::CPPLanguageRuntime {
public:
~ItaniumABILanguageRuntime() override = default;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void Initialize();
static void Terminate();
static lldb_private::LanguageRuntime *
CreateInstance(Process *process, lldb::LanguageType language);
static lldb_private::ConstString GetPluginNameStatic();
bool IsVTableName(const char *name) override;
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
void SetExceptionBreakpoints() override;
void ClearExceptionBreakpoints() override;
bool ExceptionBreakpointsAreSet() override;
bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override;
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
bool catch_bp,
bool throw_bp) override;
lldb::SearchFilterSP CreateExceptionSearchFilter() override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
protected:
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
bool catch_bp,
bool throw_bp,
bool for_expressions);
lldb::BreakpointSP CreateExceptionBreakpoint(bool catch_bp, bool throw_bp,
bool for_expressions,
bool is_internal);
private:
typedef std::map<lldb_private::Address, TypeAndOrName> DynamicTypeCache;
ItaniumABILanguageRuntime(Process *process)
: // Call CreateInstance instead.
lldb_private::CPPLanguageRuntime(process),
m_cxx_exception_bp_sp(), m_dynamic_type_map(),
m_dynamic_type_map_mutex() {}
lldb::BreakpointSP m_cxx_exception_bp_sp;
DynamicTypeCache m_dynamic_type_map;
std::mutex m_dynamic_type_map_mutex;
TypeAndOrName GetTypeInfoFromVTableAddress(ValueObject &in_value,
lldb::addr_t original_ptr,
lldb::addr_t vtable_addr);
TypeAndOrName GetDynamicTypeInfo(const lldb_private::Address &vtable_addr);
void SetDynamicTypeInfo(const lldb_private::Address &vtable_addr,
const TypeAndOrName &type_info);
};
} // namespace lldb_private
#endif // liblldb_ItaniumABILanguageRuntime_h_

View File

@@ -0,0 +1,13 @@
set(LLVM_NO_RTTI 1)
add_lldb_library(lldbPluginLanguageRuntimeGo PLUGIN
GoLanguageRuntime.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbSymbol
lldbTarget
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,215 @@
//===-- GoLanguageRuntime.cpp --------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "GoLanguageRuntime.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "llvm/ADT/Twine.h"
#include <vector>
using namespace lldb;
using namespace lldb_private;
namespace {
ValueObjectSP GetChild(ValueObject &obj, const char *name,
bool dereference = true) {
ConstString name_const_str(name);
ValueObjectSP result = obj.GetChildMemberWithName(name_const_str, true);
if (dereference && result && result->IsPointerType()) {
Status err;
result = result->Dereference(err);
if (err.Fail())
result.reset();
}
return result;
}
ConstString ReadString(ValueObject &str, Process *process) {
ConstString result;
ValueObjectSP data = GetChild(str, "str", false);
ValueObjectSP len = GetChild(str, "len");
if (len && data) {
Status err;
lldb::addr_t addr = data->GetPointerValue();
if (addr == LLDB_INVALID_ADDRESS)
return result;
uint64_t byte_size = len->GetValueAsUnsigned(0);
char *buf = new char[byte_size + 1];
buf[byte_size] = 0;
size_t bytes_read = process->ReadMemory(addr, buf, byte_size, err);
if (!(err.Fail() || bytes_read != byte_size))
result = ConstString(buf, bytes_read);
delete[] buf;
}
return result;
}
ConstString ReadTypeName(ValueObjectSP type, Process *process) {
if (ValueObjectSP uncommon = GetChild(*type, "x")) {
ValueObjectSP name = GetChild(*uncommon, "name");
ValueObjectSP package = GetChild(*uncommon, "pkgpath");
if (name && name->GetPointerValue() != 0 && package &&
package->GetPointerValue() != 0) {
ConstString package_const_str = ReadString(*package, process);
ConstString name_const_str = ReadString(*name, process);
if (package_const_str.GetLength() == 0)
return name_const_str;
return ConstString((package_const_str.GetStringRef() + "." +
name_const_str.GetStringRef())
.str());
}
}
ValueObjectSP name = GetChild(*type, "_string");
if (name)
return ReadString(*name, process);
return ConstString("");
}
CompilerType LookupRuntimeType(ValueObjectSP type, ExecutionContext *exe_ctx,
bool *is_direct) {
uint8_t kind = GetChild(*type, "kind")->GetValueAsUnsigned(0);
*is_direct = GoASTContext::IsDirectIface(kind);
if (GoASTContext::IsPointerKind(kind)) {
CompilerType type_ptr = type->GetCompilerType().GetPointerType();
Status err;
ValueObjectSP elem =
type->CreateValueObjectFromAddress("elem", type->GetAddressOf() +
type->GetByteSize(),
*exe_ctx, type_ptr)
->Dereference(err);
if (err.Fail())
return CompilerType();
bool tmp_direct;
return LookupRuntimeType(elem, exe_ctx, &tmp_direct).GetPointerType();
}
Target *target = exe_ctx->GetTargetPtr();
Process *process = exe_ctx->GetProcessPtr();
ConstString const_typename = ReadTypeName(type, process);
if (const_typename.GetLength() == 0)
return CompilerType();
SymbolContext sc;
TypeList type_list;
llvm::DenseSet<SymbolFile *> searched_symbol_files;
uint32_t num_matches = target->GetImages().FindTypes(
sc, const_typename, false, 2, searched_symbol_files, type_list);
if (num_matches > 0) {
return type_list.GetTypeAtIndex(0)->GetFullCompilerType();
}
return CompilerType();
}
}
bool GoLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
return GoASTContext::IsGoInterface(in_value.GetCompilerType());
}
bool GoLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &dynamic_address,
Value::ValueType &value_type) {
value_type = Value::eValueTypeScalar;
class_type_or_name.Clear();
if (CouldHaveDynamicValue(in_value)) {
Status err;
ValueObjectSP iface = in_value.GetStaticValue();
ValueObjectSP data_sp = GetChild(*iface, "data", false);
if (!data_sp)
return false;
if (ValueObjectSP tab = GetChild(*iface, "tab"))
iface = tab;
ValueObjectSP type = GetChild(*iface, "_type");
if (!type) {
return false;
}
bool direct;
ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
CompilerType final_type = LookupRuntimeType(type, &exe_ctx, &direct);
if (!final_type)
return false;
if (direct) {
class_type_or_name.SetCompilerType(final_type);
} else {
// TODO: implement reference types or fix caller to support dynamic types
// that aren't pointers
// so we don't have to introduce this extra pointer.
class_type_or_name.SetCompilerType(final_type.GetPointerType());
}
dynamic_address.SetLoadAddress(data_sp->GetPointerValue(),
exe_ctx.GetTargetPtr());
return true;
}
return false;
}
TypeAndOrName
GoLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) {
return type_and_or_name;
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
LanguageRuntime *
GoLanguageRuntime::CreateInstance(Process *process,
lldb::LanguageType language) {
if (language == eLanguageTypeGo)
return new GoLanguageRuntime(process);
else
return NULL;
}
void GoLanguageRuntime::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), "Go Language Runtime",
CreateInstance);
}
void GoLanguageRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString GoLanguageRuntime::GetPluginNameStatic() {
static ConstString g_name("golang");
return g_name;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GoLanguageRuntime::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t GoLanguageRuntime::GetPluginVersion() { return 1; }

View File

@@ -0,0 +1,86 @@
//===-- GoLanguageRuntime.h -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_GoLanguageRuntime_h_
#define liblldb_GoLanguageRuntime_h_
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/BreakpointResolver.h"
#include "lldb/Core/Value.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class GoLanguageRuntime : public lldb_private::LanguageRuntime {
public:
~GoLanguageRuntime() override = default;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void Initialize();
static void Terminate();
static lldb_private::LanguageRuntime *
CreateInstance(Process *process, lldb::LanguageType language);
static lldb_private::ConstString GetPluginNameStatic();
lldb::LanguageType GetLanguageType() const override {
return lldb::eLanguageTypeGo;
}
bool GetObjectDescription(Stream &str, ValueObject &object) override {
// TODO(ribrdb): Maybe call String() method?
return false;
}
bool GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override {
return false;
}
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
bool catch_bp,
bool throw_bp) override {
return lldb::BreakpointResolverSP();
}
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
private:
GoLanguageRuntime(Process *process)
: lldb_private::LanguageRuntime(process) {
} // Call CreateInstance instead.
};
} // namespace lldb_private
#endif // liblldb_GoLanguageRuntime_h_

View File

@@ -0,0 +1,10 @@
add_lldb_library(lldbPluginLanguageRuntimeJava PLUGIN
JavaLanguageRuntime.cpp
LINK_LIBS
lldbCore
lldbSymbol
lldbTarget
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,157 @@
//===-- JavaLanguageRuntime.cpp ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "JavaLanguageRuntime.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/JavaASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb;
using namespace lldb_private;
JavaLanguageRuntime::JavaLanguageRuntime(Process *process)
: LanguageRuntime(process) {}
LanguageRuntime *
JavaLanguageRuntime::CreateInstance(Process *process,
lldb::LanguageType language) {
if (language == eLanguageTypeJava)
return new JavaLanguageRuntime(process);
return nullptr;
}
void JavaLanguageRuntime::Initialize() {
PluginManager::RegisterPlugin(GetPluginNameStatic(), "Java language runtime",
CreateInstance);
}
void JavaLanguageRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString JavaLanguageRuntime::GetPluginNameStatic() {
static ConstString g_name("java");
return g_name;
}
lldb_private::ConstString JavaLanguageRuntime::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t JavaLanguageRuntime::GetPluginVersion() { return 1; }
bool JavaLanguageRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
return true;
}
static ConstString GetDynamicTypeId(ExecutionContext *exe_ctx, Target *target,
ValueObject &in_value) {
SymbolContext sc;
TypeList class_types;
llvm::DenseSet<SymbolFile *> searched_symbol_files;
size_t num_matches = target->GetImages().FindTypes(
sc, ConstString("Object"),
true, // name_is_fully_qualified
UINT32_MAX, searched_symbol_files, class_types);
for (size_t i = 0; i < num_matches; ++i) {
TypeSP type_sp = class_types.GetTypeAtIndex(i);
CompilerType compiler_type = type_sp->GetFullCompilerType();
if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava ||
compiler_type.GetTypeName() != ConstString("java::lang::Object"))
continue;
if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) {
uint64_t type_id = JavaASTContext::CalculateDynamicTypeId(
exe_ctx, compiler_type, in_value);
if (type_id != UINT64_MAX) {
char id[32];
snprintf(id, sizeof(id), "0x%" PRIX64, type_id);
return ConstString(id);
}
}
}
return ConstString();
}
bool JavaLanguageRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &dynamic_address,
Value::ValueType &value_type) {
class_type_or_name.Clear();
// null references don't have a dynamic type
if (in_value.IsNilReference())
return false;
ExecutionContext exe_ctx(in_value.GetExecutionContextRef());
Target *target = exe_ctx.GetTargetPtr();
if (!target)
return false;
ConstString linkage_name;
CompilerType in_type = in_value.GetCompilerType();
if (in_type.IsPossibleDynamicType(nullptr, false, false))
linkage_name = GetDynamicTypeId(&exe_ctx, target, in_value);
else
linkage_name = JavaASTContext::GetLinkageName(in_type);
if (!linkage_name)
return false;
class_type_or_name.SetName(in_type.GetNonReferenceType().GetTypeName());
SymbolContext sc;
TypeList class_types;
llvm::DenseSet<SymbolFile *> searched_symbol_files;
size_t num_matches = target->GetImages().FindTypes(
sc, linkage_name,
true, // name_is_fully_qualified
UINT32_MAX, searched_symbol_files, class_types);
for (size_t i = 0; i < num_matches; ++i) {
TypeSP type_sp = class_types.GetTypeAtIndex(i);
CompilerType compiler_type = type_sp->GetFullCompilerType();
if (compiler_type.GetMinimumLanguage() != eLanguageTypeJava)
continue;
if (compiler_type.GetCompleteType() && compiler_type.IsCompleteType()) {
class_type_or_name.SetTypeSP(type_sp);
Value &value = in_value.GetValue();
value_type = value.GetValueType();
dynamic_address.SetRawAddress(value.GetScalar().ULongLong(0));
return true;
}
}
return false;
}
TypeAndOrName
JavaLanguageRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) {
CompilerType static_type(static_value.GetCompilerType());
TypeAndOrName ret(type_and_or_name);
if (type_and_or_name.HasType()) {
CompilerType orig_type = type_and_or_name.GetCompilerType();
if (static_type.IsReferenceType())
ret.SetCompilerType(orig_type.GetLValueReferenceType());
}
return ret;
}

View File

@@ -0,0 +1,78 @@
//===-- JavaLanguageRuntime.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_JavaLanguageRuntime_h_
#define liblldb_JavaLanguageRuntime_h_
// C Includes
// C++ Includes
#include <vector>
// Other libraries and framework includes
// Project includes
#include "lldb/Core/PluginInterface.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class JavaLanguageRuntime : public LanguageRuntime {
public:
static void Initialize();
static void Terminate();
static lldb_private::LanguageRuntime *
CreateInstance(Process *process, lldb::LanguageType language);
static lldb_private::ConstString GetPluginNameStatic();
lldb_private::ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
lldb::LanguageType GetLanguageType() const override {
return lldb::eLanguageTypeJava;
}
bool GetObjectDescription(Stream &str, ValueObject &object) override {
return false;
}
bool GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override {
return false;
}
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
bool catch_bp,
bool throw_bp) override {
return nullptr;
}
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
protected:
JavaLanguageRuntime(Process *process);
private:
DISALLOW_COPY_AND_ASSIGN(JavaLanguageRuntime);
};
} // namespace lldb_private
#endif // liblldb_JavaLanguageRuntime_h_

View File

@@ -0,0 +1,335 @@
//===-- AppleObjCClassDescriptorV2.h ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_AppleObjCClassDescriptorV2_h_
#define liblldb_AppleObjCClassDescriptorV2_h_
// C Includes
// C++ Includes
#include <mutex>
// Other libraries and framework includes
// Project includes
#include "AppleObjCRuntimeV2.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
public:
friend class lldb_private::AppleObjCRuntimeV2;
~ClassDescriptorV2() override = default;
ConstString GetClassName() override;
ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override;
ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override;
bool IsValid() override {
return true; // any Objective-C v2 runtime class descriptor we vend is valid
}
// a custom descriptor is used for tagged pointers
bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
uint64_t *value_bits = nullptr,
uint64_t *payload = nullptr) override {
return false;
}
uint64_t GetInstanceSize() override;
ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }
bool Describe(
std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
std::function<bool(const char *, const char *)> const
&instance_method_func,
std::function<bool(const char *, const char *)> const &class_method_func,
std::function<bool(const char *, const char *, lldb::addr_t,
uint64_t)> const &ivar_func) const override;
size_t GetNumIVars() override {
GetIVarInformation();
return m_ivars_storage.size();
}
iVarDescriptor GetIVarAtIndex(size_t idx) override {
if (idx >= GetNumIVars())
return iVarDescriptor();
return m_ivars_storage[idx];
}
protected:
void GetIVarInformation();
private:
static const uint32_t RW_REALIZED = (1 << 31);
struct objc_class_t {
ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass.
ObjCLanguageRuntime::ObjCISA m_superclass;
lldb::addr_t m_cache_ptr;
lldb::addr_t m_vtable_ptr;
lldb::addr_t m_data_ptr;
uint8_t m_flags;
objc_class_t()
: m_isa(0), m_superclass(0), m_cache_ptr(0), m_vtable_ptr(0),
m_data_ptr(0), m_flags(0) {}
void Clear() {
m_isa = 0;
m_superclass = 0;
m_cache_ptr = 0;
m_vtable_ptr = 0;
m_data_ptr = 0;
m_flags = 0;
}
bool Read(Process *process, lldb::addr_t addr);
};
struct class_ro_t {
uint32_t m_flags;
uint32_t m_instanceStart;
uint32_t m_instanceSize;
uint32_t m_reserved;
lldb::addr_t m_ivarLayout_ptr;
lldb::addr_t m_name_ptr;
lldb::addr_t m_baseMethods_ptr;
lldb::addr_t m_baseProtocols_ptr;
lldb::addr_t m_ivars_ptr;
lldb::addr_t m_weakIvarLayout_ptr;
lldb::addr_t m_baseProperties_ptr;
std::string m_name;
bool Read(Process *process, lldb::addr_t addr);
};
struct class_rw_t {
uint32_t m_flags;
uint32_t m_version;
lldb::addr_t m_ro_ptr;
union {
lldb::addr_t m_method_list_ptr;
lldb::addr_t m_method_lists_ptr;
};
lldb::addr_t m_properties_ptr;
lldb::addr_t m_protocols_ptr;
ObjCLanguageRuntime::ObjCISA m_firstSubclass;
ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
bool Read(Process *process, lldb::addr_t addr);
};
struct method_list_t {
uint32_t m_entsize;
uint32_t m_count;
lldb::addr_t m_first_ptr;
bool Read(Process *process, lldb::addr_t addr);
};
struct method_t {
lldb::addr_t m_name_ptr;
lldb::addr_t m_types_ptr;
lldb::addr_t m_imp_ptr;
std::string m_name;
std::string m_types;
static size_t GetSize(Process *process) {
size_t ptr_size = process->GetAddressByteSize();
return ptr_size // SEL name;
+ ptr_size // const char *types;
+ ptr_size; // IMP imp;
}
bool Read(Process *process, lldb::addr_t addr);
};
struct ivar_list_t {
uint32_t m_entsize;
uint32_t m_count;
lldb::addr_t m_first_ptr;
bool Read(Process *process, lldb::addr_t addr);
};
struct ivar_t {
lldb::addr_t m_offset_ptr;
lldb::addr_t m_name_ptr;
lldb::addr_t m_type_ptr;
uint32_t m_alignment;
uint32_t m_size;
std::string m_name;
std::string m_type;
static size_t GetSize(Process *process) {
size_t ptr_size = process->GetAddressByteSize();
return ptr_size // uintptr_t *offset;
+ ptr_size // const char *name;
+ ptr_size // const char *type;
+ sizeof(uint32_t) // uint32_t alignment;
+ sizeof(uint32_t); // uint32_t size;
}
bool Read(Process *process, lldb::addr_t addr);
};
class iVarsStorage {
public:
iVarsStorage();
size_t size();
iVarDescriptor &operator[](size_t idx);
void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
private:
bool m_filled;
std::vector<iVarDescriptor> m_ivars;
std::recursive_mutex m_mutex;
};
// The constructor should only be invoked by the runtime as it builds its
// caches
// or populates them. A ClassDescriptorV2 should only ever exist in a cache.
ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
ObjCLanguageRuntime::ObjCISA isa, const char *name)
: m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
m_ivars_storage() {}
bool Read_objc_class(Process *process,
std::unique_ptr<objc_class_t> &objc_class) const;
bool Read_class_row(Process *process, const objc_class_t &objc_class,
std::unique_ptr<class_ro_t> &class_ro,
std::unique_ptr<class_rw_t> &class_rw) const;
AppleObjCRuntimeV2
&m_runtime; // The runtime, so we can read information lazily.
lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e.,
// objects of this class type have this as
// their ISA)
ConstString m_name; // May be NULL
iVarsStorage m_ivars_storage;
};
// tagged pointer descriptor
class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
public:
ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
m_name = class_name;
if (!m_name) {
m_valid = false;
return;
}
m_valid = true;
m_payload = payload;
m_info_bits = (m_payload & 0xF0ULL) >> 4;
m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
}
ClassDescriptorV2Tagged(
ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
uint64_t payload) {
if (!actual_class_sp) {
m_valid = false;
return;
}
m_name = actual_class_sp->GetClassName();
if (!m_name) {
m_valid = false;
return;
}
m_valid = true;
m_payload = payload;
m_info_bits = (m_payload & 0x0FULL);
m_value_bits = (m_payload & ~0x0FULL) >> 4;
}
~ClassDescriptorV2Tagged() override = default;
ConstString GetClassName() override { return m_name; }
ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override {
// tagged pointers can represent a class that has a superclass, but since
// that information is not
// stored in the object itself, we would have to query the runtime to
// discover the hierarchy
// for the time being, we skip this step in the interest of static discovery
return ObjCLanguageRuntime::ClassDescriptorSP();
}
ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override {
return ObjCLanguageRuntime::ClassDescriptorSP();
}
bool IsValid() override { return m_valid; }
bool IsKVO() override {
return false; // tagged pointers are not KVO'ed
}
bool IsCFType() override {
return false; // tagged pointers are not CF objects
}
bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
uint64_t *value_bits = nullptr,
uint64_t *payload = nullptr) override {
if (info_bits)
*info_bits = GetInfoBits();
if (value_bits)
*value_bits = GetValueBits();
if (payload)
*payload = GetPayload();
return true;
}
uint64_t GetInstanceSize() override {
return (IsValid() ? m_pointer_size : 0);
}
ObjCLanguageRuntime::ObjCISA GetISA() override {
return 0; // tagged pointers have no ISA
}
// these calls are not part of any formal tagged pointers specification
virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 0); }
virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 0); }
virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 0); }
private:
ConstString m_name;
uint8_t m_pointer_size;
bool m_valid;
uint64_t m_info_bits;
uint64_t m_value_bits;
uint64_t m_payload;
};
} // namespace lldb_private
#endif // liblldb_AppleObjCClassDescriptorV2_h_

View File

@@ -0,0 +1,55 @@
//===-- AppleObjCDeclVendor.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_AppleObjCDeclVendor_h_
#define liblldb_AppleObjCDeclVendor_h_
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class AppleObjCExternalASTSource;
class AppleObjCDeclVendor : public DeclVendor {
public:
AppleObjCDeclVendor(ObjCLanguageRuntime &runtime);
uint32_t FindDecls(const ConstString &name, bool append, uint32_t max_matches,
std::vector<clang::NamedDecl *> &decls) override;
clang::ExternalASTMerger::ImporterSource GetImporterSource() override;
friend class AppleObjCExternalASTSource;
private:
clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa);
bool FinishDecl(clang::ObjCInterfaceDecl *decl);
ObjCLanguageRuntime &m_runtime;
ClangASTContext m_ast_ctx;
ObjCLanguageRuntime::EncodingToTypeSP m_type_realizer_sp;
AppleObjCExternalASTSource *m_external_source;
typedef llvm::DenseMap<ObjCLanguageRuntime::ObjCISA,
clang::ObjCInterfaceDecl *>
ISAToInterfaceMap;
ISAToInterfaceMap m_isa_to_interface;
};
} // namespace lldb_private
#endif // liblldb_AppleObjCDeclVendor_h_

View File

@@ -0,0 +1,489 @@
//===-- AppleObjCRuntime.cpp -------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AppleObjCRuntime.h"
#include "AppleObjCTrampolineHandler.h"
#include "clang/AST/Type.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/DiagnosticManager.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
#include <vector>
using namespace lldb;
using namespace lldb_private;
static constexpr std::chrono::seconds g_po_function_timeout(15);
AppleObjCRuntime::~AppleObjCRuntime() {}
AppleObjCRuntime::AppleObjCRuntime(Process *process)
: ObjCLanguageRuntime(process), m_read_objc_library(false),
m_objc_trampoline_handler_ap(), m_Foundation_major() {
ReadObjCLibraryIfNeeded(process->GetTarget().GetImages());
}
bool AppleObjCRuntime::GetObjectDescription(Stream &str, ValueObject &valobj) {
CompilerType compiler_type(valobj.GetCompilerType());
bool is_signed;
// ObjC objects can only be pointers (or numbers that actually represents
// pointers
// but haven't been typecast, because reasons..)
if (!compiler_type.IsIntegerType(is_signed) && !compiler_type.IsPointerType())
return false;
// Make the argument list: we pass one arg, the address of our pointer, to the
// print function.
Value val;
if (!valobj.ResolveValue(val.GetScalar()))
return false;
// Value Objects may not have a process in their ExecutionContextRef. But we
// need to have one
// in the ref we pass down to eventually call description. Get it from the
// target if it isn't
// present.
ExecutionContext exe_ctx;
if (valobj.GetProcessSP()) {
exe_ctx = ExecutionContext(valobj.GetExecutionContextRef());
} else {
exe_ctx.SetContext(valobj.GetTargetSP(), true);
if (!exe_ctx.HasProcessScope())
return false;
}
return GetObjectDescription(str, val, exe_ctx.GetBestExecutionContextScope());
}
bool AppleObjCRuntime::GetObjectDescription(Stream &strm, Value &value,
ExecutionContextScope *exe_scope) {
if (!m_read_objc_library)
return false;
ExecutionContext exe_ctx;
exe_scope->CalculateExecutionContext(exe_ctx);
Process *process = exe_ctx.GetProcessPtr();
if (!process)
return false;
// We need other parts of the exe_ctx, but the processes have to match.
assert(m_process == process);
// Get the function address for the print function.
const Address *function_address = GetPrintForDebuggerAddr();
if (!function_address)
return false;
Target *target = exe_ctx.GetTargetPtr();
CompilerType compiler_type = value.GetCompilerType();
if (compiler_type) {
if (!ClangASTContext::IsObjCObjectPointerType(compiler_type)) {
strm.Printf("Value doesn't point to an ObjC object.\n");
return false;
}
} else {
// If it is not a pointer, see if we can make it into a pointer.
ClangASTContext *ast_context = target->GetScratchClangASTContext();
CompilerType opaque_type = ast_context->GetBasicType(eBasicTypeObjCID);
if (!opaque_type)
opaque_type = ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
// value.SetContext(Value::eContextTypeClangType, opaque_type_ptr);
value.SetCompilerType(opaque_type);
}
ValueList arg_value_list;
arg_value_list.PushValue(value);
// This is the return value:
ClangASTContext *ast_context = target->GetScratchClangASTContext();
CompilerType return_compiler_type = ast_context->GetCStringType(true);
Value ret;
// ret.SetContext(Value::eContextTypeClangType, return_compiler_type);
ret.SetCompilerType(return_compiler_type);
if (exe_ctx.GetFramePtr() == NULL) {
Thread *thread = exe_ctx.GetThreadPtr();
if (thread == NULL) {
exe_ctx.SetThreadSP(process->GetThreadList().GetSelectedThread());
thread = exe_ctx.GetThreadPtr();
}
if (thread) {
exe_ctx.SetFrameSP(thread->GetSelectedFrame());
}
}
// Now we're ready to call the function:
DiagnosticManager diagnostics;
lldb::addr_t wrapper_struct_addr = LLDB_INVALID_ADDRESS;
if (!m_print_object_caller_up) {
Status error;
m_print_object_caller_up.reset(
exe_scope->CalculateTarget()->GetFunctionCallerForLanguage(
eLanguageTypeObjC, return_compiler_type, *function_address,
arg_value_list, "objc-object-description", error));
if (error.Fail()) {
m_print_object_caller_up.reset();
strm.Printf("Could not get function runner to call print for debugger "
"function: %s.",
error.AsCString());
return false;
}
m_print_object_caller_up->InsertFunction(exe_ctx, wrapper_struct_addr,
diagnostics);
} else {
m_print_object_caller_up->WriteFunctionArguments(
exe_ctx, wrapper_struct_addr, arg_value_list, diagnostics);
}
EvaluateExpressionOptions options;
options.SetUnwindOnError(true);
options.SetTryAllThreads(true);
options.SetStopOthers(true);
options.SetIgnoreBreakpoints(true);
options.SetTimeout(g_po_function_timeout);
ExpressionResults results = m_print_object_caller_up->ExecuteFunction(
exe_ctx, &wrapper_struct_addr, options, diagnostics, ret);
if (results != eExpressionCompleted) {
strm.Printf("Error evaluating Print Object function: %d.\n", results);
return false;
}
addr_t result_ptr = ret.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
char buf[512];
size_t cstr_len = 0;
size_t full_buffer_len = sizeof(buf) - 1;
size_t curr_len = full_buffer_len;
while (curr_len == full_buffer_len) {
Status error;
curr_len = process->ReadCStringFromMemory(result_ptr + cstr_len, buf,
sizeof(buf), error);
strm.Write(buf, curr_len);
cstr_len += curr_len;
}
return cstr_len > 0;
}
lldb::ModuleSP AppleObjCRuntime::GetObjCModule() {
ModuleSP module_sp(m_objc_module_wp.lock());
if (module_sp)
return module_sp;
Process *process = GetProcess();
if (process) {
const ModuleList &modules = process->GetTarget().GetImages();
for (uint32_t idx = 0; idx < modules.GetSize(); idx++) {
module_sp = modules.GetModuleAtIndex(idx);
if (AppleObjCRuntime::AppleIsModuleObjCLibrary(module_sp)) {
m_objc_module_wp = module_sp;
return module_sp;
}
}
}
return ModuleSP();
}
Address *AppleObjCRuntime::GetPrintForDebuggerAddr() {
if (!m_PrintForDebugger_addr.get()) {
const ModuleList &modules = m_process->GetTarget().GetImages();
SymbolContextList contexts;
SymbolContext context;
if ((!modules.FindSymbolsWithNameAndType(ConstString("_NSPrintForDebugger"),
eSymbolTypeCode, contexts)) &&
(!modules.FindSymbolsWithNameAndType(ConstString("_CFPrintForDebugger"),
eSymbolTypeCode, contexts)))
return NULL;
contexts.GetContextAtIndex(0, context);
m_PrintForDebugger_addr.reset(new Address(context.symbol->GetAddress()));
}
return m_PrintForDebugger_addr.get();
}
bool AppleObjCRuntime::CouldHaveDynamicValue(ValueObject &in_value) {
return in_value.GetCompilerType().IsPossibleDynamicType(
NULL,
false, // do not check C++
true); // check ObjC
}
bool AppleObjCRuntime::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
return false;
}
TypeAndOrName
AppleObjCRuntime::FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) {
CompilerType static_type(static_value.GetCompilerType());
Flags static_type_flags(static_type.GetTypeInfo());
TypeAndOrName ret(type_and_or_name);
if (type_and_or_name.HasType()) {
// The type will always be the type of the dynamic object. If our parent's
// type was a pointer,
// then our type should be a pointer to the type of the dynamic object. If
// a reference, then the original type
// should be okay...
CompilerType orig_type = type_and_or_name.GetCompilerType();
CompilerType corrected_type = orig_type;
if (static_type_flags.AllSet(eTypeIsPointer))
corrected_type = orig_type.GetPointerType();
ret.SetCompilerType(corrected_type);
} else {
// If we are here we need to adjust our dynamic type name to include the
// correct & or * symbol
std::string corrected_name(type_and_or_name.GetName().GetCString());
if (static_type_flags.AllSet(eTypeIsPointer))
corrected_name.append(" *");
// the parent type should be a correctly pointer'ed or referenc'ed type
ret.SetCompilerType(static_type);
ret.SetName(corrected_name.c_str());
}
return ret;
}
bool AppleObjCRuntime::AppleIsModuleObjCLibrary(const ModuleSP &module_sp) {
if (module_sp) {
const FileSpec &module_file_spec = module_sp->GetFileSpec();
static ConstString ObjCName("libobjc.A.dylib");
if (module_file_spec) {
if (module_file_spec.GetFilename() == ObjCName)
return true;
}
}
return false;
}
// we use the version of Foundation to make assumptions about the ObjC runtime
// on a target
uint32_t AppleObjCRuntime::GetFoundationVersion() {
if (!m_Foundation_major.hasValue()) {
const ModuleList &modules = m_process->GetTarget().GetImages();
uint32_t major = UINT32_MAX;
for (uint32_t idx = 0; idx < modules.GetSize(); idx++) {
lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx);
if (!module_sp)
continue;
if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),
"Foundation") == 0) {
module_sp->GetVersion(&major, 1);
m_Foundation_major = major;
return major;
}
}
return LLDB_INVALID_MODULE_VERSION;
} else
return m_Foundation_major.getValue();
}
void AppleObjCRuntime::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
lldb::addr_t &cf_false) {
cf_true = cf_false = LLDB_INVALID_ADDRESS;
}
bool AppleObjCRuntime::IsModuleObjCLibrary(const ModuleSP &module_sp) {
return AppleIsModuleObjCLibrary(module_sp);
}
bool AppleObjCRuntime::ReadObjCLibrary(const ModuleSP &module_sp) {
// Maybe check here and if we have a handler already, and the UUID of this
// module is the same as the one in the
// current module, then we don't have to reread it?
m_objc_trampoline_handler_ap.reset(
new AppleObjCTrampolineHandler(m_process->shared_from_this(), module_sp));
if (m_objc_trampoline_handler_ap.get() != NULL) {
m_read_objc_library = true;
return true;
} else
return false;
}
ThreadPlanSP AppleObjCRuntime::GetStepThroughTrampolinePlan(Thread &thread,
bool stop_others) {
ThreadPlanSP thread_plan_sp;
if (m_objc_trampoline_handler_ap.get())
thread_plan_sp = m_objc_trampoline_handler_ap->GetStepThroughDispatchPlan(
thread, stop_others);
return thread_plan_sp;
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
ObjCLanguageRuntime::ObjCRuntimeVersions
AppleObjCRuntime::GetObjCVersion(Process *process, ModuleSP &objc_module_sp) {
if (!process)
return ObjCRuntimeVersions::eObjC_VersionUnknown;
Target &target = process->GetTarget();
if (target.GetArchitecture().GetTriple().getVendor() !=
llvm::Triple::VendorType::Apple)
return ObjCRuntimeVersions::eObjC_VersionUnknown;
const ModuleList &target_modules = target.GetImages();
std::lock_guard<std::recursive_mutex> gaurd(target_modules.GetMutex());
size_t num_images = target_modules.GetSize();
for (size_t i = 0; i < num_images; i++) {
ModuleSP module_sp = target_modules.GetModuleAtIndexUnlocked(i);
// One tricky bit here is that we might get called as part of the initial
// module loading, but
// before all the pre-run libraries get winnowed from the module list. So
// there might actually
// be an old and incorrect ObjC library sitting around in the list, and we
// don't want to look at that.
// That's why we call IsLoadedInTarget.
if (AppleIsModuleObjCLibrary(module_sp) &&
module_sp->IsLoadedInTarget(&target)) {
objc_module_sp = module_sp;
ObjectFile *ofile = module_sp->GetObjectFile();
if (!ofile)
return ObjCRuntimeVersions::eObjC_VersionUnknown;
SectionList *sections = module_sp->GetSectionList();
if (!sections)
return ObjCRuntimeVersions::eObjC_VersionUnknown;
SectionSP v1_telltale_section_sp =
sections->FindSectionByName(ConstString("__OBJC"));
if (v1_telltale_section_sp) {
return ObjCRuntimeVersions::eAppleObjC_V1;
}
return ObjCRuntimeVersions::eAppleObjC_V2;
}
}
return ObjCRuntimeVersions::eObjC_VersionUnknown;
}
void AppleObjCRuntime::SetExceptionBreakpoints() {
const bool catch_bp = false;
const bool throw_bp = true;
const bool is_internal = true;
if (!m_objc_exception_bp_sp) {
m_objc_exception_bp_sp = LanguageRuntime::CreateExceptionBreakpoint(
m_process->GetTarget(), GetLanguageType(), catch_bp, throw_bp,
is_internal);
if (m_objc_exception_bp_sp)
m_objc_exception_bp_sp->SetBreakpointKind("ObjC exception");
} else
m_objc_exception_bp_sp->SetEnabled(true);
}
void AppleObjCRuntime::ClearExceptionBreakpoints() {
if (!m_process)
return;
if (m_objc_exception_bp_sp.get()) {
m_objc_exception_bp_sp->SetEnabled(false);
}
}
bool AppleObjCRuntime::ExceptionBreakpointsAreSet() {
return m_objc_exception_bp_sp && m_objc_exception_bp_sp->IsEnabled();
}
bool AppleObjCRuntime::ExceptionBreakpointsExplainStop(
lldb::StopInfoSP stop_reason) {
if (!m_process)
return false;
if (!stop_reason || stop_reason->GetStopReason() != eStopReasonBreakpoint)
return false;
uint64_t break_site_id = stop_reason->GetValue();
return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(
break_site_id, m_objc_exception_bp_sp->GetID());
}
bool AppleObjCRuntime::CalculateHasNewLiteralsAndIndexing() {
if (!m_process)
return false;
Target &target(m_process->GetTarget());
static ConstString s_method_signature(
"-[NSDictionary objectForKeyedSubscript:]");
static ConstString s_arclite_method_signature(
"__arclite_objectForKeyedSubscript");
SymbolContextList sc_list;
if (target.GetImages().FindSymbolsWithNameAndType(s_method_signature,
eSymbolTypeCode, sc_list) ||
target.GetImages().FindSymbolsWithNameAndType(s_arclite_method_signature,
eSymbolTypeCode, sc_list))
return true;
else
return false;
}
lldb::SearchFilterSP AppleObjCRuntime::CreateExceptionSearchFilter() {
Target &target = m_process->GetTarget();
if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple) {
FileSpecList filter_modules;
filter_modules.Append(FileSpec("libobjc.A.dylib", false));
return target.GetSearchFilterForModuleList(&filter_modules);
} else {
return LanguageRuntime::CreateExceptionSearchFilter();
}
}
void AppleObjCRuntime::ReadObjCLibraryIfNeeded(const ModuleList &module_list) {
if (!HasReadObjCLibrary()) {
std::lock_guard<std::recursive_mutex> guard(module_list.GetMutex());
size_t num_modules = module_list.GetSize();
for (size_t i = 0; i < num_modules; i++) {
auto mod = module_list.GetModuleAtIndex(i);
if (IsModuleObjCLibrary(mod)) {
ReadObjCLibrary(mod);
break;
}
}
}
}
void AppleObjCRuntime::ModulesDidLoad(const ModuleList &module_list) {
ReadObjCLibraryIfNeeded(module_list);
}

View File

@@ -0,0 +1,129 @@
//===-- AppleObjCRuntime.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_AppleObjCRuntime_h_
#define liblldb_AppleObjCRuntime_h_
// C Includes
// C++ Includes
// Other libraries and framework includes
#include "llvm/ADT/Optional.h"
// Project includes
#include "AppleObjCTrampolineHandler.h"
#include "AppleThreadPlanStepThroughObjCTrampoline.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class AppleObjCRuntime : public lldb_private::ObjCLanguageRuntime {
public:
~AppleObjCRuntime() override;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
// Note there is no CreateInstance, Initialize & Terminate functions here,
// because
// you can't make an instance of this generic runtime.
static bool classof(const ObjCLanguageRuntime *runtime) {
switch (runtime->GetRuntimeVersion()) {
case ObjCRuntimeVersions::eAppleObjC_V1:
case ObjCRuntimeVersions::eAppleObjC_V2:
return true;
default:
return false;
}
}
// These are generic runtime functions:
bool GetObjectDescription(Stream &str, Value &value,
ExecutionContextScope *exe_scope) override;
bool GetObjectDescription(Stream &str, ValueObject &object) override;
bool CouldHaveDynamicValue(ValueObject &in_value) override;
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
TypeAndOrName FixUpDynamicType(const TypeAndOrName &type_and_or_name,
ValueObject &static_value) override;
// These are the ObjC specific functions.
bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) override;
bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) override;
bool HasReadObjCLibrary() override { return m_read_objc_library; }
lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
bool stop_others) override;
// Get the "libobjc.A.dylib" module from the current target if we can find
// it, also cache it once it is found to ensure quick lookups.
lldb::ModuleSP GetObjCModule();
// Sync up with the target
void ModulesDidLoad(const ModuleList &module_list) override;
void SetExceptionBreakpoints() override;
void ClearExceptionBreakpoints() override;
bool ExceptionBreakpointsAreSet() override;
bool ExceptionBreakpointsExplainStop(lldb::StopInfoSP stop_reason) override;
lldb::SearchFilterSP CreateExceptionSearchFilter() override;
uint32_t GetFoundationVersion();
virtual void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
lldb::addr_t &cf_false);
virtual bool IsTaggedPointer (lldb::addr_t addr) { return false; }
protected:
// Call CreateInstance instead.
AppleObjCRuntime(Process *process);
bool CalculateHasNewLiteralsAndIndexing() override;
static bool AppleIsModuleObjCLibrary(const lldb::ModuleSP &module_sp);
static ObjCRuntimeVersions GetObjCVersion(Process *process,
lldb::ModuleSP &objc_module_sp);
void ReadObjCLibraryIfNeeded(const ModuleList &module_list);
Address *GetPrintForDebuggerAddr();
std::unique_ptr<Address> m_PrintForDebugger_addr;
bool m_read_objc_library;
std::unique_ptr<lldb_private::AppleObjCTrampolineHandler>
m_objc_trampoline_handler_ap;
lldb::BreakpointSP m_objc_exception_bp_sp;
lldb::ModuleWP m_objc_module_wp;
std::unique_ptr<FunctionCaller> m_print_object_caller_up;
llvm::Optional<uint32_t> m_Foundation_major;
};
} // namespace lldb_private
#endif // liblldb_AppleObjCRuntime_h_

View File

@@ -0,0 +1,441 @@
//===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++
//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "AppleObjCRuntimeV1.h"
#include "AppleObjCDeclVendor.h"
#include "AppleObjCTrampolineHandler.h"
#include "clang/AST/Type.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
#include "lldb/Expression/FunctionCaller.h"
#include "lldb/Expression/UtilityFunction.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
#include <vector>
using namespace lldb;
using namespace lldb_private;
AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)
: AppleObjCRuntime(process), m_hash_signature(),
m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {}
// for V1 runtime we just try to return a class name as that is the minimum
// level of support
// required for the data formatters to work
bool AppleObjCRuntimeV1::GetDynamicTypeAndAddress(
ValueObject &in_value, lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name, Address &address,
Value::ValueType &value_type) {
class_type_or_name.Clear();
value_type = Value::ValueType::eValueTypeScalar;
if (CouldHaveDynamicValue(in_value)) {
auto class_descriptor(GetClassDescriptor(in_value));
if (class_descriptor && class_descriptor->IsValid() &&
class_descriptor->GetClassName()) {
const addr_t object_ptr = in_value.GetPointerValue();
address.SetRawAddress(object_ptr);
class_type_or_name.SetName(class_descriptor->GetClassName());
}
}
return class_type_or_name.IsEmpty() == false;
}
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
lldb_private::LanguageRuntime *
AppleObjCRuntimeV1::CreateInstance(Process *process,
lldb::LanguageType language) {
// FIXME: This should be a MacOS or iOS process, and we need to look for the
// OBJC section to make
// sure we aren't using the V1 runtime.
if (language == eLanguageTypeObjC) {
ModuleSP objc_module_sp;
if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
ObjCRuntimeVersions::eAppleObjC_V1)
return new AppleObjCRuntimeV1(process);
else
return NULL;
} else
return NULL;
}
void AppleObjCRuntimeV1::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 1",
CreateInstance);
}
void AppleObjCRuntimeV1::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString AppleObjCRuntimeV1::GetPluginNameStatic() {
static ConstString g_name("apple-objc-v1");
return g_name;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString AppleObjCRuntimeV1::GetPluginName() {
return GetPluginNameStatic();
}
uint32_t AppleObjCRuntimeV1::GetPluginVersion() { return 1; }
BreakpointResolverSP
AppleObjCRuntimeV1::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp,
bool throw_bp) {
BreakpointResolverSP resolver_sp;
if (throw_bp)
resolver_sp.reset(new BreakpointResolverName(
bkpt, "objc_exception_throw", eFunctionNameTypeBase,
eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo));
// FIXME: don't do catch yet.
return resolver_sp;
}
struct BufStruct {
char contents[2048];
};
UtilityFunction *AppleObjCRuntimeV1::CreateObjectChecker(const char *name) {
std::unique_ptr<BufStruct> buf(new BufStruct);
int strformatsize = snprintf(&buf->contents[0], sizeof(buf->contents),
"struct __objc_class "
" \n"
"{ "
" \n"
" struct __objc_class *isa; "
" \n"
" struct __objc_class *super_class; "
" \n"
" const char *name; "
" \n"
" // rest of struct elided because unused "
" \n"
"}; "
" \n"
" "
" \n"
"struct __objc_object "
" \n"
"{ "
" \n"
" struct __objc_class *isa; "
" \n"
"}; "
" \n"
" "
" \n"
"extern \"C\" void "
" \n"
"%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) "
" \n"
"{ "
" \n"
" struct __objc_object *obj = (struct "
"__objc_object*)$__lldb_arg_obj; \n"
" if ($__lldb_arg_obj == (void *)0) "
" \n"
" return; // nil is ok "
" (int)strlen(obj->isa->name); "
" \n"
"} "
" \n",
name);
assert(strformatsize < (int)sizeof(buf->contents));
(void)strformatsize;
Status error;
return GetTargetRef().GetUtilityFunctionForLanguage(
buf->contents, eLanguageTypeObjC, name, error);
}
AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(
ValueObject &isa_pointer) {
Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP());
}
AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1(
ObjCISA isa, lldb::ProcessSP process_sp) {
Initialize(isa, process_sp);
}
void AppleObjCRuntimeV1::ClassDescriptorV1::Initialize(
ObjCISA isa, lldb::ProcessSP process_sp) {
if (!isa || !process_sp) {
m_valid = false;
return;
}
m_valid = true;
Status error;
m_isa = process_sp->ReadPointerFromMemory(isa, error);
if (error.Fail()) {
m_valid = false;
return;
}
uint32_t ptr_size = process_sp->GetAddressByteSize();
if (!IsPointerValid(m_isa, ptr_size)) {
m_valid = false;
return;
}
m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error);
if (error.Fail()) {
m_valid = false;
return;
}
if (!IsPointerValid(m_parent_isa, ptr_size, true)) {
m_valid = false;
return;
}
lldb::addr_t name_ptr =
process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error);
if (error.Fail()) {
m_valid = false;
return;
}
lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
size_t count = process_sp->ReadCStringFromMemory(
name_ptr, (char *)buffer_sp->GetBytes(), 1024, error);
if (error.Fail()) {
m_valid = false;
return;
}
if (count)
m_name = ConstString((char *)buffer_sp->GetBytes());
else
m_name = ConstString();
m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(
m_isa + 5 * ptr_size, ptr_size, 0, error);
if (error.Fail()) {
m_valid = false;
return;
}
m_process_wp = lldb::ProcessWP(process_sp);
}
AppleObjCRuntime::ClassDescriptorSP
AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass() {
if (!m_valid)
return AppleObjCRuntime::ClassDescriptorSP();
ProcessSP process_sp = m_process_wp.lock();
if (!process_sp)
return AppleObjCRuntime::ClassDescriptorSP();
return ObjCLanguageRuntime::ClassDescriptorSP(
new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp));
}
AppleObjCRuntime::ClassDescriptorSP
AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass() const {
return ClassDescriptorSP();
}
bool AppleObjCRuntimeV1::ClassDescriptorV1::Describe(
std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
std::function<bool(const char *, const char *)> const &instance_method_func,
std::function<bool(const char *, const char *)> const &class_method_func,
std::function<bool(const char *, const char *, lldb::addr_t,
uint64_t)> const &ivar_func) const {
return false;
}
lldb::addr_t AppleObjCRuntimeV1::GetISAHashTablePointer() {
if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
ModuleSP objc_module_sp(GetObjCModule());
if (!objc_module_sp)
return LLDB_INVALID_ADDRESS;
static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");
const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
g_objc_debug_class_hash, lldb::eSymbolTypeData);
if (symbol && symbol->ValueIsAddress()) {
Process *process = GetProcess();
if (process) {
lldb::addr_t objc_debug_class_hash_addr =
symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {
Status error;
lldb::addr_t objc_debug_class_hash_ptr =
process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
if (objc_debug_class_hash_ptr != 0 &&
objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) {
m_isa_hash_table_ptr = objc_debug_class_hash_ptr;
}
}
}
}
}
return m_isa_hash_table_ptr;
}
void AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() {
// TODO: implement HashTableSignature...
Process *process = GetProcess();
if (process) {
// Update the process stop ID that indicates the last time we updated the
// map, whether it was successful or not.
m_isa_to_descriptor_stop_id = process->GetStopID();
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
ProcessSP process_sp = process->shared_from_this();
ModuleSP objc_module_sp(GetObjCModule());
if (!objc_module_sp)
return;
uint32_t isa_count = 0;
lldb::addr_t hash_table_ptr = GetISAHashTablePointer();
if (hash_table_ptr != LLDB_INVALID_ADDRESS) {
// Read the NXHashTable struct:
//
// typedef struct {
// const NXHashTablePrototype *prototype;
// unsigned count;
// unsigned nbBuckets;
// void *buckets;
// const void *info;
// } NXHashTable;
Status error;
DataBufferHeap buffer(1024, 0);
if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==
20) {
const uint32_t addr_size = m_process->GetAddressByteSize();
const ByteOrder byte_order = m_process->GetByteOrder();
DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order,
addr_size);
lldb::offset_t offset = addr_size; // Skip prototype
const uint32_t count = data.GetU32(&offset);
const uint32_t num_buckets = data.GetU32(&offset);
const addr_t buckets_ptr = data.GetPointer(&offset);
if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) {
m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr);
const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);
buffer.SetByteSize(data_size);
if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size,
error) == data_size) {
data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);
offset = 0;
for (uint32_t bucket_idx = 0; bucket_idx < num_buckets;
++bucket_idx) {
const uint32_t bucket_isa_count = data.GetU32(&offset);
const lldb::addr_t bucket_data = data.GetU32(&offset);
if (bucket_isa_count == 0)
continue;
isa_count += bucket_isa_count;
ObjCISA isa;
if (bucket_isa_count == 1) {
// When we only have one entry in the bucket, the bucket data is
// the "isa"
isa = bucket_data;
if (isa) {
if (!ISAIsCached(isa)) {
ClassDescriptorSP descriptor_sp(
new ClassDescriptorV1(isa, process_sp));
if (log && log->GetVerbose())
log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
" from _objc_debug_class_hash to "
"isa->descriptor cache",
isa);
AddClass(isa, descriptor_sp);
}
}
} else {
// When we have more than one entry in the bucket, the bucket
// data is a pointer
// to an array of "isa" values
addr_t isa_addr = bucket_data;
for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count;
++isa_idx, isa_addr += addr_size) {
isa = m_process->ReadPointerFromMemory(isa_addr, error);
if (isa && isa != LLDB_INVALID_ADDRESS) {
if (!ISAIsCached(isa)) {
ClassDescriptorSP descriptor_sp(
new ClassDescriptorV1(isa, process_sp));
if (log && log->GetVerbose())
log->Printf(
"AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
" from _objc_debug_class_hash to isa->descriptor "
"cache",
isa);
AddClass(isa, descriptor_sp);
}
}
}
}
}
}
}
}
}
} else {
m_isa_to_descriptor_stop_id = UINT32_MAX;
}
}
DeclVendor *AppleObjCRuntimeV1::GetDeclVendor() {
return nullptr;
}

View File

@@ -0,0 +1,161 @@
//===-- AppleObjCRuntimeV1.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_AppleObjCRuntimeV1_h_
#define liblldb_AppleObjCRuntimeV1_h_
// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "AppleObjCRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class AppleObjCRuntimeV1 : public AppleObjCRuntime {
public:
~AppleObjCRuntimeV1() override = default;
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
static void Initialize();
static void Terminate();
static lldb_private::LanguageRuntime *
CreateInstance(Process *process, lldb::LanguageType language);
static lldb_private::ConstString GetPluginNameStatic();
static bool classof(const ObjCLanguageRuntime *runtime) {
switch (runtime->GetRuntimeVersion()) {
case ObjCRuntimeVersions::eAppleObjC_V1:
return true;
default:
return false;
}
}
class ClassDescriptorV1 : public ObjCLanguageRuntime::ClassDescriptor {
public:
ClassDescriptorV1(ValueObject &isa_pointer);
ClassDescriptorV1(ObjCISA isa, lldb::ProcessSP process_sp);
~ClassDescriptorV1() override = default;
ConstString GetClassName() override { return m_name; }
ClassDescriptorSP GetSuperclass() override;
ClassDescriptorSP GetMetaclass() const override;
bool IsValid() override { return m_valid; }
// v1 does not support tagged pointers
bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
uint64_t *value_bits = nullptr,
uint64_t *payload = nullptr) override {
return false;
}
uint64_t GetInstanceSize() override { return m_instance_size; }
ObjCISA GetISA() override { return m_isa; }
bool
Describe(std::function<void(ObjCLanguageRuntime::ObjCISA)> const
&superclass_func,
std::function<bool(const char *, const char *)> const
&instance_method_func,
std::function<bool(const char *, const char *)> const
&class_method_func,
std::function<bool(const char *, const char *, lldb::addr_t,
uint64_t)> const &ivar_func) const override;
protected:
void Initialize(ObjCISA isa, lldb::ProcessSP process_sp);
private:
ConstString m_name;
ObjCISA m_isa;
ObjCISA m_parent_isa;
bool m_valid;
lldb::ProcessWP m_process_wp;
uint64_t m_instance_size;
};
// These are generic runtime functions:
bool GetDynamicTypeAndAddress(ValueObject &in_value,
lldb::DynamicValueType use_dynamic,
TypeAndOrName &class_type_or_name,
Address &address,
Value::ValueType &value_type) override;
UtilityFunction *CreateObjectChecker(const char *) override;
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
ConstString GetPluginName() override;
uint32_t GetPluginVersion() override;
ObjCRuntimeVersions GetRuntimeVersion() const override {
return ObjCRuntimeVersions::eAppleObjC_V1;
}
void UpdateISAToDescriptorMapIfNeeded() override;
DeclVendor *GetDeclVendor() override;
protected:
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
bool catch_bp,
bool throw_bp) override;
class HashTableSignature {
public:
HashTableSignature()
: m_count(0), m_num_buckets(0), m_buckets_ptr(LLDB_INVALID_ADDRESS) {}
bool NeedsUpdate(uint32_t count, uint32_t num_buckets,
lldb::addr_t buckets_ptr) {
return m_count != count || m_num_buckets != num_buckets ||
m_buckets_ptr != buckets_ptr;
}
void UpdateSignature(uint32_t count, uint32_t num_buckets,
lldb::addr_t buckets_ptr) {
m_count = count;
m_num_buckets = num_buckets;
m_buckets_ptr = buckets_ptr;
}
protected:
uint32_t m_count;
uint32_t m_num_buckets;
lldb::addr_t m_buckets_ptr;
};
lldb::addr_t GetISAHashTablePointer();
HashTableSignature m_hash_signature;
lldb::addr_t m_isa_hash_table_ptr;
std::unique_ptr<DeclVendor> m_decl_vendor_ap;
private:
AppleObjCRuntimeV1(Process *process);
};
} // namespace lldb_private
#endif // liblldb_AppleObjCRuntimeV1_h_

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