Coverage Report

Created: 2023-09-30 09:22

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCClassDescriptorV2.cpp
Line
Count
Source (jump to first uncovered line)
1
//===-- AppleObjCClassDescriptorV2.cpp ------------------------------------===//
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
#include "AppleObjCClassDescriptorV2.h"
10
11
#include "lldb/Expression/FunctionCaller.h"
12
#include "lldb/Target/ABI.h"
13
#include "lldb/Target/Language.h"
14
#include "lldb/Utility/LLDBLog.h"
15
#include "lldb/Utility/Log.h"
16
#include "lldb/lldb-enumerations.h"
17
18
using namespace lldb;
19
using namespace lldb_private;
20
21
bool ClassDescriptorV2::Read_objc_class(
22
2.99k
    Process *process, std::unique_ptr<objc_class_t> &objc_class) const {
23
2.99k
  objc_class = std::make_unique<objc_class_t>();
24
25
2.99k
  bool ret = objc_class->Read(process, m_objc_class_ptr);
26
27
2.99k
  if (!ret)
28
0
    objc_class.reset();
29
30
2.99k
  return ret;
31
2.99k
}
32
33
2.99k
static lldb::addr_t GetClassDataMask(Process *process) {
34
2.99k
  switch (process->GetAddressByteSize()) {
35
0
  case 4:
36
0
    return 0xfffffffcUL;
37
2.99k
  case 8:
38
2.99k
    return 0x00007ffffffffff8UL;
39
0
  default:
40
0
    break;
41
2.99k
  }
42
43
0
  return LLDB_INVALID_ADDRESS;
44
2.99k
}
45
46
bool ClassDescriptorV2::objc_class_t::Read(Process *process,
47
2.99k
                                           lldb::addr_t addr) {
48
2.99k
  size_t ptr_size = process->GetAddressByteSize();
49
50
2.99k
  size_t objc_class_size = ptr_size    // uintptr_t isa;
51
2.99k
                           + ptr_size  // Class superclass;
52
2.99k
                           + ptr_size  // void *cache;
53
2.99k
                           + ptr_size  // IMP *vtable;
54
2.99k
                           + ptr_size; // uintptr_t data_NEVER_USE;
55
56
2.99k
  DataBufferHeap objc_class_buf(objc_class_size, '\0');
57
2.99k
  Status error;
58
59
2.99k
  process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
60
2.99k
  if (error.Fail()) {
61
0
    return false;
62
0
  }
63
64
2.99k
  DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size,
65
2.99k
                          process->GetByteOrder(),
66
2.99k
                          process->GetAddressByteSize());
67
68
2.99k
  lldb::offset_t cursor = 0;
69
70
2.99k
  m_isa = extractor.GetAddress_unchecked(&cursor);        // uintptr_t isa;
71
2.99k
  m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass;
72
2.99k
  m_cache_ptr = extractor.GetAddress_unchecked(&cursor);  // void *cache;
73
2.99k
  m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
74
2.99k
  lldb::addr_t data_NEVER_USE =
75
2.99k
      extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
76
77
2.99k
  m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
78
2.99k
  m_data_ptr = data_NEVER_USE & GetClassDataMask(process);
79
80
2.99k
  if (ABISP abi_sp = process->GetABI()) {
81
2.99k
    m_isa = abi_sp->FixCodeAddress(m_isa);
82
2.99k
    m_superclass = abi_sp->FixCodeAddress(m_superclass);
83
2.99k
    m_data_ptr = abi_sp->FixCodeAddress(m_data_ptr);
84
2.99k
  }
85
2.99k
  return true;
86
2.99k
}
87
88
1.51k
bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
89
1.51k
  size_t ptr_size = process->GetAddressByteSize();
90
91
1.51k
  size_t size = sizeof(uint32_t)   // uint32_t flags;
92
1.51k
                + sizeof(uint32_t) // uint32_t version;
93
1.51k
                + ptr_size         // const class_ro_t *ro;
