blob: 113103f725ff9264ac56eadc717fd4ed4be25726 [file] [log] [blame]
#define _FILE_OFFSET_BITS 64
#include "vg_include.h"
#include "ume.h"
#include "ume_arch.h"
#include "ume_archdefs.h"
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <fcntl.h>
#include <errno.h>
#include <dirent.h>
#ifndef AT_SYSINFO
#define AT_SYSINFO 32
#endif /* AT_SYSINFO */
#ifndef AT_SYSINFO_EHDR
#define AT_SYSINFO_EHDR 33
#endif /* AT_SYSINFO_EHDR */
#ifndef AT_SECURE
#define AT_SECURE 23 /* secure mode boolean */
#endif /* AT_SECURE */
/* Amount to reserve for Valgrind's internal heap */
#define VALGRIND_HEAPSIZE (128*1024*1024)
/* Amount to reserve for Valgrind's internal mappings */
#define VALGRIND_MAPSIZE (128*1024*1024)
/* redzone gap between client address space and shadow */
#define REDZONE_SIZE (1 * 1024*1024)
/* size multiple for client address space */
#define CLIENT_SIZE_MULTIPLE (64 * 1024*1024)
extern char kickstart_base; /* linker-defined base address */
/* Where we expect to find all our aux files */
static const char *valgrind_lib = VG_LIBDIR;
/* Parameters we're going to pass to Valgrind */
static KickstartParams kp;
/* Shape of the client address space */
static addr_t client_base, client_end, client_size;
/* Look for our AUXV table */
static int scan_auxv(void)
{
const struct ume_auxv *auxv = find_auxv((int *)ume_exec_esp);
int found = 0;
for(; auxv->a_type != AT_NULL; auxv++)
switch(auxv->a_type) {
case AT_UME_PADFD:
as_setpadfd(auxv->a_val);
found |= 1;
break;
case AT_UME_EXECFD:
kp.vgexecfd = auxv->a_val;
found |= 2;
break;
}
return found == (1|2);
}
/* Scan a colon-separated list, and call a function on each element.
The string must be mutable, because we insert a temporary '\0', but
the string will end up unmodified. (*func) should return 1 if it
doesn't need to see any more.
*/
static void scan_colsep(char *colsep, int (*func)(const char *))
{
char *cp, *entry;
int end;
if (colsep == NULL ||
*colsep == '\0')
return;
entry = cp = colsep;
do {
end = (*cp == '\0');
if (*cp == ':' || *cp == '\0') {
char save = *cp;
*cp = '\0';
if ((*func)(entry))
end = 1;
*cp = save;
entry = cp+1;
}
cp++;
} while(!end);
}
/* Add a string onto the string table, and return its address */
static char *copy_str(char **tab, const char *str)
{
char *cp = *tab;
char *orig = cp;
while(*str)
*cp++ = *str++;
*cp++ = '\0';
if (0)
printf("copied %p \"%s\" len %d\n",
orig, orig, cp-orig);
*tab = cp;
return orig;
}
/*
This sets up the client's initial stack, containing the args,
environment and aux vector.
The format of the stack is:
higher address +-----------------+
| |
: string table :
| |
+-----------------+
| AT_NULL |
- -
| auxv |
+-----------------+
| NULL |
- -
| envp |
+-----------------+
| NULL |
- -
| argv |
+-----------------+
| argc |
lower address +-----------------+ <- esp
| undefined |
: :
*/
static Addr setup_client_stack(char **orig_argv, char **orig_envp,
const struct ume_auxv *orig_auxv,
const struct exeinfo *info)
{
char **cpp;
char *strtab; /* string table */
char *stringbase;
addr_t *ptr;
struct ume_auxv *auxv;
const struct ume_auxv *cauxv;
unsigned stringsize; /* total size of strings in bytes */
unsigned auxsize; /* total size of auxv in bytes */
int argc; /* total argc */
int envc; /* total number of env vars */
unsigned stacksize; /* total client stack size */
addr_t cl_esp; /* client stack base (initial esp) */
/* ==================== compute sizes ==================== */
/* first of all, work out how big the client stack will be */
stringsize = 0;
/* paste on the extra args if the loader needs them (ie, the #!
interpreter and its argument) */
argc = 0;
if (info->argv0 != NULL) {
argc++;
stringsize += strlen(info->argv0) + 1;
}
if (info->argv1 != NULL) {
argc++;
stringsize += strlen(info->argv1) + 1;
}
/* now scan the args we're given... */
for(cpp = orig_argv; *cpp; cpp++) {
argc++;
stringsize += strlen(*cpp) + 1;
}
/* ...and the environment */
envc = 0;
for(cpp = orig_envp; cpp && *cpp; cpp++) {
envc++;
stringsize += strlen(*cpp) + 1;
}
/* now, how big is the auxv? */
auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */
for(cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) {
if (cauxv->a_type == AT_PLATFORM)
stringsize += strlen(cauxv->a_ptr) + 1;
auxsize += sizeof(*cauxv);
}
/* OK, now we know how big the client stack is */
stacksize =
sizeof(int) + /* argc */
sizeof(char **)*argc + /* argv */
sizeof(char **) + /* terminal NULL */
sizeof(char **)*envc + /* envp */
sizeof(char **) + /* terminal NULL */
auxsize + /* auxv */
ROUNDUP(stringsize, sizeof(int)); /* strings (aligned) */
/* cl_esp is the client's stack pointer */
cl_esp = client_end - stacksize;
cl_esp = ROUNDDN(cl_esp, 16); /* make stack 16 byte aligned */
if (0)
printf("stringsize=%d auxsize=%d stacksize=%d\n",
stringsize, auxsize, stacksize);
/* base of the string table (aligned) */
stringbase = strtab = (char *)(client_end - ROUNDUP(stringsize, sizeof(int)));
kp.clstk_base = PGROUNDDN(cl_esp);
kp.clstk_end = client_end;
/* ==================== allocate space ==================== */
/* allocate a stack - mmap enough space for the stack */
mmap((void *)PGROUNDDN(cl_esp),
client_end - PGROUNDDN(cl_esp),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
/* ==================== copy client stack ==================== */
ptr = (addr_t *)cl_esp;
/* --- argc --- */
*ptr++ = argc; /* client argc */
/* --- argv --- */
if (info->argv0) {
*ptr++ = (addr_t)copy_str(&strtab, info->argv0);
free(info->argv0);
}
if (info->argv1) {
*ptr++ = (addr_t)copy_str(&strtab, info->argv1);
free(info->argv1);
}
for(cpp = orig_argv; *cpp; ptr++, cpp++) {
*ptr = (addr_t)copy_str(&strtab, *cpp);
}
*ptr++ = 0;
/* --- envp --- */
kp.client_envp = (Char **)ptr;
for(cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
*ptr = (addr_t)copy_str(&strtab, *cpp);
*ptr++ = 0;
/* --- auxv --- */
auxv = (struct ume_auxv *)ptr;
kp.client_auxv = (UInt *)auxv;
for(; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
/* copy the entry... */
*auxv = *orig_auxv;
/* ...and fix up the copy */
switch(auxv->a_type) {
case AT_PHDR:
if (info->phdr == 0)
auxv->a_type = AT_IGNORE;
else
auxv->a_val = info->phdr;
break;
case AT_PHNUM:
if (info->phdr == 0)
auxv->a_type = AT_IGNORE;
else
auxv->a_val = info->phnum;
break;
case AT_BASE:
if (info->interp_base == 0)
auxv->a_type = AT_IGNORE;
else
auxv->a_val = info->interp_base;
break;
case AT_PLATFORM: /* points to a platform description string */
auxv->a_ptr = copy_str(&strtab, orig_auxv->a_ptr);
break;
case AT_ENTRY:
auxv->a_val = info->entry;
break;
case AT_IGNORE:
case AT_EXECFD:
case AT_PHENT:
case AT_PAGESZ:
case AT_FLAGS:
case AT_NOTELF:
case AT_UID:
case AT_EUID:
case AT_GID:
case AT_EGID:
case AT_CLKTCK:
case AT_HWCAP:
case AT_FPUCW:
case AT_DCACHEBSIZE:
case AT_ICACHEBSIZE:
case AT_UCACHEBSIZE:
/* All these are pointerless, so we don't need to do anything
about them. */
break;
case AT_SECURE:
/* If this is 1, then it means that this program is running
suid, and therefore the dynamic linker should be careful
about LD_PRELOAD, etc. However, since stage1 (the thing
the kernel actually execve's) should never be SUID, and we
need LD_PRELOAD/LD_LIBRARY_PATH to work for the client, we
set AT_SECURE to 0. */
auxv->a_val = 0;
break;
#if 1
case AT_SYSINFO:
case AT_SYSINFO_EHDR:
/* trash vsyscalls for now
XXX should probably replace with our own sysinfo page so
we can intercept sysenter syscalls too - or at least note
the address so that we can catch jumps here
*/
auxv->a_type = AT_IGNORE;
break;
#endif
default:
/* stomp out anything we don't know about */
if (0)
printf("stomping auxv entry %d\n", auxv->a_type);
auxv->a_type = AT_IGNORE;
break;
}
}
*auxv = *orig_auxv;
assert(auxv->a_type == AT_NULL);
assert((strtab-stringbase) == stringsize);
return cl_esp;
}
/* Find and load a tool. Also looks to see if there's a matching
vgpreload_*.so file, and returns its name in *preloadpath. */
static void *load_tool(const char *name, char **preloadpath)
{
int len = strlen(valgrind_lib) + strlen(name)*2 + 16;
char buf[len];
void *ret;
*preloadpath = NULL;
if (strchr(name, '/') != 0) {
/* name contains '/', and so must be a pathname */
ret = dlopen(name, RTLD_NOW);
} else {
/* just try in the libdir */
snprintf(buf, len, "%s/vgskin_%s.so", valgrind_lib, name);
ret = dlopen(buf, RTLD_NOW);
if (ret != NULL) {
snprintf(buf, len, "%s/vgpreload_%s.so", valgrind_lib, name);
if (access(buf, R_OK) == 0)
*preloadpath = strdup(buf);
}
}
return ret;
}
/* list the available tools */
static void list_tools(void)
{
DIR *dir = opendir(valgrind_lib);
struct dirent *de;
int first = 1;
if (dir == NULL) {
fprintf(stderr, "Can't open %s: %s (installation problem?)\n",
valgrind_lib, strerror(errno));
return;
}
while((de = readdir(dir)) != NULL) {
int len = strlen(de->d_name);
/* look for vgskin_TOOL.so names */
if (len > (7+1+3) && /* "vgskin_" + at least on character tool name + ".so" */
strncmp(de->d_name, "vgskin_", 7) == 0 &&
strcmp(de->d_name + len - 3, ".so") == 0) {
if (first) {
printf("Available tools:\n");
first = 0;
}
de->d_name[len-3] = '\0';
printf("\t%s\n", de->d_name+7);
}
}
closedir(dir);
if (first)
printf("No tools available in \"%s\" (installation problem?)\n",
valgrind_lib);
}
/*
Prepare the client's environment. This is basically a copy of our
environment, except:
1. LD_LIBRARY_PATH=$VALGRINDLIB:$LD_LIBRARY_PATH
2. LD_PRELOAD=$VALGRINDLIB/vg_inject.so:($VALGRINDLIB/vgpreload_TOOL.so:)?$LD_PRELOAD
3. LD_ASSUME_KERNEL=2.4.1
If any of these is missing, then it is added.
Yummy. String hacking in C.
XXX If this needs to handle any more variables it should be hacked
into something table driven.
*/
static char **fix_environment(char **origenv, const char *preload)
{
static const char inject_so[] = "vg_inject.so";
static const char ld_library_path[] = "LD_LIBRARY_PATH=";
static const int ld_library_path_len = sizeof(ld_library_path)-1;
static const char ld_preload[] = "LD_PRELOAD=";
static const int ld_preload_len = sizeof(ld_preload)-1;
static const char ld_assume_kernel[] = "LD_ASSUME_KERNEL=";
static const int ld_assume_kernel_len = sizeof(ld_assume_kernel)-1;
static const char valgrind_clo[] = VALGRINDCLO "=";
static const char valgrind_clo_len = sizeof(valgrind_clo)-1;
int ld_preload_done = 0;
int ld_library_path_done = 0;
int ld_assume_kernel_done = 0;
char *inject_path;
int inject_path_len;
int vgliblen = strlen(valgrind_lib);
char **cpp;
char **ret;
int envc;
const int preloadlen = (preload == NULL) ? 0 : strlen(preload);
/* Find the vg_inject.so; also make room for the tool preload
library */
inject_path_len = sizeof(inject_so) + vgliblen + preloadlen + 16;
inject_path = malloc(inject_path_len);
if (preload)
snprintf(inject_path, inject_path_len, "%s/%s:%s",
valgrind_lib, inject_so, preload);
else
snprintf(inject_path, inject_path_len, "%s/%s",
valgrind_lib, inject_so);
/* Count the original size of the env */
envc = 0; /* trailing NULL */
for(cpp = origenv; cpp && *cpp; cpp++)
envc++;
/* Allocate a new space */
ret = malloc(sizeof(char *) * (envc+3+1)); /* 3 new entries + NULL */
/* copy it over */
for(cpp = ret; *origenv; )
*cpp++ = *origenv++;
*cpp = NULL;
assert(envc == (cpp - ret));
/* Walk over the new environment, mashing as we go */
for(cpp = ret; cpp && *cpp; cpp++) {
if (memcmp(*cpp, ld_library_path, ld_library_path_len) == 0) {
int done = 0;
int contains(const char *p) {
if (strcmp(p, valgrind_lib) == 0) {
done = 1;
return 1;
}
return 0;
}
/* If the LD_LIBRARY_PATH already contains libdir, then don't
bother adding it again, even if it isn't the first (it
seems that the Java runtime will keep reexecing itself
unless its paths are at the front of LD_LIBRARY_PATH) */
scan_colsep(*cpp + ld_library_path_len, contains);
if (!done) {
int len = strlen(*cpp) + vgliblen*2 + 16;
char *cp = malloc(len);
snprintf(cp, len, "%s%s:%s",
ld_library_path, valgrind_lib,
(*cpp)+ld_library_path_len);
*cpp = cp;
}
ld_library_path_done = 1;
} else if (memcmp(*cpp, ld_preload, ld_preload_len) == 0) {
int len = strlen(*cpp) + inject_path_len;
char *cp = malloc(len);
snprintf(cp, len, "%s%s:%s",
ld_preload, inject_path, (*cpp)+ld_preload_len);
*cpp = cp;
ld_preload_done = 1;
} else if (memcmp(*cpp, ld_assume_kernel, ld_assume_kernel_len) == 0) {
*cpp = "LD_ASSUME_KERNEL=2.4.1";
ld_assume_kernel_done = 1;
} else if (memcmp(*cpp, valgrind_clo, valgrind_clo_len) == 0) {
*cpp = "";
}
}
/* Add the missing bits */
if (!ld_library_path_done) {
int len = ld_library_path_len + vgliblen*2 + 16;
char *cp = malloc(len);
snprintf(cp, len, "%s%s",
ld_library_path, valgrind_lib);
ret[envc++] = cp;
}
if (!ld_preload_done) {
int len = ld_preload_len + inject_path_len;
char *cp = malloc(len);
snprintf(cp, len, "%s%s",
ld_preload, inject_path);
ret[envc++] = cp;
}
if (!ld_assume_kernel_done)
ret[envc++] = "LD_ASSUME_KERNEL=2.4.1";
ret[envc] = NULL;
return ret;
}
extern char **environ; /* our environment */
int main(int argc, char **argv)
{
int vg_argc;
char **vg_argv;
char **cl_argv;
const char *tool = NULL;
const char *exec = NULL;
float ratio = 0.; /* ratio of client bytes:shadow bytes */
addr_t valgrind_base, valgrind_mmap_end;
addr_t shadow_base, shadow_end, shadow_size;
struct exeinfo info;
ToolInfo *toolinfo = NULL;
void *dl_handle;
char *preload; /* tool-specific LD_PRELOAD .so */
int ok;
char *env_clo;
int i;
if (!scan_auxv()) {
fprintf(stderr, "stage2 must be launched by stage1\n");
exit(127);
}
if (0) {
int prmap(void *start, void *end, const char *perm, off_t off, int maj, int min, int ino) {
printf("mapping %10p-%10p %s %02x:%02x %d\n",
start, end, perm, maj, min, ino);
return 1;
}
printf("========== stage2 ==========\n");
foreach_map(prmap);
}
/* Pad out client's part of memory, so that we don't accidentally
put things there - do this before anything else */
valgrind_mmap_end = (addr_t)&kickstart_base; /* end of valgrind's mmaps */
valgrind_base = valgrind_mmap_end - VALGRIND_MAPSIZE;
as_pad((void *)CLIENT_BASE, (void *)valgrind_base);
/* Work out if we're getting our main set of arguments from the
command line or from the environment (_VALGRIND_CLO). */
env_clo = getenv(VALGRINDCLO);
if (env_clo != NULL && *env_clo != '\0') {
char *cp;
char **cpp;
/* OK, we're getting all our arguments from the environment -
the entire command line belongs to the client (including
argv[0]) */
vg_argc = 1; /* argv[0] */
for(cp = env_clo; *cp; cp++)
if (*cp == '\01')
vg_argc++;
vg_argv = malloc(sizeof(char **) * (vg_argc + 1));
cpp = vg_argv;
*cpp++ = "valgrind"; /* nominal argv[0] */
*cpp++ = env_clo;
for(cp = env_clo;
*cp; cp++) {
if (*cp == '\01') {
*cp++ = '\0'; /* chop it up in place */
*cpp++ = cp;
}
}
*cpp = NULL;
cl_argv = argv;
if (0)
for(i = 0; i < vg_argc; i++)
printf("vg_argv[%d]=\"%s\"\n", i, vg_argv[i]);
} else {
/* Count the arguments on the command line. */
vg_argv = argv;
for(vg_argc = 1; vg_argc < argc; vg_argc++) {
if (argv[vg_argc][0] != '-') /* exe name */
break;
if (strcmp(argv[vg_argc], "--") == 0) { /* dummy arg */
vg_argc++;
break;
}
}
cl_argv = &argv[vg_argc];
if (cl_argv[0] == NULL) {
VG_(usage)();
exit(1);
}
}
/* look for additional user-set options from the environment (VALGRIND_OPTS) */
env_clo = getenv(VALGRINDOPTS);
if (env_clo && *env_clo) {
/* ' ' separated extra options */
char *cp;
char **from;
char **to;
char **new_argv;
int count;
count = 1;
for(cp = env_clo; *cp; cp++)
if (*cp == ' ' || *cp == '\t') {
while(cp[1] == ' ' || cp[1] == '\t')
cp++;
count++;
}
if (0)
printf("VALGRIND_OPTS=%s argc=%d\n",
env_clo, count);
new_argv = malloc((vg_argc + count + 3) * sizeof(char **));
from = vg_argv;
to = new_argv;
*to++ = *from++; /* copy argv[0] */
/* add args out of environment, skipping multiple spaces and --
args */
*to++ = env_clo;
for(cp = env_clo; *cp; cp++)
if (*cp == ' ' || *cp == '\t') {
*cp = '\0';
while(cp[1] == ' ' || cp[1] == '\t')
cp++;
if (strcmp(to[-1], "--") == 0) {
to--;
}
*to++ = cp+1;
}
/* copy original arguments, stopping at command or -- */
while(*from) {
if (**from != '-')
break;
if (strcmp(*from, "--") == 0) {
from++; /* skip -- */
break;
}
*to++ = *from++;
}
/* add -- if not already present */
if (strcmp(to[-1], "--") != 0)
*to++ = "--";
vg_argc = to-new_argv;
/* reset of original command line */
while(*from)
*to++ = *from++;
*to = NULL;
vg_argv = new_argv;
if (0)
for(i = 0; i < vg_argc; i++)
printf("vg_argv[%d]=%s\n",
i, vg_argv[i]);
}
/* parse the options we have */
for(i = 1; i < vg_argc; i++) {
if (0)
printf("vg_argv[%d]=%s\n",
i, vg_argv[i]);
if (strncmp(vg_argv[i], "--tool=", 7) == 0 ||
strncmp(vg_argv[i], "--skin=", 7) == 0)
tool = &vg_argv[i][7];
if (strncmp(vg_argv[i], "--exec=", 7) == 0)
exec = &vg_argv[i][7];
}
if (tool == NULL) {
if (tool == NULL)
list_tools();
if (0) {
for(i = 0; i < argc; i++)
fprintf(stderr, "argv[%d%s]=%s\n", i, i==vg_argc?"*":"", argv[i]);
fprintf(stderr, "tool=%s\n", tool);
}
VG_(usage)();
exit(1);
}
/* If they didn't specify an executable, then use client argv[0] -
search $PATH if it isn't already specified */
if (exec == NULL) {
exec = cl_argv[0];
if (strchr(exec, '/') == NULL) {
/* no '/' - we need to search the path */
char *path = getenv("PATH");
int pathlen = path ? strlen(path) : 0;
int match_exe(const char *entry) {
char buf[pathlen + strlen(entry) + 3];
/* empty PATH element means . */
if (*entry == '\0')
entry = ".";
snprintf(buf, sizeof(buf), "%s/%s", entry, exec);
if (access(buf, R_OK|X_OK) == 0) {
exec = strdup(buf);
return 1;
}
return 0;
}
scan_colsep(path, match_exe);
}
}
/* Look to see if we should be finding our pieces elsewhere */
{
char *cp = getenv(VALGRINDLIB);
if (cp != NULL)
valgrind_lib = cp;
}
/* While the client part of the address space is all padded
out, map in valgrind+tool proper */
ok = 1;
dl_handle = load_tool(tool, &preload);
if (dl_handle == NULL) {
fprintf(stderr, "Can't open tool \"%s\": %s\n", tool, dlerror());
ok = 0;
}
if (ok) {
Int *vg_malloc_redzonep = NULL;
toolinfo = dlsym(dl_handle, "vgSkin_tool_info");
if (toolinfo == NULL) {
fprintf(stderr, "Tool \"%s\" doesn't define SK_(tool_info) - add VG_DETERMINE_INTERFACE_VERSION?\n", tool);
ok = 0;
}
if (ok &&
(toolinfo->sizeof_ToolInfo != sizeof(*toolinfo) ||
toolinfo->interface_major_version != VG_CORE_INTERFACE_MAJOR_VERSION ||
toolinfo->sk_pre_clo_init == NULL)) {
fprintf(stderr, "Error:\n"
" Tool and core interface versions do not match.\n"
" Interface version used by core is: %d.%d (size %d)\n"
" Interface version used by tool is: %d.%d (size %d)\n"
" The major version numbers must match.\n",
VG_CORE_INTERFACE_MAJOR_VERSION,
VG_CORE_INTERFACE_MINOR_VERSION,
sizeof(*toolinfo),
toolinfo->interface_major_version,
toolinfo->interface_minor_version,
toolinfo->sizeof_ToolInfo);
fprintf(stderr, " You need to at least recompile, and possibly update,\n");
if (VG_CORE_INTERFACE_MAJOR_VERSION > toolinfo->interface_major_version)
fprintf(stderr, " your skin to work with this version of Valgrind.\n");
else
fprintf(stderr, " your version of Valgrind to work with this skin.\n");
fprintf(stderr, " Aborting, sorry.\n");
ok = 0;
}
ratio = toolinfo->shadow_ratio;
/* If the tool wants a different malloc heap redzone size, then
set it up here, before we start using the core's
allocator. */
if (ok && (vg_malloc_redzonep = dlsym(dl_handle, STR(VG_(vg_malloc_redzone_szB)))) != NULL)
VG_(vg_malloc_redzone_szB) = *vg_malloc_redzonep;
}
if (!ok) {
if (dl_handle != NULL)
dlclose(dl_handle);
fprintf(stderr, "Aborting: couldn't initialize valgrind\n");
list_tools();
exit(127);
}
/* Work out overall shape of the address space. This tries to give
the client as large as possible address space while taking into
account the tool's shadow needs. */
client_size = ROUNDDN((valgrind_base - REDZONE_SIZE) / (1. + ratio), CLIENT_SIZE_MULTIPLE);
client_end = CLIENT_BASE + client_size;
shadow_size = PGROUNDUP(client_size * ratio);
shadow_base = client_end + REDZONE_SIZE;
shadow_end = shadow_base + shadow_size;
if (0)
printf("valgrind_base=%x client_size=%x shadow=%x-%x (%x)\n",
valgrind_base, client_size,
shadow_base, shadow_end, shadow_size);
/* make the redzone inaccessible */
mmap((void *)client_end, REDZONE_SIZE, PROT_NONE,
MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
munmap(CLIENT_BASE, client_size); /* make client hole */
kp.client_mapbase = PGROUNDDN((client_size/4)*3); /* where !FIXED mmap goes */
info.exe_base = client_base;
info.exe_end = client_end;
info.map_base = kp.client_mapbase;
info.setbrk = 0;
info.argv = cl_argv;
kp.clexecfd = open(exec, O_RDONLY);
{
int ret = do_exec(exec, &info);
if (ret != 0) {
fprintf(stderr, "do_exec(%s) failed: %s\n", exec, strerror(ret));
exit(127);
}
}
/* Shadow memory - initially all inaccessible, but then
incrementally initialized as it is used */
if (shadow_size != 0)
mmap((char *)shadow_base, shadow_size, PROT_NONE,
MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0);
/* unpad us */
as_unpad((void *)shadow_end, (void *)~0);
{
char **env;
const struct ume_auxv *auxv;
/* use our own auxv as a prototype */
auxv = find_auxv(ume_exec_esp);
/* set up the client's environment */
env = fix_environment(environ, preload);
/* client's stack and eip */
kp.client_esp = setup_client_stack(cl_argv, env, auxv, &info);
kp.client_eip = info.init_eip;
}
/* Valgrind's argc/argv */
kp.argc = vg_argc;
kp.argv = (Char **)vg_argv;
kp.libdir = valgrind_lib;
/* client address space */
kp.client_base = CLIENT_BASE;
kp.client_end = client_end;
kp.client_brkbase = info.brkbase;
/* shadow segment */
kp.shadow_base = shadow_base;
kp.shadow_end = shadow_end;
/* valgrind address space */
kp.vg_base = valgrind_base;
kp.vg_mmap_end = valgrind_mmap_end;
kp.vg_end = ROUNDUP((Addr)&argc, 0x10000); /* stack */
as_closepadfile(); /* no more padding */
if (0)
printf("entry=%x client esp=%x vg_argc=%d brkbase=%x\n",
kp.client_eip, kp.client_esp, kp.argc, kp.client_brkbase);
#if 1
VG_(main)(&kp, toolinfo->sk_pre_clo_init, dl_handle);
#else
ume_go(kp.client_eip, kp.client_esp);
#endif
abort();
}