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 LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H
10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H
16 #include <unordered_set>
18 #include "llvm/Support/Casting.h"
20 #include "lldb/Breakpoint/BreakpointPrecondition.h"
21 #include "lldb/Core/PluginInterface.h"
22 #include "lldb/Symbol/CompilerType.h"
23 #include "lldb/Symbol/Type.h"
24 #include "lldb/Target/LanguageRuntime.h"
25 #include "lldb/Utility/ConstString.h"
26 #include "lldb/Utility/ThreadSafeDenseMap.h"
27 #include "lldb/lldb-enumerations.h"
28 #include "lldb/lldb-private.h"
30 class CommandObjectObjC_ClassTable_Dump
;
32 namespace lldb_private
{
34 class TypeSystemClang
;
35 class UtilityFunction
;
37 class ObjCLanguageRuntime
: public LanguageRuntime
{
39 enum class ObjCRuntimeVersions
{
40 eObjC_VersionUnknown
= 0,
43 eGNUstep_libobjc2
= 3,
46 typedef lldb::addr_t ObjCISA
;
48 class ClassDescriptor
;
49 typedef std::shared_ptr
<ClassDescriptor
> ClassDescriptorSP
;
51 // the information that we want to support retrieving from an ObjC class this
52 // needs to be pure virtual since there are at least 2 different
53 // implementations of the runtime, and more might come
54 class ClassDescriptor
{
56 ClassDescriptor() : m_type_wp() {}
58 virtual ~ClassDescriptor() = default;
60 virtual ConstString
GetClassName() = 0;
62 virtual ClassDescriptorSP
GetSuperclass() = 0;
64 virtual ClassDescriptorSP
GetMetaclass() const = 0;
66 // virtual if any implementation has some other version-specific rules but
67 // for the known v1/v2 this is all that needs to be done
68 virtual bool IsKVO() {
69 if (m_is_kvo
== eLazyBoolCalculate
) {
70 const char *class_name
= GetClassName().AsCString();
71 if (class_name
&& *class_name
)
73 (LazyBool
)(strstr(class_name
, "NSKVONotifying_") == class_name
);
75 return (m_is_kvo
== eLazyBoolYes
);
78 // virtual if any implementation has some other version-specific rules but
79 // for the known v1/v2 this is all that needs to be done
80 virtual bool IsCFType() {
81 if (m_is_cf
== eLazyBoolCalculate
) {
82 const char *class_name
= GetClassName().AsCString();
83 if (class_name
&& *class_name
)
84 m_is_cf
= (LazyBool
)(strcmp(class_name
, "__NSCFType") == 0 ||
85 strcmp(class_name
, "NSCFType") == 0);
87 return (m_is_cf
== eLazyBoolYes
);
90 /// Determine whether this class is implemented in Swift.
91 virtual lldb::LanguageType
GetImplementationLanguage() const {
92 return lldb::eLanguageTypeObjC
;
95 virtual bool IsValid() = 0;
97 /// There are two routines in the ObjC runtime that tagged pointer clients
98 /// can call to get the value from their tagged pointer, one that retrieves
99 /// it as an unsigned value and one a signed value. These two
100 /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls.
102 virtual bool GetTaggedPointerInfo(uint64_t *info_bits
= nullptr,
103 uint64_t *value_bits
= nullptr,
104 uint64_t *payload
= nullptr) = 0;
106 virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits
= nullptr,
107 int64_t *value_bits
= nullptr,
108 uint64_t *payload
= nullptr) = 0;
111 virtual uint64_t GetInstanceSize() = 0;
113 // use to implement version-specific additional constraints on pointers
114 virtual bool CheckPointer(lldb::addr_t value
, uint32_t ptr_size
) const {
118 virtual ObjCISA
GetISA() = 0;
120 // This should return true iff the interface could be completed
122 Describe(std::function
<void(ObjCISA
)> const &superclass_func
,
123 std::function
<bool(const char *, const char *)> const
124 &instance_method_func
,
125 std::function
<bool(const char *, const char *)> const
127 std::function
<bool(const char *, const char *, lldb::addr_t
,
128 uint64_t)> const &ivar_func
) const {
132 lldb::TypeSP
GetType() { return m_type_wp
.lock(); }
134 void SetType(const lldb::TypeSP
&type_sp
) { m_type_wp
= type_sp
; }
136 struct iVarDescriptor
{
143 virtual size_t GetNumIVars() { return 0; }
145 virtual iVarDescriptor
GetIVarAtIndex(size_t idx
) {
146 return iVarDescriptor();
150 bool IsPointerValid(lldb::addr_t value
, uint32_t ptr_size
,
151 bool allow_NULLs
= false, bool allow_tagged
= false,
152 bool check_version_specific
= false) const;
155 LazyBool m_is_kvo
= eLazyBoolCalculate
;
156 LazyBool m_is_cf
= eLazyBoolCalculate
;
157 lldb::TypeWP m_type_wp
;
160 class EncodingToType
{
162 virtual ~EncodingToType();
164 virtual CompilerType
RealizeType(TypeSystemClang
&ast_ctx
, const char *name
,
165 bool for_expression
) = 0;
166 virtual CompilerType
RealizeType(const char *name
, bool for_expression
);
169 std::shared_ptr
<TypeSystemClang
> m_scratch_ast_ctx_sp
;
172 class ObjCExceptionPrecondition
: public BreakpointPrecondition
{
174 ObjCExceptionPrecondition();
176 ~ObjCExceptionPrecondition() override
= default;
178 bool EvaluatePrecondition(StoppointCallbackContext
&context
) override
;
179 void GetDescription(Stream
&stream
, lldb::DescriptionLevel level
) override
;
180 Status
ConfigurePrecondition(Args
&args
) override
;
183 void AddClassName(const char *class_name
);
186 std::unordered_set
<std::string
> m_class_names
;
189 static lldb::BreakpointPreconditionSP
190 GetBreakpointExceptionPrecondition(lldb::LanguageType language
,
193 class TaggedPointerVendor
{
195 virtual ~TaggedPointerVendor() = default;
197 virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr
) = 0;
199 virtual ObjCLanguageRuntime::ClassDescriptorSP
200 GetClassDescriptor(lldb::addr_t ptr
) = 0;
203 TaggedPointerVendor() = default;
206 TaggedPointerVendor(const TaggedPointerVendor
&) = delete;
207 const TaggedPointerVendor
&operator=(const TaggedPointerVendor
&) = delete;
210 ~ObjCLanguageRuntime() override
;
214 bool isA(const void *ClassID
) const override
{
215 return ClassID
== &ID
|| LanguageRuntime::isA(ClassID
);
218 static bool classof(const LanguageRuntime
*runtime
) {
219 return runtime
->isA(&ID
);
222 static ObjCLanguageRuntime
*Get(Process
&process
) {
223 return llvm::cast_or_null
<ObjCLanguageRuntime
>(
224 process
.GetLanguageRuntime(lldb::eLanguageTypeObjC
));
227 virtual TaggedPointerVendor
*GetTaggedPointerVendor() { return nullptr; }
229 typedef std::shared_ptr
<EncodingToType
> EncodingToTypeSP
;
231 virtual EncodingToTypeSP
GetEncodingToType();
233 virtual ClassDescriptorSP
GetClassDescriptor(ValueObject
&in_value
);
235 ClassDescriptorSP
GetNonKVOClassDescriptor(ValueObject
&in_value
);
237 virtual ClassDescriptorSP
238 GetClassDescriptorFromClassName(ConstString class_name
);
240 virtual ClassDescriptorSP
GetClassDescriptorFromISA(ObjCISA isa
);
242 ClassDescriptorSP
GetNonKVOClassDescriptor(ObjCISA isa
);
244 lldb::LanguageType
GetLanguageType() const override
{
245 return lldb::eLanguageTypeObjC
;
248 virtual bool IsModuleObjCLibrary(const lldb::ModuleSP
&module_sp
) = 0;
250 virtual bool ReadObjCLibrary(const lldb::ModuleSP
&module_sp
) = 0;
252 virtual bool HasReadObjCLibrary() = 0;
254 // These two methods actually use different caches. The only time we'll
255 // cache a sel_str is if we found a "selector specific stub" for the selector
256 // and conversely we only add to the SEL cache if we saw a regular dispatch.
257 lldb::addr_t
LookupInMethodCache(lldb::addr_t class_addr
, lldb::addr_t sel
);
258 lldb::addr_t
LookupInMethodCache(lldb::addr_t class_addr
,
259 llvm::StringRef sel_str
);
261 void AddToMethodCache(lldb::addr_t class_addr
, lldb::addr_t sel
,
262 lldb::addr_t impl_addr
);
264 void AddToMethodCache(lldb::addr_t class_addr
, llvm::StringRef sel_str
,
265 lldb::addr_t impl_addr
);
267 TypeAndOrName
LookupInClassNameCache(lldb::addr_t class_addr
);
269 void AddToClassNameCache(lldb::addr_t class_addr
, const char *name
,
270 lldb::TypeSP type_sp
);
272 void AddToClassNameCache(lldb::addr_t class_addr
,
273 const TypeAndOrName
&class_or_type_name
);
275 lldb::TypeSP
LookupInCompleteClassCache(ConstString
&name
);
277 std::optional
<CompilerType
> GetRuntimeType(CompilerType base_type
) override
;
279 virtual llvm::Expected
<std::unique_ptr
<UtilityFunction
>>
280 CreateObjectChecker(std::string name
, ExecutionContext
&exe_ctx
) = 0;
282 virtual ObjCRuntimeVersions
GetRuntimeVersion() const {
283 return ObjCRuntimeVersions::eObjC_VersionUnknown
;
286 bool IsValidISA(ObjCISA isa
) {
287 UpdateISAToDescriptorMap();
288 return m_isa_to_descriptor
.count(isa
) > 0;
291 virtual void UpdateISAToDescriptorMapIfNeeded() = 0;
293 void UpdateISAToDescriptorMap() {
294 if (m_process
&& m_process
->GetStopID() != m_isa_to_descriptor_stop_id
) {
295 UpdateISAToDescriptorMapIfNeeded();
299 virtual ObjCISA
GetISA(ConstString name
);
301 virtual ObjCISA
GetParentClass(ObjCISA isa
);
303 // Finds the byte offset of the child_type ivar in parent_type. If it can't
304 // find the offset, returns LLDB_INVALID_IVAR_OFFSET.
306 virtual size_t GetByteOffsetForIvar(CompilerType
&parent_qual_type
,
307 const char *ivar_name
);
309 bool HasNewLiteralsAndIndexing() {
310 if (m_has_new_literals_and_indexing
== eLazyBoolCalculate
) {
311 if (CalculateHasNewLiteralsAndIndexing())
312 m_has_new_literals_and_indexing
= eLazyBoolYes
;
314 m_has_new_literals_and_indexing
= eLazyBoolNo
;
317 return (m_has_new_literals_and_indexing
== eLazyBoolYes
);
320 void SymbolsDidLoad(const ModuleList
&module_list
) override
{
321 m_negative_complete_class_cache
.clear();
324 std::optional
<uint64_t>
325 GetTypeBitSize(const CompilerType
&compiler_type
) override
;
327 /// Check whether the name is "self" or "_cmd" and should show up in
328 /// "frame variable".
329 bool IsAllowedRuntimeValue(ConstString name
) override
;
332 // Classes that inherit from ObjCLanguageRuntime can see and modify these
333 ObjCLanguageRuntime(Process
*process
);
335 virtual bool CalculateHasNewLiteralsAndIndexing() { return false; }
337 bool ISAIsCached(ObjCISA isa
) const {
338 return m_isa_to_descriptor
.find(isa
) != m_isa_to_descriptor
.end();
341 bool AddClass(ObjCISA isa
, const ClassDescriptorSP
&descriptor_sp
) {
343 m_isa_to_descriptor
[isa
] = descriptor_sp
;
349 bool AddClass(ObjCISA isa
, const ClassDescriptorSP
&descriptor_sp
,
350 const char *class_name
);
352 bool AddClass(ObjCISA isa
, const ClassDescriptorSP
&descriptor_sp
,
353 uint32_t class_name_hash
) {
355 m_isa_to_descriptor
[isa
] = descriptor_sp
;
356 m_hash_to_isa_map
.insert(std::make_pair(class_name_hash
, isa
));
363 // We keep two maps of <Class,Selector>->Implementation so we don't have
364 // to call the resolver function over and over.
365 // The first comes from regular obj_msgSend type dispatch, and maps the
366 // class + uniqued SEL value to an implementation.
367 // The second comes from the "selector-specific stubs", which are always
368 // of the form _objc_msgSend$SelectorName, so we don't know the uniqued
369 // selector, only the string name.
371 // FIXME: We need to watch for the loading of Protocols, and flush the cache
373 // class that we see so changed.
376 ClassAndSel() = default;
378 ClassAndSel(lldb::addr_t in_class_addr
, lldb::addr_t in_sel_addr
)
379 : class_addr(in_class_addr
), sel_addr(in_sel_addr
) {}
381 bool operator==(const ClassAndSel
&rhs
) {
382 if (class_addr
== rhs
.class_addr
&& sel_addr
== rhs
.sel_addr
)
388 bool operator<(const ClassAndSel
&rhs
) const {
389 if (class_addr
< rhs
.class_addr
)
391 else if (class_addr
> rhs
.class_addr
)
394 if (sel_addr
< rhs
.sel_addr
)
401 lldb::addr_t class_addr
= LLDB_INVALID_ADDRESS
;
402 lldb::addr_t sel_addr
= LLDB_INVALID_ADDRESS
;
405 struct ClassAndSelStr
{
406 ClassAndSelStr() = default;
408 ClassAndSelStr(lldb::addr_t in_class_addr
, llvm::StringRef in_sel_name
)
409 : class_addr(in_class_addr
), sel_name(in_sel_name
) {}
411 bool operator==(const ClassAndSelStr
&rhs
) {
412 return class_addr
== rhs
.class_addr
&& sel_name
== rhs
.sel_name
;
415 bool operator<(const ClassAndSelStr
&rhs
) const {
416 if (class_addr
< rhs
.class_addr
)
418 else if (class_addr
> rhs
.class_addr
)
421 return ConstString::Compare(sel_name
, rhs
.sel_name
);
424 lldb::addr_t class_addr
= LLDB_INVALID_ADDRESS
;
425 ConstString sel_name
;
428 typedef std::map
<ClassAndSel
, lldb::addr_t
> MsgImplMap
;
429 typedef std::map
<ClassAndSelStr
, lldb::addr_t
> MsgImplStrMap
;
430 typedef std::map
<ObjCISA
, ClassDescriptorSP
> ISAToDescriptorMap
;
431 typedef std::multimap
<uint32_t, ObjCISA
> HashToISAMap
;
432 typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator
;
433 typedef HashToISAMap::iterator HashToISAIterator
;
434 typedef ThreadSafeDenseMap
<void *, uint64_t> TypeSizeCache
;
436 MsgImplMap m_impl_cache
;
437 MsgImplStrMap m_impl_str_cache
;
438 LazyBool m_has_new_literals_and_indexing
;
439 ISAToDescriptorMap m_isa_to_descriptor
;
440 HashToISAMap m_hash_to_isa_map
;
441 TypeSizeCache m_type_size_cache
;
444 uint32_t m_isa_to_descriptor_stop_id
;
446 typedef std::map
<ConstString
, lldb::TypeWP
> CompleteClassMap
;
447 CompleteClassMap m_complete_class_cache
;
449 struct ConstStringSetHelpers
{
450 size_t operator()(ConstString arg
) const // for hashing
452 return (size_t)arg
.GetCString();
454 bool operator()(ConstString arg1
,
455 ConstString arg2
) const // for equality
457 return arg1
.operator==(arg2
);
460 typedef std::unordered_set
<ConstString
, ConstStringSetHelpers
,
461 ConstStringSetHelpers
>
463 CompleteClassSet m_negative_complete_class_cache
;
465 ISAToDescriptorIterator
GetDescriptorIterator(ConstString name
);
467 friend class ::CommandObjectObjC_ClassTable_Dump
;
469 std::pair
<ISAToDescriptorIterator
, ISAToDescriptorIterator
>
470 GetDescriptorIteratorPair(bool update_if_needed
= true);
472 void ReadObjCLibraryIfNeeded(const ModuleList
&module_list
);
474 ObjCLanguageRuntime(const ObjCLanguageRuntime
&) = delete;
475 const ObjCLanguageRuntime
&operator=(const ObjCLanguageRuntime
&) = delete;
478 } // namespace lldb_private
480 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H