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