Bug Summary

File:build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/lldb/include/lldb/Target/StackFrameRecognizer.h
Warning:line 149, column 5
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-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-16~++20220816100716+b5a18de65169/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-16/lib/clang/16.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-16~++20220816100716+b5a18de65169/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime -I tools/lldb/source/Plugins/LanguageRuntime/ObjC -I /build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/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-16/lib/clang/16.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-16~++20220816100716+b5a18de65169/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/= -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-stringop-truncation -std=c++17 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/= -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-08-17-052721-121489-1 -x c++ /build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

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

/build/llvm-toolchain-snapshot-16~++20220816100716+b5a18de65169/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