| //===-- 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 "OSInterface.h" |
| #include "SysUtils.h" |
| #include "Config/errno.h" |
| #include "Config/stdlib.h" |
| #include "Config/unistd.h" |
| #include <fcntl.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"; |
| |
| /* |
| * 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" */ |
| 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(realFilename, O_RDONLY); |
| /* Check validity of `file' */ |
| if (errno) return EIO; |
| /* Read the header from the file */ |
| ssize_t bytesRead = read(file, header, headerSize); |
| 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. |
| */ |
| 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; |
| LLIargs[1] = realFilename; |
| for (idx = 1; idx != argvSize; ++idx) |
| LLIargs[idx+1] = argv[idx]; |
| LLIargs[argvSize + 1] = '\0'; |
| return executeProgram(LLIpath, LLIargs, envp); |
| } |
| return executeProgram(filename, argv, envp); |
| } |