base: support gzip-compressed object files
authorCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 1 Mar 2016 01:13:13 +0000 (19:13 -0600)
committerCurtis Dunham <Curtis.Dunham@arm.com>
Tue, 1 Mar 2016 01:13:13 +0000 (19:13 -0600)
src/base/loader/object_file.cc

index e24aeddd33ad87d6f3860eca4562256cd4ef830d..d9ec852b75348ea1cbb625ffbb2cf3ab4d377b5d 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/types.h>
 #include <fcntl.h>
 #include <unistd.h>
+#include <zlib.h>
 
 #include <cstdio>
 #include <list>
@@ -101,6 +102,61 @@ ObjectFile::close()
     }
 }
 
+static bool
+hasGzipMagic(int fd)
+{
+    uint8_t buf[2] = {0};
+    size_t sz = pread(fd, buf, 2, 0);
+    panic_if(sz != 2, "Couldn't read magic bytes from object file");
+    return ((buf[0] == 0x1f) && (buf[1] == 0x8b));
+}
+
+static int
+doGzipLoad(int fd)
+{
+    const size_t blk_sz = 4096;
+
+    gzFile fdz = gzdopen(fd, "rb");
+    if (!fdz) {
+        return -1;
+    }
+
+    size_t tmp_len = strlen(P_tmpdir);
+    char *tmpnam = (char*) malloc(tmp_len + 20);
+    strcpy(tmpnam, P_tmpdir);
+    strcpy(tmpnam+tmp_len, "/gem5-gz-obj-XXXXXX"); // 19 chars
+    fd = mkstemp(tmpnam); // repurposing fd variable for output
+    if (fd < 0) {
+        free(tmpnam);
+        gzclose(fdz);
+        return fd;
+    }
+
+    if (unlink(tmpnam) != 0)
+        warn("couldn't remove temporary file %s\n", tmpnam);
+
+    free(tmpnam);
+
+    auto buf = new uint8_t[blk_sz];
+    int r; // size of (r)emaining uncopied data in (buf)fer
+    while ((r = gzread(fdz, buf, blk_sz)) > 0) {
+        auto p = buf; // pointer into buffer
+        while (r > 0) {
+            auto sz = write(fd, p, r);
+            assert(sz <= r);
+            r -= sz;
+            p += sz;
+        }
+    }
+    delete[] buf;
+    gzclose(fdz);
+    if (r < 0) { // error
+        close(fd);
+        return -1;
+    }
+    assert(r == 0); // finished successfully
+    return fd; // return fd to decompressed temporary file for mmap()'ing
+}
 
 ObjectFile *
 createObjectFile(const string &fname, bool raw)
@@ -111,15 +167,24 @@ createObjectFile(const string &fname, bool raw)
         return NULL;
     }
 
+    // decompress GZ files
+    if (hasGzipMagic(fd)) {
+        fd = doGzipLoad(fd);
+        if (fd < 0) {
+            return NULL;
+        }
+    }
+
     // find the length of the file by seeking to the end
     off_t off = lseek(fd, 0, SEEK_END);
-    fatal_if(off < 0, "Failed to determine size of object file %s\n", fname);
-    size_t len = static_cast<size_t>(off);
+    fatal_if(off < 0,
+             "Failed to determine size of object file %s\n", fname);
+    auto len = static_cast<size_t>(off);
 
     // mmap the whole shebang
-    uint8_t *fileData =
-        (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
+    auto fileData = (uint8_t *)mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
     close(fd);
+
     if (fileData == MAP_FAILED) {
         return NULL;
     }