Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h
Line
Count
Source (jump to first uncovered line)
1
//===-- ObjCLanguageRuntime.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_OBJCLANGUAGERUNTIME_H
10
#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H
11
12
#include <functional>
13
#include <map>
14
#include <memory>
15
#include <unordered_set>
16
17
#include "llvm/Support/Casting.h"
18
19
#include "lldb/Breakpoint/BreakpointPrecondition.h"
20
#include "lldb/Core/PluginInterface.h"
21
#include "lldb/Core/ThreadSafeDenseMap.h"
22
#include "lldb/Symbol/CompilerType.h"
23
#include "lldb/Symbol/Type.h"
24
#include "lldb/Target/LanguageRuntime.h"
25
#include "lldb/Utility/ConstString.h"
26
#include "lldb/lldb-private.h"
27
28
class CommandObjectObjC_ClassTable_Dump;
29
30
namespace lldb_private {
31
32
class TypeSystemClang;
33
class UtilityFunction;
34
35
class ObjCLanguageRuntime : public LanguageRuntime {
36
public:
37
  enum class ObjCRuntimeVersions {
38
    eObjC_VersionUnknown = 0,
39
    eAppleObjC_V1 = 1,
40
    eAppleObjC_V2 = 2
41
  };
42
43
  typedef lldb::addr_t ObjCISA;
44
45
  class ClassDescriptor;
46
  typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
47
48
  // the information that we want to support retrieving from an ObjC class this
49
  // needs to be pure virtual since there are at least 2 different
50
  // implementations of the runtime, and more might come
51
  class ClassDescriptor {
52
  public:
53
99.3M
    ClassDescriptor() : m_type_wp() {}
54
55
99.3M
    virtual ~ClassDescriptor() = default;
56
57
    virtual ConstString GetClassName() = 0;
58
59
    virtual ClassDescriptorSP GetSuperclass() = 0;
60
61
    virtual ClassDescriptorSP GetMetaclass() const = 0;
62
63
    // virtual if any implementation has some other version-specific rules but
64
    // for the known v1/v2 this is all that needs to be done
65
951
    virtual bool IsKVO() {
66
951
      if (m_is_kvo == eLazyBoolCalculate) {
67
281
        const char *class_name = GetClassName().AsCString();
68
281
        if (class_name && *class_name)
69
281
          m_is_kvo =
70
281
              (LazyBool)(strstr(class_name, "NSKVONotifying_") == class_name);
71
281
      }
72
951
      return (m_is_kvo == eLazyBoolYes);
73
951
    }
74
75
    // virtual if any implementation has some other version-specific rules but
76
    // for the known v1/v2 this is all that needs to be done
77
24
    virtual bool IsCFType() {
78
24
      if (m_is_cf == eLazyBoolCalculate) {
79
12
        const char *class_name = GetClassName().AsCString();
80
12
        if (class_name && *class_name)
81
12
          m_is_cf = (LazyBool)(strcmp(class_name, "__NSCFType") == 0 ||
82
12
                               
strcmp(class_name, "NSCFType") == 00
);
83
12
      }
84
24
      return (m_is_cf == eLazyBoolYes);
85
24
    }
86
87
    virtual bool IsValid() = 0;
88
89
    /// There are two routines in the ObjC runtime that tagged pointer clients
90
    /// can call to get the value from their tagged pointer, one that retrieves
91
    /// it as an unsigned value and one a signed value.  These two
92
    /// GetTaggedPointerInfo methods mirror those two ObjC runtime calls.
93
    /// @{
94
    virtual bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
95
                                      uint64_t *value_bits = nullptr,
96
                                      uint64_t *payload = nullptr) = 0;
97
98
    virtual bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
99
                                            int64_t *value_bits = nullptr,
100
                                            uint64_t *payload = nullptr) = 0;
101
    /// @}
102
 
103
    virtual uint64_t GetInstanceSize() = 0;
104
105
    // use to implement version-specific additional constraints on pointers
106
0
    virtual bool CheckPointer(lldb::addr_t value, uint32_t ptr_size) const {
107
0
      return true;
108
0
    }
109
110
    virtual ObjCISA GetISA() = 0;
111
112
    // This should return true iff the interface could be completed
113
    virtual bool
114
    Describe(std::function<void(ObjCISA)> const &superclass_func,
115
             std::function<bool(const char *, const char *)> const
116
                 &instance_method_func,
117
             std::function<bool(const char *, const char *)> const
118
                 &class_method_func,
119
             std::function<bool(const char *, const char *, lldb::addr_t,
120
0
                                uint64_t)> const &ivar_func) const {
121
0
      return false;
122
0
    }
123
124
930
    lldb::TypeSP GetType() { return m_type_wp.lock(); }
125
126
23
    void SetType(const lldb::TypeSP &type_sp) { m_type_wp = type_sp; }
127
128
    struct iVarDescriptor {
129
      ConstString m_name;
130
      CompilerType m_type;
131
      uint64_t m_size;
132
      int32_t m_offset;
133
    };
134
135
0
    virtual size_t GetNumIVars() { return 0; }
136
137
0
    virtual iVarDescriptor GetIVarAtIndex(size_t idx) {
138
0
      return iVarDescriptor();
139
0
    }
140
141
  protected:
142
    bool IsPointerValid(lldb::addr_t value, uint32_t ptr_size,
143
                        bool allow_NULLs = false, bool allow_tagged = false,
144
                        bool check_version_specific = false) const;
145
146
  private:
147
    LazyBool m_is_kvo = eLazyBoolCalculate;
148
    LazyBool m_is_cf = eLazyBoolCalculate;
149
    lldb::TypeWP m_type_wp;
150
  };
