Coverage Report

Created: 2022-01-18 06:27

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
Line
Count
Source (jump to first uncovered line)
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
2.57k
  ~AppleObjCRuntimeV2() override = default;
28
29
  static void Initialize();
30
31
  static void Terminate();
32
33
  static lldb_private::LanguageRuntime *
34
  CreateInstance(Process *process, lldb::LanguageType language);
35
36
3.44k
  static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; }
37
38
  static char ID;
39
40
159k
  bool isA(const void *ClassID) const override {
41
159k
    return ClassID == &ID || AppleObjCRuntime::isA(ClassID);
42
159k
  }
43
44
0
  static bool classof(const LanguageRuntime *runtime) {
45
0
    return runtime->isA(&ID);
46
0
  }
47
48
  bool GetDynamicTypeAndAddress(ValueObject &in_value,
49
                                lldb::DynamicValueType use_dynamic,
50
                                TypeAndOrName &class_type_or_name,
51
                                Address &address,
52
                                Value::ValueType &value_type) override;
53
54
  llvm::Expected<std::unique_ptr<UtilityFunction>>
55
  CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
56
57
0
  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
58
59
14.2k
  ObjCRuntimeVersions GetRuntimeVersion() const override {
60
14.2k
    return ObjCRuntimeVersions::eAppleObjC_V2;
61
14.2k
  }
62
63
  size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,
64
                              const char *ivar_name) override;
65
66
  void UpdateISAToDescriptorMapIfNeeded() override;
67
68
  ClassDescriptorSP GetClassDescriptor(ValueObject &in_value) override;
69
70
  ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa) override;
71
72
  DeclVendor *GetDeclVendor() override;
73
74
  lldb::addr_t LookupRuntimeSymbol(ConstString name) override;
75
76
  EncodingToTypeSP GetEncodingToType() override;
77
78
  bool IsTaggedPointer(lldb::addr_t ptr) override;
79
80
2
  TaggedPointerVendor *GetTaggedPointerVendor() override {
81
2
    return m_tagged_pointer_vendor_up.get();
82
2
  }
83
84
  lldb::addr_t GetTaggedPointerObfuscator();
85
86
  /// Returns the base address for relative method list selector strings.
87
727
  lldb::addr_t GetRelativeSelectorBaseAddr() {
88
727
    return m_relative_selector_base;
89
727
  }
90
91
0
  void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) {
92
0
    m_relative_selector_base = relative_selector_base;
93
0
  }
94
95
  void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
96
                                    lldb::addr_t &cf_false) override;
97
98
  // none of these are valid ISAs - we use them to infer the type
99
  // of tagged pointers - if we have something meaningful to say
100
  // we report an actual type - otherwise, we just say tagged
101
  // there is no connection between the values here and the tagged pointers map
102
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA = 1;
103
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSAtom = 2;
104
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSNumber = 3;
105
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDateTS = 4;
106
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSManagedObject =
107
      5;
108
  static const ObjCLanguageRuntime::ObjCISA g_objc_Tagged_ISA_NSDate = 6;
109
110
protected:
111
  lldb::BreakpointResolverSP
112
  CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
113
                          bool throw_bp) override;
114
115
private:
116
  class HashTableSignature {
117
  public:
118
    HashTableSignature();
119
120
    bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,
121
                     RemoteNXMapTable &hash_table);
122
123
    void UpdateSignature(const RemoteNXMapTable &hash_table);
124
125
  protected:
126
    uint32_t m_count = 0;
127
    uint32_t m_num_buckets = 0;
128
    lldb::addr_t m_buckets_ptr = 0;
129
  };
130
131
  class NonPointerISACache {
132
  public:
133
    static NonPointerISACache *
134
    CreateInstance(AppleObjCRuntimeV2 &runtime,
135
                   const lldb::ModuleSP &objc_module_sp);
136
137
    ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);
138
139
  private:
