* Added an interface for how LLEE would communicate with the OS
authorMisha Brukman <brukman+llvm@gmail.com>
Mon, 29 Sep 2003 22:37:00 +0000 (22:37 +0000)
committerMisha Brukman <brukman+llvm@gmail.com>
Mon, 29 Sep 2003 22:37:00 +0000 (22:37 +0000)
* Implemented the interface in StorageProxy.c
* Removed the script `llee' as it is now created by the Makefile
* Makefile now compiles a shared object version of the library, but only if
  using gcc-3.3, linking fails under gcc-3.2

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8751 91177308-0d34-0410-b5e6-96231b3b80d8

tools/llee/ExecveHandler.c
tools/llee/Makefile
tools/llee/OSInterface.h [new file with mode: 0644]
tools/llee/StorageProxy.c [new file with mode: 0644]
tools/llee/SysUtils.c
tools/llee/SysUtils.h
tools/llee/llee [deleted file]

index dba419cfa3173f996b943b74de3599856b92fa86..4b740147adf9041e7178bb04cbd1cec9b3ede910 100644 (file)
@@ -5,8 +5,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "OSInterface.h"
 #include "SysUtils.h"
-#include "Config/dlfcn.h"
 #include "Config/errno.h"
 #include "Config/stdlib.h"
 #include "Config/unistd.h"
  */
 static const char llvmHeader[] = "llvm";
 
-/*
- * The type of the execve() function is long and boring, but required.
- */
-typedef int(*execveTy)(const char*, char *const[], char *const[]);
-
-/*
- * This method finds the real `execve' call in the C library and executes the
- * given program.
- */
-int executeProgram(const char *filename, char *const argv[], char *const envp[])
-{
-  /*
-   * Find a pointer to the *real* execve() function starting the search in the
-   * next library and forward, to avoid finding the one defined in this file.
-   */
-  char *error;
-  execveTy execvePtr = (execveTy) dlsym(RTLD_NEXT, "execve");
-  if ((error = dlerror()) != NULL) {
-    fprintf(stderr, "%s\n", error);
-    return -1;
-  }
-
-  /* Really execute the program */
-  return execvePtr(filename, argv, envp);
-}
-
 /*
  * This replacement execve() function first checks the file to be executed
  * to see if it is a valid LLVM bytecode file, and then either invokes our
@@ -56,8 +30,21 @@ int execve(const char *filename, char *const argv[], char *const envp[])
   /* Open the file, test to see if first four characters are "llvm" */
   size_t headerSize = strlen(llvmHeader);
   char header[headerSize];
+  char* realFilename = 0;
+  /* 
+   * If the program is specified with a relative or absolute path, 
+   * then just use the path and filename as is, otherwise search for it.
+   */
+  if (filename[0] != '.' && filename[0] != '/')
+    realFilename = FindExecutable(filename);
+  else
+    realFilename = (char*) filename;
+  if (!realFilename) {
+    fprintf(stderr, "Cannot find path to `%s', exiting.\n", filename);
+    return -1;
+  }
   errno = 0;
-  int file = open(filename, O_RDONLY);
+  int file = open(realFilename, O_RDONLY);
   /* Check validity of `file' */
   if (errno) return EIO;
   /* Read the header from the file */
