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