Skip to content

Commit

Permalink
Extra safeguards to ensure that we never query
Browse files Browse the repository at this point in the history
the runtime if we have complete debug information
for a class.

Also made the Objective-C language runtime return
NULL when asked for the complete debug information
(i.e., information from DWARF, not information from
the runtime) if that information isn't present.  It
used to return a non-authoritative version, which
made it hard for clients to determine whether
complete debug information was available.

<rdar://problem/12608895>


git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@167299 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
scallanan committed Nov 2, 2012
1 parent cbd3905 commit 4cbeeff
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 131 deletions.
276 changes: 156 additions & 120 deletions source/Expression/ClangASTSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,63 @@ ClangASTSource::FindExternalVisibleDecls (NameSearchContext &context,
} while(0);
}

template <class D> class TaggedASTDecl {
public:
TaggedASTDecl() : decl(NULL) { }
TaggedASTDecl(D *_decl) : decl(_decl) { }
bool IsValid() const { return (decl != NULL); }
bool IsInvalid() const { return !IsValid(); }
D *operator->() const { return decl; }
D *decl;
};

template <class D2, template <class D> class TD, class D1>
TD<D2>
DynCast(TD<D1> source)
{
return TD<D2> (dyn_cast<D2>(source.decl));
}

template <class D = Decl> class DeclFromParser;
template <class D = Decl> class DeclFromUser;

template <class D> class DeclFromParser : public TaggedASTDecl<D> {
public:
DeclFromParser() : TaggedASTDecl<D>() { }
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }

DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
};

template <class D> class DeclFromUser : public TaggedASTDecl<D> {
public:
DeclFromUser() : TaggedASTDecl<D>() { }
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }

DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
};

template <class D>
DeclFromUser<D>
DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
{
DeclFromUser <> origin_decl;
importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
if (origin_decl.IsInvalid())
return DeclFromUser<D>();
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
}

template <class D>
DeclFromParser<D>
DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx)
{
DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl));
if (parser_generic_decl.IsInvalid())
return DeclFromParser<D>();
return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
}

static void
FindObjCMethodDeclsWithOrigin (unsigned int current_id,
NameSearchContext &context,
Expand Down Expand Up @@ -807,7 +864,7 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
original_interface_decl,
m_ast_context,
m_ast_importer,
"in debug info");
"at origin");
} while (0);

StreamString ss;
Expand Down Expand Up @@ -964,117 +1021,93 @@ ClangASTSource::FindObjCMethodDecls (NameSearchContext &context)
if (log)
{
ASTDumper dumper((Decl*)copied_method_decl);
log->Printf(" CAS::FOMD[%d] found (in debug info) %s", current_id, dumper.GetCString());
log->Printf(" CAS::FOMD[%d] found (in symbols) %s", current_id, dumper.GetCString());
}

context.AddNamedDecl(copied_method_decl);
}
}

return;
}
else

// Try the debug information.

do
{
do
{
// We need to look at the runtime.

lldb::ProcessSP process(m_target->GetProcessSP());

if (!process)
break;

ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());

TypeVendor *type_vendor = language_runtime->GetTypeVendor();

if (!type_vendor)
break;

ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;

if (!type_vendor->FindTypes(interface_name,
append,
max_matches,
types))
break;

const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();

const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);

if (!runtime_interface_type)
break;

ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();

FindObjCMethodDeclsWithOrigin(current_id,
context,
runtime_interface_decl,
m_ast_context,
m_ast_importer,
"in runtime");
}
while(0);
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(interface_decl));

if (!complete_interface_decl)
break;

// We found the complete interface. The runtime never needs to be queried in this scenario.

DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);

if (complete_interface_decl == interface_decl)
break; // already checked this one

if (log)
log->Printf("CAS::FOPD[%d] trying origin (ObjCInterfaceDecl*)%p/(ASTContext*)%p...",
current_id,
complete_interface_decl,
&complete_iface_decl->getASTContext());

FindObjCMethodDeclsWithOrigin(current_id,
context,
complete_interface_decl,
m_ast_context,
m_ast_importer,
"in debug info");

return;
}
}

template <class D> class TaggedASTDecl {
public:
TaggedASTDecl() : decl(NULL) { }
TaggedASTDecl(D *_decl) : decl(_decl) { }
bool IsValid() const { return (decl != NULL); }
bool IsInvalid() const { return !IsValid(); }
D *operator->() const { return decl; }
D *decl;
};

template <class D2, template <class D> class TD, class D1>
TD<D2>
DynCast(TD<D1> source)
{
return TD<D2> (dyn_cast<D2>(source.decl));
}

template <class D = Decl> class DeclFromParser;
template <class D = Decl> class DeclFromUser;

