947b2fcdbd0ee23ef04f896ab6e40d67e4f18bd0
[oota-llvm.git] / tools / llee / ExecveHandler.c
1 //===-- ExecveHandler.c - Replaces execve() to run LLVM files -------------===//
2 //
3 // This file implements a replacement execve() to spawn off LLVM programs to run
4 // transparently, without needing to be (JIT-)compiled manually by the user.
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "SysUtils.h"
9 #include <Config/dlfcn.h>
10 #include <Config/errno.h>
11 #include <Config/stdlib.h>
12 #include <stdio.h>
13 #include <string.h>
14
15 /*
16  * This is the expected header for all valid LLVM bytecode files.
17  * The first four characters must be exactly this.
18  */
19 static const char llvmHeader[] = "llvm";
20
21 /*
22  * The type of the execve() function is long and boring, but required.
23  */
24 typedef int(*execveTy)(const char*, char *const[], char *const[]);
25
26 /*
27  * This method finds the real `execve' call in the C library and executes the
28  * given program.
29  */
30 int executeProgram(const char *filename, char *const argv[], char *const envp[])
31 {
32   /*
33    * Find a pointer to the *real* execve() function starting the search in the
34    * next library and forward, to avoid finding the one defined in this file.
35    */
36   char *error;
37   execveTy execvePtr = (execveTy) dlsym(RTLD_NEXT, "execve");
38   if ((error = dlerror()) != NULL) {
39     fprintf(stderr, "%s\n", error);
40     return -1;
41   }
42
43   /* Really execute the program */
44   return execvePtr(filename, argv, envp);
45 }
46
47 /*
48  * This replacement execve() function first checks the file to be executed
49  * to see if it is a valid LLVM bytecode file, and then either invokes our
50  * execution environment or passes it on to the system execve() call.
51  */
52 int execve(const char *filename, char *const argv[], char *const envp[])
53 {
54   /* Open the file, test to see if first four characters are "llvm" */
55   char header[4];
56   FILE *file = fopen(filename, "r");
57   /* Check validity of `file' */
58   if (errno) { return errno; }
59   /* Read the header from the file */
60   size_t headerSize = strlen(llvmHeader) - 1; // ignore the NULL terminator
61   size_t bytesRead = fread(header, sizeof(char), headerSize, file);
62   fclose(file);
63   if (bytesRead != headerSize) { 
64     return EIO;
65   }
66   if (!strncmp(llvmHeader, header, headerSize)) {
67     /* 
68      * This is a bytecode file, so execute the JIT with the program and
69      * parameters.
70      */
71     unsigned argvSize, idx;
72     for (argvSize = 0, idx = 0; argv[idx] && argv[idx][0]; ++idx)
73       ++argvSize;
74     char **LLIargs = (char**) malloc(sizeof(char*) * (argvSize+2));
75     char *LLIpath = FindExecutable("lli");
76     if (!LLIpath) {
77       fprintf(stderr, "Cannot find path to `lli', exiting.\n");
78       return -1;
79     }
80     LLIargs[0] = LLIpath;
81     for (idx = 0; idx != argvSize; ++idx)
82       LLIargs[idx+1] = argv[idx];
83     LLIargs[argvSize + 1] = '\0';
84     /*
85     for (idx = 0; idx != argvSize+2; ++idx)
86       printf("LLI args[%d] = \"%s\"\n", idx, LLIargs[idx]);
87     */
88     return executeProgram(LLIpath, LLIargs, envp);
89   }
90   executeProgram(filename, argv, envp); 
91   return 0;
92 }