Coverage Report

Created: 2023-11-11 10:31

/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
#include <optional>
16
17
#include "AppleObjCRuntime.h"
18
#include "lldb/lldb-private.h"
19
20
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
21
22
#include "llvm/ADT/BitVector.h"
23
24
class RemoteNXMapTable;
25
26
namespace lldb_private {
27
28
class AppleObjCRuntimeV2 : public AppleObjCRuntime {
29
public:
30
2.13k
  ~AppleObjCRuntimeV2() override = default;
31
32
  static void Initialize();
33
34
  static void Terminate();
35
36
  static lldb_private::LanguageRuntime *
37
  CreateInstance(Process *process, lldb::LanguageType language);
38
39
3.95k
  static llvm::StringRef GetPluginNameStatic() { return "apple-objc-v2"; }
40
41
  LanguageRuntime *GetPreferredLanguageRuntime(ValueObject &in_value) override;
42
43
  static char ID;
44
45
124k
  bool isA(const void *ClassID) const override {
46
124k
    return ClassID == &ID || AppleObjCRuntime::isA(ClassID);
47
124k
  }
48
49
0
  static bool classof(const LanguageRuntime *runtime) {
50
0
    return runtime->isA(&ID);
51
0
  }
52
53
  bool GetDynamicTypeAndAddress(ValueObject &in_value,
54
                                lldb::DynamicValueType use_dynamic,
55
                                TypeAndOrName &class_type_or_name,
56
                                Address &address,
57
                                Value::ValueType &value_type) override;
58
59
  llvm::Expected<std::unique_ptr<UtilityFunction>>
60
  CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) override;
61
62
0
  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
63
64
10.9k
  ObjCRuntimeVersions GetRuntimeVersion() const override {
65
10.9k
    return ObjCRuntimeVersions::eAppleObjC_V2;
66
10.9k
  }
67
68
  size_t GetByteOffsetForIvar(CompilerType &parent_ast_type,
69
                              const char *ivar_name) override;
70
71
  void UpdateISAToDescriptorMapIfNeeded() override;
72
73
  ClassDescriptorSP GetClassDescriptor(ValueObject &valobj) 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
85
2
  TaggedPointerVendor *GetTaggedPointerVendor() override {
86
2
    return m_tagged_pointer_vendor_up.get();
87
2
  }
88
89
  lldb::addr_t GetTaggedPointerObfuscator();
90
91
  /// Returns the base address for relative method list selector strings.
92
582
  lldb::addr_t GetRelativeSelectorBaseAddr() {
93
582
    return m_relative_selector_base;
94
582
  }
95
96
0
  void SetRelativeSelectorBaseAddr(lldb::addr_t relative_selector_base) {
97
0
    m_relative_selector_base = relative_selector_base;
98
0
  }
99
100
  void GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
101
                                    lldb::addr_t &cf_false) override;
102
103
  void ModulesDidLoad(const ModuleList &module_list) override;
104
105
  bool IsSharedCacheImageLoaded(uint16_t image_index);
106
107
  std::optional<uint64_t> GetSharedCacheImageHeaderVersion();
108
109
protected:
110
  lldb::BreakpointResolverSP
111
  CreateExceptionResolver(const lldb::BreakpointSP &bkpt, bool catch_bp,
112
                          bool throw_bp) override;
113
114
private:
115
  class HashTableSignature {
116
  public:
117
    HashTableSignature();
118
119
    bool NeedsUpdate(Process *process, AppleObjCRuntimeV2 *runtime,
120
                     RemoteNXMapTable &hash_table);
121
122
    void UpdateSignature(const RemoteNXMapTable &hash_table);
123
124
  protected:
125
    uint32_t m_count = 0;
126
    uint32_t m_num_buckets = 0;
127
    lldb::addr_t m_buckets_ptr = 0;
128
  };
