Loading...
--- /dev/null
+++ dyld/dyld-1162/cache_builder/SubCache.h
@@ -0,0 +1,324 @@
+/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
+*
+* Copyright (c) 2017 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@
+*/
+
+#ifndef SubCache_hpp
+#define SubCache_hpp
+
+#include "Defines.h"
+#include "Chunk.h"
+#include "MachOFile.h"
+#include "Optimizers.h"
+#include "Types.h"
+
+#include <uuid/uuid.h>
+#include <vector>
+
+namespace cache_builder
+{
+
+struct Region
+{
+ // Note the order of this enum is the order in the final cache binary.
+ // It is sorted to try keep page tables to a minimum, ie, keeping similar regions adjacent
+ enum class Kind : uint32_t
+ {
+ text,
+
+ // Rosetta expects __DATA_CONST after __TEXT, as we currently sort using this enum
+ dataConst,
+
+ data,
+ auth,
+
+ // FIXME: Move this to be after DATA_CONST to reduce page tables
+ // Needs rdar://96315050
+ authConst,
+
+ linkedit,
+ unmapped,
+ dynamicConfig,
+ codeSignature,
+
+ numKinds
+ };
+
+ Region(Kind kind) : kind(kind) { }
+
+ uint32_t initProt() const;
+ uint32_t maxProt() const;
+ bool canContainAuthPointers() const;
+ bool needsSharedCacheMapping() const;
+ bool needsSharedCacheReserveAddressSpace() const;
+
+ bool needsRegionPadding(const Region& next) const;
+
+ Kind kind;
+
+ // The chunks from dylibs, optimzations, etc, which make up this Region
+ std::vector<Chunk*> chunks;
+
+ CacheFileOffset subCacheFileOffset;
+ CacheFileSize subCacheFileSize;
+ CacheVMAddress subCacheVMAddress;
+ CacheVMSize subCacheVMSize;
+ uint8_t* subCacheBuffer = nullptr;
+};
+
+struct SubCache
+{
+private:
+ enum class Kind
+ {
+ mainDevelopment,
+ stubsDevelopment,
+
+ mainCustomer,
+ stubsCustomer,
+
+ // If we aren't the main cache, or a stubs cache, then the remainder is a universal "sub" cache
+ // which is typically TEXT/DATA/LINKEDIT
+ subUniversal,
+
+ symbols
+ };
+
+ SubCache(Kind kind);
+
+public:
+ SubCache() = delete;
+ ~SubCache() = default;
+ SubCache(const SubCache&) = delete;
+ SubCache& operator=(const SubCache&) = delete;
+ SubCache(SubCache&&) = default;
+ SubCache& operator=(SubCache&&) = default;
+
+ // Helper methods to build the various kinds of subCache
+ static SubCache makeMainCache(const BuilderOptions& options, bool isDevelopment);
+ static SubCache makeSubCache(const BuilderOptions& options);
+ static SubCache makeStubsCache(const BuilderOptions& options, bool isDevelopment);
+ static SubCache makeSymbolsCache();
+
+ // These methods are called by computeSubCaches() to add Chunk's to the subCache
+ void addDylib(CacheDylib& cacheDylib, bool addLinkedit);
+ void addLinkeditFromDylib(CacheDylib& cacheDylib);
+ void addCacheHeaderChunk(const std::span<CacheDylib> cacheDylibs);
+ void addObjCHeaderInfoReadWriteChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer);
+ void addCodeSignatureChunk();
+ void addObjCOptsHeaderChunk(ObjCOptimizer& objcOptimizer);
+ void addObjCHeaderInfoReadOnlyChunk(ObjCOptimizer& objcOptimizer);
+ void addObjCImageInfoChunk(ObjCOptimizer& objcOptimizer);
+ void addObjCSelectorStringsChunk(ObjCSelectorOptimizer& objCSelectorOptimizer);
+ void addObjCSelectorHashTableChunk(ObjCSelectorOptimizer& objCSelectorOptimizer);
+ void addObjCClassNameStringsChunk(ObjCClassOptimizer& objcClassOptimizer);
+ void addObjCClassHashTableChunk(ObjCClassOptimizer& objcClassOptimizer);
+ void addObjCProtocolNameStringsChunk(ObjCProtocolOptimizer& objcProtocolOptimizer);
+ void addObjCProtocolHashTableChunk(ObjCProtocolOptimizer& objcProtocolOptimizer);
+ void addObjCProtocolSwiftDemangledNamesChunk(ObjCProtocolOptimizer& objcProtocolOptimizer);
+ void addObjCCanonicalProtocolsChunk(const BuilderConfig& config,
+ ObjCProtocolOptimizer& objcProtocolOptimizer);
+ void addObjCCategoriesChunk(const BuilderConfig& config,
+ ObjCCategoryOptimizer& objcCategoryOptimizer);
+ void addObjCIMPCachesChunk(ObjCIMPCachesOptimizer& objcIMPCachesOptimizer);
+ void addCacheTrieChunk(DylibTrieOptimizer& dylibTrieOptimizer);
+ void addPatchTableChunk(PatchTableOptimizer& patchTableOptimizer);
+ void addCacheDylibsLoaderChunk(PrebuiltLoaderBuilder& builder);
+ void addExecutableLoaderChunk(PrebuiltLoaderBuilder& builder);
+ void addExecutablesTrieChunk(PrebuiltLoaderBuilder& builder);
+ void addSwiftOptsHeaderChunk(SwiftProtocolConformanceOptimizer& opt);
+ void addSwiftTypeHashTableChunk(SwiftProtocolConformanceOptimizer& opt);
+ void addSwiftMetadataHashTableChunk(SwiftProtocolConformanceOptimizer& opt);
+ void addSwiftForeignHashTableChunk(SwiftProtocolConformanceOptimizer& opt);
+ void addUnmappedSymbols(const BuilderConfig& config, UnmappedSymbolsOptimizer& opt);
+ void addDynamicConfigChunk();
+ void addSlideInfoChunks();
+ void removeEmptyRegions();
+
+ // When "kind == sub", sets the suffix on this subCache
+ // This has to be done after creating things like stubs sub caches, which might move the indices
+ void setSuffix(dyld3::Platform platform, bool forceDevelopmentSubCacheSuffix,
+ size_t subCacheIndex);
+
+ void setCodeSignatureSize(const BuilderOptions& options, const BuilderConfig& config,
+ CacheFileSize estimatedSize);
+
+ error::Error computeSlideInfo(const BuilderConfig& config);
+
+ // Emits a dyld_cache_header for this subCache
+ void writeCacheHeader(const BuilderOptions& options, const BuilderConfig& config,
+ const std::span<CacheDylib> cacheDylibs);
+
+ // Adds any additional fields which are set only on the main subCache(s)
+ void addMainCacheHeaderInfo(const BuilderOptions& options, const BuilderConfig& config,
+ const std::span<CacheDylib> cacheDylibs,
+ CacheVMSize totalVMSize, uint64_t maxSlide,
+ uint32_t osVersion, uint32_t altPlatform, uint32_t altOsVersion,
+ CacheVMAddress dyldInCacheUnslidAddr,
+ CacheVMAddress dyldInCacheEntryUnslidAddr,
+ const DylibTrieOptimizer& dylibTrieOptimizer,
+ const ObjCOptimizer& objcOpt,
+ const SwiftProtocolConformanceOptimizer& swiftProtocolConformanceOpt,
+ const PatchTableOptimizer& patchTableOptimizer,
+ const PrebuiltLoaderBuilder& prebuiltLoaderBuilder);
+
+ // Adds any additional fields which are set only on the .symbols subCache
+ void addSymbolsCacheHeaderInfo(const UnmappedSymbolsOptimizer& unmappedSymbolsOptimizer);
+
+ void codeSign(Diagnostics& diag, const BuilderOptions& options, const BuilderConfig& config);
+
+ bool isMainCache() const;
+ bool isMainDevelopmentCache() const;
+ bool isMainCustomerCache() const;
+ bool isSubCache() const;
+ bool isStubsCache() const;
+ bool isStubsDevelopmentCache() const;
+ bool isStubsCustomerCache() const;
+ bool isSymbolsCache() const;
+
+ void addStubsChunk(Chunk* chunk);
+
+ bool shouldKeepCache(bool keepDevelopmentCaches, bool keepCustomerCaches) const;
+
+#if BUILDING_CACHE_BUILDER_UNIT_TESTS
+ // We need everything public to write tests
+public:
+#else
+private:
+#endif
+
+ // Adds the given chunk to the given region
+ void addTextChunk(Chunk* chunk);
+ void addDataChunk(Chunk* chunk);
+ void addDataConstChunk(Chunk* chunk);
+ void addAuthChunk(Chunk* chunk);
+ void addAuthConstChunk(Chunk* chunk);
+ void addLinkeditChunk(Chunk* chunk);
+ void addUnmappedChunk(Chunk* chunk);
+ void addCodeSignatureChunk(Chunk* chunk);
+ void addObjCTextChunk(Chunk* chunk);
+ void addObjCReadOnlyChunk(Chunk* chunk);
+ void addObjCReadWriteChunk(const BuilderConfig& config, Chunk* chunk);
+
+ // Returns true if the cache header on this subCache needs an image list
+ // The symbols cache and stubs caches, for example, don't need this
+ bool needsCacheHeaderImageList() const;
+
+ // Add image info to the subCache header, if it needs it
+ void addCacheHeaderImageInfo(const BuilderOptions& options,
+ const std::span<CacheDylib> cacheDylibs);
+
+ static uint64_t getCacheType(const BuilderOptions& options);
+ uint32_t getCacheSubType() const;
+ void writeCacheHeaderMappings();
+
+ static error::Error convertChainsToVMAddresses(const BuilderConfig& config, Region& region);
+ static error::Error computeSlideInfoV1(const BuilderConfig& config,
+ SlideInfoChunk* slideChunk,
+ Region& region);
+ static error::Error computeSlideInfoV2(const BuilderConfig& config,
+ SlideInfoChunk* slideChunk,
+ Region& region);
+ static error::Error computeSlideInfoV3(const BuilderConfig& config,
+ SlideInfoChunk* slideChunk,
+ Region& region);
+ static error::Error computeSlideInfoV5(const BuilderConfig& config,
+ SlideInfoChunk* slideChunk,
+ Region& region);
+ static error::Error computeSlideInfoForRegion(const BuilderConfig& config,
+ SlideInfoChunk* slideChunk,
+ Region& region);
+
+public:
+ Kind kind;
+ std::vector<Region> regions;
+
+ // This buffer is vm_allocated (or points to a file on disk). Either way, the builder
+ // creates it but doesn't destroy it. Its ownership will move out to the calling code via
+ // getResults(), and the caller will deallocate/unmap as needed
+ uint8_t* buffer = nullptr;
+ uint64_t bufferSize = 0;
+ CacheVMAddress subCacheVMAddress;
+#if !SUPPORT_CACHE_BUILDER_MEMORY_BUFFERS
+ int fd = 0;
+ std::string tempPath;
+#endif
+ uint8_t cdHash[20];
+ uuid_string_t uuidString;
+ std::string fileSuffix;
+
+ // Some Chunk instances are owned by the SubCache. Eg, it owns its own header
+ std::unique_ptr<CacheHeaderChunk> cacheHeader;
+ std::unique_ptr<SlideInfoChunk> dataSlideInfo;
+ std::unique_ptr<SlideInfoChunk> dataConstSlideInfo;
+ std::unique_ptr<SlideInfoChunk> authSlideInfo;
+ std::unique_ptr<SlideInfoChunk> authConstSlideInfo;
+ std::unique_ptr<CodeSignatureChunk> codeSignature;
+ std::unique_ptr<ObjCOptsHeaderChunk> objcOptsHeader;
+ std::unique_ptr<ObjCHeaderInfoReadOnlyChunk> objcHeaderInfoRO;
+ std::unique_ptr<ObjCHeaderInfoReadWriteChunk> objcHeaderInfoRW;
+ std::unique_ptr<ObjCImageInfoChunk> objcImageInfo;
+ std::unique_ptr<ObjCStringsChunk> objcSelectorStrings;
+ std::unique_ptr<ObjCSelectorHashTableChunk> objcSelectorsHashTable;
+ std::unique_ptr<ObjCStringsChunk> objcClassNameStrings;
+ std::unique_ptr<ObjCClassHashTableChunk> objcClassesHashTable;
+ std::unique_ptr<ObjCStringsChunk> objcProtocolNameStrings;
+ std::unique_ptr<ObjCProtocolHashTableChunk> objcProtocolsHashTable;
+ std::unique_ptr<ObjCCanonicalProtocolsChunk> objcCanonicalProtocols;
+ std::unique_ptr<ObjCPreAttachedCategoriesChunk> objcCategories;
+ std::unique_ptr<ObjCStringsChunk> objcSwiftDemangledNameStrings;
+ std::unique_ptr<ObjCIMPCachesChunk> objcIMPCaches;
+ std::unique_ptr<SwiftOptsHeaderChunk> swiftOptsHeader;
+ std::unique_ptr<SwiftProtocolConformancesHashTableChunk> swiftTypeHashTable;
+ std::unique_ptr<SwiftProtocolConformancesHashTableChunk> swiftMetadataHashTable;
+ std::unique_ptr<SwiftProtocolConformancesHashTableChunk> swiftForeignTypeHashTable;
+ std::unique_ptr<CacheTrieChunk> cacheDylibsTrie;
+ std::unique_ptr<PatchTableChunk> patchTable;
+ std::unique_ptr<DynamicConfigChunk> dynamicConfig;
+ std::unique_ptr<PrebuiltLoaderChunk> cacheDylibsLoaders;
+ std::unique_ptr<PrebuiltLoaderChunk> executableLoaders;
+ std::unique_ptr<CacheTrieChunk> executablesTrie;
+ std::unique_ptr<SymbolStringsChunk> optimizedSymbolStrings;
+ std::unique_ptr<UniquedGOTsChunk> uniquedGOTs;
+ std::unique_ptr<UniquedGOTsChunk> uniquedAuthGOTs;
+
+ // Each subCache has its own Linkedit so needs its own optimizer
+ SymbolStringsOptimizer symbolStringsOptimizer;
+
+ // Each subCache can have its own uniqued GOTs
+ UniquedGOTsOptimizer uniquedGOTsOptimizer;
+
+ // FIXME: Should these be zero-sized Chunk's instead?
+ uint64_t rosettaReadOnlyAddr = 0;
+ uint64_t rosettaReadOnlySize = 0;
+ uint64_t rosettaReadWriteAddr = 0;
+ uint64_t rosettaReadWriteSize = 0;
+
+ // The following is only used depending on the kind field
+
+ // Main sub caches have a list of the other sub caches (indices are in to the builder subCaches array)
+ std::vector<SubCache*> subCaches;
+};
+
+} // namespace cache_builder
+
+#endif /* SubCache_hpp */