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