129
130
  class NonPointerISACache {
131
  public:
132
    static NonPointerISACache *
133
    CreateInstance(AppleObjCRuntimeV2 &runtime,
134
                   const lldb::ModuleSP &objc_module_sp);
135
136
    ObjCLanguageRuntime::ClassDescriptorSP GetClassDescriptor(ObjCISA isa);
137
138
  private:
139
    NonPointerISACache(AppleObjCRuntimeV2 &runtime,
140
                       const lldb::ModuleSP &objc_module_sp,
141
                       uint64_t objc_debug_isa_class_mask,
142
                       uint64_t objc_debug_isa_magic_mask,
143
                       uint64_t objc_debug_isa_magic_value,
144
                       uint64_t objc_debug_indexed_isa_magic_mask,
145
                       uint64_t objc_debug_indexed_isa_magic_value,
146
                       uint64_t objc_debug_indexed_isa_index_mask,
147
                       uint64_t objc_debug_indexed_isa_index_shift,
148
                       lldb::addr_t objc_indexed_classes);
149
150
    bool EvaluateNonPointerISA(ObjCISA isa, ObjCISA &ret_isa);
151
152
    AppleObjCRuntimeV2 &m_runtime;
153
    std::map<ObjCISA, ObjCLanguageRuntime::ClassDescriptorSP> m_cache;
154
    lldb::ModuleWP m_objc_module_wp;
155
    uint64_t m_objc_debug_isa_class_mask;
156
    uint64_t m_objc_debug_isa_magic_mask;
157
    uint64_t m_objc_debug_isa_magic_value;
158
159
    uint64_t m_objc_debug_indexed_isa_magic_mask;
160
    uint64_t m_objc_debug_indexed_isa_magic_value;
161
    uint64_t m_objc_debug_indexed_isa_index_mask;
162
    uint64_t m_objc_debug_indexed_isa_index_shift;
163
    lldb::addr_t m_objc_indexed_classes;
164
165
    std::vector<lldb::addr_t> m_indexed_isa_cache;
166
167
    friend class AppleObjCRuntimeV2;
168
169
    NonPointerISACache(const NonPointerISACache &) = delete;
170
    const NonPointerISACache &operator=(const NonPointerISACache &) = delete;
171
  };
172
173
  class TaggedPointerVendorV2
174
      : public ObjCLanguageRuntime::TaggedPointerVendor {
175
  public:
176
2.13k
    ~TaggedPointerVendorV2() override = default;
177
178
    static TaggedPointerVendorV2 *
179
    CreateInstance(AppleObjCRuntimeV2 &runtime,
180
                   const lldb::ModuleSP &objc_module_sp);
181
182
  protected:
183
    AppleObjCRuntimeV2 &m_runtime;
184
185
    TaggedPointerVendorV2(AppleObjCRuntimeV2 &runtime)
186
2.13k
        : TaggedPointerVendor(), m_runtime(runtime) {}
187
188
  private:
189
    TaggedPointerVendorV2(const TaggedPointerVendorV2 &) = delete;
190
    const TaggedPointerVendorV2 &
191
    operator=(const TaggedPointerVendorV2 &) = delete;
192
  };
193
194
  class TaggedPointerVendorRuntimeAssisted : public TaggedPointerVendorV2 {
195
  public:
196
    bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
197
198
    ObjCLanguageRuntime::ClassDescriptorSP
199
    GetClassDescriptor(lldb::addr_t ptr) override;
200
201
  protected:
202
    TaggedPointerVendorRuntimeAssisted(
203
        AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
204
        uint32_t objc_debug_taggedpointer_slot_shift,
205
        uint32_t objc_debug_taggedpointer_slot_mask,
206
        uint32_t objc_debug_taggedpointer_payload_lshift,
207
        uint32_t objc_debug_taggedpointer_payload_rshift,
208
        lldb::addr_t objc_debug_taggedpointer_classes);
209
210
    typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
211
    typedef Cache::iterator CacheIterator;
212
    Cache m_cache;
213
    uint64_t m_objc_debug_taggedpointer_mask;
214
    uint32_t m_objc_debug_taggedpointer_slot_shift;
215
    uint32_t m_objc_debug_taggedpointer_slot_mask;
216
    uint32_t m_objc_debug_taggedpointer_payload_lshift;
217
    uint32_t m_objc_debug_taggedpointer_payload_rshift;
218
    lldb::addr_t m_objc_debug_taggedpointer_classes;
219
220
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
221
222
    TaggedPointerVendorRuntimeAssisted(
223
        const TaggedPointerVendorRuntimeAssisted &) = delete;
224
    const TaggedPointerVendorRuntimeAssisted &
225
    operator=(const TaggedPointerVendorRuntimeAssisted &) = delete;
226
  };