template <class D> class DeclFromParser : public TaggedASTDecl<D> {
public:
DeclFromParser() : TaggedASTDecl<D>() { }
DeclFromParser(D *_decl) : TaggedASTDecl<D>(_decl) { }

DeclFromUser<D> GetOrigin(ClangASTImporter *importer);
};

template <class D> class DeclFromUser : public TaggedASTDecl<D> {
public:
DeclFromUser() : TaggedASTDecl<D>() { }
DeclFromUser(D *_decl) : TaggedASTDecl<D>(_decl) { }
while (0);

DeclFromParser<D> Import(ClangASTImporter *importer, ASTContext &dest_ctx);
};

template <class D>
DeclFromUser<D>
DeclFromParser<D>::GetOrigin(ClangASTImporter *importer)
{
DeclFromUser <> origin_decl;
importer->ResolveDeclOrigin(this->decl, &origin_decl.decl, NULL);
if (origin_decl.IsInvalid())
return DeclFromUser<D>();
return DeclFromUser<D>(dyn_cast<D>(origin_decl.decl));
}

template <class D>
DeclFromParser<D>
DeclFromUser<D>::Import(ClangASTImporter *importer, ASTContext &dest_ctx)
{
DeclFromParser <> parser_generic_decl(importer->CopyDecl(&dest_ctx, &this->decl->getASTContext(), this->decl));
if (parser_generic_decl.IsInvalid())
return DeclFromParser<D>();
return DeclFromParser<D>(dyn_cast<D>(parser_generic_decl.decl));
do
{
// Check the runtime only if the debug information didn't have a complete interface.

lldb::ProcessSP process(m_target->GetProcessSP());

if (!process)
break;

ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());

TypeVendor *type_vendor = language_runtime->GetTypeVendor();

if (!type_vendor)
break;

ConstString interface_name(interface_decl->getNameAsString().c_str());
bool append = false;
uint32_t max_matches = 1;
std::vector <ClangASTType> types;

if (!type_vendor->FindTypes(interface_name,
append,
max_matches,
types))
break;

const clang::Type *runtime_clang_type = QualType::getFromOpaquePtr(types[0].GetOpaqueQualType()).getTypePtr();

const ObjCInterfaceType *runtime_interface_type = dyn_cast<ObjCInterfaceType>(runtime_clang_type);

if (!runtime_interface_type)
break;

ObjCInterfaceDecl *runtime_interface_decl = runtime_interface_type->getDecl();

FindObjCMethodDeclsWithOrigin(current_id,
context,
runtime_interface_decl,
m_ast_context,
m_ast_importer,
"in runtime");
}
while(0);
}

static bool
Expand Down Expand Up @@ -1170,23 +1203,15 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
SymbolContext null_sc;
TypeList type_list;

lldb::ProcessSP process(m_target->GetProcessSP());

if (!process)
return;

ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());

if (!language_runtime)
return;

do
{
ObjCInterfaceDecl *complete_interface_decl = GetCompleteObjCInterface(const_cast<ObjCInterfaceDecl*>(parser_iface_decl.decl));

if (!complete_interface_decl)
break;

// We found the complete interface. The runtime never needs to be queried in this scenario.

DeclFromUser<const ObjCInterfaceDecl> complete_iface_decl(complete_interface_decl);

if (complete_iface_decl.decl == origin_iface_decl.decl)
Expand All @@ -1198,18 +1223,29 @@ ClangASTSource::FindObjCPropertyAndIvarDecls (NameSearchContext &context)
complete_iface_decl.decl,
&complete_iface_decl->getASTContext());

if (FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
context,
*m_ast_context,
m_ast_importer,
complete_iface_decl))
return;
FindObjCPropertyAndIvarDeclsWithOrigin(current_id,
context,
*m_ast_context,
m_ast_importer,
complete_iface_decl);

return;
}
while(0);

do
{
// Now check the runtime.
// Check the runtime only if the debug information didn't have a complete interface.

lldb::ProcessSP process(m_target->GetProcessSP());

if (!process)
return;

ObjCLanguageRuntime *language_runtime(process->GetObjCLanguageRuntime());

if (!language_runtime)
return;

TypeVendor *type_vendor = language_runtime->GetTypeVendor();

Expand Down
11 changes: 0 additions & 11 deletions source/Target/ObjCLanguageRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,17 +124,6 @@ ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name)
incomplete_type_sp = type_sp;
}
}

// We didn't find any "real" definitions, so just use any??? Why was
// this being done? Prior to this, if there was 1 match only, then it
// would always use any objc definition, else we would only accept a
// definition if it was the real thing???? Doesn't make sense.

if (incomplete_type_sp)
{
m_complete_class_cache[name] = incomplete_type_sp;
return incomplete_type_sp;
}
}
}
return TypeSP();
Expand Down

0 comments on commit 4cbeeff

Please sign in to comment.