AppleObjCRuntimeV2.cpp revision 341825
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/OptionArgParser.h" 41#include "lldb/Interpreter/OptionValueBoolean.h" 42#include "lldb/Symbol/ClangASTContext.h" 43#include "lldb/Symbol/ObjectFile.h" 44#include "lldb/Symbol/Symbol.h" 45#include "lldb/Symbol/TypeList.h" 46#include "lldb/Symbol/VariableList.h" 47#include "lldb/Target/ExecutionContext.h" 48#include "lldb/Target/Platform.h" 49#include "lldb/Target/Process.h" 50#include "lldb/Target/RegisterContext.h" 51#include "lldb/Target/Target.h" 52#include "lldb/Target/Thread.h" 53#include "lldb/Utility/ConstString.h" 54#include "lldb/Utility/Log.h" 55#include "lldb/Utility/Status.h" 56#include "lldb/Utility/Stream.h" 57#include "lldb/Utility/StreamString.h" 58#include "lldb/Utility/Timer.h" 59 60#include "AppleObjCClassDescriptorV2.h" 61#include "AppleObjCDeclVendor.h" 62#include "AppleObjCRuntimeV2.h" 63#include "AppleObjCTrampolineHandler.h" 64#include "AppleObjCTypeEncodingParser.h" 65 66#include "clang/AST/ASTContext.h" 67#include "clang/AST/DeclObjC.h" 68 69#include <vector> 70 71using namespace lldb; 72using namespace lldb_private; 73 74// 2 second timeout when running utility functions 75static constexpr std::chrono::seconds g_utility_function_timeout(2); 76 77static const char *g_get_dynamic_class_info_name = 78 "__lldb_apple_objc_v2_get_dynamic_class_info"; 79// Testing using the new C++11 raw string literals. If this breaks GCC then we 80// will 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 need to revert to the code above... 165static const char *g_get_shared_cache_class_info_body = R"( 166 167extern "C" 168{ 169 const char *class_getName(void *objc_class); 170 size_t strlen(const char *); 171 char *strncpy (char * s1, const char * s2, size_t n); 172 int printf(const char * format, ...); 173} 174 175#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__) 176 177 178struct objc_classheader_t { 179 int32_t clsOffset; 180 int32_t hiOffset; 181}; 182 183struct objc_clsopt_t { 184 uint32_t capacity; 185 uint32_t occupied; 186 uint32_t shift; 187 uint32_t mask; 188 uint32_t zero; 189 uint32_t unused; 190 uint64_t salt; 191 uint32_t scramble[256]; 192 uint8_t tab[0]; // tab[mask+1] 193 // uint8_t checkbytes[capacity]; 194 // int32_t offset[capacity]; 195 // objc_classheader_t clsOffsets[capacity]; 196 // uint32_t duplicateCount; 197 // objc_classheader_t duplicateOffsets[duplicateCount]; 198}; 199 200struct objc_opt_t { 201 uint32_t version; 202 int32_t selopt_offset; 203 int32_t headeropt_offset; 204 int32_t clsopt_offset; 205}; 206 207struct objc_opt_v14_t { 208 uint32_t version; 209 uint32_t flags; 210 int32_t selopt_offset; 211 int32_t headeropt_offset; 212 int32_t clsopt_offset; 213}; 214 215struct ClassInfo 216{ 217 Class isa; 218 uint32_t hash; 219} __attribute__((__packed__)); 220 221uint32_t 222__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, 223 void *class_infos_ptr, 224 uint32_t class_infos_byte_size, 225 uint32_t should_log) 226{ 227 uint32_t idx = 0; 228 DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr); 229 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr); 230 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo))); 231 if (objc_opt_ro_ptr) 232 { 233 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr; 234 const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr; 235 const bool is_v14_format = objc_opt->version >= 14; 236 if (is_v14_format) 237 { 238 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version); 239 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags); 240 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset); 241 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset); 242 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset); 243 } 244 else 245 { 246 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version); 247 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset); 248 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset); 249 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset); 250 } 251 if (objc_opt->version == 12 || objc_opt->version == 13 || objc_opt->version == 14 || objc_opt->version == 15) 252 { 253 const objc_clsopt_t* clsopt = NULL; 254 if (is_v14_format) 255 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset); 256 else 257 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset); 258 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); 259 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos); 260 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; 261 int32_t invalidEntryOffset = 0; 262 // this is safe to do because the version field order is invariant 263 if (objc_opt->version == 12) 264 invalidEntryOffset = 16; 265 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1]; 266 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity); 267 const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity); 268 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity); 269 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask); 270 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets); 271 DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset); 272 for (uint32_t i=0; i<clsopt->capacity; ++i) 273 { 274 const int32_t clsOffset = classOffsets[i].clsOffset; 275 DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset); 276 if (clsOffset & 1) 277 { 278 DEBUG_PRINTF("clsOffset & 1\n"); 279 continue; // duplicate 280 } 281 else if (clsOffset == invalidEntryOffset) 282 { 283 DEBUG_PRINTF("clsOffset == invalidEntryOffset\n"); 284 continue; // invalid offset 285 } 286 287 if (class_infos && idx < max_class_infos) 288 { 289 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); 290 const char *name = class_getName (class_infos[idx].isa); 291 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name); 292 // Hash the class name so we don't have to read it 293 const char *s = name; 294 uint32_t h = 5381; 295 for (unsigned char c = *s; c; c = *++s) 296 h = ((h << 5) + h) + c; 297 class_infos[idx].hash = h; 298 } 299 else 300 { 301 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n"); 302 } 303 ++idx; 304 } 305 306 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity]; 307 const uint32_t duplicate_count = *duplicate_count_ptr; 308 const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]); 309 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count); 310 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets); 311 for (uint32_t i=0; i<duplicate_count; ++i) 312 { 313 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset; 314 if (clsOffset & 1) 315 continue; // duplicate 316 else if (clsOffset == invalidEntryOffset) 317 continue; // invalid offset 318 319 if (class_infos && idx < max_class_infos) 320 { 321 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); 322 const char *name = class_getName (class_infos[idx].isa); 323 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name); 324 // Hash the class name so we don't have to read it 325 const char *s = name; 326 uint32_t h = 5381; 327 for (unsigned char c = *s; c; c = *++s) 328 h = ((h << 5) + h) + c; 329 class_infos[idx].hash = h; 330 } 331 ++idx; 332 } 333 } 334 DEBUG_PRINTF ("%u class_infos\n", idx); 335 DEBUG_PRINTF ("done\n"); 336 } 337 return idx; 338} 339 340 341)"; 342 343static uint64_t 344ExtractRuntimeGlobalSymbol(Process *process, ConstString name, 345 const ModuleSP &module_sp, Status &error, 346 bool read_value = true, uint8_t byte_size = 0, 347 uint64_t default_value = LLDB_INVALID_ADDRESS, 348 SymbolType sym_type = lldb::eSymbolTypeData) { 349 if (!process) { 350 error.SetErrorString("no process"); 351 return default_value; 352 } 353 if (!module_sp) { 354 error.SetErrorString("no module"); 355 return default_value; 356 } 357 if (!byte_size) 358 byte_size = process->GetAddressByteSize(); 359 const Symbol *symbol = 360 module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData); 361 if (symbol && symbol->ValueIsAddress()) { 362 lldb::addr_t symbol_load_addr = 363 symbol->GetAddressRef().GetLoadAddress(&process->GetTarget()); 364 if (symbol_load_addr != LLDB_INVALID_ADDRESS) { 365 if (read_value) 366 return process->ReadUnsignedIntegerFromMemory( 367 symbol_load_addr, byte_size, default_value, error); 368 else 369 return symbol_load_addr; 370 } else { 371 error.SetErrorString("symbol address invalid"); 372 return default_value; 373 } 374 } else { 375 error.SetErrorString("no symbol"); 376 return default_value; 377 } 378} 379 380AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, 381 const ModuleSP &objc_module_sp) 382 : AppleObjCRuntime(process), m_get_class_info_code(), 383 m_get_class_info_args(LLDB_INVALID_ADDRESS), 384 m_get_class_info_args_mutex(), m_get_shared_cache_class_info_code(), 385 m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS), 386 m_get_shared_cache_class_info_args_mutex(), m_decl_vendor_ap(), 387 m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS), 388 m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS), 389 m_hash_signature(), 390 m_has_object_getClass(false), m_loaded_objc_opt(false), 391 m_non_pointer_isa_cache_ap( 392 NonPointerISACache::CreateInstance(*this, objc_module_sp)), 393 m_tagged_pointer_vendor_ap( 394 TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)), 395 m_encoding_to_type_sp(), m_noclasses_warning_emitted(false), 396 m_CFBoolean_values() { 397 static const ConstString g_gdb_object_getClass("gdb_object_getClass"); 398 m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType( 399 g_gdb_object_getClass, eSymbolTypeCode) != NULL); 400} 401 402bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress( 403 ValueObject &in_value, lldb::DynamicValueType use_dynamic, 404 TypeAndOrName &class_type_or_name, Address &address, 405 Value::ValueType &value_type) { 406 // We should never get here with a null process... 407 assert(m_process != NULL); 408 409 // The Runtime is attached to a particular process, you shouldn't pass in a 410 // value from another process. Note, however, the process might be NULL (e.g. 411 // if the value was made with SBTarget::EvaluateExpression...) in which case 412 // 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 426 // be 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 = OptionArgParser::ToAddress( 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 class 874 // 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 the 884 // 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 this routine attempts to check with as little 918// computational effort as possible whether something could possibly be a 919// tagged pointer - false positives are possible but false negatives shouldn't 920bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) { 921 if (!m_tagged_pointer_vendor_ap) 922 return false; 923 return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr); 924} 925 926class RemoteNXMapTable { 927public: 928 RemoteNXMapTable() 929 : m_count(0), m_num_buckets_minus_one(0), 930 m_buckets_ptr(LLDB_INVALID_ADDRESS), m_process(NULL), 931 m_end_iterator(*this, -1), m_load_addr(LLDB_INVALID_ADDRESS), 932 m_map_pair_size(0), m_invalid_key(0) {} 933 934 void Dump() { 935 printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr); 936 printf("RemoteNXMapTable.m_count = %u\n", m_count); 937 printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", 938 m_num_buckets_minus_one); 939 printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr); 940 } 941 942 bool ParseHeader(Process *process, lldb::addr_t load_addr) { 943 m_process = process; 944 m_load_addr = load_addr; 945 m_map_pair_size = m_process->GetAddressByteSize() * 2; 946 m_invalid_key = 947 m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX; 948 Status err; 949 950 // This currently holds true for all platforms we support, but we might 951 // need to change this to use get the actually byte size of "unsigned" from 952 // the target AST... 953 const uint32_t unsigned_byte_size = sizeof(uint32_t); 954 // Skip the prototype as we don't need it (const struct 955 // +NXMapTablePrototype *prototype) 956 957 bool success = true; 958 if (load_addr == LLDB_INVALID_ADDRESS) 959 success = false; 960 else { 961 lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize(); 962 963 // unsigned count; 964 m_count = m_process->ReadUnsignedIntegerFromMemory( 965 cursor, unsigned_byte_size, 0, err); 966 if (m_count) { 967 cursor += unsigned_byte_size; 968 969 // unsigned nbBucketsMinusOne; 970 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory( 971 cursor, unsigned_byte_size, 0, err); 972 cursor += unsigned_byte_size; 973 974 // void *buckets; 975 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err); 976 977 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS; 978 } 979 } 980 981 if (!success) { 982 m_count = 0; 983 m_num_buckets_minus_one = 0; 984 m_buckets_ptr = LLDB_INVALID_ADDRESS; 985 } 986 return success; 987 } 988 989 // const_iterator mimics NXMapState and its code comes from NXInitMapState 990 // and NXNextMapState. 991 typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element; 992 993 friend class const_iterator; 994 class const_iterator { 995 public: 996 const_iterator(RemoteNXMapTable &parent, int index) 997 : m_parent(parent), m_index(index) { 998 AdvanceToValidIndex(); 999 } 1000 1001 const_iterator(const const_iterator &rhs) 1002 : m_parent(rhs.m_parent), m_index(rhs.m_index) { 1003 // AdvanceToValidIndex() has been called by rhs already. 1004 } 1005 1006 const_iterator &operator=(const const_iterator &rhs) { 1007 // AdvanceToValidIndex() has been called by rhs already. 1008 assert(&m_parent == &rhs.m_parent); 1009 m_index = rhs.m_index; 1010 return *this; 1011 } 1012 1013 bool operator==(const const_iterator &rhs) const { 1014 if (&m_parent != &rhs.m_parent) 1015 return false; 1016 if (m_index != rhs.m_index) 1017 return false; 1018 1019 return true; 1020 } 1021 1022 bool operator!=(const const_iterator &rhs) const { 1023 return !(operator==(rhs)); 1024 } 1025 1026 const_iterator &operator++() { 1027 AdvanceToValidIndex(); 1028 return *this; 1029 } 1030 1031 const element operator*() const { 1032 if (m_index == -1) { 1033 // TODO find a way to make this an error, but not an assert 1034 return element(); 1035 } 1036 1037 lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; 1038 size_t map_pair_size = m_parent.m_map_pair_size; 1039 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); 1040 1041 Status err; 1042 1043 lldb::addr_t key = 1044 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); 1045 if (!err.Success()) 1046 return element(); 1047 lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory( 1048 pair_ptr + m_parent.m_process->GetAddressByteSize(), err); 1049 if (!err.Success()) 1050 return element(); 1051 1052 std::string key_string; 1053 1054 m_parent.m_process->ReadCStringFromMemory(key, key_string, err); 1055 if (!err.Success()) 1056 return element(); 1057 1058 return element(ConstString(key_string.c_str()), 1059 (ObjCLanguageRuntime::ObjCISA)value); 1060 } 1061 1062 private: 1063 void AdvanceToValidIndex() { 1064 if (m_index == -1) 1065 return; 1066 1067 const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; 1068 const size_t map_pair_size = m_parent.m_map_pair_size; 1069 const lldb::addr_t invalid_key = m_parent.m_invalid_key; 1070 Status err; 1071 1072 while (m_index--) { 1073 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); 1074 lldb::addr_t key = 1075 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); 1076 1077 if (!err.Success()) { 1078 m_index = -1; 1079 return; 1080 } 1081 1082 if (key != invalid_key) 1083 return; 1084 } 1085 } 1086 RemoteNXMapTable &m_parent; 1087 int m_index; 1088 }; 1089 1090 const_iterator begin() { 1091 return const_iterator(*this, m_num_buckets_minus_one + 1); 1092 } 1093 1094 const_iterator end() { return m_end_iterator; } 1095 1096 uint32_t GetCount() const { return m_count; } 1097 1098 uint32_t GetBucketCount() const { return m_num_buckets_minus_one; } 1099 1100 lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; } 1101 1102 lldb::addr_t GetTableLoadAddress() const { return m_load_addr; } 1103 1104private: 1105 // contents of _NXMapTable struct 1106 uint32_t m_count; 1107 uint32_t m_num_buckets_minus_one; 1108 lldb::addr_t m_buckets_ptr; 1109 lldb_private::Process *m_process; 1110 const_iterator m_end_iterator; 1111 lldb::addr_t m_load_addr; 1112 size_t m_map_pair_size; 1113 lldb::addr_t m_invalid_key; 1114}; 1115 1116AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() 1117 : m_count(0), m_num_buckets(0), m_buckets_ptr(0) {} 1118 1119void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature( 1120 const RemoteNXMapTable &hash_table) { 1121 m_count = hash_table.GetCount(); 1122 m_num_buckets = hash_table.GetBucketCount(); 1123 m_buckets_ptr = hash_table.GetBucketDataPointer(); 1124} 1125 1126bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate( 1127 Process *process, AppleObjCRuntimeV2 *runtime, 1128 RemoteNXMapTable &hash_table) { 1129 if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) { 1130 return false; // Failed to parse the header, no need to update anything 1131 } 1132 1133 // Check with out current signature and return true if the count, number of 1134 // buckets or the hash table address changes. 1135 if (m_count == hash_table.GetCount() && 1136 m_num_buckets == hash_table.GetBucketCount() && 1137 m_buckets_ptr == hash_table.GetBucketDataPointer()) { 1138 // Hash table hasn't changed 1139 return false; 1140 } 1141 // Hash table data has changed, we need to update 1142 return true; 1143} 1144 1145ObjCLanguageRuntime::ClassDescriptorSP 1146AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) { 1147 ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp; 1148 if (m_non_pointer_isa_cache_ap.get()) 1149 class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa); 1150 if (!class_descriptor_sp) 1151 class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa); 1152 return class_descriptor_sp; 1153} 1154 1155ObjCLanguageRuntime::ClassDescriptorSP 1156AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) { 1157 ClassDescriptorSP objc_class_sp; 1158 if (valobj.IsBaseClass()) { 1159 ValueObject *parent = valobj.GetParent(); 1160 // if I am my own parent, bail out of here fast.. 1161 if (parent && parent != &valobj) { 1162 ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent); 1163 if (parent_descriptor_sp) 1164 return parent_descriptor_sp->GetSuperclass(); 1165 } 1166 return nullptr; 1167 } 1168 // if we get an invalid VO (which might still happen when playing around with 1169 // pointers returned by the expression parser, don't consider this a valid 1170 // ObjC object) 1171 if (valobj.GetCompilerType().IsValid()) { 1172 addr_t isa_pointer = valobj.GetPointerValue(); 1173 1174 // tagged pointer 1175 if (IsTaggedPointer(isa_pointer)) { 1176 return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer); 1177 } else { 1178 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 1179 1180 Process *process = exe_ctx.GetProcessPtr(); 1181 if (process) { 1182 Status error; 1183 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 1184 if (isa != LLDB_INVALID_ADDRESS) { 1185 objc_class_sp = GetClassDescriptorFromISA(isa); 1186 if (isa && !objc_class_sp) { 1187 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 1188 if (log) 1189 log->Printf("0x%" PRIx64 1190 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was " 1191 "not in class descriptor cache 0x%" PRIx64, 1192 isa_pointer, isa); 1193 } 1194 } 1195 } 1196 } 1197 } 1198 return objc_class_sp; 1199} 1200 1201lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() { 1202 if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS) 1203 return m_tagged_pointer_obfuscator; 1204 1205 1206 Process *process = GetProcess(); 1207 ModuleSP objc_module_sp(GetObjCModule()); 1208 1209 if (!objc_module_sp) 1210 return LLDB_INVALID_ADDRESS; 1211 1212 static ConstString g_gdb_objc_obfuscator("objc_debug_taggedpointer_obfuscator"); 1213 1214 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( 1215 g_gdb_objc_obfuscator, lldb::eSymbolTypeAny); 1216 if (symbol) { 1217 lldb::addr_t g_gdb_obj_obfuscator_ptr = 1218 symbol->GetLoadAddress(&process->GetTarget()); 1219 1220 if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) { 1221 Status error; 1222 m_tagged_pointer_obfuscator = process->ReadPointerFromMemory( 1223 g_gdb_obj_obfuscator_ptr, error); 1224 } 1225 } 1226 // If we don't have a correct value at this point, there must be no obfuscation. 1227 if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS) 1228 m_tagged_pointer_obfuscator = 0; 1229 1230 return m_tagged_pointer_obfuscator; 1231} 1232 1233lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() { 1234 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) { 1235 Process *process = GetProcess(); 1236 1237 ModuleSP objc_module_sp(GetObjCModule()); 1238 1239 if (!objc_module_sp) 1240 return LLDB_INVALID_ADDRESS; 1241 1242 static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes"); 1243 1244 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType( 1245 g_gdb_objc_realized_classes, lldb::eSymbolTypeAny); 1246 if (symbol) { 1247 lldb::addr_t gdb_objc_realized_classes_ptr = 1248 symbol->GetLoadAddress(&process->GetTarget()); 1249 1250 if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) { 1251 Status error; 1252 m_isa_hash_table_ptr = process->ReadPointerFromMemory( 1253 gdb_objc_realized_classes_ptr, error); 1254 } 1255 } 1256 } 1257 return m_isa_hash_table_ptr; 1258} 1259 1260AppleObjCRuntimeV2::DescriptorMapUpdateResult 1261AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic( 1262 RemoteNXMapTable &hash_table) { 1263 Process *process = GetProcess(); 1264 1265 if (process == NULL) 1266 return DescriptorMapUpdateResult::Fail(); 1267 1268 uint32_t num_class_infos = 0; 1269 1270 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); 1271 1272 ExecutionContext exe_ctx; 1273 1274 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 1275 1276 if (!thread_sp) 1277 return DescriptorMapUpdateResult::Fail(); 1278 1279 thread_sp->CalculateExecutionContext(exe_ctx); 1280 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1281 1282 if (!ast) 1283 return DescriptorMapUpdateResult::Fail(); 1284 1285 Address function_address; 1286 1287 DiagnosticManager diagnostics; 1288 1289 const uint32_t addr_size = process->GetAddressByteSize(); 1290 1291 Status err; 1292 1293 // Read the total number of classes from the hash table 1294 const uint32_t num_classes = hash_table.GetCount(); 1295 if (num_classes == 0) { 1296 if (log) 1297 log->Printf("No dynamic classes found in gdb_objc_realized_classes."); 1298 return DescriptorMapUpdateResult::Success(0); 1299 } 1300 1301 // Make some types for our arguments 1302 CompilerType clang_uint32_t_type = 1303 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); 1304 CompilerType clang_void_pointer_type = 1305 ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1306 1307 ValueList arguments; 1308 FunctionCaller *get_class_info_function = nullptr; 1309 1310 if (!m_get_class_info_code.get()) { 1311 Status error; 1312 m_get_class_info_code.reset(GetTargetRef().GetUtilityFunctionForLanguage( 1313 g_get_dynamic_class_info_body, eLanguageTypeObjC, 1314 g_get_dynamic_class_info_name, error)); 1315 if (error.Fail()) { 1316 if (log) 1317 log->Printf( 1318 "Failed to get Utility Function for implementation lookup: %s", 1319 error.AsCString()); 1320 m_get_class_info_code.reset(); 1321 } else { 1322 diagnostics.Clear(); 1323 1324 if (!m_get_class_info_code->Install(diagnostics, exe_ctx)) { 1325 if (log) { 1326 log->Printf("Failed to install implementation lookup"); 1327 diagnostics.Dump(log); 1328 } 1329 m_get_class_info_code.reset(); 1330 } 1331 } 1332 if (!m_get_class_info_code.get()) 1333 return DescriptorMapUpdateResult::Fail(); 1334 1335 // Next make the runner function for our implementation utility function. 1336 Value value; 1337 value.SetValueType(Value::eValueTypeScalar); 1338 value.SetCompilerType(clang_void_pointer_type); 1339 arguments.PushValue(value); 1340 arguments.PushValue(value); 1341 1342 value.SetValueType(Value::eValueTypeScalar); 1343 value.SetCompilerType(clang_uint32_t_type); 1344 arguments.PushValue(value); 1345 arguments.PushValue(value); 1346 1347 get_class_info_function = m_get_class_info_code->MakeFunctionCaller( 1348 clang_uint32_t_type, arguments, thread_sp, error); 1349 1350 if (error.Fail()) { 1351 if (log) 1352 log->Printf( 1353 "Failed to make function caller for implementation lookup: %s.", 1354 error.AsCString()); 1355 return DescriptorMapUpdateResult::Fail(); 1356 } 1357 } else { 1358 get_class_info_function = m_get_class_info_code->GetFunctionCaller(); 1359 if (!get_class_info_function) { 1360 if (log) { 1361 log->Printf("Failed to get implementation lookup function caller."); 1362 diagnostics.Dump(log); 1363 } 1364 1365 return DescriptorMapUpdateResult::Fail(); 1366 } 1367 arguments = get_class_info_function->GetArgumentValues(); 1368 } 1369 1370 diagnostics.Clear(); 1371 1372 const uint32_t class_info_byte_size = addr_size + 4; 1373 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; 1374 lldb::addr_t class_infos_addr = process->AllocateMemory( 1375 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err); 1376 1377 if (class_infos_addr == LLDB_INVALID_ADDRESS) { 1378 if (log) 1379 log->Printf("unable to allocate %" PRIu32 1380 " bytes in process for shared cache read", 1381 class_infos_byte_size); 1382 return DescriptorMapUpdateResult::Fail(); 1383 } 1384 1385 std::lock_guard<std::mutex> guard(m_get_class_info_args_mutex); 1386 1387 // Fill in our function argument values 1388 arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress(); 1389 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; 1390 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; 1391 1392 // Only dump the runtime classes from the expression evaluation if the log is 1393 // verbose: 1394 Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); 1395 bool dump_log = type_log && type_log->GetVerbose(); 1396 1397 arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0; 1398 1399 bool success = false; 1400 1401 diagnostics.Clear(); 1402 1403 // Write our function arguments into the process so we can run our function 1404 if (get_class_info_function->WriteFunctionArguments( 1405 exe_ctx, m_get_class_info_args, arguments, diagnostics)) { 1406 EvaluateExpressionOptions options; 1407 options.SetUnwindOnError(true); 1408 options.SetTryAllThreads(false); 1409 options.SetStopOthers(true); 1410 options.SetIgnoreBreakpoints(true); 1411 options.SetTimeout(g_utility_function_timeout); 1412 1413 Value return_value; 1414 return_value.SetValueType(Value::eValueTypeScalar); 1415 // return_value.SetContext (Value::eContextTypeClangType, 1416 // clang_uint32_t_type); 1417 return_value.SetCompilerType(clang_uint32_t_type); 1418 return_value.GetScalar() = 0; 1419 1420 diagnostics.Clear(); 1421 1422 // Run the function 1423 ExpressionResults results = get_class_info_function->ExecuteFunction( 1424 exe_ctx, &m_get_class_info_args, options, diagnostics, return_value); 1425 1426 if (results == eExpressionCompleted) { 1427 // The result is the number of ClassInfo structures that were filled in 1428 num_class_infos = return_value.GetScalar().ULong(); 1429 if (log) 1430 log->Printf("Discovered %u ObjC classes\n", num_class_infos); 1431 if (num_class_infos > 0) { 1432 // Read the ClassInfo structures 1433 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); 1434 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), 1435 buffer.GetByteSize(), 1436 err) == buffer.GetByteSize()) { 1437 DataExtractor class_infos_data(buffer.GetBytes(), 1438 buffer.GetByteSize(), 1439 process->GetByteOrder(), addr_size); 1440 ParseClassInfoArray(class_infos_data, num_class_infos); 1441 } 1442 } 1443 success = true; 1444 } else { 1445 if (log) { 1446 log->Printf("Error evaluating our find class name function."); 1447 diagnostics.Dump(log); 1448 } 1449 } 1450 } else { 1451 if (log) { 1452 log->Printf("Error writing function arguments."); 1453 diagnostics.Dump(log); 1454 } 1455 } 1456 1457 // Deallocate the memory we allocated for the ClassInfo array 1458 process->DeallocateMemory(class_infos_addr); 1459 1460 return DescriptorMapUpdateResult(success, num_class_infos); 1461} 1462 1463uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data, 1464 uint32_t num_class_infos) { 1465 // Parses an array of "num_class_infos" packed ClassInfo structures: 1466 // 1467 // struct ClassInfo 1468 // { 1469 // Class isa; 1470 // uint32_t hash; 1471 // } __attribute__((__packed__)); 1472 1473 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); 1474 bool should_log = log && log->GetVerbose(); 1475 1476 uint32_t num_parsed = 0; 1477 1478 // Iterate through all ClassInfo structures 1479 lldb::offset_t offset = 0; 1480 for (uint32_t i = 0; i < num_class_infos; ++i) { 1481 ObjCISA isa = data.GetPointer(&offset); 1482 1483 if (isa == 0) { 1484 if (should_log) 1485 log->Printf( 1486 "AppleObjCRuntimeV2 found NULL isa, ignoring this class info"); 1487 continue; 1488 } 1489 // Check if we already know about this ISA, if we do, the info will never 1490 // change, so we can just skip it. 1491 if (ISAIsCached(isa)) { 1492 if (should_log) 1493 log->Printf("AppleObjCRuntimeV2 found cached isa=0x%" PRIx64 1494 ", ignoring this class info", 1495 isa); 1496 offset += 4; 1497 } else { 1498 // Read the 32 bit hash for the class name 1499 const uint32_t name_hash = data.GetU32(&offset); 1500 ClassDescriptorSP descriptor_sp(new ClassDescriptorV2(*this, isa, NULL)); 1501 AddClass(isa, descriptor_sp, name_hash); 1502 num_parsed++; 1503 if (should_log) 1504 log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 1505 ", hash=0x%8.8x, name=%s", 1506 isa, name_hash, 1507 descriptor_sp->GetClassName().AsCString("<unknown>")); 1508 } 1509 } 1510 if (should_log) 1511 log->Printf("AppleObjCRuntimeV2 parsed %" PRIu32 " class infos", 1512 num_parsed); 1513 return num_parsed; 1514} 1515 1516AppleObjCRuntimeV2::DescriptorMapUpdateResult 1517AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() { 1518 Process *process = GetProcess(); 1519 1520 if (process == NULL) 1521 return DescriptorMapUpdateResult::Fail(); 1522 1523 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); 1524 1525 ExecutionContext exe_ctx; 1526 1527 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread(); 1528 1529 if (!thread_sp) 1530 return DescriptorMapUpdateResult::Fail(); 1531 1532 thread_sp->CalculateExecutionContext(exe_ctx); 1533 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1534 1535 if (!ast) 1536 return DescriptorMapUpdateResult::Fail(); 1537 1538 Address function_address; 1539 1540 DiagnosticManager diagnostics; 1541 1542 const uint32_t addr_size = process->GetAddressByteSize(); 1543 1544 Status err; 1545 1546 uint32_t num_class_infos = 0; 1547 1548 const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress(); 1549 1550 if (objc_opt_ptr == LLDB_INVALID_ADDRESS) 1551 return DescriptorMapUpdateResult::Fail(); 1552 1553 const uint32_t num_classes = 128 * 1024; 1554 1555 // Make some types for our arguments 1556 CompilerType clang_uint32_t_type = 1557 ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); 1558 CompilerType clang_void_pointer_type = 1559 ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1560 1561 ValueList arguments; 1562 FunctionCaller *get_shared_cache_class_info_function = nullptr; 1563 1564 if (!m_get_shared_cache_class_info_code.get()) { 1565 Status error; 1566 m_get_shared_cache_class_info_code.reset( 1567 GetTargetRef().GetUtilityFunctionForLanguage( 1568 g_get_shared_cache_class_info_body, eLanguageTypeObjC, 1569 g_get_shared_cache_class_info_name, error)); 1570 if (error.Fail()) { 1571 if (log) 1572 log->Printf( 1573 "Failed to get Utility function for implementation lookup: %s.", 1574 error.AsCString()); 1575 m_get_shared_cache_class_info_code.reset(); 1576 } else { 1577 diagnostics.Clear(); 1578 1579 if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx)) { 1580 if (log) { 1581 log->Printf("Failed to install implementation lookup."); 1582 diagnostics.Dump(log); 1583 } 1584 m_get_shared_cache_class_info_code.reset(); 1585 } 1586 } 1587 1588 if (!m_get_shared_cache_class_info_code.get()) 1589 return DescriptorMapUpdateResult::Fail(); 1590 1591 // Next make the function caller for our implementation utility function. 1592 Value value; 1593 value.SetValueType(Value::eValueTypeScalar); 1594 // value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); 1595 value.SetCompilerType(clang_void_pointer_type); 1596 arguments.PushValue(value); 1597 arguments.PushValue(value); 1598 1599 value.SetValueType(Value::eValueTypeScalar); 1600 // value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); 1601 value.SetCompilerType(clang_uint32_t_type); 1602 arguments.PushValue(value); 1603 arguments.PushValue(value); 1604 1605 get_shared_cache_class_info_function = 1606 m_get_shared_cache_class_info_code->MakeFunctionCaller( 1607 clang_uint32_t_type, arguments, thread_sp, error); 1608 1609 if (get_shared_cache_class_info_function == nullptr) 1610 return DescriptorMapUpdateResult::Fail(); 1611 1612 } else { 1613 get_shared_cache_class_info_function = 1614 m_get_shared_cache_class_info_code->GetFunctionCaller(); 1615 if (get_shared_cache_class_info_function == nullptr) 1616 return DescriptorMapUpdateResult::Fail(); 1617 arguments = get_shared_cache_class_info_function->GetArgumentValues(); 1618 } 1619 1620 diagnostics.Clear(); 1621 1622 const uint32_t class_info_byte_size = addr_size + 4; 1623 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; 1624 lldb::addr_t class_infos_addr = process->AllocateMemory( 1625 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err); 1626 1627 if (class_infos_addr == LLDB_INVALID_ADDRESS) { 1628 if (log) 1629 log->Printf("unable to allocate %" PRIu32 1630 " bytes in process for shared cache read", 1631 class_infos_byte_size); 1632 return DescriptorMapUpdateResult::Fail(); 1633 } 1634 1635 std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex); 1636 1637 // Fill in our function argument values 1638 arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; 1639 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; 1640 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; 1641 // Only dump the runtime classes from the expression evaluation if the log is 1642 // verbose: 1643 Log *type_log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES); 1644 bool dump_log = type_log && type_log->GetVerbose(); 1645 1646 arguments.GetValueAtIndex(3)->GetScalar() = dump_log ? 1 : 0; 1647 1648 bool success = false; 1649 1650 diagnostics.Clear(); 1651 1652 // Write our function arguments into the process so we can run our function 1653 if (get_shared_cache_class_info_function->WriteFunctionArguments( 1654 exe_ctx, m_get_shared_cache_class_info_args, arguments, 1655 diagnostics)) { 1656 EvaluateExpressionOptions options; 1657 options.SetUnwindOnError(true); 1658 options.SetTryAllThreads(false); 1659 options.SetStopOthers(true); 1660 options.SetIgnoreBreakpoints(true); 1661 options.SetTimeout(g_utility_function_timeout); 1662 1663 Value return_value; 1664 return_value.SetValueType(Value::eValueTypeScalar); 1665 // return_value.SetContext (Value::eContextTypeClangType, 1666 // clang_uint32_t_type); 1667 return_value.SetCompilerType(clang_uint32_t_type); 1668 return_value.GetScalar() = 0; 1669 1670 diagnostics.Clear(); 1671 1672 // Run the function 1673 ExpressionResults results = 1674 get_shared_cache_class_info_function->ExecuteFunction( 1675 exe_ctx, &m_get_shared_cache_class_info_args, options, diagnostics, 1676 return_value); 1677 1678 if (results == eExpressionCompleted) { 1679 // The result is the number of ClassInfo structures that were filled in 1680 num_class_infos = return_value.GetScalar().ULong(); 1681 if (log) 1682 log->Printf("Discovered %u ObjC classes in shared cache\n", 1683 num_class_infos); 1684#ifdef LLDB_CONFIGURATION_DEBUG 1685 assert(num_class_infos <= num_classes); 1686#endif 1687 if (num_class_infos > 0) { 1688 if (num_class_infos > num_classes) { 1689 num_class_infos = num_classes; 1690 1691 success = false; 1692 } else { 1693 success = true; 1694 } 1695 1696 // Read the ClassInfo structures 1697 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0); 1698 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), 1699 buffer.GetByteSize(), 1700 err) == buffer.GetByteSize()) { 1701 DataExtractor class_infos_data(buffer.GetBytes(), 1702 buffer.GetByteSize(), 1703 process->GetByteOrder(), addr_size); 1704 1705 ParseClassInfoArray(class_infos_data, num_class_infos); 1706 } 1707 } else { 1708 success = true; 1709 } 1710 } else { 1711 if (log) { 1712 log->Printf("Error evaluating our find class name function."); 1713 diagnostics.Dump(log); 1714 } 1715 } 1716 } else { 1717 if (log) { 1718 log->Printf("Error writing function arguments."); 1719 diagnostics.Dump(log); 1720 } 1721 } 1722 1723 // Deallocate the memory we allocated for the ClassInfo array 1724 process->DeallocateMemory(class_infos_addr); 1725 1726 return DescriptorMapUpdateResult(success, num_class_infos); 1727} 1728 1729bool AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory( 1730 RemoteNXMapTable &hash_table) { 1731 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); 1732 1733 Process *process = GetProcess(); 1734 1735 if (process == NULL) 1736 return false; 1737 1738 uint32_t num_map_table_isas = 0; 1739 1740 ModuleSP objc_module_sp(GetObjCModule()); 1741 1742 if (objc_module_sp) { 1743 for (RemoteNXMapTable::element elt : hash_table) { 1744 ++num_map_table_isas; 1745 1746 if (ISAIsCached(elt.second)) 1747 continue; 1748 1749 ClassDescriptorSP descriptor_sp = ClassDescriptorSP( 1750 new ClassDescriptorV2(*this, elt.second, elt.first.AsCString())); 1751 1752 if (log && log->GetVerbose()) 1753 log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 1754 " (%s) from dynamic table to isa->descriptor cache", 1755 elt.second, elt.first.AsCString()); 1756 1757 AddClass(elt.second, descriptor_sp, elt.first.AsCString()); 1758 } 1759 } 1760 1761 return num_map_table_isas > 0; 1762} 1763 1764lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() { 1765 Process *process = GetProcess(); 1766 1767 if (process) { 1768 ModuleSP objc_module_sp(GetObjCModule()); 1769 1770 if (objc_module_sp) { 1771 ObjectFile *objc_object = objc_module_sp->GetObjectFile(); 1772 1773 if (objc_object) { 1774 SectionList *section_list = objc_module_sp->GetSectionList(); 1775 1776 if (section_list) { 1777 SectionSP text_segment_sp( 1778 section_list->FindSectionByName(ConstString("__TEXT"))); 1779 1780 if (text_segment_sp) { 1781 SectionSP objc_opt_section_sp( 1782 text_segment_sp->GetChildren().FindSectionByName( 1783 ConstString("__objc_opt_ro"))); 1784 1785 if (objc_opt_section_sp) { 1786 return objc_opt_section_sp->GetLoadBaseAddress( 1787 &process->GetTarget()); 1788 } 1789 } 1790 } 1791 } 1792 } 1793 } 1794 return LLDB_INVALID_ADDRESS; 1795} 1796 1797void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() { 1798 Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TYPES)); 1799 1800 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 1801 Timer scoped_timer(func_cat, LLVM_PRETTY_FUNCTION); 1802 1803 // Else we need to check with our process to see when the map was updated. 1804 Process *process = GetProcess(); 1805 1806 if (process) { 1807 RemoteNXMapTable hash_table; 1808 1809 // Update the process stop ID that indicates the last time we updated the 1810 // map, whether it was successful or not. 1811 m_isa_to_descriptor_stop_id = process->GetStopID(); 1812 1813 if (!m_hash_signature.NeedsUpdate(process, this, hash_table)) 1814 return; 1815 1816 m_hash_signature.UpdateSignature(hash_table); 1817 1818 // Grab the dynamically loaded objc classes from the hash table in memory 1819 DescriptorMapUpdateResult dynamic_update_result = 1820 UpdateISAToDescriptorMapDynamic(hash_table); 1821 1822 // Now get the objc classes that are baked into the Objective-C runtime in 1823 // the shared cache, but only once per process as this data never changes 1824 if (!m_loaded_objc_opt) { 1825 // it is legitimately possible for the shared cache to be empty - in that 1826 // case, the dynamic hash table will contain all the class information we 1827 // need; the situation we're trying to detect is one where we aren't 1828 // seeing class information from the runtime - in order to detect that 1829 // vs. just the shared cache being empty or sparsely populated, we set an 1830 // arbitrary (very low) threshold for the number of classes that we want 1831 // to see in a "good" scenario - anything below that is suspicious 1832 // (Foundation alone has thousands of classes) 1833 const uint32_t num_classes_to_warn_at = 500; 1834 1835 DescriptorMapUpdateResult shared_cache_update_result = 1836 UpdateISAToDescriptorMapSharedCache(); 1837 1838 if (log) 1839 log->Printf("attempted to read objc class data - results: " 1840 "[dynamic_update]: ran: %s, count: %" PRIu32 1841 " [shared_cache_update]: ran: %s, count: %" PRIu32, 1842 dynamic_update_result.m_update_ran ? "yes" : "no", 1843 dynamic_update_result.m_num_found, 1844 shared_cache_update_result.m_update_ran ? "yes" : "no", 1845 shared_cache_update_result.m_num_found); 1846 1847 // warn if: 1848 // - we could not run either expression 1849 // - we found fewer than num_classes_to_warn_at classes total 1850 if ((false == shared_cache_update_result.m_update_ran) || 1851 (false == dynamic_update_result.m_update_ran)) 1852 WarnIfNoClassesCached( 1853 SharedCacheWarningReason::eExpressionExecutionFailure); 1854 else if (dynamic_update_result.m_num_found + 1855 shared_cache_update_result.m_num_found < 1856 num_classes_to_warn_at) 1857 WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead); 1858 else 1859 m_loaded_objc_opt = true; 1860 } 1861 } else { 1862 m_isa_to_descriptor_stop_id = UINT32_MAX; 1863 } 1864} 1865 1866static bool DoesProcessHaveSharedCache(Process &process) { 1867 PlatformSP platform_sp = process.GetTarget().GetPlatform(); 1868 if (!platform_sp) 1869 return true; // this should not happen 1870 1871 ConstString platform_plugin_name = platform_sp->GetPluginName(); 1872 if (platform_plugin_name) { 1873 llvm::StringRef platform_plugin_name_sr = 1874 platform_plugin_name.GetStringRef(); 1875 if (platform_plugin_name_sr.endswith("-simulator")) 1876 return false; 1877 } 1878 1879 return true; 1880} 1881 1882void AppleObjCRuntimeV2::WarnIfNoClassesCached( 1883 SharedCacheWarningReason reason) { 1884 if (m_noclasses_warning_emitted) 1885 return; 1886 1887 if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) { 1888 // Simulators do not have the objc_opt_ro class table so don't actually 1889 // complain to the user 1890 m_noclasses_warning_emitted = true; 1891 return; 1892 } 1893 1894 Debugger &debugger(GetProcess()->GetTarget().GetDebugger()); 1895 if (auto stream = debugger.GetAsyncOutputStream()) { 1896 switch (reason) { 1897 case SharedCacheWarningReason::eNotEnoughClassesRead: 1898 stream->PutCString("warning: could not find Objective-C class data in " 1899 "the process. This may reduce the quality of type " 1900 "information available.\n"); 1901 m_noclasses_warning_emitted = true; 1902 break; 1903 case SharedCacheWarningReason::eExpressionExecutionFailure: 1904 stream->PutCString("warning: could not execute support code to read " 1905 "Objective-C class data in the process. This may " 1906 "reduce the quality of type information available.\n"); 1907 m_noclasses_warning_emitted = true; 1908 break; 1909 } 1910 } 1911} 1912 1913ConstString 1914AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { 1915 if (isa == g_objc_Tagged_ISA) { 1916 static const ConstString g_objc_tagged_isa_name("_lldb_Tagged_ObjC_ISA"); 1917 return g_objc_tagged_isa_name; 1918 } 1919 if (isa == g_objc_Tagged_ISA_NSAtom) { 1920 static const ConstString g_objc_tagged_isa_nsatom_name("NSAtom"); 1921 return g_objc_tagged_isa_nsatom_name; 1922 } 1923 if (isa == g_objc_Tagged_ISA_NSNumber) { 1924 static const ConstString g_objc_tagged_isa_nsnumber_name("NSNumber"); 1925 return g_objc_tagged_isa_nsnumber_name; 1926 } 1927 if (isa == g_objc_Tagged_ISA_NSDateTS) { 1928 static const ConstString g_objc_tagged_isa_nsdatets_name("NSDateTS"); 1929 return g_objc_tagged_isa_nsdatets_name; 1930 } 1931 if (isa == g_objc_Tagged_ISA_NSManagedObject) { 1932 static const ConstString g_objc_tagged_isa_nsmanagedobject_name( 1933 "NSManagedObject"); 1934 return g_objc_tagged_isa_nsmanagedobject_name; 1935 } 1936 if (isa == g_objc_Tagged_ISA_NSDate) { 1937 static const ConstString g_objc_tagged_isa_nsdate_name("NSDate"); 1938 return g_objc_tagged_isa_nsdate_name; 1939 } 1940 return ObjCLanguageRuntime::GetActualTypeName(isa); 1941} 1942 1943DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() { 1944 if (!m_decl_vendor_ap.get()) 1945 m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this)); 1946 1947 return m_decl_vendor_ap.get(); 1948} 1949 1950lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(const ConstString &name) { 1951 lldb::addr_t ret = LLDB_INVALID_ADDRESS; 1952 1953 const char *name_cstr = name.AsCString(); 1954 1955 if (name_cstr) { 1956 llvm::StringRef name_strref(name_cstr); 1957 1958 static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_"); 1959 static const llvm::StringRef class_prefix("OBJC_CLASS_$_"); 1960 1961 if (name_strref.startswith(ivar_prefix)) { 1962 llvm::StringRef ivar_skipped_prefix = 1963 name_strref.substr(ivar_prefix.size()); 1964 std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = 1965 ivar_skipped_prefix.split('.'); 1966 1967 if (class_and_ivar.first.size() && class_and_ivar.second.size()) { 1968 const ConstString class_name_cs(class_and_ivar.first); 1969 ClassDescriptorSP descriptor = 1970 ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs); 1971 1972 if (descriptor) { 1973 const ConstString ivar_name_cs(class_and_ivar.second); 1974 const char *ivar_name_cstr = ivar_name_cs.AsCString(); 1975 1976 auto ivar_func = [&ret, ivar_name_cstr]( 1977 const char *name, const char *type, lldb::addr_t offset_addr, 1978 uint64_t size) -> lldb::addr_t { 1979 if (!strcmp(name, ivar_name_cstr)) { 1980 ret = offset_addr; 1981 return true; 1982 } 1983 return false; 1984 }; 1985 1986 descriptor->Describe( 1987 std::function<void(ObjCISA)>(nullptr), 1988 std::function<bool(const char *, const char *)>(nullptr), 1989 std::function<bool(const char *, const char *)>(nullptr), 1990 ivar_func); 1991 } 1992 } 1993 } else if (name_strref.startswith(class_prefix)) { 1994 llvm::StringRef class_skipped_prefix = 1995 name_strref.substr(class_prefix.size()); 1996 const ConstString class_name_cs(class_skipped_prefix); 1997 ClassDescriptorSP descriptor = 1998 GetClassDescriptorFromClassName(class_name_cs); 1999 2000 if (descriptor) 2001 ret = descriptor->GetISA(); 2002 } 2003 } 2004 2005 return ret; 2006} 2007 2008AppleObjCRuntimeV2::NonPointerISACache * 2009AppleObjCRuntimeV2::NonPointerISACache::CreateInstance( 2010 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) { 2011 Process *process(runtime.GetProcess()); 2012 2013 Status error; 2014 2015 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); 2016 2017 auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol( 2018 process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error); 2019 if (error.Fail()) 2020 return NULL; 2021 2022 auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol( 2023 process, ConstString("objc_debug_isa_magic_value"), objc_module_sp, 2024 error); 2025 if (error.Fail()) 2026 return NULL; 2027 2028 auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol( 2029 process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error); 2030 if (error.Fail()) 2031 return NULL; 2032 2033 if (log) 2034 log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks"); 2035 2036 bool foundError = false; 2037 auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol( 2038 process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp, 2039 error); 2040 foundError |= error.Fail(); 2041 2042 auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol( 2043 process, ConstString("objc_debug_indexed_isa_magic_value"), 2044 objc_module_sp, error); 2045 foundError |= error.Fail(); 2046 2047 auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol( 2048 process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp, 2049 error); 2050 foundError |= error.Fail(); 2051 2052 auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol( 2053 process, ConstString("objc_debug_indexed_isa_index_shift"), 2054 objc_module_sp, error); 2055 foundError |= error.Fail(); 2056 2057 auto objc_indexed_classes = 2058 ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"), 2059 objc_module_sp, error, false); 2060 foundError |= error.Fail(); 2061 2062 if (log) 2063 log->PutCString("AOCRT::NPI: Found all the indexed ISA masks"); 2064 2065 // we might want to have some rules to outlaw these other values (e.g if the 2066 // mask is zero but the value is non-zero, ...) 2067 2068 return new NonPointerISACache( 2069 runtime, objc_module_sp, objc_debug_isa_class_mask, 2070 objc_debug_isa_magic_mask, objc_debug_isa_magic_value, 2071 objc_debug_indexed_isa_magic_mask, objc_debug_indexed_isa_magic_value, 2072 objc_debug_indexed_isa_index_mask, objc_debug_indexed_isa_index_shift, 2073 foundError ? 0 : objc_indexed_classes); 2074} 2075 2076AppleObjCRuntimeV2::TaggedPointerVendorV2 * 2077AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance( 2078 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) { 2079 Process *process(runtime.GetProcess()); 2080 2081 Status error; 2082 2083 auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol( 2084 process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp, 2085 error); 2086 if (error.Fail()) 2087 return new TaggedPointerVendorLegacy(runtime); 2088 2089 auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol( 2090 process, ConstString("objc_debug_taggedpointer_slot_shift"), 2091 objc_module_sp, error, true, 4); 2092 if (error.Fail()) 2093 return new TaggedPointerVendorLegacy(runtime); 2094 2095 auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol( 2096 process, ConstString("objc_debug_taggedpointer_slot_mask"), 2097 objc_module_sp, error, true, 4); 2098 if (error.Fail()) 2099 return new TaggedPointerVendorLegacy(runtime); 2100 2101 auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol( 2102 process, ConstString("objc_debug_taggedpointer_payload_lshift"), 2103 objc_module_sp, error, true, 4); 2104 if (error.Fail()) 2105 return new TaggedPointerVendorLegacy(runtime); 2106 2107 auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol( 2108 process, ConstString("objc_debug_taggedpointer_payload_rshift"), 2109 objc_module_sp, error, true, 4); 2110 if (error.Fail()) 2111 return new TaggedPointerVendorLegacy(runtime); 2112 2113 auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol( 2114 process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp, 2115 error, false); 2116 if (error.Fail()) 2117 return new TaggedPointerVendorLegacy(runtime); 2118 2119 // try to detect the "extended tagged pointer" variables - if any are 2120 // missing, use the non-extended vendor 2121 do { 2122 auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol( 2123 process, ConstString("objc_debug_taggedpointer_ext_mask"), 2124 objc_module_sp, error); 2125 if (error.Fail()) 2126 break; 2127 2128 auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol( 2129 process, ConstString("objc_debug_taggedpointer_ext_slot_shift"), 2130 objc_module_sp, error, true, 4); 2131 if (error.Fail()) 2132 break; 2133 2134 auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol( 2135 process, ConstString("objc_debug_taggedpointer_ext_slot_mask"), 2136 objc_module_sp, error, true, 4); 2137 if (error.Fail()) 2138 break; 2139 2140 auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol( 2141 process, ConstString("objc_debug_taggedpointer_ext_classes"), 2142 objc_module_sp, error, false); 2143 if (error.Fail()) 2144 break; 2145 2146 auto objc_debug_taggedpointer_ext_payload_lshift = 2147 ExtractRuntimeGlobalSymbol( 2148 process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"), 2149 objc_module_sp, error, true, 4); 2150 if (error.Fail()) 2151 break; 2152 2153 auto objc_debug_taggedpointer_ext_payload_rshift = 2154 ExtractRuntimeGlobalSymbol( 2155 process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"), 2156 objc_module_sp, error, true, 4); 2157 if (error.Fail()) 2158 break; 2159 2160 return new TaggedPointerVendorExtended( 2161 runtime, objc_debug_taggedpointer_mask, 2162 objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift, 2163 objc_debug_taggedpointer_ext_slot_shift, 2164 objc_debug_taggedpointer_slot_mask, 2165 objc_debug_taggedpointer_ext_slot_mask, 2166 objc_debug_taggedpointer_payload_lshift, 2167 objc_debug_taggedpointer_payload_rshift, 2168 objc_debug_taggedpointer_ext_payload_lshift, 2169 objc_debug_taggedpointer_ext_payload_rshift, 2170 objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes); 2171 } while (false); 2172 2173 // we might want to have some rules to outlaw these values (e.g if the 2174 // table's address is zero) 2175 2176 return new TaggedPointerVendorRuntimeAssisted( 2177 runtime, objc_debug_taggedpointer_mask, 2178 objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask, 2179 objc_debug_taggedpointer_payload_lshift, 2180 objc_debug_taggedpointer_payload_rshift, 2181 objc_debug_taggedpointer_classes); 2182} 2183 2184bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer( 2185 lldb::addr_t ptr) { 2186 return (ptr & 1); 2187} 2188 2189ObjCLanguageRuntime::ClassDescriptorSP 2190AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor( 2191 lldb::addr_t ptr) { 2192 if (!IsPossibleTaggedPointer(ptr)) 2193 return ObjCLanguageRuntime::ClassDescriptorSP(); 2194 2195 uint32_t foundation_version = m_runtime.GetFoundationVersion(); 2196 2197 if (foundation_version == LLDB_INVALID_MODULE_VERSION) 2198 return ObjCLanguageRuntime::ClassDescriptorSP(); 2199 2200 uint64_t class_bits = (ptr & 0xE) >> 1; 2201 ConstString name; 2202 2203 static ConstString g_NSAtom("NSAtom"); 2204 static ConstString g_NSNumber("NSNumber"); 2205 static ConstString g_NSDateTS("NSDateTS"); 2206 static ConstString g_NSManagedObject("NSManagedObject"); 2207 static ConstString g_NSDate("NSDate"); 2208 2209 if (foundation_version >= 900) { 2210 switch (class_bits) { 2211 case 0: 2212 name = g_NSAtom; 2213 break; 2214 case 3: 2215 name = g_NSNumber; 2216 break; 2217 case 4: 2218 name = g_NSDateTS; 2219 break; 2220 case 5: 2221 name = g_NSManagedObject; 2222 break; 2223 case 6: 2224 name = g_NSDate; 2225 break; 2226 default: 2227 return ObjCLanguageRuntime::ClassDescriptorSP(); 2228 } 2229 } else { 2230 switch (class_bits) { 2231 case 1: 2232 name = g_NSNumber; 2233 break; 2234 case 5: 2235 name = g_NSManagedObject; 2236 break; 2237 case 6: 2238 name = g_NSDate; 2239 break; 2240 case 7: 2241 name = g_NSDateTS; 2242 break; 2243 default: 2244 return ObjCLanguageRuntime::ClassDescriptorSP(); 2245 } 2246 } 2247 2248 lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator(); 2249 return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated)); 2250} 2251 2252AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted:: 2253 TaggedPointerVendorRuntimeAssisted( 2254 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 2255 uint32_t objc_debug_taggedpointer_slot_shift, 2256 uint32_t objc_debug_taggedpointer_slot_mask, 2257 uint32_t objc_debug_taggedpointer_payload_lshift, 2258 uint32_t objc_debug_taggedpointer_payload_rshift, 2259 lldb::addr_t objc_debug_taggedpointer_classes) 2260 : TaggedPointerVendorV2(runtime), m_cache(), 2261 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask), 2262 m_objc_debug_taggedpointer_slot_shift( 2263 objc_debug_taggedpointer_slot_shift), 2264 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask), 2265 m_objc_debug_taggedpointer_payload_lshift( 2266 objc_debug_taggedpointer_payload_lshift), 2267 m_objc_debug_taggedpointer_payload_rshift( 2268 objc_debug_taggedpointer_payload_rshift), 2269 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {} 2270 2271bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted:: 2272 IsPossibleTaggedPointer(lldb::addr_t ptr) { 2273 return (ptr & m_objc_debug_taggedpointer_mask) != 0; 2274} 2275 2276ObjCLanguageRuntime::ClassDescriptorSP 2277AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor( 2278 lldb::addr_t ptr) { 2279 ClassDescriptorSP actual_class_descriptor_sp; 2280 uint64_t data_payload; 2281 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); 2282 2283 if (!IsPossibleTaggedPointer(unobfuscated)) 2284 return ObjCLanguageRuntime::ClassDescriptorSP(); 2285 2286 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & 2287 m_objc_debug_taggedpointer_slot_mask; 2288 2289 CacheIterator iterator = m_cache.find(slot), end = m_cache.end(); 2290 if (iterator != end) { 2291 actual_class_descriptor_sp = iterator->second; 2292 } else { 2293 Process *process(m_runtime.GetProcess()); 2294 uintptr_t slot_ptr = slot * process->GetAddressByteSize() + 2295 m_objc_debug_taggedpointer_classes; 2296 Status error; 2297 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); 2298 if (error.Fail() || slot_data == 0 || 2299 slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) 2300 return nullptr; 2301 actual_class_descriptor_sp = 2302 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); 2303 if (!actual_class_descriptor_sp) 2304 return ObjCLanguageRuntime::ClassDescriptorSP(); 2305 m_cache[slot] = actual_class_descriptor_sp; 2306 } 2307 2308 data_payload = 2309 (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >> 2310 m_objc_debug_taggedpointer_payload_rshift); 2311 2312 return ClassDescriptorSP( 2313 new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); 2314} 2315 2316AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended( 2317 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask, 2318 uint64_t objc_debug_taggedpointer_ext_mask, 2319 uint32_t objc_debug_taggedpointer_slot_shift, 2320 uint32_t objc_debug_taggedpointer_ext_slot_shift, 2321 uint32_t objc_debug_taggedpointer_slot_mask, 2322 uint32_t objc_debug_taggedpointer_ext_slot_mask, 2323 uint32_t objc_debug_taggedpointer_payload_lshift, 2324 uint32_t objc_debug_taggedpointer_payload_rshift, 2325 uint32_t objc_debug_taggedpointer_ext_payload_lshift, 2326 uint32_t objc_debug_taggedpointer_ext_payload_rshift, 2327 lldb::addr_t objc_debug_taggedpointer_classes, 2328 lldb::addr_t objc_debug_taggedpointer_ext_classes) 2329 : TaggedPointerVendorRuntimeAssisted( 2330 runtime, objc_debug_taggedpointer_mask, 2331 objc_debug_taggedpointer_slot_shift, 2332 objc_debug_taggedpointer_slot_mask, 2333 objc_debug_taggedpointer_payload_lshift, 2334 objc_debug_taggedpointer_payload_rshift, 2335 objc_debug_taggedpointer_classes), 2336 m_ext_cache(), 2337 m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask), 2338 m_objc_debug_taggedpointer_ext_slot_shift( 2339 objc_debug_taggedpointer_ext_slot_shift), 2340 m_objc_debug_taggedpointer_ext_slot_mask( 2341 objc_debug_taggedpointer_ext_slot_mask), 2342 m_objc_debug_taggedpointer_ext_payload_lshift( 2343 objc_debug_taggedpointer_ext_payload_lshift), 2344 m_objc_debug_taggedpointer_ext_payload_rshift( 2345 objc_debug_taggedpointer_ext_payload_rshift), 2346 m_objc_debug_taggedpointer_ext_classes( 2347 objc_debug_taggedpointer_ext_classes) {} 2348 2349bool AppleObjCRuntimeV2::TaggedPointerVendorExtended:: 2350 IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) { 2351 if (!IsPossibleTaggedPointer(ptr)) 2352 return false; 2353 2354 if (m_objc_debug_taggedpointer_ext_mask == 0) 2355 return false; 2356 2357 return ((ptr & m_objc_debug_taggedpointer_ext_mask) == 2358 m_objc_debug_taggedpointer_ext_mask); 2359} 2360 2361ObjCLanguageRuntime::ClassDescriptorSP 2362AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor( 2363 lldb::addr_t ptr) { 2364 ClassDescriptorSP actual_class_descriptor_sp; 2365 uint64_t data_payload; 2366 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator(); 2367 2368 if (!IsPossibleTaggedPointer(unobfuscated)) 2369 return ObjCLanguageRuntime::ClassDescriptorSP(); 2370 2371 if (!IsPossibleExtendedTaggedPointer(unobfuscated)) 2372 return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr); 2373 2374 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) & 2375 m_objc_debug_taggedpointer_ext_slot_mask; 2376 2377 CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end(); 2378 if (iterator != end) { 2379 actual_class_descriptor_sp = iterator->second; 2380 } else { 2381 Process *process(m_runtime.GetProcess()); 2382 uintptr_t slot_ptr = slot * process->GetAddressByteSize() + 2383 m_objc_debug_taggedpointer_ext_classes; 2384 Status error; 2385 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); 2386 if (error.Fail() || slot_data == 0 || 2387 slot_data == uintptr_t(LLDB_INVALID_ADDRESS)) 2388 return nullptr; 2389 actual_class_descriptor_sp = 2390 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data); 2391 if (!actual_class_descriptor_sp) 2392 return ObjCLanguageRuntime::ClassDescriptorSP(); 2393 m_ext_cache[slot] = actual_class_descriptor_sp; 2394 } 2395 2396 data_payload = 2397 (((uint64_t)unobfuscated << m_objc_debug_taggedpointer_ext_payload_lshift) >> 2398 m_objc_debug_taggedpointer_ext_payload_rshift); 2399 2400 return ClassDescriptorSP( 2401 new ClassDescriptorV2Tagged(actual_class_descriptor_sp, data_payload)); 2402} 2403 2404AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache( 2405 AppleObjCRuntimeV2 &runtime, const ModuleSP &objc_module_sp, 2406 uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask, 2407 uint64_t objc_debug_isa_magic_value, 2408 uint64_t objc_debug_indexed_isa_magic_mask, 2409 uint64_t objc_debug_indexed_isa_magic_value, 2410 uint64_t objc_debug_indexed_isa_index_mask, 2411 uint64_t objc_debug_indexed_isa_index_shift, 2412 lldb::addr_t objc_indexed_classes) 2413 : m_runtime(runtime), m_cache(), m_objc_module_wp(objc_module_sp), 2414 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask), 2415 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask), 2416 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value), 2417 m_objc_debug_indexed_isa_magic_mask(objc_debug_indexed_isa_magic_mask), 2418 m_objc_debug_indexed_isa_magic_value(objc_debug_indexed_isa_magic_value), 2419 m_objc_debug_indexed_isa_index_mask(objc_debug_indexed_isa_index_mask), 2420 m_objc_debug_indexed_isa_index_shift(objc_debug_indexed_isa_index_shift), 2421 m_objc_indexed_classes(objc_indexed_classes), m_indexed_isa_cache() {} 2422 2423ObjCLanguageRuntime::ClassDescriptorSP 2424AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) { 2425 ObjCISA real_isa = 0; 2426 if (EvaluateNonPointerISA(isa, real_isa) == false) 2427 return ObjCLanguageRuntime::ClassDescriptorSP(); 2428 auto cache_iter = m_cache.find(real_isa); 2429 if (cache_iter != m_cache.end()) 2430 return cache_iter->second; 2431 auto descriptor_sp = 2432 m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa); 2433 if (descriptor_sp) // cache only positive matches since the table might grow 2434 m_cache[real_isa] = descriptor_sp; 2435 return descriptor_sp; 2436} 2437 2438bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA( 2439 ObjCISA isa, ObjCISA &ret_isa) { 2440 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); 2441 2442 if (log) 2443 log->Printf("AOCRT::NPI Evalulate(isa = 0x%" PRIx64 ")", (uint64_t)isa); 2444 2445 if ((isa & ~m_objc_debug_isa_class_mask) == 0) 2446 return false; 2447 2448 // If all of the indexed ISA variables are set, then its possible that this 2449 // ISA is indexed, and we should first try to get its value using the index. 2450 // Note, we check these varaibles first as the ObjC runtime will set at least 2451 // one of their values to 0 if they aren't needed. 2452 if (m_objc_debug_indexed_isa_magic_mask && 2453 m_objc_debug_indexed_isa_magic_value && 2454 m_objc_debug_indexed_isa_index_mask && 2455 m_objc_debug_indexed_isa_index_shift && m_objc_indexed_classes) { 2456 if ((isa & ~m_objc_debug_indexed_isa_index_mask) == 0) 2457 return false; 2458 2459 if ((isa & m_objc_debug_indexed_isa_magic_mask) == 2460 m_objc_debug_indexed_isa_magic_value) { 2461 // Magic bits are correct, so try extract the index. 2462 uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >> 2463 m_objc_debug_indexed_isa_index_shift; 2464 // If the index is out of bounds of the length of the array then check if 2465 // the array has been updated. If that is the case then we should try 2466 // read the count again, and update the cache if the count has been 2467 // updated. 2468 if (index > m_indexed_isa_cache.size()) { 2469 if (log) 2470 log->Printf("AOCRT::NPI (index = %" PRIu64 2471 ") exceeds cache (size = %" PRIu64 ")", 2472 (uint64_t)index, (uint64_t)m_indexed_isa_cache.size()); 2473 2474 Process *process(m_runtime.GetProcess()); 2475 2476 ModuleSP objc_module_sp(m_objc_module_wp.lock()); 2477 if (!objc_module_sp) 2478 return false; 2479 2480 Status error; 2481 auto objc_indexed_classes_count = ExtractRuntimeGlobalSymbol( 2482 process, ConstString("objc_indexed_classes_count"), objc_module_sp, 2483 error); 2484 if (error.Fail()) 2485 return false; 2486 2487 if (log) 2488 log->Printf("AOCRT::NPI (new class count = %" PRIu64 ")", 2489 (uint64_t)objc_indexed_classes_count); 2490 2491 if (objc_indexed_classes_count > m_indexed_isa_cache.size()) { 2492 // Read the class entries we don't have. We should just read all of 2493 // them instead of just the one we need as then we can cache those we 2494 // may need later. 2495 auto num_new_classes = 2496 objc_indexed_classes_count - m_indexed_isa_cache.size(); 2497 const uint32_t addr_size = process->GetAddressByteSize(); 2498 DataBufferHeap buffer(num_new_classes * addr_size, 0); 2499 2500 lldb::addr_t last_read_class = 2501 m_objc_indexed_classes + (m_indexed_isa_cache.size() * addr_size); 2502 size_t bytes_read = process->ReadMemory( 2503 last_read_class, buffer.GetBytes(), buffer.GetByteSize(), error); 2504 if (error.Fail() || bytes_read != buffer.GetByteSize()) 2505 return false; 2506 2507 if (log) 2508 log->Printf("AOCRT::NPI (read new classes count = %" PRIu64 ")", 2509 (uint64_t)num_new_classes); 2510 2511 // Append the new entries to the existing cache. 2512 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), 2513 process->GetByteOrder(), 2514 process->GetAddressByteSize()); 2515 2516 lldb::offset_t offset = 0; 2517 for (unsigned i = 0; i != num_new_classes; ++i) 2518 m_indexed_isa_cache.push_back(data.GetPointer(&offset)); 2519 } 2520 } 2521 2522 // If the index is still out of range then this isn't a pointer. 2523 if (index > m_indexed_isa_cache.size()) 2524 return false; 2525 2526 if (log) 2527 log->Printf("AOCRT::NPI Evalulate(ret_isa = 0x%" PRIx64 ")", 2528 (uint64_t)m_indexed_isa_cache[index]); 2529 2530 ret_isa = m_indexed_isa_cache[index]; 2531 return (ret_isa != 0); // this is a pointer so 0 is not a valid value 2532 } 2533 2534 return false; 2535 } 2536 2537 // Definately not an indexed ISA, so try to use a mask to extract the pointer 2538 // from the ISA. 2539 if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) { 2540 ret_isa = isa & m_objc_debug_isa_class_mask; 2541 return (ret_isa != 0); // this is a pointer so 0 is not a valid value 2542 } 2543 return false; 2544} 2545 2546ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() { 2547 if (!m_encoding_to_type_sp) 2548 m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this)); 2549 return m_encoding_to_type_sp; 2550} 2551 2552lldb_private::AppleObjCRuntime::ObjCISA 2553AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) { 2554 ObjCISA ret = isa; 2555 2556 if (m_non_pointer_isa_cache_ap) 2557 m_non_pointer_isa_cache_ap->EvaluateNonPointerISA(isa, ret); 2558 2559 return ret; 2560} 2561 2562bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() { 2563 if (m_CFBoolean_values) 2564 return true; 2565 2566 static ConstString g_kCFBooleanFalse("__kCFBooleanFalse"); 2567 static ConstString g_kCFBooleanTrue("__kCFBooleanTrue"); 2568 2569 std::function<lldb::addr_t(ConstString)> get_symbol = 2570 [this](ConstString sym) -> lldb::addr_t { 2571 SymbolContextList sc_list; 2572 if (GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType( 2573 sym, lldb::eSymbolTypeData, sc_list) == 1) { 2574 SymbolContext sc; 2575 sc_list.GetContextAtIndex(0, sc); 2576 if (sc.symbol) 2577 return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget()); 2578 } 2579 2580 return LLDB_INVALID_ADDRESS; 2581 }; 2582 2583 lldb::addr_t false_addr = get_symbol(g_kCFBooleanFalse); 2584 lldb::addr_t true_addr = get_symbol(g_kCFBooleanTrue); 2585 2586 return (m_CFBoolean_values = {false_addr, true_addr}).operator bool(); 2587} 2588 2589void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true, 2590 lldb::addr_t &cf_false) { 2591 if (GetCFBooleanValuesIfNeeded()) { 2592 cf_true = m_CFBoolean_values->second; 2593 cf_false = m_CFBoolean_values->first; 2594 } else 2595 this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false); 2596} 2597