227
228
  class TaggedPointerVendorExtended
229
      : public TaggedPointerVendorRuntimeAssisted {
230
  public:
231
    ObjCLanguageRuntime::ClassDescriptorSP
232
    GetClassDescriptor(lldb::addr_t ptr) override;
233
234
  protected:
235
    TaggedPointerVendorExtended(
236
        AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
237
        uint64_t objc_debug_taggedpointer_ext_mask,
238
        uint32_t objc_debug_taggedpointer_slot_shift,
239
        uint32_t objc_debug_taggedpointer_ext_slot_shift,
240
        uint32_t objc_debug_taggedpointer_slot_mask,
241
        uint32_t objc_debug_taggedpointer_ext_slot_mask,
242
        uint32_t objc_debug_taggedpointer_payload_lshift,
243
        uint32_t objc_debug_taggedpointer_payload_rshift,
244
        uint32_t objc_debug_taggedpointer_ext_payload_lshift,
245
        uint32_t objc_debug_taggedpointer_ext_payload_rshift,
246
        lldb::addr_t objc_debug_taggedpointer_classes,
247
        lldb::addr_t objc_debug_taggedpointer_ext_classes);
248
249
    bool IsPossibleExtendedTaggedPointer(lldb::addr_t ptr);
250
251
    typedef std::map<uint8_t, ObjCLanguageRuntime::ClassDescriptorSP> Cache;
252
    typedef Cache::iterator CacheIterator;
253
    Cache m_ext_cache;
254
    uint64_t m_objc_debug_taggedpointer_ext_mask;
255
    uint32_t m_objc_debug_taggedpointer_ext_slot_shift;
256
    uint32_t m_objc_debug_taggedpointer_ext_slot_mask;
257
    uint32_t m_objc_debug_taggedpointer_ext_payload_lshift;
258
    uint32_t m_objc_debug_taggedpointer_ext_payload_rshift;
259
    lldb::addr_t m_objc_debug_taggedpointer_ext_classes;
260
261
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
262
263
    TaggedPointerVendorExtended(const TaggedPointerVendorExtended &) = delete;
264
    const TaggedPointerVendorExtended &
265
    operator=(const TaggedPointerVendorExtended &) = delete;
266
  };
267
268
  class TaggedPointerVendorLegacy : public TaggedPointerVendorV2 {
269
  public:
270
    bool IsPossibleTaggedPointer(lldb::addr_t ptr) override;
271
272
    ObjCLanguageRuntime::ClassDescriptorSP
273
    GetClassDescriptor(lldb::addr_t ptr) override;
274
275
  protected:
276
    TaggedPointerVendorLegacy(AppleObjCRuntimeV2 &runtime)
277
0
        : TaggedPointerVendorV2(runtime) {}
278
279
    friend class AppleObjCRuntimeV2::TaggedPointerVendorV2;
280
281
    TaggedPointerVendorLegacy(const TaggedPointerVendorLegacy &) = delete;
282
    const TaggedPointerVendorLegacy &
283
    operator=(const TaggedPointerVendorLegacy &) = delete;
284
  };
285
286
  struct DescriptorMapUpdateResult {
287
    bool m_update_ran;
288
    bool m_retry_update;
289
    uint32_t m_num_found;
290
291
1.95k
    DescriptorMapUpdateResult(bool ran, bool retry, uint32_t found) {
292
1.95k
      m_update_ran = ran;
293
294
1.95k
      m_retry_update = retry;
295
296
1.95k
      m_num_found = found;
297
1.95k
    }
298
299
0
    static DescriptorMapUpdateResult Fail() { return {false, false, 0}; }
300
301
0
    static DescriptorMapUpdateResult Success(uint32_t found) {
302
0
      return {true, false, found};
303
0
    }
304
305
0
    static DescriptorMapUpdateResult Retry() { return {false, true, 0}; }
306
  };
