1 //===-- AppleObjCRuntimeV2.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include <cstdint>
10
11 #include <memory>
12 #include <string>
13 #include <vector>
14
15 #include "clang/AST/ASTContext.h"
16 #include "clang/AST/DeclObjC.h"
17
18 #include "lldb/Host/OptionParser.h"
19 #include "lldb/Symbol/CompilerType.h"
20 #include "lldb/lldb-enumerations.h"
21
22 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
23 #include "lldb/Core/Debugger.h"
24 #include "lldb/Core/Module.h"
25 #include "lldb/Core/PluginManager.h"
26 #include "lldb/Core/Section.h"
27 #include "lldb/Core/ValueObjectConstResult.h"
28 #include "lldb/Core/ValueObjectVariable.h"
29 #include "lldb/Expression/DiagnosticManager.h"
30 #include "lldb/Expression/FunctionCaller.h"
31 #include "lldb/Expression/UtilityFunction.h"
32 #include "lldb/Interpreter/CommandObject.h"
33 #include "lldb/Interpreter/CommandObjectMultiword.h"
34 #include "lldb/Interpreter/CommandReturnObject.h"
35 #include "lldb/Interpreter/OptionArgParser.h"
36 #include "lldb/Interpreter/OptionValueBoolean.h"
37 #include "lldb/Symbol/ObjectFile.h"
38 #include "lldb/Symbol/Symbol.h"
39 #include "lldb/Symbol/TypeList.h"
40 #include "lldb/Symbol/VariableList.h"
41 #include "lldb/Target/ABI.h"
42 #include "lldb/Target/DynamicLoader.h"
43 #include "lldb/Target/ExecutionContext.h"
44 #include "lldb/Target/Platform.h"
45 #include "lldb/Target/Process.h"
46 #include "lldb/Target/RegisterContext.h"
47 #include "lldb/Target/StackFrameRecognizer.h"
48 #include "lldb/Target/Target.h"
49 #include "lldb/Target/Thread.h"
50 #include "lldb/Utility/ConstString.h"
51 #include "lldb/Utility/Log.h"
52 #include "lldb/Utility/Scalar.h"
53 #include "lldb/Utility/Status.h"
54 #include "lldb/Utility/Stream.h"
55 #include "lldb/Utility/StreamString.h"
56 #include "lldb/Utility/Timer.h"
57
58 #include "AppleObjCClassDescriptorV2.h"
59 #include "AppleObjCDeclVendor.h"
60 #include "AppleObjCRuntimeV2.h"
61 #include "AppleObjCTrampolineHandler.h"
62 #include "AppleObjCTypeEncodingParser.h"
63
64 #include "clang/AST/ASTContext.h"
65 #include "clang/AST/DeclObjC.h"
66 #include "clang/Basic/TargetInfo.h"
67
68 #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
69
70 #include <vector>
71
72 using namespace lldb;
73 using namespace lldb_private;
74
75 char AppleObjCRuntimeV2::ID = 0;
76
77 static const char *g_get_dynamic_class_info_name =
78 "__lldb_apple_objc_v2_get_dynamic_class_info";
79
80 static const char *g_get_dynamic_class_info_body = R"(
81
82 extern "C"
83 {
84 size_t strlen(const char *);
85 char *strncpy (char * s1, const char * s2, size_t n);
86 int printf(const char * format, ...);
87 }
88 #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
89
90 typedef struct _NXMapTable {
91 void *prototype;
92 unsigned num_classes;
93 unsigned num_buckets_minus_one;
94 void *buckets;
95 } NXMapTable;
96
97 #define NX_MAPNOTAKEY ((void *)(-1))
98
99 typedef struct BucketInfo
100 {
101 const char *name_ptr;
102 Class isa;
103 } BucketInfo;
104
105 struct ClassInfo
106 {
107 Class isa;
108 uint32_t hash;
109 } __attribute__((__packed__));
110
111 uint32_t
112 __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
113 void *class_infos_ptr,
114 uint32_t class_infos_byte_size,
115 uint32_t should_log)
116 {
117 DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
118 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
119 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
120 const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
121 if (grc)
122 {
123 const unsigned num_classes = grc->num_classes;
124 DEBUG_PRINTF ("num_classes = %u\n", grc->num_classes);
125 if (class_infos_ptr)
126 {
127 const unsigned num_buckets_minus_one = grc->num_buckets_minus_one;
128 DEBUG_PRINTF ("num_buckets_minus_one = %u\n", num_buckets_minus_one);
129
130 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
131 DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
132
133 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
134 BucketInfo *buckets = (BucketInfo *)grc->buckets;
135
136 uint32_t idx = 0;
137 for (unsigned i=0; i<=num_buckets_minus_one; ++i)
138 {
139 if (buckets[i].name_ptr != NX_MAPNOTAKEY)
140 {
141 if (idx < max_class_infos)
142 {
143 const char *s = buckets[i].name_ptr;
144 uint32_t h = 5381;
145 for (unsigned char c = *s; c; c = *++s)
146 h = ((h << 5) + h) + c;
147 class_infos[idx].hash = h;
148 class_infos[idx].isa = buckets[i].isa;
149 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, buckets[i].name_ptr);
150 }
151 ++idx;
152 }
153 }
154 if (idx < max_class_infos)
155 {
156 class_infos[idx].isa = NULL;
157 class_infos[idx].hash = 0;
158 }
159 }
160 return num_classes;
161 }
162 return 0;
163 }
164
165 )";
166
167 static const char *g_get_dynamic_class_info2_name =
168 "__lldb_apple_objc_v2_get_dynamic_class_info2";
169
170 static const char *g_get_dynamic_class_info2_body = R"(
171
172 extern "C" {
173 int printf(const char * format, ...);
174 void free(void *ptr);
175 Class* objc_copyRealizedClassList_nolock(unsigned int *outCount);
176 const char* objc_debug_class_getNameRaw(Class cls);
177 }
178
179 #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
180
181 struct ClassInfo
182 {
183 Class isa;
184 uint32_t hash;
185 } __attribute__((__packed__));
186
187 uint32_t
188 __lldb_apple_objc_v2_get_dynamic_class_info2(void *gdb_objc_realized_classes_ptr,
189 void *class_infos_ptr,
190 uint32_t class_infos_byte_size,
191 uint32_t should_log)
192 {
193 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
194 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
195
196 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
197 DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
198
199 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
200
201 uint32_t count = 0;
202 Class* realized_class_list = objc_copyRealizedClassList_nolock(&count);
203 DEBUG_PRINTF ("count = %u\n", count);
204
205 uint32_t idx = 0;
206 for (uint32_t i=0; i<=count; ++i)
207 {
208 if (idx < max_class_infos)
209 {
210 Class isa = realized_class_list[i];
211 const char *name_ptr = objc_debug_class_getNameRaw(isa);
212 if (name_ptr == NULL)
213 continue;
214 const char *s = name_ptr;
215 uint32_t h = 5381;
216 for (unsigned char c = *s; c; c = *++s)
217 h = ((h << 5) + h) + c;
218 class_infos[idx].hash = h;
219 class_infos[idx].isa = isa;
220 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);
221 }
222 idx++;
223 }
224
225 if (idx < max_class_infos)
226 {
227 class_infos[idx].isa = NULL;
228 class_infos[idx].hash = 0;
229 }
230
231 free(realized_class_list);
232 return count;
233 }
234 )";
235
236 // We'll substitute in class_getName or class_getNameRaw depending
237 // on which is present.
238 static const char *g_shared_cache_class_name_funcptr = R"(
239 extern "C"
240 {
241 const char *%s(void *objc_class);
242 const char *(*class_name_lookup_func)(void *) = %s;
243 }
244 )";
245
246 static const char *g_get_shared_cache_class_info_name =
247 "__lldb_apple_objc_v2_get_shared_cache_class_info";
248
249 static const char *g_get_shared_cache_class_info_body = R"(
250
251 extern "C"
252 {
253 size_t strlen(const char *);
254 char *strncpy (char * s1, const char * s2, size_t n);
255 int printf(const char * format, ...);
256 }
257
258 #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
259
260
261 struct objc_classheader_t {
262 int32_t clsOffset;
263 int32_t hiOffset;
264 };
265
266 struct objc_classheader_v16_t {
267 uint64_t isDuplicate : 1,
268 objectCacheOffset : 47, // Offset from the shared cache base
269 dylibObjCIndex : 16;
270 };
271
272 struct objc_clsopt_t {
273 uint32_t capacity;
274 uint32_t occupied;
275 uint32_t shift;
276 uint32_t mask;
277 uint32_t zero;
278 uint32_t unused;
279 uint64_t salt;
280 uint32_t scramble[256];
281 uint8_t tab[0]; // tab[mask+1]
282 // uint8_t checkbytes[capacity];
283 // int32_t offset[capacity];
284 // objc_classheader_t clsOffsets[capacity];
285 // uint32_t duplicateCount;
286 // objc_classheader_t duplicateOffsets[duplicateCount];
287 };
288
289 struct objc_clsopt_v16_t {
290 uint32_t version;
291 uint32_t capacity;
292 uint32_t occupied;
293 uint32_t shift;
294 uint32_t mask;
295 uint64_t salt;
296 uint32_t scramble[256];
297 uint8_t tab[0]; // tab[mask+1]
298 // uint8_t checkbytes[capacity];
299 // int32_t offset[capacity];
300 // objc_classheader_t clsOffsets[capacity];
301 // uint32_t duplicateCount;
302 // objc_classheader_t duplicateOffsets[duplicateCount];
303 };
304
305 struct objc_opt_t {
306 uint32_t version;
307 int32_t selopt_offset;
308 int32_t headeropt_offset;
309 int32_t clsopt_offset;
310 };
311
312 struct objc_opt_v14_t {
313 uint32_t version;
314 uint32_t flags;
315 int32_t selopt_offset;
316 int32_t headeropt_offset;
317 int32_t clsopt_offset;
318 };
319
320 struct objc_opt_v16_t {
321 uint32_t version;
322 uint32_t flags;
323 int32_t selopt_offset;
324 int32_t headeropt_ro_offset;
325 int32_t unused_clsopt_offset;
326 int32_t unused_protocolopt_offset;
327 int32_t headeropt_rw_offset;
328 int32_t unused_protocolopt2_offset;
329 int32_t largeSharedCachesClassOffset;
330 int32_t largeSharedCachesProtocolOffset;
331 uint64_t relativeMethodSelectorBaseAddressCacheOffset;
332 };
333
334 struct ClassInfo
335 {
336 Class isa;
337 uint32_t hash;
338 } __attribute__((__packed__));
339
340 uint32_t
341 __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
342 void *shared_cache_base_ptr,
343 void *class_infos_ptr,
344 uint64_t *relative_selector_offset,
345 uint32_t class_infos_byte_size,
346 uint32_t should_log)
347 {
348 *relative_selector_offset = 0;
349 uint32_t idx = 0;
350 DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
351 DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
352 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
353 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
354 if (objc_opt_ro_ptr)
355 {
356 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
357 const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;
358 const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr;
359 if (objc_opt->version >= 16)
360 {
361 *relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset;
362 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version);
363 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags);
364 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset);
365 DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset);
366 DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset);
367 }
368 else if (objc_opt->version >= 14)
369 {
370 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);
371 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);
372 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);
373 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);
374 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);
375 }
376 else
377 {
378 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
379 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
380 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
381 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
382 }
383
384 if (objc_opt->version == 16)
385 {
386 const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + objc_opt_v16->largeSharedCachesClassOffset);
387 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
388
389 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
390
391 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
392
393 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
394 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
395 const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity);
396
397 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
398 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
399 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
400
401 for (uint32_t i=0; i<clsopt->capacity; ++i)
402 {
403 const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
404 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
405
406 if (classOffsets[i].isDuplicate) {
407 DEBUG_PRINTF("isDuplicate = true\n");
408 continue; // duplicate
409 }
410
411 if (objectCacheOffset == 0) {
412 DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
413 continue; // invalid offset
414 }
415
416 if (class_infos && idx < max_class_infos)
417 {
418 class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
419
420 // Lookup the class name.
421 const char *name = class_name_lookup_func(class_infos[idx].isa);
422 DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
423
424 // Hash the class name so we don't have to read it.
425 const char *s = name;
426 uint32_t h = 5381;
427 for (unsigned char c = *s; c; c = *++s)
428 {
429 // class_getName demangles swift names and the hash must
430 // be calculated on the mangled name. hash==0 means lldb
431 // will fetch the mangled name and compute the hash in
432 // ParseClassInfoArray.
433 if (c == '.')
434 {
435 h = 0;
436 break;
437 }
438 h = ((h << 5) + h) + c;
439 }
440 class_infos[idx].hash = h;
441 }
442 else
443 {
444 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
445 }
446 ++idx;
447 }
448
449 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
450 const uint32_t duplicate_count = *duplicate_count_ptr;
451 const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
452
453 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
454 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
455
456 for (uint32_t i=0; i<duplicate_count; ++i)
457 {
458 const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
459 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
460
461 if (classOffsets[i].isDuplicate) {
462 DEBUG_PRINTF("isDuplicate = true\n");
463 continue; // duplicate
464 }
465
466 if (objectCacheOffset == 0) {
467 DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
468 continue; // invalid offset
469 }
470
471 if (class_infos && idx < max_class_infos)
472 {
473 class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
474
475 // Lookup the class name.
476 const char *name = class_name_lookup_func(class_infos[idx].isa);
477 DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
478
479 // Hash the class name so we don't have to read it.
480 const char *s = name;
481 uint32_t h = 5381;
482 for (unsigned char c = *s; c; c = *++s)
483 {
484 // class_getName demangles swift names and the hash must
485 // be calculated on the mangled name. hash==0 means lldb
486 // will fetch the mangled name and compute the hash in
487 // ParseClassInfoArray.
488 if (c == '.')
489 {
490 h = 0;
491 break;
492 }
493 h = ((h << 5) + h) + c;
494 }
495 class_infos[idx].hash = h;
496 }
497 }
498 }
499 else if (objc_opt->version >= 12 && objc_opt->version <= 15)
500 {
501 const objc_clsopt_t* clsopt = NULL;
502 if (objc_opt->version >= 14)
503 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);
504 else
505 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
506 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
507 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
508 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
509 int32_t invalidEntryOffset = 0;
510 // this is safe to do because the version field order is invariant
511 if (objc_opt->version == 12)
512 invalidEntryOffset = 16;
513 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
514 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
515 const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
516 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
517 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
518 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
519 DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);
520 for (uint32_t i=0; i<clsopt->capacity; ++i)
521 {
522 const int32_t clsOffset = classOffsets[i].clsOffset;
523 DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);
524 if (clsOffset & 1)
525 {
526 DEBUG_PRINTF("clsOffset & 1\n");
527 continue; // duplicate
528 }
529 else if (clsOffset == invalidEntryOffset)
530 {
531 DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");
532 continue; // invalid offset
533 }
534
535 if (class_infos && idx < max_class_infos)
536 {
537 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
538 const char *name = class_name_lookup_func (class_infos[idx].isa);
539 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
540 // Hash the class name so we don't have to read it
541 const char *s = name;
542 uint32_t h = 5381;
543 for (unsigned char c = *s; c; c = *++s)
544 {
545 // class_getName demangles swift names and the hash must
546 // be calculated on the mangled name. hash==0 means lldb
547 // will fetch the mangled name and compute the hash in
548 // ParseClassInfoArray.
549 if (c == '.')
550 {
551 h = 0;
552 break;
553 }
554 h = ((h << 5) + h) + c;
555 }
556 class_infos[idx].hash = h;
557 }
558 else
559 {
560 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
561 }
562 ++idx;
563 }
564
565 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
566 const uint32_t duplicate_count = *duplicate_count_ptr;
567 const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
568 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
569 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
570 for (uint32_t i=0; i<duplicate_count; ++i)
571 {
572 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
573 if (clsOffset & 1)
574 continue; // duplicate
575 else if (clsOffset == invalidEntryOffset)
576 continue; // invalid offset
577
578 if (class_infos && idx < max_class_infos)
579 {
580 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
581 const char *name = class_name_lookup_func (class_infos[idx].isa);
582 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
583 // Hash the class name so we don't have to read it
584 const char *s = name;
585 uint32_t h = 5381;
586 for (unsigned char c = *s; c; c = *++s)
587 {
588 // class_getName demangles swift names and the hash must
589 // be calculated on the mangled name. hash==0 means lldb
590 // will fetch the mangled name and compute the hash in
591 // ParseClassInfoArray.
592 if (c == '.')
593 {
594 h = 0;
595 break;
596 }
597 h = ((h << 5) + h) + c;
598 }
599 class_infos[idx].hash = h;
600 }
601 ++idx;
602 }
603 }
604 DEBUG_PRINTF ("%u class_infos\n", idx);
605 DEBUG_PRINTF ("done\n");
606 }
607 return idx;
608 }
609
610
611 )";
612
613 static uint64_t
ExtractRuntimeGlobalSymbol(Process * process,ConstString name,const ModuleSP & module_sp,Status & error,bool read_value=true,uint8_t byte_size=0,uint64_t default_value=LLDB_INVALID_ADDRESS,SymbolType sym_type=lldb::eSymbolTypeData)614 ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
615 const ModuleSP &module_sp, Status &error,
616 bool read_value = true, uint8_t byte_size = 0,
617 uint64_t default_value = LLDB_INVALID_ADDRESS,
618 SymbolType sym_type = lldb::eSymbolTypeData) {
619 if (!process) {
620 error.SetErrorString("no process");
621 return default_value;
622 }
623
624 if (!module_sp) {
625 error.SetErrorString("no module");
626 return default_value;
627 }
628
629 if (!byte_size)
630 byte_size = process->GetAddressByteSize();
631 const Symbol *symbol =
632 module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
633
634 if (!symbol || !symbol->ValueIsAddress()) {
635 error.SetErrorString("no symbol");
636 return default_value;
637 }
638
639 lldb::addr_t symbol_load_addr =
640 symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
641 if (symbol_load_addr == LLDB_INVALID_ADDRESS) {
642 error.SetErrorString("symbol address invalid");
643 return default_value;
644 }
645
646 if (read_value)
647 return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size,
648 default_value, error);
649 return symbol_load_addr;
650 }
651
652 static void RegisterObjCExceptionRecognizer(Process *process);
653
AppleObjCRuntimeV2(Process * process,const ModuleSP & objc_module_sp)654 AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
655 const ModuleSP &objc_module_sp)
656 : AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp),
657 m_dynamic_class_info_extractor(*this),
658 m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),
659 m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),
660 m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),
661 m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),
662 m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),
663 m_loaded_objc_opt(false), m_non_pointer_isa_cache_up(),
664 m_tagged_pointer_vendor_up(
665 TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),
666 m_encoding_to_type_sp(), m_noclasses_warning_emitted(false),
667 m_CFBoolean_values(), m_realized_class_generation_count(0) {
668 static const ConstString g_gdb_object_getClass("gdb_object_getClass");
669 m_has_object_getClass = HasSymbol(g_gdb_object_getClass);
670 static const ConstString g_objc_copyRealizedClassList(
671 "_ZL33objc_copyRealizedClassList_nolockPj");
672 m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList);
673
674 RegisterObjCExceptionRecognizer(process);
675 }
676
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)677 bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
678 ValueObject &in_value, lldb::DynamicValueType use_dynamic,
679 TypeAndOrName &class_type_or_name, Address &address,
680 Value::ValueType &value_type) {
681 // We should never get here with a null process...
682 assert(m_process != nullptr);
683
684 // The Runtime is attached to a particular process, you shouldn't pass in a
685 // value from another process. Note, however, the process might be NULL (e.g.
686 // if the value was made with SBTarget::EvaluateExpression...) in which case
687 // it is sufficient if the target's match:
688
689 Process *process = in_value.GetProcessSP().get();
690 if (process)
691 assert(process == m_process);
692 else
693 assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get());
694
695 class_type_or_name.Clear();
696 value_type = Value::ValueType::Scalar;
697
698 // Make sure we can have a dynamic value before starting...
699 if (CouldHaveDynamicValue(in_value)) {
700 // First job, pull out the address at 0 offset from the object That will
701 // be the ISA pointer.
702 ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value));
703 if (objc_class_sp) {
704 const addr_t object_ptr = in_value.GetPointerValue();
705 address.SetRawAddress(object_ptr);
706
707 ConstString class_name(objc_class_sp->GetClassName());
708 class_type_or_name.SetName(class_name);
709 TypeSP type_sp(objc_class_sp->GetType());
710 if (type_sp)
711 class_type_or_name.SetTypeSP(type_sp);
712 else {
713 type_sp = LookupInCompleteClassCache(class_name);
714 if (type_sp) {
715 objc_class_sp->SetType(type_sp);
716 class_type_or_name.SetTypeSP(type_sp);
717 } else {
718 // try to go for a CompilerType at least
719 if (auto *vendor = GetDeclVendor()) {
720 auto types = vendor->FindTypes(class_name, /*max_matches*/ 1);
721 if (!types.empty())
722 class_type_or_name.SetCompilerType(types.front());
723 }
724 }
725 }
726 }
727 }
728 return !class_type_or_name.IsEmpty();
729 }
730
731 // Static Functions
CreateInstance(Process * process,LanguageType language)732 LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process,
733 LanguageType language) {
734 // FIXME: This should be a MacOS or iOS process, and we need to look for the
735 // OBJC section to make
736 // sure we aren't using the V1 runtime.
737 if (language == eLanguageTypeObjC) {
738 ModuleSP objc_module_sp;
739
740 if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
741 ObjCRuntimeVersions::eAppleObjC_V2)
742 return new AppleObjCRuntimeV2(process, objc_module_sp);
743 return nullptr;
744 }
745 return nullptr;
746 }
747
748 static constexpr OptionDefinition g_objc_classtable_dump_options[] = {
749 {LLDB_OPT_SET_ALL,
750 false,
751 "verbose",
752 'v',
753 OptionParser::eNoArgument,
754 nullptr,
755 {},
756 0,
757 eArgTypeNone,
758 "Print ivar and method information in detail"}};
759
760 class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {
761 public:
762 class CommandOptions : public Options {
763 public:
CommandOptions()764 CommandOptions() : Options(), m_verbose(false, false) {}
765
766 ~CommandOptions() override = default;
767
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)768 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
769 ExecutionContext *execution_context) override {
770 Status error;
771 const int short_option = m_getopt_table[option_idx].val;
772 switch (short_option) {
773 case 'v':
774 m_verbose.SetCurrentValue(true);
775 m_verbose.SetOptionWasSet();
776 break;
777
778 default:
779 error.SetErrorStringWithFormat("unrecognized short option '%c'",
780 short_option);
781 break;
782 }
783
784 return error;
785 }
786
OptionParsingStarting(ExecutionContext * execution_context)787 void OptionParsingStarting(ExecutionContext *execution_context) override {
788 m_verbose.Clear();
789 }
790
GetDefinitions()791 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
792 return llvm::makeArrayRef(g_objc_classtable_dump_options);
793 }
794
795 OptionValueBoolean m_verbose;
796 };
797
CommandObjectObjC_ClassTable_Dump(CommandInterpreter & interpreter)798 CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter)
799 : CommandObjectParsed(interpreter, "dump",
800 "Dump information on Objective-C classes "
801 "known to the current process.",
802 "language objc class-table dump",
803 eCommandRequiresProcess |
804 eCommandProcessMustBeLaunched |
805 eCommandProcessMustBePaused),
806 m_options() {
807 CommandArgumentEntry arg;
808 CommandArgumentData index_arg;
809
810 // Define the first (and only) variant of this arg.
811 index_arg.arg_type = eArgTypeRegularExpression;
812 index_arg.arg_repetition = eArgRepeatOptional;
813
814 // There is only one variant this argument could be; put it into the
815 // argument entry.
816 arg.push_back(index_arg);
817
818 // Push the data for the first argument into the m_arguments vector.
819 m_arguments.push_back(arg);
820 }
821
822 ~CommandObjectObjC_ClassTable_Dump() override = default;
823
GetOptions()824 Options *GetOptions() override { return &m_options; }
825
826 protected:
DoExecute(Args & command,CommandReturnObject & result)827 bool DoExecute(Args &command, CommandReturnObject &result) override {
828 std::unique_ptr<RegularExpression> regex_up;
829 switch (command.GetArgumentCount()) {
830 case 0:
831 break;
832 case 1: {
833 regex_up =
834 std::make_unique<RegularExpression>(command.GetArgumentAtIndex(0));
835 if (!regex_up->IsValid()) {
836 result.AppendError(
837 "invalid argument - please provide a valid regular expression");
838 result.SetStatus(lldb::eReturnStatusFailed);
839 return false;
840 }
841 break;
842 }
843 default: {
844 result.AppendError("please provide 0 or 1 arguments");
845 result.SetStatus(lldb::eReturnStatusFailed);
846 return false;
847 }
848 }
849
850 Process *process = m_exe_ctx.GetProcessPtr();
851 ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
852 if (objc_runtime) {
853 auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();
854 auto iterator = iterators_pair.first;
855 auto &std_out = result.GetOutputStream();
856 for (; iterator != iterators_pair.second; iterator++) {
857 if (iterator->second) {
858 const char *class_name =
859 iterator->second->GetClassName().AsCString("<unknown>");
860 if (regex_up && class_name &&
861 !regex_up->Execute(llvm::StringRef(class_name)))
862 continue;
863 std_out.Printf("isa = 0x%" PRIx64, iterator->first);
864 std_out.Printf(" name = %s", class_name);
865 std_out.Printf(" instance size = %" PRIu64,
866 iterator->second->GetInstanceSize());
867 std_out.Printf(" num ivars = %" PRIuPTR,
868 (uintptr_t)iterator->second->GetNumIVars());
869 if (auto superclass = iterator->second->GetSuperclass()) {
870 std_out.Printf(" superclass = %s",
871 superclass->GetClassName().AsCString("<unknown>"));
872 }
873 std_out.Printf("\n");
874 if (m_options.m_verbose) {
875 for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) {
876 auto ivar = iterator->second->GetIVarAtIndex(i);
877 std_out.Printf(
878 " ivar name = %s type = %s size = %" PRIu64
879 " offset = %" PRId32 "\n",
880 ivar.m_name.AsCString("<unknown>"),
881 ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),
882 ivar.m_size, ivar.m_offset);
883 }
884
885 iterator->second->Describe(
886 nullptr,
887 [&std_out](const char *name, const char *type) -> bool {
888 std_out.Printf(" instance method name = %s type = %s\n",
889 name, type);
890 return false;
891 },
892 [&std_out](const char *name, const char *type) -> bool {
893 std_out.Printf(" class method name = %s type = %s\n", name,
894 type);
895 return false;
896 },
897 nullptr);
898 }
899 } else {
900 if (regex_up && !regex_up->Execute(llvm::StringRef()))
901 continue;
902 std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n",
903 iterator->first);
904 }
905 }
906 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
907 return true;
908 }
909 result.AppendError("current process has no Objective-C runtime loaded");
910 result.SetStatus(lldb::eReturnStatusFailed);
911 return false;
912 }
913
914 CommandOptions m_options;
915 };
916
917 class CommandObjectMultiwordObjC_TaggedPointer_Info
918 : public CommandObjectParsed {
919 public:
CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter & interpreter)920 CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter)
921 : CommandObjectParsed(
922 interpreter, "info", "Dump information on a tagged pointer.",
923 "language objc tagged-pointer info",
924 eCommandRequiresProcess | eCommandProcessMustBeLaunched |
925 eCommandProcessMustBePaused) {
926 CommandArgumentEntry arg;
927 CommandArgumentData index_arg;
928
929 // Define the first (and only) variant of this arg.
930 index_arg.arg_type = eArgTypeAddress;
931 index_arg.arg_repetition = eArgRepeatPlus;
932
933 // There is only one variant this argument could be; put it into the
934 // argument entry.
935 arg.push_back(index_arg);
936
937 // Push the data for the first argument into the m_arguments vector.
938 m_arguments.push_back(arg);
939 }
940
941 ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;
942
943 protected:
DoExecute(Args & command,CommandReturnObject & result)944 bool DoExecute(Args &command, CommandReturnObject &result) override {
945 if (command.GetArgumentCount() == 0) {
946 result.AppendError("this command requires arguments");
947 result.SetStatus(lldb::eReturnStatusFailed);
948 return false;
949 }
950
951 Process *process = m_exe_ctx.GetProcessPtr();
952 ExecutionContext exe_ctx(process);
953 ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
954 if (objc_runtime) {
955 ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor =
956 objc_runtime->GetTaggedPointerVendor();
957 if (tagged_ptr_vendor) {
958 for (size_t i = 0; i < command.GetArgumentCount(); i++) {
959 const char *arg_str = command.GetArgumentAtIndex(i);
960 if (!arg_str)
961 continue;
962 Status error;
963 lldb::addr_t arg_addr = OptionArgParser::ToAddress(
964 &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);
965 if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail())
966 continue;
967 auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);
968 if (!descriptor_sp)
969 continue;
970 uint64_t info_bits = 0;
971 uint64_t value_bits = 0;
972 uint64_t payload = 0;
973 if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits,
974 &payload)) {
975 result.GetOutputStream().Printf(
976 "0x%" PRIx64 " is tagged.\n\tpayload = 0x%" PRIx64
977 "\n\tvalue = 0x%" PRIx64 "\n\tinfo bits = 0x%" PRIx64
978 "\n\tclass = %s\n",
979 (uint64_t)arg_addr, payload, value_bits, info_bits,
980 descriptor_sp->GetClassName().AsCString("<unknown>"));
981 } else {
982 result.GetOutputStream().Printf("0x%" PRIx64 " is not tagged.\n",
983 (uint64_t)arg_addr);
984 }
985 }
986 } else {
987 result.AppendError("current process has no tagged pointer support");
988 result.SetStatus(lldb::eReturnStatusFailed);
989 return false;
990 }
991 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
992 return true;
993 }
994 result.AppendError("current process has no Objective-C runtime loaded");
995 result.SetStatus(lldb::eReturnStatusFailed);
996 return false;
997 }
998 };
999
1000 class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword {
1001 public:
CommandObjectMultiwordObjC_ClassTable(CommandInterpreter & interpreter)1002 CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)
1003 : CommandObjectMultiword(
1004 interpreter, "class-table",
1005 "Commands for operating on the Objective-C class table.",
1006 "class-table <subcommand> [<subcommand-options>]") {
1007 LoadSubCommand(
1008 "dump",
1009 CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter)));
1010 }
1011
1012 ~CommandObjectMultiwordObjC_ClassTable() override = default;
1013 };
1014
1015 class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword {
1016 public:
CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter & interpreter)1017 CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)
1018 : CommandObjectMultiword(
1019 interpreter, "tagged-pointer",
1020 "Commands for operating on Objective-C tagged pointers.",
1021 "class-table <subcommand> [<subcommand-options>]") {
1022 LoadSubCommand(
1023 "info",
1024 CommandObjectSP(
1025 new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter)));
1026 }
1027
1028 ~CommandObjectMultiwordObjC_TaggedPointer() override = default;
1029 };
1030
1031 class CommandObjectMultiwordObjC : public CommandObjectMultiword {
1032 public:
CommandObjectMultiwordObjC(CommandInterpreter & interpreter)1033 CommandObjectMultiwordObjC(CommandInterpreter &interpreter)
1034 : CommandObjectMultiword(
1035 interpreter, "objc",
1036 "Commands for operating on the Objective-C language runtime.",
1037 "objc <subcommand> [<subcommand-options>]") {
1038 LoadSubCommand("class-table",
1039 CommandObjectSP(
1040 new CommandObjectMultiwordObjC_ClassTable(interpreter)));
1041 LoadSubCommand("tagged-pointer",
1042 CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer(
1043 interpreter)));
1044 }
1045
1046 ~CommandObjectMultiwordObjC() override = default;
1047 };
1048
Initialize()1049 void AppleObjCRuntimeV2::Initialize() {
1050 PluginManager::RegisterPlugin(
1051 GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 2",
1052 CreateInstance,
1053 [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
1054 return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));
1055 },
1056 GetBreakpointExceptionPrecondition);
1057 }
1058
Terminate()1059 void AppleObjCRuntimeV2::Terminate() {
1060 PluginManager::UnregisterPlugin(CreateInstance);
1061 }
1062
GetPluginNameStatic()1063 lldb_private::ConstString AppleObjCRuntimeV2::GetPluginNameStatic() {
1064 static ConstString g_name("apple-objc-v2");
1065 return g_name;
1066 }
1067
1068 // PluginInterface protocol
GetPluginName()1069 lldb_private::ConstString AppleObjCRuntimeV2::GetPluginName() {
1070 return GetPluginNameStatic();
1071 }
1072
GetPluginVersion()1073 uint32_t AppleObjCRuntimeV2::GetPluginVersion() { return 1; }
1074
1075 BreakpointResolverSP
CreateExceptionResolver(const BreakpointSP & bkpt,bool catch_bp,bool throw_bp)1076 AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt,
1077 bool catch_bp, bool throw_bp) {
1078 BreakpointResolverSP resolver_sp;
1079
1080 if (throw_bp)
1081 resolver_sp = std::make_shared<BreakpointResolverName>(
1082 bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
1083 eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
1084 eLazyBoolNo);
1085 // FIXME: We don't do catch breakpoints for ObjC yet.
1086 // Should there be some way for the runtime to specify what it can do in this
1087 // regard?
1088 return resolver_sp;
1089 }
1090
1091 llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string name,ExecutionContext & exe_ctx)1092 AppleObjCRuntimeV2::CreateObjectChecker(std::string name,
1093 ExecutionContext &exe_ctx) {
1094 char check_function_code[2048];
1095
1096 int len = 0;
1097 if (m_has_object_getClass) {
1098 len = ::snprintf(check_function_code, sizeof(check_function_code), R"(
1099 extern "C" void *gdb_object_getClass(void *);
1100 extern "C" int printf(const char *format, ...);
1101 extern "C" void
1102 %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {
1103 if ($__lldb_arg_obj == (void *)0)
1104 return; // nil is ok
1105 if (!gdb_object_getClass($__lldb_arg_obj)) {
1106 *((volatile int *)0) = 'ocgc';
1107 } else if ($__lldb_arg_selector != (void *)0) {
1108 signed char $responds = (signed char)
1109 [(id)$__lldb_arg_obj respondsToSelector:
1110 (void *) $__lldb_arg_selector];
1111 if ($responds == (signed char) 0)
1112 *((volatile int *)0) = 'ocgc';
1113 }
1114 })",
1115 name.c_str());
1116 } else {
1117 len = ::snprintf(check_function_code, sizeof(check_function_code), R"(
1118 extern "C" void *gdb_class_getClass(void *);
1119 extern "C" int printf(const char *format, ...);
1120 extern "C" void
1121 %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {
1122 if ($__lldb_arg_obj == (void *)0)
1123 return; // nil is ok
1124 void **$isa_ptr = (void **)$__lldb_arg_obj;
1125 if (*$isa_ptr == (void *)0 ||
1126 !gdb_class_getClass(*$isa_ptr))
1127 *((volatile int *)0) = 'ocgc';
1128 else if ($__lldb_arg_selector != (void *)0) {
1129 signed char $responds = (signed char)
1130 [(id)$__lldb_arg_obj respondsToSelector:
1131 (void *) $__lldb_arg_selector];
1132 if ($responds == (signed char) 0)
1133 *((volatile int *)0) = 'ocgc';
1134 }
1135 })",
1136 name.c_str());
1137 }
1138
1139 assert(len < (int)sizeof(check_function_code));
1140 UNUSED_IF_ASSERT_DISABLED(len);
1141
1142 return GetTargetRef().CreateUtilityFunction(check_function_code, name,
1143 eLanguageTypeC, exe_ctx);
1144 }
1145
GetByteOffsetForIvar(CompilerType & parent_ast_type,const char * ivar_name)1146 size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,
1147 const char *ivar_name) {
1148 uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;
1149
1150 ConstString class_name = parent_ast_type.GetTypeName();
1151 if (!class_name.IsEmpty() && ivar_name && ivar_name[0]) {
1152 // Make the objective C V2 mangled name for the ivar offset from the class
1153 // name and ivar name
1154 std::string buffer("OBJC_IVAR_$_");
1155 buffer.append(class_name.AsCString());
1156 buffer.push_back('.');
1157 buffer.append(ivar_name);
1158 ConstString ivar_const_str(buffer.c_str());
1159
1160 // Try to get the ivar offset address from the symbol table first using the
1161 // name we created above
1162 SymbolContextList sc_list;
1163 Target &target = m_process->GetTarget();
1164 target.GetImages().FindSymbolsWithNameAndType(ivar_const_str,
1165 eSymbolTypeObjCIVar, sc_list);
1166
1167 addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
1168
1169 Status error;
1170 SymbolContext ivar_offset_symbol;
1171 if (sc_list.GetSize() == 1 &&
1172 sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {
1173 if (ivar_offset_symbol.symbol)
1174 ivar_offset_address =
1175 ivar_offset_symbol.symbol->GetLoadAddress(&target);
1176 }
1177
1178 // If we didn't get the ivar offset address from the symbol table, fall
1179 // back to getting it from the runtime
1180 if (ivar_offset_address == LLDB_INVALID_ADDRESS)
1181 ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);
1182
1183 if (ivar_offset_address != LLDB_INVALID_ADDRESS)
1184 ivar_offset = m_process->ReadUnsignedIntegerFromMemory(
1185 ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error);
1186 }
1187 return ivar_offset;
1188 }
1189
1190 // tagged pointers are special not-a-real-pointer values that contain both type
1191 // and value information this routine attempts to check with as little
1192 // computational effort as possible whether something could possibly be a
1193 // tagged pointer - false positives are possible but false negatives shouldn't
IsTaggedPointer(addr_t ptr)1194 bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) {
1195 if (!m_tagged_pointer_vendor_up)
1196 return false;
1197 return m_tagged_pointer_vendor_up->IsPossibleTaggedPointer(ptr);
1198 }
1199
1200 class RemoteNXMapTable {
1201 public:
RemoteNXMapTable()1202 RemoteNXMapTable() : m_end_iterator(*this, -1) {}
1203
Dump()1204 void Dump() {
1205 printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);
1206 printf("RemoteNXMapTable.m_count = %u\n", m_count);
1207 printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n",
1208 m_num_buckets_minus_one);
1209 printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);
1210 }
1211
ParseHeader(Process * process,lldb::addr_t load_addr)1212 bool ParseHeader(Process *process, lldb::addr_t load_addr) {
1213 m_process = process;
1214 m_load_addr = load_addr;
1215 m_map_pair_size = m_process->GetAddressByteSize() * 2;
1216 m_invalid_key =
1217 m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
1218 Status err;
1219
1220 // This currently holds true for all platforms we support, but we might
1221 // need to change this to use get the actually byte size of "unsigned" from
1222 // the target AST...
1223 const uint32_t unsigned_byte_size = sizeof(uint32_t);
1224 // Skip the prototype as we don't need it (const struct
1225 // +NXMapTablePrototype *prototype)
1226
1227 bool success = true;
1228 if (load_addr == LLDB_INVALID_ADDRESS)
1229 success = false;
1230 else {
1231 lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();
1232
1233 // unsigned count;
1234 m_count = m_process->ReadUnsignedIntegerFromMemory(
1235 cursor, unsigned_byte_size, 0, err);
1236 if (m_count) {
1237 cursor += unsigned_byte_size;
1238
1239 // unsigned nbBucketsMinusOne;
1240 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(
1241 cursor, unsigned_byte_size, 0, err);
1242 cursor += unsigned_byte_size;
1243
1244 // void *buckets;
1245 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);
1246
1247 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;
1248 }
1249 }
1250
1251 if (!success) {
1252 m_count = 0;
1253 m_num_buckets_minus_one = 0;
1254 m_buckets_ptr = LLDB_INVALID_ADDRESS;
1255 }
1256 return success;
1257 }
1258
1259 // const_iterator mimics NXMapState and its code comes from NXInitMapState
1260 // and NXNextMapState.
1261 typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;
1262
1263 friend class const_iterator;
1264 class const_iterator {
1265 public:
const_iterator(RemoteNXMapTable & parent,int index)1266 const_iterator(RemoteNXMapTable &parent, int index)
1267 : m_parent(parent), m_index(index) {
1268 AdvanceToValidIndex();
1269 }
1270
const_iterator(const const_iterator & rhs)1271 const_iterator(const const_iterator &rhs)
1272 : m_parent(rhs.m_parent), m_index(rhs.m_index) {
1273 // AdvanceToValidIndex() has been called by rhs already.
1274 }
1275
operator =(const const_iterator & rhs)1276 const_iterator &operator=(const const_iterator &rhs) {
1277 // AdvanceToValidIndex() has been called by rhs already.
1278 assert(&m_parent == &rhs.m_parent);
1279 m_index = rhs.m_index;
1280 return *this;
1281 }
1282
operator ==(const const_iterator & rhs) const1283 bool operator==(const const_iterator &rhs) const {
1284 if (&m_parent != &rhs.m_parent)
1285 return false;
1286 if (m_index != rhs.m_index)
1287 return false;
1288
1289 return true;
1290 }
1291
operator !=(const const_iterator & rhs) const1292 bool operator!=(const const_iterator &rhs) const {
1293 return !(operator==(rhs));
1294 }
1295
operator ++()1296 const_iterator &operator++() {
1297 AdvanceToValidIndex();
1298 return *this;
1299 }
1300
operator *() const1301 const element operator*() const {
1302 if (m_index == -1) {
1303 // TODO find a way to make this an error, but not an assert
1304 return element();
1305 }
1306
1307 lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1308 size_t map_pair_size = m_parent.m_map_pair_size;
1309 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1310
1311 Status err;
1312
1313 lldb::addr_t key =
1314 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1315 if (!err.Success())
1316 return element();
1317 lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(
1318 pair_ptr + m_parent.m_process->GetAddressByteSize(), err);
1319 if (!err.Success())
1320 return element();
1321
1322 std::string key_string;
1323
1324 m_parent.m_process->ReadCStringFromMemory(key, key_string, err);
1325 if (!err.Success())
1326 return element();
1327
1328 return element(ConstString(key_string.c_str()),
1329 (ObjCLanguageRuntime::ObjCISA)value);
1330 }
1331
1332 private:
AdvanceToValidIndex()1333 void AdvanceToValidIndex() {
1334 if (m_index == -1)
1335 return;
1336
1337 const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1338 const size_t map_pair_size = m_parent.m_map_pair_size;
1339 const lldb::addr_t invalid_key = m_parent.m_invalid_key;
1340 Status err;
1341
1342 while (m_index--) {
1343 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1344 lldb::addr_t key =
1345 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1346
1347 if (!err.Success()) {
1348 m_index = -1;
1349 return;
1350 }
1351
1352 if (key != invalid_key)
1353 return;
1354 }
1355 }
1356 RemoteNXMapTable &m_parent;
1357 int m_index;
1358 };
1359
begin()1360 const_iterator begin() {
1361 return const_iterator(*this, m_num_buckets_minus_one + 1);
1362 }
1363
end()1364 const_iterator end() { return m_end_iterator; }
1365
GetCount() const1366 uint32_t GetCount() const { return m_count; }
1367
GetBucketCount() const1368 uint32_t GetBucketCount() const { return m_num_buckets_minus_one; }
1369
GetBucketDataPointer() const1370 lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; }
1371
GetTableLoadAddress() const1372 lldb::addr_t GetTableLoadAddress() const { return m_load_addr; }
1373
1374 private:
1375 // contents of _NXMapTable struct
1376 uint32_t m_count = 0;
1377 uint32_t m_num_buckets_minus_one = 0;
1378 lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS;
1379 lldb_private::Process *m_process = nullptr;
1380 const_iterator m_end_iterator;
1381 lldb::addr_t m_load_addr = LLDB_INVALID_ADDRESS;
1382 size_t m_map_pair_size = 0;
1383 lldb::addr_t m_invalid_key = 0;
1384 };
1385
1386 AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() = default;
1387
UpdateSignature(const RemoteNXMapTable & hash_table)1388 void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature(
1389 const RemoteNXMapTable &hash_table) {
1390 m_count = hash_table.GetCount();
1391 m_num_buckets = hash_table.GetBucketCount();
1392 m_buckets_ptr = hash_table.GetBucketDataPointer();
1393 }
1394
NeedsUpdate(Process * process,AppleObjCRuntimeV2 * runtime,RemoteNXMapTable & hash_table)1395 bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate(
1396 Process *process, AppleObjCRuntimeV2 *runtime,
1397 RemoteNXMapTable &hash_table) {
1398 if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) {
1399 return false; // Failed to parse the header, no need to update anything
1400 }
1401
1402 // Check with out current signature and return true if the count, number of
1403 // buckets or the hash table address changes.
1404 if (m_count == hash_table.GetCount() &&
1405 m_num_buckets == hash_table.GetBucketCount() &&
1406 m_buckets_ptr == hash_table.GetBucketDataPointer()) {
1407 // Hash table hasn't changed
1408 return false;
1409 }
1410 // Hash table data has changed, we need to update
1411 return true;
1412 }
1413
1414 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptorFromISA(ObjCISA isa)1415 AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {
1416 ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
1417 if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())
1418 class_descriptor_sp = non_pointer_isa_cache->GetClassDescriptor(isa);
1419 if (!class_descriptor_sp)
1420 class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
1421 return class_descriptor_sp;
1422 }
1423
1424 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ValueObject & valobj)1425 AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
1426 ClassDescriptorSP objc_class_sp;
1427 if (valobj.IsBaseClass()) {
1428 ValueObject *parent = valobj.GetParent();
1429 // if I am my own parent, bail out of here fast..
1430 if (parent && parent != &valobj) {
1431 ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
1432 if (parent_descriptor_sp)
1433 return parent_descriptor_sp->GetSuperclass();
1434 }
1435 return nullptr;
1436 }
1437 // if we get an invalid VO (which might still happen when playing around with
1438 // pointers returned by the expression parser, don't consider this a valid
1439 // ObjC object)
1440 if (!valobj.GetCompilerType().IsValid())
1441 return objc_class_sp;
1442 addr_t isa_pointer = valobj.GetPointerValue();
1443
1444 // tagged pointer
1445 if (IsTaggedPointer(isa_pointer))
1446 return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer);
1447 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1448
1449 Process *process = exe_ctx.GetProcessPtr();
1450 if (!process)
1451 return objc_class_sp;
1452
1453 Status error;
1454 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
1455 if (isa == LLDB_INVALID_ADDRESS)
1456 return objc_class_sp;
1457
1458 objc_class_sp = GetClassDescriptorFromISA(isa);
1459 if (isa && !objc_class_sp) {
1460 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1461 LLDB_LOGF(log,
1462 "0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was "
1463 "not in class descriptor cache 0x%" PRIx64,
1464 isa_pointer, isa);
1465 }
1466 return objc_class_sp;
1467 }
1468
GetTaggedPointerObfuscator()1469 lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() {
1470 if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS)
1471 return m_tagged_pointer_obfuscator;
1472
1473 Process *process = GetProcess();
1474 ModuleSP objc_module_sp(GetObjCModule());
1475
1476 if (!objc_module_sp)
1477 return LLDB_INVALID_ADDRESS;
1478
1479 static ConstString g_gdb_objc_obfuscator(
1480 "objc_debug_taggedpointer_obfuscator");
1481
1482 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
1483 g_gdb_objc_obfuscator, lldb::eSymbolTypeAny);
1484 if (symbol) {
1485 lldb::addr_t g_gdb_obj_obfuscator_ptr =
1486 symbol->GetLoadAddress(&process->GetTarget());
1487
1488 if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) {
1489 Status error;
1490 m_tagged_pointer_obfuscator =
1491 process->ReadPointerFromMemory(g_gdb_obj_obfuscator_ptr, error);
1492 }
1493 }
1494 // If we don't have a correct value at this point, there must be no
1495 // obfuscation.
1496 if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS)
1497 m_tagged_pointer_obfuscator = 0;
1498
1499 return m_tagged_pointer_obfuscator;
1500 }
1501
GetISAHashTablePointer()1502 lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {
1503 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
1504 Process *process = GetProcess();
1505
1506 ModuleSP objc_module_sp(GetObjCModule());
1507
1508 if (!objc_module_sp)
1509 return LLDB_INVALID_ADDRESS;
1510
1511 static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");
1512
1513 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
1514 g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);
1515 if (symbol) {
1516 lldb::addr_t gdb_objc_realized_classes_ptr =
1517 symbol->GetLoadAddress(&process->GetTarget());
1518
1519 if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {
1520 Status error;
1521 m_isa_hash_table_ptr = process->ReadPointerFromMemory(
1522 gdb_objc_realized_classes_ptr, error);
1523 }
1524 }
1525 }
1526 return m_isa_hash_table_ptr;
1527 }
1528
1529 std::unique_ptr<UtilityFunction>
GetClassInfoUtilityFunctionImpl(ExecutionContext & exe_ctx,std::string code,std::string name)1530 AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(
1531 ExecutionContext &exe_ctx, std::string code, std::string name) {
1532 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1533
1534 LLDB_LOG(log, "Creating utility function {0}", name);
1535
1536 TypeSystemClang *ast =
1537 ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());
1538 if (!ast)
1539 return {};
1540
1541 auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
1542 std::move(code), std::move(name), eLanguageTypeC, exe_ctx);
1543 if (!utility_fn_or_error) {
1544 LLDB_LOG_ERROR(
1545 log, utility_fn_or_error.takeError(),
1546 "Failed to get utility function for implementation lookup: {0}");
1547 return {};
1548 }
1549
1550 // Make some types for our arguments.
1551 CompilerType clang_uint32_t_type =
1552 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1553 CompilerType clang_void_pointer_type =
1554 ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1555
1556 // Make the runner function for our implementation utility function.
1557 ValueList arguments;
1558 Value value;
1559 value.SetValueType(Value::ValueType::Scalar);
1560 value.SetCompilerType(clang_void_pointer_type);
1561 arguments.PushValue(value);
1562 arguments.PushValue(value);
1563 value.SetValueType(Value::ValueType::Scalar);
1564 value.SetCompilerType(clang_uint32_t_type);
1565 arguments.PushValue(value);
1566 arguments.PushValue(value);
1567
1568 std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
1569
1570 Status error;
1571 utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,
1572 exe_ctx.GetThreadSP(), error);
1573
1574 if (error.Fail()) {
1575 LLDB_LOG(log,
1576 "Failed to make function caller for implementation lookup: {0}.",
1577 error.AsCString());
1578 return {};
1579 }
1580
1581 return utility_fn;
1582 }
1583
1584 UtilityFunction *
GetClassInfoUtilityFunction(ExecutionContext & exe_ctx,Helper helper)1585 AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunction(
1586 ExecutionContext &exe_ctx, Helper helper) {
1587 switch (helper) {
1588 case gdb_objc_realized_classes: {
1589 if (!m_gdb_objc_realized_classes_helper.utility_function)
1590 m_gdb_objc_realized_classes_helper.utility_function =
1591 GetClassInfoUtilityFunctionImpl(exe_ctx,
1592 g_get_dynamic_class_info_body,
1593 g_get_dynamic_class_info_name);
1594 return m_gdb_objc_realized_classes_helper.utility_function.get();
1595 }
1596 case objc_copyRealizedClassList: {
1597 if (!m_objc_copyRealizedClassList_helper.utility_function)
1598 m_objc_copyRealizedClassList_helper.utility_function =
1599 GetClassInfoUtilityFunctionImpl(exe_ctx,
1600 g_get_dynamic_class_info2_body,
1601 g_get_dynamic_class_info2_name);
1602 return m_objc_copyRealizedClassList_helper.utility_function.get();
1603 }
1604 }
1605 llvm_unreachable("Unexpected helper");
1606 }
1607
1608 lldb::addr_t &
GetClassInfoArgs(Helper helper)1609 AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) {
1610 switch (helper) {
1611 case gdb_objc_realized_classes:
1612 return m_gdb_objc_realized_classes_helper.args;
1613 case objc_copyRealizedClassList:
1614 return m_objc_copyRealizedClassList_helper.args;
1615 }
1616 llvm_unreachable("Unexpected helper");
1617 }
1618
1619 AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper
ComputeHelper() const1620 AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper() const {
1621 if (!m_runtime.m_has_objc_copyRealizedClassList)
1622 return DynamicClassInfoExtractor::gdb_objc_realized_classes;
1623
1624 if (Process *process = m_runtime.GetProcess()) {
1625 if (DynamicLoader *loader = process->GetDynamicLoader()) {
1626 if (loader->IsFullyInitialized())
1627 return DynamicClassInfoExtractor::objc_copyRealizedClassList;
1628 }
1629 }
1630
1631 return DynamicClassInfoExtractor::gdb_objc_realized_classes;
1632 }
1633
1634 std::unique_ptr<UtilityFunction>
1635 AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
GetClassInfoUtilityFunctionImpl(ExecutionContext & exe_ctx)1636 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) {
1637 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1638
1639 LLDB_LOG(log, "Creating utility function {0}",
1640 g_get_shared_cache_class_info_name);
1641
1642 TypeSystemClang *ast =
1643 ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());
1644 if (!ast)
1645 return {};
1646
1647 // If the inferior objc.dylib has the class_getNameRaw function, use that in
1648 // our jitted expression. Else fall back to the old class_getName.
1649 static ConstString g_class_getName_symbol_name("class_getName");
1650 static ConstString g_class_getNameRaw_symbol_name(
1651 "objc_debug_class_getNameRaw");
1652
1653 ConstString class_name_getter_function_name =
1654 m_runtime.HasSymbol(g_class_getNameRaw_symbol_name)
1655 ? g_class_getNameRaw_symbol_name
1656 : g_class_getName_symbol_name;
1657
1658 // Substitute in the correct class_getName / class_getNameRaw function name,
1659 // concatenate the two parts of our expression text. The format string has
1660 // two %s's, so provide the name twice.
1661 std::string shared_class_expression;
1662 llvm::raw_string_ostream(shared_class_expression)
1663 << llvm::format(g_shared_cache_class_name_funcptr,
1664 class_name_getter_function_name.AsCString(),
1665 class_name_getter_function_name.AsCString());
1666
1667 shared_class_expression += g_get_shared_cache_class_info_body;
1668
1669 auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
1670 std::move(shared_class_expression), g_get_shared_cache_class_info_name,
1671 eLanguageTypeC, exe_ctx);
1672
1673 if (!utility_fn_or_error) {
1674 LLDB_LOG_ERROR(
1675 log, utility_fn_or_error.takeError(),
1676 "Failed to get utility function for implementation lookup: {0}");
1677 return nullptr;
1678 }
1679
1680 // Make some types for our arguments.
1681 CompilerType clang_uint32_t_type =
1682 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1683 CompilerType clang_void_pointer_type =
1684 ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1685 CompilerType clang_uint64_t_pointer_type =
1686 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)
1687 .GetPointerType();
1688
1689 // Next make the function caller for our implementation utility function.
1690 ValueList arguments;
1691 Value value;
1692 value.SetValueType(Value::ValueType::Scalar);
1693 value.SetCompilerType(clang_void_pointer_type);
1694 arguments.PushValue(value);
1695 arguments.PushValue(value);
1696 arguments.PushValue(value);
1697
1698 value.SetValueType(Value::ValueType::Scalar);
1699 value.SetCompilerType(clang_uint64_t_pointer_type);
1700 arguments.PushValue(value);
1701
1702 value.SetValueType(Value::ValueType::Scalar);
1703 value.SetCompilerType(clang_uint32_t_type);
1704 arguments.PushValue(value);
1705 arguments.PushValue(value);
1706
1707 std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
1708
1709 Status error;
1710 utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,
1711 exe_ctx.GetThreadSP(), error);
1712
1713 if (error.Fail()) {
1714 LLDB_LOG(log,
1715 "Failed to make function caller for implementation lookup: {0}.",
1716 error.AsCString());
1717 return {};
1718 }
1719
1720 return utility_fn;
1721 }
1722
1723 UtilityFunction *
GetClassInfoUtilityFunction(ExecutionContext & exe_ctx)1724 AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction(
1725 ExecutionContext &exe_ctx) {
1726 if (!m_utility_function)
1727 m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx);
1728 return m_utility_function.get();
1729 }
1730
1731 AppleObjCRuntimeV2::DescriptorMapUpdateResult
UpdateISAToDescriptorMap(RemoteNXMapTable & hash_table)1732 AppleObjCRuntimeV2::DynamicClassInfoExtractor::UpdateISAToDescriptorMap(
1733 RemoteNXMapTable &hash_table) {
1734 Process *process = m_runtime.GetProcess();
1735 if (process == nullptr)
1736 return DescriptorMapUpdateResult::Fail();
1737
1738 uint32_t num_class_infos = 0;
1739
1740 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1741
1742 ExecutionContext exe_ctx;
1743
1744 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1745
1746 if (!thread_sp)
1747 return DescriptorMapUpdateResult::Fail();
1748
1749 thread_sp->CalculateExecutionContext(exe_ctx);
1750 TypeSystemClang *ast =
1751 ScratchTypeSystemClang::GetForTarget(process->GetTarget());
1752
1753 if (!ast)
1754 return DescriptorMapUpdateResult::Fail();
1755
1756 Address function_address;
1757
1758 const uint32_t addr_size = process->GetAddressByteSize();
1759
1760 Status err;
1761
1762 // Compute which helper we're going to use for this update.
1763 const DynamicClassInfoExtractor::Helper helper = ComputeHelper();
1764
1765 // Read the total number of classes from the hash table
1766 const uint32_t num_classes =
1767 helper == DynamicClassInfoExtractor::gdb_objc_realized_classes
1768 ? hash_table.GetCount()
1769 : m_runtime.m_realized_class_generation_count;
1770 if (num_classes == 0) {
1771 LLDB_LOGF(log, "No dynamic classes found.");
1772 return DescriptorMapUpdateResult::Success(0);
1773 }
1774
1775 UtilityFunction *get_class_info_code =
1776 GetClassInfoUtilityFunction(exe_ctx, helper);
1777 if (!get_class_info_code) {
1778 // The callee will have already logged a useful error message.
1779 return DescriptorMapUpdateResult::Fail();
1780 }
1781
1782 FunctionCaller *get_class_info_function =
1783 get_class_info_code->GetFunctionCaller();
1784
1785 if (!get_class_info_function) {
1786 LLDB_LOGF(log, "Failed to get implementation lookup function caller.");
1787 return DescriptorMapUpdateResult::Fail();
1788 }
1789
1790 ValueList arguments = get_class_info_function->GetArgumentValues();
1791
1792 DiagnosticManager diagnostics;
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(
1797 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
1798
1799 if (class_infos_addr == LLDB_INVALID_ADDRESS) {
1800 LLDB_LOGF(log,
1801 "unable to allocate %" PRIu32
1802 " bytes in process for shared cache read",
1803 class_infos_byte_size);
1804 return DescriptorMapUpdateResult::Fail();
1805 }
1806
1807 std::lock_guard<std::mutex> guard(m_mutex);
1808
1809 // Fill in our function argument values
1810 arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
1811 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1812 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1813
1814 // Only dump the runtime classes from the expression evaluation if the log is
1815 // verbose:
1816 Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES);
1817 bool dump_log = type_log && type_log->GetVerbose();
1818
1819 arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0;
1820
1821 bool success = false;
1822
1823 diagnostics.Clear();
1824
1825 // Write our function arguments into the process so we can run our function
1826 if (get_class_info_function->WriteFunctionArguments(
1827 exe_ctx, GetClassInfoArgs(helper), arguments, diagnostics)) {
1828 EvaluateExpressionOptions options;
1829 options.SetUnwindOnError(true);
1830 options.SetTryAllThreads(false);
1831 options.SetStopOthers(true);
1832 options.SetIgnoreBreakpoints(true);
1833 options.SetTimeout(process->GetUtilityExpressionTimeout());
1834 options.SetIsForUtilityExpr(true);
1835
1836 CompilerType clang_uint32_t_type =
1837 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1838
1839 Value return_value;
1840 return_value.SetValueType(Value::ValueType::Scalar);
1841 return_value.SetCompilerType(clang_uint32_t_type);
1842 return_value.GetScalar() = 0;
1843
1844 diagnostics.Clear();
1845
1846 // Run the function
1847 ExpressionResults results = get_class_info_function->ExecuteFunction(
1848 exe_ctx, &GetClassInfoArgs(helper), options, diagnostics, return_value);
1849
1850 if (results == eExpressionCompleted) {
1851 // The result is the number of ClassInfo structures that were filled in
1852 num_class_infos = return_value.GetScalar().ULong();
1853 LLDB_LOG(log, "Discovered {0} Objective-C classes", num_class_infos);
1854 if (num_class_infos > 0) {
1855 // Read the ClassInfo structures
1856 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);
1857 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),
1858 buffer.GetByteSize(),
1859 err) == buffer.GetByteSize()) {
1860 DataExtractor class_infos_data(buffer.GetBytes(),
1861 buffer.GetByteSize(),
1862 process->GetByteOrder(), addr_size);
1863 m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
1864 }
1865 }
1866 success = true;
1867 } else {
1868 if (log) {
1869 LLDB_LOGF(log, "Error evaluating our find class name function.");
1870 diagnostics.Dump(log);
1871 }
1872 }
1873 } else {
1874 if (log) {
1875 LLDB_LOGF(log, "Error writing function arguments.");
1876 diagnostics.Dump(log);
1877 }
1878 }
1879
1880 // Deallocate the memory we allocated for the ClassInfo array
1881 process->DeallocateMemory(class_infos_addr);
1882
1883 return DescriptorMapUpdateResult(success, num_class_infos);
1884 }
1885
ParseClassInfoArray(const DataExtractor & data,uint32_t num_class_infos)1886 uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,
1887 uint32_t num_class_infos) {
1888 // Parses an array of "num_class_infos" packed ClassInfo structures:
1889 //
1890 // struct ClassInfo
1891 // {
1892 // Class isa;
1893 // uint32_t hash;
1894 // } __attribute__((__packed__));
1895
1896 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
1897 bool should_log = log && log->GetVerbose();
1898
1899 uint32_t num_parsed = 0;
1900
1901 // Iterate through all ClassInfo structures
1902 lldb::offset_t offset = 0;
1903 for (uint32_t i = 0; i < num_class_infos; ++i) {
1904 ObjCISA isa = data.GetAddress(&offset);
1905
1906 if (isa == 0) {
1907 if (should_log)
1908 LLDB_LOGF(
1909 log, "AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
1910 continue;
1911 }
1912 // Check if we already know about this ISA, if we do, the info will never
1913 // change, so we can just skip it.
1914 if (ISAIsCached(isa)) {
1915 if (should_log)
1916 LLDB_LOGF(log,
1917 "AppleObjCRuntimeV2 found cached isa=0x%" PRIx64
1918 ", ignoring this class info",
1919 isa);
1920 offset += 4;
1921 } else {
1922 // Read the 32 bit hash for the class name
1923 const uint32_t name_hash = data.GetU32(&offset);
1924 ClassDescriptorSP descriptor_sp(
1925 new ClassDescriptorV2(*this, isa, nullptr));
1926
1927 // The code in g_get_shared_cache_class_info_body sets the value of the
1928 // hash to 0 to signal a demangled symbol. We use class_getName() in that
1929 // code to find the class name, but this returns a demangled name for
1930 // Swift symbols. For those symbols, recompute the hash here by reading
1931 // their name from the runtime.
1932 if (name_hash)
1933 AddClass(isa, descriptor_sp, name_hash);
1934 else
1935 AddClass(isa, descriptor_sp,
1936 descriptor_sp->GetClassName().AsCString(nullptr));
1937 num_parsed++;
1938 if (should_log)
1939 LLDB_LOGF(log,
1940 "AppleObjCRuntimeV2 added isa=0x%" PRIx64
1941 ", hash=0x%8.8x, name=%s",
1942 isa, name_hash,
1943 descriptor_sp->GetClassName().AsCString("<unknown>"));
1944 }
1945 }
1946 if (should_log)
1947 LLDB_LOGF(log, "AppleObjCRuntimeV2 parsed %" PRIu32 " class infos",
1948 num_parsed);
1949 return num_parsed;
1950 }
1951
HasSymbol(ConstString Name)1952 bool AppleObjCRuntimeV2::HasSymbol(ConstString Name) {
1953 if (!m_objc_module_sp)
1954 return false;
1955 if (const Symbol *symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(
1956 Name, lldb::eSymbolTypeCode)) {
1957 if (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())
1958 return true;
1959 }
1960 return false;
1961 }
1962
1963 AppleObjCRuntimeV2::DescriptorMapUpdateResult
UpdateISAToDescriptorMap()1964 AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
1965 Process *process = m_runtime.GetProcess();
1966 if (process == nullptr)
1967 return DescriptorMapUpdateResult::Fail();
1968
1969 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1970
1971 ExecutionContext exe_ctx;
1972
1973 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1974
1975 if (!thread_sp)
1976 return DescriptorMapUpdateResult::Fail();
1977
1978 thread_sp->CalculateExecutionContext(exe_ctx);
1979 TypeSystemClang *ast =
1980 ScratchTypeSystemClang::GetForTarget(process->GetTarget());
1981
1982 if (!ast)
1983 return DescriptorMapUpdateResult::Fail();
1984
1985 Address function_address;
1986
1987 const uint32_t addr_size = process->GetAddressByteSize();
1988
1989 Status err;
1990
1991 uint32_t num_class_infos = 0;
1992
1993 const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress();
1994 const lldb::addr_t shared_cache_base_addr =
1995 m_runtime.GetSharedCacheBaseAddress();
1996
1997 if (objc_opt_ptr == LLDB_INVALID_ADDRESS ||
1998 shared_cache_base_addr == LLDB_INVALID_ADDRESS)
1999 return DescriptorMapUpdateResult::Fail();
2000
2001 const uint32_t num_classes = 128 * 1024;
2002
2003 UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);
2004 FunctionCaller *get_shared_cache_class_info_function =
2005 get_class_info_code->GetFunctionCaller();
2006
2007 if (!get_shared_cache_class_info_function) {
2008 LLDB_LOGF(log, "Failed to get implementation lookup function caller.");
2009 return DescriptorMapUpdateResult::Fail();
2010 }
2011
2012 ValueList arguments =
2013 get_shared_cache_class_info_function->GetArgumentValues();
2014
2015 DiagnosticManager diagnostics;
2016
2017 const uint32_t class_info_byte_size = addr_size + 4;
2018 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
2019 lldb::addr_t class_infos_addr = process->AllocateMemory(
2020 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
2021 const uint32_t relative_selector_offset_addr_size = 64;
2022 lldb::addr_t relative_selector_offset_addr =
2023 process->AllocateMemory(relative_selector_offset_addr_size,
2024 ePermissionsReadable | ePermissionsWritable, err);
2025
2026 if (class_infos_addr == LLDB_INVALID_ADDRESS) {
2027 LLDB_LOGF(log,
2028 "unable to allocate %" PRIu32
2029 " bytes in process for shared cache read",
2030 class_infos_byte_size);
2031 return DescriptorMapUpdateResult::Fail();
2032 }
2033
2034 std::lock_guard<std::mutex> guard(m_mutex);
2035
2036 // Fill in our function argument values
2037 arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
2038 arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr;
2039 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;
2040 arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;
2041 arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;
2042 // Only dump the runtime classes from the expression evaluation if the log is
2043 // verbose:
2044 Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES);
2045 bool dump_log = type_log && type_log->GetVerbose();
2046
2047 arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;
2048
2049 bool success = false;
2050
2051 diagnostics.Clear();
2052
2053 // Write our function arguments into the process so we can run our function
2054 if (get_shared_cache_class_info_function->WriteFunctionArguments(
2055 exe_ctx, m_args, arguments, diagnostics)) {
2056 EvaluateExpressionOptions options;
2057 options.SetUnwindOnError(true);
2058 options.SetTryAllThreads(false);
2059 options.SetStopOthers(true);
2060 options.SetIgnoreBreakpoints(true);
2061 options.SetTimeout(process->GetUtilityExpressionTimeout());
2062 options.SetIsForUtilityExpr(true);
2063
2064 CompilerType clang_uint32_t_type =
2065 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
2066
2067 Value return_value;
2068 return_value.SetValueType(Value::ValueType::Scalar);
2069 return_value.SetCompilerType(clang_uint32_t_type);
2070 return_value.GetScalar() = 0;
2071
2072 diagnostics.Clear();
2073
2074 // Run the function
2075 ExpressionResults results =
2076 get_shared_cache_class_info_function->ExecuteFunction(
2077 exe_ctx, &m_args, options, diagnostics, return_value);
2078
2079 if (results == eExpressionCompleted) {
2080 // The result is the number of ClassInfo structures that were filled in
2081 num_class_infos = return_value.GetScalar().ULong();
2082 LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
2083 num_class_infos);
2084 assert(num_class_infos <= num_classes);
2085 if (num_class_infos > 0) {
2086 if (num_class_infos > num_classes) {
2087 num_class_infos = num_classes;
2088
2089 success = false;
2090 } else {
2091 success = true;
2092 }
2093
2094 // Read the relative selector offset.
2095 DataBufferHeap relative_selector_offset_buffer(64, 0);
2096 if (process->ReadMemory(relative_selector_offset_addr,
2097 relative_selector_offset_buffer.GetBytes(),
2098 relative_selector_offset_buffer.GetByteSize(),
2099 err) ==
2100 relative_selector_offset_buffer.GetByteSize()) {
2101 DataExtractor relative_selector_offset_data(
2102 relative_selector_offset_buffer.GetBytes(),
2103 relative_selector_offset_buffer.GetByteSize(),
2104 process->GetByteOrder(), addr_size);
2105 lldb::offset_t offset = 0;
2106 uint64_t relative_selector_offset =
2107 relative_selector_offset_data.GetU64(&offset);
2108 if (relative_selector_offset > 0) {
2109 // The offset is relative to the objc_opt struct.
2110 m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
2111 relative_selector_offset);
2112 }
2113 }
2114
2115 // Read the ClassInfo structures
2116 DataBufferHeap class_infos_buffer(
2117 num_class_infos * class_info_byte_size, 0);
2118 if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),
2119 class_infos_buffer.GetByteSize(),
2120 err) == class_infos_buffer.GetByteSize()) {
2121 DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
2122 class_infos_buffer.GetByteSize(),
2123 process->GetByteOrder(), addr_size);
2124
2125 m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
2126 }
2127 } else {
2128 success = true;
2129 }
2130 } else {
2131 if (log) {
2132 LLDB_LOGF(log, "Error evaluating our find class name function.");
2133 diagnostics.Dump(log);
2134 }
2135 }
2136 } else {
2137 if (log) {
2138 LLDB_LOGF(log, "Error writing function arguments.");
2139 diagnostics.Dump(log);
2140 }
2141 }
2142
2143 // Deallocate the memory we allocated for the ClassInfo array
2144 process->DeallocateMemory(class_infos_addr);
2145
2146 return DescriptorMapUpdateResult(success, num_class_infos);
2147 }
2148
GetSharedCacheReadOnlyAddress()2149 lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
2150 Process *process = GetProcess();
2151
2152 if (process) {
2153 ModuleSP objc_module_sp(GetObjCModule());
2154
2155 if (objc_module_sp) {
2156 ObjectFile *objc_object = objc_module_sp->GetObjectFile();
2157
2158 if (objc_object) {
2159 SectionList *section_list = objc_module_sp->GetSectionList();
2160
2161 if (section_list) {
2162 SectionSP text_segment_sp(
2163 section_list->FindSectionByName(ConstString("__TEXT")));
2164
2165 if (text_segment_sp) {
2166 SectionSP objc_opt_section_sp(
2167 text_segment_sp->GetChildren().FindSectionByName(
2168 ConstString("__objc_opt_ro")));
2169
2170 if (objc_opt_section_sp) {
2171 return objc_opt_section_sp->GetLoadBaseAddress(
2172 &process->GetTarget());
2173 }
2174 }
2175 }
2176 }
2177 }
2178 }
2179 return LLDB_INVALID_ADDRESS;
2180 }
2181
GetSharedCacheBaseAddress()2182 lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() {
2183 StructuredData::ObjectSP info = m_process->GetSharedCacheInfo();
2184 if (!info)
2185 return LLDB_INVALID_ADDRESS;
2186
2187 StructuredData::Dictionary *info_dict = info->GetAsDictionary();
2188 if (!info_dict)
2189 return LLDB_INVALID_ADDRESS;
2190
2191 return info_dict->GetValueForKey("shared_cache_base_address")
2192 ->GetIntegerValue(LLDB_INVALID_ADDRESS);
2193 }
2194
UpdateISAToDescriptorMapIfNeeded()2195 void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {
2196 LLDB_SCOPED_TIMER();
2197
2198 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
2199
2200 // Else we need to check with our process to see when the map was updated.
2201 Process *process = GetProcess();
2202
2203 if (process) {
2204 RemoteNXMapTable hash_table;
2205
2206 // Update the process stop ID that indicates the last time we updated the
2207 // map, whether it was successful or not.
2208 m_isa_to_descriptor_stop_id = process->GetStopID();
2209
2210 // Ask the runtime is the realized class generation count changed. Unlike
2211 // the hash table, this accounts for lazily named classes.
2212 const bool class_count_changed = RealizedClassGenerationCountChanged();
2213
2214 if (!m_hash_signature.NeedsUpdate(process, this, hash_table) &&
2215 !class_count_changed)
2216 return;
2217
2218 m_hash_signature.UpdateSignature(hash_table);
2219
2220 // Grab the dynamically loaded Objective-C classes from memory.
2221 DescriptorMapUpdateResult dynamic_update_result =
2222 m_dynamic_class_info_extractor.UpdateISAToDescriptorMap(hash_table);
2223
2224 // Now get the objc classes that are baked into the Objective-C runtime in
2225 // the shared cache, but only once per process as this data never changes
2226 if (!m_loaded_objc_opt) {
2227 // it is legitimately possible for the shared cache to be empty - in that
2228 // case, the dynamic hash table will contain all the class information we
2229 // need; the situation we're trying to detect is one where we aren't
2230 // seeing class information from the runtime - in order to detect that
2231 // vs. just the shared cache being empty or sparsely populated, we set an
2232 // arbitrary (very low) threshold for the number of classes that we want
2233 // to see in a "good" scenario - anything below that is suspicious
2234 // (Foundation alone has thousands of classes)
2235 const uint32_t num_classes_to_warn_at = 500;
2236
2237 DescriptorMapUpdateResult shared_cache_update_result =
2238 m_shared_cache_class_info_extractor.UpdateISAToDescriptorMap();
2239
2240 LLDB_LOGF(log,
2241 "attempted to read objc class data - results: "
2242 "[dynamic_update]: ran: %s, count: %" PRIu32
2243 " [shared_cache_update]: ran: %s, count: %" PRIu32,
2244 dynamic_update_result.m_update_ran ? "yes" : "no",
2245 dynamic_update_result.m_num_found,
2246 shared_cache_update_result.m_update_ran ? "yes" : "no",
2247 shared_cache_update_result.m_num_found);
2248
2249 // warn if:
2250 // - we could not run either expression
2251 // - we found fewer than num_classes_to_warn_at classes total
2252 if ((!shared_cache_update_result.m_update_ran) ||
2253 (!dynamic_update_result.m_update_ran))
2254 WarnIfNoClassesCached(
2255 SharedCacheWarningReason::eExpressionExecutionFailure);
2256 else if (dynamic_update_result.m_num_found +
2257 shared_cache_update_result.m_num_found <
2258 num_classes_to_warn_at)
2259 WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead);
2260 else
2261 m_loaded_objc_opt = true;
2262 }
2263 } else {
2264 m_isa_to_descriptor_stop_id = UINT32_MAX;
2265 }
2266 }
2267
RealizedClassGenerationCountChanged()2268 bool AppleObjCRuntimeV2::RealizedClassGenerationCountChanged() {
2269 Process *process = GetProcess();
2270 if (!process)
2271 return false;
2272
2273 Status error;
2274 uint64_t objc_debug_realized_class_generation_count =
2275 ExtractRuntimeGlobalSymbol(
2276 process, ConstString("objc_debug_realized_class_generation_count"),
2277 GetObjCModule(), error);
2278 if (error.Fail())
2279 return false;
2280
2281 if (m_realized_class_generation_count ==
2282 objc_debug_realized_class_generation_count)
2283 return false;
2284
2285 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
2286 LLDB_LOG(log,
2287 "objc_debug_realized_class_generation_count changed from {0} to {1}",
2288 m_realized_class_generation_count,
2289 objc_debug_realized_class_generation_count);
2290
2291 m_realized_class_generation_count =
2292 objc_debug_realized_class_generation_count;
2293
2294 return true;
2295 }
2296
DoesProcessHaveSharedCache(Process & process)2297 static bool DoesProcessHaveSharedCache(Process &process) {
2298 PlatformSP platform_sp = process.GetTarget().GetPlatform();
2299 if (!platform_sp)
2300 return true; // this should not happen
2301
2302 ConstString platform_plugin_name = platform_sp->GetPluginName();
2303 if (platform_plugin_name) {
2304 llvm::StringRef platform_plugin_name_sr =
2305 platform_plugin_name.GetStringRef();
2306 if (platform_plugin_name_sr.endswith("-simulator"))
2307 return false;
2308 }
2309
2310 return true;
2311 }
2312
WarnIfNoClassesCached(SharedCacheWarningReason reason)2313 void AppleObjCRuntimeV2::WarnIfNoClassesCached(
2314 SharedCacheWarningReason reason) {
2315 if (m_noclasses_warning_emitted)
2316 return;
2317
2318 if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) {
2319 // Simulators do not have the objc_opt_ro class table so don't actually
2320 // complain to the user
2321 m_noclasses_warning_emitted = true;
2322 return;
2323 }
2324
2325 Debugger &debugger(GetProcess()->GetTarget().GetDebugger());
2326 if (auto stream = debugger.GetAsyncOutputStream()) {
2327 switch (reason) {
2328 case SharedCacheWarningReason::eNotEnoughClassesRead:
2329 stream->PutCString("warning: could not find Objective-C class data in "
2330 "the process. This may reduce the quality of type "
2331 "information available.\n");
2332 m_noclasses_warning_emitted = true;
2333 break;
2334 case SharedCacheWarningReason::eExpressionExecutionFailure:
2335 stream->PutCString("warning: could not execute support code to read "
2336 "Objective-C class data in the process. This may "
2337 "reduce the quality of type information available.\n");
2338 m_noclasses_warning_emitted = true;
2339 break;
2340 }
2341 }
2342 }
2343
GetDeclVendor()2344 DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() {
2345 if (!m_decl_vendor_up)
2346 m_decl_vendor_up = std::make_unique<AppleObjCDeclVendor>(*this);
2347
2348 return m_decl_vendor_up.get();
2349 }
2350
LookupRuntimeSymbol(ConstString name)2351 lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {
2352 lldb::addr_t ret = LLDB_INVALID_ADDRESS;
2353
2354 const char *name_cstr = name.AsCString();
2355
2356 if (name_cstr) {
2357 llvm::StringRef name_strref(name_cstr);
2358
2359 llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
2360 llvm::StringRef class_prefix("OBJC_CLASS_$_");
2361
2362 if (name_strref.startswith(ivar_prefix)) {
2363 llvm::StringRef ivar_skipped_prefix =
2364 name_strref.substr(ivar_prefix.size());
2365 std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =
2366 ivar_skipped_prefix.split('.');
2367
2368 if (class_and_ivar.first.size() && class_and_ivar.second.size()) {
2369 const ConstString class_name_cs(class_and_ivar.first);
2370 ClassDescriptorSP descriptor =
2371 ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);
2372
2373 if (descriptor) {
2374 const ConstString ivar_name_cs(class_and_ivar.second);
2375 const char *ivar_name_cstr = ivar_name_cs.AsCString();
2376
2377 auto ivar_func = [&ret,
2378 ivar_name_cstr](const char *name, const char *type,
2379 lldb::addr_t offset_addr,
2380 uint64_t size) -> lldb::addr_t {
2381 if (!strcmp(name, ivar_name_cstr)) {
2382 ret = offset_addr;
2383 return true;
2384 }
2385 return false;
2386 };
2387
2388 descriptor->Describe(
2389 std::function<void(ObjCISA)>(nullptr),
2390 std::function<bool(const char *, const char *)>(nullptr),
2391 std::function<bool(const char *, const char *)>(nullptr),
2392 ivar_func);
2393 }
2394 }
2395 } else if (name_strref.startswith(class_prefix)) {
2396 llvm::StringRef class_skipped_prefix =
2397 name_strref.substr(class_prefix.size());
2398 const ConstString class_name_cs(class_skipped_prefix);
2399 ClassDescriptorSP descriptor =
2400 GetClassDescriptorFromClassName(class_name_cs);
2401
2402 if (descriptor)
2403 ret = descriptor->GetISA();
2404 }
2405 }
2406
2407 return ret;
2408 }
2409
2410 AppleObjCRuntimeV2::NonPointerISACache *
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2411 AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(
2412 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2413 Process *process(runtime.GetProcess());
2414
2415 Status error;
2416
2417 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
2418
2419 auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(
2420 process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);
2421 if (error.Fail())
2422 return nullptr;
2423
2424 auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(
2425 process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,
2426 error);
2427 if (error.Fail())
2428 return nullptr;
2429
2430 auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(
2431 process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);
2432 if (error.Fail())
2433 return nullptr;
2434
2435 if (log)
2436 log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks");
2437
2438 bool foundError = false;
2439 auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol(
2440 process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp,
2441 error);
2442 foundError |= error.Fail();
2443
2444 auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol(
2445 process, ConstString("objc_debug_indexed_isa_magic_value"),
2446 objc_module_sp, error);
2447 foundError |= error.Fail();
2448
2449 auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol(
2450 process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp,
2451 error);
2452 foundError |= error.Fail();
2453
2454 auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol(
2455 process, ConstString("objc_debug_indexed_isa_index_shift"),
2456 objc_module_sp, error);
2457 foundError |= error.Fail();
2458
2459 auto objc_indexed_classes =
2460 ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"),
2461 objc_module_sp, error, false);
2462 foundError |= error.Fail();
2463
2464 if (log)
2465 log->PutCString("AOCRT::NPI: Found all the indexed ISA masks");
2466
2467 // we might want to have some rules to outlaw these other values (e.g if the
2468 // mask is zero but the value is non-zero, ...)
2469
2470 return new NonPointerISACache(
2471 runtime, objc_module_sp, objc_debug_isa_class_mask,
2472 objc_debug_isa_magic_mask, objc_debug_isa_magic_value,
2473 objc_debug_indexed_isa_magic_mask, objc_debug_indexed_isa_magic_value,
2474 objc_debug_indexed_isa_index_mask, objc_debug_indexed_isa_index_shift,
2475 foundError ? 0 : objc_indexed_classes);
2476 }
2477
2478 AppleObjCRuntimeV2::TaggedPointerVendorV2 *
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2479 AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
2480 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2481 Process *process(runtime.GetProcess());
2482
2483 Status error;
2484
2485 auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(
2486 process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,
2487 error);
2488 if (error.Fail())
2489 return new TaggedPointerVendorLegacy(runtime);
2490
2491 auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(
2492 process, ConstString("objc_debug_taggedpointer_slot_shift"),
2493 objc_module_sp, error, true, 4);
2494 if (error.Fail())
2495 return new TaggedPointerVendorLegacy(runtime);
2496
2497 auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(
2498 process, ConstString("objc_debug_taggedpointer_slot_mask"),
2499 objc_module_sp, error, true, 4);
2500 if (error.Fail())
2501 return new TaggedPointerVendorLegacy(runtime);
2502
2503 auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(
2504 process, ConstString("objc_debug_taggedpointer_payload_lshift"),
2505 objc_module_sp, error, true, 4);
2506 if (error.Fail())
2507 return new TaggedPointerVendorLegacy(runtime);
2508
2509 auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(
2510 process, ConstString("objc_debug_taggedpointer_payload_rshift"),
2511 objc_module_sp, error, true, 4);
2512 if (error.Fail())
2513 return new TaggedPointerVendorLegacy(runtime);
2514
2515 auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(
2516 process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,
2517 error, false);
2518 if (error.Fail())
2519 return new TaggedPointerVendorLegacy(runtime);
2520
2521 // try to detect the "extended tagged pointer" variables - if any are
2522 // missing, use the non-extended vendor
2523 do {
2524 auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(
2525 process, ConstString("objc_debug_taggedpointer_ext_mask"),
2526 objc_module_sp, error);
2527 if (error.Fail())
2528 break;
2529
2530 auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(
2531 process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),
2532 objc_module_sp, error, true, 4);
2533 if (error.Fail())
2534 break;
2535
2536 auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(
2537 process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),
2538 objc_module_sp, error, true, 4);
2539 if (error.Fail())
2540 break;
2541
2542 auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(
2543 process, ConstString("objc_debug_taggedpointer_ext_classes"),
2544 objc_module_sp, error, false);
2545 if (error.Fail())
2546 break;
2547
2548 auto objc_debug_taggedpointer_ext_payload_lshift =
2549 ExtractRuntimeGlobalSymbol(
2550 process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),
2551 objc_module_sp, error, true, 4);
2552 if (error.Fail())
2553 break;
2554
2555 auto objc_debug_taggedpointer_ext_payload_rshift =
2556 ExtractRuntimeGlobalSymbol(
2557 process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),
2558 objc_module_sp, error, true, 4);
2559 if (error.Fail())
2560 break;
2561
2562 return new TaggedPointerVendorExtended(
2563 runtime, objc_debug_taggedpointer_mask,
2564 objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift,
2565 objc_debug_taggedpointer_ext_slot_shift,
2566 objc_debug_taggedpointer_slot_mask,
2567 objc_debug_taggedpointer_ext_slot_mask,
2568 objc_debug_taggedpointer_payload_lshift,
2569 objc_debug_taggedpointer_payload_rshift,
2570 objc_debug_taggedpointer_ext_payload_lshift,
2571 objc_debug_taggedpointer_ext_payload_rshift,
2572 objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);
2573 } while (false);
2574
2575 // we might want to have some rules to outlaw these values (e.g if the
2576 // table's address is zero)
2577
2578 return new TaggedPointerVendorRuntimeAssisted(
2579 runtime, objc_debug_taggedpointer_mask,
2580 objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask,
2581 objc_debug_taggedpointer_payload_lshift,
2582 objc_debug_taggedpointer_payload_rshift,
2583 objc_debug_taggedpointer_classes);
2584 }
2585
IsPossibleTaggedPointer(lldb::addr_t ptr)2586 bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer(
2587 lldb::addr_t ptr) {
2588 return (ptr & 1);
2589 }
2590
2591 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2592 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor(
2593 lldb::addr_t ptr) {
2594 if (!IsPossibleTaggedPointer(ptr))
2595 return ObjCLanguageRuntime::ClassDescriptorSP();
2596
2597 uint32_t foundation_version = m_runtime.GetFoundationVersion();
2598
2599 if (foundation_version == LLDB_INVALID_MODULE_VERSION)
2600 return ObjCLanguageRuntime::ClassDescriptorSP();
2601
2602 uint64_t class_bits = (ptr & 0xE) >> 1;
2603 ConstString name;
2604
2605 static ConstString g_NSAtom("NSAtom");
2606 static ConstString g_NSNumber("NSNumber");
2607 static ConstString g_NSDateTS("NSDateTS");
2608 static ConstString g_NSManagedObject("NSManagedObject");
2609 static ConstString g_NSDate("NSDate");
2610
2611 if (foundation_version >= 900) {
2612 switch (class_bits) {
2613 case 0:
2614 name = g_NSAtom;
2615 break;
2616 case 3:
2617 name = g_NSNumber;
2618 break;
2619 case 4:
2620 name = g_NSDateTS;
2621 break;
2622 case 5:
2623 name = g_NSManagedObject;
2624 break;
2625 case 6:
2626 name = g_NSDate;
2627 break;
2628 default:
2629 return ObjCLanguageRuntime::ClassDescriptorSP();
2630 }
2631 } else {
2632 switch (class_bits) {
2633 case 1:
2634 name = g_NSNumber;
2635 break;
2636 case 5:
2637 name = g_NSManagedObject;
2638 break;
2639 case 6:
2640 name = g_NSDate;
2641 break;
2642 case 7:
2643 name = g_NSDateTS;
2644 break;
2645 default:
2646 return ObjCLanguageRuntime::ClassDescriptorSP();
2647 }
2648 }
2649
2650 lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator();
2651 return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated));
2652 }
2653
2654 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
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)2655 TaggedPointerVendorRuntimeAssisted(
2656 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2657 uint32_t objc_debug_taggedpointer_slot_shift,
2658 uint32_t objc_debug_taggedpointer_slot_mask,
2659 uint32_t objc_debug_taggedpointer_payload_lshift,
2660 uint32_t objc_debug_taggedpointer_payload_rshift,
2661 lldb::addr_t objc_debug_taggedpointer_classes)
2662 : TaggedPointerVendorV2(runtime), m_cache(),
2663 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
2664 m_objc_debug_taggedpointer_slot_shift(
2665 objc_debug_taggedpointer_slot_shift),
2666 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
2667 m_objc_debug_taggedpointer_payload_lshift(
2668 objc_debug_taggedpointer_payload_lshift),
2669 m_objc_debug_taggedpointer_payload_rshift(
2670 objc_debug_taggedpointer_payload_rshift),
2671 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {}
2672
2673 bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
IsPossibleTaggedPointer(lldb::addr_t ptr)2674 IsPossibleTaggedPointer(lldb::addr_t ptr) {
2675 return (ptr & m_objc_debug_taggedpointer_mask) != 0;
2676 }
2677
2678 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2679 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
2680 lldb::addr_t ptr) {
2681 ClassDescriptorSP actual_class_descriptor_sp;
2682 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
2683
2684 if (!IsPossibleTaggedPointer(unobfuscated))
2685 return ObjCLanguageRuntime::ClassDescriptorSP();
2686
2687 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) &
2688 m_objc_debug_taggedpointer_slot_mask;
2689
2690 CacheIterator iterator = m_cache.find(slot), end = m_cache.end();
2691 if (iterator != end) {
2692 actual_class_descriptor_sp = iterator->second;
2693 } else {
2694 Process *process(m_runtime.GetProcess());
2695 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
2696 m_objc_debug_taggedpointer_classes;
2697 Status error;
2698 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2699 if (error.Fail() || slot_data == 0 ||
2700 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2701 return nullptr;
2702 actual_class_descriptor_sp =
2703 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2704 if (!actual_class_descriptor_sp)
2705 return ObjCLanguageRuntime::ClassDescriptorSP();
2706 m_cache[slot] = actual_class_descriptor_sp;
2707 }
2708
2709 uint64_t data_payload =
2710 (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>
2711 m_objc_debug_taggedpointer_payload_rshift);
2712 int64_t data_payload_signed =
2713 ((int64_t)((int64_t)unobfuscated
2714 << m_objc_debug_taggedpointer_payload_lshift) >>
2715 m_objc_debug_taggedpointer_payload_rshift);
2716 return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2717 actual_class_descriptor_sp, data_payload, data_payload_signed));
2718 }
2719
TaggedPointerVendorExtended(AppleObjCRuntimeV2 & runtime,uint64_t objc_debug_taggedpointer_mask,uint64_t objc_debug_taggedpointer_ext_mask,uint32_t objc_debug_taggedpointer_slot_shift,uint32_t objc_debug_taggedpointer_ext_slot_shift,uint32_t objc_debug_taggedpointer_slot_mask,uint32_t objc_debug_taggedpointer_ext_slot_mask,uint32_t objc_debug_taggedpointer_payload_lshift,uint32_t objc_debug_taggedpointer_payload_rshift,uint32_t objc_debug_taggedpointer_ext_payload_lshift,uint32_t objc_debug_taggedpointer_ext_payload_rshift,lldb::addr_t objc_debug_taggedpointer_classes,lldb::addr_t objc_debug_taggedpointer_ext_classes)2720 AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(
2721 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2722 uint64_t objc_debug_taggedpointer_ext_mask,
2723 uint32_t objc_debug_taggedpointer_slot_shift,
2724 uint32_t objc_debug_taggedpointer_ext_slot_shift,
2725 uint32_t objc_debug_taggedpointer_slot_mask,
2726 uint32_t objc_debug_taggedpointer_ext_slot_mask,
2727 uint32_t objc_debug_taggedpointer_payload_lshift,
2728 uint32_t objc_debug_taggedpointer_payload_rshift,
2729 uint32_t objc_debug_taggedpointer_ext_payload_lshift,
2730 uint32_t objc_debug_taggedpointer_ext_payload_rshift,
2731 lldb::addr_t objc_debug_taggedpointer_classes,
2732 lldb::addr_t objc_debug_taggedpointer_ext_classes)
2733 : TaggedPointerVendorRuntimeAssisted(
2734 runtime, objc_debug_taggedpointer_mask,
2735 objc_debug_taggedpointer_slot_shift,
2736 objc_debug_taggedpointer_slot_mask,
2737 objc_debug_taggedpointer_payload_lshift,
2738 objc_debug_taggedpointer_payload_rshift,
2739 objc_debug_taggedpointer_classes),
2740 m_ext_cache(),
2741 m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),
2742 m_objc_debug_taggedpointer_ext_slot_shift(
2743 objc_debug_taggedpointer_ext_slot_shift),
2744 m_objc_debug_taggedpointer_ext_slot_mask(
2745 objc_debug_taggedpointer_ext_slot_mask),
2746 m_objc_debug_taggedpointer_ext_payload_lshift(
2747 objc_debug_taggedpointer_ext_payload_lshift),
2748 m_objc_debug_taggedpointer_ext_payload_rshift(
2749 objc_debug_taggedpointer_ext_payload_rshift),
2750 m_objc_debug_taggedpointer_ext_classes(
2751 objc_debug_taggedpointer_ext_classes) {}
2752
2753 bool AppleObjCRuntimeV2::TaggedPointerVendorExtended::
IsPossibleExtendedTaggedPointer(lldb::addr_t ptr)2754 IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) {
2755 if (!IsPossibleTaggedPointer(ptr))
2756 return false;
2757
2758 if (m_objc_debug_taggedpointer_ext_mask == 0)
2759 return false;
2760
2761 return ((ptr & m_objc_debug_taggedpointer_ext_mask) ==
2762 m_objc_debug_taggedpointer_ext_mask);
2763 }
2764
2765 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2766 AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
2767 lldb::addr_t ptr) {
2768 ClassDescriptorSP actual_class_descriptor_sp;
2769 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
2770
2771 if (!IsPossibleTaggedPointer(unobfuscated))
2772 return ObjCLanguageRuntime::ClassDescriptorSP();
2773
2774 if (!IsPossibleExtendedTaggedPointer(unobfuscated))
2775 return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);
2776
2777 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) &
2778 m_objc_debug_taggedpointer_ext_slot_mask;
2779
2780 CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end();
2781 if (iterator != end) {
2782 actual_class_descriptor_sp = iterator->second;
2783 } else {
2784 Process *process(m_runtime.GetProcess());
2785 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
2786 m_objc_debug_taggedpointer_ext_classes;
2787 Status error;
2788 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2789 if (error.Fail() || slot_data == 0 ||
2790 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2791 return nullptr;
2792 actual_class_descriptor_sp =
2793 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2794 if (!actual_class_descriptor_sp)
2795 return ObjCLanguageRuntime::ClassDescriptorSP();
2796 m_ext_cache[slot] = actual_class_descriptor_sp;
2797 }
2798
2799 uint64_t data_payload = (((uint64_t)unobfuscated
2800 << m_objc_debug_taggedpointer_ext_payload_lshift) >>
2801 m_objc_debug_taggedpointer_ext_payload_rshift);
2802 int64_t data_payload_signed =
2803 ((int64_t)((int64_t)unobfuscated
2804 << m_objc_debug_taggedpointer_ext_payload_lshift) >>
2805 m_objc_debug_taggedpointer_ext_payload_rshift);
2806
2807 return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2808 actual_class_descriptor_sp, data_payload, data_payload_signed));
2809 }
2810
NonPointerISACache(AppleObjCRuntimeV2 & runtime,const ModuleSP & objc_module_sp,uint64_t objc_debug_isa_class_mask,uint64_t objc_debug_isa_magic_mask,uint64_t objc_debug_isa_magic_value,uint64_t objc_debug_indexed_isa_magic_mask,uint64_t objc_debug_indexed_isa_magic_value,uint64_t objc_debug_indexed_isa_index_mask,uint64_t objc_debug_indexed_isa_index_shift,lldb::addr_t objc_indexed_classes)2811 AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(
2812 AppleObjCRuntimeV2 &runtime, const ModuleSP &objc_module_sp,
2813 uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask,
2814 uint64_t objc_debug_isa_magic_value,
2815 uint64_t objc_debug_indexed_isa_magic_mask,
2816 uint64_t objc_debug_indexed_isa_magic_value,
2817 uint64_t objc_debug_indexed_isa_index_mask,
2818 uint64_t objc_debug_indexed_isa_index_shift,
2819 lldb::addr_t objc_indexed_classes)
2820 : m_runtime(runtime), m_cache(), m_objc_module_wp(objc_module_sp),
2821 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
2822 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
2823 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value),
2824 m_objc_debug_indexed_isa_magic_mask(objc_debug_indexed_isa_magic_mask),
2825 m_objc_debug_indexed_isa_magic_value(objc_debug_indexed_isa_magic_value),
2826 m_objc_debug_indexed_isa_index_mask(objc_debug_indexed_isa_index_mask),
2827 m_objc_debug_indexed_isa_index_shift(objc_debug_indexed_isa_index_shift),
2828 m_objc_indexed_classes(objc_indexed_classes), m_indexed_isa_cache() {}
2829
2830 ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ObjCISA isa)2831 AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) {
2832 ObjCISA real_isa = 0;
2833 if (!EvaluateNonPointerISA(isa, real_isa))
2834 return ObjCLanguageRuntime::ClassDescriptorSP();
2835 auto cache_iter = m_cache.find(real_isa);
2836 if (cache_iter != m_cache.end())
2837 return cache_iter->second;
2838 auto descriptor_sp =
2839 m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
2840 if (descriptor_sp) // cache only positive matches since the table might grow
2841 m_cache[real_isa] = descriptor_sp;
2842 return descriptor_sp;
2843 }
2844
EvaluateNonPointerISA(ObjCISA isa,ObjCISA & ret_isa)2845 bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA(
2846 ObjCISA isa, ObjCISA &ret_isa) {
2847 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
2848
2849 LLDB_LOGF(log, "AOCRT::NPI Evaluate(isa = 0x%" PRIx64 ")", (uint64_t)isa);
2850
2851 if ((isa & ~m_objc_debug_isa_class_mask) == 0)
2852 return false;
2853
2854 // If all of the indexed ISA variables are set, then its possible that this
2855 // ISA is indexed, and we should first try to get its value using the index.
2856 // Note, we check these variables first as the ObjC runtime will set at least
2857 // one of their values to 0 if they aren't needed.
2858 if (m_objc_debug_indexed_isa_magic_mask &&
2859 m_objc_debug_indexed_isa_magic_value &&
2860 m_objc_debug_indexed_isa_index_mask &&
2861 m_objc_debug_indexed_isa_index_shift && m_objc_indexed_classes) {
2862 if ((isa & ~m_objc_debug_indexed_isa_index_mask) == 0)
2863 return false;
2864
2865 if ((isa & m_objc_debug_indexed_isa_magic_mask) ==
2866 m_objc_debug_indexed_isa_magic_value) {
2867 // Magic bits are correct, so try extract the index.
2868 uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >>
2869 m_objc_debug_indexed_isa_index_shift;
2870 // If the index is out of bounds of the length of the array then check if
2871 // the array has been updated. If that is the case then we should try
2872 // read the count again, and update the cache if the count has been
2873 // updated.
2874 if (index > m_indexed_isa_cache.size()) {
2875 LLDB_LOGF(log,
2876 "AOCRT::NPI (index = %" PRIu64
2877 ") exceeds cache (size = %" PRIu64 ")",
2878 (uint64_t)index, (uint64_t)m_indexed_isa_cache.size());
2879
2880 Process *process(m_runtime.GetProcess());
2881
2882 ModuleSP objc_module_sp(m_objc_module_wp.lock());
2883 if (!objc_module_sp)
2884 return false;
2885
2886 Status error;
2887 auto objc_indexed_classes_count = ExtractRuntimeGlobalSymbol(
2888 process, ConstString("objc_indexed_classes_count"), objc_module_sp,
2889 error);
2890 if (error.Fail())
2891 return false;
2892
2893 LLDB_LOGF(log, "AOCRT::NPI (new class count = %" PRIu64 ")",
2894 (uint64_t)objc_indexed_classes_count);
2895
2896 if (objc_indexed_classes_count > m_indexed_isa_cache.size()) {
2897 // Read the class entries we don't have. We should just read all of
2898 // them instead of just the one we need as then we can cache those we
2899 // may need later.
2900 auto num_new_classes =
2901 objc_indexed_classes_count - m_indexed_isa_cache.size();
2902 const uint32_t addr_size = process->GetAddressByteSize();
2903 DataBufferHeap buffer(num_new_classes * addr_size, 0);
2904
2905 lldb::addr_t last_read_class =
2906 m_objc_indexed_classes + (m_indexed_isa_cache.size() * addr_size);
2907 size_t bytes_read = process->ReadMemory(
2908 last_read_class, buffer.GetBytes(), buffer.GetByteSize(), error);
2909 if (error.Fail() || bytes_read != buffer.GetByteSize())
2910 return false;
2911
2912 LLDB_LOGF(log, "AOCRT::NPI (read new classes count = %" PRIu64 ")",
2913 (uint64_t)num_new_classes);
2914
2915 // Append the new entries to the existing cache.
2916 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
2917 process->GetByteOrder(),
2918 process->GetAddressByteSize());
2919
2920 lldb::offset_t offset = 0;
2921 for (unsigned i = 0; i != num_new_classes; ++i)
2922 m_indexed_isa_cache.push_back(data.GetAddress(&offset));
2923 }
2924 }
2925
2926 // If the index is still out of range then this isn't a pointer.
2927 if (index > m_indexed_isa_cache.size())
2928 return false;
2929
2930 LLDB_LOGF(log, "AOCRT::NPI Evaluate(ret_isa = 0x%" PRIx64 ")",
2931 (uint64_t)m_indexed_isa_cache[index]);
2932
2933 ret_isa = m_indexed_isa_cache[index];
2934 return (ret_isa != 0); // this is a pointer so 0 is not a valid value
2935 }
2936
2937 return false;
2938 }
2939
2940 // Definitely not an indexed ISA, so try to use a mask to extract the pointer
2941 // from the ISA.
2942 if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) {
2943 ret_isa = isa & m_objc_debug_isa_class_mask;
2944 return (ret_isa != 0); // this is a pointer so 0 is not a valid value
2945 }
2946 return false;
2947 }
2948
GetEncodingToType()2949 ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() {
2950 if (!m_encoding_to_type_sp)
2951 m_encoding_to_type_sp =
2952 std::make_shared<AppleObjCTypeEncodingParser>(*this);
2953 return m_encoding_to_type_sp;
2954 }
2955
2956 lldb_private::AppleObjCRuntime::ObjCISA
GetPointerISA(ObjCISA isa)2957 AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) {
2958 ObjCISA ret = isa;
2959
2960 if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())
2961 non_pointer_isa_cache->EvaluateNonPointerISA(isa, ret);
2962
2963 return ret;
2964 }
2965
GetCFBooleanValuesIfNeeded()2966 bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() {
2967 if (m_CFBoolean_values)
2968 return true;
2969
2970 static ConstString g_kCFBooleanFalse("__kCFBooleanFalse");
2971 static ConstString g_kCFBooleanTrue("__kCFBooleanTrue");
2972
2973 std::function<lldb::addr_t(ConstString)> get_symbol =
2974 [this](ConstString sym) -> lldb::addr_t {
2975 SymbolContextList sc_list;
2976 GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(
2977 sym, lldb::eSymbolTypeData, sc_list);
2978 if (sc_list.GetSize() == 1) {
2979 SymbolContext sc;
2980 sc_list.GetContextAtIndex(0, sc);
2981 if (sc.symbol)
2982 return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());
2983 }
2984
2985 return LLDB_INVALID_ADDRESS;
2986 };
2987
2988 lldb::addr_t false_addr = get_symbol(g_kCFBooleanFalse);
2989 lldb::addr_t true_addr = get_symbol(g_kCFBooleanTrue);
2990
2991 return (m_CFBoolean_values = {false_addr, true_addr}).operator bool();
2992 }
2993
GetValuesForGlobalCFBooleans(lldb::addr_t & cf_true,lldb::addr_t & cf_false)2994 void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
2995 lldb::addr_t &cf_false) {
2996 if (GetCFBooleanValuesIfNeeded()) {
2997 cf_true = m_CFBoolean_values->second;
2998 cf_false = m_CFBoolean_values->first;
2999 } else
3000 this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);
3001 }
3002
3003 #pragma mark Frame recognizers
3004
3005 class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
3006 public:
ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp)3007 ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) {
3008 ThreadSP thread_sp = frame_sp->GetThread();
3009 ProcessSP process_sp = thread_sp->GetProcess();
3010
3011 const lldb::ABISP &abi = process_sp->GetABI();
3012 if (!abi)
3013 return;
3014
3015 TypeSystemClang *clang_ast_context =
3016 ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
3017 if (!clang_ast_context)
3018 return;
3019 CompilerType voidstar =
3020 clang_ast_context->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
3021
3022 ValueList args;
3023 Value input_value;
3024 input_value.SetCompilerType(voidstar);
3025 args.PushValue(input_value);
3026
3027 if (!abi->GetArgumentValues(*thread_sp, args))
3028 return;
3029
3030 addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong();
3031
3032 Value value(exception_addr);
3033 value.SetCompilerType(voidstar);
3034 exception = ValueObjectConstResult::Create(frame_sp.get(), value,
3035 ConstString("exception"));
3036 exception = ValueObjectRecognizerSynthesizedValue::Create(
3037 *exception, eValueTypeVariableArgument);
3038 exception = exception->GetDynamicValue(eDynamicDontRunTarget);
3039
3040 m_arguments = ValueObjectListSP(new ValueObjectList());
3041 m_arguments->Append(exception);
3042
3043 m_stop_desc = "hit Objective-C exception";
3044 }
3045
3046 ValueObjectSP exception;
3047
GetExceptionObject()3048 lldb::ValueObjectSP GetExceptionObject() override { return exception; }
3049 };
3050
3051 class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {
3052 lldb::RecognizedStackFrameSP
RecognizeFrame(lldb::StackFrameSP frame)3053 RecognizeFrame(lldb::StackFrameSP frame) override {
3054 return lldb::RecognizedStackFrameSP(
3055 new ObjCExceptionRecognizedStackFrame(frame));
3056 };
GetName()3057 std::string GetName() override {
3058 return "ObjC Exception Throw StackFrame Recognizer";
3059 }
3060 };
3061
RegisterObjCExceptionRecognizer(Process * process)3062 static void RegisterObjCExceptionRecognizer(Process *process) {
3063 FileSpec module;
3064 ConstString function;
3065 std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();
3066 std::vector<ConstString> symbols = {function};
3067
3068 process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
3069 StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
3070 module.GetFilename(), symbols,
3071 /*first_instruction_only*/ true);
3072 }
3073