94
1.51k
                + ptr_size         // union { method_list_t **method_lists;
95
                                   // method_list_t *method_list; };
96
1.51k
                + ptr_size         // struct chained_property_list *properties;
97
1.51k
                + ptr_size         // const protocol_list_t **protocols;
98
1.51k
                + ptr_size         // Class firstSubclass;
99
1.51k
                + ptr_size;        // Class nextSiblingClass;
100
101
1.51k
  DataBufferHeap buffer(size, '\0');
102
1.51k
  Status error;
103
104
1.51k
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
105
1.51k
  if (error.Fail()) {
106
0
    return false;
107
0
  }
108
109
1.51k
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
110
1.51k
                          process->GetAddressByteSize());
111
112
1.51k
  lldb::offset_t cursor = 0;
113
114
1.51k
  m_flags = extractor.GetU32_unchecked(&cursor);
115
1.51k
  m_version = extractor.GetU32_unchecked(&cursor);
116
1.51k
  m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
117
1.51k
  if (ABISP abi_sp = process->GetABI())
118
1.51k
    m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
119
1.51k
  m_method_list_ptr = extractor.GetAddress_unchecked(&cursor);
120
1.51k
  m_properties_ptr = extractor.GetAddress_unchecked(&cursor);
121
1.51k
  m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
122
1.51k
  m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
123
124
1.51k
  if (m_ro_ptr & 1) {
125
538
    DataBufferHeap buffer(ptr_size, '\0');
126
538
    process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error);
127
538
    if (error.Fail())
128
0
      return false;
129
538
    cursor = 0;
130
538
    DataExtractor extractor(buffer.GetBytes(), ptr_size,
131
538
                            process->GetByteOrder(),
132
538
                            process->GetAddressByteSize());
133
538
    m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
134
538
    if (ABISP abi_sp = process->GetABI())
135
538
      m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
136
538
  }
137
138
1.51k
  return true;
139
1.51k
}
140
141
1.53k
bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) {
142
1.53k
  size_t ptr_size = process->GetAddressByteSize();
143
144
1.53k
  size_t size = sizeof(uint32_t)   // uint32_t flags;
145
1.53k
                + sizeof(uint32_t) // uint32_t instanceStart;
146
1.53k
                + sizeof(uint32_t) // uint32_t instanceSize;
147
1.53k
                + (ptr_size == 8 ? sizeof(uint32_t)
148
1.53k
                                 : 
00
) // uint32_t reserved; // __LP64__ only
149
1.53k
                + ptr_size            // const uint8_t *ivarLayout;
150
1.53k
                + ptr_size            // const char *name;
151
1.53k
                + ptr_size            // const method_list_t *baseMethods;
152
1.53k
                + ptr_size            // const protocol_list_t *baseProtocols;
153
1.53k
                + ptr_size            // const ivar_list_t *ivars;
154
1.53k
                + ptr_size            // const uint8_t *weakIvarLayout;
155
1.53k
                + ptr_size;           // const property_list_t *baseProperties;
156
157
1.53k
  DataBufferHeap buffer(size, '\0');
158
1.53k
  Status error;
159
160
1.53k
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
161
1.53k
  if (error.Fail()) {
162
0
    return false;
163
0
  }
164
165
1.53k
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
166
1.53k
                          process->GetAddressByteSize());
167
168
1.53k
  lldb::offset_t cursor = 0;
169
170
1.53k
  m_flags = extractor.GetU32_unchecked(&cursor);
171
1.53k
  m_instanceStart = extractor.GetU32_unchecked(&cursor);
172
1.53k
  m_instanceSize = extractor.GetU32_unchecked(&cursor);
173
1.53k
  if (ptr_size == 8)
174
1.53k
    m_reserved = extractor.GetU32_unchecked(&cursor);
175
0
  else
176
0
    m_reserved = 0;
177
1.53k
  m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
178
1.53k
  m_name_ptr = extractor.GetAddress_unchecked(&cursor);