307
308
  /// Abstraction to read the Objective-C class info.
309
  class ClassInfoExtractor {
310
  public:
311
4.26k
    ClassInfoExtractor(AppleObjCRuntimeV2 &runtime) : m_runtime(runtime) {}
312
0
    std::mutex &GetMutex() { return m_mutex; }
313
314
  protected:
315
    /// The lifetime of this object is tied to that of the runtime.
316
    AppleObjCRuntimeV2 &m_runtime;
317
    std::mutex m_mutex;
318
  };
319
320
  /// We can read the class info from the Objective-C runtime using
321
  /// gdb_objc_realized_classes, objc_copyRealizedClassList or
322
  /// objc_getRealizedClassList_trylock. The RealizedClassList variants are
323
  /// preferred because they include lazily named classes, but they are not
324
  /// always available or safe to call.
325
  ///
326
  /// We potentially need more than one helper for the same process, because we
327
  /// may need to use gdb_objc_realized_classes until dyld is initialized and
328
  /// then switch over to objc_copyRealizedClassList or
329
  /// objc_getRealizedClassList_trylock for lazily named classes.
330
  class DynamicClassInfoExtractor : public ClassInfoExtractor {
331
  public:
332
    DynamicClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
333
2.13k
        : ClassInfoExtractor(runtime) {}
334
335
    DescriptorMapUpdateResult
336
    UpdateISAToDescriptorMap(RemoteNXMapTable &hash_table);
337
338
  private:
339
    enum Helper {
340
      gdb_objc_realized_classes,
341
      objc_copyRealizedClassList,
342
      objc_getRealizedClassList_trylock
343
    };
344
345
    /// Compute which helper to use. If dyld is not yet fully initialized we
346
    /// must use gdb_objc_realized_classes. Otherwise, we prefer
347
    /// objc_getRealizedClassList_trylock and objc_copyRealizedClassList
348
    /// respectively, depending on availability.
349
    Helper ComputeHelper(ExecutionContext &exe_ctx) const;
350
351
    UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx,
352
                                                 Helper helper);
353
    lldb::addr_t &GetClassInfoArgs(Helper helper);
354
355
    std::unique_ptr<UtilityFunction>
356
    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx, Helper helper,
357
                                    std::string code, std::string name);
358
359
    struct UtilityFunctionHelper {
360
      std::unique_ptr<UtilityFunction> utility_function;
361
      lldb::addr_t args = LLDB_INVALID_ADDRESS;
362
    };
363
364
    UtilityFunctionHelper m_gdb_objc_realized_classes_helper;
365
    UtilityFunctionHelper m_objc_copyRealizedClassList_helper;
366
    UtilityFunctionHelper m_objc_getRealizedClassList_trylock_helper;
367
  };
368
369
  /// Abstraction to read the Objective-C class info from the shared cache.
370
  class SharedCacheClassInfoExtractor : public ClassInfoExtractor {
371
  public:
372
    SharedCacheClassInfoExtractor(AppleObjCRuntimeV2 &runtime)
373
2.13k
        : ClassInfoExtractor(runtime) {}
374
375
    DescriptorMapUpdateResult UpdateISAToDescriptorMap();
376
377
  private:
378
    UtilityFunction *GetClassInfoUtilityFunction(ExecutionContext &exe_ctx);
379
380
    std::unique_ptr<UtilityFunction>
381
    GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx);
382
383
    std::unique_ptr<UtilityFunction> m_utility_function;
384
    lldb::addr_t m_args = LLDB_INVALID_ADDRESS;
385
  };
386
387
  class SharedCacheImageHeaders {
388
  public:
389
    static std::unique_ptr<SharedCacheImageHeaders>
390
    CreateSharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime);
391
392
0
    void SetNeedsUpdate() { m_needs_update = true; }
393
394
    bool IsImageLoaded(uint16_t image_index);
395
396
    uint64_t GetVersion();
397
398
  private:
