forked from OSchip/llvm-project
* Added an interface for how LLEE would communicate with the OS
* 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 llvm-svn: 8751
This commit is contained in:
parent
b3541d4264
commit
64adfee893
|
|
@ -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"
|
||||
|
|
@ -20,32 +20,6 @@
|
|||
*/
|
||||
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';
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -6,35 +6,46 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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/dlfcn.h"
|
||||
#include "Config/errno.h"
|
||||
#include "Config/fcntl.h"
|
||||
#include "Config/unistd.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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
exec env LD_PRELOAD=`pwd`/execve.so $*
|
||||
Loading…
Reference in New Issue