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