about summary refs log tree commit diff
path: root/src/resolve-system-dependencies
diff options
context:
space:
mode:
authorJude Taylor <me@jude.bio>2016-08-16T19·45-0700
committerJude Taylor <me@jude.bio>2016-08-16T19·45-0700
commit90516c5a7be5457813313d89ecf8ae9d3c0d1708 (patch)
treeeb58169ba73e4dfb7b6cd60028609666de8594f1 /src/resolve-system-dependencies
parent7b006122aee221f1ec69b6439bf86e79190491c1 (diff)
switch to mmap strategy
Diffstat (limited to 'src/resolve-system-dependencies')
-rw-r--r--src/resolve-system-dependencies/resolve-system-dependencies.cc149
1 files changed, 68 insertions, 81 deletions
diff --git a/src/resolve-system-dependencies/resolve-system-dependencies.cc b/src/resolve-system-dependencies/resolve-system-dependencies.cc
index 4b2f55f09580..216be12100cd 100644
--- a/src/resolve-system-dependencies/resolve-system-dependencies.cc
+++ b/src/resolve-system-dependencies/resolve-system-dependencies.cc
@@ -6,9 +6,13 @@
 #include <algorithm>
 #include <iostream>
 #include <fstream>
+#include <sys/mman.h>
+#include <fcntl.h>
 #include <mach-o/loader.h>
 #include <mach-o/swap.h>
 
+#define DO_SWAP(x, y) ((x) ? OSSwapInt32(y) : (y))
+
 using namespace nix;
 
 static auto cacheDir = Path{};
@@ -31,76 +35,59 @@ void writeCacheFile(const Path & file, std::set<string> & deps) {
     fp.close();
 }
 
