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