Path: blob/main/contrib/llvm-project/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
39690 views
//===-- AppleObjCRuntimeV2.cpp --------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"9#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"1011#include "lldb/Core/Debugger.h"12#include "lldb/Core/DebuggerEvents.h"13#include "lldb/Core/Module.h"14#include "lldb/Core/PluginManager.h"15#include "lldb/Core/Section.h"16#include "lldb/Core/ValueObjectConstResult.h"17#include "lldb/Core/ValueObjectVariable.h"18#include "lldb/Expression/DiagnosticManager.h"19#include "lldb/Expression/FunctionCaller.h"20#include "lldb/Expression/UtilityFunction.h"21#include "lldb/Host/OptionParser.h"22#include "lldb/Interpreter/CommandObject.h"23#include "lldb/Interpreter/CommandObjectMultiword.h"24#include "lldb/Interpreter/CommandReturnObject.h"25#include "lldb/Interpreter/OptionArgParser.h"26#include "lldb/Interpreter/OptionValueBoolean.h"27#include "lldb/Symbol/CompilerType.h"28#include "lldb/Symbol/ObjectFile.h"29#include "lldb/Symbol/Symbol.h"30#include "lldb/Symbol/TypeList.h"31#include "lldb/Symbol/VariableList.h"32#include "lldb/Target/ABI.h"33#include "lldb/Target/DynamicLoader.h"34#include "lldb/Target/ExecutionContext.h"35#include "lldb/Target/LanguageRuntime.h"36#include "lldb/Target/Platform.h"37#include "lldb/Target/Process.h"38#include "lldb/Target/RegisterContext.h"39#include "lldb/Target/StackFrameRecognizer.h"40#include "lldb/Target/Target.h"41#include "lldb/Target/Thread.h"42#include "lldb/Utility/ConstString.h"43#include "lldb/Utility/LLDBLog.h"44#include "lldb/Utility/Log.h"45#include "lldb/Utility/Scalar.h"46#include "lldb/Utility/Status.h"47#include "lldb/Utility/Stream.h"48#include "lldb/Utility/StreamString.h"49#include "lldb/Utility/Timer.h"50#include "lldb/lldb-enumerations.h"5152#include "AppleObjCClassDescriptorV2.h"53#include "AppleObjCDeclVendor.h"54#include "AppleObjCRuntimeV2.h"55#include "AppleObjCTrampolineHandler.h"56#include "AppleObjCTypeEncodingParser.h"5758#include "clang/AST/ASTContext.h"59#include "clang/AST/DeclObjC.h"60#include "clang/Basic/TargetInfo.h"61#include "llvm/ADT/ScopeExit.h"6263#include <cstdint>64#include <memory>65#include <string>66#include <vector>6768using namespace lldb;69using namespace lldb_private;7071char AppleObjCRuntimeV2::ID = 0;7273static const char *g_get_dynamic_class_info_name =74"__lldb_apple_objc_v2_get_dynamic_class_info";7576static const char *g_get_dynamic_class_info_body = R"(7778extern "C"79{80size_t strlen(const char *);81char *strncpy (char * s1, const char * s2, size_t n);82int printf(const char * format, ...);83}84#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)8586typedef struct _NXMapTable {87void *prototype;88unsigned num_classes;89unsigned num_buckets_minus_one;90void *buckets;91} NXMapTable;9293#define NX_MAPNOTAKEY ((void *)(-1))9495typedef struct BucketInfo96{97const char *name_ptr;98Class isa;99} BucketInfo;100101struct ClassInfo102{103Class isa;104uint32_t hash;105} __attribute__((__packed__));106107uint32_t108__lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,109void *class_infos_ptr,110uint32_t class_infos_byte_size,111uint32_t should_log)112{113DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);114DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);115DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);116const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;117if (grc)118{119const unsigned num_classes = grc->num_classes;120DEBUG_PRINTF ("num_classes = %u\n", grc->num_classes);121if (class_infos_ptr)122{123const unsigned num_buckets_minus_one = grc->num_buckets_minus_one;124DEBUG_PRINTF ("num_buckets_minus_one = %u\n", num_buckets_minus_one);125126const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);127DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);128129ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;130BucketInfo *buckets = (BucketInfo *)grc->buckets;131132uint32_t idx = 0;133for (unsigned i=0; i<=num_buckets_minus_one; ++i)134{135if (buckets[i].name_ptr != NX_MAPNOTAKEY)136{137if (idx < max_class_infos)138{139const char *s = buckets[i].name_ptr;140uint32_t h = 5381;141for (unsigned char c = *s; c; c = *++s)142h = ((h << 5) + h) + c;143class_infos[idx].hash = h;144class_infos[idx].isa = buckets[i].isa;145DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, buckets[i].name_ptr);146}147++idx;148}149}150if (idx < max_class_infos)151{152class_infos[idx].isa = NULL;153class_infos[idx].hash = 0;154}155}156return num_classes;157}158return 0;159}160161)";162163static const char *g_get_dynamic_class_info2_name =164"__lldb_apple_objc_v2_get_dynamic_class_info2";165166static const char *g_get_dynamic_class_info2_body = R"(167168extern "C" {169int printf(const char * format, ...);170void free(void *ptr);171Class* objc_copyRealizedClassList_nolock(unsigned int *outCount);172const char* objc_debug_class_getNameRaw(Class cls);173}174175#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)176177struct ClassInfo178{179Class isa;180uint32_t hash;181} __attribute__((__packed__));182183uint32_t184__lldb_apple_objc_v2_get_dynamic_class_info2(void *gdb_objc_realized_classes_ptr,185void *class_infos_ptr,186uint32_t class_infos_byte_size,187uint32_t should_log)188{189DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);190DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);191192const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);193DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);194195ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;196197uint32_t count = 0;198Class* realized_class_list = objc_copyRealizedClassList_nolock(&count);199DEBUG_PRINTF ("count = %u\n", count);200201uint32_t idx = 0;202for (uint32_t i=0; i<count; ++i)203{204if (idx < max_class_infos)205{206Class isa = realized_class_list[i];207const char *name_ptr = objc_debug_class_getNameRaw(isa);208if (!name_ptr)209continue;210const char *s = name_ptr;211uint32_t h = 5381;212for (unsigned char c = *s; c; c = *++s)213h = ((h << 5) + h) + c;214class_infos[idx].hash = h;215class_infos[idx].isa = isa;216DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);217}218idx++;219}220221if (idx < max_class_infos)222{223class_infos[idx].isa = NULL;224class_infos[idx].hash = 0;225}226227free(realized_class_list);228return count;229}230)";231232static const char *g_get_dynamic_class_info3_name =233"__lldb_apple_objc_v2_get_dynamic_class_info3";234235static const char *g_get_dynamic_class_info3_body = R"(236237extern "C" {238int printf(const char * format, ...);239void free(void *ptr);240size_t objc_getRealizedClassList_trylock(Class *buffer, size_t len);241const char* objc_debug_class_getNameRaw(Class cls);242const char* class_getName(Class cls);243}244245#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)246247struct ClassInfo248{249Class isa;250uint32_t hash;251} __attribute__((__packed__));252253uint32_t254__lldb_apple_objc_v2_get_dynamic_class_info3(void *gdb_objc_realized_classes_ptr,255void *class_infos_ptr,256uint32_t class_infos_byte_size,257void *class_buffer,258uint32_t class_buffer_len,259uint32_t should_log)260{261DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);262DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);263264const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);265DEBUG_PRINTF ("max_class_infos = %u\n", max_class_infos);266267ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;268269Class *realized_class_list = (Class*)class_buffer;270271uint32_t count = objc_getRealizedClassList_trylock(realized_class_list,272class_buffer_len);273DEBUG_PRINTF ("count = %u\n", count);274275uint32_t idx = 0;276for (uint32_t i=0; i<count; ++i)277{278if (idx < max_class_infos)279{280Class isa = realized_class_list[i];281const char *name_ptr = objc_debug_class_getNameRaw(isa);282if (!name_ptr) {283class_getName(isa); // Realize name of lazy classes.284name_ptr = objc_debug_class_getNameRaw(isa);285}286if (!name_ptr)287continue;288const char *s = name_ptr;289uint32_t h = 5381;290for (unsigned char c = *s; c; c = *++s)291h = ((h << 5) + h) + c;292class_infos[idx].hash = h;293class_infos[idx].isa = isa;294DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name_ptr);295}296idx++;297}298299if (idx < max_class_infos)300{301class_infos[idx].isa = NULL;302class_infos[idx].hash = 0;303}304305return count;306}307)";308309// We'll substitute in class_getName or class_getNameRaw depending310// on which is present.311static const char *g_shared_cache_class_name_funcptr = R"(312extern "C"313{314const char *%s(void *objc_class);315const char *(*class_name_lookup_func)(void *) = %s;316}317)";318319static const char *g_get_shared_cache_class_info_name =320"__lldb_apple_objc_v2_get_shared_cache_class_info";321322static const char *g_get_shared_cache_class_info_body = R"(323324extern "C"325{326size_t strlen(const char *);327char *strncpy (char * s1, const char * s2, size_t n);328int printf(const char * format, ...);329}330331#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)332333334struct objc_classheader_t {335int32_t clsOffset;336int32_t hiOffset;337};338339struct objc_classheader_v16_t {340uint64_t isDuplicate : 1,341objectCacheOffset : 47, // Offset from the shared cache base342dylibObjCIndex : 16;343};344345struct objc_clsopt_t {346uint32_t capacity;347uint32_t occupied;348uint32_t shift;349uint32_t mask;350uint32_t zero;351uint32_t unused;352uint64_t salt;353uint32_t scramble[256];354uint8_t tab[0]; // tab[mask+1]355// uint8_t checkbytes[capacity];356// int32_t offset[capacity];357// objc_classheader_t clsOffsets[capacity];358// uint32_t duplicateCount;359// objc_classheader_t duplicateOffsets[duplicateCount];360};361362struct objc_clsopt_v16_t {363uint32_t version;364uint32_t capacity;365uint32_t occupied;366uint32_t shift;367uint32_t mask;368uint32_t zero;369uint64_t salt;370uint32_t scramble[256];371uint8_t tab[0]; // tab[mask+1]372// uint8_t checkbytes[capacity];373// int32_t offset[capacity];374// objc_classheader_t clsOffsets[capacity];375// uint32_t duplicateCount;376// objc_classheader_t duplicateOffsets[duplicateCount];377};378379struct objc_opt_t {380uint32_t version;381int32_t selopt_offset;382int32_t headeropt_offset;383int32_t clsopt_offset;384};385386struct objc_opt_v14_t {387uint32_t version;388uint32_t flags;389int32_t selopt_offset;390int32_t headeropt_offset;391int32_t clsopt_offset;392};393394struct objc_opt_v16_t {395uint32_t version;396uint32_t flags;397int32_t selopt_offset;398int32_t headeropt_ro_offset;399int32_t unused_clsopt_offset;400int32_t unused_protocolopt_offset;401int32_t headeropt_rw_offset;402int32_t unused_protocolopt2_offset;403int32_t largeSharedCachesClassOffset;404int32_t largeSharedCachesProtocolOffset;405uint64_t relativeMethodSelectorBaseAddressCacheOffset;406};407408struct ClassInfo409{410Class isa;411uint32_t hash;412} __attribute__((__packed__));413414uint32_t415__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,416void *shared_cache_base_ptr,417void *class_infos_ptr,418uint64_t *relative_selector_offset,419uint32_t class_infos_byte_size,420uint32_t should_log)421{422*relative_selector_offset = 0;423uint32_t idx = 0;424DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);425DEBUG_PRINTF ("shared_cache_base_ptr = %p\n", shared_cache_base_ptr);426DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);427DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));428if (objc_opt_ro_ptr)429{430const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;431const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;432const objc_opt_v16_t* objc_opt_v16 = (objc_opt_v16_t*)objc_opt_ro_ptr;433if (objc_opt->version >= 16)434{435*relative_selector_offset = objc_opt_v16->relativeMethodSelectorBaseAddressCacheOffset;436DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v16->version);437DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v16->flags);438DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v16->selopt_offset);439DEBUG_PRINTF ("objc_opt->headeropt_ro_offset = %d\n", objc_opt_v16->headeropt_ro_offset);440DEBUG_PRINTF ("objc_opt->relativeMethodSelectorBaseAddressCacheOffset = %d\n", *relative_selector_offset);441}442else if (objc_opt->version >= 14)443{444DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);445DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);446DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);447DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);448DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);449}450else451{452DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);453DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);454DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);455DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);456}457458if (objc_opt->version == 16)459{460const objc_clsopt_v16_t* clsopt = (const objc_clsopt_v16_t*)((uint8_t *)objc_opt + objc_opt_v16->largeSharedCachesClassOffset);461const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);462463DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);464465ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;466467const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];468const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);469const objc_classheader_v16_t *classOffsets = (const objc_classheader_v16_t *)(offsets + clsopt->capacity);470471DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);472DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);473DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);474475for (uint32_t i=0; i<clsopt->capacity; ++i)476{477const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;478DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);479480if (classOffsets[i].isDuplicate) {481DEBUG_PRINTF("isDuplicate = true\n");482continue; // duplicate483}484485if (objectCacheOffset == 0) {486DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");487continue; // invalid offset488}489490if (class_infos && idx < max_class_infos)491{492class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);493494// Lookup the class name.495const char *name = class_name_lookup_func(class_infos[idx].isa);496DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);497498// Hash the class name so we don't have to read it.499const char *s = name;500uint32_t h = 5381;501for (unsigned char c = *s; c; c = *++s)502{503// class_getName demangles swift names and the hash must504// be calculated on the mangled name. hash==0 means lldb505// will fetch the mangled name and compute the hash in506// ParseClassInfoArray.507if (c == '.')508{509h = 0;510break;511}512h = ((h << 5) + h) + c;513}514class_infos[idx].hash = h;515}516else517{518DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");519}520++idx;521}522523const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];524const uint32_t duplicate_count = *duplicate_count_ptr;525const objc_classheader_v16_t *duplicateClassOffsets = (const objc_classheader_v16_t *)(&duplicate_count_ptr[1]);526527DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);528DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);529530for (uint32_t i=0; i<duplicate_count; ++i)531{532const uint64_t objectCacheOffset = classOffsets[i].objectCacheOffset;533DEBUG_PRINTF("objectCacheOffset[%u] = %u\n", i, objectCacheOffset);534535if (classOffsets[i].isDuplicate) {536DEBUG_PRINTF("isDuplicate = true\n");537continue; // duplicate538}539540if (objectCacheOffset == 0) {541DEBUG_PRINTF("objectCacheOffset == invalidEntryOffset\n");542continue; // invalid offset543}544545if (class_infos && idx < max_class_infos)546{547class_infos[idx].isa = (Class)((uint8_t *)shared_cache_base_ptr + objectCacheOffset);548549// Lookup the class name.550const char *name = class_name_lookup_func(class_infos[idx].isa);551DEBUG_PRINTF("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);552553// Hash the class name so we don't have to read it.554const char *s = name;555uint32_t h = 5381;556for (unsigned char c = *s; c; c = *++s)557{558// class_getName demangles swift names and the hash must559// be calculated on the mangled name. hash==0 means lldb560// will fetch the mangled name and compute the hash in561// ParseClassInfoArray.562if (c == '.')563{564h = 0;565break;566}567h = ((h << 5) + h) + c;568}569class_infos[idx].hash = h;570}571}572}573else if (objc_opt->version >= 12 && objc_opt->version <= 15)574{575const objc_clsopt_t* clsopt = NULL;576if (objc_opt->version >= 14)577clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);578else579clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);580const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);581DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);582ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;583int32_t invalidEntryOffset = 0;584// this is safe to do because the version field order is invariant585if (objc_opt->version == 12)586invalidEntryOffset = 16;587const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];588const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);589const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);590DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);591DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);592DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);593DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);594for (uint32_t i=0; i<clsopt->capacity; ++i)595{596const int32_t clsOffset = classOffsets[i].clsOffset;597DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);598if (clsOffset & 1)599{600DEBUG_PRINTF("clsOffset & 1\n");601continue; // duplicate602}603else if (clsOffset == invalidEntryOffset)604{605DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");606continue; // invalid offset607}608609if (class_infos && idx < max_class_infos)610{611class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);612const char *name = class_name_lookup_func (class_infos[idx].isa);613DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);614// Hash the class name so we don't have to read it615const char *s = name;616uint32_t h = 5381;617for (unsigned char c = *s; c; c = *++s)618{619// class_getName demangles swift names and the hash must620// be calculated on the mangled name. hash==0 means lldb621// will fetch the mangled name and compute the hash in622// ParseClassInfoArray.623if (c == '.')624{625h = 0;626break;627}628h = ((h << 5) + h) + c;629}630class_infos[idx].hash = h;631}632else633{634DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");635}636++idx;637}638639const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];640const uint32_t duplicate_count = *duplicate_count_ptr;641const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);642DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);643DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);644for (uint32_t i=0; i<duplicate_count; ++i)645{646const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;647if (clsOffset & 1)648continue; // duplicate649else if (clsOffset == invalidEntryOffset)650continue; // invalid offset651652if (class_infos && idx < max_class_infos)653{654class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);655const char *name = class_name_lookup_func (class_infos[idx].isa);656DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);657// Hash the class name so we don't have to read it658const char *s = name;659uint32_t h = 5381;660for (unsigned char c = *s; c; c = *++s)661{662// class_getName demangles swift names and the hash must663// be calculated on the mangled name. hash==0 means lldb664// will fetch the mangled name and compute the hash in665// ParseClassInfoArray.666if (c == '.')667{668h = 0;669break;670}671h = ((h << 5) + h) + c;672}673class_infos[idx].hash = h;674}675++idx;676}677}678DEBUG_PRINTF ("%u class_infos\n", idx);679DEBUG_PRINTF ("done\n");680}681return idx;682}683684685)";686687static uint64_t688ExtractRuntimeGlobalSymbol(Process *process, ConstString name,689const ModuleSP &module_sp, Status &error,690bool read_value = true, uint8_t byte_size = 0,691uint64_t default_value = LLDB_INVALID_ADDRESS,692SymbolType sym_type = lldb::eSymbolTypeData) {693if (!process) {694error.SetErrorString("no process");695return default_value;696}697698if (!module_sp) {699error.SetErrorString("no module");700return default_value;701}702703if (!byte_size)704byte_size = process->GetAddressByteSize();705const Symbol *symbol =706module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);707708if (!symbol || !symbol->ValueIsAddress()) {709error.SetErrorString("no symbol");710return default_value;711}712713lldb::addr_t symbol_load_addr =714symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());715if (symbol_load_addr == LLDB_INVALID_ADDRESS) {716error.SetErrorString("symbol address invalid");717return default_value;718}719720if (read_value)721return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size,722default_value, error);723return symbol_load_addr;724}725726static void RegisterObjCExceptionRecognizer(Process *process);727728AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process,729const ModuleSP &objc_module_sp)730: AppleObjCRuntime(process), m_objc_module_sp(objc_module_sp),731m_dynamic_class_info_extractor(*this),732m_shared_cache_class_info_extractor(*this), m_decl_vendor_up(),733m_tagged_pointer_obfuscator(LLDB_INVALID_ADDRESS),734m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),735m_relative_selector_base(LLDB_INVALID_ADDRESS), m_hash_signature(),736m_has_object_getClass(false), m_has_objc_copyRealizedClassList(false),737m_has_objc_getRealizedClassList_trylock(false), m_loaded_objc_opt(false),738m_non_pointer_isa_cache_up(),739m_tagged_pointer_vendor_up(740TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),741m_encoding_to_type_sp(), m_CFBoolean_values(),742m_realized_class_generation_count(0) {743static const ConstString g_gdb_object_getClass("gdb_object_getClass");744m_has_object_getClass = HasSymbol(g_gdb_object_getClass);745static const ConstString g_objc_copyRealizedClassList(746"_ZL33objc_copyRealizedClassList_nolockPj");747static const ConstString g_objc_getRealizedClassList_trylock(748"_objc_getRealizedClassList_trylock");749m_has_objc_copyRealizedClassList = HasSymbol(g_objc_copyRealizedClassList);750m_has_objc_getRealizedClassList_trylock =751HasSymbol(g_objc_getRealizedClassList_trylock);752WarnIfNoExpandedSharedCache();753RegisterObjCExceptionRecognizer(process);754}755756LanguageRuntime *757AppleObjCRuntimeV2::GetPreferredLanguageRuntime(ValueObject &in_value) {758if (auto process_sp = in_value.GetProcessSP()) {759assert(process_sp.get() == m_process);760if (auto descriptor_sp = GetNonKVOClassDescriptor(in_value)) {761LanguageType impl_lang = descriptor_sp->GetImplementationLanguage();762if (impl_lang != eLanguageTypeUnknown)763return process_sp->GetLanguageRuntime(impl_lang);764}765}766return nullptr;767}768769bool AppleObjCRuntimeV2::GetDynamicTypeAndAddress(770ValueObject &in_value, lldb::DynamicValueType use_dynamic,771TypeAndOrName &class_type_or_name, Address &address,772Value::ValueType &value_type) {773// We should never get here with a null process...774assert(m_process != nullptr);775776// The Runtime is attached to a particular process, you shouldn't pass in a777// value from another process. Note, however, the process might be NULL (e.g.778// if the value was made with SBTarget::EvaluateExpression...) in which case779// it is sufficient if the target's match:780781Process *process = in_value.GetProcessSP().get();782if (process)783assert(process == m_process);784else785assert(in_value.GetTargetSP().get() == m_process->CalculateTarget().get());786787class_type_or_name.Clear();788value_type = Value::ValueType::Scalar;789790// Make sure we can have a dynamic value before starting...791if (CouldHaveDynamicValue(in_value)) {792// First job, pull out the address at 0 offset from the object That will793// be the ISA pointer.794ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(in_value));795if (objc_class_sp) {796const addr_t object_ptr = in_value.GetPointerValue();797address.SetRawAddress(object_ptr);798799ConstString class_name(objc_class_sp->GetClassName());800class_type_or_name.SetName(class_name);801TypeSP type_sp(objc_class_sp->GetType());802if (type_sp)803class_type_or_name.SetTypeSP(type_sp);804else {805type_sp = LookupInCompleteClassCache(class_name);806if (type_sp) {807objc_class_sp->SetType(type_sp);808class_type_or_name.SetTypeSP(type_sp);809} else {810// try to go for a CompilerType at least811if (auto *vendor = GetDeclVendor()) {812auto types = vendor->FindTypes(class_name, /*max_matches*/ 1);813if (!types.empty())814class_type_or_name.SetCompilerType(types.front());815}816}817}818}819}820return !class_type_or_name.IsEmpty();821}822823// Static Functions824LanguageRuntime *AppleObjCRuntimeV2::CreateInstance(Process *process,825LanguageType language) {826// FIXME: This should be a MacOS or iOS process, and we need to look for the827// OBJC section to make828// sure we aren't using the V1 runtime.829if (language == eLanguageTypeObjC) {830ModuleSP objc_module_sp;831832if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==833ObjCRuntimeVersions::eAppleObjC_V2)834return new AppleObjCRuntimeV2(process, objc_module_sp);835return nullptr;836}837return nullptr;838}839840static constexpr OptionDefinition g_objc_classtable_dump_options[] = {841{LLDB_OPT_SET_ALL,842false,843"verbose",844'v',845OptionParser::eNoArgument,846nullptr,847{},8480,849eArgTypeNone,850"Print ivar and method information in detail"}};851852class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {853public:854class CommandOptions : public Options {855public:856CommandOptions() : Options(), m_verbose(false, false) {}857858~CommandOptions() override = default;859860Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,861ExecutionContext *execution_context) override {862Status error;863const int short_option = m_getopt_table[option_idx].val;864switch (short_option) {865case 'v':866m_verbose.SetCurrentValue(true);867m_verbose.SetOptionWasSet();868break;869870default:871error.SetErrorStringWithFormat("unrecognized short option '%c'",872short_option);873break;874}875876return error;877}878879void OptionParsingStarting(ExecutionContext *execution_context) override {880m_verbose.Clear();881}882883llvm::ArrayRef<OptionDefinition> GetDefinitions() override {884return llvm::ArrayRef(g_objc_classtable_dump_options);885}886887OptionValueBoolean m_verbose;888};889890CommandObjectObjC_ClassTable_Dump(CommandInterpreter &interpreter)891: CommandObjectParsed(interpreter, "dump",892"Dump information on Objective-C classes "893"known to the current process.",894"language objc class-table dump",895eCommandRequiresProcess |896eCommandProcessMustBeLaunched |897eCommandProcessMustBePaused),898m_options() {899AddSimpleArgumentList(eArgTypeRegularExpression, eArgRepeatOptional);900}901902~CommandObjectObjC_ClassTable_Dump() override = default;903904Options *GetOptions() override { return &m_options; }905906protected:907void DoExecute(Args &command, CommandReturnObject &result) override {908std::unique_ptr<RegularExpression> regex_up;909switch (command.GetArgumentCount()) {910case 0:911break;912case 1: {913regex_up =914std::make_unique<RegularExpression>(command.GetArgumentAtIndex(0));915if (!regex_up->IsValid()) {916result.AppendError(917"invalid argument - please provide a valid regular expression");918result.SetStatus(lldb::eReturnStatusFailed);919return;920}921break;922}923default: {924result.AppendError("please provide 0 or 1 arguments");925result.SetStatus(lldb::eReturnStatusFailed);926return;927}928}929930Process *process = m_exe_ctx.GetProcessPtr();931ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);932if (objc_runtime) {933auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();934auto iterator = iterators_pair.first;935auto &std_out = result.GetOutputStream();936for (; iterator != iterators_pair.second; iterator++) {937if (iterator->second) {938const char *class_name =939iterator->second->GetClassName().AsCString("<unknown>");940if (regex_up && class_name &&941!regex_up->Execute(llvm::StringRef(class_name)))942continue;943std_out.Printf("isa = 0x%" PRIx64, iterator->first);944std_out.Printf(" name = %s", class_name);945std_out.Printf(" instance size = %" PRIu64,946iterator->second->GetInstanceSize());947std_out.Printf(" num ivars = %" PRIuPTR,948(uintptr_t)iterator->second->GetNumIVars());949if (auto superclass = iterator->second->GetSuperclass()) {950std_out.Printf(" superclass = %s",951superclass->GetClassName().AsCString("<unknown>"));952}953std_out.Printf("\n");954if (m_options.m_verbose) {955for (size_t i = 0; i < iterator->second->GetNumIVars(); i++) {956auto ivar = iterator->second->GetIVarAtIndex(i);957std_out.Printf(958" ivar name = %s type = %s size = %" PRIu64959" offset = %" PRId32 "\n",960ivar.m_name.AsCString("<unknown>"),961ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),962ivar.m_size, ivar.m_offset);963}964965iterator->second->Describe(966nullptr,967[&std_out](const char *name, const char *type) -> bool {968std_out.Printf(" instance method name = %s type = %s\n",969name, type);970return false;971},972[&std_out](const char *name, const char *type) -> bool {973std_out.Printf(" class method name = %s type = %s\n", name,974type);975return false;976},977nullptr);978}979} else {980if (regex_up && !regex_up->Execute(llvm::StringRef()))981continue;982std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n",983iterator->first);984}985}986result.SetStatus(lldb::eReturnStatusSuccessFinishResult);987return;988}989result.AppendError("current process has no Objective-C runtime loaded");990result.SetStatus(lldb::eReturnStatusFailed);991}992993CommandOptions m_options;994};995996class CommandObjectMultiwordObjC_TaggedPointer_Info997: public CommandObjectParsed {998public:999CommandObjectMultiwordObjC_TaggedPointer_Info(CommandInterpreter &interpreter)1000: CommandObjectParsed(1001interpreter, "info", "Dump information on a tagged pointer.",1002"language objc tagged-pointer info",1003eCommandRequiresProcess | eCommandProcessMustBeLaunched |1004eCommandProcessMustBePaused) {1005AddSimpleArgumentList(eArgTypeAddress, eArgRepeatPlus);1006}10071008~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;10091010protected:1011void DoExecute(Args &command, CommandReturnObject &result) override {1012if (command.GetArgumentCount() == 0) {1013result.AppendError("this command requires arguments");1014result.SetStatus(lldb::eReturnStatusFailed);1015return;1016}10171018Process *process = m_exe_ctx.GetProcessPtr();1019ExecutionContext exe_ctx(process);10201021ObjCLanguageRuntime *objc_runtime = ObjCLanguageRuntime::Get(*process);1022if (!objc_runtime) {1023result.AppendError("current process has no Objective-C runtime loaded");1024result.SetStatus(lldb::eReturnStatusFailed);1025return;1026}10271028ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor =1029objc_runtime->GetTaggedPointerVendor();1030if (!tagged_ptr_vendor) {1031result.AppendError("current process has no tagged pointer support");1032result.SetStatus(lldb::eReturnStatusFailed);1033return;1034}10351036for (size_t i = 0; i < command.GetArgumentCount(); i++) {1037const char *arg_str = command.GetArgumentAtIndex(i);1038if (!arg_str)1039continue;10401041Status error;1042lldb::addr_t arg_addr = OptionArgParser::ToAddress(1043&exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);1044if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail()) {1045result.AppendErrorWithFormatv(1046"could not convert '{0}' to a valid address\n", arg_str);1047result.SetStatus(lldb::eReturnStatusFailed);1048return;1049}10501051if (!tagged_ptr_vendor->IsPossibleTaggedPointer(arg_addr)) {1052result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);1053continue;1054}10551056auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);1057if (!descriptor_sp) {1058result.AppendErrorWithFormatv(1059"could not get class descriptor for {0:x16}\n", arg_addr);1060result.SetStatus(lldb::eReturnStatusFailed);1061return;1062}10631064uint64_t info_bits = 0;1065uint64_t value_bits = 0;1066uint64_t payload = 0;1067if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits,1068&payload)) {1069result.GetOutputStream().Format(1070"{0:x} is tagged\n"1071"\tpayload = {1:x16}\n"1072"\tvalue = {2:x16}\n"1073"\tinfo bits = {3:x16}\n"1074"\tclass = {4}\n",1075arg_addr, payload, value_bits, info_bits,1076descriptor_sp->GetClassName().AsCString("<unknown>"));1077} else {1078result.GetOutputStream().Format("{0:x16} is not tagged\n", arg_addr);1079}1080}10811082result.SetStatus(lldb::eReturnStatusSuccessFinishResult);1083}1084};10851086class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword {1087public:1088CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)1089: CommandObjectMultiword(1090interpreter, "class-table",1091"Commands for operating on the Objective-C class table.",1092"class-table <subcommand> [<subcommand-options>]") {1093LoadSubCommand(1094"dump",1095CommandObjectSP(new CommandObjectObjC_ClassTable_Dump(interpreter)));1096}10971098~CommandObjectMultiwordObjC_ClassTable() override = default;1099};11001101class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword {1102public:1103CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)1104: CommandObjectMultiword(1105interpreter, "tagged-pointer",1106"Commands for operating on Objective-C tagged pointers.",1107"class-table <subcommand> [<subcommand-options>]") {1108LoadSubCommand(1109"info",1110CommandObjectSP(1111new CommandObjectMultiwordObjC_TaggedPointer_Info(interpreter)));1112}11131114~CommandObjectMultiwordObjC_TaggedPointer() override = default;1115};11161117class CommandObjectMultiwordObjC : public CommandObjectMultiword {1118public:1119CommandObjectMultiwordObjC(CommandInterpreter &interpreter)1120: CommandObjectMultiword(1121interpreter, "objc",1122"Commands for operating on the Objective-C language runtime.",1123"objc <subcommand> [<subcommand-options>]") {1124LoadSubCommand("class-table",1125CommandObjectSP(1126new CommandObjectMultiwordObjC_ClassTable(interpreter)));1127LoadSubCommand("tagged-pointer",1128CommandObjectSP(new CommandObjectMultiwordObjC_TaggedPointer(1129interpreter)));1130}11311132~CommandObjectMultiwordObjC() override = default;1133};11341135void AppleObjCRuntimeV2::Initialize() {1136PluginManager::RegisterPlugin(1137GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 2",1138CreateInstance,1139[](CommandInterpreter &interpreter) -> lldb::CommandObjectSP {1140return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));1141},1142GetBreakpointExceptionPrecondition);1143}11441145void AppleObjCRuntimeV2::Terminate() {1146PluginManager::UnregisterPlugin(CreateInstance);1147}11481149BreakpointResolverSP1150AppleObjCRuntimeV2::CreateExceptionResolver(const BreakpointSP &bkpt,1151bool catch_bp, bool throw_bp) {1152BreakpointResolverSP resolver_sp;11531154if (throw_bp)1155resolver_sp = std::make_shared<BreakpointResolverName>(1156bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),1157eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,1158eLazyBoolNo);1159// FIXME: We don't do catch breakpoints for ObjC yet.1160// Should there be some way for the runtime to specify what it can do in this1161// regard?1162return resolver_sp;1163}11641165llvm::Expected<std::unique_ptr<UtilityFunction>>1166AppleObjCRuntimeV2::CreateObjectChecker(std::string name,1167ExecutionContext &exe_ctx) {1168char check_function_code[2048];11691170int len = 0;1171if (m_has_object_getClass) {1172len = ::snprintf(check_function_code, sizeof(check_function_code), R"(1173extern "C" void *gdb_object_getClass(void *);1174extern "C" int printf(const char *format, ...);1175extern "C" void1176%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {1177if ($__lldb_arg_obj == (void *)0)1178return; // nil is ok1179if (!gdb_object_getClass($__lldb_arg_obj)) {1180*((volatile int *)0) = 'ocgc';1181} else if ($__lldb_arg_selector != (void *)0) {1182signed char $responds = (signed char)1183[(id)$__lldb_arg_obj respondsToSelector:1184(void *) $__lldb_arg_selector];1185if ($responds == (signed char) 0)1186*((volatile int *)0) = 'ocgc';1187}1188})",1189name.c_str());1190} else {1191len = ::snprintf(check_function_code, sizeof(check_function_code), R"(1192extern "C" void *gdb_class_getClass(void *);1193extern "C" int printf(const char *format, ...);1194extern "C" void1195%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) {1196if ($__lldb_arg_obj == (void *)0)1197return; // nil is ok1198void **$isa_ptr = (void **)$__lldb_arg_obj;1199if (*$isa_ptr == (void *)0 ||1200!gdb_class_getClass(*$isa_ptr))1201*((volatile int *)0) = 'ocgc';1202else if ($__lldb_arg_selector != (void *)0) {1203signed char $responds = (signed char)1204[(id)$__lldb_arg_obj respondsToSelector:1205(void *) $__lldb_arg_selector];1206if ($responds == (signed char) 0)1207*((volatile int *)0) = 'ocgc';1208}1209})",1210name.c_str());1211}12121213assert(len < (int)sizeof(check_function_code));1214UNUSED_IF_ASSERT_DISABLED(len);12151216return GetTargetRef().CreateUtilityFunction(check_function_code, name,1217eLanguageTypeC, exe_ctx);1218}12191220size_t AppleObjCRuntimeV2::GetByteOffsetForIvar(CompilerType &parent_ast_type,1221const char *ivar_name) {1222uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;12231224ConstString class_name = parent_ast_type.GetTypeName();1225if (!class_name.IsEmpty() && ivar_name && ivar_name[0]) {1226// Make the objective C V2 mangled name for the ivar offset from the class1227// name and ivar name1228std::string buffer("OBJC_IVAR_$_");1229buffer.append(class_name.AsCString());1230buffer.push_back('.');1231buffer.append(ivar_name);1232ConstString ivar_const_str(buffer.c_str());12331234// Try to get the ivar offset address from the symbol table first using the1235// name we created above1236SymbolContextList sc_list;1237Target &target = m_process->GetTarget();1238target.GetImages().FindSymbolsWithNameAndType(ivar_const_str,1239eSymbolTypeObjCIVar, sc_list);12401241addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;12421243Status error;1244SymbolContext ivar_offset_symbol;1245if (sc_list.GetSize() == 1 &&1246sc_list.GetContextAtIndex(0, ivar_offset_symbol)) {1247if (ivar_offset_symbol.symbol)1248ivar_offset_address =1249ivar_offset_symbol.symbol->GetLoadAddress(&target);1250}12511252// If we didn't get the ivar offset address from the symbol table, fall1253// back to getting it from the runtime1254if (ivar_offset_address == LLDB_INVALID_ADDRESS)1255ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);12561257if (ivar_offset_address != LLDB_INVALID_ADDRESS)1258ivar_offset = m_process->ReadUnsignedIntegerFromMemory(1259ivar_offset_address, 4, LLDB_INVALID_IVAR_OFFSET, error);1260}1261return ivar_offset;1262}12631264// tagged pointers are special not-a-real-pointer values that contain both type1265// and value information this routine attempts to check with as little1266// computational effort as possible whether something could possibly be a1267// tagged pointer - false positives are possible but false negatives shouldn't1268bool AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr) {1269if (!m_tagged_pointer_vendor_up)1270return false;1271return m_tagged_pointer_vendor_up->IsPossibleTaggedPointer(ptr);1272}12731274class RemoteNXMapTable {1275public:1276RemoteNXMapTable() : m_end_iterator(*this, -1) {}12771278void Dump() {1279printf("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);1280printf("RemoteNXMapTable.m_count = %u\n", m_count);1281printf("RemoteNXMapTable.m_num_buckets_minus_one = %u\n",1282m_num_buckets_minus_one);1283printf("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);1284}12851286bool ParseHeader(Process *process, lldb::addr_t load_addr) {1287m_process = process;1288m_load_addr = load_addr;1289m_map_pair_size = m_process->GetAddressByteSize() * 2;1290m_invalid_key =1291m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;1292Status err;12931294// This currently holds true for all platforms we support, but we might1295// need to change this to use get the actually byte size of "unsigned" from1296// the target AST...1297const uint32_t unsigned_byte_size = sizeof(uint32_t);1298// Skip the prototype as we don't need it (const struct1299// +NXMapTablePrototype *prototype)13001301bool success = true;1302if (load_addr == LLDB_INVALID_ADDRESS)1303success = false;1304else {1305lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();13061307// unsigned count;1308m_count = m_process->ReadUnsignedIntegerFromMemory(1309cursor, unsigned_byte_size, 0, err);1310if (m_count) {1311cursor += unsigned_byte_size;13121313// unsigned nbBucketsMinusOne;1314m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(1315cursor, unsigned_byte_size, 0, err);1316cursor += unsigned_byte_size;13171318// void *buckets;1319m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);13201321success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;1322}1323}13241325if (!success) {1326m_count = 0;1327m_num_buckets_minus_one = 0;1328m_buckets_ptr = LLDB_INVALID_ADDRESS;1329}1330return success;1331}13321333// const_iterator mimics NXMapState and its code comes from NXInitMapState1334// and NXNextMapState.1335typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;13361337friend class const_iterator;1338class const_iterator {1339public:1340const_iterator(RemoteNXMapTable &parent, int index)1341: m_parent(parent), m_index(index) {1342AdvanceToValidIndex();1343}13441345const_iterator(const const_iterator &rhs)1346: m_parent(rhs.m_parent), m_index(rhs.m_index) {1347// AdvanceToValidIndex() has been called by rhs already.1348}13491350const_iterator &operator=(const const_iterator &rhs) {1351// AdvanceToValidIndex() has been called by rhs already.1352assert(&m_parent == &rhs.m_parent);1353m_index = rhs.m_index;1354return *this;1355}13561357bool operator==(const const_iterator &rhs) const {1358if (&m_parent != &rhs.m_parent)1359return false;1360if (m_index != rhs.m_index)1361return false;13621363return true;1364}13651366bool operator!=(const const_iterator &rhs) const {1367return !(operator==(rhs));1368}13691370const_iterator &operator++() {1371AdvanceToValidIndex();1372return *this;1373}13741375element operator*() const {1376if (m_index == -1) {1377// TODO find a way to make this an error, but not an assert1378return element();1379}13801381lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;1382size_t map_pair_size = m_parent.m_map_pair_size;1383lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);13841385Status err;13861387lldb::addr_t key =1388m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);1389if (!err.Success())1390return element();1391lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(1392pair_ptr + m_parent.m_process->GetAddressByteSize(), err);1393if (!err.Success())1394return element();13951396std::string key_string;13971398m_parent.m_process->ReadCStringFromMemory(key, key_string, err);1399if (!err.Success())1400return element();14011402return element(ConstString(key_string.c_str()),1403(ObjCLanguageRuntime::ObjCISA)value);1404}14051406private:1407void AdvanceToValidIndex() {1408if (m_index == -1)1409return;14101411const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;1412const size_t map_pair_size = m_parent.m_map_pair_size;1413const lldb::addr_t invalid_key = m_parent.m_invalid_key;1414Status err;14151416while (m_index--) {1417lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);1418lldb::addr_t key =1419m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);14201421if (!err.Success()) {1422m_index = -1;1423return;1424}14251426if (key != invalid_key)1427return;1428}1429}1430RemoteNXMapTable &m_parent;1431int m_index;1432};14331434const_iterator begin() {1435return const_iterator(*this, m_num_buckets_minus_one + 1);1436}14371438const_iterator end() { return m_end_iterator; }14391440uint32_t GetCount() const { return m_count; }14411442uint32_t GetBucketCount() const { return m_num_buckets_minus_one; }14431444lldb::addr_t GetBucketDataPointer() const { return m_buckets_ptr; }14451446lldb::addr_t GetTableLoadAddress() const { return m_load_addr; }14471448private:1449// contents of _NXMapTable struct1450uint32_t m_count = 0;1451uint32_t m_num_buckets_minus_one = 0;1452lldb::addr_t m_buckets_ptr = LLDB_INVALID_ADDRESS;1453lldb_private::Process *m_process = nullptr;1454const_iterator m_end_iterator;1455lldb::addr_t m_load_addr = LLDB_INVALID_ADDRESS;1456size_t m_map_pair_size = 0;1457lldb::addr_t m_invalid_key = 0;1458};14591460AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() = default;14611462void AppleObjCRuntimeV2::HashTableSignature::UpdateSignature(1463const RemoteNXMapTable &hash_table) {1464m_count = hash_table.GetCount();1465m_num_buckets = hash_table.GetBucketCount();1466m_buckets_ptr = hash_table.GetBucketDataPointer();1467}14681469bool AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate(1470Process *process, AppleObjCRuntimeV2 *runtime,1471RemoteNXMapTable &hash_table) {1472if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer())) {1473return false; // Failed to parse the header, no need to update anything1474}14751476// Check with out current signature and return true if the count, number of1477// buckets or the hash table address changes.1478if (m_count == hash_table.GetCount() &&1479m_num_buckets == hash_table.GetBucketCount() &&1480m_buckets_ptr == hash_table.GetBucketDataPointer()) {1481// Hash table hasn't changed1482return false;1483}1484// Hash table data has changed, we need to update1485return true;1486}14871488ObjCLanguageRuntime::ClassDescriptorSP1489AppleObjCRuntimeV2::GetClassDescriptorFromISA(ObjCISA isa) {1490ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;1491if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())1492class_descriptor_sp = non_pointer_isa_cache->GetClassDescriptor(isa);1493if (!class_descriptor_sp)1494class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);1495return class_descriptor_sp;1496}14971498ObjCLanguageRuntime::ClassDescriptorSP1499AppleObjCRuntimeV2::GetClassDescriptor(ValueObject &valobj) {1500ClassDescriptorSP objc_class_sp;1501if (valobj.IsBaseClass()) {1502ValueObject *parent = valobj.GetParent();1503// if I am my own parent, bail out of here fast..1504if (parent && parent != &valobj) {1505ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);1506if (parent_descriptor_sp)1507return parent_descriptor_sp->GetSuperclass();1508}1509return nullptr;1510}1511// if we get an invalid VO (which might still happen when playing around with1512// pointers returned by the expression parser, don't consider this a valid1513// ObjC object)1514if (!valobj.GetCompilerType().IsValid())1515return objc_class_sp;1516addr_t isa_pointer = valobj.GetPointerValue();15171518// tagged pointer1519if (IsTaggedPointer(isa_pointer))1520return m_tagged_pointer_vendor_up->GetClassDescriptor(isa_pointer);1521ExecutionContext exe_ctx(valobj.GetExecutionContextRef());15221523Process *process = exe_ctx.GetProcessPtr();1524if (!process)1525return objc_class_sp;15261527Status error;1528ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);1529if (isa == LLDB_INVALID_ADDRESS)1530return objc_class_sp;15311532objc_class_sp = GetClassDescriptorFromISA(isa);1533if (!objc_class_sp) {1534if (ABISP abi_sp = process->GetABI())1535isa = abi_sp->FixCodeAddress(isa);1536objc_class_sp = GetClassDescriptorFromISA(isa);1537}15381539if (isa && !objc_class_sp) {1540Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1541LLDB_LOGF(log,1542"0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was "1543"not in class descriptor cache 0x%" PRIx64,1544isa_pointer, isa);1545}1546return objc_class_sp;1547}15481549lldb::addr_t AppleObjCRuntimeV2::GetTaggedPointerObfuscator() {1550if (m_tagged_pointer_obfuscator != LLDB_INVALID_ADDRESS)1551return m_tagged_pointer_obfuscator;15521553Process *process = GetProcess();1554ModuleSP objc_module_sp(GetObjCModule());15551556if (!objc_module_sp)1557return LLDB_INVALID_ADDRESS;15581559static ConstString g_gdb_objc_obfuscator(1560"objc_debug_taggedpointer_obfuscator");15611562const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1563g_gdb_objc_obfuscator, lldb::eSymbolTypeAny);1564if (symbol) {1565lldb::addr_t g_gdb_obj_obfuscator_ptr =1566symbol->GetLoadAddress(&process->GetTarget());15671568if (g_gdb_obj_obfuscator_ptr != LLDB_INVALID_ADDRESS) {1569Status error;1570m_tagged_pointer_obfuscator =1571process->ReadPointerFromMemory(g_gdb_obj_obfuscator_ptr, error);1572}1573}1574// If we don't have a correct value at this point, there must be no1575// obfuscation.1576if (m_tagged_pointer_obfuscator == LLDB_INVALID_ADDRESS)1577m_tagged_pointer_obfuscator = 0;15781579return m_tagged_pointer_obfuscator;1580}15811582lldb::addr_t AppleObjCRuntimeV2::GetISAHashTablePointer() {1583if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {1584Process *process = GetProcess();15851586ModuleSP objc_module_sp(GetObjCModule());15871588if (!objc_module_sp)1589return LLDB_INVALID_ADDRESS;15901591static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");15921593const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1594g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);1595if (symbol) {1596lldb::addr_t gdb_objc_realized_classes_ptr =1597symbol->GetLoadAddress(&process->GetTarget());15981599if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS) {1600Status error;1601m_isa_hash_table_ptr = process->ReadPointerFromMemory(1602gdb_objc_realized_classes_ptr, error);1603}1604}1605}1606return m_isa_hash_table_ptr;1607}16081609std::unique_ptr<AppleObjCRuntimeV2::SharedCacheImageHeaders>1610AppleObjCRuntimeV2::SharedCacheImageHeaders::CreateSharedCacheImageHeaders(1611AppleObjCRuntimeV2 &runtime) {1612Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1613Process *process = runtime.GetProcess();1614ModuleSP objc_module_sp(runtime.GetObjCModule());1615if (!objc_module_sp || !process)1616return nullptr;16171618const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(1619ConstString("objc_debug_headerInfoRWs"), lldb::eSymbolTypeAny);1620if (!symbol) {1621LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' unavailable. Some "1622"information concerning the shared cache may be unavailable");1623return nullptr;1624}16251626lldb::addr_t objc_debug_headerInfoRWs_addr =1627symbol->GetLoadAddress(&process->GetTarget());1628if (objc_debug_headerInfoRWs_addr == LLDB_INVALID_ADDRESS) {1629LLDB_LOG(log, "Symbol 'objc_debug_headerInfoRWs' was found but we were "1630"unable to get its load address");1631return nullptr;1632}16331634Status error;1635lldb::addr_t objc_debug_headerInfoRWs_ptr =1636process->ReadPointerFromMemory(objc_debug_headerInfoRWs_addr, error);1637if (error.Fail()) {1638LLDB_LOG(log,1639"Failed to read address of 'objc_debug_headerInfoRWs' at {0:x}",1640objc_debug_headerInfoRWs_addr);1641return nullptr;1642}16431644const size_t metadata_size =1645sizeof(uint32_t) + sizeof(uint32_t); // count + entsize1646DataBufferHeap metadata_buffer(metadata_size, '\0');1647process->ReadMemory(objc_debug_headerInfoRWs_ptr, metadata_buffer.GetBytes(),1648metadata_size, error);1649if (error.Fail()) {1650LLDB_LOG(log,1651"Unable to read metadata for 'objc_debug_headerInfoRWs' at {0:x}",1652objc_debug_headerInfoRWs_ptr);1653return nullptr;1654}16551656DataExtractor metadata_extractor(metadata_buffer.GetBytes(), metadata_size,1657process->GetByteOrder(),1658process->GetAddressByteSize());1659lldb::offset_t cursor = 0;1660uint32_t count = metadata_extractor.GetU32_unchecked(&cursor);1661uint32_t entsize = metadata_extractor.GetU32_unchecked(&cursor);1662if (count == 0 || entsize == 0) {1663LLDB_LOG(log,1664"'objc_debug_headerInfoRWs' had count {0} with entsize {1}. These "1665"should both be non-zero.",1666count, entsize);1667return nullptr;1668}16691670std::unique_ptr<SharedCacheImageHeaders> shared_cache_image_headers(1671new SharedCacheImageHeaders(runtime, objc_debug_headerInfoRWs_ptr, count,1672entsize));1673if (auto Err = shared_cache_image_headers->UpdateIfNeeded()) {1674LLDB_LOG_ERROR(log, std::move(Err),1675"Failed to update SharedCacheImageHeaders: {0}");1676return nullptr;1677}16781679return shared_cache_image_headers;1680}16811682llvm::Error AppleObjCRuntimeV2::SharedCacheImageHeaders::UpdateIfNeeded() {1683if (!m_needs_update)1684return llvm::Error::success();16851686Process *process = m_runtime.GetProcess();1687constexpr lldb::addr_t metadata_size =1688sizeof(uint32_t) + sizeof(uint32_t); // count + entsize16891690Status error;1691const lldb::addr_t first_header_addr = m_headerInfoRWs_ptr + metadata_size;1692DataBufferHeap header_buffer(m_entsize, '\0');1693lldb::offset_t cursor = 0;1694for (uint32_t i = 0; i < m_count; i++) {1695const lldb::addr_t header_addr = first_header_addr + (i * m_entsize);1696process->ReadMemory(header_addr, header_buffer.GetBytes(), m_entsize,1697error);1698if (error.Fail())1699return llvm::createStringError(llvm::inconvertibleErrorCode(),1700"Failed to read memory from inferior when "1701"populating SharedCacheImageHeaders");17021703DataExtractor header_extractor(header_buffer.GetBytes(), m_entsize,1704process->GetByteOrder(),1705process->GetAddressByteSize());1706cursor = 0;1707bool is_loaded = false;1708if (m_entsize == 4) {1709uint32_t header = header_extractor.GetU32_unchecked(&cursor);1710if (header & 1)1711is_loaded = true;1712} else {1713uint64_t header = header_extractor.GetU64_unchecked(&cursor);1714if (header & 1)1715is_loaded = true;1716}17171718if (is_loaded)1719m_loaded_images.set(i);1720else1721m_loaded_images.reset(i);1722}1723m_needs_update = false;1724m_version++;1725return llvm::Error::success();1726}17271728bool AppleObjCRuntimeV2::SharedCacheImageHeaders::IsImageLoaded(1729uint16_t image_index) {1730if (image_index >= m_count)1731return false;1732if (auto Err = UpdateIfNeeded()) {1733Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1734LLDB_LOG_ERROR(log, std::move(Err),1735"Failed to update SharedCacheImageHeaders: {0}");1736}1737return m_loaded_images.test(image_index);1738}17391740uint64_t AppleObjCRuntimeV2::SharedCacheImageHeaders::GetVersion() {1741if (auto Err = UpdateIfNeeded()) {1742Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);1743LLDB_LOG_ERROR(log, std::move(Err),1744"Failed to update SharedCacheImageHeaders: {0}");1745}1746return m_version;1747}17481749std::unique_ptr<UtilityFunction>1750AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunctionImpl(1751ExecutionContext &exe_ctx, Helper helper, std::string code,1752std::string name) {1753Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);17541755LLDB_LOG(log, "Creating utility function {0}", name);17561757TypeSystemClangSP scratch_ts_sp =1758ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());1759if (!scratch_ts_sp)1760return {};17611762auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(1763std::move(code), std::move(name), eLanguageTypeC, exe_ctx);1764if (!utility_fn_or_error) {1765LLDB_LOG_ERROR(1766log, utility_fn_or_error.takeError(),1767"Failed to get utility function for dynamic info extractor: {0}");1768return {};1769}17701771// Make some types for our arguments.1772CompilerType clang_uint32_t_type =1773scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);1774CompilerType clang_void_pointer_type =1775scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();17761777// Make the runner function for our implementation utility function.1778ValueList arguments;1779Value value;1780value.SetValueType(Value::ValueType::Scalar);1781value.SetCompilerType(clang_void_pointer_type);1782arguments.PushValue(value);1783arguments.PushValue(value);1784value.SetValueType(Value::ValueType::Scalar);1785value.SetCompilerType(clang_uint32_t_type);1786arguments.PushValue(value);17871788// objc_getRealizedClassList_trylock takes an additional buffer and length.1789if (helper == Helper::objc_getRealizedClassList_trylock) {1790value.SetCompilerType(clang_void_pointer_type);1791arguments.PushValue(value);1792value.SetCompilerType(clang_uint32_t_type);1793arguments.PushValue(value);1794}17951796arguments.PushValue(value);17971798std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);17991800Status error;1801utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,1802exe_ctx.GetThreadSP(), error);18031804if (error.Fail()) {1805LLDB_LOG(log,1806"Failed to make function caller for implementation lookup: {0}.",1807error.AsCString());1808return {};1809}18101811return utility_fn;1812}18131814UtilityFunction *1815AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoUtilityFunction(1816ExecutionContext &exe_ctx, Helper helper) {1817switch (helper) {1818case gdb_objc_realized_classes: {1819if (!m_gdb_objc_realized_classes_helper.utility_function)1820m_gdb_objc_realized_classes_helper.utility_function =1821GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1822g_get_dynamic_class_info_body,1823g_get_dynamic_class_info_name);1824return m_gdb_objc_realized_classes_helper.utility_function.get();1825}1826case objc_copyRealizedClassList: {1827if (!m_objc_copyRealizedClassList_helper.utility_function)1828m_objc_copyRealizedClassList_helper.utility_function =1829GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1830g_get_dynamic_class_info2_body,1831g_get_dynamic_class_info2_name);1832return m_objc_copyRealizedClassList_helper.utility_function.get();1833}1834case objc_getRealizedClassList_trylock: {1835if (!m_objc_getRealizedClassList_trylock_helper.utility_function)1836m_objc_getRealizedClassList_trylock_helper.utility_function =1837GetClassInfoUtilityFunctionImpl(exe_ctx, helper,1838g_get_dynamic_class_info3_body,1839g_get_dynamic_class_info3_name);1840return m_objc_getRealizedClassList_trylock_helper.utility_function.get();1841}1842}1843llvm_unreachable("Unexpected helper");1844}18451846lldb::addr_t &1847AppleObjCRuntimeV2::DynamicClassInfoExtractor::GetClassInfoArgs(Helper helper) {1848switch (helper) {1849case gdb_objc_realized_classes:1850return m_gdb_objc_realized_classes_helper.args;1851case objc_copyRealizedClassList:1852return m_objc_copyRealizedClassList_helper.args;1853case objc_getRealizedClassList_trylock:1854return m_objc_getRealizedClassList_trylock_helper.args;1855}1856llvm_unreachable("Unexpected helper");1857}18581859AppleObjCRuntimeV2::DynamicClassInfoExtractor::Helper1860AppleObjCRuntimeV2::DynamicClassInfoExtractor::ComputeHelper(1861ExecutionContext &exe_ctx) const {1862if (!m_runtime.m_has_objc_copyRealizedClassList &&1863!m_runtime.m_has_objc_getRealizedClassList_trylock)1864return DynamicClassInfoExtractor::gdb_objc_realized_classes;18651866if (Process *process = m_runtime.GetProcess()) {1867if (DynamicLoader *loader = process->GetDynamicLoader()) {1868if (loader->IsFullyInitialized()) {1869switch (exe_ctx.GetTargetRef().GetDynamicClassInfoHelper()) {1870case eDynamicClassInfoHelperAuto:1871[[fallthrough]];1872case eDynamicClassInfoHelperGetRealizedClassList:1873if (m_runtime.m_has_objc_getRealizedClassList_trylock)1874return DynamicClassInfoExtractor::objc_getRealizedClassList_trylock;1875[[fallthrough]];1876case eDynamicClassInfoHelperCopyRealizedClassList:1877if (m_runtime.m_has_objc_copyRealizedClassList)1878return DynamicClassInfoExtractor::objc_copyRealizedClassList;1879[[fallthrough]];1880case eDynamicClassInfoHelperRealizedClassesStruct:1881return DynamicClassInfoExtractor::gdb_objc_realized_classes;1882}1883}1884}1885}18861887return DynamicClassInfoExtractor::gdb_objc_realized_classes;1888}18891890std::unique_ptr<UtilityFunction>1891AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::1892GetClassInfoUtilityFunctionImpl(ExecutionContext &exe_ctx) {1893Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);18941895LLDB_LOG(log, "Creating utility function {0}",1896g_get_shared_cache_class_info_name);18971898TypeSystemClangSP scratch_ts_sp =1899ScratchTypeSystemClang::GetForTarget(exe_ctx.GetTargetRef());1900if (!scratch_ts_sp)1901return {};19021903// If the inferior objc.dylib has the class_getNameRaw function, use that in1904// our jitted expression. Else fall back to the old class_getName.1905static ConstString g_class_getName_symbol_name("class_getName");1906static ConstString g_class_getNameRaw_symbol_name(1907"objc_debug_class_getNameRaw");19081909ConstString class_name_getter_function_name =1910m_runtime.HasSymbol(g_class_getNameRaw_symbol_name)1911? g_class_getNameRaw_symbol_name1912: g_class_getName_symbol_name;19131914// Substitute in the correct class_getName / class_getNameRaw function name,1915// concatenate the two parts of our expression text. The format string has1916// two %s's, so provide the name twice.1917std::string shared_class_expression;1918llvm::raw_string_ostream(shared_class_expression)1919<< llvm::format(g_shared_cache_class_name_funcptr,1920class_name_getter_function_name.AsCString(),1921class_name_getter_function_name.AsCString());19221923shared_class_expression += g_get_shared_cache_class_info_body;19241925auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction(1926std::move(shared_class_expression), g_get_shared_cache_class_info_name,1927eLanguageTypeC, exe_ctx);19281929if (!utility_fn_or_error) {1930LLDB_LOG_ERROR(1931log, utility_fn_or_error.takeError(),1932"Failed to get utility function for shared class info extractor: {0}");1933return nullptr;1934}19351936// Make some types for our arguments.1937CompilerType clang_uint32_t_type =1938scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);1939CompilerType clang_void_pointer_type =1940scratch_ts_sp->GetBasicType(eBasicTypeVoid).GetPointerType();1941CompilerType clang_uint64_t_pointer_type =1942scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 64)1943.GetPointerType();19441945// Next make the function caller for our implementation utility function.1946ValueList arguments;1947Value value;1948value.SetValueType(Value::ValueType::Scalar);1949value.SetCompilerType(clang_void_pointer_type);1950arguments.PushValue(value);1951arguments.PushValue(value);1952arguments.PushValue(value);19531954value.SetValueType(Value::ValueType::Scalar);1955value.SetCompilerType(clang_uint64_t_pointer_type);1956arguments.PushValue(value);19571958value.SetValueType(Value::ValueType::Scalar);1959value.SetCompilerType(clang_uint32_t_type);1960arguments.PushValue(value);1961arguments.PushValue(value);19621963std::unique_ptr<UtilityFunction> utility_fn = std::move(*utility_fn_or_error);19641965Status error;1966utility_fn->MakeFunctionCaller(clang_uint32_t_type, arguments,1967exe_ctx.GetThreadSP(), error);19681969if (error.Fail()) {1970LLDB_LOG(log,1971"Failed to make function caller for implementation lookup: {0}.",1972error.AsCString());1973return {};1974}19751976return utility_fn;1977}19781979UtilityFunction *1980AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::GetClassInfoUtilityFunction(1981ExecutionContext &exe_ctx) {1982if (!m_utility_function)1983m_utility_function = GetClassInfoUtilityFunctionImpl(exe_ctx);1984return m_utility_function.get();1985}19861987AppleObjCRuntimeV2::DescriptorMapUpdateResult1988AppleObjCRuntimeV2::DynamicClassInfoExtractor::UpdateISAToDescriptorMap(1989RemoteNXMapTable &hash_table) {1990Process *process = m_runtime.GetProcess();1991if (process == nullptr)1992return DescriptorMapUpdateResult::Fail();19931994uint32_t num_class_infos = 0;19951996Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);19971998ExecutionContext exe_ctx;19992000ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();20012002if (!thread_sp)2003return DescriptorMapUpdateResult::Fail();20042005if (!thread_sp->SafeToCallFunctions())2006return DescriptorMapUpdateResult::Retry();20072008thread_sp->CalculateExecutionContext(exe_ctx);2009TypeSystemClangSP scratch_ts_sp =2010ScratchTypeSystemClang::GetForTarget(process->GetTarget());20112012if (!scratch_ts_sp)2013return DescriptorMapUpdateResult::Fail();20142015Address function_address;20162017const uint32_t addr_size = process->GetAddressByteSize();20182019Status err;20202021// Compute which helper we're going to use for this update.2022const DynamicClassInfoExtractor::Helper helper = ComputeHelper(exe_ctx);20232024// Read the total number of classes from the hash table2025const uint32_t num_classes =2026helper == DynamicClassInfoExtractor::gdb_objc_realized_classes2027? hash_table.GetCount()2028: m_runtime.m_realized_class_generation_count;2029if (num_classes == 0) {2030LLDB_LOGF(log, "No dynamic classes found.");2031return DescriptorMapUpdateResult::Success(0);2032}20332034UtilityFunction *get_class_info_code =2035GetClassInfoUtilityFunction(exe_ctx, helper);2036if (!get_class_info_code) {2037// The callee will have already logged a useful error message.2038return DescriptorMapUpdateResult::Fail();2039}20402041FunctionCaller *get_class_info_function =2042get_class_info_code->GetFunctionCaller();20432044if (!get_class_info_function) {2045LLDB_LOGF(log, "Failed to get implementation lookup function caller.");2046return DescriptorMapUpdateResult::Fail();2047}20482049ValueList arguments = get_class_info_function->GetArgumentValues();20502051DiagnosticManager diagnostics;20522053const uint32_t class_info_byte_size = addr_size + 4;2054const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;2055lldb::addr_t class_infos_addr = process->AllocateMemory(2056class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);20572058if (class_infos_addr == LLDB_INVALID_ADDRESS) {2059LLDB_LOGF(log,2060"unable to allocate %" PRIu322061" bytes in process for shared cache read",2062class_infos_byte_size);2063return DescriptorMapUpdateResult::Fail();2064}20652066auto deallocate_class_infos = llvm::make_scope_exit([&] {2067// Deallocate the memory we allocated for the ClassInfo array2068if (class_infos_addr != LLDB_INVALID_ADDRESS)2069process->DeallocateMemory(class_infos_addr);2070});20712072lldb::addr_t class_buffer_addr = LLDB_INVALID_ADDRESS;2073const uint32_t class_byte_size = addr_size;2074const uint32_t class_buffer_len = num_classes;2075const uint32_t class_buffer_byte_size = class_buffer_len * class_byte_size;2076if (helper == Helper::objc_getRealizedClassList_trylock) {2077class_buffer_addr = process->AllocateMemory(2078class_buffer_byte_size, ePermissionsReadable | ePermissionsWritable,2079err);2080if (class_buffer_addr == LLDB_INVALID_ADDRESS) {2081LLDB_LOGF(log,2082"unable to allocate %" PRIu322083" bytes in process for shared cache read",2084class_buffer_byte_size);2085return DescriptorMapUpdateResult::Fail();2086}2087}20882089auto deallocate_class_buffer = llvm::make_scope_exit([&] {2090// Deallocate the memory we allocated for the Class array2091if (class_buffer_addr != LLDB_INVALID_ADDRESS)2092process->DeallocateMemory(class_buffer_addr);2093});20942095std::lock_guard<std::mutex> guard(m_mutex);20962097// Fill in our function argument values2098uint32_t index = 0;2099arguments.GetValueAtIndex(index++)->GetScalar() =2100hash_table.GetTableLoadAddress();2101arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_addr;2102arguments.GetValueAtIndex(index++)->GetScalar() = class_infos_byte_size;21032104if (class_buffer_addr != LLDB_INVALID_ADDRESS) {2105arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_addr;2106arguments.GetValueAtIndex(index++)->GetScalar() = class_buffer_byte_size;2107}21082109// Only dump the runtime classes from the expression evaluation if the log is2110// verbose:2111Log *type_log = GetLog(LLDBLog::Types);2112bool dump_log = type_log && type_log->GetVerbose();21132114arguments.GetValueAtIndex(index++)->GetScalar() = dump_log ? 1 : 0;21152116bool success = false;21172118diagnostics.Clear();21192120// Write our function arguments into the process so we can run our function2121if (get_class_info_function->WriteFunctionArguments(2122exe_ctx, GetClassInfoArgs(helper), arguments, diagnostics)) {2123EvaluateExpressionOptions options;2124options.SetUnwindOnError(true);2125options.SetTryAllThreads(false);2126options.SetStopOthers(true);2127options.SetIgnoreBreakpoints(true);2128options.SetTimeout(process->GetUtilityExpressionTimeout());2129options.SetIsForUtilityExpr(true);21302131CompilerType clang_uint32_t_type =2132scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);21332134Value return_value;2135return_value.SetValueType(Value::ValueType::Scalar);2136return_value.SetCompilerType(clang_uint32_t_type);2137return_value.GetScalar() = 0;21382139diagnostics.Clear();21402141// Run the function2142ExpressionResults results = get_class_info_function->ExecuteFunction(2143exe_ctx, &GetClassInfoArgs(helper), options, diagnostics, return_value);21442145if (results == eExpressionCompleted) {2146// The result is the number of ClassInfo structures that were filled in2147num_class_infos = return_value.GetScalar().ULong();2148LLDB_LOG(log, "Discovered {0} Objective-C classes", num_class_infos);2149if (num_class_infos > 0) {2150// Read the ClassInfo structures2151DataBufferHeap buffer(num_class_infos * class_info_byte_size, 0);2152if (process->ReadMemory(class_infos_addr, buffer.GetBytes(),2153buffer.GetByteSize(),2154err) == buffer.GetByteSize()) {2155DataExtractor class_infos_data(buffer.GetBytes(),2156buffer.GetByteSize(),2157process->GetByteOrder(), addr_size);2158m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);2159}2160}2161success = true;2162} else {2163if (log) {2164LLDB_LOGF(log, "Error evaluating our find class name function.");2165diagnostics.Dump(log);2166}2167}2168} else {2169if (log) {2170LLDB_LOGF(log, "Error writing function arguments.");2171diagnostics.Dump(log);2172}2173}21742175return DescriptorMapUpdateResult(success, false, num_class_infos);2176}21772178uint32_t AppleObjCRuntimeV2::ParseClassInfoArray(const DataExtractor &data,2179uint32_t num_class_infos) {2180// Parses an array of "num_class_infos" packed ClassInfo structures:2181//2182// struct ClassInfo2183// {2184// Class isa;2185// uint32_t hash;2186// } __attribute__((__packed__));21872188Log *log = GetLog(LLDBLog::Types);2189bool should_log = log && log->GetVerbose();21902191uint32_t num_parsed = 0;21922193// Iterate through all ClassInfo structures2194lldb::offset_t offset = 0;2195for (uint32_t i = 0; i < num_class_infos; ++i) {2196ObjCISA isa = data.GetAddress(&offset);21972198if (isa == 0) {2199if (should_log)2200LLDB_LOGF(2201log, "AppleObjCRuntimeV2 found NULL isa, ignoring this class info");2202continue;2203}2204// Check if we already know about this ISA, if we do, the info will never2205// change, so we can just skip it.2206if (ISAIsCached(isa)) {2207if (should_log)2208LLDB_LOGF(log,2209"AppleObjCRuntimeV2 found cached isa=0x%" PRIx642210", ignoring this class info",2211isa);2212offset += 4;2213} else {2214// Read the 32 bit hash for the class name2215const uint32_t name_hash = data.GetU32(&offset);2216ClassDescriptorSP descriptor_sp(2217new ClassDescriptorV2(*this, isa, nullptr));22182219// The code in g_get_shared_cache_class_info_body sets the value of the2220// hash to 0 to signal a demangled symbol. We use class_getName() in that2221// code to find the class name, but this returns a demangled name for2222// Swift symbols. For those symbols, recompute the hash here by reading2223// their name from the runtime.2224if (name_hash)2225AddClass(isa, descriptor_sp, name_hash);2226else2227AddClass(isa, descriptor_sp,2228descriptor_sp->GetClassName().AsCString(nullptr));2229num_parsed++;2230if (should_log)2231LLDB_LOGF(log,2232"AppleObjCRuntimeV2 added isa=0x%" PRIx642233", hash=0x%8.8x, name=%s",2234isa, name_hash,2235descriptor_sp->GetClassName().AsCString("<unknown>"));2236}2237}2238if (should_log)2239LLDB_LOGF(log, "AppleObjCRuntimeV2 parsed %" PRIu32 " class infos",2240num_parsed);2241return num_parsed;2242}22432244bool AppleObjCRuntimeV2::HasSymbol(ConstString Name) {2245if (!m_objc_module_sp)2246return false;2247if (const Symbol *symbol = m_objc_module_sp->FindFirstSymbolWithNameAndType(2248Name, lldb::eSymbolTypeCode)) {2249if (symbol->ValueIsAddress() || symbol->GetAddressRef().IsValid())2250return true;2251}2252return false;2253}22542255AppleObjCRuntimeV2::DescriptorMapUpdateResult2256AppleObjCRuntimeV2::SharedCacheClassInfoExtractor::UpdateISAToDescriptorMap() {2257Process *process = m_runtime.GetProcess();2258if (process == nullptr)2259return DescriptorMapUpdateResult::Fail();22602261Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);22622263ExecutionContext exe_ctx;22642265ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();22662267if (!thread_sp)2268return DescriptorMapUpdateResult::Fail();22692270if (!thread_sp->SafeToCallFunctions())2271return DescriptorMapUpdateResult::Retry();22722273thread_sp->CalculateExecutionContext(exe_ctx);2274TypeSystemClangSP scratch_ts_sp =2275ScratchTypeSystemClang::GetForTarget(process->GetTarget());22762277if (!scratch_ts_sp)2278return DescriptorMapUpdateResult::Fail();22792280Address function_address;22812282const uint32_t addr_size = process->GetAddressByteSize();22832284Status err;22852286uint32_t num_class_infos = 0;22872288const lldb::addr_t objc_opt_ptr = m_runtime.GetSharedCacheReadOnlyAddress();2289const lldb::addr_t shared_cache_base_addr =2290m_runtime.GetSharedCacheBaseAddress();22912292if (objc_opt_ptr == LLDB_INVALID_ADDRESS ||2293shared_cache_base_addr == LLDB_INVALID_ADDRESS)2294return DescriptorMapUpdateResult::Fail();22952296// The number of entries to pre-allocate room for.2297// Each entry is (addrsize + 4) bytes2298// FIXME: It is not sustainable to continue incrementing this value every time2299// the shared cache grows. This is because it requires allocating memory in2300// the inferior process and some inferior processes have small memory limits.2301const uint32_t max_num_classes = 212992;23022303UtilityFunction *get_class_info_code = GetClassInfoUtilityFunction(exe_ctx);2304if (!get_class_info_code) {2305// The callee will have already logged a useful error message.2306return DescriptorMapUpdateResult::Fail();2307}23082309FunctionCaller *get_shared_cache_class_info_function =2310get_class_info_code->GetFunctionCaller();23112312if (!get_shared_cache_class_info_function) {2313LLDB_LOGF(log, "Failed to get implementation lookup function caller.");2314return DescriptorMapUpdateResult::Fail();2315}23162317ValueList arguments =2318get_shared_cache_class_info_function->GetArgumentValues();23192320DiagnosticManager diagnostics;23212322const uint32_t class_info_byte_size = addr_size + 4;2323const uint32_t class_infos_byte_size = max_num_classes * class_info_byte_size;2324lldb::addr_t class_infos_addr = process->AllocateMemory(2325class_infos_byte_size, ePermissionsReadable | ePermissionsWritable, err);2326const uint32_t relative_selector_offset_addr_size = 64;2327lldb::addr_t relative_selector_offset_addr =2328process->AllocateMemory(relative_selector_offset_addr_size,2329ePermissionsReadable | ePermissionsWritable, err);23302331if (class_infos_addr == LLDB_INVALID_ADDRESS) {2332LLDB_LOGF(log,2333"unable to allocate %" PRIu322334" bytes in process for shared cache read",2335class_infos_byte_size);2336return DescriptorMapUpdateResult::Fail();2337}23382339std::lock_guard<std::mutex> guard(m_mutex);23402341// Fill in our function argument values2342arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;2343arguments.GetValueAtIndex(1)->GetScalar() = shared_cache_base_addr;2344arguments.GetValueAtIndex(2)->GetScalar() = class_infos_addr;2345arguments.GetValueAtIndex(3)->GetScalar() = relative_selector_offset_addr;2346arguments.GetValueAtIndex(4)->GetScalar() = class_infos_byte_size;2347// Only dump the runtime classes from the expression evaluation if the log is2348// verbose:2349Log *type_log = GetLog(LLDBLog::Types);2350bool dump_log = type_log && type_log->GetVerbose();23512352arguments.GetValueAtIndex(5)->GetScalar() = dump_log ? 1 : 0;23532354bool success = false;23552356diagnostics.Clear();23572358// Write our function arguments into the process so we can run our function2359if (get_shared_cache_class_info_function->WriteFunctionArguments(2360exe_ctx, m_args, arguments, diagnostics)) {2361EvaluateExpressionOptions options;2362options.SetUnwindOnError(true);2363options.SetTryAllThreads(false);2364options.SetStopOthers(true);2365options.SetIgnoreBreakpoints(true);2366options.SetTimeout(process->GetUtilityExpressionTimeout());2367options.SetIsForUtilityExpr(true);23682369CompilerType clang_uint32_t_type =2370scratch_ts_sp->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);23712372Value return_value;2373return_value.SetValueType(Value::ValueType::Scalar);2374return_value.SetCompilerType(clang_uint32_t_type);2375return_value.GetScalar() = 0;23762377diagnostics.Clear();23782379// Run the function2380ExpressionResults results =2381get_shared_cache_class_info_function->ExecuteFunction(2382exe_ctx, &m_args, options, diagnostics, return_value);23832384if (results == eExpressionCompleted) {2385// The result is the number of ClassInfo structures that were filled in2386num_class_infos = return_value.GetScalar().ULong();2387LLDB_LOG(log, "Discovered {0} Objective-C classes in the shared cache",2388num_class_infos);2389// Assert if there were more classes than we pre-allocated2390// room for.2391assert(num_class_infos <= max_num_classes);2392if (num_class_infos > 0) {2393if (num_class_infos > max_num_classes) {2394num_class_infos = max_num_classes;23952396success = false;2397} else {2398success = true;2399}24002401// Read the relative selector offset.2402DataBufferHeap relative_selector_offset_buffer(64, 0);2403if (process->ReadMemory(relative_selector_offset_addr,2404relative_selector_offset_buffer.GetBytes(),2405relative_selector_offset_buffer.GetByteSize(),2406err) ==2407relative_selector_offset_buffer.GetByteSize()) {2408DataExtractor relative_selector_offset_data(2409relative_selector_offset_buffer.GetBytes(),2410relative_selector_offset_buffer.GetByteSize(),2411process->GetByteOrder(), addr_size);2412lldb::offset_t offset = 0;2413uint64_t relative_selector_offset =2414relative_selector_offset_data.GetU64(&offset);2415if (relative_selector_offset > 0) {2416// The offset is relative to the objc_opt struct.2417m_runtime.SetRelativeSelectorBaseAddr(objc_opt_ptr +2418relative_selector_offset);2419}2420}24212422// Read the ClassInfo structures2423DataBufferHeap class_infos_buffer(2424num_class_infos * class_info_byte_size, 0);2425if (process->ReadMemory(class_infos_addr, class_infos_buffer.GetBytes(),2426class_infos_buffer.GetByteSize(),2427err) == class_infos_buffer.GetByteSize()) {2428DataExtractor class_infos_data(class_infos_buffer.GetBytes(),2429class_infos_buffer.GetByteSize(),2430process->GetByteOrder(), addr_size);24312432m_runtime.ParseClassInfoArray(class_infos_data, num_class_infos);2433}2434} else {2435success = true;2436}2437} else {2438if (log) {2439LLDB_LOGF(log, "Error evaluating our find class name function.");2440diagnostics.Dump(log);2441}2442}2443} else {2444if (log) {2445LLDB_LOGF(log, "Error writing function arguments.");2446diagnostics.Dump(log);2447}2448}24492450// Deallocate the memory we allocated for the ClassInfo array2451process->DeallocateMemory(class_infos_addr);24522453return DescriptorMapUpdateResult(success, false, num_class_infos);2454}24552456lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress() {2457Process *process = GetProcess();24582459if (process) {2460ModuleSP objc_module_sp(GetObjCModule());24612462if (objc_module_sp) {2463ObjectFile *objc_object = objc_module_sp->GetObjectFile();24642465if (objc_object) {2466SectionList *section_list = objc_module_sp->GetSectionList();24672468if (section_list) {2469SectionSP text_segment_sp(2470section_list->FindSectionByName(ConstString("__TEXT")));24712472if (text_segment_sp) {2473SectionSP objc_opt_section_sp(2474text_segment_sp->GetChildren().FindSectionByName(2475ConstString("__objc_opt_ro")));24762477if (objc_opt_section_sp) {2478return objc_opt_section_sp->GetLoadBaseAddress(2479&process->GetTarget());2480}2481}2482}2483}2484}2485}2486return LLDB_INVALID_ADDRESS;2487}24882489lldb::addr_t AppleObjCRuntimeV2::GetSharedCacheBaseAddress() {2490StructuredData::ObjectSP info = m_process->GetSharedCacheInfo();2491if (!info)2492return LLDB_INVALID_ADDRESS;24932494StructuredData::Dictionary *info_dict = info->GetAsDictionary();2495if (!info_dict)2496return LLDB_INVALID_ADDRESS;24972498StructuredData::ObjectSP value =2499info_dict->GetValueForKey("shared_cache_base_address");2500if (!value)2501return LLDB_INVALID_ADDRESS;25022503return value->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);2504}25052506void AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded() {2507LLDB_SCOPED_TIMER();25082509Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);25102511// Else we need to check with our process to see when the map was updated.2512Process *process = GetProcess();25132514if (process) {2515RemoteNXMapTable hash_table;25162517// Update the process stop ID that indicates the last time we updated the2518// map, whether it was successful or not.2519m_isa_to_descriptor_stop_id = process->GetStopID();25202521// Ask the runtime is the realized class generation count changed. Unlike2522// the hash table, this accounts for lazily named classes.2523const bool class_count_changed = RealizedClassGenerationCountChanged();25242525if (!m_hash_signature.NeedsUpdate(process, this, hash_table) &&2526!class_count_changed)2527return;25282529m_hash_signature.UpdateSignature(hash_table);25302531// Grab the dynamically loaded Objective-C classes from memory.2532DescriptorMapUpdateResult dynamic_update_result =2533m_dynamic_class_info_extractor.UpdateISAToDescriptorMap(hash_table);25342535// Now get the objc classes that are baked into the Objective-C runtime in2536// the shared cache, but only once per process as this data never changes2537if (!m_loaded_objc_opt) {2538// it is legitimately possible for the shared cache to be empty - in that2539// case, the dynamic hash table will contain all the class information we2540// need; the situation we're trying to detect is one where we aren't2541// seeing class information from the runtime - in order to detect that2542// vs. just the shared cache being empty or sparsely populated, we set an2543// arbitrary (very low) threshold for the number of classes that we want2544// to see in a "good" scenario - anything below that is suspicious2545// (Foundation alone has thousands of classes)2546const uint32_t num_classes_to_warn_at = 500;25472548DescriptorMapUpdateResult shared_cache_update_result =2549m_shared_cache_class_info_extractor.UpdateISAToDescriptorMap();25502551LLDB_LOGF(log,2552"attempted to read objc class data - results: "2553"[dynamic_update]: ran: %s, retry: %s, count: %" PRIu322554" [shared_cache_update]: ran: %s, retry: %s, count: %" PRIu32,2555dynamic_update_result.m_update_ran ? "yes" : "no",2556dynamic_update_result.m_retry_update ? "yes" : "no",2557dynamic_update_result.m_num_found,2558shared_cache_update_result.m_update_ran ? "yes" : "no",2559shared_cache_update_result.m_retry_update ? "yes" : "no",2560shared_cache_update_result.m_num_found);25612562// warn if:2563// - we could not run either expression2564// - we found fewer than num_classes_to_warn_at classes total2565if (dynamic_update_result.m_retry_update ||2566shared_cache_update_result.m_retry_update)2567WarnIfNoClassesCached(SharedCacheWarningReason::eExpressionUnableToRun);2568else if ((!shared_cache_update_result.m_update_ran) ||2569(!dynamic_update_result.m_update_ran))2570WarnIfNoClassesCached(2571SharedCacheWarningReason::eExpressionExecutionFailure);2572else if (dynamic_update_result.m_num_found +2573shared_cache_update_result.m_num_found <2574num_classes_to_warn_at)2575WarnIfNoClassesCached(SharedCacheWarningReason::eNotEnoughClassesRead);2576else2577m_loaded_objc_opt = true;2578}2579} else {2580m_isa_to_descriptor_stop_id = UINT32_MAX;2581}2582}25832584bool AppleObjCRuntimeV2::RealizedClassGenerationCountChanged() {2585Process *process = GetProcess();2586if (!process)2587return false;25882589Status error;2590uint64_t objc_debug_realized_class_generation_count =2591ExtractRuntimeGlobalSymbol(2592process, ConstString("objc_debug_realized_class_generation_count"),2593GetObjCModule(), error);2594if (error.Fail())2595return false;25962597if (m_realized_class_generation_count ==2598objc_debug_realized_class_generation_count)2599return false;26002601Log *log = GetLog(LLDBLog::Process | LLDBLog::Types);2602LLDB_LOG(log,2603"objc_debug_realized_class_generation_count changed from {0} to {1}",2604m_realized_class_generation_count,2605objc_debug_realized_class_generation_count);26062607m_realized_class_generation_count =2608objc_debug_realized_class_generation_count;26092610return true;2611}26122613static bool DoesProcessHaveSharedCache(Process &process) {2614PlatformSP platform_sp = process.GetTarget().GetPlatform();2615if (!platform_sp)2616return true; // this should not happen26172618llvm::StringRef platform_plugin_name_sr = platform_sp->GetPluginName();2619if (platform_plugin_name_sr.ends_with("-simulator"))2620return false;26212622return true;2623}26242625void AppleObjCRuntimeV2::WarnIfNoClassesCached(2626SharedCacheWarningReason reason) {2627if (GetProcess() && !DoesProcessHaveSharedCache(*GetProcess())) {2628// Simulators do not have the objc_opt_ro class table so don't actually2629// complain to the user2630return;2631}26322633Debugger &debugger(GetProcess()->GetTarget().GetDebugger());2634switch (reason) {2635case SharedCacheWarningReason::eNotEnoughClassesRead:2636Debugger::ReportWarning("could not find Objective-C class data in "2637"the process. This may reduce the quality of type "2638"information available.\n",2639debugger.GetID(), &m_no_classes_cached_warning);2640break;2641case SharedCacheWarningReason::eExpressionExecutionFailure:2642Debugger::ReportWarning(2643"could not execute support code to read "2644"Objective-C class data in the process. This may "2645"reduce the quality of type information available.\n",2646debugger.GetID(), &m_no_classes_cached_warning);2647break;2648case SharedCacheWarningReason::eExpressionUnableToRun:2649Debugger::ReportWarning(2650"could not execute support code to read Objective-C class data because "2651"it's not yet safe to do so, and will be retried later.\n",2652debugger.GetID(), nullptr);2653break;2654}2655}26562657void AppleObjCRuntimeV2::WarnIfNoExpandedSharedCache() {2658if (!m_objc_module_sp)2659return;26602661ObjectFile *object_file = m_objc_module_sp->GetObjectFile();2662if (!object_file)2663return;26642665if (!object_file->IsInMemory())2666return;26672668Target &target = GetProcess()->GetTarget();2669Debugger &debugger = target.GetDebugger();26702671std::string buffer;2672llvm::raw_string_ostream os(buffer);26732674os << "libobjc.A.dylib is being read from process memory. This "2675"indicates that LLDB could not ";2676if (PlatformSP platform_sp = target.GetPlatform()) {2677if (platform_sp->IsHost()) {2678os << "read from the host's in-memory shared cache";2679} else {2680os << "find the on-disk shared cache for this device";2681}2682} else {2683os << "read from the shared cache";2684}2685os << ". This will likely reduce debugging performance.\n";26862687Debugger::ReportWarning(os.str(), debugger.GetID(),2688&m_no_expanded_cache_warning);2689}26902691DeclVendor *AppleObjCRuntimeV2::GetDeclVendor() {2692if (!m_decl_vendor_up)2693m_decl_vendor_up = std::make_unique<AppleObjCDeclVendor>(*this);26942695return m_decl_vendor_up.get();2696}26972698lldb::addr_t AppleObjCRuntimeV2::LookupRuntimeSymbol(ConstString name) {2699lldb::addr_t ret = LLDB_INVALID_ADDRESS;27002701const char *name_cstr = name.AsCString();27022703if (name_cstr) {2704llvm::StringRef name_strref(name_cstr);27052706llvm::StringRef ivar_prefix("OBJC_IVAR_$_");2707llvm::StringRef class_prefix("OBJC_CLASS_$_");27082709if (name_strref.starts_with(ivar_prefix)) {2710llvm::StringRef ivar_skipped_prefix =2711name_strref.substr(ivar_prefix.size());2712std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar =2713ivar_skipped_prefix.split('.');27142715if (!class_and_ivar.first.empty() && !class_and_ivar.second.empty()) {2716const ConstString class_name_cs(class_and_ivar.first);2717ClassDescriptorSP descriptor =2718ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);27192720if (descriptor) {2721const ConstString ivar_name_cs(class_and_ivar.second);2722const char *ivar_name_cstr = ivar_name_cs.AsCString();27232724auto ivar_func = [&ret,2725ivar_name_cstr](const char *name, const char *type,2726lldb::addr_t offset_addr,2727uint64_t size) -> lldb::addr_t {2728if (!strcmp(name, ivar_name_cstr)) {2729ret = offset_addr;2730return true;2731}2732return false;2733};27342735descriptor->Describe(2736std::function<void(ObjCISA)>(nullptr),2737std::function<bool(const char *, const char *)>(nullptr),2738std::function<bool(const char *, const char *)>(nullptr),2739ivar_func);2740}2741}2742} else if (name_strref.starts_with(class_prefix)) {2743llvm::StringRef class_skipped_prefix =2744name_strref.substr(class_prefix.size());2745const ConstString class_name_cs(class_skipped_prefix);2746ClassDescriptorSP descriptor =2747GetClassDescriptorFromClassName(class_name_cs);27482749if (descriptor)2750ret = descriptor->GetISA();2751}2752}27532754return ret;2755}27562757AppleObjCRuntimeV2::NonPointerISACache *2758AppleObjCRuntimeV2::NonPointerISACache::CreateInstance(2759AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {2760Process *process(runtime.GetProcess());27612762Status error;27632764Log *log = GetLog(LLDBLog::Types);27652766auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(2767process, ConstString("objc_debug_isa_magic_mask"), objc_module_sp, error);2768if (error.Fail())2769return nullptr;27702771auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(2772process, ConstString("objc_debug_isa_magic_value"), objc_module_sp,2773error);2774if (error.Fail())2775return nullptr;27762777auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(2778process, ConstString("objc_debug_isa_class_mask"), objc_module_sp, error);2779if (error.Fail())2780return nullptr;27812782if (log)2783log->PutCString("AOCRT::NPI: Found all the non-indexed ISA masks");27842785bool foundError = false;2786auto objc_debug_indexed_isa_magic_mask = ExtractRuntimeGlobalSymbol(2787process, ConstString("objc_debug_indexed_isa_magic_mask"), objc_module_sp,2788error);2789foundError |= error.Fail();27902791auto objc_debug_indexed_isa_magic_value = ExtractRuntimeGlobalSymbol(2792process, ConstString("objc_debug_indexed_isa_magic_value"),2793objc_module_sp, error);2794foundError |= error.Fail();27952796auto objc_debug_indexed_isa_index_mask = ExtractRuntimeGlobalSymbol(2797process, ConstString("objc_debug_indexed_isa_index_mask"), objc_module_sp,2798error);2799foundError |= error.Fail();28002801auto objc_debug_indexed_isa_index_shift = ExtractRuntimeGlobalSymbol(2802process, ConstString("objc_debug_indexed_isa_index_shift"),2803objc_module_sp, error);2804foundError |= error.Fail();28052806auto objc_indexed_classes =2807ExtractRuntimeGlobalSymbol(process, ConstString("objc_indexed_classes"),2808objc_module_sp, error, false);2809foundError |= error.Fail();28102811if (log)2812log->PutCString("AOCRT::NPI: Found all the indexed ISA masks");28132814// we might want to have some rules to outlaw these other values (e.g if the2815// mask is zero but the value is non-zero, ...)28162817return new NonPointerISACache(2818runtime, objc_module_sp, objc_debug_isa_class_mask,2819objc_debug_isa_magic_mask, objc_debug_isa_magic_value,2820objc_debug_indexed_isa_magic_mask, objc_debug_indexed_isa_magic_value,2821objc_debug_indexed_isa_index_mask, objc_debug_indexed_isa_index_shift,2822foundError ? 0 : objc_indexed_classes);2823}28242825AppleObjCRuntimeV2::TaggedPointerVendorV2 *2826AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance(2827AppleObjCRuntimeV2 &runtime, const lldb::ModuleSP &objc_module_sp) {2828Process *process(runtime.GetProcess());28292830Status error;28312832auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(2833process, ConstString("objc_debug_taggedpointer_mask"), objc_module_sp,2834error);2835if (error.Fail())2836return new TaggedPointerVendorLegacy(runtime);28372838auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(2839process, ConstString("objc_debug_taggedpointer_slot_shift"),2840objc_module_sp, error, true, 4);2841if (error.Fail())2842return new TaggedPointerVendorLegacy(runtime);28432844auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(2845process, ConstString("objc_debug_taggedpointer_slot_mask"),2846objc_module_sp, error, true, 4);2847if (error.Fail())2848return new TaggedPointerVendorLegacy(runtime);28492850auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(2851process, ConstString("objc_debug_taggedpointer_payload_lshift"),2852objc_module_sp, error, true, 4);2853if (error.Fail())2854return new TaggedPointerVendorLegacy(runtime);28552856auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(2857process, ConstString("objc_debug_taggedpointer_payload_rshift"),2858objc_module_sp, error, true, 4);2859if (error.Fail())2860return new TaggedPointerVendorLegacy(runtime);28612862auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(2863process, ConstString("objc_debug_taggedpointer_classes"), objc_module_sp,2864error, false);2865if (error.Fail())2866return new TaggedPointerVendorLegacy(runtime);28672868// try to detect the "extended tagged pointer" variables - if any are2869// missing, use the non-extended vendor2870do {2871auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(2872process, ConstString("objc_debug_taggedpointer_ext_mask"),2873objc_module_sp, error);2874if (error.Fail())2875break;28762877auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(2878process, ConstString("objc_debug_taggedpointer_ext_slot_shift"),2879objc_module_sp, error, true, 4);2880if (error.Fail())2881break;28822883auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(2884process, ConstString("objc_debug_taggedpointer_ext_slot_mask"),2885objc_module_sp, error, true, 4);2886if (error.Fail())2887break;28882889auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(2890process, ConstString("objc_debug_taggedpointer_ext_classes"),2891objc_module_sp, error, false);2892if (error.Fail())2893break;28942895auto objc_debug_taggedpointer_ext_payload_lshift =2896ExtractRuntimeGlobalSymbol(2897process, ConstString("objc_debug_taggedpointer_ext_payload_lshift"),2898objc_module_sp, error, true, 4);2899if (error.Fail())2900break;29012902auto objc_debug_taggedpointer_ext_payload_rshift =2903ExtractRuntimeGlobalSymbol(2904process, ConstString("objc_debug_taggedpointer_ext_payload_rshift"),2905objc_module_sp, error, true, 4);2906if (error.Fail())2907break;29082909return new TaggedPointerVendorExtended(2910runtime, objc_debug_taggedpointer_mask,2911objc_debug_taggedpointer_ext_mask, objc_debug_taggedpointer_slot_shift,2912objc_debug_taggedpointer_ext_slot_shift,2913objc_debug_taggedpointer_slot_mask,2914objc_debug_taggedpointer_ext_slot_mask,2915objc_debug_taggedpointer_payload_lshift,2916objc_debug_taggedpointer_payload_rshift,2917objc_debug_taggedpointer_ext_payload_lshift,2918objc_debug_taggedpointer_ext_payload_rshift,2919objc_debug_taggedpointer_classes, objc_debug_taggedpointer_ext_classes);2920} while (false);29212922// we might want to have some rules to outlaw these values (e.g if the2923// table's address is zero)29242925return new TaggedPointerVendorRuntimeAssisted(2926runtime, objc_debug_taggedpointer_mask,2927objc_debug_taggedpointer_slot_shift, objc_debug_taggedpointer_slot_mask,2928objc_debug_taggedpointer_payload_lshift,2929objc_debug_taggedpointer_payload_rshift,2930objc_debug_taggedpointer_classes);2931}29322933bool AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer(2934lldb::addr_t ptr) {2935return (ptr & 1);2936}29372938ObjCLanguageRuntime::ClassDescriptorSP2939AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor(2940lldb::addr_t ptr) {2941if (!IsPossibleTaggedPointer(ptr))2942return ObjCLanguageRuntime::ClassDescriptorSP();29432944uint32_t foundation_version = m_runtime.GetFoundationVersion();29452946if (foundation_version == LLDB_INVALID_MODULE_VERSION)2947return ObjCLanguageRuntime::ClassDescriptorSP();29482949uint64_t class_bits = (ptr & 0xE) >> 1;2950ConstString name;29512952static ConstString g_NSAtom("NSAtom");2953static ConstString g_NSNumber("NSNumber");2954static ConstString g_NSDateTS("NSDateTS");2955static ConstString g_NSManagedObject("NSManagedObject");2956static ConstString g_NSDate("NSDate");29572958if (foundation_version >= 900) {2959switch (class_bits) {2960case 0:2961name = g_NSAtom;2962break;2963case 3:2964name = g_NSNumber;2965break;2966case 4:2967name = g_NSDateTS;2968break;2969case 5:2970name = g_NSManagedObject;2971break;2972case 6:2973name = g_NSDate;2974break;2975default:2976return ObjCLanguageRuntime::ClassDescriptorSP();2977}2978} else {2979switch (class_bits) {2980case 1:2981name = g_NSNumber;2982break;2983case 5:2984name = g_NSManagedObject;2985break;2986case 6:2987name = g_NSDate;2988break;2989case 7:2990name = g_NSDateTS;2991break;2992default:2993return ObjCLanguageRuntime::ClassDescriptorSP();2994}2995}29962997lldb::addr_t unobfuscated = ptr ^ m_runtime.GetTaggedPointerObfuscator();2998return ClassDescriptorSP(new ClassDescriptorV2Tagged(name, unobfuscated));2999}30003001AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::3002TaggedPointerVendorRuntimeAssisted(3003AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,3004uint32_t objc_debug_taggedpointer_slot_shift,3005uint32_t objc_debug_taggedpointer_slot_mask,3006uint32_t objc_debug_taggedpointer_payload_lshift,3007uint32_t objc_debug_taggedpointer_payload_rshift,3008lldb::addr_t objc_debug_taggedpointer_classes)3009: TaggedPointerVendorV2(runtime), m_cache(),3010m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),3011m_objc_debug_taggedpointer_slot_shift(3012objc_debug_taggedpointer_slot_shift),3013m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),3014m_objc_debug_taggedpointer_payload_lshift(3015objc_debug_taggedpointer_payload_lshift),3016m_objc_debug_taggedpointer_payload_rshift(3017objc_debug_taggedpointer_payload_rshift),3018m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes) {}30193020bool AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::3021IsPossibleTaggedPointer(lldb::addr_t ptr) {3022return (ptr & m_objc_debug_taggedpointer_mask) != 0;3023}30243025ObjCLanguageRuntime::ClassDescriptorSP3026AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(3027lldb::addr_t ptr) {3028ClassDescriptorSP actual_class_descriptor_sp;3029uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();30303031if (!IsPossibleTaggedPointer(unobfuscated))3032return ObjCLanguageRuntime::ClassDescriptorSP();30333034uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) &3035m_objc_debug_taggedpointer_slot_mask;30363037CacheIterator iterator = m_cache.find(slot), end = m_cache.end();3038if (iterator != end) {3039actual_class_descriptor_sp = iterator->second;3040} else {3041Process *process(m_runtime.GetProcess());3042uintptr_t slot_ptr = slot * process->GetAddressByteSize() +3043m_objc_debug_taggedpointer_classes;3044Status error;3045uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);3046if (error.Fail() || slot_data == 0 ||3047slot_data == uintptr_t(LLDB_INVALID_ADDRESS))3048return nullptr;3049actual_class_descriptor_sp =3050m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);3051if (!actual_class_descriptor_sp) {3052if (ABISP abi_sp = process->GetABI()) {3053ObjCISA fixed_isa = abi_sp->FixCodeAddress((ObjCISA)slot_data);3054actual_class_descriptor_sp =3055m_runtime.GetClassDescriptorFromISA(fixed_isa);3056}3057}3058if (!actual_class_descriptor_sp)3059return ObjCLanguageRuntime::ClassDescriptorSP();3060m_cache[slot] = actual_class_descriptor_sp;3061}30623063uint64_t data_payload =3064((unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>3065m_objc_debug_taggedpointer_payload_rshift);3066int64_t data_payload_signed =3067((int64_t)(unobfuscated << m_objc_debug_taggedpointer_payload_lshift) >>3068m_objc_debug_taggedpointer_payload_rshift);3069return ClassDescriptorSP(new ClassDescriptorV2Tagged(3070actual_class_descriptor_sp, data_payload, data_payload_signed));3071}30723073AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended(3074AppleObjCRuntimeV2 &runtime, uint64_t objc_debug_taggedpointer_mask,3075uint64_t objc_debug_taggedpointer_ext_mask,3076uint32_t objc_debug_taggedpointer_slot_shift,3077uint32_t objc_debug_taggedpointer_ext_slot_shift,3078uint32_t objc_debug_taggedpointer_slot_mask,3079uint32_t objc_debug_taggedpointer_ext_slot_mask,3080uint32_t objc_debug_taggedpointer_payload_lshift,3081uint32_t objc_debug_taggedpointer_payload_rshift,3082uint32_t objc_debug_taggedpointer_ext_payload_lshift,3083uint32_t objc_debug_taggedpointer_ext_payload_rshift,3084lldb::addr_t objc_debug_taggedpointer_classes,3085lldb::addr_t objc_debug_taggedpointer_ext_classes)3086: TaggedPointerVendorRuntimeAssisted(3087runtime, objc_debug_taggedpointer_mask,3088objc_debug_taggedpointer_slot_shift,3089objc_debug_taggedpointer_slot_mask,3090objc_debug_taggedpointer_payload_lshift,3091objc_debug_taggedpointer_payload_rshift,3092objc_debug_taggedpointer_classes),3093m_ext_cache(),3094m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),3095m_objc_debug_taggedpointer_ext_slot_shift(3096objc_debug_taggedpointer_ext_slot_shift),3097m_objc_debug_taggedpointer_ext_slot_mask(3098objc_debug_taggedpointer_ext_slot_mask),3099m_objc_debug_taggedpointer_ext_payload_lshift(3100objc_debug_taggedpointer_ext_payload_lshift),3101m_objc_debug_taggedpointer_ext_payload_rshift(3102objc_debug_taggedpointer_ext_payload_rshift),3103m_objc_debug_taggedpointer_ext_classes(3104objc_debug_taggedpointer_ext_classes) {}31053106bool AppleObjCRuntimeV2::TaggedPointerVendorExtended::3107IsPossibleExtendedTaggedPointer(lldb::addr_t ptr) {3108if (!IsPossibleTaggedPointer(ptr))3109return false;31103111if (m_objc_debug_taggedpointer_ext_mask == 0)3112return false;31133114return ((ptr & m_objc_debug_taggedpointer_ext_mask) ==3115m_objc_debug_taggedpointer_ext_mask);3116}31173118ObjCLanguageRuntime::ClassDescriptorSP3119AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor(3120lldb::addr_t ptr) {3121ClassDescriptorSP actual_class_descriptor_sp;3122uint64_t unobfuscated = (ptr) ^ m_runtime.GetTaggedPointerObfuscator();31233124if (!IsPossibleTaggedPointer(unobfuscated))3125return ObjCLanguageRuntime::ClassDescriptorSP();31263127if (!IsPossibleExtendedTaggedPointer(unobfuscated))3128return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);31293130uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) &3131m_objc_debug_taggedpointer_ext_slot_mask;31323133CacheIterator iterator = m_ext_cache.find(slot), end = m_ext_cache.end();3134if (iterator != end) {3135actual_class_descriptor_sp = iterator->second;3136} else {3137Process *process(m_runtime.GetProcess());3138uintptr_t slot_ptr = slot * process->GetAddressByteSize() +3139m_objc_debug_taggedpointer_ext_classes;3140Status error;3141uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);3142if (error.Fail() || slot_data == 0 ||3143slot_data == uintptr_t(LLDB_INVALID_ADDRESS))3144return nullptr;3145actual_class_descriptor_sp =3146m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);3147if (!actual_class_descriptor_sp)3148return ObjCLanguageRuntime::ClassDescriptorSP();3149m_ext_cache[slot] = actual_class_descriptor_sp;3150}31513152uint64_t data_payload = (((uint64_t)unobfuscated3153<< m_objc_debug_taggedpointer_ext_payload_lshift) >>3154m_objc_debug_taggedpointer_ext_payload_rshift);3155int64_t data_payload_signed =3156((int64_t)((uint64_t)unobfuscated3157<< m_objc_debug_taggedpointer_ext_payload_lshift) >>3158m_objc_debug_taggedpointer_ext_payload_rshift);31593160return ClassDescriptorSP(new ClassDescriptorV2Tagged(3161actual_class_descriptor_sp, data_payload, data_payload_signed));3162}31633164AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache(3165AppleObjCRuntimeV2 &runtime, const ModuleSP &objc_module_sp,3166uint64_t objc_debug_isa_class_mask, uint64_t objc_debug_isa_magic_mask,3167uint64_t objc_debug_isa_magic_value,3168uint64_t objc_debug_indexed_isa_magic_mask,3169uint64_t objc_debug_indexed_isa_magic_value,3170uint64_t objc_debug_indexed_isa_index_mask,3171uint64_t objc_debug_indexed_isa_index_shift,3172lldb::addr_t objc_indexed_classes)3173: m_runtime(runtime), m_cache(), m_objc_module_wp(objc_module_sp),3174m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),3175m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),3176m_objc_debug_isa_magic_value(objc_debug_isa_magic_value),3177m_objc_debug_indexed_isa_magic_mask(objc_debug_indexed_isa_magic_mask),3178m_objc_debug_indexed_isa_magic_value(objc_debug_indexed_isa_magic_value),3179m_objc_debug_indexed_isa_index_mask(objc_debug_indexed_isa_index_mask),3180m_objc_debug_indexed_isa_index_shift(objc_debug_indexed_isa_index_shift),3181m_objc_indexed_classes(objc_indexed_classes), m_indexed_isa_cache() {}31823183ObjCLanguageRuntime::ClassDescriptorSP3184AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor(ObjCISA isa) {3185ObjCISA real_isa = 0;3186if (!EvaluateNonPointerISA(isa, real_isa))3187return ObjCLanguageRuntime::ClassDescriptorSP();3188auto cache_iter = m_cache.find(real_isa);3189if (cache_iter != m_cache.end())3190return cache_iter->second;3191auto descriptor_sp =3192m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);3193if (descriptor_sp) // cache only positive matches since the table might grow3194m_cache[real_isa] = descriptor_sp;3195return descriptor_sp;3196}31973198bool AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA(3199ObjCISA isa, ObjCISA &ret_isa) {3200Log *log = GetLog(LLDBLog::Types);32013202LLDB_LOGF(log, "AOCRT::NPI Evaluate(isa = 0x%" PRIx64 ")", (uint64_t)isa);32033204if ((isa & ~m_objc_debug_isa_class_mask) == 0)3205return false;32063207// If all of the indexed ISA variables are set, then its possible that this3208// ISA is indexed, and we should first try to get its value using the index.3209// Note, we check these variables first as the ObjC runtime will set at least3210// one of their values to 0 if they aren't needed.3211if (m_objc_debug_indexed_isa_magic_mask &&3212m_objc_debug_indexed_isa_magic_value &&3213m_objc_debug_indexed_isa_index_mask &&3214m_objc_debug_indexed_isa_index_shift && m_objc_indexed_classes) {3215if ((isa & ~m_objc_debug_indexed_isa_index_mask) == 0)3216return false;32173218if ((isa & m_objc_debug_indexed_isa_magic_mask) ==3219m_objc_debug_indexed_isa_magic_value) {3220// Magic bits are correct, so try extract the index.3221uintptr_t index = (isa & m_objc_debug_indexed_isa_index_mask) >>3222m_objc_debug_indexed_isa_index_shift;3223// If the index is out of bounds of the length of the array then check if3224// the array has been updated. If that is the case then we should try3225// read the count again, and update the cache if the count has been3226// updated.3227if (index > m_indexed_isa_cache.size()) {3228LLDB_LOGF(log,3229"AOCRT::NPI (index = %" PRIu643230") exceeds cache (size = %" PRIu64 ")",3231(uint64_t)index, (uint64_t)m_indexed_isa_cache.size());32323233Process *process(m_runtime.GetProcess());32343235ModuleSP objc_module_sp(m_objc_module_wp.lock());3236if (!objc_module_sp)3237return false;32383239Status error;3240auto objc_indexed_classes_count = ExtractRuntimeGlobalSymbol(3241process, ConstString("objc_indexed_classes_count"), objc_module_sp,3242error);3243if (error.Fail())3244return false;32453246LLDB_LOGF(log, "AOCRT::NPI (new class count = %" PRIu64 ")",3247(uint64_t)objc_indexed_classes_count);32483249if (objc_indexed_classes_count > m_indexed_isa_cache.size()) {3250// Read the class entries we don't have. We should just read all of3251// them instead of just the one we need as then we can cache those we3252// may need later.3253auto num_new_classes =3254objc_indexed_classes_count - m_indexed_isa_cache.size();3255const uint32_t addr_size = process->GetAddressByteSize();3256DataBufferHeap buffer(num_new_classes * addr_size, 0);32573258lldb::addr_t last_read_class =3259m_objc_indexed_classes + (m_indexed_isa_cache.size() * addr_size);3260size_t bytes_read = process->ReadMemory(3261last_read_class, buffer.GetBytes(), buffer.GetByteSize(), error);3262if (error.Fail() || bytes_read != buffer.GetByteSize())3263return false;32643265LLDB_LOGF(log, "AOCRT::NPI (read new classes count = %" PRIu64 ")",3266(uint64_t)num_new_classes);32673268// Append the new entries to the existing cache.3269DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(),3270process->GetByteOrder(),3271process->GetAddressByteSize());32723273lldb::offset_t offset = 0;3274for (unsigned i = 0; i != num_new_classes; ++i)3275m_indexed_isa_cache.push_back(data.GetAddress(&offset));3276}3277}32783279// If the index is still out of range then this isn't a pointer.3280if (index > m_indexed_isa_cache.size())3281return false;32823283LLDB_LOGF(log, "AOCRT::NPI Evaluate(ret_isa = 0x%" PRIx64 ")",3284(uint64_t)m_indexed_isa_cache[index]);32853286ret_isa = m_indexed_isa_cache[index];3287return (ret_isa != 0); // this is a pointer so 0 is not a valid value3288}32893290return false;3291}32923293// Definitely not an indexed ISA, so try to use a mask to extract the pointer3294// from the ISA.3295if ((isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value) {3296ret_isa = isa & m_objc_debug_isa_class_mask;3297return (ret_isa != 0); // this is a pointer so 0 is not a valid value3298}3299return false;3300}33013302ObjCLanguageRuntime::EncodingToTypeSP AppleObjCRuntimeV2::GetEncodingToType() {3303if (!m_encoding_to_type_sp)3304m_encoding_to_type_sp =3305std::make_shared<AppleObjCTypeEncodingParser>(*this);3306return m_encoding_to_type_sp;3307}33083309lldb_private::AppleObjCRuntime::ObjCISA3310AppleObjCRuntimeV2::GetPointerISA(ObjCISA isa) {3311ObjCISA ret = isa;33123313if (auto *non_pointer_isa_cache = GetNonPointerIsaCache())3314non_pointer_isa_cache->EvaluateNonPointerISA(isa, ret);33153316return ret;3317}33183319bool AppleObjCRuntimeV2::GetCFBooleanValuesIfNeeded() {3320if (m_CFBoolean_values)3321return true;33223323static ConstString g_dunder_kCFBooleanFalse("__kCFBooleanFalse");3324static ConstString g_dunder_kCFBooleanTrue("__kCFBooleanTrue");3325static ConstString g_kCFBooleanFalse("kCFBooleanFalse");3326static ConstString g_kCFBooleanTrue("kCFBooleanTrue");33273328std::function<lldb::addr_t(ConstString, ConstString)> get_symbol =3329[this](ConstString sym, ConstString real_sym) -> lldb::addr_t {3330SymbolContextList sc_list;3331GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(3332sym, lldb::eSymbolTypeData, sc_list);3333if (sc_list.GetSize() == 1) {3334SymbolContext sc;3335sc_list.GetContextAtIndex(0, sc);3336if (sc.symbol)3337return sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());3338}3339GetProcess()->GetTarget().GetImages().FindSymbolsWithNameAndType(3340real_sym, lldb::eSymbolTypeData, sc_list);3341if (sc_list.GetSize() != 1)3342return LLDB_INVALID_ADDRESS;33433344SymbolContext sc;3345sc_list.GetContextAtIndex(0, sc);3346if (!sc.symbol)3347return LLDB_INVALID_ADDRESS;33483349lldb::addr_t addr = sc.symbol->GetLoadAddress(&GetProcess()->GetTarget());3350Status error;3351addr = GetProcess()->ReadPointerFromMemory(addr, error);3352if (error.Fail())3353return LLDB_INVALID_ADDRESS;3354return addr;3355};33563357lldb::addr_t false_addr = get_symbol(g_dunder_kCFBooleanFalse, g_kCFBooleanFalse);3358lldb::addr_t true_addr = get_symbol(g_dunder_kCFBooleanTrue, g_kCFBooleanTrue);33593360return (m_CFBoolean_values = {false_addr, true_addr}).operator bool();3361}33623363void AppleObjCRuntimeV2::GetValuesForGlobalCFBooleans(lldb::addr_t &cf_true,3364lldb::addr_t &cf_false) {3365if (GetCFBooleanValuesIfNeeded()) {3366cf_true = m_CFBoolean_values->second;3367cf_false = m_CFBoolean_values->first;3368} else3369this->AppleObjCRuntime::GetValuesForGlobalCFBooleans(cf_true, cf_false);3370}33713372void AppleObjCRuntimeV2::ModulesDidLoad(const ModuleList &module_list) {3373AppleObjCRuntime::ModulesDidLoad(module_list);3374if (HasReadObjCLibrary() && m_shared_cache_image_headers_up)3375m_shared_cache_image_headers_up->SetNeedsUpdate();3376}33773378bool AppleObjCRuntimeV2::IsSharedCacheImageLoaded(uint16_t image_index) {3379if (!m_shared_cache_image_headers_up) {3380m_shared_cache_image_headers_up =3381SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);3382}3383if (m_shared_cache_image_headers_up)3384return m_shared_cache_image_headers_up->IsImageLoaded(image_index);33853386return false;3387}33883389std::optional<uint64_t> AppleObjCRuntimeV2::GetSharedCacheImageHeaderVersion() {3390if (!m_shared_cache_image_headers_up) {3391m_shared_cache_image_headers_up =3392SharedCacheImageHeaders::CreateSharedCacheImageHeaders(*this);3393}3394if (m_shared_cache_image_headers_up)3395return m_shared_cache_image_headers_up->GetVersion();33963397return std::nullopt;3398}33993400#pragma mark Frame recognizers34013402class ObjCExceptionRecognizedStackFrame : public RecognizedStackFrame {3403public:3404ObjCExceptionRecognizedStackFrame(StackFrameSP frame_sp) {3405ThreadSP thread_sp = frame_sp->GetThread();3406ProcessSP process_sp = thread_sp->GetProcess();34073408const lldb::ABISP &abi = process_sp->GetABI();3409if (!abi)3410return;34113412TypeSystemClangSP scratch_ts_sp =3413ScratchTypeSystemClang::GetForTarget(process_sp->GetTarget());3414if (!scratch_ts_sp)3415return;3416CompilerType voidstar =3417scratch_ts_sp->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();34183419ValueList args;3420Value input_value;3421input_value.SetCompilerType(voidstar);3422args.PushValue(input_value);34233424if (!abi->GetArgumentValues(*thread_sp, args))3425return;34263427addr_t exception_addr = args.GetValueAtIndex(0)->GetScalar().ULongLong();34283429Value value(exception_addr);3430value.SetCompilerType(voidstar);3431exception = ValueObjectConstResult::Create(frame_sp.get(), value,3432ConstString("exception"));3433exception = ValueObjectRecognizerSynthesizedValue::Create(3434*exception, eValueTypeVariableArgument);3435exception = exception->GetDynamicValue(eDynamicDontRunTarget);34363437m_arguments = ValueObjectListSP(new ValueObjectList());3438m_arguments->Append(exception);34393440m_stop_desc = "hit Objective-C exception";3441}34423443ValueObjectSP exception;34443445lldb::ValueObjectSP GetExceptionObject() override { return exception; }3446};34473448class ObjCExceptionThrowFrameRecognizer : public StackFrameRecognizer {3449lldb::RecognizedStackFrameSP3450RecognizeFrame(lldb::StackFrameSP frame) override {3451return lldb::RecognizedStackFrameSP(3452new ObjCExceptionRecognizedStackFrame(frame));3453};3454std::string GetName() override {3455return "ObjC Exception Throw StackFrame Recognizer";3456}3457};34583459static void RegisterObjCExceptionRecognizer(Process *process) {3460FileSpec module;3461ConstString function;3462std::tie(module, function) = AppleObjCRuntime::GetExceptionThrowLocation();3463std::vector<ConstString> symbols = {function};34643465process->GetTarget().GetFrameRecognizerManager().AddRecognizer(3466StackFrameRecognizerSP(new ObjCExceptionThrowFrameRecognizer()),3467module.GetFilename(), symbols,3468/*first_instruction_only*/ true);3469}347034713472