1 //===-- ObjCLanguageRuntime.h -----------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef liblldb_ObjCLanguageRuntime_h_ 11 #define liblldb_ObjCLanguageRuntime_h_ 12 13 #include <functional> 14 #include <map> 15 #include <memory> 16 #include <unordered_set> 17 18 #include "llvm/Support/Casting.h" 19 20 #include "lldb/Core/PluginInterface.h" 21 #include "lldb/Core/ThreadSafeDenseMap.h" 22 #include "lldb/Symbol/CompilerType.h" 23 #include "lldb/Symbol/DeclVendor.h" 24 #include "lldb/Symbol/Type.h" 25 #include "lldb/Target/LanguageRuntime.h" 26 #include "lldb/lldb-private.h" 27 28 class CommandObjectObjC_ClassTable_Dump; 29 30 namespace lldb_private { 31 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: ClassDescriptor()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 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 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 CheckPointer(lldb::addr_t value,uint32_t ptr_size)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 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)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 GetType()115 lldb::TypeSP GetType() { return m_type_wp.lock(); } 116 SetType(const lldb::TypeSP & type_sp)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 GetNumIVars()126 virtual size_t GetNumIVars() { return 0; } 127 GetIVarAtIndex(size_t idx)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); 149 virtual CompilerType RealizeType(const char *name, bool for_expression); 150 151 virtual CompilerType RealizeType(clang::ASTContext &ast_ctx, 152 const char *name, bool for_expression) = 0; 153 154 protected: 155 std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap; 156 }; 157 158 class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition { 159 public: 160 ObjCExceptionPrecondition(); 161 162 ~ObjCExceptionPrecondition() override = default; 163 164 bool EvaluatePrecondition(StoppointCallbackContext &context) override; 165 void GetDescription(Stream &stream, lldb::DescriptionLevel level) override; 166 Status ConfigurePrecondition(Args &args) override; 167 168 protected: 169 void AddClassName(const char *class_name); 170 171 private: 172 std::unordered_set<std::string> m_class_names; 173 }; 174 175 class TaggedPointerVendor { 176 public: 177 virtual ~TaggedPointerVendor() = default; 178 179 virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0; 180 181 virtual ObjCLanguageRuntime::ClassDescriptorSP 182 GetClassDescriptor(lldb::addr_t ptr) = 0; 183 184 protected: 185 TaggedPointerVendor() = default; 186 187 private: 188 DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor); 189 }; 190 191 ~ObjCLanguageRuntime() override; 192 GetTaggedPointerVendor()193 virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; } 194 195 typedef std::shared_ptr<EncodingToType> EncodingToTypeSP; 196 197 virtual EncodingToTypeSP GetEncodingToType(); 198 199 virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value); 200 201 ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value); 202 203 virtual ClassDescriptorSP 204 GetClassDescriptorFromClassName(const ConstString &class_name); 205 206 virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa); 207 208 ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa); 209 GetLanguageType()210 lldb::LanguageType GetLanguageType() const override { 211 return lldb::eLanguageTypeObjC; 212 } 213 214 virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 215 216 virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0; 217 218 virtual bool HasReadObjCLibrary() = 0; 219 220 virtual lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread, 221 bool stop_others) = 0; 222 223 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel); 224 225 void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel, 226 lldb::addr_t impl_addr); 227 228 TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr); 229 230 void AddToClassNameCache(lldb::addr_t class_addr, const char *name, 231 lldb::TypeSP type_sp); 232 233 void AddToClassNameCache(lldb::addr_t class_addr, 234 const TypeAndOrName &class_or_type_name); 235 236 lldb::TypeSP LookupInCompleteClassCache(ConstString &name); 237 238 virtual UtilityFunction *CreateObjectChecker(const char *) = 0; 239 GetRuntimeVersion()240 virtual ObjCRuntimeVersions GetRuntimeVersion() const { 241 return ObjCRuntimeVersions::eObjC_VersionUnknown; 242 } 243 IsValidISA(ObjCISA isa)244 bool IsValidISA(ObjCISA isa) { 245 UpdateISAToDescriptorMap(); 246 return m_isa_to_descriptor.count(isa) > 0; 247 } 248 249 virtual void UpdateISAToDescriptorMapIfNeeded() = 0; 250 UpdateISAToDescriptorMap()251 void UpdateISAToDescriptorMap() { 252 if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) { 253 UpdateISAToDescriptorMapIfNeeded(); 254 } 255 } 256 257 virtual ObjCISA GetISA(const ConstString &name); 258 259 virtual ConstString GetActualTypeName(ObjCISA isa); 260 261 virtual ObjCISA GetParentClass(ObjCISA isa); 262 GetDeclVendor()263 virtual DeclVendor *GetDeclVendor() { return nullptr; } 264 265 // Finds the byte offset of the child_type ivar in parent_type. If it can't 266 // find the offset, returns LLDB_INVALID_IVAR_OFFSET. 267 268 virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type, 269 const char *ivar_name); 270 271 // Given the name of an Objective-C runtime symbol (e.g., ivar offset 272 // symbol), try to determine from the runtime what the value of that symbol 273 // would be. Useful when the underlying binary is stripped. LookupRuntimeSymbol(const ConstString & name)274 virtual lldb::addr_t LookupRuntimeSymbol(const ConstString &name) { 275 return LLDB_INVALID_ADDRESS; 276 } 277 HasNewLiteralsAndIndexing()278 bool HasNewLiteralsAndIndexing() { 279 if (m_has_new_literals_and_indexing == eLazyBoolCalculate) { 280 if (CalculateHasNewLiteralsAndIndexing()) 281 m_has_new_literals_and_indexing = eLazyBoolYes; 282 else 283 m_has_new_literals_and_indexing = eLazyBoolNo; 284 } 285 286 return (m_has_new_literals_and_indexing == eLazyBoolYes); 287 } 288 SymbolsDidLoad(const ModuleList & module_list)289 virtual void SymbolsDidLoad(const ModuleList &module_list) { 290 m_negative_complete_class_cache.clear(); 291 } 292 293 bool GetTypeBitSize(const CompilerType &compiler_type, 294 uint64_t &size) override; 295 296 protected: 297 //------------------------------------------------------------------ 298 // Classes that inherit from ObjCLanguageRuntime can see and modify these 299 //------------------------------------------------------------------ 300 ObjCLanguageRuntime(Process *process); 301 CalculateHasNewLiteralsAndIndexing()302 virtual bool CalculateHasNewLiteralsAndIndexing() { return false; } 303 ISAIsCached(ObjCISA isa)304 bool ISAIsCached(ObjCISA isa) const { 305 return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end(); 306 } 307 AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp)308 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) { 309 if (isa != 0) { 310 m_isa_to_descriptor[isa] = descriptor_sp; 311 return true; 312 } 313 return false; 314 } 315 316 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 317 const char *class_name); 318 AddClass(ObjCISA isa,const ClassDescriptorSP & descriptor_sp,uint32_t class_name_hash)319 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp, 320 uint32_t class_name_hash) { 321 if (isa != 0) { 322 m_isa_to_descriptor[isa] = descriptor_sp; 323 m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa)); 324 return true; 325 } 326 return false; 327 } 328 329 private: 330 // We keep a map of <Class,Selector>->Implementation so we don't have to call 331 // the resolver function over and over. 332 333 // FIXME: We need to watch for the loading of Protocols, and flush the cache 334 // for any 335 // class that we see so changed. 336 337 struct ClassAndSel { ClassAndSelClassAndSel338 ClassAndSel() { 339 sel_addr = LLDB_INVALID_ADDRESS; 340 class_addr = LLDB_INVALID_ADDRESS; 341 } 342 ClassAndSelClassAndSel343 ClassAndSel(lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) 344 : class_addr(in_class_addr), sel_addr(in_sel_addr) {} 345 346 bool operator==(const ClassAndSel &rhs) { 347 if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr) 348 return true; 349 else 350 return false; 351 } 352 353 bool operator<(const ClassAndSel &rhs) const { 354 if (class_addr < rhs.class_addr) 355 return true; 356 else if (class_addr > rhs.class_addr) 357 return false; 358 else { 359 if (sel_addr < rhs.sel_addr) 360 return true; 361 else 362 return false; 363 } 364 } 365 366 lldb::addr_t class_addr; 367 lldb::addr_t sel_addr; 368 }; 369 370 typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap; 371 typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap; 372 typedef std::multimap<uint32_t, ObjCISA> HashToISAMap; 373 typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator; 374 typedef HashToISAMap::iterator HashToISAIterator; 375 typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache; 376 377 MsgImplMap m_impl_cache; 378 LazyBool m_has_new_literals_and_indexing; 379 ISAToDescriptorMap m_isa_to_descriptor; 380 HashToISAMap m_hash_to_isa_map; 381 TypeSizeCache m_type_size_cache; 382 383 protected: 384 uint32_t m_isa_to_descriptor_stop_id; 385 386 typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap; 387 CompleteClassMap m_complete_class_cache; 388 389 struct ConstStringSetHelpers { operatorConstStringSetHelpers390 size_t operator()(const ConstString &arg) const // for hashing 391 { 392 return (size_t)arg.GetCString(); 393 } operatorConstStringSetHelpers394 bool operator()(const ConstString &arg1, 395 const ConstString &arg2) const // for equality 396 { 397 return arg1.operator==(arg2); 398 } 399 }; 400 typedef std::unordered_set<ConstString, ConstStringSetHelpers, 401 ConstStringSetHelpers> 402 CompleteClassSet; 403 CompleteClassSet m_negative_complete_class_cache; 404 405 ISAToDescriptorIterator GetDescriptorIterator(const ConstString &name); 406 407 friend class ::CommandObjectObjC_ClassTable_Dump; 408 409 std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator> 410 GetDescriptorIteratorPair(bool update_if_needed = true); 411 412 void ReadObjCLibraryIfNeeded(const ModuleList &module_list); 413 414 DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime); 415 }; 416 417 } // namespace lldb_private 418 419 #endif // liblldb_ObjCLanguageRuntime_h_ 420