xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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