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