Initial checkin of the LLEE, the (LL)VM (E)xecution (E)nvironment.
authorMisha Brukman <brukman+llvm@gmail.com>
Mon, 11 Aug 2003 22:29:36 +0000 (22:29 +0000)
committerMisha Brukman <brukman+llvm@gmail.com>
Mon, 11 Aug 2003 22:29:36 +0000 (22:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@7760 91177308-0d34-0410-b5e6-96231b3b80d8

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

diff --git a/tools/llee/ExecveHandler.c b/tools/llee/ExecveHandler.c
new file mode 100644 (file)
index 0000000..947b2fc
--- /dev/null
@@ -0,0 +1,92 @@
+//===-- ExecveHandler.c - Replaces execve() to run LLVM files -------------===//
+//
+// This file implements a replacement execve() to spawn off LLVM programs to run
+// transparently, without needing to be (JIT-)compiled manually by the user.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SysUtils.h"
+#include <Config/dlfcn.h>
+#include <Config/errno.h>
+#include <Config/stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/*
+ * This is the expected header for all valid LLVM bytecode files.
+ * The first four characters must be exactly this.
+ */
+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
+ * execution environment or passes it on to the system execve() call.
+ */
+int execve(const char *filename, char *const argv[], char *const envp[])
+{
+  /* Open the file, test to see if first four characters are "llvm" */
+  char header[4];
+  FILE *file = fopen(filename, "r");
+  /* Check validity of `file' */
+  if (errno) { return errno; }
+  /* Read the header from the file */
+  size_t headerSize = strlen(llvmHeader) - 1; // ignore the NULL terminator
+  size_t bytesRead = fread(header, sizeof(char), headerSize, file);
+  fclose(file);
+  if (bytesRead != headerSize) { 
+    return EIO;
+  }
+  if (!strncmp(llvmHeader, header, headerSize)) {
+    /* 
+     * This is a bytecode file, so execute the JIT with the program and
+     * parameters.
+     */
+    unsigned argvSize, idx;
+    for (argvSize = 0, idx = 0; argv[idx] && argv[idx][0]; ++idx)
+      ++argvSize;
+    char **LLIargs = (char**) malloc(sizeof(char*) * (argvSize+2));
+    char *LLIpath = FindExecutable("lli");
+    if (!LLIpath) {
+      fprintf(stderr, "Cannot find path to `lli', exiting.\n");
+      return -1;
+    }
+    LLIargs[0] = LLIpath;
+    for (idx = 0; idx != argvSize; ++idx)
+      LLIargs[idx+1] = argv[idx];
+    LLIargs[argvSize + 1] = '\0';
+    /*
+    for (idx = 0; idx != argvSize+2; ++idx)
+      printf("LLI args[%d] = \"%s\"\n", idx, LLIargs[idx]);
+    */
+    return executeProgram(LLIpath, LLIargs, envp);
+  }
+  executeProgram(filename, argv, envp); 
+  return 0;
+}
diff --git a/tools/llee/Makefile b/tools/llee/Makefile
new file mode 100644 (file)
index 0000000..aabbed6
--- /dev/null
@@ -0,0 +1,21 @@
+LEVEL = ../..
+include $(LEVEL)/Makefile.config
+
+SRCS = ExecveHandler.c SysUtils.c
+
+OBJS = $(SRCS:%.c=%.o)
+SO   = execve.so
+
+all: $(SO) execve_test
+       
+%.o: %.c
+       gcc -g -I../../include -D_GNU_SOURCE $< -c -o $@
+
+$(SO): $(OBJS)
+       gcc -g -shared -ldl -rdynamic $(OBJS) -o $@
+
+execve_test: execve_test.c
+       gcc -g $< -o $@
+
+clean:
+       rm -f $(OBJS) $(SO)
diff --git a/tools/llee/SysUtils.c b/tools/llee/SysUtils.c
new file mode 100644 (file)
index 0000000..1c3aa85
--- /dev/null
@@ -0,0 +1,81 @@
+//===- SystemUtils.h - Utilities to do low-level system stuff --*- C++ -*--===//
+//
+// This file contains functions used to do a variety of low-level, often
+// system-specific, tasks.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SysUtils.h"
+#include "Config/sys/types.h"
+#include "Config/sys/stat.h"
+#include "Config/fcntl.h"
+#include "Config/sys/wait.h"
+#include "Config/unistd.h"
+#include "Config/errno.h"
+#include <stdlib.h>
+#include <string.h>
+
+/// isExecutableFile - This function returns true if the filename specified
+/// exists and is executable.
+///
+bool isExecutableFile(const char *ExeFileName) {
+  struct stat Buf;
+  if (stat(ExeFileName, &Buf))
+    return false;  // Must not be executable!
+
+  if (!(Buf.st_mode & S_IFREG))
+    return false;                    // 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;
+}
+
+/// FindExecutable - Find a named executable in the directories listed in $PATH.
+/// If the executable cannot be found, returns NULL.
+/// 
+char *FindExecutable(const char *ExeName) {
+  /* Try to find the executable in the path */
+  const char *PathStr = getenv("PATH");
+  if (PathStr == 0) return "";
+
+  // Now we have a colon separated list of directories to search... try them...
+  unsigned PathLen = strlen(PathStr);
+  while (PathLen) {
+    /* Find the next colon */
+    const char *Colon = strchr(PathStr, ':');
+    
+    /* Check to see if this first directory contains the executable... */
+    unsigned DirLen = Colon ? (Colon-PathStr) : strlen(PathStr);
+    char *FilePath = alloca(sizeof(char) * (DirLen+1+strlen(ExeName)+1));
+    unsigned i, e;
+    for (i = 0; i != DirLen; ++i)
+      FilePath[i] = PathStr[i];
+    FilePath[i] = '/';
+    for (i = 0, e = strlen(ExeName); i != e; ++i)
+      FilePath[DirLen + 1 + i] = ExeName[i];
+    FilePath[DirLen + 1 + i] = '\0';
+    if (isExecutableFile(FilePath))
+      return strdup(FilePath); /* Found the executable! */
+
+    /* If Colon is NULL, there are no more colon separators and no more dirs */
+    if (!Colon) break;
+
+    /* Nope, it wasn't in this directory, check the next range! */
+    PathLen -= DirLen;
+    PathStr = Colon;
+    while (*PathStr == ':') {   /* Advance past colons */
+      PathStr++;
+      PathLen--;
+    }
+
+    /* Advance past the colon */
+    ++Colon;
+  }
+
+  // If we fell out, we ran out of directories in PATH to search, return failure
+  return NULL;
+}
diff --git a/tools/llee/SysUtils.h b/tools/llee/SysUtils.h
new file mode 100644 (file)
index 0000000..89b6479
--- /dev/null
@@ -0,0 +1,28 @@
+/*===- sysutils.h - Utilities to do low-level system stuff -------*- C -*--===*\
+ *                                                                            *
+ * This file contains functions used to do a variety of low-level, often      *
+ * system-specific, tasks.                                                    *
+ *                                                                            *
+\*===----------------------------------------------------------------------===*/
+
+#ifndef SYSUTILS_H
+#define SYSUTILS_H
+
+typedef unsigned bool;
+enum { false = 0, true = 1 };
+
+/*
+ * isExecutableFile - This function returns true if the filename specified
+ * exists and is executable.
+ */
+bool isExecutableFile(const char *ExeFileName);
+
+/*
+ * FindExecutable - Find a named executable, giving the argv[0] of program
+ * being executed. This allows us to find another LLVM tool if it is built into
+ * the same directory, but that directory is neither the current directory, nor
+ * in the PATH.  If the executable cannot be found, return an empty string.
+ */ 
+char *FindExecutable(const char *ExeName);
+
+#endif
diff --git a/tools/llee/llee b/tools/llee/llee
new file mode 100755 (executable)
index 0000000..7a3ea95
--- /dev/null
@@ -0,0 +1 @@
+exec env LD_PRELOAD=`pwd`/execve.so $*