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
21class RemoteNXMapTable;
22
23namespace lldb_private {
24
25class AppleObjCRuntimeV2 : public AppleObjCRuntime {
26public:
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
105protected:
106  lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt,
107                                                     bool catch_bp,
108                                                     bool throw_bp) override;
109
110private:
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