140
    NonPointerISACache(AppleObjCRuntimeV2 &runtime,
141
                       const lldb::ModuleSP &objc_module_sp,
142
                       uint64_t objc_debug_isa_class_mask,
143
                       uint64_t objc_debug_isa_magic_mask,
144
                       uint64_t objc_debug_isa_magic_value,
145
                       uint64_t objc_debug_indexed_isa_magic_mask,
146
                       uint64_t objc_debug_indexed_isa_magic_value,
147
                       uint64_t objc_debug_indexed_isa_index_mask,
148
                       uint64_t objc_debug_indexed_isa_index_shift,
149
                       lldb::addr_t objc_indexed_classes);
150
151
    bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);
152
153
    AppleObjCRuntimeV2 &m_runtime;
154
    std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache;
155
    lldb::ModuleWP m_objc_module_wp;
156
    uint64_t m_objc_debug_isa_class_mask;
157
    uint64_t m_objc_debug_isa_magic_mask;
158
    uint64_t m_objc_debug_isa_magic_value;
159
160
    uint64_t m_objc_debug_indexed_isa_magic_mask;
161
    uint64_t m_objc_debug_indexed_isa_magic_value;
162
    uint64_t m_objc_debug_indexed_isa_index_mask;
163
    uint64_t m_objc_debug_indexed_isa_index_shift;
164
    lldb::addr_t m_objc_indexed_classes;
165
166
    std::vector<lldb::addr_t> m_indexed_isa_cache;
167
168
    friend class AppleObjCRuntimeV2;
169
170
    NonPointerISACache(const NonPointerISACache &) = delete;
171
    const NonPointerISACache &operator=(const NonPointerISACache &) = delete;
172
  };
173
174
  class TaggedPointerVendorV2
175
      : public ObjCLanguageRuntime::TaggedPointerVendor {
176
  public:
177
2.57k
    ~TaggedPointerVendorV2() override = default;
178
179
    static TaggedPointerVendorV2 *
180
    CreateInstance(AppleObjCRuntimeV2 &runtime,
181
                   const lldb::ModuleSP &objc_module_sp);
182
183
  protected:
184
    AppleObjCRuntimeV2 &m_runtime;
185
186
    TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
187
2.57k
        : TaggedPointerVendor(), m_runtime(runtime) {}
188
189
  private:
190
    TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;
191
    const TaggedPointerVendorV2 &
192
    operator=(const TaggedPointerVendorV2 &) = delete;
193
  };
194
195
  class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
196
  public:
197
    bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
198
199
    ObjCLanguageRuntime::ClassDescriptorSP
200
    GetClassDescriptor(lldb::addr_t ptr) override;
201
202
  protected:
203
    TaggedPointerVendorRuntimeAssisted(
204
        AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
205
        uint32_t objc_debug_taggedpointer_slot_shift,
206
        uint32_t objc_debug_taggedpointer_slot_mask,
207
        uint32_t objc_debug_taggedpointer_payload_lshift,
208
        uint32_t objc_debug_taggedpointer_payload_rshift,
209
        lldb::addr_t objc_debug_taggedpointer_classes);
210
211
    typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
212
    typedef Cache::iterator CacheIterator;
213
    Cache m_cache;
214
    uint64_t m_objc_debug_taggedpointer_mask;
215
    uint32_t m_objc_debug_taggedpointer_slot_shift;
216
    uint32_t m_objc_debug_taggedpointer_slot_mask;
217
    uint32_t m_objc_debug_taggedpointer_payload_lshift;
218
    uint32_t m_objc_debug_taggedpointer_payload_rshift;
219
    lldb::addr_t m_objc_debug_taggedpointer_classes;
220
221
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
222
223
    TaggedPointerVendorRuntimeAssisted(
224
        const TaggedPointerVendorRuntimeAssisted &) = delete;
225
    const TaggedPointerVendorRuntimeAssisted &
226
    operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;
227
  };
228
229
  class TaggedPointerVendorExtended