179
1.53k
  m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor);
180
1.53k
  m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor);
181
1.53k
  m_ivars_ptr = extractor.GetAddress_unchecked(&cursor);
182
1.53k
  m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
183
1.53k
  m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor);
184
185
1.53k
  DataBufferHeap name_buf(1024, '\0');
186
187
1.53k
  process->ReadCStringFromMemory(m_name_ptr, (char *)name_buf.GetBytes(),
188
1.53k
                                 name_buf.GetByteSize(), error);
189
190
1.53k
  if (error.Fail()) {
191
0
    return false;
192
0
  }
193
194
1.53k
  m_name.assign((char *)name_buf.GetBytes());
195
196
1.53k
  return true;
197
1.53k
}
198
199
bool ClassDescriptorV2::Read_class_row(
200
    Process *process, const objc_class_t &objc_class,
201
    std::unique_ptr<class_ro_t> &class_ro,
202
1.53k
    std::unique_ptr<class_rw_t> &class_rw) const {
203
1.53k
  class_ro.reset();
204
1.53k
  class_rw.reset();
205
206
1.53k
  Status error;
207
1.53k
  uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(
208
1.53k
      objc_class.m_data_ptr, sizeof(uint32_t), 0, error);
209
1.53k
  if (!error.Success())
210
0
    return false;
211
212
1.53k
  if (class_row_t_flags & RW_REALIZED) {
213
1.51k
    class_rw = std::make_unique<class_rw_t>();
214
215
1.51k
    if (!class_rw->Read(process, objc_class.m_data_ptr)) {
216
0
      class_rw.reset();
217
0
      return false;
218
0
    }
219
220
1.51k
    class_ro = std::make_unique<class_ro_t>();
221
222
1.51k
    if (!class_ro->Read(process, class_rw->m_ro_ptr)) {
223
0
      class_rw.reset();
224
0
      class_ro.reset();
225
0
      return false;
226
0
    }
227
1.51k
  } else {
228
26
    class_ro = std::make_unique<class_ro_t>();
229
230
26
    if (!class_ro->Read(process, objc_class.m_data_ptr)) {
231
0
      class_ro.reset();
232
0
      return false;
233
0
    }
234
26
  }
235
236
1.53k
  return true;
237
1.53k
}
238
239
bool ClassDescriptorV2::method_list_t::Read(Process *process,
240
636
                                            lldb::addr_t addr) {
241
636
  size_t size = sizeof(uint32_t)    // uint32_t entsize_NEVER_USE;
242
636
                + sizeof(uint32_t); // uint32_t count;
243
244
636
  DataBufferHeap buffer(size, '\0');
245
636
  Status error;
246
247
636
  if (ABISP abi_sp = process->GetABI())
248
636
    addr = abi_sp->FixCodeAddress(addr);
249
636
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
250
636
  if (error.Fail()) {
251
52
    return false;
252
52
  }
253
254
584
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
255
584
                          process->GetAddressByteSize());
256
257
584
  lldb::offset_t cursor = 0;
258
259
584
  uint32_t entsize = extractor.GetU32_unchecked(&cursor);
260
584
  m_is_small = (entsize & 0x80000000) != 0;
261
584
  m_has_direct_selector = (entsize & 0x40000000) != 0;
262
584
  m_entsize = entsize & 0xfffc;
263
584
  m_count = extractor.GetU32_unchecked(&cursor);
264
584
  m_first_ptr = addr + cursor;
265
266
584
  return true;
267
636
}
268
269
bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
270
                                       lldb::addr_t relative_selector_base_addr,
271
20.4k
                                       bool is_small, bool has_direct_sel) {
272
20.4k
  size_t ptr_size = process->GetAddressByteSize();
273
20.4k
  size_t size = GetSize(process, is_small);
274
275
20.4k
  DataBufferHeap buffer(size, '\0');
276
20.4k
  Status error;
277
278
20.4k
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
279
20.4k
  if (error.Fail()) {
280
0
    return false;
281
0
  }
282
283
20.4k
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
284
20.4k
                          ptr_size);
