forked from OSchip/llvm-project
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:
parent
dd09c34351
commit
2885a7088d
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue