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