285
20.4k
  lldb::offset_t cursor = 0;
286
287
20.4k
  if (is_small) {
288
0
    uint32_t nameref_offset = extractor.GetU32_unchecked(&cursor);
289
0
    uint32_t types_offset = extractor.GetU32_unchecked(&cursor);
290
0
    uint32_t imp_offset = extractor.GetU32_unchecked(&cursor);
291
292
0
    m_name_ptr = addr + nameref_offset;
293
294
0
    if (!has_direct_sel) {
295
      // The SEL offset points to a SELRef. We need to dereference twice.
296
0
      m_name_ptr = process->ReadUnsignedIntegerFromMemory(m_name_ptr, ptr_size,
297
0
                                                          0, error);
298
0
      if (!error.Success())
299
0
        return false;
300
0
    } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) {
301
0
      m_name_ptr = relative_selector_base_addr + nameref_offset;
302
0
    }
303
0
    m_types_ptr = addr + 4 + types_offset;
304
0
    m_imp_ptr = addr + 8 + imp_offset;
305
20.4k
  } else {
306
20.4k
    m_name_ptr = extractor.GetAddress_unchecked(&cursor);
307
20.4k
    m_types_ptr = extractor.GetAddress_unchecked(&cursor);
308
20.4k
    m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
309
20.4k
  }
310
311
20.4k
  process->ReadCStringFromMemory(m_name_ptr, m_name, error);
312
20.4k
  if (error.Fail()) {
313
0
    return false;
314
0
  }
315
316
20.4k
  process->ReadCStringFromMemory(m_types_ptr, m_types, error);
317
20.4k
  return !error.Fail();
318
20.4k
}
319
320
241
bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) {
321
241
  size_t size = sizeof(uint32_t)    // uint32_t entsize;
322
241
                + sizeof(uint32_t); // uint32_t count;
323
324
241
  DataBufferHeap buffer(size, '\0');
325
241
  Status error;
326
327
241
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
328
241
  if (error.Fail()) {
329
0
    return false;
330
0
  }
331
332
241
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
333
241
                          process->GetAddressByteSize());
334
335
241
  lldb::offset_t cursor = 0;
336
337
241
  m_entsize = extractor.GetU32_unchecked(&cursor);
338
241
  m_count = extractor.GetU32_unchecked(&cursor);
339
241
  m_first_ptr = addr + cursor;
340
341
241
  return true;
342
241
}
343
344
515
bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
345
515
  size_t size = GetSize(process);
346
347
515
  DataBufferHeap buffer(size, '\0');
348
515
  Status error;
349
350
515
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
351
515
  if (error.Fail()) {
352
0
    return false;
353
0
  }
354
355
515
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
356
515
                          process->GetAddressByteSize());
357
358
515
  lldb::offset_t cursor = 0;
359
360
515
  m_offset_ptr = extractor.GetAddress_unchecked(&cursor);
361
515
  m_name_ptr = extractor.GetAddress_unchecked(&cursor);
362
515
  m_type_ptr = extractor.GetAddress_unchecked(&cursor);
363
515
  m_alignment = extractor.GetU32_unchecked(&cursor);
364
515
  m_size = extractor.GetU32_unchecked(&cursor);
365
366
515
  process->ReadCStringFromMemory(m_name_ptr, m_name, error);
367
515
  if (error.Fail()) {
368
0
    return false;
369
0
  }
370
371
515
  process->ReadCStringFromMemory(m_type_ptr, m_type, error);
372
515
  return !error.Fail();
