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