Coverage Report

Created: 2023-09-12 09:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.h
Line
Count
Source (jump to first uncovered line)
1
//===-- AppleObjCClassDescriptorV2.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_APPLEOBJCCLASSDESCRIPTORV2_H
10
#define LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H
11
12
#include <mutex>
13
14
#include "AppleObjCRuntimeV2.h"
15
#include "lldb/lldb-enumerations.h"
16
#include "lldb/lldb-private.h"
17
18
#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
19
20
namespace lldb_private {
21
22
class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor {
23
public:
24
  friend class lldb_private::AppleObjCRuntimeV2;
25
26
70.1M
  ~ClassDescriptorV2() override = default;
27
28
  ConstString GetClassName() override;
29
30
  ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override;
31
32
  ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override;
33
34
2.45k
  bool IsValid() override {
35
2.45k
    return true; // any Objective-C v2 runtime class descriptor we vend is valid
36
2.45k
  }
37
38
  lldb::LanguageType GetImplementationLanguage() const override;
39
40
  // a custom descriptor is used for tagged pointers
41
  bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
42
                            uint64_t *value_bits = nullptr,
43
24
                            uint64_t *payload = nullptr) override {
44
24
    return false;
45
24
  }
46
47
  bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
48
                                  int64_t *value_bits = nullptr,
49
104
                                  uint64_t *payload = nullptr) override {
50
104
    return false;
51
104
  }
52
53
  uint64_t GetInstanceSize() override;
54
55
0
  ObjCLanguageRuntime::ObjCISA GetISA() override { return m_objc_class_ptr; }
56
57
  bool Describe(
58
      std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
59
      std::function<bool(const char *, const char *)> const
60
          &instance_method_func,
61
      std::function<bool(const char *, const char *)> const &class_method_func,
62
      std::function<bool(const char *, const char *, lldb::addr_t,
63
                         uint64_t)> const &ivar_func) const override;
64
65
316
  size_t GetNumIVars() override {
66
316
    GetIVarInformation();
67
316
    return m_ivars_storage.size();
68
316
  }
69
70
125
  iVarDescriptor GetIVarAtIndex(size_t idx) override {
71
125
    if (idx >= GetNumIVars())
72
0
      return iVarDescriptor();
73
125
    return m_ivars_storage[idx];
74
125
  }
75
76
protected:
77
  void GetIVarInformation();
78
79
private:
80
  static const uint32_t RW_REALIZED = (1u << 31);
81
82
  struct objc_class_t {
83
    ObjCLanguageRuntime::ObjCISA m_isa = 0; // The class's metaclass.
84
    ObjCLanguageRuntime::ObjCISA m_superclass = 0;
85
    lldb::addr_t m_cache_ptr = 0;
86
    lldb::addr_t m_vtable_ptr = 0;
87
    lldb::addr_t m_data_ptr = 0;
88
    uint8_t m_flags = 0;
89
90
2.60k
    objc_class_t() = default;
91
92
0
    void Clear() {
93
0
      m_isa = 0;
94
0
      m_superclass = 0;
95
0
      m_cache_ptr = 0;
96
0
      m_vtable_ptr = 0;
97
0
      m_data_ptr = 0;
98
0
      m_flags = 0;
99
0
    }
100
101
    bool Read(Process *process, lldb::addr_t addr);
102
  };
103
104
  struct class_ro_t {
105
    uint32_t m_flags;
106
    uint32_t m_instanceStart;
107
    uint32_t m_instanceSize;
108
    uint32_t m_reserved;
109
110
    lldb::addr_t m_ivarLayout_ptr;
111
    lldb::addr_t m_name_ptr;
112
    lldb::addr_t m_baseMethods_ptr;
113
    lldb::addr_t m_baseProtocols_ptr;
114
    lldb::addr_t m_ivars_ptr;
115
116
    lldb::addr_t m_weakIvarLayout_ptr;
117
    lldb::addr_t m_baseProperties_ptr;
118
119
    std::string m_name;
120
121
    bool Read(Process *process, lldb::addr_t addr);
122
  };
123
124
  struct class_rw_t {
125
    uint32_t m_flags;
126
    uint32_t m_version;
127
128
    lldb::addr_t m_ro_ptr;
129
    union {
130
      lldb::addr_t m_method_list_ptr;
131
      lldb::addr_t m_method_lists_ptr;
132
    };
133
    lldb::addr_t m_properties_ptr;
134
    lldb::addr_t m_protocols_ptr;
135
136
    ObjCLanguageRuntime::ObjCISA m_firstSubclass;
137
    ObjCLanguageRuntime::ObjCISA m_nextSiblingClass;
138
139
    bool Read(Process *process, lldb::addr_t addr);
140
  };
141
142
  struct method_list_t {
143
    uint16_t m_entsize;
144
    bool m_is_small;
145
    bool m_has_direct_selector;
146
    uint32_t m_count;
147
    lldb::addr_t m_first_ptr;
148
149
    bool Read(Process *process, lldb::addr_t addr);
150
  };
