summaryrefslogtreecommitdiff
path: root/view/sharedcache/core/SharedCacheView.cpp
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-03-10 11:05:40 -0400
committerMason Reed <mason@vector35.com>2025-04-02 05:36:54 -0400
commit25cc02431b61097b2adfc2fbc493b648b0300c3b (patch)
treea79d9c4f4f67234d3bf9bda413e8608f479a4cc8 /view/sharedcache/core/SharedCacheView.cpp
parentfa85bf28502286c4821427c5d0ed91a7ed46f8f6 (diff)
[SharedCache] Refactor Shared Cache
In absence of a better name, this commit refactors the shared cache code.
Diffstat (limited to 'view/sharedcache/core/SharedCacheView.cpp')
-rw-r--r--view/sharedcache/core/SharedCacheView.cpp854
1 files changed, 854 insertions, 0 deletions
diff --git a/view/sharedcache/core/SharedCacheView.cpp b/view/sharedcache/core/SharedCacheView.cpp
new file mode 100644
index 00000000..bf80c6eb
--- /dev/null
+++ b/view/sharedcache/core/SharedCacheView.cpp
@@ -0,0 +1,854 @@
+#include "SharedCacheView.h"
+#include <regex>
+#include "SharedCacheController.h"
+#include "FileAccessorCache.h"
+#include "MappedFileAccessor.h"
+
+using namespace BinaryNinja;
+using namespace BinaryNinja::DSC;
+
+SharedCacheViewType::SharedCacheViewType() : BinaryViewType(VIEW_NAME, VIEW_NAME) {}
+
+// We register all our one-shot stuff here, such as the object destructor.
+void SharedCacheViewType::Register()
+{
+ auto fdLimit = AdjustFileDescriptorLimit();
+ LogDebug("Shared Cache processing initialized with a max file descriptor limit of %lld", fdLimit);
+
+ // Adjust the global accessor cache to the fdlimit.
+ FileAccessorCache::Global().SetCacheSize(fdLimit);
+
+ // TODO: Register object destructor to clear accessor cache
+ RegisterSharedCacheControllerDestructor();
+
+ static SharedCacheViewType type;
+ BinaryViewType::Register(&type);
+}
+
+Ref<BinaryView> SharedCacheViewType::Create(BinaryView* data)
+{
+ return new SharedCacheView(VIEW_NAME, data, false);
+}
+
+Ref<Settings> SharedCacheViewType::GetLoadSettingsForData(BinaryView* data)
+{
+ Ref<BinaryView> viewRef = Parse(data);
+ if (!viewRef || !viewRef->Init())
+ {
+ LogWarn("Failed to initialize view of type '%s'. Generating default load settings.", GetName().c_str());
+ viewRef = data;
+ }
+
+ Ref<Settings> settings = GetDefaultLoadSettingsForData(viewRef);
+
+ // specify default load settings that can be overridden
+ std::vector<std::string> overrides = {"loader.imageBase", "loader.platform"};
+ settings->UpdateProperty("loader.imageBase", "message", "Note: File indicates image is not relocatable.");
+
+ for (const auto& override : overrides)
+ {
+ if (settings->Contains(override))
+ settings->UpdateProperty(override, "readOnly", false);
+ }
+
+ Ref<Settings> programSettings = Settings::Instance();
+ programSettings->Set("analysis.workflows.functionWorkflow", "core.function.sharedCache", viewRef);
+
+ settings->RegisterSetting("loader.dsc.processCFStrings",
+ R"({
+ "title" : "Process CFString Metadata",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Processes CoreFoundation strings, applying string values from encoded metadata"
+ })");
+
+ settings->RegisterSetting("loader.dsc.autoLoadPattern",
+ R"({
+ "title" : "Image Auto-Load Regex Pattern",
+ "type" : "string",
+ "default" : ".*libsystem_c.dylib",
+ "description" : "A regex pattern to auto load matching images at the end of view init, defaults to the system_c image only."
+ })");
+
+ settings->RegisterSetting("loader.dsc.processObjC",
+ R"({
+ "title" : "Process Objective-C Metadata",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Processes Objective-C metadata, applying class and method names from encoded metadata"
+ })");
+
+ settings->RegisterSetting("loader.dsc.regionFilter",
+ R"({
+ "title" : "Region Regex Filter",
+ "type" : "string",
+ "default" : "LINKEDIT",
+ "description" : "Regex filter for region names to skip loading, by default this filters out the link edit region which is not necessary to be applied to the view."
+ })");
+
+ settings->RegisterSetting("loader.dsc.autoLoadObjCStubRequirements",
+ R"({
+ "title" : "Auto-Load Objective-C Stub Requirements",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Automatically loads segments required for inlining Objective-C stubs. Recommended you keep this on."
+ })");
+
+ settings->RegisterSetting("loader.dsc.autoLoadStubsAndDyldData",
+ R"({
+ "title" : "Auto-Load Stub Islands",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Automatically loads stub and dylddata regions that contain just branches and pointers. These are required for resolving stub names, and performance impact is minimal. Recommended you keep this on."
+ })");
+
+ settings->RegisterSetting("loader.dsc.processFunctionStarts",
+ R"({
+ "title" : "Process Mach-O Function Starts Tables",
+ "type" : "boolean",
+ "default" : true,
+ "description" : "Add function starts sourced from the Function Starts tables to the core for analysis."
+ })");
+
+ // Merge existing load settings if they exist. This allows for the selection of a specific object file from a Mach-O
+ // Universal file. The 'Universal' BinaryViewType generates a schema with 'loader.universal.architectures'. This
+ // schema contains an appropriate 'Mach-O' load schema for selecting a specific object file. The embedded schema
+ // contains 'loader.macho.universalImageOffset'.
+ Ref<Settings> loadSettings = viewRef->GetLoadSettings(GetName());
+ if (loadSettings && !loadSettings->IsEmpty())
+ settings->DeserializeSchema(loadSettings->SerializeSchema());
+
+ return settings;
+}
+
+Ref<BinaryView> SharedCacheViewType::Parse(BinaryView* data)
+{
+ return new SharedCacheView(VIEW_NAME, data, true);
+}
+
+bool SharedCacheViewType::IsTypeValidForData(BinaryView* data)
+{
+ if (!data)
+ return false;
+
+ DataBuffer sig = data->ReadBuffer(data->GetStart(), 4);
+ if (sig.GetLength() != 4)
+ return false;
+
+ const char* magic = (char*)sig.GetData();
+ if (strncmp(magic, "dyld", 4) == 0)
+ return true;
+
+ return false;
+}
+
+SharedCacheView::SharedCacheView(const std::string& typeName, BinaryView* data, bool parseOnly) :
+ BinaryView(typeName, data->GetFile(), data), m_parseOnly(parseOnly)
+{
+ CreateLogger("SharedCache");
+ CreateLogger("SharedCache.ObjC");
+}
+
+enum DSCPlatform
+{
+ DSCPlatformMacOS = 1,
+ DSCPlatformiOS = 2,
+ DSCPlatformTVOS = 3,
+ DSCPlatformWatchOS = 4,
+ DSCPlatformBridgeOS = 5, // T1/T2 APL1023/T8012, this is your touchbar/touchid in intel macs. Similar to watchOS.
+ // DSCPlatformMacCatalyst = 6,
+ DSCPlatformiOSSimulator = 7,
+ DSCPlatformTVOSSimulator = 8,
+ DSCPlatformWatchOSSimulator = 9,
+ DSCPlatformVisionOS = 11, // Apple Vision Pro
+ DSCPlatformVisionOSSimulator = 12 // Apple Vision Pro Simulator
+};
+
+bool SharedCacheView::Init()
+{
+ std::string os;
+ std::string arch;
+
+ auto logger = new Logger("SharedCacheView", GetFile()->GetSessionId());
+
+ uint32_t platform;
+ GetParentView()->Read(&platform, 0xd8, 4);
+ char magic[17];
+ GetParentView()->Read(&magic, 0, 16);
+ magic[16] = 0;
+
+ // TODO: Do we want to add any warnings about platform support here?
+ // TODO: Do we still consider macos experimental?
+ switch (platform)
+ {
+ case DSCPlatformMacOS:
+ case DSCPlatformTVOS:
+ case DSCPlatformTVOSSimulator:
+ os = "mac";
+ break;
+ case DSCPlatformiOS:
+ case DSCPlatformiOSSimulator:
+ case DSCPlatformVisionOS:
+ case DSCPlatformVisionOSSimulator:
+ os = "ios";
+ break;
+ // armv7 or slide info v1 (unsupported)
+ case DSCPlatformWatchOS:
+ case DSCPlatformWatchOSSimulator:
+ case DSCPlatformBridgeOS:
+ default:
+ logger->LogError("Unknown platform: %d", platform);
+ return false;
+ }
+
+ if (std::string(magic) == "dyld_v1 arm64" || std::string(magic) == "dyld_v1 arm64e"
+ || std::string(magic) == "dyld_v1arm64_32")
+ {
+ arch = "aarch64";
+ }
+ else if (std::string(magic) == "dyld_v1 x86_64" || std::string(magic) == "dyld_v1 x86_64h")
+ {
+ arch = "x86_64";
+ }
+ else
+ {
+ logger->LogError("Unknown magic: %s", magic);
+ return false;
+ }
+
+ SetDefaultPlatform(Platform::GetByName(os + "-" + arch));
+ SetDefaultArchitecture(Architecture::GetByName(arch));
+
+ Ref<Settings> settings = GetLoadSettings(GetTypeName());
+
+ if (!settings)
+ {
+ Ref<Settings> programSettings = Settings::Instance();
+ programSettings->Set("analysis.workflows.functionWorkflow", "core.function.sharedCache", this);
+ }
+
+ if (m_parseOnly)
+ return true;
+
+ QualifiedNameAndType headerType;
+ std::string err;
+
+ ParseTypeString(
+ "\n"
+ "\tstruct dyld_cache_header\n"
+ "\t{\n"
+ "\t\tchar magic[16];\t\t\t\t\t // e.g. \"dyld_v0 i386\"\n"
+ "\t\tuint32_t mappingOffset;\t\t\t // file offset to first dyld_cache_mapping_info\n"
+ "\t\tuint32_t mappingCount;\t\t\t // number of dyld_cache_mapping_info entries\n"
+ "\t\tuint32_t imagesOffsetOld;\t\t // UNUSED: moved to imagesOffset to prevent older dsc_extarctors from "
+ "crashing\n"
+ "\t\tuint32_t imagesCountOld;\t\t // UNUSED: moved to imagesCount to prevent older dsc_extarctors from "
+ "crashing\n"
+ "\t\tuint64_t dyldBaseAddress;\t\t // base address of dyld when cache was built\n"
+ "\t\tuint64_t codeSignatureOffset;\t // file offset of code signature blob\n"
+ "\t\tuint64_t codeSignatureSize;\t\t // size of code signature blob (zero means to end of file)\n"
+ "\t\tuint64_t slideInfoOffsetUnused;\t // unused. Used to be file offset of kernel slid info\n"
+ "\t\tuint64_t slideInfoSizeUnused;\t // unused. Used to be size of kernel slid info\n"
+ "\t\tuint64_t localSymbolsOffset;\t // file offset of where local symbols are stored\n"
+ "\t\tuint64_t localSymbolsSize;\t\t // size of local symbols information\n"
+ "\t\tuint8_t uuid[16];\t\t\t\t // unique value for each shared cache file\n"
+ "\t\tuint64_t cacheType;\t\t\t\t // 0 for development, 1 for production // Kat: , 2 for iOS 16?\n"
+ "\t\tuint32_t branchPoolsOffset;\t\t // file offset to table of uint64_t pool addresses\n"
+ "\t\tuint32_t branchPoolsCount;\t\t // number of uint64_t entries\n"
+ "\t\tuint64_t accelerateInfoAddr;\t // (unslid) address of optimization info\n"
+ "\t\tuint64_t accelerateInfoSize;\t // size of optimization info\n"
+ "\t\tuint64_t imagesTextOffset;\t\t // file offset to first dyld_cache_image_text_info\n"
+ "\t\tuint64_t imagesTextCount;\t\t // number of dyld_cache_image_text_info entries\n"
+ "\t\tuint64_t patchInfoAddr;\t\t\t // (unslid) address of dyld_cache_patch_info\n"
+ "\t\tuint64_t patchInfoSize;\t // Size of all of the patch information pointed to via the "
+ "dyld_cache_patch_info\n"
+ "\t\tuint64_t otherImageGroupAddrUnused;\t // unused\n"
+ "\t\tuint64_t otherImageGroupSizeUnused;\t // unused\n"
+ "\t\tuint64_t progClosuresAddr;\t\t\t // (unslid) address of list of program launch closures\n"
+ "\t\tuint64_t progClosuresSize;\t\t\t // size of list of program launch closures\n"
+ "\t\tuint64_t progClosuresTrieAddr;\t\t // (unslid) address of trie of indexes into program launch closures\n"
+ "\t\tuint64_t progClosuresTrieSize;\t\t // size of trie of indexes into program launch closures\n"
+ "\t\tuint32_t platform;\t\t\t\t\t // platform number (macOS=1, etc)\n"
+ "\t\tuint32_t formatVersion : 8,\t\t\t // dyld3::closure::kFormatVersion\n"
+ "\t\t\tdylibsExpectedOnDisk : 1, // dyld should expect the dylib exists on disk and to compare inode/mtime to "
+ "see if cache is valid\n"
+ "\t\t\tsimulator : 1,\t\t\t // for simulator of specified platform\n"
+ "\t\t\tlocallyBuiltCache : 1,\t // 0 for B&I built cache, 1 for locally built cache\n"
+ "\t\t\tbuiltFromChainedFixups : 1,\t // some dylib in cache was built using chained fixups, so patch tables "
+ "must be used for overrides\n"
+ "\t\t\tpadding : 20;\t\t\t\t // TBD\n"
+ "\t\tuint64_t sharedRegionStart;\t\t // base load address of cache if not slid\n"
+ "\t\tuint64_t sharedRegionSize;\t\t // overall size required to map the cache and all subCaches, if any\n"
+ "\t\tuint64_t maxSlide;\t\t\t\t // runtime slide of cache can be between zero and this value\n"
+ "\t\tuint64_t dylibsImageArrayAddr;\t // (unslid) address of ImageArray for dylibs in this cache\n"
+ "\t\tuint64_t dylibsImageArraySize;\t // size of ImageArray for dylibs in this cache\n"
+ "\t\tuint64_t dylibsTrieAddr;\t\t // (unslid) address of trie of indexes of all cached dylibs\n"
+ "\t\tuint64_t dylibsTrieSize;\t\t // size of trie of cached dylib paths\n"
+ "\t\tuint64_t otherImageArrayAddr;\t // (unslid) address of ImageArray for dylibs and bundles with dlopen "
+ "closures\n"
+ "\t\tuint64_t otherImageArraySize;\t // size of ImageArray for dylibs and bundles with dlopen closures\n"
+ "\t\tuint64_t otherTrieAddr;\t // (unslid) address of trie of indexes of all dylibs and bundles with dlopen "
+ "closures\n"
+ "\t\tuint64_t otherTrieSize;\t // size of trie of dylibs and bundles with dlopen closures\n"
+ "\t\tuint32_t mappingWithSlideOffset;\t\t // file offset to first dyld_cache_mapping_and_slide_info\n"
+ "\t\tuint32_t mappingWithSlideCount;\t\t\t // number of dyld_cache_mapping_and_slide_info entries\n"
+ "\t\tuint64_t dylibsPBLStateArrayAddrUnused;\t // unused\n"
+ "\t\tuint64_t dylibsPBLSetAddr;\t\t\t\t // (unslid) address of PrebuiltLoaderSet of all cached dylibs\n"
+ "\t\tuint64_t programsPBLSetPoolAddr;\t\t // (unslid) address of pool of PrebuiltLoaderSet for each program\n"
+ "\t\tuint64_t programsPBLSetPoolSize;\t\t // size of pool of PrebuiltLoaderSet for each program\n"
+ "\t\tuint64_t programTrieAddr;\t\t\t\t // (unslid) address of trie mapping program path to PrebuiltLoaderSet\n"
+ "\t\tuint32_t programTrieSize;\n"
+ "\t\tuint32_t osVersion;\t\t\t\t// OS Version of dylibs in this cache for the main platform\n"
+ "\t\tuint32_t altPlatform;\t\t\t// e.g. iOSMac on macOS\n"
+ "\t\tuint32_t altOsVersion;\t\t\t// e.g. 14.0 for iOSMac\n"
+ "\t\tuint64_t swiftOptsOffset;\t\t// file offset to Swift optimizations header\n"
+ "\t\tuint64_t swiftOptsSize;\t\t\t// size of Swift optimizations header\n"
+ "\t\tuint32_t subCacheArrayOffset;\t// file offset to first dyld_subcache_entry\n"
+ "\t\tuint32_t subCacheArrayCount;\t// number of subCache entries\n"
+ "\t\tuint8_t symbolFileUUID[16];\t\t// unique value for the shared cache file containing unmapped local "
+ "symbols\n"
+ "\t\tuint64_t rosettaReadOnlyAddr;\t// (unslid) address of the start of where Rosetta can add "
+ "read-only/executable data\n"
+ "\t\tuint64_t rosettaReadOnlySize;\t// maximum size of the Rosetta read-only/executable region\n"
+ "\t\tuint64_t rosettaReadWriteAddr;\t// (unslid) address of the start of where Rosetta can add read-write "
+ "data\n"
+ "\t\tuint64_t rosettaReadWriteSize;\t// maximum size of the Rosetta read-write region\n"
+ "\t\tuint32_t imagesOffset;\t\t\t// file offset to first dyld_cache_image_info\n"
+ "\t\tuint32_t imagesCount;\t\t\t// number of dyld_cache_image_info entries\n"
+ "\t\tuint32_t cacheSubType; // 0 for development, 1 for production, when cacheType is "
+ "multi-cache(2)\n"
+ "\t\tuint64_t objcOptsOffset; // VM offset from cache_header* to ObjC optimizations header\n"
+ "\t\tuint64_t objcOptsSize; // size of ObjC optimizations header\n"
+ "\t\tuint64_t cacheAtlasOffset; // VM offset from cache_header* to embedded cache atlas for process "
+ "introspection\n"
+ "\t\tuint64_t cacheAtlasSize; // size of embedded cache atlas\n"
+ "\t\tuint64_t dynamicDataOffset; // VM offset from cache_header* to the location of "
+ "dyld_cache_dynamic_data_header\n"
+ "\t\tuint64_t dynamicDataMaxSize; // maximum size of space reserved from dynamic data\n"
+ "\t\tuint32_t tproMappingsOffset; // file offset to first dyld_cache_tpro_mapping_info\n"
+ "\t\tuint32_t tproMappingsCount; // number of dyld_cache_tpro_mapping_info entries\n"
+ "\t};",
+ headerType, err);
+
+ if (!err.empty() || !headerType.type)
+ {
+ logger->LogError("Failed to parse header type: %s", err.c_str());
+ return false;
+ }
+
+ // Add Mach-O file header type info
+ EnumerationBuilder cpuTypeBuilder;
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ANY", MACHO_CPU_TYPE_ANY);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_VAX", MACHO_CPU_TYPE_VAX);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC680x0", MACHO_CPU_TYPE_MC680x0);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86", MACHO_CPU_TYPE_X86);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_X86_64", MACHO_CPU_TYPE_X86_64);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MIPS", MACHO_CPU_TYPE_MIPS);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC98000", MACHO_CPU_TYPE_MC98000);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_HPPA", MACHO_CPU_TYPE_HPPA);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM", MACHO_CPU_TYPE_ARM);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64", MACHO_CPU_TYPE_ARM64);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ARM64_32", MACHO_CPU_TYPE_ARM64_32);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_MC88000", MACHO_CPU_TYPE_MC88000);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_SPARC", MACHO_CPU_TYPE_SPARC);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_I860", MACHO_CPU_TYPE_I860);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_ALPHA", MACHO_CPU_TYPE_ALPHA);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC", MACHO_CPU_TYPE_POWERPC);
+ cpuTypeBuilder.AddMemberWithValue("CPU_TYPE_POWERPC64", MACHO_CPU_TYPE_POWERPC64);
+ Ref<Enumeration> cpuTypeEnum = cpuTypeBuilder.Finalize();
+
+ Ref<Type> cpuTypeEnumType = Type::EnumerationType(nullptr, cpuTypeEnum, 4, false);
+ std::string cpuTypeEnumName = "cpu_type_t";
+ std::string cpuTypeEnumId = Type::GenerateAutoTypeId("macho", cpuTypeEnumName);
+ DefineType(cpuTypeEnumId, cpuTypeEnumName, cpuTypeEnumType);
+
+ EnumerationBuilder fileTypeBuilder;
+ fileTypeBuilder.AddMemberWithValue("MH_OBJECT", MH_OBJECT);
+ fileTypeBuilder.AddMemberWithValue("MH_EXECUTE", MH_EXECUTE);
+ fileTypeBuilder.AddMemberWithValue("MH_FVMLIB", MH_FVMLIB);
+ fileTypeBuilder.AddMemberWithValue("MH_CORE", MH_CORE);
+ fileTypeBuilder.AddMemberWithValue("MH_PRELOAD", MH_PRELOAD);
+ fileTypeBuilder.AddMemberWithValue("MH_DYLIB", MH_DYLIB);
+ fileTypeBuilder.AddMemberWithValue("MH_DYLINKER", MH_DYLINKER);
+ fileTypeBuilder.AddMemberWithValue("MH_BUNDLE", MH_BUNDLE);
+ fileTypeBuilder.AddMemberWithValue("MH_DYLIB_STUB", MH_DYLIB_STUB);
+ fileTypeBuilder.AddMemberWithValue("MH_DSYM", MH_DSYM);
+ fileTypeBuilder.AddMemberWithValue("MH_KEXT_BUNDLE", MH_KEXT_BUNDLE);
+ fileTypeBuilder.AddMemberWithValue("MH_FILESET", MH_FILESET);
+ Ref<Enumeration> fileTypeEnum = fileTypeBuilder.Finalize();
+
+ Ref<Type> fileTypeEnumType = Type::EnumerationType(nullptr, fileTypeEnum, 4, false);
+ std::string fileTypeEnumName = "file_type_t";
+ std::string fileTypeEnumId = Type::GenerateAutoTypeId("macho", fileTypeEnumName);
+ DefineType(fileTypeEnumId, fileTypeEnumName, fileTypeEnumType);
+
+ EnumerationBuilder flagsTypeBuilder;
+ flagsTypeBuilder.AddMemberWithValue("MH_NOUNDEFS", MH_NOUNDEFS);
+ flagsTypeBuilder.AddMemberWithValue("MH_INCRLINK", MH_INCRLINK);
+ flagsTypeBuilder.AddMemberWithValue("MH_DYLDLINK", MH_DYLDLINK);
+ flagsTypeBuilder.AddMemberWithValue("MH_BINDATLOAD", MH_BINDATLOAD);
+ flagsTypeBuilder.AddMemberWithValue("MH_PREBOUND", MH_PREBOUND);
+ flagsTypeBuilder.AddMemberWithValue("MH_SPLIT_SEGS", MH_SPLIT_SEGS);
+ flagsTypeBuilder.AddMemberWithValue("MH_LAZY_INIT", MH_LAZY_INIT);
+ flagsTypeBuilder.AddMemberWithValue("MH_TWOLEVEL", MH_TWOLEVEL);
+ flagsTypeBuilder.AddMemberWithValue("MH_FORCE_FLAT", MH_FORCE_FLAT);
+ flagsTypeBuilder.AddMemberWithValue("MH_NOMULTIDEFS", MH_NOMULTIDEFS);
+ flagsTypeBuilder.AddMemberWithValue("MH_NOFIXPREBINDING", MH_NOFIXPREBINDING);
+ flagsTypeBuilder.AddMemberWithValue("MH_PREBINDABLE", MH_PREBINDABLE);
+ flagsTypeBuilder.AddMemberWithValue("MH_ALLMODSBOUND", MH_ALLMODSBOUND);
+ flagsTypeBuilder.AddMemberWithValue("MH_SUBSECTIONS_VIA_SYMBOLS", MH_SUBSECTIONS_VIA_SYMBOLS);
+ flagsTypeBuilder.AddMemberWithValue("MH_CANONICAL", MH_CANONICAL);
+ flagsTypeBuilder.AddMemberWithValue("MH_WEAK_DEFINES", MH_WEAK_DEFINES);
+ flagsTypeBuilder.AddMemberWithValue("MH_BINDS_TO_WEAK", MH_BINDS_TO_WEAK);
+ flagsTypeBuilder.AddMemberWithValue("MH_ALLOW_STACK_EXECUTION", MH_ALLOW_STACK_EXECUTION);
+ flagsTypeBuilder.AddMemberWithValue("MH_ROOT_SAFE", MH_ROOT_SAFE);
+ flagsTypeBuilder.AddMemberWithValue("MH_SETUID_SAFE", MH_SETUID_SAFE);
+ flagsTypeBuilder.AddMemberWithValue("MH_NO_REEXPORTED_DYLIBS", MH_NO_REEXPORTED_DYLIBS);
+ flagsTypeBuilder.AddMemberWithValue("MH_PIE", MH_PIE);
+ flagsTypeBuilder.AddMemberWithValue("MH_DEAD_STRIPPABLE_DYLIB", MH_DEAD_STRIPPABLE_DYLIB);
+ flagsTypeBuilder.AddMemberWithValue("MH_HAS_TLV_DESCRIPTORS", MH_HAS_TLV_DESCRIPTORS);
+ flagsTypeBuilder.AddMemberWithValue("MH_NO_HEAP_EXECUTION", MH_NO_HEAP_EXECUTION);
+ flagsTypeBuilder.AddMemberWithValue("MH_APP_EXTENSION_SAFE", _MH_APP_EXTENSION_SAFE);
+ flagsTypeBuilder.AddMemberWithValue("MH_NLIST_OUTOFSYNC_WITH_DYLDINFO", _MH_NLIST_OUTOFSYNC_WITH_DYLDINFO);
+ flagsTypeBuilder.AddMemberWithValue("MH_SIM_SUPPORT", _MH_SIM_SUPPORT);
+ flagsTypeBuilder.AddMemberWithValue("MH_DYLIB_IN_CACHE", _MH_DYLIB_IN_CACHE);
+ Ref<Enumeration> flagsTypeEnum = flagsTypeBuilder.Finalize();
+
+ Ref<Type> flagsTypeEnumType = Type::EnumerationType(nullptr, flagsTypeEnum, 4, false);
+ std::string flagsTypeEnumName = "flags_type_t";
+ std::string flagsTypeEnumId = Type::GenerateAutoTypeId("macho", flagsTypeEnumName);
+ DefineType(flagsTypeEnumId, flagsTypeEnumName, flagsTypeEnumType);
+
+ StructureBuilder machoHeaderBuilder;
+ machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "magic");
+ machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("cpu_type_t")), "cputype");
+ machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "cpusubtype");
+ machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("file_type_t")), "filetype");
+ machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "ncmds");
+ machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "sizeofcmds");
+ machoHeaderBuilder.AddMember(Type::NamedType(this, QualifiedName("flags_type_t")), "flags");
+ if (GetAddressSize() == 8)
+ machoHeaderBuilder.AddMember(Type::IntegerType(4, false), "reserved");
+ Ref<Structure> machoHeaderStruct = machoHeaderBuilder.Finalize();
+ QualifiedName headerName = (GetAddressSize() == 8) ? std::string("mach_header_64") : std::string("mach_header");
+
+ std::string headerTypeId = Type::GenerateAutoTypeId("macho", headerName);
+ Ref<Type> machoHeaderType = Type::StructureType(machoHeaderStruct);
+ DefineType(headerTypeId, headerName, machoHeaderType);
+
+ EnumerationBuilder cmdTypeBuilder;
+ cmdTypeBuilder.AddMemberWithValue("LC_REQ_DYLD", LC_REQ_DYLD);
+ cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT", LC_SEGMENT);
+ cmdTypeBuilder.AddMemberWithValue("LC_SYMTAB", LC_SYMTAB);
+ cmdTypeBuilder.AddMemberWithValue("LC_SYMSEG", LC_SYMSEG);
+ cmdTypeBuilder.AddMemberWithValue("LC_THREAD", LC_THREAD);
+ cmdTypeBuilder.AddMemberWithValue("LC_UNIXTHREAD", LC_UNIXTHREAD);
+ cmdTypeBuilder.AddMemberWithValue("LC_LOADFVMLIB", LC_LOADFVMLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_IDFVMLIB", LC_IDFVMLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_IDENT", LC_IDENT);
+ cmdTypeBuilder.AddMemberWithValue("LC_FVMFILE", LC_FVMFILE);
+ cmdTypeBuilder.AddMemberWithValue("LC_PREPAGE", LC_PREPAGE);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYSYMTAB", LC_DYSYMTAB);
+ cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLIB", LC_LOAD_DYLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLIB", LC_ID_DYLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_LOAD_DYLINKER", LC_LOAD_DYLINKER);
+ cmdTypeBuilder.AddMemberWithValue("LC_ID_DYLINKER", LC_ID_DYLINKER);
+ cmdTypeBuilder.AddMemberWithValue("LC_PREBOUND_DYLIB", LC_PREBOUND_DYLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES", LC_ROUTINES);
+ cmdTypeBuilder.AddMemberWithValue("LC_SUB_FRAMEWORK", LC_SUB_FRAMEWORK);
+ cmdTypeBuilder.AddMemberWithValue("LC_SUB_UMBRELLA", LC_SUB_UMBRELLA);
+ cmdTypeBuilder.AddMemberWithValue("LC_SUB_CLIENT", LC_SUB_CLIENT);
+ cmdTypeBuilder.AddMemberWithValue("LC_SUB_LIBRARY", LC_SUB_LIBRARY);
+ cmdTypeBuilder.AddMemberWithValue("LC_TWOLEVEL_HINTS", LC_TWOLEVEL_HINTS);
+ cmdTypeBuilder.AddMemberWithValue("LC_PREBIND_CKSUM", LC_PREBIND_CKSUM);
+ cmdTypeBuilder.AddMemberWithValue("LC_LOAD_WEAK_DYLIB", LC_LOAD_WEAK_DYLIB); // (0x18 | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_64", LC_SEGMENT_64);
+ cmdTypeBuilder.AddMemberWithValue("LC_ROUTINES_64", LC_ROUTINES_64);
+ cmdTypeBuilder.AddMemberWithValue("LC_UUID", LC_UUID);
+ cmdTypeBuilder.AddMemberWithValue("LC_RPATH", LC_RPATH); // (0x1c | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_CODE_SIGNATURE", LC_CODE_SIGNATURE);
+ cmdTypeBuilder.AddMemberWithValue("LC_SEGMENT_SPLIT_INFO", LC_SEGMENT_SPLIT_INFO);
+ cmdTypeBuilder.AddMemberWithValue("LC_REEXPORT_DYLIB", LC_REEXPORT_DYLIB); // (0x1f | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_LAZY_LOAD_DYLIB", LC_LAZY_LOAD_DYLIB);
+ cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO", LC_ENCRYPTION_INFO);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO", LC_DYLD_INFO);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLD_INFO_ONLY", LC_DYLD_INFO_ONLY); // (0x22 | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_LOAD_UPWARD_DYLIB", LC_LOAD_UPWARD_DYLIB); // (0x23 | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_MACOSX", LC_VERSION_MIN_MACOSX);
+ cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_IPHONEOS", LC_VERSION_MIN_IPHONEOS);
+ cmdTypeBuilder.AddMemberWithValue("LC_FUNCTION_STARTS", LC_FUNCTION_STARTS);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLD_ENVIRONMENT", LC_DYLD_ENVIRONMENT);
+ cmdTypeBuilder.AddMemberWithValue("LC_MAIN", LC_MAIN); // (0x28 | LC_REQ_DYLD)
+ cmdTypeBuilder.AddMemberWithValue("LC_DATA_IN_CODE", LC_DATA_IN_CODE);
+ cmdTypeBuilder.AddMemberWithValue("LC_SOURCE_VERSION", LC_SOURCE_VERSION);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLIB_CODE_SIGN_DRS", LC_DYLIB_CODE_SIGN_DRS);
+ cmdTypeBuilder.AddMemberWithValue("LC_ENCRYPTION_INFO_64", _LC_ENCRYPTION_INFO_64);
+ cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTION", _LC_LINKER_OPTION);
+ cmdTypeBuilder.AddMemberWithValue("LC_LINKER_OPTIMIZATION_HINT", _LC_LINKER_OPTIMIZATION_HINT);
+ cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_TVOS", _LC_VERSION_MIN_TVOS);
+ cmdTypeBuilder.AddMemberWithValue("LC_VERSION_MIN_WATCHOS", LC_VERSION_MIN_WATCHOS);
+ cmdTypeBuilder.AddMemberWithValue("LC_NOTE", LC_NOTE);
+ cmdTypeBuilder.AddMemberWithValue("LC_BUILD_VERSION", LC_BUILD_VERSION);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLD_EXPORTS_TRIE", LC_DYLD_EXPORTS_TRIE);
+ cmdTypeBuilder.AddMemberWithValue("LC_DYLD_CHAINED_FIXUPS", LC_DYLD_CHAINED_FIXUPS);
+ cmdTypeBuilder.AddMemberWithValue("LC_FILESET_ENTRY", LC_FILESET_ENTRY);
+ Ref<Enumeration> cmdTypeEnum = cmdTypeBuilder.Finalize();
+
+ Ref<Type> cmdTypeEnumType = Type::EnumerationType(nullptr, cmdTypeEnum, 4, false);
+ std::string cmdTypeEnumName = "load_command_type_t";
+ std::string cmdTypeEnumId = Type::GenerateAutoTypeId("macho", cmdTypeEnumName);
+ DefineType(cmdTypeEnumId, cmdTypeEnumName, cmdTypeEnumType);
+
+ StructureBuilder loadCommandBuilder;
+ loadCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ loadCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ Ref<Structure> loadCommandStruct = loadCommandBuilder.Finalize();
+ QualifiedName loadCommandName = std::string("load_command");
+ std::string loadCommandTypeId = Type::GenerateAutoTypeId("macho", loadCommandName);
+ Ref<Type> loadCommandType = Type::StructureType(loadCommandStruct);
+ DefineType(loadCommandTypeId, loadCommandName, loadCommandType);
+
+ EnumerationBuilder protTypeBuilder;
+ protTypeBuilder.AddMemberWithValue("VM_PROT_NONE", MACHO_VM_PROT_NONE);
+ protTypeBuilder.AddMemberWithValue("VM_PROT_READ", MACHO_VM_PROT_READ);
+ protTypeBuilder.AddMemberWithValue("VM_PROT_WRITE", MACHO_VM_PROT_WRITE);
+ protTypeBuilder.AddMemberWithValue("VM_PROT_EXECUTE", MACHO_VM_PROT_EXECUTE);
+ // protTypeBuilder.AddMemberWithValue("VM_PROT_DEFAULT", MACHO_VM_PROT_DEFAULT);
+ // protTypeBuilder.AddMemberWithValue("VM_PROT_ALL", MACHO_VM_PROT_ALL);
+ protTypeBuilder.AddMemberWithValue("VM_PROT_NO_CHANGE", MACHO_VM_PROT_NO_CHANGE);
+ protTypeBuilder.AddMemberWithValue("VM_PROT_COPY_OR_WANTS_COPY", MACHO_VM_PROT_COPY);
+ // protTypeBuilder.AddMemberWithValue("VM_PROT_WANTS_COPY", MACHO_VM_PROT_WANTS_COPY);
+ Ref<Enumeration> protTypeEnum = protTypeBuilder.Finalize();
+
+ Ref<Type> protTypeEnumType = Type::EnumerationType(nullptr, protTypeEnum, 4, false);
+ std::string protTypeEnumName = "vm_prot_t";
+ std::string protTypeEnumId = Type::GenerateAutoTypeId("macho", protTypeEnumName);
+ DefineType(protTypeEnumId, protTypeEnumName, protTypeEnumType);
+
+ EnumerationBuilder segFlagsTypeBuilder;
+ segFlagsTypeBuilder.AddMemberWithValue("SG_HIGHVM", SG_HIGHVM);
+ segFlagsTypeBuilder.AddMemberWithValue("SG_FVMLIB", SG_FVMLIB);
+ segFlagsTypeBuilder.AddMemberWithValue("SG_NORELOC", SG_NORELOC);
+ segFlagsTypeBuilder.AddMemberWithValue("SG_PROTECTED_VERSION_1", SG_PROTECTED_VERSION_1);
+ Ref<Enumeration> segFlagsTypeEnum = segFlagsTypeBuilder.Finalize();
+
+ Ref<Type> segFlagsTypeEnumType = Type::EnumerationType(nullptr, segFlagsTypeEnum, 4, false);
+ std::string segFlagsTypeEnumName = "sg_flags_t";
+ std::string segFlagsTypeEnumId = Type::GenerateAutoTypeId("macho", segFlagsTypeEnumName);
+ DefineType(segFlagsTypeEnumId, segFlagsTypeEnumName, segFlagsTypeEnumType);
+
+ StructureBuilder loadSegmentCommandBuilder;
+ loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ loadSegmentCommandBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmaddr");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "vmsize");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "fileoff");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "filesize");
+ loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot");
+ loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot");
+ loadSegmentCommandBuilder.AddMember(Type::IntegerType(4, false), "nsects");
+ loadSegmentCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags");
+ Ref<Structure> loadSegmentCommandStruct = loadSegmentCommandBuilder.Finalize();
+ QualifiedName loadSegmentCommandName = std::string("segment_command");
+ std::string loadSegmentCommandTypeId = Type::GenerateAutoTypeId("macho", loadSegmentCommandName);
+ Ref<Type> loadSegmentCommandType = Type::StructureType(loadSegmentCommandStruct);
+ DefineType(loadSegmentCommandTypeId, loadSegmentCommandName, loadSegmentCommandType);
+
+ StructureBuilder loadSegmentCommand64Builder;
+ loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ loadSegmentCommand64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmaddr");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "vmsize");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "fileoff");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(8, false), "filesize");
+ loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "maxprot");
+ loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("vm_prot_t")), "initprot");
+ loadSegmentCommand64Builder.AddMember(Type::IntegerType(4, false), "nsects");
+ loadSegmentCommand64Builder.AddMember(Type::NamedType(this, QualifiedName("sg_flags_t")), "flags");
+ Ref<Structure> loadSegmentCommand64Struct = loadSegmentCommand64Builder.Finalize();
+ QualifiedName loadSegment64CommandName = std::string("segment_command_64");
+ std::string loadSegment64CommandTypeId = Type::GenerateAutoTypeId("macho", loadSegment64CommandName);
+ Ref<Type> loadSegment64CommandType = Type::StructureType(loadSegmentCommand64Struct);
+ DefineType(loadSegment64CommandTypeId, loadSegment64CommandName, loadSegment64CommandType);
+
+ StructureBuilder sectionBuilder;
+ sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname");
+ sectionBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "addr");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "size");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "offset");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "align");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "reloff");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "nreloc");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "flags");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved1");
+ sectionBuilder.AddMember(Type::IntegerType(4, false), "reserved2");
+ Ref<Structure> sectionStruct = sectionBuilder.Finalize();
+ QualifiedName sectionName = std::string("section");
+ std::string sectionTypeId = Type::GenerateAutoTypeId("macho", sectionName);
+ Ref<Type> sectionType = Type::StructureType(sectionStruct);
+ DefineType(sectionTypeId, sectionName, sectionType);
+
+ StructureBuilder section64Builder;
+ section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "sectname");
+ section64Builder.AddMember(Type::ArrayType(Type::IntegerType(1, true), 16), "segname");
+ section64Builder.AddMember(Type::IntegerType(8, false), "addr");
+ section64Builder.AddMember(Type::IntegerType(8, false), "size");
+ section64Builder.AddMember(Type::IntegerType(4, false), "offset");
+ section64Builder.AddMember(Type::IntegerType(4, false), "align");
+ section64Builder.AddMember(Type::IntegerType(4, false), "reloff");
+ section64Builder.AddMember(Type::IntegerType(4, false), "nreloc");
+ section64Builder.AddMember(Type::IntegerType(4, false), "flags");
+ section64Builder.AddMember(Type::IntegerType(4, false), "reserved1");
+ section64Builder.AddMember(Type::IntegerType(4, false), "reserved2");
+ section64Builder.AddMember(Type::IntegerType(4, false), "reserved3");
+ Ref<Structure> section64Struct = section64Builder.Finalize();
+ QualifiedName section64Name = std::string("section_64");
+ std::string section64TypeId = Type::GenerateAutoTypeId("macho", section64Name);
+ Ref<Type> section64Type = Type::StructureType(section64Struct);
+ DefineType(section64TypeId, section64Name, section64Type);
+
+ StructureBuilder symtabBuilder;
+ symtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ symtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ symtabBuilder.AddMember(Type::IntegerType(4, false), "symoff");
+ symtabBuilder.AddMember(Type::IntegerType(4, false), "nsyms");
+ symtabBuilder.AddMember(Type::IntegerType(4, false), "stroff");
+ symtabBuilder.AddMember(Type::IntegerType(4, false), "strsize");
+ Ref<Structure> symtabStruct = symtabBuilder.Finalize();
+ QualifiedName symtabName = std::string("symtab");
+ std::string symtabTypeId = Type::GenerateAutoTypeId("macho", symtabName);
+ Ref<Type> symtabType = Type::StructureType(symtabStruct);
+ DefineType(symtabTypeId, symtabName, symtabType);
+
+ StructureBuilder dynsymtabBuilder;
+ dynsymtabBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ilocalsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocalsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iextdefsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextdefsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "iundefsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nundefsym");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "tocoff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "ntoc");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "modtaboff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nmodtab");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extrefsymoff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrefsyms");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "indirectsymoff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nindirectsyms");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "extreloff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nextrel");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "locreloff");
+ dynsymtabBuilder.AddMember(Type::IntegerType(4, false), "nlocrel");
+ Ref<Structure> dynsymtabStruct = dynsymtabBuilder.Finalize();
+ QualifiedName dynsymtabName = std::string("dynsymtab");
+ std::string dynsymtabTypeId = Type::GenerateAutoTypeId("macho", dynsymtabName);
+ Ref<Type> dynsymtabType = Type::StructureType(dynsymtabStruct);
+ DefineType(dynsymtabTypeId, dynsymtabName, dynsymtabType);
+
+ StructureBuilder uuidBuilder;
+ uuidBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ uuidBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ uuidBuilder.AddMember(Type::ArrayType(Type::IntegerType(1, false), 16), "uuid");
+ Ref<Structure> uuidStruct = uuidBuilder.Finalize();
+ QualifiedName uuidName = std::string("uuid");
+ std::string uuidTypeId = Type::GenerateAutoTypeId("macho", uuidName);
+ Ref<Type> uuidType = Type::StructureType(uuidStruct);
+ DefineType(uuidTypeId, uuidName, uuidType);
+
+ StructureBuilder linkeditDataBuilder;
+ linkeditDataBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "dataoff");
+ linkeditDataBuilder.AddMember(Type::IntegerType(4, false), "datasize");
+ Ref<Structure> linkeditDataStruct = linkeditDataBuilder.Finalize();
+ QualifiedName linkeditDataName = std::string("linkedit_data");
+ std::string linkeditDataTypeId = Type::GenerateAutoTypeId("macho", linkeditDataName);
+ Ref<Type> linkeditDataType = Type::StructureType(linkeditDataStruct);
+ DefineType(linkeditDataTypeId, linkeditDataName, linkeditDataType);
+
+ StructureBuilder encryptionInfoBuilder;
+ encryptionInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptoff");
+ encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptsize");
+ encryptionInfoBuilder.AddMember(Type::IntegerType(4, false), "cryptid");
+ Ref<Structure> encryptionInfoStruct = encryptionInfoBuilder.Finalize();
+ QualifiedName encryptionInfoName = std::string("encryption_info");
+ std::string encryptionInfoTypeId = Type::GenerateAutoTypeId("macho", encryptionInfoName);
+ Ref<Type> encryptionInfoType = Type::StructureType(encryptionInfoStruct);
+ DefineType(encryptionInfoTypeId, encryptionInfoName, encryptionInfoType);
+
+ StructureBuilder versionMinBuilder;
+ versionMinBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ versionMinBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ versionMinBuilder.AddMember(Type::IntegerType(4, false), "version");
+ versionMinBuilder.AddMember(Type::IntegerType(4, false), "sdk");
+ Ref<Structure> versionMinStruct = versionMinBuilder.Finalize();
+ QualifiedName versionMinName = std::string("version_min");
+ std::string versionMinTypeId = Type::GenerateAutoTypeId("macho", versionMinName);
+ Ref<Type> versionMinType = Type::StructureType(versionMinStruct);
+ DefineType(versionMinTypeId, versionMinName, versionMinType);
+
+ StructureBuilder dyldInfoBuilder;
+ dyldInfoBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_off");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "rebase_size");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_off");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "bind_size");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_off");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "weak_bind_size");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_off");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "lazy_bind_size");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_off");
+ dyldInfoBuilder.AddMember(Type::IntegerType(4, false), "export_size");
+ Ref<Structure> dyldInfoStruct = dyldInfoBuilder.Finalize();
+ QualifiedName dyldInfoName = std::string("dyld_info");
+ std::string dyldInfoTypeId = Type::GenerateAutoTypeId("macho", dyldInfoName);
+ Ref<Type> dyldInfoType = Type::StructureType(dyldInfoStruct);
+ DefineType(dyldInfoTypeId, dyldInfoName, dyldInfoType);
+
+ StructureBuilder dylibBuilder;
+ dylibBuilder.AddMember(Type::IntegerType(4, false), "name");
+ dylibBuilder.AddMember(Type::IntegerType(4, false), "timestamp");
+ dylibBuilder.AddMember(Type::IntegerType(4, false), "current_version");
+ dylibBuilder.AddMember(Type::IntegerType(4, false), "compatibility_version");
+ Ref<Structure> dylibStruct = dylibBuilder.Finalize();
+ QualifiedName dylibName = std::string("dylib");
+ std::string dylibTypeId = Type::GenerateAutoTypeId("macho", dylibName);
+ Ref<Type> dylibType = Type::StructureType(dylibStruct);
+ DefineType(dylibTypeId, dylibName, dylibType);
+
+ StructureBuilder dylibCommandBuilder;
+ dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ dylibCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ dylibCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("dylib")), "dylib");
+ Ref<Structure> dylibCommandStruct = dylibCommandBuilder.Finalize();
+ QualifiedName dylibCommandName = std::string("dylib_command");
+ std::string dylibCommandTypeId = Type::GenerateAutoTypeId("macho", dylibCommandName);
+ Ref<Type> dylibCommandType = Type::StructureType(dylibCommandStruct);
+ DefineType(dylibCommandTypeId, dylibCommandName, dylibCommandType);
+
+ StructureBuilder filesetEntryCommandBuilder;
+ filesetEntryCommandBuilder.AddMember(Type::NamedType(this, QualifiedName("load_command_type_t")), "cmd");
+ filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "cmdsize");
+ filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "vmaddr");
+ filesetEntryCommandBuilder.AddMember(Type::IntegerType(8, false), "fileoff");
+ filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "entry_id");
+ filesetEntryCommandBuilder.AddMember(Type::IntegerType(4, false), "reserved");
+ Ref<Structure> filesetEntryCommandStruct = filesetEntryCommandBuilder.Finalize();
+ QualifiedName filesetEntryCommandName = std::string("fileset_entry_command");
+ std::string filesetEntryCommandTypeId = Type::GenerateAutoTypeId("macho", filesetEntryCommandName);
+ Ref<Type> filesetEntryCommandType = Type::StructureType(filesetEntryCommandStruct);
+ DefineType(filesetEntryCommandTypeId, filesetEntryCommandName, filesetEntryCommandType);
+
+ // uint32_t at 0x10 is offset to mapping table.
+ // first mapping struct in that table is base of primary
+ // first uint64_t in that struct is the base address of the primary
+ // double gpv here because DSCRaw explicitly stops at the start of this mapping table
+ uint64_t basePointer = 0;
+ GetParentView()->Read(&basePointer, 16, 4);
+ if (basePointer == 0)
+ {
+ logger->LogError("Failed to read base pointer");
+ return false;
+ }
+ uint64_t primaryBase = 0;
+ GetParentView()->Read(&primaryBase, basePointer, 8);
+ if (primaryBase == 0)
+ {
+ logger->LogError("Failed to read primary base at 0x%llx", basePointer);
+ return false;
+ }
+
+ uint64_t headerSize = std::min(basePointer, headerType.type->GetWidth());
+ // Truncate the `dyld_cache_header` structure to the structure present in the cache file.
+ auto newStructure = StructureBuilder(headerType.type->GetStructure()).SetWidth(headerSize).Finalize();
+ headerType.type = TypeBuilder::StructureType(newStructure).Finalize();
+
+ AddAutoSegment(primaryBase, headerSize, 0, headerSize, SegmentReadable);
+ AddAutoSection("__dsc_header", primaryBase, headerSize, ReadOnlyDataSectionSemantics);
+ DefineType("dyld_cache_header", headerType.name, headerType.type);
+ DefineAutoSymbolAndVariableOrFunction(
+ GetDefaultPlatform(), new Symbol(DataSymbol, "primary_cache_header", primaryBase), headerType.type);
+
+ auto sharedCache = SharedCache(GetAddressSize());
+
+ {
+ // Add up all the cache entries using the cache processor.
+ // After this we should have all the mappings available as well.
+ CacheProcessor cacheProcessor = CacheProcessor(this);
+ auto startTime = std::chrono::high_resolution_clock::now();
+ if (!cacheProcessor.ProcessCache(sharedCache))
+ {
+ // Oh no, we failed to process the cache, this likely means the primary on-disk file was not able to be
+ // found.
+ // TODO: Prompt the user to select the primary cache file? We can still recover from here.
+ logger->LogError("Failed to process cache, likely missing cache files.");
+ // NOTE: An interaction handler headlessly could select yes to this, however for the purposes of this we will just let them continue by defualt.
+ if (IsUIEnabled() && ShowMessageBox("Continue opening", "This shared cache file was unable to be processed, would you like to open without shared cache information?", YesNoButtonSet, QuestionIcon) != YesButton)
+ return false;
+ }
+ auto endTime = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double> elapsed = endTime - startTime;
+ logger->LogInfo("Processing %zu entries took %.3f seconds", sharedCache.GetEntries().size(), elapsed.count());
+ }
+
+ {
+ // Write all the slide info pointers to the virtual memory.
+ // This should be done before any other work begins, as the backing data will be altered by this process.
+ auto startTime = std::chrono::high_resolution_clock::now();
+ for (const auto& [_, entry] : sharedCache.GetEntries())
+ sharedCache.ProcessEntrySlideInfo(entry);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double> elapsed = endTime - startTime;
+ logger->LogInfo("Processing slide info took %.3f seconds", elapsed.count());
+ }
+
+ {
+ // Load up all images into the cache before adding extra regions.
+ // Currently, it is expected that a primary entry contain all relevant images, so we only check that one.
+ auto startTime = std::chrono::high_resolution_clock::now();
+ for (const auto& [_, entry] : sharedCache.GetEntries())
+ if (entry.GetType() == CacheEntryType::Primary)
+ sharedCache.ProcessEntryImages(entry);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double> elapsed = endTime - startTime;
+ auto images = sharedCache.GetImages();
+ logger->LogInfo("Processing %zu images took %.3f seconds", images.size(), elapsed.count());
+ // Warn if we found no images, and provide the likely explanation
+ if (images.empty())
+ logger->LogWarn("Failed to process any images, likely missing cache files.");
+ }
+
+ {
+ // TODO: Run this up on a separate thread maybe and have callback notifications?
+ // Load up all the regions into the cache.
+ auto startTime = std::chrono::high_resolution_clock::now();
+ for (const auto& [_, entry] : sharedCache.GetEntries())
+ sharedCache.ProcessEntryRegions(entry);
+ auto endTime = std::chrono::high_resolution_clock::now();
+ std::chrono::duration<double> elapsed = endTime - startTime;
+ logger->LogInfo("Processing %zu regions took %.3f seconds", sharedCache.GetRegions().size(), elapsed.count());
+ }
+
+ auto cacheController = SharedCacheController::Initialize(*this, std::move(sharedCache));
+
+ // Users can adjust which images are loaded by default using the `loader.dsc.autoLoadPattern` setting.
+ std::string autoLoadPattern = ".*libsystem_c.dylib";
+ if (settings && settings->Contains("loader.dsc.autoLoadPattern"))
+ autoLoadPattern = settings->Get<std::string>("loader.dsc.autoLoadPattern", this);
+ logger->LogDebug("Loading images using pattern: %s", autoLoadPattern.c_str());
+
+ std::regex autoLoadRegex(autoLoadPattern);
+ for (const auto& [_, image] : cacheController->GetCache().GetImages())
+ if (std::regex_match(image.GetName(), autoLoadRegex))
+ cacheController->ApplyImage(*this, image);
+
+ return true;
+}