1dda28197Spatrick //===-- AppleObjCRuntimeV2.cpp --------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9*f6aab3d8Srobert #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
10dda28197Spatrick #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
11*f6aab3d8Srobert
12061da546Spatrick #include "lldb/Core/Debugger.h"
13*f6aab3d8Srobert #include "lldb/Core/DebuggerEvents.h"
14061da546Spatrick #include "lldb/Core/Module.h"
15061da546Spatrick #include "lldb/Core/PluginManager.h"
16061da546Spatrick #include "lldb/Core/Section.h"
17061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
18061da546Spatrick #include "lldb/Core/ValueObjectVariable.h"
19061da546Spatrick #include "lldb/Expression/DiagnosticManager.h"
20061da546Spatrick #include "lldb/Expression/FunctionCaller.h"
21061da546Spatrick #include "lldb/Expression/UtilityFunction.h"
22*f6aab3d8Srobert #include "lldb/Host/OptionParser.h"
23061da546Spatrick #include "lldb/Interpreter/CommandObject.h"
24061da546Spatrick #include "lldb/Interpreter/CommandObjectMultiword.h"
25061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
26061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
27061da546Spatrick #include "lldb/Interpreter/OptionValueBoolean.h"
28*f6aab3d8Srobert #include "lldb/Symbol/CompilerType.h"
29061da546Spatrick #include "lldb/Symbol/ObjectFile.h"
30061da546Spatrick #include "lldb/Symbol/Symbol.h"
31061da546Spatrick #include "lldb/Symbol/TypeList.h"
32061da546Spatrick #include "lldb/Symbol/VariableList.h"
33061da546Spatrick #include "lldb/Target/ABI.h"
34be691f3bSpatrick #include "lldb/Target/DynamicLoader.h"
35061da546Spatrick #include "lldb/Target/ExecutionContext.h"
36061da546Spatrick #include "lldb/Target/Platform.h"
37061da546Spatrick #include "lldb/Target/Process.h"
38061da546Spatrick #include "lldb/Target/RegisterContext.h"
39061da546Spatrick #include "lldb/Target/StackFrameRecognizer.h"
40061da546Spatrick #include "lldb/Target/Target.h"
41061da546Spatrick #include "lldb/Target/Thread.h"
42061da546Spatrick #include "lldb/Utility/ConstString.h"
43*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
44061da546Spatrick #include "lldb/Utility/Log.h"
45061da546Spatrick #include "lldb/Utility/Scalar.h"
46061da546Spatrick #include "lldb/Utility/Status.h"
47061da546Spatrick #include "lldb/Utility/Stream.h"
48061da546Spatrick #include "lldb/Utility/StreamString.h"
49061da546Spatrick #include "lldb/Utility/Timer.h"
50*f6aab3d8Srobert #include "lldb/lldb-enumerations.h"
51061da546Spatrick
52061da546Spatrick #include "AppleObjCClassDescriptorV2.h"
53061da546Spatrick #include "AppleObjCDeclVendor.h"
54061da546Spatrick #include "AppleObjCRuntimeV2.h"
55061da546Spatrick #include "AppleObjCTrampolineHandler.h"
56061da546Spatrick #include "AppleObjCTypeEncodingParser.h"
57061da546Spatrick
58061da546Spatrick #include "clang/AST/ASTContext.h"
59061da546Spatrick #include "clang/AST/DeclObjC.h"
60dda28197Spatrick #include "clang/Basic/TargetInfo.h"
61*f6aab3d8Srobert #include "llvm/ADT/ScopeExit.h"
62061da546Spatrick
63*f6aab3d8Srobert #include <cstdint>
64*f6aab3d8Srobert #include <memory>
65*f6aab3d8Srobert #include <string>
66061da546Spatrick #include <vector>
67061da546Spatrick
68061da546Spatrick using namespace lldb;
69061da546Spatrick using namespace lldb_private;
70061da546Spatrick
71061da546Spatrick char AppleObjCRuntimeV2::ID = 0;
72061da546Spatrick
73061da546Spatrick static const char *g_get_dynamic_class_info_name =
74061da546Spatrick "__lldb_apple_objc_v2_get_dynamic_class_info";
75be691f3bSpatrick
76061da546Spatrick static const char *g_get_dynamic_class_info_body = R"(
77061da546Spatrick
78061da546Spatrick extern "C"
79061da546Spatrick {
80061da546Spatrick size_t strlen(const char *);
81061da546Spatrick char *strncpy (char * s1, const char * s2, size_t n);
82061da546Spatrick int printf(const char * format, ...);
83061da546Spatrick }
84061da546Spatrick #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
85061da546Spatrick
86061da546Spatrick typedef struct _NXMapTable {
87061da546Spatrick void *prototype;
88061da546Spatrick unsigned num_classes;
89061da546Spatrick unsigned num_buckets_minus_one;
90061da546Spatrick void *buckets;
91061da546Spatrick } NXMapTable;
92061da546Spatrick
93061da546Spatrick #define NX_MAPNOTAKEY ((void *)(-1))
94061da546Spatrick
95061da546Spatrick typedef struct BucketInfo
96061da546Spatrick {
97061da546Spatrick const char *name_ptr;
98061da546Spatrick Class isa;
99061da546Spatrick } BucketInfo;
100061da546Spatrick
101061da546Spatrick struct ClassInfo
102061da546Spatrick {
103061da546Spatrick Class isa;
104061da546Spatrick uint32_t hash;
105061da546Spatrick } __attribute__((__packed__));
106061da546Spatrick
107061da546Spatrick uint32_t
108061da546Spatrick __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
109061da546Spatrick void *class_infos_ptr,
110061da546Spatrick uint32_t class_infos_byte_size,
111061da546Spatrick uint32_t should_log)
112061da546Spatrick {
113061da546Spatrick DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
114061da546Spatrick DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
115061da546Spatrick DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
116061da546Spatrick const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
117061da546Spatrick if (grc)
118061da546Spatrick {
119061da546Spatrick const unsigned num_classes = grc->num_classes;
120be691f3bSpatrick DEBUG_PRINTF ("num_classes = %u\n", grc->num_classes);
121061da546Spatrick if (class_infos_ptr)
122061da546Spatrick {
123be691f3bSpatrick const unsigned num_buckets_minus_one = grc->num_buckets_minus_one;
124be691f3bSpatrick DEBUG_PRINTF ("num_buckets_minus_one = %u\n", num_buckets_minus_one);
125be691f3bSpatrick
126061da546Spatrick const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
127be691f3bSpatrick DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
128be691f3bSpatrick
129061da546Spatrick ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
130061da546Spatrick BucketInfo *buckets = (BucketInfo *)grc->buckets;
131061da546Spatrick
132061da546Spatrick uint32_t idx = 0;
133be691f3bSpatrick for (unsigned i=0; i<=num_buckets_minus_one; ++i)
134061da546Spatrick {
135061da546Spatrick if (buckets[i].name_ptr != NX_MAPNOTAKEY)
136061da546Spatrick {
137061da546Spatrick if (idx < max_class_infos)
138061da546Spatrick {
139061da546Spatrick const char *s = buckets[i].name_ptr;
140061da546Spatrick uint32_t h = 5381;
141061da546Spatrick for (unsigned char c = *s; c; c = *++s)
142061da546Spatrick h = ((h << 5) + h) + c;
143061da546Spatrick class_infos[idx].hash = h;
144061da546Spatrick class_infos[idx].isa = buckets[i].isa;
145be691f3bSpatrick DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, buckets[i].name_ptr);
146061da546Spatrick }
147061da546Spatrick ++idx;
148061da546Spatrick }
149061da546Spatrick }
150061da546Spatrick if (idx < max_class_infos)
151061da546Spatrick {
152061da546Spatrick class_infos[idx].isa = NULL;
153061da546Spatrick class_infos[idx].hash = 0;
154061da546Spatrick }
155061da546Spatrick }
156061da546Spatrick return num_classes;
157061da546Spatrick }
158061da546Spatrick return 0;
159061da546Spatrick }
160061da546Spatrick
161061da546Spatrick )";
162061da546Spatrick
163be691f3bSpatrick static const char *g_get_dynamic_class_info2_name =
164be691f3bSpatrick "__lldb_apple_objc_v2_get_dynamic_class_info2";
165be691f3bSpatrick
166be691f3bSpatrick static const char *g_get_dynamic_class_info2_body = R"(
167be691f3bSpatrick
168be691f3bSpatrick extern "C" {
169be691f3bSpatrick int printf(const char * format, ...);
170be691f3bSpatrick void free(void *ptr);
171be691f3bSpatrick Class* objc_copyRealizedClassList_nolock(unsigned int *outCount);
172be691f3bSpatrick const char* objc_debug_class_getNameRaw(Class cls);
173be691f3bSpatrick }
174be691f3bSpatrick
175be691f3bSpatrick #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
176be691f3bSpatrick
177be691f3bSpatrick struct ClassInfo
178be691f3bSpatrick {
179be691f3bSpatrick Class isa;
180be691f3bSpatrick uint32_t hash;
181be691f3bSpatrick } __attribute__((__packed__));
182be691f3bSpatrick
183be691f3bSpatrick uint32_t
184be691f3bSpatrick __lldb_apple_objc_v2_get_dynamic_class_info2(void *gdb_objc_realized_classes_ptr,
185be691f3bSpatrick void *class_infos_ptr,
186be691f3bSpatrick uint32_t class_infos_byte_size,
187be691f3bSpatrick uint32_t should_log)
188be691f3bSpatrick {
189be691f3bSpatrick DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
190be691f3bSpatrick DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
191be691f3bSpatrick
192be691f3bSpatrick const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
193be691f3bSpatrick DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
194be691f3bSpatrick
195be691f3bSpatrick ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
196be691f3bSpatrick
197be691f3bSpatrick uint32_t count = 0;
198be691f3bSpatrick Class* realized_class_list = objc_copyRealizedClassList_nolock(&count);
199be691f3bSpatrick DEBUG_PRINTF ("count = %u\n", count);
200be691f3bSpatrick
201be691f3bSpatrick uint32_t idx = 0;
202*f6aab3d8Srobert for (uint32_t i=0; i<count; ++i)
203be691f3bSpatrick {
204be691f3bSpatrick if (idx < max_class_infos)
205be691f3bSpatrick {
206be691f3bSpatrick Class isa = realized_class_list[i];
207be691f3bSpatrick const char *name_ptr = objc_debug_class_getNameRaw(isa);
208*f6aab3d8Srobert if (!name_ptr)
209be691f3bSpatrick continue;
210be691f3bSpatrick const char *s = name_ptr;
211be691f3bSpatrick uint32_t h = 5381;
212be691f3bSpatrick for (unsigned char c = *s; c; c = *++s)
213be691f3bSpatrick h = ((h << 5) + h) + c;
214be691f3bSpatrick class_infos[idx].hash = h;
215be691f3bSpatrick class_infos[idx].isa = isa;
216be691f3bSpatrick DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);
217be691f3bSpatrick }
218be691f3bSpatrick idx++;
219be691f3bSpatrick }
220be691f3bSpatrick
221be691f3bSpatrick if (idx < max_class_infos)
222be691f3bSpatrick {
223be691f3bSpatrick class_infos[idx].isa = NULL;
224be691f3bSpatrick class_infos[idx].hash = 0;
225be691f3bSpatrick }
226be691f3bSpatrick
227be691f3bSpatrick free(realized_class_list);
228be691f3bSpatrick return count;
229be691f3bSpatrick }
230be691f3bSpatrick )";
231be691f3bSpatrick
232*f6aab3d8Srobert static const char *g_get_dynamic_class_info3_name =
233*f6aab3d8Srobert "__lldb_apple_objc_v2_get_dynamic_class_info3";
234*f6aab3d8Srobert
235*f6aab3d8Srobert static const char *g_get_dynamic_class_info3_body = R"(
236*f6aab3d8Srobert
237*f6aab3d8Srobert extern "C" {
238*f6aab3d8Srobert int printf(const char * format, ...);
239*f6aab3d8Srobert void free(void *ptr);
240*f6aab3d8Srobert size_t objc_getRealizedClassList_trylock(Class *buffer, size_t len);
241*f6aab3d8Srobert const char* objc_debug_class_getNameRaw(Class cls);
242*f6aab3d8Srobert const char* class_getName(Class cls);
243*f6aab3d8Srobert }
244*f6aab3d8Srobert
245*f6aab3d8Srobert #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
246*f6aab3d8Srobert
247*f6aab3d8Srobert struct ClassInfo
248*f6aab3d8Srobert {
249*f6aab3d8Srobert Class isa;
250*f6aab3d8Srobert uint32_t hash;
251*f6aab3d8Srobert } __attribute__((__packed__));
252*f6aab3d8Srobert
253*f6aab3d8Srobert uint32_t
254*f6aab3d8Srobert __lldb_apple_objc_v2_get_dynamic_class_info3(void *gdb_objc_realized_classes_ptr,
255*f6aab3d8Srobert void *class_infos_ptr,
256*f6aab3d8Srobert uint32_t class_infos_byte_size,
257*f6aab3d8Srobert void *class_buffer,
258*f6aab3d8Srobert uint32_t class_buffer_len,
259*f6aab3d8Srobert uint32_t should_log)
260*f6aab3d8Srobert {
261*f6aab3d8Srobert DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
262*f6aab3d8Srobert DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
263*f6aab3d8Srobert
264*f6aab3d8Srobert const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
265*f6aab3d8Srobert DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);
266*f6aab3d8Srobert
267*f6aab3d8Srobert ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
268*f6aab3d8Srobert
269*f6aab3d8Srobert Class *realized_class_list = (Class*)class_buffer;
270*f6aab3d8Srobert
271*f6aab3d8Srobert uint32_t count = objc_getRealizedClassList_trylock(realized_class_list,
272*f6aab3d8Srobert class_buffer_len);
273*f6aab3d8Srobert DEBUG_PRINTF ("count = %u\n", count);
274*f6aab3d8Srobert
275*f6aab3d8Srobert uint32_t idx = 0;
276*f6aab3d8Srobert for (uint32_t i=0; i<count; ++i)
277*f6aab3d8Srobert {
278*f6aab3d8Srobert if (idx < max_class_infos)
279*f6aab3d8Srobert {
280*f6aab3d8Srobert Class isa = realized_class_list[i];
281*f6aab3d8Srobert const char *name_ptr = objc_debug_class_getNameRaw(isa);
282*f6aab3d8Srobert if (!name_ptr) {
283*f6aab3d8Srobert class_getName(isa); // Realize name of lazy classes.
284*f6aab3d8Srobert name_ptr = objc_debug_class_getNameRaw(isa);
285*f6aab3d8Srobert }
286*f6aab3d8Srobert if (!name_ptr)
287*f6aab3d8Srobert continue;
288*f6aab3d8Srobert const char *s = name_ptr;
289*f6aab3d8Srobert uint32_t h = 5381;
290*f6aab3d8Srobert for (unsigned char c = *s; c; c = *++s)
291*f6aab3d8Srobert h = ((h << 5) + h) + c;
292*f6aab3d8Srobert class_infos[idx].hash = h;
293*f6aab3d8Srobert class_infos[idx].isa = isa;
294*f6aab3d8Srobert DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);
295*f6aab3d8Srobert }
296*f6aab3d8Srobert idx++;
297*f6aab3d8Srobert }
298*f6aab3d8Srobert
299*f6aab3d8Srobert if (idx < max_class_infos)
300*f6aab3d8Srobert {
301*f6aab3d8Srobert class_infos[idx].isa = NULL;
302*f6aab3d8Srobert class_infos[idx].hash = 0;
303*f6aab3d8Srobert }
304*f6aab3d8Srobert
305*f6aab3d8Srobert return count;
306*f6aab3d8Srobert }
307*f6aab3d8Srobert )";
308*f6aab3d8Srobert
309061da546Spatrick // We'll substitute in class_getName or class_getNameRaw depending
310061da546Spatrick // on which is present.
311061da546Spatrick static const char *g_shared_cache_class_name_funcptr = R"(
312061da546Spatrick extern "C"
313061da546Spatrick {
314061da546Spatrick const char *%s(void *objc_class);
315061da546Spatrick const char *(*class_name_lookup_func)(void *) = %s;
316061da546Spatrick }
317061da546Spatrick )";
318061da546Spatrick
319061da546Spatrick static const char *g_get_shared_cache_class_info_name =
320061da546Spatrick "__lldb_apple_objc_v2_get_shared_cache_class_info";
321be691f3bSpatrick
322061da546Spatrick static const char *g_get_shared_cache_class_info_body = R"(
323061da546Spatrick
324061da546Spatrick extern "C"
325061da546Spatrick {
326061da546Spatrick size_t strlen(const char *);
327061da546Spatrick char *strncpy (char * s1, const char * s2, size_t n);
328061da546Spatrick int printf(const char * format, ...);
329061da546Spatrick }
330061da546Spatrick
331061da546Spatrick #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
332061da546Spatrick
333061da546Spatrick
334061da546Spatrick struct objc_classheader_t {
335061da546Spatrick int32_t clsOffset;
336061da546Spatrick int32_t hiOffset;
337061da546Spatrick };
338061da546Spatrick
339be691f3bSpatrick struct objc_classheader_v16_t {
340be691f3bSpatrick uint64_t isDuplicate : 1,
341be691f3bSpatrick objectCacheOffset : 47, // Offset from the shared cache base
342be691f3bSpatrick dylibObjCIndex : 16;
343be691f3bSpatrick };
344be691f3bSpatrick
345061da546Spatrick struct objc_clsopt_t {
346061da546Spatrick uint32_t capacity;
347061da546Spatrick uint32_t occupied;
348061da546Spatrick uint32_t shift;
349061da546Spatrick uint32_t mask;
350061da546Spatrick uint32_t zero;
351061da546Spatrick uint32_t unused;
352061da546Spatrick uint64_t salt;
353061da546Spatrick uint32_t scramble[256];
354061da546Spatrick uint8_t tab[0]; // tab[mask+1]
355061da546Spatrick // uint8_t checkbytes[capacity];
356061da546Spatrick // int32_t offset[capacity];
357061da546Spatrick // objc_classheader_t clsOffsets[capacity];
358061da546Spatrick // uint32_t duplicateCount;
359061da546Spatrick // objc_classheader_t duplicateOffsets[duplicateCount];
360061da546Spatrick };
361061da546Spatrick
362be691f3bSpatrick struct objc_clsopt_v16_t {
363be691f3bSpatrick uint32_t version;
364be691f3bSpatrick uint32_t capacity;
365be691f3bSpatrick uint32_t occupied;
366be691f3bSpatrick uint32_t shift;
367be691f3bSpatrick uint32_t mask;
368*f6aab3d8Srobert uint32_t zero;
369be691f3bSpatrick uint64_t salt;
370be691f3bSpatrick uint32_t scramble[256];
371be691f3bSpatrick uint8_t tab[0]; // tab[mask+1]
372be691f3bSpatrick // uint8_t checkbytes[capacity];
373be691f3bSpatrick // int32_t offset[capacity];
374be691f3bSpatrick // objc_classheader_t clsOffsets[capacity];
375be691f3bSpatrick // uint32_t duplicateCount;
376be691f3bSpatrick // objc_classheader_t duplicateOffsets[duplicateCount];
377be691f3bSpatrick };
378be691f3bSpatrick
379061da546Spatrick struct objc_opt_t {
380061da546Spatrick uint32_t version;
381061da546Spatrick int32_t selopt_offset;
382061da546Spatrick int32_t headeropt_offset;
383061da546Spatrick int32_t clsopt_offset;
384061da546Spatrick };
385061da546Spatrick
386061da546Spatrick struct objc_opt_v14_t {
387061da546Spatrick uint32_t version;
388061da546Spatrick uint32_t flags;
389061da546Spatrick int32_t selopt_offset;
390061da546Spatrick int32_t headeropt_offset;
391061da546Spatrick int32_t clsopt_offset;
392061da546Spatrick };
393061da546Spatrick
394be691f3bSpatrick struct objc_opt_v16_t {
395be691f3bSpatrick uint32_t version;
396be691f3bSpatrick uint32_t flags;
397be691f3bSpatrick int32_t selopt_offset;
398be691f3bSpatrick int32_t headeropt_ro_offset;
399be691f3bSpatrick int32_t unused_clsopt_offset;
400be691f3bSpatrick int32_t unused_protocolopt_offset;
401be691f3bSpatrick int32_t headeropt_rw_offset;
402be691f3bSpatrick int32_t unused_protocolopt2_offset;
403be691f3bSpatrick int32_t largeSharedCachesClassOffset;
404be691f3bSpatrick int32_t largeSharedCachesProtocolOffset;
405be691f3bSpatrick uint64_t relativeMethodSelectorBaseAddressCacheOffset;
406be691f3bSpatrick };
407be691f3bSpatrick
408061da546Spatrick struct ClassInfo
409061da546Spatrick {
410061da546Spatrick Class isa;
411061da546Spatrick uint32_t hash;
412061da546Spatrick } __attribute__((__packed__));
413061da546Spatrick
414061da546Spatrick uint32_t
415061da546Spatrick __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
416be691f3bSpatrick void *shared_cache_base_ptr,
417061da546Spatrick void *class_infos_ptr,
418be691f3bSpatrick uint64_t *relative_selector_offset,
419061da546Spatrick uint32_t class_infos_byte_size,
420061da546Spatrick uint32_t should_log)
421061da546Spatrick {
422be691f3bSpatrick *relative_selector_offset = 0;
423061da546Spatrick uint32_t idx = 0;
424061da546Spatrick DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
425be691f3bSpatrick DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);
426061da546Spatrick DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
427061da546Spatrick DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
428061da546Spatrick if (objc_opt_ro_ptr)
429061da546Spatrick {
430061da546Spatrick const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
431061da546Spatrick const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;
432be691f3bSpatrick const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr;
433be691f3bSpatrick if (objc_opt->version >= 16)
434be691f3bSpatrick {
435be691f3bSpatrick *relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset;
436be691f3bSpatrick DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version);
437be691f3bSpatrick DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags);
438be691f3bSpatrick DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset);
439be691f3bSpatrick DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset);
440be691f3bSpatrick DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset);
441be691f3bSpatrick }
442be691f3bSpatrick else if (objc_opt->version >= 14)
443061da546Spatrick {
444061da546Spatrick DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);
445061da546Spatrick DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);
446061da546Spatrick DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);
447061da546Spatrick DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);
448061da546Spatrick DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);
449061da546Spatrick }
450061da546Spatrick else
451061da546Spatrick {
452061da546Spatrick DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
453061da546Spatrick DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
454061da546Spatrick DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
455061da546Spatrick DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
456061da546Spatrick }
457be691f3bSpatrick
458be691f3bSpatrick if (objc_opt->version == 16)
459be691f3bSpatrick {
460be691f3bSpatrick const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + objc_opt_v16->largeSharedCachesClassOffset);
461be691f3bSpatrick const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
462be691f3bSpatrick
463be691f3bSpatrick DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
464be691f3bSpatrick
465be691f3bSpatrick ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
466be691f3bSpatrick
467be691f3bSpatrick const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
468be691f3bSpatrick const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
469be691f3bSpatrick const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity);
470be691f3bSpatrick
471be691f3bSpatrick DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
472be691f3bSpatrick DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
473be691f3bSpatrick DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
474be691f3bSpatrick
475be691f3bSpatrick for (uint32_t i=0; i<clsopt->capacity; ++i)
476be691f3bSpatrick {
477be691f3bSpatrick const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
478be691f3bSpatrick DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
479be691f3bSpatrick
480be691f3bSpatrick if (classOffsets[i].isDuplicate) {
481be691f3bSpatrick DEBUG_PRINTF("isDuplicate = true\n");
482be691f3bSpatrick continue; // duplicate
483be691f3bSpatrick }
484be691f3bSpatrick
485be691f3bSpatrick if (objectCacheOffset == 0) {
486be691f3bSpatrick DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
487be691f3bSpatrick continue; // invalid offset
488be691f3bSpatrick }
489be691f3bSpatrick
490be691f3bSpatrick if (class_infos && idx < max_class_infos)
491be691f3bSpatrick {
492be691f3bSpatrick class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
493be691f3bSpatrick
494be691f3bSpatrick // Lookup the class name.
495be691f3bSpatrick const char *name = class_name_lookup_func(class_infos[idx].isa);
496be691f3bSpatrick DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
497be691f3bSpatrick
498be691f3bSpatrick // Hash the class name so we don't have to read it.
499be691f3bSpatrick const char *s = name;
500be691f3bSpatrick uint32_t h = 5381;
501be691f3bSpatrick for (unsigned char c = *s; c; c = *++s)
502be691f3bSpatrick {
503be691f3bSpatrick // class_getName demangles swift names and the hash must
504be691f3bSpatrick // be calculated on the mangled name. hash==0 means lldb
505be691f3bSpatrick // will fetch the mangled name and compute the hash in
506be691f3bSpatrick // ParseClassInfoArray.
507be691f3bSpatrick if (c == '.')
508be691f3bSpatrick {
509be691f3bSpatrick h = 0;
510be691f3bSpatrick break;
511be691f3bSpatrick }
512be691f3bSpatrick h = ((h << 5) + h) + c;
513be691f3bSpatrick }
514be691f3bSpatrick class_infos[idx].hash = h;
515be691f3bSpatrick }
516be691f3bSpatrick else
517be691f3bSpatrick {
518be691f3bSpatrick DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
519be691f3bSpatrick }
520be691f3bSpatrick ++idx;
521be691f3bSpatrick }
522be691f3bSpatrick
523be691f3bSpatrick const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
524be691f3bSpatrick const uint32_t duplicate_count = *duplicate_count_ptr;
525be691f3bSpatrick const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);
526be691f3bSpatrick
527be691f3bSpatrick DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
528be691f3bSpatrick DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
529be691f3bSpatrick
530be691f3bSpatrick for (uint32_t i=0; i<duplicate_count; ++i)
531be691f3bSpatrick {
532be691f3bSpatrick const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;
533be691f3bSpatrick DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);
534be691f3bSpatrick
535be691f3bSpatrick if (classOffsets[i].isDuplicate) {
536be691f3bSpatrick DEBUG_PRINTF("isDuplicate = true\n");
537be691f3bSpatrick continue; // duplicate
538be691f3bSpatrick }
539be691f3bSpatrick
540be691f3bSpatrick if (objectCacheOffset == 0) {
541be691f3bSpatrick DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");
542be691f3bSpatrick continue; // invalid offset
543be691f3bSpatrick }
544be691f3bSpatrick
545be691f3bSpatrick if (class_infos && idx < max_class_infos)
546be691f3bSpatrick {
547be691f3bSpatrick class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);
548be691f3bSpatrick
549be691f3bSpatrick // Lookup the class name.
550be691f3bSpatrick const char *name = class_name_lookup_func(class_infos[idx].isa);
551be691f3bSpatrick DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
552be691f3bSpatrick
553be691f3bSpatrick // Hash the class name so we don't have to read it.
554be691f3bSpatrick const char *s = name;
555be691f3bSpatrick uint32_t h = 5381;
556be691f3bSpatrick for (unsigned char c = *s; c; c = *++s)
557be691f3bSpatrick {
558be691f3bSpatrick // class_getName demangles swift names and the hash must
559be691f3bSpatrick // be calculated on the mangled name. hash==0 means lldb
560be691f3bSpatrick // will fetch the mangled name and compute the hash in
561be691f3bSpatrick // ParseClassInfoArray.
562be691f3bSpatrick if (c == '.')
563be691f3bSpatrick {
564be691f3bSpatrick h = 0;
565be691f3bSpatrick break;
566be691f3bSpatrick }
567be691f3bSpatrick h = ((h << 5) + h) + c;
568be691f3bSpatrick }
569be691f3bSpatrick class_infos[idx].hash = h;
570be691f3bSpatrick }
571be691f3bSpatrick }
572be691f3bSpatrick }
573be691f3bSpatrick else if (objc_opt->version >= 12 && objc_opt->version <= 15)
574061da546Spatrick {
575061da546Spatrick const objc_clsopt_t* clsopt = NULL;
576be691f3bSpatrick if (objc_opt->version >= 14)
577061da546Spatrick clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);
578061da546Spatrick else
579061da546Spatrick clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
580061da546Spatrick const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
581061da546Spatrick DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
582061da546Spatrick ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
583061da546Spatrick int32_t invalidEntryOffset = 0;
584061da546Spatrick // this is safe to do because the version field order is invariant
585061da546Spatrick if (objc_opt->version == 12)
586061da546Spatrick invalidEntryOffset = 16;
587061da546Spatrick const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
588061da546Spatrick const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
589061da546Spatrick const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
590061da546Spatrick DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
591061da546Spatrick DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
592061da546Spatrick DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
593061da546Spatrick DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);
594061da546Spatrick for (uint32_t i=0; i<clsopt->capacity; ++i)
595061da546Spatrick {
596061da546Spatrick const int32_t clsOffset = classOffsets[i].clsOffset;
597061da546Spatrick DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);
598061da546Spatrick if (clsOffset & 1)
599061da546Spatrick {
600061da546Spatrick DEBUG_PRINTF("clsOffset & 1\n");
601061da546Spatrick continue; // duplicate
602061da546Spatrick }
603061da546Spatrick else if (clsOffset == invalidEntryOffset)
604061da546Spatrick {
605061da546Spatrick DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");
606061da546Spatrick continue; // invalid offset
607061da546Spatrick }
608061da546Spatrick
609061da546Spatrick if (class_infos && idx < max_class_infos)
610061da546Spatrick {
611061da546Spatrick class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
612061da546Spatrick const char *name = class_name_lookup_func (class_infos[idx].isa);
613061da546Spatrick DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
614061da546Spatrick // Hash the class name so we don't have to read it
615061da546Spatrick const char *s = name;
616061da546Spatrick uint32_t h = 5381;
617061da546Spatrick for (unsigned char c = *s; c; c = *++s)
618061da546Spatrick {
619061da546Spatrick // class_getName demangles swift names and the hash must
620061da546Spatrick // be calculated on the mangled name. hash==0 means lldb
621061da546Spatrick // will fetch the mangled name and compute the hash in
622061da546Spatrick // ParseClassInfoArray.
623061da546Spatrick if (c == '.')
624061da546Spatrick {
625061da546Spatrick h = 0;
626061da546Spatrick break;
627061da546Spatrick }
628061da546Spatrick h = ((h << 5) + h) + c;
629061da546Spatrick }
630061da546Spatrick class_infos[idx].hash = h;
631061da546Spatrick }
632061da546Spatrick else
633061da546Spatrick {
634061da546Spatrick DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
635061da546Spatrick }
636061da546Spatrick ++idx;
637061da546Spatrick }
638061da546Spatrick
639061da546Spatrick const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
640061da546Spatrick const uint32_t duplicate_count = *duplicate_count_ptr;
641061da546Spatrick const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
642061da546Spatrick DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
643061da546Spatrick DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
644061da546Spatrick for (uint32_t i=0; i<duplicate_count; ++i)
645061da546Spatrick {
646061da546Spatrick const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
647061da546Spatrick if (clsOffset & 1)
648061da546Spatrick continue; // duplicate
649061da546Spatrick else if (clsOffset == invalidEntryOffset)
650061da546Spatrick continue; // invalid offset
651061da546Spatrick
652061da546Spatrick if (class_infos && idx < max_class_infos)
653061da546Spatrick {
654061da546Spatrick class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
655061da546Spatrick const char *name = class_name_lookup_func (class_infos[idx].isa);
656061da546Spatrick DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
657061da546Spatrick // Hash the class name so we don't have to read it
658061da546Spatrick const char *s = name;
659061da546Spatrick uint32_t h = 5381;
660061da546Spatrick for (unsigned char c = *s; c; c = *++s)
661061da546Spatrick {
662061da546Spatrick // class_getName demangles swift names and the hash must
663061da546Spatrick // be calculated on the mangled name. hash==0 means lldb
664061da546Spatrick // will fetch the mangled name and compute the hash in
665061da546Spatrick // ParseClassInfoArray.
666061da546Spatrick if (c == '.')
667061da546Spatrick {
668061da546Spatrick h = 0;
669061da546Spatrick break;
670061da546Spatrick }
671061da546Spatrick h = ((h << 5) + h) + c;
672061da546Spatrick }
673061da546Spatrick class_infos[idx].hash = h;
674061da546Spatrick }
675061da546Spatrick ++idx;
676061da546Spatrick }
677061da546Spatrick }
678061da546Spatrick DEBUG_PRINTF ("%u class_infos\n", idx);
679061da546Spatrick DEBUG_PRINTF ("done\n");
680061da546Spatrick }
681061da546Spatrick return idx;
682061da546Spatrick }
683061da546Spatrick
684061da546Spatrick
685061da546Spatrick )";
686061da546Spatrick
687061da546Spatrick static uint64_t
ExtractRuntimeGlobalSymbol(Process * process,ConstString name,const ModuleSP & module_sp,Status & error,bool read_value=true,uint8_t byte_size=0,uint64_t default_value=LLDB_INVALID_ADDRESS,SymbolType sym_type=lldb::eSymbolTypeData)688061da546Spatrick ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
689061da546Spatrick const ModuleSP &module_sp, Status &error,
690061da546Spatrick bool read_value = true, uint8_t byte_size = 0,
691061da546Spatrick uint64_t default_value = LLDB_INVALID_ADDRESS,
692061da546Spatrick SymbolType sym_type = lldb::eSymbolTypeData) {
693061da546Spatrick if (!process) {
694061da546Spatrick error.SetErrorString("no process");
695061da546Spatrick return default_value;
696061da546Spatrick }
697be691f3bSpatrick
698061da546Spatrick if (!module_sp) {
699061da546Spatrick error.SetErrorString("no module");
700061da546Spatrick return default_value;
701061da546Spatrick }
702be691f3bSpatrick
703061da546Spatrick if (!byte_size)
704061da546Spatrick byte_size = process->GetAddressByteSize();
705061da546Spatrick const Symbol *symbol =
706061da546Spatrick module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
707be691f3bSpatrick
708be691f3bSpatrick if (!symbol || !symbol->ValueIsAddress()) {
709061da546Spatrick error.SetErrorString("no symbol");
710061da546Spatrick return default_value;
711061da546Spatrick }
712be691f3bSpatrick
713be691f3bSpatrick lldb::addr_t symbol_load_addr =
714be691f3bSpatrick symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
715be691f3bSpatrick if (symbol_load_addr == LLDB_INVALID_ADDRESS) {
716be691f3bSpatrick error.SetErrorString("symbol address invalid");
717be691f3bSpatrick return default_value;
718061da546Spatrick }
719061da546Spatrick
720be691f3bSpatrick if (read_value)
721be691f3bSpatrick return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size,
722be691f3bSpatrick default_value, error);
723be691f3bSpatrick return symbol_load_addr;
724be691f3bSpatrick }
725be691f3bSpatrick
726be691f3bSpatrick static void RegisterObjCExceptionRecognizer(Process *process);
727061da546Spatrick
AppleObjCRuntimeV2(Process * process,const ModuleSP & objc_module_sp)728061da546Spatrick AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
729061da546Spatrick const ModuleSP &objc_module_sp)
730be691f3bSpatrick : AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp),
731be691f3bSpatrick m_dynamic_class_info_extractor(*this),
732be691f3bSpatrick m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),
733061da546Spatrick m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),
734be691f3bSpatrick m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),
735be691f3bSpatrick m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),
736be691f3bSpatrick m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),
737*f6aab3d8Srobert m_has_objc_getRealizedClassList_trylock(false), m_loaded_objc_opt(false),
738*f6aab3d8Srobert m_non_pointer_isa_cache_up(),
739061da546Spatrick m_tagged_pointer_vendor_up(
740061da546Spatrick TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),
741*f6aab3d8Srobert m_encoding_to_type_sp(), m_CFBoolean_values(),
742*f6aab3d8Srobert m_realized_class_generation_count(0) {
743061da546Spatrick static const ConstString g_gdb_object_getClass("gdb_object_getClass");
744be691f3bSpatrick m_has_object_getClass = HasSymbol(g_gdb_object_getClass);
745be691f3bSpatrick static const ConstString g_objc_copyRealizedClassList(
746be691f3bSpatrick "_ZL33objc_copyRealizedClassList_nolockPj");
747*f6aab3d8Srobert static const ConstString g_objc_getRealizedClassList_trylock(
748*f6aab3d8Srobert "_objc_getRealizedClassList_trylock");
749be691f3bSpatrick m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList);
750*f6aab3d8Srobert m_has_objc_getRealizedClassList_trylock =
751*f6aab3d8Srobert HasSymbol(g_objc_getRealizedClassList_trylock);
752*f6aab3d8Srobert WarnIfNoExpandedSharedCache();
753be691f3bSpatrick RegisterObjCExceptionRecognizer(process);
754061da546Spatrick }
755061da546Spatrick
GetDynamicTypeAndAddress(ValueObject & in_value,lldb::DynamicValueType use_dynamic,TypeAndOrName & class_type_or_name,Address & address,Value::ValueType & value_type)756061da546Spatrick bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
757061da546Spatrick ValueObject &in_value, lldb::DynamicValueType use_dynamic,
758061da546Spatrick TypeAndOrName &class_type_or_name, Address &address,
759061da546Spatrick Value::ValueType &value_type) {
760061da546Spatrick // We should never get here with a null process...
761061da546Spatrick assert(m_process != nullptr);
762061da546Spatrick
763061da546Spatrick // The Runtime is attached to a particular process, you shouldn't pass in a
764061da546Spatrick // value from another process. Note, however, the process might be NULL (e.g.
765061da546Spatrick // if the value was made with SBTarget::EvaluateExpression...) in which case
766061da546Spatrick // it is sufficient if the target's match:
767061da546Spatrick
768061da546Spatrick Process *process = in_value.GetProcessSP().get();
769061da546Spatrick if (process)
770061da546Spatrick assert(process == m_process);
771061da546Spatrick else
772061da546Spatrick assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get());
773061da546Spatrick
774061da546Spatrick class_type_or_name.Clear();
775be691f3bSpatrick value_type = Value::ValueType::Scalar;
776061da546Spatrick
777061da546Spatrick // Make sure we can have a dynamic value before starting...
778061da546Spatrick if (CouldHaveDynamicValue(in_value)) {
779061da546Spatrick // First job, pull out the address at 0 offset from the object That will
780061da546Spatrick // be the ISA pointer.
781061da546Spatrick ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value));
782061da546Spatrick if (objc_class_sp) {
783061da546Spatrick const addr_t object_ptr = in_value.GetPointerValue();
784061da546Spatrick address.SetRawAddress(object_ptr);
785061da546Spatrick
786061da546Spatrick ConstString class_name(objc_class_sp->GetClassName());
787061da546Spatrick class_type_or_name.SetName(class_name);
788061da546Spatrick TypeSP type_sp(objc_class_sp->GetType());
789061da546Spatrick if (type_sp)
790061da546Spatrick class_type_or_name.SetTypeSP(type_sp);
791061da546Spatrick else {
792061da546Spatrick type_sp = LookupInCompleteClassCache(class_name);
793061da546Spatrick if (type_sp) {
794061da546Spatrick objc_class_sp->SetType(type_sp);
795061da546Spatrick class_type_or_name.SetTypeSP(type_sp);
796061da546Spatrick } else {
797061da546Spatrick // try to go for a CompilerType at least
798061da546Spatrick if (auto *vendor = GetDeclVendor()) {
799061da546Spatrick auto types = vendor->FindTypes(class_name, /*max_matches*/ 1);
800061da546Spatrick if (!types.empty())
801061da546Spatrick class_type_or_name.SetCompilerType(types.front());
802061da546Spatrick }
803061da546Spatrick }
804061da546Spatrick }
805061da546Spatrick }
806061da546Spatrick }
807061da546Spatrick return !class_type_or_name.IsEmpty();
808061da546Spatrick }
809061da546Spatrick
810061da546Spatrick // Static Functions
CreateInstance(Process * process,LanguageType language)811061da546Spatrick LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process,
812061da546Spatrick LanguageType language) {
813061da546Spatrick // FIXME: This should be a MacOS or iOS process, and we need to look for the
814061da546Spatrick // OBJC section to make
815061da546Spatrick // sure we aren't using the V1 runtime.
816061da546Spatrick if (language == eLanguageTypeObjC) {
817061da546Spatrick ModuleSP objc_module_sp;
818061da546Spatrick
819061da546Spatrick if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
820061da546Spatrick ObjCRuntimeVersions::eAppleObjC_V2)
821061da546Spatrick return new AppleObjCRuntimeV2(process, objc_module_sp);
822061da546Spatrick return nullptr;
823be691f3bSpatrick }
824061da546Spatrick return nullptr;
825061da546Spatrick }
826061da546Spatrick
827061da546Spatrick static constexpr OptionDefinition g_objc_classtable_dump_options[] = {
828be691f3bSpatrick {LLDB_OPT_SET_ALL,
829be691f3bSpatrick false,
830be691f3bSpatrick "verbose",
831be691f3bSpatrick 'v',
832be691f3bSpatrick OptionParser::eNoArgument,
833be691f3bSpatrick nullptr,
834be691f3bSpatrick {},
835be691f3bSpatrick 0,
836be691f3bSpatrick eArgTypeNone,
837061da546Spatrick "Print ivar and method information in detail"}};
838061da546Spatrick
839061da546Spatrick class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {
840061da546Spatrick public:
841061da546Spatrick class CommandOptions : public Options {
842061da546Spatrick public:
CommandOptions()843061da546Spatrick CommandOptions() : Options(), m_verbose(false, false) {}
844061da546Spatrick
845061da546Spatrick ~CommandOptions() override = default;
846061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)847061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
848061da546Spatrick ExecutionContext *execution_context) override {
849061da546Spatrick Status error;
850061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
851061da546Spatrick switch (short_option) {
852061da546Spatrick case 'v':
853061da546Spatrick m_verbose.SetCurrentValue(true);
854061da546Spatrick m_verbose.SetOptionWasSet();
855061da546Spatrick break;
856061da546Spatrick
857061da546Spatrick default:
858061da546Spatrick error.SetErrorStringWithFormat("unrecognized short option '%c'",
859061da546Spatrick short_option);
860061da546Spatrick break;
861061da546Spatrick }
862061da546Spatrick
863061da546Spatrick return error;
864061da546Spatrick }
865061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)866061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
867061da546Spatrick m_verbose.Clear();
868061da546Spatrick }
869061da546Spatrick
GetDefinitions()870061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
871*f6aab3d8Srobert return llvm::ArrayRef(g_objc_classtable_dump_options);
872061da546Spatrick }
873061da546Spatrick
874061da546Spatrick OptionValueBoolean m_verbose;
875061da546Spatrick };
876061da546Spatrick
CommandObjectObjC_ClassTable_Dump(CommandInterpreter & interpreter)877061da546Spatrick CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter)
878be691f3bSpatrick : CommandObjectParsed(interpreter, "dump",
879be691f3bSpatrick "Dump information on Objective-C classes "
880061da546Spatrick "known to the current process.",
881061da546Spatrick "language objc class-table dump",
882be691f3bSpatrick eCommandRequiresProcess |
883be691f3bSpatrick eCommandProcessMustBeLaunched |
884061da546Spatrick eCommandProcessMustBePaused),
885061da546Spatrick m_options() {
886061da546Spatrick CommandArgumentEntry arg;
887061da546Spatrick CommandArgumentData index_arg;
888061da546Spatrick
889061da546Spatrick // Define the first (and only) variant of this arg.
890061da546Spatrick index_arg.arg_type = eArgTypeRegularExpression;
891061da546Spatrick index_arg.arg_repetition = eArgRepeatOptional;
892061da546Spatrick
893061da546Spatrick // There is only one variant this argument could be; put it into the
894061da546Spatrick // argument entry.
895061da546Spatrick arg.push_back(index_arg);
896061da546Spatrick
897061da546Spatrick // Push the data for the first argument into the m_arguments vector.
898061da546Spatrick m_arguments.push_back(arg);
899061da546Spatrick }
900061da546Spatrick
901061da546Spatrick ~CommandObjectObjC_ClassTable_Dump() override = default;
902061da546Spatrick
GetOptions()903061da546Spatrick Options *GetOptions() override { return &m_options; }
904061da546Spatrick
905061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)906061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
907061da546Spatrick std::unique_ptr<RegularExpression> regex_up;
908061da546Spatrick switch (command.GetArgumentCount()) {
909061da546Spatrick case 0:
910061da546Spatrick break;
911061da546Spatrick case 1: {
912be691f3bSpatrick regex_up =
913be691f3bSpatrick std::make_unique<RegularExpression>(command.GetArgumentAtIndex(0));
914061da546Spatrick if (!regex_up->IsValid()) {
915061da546Spatrick result.AppendError(
916061da546Spatrick "invalid argument - please provide a valid regular expression");
917061da546Spatrick result.SetStatus(lldb::eReturnStatusFailed);
918061da546Spatrick return false;
919061da546Spatrick }
920061da546Spatrick break;
921061da546Spatrick }
922061da546Spatrick default: {
923061da546Spatrick result.AppendError("please provide 0 or 1 arguments");
924061da546Spatrick result.SetStatus(lldb::eReturnStatusFailed);
925061da546Spatrick return false;
926061da546Spatrick }
927061da546Spatrick }
928061da546Spatrick
929061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
930061da546Spatrick ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
931061da546Spatrick if (objc_runtime) {
932061da546Spatrick auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();
933061da546Spatrick auto iterator = iterators_pair.first;
934061da546Spatrick auto &std_out = result.GetOutputStream();
935061da546Spatrick for (; iterator != iterators_pair.second; iterator++) {
936061da546Spatrick if (iterator->second) {
937061da546Spatrick const char *class_name =
938061da546Spatrick iterator->second->GetClassName().AsCString("<unknown>");
939061da546Spatrick if (regex_up && class_name &&
940061da546Spatrick !regex_up->Execute(llvm::StringRef(class_name)))
941061da546Spatrick continue;
942061da546Spatrick std_out.Printf("isa = 0x%" PRIx64, iterator->first);
943061da546Spatrick std_out.Printf(" name = %s", class_name);
944061da546Spatrick std_out.Printf(" instance size = %" PRIu64,
945061da546Spatrick iterator->second->GetInstanceSize());
946061da546Spatrick std_out.Printf(" num ivars = %" PRIuPTR,
947061da546Spatrick (uintptr_t)iterator->second->GetNumIVars());
948061da546Spatrick if (auto superclass = iterator->second->GetSuperclass()) {
949061da546Spatrick std_out.Printf(" superclass = %s",
950061da546Spatrick superclass->GetClassName().AsCString("<unknown>"));
951061da546Spatrick }
952061da546Spatrick std_out.Printf("\n");
953061da546Spatrick if (m_options.m_verbose) {
954061da546Spatrick for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) {
955061da546Spatrick auto ivar = iterator->second->GetIVarAtIndex(i);
956061da546Spatrick std_out.Printf(
957061da546Spatrick " ivar name = %s type = %s size = %" PRIu64
958061da546Spatrick " offset = %" PRId32 "\n",
959061da546Spatrick ivar.m_name.AsCString("<unknown>"),
960061da546Spatrick ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),
961061da546Spatrick ivar.m_size, ivar.m_offset);
962061da546Spatrick }
963be691f3bSpatrick
964061da546Spatrick iterator->second->Describe(
965061da546Spatrick nullptr,
966061da546Spatrick [&std_out](const char *name, const char *type) -> bool {
967061da546Spatrick std_out.Printf(" instance method name = %s type = %s\n",
968061da546Spatrick name, type);
969061da546Spatrick return false;
970061da546Spatrick },
971061da546Spatrick [&std_out](const char *name, const char *type) -> bool {
972061da546Spatrick std_out.Printf(" class method name = %s type = %s\n", name,
973061da546Spatrick type);
974061da546Spatrick return false;
975061da546Spatrick },
976061da546Spatrick nullptr);
977061da546Spatrick }
978061da546Spatrick } else {
979061da546Spatrick if (regex_up && !regex_up->Execute(llvm::StringRef()))
980061da546Spatrick continue;
981061da546Spatrick std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n",
982061da546Spatrick iterator->first);
983061da546Spatrick }
984061da546Spatrick }
985061da546Spatrick result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
986061da546Spatrick return true;
987be691f3bSpatrick }
988061da546Spatrick result.AppendError("current process has no Objective-C runtime loaded");
989061da546Spatrick result.SetStatus(lldb::eReturnStatusFailed);
990061da546Spatrick return false;
991061da546Spatrick }
992061da546Spatrick
993061da546Spatrick CommandOptions m_options;
994061da546Spatrick };
995061da546Spatrick
996061da546Spatrick class CommandObjectMultiwordObjC_TaggedPointer_Info
997061da546Spatrick : public CommandObjectParsed {
998061da546Spatrick public:
CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter & interpreter)999061da546Spatrick CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter)
1000061da546Spatrick : CommandObjectParsed(
1001061da546Spatrick interpreter, "info", "Dump information on a tagged pointer.",
1002061da546Spatrick "language objc tagged-pointer info",
1003061da546Spatrick eCommandRequiresProcess | eCommandProcessMustBeLaunched |
1004061da546Spatrick eCommandProcessMustBePaused) {
1005061da546Spatrick CommandArgumentEntry arg;
1006061da546Spatrick CommandArgumentData index_arg;
1007061da546Spatrick
1008061da546Spatrick // Define the first (and only) variant of this arg.
1009061da546Spatrick index_arg.arg_type = eArgTypeAddress;
1010061da546Spatrick index_arg.arg_repetition = eArgRepeatPlus;
1011061da546Spatrick
1012061da546Spatrick // There is only one variant this argument could be; put it into the
1013061da546Spatrick // argument entry.
1014061da546Spatrick arg.push_back(index_arg);
1015061da546Spatrick
1016061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1017061da546Spatrick m_arguments.push_back(arg);
1018061da546Spatrick }
1019061da546Spatrick
1020061da546Spatrick ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;
1021061da546Spatrick
1022061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1023061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1024061da546Spatrick if (command.GetArgumentCount() == 0) {
1025061da546Spatrick result.AppendError("this command requires arguments");
1026061da546Spatrick result.SetStatus(lldb::eReturnStatusFailed);
1027061da546Spatrick return false;
1028061da546Spatrick }
1029061da546Spatrick
1030061da546Spatrick Process *process = m_exe_ctx.GetProcessPtr();
1031061da546Spatrick ExecutionContext exe_ctx(process);
1032*f6aab3d8Srobert
1033061da546Spatrick ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);
1034*f6aab3d8Srobert if (!objc_runtime) {
1035*f6aab3d8Srobert result.AppendError("current process has no Objective-C runtime loaded");
1036*f6aab3d8Srobert result.SetStatus(lldb::eReturnStatusFailed);
1037*f6aab3d8Srobert return false;
1038*f6aab3d8Srobert }
1039*f6aab3d8Srobert
1040061da546Spatrick ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor =
1041061da546Spatrick objc_runtime->GetTaggedPointerVendor();
1042*f6aab3d8Srobert if (!tagged_ptr_vendor) {
1043*f6aab3d8Srobert result.AppendError("current process has no tagged pointer support");
1044*f6aab3d8Srobert result.SetStatus(lldb::eReturnStatusFailed);
1045*f6aab3d8Srobert return false;
1046*f6aab3d8Srobert }
1047*f6aab3d8Srobert
1048061da546Spatrick for (size_t i = 0; i < command.GetArgumentCount(); i++) {
1049061da546Spatrick const char *arg_str = command.GetArgumentAtIndex(i);
1050061da546Spatrick if (!arg_str)
1051061da546Spatrick continue;
1052*f6aab3d8Srobert
1053061da546Spatrick Status error;
1054061da546Spatrick lldb::addr_t arg_addr = OptionArgParser::ToAddress(
1055061da546Spatrick &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);
1056*f6aab3d8Srobert if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) {
1057*f6aab3d8Srobert result.AppendErrorWithFormatv(
1058*f6aab3d8Srobert "could not convert '{0}' to a valid address\n", arg_str);
1059*f6aab3d8Srobert result.SetStatus(lldb::eReturnStatusFailed);
1060*f6aab3d8Srobert return false;
1061*f6aab3d8Srobert }
1062*f6aab3d8Srobert
1063*f6aab3d8Srobert if (!tagged_ptr_vendor->IsPossibleTaggedPointer(arg_addr)) {
1064*f6aab3d8Srobert result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);
1065061da546Spatrick continue;
1066*f6aab3d8Srobert }
1067*f6aab3d8Srobert
1068061da546Spatrick auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);
1069*f6aab3d8Srobert if (!descriptor_sp) {
1070*f6aab3d8Srobert result.AppendErrorWithFormatv(
1071*f6aab3d8Srobert "could not get class descriptor for {0:x16}\n", arg_addr);
1072*f6aab3d8Srobert result.SetStatus(lldb::eReturnStatusFailed);
1073*f6aab3d8Srobert return false;
1074*f6aab3d8Srobert }
1075*f6aab3d8Srobert
1076061da546Spatrick uint64_t info_bits = 0;
1077061da546Spatrick uint64_t value_bits = 0;
1078061da546Spatrick uint64_t payload = 0;
1079061da546Spatrick if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits,
1080061da546Spatrick &payload)) {
1081*f6aab3d8Srobert result.GetOutputStream().Format(
1082*f6aab3d8Srobert "{0:x} is tagged\n"
1083*f6aab3d8Srobert "\tpayload = {1:x16}\n"
1084*f6aab3d8Srobert "\tvalue = {2:x16}\n"
1085*f6aab3d8Srobert "\tinfo bits = {3:x16}\n"
1086*f6aab3d8Srobert "\tclass = {4}\n",
1087*f6aab3d8Srobert arg_addr, payload, value_bits, info_bits,
1088061da546Spatrick descriptor_sp->GetClassName().AsCString("<unknown>"));
1089061da546Spatrick } else {
1090*f6aab3d8Srobert result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);
1091061da546Spatrick }
1092061da546Spatrick }
1093*f6aab3d8Srobert
1094061da546Spatrick result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
1095061da546Spatrick return true;
1096be691f3bSpatrick }
1097061da546Spatrick };
1098061da546Spatrick
1099061da546Spatrick class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword {
1100061da546Spatrick public:
CommandObjectMultiwordObjC_ClassTable(CommandInterpreter & interpreter)1101061da546Spatrick CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)
1102061da546Spatrick : CommandObjectMultiword(
1103061da546Spatrick interpreter, "class-table",
1104061da546Spatrick "Commands for operating on the Objective-C class table.",
1105061da546Spatrick "class-table <subcommand> [<subcommand-options>]") {
1106061da546Spatrick LoadSubCommand(
1107061da546Spatrick "dump",
1108061da546Spatrick CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter)));
1109061da546Spatrick }
1110061da546Spatrick
1111061da546Spatrick ~CommandObjectMultiwordObjC_ClassTable() override = default;
1112061da546Spatrick };
1113061da546Spatrick
1114061da546Spatrick class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword {
1115061da546Spatrick public:
CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter & interpreter)1116061da546Spatrick CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)
1117061da546Spatrick : CommandObjectMultiword(
1118061da546Spatrick interpreter, "tagged-pointer",
1119061da546Spatrick "Commands for operating on Objective-C tagged pointers.",
1120061da546Spatrick "class-table <subcommand> [<subcommand-options>]") {
1121061da546Spatrick LoadSubCommand(
1122061da546Spatrick "info",
1123061da546Spatrick CommandObjectSP(
1124061da546Spatrick new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter)));
1125061da546Spatrick }
1126061da546Spatrick
1127061da546Spatrick ~CommandObjectMultiwordObjC_TaggedPointer() override = default;
1128061da546Spatrick };
1129061da546Spatrick
1130061da546Spatrick class CommandObjectMultiwordObjC : public CommandObjectMultiword {
1131061da546Spatrick public:
CommandObjectMultiwordObjC(CommandInterpreter & interpreter)1132061da546Spatrick CommandObjectMultiwordObjC(CommandInterpreter &interpreter)
1133061da546Spatrick : CommandObjectMultiword(
1134061da546Spatrick interpreter, "objc",
1135061da546Spatrick "Commands for operating on the Objective-C language runtime.",
1136061da546Spatrick "objc <subcommand> [<subcommand-options>]") {
1137061da546Spatrick LoadSubCommand("class-table",
1138061da546Spatrick CommandObjectSP(
1139061da546Spatrick new CommandObjectMultiwordObjC_ClassTable(interpreter)));
1140061da546Spatrick LoadSubCommand("tagged-pointer",
1141061da546Spatrick CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer(
1142061da546Spatrick interpreter)));
1143061da546Spatrick }
1144061da546Spatrick
1145061da546Spatrick ~CommandObjectMultiwordObjC() override = default;
1146061da546Spatrick };
1147061da546Spatrick
Initialize()1148061da546Spatrick void AppleObjCRuntimeV2::Initialize() {
1149061da546Spatrick PluginManager::RegisterPlugin(
1150061da546Spatrick GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 2",
1151061da546Spatrick CreateInstance,
1152061da546Spatrick [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
1153061da546Spatrick return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));
1154061da546Spatrick },
1155061da546Spatrick GetBreakpointExceptionPrecondition);
1156061da546Spatrick }
1157061da546Spatrick
Terminate()1158061da546Spatrick void AppleObjCRuntimeV2::Terminate() {
1159061da546Spatrick PluginManager::UnregisterPlugin(CreateInstance);
1160061da546Spatrick }
1161061da546Spatrick
1162061da546Spatrick BreakpointResolverSP
CreateExceptionResolver(const BreakpointSP & bkpt,bool catch_bp,bool throw_bp)1163dda28197Spatrick AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt,
1164dda28197Spatrick bool catch_bp, bool throw_bp) {
1165061da546Spatrick BreakpointResolverSP resolver_sp;
1166061da546Spatrick
1167061da546Spatrick if (throw_bp)
1168061da546Spatrick resolver_sp = std::make_shared<BreakpointResolverName>(
1169061da546Spatrick bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
1170061da546Spatrick eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
1171061da546Spatrick eLazyBoolNo);
1172061da546Spatrick // FIXME: We don't do catch breakpoints for ObjC yet.
1173061da546Spatrick // Should there be some way for the runtime to specify what it can do in this
1174061da546Spatrick // regard?
1175061da546Spatrick return resolver_sp;
1176061da546Spatrick }
1177061da546Spatrick
1178be691f3bSpatrick llvm::Expected<std::unique_ptr<UtilityFunction>>
CreateObjectChecker(std::string name,ExecutionContext & exe_ctx)1179be691f3bSpatrick AppleObjCRuntimeV2::CreateObjectChecker(std::string name,
1180be691f3bSpatrick ExecutionContext &exe_ctx) {
1181061da546Spatrick char check_function_code[2048];
1182061da546Spatrick
1183061da546Spatrick int len = 0;
1184061da546Spatrick if (m_has_object_getClass) {
1185061da546Spatrick len = ::snprintf(check_function_code, sizeof(check_function_code), R"(
1186061da546Spatrick extern "C" void *gdb_object_getClass(void *);
1187061da546Spatrick extern "C" int printf(const char *format, ...);
1188061da546Spatrick extern "C" void
1189061da546Spatrick %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {
1190061da546Spatrick if ($__lldb_arg_obj == (void *)0)
1191061da546Spatrick return; // nil is ok
1192061da546Spatrick if (!gdb_object_getClass($__lldb_arg_obj)) {
1193061da546Spatrick *((volatile int *)0) = 'ocgc';
1194061da546Spatrick } else if ($__lldb_arg_selector != (void *)0) {
1195061da546Spatrick signed char $responds = (signed char)
1196061da546Spatrick [(id)$__lldb_arg_obj respondsToSelector:
1197061da546Spatrick (void *) $__lldb_arg_selector];
1198061da546Spatrick if ($responds == (signed char) 0)
1199061da546Spatrick *((volatile int *)0) = 'ocgc';
1200061da546Spatrick }
1201be691f3bSpatrick })",
1202be691f3bSpatrick name.c_str());
1203061da546Spatrick } else {
1204061da546Spatrick len = ::snprintf(check_function_code, sizeof(check_function_code), R"(
1205061da546Spatrick extern "C" void *gdb_class_getClass(void *);
1206061da546Spatrick extern "C" int printf(const char *format, ...);
1207061da546Spatrick extern "C" void
1208061da546Spatrick %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {
1209061da546Spatrick if ($__lldb_arg_obj == (void *)0)
1210061da546Spatrick return; // nil is ok
1211061da546Spatrick void **$isa_ptr = (void **)$__lldb_arg_obj;
1212061da546Spatrick if (*$isa_ptr == (void *)0 ||
1213061da546Spatrick !gdb_class_getClass(*$isa_ptr))
1214061da546Spatrick *((volatile int *)0) = 'ocgc';
1215061da546Spatrick else if ($__lldb_arg_selector != (void *)0) {
1216061da546Spatrick signed char $responds = (signed char)
1217061da546Spatrick [(id)$__lldb_arg_obj respondsToSelector:
1218061da546Spatrick (void *) $__lldb_arg_selector];
1219061da546Spatrick if ($responds == (signed char) 0)
1220061da546Spatrick *((volatile int *)0) = 'ocgc';
1221061da546Spatrick }
1222be691f3bSpatrick })",
1223be691f3bSpatrick name.c_str());
1224061da546Spatrick }
1225061da546Spatrick
1226061da546Spatrick assert(len < (int)sizeof(check_function_code));
1227061da546Spatrick UNUSED_IF_ASSERT_DISABLED(len);
1228061da546Spatrick
1229be691f3bSpatrick return GetTargetRef().CreateUtilityFunction(check_function_code, name,
1230be691f3bSpatrick eLanguageTypeC, exe_ctx);
1231061da546Spatrick }
1232061da546Spatrick
GetByteOffsetForIvar(CompilerType & parent_ast_type,const char * ivar_name)1233061da546Spatrick size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,
1234061da546Spatrick const char *ivar_name) {
1235061da546Spatrick uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;
1236061da546Spatrick
1237dda28197Spatrick ConstString class_name = parent_ast_type.GetTypeName();
1238dda28197Spatrick if (!class_name.IsEmpty() && ivar_name && ivar_name[0]) {
1239061da546Spatrick // Make the objective C V2 mangled name for the ivar offset from the class
1240061da546Spatrick // name and ivar name
1241061da546Spatrick std::string buffer("OBJC_IVAR_$_");
1242dda28197Spatrick buffer.append(class_name.AsCString());
1243061da546Spatrick buffer.push_back('.');
1244061da546Spatrick buffer.append(ivar_name);
1245061da546Spatrick ConstString ivar_const_str(buffer.c_str());
1246061da546Spatrick
1247061da546Spatrick // Try to get the ivar offset address from the symbol table first using the
1248061da546Spatrick // name we created above
1249061da546Spatrick SymbolContextList sc_list;
1250061da546Spatrick Target &target = m_process->GetTarget();
1251061da546Spatrick target.GetImages().FindSymbolsWithNameAndType(ivar_const_str,
1252061da546Spatrick eSymbolTypeObjCIVar, sc_list);
1253061da546Spatrick
1254061da546Spatrick addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
1255061da546Spatrick
1256061da546Spatrick Status error;
1257061da546Spatrick SymbolContext ivar_offset_symbol;
1258061da546Spatrick if (sc_list.GetSize() == 1 &&
1259061da546Spatrick sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {
1260061da546Spatrick if (ivar_offset_symbol.symbol)
1261061da546Spatrick ivar_offset_address =
1262061da546Spatrick ivar_offset_symbol.symbol->GetLoadAddress(&target);
1263061da546Spatrick }
1264061da546Spatrick
1265061da546Spatrick // If we didn't get the ivar offset address from the symbol table, fall
1266061da546Spatrick // back to getting it from the runtime
1267061da546Spatrick if (ivar_offset_address == LLDB_INVALID_ADDRESS)
1268061da546Spatrick ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);
1269061da546Spatrick
1270061da546Spatrick if (ivar_offset_address != LLDB_INVALID_ADDRESS)
1271061da546Spatrick ivar_offset = m_process->ReadUnsignedIntegerFromMemory(
1272061da546Spatrick ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error);
1273061da546Spatrick }
1274061da546Spatrick return ivar_offset;
1275061da546Spatrick }
1276061da546Spatrick
1277061da546Spatrick // tagged pointers are special not-a-real-pointer values that contain both type
1278061da546Spatrick // and value information this routine attempts to check with as little
1279061da546Spatrick // computational effort as possible whether something could possibly be a
1280061da546Spatrick // tagged pointer - false positives are possible but false negatives shouldn't
IsTaggedPointer(addr_t ptr)1281061da546Spatrick bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) {
1282061da546Spatrick if (!m_tagged_pointer_vendor_up)
1283061da546Spatrick return false;
1284061da546Spatrick return m_tagged_pointer_vendor_up->IsPossibleTaggedPointer(ptr);
1285061da546Spatrick }
1286061da546Spatrick
1287061da546Spatrick class RemoteNXMapTable {
1288061da546Spatrick public:
RemoteNXMapTable()1289be691f3bSpatrick RemoteNXMapTable() : m_end_iterator(*this, -1) {}
1290061da546Spatrick
Dump()1291061da546Spatrick void Dump() {
1292061da546Spatrick printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);
1293061da546Spatrick printf("RemoteNXMapTable.m_count = %u\n", m_count);
1294061da546Spatrick printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n",
1295061da546Spatrick m_num_buckets_minus_one);
1296061da546Spatrick printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);
1297061da546Spatrick }
1298061da546Spatrick
ParseHeader(Process * process,lldb::addr_t load_addr)1299061da546Spatrick bool ParseHeader(Process *process, lldb::addr_t load_addr) {
1300061da546Spatrick m_process = process;
1301061da546Spatrick m_load_addr = load_addr;
1302061da546Spatrick m_map_pair_size = m_process->GetAddressByteSize() * 2;
1303061da546Spatrick m_invalid_key =
1304061da546Spatrick m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
1305061da546Spatrick Status err;
1306061da546Spatrick
1307061da546Spatrick // This currently holds true for all platforms we support, but we might
1308061da546Spatrick // need to change this to use get the actually byte size of "unsigned" from
1309061da546Spatrick // the target AST...
1310061da546Spatrick const uint32_t unsigned_byte_size = sizeof(uint32_t);
1311061da546Spatrick // Skip the prototype as we don't need it (const struct
1312061da546Spatrick // +NXMapTablePrototype *prototype)
1313061da546Spatrick
1314061da546Spatrick bool success = true;
1315061da546Spatrick if (load_addr == LLDB_INVALID_ADDRESS)
1316061da546Spatrick success = false;
1317061da546Spatrick else {
1318061da546Spatrick lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();
1319061da546Spatrick
1320061da546Spatrick // unsigned count;
1321061da546Spatrick m_count = m_process->ReadUnsignedIntegerFromMemory(
1322061da546Spatrick cursor, unsigned_byte_size, 0, err);
1323061da546Spatrick if (m_count) {
1324061da546Spatrick cursor += unsigned_byte_size;
1325061da546Spatrick
1326061da546Spatrick // unsigned nbBucketsMinusOne;
1327061da546Spatrick m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(
1328061da546Spatrick cursor, unsigned_byte_size, 0, err);
1329061da546Spatrick cursor += unsigned_byte_size;
1330061da546Spatrick
1331061da546Spatrick // void *buckets;
1332061da546Spatrick m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);
1333061da546Spatrick
1334061da546Spatrick success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;
1335061da546Spatrick }
1336061da546Spatrick }
1337061da546Spatrick
1338061da546Spatrick if (!success) {
1339061da546Spatrick m_count = 0;
1340061da546Spatrick m_num_buckets_minus_one = 0;
1341061da546Spatrick m_buckets_ptr = LLDB_INVALID_ADDRESS;
1342061da546Spatrick }
1343061da546Spatrick return success;
1344061da546Spatrick }
1345061da546Spatrick
1346061da546Spatrick // const_iterator mimics NXMapState and its code comes from NXInitMapState
1347061da546Spatrick // and NXNextMapState.
1348061da546Spatrick typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;
1349061da546Spatrick
1350061da546Spatrick friend class const_iterator;
1351061da546Spatrick class const_iterator {
1352061da546Spatrick public:
const_iterator(RemoteNXMapTable & parent,int index)1353061da546Spatrick const_iterator(RemoteNXMapTable &parent, int index)
1354061da546Spatrick : m_parent(parent), m_index(index) {
1355061da546Spatrick AdvanceToValidIndex();
1356061da546Spatrick }
1357061da546Spatrick
const_iterator(const const_iterator & rhs)1358061da546Spatrick const_iterator(const const_iterator &rhs)
1359061da546Spatrick : m_parent(rhs.m_parent), m_index(rhs.m_index) {
1360061da546Spatrick // AdvanceToValidIndex() has been called by rhs already.
1361061da546Spatrick }
1362061da546Spatrick
operator =(const const_iterator & rhs)1363061da546Spatrick const_iterator &operator=(const const_iterator &rhs) {
1364061da546Spatrick // AdvanceToValidIndex() has been called by rhs already.
1365061da546Spatrick assert(&m_parent == &rhs.m_parent);
1366061da546Spatrick m_index = rhs.m_index;
1367061da546Spatrick return *this;
1368061da546Spatrick }
1369061da546Spatrick
operator ==(const const_iterator & rhs) const1370061da546Spatrick bool operator==(const const_iterator &rhs) const {
1371061da546Spatrick if (&m_parent != &rhs.m_parent)
1372061da546Spatrick return false;
1373061da546Spatrick if (m_index != rhs.m_index)
1374061da546Spatrick return false;
1375061da546Spatrick
1376061da546Spatrick return true;
1377061da546Spatrick }
1378061da546Spatrick
operator !=(const const_iterator & rhs) const1379061da546Spatrick bool operator!=(const const_iterator &rhs) const {
1380061da546Spatrick return !(operator==(rhs));
1381061da546Spatrick }
1382061da546Spatrick
operator ++()1383061da546Spatrick const_iterator &operator++() {
1384061da546Spatrick AdvanceToValidIndex();
1385061da546Spatrick return *this;
1386061da546Spatrick }
1387061da546Spatrick
operator *() const1388061da546Spatrick const element operator*() const {
1389061da546Spatrick if (m_index == -1) {
1390061da546Spatrick // TODO find a way to make this an error, but not an assert
1391061da546Spatrick return element();
1392061da546Spatrick }
1393061da546Spatrick
1394061da546Spatrick lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1395061da546Spatrick size_t map_pair_size = m_parent.m_map_pair_size;
1396061da546Spatrick lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1397061da546Spatrick
1398061da546Spatrick Status err;
1399061da546Spatrick
1400061da546Spatrick lldb::addr_t key =
1401061da546Spatrick m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1402061da546Spatrick if (!err.Success())
1403061da546Spatrick return element();
1404061da546Spatrick lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(
1405061da546Spatrick pair_ptr + m_parent.m_process->GetAddressByteSize(), err);
1406061da546Spatrick if (!err.Success())
1407061da546Spatrick return element();
1408061da546Spatrick
1409061da546Spatrick std::string key_string;
1410061da546Spatrick
1411061da546Spatrick m_parent.m_process->ReadCStringFromMemory(key, key_string, err);
1412061da546Spatrick if (!err.Success())
1413061da546Spatrick return element();
1414061da546Spatrick
1415061da546Spatrick return element(ConstString(key_string.c_str()),
1416061da546Spatrick (ObjCLanguageRuntime::ObjCISA)value);
1417061da546Spatrick }
1418061da546Spatrick
1419061da546Spatrick private:
AdvanceToValidIndex()1420061da546Spatrick void AdvanceToValidIndex() {
1421061da546Spatrick if (m_index == -1)
1422061da546Spatrick return;
1423061da546Spatrick
1424061da546Spatrick const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1425061da546Spatrick const size_t map_pair_size = m_parent.m_map_pair_size;
1426061da546Spatrick const lldb::addr_t invalid_key = m_parent.m_invalid_key;
1427061da546Spatrick Status err;
1428061da546Spatrick
1429061da546Spatrick while (m_index--) {
1430061da546Spatrick lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1431061da546Spatrick lldb::addr_t key =
1432061da546Spatrick m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1433061da546Spatrick
1434061da546Spatrick if (!err.Success()) {
1435061da546Spatrick m_index = -1;
1436061da546Spatrick return;
1437061da546Spatrick }
1438061da546Spatrick
1439061da546Spatrick if (key != invalid_key)
1440061da546Spatrick return;
1441061da546Spatrick }
1442061da546Spatrick }
1443061da546Spatrick RemoteNXMapTable &m_parent;
1444061da546Spatrick int m_index;
1445061da546Spatrick };
1446061da546Spatrick
begin()1447061da546Spatrick const_iterator begin() {
1448061da546Spatrick return const_iterator(*this, m_num_buckets_minus_one + 1);
1449061da546Spatrick }
1450061da546Spatrick
end()1451061da546Spatrick const_iterator end() { return m_end_iterator; }
1452061da546Spatrick
GetCount() const1453061da546Spatrick uint32_t GetCount() const { return m_count; }
1454061da546Spatrick
GetBucketCount() const1455061da546Spatrick uint32_t GetBucketCount() const { return m_num_buckets_minus_one; }
1456061da546Spatrick
GetBucketDataPointer() const1457061da546Spatrick lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; }
1458061da546Spatrick
GetTableLoadAddress() const1459061da546Spatrick lldb::addr_t GetTableLoadAddress() const { return m_load_addr; }
1460061da546Spatrick
1461061da546Spatrick private:
1462061da546Spatrick // contents of _NXMapTable struct
1463be691f3bSpatrick uint32_t m_count = 0;
1464be691f3bSpatrick uint32_t m_num_buckets_minus_one = 0;
1465be691f3bSpatrick lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS;
1466be691f3bSpatrick lldb_private::Process *m_process = nullptr;
1467061da546Spatrick const_iterator m_end_iterator;
1468be691f3bSpatrick lldb::addr_t m_load_addr = LLDB_INVALID_ADDRESS;
1469be691f3bSpatrick size_t m_map_pair_size = 0;
1470be691f3bSpatrick lldb::addr_t m_invalid_key = 0;
1471061da546Spatrick };
1472061da546Spatrick
1473be691f3bSpatrick AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() = default;
1474061da546Spatrick
UpdateSignature(const RemoteNXMapTable & hash_table)1475061da546Spatrick void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature(
1476061da546Spatrick const RemoteNXMapTable &hash_table) {
1477061da546Spatrick m_count = hash_table.GetCount();
1478061da546Spatrick m_num_buckets = hash_table.GetBucketCount();
1479061da546Spatrick m_buckets_ptr = hash_table.GetBucketDataPointer();
1480061da546Spatrick }
1481061da546Spatrick
NeedsUpdate(Process * process,AppleObjCRuntimeV2 * runtime,RemoteNXMapTable & hash_table)1482061da546Spatrick bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate(
1483061da546Spatrick Process *process, AppleObjCRuntimeV2 *runtime,
1484061da546Spatrick RemoteNXMapTable &hash_table) {
1485061da546Spatrick if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) {
1486061da546Spatrick return false; // Failed to parse the header, no need to update anything
1487061da546Spatrick }
1488061da546Spatrick
1489061da546Spatrick // Check with out current signature and return true if the count, number of
1490061da546Spatrick // buckets or the hash table address changes.
1491061da546Spatrick if (m_count == hash_table.GetCount() &&
1492061da546Spatrick m_num_buckets == hash_table.GetBucketCount() &&
1493061da546Spatrick m_buckets_ptr == hash_table.GetBucketDataPointer()) {
1494061da546Spatrick // Hash table hasn't changed
1495061da546Spatrick return false;
1496061da546Spatrick }
1497061da546Spatrick // Hash table data has changed, we need to update
1498061da546Spatrick return true;
1499061da546Spatrick }
1500061da546Spatrick
1501061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptorFromISA(ObjCISA isa)1502061da546Spatrick AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {
1503061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
1504be691f3bSpatrick if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())
1505be691f3bSpatrick class_descriptor_sp = non_pointer_isa_cache->GetClassDescriptor(isa);
1506061da546Spatrick if (!class_descriptor_sp)
1507061da546Spatrick class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
1508061da546Spatrick return class_descriptor_sp;
1509061da546Spatrick }
1510061da546Spatrick
1511061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ValueObject & valobj)1512061da546Spatrick AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
1513061da546Spatrick ClassDescriptorSP objc_class_sp;
1514061da546Spatrick if (valobj.IsBaseClass()) {
1515061da546Spatrick ValueObject *parent = valobj.GetParent();
1516061da546Spatrick // if I am my own parent, bail out of here fast..
1517061da546Spatrick if (parent && parent != &valobj) {
1518061da546Spatrick ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
1519061da546Spatrick if (parent_descriptor_sp)
1520061da546Spatrick return parent_descriptor_sp->GetSuperclass();
1521061da546Spatrick }
1522061da546Spatrick return nullptr;
1523061da546Spatrick }
1524061da546Spatrick // if we get an invalid VO (which might still happen when playing around with
1525061da546Spatrick // pointers returned by the expression parser, don't consider this a valid
1526061da546Spatrick // ObjC object)
1527dda28197Spatrick if (!valobj.GetCompilerType().IsValid())
1528dda28197Spatrick return objc_class_sp;
1529061da546Spatrick addr_t isa_pointer = valobj.GetPointerValue();
1530061da546Spatrick
1531061da546Spatrick // tagged pointer
1532dda28197Spatrick if (IsTaggedPointer(isa_pointer))
1533061da546Spatrick return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer);
1534061da546Spatrick ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1535061da546Spatrick
1536061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
1537dda28197Spatrick if (!process)
1538dda28197Spatrick return objc_class_sp;
1539dda28197Spatrick
1540061da546Spatrick Status error;
1541061da546Spatrick ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
1542dda28197Spatrick if (isa == LLDB_INVALID_ADDRESS)
1543dda28197Spatrick return objc_class_sp;
1544dda28197Spatrick
1545061da546Spatrick objc_class_sp = GetClassDescriptorFromISA(isa);
1546*f6aab3d8Srobert if (!objc_class_sp) {
1547*f6aab3d8Srobert if (ABISP abi_sp = process->GetABI())
1548*f6aab3d8Srobert isa = abi_sp->FixCodeAddress(isa);
1549*f6aab3d8Srobert objc_class_sp = GetClassDescriptorFromISA(isa);
1550*f6aab3d8Srobert }
1551*f6aab3d8Srobert
1552be691f3bSpatrick if (isa && !objc_class_sp) {
1553*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
1554061da546Spatrick LLDB_LOGF(log,
1555be691f3bSpatrick "0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was "
1556061da546Spatrick "not in class descriptor cache 0x%" PRIx64,
1557061da546Spatrick isa_pointer, isa);
1558061da546Spatrick }
1559061da546Spatrick return objc_class_sp;
1560061da546Spatrick }
1561061da546Spatrick
GetTaggedPointerObfuscator()1562061da546Spatrick lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() {
1563061da546Spatrick if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS)
1564061da546Spatrick return m_tagged_pointer_obfuscator;
1565061da546Spatrick
1566061da546Spatrick Process *process = GetProcess();
1567061da546Spatrick ModuleSP objc_module_sp(GetObjCModule());
1568061da546Spatrick
1569061da546Spatrick if (!objc_module_sp)
1570061da546Spatrick return LLDB_INVALID_ADDRESS;
1571061da546Spatrick
1572be691f3bSpatrick static ConstString g_gdb_objc_obfuscator(
1573be691f3bSpatrick "objc_debug_taggedpointer_obfuscator");
1574061da546Spatrick
1575061da546Spatrick const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
1576061da546Spatrick g_gdb_objc_obfuscator, lldb::eSymbolTypeAny);
1577061da546Spatrick if (symbol) {
1578061da546Spatrick lldb::addr_t g_gdb_obj_obfuscator_ptr =
1579061da546Spatrick symbol->GetLoadAddress(&process->GetTarget());
1580061da546Spatrick
1581061da546Spatrick if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) {
1582061da546Spatrick Status error;
1583be691f3bSpatrick m_tagged_pointer_obfuscator =
1584be691f3bSpatrick process->ReadPointerFromMemory(g_gdb_obj_obfuscator_ptr, error);
1585061da546Spatrick }
1586061da546Spatrick }
1587be691f3bSpatrick // If we don't have a correct value at this point, there must be no
1588be691f3bSpatrick // obfuscation.
1589061da546Spatrick if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS)
1590061da546Spatrick m_tagged_pointer_obfuscator = 0;
1591061da546Spatrick
1592061da546Spatrick return m_tagged_pointer_obfuscator;
1593061da546Spatrick }
1594061da546Spatrick
GetISAHashTablePointer()1595061da546Spatrick lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {
1596061da546Spatrick if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
1597061da546Spatrick Process *process = GetProcess();
1598061da546Spatrick
1599061da546Spatrick ModuleSP objc_module_sp(GetObjCModule());
1600061da546Spatrick
1601061da546Spatrick if (!objc_module_sp)
1602061da546Spatrick return LLDB_INVALID_ADDRESS;
1603061da546Spatrick
1604061da546Spatrick static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");
1605061da546Spatrick
1606061da546Spatrick const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
1607061da546Spatrick g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);
1608061da546Spatrick if (symbol) {
1609061da546Spatrick lldb::addr_t gdb_objc_realized_classes_ptr =
1610061da546Spatrick symbol->GetLoadAddress(&process->GetTarget());
1611061da546Spatrick
1612061da546Spatrick if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {
1613061da546Spatrick Status error;
1614061da546Spatrick m_isa_hash_table_ptr = process->ReadPointerFromMemory(
1615061da546Spatrick gdb_objc_realized_classes_ptr, error);
1616061da546Spatrick }
1617061da546Spatrick }
1618061da546Spatrick }
1619061da546Spatrick return m_isa_hash_table_ptr;
1620061da546Spatrick }
1621061da546Spatrick
1622be691f3bSpatrick std::unique_ptr<UtilityFunction>
GetClassInfoUtilityFunctionImpl(ExecutionContext & exe_ctx,Helper helper,std::string code,std::string name)1623be691f3bSpatrick AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(
1624*f6aab3d8Srobert ExecutionContext &exe_ctx, Helper helper, std::string code,
1625*f6aab3d8Srobert std::string name) {
1626*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
1627061da546Spatrick
1628be691f3bSpatrick LLDB_LOG(log, "Creating utility function {0}", name);
1629be691f3bSpatrick
1630*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
1631be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());
1632*f6aab3d8Srobert if (!scratch_ts_sp)
1633be691f3bSpatrick return {};
1634be691f3bSpatrick
1635be691f3bSpatrick auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
1636be691f3bSpatrick std::move(code), std::move(name), eLanguageTypeC, exe_ctx);
1637be691f3bSpatrick if (!utility_fn_or_error) {
1638be691f3bSpatrick LLDB_LOG_ERROR(
1639be691f3bSpatrick log, utility_fn_or_error.takeError(),
1640*f6aab3d8Srobert "Failed to get utility function for dynamic info extractor: {0}");
1641be691f3bSpatrick return {};
1642be691f3bSpatrick }
1643be691f3bSpatrick
1644be691f3bSpatrick // Make some types for our arguments.
1645be691f3bSpatrick CompilerType clang_uint32_t_type =
1646*f6aab3d8Srobert scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1647be691f3bSpatrick CompilerType clang_void_pointer_type =
1648*f6aab3d8Srobert scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1649be691f3bSpatrick
1650be691f3bSpatrick // Make the runner function for our implementation utility function.
1651be691f3bSpatrick ValueList arguments;
1652be691f3bSpatrick Value value;
1653be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
1654be691f3bSpatrick value.SetCompilerType(clang_void_pointer_type);
1655be691f3bSpatrick arguments.PushValue(value);
1656be691f3bSpatrick arguments.PushValue(value);
1657be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
1658be691f3bSpatrick value.SetCompilerType(clang_uint32_t_type);
1659be691f3bSpatrick arguments.PushValue(value);
1660*f6aab3d8Srobert
1661*f6aab3d8Srobert // objc_getRealizedClassList_trylock takes an additional buffer and length.
1662*f6aab3d8Srobert if (helper == Helper::objc_getRealizedClassList_trylock) {
1663*f6aab3d8Srobert value.SetCompilerType(clang_void_pointer_type);
1664*f6aab3d8Srobert arguments.PushValue(value);
1665*f6aab3d8Srobert value.SetCompilerType(clang_uint32_t_type);
1666*f6aab3d8Srobert arguments.PushValue(value);
1667*f6aab3d8Srobert }
1668*f6aab3d8Srobert
1669be691f3bSpatrick arguments.PushValue(value);
1670be691f3bSpatrick
1671be691f3bSpatrick std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
1672be691f3bSpatrick
1673be691f3bSpatrick Status error;
1674be691f3bSpatrick utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,
1675be691f3bSpatrick exe_ctx.GetThreadSP(), error);
1676be691f3bSpatrick
1677be691f3bSpatrick if (error.Fail()) {
1678be691f3bSpatrick LLDB_LOG(log,
1679be691f3bSpatrick "Failed to make function caller for implementation lookup: {0}.",
1680be691f3bSpatrick error.AsCString());
1681be691f3bSpatrick return {};
1682be691f3bSpatrick }
1683be691f3bSpatrick
1684be691f3bSpatrick return utility_fn;
1685be691f3bSpatrick }
1686be691f3bSpatrick
1687be691f3bSpatrick UtilityFunction *
GetClassInfoUtilityFunction(ExecutionContext & exe_ctx,Helper helper)1688be691f3bSpatrick AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunction(
1689be691f3bSpatrick ExecutionContext &exe_ctx, Helper helper) {
1690be691f3bSpatrick switch (helper) {
1691be691f3bSpatrick case gdb_objc_realized_classes: {
1692be691f3bSpatrick if (!m_gdb_objc_realized_classes_helper.utility_function)
1693be691f3bSpatrick m_gdb_objc_realized_classes_helper.utility_function =
1694*f6aab3d8Srobert GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
1695be691f3bSpatrick g_get_dynamic_class_info_body,
1696be691f3bSpatrick g_get_dynamic_class_info_name);
1697be691f3bSpatrick return m_gdb_objc_realized_classes_helper.utility_function.get();
1698be691f3bSpatrick }
1699be691f3bSpatrick case objc_copyRealizedClassList: {
1700be691f3bSpatrick if (!m_objc_copyRealizedClassList_helper.utility_function)
1701be691f3bSpatrick m_objc_copyRealizedClassList_helper.utility_function =
1702*f6aab3d8Srobert GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
1703be691f3bSpatrick g_get_dynamic_class_info2_body,
1704be691f3bSpatrick g_get_dynamic_class_info2_name);
1705be691f3bSpatrick return m_objc_copyRealizedClassList_helper.utility_function.get();
1706be691f3bSpatrick }
1707*f6aab3d8Srobert case objc_getRealizedClassList_trylock: {
1708*f6aab3d8Srobert if (!m_objc_getRealizedClassList_trylock_helper.utility_function)
1709*f6aab3d8Srobert m_objc_getRealizedClassList_trylock_helper.utility_function =
1710*f6aab3d8Srobert GetClassInfoUtilityFunctionImpl(exe_ctx, helper,
1711*f6aab3d8Srobert g_get_dynamic_class_info3_body,
1712*f6aab3d8Srobert g_get_dynamic_class_info3_name);
1713*f6aab3d8Srobert return m_objc_getRealizedClassList_trylock_helper.utility_function.get();
1714*f6aab3d8Srobert }
1715be691f3bSpatrick }
1716be691f3bSpatrick llvm_unreachable("Unexpected helper");
1717be691f3bSpatrick }
1718be691f3bSpatrick
1719be691f3bSpatrick lldb::addr_t &
GetClassInfoArgs(Helper helper)1720be691f3bSpatrick AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) {
1721be691f3bSpatrick switch (helper) {
1722be691f3bSpatrick case gdb_objc_realized_classes:
1723be691f3bSpatrick return m_gdb_objc_realized_classes_helper.args;
1724be691f3bSpatrick case objc_copyRealizedClassList:
1725be691f3bSpatrick return m_objc_copyRealizedClassList_helper.args;
1726*f6aab3d8Srobert case objc_getRealizedClassList_trylock:
1727*f6aab3d8Srobert return m_objc_getRealizedClassList_trylock_helper.args;
1728be691f3bSpatrick }
1729be691f3bSpatrick llvm_unreachable("Unexpected helper");
1730be691f3bSpatrick }
1731be691f3bSpatrick
1732be691f3bSpatrick AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper
ComputeHelper(ExecutionContext & exe_ctx) const1733*f6aab3d8Srobert AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper(
1734*f6aab3d8Srobert ExecutionContext &exe_ctx) const {
1735*f6aab3d8Srobert if (!m_runtime.m_has_objc_copyRealizedClassList &&
1736*f6aab3d8Srobert !m_runtime.m_has_objc_getRealizedClassList_trylock)
1737be691f3bSpatrick return DynamicClassInfoExtractor::gdb_objc_realized_classes;
1738be691f3bSpatrick
1739be691f3bSpatrick if (Process *process = m_runtime.GetProcess()) {
1740be691f3bSpatrick if (DynamicLoader *loader = process->GetDynamicLoader()) {
1741*f6aab3d8Srobert if (loader->IsFullyInitialized()) {
1742*f6aab3d8Srobert switch (exe_ctx.GetTargetRef().GetDynamicClassInfoHelper()) {
1743*f6aab3d8Srobert case eDynamicClassInfoHelperAuto:
1744*f6aab3d8Srobert [[clang::fallthrough]];
1745*f6aab3d8Srobert case eDynamicClassInfoHelperGetRealizedClassList:
1746*f6aab3d8Srobert if (m_runtime.m_has_objc_getRealizedClassList_trylock)
1747*f6aab3d8Srobert return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock;
1748*f6aab3d8Srobert [[clang::fallthrough]];
1749*f6aab3d8Srobert case eDynamicClassInfoHelperCopyRealizedClassList:
1750*f6aab3d8Srobert if (m_runtime.m_has_objc_copyRealizedClassList)
1751be691f3bSpatrick return DynamicClassInfoExtractor::objc_copyRealizedClassList;
1752*f6aab3d8Srobert [[clang::fallthrough]];
1753*f6aab3d8Srobert case eDynamicClassInfoHelperRealizedClassesStruct:
1754*f6aab3d8Srobert return DynamicClassInfoExtractor::gdb_objc_realized_classes;
1755*f6aab3d8Srobert }
1756*f6aab3d8Srobert }
1757be691f3bSpatrick }
1758be691f3bSpatrick }
1759be691f3bSpatrick
1760be691f3bSpatrick return DynamicClassInfoExtractor::gdb_objc_realized_classes;
1761be691f3bSpatrick }
1762be691f3bSpatrick
1763be691f3bSpatrick std::unique_ptr<UtilityFunction>
1764be691f3bSpatrick AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::
GetClassInfoUtilityFunctionImpl(ExecutionContext & exe_ctx)1765be691f3bSpatrick GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) {
1766*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
1767be691f3bSpatrick
1768be691f3bSpatrick LLDB_LOG(log, "Creating utility function {0}",
1769be691f3bSpatrick g_get_shared_cache_class_info_name);
1770be691f3bSpatrick
1771*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
1772be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());
1773*f6aab3d8Srobert if (!scratch_ts_sp)
1774be691f3bSpatrick return {};
1775be691f3bSpatrick
1776be691f3bSpatrick // If the inferior objc.dylib has the class_getNameRaw function, use that in
1777be691f3bSpatrick // our jitted expression. Else fall back to the old class_getName.
1778be691f3bSpatrick static ConstString g_class_getName_symbol_name("class_getName");
1779be691f3bSpatrick static ConstString g_class_getNameRaw_symbol_name(
1780be691f3bSpatrick "objc_debug_class_getNameRaw");
1781be691f3bSpatrick
1782be691f3bSpatrick ConstString class_name_getter_function_name =
1783be691f3bSpatrick m_runtime.HasSymbol(g_class_getNameRaw_symbol_name)
1784be691f3bSpatrick ? g_class_getNameRaw_symbol_name
1785be691f3bSpatrick : g_class_getName_symbol_name;
1786be691f3bSpatrick
1787be691f3bSpatrick // Substitute in the correct class_getName / class_getNameRaw function name,
1788be691f3bSpatrick // concatenate the two parts of our expression text. The format string has
1789be691f3bSpatrick // two %s's, so provide the name twice.
1790be691f3bSpatrick std::string shared_class_expression;
1791be691f3bSpatrick llvm::raw_string_ostream(shared_class_expression)
1792be691f3bSpatrick << llvm::format(g_shared_cache_class_name_funcptr,
1793be691f3bSpatrick class_name_getter_function_name.AsCString(),
1794be691f3bSpatrick class_name_getter_function_name.AsCString());
1795be691f3bSpatrick
1796be691f3bSpatrick shared_class_expression += g_get_shared_cache_class_info_body;
1797be691f3bSpatrick
1798be691f3bSpatrick auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(
1799be691f3bSpatrick std::move(shared_class_expression), g_get_shared_cache_class_info_name,
1800be691f3bSpatrick eLanguageTypeC, exe_ctx);
1801be691f3bSpatrick
1802be691f3bSpatrick if (!utility_fn_or_error) {
1803be691f3bSpatrick LLDB_LOG_ERROR(
1804be691f3bSpatrick log, utility_fn_or_error.takeError(),
1805*f6aab3d8Srobert "Failed to get utility function for shared class info extractor: {0}");
1806be691f3bSpatrick return nullptr;
1807be691f3bSpatrick }
1808be691f3bSpatrick
1809be691f3bSpatrick // Make some types for our arguments.
1810be691f3bSpatrick CompilerType clang_uint32_t_type =
1811*f6aab3d8Srobert scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1812be691f3bSpatrick CompilerType clang_void_pointer_type =
1813*f6aab3d8Srobert scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();
1814be691f3bSpatrick CompilerType clang_uint64_t_pointer_type =
1815*f6aab3d8Srobert scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)
1816be691f3bSpatrick .GetPointerType();
1817be691f3bSpatrick
1818be691f3bSpatrick // Next make the function caller for our implementation utility function.
1819be691f3bSpatrick ValueList arguments;
1820be691f3bSpatrick Value value;
1821be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
1822be691f3bSpatrick value.SetCompilerType(clang_void_pointer_type);
1823be691f3bSpatrick arguments.PushValue(value);
1824be691f3bSpatrick arguments.PushValue(value);
1825be691f3bSpatrick arguments.PushValue(value);
1826be691f3bSpatrick
1827be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
1828be691f3bSpatrick value.SetCompilerType(clang_uint64_t_pointer_type);
1829be691f3bSpatrick arguments.PushValue(value);
1830be691f3bSpatrick
1831be691f3bSpatrick value.SetValueType(Value::ValueType::Scalar);
1832be691f3bSpatrick value.SetCompilerType(clang_uint32_t_type);
1833be691f3bSpatrick arguments.PushValue(value);
1834be691f3bSpatrick arguments.PushValue(value);
1835be691f3bSpatrick
1836be691f3bSpatrick std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);
1837be691f3bSpatrick
1838be691f3bSpatrick Status error;
1839be691f3bSpatrick utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,
1840be691f3bSpatrick exe_ctx.GetThreadSP(), error);
1841be691f3bSpatrick
1842be691f3bSpatrick if (error.Fail()) {
1843be691f3bSpatrick LLDB_LOG(log,
1844be691f3bSpatrick "Failed to make function caller for implementation lookup: {0}.",
1845be691f3bSpatrick error.AsCString());
1846be691f3bSpatrick return {};
1847be691f3bSpatrick }
1848be691f3bSpatrick
1849be691f3bSpatrick return utility_fn;
1850be691f3bSpatrick }
1851be691f3bSpatrick
1852be691f3bSpatrick UtilityFunction *
GetClassInfoUtilityFunction(ExecutionContext & exe_ctx)1853be691f3bSpatrick AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction(
1854be691f3bSpatrick ExecutionContext &exe_ctx) {
1855be691f3bSpatrick if (!m_utility_function)
1856be691f3bSpatrick m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx);
1857be691f3bSpatrick return m_utility_function.get();
1858be691f3bSpatrick }
1859be691f3bSpatrick
1860be691f3bSpatrick AppleObjCRuntimeV2::DescriptorMapUpdateResult
UpdateISAToDescriptorMap(RemoteNXMapTable & hash_table)1861be691f3bSpatrick AppleObjCRuntimeV2::DynamicClassInfoExtractor::UpdateISAToDescriptorMap(
1862be691f3bSpatrick RemoteNXMapTable &hash_table) {
1863be691f3bSpatrick Process *process = m_runtime.GetProcess();
1864061da546Spatrick if (process == nullptr)
1865061da546Spatrick return DescriptorMapUpdateResult::Fail();
1866061da546Spatrick
1867061da546Spatrick uint32_t num_class_infos = 0;
1868061da546Spatrick
1869*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
1870061da546Spatrick
1871061da546Spatrick ExecutionContext exe_ctx;
1872061da546Spatrick
1873061da546Spatrick ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1874061da546Spatrick
1875061da546Spatrick if (!thread_sp)
1876061da546Spatrick return DescriptorMapUpdateResult::Fail();
1877061da546Spatrick
1878*f6aab3d8Srobert if (!thread_sp->SafeToCallFunctions())
1879*f6aab3d8Srobert return DescriptorMapUpdateResult::Retry();
1880*f6aab3d8Srobert
1881061da546Spatrick thread_sp->CalculateExecutionContext(exe_ctx);
1882*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
1883be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(process->GetTarget());
1884061da546Spatrick
1885*f6aab3d8Srobert if (!scratch_ts_sp)
1886061da546Spatrick return DescriptorMapUpdateResult::Fail();
1887061da546Spatrick
1888061da546Spatrick Address function_address;
1889061da546Spatrick
1890061da546Spatrick const uint32_t addr_size = process->GetAddressByteSize();
1891061da546Spatrick
1892061da546Spatrick Status err;
1893061da546Spatrick
1894be691f3bSpatrick // Compute which helper we're going to use for this update.
1895*f6aab3d8Srobert const DynamicClassInfoExtractor::Helper helper = ComputeHelper(exe_ctx);
1896be691f3bSpatrick
1897061da546Spatrick // Read the total number of classes from the hash table
1898be691f3bSpatrick const uint32_t num_classes =
1899be691f3bSpatrick helper == DynamicClassInfoExtractor::gdb_objc_realized_classes
1900be691f3bSpatrick ? hash_table.GetCount()
1901be691f3bSpatrick : m_runtime.m_realized_class_generation_count;
1902061da546Spatrick if (num_classes == 0) {
1903be691f3bSpatrick LLDB_LOGF(log, "No dynamic classes found.");
1904061da546Spatrick return DescriptorMapUpdateResult::Success(0);
1905061da546Spatrick }
1906061da546Spatrick
1907be691f3bSpatrick UtilityFunction *get_class_info_code =
1908be691f3bSpatrick GetClassInfoUtilityFunction(exe_ctx, helper);
1909be691f3bSpatrick if (!get_class_info_code) {
1910be691f3bSpatrick // The callee will have already logged a useful error message.
1911061da546Spatrick return DescriptorMapUpdateResult::Fail();
1912061da546Spatrick }
1913be691f3bSpatrick
1914be691f3bSpatrick FunctionCaller *get_class_info_function =
1915be691f3bSpatrick get_class_info_code->GetFunctionCaller();
1916be691f3bSpatrick
1917061da546Spatrick if (!get_class_info_function) {
1918061da546Spatrick LLDB_LOGF(log, "Failed to get implementation lookup function caller.");
1919061da546Spatrick return DescriptorMapUpdateResult::Fail();
1920061da546Spatrick }
1921061da546Spatrick
1922be691f3bSpatrick ValueList arguments = get_class_info_function->GetArgumentValues();
1923be691f3bSpatrick
1924be691f3bSpatrick DiagnosticManager diagnostics;
1925061da546Spatrick
1926061da546Spatrick const uint32_t class_info_byte_size = addr_size + 4;
1927061da546Spatrick const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1928061da546Spatrick lldb::addr_t class_infos_addr = process->AllocateMemory(
1929061da546Spatrick class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
1930061da546Spatrick
1931061da546Spatrick if (class_infos_addr == LLDB_INVALID_ADDRESS) {
1932061da546Spatrick LLDB_LOGF(log,
1933061da546Spatrick "unable to allocate %" PRIu32
1934061da546Spatrick " bytes in process for shared cache read",
1935061da546Spatrick class_infos_byte_size);
1936061da546Spatrick return DescriptorMapUpdateResult::Fail();
1937061da546Spatrick }
1938061da546Spatrick
1939*f6aab3d8Srobert auto deallocate_class_infos = llvm::make_scope_exit([&] {
1940*f6aab3d8Srobert // Deallocate the memory we allocated for the ClassInfo array
1941*f6aab3d8Srobert if (class_infos_addr != LLDB_INVALID_ADDRESS)
1942*f6aab3d8Srobert process->DeallocateMemory(class_infos_addr);
1943*f6aab3d8Srobert });
1944*f6aab3d8Srobert
1945*f6aab3d8Srobert lldb::addr_t class_buffer_addr = LLDB_INVALID_ADDRESS;
1946*f6aab3d8Srobert const uint32_t class_byte_size = addr_size;
1947*f6aab3d8Srobert const uint32_t class_buffer_len = num_classes;
1948*f6aab3d8Srobert const uint32_t class_buffer_byte_size = class_buffer_len * class_byte_size;
1949*f6aab3d8Srobert if (helper == Helper::objc_getRealizedClassList_trylock) {
1950*f6aab3d8Srobert class_buffer_addr = process->AllocateMemory(
1951*f6aab3d8Srobert class_buffer_byte_size, ePermissionsReadable | ePermissionsWritable,
1952*f6aab3d8Srobert err);
1953*f6aab3d8Srobert if (class_buffer_addr == LLDB_INVALID_ADDRESS) {
1954*f6aab3d8Srobert LLDB_LOGF(log,
1955*f6aab3d8Srobert "unable to allocate %" PRIu32
1956*f6aab3d8Srobert " bytes in process for shared cache read",
1957*f6aab3d8Srobert class_buffer_byte_size);
1958*f6aab3d8Srobert return DescriptorMapUpdateResult::Fail();
1959*f6aab3d8Srobert }
1960*f6aab3d8Srobert }
1961*f6aab3d8Srobert
1962*f6aab3d8Srobert auto deallocate_class_buffer = llvm::make_scope_exit([&] {
1963*f6aab3d8Srobert // Deallocate the memory we allocated for the Class array
1964*f6aab3d8Srobert if (class_buffer_addr != LLDB_INVALID_ADDRESS)
1965*f6aab3d8Srobert process->DeallocateMemory(class_buffer_addr);
1966*f6aab3d8Srobert });
1967*f6aab3d8Srobert
1968be691f3bSpatrick std::lock_guard<std::mutex> guard(m_mutex);
1969061da546Spatrick
1970061da546Spatrick // Fill in our function argument values
1971*f6aab3d8Srobert uint32_t index = 0;
1972*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() =
1973*f6aab3d8Srobert hash_table.GetTableLoadAddress();
1974*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_addr;
1975*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_byte_size;
1976*f6aab3d8Srobert
1977*f6aab3d8Srobert if (class_buffer_addr != LLDB_INVALID_ADDRESS) {
1978*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_addr;
1979*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_byte_size;
1980*f6aab3d8Srobert }
1981061da546Spatrick
1982061da546Spatrick // Only dump the runtime classes from the expression evaluation if the log is
1983061da546Spatrick // verbose:
1984*f6aab3d8Srobert Log *type_log = GetLog(LLDBLog::Types);
1985061da546Spatrick bool dump_log = type_log && type_log->GetVerbose();
1986061da546Spatrick
1987*f6aab3d8Srobert arguments.GetValueAtIndex(index++)->GetScalar() = dump_log ? 1 : 0;
1988061da546Spatrick
1989061da546Spatrick bool success = false;
1990061da546Spatrick
1991061da546Spatrick diagnostics.Clear();
1992061da546Spatrick
1993061da546Spatrick // Write our function arguments into the process so we can run our function
1994061da546Spatrick if (get_class_info_function->WriteFunctionArguments(
1995be691f3bSpatrick exe_ctx, GetClassInfoArgs(helper), arguments, diagnostics)) {
1996061da546Spatrick EvaluateExpressionOptions options;
1997061da546Spatrick options.SetUnwindOnError(true);
1998061da546Spatrick options.SetTryAllThreads(false);
1999061da546Spatrick options.SetStopOthers(true);
2000061da546Spatrick options.SetIgnoreBreakpoints(true);
2001061da546Spatrick options.SetTimeout(process->GetUtilityExpressionTimeout());
2002061da546Spatrick options.SetIsForUtilityExpr(true);
2003061da546Spatrick
2004be691f3bSpatrick CompilerType clang_uint32_t_type =
2005*f6aab3d8Srobert scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
2006be691f3bSpatrick
2007061da546Spatrick Value return_value;
2008be691f3bSpatrick return_value.SetValueType(Value::ValueType::Scalar);
2009061da546Spatrick return_value.SetCompilerType(clang_uint32_t_type);
2010061da546Spatrick return_value.GetScalar() = 0;
2011061da546Spatrick
2012061da546Spatrick diagnostics.Clear();
2013061da546Spatrick
2014061da546Spatrick // Run the function
2015061da546Spatrick ExpressionResults results = get_class_info_function->ExecuteFunction(
2016be691f3bSpatrick exe_ctx, &GetClassInfoArgs(helper), options, diagnostics, return_value);
2017061da546Spatrick
2018061da546Spatrick if (results == eExpressionCompleted) {
2019061da546Spatrick // The result is the number of ClassInfo structures that were filled in
2020061da546Spatrick num_class_infos = return_value.GetScalar().ULong();
2021be691f3bSpatrick LLDB_LOG(log, "Discovered {0} Objective-C classes", num_class_infos);
2022061da546Spatrick if (num_class_infos > 0) {
2023061da546Spatrick // Read the ClassInfo structures
2024061da546Spatrick DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);
2025061da546Spatrick if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),
2026061da546Spatrick buffer.GetByteSize(),
2027061da546Spatrick err) == buffer.GetByteSize()) {
2028061da546Spatrick DataExtractor class_infos_data(buffer.GetBytes(),
2029061da546Spatrick buffer.GetByteSize(),
2030061da546Spatrick process->GetByteOrder(), addr_size);
2031be691f3bSpatrick m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
2032061da546Spatrick }
2033061da546Spatrick }
2034061da546Spatrick success = true;
2035061da546Spatrick } else {
2036061da546Spatrick if (log) {
2037061da546Spatrick LLDB_LOGF(log, "Error evaluating our find class name function.");
2038061da546Spatrick diagnostics.Dump(log);
2039061da546Spatrick }
2040061da546Spatrick }
2041061da546Spatrick } else {
2042061da546Spatrick if (log) {
2043061da546Spatrick LLDB_LOGF(log, "Error writing function arguments.");
2044061da546Spatrick diagnostics.Dump(log);
2045061da546Spatrick }
2046061da546Spatrick }
2047061da546Spatrick
2048*f6aab3d8Srobert return DescriptorMapUpdateResult(success, false, num_class_infos);
2049061da546Spatrick }
2050061da546Spatrick
ParseClassInfoArray(const DataExtractor & data,uint32_t num_class_infos)2051061da546Spatrick uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,
2052061da546Spatrick uint32_t num_class_infos) {
2053061da546Spatrick // Parses an array of "num_class_infos" packed ClassInfo structures:
2054061da546Spatrick //
2055061da546Spatrick // struct ClassInfo
2056061da546Spatrick // {
2057061da546Spatrick // Class isa;
2058061da546Spatrick // uint32_t hash;
2059061da546Spatrick // } __attribute__((__packed__));
2060061da546Spatrick
2061*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Types);
2062061da546Spatrick bool should_log = log && log->GetVerbose();
2063061da546Spatrick
2064061da546Spatrick uint32_t num_parsed = 0;
2065061da546Spatrick
2066061da546Spatrick // Iterate through all ClassInfo structures
2067061da546Spatrick lldb::offset_t offset = 0;
2068061da546Spatrick for (uint32_t i = 0; i < num_class_infos; ++i) {
2069dda28197Spatrick ObjCISA isa = data.GetAddress(&offset);
2070061da546Spatrick
2071061da546Spatrick if (isa == 0) {
2072061da546Spatrick if (should_log)
2073061da546Spatrick LLDB_LOGF(
2074061da546Spatrick log, "AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
2075061da546Spatrick continue;
2076061da546Spatrick }
2077061da546Spatrick // Check if we already know about this ISA, if we do, the info will never
2078061da546Spatrick // change, so we can just skip it.
2079061da546Spatrick if (ISAIsCached(isa)) {
2080061da546Spatrick if (should_log)
2081061da546Spatrick LLDB_LOGF(log,
2082061da546Spatrick "AppleObjCRuntimeV2 found cached isa=0x%" PRIx64
2083061da546Spatrick ", ignoring this class info",
2084061da546Spatrick isa);
2085061da546Spatrick offset += 4;
2086061da546Spatrick } else {
2087061da546Spatrick // Read the 32 bit hash for the class name
2088061da546Spatrick const uint32_t name_hash = data.GetU32(&offset);
2089061da546Spatrick ClassDescriptorSP descriptor_sp(
2090061da546Spatrick new ClassDescriptorV2(*this, isa, nullptr));
2091061da546Spatrick
2092be691f3bSpatrick // The code in g_get_shared_cache_class_info_body sets the value of the
2093be691f3bSpatrick // hash to 0 to signal a demangled symbol. We use class_getName() in that
2094be691f3bSpatrick // code to find the class name, but this returns a demangled name for
2095be691f3bSpatrick // Swift symbols. For those symbols, recompute the hash here by reading
2096be691f3bSpatrick // their name from the runtime.
2097061da546Spatrick if (name_hash)
2098061da546Spatrick AddClass(isa, descriptor_sp, name_hash);
2099061da546Spatrick else
2100be691f3bSpatrick AddClass(isa, descriptor_sp,
2101be691f3bSpatrick descriptor_sp->GetClassName().AsCString(nullptr));
2102061da546Spatrick num_parsed++;
2103061da546Spatrick if (should_log)
2104061da546Spatrick LLDB_LOGF(log,
2105061da546Spatrick "AppleObjCRuntimeV2 added isa=0x%" PRIx64
2106061da546Spatrick ", hash=0x%8.8x, name=%s",
2107061da546Spatrick isa, name_hash,
2108061da546Spatrick descriptor_sp->GetClassName().AsCString("<unknown>"));
2109061da546Spatrick }
2110061da546Spatrick }
2111061da546Spatrick if (should_log)
2112061da546Spatrick LLDB_LOGF(log, "AppleObjCRuntimeV2 parsed %" PRIu32 " class infos",
2113061da546Spatrick num_parsed);
2114061da546Spatrick return num_parsed;
2115061da546Spatrick }
2116061da546Spatrick
HasSymbol(ConstString Name)2117be691f3bSpatrick bool AppleObjCRuntimeV2::HasSymbol(ConstString Name) {
2118be691f3bSpatrick if (!m_objc_module_sp)
2119be691f3bSpatrick return false;
2120be691f3bSpatrick if (const Symbol *symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(
2121be691f3bSpatrick Name, lldb::eSymbolTypeCode)) {
2122be691f3bSpatrick if (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())
2123be691f3bSpatrick return true;
2124be691f3bSpatrick }
2125be691f3bSpatrick return false;
2126be691f3bSpatrick }
2127061da546Spatrick
2128be691f3bSpatrick AppleObjCRuntimeV2::DescriptorMapUpdateResult
UpdateISAToDescriptorMap()2129be691f3bSpatrick AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {
2130be691f3bSpatrick Process *process = m_runtime.GetProcess();
2131061da546Spatrick if (process == nullptr)
2132061da546Spatrick return DescriptorMapUpdateResult::Fail();
2133061da546Spatrick
2134*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
2135061da546Spatrick
2136061da546Spatrick ExecutionContext exe_ctx;
2137061da546Spatrick
2138061da546Spatrick ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
2139061da546Spatrick
2140061da546Spatrick if (!thread_sp)
2141061da546Spatrick return DescriptorMapUpdateResult::Fail();
2142061da546Spatrick
2143*f6aab3d8Srobert if (!thread_sp->SafeToCallFunctions())
2144*f6aab3d8Srobert return DescriptorMapUpdateResult::Retry();
2145*f6aab3d8Srobert
2146061da546Spatrick thread_sp->CalculateExecutionContext(exe_ctx);
2147*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
2148be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(process->GetTarget());
2149061da546Spatrick
2150*f6aab3d8Srobert if (!scratch_ts_sp)
2151061da546Spatrick return DescriptorMapUpdateResult::Fail();
2152061da546Spatrick
2153061da546Spatrick Address function_address;
2154061da546Spatrick
2155061da546Spatrick const uint32_t addr_size = process->GetAddressByteSize();
2156061da546Spatrick
2157061da546Spatrick Status err;
2158061da546Spatrick
2159061da546Spatrick uint32_t num_class_infos = 0;
2160061da546Spatrick
2161be691f3bSpatrick const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress();
2162be691f3bSpatrick const lldb::addr_t shared_cache_base_addr =
2163be691f3bSpatrick m_runtime.GetSharedCacheBaseAddress();
2164061da546Spatrick
2165be691f3bSpatrick if (objc_opt_ptr == LLDB_INVALID_ADDRESS ||
2166be691f3bSpatrick shared_cache_base_addr == LLDB_INVALID_ADDRESS)
2167061da546Spatrick return DescriptorMapUpdateResult::Fail();
2168061da546Spatrick
2169*f6aab3d8Srobert // The number of entries to pre-allocate room for.
2170*f6aab3d8Srobert // Each entry is (addrsize + 4) bytes
2171*f6aab3d8Srobert const uint32_t max_num_classes = 163840;
2172061da546Spatrick
2173be691f3bSpatrick UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);
2174*f6aab3d8Srobert if (!get_class_info_code) {
2175*f6aab3d8Srobert // The callee will have already logged a useful error message.
2176*f6aab3d8Srobert return DescriptorMapUpdateResult::Fail();
2177*f6aab3d8Srobert }
2178*f6aab3d8Srobert
2179be691f3bSpatrick FunctionCaller *get_shared_cache_class_info_function =
2180be691f3bSpatrick get_class_info_code->GetFunctionCaller();
2181061da546Spatrick
2182be691f3bSpatrick if (!get_shared_cache_class_info_function) {
2183be691f3bSpatrick LLDB_LOGF(log, "Failed to get implementation lookup function caller.");
2184061da546Spatrick return DescriptorMapUpdateResult::Fail();
2185061da546Spatrick }
2186061da546Spatrick
2187be691f3bSpatrick ValueList arguments =
2188be691f3bSpatrick get_shared_cache_class_info_function->GetArgumentValues();
2189be691f3bSpatrick
2190be691f3bSpatrick DiagnosticManager diagnostics;
2191061da546Spatrick
2192061da546Spatrick const uint32_t class_info_byte_size = addr_size + 4;
2193*f6aab3d8Srobert const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;
2194061da546Spatrick lldb::addr_t class_infos_addr = process->AllocateMemory(
2195061da546Spatrick class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
2196be691f3bSpatrick const uint32_t relative_selector_offset_addr_size = 64;
2197be691f3bSpatrick lldb::addr_t relative_selector_offset_addr =
2198be691f3bSpatrick process->AllocateMemory(relative_selector_offset_addr_size,
2199be691f3bSpatrick ePermissionsReadable | ePermissionsWritable, err);
2200061da546Spatrick
2201061da546Spatrick if (class_infos_addr == LLDB_INVALID_ADDRESS) {
2202061da546Spatrick LLDB_LOGF(log,
2203061da546Spatrick "unable to allocate %" PRIu32
2204061da546Spatrick " bytes in process for shared cache read",
2205061da546Spatrick class_infos_byte_size);
2206061da546Spatrick return DescriptorMapUpdateResult::Fail();
2207061da546Spatrick }
2208061da546Spatrick
2209be691f3bSpatrick std::lock_guard<std::mutex> guard(m_mutex);
2210061da546Spatrick
2211061da546Spatrick // Fill in our function argument values
2212061da546Spatrick arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
2213be691f3bSpatrick arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr;
2214be691f3bSpatrick arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;
2215be691f3bSpatrick arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;
2216be691f3bSpatrick arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;
2217061da546Spatrick // Only dump the runtime classes from the expression evaluation if the log is
2218061da546Spatrick // verbose:
2219*f6aab3d8Srobert Log *type_log = GetLog(LLDBLog::Types);
2220061da546Spatrick bool dump_log = type_log && type_log->GetVerbose();
2221061da546Spatrick
2222be691f3bSpatrick arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;
2223061da546Spatrick
2224061da546Spatrick bool success = false;
2225061da546Spatrick
2226061da546Spatrick diagnostics.Clear();
2227061da546Spatrick
2228061da546Spatrick // Write our function arguments into the process so we can run our function
2229061da546Spatrick if (get_shared_cache_class_info_function->WriteFunctionArguments(
2230be691f3bSpatrick exe_ctx, m_args, arguments, diagnostics)) {
2231061da546Spatrick EvaluateExpressionOptions options;
2232061da546Spatrick options.SetUnwindOnError(true);
2233061da546Spatrick options.SetTryAllThreads(false);
2234061da546Spatrick options.SetStopOthers(true);
2235061da546Spatrick options.SetIgnoreBreakpoints(true);
2236061da546Spatrick options.SetTimeout(process->GetUtilityExpressionTimeout());
2237061da546Spatrick options.SetIsForUtilityExpr(true);
2238061da546Spatrick
2239be691f3bSpatrick CompilerType clang_uint32_t_type =
2240*f6aab3d8Srobert scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
2241be691f3bSpatrick
2242061da546Spatrick Value return_value;
2243be691f3bSpatrick return_value.SetValueType(Value::ValueType::Scalar);
2244061da546Spatrick return_value.SetCompilerType(clang_uint32_t_type);
2245061da546Spatrick return_value.GetScalar() = 0;
2246061da546Spatrick
2247061da546Spatrick diagnostics.Clear();
2248061da546Spatrick
2249061da546Spatrick // Run the function
2250061da546Spatrick ExpressionResults results =
2251061da546Spatrick get_shared_cache_class_info_function->ExecuteFunction(
2252be691f3bSpatrick exe_ctx, &m_args, options, diagnostics, return_value);
2253061da546Spatrick
2254061da546Spatrick if (results == eExpressionCompleted) {
2255061da546Spatrick // The result is the number of ClassInfo structures that were filled in
2256061da546Spatrick num_class_infos = return_value.GetScalar().ULong();
2257be691f3bSpatrick LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",
2258061da546Spatrick num_class_infos);
2259*f6aab3d8Srobert // Assert if there were more classes than we pre-allocated
2260*f6aab3d8Srobert // room for.
2261*f6aab3d8Srobert assert(num_class_infos <= max_num_classes);
2262061da546Spatrick if (num_class_infos > 0) {
2263*f6aab3d8Srobert if (num_class_infos > max_num_classes) {
2264*f6aab3d8Srobert num_class_infos = max_num_classes;
2265061da546Spatrick
2266061da546Spatrick success = false;
2267061da546Spatrick } else {
2268061da546Spatrick success = true;
2269061da546Spatrick }
2270061da546Spatrick
2271be691f3bSpatrick // Read the relative selector offset.
2272be691f3bSpatrick DataBufferHeap relative_selector_offset_buffer(64, 0);
2273be691f3bSpatrick if (process->ReadMemory(relative_selector_offset_addr,
2274be691f3bSpatrick relative_selector_offset_buffer.GetBytes(),
2275be691f3bSpatrick relative_selector_offset_buffer.GetByteSize(),
2276be691f3bSpatrick err) ==
2277be691f3bSpatrick relative_selector_offset_buffer.GetByteSize()) {
2278be691f3bSpatrick DataExtractor relative_selector_offset_data(
2279be691f3bSpatrick relative_selector_offset_buffer.GetBytes(),
2280be691f3bSpatrick relative_selector_offset_buffer.GetByteSize(),
2281be691f3bSpatrick process->GetByteOrder(), addr_size);
2282be691f3bSpatrick lldb::offset_t offset = 0;
2283be691f3bSpatrick uint64_t relative_selector_offset =
2284be691f3bSpatrick relative_selector_offset_data.GetU64(&offset);
2285be691f3bSpatrick if (relative_selector_offset > 0) {
2286be691f3bSpatrick // The offset is relative to the objc_opt struct.
2287be691f3bSpatrick m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +
2288be691f3bSpatrick relative_selector_offset);
2289be691f3bSpatrick }
2290be691f3bSpatrick }
2291be691f3bSpatrick
2292061da546Spatrick // Read the ClassInfo structures
2293be691f3bSpatrick DataBufferHeap class_infos_buffer(
2294be691f3bSpatrick num_class_infos * class_info_byte_size, 0);
2295be691f3bSpatrick if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),
2296be691f3bSpatrick class_infos_buffer.GetByteSize(),
2297be691f3bSpatrick err) == class_infos_buffer.GetByteSize()) {
2298be691f3bSpatrick DataExtractor class_infos_data(class_infos_buffer.GetBytes(),
2299be691f3bSpatrick class_infos_buffer.GetByteSize(),
2300061da546Spatrick process->GetByteOrder(), addr_size);
2301061da546Spatrick
2302be691f3bSpatrick m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);
2303061da546Spatrick }
2304061da546Spatrick } else {
2305061da546Spatrick success = true;
2306061da546Spatrick }
2307061da546Spatrick } else {
2308061da546Spatrick if (log) {
2309061da546Spatrick LLDB_LOGF(log, "Error evaluating our find class name function.");
2310061da546Spatrick diagnostics.Dump(log);
2311061da546Spatrick }
2312061da546Spatrick }
2313061da546Spatrick } else {
2314061da546Spatrick if (log) {
2315061da546Spatrick LLDB_LOGF(log, "Error writing function arguments.");
2316061da546Spatrick diagnostics.Dump(log);
2317061da546Spatrick }
2318061da546Spatrick }
2319061da546Spatrick
2320061da546Spatrick // Deallocate the memory we allocated for the ClassInfo array
2321061da546Spatrick process->DeallocateMemory(class_infos_addr);
2322061da546Spatrick
2323*f6aab3d8Srobert return DescriptorMapUpdateResult(success, false, num_class_infos);
2324061da546Spatrick }
2325061da546Spatrick
GetSharedCacheReadOnlyAddress()2326061da546Spatrick lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
2327061da546Spatrick Process *process = GetProcess();
2328061da546Spatrick
2329061da546Spatrick if (process) {
2330061da546Spatrick ModuleSP objc_module_sp(GetObjCModule());
2331061da546Spatrick
2332061da546Spatrick if (objc_module_sp) {
2333061da546Spatrick ObjectFile *objc_object = objc_module_sp->GetObjectFile();
2334061da546Spatrick
2335061da546Spatrick if (objc_object) {
2336061da546Spatrick SectionList *section_list = objc_module_sp->GetSectionList();
2337061da546Spatrick
2338061da546Spatrick if (section_list) {
2339061da546Spatrick SectionSP text_segment_sp(
2340061da546Spatrick section_list->FindSectionByName(ConstString("__TEXT")));
2341061da546Spatrick
2342061da546Spatrick if (text_segment_sp) {
2343061da546Spatrick SectionSP objc_opt_section_sp(
2344061da546Spatrick text_segment_sp->GetChildren().FindSectionByName(
2345061da546Spatrick ConstString("__objc_opt_ro")));
2346061da546Spatrick
2347061da546Spatrick if (objc_opt_section_sp) {
2348061da546Spatrick return objc_opt_section_sp->GetLoadBaseAddress(
2349061da546Spatrick &process->GetTarget());
2350061da546Spatrick }
2351061da546Spatrick }
2352061da546Spatrick }
2353061da546Spatrick }
2354061da546Spatrick }
2355061da546Spatrick }
2356061da546Spatrick return LLDB_INVALID_ADDRESS;
2357061da546Spatrick }
2358061da546Spatrick
GetSharedCacheBaseAddress()2359be691f3bSpatrick lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() {
2360be691f3bSpatrick StructuredData::ObjectSP info = m_process->GetSharedCacheInfo();
2361be691f3bSpatrick if (!info)
2362be691f3bSpatrick return LLDB_INVALID_ADDRESS;
2363061da546Spatrick
2364be691f3bSpatrick StructuredData::Dictionary *info_dict = info->GetAsDictionary();
2365be691f3bSpatrick if (!info_dict)
2366be691f3bSpatrick return LLDB_INVALID_ADDRESS;
2367be691f3bSpatrick
2368*f6aab3d8Srobert StructuredData::ObjectSP value =
2369*f6aab3d8Srobert info_dict->GetValueForKey("shared_cache_base_address");
2370*f6aab3d8Srobert if (!value)
2371*f6aab3d8Srobert return LLDB_INVALID_ADDRESS;
2372*f6aab3d8Srobert
2373*f6aab3d8Srobert return value->GetIntegerValue(LLDB_INVALID_ADDRESS);
2374be691f3bSpatrick }
2375be691f3bSpatrick
UpdateISAToDescriptorMapIfNeeded()2376be691f3bSpatrick void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {
2377be691f3bSpatrick LLDB_SCOPED_TIMER();
2378be691f3bSpatrick
2379*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
2380061da546Spatrick
2381061da546Spatrick // Else we need to check with our process to see when the map was updated.
2382061da546Spatrick Process *process = GetProcess();
2383061da546Spatrick
2384061da546Spatrick if (process) {
2385061da546Spatrick RemoteNXMapTable hash_table;
2386061da546Spatrick
2387061da546Spatrick // Update the process stop ID that indicates the last time we updated the
2388061da546Spatrick // map, whether it was successful or not.
2389061da546Spatrick m_isa_to_descriptor_stop_id = process->GetStopID();
2390061da546Spatrick
2391be691f3bSpatrick // Ask the runtime is the realized class generation count changed. Unlike
2392be691f3bSpatrick // the hash table, this accounts for lazily named classes.
2393be691f3bSpatrick const bool class_count_changed = RealizedClassGenerationCountChanged();
2394be691f3bSpatrick
2395be691f3bSpatrick if (!m_hash_signature.NeedsUpdate(process, this, hash_table) &&
2396be691f3bSpatrick !class_count_changed)
2397061da546Spatrick return;
2398061da546Spatrick
2399061da546Spatrick m_hash_signature.UpdateSignature(hash_table);
2400061da546Spatrick
2401be691f3bSpatrick // Grab the dynamically loaded Objective-C classes from memory.
2402061da546Spatrick DescriptorMapUpdateResult dynamic_update_result =
2403be691f3bSpatrick m_dynamic_class_info_extractor.UpdateISAToDescriptorMap(hash_table);
2404061da546Spatrick
2405061da546Spatrick // Now get the objc classes that are baked into the Objective-C runtime in
2406061da546Spatrick // the shared cache, but only once per process as this data never changes
2407061da546Spatrick if (!m_loaded_objc_opt) {
2408061da546Spatrick // it is legitimately possible for the shared cache to be empty - in that
2409061da546Spatrick // case, the dynamic hash table will contain all the class information we
2410061da546Spatrick // need; the situation we're trying to detect is one where we aren't
2411061da546Spatrick // seeing class information from the runtime - in order to detect that
2412061da546Spatrick // vs. just the shared cache being empty or sparsely populated, we set an
2413061da546Spatrick // arbitrary (very low) threshold for the number of classes that we want
2414061da546Spatrick // to see in a "good" scenario - anything below that is suspicious
2415061da546Spatrick // (Foundation alone has thousands of classes)
2416061da546Spatrick const uint32_t num_classes_to_warn_at = 500;
2417061da546Spatrick
2418061da546Spatrick DescriptorMapUpdateResult shared_cache_update_result =
2419be691f3bSpatrick m_shared_cache_class_info_extractor.UpdateISAToDescriptorMap();
2420061da546Spatrick
2421061da546Spatrick LLDB_LOGF(log,
2422061da546Spatrick "attempted to read objc class data - results: "
2423*f6aab3d8Srobert "[dynamic_update]: ran: %s, retry: %s, count: %" PRIu32
2424*f6aab3d8Srobert " [shared_cache_update]: ran: %s, retry: %s, count: %" PRIu32,
2425061da546Spatrick dynamic_update_result.m_update_ran ? "yes" : "no",
2426*f6aab3d8Srobert dynamic_update_result.m_retry_update ? "yes" : "no",
2427061da546Spatrick dynamic_update_result.m_num_found,
2428061da546Spatrick shared_cache_update_result.m_update_ran ? "yes" : "no",
2429*f6aab3d8Srobert shared_cache_update_result.m_retry_update ? "yes" : "no",
2430061da546Spatrick shared_cache_update_result.m_num_found);
2431061da546Spatrick
2432061da546Spatrick // warn if:
2433061da546Spatrick // - we could not run either expression
2434061da546Spatrick // - we found fewer than num_classes_to_warn_at classes total
2435*f6aab3d8Srobert if (dynamic_update_result.m_retry_update ||
2436*f6aab3d8Srobert shared_cache_update_result.m_retry_update)
2437*f6aab3d8Srobert WarnIfNoClassesCached(SharedCacheWarningReason::eExpressionUnableToRun);
2438*f6aab3d8Srobert else if ((!shared_cache_update_result.m_update_ran) ||
2439061da546Spatrick (!dynamic_update_result.m_update_ran))
2440061da546Spatrick WarnIfNoClassesCached(
2441061da546Spatrick SharedCacheWarningReason::eExpressionExecutionFailure);
2442061da546Spatrick else if (dynamic_update_result.m_num_found +
2443061da546Spatrick shared_cache_update_result.m_num_found <
2444061da546Spatrick num_classes_to_warn_at)
2445061da546Spatrick WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead);
2446061da546Spatrick else
2447061da546Spatrick m_loaded_objc_opt = true;
2448061da546Spatrick }
2449061da546Spatrick } else {
2450061da546Spatrick m_isa_to_descriptor_stop_id = UINT32_MAX;
2451061da546Spatrick }
2452061da546Spatrick }
2453061da546Spatrick
RealizedClassGenerationCountChanged()2454be691f3bSpatrick bool AppleObjCRuntimeV2::RealizedClassGenerationCountChanged() {
2455be691f3bSpatrick Process *process = GetProcess();
2456be691f3bSpatrick if (!process)
2457be691f3bSpatrick return false;
2458be691f3bSpatrick
2459be691f3bSpatrick Status error;
2460be691f3bSpatrick uint64_t objc_debug_realized_class_generation_count =
2461be691f3bSpatrick ExtractRuntimeGlobalSymbol(
2462be691f3bSpatrick process, ConstString("objc_debug_realized_class_generation_count"),
2463be691f3bSpatrick GetObjCModule(), error);
2464be691f3bSpatrick if (error.Fail())
2465be691f3bSpatrick return false;
2466be691f3bSpatrick
2467be691f3bSpatrick if (m_realized_class_generation_count ==
2468be691f3bSpatrick objc_debug_realized_class_generation_count)
2469be691f3bSpatrick return false;
2470be691f3bSpatrick
2471*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);
2472be691f3bSpatrick LLDB_LOG(log,
2473be691f3bSpatrick "objc_debug_realized_class_generation_count changed from {0} to {1}",
2474be691f3bSpatrick m_realized_class_generation_count,
2475be691f3bSpatrick objc_debug_realized_class_generation_count);
2476be691f3bSpatrick
2477be691f3bSpatrick m_realized_class_generation_count =
2478be691f3bSpatrick objc_debug_realized_class_generation_count;
2479be691f3bSpatrick
2480be691f3bSpatrick return true;
2481be691f3bSpatrick }
2482be691f3bSpatrick
DoesProcessHaveSharedCache(Process & process)2483061da546Spatrick static bool DoesProcessHaveSharedCache(Process &process) {
2484061da546Spatrick PlatformSP platform_sp = process.GetTarget().GetPlatform();
2485061da546Spatrick if (!platform_sp)
2486061da546Spatrick return true; // this should not happen
2487061da546Spatrick
2488*f6aab3d8Srobert llvm::StringRef platform_plugin_name_sr = platform_sp->GetPluginName();
2489061da546Spatrick if (platform_plugin_name_sr.endswith("-simulator"))
2490061da546Spatrick return false;
2491061da546Spatrick
2492061da546Spatrick return true;
2493061da546Spatrick }
2494061da546Spatrick
WarnIfNoClassesCached(SharedCacheWarningReason reason)2495061da546Spatrick void AppleObjCRuntimeV2::WarnIfNoClassesCached(
2496061da546Spatrick SharedCacheWarningReason reason) {
2497061da546Spatrick if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) {
2498061da546Spatrick // Simulators do not have the objc_opt_ro class table so don't actually
2499061da546Spatrick // complain to the user
2500061da546Spatrick return;
2501061da546Spatrick }
2502061da546Spatrick
2503061da546Spatrick Debugger &debugger(GetProcess()->GetTarget().GetDebugger());
2504061da546Spatrick switch (reason) {
2505061da546Spatrick case SharedCacheWarningReason::eNotEnoughClassesRead:
2506*f6aab3d8Srobert Debugger::ReportWarning("could not find Objective-C class data in "
2507061da546Spatrick "the process. This may reduce the quality of type "
2508*f6aab3d8Srobert "information available.\n",
2509*f6aab3d8Srobert debugger.GetID(), &m_no_classes_cached_warning);
2510061da546Spatrick break;
2511061da546Spatrick case SharedCacheWarningReason::eExpressionExecutionFailure:
2512*f6aab3d8Srobert Debugger::ReportWarning(
2513*f6aab3d8Srobert "could not execute support code to read "
2514061da546Spatrick "Objective-C class data in the process. This may "
2515*f6aab3d8Srobert "reduce the quality of type information available.\n",
2516*f6aab3d8Srobert debugger.GetID(), &m_no_classes_cached_warning);
2517*f6aab3d8Srobert break;
2518*f6aab3d8Srobert case SharedCacheWarningReason::eExpressionUnableToRun:
2519*f6aab3d8Srobert Debugger::ReportWarning(
2520*f6aab3d8Srobert "could not execute support code to read Objective-C class data because "
2521*f6aab3d8Srobert "it's not yet safe to do so, and will be retried later.\n",
2522*f6aab3d8Srobert debugger.GetID(), nullptr);
2523061da546Spatrick break;
2524061da546Spatrick }
2525061da546Spatrick }
2526*f6aab3d8Srobert
WarnIfNoExpandedSharedCache()2527*f6aab3d8Srobert void AppleObjCRuntimeV2::WarnIfNoExpandedSharedCache() {
2528*f6aab3d8Srobert if (!m_objc_module_sp)
2529*f6aab3d8Srobert return;
2530*f6aab3d8Srobert
2531*f6aab3d8Srobert ObjectFile *object_file = m_objc_module_sp->GetObjectFile();
2532*f6aab3d8Srobert if (!object_file)
2533*f6aab3d8Srobert return;
2534*f6aab3d8Srobert
2535*f6aab3d8Srobert if (!object_file->IsInMemory())
2536*f6aab3d8Srobert return;
2537*f6aab3d8Srobert
2538*f6aab3d8Srobert Target &target = GetProcess()->GetTarget();
2539*f6aab3d8Srobert Debugger &debugger = target.GetDebugger();
2540*f6aab3d8Srobert
2541*f6aab3d8Srobert std::string buffer;
2542*f6aab3d8Srobert llvm::raw_string_ostream os(buffer);
2543*f6aab3d8Srobert
2544*f6aab3d8Srobert os << "libobjc.A.dylib is being read from process memory. This "
2545*f6aab3d8Srobert "indicates that LLDB could not ";
2546*f6aab3d8Srobert if (PlatformSP platform_sp = target.GetPlatform()) {
2547*f6aab3d8Srobert if (platform_sp->IsHost()) {
2548*f6aab3d8Srobert os << "read from the host's in-memory shared cache";
2549*f6aab3d8Srobert } else {
2550*f6aab3d8Srobert os << "find the on-disk shared cache for this device";
2551*f6aab3d8Srobert }
2552*f6aab3d8Srobert } else {
2553*f6aab3d8Srobert os << "read from the shared cache";
2554*f6aab3d8Srobert }
2555*f6aab3d8Srobert os << ". This will likely reduce debugging performance.\n";
2556*f6aab3d8Srobert
2557*f6aab3d8Srobert Debugger::ReportWarning(os.str(), debugger.GetID(),
2558*f6aab3d8Srobert &m_no_expanded_cache_warning);
2559061da546Spatrick }
2560061da546Spatrick
GetDeclVendor()2561061da546Spatrick DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() {
2562061da546Spatrick if (!m_decl_vendor_up)
2563dda28197Spatrick m_decl_vendor_up = std::make_unique<AppleObjCDeclVendor>(*this);
2564061da546Spatrick
2565061da546Spatrick return m_decl_vendor_up.get();
2566061da546Spatrick }
2567061da546Spatrick
LookupRuntimeSymbol(ConstString name)2568061da546Spatrick lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {
2569061da546Spatrick lldb::addr_t ret = LLDB_INVALID_ADDRESS;
2570061da546Spatrick
2571061da546Spatrick const char *name_cstr = name.AsCString();
2572061da546Spatrick
2573061da546Spatrick if (name_cstr) {
2574061da546Spatrick llvm::StringRef name_strref(name_cstr);
2575061da546Spatrick
2576061da546Spatrick llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
2577061da546Spatrick llvm::StringRef class_prefix("OBJC_CLASS_$_");
2578061da546Spatrick
2579061da546Spatrick if (name_strref.startswith(ivar_prefix)) {
2580061da546Spatrick llvm::StringRef ivar_skipped_prefix =
2581061da546Spatrick name_strref.substr(ivar_prefix.size());
2582061da546Spatrick std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =
2583061da546Spatrick ivar_skipped_prefix.split('.');
2584061da546Spatrick
2585061da546Spatrick if (class_and_ivar.first.size() && class_and_ivar.second.size()) {
2586061da546Spatrick const ConstString class_name_cs(class_and_ivar.first);
2587061da546Spatrick ClassDescriptorSP descriptor =
2588061da546Spatrick ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);
2589061da546Spatrick
2590061da546Spatrick if (descriptor) {
2591061da546Spatrick const ConstString ivar_name_cs(class_and_ivar.second);
2592061da546Spatrick const char *ivar_name_cstr = ivar_name_cs.AsCString();
2593061da546Spatrick
2594be691f3bSpatrick auto ivar_func = [&ret,
2595be691f3bSpatrick ivar_name_cstr](const char *name, const char *type,
2596be691f3bSpatrick lldb::addr_t offset_addr,
2597061da546Spatrick uint64_t size) -> lldb::addr_t {
2598061da546Spatrick if (!strcmp(name, ivar_name_cstr)) {
2599061da546Spatrick ret = offset_addr;
2600061da546Spatrick return true;
2601061da546Spatrick }
2602061da546Spatrick return false;
2603061da546Spatrick };
2604061da546Spatrick
2605061da546Spatrick descriptor->Describe(
2606061da546Spatrick std::function<void(ObjCISA)>(nullptr),
2607061da546Spatrick std::function<bool(const char *, const char *)>(nullptr),
2608061da546Spatrick std::function<bool(const char *, const char *)>(nullptr),
2609061da546Spatrick ivar_func);
2610061da546Spatrick }
2611061da546Spatrick }
2612061da546Spatrick } else if (name_strref.startswith(class_prefix)) {
2613061da546Spatrick llvm::StringRef class_skipped_prefix =
2614061da546Spatrick name_strref.substr(class_prefix.size());
2615061da546Spatrick const ConstString class_name_cs(class_skipped_prefix);
2616061da546Spatrick ClassDescriptorSP descriptor =
2617061da546Spatrick GetClassDescriptorFromClassName(class_name_cs);
2618061da546Spatrick
2619061da546Spatrick if (descriptor)
2620061da546Spatrick ret = descriptor->GetISA();
2621061da546Spatrick }
2622061da546Spatrick }
2623061da546Spatrick
2624061da546Spatrick return ret;
2625061da546Spatrick }
2626061da546Spatrick
2627061da546Spatrick AppleObjCRuntimeV2::NonPointerISACache *
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2628061da546Spatrick AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(
2629061da546Spatrick AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2630061da546Spatrick Process *process(runtime.GetProcess());
2631061da546Spatrick
2632061da546Spatrick Status error;
2633061da546Spatrick
2634*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Types);
2635061da546Spatrick
2636061da546Spatrick auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(
2637061da546Spatrick process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);
2638061da546Spatrick if (error.Fail())
2639061da546Spatrick return nullptr;
2640061da546Spatrick
2641061da546Spatrick auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(
2642061da546Spatrick process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,
2643061da546Spatrick error);
2644061da546Spatrick if (error.Fail())
2645061da546Spatrick return nullptr;
2646061da546Spatrick
2647061da546Spatrick auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(
2648061da546Spatrick process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);
2649061da546Spatrick if (error.Fail())
2650061da546Spatrick return nullptr;
2651061da546Spatrick
2652061da546Spatrick if (log)
2653061da546Spatrick log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks");
2654061da546Spatrick
2655061da546Spatrick bool foundError = false;
2656061da546Spatrick auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol(
2657061da546Spatrick process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp,
2658061da546Spatrick error);
2659061da546Spatrick foundError |= error.Fail();
2660061da546Spatrick
2661061da546Spatrick auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol(
2662061da546Spatrick process, ConstString("objc_debug_indexed_isa_magic_value"),
2663061da546Spatrick objc_module_sp, error);
2664061da546Spatrick foundError |= error.Fail();
2665061da546Spatrick
2666061da546Spatrick auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol(
2667061da546Spatrick process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp,
2668061da546Spatrick error);
2669061da546Spatrick foundError |= error.Fail();
2670061da546Spatrick
2671061da546Spatrick auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol(
2672061da546Spatrick process, ConstString("objc_debug_indexed_isa_index_shift"),
2673061da546Spatrick objc_module_sp, error);
2674061da546Spatrick foundError |= error.Fail();
2675061da546Spatrick
2676061da546Spatrick auto objc_indexed_classes =
2677061da546Spatrick ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"),
2678061da546Spatrick objc_module_sp, error, false);
2679061da546Spatrick foundError |= error.Fail();
2680061da546Spatrick
2681061da546Spatrick if (log)
2682061da546Spatrick log->PutCString("AOCRT::NPI: Found all the indexed ISA masks");
2683061da546Spatrick
2684061da546Spatrick // we might want to have some rules to outlaw these other values (e.g if the
2685061da546Spatrick // mask is zero but the value is non-zero, ...)
2686061da546Spatrick
2687061da546Spatrick return new NonPointerISACache(
2688061da546Spatrick runtime, objc_module_sp, objc_debug_isa_class_mask,
2689061da546Spatrick objc_debug_isa_magic_mask, objc_debug_isa_magic_value,
2690061da546Spatrick objc_debug_indexed_isa_magic_mask, objc_debug_indexed_isa_magic_value,
2691061da546Spatrick objc_debug_indexed_isa_index_mask, objc_debug_indexed_isa_index_shift,
2692061da546Spatrick foundError ? 0 : objc_indexed_classes);
2693061da546Spatrick }
2694061da546Spatrick
2695061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorV2 *
CreateInstance(AppleObjCRuntimeV2 & runtime,const lldb::ModuleSP & objc_module_sp)2696061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
2697061da546Spatrick AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2698061da546Spatrick Process *process(runtime.GetProcess());
2699061da546Spatrick
2700061da546Spatrick Status error;
2701061da546Spatrick
2702061da546Spatrick auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(
2703061da546Spatrick process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,
2704061da546Spatrick error);
2705061da546Spatrick if (error.Fail())
2706061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2707061da546Spatrick
2708061da546Spatrick auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(
2709061da546Spatrick process, ConstString("objc_debug_taggedpointer_slot_shift"),
2710061da546Spatrick objc_module_sp, error, true, 4);
2711061da546Spatrick if (error.Fail())
2712061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2713061da546Spatrick
2714061da546Spatrick auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(
2715061da546Spatrick process, ConstString("objc_debug_taggedpointer_slot_mask"),
2716061da546Spatrick objc_module_sp, error, true, 4);
2717061da546Spatrick if (error.Fail())
2718061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2719061da546Spatrick
2720061da546Spatrick auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(
2721061da546Spatrick process, ConstString("objc_debug_taggedpointer_payload_lshift"),
2722061da546Spatrick objc_module_sp, error, true, 4);
2723061da546Spatrick if (error.Fail())
2724061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2725061da546Spatrick
2726061da546Spatrick auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(
2727061da546Spatrick process, ConstString("objc_debug_taggedpointer_payload_rshift"),
2728061da546Spatrick objc_module_sp, error, true, 4);
2729061da546Spatrick if (error.Fail())
2730061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2731061da546Spatrick
2732061da546Spatrick auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(
2733061da546Spatrick process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,
2734061da546Spatrick error, false);
2735061da546Spatrick if (error.Fail())
2736061da546Spatrick return new TaggedPointerVendorLegacy(runtime);
2737061da546Spatrick
2738061da546Spatrick // try to detect the "extended tagged pointer" variables - if any are
2739061da546Spatrick // missing, use the non-extended vendor
2740061da546Spatrick do {
2741061da546Spatrick auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(
2742061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_mask"),
2743061da546Spatrick objc_module_sp, error);
2744061da546Spatrick if (error.Fail())
2745061da546Spatrick break;
2746061da546Spatrick
2747061da546Spatrick auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(
2748061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),
2749061da546Spatrick objc_module_sp, error, true, 4);
2750061da546Spatrick if (error.Fail())
2751061da546Spatrick break;
2752061da546Spatrick
2753061da546Spatrick auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(
2754061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),
2755061da546Spatrick objc_module_sp, error, true, 4);
2756061da546Spatrick if (error.Fail())
2757061da546Spatrick break;
2758061da546Spatrick
2759061da546Spatrick auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(
2760061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_classes"),
2761061da546Spatrick objc_module_sp, error, false);
2762061da546Spatrick if (error.Fail())
2763061da546Spatrick break;
2764061da546Spatrick
2765061da546Spatrick auto objc_debug_taggedpointer_ext_payload_lshift =
2766061da546Spatrick ExtractRuntimeGlobalSymbol(
2767061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),
2768061da546Spatrick objc_module_sp, error, true, 4);
2769061da546Spatrick if (error.Fail())
2770061da546Spatrick break;
2771061da546Spatrick
2772061da546Spatrick auto objc_debug_taggedpointer_ext_payload_rshift =
2773061da546Spatrick ExtractRuntimeGlobalSymbol(
2774061da546Spatrick process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),
2775061da546Spatrick objc_module_sp, error, true, 4);
2776061da546Spatrick if (error.Fail())
2777061da546Spatrick break;
2778061da546Spatrick
2779061da546Spatrick return new TaggedPointerVendorExtended(
2780061da546Spatrick runtime, objc_debug_taggedpointer_mask,
2781061da546Spatrick objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift,
2782061da546Spatrick objc_debug_taggedpointer_ext_slot_shift,
2783061da546Spatrick objc_debug_taggedpointer_slot_mask,
2784061da546Spatrick objc_debug_taggedpointer_ext_slot_mask,
2785061da546Spatrick objc_debug_taggedpointer_payload_lshift,
2786061da546Spatrick objc_debug_taggedpointer_payload_rshift,
2787061da546Spatrick objc_debug_taggedpointer_ext_payload_lshift,
2788061da546Spatrick objc_debug_taggedpointer_ext_payload_rshift,
2789061da546Spatrick objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);
2790061da546Spatrick } while (false);
2791061da546Spatrick
2792061da546Spatrick // we might want to have some rules to outlaw these values (e.g if the
2793061da546Spatrick // table's address is zero)
2794061da546Spatrick
2795061da546Spatrick return new TaggedPointerVendorRuntimeAssisted(
2796061da546Spatrick runtime, objc_debug_taggedpointer_mask,
2797061da546Spatrick objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask,
2798061da546Spatrick objc_debug_taggedpointer_payload_lshift,
2799061da546Spatrick objc_debug_taggedpointer_payload_rshift,
2800061da546Spatrick objc_debug_taggedpointer_classes);
2801061da546Spatrick }
2802061da546Spatrick
IsPossibleTaggedPointer(lldb::addr_t ptr)2803061da546Spatrick bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer(
2804061da546Spatrick lldb::addr_t ptr) {
2805061da546Spatrick return (ptr & 1);
2806061da546Spatrick }
2807061da546Spatrick
2808061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2809061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor(
2810061da546Spatrick lldb::addr_t ptr) {
2811061da546Spatrick if (!IsPossibleTaggedPointer(ptr))
2812061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2813061da546Spatrick
2814061da546Spatrick uint32_t foundation_version = m_runtime.GetFoundationVersion();
2815061da546Spatrick
2816061da546Spatrick if (foundation_version == LLDB_INVALID_MODULE_VERSION)
2817061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2818061da546Spatrick
2819061da546Spatrick uint64_t class_bits = (ptr & 0xE) >> 1;
2820061da546Spatrick ConstString name;
2821061da546Spatrick
2822061da546Spatrick static ConstString g_NSAtom("NSAtom");
2823061da546Spatrick static ConstString g_NSNumber("NSNumber");
2824061da546Spatrick static ConstString g_NSDateTS("NSDateTS");
2825061da546Spatrick static ConstString g_NSManagedObject("NSManagedObject");
2826061da546Spatrick static ConstString g_NSDate("NSDate");
2827061da546Spatrick
2828061da546Spatrick if (foundation_version >= 900) {
2829061da546Spatrick switch (class_bits) {
2830061da546Spatrick case 0:
2831061da546Spatrick name = g_NSAtom;
2832061da546Spatrick break;
2833061da546Spatrick case 3:
2834061da546Spatrick name = g_NSNumber;
2835061da546Spatrick break;
2836061da546Spatrick case 4:
2837061da546Spatrick name = g_NSDateTS;
2838061da546Spatrick break;
2839061da546Spatrick case 5:
2840061da546Spatrick name = g_NSManagedObject;
2841061da546Spatrick break;
2842061da546Spatrick case 6:
2843061da546Spatrick name = g_NSDate;
2844061da546Spatrick break;
2845061da546Spatrick default:
2846061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2847061da546Spatrick }
2848061da546Spatrick } else {
2849061da546Spatrick switch (class_bits) {
2850061da546Spatrick case 1:
2851061da546Spatrick name = g_NSNumber;
2852061da546Spatrick break;
2853061da546Spatrick case 5:
2854061da546Spatrick name = g_NSManagedObject;
2855061da546Spatrick break;
2856061da546Spatrick case 6:
2857061da546Spatrick name = g_NSDate;
2858061da546Spatrick break;
2859061da546Spatrick case 7:
2860061da546Spatrick name = g_NSDateTS;
2861061da546Spatrick break;
2862061da546Spatrick default:
2863061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2864061da546Spatrick }
2865061da546Spatrick }
2866061da546Spatrick
2867061da546Spatrick lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator();
2868061da546Spatrick return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated));
2869061da546Spatrick }
2870061da546Spatrick
2871061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
TaggedPointerVendorRuntimeAssisted(AppleObjCRuntimeV2 & runtime,uint64_t objc_debug_taggedpointer_mask,uint32_t objc_debug_taggedpointer_slot_shift,uint32_t objc_debug_taggedpointer_slot_mask,uint32_t objc_debug_taggedpointer_payload_lshift,uint32_t objc_debug_taggedpointer_payload_rshift,lldb::addr_t objc_debug_taggedpointer_classes)2872061da546Spatrick TaggedPointerVendorRuntimeAssisted(
2873061da546Spatrick AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2874061da546Spatrick uint32_t objc_debug_taggedpointer_slot_shift,
2875061da546Spatrick uint32_t objc_debug_taggedpointer_slot_mask,
2876061da546Spatrick uint32_t objc_debug_taggedpointer_payload_lshift,
2877061da546Spatrick uint32_t objc_debug_taggedpointer_payload_rshift,
2878061da546Spatrick lldb::addr_t objc_debug_taggedpointer_classes)
2879061da546Spatrick : TaggedPointerVendorV2(runtime), m_cache(),
2880061da546Spatrick m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
2881061da546Spatrick m_objc_debug_taggedpointer_slot_shift(
2882061da546Spatrick objc_debug_taggedpointer_slot_shift),
2883061da546Spatrick m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
2884061da546Spatrick m_objc_debug_taggedpointer_payload_lshift(
2885061da546Spatrick objc_debug_taggedpointer_payload_lshift),
2886061da546Spatrick m_objc_debug_taggedpointer_payload_rshift(
2887061da546Spatrick objc_debug_taggedpointer_payload_rshift),
2888061da546Spatrick m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {}
2889061da546Spatrick
2890061da546Spatrick bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
IsPossibleTaggedPointer(lldb::addr_t ptr)2891061da546Spatrick IsPossibleTaggedPointer(lldb::addr_t ptr) {
2892061da546Spatrick return (ptr & m_objc_debug_taggedpointer_mask) != 0;
2893061da546Spatrick }
2894061da546Spatrick
2895061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2896061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
2897061da546Spatrick lldb::addr_t ptr) {
2898061da546Spatrick ClassDescriptorSP actual_class_descriptor_sp;
2899061da546Spatrick uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
2900061da546Spatrick
2901061da546Spatrick if (!IsPossibleTaggedPointer(unobfuscated))
2902061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2903061da546Spatrick
2904061da546Spatrick uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) &
2905061da546Spatrick m_objc_debug_taggedpointer_slot_mask;
2906061da546Spatrick
2907061da546Spatrick CacheIterator iterator = m_cache.find(slot), end = m_cache.end();
2908061da546Spatrick if (iterator != end) {
2909061da546Spatrick actual_class_descriptor_sp = iterator->second;
2910061da546Spatrick } else {
2911061da546Spatrick Process *process(m_runtime.GetProcess());
2912061da546Spatrick uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
2913061da546Spatrick m_objc_debug_taggedpointer_classes;
2914061da546Spatrick Status error;
2915061da546Spatrick uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2916061da546Spatrick if (error.Fail() || slot_data == 0 ||
2917061da546Spatrick slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2918061da546Spatrick return nullptr;
2919061da546Spatrick actual_class_descriptor_sp =
2920061da546Spatrick m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2921*f6aab3d8Srobert if (!actual_class_descriptor_sp) {
2922*f6aab3d8Srobert if (ABISP abi_sp = process->GetABI()) {
2923*f6aab3d8Srobert ObjCISA fixed_isa = abi_sp->FixCodeAddress((ObjCISA)slot_data);
2924*f6aab3d8Srobert actual_class_descriptor_sp =
2925*f6aab3d8Srobert m_runtime.GetClassDescriptorFromISA(fixed_isa);
2926*f6aab3d8Srobert }
2927*f6aab3d8Srobert }
2928061da546Spatrick if (!actual_class_descriptor_sp)
2929061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2930061da546Spatrick m_cache[slot] = actual_class_descriptor_sp;
2931061da546Spatrick }
2932061da546Spatrick
2933be691f3bSpatrick uint64_t data_payload =
2934*f6aab3d8Srobert ((unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>
2935061da546Spatrick m_objc_debug_taggedpointer_payload_rshift);
2936be691f3bSpatrick int64_t data_payload_signed =
2937*f6aab3d8Srobert ((int64_t)(unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>
2938be691f3bSpatrick m_objc_debug_taggedpointer_payload_rshift);
2939be691f3bSpatrick return ClassDescriptorSP(new ClassDescriptorV2Tagged(
2940be691f3bSpatrick actual_class_descriptor_sp, data_payload, data_payload_signed));
2941061da546Spatrick }
2942061da546Spatrick
TaggedPointerVendorExtended(AppleObjCRuntimeV2 & runtime,uint64_t objc_debug_taggedpointer_mask,uint64_t objc_debug_taggedpointer_ext_mask,uint32_t objc_debug_taggedpointer_slot_shift,uint32_t objc_debug_taggedpointer_ext_slot_shift,uint32_t objc_debug_taggedpointer_slot_mask,uint32_t objc_debug_taggedpointer_ext_slot_mask,uint32_t objc_debug_taggedpointer_payload_lshift,uint32_t objc_debug_taggedpointer_payload_rshift,uint32_t objc_debug_taggedpointer_ext_payload_lshift,uint32_t objc_debug_taggedpointer_ext_payload_rshift,lldb::addr_t objc_debug_taggedpointer_classes,lldb::addr_t objc_debug_taggedpointer_ext_classes)2943061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(
2944061da546Spatrick AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2945061da546Spatrick uint64_t objc_debug_taggedpointer_ext_mask,
2946061da546Spatrick uint32_t objc_debug_taggedpointer_slot_shift,
2947061da546Spatrick uint32_t objc_debug_taggedpointer_ext_slot_shift,
2948061da546Spatrick uint32_t objc_debug_taggedpointer_slot_mask,
2949061da546Spatrick uint32_t objc_debug_taggedpointer_ext_slot_mask,
2950061da546Spatrick uint32_t objc_debug_taggedpointer_payload_lshift,
2951061da546Spatrick uint32_t objc_debug_taggedpointer_payload_rshift,
2952061da546Spatrick uint32_t objc_debug_taggedpointer_ext_payload_lshift,
2953061da546Spatrick uint32_t objc_debug_taggedpointer_ext_payload_rshift,
2954061da546Spatrick lldb::addr_t objc_debug_taggedpointer_classes,
2955061da546Spatrick lldb::addr_t objc_debug_taggedpointer_ext_classes)
2956061da546Spatrick : TaggedPointerVendorRuntimeAssisted(
2957061da546Spatrick runtime, objc_debug_taggedpointer_mask,
2958061da546Spatrick objc_debug_taggedpointer_slot_shift,
2959061da546Spatrick objc_debug_taggedpointer_slot_mask,
2960061da546Spatrick objc_debug_taggedpointer_payload_lshift,
2961061da546Spatrick objc_debug_taggedpointer_payload_rshift,
2962061da546Spatrick objc_debug_taggedpointer_classes),
2963061da546Spatrick m_ext_cache(),
2964061da546Spatrick m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),
2965061da546Spatrick m_objc_debug_taggedpointer_ext_slot_shift(
2966061da546Spatrick objc_debug_taggedpointer_ext_slot_shift),
2967061da546Spatrick m_objc_debug_taggedpointer_ext_slot_mask(
2968061da546Spatrick objc_debug_taggedpointer_ext_slot_mask),
2969061da546Spatrick m_objc_debug_taggedpointer_ext_payload_lshift(
2970061da546Spatrick objc_debug_taggedpointer_ext_payload_lshift),
2971061da546Spatrick m_objc_debug_taggedpointer_ext_payload_rshift(
2972061da546Spatrick objc_debug_taggedpointer_ext_payload_rshift),
2973061da546Spatrick m_objc_debug_taggedpointer_ext_classes(
2974061da546Spatrick objc_debug_taggedpointer_ext_classes) {}
2975061da546Spatrick
2976061da546Spatrick bool AppleObjCRuntimeV2::TaggedPointerVendorExtended::
IsPossibleExtendedTaggedPointer(lldb::addr_t ptr)2977061da546Spatrick IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) {
2978061da546Spatrick if (!IsPossibleTaggedPointer(ptr))
2979061da546Spatrick return false;
2980061da546Spatrick
2981061da546Spatrick if (m_objc_debug_taggedpointer_ext_mask == 0)
2982061da546Spatrick return false;
2983061da546Spatrick
2984061da546Spatrick return ((ptr & m_objc_debug_taggedpointer_ext_mask) ==
2985061da546Spatrick m_objc_debug_taggedpointer_ext_mask);
2986061da546Spatrick }
2987061da546Spatrick
2988061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(lldb::addr_t ptr)2989061da546Spatrick AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
2990061da546Spatrick lldb::addr_t ptr) {
2991061da546Spatrick ClassDescriptorSP actual_class_descriptor_sp;
2992061da546Spatrick uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();
2993061da546Spatrick
2994061da546Spatrick if (!IsPossibleTaggedPointer(unobfuscated))
2995061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
2996061da546Spatrick
2997061da546Spatrick if (!IsPossibleExtendedTaggedPointer(unobfuscated))
2998061da546Spatrick return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);
2999061da546Spatrick
3000061da546Spatrick uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) &
3001061da546Spatrick m_objc_debug_taggedpointer_ext_slot_mask;
3002061da546Spatrick
3003061da546Spatrick CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end();
3004061da546Spatrick if (iterator != end) {
3005061da546Spatrick actual_class_descriptor_sp = iterator->second;
3006061da546Spatrick } else {
3007061da546Spatrick Process *process(m_runtime.GetProcess());
3008061da546Spatrick uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
3009061da546Spatrick m_objc_debug_taggedpointer_ext_classes;
3010061da546Spatrick Status error;
3011061da546Spatrick uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
3012061da546Spatrick if (error.Fail() || slot_data == 0 ||
3013061da546Spatrick slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
3014061da546Spatrick return nullptr;
3015061da546Spatrick actual_class_descriptor_sp =
3016061da546Spatrick m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
3017061da546Spatrick if (!actual_class_descriptor_sp)
3018061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
3019061da546Spatrick m_ext_cache[slot] = actual_class_descriptor_sp;
3020061da546Spatrick }
3021061da546Spatrick
3022be691f3bSpatrick uint64_t data_payload = (((uint64_t)unobfuscated
3023be691f3bSpatrick << m_objc_debug_taggedpointer_ext_payload_lshift) >>
3024be691f3bSpatrick m_objc_debug_taggedpointer_ext_payload_rshift);
3025be691f3bSpatrick int64_t data_payload_signed =
3026be691f3bSpatrick ((int64_t)((int64_t)unobfuscated
3027be691f3bSpatrick << m_objc_debug_taggedpointer_ext_payload_lshift) >>
3028061da546Spatrick m_objc_debug_taggedpointer_ext_payload_rshift);
3029061da546Spatrick
3030be691f3bSpatrick return ClassDescriptorSP(new ClassDescriptorV2Tagged(
3031be691f3bSpatrick actual_class_descriptor_sp, data_payload, data_payload_signed));
3032061da546Spatrick }
3033061da546Spatrick
NonPointerISACache(AppleObjCRuntimeV2 & runtime,const ModuleSP & objc_module_sp,uint64_t objc_debug_isa_class_mask,uint64_t objc_debug_isa_magic_mask,uint64_t objc_debug_isa_magic_value,uint64_t objc_debug_indexed_isa_magic_mask,uint64_t objc_debug_indexed_isa_magic_value,uint64_t objc_debug_indexed_isa_index_mask,uint64_t objc_debug_indexed_isa_index_shift,lldb::addr_t objc_indexed_classes)3034061da546Spatrick AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(
3035061da546Spatrick AppleObjCRuntimeV2 &runtime, const ModuleSP &objc_module_sp,
3036061da546Spatrick uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask,
3037061da546Spatrick uint64_t objc_debug_isa_magic_value,
3038061da546Spatrick uint64_t objc_debug_indexed_isa_magic_mask,
3039061da546Spatrick uint64_t objc_debug_indexed_isa_magic_value,
3040061da546Spatrick uint64_t objc_debug_indexed_isa_index_mask,
3041061da546Spatrick uint64_t objc_debug_indexed_isa_index_shift,
3042061da546Spatrick lldb::addr_t objc_indexed_classes)
3043061da546Spatrick : m_runtime(runtime), m_cache(), m_objc_module_wp(objc_module_sp),
3044061da546Spatrick m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
3045061da546Spatrick m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
3046061da546Spatrick m_objc_debug_isa_magic_value(objc_debug_isa_magic_value),
3047061da546Spatrick m_objc_debug_indexed_isa_magic_mask(objc_debug_indexed_isa_magic_mask),
3048061da546Spatrick m_objc_debug_indexed_isa_magic_value(objc_debug_indexed_isa_magic_value),
3049061da546Spatrick m_objc_debug_indexed_isa_index_mask(objc_debug_indexed_isa_index_mask),
3050061da546Spatrick m_objc_debug_indexed_isa_index_shift(objc_debug_indexed_isa_index_shift),
3051061da546Spatrick m_objc_indexed_classes(objc_indexed_classes), m_indexed_isa_cache() {}
3052061da546Spatrick
3053061da546Spatrick ObjCLanguageRuntime::ClassDescriptorSP
GetClassDescriptor(ObjCISA isa)3054061da546Spatrick AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) {
3055061da546Spatrick ObjCISA real_isa = 0;
3056061da546Spatrick if (!EvaluateNonPointerISA(isa, real_isa))
3057061da546Spatrick return ObjCLanguageRuntime::ClassDescriptorSP();
3058061da546Spatrick auto cache_iter = m_cache.find(real_isa);
3059061da546Spatrick if (cache_iter != m_cache.end())
3060061da546Spatrick return cache_iter->second;
3061061da546Spatrick auto descriptor_sp =
3062061da546Spatrick m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
3063061da546Spatrick if (descriptor_sp) // cache only positive matches since the table might grow
3064061da546Spatrick m_cache[real_isa] = descriptor_sp;
3065061da546Spatrick return descriptor_sp;
3066061da546Spatrick }
3067061da546Spatrick
EvaluateNonPointerISA(ObjCISA isa,ObjCISA & ret_isa)3068061da546Spatrick bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA(
3069061da546Spatrick ObjCISA isa, ObjCISA &ret_isa) {
3070*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Types);
3071061da546Spatrick
3072dda28197Spatrick LLDB_LOGF(log, "AOCRT::NPI Evaluate(isa = 0x%" PRIx64 ")", (uint64_t)isa);
3073061da546Spatrick
3074061da546Spatrick if ((isa & ~m_objc_debug_isa_class_mask) == 0)
3075061da546Spatrick return false;
3076061da546Spatrick
3077061da546Spatrick // If all of the indexed ISA variables are set, then its possible that this
3078061da546Spatrick // ISA is indexed, and we should first try to get its value using the index.
3079061da546Spatrick // Note, we check these variables first as the ObjC runtime will set at least
3080061da546Spatrick // one of their values to 0 if they aren't needed.
3081061da546Spatrick if (m_objc_debug_indexed_isa_magic_mask &&
3082061da546Spatrick m_objc_debug_indexed_isa_magic_value &&
3083061da546Spatrick m_objc_debug_indexed_isa_index_mask &&
3084061da546Spatrick m_objc_debug_indexed_isa_index_shift && m_objc_indexed_classes) {
3085061da546Spatrick if ((isa & ~m_objc_debug_indexed_isa_index_mask) == 0)
3086061da546Spatrick return false;
3087061da546Spatrick
3088061da546Spatrick if ((isa & m_objc_debug_indexed_isa_magic_mask) ==
3089061da546Spatrick m_objc_debug_indexed_isa_magic_value) {
3090061da546Spatrick // Magic bits are correct, so try extract the index.
3091061da546Spatrick uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >>
3092061da546Spatrick m_objc_debug_indexed_isa_index_shift;
3093061da546Spatrick // If the index is out of bounds of the length of the array then check if
3094061da546Spatrick // the array has been updated. If that is the case then we should try
3095061da546Spatrick // read the count again, and update the cache if the count has been
3096061da546Spatrick // updated.
3097061da546Spatrick if (index > m_indexed_isa_cache.size()) {
3098061da546Spatrick LLDB_LOGF(log,
3099061da546Spatrick "AOCRT::NPI (index = %" PRIu64
3100061da546Spatrick ") exceeds cache (size = %" PRIu64 ")",
3101061da546Spatrick (uint64_t)index, (uint64_t)m_indexed_isa_cache.size());
3102061da546Spatrick
3103061da546Spatrick Process *process(m_runtime.GetProcess());
3104061da546Spatrick
3105061da546Spatrick ModuleSP objc_module_sp(m_objc_module_wp.lock());
3106061da546Spatrick if (!objc_module_sp)
3107061da546Spatrick return false;
3108061da546Spatrick
3109061da546Spatrick Status error;
3110061da546Spatrick auto objc_indexed_classes_count = ExtractRuntimeGlobalSymbol(
3111061da546Spatrick process, ConstString("objc_indexed_classes_count"), objc_module_sp,
3112061da546Spatrick error);
3113061da546Spatrick if (error.Fail())
3114061da546Spatrick return false;
3115061da546Spatrick
3116061da546Spatrick LLDB_LOGF(log, "AOCRT::NPI (new class count = %" PRIu64 ")",
3117061da546Spatrick (uint64_t)objc_indexed_classes_count);
3118061da546Spatrick
3119061da546Spatrick if (objc_indexed_classes_count > m_indexed_isa_cache.size()) {
3120061da546Spatrick // Read the class entries we don't have. We should just read all of
3121061da546Spatrick // them instead of just the one we need as then we can cache those we
3122061da546Spatrick // may need later.
3123061da546Spatrick auto num_new_classes =
3124061da546Spatrick objc_indexed_classes_count - m_indexed_isa_cache.size();
3125061da546Spatrick const uint32_t addr_size = process->GetAddressByteSize();
3126061da546Spatrick DataBufferHeap buffer(num_new_classes * addr_size, 0);
3127061da546Spatrick
3128061da546Spatrick lldb::addr_t last_read_class =
3129061da546Spatrick m_objc_indexed_classes + (m_indexed_isa_cache.size() * addr_size);
3130061da546Spatrick size_t bytes_read = process->ReadMemory(
3131061da546Spatrick last_read_class, buffer.GetBytes(), buffer.GetByteSize(), error);
3132061da546Spatrick if (error.Fail() || bytes_read != buffer.GetByteSize())
3133061da546Spatrick return false;
3134061da546Spatrick
3135061da546Spatrick LLDB_LOGF(log, "AOCRT::NPI (read new classes count = %" PRIu64 ")",
3136061da546Spatrick (uint64_t)num_new_classes);
3137061da546Spatrick
3138061da546Spatrick // Append the new entries to the existing cache.
3139061da546Spatrick DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),
3140061da546Spatrick process->GetByteOrder(),
3141061da546Spatrick process->GetAddressByteSize());
3142061da546Spatrick
3143061da546Spatrick lldb::offset_t offset = 0;
3144061da546Spatrick for (unsigned i = 0; i != num_new_classes; ++i)
3145dda28197Spatrick m_indexed_isa_cache.push_back(data.GetAddress(&offset));
3146061da546Spatrick }
3147061da546Spatrick }
3148061da546Spatrick
3149061da546Spatrick // If the index is still out of range then this isn't a pointer.
3150061da546Spatrick if (index > m_indexed_isa_cache.size())
3151061da546Spatrick return false;
3152061da546Spatrick
3153dda28197Spatrick LLDB_LOGF(log, "AOCRT::NPI Evaluate(ret_isa = 0x%" PRIx64 ")",
3154061da546Spatrick (uint64_t)m_indexed_isa_cache[index]);
3155061da546Spatrick
3156061da546Spatrick ret_isa = m_indexed_isa_cache[index];
3157061da546Spatrick return (ret_isa != 0); // this is a pointer so 0 is not a valid value
3158061da546Spatrick }
3159061da546Spatrick
3160061da546Spatrick return false;
3161061da546Spatrick }
3162061da546Spatrick
3163061da546Spatrick // Definitely not an indexed ISA, so try to use a mask to extract the pointer
3164061da546Spatrick // from the ISA.
3165061da546Spatrick if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) {
3166061da546Spatrick ret_isa = isa & m_objc_debug_isa_class_mask;
3167061da546Spatrick return (ret_isa != 0); // this is a pointer so 0 is not a valid value
3168061da546Spatrick }
3169061da546Spatrick return false;
3170061da546Spatrick }
3171061da546Spatrick
GetEncodingToType()3172061da546Spatrick ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() {
3173061da546Spatrick if (!m_encoding_to_type_sp)
3174061da546Spatrick m_encoding_to_type_sp =
3175061da546Spatrick std::make_shared<AppleObjCTypeEncodingParser>(*this);
3176061da546Spatrick return m_encoding_to_type_sp;
3177061da546Spatrick }
3178061da546Spatrick
3179061da546Spatrick lldb_private::AppleObjCRuntime::ObjCISA
GetPointerISA(ObjCISA isa)3180061da546Spatrick AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) {
3181061da546Spatrick ObjCISA ret = isa;
3182061da546Spatrick
3183be691f3bSpatrick if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())
3184be691f3bSpatrick non_pointer_isa_cache->EvaluateNonPointerISA(isa, ret);
3185061da546Spatrick
3186061da546Spatrick return ret;
3187061da546Spatrick }
3188061da546Spatrick
GetCFBooleanValuesIfNeeded()3189061da546Spatrick bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() {
3190061da546Spatrick if (m_CFBoolean_values)
3191061da546Spatrick return true;
3192061da546Spatrick
3193*f6aab3d8Srobert static ConstString g_dunder_kCFBooleanFalse("__kCFBooleanFalse");
3194*f6aab3d8Srobert static ConstString g_dunder_kCFBooleanTrue("__kCFBooleanTrue");
3195*f6aab3d8Srobert static ConstString g_kCFBooleanFalse("kCFBooleanFalse");
3196*f6aab3d8Srobert static ConstString g_kCFBooleanTrue("kCFBooleanTrue");
3197061da546Spatrick
3198*f6aab3d8Srobert std::function<lldb::addr_t(ConstString, ConstString)> get_symbol =
3199*f6aab3d8Srobert [this](ConstString sym, ConstString real_sym) -> lldb::addr_t {
3200061da546Spatrick SymbolContextList sc_list;
3201061da546Spatrick GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(
3202061da546Spatrick sym, lldb::eSymbolTypeData, sc_list);
3203061da546Spatrick if (sc_list.GetSize() == 1) {
3204061da546Spatrick SymbolContext sc;
3205061da546Spatrick sc_list.GetContextAtIndex(0, sc);
3206061da546Spatrick if (sc.symbol)
3207061da546Spatrick return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());
3208061da546Spatrick }
3209*f6aab3d8Srobert GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(
3210*f6aab3d8Srobert real_sym, lldb::eSymbolTypeData, sc_list);
3211*f6aab3d8Srobert if (sc_list.GetSize() != 1)
3212061da546Spatrick return LLDB_INVALID_ADDRESS;
3213*f6aab3d8Srobert
3214*f6aab3d8Srobert SymbolContext sc;
3215*f6aab3d8Srobert sc_list.GetContextAtIndex(0, sc);
3216*f6aab3d8Srobert if (!sc.symbol)
3217*f6aab3d8Srobert return LLDB_INVALID_ADDRESS;
3218*f6aab3d8Srobert
3219*f6aab3d8Srobert lldb::addr_t addr = sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());
3220*f6aab3d8Srobert Status error;
3221*f6aab3d8Srobert addr = GetProcess()->ReadPointerFromMemory(addr, error);
3222*f6aab3d8Srobert if (error.Fail())
3223*f6aab3d8Srobert return LLDB_INVALID_ADDRESS;
3224*f6aab3d8Srobert return addr;
3225061da546Spatrick };
3226061da546Spatrick
3227*f6aab3d8Srobert lldb::addr_t false_addr = get_symbol(g_dunder_kCFBooleanFalse, g_kCFBooleanFalse);
3228*f6aab3d8Srobert lldb::addr_t true_addr = get_symbol(g_dunder_kCFBooleanTrue, g_kCFBooleanTrue);
3229061da546Spatrick
3230061da546Spatrick return (m_CFBoolean_values = {false_addr, true_addr}).operator bool();
3231061da546Spatrick }
3232061da546Spatrick
GetValuesForGlobalCFBooleans(lldb::addr_t & cf_true,lldb::addr_t & cf_false)3233061da546Spatrick void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
3234061da546Spatrick lldb::addr_t &cf_false) {
3235061da546Spatrick if (GetCFBooleanValuesIfNeeded()) {
3236061da546Spatrick cf_true = m_CFBoolean_values->second;
3237061da546Spatrick cf_false = m_CFBoolean_values->first;
3238061da546Spatrick } else
3239061da546Spatrick this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);
3240061da546Spatrick }
3241061da546Spatrick
3242061da546Spatrick #pragma mark Frame recognizers
3243061da546Spatrick
3244061da546Spatrick class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {
3245061da546Spatrick public:
ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp)3246061da546Spatrick ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) {
3247061da546Spatrick ThreadSP thread_sp = frame_sp->GetThread();
3248061da546Spatrick ProcessSP process_sp = thread_sp->GetProcess();
3249061da546Spatrick
3250061da546Spatrick const lldb::ABISP &abi = process_sp->GetABI();
3251be691f3bSpatrick if (!abi)
3252be691f3bSpatrick return;
3253061da546Spatrick
3254*f6aab3d8Srobert TypeSystemClangSP scratch_ts_sp =
3255be691f3bSpatrick ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());
3256*f6aab3d8Srobert if (!scratch_ts_sp)
3257061da546Spatrick return;
3258061da546Spatrick CompilerType voidstar =
3259*f6aab3d8Srobert scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
3260061da546Spatrick
3261061da546Spatrick ValueList args;
3262061da546Spatrick Value input_value;
3263061da546Spatrick input_value.SetCompilerType(voidstar);
3264061da546Spatrick args.PushValue(input_value);
3265061da546Spatrick
3266be691f3bSpatrick if (!abi->GetArgumentValues(*thread_sp, args))
3267be691f3bSpatrick return;
3268061da546Spatrick
3269061da546Spatrick addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong();
3270061da546Spatrick
3271061da546Spatrick Value value(exception_addr);
3272061da546Spatrick value.SetCompilerType(voidstar);
3273061da546Spatrick exception = ValueObjectConstResult::Create(frame_sp.get(), value,
3274061da546Spatrick ConstString("exception"));
3275061da546Spatrick exception = ValueObjectRecognizerSynthesizedValue::Create(
3276061da546Spatrick *exception, eValueTypeVariableArgument);
3277061da546Spatrick exception = exception->GetDynamicValue(eDynamicDontRunTarget);
3278061da546Spatrick
3279061da546Spatrick m_arguments = ValueObjectListSP(new ValueObjectList());
3280061da546Spatrick m_arguments->Append(exception);
3281dda28197Spatrick
3282dda28197Spatrick m_stop_desc = "hit Objective-C exception";
3283061da546Spatrick }
3284061da546Spatrick
3285061da546Spatrick ValueObjectSP exception;
3286061da546Spatrick
GetExceptionObject()3287061da546Spatrick lldb::ValueObjectSP GetExceptionObject() override { return exception; }
3288061da546Spatrick };
3289061da546Spatrick
3290061da546Spatrick class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {
3291061da546Spatrick lldb::RecognizedStackFrameSP
RecognizeFrame(lldb::StackFrameSP frame)3292061da546Spatrick RecognizeFrame(lldb::StackFrameSP frame) override {
3293061da546Spatrick return lldb::RecognizedStackFrameSP(
3294061da546Spatrick new ObjCExceptionRecognizedStackFrame(frame));
3295061da546Spatrick };
GetName()3296be691f3bSpatrick std::string GetName() override {
3297be691f3bSpatrick return "ObjC Exception Throw StackFrame Recognizer";
3298be691f3bSpatrick }
3299061da546Spatrick };
3300061da546Spatrick
RegisterObjCExceptionRecognizer(Process * process)3301be691f3bSpatrick static void RegisterObjCExceptionRecognizer(Process *process) {
3302061da546Spatrick FileSpec module;
3303061da546Spatrick ConstString function;
3304061da546Spatrick std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();
3305dda28197Spatrick std::vector<ConstString> symbols = {function};
3306be691f3bSpatrick
3307be691f3bSpatrick process->GetTarget().GetFrameRecognizerManager().AddRecognizer(
3308061da546Spatrick StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),
3309dda28197Spatrick module.GetFilename(), symbols,
3310dda28197Spatrick /*first_instruction_only*/ true);
3311061da546Spatrick }
3312