opnsense-src/include/lldb/Target/ObjCLanguageRuntime.h

522 lines
14 KiB
C++

//===-- 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 <functional>
#include <map>
#include <memory>
#include <unordered_set>
// Other libraries and framework includes
#include "llvm/Support/Casting.h"
// Project includes
#include "lldb/lldb-private.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/ThreadSafeDenseMap.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/DeclVendor.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/LanguageRuntime.h"
class CommandObjectObjC_ClassTable_Dump;
namespace lldb_private {
class UtilityFunction;
class ObjCLanguageRuntime :
public LanguageRuntime
{
public:
enum class ObjCRuntimeVersions
{
eObjC_VersionUnknown = 0,
eAppleObjC_V1 = 1,
eAppleObjC_V2 = 2
};
typedef lldb::addr_t ObjCISA;
class ClassDescriptor;
typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
// the information that we want to support retrieving from an ObjC class
// this needs to be pure virtual since there are at least 2 different implementations
// of the runtime, and more might come
class ClassDescriptor
{
public:
ClassDescriptor() :
m_is_kvo (eLazyBoolCalculate),
m_is_cf (eLazyBoolCalculate),
m_type_wp ()
{
}
virtual
~ClassDescriptor() = default;
virtual ConstString
GetClassName () = 0;
virtual ClassDescriptorSP
GetSuperclass () = 0;
virtual ClassDescriptorSP
GetMetaclass () const = 0;
// virtual if any implementation has some other version-specific rules
// but for the known v1/v2 this is all that needs to be done
virtual bool
IsKVO ()
{
if (m_is_kvo == eLazyBoolCalculate)
{
const char* class_name = GetClassName().AsCString();
if (class_name && *class_name)
m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name);
}
return (m_is_kvo == eLazyBoolYes);
}
// virtual if any implementation has some other version-specific rules
// but for the known v1/v2 this is all that needs to be done
virtual bool
IsCFType ()
{
if (m_is_cf == eLazyBoolCalculate)
{
const char* class_name = GetClassName().AsCString();
if (class_name && *class_name)
m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 ||
strcmp(class_name,"NSCFType") == 0);
}
return (m_is_cf == eLazyBoolYes);
}
virtual bool
IsValid () = 0;
virtual bool
GetTaggedPointerInfo(uint64_t* info_bits = nullptr,
uint64_t* value_bits = nullptr,
uint64_t* payload = nullptr) = 0;
virtual uint64_t
GetInstanceSize () = 0;
// use to implement version-specific additional constraints on pointers
virtual bool
CheckPointer (lldb::addr_t value,
uint32_t ptr_size) const
{
return true;
}
virtual ObjCISA
GetISA () = 0;
// This should return true iff the interface could be completed
virtual bool
Describe (std::function <void (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) const
{
return false;
}
lldb::TypeSP
GetType ()
{
return m_type_wp.lock();
}
void
SetType (const lldb::TypeSP &type_sp)
{
m_type_wp = type_sp;
}
struct iVarDescriptor {
ConstString m_name;
CompilerType m_type;
uint64_t m_size;
int32_t m_offset;
};
virtual size_t
GetNumIVars ()
{
return 0;
}
virtual iVarDescriptor
GetIVarAtIndex (size_t idx)
{
return iVarDescriptor();
}
protected:
bool
IsPointerValid (lldb::addr_t value,
uint32_t ptr_size,
bool allow_NULLs = false,
bool allow_tagged = false,
bool check_version_specific = false) const;
private:
LazyBool m_is_kvo;
LazyBool m_is_cf;
lldb::TypeWP m_type_wp;
};
class EncodingToType
{
public:
virtual ~EncodingToType();
virtual CompilerType RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression);
virtual CompilerType RealizeType (const char* name, bool for_expression);
virtual CompilerType RealizeType (clang::ASTContext& ast_ctx, const char* name, bool for_expression) = 0;
protected:
std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap;
};
class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition
{
public:
ObjCExceptionPrecondition();
~ObjCExceptionPrecondition() override = default;
bool EvaluatePrecondition(StoppointCallbackContext &context) override;
void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
Error ConfigurePrecondition(Args &args) override;
protected:
void AddClassName(const char *class_name);
private:
std::unordered_set<std::string> m_class_names;
};
class TaggedPointerVendor
{
public:
virtual
~TaggedPointerVendor() = default;
virtual bool
IsPossibleTaggedPointer (lldb::addr_t ptr) = 0;
virtual ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor (lldb::addr_t ptr) = 0;
protected:
TaggedPointerVendor() = default;
private:
DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor);
};
~ObjCLanguageRuntime() override;
virtual TaggedPointerVendor*
GetTaggedPointerVendor ()
{
return nullptr;
}
typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
virtual EncodingToTypeSP
GetEncodingToType ();
virtual ClassDescriptorSP
GetClassDescriptor (ValueObject& in_value);
ClassDescriptorSP
GetNonKVOClassDescriptor (ValueObject& in_value);
virtual ClassDescriptorSP
GetClassDescriptorFromClassName (const ConstString &class_name);
virtual ClassDescriptorSP
GetClassDescriptorFromISA (ObjCISA isa);
ClassDescriptorSP
GetNonKVOClassDescriptor (ObjCISA isa);
lldb::LanguageType
GetLanguageType () const override
{
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 UtilityFunction *
CreateObjectChecker (const char *) = 0;
virtual ObjCRuntimeVersions
GetRuntimeVersion () const
{
return ObjCRuntimeVersions::eObjC_VersionUnknown;
}
bool
IsValidISA(ObjCISA isa)
{
UpdateISAToDescriptorMap();
return m_isa_to_descriptor.count(isa) > 0;
}
virtual void
UpdateISAToDescriptorMapIfNeeded() = 0;
void
UpdateISAToDescriptorMap()
{
if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id)
{
UpdateISAToDescriptorMapIfNeeded ();
}
}
virtual ObjCISA
GetISA(const ConstString &name);
virtual ConstString
GetActualTypeName(ObjCISA isa);
virtual ObjCISA
GetParentClass(ObjCISA isa);
virtual DeclVendor *
GetDeclVendor()
{
return nullptr;
}
// 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 (CompilerType &parent_qual_type, const char *ivar_name);
// Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol),
// try to determine from the runtime what the value of that symbol would be.
// Useful when the underlying binary is stripped.
virtual lldb::addr_t
LookupRuntimeSymbol (const ConstString &name)
{
return LLDB_INVALID_ADDRESS;
}
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);
}
virtual void
SymbolsDidLoad (const ModuleList& module_list)
{
m_negative_complete_class_cache.clear();
}
bool
GetTypeBitSize (const CompilerType& compiler_type,
uint64_t &size) override;
protected:
//------------------------------------------------------------------
// Classes that inherit from ObjCLanguageRuntime can see and modify these
//------------------------------------------------------------------
ObjCLanguageRuntime(Process *process);
virtual bool CalculateHasNewLiteralsAndIndexing()
{
return false;
}
bool
ISAIsCached (ObjCISA isa) const
{
return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
}
bool
AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
{
if (isa != 0)
{
m_isa_to_descriptor[isa] = descriptor_sp;
return true;
}
return false;
}
bool
AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name);
bool
AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
{
if (isa != 0)
{
m_isa_to_descriptor[isa] = descriptor_sp;
m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
return true;
}
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;
typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
typedef HashToISAMap::iterator HashToISAIterator;
typedef ThreadSafeDenseMap<void*, uint64_t> TypeSizeCache;
MsgImplMap m_impl_cache;
LazyBool m_has_new_literals_and_indexing;
ISAToDescriptorMap m_isa_to_descriptor;
HashToISAMap m_hash_to_isa_map;
TypeSizeCache m_type_size_cache;
protected:
uint32_t m_isa_to_descriptor_stop_id;
typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
CompleteClassMap m_complete_class_cache;
struct ConstStringSetHelpers {
size_t operator () (const ConstString& arg) const // for hashing
{
return (size_t)arg.GetCString();
}
bool operator () (const ConstString& arg1, const ConstString& arg2) const // for equality
{
return arg1.operator==(arg2);
}
};
typedef std::unordered_set<ConstString, ConstStringSetHelpers, ConstStringSetHelpers> CompleteClassSet;
CompleteClassSet m_negative_complete_class_cache;
ISAToDescriptorIterator
GetDescriptorIterator (const ConstString &name);
friend class ::CommandObjectObjC_ClassTable_Dump;
std::pair<ISAToDescriptorIterator,ISAToDescriptorIterator>
GetDescriptorIteratorPair (bool update_if_needed = true);
void
ReadObjCLibraryIfNeeded (const ModuleList &module_list);
DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
};
} // namespace lldb_private
#endif // liblldb_ObjCLanguageRuntime_h_