373
515
}
374
375
bool ClassDescriptorV2::relative_list_entry_t::Read(Process *process,
376
0
                                                    lldb::addr_t addr) {
377
0
  Log *log = GetLog(LLDBLog::Types);
378
0
  size_t size = sizeof(uint64_t); // m_image_index : 16
379
                                  // m_list_offset : 48
380
381
0
  DataBufferHeap buffer(size, '\0');
382
0
  Status error;
383
384
0
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
385
  // FIXME: Propagate this error up
386
0
  if (error.Fail()) {
387
0
    LLDB_LOG(log, "Failed to read relative_list_entry_t at address {0:x}",
388
0
             addr);
389
0
    return false;
390
0
  }
391
392
0
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
393
0
                          process->GetAddressByteSize());
394
0
  lldb::offset_t cursor = 0;
395
0
  uint64_t raw_entry = extractor.GetU64_unchecked(&cursor);
396
0
  m_image_index = raw_entry & 0xFFFF;
397
0
  m_list_offset = (int64_t)(raw_entry >> 16);
398
0
  return true;
399
0
}
400
401
bool ClassDescriptorV2::relative_list_list_t::Read(Process *process,
402
0
                                                   lldb::addr_t addr) {
403
0
  Log *log = GetLog(LLDBLog::Types);
404
0
  size_t size = sizeof(uint32_t)    // m_entsize
405
0
                + sizeof(uint32_t); // m_count
406
407
0
  DataBufferHeap buffer(size, '\0');
408
0
  Status error;
409
410
  // FIXME: Propagate this error up
411
0
  process->ReadMemory(addr, buffer.GetBytes(), size, error);
412
0
  if (error.Fail()) {
413
0
    LLDB_LOG(log, "Failed to read relative_list_list_t at address 0x" PRIx64,
414
0
             addr);
415
0
    return false;
416
0
  }
417
418
0
  DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
419
0
                          process->GetAddressByteSize());
420
0
  lldb::offset_t cursor = 0;
421
0
  m_entsize = extractor.GetU32_unchecked(&cursor);
422
0
  m_count = extractor.GetU32_unchecked(&cursor);
423
0
  m_first_ptr = addr + cursor;
424
0
  return true;
