xref: /llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h (revision 8f8dcedb007c21412956208e524ff245c0ba5f58)
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 
24 class RemoteNXMapTable;
25 
26 namespace lldb_private {
27 
28 class AppleObjCRuntimeV2 : public AppleObjCRuntime {
29 public:
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(&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 
109   StructuredData::ObjectSP GetLanguageSpecificData(SymbolContext sc) override;
110 
111 protected:
112   lldb::BreakpointResolverSP
113   CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
114                           bool throw_bp) override;
115 
116 private:
117   class HashTableSignature {
118   public:
119     HashTableSignature();
120 
121     bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,
122                      RemoteNXMapTable &hash_table);
123 
124     void UpdateSignature(const RemoteNXMapTable &hash_table);
125 
126   protected:
127     uint32_t m_count = 0;
128     uint32_t m_num_buckets = 0;
129     lldb::addr_t m_buckets_ptr = 0;
130   };
131 
132   class NonPointerISACache {
133   public:
134     static NonPointerISACache *
135     CreateInstance(AppleObjCRuntimeV2 &runtime,
136                    const lldb::ModuleSP &objc_module_sp);
137 
138     ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);
139 
140   private:
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);
151 
152     bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);
153 
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;
160 
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;
166 
167     std::vector<lldb::addr_t> m_indexed_isa_cache;
168 
169     friend class AppleObjCRuntimeV2;
170 
171     NonPointerISACache(const NonPointerISACache &) = delete;
172     const NonPointerISACache &operator=(const NonPointerISACache &) = delete;
173   };
174 
175   class TaggedPointerVendorV2
176       : public ObjCLanguageRuntime::TaggedPointerVendor {
177   public:
178     ~TaggedPointerVendorV2() override = default;
179 
180     static TaggedPointerVendorV2 *
181     CreateInstance(AppleObjCRuntimeV2 &runtime,
182                    const lldb::ModuleSP &objc_module_sp);
183 
184   protected:
185     AppleObjCRuntimeV2 &m_runtime;
186 
187     TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
188         : TaggedPointerVendor(), m_runtime(runtime) {}
189 
190   private:
191     TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;
192     const TaggedPointerVendorV2 &
193     operator=(const TaggedPointerVendorV2 &) = delete;
194   };
195 
196   class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
197   public:
198     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
199 
200     ObjCLanguageRuntime::ClassDescriptorSP
201     GetClassDescriptor(lldb::addr_t ptr) override;
202 
203   protected:
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);
211 
212     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
213     typedef Cache::iterator CacheIterator;
214     Cache m_cache;
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;
221 
222     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
223 
224     TaggedPointerVendorRuntimeAssisted(
225         const TaggedPointerVendorRuntimeAssisted &) = delete;
226     const TaggedPointerVendorRuntimeAssisted &
227     operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;
228   };
229 
230   class TaggedPointerVendorExtended
231       : public TaggedPointerVendorRuntimeAssisted {
232   public:
233     ObjCLanguageRuntime::ClassDescriptorSP
234     GetClassDescriptor(lldb::addr_t ptr) override;
235 
236   protected:
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);
250 
251     bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
252 
253     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
254     typedef Cache::iterator CacheIterator;
255     Cache m_ext_cache;
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;
262 
263     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
264 
265     TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;
266     const TaggedPointerVendorExtended &
267     operator=(const TaggedPointerVendorExtended &) = delete;
268   };
269 
270   class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
271   public:
272     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
273 
274     ObjCLanguageRuntime::ClassDescriptorSP
275     GetClassDescriptor(lldb::addr_t ptr) override;
276 
277   protected:
278     TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
279         : TaggedPointerVendorV2(runtime) {}
280 
281     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
282 
283     TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;
284     const TaggedPointerVendorLegacy &
285     operator=(const TaggedPointerVendorLegacy &) = delete;
286   };
287 
288   struct DescriptorMapUpdateResult {
289     bool m_update_ran;
290     bool m_retry_update;
291     uint32_t m_num_found;
292 
293     DescriptorMapUpdateResult(bool ran, bool retry, uint32_t found) {
294       m_update_ran = ran;
295 
296       m_retry_update = retry;
297 
298       m_num_found = found;
299     }
300 
301     static DescriptorMapUpdateResult Fail() { return {false, false, 0}; }
302 
303     static DescriptorMapUpdateResult Success(uint32_t found) {
304       return {true, false, found};
305     }
306 
307     static DescriptorMapUpdateResult Retry() { return {false, true, 0}; }
308   };
309 
310   /// Abstraction to read the Objective-C class info.
311   class ClassInfoExtractor {
312   public:
313     ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}
314     std::mutex &GetMutex() { return m_mutex; }
315 
316   protected:
317     /// The lifetime of this object is tied to that of the runtime.
318     AppleObjCRuntimeV2 &m_runtime;
319     std::mutex m_mutex;
320   };
321 
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.
327   ///
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 {
333   public:
334     DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
335         : ClassInfoExtractor(runtime) {}
336 
337     DescriptorMapUpdateResult
338     UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);
339 
340   private:
341     enum Helper {
342       gdb_objc_realized_classes,
343       objc_copyRealizedClassList,
344       objc_getRealizedClassList_trylock
345     };
346 
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;
352 
353     UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
354                                                  Helper helper);
355     lldb::addr_t &GetClassInfoArgs(Helper helper);
356 
357     std::unique_ptr<UtilityFunction>
358     GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper,
359                                     std::string code, std::string name);
360 
361     struct UtilityFunctionHelper {
362       std::unique_ptr<UtilityFunction> utility_function;
363       lldb::addr_t args = LLDB_INVALID_ADDRESS;
364     };
365 
366     UtilityFunctionHelper m_gdb_objc_realized_classes_helper;
367     UtilityFunctionHelper m_objc_copyRealizedClassList_helper;
368     UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper;
369   };
370 
371   /// Abstraction to read the Objective-C class info from the shared cache.
372   class SharedCacheClassInfoExtractor : public ClassInfoExtractor {
373   public:
374     SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
375         : ClassInfoExtractor(runtime) {}
376 
377     DescriptorMapUpdateResult UpdateISAToDescriptorMap();
378 
379   private:
380     UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);
381 
382     std::unique_ptr<UtilityFunction>
383     GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);
384 
385     std::unique_ptr<UtilityFunction> m_utility_function;
386     lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
387   };
388 
389   class SharedCacheImageHeaders {
390   public:
391     static std::unique_ptr<SharedCacheImageHeaders>
392     CreateSharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime);
393 
394     void SetNeedsUpdate() { m_needs_update = true; }
395 
396     bool IsImageLoaded(uint16_t image_index);
397 
398     uint64_t GetVersion();
399 
400   private:
401     SharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime,
402                             lldb::addr_t headerInfoRWs_ptr, uint32_t count,
403                             uint32_t entsize)
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();
408 
409     AppleObjCRuntimeV2 &m_runtime;
410     lldb::addr_t m_headerInfoRWs_ptr;
411     llvm::BitVector m_loaded_images;
412     uint64_t m_version;
413     uint32_t m_count;
414     uint32_t m_entsize;
415     bool m_needs_update;
416   };
417 
418   AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
419 
420   ObjCISA GetPointerISA(ObjCISA isa);
421 
422   lldb::addr_t GetISAHashTablePointer();
423 
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();
429 
430   uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
431                                uint32_t num_class_infos);
432 
433   enum class SharedCacheWarningReason {
434     eExpressionUnableToRun,
435     eExpressionExecutionFailure,
436     eNotEnoughClassesRead
437   };
438 
439   void WarnIfNoClassesCached(SharedCacheWarningReason reason);
440   void WarnIfNoExpandedSharedCache();
441 
442   lldb::addr_t GetSharedCacheReadOnlyAddress();
443   lldb::addr_t GetSharedCacheBaseAddress();
444 
445   bool GetCFBooleanValuesIfNeeded();
446 
447   bool HasSymbol(ConstString Name);
448 
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();
454   }
455 
456   friend class ClassDescriptorV2;
457 
458   lldb::ModuleSP m_objc_module_sp;
459 
460   DynamicClassInfoExtractor m_dynamic_class_info_extractor;
461   SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;
462 
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;
480 };
481 
482 } // namespace lldb_private
483 
484 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
485