dyld-832.7.1.tar.gz
[apple/dyld.git] / dyld3 / shared-cache / AppCacheBuilder.h
1 /*
2 * Copyright (c) 2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #ifndef AppCacheBuilder_h
25 #define AppCacheBuilder_h
26
27 #include "CacheBuilder.h"
28 #include "MachOFileAbstraction.hpp"
29 #include "MachOAppCache.h"
30
31 #include <list>
32
33 #include <CoreFoundation/CFDictionary.h>
34
35 class AppCacheBuilder final : public CacheBuilder {
36 public:
37 struct Options {
38 enum class AppCacheKind {
39 none,
40 kernel, // The base first party kernel collection with xnu and boot time kexts
41 pageableKC, // Other first party kexts which are usually only for some HW, eg, different GPUs
42 kernelCollectionLevel2, // Placeholder until we find a use for this
43 auxKC, // Third party kexts, or Apple kexts updated out of band with the OS, if any
44 };
45
46 enum class StripMode {
47 none, // Don't strip anything
48 all, // Strip everything
49 allExceptKernel // Strip everything other than the static kernel
50 };
51
52 AppCacheKind cacheKind = AppCacheKind::none;
53 StripMode stripMode = StripMode::none;
54 };
55 AppCacheBuilder(const DyldSharedCache::CreateOptions& dyldCacheOptions, const Options& appCacheOptions,
56 const dyld3::closure::FileSystem& fileSystem);
57 ~AppCacheBuilder() override final;
58
59 // Wraps up a loaded macho with the other information required by kext's, eg, the list of dependencies
60 struct InputDylib {
61 LoadedMachO dylib;
62 std::string dylibID;
63 std::vector<std::string> dylibDeps;
64 CFDictionaryRef infoPlist = nullptr;
65 std::string bundlePath;
66 Diagnostics* errors = nullptr;
67 CacheBuilder::DylibStripMode stripMode = CacheBuilder::DylibStripMode::stripNone;
68 };
69
70 // The payload for -sectcreate
71 struct CustomSegment {
72 struct CustomSection {
73 std::string sectionName;
74 std::vector<uint8_t> data;
75 uint64_t offsetInRegion = 0;
76 };
77
78 std::string segmentName;
79 std::vector<CustomSection> sections;
80 Region* parentRegion = nullptr;
81 };
82
83 bool addCustomSection(const std::string& segmentName,
84 CustomSegment::CustomSection section);
85 void setExistingKernelCollection(const dyld3::MachOAppCache* appCacheMA);
86 void setExistingPageableKernelCollection(const dyld3::MachOAppCache* appCacheMA);
87 void setExtraPrelinkInfo(CFDictionaryRef dictionary);
88 void buildAppCache(const std::vector<InputDylib>& dylibs);
89 void writeFile(const std::string& path);
90 void writeBuffer(uint8_t*& buffer, uint64_t& bufferSize) const;
91
92 private:
93
94 enum {
95 // The fixup format can't support more than 3 levels right now
96 numFixupLevels = 4
97 };
98
99 struct AppCacheDylibInfo : CacheBuilder::DylibInfo
100 {
101 // From CacheBuilder::DylibInfo
102 // const LoadedMachO* input;
103 // std::string dylibID;
104 // std::vector<SegmentMappingInfo> cacheLocation;
105
106 DylibStripMode stripMode = DylibStripMode::stripNone;
107 std::vector<std::string> dependencies;
108 CFDictionaryRef infoPlist = nullptr;
109 Diagnostics* errors = nullptr;
110 std::string bundlePath;
111 };
112
113 static_assert(std::is_move_constructible<AppCacheDylibInfo>::value);
114
115 void forEachDylibInfo(void (^callback)(const DylibInfo& dylib, Diagnostics& dylibDiag)) override final;
116
117 void forEachCacheDylib(void (^callback)(const dyld3::MachOAnalyzer* ma,
118 const std::string& dylibID,
119 DylibStripMode stripMode,
120 const std::vector<std::string>& dependencies,
121 Diagnostics& dylibDiag,
122 bool& stop)) const;
123
124 const DylibInfo* getKernelStaticExecutableInputFile() const;
125 const dyld3::MachOAnalyzer* getKernelStaticExecutableFromCache() const;
126
127 void makeSortedDylibs(const std::vector<InputDylib>& dylibs);
128 void allocateBuffer();
129 void assignSegmentRegionsAndOffsets();
130 void copyRawSegments();
131 void assignSegmentAddresses();
132 void generateCacheHeader();
133 void generatePrelinkInfo();
134 uint32_t getCurrentFixupLevel() const;
135 void processFixups();
136 void writeFixups();
137 void fipsSign();
138 void generateUUID();
139 uint64_t numRegions() const;
140 uint64_t numBranchRelocationTargets();
141 uint64_t fixupsPageSize() const;
142 uint64_t numWritablePagesToFixup(uint64_t numBytesToFixup) const;
143 bool fixupsArePerKext() const;
144 void forEachRegion(void (^callback)(const Region& region)) const;
145
146 Options appCacheOptions;
147 const dyld3::MachOAppCache* existingKernelCollection = nullptr;
148 const dyld3::MachOAppCache* pageableKernelCollection = nullptr;
149 CFDictionaryRef extraPrelinkInfo = nullptr;
150
151 std::vector<AppCacheDylibInfo> sortedDylibs;
152 std::vector<InputDylib> codelessKexts;
153 std::vector<CustomSegment> customSegments;
154 Region cacheHeaderRegion;
155 Region readExecuteRegion;
156 Region branchStubsRegion;
157 Region dataConstRegion;
158 Region branchGOTsRegion;
159 Region readWriteRegion;
160 Region hibernateRegion;
161 Region readOnlyTextRegion;
162 std::list<Region> customDataRegions; // -sectcreate
163 Region prelinkInfoRegion;
164 std::list<Region> nonSplitSegRegions;
165 // Region _readOnlyRegion; // This comes from the base class
166 Region fixupsSubRegion; // This will be in the __LINKEDIT when we write the file
167
168 // This is the base address from the statically linked kernel, or 0 for other caches
169 uint64_t cacheBaseAddress = 0;
170 // For x86_64 only, we want to keep the address of the hibernate segment from xnu
171 // We'll ensure this is mapped lower than the cache base address
172 uint64_t hibernateAddress = 0;
173
174 uint16_t chainedPointerFormat = 0;
175
176 // The dictionary we ultimately store in the __PRELINK_INFO region
177 CFMutableDictionaryRef prelinkInfoDict = nullptr;
178
179 // Cache header fields
180 // FIXME: 32-bit
181
182 struct CacheHeader64 {
183 typedef std::pair<segment_command_64*, Region*> SegmentCommandAndRegion;
184 typedef std::pair<fileset_entry_command*, const DylibInfo*> DylibCommandAndInfo;
185
186 mach_header_64* header = nullptr;
187
188 uint64_t numLoadCommands = 0;
189 uint64_t loadCommandsSize = 0;
190
191 uuid_command* uuid = nullptr;
192 build_version_command* buildVersion = nullptr;
193 thread_command* unixThread = nullptr;
194 symtab_command* symbolTable = nullptr;
195 dysymtab_command* dynSymbolTable = nullptr;
196 linkedit_data_command* chainedFixups = nullptr;
197 std::vector<SegmentCommandAndRegion> segments;
198 std::vector<DylibCommandAndInfo> dylibs;
199 };
200
201 CacheHeader64 cacheHeader;
202 };
203
204 #endif /* AppCacheBuilder_h */