More work for reading the Objective-C runtime.

We can now read the relevant data structures for
the method list, and use a callback mechanism to
report their details to the AppleObjCTypeVendor,
which constructs appropriate Clang types.

llvm-svn: 164310
This commit is contained in:
Sean Callanan 2012-09-20 17:01:52 +00:00
parent c727bacb38
commit d0dcae08e5
4 changed files with 347 additions and 68 deletions

View File

@ -12,6 +12,7 @@
// C Includes
// C++ Includes
#include <functional>
#include <map>
// Other libraries and framework includes
@ -115,7 +116,8 @@ public:
// This should return true iff the interface could be completed
virtual bool
CompleteInterface (clang::ObjCInterfaceDecl *interface_decl)
Describe (std::function <void (ObjCISA)> const &superclass_func,
std::function <void (const char*, const char*)> const &method_func)
{
return false;
}

View File

@ -1039,12 +1039,56 @@ public:
}
virtual bool
CompleteInterface (clang::ObjCInterfaceDecl *interface_decl)
Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
std::function <void (const char *, const char *)> const &method_func)
{
if (!m_valid)
return false;
return false;
std::auto_ptr <class_ro_t> ro;
std::auto_ptr <class_rw_t> rw;
ProcessSP process_sp = m_process_wp.lock();
if (!process_sp)
return false;
if (IsRealized())
{
rw.reset(new class_rw_t);
if (!rw->Read(process_sp, m_objc_class.m_data_la))
return false;
ro.reset(new class_ro_t);
if (!ro->Read(process_sp, rw->m_ro_la))
return false;
}
else
{
ro.reset(new class_ro_t);
if (!ro->Read(process_sp, m_objc_class.m_data_la))
return false;
}
superclass_func(m_objc_class.m_superclass);
std::auto_ptr <method_list_t> base_method_list;
base_method_list.reset(new method_list_t);
if (!base_method_list->Read(process_sp, ro->m_baseMethods_la))
return false;
std::auto_ptr <method_t> method;
method.reset(new method_t);
for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i)
{
method->Read(process_sp, base_method_list->m_first_la + (i * base_method_list->m_entsize));
method_func(method->m_name.c_str(), method->m_types.c_str());
}
return true;
}
virtual bool
@ -1102,35 +1146,11 @@ protected:
m_valid = false;
return;
}
size_t objc_class_size = ptr_size // uintptr_t isa;
+ ptr_size // Class superclass;
+ ptr_size // void *cache;
+ ptr_size // IMP *vtable;
+ ptr_size; // uintptr_t data_NEVER_USE;
if (!m_objc_class.Read(process_sp, m_objc_class_la))
{
DataBufferHeap objc_class_buf (objc_class_size, '\0');
process_sp->ReadMemory(m_objc_class_la, objc_class_buf.GetBytes(), objc_class_size, error);
if (error.Fail())
{
m_valid = false;
return;
}
DataExtractor objc_class_extractor(objc_class_buf.GetBytes(), objc_class_size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_objc_class.m_isa = objc_class_extractor.GetAddress_unchecked(&cursor); // uintptr_t isa;
m_objc_class.m_superclass = objc_class_extractor.GetAddress_unchecked(&cursor); // Class superclass;
m_objc_class.m_cache_la = objc_class_extractor.GetAddress_unchecked(&cursor); // void *cache;
m_objc_class.m_vtable_la = objc_class_extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
lldb::addr_t data_NEVER_USE = objc_class_extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
m_objc_class.m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
m_objc_class.m_data_la = data_NEVER_USE & ~(lldb::addr_t)3;
m_valid = false;
return;
}
// Now we just want to grab the instance size and the name.
@ -1227,7 +1247,7 @@ protected:
m_process_wp = lldb::ProcessWP(process_sp);
}
private:
static const uint32_t RW_REALIZED = (1 << 31);
@ -1241,6 +1261,41 @@ private:
lldb::addr_t m_vtable_la;
lldb::addr_t m_data_la;
uint8_t m_flags;
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
{
size_t ptr_size = process_sp->GetAddressByteSize();
size_t objc_class_size = ptr_size // uintptr_t isa;
+ ptr_size // Class superclass;
+ ptr_size // void *cache;
+ ptr_size // IMP *vtable;
+ ptr_size; // uintptr_t data_NEVER_USE;
DataBufferHeap objc_class_buf (objc_class_size, '\0');
Error error;
process_sp->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
if (error.Fail())
{
return false;
}
DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa;
m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass;
m_cache_la = extractor.GetAddress_unchecked(&cursor); // void *cache;
m_vtable_la = extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
m_data_la = data_NEVER_USE & ~(lldb::addr_t)3;
return true;
}
};
objc_class_t m_objc_class;
@ -1264,10 +1319,55 @@ private:
lldb::addr_t m_weakIvarLayout_la;
lldb::addr_t m_baseProperties_la;
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
{
size_t ptr_size = process_sp->GetAddressByteSize();
size_t size = sizeof(uint32_t) // uint32_t flags;
+ sizeof(uint32_t) // uint32_t instanceStart;
+ sizeof(uint32_t) // uint32_t instanceSize;
+ (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only
+ ptr_size // const uint8_t *ivarLayout;
+ ptr_size // const char *name;
+ ptr_size // const method_list_t *baseMethods;
+ ptr_size // const protocol_list_t *baseProtocols;
+ ptr_size // const ivar_list_t *ivars;
+ ptr_size // const uint8_t *weakIvarLayout;
+ ptr_size; // const property_list_t *baseProperties;
DataBufferHeap buffer (size, '\0');
Error error;
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail())
{
return false;
}
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_flags = extractor.GetU32_unchecked(&cursor);
m_instanceStart = extractor.GetU32_unchecked(&cursor);
m_instanceSize = extractor.GetU32_unchecked(&cursor);
if (ptr_size == 8)
m_reserved = extractor.GetU32_unchecked(&cursor);
else
m_reserved = 0;
m_ivarLayout_la = extractor.GetAddress_unchecked(&cursor);
m_name_la = extractor.GetAddress_unchecked(&cursor);
m_baseMethods_la = extractor.GetAddress_unchecked(&cursor);
m_baseProtocols_la = extractor.GetAddress_unchecked(&cursor);
m_ivars_la = extractor.GetAddress_unchecked(&cursor);
m_weakIvarLayout_la = extractor.GetAddress_unchecked(&cursor);
m_baseProperties_la = extractor.GetAddress_unchecked(&cursor);
return true;
}
};
std::auto_ptr<class_ro_t> m_class_ro;
struct class_rw_t {
uint32_t m_flags;
uint32_t m_version;
@ -1282,9 +1382,122 @@ private:
ObjCLanguageRuntime::ObjCISA m_firstSubclass;
ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
{
size_t ptr_size = process_sp->GetAddressByteSize();
size_t size = sizeof(uint32_t) // uint32_t flags;
+ sizeof(uint32_t) // uint32_t version;
+ ptr_size // const class_ro_t *ro;
+ ptr_size // union { method_list_t **method_lists; method_list_t *method_list; };
+ ptr_size // struct chained_property_list *properties;
+ ptr_size // const protocol_list_t **protocols;
+ ptr_size // Class firstSubclass;
+ ptr_size; // Class nextSiblingClass;
DataBufferHeap buffer (size, '\0');
Error error;
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail())
{
return false;
}
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_flags = extractor.GetU32_unchecked(&cursor);
m_version = extractor.GetU32_unchecked(&cursor);
m_ro_la = extractor.GetAddress_unchecked(&cursor);
m_method_list_la = extractor.GetAddress_unchecked(&cursor);
m_properties_la = extractor.GetAddress_unchecked(&cursor);
m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
return true;
}
};
std::auto_ptr<class_rw_t> m_class_rw;
struct method_list_t
{
uint32_t m_entsize;
uint32_t m_count;
lldb::addr_t m_first_la;
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
{
size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE;
+ sizeof(uint32_t); // uint32_t count;
DataBufferHeap buffer (size, '\0');
Error error;
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail())
{
return false;
}
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3;
m_count = extractor.GetU32_unchecked(&cursor);
m_first_la = addr + cursor;
return true;
}
};
struct method_t
{
lldb::addr_t m_name_la;
lldb::addr_t m_types_la;
lldb::addr_t m_imp_la;
std::string m_name;
std::string m_types;
bool Read(ProcessSP &process_sp, lldb::addr_t addr)
{
size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE;
+ sizeof(uint32_t); // uint32_t count;
DataBufferHeap buffer (size, '\0');
Error error;
process_sp->ReadMemory(addr, buffer.GetBytes(), size, error);
if (error.Fail())
{
return false;
}
DataExtractor extractor(buffer.GetBytes(), size, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
uint32_t cursor = 0;
m_name_la = extractor.GetAddress_unchecked(&cursor);
m_types_la = extractor.GetAddress_unchecked(&cursor);
m_imp_la = extractor.GetAddress_unchecked(&cursor);
const size_t buffer_size = 1024;
size_t count;
DataBufferHeap string_buf(buffer_size, 0);
count = process_sp->ReadCStringFromMemory(m_name_la, (char*)string_buf.GetBytes(), buffer_size, error);
m_name.assign((char*)string_buf.GetBytes(), count);
count = process_sp->ReadCStringFromMemory(m_types_la, (char*)string_buf.GetBytes(), buffer_size, error);
m_types.assign((char*)string_buf.GetBytes(), count);
return true;
}
};
lldb::ProcessWP m_process_wp;
};

