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