Bug Summary

File:build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/include/lldb/Target/StackFrameRecognizer.h
Warning:line 149, column 12
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name AppleObjCRuntimeV2.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.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-15~++20220420111733+e13d2efed663/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime -I tools/lldb/source/Plugins/LanguageRuntime/ObjC -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/include -I tools/lldb/include -I include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/llvm/include -I /usr/include/python3.9 -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/clang/include -I tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/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-15/lib/clang/15.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-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -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++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/= -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-04-20-140412-16051-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp

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

/build/llvm-toolchain-snapshot-15~++20220420111733+e13d2efed663/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