View File

@ -55,28 +55,12 @@ public:
if (!interface_decl)
break;
ObjCLanguageRuntime::ObjCISA objc_isa = (ObjCLanguageRuntime::ObjCISA)GetMetadata((uintptr_t)interface_decl);
if (!objc_isa)
break;
clang::ObjCInterfaceDecl *non_const_interface_decl = const_cast<clang::ObjCInterfaceDecl*>(interface_decl);
if (non_const_interface_decl->hasExternalVisibleStorage())
{
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_type_vendor.m_runtime.GetClassDescriptor(objc_isa);
if (!descriptor)
break;
if (descriptor->CompleteInterface(non_const_interface_decl))
non_const_interface_decl->setHasExternalVisibleStorage(false);
}
if (non_const_interface_decl->hasExternalVisibleStorage())
if (!m_type_vendor.FinishDecl(non_const_interface_decl))
break;
return non_const_interface_decl->lookup(name);
}
while(0);
@ -183,6 +167,78 @@ AppleObjCTypeVendor::AppleObjCTypeVendor(ObjCLanguageRuntime &runtime) :
m_ast_ctx.getASTContext()->setExternalSource(external_source_owning_ptr);
}
clang::ObjCInterfaceDecl*
AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
{
ISAToInterfaceMap::const_iterator iter = m_isa_to_interface.find(isa);
if (iter != m_isa_to_interface.end())
return iter->second;
clang::ASTContext *ast_ctx = m_ast_ctx.getASTContext();
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(isa);
if (!descriptor)
return NULL;
const ConstString &name(descriptor->GetClassName());
clang::IdentifierInfo &identifier_info = ast_ctx->Idents.get(name.GetStringRef());
clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
ast_ctx->getTranslationUnitDecl(),
clang::SourceLocation(),
&identifier_info,
NULL);
m_external_source->SetMetadata((uintptr_t)new_iface_decl, (uint64_t)isa);
new_iface_decl->setHasExternalVisibleStorage();
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
m_isa_to_interface[isa] = new_iface_decl;
return new_iface_decl;
}
bool
AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
{
ObjCLanguageRuntime::ObjCISA objc_isa = (ObjCLanguageRuntime::ObjCISA)m_external_source->GetMetadata((uintptr_t)interface_decl);
if (!objc_isa)
return false;
if (!interface_decl->hasExternalVisibleStorage())
return true;
interface_decl->startDefinition();
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(objc_isa);
if (!descriptor)
return false;
auto superclass_func = [interface_decl, this](ObjCLanguageRuntime::ObjCISA isa)
{
clang::ObjCInterfaceDecl *superclass_decl = GetDeclForISA(isa);
if (!superclass_decl)
return;
interface_decl->setSuperClass(superclass_decl);
};
auto method_func = [interface_decl, this](const char *name, const char *types)
{
};
if (!descriptor->Describe(superclass_func, method_func))
return false;
interface_decl->setHasExternalVisibleStorage(false);
return true;
}
uint32_t
AppleObjCTypeVendor::FindTypes (const ConstString &name,
bool append,
@ -206,6 +262,9 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
uint32_t ret = 0;
// TODO Remove this return once testing is complete.
return ret;
do
{
// See if the type is already in our ASTContext.
@ -252,10 +311,7 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
}
// It's not. If it exists, we have to put it into our ASTContext.
// TODO Remove this break once testing is complete.
break;
ObjCLanguageRuntime::ObjCISA isa = m_runtime.GetISA(name);
if (!isa)
@ -267,17 +323,17 @@ AppleObjCTypeVendor::FindTypes (const ConstString &name,
break;
}
clang::ObjCInterfaceDecl *new_iface_decl = clang::ObjCInterfaceDecl::Create(*ast_ctx,
ast_ctx->getTranslationUnitDecl(),
clang::SourceLocation(),
&identifier_info,
NULL);
clang::ObjCInterfaceDecl *iface_decl = GetDeclForISA(isa);
m_external_source->SetMetadata((uintptr_t)new_iface_decl, (uint64_t)isa);
new_iface_decl->setHasExternalVisibleStorage();
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
if (!iface_decl)
{
if (log)
log->Printf("AOCTV::FT [%u] Couldn't get the Objective-C interface for isa 0x%llx",
current_id,
(uint64_t)isa);
}
clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(new_iface_decl);
clang::QualType new_iface_type = ast_ctx->getObjCInterfaceType(iface_decl);
if (log)
{

View File

@ -21,6 +21,7 @@
#include "lldb/lldb-private.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/TypeVendor.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
namespace lldb_private {
@ -39,9 +40,16 @@ public:
friend class AppleObjCExternalASTSource;
private:
ObjCLanguageRuntime &m_runtime;
ClangASTContext m_ast_ctx;
AppleObjCExternalASTSource *m_external_source;
clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa);
bool FinishDecl(clang::ObjCInterfaceDecl *decl);
ObjCLanguageRuntime &m_runtime;
ClangASTContext m_ast_ctx;
AppleObjCExternalASTSource *m_external_source;
typedef llvm::DenseMap<ObjCLanguageRuntime::ObjCISA, clang::ObjCInterfaceDecl *> ISAToInterfaceMap;
ISAToInterfaceMap m_isa_to_interface;
};
} // namespace lldb_private