//===-- AppleObjCRuntimeV2.h ------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef liblldb_AppleObjCRuntimeV2_h_ #define liblldb_AppleObjCRuntimeV2_h_ #include #include #include #include "AppleObjCRuntime.h" #include "lldb/lldb-private.h" #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" class RemoteNXMapTable; namespace lldb_private { class AppleObjCRuntimeV2 : public AppleObjCRuntime { public: ~AppleObjCRuntimeV2() override = default; // Static Functions static void Initialize(); static void Terminate(); static lldb_private::LanguageRuntime * CreateInstance(Process *process, lldb::LanguageType language); static lldb_private::ConstString GetPluginNameStatic(); static char ID; bool isA(const void *ClassID) const override { return ClassID == &ID || AppleObjCRuntime::isA(ClassID); } static bool classof(const LanguageRuntime *runtime) { return runtime->isA(&ID); } // These are generic runtime functions: bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type) override; UtilityFunction *CreateObjectChecker(const char *) override; // PluginInterface protocol ConstString GetPluginName() override; uint32_t GetPluginVersion() override; ObjCRuntimeVersions GetRuntimeVersion() const override { return ObjCRuntimeVersions::eAppleObjC_V2; } size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, const char *ivar_name) override; void UpdateISAToDescriptorMapIfNeeded() override; ConstString GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) override; ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; DeclVendor *GetDeclVendor() override; lldb::addr_t LookupRuntimeSymbol(ConstString name) override; EncodingToTypeSP GetEncodingToType() override; bool IsTaggedPointer(lldb::addr_t ptr) override; TaggedPointerVendor *GetTaggedPointerVendor() override { return m_tagged_pointer_vendor_up.get(); } lldb::addr_t GetTaggedPointerObfuscator(); void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, lldb::addr_t &cf_false) override; // none of these are valid ISAs - we use them to infer the type // of tagged pointers - if we have something meaningful to say // we report an actual type - otherwise, we just say tagged // there is no connection between the values here and the tagged pointers map static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 5; static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; protected: lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override; private: class HashTableSignature { public: HashTableSignature(); bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table); void UpdateSignature(const RemoteNXMapTable &hash_table); protected: uint32_t m_count; uint32_t m_num_buckets; lldb::addr_t m_buckets_ptr; }; class NonPointerISACache { public: static NonPointerISACache * CreateInstance(AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp); ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa); private: NonPointerISACache(AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp, uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask, uint64_t objc_debug_isa_magic_value, uint64_t objc_debug_indexed_isa_magic_mask, uint64_t objc_debug_indexed_isa_magic_value, uint64_t objc_debug_indexed_isa_index_mask, uint64_t objc_debug_indexed_isa_index_shift, lldb::addr_t objc_indexed_classes); bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa); AppleObjCRuntimeV2 &m_runtime; std::map m_cache; lldb::ModuleWP m_objc_module_wp; uint64_t m_objc_debug_isa_class_mask; uint64_t m_objc_debug_isa_magic_mask; uint64_t m_objc_debug_isa_magic_value; uint64_t m_objc_debug_indexed_isa_magic_mask; uint64_t m_objc_debug_indexed_isa_magic_value; uint64_t m_objc_debug_indexed_isa_index_mask; uint64_t m_objc_debug_indexed_isa_index_shift; lldb::addr_t m_objc_indexed_classes; std::vector m_indexed_isa_cache; friend class AppleObjCRuntimeV2; DISALLOW_COPY_AND_ASSIGN(NonPointerISACache); }; class TaggedPointerVendorV2 : public ObjCLanguageRuntime::TaggedPointerVendor { public: ~TaggedPointerVendorV2() override = default; static TaggedPointerVendorV2 * CreateInstance(AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp); protected: AppleObjCRuntimeV2 &m_runtime; TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime) : TaggedPointerVendor(), m_runtime(runtime) {} private: DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorV2); }; class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { public: bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(lldb::addr_t ptr) override; protected: TaggedPointerVendorRuntimeAssisted( AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, uint32_t objc_debug_taggedpointer_slot_shift, uint32_t objc_debug_taggedpointer_slot_mask, uint32_t objc_debug_taggedpointer_payload_lshift, uint32_t objc_debug_taggedpointer_payload_rshift, lldb::addr_t objc_debug_taggedpointer_classes); typedef std::map Cache; typedef Cache::iterator CacheIterator; Cache m_cache; uint64_t m_objc_debug_taggedpointer_mask; uint32_t m_objc_debug_taggedpointer_slot_shift; uint32_t m_objc_debug_taggedpointer_slot_mask; uint32_t m_objc_debug_taggedpointer_payload_lshift; uint32_t m_objc_debug_taggedpointer_payload_rshift; lldb::addr_t m_objc_debug_taggedpointer_classes; friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted); }; class TaggedPointerVendorExtended : public TaggedPointerVendorRuntimeAssisted { public: ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(lldb::addr_t ptr) override; protected: TaggedPointerVendorExtended( AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, uint64_t objc_debug_taggedpointer_ext_mask, uint32_t objc_debug_taggedpointer_slot_shift, uint32_t objc_debug_taggedpointer_ext_slot_shift, uint32_t objc_debug_taggedpointer_slot_mask, uint32_t objc_debug_taggedpointer_ext_slot_mask, uint32_t objc_debug_taggedpointer_payload_lshift, uint32_t objc_debug_taggedpointer_payload_rshift, uint32_t objc_debug_taggedpointer_ext_payload_lshift, uint32_t objc_debug_taggedpointer_ext_payload_rshift, lldb::addr_t objc_debug_taggedpointer_classes, lldb::addr_t objc_debug_taggedpointer_ext_classes); bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr); typedef std::map Cache; typedef Cache::iterator CacheIterator; Cache m_ext_cache; uint64_t m_objc_debug_taggedpointer_ext_mask; uint32_t m_objc_debug_taggedpointer_ext_slot_shift; uint32_t m_objc_debug_taggedpointer_ext_slot_mask; uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; lldb::addr_t m_objc_debug_taggedpointer_ext_classes; friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorExtended); }; class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { public: bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(lldb::addr_t ptr) override; protected: TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime) : TaggedPointerVendorV2(runtime) {} friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy); }; struct DescriptorMapUpdateResult { bool m_update_ran; uint32_t m_num_found; DescriptorMapUpdateResult(bool ran, uint32_t found) { m_update_ran = ran; m_num_found = found; } static DescriptorMapUpdateResult Fail() { return {false, 0}; } static DescriptorMapUpdateResult Success(uint32_t found) { return {true, found}; } }; AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); ObjCISA GetPointerISA(ObjCISA isa); lldb::addr_t GetISAHashTablePointer(); bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table); DescriptorMapUpdateResult UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, uint32_t num_class_infos); DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache(); enum class SharedCacheWarningReason { eExpressionExecutionFailure, eNotEnoughClassesRead }; void WarnIfNoClassesCached(SharedCacheWarningReason reason); lldb::addr_t GetSharedCacheReadOnlyAddress(); bool GetCFBooleanValuesIfNeeded(); friend class ClassDescriptorV2; std::unique_ptr m_get_class_info_code; lldb::addr_t m_get_class_info_args; std::mutex m_get_class_info_args_mutex; std::unique_ptr m_get_shared_cache_class_info_code; lldb::addr_t m_get_shared_cache_class_info_args; std::mutex m_get_shared_cache_class_info_args_mutex; std::unique_ptr m_decl_vendor_up; lldb::addr_t m_tagged_pointer_obfuscator; lldb::addr_t m_isa_hash_table_ptr; HashTableSignature m_hash_signature; bool m_has_object_getClass; bool m_loaded_objc_opt; std::unique_ptr m_non_pointer_isa_cache_up; std::unique_ptr m_tagged_pointer_vendor_up; EncodingToTypeSP m_encoding_to_type_sp; bool m_noclasses_warning_emitted; llvm::Optional> m_CFBoolean_values; }; } // namespace lldb_private #endif // liblldb_AppleObjCRuntimeV2_h_