Loading...
cache_builder/SubCache.h /dev/null dyld-1330
--- /dev/null
+++ dyld/dyld-1330/cache_builder/SubCache.h
@@ -0,0 +1,348 @@
+/* -*- 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 "Platform.h"
+#include "Types.h"
+
+#include <uuid/uuid.h>
+#include <vector>
+
+namespace cache_builder
+{
+
+struct BuilderOptions;
+
+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,
+
+        // Put TPRO const before data as we want it to be adjacent to the DATA_DIRTY which it at the start of data
+        tproConst,
+
+        data,
+
+        // Put TPRO auth const before auth as we want it to be adjacent to the DATA_DIRTY which it at the start of auth
+        tproAuthConst,
+
+        auth,
+
+        // FIXME: Move this to be after DATA_CONST to reduce page tables
+        // Needs rdar://96315050
+        authConst,
+
+        readOnly,
+        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;
+
+    std::list<AlignChunk>                   alignmentChunks;
+
+    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(const BuilderConfig& config, CacheDylib& cacheDylib);
+    void addLinkeditFromDylib(CacheDylib& cacheDylib);
+    void addCacheHeaderChunk(const BuilderOptions& options, const BuilderConfig& config,
+                             const std::span<CacheDylib> cacheDylibs);
+    void addObjCHeaderInfoReadWriteChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer);
+    void addCodeSignatureChunk();
+    void addObjCOptsHeaderChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer);
+    void addObjCHeaderInfoReadOnlyChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer);
+    void addObjCImageInfoChunk(const BuilderConfig& config, ObjCOptimizer& objcOptimizer);
+    void addObjCSelectorStringsChunk(const BuilderConfig& config, ObjCSelectorOptimizer& objCSelectorOptimizer);
+    void addObjCSelectorHashTableChunk(const BuilderConfig& config, ObjCSelectorOptimizer& objCSelectorOptimizer);
+    void addObjCClassNameStringsChunk(const BuilderConfig& config, ObjCClassOptimizer& objcClassOptimizer);
+    void addObjCClassHashTableChunk(const BuilderConfig& config, ObjCClassOptimizer& objcClassOptimizer);
+    void addObjCProtocolNameStringsChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer);
+    void addObjCProtocolHashTableChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer);
+    void addObjCProtocolSwiftDemangledNamesChunk(const BuilderConfig& config, ObjCProtocolOptimizer& objcProtocolOptimizer);
+    void addObjCCanonicalProtocolsChunk(const BuilderConfig& config,
+                                        ObjCProtocolOptimizer& objcProtocolOptimizer);
+    void addObjCCategoriesChunk(const BuilderConfig& config,
+                                ObjCCategoryOptimizer& objcCategoryOptimizer);
+    void addObjCIMPCachesChunk(const BuilderConfig& config, ObjCIMPCachesOptimizer& objcIMPCachesOptimizer);
+    void addCacheTrieChunk(DylibTrieOptimizer& dylibTrieOptimizer);
+    void addPatchTableChunk(PatchTableOptimizer& patchTableOptimizer);
+    void addFunctionVariantsChunk(FunctionVariantsOptimizer& optimizer);
+    void addCacheDylibsLoaderChunk(PrebuiltLoaderBuilder& builder);
+    void addExecutableLoaderChunk(PrebuiltLoaderBuilder& builder);
+    void addExecutablesTrieChunk(PrebuiltLoaderBuilder& builder);
+    void addSwiftOptsHeaderChunk(const BuilderConfig& config, SwiftOptimizer& opt);
+    void addSwiftTypeHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt);
+    void addSwiftMetadataHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt);
+    void addSwiftForeignHashTableChunk(const BuilderConfig& config, SwiftOptimizer& opt);
+    void addSwiftPrespecializedMetadataPointerTableChunks(const BuilderConfig& config, SwiftOptimizer& opt);
+    void addPrewarmingDataChunk(const BuilderConfig& config, PrewarmingOptimizer& 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(mach_o::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,
+                          uint32_t osVersion, uint32_t altPlatform, uint32_t altOsVersion);
+
+    // 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,
+                                CacheVMAddress dyldInCacheUnslidAddr,
+                                CacheVMAddress dyldInCacheEntryUnslidAddr,
+                                const DylibTrieOptimizer& dylibTrieOptimizer,
+                                const ObjCOptimizer& objcOpt,
+                                const SwiftOptimizer& swiftOpt,
+                                const PatchTableOptimizer& patchTableOptimizer,
+                                const FunctionVariantsOptimizer& functionVariantOptimizer,
+                                const PrebuiltLoaderBuilder& prebuiltLoaderBuilder,
+                                const PrewarmingOptimizer& prewarmingOptimizer);
+
+    // 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;
+
+    // Note this is for x86_64 only, and works out where the TPRO "regions" are inside the DATA region
+    static void     forEachTPRORegionInData(SubCache* mainSubCache, std::span<SubCache*> subCaches,
+                                            void (^callback)(Region& region, const Chunk* firstChunk, const Chunk* lastChunk));
+
+    // Adds the given chunk to the given region
+    void addTextChunk(Chunk* chunk);
+    void addDataChunk(Chunk* chunk);
+    void addTPROConstChunk(const BuilderConfig& config, Chunk* chunk);
+    void addDataConstChunk(Chunk* chunk);
+    void addAuthChunk(Chunk* chunk);
+    void addAuthConstChunk(Chunk* chunk);
+    void addReadOnlyChunk(const BuilderConfig& config, Chunk* chunk);
+    void addLinkeditChunk(Chunk* chunk);
+    void addUnmappedChunk(Chunk* chunk);
+    void addCodeSignatureChunk(Chunk* chunk);
+    void addObjCReadWriteChunk(const BuilderConfig& config, Chunk* chunk);
+
+#if BUILDING_CACHE_BUILDER_UNIT_TESTS
+    // We need everything public to write tests
+public:
+#else
+private:
+#endif
+
+    // 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 BuilderOptions& options) const;
+
+    // Add image info to the subCache header, if it needs it
+    void addCacheHeaderImageInfo(const BuilderOptions& options,
+                                 const BuilderConfig& config,
+                                 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;
+    uint8_t             cdHash[20];
+    uint8_t             agilecdHash[20];  // if using agile signatures, this is the sha256
+    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>                             tproConstSlideInfo;
+    std::unique_ptr<SlideInfoChunk>                             dataSlideInfo;
+    std::unique_ptr<SlideInfoChunk>                             dataConstSlideInfo;
+    std::unique_ptr<SlideInfoChunk>                             tproAuthConstSlideInfo;
+    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<FunctionVariantsPatchTableChunk>            functionVariants;
+    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::vector<std::unique_ptr<PointerHashTableChunk>>         pointerHashTables;
+    std::unique_ptr<PrewarmingChunk>                            prewarmingChunk;
+
+    // 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 */