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