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