3555 lines · cpp
1//===-- AppleObjCRuntimeV2.cpp --------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"10#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"11 12#include "lldb/Core/Debugger.h"13#include "lldb/Core/DebuggerEvents.h"14#include "lldb/Core/Module.h"15#include "lldb/Core/PluginManager.h"16#include "lldb/Core/Section.h"17#include "lldb/Expression/DiagnosticManager.h"18#include "lldb/Expression/FunctionCaller.h"19#include "lldb/Expression/UtilityFunction.h"20#include "lldb/Host/OptionParser.h"21#include "lldb/Interpreter/CommandObject.h"22#include "lldb/Interpreter/CommandObjectMultiword.h"23#include "lldb/Interpreter/CommandReturnObject.h"24#include "lldb/Interpreter/OptionArgParser.h"25#include "lldb/Interpreter/OptionValueBoolean.h"26#include "lldb/Symbol/CompilerType.h"27#include "lldb/Symbol/ObjectFile.h"28#include "lldb/Symbol/Symbol.h"29#include "lldb/Symbol/TypeList.h"30#include "lldb/Symbol/VariableList.h"31#include "lldb/Target/ABI.h"32#include "lldb/Target/DynamicLoader.h"33#include "lldb/Target/ExecutionContext.h"34#include "lldb/Target/LanguageRuntime.h"35#include "lldb/Target/Platform.h"36#include "lldb/Target/Process.h"37#include "lldb/Target/RegisterContext.h"38#include "lldb/Target/StackFrameRecognizer.h"39#include "lldb/Target/Target.h"40#include "lldb/Target/Thread.h"41#include "lldb/Utility/ConstString.h"42#include "lldb/Utility/LLDBLog.h"43#include "lldb/Utility/Log.h"44#include "lldb/Utility/Scalar.h"45#include "lldb/Utility/Status.h"46#include "lldb/Utility/Stream.h"47#include "lldb/Utility/StreamString.h"48#include "lldb/Utility/Timer.h"49#include "lldb/ValueObject/ValueObjectConstResult.h"50#include "lldb/ValueObject/ValueObjectVariable.h"51#include "lldb/lldb-enumerations.h"52 53#include "AppleObjCClassDescriptorV2.h"54#include "AppleObjCDeclVendor.h"55#include "AppleObjCRuntimeV2.h"56#include "AppleObjCTrampolineHandler.h"57#include "AppleObjCTypeEncodingParser.h"58 59#include "clang/AST/ASTContext.h"60#include "clang/AST/DeclObjC.h"61#include "clang/Basic/TargetInfo.h"62#include "llvm/ADT/ScopeExit.h"63 64#include <cstdint>65#include <memory>66#include <string>67#include <vector>68 69using namespace lldb;70using namespace lldb_private;71 72char AppleObjCRuntimeV2::ID = 0;73 74static const char *g_get_dynamic_class_info_name =75 "__lldb_apple_objc_v2_get_dynamic_class_info";76 77static const char *g_get_dynamic_class_info_body = R"(78 79extern "C"80{81 size_t strlen(const char *);82 char *strncpy (char * s1, const char * s2, size_t n);83 int printf(const char * format, ...);84}85#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)86 87typedef struct _NXMapTable {88 void *prototype;89 unsigned num_classes;90 unsigned num_buckets_minus_one;91 void *buckets;92} NXMapTable;93 94#define NX_MAPNOTAKEY ((void *)(-1))95 96typedef struct BucketInfo97{98 const char *name_ptr;99 Class isa;100} BucketInfo;101 102struct ClassInfo103{104 Class isa;105 uint32_t hash;106} __attribute__((__packed__));107 108uint32_t109__lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,110 void *class_infos_ptr,111 uint32_t class_infos_byte_size,112 uint32_t should_log)113{114 DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);115 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);116 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);117 const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;118 if (grc)119 {120 const unsigned num_classes = grc->num_classes;121 DEBUG_PRINTF ("num_classes = %u\n", grc->num_classes);122 if (class_infos_ptr)123 {124 const unsigned num_buckets_minus_one = grc->num_buckets_minus_one;125 DEBUG_PRINTF ("num_buckets_minus_one = %u\n", num_buckets_minus_one);126 127 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);128 DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);129 130 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;131 BucketInfo *buckets = (BucketInfo *)grc->buckets;132 133 uint32_t idx = 0;134 for (unsigned i=0; i<=num_buckets_minus_one; ++i)135 {136 if (buckets[i].name_ptr != NX_MAPNOTAKEY)137 {138 if (idx < max_class_infos)139 {140 const char *s = buckets[i].name_ptr;141 uint32_t h = 5381;142 for (unsigned char c = *s; c; c = *++s)143 h = ((h << 5) + h) + c;144 class_infos[idx].hash = h;145 class_infos[idx].isa = buckets[i].isa;146 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, buckets[i].name_ptr);147 }148 ++idx;149 }150 }151 if (idx < max_class_infos)152 {153 class_infos[idx].isa = NULL;154 class_infos[idx].hash = 0;155 }156 }157 return num_classes;158 }159 return 0;160}161 162)";163 164static const char *g_get_dynamic_class_info2_name =165 "__lldb_apple_objc_v2_get_dynamic_class_info2";166 167static const char *g_get_dynamic_class_info2_body = R"(168 169extern "C" {170 int printf(const char * format, ...);171 void free(void *ptr);172 Class* objc_copyRealizedClassList_nolock(unsigned int *outCount);173 const char* objc_debug_class_getNameRaw(Class cls);174}175 176#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)177 178struct ClassInfo179{180 Class isa;181 uint32_t hash;182} __attribute__((__packed__));183 184uint32_t185__lldb_apple_objc_v2_get_dynamic_class_info2(void *gdb_objc_realized_classes_ptr,186 void *class_infos_ptr,187 uint32_t class_infos_byte_size,188 uint32_t should_log)189{190 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);191 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);192 193 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);194 DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);195 196 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;197 198 uint32_t count = 0;199 Class* realized_class_list = objc_copyRealizedClassList_nolock(&count);200 DEBUG_PRINTF ("count = %u\n", count);201 202 uint32_t idx = 0;203 for (uint32_t i=0; i<count; ++i)204 {205 if (idx < max_class_infos)206 {207 Class isa = realized_class_list[i];208 const char *name_ptr = objc_debug_class_getNameRaw(isa);209 if (!name_ptr)210 continue;211 const char *s = name_ptr;212 uint32_t h = 5381;213 for (unsigned char c = *s; c; c = *++s)214 h = ((h << 5) + h) + c;215 class_infos[idx].hash = h;216 class_infos[idx].isa = isa;217 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);218 }219 idx++;220 }221 222 if (idx < max_class_infos)223 {224 class_infos[idx].isa = NULL;225 class_infos[idx].hash = 0;226 }227 228 free(realized_class_list);229 return count;230}231)";232 233static const char *g_get_dynamic_class_info3_name =234 "__lldb_apple_objc_v2_get_dynamic_class_info3";235 236static const char *g_get_dynamic_class_info3_body = R"(237 238extern "C" {239 int printf(const char * format, ...);240 void free(void *ptr);241 size_t objc_getRealizedClassList_trylock(Class *buffer, size_t len);242 const char* objc_debug_class_getNameRaw(Class cls);243 const char* class_getName(Class cls);244}245 246#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)247 248struct ClassInfo249{250 Class isa;251 uint32_t hash;252} __attribute__((__packed__));253 254uint32_t255__lldb_apple_objc_v2_get_dynamic_class_info3(void *gdb_objc_realized_classes_ptr,256 void *class_infos_ptr,257 uint32_t class_infos_byte_size,258 void *class_buffer,259 uint32_t class_buffer_len,260 uint32_t should_log)261{262 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);263 DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);264 265 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);266 DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);267 268 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;269 270 Class *realized_class_list = (Class*)class_buffer;271 272 uint32_t count = objc_getRealizedClassList_trylock(realized_class_list,273 class_buffer_len);274 DEBUG_PRINTF ("count = %u\n", count);275 276 uint32_t idx = 0;277 for (uint32_t i=0; i<count; ++i)278 {279 if (idx < max_class_infos)280 {281 Class isa = realized_class_list[i];282 const char *name_ptr = objc_debug_class_getNameRaw(isa);283 if (!name_ptr) {284 class_getName(isa); // Realize name of lazy classes.285 name_ptr = objc_debug_class_getNameRaw(isa);286 }287 if (!name_ptr)288 continue;289 const char *s = name_ptr;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 class_infos[idx].isa = isa;295 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);296 }297 idx++;298 }299 300 if (idx < max_class_infos)301 {302 class_infos[idx].isa = NULL;303 class_infos[idx].hash = 0;304 }305 306 return count;307}308)";309 310// We'll substitute in class_getName or class_getNameRaw depending311// on which is present.312static const char *g_shared_cache_class_name_funcptr = R"(313extern "C"314{315 const char *%s(void *objc_class);316 const char *(*class_name_lookup_func)(void *) = %s;317}318)";319 320static const char *g_get_shared_cache_class_info_name =321 "__lldb_apple_objc_v2_get_shared_cache_class_info";322 323static const char *g_get_shared_cache_class_info_definitions = R"(324 325extern "C"326{327 size_t strlen(const char *);328 char *strncpy (char * s1, const char * s2, size_t n);329 int printf(const char * format, ...);330}331 332#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)333 334 335struct objc_classheader_t {336 int32_t clsOffset;337 int32_t hiOffset;338};339 340struct objc_classheader_v16_t {341 uint64_t isDuplicate : 1,342 objectCacheOffset : 47, // Offset from the shared cache base343 dylibObjCIndex : 16;344};345 346struct objc_clsopt_t {347 uint32_t capacity;348 uint32_t occupied;349 uint32_t shift;350 uint32_t mask;351 uint32_t zero;352 uint32_t unused;353 uint64_t salt;354 uint32_t scramble[256];355 uint8_t tab[0]; // tab[mask+1]356 // uint8_t checkbytes[capacity];357 // int32_t offset[capacity];358 // objc_classheader_t clsOffsets[capacity];359 // uint32_t duplicateCount;360 // objc_classheader_t duplicateOffsets[duplicateCount];361};362 363struct objc_clsopt_v16_t {364 uint32_t version;365 uint32_t capacity;366 uint32_t occupied;367 uint32_t shift;368 uint32_t mask;369 uint32_t zero;370 uint64_t salt;371 uint32_t scramble[256];372 uint8_t tab[0]; // tab[mask+1]373 // uint8_t checkbytes[capacity];374 // int32_t offset[capacity];375 // objc_classheader_t clsOffsets[capacity];376 // uint32_t duplicateCount;377 // objc_classheader_t duplicateOffsets[duplicateCount];378};379 380struct objc_opt_t {381 uint32_t version;382 int32_t selopt_offset;383 int32_t headeropt_offset;384 int32_t clsopt_offset;385};386 387struct objc_opt_v14_t {388 uint32_t version;389 uint32_t flags;390 int32_t selopt_offset;391 int32_t headeropt_offset;392 int32_t clsopt_offset;393};394 395struct objc_opt_v16_t {396 uint32_t version;397 uint32_t flags;398 int32_t selopt_offset;399 int32_t headeropt_ro_offset;400 int32_t unused_clsopt_offset;401 int32_t unused_protocolopt_offset;402 int32_t headeropt_rw_offset;403 int32_t unused_protocolopt2_offset;404 int32_t largeSharedCachesClassOffset;405 int32_t largeSharedCachesProtocolOffset;406 uint64_t relativeMethodSelectorBaseAddressCacheOffset;407};408 409struct ClassInfo410{411 Class isa;412 uint32_t hash;413} __attribute__((__packed__));414)";415 416static const char *g_get_shared_cache_class_info_body = R"(417 418uint32_t419__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,420 void *shared_cache_base_ptr,421 void *class_infos_ptr,422 uint64_t *relative_selector_offset,423 uint32_t class_infos_byte_size,424 uint32_t *start_idx,425 uint32_t should_log)426{427 *relative_selector_offset = 0;428 uint32_t idx = 0;429 DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);430 DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);431 DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);432 DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));433 DEBUG_PRINTF ("start_idx = %u\n", *start_idx);434 if (objc_opt_ro_ptr)435 {436 const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;437 const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;438 const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr;439 if (objc_opt->version >= 16)440 {441 *relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset;442 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version);443 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags);444 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset);445 DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset);446 DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset);447 }448 else if (objc_opt->version >= 14)449 {450 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);451 DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);452 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);453 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);454 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);455 }456 else457 {458 DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);459 DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);460 DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);461 DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);462 }463 464 if (objc_opt->version == 16)465 {466 int32_t large_offset = objc_opt_v16->largeSharedCachesClassOffset;467 const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + large_offset);468 // Work around a bug in some version shared cache builder where the offset overflows 2GiB (rdar://146432183).469 uint32_t unsigned_offset = (uint32_t)large_offset;470 if (unsigned_offset > 0x7fffffff && unsigned_offset < 0x82000000) {471 clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + unsigned_offset);472 DEBUG_PRINTF("warning: applying largeSharedCachesClassOffset overflow workaround!\n");473 }474 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);475 476 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);477 478 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;479 480 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];481 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);482 const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity);483 484 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);485 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);486 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);487 488 const uint32_t original_start_idx = *start_idx;489 490 // Always start at the start_idx here. If it's greater than the capacity,491 // it will skip the loop entirely and go to the duplicate handling below.492 for (uint32_t i=*start_idx; i<clsopt->capacity; ++i)493 {494 const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;495 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);496 497 if (classOffsets[i].isDuplicate) {498 DEBUG_PRINTF("isDuplicate = true\n");499 continue; // duplicate500 }501 502 if (objectCacheOffset == 0) {503 DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");504 continue; // invalid offset505 }506 507 if (class_infos && idx < max_class_infos)508 {509 class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);510 511 // Lookup the class name.512 const char *name = class_name_lookup_func(class_infos[idx].isa);513 DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);514 515 // Hash the class name so we don't have to read it.516 const char *s = name;517 uint32_t h = 5381;518 for (unsigned char c = *s; c; c = *++s)519 {520 // class_getName demangles swift names and the hash must521 // be calculated on the mangled name. hash==0 means lldb522 // will fetch the mangled name and compute the hash in523 // ParseClassInfoArray.524 if (c == '.')525 {526 h = 0;527 break;528 }529 h = ((h << 5) + h) + c;530 }531 class_infos[idx].hash = h;532 }533 else534 {535 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");536 *start_idx = i;537 break;538 }539 ++idx;540 }541 542 if (idx < max_class_infos) {543 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];544 const uint32_t duplicate_count = *duplicate_count_ptr;545 const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);546 547 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);548 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);549 550 const uint32_t duplicate_start_idx =551 *start_idx < clsopt->capacity ?552 0 :553 *start_idx - clsopt->capacity;554 555 for (uint32_t i=duplicate_start_idx; i<duplicate_count; ++i)556 {557 const uint64_t objectCacheOffset = duplicateClassOffsets[i].objectCacheOffset;558 DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);559 560 if (duplicateClassOffsets[i].isDuplicate) {561 DEBUG_PRINTF("isDuplicate = true\n");562 continue; // duplicate563 }564 565 if (objectCacheOffset == 0) {566 DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");567 continue; // invalid offset568 }569 570 if (class_infos && idx < max_class_infos)571 {572 class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);573 574 // Lookup the class name.575 const char *name = class_name_lookup_func(class_infos[idx].isa);576 DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);577 578 // Hash the class name so we don't have to read it.579 const char *s = name;580 uint32_t h = 5381;581 for (unsigned char c = *s; c; c = *++s)582 {583 // class_getName demangles swift names and the hash must584 // be calculated on the mangled name. hash==0 means lldb585 // will fetch the mangled name and compute the hash in586 // ParseClassInfoArray.587 if (c == '.')588 {589 h = 0;590 break;591 }592 h = ((h << 5) + h) + c;593 }594 class_infos[idx].hash = h;595 } else {596 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");597 *start_idx = i;598 break;599 }600 ++idx;601 }602 }603 // Always make sure start_idx gets updated. Otherwise we have an infinite604 // loop if there are exactly max_class_infos number of classes.605 if (*start_idx == original_start_idx) {606 *start_idx = idx;607 }608 }609 else if (objc_opt->version >= 12 && objc_opt->version <= 15)610 {611 const objc_clsopt_t* clsopt = NULL;612 if (objc_opt->version >= 14)613 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);614 else615 clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);616 const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);617 DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);618 ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;619 int32_t invalidEntryOffset = 0;620 // this is safe to do because the version field order is invariant621 if (objc_opt->version == 12)622 invalidEntryOffset = 16;623 const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];624 const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);625 const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);626 DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);627 DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);628 DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);629 DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);630 for (uint32_t i=0; i<clsopt->capacity; ++i)631 {632 const int32_t clsOffset = classOffsets[i].clsOffset;633 DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);634 if (clsOffset & 1)635 {636 DEBUG_PRINTF("clsOffset & 1\n");637 continue; // duplicate638 }639 else if (clsOffset == invalidEntryOffset)640 {641 DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");642 continue; // invalid offset643 }644 645 if (class_infos && idx < max_class_infos)646 {647 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);648 const char *name = class_name_lookup_func (class_infos[idx].isa);649 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);650 // Hash the class name so we don't have to read it651 const char *s = name;652 uint32_t h = 5381;653 for (unsigned char c = *s; c; c = *++s)654 {655 // class_getName demangles swift names and the hash must656 // be calculated on the mangled name. hash==0 means lldb657 // will fetch the mangled name and compute the hash in658 // ParseClassInfoArray.659 if (c == '.')660 {661 h = 0;662 break;663 }664 h = ((h << 5) + h) + c;665 }666 class_infos[idx].hash = h;667 }668 else669 {670 DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");671 }672 ++idx;673 }674 675 const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];676 const uint32_t duplicate_count = *duplicate_count_ptr;677 const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);678 DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);679 DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);680 for (uint32_t i=0; i<duplicate_count; ++i)681 {682 const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;683 if (clsOffset & 1)684 continue; // duplicate685 else if (clsOffset == invalidEntryOffset)686 continue; // invalid offset687 688 if (class_infos && idx < max_class_infos)689 {690 class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);691 const char *name = class_name_lookup_func (class_infos[idx].isa);692 DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);693 // Hash the class name so we don't have to read it694 const char *s = name;695 uint32_t h = 5381;696 for (unsigned char c = *s; c; c = *++s)697 {698 // class_getName demangles swift names and the hash must699 // be calculated on the mangled name. hash==0 means lldb700 // will fetch the mangled name and compute the hash in701 // ParseClassInfoArray.702 if (c == '.')703 {704 h = 0;705 break;706 }707 h = ((h << 5) + h) + c;708 }709 class_infos[idx].hash = h;710 }711 ++idx;712 }713 }714 DEBUG_PRINTF ("%u class_infos\n", idx);715 DEBUG_PRINTF ("done\n");716 }717 return idx;718}719 720 721)";722 723static uint64_t724ExtractRuntimeGlobalSymbol(Process *process, ConstString name,725 const ModuleSP &module_sp, Status &error,726 bool read_value = true, uint8_t byte_size = 0,727 uint64_t default_value = LLDB_INVALID_ADDRESS,728 SymbolType sym_type = lldb::eSymbolTypeData) {729 if (!process) {730 error = Status::FromErrorString("no process");731 return default_value;732 }733 734 if (!module_sp) {735 error = Status::FromErrorString("no module");736 return default_value;737 }738 739 if (!byte_size)740 byte_size = process->GetAddressByteSize();741 const Symbol *symbol =742 module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);743 744 if (!symbol || !symbol->ValueIsAddress()) {745 error = Status::FromErrorString("no symbol");746 return default_value;747 }748 749 lldb::addr_t symbol_load_addr =750 symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());751 if (symbol_load_addr == LLDB_INVALID_ADDRESS) {752 error = Status::FromErrorString("symbol address invalid");753 return default_value;754 }755 756 if (read_value)757 return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size,758 default_value, error);759 return symbol_load_addr;760}761 762static void RegisterObjCExceptionRecognizer(Process *process);763 764AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,765 const ModuleSP &objc_module_sp)766 : AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp),767 m_dynamic_class_info_extractor(*this),768 m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),769 m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),770 m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),771 m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),772 m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),773 m_has_objc_getRealizedClassList_trylock(false), m_loaded_objc_opt(false),774 m_non_pointer_isa_cache_up(),775 m_tagged_pointer_vendor_up(776 TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),777 m_encoding_to_type_sp(), m_CFBoolean_values(),778 m_realized_class_generation_count(0) {779 static const ConstString g_gdb_object_getClass("gdb_object_getClass");780 m_has_object_getClass = HasSymbol(g_gdb_object_getClass);781 static const ConstString g_objc_copyRealizedClassList(782 "_ZL33objc_copyRealizedClassList_nolockPj");783 static const ConstString g_objc_getRealizedClassList_trylock(784 "_objc_getRealizedClassList_trylock");785 m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList);786 m_has_objc_getRealizedClassList_trylock =787 HasSymbol(g_objc_getRealizedClassList_trylock);788 WarnIfNoExpandedSharedCache();789 RegisterObjCExceptionRecognizer(process);790}791 792LanguageRuntime *793AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) {794 if (auto process_sp = in_value.GetProcessSP()) {795 assert(process_sp.get() == m_process);796 if (auto descriptor_sp = GetNonKVOClassDescriptor(in_value)) {797 LanguageType impl_lang = descriptor_sp->GetImplementationLanguage();798 if (impl_lang != eLanguageTypeUnknown)799 return process_sp->GetLanguageRuntime(impl_lang);800 }801 }802 return nullptr;803}804 805bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(806 ValueObject &in_value, lldb::DynamicValueType use_dynamic,807 TypeAndOrName &class_type_or_name, Address &address,808 Value::ValueType &value_type, llvm::ArrayRef<uint8_t> &local_buffer) {809 // We should never get here with a null process...810 assert(m_process != nullptr);811 812 // The Runtime is attached to a particular process, you shouldn't pass in a813 // value from another process. Note, however, the process might be NULL (e.g.814 // if the value was made with SBTarget::EvaluateExpression...) in which case815 // it is sufficient if the target's match:816 817 Process *process = in_value.GetProcessSP().get();818 if (process)819 assert(process == m_process);820 else821 assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get());822 823 class_type_or_name.Clear();824 value_type = Value::ValueType::Scalar;825 826 // Make sure we can have a dynamic value before starting...827 if (CouldHaveDynamicValue(in_value)) {828 // First job, pull out the address at 0 offset from the object That will829 // be the ISA pointer.830 ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value));831 if (objc_class_sp) {832 const addr_t object_ptr = in_value.GetPointerValue().address;833 address.SetRawAddress(object_ptr);834 835 ConstString class_name(objc_class_sp->GetClassName());836 class_type_or_name.SetName(class_name);837 TypeSP type_sp(objc_class_sp->GetType());838 if (type_sp)839 class_type_or_name.SetTypeSP(type_sp);840 else {841 type_sp = LookupInCompleteClassCache(class_name);842 if (type_sp) {843 objc_class_sp->SetType(type_sp);844 class_type_or_name.SetTypeSP(type_sp);845 } else {846 // try to go for a CompilerType at least847 if (auto *vendor = GetDeclVendor()) {848 auto types = vendor->FindTypes(class_name, /*max_matches*/ 1);849 if (!types.empty())850 class_type_or_name.SetCompilerType(types.front());851 }852 }853 }854 }855 }856 return !class_type_or_name.IsEmpty();857}858 859// Static Functions860LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process,861 LanguageType language) {862 // FIXME: This should be a MacOS or iOS process, and we need to look for the863 // OBJC section to make864 // sure we aren't using the V1 runtime.865 if (language == eLanguageTypeObjC) {866 ModuleSP objc_module_sp;867 868 if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==869 ObjCRuntimeVersions::eAppleObjC_V2)870 return new AppleObjCRuntimeV2(process, objc_module_sp);871 return nullptr;872 }873 return nullptr;874}875 876static constexpr OptionDefinition g_objc_classtable_dump_options[] = {877 {LLDB_OPT_SET_ALL,878 false,879 "verbose",880 'v',881 OptionParser::eNoArgument,882 nullptr,883 {},884 0,885 eArgTypeNone,886 "Print ivar and method information in detail"}};887 888class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {889public:890 class CommandOptions : public Options {891 public:892 CommandOptions() : Options(), m_verbose(false, false) {}893 894 ~CommandOptions() override = default;895 896 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,897 ExecutionContext *execution_context) override {898 Status error;899 const int short_option = m_getopt_table[option_idx].val;900 switch (short_option) {901 case 'v':902 m_verbose.SetCurrentValue(true);903 m_verbose.SetOptionWasSet();904 break;905 906 default:907 error = Status::FromErrorStringWithFormat(908 "unrecognized short option '%c'", short_option);909 break;910 }911 912 return error;913 }914 915 void OptionParsingStarting(ExecutionContext *execution_context) override {916 m_verbose.Clear();917 }918 919 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {920 return llvm::ArrayRef(g_objc_classtable_dump_options);921 }922 923 OptionValueBoolean m_verbose;924 };925 926 CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter)927 : CommandObjectParsed(interpreter, "dump",928 "Dump information on Objective-C classes "929 "known to the current process.",930 "language objc class-table dump",931 eCommandRequiresProcess |932 eCommandProcessMustBeLaunched |933 eCommandProcessMustBePaused),934 m_options() {935 AddSimpleArgumentList(eArgTypeRegularExpression, eArgRepeatOptional);936 }937 938 ~CommandObjectObjC_ClassTable_Dump() override = default;939 940 Options *GetOptions() override { return &m_options; }941 942protected:943 void DoExecute(Args &command, CommandReturnObject &result) override {944 std::unique_ptr<RegularExpression> regex_up;945 switch (command.GetArgumentCount()) {946 case 0:947 break;948 case 1: {949 regex_up =950 std::make_unique<RegularExpression>(command.GetArgumentAtIndex(0));951 if (!regex_up->IsValid()) {952 result.AppendError(953 "invalid argument - please provide a valid regular expression");954 result.SetStatus(lldb::eReturnStatusFailed);955 return;956 }957 break;958 }959 default: {960 result.AppendError("please provide 0 or 1 arguments");961 result.SetStatus(lldb::eReturnStatusFailed);962 return;963 }964 }965 966 Process *process = m_exe_ctx.GetProcessPtr();967 ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);968 if (objc_runtime) {969 auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();970 auto iterator = iterators_pair.first;971 auto &std_out = result.GetOutputStream();972 for (; iterator != iterators_pair.second; iterator++) {973 if (iterator->second) {974 const char *class_name =975 iterator->second->GetClassName().AsCString("<unknown>");976 if (regex_up && class_name &&977 !regex_up->Execute(llvm::StringRef(class_name)))978 continue;979 std_out.Printf("isa = 0x%" PRIx64, iterator->first);980 std_out.Printf(" name = %s", class_name);981 std_out.Printf(" instance size = %" PRIu64,982 iterator->second->GetInstanceSize());983 std_out.Printf(" num ivars = %" PRIuPTR,984 (uintptr_t)iterator->second->GetNumIVars());985 if (auto superclass = iterator->second->GetSuperclass()) {986 std_out.Printf(" superclass = %s",987 superclass->GetClassName().AsCString("<unknown>"));988 }989 std_out.Printf("\n");990 if (m_options.m_verbose) {991 for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) {992 auto ivar = iterator->second->GetIVarAtIndex(i);993 std_out.Printf(994 " ivar name = %s type = %s size = %" PRIu64995 " offset = %" PRId32 "\n",996 ivar.m_name.AsCString("<unknown>"),997 ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),998 ivar.m_size, ivar.m_offset);999 }1000 1001 iterator->second->Describe(1002 nullptr,1003 [&std_out](const char *name, const char *type) -> bool {1004 std_out.Printf(" instance method name = %s type = %s\n",1005 name, type);1006 return false;1007 },1008 [&std_out](const char *name, const char *type) -> bool {1009 std_out.Printf(" class method name = %s type = %s\n", name,1010 type);1011 return false;1012 },1013 nullptr);1014 }1015 } else {1016 if (regex_up && !regex_up->Execute(llvm::StringRef()))1017 continue;1018 std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n",1019 iterator->first);1020 }1021 }1022 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);1023 return;1024 }1025 result.AppendError("current process has no Objective-C runtime loaded");1026 result.SetStatus(lldb::eReturnStatusFailed);1027 }1028 1029 CommandOptions m_options;1030};1031 1032class CommandObjectMultiwordObjC_TaggedPointer_Info1033 : public CommandObjectParsed {1034public:1035 CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter)1036 : CommandObjectParsed(1037 interpreter, "info", "Dump information on a tagged pointer.",1038 "language objc tagged-pointer info",1039 eCommandRequiresProcess | eCommandProcessMustBeLaunched |1040 eCommandProcessMustBePaused) {1041 AddSimpleArgumentList(eArgTypeAddress, eArgRepeatPlus);1042 }1043 1044 ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;1045 1046protected:1047 void DoExecute(Args &command, CommandReturnObject &result) override {1048 if (command.GetArgumentCount() == 0) {1049 result.AppendError("this command requires arguments");1050 result.SetStatus(lldb::eReturnStatusFailed);1051 return;1052 }1053 1054 Process *process = m_exe_ctx.GetProcessPtr();1055 ExecutionContext exe_ctx(process);1056 1057 ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);1058 if (!objc_runtime) {1059 result.AppendError("current process has no Objective-C runtime loaded");1060 result.SetStatus(lldb::eReturnStatusFailed);1061 return;1062 }1063 1064 ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor =1065 objc_runtime->GetTaggedPointerVendor();1066 if (!tagged_ptr_vendor) {1067 result.AppendError("current process has no tagged pointer support");1068 result.SetStatus(lldb::eReturnStatusFailed);1069 return;1070 }1071 1072 for (size_t i = 0; i < command.GetArgumentCount(); i++) {1073 const char *arg_str = command.GetArgumentAtIndex(i);1074 if (!arg_str)1075 continue;1076 1077 Status error;1078 lldb::addr_t arg_addr = OptionArgParser::ToRawAddress(1079 &exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);1080 if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) {1081 result.AppendErrorWithFormatv(1082 "could not convert '{0}' to a valid address\n", arg_str);1083 result.SetStatus(lldb::eReturnStatusFailed);1084 return;1085 }1086 1087 if (!tagged_ptr_vendor->IsPossibleTaggedPointer(arg_addr)) {1088 result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);1089 continue;1090 }1091 1092 auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);1093 if (!descriptor_sp) {1094 result.AppendErrorWithFormatv(1095 "could not get class descriptor for {0:x16}\n", arg_addr);1096 result.SetStatus(lldb::eReturnStatusFailed);1097 return;1098 }1099 1100 uint64_t info_bits = 0;1101 uint64_t value_bits = 0;1102 uint64_t payload = 0;1103 if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits,1104 &payload)) {1105 result.GetOutputStream().Format(1106 "{0:x} is tagged\n"1107 "\tpayload = {1:x16}\n"1108 "\tvalue = {2:x16}\n"1109 "\tinfo bits = {3:x16}\n"1110 "\tclass = {4}\n",1111 arg_addr, payload, value_bits, info_bits,1112 descriptor_sp->GetClassName().AsCString("<unknown>"));1113 } else {1114 result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);1115 }1116 }1117 1118 result.SetStatus(lldb::eReturnStatusSuccessFinishResult);1119 }1120};1121 1122class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword {1123public:1124 CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)1125 : CommandObjectMultiword(1126 interpreter, "class-table",1127 "Commands for operating on the Objective-C class table.",1128 "class-table <subcommand> [<subcommand-options>]") {1129 LoadSubCommand(1130 "dump",1131 CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter)));1132 }1133 1134 ~CommandObjectMultiwordObjC_ClassTable() override = default;1135};1136 1137class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword {1138public:1139 CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)1140 : CommandObjectMultiword(1141 interpreter, "tagged-pointer",1142 "Commands for operating on Objective-C tagged pointers.",1143 "tagged-pointer <subcommand> [<subcommand-options>]") {1144 LoadSubCommand(1145 "info",1146 CommandObjectSP(1147 new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter)));1148 }1149 1150 ~CommandObjectMultiwordObjC_TaggedPointer() override = default;1151};1152 1153class CommandObjectMultiwordObjC : public CommandObjectMultiword {1154public:1155 CommandObjectMultiwordObjC(CommandInterpreter &interpreter)1156 : CommandObjectMultiword(1157 interpreter, "objc",1158 "Commands for operating on the Objective-C language runtime.",1159 "objc <subcommand> [<subcommand-options>]") {1160 LoadSubCommand("class-table",1161 CommandObjectSP(1162 new CommandObjectMultiwordObjC_ClassTable(interpreter)));1163 LoadSubCommand("tagged-pointer",1164 CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer(1165 interpreter)));1166 }1167 1168 ~CommandObjectMultiwordObjC() override = default;1169};1170 1171void AppleObjCRuntimeV2::Initialize() {1172 PluginManager::RegisterPlugin(1173 GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 2",1174 CreateInstance,1175 [](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {1176 return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));1177 },1178 GetBreakpointExceptionPrecondition);1179}1180 1181void AppleObjCRuntimeV2::Terminate() {1182 PluginManager::UnregisterPlugin(CreateInstance);1183}1184 1185BreakpointResolverSP1186AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt,1187 bool catch_bp, bool throw_bp) {1188 BreakpointResolverSP resolver_sp;1189 1190 if (throw_bp)1191 resolver_sp = std::make_shared<BreakpointResolverName>(1192 bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),1193 eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,1194 /*offset_is_insn_count = */ false, eLazyBoolNo);1195 // FIXME: We don't do catch breakpoints for ObjC yet.1196 // Should there be some way for the runtime to specify what it can do in this1197 // regard?1198 return resolver_sp;1199}1200 1201llvm::Expected<std::unique_ptr<UtilityFunction>>1202AppleObjCRuntimeV2::CreateObjectChecker(std::string name,1203 ExecutionContext &exe_ctx) {1204 char check_function_code[2048];1205 1206 int len = 0;1207 if (m_has_object_getClass) {1208 len = ::snprintf(check_function_code, sizeof(check_function_code), R"(1209 extern "C" void *gdb_object_getClass(void *);1210 extern "C" int printf(const char *format, ...);1211 extern "C" void1212 %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {1213 if ($__lldb_arg_obj == (void *)0)1214 return; // nil is ok1215 if (!gdb_object_getClass($__lldb_arg_obj)) {1216 *((volatile int *)0) = 'ocgc';1217 } else if ($__lldb_arg_selector != (void *)0) {1218 signed char $responds = (signed char)1219 [(id)$__lldb_arg_obj respondsToSelector:1220 (void *) $__lldb_arg_selector];1221 if ($responds == (signed char) 0)1222 *((volatile int *)0) = 'ocgc';1223 }1224 })",1225 name.c_str());1226 } else {1227 len = ::snprintf(check_function_code, sizeof(check_function_code), R"(1228 extern "C" void *gdb_class_getClass(void *);1229 extern "C" int printf(const char *format, ...);1230 extern "C" void1231 %s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {1232 if ($__lldb_arg_obj == (void *)0)1233 return; // nil is ok1234 void **$isa_ptr = (void **)$__lldb_arg_obj;1235 if (*$isa_ptr == (void *)0 ||1236 !gdb_class_getClass(*$isa_ptr))1237 *((volatile int *)0) = 'ocgc';1238 else if ($__lldb_arg_selector != (void *)0) {1239 signed char $responds = (signed char)1240 [(id)$__lldb_arg_obj respondsToSelector:1241 (void *) $__lldb_arg_selector];1242 if ($responds == (signed char) 0)1243 *((volatile int *)0) = 'ocgc';1244 }1245 })",1246 name.c_str());1247 }1248 1249 assert(len < (int)sizeof(check_function_code));1250 UNUSED_IF_ASSERT_DISABLED(len);1251 1252 return GetTargetRef().CreateUtilityFunction(check_function_code, name,1253 eLanguageTypeC, exe_ctx);1254}1255 1256size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,1257 const char *ivar_name) {1258 uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;1259 1260 ConstString class_name = parent_ast_type.GetTypeName();1261 if (!class_name.IsEmpty() && ivar_name && ivar_name[0]) {1262 // Make the objective C V2 mangled name for the ivar offset from the class1263 // name and ivar name1264 std::string buffer("OBJC_IVAR_$_");1265 buffer.append(class_name.AsCString());1266 buffer.push_back('.');1267 buffer.append(ivar_name);1268 ConstString ivar_const_str(buffer.c_str());1269 1270 // Try to get the ivar offset address from the symbol table first using the1271 // name we created above1272 SymbolContextList sc_list;1273 Target &target = m_process->GetTarget();1274 target.GetImages().FindSymbolsWithNameAndType(ivar_const_str,1275 eSymbolTypeObjCIVar, sc_list);1276 1277 addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;1278 1279 Status error;1280 SymbolContext ivar_offset_symbol;1281 if (sc_list.GetSize() == 1 &&1282 sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {1283 if (ivar_offset_symbol.symbol)1284 ivar_offset_address =1285 ivar_offset_symbol.symbol->GetLoadAddress(&target);1286 }1287 1288 // If we didn't get the ivar offset address from the symbol table, fall1289 // back to getting it from the runtime1290 if (ivar_offset_address == LLDB_INVALID_ADDRESS)1291 ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);1292 1293 if (ivar_offset_address != LLDB_INVALID_ADDRESS)1294 ivar_offset = m_process->ReadUnsignedIntegerFromMemory(1295 ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error);1296 }1297 return ivar_offset;1298}1299 1300// tagged pointers are special not-a-real-pointer values that contain both type1301// and value information this routine attempts to check with as little1302// computational effort as possible whether something could possibly be a1303// tagged pointer - false positives are possible but false negatives shouldn't1304bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) {1305 if (!m_tagged_pointer_vendor_up)1306 return false;1307 return m_tagged_pointer_vendor_up->IsPossibleTaggedPointer(ptr);1308}1309 1310class RemoteNXMapTable {1311public:1312 RemoteNXMapTable() : m_end_iterator(*this, -1) {}1313 1314 void Dump() {1315 printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);1316 printf("RemoteNXMapTable.m_count = %u\n", m_count);1317 printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n",1318 m_num_buckets_minus_one);1319 printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);1320 }1321 1322 bool ParseHeader(Process *process, lldb::addr_t load_addr) {1323 m_process = process;1324 m_load_addr = load_addr;1325 m_map_pair_size = m_process->GetAddressByteSize() * 2;1326 m_invalid_key =1327 m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;1328 Status err;1329 1330 // This currently holds true for all platforms we support, but we might1331 // need to change this to use get the actually byte size of "unsigned" from1332 // the target AST...1333 const uint32_t unsigned_byte_size = sizeof(uint32_t);1334 // Skip the prototype as we don't need it (const struct1335 // +NXMapTablePrototype *prototype)1336 1337 bool success = true;1338 if (load_addr == LLDB_INVALID_ADDRESS)1339 success = false;1340 else {1341 lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();1342 1343 // unsigned count;1344 m_count = m_process->ReadUnsignedIntegerFromMemory(1345 cursor, unsigned_byte_size, 0, err);1346 if (m_count) {1347 cursor += unsigned_byte_size;1348 1349 // unsigned nbBucketsMinusOne;1350 m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(1351 cursor, unsigned_byte_size, 0, err);1352 cursor += unsigned_byte_size;1353 1354 // void *buckets;1355 m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);1356 1357 success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;1358 }1359 }1360 1361 if (!success) {1362 m_count = 0;1363 m_num_buckets_minus_one = 0;1364 m_buckets_ptr = LLDB_INVALID_ADDRESS;1365 }1366 return success;1367 }1368 1369 // const_iterator mimics NXMapState and its code comes from NXInitMapState1370 // and NXNextMapState.1371 typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;1372 1373 friend class const_iterator;1374 class const_iterator {1375 public:1376 const_iterator(RemoteNXMapTable &parent, int index)1377 : m_parent(parent), m_index(index) {1378 AdvanceToValidIndex();1379 }1380 1381 const_iterator(const const_iterator &rhs)1382 : m_parent(rhs.m_parent), m_index(rhs.m_index) {1383 // AdvanceToValidIndex() has been called by rhs already.1384 }1385 1386 const_iterator &operator=(const const_iterator &rhs) {1387 // AdvanceToValidIndex() has been called by rhs already.1388 assert(&m_parent == &rhs.m_parent);1389 m_index = rhs.m_index;1390 return *this;1391 }1392 1393 bool operator==(const const_iterator &rhs) const {1394 if (&m_parent != &rhs.m_parent)1395 return false;1396 if (m_index != rhs.m_index)1397 return false;1398 1399 return true;1400 }1401 1402 bool operator!=(const const_iterator &rhs) const {1403 return !(operator==(rhs));1404 }1405 1406 const_iterator &operator++() {1407 AdvanceToValidIndex();1408 return *this;1409 }1410 1411 element operator*() const {1412 if (m_index == -1) {1413 // TODO find a way to make this an error, but not an assert1414 return element();1415 }1416 1417 lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;1418 size_t map_pair_size = m_parent.m_map_pair_size;1419 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);1420 1421 Status err;1422 1423 lldb::addr_t key =1424 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);1425 if (!err.Success())1426 return element();1427 lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(1428 pair_ptr + m_parent.m_process->GetAddressByteSize(), err);1429 if (!err.Success())1430 return element();1431 1432 std::string key_string;1433 1434 m_parent.m_process->ReadCStringFromMemory(key, key_string, err);1435 if (!err.Success())1436 return element();1437 1438 return element(ConstString(key_string.c_str()),1439 (ObjCLanguageRuntime::ObjCISA)value);1440 }1441 1442 private:1443 void AdvanceToValidIndex() {1444 if (m_index == -1)1445 return;1446 1447 const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;1448 const size_t map_pair_size = m_parent.m_map_pair_size;1449 const lldb::addr_t invalid_key = m_parent.m_invalid_key;1450 Status err;1451 1452 while (m_index--) {1453 lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);1454 lldb::addr_t key =1455 m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);1456 1457 if (!err.Success()) {1458 m_index = -1;1459 return;1460 }1461 1462 if (key != invalid_key)1463 return;1464 }1465 }1466 RemoteNXMapTable &m_parent;1467 int m_index;1468 };1469 1470 const_iterator begin() {1471 return const_iterator(*this, m_num_buckets_minus_one + 1);1472 }1473 1474 const_iterator end() { return m_end_iterator; }1475 1476 uint32_t GetCount() const { return m_count; }1477 1478 uint32_t GetBucketCount() const { return m_num_buckets_minus_one; }1479 1480 lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; }1481 1482 lldb::addr_t GetTableLoadAddress() const { return m_load_addr; }1483 1484private:1485 // contents of _NXMapTable struct1486 uint32_t m_count = 0;1487 uint32_t m_num_buckets_minus_one = 0;1488 lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS;1489 lldb_private::Process *m_process = nullptr;1490 const_iterator m_end_iterator;1491 lldb::addr_t m_load_addr = LLDB_INVALID_ADDRESS;1492 size_t m_map_pair_size = 0;1493 lldb::addr_t m_invalid_key = 0;1494};1495 1496AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() = default;1497 1498void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature(1499 const RemoteNXMapTable &hash_table) {1500 m_count = hash_table.GetCount();1501 m_num_buckets = hash_table.GetBucketCount();1502 m_buckets_ptr = hash_table.GetBucketDataPointer();1503}1504 1505bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate(1506 Process *process, AppleObjCRuntimeV2 *runtime,1507 RemoteNXMapTable &hash_table) {1508 if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) {1509 return false; // Failed to parse the header, no need to update anything1510 }1511 1512 // Check with out current signature and return true if the count, number of1513 // buckets or the hash table address changes.1514 if (m_count == hash_table.GetCount() &&1515 m_num_buckets == hash_table.GetBucketCount() &&1516 m_buckets_ptr == hash_table.GetBucketDataPointer()) {1517 // Hash table hasn't changed1518 return false;1519 }1520 // Hash table data has changed, we need to update1521 return true;1522}1523 1524ObjCLanguageRuntime::ClassDescriptorSP1525AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {1526 ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;1527 if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())1528 class_descriptor_sp = non_pointer_isa_cache->GetClassDescriptor(isa);1529 if (!class_descriptor_sp)1530 class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);1531 return class_descriptor_sp;1532}1533 1534ObjCLanguageRuntime::ClassDescriptorSP1535AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {1536 ValueObjectSet seen;1537 return GetClassDescriptorImpl(valobj, seen);1538}1539 1540ObjCLanguageRuntime::ClassDescriptorSP1541AppleObjCRuntimeV2::GetClassDescriptorImpl(ValueObject &valobj,1542 ValueObjectSet &seen) {1543 seen.insert(&valobj);1544 1545 ClassDescriptorSP objc_class_sp;1546 if (valobj.IsBaseClass()) {1547 ValueObject *parent = valobj.GetParent();1548 // Fail if there's a cycle in our parent chain.1549 if (!parent || seen.count(parent))1550 return nullptr;1551 if (ClassDescriptorSP parent_descriptor_sp =1552 GetClassDescriptorImpl(*parent, seen))1553 return parent_descriptor_sp->GetSuperclass();1554 return nullptr;1555 }1556 // if we get an invalid VO (which might still happen when playing around with1557 // pointers returned by the expression parser, don't consider this a valid1558 // ObjC object)1559 if (!valobj.GetCompilerType().IsValid())1560 return objc_class_sp;1561 addr_t isa_pointer = valobj.GetPointerValue().address;1562 1563 // tagged pointer1564 if (IsTaggedPointer(isa_pointer))1565 return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer);1566 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());1567 1568 Process *process = exe_ctx.GetProcessPtr();1569 if (!process)1570 return objc_class_sp;1571 1572 Status error;1573 ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);1574 if (isa == LLDB_INVALID_ADDRESS)1575 return objc_class_sp;1576 1577 objc_class_sp = GetClassDescriptorFromISA(isa);1578 if (!objc_class_sp) {1579 if (ABISP abi_sp = process->GetABI())1580 isa = abi_sp->FixCodeAddress(isa);1581 objc_class_sp = GetClassDescriptorFromISA(isa);1582 }1583 1584 if (isa && !objc_class_sp) {1585 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1586 LLDB_LOGF(log,1587 "0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was "1588 "not in class descriptor cache 0x%" PRIx64,1589 isa_pointer, isa);1590 }1591 return objc_class_sp;1592}1593 1594lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() {1595 if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS)1596 return m_tagged_pointer_obfuscator;1597 1598 Process *process = GetProcess();1599 ModuleSP objc_module_sp(GetObjCModule());1600 1601 if (!objc_module_sp)1602 return LLDB_INVALID_ADDRESS;1603 1604 static ConstString g_gdb_objc_obfuscator(1605 "objc_debug_taggedpointer_obfuscator");1606 1607 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1608 g_gdb_objc_obfuscator, lldb::eSymbolTypeAny);1609 if (symbol) {1610 lldb::addr_t g_gdb_obj_obfuscator_ptr =1611 symbol->GetLoadAddress(&process->GetTarget());1612 1613 if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) {1614 Status error;1615 m_tagged_pointer_obfuscator =1616 process->ReadPointerFromMemory(g_gdb_obj_obfuscator_ptr, error);1617 }1618 }1619 // If we don't have a correct value at this point, there must be no1620 // obfuscation.1621 if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS)1622 m_tagged_pointer_obfuscator = 0;1623 1624 return m_tagged_pointer_obfuscator;1625}1626 1627lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {1628 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {1629 Process *process = GetProcess();1630 1631 ModuleSP objc_module_sp(GetObjCModule());1632 1633 if (!objc_module_sp)1634 return LLDB_INVALID_ADDRESS;1635 1636 static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");1637 1638 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1639 g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);1640 if (symbol) {1641 lldb::addr_t gdb_objc_realized_classes_ptr =1642 symbol->GetLoadAddress(&process->GetTarget());1643 1644 if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {1645 Status error;1646 m_isa_hash_table_ptr = process->ReadPointerFromMemory(1647 gdb_objc_realized_classes_ptr, error);1648 }1649 }1650 }1651 return m_isa_hash_table_ptr;1652}1653 1654std::unique_ptr<AppleObjCRuntimeV2::SharedCacheImageHeaders>1655AppleObjCRuntimeV2::SharedCacheImageHeaders::CreateSharedCacheImageHeaders(1656 AppleObjCRuntimeV2 &runtime) {1657 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1658 Process *process = runtime.GetProcess();1659 ModuleSP objc_module_sp(runtime.GetObjCModule());1660 if (!objc_module_sp || !process)1661 return nullptr;1662 1663 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1664 ConstString("objc_debug_headerInfoRWs"), lldb::eSymbolTypeAny);1665 if (!symbol) {1666 LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' unavailable. Some "1667 "information concerning the shared cache may be unavailable");1668 return nullptr;1669 }1670 1671 lldb::addr_t objc_debug_headerInfoRWs_addr =1672 symbol->GetLoadAddress(&process->GetTarget());1673 if (objc_debug_headerInfoRWs_addr == LLDB_INVALID_ADDRESS) {1674 LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' was found but we were "1675 "unable to get its load address");1676 return nullptr;1677 }1678 1679 Status error;1680 lldb::addr_t objc_debug_headerInfoRWs_ptr =1681 process->ReadPointerFromMemory(objc_debug_headerInfoRWs_addr, error);1682 if (error.Fail()) {1683 LLDB_LOG(log,1684 "Failed to read address of 'objc_debug_headerInfoRWs' at {0:x}",1685 objc_debug_headerInfoRWs_addr);1686 return nullptr;1687 }1688 1689 const size_t metadata_size =1690 sizeof(uint32_t) + sizeof(uint32_t); // count + entsize1691 DataBufferHeap metadata_buffer(metadata_size, '\0');1692 process->ReadMemory(objc_debug_headerInfoRWs_ptr, metadata_buffer.GetBytes(),1693 metadata_size, error);1694 if (error.Fail()) {1695 LLDB_LOG(log,1696 "Unable to read metadata for 'objc_debug_headerInfoRWs' at {0:x}",1697 objc_debug_headerInfoRWs_ptr);1698 return nullptr;1699 }1700 1701 DataExtractor metadata_extractor(metadata_buffer.GetBytes(), metadata_size,1702 process->GetByteOrder(),1703 process->GetAddressByteSize());1704 lldb::offset_t cursor = 0;1705 uint32_t count = metadata_extractor.GetU32_unchecked(&cursor);1706 uint32_t entsize = metadata_extractor.GetU32_unchecked(&cursor);1707 if (count == 0 || entsize == 0) {1708 LLDB_LOG(log,1709 "'objc_debug_headerInfoRWs' had count {0} with entsize {1}. These "1710 "should both be non-zero.",1711 count, entsize);1712 return nullptr;1713 }1714 1715 std::unique_ptr<SharedCacheImageHeaders> shared_cache_image_headers(1716 new SharedCacheImageHeaders(runtime, objc_debug_headerInfoRWs_ptr, count,1717 entsize));1718 if (auto Err = shared_cache_image_headers->UpdateIfNeeded()) {1719 LLDB_LOG_ERROR(log, std::move(Err),1720 "Failed to update SharedCacheImageHeaders: {0}");1721 return nullptr;1722 }1723 1724 return shared_cache_image_headers;1725}1726 1727llvm::Error AppleObjCRuntimeV2::SharedCacheImageHeaders::UpdateIfNeeded() {1728 if (!m_needs_update)1729 return llvm::Error::success();1730 1731 Process *process = m_runtime.GetProcess();1732 constexpr lldb::addr_t metadata_size =1733 sizeof(uint32_t) + sizeof(uint32_t); // count + entsize1734 1735 Status error;1736 const lldb::addr_t first_header_addr = m_headerInfoRWs_ptr + metadata_size;1737 DataBufferHeap header_buffer(m_entsize, '\0');1738 lldb::offset_t cursor = 0;1739 for (uint32_t i = 0; i < m_count; i++) {1740 const lldb::addr_t header_addr = first_header_addr + (i * m_entsize);1741 process->ReadMemory(header_addr, header_buffer.GetBytes(), m_entsize,1742 error);1743 if (error.Fail())1744 return llvm::createStringError(llvm::inconvertibleErrorCode(),1745 "Failed to read memory from inferior when "1746 "populating SharedCacheImageHeaders");1747 1748 DataExtractor header_extractor(header_buffer.GetBytes(), m_entsize,1749 process->GetByteOrder(),1750 process->GetAddressByteSize());1751 cursor = 0;1752 bool is_loaded = false;1753 if (m_entsize == 4) {1754 uint32_t header = header_extractor.GetU32_unchecked(&cursor);1755 if (header & 1)1756 is_loaded = true;1757 } else {1758 uint64_t header = header_extractor.GetU64_unchecked(&cursor);1759 if (header & 1)1760 is_loaded = true;1761 }1762 1763 if (is_loaded)1764 m_loaded_images.set(i);1765 else1766 m_loaded_images.reset(i);1767 }1768 m_needs_update = false;1769 m_version++;1770 return llvm::Error::success();1771}1772 1773bool AppleObjCRuntimeV2::SharedCacheImageHeaders::IsImageLoaded(1774 uint16_t image_index) {1775 if (image_index >= m_count)1776 return false;1777 if (auto Err = UpdateIfNeeded()) {1778 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1779 LLDB_LOG_ERROR(log, std::move(Err),1780 "Failed to update SharedCacheImageHeaders: {0}");1781 }1782 return m_loaded_images.test(image_index);1783}1784 1785uint64_t AppleObjCRuntimeV2::SharedCacheImageHeaders::GetVersion() {1786 if (auto Err = UpdateIfNeeded()) {1787 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1788 LLDB_LOG_ERROR(log, std::move(Err),1789 "Failed to update SharedCacheImageHeaders: {0}");1790 }1791 return m_version;1792}1793 1794std::unique_ptr<UtilityFunction>1795AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(1796 ExecutionContext &exe_ctx, Helper helper, std::string code,1797 std::string name) {1798 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1799 1800 LLDB_LOG(log, "Creating utility function {0}", name);1801 1802 TypeSystemClangSP scratch_ts_sp =1803 ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());1804 if (!scratch_ts_sp)1805 return {};1806 1807 auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(1808 std::move(code), std::move(name), eLanguageTypeC, exe_ctx);1809 if (!utility_fn_or_error) {1810 LLDB_LOG_ERROR(1811 log, utility_fn_or_error.takeError(),1812 "Failed to get utility function for dynamic info extractor: {0}");1813 return {};1814 }1815 1816 // Make some types for our arguments.1817 CompilerType clang_uint32_t_type =1818 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);1819 CompilerType clang_void_pointer_type =1820 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();1821 1822 // Make the runner function for our implementation utility function.1823 ValueList arguments;1824 Value value;1825 value.SetValueType(Value::ValueType::Scalar);1826 value.SetCompilerType(clang_void_pointer_type);1827 arguments.PushValue(value);1828 arguments.PushValue(value);1829 value.SetValueType(Value::ValueType::Scalar);1830 value.SetCompilerType(clang_uint32_t_type);1831 arguments.PushValue(value);1832 1833 // objc_getRealizedClassList_trylock takes an additional buffer and length.1834 if (helper == Helper::objc_getRealizedClassList_trylock) {1835 value.SetCompilerType(clang_void_pointer_type);1836 arguments.PushValue(value);1837 value.SetCompilerType(clang_uint32_t_type);1838 arguments.PushValue(value);1839 }1840 1841 arguments.PushValue(value);1842 1843 std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);1844 1845 Status error;1846 utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,1847 exe_ctx.GetThreadSP(), error);1848 1849 if (error.Fail()) {1850 LLDB_LOG(log,1851 "Failed to make function caller for implementation lookup: {0}.",1852 error.AsCString());1853 return {};1854 }1855 1856 return utility_fn;1857}1858 1859UtilityFunction *1860AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunction(1861 ExecutionContext &exe_ctx, Helper helper) {1862 switch (helper) {1863 case gdb_objc_realized_classes: {1864 if (!m_gdb_objc_realized_classes_helper.utility_function)1865 m_gdb_objc_realized_classes_helper.utility_function =1866 GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1867 g_get_dynamic_class_info_body,1868 g_get_dynamic_class_info_name);1869 return m_gdb_objc_realized_classes_helper.utility_function.get();1870 }1871 case objc_copyRealizedClassList: {1872 if (!m_objc_copyRealizedClassList_helper.utility_function)1873 m_objc_copyRealizedClassList_helper.utility_function =1874 GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1875 g_get_dynamic_class_info2_body,1876 g_get_dynamic_class_info2_name);1877 return m_objc_copyRealizedClassList_helper.utility_function.get();1878 }1879 case objc_getRealizedClassList_trylock: {1880 if (!m_objc_getRealizedClassList_trylock_helper.utility_function)1881 m_objc_getRealizedClassList_trylock_helper.utility_function =1882 GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1883 g_get_dynamic_class_info3_body,1884 g_get_dynamic_class_info3_name);1885 return m_objc_getRealizedClassList_trylock_helper.utility_function.get();1886 }1887 }1888 llvm_unreachable("Unexpected helper");1889}1890 1891lldb::addr_t &1892AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) {1893 switch (helper) {1894 case gdb_objc_realized_classes:1895 return m_gdb_objc_realized_classes_helper.args;1896 case objc_copyRealizedClassList:1897 return m_objc_copyRealizedClassList_helper.args;1898 case objc_getRealizedClassList_trylock:1899 return m_objc_getRealizedClassList_trylock_helper.args;1900 }1901 llvm_unreachable("Unexpected helper");1902}1903 1904AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper1905AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper(1906 ExecutionContext &exe_ctx) const {1907 if (!m_runtime.m_has_objc_copyRealizedClassList &&1908 !m_runtime.m_has_objc_getRealizedClassList_trylock)1909 return DynamicClassInfoExtractor::gdb_objc_realized_classes;1910 1911 if (Process *process = m_runtime.GetProcess()) {1912 if (DynamicLoader *loader = process->GetDynamicLoader()) {1913 if (loader->IsFullyInitialized()) {1914 switch (exe_ctx.GetTargetRef().GetDynamicClassInfoHelper()) {1915 case eDynamicClassInfoHelperAuto:1916 [[fallthrough]];1917 case eDynamicClassInfoHelperGetRealizedClassList:1918 if (m_runtime.m_has_objc_getRealizedClassList_trylock)1919 return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock;1920 [[fallthrough]];1921 case eDynamicClassInfoHelperCopyRealizedClassList:1922 if (m_runtime.m_has_objc_copyRealizedClassList)1923 return DynamicClassInfoExtractor::objc_copyRealizedClassList;1924 [[fallthrough]];1925 case eDynamicClassInfoHelperRealizedClassesStruct:1926 return DynamicClassInfoExtractor::gdb_objc_realized_classes;1927 }1928 }1929 }1930 }1931 1932 return DynamicClassInfoExtractor::gdb_objc_realized_classes;1933}1934 1935std::unique_ptr<UtilityFunction>1936AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::1937 GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) {1938 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1939 1940 LLDB_LOG(log, "Creating utility function {0}",1941 g_get_shared_cache_class_info_name);1942 1943 TypeSystemClangSP scratch_ts_sp =1944 ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());1945 if (!scratch_ts_sp)1946 return {};1947 1948 // If the inferior objc.dylib has the class_getNameRaw function, use that in1949 // our jitted expression. Else fall back to the old class_getName.1950 static ConstString g_class_getName_symbol_name("class_getName");1951 static ConstString g_class_getNameRaw_symbol_name(1952 "objc_debug_class_getNameRaw");1953 1954 ConstString class_name_getter_function_name =1955 m_runtime.HasSymbol(g_class_getNameRaw_symbol_name)1956 ? g_class_getNameRaw_symbol_name1957 : g_class_getName_symbol_name;1958 1959 // Substitute in the correct class_getName / class_getNameRaw function name,1960 // concatenate the two parts of our expression text. The format string has1961 // two %s's, so provide the name twice.1962 std::string shared_class_expression;1963 llvm::raw_string_ostream(shared_class_expression)1964 << llvm::format(g_shared_cache_class_name_funcptr,1965 class_name_getter_function_name.AsCString(),1966 class_name_getter_function_name.AsCString());1967 1968 shared_class_expression += g_get_shared_cache_class_info_definitions;1969 shared_class_expression += g_get_shared_cache_class_info_body;1970 1971 auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(1972 std::move(shared_class_expression), g_get_shared_cache_class_info_name,1973 eLanguageTypeC, exe_ctx);1974 1975 if (!utility_fn_or_error) {1976 LLDB_LOG_ERROR(1977 log, utility_fn_or_error.takeError(),1978 "Failed to get utility function for shared class info extractor: {0}");1979 return nullptr;1980 }1981 1982 // Make some types for our arguments.1983 CompilerType clang_uint32_t_type =1984 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);1985 CompilerType clang_void_pointer_type =1986 scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();1987 CompilerType clang_uint64_t_pointer_type =1988 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)1989 .GetPointerType();1990 CompilerType clang_uint32_t_pointer_type =1991 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32)1992 .GetPointerType();1993 1994 // Next make the function caller for our implementation utility function.1995 ValueList arguments;1996 Value value;1997 value.SetValueType(Value::ValueType::Scalar);1998 value.SetCompilerType(clang_void_pointer_type);1999 arguments.PushValue(value);2000 arguments.PushValue(value);2001 arguments.PushValue(value);2002 2003 value.SetValueType(Value::ValueType::Scalar);2004 value.SetCompilerType(clang_uint64_t_pointer_type);2005 arguments.PushValue(value);2006 2007 value.SetValueType(Value::ValueType::Scalar);2008 value.SetCompilerType(clang_uint32_t_type);2009 arguments.PushValue(value);2010 2011 value.SetValueType(Value::ValueType::Scalar);2012 value.SetCompilerType(clang_uint32_t_pointer_type);2013 arguments.PushValue(value);2014 2015 value.SetValueType(Value::ValueType::Scalar);2016 value.SetCompilerType(clang_uint32_t_type);2017 arguments.PushValue(value);2018 2019 std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);2020 2021 Status error;2022 utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,2023 exe_ctx.GetThreadSP(), error);2024 2025 if (error.Fail()) {2026 LLDB_LOG(log,2027 "Failed to make function caller for implementation lookup: {0}.",2028 error.AsCString());2029 return {};2030 }2031 2032 return utility_fn;2033}2034 2035UtilityFunction *2036AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction(2037 ExecutionContext &exe_ctx) {2038 if (!m_utility_function)2039 m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx);2040 return m_utility_function.get();2041}2042 2043AppleObjCRuntimeV2::DescriptorMapUpdateResult2044AppleObjCRuntimeV2::DynamicClassInfoExtractor::UpdateISAToDescriptorMap(2045 RemoteNXMapTable &hash_table) {2046 Process *process = m_runtime.GetProcess();2047 if (process == nullptr)2048 return DescriptorMapUpdateResult::Fail();2049 2050 uint32_t num_class_infos = 0;2051 2052 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);2053 2054 ExecutionContext exe_ctx;2055 2056 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();2057 2058 if (!thread_sp)2059 return DescriptorMapUpdateResult::Fail();2060 2061 if (!thread_sp->SafeToCallFunctions())2062 return DescriptorMapUpdateResult::Retry();2063 2064 thread_sp->CalculateExecutionContext(exe_ctx);2065 TypeSystemClangSP scratch_ts_sp =2066 ScratchTypeSystemClang::GetForTarget(process->GetTarget());2067 2068 if (!scratch_ts_sp)2069 return DescriptorMapUpdateResult::Fail();2070 2071 Address function_address;2072 2073 const uint32_t addr_size = process->GetAddressByteSize();2074 2075 Status err;2076 2077 // Compute which helper we're going to use for this update.2078 const DynamicClassInfoExtractor::Helper helper = ComputeHelper(exe_ctx);2079 2080 // Read the total number of classes from the hash table2081 const uint32_t num_classes =2082 helper == DynamicClassInfoExtractor::gdb_objc_realized_classes2083 ? hash_table.GetCount()2084 : m_runtime.m_realized_class_generation_count;2085 if (num_classes == 0) {2086 LLDB_LOGF(log, "No dynamic classes found.");2087 return DescriptorMapUpdateResult::Success(0);2088 }2089 2090 UtilityFunction *get_class_info_code =2091 GetClassInfoUtilityFunction(exe_ctx, helper);2092 if (!get_class_info_code) {2093 // The callee will have already logged a useful error message.2094 return DescriptorMapUpdateResult::Fail();2095 }2096 2097 FunctionCaller *get_class_info_function =2098 get_class_info_code->GetFunctionCaller();2099 2100 if (!get_class_info_function) {2101 LLDB_LOGF(log, "Failed to get implementation lookup function caller.");2102 return DescriptorMapUpdateResult::Fail();2103 }2104 2105 ValueList arguments = get_class_info_function->GetArgumentValues();2106 2107 DiagnosticManager diagnostics;2108 2109 const uint32_t class_info_byte_size = addr_size + 4;2110 const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;2111 lldb::addr_t class_infos_addr = process->AllocateMemory(2112 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);2113 2114 if (class_infos_addr == LLDB_INVALID_ADDRESS) {2115 LLDB_LOGF(log,2116 "unable to allocate %" PRIu322117 " bytes in process for shared cache read",2118 class_infos_byte_size);2119 return DescriptorMapUpdateResult::Fail();2120 }2121 2122 auto deallocate_class_infos = llvm::make_scope_exit([&] {2123 // Deallocate the memory we allocated for the ClassInfo array2124 if (class_infos_addr != LLDB_INVALID_ADDRESS)2125 process->DeallocateMemory(class_infos_addr);2126 });2127 2128 lldb::addr_t class_buffer_addr = LLDB_INVALID_ADDRESS;2129 const uint32_t class_byte_size = addr_size;2130 const uint32_t class_buffer_len = num_classes;2131 const uint32_t class_buffer_byte_size = class_buffer_len * class_byte_size;2132 if (helper == Helper::objc_getRealizedClassList_trylock) {2133 class_buffer_addr = process->AllocateMemory(2134 class_buffer_byte_size, ePermissionsReadable | ePermissionsWritable,2135 err);2136 if (class_buffer_addr == LLDB_INVALID_ADDRESS) {2137 LLDB_LOGF(log,2138 "unable to allocate %" PRIu322139 " bytes in process for shared cache read",2140 class_buffer_byte_size);2141 return DescriptorMapUpdateResult::Fail();2142 }2143 }2144 2145 auto deallocate_class_buffer = llvm::make_scope_exit([&] {2146 // Deallocate the memory we allocated for the Class array2147 if (class_buffer_addr != LLDB_INVALID_ADDRESS)2148 process->DeallocateMemory(class_buffer_addr);2149 });2150 2151 std::lock_guard<std::mutex> guard(m_mutex);2152 2153 // Fill in our function argument values2154 uint32_t index = 0;2155 arguments.GetValueAtIndex(index++)->GetScalar() =2156 hash_table.GetTableLoadAddress();2157 arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_addr;2158 arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_byte_size;2159 2160 if (class_buffer_addr != LLDB_INVALID_ADDRESS) {2161 arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_addr;2162 arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_byte_size;2163 }2164 2165 // Only dump the runtime classes from the expression evaluation if the log is2166 // verbose:2167 Log *type_log = GetLog(LLDBLog::Types);2168 bool dump_log = type_log && type_log->GetVerbose();2169 2170 arguments.GetValueAtIndex(index++)->GetScalar() = dump_log ? 1 : 0;2171 2172 bool success = false;2173 2174 diagnostics.Clear();2175 2176 // Write our function arguments into the process so we can run our function2177 if (get_class_info_function->WriteFunctionArguments(2178 exe_ctx, GetClassInfoArgs(helper), arguments, diagnostics)) {2179 EvaluateExpressionOptions options;2180 options.SetUnwindOnError(true);2181 options.SetTryAllThreads(false);2182 options.SetStopOthers(true);2183 options.SetIgnoreBreakpoints(true);2184 options.SetTimeout(process->GetUtilityExpressionTimeout());2185 options.SetIsForUtilityExpr(true);2186 2187 CompilerType clang_uint32_t_type =2188 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);2189 2190 Value return_value;2191 return_value.SetValueType(Value::ValueType::Scalar);2192 return_value.SetCompilerType(clang_uint32_t_type);2193 return_value.GetScalar() = 0;2194 2195 diagnostics.Clear();2196 2197 // Run the function2198 ExpressionResults results = get_class_info_function->ExecuteFunction(2199 exe_ctx, &GetClassInfoArgs(helper), options, diagnostics, return_value);2200 2201 if (results == eExpressionCompleted) {2202 // The result is the number of ClassInfo structures that were filled in2203 num_class_infos = return_value.GetScalar().ULong();2204 LLDB_LOG(log, "Discovered {0} Objective-C classes", num_class_infos);2205 if (num_class_infos > 0) {2206 // Read the ClassInfo structures2207 DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);2208 if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),2209 buffer.GetByteSize(),2210 err) == buffer.GetByteSize()) {2211 DataExtractor class_infos_data(buffer.GetBytes(),2212 buffer.GetByteSize(),2213 process->GetByteOrder(), addr_size);2214 m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);2215 }2216 }2217 success = true;2218 } else {2219 if (log) {2220 LLDB_LOGF(log, "Error evaluating our find class name function.");2221 diagnostics.Dump(log);2222 }2223 }2224 } else {2225 if (log) {2226 LLDB_LOGF(log, "Error writing function arguments.");2227 diagnostics.Dump(log);2228 }2229 }2230 2231 return DescriptorMapUpdateResult(success, false, num_class_infos);2232}2233 2234uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,2235 uint32_t num_class_infos) {2236 // Parses an array of "num_class_infos" packed ClassInfo structures:2237 //2238 // struct ClassInfo2239 // {2240 // Class isa;2241 // uint32_t hash;2242 // } __attribute__((__packed__));2243 2244 Log *log = GetLog(LLDBLog::Types);2245 bool should_log = log && log->GetVerbose();2246 2247 uint32_t num_parsed = 0;2248 2249 // Iterate through all ClassInfo structures2250 lldb::offset_t offset = 0;2251 for (uint32_t i = 0; i < num_class_infos; ++i) {2252 ObjCISA isa = data.GetAddress(&offset);2253 2254 if (isa == 0) {2255 if (should_log)2256 LLDB_LOGF(2257 log, "AppleObjCRuntimeV2 found NULL isa, ignoring this class info");2258 continue;2259 }2260 // Check if we already know about this ISA, if we do, the info will never2261 // change, so we can just skip it.2262 if (ISAIsCached(isa)) {2263 if (should_log)2264 LLDB_LOGF(log,2265 "AppleObjCRuntimeV2 found cached isa=0x%" PRIx642266 ", ignoring this class info",2267 isa);2268 offset += 4;2269 } else {2270 // Read the 32 bit hash for the class name2271 const uint32_t name_hash = data.GetU32(&offset);2272 ClassDescriptorSP descriptor_sp(2273 new ClassDescriptorV2(*this, isa, nullptr));2274 2275 // The code in g_get_shared_cache_class_info_body sets the value of the2276 // hash to 0 to signal a demangled symbol. We use class_getName() in that2277 // code to find the class name, but this returns a demangled name for2278 // Swift symbols. For those symbols, recompute the hash here by reading2279 // their name from the runtime.2280 if (name_hash)2281 AddClass(isa, descriptor_sp, name_hash);2282 else2283 AddClass(isa, descriptor_sp,2284 descriptor_sp->GetClassName().AsCString(nullptr));2285 num_parsed++;2286 if (should_log)2287 LLDB_LOGF(log,2288 "AppleObjCRuntimeV2 added isa=0x%" PRIx642289 ", hash=0x%8.8x, name=%s",2290 isa, name_hash,2291 descriptor_sp->GetClassName().AsCString("<unknown>"));2292 }2293 }2294 if (should_log)2295 LLDB_LOGF(log, "AppleObjCRuntimeV2 parsed %" PRIu32 " class infos",2296 num_parsed);2297 return num_parsed;2298}2299 2300bool AppleObjCRuntimeV2::HasSymbol(ConstString Name) {2301 if (!m_objc_module_sp)2302 return false;2303 if (const Symbol *symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(2304 Name, lldb::eSymbolTypeCode)) {2305 if (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())2306 return true;2307 }2308 return false;2309}2310 2311AppleObjCRuntimeV2::DescriptorMapUpdateResult2312AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {2313 Process *process = m_runtime.GetProcess();2314 if (process == nullptr)2315 return DescriptorMapUpdateResult::Fail();2316 2317 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);2318 2319 ExecutionContext exe_ctx;2320 2321 ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();2322 2323 if (!thread_sp)2324 return DescriptorMapUpdateResult::Fail();2325 2326 if (!thread_sp->SafeToCallFunctions())2327 return DescriptorMapUpdateResult::Retry();2328 2329 thread_sp->CalculateExecutionContext(exe_ctx);2330 TypeSystemClangSP scratch_ts_sp =2331 ScratchTypeSystemClang::GetForTarget(process->GetTarget());2332 2333 if (!scratch_ts_sp)2334 return DescriptorMapUpdateResult::Fail();2335 2336 Address function_address;2337 2338 const uint32_t addr_size = process->GetAddressByteSize();2339 2340 Status err;2341 2342 uint32_t num_class_infos = 0;2343 2344 const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress();2345 const lldb::addr_t shared_cache_base_addr =2346 m_runtime.GetSharedCacheBaseAddress();2347 2348 if (objc_opt_ptr == LLDB_INVALID_ADDRESS ||2349 shared_cache_base_addr == LLDB_INVALID_ADDRESS)2350 return DescriptorMapUpdateResult::Fail();2351 2352 // The number of entries to pre-allocate room for.2353 // Each entry is (addrsize + 4) bytes2354 const uint32_t max_num_classes_in_buffer = 212992;2355 2356 UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);2357 if (!get_class_info_code) {2358 // The callee will have already logged a useful error message.2359 return DescriptorMapUpdateResult::Fail();2360 }2361 2362 FunctionCaller *get_shared_cache_class_info_function =2363 get_class_info_code->GetFunctionCaller();2364 2365 if (!get_shared_cache_class_info_function) {2366 LLDB_LOGF(log, "Failed to get implementation lookup function caller.");2367 return DescriptorMapUpdateResult::Fail();2368 }2369 2370 ValueList arguments =2371 get_shared_cache_class_info_function->GetArgumentValues();2372 2373 DiagnosticManager diagnostics;2374 2375 const uint32_t class_info_byte_size = addr_size + 4;2376 const uint32_t class_infos_byte_size =2377 max_num_classes_in_buffer * class_info_byte_size;2378 lldb::addr_t class_infos_addr = process->AllocateMemory(2379 class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);2380 const uint32_t relative_selector_offset_addr_size = 64;2381 lldb::addr_t relative_selector_offset_addr =2382 process->AllocateMemory(relative_selector_offset_addr_size,2383 ePermissionsReadable | ePermissionsWritable, err);2384 constexpr uint32_t class_info_start_idx_byte_size = sizeof(uint32_t);2385 lldb::addr_t class_info_start_idx_addr =2386 process->AllocateMemory(class_info_start_idx_byte_size,2387 ePermissionsReadable | ePermissionsWritable, err);2388 2389 if (class_infos_addr == LLDB_INVALID_ADDRESS ||2390 relative_selector_offset_addr == LLDB_INVALID_ADDRESS ||2391 class_info_start_idx_addr == LLDB_INVALID_ADDRESS) {2392 LLDB_LOGF(log,2393 "unable to allocate %" PRIu322394 " bytes in process for shared cache read",2395 class_infos_byte_size);2396 return DescriptorMapUpdateResult::Fail();2397 }2398 2399 const uint32_t start_idx_init_value = 0;2400 size_t bytes_written = process->WriteMemory(2401 class_info_start_idx_addr, &start_idx_init_value, sizeof(uint32_t), err);2402 if (bytes_written != sizeof(uint32_t)) {2403 LLDB_LOGF(log,2404 "unable to write %" PRIu322405 " bytes in process for shared cache read",2406 class_infos_byte_size);2407 return DescriptorMapUpdateResult::Fail();2408 }2409 2410 std::lock_guard<std::mutex> guard(m_mutex);2411 2412 // Fill in our function argument values2413 arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;2414 arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr;2415 arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;2416 arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;2417 arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;2418 arguments.GetValueAtIndex(5)->GetScalar() = class_info_start_idx_addr;2419 // Only dump the runtime classes from the expression evaluation if the log is2420 // verbose:2421 Log *type_log = GetLog(LLDBLog::Types);2422 bool dump_log = type_log && type_log->GetVerbose();2423 2424 arguments.GetValueAtIndex(6)->GetScalar() = dump_log ? 1 : 0;2425 2426 bool success = false;2427 2428 diagnostics.Clear();2429 2430 // Write our function arguments into the process so we can run our function2431 if (get_shared_cache_class_info_function->WriteFunctionArguments(2432 exe_ctx, m_args, arguments, diagnostics)) {2433 EvaluateExpressionOptions options;2434 options.SetUnwindOnError(true);2435 options.SetTryAllThreads(false);2436 options.SetStopOthers(true);2437 options.SetIgnoreBreakpoints(true);2438 options.SetTimeout(process->GetUtilityExpressionTimeout());2439 options.SetIsForUtilityExpr(true);2440 2441 CompilerType clang_uint32_t_type =2442 scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);2443 2444 Value return_value;2445 return_value.SetValueType(Value::ValueType::Scalar);2446 return_value.SetCompilerType(clang_uint32_t_type);2447 return_value.GetScalar() = 0;2448 2449 diagnostics.Clear();2450 2451 uint32_t num_class_infos_read = 0;2452 bool already_read_relative_selector_offset = false;2453 2454 do {2455 // Run the function.2456 ExpressionResults results =2457 get_shared_cache_class_info_function->ExecuteFunction(2458 exe_ctx, &m_args, options, diagnostics, return_value);2459 2460 if (results == eExpressionCompleted) {2461 // The result is the number of ClassInfo structures that were filled in.2462 num_class_infos_read = return_value.GetScalar().ULong();2463 num_class_infos += num_class_infos_read;2464 LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",2465 num_class_infos_read);2466 if (num_class_infos_read > 0) {2467 success = true;2468 2469 // Read the relative selector offset. This only needs to occur once no2470 // matter how many times the function is called.2471 if (!already_read_relative_selector_offset) {2472 DataBufferHeap relative_selector_offset_buffer(64, 0);2473 if (process->ReadMemory(2474 relative_selector_offset_addr,2475 relative_selector_offset_buffer.GetBytes(),2476 relative_selector_offset_buffer.GetByteSize(),2477 err) == relative_selector_offset_buffer.GetByteSize()) {2478 DataExtractor relative_selector_offset_data(2479 relative_selector_offset_buffer.GetBytes(),2480 relative_selector_offset_buffer.GetByteSize(),2481 process->GetByteOrder(), addr_size);2482 lldb::offset_t offset = 0;2483 uint64_t relative_selector_offset =2484 relative_selector_offset_data.GetU64(&offset);2485 if (relative_selector_offset > 0) {2486 // The offset is relative to the objc_opt struct.2487 m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +2488 relative_selector_offset);2489 }2490 }2491 already_read_relative_selector_offset = true;2492 }2493 2494 // Read the ClassInfo structures2495 DataBufferHeap class_infos_buffer(2496 num_class_infos_read * class_info_byte_size, 0);2497 if (process->ReadMemory(class_infos_addr,2498 class_infos_buffer.GetBytes(),2499 class_infos_buffer.GetByteSize(),2500 err) == class_infos_buffer.GetByteSize()) {2501 DataExtractor class_infos_data(class_infos_buffer.GetBytes(),2502 class_infos_buffer.GetByteSize(),2503 process->GetByteOrder(), addr_size);2504 2505 m_runtime.ParseClassInfoArray(class_infos_data,2506 num_class_infos_read);2507 }2508 }2509 } else if (log) {2510 LLDB_LOGF(log, "Error evaluating our find class name function.");2511 diagnostics.Dump(log);2512 break;2513 }2514 } while (num_class_infos_read == max_num_classes_in_buffer);2515 } else if (log) {2516 LLDB_LOGF(log, "Error writing function arguments.");2517 diagnostics.Dump(log);2518 }2519 2520 LLDB_LOG(log, "Processed {0} Objective-C classes total from the shared cache",2521 num_class_infos);2522 // Cleanup memory we allocated in the process.2523 process->DeallocateMemory(relative_selector_offset_addr);2524 process->DeallocateMemory(class_info_start_idx_addr);2525 process->DeallocateMemory(class_infos_addr);2526 2527 return DescriptorMapUpdateResult(success, false, num_class_infos);2528}2529 2530lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {2531 Process *process = GetProcess();2532 2533 if (process) {2534 ModuleSP objc_module_sp(GetObjCModule());2535 2536 if (objc_module_sp) {2537 ObjectFile *objc_object = objc_module_sp->GetObjectFile();2538 2539 if (objc_object) {2540 SectionList *section_list = objc_module_sp->GetSectionList();2541 2542 if (section_list) {2543 SectionSP text_segment_sp(2544 section_list->FindSectionByName(ConstString("__TEXT")));2545 2546 if (text_segment_sp) {2547 SectionSP objc_opt_section_sp(2548 text_segment_sp->GetChildren().FindSectionByName(2549 ConstString("__objc_opt_ro")));2550 2551 if (objc_opt_section_sp) {2552 return objc_opt_section_sp->GetLoadBaseAddress(2553 &process->GetTarget());2554 }2555 }2556 }2557 }2558 }2559 }2560 return LLDB_INVALID_ADDRESS;2561}2562 2563lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() {2564 StructuredData::ObjectSP info = m_process->GetSharedCacheInfo();2565 if (!info)2566 return LLDB_INVALID_ADDRESS;2567 2568 StructuredData::Dictionary *info_dict = info->GetAsDictionary();2569 if (!info_dict)2570 return LLDB_INVALID_ADDRESS;2571 2572 StructuredData::ObjectSP value =2573 info_dict->GetValueForKey("shared_cache_base_address");2574 if (!value)2575 return LLDB_INVALID_ADDRESS;2576 2577 return value->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);2578}2579 2580void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {2581 LLDB_SCOPED_TIMER();2582 2583 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);2584 2585 // Else we need to check with our process to see when the map was updated.2586 Process *process = GetProcess();2587 2588 if (process) {2589 RemoteNXMapTable hash_table;2590 2591 // Update the process stop ID that indicates the last time we updated the2592 // map, whether it was successful or not.2593 m_isa_to_descriptor_stop_id = process->GetStopID();2594 2595 // Ask the runtime is the realized class generation count changed. Unlike2596 // the hash table, this accounts for lazily named classes.2597 const bool class_count_changed = RealizedClassGenerationCountChanged();2598 2599 if (!m_hash_signature.NeedsUpdate(process, this, hash_table) &&2600 !class_count_changed)2601 return;2602 2603 m_hash_signature.UpdateSignature(hash_table);2604 2605 // Grab the dynamically loaded Objective-C classes from memory.2606 DescriptorMapUpdateResult dynamic_update_result =2607 m_dynamic_class_info_extractor.UpdateISAToDescriptorMap(hash_table);2608 2609 // Now get the objc classes that are baked into the Objective-C runtime in2610 // the shared cache, but only once per process as this data never changes2611 if (!m_loaded_objc_opt) {2612 // it is legitimately possible for the shared cache to be empty - in that2613 // case, the dynamic hash table will contain all the class information we2614 // need; the situation we're trying to detect is one where we aren't2615 // seeing class information from the runtime - in order to detect that2616 // vs. just the shared cache being empty or sparsely populated, we set an2617 // arbitrary (very low) threshold for the number of classes that we want2618 // to see in a "good" scenario - anything below that is suspicious2619 // (Foundation alone has thousands of classes)2620 const uint32_t num_classes_to_warn_at = 500;2621 2622 DescriptorMapUpdateResult shared_cache_update_result =2623 m_shared_cache_class_info_extractor.UpdateISAToDescriptorMap();2624 2625 LLDB_LOGF(log,2626 "attempted to read objc class data - results: "2627 "[dynamic_update]: ran: %s, retry: %s, count: %" PRIu322628 " [shared_cache_update]: ran: %s, retry: %s, count: %" PRIu32,2629 dynamic_update_result.m_update_ran ? "yes" : "no",2630 dynamic_update_result.m_retry_update ? "yes" : "no",2631 dynamic_update_result.m_num_found,2632 shared_cache_update_result.m_update_ran ? "yes" : "no",2633 shared_cache_update_result.m_retry_update ? "yes" : "no",2634 shared_cache_update_result.m_num_found);2635 2636 // warn if:2637 // - we could not run either expression2638 // - we found fewer than num_classes_to_warn_at classes total2639 if (dynamic_update_result.m_retry_update ||2640 shared_cache_update_result.m_retry_update)2641 WarnIfNoClassesCached(SharedCacheWarningReason::eExpressionUnableToRun);2642 else if ((!shared_cache_update_result.m_update_ran) ||2643 (!dynamic_update_result.m_update_ran))2644 WarnIfNoClassesCached(2645 SharedCacheWarningReason::eExpressionExecutionFailure);2646 else if (dynamic_update_result.m_num_found +2647 shared_cache_update_result.m_num_found <2648 num_classes_to_warn_at)2649 WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead);2650 else2651 m_loaded_objc_opt = true;2652 }2653 } else {2654 m_isa_to_descriptor_stop_id = UINT32_MAX;2655 }2656}2657 2658bool AppleObjCRuntimeV2::RealizedClassGenerationCountChanged() {2659 Process *process = GetProcess();2660 if (!process)2661 return false;2662 2663 Status error;2664 uint64_t objc_debug_realized_class_generation_count =2665 ExtractRuntimeGlobalSymbol(2666 process, ConstString("objc_debug_realized_class_generation_count"),2667 GetObjCModule(), error);2668 if (error.Fail())2669 return false;2670 2671 if (m_realized_class_generation_count ==2672 objc_debug_realized_class_generation_count)2673 return false;2674 2675 Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);2676 LLDB_LOG(log,2677 "objc_debug_realized_class_generation_count changed from {0} to {1}",2678 m_realized_class_generation_count,2679 objc_debug_realized_class_generation_count);2680 2681 m_realized_class_generation_count =2682 objc_debug_realized_class_generation_count;2683 2684 return true;2685}2686 2687static bool DoesProcessHaveSharedCache(Process &process) {2688 PlatformSP platform_sp = process.GetTarget().GetPlatform();2689 if (!platform_sp)2690 return true; // this should not happen2691 2692 llvm::StringRef platform_plugin_name_sr = platform_sp->GetPluginName();2693 if (platform_plugin_name_sr.ends_with("-simulator"))2694 return false;2695 2696 return true;2697}2698 2699void AppleObjCRuntimeV2::WarnIfNoClassesCached(2700 SharedCacheWarningReason reason) {2701 if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) {2702 // Simulators do not have the objc_opt_ro class table so don't actually2703 // complain to the user2704 return;2705 }2706 2707 Debugger &debugger(GetProcess()->GetTarget().GetDebugger());2708 switch (reason) {2709 case SharedCacheWarningReason::eNotEnoughClassesRead:2710 Debugger::ReportWarning("could not find Objective-C class data in "2711 "the process. This may reduce the quality of type "2712 "information available.\n",2713 debugger.GetID(), &m_no_classes_cached_warning);2714 break;2715 case SharedCacheWarningReason::eExpressionExecutionFailure:2716 Debugger::ReportWarning(2717 "could not execute support code to read "2718 "Objective-C class data in the process. This may "2719 "reduce the quality of type information available.\n",2720 debugger.GetID(), &m_no_classes_cached_warning);2721 break;2722 case SharedCacheWarningReason::eExpressionUnableToRun:2723 Debugger::ReportWarning(2724 "could not execute support code to read Objective-C class data because "2725 "it's not yet safe to do so, and will be retried later.\n",2726 debugger.GetID(), nullptr);2727 break;2728 }2729}2730 2731void AppleObjCRuntimeV2::WarnIfNoExpandedSharedCache() {2732 if (!m_objc_module_sp)2733 return;2734 2735 ObjectFile *object_file = m_objc_module_sp->GetObjectFile();2736 if (!object_file)2737 return;2738 2739 if (!object_file->IsInMemory())2740 return;2741 2742 if (!GetProcess()->IsLiveDebugSession())2743 return;2744 2745 Target &target = GetProcess()->GetTarget();2746 Debugger &debugger = target.GetDebugger();2747 2748 std::string buffer;2749 llvm::raw_string_ostream os(buffer);2750 2751 os << "libobjc.A.dylib is being read from process memory. This "2752 "indicates that LLDB could not ";2753 if (PlatformSP platform_sp = target.GetPlatform()) {2754 if (platform_sp->IsHost()) {2755 os << "read from the host's in-memory shared cache";2756 } else {2757 os << "find the on-disk shared cache for this device";2758 }2759 } else {2760 os << "read from the shared cache";2761 }2762 os << ". This will likely reduce debugging performance.\n";2763 2764 Debugger::ReportWarning(buffer, debugger.GetID(),2765 &m_no_expanded_cache_warning);2766}2767 2768DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() {2769 if (!m_decl_vendor_up)2770 m_decl_vendor_up = std::make_unique<AppleObjCDeclVendor>(*this);2771 2772 return m_decl_vendor_up.get();2773}2774 2775lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {2776 lldb::addr_t ret = LLDB_INVALID_ADDRESS;2777 2778 const char *name_cstr = name.AsCString();2779 2780 if (name_cstr) {2781 llvm::StringRef name_strref(name_cstr);2782 2783 llvm::StringRef ivar_prefix("OBJC_IVAR_$_");2784 llvm::StringRef class_prefix("OBJC_CLASS_$_");2785 2786 if (name_strref.starts_with(ivar_prefix)) {2787 llvm::StringRef ivar_skipped_prefix =2788 name_strref.substr(ivar_prefix.size());2789 std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =2790 ivar_skipped_prefix.split('.');2791 2792 if (!class_and_ivar.first.empty() && !class_and_ivar.second.empty()) {2793 const ConstString class_name_cs(class_and_ivar.first);2794 ClassDescriptorSP descriptor =2795 ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);2796 2797 if (descriptor) {2798 const ConstString ivar_name_cs(class_and_ivar.second);2799 const char *ivar_name_cstr = ivar_name_cs.AsCString();2800 2801 auto ivar_func = [&ret,2802 ivar_name_cstr](const char *name, const char *type,2803 lldb::addr_t offset_addr,2804 uint64_t size) -> lldb::addr_t {2805 if (!strcmp(name, ivar_name_cstr)) {2806 ret = offset_addr;2807 return true;2808 }2809 return false;2810 };2811 2812 descriptor->Describe(2813 std::function<void(ObjCISA)>(nullptr),2814 std::function<bool(const char *, const char *)>(nullptr),2815 std::function<bool(const char *, const char *)>(nullptr),2816 ivar_func);2817 }2818 }2819 } else if (name_strref.starts_with(class_prefix)) {2820 llvm::StringRef class_skipped_prefix =2821 name_strref.substr(class_prefix.size());2822 const ConstString class_name_cs(class_skipped_prefix);2823 ClassDescriptorSP descriptor =2824 GetClassDescriptorFromClassName(class_name_cs);2825 2826 if (descriptor)2827 ret = descriptor->GetISA();2828 }2829 }2830 2831 return ret;2832}2833 2834AppleObjCRuntimeV2::NonPointerISACache *2835AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(2836 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {2837 Process *process(runtime.GetProcess());2838 2839 Status error;2840 2841 Log *log = GetLog(LLDBLog::Types);2842 2843 auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(2844 process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);2845 if (error.Fail())2846 return nullptr;2847 2848 auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(2849 process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,2850 error);2851 if (error.Fail())2852 return nullptr;2853 2854 auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(2855 process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);2856 if (error.Fail())2857 return nullptr;2858 2859 if (log)2860 log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks");2861 2862 bool foundError = false;2863 auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol(2864 process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp,2865 error);2866 foundError |= error.Fail();2867 2868 auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol(2869 process, ConstString("objc_debug_indexed_isa_magic_value"),2870 objc_module_sp, error);2871 foundError |= error.Fail();2872 2873 auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol(2874 process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp,2875 error);2876 foundError |= error.Fail();2877 2878 auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol(2879 process, ConstString("objc_debug_indexed_isa_index_shift"),2880 objc_module_sp, error);2881 foundError |= error.Fail();2882 2883 auto objc_indexed_classes =2884 ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"),2885 objc_module_sp, error, false);2886 foundError |= error.Fail();2887 2888 if (log)2889 log->PutCString("AOCRT::NPI: Found all the indexed ISA masks");2890 2891 // we might want to have some rules to outlaw these other values (e.g if the2892 // mask is zero but the value is non-zero, ...)2893 2894 return new NonPointerISACache(2895 runtime, objc_module_sp, objc_debug_isa_class_mask,2896 objc_debug_isa_magic_mask, objc_debug_isa_magic_value,2897 objc_debug_indexed_isa_magic_mask, objc_debug_indexed_isa_magic_value,2898 objc_debug_indexed_isa_index_mask, objc_debug_indexed_isa_index_shift,2899 foundError ? 0 : objc_indexed_classes);2900}2901 2902AppleObjCRuntimeV2::TaggedPointerVendorV2 *2903AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(2904 AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {2905 Process *process(runtime.GetProcess());2906 2907 Status error;2908 2909 auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(2910 process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,2911 error);2912 if (error.Fail())2913 return new TaggedPointerVendorLegacy(runtime);2914 2915 auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(2916 process, ConstString("objc_debug_taggedpointer_slot_shift"),2917 objc_module_sp, error, true, 4);2918 if (error.Fail())2919 return new TaggedPointerVendorLegacy(runtime);2920 2921 auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(2922 process, ConstString("objc_debug_taggedpointer_slot_mask"),2923 objc_module_sp, error, true, 4);2924 if (error.Fail())2925 return new TaggedPointerVendorLegacy(runtime);2926 2927 auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(2928 process, ConstString("objc_debug_taggedpointer_payload_lshift"),2929 objc_module_sp, error, true, 4);2930 if (error.Fail())2931 return new TaggedPointerVendorLegacy(runtime);2932 2933 auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(2934 process, ConstString("objc_debug_taggedpointer_payload_rshift"),2935 objc_module_sp, error, true, 4);2936 if (error.Fail())2937 return new TaggedPointerVendorLegacy(runtime);2938 2939 auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(2940 process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,2941 error, false);2942 if (error.Fail())2943 return new TaggedPointerVendorLegacy(runtime);2944 2945 // try to detect the "extended tagged pointer" variables - if any are2946 // missing, use the non-extended vendor2947 do {2948 auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(2949 process, ConstString("objc_debug_taggedpointer_ext_mask"),2950 objc_module_sp, error);2951 if (error.Fail())2952 break;2953 2954 auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(2955 process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),2956 objc_module_sp, error, true, 4);2957 if (error.Fail())2958 break;2959 2960 auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(2961 process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),2962 objc_module_sp, error, true, 4);2963 if (error.Fail())2964 break;2965 2966 auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(2967 process, ConstString("objc_debug_taggedpointer_ext_classes"),2968 objc_module_sp, error, false);2969 if (error.Fail())2970 break;2971 2972 auto objc_debug_taggedpointer_ext_payload_lshift =2973 ExtractRuntimeGlobalSymbol(2974 process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),2975 objc_module_sp, error, true, 4);2976 if (error.Fail())2977 break;2978 2979 auto objc_debug_taggedpointer_ext_payload_rshift =2980 ExtractRuntimeGlobalSymbol(2981 process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),2982 objc_module_sp, error, true, 4);2983 if (error.Fail())2984 break;2985 2986 return new TaggedPointerVendorExtended(2987 runtime, objc_debug_taggedpointer_mask,2988 objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift,2989 objc_debug_taggedpointer_ext_slot_shift,2990 objc_debug_taggedpointer_slot_mask,2991 objc_debug_taggedpointer_ext_slot_mask,2992 objc_debug_taggedpointer_payload_lshift,2993 objc_debug_taggedpointer_payload_rshift,2994 objc_debug_taggedpointer_ext_payload_lshift,2995 objc_debug_taggedpointer_ext_payload_rshift,2996 objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);2997 } while (false);2998 2999 // we might want to have some rules to outlaw these values (e.g if the3000 // table's address is zero)3001 3002 return new TaggedPointerVendorRuntimeAssisted(3003 runtime, objc_debug_taggedpointer_mask,3004 objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask,3005 objc_debug_taggedpointer_payload_lshift,3006 objc_debug_taggedpointer_payload_rshift,3007 objc_debug_taggedpointer_classes);3008}3009 3010bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer(3011 lldb::addr_t ptr) {3012 return (ptr & 1);3013}3014 3015ObjCLanguageRuntime::ClassDescriptorSP3016AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor(3017 lldb::addr_t ptr) {3018 if (!IsPossibleTaggedPointer(ptr))3019 return ObjCLanguageRuntime::ClassDescriptorSP();3020 3021 uint32_t foundation_version = m_runtime.GetFoundationVersion();3022 3023 if (foundation_version == LLDB_INVALID_MODULE_VERSION)3024 return ObjCLanguageRuntime::ClassDescriptorSP();3025 3026 uint64_t class_bits = (ptr & 0xE) >> 1;3027 ConstString name;3028 3029 static ConstString g_NSAtom("NSAtom");3030 static ConstString g_NSNumber("NSNumber");3031 static ConstString g_NSDateTS("NSDateTS");3032 static ConstString g_NSManagedObject("NSManagedObject");3033 static ConstString g_NSDate("NSDate");3034 3035 if (foundation_version >= 900) {3036 switch (class_bits) {3037 case 0:3038 name = g_NSAtom;3039 break;3040 case 3:3041 name = g_NSNumber;3042 break;3043 case 4:3044 name = g_NSDateTS;3045 break;3046 case 5:3047 name = g_NSManagedObject;3048 break;3049 case 6:3050 name = g_NSDate;3051 break;3052 default:3053 return ObjCLanguageRuntime::ClassDescriptorSP();3054 }3055 } else {3056 switch (class_bits) {3057 case 1:3058 name = g_NSNumber;3059 break;3060 case 5:3061 name = g_NSManagedObject;3062 break;3063 case 6:3064 name = g_NSDate;3065 break;3066 case 7:3067 name = g_NSDateTS;3068 break;3069 default:3070 return ObjCLanguageRuntime::ClassDescriptorSP();3071 }3072 }3073 3074 lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator();3075 return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated));3076}3077 3078AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::3079 TaggedPointerVendorRuntimeAssisted(3080 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,3081 uint32_t objc_debug_taggedpointer_slot_shift,3082 uint32_t objc_debug_taggedpointer_slot_mask,3083 uint32_t objc_debug_taggedpointer_payload_lshift,3084 uint32_t objc_debug_taggedpointer_payload_rshift,3085 lldb::addr_t objc_debug_taggedpointer_classes)3086 : TaggedPointerVendorV2(runtime), m_cache(),3087 m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),3088 m_objc_debug_taggedpointer_slot_shift(3089 objc_debug_taggedpointer_slot_shift),3090 m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),3091 m_objc_debug_taggedpointer_payload_lshift(3092 objc_debug_taggedpointer_payload_lshift),3093 m_objc_debug_taggedpointer_payload_rshift(3094 objc_debug_taggedpointer_payload_rshift),3095 m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {}3096 3097bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::3098 IsPossibleTaggedPointer(lldb::addr_t ptr) {3099 return (ptr & m_objc_debug_taggedpointer_mask) != 0;3100}3101 3102ObjCLanguageRuntime::ClassDescriptorSP3103AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(3104 lldb::addr_t ptr) {3105 ClassDescriptorSP actual_class_descriptor_sp;3106 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();3107 3108 if (!IsPossibleTaggedPointer(unobfuscated))3109 return ObjCLanguageRuntime::ClassDescriptorSP();3110 3111 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) &3112 m_objc_debug_taggedpointer_slot_mask;3113 3114 CacheIterator iterator = m_cache.find(slot), end = m_cache.end();3115 if (iterator != end) {3116 actual_class_descriptor_sp = iterator->second;3117 } else {3118 Process *process(m_runtime.GetProcess());3119 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +3120 m_objc_debug_taggedpointer_classes;3121 Status error;3122 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);3123 if (error.Fail() || slot_data == 0 ||3124 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))3125 return nullptr;3126 actual_class_descriptor_sp =3127 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);3128 if (!actual_class_descriptor_sp) {3129 if (ABISP abi_sp = process->GetABI()) {3130 ObjCISA fixed_isa = abi_sp->FixCodeAddress((ObjCISA)slot_data);3131 actual_class_descriptor_sp =3132 m_runtime.GetClassDescriptorFromISA(fixed_isa);3133 }3134 }3135 if (!actual_class_descriptor_sp)3136 return ObjCLanguageRuntime::ClassDescriptorSP();3137 m_cache[slot] = actual_class_descriptor_sp;3138 }3139 3140 uint64_t data_payload =3141 ((unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>3142 m_objc_debug_taggedpointer_payload_rshift);3143 int64_t data_payload_signed =3144 ((int64_t)(unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>3145 m_objc_debug_taggedpointer_payload_rshift);3146 return ClassDescriptorSP(new ClassDescriptorV2Tagged(3147 actual_class_descriptor_sp, data_payload, data_payload_signed));3148}3149 3150AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(3151 AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,3152 uint64_t objc_debug_taggedpointer_ext_mask,3153 uint32_t objc_debug_taggedpointer_slot_shift,3154 uint32_t objc_debug_taggedpointer_ext_slot_shift,3155 uint32_t objc_debug_taggedpointer_slot_mask,3156 uint32_t objc_debug_taggedpointer_ext_slot_mask,3157 uint32_t objc_debug_taggedpointer_payload_lshift,3158 uint32_t objc_debug_taggedpointer_payload_rshift,3159 uint32_t objc_debug_taggedpointer_ext_payload_lshift,3160 uint32_t objc_debug_taggedpointer_ext_payload_rshift,3161 lldb::addr_t objc_debug_taggedpointer_classes,3162 lldb::addr_t objc_debug_taggedpointer_ext_classes)3163 : TaggedPointerVendorRuntimeAssisted(3164 runtime, objc_debug_taggedpointer_mask,3165 objc_debug_taggedpointer_slot_shift,3166 objc_debug_taggedpointer_slot_mask,3167 objc_debug_taggedpointer_payload_lshift,3168 objc_debug_taggedpointer_payload_rshift,3169 objc_debug_taggedpointer_classes),3170 m_ext_cache(),3171 m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),3172 m_objc_debug_taggedpointer_ext_slot_shift(3173 objc_debug_taggedpointer_ext_slot_shift),3174 m_objc_debug_taggedpointer_ext_slot_mask(3175 objc_debug_taggedpointer_ext_slot_mask),3176 m_objc_debug_taggedpointer_ext_payload_lshift(3177 objc_debug_taggedpointer_ext_payload_lshift),3178 m_objc_debug_taggedpointer_ext_payload_rshift(3179 objc_debug_taggedpointer_ext_payload_rshift),3180 m_objc_debug_taggedpointer_ext_classes(3181 objc_debug_taggedpointer_ext_classes) {}3182 3183bool AppleObjCRuntimeV2::TaggedPointerVendorExtended::3184 IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) {3185 if (!IsPossibleTaggedPointer(ptr))3186 return false;3187 3188 if (m_objc_debug_taggedpointer_ext_mask == 0)3189 return false;3190 3191 return ((ptr & m_objc_debug_taggedpointer_ext_mask) ==3192 m_objc_debug_taggedpointer_ext_mask);3193}3194 3195ObjCLanguageRuntime::ClassDescriptorSP3196AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(3197 lldb::addr_t ptr) {3198 ClassDescriptorSP actual_class_descriptor_sp;3199 uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();3200 3201 if (!IsPossibleTaggedPointer(unobfuscated))3202 return ObjCLanguageRuntime::ClassDescriptorSP();3203 3204 if (!IsPossibleExtendedTaggedPointer(unobfuscated))3205 return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);3206 3207 uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) &3208 m_objc_debug_taggedpointer_ext_slot_mask;3209 3210 CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end();3211 if (iterator != end) {3212 actual_class_descriptor_sp = iterator->second;3213 } else {3214 Process *process(m_runtime.GetProcess());3215 uintptr_t slot_ptr = slot * process->GetAddressByteSize() +3216 m_objc_debug_taggedpointer_ext_classes;3217 Status error;3218 uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);3219 if (error.Fail() || slot_data == 0 ||3220 slot_data == uintptr_t(LLDB_INVALID_ADDRESS))3221 return nullptr;3222 actual_class_descriptor_sp =3223 m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);3224 if (!actual_class_descriptor_sp)3225 return ObjCLanguageRuntime::ClassDescriptorSP();3226 m_ext_cache[slot] = actual_class_descriptor_sp;3227 }3228 3229 uint64_t data_payload = (((uint64_t)unobfuscated3230 << m_objc_debug_taggedpointer_ext_payload_lshift) >>3231 m_objc_debug_taggedpointer_ext_payload_rshift);3232 int64_t data_payload_signed =3233 ((int64_t)((uint64_t)unobfuscated3234 << m_objc_debug_taggedpointer_ext_payload_lshift) >>3235 m_objc_debug_taggedpointer_ext_payload_rshift);3236 3237 return ClassDescriptorSP(new ClassDescriptorV2Tagged(3238 actual_class_descriptor_sp, data_payload, data_payload_signed));3239}3240 3241AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(3242 AppleObjCRuntimeV2 &runtime, const ModuleSP &objc_module_sp,3243 uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask,3244 uint64_t objc_debug_isa_magic_value,3245 uint64_t objc_debug_indexed_isa_magic_mask,3246 uint64_t objc_debug_indexed_isa_magic_value,3247 uint64_t objc_debug_indexed_isa_index_mask,3248 uint64_t objc_debug_indexed_isa_index_shift,3249 lldb::addr_t objc_indexed_classes)3250 : m_runtime(runtime), m_cache(), m_objc_module_wp(objc_module_sp),3251 m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),3252 m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),3253 m_objc_debug_isa_magic_value(objc_debug_isa_magic_value),3254 m_objc_debug_indexed_isa_magic_mask(objc_debug_indexed_isa_magic_mask),3255 m_objc_debug_indexed_isa_magic_value(objc_debug_indexed_isa_magic_value),3256 m_objc_debug_indexed_isa_index_mask(objc_debug_indexed_isa_index_mask),3257 m_objc_debug_indexed_isa_index_shift(objc_debug_indexed_isa_index_shift),3258 m_objc_indexed_classes(objc_indexed_classes), m_indexed_isa_cache() {}3259 3260ObjCLanguageRuntime::ClassDescriptorSP3261AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) {3262 ObjCISA real_isa = 0;3263 if (!EvaluateNonPointerISA(isa, real_isa))3264 return ObjCLanguageRuntime::ClassDescriptorSP();3265 auto cache_iter = m_cache.find(real_isa);3266 if (cache_iter != m_cache.end())3267 return cache_iter->second;3268 auto descriptor_sp =3269 m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);3270 if (descriptor_sp) // cache only positive matches since the table might grow3271 m_cache[real_isa] = descriptor_sp;3272 return descriptor_sp;3273}3274 3275bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA(3276 ObjCISA isa, ObjCISA &ret_isa) {3277 Log *log = GetLog(LLDBLog::Types);3278 3279 LLDB_LOGF(log, "AOCRT::NPI Evaluate(isa = 0x%" PRIx64 ")", (uint64_t)isa);3280 3281 if ((isa & ~m_objc_debug_isa_class_mask) == 0)3282 return false;3283 3284 // If all of the indexed ISA variables are set, then its possible that this3285 // ISA is indexed, and we should first try to get its value using the index.3286 // Note, we check these variables first as the ObjC runtime will set at least3287 // one of their values to 0 if they aren't needed.3288 if (m_objc_debug_indexed_isa_magic_mask &&3289 m_objc_debug_indexed_isa_magic_value &&3290 m_objc_debug_indexed_isa_index_mask &&3291 m_objc_debug_indexed_isa_index_shift && m_objc_indexed_classes) {3292 if ((isa & ~m_objc_debug_indexed_isa_index_mask) == 0)3293 return false;3294 3295 if ((isa & m_objc_debug_indexed_isa_magic_mask) ==3296 m_objc_debug_indexed_isa_magic_value) {3297 // Magic bits are correct, so try extract the index.3298 uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >>3299 m_objc_debug_indexed_isa_index_shift;3300 // If the index is out of bounds of the length of the array then check if3301 // the array has been updated. If that is the case then we should try3302 // read the count again, and update the cache if the count has been3303 // updated.3304 if (index > m_indexed_isa_cache.size()) {3305 LLDB_LOGF(log,3306 "AOCRT::NPI (index = %" PRIu643307 ") exceeds cache (size = %" PRIu64 ")",3308 (uint64_t)index, (uint64_t)m_indexed_isa_cache.size());3309 3310 Process *process(m_runtime.GetProcess());3311 3312 ModuleSP objc_module_sp(m_objc_module_wp.lock());3313 if (!objc_module_sp)3314 return false;3315 3316 Status error;3317 auto objc_indexed_classes_count = ExtractRuntimeGlobalSymbol(3318 process, ConstString("objc_indexed_classes_count"), objc_module_sp,3319 error);3320 if (error.Fail())3321 return false;3322 3323 LLDB_LOGF(log, "AOCRT::NPI (new class count = %" PRIu64 ")",3324 (uint64_t)objc_indexed_classes_count);3325 3326 if (objc_indexed_classes_count > m_indexed_isa_cache.size()) {3327 // Read the class entries we don't have. We should just read all of3328 // them instead of just the one we need as then we can cache those we3329 // may need later.3330 auto num_new_classes =3331 objc_indexed_classes_count - m_indexed_isa_cache.size();3332 const uint32_t addr_size = process->GetAddressByteSize();3333 DataBufferHeap buffer(num_new_classes * addr_size, 0);3334 3335 lldb::addr_t last_read_class =3336 m_objc_indexed_classes + (m_indexed_isa_cache.size() * addr_size);3337 size_t bytes_read = process->ReadMemory(3338 last_read_class, buffer.GetBytes(), buffer.GetByteSize(), error);3339 if (error.Fail() || bytes_read != buffer.GetByteSize())3340 return false;3341 3342 LLDB_LOGF(log, "AOCRT::NPI (read new classes count = %" PRIu64 ")",3343 (uint64_t)num_new_classes);3344 3345 // Append the new entries to the existing cache.3346 DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),3347 process->GetByteOrder(),3348 process->GetAddressByteSize());3349 3350 lldb::offset_t offset = 0;3351 for (unsigned i = 0; i != num_new_classes; ++i)3352 m_indexed_isa_cache.push_back(data.GetAddress(&offset));3353 }3354 }3355 3356 // If the index is still out of range then this isn't a pointer.3357 if (index >= m_indexed_isa_cache.size())3358 return false;3359 3360 LLDB_LOGF(log, "AOCRT::NPI Evaluate(ret_isa = 0x%" PRIx64 ")",3361 (uint64_t)m_indexed_isa_cache[index]);3362 3363 ret_isa = m_indexed_isa_cache[index];3364 return (ret_isa != 0); // this is a pointer so 0 is not a valid value3365 }3366 3367 return false;3368 }3369 3370 // Definitely not an indexed ISA, so try to use a mask to extract the pointer3371 // from the ISA.3372 if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) {3373 ret_isa = isa & m_objc_debug_isa_class_mask;3374 return (ret_isa != 0); // this is a pointer so 0 is not a valid value3375 }3376 return false;3377}3378 3379ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() {3380 if (!m_encoding_to_type_sp)3381 m_encoding_to_type_sp =3382 std::make_shared<AppleObjCTypeEncodingParser>(*this);3383 return m_encoding_to_type_sp;3384}3385 3386lldb_private::AppleObjCRuntime::ObjCISA3387AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) {3388 ObjCISA ret = isa;3389 3390 if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())3391 non_pointer_isa_cache->EvaluateNonPointerISA(isa, ret);3392 3393 return ret;3394}3395 3396bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() {3397 if (m_CFBoolean_values)3398 return true;3399 3400 static ConstString g_dunder_kCFBooleanFalse("__kCFBooleanFalse");3401 static ConstString g_dunder_kCFBooleanTrue("__kCFBooleanTrue");3402 static ConstString g_kCFBooleanFalse("kCFBooleanFalse");3403 static ConstString g_kCFBooleanTrue("kCFBooleanTrue");3404 3405 std::function<lldb::addr_t(ConstString, ConstString)> get_symbol =3406 [this](ConstString sym, ConstString real_sym) -> lldb::addr_t {3407 SymbolContextList sc_list;3408 GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(3409 sym, lldb::eSymbolTypeData, sc_list);3410 if (sc_list.GetSize() == 1) {3411 SymbolContext sc;3412 sc_list.GetContextAtIndex(0, sc);3413 if (sc.symbol)3414 return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());3415 }3416 GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(3417 real_sym, lldb::eSymbolTypeData, sc_list);3418 if (sc_list.GetSize() != 1)3419 return LLDB_INVALID_ADDRESS;3420 3421 SymbolContext sc;3422 sc_list.GetContextAtIndex(0, sc);3423 if (!sc.symbol)3424 return LLDB_INVALID_ADDRESS;3425 3426 lldb::addr_t addr = sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());3427 Status error;3428 addr = GetProcess()->ReadPointerFromMemory(addr, error);3429 if (error.Fail())3430 return LLDB_INVALID_ADDRESS;3431 return addr;3432 };3433 3434 lldb::addr_t false_addr = get_symbol(g_dunder_kCFBooleanFalse, g_kCFBooleanFalse);3435 lldb::addr_t true_addr = get_symbol(g_dunder_kCFBooleanTrue, g_kCFBooleanTrue);3436 3437 return (m_CFBoolean_values = {false_addr, true_addr}).operator bool();3438}3439 3440void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,3441 lldb::addr_t &cf_false) {3442 if (GetCFBooleanValuesIfNeeded()) {3443 cf_true = m_CFBoolean_values->second;3444 cf_false = m_CFBoolean_values->first;3445 } else3446 this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);3447}3448 3449void AppleObjCRuntimeV2::ModulesDidLoad(const ModuleList &module_list) {3450 AppleObjCRuntime::ModulesDidLoad(module_list);3451 if (HasReadObjCLibrary() && m_shared_cache_image_headers_up)3452 m_shared_cache_image_headers_up->SetNeedsUpdate();3453}3454 3455bool AppleObjCRuntimeV2::IsSharedCacheImageLoaded(uint16_t image_index) {3456 if (!m_shared_cache_image_headers_up) {3457 m_shared_cache_image_headers_up =3458 SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);3459 }3460 if (m_shared_cache_image_headers_up)3461 return m_shared_cache_image_headers_up->IsImageLoaded(image_index);3462 3463 return false;3464}3465 3466std::optional<uint64_t> AppleObjCRuntimeV2::GetSharedCacheImageHeaderVersion() {3467 if (!m_shared_cache_image_headers_up) {3468 m_shared_cache_image_headers_up =3469 SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);3470 }3471 if (m_shared_cache_image_headers_up)3472 return m_shared_cache_image_headers_up->GetVersion();3473 3474 return std::nullopt;3475}3476 3477StructuredData::ObjectSP3478AppleObjCRuntimeV2::GetLanguageSpecificData(SymbolContext sc) {3479 auto dict_up = std::make_unique<StructuredData::Dictionary>();3480 dict_up->AddItem("Objective-C runtime version",3481 std::make_unique<StructuredData::UnsignedInteger>(2));3482 return dict_up;3483}3484 3485#pragma mark Frame recognizers3486 3487class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {3488public:3489 ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) {3490 ThreadSP thread_sp = frame_sp->GetThread();3491 ProcessSP process_sp = thread_sp->GetProcess();3492 3493 const lldb::ABISP &abi = process_sp->GetABI();3494 if (!abi)3495 return;3496 3497 TypeSystemClangSP scratch_ts_sp =3498 ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());3499 if (!scratch_ts_sp)3500 return;3501 CompilerType voidstar =3502 scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();3503 3504 ValueList args;3505 Value input_value;3506 input_value.SetCompilerType(voidstar);3507 args.PushValue(input_value);3508 3509 if (!abi->GetArgumentValues(*thread_sp, args))3510 return;3511 3512 addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong();3513 3514 Value value(exception_addr);3515 value.SetCompilerType(voidstar);3516 exception = ValueObjectConstResult::Create(frame_sp.get(), value,3517 ConstString("exception"));3518 exception = ValueObjectRecognizerSynthesizedValue::Create(3519 *exception, eValueTypeVariableArgument);3520 exception = exception->GetDynamicValue(eDynamicDontRunTarget);3521 3522 m_arguments = std::make_shared<ValueObjectList>();3523 m_arguments->Append(exception);3524 3525 m_stop_desc = "hit Objective-C exception";3526 }3527 3528 ValueObjectSP exception;3529 3530 lldb::ValueObjectSP GetExceptionObject() override { return exception; }3531};3532 3533class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {3534 lldb::RecognizedStackFrameSP3535 RecognizeFrame(lldb::StackFrameSP frame) override {3536 return lldb::RecognizedStackFrameSP(3537 new ObjCExceptionRecognizedStackFrame(frame));3538 };3539 std::string GetName() override {3540 return "ObjC Exception Throw StackFrame Recognizer";3541 }3542};3543 3544static void RegisterObjCExceptionRecognizer(Process *process) {3545 FileSpec module;3546 ConstString function;3547 std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();3548 std::vector<ConstString> symbols = {function};3549 3550 process->GetTarget().GetFrameRecognizerManager().AddRecognizer(3551 StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),3552 module.GetFilename(), symbols, Mangled::NamePreference::ePreferDemangled,3553 /*first_instruction_only*/ true);3554}3555