151
152
  class EncodingToType {
153
  public:
154
    virtual ~EncodingToType();
155
156
    virtual CompilerType RealizeType(TypeSystemClang &ast_ctx, const char *name,
157
                                     bool for_expression) = 0;
158
    virtual CompilerType RealizeType(const char *name, bool for_expression);
159
160
  protected:
161
    std::unique_ptr<TypeSystemClang> m_scratch_ast_ctx_up;
162
  };
163
164
  class ObjCExceptionPrecondition : public BreakpointPrecondition {
165
  public:
166
    ObjCExceptionPrecondition();
167
168
1.26k
    ~ObjCExceptionPrecondition() override = default;
169
170
    bool EvaluatePrecondition(StoppointCallbackContext &context) override;
171
    void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
172
    Status ConfigurePrecondition(Args &args) override;
173
174
  protected:
175
    void AddClassName(const char *class_name);
176
177
  private:
178
    std::unordered_set<std::string> m_class_names;
179
  };
180
181
  static lldb::BreakpointPreconditionSP
182
  GetBreakpointExceptionPrecondition(lldb::LanguageType language,
183
                                     bool throw_bp);
184
185
  class TaggedPointerVendor {
186
  public:
187
2.66k
    virtual ~TaggedPointerVendor() = default;
188
189
    virtual bool IsPossibleTaggedPointer(lldb::addr_t ptr) = 0;
190
191
    virtual ObjCLanguageRuntime::ClassDescriptorSP
192
    GetClassDescriptor(lldb::addr_t ptr) = 0;
193
194
  protected:
195
2.66k
    TaggedPointerVendor() = default;
196
197
  private:
198
    TaggedPointerVendor(const TaggedPointerVendor &) = delete;
199
    const TaggedPointerVendor &operator=(const TaggedPointerVendor &) = delete;
200
  };
201
202
  ~ObjCLanguageRuntime() override;
203
204
  static char ID;
205
206
157k
  bool isA(const void *ClassID) const override {
207
157k
    return ClassID == &ID || 
LanguageRuntime::isA(ClassID)891
;
208
157k
  }
209
210
156k
  static bool classof(const LanguageRuntime *runtime) {
211
156k
    return runtime->isA(&ID);
212
156k
  }
213
214
83.5k
  static ObjCLanguageRuntime *Get(Process &process) {
215
83.5k
    return llvm::cast_or_null<ObjCLanguageRuntime>(
216
83.5k
        process.GetLanguageRuntime(lldb::eLanguageTypeObjC));
217
83.5k
  }
218
219
0
  virtual TaggedPointerVendor *GetTaggedPointerVendor() { return nullptr; }
220
221
  typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
222
223
  virtual EncodingToTypeSP GetEncodingToType();
224
225
  virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value);
226
227
  ClassDescriptorSP GetNonKVOClassDescriptor(ValueObject &in_value);
228
229
  virtual ClassDescriptorSP
230
  GetClassDescriptorFromClassName(ConstString class_name);
231
232
  virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa);
233
234
  ClassDescriptorSP GetNonKVOClassDescriptor(ObjCISA isa);
235
236
223k
  lldb::LanguageType GetLanguageType() const override {
237
223k
    return lldb::eLanguageTypeObjC;
238
223k
  }
239
240
  virtual bool IsModuleObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
241
242
  virtual bool ReadObjCLibrary(const lldb::ModuleSP &module_sp) = 0;
243
244
  virtual bool HasReadObjCLibrary() = 0;
245
246
  // These two methods actually use different caches.  The only time we'll
247
  // cache a sel_str is if we found a "selector specific stub" for the selector
248
  // and conversely we only add to the SEL cache if we saw a regular dispatch.
