1 //===-- AppleObjCRuntimeV2.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 "lldb/lldb-python.h"
11 
12 #include <string>
13 #include <vector>
14 #include <stdint.h>
15 
16 #include "lldb/lldb-enumerations.h"
17 #include "lldb/Core/ClangForward.h"
18 #include "lldb/Symbol/ClangASTType.h"
19 
20 #include "lldb/Core/ClangForward.h"
21 #include "lldb/Core/ConstString.h"
22 #include "lldb/Core/Error.h"
23 #include "lldb/Core/Log.h"
24 #include "lldb/Core/Module.h"
25 #include "lldb/Core/PluginManager.h"
26 #include "lldb/Core/Scalar.h"
27 #include "lldb/Core/Section.h"
28 #include "lldb/Core/StreamString.h"
29 #include "lldb/Core/Timer.h"
30 #include "lldb/Core/ValueObjectVariable.h"
31 #include "lldb/Expression/ClangFunction.h"
32 #include "lldb/Expression/ClangUtilityFunction.h"
33 #include "lldb/Symbol/ClangASTContext.h"
34 #include "lldb/Symbol/ObjectFile.h"
35 #include "lldb/Symbol/Symbol.h"
36 #include "lldb/Symbol/TypeList.h"
37 #include "lldb/Symbol/VariableList.h"
38 #include "lldb/Target/ExecutionContext.h"
39 #include "lldb/Target/Process.h"
40 #include "lldb/Target/RegisterContext.h"
41 #include "lldb/Target/Target.h"
42 #include "lldb/Target/Thread.h"
43 
44 #include "AppleObjCRuntimeV2.h"
45 #include "AppleObjCTypeVendor.h"
46 #include "AppleObjCTrampolineHandler.h"
47 
48 #include <vector>
49 
50 using namespace lldb;
51 using namespace lldb_private;
52 
53 // 2 second timeout when running utility functions
54 #define UTILITY_FUNCTION_TIMEOUT_USEC 2*1000*1000
55 
56 static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info";
57 // Testing using the new C++11 raw string literals. If this breaks GCC then we will
58 // need to revert to the code above...
59 static const char *g_get_dynamic_class_info_body = R"(
60 
61 extern "C"
62 {
63     size_t strlen(const char *);
64     char *strncpy (char * s1, const char * s2, size_t n);
65     int printf(const char * format, ...);
66 }
67 //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
68 #ifdef ENABLE_DEBUG_PRINTF
69 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
70 #else
71 #define DEBUG_PRINTF(fmt, ...)
72 #endif
73 
74 typedef struct _NXMapTable {
75     void *prototype;
76     unsigned num_classes;
77     unsigned num_buckets_minus_one;
78     void *buckets;
79 } NXMapTable;
80 
81 #define NX_MAPNOTAKEY   ((void *)(-1))
82 
83 typedef struct BucketInfo
84 {
85     const char *name_ptr;
86     Class isa;
87 } BucketInfo;
88 
89 struct ClassInfo
90 {
91     Class isa;
92     uint32_t hash;
93 } __attribute__((__packed__));
94 
95 uint32_t
96 __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
97                                              void *class_infos_ptr,
98                                              uint32_t class_infos_byte_size)
99 {
100     DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
101     DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
102     DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
103     const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
104     if (grc)
105     {
106         const unsigned num_classes = grc->num_classes;
107         if (class_infos_ptr)
108         {
109             const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
110             ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
111             BucketInfo *buckets = (BucketInfo *)grc->buckets;
112 
113             uint32_t idx = 0;
114             for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i)
115             {
116                 if (buckets[i].name_ptr != NX_MAPNOTAKEY)
117                 {
118                     if (idx < max_class_infos)
119                     {
120                         const char *s = buckets[i].name_ptr;
121                         uint32_t h = 5381;
122                         for (unsigned char c = *s; c; c = *++s)
123                             h = ((h << 5) + h) + c;
124                         class_infos[idx].hash = h;
125                         class_infos[idx].isa = buckets[i].isa;
126                     }
127                     ++idx;
128                 }
129             }
130             if (idx < max_class_infos)
131             {
132                 class_infos[idx].isa = NULL;
133                 class_infos[idx].hash = 0;
134             }
135         }
136         return num_classes;
137     }
138     return 0;
139 }
140 
141 )";
142 
143 static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info";
144 // Testing using the new C++11 raw string literals. If this breaks GCC then we will
145 // need to revert to the code above...
146 static const char *g_get_shared_cache_class_info_body = R"(
147 
148 extern "C"
149 {
150     const char *class_getName(void *objc_class);
151     size_t strlen(const char *);
152     char *strncpy (char * s1, const char * s2, size_t n);
153     int printf(const char * format, ...);
154 }
155 
156 //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN
157 #ifdef ENABLE_DEBUG_PRINTF
158 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
159 #else
160 #define DEBUG_PRINTF(fmt, ...)
161 #endif
162 
163 
164 struct objc_classheader_t {
165     int32_t clsOffset;
166     int32_t hiOffset;
167 };
168 
169 struct objc_clsopt_t {
170     uint32_t capacity;
171     uint32_t occupied;
172     uint32_t shift;
173     uint32_t mask;
174     uint32_t zero;
175     uint32_t unused;
176     uint64_t salt;
177     uint32_t scramble[256];
178     uint8_t tab[0]; // tab[mask+1]
179     //  uint8_t checkbytes[capacity];
180     //  int32_t offset[capacity];
181     //  objc_classheader_t clsOffsets[capacity];
182     //  uint32_t duplicateCount;
183     //  objc_classheader_t duplicateOffsets[duplicateCount];
184 };
185 
186 struct objc_opt_t {
187     uint32_t version;
188     int32_t selopt_offset;
189     int32_t headeropt_offset;
190     int32_t clsopt_offset;
191 };
192 
193 struct ClassInfo
194 {
195     Class isa;
196     uint32_t hash;
197 }  __attribute__((__packed__));
198 
199 uint32_t
200 __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
201                                                   void *class_infos_ptr,
202                                                   uint32_t class_infos_byte_size)
203 {
204     uint32_t idx = 0;
205     DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
206     DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
207     DEBUG_PRINTF ("class_infos_byte_size = %u (%zu class infos)\n", class_infos_byte_size, (size_t)(class_infos_byte_size/sizeof(ClassInfo)));
208     if (objc_opt_ro_ptr)
209     {
210         const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
211         DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
212         DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
213         DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
214         DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
215         if (objc_opt->version == 12)
216         {
217             const objc_clsopt_t* clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
218             const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
219             ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
220             int32_t zeroOffset = 16;
221             const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
222             const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
223             const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
224             DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
225             DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
226             DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
227             for (uint32_t i=0; i<clsopt->capacity; ++i)
228             {
229                 const int32_t clsOffset = classOffsets[i].clsOffset;
230                 if (clsOffset & 1)
231                     continue; // duplicate
232                 else if (clsOffset == zeroOffset)
233                     continue; // zero offset
234 
235                 if (class_infos && idx < max_class_infos)
236                 {
237                     class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
238                     const char *name = class_getName (class_infos[idx].isa);
239                     DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
240                     // Hash the class name so we don't have to read it
241                     const char *s = name;
242                     uint32_t h = 5381;
243                     for (unsigned char c = *s; c; c = *++s)
244                         h = ((h << 5) + h) + c;
245                     class_infos[idx].hash = h;
246                 }
247                 ++idx;
248             }
249 
250             const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
251             const uint32_t duplicate_count = *duplicate_count_ptr;
252             const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
253             DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
254             DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
255             for (uint32_t i=0; i<duplicate_count; ++i)
256             {
257                 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
258                 if (clsOffset & 1)
259                     continue; // duplicate
260                 else if (clsOffset == zeroOffset)
261                     continue; // zero offset
262 
263                 if (class_infos && idx < max_class_infos)
264                 {
265                     class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
266                     const char *name = class_getName (class_infos[idx].isa);
267                     DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
268                     // Hash the class name so we don't have to read it
269                     const char *s = name;
270                     uint32_t h = 5381;
271                     for (unsigned char c = *s; c; c = *++s)
272                         h = ((h << 5) + h) + c;
273                     class_infos[idx].hash = h;
274                 }
275                 ++idx;
276             }
277         }
278         DEBUG_PRINTF ("%u class_infos\n", idx);
279         DEBUG_PRINTF ("done\n");
280     }
281     return idx;
282 }
283 
284 
285 )";
286 
287 static uint64_t
ExtractRuntimeGlobalSymbol(Process * process,ConstString name,const ModuleSP & module_sp,Error & error,bool read_value=true,uint8_t byte_size=0,uint64_t default_value=LLDB_INVALID_ADDRESS,SymbolType sym_type=lldb::eSymbolTypeData)288 ExtractRuntimeGlobalSymbol (Process* process,
289                             ConstString name,
290                             const ModuleSP &module_sp,
291                             Error& error,
292                             bool read_value = true,
293                             uint8_t byte_size = 0,
294                             uint64_t default_value = LLDB_INVALID_ADDRESS,
295                             SymbolType sym_type = lldb::eSymbolTypeData)
296 {
297     if (!process)
298     {
299         error.SetErrorString("no process");
300         return default_value;
301     }
302     if (!module_sp)
303     {
304         error.SetErrorString("no module");
305         return default_value;
306     }
307     if (!byte_size)
308         byte_size = process->GetAddressByteSize();
309     const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
310     if (symbol)
311     {
312         lldb::addr_t symbol_load_addr = symbol->GetAddress().GetLoadAddress(&process->GetTarget());
313         if (symbol_load_addr != LLDB_INVALID_ADDRESS)
314         {
315             if (read_value)
316                 return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, default_value, error);
317             else
318                 return symbol_load_addr;
319         }
320         else
321         {
322             error.SetErrorString("symbol address invalid");
323             return default_value;
324         }
325     }
326     else
327     {
328         error.SetErrorString("no symbol");
329         return default_value;
330     }
331 
332 }
333 
AppleObjCRuntimeV2(Process * process,const ModuleSP & objc_module_sp)334 AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process,
335                                         const ModuleSP &objc_module_sp) :
336     AppleObjCRuntime (process),
337     m_get_class_info_function(),
338     m_get_class_info_code(),
339     m_get_class_info_args (LLDB_INVALID_ADDRESS),
340     m_get_class_info_args_mutex (Mutex::eMutexTypeNormal),
341     m_get_shared_cache_class_info_function(),
342     m_get_shared_cache_class_info_code(),
343     m_get_shared_cache_class_info_args (LLDB_INVALID_ADDRESS),
344     m_get_shared_cache_class_info_args_mutex (Mutex::eMutexTypeNormal),
345     m_type_vendor_ap (),
346     m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS),
347     m_hash_signature (),
348     m_has_object_getClass (false),
349     m_loaded_objc_opt (false),
350     m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this,objc_module_sp)),
351     m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp))
352 {
353     static const ConstString g_gdb_object_getClass("gdb_object_getClass");
354     m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
355 }
356 
~AppleObjCRuntimeV2()357 AppleObjCRuntimeV2::~AppleObjCRuntimeV2()
358 {
359 }
360 
361 bool
GetDynamicTypeAndAddress(ValueObject & in_value,DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address)362 AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
363                                               DynamicValueType use_dynamic,
364                                               TypeAndOrName &class_type_or_name,
365                                               Address &address)
366 {
367     // The Runtime is attached to a particular process, you shouldn't pass in a value from another process.
368     assert (in_value.GetProcessSP().get() == m_process);
369     assert (m_process != NULL);
370 
371     class_type_or_name.Clear();
372 
373     // Make sure we can have a dynamic value before starting...
374     if (CouldHaveDynamicValue (in_value))
375     {
376         // First job, pull out the address at 0 offset from the object  That will be the ISA pointer.
377         ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor (in_value));
378         if (objc_class_sp)
379         {
380             const addr_t object_ptr = in_value.GetPointerValue();
381             address.SetRawAddress(object_ptr);
382 
383             ConstString class_name (objc_class_sp->GetClassName());
384             class_type_or_name.SetName(class_name);
385             TypeSP type_sp (objc_class_sp->GetType());
386             if (type_sp)
387                 class_type_or_name.SetTypeSP (type_sp);
388             else
389             {
390                 type_sp = LookupInCompleteClassCache (class_name);
391                 if (type_sp)
392                 {
393                     objc_class_sp->SetType (type_sp);
394                     class_type_or_name.SetTypeSP (type_sp);
395                 }
396             }
397         }
398     }
399     return class_type_or_name.IsEmpty() == false;
400 }
401 
402 //------------------------------------------------------------------
403 // Static Functions
404 //------------------------------------------------------------------
405 LanguageRuntime *
CreateInstance(Process * process,LanguageType language)406 AppleObjCRuntimeV2::CreateInstance (Process *process, LanguageType language)
407 {
408     // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make
409     // sure we aren't using the V1 runtime.
410     if (language == eLanguageTypeObjC)
411     {
412         ModuleSP objc_module_sp;
413 
414         if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == eAppleObjC_V2)
415             return new AppleObjCRuntimeV2 (process, objc_module_sp);
416         else
417             return NULL;
418     }
419     else
420         return NULL;
421 }
422 
423 void
Initialize()424 AppleObjCRuntimeV2::Initialize()
425 {
426     PluginManager::RegisterPlugin (GetPluginNameStatic(),
427                                    "Apple Objective C Language Runtime - Version 2",
428                                    CreateInstance);
429 }
430 
431 void
Terminate()432 AppleObjCRuntimeV2::Terminate()
433 {
434     PluginManager::UnregisterPlugin (CreateInstance);
435 }
436 
437 lldb_private::ConstString
GetPluginNameStatic()438 AppleObjCRuntimeV2::GetPluginNameStatic()
439 {
440     static ConstString g_name("apple-objc-v2");
441     return g_name;
442 }
443 
444 
445 //------------------------------------------------------------------
446 // PluginInterface protocol
447 //------------------------------------------------------------------
448 lldb_private::ConstString
GetPluginName()449 AppleObjCRuntimeV2::GetPluginName()
450 {
451     return GetPluginNameStatic();
452 }
453 
454 uint32_t
GetPluginVersion()455 AppleObjCRuntimeV2::GetPluginVersion()
456 {
457     return 1;
458 }
459 
460 BreakpointResolverSP
CreateExceptionResolver(Breakpoint * bkpt,bool catch_bp,bool throw_bp)461 AppleObjCRuntimeV2::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
462 {
463     BreakpointResolverSP resolver_sp;
464 
465     if (throw_bp)
466         resolver_sp.reset (new BreakpointResolverName (bkpt,
467                                                        "objc_exception_throw",
468                                                        eFunctionNameTypeBase,
469                                                        Breakpoint::Exact,
470                                                        eLazyBoolNo));
471     // FIXME: We don't do catch breakpoints for ObjC yet.
472     // Should there be some way for the runtime to specify what it can do in this regard?
473     return resolver_sp;
474 }
475 
476 ClangUtilityFunction *
CreateObjectChecker(const char * name)477 AppleObjCRuntimeV2::CreateObjectChecker(const char *name)
478 {
479     char check_function_code[2048];
480 
481     int len = 0;
482     if (m_has_object_getClass)
483     {
484         len = ::snprintf (check_function_code,
485                           sizeof(check_function_code),
486                           "extern \"C\" void *gdb_object_getClass(void *);                                          \n"
487                           "extern \"C\"  int printf(const char *format, ...);                                       \n"
488                           "extern \"C\" void                                                                        \n"
489                           "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)                                    \n"
490                           "{                                                                                        \n"
491                           "   if ($__lldb_arg_obj == (void *)0)                                                     \n"
492                           "       return; // nil is ok                                                              \n"
493                           "   if (!gdb_object_getClass($__lldb_arg_obj))                                            \n"
494                           "       *((volatile int *)0) = 'ocgc';                                                    \n"
495                           "   else if ($__lldb_arg_selector != (void *)0)                                           \n"
496                           "   {                                                                                     \n"
497                           "        signed char responds = (signed char) [(id) $__lldb_arg_obj                       \n"
498                           "                                                respondsToSelector:                      \n"
499                           "                                       (struct objc_selector *) $__lldb_arg_selector];   \n"
500                           "       if (responds == (signed char) 0)                                                  \n"
501                           "           *((volatile int *)0) = 'ocgc';                                                \n"
502                           "   }                                                                                     \n"
503                           "}                                                                                        \n",
504                           name);
505     }
506     else
507     {
508         len = ::snprintf (check_function_code,
509                           sizeof(check_function_code),
510                           "extern \"C\" void *gdb_class_getClass(void *);                                           \n"
511                           "extern \"C\"  int printf(const char *format, ...);                                       \n"
512                           "extern \"C\"  void                                                                       \n"
513                           "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)                                    \n"
514                           "{                                                                                        \n"
515                           "   if ($__lldb_arg_obj == (void *)0)                                                     \n"
516                           "       return; // nil is ok                                                              \n"
517                           "    void **$isa_ptr = (void **)$__lldb_arg_obj;                                          \n"
518                           "    if (*$isa_ptr == (void *)0 || !gdb_class_getClass(*$isa_ptr))                        \n"
519                           "       *((volatile int *)0) = 'ocgc';                                                    \n"
520                           "   else if ($__lldb_arg_selector != (void *)0)                                           \n"
521                           "   {                                                                                     \n"
522                           "        signed char responds = (signed char) [(id) $__lldb_arg_obj                       \n"
523                           "                                                respondsToSelector:                      \n"
524                           "                                        (struct objc_selector *) $__lldb_arg_selector];  \n"
525                           "       if (responds == (signed char) 0)                                                  \n"
526                           "           *((volatile int *)0) = 'ocgc';                                                \n"
527                           "   }                                                                                     \n"
528                           "}                                                                                        \n",
529                           name);
530     }
531 
532     assert (len < (int)sizeof(check_function_code));
533 
534     return new ClangUtilityFunction(check_function_code, name);
535 }
536 
537 size_t
GetByteOffsetForIvar(ClangASTType & parent_ast_type,const char * ivar_name)538 AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const char *ivar_name)
539 {
540     const char *class_name = parent_ast_type.GetConstTypeName().AsCString();
541 
542     if (!class_name || *class_name == '\0' || !ivar_name || *ivar_name == '\0')
543         return LLDB_INVALID_IVAR_OFFSET;
544 
545     std::string buffer("OBJC_IVAR_$_");
546     buffer.append (class_name);
547     buffer.push_back ('.');
548     buffer.append (ivar_name);
549     ConstString ivar_const_str (buffer.c_str());
550 
551     SymbolContextList sc_list;
552     Target &target = m_process->GetTarget();
553 
554     target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list);
555 
556     SymbolContext ivar_offset_symbol;
557     if (sc_list.GetSize() != 1
558         || !sc_list.GetContextAtIndex(0, ivar_offset_symbol)
559         || ivar_offset_symbol.symbol == NULL)
560         return LLDB_INVALID_IVAR_OFFSET;
561 
562     addr_t ivar_offset_address = ivar_offset_symbol.symbol->GetAddress().GetLoadAddress (&target);
563 
564     Error error;
565 
566     uint32_t ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address,
567                                                                      4,
568                                                                      LLDB_INVALID_IVAR_OFFSET,
569                                                                      error);
570     return ivar_offset;
571 }
572 
573 
574 // tagged pointers are special not-a-real-pointer values that contain both type and value information
575 // this routine attempts to check with as little computational effort as possible whether something
576 // could possibly be a tagged pointer - false positives are possible but false negatives shouldn't
577 bool
IsTaggedPointer(addr_t ptr)578 AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr)
579 {
580     if (!m_tagged_pointer_vendor_ap)
581         return false;
582     return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr);
583 }
584 
585 class RemoteNXMapTable
586 {
587 public:
588 
RemoteNXMapTable()589     RemoteNXMapTable () :
590         m_count (0),
591         m_num_buckets_minus_one (0),
592         m_buckets_ptr (LLDB_INVALID_ADDRESS),
593         m_process (NULL),
594         m_end_iterator (*this, -1),
595         m_load_addr (LLDB_INVALID_ADDRESS),
596         m_map_pair_size (0),
597         m_invalid_key (0)
598     {
599     }
600 
601     void
Dump()602     Dump ()
603     {
604         printf ("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);
605         printf ("RemoteNXMapTable.m_count = %u\n", m_count);
606         printf ("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", m_num_buckets_minus_one);
607         printf ("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);
608     }
609 
610     bool
ParseHeader(Process * process,lldb::addr_t load_addr)611     ParseHeader (Process* process, lldb::addr_t load_addr)
612     {
613         m_process = process;
614         m_load_addr = load_addr;
615         m_map_pair_size = m_process->GetAddressByteSize() * 2;
616         m_invalid_key = m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
617         Error err;
618 
619         // This currently holds true for all platforms we support, but we might
620         // need to change this to use get the actualy byte size of "unsigned"
621         // from the target AST...
622         const uint32_t unsigned_byte_size = sizeof(uint32_t);
623         // Skip the prototype as we don't need it (const struct +NXMapTablePrototype *prototype)
624 
625         bool success = true;
626         if (load_addr == LLDB_INVALID_ADDRESS)
627             success = false;
628         else
629         {
630             lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();
631 
632             // unsigned count;
633             m_count = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err);
634             if (m_count)
635             {
636                 cursor += unsigned_byte_size;
637 
638                 // unsigned nbBucketsMinusOne;
639                 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err);
640                 cursor += unsigned_byte_size;
641 
642                 // void *buckets;
643                 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);
644 
645                 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;
646             }
647         }
648 
649         if (!success)
650         {
651             m_count = 0;
652             m_num_buckets_minus_one = 0;
653             m_buckets_ptr = LLDB_INVALID_ADDRESS;
654         }
655         return success;
656     }
657 
658     // const_iterator mimics NXMapState and its code comes from NXInitMapState and NXNextMapState.
659     typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;
660 
661     friend class const_iterator;
662     class const_iterator
663     {
664     public:
const_iterator(RemoteNXMapTable & parent,int index)665         const_iterator (RemoteNXMapTable &parent, int index) : m_parent(parent), m_index(index)
666         {
667             AdvanceToValidIndex();
668         }
669 
const_iterator(const const_iterator & rhs)670         const_iterator (const const_iterator &rhs) : m_parent(rhs.m_parent), m_index(rhs.m_index)
671         {
672             // AdvanceToValidIndex() has been called by rhs already.
673         }
674 
operator =(const const_iterator & rhs)675         const_iterator &operator=(const const_iterator &rhs)
676         {
677             // AdvanceToValidIndex() has been called by rhs already.
678             assert (&m_parent == &rhs.m_parent);
679             m_index = rhs.m_index;
680             return *this;
681         }
682 
operator ==(const const_iterator & rhs) const683         bool operator==(const const_iterator &rhs) const
684         {
685             if (&m_parent != &rhs.m_parent)
686                 return false;
687             if (m_index != rhs.m_index)
688                 return false;
689 
690             return true;
691         }
692 
operator !=(const const_iterator & rhs) const693         bool operator!=(const const_iterator &rhs) const
694         {
695             return !(operator==(rhs));
696         }
697 
operator ++()698         const_iterator &operator++()
699         {
700             AdvanceToValidIndex();
701             return *this;
702         }
703 
operator *() const704         const element operator*() const
705         {
706             if (m_index == -1)
707             {
708                 // TODO find a way to make this an error, but not an assert
709                 return element();
710             }
711 
712             lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
713             size_t map_pair_size = m_parent.m_map_pair_size;
714             lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
715 
716             Error err;
717 
718             lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
719             if (!err.Success())
720                 return element();
721             lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(pair_ptr + m_parent.m_process->GetAddressByteSize(), err);
722             if (!err.Success())
723                 return element();
724 
725             std::string key_string;
726 
727             m_parent.m_process->ReadCStringFromMemory(key, key_string, err);
728             if (!err.Success())
729                 return element();
730 
731             return element(ConstString(key_string.c_str()), (ObjCLanguageRuntime::ObjCISA)value);
732         }
733     private:
AdvanceToValidIndex()734         void AdvanceToValidIndex ()
735         {
736             if (m_index == -1)
737                 return;
738 
739             const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
740             const size_t map_pair_size = m_parent.m_map_pair_size;
741             const lldb::addr_t invalid_key = m_parent.m_invalid_key;
742             Error err;
743 
744             while (m_index--)
745             {
746                 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
747                 lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
748 
749                 if (!err.Success())
750                 {
751                     m_index = -1;
752                     return;
753                 }
754 
755                 if (key != invalid_key)
756                     return;
757             }
758         }
759         RemoteNXMapTable   &m_parent;
760         int                 m_index;
761     };
762 
begin()763     const_iterator begin ()
764     {
765         return const_iterator(*this, m_num_buckets_minus_one + 1);
766     }
767 
end()768     const_iterator end ()
769     {
770         return m_end_iterator;
771     }
772 
773     uint32_t
GetCount() const774     GetCount () const
775     {
776         return m_count;
777     }
778 
779     uint32_t
GetBucketCount() const780     GetBucketCount () const
781     {
782         return m_num_buckets_minus_one;
783     }
784 
785     lldb::addr_t
GetBucketDataPointer() const786     GetBucketDataPointer () const
787     {
788         return m_buckets_ptr;
789     }
790 
791     lldb::addr_t
GetTableLoadAddress() const792     GetTableLoadAddress() const
793     {
794         return m_load_addr;
795     }
796 
797 private:
798     // contents of _NXMapTable struct
799     uint32_t m_count;
800     uint32_t m_num_buckets_minus_one;
801     lldb::addr_t m_buckets_ptr;
802     lldb_private::Process *m_process;
803     const_iterator m_end_iterator;
804     lldb::addr_t m_load_addr;
805     size_t m_map_pair_size;
806     lldb::addr_t m_invalid_key;
807 };
808 
809 
810 
HashTableSignature()811 AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() :
812     m_count (0),
813     m_num_buckets (0),
814     m_buckets_ptr (0)
815 {
816 }
817 
818 void
UpdateSignature(const RemoteNXMapTable & hash_table)819 AppleObjCRuntimeV2::HashTableSignature::UpdateSignature (const RemoteNXMapTable &hash_table)
820 {
821     m_count = hash_table.GetCount();
822     m_num_buckets = hash_table.GetBucketCount();
823     m_buckets_ptr = hash_table.GetBucketDataPointer();
824 }
825 
826 bool
NeedsUpdate(Process * process,AppleObjCRuntimeV2 * runtime,RemoteNXMapTable & hash_table)827 AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate (Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table)
828 {
829     if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer ()))
830     {
831         return false; // Failed to parse the header, no need to update anything
832     }
833 
834     // Check with out current signature and return true if the count,
835     // number of buckets or the hash table address changes.
836     if (m_count == hash_table.GetCount() &&
837         m_num_buckets == hash_table.GetBucketCount() &&
838         m_buckets_ptr == hash_table.GetBucketDataPointer())
839     {
840         // Hash table hasn't changed
841         return false;
842     }
843     // Hash table data has changed, we need to update
844     return true;
845 }
846 
847 class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor
848 {
849 public:
850     friend class lldb_private::AppleObjCRuntimeV2;
851 
852 private:
853     // The constructor should only be invoked by the runtime as it builds its caches
854     // or populates them.  A ClassDescriptorV2 should only ever exist in a cache.
ClassDescriptorV2(AppleObjCRuntimeV2 & runtime,ObjCLanguageRuntime::ObjCISA isa,const char * name)855     ClassDescriptorV2 (AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name) :
856         m_runtime (runtime),
857         m_objc_class_ptr (isa),
858         m_name (name)
859     {
860     }
861 
862 public:
863     virtual ConstString
GetClassName()864     GetClassName ()
865     {
866         if (!m_name)
867         {
868             lldb_private::Process *process = m_runtime.GetProcess();
869 
870             if (process)
871             {
872                 std::unique_ptr<objc_class_t> objc_class;
873                 std::unique_ptr<class_ro_t> class_ro;
874                 std::unique_ptr<class_rw_t> class_rw;
875 
876                 if (!Read_objc_class(process, objc_class))
877                     return m_name;
878                 if (!Read_class_row(process, *objc_class, class_ro, class_rw))
879                     return m_name;
880 
881                 m_name = ConstString(class_ro->m_name.c_str());
882             }
883         }
884         return m_name;
885     }
886 
887     virtual ObjCLanguageRuntime::ClassDescriptorSP
GetSuperclass()888     GetSuperclass ()
889     {
890         lldb_private::Process *process = m_runtime.GetProcess();
891 
892         if (!process)
893             return ObjCLanguageRuntime::ClassDescriptorSP();
894 
895         std::unique_ptr<objc_class_t> objc_class;
896 
897         if (!Read_objc_class(process, objc_class))
898             return ObjCLanguageRuntime::ClassDescriptorSP();
899 
900         return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(objc_class->m_superclass);
901     }
902 
903     virtual bool
IsValid()904     IsValid ()
905     {
906         return true;    // any Objective-C v2 runtime class descriptor we vend is valid
907     }
908 
909     // a custom descriptor is used for tagged pointers
910     virtual bool
GetTaggedPointerInfo(uint64_t * info_bits=NULL,uint64_t * value_bits=NULL,uint64_t * payload=NULL)911     GetTaggedPointerInfo (uint64_t* info_bits = NULL,
912                           uint64_t* value_bits = NULL,
913                           uint64_t* payload = NULL)
914     {
915         return false;
916     }
917 
918     virtual uint64_t
GetInstanceSize()919     GetInstanceSize ()
920     {
921         lldb_private::Process *process = m_runtime.GetProcess();
922 
923         if (process)
924         {
925             std::unique_ptr<objc_class_t> objc_class;
926             std::unique_ptr<class_ro_t> class_ro;
927             std::unique_ptr<class_rw_t> class_rw;
928 
929             if (!Read_objc_class(process, objc_class))
930                 return 0;
931             if (!Read_class_row(process, *objc_class, class_ro, class_rw))
932                 return 0;
933 
934             return class_ro->m_instanceSize;
935         }
936 
937         return 0;
938     }
939 
940     virtual ObjCLanguageRuntime::ObjCISA
GetISA()941     GetISA ()
942     {
943         return m_objc_class_ptr;
944     }
945 
946     virtual bool
Describe(std::function<void (ObjCLanguageRuntime::ObjCISA)> const & superclass_func,std::function<bool (const char *,const char *)> const & instance_method_func,std::function<bool (const char *,const char *)> const & class_method_func,std::function<bool (const char *,const char *,lldb::addr_t,uint64_t)> const & ivar_func)947     Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
948               std::function <bool (const char *, const char *)> const &instance_method_func,
949               std::function <bool (const char *, const char *)> const &class_method_func,
950               std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func)
951     {
952         lldb_private::Process *process = m_runtime.GetProcess();
953 
954         std::unique_ptr<objc_class_t> objc_class;
955         std::unique_ptr<class_ro_t> class_ro;
956         std::unique_ptr<class_rw_t> class_rw;
957 
958         if (!Read_objc_class(process, objc_class))
959             return 0;
960         if (!Read_class_row(process, *objc_class, class_ro, class_rw))
961             return 0;
962 
963         static ConstString NSObject_name("NSObject");
964 
965         if (m_name != NSObject_name && superclass_func)
966             superclass_func(objc_class->m_superclass);
967 
968         if (instance_method_func)
969         {
970             std::unique_ptr<method_list_t> base_method_list;
971 
972             base_method_list.reset(new method_list_t);
973             if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr))
974                 return false;
975 
976             if (base_method_list->m_entsize != method_t::GetSize(process))
977                 return false;
978 
979             std::unique_ptr<method_t> method;
980             method.reset(new method_t);
981 
982             for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i)
983             {
984                 method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize));
985 
986                 if (instance_method_func(method->m_name.c_str(), method->m_types.c_str()))
987                     break;
988             }
989         }
990 
991         if (class_method_func)
992         {
993             ClassDescriptorV2 metaclass(m_runtime, objc_class->m_isa, NULL); // The metaclass is not in the cache
994 
995             // We don't care about the metaclass's superclass, or its class methods.  Its instance methods are
996             // our class methods.
997 
998             metaclass.Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> (nullptr),
999                                class_method_func,
1000                                std::function <bool (const char *, const char *)> (nullptr),
1001                                std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr));
1002         }
1003 
1004         if (ivar_func)
1005         {
1006             ivar_list_t ivar_list;
1007             if (!ivar_list.Read(process, class_ro->m_ivars_ptr))
1008                 return false;
1009 
1010             if (ivar_list.m_entsize != ivar_t::GetSize(process))
1011                 return false;
1012 
1013             ivar_t ivar;
1014 
1015             for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i)
1016             {
1017                 ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize));
1018 
1019                 if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), ivar.m_offset_ptr, ivar.m_size))
1020                     break;
1021             }
1022         }
1023 
1024         return true;
1025     }
1026 
1027     virtual
~ClassDescriptorV2()1028     ~ClassDescriptorV2 ()
1029     {
1030     }
1031 
1032 private:
1033     static const uint32_t RW_REALIZED = (1 << 31);
1034 
1035     struct objc_class_t {
1036         ObjCLanguageRuntime::ObjCISA    m_isa;              // The class's metaclass.
1037         ObjCLanguageRuntime::ObjCISA    m_superclass;
1038         lldb::addr_t                    m_cache_ptr;
1039         lldb::addr_t                    m_vtable_ptr;
1040         lldb::addr_t                    m_data_ptr;
1041         uint8_t                         m_flags;
1042 
objc_class_tClassDescriptorV2::objc_class_t1043         objc_class_t () :
1044             m_isa (0),
1045             m_superclass (0),
1046             m_cache_ptr (0),
1047             m_vtable_ptr (0),
1048             m_data_ptr (0),
1049             m_flags (0)
1050         {
1051         }
1052 
1053         void
ClearClassDescriptorV2::objc_class_t1054         Clear()
1055         {
1056             m_isa = 0;
1057             m_superclass = 0;
1058             m_cache_ptr = 0;
1059             m_vtable_ptr = 0;
1060             m_data_ptr = 0;
1061             m_flags = 0;
1062         }
1063 
ReadClassDescriptorV2::objc_class_t1064         bool Read(Process *process, lldb::addr_t addr)
1065         {
1066             size_t ptr_size = process->GetAddressByteSize();
1067 
1068             size_t objc_class_size = ptr_size   // uintptr_t isa;
1069             + ptr_size   // Class superclass;
1070             + ptr_size   // void *cache;
1071             + ptr_size   // IMP *vtable;
1072             + ptr_size;  // uintptr_t data_NEVER_USE;
1073 
1074             DataBufferHeap objc_class_buf (objc_class_size, '\0');
1075             Error error;
1076 
1077             process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error);
1078             if (error.Fail())
1079             {
1080                 return false;
1081             }
1082 
1083             DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process->GetByteOrder(), process->GetAddressByteSize());
1084 
1085             lldb::offset_t cursor = 0;
1086 
1087             m_isa           = extractor.GetAddress_unchecked(&cursor);   // uintptr_t isa;
1088             m_superclass    = extractor.GetAddress_unchecked(&cursor);   // Class superclass;
1089             m_cache_ptr     = extractor.GetAddress_unchecked(&cursor);   // void *cache;
1090             m_vtable_ptr    = extractor.GetAddress_unchecked(&cursor);   // IMP *vtable;
1091             lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor);   // uintptr_t data_NEVER_USE;
1092 
1093             m_flags         = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3);
1094             m_data_ptr      = data_NEVER_USE & ~(lldb::addr_t)3;
1095 
1096             return true;
1097         }
1098     };
1099 
1100     struct class_ro_t {
1101         uint32_t                        m_flags;
1102         uint32_t                        m_instanceStart;
1103         uint32_t                        m_instanceSize;
1104         uint32_t                        m_reserved;
1105 
1106         lldb::addr_t                    m_ivarLayout_ptr;
1107         lldb::addr_t                    m_name_ptr;
1108         lldb::addr_t                    m_baseMethods_ptr;
1109         lldb::addr_t                    m_baseProtocols_ptr;
1110         lldb::addr_t                    m_ivars_ptr;
1111 
1112         lldb::addr_t                    m_weakIvarLayout_ptr;
1113         lldb::addr_t                    m_baseProperties_ptr;
1114 
1115         std::string                     m_name;
1116 
ReadClassDescriptorV2::class_ro_t1117         bool Read(Process *process, lldb::addr_t addr)
1118         {
1119             size_t ptr_size = process->GetAddressByteSize();
1120 
1121             size_t size = sizeof(uint32_t)             // uint32_t flags;
1122             + sizeof(uint32_t)                         // uint32_t instanceStart;
1123             + sizeof(uint32_t)                         // uint32_t instanceSize;
1124             + (ptr_size == 8 ? sizeof(uint32_t) : 0)   // uint32_t reserved; // __LP64__ only
1125             + ptr_size                                 // const uint8_t *ivarLayout;
1126             + ptr_size                                 // const char *name;
1127             + ptr_size                                 // const method_list_t *baseMethods;
1128             + ptr_size                                 // const protocol_list_t *baseProtocols;
1129             + ptr_size                                 // const ivar_list_t *ivars;
1130             + ptr_size                                 // const uint8_t *weakIvarLayout;
1131             + ptr_size;                                // const property_list_t *baseProperties;
1132 
1133             DataBufferHeap buffer (size, '\0');
1134             Error error;
1135 
1136             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1137             if (error.Fail())
1138             {
1139                 return false;
1140             }
1141 
1142             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1143 
1144             lldb::offset_t cursor = 0;
1145 
1146             m_flags             = extractor.GetU32_unchecked(&cursor);
1147             m_instanceStart     = extractor.GetU32_unchecked(&cursor);
1148             m_instanceSize      = extractor.GetU32_unchecked(&cursor);
1149             if (ptr_size == 8)
1150                 m_reserved      = extractor.GetU32_unchecked(&cursor);
1151             else
1152                 m_reserved      = 0;
1153             m_ivarLayout_ptr     = extractor.GetAddress_unchecked(&cursor);
1154             m_name_ptr           = extractor.GetAddress_unchecked(&cursor);
1155             m_baseMethods_ptr    = extractor.GetAddress_unchecked(&cursor);
1156             m_baseProtocols_ptr  = extractor.GetAddress_unchecked(&cursor);
1157             m_ivars_ptr          = extractor.GetAddress_unchecked(&cursor);
1158             m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor);
1159             m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor);
1160 
1161             DataBufferHeap name_buf(1024, '\0');
1162 
1163             process->ReadCStringFromMemory(m_name_ptr, (char*)name_buf.GetBytes(), name_buf.GetByteSize(), error);
1164 
1165             if (error.Fail())
1166             {
1167                 return false;
1168             }
1169 
1170             m_name.assign((char*)name_buf.GetBytes());
1171 
1172             return true;
1173         }
1174     };
1175 
1176     struct class_rw_t {
1177         uint32_t                        m_flags;
1178         uint32_t                        m_version;
1179 
1180         lldb::addr_t                    m_ro_ptr;
1181         union {
1182             lldb::addr_t                m_method_list_ptr;
1183             lldb::addr_t                m_method_lists_ptr;
1184         };
1185         lldb::addr_t                    m_properties_ptr;
1186         lldb::addr_t                    m_protocols_ptr;
1187 
1188         ObjCLanguageRuntime::ObjCISA    m_firstSubclass;
1189         ObjCLanguageRuntime::ObjCISA    m_nextSiblingClass;
1190 
ReadClassDescriptorV2::class_rw_t1191         bool Read(Process *process, lldb::addr_t addr)
1192         {
1193             size_t ptr_size = process->GetAddressByteSize();
1194 
1195             size_t size = sizeof(uint32_t)  // uint32_t flags;
1196             + sizeof(uint32_t)  // uint32_t version;
1197             + ptr_size          // const class_ro_t *ro;
1198             + ptr_size          // union { method_list_t **method_lists; method_list_t *method_list; };
1199             + ptr_size          // struct chained_property_list *properties;
1200             + ptr_size          // const protocol_list_t **protocols;
1201             + ptr_size          // Class firstSubclass;
1202             + ptr_size;         // Class nextSiblingClass;
1203 
1204             DataBufferHeap buffer (size, '\0');
1205             Error error;
1206 
1207             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1208             if (error.Fail())
1209             {
1210                 return false;
1211             }
1212 
1213             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1214 
1215             lldb::offset_t cursor = 0;
1216 
1217             m_flags             = extractor.GetU32_unchecked(&cursor);
1218             m_version           = extractor.GetU32_unchecked(&cursor);
1219             m_ro_ptr            = extractor.GetAddress_unchecked(&cursor);
1220             m_method_list_ptr   = extractor.GetAddress_unchecked(&cursor);
1221             m_properties_ptr    = extractor.GetAddress_unchecked(&cursor);
1222             m_firstSubclass     = extractor.GetAddress_unchecked(&cursor);
1223             m_nextSiblingClass  = extractor.GetAddress_unchecked(&cursor);
1224 
1225             return true;
1226         }
1227     };
1228 
1229     struct method_list_t
1230     {
1231         uint32_t        m_entsize;
1232         uint32_t        m_count;
1233         lldb::addr_t    m_first_ptr;
1234 
ReadClassDescriptorV2::method_list_t1235         bool Read(Process *process, lldb::addr_t addr)
1236         {
1237             size_t size = sizeof(uint32_t)  // uint32_t entsize_NEVER_USE;
1238             + sizeof(uint32_t); // uint32_t count;
1239 
1240             DataBufferHeap buffer (size, '\0');
1241             Error error;
1242 
1243             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1244             if (error.Fail())
1245             {
1246                 return false;
1247             }
1248 
1249             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1250 
1251             lldb::offset_t cursor = 0;
1252 
1253             m_entsize   = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3;
1254             m_count     = extractor.GetU32_unchecked(&cursor);
1255             m_first_ptr  = addr + cursor;
1256 
1257             return true;
1258         }
1259     };
1260 
1261     struct method_t
1262     {
1263         lldb::addr_t    m_name_ptr;
1264         lldb::addr_t    m_types_ptr;
1265         lldb::addr_t    m_imp_ptr;
1266 
1267         std::string     m_name;
1268         std::string     m_types;
1269 
GetSizeClassDescriptorV2::method_t1270         static size_t GetSize(Process *process)
1271         {
1272             size_t ptr_size = process->GetAddressByteSize();
1273 
1274             return ptr_size     // SEL name;
1275             + ptr_size   // const char *types;
1276             + ptr_size;  // IMP imp;
1277         }
1278 
ReadClassDescriptorV2::method_t1279         bool Read(Process *process, lldb::addr_t addr)
1280         {
1281             size_t size = GetSize(process);
1282 
1283             DataBufferHeap buffer (size, '\0');
1284             Error error;
1285 
1286             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1287             if (error.Fail())
1288             {
1289                 return false;
1290             }
1291 
1292             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1293 
1294             lldb::offset_t cursor = 0;
1295 
1296             m_name_ptr   = extractor.GetAddress_unchecked(&cursor);
1297             m_types_ptr  = extractor.GetAddress_unchecked(&cursor);
1298             m_imp_ptr    = extractor.GetAddress_unchecked(&cursor);
1299 
1300             const size_t buffer_size = 1024;
1301             size_t count;
1302 
1303             DataBufferHeap string_buf(buffer_size, 0);
1304 
1305             count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
1306             m_name.assign((char*)string_buf.GetBytes(), count);
1307 
1308             count = process->ReadCStringFromMemory(m_types_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
1309             m_types.assign((char*)string_buf.GetBytes(), count);
1310 
1311             return true;
1312         }
1313     };
1314 
1315     struct ivar_list_t
1316     {
1317         uint32_t        m_entsize;
1318         uint32_t        m_count;
1319         lldb::addr_t    m_first_ptr;
1320 
ReadClassDescriptorV2::ivar_list_t1321         bool Read(Process *process, lldb::addr_t addr)
1322         {
1323             size_t size = sizeof(uint32_t)  // uint32_t entsize;
1324                         + sizeof(uint32_t); // uint32_t count;
1325 
1326             DataBufferHeap buffer (size, '\0');
1327             Error error;
1328 
1329             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1330             if (error.Fail())
1331             {
1332                 return false;
1333             }
1334 
1335             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1336 
1337             lldb::offset_t cursor = 0;
1338 
1339             m_entsize   = extractor.GetU32_unchecked(&cursor);
1340             m_count     = extractor.GetU32_unchecked(&cursor);
1341             m_first_ptr = addr + cursor;
1342 
1343             return true;
1344         }
1345     };
1346 
1347     struct ivar_t
1348     {
1349         lldb::addr_t    m_offset_ptr;
1350         lldb::addr_t    m_name_ptr;
1351         lldb::addr_t    m_type_ptr;
1352         uint32_t        m_alignment;
1353         uint32_t        m_size;
1354 
1355         std::string     m_name;
1356         std::string     m_type;
1357 
GetSizeClassDescriptorV2::ivar_t1358         static size_t GetSize(Process *process)
1359         {
1360             size_t ptr_size = process->GetAddressByteSize();
1361 
1362             return ptr_size             // uintptr_t *offset;
1363                  + ptr_size             // const char *name;
1364                  + ptr_size             // const char *type;
1365                  + sizeof(uint32_t)     // uint32_t alignment;
1366                  + sizeof(uint32_t);    // uint32_t size;
1367         }
1368 
ReadClassDescriptorV2::ivar_t1369         bool Read(Process *process, lldb::addr_t addr)
1370         {
1371             size_t size = GetSize(process);
1372 
1373             DataBufferHeap buffer (size, '\0');
1374             Error error;
1375 
1376             process->ReadMemory(addr, buffer.GetBytes(), size, error);
1377             if (error.Fail())
1378             {
1379                 return false;
1380             }
1381 
1382             DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize());
1383 
1384             lldb::offset_t cursor = 0;
1385 
1386             m_offset_ptr = extractor.GetAddress_unchecked(&cursor);
1387             m_name_ptr   = extractor.GetAddress_unchecked(&cursor);
1388             m_type_ptr   = extractor.GetAddress_unchecked(&cursor);
1389             m_alignment  = extractor.GetU32_unchecked(&cursor);
1390             m_size       = extractor.GetU32_unchecked(&cursor);
1391 
1392             const size_t buffer_size = 1024;
1393             size_t count;
1394 
1395             DataBufferHeap string_buf(buffer_size, 0);
1396 
1397             count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
1398             m_name.assign((char*)string_buf.GetBytes(), count);
1399 
1400             count = process->ReadCStringFromMemory(m_type_ptr, (char*)string_buf.GetBytes(), buffer_size, error);
1401             m_type.assign((char*)string_buf.GetBytes(), count);
1402 
1403             return true;
1404         }
1405     };
1406 
Read_objc_class(Process * process,std::unique_ptr<objc_class_t> & objc_class)1407     bool Read_objc_class (Process* process, std::unique_ptr<objc_class_t> &objc_class)
1408     {
1409         objc_class.reset(new objc_class_t);
1410 
1411         bool ret = objc_class->Read (process, m_objc_class_ptr);
1412 
1413         if (!ret)
1414             objc_class.reset();
1415 
1416         return ret;
1417     }
1418 
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)1419     bool 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)
1420     {
1421         class_ro.reset();
1422         class_rw.reset();
1423 
1424         Error error;
1425         uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(objc_class.m_data_ptr, sizeof(uint32_t), 0, error);
1426         if (!error.Success())
1427             return false;
1428 
1429         if (class_row_t_flags & RW_REALIZED)
1430         {
1431             class_rw.reset(new class_rw_t);
1432 
1433             if (!class_rw->Read(process, objc_class.m_data_ptr))
1434             {
1435                 class_rw.reset();
1436                 return false;
1437             }
1438 
1439             class_ro.reset(new class_ro_t);
1440 
1441             if (!class_ro->Read(process, class_rw->m_ro_ptr))
1442             {
1443                 class_rw.reset();
1444                 class_ro.reset();
1445                 return false;
1446             }
1447         }
1448         else
1449         {
1450             class_ro.reset(new class_ro_t);
1451 
1452             if (!class_ro->Read(process, objc_class.m_data_ptr))
1453             {
1454                 class_ro.reset();
1455                 return false;
1456             }
1457         }
1458 
1459         return true;
1460     }
1461 
1462     AppleObjCRuntimeV2 &m_runtime;          // The runtime, so we can read information lazily.
1463     lldb::addr_t        m_objc_class_ptr;   // The address of the objc_class_t.  (I.e., objects of this class type have this as their ISA)
1464     ConstString         m_name;             // May be NULL
1465 };
1466 
1467 // tagged pointer descriptor
1468 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor
1469 {
1470 public:
ClassDescriptorV2Tagged(ConstString class_name,uint64_t payload)1471     ClassDescriptorV2Tagged (ConstString class_name,
1472                              uint64_t payload)
1473     {
1474         m_name = class_name;
1475         if (!m_name)
1476         {
1477             m_valid = false;
1478             return;
1479         }
1480         m_valid = true;
1481         m_payload = payload;
1482         m_info_bits = (m_payload & 0xF0ULL) >> 4;
1483         m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8;
1484     }
1485 
ClassDescriptorV2Tagged(ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,uint64_t payload)1486     ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp,
1487                              uint64_t payload)
1488     {
1489         if (!actual_class_sp)
1490         {
1491             m_valid = false;
1492             return;
1493         }
1494         m_name = actual_class_sp->GetClassName();
1495         if (!m_name)
1496         {
1497             m_valid = false;
1498             return;
1499         }
1500         m_valid = true;
1501         m_payload = payload;
1502         m_info_bits = (m_payload & 0x0FULL);
1503         m_value_bits = (m_payload & ~0x0FULL) >> 4;
1504     }
1505 
1506     virtual ConstString
GetClassName()1507     GetClassName ()
1508     {
1509         return m_name;
1510     }
1511 
1512     virtual ObjCLanguageRuntime::ClassDescriptorSP
GetSuperclass()1513     GetSuperclass ()
1514     {
1515         // tagged pointers can represent a class that has a superclass, but since that information is not
1516         // stored in the object itself, we would have to query the runtime to discover the hierarchy
1517         // for the time being, we skip this step in the interest of static discovery
1518         return ObjCLanguageRuntime::ClassDescriptorSP();
1519     }
1520 
1521     virtual bool
IsValid()1522     IsValid ()
1523     {
1524         return m_valid;
1525     }
1526 
1527     virtual bool
IsKVO()1528     IsKVO ()
1529     {
1530         return false; // tagged pointers are not KVO'ed
1531     }
1532 
1533     virtual bool
IsCFType()1534     IsCFType ()
1535     {
1536         return false; // tagged pointers are not CF objects
1537     }
1538 
1539     virtual bool
GetTaggedPointerInfo(uint64_t * info_bits=NULL,uint64_t * value_bits=NULL,uint64_t * payload=NULL)1540     GetTaggedPointerInfo (uint64_t* info_bits = NULL,
1541                           uint64_t* value_bits = NULL,
1542                           uint64_t* payload = NULL)
1543     {
1544         if (info_bits)
1545             *info_bits = GetInfoBits();
1546         if (value_bits)
1547             *value_bits = GetValueBits();
1548         if (payload)
1549             *payload = GetPayload();
1550         return true;
1551     }
1552 
1553     virtual uint64_t
GetInstanceSize()1554     GetInstanceSize ()
1555     {
1556         return (IsValid() ? m_pointer_size : 0);
1557     }
1558 
1559     virtual ObjCLanguageRuntime::ObjCISA
GetISA()1560     GetISA ()
1561     {
1562         return 0; // tagged pointers have no ISA
1563     }
1564 
1565     // these calls are not part of any formal tagged pointers specification
1566     virtual uint64_t
GetValueBits()1567     GetValueBits ()
1568     {
1569         return (IsValid() ? m_value_bits : 0);
1570     }
1571 
1572     virtual uint64_t
GetInfoBits()1573     GetInfoBits ()
1574     {
1575         return (IsValid() ? m_info_bits : 0);
1576     }
1577 
1578     virtual uint64_t
GetPayload()1579     GetPayload ()
1580     {
1581         return (IsValid() ? m_payload : 0);
1582     }
1583 
1584     virtual
~ClassDescriptorV2Tagged()1585     ~ClassDescriptorV2Tagged ()
1586     {}
1587 
1588 private:
1589     ConstString m_name;
1590     uint8_t m_pointer_size;
1591     bool m_valid;
1592     uint64_t m_info_bits;
1593     uint64_t m_value_bits;
1594     uint64_t m_payload;
1595 
1596 };
1597 
1598 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ObjCISA isa)1599 AppleObjCRuntimeV2::GetClassDescriptor (ObjCISA isa)
1600 {
1601     ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
1602     if (m_non_pointer_isa_cache_ap.get())
1603         class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa);
1604     if (!class_descriptor_sp)
1605         class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
1606     return class_descriptor_sp;
1607 }
1608 
1609 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ValueObject & valobj)1610 AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj)
1611 {
1612     ClassDescriptorSP objc_class_sp;
1613     // if we get an invalid VO (which might still happen when playing around
1614     // with pointers returned by the expression parser, don't consider this
1615     // a valid ObjC object)
1616     if (valobj.GetClangType().IsValid())
1617     {
1618         addr_t isa_pointer = valobj.GetPointerValue();
1619 
1620         // tagged pointer
1621         if (IsTaggedPointer(isa_pointer))
1622         {
1623             return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer);
1624         }
1625         else
1626         {
1627             ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
1628 
1629             Process *process = exe_ctx.GetProcessPtr();
1630             if (process)
1631             {
1632                 Error error;
1633                 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
1634                 if (isa != LLDB_INVALID_ADDRESS)
1635                 {
1636                     objc_class_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA (isa);
1637                     if (isa && !objc_class_sp)
1638                     {
1639                         Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1640                         if (log)
1641                             log->Printf("0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was not in class descriptor cache 0x%" PRIx64,
1642                                         isa_pointer,
1643                                         isa);
1644                     }
1645                 }
1646             }
1647         }
1648     }
1649     return objc_class_sp;
1650 }
1651 
1652 lldb::addr_t
GetISAHashTablePointer()1653 AppleObjCRuntimeV2::GetISAHashTablePointer ()
1654 {
1655     if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS)
1656     {
1657         Process *process = GetProcess();
1658 
1659         ModuleSP objc_module_sp(GetObjCModule());
1660 
1661         if (!objc_module_sp)
1662             return LLDB_INVALID_ADDRESS;
1663 
1664         static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");
1665 
1666         const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_objc_realized_classes, lldb::eSymbolTypeData);
1667         if (symbol)
1668         {
1669             lldb::addr_t gdb_objc_realized_classes_ptr = symbol->GetAddress().GetLoadAddress(&process->GetTarget());
1670 
1671             if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS)
1672             {
1673                 Error error;
1674                 m_isa_hash_table_ptr = process->ReadPointerFromMemory(gdb_objc_realized_classes_ptr, error);
1675             }
1676         }
1677     }
1678     return m_isa_hash_table_ptr;
1679 }
1680 
1681 bool
UpdateISAToDescriptorMapDynamic(RemoteNXMapTable & hash_table)1682 AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table)
1683 {
1684     Process *process = GetProcess();
1685 
1686     if (process == NULL)
1687         return false;
1688 
1689     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1690 
1691     ExecutionContext exe_ctx;
1692 
1693     ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
1694 
1695     if (!thread_sp)
1696         return false;
1697 
1698     thread_sp->CalculateExecutionContext(exe_ctx);
1699     ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1700 
1701     if (!ast)
1702         return false;
1703 
1704     Address function_address;
1705 
1706     StreamString errors;
1707 
1708     const uint32_t addr_size = process->GetAddressByteSize();
1709 
1710     Error err;
1711 
1712     // Read the total number of classes from the hash table
1713     const uint32_t num_classes = hash_table.GetCount();
1714     if (num_classes == 0)
1715     {
1716         if (log)
1717             log->Printf ("No dynamic classes found in gdb_objc_realized_classes.");
1718         return false;
1719     }
1720 
1721     // Make some types for our arguments
1722     ClangASTType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1723     ClangASTType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1724 
1725     if (!m_get_class_info_code.get())
1726     {
1727         m_get_class_info_code.reset (new ClangUtilityFunction (g_get_dynamic_class_info_body,
1728                                                                g_get_dynamic_class_info_name));
1729 
1730         errors.Clear();
1731 
1732         if (!m_get_class_info_code->Install(errors, exe_ctx))
1733         {
1734             if (log)
1735                 log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
1736             m_get_class_info_code.reset();
1737         }
1738     }
1739 
1740     if (m_get_class_info_code.get())
1741         function_address.SetOffset(m_get_class_info_code->StartAddress());
1742     else
1743         return false;
1744 
1745     ValueList arguments;
1746 
1747     // Next make the runner function for our implementation utility function.
1748     if (!m_get_class_info_function.get())
1749     {
1750         Value value;
1751         value.SetValueType (Value::eValueTypeScalar);
1752 //        value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
1753         value.SetClangType (clang_void_pointer_type);
1754         arguments.PushValue (value);
1755         arguments.PushValue (value);
1756 
1757         value.SetValueType (Value::eValueTypeScalar);
1758 //        value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1759         value.SetClangType (clang_uint32_t_type);
1760         arguments.PushValue (value);
1761 
1762         m_get_class_info_function.reset(new ClangFunction (*m_process,
1763                                                            clang_uint32_t_type,
1764                                                            function_address,
1765                                                            arguments));
1766 
1767         if (m_get_class_info_function.get() == NULL)
1768             return false;
1769 
1770         errors.Clear();
1771 
1772         unsigned num_errors = m_get_class_info_function->CompileFunction(errors);
1773         if (num_errors)
1774         {
1775             if (log)
1776                 log->Printf ("Error compiling function: \"%s\".", errors.GetData());
1777             return false;
1778         }
1779 
1780         errors.Clear();
1781 
1782         if (!m_get_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
1783         {
1784             if (log)
1785                 log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
1786             return false;
1787         }
1788     }
1789     else
1790     {
1791         arguments = m_get_class_info_function->GetArgumentValues ();
1792     }
1793 
1794     const uint32_t class_info_byte_size = addr_size + 4;
1795     const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1796     lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size,
1797                                                             ePermissionsReadable | ePermissionsWritable,
1798                                                             err);
1799 
1800     if (class_infos_addr == LLDB_INVALID_ADDRESS)
1801         return false;
1802 
1803     Mutex::Locker locker(m_get_class_info_args_mutex);
1804 
1805     // Fill in our function argument values
1806     arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
1807     arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1808     arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1809 
1810     bool success = false;
1811 
1812     errors.Clear();
1813 
1814     // Write our function arguments into the process so we can run our function
1815     if (m_get_class_info_function->WriteFunctionArguments (exe_ctx,
1816                                                            m_get_class_info_args,
1817                                                            function_address,
1818                                                            arguments,
1819                                                            errors))
1820     {
1821         bool stop_others = true;
1822         bool try_all_threads = false;
1823         bool unwind_on_error = true;
1824         bool ignore_breakpoints = true;
1825 
1826         Value return_value;
1827         return_value.SetValueType (Value::eValueTypeScalar);
1828         //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1829         return_value.SetClangType (clang_uint32_t_type);
1830         return_value.GetScalar() = 0;
1831 
1832         errors.Clear();
1833 
1834         // Run the function
1835         ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx,
1836                                                                                &m_get_class_info_args,
1837                                                                                errors,
1838                                                                                stop_others,
1839                                                                                UTILITY_FUNCTION_TIMEOUT_USEC,
1840                                                                                try_all_threads,
1841                                                                                unwind_on_error,
1842                                                                                ignore_breakpoints,
1843                                                                                return_value);
1844 
1845         if (results == eExecutionCompleted)
1846         {
1847             // The result is the number of ClassInfo structures that were filled in
1848             uint32_t num_class_infos = return_value.GetScalar().ULong();
1849             if (log)
1850                 log->Printf("Discovered %u ObjC classes\n",num_class_infos);
1851             if (num_class_infos > 0)
1852             {
1853                 // Read the ClassInfo structures
1854                 DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
1855                 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize())
1856                 {
1857                     DataExtractor class_infos_data (buffer.GetBytes(),
1858                                                     buffer.GetByteSize(),
1859                                                     process->GetByteOrder(),
1860                                                     addr_size);
1861                     ParseClassInfoArray (class_infos_data, num_class_infos);
1862                 }
1863             }
1864             success = true;
1865         }
1866         else
1867         {
1868             if (log)
1869                 log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
1870         }
1871     }
1872     else
1873     {
1874         if (log)
1875             log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
1876     }
1877 
1878     // Deallocate the memory we allocated for the ClassInfo array
1879     process->DeallocateMemory(class_infos_addr);
1880 
1881     return success;
1882 }
1883 
1884 void
ParseClassInfoArray(const DataExtractor & data,uint32_t num_class_infos)1885 AppleObjCRuntimeV2::ParseClassInfoArray (const DataExtractor &data, uint32_t num_class_infos)
1886 {
1887     // Parses an array of "num_class_infos" packed ClassInfo structures:
1888     //
1889     //    struct ClassInfo
1890     //    {
1891     //        Class isa;
1892     //        uint32_t hash;
1893     //    } __attribute__((__packed__));
1894 
1895     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1896 
1897     // Iterate through all ClassInfo structures
1898     lldb::offset_t offset = 0;
1899     for (uint32_t i=0; i<num_class_infos; ++i)
1900     {
1901         ObjCISA isa = data.GetPointer(&offset);
1902 
1903         if (isa == 0)
1904         {
1905             if (log)
1906                 log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
1907             continue;
1908         }
1909         // Check if we already know about this ISA, if we do, the info will
1910         // never change, so we can just skip it.
1911         if (ISAIsCached(isa))
1912         {
1913             offset += 4;
1914         }
1915         else
1916         {
1917             // Read the 32 bit hash for the class name
1918             const uint32_t name_hash = data.GetU32(&offset);
1919             ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL));
1920             AddClass (isa, descriptor_sp, name_hash);
1921             if (log && log->GetVerbose())
1922                 log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x", isa, name_hash);
1923         }
1924     }
1925 }
1926 
1927 bool
UpdateISAToDescriptorMapSharedCache()1928 AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
1929 {
1930     Process *process = GetProcess();
1931 
1932     if (process == NULL)
1933         return false;
1934 
1935     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1936 
1937     ExecutionContext exe_ctx;
1938 
1939     ThreadSP thread_sp = process->GetThreadList().GetSelectedThread();
1940 
1941     if (!thread_sp)
1942         return false;
1943 
1944     thread_sp->CalculateExecutionContext(exe_ctx);
1945     ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1946 
1947     if (!ast)
1948         return false;
1949 
1950     Address function_address;
1951 
1952     StreamString errors;
1953 
1954     const uint32_t addr_size = process->GetAddressByteSize();
1955 
1956     Error err;
1957 
1958     const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
1959 
1960     if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
1961         return false;
1962 
1963     // Read the total number of classes from the hash table
1964     const uint32_t num_classes = 16*1024;
1965     if (num_classes == 0)
1966     {
1967         if (log)
1968             log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr.");
1969         return false;
1970     }
1971 
1972     // Make some types for our arguments
1973     ClangASTType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1974     ClangASTType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1975 
1976     if (!m_get_shared_cache_class_info_code.get())
1977     {
1978         m_get_shared_cache_class_info_code.reset (new ClangUtilityFunction (g_get_shared_cache_class_info_body,
1979                                                                             g_get_shared_cache_class_info_name));
1980 
1981         errors.Clear();
1982 
1983         if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx))
1984         {
1985             if (log)
1986                 log->Printf ("Failed to install implementation lookup: %s.", errors.GetData());
1987             m_get_shared_cache_class_info_code.reset();
1988         }
1989     }
1990 
1991     if (m_get_shared_cache_class_info_code.get())
1992         function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress());
1993     else
1994         return false;
1995 
1996     ValueList arguments;
1997 
1998     // Next make the runner function for our implementation utility function.
1999     if (!m_get_shared_cache_class_info_function.get())
2000     {
2001         Value value;
2002         value.SetValueType (Value::eValueTypeScalar);
2003         //value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
2004         value.SetClangType (clang_void_pointer_type);
2005         arguments.PushValue (value);
2006         arguments.PushValue (value);
2007 
2008         value.SetValueType (Value::eValueTypeScalar);
2009         //value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
2010         value.SetClangType (clang_uint32_t_type);
2011         arguments.PushValue (value);
2012 
2013         m_get_shared_cache_class_info_function.reset(new ClangFunction (*m_process,
2014                                                                         clang_uint32_t_type,
2015                                                                         function_address,
2016                                                                         arguments));
2017 
2018         if (m_get_shared_cache_class_info_function.get() == NULL)
2019             return false;
2020 
2021         errors.Clear();
2022 
2023         unsigned num_errors = m_get_shared_cache_class_info_function->CompileFunction(errors);
2024         if (num_errors)
2025         {
2026             if (log)
2027                 log->Printf ("Error compiling function: \"%s\".", errors.GetData());
2028             return false;
2029         }
2030 
2031         errors.Clear();
2032 
2033         if (!m_get_shared_cache_class_info_function->WriteFunctionWrapper(exe_ctx, errors))
2034         {
2035             if (log)
2036                 log->Printf ("Error Inserting function: \"%s\".", errors.GetData());
2037             return false;
2038         }
2039     }
2040     else
2041     {
2042         arguments = m_get_shared_cache_class_info_function->GetArgumentValues ();
2043     }
2044 
2045     const uint32_t class_info_byte_size = addr_size + 4;
2046     const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
2047     lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size,
2048                                                              ePermissionsReadable | ePermissionsWritable,
2049                                                              err);
2050 
2051     if (class_infos_addr == LLDB_INVALID_ADDRESS)
2052         return false;
2053 
2054     Mutex::Locker locker(m_get_shared_cache_class_info_args_mutex);
2055 
2056     // Fill in our function argument values
2057     arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
2058     arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
2059     arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
2060 
2061     bool success = false;
2062 
2063     errors.Clear();
2064 
2065     // Write our function arguments into the process so we can run our function
2066     if (m_get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx,
2067                                                                         m_get_shared_cache_class_info_args,
2068                                                                         function_address,
2069                                                                         arguments,
2070                                                                         errors))
2071     {
2072         bool stop_others = true;
2073         bool try_all_threads = false;
2074         bool unwind_on_error = true;
2075         bool ignore_breakpoints = true;
2076 
2077         Value return_value;
2078         return_value.SetValueType (Value::eValueTypeScalar);
2079         //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
2080         return_value.SetClangType (clang_uint32_t_type);
2081         return_value.GetScalar() = 0;
2082 
2083         errors.Clear();
2084 
2085         // Run the function
2086         ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx,
2087                                                                                             &m_get_shared_cache_class_info_args,
2088                                                                                             errors,
2089                                                                                             stop_others,
2090                                                                                             UTILITY_FUNCTION_TIMEOUT_USEC,
2091                                                                                             try_all_threads,
2092                                                                                             unwind_on_error,
2093                                                                                             ignore_breakpoints,
2094                                                                                             return_value);
2095 
2096         if (results == eExecutionCompleted)
2097         {
2098             // The result is the number of ClassInfo structures that were filled in
2099             uint32_t num_class_infos = return_value.GetScalar().ULong();
2100             if (log)
2101                 log->Printf("Discovered %u ObjC classes in shared cache\n",num_class_infos);
2102             if (num_class_infos > 0)
2103             {
2104                 // Read the ClassInfo structures
2105                 DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
2106                 if (process->ReadMemory(class_infos_addr,
2107                                         buffer.GetBytes(),
2108                                         buffer.GetByteSize(),
2109                                         err) == buffer.GetByteSize())
2110                 {
2111                     DataExtractor class_infos_data (buffer.GetBytes(),
2112                                                     buffer.GetByteSize(),
2113                                                     process->GetByteOrder(),
2114                                                     addr_size);
2115 
2116                     ParseClassInfoArray (class_infos_data, num_class_infos);
2117                 }
2118             }
2119             success = true;
2120         }
2121         else
2122         {
2123             if (log)
2124                 log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData());
2125         }
2126     }
2127     else
2128     {
2129         if (log)
2130             log->Printf ("Error writing function arguments: \"%s\".", errors.GetData());
2131     }
2132 
2133     // Deallocate the memory we allocated for the ClassInfo array
2134     process->DeallocateMemory(class_infos_addr);
2135 
2136     return success;
2137 }
2138 
2139 
2140 bool
UpdateISAToDescriptorMapFromMemory(RemoteNXMapTable & hash_table)2141 AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table)
2142 {
2143     Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
2144 
2145     Process *process = GetProcess();
2146 
2147     if (process == NULL)
2148         return false;
2149 
2150     uint32_t num_map_table_isas = 0;
2151 
2152     ModuleSP objc_module_sp(GetObjCModule());
2153 
2154     if (objc_module_sp)
2155     {
2156         for (RemoteNXMapTable::element elt : hash_table)
2157         {
2158             ++num_map_table_isas;
2159 
2160             if (ISAIsCached(elt.second))
2161                 continue;
2162 
2163             ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString()));
2164 
2165             if (log && log->GetVerbose())
2166                 log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString());
2167 
2168             AddClass (elt.second, descriptor_sp, elt.first.AsCString());
2169         }
2170     }
2171 
2172     return num_map_table_isas > 0;
2173 }
2174 
2175 lldb::addr_t
GetSharedCacheReadOnlyAddress()2176 AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress()
2177 {
2178     Process *process = GetProcess();
2179 
2180     if (process)
2181     {
2182         ModuleSP objc_module_sp(GetObjCModule());
2183 
2184         if (objc_module_sp)
2185         {
2186             ObjectFile *objc_object = objc_module_sp->GetObjectFile();
2187 
2188             if (objc_object)
2189             {
2190                 SectionList *section_list = objc_module_sp->GetSectionList();
2191 
2192                 if (section_list)
2193                 {
2194                     SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT")));
2195 
2196                     if (text_segment_sp)
2197                     {
2198                         SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro")));
2199 
2200                         if (objc_opt_section_sp)
2201                         {
2202                             return objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget());
2203                         }
2204                     }
2205                 }
2206             }
2207         }
2208     }
2209     return LLDB_INVALID_ADDRESS;
2210 }
2211 
2212 void
UpdateISAToDescriptorMapIfNeeded()2213 AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded()
2214 {
2215     Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
2216 
2217     // Else we need to check with our process to see when the map was updated.
2218     Process *process = GetProcess();
2219 
2220     if (process)
2221     {
2222         RemoteNXMapTable hash_table;
2223 
2224         // Update the process stop ID that indicates the last time we updated the
2225         // map, wether it was successful or not.
2226         m_isa_to_descriptor_stop_id = process->GetStopID();
2227 
2228         if (!m_hash_signature.NeedsUpdate(process, this, hash_table))
2229             return;
2230 
2231         m_hash_signature.UpdateSignature (hash_table);
2232 
2233         // Grab the dynamicly loaded objc classes from the hash table in memory
2234         UpdateISAToDescriptorMapDynamic(hash_table);
2235 
2236         // Now get the objc classes that are baked into the Objective C runtime
2237         // in the shared cache, but only once per process as this data never
2238         // changes
2239         if (!m_loaded_objc_opt)
2240             UpdateISAToDescriptorMapSharedCache();
2241     }
2242     else
2243     {
2244         m_isa_to_descriptor_stop_id = UINT32_MAX;
2245     }
2246 }
2247 
2248 
2249 // TODO: should we have a transparent_kvo parameter here to say if we
2250 // want to replace the KVO swizzled class with the actual user-level type?
2251 ConstString
GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)2252 AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
2253 {
2254     if (isa == g_objc_Tagged_ISA)
2255     {
2256         static const ConstString g_objc_tagged_isa_name ("_lldb_Tagged_ObjC_ISA");
2257         return g_objc_tagged_isa_name;
2258     }
2259     if (isa == g_objc_Tagged_ISA_NSAtom)
2260     {
2261         static const ConstString g_objc_tagged_isa_nsatom_name ("NSAtom");
2262         return g_objc_tagged_isa_nsatom_name;
2263     }
2264     if (isa == g_objc_Tagged_ISA_NSNumber)
2265     {
2266         static const ConstString g_objc_tagged_isa_nsnumber_name ("NSNumber");
2267         return g_objc_tagged_isa_nsnumber_name;
2268     }
2269     if (isa == g_objc_Tagged_ISA_NSDateTS)
2270     {
2271         static const ConstString g_objc_tagged_isa_nsdatets_name ("NSDateTS");
2272         return g_objc_tagged_isa_nsdatets_name;
2273     }
2274     if (isa == g_objc_Tagged_ISA_NSManagedObject)
2275     {
2276         static const ConstString g_objc_tagged_isa_nsmanagedobject_name ("NSManagedObject");
2277         return g_objc_tagged_isa_nsmanagedobject_name;
2278     }
2279     if (isa == g_objc_Tagged_ISA_NSDate)
2280     {
2281         static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate");
2282         return g_objc_tagged_isa_nsdate_name;
2283     }
2284     return ObjCLanguageRuntime::GetActualTypeName(isa);
2285 }
2286 
2287 TypeVendor *
GetTypeVendor()2288 AppleObjCRuntimeV2::GetTypeVendor()
2289 {
2290     if (!m_type_vendor_ap.get())
2291         m_type_vendor_ap.reset(new AppleObjCTypeVendor(*this));
2292 
2293     return m_type_vendor_ap.get();
2294 }
2295 
2296 lldb::addr_t
LookupRuntimeSymbol(const ConstString & name)2297 AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name)
2298 {
2299     lldb::addr_t ret = LLDB_INVALID_ADDRESS;
2300 
2301     const char *name_cstr = name.AsCString();
2302 
2303     if (name_cstr)
2304     {
2305         llvm::StringRef name_strref(name_cstr);
2306 
2307         static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
2308         static const llvm::StringRef class_prefix("OBJC_CLASS_$_");
2309 
2310         if (name_strref.startswith(ivar_prefix))
2311         {
2312             llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size());
2313             std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.');
2314 
2315             if (class_and_ivar.first.size() && class_and_ivar.second.size())
2316             {
2317                 const ConstString class_name_cs(class_and_ivar.first);
2318                 ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);
2319 
2320                 if (descriptor)
2321                 {
2322                     const ConstString ivar_name_cs(class_and_ivar.second);
2323                     const char *ivar_name_cstr = ivar_name_cs.AsCString();
2324 
2325                     auto ivar_func = [&ret, ivar_name_cstr](const char *name, const char *type, lldb::addr_t offset_addr, uint64_t size) -> lldb::addr_t
2326                     {
2327                         if (!strcmp(name, ivar_name_cstr))
2328                         {
2329                             ret = offset_addr;
2330                             return true;
2331                         }
2332                         return false;
2333                     };
2334 
2335                     descriptor->Describe(std::function<void (ObjCISA)>(nullptr),
2336                                          std::function<bool (const char *, const char *)>(nullptr),
2337                                          std::function<bool (const char *, const char *)>(nullptr),
2338                                          ivar_func);
2339                 }
2340             }
2341         }
2342         else if (name_strref.startswith(class_prefix))
2343         {
2344             llvm::StringRef class_skipped_prefix = name_strref.substr(class_prefix.size());
2345             const ConstString class_name_cs(class_skipped_prefix);
2346             ClassDescriptorSP descriptor = GetClassDescriptorFromClassName(class_name_cs);
2347 
2348             if (descriptor)
2349                 ret = descriptor->GetISA();
2350         }
2351     }
2352 
2353     return ret;
2354 }
2355 
2356 AppleObjCRuntimeV2::NonPointerISACache*
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2357 AppleObjCRuntimeV2::NonPointerISACache::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
2358 {
2359     Process* process(runtime.GetProcess());
2360 
2361     Error error;
2362 
2363     auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(process,
2364                                                                 ConstString("objc_debug_isa_magic_mask"),
2365                                                                 objc_module_sp,
2366                                                                 error);
2367     if (error.Fail())
2368         return NULL;
2369 
2370     auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(process,
2371                                                                  ConstString("objc_debug_isa_magic_value"),
2372                                                                  objc_module_sp,
2373                                                                  error);
2374     if (error.Fail())
2375         return NULL;
2376 
2377     auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(process,
2378                                                                 ConstString("objc_debug_isa_class_mask"),
2379                                                                 objc_module_sp,
2380                                                                 error);
2381     if (error.Fail())
2382         return NULL;
2383 
2384     // we might want to have some rules to outlaw these other values (e.g if the mask is zero but the value is non-zero, ...)
2385 
2386     return new NonPointerISACache(runtime,
2387                                   objc_debug_isa_class_mask,
2388                                   objc_debug_isa_magic_mask,
2389                                   objc_debug_isa_magic_value);
2390 }
2391 
2392 AppleObjCRuntimeV2::TaggedPointerVendor*
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2393 AppleObjCRuntimeV2::TaggedPointerVendor::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
2394 {
2395     Process* process(runtime.GetProcess());
2396 
2397     Error error;
2398 
2399     auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(process,
2400                                                                     ConstString("objc_debug_taggedpointer_mask"),
2401                                                                     objc_module_sp,
2402                                                                     error);
2403     if (error.Fail())
2404         return new TaggedPointerVendorLegacy(runtime);
2405 
2406     auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(process,
2407                                                                           ConstString("objc_debug_taggedpointer_slot_shift"),
2408                                                                           objc_module_sp,
2409                                                                           error,
2410                                                                           true,
2411                                                                           4);
2412     if (error.Fail())
2413         return new TaggedPointerVendorLegacy(runtime);
2414 
2415     auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(process,
2416                                                                           ConstString("objc_debug_taggedpointer_slot_mask"),
2417                                                                           objc_module_sp,
2418                                                                           error,
2419                                                                           true,
2420                                                                           4);
2421     if (error.Fail())
2422         return new TaggedPointerVendorLegacy(runtime);
2423 
2424     auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(process,
2425                                                                               ConstString("objc_debug_taggedpointer_payload_lshift"),
2426                                                                               objc_module_sp,
2427                                                                               error,
2428                                                                               true,
2429                                                                               4);
2430     if (error.Fail())
2431         return new TaggedPointerVendorLegacy(runtime);
2432 
2433     auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(process,
2434                                                                               ConstString("objc_debug_taggedpointer_payload_rshift"),
2435                                                                               objc_module_sp,
2436                                                                               error,
2437                                                                               true,
2438                                                                               4);
2439     if (error.Fail())
2440         return new TaggedPointerVendorLegacy(runtime);
2441 
2442     auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(process,
2443                                                                        ConstString("objc_debug_taggedpointer_classes"),
2444                                                                        objc_module_sp,
2445                                                                        error,
2446                                                                        false);
2447     if (error.Fail())
2448         return new TaggedPointerVendorLegacy(runtime);
2449 
2450 
2451     // we might want to have some rules to outlaw these values (e.g if the table's address is zero)
2452 
2453     return new TaggedPointerVendorRuntimeAssisted(runtime,
2454                                                   objc_debug_taggedpointer_mask,
2455                                                   objc_debug_taggedpointer_slot_shift,
2456                                                   objc_debug_taggedpointer_slot_mask,
2457                                                   objc_debug_taggedpointer_payload_lshift,
2458                                                   objc_debug_taggedpointer_payload_rshift,
2459                                                   objc_debug_taggedpointer_classes);
2460 }
2461 
2462 bool
IsPossibleTaggedPointer(lldb::addr_t ptr)2463 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer (lldb::addr_t ptr)
2464 {
2465     return (ptr & 1);
2466 }
2467 
2468 // we use the version of Foundation to make assumptions about the ObjC runtime on a target
2469 uint32_t
GetFoundationVersion(Target & target)2470 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetFoundationVersion (Target &target)
2471 {
2472     const ModuleList& modules = target.GetImages();
2473     uint32_t major = UINT32_MAX;
2474     for (uint32_t idx = 0; idx < modules.GetSize(); idx++)
2475     {
2476         lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx);
2477         if (!module_sp)
2478             continue;
2479         if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0)
2480         {
2481             module_sp->GetVersion(&major,1);
2482             break;
2483         }
2484     }
2485     return major;
2486 }
2487 
2488 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2489 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor (lldb::addr_t ptr)
2490 {
2491     if (!IsPossibleTaggedPointer(ptr))
2492         return ObjCLanguageRuntime::ClassDescriptorSP();
2493 
2494     Process* process(m_runtime.GetProcess());
2495 
2496     if (m_Foundation_version == 0)
2497         m_Foundation_version = GetFoundationVersion(process->GetTarget());
2498 
2499     if (m_Foundation_version == UINT32_MAX)
2500         return ObjCLanguageRuntime::ClassDescriptorSP();
2501 
2502     uint64_t class_bits = (ptr & 0xE) >> 1;
2503     ConstString name;
2504 
2505     // TODO: make a table
2506     if (m_Foundation_version >= 900)
2507     {
2508         switch (class_bits)
2509         {
2510             case 0:
2511                 name = ConstString("NSAtom");
2512                 break;
2513             case 3:
2514                 name = ConstString("NSNumber");
2515                 break;
2516             case 4:
2517                 name = ConstString("NSDateTS");
2518                 break;
2519             case 5:
2520                 name = ConstString("NSManagedObject");
2521                 break;
2522             case 6:
2523                 name = ConstString("NSDate");
2524                 break;
2525             default:
2526                 return ObjCLanguageRuntime::ClassDescriptorSP();
2527         }
2528     }
2529     else
2530     {
2531         switch (class_bits)
2532         {
2533             case 1:
2534                 name = ConstString("NSNumber");
2535                 break;
2536             case 5:
2537                 name = ConstString("NSManagedObject");
2538                 break;
2539             case 6:
2540                 name = ConstString("NSDate");
2541                 break;
2542             case 7:
2543                 name = ConstString("NSDateTS");
2544                 break;
2545             default:
2546                 return ObjCLanguageRuntime::ClassDescriptorSP();
2547         }
2548     }
2549     return ClassDescriptorSP(new ClassDescriptorV2Tagged(name,ptr));
2550 }
2551 
TaggedPointerVendorRuntimeAssisted(AppleObjCRuntimeV2 & runtime,uint64_t objc_debug_taggedpointer_mask,uint32_t objc_debug_taggedpointer_slot_shift,uint32_t objc_debug_taggedpointer_slot_mask,uint32_t objc_debug_taggedpointer_payload_lshift,uint32_t objc_debug_taggedpointer_payload_rshift,lldb::addr_t objc_debug_taggedpointer_classes)2552 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime,
2553                                                                                             uint64_t objc_debug_taggedpointer_mask,
2554                                                                                             uint32_t objc_debug_taggedpointer_slot_shift,
2555                                                                                             uint32_t objc_debug_taggedpointer_slot_mask,
2556                                                                                             uint32_t objc_debug_taggedpointer_payload_lshift,
2557                                                                                             uint32_t objc_debug_taggedpointer_payload_rshift,
2558                                                                                             lldb::addr_t objc_debug_taggedpointer_classes) :
2559 TaggedPointerVendor(runtime),
2560 m_cache(),
2561 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
2562 m_objc_debug_taggedpointer_slot_shift(objc_debug_taggedpointer_slot_shift),
2563 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
2564 m_objc_debug_taggedpointer_payload_lshift(objc_debug_taggedpointer_payload_lshift),
2565 m_objc_debug_taggedpointer_payload_rshift(objc_debug_taggedpointer_payload_rshift),
2566 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes)
2567 {
2568 }
2569 
2570 bool
IsPossibleTaggedPointer(lldb::addr_t ptr)2571 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::IsPossibleTaggedPointer (lldb::addr_t ptr)
2572 {
2573     return (ptr & m_objc_debug_taggedpointer_mask) != 0;
2574 }
2575 
2576 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2577 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor (lldb::addr_t ptr)
2578 {
2579     ClassDescriptorSP actual_class_descriptor_sp;
2580     uint64_t data_payload;
2581 
2582     if (!IsPossibleTaggedPointer(ptr))
2583         return ObjCLanguageRuntime::ClassDescriptorSP();
2584 
2585     uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & m_objc_debug_taggedpointer_slot_mask;
2586 
2587     CacheIterator iterator = m_cache.find(slot),
2588     end = m_cache.end();
2589     if (iterator != end)
2590     {
2591         actual_class_descriptor_sp = iterator->second;
2592     }
2593     else
2594     {
2595         Process* process(m_runtime.GetProcess());
2596         uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_classes;
2597         Error error;
2598         uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2599         if (error.Fail() || slot_data == 0 || slot_data == LLDB_INVALID_ADDRESS)
2600             return nullptr;
2601         actual_class_descriptor_sp = m_runtime.GetClassDescriptor(slot_data);
2602         if (!actual_class_descriptor_sp)
2603             return ObjCLanguageRuntime::ClassDescriptorSP();
2604         m_cache[slot] = actual_class_descriptor_sp;
2605     }
2606 
2607     data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift);
2608 
2609     return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload));
2610 }
2611 
NonPointerISACache(AppleObjCRuntimeV2 & runtime,uint64_t objc_debug_isa_class_mask,uint64_t objc_debug_isa_magic_mask,uint64_t objc_debug_isa_magic_value)2612 AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache (AppleObjCRuntimeV2& runtime,
2613                                                             uint64_t objc_debug_isa_class_mask,
2614                                                             uint64_t objc_debug_isa_magic_mask,
2615                                                             uint64_t objc_debug_isa_magic_value) :
2616 m_runtime(runtime),
2617 m_cache(),
2618 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
2619 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
2620 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value)
2621 {
2622 }
2623 
2624 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ObjCISA isa)2625 AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor (ObjCISA isa)
2626 {
2627     ObjCISA real_isa = 0;
2628     if (EvaluateNonPointerISA(isa, real_isa) == false)
2629         return ObjCLanguageRuntime::ClassDescriptorSP();
2630     auto cache_iter = m_cache.find(real_isa);
2631     if (cache_iter != m_cache.end())
2632         return cache_iter->second;
2633     auto descriptor_sp = m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
2634     if (descriptor_sp) // cache only positive matches since the table might grow
2635         m_cache[real_isa] = descriptor_sp;
2636     return descriptor_sp;
2637 }
2638 
2639 bool
EvaluateNonPointerISA(ObjCISA isa,ObjCISA & ret_isa)2640 AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa)
2641 {
2642     if ( (isa & ~m_objc_debug_isa_class_mask) == 0)
2643         return false;
2644     if ( (isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value)
2645     {
2646         ret_isa = isa & m_objc_debug_isa_class_mask;
2647         return (ret_isa != 0); // this is a pointer so 0 is not a valid value
2648     }
2649     return false;
2650 }
2651