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