blob: 947b2fcdbd0ee23ef04f896ab6e40d67e4f18bd0 [file] [log] [blame]
Misha Brukman0abaaf42003-08-11 22:29:36 +00001//===-- 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 */
19static const char llvmHeader[] = "llvm";
20
21/*
22 * The type of the execve() function is long and boring, but required.
23 */
24typedef 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 */
30int 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 */
52int 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}