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