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