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 #include "lldb/lldb-python.h" 11 12 #include <string> 13 #include <vector> 14 #include <stdint.h> 15 16 #include "lldb/lldb-enumerations.h" 17 #include "lldb/Core/ClangForward.h" 18 #include "lldb/Symbol/ClangASTType.h" 19 20 #include "lldb/Core/ClangForward.h" 21 #include "lldb/Core/ConstString.h" 22 #include "lldb/Core/Error.h" 23 #include "lldb/Core/Log.h" 24 #include "lldb/Core/Module.h" 25 #include "lldb/Core/PluginManager.h" 26 #include "lldb/Core/Scalar.h" 27 #include "lldb/Core/Section.h" 28 #include "lldb/Core/StreamString.h" 29 #include "lldb/Core/Timer.h" 30 #include "lldb/Core/ValueObjectVariable.h" 31 #include "lldb/Expression/ClangFunction.h" 32 #include "lldb/Expression/ClangUtilityFunction.h" 33 #include "lldb/Symbol/ClangASTContext.h" 34 #include "lldb/Symbol/ObjectFile.h" 35 #include "lldb/Symbol/Symbol.h" 36 #include "lldb/Symbol/TypeList.h" 37 #include "lldb/Symbol/VariableList.h" 38 #include "lldb/Target/ExecutionContext.h" 39 #include "lldb/Target/Process.h" 40 #include "lldb/Target/RegisterContext.h" 41 #include "lldb/Target/Target.h" 42 #include "lldb/Target/Thread.h" 43 44 #include "AppleObjCRuntimeV2.h" 45 #include "AppleObjCTypeVendor.h" 46 #include "AppleObjCTrampolineHandler.h" 47 48 #include <vector> 49 50 using namespace lldb; 51 using namespace lldb_private; 52 53 // 2 second timeout when running utility functions 54 #define UTILITY_FUNCTION_TIMEOUT_USEC 2*1000*1000 55 56 static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info"; 57 // Testing using the new C++11 raw string literals. If this breaks GCC then we will 58 // need to revert to the code above... 59 static const char *g_get_dynamic_class_info_body = R"( 60 61 extern "C" 62 { 63 size_t strlen(const char *); 64 char *strncpy (char * s1, const char * s2, size_t n); 65 int printf(const char * format, ...); 66 } 67 //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN 68 #ifdef ENABLE_DEBUG_PRINTF 69 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) 70 #else 71 #define DEBUG_PRINTF(fmt, ...) 72 #endif 73 74 typedef struct _NXMapTable { 75 void *prototype; 76 unsigned num_classes; 77 unsigned num_buckets_minus_one; 78 void *buckets; 79 } NXMapTable; 80 81 #define NX_MAPNOTAKEY ((void *)(-1)) 82 83 typedef struct BucketInfo 84 { 85 const char *name_ptr; 86 Class isa; 87 } BucketInfo; 88 89 struct ClassInfo 90 { 91 Class isa; 92 uint32_t hash; 93 } __attribute__((__packed__)); 94 95 uint32_t 96 __lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr, 97 void *class_infos_ptr, 98 uint32_t class_infos_byte_size) 99 { 100 DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr); 101 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr); 102 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size); 103 const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr; 104 if (grc) 105 { 106 const unsigned num_classes = grc->num_classes; 107 if (class_infos_ptr) 108 { 109 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); 110 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; 111 BucketInfo *buckets = (BucketInfo *)grc->buckets; 112 113 uint32_t idx = 0; 114 for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i) 115 { 116 if (buckets[i].name_ptr != NX_MAPNOTAKEY) 117 { 118 if (idx < max_class_infos) 119 { 120 const char *s = buckets[i].name_ptr; 121 uint32_t h = 5381; 122 for (unsigned char c = *s; c; c = *++s) 123 h = ((h << 5) + h) + c; 124 class_infos[idx].hash = h; 125 class_infos[idx].isa = buckets[i].isa; 126 } 127 ++idx; 128 } 129 } 130 if (idx < max_class_infos) 131 { 132 class_infos[idx].isa = NULL; 133 class_infos[idx].hash = 0; 134 } 135 } 136 return num_classes; 137 } 138 return 0; 139 } 140 141 )"; 142 143 static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info"; 144 // Testing using the new C++11 raw string literals. If this breaks GCC then we will 145 // need to revert to the code above... 146 static const char *g_get_shared_cache_class_info_body = R"( 147 148 extern "C" 149 { 150 const char *class_getName(void *objc_class); 151 size_t strlen(const char *); 152 char *strncpy (char * s1, const char * s2, size_t n); 153 int printf(const char * format, ...); 154 } 155 156 //#define ENABLE_DEBUG_PRINTF // COMMENT THIS LINE OUT PRIOR TO CHECKIN 157 #ifdef ENABLE_DEBUG_PRINTF 158 #define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__) 159 #else 160 #define DEBUG_PRINTF(fmt, ...) 161 #endif 162 163 164 struct objc_classheader_t { 165 int32_t clsOffset; 166 int32_t hiOffset; 167 }; 168 169 struct objc_clsopt_t { 170 uint32_t capacity; 171 uint32_t occupied; 172 uint32_t shift; 173 uint32_t mask; 174 uint32_t zero; 175 uint32_t unused; 176 uint64_t salt; 177 uint32_t scramble[256]; 178 uint8_t tab[0]; // tab[mask+1] 179 // uint8_t checkbytes[capacity]; 180 // int32_t offset[capacity]; 181 // objc_classheader_t clsOffsets[capacity]; 182 // uint32_t duplicateCount; 183 // objc_classheader_t duplicateOffsets[duplicateCount]; 184 }; 185 186 struct objc_opt_t { 187 uint32_t version; 188 int32_t selopt_offset; 189 int32_t headeropt_offset; 190 int32_t clsopt_offset; 191 }; 192 193 struct ClassInfo 194 { 195 Class isa; 196 uint32_t hash; 197 } __attribute__((__packed__)); 198 199 uint32_t 200 __lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr, 201 void *class_infos_ptr, 202 uint32_t class_infos_byte_size) 203 { 204 uint32_t idx = 0; 205 DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr); 206 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr); 207 DEBUG_PRINTF ("class_infos_byte_size = %u (%zu class infos)\n", class_infos_byte_size, (size_t)(class_infos_byte_size/sizeof(ClassInfo))); 208 if (objc_opt_ro_ptr) 209 { 210 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr; 211 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version); 212 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset); 213 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset); 214 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset); 215 if (objc_opt->version == 12) 216 { 217 const objc_clsopt_t* clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset); 218 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo); 219 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr; 220 int32_t zeroOffset = 16; 221 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1]; 222 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity); 223 const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity); 224 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity); 225 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask); 226 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets); 227 for (uint32_t i=0; i<clsopt->capacity; ++i) 228 { 229 const int32_t clsOffset = classOffsets[i].clsOffset; 230 if (clsOffset & 1) 231 continue; // duplicate 232 else if (clsOffset == zeroOffset) 233 continue; // zero offset 234 235 if (class_infos && idx < max_class_infos) 236 { 237 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); 238 const char *name = class_getName (class_infos[idx].isa); 239 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name); 240 // Hash the class name so we don't have to read it 241 const char *s = name; 242 uint32_t h = 5381; 243 for (unsigned char c = *s; c; c = *++s) 244 h = ((h << 5) + h) + c; 245 class_infos[idx].hash = h; 246 } 247 ++idx; 248 } 249 250 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity]; 251 const uint32_t duplicate_count = *duplicate_count_ptr; 252 const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]); 253 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count); 254 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets); 255 for (uint32_t i=0; i<duplicate_count; ++i) 256 { 257 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset; 258 if (clsOffset & 1) 259 continue; // duplicate 260 else if (clsOffset == zeroOffset) 261 continue; // zero offset 262 263 if (class_infos && idx < max_class_infos) 264 { 265 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset); 266 const char *name = class_getName (class_infos[idx].isa); 267 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name); 268 // Hash the class name so we don't have to read it 269 const char *s = name; 270 uint32_t h = 5381; 271 for (unsigned char c = *s; c; c = *++s) 272 h = ((h << 5) + h) + c; 273 class_infos[idx].hash = h; 274 } 275 ++idx; 276 } 277 } 278 DEBUG_PRINTF ("%u class_infos\n", idx); 279 DEBUG_PRINTF ("done\n"); 280 } 281 return idx; 282 } 283 284 285 )"; 286 287 static uint64_t 288 ExtractRuntimeGlobalSymbol (Process* process, 289 ConstString name, 290 const ModuleSP &module_sp, 291 Error& error, 292 bool read_value = true, 293 uint8_t byte_size = 0, 294 uint64_t default_value = LLDB_INVALID_ADDRESS, 295 SymbolType sym_type = lldb::eSymbolTypeData) 296 { 297 if (!process) 298 { 299 error.SetErrorString("no process"); 300 return default_value; 301 } 302 if (!module_sp) 303 { 304 error.SetErrorString("no module"); 305 return default_value; 306 } 307 if (!byte_size) 308 byte_size = process->GetAddressByteSize(); 309 const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData); 310 if (symbol) 311 { 312 lldb::addr_t symbol_load_addr = symbol->GetAddress().GetLoadAddress(&process->GetTarget()); 313 if (symbol_load_addr != LLDB_INVALID_ADDRESS) 314 { 315 if (read_value) 316 return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, default_value, error); 317 else 318 return symbol_load_addr; 319 } 320 else 321 { 322 error.SetErrorString("symbol address invalid"); 323 return default_value; 324 } 325 } 326 else 327 { 328 error.SetErrorString("no symbol"); 329 return default_value; 330 } 331 332 } 333 334 AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, 335 const ModuleSP &objc_module_sp) : 336 AppleObjCRuntime (process), 337 m_get_class_info_function(), 338 m_get_class_info_code(), 339 m_get_class_info_args (LLDB_INVALID_ADDRESS), 340 m_get_class_info_args_mutex (Mutex::eMutexTypeNormal), 341 m_get_shared_cache_class_info_function(), 342 m_get_shared_cache_class_info_code(), 343 m_get_shared_cache_class_info_args (LLDB_INVALID_ADDRESS), 344 m_get_shared_cache_class_info_args_mutex (Mutex::eMutexTypeNormal), 345 m_type_vendor_ap (), 346 m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS), 347 m_hash_signature (), 348 m_has_object_getClass (false), 349 m_loaded_objc_opt (false), 350 m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this,objc_module_sp)), 351 m_tagged_pointer_vendor_ap(TaggedPointerVendor::CreateInstance(*this,objc_module_sp)) 352 { 353 static const ConstString g_gdb_object_getClass("gdb_object_getClass"); 354 m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL); 355 } 356 357 AppleObjCRuntimeV2::~AppleObjCRuntimeV2() 358 { 359 } 360 361 bool 362 AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value, 363 DynamicValueType use_dynamic, 364 TypeAndOrName &class_type_or_name, 365 Address &address) 366 { 367 // The Runtime is attached to a particular process, you shouldn't pass in a value from another process. 368 assert (in_value.GetProcessSP().get() == m_process); 369 assert (m_process != NULL); 370 371 class_type_or_name.Clear(); 372 373 // Make sure we can have a dynamic value before starting... 374 if (CouldHaveDynamicValue (in_value)) 375 { 376 // First job, pull out the address at 0 offset from the object That will be the ISA pointer. 377 ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor (in_value)); 378 if (objc_class_sp) 379 { 380 const addr_t object_ptr = in_value.GetPointerValue(); 381 address.SetRawAddress(object_ptr); 382 383 ConstString class_name (objc_class_sp->GetClassName()); 384 class_type_or_name.SetName(class_name); 385 TypeSP type_sp (objc_class_sp->GetType()); 386 if (type_sp) 387 class_type_or_name.SetTypeSP (type_sp); 388 else 389 { 390 type_sp = LookupInCompleteClassCache (class_name); 391 if (type_sp) 392 { 393 objc_class_sp->SetType (type_sp); 394 class_type_or_name.SetTypeSP (type_sp); 395 } 396 } 397 } 398 } 399 return class_type_or_name.IsEmpty() == false; 400 } 401 402 //------------------------------------------------------------------ 403 // Static Functions 404 //------------------------------------------------------------------ 405 LanguageRuntime * 406 AppleObjCRuntimeV2::CreateInstance (Process *process, LanguageType language) 407 { 408 // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make 409 // sure we aren't using the V1 runtime. 410 if (language == eLanguageTypeObjC) 411 { 412 ModuleSP objc_module_sp; 413 414 if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == eAppleObjC_V2) 415 return new AppleObjCRuntimeV2 (process, objc_module_sp); 416 else 417 return NULL; 418 } 419 else 420 return NULL; 421 } 422 423 void 424 AppleObjCRuntimeV2::Initialize() 425 { 426 PluginManager::RegisterPlugin (GetPluginNameStatic(), 427 "Apple Objective C Language Runtime - Version 2", 428 CreateInstance); 429 } 430 431 void 432 AppleObjCRuntimeV2::Terminate() 433 { 434 PluginManager::UnregisterPlugin (CreateInstance); 435 } 436 437 lldb_private::ConstString 438 AppleObjCRuntimeV2::GetPluginNameStatic() 439 { 440 static ConstString g_name("apple-objc-v2"); 441 return g_name; 442 } 443 444 445 //------------------------------------------------------------------ 446 // PluginInterface protocol 447 //------------------------------------------------------------------ 448 lldb_private::ConstString 449 AppleObjCRuntimeV2::GetPluginName() 450 { 451 return GetPluginNameStatic(); 452 } 453 454 uint32_t 455 AppleObjCRuntimeV2::GetPluginVersion() 456 { 457 return 1; 458 } 459 460 BreakpointResolverSP 461 AppleObjCRuntimeV2::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) 462 { 463 BreakpointResolverSP resolver_sp; 464 465 if (throw_bp) 466 resolver_sp.reset (new BreakpointResolverName (bkpt, 467 "objc_exception_throw", 468 eFunctionNameTypeBase, 469 Breakpoint::Exact, 470 eLazyBoolNo)); 471 // FIXME: We don't do catch breakpoints for ObjC yet. 472 // Should there be some way for the runtime to specify what it can do in this regard? 473 return resolver_sp; 474 } 475 476 ClangUtilityFunction * 477 AppleObjCRuntimeV2::CreateObjectChecker(const char *name) 478 { 479 char check_function_code[2048]; 480 481 int len = 0; 482 if (m_has_object_getClass) 483 { 484 len = ::snprintf (check_function_code, 485 sizeof(check_function_code), 486 "extern \"C\" void *gdb_object_getClass(void *); \n" 487 "extern \"C\" int printf(const char *format, ...); \n" 488 "extern \"C\" void \n" 489 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" 490 "{ \n" 491 " if ($__lldb_arg_obj == (void *)0) \n" 492 " return; // nil is ok \n" 493 " if (!gdb_object_getClass($__lldb_arg_obj)) \n" 494 " *((volatile int *)0) = 'ocgc'; \n" 495 " else if ($__lldb_arg_selector != (void *)0) \n" 496 " { \n" 497 " signed char responds = (signed char) [(id) $__lldb_arg_obj \n" 498 " respondsToSelector: \n" 499 " (struct objc_selector *) $__lldb_arg_selector]; \n" 500 " if (responds == (signed char) 0) \n" 501 " *((volatile int *)0) = 'ocgc'; \n" 502 " } \n" 503 "} \n", 504 name); 505 } 506 else 507 { 508 len = ::snprintf (check_function_code, 509 sizeof(check_function_code), 510 "extern \"C\" void *gdb_class_getClass(void *); \n" 511 "extern \"C\" int printf(const char *format, ...); \n" 512 "extern \"C\" void \n" 513 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" 514 "{ \n" 515 " if ($__lldb_arg_obj == (void *)0) \n" 516 " return; // nil is ok \n" 517 " void **$isa_ptr = (void **)$__lldb_arg_obj; \n" 518 " if (*$isa_ptr == (void *)0 || !gdb_class_getClass(*$isa_ptr)) \n" 519 " *((volatile int *)0) = 'ocgc'; \n" 520 " else if ($__lldb_arg_selector != (void *)0) \n" 521 " { \n" 522 " signed char responds = (signed char) [(id) $__lldb_arg_obj \n" 523 " respondsToSelector: \n" 524 " (struct objc_selector *) $__lldb_arg_selector]; \n" 525 " if (responds == (signed char) 0) \n" 526 " *((volatile int *)0) = 'ocgc'; \n" 527 " } \n" 528 "} \n", 529 name); 530 } 531 532 assert (len < (int)sizeof(check_function_code)); 533 534 return new ClangUtilityFunction(check_function_code, name); 535 } 536 537 size_t 538 AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const char *ivar_name) 539 { 540 const char *class_name = parent_ast_type.GetConstTypeName().AsCString(); 541 542 if (!class_name || *class_name == '\0' || !ivar_name || *ivar_name == '\0') 543 return LLDB_INVALID_IVAR_OFFSET; 544 545 std::string buffer("OBJC_IVAR_$_"); 546 buffer.append (class_name); 547 buffer.push_back ('.'); 548 buffer.append (ivar_name); 549 ConstString ivar_const_str (buffer.c_str()); 550 551 SymbolContextList sc_list; 552 Target &target = m_process->GetTarget(); 553 554 target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list); 555 556 SymbolContext ivar_offset_symbol; 557 if (sc_list.GetSize() != 1 558 || !sc_list.GetContextAtIndex(0, ivar_offset_symbol) 559 || ivar_offset_symbol.symbol == NULL) 560 return LLDB_INVALID_IVAR_OFFSET; 561 562 addr_t ivar_offset_address = ivar_offset_symbol.symbol->GetAddress().GetLoadAddress (&target); 563 564 Error error; 565 566 uint32_t ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address, 567 4, 568 LLDB_INVALID_IVAR_OFFSET, 569 error); 570 return ivar_offset; 571 } 572 573 574 // tagged pointers are special not-a-real-pointer values that contain both type and value information 575 // this routine attempts to check with as little computational effort as possible whether something 576 // could possibly be a tagged pointer - false positives are possible but false negatives shouldn't 577 bool 578 AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) 579 { 580 if (!m_tagged_pointer_vendor_ap) 581 return false; 582 return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr); 583 } 584 585 class RemoteNXMapTable 586 { 587 public: 588 589 RemoteNXMapTable () : 590 m_count (0), 591 m_num_buckets_minus_one (0), 592 m_buckets_ptr (LLDB_INVALID_ADDRESS), 593 m_process (NULL), 594 m_end_iterator (*this, -1), 595 m_load_addr (LLDB_INVALID_ADDRESS), 596 m_map_pair_size (0), 597 m_invalid_key (0) 598 { 599 } 600 601 void 602 Dump () 603 { 604 printf ("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr); 605 printf ("RemoteNXMapTable.m_count = %u\n", m_count); 606 printf ("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", m_num_buckets_minus_one); 607 printf ("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr); 608 } 609 610 bool 611 ParseHeader (Process* process, lldb::addr_t load_addr) 612 { 613 m_process = process; 614 m_load_addr = load_addr; 615 m_map_pair_size = m_process->GetAddressByteSize() * 2; 616 m_invalid_key = m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX; 617 Error err; 618 619 // This currently holds true for all platforms we support, but we might 620 // need to change this to use get the actualy byte size of "unsigned" 621 // from the target AST... 622 const uint32_t unsigned_byte_size = sizeof(uint32_t); 623 // Skip the prototype as we don't need it (const struct +NXMapTablePrototype *prototype) 624 625 bool success = true; 626 if (load_addr == LLDB_INVALID_ADDRESS) 627 success = false; 628 else 629 { 630 lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize(); 631 632 // unsigned count; 633 m_count = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err); 634 if (m_count) 635 { 636 cursor += unsigned_byte_size; 637 638 // unsigned nbBucketsMinusOne; 639 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err); 640 cursor += unsigned_byte_size; 641 642 // void *buckets; 643 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err); 644 645 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS; 646 } 647 } 648 649 if (!success) 650 { 651 m_count = 0; 652 m_num_buckets_minus_one = 0; 653 m_buckets_ptr = LLDB_INVALID_ADDRESS; 654 } 655 return success; 656 } 657 658 // const_iterator mimics NXMapState and its code comes from NXInitMapState and NXNextMapState. 659 typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element; 660 661 friend class const_iterator; 662 class const_iterator 663 { 664 public: 665 const_iterator (RemoteNXMapTable &parent, int index) : m_parent(parent), m_index(index) 666 { 667 AdvanceToValidIndex(); 668 } 669 670 const_iterator (const const_iterator &rhs) : m_parent(rhs.m_parent), m_index(rhs.m_index) 671 { 672 // AdvanceToValidIndex() has been called by rhs already. 673 } 674 675 const_iterator &operator=(const const_iterator &rhs) 676 { 677 // AdvanceToValidIndex() has been called by rhs already. 678 assert (&m_parent == &rhs.m_parent); 679 m_index = rhs.m_index; 680 return *this; 681 } 682 683 bool operator==(const const_iterator &rhs) const 684 { 685 if (&m_parent != &rhs.m_parent) 686 return false; 687 if (m_index != rhs.m_index) 688 return false; 689 690 return true; 691 } 692 693 bool operator!=(const const_iterator &rhs) const 694 { 695 return !(operator==(rhs)); 696 } 697 698 const_iterator &operator++() 699 { 700 AdvanceToValidIndex(); 701 return *this; 702 } 703 704 const element operator*() const 705 { 706 if (m_index == -1) 707 { 708 // TODO find a way to make this an error, but not an assert 709 return element(); 710 } 711 712 lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; 713 size_t map_pair_size = m_parent.m_map_pair_size; 714 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); 715 716 Error err; 717 718 lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); 719 if (!err.Success()) 720 return element(); 721 lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(pair_ptr + m_parent.m_process->GetAddressByteSize(), err); 722 if (!err.Success()) 723 return element(); 724 725 std::string key_string; 726 727 m_parent.m_process->ReadCStringFromMemory(key, key_string, err); 728 if (!err.Success()) 729 return element(); 730 731 return element(ConstString(key_string.c_str()), (ObjCLanguageRuntime::ObjCISA)value); 732 } 733 private: 734 void AdvanceToValidIndex () 735 { 736 if (m_index == -1) 737 return; 738 739 const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr; 740 const size_t map_pair_size = m_parent.m_map_pair_size; 741 const lldb::addr_t invalid_key = m_parent.m_invalid_key; 742 Error err; 743 744 while (m_index--) 745 { 746 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size); 747 lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err); 748 749 if (!err.Success()) 750 { 751 m_index = -1; 752 return; 753 } 754 755 if (key != invalid_key) 756 return; 757 } 758 } 759 RemoteNXMapTable &m_parent; 760 int m_index; 761 }; 762 763 const_iterator begin () 764 { 765 return const_iterator(*this, m_num_buckets_minus_one + 1); 766 } 767 768 const_iterator end () 769 { 770 return m_end_iterator; 771 } 772 773 uint32_t 774 GetCount () const 775 { 776 return m_count; 777 } 778 779 uint32_t 780 GetBucketCount () const 781 { 782 return m_num_buckets_minus_one; 783 } 784 785 lldb::addr_t 786 GetBucketDataPointer () const 787 { 788 return m_buckets_ptr; 789 } 790 791 lldb::addr_t 792 GetTableLoadAddress() const 793 { 794 return m_load_addr; 795 } 796 797 private: 798 // contents of _NXMapTable struct 799 uint32_t m_count; 800 uint32_t m_num_buckets_minus_one; 801 lldb::addr_t m_buckets_ptr; 802 lldb_private::Process *m_process; 803 const_iterator m_end_iterator; 804 lldb::addr_t m_load_addr; 805 size_t m_map_pair_size; 806 lldb::addr_t m_invalid_key; 807 }; 808 809 810 811 AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() : 812 m_count (0), 813 m_num_buckets (0), 814 m_buckets_ptr (0) 815 { 816 } 817 818 void 819 AppleObjCRuntimeV2::HashTableSignature::UpdateSignature (const RemoteNXMapTable &hash_table) 820 { 821 m_count = hash_table.GetCount(); 822 m_num_buckets = hash_table.GetBucketCount(); 823 m_buckets_ptr = hash_table.GetBucketDataPointer(); 824 } 825 826 bool 827 AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate (Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table) 828 { 829 if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer ())) 830 { 831 return false; // Failed to parse the header, no need to update anything 832 } 833 834 // Check with out current signature and return true if the count, 835 // number of buckets or the hash table address changes. 836 if (m_count == hash_table.GetCount() && 837 m_num_buckets == hash_table.GetBucketCount() && 838 m_buckets_ptr == hash_table.GetBucketDataPointer()) 839 { 840 // Hash table hasn't changed 841 return false; 842 } 843 // Hash table data has changed, we need to update 844 return true; 845 } 846 847 class ClassDescriptorV2 : public ObjCLanguageRuntime::ClassDescriptor 848 { 849 public: 850 friend class lldb_private::AppleObjCRuntimeV2; 851 852 private: 853 // The constructor should only be invoked by the runtime as it builds its caches 854 // or populates them. A ClassDescriptorV2 should only ever exist in a cache. 855 ClassDescriptorV2 (AppleObjCRuntimeV2 &runtime, ObjCLanguageRuntime::ObjCISA isa, const char *name) : 856 m_runtime (runtime), 857 m_objc_class_ptr (isa), 858 m_name (name) 859 { 860 } 861 862 public: 863 virtual ConstString 864 GetClassName () 865 { 866 if (!m_name) 867 { 868 lldb_private::Process *process = m_runtime.GetProcess(); 869 870 if (process) 871 { 872 std::unique_ptr<objc_class_t> objc_class; 873 std::unique_ptr<class_ro_t> class_ro; 874 std::unique_ptr<class_rw_t> class_rw; 875 876 if (!Read_objc_class(process, objc_class)) 877 return m_name; 878 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 879 return m_name; 880 881 m_name = ConstString(class_ro->m_name.c_str()); 882 } 883 } 884 return m_name; 885 } 886 887 virtual ObjCLanguageRuntime::ClassDescriptorSP 888 GetSuperclass () 889 { 890 lldb_private::Process *process = m_runtime.GetProcess(); 891 892 if (!process) 893 return ObjCLanguageRuntime::ClassDescriptorSP(); 894 895 std::unique_ptr<objc_class_t> objc_class; 896 897 if (!Read_objc_class(process, objc_class)) 898 return ObjCLanguageRuntime::ClassDescriptorSP(); 899 900 return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(objc_class->m_superclass); 901 } 902 903 virtual bool 904 IsValid () 905 { 906 return true; // any Objective-C v2 runtime class descriptor we vend is valid 907 } 908 909 // a custom descriptor is used for tagged pointers 910 virtual bool 911 GetTaggedPointerInfo (uint64_t* info_bits = NULL, 912 uint64_t* value_bits = NULL, 913 uint64_t* payload = NULL) 914 { 915 return false; 916 } 917 918 virtual uint64_t 919 GetInstanceSize () 920 { 921 lldb_private::Process *process = m_runtime.GetProcess(); 922 923 if (process) 924 { 925 std::unique_ptr<objc_class_t> objc_class; 926 std::unique_ptr<class_ro_t> class_ro; 927 std::unique_ptr<class_rw_t> class_rw; 928 929 if (!Read_objc_class(process, objc_class)) 930 return 0; 931 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 932 return 0; 933 934 return class_ro->m_instanceSize; 935 } 936 937 return 0; 938 } 939 940 virtual ObjCLanguageRuntime::ObjCISA 941 GetISA () 942 { 943 return m_objc_class_ptr; 944 } 945 946 virtual bool 947 Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, 948 std::function <bool (const char *, const char *)> const &instance_method_func, 949 std::function <bool (const char *, const char *)> const &class_method_func, 950 std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) 951 { 952 lldb_private::Process *process = m_runtime.GetProcess(); 953 954 std::unique_ptr<objc_class_t> objc_class; 955 std::unique_ptr<class_ro_t> class_ro; 956 std::unique_ptr<class_rw_t> class_rw; 957 958 if (!Read_objc_class(process, objc_class)) 959 return 0; 960 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 961 return 0; 962 963 static ConstString NSObject_name("NSObject"); 964 965 if (m_name != NSObject_name && superclass_func) 966 superclass_func(objc_class->m_superclass); 967 968 if (instance_method_func) 969 { 970 std::unique_ptr<method_list_t> base_method_list; 971 972 base_method_list.reset(new method_list_t); 973 if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) 974 return false; 975 976 if (base_method_list->m_entsize != method_t::GetSize(process)) 977 return false; 978 979 std::unique_ptr<method_t> method; 980 method.reset(new method_t); 981 982 for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) 983 { 984 method->Read(process, base_method_list->m_first_ptr + (i * base_method_list->m_entsize)); 985 986 if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) 987 break; 988 } 989 } 990 991 if (class_method_func) 992 { 993 ClassDescriptorV2 metaclass(m_runtime, objc_class->m_isa, NULL); // The metaclass is not in the cache 994 995 // We don't care about the metaclass's superclass, or its class methods. Its instance methods are 996 // our class methods. 997 998 metaclass.Describe(std::function <void (ObjCLanguageRuntime::ObjCISA)> (nullptr), 999 class_method_func, 1000 std::function <bool (const char *, const char *)> (nullptr), 1001 std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> (nullptr)); 1002 } 1003 1004 if (ivar_func) 1005 { 1006 ivar_list_t ivar_list; 1007 if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) 1008 return false; 1009 1010 if (ivar_list.m_entsize != ivar_t::GetSize(process)) 1011 return false; 1012 1013 ivar_t ivar; 1014 1015 for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) 1016 { 1017 ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); 1018 1019 if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), ivar.m_offset_ptr, ivar.m_size)) 1020 break; 1021 } 1022 } 1023 1024 return true; 1025 } 1026 1027 virtual 1028 ~ClassDescriptorV2 () 1029 { 1030 } 1031 1032 private: 1033 static const uint32_t RW_REALIZED = (1 << 31); 1034 1035 struct objc_class_t { 1036 ObjCLanguageRuntime::ObjCISA m_isa; // The class's metaclass. 1037 ObjCLanguageRuntime::ObjCISA m_superclass; 1038 lldb::addr_t m_cache_ptr; 1039 lldb::addr_t m_vtable_ptr; 1040 lldb::addr_t m_data_ptr; 1041 uint8_t m_flags; 1042 1043 objc_class_t () : 1044 m_isa (0), 1045 m_superclass (0), 1046 m_cache_ptr (0), 1047 m_vtable_ptr (0), 1048 m_data_ptr (0), 1049 m_flags (0) 1050 { 1051 } 1052 1053 void 1054 Clear() 1055 { 1056 m_isa = 0; 1057 m_superclass = 0; 1058 m_cache_ptr = 0; 1059 m_vtable_ptr = 0; 1060 m_data_ptr = 0; 1061 m_flags = 0; 1062 } 1063 1064 bool Read(Process *process, lldb::addr_t addr) 1065 { 1066 size_t ptr_size = process->GetAddressByteSize(); 1067 1068 size_t objc_class_size = ptr_size // uintptr_t isa; 1069 + ptr_size // Class superclass; 1070 + ptr_size // void *cache; 1071 + ptr_size // IMP *vtable; 1072 + ptr_size; // uintptr_t data_NEVER_USE; 1073 1074 DataBufferHeap objc_class_buf (objc_class_size, '\0'); 1075 Error error; 1076 1077 process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); 1078 if (error.Fail()) 1079 { 1080 return false; 1081 } 1082 1083 DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, process->GetByteOrder(), process->GetAddressByteSize()); 1084 1085 lldb::offset_t cursor = 0; 1086 1087 m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; 1088 m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; 1089 m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; 1090 m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; 1091 lldb::addr_t data_NEVER_USE = extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; 1092 1093 m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); 1094 m_data_ptr = data_NEVER_USE & ~(lldb::addr_t)3; 1095 1096 return true; 1097 } 1098 }; 1099 1100 struct class_ro_t { 1101 uint32_t m_flags; 1102 uint32_t m_instanceStart; 1103 uint32_t m_instanceSize; 1104 uint32_t m_reserved; 1105 1106 lldb::addr_t m_ivarLayout_ptr; 1107 lldb::addr_t m_name_ptr; 1108 lldb::addr_t m_baseMethods_ptr; 1109 lldb::addr_t m_baseProtocols_ptr; 1110 lldb::addr_t m_ivars_ptr; 1111 1112 lldb::addr_t m_weakIvarLayout_ptr; 1113 lldb::addr_t m_baseProperties_ptr; 1114 1115 std::string m_name; 1116 1117 bool Read(Process *process, lldb::addr_t addr) 1118 { 1119 size_t ptr_size = process->GetAddressByteSize(); 1120 1121 size_t size = sizeof(uint32_t) // uint32_t flags; 1122 + sizeof(uint32_t) // uint32_t instanceStart; 1123 + sizeof(uint32_t) // uint32_t instanceSize; 1124 + (ptr_size == 8 ? sizeof(uint32_t) : 0) // uint32_t reserved; // __LP64__ only 1125 + ptr_size // const uint8_t *ivarLayout; 1126 + ptr_size // const char *name; 1127 + ptr_size // const method_list_t *baseMethods; 1128 + ptr_size // const protocol_list_t *baseProtocols; 1129 + ptr_size // const ivar_list_t *ivars; 1130 + ptr_size // const uint8_t *weakIvarLayout; 1131 + ptr_size; // const property_list_t *baseProperties; 1132 1133 DataBufferHeap buffer (size, '\0'); 1134 Error error; 1135 1136 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1137 if (error.Fail()) 1138 { 1139 return false; 1140 } 1141 1142 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1143 1144 lldb::offset_t cursor = 0; 1145 1146 m_flags = extractor.GetU32_unchecked(&cursor); 1147 m_instanceStart = extractor.GetU32_unchecked(&cursor); 1148 m_instanceSize = extractor.GetU32_unchecked(&cursor); 1149 if (ptr_size == 8) 1150 m_reserved = extractor.GetU32_unchecked(&cursor); 1151 else 1152 m_reserved = 0; 1153 m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); 1154 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 1155 m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); 1156 m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); 1157 m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); 1158 m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); 1159 m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); 1160 1161 DataBufferHeap name_buf(1024, '\0'); 1162 1163 process->ReadCStringFromMemory(m_name_ptr, (char*)name_buf.GetBytes(), name_buf.GetByteSize(), error); 1164 1165 if (error.Fail()) 1166 { 1167 return false; 1168 } 1169 1170 m_name.assign((char*)name_buf.GetBytes()); 1171 1172 return true; 1173 } 1174 }; 1175 1176 struct class_rw_t { 1177 uint32_t m_flags; 1178 uint32_t m_version; 1179 1180 lldb::addr_t m_ro_ptr; 1181 union { 1182 lldb::addr_t m_method_list_ptr; 1183 lldb::addr_t m_method_lists_ptr; 1184 }; 1185 lldb::addr_t m_properties_ptr; 1186 lldb::addr_t m_protocols_ptr; 1187 1188 ObjCLanguageRuntime::ObjCISA m_firstSubclass; 1189 ObjCLanguageRuntime::ObjCISA m_nextSiblingClass; 1190 1191 bool Read(Process *process, lldb::addr_t addr) 1192 { 1193 size_t ptr_size = process->GetAddressByteSize(); 1194 1195 size_t size = sizeof(uint32_t) // uint32_t flags; 1196 + sizeof(uint32_t) // uint32_t version; 1197 + ptr_size // const class_ro_t *ro; 1198 + ptr_size // union { method_list_t **method_lists; method_list_t *method_list; }; 1199 + ptr_size // struct chained_property_list *properties; 1200 + ptr_size // const protocol_list_t **protocols; 1201 + ptr_size // Class firstSubclass; 1202 + ptr_size; // Class nextSiblingClass; 1203 1204 DataBufferHeap buffer (size, '\0'); 1205 Error error; 1206 1207 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1208 if (error.Fail()) 1209 { 1210 return false; 1211 } 1212 1213 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1214 1215 lldb::offset_t cursor = 0; 1216 1217 m_flags = extractor.GetU32_unchecked(&cursor); 1218 m_version = extractor.GetU32_unchecked(&cursor); 1219 m_ro_ptr = extractor.GetAddress_unchecked(&cursor); 1220 m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); 1221 m_properties_ptr = extractor.GetAddress_unchecked(&cursor); 1222 m_firstSubclass = extractor.GetAddress_unchecked(&cursor); 1223 m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); 1224 1225 return true; 1226 } 1227 }; 1228 1229 struct method_list_t 1230 { 1231 uint32_t m_entsize; 1232 uint32_t m_count; 1233 lldb::addr_t m_first_ptr; 1234 1235 bool Read(Process *process, lldb::addr_t addr) 1236 { 1237 size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; 1238 + sizeof(uint32_t); // uint32_t count; 1239 1240 DataBufferHeap buffer (size, '\0'); 1241 Error error; 1242 1243 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1244 if (error.Fail()) 1245 { 1246 return false; 1247 } 1248 1249 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1250 1251 lldb::offset_t cursor = 0; 1252 1253 m_entsize = extractor.GetU32_unchecked(&cursor) & ~(uint32_t)3; 1254 m_count = extractor.GetU32_unchecked(&cursor); 1255 m_first_ptr = addr + cursor; 1256 1257 return true; 1258 } 1259 }; 1260 1261 struct method_t 1262 { 1263 lldb::addr_t m_name_ptr; 1264 lldb::addr_t m_types_ptr; 1265 lldb::addr_t m_imp_ptr; 1266 1267 std::string m_name; 1268 std::string m_types; 1269 1270 static size_t GetSize(Process *process) 1271 { 1272 size_t ptr_size = process->GetAddressByteSize(); 1273 1274 return ptr_size // SEL name; 1275 + ptr_size // const char *types; 1276 + ptr_size; // IMP imp; 1277 } 1278 1279 bool Read(Process *process, lldb::addr_t addr) 1280 { 1281 size_t size = GetSize(process); 1282 1283 DataBufferHeap buffer (size, '\0'); 1284 Error error; 1285 1286 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1287 if (error.Fail()) 1288 { 1289 return false; 1290 } 1291 1292 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1293 1294 lldb::offset_t cursor = 0; 1295 1296 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 1297 m_types_ptr = extractor.GetAddress_unchecked(&cursor); 1298 m_imp_ptr = extractor.GetAddress_unchecked(&cursor); 1299 1300 const size_t buffer_size = 1024; 1301 size_t count; 1302 1303 DataBufferHeap string_buf(buffer_size, 0); 1304 1305 count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); 1306 m_name.assign((char*)string_buf.GetBytes(), count); 1307 1308 count = process->ReadCStringFromMemory(m_types_ptr, (char*)string_buf.GetBytes(), buffer_size, error); 1309 m_types.assign((char*)string_buf.GetBytes(), count); 1310 1311 return true; 1312 } 1313 }; 1314 1315 struct ivar_list_t 1316 { 1317 uint32_t m_entsize; 1318 uint32_t m_count; 1319 lldb::addr_t m_first_ptr; 1320 1321 bool Read(Process *process, lldb::addr_t addr) 1322 { 1323 size_t size = sizeof(uint32_t) // uint32_t entsize; 1324 + sizeof(uint32_t); // uint32_t count; 1325 1326 DataBufferHeap buffer (size, '\0'); 1327 Error error; 1328 1329 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1330 if (error.Fail()) 1331 { 1332 return false; 1333 } 1334 1335 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1336 1337 lldb::offset_t cursor = 0; 1338 1339 m_entsize = extractor.GetU32_unchecked(&cursor); 1340 m_count = extractor.GetU32_unchecked(&cursor); 1341 m_first_ptr = addr + cursor; 1342 1343 return true; 1344 } 1345 }; 1346 1347 struct ivar_t 1348 { 1349 lldb::addr_t m_offset_ptr; 1350 lldb::addr_t m_name_ptr; 1351 lldb::addr_t m_type_ptr; 1352 uint32_t m_alignment; 1353 uint32_t m_size; 1354 1355 std::string m_name; 1356 std::string m_type; 1357 1358 static size_t GetSize(Process *process) 1359 { 1360 size_t ptr_size = process->GetAddressByteSize(); 1361 1362 return ptr_size // uintptr_t *offset; 1363 + ptr_size // const char *name; 1364 + ptr_size // const char *type; 1365 + sizeof(uint32_t) // uint32_t alignment; 1366 + sizeof(uint32_t); // uint32_t size; 1367 } 1368 1369 bool Read(Process *process, lldb::addr_t addr) 1370 { 1371 size_t size = GetSize(process); 1372 1373 DataBufferHeap buffer (size, '\0'); 1374 Error error; 1375 1376 process->ReadMemory(addr, buffer.GetBytes(), size, error); 1377 if (error.Fail()) 1378 { 1379 return false; 1380 } 1381 1382 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), process->GetAddressByteSize()); 1383 1384 lldb::offset_t cursor = 0; 1385 1386 m_offset_ptr = extractor.GetAddress_unchecked(&cursor); 1387 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 1388 m_type_ptr = extractor.GetAddress_unchecked(&cursor); 1389 m_alignment = extractor.GetU32_unchecked(&cursor); 1390 m_size = extractor.GetU32_unchecked(&cursor); 1391 1392 const size_t buffer_size = 1024; 1393 size_t count; 1394 1395 DataBufferHeap string_buf(buffer_size, 0); 1396 1397 count = process->ReadCStringFromMemory(m_name_ptr, (char*)string_buf.GetBytes(), buffer_size, error); 1398 m_name.assign((char*)string_buf.GetBytes(), count); 1399 1400 count = process->ReadCStringFromMemory(m_type_ptr, (char*)string_buf.GetBytes(), buffer_size, error); 1401 m_type.assign((char*)string_buf.GetBytes(), count); 1402 1403 return true; 1404 } 1405 }; 1406 1407 bool Read_objc_class (Process* process, std::unique_ptr<objc_class_t> &objc_class) 1408 { 1409 objc_class.reset(new objc_class_t); 1410 1411 bool ret = objc_class->Read (process, m_objc_class_ptr); 1412 1413 if (!ret) 1414 objc_class.reset(); 1415 1416 return ret; 1417 } 1418 1419 bool Read_class_row (Process* process, const objc_class_t &objc_class, std::unique_ptr<class_ro_t> &class_ro, std::unique_ptr<class_rw_t> &class_rw) 1420 { 1421 class_ro.reset(); 1422 class_rw.reset(); 1423 1424 Error error; 1425 uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory(objc_class.m_data_ptr, sizeof(uint32_t), 0, error); 1426 if (!error.Success()) 1427 return false; 1428 1429 if (class_row_t_flags & RW_REALIZED) 1430 { 1431 class_rw.reset(new class_rw_t); 1432 1433 if (!class_rw->Read(process, objc_class.m_data_ptr)) 1434 { 1435 class_rw.reset(); 1436 return false; 1437 } 1438 1439 class_ro.reset(new class_ro_t); 1440 1441 if (!class_ro->Read(process, class_rw->m_ro_ptr)) 1442 { 1443 class_rw.reset(); 1444 class_ro.reset(); 1445 return false; 1446 } 1447 } 1448 else 1449 { 1450 class_ro.reset(new class_ro_t); 1451 1452 if (!class_ro->Read(process, objc_class.m_data_ptr)) 1453 { 1454 class_ro.reset(); 1455 return false; 1456 } 1457 } 1458 1459 return true; 1460 } 1461 1462 AppleObjCRuntimeV2 &m_runtime; // The runtime, so we can read information lazily. 1463 lldb::addr_t m_objc_class_ptr; // The address of the objc_class_t. (I.e., objects of this class type have this as their ISA) 1464 ConstString m_name; // May be NULL 1465 }; 1466 1467 // tagged pointer descriptor 1468 class ClassDescriptorV2Tagged : public ObjCLanguageRuntime::ClassDescriptor 1469 { 1470 public: 1471 ClassDescriptorV2Tagged (ConstString class_name, 1472 uint64_t payload) 1473 { 1474 m_name = class_name; 1475 if (!m_name) 1476 { 1477 m_valid = false; 1478 return; 1479 } 1480 m_valid = true; 1481 m_payload = payload; 1482 m_info_bits = (m_payload & 0xF0ULL) >> 4; 1483 m_value_bits = (m_payload & ~0x0000000000000000FFULL) >> 8; 1484 } 1485 1486 ClassDescriptorV2Tagged (ObjCLanguageRuntime::ClassDescriptorSP actual_class_sp, 1487 uint64_t payload) 1488 { 1489 if (!actual_class_sp) 1490 { 1491 m_valid = false; 1492 return; 1493 } 1494 m_name = actual_class_sp->GetClassName(); 1495 if (!m_name) 1496 { 1497 m_valid = false; 1498 return; 1499 } 1500 m_valid = true; 1501 m_payload = payload; 1502 m_info_bits = (m_payload & 0x0FULL); 1503 m_value_bits = (m_payload & ~0x0FULL) >> 4; 1504 } 1505 1506 virtual ConstString 1507 GetClassName () 1508 { 1509 return m_name; 1510 } 1511 1512 virtual ObjCLanguageRuntime::ClassDescriptorSP 1513 GetSuperclass () 1514 { 1515 // tagged pointers can represent a class that has a superclass, but since that information is not 1516 // stored in the object itself, we would have to query the runtime to discover the hierarchy 1517 // for the time being, we skip this step in the interest of static discovery 1518 return ObjCLanguageRuntime::ClassDescriptorSP(); 1519 } 1520 1521 virtual bool 1522 IsValid () 1523 { 1524 return m_valid; 1525 } 1526 1527 virtual bool 1528 IsKVO () 1529 { 1530 return false; // tagged pointers are not KVO'ed 1531 } 1532 1533 virtual bool 1534 IsCFType () 1535 { 1536 return false; // tagged pointers are not CF objects 1537 } 1538 1539 virtual bool 1540 GetTaggedPointerInfo (uint64_t* info_bits = NULL, 1541 uint64_t* value_bits = NULL, 1542 uint64_t* payload = NULL) 1543 { 1544 if (info_bits) 1545 *info_bits = GetInfoBits(); 1546 if (value_bits) 1547 *value_bits = GetValueBits(); 1548 if (payload) 1549 *payload = GetPayload(); 1550 return true; 1551 } 1552 1553 virtual uint64_t 1554 GetInstanceSize () 1555 { 1556 return (IsValid() ? m_pointer_size : 0); 1557 } 1558 1559 virtual ObjCLanguageRuntime::ObjCISA 1560 GetISA () 1561 { 1562 return 0; // tagged pointers have no ISA 1563 } 1564 1565 // these calls are not part of any formal tagged pointers specification 1566 virtual uint64_t 1567 GetValueBits () 1568 { 1569 return (IsValid() ? m_value_bits : 0); 1570 } 1571 1572 virtual uint64_t 1573 GetInfoBits () 1574 { 1575 return (IsValid() ? m_info_bits : 0); 1576 } 1577 1578 virtual uint64_t 1579 GetPayload () 1580 { 1581 return (IsValid() ? m_payload : 0); 1582 } 1583 1584 virtual 1585 ~ClassDescriptorV2Tagged () 1586 {} 1587 1588 private: 1589 ConstString m_name; 1590 uint8_t m_pointer_size; 1591 bool m_valid; 1592 uint64_t m_info_bits; 1593 uint64_t m_value_bits; 1594 uint64_t m_payload; 1595 1596 }; 1597 1598 ObjCLanguageRuntime::ClassDescriptorSP 1599 AppleObjCRuntimeV2::GetClassDescriptor (ObjCISA isa) 1600 { 1601 ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp; 1602 if (m_non_pointer_isa_cache_ap.get()) 1603 class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa); 1604 if (!class_descriptor_sp) 1605 class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa); 1606 return class_descriptor_sp; 1607 } 1608 1609 ObjCLanguageRuntime::ClassDescriptorSP 1610 AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj) 1611 { 1612 ClassDescriptorSP objc_class_sp; 1613 // if we get an invalid VO (which might still happen when playing around 1614 // with pointers returned by the expression parser, don't consider this 1615 // a valid ObjC object) 1616 if (valobj.GetClangType().IsValid()) 1617 { 1618 addr_t isa_pointer = valobj.GetPointerValue(); 1619 1620 // tagged pointer 1621 if (IsTaggedPointer(isa_pointer)) 1622 { 1623 return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer); 1624 } 1625 else 1626 { 1627 ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 1628 1629 Process *process = exe_ctx.GetProcessPtr(); 1630 if (process) 1631 { 1632 Error error; 1633 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); 1634 if (isa != LLDB_INVALID_ADDRESS) 1635 { 1636 objc_class_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA (isa); 1637 if (isa && !objc_class_sp) 1638 { 1639 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 1640 if (log) 1641 log->Printf("0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was not in class descriptor cache 0x%" PRIx64, 1642 isa_pointer, 1643 isa); 1644 } 1645 } 1646 } 1647 } 1648 } 1649 return objc_class_sp; 1650 } 1651 1652 lldb::addr_t 1653 AppleObjCRuntimeV2::GetISAHashTablePointer () 1654 { 1655 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) 1656 { 1657 Process *process = GetProcess(); 1658 1659 ModuleSP objc_module_sp(GetObjCModule()); 1660 1661 if (!objc_module_sp) 1662 return LLDB_INVALID_ADDRESS; 1663 1664 static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes"); 1665 1666 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_objc_realized_classes, lldb::eSymbolTypeData); 1667 if (symbol) 1668 { 1669 lldb::addr_t gdb_objc_realized_classes_ptr = symbol->GetAddress().GetLoadAddress(&process->GetTarget()); 1670 1671 if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) 1672 { 1673 Error error; 1674 m_isa_hash_table_ptr = process->ReadPointerFromMemory(gdb_objc_realized_classes_ptr, error); 1675 } 1676 } 1677 } 1678 return m_isa_hash_table_ptr; 1679 } 1680 1681 bool 1682 AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table) 1683 { 1684 Process *process = GetProcess(); 1685 1686 if (process == NULL) 1687 return false; 1688 1689 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 1690 1691 ExecutionContext exe_ctx; 1692 1693 ThreadSP thread_sp = process->GetThreadList().GetSelectedThread(); 1694 1695 if (!thread_sp) 1696 return false; 1697 1698 thread_sp->CalculateExecutionContext(exe_ctx); 1699 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1700 1701 if (!ast) 1702 return false; 1703 1704 Address function_address; 1705 1706 StreamString errors; 1707 1708 const uint32_t addr_size = process->GetAddressByteSize(); 1709 1710 Error err; 1711 1712 // Read the total number of classes from the hash table 1713 const uint32_t num_classes = hash_table.GetCount(); 1714 if (num_classes == 0) 1715 { 1716 if (log) 1717 log->Printf ("No dynamic classes found in gdb_objc_realized_classes."); 1718 return false; 1719 } 1720 1721 // Make some types for our arguments 1722 ClangASTType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); 1723 ClangASTType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1724 1725 if (!m_get_class_info_code.get()) 1726 { 1727 m_get_class_info_code.reset (new ClangUtilityFunction (g_get_dynamic_class_info_body, 1728 g_get_dynamic_class_info_name)); 1729 1730 errors.Clear(); 1731 1732 if (!m_get_class_info_code->Install(errors, exe_ctx)) 1733 { 1734 if (log) 1735 log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); 1736 m_get_class_info_code.reset(); 1737 } 1738 } 1739 1740 if (m_get_class_info_code.get()) 1741 function_address.SetOffset(m_get_class_info_code->StartAddress()); 1742 else 1743 return false; 1744 1745 ValueList arguments; 1746 1747 // Next make the runner function for our implementation utility function. 1748 if (!m_get_class_info_function.get()) 1749 { 1750 Value value; 1751 value.SetValueType (Value::eValueTypeScalar); 1752 // value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); 1753 value.SetClangType (clang_void_pointer_type); 1754 arguments.PushValue (value); 1755 arguments.PushValue (value); 1756 1757 value.SetValueType (Value::eValueTypeScalar); 1758 // value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); 1759 value.SetClangType (clang_uint32_t_type); 1760 arguments.PushValue (value); 1761 1762 m_get_class_info_function.reset(new ClangFunction (*m_process, 1763 clang_uint32_t_type, 1764 function_address, 1765 arguments)); 1766 1767 if (m_get_class_info_function.get() == NULL) 1768 return false; 1769 1770 errors.Clear(); 1771 1772 unsigned num_errors = m_get_class_info_function->CompileFunction(errors); 1773 if (num_errors) 1774 { 1775 if (log) 1776 log->Printf ("Error compiling function: \"%s\".", errors.GetData()); 1777 return false; 1778 } 1779 1780 errors.Clear(); 1781 1782 if (!m_get_class_info_function->WriteFunctionWrapper(exe_ctx, errors)) 1783 { 1784 if (log) 1785 log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); 1786 return false; 1787 } 1788 } 1789 else 1790 { 1791 arguments = m_get_class_info_function->GetArgumentValues (); 1792 } 1793 1794 const uint32_t class_info_byte_size = addr_size + 4; 1795 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; 1796 lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size, 1797 ePermissionsReadable | ePermissionsWritable, 1798 err); 1799 1800 if (class_infos_addr == LLDB_INVALID_ADDRESS) 1801 return false; 1802 1803 Mutex::Locker locker(m_get_class_info_args_mutex); 1804 1805 // Fill in our function argument values 1806 arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress(); 1807 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; 1808 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; 1809 1810 bool success = false; 1811 1812 errors.Clear(); 1813 1814 // Write our function arguments into the process so we can run our function 1815 if (m_get_class_info_function->WriteFunctionArguments (exe_ctx, 1816 m_get_class_info_args, 1817 function_address, 1818 arguments, 1819 errors)) 1820 { 1821 bool stop_others = true; 1822 bool try_all_threads = false; 1823 bool unwind_on_error = true; 1824 bool ignore_breakpoints = true; 1825 1826 Value return_value; 1827 return_value.SetValueType (Value::eValueTypeScalar); 1828 //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); 1829 return_value.SetClangType (clang_uint32_t_type); 1830 return_value.GetScalar() = 0; 1831 1832 errors.Clear(); 1833 1834 // Run the function 1835 ExecutionResults results = m_get_class_info_function->ExecuteFunction (exe_ctx, 1836 &m_get_class_info_args, 1837 errors, 1838 stop_others, 1839 UTILITY_FUNCTION_TIMEOUT_USEC, 1840 try_all_threads, 1841 unwind_on_error, 1842 ignore_breakpoints, 1843 return_value); 1844 1845 if (results == eExecutionCompleted) 1846 { 1847 // The result is the number of ClassInfo structures that were filled in 1848 uint32_t num_class_infos = return_value.GetScalar().ULong(); 1849 if (log) 1850 log->Printf("Discovered %u ObjC classes\n",num_class_infos); 1851 if (num_class_infos > 0) 1852 { 1853 // Read the ClassInfo structures 1854 DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0); 1855 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize()) 1856 { 1857 DataExtractor class_infos_data (buffer.GetBytes(), 1858 buffer.GetByteSize(), 1859 process->GetByteOrder(), 1860 addr_size); 1861 ParseClassInfoArray (class_infos_data, num_class_infos); 1862 } 1863 } 1864 success = true; 1865 } 1866 else 1867 { 1868 if (log) 1869 log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData()); 1870 } 1871 } 1872 else 1873 { 1874 if (log) 1875 log->Printf ("Error writing function arguments: \"%s\".", errors.GetData()); 1876 } 1877 1878 // Deallocate the memory we allocated for the ClassInfo array 1879 process->DeallocateMemory(class_infos_addr); 1880 1881 return success; 1882 } 1883 1884 void 1885 AppleObjCRuntimeV2::ParseClassInfoArray (const DataExtractor &data, uint32_t num_class_infos) 1886 { 1887 // Parses an array of "num_class_infos" packed ClassInfo structures: 1888 // 1889 // struct ClassInfo 1890 // { 1891 // Class isa; 1892 // uint32_t hash; 1893 // } __attribute__((__packed__)); 1894 1895 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 1896 1897 // Iterate through all ClassInfo structures 1898 lldb::offset_t offset = 0; 1899 for (uint32_t i=0; i<num_class_infos; ++i) 1900 { 1901 ObjCISA isa = data.GetPointer(&offset); 1902 1903 if (isa == 0) 1904 { 1905 if (log) 1906 log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info"); 1907 continue; 1908 } 1909 // Check if we already know about this ISA, if we do, the info will 1910 // never change, so we can just skip it. 1911 if (ISAIsCached(isa)) 1912 { 1913 offset += 4; 1914 } 1915 else 1916 { 1917 // Read the 32 bit hash for the class name 1918 const uint32_t name_hash = data.GetU32(&offset); 1919 ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL)); 1920 AddClass (isa, descriptor_sp, name_hash); 1921 if (log && log->GetVerbose()) 1922 log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x", isa, name_hash); 1923 } 1924 } 1925 } 1926 1927 bool 1928 AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache() 1929 { 1930 Process *process = GetProcess(); 1931 1932 if (process == NULL) 1933 return false; 1934 1935 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 1936 1937 ExecutionContext exe_ctx; 1938 1939 ThreadSP thread_sp = process->GetThreadList().GetSelectedThread(); 1940 1941 if (!thread_sp) 1942 return false; 1943 1944 thread_sp->CalculateExecutionContext(exe_ctx); 1945 ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext(); 1946 1947 if (!ast) 1948 return false; 1949 1950 Address function_address; 1951 1952 StreamString errors; 1953 1954 const uint32_t addr_size = process->GetAddressByteSize(); 1955 1956 Error err; 1957 1958 const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress(); 1959 1960 if (objc_opt_ptr == LLDB_INVALID_ADDRESS) 1961 return false; 1962 1963 // Read the total number of classes from the hash table 1964 const uint32_t num_classes = 16*1024; 1965 if (num_classes == 0) 1966 { 1967 if (log) 1968 log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr."); 1969 return false; 1970 } 1971 1972 // Make some types for our arguments 1973 ClangASTType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32); 1974 ClangASTType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType(); 1975 1976 if (!m_get_shared_cache_class_info_code.get()) 1977 { 1978 m_get_shared_cache_class_info_code.reset (new ClangUtilityFunction (g_get_shared_cache_class_info_body, 1979 g_get_shared_cache_class_info_name)); 1980 1981 errors.Clear(); 1982 1983 if (!m_get_shared_cache_class_info_code->Install(errors, exe_ctx)) 1984 { 1985 if (log) 1986 log->Printf ("Failed to install implementation lookup: %s.", errors.GetData()); 1987 m_get_shared_cache_class_info_code.reset(); 1988 } 1989 } 1990 1991 if (m_get_shared_cache_class_info_code.get()) 1992 function_address.SetOffset(m_get_shared_cache_class_info_code->StartAddress()); 1993 else 1994 return false; 1995 1996 ValueList arguments; 1997 1998 // Next make the runner function for our implementation utility function. 1999 if (!m_get_shared_cache_class_info_function.get()) 2000 { 2001 Value value; 2002 value.SetValueType (Value::eValueTypeScalar); 2003 //value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type); 2004 value.SetClangType (clang_void_pointer_type); 2005 arguments.PushValue (value); 2006 arguments.PushValue (value); 2007 2008 value.SetValueType (Value::eValueTypeScalar); 2009 //value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); 2010 value.SetClangType (clang_uint32_t_type); 2011 arguments.PushValue (value); 2012 2013 m_get_shared_cache_class_info_function.reset(new ClangFunction (*m_process, 2014 clang_uint32_t_type, 2015 function_address, 2016 arguments)); 2017 2018 if (m_get_shared_cache_class_info_function.get() == NULL) 2019 return false; 2020 2021 errors.Clear(); 2022 2023 unsigned num_errors = m_get_shared_cache_class_info_function->CompileFunction(errors); 2024 if (num_errors) 2025 { 2026 if (log) 2027 log->Printf ("Error compiling function: \"%s\".", errors.GetData()); 2028 return false; 2029 } 2030 2031 errors.Clear(); 2032 2033 if (!m_get_shared_cache_class_info_function->WriteFunctionWrapper(exe_ctx, errors)) 2034 { 2035 if (log) 2036 log->Printf ("Error Inserting function: \"%s\".", errors.GetData()); 2037 return false; 2038 } 2039 } 2040 else 2041 { 2042 arguments = m_get_shared_cache_class_info_function->GetArgumentValues (); 2043 } 2044 2045 const uint32_t class_info_byte_size = addr_size + 4; 2046 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size; 2047 lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size, 2048 ePermissionsReadable | ePermissionsWritable, 2049 err); 2050 2051 if (class_infos_addr == LLDB_INVALID_ADDRESS) 2052 return false; 2053 2054 Mutex::Locker locker(m_get_shared_cache_class_info_args_mutex); 2055 2056 // Fill in our function argument values 2057 arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr; 2058 arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr; 2059 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size; 2060 2061 bool success = false; 2062 2063 errors.Clear(); 2064 2065 // Write our function arguments into the process so we can run our function 2066 if (m_get_shared_cache_class_info_function->WriteFunctionArguments (exe_ctx, 2067 m_get_shared_cache_class_info_args, 2068 function_address, 2069 arguments, 2070 errors)) 2071 { 2072 bool stop_others = true; 2073 bool try_all_threads = false; 2074 bool unwind_on_error = true; 2075 bool ignore_breakpoints = true; 2076 2077 Value return_value; 2078 return_value.SetValueType (Value::eValueTypeScalar); 2079 //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type); 2080 return_value.SetClangType (clang_uint32_t_type); 2081 return_value.GetScalar() = 0; 2082 2083 errors.Clear(); 2084 2085 // Run the function 2086 ExecutionResults results = m_get_shared_cache_class_info_function->ExecuteFunction (exe_ctx, 2087 &m_get_shared_cache_class_info_args, 2088 errors, 2089 stop_others, 2090 UTILITY_FUNCTION_TIMEOUT_USEC, 2091 try_all_threads, 2092 unwind_on_error, 2093 ignore_breakpoints, 2094 return_value); 2095 2096 if (results == eExecutionCompleted) 2097 { 2098 // The result is the number of ClassInfo structures that were filled in 2099 uint32_t num_class_infos = return_value.GetScalar().ULong(); 2100 if (log) 2101 log->Printf("Discovered %u ObjC classes in shared cache\n",num_class_infos); 2102 if (num_class_infos > 0) 2103 { 2104 // Read the ClassInfo structures 2105 DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0); 2106 if (process->ReadMemory(class_infos_addr, 2107 buffer.GetBytes(), 2108 buffer.GetByteSize(), 2109 err) == buffer.GetByteSize()) 2110 { 2111 DataExtractor class_infos_data (buffer.GetBytes(), 2112 buffer.GetByteSize(), 2113 process->GetByteOrder(), 2114 addr_size); 2115 2116 ParseClassInfoArray (class_infos_data, num_class_infos); 2117 } 2118 } 2119 success = true; 2120 } 2121 else 2122 { 2123 if (log) 2124 log->Printf("Error evaluating our find class name function: %s.\n", errors.GetData()); 2125 } 2126 } 2127 else 2128 { 2129 if (log) 2130 log->Printf ("Error writing function arguments: \"%s\".", errors.GetData()); 2131 } 2132 2133 // Deallocate the memory we allocated for the ClassInfo array 2134 process->DeallocateMemory(class_infos_addr); 2135 2136 return success; 2137 } 2138 2139 2140 bool 2141 AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table) 2142 { 2143 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 2144 2145 Process *process = GetProcess(); 2146 2147 if (process == NULL) 2148 return false; 2149 2150 uint32_t num_map_table_isas = 0; 2151 2152 ModuleSP objc_module_sp(GetObjCModule()); 2153 2154 if (objc_module_sp) 2155 { 2156 for (RemoteNXMapTable::element elt : hash_table) 2157 { 2158 ++num_map_table_isas; 2159 2160 if (ISAIsCached(elt.second)) 2161 continue; 2162 2163 ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString())); 2164 2165 if (log && log->GetVerbose()) 2166 log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString()); 2167 2168 AddClass (elt.second, descriptor_sp, elt.first.AsCString()); 2169 } 2170 } 2171 2172 return num_map_table_isas > 0; 2173 } 2174 2175 lldb::addr_t 2176 AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() 2177 { 2178 Process *process = GetProcess(); 2179 2180 if (process) 2181 { 2182 ModuleSP objc_module_sp(GetObjCModule()); 2183 2184 if (objc_module_sp) 2185 { 2186 ObjectFile *objc_object = objc_module_sp->GetObjectFile(); 2187 2188 if (objc_object) 2189 { 2190 SectionList *section_list = objc_module_sp->GetSectionList(); 2191 2192 if (section_list) 2193 { 2194 SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT"))); 2195 2196 if (text_segment_sp) 2197 { 2198 SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro"))); 2199 2200 if (objc_opt_section_sp) 2201 { 2202 return objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget()); 2203 } 2204 } 2205 } 2206 } 2207 } 2208 } 2209 return LLDB_INVALID_ADDRESS; 2210 } 2211 2212 void 2213 AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() 2214 { 2215 Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__); 2216 2217 // Else we need to check with our process to see when the map was updated. 2218 Process *process = GetProcess(); 2219 2220 if (process) 2221 { 2222 RemoteNXMapTable hash_table; 2223 2224 // Update the process stop ID that indicates the last time we updated the 2225 // map, wether it was successful or not. 2226 m_isa_to_descriptor_stop_id = process->GetStopID(); 2227 2228 if (!m_hash_signature.NeedsUpdate(process, this, hash_table)) 2229 return; 2230 2231 m_hash_signature.UpdateSignature (hash_table); 2232 2233 // Grab the dynamicly loaded objc classes from the hash table in memory 2234 UpdateISAToDescriptorMapDynamic(hash_table); 2235 2236 // Now get the objc classes that are baked into the Objective C runtime 2237 // in the shared cache, but only once per process as this data never 2238 // changes 2239 if (!m_loaded_objc_opt) 2240 UpdateISAToDescriptorMapSharedCache(); 2241 } 2242 else 2243 { 2244 m_isa_to_descriptor_stop_id = UINT32_MAX; 2245 } 2246 } 2247 2248 2249 // TODO: should we have a transparent_kvo parameter here to say if we 2250 // want to replace the KVO swizzled class with the actual user-level type? 2251 ConstString 2252 AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) 2253 { 2254 if (isa == g_objc_Tagged_ISA) 2255 { 2256 static const ConstString g_objc_tagged_isa_name ("_lldb_Tagged_ObjC_ISA"); 2257 return g_objc_tagged_isa_name; 2258 } 2259 if (isa == g_objc_Tagged_ISA_NSAtom) 2260 { 2261 static const ConstString g_objc_tagged_isa_nsatom_name ("NSAtom"); 2262 return g_objc_tagged_isa_nsatom_name; 2263 } 2264 if (isa == g_objc_Tagged_ISA_NSNumber) 2265 { 2266 static const ConstString g_objc_tagged_isa_nsnumber_name ("NSNumber"); 2267 return g_objc_tagged_isa_nsnumber_name; 2268 } 2269 if (isa == g_objc_Tagged_ISA_NSDateTS) 2270 { 2271 static const ConstString g_objc_tagged_isa_nsdatets_name ("NSDateTS"); 2272 return g_objc_tagged_isa_nsdatets_name; 2273 } 2274 if (isa == g_objc_Tagged_ISA_NSManagedObject) 2275 { 2276 static const ConstString g_objc_tagged_isa_nsmanagedobject_name ("NSManagedObject"); 2277 return g_objc_tagged_isa_nsmanagedobject_name; 2278 } 2279 if (isa == g_objc_Tagged_ISA_NSDate) 2280 { 2281 static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate"); 2282 return g_objc_tagged_isa_nsdate_name; 2283 } 2284 return ObjCLanguageRuntime::GetActualTypeName(isa); 2285 } 2286 2287 TypeVendor * 2288 AppleObjCRuntimeV2::GetTypeVendor() 2289 { 2290 if (!m_type_vendor_ap.get()) 2291 m_type_vendor_ap.reset(new AppleObjCTypeVendor(*this)); 2292 2293 return m_type_vendor_ap.get(); 2294 } 2295 2296 lldb::addr_t 2297 AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name) 2298 { 2299 lldb::addr_t ret = LLDB_INVALID_ADDRESS; 2300 2301 const char *name_cstr = name.AsCString(); 2302 2303 if (name_cstr) 2304 { 2305 llvm::StringRef name_strref(name_cstr); 2306 2307 static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_"); 2308 static const llvm::StringRef class_prefix("OBJC_CLASS_$_"); 2309 2310 if (name_strref.startswith(ivar_prefix)) 2311 { 2312 llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size()); 2313 std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.'); 2314 2315 if (class_and_ivar.first.size() && class_and_ivar.second.size()) 2316 { 2317 const ConstString class_name_cs(class_and_ivar.first); 2318 ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs); 2319 2320 if (descriptor) 2321 { 2322 const ConstString ivar_name_cs(class_and_ivar.second); 2323 const char *ivar_name_cstr = ivar_name_cs.AsCString(); 2324 2325 auto ivar_func = [&ret, ivar_name_cstr](const char *name, const char *type, lldb::addr_t offset_addr, uint64_t size) -> lldb::addr_t 2326 { 2327 if (!strcmp(name, ivar_name_cstr)) 2328 { 2329 ret = offset_addr; 2330 return true; 2331 } 2332 return false; 2333 }; 2334 2335 descriptor->Describe(std::function<void (ObjCISA)>(nullptr), 2336 std::function<bool (const char *, const char *)>(nullptr), 2337 std::function<bool (const char *, const char *)>(nullptr), 2338 ivar_func); 2339 } 2340 } 2341 } 2342 else if (name_strref.startswith(class_prefix)) 2343 { 2344 llvm::StringRef class_skipped_prefix = name_strref.substr(class_prefix.size()); 2345 const ConstString class_name_cs(class_skipped_prefix); 2346 ClassDescriptorSP descriptor = GetClassDescriptorFromClassName(class_name_cs); 2347 2348 if (descriptor) 2349 ret = descriptor->GetISA(); 2350 } 2351 } 2352 2353 return ret; 2354 } 2355 2356 AppleObjCRuntimeV2::NonPointerISACache* 2357 AppleObjCRuntimeV2::NonPointerISACache::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp) 2358 { 2359 Process* process(runtime.GetProcess()); 2360 2361 Error error; 2362 2363 auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(process, 2364 ConstString("objc_debug_isa_magic_mask"), 2365 objc_module_sp, 2366 error); 2367 if (error.Fail()) 2368 return NULL; 2369 2370 auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(process, 2371 ConstString("objc_debug_isa_magic_value"), 2372 objc_module_sp, 2373 error); 2374 if (error.Fail()) 2375 return NULL; 2376 2377 auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(process, 2378 ConstString("objc_debug_isa_class_mask"), 2379 objc_module_sp, 2380 error); 2381 if (error.Fail()) 2382 return NULL; 2383 2384 // 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, ...) 2385 2386 return new NonPointerISACache(runtime, 2387 objc_debug_isa_class_mask, 2388 objc_debug_isa_magic_mask, 2389 objc_debug_isa_magic_value); 2390 } 2391 2392 AppleObjCRuntimeV2::TaggedPointerVendor* 2393 AppleObjCRuntimeV2::TaggedPointerVendor::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp) 2394 { 2395 Process* process(runtime.GetProcess()); 2396 2397 Error error; 2398 2399 auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(process, 2400 ConstString("objc_debug_taggedpointer_mask"), 2401 objc_module_sp, 2402 error); 2403 if (error.Fail()) 2404 return new TaggedPointerVendorLegacy(runtime); 2405 2406 auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(process, 2407 ConstString("objc_debug_taggedpointer_slot_shift"), 2408 objc_module_sp, 2409 error, 2410 true, 2411 4); 2412 if (error.Fail()) 2413 return new TaggedPointerVendorLegacy(runtime); 2414 2415 auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(process, 2416 ConstString("objc_debug_taggedpointer_slot_mask"), 2417 objc_module_sp, 2418 error, 2419 true, 2420 4); 2421 if (error.Fail()) 2422 return new TaggedPointerVendorLegacy(runtime); 2423 2424 auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(process, 2425 ConstString("objc_debug_taggedpointer_payload_lshift"), 2426 objc_module_sp, 2427 error, 2428 true, 2429 4); 2430 if (error.Fail()) 2431 return new TaggedPointerVendorLegacy(runtime); 2432 2433 auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(process, 2434 ConstString("objc_debug_taggedpointer_payload_rshift"), 2435 objc_module_sp, 2436 error, 2437 true, 2438 4); 2439 if (error.Fail()) 2440 return new TaggedPointerVendorLegacy(runtime); 2441 2442 auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(process, 2443 ConstString("objc_debug_taggedpointer_classes"), 2444 objc_module_sp, 2445 error, 2446 false); 2447 if (error.Fail()) 2448 return new TaggedPointerVendorLegacy(runtime); 2449 2450 2451 // we might want to have some rules to outlaw these values (e.g if the table's address is zero) 2452 2453 return new TaggedPointerVendorRuntimeAssisted(runtime, 2454 objc_debug_taggedpointer_mask, 2455 objc_debug_taggedpointer_slot_shift, 2456 objc_debug_taggedpointer_slot_mask, 2457 objc_debug_taggedpointer_payload_lshift, 2458 objc_debug_taggedpointer_payload_rshift, 2459 objc_debug_taggedpointer_classes); 2460 } 2461 2462 bool 2463 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer (lldb::addr_t ptr) 2464 { 2465 return (ptr & 1); 2466 } 2467 2468 // we use the version of Foundation to make assumptions about the ObjC runtime on a target 2469 uint32_t 2470 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetFoundationVersion (Target &target) 2471 { 2472 const ModuleList& modules = target.GetImages(); 2473 uint32_t major = UINT32_MAX; 2474 for (uint32_t idx = 0; idx < modules.GetSize(); idx++) 2475 { 2476 lldb::ModuleSP module_sp = modules.GetModuleAtIndex(idx); 2477 if (!module_sp) 2478 continue; 2479 if (strcmp(module_sp->GetFileSpec().GetFilename().AsCString(""),"Foundation") == 0) 2480 { 2481 module_sp->GetVersion(&major,1); 2482 break; 2483 } 2484 } 2485 return major; 2486 } 2487 2488 ObjCLanguageRuntime::ClassDescriptorSP 2489 AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor (lldb::addr_t ptr) 2490 { 2491 if (!IsPossibleTaggedPointer(ptr)) 2492 return ObjCLanguageRuntime::ClassDescriptorSP(); 2493 2494 Process* process(m_runtime.GetProcess()); 2495 2496 if (m_Foundation_version == 0) 2497 m_Foundation_version = GetFoundationVersion(process->GetTarget()); 2498 2499 if (m_Foundation_version == UINT32_MAX) 2500 return ObjCLanguageRuntime::ClassDescriptorSP(); 2501 2502 uint64_t class_bits = (ptr & 0xE) >> 1; 2503 ConstString name; 2504 2505 // TODO: make a table 2506 if (m_Foundation_version >= 900) 2507 { 2508 switch (class_bits) 2509 { 2510 case 0: 2511 name = ConstString("NSAtom"); 2512 break; 2513 case 3: 2514 name = ConstString("NSNumber"); 2515 break; 2516 case 4: 2517 name = ConstString("NSDateTS"); 2518 break; 2519 case 5: 2520 name = ConstString("NSManagedObject"); 2521 break; 2522 case 6: 2523 name = ConstString("NSDate"); 2524 break; 2525 default: 2526 return ObjCLanguageRuntime::ClassDescriptorSP(); 2527 } 2528 } 2529 else 2530 { 2531 switch (class_bits) 2532 { 2533 case 1: 2534 name = ConstString("NSNumber"); 2535 break; 2536 case 5: 2537 name = ConstString("NSManagedObject"); 2538 break; 2539 case 6: 2540 name = ConstString("NSDate"); 2541 break; 2542 case 7: 2543 name = ConstString("NSDateTS"); 2544 break; 2545 default: 2546 return ObjCLanguageRuntime::ClassDescriptorSP(); 2547 } 2548 } 2549 return ClassDescriptorSP(new ClassDescriptorV2Tagged(name,ptr)); 2550 } 2551 2552 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime, 2553 uint64_t objc_debug_taggedpointer_mask, 2554 uint32_t objc_debug_taggedpointer_slot_shift, 2555 uint32_t objc_debug_taggedpointer_slot_mask, 2556 uint32_t objc_debug_taggedpointer_payload_lshift, 2557 uint32_t objc_debug_taggedpointer_payload_rshift, 2558 lldb::addr_t objc_debug_taggedpointer_classes) : 2559 TaggedPointerVendor(runtime), 2560 m_cache(), 2561 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask), 2562 m_objc_debug_taggedpointer_slot_shift(objc_debug_taggedpointer_slot_shift), 2563 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask), 2564 m_objc_debug_taggedpointer_payload_lshift(objc_debug_taggedpointer_payload_lshift), 2565 m_objc_debug_taggedpointer_payload_rshift(objc_debug_taggedpointer_payload_rshift), 2566 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) 2567 { 2568 } 2569 2570 bool 2571 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::IsPossibleTaggedPointer (lldb::addr_t ptr) 2572 { 2573 return (ptr & m_objc_debug_taggedpointer_mask) != 0; 2574 } 2575 2576 ObjCLanguageRuntime::ClassDescriptorSP 2577 AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor (lldb::addr_t ptr) 2578 { 2579 ClassDescriptorSP actual_class_descriptor_sp; 2580 uint64_t data_payload; 2581 2582 if (!IsPossibleTaggedPointer(ptr)) 2583 return ObjCLanguageRuntime::ClassDescriptorSP(); 2584 2585 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & m_objc_debug_taggedpointer_slot_mask; 2586 2587 CacheIterator iterator = m_cache.find(slot), 2588 end = m_cache.end(); 2589 if (iterator != end) 2590 { 2591 actual_class_descriptor_sp = iterator->second; 2592 } 2593 else 2594 { 2595 Process* process(m_runtime.GetProcess()); 2596 uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_classes; 2597 Error error; 2598 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error); 2599 if (error.Fail() || slot_data == 0 || slot_data == LLDB_INVALID_ADDRESS) 2600 return nullptr; 2601 actual_class_descriptor_sp = m_runtime.GetClassDescriptor(slot_data); 2602 if (!actual_class_descriptor_sp) 2603 return ObjCLanguageRuntime::ClassDescriptorSP(); 2604 m_cache[slot] = actual_class_descriptor_sp; 2605 } 2606 2607 data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift); 2608 2609 return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload)); 2610 } 2611 2612 AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache (AppleObjCRuntimeV2& runtime, 2613 uint64_t objc_debug_isa_class_mask, 2614 uint64_t objc_debug_isa_magic_mask, 2615 uint64_t objc_debug_isa_magic_value) : 2616 m_runtime(runtime), 2617 m_cache(), 2618 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask), 2619 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask), 2620 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value) 2621 { 2622 } 2623 2624 ObjCLanguageRuntime::ClassDescriptorSP 2625 AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor (ObjCISA isa) 2626 { 2627 ObjCISA real_isa = 0; 2628 if (EvaluateNonPointerISA(isa, real_isa) == false) 2629 return ObjCLanguageRuntime::ClassDescriptorSP(); 2630 auto cache_iter = m_cache.find(real_isa); 2631 if (cache_iter != m_cache.end()) 2632 return cache_iter->second; 2633 auto descriptor_sp = m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa); 2634 if (descriptor_sp) // cache only positive matches since the table might grow 2635 m_cache[real_isa] = descriptor_sp; 2636 return descriptor_sp; 2637 } 2638 2639 bool 2640 AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa) 2641 { 2642 if ( (isa & ~m_objc_debug_isa_class_mask) == 0) 2643 return false; 2644 if ( (isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) 2645 { 2646 ret_isa = isa & m_objc_debug_isa_class_mask; 2647 return (ret_isa != 0); // this is a pointer so 0 is not a valid value 2648 } 2649 return false; 2650 } 2651