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:
Sean Callanan 2012-12-19 23:05:01 +00:00
parent 6848e38daf
commit 7be70e8528
13 changed files with 170 additions and 78 deletions

View File

@ -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:
//------------------------------------------------------------------

View File

@ -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();

View File

@ -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)

View File

@ -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();
}

View File

@ -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);
};

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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__':

View File

@ -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;

View File

@ -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")

View File

@ -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)