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