230
      : public TaggedPointerVendorRuntimeAssisted {
231
  public:
232
    ObjCLanguageRuntime::ClassDescriptorSP
233
    GetClassDescriptor(lldb::addr_t ptr) override;
234
235
  protected:
236
    TaggedPointerVendorExtended(
237
        AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
238
        uint64_t objc_debug_taggedpointer_ext_mask,
239
        uint32_t objc_debug_taggedpointer_slot_shift,
240
        uint32_t objc_debug_taggedpointer_ext_slot_shift,
241
        uint32_t objc_debug_taggedpointer_slot_mask,
242
        uint32_t objc_debug_taggedpointer_ext_slot_mask,
243
        uint32_t objc_debug_taggedpointer_payload_lshift,
244
        uint32_t objc_debug_taggedpointer_payload_rshift,
245
        uint32_t objc_debug_taggedpointer_ext_payload_lshift,
246
        uint32_t objc_debug_taggedpointer_ext_payload_rshift,
247
        lldb::addr_t objc_debug_taggedpointer_classes,
248
        lldb::addr_t objc_debug_taggedpointer_ext_classes);
249
250
    bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
251
252
    typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
253
    typedef Cache::iterator CacheIterator;
254
    Cache m_ext_cache;
255
    uint64_t m_objc_debug_taggedpointer_ext_mask;
256
    uint32_t m_objc_debug_taggedpointer_ext_slot_shift;
257
    uint32_t m_objc_debug_taggedpointer_ext_slot_mask;
258
    uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;
259
    uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;
260
    lldb::addr_t m_objc_debug_taggedpointer_ext_classes;
261
262
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
263
264
    TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;
265
    const TaggedPointerVendorExtended &
266
    operator=(const TaggedPointerVendorExtended &) = delete;
267
  };
268
269
  class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
270
  public:
271
    bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
272
273
    ObjCLanguageRuntime::ClassDescriptorSP
274
    GetClassDescriptor(lldb::addr_t ptr) override;
275
276
  protected:
277
    TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
278
0
        : TaggedPointerVendorV2(runtime) {}
279
280
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
281
282
    TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;
283
    const TaggedPointerVendorLegacy &
284
    operator=(const TaggedPointerVendorLegacy &) = delete;
285
  };
286
287
  struct DescriptorMapUpdateResult {
288
    bool m_update_ran;
289
    uint32_t m_num_found;
290
291
2.41k
    DescriptorMapUpdateResult(bool ran, uint32_t found) {
292
2.41k
      m_update_ran = ran;
293
2.41k
      m_num_found = found;
294
2.41k
    }
295
296
0
    static DescriptorMapUpdateResult Fail() { return {false, 0}; }
297
298
0
    static DescriptorMapUpdateResult Success(uint32_t found) {
299
0
      return {true, found};
300
0
    }
301
  };
302
303
  /// Abstraction to read the Objective-C class info.
304
  class ClassInfoExtractor {
305
  public:
306
5.15k
    ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}
307
0
    std::mutex &GetMutex() { return m_mutex; }
308
309
  protected:
310
    /// The lifetime of this object is tied to that of the runtime.
311
    AppleObjCRuntimeV2 &m_runtime;
312
    std::mutex m_mutex;
313
  };
314
315
  /// We can read the class info from the Objective-C runtime using
316
  /// gdb_objc_realized_classes or objc_copyRealizedClassList. The latter is
317
  /// preferred because it includes lazily named classes, but it's not always
318
  /// available or safe to call.
319
  ///
320
  /// We potentially need both for the same process, because we may need to use
321
  /// gdb_objc_realized_classes until dyld is initialized and then switch over
322
  /// to objc_copyRealizedClassList for lazily named classes.
323
  class DynamicClassInfoExtractor : public ClassInfoExtractor {
324
  public:
325
    DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
326
2.57k
        : ClassInfoExtractor(runtime) {}
327
328
    DescriptorMapUpdateResult
329
    UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);
330
331
  private:
332
    enum Helper { gdb_objc_realized_classes, objc_copyRealizedClassList };
333
334
    /// Compute which helper to use. Prefer objc_copyRealizedClassList if it's
335
    /// available and it's safe to call (i.e. dyld is fully initialized). Use