399
    SharedCacheImageHeaders(AppleObjCRuntimeV2 &runtime,
400
                            lldb::addr_t headerInfoRWs_ptr, uint32_t count,
401
                            uint32_t entsize)
402
0
        : m_runtime(runtime), m_headerInfoRWs_ptr(headerInfoRWs_ptr),
403
0
          m_loaded_images(count, false), m_version(0), m_count(count),
404
0
          m_entsize(entsize), m_needs_update(true) {}
405
    llvm::Error UpdateIfNeeded();
406
407
    AppleObjCRuntimeV2 &m_runtime;
408
    lldb::addr_t m_headerInfoRWs_ptr;
409
    llvm::BitVector m_loaded_images;
410
    uint64_t m_version;
411
    uint32_t m_count;
412
    uint32_t m_entsize;
413
    bool m_needs_update;
414
  };
415
416
  AppleObjCRuntimeV2(Process *process, const lldb::ModuleSP &objc_module_sp);
417
418
  ObjCISA GetPointerISA(ObjCISA isa);
419
420
  lldb::addr_t GetISAHashTablePointer();
421
422
  /// Update the generation count of realized classes. This is not an exact
423
  /// count but rather a value that is incremented when new classes are realized
424
  /// or destroyed. Unlike the count in gdb_objc_realized_classes, it will
425
  /// change when lazily named classes get realized.
426
  bool RealizedClassGenerationCountChanged();
427
428
  uint32_t ParseClassInfoArray(const lldb_private::DataExtractor &data,
429
                               uint32_t num_class_infos);
430
431
  enum class SharedCacheWarningReason {
432
    eExpressionUnableToRun,
433
    eExpressionExecutionFailure,
434
    eNotEnoughClassesRead
435
  };
436
437
  void WarnIfNoClassesCached(SharedCacheWarningReason reason);
438
  void WarnIfNoExpandedSharedCache();
439
440
  lldb::addr_t GetSharedCacheReadOnlyAddress();
441
  lldb::addr_t GetSharedCacheBaseAddress();
442
443
  bool GetCFBooleanValuesIfNeeded();
444
445
  bool HasSymbol(ConstString Name);
446
447
7.91k
  NonPointerISACache *GetNonPointerIsaCache() {
448
7.91k
    if (!m_non_pointer_isa_cache_up)
449
296
      m_non_pointer_isa_cache_up.reset(
450
296
          NonPointerISACache::CreateInstance(*this, m_objc_module_sp));
451
7.91k
    return m_non_pointer_isa_cache_up.get();
452
7.91k
  }
453
454
  friend class ClassDescriptorV2;
455
456
  lldb::ModuleSP m_objc_module_sp;
457
458
  DynamicClassInfoExtractor m_dynamic_class_info_extractor;
459
  SharedCacheClassInfoExtractor m_shared_cache_class_info_extractor;
460
461
  std::unique_ptr<DeclVendor> m_decl_vendor_up;
462
  lldb::addr_t m_tagged_pointer_obfuscator;
463
  lldb::addr_t m_isa_hash_table_ptr;
464
  lldb::addr_t m_relative_selector_base;
465
  HashTableSignature m_hash_signature;
466
  bool m_has_object_getClass;
467
  bool m_has_objc_copyRealizedClassList;
468
  bool m_has_objc_getRealizedClassList_trylock;
469
  bool m_loaded_objc_opt;
470
  std::unique_ptr<NonPointerISACache> m_non_pointer_isa_cache_up;
471
  std::unique_ptr<TaggedPointerVendor> m_tagged_pointer_vendor_up;
472
  EncodingToTypeSP m_encoding_to_type_sp;
473
  std::once_flag m_no_classes_cached_warning;
474
  std::once_flag m_no_expanded_cache_warning;
475
  std::optional<std::pair<lldb::addr_t, lldb::addr_t>> m_CFBoolean_values;
476
  uint64_t m_realized_class_generation_count;
477
  std::unique_ptr<SharedCacheImageHeaders> m_shared_cache_image_headers_up;
478
};
479
480
} // namespace lldb_private
481
482
#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCRUNTIMEV2_H