2 * Copyright (c) 2017 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #ifndef AppCacheBuilder_h
25 #define AppCacheBuilder_h
27 #include "CacheBuilder.h"
28 #include "MachOFileAbstraction.hpp"
29 #include "MachOAppCache.h"
33 #include <CoreFoundation/CFDictionary.h>
35 class AppCacheBuilder final
: public CacheBuilder
{
38 enum class AppCacheKind
{
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
46 enum class StripMode
{
47 none
, // Don't strip anything
48 all
, // Strip everything
49 allExceptKernel
// Strip everything other than the static kernel
52 AppCacheKind cacheKind
= AppCacheKind::none
;
53 StripMode stripMode
= StripMode::none
;
55 AppCacheBuilder(const DyldSharedCache::CreateOptions
& dyldCacheOptions
, const Options
& appCacheOptions
,
56 const dyld3::closure::FileSystem
& fileSystem
);
57 ~AppCacheBuilder() override final
;
59 // Wraps up a loaded macho with the other information required by kext's, eg, the list of dependencies
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
;
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;
78 std::string segmentName
;
79 std::vector
<CustomSection
> sections
;
80 Region
* parentRegion
= nullptr;
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;
95 // The fixup format can't support more than 3 levels right now
99 struct AppCacheDylibInfo
: CacheBuilder::DylibInfo
101 // From CacheBuilder::DylibInfo
102 // const LoadedMachO* input;
103 // std::string dylibID;
104 // std::vector<SegmentMappingInfo> cacheLocation;
106 DylibStripMode stripMode
= DylibStripMode::stripNone
;
107 std::vector
<std::string
> dependencies
;
108 CFDictionaryRef infoPlist
= nullptr;
109 Diagnostics
* errors
= nullptr;
110 std::string bundlePath
;
113 static_assert(std::is_move_constructible
<AppCacheDylibInfo
>::value
);
115 void forEachDylibInfo(void (^callback
)(const DylibInfo
& dylib
, Diagnostics
& dylibDiag
)) override final
;
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
,
124 const DylibInfo
* getKernelStaticExecutableInputFile() const;
125 const dyld3::MachOAnalyzer
* getKernelStaticExecutableFromCache() const;
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();
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;
146 Options appCacheOptions
;
147 const dyld3::MachOAppCache
* existingKernelCollection
= nullptr;
148 const dyld3::MachOAppCache
* pageableKernelCollection
= nullptr;
149 CFDictionaryRef extraPrelinkInfo
= nullptr;
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
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;
174 uint16_t chainedPointerFormat
= 0;
176 // The dictionary we ultimately store in the __PRELINK_INFO region
177 CFMutableDictionaryRef prelinkInfoDict
= nullptr;
179 // Cache header fields
182 struct CacheHeader64
{
183 typedef std::pair
<segment_command_64
*, Region
*> SegmentCommandAndRegion
;
184 typedef std::pair
<fileset_entry_command
*, const DylibInfo
*> DylibCommandAndInfo
;
186 mach_header_64
* header
= nullptr;
188 uint64_t numLoadCommands
= 0;
189 uint64_t loadCommandsSize
= 0;
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
;
201 CacheHeader64 cacheHeader
;
204 #endif /* AppCacheBuilder_h */