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