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