249
  lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr, lldb::addr_t sel);
250
  lldb::addr_t LookupInMethodCache(lldb::addr_t class_addr,
251
                                   llvm::StringRef sel_str);
252
253
  void AddToMethodCache(lldb::addr_t class_addr, lldb::addr_t sel,
254
                        lldb::addr_t impl_addr);
255
256
  void AddToMethodCache(lldb::addr_t class_addr, llvm::StringRef sel_str,
257
                        lldb::addr_t impl_addr);
258
259
  TypeAndOrName LookupInClassNameCache(lldb::addr_t class_addr);
260
261
  void AddToClassNameCache(lldb::addr_t class_addr, const char *name,
262
                           lldb::TypeSP type_sp);
263
264
  void AddToClassNameCache(lldb::addr_t class_addr,
265
                           const TypeAndOrName &class_or_type_name);
266
267
  lldb::TypeSP LookupInCompleteClassCache(ConstString &name);
268
269
  llvm::Optional<CompilerType> GetRuntimeType(CompilerType base_type) override;
270
271
  virtual llvm::Expected<std::unique_ptr<UtilityFunction>>
272
  CreateObjectChecker(std::string name, ExecutionContext &exe_ctx) = 0;
273
274
0
  virtual ObjCRuntimeVersions GetRuntimeVersion() const {
275
0
    return ObjCRuntimeVersions::eObjC_VersionUnknown;
276
0
  }
277
278
0
  bool IsValidISA(ObjCISA isa) {
279
0
    UpdateISAToDescriptorMap();
280
0
    return m_isa_to_descriptor.count(isa) > 0;
281
0
  }
282
283
  virtual void UpdateISAToDescriptorMapIfNeeded() = 0;
284
285
17.0k
  void UpdateISAToDescriptorMap() {
286
17.0k
    if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id) {
287
3.58k
      UpdateISAToDescriptorMapIfNeeded();
288
3.58k
    }
289
17.0k
  }
290
291
  virtual ObjCISA GetISA(ConstString name);
292
293
  virtual ObjCISA GetParentClass(ObjCISA isa);
294
295
  // Finds the byte offset of the child_type ivar in parent_type.  If it can't
296
  // find the offset, returns LLDB_INVALID_IVAR_OFFSET.
297
298
  virtual size_t GetByteOffsetForIvar(CompilerType &parent_qual_type,
299
                                      const char *ivar_name);
300
301
14.6k
  bool HasNewLiteralsAndIndexing() {
302
14.6k
    if (m_has_new_literals_and_indexing == eLazyBoolCalculate) {
303
1.33k
      if (CalculateHasNewLiteralsAndIndexing())
304
311
        m_has_new_literals_and_indexing = eLazyBoolYes;
305
1.02k
      else
306
1.02k
        m_has_new_literals_and_indexing = eLazyBoolNo;
307
1.33k
    }
308
309
14.6k
    return (m_has_new_literals_and_indexing == eLazyBoolYes);
310
14.6k
  }
311
312
4
  void SymbolsDidLoad(const ModuleList &module_list) override {
313
4
    m_negative_complete_class_cache.clear();
314
4
  }
315
316
  bool GetTypeBitSize(const CompilerType &compiler_type,
317
                      uint64_t &size) override;
318
319
  /// Check whether the name is "self" or "_cmd" and should show up in
320
  /// "frame variable".
321
  bool IsAllowedRuntimeValue(ConstString name) override;
322
323
protected:
324
  // Classes that inherit from ObjCLanguageRuntime can see and modify these
325
  ObjCLanguageRuntime(Process *process);
326
327
0
  virtual bool CalculateHasNewLiteralsAndIndexing() { return false; }
328
329
99.4M
  bool ISAIsCached(ObjCISA isa) const {
330
99.4M
    return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
331
99.4M
  }
332
333
0
  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp) {
334
0
    if (isa != 0) {
335
0
      m_isa_to_descriptor[isa] = descriptor_sp;
336
0
      return true;
337
0
    }
338
0
    return false;
339
0
  }
340
341
  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
342
                const char *class_name);
343
344
  bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp,
345
99.3M
                uint32_t class_name_hash) {
346
99.3M
    if (isa != 0) {
347
99.3M
      m_isa_to_descriptor[isa] = descriptor_sp;
348
99.3M
      m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
349
99.3M
      return true;
350
99.3M
    }
351
0
    return false;
352
99.3M
  }
353
354
private:
355
  // We keep two maps of <Class,Selector>->Implementation so we don't have
356
  // to call the resolver function over and over.
357
  // The first comes from regular obj_msgSend type dispatch, and maps the
358
  // class + uniqued SEL value to an implementation.
