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