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