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