Coverage Report

Created: 2023-09-12 09:32

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