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