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 lldb_private::ConstString GetPluginNameStatic(); 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 ConstString GetPluginName() override; 58 59 uint32_t GetPluginVersion() override; 60 61 ObjCRuntimeVersions GetRuntimeVersion() const override { 62 return ObjCRuntimeVersions::eAppleObjC_V2; 63 } 64 65 size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 66 const char *ivar_name) override; 67 68 void UpdateISAToDescriptorMapIfNeeded() override; 69 70 ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override; 71 72 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override; 73 74 DeclVendor *GetDeclVendor() override; 75 76 lldb::addr_t LookupRuntimeSymbol(ConstString name) override; 77 78 EncodingToTypeSP GetEncodingToType() override; 79 80 bool IsTaggedPointer(lldb::addr_t ptr) override; 81 82 TaggedPointerVendor *GetTaggedPointerVendor() override { 83 return m_tagged_pointer_vendor_up.get(); 84 } 85 86 lldb::addr_t GetTaggedPointerObfuscator(); 87 88 /// Returns the base address for relative method list selector strings. 89 lldb::addr_t GetRelativeSelectorBaseAddr() { 90 return m_relative_selector_base; 91 } 92 93 void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) { 94 m_relative_selector_base = relative_selector_base; 95 } 96 97 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, 98 lldb::addr_t &cf_false) override; 99 100 // none of these are valid ISAs - we use them to infer the type 101 // of tagged pointers - if we have something meaningful to say 102 // we report an actual type - otherwise, we just say tagged 103 // there is no connection between the values here and the tagged pointers map 104 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1; 105 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2; 106 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3; 107 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4; 108 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject = 109 5; 110 static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6; 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 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: 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 uint32_t m_num_found; 292 293 DescriptorMapUpdateResult(bool ran, uint32_t found) { 294 m_update_ran = ran; 295 m_num_found = found; 296 } 297 298 static DescriptorMapUpdateResult Fail() { return {false, 0}; } 299 300 static DescriptorMapUpdateResult Success(uint32_t found) { 301 return {true, found}; 302 } 303 }; 304 305 /// Abstraction to read the Objective-C class info. 306 class ClassInfoExtractor { 307 public: 308 ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {} 309 std::mutex &GetMutex() { return m_mutex; } 310 311 protected: 312 /// The lifetime of this object is tied to that of the runtime. 313 AppleObjCRuntimeV2 &m_runtime; 314 std::mutex m_mutex; 315 }; 316 317 /// We can read the class info from the Objective-C runtime using 318 /// gdb_objc_realized_classes or objc_copyRealizedClassList. The latter is 319 /// preferred because it includes lazily named classes, but it's not always 320 /// available or safe to call. 321 /// 322 /// We potentially need both for the same process, because we may need to use 323 /// gdb_objc_realized_classes until dyld is initialized and then switch over 324 /// to objc_copyRealizedClassList 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 { gdb_objc_realized_classes, objc_copyRealizedClassList }; 335 336 /// Compute which helper to use. Prefer objc_copyRealizedClassList if it's 337 /// available and it's safe to call (i.e. dyld is fully initialized). Use 338 /// gdb_objc_realized_classes otherwise. 339 Helper ComputeHelper() const; 340 341 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx, 342 Helper helper); 343 lldb::addr_t &GetClassInfoArgs(Helper helper); 344 345 std::unique_ptr<UtilityFunction> 346 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, std::string code, 347 std::string name); 348 349 /// Helper to read class info using the gdb_objc_realized_classes. 350 struct gdb_objc_realized_classes_helper { 351 std::unique_ptr<UtilityFunction> utility_function; 352 lldb::addr_t args = LLDB_INVALID_ADDRESS; 353 }; 354 355 /// Helper to read class info using objc_copyRealizedClassList. 356 struct objc_copyRealizedClassList_helper { 357 std::unique_ptr<UtilityFunction> utility_function; 358 lldb::addr_t args = LLDB_INVALID_ADDRESS; 359 }; 360 361 gdb_objc_realized_classes_helper m_gdb_objc_realized_classes_helper; 362 objc_copyRealizedClassList_helper m_objc_copyRealizedClassList_helper; 363 }; 364 365 /// Abstraction to read the Objective-C class info from the shared cache. 366 class SharedCacheClassInfoExtractor : public ClassInfoExtractor { 367 public: 368 SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime) 369 : ClassInfoExtractor(runtime) {} 370 371 DescriptorMapUpdateResult UpdateISAToDescriptorMap(); 372 373 private: 374 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx); 375 376 std::unique_ptr<UtilityFunction> 377 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx); 378 379 std::unique_ptr<UtilityFunction> m_utility_function; 380 lldb::addr_t m_args = LLDB_INVALID_ADDRESS; 381 }; 382 383 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp); 384 385 ObjCISA GetPointerISA(ObjCISA isa); 386 387 lldb::addr_t GetISAHashTablePointer(); 388 389 /// Update the generation count of realized classes. This is not an exact 390 /// count but rather a value that is incremented when new classes are realized 391 /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will 392 /// change when lazily named classes get realized. 393 bool RealizedClassGenerationCountChanged(); 394 395 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data, 396 uint32_t num_class_infos); 397 398 enum class SharedCacheWarningReason { 399 eExpressionExecutionFailure, 400 eNotEnoughClassesRead 401 }; 402 403 void WarnIfNoClassesCached(SharedCacheWarningReason reason); 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_loaded_objc_opt; 434 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up; 435 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up; 436 EncodingToTypeSP m_encoding_to_type_sp; 437 bool m_noclasses_warning_emitted; 438 llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values; 439 uint64_t m_realized_class_generation_count; 440 }; 441 442 } // namespace lldb_private 443 444 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H 445