359
  // The second comes from the "selector-specific stubs", which are always
360
  // of the form _objc_msgSend$SelectorName, so we don't know the uniqued
361
  // selector, only the string name.
362
363
  // FIXME: We need to watch for the loading of Protocols, and flush the cache
364
  // for any
365
  // class that we see so changed.
366
367
  struct ClassAndSel {
368
    ClassAndSel() = default;
369
370
    ClassAndSel(lldb::addr_t in_class_addr, lldb::addr_t in_sel_addr)
371
77
        : class_addr(in_class_addr), sel_addr(in_sel_addr) {}
372
373
0
    bool operator==(const ClassAndSel &rhs) {
374
0
      if (class_addr == rhs.class_addr && sel_addr == rhs.sel_addr)
375
0
        return true;
376
0
      else
377
0
        return false;
378
0
    }
379
380
216
    bool operator<(const ClassAndSel &rhs) const {
381
216
      if (class_addr < rhs.class_addr)
382
89
        return true;
383
127
      else if (class_addr > rhs.class_addr)
384
52
        return false;
385
75
      else {
386
75
        if (sel_addr < rhs.sel_addr)
387
38
          return true;
388
37
        else
389
37
          return false;
390
75
      }
391
216
    }
392
393
    lldb::addr_t class_addr = LLDB_INVALID_ADDRESS;
394
    lldb::addr_t sel_addr = LLDB_INVALID_ADDRESS;
395
  };
396
397
  struct ClassAndSelStr {
398
    ClassAndSelStr() = default;
399
400
    ClassAndSelStr(lldb::addr_t in_class_addr, llvm::StringRef in_sel_name)
401
0
        : class_addr(in_class_addr), sel_name(in_sel_name) {}
402
403
0
    bool operator==(const ClassAndSelStr &rhs) {
404
0
      return class_addr == rhs.class_addr && sel_name == rhs.sel_name;
405
0
    }
406
407
0
    bool operator<(const ClassAndSelStr &rhs) const {
408
0
      if (class_addr < rhs.class_addr)
409
0
        return true;
410
0
      else if (class_addr > rhs.class_addr)
411
0
        return false;
412
0
      else
413
0
        return ConstString::Compare(sel_name, rhs.sel_name);
414
0
    }
415
416
    lldb::addr_t class_addr = LLDB_INVALID_ADDRESS;
417
    ConstString sel_name;
418
  };
419
420
  typedef std::map<ClassAndSel, lldb::addr_t> MsgImplMap;
421
  typedef std::map<ClassAndSelStr, lldb::addr_t> MsgImplStrMap;
422
  typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
423
  typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
424
  typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
425
  typedef HashToISAMap::iterator HashToISAIterator;
426
  typedef ThreadSafeDenseMap<void *, uint64_t> TypeSizeCache;
427
428
  MsgImplMap m_impl_cache;
429
  MsgImplStrMap m_impl_str_cache;
430
  LazyBool m_has_new_literals_and_indexing;
431
  ISAToDescriptorMap m_isa_to_descriptor;
432
  HashToISAMap m_hash_to_isa_map;
433
  TypeSizeCache m_type_size_cache;
434
435
protected:
436
  uint32_t m_isa_to_descriptor_stop_id;
437
438
  typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
439
  CompleteClassMap m_complete_class_cache;
440
441
  struct ConstStringSetHelpers {
442
    size_t operator()(ConstString arg) const // for hashing
443
7.75k
    {
444
7.75k
      return (size_t)arg.GetCString();
445
7.75k
    }
446
    bool operator()(ConstString arg1,
447
                    ConstString arg2) const // for equality
448
6.41k
    {
449
6.41k
      return arg1.operator==(arg2);
450
6.41k
    }
451
  };
452
  typedef std::unordered_set<ConstString, ConstStringSetHelpers,
453
                             ConstStringSetHelpers>
454
      CompleteClassSet;
455
  CompleteClassSet m_negative_complete_class_cache;
456
457
  ISAToDescriptorIterator GetDescriptorIterator(ConstString name);
458
459
  friend class ::CommandObjectObjC_ClassTable_Dump;
460
461
  std::pair<ISAToDescriptorIterator, ISAToDescriptorIterator>
462
  GetDescriptorIteratorPair(bool update_if_needed = true);
463
464
  void ReadObjCLibraryIfNeeded(const ModuleList &module_list);
465
466
  ObjCLanguageRuntime(const ObjCLanguageRuntime &) = delete;
467
  const ObjCLanguageRuntime &operator=(const ObjCLanguageRuntime &) = delete;
468
};
469
470
} // namespace lldb_private
471
472
#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_OBJCLANGUAGERUNTIME_H