* 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


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@8751 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Misha Brukman 2003-09-29 22:37:00 +00:00
parent e676313966
commit 2e1fbdd267
7 changed files with 264 additions and 75 deletions

View File

@ -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';

View File

@ -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

48
tools/llee/OSInterface.h Normal file
View File

@ -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

101
tools/llee/StorageProxy.c Normal file
View File

@ -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);
}

View File

@ -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);
}

View File

@ -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

View File

@ -1 +0,0 @@
exec env LD_PRELOAD=`pwd`/execve.so $*