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