Fixed some bugs in the runtime reader code. Also

added a parser for method signatures in the
Objective-C @encode format.

llvm-svn: 164792
This commit is contained in:
Sean Callanan 2012-09-27 20:38:15 +00:00
parent dd09c34351
commit 2885a7088d
2 changed files with 320 additions and 7 deletions

View File

@ -1084,6 +1084,9 @@ public:
if (!base_method_list->Read(process_sp, ro->m_baseMethods_la))
return false;
if (base_method_list->m_entsize != method_t::GetSize(process_sp))
return false;
std::auto_ptr <method_t> method;
method.reset(new method_t);
@ -1462,10 +1465,18 @@ private:
std::string m_name;
std::string m_types;
static size_t GetSize(ProcessSP &process_sp)
{
size_t ptr_size = process_sp->GetAddressByteSize();
return ptr_size // SEL name;
+ ptr_size // const char *types;
+ ptr_size; // IMP imp;
}
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;
size_t size = GetSize(process_sp);
DataBufferHeap buffer (size, '\0');
Error error;

View File

@ -193,7 +193,12 @@ AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
NULL);
m_external_source->SetMetadata((uintptr_t)new_iface_decl, (uint64_t)isa);
new_iface_decl->setHasExternalVisibleStorage();
static ConstString NSObject_name("NSObject");
if (name != NSObject_name)
new_iface_decl->setHasExternalVisibleStorage();
ast_ctx->getTranslationUnitDecl()->addDecl(new_iface_decl);
m_isa_to_interface[isa] = new_iface_decl;
@ -201,9 +206,291 @@ AppleObjCTypeVendor::GetDeclForISA(ObjCLanguageRuntime::ObjCISA isa)
return new_iface_decl;
}
class ObjCRuntimeMethodType
{
public:
ObjCRuntimeMethodType (const char *types) : m_is_valid(false)
{
const char *cursor = types;
enum ParserState {
Start = 0,
InType,
InPos
} state = Start;
const char *type = NULL;
int brace_depth = 0;
uint32_t stepsLeft = 256;
while (1)
{
if (--stepsLeft == 0)
{
m_is_valid = false;
return;
}
switch (state)
{
case Start:
{
switch (*cursor)
{
default:
state = InType;
type = cursor;
break;
case '\0':
m_is_valid = true;
return;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
m_is_valid = false;
return;
}
}
break;
case InType:
{
switch (*cursor)
{
default:
++cursor;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (!brace_depth)
{
state = InPos;
if (type)
{
m_type_vector.push_back(std::string(type, (cursor - type)));
}
else
{
m_is_valid = false;
return;
}
type = NULL;
}
else
{
++cursor;
}
break;
case '[': case '{': case '(':
++brace_depth;
++cursor;
break;
case ']': case '}': case ')':
if (!brace_depth)
{
m_is_valid = false;
return;
}
--brace_depth;
++cursor;
break;
case '\0':
m_is_valid = false;
return;
}
}
break;
case InPos:
{
switch (*cursor)
{
default:
state = InType;
type = cursor;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
++cursor;
break;
case '\0':
m_is_valid = true;
return;
}
}
break;
}
}
}
clang::ObjCMethodDecl *BuildMethod (clang::ObjCInterfaceDecl *interface_decl, const char *name)
{
lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
if (!m_is_valid || m_type_vector.size() < 3)
return NULL;
clang::ASTContext &ast_ctx(interface_decl->getASTContext());
clang::QualType return_qual_type;
const bool isInstance = true;
const bool isVariadic = false;
const bool isSynthesized = false;
const bool isImplicitlyDeclared = true;
const bool isDefined = false;
const clang::ObjCMethodDecl::ImplementationControl impControl = clang::ObjCMethodDecl::None;
const bool HasRelatedResultType = false;
std::vector <clang::IdentifierInfo *> selector_components;
const char *name_cursor = name;
bool is_zero_argument = true;
while (*name_cursor != '\0')
{
char *colon_loc = strchr(name_cursor, ':');
if (!colon_loc)
{
selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor)));
break;
}
else
{
is_zero_argument = true;
selector_components.push_back(&ast_ctx.Idents.get(llvm::StringRef(name_cursor, colon_loc - name_cursor)));
name_cursor = colon_loc + 1;
}
}
clang::Selector sel = ast_ctx.Selectors.getSelector(is_zero_argument ? 0 : selector_components.size(), selector_components.data());
clang::QualType ret_type = BuildType(ast_ctx, m_type_vector[0].c_str());
if (ret_type.isNull())
return NULL;
clang::ObjCMethodDecl *ret = clang::ObjCMethodDecl::Create(ast_ctx,
clang::SourceLocation(),
clang::SourceLocation(),
sel,
ret_type,
NULL,
interface_decl,
isInstance,
isVariadic,
isSynthesized,
isImplicitlyDeclared,
isDefined,
impControl,
HasRelatedResultType);
std::vector <clang::ParmVarDecl*> parm_vars;
for (size_t ai = 3, ae = m_type_vector.size();
ai != ae;
++ai)
{
clang::QualType arg_type = BuildType(ast_ctx, m_type_vector[ai].c_str());
if (arg_type.isNull())
return NULL; // well, we just wasted a bunch of time. Wish we could delete the stuff we'd just made!
parm_vars.push_back(clang::ParmVarDecl::Create(ast_ctx,
ret,
clang::SourceLocation(),
clang::SourceLocation(),
NULL,
arg_type,
NULL,
clang::SC_None,
clang::SC_None,
NULL));
}
ret->setMethodParams(ast_ctx, llvm::ArrayRef<clang::ParmVarDecl*>(parm_vars), llvm::ArrayRef<clang::SourceLocation>());
return ret;
}
private:
clang::QualType BuildType (clang::ASTContext &ast_ctx, const char *type)
{
if (!type)
return clang::QualType();
switch (*type)
{
default:
return ast_ctx.UnknownAnyTy;
case 'r':
{
clang::QualType target_type = BuildType(ast_ctx, type+1);
if (target_type.isNull())
return clang::QualType();
else
return ast_ctx.getConstType(target_type);
}
case '^':
{
clang::QualType target_type = BuildType(ast_ctx, type+1);
if (target_type.isNull())
return clang::QualType();
else
return ast_ctx.getPointerType(target_type);
}
case 'c':
return ast_ctx.CharTy;
case 'i':
return ast_ctx.IntTy;
case 's':
return ast_ctx.ShortTy;
case 'l':
if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
return ast_ctx.IntTy;
else
return ast_ctx.LongTy;
case 'q':
return ast_ctx.LongLongTy;
case 'C':
return ast_ctx.UnsignedCharTy;
case 'I':
return ast_ctx.UnsignedIntTy;
case 'S':
return ast_ctx.UnsignedShortTy;
case 'L':
if (ast_ctx.getTypeSize(ast_ctx.VoidTy) == 64)
return ast_ctx.UnsignedIntTy;
else
return ast_ctx.UnsignedLongTy;
case 'Q':
return ast_ctx.UnsignedLongLongTy;
case 'f':
return ast_ctx.FloatTy;
case 'd':
return ast_ctx.DoubleTy;
case 'B':
return ast_ctx.BoolTy;
case 'v':
return ast_ctx.VoidTy;
case '*':
return ast_ctx.getPointerType(ast_ctx.CharTy);
case '@':
return ast_ctx.getObjCIdType();
case '#':
return ast_ctx.getObjCClassType();
case ':':
return ast_ctx.getObjCSelType();
}
return clang::QualType();
}
typedef std::vector <std::string> TypeVector;
TypeVector m_type_vector;
bool m_is_valid;
};
bool
AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
{
lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); // FIXME - a more appropriate log channel?
ObjCLanguageRuntime::ObjCISA objc_isa = (ObjCLanguageRuntime::ObjCISA)m_external_source->GetMetadata((uintptr_t)interface_decl);
if (!objc_isa)
@ -214,6 +501,8 @@ AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
interface_decl->startDefinition();
interface_decl->setHasExternalVisibleStorage(false);
ObjCLanguageRuntime::ClassDescriptorSP descriptor = m_runtime.GetClassDescriptor(objc_isa);
if (!descriptor)
@ -227,15 +516,28 @@ AppleObjCTypeVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
interface_decl->setSuperClass(superclass_decl);
};
auto method_func = [interface_decl, this](const char *name, const char *types)
{
auto method_func = [log, interface_decl, this](const char *name, const char *types)
{
ObjCRuntimeMethodType method_type(types);
clang::ObjCMethodDecl *method_decl = method_type.BuildMethod (interface_decl, name);
if (method_decl)
interface_decl->addDecl(method_decl);
};
if (!descriptor->Describe(superclass_func, method_func))
return false;
interface_decl->setHasExternalVisibleStorage(false);
if (log)
{
ASTDumper method_dumper ((clang::Decl*)interface_decl);
log->Printf("[AppleObjCTypeVendor::FinishDecl] Finished Objective-C interface");
method_dumper.ToLog(log, " [AOTV::FD] ");
}
return true;
}