brintos

brintos / llvm-project-archived public Read only

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