1 //===-- AppleObjCClassDescriptorV2.cpp -----------------------------*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "AppleObjCClassDescriptorV2.h"
11 
12 #include "lldb/Expression/FunctionCaller.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.reset(new 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   return true;
78 }
79 
80 bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) {
81   size_t ptr_size = process->GetAddressByteSize();
82 
83   size_t size = sizeof(uint32_t)   // uint32_t flags;
84                 + sizeof(uint32_t) // uint32_t version;
85                 + ptr_size         // const class_ro_t *ro;
86                 + ptr_size         // union { method_list_t **method_lists;
87                                    // method_list_t *method_list; };
88                 + ptr_size         // struct chained_property_list *properties;
89                 + ptr_size         // const protocol_list_t **protocols;
90                 + ptr_size         // Class firstSubclass;
91                 + ptr_size;        // Class nextSiblingClass;
92 
93   DataBufferHeap buffer(size, '\0');
94   Status error;
95 
96   process->ReadMemory(addr, buffer.GetBytes(), size, error);
97   if (error.Fail()) {
98     return false;
99   }
100 
101   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
102                           process->GetAddressByteSize());
103 
104   lldb::offset_t cursor = 0;
105 
106   m_flags = extractor.GetU32_unchecked(&cursor);
107   m_version = extractor.GetU32_unchecked(&cursor);
108   m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
109   m_method_list_ptr = extractor.GetAddress_unchecked(&cursor);
110   m_properties_ptr = extractor.GetAddress_unchecked(&cursor);
111   m_firstSubclass = extractor.GetAddress_unchecked(&cursor);
112   m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor);
113 
114   if (m_ro_ptr & 1) {
115     DataBufferHeap buffer(ptr_size, '\0');
116     process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error);
117     if (error.Fail())
118       return false;
119     cursor = 0;
120     DataExtractor extractor(buffer.GetBytes(), ptr_size,
121                             process->GetByteOrder(),
122                             process->GetAddressByteSize());
123     m_ro_ptr = extractor.GetAddress_unchecked(&cursor);
124   }
125 
126   return true;
127 }
128 
129 bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) {
130   size_t ptr_size = process->GetAddressByteSize();
131 
132   size_t size = sizeof(uint32_t)   // uint32_t flags;
133                 + sizeof(uint32_t) // uint32_t instanceStart;
134                 + sizeof(uint32_t) // uint32_t instanceSize;
135                 + (ptr_size == 8 ? sizeof(uint32_t)
136                                  : 0) // uint32_t reserved; // __LP64__ only
137                 + ptr_size            // const uint8_t *ivarLayout;
138                 + ptr_size            // const char *name;
139                 + ptr_size            // const method_list_t *baseMethods;
140                 + ptr_size            // const protocol_list_t *baseProtocols;
141                 + ptr_size            // const ivar_list_t *ivars;
142                 + ptr_size            // const uint8_t *weakIvarLayout;
143                 + ptr_size;           // const property_list_t *baseProperties;
144 
145   DataBufferHeap buffer(size, '\0');
146   Status error;
147 
148   process->ReadMemory(addr, buffer.GetBytes(), size, error);
149   if (error.Fail()) {
150     return false;
151   }
152 
153   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
154                           process->GetAddressByteSize());
155 
156   lldb::offset_t cursor = 0;
157 
158   m_flags = extractor.GetU32_unchecked(&cursor);
159   m_instanceStart = extractor.GetU32_unchecked(&cursor);
160   m_instanceSize = extractor.GetU32_unchecked(&cursor);
161   if (ptr_size == 8)
162     m_reserved = extractor.GetU32_unchecked(&cursor);
163   else
164     m_reserved = 0;
165   m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
166   m_name_ptr = extractor.GetAddress_unchecked(&cursor);
167   m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor);
168   m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor);
169   m_ivars_ptr = extractor.GetAddress_unchecked(&cursor);
170   m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
171   m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor);
172 
173   DataBufferHeap name_buf(1024, '\0');
174 
175   process->ReadCStringFromMemory(m_name_ptr, (char *)name_buf.GetBytes(),
176                                  name_buf.GetByteSize(), error);
177 
178   if (error.Fail()) {
179     return false;
180   }
181 
182   m_name.assign((char *)name_buf.GetBytes());
183 
184   return true;
185 }
186 
187 bool ClassDescriptorV2::Read_class_row(
188     Process *process, const objc_class_t &objc_class,
189     std::unique_ptr<class_ro_t> &class_ro,
190     std::unique_ptr<class_rw_t> &class_rw) const {
191   class_ro.reset();
192   class_rw.reset();
193 
194   Status error;
195   uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(
196       objc_class.m_data_ptr, sizeof(uint32_t), 0, error);
197   if (!error.Success())
198     return false;
199 
200   if (class_row_t_flags & RW_REALIZED) {
201     class_rw.reset(new class_rw_t);
202 
203     if (!class_rw->Read(process, objc_class.m_data_ptr)) {
204       class_rw.reset();
205       return false;
206     }
207 
208     class_ro.reset(new class_ro_t);
209 
210     if (!class_ro->Read(process, class_rw->m_ro_ptr)) {
211       class_rw.reset();
212       class_ro.reset();
213       return false;
214     }
215   } else {
216     class_ro.reset(new class_ro_t);
217 
218     if (!class_ro->Read(process, objc_class.m_data_ptr)) {
219       class_ro.reset();
220       return false;
221     }
222   }
223 
224   return true;
225 }
226 
227 bool ClassDescriptorV2::method_list_t::Read(Process *process,
228                                             lldb::addr_t addr) {
229   size_t size = sizeof(uint32_t)    // uint32_t entsize_NEVER_USE;
230                 + sizeof(uint32_t); // uint32_t count;
231 
232   DataBufferHeap buffer(size, '\0');
233   Status error;
234 
235   process->ReadMemory(addr, buffer.GetBytes(), size, error);
236   if (error.Fail()) {
237     return false;
238   }
239 
240   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
241                           process->GetAddressByteSize());
242 
243   lldb::offset_t cursor = 0;
244 
245   m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3;
246   m_count = extractor.GetU32_unchecked(&cursor);
247   m_first_ptr = addr + cursor;
248 
249   return true;
250 }
251 
252 bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr) {
253   size_t size = GetSize(process);
254 
255   DataBufferHeap buffer(size, '\0');
256   Status error;
257 
258   process->ReadMemory(addr, buffer.GetBytes(), size, error);
259   if (error.Fail()) {
260     return false;
261   }
262 
263   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
264                           process->GetAddressByteSize());
265 
266   lldb::offset_t cursor = 0;
267 
268   m_name_ptr = extractor.GetAddress_unchecked(&cursor);
269   m_types_ptr = extractor.GetAddress_unchecked(&cursor);
270   m_imp_ptr = extractor.GetAddress_unchecked(&cursor);
271 
272   process->ReadCStringFromMemory(m_name_ptr, m_name, error);
273   if (error.Fail()) {
274     return false;
275   }
276 
277   process->ReadCStringFromMemory(m_types_ptr, m_types, error);
278   return !error.Fail();
279 }
280 
281 bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) {
282   size_t size = sizeof(uint32_t)    // uint32_t entsize;
283                 + sizeof(uint32_t); // uint32_t count;
284 
285   DataBufferHeap buffer(size, '\0');
286   Status error;
287 
288   process->ReadMemory(addr, buffer.GetBytes(), size, error);
289   if (error.Fail()) {
290     return false;
291   }
292 
293   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
294                           process->GetAddressByteSize());
295 
296   lldb::offset_t cursor = 0;
297 
298   m_entsize = extractor.GetU32_unchecked(&cursor);
299   m_count = extractor.GetU32_unchecked(&cursor);
300   m_first_ptr = addr + cursor;
301 
302   return true;
303 }
304 
305 bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
306   size_t size = GetSize(process);
307 
308   DataBufferHeap buffer(size, '\0');
309   Status error;
310 
311   process->ReadMemory(addr, buffer.GetBytes(), size, error);
312   if (error.Fail()) {
313     return false;
314   }
315 
316   DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(),
317                           process->GetAddressByteSize());
318 
319   lldb::offset_t cursor = 0;
320 
321   m_offset_ptr = extractor.GetAddress_unchecked(&cursor);
322   m_name_ptr = extractor.GetAddress_unchecked(&cursor);
323   m_type_ptr = extractor.GetAddress_unchecked(&cursor);
324   m_alignment = extractor.GetU32_unchecked(&cursor);
325   m_size = extractor.GetU32_unchecked(&cursor);
326 
327   process->ReadCStringFromMemory(m_name_ptr, m_name, error);
328   if (error.Fail()) {
329     return false;
330   }
331 
332   process->ReadCStringFromMemory(m_type_ptr, m_type, error);
333   return !error.Fail();
334 }
335 
336 bool ClassDescriptorV2::Describe(
337     std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
338     std::function<bool(const char *, const char *)> const &instance_method_func,
339     std::function<bool(const char *, const char *)> const &class_method_func,
340     std::function<bool(const char *, const char *, lldb::addr_t,
341                        uint64_t)> const &ivar_func) const {
342   lldb_private::Process *process = m_runtime.GetProcess();
343 
344   std::unique_ptr<objc_class_t> objc_class;
345   std::unique_ptr<class_ro_t> class_ro;
346   std::unique_ptr<class_rw_t> class_rw;
347 
348   if (!Read_objc_class(process, objc_class))
349     return false;
350   if (!Read_class_row(process, *objc_class, class_ro, class_rw))
351     return false;
352 
353   static ConstString NSObject_name("NSObject");
354 
355   if (m_name != NSObject_name && superclass_func)
356     superclass_func(objc_class->m_superclass);
357 
358   if (instance_method_func) {
359     std::unique_ptr<method_list_t> base_method_list;
360 
361     base_method_list.reset(new method_list_t);
362     if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
363       return false;
364 
365     if (base_method_list->m_entsize != method_t::GetSize(process))
366       return false;
367 
368     std::unique_ptr<method_t> method;
369     method.reset(new method_t);
370 
371     for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) {
372       method->Read(process, base_method_list->m_first_ptr +
373                                 (i * base_method_list->m_entsize));
374 
375       if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
376         break;
377     }
378   }
379 
380   if (class_method_func) {
381     AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass());
382 
383     // We don't care about the metaclass's superclass, or its class methods.
384     // Its instance methods are our class methods.
385 
386     if (metaclass) {
387       metaclass->Describe(
388           std::function<void(ObjCLanguageRuntime::ObjCISA)>(nullptr),
389           class_method_func,
390           std::function<bool(const char *, const char *)>(nullptr),
391           std::function<bool(const char *, const char *, lldb::addr_t,
392                              uint64_t)>(nullptr));
393     }
394   }
395 
396   if (ivar_func) {
397     if (class_ro->m_ivars_ptr != 0) {
398       ivar_list_t ivar_list;
399       if (!ivar_list.Read(process, class_ro->m_ivars_ptr))
400         return false;
401 
402       if (ivar_list.m_entsize != ivar_t::GetSize(process))
403         return false;
404 
405       ivar_t ivar;
406 
407       for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) {
408         ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize));
409 
410         if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(),
411                       ivar.m_offset_ptr, ivar.m_size))
412           break;
413       }
414     }
415   }
416 
417   return true;
418 }
419 
420 ConstString ClassDescriptorV2::GetClassName() {
421   if (!m_name) {
422     lldb_private::Process *process = m_runtime.GetProcess();
423 
424     if (process) {
425       std::unique_ptr<objc_class_t> objc_class;
426       std::unique_ptr<class_ro_t> class_ro;
427       std::unique_ptr<class_rw_t> class_rw;
428 
429       if (!Read_objc_class(process, objc_class))
430         return m_name;
431       if (!Read_class_row(process, *objc_class, class_ro, class_rw))
432         return m_name;
433 
434       m_name = ConstString(class_ro->m_name.c_str());
435     }
436   }
437   return m_name;
438 }
439 
440 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetSuperclass() {
441   lldb_private::Process *process = m_runtime.GetProcess();
442 
443   if (!process)
444     return ObjCLanguageRuntime::ClassDescriptorSP();
445 
446   std::unique_ptr<objc_class_t> objc_class;
447 
448   if (!Read_objc_class(process, objc_class))
449     return ObjCLanguageRuntime::ClassDescriptorSP();
450 
451   return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(
452       objc_class->m_superclass);
453 }
454 
455 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetMetaclass() const {
456   lldb_private::Process *process = m_runtime.GetProcess();
457 
458   if (!process)
459     return ObjCLanguageRuntime::ClassDescriptorSP();
460 
461   std::unique_ptr<objc_class_t> objc_class;
462 
463   if (!Read_objc_class(process, objc_class))
464     return ObjCLanguageRuntime::ClassDescriptorSP();
465 
466   lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa);
467 
468   return ObjCLanguageRuntime::ClassDescriptorSP(
469       new ClassDescriptorV2(m_runtime, candidate_isa, nullptr));
470 }
471 
472 uint64_t ClassDescriptorV2::GetInstanceSize() {
473   lldb_private::Process *process = m_runtime.GetProcess();
474 
475   if (process) {
476     std::unique_ptr<objc_class_t> objc_class;
477     std::unique_ptr<class_ro_t> class_ro;
478     std::unique_ptr<class_rw_t> class_rw;
479 
480     if (!Read_objc_class(process, objc_class))
481       return 0;
482     if (!Read_class_row(process, *objc_class, class_ro, class_rw))
483       return 0;
484 
485     return class_ro->m_instanceSize;
486   }
487 
488   return 0;
489 }
490 
491 ClassDescriptorV2::iVarsStorage::iVarsStorage()
492     : m_filled(false), m_ivars(), m_mutex() {}
493 
494 size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); }
495 
496 ClassDescriptorV2::iVarDescriptor &ClassDescriptorV2::iVarsStorage::
497 operator[](size_t idx) {
498   return m_ivars[idx];
499 }
500 
501 void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime,
502                                            ClassDescriptorV2 &descriptor) {
503   if (m_filled)
504     return;
505   std::lock_guard<std::recursive_mutex> guard(m_mutex);
506   Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
507   LLDB_LOGV(log, "class_name = {0}", descriptor.GetClassName());
508   m_filled = true;
509   ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp(
510       runtime.GetEncodingToType());
511   Process *process(runtime.GetProcess());
512   if (!encoding_to_type_sp)
513     return;
514   descriptor.Describe(nullptr, nullptr, nullptr, [this, process,
515                                                   encoding_to_type_sp,
516                                                   log](const char *name,
517                                                        const char *type,
518                                                        lldb::addr_t offset_ptr,
519                                                        uint64_t size) -> bool {
520     const bool for_expression = false;
521     const bool stop_loop = false;
522     LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}",
523               name, type, offset_ptr, size);
524     CompilerType ivar_type =
525         encoding_to_type_sp->RealizeType(type, for_expression);
526     if (ivar_type) {
527       LLDB_LOGV(log,
528                 "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = "
529                 "{3}, type_size = {4}",
530                 name, type, offset_ptr, size,
531                 ivar_type.GetByteSize(nullptr).getValueOr(0));
532       Scalar offset_scalar;
533       Status error;
534       const int offset_ptr_size = 4;
535       const bool is_signed = false;
536       size_t read = process->ReadScalarIntegerFromMemory(
537           offset_ptr, offset_ptr_size, is_signed, offset_scalar, error);
538       if (error.Success() && 4 == read) {
539         LLDB_LOGV(log, "offset_ptr = {0:x} --> {1}", offset_ptr,
540                   offset_scalar.SInt());
541         m_ivars.push_back(
542             {ConstString(name), ivar_type, size, offset_scalar.SInt()});
543       } else
544         LLDB_LOGV(log, "offset_ptr = {0:x} --> read fail, read = %{1}",
545                   offset_ptr, read);
546     }
547     return stop_loop;
548   });
549 }
550 
551 void ClassDescriptorV2::GetIVarInformation() {
552   m_ivars_storage.fill(m_runtime, *this);
553 }
554