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 liblldb_AppleObjCRuntimeV2_h_
10 #define liblldb_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 CreateExceptionResolver(Breakpoint *bkpt,
107                                                      bool catch_bp,
108                                                      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     DISALLOW_COPY_AND_ASSIGN(NonPointerISACache);
166   };
167 
168   class TaggedPointerVendorV2
169       : public ObjCLanguageRuntime::TaggedPointerVendor {
170   public:
171     ~TaggedPointerVendorV2() override = default;
172 
173     static TaggedPointerVendorV2 *
174     CreateInstance(AppleObjCRuntimeV2 &runtime,
175                    const lldb::ModuleSP &objc_module_sp);
176 
177   protected:
178     AppleObjCRuntimeV2 &m_runtime;
179 
180     TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
181         : TaggedPointerVendor(), m_runtime(runtime) {}
182 
183   private:
184     DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorV2);
185   };
186 
187   class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
188   public:
189     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
190 
191     ObjCLanguageRuntime::ClassDescriptorSP
192     GetClassDescriptor(lldb::addr_t ptr) override;
193 
194   protected:
195     TaggedPointerVendorRuntimeAssisted(
196         AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
197         uint32_t objc_debug_taggedpointer_slot_shift,
198         uint32_t objc_debug_taggedpointer_slot_mask,
199         uint32_t objc_debug_taggedpointer_payload_lshift,
200         uint32_t objc_debug_taggedpointer_payload_rshift,
201         lldb::addr_t objc_debug_taggedpointer_classes);
202 
203     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
204     typedef Cache::iterator CacheIterator;
205     Cache m_cache;
206     uint64_t m_objc_debug_taggedpointer_mask;
207     uint32_t m_objc_debug_taggedpointer_slot_shift;
208     uint32_t m_objc_debug_taggedpointer_slot_mask;
209     uint32_t m_objc_debug_taggedpointer_payload_lshift;
210     uint32_t m_objc_debug_taggedpointer_payload_rshift;
211     lldb::addr_t m_objc_debug_taggedpointer_classes;
212 
213     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
214 
215     DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorRuntimeAssisted);
216   };
217 
218   class TaggedPointerVendorExtended
219       : public TaggedPointerVendorRuntimeAssisted {
220   public:
221     ObjCLanguageRuntime::ClassDescriptorSP
222     GetClassDescriptor(lldb::addr_t ptr) override;
223 
224   protected:
225     TaggedPointerVendorExtended(
226         AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
227         uint64_t objc_debug_taggedpointer_ext_mask,
228         uint32_t objc_debug_taggedpointer_slot_shift,
229         uint32_t objc_debug_taggedpointer_ext_slot_shift,
230         uint32_t objc_debug_taggedpointer_slot_mask,
231         uint32_t objc_debug_taggedpointer_ext_slot_mask,
232         uint32_t objc_debug_taggedpointer_payload_lshift,
233         uint32_t objc_debug_taggedpointer_payload_rshift,
234         uint32_t objc_debug_taggedpointer_ext_payload_lshift,
235         uint32_t objc_debug_taggedpointer_ext_payload_rshift,
236         lldb::addr_t objc_debug_taggedpointer_classes,
237         lldb::addr_t objc_debug_taggedpointer_ext_classes);
238 
239     bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
240 
241     typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
242     typedef Cache::iterator CacheIterator;
243     Cache m_ext_cache;
244     uint64_t m_objc_debug_taggedpointer_ext_mask;
245     uint32_t m_objc_debug_taggedpointer_ext_slot_shift;
246     uint32_t m_objc_debug_taggedpointer_ext_slot_mask;
247     uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;
248     uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;
249     lldb::addr_t m_objc_debug_taggedpointer_ext_classes;
250 
251     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
252 
253     DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorExtended);
254   };
255 
256   class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
257   public:
258     bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
259 
260     ObjCLanguageRuntime::ClassDescriptorSP
261     GetClassDescriptor(lldb::addr_t ptr) override;
262 
263   protected:
264     TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
265         : TaggedPointerVendorV2(runtime) {}
266 
267     friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
268 
269     DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendorLegacy);
270   };
271 
272   struct DescriptorMapUpdateResult {
273     bool m_update_ran;
274     uint32_t m_num_found;
275 
276     DescriptorMapUpdateResult(bool ran, uint32_t found) {
277       m_update_ran = ran;
278       m_num_found = found;
279     }
280 
281     static DescriptorMapUpdateResult Fail() { return {false, 0}; }
282 
283     static DescriptorMapUpdateResult Success(uint32_t found) {
284       return {true, found};
285     }
286   };
287 
288   AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
289 
290   ObjCISA GetPointerISA(ObjCISA isa);
291 
292   lldb::addr_t GetISAHashTablePointer();
293 
294   bool UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable &hash_table);
295 
296   DescriptorMapUpdateResult
297   UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table);
298 
299   uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
300                                uint32_t num_class_infos);
301 
302   DescriptorMapUpdateResult UpdateISAToDescriptorMapSharedCache();
303 
304   enum class SharedCacheWarningReason {
305     eExpressionExecutionFailure,
306     eNotEnoughClassesRead
307   };
308 
309   void WarnIfNoClassesCached(SharedCacheWarningReason reason);
310 
311   lldb::addr_t GetSharedCacheReadOnlyAddress();
312 
313   bool GetCFBooleanValuesIfNeeded();
314 
315   friend class ClassDescriptorV2;
316 
317   std::unique_ptr<UtilityFunction> m_get_class_info_code;
318   lldb::addr_t m_get_class_info_args;
319   std::mutex m_get_class_info_args_mutex;
320 
321   std::unique_ptr<UtilityFunction> m_get_shared_cache_class_info_code;
322   lldb::addr_t m_get_shared_cache_class_info_args;
323   std::mutex m_get_shared_cache_class_info_args_mutex;
324 
325   std::unique_ptr<DeclVendor> m_decl_vendor_up;
326   lldb::addr_t m_tagged_pointer_obfuscator;
327   lldb::addr_t m_isa_hash_table_ptr;
328   HashTableSignature m_hash_signature;
329   bool m_has_object_getClass;
330   bool m_loaded_objc_opt;
331   std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
332   std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
333   EncodingToTypeSP m_encoding_to_type_sp;
334   bool m_noclasses_warning_emitted;
335   llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
336 };
337 
338 } // namespace lldb_private
339 
340 #endif // liblldb_AppleObjCRuntimeV2_h_
341