@@ -65,6 +52,27 @@ int execve(const char *filename, char *const argv[], char *const envp[])
   close(file);
   if (bytesRead != (ssize_t)headerSize) return EIO;
   if (!memcmp(llvmHeader, header, headerSize)) {
+    /*
+     * Check if we have a cached translation on disk
+     */ 
+    struct stat buf;
+    llvmStat(realFilename, &buf);
+    if (isExecutable(&buf)) {
+      size_t size;
+      void *fileAddr = llvmReadFile(realFilename, &size);
+      fprintf(stderr, "Found in cache: '%s'\n", realFilename);
+      if (fileAddr) {
+        free(fileAddr);
+      }
+      llvmExecve(realFilename, argv, envp);
+    } else {
+      /* 
+       * Not in cache: save translation
+       */ 
+      //llvmSaveFile(realFilename, addr, len);
+      //fprintf(stderr, "Cached: '%s'\n", realFilename);
+    }
+    
     /* 
      * This is a bytecode file, so execute the JIT with the program and
      * parameters.
@@ -73,26 +81,13 @@ int execve(const char *filename, char *const argv[], char *const envp[])
     for (argvSize = 0, idx = 0; argv[idx] && argv[idx][0]; ++idx)
       ++argvSize;
     char **LLIargs = (char**) malloc(sizeof(char*) * (argvSize+2));
-    char *BCpath;
-    /* 
-     * If the program is specified with a relative or absolute path, 
-     * then just use the path and filename as is, otherwise search for it.
-     */
-    if (filename[0] != '.' && filename[0] != '/')
-      BCpath = FindExecutable(filename);
-    else
-      BCpath = (char*) filename;
-    if (!BCpath) {
-      fprintf(stderr, "Cannot find path to `%s', exiting.\n", filename);
-      return -1;
-    }
     char *LLIpath = FindExecutable("lli");
     if (!LLIpath) {
       fprintf(stderr, "Cannot find path to `lli', exiting.\n");
       return -1;
     }
     LLIargs[0] = LLIpath;
-    LLIargs[1] = BCpath;
+    LLIargs[1] = realFilename;
     for (idx = 1; idx != argvSize; ++idx)
       LLIargs[idx+1] = argv[idx];
     LLIargs[argvSize + 1] = '\0';
index b39129829ddc9842ca36f646708c01cd6dcc3cfa..cbaf896f6ababfe0bba68112eb9dad0a10fedd2c 100644 (file)
@@ -1,21 +1,15 @@
 LEVEL = ../..
-include $(LEVEL)/Makefile.config
+LIBRARYNAME = execve
+SHARED_LIBRARY = 1
+include $(LEVEL)/Makefile.common
 
-SRCS = ExecveHandler.c SysUtils.c
+all:: llee
 
-OBJS = $(SRCS:%.c=%.o)
-SO   = execve.so
+llee: $(DESTTOOLCURRENT)/llee
 
-all: $(SO)
-       
-%.o: %.c
-       gcc -g -I../../include -D_GNU_SOURCE $< -c -o $@
+$(DESTTOOLCURRENT)/llee: Makefile
+       echo exec env LD_PRELOAD=$(DESTLIBCURRENT)/execve.so $$\* > $@
+       chmod u+x $@
 
-$(SO): $(OBJS)
-       gcc -g -shared -ldl -rdynamic $(OBJS) -o $@
-
-execve_test: execve_test.c
-       gcc -g $< -o $@
-
-clean:
-       rm -f $(OBJS) $(SO)
+clean::
+       rm -f $(DESTTOOLCURRENT)/llee
diff --git a/tools/llee/OSInterface.h b/tools/llee/OSInterface.h
new file mode 100644 (file)
index 0000000..18fe0da
--- /dev/null
@@ -0,0 +1,48 @@
+/*===- OSInterface.h - Interface to query OS for functionality ---*- C -*--===*\
+ *                                                                            *
+ * This file defines the prototype interface that we will expect operating    *
+ * systems to implement if they wish to support offline cachine.              *
+ *                                                                            *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef OS_INTERFACE_H
+#define OS_INTERFACE_H
+
+#include "Config/sys/types.h"
+
+struct stat;
+
+/*
+ * llvmStat - equivalent to stat(3), except the key may not necessarily
+ * correspond to a file by that name, implementation is up to the OS.
+ * Values returned in buf are similar as they are in Unix.
+ */
+void llvmStat(const char *key, struct stat *buf);
+
+/*
+ * llvmWriteFile - implements a 'save' of a file in the OS. 'key' may not
+ * necessarily map to a file of the same name.
+ * Returns:
+ * 0 - success
+ * non-zero - error
+ */ 
+int llvmWriteFile(const char *key, const void *data, size_t len);
+
+/* 
+ * llvmLoadFile - tells the OS to load data corresponding to a particular key
+ * somewhere into memory.
+ * Returns:
+ * 0 - failure
+ * non-zero - address of loaded file
+ *
+ * Value of size is the length of data loaded into memory.
+ */ 
+void* llvmReadFile(const char *key, size_t *size);
+
+/*
+ * llvmExecve - execute a file from cache. This is a temporary proof-of-concept
+ * because we do not relocate what we can read from disk.
+ */ 
+int llvmExecve(const char *filename, char *const argv[], char *const envp[]);
+
+#endif
diff --git a/tools/llee/StorageProxy.c b/tools/llee/StorageProxy.c
new file mode 100644 (file)
index 0000000..0562796
--- /dev/null
@@ -0,0 +1,101 @@
+/*===- StorageProxy.c - OS implementation of the caching interface --------===*\
+ *                                                                            *
+ * This file implements the interface that we will expect operating           *
+ * systems to implement if they wish to support offline cachine.              *
+ *                                                                            *
+\*===----------------------------------------------------------------------===*/
+
+#include "OSInterface.h"
+#include "SysUtils.h"
+#include "Config/fcntl.h"
+#include "Config/stdlib.h"
+#include "Config/unistd.h"
+#include "Config/sys/types.h"
+#include "Config/sys/stat.h"
+#include <stdio.h>
+#include <string.h>
+
+static const char CacheRoot[] = "/tmp/LLVMCache";
+static const char ExeSuffix[] = ".exe";
+
+char* computeCachedFile(const char *key) {
+  /* CacheRoot + "/" + std::string(key) + ExeSuffix; */
+  char *cacheFile = (char*) malloc(strlen(CacheRoot) + 1 + strlen(key) + 
+                                   strlen(ExeSuffix) + 1);
+  char *pCacheFile = cacheFile;
+  if (!cacheFile) return 0;
+  memcpy(cacheFile, CacheRoot, strlen(CacheRoot));
+  pCacheFile += strlen(CacheRoot);
+  *pCacheFile++ = '/';
+  memcpy(pCacheFile, key, strlen(key));
+  pCacheFile += strlen(key);
+  memcpy(pCacheFile, ExeSuffix, strlen(ExeSuffix));
+  pCacheFile += strlen(ExeSuffix);
+  *pCacheFile = 0; // Null-terminate
+  return cacheFile;
+}
+
+/*
+ * llvmStat - equivalent to stat(3), except the key may not necessarily
+ * correspond to a file by that name, implementation is up to the OS.
+ * Values returned in buf are similar as they are in Unix.
+ */
+void llvmStat(const char *key, struct stat *buf) {
+  char* cacheFile = computeCachedFile(key);
+  fprintf(stderr, "llvmStat(%s)\n", cacheFile);
+  stat(cacheFile, buf);
+  free(cacheFile);
+}
+
+/*
+ * llvmWriteFile - implements a 'save' of a file in the OS. 'key' may not
+ * necessarily map to a file of the same name.
+ * Returns:
+ * 0 - success
+ * non-zero - error
+ */ 
+int llvmWriteFile(const char *key, const void *data, size_t len)
+{
+  char* cacheFile = computeCachedFile(key);
+  int fd = open(cacheFile, O_CREAT|O_WRONLY|O_TRUNC);
+  free(cacheFile);
+  if (fd < 0) return -1; // encountered an error
+  if (write(fd, data, len)) return -1;
+  if (fsync(fd)) return -1;
+  if (close(fd)) return -1;
+  return 0;
+}
+
+/* 
+ * llvmReadFile - tells the OS to load data corresponding to a particular key
+ * somewhere into memory.
+ * Returns:
+ * 0 - failure
+ * non-zero - address of loaded file
+ *
+ * Value of size is the length of data loaded into memory.
+ */ 
+void* llvmReadFile(const char *key, size_t *size) {
+  char* cacheFile = computeCachedFile(key);
+  if (!cacheFile) return 0;
+  struct stat buf;
+  stat(cacheFile, &buf);
+  int fd = open(cacheFile, O_RDONLY);
+  if (fd < 0) return 0; // encountered an error
+  void* data = malloc(buf.st_size);
+  if (read(fd, data, buf.st_size)) {
+    free(data);  
+    return 0;
+  }
+  *size = buf.st_size;
+  return data;
+}
+
+/*
+ * llvmExecve - execute a file from cache. This is a temporary proof-of-concept
+ * because we do not relocate what we can read from disk.
+ */
+int llvmExecve(const char *filename, char *const argv[], char *const envp[]) {
+  char* cacheFile = computeCachedFile(filename);
+  executeProgram(cacheFile, argv, envp);
+}
index 8399612446e7c69417eb5274aeb547b9f3116cc1..6d6dc50a6aae634cf6768cfb09ec5877a0d3e0f3 100644 (file)
@@ -6,35 +6,46 @@
 //===----------------------------------------------------------------------===//
 
 #include "SysUtils.h"
-#include "Config/sys/types.h"
-#include "Config/sys/stat.h"
+#include "Config/dlfcn.h"
+#include "Config/errno.h"
 #include "Config/fcntl.h"
-#include "Config/sys/wait.h"
 #include "Config/unistd.h"
-#include "Config/errno.h"
+#include "Config/sys/stat.h"
+#include "Config/sys/types.h"
+#include "Config/sys/wait.h"
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
+/*
+ * isExecutable - This function returns true if given struct stat describes the
+ * file as being executable.
+ */ 
+unsigned isExecutable(const struct stat *buf) {
+  if (!(buf->st_mode & S_IFREG))
+    return 0;                         // Not a regular file?
+
+  if (buf->st_uid == getuid())        // Owner of file?
+    return buf->st_mode & S_IXUSR;
+  else if (buf->st_gid == getgid())   // In group of file?
+    return buf->st_mode & S_IXGRP;
+  else                                // Unrelated to file?
+    return buf->st_mode & S_IXOTH;
+}
+
 /*
  * isExecutableFile - This function returns true if the filename specified
  * exists and is executable.
  */
 unsigned isExecutableFile(const char *ExeFileName) {
-  struct stat Buf;
-  if (stat(ExeFileName, &Buf))
+  struct stat buf;
+  if (stat(ExeFileName, &buf))
     return 0;                        // Must not be executable!
 
-  if (!(Buf.st_mode & S_IFREG))
-    return 0;                        // Not a regular file?
-
-  if (Buf.st_uid == getuid())        // Owner of file?
-    return Buf.st_mode & S_IXUSR;
-  else if (Buf.st_gid == getgid())   // In group of file?
-    return Buf.st_mode & S_IXGRP;
-  else                               // Unrelated to file?
-    return Buf.st_mode & S_IXOTH;
+  return isExecutable(&buf);
 }
 
+
 /*
  * FindExecutable - Find a named executable in the directories listed in $PATH.
  * If the executable cannot be found, returns NULL.
@@ -81,3 +92,29 @@ char *FindExecutable(const char *ExeName) {
   /* If we fell out, we ran out of directories to search, return failure. */
   return NULL;
 }