151
152
  std::optional<method_list_t>
153
  GetMethodList(Process *process, lldb::addr_t method_list_ptr) const;
154
155
  struct method_t {
156
    lldb::addr_t m_name_ptr;
157
    lldb::addr_t m_types_ptr;
158
    lldb::addr_t m_imp_ptr;
159
160
    std::string m_name;
161
    std::string m_types;
162
163
17.8k
    static size_t GetSize(Process *process, bool is_small) {
164
17.8k
      size_t field_size;
165
17.8k
      if (is_small)
166
0
        field_size = 4; // uint32_t relative indirect fields
167
17.8k
      else
168
17.8k
        field_size = process->GetAddressByteSize();
169
170
17.8k
      return field_size    // SEL name;
171
17.8k
             + field_size  // const char *types;
172
17.8k
             + field_size; // IMP imp;
173
17.8k
    }
174
175
    bool Read(Process *process, lldb::addr_t addr,
176
              lldb::addr_t relative_selector_base_addr, bool is_small,
177
              bool has_direct_sel);
178
  };
179
180
  struct ivar_list_t {
181
    uint32_t m_entsize;
182
    uint32_t m_count;
183
    lldb::addr_t m_first_ptr;
184
185
    bool Read(Process *process, lldb::addr_t addr);
186
  };
187
188
  struct ivar_t {
189
    lldb::addr_t m_offset_ptr;
190
    lldb::addr_t m_name_ptr;
191
    lldb::addr_t m_type_ptr;
192
    uint32_t m_alignment;
193
    uint32_t m_size;
194
195
    std::string m_name;
196
    std::string m_type;
197
198
556
    static size_t GetSize(Process *process) {
199
556
      size_t ptr_size = process->GetAddressByteSize();
200
201
556
      return ptr_size            // uintptr_t *offset;
202
556
             + ptr_size          // const char *name;
203
556
             + ptr_size          // const char *type;
204
556
             + sizeof(uint32_t)  // uint32_t alignment;
205
556
             + sizeof(uint32_t); // uint32_t size;
206
556
    }
207
208
    bool Read(Process *process, lldb::addr_t addr);
209
  };
210
211
  struct relative_list_entry_t {
212
    uint16_t m_image_index;
213
    int64_t m_list_offset;
214
215
    bool Read(Process *process, lldb::addr_t addr);
216
  };
217
218
  struct relative_list_list_t {
219
    uint32_t m_entsize;
220
    uint32_t m_count;
221
    lldb::addr_t m_first_ptr;
222
223
    bool Read(Process *process, lldb::addr_t addr);
224
  };
225
226
  class iVarsStorage {
227
  public:
228
    iVarsStorage();
229
230
    size_t size();
231
232
    iVarDescriptor &operator[](size_t idx);
233
234
    void fill(AppleObjCRuntimeV2 &runtime, ClassDescriptorV2 &descriptor);
235
236
  private:
237
    bool m_filled = false;
238
    std::vector<iVarDescriptor> m_ivars;
239
    std::recursive_mutex m_mutex;
240
  };
241
242
  // The constructor should only be invoked by the runtime as it builds its
243
  // caches
244
  // or populates them.  A ClassDescriptorV2 should only ever exist in a cache.
245
  ClassDescriptorV2(AppleObjCRuntimeV2 &runtime,
246
                    ObjCLanguageRuntime::ObjCISA isa, const char *name)
247
      : m_runtime(runtime), m_objc_class_ptr(isa), m_name(name),
248
70.1M
        m_ivars_storage(), m_image_to_method_lists(), m_last_version_updated() {
249
70.1M
  }
250
251
  bool Read_objc_class(Process *process,
252
                       std::unique_ptr<objc_class_t> &objc_class) const;
253
254
  bool Read_class_row(Process *process, const objc_class_t &objc_class,
255
                      std::unique_ptr<class_ro_t> &class_ro,
256
                      std::unique_ptr<class_rw_t> &class_rw) const;
257
258
  bool ProcessMethodList(std::function<bool(const char *, const char *)> const
259
                             &instance_method_func,
260
                         method_list_t &method_list) const;
261
262
  bool ProcessRelativeMethodLists(
263
      std::function<bool(const char *, const char *)> const
264
          &instance_method_func,
265
      lldb::addr_t relative_method_list_ptr) const;
266
267
  AppleObjCRuntimeV2
268
      &m_runtime; // The runtime, so we can read information lazily.
