Loading...
--- dyld/dyld-1340/kernel-collection-builder/kernel_collection_builder.cpp
+++ /dev/null
@@ -1,692 +0,0 @@
-/* -*- 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@
- */
-
-#include "kernel_collection_builder.h"
-
-#include "AppCacheBuilder.h"
-#include "Diagnostics.h"
-#include "ClosureFileSystemNull.h"
-#include "MachOAppCache.h"
-#include "GradedArchitectures.h"
-
-#include <dispatch/dispatch.h>
-#include <span>
-#include <string>
-#include <vector>
-
-using mach_o::GradedArchitectures;
-using mach_o::Platform;
-
-static const uint64_t kMinBuildVersion = 1; //The minimum version BuildOptions struct we can support
-static const uint64_t kMaxBuildVersion = 1; //The maximum version BuildOptions struct we can support
-
-static const uint32_t MajorVersion = 1;
-static const uint32_t MinorVersion = 0;
-
-struct KernelCollectionBuilder {
-
- KernelCollectionBuilder(const BuildOptions_v1* options);
-
- struct CollectionFile {
- const uint8_t* data = nullptr;
- uint64_t size = 0;
- const char* path = nullptr;
- };
-
- struct CacheBuffer {
- uint8_t* buffer = nullptr;
- uint64_t bufferSize = 0;
- };
-
- const char* arch = "";
- BuildOptions_v1 options;
- std::list<Diagnostics> inputFileDiags;
- std::vector<AppCacheBuilder::InputDylib> inputFiles;
- dyld3::closure::LoadedFileInfo kernelCollectionFileInfo;
- dyld3::closure::LoadedFileInfo pageableCollectionFileInfo;
- std::vector<AppCacheBuilder::CustomSegment> customSections;
- CFDictionaryRef prelinkInfoExtraData = nullptr;
-
- std::list<CollectionFileResult_v1> fileResultsStorage;
- std::vector<const CollectionFileResult_v1*> fileResults;
- CFDictionaryRef errorsDict = nullptr;
-
- std::vector<const char*> errors;
- std::vector<std::string> errorStorage;
-
- std::list<std::string> duplicatedStrings;
- std::vector<CFTypeRef> typeRefs;
-
- __attribute__((format(printf, 2, 3)))
- void error(const char* format, ...) {
- va_list list;
- va_start(list, format);
- Diagnostics diag;
- diag.error(format, va_list_wrap(list));
- va_end(list);
-
- errorStorage.push_back(diag.errorMessage());
- errors.push_back(errorStorage.back().data());
- }
-
- void retain(CFTypeRef v) {
- CFRetain(v);
- typeRefs.push_back(v);
- }
-
- const char* strdup(CFStringRef str) {
- size_t length = CFStringGetLength(str);
- char buffer[length + 1];
- memset(&buffer[0], 0, length + 1);
- if ( !CFStringGetCString(str, buffer, length + 1, kCFStringEncodingASCII) ) {
- error("Could not convert to ASCII");
- return nullptr;
- }
- duplicatedStrings.push_back(buffer);
- return duplicatedStrings.back().c_str();
- }
-
-};
-
-// What is the version of this builder dylib. Can be used to determine what API is available.
-void getVersion(uint32_t *major, uint32_t *minor) {
- *major = MajorVersion;
- *minor = MinorVersion;
-}
-
-KernelCollectionBuilder::KernelCollectionBuilder(const BuildOptions_v1* options)
- : options(*options) {
- retain(this->options.arch);
-}
-
-// Returns a valid object on success, or NULL on failure.
-__API_AVAILABLE(macos(10.14))
-struct KernelCollectionBuilder* createKernelCollectionBuilder(const struct BuildOptions_v1* options) {
- KernelCollectionBuilder* builder = new KernelCollectionBuilder(options);
-
- if (options->version < kMinBuildVersion) {
- builder->error("Builder version %llu is less than minimum supported version of %llu", options->version, kMinBuildVersion);
- return builder;
- }
- if (options->version > kMaxBuildVersion) {
- builder->error("Builder version %llu is greater than maximum supported version of %llu", options->version, kMaxBuildVersion);
- return builder;
- }
- if ( options->arch == nullptr ) {
- builder->error("arch must not be null");
- return builder;
- }
- const char* archName = builder->strdup(options->arch);
- if ( archName == nullptr ) {
- // Already generated an error in strdup.
- return builder;
- }
- builder->arch = archName;
-
- return builder;
-}
-
-static bool loadFileFromData(struct KernelCollectionBuilder* builder,
- const CFStringRef path, const CFDataRef data,
- dyld3::closure::LoadedFileInfo& fileInfo) {
- fileInfo.fileContent = CFDataGetBytePtr(data);
- fileInfo.fileContentLen = CFDataGetLength(data);
- fileInfo.sliceOffset = 0;
- fileInfo.sliceLen = CFDataGetLength(data);
- fileInfo.isOSBinary = false;
- fileInfo.inode = 0;
- fileInfo.mtime = 0;
- fileInfo.unload = nullptr;
- fileInfo.path = builder->strdup(path);
-
- Diagnostics diag;
- dyld3::closure::FileSystemNull fileSystem;
- const GradedArchitectures& archs = GradedArchitectures::forName(builder->arch, /*keysOff=*/false, /*isKernel=*/true);
- auto loaded = dyld3::MachOAnalyzer::loadFromBuffer(diag, fileSystem, fileInfo.path, archs,
- Platform(), fileInfo);
- if ( !loaded ) {
- builder->error("in %s: %s", fileInfo.path, diag.errorMessage().c_str());
- return false;
- }
-
- return true;
-}
-
-// Add a kernel static executable file. Returns true on success.
-__API_AVAILABLE(macos(10.14))
-bool addKernelFile(struct KernelCollectionBuilder* builder, const CFStringRef path, const CFDataRef data) {
- builder->retain(path);
- builder->retain(data);
-
- dyld3::closure::LoadedFileInfo info;
- bool loaded = loadFileFromData(builder, path, data, info);
- if ( !loaded )
- return false;
-
- DyldSharedCache::MappedMachO mappedFile(info.path, (const dyld3::MachOAnalyzer *)info.fileContent,
- info.fileContentLen, false, false,
- info.sliceOffset, info.mtime, info.inode);
-
- AppCacheBuilder::InputDylib input;
- input.dylib.mappedFile = mappedFile;
- input.dylib.loadedFileInfo = info;
- input.dylib.inputFile = nullptr;
- input.dylibID = "com.apple.kernel";
- input.errors = &builder->inputFileDiags.emplace_back();
-
- builder->inputFiles.push_back(input);
- return true;
-}
-
-// Add kext mach-o and plist files. Returns true on success.
-__API_AVAILABLE(macos(10.14))
-bool addKextDataFile(struct KernelCollectionBuilder* builder, const KextFileData_v1* fileData) {
- if (fileData->version != 1) {
- builder->error("addKextDataFile version %llu is less than minimum supported version of %d", fileData->version, 1);
- return false;
- }
-
- builder->retain(fileData->dependencies);
- builder->retain(fileData->bundleID);
- builder->retain(fileData->bundlePath);
- builder->retain(fileData->plist);
-
- dyld3::closure::LoadedFileInfo info;
-
- // Code-less kext's don't have a mach-o to load
- const char* kextpath = nullptr;
- if ( fileData->kextdata != nullptr ) {
- builder->retain(fileData->kextpath);
- builder->retain(fileData->kextdata);
- bool loaded = loadFileFromData(builder, fileData->kextpath, fileData->kextdata, info);
- if ( !loaded )
- return false;
- kextpath = info.path;
- } else {
- kextpath = "codeless";
- }
-
- DyldSharedCache::MappedMachO mappedFile(kextpath, (const dyld3::MachOAnalyzer *)info.fileContent,
- info.fileContentLen, false, false,
- info.sliceOffset, info.mtime, info.inode);
-
- uint64_t numDependencies = CFArrayGetCount(fileData->dependencies);
-
- AppCacheBuilder::InputDylib input;
- input.dylib.mappedFile = mappedFile;
- input.dylib.loadedFileInfo = info;
- input.dylib.inputFile = nullptr;
- input.dylibID = builder->strdup(fileData->bundleID);
- for (uint64_t i = 0; i != numDependencies; ++i) {
- CFTypeRef elementRef = CFArrayGetValueAtIndex(fileData->dependencies, i);
- if ( CFGetTypeID(elementRef) != CFStringGetTypeID() ) {
- builder->error("Dependency %llu of %s is not a string", i, info.path);
- return false;
- }
- CFStringRef stringRef = (CFStringRef)elementRef;
- input.dylibDeps.push_back(builder->strdup(stringRef));
- }
- input.infoPlist = fileData->plist;
- input.errors = &builder->inputFileDiags.emplace_back();
- input.bundlePath = builder->strdup(fileData->bundlePath);
- switch ( fileData->stripMode ) {
- case binaryUnknownStripMode:
- input.stripMode = CacheBuilder::DylibStripMode::stripNone;
- break;
- case binaryStripNone:
- input.stripMode = CacheBuilder::DylibStripMode::stripNone;
- break;
- case binaryStripExports:
- input.stripMode = CacheBuilder::DylibStripMode::stripExports;
- break;
- case binaryStripLocals:
- input.stripMode = CacheBuilder::DylibStripMode::stripLocals;
- break;
- case binaryStripAll:
- input.stripMode = CacheBuilder::DylibStripMode::stripAll;
- break;
- }
-
- builder->inputFiles.push_back(input);
- return true;
-}
-
-// Add interface plist file. Returns true on success.
-__API_AVAILABLE(macos(10.14))
-bool addInterfaceFile(struct KernelCollectionBuilder* builder, const CFStringRef path, const CFDataRef data) {
- builder->retain(path);
- builder->retain(data);
-
- assert(0);
-}
-
-// Add collection file. Returns true on success.
-__API_AVAILABLE(macos(10.14))
-bool addCollectionFile(struct KernelCollectionBuilder* builder, const CFStringRef path, const CFDataRef data,
- CollectionKind kind) {
- dyld3::closure::LoadedFileInfo* fileInfo = nullptr;
- if ( kind == baseKC ) {
- if ( (builder->options.collectionKind != auxKC) && (builder->options.collectionKind != pageableKC) ) {
- builder->error("Invalid collection file for build");
- return false;
- }
- fileInfo = &builder->kernelCollectionFileInfo;
- } else if ( kind == pageableKC ) {
- if ( builder->options.collectionKind != auxKC ) {
- builder->error("Invalid collection file for build");
- return false;
- }
- if ( builder->pageableCollectionFileInfo.fileContent != nullptr ) {
- builder->error("Already have collection file");
- return false;
- }
- fileInfo = &builder->pageableCollectionFileInfo;
- } else {
- builder->error("Unsupported collection kind");
- return false;
- }
- if ( fileInfo->fileContent != nullptr ) {
- builder->error("Already have collection file");
- return false;
- }
-
- builder->retain(path);
- builder->retain(data);
-
- bool loaded = loadFileFromData(builder, path, data, *fileInfo);
- if ( !loaded )
- return false;
-
- const dyld3::MachOFile* mf = (const dyld3::MachOFile*)fileInfo->fileContent;
- if ( !mf->isFileSet() ) {
- builder->error("kernel collection is not a cache file: %s\n", builder->strdup(path));
- return false;
- }
-
- return true;
-}
-
-// Add data to the given segment of the final file. Note the section can be null (or "") if desired
-__API_AVAILABLE(macos(10.14))
-bool addSegmentData(struct KernelCollectionBuilder* builder, const CFStringRef segmentName,
- const CFStringRef sectionName, const CFDataRef data) {
- // Check the segment name
- if ( segmentName == nullptr ) {
- builder->error("Segment data name must be non-null");
- return false;
- }
- CFIndex segmentNameLength = CFStringGetLength(segmentName);
- if ( (segmentNameLength == 0) || (segmentNameLength > 16) ) {
- builder->error("Segment data name must not be empty or > 16 characters");
- return false;
- }
-
- AppCacheBuilder::CustomSegment::CustomSection section;
-
- // Check the section name
- if ( sectionName != nullptr ) {
- CFIndex sectionNameLength = CFStringGetLength(sectionName);
- if ( sectionNameLength != 0 ) {
- if ( sectionNameLength > 16 ) {
- builder->error("Section data name must not be empty or > 16 characters");
- return false;
- }
- section.sectionName = builder->strdup(sectionName);
- }
- }
-
- // Check the data
- if ( data == nullptr ) {
- builder->error("Segment data payload must be non-null");
- return false;
- }
- const uint8_t* dataStart = CFDataGetBytePtr(data);
- const uint64_t dataLength = CFDataGetLength(data);
- if ( dataLength == 0 ) {
- builder->error("Segment data payload must not be empty");
- return false;
- }
-
- builder->retain(data);
- section.data.insert(section.data.end(), dataStart, dataStart + dataLength);
-
- AppCacheBuilder::CustomSegment segment;
- segment.segmentName = builder->strdup(segmentName);
- segment.sections.push_back(section);
- builder->customSections.push_back(segment);
- return true;
-}
-
-// Add data to the given segment of the final file. Note the section can be null (or "") if desired
-__API_AVAILABLE(macos(10.14))
-bool addPrelinkInfo(struct KernelCollectionBuilder* builder, const CFDictionaryRef extraData) {
- if ( builder->prelinkInfoExtraData != nullptr ) {
- builder->error("Prelink info data has already been set by an earlier call");
- return false;
- }
- // Check the data
- if ( extraData == nullptr ) {
- builder->error("Prelink info data payload must be non-null");
- return false;
- }
- if ( CFDictionaryGetCount(extraData) == 0 ) {
- builder->error("Prelink info data payload must not be empty");
- return false;
- }
- builder->retain(extraData);
- builder->prelinkInfoExtraData = extraData;
- return true;
-}
-
-// Set a handler to be called at various points during the build to notify the user of progress.
-__API_AVAILABLE(macos(10.14))
-void setProgressCallback(const ProgressCallback callback) {
- assert(0);
-}
-
-static AppCacheBuilder::Options::AppCacheKind cacheKind(CollectionKind kind) {
- switch (kind) {
- case unknownKC:
- return AppCacheBuilder::Options::AppCacheKind::none;
- case baseKC:
- return AppCacheBuilder::Options::AppCacheKind::kernel;
- case auxKC:
- return AppCacheBuilder::Options::AppCacheKind::auxKC;
- case pageableKC:
- return AppCacheBuilder::Options::AppCacheKind::pageableKC;
- }
-}
-
-static AppCacheBuilder::Options::StripMode stripMode(StripMode mode) {
- switch (mode) {
- case unknownStripMode:
- return AppCacheBuilder::Options::StripMode::none;
- case stripNone:
- return AppCacheBuilder::Options::StripMode::none;
- case stripAll:
- return AppCacheBuilder::Options::StripMode::all;
- case stripAllKexts:
- return AppCacheBuilder::Options::StripMode::allExceptKernel;
- }
-}
-
-static void generatePerKextErrors(struct KernelCollectionBuilder* builder) {
- CFMutableDictionaryRef errorsDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
- builder->typeRefs.push_back(errorsDict);
-
- for (const AppCacheBuilder::InputDylib& file : builder->inputFiles) {
- if ( !file.errors->hasError() )
- continue;
-
- CFStringRef bundleID = CFStringCreateWithCString(kCFAllocatorDefault, file.dylibID.c_str(),
- kCFStringEncodingASCII);
- builder->typeRefs.push_back(bundleID);
-
- CFMutableArrayRef errorsArray = CFArrayCreateMutable(kCFAllocatorDefault, 1, nullptr);
- builder->typeRefs.push_back(errorsArray);
-
- CFStringRef errorString = CFStringCreateWithCString(kCFAllocatorDefault, file.errors->errorMessage().c_str(),
- kCFStringEncodingASCII);
- builder->typeRefs.push_back(errorString);
-
- CFArrayAppendValue(errorsArray, errorString);
-
- // Add this bundle to the dictionary
- CFDictionarySetValue(errorsDict, bundleID, errorsArray);
-
- // FIXME: Remove this once the kernel linker has adopted the new API to get the per-kext errors
- // For now also put the per-kext errors on the main error list
- builder->error("Could not use '%s' because: %s", file.dylibID.c_str(), file.errors->errorMessage().c_str());
- }
-
- if ( CFDictionaryGetCount(errorsDict) != 0 ) {
- builder->errorsDict = errorsDict;
- }
-}
-
-// Returns true on success.
-__API_AVAILABLE(macos(10.14))
-bool runKernelCollectionBuilder(struct KernelCollectionBuilder* builder) {
-
- // Make sure specificed bundle-id's are not already in the caches we
- // are linking to
- __block std::set<std::string_view> existingBundles;
- if ( (builder->options.collectionKind == auxKC) || (builder->options.collectionKind == pageableKC) ) {
- if ( builder->kernelCollectionFileInfo.fileContent == nullptr ) {
- builder->error("Cannot build pageableKC/auxKC without baseKC");
- return false;
- }
- Diagnostics diag;
-
- // Check the base KC
- const dyld3::MachOAppCache* kernelCacheMA = (const dyld3::MachOAppCache*)builder->kernelCollectionFileInfo.fileContent;
- kernelCacheMA->forEachDylib(diag, ^(const dyld3::MachOAnalyzer *ma, const char *name, bool &stop) {
- existingBundles.insert(name);
- });
-
- // Check the pageableKC if we have one
- const dyld3::MachOAppCache* pageableCacheMA = (const dyld3::MachOAppCache*)builder->kernelCollectionFileInfo.fileContent;
- if ( pageableCacheMA != nullptr ) {
- pageableCacheMA->forEachDylib(diag, ^(const dyld3::MachOAnalyzer *ma, const char *name, bool &stop) {
- existingBundles.insert(name);
- });
- }
-
- bool foundBadBundle = false;
- for (const AppCacheBuilder::InputDylib& input : builder->inputFiles) {
- if ( existingBundles.find(input.dylibID) != existingBundles.end() ) {
- builder->error("kernel collection already contains bundle-id: %s\n", input.dylibID.c_str());
- foundBadBundle = true;
- }
- }
- if ( foundBadBundle )
- return false;
- }
-
- // Make sure we have an xnu binary, from this collection or an existing one
- __block const dyld3::MachOAnalyzer* kernelMA = nullptr;
- if ( builder->options.collectionKind == baseKC ) {
- for (const AppCacheBuilder::InputDylib& input : builder->inputFiles) {
- const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)input.dylib.loadedFileInfo.fileContent;
-
- // Skip codeless kexts
- if ( ma == nullptr )
- continue;
-
- if ( ma->isStaticExecutable() ) {
- kernelMA = ma;
- }
- }
- if ( !kernelMA ) {
- builder->error("Cannot build bootKC without xnu binary");
- return false;
- }
- } else {
- // auxKC/pageableKC
- Diagnostics diag;
-
- const dyld3::MachOAppCache* kernelCacheMA = (const dyld3::MachOAppCache*)builder->kernelCollectionFileInfo.fileContent;
- kernelCacheMA->forEachDylib(diag, ^(const dyld3::MachOAnalyzer *ma, const char *name, bool &stop) {
- if ( ma->isStaticExecutable() ) {
- kernelMA = ma;
- stop = true;
- }
- });
-
- if ( !kernelMA ) {
- builder->error("Cannot build pageableKC/auxKC without xnu binary from bootKC");
- return false;
- }
- }
-
-
- dispatch_apply(builder->inputFiles.size(), DISPATCH_APPLY_AUTO, ^(size_t index) {
- const AppCacheBuilder::InputDylib& input = builder->inputFiles[index];
- auto errorHandler = ^(const char* msg) {
- input.errors->error("cannot be placed in kernel collection because: %s", msg);
- };
- const dyld3::MachOAnalyzer* ma = (const dyld3::MachOAnalyzer*)input.dylib.loadedFileInfo.fileContent;
- // Skip codeless kexts
- if ( ma == nullptr )
- return;
- if (!ma->canBePlacedInKernelCollection(input.dylib.loadedFileInfo.path, errorHandler)) {
- assert(input.errors->hasError());
- return;
- }
-
- });
- for (const AppCacheBuilder::InputDylib& input : builder->inputFiles) {
- if ( input.errors->hasError() ) {
- builder->error("One or more binaries has an error which prevented linking. See other errors.");
- generatePerKextErrors(builder);
- return false;
- }
- }
-
- DyldSharedCache::CreateOptions builderOptions = {};
- std::string runtimePath = "";
- builderOptions.outputFilePath = runtimePath;
- builderOptions.outputMapFilePath = builderOptions.outputFilePath + ".json";
- // Use the kernel version of arm64e.
- std::string_view arch = builder->arch;
- if ( arch == "arm64e" ) {
- arch = "arm64e.kernel";
- }
- builderOptions.arch = mach_o::Architecture::byName(arch);
- builderOptions.platform = Platform();
- builderOptions.localSymbolMode = DyldSharedCache::LocalSymbolsMode::keep;
- builderOptions.cacheConfiguration = kDyldSharedCacheTypeProduction;
- builderOptions.optimizeDyldDlopens = false;
- builderOptions.optimizeDyldLaunches = false;
- builderOptions.codeSigningDigestMode = DyldSharedCache::CodeSigningDigestMode::SHA256only;
- builderOptions.dylibsRemovedDuringMastering = true;
- builderOptions.inodesAreSameAsRuntime = false;
- builderOptions.cacheSupportsASLR = true;
- builderOptions.forSimulator = false;
- builderOptions.isLocallyBuiltCache = true;
- builderOptions.verbose = builder->options.verboseDiagnostics;
- builderOptions.evictLeafDylibsOnOverflow = true;
- builderOptions.loggingPrefix = "";
- builderOptions.dylibOrdering = {};
- builderOptions.dirtyDataSegmentOrdering = {};
- builderOptions.objcOptimizations = {};
-
- AppCacheBuilder::Options appCacheOptions;
- appCacheOptions.cacheKind = cacheKind(builder->options.collectionKind);
- appCacheOptions.stripMode = stripMode(builder->options.stripMode);
-
- const dyld3::closure::FileSystemNull builderFileSystem;
-
- AppCacheBuilder cacheBuilder(builderOptions, appCacheOptions, builderFileSystem);
- if ( builder->kernelCollectionFileInfo.fileContent != nullptr ) {
- const dyld3::MachOAppCache* appCacheMA = (const dyld3::MachOAppCache*)builder->kernelCollectionFileInfo.fileContent;
- cacheBuilder.setExistingKernelCollection(appCacheMA);
- }
- if ( builder->pageableCollectionFileInfo.fileContent != nullptr ) {
- const dyld3::MachOAppCache* appCacheMA = (const dyld3::MachOAppCache*)builder->pageableCollectionFileInfo.fileContent;
- cacheBuilder.setExistingPageableKernelCollection(appCacheMA);
- }
-
- // Add custom sections
- for (const AppCacheBuilder::CustomSegment& segment : builder->customSections) {
- if ( !cacheBuilder.addCustomSection(segment.segmentName, segment.sections.front()) ) {
- builder->error("%s", cacheBuilder.errorMessage().c_str());
- return false;
- }
- }
-
- // Add prelink info data
- if ( builder->prelinkInfoExtraData != nullptr ) {
- cacheBuilder.setExtraPrelinkInfo(builder->prelinkInfoExtraData);
- }
-
- cacheBuilder.buildAppCache(builder->inputFiles);
- if ( !cacheBuilder.errorMessage().empty() ) {
- builder->error("%s", cacheBuilder.errorMessage().c_str());
- generatePerKextErrors(builder);
- return false;
- }
-
- uint8_t* cacheBuffer = nullptr;
- uint64_t cacheSize = 0;
- cacheBuilder.writeBuffer(cacheBuffer, cacheSize);
-
- CFDataRef dataRef = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, cacheBuffer, cacheSize, kCFAllocatorDefault);
- builder->retain(dataRef);
- CFRelease(dataRef);
-
- CFArrayRef warningsArrayRef = CFArrayCreate(kCFAllocatorDefault, nullptr, 0, nullptr);
- builder->retain(warningsArrayRef);
- CFRelease(warningsArrayRef);
-
- CollectionFileResult_v1 fileResult = { 1, kernelCollection, dataRef, warningsArrayRef };
-
- builder->fileResultsStorage.push_back(fileResult);
- builder->fileResults.push_back(&builder->fileResultsStorage.back());
-
- return true;
-}
-
-// Gets the list of errors we have produced. These may be from incorrect input values, or failures in the build itself
-__API_AVAILABLE(macos(10.14))
-const char* const* getErrors(const struct KernelCollectionBuilder* builder, uint64_t* errorCount) {
- if (builder->errors.empty())
- return nullptr;
- *errorCount = builder->errors.size();
- return builder->errors.data();
-}
-
-__API_AVAILABLE(macos(10.14))
-CFDictionaryRef getKextErrors(const struct KernelCollectionBuilder* builder) {
- return builder->errorsDict;
-}
-
-// Returns an array of the resulting files. These may be new collections, or other files required later
-__API_AVAILABLE(macos(10.14))
-const struct CollectionFileResult_v1* const* getCollectionFileResults(struct KernelCollectionBuilder* builder, uint64_t* resultCount) {
- if ( builder->fileResults.empty() ) {
- *resultCount = 0;
- return nullptr;
- }
-
- *resultCount = builder->fileResults.size();
- return builder->fileResults.data();
-}
-
-__API_AVAILABLE(macos(10.14))
-void destroyKernelCollectionBuilder(struct KernelCollectionBuilder* builder) {
- for (CFTypeRef ref : builder->typeRefs)
- CFRelease(ref);
- dyld3::closure::FileSystemNull fileSystem;
- for (const AppCacheBuilder::InputDylib& inputFile : builder->inputFiles) {
- fileSystem.unloadFile(inputFile.dylib.loadedFileInfo);
- }
- if ( builder->kernelCollectionFileInfo.fileContent != nullptr) {
- fileSystem.unloadFile(builder->kernelCollectionFileInfo);
- }
- if ( builder->pageableCollectionFileInfo.fileContent != nullptr) {
- fileSystem.unloadFile(builder->pageableCollectionFileInfo);
- }
- delete builder;
-}