Bug Summary

File:lldb/include/lldb/Target/StackFrameRecognizer.h
Warning:line 149, column 12
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name AppleObjCRuntimeV2.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-14/lib/clang/14.0.0 -isystem /usr/include/libxml2 -D HAVE_ROUND -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime -I tools/lldb/source/Plugins/LanguageRuntime/ObjC -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source -I tools/lldb/source -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-19-134126-35450-1 -x c++ /build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

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

/build/llvm-toolchain-snapshot-14~++20220119111520+da61cb019eb2/lldb/include/lldb/Target/StackFrameRecognizer.h

1//===-- StackFrameRecognizer.h ----------------------------------*- C++ -*-===//
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#ifndef LLDB_TARGET_STACKFRAMERECOGNIZER_H
10#define LLDB_TARGET_STACKFRAMERECOGNIZER_H
11
12#include "lldb/Core/ValueObject.h"
13#include "lldb/Core/ValueObjectList.h"
14#include "lldb/Symbol/VariableList.h"
15#include "lldb/Target/StopInfo.h"
16#include "lldb/Utility/StructuredData.h"
17#include "lldb/lldb-private-forward.h"
18#include "lldb/lldb-public.h"
19
20#include <vector>
21
22namespace lldb_private {
23
24/// \class RecognizedStackFrame
25///
26/// This class provides extra information about a stack frame that was
27/// provided by a specific stack frame recognizer. Right now, this class only
28/// holds recognized arguments (via GetRecognizedArguments).
29
30class RecognizedStackFrame
31 : public std::enable_shared_from_this<RecognizedStackFrame> {
32public:
33 virtual lldb::ValueObjectListSP GetRecognizedArguments() {
34 return m_arguments;
35 }
36 virtual lldb::ValueObjectSP GetExceptionObject() {
37 return lldb::ValueObjectSP();
38 }
39 virtual lldb::StackFrameSP GetMostRelevantFrame() { return nullptr; };
40 virtual ~RecognizedStackFrame() = default;
41
42 std::string GetStopDescription() { return m_stop_desc; }
43
44protected:
45 lldb::ValueObjectListSP m_arguments;
46 std::string m_stop_desc;
47};
48
49/// \class StackFrameRecognizer
50///
51/// A base class for frame recognizers. Subclasses (actual frame recognizers)
52/// should implement RecognizeFrame to provide a RecognizedStackFrame for a
53/// given stack frame.
54
55class StackFrameRecognizer
56 : public std::enable_shared_from_this<StackFrameRecognizer> {
57public:
58 virtual lldb::RecognizedStackFrameSP RecognizeFrame(
59 lldb::StackFrameSP frame) {
60 return lldb::RecognizedStackFrameSP();
61 };
62 virtual std::string GetName() {
63 return "";
64 }
65
66 virtual ~StackFrameRecognizer() = default;
67};
68
69/// \class ScriptedStackFrameRecognizer
70///
71/// Python implementation for frame recognizers. An instance of this class
72/// tracks a particular Python classobject, which will be asked to recognize
73/// stack frames.
74
75class ScriptedStackFrameRecognizer : public StackFrameRecognizer {
76 lldb_private::ScriptInterpreter *m_interpreter;
77 lldb_private::StructuredData::ObjectSP m_python_object_sp;
78 std::string m_python_class;
79
80public:
81 ScriptedStackFrameRecognizer(lldb_private::ScriptInterpreter *interpreter,
82 const char *pclass);
83 ~ScriptedStackFrameRecognizer() override = default;
84
85 std::string GetName() override {
86 return GetPythonClassName();
87 }
88
89 const char *GetPythonClassName() { return m_python_class.c_str(); }
90
91 lldb::RecognizedStackFrameSP RecognizeFrame(
92 lldb::StackFrameSP frame) override;
93
94private:
95 ScriptedStackFrameRecognizer(const ScriptedStackFrameRecognizer &) = delete;
96 const ScriptedStackFrameRecognizer &
97 operator=(const ScriptedStackFrameRecognizer &) = delete;
98};
99
100/// Class that provides a registry of known stack frame recognizers.
101class StackFrameRecognizerManager {
102public:
103 void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
104 ConstString module, llvm::ArrayRef<ConstString> symbols,
105 bool first_instruction_only = true);
106
107 void AddRecognizer(lldb::StackFrameRecognizerSP recognizer,
108 lldb::RegularExpressionSP module,
109 lldb::RegularExpressionSP symbol,
110 bool first_instruction_only = true);
111
112 void ForEach(std::function<
113 void(uint32_t recognizer_id, std::string recognizer_name,
114 std::string module, llvm::ArrayRef<ConstString> symbols,
115 bool regexp)> const &callback);
116
117 bool RemoveRecognizerWithID(uint32_t recognizer_id);
118
119 void RemoveAllRecognizers();
120
121 lldb::StackFrameRecognizerSP GetRecognizerForFrame(lldb::StackFrameSP frame);
122
123 lldb::RecognizedStackFrameSP RecognizeFrame(lldb::StackFrameSP frame);
124
125private:
126 struct RegisteredEntry {
127 uint32_t recognizer_id;
128 lldb::StackFrameRecognizerSP recognizer;
129 bool is_regexp;
130 ConstString module;
131 lldb::RegularExpressionSP module_regexp;
132 std::vector<ConstString> symbols;
133 lldb::RegularExpressionSP symbol_regexp;
134 bool first_instruction_only;
135 };
136
137 std::deque<RegisteredEntry> m_recognizers;
138};
139
140/// \class ValueObjectRecognizerSynthesizedValue
141///
142/// ValueObject subclass that presents the passed ValueObject as a recognized
143/// value with the specified ValueType. Frame recognizers should return
144/// instances of this class as the returned objects in GetRecognizedArguments().
145
146class ValueObjectRecognizerSynthesizedValue : public ValueObject {
147 public:
148 static lldb::ValueObjectSP Create(ValueObject &parent, lldb::ValueType type) {
149 return (new ValueObjectRecognizerSynthesizedValue(parent, type))->GetSP();
8
Memory is allocated
9
Potential memory leak
150 }
151 ValueObjectRecognizerSynthesizedValue(ValueObject &parent,
152 lldb::ValueType type)
153 : ValueObject(parent), m_type(type) {
154 SetName(parent.GetName());
155 }
156
157 llvm::Optional<uint64_t> GetByteSize() override {
158 return m_parent->GetByteSize();
159 }
160 lldb::ValueType GetValueType() const override { return m_type; }
161 bool UpdateValue() override {
162 if (!m_parent->UpdateValueIfNeeded()) return false;
163 m_value = m_parent->GetValue();
164 return true;
165 }
166 size_t CalculateNumChildren(uint32_t max = UINT32_MAX(4294967295U)) override {
167 return m_parent->GetNumChildren(max);
168 }
169 CompilerType GetCompilerTypeImpl() override {
170 return m_parent->GetCompilerType();
171 }
172 bool IsSynthetic() override { return true; }
173
174 private:
175 lldb::ValueType m_type;
176};
177
178} // namespace lldb_private
179
180#endif // LLDB_TARGET_STACKFRAMERECOGNIZER_H