425
0
}
426
427
std::optional<ClassDescriptorV2::method_list_t>
428
ClassDescriptorV2::GetMethodList(Process *process,
429
636
                                 lldb::addr_t method_list_ptr) const {
430
636
  Log *log = GetLog(LLDBLog::Types);
431
636
  ClassDescriptorV2::method_list_t method_list;
432
636
  if (!method_list.Read(process, method_list_ptr))
433
52
    return std::nullopt;
434
435
584
  const size_t method_size = method_t::GetSize(process, method_list.m_is_small);
436
584
  if (method_list.m_entsize != method_size) {
437
0
    LLDB_LOG(log,
438
0
             "method_list_t at address 0x" PRIx64 " has an entsize of " PRIu16
439
0
             " but method size should be " PRIu64,
440
0
             method_list_ptr, method_list.m_entsize, method_size);
441
0
    return std::nullopt;
442
0
  }
443
444
584
  return method_list;
445
584
}
446
447
bool ClassDescriptorV2::ProcessMethodList(
448
    std::function<bool(const char *, const char *)> const &instance_method_func,
449
584
    ClassDescriptorV2::method_list_t &method_list) const {
450
584
  lldb_private::Process *process = m_runtime.GetProcess();
451
584
  auto method = std::make_unique<method_t>();
452
584
  lldb::addr_t relative_selector_base_addr =
453
584
      m_runtime.GetRelativeSelectorBaseAddr();
454
20.9k
  for (uint32_t i = 0, e = method_list.m_count; i < e; 
++i20.4k
) {
455
20.4k
    method->Read(process, method_list.m_first_ptr + (i * method_list.m_entsize),
456
20.4k
                 relative_selector_base_addr, method_list.m_is_small,
457
20.4k
                 method_list.m_has_direct_selector);
458
20.4k
    if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
459
0
      break;
460
20.4k
  }
461
584
  return true;
462
584
}
463
464
// The relevant data structures:
465
//  - relative_list_list_t
466
//    - uint32_t count
467
//    - uint32_t entsize
468
//    - Followed by <count> number of relative_list_entry_t of size <entsize>
469
//
470
//  - relative_list_entry_t
471
//    - uint64_t image_index : 16
472
//    - int64_t list_offset : 48
473
//    - Note: The above 2 fit into 8 bytes always
474
//
475
//    image_index corresponds to an image in the shared cache
476
//    list_offset is used to calculate the address of the method_list_t we want
477
bool ClassDescriptorV2::ProcessRelativeMethodLists(
478
    std::function<bool(const char *, const char *)> const &instance_method_func,
479
0
    lldb::addr_t relative_method_list_ptr) const {
480
0
  lldb_private::Process *process = m_runtime.GetProcess();
481
0
  auto relative_method_lists = std::make_unique<relative_list_list_t>();
482
483
  // 1. Process the count and entsize of the relative_list_list_t
484
0
  if (!relative_method_lists->Read(process, relative_method_list_ptr))
485
0
    return false;
486
487
0
  auto entry = std::make_unique<relative_list_entry_t>();
488
0
  for (uint32_t i = 0; i < relative_method_lists->m_count; i++) {
489
    // 2. Extract the image index and the list offset from the
490
    // relative_list_entry_t
491
0
    const lldb::addr_t entry_addr = relative_method_lists->m_first_ptr +
492
0
                                    (i * relative_method_lists->m_entsize);
493
0
    if (!entry->Read(process, entry_addr))
494
0
      return false;
495
496
    // 3. Calculate the pointer to the method_list_t from the
497
    // relative_list_entry_t
498
0
    const lldb::addr_t method_list_addr = entry_addr + entry->m_list_offset;
499
500
    // 4. Get the method_list_t from the pointer
501
0
    std::optional<method_list_t> method_list =
502
0
        GetMethodList(process, method_list_addr);
503
0
    if (!method_list)
504
0
      return false;
505
506
    // 5. Cache the result so we don't need to reconstruct it later.
507
0
    m_image_to_method_lists[entry->m_image_index].emplace_back(*method_list);
508
509
    // 6. If the relevant image is loaded, add the methods to the Decl
510
0
    if (!m_runtime.IsSharedCacheImageLoaded(entry->m_image_index))
511
0
      continue;
512
513
0
    if (!ProcessMethodList(instance_method_func, *method_list))
514
0
      return false;
515
0
  }
516
517
  // We need to keep track of the last time we updated so we can re-update the
518
  // type information in the future
519
0
  m_last_version_updated = m_runtime.GetSharedCacheImageHeaderVersion();
520
521
0
  return true;
522
0
}
523
524
bool ClassDescriptorV2::Describe(
525
    std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
526
    std::function<bool(const char *, const char *)> const &instance_method_func,
527
    std::function<bool(const char *, const char *)> const &class_method_func,
528
    std::function<bool(const char *, const char *, lldb::addr_t,
529
692
                       uint64_t)> const &ivar_func) const {
530
692
  lldb_private::Process *process = m_runtime.GetProcess();
531
532
692
  std::unique_ptr<objc_class_t> objc_class;
533
692
  std::unique_ptr<class_ro_t> class_ro;
534
692
  std::unique_ptr<class_rw_t> class_rw;
535
536
692
  if (!Read_objc_class(process, objc_class))
537
0
    return false;
538
692
  if (!Read_class_row(process, *objc_class, class_ro, class_rw))
539
0
    return false;
540
541
692
  static ConstString NSObject_name("NSObject");
542
543
692
  if (m_name != NSObject_name && 
superclass_func584
)
544
212
    superclass_func(objc_class->m_superclass);
545
546
692
  if (instance_method_func) {
547
    // This is a relative list of lists
548
636
    if (class_ro->m_baseMethods_ptr & 1) {
549
0
      if (!ProcessRelativeMethodLists(instance_method_func,
550
0
                                      class_ro->m_baseMethods_ptr ^ 1))
551
0
        return false;
552
636
    } else {
553
636
      std::optional<method_list_t> base_method_list =
554
636
          GetMethodList(process, class_ro->m_baseMethods_ptr);
555
636
      if (!base_method_list)
556
52
        return false;
557
584
      if (!ProcessMethodList(instance_method_func, *base_method_list))
558
0
        return false;
559
584
    }
560
636
  }
561
562
640
  if (class_method_func) {
563
316
    AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass());
564
565
    // We don't care about the metaclass's superclass, or its class methods.
566
    // Its instance methods are our class methods.
567
568
316
    if (metaclass) {
569
316
      metaclass->Describe(
570
316
          std::function<void(ObjCLanguageRuntime::ObjCISA)>(nullptr),
571
316
          class_method_func,
572
316
          std::function<bool(const char *, const char *)>(nullptr),
573
316
          std::function<bool(const char *, const char *, lldb::addr_t,
574
316
                             uint64_t)>(nullptr));
575
316
    }
576
316
  }