336
    /// gdb_objc_realized_classes otherwise.
337
    Helper ComputeHelper() const;
338
339
    UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
340
                                                 Helper helper);
341
    lldb::addr_t &GetClassInfoArgs(Helper helper);
342
343
    std::unique_ptr<UtilityFunction>
344
    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, std::string code,
345
                                    std::string name);
346
347
    /// Helper to read class info using the gdb_objc_realized_classes.
348
    struct gdb_objc_realized_classes_helper {
349
      std::unique_ptr<UtilityFunction> utility_function;
350
      lldb::addr_t args = LLDB_INVALID_ADDRESS;
351
    };
352
353
    /// Helper to read class info using objc_copyRealizedClassList.
354
    struct objc_copyRealizedClassList_helper {
355
      std::unique_ptr<UtilityFunction> utility_function;
356
      lldb::addr_t args = LLDB_INVALID_ADDRESS;
357
    };
358
359
    gdb_objc_realized_classes_helper m_gdb_objc_realized_classes_helper;
360
    objc_copyRealizedClassList_helper m_objc_copyRealizedClassList_helper;
361
  };
362
363
  /// Abstraction to read the Objective-C class info from the shared cache.
364
  class SharedCacheClassInfoExtractor : public ClassInfoExtractor {
365
  public:
366
    SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
367
2.57k
        : ClassInfoExtractor(runtime) {}
368
369
    DescriptorMapUpdateResult UpdateISAToDescriptorMap();
370
371
  private:
372
    UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);
373
374
    std::unique_ptr<UtilityFunction>
375
    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);
376
377
    std::unique_ptr<UtilityFunction> m_utility_function;
378
    lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
379
  };
380
381
  AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
382
383
  ObjCISA GetPointerISA(ObjCISA isa);
384
385
  lldb::addr_t GetISAHashTablePointer();
386
387
  /// Update the generation count of realized classes. This is not an exact
388
  /// count but rather a value that is incremented when new classes are realized
389
  /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will
390
  /// change when lazily named classes get realized.
391
  bool RealizedClassGenerationCountChanged();
392
393
  uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
394
                               uint32_t num_class_infos);
395
396
  enum class SharedCacheWarningReason {
397
    eExpressionExecutionFailure,
398
    eNotEnoughClassesRead
399
  };
400
401
  void WarnIfNoClassesCached(SharedCacheWarningReason reason);
402
403
  lldb::addr_t GetSharedCacheReadOnlyAddress();
404
  lldb::addr_t GetSharedCacheBaseAddress();
405
406
  bool GetCFBooleanValuesIfNeeded();
407
408
  bool HasSymbol(ConstString Name);
409
410
7.48k
  NonPointerISACache *GetNonPointerIsaCache() {
411
7.48k
    if (!m_non_pointer_isa_cache_up)
412
314
      m_non_pointer_isa_cache_up.reset(
413
314
          NonPointerISACache::CreateInstance(*this, m_objc_module_sp));
414
7.48k
    return m_non_pointer_isa_cache_up.get();
415
7.48k
  }
416
417
  friend class ClassDescriptorV2;
418
419
  lldb::ModuleSP m_objc_module_sp;
420
421
  DynamicClassInfoExtractor m_dynamic_class_info_extractor;
422
  SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;
423
424
  std::unique_ptr<DeclVendor> m_decl_vendor_up;
425
  lldb::addr_t m_tagged_pointer_obfuscator;
426
  lldb::addr_t m_isa_hash_table_ptr;
427
  lldb::addr_t m_relative_selector_base;
428
  HashTableSignature m_hash_signature;
429
  bool m_has_object_getClass;
430
  bool m_has_objc_copyRealizedClassList;
431
  bool m_loaded_objc_opt;
432
  std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
433
  std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
434
  EncodingToTypeSP m_encoding_to_type_sp;
435
  bool m_noclasses_warning_emitted;
436
  llvm::Optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
437
  uint64_t m_realized_class_generation_count;
438
};
439
440
} // namespace lldb_private
441
442
#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H