blob: ec921525c70396c1d5314fed81a0e03d1b72ce58 [file] [log] [blame]
//===-- ObjCLanguageRuntime.h ---------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef liblldb_ObjCLanguageRuntime_h_
#define liblldb_ObjCLanguageRuntime_h_
// C Includes
// C++ Includes
#include <map>
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/LanguageRuntime.h"
namespace lldb_private {
class ClangUtilityFunction;
class ObjCLanguageRuntime :
public LanguageRuntime
{
public:
virtual
~ObjCLanguageRuntime();
virtual lldb::LanguageType
GetLanguageType () const
{
return lldb::eLanguageTypeObjC;
}
virtual bool
IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
virtual bool
ReadObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
virtual bool
HasReadObjCLibrary () = 0;
virtual lldb::ThreadPlanSP
GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
lldb::addr_t
LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel);
void
AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
TypeAndOrName
LookupInClassNameCache (lldb::addr_t class_addr);
void
AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp);
void
AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
lldb::TypeSP
LookupInCompleteClassCache (ConstString &name);
virtual ClangUtilityFunction *
CreateObjectChecker (const char *) = 0;
virtual ObjCRuntimeVersions
GetRuntimeVersion ()
{
return eObjC_VersionUnknown;
}
typedef lldb::addr_t ObjCISA;
virtual bool
IsValidISA(ObjCISA isa) = 0;
virtual ObjCISA
GetISA(ValueObject& valobj) = 0;
virtual ConstString
GetActualTypeName(ObjCISA isa) = 0;
virtual ObjCISA
GetParentClass(ObjCISA isa) = 0;
virtual SymbolVendor *
GetSymbolVendor()
{
return NULL;
}
// Finds the byte offset of the child_type ivar in parent_type. If it can't find the
// offset, returns LLDB_INVALID_IVAR_OFFSET.
virtual size_t
GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name);
//------------------------------------------------------------------
/// Chop up an objective C function prototype.
///
/// Chop up an objective C function fullname and optionally fill in
/// any non-NULL ConstString objects. If a ConstString * is NULL,
/// then this name doesn't get filled in
///
/// @param[in] name
/// A fully specified objective C function name. The string might
/// contain a category and it includes the leading "+" or "-" and
/// the square brackets, no types for the arguments, just the plain
/// selector. A few examples:
/// "-[NSStringDrawingContext init]"
/// "-[NSStringDrawingContext addString:inRect:]"
/// "-[NSString(NSStringDrawing) sizeWithAttributes:]"
/// "+[NSString(NSStringDrawing) usesFontLeading]"
///
/// @param[out] class_name
/// If non-NULL, this string will be filled in with the class
/// name including the category. The examples above would return:
/// "NSStringDrawingContext"
/// "NSStringDrawingContext"
/// "NSString(NSStringDrawing)"
/// "NSString(NSStringDrawing)"
///
/// @param[out] selector_name
/// If non-NULL, this string will be filled in with the selector
/// name. The examples above would return:
/// "init"
/// "addString:inRect:"
/// "sizeWithAttributes:"
/// "usesFontLeading"
///
/// @param[out] name_sans_category
/// If non-NULL, this string will be filled in with the class
/// name _without_ the category. If there is no category, and empty
/// string will be returned (as the result would be normally returned
/// in the "class_name" argument). The examples above would return:
/// <empty>
/// <empty>
/// "-[NSString sizeWithAttributes:]"
/// "+[NSString usesFontLeading]"
///
/// @param[out] class_name_sans_category
/// If non-NULL, this string will be filled in with the prototype
/// name _without_ the category. If there is no category, and empty
/// string will be returned (as this is already the value that was
/// passed in). The examples above would return:
/// <empty>
/// <empty>
/// "NSString"
/// "NSString"
///
/// @return
/// Returns the number of strings that were successfully filled
/// in.
//------------------------------------------------------------------
static uint32_t
ParseMethodName (const char *name,
ConstString *class_name, // Class name (with category if there is one)
ConstString *selector_name, // selector only
ConstString *name_sans_category, // full function name with no category (empty if no category)
ConstString *class_name_sans_category);// Class name without category (empty if no category)
static bool
IsPossibleObjCMethodName (const char *name)
{
if (!name)
return false;
bool starts_right = (name[0] == '+' || name[0] == '-') && name[1] == '[';
bool ends_right = (name[strlen(name) - 1] == ']');
return (starts_right && ends_right);
}
static bool
IsPossibleObjCSelector (const char *name)
{
if (!name)
return false;
if (strchr(name, ':') == NULL)
return true;
else if (name[strlen(name) - 1] == ':')
return true;
else
return false;
}
bool
HasNewLiteralsAndIndexing ()
{
if (m_has_new_literals_and_indexing == eLazyBoolCalculate)
{
if (CalculateHasNewLiteralsAndIndexing())
m_has_new_literals_and_indexing = eLazyBoolYes;
else
m_has_new_literals_and_indexing = eLazyBoolNo;
}
return (m_has_new_literals_and_indexing == eLazyBoolYes);
}
protected:
//------------------------------------------------------------------
// Classes that inherit from ObjCLanguageRuntime can see and modify these
//------------------------------------------------------------------
ObjCLanguageRuntime(Process *process);
virtual bool CalculateHasNewLiteralsAndIndexing()
{
return false;
}
private:
// We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
// function over and over.
// FIXME: We need to watch for the loading of Protocols, and flush the cache for any
// class that we see so changed.
struct ClassAndSel
{
ClassAndSel()
{
sel_addr = LLDB_INVALID_ADDRESS;
class_addr = LLDB_INVALID_ADDRESS;
}
ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) :
class_addr (in_class_addr),
sel_addr(in_sel_addr)
{
}
bool operator== (const ClassAndSel &rhs)
{
if (class_addr == rhs.class_addr
&& sel_addr == rhs.sel_addr)
return true;
else
return false;
}
bool operator< (const ClassAndSel &rhs) const
{
if (class_addr < rhs.class_addr)
return true;
else if (class_addr > rhs.class_addr)
return false;
else
{
if (sel_addr < rhs.sel_addr)
return true;
else
return false;
}
}
lldb::addr_t class_addr;
lldb::addr_t sel_addr;
};
typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
MsgImplMap m_impl_cache;
LazyBool m_has_new_literals_and_indexing;
protected:
typedef std::map<lldb::addr_t,TypeAndOrName> ClassNameMap;
typedef ClassNameMap::iterator ClassNameIterator;
ClassNameMap m_class_name_cache;
typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
CompleteClassMap m_complete_class_cache;
DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
};
} // namespace lldb_private
#endif // liblldb_ObjCLanguageRuntime_h_