This patch removes the SymbolFileSymtab support
for reporting class types from Objective-C runtime class symbols. Instead, LLDB now queries the Objective-C runtime for class types. We have also added a (minimal) Objective-C runtime type vendor for Objective-C runtime version 1, to prevent regressions when calling class methods in the V1 runtime. Other components of this fix include: - We search the Objective-C runtime in a few more places. - We enable enumeration of all members of Objective-C classes, which Clang does in certain circumstances. - SBTarget::FindFirstType and SBTarget::FindTypes now query the Objective-C runtime as needed. - I fixed several test cases. <rdar://problem/12885034> llvm-svn: 170601
This commit is contained in:
parent
6848e38daf
commit
7be70e8528
|
@ -10,6 +10,8 @@
|
|||
#ifndef liblldb_TypeVendor_h_
|
||||
#define liblldb_TypeVendor_h_
|
||||
|
||||
#include "lldb/Core/ClangForward.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -37,6 +39,9 @@ public:
|
|||
bool append,
|
||||
uint32_t max_matches,
|
||||
std::vector <ClangASTType> &types) = 0;
|
||||
|
||||
virtual clang::ASTContext *
|
||||
GetClangASTContext () = 0;
|
||||
|
||||
protected:
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -2085,6 +2085,29 @@ SBTarget::FindFirstType (const char* typename_cstr)
|
|||
return SBType(type_sp);
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't find the type in the symbols; try the Objective-C runtime
|
||||
// if one is installed
|
||||
|
||||
ProcessSP process_sp(target_sp->GetProcessSP());
|
||||
|
||||
if (process_sp)
|
||||
{
|
||||
ObjCLanguageRuntime *objc_language_runtime = process_sp->GetObjCLanguageRuntime();
|
||||
|
||||
if (objc_language_runtime)
|
||||
{
|
||||
TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
|
||||
|
||||
if (objc_type_vendor)
|
||||
{
|
||||
std::vector <ClangASTType> types;
|
||||
|
||||
if (objc_type_vendor->FindTypes(const_typename, true, 1, types) > 0)
|
||||
return SBType(types[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No matches, search for basic typename matches
|
||||
ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
|
||||
|
@ -2136,7 +2159,35 @@ SBTarget::FindTypes (const char* typename_cstr)
|
|||
sb_type_list.Append(SBType(type_sp));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// Try the Objective-C runtime if one is installed
|
||||
|
||||
ProcessSP process_sp(target_sp->GetProcessSP());
|
||||
|
||||
if (process_sp)
|
||||
{
|
||||
ObjCLanguageRuntime *objc_language_runtime = process_sp->GetObjCLanguageRuntime();
|
||||
|
||||
if (objc_language_runtime)
|
||||
{
|
||||
TypeVendor *objc_type_vendor = objc_language_runtime->GetTypeVendor();
|
||||
|
||||
if (objc_type_vendor)
|
||||
{
|
||||
std::vector <ClangASTType> types;
|
||||
|
||||
if (objc_type_vendor->FindTypes(const_typename, true, UINT32_MAX, types))
|
||||
{
|
||||
for (ClangASTType &type : types)
|
||||
{
|
||||
sb_type_list.Append(SBType(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sb_type_list.GetSize() == 0)
|
||||
{
|
||||
// No matches, search for basic typename matches
|
||||
ClangASTContext *clang_ast = target_sp->GetScratchClangASTContext();
|
||||
|
|
|
@ -681,7 +681,7 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
|
|||
if (!copied_type)
|
||||
{
|
||||
if (log)
|
||||
log->Printf(" CAS::FEVD[%u] - Couldn't export the type for a constant integer result",
|
||||
log->Printf(" CAS::FEVD[%u] - Couldn't export a type",
|
||||
current_id);
|
||||
|
||||
break;
|
||||
|
@ -689,6 +689,63 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
|
|||
|
||||
context.AddTypeDecl(copied_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
// Couldn't find any types elsewhere. Try the Objective-C runtime if one exists.
|
||||
|
||||
lldb::ProcessSP process(m_target->GetProcessSP());
|
||||
|
||||
if (!process)
|
||||
break;
|
||||
|
||||
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
|
||||
|
||||
if (!language_runtime)
|
||||
break;
|
||||
|
||||
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
|
||||
|
||||
if (!type_vendor)
|
||||
break;
|
||||
|
||||
bool append = false;
|
||||
uint32_t max_matches = 1;
|
||||
std::vector <ClangASTType> types;
|
||||
|
||||
if (!type_vendor->FindTypes(name,
|
||||
append,
|
||||
max_matches,
|
||||
types))
|
||||
break;
|
||||
|
||||
if (log)
|
||||
{
|
||||
log->Printf(" CAS::FEVD[%u] Matching type found for \"%s\" in the runtime",
|
||||
current_id,
|
||||
name.GetCString());
|
||||
}
|
||||
|
||||
const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();
|
||||
|
||||
clang::QualType runtime_qual_type(runtime_clang_type, 0);
|
||||
|
||||
void *copied_type = GuardedCopyType(m_ast_context, type_vendor->GetClangASTContext(), runtime_qual_type.getAsOpaquePtr());
|
||||
|
||||
if (!copied_type)
|
||||
{
|
||||
if (log)
|
||||
log->Printf(" CAS::FEVD[%u] - Couldn't export a type from the runtime",
|
||||
current_id);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
context.AddTypeDecl(copied_type);
|
||||
}
|
||||
while(0);
|
||||
}
|
||||
|
||||
} while(0);
|
||||
}
|
||||
|
@ -1076,6 +1133,9 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
|
|||
|
||||
ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());
|
||||
|
||||
if (!language_runtime)
|
||||
break;
|
||||
|
||||
TypeVendor *type_vendor = language_runtime->GetTypeVendor();
|
||||
|
||||
if (!type_vendor)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "AppleObjCRuntimeV1.h"
|
||||
#include "AppleObjCTrampolineHandler.h"
|
||||
#include "AppleObjCTypeVendor.h"
|
||||
|
||||
#include "llvm/Support/MachO.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
@ -294,6 +295,15 @@ AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass ()
|
|||
return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
AppleObjCRuntimeV1::GetISAHashTablePointer ()
|
||||
{
|
||||
|
@ -454,3 +464,11 @@ AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded()
|
|||
}
|
||||
}
|
||||
|
||||
TypeVendor *
|
||||
AppleObjCRuntimeV1::GetTypeVendor()
|
||||
{
|
||||
if (!m_type_vendor_ap.get())
|
||||
m_type_vendor_ap.reset(new AppleObjCTypeVendor(*this));
|
||||
|
||||
return m_type_vendor_ap.get();
|
||||
}
|
||||
|
|
|
@ -64,6 +64,12 @@ public:
|
|||
return m_isa;
|
||||
}
|
||||
|
||||
virtual 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);
|
||||
|
||||
virtual
|
||||
~ClassDescriptorV1 ()
|
||||
{}
|
||||
|
@ -125,6 +131,9 @@ public:
|
|||
|
||||
virtual void
|
||||
UpdateISAToDescriptorMapIfNeeded();
|
||||
|
||||
virtual TypeVendor *
|
||||
GetTypeVendor();
|
||||
|
||||
protected:
|
||||
virtual lldb::BreakpointResolverSP
|
||||
|
@ -173,6 +182,7 @@ protected:
|
|||
|
||||
HashTableSignature m_hash_signature;
|
||||
lldb::addr_t m_isa_hash_table_ptr;
|
||||
std::auto_ptr<TypeVendor> m_type_vendor_ap;
|
||||
private:
|
||||
AppleObjCRuntimeV1(Process *process);
|
||||
};
|
||||
|
|
|
@ -126,6 +126,8 @@ public:
|
|||
ASTDumper dumper((clang::Decl*)interface_decl);
|
||||
dumper.ToLog(log, " [CT] ");
|
||||
}
|
||||
|
||||
m_type_vendor.FinishDecl(interface_decl);
|
||||
|
||||
if (log)
|
||||
{
|
||||
|
@ -197,6 +199,7 @@ AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
|
|||
m_external_source->SetMetadata((uintptr_t)new_iface_decl, meta_data);
|
||||
|
||||
new_iface_decl->setHasExternalVisibleStorage();
|
||||
new_iface_decl->setHasExternalLexicalStorage();
|
||||
|
||||
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
|
||||
|
||||
|
@ -508,6 +511,7 @@ AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
|
|||
interface_decl->startDefinition();
|
||||
|
||||
interface_decl->setHasExternalVisibleStorage(false);
|
||||
interface_decl->setHasExternalLexicalStorage(false);
|
||||
|
||||
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(objc_isa);
|
||||
|
||||
|
|
|
@ -38,6 +38,12 @@ public:
|
|||
uint32_t max_matches,
|
||||
std::vector <ClangASTType> &types);
|
||||
|
||||
virtual clang::ASTContext *
|
||||
GetClangASTContext ()
|
||||
{
|
||||
return m_ast_ctx.getASTContext();
|
||||
}
|
||||
|
||||
friend class AppleObjCExternalASTSource;
|
||||
private:
|
||||
clang::ObjCInterfaceDecl *GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa);
|
||||
|
|
|
@ -381,66 +381,8 @@ SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc,
|
|||
uint32_t max_matches,
|
||||
lldb_private::TypeList& types)
|
||||
{
|
||||
if (!append)
|
||||
types.Clear();
|
||||
|
||||
if (!m_objc_class_name_to_index.IsEmpty())
|
||||
{
|
||||
TypeMap::iterator iter = m_objc_class_types.find(name);
|
||||
|
||||
if (iter != m_objc_class_types.end())
|
||||
{
|
||||
types.Insert(iter->second);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const Symtab::NameToIndexMap::Entry *match = m_objc_class_name_to_index.FindFirstValueForName(name.GetCString());
|
||||
|
||||
if (match == NULL)
|
||||
return 0;
|
||||
|
||||
const bool isForwardDecl = false;
|
||||
const bool isInternal = true;
|
||||
|
||||
ClangASTContext &ast = GetClangASTContext();
|
||||
|
||||
ClangASTMetadata metadata;
|
||||
metadata.SetUserID(0xffaaffaaffaaffaall);
|
||||
lldb::clang_type_t objc_object_type = ast.CreateObjCClass (name.AsCString(),
|
||||
ast.GetTranslationUnitDecl(),
|
||||
isForwardDecl,
|
||||
isInternal,
|
||||
&metadata);
|
||||
|
||||
Declaration decl;
|
||||
|
||||
lldb::TypeSP type(new Type (match->value,
|
||||
this,
|
||||
name,
|
||||
0, // byte_size - don't change this from 0, we currently use that to identify these "synthetic" ObjC class types.
|
||||
NULL, // SymbolContextScope*
|
||||
0, // encoding_uid
|
||||
Type::eEncodingInvalid,
|
||||
decl,
|
||||
objc_object_type,
|
||||
Type::eResolveStateFull));
|
||||
|
||||
m_objc_class_types[name] = type;
|
||||
|
||||
types.Insert(type);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
//uint32_t
|
||||
//SymbolFileSymtab::FindTypes(const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, TypeList& types)
|
||||
//{
|
||||
// return 0;
|
||||
//}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// PluginInterface protocol
|
||||
|
|
|
@ -105,9 +105,7 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
|
|||
types);
|
||||
|
||||
if (num_types)
|
||||
{
|
||||
TypeSP incomplete_type_sp;
|
||||
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < num_types; ++i)
|
||||
{
|
||||
|
@ -120,8 +118,6 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
|
|||
m_complete_class_cache[name] = type_sp;
|
||||
return type_sp;
|
||||
}
|
||||
else if (!incomplete_type_sp)
|
||||
incomplete_type_sp = type_sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,23 +59,23 @@ class DataFormatterRdar11988289TestCase(TestBase):
|
|||
# Now check that we are displaying Cocoa classes correctly
|
||||
self.expect('frame variable dictionary',
|
||||
substrs = ['3 key/value pairs'])
|
||||
self.expect('frame variable mutable',
|
||||
self.expect('frame variable mutabledict',
|
||||
substrs = ['4 key/value pairs'])
|
||||
self.expect('frame variable dictionary --ptr-depth 1',
|
||||
substrs = ['3 key/value pairs','[0] = {','key = 0x','value = 0x','[1] = {','[2] = {'])
|
||||
self.expect('frame variable mutable --ptr-depth 1',
|
||||
self.expect('frame variable mutabledict --ptr-depth 1',
|
||||
substrs = ['4 key/value pairs','[0] = {','key = 0x','value = 0x','[1] = {','[2] = {','[3] = {'])
|
||||
self.expect('frame variable dictionary --ptr-depth 1 --dynamic-type no-run-target',
|
||||
substrs = ['3 key/value pairs','@"bar"','@"2 objects"','@"baz"','2 key/value pairs'])
|
||||
self.expect('frame variable mutable --ptr-depth 1 --dynamic-type no-run-target',
|
||||
self.expect('frame variable mutabledict --ptr-depth 1 --dynamic-type no-run-target',
|
||||
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs'])
|
||||
self.expect('frame variable mutable --ptr-depth 2 --dynamic-type no-run-target',
|
||||
self.expect('frame variable mutabledict --ptr-depth 2 --dynamic-type no-run-target',
|
||||
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs {','@"bar"','@"2 objects"'])
|
||||
self.expect('frame variable mutable --ptr-depth 3 --dynamic-type no-run-target',
|
||||
self.expect('frame variable mutabledict --ptr-depth 3 --dynamic-type no-run-target',
|
||||
substrs = ['4 key/value pairs','(int)23','@"123"','@"http://www.apple.com"','@"puartist"','3 key/value pairs {','@"bar"','@"2 objects"','(int)1','@"two"'])
|
||||
|
||||
self.assertTrue(self.frame().FindVariable("dictionary").MightHaveChildren(), "dictionary says it does not have children!")
|
||||
self.assertTrue(self.frame().FindVariable("mutable").MightHaveChildren(), "mutable says it does not have children!")
|
||||
self.assertTrue(self.frame().FindVariable("mutabledict").MightHaveChildren(), "mutable says it does not have children!")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -18,11 +18,11 @@ int main (int argc, const char * argv[])
|
|||
NSArray* keys = @[@"foo",@"bar",@"baz"];
|
||||
NSArray* values = @[@"hello",@[@"X",@"Y"],@{@1 : @"one",@2 : @"two"}];
|
||||
NSDictionary* dictionary = [NSDictionary dictionaryWithObjects:values forKeys:keys];
|
||||
NSMutableDictionary* mutable = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||
[mutable setObject:@"123" forKey:@23];
|
||||
[mutable setObject:[NSURL URLWithString:@"http://www.apple.com"] forKey:@"foobar"];
|
||||
[mutable setObject:@[@"a",@12] forKey:@57];
|
||||
[mutable setObject:dictionary forKey:@"puartist"];
|
||||
NSMutableDictionary* mutabledict = [NSMutableDictionary dictionaryWithCapacity:5];
|
||||
[mutabledict setObject:@"123" forKey:@23];
|
||||
[mutabledict setObject:[NSURL URLWithString:@"http://www.apple.com"] forKey:@"foobar"];
|
||||
[mutabledict setObject:@[@"a",@12] forKey:@57];
|
||||
[mutabledict setObject:dictionary forKey:@"puartist"];
|
||||
|
||||
[pool drain];// Set break point at this line.
|
||||
return 0;
|
||||
|
|
|
@ -230,7 +230,7 @@ class FoundationTestCase2(TestBase):
|
|||
|
||||
self.runCmd("run", RUN_SUCCEEDED)
|
||||
|
||||
self.expect("p [NSError errorWithDomain:@\"Hello\" code:35 userInfo:nil]",
|
||||
self.expect("p [NSError thisMethodIsntImplemented:0]",
|
||||
error = True,
|
||||
patterns = ["no known method", "cast the message send to the method's return type"])
|
||||
self.runCmd("process continue")
|
||||
|
|
|
@ -66,7 +66,7 @@ class TypeAndTypeListTestCase(TestBase):
|
|||
type_list = target.FindTypes('Task')
|
||||
if self.TraceOn():
|
||||
print "Size of type_list from target.FindTypes('Task') query: %d" % type_list.GetSize()
|
||||
self.assertTrue(len(type_list) == 1)
|
||||
self.assertTrue(len(type_list) >= 1) # a second Task make be scared up by the Objective-C runtime
|
||||
for type in type_list:
|
||||
self.assertTrue(type)
|
||||
self.DebugSBType(type)
|
||||
|
|
Loading…
Reference in New Issue