forked from OSchip/llvm-project
parent
eb3f1007d8
commit
b636be79c0
|
@ -199,7 +199,8 @@ public:
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
||||||
uint64_t* value_bits = NULL) = 0;
|
uint64_t* value_bits = NULL,
|
||||||
|
uint64_t* payload = NULL) = 0;
|
||||||
|
|
||||||
virtual uint64_t
|
virtual uint64_t
|
||||||
GetInstanceSize () = 0;
|
GetInstanceSize () = 0;
|
||||||
|
|
|
@ -330,17 +330,20 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream&
|
||||||
case 0:
|
case 0:
|
||||||
stream.Printf("(char)%hhd",(char)value);
|
stream.Printf("(char)%hhd",(char)value);
|
||||||
break;
|
break;
|
||||||
|
case 1:
|
||||||
case 4:
|
case 4:
|
||||||
stream.Printf("(short)%hd",(short)value);
|
stream.Printf("(short)%hd",(short)value);
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
case 8:
|
case 8:
|
||||||
stream.Printf("(int)%d",(int)value);
|
stream.Printf("(int)%d",(int)value);
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
case 12:
|
case 12:
|
||||||
stream.Printf("(long)%" PRId64,value);
|
stream.Printf("(long)%" PRId64,value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64 ")",i_bits,value);
|
stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -49,7 +49,8 @@ public:
|
||||||
// v1 does not support tagged pointers
|
// v1 does not support tagged pointers
|
||||||
virtual bool
|
virtual bool
|
||||||
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
||||||
uint64_t* value_bits = NULL)
|
uint64_t* value_bits = NULL,
|
||||||
|
uint64_t* payload = NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,14 @@
|
||||||
#include "lldb/Core/Section.h"
|
#include "lldb/Core/Section.h"
|
||||||
#include "lldb/Core/StreamString.h"
|
#include "lldb/Core/StreamString.h"
|
||||||
#include "lldb/Core/Timer.h"
|
#include "lldb/Core/Timer.h"
|
||||||
|
#include "lldb/Core/ValueObjectVariable.h"
|
||||||
#include "lldb/Expression/ClangFunction.h"
|
#include "lldb/Expression/ClangFunction.h"
|
||||||
#include "lldb/Expression/ClangUtilityFunction.h"
|
#include "lldb/Expression/ClangUtilityFunction.h"
|
||||||
#include "lldb/Symbol/ClangASTContext.h"
|
#include "lldb/Symbol/ClangASTContext.h"
|
||||||
#include "lldb/Symbol/ObjectFile.h"
|
#include "lldb/Symbol/ObjectFile.h"
|
||||||
#include "lldb/Symbol/Symbol.h"
|
#include "lldb/Symbol/Symbol.h"
|
||||||
#include "lldb/Symbol/TypeList.h"
|
#include "lldb/Symbol/TypeList.h"
|
||||||
|
#include "lldb/Symbol/VariableList.h"
|
||||||
#include "lldb/Target/ExecutionContext.h"
|
#include "lldb/Target/ExecutionContext.h"
|
||||||
#include "lldb/Target/Process.h"
|
#include "lldb/Target/Process.h"
|
||||||
#include "lldb/Target/RegisterContext.h"
|
#include "lldb/Target/RegisterContext.h"
|
||||||
|
@ -286,6 +288,52 @@ __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
|
||||||
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
static uint64_t
|
||||||
|
ExtractRuntimeGlobalSymbol (Process* process,
|
||||||
|
ConstString name,
|
||||||
|
const ModuleSP &module_sp,
|
||||||
|
Error& error,
|
||||||
|
bool read_value = true,
|
||||||
|
uint8_t byte_size = 0,
|
||||||
|
uint64_t default_value = LLDB_INVALID_ADDRESS,
|
||||||
|
SymbolType sym_type = lldb::eSymbolTypeData)
|
||||||
|
{
|
||||||
|
if (!process)
|
||||||
|
{
|
||||||
|
error.SetErrorString("no process");
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
if (!module_sp)
|
||||||
|
{
|
||||||
|
error.SetErrorString("no module");
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
if (!byte_size)
|
||||||
|
byte_size = process->GetAddressByteSize();
|
||||||
|
const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
|
||||||
|
if (symbol)
|
||||||
|
{
|
||||||
|
lldb::addr_t symbol_load_addr = symbol->GetAddress().GetLoadAddress(&process->GetTarget());
|
||||||
|
if (symbol_load_addr != LLDB_INVALID_ADDRESS)
|
||||||
|
{
|
||||||
|
if (read_value)
|
||||||
|
return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, default_value, error);
|
||||||
|
else
|
||||||
|
return symbol_load_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error.SetErrorString("symbol address invalid");
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error.SetErrorString("no symbol");
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process,
|
AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process,
|
||||||
const ModuleSP &objc_module_sp) :
|
const ModuleSP &objc_module_sp) :
|
||||||
|
@ -302,7 +350,9 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process,
|
||||||
m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS),
|
m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS),
|
||||||
m_hash_signature (),
|
m_hash_signature (),
|
||||||
m_has_object_getClass (false),
|
m_has_object_getClass (false),
|
||||||
m_loaded_objc_opt (false)
|
m_loaded_objc_opt (false),
|
||||||
|
m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this,objc_module_sp)),
|
||||||
|
m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp))
|
||||||
{
|
{
|
||||||
static const ConstString g_gdb_object_getClass("gdb_object_getClass");
|
static const ConstString g_gdb_object_getClass("gdb_object_getClass");
|
||||||
m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
|
m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
|
||||||
|
@ -313,7 +363,7 @@ AppleObjCRuntimeV2::~AppleObjCRuntimeV2()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
|
AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
|
||||||
DynamicValueType use_dynamic,
|
DynamicValueType use_dynamic,
|
||||||
TypeAndOrName &class_type_or_name,
|
TypeAndOrName &class_type_or_name,
|
||||||
Address &address)
|
Address &address)
|
||||||
|
@ -522,15 +572,16 @@ AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const c
|
||||||
return ivar_offset;
|
return ivar_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tagged pointers are marked by having their least-significant bit
|
|
||||||
// set. this makes them "invalid" as pointers because they violate
|
// tagged pointers are special not-a-real-pointer values that contain both type and value information
|
||||||
// the alignment requirements. of course, this detection algorithm
|
// this routine attempts to check with as little computational effort as possible whether something
|
||||||
// is not accurate (it might become better by incorporating further
|
// could possibly be a tagged pointer - false positives are possible but false negatives shouldn't
|
||||||
// knowledge about the internals of tagged pointers)
|
|
||||||
bool
|
bool
|
||||||
AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr)
|
AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr)
|
||||||
{
|
{
|
||||||
return (ptr & 1);
|
if (!m_tagged_pointer_vendor_ap)
|
||||||
|
return false;
|
||||||
|
return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
class RemoteNXMapTable
|
class RemoteNXMapTable
|
||||||
|
@ -860,7 +911,8 @@ public:
|
||||||
// a custom descriptor is used for tagged pointers
|
// a custom descriptor is used for tagged pointers
|
||||||
virtual bool
|
virtual bool
|
||||||
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
||||||
uint64_t* value_bits = NULL)
|
uint64_t* value_bits = NULL,
|
||||||
|
uint64_t* payload = NULL)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1414,88 +1466,43 @@ private:
|
||||||
ConstString m_name; // May be NULL
|
ConstString m_name; // May be NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// tagged pointer descriptor
|
||||||
class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor
|
class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClassDescriptorV2Tagged (ValueObject &isa_pointer)
|
ClassDescriptorV2Tagged (ConstString class_name,
|
||||||
|
uint64_t payload)
|
||||||
{
|
{
|
||||||
m_valid = false;
|
m_name = class_name;
|
||||||
uint64_t value = isa_pointer.GetValueAsUnsigned(0);
|
if (!m_name)
|
||||||
ProcessSP process_sp = isa_pointer.GetProcessSP();
|
|
||||||
if (process_sp)
|
|
||||||
m_pointer_size = process_sp->GetAddressByteSize();
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
m_name = ConstString("");
|
m_valid = false;
|
||||||
m_pointer_size = 0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_valid = true;
|
m_valid = true;
|
||||||
m_class_bits = (value & 0xE) >> 1;
|
m_payload = payload;
|
||||||
lldb::TargetSP target_sp = isa_pointer.GetTargetSP();
|
m_info_bits = (m_payload & 0xF0ULL) >> 4;
|
||||||
|
m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
|
||||||
uint32_t foundation_version = GetFoundationVersion(target_sp);
|
}
|
||||||
|
|
||||||
// TODO: check for OSX version - for now assume Mtn Lion
|
ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
|
||||||
if (foundation_version == UINT32_MAX)
|
uint64_t payload)
|
||||||
|
{
|
||||||
|
if (!actual_class_sp)
|
||||||
{
|
{
|
||||||
// if we can't determine the matching table (e.g. we have no Foundation),
|
|
||||||
// assume this is not a valid tagged pointer
|
|
||||||
m_valid = false;
|
m_valid = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else if (foundation_version >= 900)
|
m_name = actual_class_sp->GetClassName();
|
||||||
|
if (!m_name)
|
||||||
{
|
{
|
||||||
switch (m_class_bits)
|
m_valid = false;
|
||||||
{
|
return;
|
||||||
case 0:
|
|
||||||
m_name = ConstString("NSAtom");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
m_name = ConstString("NSNumber");
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
m_name = ConstString("NSDateTS");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
m_name = ConstString("NSManagedObject");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
m_name = ConstString("NSDate");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
m_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (m_class_bits)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
m_name = ConstString("NSNumber");
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
m_name = ConstString("NSManagedObject");
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
m_name = ConstString("NSDate");
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
m_name = ConstString("NSDateTS");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
m_valid = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!m_valid)
|
|
||||||
m_name = ConstString("");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_info_bits = (value & 0xF0ULL) >> 4;
|
|
||||||
m_value_bits = (value & ~0x0000000000000000FFULL) >> 8;
|
|
||||||
}
|
}
|
||||||
|
m_valid = true;
|
||||||
|
m_payload = payload;
|
||||||
|
m_info_bits = (m_payload & 0x0FULL);
|
||||||
|
m_value_bits = (m_payload & ~0x0FULL) >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ConstString
|
virtual ConstString
|
||||||
|
@ -1533,12 +1540,15 @@ public:
|
||||||
|
|
||||||
virtual bool
|
virtual bool
|
||||||
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
GetTaggedPointerInfo (uint64_t* info_bits = NULL,
|
||||||
uint64_t* value_bits = NULL)
|
uint64_t* value_bits = NULL,
|
||||||
|
uint64_t* payload = NULL)
|
||||||
{
|
{
|
||||||
if (info_bits)
|
if (info_bits)
|
||||||
*info_bits = GetInfoBits();
|
*info_bits = GetInfoBits();
|
||||||
if (value_bits)
|
if (value_bits)
|
||||||
*value_bits = GetValueBits();
|
*value_bits = GetValueBits();
|
||||||
|
if (payload)
|
||||||
|
*payload = GetPayload();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1554,12 +1564,6 @@ public:
|
||||||
return 0; // tagged pointers have no ISA
|
return 0; // tagged pointers have no ISA
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual uint64_t
|
|
||||||
GetClassBits ()
|
|
||||||
{
|
|
||||||
return (IsValid() ? m_class_bits : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// these calls are not part of any formal tagged pointers specification
|
// these calls are not part of any formal tagged pointers specification
|
||||||
virtual uint64_t
|
virtual uint64_t
|
||||||
GetValueBits ()
|
GetValueBits ()
|
||||||
|
@ -1573,42 +1577,37 @@ public:
|
||||||
return (IsValid() ? m_info_bits : 0);
|
return (IsValid() ? m_info_bits : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual uint64_t
|
||||||
|
GetPayload ()
|
||||||
|
{
|
||||||
|
return (IsValid() ? m_payload : 0);
|
||||||
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
~ClassDescriptorV2Tagged ()
|
~ClassDescriptorV2Tagged ()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
protected:
|
|
||||||
// we use the version of Foundation to make assumptions about the ObjC runtime on a target
|
|
||||||
uint32_t
|
|
||||||
GetFoundationVersion (lldb::TargetSP &target_sp)
|
|
||||||
{
|
|
||||||
if (!target_sp)
|
|
||||||
return eLazyBoolCalculate;
|
|
||||||
const ModuleList& modules = target_sp->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);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return major;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConstString m_name;
|
ConstString m_name;
|
||||||
uint8_t m_pointer_size;
|
uint8_t m_pointer_size;
|
||||||
bool m_valid;
|
bool m_valid;
|
||||||
uint64_t m_class_bits;
|
|
||||||
uint64_t m_info_bits;
|
uint64_t m_info_bits;
|
||||||
uint64_t m_value_bits;
|
uint64_t m_value_bits;
|
||||||
|
uint64_t m_payload;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
AppleObjCRuntimeV2::GetClassDescriptor (ObjCISA isa)
|
||||||
|
{
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
|
||||||
|
if (m_non_pointer_isa_cache_ap.get())
|
||||||
|
class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa);
|
||||||
|
if (!class_descriptor_sp)
|
||||||
|
class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
|
||||||
|
return class_descriptor_sp;
|
||||||
|
}
|
||||||
|
|
||||||
ObjCLanguageRuntime::ClassDescriptorSP
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj)
|
AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj)
|
||||||
{
|
{
|
||||||
|
@ -1623,13 +1622,7 @@ AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj)
|
||||||
// tagged pointer
|
// tagged pointer
|
||||||
if (IsTaggedPointer(isa_pointer))
|
if (IsTaggedPointer(isa_pointer))
|
||||||
{
|
{
|
||||||
objc_class_sp.reset (new ClassDescriptorV2Tagged(valobj));
|
return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer);
|
||||||
|
|
||||||
// probably an invalid tagged pointer - say it's wrong
|
|
||||||
if (objc_class_sp->IsValid())
|
|
||||||
return objc_class_sp;
|
|
||||||
else
|
|
||||||
objc_class_sp.reset();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2353,3 +2346,299 @@ AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name)
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppleObjCRuntimeV2::NonPointerISACache*
|
||||||
|
AppleObjCRuntimeV2::NonPointerISACache::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
|
||||||
|
{
|
||||||
|
Process* process(runtime.GetProcess());
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_isa_magic_mask"),
|
||||||
|
objc_module_sp,
|
||||||
|
error);
|
||||||
|
if (error.Fail())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_isa_magic_value"),
|
||||||
|
objc_module_sp,
|
||||||
|
error);
|
||||||
|
if (error.Fail())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_isa_class_mask"),
|
||||||
|
objc_module_sp,
|
||||||
|
error);
|
||||||
|
if (error.Fail())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// we might want to have some rules to outlaw these other values (e.g if the mask is zero but the value is non-zero, ...)
|
||||||
|
|
||||||
|
return new NonPointerISACache(runtime,
|
||||||
|
objc_debug_isa_class_mask,
|
||||||
|
objc_debug_isa_magic_mask,
|
||||||
|
objc_debug_isa_magic_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendor*
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendor::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
|
||||||
|
{
|
||||||
|
Process* process(runtime.GetProcess());
|
||||||
|
|
||||||
|
Error error;
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_mask"),
|
||||||
|
objc_module_sp,
|
||||||
|
error);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_slot_shift"),
|
||||||
|
objc_module_sp,
|
||||||
|
error,
|
||||||
|
true,
|
||||||
|
4);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_slot_mask"),
|
||||||
|
objc_module_sp,
|
||||||
|
error,
|
||||||
|
true,
|
||||||
|
4);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_payload_lshift"),
|
||||||
|
objc_module_sp,
|
||||||
|
error,
|
||||||
|
true,
|
||||||
|
4);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_payload_rshift"),
|
||||||
|
objc_module_sp,
|
||||||
|
error,
|
||||||
|
true,
|
||||||
|
4);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(process,
|
||||||
|
ConstString("objc_debug_taggedpointer_classes"),
|
||||||
|
objc_module_sp,
|
||||||
|
error,
|
||||||
|
false);
|
||||||
|
if (error.Fail())
|
||||||
|
return new TaggedPointerVendorLegacy(runtime);
|
||||||
|
|
||||||
|
|
||||||
|
// we might want to have some rules to outlaw these values (e.g if the table's address is zero)
|
||||||
|
|
||||||
|
return new TaggedPointerVendorRuntimeAssisted(runtime,
|
||||||
|
objc_debug_taggedpointer_mask,
|
||||||
|
objc_debug_taggedpointer_slot_shift,
|
||||||
|
objc_debug_taggedpointer_slot_mask,
|
||||||
|
objc_debug_taggedpointer_payload_lshift,
|
||||||
|
objc_debug_taggedpointer_payload_rshift,
|
||||||
|
objc_debug_taggedpointer_classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer (lldb::addr_t ptr)
|
||||||
|
{
|
||||||
|
return (ptr & 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we use the version of Foundation to make assumptions about the ObjC runtime on a target
|
||||||
|
uint32_t
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetFoundationVersion (Target &target)
|
||||||
|
{
|
||||||
|
const ModuleList& modules = target.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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor (lldb::addr_t ptr)
|
||||||
|
{
|
||||||
|
if (!IsPossibleTaggedPointer(ptr))
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
|
||||||
|
Process* process(m_runtime.GetProcess());
|
||||||
|
|
||||||
|
if (m_Foundation_version == 0)
|
||||||
|
m_Foundation_version = GetFoundationVersion(process->GetTarget());
|
||||||
|
|
||||||
|
if (m_Foundation_version == UINT32_MAX)
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
|
||||||
|
uint64_t class_bits = (ptr & 0xE) >> 1;
|
||||||
|
ConstString name;
|
||||||
|
|
||||||
|
// TODO: make a table
|
||||||
|
if (m_Foundation_version >= 900)
|
||||||
|
{
|
||||||
|
switch (class_bits)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
name = ConstString("NSAtom");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
name = ConstString("NSNumber");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
name = ConstString("NSDateTS");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
name = ConstString("NSManagedObject");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
name = ConstString("NSDate");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (class_bits)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
name = ConstString("NSNumber");
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
name = ConstString("NSManagedObject");
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
name = ConstString("NSDate");
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
name = ConstString("NSDateTS");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ClassDescriptorSP(new ClassDescriptorV2Tagged(name,ptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime,
|
||||||
|
uint64_t objc_debug_taggedpointer_mask,
|
||||||
|
uint32_t objc_debug_taggedpointer_slot_shift,
|
||||||
|
uint32_t objc_debug_taggedpointer_slot_mask,
|
||||||
|
uint32_t objc_debug_taggedpointer_payload_lshift,
|
||||||
|
uint32_t objc_debug_taggedpointer_payload_rshift,
|
||||||
|
lldb::addr_t objc_debug_taggedpointer_classes) :
|
||||||
|
TaggedPointerVendor(runtime),
|
||||||
|
m_cache(),
|
||||||
|
m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
|
||||||
|
m_objc_debug_taggedpointer_slot_shift(objc_debug_taggedpointer_slot_shift),
|
||||||
|
m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
|
||||||
|
m_objc_debug_taggedpointer_payload_lshift(objc_debug_taggedpointer_payload_lshift),
|
||||||
|
m_objc_debug_taggedpointer_payload_rshift(objc_debug_taggedpointer_payload_rshift),
|
||||||
|
m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::IsPossibleTaggedPointer (lldb::addr_t ptr)
|
||||||
|
{
|
||||||
|
return (ptr & m_objc_debug_taggedpointer_mask) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor (lldb::addr_t ptr)
|
||||||
|
{
|
||||||
|
ClassDescriptorSP actual_class_descriptor_sp;
|
||||||
|
uint64_t data_payload;
|
||||||
|
|
||||||
|
if (!IsPossibleTaggedPointer(ptr))
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
|
||||||
|
uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & m_objc_debug_taggedpointer_slot_mask;
|
||||||
|
|
||||||
|
CacheIterator iterator = m_cache.find(slot),
|
||||||
|
end = m_cache.end();
|
||||||
|
if (iterator != end)
|
||||||
|
{
|
||||||
|
actual_class_descriptor_sp = iterator->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Process* process(m_runtime.GetProcess());
|
||||||
|
uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_classes;
|
||||||
|
Error error;
|
||||||
|
uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
|
||||||
|
if (error.Fail() || slot_data == 0 || slot_data == LLDB_INVALID_ADDRESS)
|
||||||
|
return false;
|
||||||
|
actual_class_descriptor_sp = m_runtime.GetClassDescriptor(slot_data);
|
||||||
|
if (!actual_class_descriptor_sp)
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
m_cache[slot] = actual_class_descriptor_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift);
|
||||||
|
|
||||||
|
return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache (AppleObjCRuntimeV2& runtime,
|
||||||
|
uint64_t objc_debug_isa_class_mask,
|
||||||
|
uint64_t objc_debug_isa_magic_mask,
|
||||||
|
uint64_t objc_debug_isa_magic_value) :
|
||||||
|
m_runtime(runtime),
|
||||||
|
m_cache(),
|
||||||
|
m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
|
||||||
|
m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
|
||||||
|
m_objc_debug_isa_magic_value(objc_debug_isa_magic_value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor (ObjCISA isa)
|
||||||
|
{
|
||||||
|
ObjCISA real_isa = 0;
|
||||||
|
if (EvaluateNonPointerISA(isa, real_isa) == false)
|
||||||
|
return ObjCLanguageRuntime::ClassDescriptorSP();
|
||||||
|
auto cache_iter = m_cache.find(real_isa);
|
||||||
|
if (cache_iter != m_cache.end())
|
||||||
|
return cache_iter->second;
|
||||||
|
auto descriptor_sp = m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
|
||||||
|
if (descriptor_sp) // cache only positive matches since the table might grow
|
||||||
|
m_cache[real_isa] = descriptor_sp;
|
||||||
|
return descriptor_sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa)
|
||||||
|
{
|
||||||
|
if ( (isa & ~m_objc_debug_isa_class_mask) == 0)
|
||||||
|
return false;
|
||||||
|
if ( (isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value)
|
||||||
|
{
|
||||||
|
ret_isa = isa & m_objc_debug_isa_class_mask;
|
||||||
|
return (ret_isa != 0); // this is a pointer so 0 is not a valid value
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
// C++ Includes
|
// C++ Includes
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
// Other libraries and framework includes
|
// Other libraries and framework includes
|
||||||
// Project includes
|
// Project includes
|
||||||
|
@ -95,6 +96,9 @@ public:
|
||||||
virtual ClassDescriptorSP
|
virtual ClassDescriptorSP
|
||||||
GetClassDescriptor (ValueObject& in_value);
|
GetClassDescriptor (ValueObject& in_value);
|
||||||
|
|
||||||
|
virtual ClassDescriptorSP
|
||||||
|
GetClassDescriptor (ObjCISA isa);
|
||||||
|
|
||||||
virtual TypeVendor *
|
virtual TypeVendor *
|
||||||
GetTypeVendor();
|
GetTypeVendor();
|
||||||
|
|
||||||
|
@ -125,6 +129,118 @@ private:
|
||||||
lldb::addr_t m_buckets_ptr;
|
lldb::addr_t m_buckets_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NonPointerISACache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static NonPointerISACache*
|
||||||
|
CreateInstance (AppleObjCRuntimeV2& runtime,
|
||||||
|
const lldb::ModuleSP& objc_module_sp);
|
||||||
|
|
||||||
|
|
||||||
|
ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
GetClassDescriptor (ObjCISA isa);
|
||||||
|
private:
|
||||||
|
NonPointerISACache (AppleObjCRuntimeV2& runtime,
|
||||||
|
uint64_t objc_debug_isa_class_mask,
|
||||||
|
uint64_t objc_debug_isa_magic_mask,
|
||||||
|
uint64_t objc_debug_isa_magic_value);
|
||||||
|
|
||||||
|
bool
|
||||||
|
EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa);
|
||||||
|
|
||||||
|
AppleObjCRuntimeV2& m_runtime;
|
||||||
|
std::map<ObjCISA,ObjCLanguageRuntime::ClassDescriptorSP> m_cache;
|
||||||
|
uint64_t m_objc_debug_isa_class_mask;
|
||||||
|
uint64_t m_objc_debug_isa_magic_mask;
|
||||||
|
uint64_t m_objc_debug_isa_magic_value;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(NonPointerISACache);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TaggedPointerVendor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static TaggedPointerVendor*
|
||||||
|
CreateInstance (AppleObjCRuntimeV2& runtime,
|
||||||
|
const lldb::ModuleSP& objc_module_sp);
|
||||||
|
|
||||||
|
virtual bool
|
||||||
|
IsPossibleTaggedPointer (lldb::addr_t ptr) = 0;
|
||||||
|
|
||||||
|
virtual ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
GetClassDescriptor (lldb::addr_t ptr) = 0;
|
||||||
|
|
||||||
|
virtual
|
||||||
|
~TaggedPointerVendor () { }
|
||||||
|
protected:
|
||||||
|
AppleObjCRuntimeV2& m_runtime;
|
||||||
|
|
||||||
|
TaggedPointerVendor (AppleObjCRuntimeV2& runtime) :
|
||||||
|
m_runtime(runtime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool
|
||||||
|
IsPossibleTaggedPointer (lldb::addr_t ptr);
|
||||||
|
|
||||||
|
virtual ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
GetClassDescriptor (lldb::addr_t ptr);
|
||||||
|
protected:
|
||||||
|
TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime,
|
||||||
|
uint64_t objc_debug_taggedpointer_mask,
|
||||||
|
uint32_t objc_debug_taggedpointer_slot_shift,
|
||||||
|
uint32_t objc_debug_taggedpointer_slot_mask,
|
||||||
|
uint32_t objc_debug_taggedpointer_payload_lshift,
|
||||||
|
uint32_t objc_debug_taggedpointer_payload_rshift,
|
||||||
|
lldb::addr_t objc_debug_taggedpointer_classes);
|
||||||
|
|
||||||
|
typedef std::map<uint8_t,ObjCLanguageRuntime::ClassDescriptorSP> Cache;
|
||||||
|
typedef Cache::iterator CacheIterator;
|
||||||
|
Cache m_cache;
|
||||||
|
uint64_t m_objc_debug_taggedpointer_mask;
|
||||||
|
uint32_t m_objc_debug_taggedpointer_slot_shift;
|
||||||
|
uint32_t m_objc_debug_taggedpointer_slot_mask;
|
||||||
|
uint32_t m_objc_debug_taggedpointer_payload_lshift;
|
||||||
|
uint32_t m_objc_debug_taggedpointer_payload_rshift;
|
||||||
|
lldb::addr_t m_objc_debug_taggedpointer_classes;
|
||||||
|
|
||||||
|
friend class AppleObjCRuntimeV2::TaggedPointerVendor;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TaggedPointerVendorLegacy : public TaggedPointerVendor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool
|
||||||
|
IsPossibleTaggedPointer (lldb::addr_t ptr);
|
||||||
|
|
||||||
|
virtual ObjCLanguageRuntime::ClassDescriptorSP
|
||||||
|
GetClassDescriptor (lldb::addr_t ptr);
|
||||||
|
protected:
|
||||||
|
TaggedPointerVendorLegacy (AppleObjCRuntimeV2& runtime) :
|
||||||
|
TaggedPointerVendor (runtime),
|
||||||
|
m_Foundation_version(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
GetFoundationVersion (Target& target);
|
||||||
|
|
||||||
|
uint32_t m_Foundation_version;
|
||||||
|
|
||||||
|
friend class AppleObjCRuntimeV2::TaggedPointerVendor;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy);
|
||||||
|
};
|
||||||
|
|
||||||
AppleObjCRuntimeV2 (Process *process,
|
AppleObjCRuntimeV2 (Process *process,
|
||||||
const lldb::ModuleSP &objc_module_sp);
|
const lldb::ModuleSP &objc_module_sp);
|
||||||
|
|
||||||
|
@ -150,22 +266,23 @@ private:
|
||||||
lldb::addr_t
|
lldb::addr_t
|
||||||
GetSharedCacheReadOnlyAddress();
|
GetSharedCacheReadOnlyAddress();
|
||||||
|
|
||||||
std::unique_ptr<ClangFunction> m_get_class_info_function;
|
std::unique_ptr<ClangFunction> m_get_class_info_function;
|
||||||
std::unique_ptr<ClangUtilityFunction> m_get_class_info_code;
|
std::unique_ptr<ClangUtilityFunction> m_get_class_info_code;
|
||||||
lldb::addr_t m_get_class_info_args;
|
lldb::addr_t m_get_class_info_args;
|
||||||
Mutex m_get_class_info_args_mutex;
|
Mutex m_get_class_info_args_mutex;
|
||||||
|
|
||||||
std::unique_ptr<ClangFunction> m_get_shared_cache_class_info_function;
|
std::unique_ptr<ClangFunction> m_get_shared_cache_class_info_function;
|
||||||
std::unique_ptr<ClangUtilityFunction> m_get_shared_cache_class_info_code;
|
std::unique_ptr<ClangUtilityFunction> m_get_shared_cache_class_info_code;
|
||||||
lldb::addr_t m_get_shared_cache_class_info_args;
|
lldb::addr_t m_get_shared_cache_class_info_args;
|
||||||
Mutex m_get_shared_cache_class_info_args_mutex;
|
Mutex m_get_shared_cache_class_info_args_mutex;
|
||||||
|
|
||||||
std::unique_ptr<TypeVendor> m_type_vendor_ap;
|
std::unique_ptr<TypeVendor> m_type_vendor_ap;
|
||||||
lldb::addr_t m_isa_hash_table_ptr;
|
lldb::addr_t m_isa_hash_table_ptr;
|
||||||
HashTableSignature m_hash_signature;
|
HashTableSignature m_hash_signature;
|
||||||
bool m_has_object_getClass;
|
bool m_has_object_getClass;
|
||||||
bool m_loaded_objc_opt;
|
bool m_loaded_objc_opt;
|
||||||
|
std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_ap;
|
||||||
|
std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_ap;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lldb_private
|
} // namespace lldb_private
|
||||||
|
|
Loading…
Reference in New Issue