1 //===-- ObjCLanguageRuntime.h -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef liblldb_ObjCLanguageRuntime_h_
10 #define liblldb_ObjCLanguageRuntime_h_
15 #include <unordered_set>
17 #include "llvm/Support/Casting.h"
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"
27 class CommandObjectObjC_ClassTable_Dump;
29 namespace lldb_private {
31 class UtilityFunction;
33 class ObjCLanguageRuntime : public LanguageRuntime {
35 enum class ObjCRuntimeVersions {
36 eObjC_VersionUnknown = 0,
41 typedef lldb::addr_t ObjCISA;
43 class ClassDescriptor;
44 typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
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 {
52 : m_is_kvo(eLazyBoolCalculate), m_is_cf(eLazyBoolCalculate),
55 virtual ~ClassDescriptor() = default;
57 virtual ConstString GetClassName() = 0;
59 virtual ClassDescriptorSP GetSuperclass() = 0;
61 virtual ClassDescriptorSP GetMetaclass() const = 0;
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)
70 (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name);
72 return (m_is_kvo == eLazyBoolYes);
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);
84 return (m_is_cf == eLazyBoolYes);
87 virtual bool IsValid() = 0;
89 virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
90 uint64_t *value_bits = nullptr,
91 uint64_t *payload = nullptr) = 0;
93 virtual uint64_t GetInstanceSize() = 0;
95 // use to implement version-specific additional constraints on pointers
96 virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const {
100 virtual ObjCISA GetISA() = 0;
102 // This should return true iff the interface could be completed
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
109 std::function<bool(const char *, const char *, lldb::addr_t,
110 uint64_t)> const &ivar_func) const {
114 lldb::TypeSP GetType() { return m_type_wp.lock(); }
116 void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; }
118 struct iVarDescriptor {
125 virtual size_t GetNumIVars() { return 0; }
127 virtual iVarDescriptor GetIVarAtIndex(size_t idx) {
128 return iVarDescriptor();
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;
139 lldb::TypeWP m_type_wp;
142 class EncodingToType {
144 virtual ~EncodingToType();
146 virtual CompilerType RealizeType(ClangASTContext &ast_ctx, const char *name,
147 bool for_expression);
148 virtual CompilerType RealizeType(const char *name, bool for_expression);
150 virtual CompilerType RealizeType(clang::ASTContext &ast_ctx,
151 const char *name, bool for_expression) = 0;
154 std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_up;
157 class ObjCExceptionPrecondition : public BreakpointPrecondition {
159 ObjCExceptionPrecondition();
161 ~ObjCExceptionPrecondition() override = default;
163 bool EvaluatePrecondition(StoppointCallbackContext &context) override;
164 void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
165 Status ConfigurePrecondition(Args &args) override;
168 void AddClassName(const char *class_name);
171 std::unordered_set<std::string> m_class_names;
174 static lldb::BreakpointPreconditionSP
175 GetBreakpointExceptionPrecondition(lldb::LanguageType language,
178 class TaggedPointerVendor {
180 virtual ~TaggedPointerVendor() = default;
182 virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0;
184 virtual ObjCLanguageRuntime::ClassDescriptorSP
185 GetClassDescriptor(lldb::addr_t ptr) = 0;
188 TaggedPointerVendor() = default;
191 DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor);
194 ~ObjCLanguageRuntime() override;
198 bool isA(const void *ClassID) const override {
199 return ClassID == &ID || LanguageRuntime::isA(ClassID);
202 static bool classof(const LanguageRuntime *runtime) {
203 return runtime->isA(&ID);
206 static ObjCLanguageRuntime *Get(Process &process) {
207 return llvm::cast_or_null<ObjCLanguageRuntime>(
208 process.GetLanguageRuntime(lldb::eLanguageTypeObjC));
211 virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; }
213 typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
215 virtual EncodingToTypeSP GetEncodingToType();
217 virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value);
219 ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value);
221 virtual ClassDescriptorSP
222 GetClassDescriptorFromClassName(ConstString class_name);
224 virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa);
226 ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa);
228 lldb::LanguageType GetLanguageType() const override {
229 return lldb::eLanguageTypeObjC;
232 virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
234 virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
236 virtual bool HasReadObjCLibrary() = 0;
238 lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel);
240 void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel,
241 lldb::addr_t impl_addr);
243 TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr);
245 void AddToClassNameCache(lldb::addr_t class_addr, const char *name,
246 lldb::TypeSP type_sp);
248 void AddToClassNameCache(lldb::addr_t class_addr,
249 const TypeAndOrName &class_or_type_name);
251 lldb::TypeSP LookupInCompleteClassCache(ConstString &name);
253 llvm::Optional<CompilerType> GetRuntimeType(CompilerType base_type) override;
255 virtual UtilityFunction *CreateObjectChecker(const char *) = 0;
257 virtual ObjCRuntimeVersions GetRuntimeVersion() const {
258 return ObjCRuntimeVersions::eObjC_VersionUnknown;
261 bool IsValidISA(ObjCISA isa) {
262 UpdateISAToDescriptorMap();
263 return m_isa_to_descriptor.count(isa) > 0;
266 virtual void UpdateISAToDescriptorMapIfNeeded() = 0;
268 void UpdateISAToDescriptorMap() {
269 if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) {
270 UpdateISAToDescriptorMapIfNeeded();
274 virtual ObjCISA GetISA(ConstString name);
276 virtual ConstString GetActualTypeName(ObjCISA isa);
278 virtual ObjCISA GetParentClass(ObjCISA isa);
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.
283 virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,
284 const char *ivar_name);
286 bool HasNewLiteralsAndIndexing() {
287 if (m_has_new_literals_and_indexing == eLazyBoolCalculate) {
288 if (CalculateHasNewLiteralsAndIndexing())
289 m_has_new_literals_and_indexing = eLazyBoolYes;
291 m_has_new_literals_and_indexing = eLazyBoolNo;
294 return (m_has_new_literals_and_indexing == eLazyBoolYes);
297 void SymbolsDidLoad(const ModuleList &module_list) override {
298 m_negative_complete_class_cache.clear();
301 bool GetTypeBitSize(const CompilerType &compiler_type,
302 uint64_t &size) override;
304 /// Check whether the name is "self" or "_cmd" and should show up in
305 /// "frame variable".
306 bool IsWhitelistedRuntimeValue(ConstString name) override;
309 // Classes that inherit from ObjCLanguageRuntime can see and modify these
310 ObjCLanguageRuntime(Process *process);
312 virtual bool CalculateHasNewLiteralsAndIndexing() { return false; }
314 bool ISAIsCached(ObjCISA isa) const {
315 return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
318 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) {
320 m_isa_to_descriptor[isa] = descriptor_sp;
326 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
327 const char *class_name);
329 bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
330 uint32_t class_name_hash) {
332 m_isa_to_descriptor[isa] = descriptor_sp;
333 m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
340 // We keep a map of <Class,Selector>->Implementation so we don't have to call
341 // the resolver function over and over.
343 // FIXME: We need to watch for the loading of Protocols, and flush the cache
345 // class that we see so changed.
349 sel_addr = LLDB_INVALID_ADDRESS;
350 class_addr = LLDB_INVALID_ADDRESS;
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) {}
356 bool operator==(const ClassAndSel &rhs) {
357 if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr)
363 bool operator<(const ClassAndSel &rhs) const {
364 if (class_addr < rhs.class_addr)
366 else if (class_addr > rhs.class_addr)
369 if (sel_addr < rhs.sel_addr)
376 lldb::addr_t class_addr;
377 lldb::addr_t sel_addr;
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;
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;
394 uint32_t m_isa_to_descriptor_stop_id;
396 typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
397 CompleteClassMap m_complete_class_cache;
399 struct ConstStringSetHelpers {
400 size_t operator()(ConstString arg) const // for hashing
402 return (size_t)arg.GetCString();
404 bool operator()(ConstString arg1,
405 ConstString arg2) const // for equality
407 return arg1.operator==(arg2);
410 typedef std::unordered_set<ConstString, ConstStringSetHelpers,
411 ConstStringSetHelpers>
413 CompleteClassSet m_negative_complete_class_cache;
415 ISAToDescriptorIterator GetDescriptorIterator(ConstString name);
417 friend class ::CommandObjectObjC_ClassTable_Dump;
419 std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator>
420 GetDescriptorIteratorPair(bool update_if_needed = true);
422 void ReadObjCLibraryIfNeeded(const ModuleList &module_list);
424 DISALLOW_COPY_AND_ASSIGN(ObjCLanguageRuntime);
427 } // namespace lldb_private
429 #endif // liblldb_ObjCLanguageRuntime_h_