1 //===-- AppleObjCRuntimeV2.cpp ----------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
17 // Other libraries and framework includes
18 #include "clang/AST/ASTContext.h"
19 #include "clang/AST/DeclObjC.h"
22 #include "lldb/Core/ClangForward.h"
23 #include "lldb/Symbol/CompilerType.h"
24 #include "lldb/lldb-enumerations.h"
26 #include "lldb/Core/ClangForward.h"
27 #include "lldb/Core/ConstString.h"
28 #include "lldb/Core/Debugger.h"
29 #include "lldb/Core/Error.h"
30 #include "lldb/Core/Log.h"
31 #include "lldb/Core/Module.h"
32 #include "lldb/Core/PluginManager.h"
33 #include "lldb/Core/Scalar.h"
34 #include "lldb/Core/Section.h"
35 #include "lldb/Core/Stream.h"
36 #include "lldb/Core/StreamString.h"
37 #include "lldb/Core/Timer.h"
38 #include "lldb/Core/ValueObjectVariable.h"
39 #include "lldb/Expression/DiagnosticManager.h"
40 #include "lldb/Expression/FunctionCaller.h"
41 #include "lldb/Expression/UtilityFunction.h"
42 #include "lldb/Host/StringConvert.h"
43 #include "lldb/Interpreter/CommandObject.h"
44 #include "lldb/Interpreter/CommandObjectMultiword.h"
45 #include "lldb/Interpreter/CommandReturnObject.h"
46 #include "lldb/Interpreter/OptionValueBoolean.h"
47 #include "lldb/Symbol/ClangASTContext.h"
48 #include "lldb/Symbol/ObjectFile.h"
49 #include "lldb/Symbol/Symbol.h"
50 #include "lldb/Symbol/TypeList.h"
51 #include "lldb/Symbol/VariableList.h"
52 #include "lldb/Target/ExecutionContext.h"
53 #include "lldb/Target/Platform.h"
54 #include "lldb/Target/Process.h"
55 #include "lldb/Target/RegisterContext.h"
56 #include "lldb/Target/Target.h"
57 #include "lldb/Target/Thread.h"
59 #include "AppleObjCClassDescriptorV2.h"
60 #include "AppleObjCDeclVendor.h"
61 #include "AppleObjCRuntimeV2.h"
62 #include "AppleObjCTrampolineHandler.h"
63 #include "AppleObjCTypeEncodingParser.h"
66 using namespace lldb_private;
68 // 2 second timeout when running utility functions
69 static constexpr std::chrono::seconds g_utility_function_timeout(2);
71 static const char *g_get_dynamic_class_info_name =
72 "__lldb_apple_objc_v2_get_dynamic_class_info";
73 // Testing using the new C++11 raw string literals. If this breaks GCC then we
75 // need to revert to the code above...
76 static const char *g_get_dynamic_class_info_body = R"(
80 size_t strlen(const char *);
81 char *strncpy (char * s1, const char * s2, size_t n);
82 int printf(const char * format, ...);
84 #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
86 typedef struct _NXMapTable {
89 unsigned num_buckets_minus_one;
93 #define NX_MAPNOTAKEY ((void *)(-1))
95 typedef struct BucketInfo
105 } __attribute__((__packed__));
108 __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
109 void *class_infos_ptr,
110 uint32_t class_infos_byte_size,
113 DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
114 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
115 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
116 const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
119 const unsigned num_classes = grc->num_classes;
122 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
123 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
124 BucketInfo *buckets = (BucketInfo *)grc->buckets;
127 for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i)
129 if (buckets[i].name_ptr != NX_MAPNOTAKEY)
131 if (idx < max_class_infos)
133 const char *s = buckets[i].name_ptr;
135 for (unsigned char c = *s; c; c = *++s)
136 h = ((h << 5) + h) + c;
137 class_infos[idx].hash = h;
138 class_infos[idx].isa = buckets[i].isa;
143 if (idx < max_class_infos)
145 class_infos[idx].isa = NULL;
146 class_infos[idx].hash = 0;
156 static const char *g_get_shared_cache_class_info_name =
157 "__lldb_apple_objc_v2_get_shared_cache_class_info";
158 // Testing using the new C++11 raw string literals. If this breaks GCC then we
160 // need to revert to the code above...
161 static const char *g_get_shared_cache_class_info_body = R"(
165 const char *class_getName(void *objc_class);
166 size_t strlen(const char *);
167 char *strncpy (char * s1, const char * s2, size_t n);
168 int printf(const char * format, ...);
171 #define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
174 struct objc_classheader_t {
179 struct objc_clsopt_t {
187 uint32_t scramble[256];
188 uint8_t tab[0]; // tab[mask+1]
189 // uint8_t checkbytes[capacity];
190 // int32_t offset[capacity];
191 // objc_classheader_t clsOffsets[capacity];
192 // uint32_t duplicateCount;
193 // objc_classheader_t duplicateOffsets[duplicateCount];
198 int32_t selopt_offset;
199 int32_t headeropt_offset;
200 int32_t clsopt_offset;
203 struct objc_opt_v14_t {
206 int32_t selopt_offset;
207 int32_t headeropt_offset;
208 int32_t clsopt_offset;
215 } __attribute__((__packed__));
218 __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
219 void *class_infos_ptr,
220 uint32_t class_infos_byte_size,
224 DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
225 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
226 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
229 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
230 const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;
231 const bool is_v14_format = objc_opt->version >= 14;
234 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);
235 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);
236 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);
237 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);
238 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);
242 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
243 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
244 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
245 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
247 if (objc_opt->version == 12 || objc_opt->version == 13 || objc_opt->version == 14 || objc_opt->version == 15)
249 const objc_clsopt_t* clsopt = NULL;
251 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);
253 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
254 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
255 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
256 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
257 int32_t invalidEntryOffset = 0;
258 // this is safe to do because the version field order is invariant
259 if (objc_opt->version == 12)
260 invalidEntryOffset = 16;
261 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
262 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
263 const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
264 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
265 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
266 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
267 DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);
268 for (uint32_t i=0; i<clsopt->capacity; ++i)
270 const int32_t clsOffset = classOffsets[i].clsOffset;
271 DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);
274 DEBUG_PRINTF("clsOffset & 1\n");
275 continue; // duplicate
277 else if (clsOffset == invalidEntryOffset)
279 DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");
280 continue; // invalid offset
283 if (class_infos && idx < max_class_infos)
285 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
286 const char *name = class_getName (class_infos[idx].isa);
287 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
288 // Hash the class name so we don't have to read it
289 const char *s = name;
291 for (unsigned char c = *s; c; c = *++s)
292 h = ((h << 5) + h) + c;
293 class_infos[idx].hash = h;
297 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
302 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
303 const uint32_t duplicate_count = *duplicate_count_ptr;
304 const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
305 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
306 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
307 for (uint32_t i=0; i<duplicate_count; ++i)
309 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
311 continue; // duplicate
312 else if (clsOffset == invalidEntryOffset)
313 continue; // invalid offset
315 if (class_infos && idx < max_class_infos)
317 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
318 const char *name = class_getName (class_infos[idx].isa);
319 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
320 // Hash the class name so we don't have to read it
321 const char *s = name;
323 for (unsigned char c = *s; c; c = *++s)
324 h = ((h << 5) + h) + c;
325 class_infos[idx].hash = h;
330 DEBUG_PRINTF ("%u class_infos\n", idx);
331 DEBUG_PRINTF ("done\n");
340 ExtractRuntimeGlobalSymbol(Process *process, ConstString name,
341 const ModuleSP &module_sp, Error &error,
342 bool read_value = true, uint8_t byte_size = 0,
343 uint64_t default_value = LLDB_INVALID_ADDRESS,
344 SymbolType sym_type = lldb::eSymbolTypeData) {
346 error.SetErrorString("no process");
347 return default_value;
350 error.SetErrorString("no module");
351 return default_value;
354 byte_size = process->GetAddressByteSize();
355 const Symbol *symbol =
356 module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
357 if (symbol && symbol->ValueIsAddress()) {
358 lldb::addr_t symbol_load_addr =
359 symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
360 if (symbol_load_addr != LLDB_INVALID_ADDRESS) {
362 return process->ReadUnsignedIntegerFromMemory(
363 symbol_load_addr, byte_size, default_value, error);
365 return symbol_load_addr;
367 error.SetErrorString("symbol address invalid");
368 return default_value;
371 error.SetErrorString("no symbol");
372 return default_value;
376 AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,
377 const ModuleSP &objc_module_sp)
378 : AppleObjCRuntime(process), m_get_class_info_code(),
379 m_get_class_info_args(LLDB_INVALID_ADDRESS),
380 m_get_class_info_args_mutex(), m_get_shared_cache_class_info_code(),
381 m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS),
382 m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_ap(),
383 m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), m_hash_signature(),
384 m_has_object_getClass(false), m_loaded_objc_opt(false),
385 m_non_pointer_isa_cache_ap(
386 NonPointerISACache::CreateInstance(*this, objc_module_sp)),
387 m_tagged_pointer_vendor_ap(
388 TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),
389 m_encoding_to_type_sp(), m_noclasses_warning_emitted(false),
390 m_CFBoolean_values() {
391 static const ConstString g_gdb_object_getClass("gdb_object_getClass");
392 m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(
393 g_gdb_object_getClass, eSymbolTypeCode) != NULL);
396 bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(
397 ValueObject &in_value, DynamicValueType use_dynamic,
398 TypeAndOrName &class_type_or_name, Address &address,
399 Value::ValueType &value_type) {
400 // We should never get here with a null process...
401 assert(m_process != NULL);
403 // The Runtime is attached to a particular process, you shouldn't pass in a
404 // value from another process.
405 // Note, however, the process might be NULL (e.g. if the value was made with
406 // SBTarget::EvaluateExpression...)
407 // in which case it is sufficient if the target's match:
409 Process *process = in_value.GetProcessSP().get();
411 assert(process == m_process);
413 assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get());
415 class_type_or_name.Clear();
416 value_type = Value::ValueType::eValueTypeScalar;
418 // Make sure we can have a dynamic value before starting...
419 if (CouldHaveDynamicValue(in_value)) {
420 // First job, pull out the address at 0 offset from the object That will be
422 ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value));
424 const addr_t object_ptr = in_value.GetPointerValue();
425 address.SetRawAddress(object_ptr);
427 ConstString class_name(objc_class_sp->GetClassName());
428 class_type_or_name.SetName(class_name);
429 TypeSP type_sp(objc_class_sp->GetType());
431 class_type_or_name.SetTypeSP(type_sp);
433 type_sp = LookupInCompleteClassCache(class_name);
435 objc_class_sp->SetType(type_sp);
436 class_type_or_name.SetTypeSP(type_sp);
438 // try to go for a CompilerType at least
439 DeclVendor *vendor = GetDeclVendor();
441 std::vector<clang::NamedDecl *> decls;
442 if (vendor->FindDecls(class_name, false, 1, decls) && decls.size())
443 class_type_or_name.SetCompilerType(
444 ClangASTContext::GetTypeForDecl(decls[0]));
450 return class_type_or_name.IsEmpty() == false;
453 //------------------------------------------------------------------
455 //------------------------------------------------------------------
456 LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process,
457 LanguageType language) {
458 // FIXME: This should be a MacOS or iOS process, and we need to look for the
459 // OBJC section to make
460 // sure we aren't using the V1 runtime.
461 if (language == eLanguageTypeObjC) {
462 ModuleSP objc_module_sp;
464 if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
465 ObjCRuntimeVersions::eAppleObjC_V2)
466 return new AppleObjCRuntimeV2(process, objc_module_sp);
473 static OptionDefinition g_objc_classtable_dump_options[] = {
474 {LLDB_OPT_SET_ALL, false, "verbose", 'v', OptionParser::eNoArgument,
475 nullptr, nullptr, 0, eArgTypeNone,
476 "Print ivar and method information in detail"}};
478 class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {
480 class CommandOptions : public Options {
482 CommandOptions() : Options(), m_verbose(false, false) {}
484 ~CommandOptions() override = default;
486 Error SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
487 ExecutionContext *execution_context) override {
489 const int short_option = m_getopt_table[option_idx].val;
490 switch (short_option) {
492 m_verbose.SetCurrentValue(true);
493 m_verbose.SetOptionWasSet();
497 error.SetErrorStringWithFormat("unrecognized short option '%c'",
505 void OptionParsingStarting(ExecutionContext *execution_context) override {
509 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
510 return llvm::makeArrayRef(g_objc_classtable_dump_options);
513 OptionValueBoolean m_verbose;
516 CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter)
517 : CommandObjectParsed(
518 interpreter, "dump", "Dump information on Objective-C classes "
519 "known to the current process.",
520 "language objc class-table dump",
521 eCommandRequiresProcess | eCommandProcessMustBeLaunched |
522 eCommandProcessMustBePaused),
524 CommandArgumentEntry arg;
525 CommandArgumentData index_arg;
527 // Define the first (and only) variant of this arg.
528 index_arg.arg_type = eArgTypeRegularExpression;
529 index_arg.arg_repetition = eArgRepeatOptional;
531 // There is only one variant this argument could be; put it into the
533 arg.push_back(index_arg);
535 // Push the data for the first argument into the m_arguments vector.
536 m_arguments.push_back(arg);
539 ~CommandObjectObjC_ClassTable_Dump() override = default;
541 Options *GetOptions() override { return &m_options; }
544 bool DoExecute(Args &command, CommandReturnObject &result) override {
545 std::unique_ptr<RegularExpression> regex_up;
546 switch (command.GetArgumentCount()) {
550 regex_up.reset(new RegularExpression());
551 if (!regex_up->Compile(llvm::StringRef::withNullAsEmpty(
552 command.GetArgumentAtIndex(0)))) {
554 "invalid argument - please provide a valid regular expression");
555 result.SetStatus(lldb::eReturnStatusFailed);
561 result.AppendError("please provide 0 or 1 arguments");
562 result.SetStatus(lldb::eReturnStatusFailed);
567 Process *process = m_exe_ctx.GetProcessPtr();
568 ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
570 auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();
571 auto iterator = iterators_pair.first;
572 auto &std_out = result.GetOutputStream();
573 for (; iterator != iterators_pair.second; iterator++) {
574 if (iterator->second) {
575 const char *class_name =
576 iterator->second->GetClassName().AsCString("<unknown>");
577 if (regex_up && class_name &&
578 !regex_up->Execute(llvm::StringRef(class_name)))
580 std_out.Printf("isa = 0x%" PRIx64, iterator->first);
581 std_out.Printf(" name = %s", class_name);
582 std_out.Printf(" instance size = %" PRIu64,
583 iterator->second->GetInstanceSize());
584 std_out.Printf(" num ivars = %" PRIuPTR,
585 (uintptr_t)iterator->second->GetNumIVars());
586 if (auto superclass = iterator->second->GetSuperclass()) {
587 std_out.Printf(" superclass = %s",
588 superclass->GetClassName().AsCString("<unknown>"));
590 std_out.Printf("\n");
591 if (m_options.m_verbose) {
592 for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) {
593 auto ivar = iterator->second->GetIVarAtIndex(i);
595 " ivar name = %s type = %s size = %" PRIu64
596 " offset = %" PRId32 "\n",
597 ivar.m_name.AsCString("<unknown>"),
598 ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),
599 ivar.m_size, ivar.m_offset);
601 iterator->second->Describe(
603 [objc_runtime, &std_out](const char *name,
604 const char *type) -> bool {
605 std_out.Printf(" instance method name = %s type = %s\n",
609 [objc_runtime, &std_out](const char *name,
610 const char *type) -> bool {
611 std_out.Printf(" class method name = %s type = %s\n", name,
618 if (regex_up && !regex_up->Execute(llvm::StringRef()))
620 std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n",
624 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
627 result.AppendError("current process has no Objective-C runtime loaded");
628 result.SetStatus(lldb::eReturnStatusFailed);
633 CommandOptions m_options;
636 class CommandObjectMultiwordObjC_TaggedPointer_Info
637 : public CommandObjectParsed {
639 CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter)
640 : CommandObjectParsed(
641 interpreter, "info", "Dump information on a tagged pointer.",
642 "language objc tagged-pointer info",
643 eCommandRequiresProcess | eCommandProcessMustBeLaunched |
644 eCommandProcessMustBePaused) {
645 CommandArgumentEntry arg;
646 CommandArgumentData index_arg;
648 // Define the first (and only) variant of this arg.
649 index_arg.arg_type = eArgTypeAddress;
650 index_arg.arg_repetition = eArgRepeatPlus;
652 // There is only one variant this argument could be; put it into the
654 arg.push_back(index_arg);
656 // Push the data for the first argument into the m_arguments vector.
657 m_arguments.push_back(arg);
660 ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;
663 bool DoExecute(Args &command, CommandReturnObject &result) override {
664 if (command.GetArgumentCount() == 0) {
665 result.AppendError("this command requires arguments");
666 result.SetStatus(lldb::eReturnStatusFailed);
670 Process *process = m_exe_ctx.GetProcessPtr();
671 ExecutionContext exe_ctx(process);
672 ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
674 ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor =
675 objc_runtime->GetTaggedPointerVendor();
676 if (tagged_ptr_vendor) {
677 for (size_t i = 0; i < command.GetArgumentCount(); i++) {
678 const char *arg_str = command.GetArgumentAtIndex(i);
682 lldb::addr_t arg_addr = Args::StringToAddress(
683 &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);
684 if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail())
686 auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);
689 uint64_t info_bits = 0;
690 uint64_t value_bits = 0;
691 uint64_t payload = 0;
692 if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits,
694 result.GetOutputStream().Printf(
695 "0x%" PRIx64 " is tagged.\n\tpayload = 0x%" PRIx64
696 "\n\tvalue = 0x%" PRIx64 "\n\tinfo bits = 0x%" PRIx64
698 (uint64_t)arg_addr, payload, value_bits, info_bits,
699 descriptor_sp->GetClassName().AsCString("<unknown>"));
701 result.GetOutputStream().Printf("0x%" PRIx64 " is not tagged.\n",
706 result.AppendError("current process has no tagged pointer support");
707 result.SetStatus(lldb::eReturnStatusFailed);
710 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
713 result.AppendError("current process has no Objective-C runtime loaded");
714 result.SetStatus(lldb::eReturnStatusFailed);
720 class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword {
722 CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)
723 : CommandObjectMultiword(
724 interpreter, "class-table",
725 "Commands for operating on the Objective-C class table.",
726 "class-table <subcommand> [<subcommand-options>]") {
729 CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter)));
732 ~CommandObjectMultiwordObjC_ClassTable() override = default;
735 class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword {
737 CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)
738 : CommandObjectMultiword(
739 interpreter, "tagged-pointer",
740 "Commands for operating on Objective-C tagged pointers.",
741 "class-table <subcommand> [<subcommand-options>]") {
745 new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter)));
748 ~CommandObjectMultiwordObjC_TaggedPointer() override = default;
751 class CommandObjectMultiwordObjC : public CommandObjectMultiword {
753 CommandObjectMultiwordObjC(CommandInterpreter &interpreter)
754 : CommandObjectMultiword(
756 "Commands for operating on the Objective-C language runtime.",
757 "objc <subcommand> [<subcommand-options>]") {
758 LoadSubCommand("class-table",
760 new CommandObjectMultiwordObjC_ClassTable(interpreter)));
761 LoadSubCommand("tagged-pointer",
762 CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer(
766 ~CommandObjectMultiwordObjC() override = default;
769 void AppleObjCRuntimeV2::Initialize() {
770 PluginManager::RegisterPlugin(
771 GetPluginNameStatic(), "Apple Objective C Language Runtime - Version 2",
773 [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {
774 return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));
778 void AppleObjCRuntimeV2::Terminate() {
779 PluginManager::UnregisterPlugin(CreateInstance);
782 lldb_private::ConstString AppleObjCRuntimeV2::GetPluginNameStatic() {
783 static ConstString g_name("apple-objc-v2");
787 //------------------------------------------------------------------
788 // PluginInterface protocol
789 //------------------------------------------------------------------
790 lldb_private::ConstString AppleObjCRuntimeV2::GetPluginName() {
791 return GetPluginNameStatic();
794 uint32_t AppleObjCRuntimeV2::GetPluginVersion() { return 1; }
797 AppleObjCRuntimeV2::CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp,
799 BreakpointResolverSP resolver_sp;
802 resolver_sp.reset(new BreakpointResolverName(
803 bkpt, "objc_exception_throw", eFunctionNameTypeBase,
804 eLanguageTypeUnknown, Breakpoint::Exact, 0, eLazyBoolNo));
805 // FIXME: We don't do catch breakpoints for ObjC yet.
806 // Should there be some way for the runtime to specify what it can do in this
811 UtilityFunction *AppleObjCRuntimeV2::CreateObjectChecker(const char *name) {
812 char check_function_code[2048];
815 if (m_has_object_getClass) {
816 len = ::snprintf(check_function_code, sizeof(check_function_code),
817 "extern \"C\" void *gdb_object_getClass(void *); "
819 "extern \"C\" int printf(const char *format, ...); "
823 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) "
827 " if ($__lldb_arg_obj == (void *)0) "
829 " return; // nil is ok "
831 " if (!gdb_object_getClass($__lldb_arg_obj)) "
833 " *((volatile int *)0) = 'ocgc'; "
835 " else if ($__lldb_arg_selector != (void *)0) "
839 " signed char responds = (signed char) [(id) "
842 "respondsToSelector: \n"
844 "objc_selector *) $__lldb_arg_selector]; \n"
845 " if (responds == (signed char) 0) "
847 " *((volatile int *)0) = 'ocgc'; "
855 len = ::snprintf(check_function_code, sizeof(check_function_code),
856 "extern \"C\" void *gdb_class_getClass(void *); "
858 "extern \"C\" int printf(const char *format, ...); "
862 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) "
866 " if ($__lldb_arg_obj == (void *)0) "
868 " return; // nil is ok "
870 " void **$isa_ptr = (void **)$__lldb_arg_obj; "
872 " if (*$isa_ptr == (void *)0 || "
873 "!gdb_class_getClass(*$isa_ptr)) \n"
874 " *((volatile int *)0) = 'ocgc'; "
876 " else if ($__lldb_arg_selector != (void *)0) "
880 " signed char responds = (signed char) [(id) "
883 "respondsToSelector: \n"
885 "objc_selector *) $__lldb_arg_selector]; \n"
886 " if (responds == (signed char) 0) "
888 " *((volatile int *)0) = 'ocgc'; "
897 assert(len < (int)sizeof(check_function_code));
900 return GetTargetRef().GetUtilityFunctionForLanguage(
901 check_function_code, eLanguageTypeObjC, name, error);
904 size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,
905 const char *ivar_name) {
906 uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;
908 const char *class_name = parent_ast_type.GetConstTypeName().AsCString();
909 if (class_name && class_name[0] && ivar_name && ivar_name[0]) {
910 //----------------------------------------------------------------------
911 // Make the objective C V2 mangled name for the ivar offset from the
912 // class name and ivar name
913 //----------------------------------------------------------------------
914 std::string buffer("OBJC_IVAR_$_");
915 buffer.append(class_name);
916 buffer.push_back('.');
917 buffer.append(ivar_name);
918 ConstString ivar_const_str(buffer.c_str());
920 //----------------------------------------------------------------------
921 // Try to get the ivar offset address from the symbol table first using
922 // the name we created above
923 //----------------------------------------------------------------------
924 SymbolContextList sc_list;
925 Target &target = m_process->GetTarget();
926 target.GetImages().FindSymbolsWithNameAndType(ivar_const_str,
927 eSymbolTypeObjCIVar, sc_list);
929 addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
932 SymbolContext ivar_offset_symbol;
933 if (sc_list.GetSize() == 1 &&
934 sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {
935 if (ivar_offset_symbol.symbol)
936 ivar_offset_address =
937 ivar_offset_symbol.symbol->GetLoadAddress(&target);
940 //----------------------------------------------------------------------
941 // If we didn't get the ivar offset address from the symbol table, fall
942 // back to getting it from the runtime
943 //----------------------------------------------------------------------
944 if (ivar_offset_address == LLDB_INVALID_ADDRESS)
945 ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);
947 if (ivar_offset_address != LLDB_INVALID_ADDRESS)
948 ivar_offset = m_process->ReadUnsignedIntegerFromMemory(
949 ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error);
954 // tagged pointers are special not-a-real-pointer values that contain both type
955 // and value information
956 // this routine attempts to check with as little computational effort as
957 // possible whether something
958 // could possibly be a tagged pointer - false positives are possible but false
959 // negatives shouldn't
960 bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) {
961 if (!m_tagged_pointer_vendor_ap)
963 return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr);
966 class RemoteNXMapTable {
969 : m_count(0), m_num_buckets_minus_one(0),
970 m_buckets_ptr(LLDB_INVALID_ADDRESS), m_process(NULL),
971 m_end_iterator(*this, -1), m_load_addr(LLDB_INVALID_ADDRESS),
972 m_map_pair_size(0), m_invalid_key(0) {}
975 printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);
976 printf("RemoteNXMapTable.m_count = %u\n", m_count);
977 printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n",
978 m_num_buckets_minus_one);
979 printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);
982 bool ParseHeader(Process *process, lldb::addr_t load_addr) {
984 m_load_addr = load_addr;
985 m_map_pair_size = m_process->GetAddressByteSize() * 2;
987 m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
990 // This currently holds true for all platforms we support, but we might
991 // need to change this to use get the actually byte size of "unsigned"
992 // from the target AST...
993 const uint32_t unsigned_byte_size = sizeof(uint32_t);
994 // Skip the prototype as we don't need it (const struct +NXMapTablePrototype
998 if (load_addr == LLDB_INVALID_ADDRESS)
1001 lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();
1004 m_count = m_process->ReadUnsignedIntegerFromMemory(
1005 cursor, unsigned_byte_size, 0, err);
1007 cursor += unsigned_byte_size;
1009 // unsigned nbBucketsMinusOne;
1010 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(
1011 cursor, unsigned_byte_size, 0, err);
1012 cursor += unsigned_byte_size;
1015 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);
1017 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;
1023 m_num_buckets_minus_one = 0;
1024 m_buckets_ptr = LLDB_INVALID_ADDRESS;
1029 // const_iterator mimics NXMapState and its code comes from NXInitMapState and
1031 typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;
1033 friend class const_iterator;
1034 class const_iterator {
1036 const_iterator(RemoteNXMapTable &parent, int index)
1037 : m_parent(parent), m_index(index) {
1038 AdvanceToValidIndex();
1041 const_iterator(const const_iterator &rhs)
1042 : m_parent(rhs.m_parent), m_index(rhs.m_index) {
1043 // AdvanceToValidIndex() has been called by rhs already.
1046 const_iterator &operator=(const const_iterator &rhs) {
1047 // AdvanceToValidIndex() has been called by rhs already.
1048 assert(&m_parent == &rhs.m_parent);
1049 m_index = rhs.m_index;
1053 bool operator==(const const_iterator &rhs) const {
1054 if (&m_parent != &rhs.m_parent)
1056 if (m_index != rhs.m_index)
1062 bool operator!=(const const_iterator &rhs) const {
1063 return !(operator==(rhs));
1066 const_iterator &operator++() {
1067 AdvanceToValidIndex();
1071 const element operator*() const {
1072 if (m_index == -1) {
1073 // TODO find a way to make this an error, but not an assert
1077 lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1078 size_t map_pair_size = m_parent.m_map_pair_size;
1079 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1084 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1087 lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(
1088 pair_ptr + m_parent.m_process->GetAddressByteSize(), err);
1092 std::string key_string;
1094 m_parent.m_process->ReadCStringFromMemory(key, key_string, err);
1098 return element(ConstString(key_string.c_str()),
1099 (ObjCLanguageRuntime::ObjCISA)value);
1103 void AdvanceToValidIndex() {
1107 const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1108 const size_t map_pair_size = m_parent.m_map_pair_size;
1109 const lldb::addr_t invalid_key = m_parent.m_invalid_key;
1113 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1115 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1117 if (!err.Success()) {
1122 if (key != invalid_key)
1126 RemoteNXMapTable &m_parent;
1130 const_iterator begin() {
1131 return const_iterator(*this, m_num_buckets_minus_one + 1);
1134 const_iterator end() { return m_end_iterator; }
1136 uint32_t GetCount() const { return m_count; }
1138 uint32_t GetBucketCount() const { return m_num_buckets_minus_one; }
1140 lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; }
1142 lldb::addr_t GetTableLoadAddress() const { return m_load_addr; }
1145 // contents of _NXMapTable struct
1147 uint32_t m_num_buckets_minus_one;
1148 lldb::addr_t m_buckets_ptr;
1149 lldb_private::Process *m_process;
1150 const_iterator m_end_iterator;
1151 lldb::addr_t m_load_addr;
1152 size_t m_map_pair_size;
1153 lldb::addr_t m_invalid_key;
1156 AppleObjCRuntimeV2::HashTableSignature::HashTableSignature()
1157 : m_count(0), m_num_buckets(0), m_buckets_ptr(0) {}
1159 void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature(
1160 const RemoteNXMapTable &hash_table) {
1161 m_count = hash_table.GetCount();
1162 m_num_buckets = hash_table.GetBucketCount();
1163 m_buckets_ptr = hash_table.GetBucketDataPointer();
1166 bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate(
1167 Process *process, AppleObjCRuntimeV2 *runtime,
1168 RemoteNXMapTable &hash_table) {
1169 if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) {
1170 return false; // Failed to parse the header, no need to update anything
1173 // Check with out current signature and return true if the count,
1174 // number of buckets or the hash table address changes.
1175 if (m_count == hash_table.GetCount() &&
1176 m_num_buckets == hash_table.GetBucketCount() &&
1177 m_buckets_ptr == hash_table.GetBucketDataPointer()) {
1178 // Hash table hasn't changed
1181 // Hash table data has changed, we need to update
1185 ObjCLanguageRuntime::ClassDescriptorSP
1186 AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {
1187 ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
1188 if (m_non_pointer_isa_cache_ap.get())
1189 class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa);
1190 if (!class_descriptor_sp)
1191 class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
1192 return class_descriptor_sp;
1195 ObjCLanguageRuntime::ClassDescriptorSP
1196 AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {
1197 ClassDescriptorSP objc_class_sp;
1198 if (valobj.IsBaseClass()) {
1199 ValueObject *parent = valobj.GetParent();
1200 // if I am my own parent, bail out of here fast..
1201 if (parent && parent != &valobj) {
1202 ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
1203 if (parent_descriptor_sp)
1204 return parent_descriptor_sp->GetSuperclass();
1208 // if we get an invalid VO (which might still happen when playing around
1209 // with pointers returned by the expression parser, don't consider this
1210 // a valid ObjC object)
1211 if (valobj.GetCompilerType().IsValid()) {
1212 addr_t isa_pointer = valobj.GetPointerValue();
1215 if (IsTaggedPointer(isa_pointer)) {
1216 return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer);
1218 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1220 Process *process = exe_ctx.GetProcessPtr();
1223 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
1224 if (isa != LLDB_INVALID_ADDRESS) {
1225 objc_class_sp = GetClassDescriptorFromISA(isa);
1226 if (isa && !objc_class_sp) {
1227 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1229 log->Printf("0x%" PRIx64
1230 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was "
1231 "not in class descriptor cache 0x%" PRIx64,
1238 return objc_class_sp;
1241 lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {
1242 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
1243 Process *process = GetProcess();
1245 ModuleSP objc_module_sp(GetObjCModule());
1247 if (!objc_module_sp)
1248 return LLDB_INVALID_ADDRESS;
1250 static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");
1252 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
1253 g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);
1255 lldb::addr_t gdb_objc_realized_classes_ptr =
1256 symbol->GetLoadAddress(&process->GetTarget());
1258 if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {
1260 m_isa_hash_table_ptr = process->ReadPointerFromMemory(
1261 gdb_objc_realized_classes_ptr, error);
1265 return m_isa_hash_table_ptr;
1268 AppleObjCRuntimeV2::DescriptorMapUpdateResult
1269 AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(
1270 RemoteNXMapTable &hash_table) {
1271 Process *process = GetProcess();
1273 if (process == NULL)
1274 return DescriptorMapUpdateResult::Fail();
1276 uint32_t num_class_infos = 0;
1278 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1280 ExecutionContext exe_ctx;
1282 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1285 return DescriptorMapUpdateResult::Fail();
1287 thread_sp->CalculateExecutionContext(exe_ctx);
1288 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1291 return DescriptorMapUpdateResult::Fail();
1293 Address function_address;
1295 DiagnosticManager diagnostics;
1297 const uint32_t addr_size = process->GetAddressByteSize();
1301 // Read the total number of classes from the hash table
1302 const uint32_t num_classes = hash_table.GetCount();
1303 if (num_classes == 0) {
1305 log->Printf("No dynamic classes found in gdb_objc_realized_classes.");
1306 return DescriptorMapUpdateResult::Success(0);
1309 // Make some types for our arguments
1310 CompilerType clang_uint32_t_type =
1311 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1312 CompilerType clang_void_pointer_type =
1313 ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1315 ValueList arguments;
1316 FunctionCaller *get_class_info_function = nullptr;
1318 if (!m_get_class_info_code.get()) {
1320 m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage(
1321 g_get_dynamic_class_info_body, eLanguageTypeObjC,
1322 g_get_dynamic_class_info_name, error));
1326 "Failed to get Utility Function for implementation lookup: %s",
1328 m_get_class_info_code.reset();
1330 diagnostics.Clear();
1332 if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) {
1334 log->Printf("Failed to install implementation lookup");
1335 diagnostics.Dump(log);
1337 m_get_class_info_code.reset();
1340 if (!m_get_class_info_code.get())
1341 return DescriptorMapUpdateResult::Fail();
1343 // Next make the runner function for our implementation utility function.
1345 value.SetValueType(Value::eValueTypeScalar);
1346 value.SetCompilerType(clang_void_pointer_type);
1347 arguments.PushValue(value);
1348 arguments.PushValue(value);
1350 value.SetValueType(Value::eValueTypeScalar);
1351 value.SetCompilerType(clang_uint32_t_type);
1352 arguments.PushValue(value);
1353 arguments.PushValue(value);
1355 get_class_info_function = m_get_class_info_code->MakeFunctionCaller(
1356 clang_uint32_t_type, arguments, thread_sp, error);
1361 "Failed to make function caller for implementation lookup: %s.",
1363 return DescriptorMapUpdateResult::Fail();
1366 get_class_info_function = m_get_class_info_code->GetFunctionCaller();
1367 if (!get_class_info_function) {
1369 log->Printf("Failed to get implementation lookup function caller.");
1370 diagnostics.Dump(log);
1373 return DescriptorMapUpdateResult::Fail();
1375 arguments = get_class_info_function->GetArgumentValues();
1378 diagnostics.Clear();
1380 const uint32_t class_info_byte_size = addr_size + 4;
1381 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1382 lldb::addr_t class_infos_addr = process->AllocateMemory(
1383 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
1385 if (class_infos_addr == LLDB_INVALID_ADDRESS) {
1387 log->Printf("unable to allocate %" PRIu32
1388 " bytes in process for shared cache read",
1389 class_infos_byte_size);
1390 return DescriptorMapUpdateResult::Fail();
1393 std::lock_guard<std::mutex> guard(m_get_class_info_args_mutex);
1395 // Fill in our function argument values
1396 arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
1397 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1398 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1399 arguments.GetValueAtIndex(3)->GetScalar() =
1400 (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
1402 bool success = false;
1404 diagnostics.Clear();
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);
1417 return_value.SetValueType(Value::eValueTypeScalar);
1418 // return_value.SetContext (Value::eContextTypeClangType,
1419 // clang_uint32_t_type);
1420 return_value.SetCompilerType(clang_uint32_t_type);
1421 return_value.GetScalar() = 0;
1423 diagnostics.Clear();
1426 ExpressionResults results = get_class_info_function->ExecuteFunction(
1427 exe_ctx, &m_get_class_info_args, options, diagnostics, return_value);
1429 if (results == eExpressionCompleted) {
1430 // The result is the number of ClassInfo structures that were filled in
1431 num_class_infos = return_value.GetScalar().ULong();
1433 log->Printf("Discovered %u ObjC classes\n", num_class_infos);
1434 if (num_class_infos > 0) {
1435 // Read the ClassInfo structures
1436 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);
1437 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),
1438 buffer.GetByteSize(),
1439 err) == buffer.GetByteSize()) {
1440 DataExtractor class_infos_data(buffer.GetBytes(),
1441 buffer.GetByteSize(),
1442 process->GetByteOrder(), addr_size);
1443 ParseClassInfoArray(class_infos_data, num_class_infos);
1449 log->Printf("Error evaluating our find class name function.");
1450 diagnostics.Dump(log);
1455 log->Printf("Error writing function arguments.");
1456 diagnostics.Dump(log);
1460 // Deallocate the memory we allocated for the ClassInfo array
1461 process->DeallocateMemory(class_infos_addr);
1463 return DescriptorMapUpdateResult(success, num_class_infos);
1466 uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,
1467 uint32_t num_class_infos) {
1468 // Parses an array of "num_class_infos" packed ClassInfo structures:
1474 // } __attribute__((__packed__));
1476 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1478 uint32_t num_parsed = 0;
1480 // Iterate through all ClassInfo structures
1481 lldb::offset_t offset = 0;
1482 for (uint32_t i = 0; i < num_class_infos; ++i) {
1483 ObjCISA isa = data.GetPointer(&offset);
1488 "AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
1491 // Check if we already know about this ISA, if we do, the info will
1492 // never change, so we can just skip it.
1493 if (ISAIsCached(isa)) {
1495 log->Printf("AppleObjCRuntimeV2 found cached isa=0x%" PRIx64
1496 ", ignoring this class info",
1500 // Read the 32 bit hash for the class name
1501 const uint32_t name_hash = data.GetU32(&offset);
1502 ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, NULL));
1503 AddClass(isa, descriptor_sp, name_hash);
1506 log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64
1507 ", hash=0x%8.8x, name=%s",
1509 descriptor_sp->GetClassName().AsCString("<unknown>"));
1513 log->Printf("AppleObjCRuntimeV2 parsed %" PRIu32 " class infos",
1518 AppleObjCRuntimeV2::DescriptorMapUpdateResult
1519 AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() {
1520 Process *process = GetProcess();
1522 if (process == NULL)
1523 return DescriptorMapUpdateResult::Fail();
1525 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1527 ExecutionContext exe_ctx;
1529 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1532 return DescriptorMapUpdateResult::Fail();
1534 thread_sp->CalculateExecutionContext(exe_ctx);
1535 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1538 return DescriptorMapUpdateResult::Fail();
1540 Address function_address;
1542 DiagnosticManager diagnostics;
1544 const uint32_t addr_size = process->GetAddressByteSize();
1548 uint32_t num_class_infos = 0;
1550 const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
1552 if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
1553 return DescriptorMapUpdateResult::Fail();
1555 const uint32_t num_classes = 128 * 1024;
1557 // Make some types for our arguments
1558 CompilerType clang_uint32_t_type =
1559 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1560 CompilerType clang_void_pointer_type =
1561 ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1563 ValueList arguments;
1564 FunctionCaller *get_shared_cache_class_info_function = nullptr;
1566 if (!m_get_shared_cache_class_info_code.get()) {
1568 m_get_shared_cache_class_info_code.reset(
1569 GetTargetRef().GetUtilityFunctionForLanguage(
1570 g_get_shared_cache_class_info_body, eLanguageTypeObjC,
1571 g_get_shared_cache_class_info_name, error));
1575 "Failed to get Utility function for implementation lookup: %s.",
1577 m_get_shared_cache_class_info_code.reset();
1579 diagnostics.Clear();
1581 if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) {
1583 log->Printf("Failed to install implementation lookup.");
1584 diagnostics.Dump(log);
1586 m_get_shared_cache_class_info_code.reset();
1590 if (!m_get_shared_cache_class_info_code.get())
1591 return DescriptorMapUpdateResult::Fail();
1593 // Next make the function caller for our implementation utility function.
1595 value.SetValueType(Value::eValueTypeScalar);
1596 // value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
1597 value.SetCompilerType(clang_void_pointer_type);
1598 arguments.PushValue(value);
1599 arguments.PushValue(value);
1601 value.SetValueType(Value::eValueTypeScalar);
1602 // value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1603 value.SetCompilerType(clang_uint32_t_type);
1604 arguments.PushValue(value);
1605 arguments.PushValue(value);
1607 get_shared_cache_class_info_function =
1608 m_get_shared_cache_class_info_code->MakeFunctionCaller(
1609 clang_uint32_t_type, arguments, thread_sp, error);
1611 if (get_shared_cache_class_info_function == nullptr)
1612 return DescriptorMapUpdateResult::Fail();
1615 get_shared_cache_class_info_function =
1616 m_get_shared_cache_class_info_code->GetFunctionCaller();
1617 if (get_shared_cache_class_info_function == nullptr)
1618 return DescriptorMapUpdateResult::Fail();
1619 arguments = get_shared_cache_class_info_function->GetArgumentValues();
1622 diagnostics.Clear();
1624 const uint32_t class_info_byte_size = addr_size + 4;
1625 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1626 lldb::addr_t class_infos_addr = process->AllocateMemory(
1627 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);
1629 if (class_infos_addr == LLDB_INVALID_ADDRESS) {
1631 log->Printf("unable to allocate %" PRIu32
1632 " bytes in process for shared cache read",
1633 class_infos_byte_size);
1634 return DescriptorMapUpdateResult::Fail();
1637 std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex);
1639 // Fill in our function argument values
1640 arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
1641 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1642 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1643 arguments.GetValueAtIndex(3)->GetScalar() =
1644 (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
1646 bool success = false;
1648 diagnostics.Clear();
1650 // Write our function arguments into the process so we can run our function
1651 if (get_shared_cache_class_info_function->WriteFunctionArguments(
1652 exe_ctx, m_get_shared_cache_class_info_args, arguments,
1654 EvaluateExpressionOptions options;
1655 options.SetUnwindOnError(true);
1656 options.SetTryAllThreads(false);
1657 options.SetStopOthers(true);
1658 options.SetIgnoreBreakpoints(true);
1659 options.SetTimeout(g_utility_function_timeout);
1662 return_value.SetValueType(Value::eValueTypeScalar);
1663 // return_value.SetContext (Value::eContextTypeClangType,
1664 // clang_uint32_t_type);
1665 return_value.SetCompilerType(clang_uint32_t_type);
1666 return_value.GetScalar() = 0;
1668 diagnostics.Clear();
1671 ExpressionResults results =
1672 get_shared_cache_class_info_function->ExecuteFunction(
1673 exe_ctx, &m_get_shared_cache_class_info_args, options, diagnostics,
1676 if (results == eExpressionCompleted) {
1677 // The result is the number of ClassInfo structures that were filled in
1678 num_class_infos = return_value.GetScalar().ULong();
1680 log->Printf("Discovered %u ObjC classes in shared cache\n",
1682 #ifdef LLDB_CONFIGURATION_DEBUG
1683 assert(num_class_infos <= num_classes);
1685 if (num_class_infos > 0) {
1686 if (num_class_infos > num_classes) {
1687 num_class_infos = num_classes;
1694 // Read the ClassInfo structures
1695 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);
1696 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),
1697 buffer.GetByteSize(),
1698 err) == buffer.GetByteSize()) {
1699 DataExtractor class_infos_data(buffer.GetBytes(),
1700 buffer.GetByteSize(),
1701 process->GetByteOrder(), addr_size);
1703 ParseClassInfoArray(class_infos_data, num_class_infos);
1710 log->Printf("Error evaluating our find class name function.");
1711 diagnostics.Dump(log);
1716 log->Printf("Error writing function arguments.");
1717 diagnostics.Dump(log);
1721 // Deallocate the memory we allocated for the ClassInfo array
1722 process->DeallocateMemory(class_infos_addr);
1724 return DescriptorMapUpdateResult(success, num_class_infos);
1727 bool AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory(
1728 RemoteNXMapTable &hash_table) {
1729 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1731 Process *process = GetProcess();
1733 if (process == NULL)
1736 uint32_t num_map_table_isas = 0;
1738 ModuleSP objc_module_sp(GetObjCModule());
1740 if (objc_module_sp) {
1741 for (RemoteNXMapTable::element elt : hash_table) {
1742 ++num_map_table_isas;
1744 if (ISAIsCached(elt.second))
1747 ClassDescriptorSP descriptor_sp = ClassDescriptorSP(
1748 new ClassDescriptorV2(*this, elt.second, elt.first.AsCString()));
1750 if (log && log->GetVerbose())
1751 log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64
1752 " (%s) from dynamic table to isa->descriptor cache",
1753 elt.second, elt.first.AsCString());
1755 AddClass(elt.second, descriptor_sp, elt.first.AsCString());
1759 return num_map_table_isas > 0;
1762 lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {
1763 Process *process = GetProcess();
1766 ModuleSP objc_module_sp(GetObjCModule());
1768 if (objc_module_sp) {
1769 ObjectFile *objc_object = objc_module_sp->GetObjectFile();
1772 SectionList *section_list = objc_module_sp->GetSectionList();
1775 SectionSP text_segment_sp(
1776 section_list->FindSectionByName(ConstString("__TEXT")));
1778 if (text_segment_sp) {
1779 SectionSP objc_opt_section_sp(
1780 text_segment_sp->GetChildren().FindSectionByName(
1781 ConstString("__objc_opt_ro")));
1783 if (objc_opt_section_sp) {
1784 return objc_opt_section_sp->GetLoadBaseAddress(
1785 &process->GetTarget());
1792 return LLDB_INVALID_ADDRESS;
1795 void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {
1796 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES));
1798 Timer scoped_timer(LLVM_PRETTY_FUNCTION, LLVM_PRETTY_FUNCTION);
1800 // Else we need to check with our process to see when the map was updated.
1801 Process *process = GetProcess();
1804 RemoteNXMapTable hash_table;
1806 // Update the process stop ID that indicates the last time we updated the
1807 // map, whether it was successful or not.
1808 m_isa_to_descriptor_stop_id = process->GetStopID();
1810 if (!m_hash_signature.NeedsUpdate(process, this, hash_table))
1813 m_hash_signature.UpdateSignature(hash_table);
1815 // Grab the dynamically loaded objc classes from the hash table in memory
1816 DescriptorMapUpdateResult dynamic_update_result =
1817 UpdateISAToDescriptorMapDynamic(hash_table);
1819 // Now get the objc classes that are baked into the Objective C runtime
1820 // in the shared cache, but only once per process as this data never
1822 if (!m_loaded_objc_opt) {
1823 // it is legitimately possible for the shared cache to be empty - in that
1824 // case, the dynamic hash table
1825 // will contain all the class information we need; the situation we're
1826 // trying to detect is one where
1827 // we aren't seeing class information from the runtime - in order to
1828 // detect that vs. just the shared cache
1829 // being empty or sparsely populated, we set an arbitrary (very low)
1830 // threshold for the number of classes
1831 // that we want to see in a "good" scenario - anything below that is
1832 // suspicious (Foundation alone has thousands
1834 const uint32_t num_classes_to_warn_at = 500;
1836 DescriptorMapUpdateResult shared_cache_update_result =
1837 UpdateISAToDescriptorMapSharedCache();
1840 log->Printf("attempted to read objc class data - results: "
1841 "[dynamic_update]: ran: %s, count: %" PRIu32
1842 " [shared_cache_update]: ran: %s, count: %" PRIu32,
1843 dynamic_update_result.m_update_ran ? "yes" : "no",
1844 dynamic_update_result.m_num_found,
1845 shared_cache_update_result.m_update_ran ? "yes" : "no",
1846 shared_cache_update_result.m_num_found);
1849 // - we could not run either expression
1850 // - we found fewer than num_classes_to_warn_at classes total
1851 if ((false == shared_cache_update_result.m_update_ran) ||
1852 (false == dynamic_update_result.m_update_ran))
1853 WarnIfNoClassesCached(
1854 SharedCacheWarningReason::eExpressionExecutionFailure);
1855 else if (dynamic_update_result.m_num_found +
1856 shared_cache_update_result.m_num_found <
1857 num_classes_to_warn_at)
1858 WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead);
1860 m_loaded_objc_opt = true;
1863 m_isa_to_descriptor_stop_id = UINT32_MAX;
1867 static bool DoesProcessHaveSharedCache(Process &process) {
1868 PlatformSP platform_sp = process.GetTarget().GetPlatform();
1870 return true; // this should not happen
1872 ConstString platform_plugin_name = platform_sp->GetPluginName();
1873 if (platform_plugin_name) {
1874 llvm::StringRef platform_plugin_name_sr =
1875 platform_plugin_name.GetStringRef();
1876 if (platform_plugin_name_sr.endswith("-simulator"))
1883 void AppleObjCRuntimeV2::WarnIfNoClassesCached(
1884 SharedCacheWarningReason reason) {
1885 if (m_noclasses_warning_emitted)
1888 if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) {
1889 // Simulators do not have the objc_opt_ro class table so don't actually
1890 // complain to the user
1891 m_noclasses_warning_emitted = true;
1895 Debugger &debugger(GetProcess()->GetTarget().GetDebugger());
1896 if (auto stream = debugger.GetAsyncOutputStream()) {
1898 case SharedCacheWarningReason::eNotEnoughClassesRead:
1899 stream->PutCString("warning: could not find Objective-C class data in "
1900 "the process. This may reduce the quality of type "
1901 "information available.\n");
1902 m_noclasses_warning_emitted = true;
1904 case SharedCacheWarningReason::eExpressionExecutionFailure:
1905 stream->PutCString("warning: could not execute support code to read "
1906 "Objective-C class data in the process. This may "
1907 "reduce the quality of type information available.\n");
1908 m_noclasses_warning_emitted = true;
1915 AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) {
1916 if (isa == g_objc_Tagged_ISA) {
1917 static const ConstString g_objc_tagged_isa_name("_lldb_Tagged_ObjC_ISA");
1918 return g_objc_tagged_isa_name;
1920 if (isa == g_objc_Tagged_ISA_NSAtom) {
1921 static const ConstString g_objc_tagged_isa_nsatom_name("NSAtom");
1922 return g_objc_tagged_isa_nsatom_name;
1924 if (isa == g_objc_Tagged_ISA_NSNumber) {
1925 static const ConstString g_objc_tagged_isa_nsnumber_name("NSNumber");
1926 return g_objc_tagged_isa_nsnumber_name;
1928 if (isa == g_objc_Tagged_ISA_NSDateTS) {
1929 static const ConstString g_objc_tagged_isa_nsdatets_name("NSDateTS");
1930 return g_objc_tagged_isa_nsdatets_name;
1932 if (isa == g_objc_Tagged_ISA_NSManagedObject) {
1933 static const ConstString g_objc_tagged_isa_nsmanagedobject_name(
1935 return g_objc_tagged_isa_nsmanagedobject_name;
1937 if (isa == g_objc_Tagged_ISA_NSDate) {
1938 static const ConstString g_objc_tagged_isa_nsdate_name("NSDate");
1939 return g_objc_tagged_isa_nsdate_name;
1941 return ObjCLanguageRuntime::GetActualTypeName(isa);
1944 DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() {
1945 if (!m_decl_vendor_ap.get())
1946 m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this));
1948 return m_decl_vendor_ap.get();
1951 lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(const ConstString &name) {
1952 lldb::addr_t ret = LLDB_INVALID_ADDRESS;
1954 const char *name_cstr = name.AsCString();
1957 llvm::StringRef name_strref(name_cstr);
1959 static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
1960 static const llvm::StringRef class_prefix("OBJC_CLASS_$_");
1962 if (name_strref.startswith(ivar_prefix)) {
1963 llvm::StringRef ivar_skipped_prefix =
1964 name_strref.substr(ivar_prefix.size());
1965 std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =
1966 ivar_skipped_prefix.split('.');
1968 if (class_and_ivar.first.size() && class_and_ivar.second.size()) {
1969 const ConstString class_name_cs(class_and_ivar.first);
1970 ClassDescriptorSP descriptor =
1971 ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);
1974 const ConstString ivar_name_cs(class_and_ivar.second);
1975 const char *ivar_name_cstr = ivar_name_cs.AsCString();
1977 auto ivar_func = [&ret, ivar_name_cstr](
1978 const char *name, const char *type, lldb::addr_t offset_addr,
1979 uint64_t size) -> lldb::addr_t {
1980 if (!strcmp(name, ivar_name_cstr)) {
1987 descriptor->Describe(
1988 std::function<void(ObjCISA)>(nullptr),
1989 std::function<bool(const char *, const char *)>(nullptr),
1990 std::function<bool(const char *, const char *)>(nullptr),
1994 } else if (name_strref.startswith(class_prefix)) {
1995 llvm::StringRef class_skipped_prefix =
1996 name_strref.substr(class_prefix.size());
1997 const ConstString class_name_cs(class_skipped_prefix);
1998 ClassDescriptorSP descriptor =
1999 GetClassDescriptorFromClassName(class_name_cs);
2002 ret = descriptor->GetISA();
2009 AppleObjCRuntimeV2::NonPointerISACache *
2010 AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(
2011 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2012 Process *process(runtime.GetProcess());
2016 auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(
2017 process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);
2021 auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(
2022 process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,
2027 auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(
2028 process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);
2032 // we might want to have some rules to outlaw these other values (e.g if the
2033 // mask is zero but the value is non-zero, ...)
2035 return new NonPointerISACache(runtime, objc_debug_isa_class_mask,
2036 objc_debug_isa_magic_mask,
2037 objc_debug_isa_magic_value);
2040 AppleObjCRuntimeV2::TaggedPointerVendorV2 *
2041 AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(
2042 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {
2043 Process *process(runtime.GetProcess());
2047 auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(
2048 process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,
2051 return new TaggedPointerVendorLegacy(runtime);
2053 auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(
2054 process, ConstString("objc_debug_taggedpointer_slot_shift"),
2055 objc_module_sp, error, true, 4);
2057 return new TaggedPointerVendorLegacy(runtime);
2059 auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(
2060 process, ConstString("objc_debug_taggedpointer_slot_mask"),
2061 objc_module_sp, error, true, 4);
2063 return new TaggedPointerVendorLegacy(runtime);
2065 auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(
2066 process, ConstString("objc_debug_taggedpointer_payload_lshift"),
2067 objc_module_sp, error, true, 4);
2069 return new TaggedPointerVendorLegacy(runtime);
2071 auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(
2072 process, ConstString("objc_debug_taggedpointer_payload_rshift"),
2073 objc_module_sp, error, true, 4);
2075 return new TaggedPointerVendorLegacy(runtime);
2077 auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(
2078 process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,
2081 return new TaggedPointerVendorLegacy(runtime);
2083 // try to detect the "extended tagged pointer" variables - if any are missing,
2084 // use the non-extended vendor
2086 auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(
2087 process, ConstString("objc_debug_taggedpointer_ext_mask"),
2088 objc_module_sp, error);
2092 auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(
2093 process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),
2094 objc_module_sp, error, true, 4);
2098 auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(
2099 process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),
2100 objc_module_sp, error, true, 4);
2104 auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(
2105 process, ConstString("objc_debug_taggedpointer_ext_classes"),
2106 objc_module_sp, error, false);
2110 auto objc_debug_taggedpointer_ext_payload_lshift =
2111 ExtractRuntimeGlobalSymbol(
2112 process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),
2113 objc_module_sp, error, true, 4);
2117 auto objc_debug_taggedpointer_ext_payload_rshift =
2118 ExtractRuntimeGlobalSymbol(
2119 process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),
2120 objc_module_sp, error, true, 4);
2124 return new TaggedPointerVendorExtended(
2125 runtime, objc_debug_taggedpointer_mask,
2126 objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift,
2127 objc_debug_taggedpointer_ext_slot_shift,
2128 objc_debug_taggedpointer_slot_mask,
2129 objc_debug_taggedpointer_ext_slot_mask,
2130 objc_debug_taggedpointer_payload_lshift,
2131 objc_debug_taggedpointer_payload_rshift,
2132 objc_debug_taggedpointer_ext_payload_lshift,
2133 objc_debug_taggedpointer_ext_payload_rshift,
2134 objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);
2137 // we might want to have some rules to outlaw these values (e.g if the table's
2140 return new TaggedPointerVendorRuntimeAssisted(
2141 runtime, objc_debug_taggedpointer_mask,
2142 objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask,
2143 objc_debug_taggedpointer_payload_lshift,
2144 objc_debug_taggedpointer_payload_rshift,
2145 objc_debug_taggedpointer_classes);
2148 bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer(
2153 ObjCLanguageRuntime::ClassDescriptorSP
2154 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor(
2156 if (!IsPossibleTaggedPointer(ptr))
2157 return ObjCLanguageRuntime::ClassDescriptorSP();
2159 uint32_t foundation_version = m_runtime.GetFoundationVersion();
2161 if (foundation_version == LLDB_INVALID_MODULE_VERSION)
2162 return ObjCLanguageRuntime::ClassDescriptorSP();
2164 uint64_t class_bits = (ptr & 0xE) >> 1;
2167 static ConstString g_NSAtom("NSAtom");
2168 static ConstString g_NSNumber("NSNumber");
2169 static ConstString g_NSDateTS("NSDateTS");
2170 static ConstString g_NSManagedObject("NSManagedObject");
2171 static ConstString g_NSDate("NSDate");
2173 if (foundation_version >= 900) {
2174 switch (class_bits) {
2185 name = g_NSManagedObject;
2191 return ObjCLanguageRuntime::ClassDescriptorSP();
2194 switch (class_bits) {
2199 name = g_NSManagedObject;
2208 return ObjCLanguageRuntime::ClassDescriptorSP();
2211 return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, ptr));
2214 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
2215 TaggedPointerVendorRuntimeAssisted(
2216 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2217 uint32_t objc_debug_taggedpointer_slot_shift,
2218 uint32_t objc_debug_taggedpointer_slot_mask,
2219 uint32_t objc_debug_taggedpointer_payload_lshift,
2220 uint32_t objc_debug_taggedpointer_payload_rshift,
2221 lldb::addr_t objc_debug_taggedpointer_classes)
2222 : TaggedPointerVendorV2(runtime), m_cache(),
2223 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
2224 m_objc_debug_taggedpointer_slot_shift(
2225 objc_debug_taggedpointer_slot_shift),
2226 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
2227 m_objc_debug_taggedpointer_payload_lshift(
2228 objc_debug_taggedpointer_payload_lshift),
2229 m_objc_debug_taggedpointer_payload_rshift(
2230 objc_debug_taggedpointer_payload_rshift),
2231 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {}
2233 bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::
2234 IsPossibleTaggedPointer(lldb::addr_t ptr) {
2235 return (ptr & m_objc_debug_taggedpointer_mask) != 0;
2238 ObjCLanguageRuntime::ClassDescriptorSP
2239 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(
2241 ClassDescriptorSP actual_class_descriptor_sp;
2242 uint64_t data_payload;
2244 if (!IsPossibleTaggedPointer(ptr))
2245 return ObjCLanguageRuntime::ClassDescriptorSP();
2247 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) &
2248 m_objc_debug_taggedpointer_slot_mask;
2250 CacheIterator iterator = m_cache.find(slot), end = m_cache.end();
2251 if (iterator != end) {
2252 actual_class_descriptor_sp = iterator->second;
2254 Process *process(m_runtime.GetProcess());
2255 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
2256 m_objc_debug_taggedpointer_classes;
2258 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2259 if (error.Fail() || slot_data == 0 ||
2260 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2262 actual_class_descriptor_sp =
2263 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2264 if (!actual_class_descriptor_sp)
2265 return ObjCLanguageRuntime::ClassDescriptorSP();
2266 m_cache[slot] = actual_class_descriptor_sp;
2270 (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >>
2271 m_objc_debug_taggedpointer_payload_rshift);
2273 return ClassDescriptorSP(
2274 new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2277 AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(
2278 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,
2279 uint64_t objc_debug_taggedpointer_ext_mask,
2280 uint32_t objc_debug_taggedpointer_slot_shift,
2281 uint32_t objc_debug_taggedpointer_ext_slot_shift,
2282 uint32_t objc_debug_taggedpointer_slot_mask,
2283 uint32_t objc_debug_taggedpointer_ext_slot_mask,
2284 uint32_t objc_debug_taggedpointer_payload_lshift,
2285 uint32_t objc_debug_taggedpointer_payload_rshift,
2286 uint32_t objc_debug_taggedpointer_ext_payload_lshift,
2287 uint32_t objc_debug_taggedpointer_ext_payload_rshift,
2288 lldb::addr_t objc_debug_taggedpointer_classes,
2289 lldb::addr_t objc_debug_taggedpointer_ext_classes)
2290 : TaggedPointerVendorRuntimeAssisted(
2291 runtime, objc_debug_taggedpointer_mask,
2292 objc_debug_taggedpointer_slot_shift,
2293 objc_debug_taggedpointer_slot_mask,
2294 objc_debug_taggedpointer_payload_lshift,
2295 objc_debug_taggedpointer_payload_rshift,
2296 objc_debug_taggedpointer_classes),
2298 m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),
2299 m_objc_debug_taggedpointer_ext_slot_shift(
2300 objc_debug_taggedpointer_ext_slot_shift),
2301 m_objc_debug_taggedpointer_ext_slot_mask(
2302 objc_debug_taggedpointer_ext_slot_mask),
2303 m_objc_debug_taggedpointer_ext_payload_lshift(
2304 objc_debug_taggedpointer_ext_payload_lshift),
2305 m_objc_debug_taggedpointer_ext_payload_rshift(
2306 objc_debug_taggedpointer_ext_payload_rshift),
2307 m_objc_debug_taggedpointer_ext_classes(
2308 objc_debug_taggedpointer_ext_classes) {}
2310 bool AppleObjCRuntimeV2::TaggedPointerVendorExtended::
2311 IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) {
2312 if (!IsPossibleTaggedPointer(ptr))
2315 if (m_objc_debug_taggedpointer_ext_mask == 0)
2318 return ((ptr & m_objc_debug_taggedpointer_ext_mask) ==
2319 m_objc_debug_taggedpointer_ext_mask);
2322 ObjCLanguageRuntime::ClassDescriptorSP
2323 AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(
2325 ClassDescriptorSP actual_class_descriptor_sp;
2326 uint64_t data_payload;
2328 if (!IsPossibleTaggedPointer(ptr))
2329 return ObjCLanguageRuntime::ClassDescriptorSP();
2331 if (!IsPossibleExtendedTaggedPointer(ptr))
2332 return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);
2334 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) &
2335 m_objc_debug_taggedpointer_ext_slot_mask;
2337 CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end();
2338 if (iterator != end) {
2339 actual_class_descriptor_sp = iterator->second;
2341 Process *process(m_runtime.GetProcess());
2342 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +
2343 m_objc_debug_taggedpointer_ext_classes;
2345 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2346 if (error.Fail() || slot_data == 0 ||
2347 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2349 actual_class_descriptor_sp =
2350 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2351 if (!actual_class_descriptor_sp)
2352 return ObjCLanguageRuntime::ClassDescriptorSP();
2353 m_ext_cache[slot] = actual_class_descriptor_sp;
2357 (((uint64_t)ptr << m_objc_debug_taggedpointer_ext_payload_lshift) >>
2358 m_objc_debug_taggedpointer_ext_payload_rshift);
2360 return ClassDescriptorSP(
2361 new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload));
2364 AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(
2365 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_isa_class_mask,
2366 uint64_t objc_debug_isa_magic_mask, uint64_t objc_debug_isa_magic_value)
2367 : m_runtime(runtime), m_cache(),
2368 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
2369 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
2370 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value) {}
2372 ObjCLanguageRuntime::ClassDescriptorSP
2373 AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) {
2374 ObjCISA real_isa = 0;
2375 if (EvaluateNonPointerISA(isa, real_isa) == false)
2376 return ObjCLanguageRuntime::ClassDescriptorSP();
2377 auto cache_iter = m_cache.find(real_isa);
2378 if (cache_iter != m_cache.end())
2379 return cache_iter->second;
2380 auto descriptor_sp =
2381 m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
2382 if (descriptor_sp) // cache only positive matches since the table might grow
2383 m_cache[real_isa] = descriptor_sp;
2384 return descriptor_sp;
2387 bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA(
2388 ObjCISA isa, ObjCISA &ret_isa) {
2389 if ((isa & ~m_objc_debug_isa_class_mask) == 0)
2391 if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) {
2392 ret_isa = isa & m_objc_debug_isa_class_mask;
2393 return (ret_isa != 0); // this is a pointer so 0 is not a valid value
2398 ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() {
2399 if (!m_encoding_to_type_sp)
2400 m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this));
2401 return m_encoding_to_type_sp;
2404 lldb_private::AppleObjCRuntime::ObjCISA
2405 AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) {
2408 if (m_non_pointer_isa_cache_ap)
2409 m_non_pointer_isa_cache_ap->EvaluateNonPointerISA(isa, ret);
2414 bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() {
2415 if (m_CFBoolean_values)
2418 static ConstString g_kCFBooleanFalse("kCFBooleanFalse");
2419 static ConstString g_kCFBooleanTrue("kCFBooleanTrue");
2421 std::function<lldb::addr_t(ConstString)> get_symbol =
2422 [this](ConstString sym) -> lldb::addr_t {
2423 SymbolContextList sc_list;
2424 if (GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(
2425 g_kCFBooleanFalse, lldb::eSymbolTypeData, sc_list) == 1) {
2427 sc_list.GetContextAtIndex(0, sc);
2429 return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());
2432 return LLDB_INVALID_ADDRESS;
2435 lldb::addr_t false_addr = get_symbol(g_kCFBooleanFalse);
2436 lldb::addr_t true_addr = get_symbol(g_kCFBooleanTrue);
2438 return (m_CFBoolean_values = {false_addr, true_addr}).operator bool();
2441 void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,
2442 lldb::addr_t &cf_false) {
2443 if (GetCFBooleanValuesIfNeeded()) {
2444 cf_true = m_CFBoolean_values->second;
2445 cf_false = m_CFBoolean_values->first;
2447 this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);