Loading...
common/ObjCVisitor.cpp dyld-1340 /dev/null
--- dyld/dyld-1340/common/ObjCVisitor.cpp
+++ /dev/null
@@ -1,2107 +0,0 @@
-/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
- *
- * Copyright (c) 2014 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <TargetConditionals.h>
-
-#if !TARGET_OS_EXCLAVEKIT
-
-#include "ObjCVisitor.h"
-
-#if SUPPORT_VM_LAYOUT
-#include "MachOAnalyzer.h"
-#endif
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-#include "ASLRTracker.h"
-#include <unordered_set>
-#endif
-
-using namespace objc_visitor;
-using ResolvedValue = metadata_visitor::ResolvedValue;
-using mach_o::Header;
-
-#if !SUPPORT_VM_LAYOUT
-using metadata_visitor::Segment;
-#endif
-
-//
-// MARK: --- Class methods ---
-//
-
-const void* Class::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const class32_t* class32 = (const class32_t*)this->classPos.value();
-        switch ( field ) {
-            case Field::isa:
-                return &class32->isaVMAddr;
-            case Field::superclass:
-                return &class32->superclassVMAddr;
-            case Field::methodCacheBuckets:
-                return &class32->methodCacheBuckets;
-            case Field::methodCacheProperties:
-                return &class32->methodCacheProperties;
-            case Field::data:
-                return &class32->dataVMAddrAndFastFlags;
-            case Field::swiftClassFlags:
-                return &class32->swiftClassFlags;
-        }
-    } else {
-        const class64_t* class64 = (const class64_t*)this->classPos.value();
-        switch ( field ) {
-            case Field::isa:
-                return &class64->isaVMAddr;
-            case Field::superclass:
-                return &class64->superclassVMAddr;
-            case Field::methodCacheBuckets:
-                return &class64->methodCacheBuckets;
-            case Field::methodCacheProperties:
-                return &class64->methodCacheProperties;
-            case Field::data:
-                return &class64->dataVMAddrAndFastFlags;
-            case Field::swiftClassFlags:
-                return &class64->swiftClassFlags;
-        }
-    }
-}
-
-ResolvedValue Class::getISA(const Visitor& objcVisitor, bool& isPatchableClass) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::isa));
-    return objcVisitor.resolveBindOrRebase(field, isPatchableClass);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS || BUILDING_SHARED_CACHE_UTIL
-std::optional<ResolvedValue> Class::getSuperclass(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::superclass));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-std::optional<VMAddress> Class::getSuperclassVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::superclass));
-    std::optional<VMAddress> targetAddress = objcVisitor.resolveOptionalRebaseToVMAddress(field);
-
-    if ( !targetAddress.has_value() )
-        return std::nullopt;
-
-    return targetAddress;
-}
-#endif
-
-ResolvedValue Class::getSuperclassField(const Visitor& objcVisitor) const
-{
-    return objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::superclass));
-}
-
-ResolvedValue Class::getMethodCache(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::methodCacheBuckets));
-
-    bool unusedIsPatchableClass;
-    return objcVisitor.resolveBindOrRebase(field, unusedIsPatchableClass);
-}
-
-std::optional<ResolvedValue> Class::getMethodCacheProperties(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::methodCacheProperties));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-ResolvedValue Class::getMethodCachePropertiesField(const Visitor& objcVisitor) const
-{
-    return objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::methodCacheProperties));
-}
-
-std::optional<VMAddress> Class::getMethodCachePropertiesVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::methodCacheProperties));
-
-    // The field might be null.  Get the target value, then see if it has a value
-    std::optional<ResolvedValue> targetValue = objcVisitor.resolveOptionalRebase(field);
-    if ( targetValue.has_value() )
-        return targetValue->vmAddress();
-
-    return { };
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Class::setMethodCachePropertiesVMAddr(const Visitor& objcVisitor, VMAddress vmAddr,
-                                           const dyld3::MachOFile::PointerMetaData& PMD)
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::methodCacheProperties));
-    objcVisitor.setTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()), PMD);
-}
-#endif
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS || BUILDING_SHARED_CACHE_UTIL
-void Class::withSuperclass(const Visitor& objcVisitor,
-                           void (^handler)(const dyld3::MachOFile::ChainedFixupPointerOnDisk* fixup, uint16_t pointerFormat)) const
-{
-    // HACK: The visitor classes need to be refactored to handle cache util. For now just force the caller of this method in
-    // cache util to have the chain format
-#if BUILDING_SHARED_CACHE_UTIL
-    uint16_t chainedPointerFormat = 0;
-#else
-    uint16_t chainedPointerFormat = this->classPos.chainedPointerFormat().value();
-#endif
-
-    const void* fieldPos = this->getFieldPos(objcVisitor, Field::superclass);
-    dyld3::MachOFile::ChainedFixupPointerOnDisk* fieldFixup = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)fieldPos;
-    handler(fieldFixup, chainedPointerFormat);
-}
-#endif
-
-bool Class::isUnfixedBackwardDeployingStableSwift(const Visitor& objcVisitor) const
-{
-    // Only classes marked as Swift legacy need apply.
-    if ( !this->isSwiftLegacy(objcVisitor) )
-        return false;
-
-    std::optional<uint32_t> swiftClassFlags = this->swiftClassFlags(objcVisitor);
-    if ( swiftClassFlags.has_value() ) {
-        // Check the true legacy vs stable distinguisher.
-        // The low bit of Swift's ClassFlags is SET for true legacy
-        // and UNSET for stable pretending to be legacy.
-        bool isActuallySwiftLegacy = (swiftClassFlags.value() & isSwiftPreStableABI) != 0;
-        return !isActuallySwiftLegacy;
-    } else {
-        // Is this possible?  We were a legacy class but had no flags?
-        return false;
-    }
-}
-
-bool Class::isSwiftLegacy(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::data));
-    ResolvedValue fieldValue = objcVisitor.resolveRebase(field);
-
-    // Mask out the flags from the data value
-    uint64_t rawDataVMAddr = fieldValue.vmAddress().rawValue();
-    return (rawDataVMAddr & FAST_IS_SWIFT_LEGACY) != 0;
-}
-
-bool Class::isSwiftStable(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::data));
-    ResolvedValue fieldValue = objcVisitor.resolveRebase(field);
-
-    // Mask out the flags from the data value
-    uint64_t rawDataVMAddr = fieldValue.vmAddress().rawValue();
-    return (rawDataVMAddr & FAST_IS_SWIFT_STABLE) != 0;
-}
-
-bool Class::isSwift(const Visitor& objcVisitor) const
-{
-    return this->isSwiftStable(objcVisitor) || this->isSwiftLegacy(objcVisitor);
-}
-
-std::optional<uint32_t> Class::swiftClassFlags(const Visitor& objcVisitor) const
-{
-    if ( !this->isSwift(objcVisitor) )
-        return { };
-
-    return *(uint32_t*)this->getFieldPos(objcVisitor, Field::swiftClassFlags);
-}
-
-ResolvedValue Class::getDataField(const Visitor& objcVisitor) const
-{
-    return objcVisitor.getField(this->classPos, this->getFieldPos(objcVisitor, Field::data));
-}
-
-ClassData Class::getClassData(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = this->getDataField(objcVisitor);
-    ResolvedValue targetValue = objcVisitor.resolveRebase(field);
-    // Mask out the low bits, if they are set
-    VMAddress vmAddr = targetValue.vmAddress();
-
-    uint64_t mask = (objcVisitor.pointerSize == 4) ? (uint64_t)FAST_DATA_MASK32 : FAST_DATA_MASK64;
-    uint64_t rawVMAddr = vmAddr.rawValue();
-    uint64_t maskedVMAddr = rawVMAddr & mask;
-    if ( maskedVMAddr != rawVMAddr ) {
-        // Adjust the pointer as we have bits to remove
-        uint64_t adjust = rawVMAddr - maskedVMAddr;
-        const uint8_t* unadjustedValue = (const uint8_t*)targetValue.value();
-        const uint8_t* adjustedValue = unadjustedValue - adjust;
-        //return ClassData(ResolvedValue(targetValue, adjustedValue));
-
-        // We can't just construct a new ResolvedValue here with the adjusted value as we don't
-        // have the right constructors when building for dyld.  Instead we'll pretend we are
-        // just accessing a field of a struct, where the value we have is the struct and we are
-        // resolving to a value before it.  Eg, "struct foo ... return &foo - 2"
-        ResolvedValue adjustedField = objcVisitor.getField(targetValue, adjustedValue);
-        return ClassData(adjustedField);
-    }
-    return ClassData(targetValue);
-}
-
-VMAddress Class::getClassDataVMAddr(const Visitor& objcVisitor) const
-{
-    return getClassData(objcVisitor).getVMAddress();
-}
-
-bool Class::isRootClass(const Visitor& objcVisitor) const
-{
-    ClassData data = getClassData(objcVisitor);
-    uint32_t flags = *(uint32_t*)data.getFieldPos(objcVisitor, ClassData::Field::flags);
-
-    const uint32_t RO_ROOT = (1 << 1);
-    return (flags & RO_ROOT) != 0;
-}
-
-const char* Class::getName(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::name);
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-VMAddress Class::getNameVMAddr(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::name);
-    return objcVisitor.resolveRebase(field).vmAddress();
-}
-
-MethodList Class::getBaseMethods(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseMethods);
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-ResolvedValue Class::setBaseMethodsVMAddr(const Visitor& objcVisitor, VMAddress vmAddr,
-                                 const dyld3::MachOFile::PointerMetaData& PMD)
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseMethods);;
-    objcVisitor.setTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()), PMD);
-    return field;
-}
-#endif
-
-ProtocolList Class::getBaseProtocols(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseProtocols);
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-ResolvedValue Class::setBaseProtocolsVMAddr(const Visitor& objcVisitor, VMAddress vmAddr)
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseProtocols);
-    objcVisitor.updateTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()));
-    return field;
-}
-#endif
-
-IVarList Class::getIVars(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::ivars);
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-PropertyList Class::getBaseProperties(const Visitor& objcVisitor) const
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseProperties);
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-ResolvedValue Class::setBasePropertiesVMAddr(const Visitor& objcVisitor, VMAddress vmAddr)
-{
-    ClassData classData = getClassData(objcVisitor);
-    ResolvedValue field = classData.getField(objcVisitor, ClassData::Field::baseProperties);
-    objcVisitor.updateTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()));
-    return field;
-}
-#endif
-
-uint32_t Class::getInstanceStart(const Visitor& objcVisitor) const
-{
-    ClassData data = getClassData(objcVisitor);
-    return *(uint32_t*)data.getFieldPos(objcVisitor, ClassData::Field::instanceStart);
-}
-
-void Class::setInstanceStart(const Visitor& objcVisitor, uint32_t value) const
-{
-    ClassData data = getClassData(objcVisitor);
-    *(uint32_t*)data.getFieldPos(objcVisitor, ClassData::Field::instanceStart) = value;
-}
-
-uint32_t Class::getInstanceSize(const Visitor& objcVisitor) const
-{
-    ClassData data = getClassData(objcVisitor);
-    return *(uint32_t*)data.getFieldPos(objcVisitor, ClassData::Field::instanceSize);
-}
-
-void Class::setInstanceSize(const Visitor& objcVisitor, uint32_t value) const
-{
-    ClassData data = getClassData(objcVisitor);
-    *(uint32_t*)data.getFieldPos(objcVisitor, ClassData::Field::instanceSize) = value;
-}
-
-const void* Class::getLocation() const
-{
-    return this->classPos.value();
-}
-
-VMAddress Class::getVMAddress() const
-{
-    return this->classPos.vmAddress();
-}
-
-//
-// MARK: --- ClassData methods ---
-//
-
-const void* ClassData::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const data32_t* data32 = (const data32_t*)this->classDataPos.value();
-        switch ( field ) {
-            case Field::flags:
-                return &data32->flags;
-            case Field::instanceStart:
-                return &data32->instanceStart;
-            case Field::instanceSize:
-                return &data32->instanceSize;
-            case Field::ivarLayout:
-                return &data32->ivarLayoutVMAddr;
-            case Field::name:
-                return &data32->nameVMAddr;
-            case Field::baseMethods:
-                return &data32->baseMethodsVMAddr;
-            case Field::baseProtocols:
-                return &data32->baseProtocolsVMAddr;
-            case Field::ivars:
-                return &data32->ivarsVMAddr;
-            case Field::weakIvarLayout:
-                return &data32->weakIvarLayoutVMAddr;
-            case Field::baseProperties:
-                return &data32->basePropertiesVMAddr;
-        }
-    } else {
-        const data64_t* data64 = (const data64_t*)this->classDataPos.value();
-        switch ( field ) {
-            case Field::flags:
-                return &data64->flags;
-            case Field::instanceStart:
-                return &data64->instanceStart;
-            case Field::instanceSize:
-                return &data64->instanceSize;
-            case Field::ivarLayout:
-                return &data64->ivarLayoutVMAddr;
-            case Field::name:
-                return &data64->nameVMAddr;
-            case Field::baseMethods:
-                return &data64->baseMethodsVMAddr;
-            case Field::baseProtocols:
-                return &data64->baseProtocolsVMAddr;
-            case Field::ivars:
-                return &data64->ivarsVMAddr;
-            case Field::weakIvarLayout:
-                return &data64->weakIvarLayoutVMAddr;
-            case Field::baseProperties:
-                return &data64->basePropertiesVMAddr;
-        }
-    }
-}
-
-ResolvedValue ClassData::getField(const Visitor& objcVisitor, Field field) const
-{
-    return objcVisitor.getField(this->classDataPos, this->getFieldPos(objcVisitor, field));
-}
-
-const void* ClassData::getLocation() const
-{
-    return this->classDataPos.value();
-}
-
-VMAddress ClassData::getVMAddress() const
-{
-    return this->classDataPos.vmAddress();
-}
-
-//
-// MARK: --- Category methods ---
-//
-
-const void* Category::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const category32_t* category32 = (const category32_t*)this->categoryPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &category32->nameVMAddr;
-            case Field::cls:
-                return &category32->clsVMAddr;
-            case Field::instanceMethods:
-                return &category32->instanceMethodsVMAddr;
-            case Field::classMethods:
-                return &category32->classMethodsVMAddr;
-            case Field::protocols:
-                return &category32->protocolsVMAddr;
-            case Field::instanceProperties:
-                return &category32->instancePropertiesVMAddr;
-            case Field::classProperties:
-                return &category32->classPropertiesVMAddr;
-        }
-    } else {
-        const category64_t* category64 = (const category64_t*)this->categoryPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &category64->nameVMAddr;
-            case Field::cls:
-                return &category64->clsVMAddr;
-            case Field::instanceMethods:
-                return &category64->instanceMethodsVMAddr;
-            case Field::classMethods:
-                return &category64->classMethodsVMAddr;
-            case Field::protocols:
-                return &category64->protocolsVMAddr;
-            case Field::instanceProperties:
-                return &category64->instancePropertiesVMAddr;
-            case Field::classProperties:
-                return &category64->classPropertiesVMAddr;
-        }
-    }
-}
-
-const char* Category::getName(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::name));
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-VMAddress Category::getVMAddress() const
-{
-    return this->categoryPos.vmAddress();
-}
-
-const void* Category::getLocation() const
-{
-    return this->categoryPos.value();
-}
-
-VMAddress Category::getNameVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::name));
-    return objcVisitor.resolveRebase(field).vmAddress();
-}
-
-MethodList Category::getInstanceMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::instanceMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-MethodList Category::getClassMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::classMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-ProtocolList Category::getProtocols(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::protocols));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-PropertyList Category::getInstanceProperties(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::instanceProperties));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-PropertyList Category::getClassProperties(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::classProperties));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS || BUILDING_SHARED_CACHE_UTIL
-void Category::withClass(const Visitor& objcVisitor,
-                         void (^handler)(const dyld3::MachOFile::ChainedFixupPointerOnDisk* fixup, uint16_t pointerFormat)) const
-{
-    // HACK: The visitor classes need to be refactored to handle cache util. For now just force the caller of this method in
-    // cache util to have the chain format
-#if BUILDING_SHARED_CACHE_UTIL
-    uint16_t chainedPointerFormat = 0;
-#else
-    assert(objcVisitor.isOnDiskBinary());
-    uint16_t chainedPointerFormat = this->categoryPos.chainedPointerFormat().value();
-#endif
-
-    const void* fieldPos = nullptr;
-    if ( objcVisitor.pointerSize == 8 ) {
-        fieldPos = &((const category64_t*)this->categoryPos.value())->clsVMAddr;
-    } else if (objcVisitor.pointerSize == 4 ){
-        fieldPos = &((const category32_t*)this->categoryPos.value())->clsVMAddr;
-    }
-    assert(fieldPos != nullptr);
-
-    dyld3::MachOFile::ChainedFixupPointerOnDisk* fieldFixup = (dyld3::MachOFile::ChainedFixupPointerOnDisk*)fieldPos;
-    handler(fieldFixup, chainedPointerFormat);
-}
-#endif
-
-uint32_t Category::getSize(bool is64)
-{
-    return is64 ? sizeof(category64_t) : sizeof(category32_t);
-}
-
-
-#if BUILDING_SHARED_CACHE_UTIL
-std::optional<VMAddress> Category::getClassVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->categoryPos, this->getFieldPos(objcVisitor, Field::cls));
-    std::optional<ResolvedValue> targetValue = objcVisitor.resolveOptionalRebase(field);
-    if ( targetValue )
-        return targetValue->vmAddress();
-
-    return { };
-}
-#endif
-
-//
-// MARK: --- Protocol methods ---
-//
-
-const void* Protocol::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const protocol32_t* protocol32 = (const protocol32_t*)this->protocolPos.value();
-        switch ( field ) {
-            case Field::isa:
-                return &protocol32->isaVMAddr;
-            case Field::name:
-                return &protocol32->nameVMAddr;
-            case Field::protocols:
-                return &protocol32->protocolsVMAddr;
-            case Field::instanceMethods:
-                return &protocol32->instanceMethodsVMAddr;
-            case Field::classMethods:
-                return &protocol32->classMethodsVMAddr;
-            case Field::optionalInstanceMethods:
-                return &protocol32->optionalInstanceMethodsVMAddr;
-            case Field::optionalClassMethods:
-                return &protocol32->optionalClassMethodsVMAddr;
-            case Field::instanceProperties:
-                return &protocol32->instancePropertiesVMAddr;
-            case Field::size:
-                return &protocol32->size;
-            case Field::flags:
-                return &protocol32->flags;
-            case Field::extendedMethodTypes:
-                return &protocol32->extendedMethodTypesVMAddr;
-            case Field::demangledName:
-                return &protocol32->demangledNameVMAddr;
-            case Field::classProperties:
-                return &protocol32->classPropertiesVMAddr;
-        }
-    } else {
-        const protocol64_t* protocol64 = (const protocol64_t*)this->protocolPos.value();
-        switch ( field ) {
-            case Field::isa:
-                return &protocol64->isaVMAddr;
-            case Field::name:
-                return &protocol64->nameVMAddr;
-            case Field::protocols:
-                return &protocol64->protocolsVMAddr;
-            case Field::instanceMethods:
-                return &protocol64->instanceMethodsVMAddr;
-            case Field::classMethods:
-                return &protocol64->classMethodsVMAddr;
-            case Field::optionalInstanceMethods:
-                return &protocol64->optionalInstanceMethodsVMAddr;
-            case Field::optionalClassMethods:
-                return &protocol64->optionalClassMethodsVMAddr;
-            case Field::instanceProperties:
-                return &protocol64->instancePropertiesVMAddr;
-            case Field::size:
-                return &protocol64->size;
-            case Field::flags:
-                return &protocol64->flags;
-            case Field::extendedMethodTypes:
-                return &protocol64->extendedMethodTypesVMAddr;
-            case Field::demangledName:
-                return &protocol64->demangledNameVMAddr;
-            case Field::classProperties:
-                return &protocol64->classPropertiesVMAddr;
-        }
-    }
-}
-
-std::optional<VMAddress> Protocol::getISAVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::isa));
-    std::optional<ResolvedValue> value = objcVisitor.resolveOptionalRebase(field);
-    if ( value )
-        return value->vmAddress();
-
-    return { };
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Protocol::setISA(const Visitor& objcVisitor, VMAddress vmAddr, const dyld3::MachOFile::PointerMetaData& PMD)
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::isa));
-    objcVisitor.setTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()), PMD);
-}
-#endif
-
-const char* Protocol::getName(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::name));
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-VMAddress Protocol::getNameVMAddr(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::name));
-    return objcVisitor.resolveRebase(field).vmAddress();
-}
-
-ProtocolList Protocol::getProtocols(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::protocols));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-MethodList Protocol::getInstanceMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::instanceMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-MethodList Protocol::getClassMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::classMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-MethodList Protocol::getOptionalInstanceMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::optionalInstanceMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-MethodList Protocol::getOptionalClassMethods(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::optionalClassMethods));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-uint32_t Protocol::getSize(const Visitor& objcVisitor) const
-{
-    return *(uint32_t*)this->getFieldPos(objcVisitor, Field::size);
-}
-
-void Protocol::setSize(const Visitor& objcVisitor, uint32_t size)
-{
-    *(uint32_t*)this->getFieldPos(objcVisitor, Field::size) = size;
-}
-
-void Protocol::setFixedUp(const Visitor& objcVisitor)
-{
-    uint32_t& flags = *(uint32_t*)this->getFieldPos(objcVisitor, Field::flags);
-
-    assert((flags & (1<<30)) == 0);
-    flags = flags | (1<<30);
-}
-
-void Protocol::setIsCanonical(const Visitor& objcVisitor)
-{
-    uint32_t& flags = *(uint32_t*)this->getFieldPos(objcVisitor, Field::flags);
-
-    assert((flags & (1<<29)) == 0);
-    flags = flags | (1<<29);
-}
-
-std::optional<ResolvedValue> Protocol::getExtendedMethodTypes(const Visitor& objcVisitor) const
-{
-    // extendedMethodTypes is not always present on disk.
-    uint32_t structSize = this->getSize(objcVisitor);
-    if ( objcVisitor.pointerSize == 4 ) {
-        if ( structSize < (offsetof(protocol32_t, extendedMethodTypesVMAddr) + sizeof(protocol32_t::extendedMethodTypesVMAddr)) )
-            return std::nullopt;
-    } else {
-        if ( structSize < (offsetof(protocol64_t, extendedMethodTypesVMAddr) + sizeof(protocol64_t::extendedMethodTypesVMAddr)) )
-            return std::nullopt;
-    }
-
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::extendedMethodTypes));
-    return objcVisitor.resolveOptionalRebase(field);
-}
-
-std::optional<const char*> Protocol::getDemangledName(const Visitor& objcVisitor) const
-{
-    // demangledName is not always present on disk.
-    uint32_t structSize = this->getSize(objcVisitor);
-    if ( objcVisitor.pointerSize == 4 ) {
-        if ( structSize < (offsetof(protocol32_t, demangledNameVMAddr) + sizeof(protocol32_t::demangledNameVMAddr)) )
-            return std::nullopt;
-    } else {
-        if ( structSize < (offsetof(protocol64_t, demangledNameVMAddr) + sizeof(protocol64_t::demangledNameVMAddr)) )
-            return std::nullopt;
-    }
-
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::demangledName));
-    std::optional<ResolvedValue> value = objcVisitor.resolveOptionalRebase(field);
-    if ( value.has_value() )
-        return (const char*)value->value();
-
-    return std::nullopt;
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Protocol::setDemangledName(const Visitor& objcVisitor, VMAddress vmAddr)
-{
-    uint32_t structSize = this->getSize(objcVisitor);
-    if ( objcVisitor.pointerSize == 4 ) {
-        assert(structSize >= (offsetof(protocol32_t, demangledNameVMAddr) + sizeof(protocol32_t::demangledNameVMAddr)));
-    } else {
-        assert(structSize >= (offsetof(protocol64_t, demangledNameVMAddr) + sizeof(protocol64_t::demangledNameVMAddr)));
-    }
-
-    ResolvedValue field = objcVisitor.getField(this->protocolPos, this->getFieldPos(objcVisitor, Field::demangledName));
-    objcVisitor.updateTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()));
-}
-#endif
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Protocol::addFixups(const Visitor& objcVisitor, std::vector<void*>& fixups) const
-{
-
-    if ( objcVisitor.pointerSize == 4 ) {
-        protocol32_t* protocol = (protocol32_t*)this->protocolPos.value();
-        if ( protocol->isaVMAddr != 0 )
-            fixups.push_back(&protocol->isaVMAddr);
-        if ( protocol->nameVMAddr != 0 )
-            fixups.push_back(&protocol->nameVMAddr);
-        if ( protocol->protocolsVMAddr != 0 )
-            fixups.push_back(&protocol->protocolsVMAddr);
-        if ( protocol->instanceMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->instanceMethodsVMAddr);
-        if ( protocol->classMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->classMethodsVMAddr);
-        if ( protocol->optionalInstanceMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->optionalInstanceMethodsVMAddr);
-        if ( protocol->optionalClassMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->optionalClassMethodsVMAddr);
-        if ( protocol->instancePropertiesVMAddr != 0 )
-            fixups.push_back(&protocol->instancePropertiesVMAddr);
-
-        uint32_t structSize = ((const protocol32_t*)this->protocolPos.value())->size;
-        if ( structSize >= (offsetof(protocol32_t, extendedMethodTypesVMAddr) + sizeof(protocol32_t::extendedMethodTypesVMAddr)) ) {
-            if ( protocol->extendedMethodTypesVMAddr != 0 )
-                fixups.push_back(&protocol->extendedMethodTypesVMAddr);
-        }
-        if ( structSize >= (offsetof(protocol32_t, demangledNameVMAddr) + sizeof(protocol32_t::demangledNameVMAddr)) ) {
-            if ( protocol->demangledNameVMAddr != 0 )
-                fixups.push_back(&protocol->demangledNameVMAddr);
-        }
-        if ( structSize >= (offsetof(protocol32_t, classPropertiesVMAddr) + sizeof(protocol32_t::classPropertiesVMAddr)) ) {
-            if ( protocol->classPropertiesVMAddr != 0 )
-                fixups.push_back(&protocol->classPropertiesVMAddr);
-        }
-    } else {
-        protocol64_t* protocol = (protocol64_t*)this->protocolPos.value();
-        if ( protocol->isaVMAddr != 0 )
-            fixups.push_back(&protocol->isaVMAddr);
-        if ( protocol->nameVMAddr != 0 )
-            fixups.push_back(&protocol->nameVMAddr);
-        if ( protocol->protocolsVMAddr != 0 )
-            fixups.push_back(&protocol->protocolsVMAddr);
-        if ( protocol->instanceMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->instanceMethodsVMAddr);
-        if ( protocol->classMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->classMethodsVMAddr);
-        if ( protocol->optionalInstanceMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->optionalInstanceMethodsVMAddr);
-        if ( protocol->optionalClassMethodsVMAddr != 0 )
-            fixups.push_back(&protocol->optionalClassMethodsVMAddr);
-        if ( protocol->instancePropertiesVMAddr != 0 )
-            fixups.push_back(&protocol->instancePropertiesVMAddr);
-
-        uint32_t structSize = ((const protocol64_t*)this->protocolPos.value())->size;
-        if ( structSize >= (offsetof(protocol64_t, extendedMethodTypesVMAddr) + sizeof(protocol64_t::extendedMethodTypesVMAddr)) ) {
-            if ( protocol->extendedMethodTypesVMAddr != 0 )
-                fixups.push_back(&protocol->extendedMethodTypesVMAddr);
-        }
-        if ( structSize >= (offsetof(protocol64_t, demangledNameVMAddr) + sizeof(protocol64_t::demangledNameVMAddr)) ) {
-            if ( protocol->demangledNameVMAddr != 0 )
-                fixups.push_back(&protocol->demangledNameVMAddr);
-        }
-        if ( structSize >= (offsetof(protocol64_t, classPropertiesVMAddr) + sizeof(protocol64_t::classPropertiesVMAddr)) ) {
-            if ( protocol->classPropertiesVMAddr != 0 )
-                fixups.push_back(&protocol->classPropertiesVMAddr);
-        }
-    }
-}
-
-std::optional<uint16_t> Protocol::chainedPointerFormat() const
-{
-    return this->protocolPos.chainedPointerFormat();
-}
-#endif
-
-const void* Protocol::getLocation() const
-{
-    return this->protocolPos.value();
-}
-
-VMAddress Protocol::getVMAddress() const
-{
-    return this->protocolPos.vmAddress();
-}
-
-uint32_t Protocol::getSize(bool is64)
-{
-    return is64 ? sizeof(protocol64_t) : sizeof(protocol32_t);
-}
-
-//
-// MARK: --- MethodList methods ---
-//
-
-uint32_t MethodList::numMethods() const
-{
-    if ( !methodListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    return methodList->getMethodCount();
-}
-
-uint32_t MethodList::listSize() const
-{
-    if ( !methodListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    uint32_t size = sizeof(uint32_t) * 2;
-    size += methodList->getMethodCount() * methodList->getMethodSize();
-    return size;
-}
-
-uint32_t MethodList::methodSize() const
-{
-    if ( !methodListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    return methodList->getMethodSize();
-}
-
-bool MethodList::usesRelativeOffsets() const
-{
-    if ( !methodListPos.has_value() )
-        return false;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    return methodList->usesRelativeOffsets();
-}
-
-bool MethodList::usesOffsetsFromSelectorBuffer() const
-{
-    if ( !methodListPos.has_value() )
-        return false;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    return methodList->usesOffsetsFromSelectorBuffer();
-}
-
-void MethodList::setIsUniqued()
-{
-    if ( !methodListPos.has_value() )
-        return;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    method_list_t* methodList = (method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    methodList->setIsUniqued();
-}
-
-void MethodList::setIsSorted()
-{
-    if ( !methodListPos.has_value() )
-        return;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    method_list_t* methodList = (method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    methodList->setIsSorted();
-}
-
-size_t MethodList::makeEmptyMethodList(void* buffer)
-{
-    assert(buffer != nullptr);
-    method_list_t* methodList = (method_list_t*)buffer;
-    bzero(methodList, sizeof(method_list_t));
-
-    methodList->setIsUniqued();
-    methodList->setIsSorted();
-
-    return sizeof(method_list_t);
-}
-
-void MethodList::setUsesOffsetsFromSelectorBuffer()
-{
-    if ( !methodListPos.has_value() )
-        return;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    method_list_t* methodList = (method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    methodList->setUsesOffsetsFromSelectorBuffer();
-}
-
-bool MethodList::isListOfLists() const
-{
-    if ( !methodListPos.has_value() )
-        return false;
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-    return methodListValue.vmAddress().rawValue() & 1;
-}
-
-const void* MethodList::getLocation() const
-{
-    if ( !this->methodListPos.has_value() )
-        return nullptr;
-    return this->methodListPos->value();
-}
-
-std::optional<VMAddress> MethodList::getVMAddress() const
-{
-    if ( !this->methodListPos.has_value() )
-        return { };
-    return this->methodListPos->vmAddress();
-}
-
-static Method::Kind getKind(const MethodList::method_list_t* methodList)
-{
-    typedef Method::Kind Kind;
-    if ( methodList->usesRelativeOffsets() )
-        return methodList->usesOffsetsFromSelectorBuffer() ? Kind::relativeDirect : Kind::relativeIndirect;
-    else
-        return Kind::pointer;
-}
-
-Method MethodList::getMethod(const Visitor& objcVisitor, uint32_t i) const
-{
-    assert(methodListPos.has_value());
-
-    const ResolvedValue& methodListValue = this->methodListPos.value();
-
-    const method_list_t* methodList = (const method_list_t*)methodListValue.value();
-    assert(methodList != nullptr);
-
-    const uint8_t* methodListBase = methodList->methodBase();
-    const uint8_t* method = methodListBase + (i * methodList->getMethodSize());
-
-    ResolvedValue methodValue = objcVisitor.getField(methodListValue, method);
-
-    return Method(getKind(methodList), methodValue);
-}
-
-//
-// MARK: --- Method methods ---
-//
-
-const void* Method::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const method32_t* method32 = (const method32_t*)this->methodPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &method32->nameVMAddr;
-            case Field::types:
-                return &method32->typesVMAddr;
-            case Field::imp:
-                return &method32->impVMAddr;
-        }
-    } else {
-        const method64_t* method64 = (const method64_t*)this->methodPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &method64->nameVMAddr;
-            case Field::types:
-                return &method64->typesVMAddr;
-            case Field::imp:
-                return &method64->impVMAddr;
-        }
-    }
-}
-
-ResolvedValue Method::getNameField(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            assert(0);
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            return objcVisitor.getField(this->methodPos, this->getFieldPos(objcVisitor, Field::name));
-        }
-    }
-}
-
-ResolvedValue Method::getTypesField(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            assert(0);
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            return objcVisitor.getField(this->methodPos, this->getFieldPos(objcVisitor, Field::types));
-        }
-    }
-}
-
-ResolvedValue Method::getIMPField(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            assert(0);
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            return objcVisitor.getField(this->methodPos, this->getFieldPos(objcVisitor, Field::imp));
-        }
-    }
-}
-
-const char* Method::getName(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            // The uint32_t name field is an offset from itself to a selref.  The selref then points to the selector string
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, nameOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress nameSelRefVMAddr = methodVMAddr + relativeOffsetFromMethod;
-
-            ResolvedValue nameSelRefValue = objcVisitor.getValueFor(nameSelRefVMAddr);
-            return (const char*)objcVisitor.resolveRebase(nameSelRefValue).value();
-        }
-        case Kind::relativeDirect: {
-#if BUILDING_SHARED_CACHE_UTIL
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            uint32_t nameOffsetInBuffer = *(uint32_t*)fieldPos;
-
-            VMAddress nameVMAddr = objcVisitor.sharedCacheSelectorStringsBaseAddress() + VMOffset((uint64_t)nameOffsetInBuffer);
-            ResolvedValue nameValue = objcVisitor.getValueFor(nameVMAddr);
-            return (const char*)nameValue.value();
-#else
-            // dyld should never walk direct methods as the objc closure optimizations skip cache dylibs
-            assert(0);
-#endif
-        }
-        case Kind::pointer: {
-            ResolvedValue nameField = this->getNameField(objcVisitor);
-            return (const char*)objcVisitor.resolveRebase(nameField).value();
-        }
-    }
-}
-
-const char* Method::getTypes(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->typesOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, typesOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress typeVMAddr = methodVMAddr + relativeOffsetFromMethod;
-
-            ResolvedValue typeValue = objcVisitor.getValueFor(typeVMAddr);
-            return (const char*)typeValue.value();
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            ResolvedValue typesField = this->getTypesField(objcVisitor);
-            return (const char*)objcVisitor.resolveRebase(typesField).value();
-        }
-    }
-}
-
-const void* Method::getIMP(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->impOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, impOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress impVMAddr = methodVMAddr + relativeOffsetFromMethod;
-
-            ResolvedValue impValue = objcVisitor.getValueFor(impVMAddr);
-            return (const char*)impValue.value();
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            ResolvedValue impField = this->getIMPField(objcVisitor);
-            return (const char*)objcVisitor.resolveRebase(impField).value();
-        }
-    }
-}
-
-// Get the selector string name.  A method often indirects via a selector reference.  This returns
-// the vmAddr of the final selector string, not the selector reference.
-VMAddress Method::getNameVMAddr(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            // The uint32_t name field is an offset from itself to a selref.  The selref then points to the selector string
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, nameOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress nameSelRefVMAddr = methodVMAddr + relativeOffsetFromMethod;
-
-            ResolvedValue nameSelRefValue = objcVisitor.getValueFor(nameSelRefVMAddr);
-            return objcVisitor.resolveRebase(nameSelRefValue).vmAddress();
-        }
-        case Kind::relativeDirect: {
-#if BUILDING_DYLD || BUILDING_CLOSURE_UTIL || BUILDING_UNIT_TESTS
-            // dyld should never walk direct methods as the objc closure optimizations skip cache dylibs
-            assert(0);
-#else
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            uint32_t nameOffsetInBuffer = *(uint32_t*)fieldPos;
-
-            return objcVisitor.sharedCacheSelectorStringsBaseAddress() + VMOffset((uint64_t)nameOffsetInBuffer);
-#endif
-        }
-        case Kind::pointer: {
-            ResolvedValue nameSelRefValue = this->getNameField(objcVisitor);
-            return objcVisitor.resolveRebase(nameSelRefValue).vmAddress();
-        }
-    }
-}
-
-VMAddress Method::getTypesVMAddr(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect:
-        case Kind::relativeDirect: {
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->typesOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, typesOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress typeVMAddr = methodVMAddr + relativeOffsetFromMethod;
-            return typeVMAddr;
-        }
-        case Kind::pointer: {
-            ResolvedValue typesRefValue = this->getTypesField(objcVisitor);
-            return objcVisitor.resolveRebase(typesRefValue).vmAddress();
-        }
-    }
-}
-
-std::optional<VMAddress> Method::getIMPVMAddr(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect:
-        case Kind::relativeDirect:  {
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->impOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-
-            // protocols have null impls
-            if ( relativeOffsetFromField == 0 )
-                return std::nullopt;
-
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, impOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress impVMAddr = methodVMAddr + relativeOffsetFromMethod;
-            return impVMAddr;
-        }
-        case Kind::pointer: {
-            ResolvedValue impRefValue = this->getIMPField(objcVisitor);
-            return objcVisitor.resolveOptionalRebaseToVMAddress(impRefValue);
-        }
-    }
-}
-
-// Get the selector string name.  A method often indirects via a selector reference.  This returns
-// the vmAddr of the selector reference, not the final selector string
-VMAddress Method::getNameSelRefVMAddr(const Visitor& objcVisitor) const
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            // The uint32_t name field is an offset from itself to a selref.  The selref then points to the selector string
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            int32_t relativeOffsetFromField = *(int32_t*)fieldPos;
-            VMOffset relativeOffsetFromMethod((uint64_t)offsetof(relative_method_t, nameOffset) + relativeOffsetFromField);
-
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress nameSelRefVMAddr = methodVMAddr + relativeOffsetFromMethod;
-
-            ResolvedValue nameSelRefValue = objcVisitor.getValueFor(nameSelRefVMAddr);
-            return nameSelRefValue.vmAddress();
-        }
-        case Kind::relativeDirect: {
-            assert(0);
-        }
-        case Kind::pointer: {
-            assert(0);
-        }
-    }
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Method::setName(const Visitor& objcVisitor, VMAddress nameVMAddr)
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            assert(0);
-        }
-        case Kind::relativeDirect: {
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-
-            VMOffset nameOffsetInBuffer = nameVMAddr - objcVisitor.sharedCacheSelectorStringsBaseAddress();
-            uint64_t relativeOffset = (uint64_t)nameOffsetInBuffer.rawValue();
-
-            assert((uint32_t)relativeOffset == relativeOffset);
-            *(uint32_t*)fieldPos = (uint32_t)relativeOffset;
-            break;
-        }
-        case Kind::pointer: {
-            ResolvedValue selRefValue = this->getNameField(objcVisitor);
-            objcVisitor.updateTargetVMAddress(selRefValue, CacheVMAddress(nameVMAddr.rawValue()));
-        }
-    }
-}
-
-void Method::setTypes(const Visitor& objcVisitor, VMAddress typesVMAddr)
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect:
-        case Kind::relativeDirect: {
-            VMAddress methodVMAddr = this->methodPos.vmAddress();
-            VMAddress typesFieldVMAddr = methodVMAddr + VMOffset((uint64_t)offsetof(relative_method_t, typesOffset));
-
-            VMOffset typesRelativeOffset = typesVMAddr - typesFieldVMAddr;
-            int64_t relativeOffset = (int64_t)typesRelativeOffset.rawValue();
-
-            const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->typesOffset;
-            assert((int32_t)relativeOffset == relativeOffset);
-            *(int32_t*)fieldPos = (int32_t)relativeOffset;
-            break;
-        }
-        case Kind::pointer: {
-            ResolvedValue refValue = this->getTypesField(objcVisitor);
-            objcVisitor.updateTargetVMAddress(refValue, CacheVMAddress(typesVMAddr.rawValue()));
-        }
-    }
-}
-
-void Method::setIMP(const Visitor& objcVisitor, std::optional<VMAddress> impVMAddr)
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect:
-        case Kind::relativeDirect: {
-            if ( !impVMAddr.has_value() ) {
-                // A NULL imp is probably a protocol, and is expected.  Every other IMP in the
-                // protocol is also going to be NULL, so just make sure this one matches
-                assert(!this->getIMPVMAddr(objcVisitor).has_value());
-            } else {
-                VMAddress methodVMAddr = this->methodPos.vmAddress();
-                VMAddress impFieldVMAddr = methodVMAddr + VMOffset((uint64_t)offsetof(relative_method_t, impOffset));
-
-                VMOffset impRelativeOffset = impVMAddr.value() - impFieldVMAddr;
-                int64_t relativeOffset = (int64_t)impRelativeOffset.rawValue();
-
-                const uint8_t* fieldPos = (const uint8_t*)&((const relative_method_t*)this->methodPos.value())->impOffset;
-                assert((int32_t)relativeOffset == relativeOffset);
-                *(int32_t*)fieldPos = (int32_t)relativeOffset;
-            }
-            break;
-        }
-        case Kind::pointer: {
-            if ( !impVMAddr.has_value() ) {
-                // A NULL imp is probably a protocol, and is expected.  Every other IMP in the
-                // protocol is also going to be NULL, so just make sure this one matches
-                assert(!this->getIMPVMAddr(objcVisitor).has_value());
-            } else {
-                ResolvedValue refValue = this->getIMPField(objcVisitor);
-                objcVisitor.updateTargetVMAddress(refValue, CacheVMAddress(impVMAddr->rawValue()));
-            }
-        }
-    }
-}
-#endif
-
-void Method::convertNameToOffset(const Visitor& objcVisitor, uint32_t nameOffset)
-{
-    switch ( this->kind ) {
-        case Kind::relativeIndirect: {
-            // We are always looking at an indirect method when converting a name to an offset
-            uint8_t* fieldPos = (uint8_t*)&((const relative_method_t*)this->methodPos.value())->nameOffset;
-            *(uint32_t*)fieldPos = (uint32_t)nameOffset;
-
-            // FIXME: Should we convert the kind field on this method to relativeDirect?
-            break;
-        }
-        case Kind::relativeDirect: {
-            // This shouldn't happen
-            assert(0);
-        }
-        case Kind::pointer: {
-            // This shouldn't happen
-            assert(0);
-        }
-    }
-}
-
-uint32_t Method::getSize(bool is64)
-{
-    return is64 ? sizeof(method64_t) : sizeof(method32_t);
-}
-
-//
-// MARK: --- IVarList methods ---
-//
-
-uint32_t IVarList::numIVars() const
-{
-    if ( !ivarListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& ivarListValue = this->ivarListPos.value();
-
-    const ivar_list_t* ivarList = (const ivar_list_t*)ivarListValue.value();
-    assert(ivarList != nullptr);
-
-    return ivarList->getCount();
-}
-
-IVar IVarList::getIVar(const Visitor& objcVisitor, uint32_t i) const
-{
-    assert(ivarListPos.has_value());
-
-    const ResolvedValue& ivarListValue = this->ivarListPos.value();
-
-    const ivar_list_t* ivarList = (const ivar_list_t*)ivarListValue.value();
-    assert(ivarList != nullptr);
-
-    const uint8_t* ivarListBase = ivarList->ivarBase();
-    const uint8_t* ivar = ivarListBase + (i * ivarList->getElementSize());
-
-    ResolvedValue ivarValue = objcVisitor.getField(ivarListValue, ivar);
-    return IVar(ivarValue);
-}
-
-#if BUILDING_CACHE_BUILDER_UNIT_TESTS
-const void* IVarList::getLocation() const
-{
-    if ( !this->ivarListPos.has_value() )
-        return nullptr;
-    return this->ivarListPos->value();
-}
-
-std::optional<VMAddress> IVarList::getVMAddress() const
-{
-    return this->ivarListPos->vmAddress();
-}
-#endif
-
-//
-// MARK: --- PropertyList methods ---
-//
-uint32_t PropertyList::numProperties() const
-{
-    if ( !this->propertyListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& propertyListValue = this->propertyListPos.value();
-
-    const property_list_t* propertyList = (const property_list_t*)propertyListValue.value();
-    assert(propertyList != nullptr);
-
-    return propertyList->getCount();
-}
-
-Property PropertyList::getProperty(const Visitor& objcVisitor, uint32_t i) const
-{
-    assert(this->propertyListPos.has_value());
-
-    const ResolvedValue& propertyListValue = this->propertyListPos.value();
-
-    const property_list_t* propertyList = (const property_list_t*)propertyListValue.value();
-    assert(propertyList != nullptr);
-
-    const uint8_t* propertyListBase = propertyList->propertyBase();
-    const uint8_t* property = propertyListBase + (i * propertyList->getElementSize());
-
-    ResolvedValue propertyValue = objcVisitor.getField(propertyListValue, property);
-    return Property(propertyValue);
-}
-
-const void* PropertyList::getLocation() const
-{
-    if ( !this->propertyListPos.has_value() )
-        return nullptr;
-    return this->propertyListPos->value();
-}
-
-std::optional<VMAddress> PropertyList::getVMAddress() const
-{
-    if ( !this->propertyListPos.has_value() )
-        return { };
-    return this->propertyListPos->vmAddress();
-}
-
-bool PropertyList::isListOfLists() const
-{
-    if ( !propertyListPos.has_value() )
-        return false;
-
-    const ResolvedValue& propertyListValue = this->propertyListPos.value();
-    return propertyListValue.vmAddress().rawValue() & 1;
-}
-
-//
-// MARK: --- ProtocolList methods ---
-//
-
-uint64_t ProtocolList::numProtocols(const Visitor& objcVisitor) const
-{
-    if ( !this->protocolListPos.has_value() )
-        return 0;
-
-    const ResolvedValue& protocolListValue = this->protocolListPos.value();
-    const void* protocolList = protocolListValue.value();
-    assert(protocolList != nullptr);
-
-    if ( objcVisitor.pointerSize == 4 ) {
-        return ((const protocol_list32_t*)protocolList)->count;
-    } else {
-        return ((const protocol_list64_t*)protocolList)->count;
-    }
-}
-
-ResolvedValue ProtocolList::getProtocolField(const Visitor& objcVisitor, uint64_t i) const
-{
-    assert(this->protocolListPos.has_value());
-    assert(i < this->numProtocols(objcVisitor));
-
-    const ResolvedValue& protocolListValue = this->protocolListPos.value();
-    const void* protocolList = protocolListValue.value();
-    assert(protocolList != nullptr);
-
-    const void* protocolFixupLoc = nullptr;
-    if ( objcVisitor.pointerSize == 4 ) {
-        protocolFixupLoc = &((const protocol_list32_t*)protocolList)->list[i];
-    } else {
-        protocolFixupLoc = &((const protocol_list64_t*)protocolList)->list[i];
-    }
-
-    return objcVisitor.getField(protocolListValue, protocolFixupLoc);
-}
-
-Protocol ProtocolList::getProtocol(const Visitor& objcVisitor, uint64_t i) const
-{
-    ResolvedValue field = this->getProtocolField(objcVisitor, i);
-    ResolvedValue protocolValue = objcVisitor.resolveRebase(field);
-    return Protocol(protocolValue);
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void ProtocolList::setProtocol(const Visitor& objcVisitor, uint64_t i, VMAddress vmAddr)
-{
-    ResolvedValue field = this->getProtocolField(objcVisitor, i);
-    objcVisitor.updateTargetVMAddress(field, CacheVMAddress(vmAddr.rawValue()));
-}
-#endif
-
-const void* ProtocolList::getLocation() const
-{
-    if ( !this->protocolListPos.has_value() )
-        return nullptr;
-    return this->protocolListPos->value();
-}
-
-std::optional<VMAddress> ProtocolList::getVMAddress() const
-{
-    if ( !this->protocolListPos.has_value() )
-        return { };
-    return this->protocolListPos->vmAddress();
-}
-
-bool ProtocolList::isListOfLists() const
-{
-    if ( !protocolListPos.has_value() )
-        return false;
-
-    const ResolvedValue& protocolListValue = this->protocolListPos.value();
-    return protocolListValue.vmAddress().rawValue() & 1;
-}
-
-
-void ProtocolList::dump(const Visitor& objcVisitor) const
-{
-    if ( !this->protocolListPos.has_value() ) {
-        fprintf(stdout, "no value\n");
-        return;
-    }
-
-    const ResolvedValue& protocolListValue = this->protocolListPos.value();
-    uint64_t count = this->numProtocols(objcVisitor);
-    fprintf(stdout, "Protocol list (count %lld): vmAddr 0x%llx at %p\n",
-            count, protocolListValue.vmAddress().rawValue(), protocolListValue.value());
-    for ( uint64_t i = 0; i != count; ++i ) {
-        Protocol objCProtocol = this->getProtocol(objcVisitor, i);
-        fprintf(stdout, "  Protocol[%lld]: vmAddr 0x%llx at %p\n", i,
-                objCProtocol.getVMAddress().rawValue(),
-                objCProtocol.getLocation());
-    }
-}
-
-//
-// MARK: --- IVar methods ---
-//
-
-const void* IVar::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const ivar32_t* ivar32 = (const ivar32_t*)this->ivarPos.value();
-        switch ( field ) {
-            case Field::offset:
-                return &ivar32->offsetVMAddr;
-            case Field::name:
-                return &ivar32->nameVMAddr;
-            case Field::type:
-                return &ivar32->typeVMAddr;
-            case Field::alignment:
-                return &ivar32->alignment;
-            case Field::size:
-                return &ivar32->size;
-        }
-    } else {
-        const ivar64_t* ivar64 = (const ivar64_t*)this->ivarPos.value();
-        switch ( field ) {
-            case Field::offset:
-                return &ivar64->offsetVMAddr;
-            case Field::name:
-                return &ivar64->nameVMAddr;
-            case Field::type:
-                return &ivar64->typeVMAddr;
-            case Field::alignment:
-                return &ivar64->alignment;
-            case Field::size:
-                return &ivar64->size;
-        }
-    }
-}
-
-std::optional<uint32_t> IVar::getOffset(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->ivarPos, this->getFieldPos(objcVisitor, Field::offset));
-
-    // The offset might not be set, if it points to 0
-    std::optional<ResolvedValue> targetValue = objcVisitor.resolveOptionalRebase(field);
-    if ( targetValue.has_value() )
-        return *(uint32_t*)targetValue->value();
-
-    return std::nullopt;
-}
-
-void IVar::setOffset(const Visitor& objcVisitor, uint32_t offset) const
-{
-    ResolvedValue field = objcVisitor.getField(this->ivarPos, this->getFieldPos(objcVisitor, Field::offset));
-    ResolvedValue targetValue = objcVisitor.resolveRebase(field);
-    *(uint32_t*)targetValue.value() = offset;
-}
-
-const char* IVar::getName(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->ivarPos, this->getFieldPos(objcVisitor, Field::name));
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-uint32_t IVar::getAlignment(const Visitor& objcVisitor) const
-{
-    return *(uint32_t*)this->getFieldPos(objcVisitor, Field::alignment);
-}
-
-bool IVar::elided(const Visitor& objcVisitor) const
-{
-    uint32_t size = *(uint32_t*)this->getFieldPos(objcVisitor, Field::size);
-    // swift can optimize away ivars.  It leaves the meta data about them, but they have no ivar offset to update
-    return (size == 0);
-}
-
-//
-// MARK: --- Property methods ---
-//
-
-const void* Property::getFieldPos(const Visitor& objcVisitor, Field field) const
-{
-    if ( objcVisitor.pointerSize == 4 ) {
-        const property32_t* property32 = (const property32_t*)this->propertyPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &property32->nameVMAddr;
-            case Field::attributes:
-                return &property32->attributesVMAddr;
-        }
-    } else {
-        const property64_t* property64 = (const property64_t*)this->propertyPos.value();
-        switch ( field ) {
-            case Field::name:
-                return &property64->nameVMAddr;
-            case Field::attributes:
-                return &property64->attributesVMAddr;
-        }
-    }
-}
-
-const char* Property::getName(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->propertyPos, this->getFieldPos(objcVisitor, Field::name));
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-const char* Property::getAttributes(const Visitor& objcVisitor) const
-{
-    ResolvedValue field = objcVisitor.getField(this->propertyPos, this->getFieldPos(objcVisitor, Field::attributes));
-    return (const char*)objcVisitor.resolveRebase(field).value();
-}
-
-//
-// MARK: --- Visitor::Section methods ---
-//
-
-std::optional<Visitor::Section> Visitor::findSection(std::span<const char*> altSegNames, const char *sectionName) const
-{
-#if SUPPORT_VM_LAYOUT
-    const dyld3::MachOFile* mf = this->dylibMA;
-#else
-    const dyld3::MachOFile* mf = this->dylibMF;
-#endif
-
-    __block std::optional<Visitor::Section> objcDataSection;
-    ((const Header*)mf)->forEachSection(^(const Header::SegmentInfo& segInfo, const Header::SectionInfo& sectInfo, bool& stop) {
-        bool segMatch = std::any_of(altSegNames.begin(), altSegNames.end(), [&sectInfo](const char* segName) {
-            return sectInfo.segmentName == segName;
-        });
-        if ( !segMatch )
-            return;
-        if ( sectInfo.sectionName != sectionName )
-            return;
-
-#if SUPPORT_VM_LAYOUT
-        const void* targetValue = (const void*)(sectInfo.address + this->dylibMA->getSlide());
-        ResolvedValue target(targetValue, VMAddress(sectInfo.address));
-#else
-        VMOffset offsetInSegment(sectInfo.address - segInfo.vmaddr);
-        ResolvedValue target(this->segments[sectInfo.segIndex], offsetInSegment);
-#endif
-        objcDataSection.emplace(std::move(target), sectInfo.size);
-
-        stop = true;
-    });
-    return objcDataSection;
-}
-
-std::optional<Visitor::Section> Visitor::findObjCDataSection(const char *sectionName) const
-{
-    static const char* objcDataSegments[] = {
-        "__DATA", "__DATA_CONST", "__DATA_DIRTY"
-    };
-    return findSection(objcDataSegments, sectionName);
-}
-
-std::optional<Visitor::Section> Visitor::findObjCTextSection(const char *sectionName) const
-{
-    static const char* objcTextSegments[] = {
-        "__TEXT"
-    };
-    return findSection(objcTextSegments, sectionName);
-}
-
-//
-// MARK: --- Visitor methods ---
-//
-
-void Visitor::forEachClass(bool visitMetaClasses, const Visitor::Section& classListSection,
-                           void (^callback)(Class& objcClass, bool isMetaClass, bool& stopClass))
-{
-    assert((classListSection.sectSize % pointerSize) == 0);
-    uint64_t numClasses = classListSection.sectSize / pointerSize;
-
-    // Use the segment index to find the corresponding cache segment
-    const ResolvedValue& sectionValue = classListSection.sectionBase;
-    const uint8_t* sectionBase = (const uint8_t*)sectionValue.value();
-    for ( uint64_t classIndex = 0; classIndex != numClasses; ++classIndex ) {
-        const uint8_t* classRefPos = sectionBase + (classIndex * pointerSize);
-
-        ResolvedValue classRefValue = this->getField(sectionValue, classRefPos);
-
-        bool isPatchableClass = false;
-        ResolvedValue classPos = this->resolveBindOrRebase(classRefValue, isPatchableClass);
-
-        Class objcClass(classPos, false, isPatchableClass);
-        bool stopClass = false;
-        callback(objcClass, false, stopClass);
-        if ( stopClass )
-            return;
-
-        // If we don't want the metaclass then skip to the next class
-        if ( !visitMetaClasses)
-            continue;
-
-        bool isPatchableMetaClass = false;
-        ResolvedValue objcClassISA = objcClass.getISA(*this, isPatchableMetaClass);
-        Class objcMetaClass(objcClassISA, true, isPatchableMetaClass);
-        callback(objcMetaClass, true, stopClass);
-        if ( stopClass )
-            return;
-    }
-}
-
-void Visitor::forEachClass(bool visitMetaClasses, void (^callback)(Class& objcClass, bool isMetaClass, bool& stopClass))
-{
-    std::optional<Section> classListSection = this->findObjCDataSection("__objc_classlist");
-    if ( !classListSection.has_value() )
-        return;
-
-    this->forEachClass(visitMetaClasses, classListSection.value(), callback);
-}
-
-void Visitor::forEachClass(void (^callback)(const Class& objcClass, bool& stopClass))
-{
-    auto adaptor = ^(Class& objcClass, bool isMetaClass, bool& stopClass) {
-        callback(objcClass, stopClass);
-    };
-    forEachClass(false, adaptor);
-}
-
-void Visitor::forEachClass(void (^callback)(Class& objcClass, bool& stopClass))
-{
-    auto adaptor = ^(Class& objcClass, bool isMetaClass, bool& stopClass) {
-        callback(objcClass, stopClass);
-    };
-    forEachClass(false, adaptor);
-}
-
-void Visitor::forEachClassAndMetaClass(void (^callback)(const Class& objcClass, bool& stopClass))
-{
-    auto adaptor = ^(Class& objcClass, bool isMetaClass, bool& stopClass) {
-        callback(objcClass, stopClass);
-    };
-    forEachClass(true, adaptor);
-}
-
-void Visitor::forEachClassAndMetaClass(void (^callback)(Class& objcClass, bool& stopClass))
-{
-    auto adaptor = ^(Class& objcClass, bool isMetaClass, bool& stopClass) {
-        callback(objcClass, stopClass);
-    };
-    forEachClass(true, adaptor);
-}
-
-void Visitor::forEachCategory(void (^callback)(const Category& objcCategory, bool& stopCategory))
-{
-    for ( bool isCatlist2 : { false, true }) {
-        const char* listSection = isCatlist2 ? "__objc_catlist2" : "__objc_catlist";
-        std::optional<Section> categoryListSection = findObjCDataSection(listSection);
-        if ( !categoryListSection.has_value() )
-            continue;
-
-        assert((categoryListSection->sectSize % pointerSize) == 0);
-        uint64_t numCategories = categoryListSection->sectSize / pointerSize;
-
-        const ResolvedValue& sectionValue = categoryListSection->sectionBase;
-        const uint8_t* sectionBase = (const uint8_t*)sectionValue.value();
-        for ( uint64_t categoryIndex = 0; categoryIndex != numCategories; ++categoryIndex ) {
-            const uint8_t* categoryRefPos = sectionBase + (categoryIndex * pointerSize);
-            ResolvedValue categoryRefValue = this->getField(sectionValue, categoryRefPos);
-
-            // Follow the category reference to get to the actual category
-            ResolvedValue categoryPos = resolveRebase(categoryRefValue);
-            Category objcCategory(categoryPos, isCatlist2);
-            bool stopCategory = false;
-            callback(objcCategory, stopCategory);
-            if ( stopCategory )
-                break;
-        }
-    }
-}
-
-void Visitor::forEachProtocol(void (^callback)(const Protocol& objcProtocol, bool& stopProtocol))
-{
-    std::optional<Section> protocolListSection = findObjCDataSection("__objc_protolist");
-    if ( !protocolListSection.has_value() )
-        return;
-
-    assert((protocolListSection->sectSize % pointerSize) == 0);
-    uint64_t numCategories = protocolListSection->sectSize / pointerSize;
-
-    const ResolvedValue& sectionValue = protocolListSection->sectionBase;
-    const uint8_t* sectionBase = (const uint8_t*)sectionValue.value();
-    for ( uint64_t protocolIndex = 0; protocolIndex != numCategories; ++protocolIndex ) {
-        const uint8_t* protocolRefPos = sectionBase + (protocolIndex * pointerSize);
-        ResolvedValue protocolRefValue = this->getField(sectionValue, protocolRefPos);
-
-        // Follow the protocol reference to get to the actual protocol
-        ResolvedValue protocolPos = resolveRebase(protocolRefValue);
-        Protocol objcProtocol(protocolPos);
-        bool stopProtocol = false;
-        callback(objcProtocol, stopProtocol);
-        if ( stopProtocol )
-            break;
-    }
-}
-
-void Visitor::forEachSelectorReference(void (^callback)(ResolvedValue& value)) const
-{
-    std::optional<Section> selRefsSection = findObjCDataSection("__objc_selrefs");
-    if ( !selRefsSection.has_value() )
-        return;
-
-    assert((selRefsSection->sectSize % pointerSize) == 0);
-    uint64_t numSelRefs = selRefsSection->sectSize / pointerSize;
-
-    const ResolvedValue& sectionValue = selRefsSection->sectionBase;
-    const uint8_t* sectionBase = (const uint8_t*)sectionValue.value();
-    for ( uint64_t selRefIndex = 0; selRefIndex != numSelRefs; ++selRefIndex ) {
-        const uint8_t* selRefPos = sectionBase + (selRefIndex * pointerSize);
-        ResolvedValue selRefValue = this->getField(sectionValue, selRefPos);
-
-        callback(selRefValue);
-    }
-}
-
-void Visitor::forEachSelectorReference(void (^callback)(VMAddress selRefVMAddr, VMAddress selRefTargetVMAddr,
-                                                            const char* selectorString)) const
-{
-    this->forEachSelectorReference(^(ResolvedValue& selRefValue) {
-        ResolvedValue selRefTarget = this->resolveRebase(selRefValue);
-
-        VMAddress selRefVMAddr = selRefValue.vmAddress();
-        VMAddress selRefTargetVMAddr = selRefTarget.vmAddress();
-        const char* selectorString = (const char*)selRefTarget.value();
-
-        callback(selRefVMAddr, selRefTargetVMAddr, selectorString);
-    });
-}
-
-void Visitor::forEachProtocolReference(void (^callback)(ResolvedValue& value))
-{
-    std::optional<Section> protocolRefsSection = findObjCDataSection("__objc_protorefs");
-    if ( !protocolRefsSection.has_value() )
-        return;
-
-    assert((protocolRefsSection->sectSize % pointerSize) == 0);
-    uint64_t numProtocolRefs = protocolRefsSection->sectSize / pointerSize;
-
-    const ResolvedValue& sectionValue = protocolRefsSection->sectionBase;
-    const uint8_t* sectionBase = (const uint8_t*)sectionValue.value();
-    for ( uint64_t protocolRefIndex = 0; protocolRefIndex != numProtocolRefs; ++protocolRefIndex ) {
-        const uint8_t* protocolRefPos = sectionBase + (protocolRefIndex * pointerSize);
-        ResolvedValue protocolRefValue = this->getField(sectionValue, protocolRefPos);
-
-        callback(protocolRefValue);
-    }
-}
-
-#if BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-void Visitor::forEachMethodList(void (^callback)(MethodList& objcMethodList, std::optional<metadata_visitor::ResolvedValue> extendedMethodTypes))
-{
-    __block std::unordered_set<const void*> visitedLists;
-
-    forEachClassAndMetaClass(^(const objc_visitor::Class& objcClass, bool&) {
-        objc_visitor::MethodList objcMethodList = objcClass.getBaseMethods(*this);
-
-        callback(objcMethodList, std::nullopt);
-        visitedLists.insert(objcMethodList.getLocation());
-    });
-
-    forEachCategory(^(const objc_visitor::Category& objcCategory, bool&) {
-        objc_visitor::MethodList instanceMethodList = objcCategory.getInstanceMethods(*this);
-        objc_visitor::MethodList classMethodList    = objcCategory.getClassMethods(*this);
-
-        callback(instanceMethodList, std::nullopt);
-        visitedLists.insert(instanceMethodList.getLocation());
-
-        callback(classMethodList, std::nullopt);
-        visitedLists.insert(classMethodList.getLocation());
-    });
-
-    forEachProtocol(^(const objc_visitor::Protocol& objcProtocol, bool&) {
-        objc_visitor::MethodList instanceMethodList         = objcProtocol.getInstanceMethods(*this);
-        objc_visitor::MethodList classMethodList            = objcProtocol.getClassMethods(*this);
-        objc_visitor::MethodList optionalInstanceMethodList = objcProtocol.getOptionalInstanceMethods(*this);
-        objc_visitor::MethodList optionalClassMethodList    = objcProtocol.getOptionalClassMethods(*this);
-
-        // This is an optional flat array with entries for all method lists.
-        // Each method list of length N has N char* entries in this list, if its present
-        std::optional<metadata_visitor::ResolvedValue> extendedMethodTypes = objcProtocol.getExtendedMethodTypes(*this);
-        const uint8_t* currentMethodTypes = extendedMethodTypes.has_value() ? (const uint8_t*)extendedMethodTypes->value() : nullptr;
-
-        callback(instanceMethodList, extendedMethodTypes);
-        visitedLists.insert(instanceMethodList.getLocation());
-        if ( extendedMethodTypes.has_value() ) {
-            currentMethodTypes += (instanceMethodList.numMethods() * pointerSize);
-            extendedMethodTypes.emplace(metadata_visitor::ResolvedValue(extendedMethodTypes.value(), currentMethodTypes));
-        }
-
-        callback(classMethodList, extendedMethodTypes);
-        visitedLists.insert(classMethodList.getLocation());
-        if ( extendedMethodTypes.has_value() ) {
-            currentMethodTypes += (classMethodList.numMethods() * pointerSize);
-            extendedMethodTypes.emplace(metadata_visitor::ResolvedValue(extendedMethodTypes.value(), currentMethodTypes));
-        }
-
-        callback(optionalInstanceMethodList, extendedMethodTypes);
-        visitedLists.insert(optionalInstanceMethodList.getLocation());
-        if ( extendedMethodTypes.has_value() ) {
-            currentMethodTypes += (optionalInstanceMethodList.numMethods() * pointerSize);
-            extendedMethodTypes.emplace(metadata_visitor::ResolvedValue(extendedMethodTypes.value(), currentMethodTypes));
-        }
-
-        callback(optionalClassMethodList, extendedMethodTypes);
-        visitedLists.insert(optionalClassMethodList.getLocation());
-        if ( extendedMethodTypes.has_value() ) {
-            currentMethodTypes += (optionalClassMethodList.numMethods() * pointerSize);
-            extendedMethodTypes.emplace(metadata_visitor::ResolvedValue(extendedMethodTypes.value(), currentMethodTypes));
-        }
-    });
-
-    // rdar://129304028 (dyld cache builder support for relative method lists in Swift generic classes)
-    // Also scan the entire __objc_methlist section looking for other method lists that
-    // aren't referenced through the regular ObjC metadata.
-    std::optional<Section> methodListSection = findObjCTextSection("__objc_methlist");
-    if ( !methodListSection.has_value() )
-        return;
-    assert((methodListSection->sectSize % 4) == 0);
-
-    const ResolvedValue& sectionValue = methodListSection->sectionBase;
-    const uint8_t* sectionPos = (const uint8_t*)sectionValue.value();
-    const uint8_t* sectionEnd = (const uint8_t*)sectionValue.value() + methodListSection->sectSize;
-
-    while ( sectionPos < sectionEnd ) {
-        ResolvedValue methodListValue = this->getField(sectionValue, sectionPos);
-
-        // method lists are 8-byte alligned, a valid method list can never start
-        // with a 0 because that's where the method size entry and flags are encoded
-        if ( *(uint32_t*)methodListValue.value() == 0 ) {
-            sectionPos += sizeof(uint32_t);
-            continue;
-        }
-
-        MethodList methodList(methodListValue);
-
-        // sanity check entry - all lists in __objc_methlist are relative and
-        // a relative method list entry is 12 bytes large
-        assert(methodList.usesRelativeOffsets() && methodList.methodSize() == 12
-                && "not a relative method list");
-
-        // skip method lists that were visited through classes etc.
-        if ( !visitedLists.contains(methodList.getLocation()) ) {
-            callback(methodList, std::nullopt);
-        }
-
-        uint32_t size = methodList.listSize();
-        assert(size != 0 && "method list can't be empty");
-        sectionPos += size;
-    }
-    assert(sectionPos == sectionEnd && "malformed __objc_methlist section");
-}
-#endif
-
-void Visitor::withImageInfo(void (^callback)(const uint32_t version, const uint32_t flags)) const
-{
-    std::optional<Section> imageInfoSection = findObjCDataSection("__objc_imageinfo");
-    if ( !imageInfoSection.has_value() )
-        return;
-
-    assert((imageInfoSection->sectSize % pointerSize) == 0);
-    const ResolvedValue& sectionValue = imageInfoSection->sectionBase;
-
-    struct objc_image_info {
-        int32_t version;
-        uint32_t flags;
-    };
-    const objc_image_info* sectionBase = (const objc_image_info*)sectionValue.value();
-    callback(sectionBase->version, sectionBase->flags);
-}
-
-#endif // !TARGET_OS_EXCLAVEKIT