1 //===-- AppleObjCRuntimeV2.h ------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 11 12 #include <map> 13 #include <memory> 14 #include <mutex> 15 16 #include "AppleObjCRuntime.h" 17 #include "lldb/lldb-private.h" 18 19 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" 20 21 class RemoteNXMapTable; 22 23 namespace lldb_private { 24 25 class AppleObjCRuntimeV2 : public AppleObjCRuntime { 26 public: 27 ~AppleObjCRuntimeV2() override = default; 28 29 // Static Functions 30 static void Initialize(); 31 32 static void Terminate(); 33 34 static lldb_private::LanguageRuntime * 35 CreateInstance(Process *process, lldb::LanguageType language); 36 37 static lldb_private::ConstString GetPluginNameStatic(); 38 39 static char ID; 40 41 bool isA(const void *ClassID) const override { 42 return ClassID == &ID || AppleObjCRuntime::isA(ClassID); 43 } 44 45 static bool classof(const LanguageRuntime *runtime) { 46 return runtime->isA(&ID); 47 } 48 49 // These are generic runtime functions: 50 bool GetDynamicTypeAndAddress(ValueObject &in_value, 51 lldb::DynamicValueType use_dynamic, 52 TypeAndOrName &class_type_or_name, 53 Address &address, 54 Value::ValueType &value_type) override; 55 56 UtilityFunction *CreateObjectChecker(const char *) override; 57 58 // PluginInterface protocol 59 ConstString GetPluginName() override; 60 61 uint32_t GetPluginVersion() override; 62 63 ObjCRuntimeVersions GetRuntimeVersion() const override { 64 return ObjCRuntimeVersions::eAppleObjC_V2; 65 } 66 67 size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 68 const char *ivar_name) override; 69 70 void UpdateISAToDescriptorMapIfNeeded() override; 71 72 ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; 73 74 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; 75 76 DeclVendor *GetDeclVendor() override; 77 78 lldb::addr_t LookupRuntimeSymbol(ConstString name) override; 79 80 EncodingToTypeSP GetEncodingToType() override; 81 82 bool IsTaggedPointer(lldb::addr_t ptr) override; 83 84 TaggedPointerVendor *GetTaggedPointerVendor() override { 85 return m_tagged_pointer_vendor_up.get(); 86 } 87 88 lldb::addr_t GetTaggedPointerObfuscator(); 89 90 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, 91 lldb::addr_t &cf_false) override; 92 93 // none of these are valid ISAs - we use them to infer the type 94 // of tagged pointers - if we have something meaningful to say 95 // we report an actual type - otherwise, we just say tagged 96 // there is no connection between the values here and the tagged pointers map 97 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; 98 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; 99 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; 100 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; 101 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 102 5; 103 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; 104 105 protected: 106 lldb::BreakpointResolverSP 107 CreateExceptionResolver(const lldb::BreakpointSP &bkpt, 108 bool catch_bp, bool throw_bp) override; 109 110 private: 111 class HashTableSignature { 112 public: 113 HashTableSignature(); 114 115 bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime, 116 RemoteNXMapTable &hash_table); 117 118 void UpdateSignature(const RemoteNXMapTable &hash_table); 119 120 protected: 121 uint32_t m_count; 122 uint32_t m_num_buckets; 123 lldb::addr_t m_buckets_ptr; 124 }; 125 126 class NonPointerISACache { 127 public: 128 static NonPointerISACache * 129 CreateInstance(AppleObjCRuntimeV2 &runtime, 130 const lldb::ModuleSP &objc_module_sp); 131 132 ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa); 133 134 private: 135 NonPointerISACache(AppleObjCRuntimeV2 &runtime, 136 const lldb::ModuleSP &objc_module_sp, 137 uint64_t objc_debug_isa_class_mask, 138 uint64_t objc_debug_isa_magic_mask, 139 uint64_t objc_debug_isa_magic_value, 140 uint64_t objc_debug_indexed_isa_magic_mask, 141 uint64_t objc_debug_indexed_isa_magic_value, 142 uint64_t objc_debug_indexed_isa_index_mask, 143 uint64_t objc_debug_indexed_isa_index_shift, 144 lldb::addr_t objc_indexed_classes); 145 146 bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa); 147 148 AppleObjCRuntimeV2 &m_runtime; 149 std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache; 150 lldb::ModuleWP m_objc_module_wp; 151 uint64_t m_objc_debug_isa_class_mask; 152 uint64_t m_objc_debug_isa_magic_mask; 153 uint64_t m_objc_debug_isa_magic_value; 154 155 uint64_t m_objc_debug_indexed_isa_magic_mask; 156 uint64_t m_objc_debug_indexed_isa_magic_value; 157 uint64_t m_objc_debug_indexed_isa_index_mask; 158 uint64_t m_objc_debug_indexed_isa_index_shift; 159 lldb::addr_t m_objc_indexed_classes; 160 161 std::vector<lldb::addr_t> m_indexed_isa_cache; 162 163 friend class AppleObjCRuntimeV2; 164 165 NonPointerISACache(const NonPointerISACache &) = delete; 166 const NonPointerISACache &operator=(const NonPointerISACache &) = delete; 167 }; 168 169 class TaggedPointerVendorV2 170 : public ObjCLanguageRuntime::TaggedPointerVendor { 171 public: 172 ~TaggedPointerVendorV2() override = default; 173 174 static TaggedPointerVendorV2 * 175 CreateInstance(AppleObjCRuntimeV2 &runtime, 176 const lldb::ModuleSP &objc_module_sp); 177 178 protected: 179 AppleObjCRuntimeV2 &m_runtime; 180 181 TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime) 182 : TaggedPointerVendor(), m_runtime(runtime) {} 183 184 private: 185 TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete; 186 const TaggedPointerVendorV2 & 187 operator=(const TaggedPointerVendorV2 &) = delete; 188 }; 189 190 class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { 191 public: 192 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 193 194 ObjCLanguageRuntime::ClassDescriptorSP 195 GetClassDescriptor(lldb::addr_t ptr) override; 196 197 protected: 198 TaggedPointerVendorRuntimeAssisted( 199 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 200 uint32_t objc_debug_taggedpointer_slot_shift, 201 uint32_t objc_debug_taggedpointer_slot_mask, 202 uint32_t objc_debug_taggedpointer_payload_lshift, 203 uint32_t objc_debug_taggedpointer_payload_rshift, 204 lldb::addr_t objc_debug_taggedpointer_classes); 205 206 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 207 typedef Cache::iterator CacheIterator; 208 Cache m_cache; 209 uint64_t m_objc_debug_taggedpointer_mask; 210 uint32_t m_objc_debug_taggedpointer_slot_shift; 211 uint32_t m_objc_debug_taggedpointer_slot_mask; 212 uint32_t m_objc_debug_taggedpointer_payload_lshift; 213 uint32_t m_objc_debug_taggedpointer_payload_rshift; 214 lldb::addr_t m_objc_debug_taggedpointer_classes; 215 216 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 217 218 TaggedPointerVendorRuntimeAssisted( 219 const TaggedPointerVendorRuntimeAssisted &) = delete; 220 const TaggedPointerVendorRuntimeAssisted & 221 operator=(const TaggedPointerVendorRuntimeAssisted &) = delete; 222 }; 223 224 class TaggedPointerVendorExtended 225 : public TaggedPointerVendorRuntimeAssisted { 226 public: 227 ObjCLanguageRuntime::ClassDescriptorSP 228 GetClassDescriptor(lldb::addr_t ptr) override; 229 230 protected: 231 TaggedPointerVendorExtended( 232 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 233 uint64_t objc_debug_taggedpointer_ext_mask, 234 uint32_t objc_debug_taggedpointer_slot_shift, 235 uint32_t objc_debug_taggedpointer_ext_slot_shift, 236 uint32_t objc_debug_taggedpointer_slot_mask, 237 uint32_t objc_debug_taggedpointer_ext_slot_mask, 238 uint32_t objc_debug_taggedpointer_payload_lshift, 239 uint32_t objc_debug_taggedpointer_payload_rshift, 240 uint32_t objc_debug_taggedpointer_ext_payload_lshift, 241 uint32_t objc_debug_taggedpointer_ext_payload_rshift, 242 lldb::addr_t objc_debug_taggedpointer_classes, 243 lldb::addr_t objc_debug_taggedpointer_ext_classes); 244 245 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr); 246 247 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 248 typedef Cache::iterator CacheIterator; 249 Cache m_ext_cache; 250 uint64_t m_objc_debug_taggedpointer_ext_mask; 251 uint32_t m_objc_debug_taggedpointer_ext_slot_shift; 252 uint32_t m_objc_debug_taggedpointer_ext_slot_mask; 253 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; 254 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; 255 lldb::addr_t m_objc_debug_taggedpointer_ext_classes; 256 257 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 258 259 TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete; 260 const TaggedPointerVendorExtended & 261 operator=(const TaggedPointerVendorExtended &) = delete; 262 }; 263 264 class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { 265 public: 266 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 267 268 ObjCLanguageRuntime::ClassDescriptorSP 269 GetClassDescriptor(lldb::addr_t ptr) override; 270 271 protected: 272 TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime) 273 : TaggedPointerVendorV2(runtime) {} 274 275 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 276 277 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete; 278 const TaggedPointerVendorLegacy & 279 operator=(const TaggedPointerVendorLegacy &) = delete; 280 }; 281 282 struct DescriptorMapUpdateResult { 283 bool m_update_ran; 284 uint32_t m_num_found; 285 286 DescriptorMapUpdateResult(bool ran, uint32_t found) { 287 m_update_ran = ran; 288 m_num_found = found; 289 } 290 291 static DescriptorMapUpdateResult Fail() { return {false, 0}; } 292 293 static DescriptorMapUpdateResult Success(uint32_t found) { 294 return {true, found}; 295 } 296 }; 297 298 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); 299 300 ObjCISA GetPointerISA(ObjCISA isa); 301 302 lldb::addr_t GetISAHashTablePointer(); 303 304 bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table); 305 306 DescriptorMapUpdateResult 307 UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table); 308 309 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, 310 uint32_t num_class_infos); 311 312 DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache(); 313 314 enum class SharedCacheWarningReason { 315 eExpressionExecutionFailure, 316 eNotEnoughClassesRead 317 }; 318 319 void WarnIfNoClassesCached(SharedCacheWarningReason reason); 320 321 lldb::addr_t GetSharedCacheReadOnlyAddress(); 322 323 bool GetCFBooleanValuesIfNeeded(); 324 325 friend class ClassDescriptorV2; 326 327 std::unique_ptr<UtilityFunction> m_get_class_info_code; 328 lldb::addr_t m_get_class_info_args; 329 std::mutex m_get_class_info_args_mutex; 330 331 std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code; 332 lldb::addr_t m_get_shared_cache_class_info_args; 333 std::mutex m_get_shared_cache_class_info_args_mutex; 334 335 std::unique_ptr<DeclVendor> m_decl_vendor_up; 336 lldb::addr_t m_tagged_pointer_obfuscator; 337 lldb::addr_t m_isa_hash_table_ptr; 338 HashTableSignature m_hash_signature; 339 bool m_has_object_getClass; 340 bool m_loaded_objc_opt; 341 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up; 342 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up; 343 EncodingToTypeSP m_encoding_to_type_sp; 344 bool m_noclasses_warning_emitted; 345 llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values; 346 }; 347 348 } // namespace lldb_private 349 350 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 351