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/Utility/Log.h"
14 
15 using namespace lldb;
16 using namespace lldb_private;
17 
18 bool ClassDescriptorV2::Read_objc_class(
19     Process *process, std::unique_ptr<objc_class_t> &objc_class) const {
20   objc_class = std::make_unique<objc_class_t>();
21 
22   bool ret = objc_class->Read(process, m_objc_class_ptr);
23 
24   if (!ret)
25     objc_class.reset();
26 
27   return ret;
28 }
29 
30 static lldb::addr_t GetClassDataMask(Process *process) {
31   switch (process->GetAddressByteSize()) {
32   case 4:
33     return 0xfffffffcUL;
34   case 8:
35     return 0x00007ffffffffff8UL;
36   default:
37     break;
38   }
39 
40   return LLDB_INVALID_ADDRESS;
41 }
42 
43 bool ClassDescriptorV2::objc_class_t::Read(Process *process,
44                                            lldb::addr_t addr) {
45   size_t ptr_size = process->GetAddressByteSize();
46 
47   size_t objc_class_size = ptr_size    // uintptr_t isa;
48                            + ptr_size  // Class superclass;
49                            + ptr_size  // void *cache;
50                            + ptr_size  // IMP *vtable;
51                            + ptr_size; // uintptr_t data_NEVER_USE;
52 
53   DataBufferHeap objc_class_buf(objc_class_size, '\0');
54   Status error;
55 
56   process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
57   if (error.Fail()) {
58     return false;
59   }
60 
61   DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size,
62                           process->GetByteOrder(),
63                           process->GetAddressByteSize());
64 
65   lldb::offset_t cursor = 0;
66 
67   m_isa = extractor.GetAddress_unchecked(&cursor);        // uintptr_t isa;
68   m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass;
69   m_cache_ptr = extractor.GetAddress_unchecked(&cursor);  // void *cache;
70   m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable;
71   lldb::addr_t data_NEVER_USE =
72       extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE;
73 
74   m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
75   m_data_ptr = data_NEVER_USE & GetClassDataMask(process);
76 
77   if (ABISP abi_sp = process->GetABI()) {
78     m_isa = abi_sp->FixCodeAddress(m_isa);
79     m_superclass = abi_sp->FixCodeAddress(m_superclass);
80   }
81   return true;
82 }
83 
84 bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
85   size_t ptr_size = process->GetAddressByteSize();
86 
87   size_t size = sizeof(uint32_t)   // uint32_t flags;
88                 + sizeof(uint32_t) // uint32_t version;
89                 + ptr_size         // const class_ro_t *ro;
90                 + ptr_size         // union { method_list_t **method_lists;
91                                    // method_list_t *method_list; };
92                 + ptr_size         // struct chained_property_list *properties;
93                 + ptr_size         // const protocol_list_t **protocols;
94                 + ptr_size         // Class firstSubclass;
95                 + ptr_size;        // Class nextSiblingClass;
96 
97   DataBufferHeap buffer(size, '\0');
98   Status error;
99 
100   process->ReadMemory(addr, buffer.GetBytes(), size, error);
101   if (error.Fail()) {
102     return false;
103   }
104 
105   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
106                           process->GetAddressByteSize());
107 
108   lldb::offset_t cursor = 0;
109 
110   m_flags = extractor.GetU32_unchecked(&cursor);
111   m_version = extractor.GetU32_unchecked(&cursor);
112   m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
113   if (ABISP abi_sp = process->GetABI())
114     m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
115   m_method_list_ptr = extractor.GetAddress_unchecked(&cursor);
116   m_properties_ptr = extractor.GetAddress_unchecked(&cursor);
117   m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
118   m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
119 
120   if (m_ro_ptr & 1) {
121     DataBufferHeap buffer(ptr_size, '\0');
122     process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error);
123     if (error.Fail())
124       return false;
125     cursor = 0;
126     DataExtractor extractor(buffer.GetBytes(), ptr_size,
127                             process->GetByteOrder(),
128                             process->GetAddressByteSize());
129     m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
130     if (ABISP abi_sp = process->GetABI())
131       m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr);
132   }
133 
134   return true;
135 }
136 
137 bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) {
138   size_t ptr_size = process->GetAddressByteSize();
139 
140   size_t size = sizeof(uint32_t)   // uint32_t flags;
141                 + sizeof(uint32_t) // uint32_t instanceStart;
142                 + sizeof(uint32_t) // uint32_t instanceSize;
143                 + (ptr_size == 8 ? sizeof(uint32_t)
144                                  : 0) // uint32_t reserved; // __LP64__ only
145                 + ptr_size            // const uint8_t *ivarLayout;
146                 + ptr_size            // const char *name;
147                 + ptr_size            // const method_list_t *baseMethods;
148                 + ptr_size            // const protocol_list_t *baseProtocols;
149                 + ptr_size            // const ivar_list_t *ivars;
150                 + ptr_size            // const uint8_t *weakIvarLayout;
151                 + ptr_size;           // const property_list_t *baseProperties;
152 
153   DataBufferHeap buffer(size, '\0');
154   Status error;
155 
156   process->ReadMemory(addr, buffer.GetBytes(), size, error);
157   if (error.Fail()) {
158     return false;
159   }
160 
161   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
162                           process->GetAddressByteSize());
163 
164   lldb::offset_t cursor = 0;
165 
166   m_flags = extractor.GetU32_unchecked(&cursor);
167   m_instanceStart = extractor.GetU32_unchecked(&cursor);
168   m_instanceSize = extractor.GetU32_unchecked(&cursor);
169   if (ptr_size == 8)
170     m_reserved = extractor.GetU32_unchecked(&cursor);
171   else
172     m_reserved = 0;
173   m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
174   m_name_ptr = extractor.GetAddress_unchecked(&cursor);
175   m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor);
176   m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor);
177   m_ivars_ptr = extractor.GetAddress_unchecked(&cursor);
178   m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
179   m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor);
180 
181   DataBufferHeap name_buf(1024, '\0');
182 
183   process->ReadCStringFromMemory(m_name_ptr, (char *)name_buf.GetBytes(),
184                                  name_buf.GetByteSize(), error);
185 
186   if (error.Fail()) {
187     return false;
188   }
189 
190   m_name.assign((char *)name_buf.GetBytes());
191 
192   return true;
193 }
194 
195 bool ClassDescriptorV2::Read_class_row(
196     Process *process, const objc_class_t &objc_class,
197     std::unique_ptr<class_ro_t> &class_ro,
198     std::unique_ptr<class_rw_t> &class_rw) const {
199   class_ro.reset();
200   class_rw.reset();
201 
202   Status error;
203   uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(
204       objc_class.m_data_ptr, sizeof(uint32_t), 0, error);
205   if (!error.Success())
206     return false;
207 
208   if (class_row_t_flags & RW_REALIZED) {
209     class_rw = std::make_unique<class_rw_t>();
210 
211     if (!class_rw->Read(process, objc_class.m_data_ptr)) {
212       class_rw.reset();
213       return false;
214     }
215 
216     class_ro = std::make_unique<class_ro_t>();
217 
218     if (!class_ro->Read(process, class_rw->m_ro_ptr)) {
219       class_rw.reset();
220       class_ro.reset();
221       return false;
222     }
223   } else {
224     class_ro = std::make_unique<class_ro_t>();
225 
226     if (!class_ro->Read(process, objc_class.m_data_ptr)) {
227       class_ro.reset();
228       return false;
229     }
230   }
231 
232   return true;
233 }
234 
235 bool ClassDescriptorV2::method_list_t::Read(Process *process,
236                                             lldb::addr_t addr) {
237   size_t size = sizeof(uint32_t)    // uint32_t entsize_NEVER_USE;
238                 + sizeof(uint32_t); // uint32_t count;
239 
240   DataBufferHeap buffer(size, '\0');
241   Status error;
242 
243   if (ABISP abi_sp = process->GetABI())
244     addr = abi_sp->FixCodeAddress(addr);
245   process->ReadMemory(addr, buffer.GetBytes(), size, error);
246   if (error.Fail()) {
247     return false;
248   }
249 
250   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
251                           process->GetAddressByteSize());
252 
253   lldb::offset_t cursor = 0;
254 
255   uint32_t entsize = extractor.GetU32_unchecked(&cursor);
256   m_is_small = (entsize & 0x80000000) != 0;
257   m_has_direct_selector = (entsize & 0x40000000) != 0;
258   m_entsize = entsize & 0xfffc;
259   m_count = extractor.GetU32_unchecked(&cursor);
260   m_first_ptr = addr + cursor;
261 
262   return true;
263 }
264 
265 bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr,
266                                        lldb::addr_t relative_selector_base_addr,
267                                        bool is_small, bool has_direct_sel) {
268   size_t ptr_size = process->GetAddressByteSize();
269   size_t size = GetSize(process, is_small);
270 
271   DataBufferHeap buffer(size, '\0');
272   Status error;
273 
274   process->ReadMemory(addr, buffer.GetBytes(), size, error);
275   if (error.Fail()) {
276     return false;
277   }
278 
279   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
280                           ptr_size);
281   lldb::offset_t cursor = 0;
282 
283   if (is_small) {
284     uint32_t nameref_offset = extractor.GetU32_unchecked(&cursor);
285     uint32_t types_offset = extractor.GetU32_unchecked(&cursor);
286     uint32_t imp_offset = extractor.GetU32_unchecked(&cursor);
287 
288     m_name_ptr = addr + nameref_offset;
289 
290     if (!has_direct_sel) {
291       // The SEL offset points to a SELRef. We need to dereference twice.
292       m_name_ptr = process->ReadUnsignedIntegerFromMemory(m_name_ptr, ptr_size,
293                                                           0, error);
294       if (!error.Success())
295         return false;
296     } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) {
297       m_name_ptr = relative_selector_base_addr + nameref_offset;
298     }
299     m_types_ptr = addr + 4 + types_offset;
300     m_imp_ptr = addr + 8 + imp_offset;
301   } else {
302     m_name_ptr = extractor.GetAddress_unchecked(&cursor);
303     m_types_ptr = extractor.GetAddress_unchecked(&cursor);
304     m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
305   }
306 
307   process->ReadCStringFromMemory(m_name_ptr, m_name, error);
308   if (error.Fail()) {
309     return false;
310   }
311 
312   process->ReadCStringFromMemory(m_types_ptr, m_types, error);
313   return !error.Fail();
314 }
315 
316 bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) {
317   size_t size = sizeof(uint32_t)    // uint32_t entsize;
318                 + sizeof(uint32_t); // uint32_t count;
319 
320   DataBufferHeap buffer(size, '\0');
321   Status error;
322 
323   process->ReadMemory(addr, buffer.GetBytes(), size, error);
324   if (error.Fail()) {
325     return false;
326   }
327 
328   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
329                           process->GetAddressByteSize());
330 
331   lldb::offset_t cursor = 0;
332 
333   m_entsize = extractor.GetU32_unchecked(&cursor);
334   m_count = extractor.GetU32_unchecked(&cursor);
335   m_first_ptr = addr + cursor;
336 
337   return true;
338 }
339 
340 bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
341   size_t size = GetSize(process);
342 
343   DataBufferHeap buffer(size, '\0');
344   Status error;
345 
346   process->ReadMemory(addr, buffer.GetBytes(), size, error);
347   if (error.Fail()) {
348     return false;
349   }
350 
351   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
352                           process->GetAddressByteSize());
353 
354   lldb::offset_t cursor = 0;
355 
356   m_offset_ptr = extractor.GetAddress_unchecked(&cursor);
357   m_name_ptr = extractor.GetAddress_unchecked(&cursor);
358   m_type_ptr = extractor.GetAddress_unchecked(&cursor);
359   m_alignment = extractor.GetU32_unchecked(&cursor);
360   m_size = extractor.GetU32_unchecked(&cursor);
361 
362   process->ReadCStringFromMemory(m_name_ptr, m_name, error);
363   if (error.Fail()) {
364     return false;
365   }
366 
367   process->ReadCStringFromMemory(m_type_ptr, m_type, error);
368   return !error.Fail();
369 }
370 
371 bool ClassDescriptorV2::Describe(
372     std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
373     std::function<bool(const char *, const char *)> const &instance_method_func,
374     std::function<bool(const char *, const char *)> const &class_method_func,
375     std::function<bool(const char *, const char *, lldb::addr_t,
376                        uint64_t)> const &ivar_func) const {
377   lldb_private::Process *process = m_runtime.GetProcess();
378 
379   std::unique_ptr<objc_class_t> objc_class;
380   std::unique_ptr<class_ro_t> class_ro;
381   std::unique_ptr<class_rw_t> class_rw;
382 
383   if (!Read_objc_class(process, objc_class))
384     return false;
385   if (!Read_class_row(process, *objc_class, class_ro, class_rw))
386     return false;
387 
388   static ConstString NSObject_name("NSObject");
389 
390   if (m_name != NSObject_name && superclass_func)
391     superclass_func(objc_class->m_superclass);
392 
393   if (instance_method_func) {
394     std::unique_ptr<method_list_t> base_method_list;
395 
396     base_method_list = std::make_unique<method_list_t>();
397     if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
398       return false;
399 
400     bool is_small = base_method_list->m_is_small;
401     bool has_direct_selector = base_method_list->m_has_direct_selector;
402 
403     if (base_method_list->m_entsize != method_t::GetSize(process, is_small))
404       return false;
405 
406     std::unique_ptr<method_t> method = std::make_unique<method_t>();
407     lldb::addr_t relative_selector_base_addr =
408         m_runtime.GetRelativeSelectorBaseAddr();
409     for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) {
410       method->Read(process,
411                    base_method_list->m_first_ptr +
412                        (i * base_method_list->m_entsize),
413                    relative_selector_base_addr, is_small, has_direct_selector);
414 
415       if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
416         break;
417     }
418   }
419 
420   if (class_method_func) {
421     AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass());
422 
423     // We don't care about the metaclass's superclass, or its class methods.
424     // Its instance methods are our class methods.
425 
426     if (metaclass) {
427       metaclass->Describe(
428           std::function<void(ObjCLanguageRuntime::ObjCISA)>(nullptr),
429           class_method_func,
430           std::function<bool(const char *, const char *)>(nullptr),
431           std::function<bool(const char *, const char *, lldb::addr_t,
432                              uint64_t)>(nullptr));
433     }
434   }
435 
436   if (ivar_func) {
437     if (class_ro->m_ivars_ptr != 0) {
438       ivar_list_t ivar_list;
439       if (!ivar_list.Read(process, class_ro->m_ivars_ptr))
440         return false;
441 
442       if (ivar_list.m_entsize != ivar_t::GetSize(process))
443         return false;
444 
445       ivar_t ivar;
446 
447       for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) {
448         ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize));
449 
450         if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(),
451                       ivar.m_offset_ptr, ivar.m_size))
452           break;
453       }
454     }
455   }
456 
457   return true;
458 }
459 
460 ConstString ClassDescriptorV2::GetClassName() {
461   if (!m_name) {
462     lldb_private::Process *process = m_runtime.GetProcess();
463 
464     if (process) {
465       std::unique_ptr<objc_class_t> objc_class;
466       std::unique_ptr<class_ro_t> class_ro;
467       std::unique_ptr<class_rw_t> class_rw;
468 
469       if (!Read_objc_class(process, objc_class))
470         return m_name;
471       if (!Read_class_row(process, *objc_class, class_ro, class_rw))
472         return m_name;
473 
474       m_name = ConstString(class_ro->m_name.c_str());
475     }
476   }
477   return m_name;
478 }
479 
480 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetSuperclass() {
481   lldb_private::Process *process = m_runtime.GetProcess();
482 
483   if (!process)
484     return ObjCLanguageRuntime::ClassDescriptorSP();
485 
486   std::unique_ptr<objc_class_t> objc_class;
487 
488   if (!Read_objc_class(process, objc_class))
489     return ObjCLanguageRuntime::ClassDescriptorSP();
490 
491   return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(
492       objc_class->m_superclass);
493 }
494 
495 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetMetaclass() const {
496   lldb_private::Process *process = m_runtime.GetProcess();
497 
498   if (!process)
499     return ObjCLanguageRuntime::ClassDescriptorSP();
500 
501   std::unique_ptr<objc_class_t> objc_class;
502 
503   if (!Read_objc_class(process, objc_class))
504     return ObjCLanguageRuntime::ClassDescriptorSP();
505 
506   lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa);
507 
508   return ObjCLanguageRuntime::ClassDescriptorSP(
509       new ClassDescriptorV2(m_runtime, candidate_isa, nullptr));
510 }
511 
512 uint64_t ClassDescriptorV2::GetInstanceSize() {
513   lldb_private::Process *process = m_runtime.GetProcess();
514 
515   if (process) {
516     std::unique_ptr<objc_class_t> objc_class;
517     std::unique_ptr<class_ro_t> class_ro;
518     std::unique_ptr<class_rw_t> class_rw;
519 
520     if (!Read_objc_class(process, objc_class))
521       return 0;
522     if (!Read_class_row(process, *objc_class, class_ro, class_rw))
523       return 0;
524 
525     return class_ro->m_instanceSize;
526   }
527 
528   return 0;
529 }
530 
531 ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {}
532 
533 size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); }
534 
535 ClassDescriptorV2::iVarDescriptor &ClassDescriptorV2::iVarsStorage::
536 operator[](size_t idx) {
537   return m_ivars[idx];
538 }
539 
540 void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime,
541                                            ClassDescriptorV2 &descriptor) {
542   if (m_filled)
543     return;
544   std::lock_guard<std::recursive_mutex> guard(m_mutex);
545   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
546   LLDB_LOGV(log, "class_name = {0}", descriptor.GetClassName());
547   m_filled = true;
548   ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(
549       runtime.GetEncodingToType());
550   Process *process(runtime.GetProcess());
551   if (!encoding_to_type_sp)
552     return;
553   descriptor.Describe(nullptr, nullptr, nullptr, [this, process,
554                                                   encoding_to_type_sp,
555                                                   log](const char *name,
556                                                        const char *type,
557                                                        lldb::addr_t offset_ptr,
558                                                        uint64_t size) -> bool {
559     const bool for_expression = false;
560     const bool stop_loop = false;
561     LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}",
562               name, type, offset_ptr, size);
563     CompilerType ivar_type =
564         encoding_to_type_sp->RealizeType(type, for_expression);
565     if (ivar_type) {
566       LLDB_LOGV(log,
567                 "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = "
568                 "{3}, type_size = {4}",
569                 name, type, offset_ptr, size,
570                 ivar_type.GetByteSize(nullptr).getValueOr(0));
571       Scalar offset_scalar;
572       Status error;
573       const int offset_ptr_size = 4;
574       const bool is_signed = false;
575       size_t read = process->ReadScalarIntegerFromMemory(
576           offset_ptr, offset_ptr_size, is_signed, offset_scalar, error);
577       if (error.Success() && 4 == read) {
578         LLDB_LOGV(log, "offset_ptr = {0:x} --> {1}", offset_ptr,
579                   offset_scalar.SInt());
580         m_ivars.push_back(
581             {ConstString(name), ivar_type, size, offset_scalar.SInt()});
582       } else
583         LLDB_LOGV(log, "offset_ptr = {0:x} --> read fail, read = %{1}",
584                   offset_ptr, read);
585     }
586     return stop_loop;
587   });
588 }
589 
590 void ClassDescriptorV2::GetIVarInformation() {
591   m_ivars_storage.fill(m_runtime, *this);
592 }
593