-std::string findDylibName(FILE *obj_file, struct load_command cmd) {
-    fpos_t pos;
-    fgetpos(obj_file, &pos);
-    struct dylib_command dylc;
-    dylc.cmd = cmd.cmd;
-    dylc.cmdsize = cmd.cmdsize;
-    fread(&dylc.dylib, sizeof(struct dylib), 1, obj_file);
-
-    char *dylib_name = (char*)calloc(cmd.cmdsize, sizeof(char));
-    fseek(obj_file,
-            // offset is calculated from the beginning of the load command, which is two
-            // uint32_t's backwards
-            dylc.dylib.name.offset - (sizeof(uint32_t) * 2) + pos,
-            SEEK_SET);
-    fread(dylib_name, sizeof(char), cmd.cmdsize, obj_file);
-    fseek(obj_file, pos, SEEK_SET);
-    return std::string(dylib_name);
-}
+std::string findDylibName(bool should_swap, ptrdiff_t dylib_command_start) {
+    struct dylib_command *dylc = (struct dylib_command*)dylib_command_start;
 
-bool seekMach64Blob(FILE *obj_file, enum NXByteOrder end) {
-    struct fat_header head;
-    fread(&head, sizeof(struct fat_header), 1, obj_file);
-    swap_fat_header(&head, end);
-    for(uint32_t narches = 0; narches < head.nfat_arch; narches++) {
-        struct fat_arch arch;
-        fread(&arch, sizeof(struct fat_arch), 1, obj_file);
-        swap_fat_arch(&arch, 1, end);
-        if(arch.cputype == CPU_TYPE_X86_64) {
-            fseek(obj_file, arch.offset, SEEK_SET);
-            return true;
-        }
-    }
-    return false;
+    return std::string((char*)(dylib_command_start + DO_SWAP(should_swap, dylc->dylib.name.offset)));
 }
 
 std::set<std::string> runResolver(const Path & filename) {
-    FILE *obj_file = fopen(filename.c_str(), "rb");
-    uint32_t magic;
-    fread(&magic, sizeof(uint32_t), 1, obj_file);
-    fseek(obj_file, 0, SEEK_SET);
-    enum NXByteOrder endianness;
-    if(magic == 0xBEBAFECA) {
-        endianness = NX_BigEndian;
-        if(!seekMach64Blob(obj_file, endianness)) {
-            std::cerr << "Could not find any mach64 blobs in file " << filename << ", continuing..." << std::endl;
+    int fd = open(filename.c_str(), O_RDONLY);
+    struct stat s;
+    fstat(fd, &s);
+    void *obj = mmap(NULL, s.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+    ptrdiff_t mach64_offset = 0;
+
+    uint32_t magic = ((struct mach_header_64*)obj)->magic;
+    if(magic == FAT_CIGAM || magic == FAT_MAGIC) {
+        bool should_swap = magic == FAT_CIGAM;
+        uint32_t narches = DO_SWAP(should_swap, ((struct fat_header*)obj)->nfat_arch);
+
+        for(uint32_t iter = 0; iter < narches; iter++) {
+            ptrdiff_t header_offset = (ptrdiff_t)obj + sizeof(struct fat_header);
+            struct fat_arch* arch = (struct fat_arch*)header_offset;
+            if(DO_SWAP(should_swap, arch->cputype) == CPU_TYPE_X86_64) {
+                mach64_offset = (ptrdiff_t)DO_SWAP(should_swap, arch->offset);
+                break;
+            }
+        }
+        if (mach64_offset == 0) {
+            printMsg(lvlError, format("Could not find any mach64 blobs in file ‘%1%’, continuing...") % filename);
             return std::set<string>();
         }
+    } else if (magic == MH_MAGIC_64 || magic == MH_CIGAM_64) {
+        mach64_offset = 0;
     }
-    struct mach_header_64 header;
-    fread(&header, sizeof(struct mach_header_64), 1, obj_file);
-    if(!(header.magic == MH_MAGIC_64 || header.magic == MH_CIGAM_64)) {
-        std::cerr << "Not a mach-o object file: " << filename << std::endl;
-        return std::set<string>();
-    }
+
+    struct mach_header_64 *m_header = (struct mach_header_64 *)((ptrdiff_t)obj + mach64_offset);
+
+    bool should_swap = magic == MH_CIGAM_64;
+    ptrdiff_t cmd_offset = (ptrdiff_t)m_header + sizeof(struct mach_header_64);
+
     std::set<string> libs;
-    for(uint32_t i = 0; i < header.ncmds; i++) {
-        struct load_command cmd;
-        fread(&cmd.cmd, sizeof(cmd.cmd), 1, obj_file);
-        fread(&cmd.cmdsize, sizeof(cmd.cmdsize), 1, obj_file);
-        switch(cmd.cmd) {
-            case LC_LOAD_DYLIB:
+    for(uint32_t i = 0; i < DO_SWAP(should_swap, m_header->ncmds); i++) {
+        struct load_command *cmd = (struct load_command*)cmd_offset;
+        switch(DO_SWAP(should_swap, cmd->cmd)) {
             case LC_LOAD_UPWARD_DYLIB:
+            case LC_LOAD_DYLIB:
             case LC_REEXPORT_DYLIB:
-                libs.insert(findDylibName(obj_file, cmd));
+                libs.insert(findDylibName(should_swap, cmd_offset));
                 break;
         }
-        fseek(obj_file, cmd.cmdsize - (sizeof(uint32_t) * 2), SEEK_CUR);
+        cmd_offset += DO_SWAP(should_swap, cmd->cmdsize);
     }
-    fclose(obj_file);
-    libs.erase(filename);
+
     return libs;
 }
 
@@ -165,40 +152,40 @@ std::set<string> getPath(const Path & path) {
 
 int main(int argc, char ** argv) {
     return handleExceptions(argv[0], [&]() {
-            initNix();
+        initNix();
 
-            struct utsname _uname;
+        struct utsname _uname;
 
-            uname(&_uname);
+        uname(&_uname);
 
-            auto cacheParentDir = (format("%1%/dependency-maps") % settings.nixStateDir).str();
+        auto cacheParentDir = (format("%1%/dependency-maps") % settings.nixStateDir).str();
 
-            cacheDir = (format("%1%/%2%-%3%-%4%")
-                    % cacheParentDir
-                    % _uname.machine
-                    % _uname.sysname
-                    % _uname.release).str();
+        cacheDir = (format("%1%/%2%-%3%-%4%")
+                % cacheParentDir
+                % _uname.machine
+                % _uname.sysname
+                % _uname.release).str();
 
-            mkdir(cacheParentDir.c_str(), 0755);
-            mkdir(cacheDir.c_str(), 0755);
+        mkdir(cacheParentDir.c_str(), 0755);
+        mkdir(cacheDir.c_str(), 0755);
 
-            auto store = openStore();
+        auto store = openStore();
 
-            auto drv = store->derivationFromPath(Path(argv[1]));
-            Strings impurePaths = tokenizeString<Strings>(get(drv.env, "__impureHostDeps"));
+        auto drv = store->derivationFromPath(Path(argv[1]));
+        Strings impurePaths = tokenizeString<Strings>(get(drv.env, "__impureHostDeps"));
 
-            std::set<string> all_paths;
+        std::set<string> all_paths;
 
-            for (auto & path : impurePaths) {
-                for(auto & p : getPath(path)) {
-                    all_paths.insert(p);
-                }
+        for (auto & path : impurePaths) {
+            for(auto & p : getPath(path)) {
+                all_paths.insert(p);
             }
+        }
 
-            std::cout << "extra-chroot-dirs" << std::endl;
-            for(auto & path : all_paths) {
-                std::cout << path << std::endl;
-            }
-            std::cout << std::endl;
+        std::cout << "extra-chroot-dirs" << std::endl;
+        for(auto & path : all_paths) {
+            std::cout << path << std::endl;
+        }
+        std::cout << std::endl;
     });
 }