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