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 void Initialize(); 30 31 static void Terminate(); 32 33 static lldb_private::LanguageRuntime * 34 CreateInstance(Process *process, lldb::LanguageType language); 35 36 static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; } 37 38 static char ID; 39 40 bool isA(const void *ClassID) const override { 41 return ClassID == &ID || AppleObjCRuntime::isA(ClassID); 42 } 43 44 static bool classof(const LanguageRuntime *runtime) { 45 return runtime->isA(&ID); 46 } 47 48 bool GetDynamicTypeAndAddress(ValueObject &in_value, 49 lldb::DynamicValueType use_dynamic, 50 TypeAndOrName &class_type_or_name, 51 Address &address, 52 Value::ValueType &value_type) override; 53 54 llvm::Expected<std::unique_ptr<UtilityFunction>> 55 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override; 56 57 llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } 58 59 ObjCRuntimeVersions GetRuntimeVersion() const override { 60 return ObjCRuntimeVersions::eAppleObjC_V2; 61 } 62 63 size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 64 const char *ivar_name) override; 65 66 void UpdateISAToDescriptorMapIfNeeded() override; 67 68 ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; 69 70 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; 71 72 DeclVendor *GetDeclVendor() override; 73 74 lldb::addr_t LookupRuntimeSymbol(ConstString name) override; 75 76 EncodingToTypeSP GetEncodingToType() override; 77 78 bool IsTaggedPointer(lldb::addr_t ptr) override; 79 80 TaggedPointerVendor *GetTaggedPointerVendor() override { 81 return m_tagged_pointer_vendor_up.get(); 82 } 83 84 lldb::addr_t GetTaggedPointerObfuscator(); 85 86 /// Returns the base address for relative method list selector strings. 87 lldb::addr_t GetRelativeSelectorBaseAddr() { 88 return m_relative_selector_base; 89 } 90 91 void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) { 92 m_relative_selector_base = relative_selector_base; 93 } 94 95 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, 96 lldb::addr_t &cf_false) override; 97 98 // none of these are valid ISAs - we use them to infer the type 99 // of tagged pointers - if we have something meaningful to say 100 // we report an actual type - otherwise, we just say tagged 101 // there is no connection between the values here and the tagged pointers map 102 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; 103 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; 104 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; 105 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; 106 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 107 5; 108 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; 109 110 protected: 111 lldb::BreakpointResolverSP 112 CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp, 113 bool throw_bp) override; 114 115 private: 116 class HashTableSignature { 117 public: 118 HashTableSignature(); 119 120 bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime, 121 RemoteNXMapTable &hash_table); 122 123 void UpdateSignature(const RemoteNXMapTable &hash_table); 124 125 protected: 126 uint32_t m_count = 0; 127 uint32_t m_num_buckets = 0; 128 lldb::addr_t m_buckets_ptr = 0; 129 }; 130 131 class NonPointerISACache { 132 public: 133 static NonPointerISACache * 134 CreateInstance(AppleObjCRuntimeV2 &runtime, 135 const lldb::ModuleSP &objc_module_sp); 136 137 ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa); 138 139 private: 140 NonPointerISACache(AppleObjCRuntimeV2 &runtime, 141 const lldb::ModuleSP &objc_module_sp, 142 uint64_t objc_debug_isa_class_mask, 143 uint64_t objc_debug_isa_magic_mask, 144 uint64_t objc_debug_isa_magic_value, 145 uint64_t objc_debug_indexed_isa_magic_mask, 146 uint64_t objc_debug_indexed_isa_magic_value, 147 uint64_t objc_debug_indexed_isa_index_mask, 148 uint64_t objc_debug_indexed_isa_index_shift, 149 lldb::addr_t objc_indexed_classes); 150 151 bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa); 152 153 AppleObjCRuntimeV2 &m_runtime; 154 std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache; 155 lldb::ModuleWP m_objc_module_wp; 156 uint64_t m_objc_debug_isa_class_mask; 157 uint64_t m_objc_debug_isa_magic_mask; 158 uint64_t m_objc_debug_isa_magic_value; 159 160 uint64_t m_objc_debug_indexed_isa_magic_mask; 161 uint64_t m_objc_debug_indexed_isa_magic_value; 162 uint64_t m_objc_debug_indexed_isa_index_mask; 163 uint64_t m_objc_debug_indexed_isa_index_shift; 164 lldb::addr_t m_objc_indexed_classes; 165 166 std::vector<lldb::addr_t> m_indexed_isa_cache; 167 168 friend class AppleObjCRuntimeV2; 169 170 NonPointerISACache(const NonPointerISACache &) = delete; 171 const NonPointerISACache &operator=(const NonPointerISACache &) = delete; 172 }; 173 174 class TaggedPointerVendorV2 175 : public ObjCLanguageRuntime::TaggedPointerVendor { 176 public: 177 ~TaggedPointerVendorV2() override = default; 178 179 static TaggedPointerVendorV2 * 180 CreateInstance(AppleObjCRuntimeV2 &runtime, 181 const lldb::ModuleSP &objc_module_sp); 182 183 protected: 184 AppleObjCRuntimeV2 &m_runtime; 185 186 TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime) 187 : TaggedPointerVendor(), m_runtime(runtime) {} 188 189 private: 190 TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete; 191 const TaggedPointerVendorV2 & 192 operator=(const TaggedPointerVendorV2 &) = delete; 193 }; 194 195 class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 { 196 public: 197 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 198 199 ObjCLanguageRuntime::ClassDescriptorSP 200 GetClassDescriptor(lldb::addr_t ptr) override; 201 202 protected: 203 TaggedPointerVendorRuntimeAssisted( 204 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 205 uint32_t objc_debug_taggedpointer_slot_shift, 206 uint32_t objc_debug_taggedpointer_slot_mask, 207 uint32_t objc_debug_taggedpointer_payload_lshift, 208 uint32_t objc_debug_taggedpointer_payload_rshift, 209 lldb::addr_t objc_debug_taggedpointer_classes); 210 211 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 212 typedef Cache::iterator CacheIterator; 213 Cache m_cache; 214 uint64_t m_objc_debug_taggedpointer_mask; 215 uint32_t m_objc_debug_taggedpointer_slot_shift; 216 uint32_t m_objc_debug_taggedpointer_slot_mask; 217 uint32_t m_objc_debug_taggedpointer_payload_lshift; 218 uint32_t m_objc_debug_taggedpointer_payload_rshift; 219 lldb::addr_t m_objc_debug_taggedpointer_classes; 220 221 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 222 223 TaggedPointerVendorRuntimeAssisted( 224 const TaggedPointerVendorRuntimeAssisted &) = delete; 225 const TaggedPointerVendorRuntimeAssisted & 226 operator=(const TaggedPointerVendorRuntimeAssisted &) = delete; 227 }; 228 229 class TaggedPointerVendorExtended 230 : public TaggedPointerVendorRuntimeAssisted { 231 public: 232 ObjCLanguageRuntime::ClassDescriptorSP 233 GetClassDescriptor(lldb::addr_t ptr) override; 234 235 protected: 236 TaggedPointerVendorExtended( 237 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 238 uint64_t objc_debug_taggedpointer_ext_mask, 239 uint32_t objc_debug_taggedpointer_slot_shift, 240 uint32_t objc_debug_taggedpointer_ext_slot_shift, 241 uint32_t objc_debug_taggedpointer_slot_mask, 242 uint32_t objc_debug_taggedpointer_ext_slot_mask, 243 uint32_t objc_debug_taggedpointer_payload_lshift, 244 uint32_t objc_debug_taggedpointer_payload_rshift, 245 uint32_t objc_debug_taggedpointer_ext_payload_lshift, 246 uint32_t objc_debug_taggedpointer_ext_payload_rshift, 247 lldb::addr_t objc_debug_taggedpointer_classes, 248 lldb::addr_t objc_debug_taggedpointer_ext_classes); 249 250 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr); 251 252 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache; 253 typedef Cache::iterator CacheIterator; 254 Cache m_ext_cache; 255 uint64_t m_objc_debug_taggedpointer_ext_mask; 256 uint32_t m_objc_debug_taggedpointer_ext_slot_shift; 257 uint32_t m_objc_debug_taggedpointer_ext_slot_mask; 258 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift; 259 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift; 260 lldb::addr_t m_objc_debug_taggedpointer_ext_classes; 261 262 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 263 264 TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete; 265 const TaggedPointerVendorExtended & 266 operator=(const TaggedPointerVendorExtended &) = delete; 267 }; 268 269 class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 { 270 public: 271 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override; 272 273 ObjCLanguageRuntime::ClassDescriptorSP 274 GetClassDescriptor(lldb::addr_t ptr) override; 275 276 protected: 277 TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime) 278 : TaggedPointerVendorV2(runtime) {} 279 280 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2; 281 282 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete; 283 const TaggedPointerVendorLegacy & 284 operator=(const TaggedPointerVendorLegacy &) = delete; 285 }; 286 287 struct DescriptorMapUpdateResult { 288 bool m_update_ran; 289 uint32_t m_num_found; 290 291 DescriptorMapUpdateResult(bool ran, uint32_t found) { 292 m_update_ran = ran; 293 m_num_found = found; 294 } 295 296 static DescriptorMapUpdateResult Fail() { return {false, 0}; } 297 298 static DescriptorMapUpdateResult Success(uint32_t found) { 299 return {true, found}; 300 } 301 }; 302 303 /// Abstraction to read the Objective-C class info. 304 class ClassInfoExtractor { 305 public: 306 ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {} 307 std::mutex &GetMutex() { return m_mutex; } 308 309 protected: 310 /// The lifetime of this object is tied to that of the runtime. 311 AppleObjCRuntimeV2 &m_runtime; 312 std::mutex m_mutex; 313 }; 314 315 /// We can read the class info from the Objective-C runtime using 316 /// gdb_objc_realized_classes, objc_copyRealizedClassList or 317 /// objc_getRealizedClassList_trylock. The RealizedClassList variants are 318 /// preferred because they include lazily named classes, but they are not 319 /// always available or safe to call. 320 /// 321 /// We potentially need more than one helper for the same process, because we 322 /// may need to use gdb_objc_realized_classes until dyld is initialized and 323 /// then switch over to objc_copyRealizedClassList or 324 /// objc_getRealizedClassList_trylock for lazily named classes. 325 class DynamicClassInfoExtractor : public ClassInfoExtractor { 326 public: 327 DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime) 328 : ClassInfoExtractor(runtime) {} 329 330 DescriptorMapUpdateResult 331 UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table); 332 333 private: 334 enum Helper { 335 gdb_objc_realized_classes, 336 objc_copyRealizedClassList, 337 objc_getRealizedClassList_trylock 338 }; 339 340 /// Compute which helper to use. If dyld is not yet fully initialized we 341 /// must use gdb_objc_realized_classes. Otherwise, we prefer 342 /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList 343 /// respectively, depending on availability. 344 Helper ComputeHelper(ExecutionContext &exe_ctx) const; 345 346 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx, 347 Helper helper); 348 lldb::addr_t &GetClassInfoArgs(Helper helper); 349 350 std::unique_ptr<UtilityFunction> 351 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper, 352 std::string code, std::string name); 353 354 struct UtilityFunctionHelper { 355 std::unique_ptr<UtilityFunction> utility_function; 356 lldb::addr_t args = LLDB_INVALID_ADDRESS; 357 }; 358 359 UtilityFunctionHelper m_gdb_objc_realized_classes_helper; 360 UtilityFunctionHelper m_objc_copyRealizedClassList_helper; 361 UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper; 362 }; 363 364 /// Abstraction to read the Objective-C class info from the shared cache. 365 class SharedCacheClassInfoExtractor : public ClassInfoExtractor { 366 public: 367 SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime) 368 : ClassInfoExtractor(runtime) {} 369 370 DescriptorMapUpdateResult UpdateISAToDescriptorMap(); 371 372 private: 373 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx); 374 375 std::unique_ptr<UtilityFunction> 376 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx); 377 378 std::unique_ptr<UtilityFunction> m_utility_function; 379 lldb::addr_t m_args = LLDB_INVALID_ADDRESS; 380 }; 381 382 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); 383 384 ObjCISA GetPointerISA(ObjCISA isa); 385 386 lldb::addr_t GetISAHashTablePointer(); 387 388 /// Update the generation count of realized classes. This is not an exact 389 /// count but rather a value that is incremented when new classes are realized 390 /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will 391 /// change when lazily named classes get realized. 392 bool RealizedClassGenerationCountChanged(); 393 394 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, 395 uint32_t num_class_infos); 396 397 enum class SharedCacheWarningReason { 398 eExpressionExecutionFailure, 399 eNotEnoughClassesRead 400 }; 401 402 void WarnIfNoClassesCached(SharedCacheWarningReason reason); 403 void WarnIfNoExpandedSharedCache(); 404 405 lldb::addr_t GetSharedCacheReadOnlyAddress(); 406 lldb::addr_t GetSharedCacheBaseAddress(); 407 408 bool GetCFBooleanValuesIfNeeded(); 409 410 bool HasSymbol(ConstString Name); 411 412 NonPointerISACache *GetNonPointerIsaCache() { 413 if (!m_non_pointer_isa_cache_up) 414 m_non_pointer_isa_cache_up.reset( 415 NonPointerISACache::CreateInstance(*this, m_objc_module_sp)); 416 return m_non_pointer_isa_cache_up.get(); 417 } 418 419 friend class ClassDescriptorV2; 420 421 lldb::ModuleSP m_objc_module_sp; 422 423 DynamicClassInfoExtractor m_dynamic_class_info_extractor; 424 SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor; 425 426 std::unique_ptr<DeclVendor> m_decl_vendor_up; 427 lldb::addr_t m_tagged_pointer_obfuscator; 428 lldb::addr_t m_isa_hash_table_ptr; 429 lldb::addr_t m_relative_selector_base; 430 HashTableSignature m_hash_signature; 431 bool m_has_object_getClass; 432 bool m_has_objc_copyRealizedClassList; 433 bool m_has_objc_getRealizedClassList_trylock; 434 bool m_loaded_objc_opt; 435 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up; 436 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up; 437 EncodingToTypeSP m_encoding_to_type_sp; 438 std::once_flag m_no_classes_cached_warning; 439 std::once_flag m_no_expanded_cache_warning; 440 llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values; 441 uint64_t m_realized_class_generation_count; 442 }; 443 444 } // namespace lldb_private 445 446 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 447