+
+/*
+ * The type of the execve() function is long and boring, but required.
+ */
+typedef int(*execveTy)(const char*, char *const[], char *const[]);
+
+/*
+ * This method finds the real `execve' call in the C library and executes the
+ * given program.
+ */
+int executeProgram(const char *filename, char *const argv[], char *const envp[])
+{
+  /*
+   * Find a pointer to the *real* execve() function starting the search in the
+   * next library and forward, to avoid finding the one defined in this file.
+   */
+  char *error;
+  execveTy execvePtr = (execveTy) dlsym(RTLD_NEXT, "execve");
+  if ((error = dlerror()) != NULL) {
+    fprintf(stderr, "%s\n", error);
+    return -1;
+  }
+
+  /* Really execute the program */
+  return execvePtr(filename, argv, envp);
+}
index 84e7f9d6b2e9148946dbf7dddeafabb489677488..2e498a80e8b740ae5fba22cbd152afb840a39fe6 100644 (file)
@@ -8,6 +8,14 @@
 #ifndef SYSUTILS_H
 #define SYSUTILS_H
 
+struct stat;
+
+/*
+ * isExecutable - This function returns true if given struct stat describes the
+ * file as being executable.
+ */ 
+unsigned isExecutable(const struct stat *buf);
+  
 /*
  * isExecutableFile - This function returns true if the filename specified
  * exists and is executable.
@@ -19,4 +27,11 @@ unsigned isExecutableFile(const char *ExeFileName);
  */ 
 char *FindExecutable(const char *ExeName);
 
+/*
+ * This method finds the real `execve' call in the C library and executes the
+ * given program.
+ */
+int
+executeProgram(const char *filename, char *const argv[], char *const envp[]);
+
 #endif
diff --git a/tools/llee/llee b/tools/llee/llee
deleted file mode 100755 (executable)
index 7a3ea95..0000000
+++ /dev/null
@@ -1 +0,0 @@
-exec env LD_PRELOAD=`pwd`/execve.so $*