1351290Sdim//===-- ObjCLanguageRuntime.h -----------------------------------*- C++ -*-===// 2351290Sdim// 3351290Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4351290Sdim// See https://llvm.org/LICENSE.txt for license information. 5351290Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6351290Sdim// 7351290Sdim//===----------------------------------------------------------------------===// 8351290Sdim 9351290Sdim#ifndef liblldb_ObjCLanguageRuntime_h_ 10351290Sdim#define liblldb_ObjCLanguageRuntime_h_ 11351290Sdim 12351290Sdim#include <functional> 13351290Sdim#include <map> 14351290Sdim#include <memory> 15351290Sdim#include <unordered_set> 16351290Sdim 17351290Sdim#include "llvm/Support/Casting.h" 18351290Sdim 19351290Sdim#include "lldb/Breakpoint/BreakpointPrecondition.h" 20360784Sdim#include "lldb/Core/ClangForward.h" 21351290Sdim#include "lldb/Core/PluginInterface.h" 22351290Sdim#include "lldb/Core/ThreadSafeDenseMap.h" 23351290Sdim#include "lldb/Symbol/CompilerType.h" 24351290Sdim#include "lldb/Symbol/Type.h" 25351290Sdim#include "lldb/Target/LanguageRuntime.h" 26351290Sdim#include "lldb/lldb-private.h" 27351290Sdim 28351290Sdimclass CommandObjectObjC_ClassTable_Dump; 29351290Sdim 30351290Sdimnamespace lldb_private { 31351290Sdim 32351290Sdimclass UtilityFunction; 33351290Sdim 34351290Sdimclass ObjCLanguageRuntime : public LanguageRuntime { 35351290Sdimpublic: 36351290Sdim enum class ObjCRuntimeVersions { 37351290Sdim eObjC_VersionUnknown = 0, 38351290Sdim eAppleObjC_V1 = 1, 39351290Sdim eAppleObjC_V2 = 2 40351290Sdim }; 41351290Sdim 42351290Sdim typedef lldb::addr_t ObjCISA; 43351290Sdim 44351290Sdim class ClassDescriptor; 45351290Sdim typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP; 46351290Sdim 47351290Sdim // the information that we want to support retrieving from an ObjC class this 48351290Sdim // needs to be pure virtual since there are at least 2 different 49351290Sdim // implementations of the runtime, and more might come 50351290Sdim class ClassDescriptor { 51351290Sdim public: 52351290Sdim ClassDescriptor() 53351290Sdim : m_is_kvo(eLazyBoolCalculate), m_is_cf(eLazyBoolCalculate), 54351290Sdim m_type_wp() {} 55351290Sdim 56351290Sdim virtual ~ClassDescriptor() = default; 57351290Sdim 58351290Sdim virtual ConstString GetClassName() = 0; 59351290Sdim 60351290Sdim virtual ClassDescriptorSP GetSuperclass() = 0; 61351290Sdim 62351290Sdim virtual ClassDescriptorSP GetMetaclass() const = 0; 63351290Sdim 64351290Sdim // virtual if any implementation has some other version-specific rules but 65351290Sdim // for the known v1/v2 this is all that needs to be done 66351290Sdim virtual bool IsKVO() { 67351290Sdim if (m_is_kvo == eLazyBoolCalculate) { 68351290Sdim const char *class_name = GetClassName().AsCString(); 69351290Sdim if (class_name && *class_name) 70351290Sdim m_is_kvo = 71351290Sdim (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name); 72351290Sdim } 73351290Sdim return (m_is_kvo == eLazyBoolYes); 74351290Sdim } 75351290Sdim 76351290Sdim // virtual if any implementation has some other version-specific rules but 77351290Sdim // for the known v1/v2 this is all that needs to be done 78351290Sdim virtual bool IsCFType() { 79351290Sdim if (m_is_cf == eLazyBoolCalculate) { 80351290Sdim const char *class_name = GetClassName().AsCString(); 81351290Sdim if (class_name && *class_name) 82351290Sdim m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 || 83351290Sdim strcmp(class_name, "NSCFType") == 0); 84351290Sdim } 85351290Sdim return (m_is_cf == eLazyBoolYes); 86351290Sdim } 87351290Sdim 88351290Sdim virtual bool IsValid() = 0; 89351290Sdim 90351290Sdim virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 91351290Sdim uint64_t *value_bits = nullptr, 92351290Sdim uint64_t *payload = nullptr) = 0; 93351290Sdim 94351290Sdim virtual uint64_t GetInstanceSize() = 0; 95351290Sdim 96351290Sdim // use to implement version-specific additional constraints on pointers 97351290Sdim virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const { 98351290Sdim return true; 99351290Sdim } 100351290Sdim 101351290Sdim virtual ObjCISA GetISA() = 0; 102351290Sdim 103351290Sdim // This should return true iff the interface could be completed 104351290Sdim virtual bool 105351290Sdim Describe(std::function<void(ObjCISA)> const &superclass_func, 106351290Sdim std::function<bool(const char *, const char *)> const 107351290Sdim &instance_method_func, 108351290Sdim std::function<bool(const char *, const char *)> const 109351290Sdim &class_method_func, 110351290Sdim std::function<bool(const char *, const char *, lldb::addr_t, 111351290Sdim uint64_t)> const &ivar_func) const { 112351290Sdim return false; 113351290Sdim } 114351290Sdim 115351290Sdim lldb::TypeSP GetType() { return m_type_wp.lock(); } 116351290Sdim 117351290Sdim void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; } 118351290Sdim 119351290Sdim struct iVarDescriptor { 120351290Sdim ConstString m_name; 121351290Sdim CompilerType m_type; 122351290Sdim uint64_t m_size; 123351290Sdim int32_t m_offset; 124351290Sdim }; 125351290Sdim 126351290Sdim virtual size_t GetNumIVars() { return 0; } 127351290Sdim 128351290Sdim virtual iVarDescriptor GetIVarAtIndex(size_t idx) { 129351290Sdim return iVarDescriptor(); 130351290Sdim } 131351290Sdim 132351290Sdim protected: 133351290Sdim bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size, 134351290Sdim bool allow_NULLs = false, bool allow_tagged = false, 135351290Sdim bool check_version_specific = false) const; 136351290Sdim 137351290Sdim private: 138351290Sdim LazyBool m_is_kvo; 139351290Sdim LazyBool m_is_cf; 140351290Sdim lldb::TypeWP m_type_wp; 141351290Sdim }; 142351290Sdim 143351290Sdim class EncodingToType { 144351290Sdim public: 145351290Sdim virtual ~EncodingToType(); 146351290Sdim 147351290Sdim virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name, 148360784Sdim bool for_expression) = 0; 149351290Sdim virtual CompilerType RealizeType(const char *name, bool for_expression); 150351290Sdim 151351290Sdim protected: 152351290Sdim std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_up; 153351290Sdim }; 154351290Sdim 155351290Sdim class ObjCExceptionPrecondition : public BreakpointPrecondition { 156351290Sdim public: 157351290Sdim ObjCExceptionPrecondition(); 158351290Sdim 159351290Sdim ~ObjCExceptionPrecondition() override = default; 160351290Sdim 161351290Sdim bool EvaluatePrecondition(StoppointCallbackContext &context) override; 162351290Sdim void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; 163351290Sdim Status ConfigurePrecondition(Args &args) override; 164351290Sdim 165351290Sdim protected: 166351290Sdim void AddClassName(const char *class_name); 167351290Sdim 168351290Sdim private: 169351290Sdim std::unordered_set<std::string> m_class_names; 170351290Sdim }; 171351290Sdim 172351290Sdim static lldb::BreakpointPreconditionSP 173351290Sdim GetBreakpointExceptionPrecondition(lldb::LanguageType language, 174351290Sdim bool throw_bp); 175351290Sdim 176351290Sdim class TaggedPointerVendor { 177351290Sdim public: 178351290Sdim virtual ~TaggedPointerVendor() = default; 179351290Sdim 180351290Sdim virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0; 181351290Sdim 182351290Sdim virtual ObjCLanguageRuntime::ClassDescriptorSP 183351290Sdim GetClassDescriptor(lldb::addr_t ptr) = 0; 184351290Sdim 185351290Sdim protected: 186351290Sdim TaggedPointerVendor() = default; 187351290Sdim 188351290Sdim private: 189351290Sdim DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor); 190351290Sdim }; 191351290Sdim 192351290Sdim ~ObjCLanguageRuntime() override; 193351290Sdim 194351290Sdim static char ID; 195351290Sdim 196351290Sdim bool isA(const void *ClassID) const override { 197351290Sdim return ClassID == &ID || LanguageRuntime::isA(ClassID); 198351290Sdim } 199351290Sdim 200351290Sdim static bool classof(const LanguageRuntime *runtime) { 201351290Sdim return runtime->isA(&ID); 202351290Sdim } 203351290Sdim 204351290Sdim static ObjCLanguageRuntime *Get(Process &process) { 205351290Sdim return llvm::cast_or_null<ObjCLanguageRuntime>( 206351290Sdim process.GetLanguageRuntime(lldb::eLanguageTypeObjC)); 207351290Sdim } 208351290Sdim 209351290Sdim virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; } 210351290Sdim 211351290Sdim typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; 212351290Sdim 213351290Sdim virtual EncodingToTypeSP GetEncodingToType(); 214351290Sdim 215351290Sdim virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value); 216351290Sdim 217351290Sdim ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value); 218351290Sdim 219351290Sdim virtual ClassDescriptorSP 220351290Sdim GetClassDescriptorFromClassName(ConstString class_name); 221351290Sdim 222351290Sdim virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa); 223351290Sdim 224351290Sdim ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa); 225351290Sdim 226351290Sdim lldb::LanguageType GetLanguageType() const override { 227351290Sdim return lldb::eLanguageTypeObjC; 228351290Sdim } 229351290Sdim 230351290Sdim virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 231351290Sdim 232351290Sdim virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 233351290Sdim 234351290Sdim virtual bool HasReadObjCLibrary() = 0; 235351290Sdim 236351290Sdim lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel); 237351290Sdim 238351290Sdim void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, 239351290Sdim lldb::addr_t impl_addr); 240351290Sdim 241351290Sdim TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr); 242351290Sdim 243351290Sdim void AddToClassNameCache(lldb::addr_t class_addr, const char *name, 244351290Sdim lldb::TypeSP type_sp); 245351290Sdim 246351290Sdim void AddToClassNameCache(lldb::addr_t class_addr, 247351290Sdim const TypeAndOrName &class_or_type_name); 248351290Sdim 249351290Sdim lldb::TypeSP LookupInCompleteClassCache(ConstString &name); 250351290Sdim 251351290Sdim llvm::Optional<CompilerType> GetRuntimeType(CompilerType base_type) override; 252351290Sdim 253351290Sdim virtual UtilityFunction *CreateObjectChecker(const char *) = 0; 254351290Sdim 255351290Sdim virtual ObjCRuntimeVersions GetRuntimeVersion() const { 256351290Sdim return ObjCRuntimeVersions::eObjC_VersionUnknown; 257351290Sdim } 258351290Sdim 259351290Sdim bool IsValidISA(ObjCISA isa) { 260351290Sdim UpdateISAToDescriptorMap(); 261351290Sdim return m_isa_to_descriptor.count(isa) > 0; 262351290Sdim } 263351290Sdim 264351290Sdim virtual void UpdateISAToDescriptorMapIfNeeded() = 0; 265351290Sdim 266351290Sdim void UpdateISAToDescriptorMap() { 267351290Sdim if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) { 268351290Sdim UpdateISAToDescriptorMapIfNeeded(); 269351290Sdim } 270351290Sdim } 271351290Sdim 272351290Sdim virtual ObjCISA GetISA(ConstString name); 273351290Sdim 274351290Sdim virtual ObjCISA GetParentClass(ObjCISA isa); 275351290Sdim 276351290Sdim // Finds the byte offset of the child_type ivar in parent_type. If it can't 277351290Sdim // find the offset, returns LLDB_INVALID_IVAR_OFFSET. 278351290Sdim 279351290Sdim virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 280351290Sdim const char *ivar_name); 281351290Sdim 282351290Sdim bool HasNewLiteralsAndIndexing() { 283351290Sdim if (m_has_new_literals_and_indexing == eLazyBoolCalculate) { 284351290Sdim if (CalculateHasNewLiteralsAndIndexing()) 285351290Sdim m_has_new_literals_and_indexing = eLazyBoolYes; 286351290Sdim else 287351290Sdim m_has_new_literals_and_indexing = eLazyBoolNo; 288351290Sdim } 289351290Sdim 290351290Sdim return (m_has_new_literals_and_indexing == eLazyBoolYes); 291351290Sdim } 292351290Sdim 293351290Sdim void SymbolsDidLoad(const ModuleList &module_list) override { 294351290Sdim m_negative_complete_class_cache.clear(); 295351290Sdim } 296351290Sdim 297351290Sdim bool GetTypeBitSize(const CompilerType &compiler_type, 298351290Sdim uint64_t &size) override; 299351290Sdim 300351290Sdim /// Check whether the name is "self" or "_cmd" and should show up in 301351290Sdim /// "frame variable". 302351290Sdim bool IsWhitelistedRuntimeValue(ConstString name) override; 303351290Sdim 304351290Sdimprotected: 305351290Sdim // Classes that inherit from ObjCLanguageRuntime can see and modify these 306351290Sdim ObjCLanguageRuntime(Process *process); 307351290Sdim 308351290Sdim virtual bool CalculateHasNewLiteralsAndIndexing() { return false; } 309351290Sdim 310351290Sdim bool ISAIsCached(ObjCISA isa) const { 311351290Sdim return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); 312351290Sdim } 313351290Sdim 314351290Sdim bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) { 315351290Sdim if (isa != 0) { 316351290Sdim m_isa_to_descriptor[isa] = descriptor_sp; 317351290Sdim return true; 318351290Sdim } 319351290Sdim return false; 320351290Sdim } 321351290Sdim 322351290Sdim bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 323351290Sdim const char *class_name); 324351290Sdim 325351290Sdim bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 326351290Sdim uint32_t class_name_hash) { 327351290Sdim if (isa != 0) { 328351290Sdim m_isa_to_descriptor[isa] = descriptor_sp; 329351290Sdim m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); 330351290Sdim return true; 331351290Sdim } 332351290Sdim return false; 333351290Sdim } 334351290Sdim 335351290Sdimprivate: 336351290Sdim // We keep a map of <Class,Selector>->Implementation so we don't have to call 337351290Sdim // the resolver function over and over. 338351290Sdim 339351290Sdim // FIXME: We need to watch for the loading of Protocols, and flush the cache 340351290Sdim // for any 341351290Sdim // class that we see so changed. 342351290Sdim 343351290Sdim struct ClassAndSel { 344351290Sdim ClassAndSel() { 345351290Sdim sel_addr = LLDB_INVALID_ADDRESS; 346351290Sdim class_addr = LLDB_INVALID_ADDRESS; 347351290Sdim } 348351290Sdim 349351290Sdim ClassAndSel(lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) 350351290Sdim : class_addr(in_class_addr), sel_addr(in_sel_addr) {} 351351290Sdim 352351290Sdim bool operator==(const ClassAndSel &rhs) { 353351290Sdim if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr) 354351290Sdim return true; 355351290Sdim else 356351290Sdim return false; 357351290Sdim } 358351290Sdim 359351290Sdim bool operator<(const ClassAndSel &rhs) const { 360351290Sdim if (class_addr < rhs.class_addr) 361351290Sdim return true; 362351290Sdim else if (class_addr > rhs.class_addr) 363351290Sdim return false; 364351290Sdim else { 365351290Sdim if (sel_addr < rhs.sel_addr) 366351290Sdim return true; 367351290Sdim else 368351290Sdim return false; 369351290Sdim } 370351290Sdim } 371351290Sdim 372351290Sdim lldb::addr_t class_addr; 373351290Sdim lldb::addr_t sel_addr; 374351290Sdim }; 375351290Sdim 376351290Sdim typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap; 377351290Sdim typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; 378351290Sdim typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; 379351290Sdim typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; 380351290Sdim typedef HashToISAMap::iterator HashToISAIterator; 381351290Sdim typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache; 382351290Sdim 383351290Sdim MsgImplMap m_impl_cache; 384351290Sdim LazyBool m_has_new_literals_and_indexing; 385351290Sdim ISAToDescriptorMap m_isa_to_descriptor; 386351290Sdim HashToISAMap m_hash_to_isa_map; 387351290Sdim TypeSizeCache m_type_size_cache; 388351290Sdim 389351290Sdimprotected: 390351290Sdim uint32_t m_isa_to_descriptor_stop_id; 391351290Sdim 392351290Sdim typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; 393351290Sdim CompleteClassMap m_complete_class_cache; 394351290Sdim 395351290Sdim struct ConstStringSetHelpers { 396351290Sdim size_t operator()(ConstString arg) const // for hashing 397351290Sdim { 398351290Sdim return (size_t)arg.GetCString(); 399351290Sdim } 400351290Sdim bool operator()(ConstString arg1, 401351290Sdim ConstString arg2) const // for equality 402351290Sdim { 403351290Sdim return arg1.operator==(arg2); 404351290Sdim } 405351290Sdim }; 406351290Sdim typedef std::unordered_set<ConstString, ConstStringSetHelpers, 407351290Sdim ConstStringSetHelpers> 408351290Sdim CompleteClassSet; 409351290Sdim CompleteClassSet m_negative_complete_class_cache; 410351290Sdim 411351290Sdim ISAToDescriptorIterator GetDescriptorIterator(ConstString name); 412351290Sdim 413351290Sdim friend class ::CommandObjectObjC_ClassTable_Dump; 414351290Sdim 415351290Sdim std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator> 416351290Sdim GetDescriptorIteratorPair(bool update_if_needed = true); 417351290Sdim 418351290Sdim void ReadObjCLibraryIfNeeded(const ModuleList &module_list); 419351290Sdim 420351290Sdim DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime); 421351290Sdim}; 422351290Sdim 423351290Sdim} // namespace lldb_private 424351290Sdim 425351290Sdim#endif // liblldb_ObjCLanguageRuntime_h_ 426