577
578
640
  if (ivar_func) {
579
372
    if (class_ro->m_ivars_ptr != 0) {
580
241
      ivar_list_t ivar_list;
581
241
      if (!ivar_list.Read(process, class_ro->m_ivars_ptr))
582
0
        return false;
583
584
241
      if (ivar_list.m_entsize != ivar_t::GetSize(process))
585
0
        return false;
586
587
241
      ivar_t ivar;
588
589
749
      for (uint32_t i = 0, e = ivar_list.m_count; i < e; 
++i508
) {
590
515
        ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize));
591
592
515
        if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(),
593
515
                      ivar.m_offset_ptr, ivar.m_size))
594
7
          break;
595
515
      }
596
241
    }
597
372
  }
598
599
640
  return true;
600
640
}
601
602
7.79k
ConstString ClassDescriptorV2::GetClassName() {
603
7.79k
  if (!m_name) {
604
847
    lldb_private::Process *process = m_runtime.GetProcess();
605
606
847
    if (process) {
607
847
      std::unique_ptr<objc_class_t> objc_class;
608
847
      std::unique_ptr<class_ro_t> class_ro;
609
847
      std::unique_ptr<class_rw_t> class_rw;
610
611
847
      if (!Read_objc_class(process, objc_class))
612
0
        return m_name;
613
847
      if (!Read_class_row(process, *objc_class, class_ro, class_rw))
614
0
        return m_name;
615
616
847
      m_name = ConstString(class_ro->m_name.c_str());
617
847
    }
618
847
  }
619
7.79k
  return m_name;
620
7.79k
}
621
622
317
ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetSuperclass() {
623
317
  lldb_private::Process *process = m_runtime.GetProcess();
624
625
317
  if (!process)
626
0
    return ObjCLanguageRuntime::ClassDescriptorSP();
627
628
317
  std::unique_ptr<objc_class_t> objc_class;
629
630
317
  if (!Read_objc_class(process, objc_class))
631
0
    return ObjCLanguageRuntime::ClassDescriptorSP();
632
633
317
  return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(
634
317
      objc_class->m_superclass);
635
317
}
636
637
316
ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetMetaclass() const {
638
316
  lldb_private::Process *process = m_runtime.GetProcess();
639
640
316
  if (!process)
641
0
    return ObjCLanguageRuntime::ClassDescriptorSP();
642
643
316
  std::unique_ptr<objc_class_t> objc_class;
644
645
316
  if (!Read_objc_class(process, objc_class))
646
0
    return ObjCLanguageRuntime::ClassDescriptorSP();
647
648
316
  lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa);
649
650
316
  return ObjCLanguageRuntime::ClassDescriptorSP(
651
316
      new ClassDescriptorV2(m_runtime, candidate_isa, nullptr));