269
  lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t.  (I.e.,
270
                                 // objects of this class type have this as
271
                                 // their ISA)
272
  ConstString m_name;            // May be NULL
273
  iVarsStorage m_ivars_storage;
274
275
  mutable std::map<uint16_t, std::vector<method_list_t>>
276
      m_image_to_method_lists;
277
  mutable std::optional<uint64_t> m_last_version_updated;
278
};
279
280
// tagged pointer descriptor
281
class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor {
282
public:
283
0
  ClassDescriptorV2Tagged(ConstString class_name, uint64_t payload) {
284
0
    m_name = class_name;
285
0
    if (!m_name) {
286
0
      m_valid = false;
287
0
      return;
288
0
    }
289
0
    m_valid = true;
290
0
    m_payload = payload;
291
0
    m_info_bits = (m_payload & 0xF0ULL) >> 4;
292
0
    m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
293
0
  }
294
295
  ClassDescriptorV2Tagged(
296
      ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
297
1.11k
      uint64_t u_payload, int64_t s_payload) {
298
1.11k
    if (!actual_class_sp) {
299
0
      m_valid = false;
300
0
      return;
301
0
    }
302
1.11k
    m_name = actual_class_sp->GetClassName();
303
1.11k
    if (!m_name) {
304
0
      m_valid = false;
305
0
      return;
306
0
    }
307
1.11k
    m_valid = true;
308
1.11k
    m_payload = u_payload;
309
1.11k
    m_info_bits = (m_payload & 0x0FULL);
310
1.11k
    m_value_bits = (m_payload & ~0x0FULL) >> 4;
311
1.11k
    m_value_bits_signed = (s_payload & ~0x0FLL) >> 4;
312
1.11k
  }
313
314
1.11k
  ~ClassDescriptorV2Tagged() override = default;
315
316
888
  ConstString GetClassName() override { return m_name; }
317
318
24
  ObjCLanguageRuntime::ClassDescriptorSP GetSuperclass() override {
319
    // tagged pointers can represent a class that has a superclass, but since
320
    // that information is not
321
    // stored in the object itself, we would have to query the runtime to
322
    // discover the hierarchy
323
    // for the time being, we skip this step in the interest of static discovery
324
24
    return ObjCLanguageRuntime::ClassDescriptorSP();
325
24
  }
326
327
0
  ObjCLanguageRuntime::ClassDescriptorSP GetMetaclass() const override {
328
0
    return ObjCLanguageRuntime::ClassDescriptorSP();
329
0
  }
330
331
1.22k
  bool IsValid() override { return m_valid; }
332
333
358
  bool IsKVO() override {
334
358
    return false; // tagged pointers are not KVO'ed
335
358
  }
336
337
0
  bool IsCFType() override {
338
0
    return false; // tagged pointers are not CF objects
339
0
  }
340
341
  bool GetTaggedPointerInfo(uint64_t *info_bits = nullptr,
342
                            uint64_t *value_bits = nullptr,
343
148
                            uint64_t *payload = nullptr) override {
344
148
    if (info_bits)
345
128
      *info_bits = GetInfoBits();
346
148
    if (value_bits)
347
128
      *value_bits = GetValueBits();
348
148
    if (payload)
349
16
      *payload = GetPayload();
350
148
    return true;
351
148
  }
352
353
  bool GetTaggedPointerInfoSigned(uint64_t *info_bits = nullptr,
354
                                  int64_t *value_bits = nullptr,
355
274
                                  uint64_t *payload = nullptr) override {
356
274
    if (info_bits)
357
274
      *info_bits = GetInfoBits();
358
274
    if (value_bits)
359
274
      *value_bits = GetValueBitsSigned();
360
274
    if (payload)
361
0
      *payload = GetPayload();
362
274
    return true;
363
274
  }
364
365
0
  uint64_t GetInstanceSize() override {
366
0
    return (IsValid() ? m_pointer_size : 0);
367
0
  }
368
369
0
  ObjCLanguageRuntime::ObjCISA GetISA() override {
370
0
    return 0; // tagged pointers have no ISA
371
0
  }
372
373
  // these calls are not part of any formal tagged pointers specification
374
128
  virtual uint64_t GetValueBits() { return (IsValid() ? m_value_bits : 
00
); }
375
376
274
  virtual int64_t GetValueBitsSigned() {
377
274
    return (IsValid() ? m_value_bits_signed : 
00
);
378
274
  }
379
380
402
  virtual uint64_t GetInfoBits() { return (IsValid() ? m_info_bits : 
00
); }
381
382
16
  virtual uint64_t GetPayload() { return (IsValid() ? m_payload : 
00
); }
383
384
private:
385
  ConstString m_name;
386
  uint8_t m_pointer_size = 0;
387
  bool m_valid = false;
388
  uint64_t m_info_bits = 0;
389
  uint64_t m_value_bits = 0;
390
  int64_t m_value_bits_signed = 0;
391
  uint64_t m_payload = 0;
392
};
393
394
} // namespace lldb_private
395
396
#endif // LLDB_SOURCE_PLUGINS_LANGUAGERUNTIME_OBJC_APPLEOBJCRUNTIME_APPLEOBJCCLASSDESCRIPTORV2_H