1 //===-- AppleObjCRuntimeV2.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_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
10 #define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
17 #include "AppleObjCRuntime.h"
18 #include "lldb/lldb-private.h"
20 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
22 #include "llvm/ADT/BitVector.h"
24 class RemoteNXMapTable
;
26 namespace lldb_private
{
28 class AppleObjCRuntimeV2
: public AppleObjCRuntime
{
30 ~AppleObjCRuntimeV2() override
= default;
32 static void Initialize();
34 static void Terminate();
36 static lldb_private::LanguageRuntime
*
37 CreateInstance(Process
*process
, lldb::LanguageType language
);
39 static llvm::StringRef
GetPluginNameStatic() { return "apple-objc-v2"; }
41 LanguageRuntime
*GetPreferredLanguageRuntime(ValueObject
&in_value
) override
;
45 bool isA(const void *ClassID
) const override
{
46 return ClassID
== &ID
|| AppleObjCRuntime::isA(ClassID
);
49 static bool classof(const LanguageRuntime
*runtime
) {
50 return runtime
->isA(&ID
);
53 bool GetDynamicTypeAndAddress(ValueObject
&in_value
,
54 lldb::DynamicValueType use_dynamic
,
55 TypeAndOrName
&class_type_or_name
,
57 Value::ValueType
&value_type
) override
;
59 llvm::Expected
<std::unique_ptr
<UtilityFunction
>>
60 CreateObjectChecker(std::string name
, ExecutionContext
&exe_ctx
) override
;
62 llvm::StringRef
GetPluginName() override
{ return GetPluginNameStatic(); }
64 ObjCRuntimeVersions
GetRuntimeVersion() const override
{
65 return ObjCRuntimeVersions::eAppleObjC_V2
;
68 size_t GetByteOffsetForIvar(CompilerType
&parent_ast_type
,
69 const char *ivar_name
) override
;
71 void UpdateISAToDescriptorMapIfNeeded() override
;
73 ClassDescriptorSP
GetClassDescriptor(ValueObject
&valobj
) override
;
75 ClassDescriptorSP
GetClassDescriptorFromISA(ObjCISA isa
) override
;
77 DeclVendor
*GetDeclVendor() override
;
79 lldb::addr_t
LookupRuntimeSymbol(ConstString name
) override
;
81 EncodingToTypeSP
GetEncodingToType() override
;
83 bool IsTaggedPointer(lldb::addr_t ptr
) override
;
85 TaggedPointerVendor
*GetTaggedPointerVendor() override
{
86 return m_tagged_pointer_vendor_up
.get();
89 lldb::addr_t
GetTaggedPointerObfuscator();
91 /// Returns the base address for relative method list selector strings.
92 lldb::addr_t
GetRelativeSelectorBaseAddr() {
93 return m_relative_selector_base
;
96 void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base
) {
97 m_relative_selector_base
= relative_selector_base
;
100 void GetValuesForGlobalCFBooleans(lldb::addr_t
&cf_true
,
101 lldb::addr_t
&cf_false
) override
;
103 void ModulesDidLoad(const ModuleList
&module_list
) override
;
105 bool IsSharedCacheImageLoaded(uint16_t image_index
);
107 std::optional
<uint64_t> GetSharedCacheImageHeaderVersion();
109 StructuredData::ObjectSP
GetLanguageSpecificData(SymbolContext sc
) override
;
112 lldb::BreakpointResolverSP
113 CreateExceptionResolver(const lldb::BreakpointSP
&bkpt
, bool catch_bp
,
114 bool throw_bp
) override
;
117 class HashTableSignature
{
119 HashTableSignature();
121 bool NeedsUpdate(Process
*process
, AppleObjCRuntimeV2
*runtime
,
122 RemoteNXMapTable
&hash_table
);
124 void UpdateSignature(const RemoteNXMapTable
&hash_table
);
127 uint32_t m_count
= 0;
128 uint32_t m_num_buckets
= 0;
129 lldb::addr_t m_buckets_ptr
= 0;
132 class NonPointerISACache
{
134 static NonPointerISACache
*
135 CreateInstance(AppleObjCRuntimeV2
&runtime
,
136 const lldb::ModuleSP
&objc_module_sp
);
138 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ObjCISA isa
);
141 NonPointerISACache(AppleObjCRuntimeV2
&runtime
,
142 const lldb::ModuleSP
&objc_module_sp
,
143 uint64_t objc_debug_isa_class_mask
,
144 uint64_t objc_debug_isa_magic_mask
,
145 uint64_t objc_debug_isa_magic_value
,
146 uint64_t objc_debug_indexed_isa_magic_mask
,
147 uint64_t objc_debug_indexed_isa_magic_value
,
148 uint64_t objc_debug_indexed_isa_index_mask
,
149 uint64_t objc_debug_indexed_isa_index_shift
,
150 lldb::addr_t objc_indexed_classes
);
152 bool EvaluateNonPointerISA(ObjCISA isa
, ObjCISA
&ret_isa
);
154 AppleObjCRuntimeV2
&m_runtime
;
155 std::map
<ObjCISA
, ObjCLanguageRuntime::ClassDescriptorSP
> m_cache
;
156 lldb::ModuleWP m_objc_module_wp
;
157 uint64_t m_objc_debug_isa_class_mask
;
158 uint64_t m_objc_debug_isa_magic_mask
;
159 uint64_t m_objc_debug_isa_magic_value
;
161 uint64_t m_objc_debug_indexed_isa_magic_mask
;
162 uint64_t m_objc_debug_indexed_isa_magic_value
;
163 uint64_t m_objc_debug_indexed_isa_index_mask
;
164 uint64_t m_objc_debug_indexed_isa_index_shift
;
165 lldb::addr_t m_objc_indexed_classes
;
167 std::vector
<lldb::addr_t
> m_indexed_isa_cache
;
169 friend class AppleObjCRuntimeV2
;
171 NonPointerISACache(const NonPointerISACache
&) = delete;
172 const NonPointerISACache
&operator=(const NonPointerISACache
&) = delete;
175 class TaggedPointerVendorV2
176 : public ObjCLanguageRuntime::TaggedPointerVendor
{
178 ~TaggedPointerVendorV2() override
= default;
180 static TaggedPointerVendorV2
*
181 CreateInstance(AppleObjCRuntimeV2
&runtime
,
182 const lldb::ModuleSP
&objc_module_sp
);
185 AppleObjCRuntimeV2
&m_runtime
;
187 TaggedPointerVendorV2(AppleObjCRuntimeV2
&runtime
)
188 : TaggedPointerVendor(), m_runtime(runtime
) {}
191 TaggedPointerVendorV2(const TaggedPointerVendorV2
&) = delete;
192 const TaggedPointerVendorV2
&
193 operator=(const TaggedPointerVendorV2
&) = delete;
196 class TaggedPointerVendorRuntimeAssisted
: public TaggedPointerVendorV2
{
198 bool IsPossibleTaggedPointer(lldb::addr_t ptr
) override
;
200 ObjCLanguageRuntime::ClassDescriptorSP
201 GetClassDescriptor(lldb::addr_t ptr
) override
;
204 TaggedPointerVendorRuntimeAssisted(
205 AppleObjCRuntimeV2
&runtime
, uint64_t objc_debug_taggedpointer_mask
,
206 uint32_t objc_debug_taggedpointer_slot_shift
,
207 uint32_t objc_debug_taggedpointer_slot_mask
,
208 uint32_t objc_debug_taggedpointer_payload_lshift
,
209 uint32_t objc_debug_taggedpointer_payload_rshift
,
210 lldb::addr_t objc_debug_taggedpointer_classes
);
212 typedef std::map
<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP
> Cache
;
213 typedef Cache::iterator CacheIterator
;
215 uint64_t m_objc_debug_taggedpointer_mask
;
216 uint32_t m_objc_debug_taggedpointer_slot_shift
;
217 uint32_t m_objc_debug_taggedpointer_slot_mask
;
218 uint32_t m_objc_debug_taggedpointer_payload_lshift
;
219 uint32_t m_objc_debug_taggedpointer_payload_rshift
;
220 lldb::addr_t m_objc_debug_taggedpointer_classes
;
222 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2
;
224 TaggedPointerVendorRuntimeAssisted(
225 const TaggedPointerVendorRuntimeAssisted
&) = delete;
226 const TaggedPointerVendorRuntimeAssisted
&
227 operator=(const TaggedPointerVendorRuntimeAssisted
&) = delete;
230 class TaggedPointerVendorExtended
231 : public TaggedPointerVendorRuntimeAssisted
{
233 ObjCLanguageRuntime::ClassDescriptorSP
234 GetClassDescriptor(lldb::addr_t ptr
) override
;
237 TaggedPointerVendorExtended(
238 AppleObjCRuntimeV2
&runtime
, uint64_t objc_debug_taggedpointer_mask
,
239 uint64_t objc_debug_taggedpointer_ext_mask
,
240 uint32_t objc_debug_taggedpointer_slot_shift
,
241 uint32_t objc_debug_taggedpointer_ext_slot_shift
,
242 uint32_t objc_debug_taggedpointer_slot_mask
,
243 uint32_t objc_debug_taggedpointer_ext_slot_mask
,
244 uint32_t objc_debug_taggedpointer_payload_lshift
,
245 uint32_t objc_debug_taggedpointer_payload_rshift
,
246 uint32_t objc_debug_taggedpointer_ext_payload_lshift
,
247 uint32_t objc_debug_taggedpointer_ext_payload_rshift
,
248 lldb::addr_t objc_debug_taggedpointer_classes
,
249 lldb::addr_t objc_debug_taggedpointer_ext_classes
);
251 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr
);
253 typedef std::map
<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP
> Cache
;
254 typedef Cache::iterator CacheIterator
;
256 uint64_t m_objc_debug_taggedpointer_ext_mask
;
257 uint32_t m_objc_debug_taggedpointer_ext_slot_shift
;
258 uint32_t m_objc_debug_taggedpointer_ext_slot_mask
;
259 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift
;
260 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift
;
261 lldb::addr_t m_objc_debug_taggedpointer_ext_classes
;
263 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2
;
265 TaggedPointerVendorExtended(const TaggedPointerVendorExtended
&) = delete;
266 const TaggedPointerVendorExtended
&
267 operator=(const TaggedPointerVendorExtended
&) = delete;
270 class TaggedPointerVendorLegacy
: public TaggedPointerVendorV2
{
272 bool IsPossibleTaggedPointer(lldb::addr_t ptr
) override
;
274 ObjCLanguageRuntime::ClassDescriptorSP
275 GetClassDescriptor(lldb::addr_t ptr
) override
;
278 TaggedPointerVendorLegacy(AppleObjCRuntimeV2
&runtime
)
279 : TaggedPointerVendorV2(runtime
) {}
281 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2
;
283 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy
&) = delete;
284 const TaggedPointerVendorLegacy
&
285 operator=(const TaggedPointerVendorLegacy
&) = delete;
288 struct DescriptorMapUpdateResult
{
291 uint32_t m_num_found
;
293 DescriptorMapUpdateResult(bool ran
, bool retry
, uint32_t found
) {
296 m_retry_update
= retry
;
301 static DescriptorMapUpdateResult
Fail() { return {false, false, 0}; }
303 static DescriptorMapUpdateResult
Success(uint32_t found
) {
304 return {true, false, found
};
307 static DescriptorMapUpdateResult
Retry() { return {false, true, 0}; }
310 /// Abstraction to read the Objective-C class info.
311 class ClassInfoExtractor
{
313 ClassInfoExtractor(AppleObjCRuntimeV2
&runtime
) : m_runtime(runtime
) {}
314 std::mutex
&GetMutex() { return m_mutex
; }
317 /// The lifetime of this object is tied to that of the runtime.
318 AppleObjCRuntimeV2
&m_runtime
;
322 /// We can read the class info from the Objective-C runtime using
323 /// gdb_objc_realized_classes, objc_copyRealizedClassList or
324 /// objc_getRealizedClassList_trylock. The RealizedClassList variants are
325 /// preferred because they include lazily named classes, but they are not
326 /// always available or safe to call.
328 /// We potentially need more than one helper for the same process, because we
329 /// may need to use gdb_objc_realized_classes until dyld is initialized and
330 /// then switch over to objc_copyRealizedClassList or
331 /// objc_getRealizedClassList_trylock for lazily named classes.
332 class DynamicClassInfoExtractor
: public ClassInfoExtractor
{
334 DynamicClassInfoExtractor(AppleObjCRuntimeV2
&runtime
)
335 : ClassInfoExtractor(runtime
) {}
337 DescriptorMapUpdateResult
338 UpdateISAToDescriptorMap(RemoteNXMapTable
&hash_table
);
342 gdb_objc_realized_classes
,
343 objc_copyRealizedClassList
,
344 objc_getRealizedClassList_trylock
347 /// Compute which helper to use. If dyld is not yet fully initialized we
348 /// must use gdb_objc_realized_classes. Otherwise, we prefer
349 /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList
350 /// respectively, depending on availability.
351 Helper
ComputeHelper(ExecutionContext
&exe_ctx
) const;
353 UtilityFunction
*GetClassInfoUtilityFunction(ExecutionContext
&exe_ctx
,
355 lldb::addr_t
&GetClassInfoArgs(Helper helper
);
357 std::unique_ptr
<UtilityFunction
>
358 GetClassInfoUtilityFunctionImpl(ExecutionContext
&exe_ctx
, Helper helper
,
359 std::string code
, std::string name
);
361 struct UtilityFunctionHelper
{
362 std::unique_ptr
<UtilityFunction
> utility_function
;
363 lldb::addr_t args
= LLDB_INVALID_ADDRESS
;
366 UtilityFunctionHelper m_gdb_objc_realized_classes_helper
;
367 UtilityFunctionHelper m_objc_copyRealizedClassList_helper
;
368 UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper
;
371 /// Abstraction to read the Objective-C class info from the shared cache.
372 class SharedCacheClassInfoExtractor
: public ClassInfoExtractor
{
374 SharedCacheClassInfoExtractor(AppleObjCRuntimeV2
&runtime
)
375 : ClassInfoExtractor(runtime
) {}
377 DescriptorMapUpdateResult
UpdateISAToDescriptorMap();
380 UtilityFunction
*GetClassInfoUtilityFunction(ExecutionContext
&exe_ctx
);
382 std::unique_ptr
<UtilityFunction
>
383 GetClassInfoUtilityFunctionImpl(ExecutionContext
&exe_ctx
);
385 std::unique_ptr
<UtilityFunction
> m_utility_function
;
386 lldb::addr_t m_args
= LLDB_INVALID_ADDRESS
;
389 class SharedCacheImageHeaders
{
391 static std::unique_ptr
<SharedCacheImageHeaders
>
392 CreateSharedCacheImageHeaders(AppleObjCRuntimeV2
&runtime
);
394 void SetNeedsUpdate() { m_needs_update
= true; }
396 bool IsImageLoaded(uint16_t image_index
);
398 uint64_t GetVersion();
401 SharedCacheImageHeaders(AppleObjCRuntimeV2
&runtime
,
402 lldb::addr_t headerInfoRWs_ptr
, uint32_t count
,
404 : m_runtime(runtime
), m_headerInfoRWs_ptr(headerInfoRWs_ptr
),
405 m_loaded_images(count
, false), m_version(0), m_count(count
),
406 m_entsize(entsize
), m_needs_update(true) {}
407 llvm::Error
UpdateIfNeeded();
409 AppleObjCRuntimeV2
&m_runtime
;
410 lldb::addr_t m_headerInfoRWs_ptr
;
411 llvm::BitVector m_loaded_images
;
418 AppleObjCRuntimeV2(Process
*process
, const lldb::ModuleSP
&objc_module_sp
);
420 ObjCISA
GetPointerISA(ObjCISA isa
);
422 lldb::addr_t
GetISAHashTablePointer();
424 /// Update the generation count of realized classes. This is not an exact
425 /// count but rather a value that is incremented when new classes are realized
426 /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will
427 /// change when lazily named classes get realized.
428 bool RealizedClassGenerationCountChanged();
430 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor
&data
,
431 uint32_t num_class_infos
);
433 enum class SharedCacheWarningReason
{
434 eExpressionUnableToRun
,
435 eExpressionExecutionFailure
,
436 eNotEnoughClassesRead
439 void WarnIfNoClassesCached(SharedCacheWarningReason reason
);
440 void WarnIfNoExpandedSharedCache();
442 lldb::addr_t
GetSharedCacheReadOnlyAddress();
443 lldb::addr_t
GetSharedCacheBaseAddress();
445 bool GetCFBooleanValuesIfNeeded();
447 bool HasSymbol(ConstString Name
);
449 NonPointerISACache
*GetNonPointerIsaCache() {
450 if (!m_non_pointer_isa_cache_up
)
451 m_non_pointer_isa_cache_up
.reset(
452 NonPointerISACache::CreateInstance(*this, m_objc_module_sp
));
453 return m_non_pointer_isa_cache_up
.get();
456 friend class ClassDescriptorV2
;
458 lldb::ModuleSP m_objc_module_sp
;
460 DynamicClassInfoExtractor m_dynamic_class_info_extractor
;
461 SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor
;
463 std::unique_ptr
<DeclVendor
> m_decl_vendor_up
;
464 lldb::addr_t m_tagged_pointer_obfuscator
;
465 lldb::addr_t m_isa_hash_table_ptr
;
466 lldb::addr_t m_relative_selector_base
;
467 HashTableSignature m_hash_signature
;
468 bool m_has_object_getClass
;
469 bool m_has_objc_copyRealizedClassList
;
470 bool m_has_objc_getRealizedClassList_trylock
;
471 bool m_loaded_objc_opt
;
472 std::unique_ptr
<NonPointerISACache
> m_non_pointer_isa_cache_up
;
473 std::unique_ptr
<TaggedPointerVendor
> m_tagged_pointer_vendor_up
;
474 EncodingToTypeSP m_encoding_to_type_sp
;
475 std::once_flag m_no_classes_cached_warning
;
476 std::once_flag m_no_expanded_cache_warning
;
477 std::optional
<std::pair
<lldb::addr_t
, lldb::addr_t
>> m_CFBoolean_values
;
478 uint64_t m_realized_class_generation_count
;
479 std::unique_ptr
<SharedCacheImageHeaders
> m_shared_cache_image_headers_up
;
482 } // namespace lldb_private
484 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H