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 
16 #include "AppleObjCRuntime.h"
17 #include "lldb/lldb-private.h"
18 
19 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
20 
21 class RemoteNXMapTable;
22 
23 namespace lldb_private {
24 
25 class AppleObjCRuntimeV2 : public AppleObjCRuntime {
26 public:
27   ~AppleObjCRuntimeV2() override = default;
28 
29   // Static Functions
30   static void Initialize();
31 
32   static void Terminate();
33 
34   static lldb_private::LanguageRuntime *
35   CreateInstance(Process *process, lldb::LanguageType language);
36 
37   static lldb_private::ConstString GetPluginNameStatic();
38 
39   static char ID;
40 
41   bool isA(const void *ClassID) const override {
42     return ClassID == &ID || AppleObjCRuntime::isA(ClassID);
43   }
44 
45   static bool classof(const LanguageRuntime *runtime) {
46     return runtime->isA(&ID);
47   }
48 
49   // These are generic runtime functions:
50   bool GetDynamicTypeAndAddress(ValueObject &in_value,
51                                 lldb::DynamicValueType use_dynamic,
52                                 TypeAndOrName &class_type_or_name,
53                                 Address &address,
54                                 Value::ValueType &value_type) override;
55 
56   UtilityFunction *CreateObjectChecker(const char *) override;
57 
58   // PluginInterface protocol
59   ConstString GetPluginName() override;
60 
61   uint32_t GetPluginVersion() override;
62 
63   ObjCRuntimeVersions GetRuntimeVersion() const override {
64     return ObjCRuntimeVersions::eAppleObjC_V2;
65   }
66 
67   size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,
68                               const char *ivar_name) override;
69 
70   void UpdateISAToDescriptorMapIfNeeded() override;
71 
72   ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override;
73 
74   ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override;
75 
76   DeclVendor *GetDeclVendor() override;
77 
78   lldb::addr_t LookupRuntimeSymbol(ConstString name) override;
79 
80   EncodingToTypeSP GetEncodingToType() override;
81 
82   bool IsTaggedPointer(lldb::addr_t ptr) override;
83 
84   TaggedPointerVendor *GetTaggedPointerVendor() override {
85     return m_tagged_pointer_vendor_up.get();
86   }
87 
88   lldb::addr_t GetTaggedPointerObfuscator();
89 
90   void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
91                                     lldb::addr_t &cf_false) override;
92 
93   // none of these are valid ISAs - we use them to infer the type
94   // of tagged pointers - if we have something meaningful to say
95   // we report an actual type - otherwise, we just say tagged
96   // there is no connection between the values here and the tagged pointers map
97   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1;
98   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2;
99   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3;
100   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4;
101   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject =
102       5;
103   static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6;
104 
105 protected:
106   lldb::BreakpointResolverSP
107   CreateExceptionResolver(const lldb::BreakpointSP &bkpt,
108                           bool catch_bp, bool throw_bp) override;
109 
110 private:
111   class HashTableSignature {
112   public:
113     HashTableSignature();
114 
115     bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,
116                      RemoteNXMapTable &hash_table);
117 
118     void UpdateSignature(const RemoteNXMapTable &hash_table);
119 
120   protected:
121     uint32_t m_count;
122     uint32_t m_num_buckets;
123     lldb::addr_t m_buckets_ptr;
124   };
125 
126   class NonPointerISACache {
127   public:
128     static NonPointerISACache *
129     CreateInstance(AppleObjCRuntimeV2 &runtime,
130                    const lldb::ModuleSP &objc_module_sp);
131 
132     ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);
133 
134   private:
135     NonPointerISACache(AppleObjCRuntimeV2 &runtime,
136                        const lldb::ModuleSP &objc_module_sp,
137                        uint64_t objc_debug_isa_class_mask,
138                        uint64_t objc_debug_isa_magic_mask,
139                        uint64_t objc_debug_isa_magic_value,
140                        uint64_t objc_debug_indexed_isa_magic_mask,
141                        uint64_t objc_debug_indexed_isa_magic_value,
142                        uint64_t objc_debug_indexed_isa_index_mask,
143                        uint64_t objc_debug_indexed_isa_index_shift,
144                        lldb::addr_t objc_indexed_classes);
145 
146     bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);
147 
148     AppleObjCRuntimeV2 &m_runtime;
149     std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache;
150     lldb::ModuleWP m_objc_module_wp;
151     uint64_t m_objc_debug_isa_class_mask;
152     uint64_t m_objc_debug_isa_magic_mask;
153     uint64_t m_objc_debug_isa_magic_value;
154 
155     uint64_t m_objc_debug_indexed_isa_magic_mask;
156     uint64_t m_objc_debug_indexed_isa_magic_value;
157     uint64_t m_objc_debug_indexed_isa_index_mask;
158     uint64_t m_objc_debug_indexed_isa_index_shift;
159     lldb::addr_t m_objc_indexed_classes;
160 
161     std::vector<lldb::addr_t> m_indexed_isa_cache;
162 
163     friend class AppleObjCRuntimeV2;
164 
165     NonPointerISACache(const NonPointerISACache &) = delete;
166     const NonPointerISACache &operator=(const NonPointerISACache &) = delete;
167   };
168 
169   class TaggedPointerVendorV2
170       : public ObjCLanguageRuntime::TaggedPointerVendor {
171   public:
172     ~TaggedPointerVendorV2() override = default;
173 
174     static TaggedPointerVendorV2 *
175     CreateInstance(AppleObjCRuntimeV2 &runtime,
176                    const lldb::ModuleSP &objc_module_sp);
177 
178   protected:
179     AppleObjCRuntimeV2 &m_runtime;
180 
181     TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
182         : TaggedPointerVendor(), m_runtime(runtime) {}
183 
184   private:
185     TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;
186     const TaggedPointerVendorV2 &
187     operator=(const TaggedPointerVendorV2 &) = delete;
188   };
189 
190   class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
191   public:
192     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
193 
194     ObjCLanguageRuntime::ClassDescriptorSP
195     GetClassDescriptor(lldb::addr_t ptr) override;
196 
197   protected:
198     TaggedPointerVendorRuntimeAssisted(
199         AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
200         uint32_t objc_debug_taggedpointer_slot_shift,
201         uint32_t objc_debug_taggedpointer_slot_mask,
202         uint32_t objc_debug_taggedpointer_payload_lshift,
203         uint32_t objc_debug_taggedpointer_payload_rshift,
204         lldb::addr_t objc_debug_taggedpointer_classes);
205 
206     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
207     typedef Cache::iterator CacheIterator;
208     Cache m_cache;
209     uint64_t m_objc_debug_taggedpointer_mask;
210     uint32_t m_objc_debug_taggedpointer_slot_shift;
211     uint32_t m_objc_debug_taggedpointer_slot_mask;
212     uint32_t m_objc_debug_taggedpointer_payload_lshift;
213     uint32_t m_objc_debug_taggedpointer_payload_rshift;
214     lldb::addr_t m_objc_debug_taggedpointer_classes;
215 
216     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
217 
218     TaggedPointerVendorRuntimeAssisted(
219         const TaggedPointerVendorRuntimeAssisted &) = delete;
220     const TaggedPointerVendorRuntimeAssisted &
221     operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;
222   };
223 
224   class TaggedPointerVendorExtended
225       : public TaggedPointerVendorRuntimeAssisted {
226   public:
227     ObjCLanguageRuntime::ClassDescriptorSP
228     GetClassDescriptor(lldb::addr_t ptr) override;
229 
230   protected:
231     TaggedPointerVendorExtended(
232         AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
233         uint64_t objc_debug_taggedpointer_ext_mask,
234         uint32_t objc_debug_taggedpointer_slot_shift,
235         uint32_t objc_debug_taggedpointer_ext_slot_shift,
236         uint32_t objc_debug_taggedpointer_slot_mask,
237         uint32_t objc_debug_taggedpointer_ext_slot_mask,
238         uint32_t objc_debug_taggedpointer_payload_lshift,
239         uint32_t objc_debug_taggedpointer_payload_rshift,
240         uint32_t objc_debug_taggedpointer_ext_payload_lshift,
241         uint32_t objc_debug_taggedpointer_ext_payload_rshift,
242         lldb::addr_t objc_debug_taggedpointer_classes,
243         lldb::addr_t objc_debug_taggedpointer_ext_classes);
244 
245     bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
246 
247     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
248     typedef Cache::iterator CacheIterator;
249     Cache m_ext_cache;
250     uint64_t m_objc_debug_taggedpointer_ext_mask;
251     uint32_t m_objc_debug_taggedpointer_ext_slot_shift;
252     uint32_t m_objc_debug_taggedpointer_ext_slot_mask;
253     uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;
254     uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;
255     lldb::addr_t m_objc_debug_taggedpointer_ext_classes;
256 
257     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
258 
259     TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;
260     const TaggedPointerVendorExtended &
261     operator=(const TaggedPointerVendorExtended &) = delete;
262   };
263 
264   class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
265   public:
266     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
267 
268     ObjCLanguageRuntime::ClassDescriptorSP
269     GetClassDescriptor(lldb::addr_t ptr) override;
270 
271   protected:
272     TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
273         : TaggedPointerVendorV2(runtime) {}
274 
275     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
276 
277     TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;
278     const TaggedPointerVendorLegacy &
279     operator=(const TaggedPointerVendorLegacy &) = delete;
280   };
281 
282   struct DescriptorMapUpdateResult {
283     bool m_update_ran;
284     uint32_t m_num_found;
285 
286     DescriptorMapUpdateResult(bool ran, uint32_t found) {
287       m_update_ran = ran;
288       m_num_found = found;
289     }
290 
291     static DescriptorMapUpdateResult Fail() { return {false, 0}; }
292 
293     static DescriptorMapUpdateResult Success(uint32_t found) {
294       return {true, found};
295     }
296   };
297 
298   AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
299 
300   ObjCISA GetPointerISA(ObjCISA isa);
301 
302   lldb::addr_t GetISAHashTablePointer();
303 
304   bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table);
305 
306   DescriptorMapUpdateResult
307   UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table);
308 
309   uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
310                                uint32_t num_class_infos);
311 
312   DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache();
313 
314   enum class SharedCacheWarningReason {
315     eExpressionExecutionFailure,
316     eNotEnoughClassesRead
317   };
318 
319   void WarnIfNoClassesCached(SharedCacheWarningReason reason);
320 
321   lldb::addr_t GetSharedCacheReadOnlyAddress();
322 
323   bool GetCFBooleanValuesIfNeeded();
324 
325   friend class ClassDescriptorV2;
326 
327   std::unique_ptr<UtilityFunction> m_get_class_info_code;
328   lldb::addr_t m_get_class_info_args;
329   std::mutex m_get_class_info_args_mutex;
330 
331   std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code;
332   lldb::addr_t m_get_shared_cache_class_info_args;
333   std::mutex m_get_shared_cache_class_info_args_mutex;
334 
335   std::unique_ptr<DeclVendor> m_decl_vendor_up;
336   lldb::addr_t m_tagged_pointer_obfuscator;
337   lldb::addr_t m_isa_hash_table_ptr;
338   HashTableSignature m_hash_signature;
339   bool m_has_object_getClass;
340   bool m_loaded_objc_opt;
341   std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
342   std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
343   EncodingToTypeSP m_encoding_to_type_sp;
344   bool m_noclasses_warning_emitted;
345   llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
346 };
347 
348 } // namespace lldb_private
349 
350 #endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H
351