1//===-- AppleObjCRuntimeV2.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 LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
10#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
11
12#include <map>
13#include <memory>
14#include <mutex>
15#include <optional>
16
17#include "AppleObjCRuntime.h"
18#include "lldb/lldb-private.h"
19
20#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
21
22#include "llvm/ADT/BitVector.h"
23
24class RemoteNXMapTable;
25
26namespace lldb_private {
27
28class AppleObjCRuntimeV2 : public AppleObjCRuntime {
29public:
30 ~AppleObjCRuntimeV2() override = default;
31
32 static void Initialize();
33
34 static void Terminate();
35
36 static lldb_private::LanguageRuntime *
37 CreateInstance(Process *process, lldb::LanguageType language);
38
39 static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; }
40
41 LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) override;
42
43 static char ID;
44
45 bool isA(const void *ClassID) const override {
46 return ClassID == &ID || AppleObjCRuntime::isA(ClassID);
47 }
48
49 static bool classof(const LanguageRuntime *runtime) {
50 return runtime->isA(ClassID: &ID);
51 }
52
53 bool GetDynamicTypeAndAddress(ValueObject &in_value,
54 lldb::DynamicValueType use_dynamic,
55 TypeAndOrName &class_type_or_name,
56 Address &address,
57 Value::ValueType &value_type) override;
58
59 llvm::Expected<std::unique_ptr<UtilityFunction>>
60 CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
61
62 llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
63
64 ObjCRuntimeVersions GetRuntimeVersion() const override {
65 return ObjCRuntimeVersions::eAppleObjC_V2;
66 }
67
68 size_t GetByteOffsetForIvar(CompilerType &parent_ast_type,
69 const char *ivar_name) override;
70
71 void UpdateISAToDescriptorMapIfNeeded() override;
72
73 ClassDescriptorSP GetClassDescriptor(ValueObject &valobj) override;
74
75 ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override;
76
77 DeclVendor *GetDeclVendor() override;
78
79 lldb::addr_t LookupRuntimeSymbol(ConstString name) override;
80
81 EncodingToTypeSP GetEncodingToType() override;
82
83 bool IsTaggedPointer(lldb::addr_t ptr) override;
84
85 TaggedPointerVendor *GetTaggedPointerVendor() override {
86 return m_tagged_pointer_vendor_up.get();
87 }
88
89 lldb::addr_t GetTaggedPointerObfuscator();
90
91 /// Returns the base address for relative method list selector strings.
92 lldb::addr_t GetRelativeSelectorBaseAddr() {
93 return m_relative_selector_base;
94 }
95
96 void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) {
97 m_relative_selector_base = relative_selector_base;
98 }
99
100 void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
101 lldb::addr_t &cf_false) override;
102
103 void ModulesDidLoad(const ModuleList &module_list) override;
104
105 bool IsSharedCacheImageLoaded(uint16_t image_index);
106
107 std::optional<uint64_t> GetSharedCacheImageHeaderVersion();
108
109protected:
110 lldb::BreakpointResolverSP
111 CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
112 bool throw_bp) override;
113
114private:
115 class HashTableSignature {
116 public:
117 HashTableSignature();
118
119 bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,
120 RemoteNXMapTable &hash_table);
121
122 void UpdateSignature(const RemoteNXMapTable &hash_table);
123
124 protected:
125 uint32_t m_count = 0;
126 uint32_t m_num_buckets = 0;
127 lldb::addr_t m_buckets_ptr = 0;
128 };
129
130 class NonPointerISACache {
131 public:
132 static NonPointerISACache *
133 CreateInstance(AppleObjCRuntimeV2 &runtime,
134 const lldb::ModuleSP &objc_module_sp);
135
136 ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);
137
138 private:
139 NonPointerISACache(AppleObjCRuntimeV2 &runtime,
140 const lldb::ModuleSP &objc_module_sp,
141 uint64_t objc_debug_isa_class_mask,
142 uint64_t objc_debug_isa_magic_mask,
143 uint64_t objc_debug_isa_magic_value,
144 uint64_t objc_debug_indexed_isa_magic_mask,
145 uint64_t objc_debug_indexed_isa_magic_value,
146 uint64_t objc_debug_indexed_isa_index_mask,
147 uint64_t objc_debug_indexed_isa_index_shift,
148 lldb::addr_t objc_indexed_classes);
149
150 bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);
151
152 AppleObjCRuntimeV2 &m_runtime;
153 std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache;
154 lldb::ModuleWP m_objc_module_wp;
155 uint64_t m_objc_debug_isa_class_mask;
156 uint64_t m_objc_debug_isa_magic_mask;
157 uint64_t m_objc_debug_isa_magic_value;
158
159 uint64_t m_objc_debug_indexed_isa_magic_mask;
160 uint64_t m_objc_debug_indexed_isa_magic_value;
161 uint64_t m_objc_debug_indexed_isa_index_mask;
162 uint64_t m_objc_debug_indexed_isa_index_shift;
163 lldb::addr_t m_objc_indexed_classes;
164
165 std::vector<lldb::addr_t> m_indexed_isa_cache;
166
167 friend class AppleObjCRuntimeV2;
168
169 NonPointerISACache(const NonPointerISACache &) = delete;
170 const NonPointerISACache &operator=(const NonPointerISACache &) = delete;
171 };
172
173 class TaggedPointerVendorV2
174 : public ObjCLanguageRuntime::TaggedPointerVendor {
175 public:
176 ~TaggedPointerVendorV2() override = default;
177
178 static TaggedPointerVendorV2 *
179 CreateInstance(AppleObjCRuntimeV2 &runtime,
180 const lldb::ModuleSP &objc_module_sp);
181
182 protected:
183 AppleObjCRuntimeV2 &m_runtime;
184
185 TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
186 : TaggedPointerVendor(), m_runtime(runtime) {}
187
188 private:
189 TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;
190 const TaggedPointerVendorV2 &
191 operator=(const TaggedPointerVendorV2 &) = delete;
192 };
193
194 class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
195 public:
196 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
197
198 ObjCLanguageRuntime::ClassDescriptorSP
199 GetClassDescriptor(lldb::addr_t ptr) override;
200
201 protected:
202 TaggedPointerVendorRuntimeAssisted(
203 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
204 uint32_t objc_debug_taggedpointer_slot_shift,
205 uint32_t objc_debug_taggedpointer_slot_mask,
206 uint32_t objc_debug_taggedpointer_payload_lshift,
207 uint32_t objc_debug_taggedpointer_payload_rshift,
208 lldb::addr_t objc_debug_taggedpointer_classes);
209
210 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
211 typedef Cache::iterator CacheIterator;
212 Cache m_cache;
213 uint64_t m_objc_debug_taggedpointer_mask;
214 uint32_t m_objc_debug_taggedpointer_slot_shift;
215 uint32_t m_objc_debug_taggedpointer_slot_mask;
216 uint32_t m_objc_debug_taggedpointer_payload_lshift;
217 uint32_t m_objc_debug_taggedpointer_payload_rshift;
218 lldb::addr_t m_objc_debug_taggedpointer_classes;
219
220 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
221
222 TaggedPointerVendorRuntimeAssisted(
223 const TaggedPointerVendorRuntimeAssisted &) = delete;
224 const TaggedPointerVendorRuntimeAssisted &
225 operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;
226 };
227
228 class TaggedPointerVendorExtended
229 : public TaggedPointerVendorRuntimeAssisted {
230 public:
231 ObjCLanguageRuntime::ClassDescriptorSP
232 GetClassDescriptor(lldb::addr_t ptr) override;
233
234 protected:
235 TaggedPointerVendorExtended(
236 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
237 uint64_t objc_debug_taggedpointer_ext_mask,
238 uint32_t objc_debug_taggedpointer_slot_shift,
239 uint32_t objc_debug_taggedpointer_ext_slot_shift,
240 uint32_t objc_debug_taggedpointer_slot_mask,
241 uint32_t objc_debug_taggedpointer_ext_slot_mask,
242 uint32_t objc_debug_taggedpointer_payload_lshift,
243 uint32_t objc_debug_taggedpointer_payload_rshift,
244 uint32_t objc_debug_taggedpointer_ext_payload_lshift,
245 uint32_t objc_debug_taggedpointer_ext_payload_rshift,
246 lldb::addr_t objc_debug_taggedpointer_classes,
247 lldb::addr_t objc_debug_taggedpointer_ext_classes);
248
249 bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
250
251 typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
252 typedef Cache::iterator CacheIterator;
253 Cache m_ext_cache;
254 uint64_t m_objc_debug_taggedpointer_ext_mask;
255 uint32_t m_objc_debug_taggedpointer_ext_slot_shift;
256 uint32_t m_objc_debug_taggedpointer_ext_slot_mask;
257 uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;
258 uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;
259 lldb::addr_t m_objc_debug_taggedpointer_ext_classes;
260
261 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
262
263 TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;
264 const TaggedPointerVendorExtended &
265 operator=(const TaggedPointerVendorExtended &) = delete;
266 };
267
268 class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
269 public:
270 bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
271
272 ObjCLanguageRuntime::ClassDescriptorSP
273 GetClassDescriptor(lldb::addr_t ptr) override;
274
275 protected:
276 TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
277 : TaggedPointerVendorV2(runtime) {}
278
279 friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
280
281 TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;
282 const TaggedPointerVendorLegacy &
283 operator=(const TaggedPointerVendorLegacy &) = delete;
284 };
285
286 struct DescriptorMapUpdateResult {
287 bool m_update_ran;
288 bool m_retry_update;
289 uint32_t m_num_found;
290
291 DescriptorMapUpdateResult(bool ran, bool retry, uint32_t found) {
292 m_update_ran = ran;
293
294 m_retry_update = retry;
295
296 m_num_found = found;
297 }
298
299 static DescriptorMapUpdateResult Fail() { return {false, false, 0}; }
300
301 static DescriptorMapUpdateResult Success(uint32_t found) {
302 return {true, false, found};
303 }
304
305 static DescriptorMapUpdateResult Retry() { return {false, true, 0}; }
306 };
307
308 /// Abstraction to read the Objective-C class info.
309 class ClassInfoExtractor {
310 public:
311 ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}
312 std::mutex &GetMutex() { return m_mutex; }
313
314 protected:
315 /// The lifetime of this object is tied to that of the runtime.
316 AppleObjCRuntimeV2 &m_runtime;
317 std::mutex m_mutex;
318 };
319
320 /// We can read the class info from the Objective-C runtime using
321 /// gdb_objc_realized_classes, objc_copyRealizedClassList or
322 /// objc_getRealizedClassList_trylock. The RealizedClassList variants are
323 /// preferred because they include lazily named classes, but they are not
324 /// always available or safe to call.
325 ///
326 /// We potentially need more than one helper for the same process, because we
327 /// may need to use gdb_objc_realized_classes until dyld is initialized and
328 /// then switch over to objc_copyRealizedClassList or
329 /// objc_getRealizedClassList_trylock for lazily named classes.
330 class DynamicClassInfoExtractor : public ClassInfoExtractor {
331 public:
332 DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
333 : ClassInfoExtractor(runtime) {}
334
335 DescriptorMapUpdateResult
336 UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);
337
338 private:
339 enum Helper {
340 gdb_objc_realized_classes,
341 objc_copyRealizedClassList,
342 objc_getRealizedClassList_trylock
343 };
344
345 /// Compute which helper to use. If dyld is not yet fully initialized we
346 /// must use gdb_objc_realized_classes. Otherwise, we prefer
347 /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList
348 /// respectively, depending on availability.
349 Helper ComputeHelper(ExecutionContext &exe_ctx) const;
350
351 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
352 Helper helper);
353 lldb::addr_t &GetClassInfoArgs(Helper helper);
354
355 std::unique_ptr<UtilityFunction>
356 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper,
357 std::string code, std::string name);
358
359 struct UtilityFunctionHelper {
360 std::unique_ptr<UtilityFunction> utility_function;
361 lldb::addr_t args = LLDB_INVALID_ADDRESS;
362 };
363
364 UtilityFunctionHelper m_gdb_objc_realized_classes_helper;
365 UtilityFunctionHelper m_objc_copyRealizedClassList_helper;
366 UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper;
367 };
368
369 /// Abstraction to read the Objective-C class info from the shared cache.
370 class SharedCacheClassInfoExtractor : public ClassInfoExtractor {
371 public:
372 SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
373 : ClassInfoExtractor(runtime) {}
374
375 DescriptorMapUpdateResult UpdateISAToDescriptorMap();
376
377 private:
378 UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);
379
380 std::unique_ptr<UtilityFunction>
381 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);
382
383 std::unique_ptr<UtilityFunction> m_utility_function;
384 lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
385 };
386
387 class SharedCacheImageHeaders {
388 public:
389 static std::unique_ptr<SharedCacheImageHeaders>
390 CreateSharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime);
391
392 void SetNeedsUpdate() { m_needs_update = true; }
393
394 bool IsImageLoaded(uint16_t image_index);
395
396 uint64_t GetVersion();
397
398 private:
399 SharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime,
400 lldb::addr_t headerInfoRWs_ptr, uint32_t count,
401 uint32_t entsize)
402 : m_runtime(runtime), m_headerInfoRWs_ptr(headerInfoRWs_ptr),
403 m_loaded_images(count, false), m_version(0), m_count(count),
404 m_entsize(entsize), m_needs_update(true) {}
405 llvm::Error UpdateIfNeeded();
406
407 AppleObjCRuntimeV2 &m_runtime;
408 lldb::addr_t m_headerInfoRWs_ptr;
409 llvm::BitVector m_loaded_images;
410 uint64_t m_version;
411 uint32_t m_count;
412 uint32_t m_entsize;
413 bool m_needs_update;
414 };
415
416 AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
417
418 ObjCISA GetPointerISA(ObjCISA isa);
419
420 lldb::addr_t GetISAHashTablePointer();
421
422 /// Update the generation count of realized classes. This is not an exact
423 /// count but rather a value that is incremented when new classes are realized
424 /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will
425 /// change when lazily named classes get realized.
426 bool RealizedClassGenerationCountChanged();
427
428 uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
429 uint32_t num_class_infos);
430
431 enum class SharedCacheWarningReason {
432 eExpressionUnableToRun,
433 eExpressionExecutionFailure,
434 eNotEnoughClassesRead
435 };
436
437 void WarnIfNoClassesCached(SharedCacheWarningReason reason);
438 void WarnIfNoExpandedSharedCache();
439
440 lldb::addr_t GetSharedCacheReadOnlyAddress();
441 lldb::addr_t GetSharedCacheBaseAddress();
442
443 bool GetCFBooleanValuesIfNeeded();
444
445 bool HasSymbol(ConstString Name);
446
447 NonPointerISACache *GetNonPointerIsaCache() {
448 if (!m_non_pointer_isa_cache_up)
449 m_non_pointer_isa_cache_up.reset(
450 p: NonPointerISACache::CreateInstance(runtime&: *this, objc_module_sp: m_objc_module_sp));
451 return m_non_pointer_isa_cache_up.get();
452 }
453
454 friend class ClassDescriptorV2;
455
456 lldb::ModuleSP m_objc_module_sp;
457
458 DynamicClassInfoExtractor m_dynamic_class_info_extractor;
459 SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;
460
461 std::unique_ptr<DeclVendor> m_decl_vendor_up;
462 lldb::addr_t m_tagged_pointer_obfuscator;
463 lldb::addr_t m_isa_hash_table_ptr;
464 lldb::addr_t m_relative_selector_base;
465 HashTableSignature m_hash_signature;
466 bool m_has_object_getClass;
467 bool m_has_objc_copyRealizedClassList;
468 bool m_has_objc_getRealizedClassList_trylock;
469 bool m_loaded_objc_opt;
470 std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
471 std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
472 EncodingToTypeSP m_encoding_to_type_sp;
473 std::once_flag m_no_classes_cached_warning;
474 std::once_flag m_no_expanded_cache_warning;
475 std::optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
476 uint64_t m_realized_class_generation_count;
477 std::unique_ptr<SharedCacheImageHeaders> m_shared_cache_image_headers_up;
478};
479
480} // namespace lldb_private
481
482#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
483

source code of lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h