1 //===-- ObjCLanguageRuntime.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_OBJCLANGUAGERUNTIME_H 10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H 11 12 #include <functional> 13 #include <map> 14 #include <memory> 15 #include <optional> 16 #include <unordered_set> 17 18 #include "llvm/Support/Casting.h" 19 20 #include "lldb/Breakpoint/BreakpointPrecondition.h" 21 #include "lldb/Core/PluginInterface.h" 22 #include "lldb/Symbol/CompilerType.h" 23 #include "lldb/Symbol/Type.h" 24 #include "lldb/Target/LanguageRuntime.h" 25 #include "lldb/Utility/ConstString.h" 26 #include "lldb/Utility/ThreadSafeDenseMap.h" 27 #include "lldb/lldb-enumerations.h" 28 #include "lldb/lldb-private.h" 29 30 class CommandObjectObjC_ClassTable_Dump; 31 32 namespace lldb_private { 33 34 class TypeSystemClang; 35 class UtilityFunction; 36 37 class ObjCLanguageRuntime : public LanguageRuntime { 38 public: 39 enum class ObjCRuntimeVersions { 40 eObjC_VersionUnknown = 0, 41 eAppleObjC_V1 = 1, 42 eAppleObjC_V2 = 2, 43 eGNUstep_libobjc2 = 3, 44 }; 45 46 typedef lldb::addr_t ObjCISA; 47 48 class ClassDescriptor; 49 typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP; 50 51 // the information that we want to support retrieving from an ObjC class this 52 // needs to be pure virtual since there are at least 2 different 53 // implementations of the runtime, and more might come 54 class ClassDescriptor { 55 public: ClassDescriptor()56 ClassDescriptor() : m_type_wp() {} 57 58 virtual ~ClassDescriptor() = default; 59 60 virtual ConstString GetClassName() = 0; 61 62 virtual ClassDescriptorSP GetSuperclass() = 0; 63 64 virtual ClassDescriptorSP GetMetaclass() const = 0; 65 66 // virtual if any implementation has some other version-specific rules but 67 // for the known v1/v2 this is all that needs to be done IsKVO()68 virtual bool IsKVO() { 69 if (m_is_kvo == eLazyBoolCalculate) { 70 const char *class_name = GetClassName().AsCString(); 71 if (class_name && *class_name) 72 m_is_kvo = 73 (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name); 74 } 75 return (m_is_kvo == eLazyBoolYes); 76 } 77 78 // virtual if any implementation has some other version-specific rules but 79 // for the known v1/v2 this is all that needs to be done IsCFType()80 virtual bool IsCFType() { 81 if (m_is_cf == eLazyBoolCalculate) { 82 const char *class_name = GetClassName().AsCString(); 83 if (class_name && *class_name) 84 m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 || 85 strcmp(class_name, "NSCFType") == 0); 86 } 87 return (m_is_cf == eLazyBoolYes); 88 } 89 90 /// Determine whether this class is implemented in Swift. GetImplementationLanguage()91 virtual lldb::LanguageType GetImplementationLanguage() const { 92 return lldb::eLanguageTypeObjC; 93 } 94 95 virtual bool IsValid() = 0; 96 97 /// There are two routines in the ObjC runtime that tagged pointer clients 98 /// can call to get the value from their tagged pointer, one that retrieves 99 /// it as an unsigned value and one a signed value. These two 100 /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls. 101 /// @{ 102 virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr, 103 uint64_t *value_bits = nullptr, 104 uint64_t *payload = nullptr) = 0; 105 106 virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr, 107 int64_t *value_bits = nullptr, 108 uint64_t *payload = nullptr) = 0; 109 /// @} 110 111 virtual uint64_t GetInstanceSize() = 0; 112 113 // use to implement version-specific additional constraints on pointers CheckPointer(lldb::addr_t value,uint32_t ptr_size)114 virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const { 115 return true; 116 } 117 118 virtual ObjCISA GetISA() = 0; 119 120 // This should return true iff the interface could be completed 121 virtual bool Describe(std::function<void (ObjCISA)> const & superclass_func,std::function<bool (const char *,const char *)> const & instance_method_func,std::function<bool (const char *,const char *)> const & class_method_func,std::function<bool (const char *,const char *,lldb::addr_t,uint64_t)> const & ivar_func)122 Describe(std::function<void(ObjCISA)> const &superclass_func, 123 std::function<bool(const char *, const char *)> const 124 &instance_method_func, 125 std::function<bool(const char *, const char *)> const 126 &class_method_func, 127 std::function<bool(const char *, const char *, lldb::addr_t, 128 uint64_t)> const &ivar_func) const { 129 return false; 130 } 131 GetType()132 lldb::TypeSP GetType() { return m_type_wp.lock(); } 133 SetType(const lldb::TypeSP & type_sp)134 void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; } 135 136 struct iVarDescriptor { 137 ConstString m_name; 138 CompilerType m_type; 139 uint64_t m_size; 140 int32_t m_offset; 141 }; 142 GetNumIVars()143 virtual size_t GetNumIVars() { return 0; } 144 GetIVarAtIndex(size_t idx)145 virtual iVarDescriptor GetIVarAtIndex(size_t idx) { 146 return iVarDescriptor(); 147 } 148 149 protected: 150 bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size, 151 bool allow_NULLs = false, bool allow_tagged = false, 152 bool check_version_specific = false) const; 153 154 private: 155 LazyBool m_is_kvo = eLazyBoolCalculate; 156 LazyBool m_is_cf = eLazyBoolCalculate; 157 lldb::TypeWP m_type_wp; 158 }; 159 160 class EncodingToType { 161 public: 162 virtual ~EncodingToType(); 163 164 virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name, 165 bool for_expression) = 0; 166 virtual CompilerType RealizeType(const char *name, bool for_expression); 167 168 protected: 169 std::shared_ptr<TypeSystemClang> m_scratch_ast_ctx_sp; 170 }; 171 172 class ObjCExceptionPrecondition : public BreakpointPrecondition { 173 public: 174 ObjCExceptionPrecondition(); 175 176 ~ObjCExceptionPrecondition() override = default; 177 178 bool EvaluatePrecondition(StoppointCallbackContext &context) override; 179 void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; 180 Status ConfigurePrecondition(Args &args) override; 181 182 protected: 183 void AddClassName(const char *class_name); 184 185 private: 186 std::unordered_set<std::string> m_class_names; 187 }; 188 189 static lldb::BreakpointPreconditionSP 190 GetBreakpointExceptionPrecondition(lldb::LanguageType language, 191 bool throw_bp); 192 193 class TaggedPointerVendor { 194 public: 195 virtual ~TaggedPointerVendor() = default; 196 197 virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0; 198 199 virtual ObjCLanguageRuntime::ClassDescriptorSP 200 GetClassDescriptor(lldb::addr_t ptr) = 0; 201 202 protected: 203 TaggedPointerVendor() = default; 204 205 private: 206 TaggedPointerVendor(const TaggedPointerVendor &) = delete; 207 const TaggedPointerVendor &operator=(const TaggedPointerVendor &) = delete; 208 }; 209 210 ~ObjCLanguageRuntime() override; 211 212 static char ID; 213 isA(const void * ClassID)214 bool isA(const void *ClassID) const override { 215 return ClassID == &ID || LanguageRuntime::isA(ClassID); 216 } 217 classof(const LanguageRuntime * runtime)218 static bool classof(const LanguageRuntime *runtime) { 219 return runtime->isA(&ID); 220 } 221 Get(Process & process)222 static ObjCLanguageRuntime *Get(Process &process) { 223 return llvm::cast_or_null<ObjCLanguageRuntime>( 224 process.GetLanguageRuntime(lldb::eLanguageTypeObjC)); 225 } 226 GetTaggedPointerVendor()227 virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; } 228 229 typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; 230 231 virtual EncodingToTypeSP GetEncodingToType(); 232 233 virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value); 234 235 ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value); 236 237 virtual ClassDescriptorSP 238 GetClassDescriptorFromClassName(ConstString class_name); 239 240 virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa); 241 242 ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa); 243 GetLanguageType()244 lldb::LanguageType GetLanguageType() const override { 245 return lldb::eLanguageTypeObjC; 246 } 247 248 virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 249 250 virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 251 252 virtual bool HasReadObjCLibrary() = 0; 253 254 // These two methods actually use different caches. The only time we'll 255 // cache a sel_str is if we found a "selector specific stub" for the selector 256 // and conversely we only add to the SEL cache if we saw a regular dispatch. 257 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel); 258 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, 259 llvm::StringRef sel_str); 260 261 void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, 262 lldb::addr_t impl_addr); 263 264 void AddToMethodCache(lldb::addr_t class_addr, llvm::StringRef sel_str, 265 lldb::addr_t impl_addr); 266 267 TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr); 268 269 void AddToClassNameCache(lldb::addr_t class_addr, const char *name, 270 lldb::TypeSP type_sp); 271 272 void AddToClassNameCache(lldb::addr_t class_addr, 273 const TypeAndOrName &class_or_type_name); 274 275 lldb::TypeSP LookupInCompleteClassCache(ConstString &name); 276 277 std::optional<CompilerType> GetRuntimeType(CompilerType base_type) override; 278 279 virtual llvm::Expected<std::unique_ptr<UtilityFunction>> 280 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0; 281 GetRuntimeVersion()282 virtual ObjCRuntimeVersions GetRuntimeVersion() const { 283 return ObjCRuntimeVersions::eObjC_VersionUnknown; 284 } 285 IsValidISA(ObjCISA isa)286 bool IsValidISA(ObjCISA isa) { 287 UpdateISAToDescriptorMap(); 288 return m_isa_to_descriptor.count(isa) > 0; 289 } 290 291 virtual void UpdateISAToDescriptorMapIfNeeded() = 0; 292 UpdateISAToDescriptorMap()293 void UpdateISAToDescriptorMap() { 294 if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) { 295 UpdateISAToDescriptorMapIfNeeded(); 296 } 297 } 298 299 virtual ObjCISA GetISA(ConstString name); 300 301 virtual ObjCISA GetParentClass(ObjCISA isa); 302 303 // Finds the byte offset of the child_type ivar in parent_type. If it can't 304 // find the offset, returns LLDB_INVALID_IVAR_OFFSET. 305 306 virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 307 const char *ivar_name); 308 HasNewLiteralsAndIndexing()309 bool HasNewLiteralsAndIndexing() { 310 if (m_has_new_literals_and_indexing == eLazyBoolCalculate) { 311 if (CalculateHasNewLiteralsAndIndexing()) 312 m_has_new_literals_and_indexing = eLazyBoolYes; 313 else 314 m_has_new_literals_and_indexing = eLazyBoolNo; 315 } 316 317 return (m_has_new_literals_and_indexing == eLazyBoolYes); 318 } 319 SymbolsDidLoad(const ModuleList & module_list)320 void SymbolsDidLoad(const ModuleList &module_list) override { 321 m_negative_complete_class_cache.clear(); 322 } 323 324 std::optional<uint64_t> 325 GetTypeBitSize(const CompilerType &compiler_type) override; 326 327 /// Check whether the name is "self" or "_cmd" and should show up in 328 /// "frame variable". 329 bool IsAllowedRuntimeValue(ConstString name) override; 330 331 protected: 332 // Classes that inherit from ObjCLanguageRuntime can see and modify these 333 ObjCLanguageRuntime(Process *process); 334 CalculateHasNewLiteralsAndIndexing()335 virtual bool CalculateHasNewLiteralsAndIndexing() { return false; } 336 ISAIsCached(ObjCISA isa)337 bool ISAIsCached(ObjCISA isa) const { 338 return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); 339 } 340 AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp)341 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) { 342 if (isa != 0) { 343 m_isa_to_descriptor[isa] = descriptor_sp; 344 return true; 345 } 346 return false; 347 } 348 349 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 350 const char *class_name); 351 AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,uint32_t class_name_hash)352 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 353 uint32_t class_name_hash) { 354 if (isa != 0) { 355 m_isa_to_descriptor[isa] = descriptor_sp; 356 m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); 357 return true; 358 } 359 return false; 360 } 361 362 private: 363 // We keep two maps of <Class,Selector>->Implementation so we don't have 364 // to call the resolver function over and over. 365 // The first comes from regular obj_msgSend type dispatch, and maps the 366 // class + uniqued SEL value to an implementation. 367 // The second comes from the "selector-specific stubs", which are always 368 // of the form _objc_msgSend$SelectorName, so we don't know the uniqued 369 // selector, only the string name. 370 371 // FIXME: We need to watch for the loading of Protocols, and flush the cache 372 // for any 373 // class that we see so changed. 374 375 struct ClassAndSel { 376 ClassAndSel() = default; 377 ClassAndSelClassAndSel378 ClassAndSel(lldb::addr_t in_class_addr, lldb::addr_t in_sel_addr) 379 : class_addr(in_class_addr), sel_addr(in_sel_addr) {} 380 381 bool operator==(const ClassAndSel &rhs) { 382 if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr) 383 return true; 384 else 385 return false; 386 } 387 388 bool operator<(const ClassAndSel &rhs) const { 389 if (class_addr < rhs.class_addr) 390 return true; 391 else if (class_addr > rhs.class_addr) 392 return false; 393 else { 394 if (sel_addr < rhs.sel_addr) 395 return true; 396 else 397 return false; 398 } 399 } 400 401 lldb::addr_t class_addr = LLDB_INVALID_ADDRESS; 402 lldb::addr_t sel_addr = LLDB_INVALID_ADDRESS; 403 }; 404 405 struct ClassAndSelStr { 406 ClassAndSelStr() = default; 407 ClassAndSelStrClassAndSelStr408 ClassAndSelStr(lldb::addr_t in_class_addr, llvm::StringRef in_sel_name) 409 : class_addr(in_class_addr), sel_name(in_sel_name) {} 410 411 bool operator==(const ClassAndSelStr &rhs) { 412 return class_addr == rhs.class_addr && sel_name == rhs.sel_name; 413 } 414 415 bool operator<(const ClassAndSelStr &rhs) const { 416 if (class_addr < rhs.class_addr) 417 return true; 418 else if (class_addr > rhs.class_addr) 419 return false; 420 else 421 return ConstString::Compare(sel_name, rhs.sel_name); 422 } 423 424 lldb::addr_t class_addr = LLDB_INVALID_ADDRESS; 425 ConstString sel_name; 426 }; 427 428 typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap; 429 typedef std::map<ClassAndSelStr, lldb::addr_t> MsgImplStrMap; 430 typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; 431 typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; 432 typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; 433 typedef HashToISAMap::iterator HashToISAIterator; 434 typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache; 435 436 MsgImplMap m_impl_cache; 437 MsgImplStrMap m_impl_str_cache; 438 LazyBool m_has_new_literals_and_indexing; 439 ISAToDescriptorMap m_isa_to_descriptor; 440 HashToISAMap m_hash_to_isa_map; 441 TypeSizeCache m_type_size_cache; 442 443 protected: 444 uint32_t m_isa_to_descriptor_stop_id; 445 446 typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; 447 CompleteClassMap m_complete_class_cache; 448 449 struct ConstStringSetHelpers { operatorConstStringSetHelpers450 size_t operator()(ConstString arg) const // for hashing 451 { 452 return (size_t)arg.GetCString(); 453 } operatorConstStringSetHelpers454 bool operator()(ConstString arg1, 455 ConstString arg2) const // for equality 456 { 457 return arg1.operator==(arg2); 458 } 459 }; 460 typedef std::unordered_set<ConstString, ConstStringSetHelpers, 461 ConstStringSetHelpers> 462 CompleteClassSet; 463 CompleteClassSet m_negative_complete_class_cache; 464 465 ISAToDescriptorIterator GetDescriptorIterator(ConstString name); 466 467 friend class ::CommandObjectObjC_ClassTable_Dump; 468 469 std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator> 470 GetDescriptorIteratorPair(bool update_if_needed = true); 471 472 void ReadObjCLibraryIfNeeded(const ModuleList &module_list); 473 474 ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete; 475 const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete; 476 }; 477 478 } // namespace lldb_private 479 480 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H 481