652
316
}
653
654
0
uint64_t ClassDescriptorV2::GetInstanceSize() {
655
0
  lldb_private::Process *process = m_runtime.GetProcess();
656
657
0
  if (process) {
658
0
    std::unique_ptr<objc_class_t> objc_class;
659
0
    std::unique_ptr<class_ro_t> class_ro;
660
0
    std::unique_ptr<class_rw_t> class_rw;
661
662
0
    if (!Read_objc_class(process, objc_class))
663
0
      return 0;
664
0
    if (!Read_class_row(process, *objc_class, class_ro, class_rw))
665
0
      return 0;
666
667
0
    return class_ro->m_instanceSize;
668
0
  }
669
670
0
  return 0;
671
0
}
672
673
// From the ObjC runtime.
674
static uint8_t IS_SWIFT_STABLE = 1U << 1;
675
676
819
LanguageType ClassDescriptorV2::GetImplementationLanguage() const {
677
819
  std::unique_ptr<objc_class_t> objc_class;
678
819
  if (auto *process = m_runtime.GetProcess())
679
819
    if (Read_objc_class(process, objc_class))
680
819
      if (objc_class->m_flags & IS_SWIFT_STABLE)
681
0
        return lldb::eLanguageTypeSwift;
682
683
819
  return lldb::eLanguageTypeObjC;
684
819
}
685
686
78.4M
ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {}
687
688
453
size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); }
689
690
ClassDescriptorV2::iVarDescriptor &ClassDescriptorV2::iVarsStorage::
691
186
operator[](size_t idx) {
692
186
  return m_ivars[idx];
693
186
}
694
695
void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime,
696
453
                                           ClassDescriptorV2 &descriptor) {
697
453
  if (m_filled)
698
404
    return;
699
49
  std::lock_guard<std::recursive_mutex> guard(m_mutex);
700
49
  Log *log = GetLog(LLDBLog::Types);
701
49
  LLDB_LOGV(log, "class_name = {0}", descriptor.GetClassName());
702
49
  m_filled = true;
703
49
  ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(
704
49
      runtime.GetEncodingToType());
705
49
  Process *process(runtime.GetProcess());
706
49
  if (!encoding_to_type_sp)
707
0
    return;
708
49
  descriptor.Describe(nullptr, nullptr, nullptr, [this, process,
709
49
                                                  encoding_to_type_sp,
710
49
                                                  log](const char *name,
711
49
                                                       const char *type,
712
49
                                                       lldb::addr_t offset_ptr,
713
143
                                                       uint64_t size) -> bool {
714
143
    const bool for_expression = false;
715
143
    const bool stop_loop = false;
716
143
    LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}",
717
143
              name, type, offset_ptr, size);
718
143
    CompilerType ivar_type =
719
143
        encoding_to_type_sp->RealizeType(type, for_expression);
720
143
    if (ivar_type) {
721
135
      LLDB_LOGV(log,
722
135
                "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = "
723
135
                "{3}, type_size = {4}",
724
135
                name, type, offset_ptr, size,
725
135
                ivar_type.GetByteSize(nullptr).value_or(0));
726
135
      Scalar offset_scalar;
727
135
      Status error;
728
135
      const int offset_ptr_size = 4;
729
135
      const bool is_signed = false;
730
135
      size_t read = process->ReadScalarIntegerFromMemory(
731
135
          offset_ptr, offset_ptr_size, is_signed, offset_scalar, error);
732
135
      if (error.Success() && 4 == read) {
733
135
        LLDB_LOGV(log, "offset_ptr = {0:x} --> {1}", offset_ptr,
734
135
                  offset_scalar.SInt());
735
135
        m_ivars.push_back(
736
135
            {ConstString(name), ivar_type, size, offset_scalar.SInt()});
737
135
      } else
738
0
        LLDB_LOGV(log, "offset_ptr = {0:x} --> read fail, read = %{1}",
739
135
                  offset_ptr, read);
740
135
    }
741
143
    return stop_loop;
742
143
  });
743
49
}
744
745
453
void ClassDescriptorV2::GetIVarInformation() {
746
453
  m_ivars_storage.fill(m_runtime, *this);
747
453
}