communicate some extra information to stage2 (namely, the fd of the
padding file, so it can identiry and remove the padding later).
*/
-static void *fix_auxv(void *v_init_esp, const struct exeinfo *info)
+static void *fix_auxv(void *v_init_esp, const struct exeinfo *info,
+ int padfile)
{
struct ume_auxv *auxv;
int *newesp;
/* stage2 needs this so it can clean up the padding we leave in
place when we start it */
auxv[0].a_type = AT_UME_PADFD;
- auxv[0].u.a_val = as_getpadfd();
+ auxv[0].u.a_val = padfile;
/* This will be needed by valgrind itself so that it can
subsequently execve() children. This needs to be done here
return v_init_esp;
}
-static int prmap(void *start, void *end, const char *perm, off_t off, int maj, int min, int ino) {
+static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
+ int min, int ino, void* dummy) {
printf("mapping %10p-%10p %s %02x:%02x %d\n",
start, end, perm, maj, min, ino);
return 1;
static void hoops(void)
{
- int err;
+ int err, padfile;
struct exeinfo info;
extern char _end;
int *esp;
/* Make sure stage2's dynamic linker can't tromp on the lower part
of the address space. */
- as_pad(0, (void *)info.map_base);
+ padfile = as_openpadfile();
+ as_pad(0, (void *)info.map_base, padfile);
- esp = fix_auxv(ume_exec_esp, &info);
+ esp = fix_auxv(ume_exec_esp, &info, padfile);
if (0) {
printf("---------- launch stage 2 ----------\n");
printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
- foreach_map(prmap);
+ foreach_map(prmap, /*dummy*/NULL);
}
ume_go(info.init_eip, (addr_t)esp);
int fd;
};
-static int padfile = -1;
-static struct stat padstat;
-
-extern int kickstart_base; /* linker created */
-
static void check_mmap(void* res, void* base, int len)
{
if ((void*)-1 == res) {
}
}
-void foreach_map(int (*fn)(void *start, void *end,
+// 'extra' allows the caller to pass in extra args to 'fn', like free
+// variables to a closure.
+void foreach_map(int (*fn)(char *start, char *end,
const char *perm, off_t offset,
- int maj, int min, int ino))
+ int maj, int min, int ino, void* extra),
+ void* extra)
{
static char buf[10240];
char *bufptr = buf;
if (bufptr != NULL)
bufptr++; /* skip \n */
- if (!(*fn)(segstart, segend, perm, offset, maj, min, ino))
+ if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
break;
}
}
-static char *fillgap_addr;
-static char *fillgap_end;
+typedef struct {
+ char* fillgap_start;
+ char* fillgap_end;
+ int fillgap_padfile;
+} fillgap_extra;
+
+static int fillgap(char *segstart, char *segend, const char *perm, off_t off,
+ int maj, int min, int ino, void* e)
+{
+ fillgap_extra* extra = e;
-static int fillgap(void *segstart, void *segend, const char *perm, off_t off,
- int maj, int min, int ino) {
- if ((char *)segstart >= fillgap_end)
+ if (segstart >= extra->fillgap_end)
return 0;
- if ((char *)segstart > fillgap_addr) {
- void* res = mmap(fillgap_addr, (char *)segstart-fillgap_addr, PROT_NONE,
- MAP_FIXED|MAP_PRIVATE, padfile, 0);
- check_mmap(res, fillgap_addr, (char*)segstart - fillgap_addr);
+ if (segstart > extra->fillgap_start) {
+ void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
+ PROT_NONE, MAP_FIXED|MAP_PRIVATE,
+ extra->fillgap_padfile, 0);
+ check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
}
- fillgap_addr = segend;
+ extra->fillgap_start = segend;
return 1;
}
-/* pad all the empty spaces in a range of address space to stop
- interlopers */
-void as_pad(void *start, void *end)
+// Choose a name for the padfile, open it.
+int as_openpadfile(void)
{
- char buf[1024];
-
- if (padfile == -1) {
- int seq = 1;
- do {
- sprintf(buf, "/tmp/.pad.%d.%d", getpid(), seq++);
- padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
- unlink(buf);
- if (padfile == -1 && errno != EEXIST)
- exit(44);
- } while(padfile == -1);
- fstat(padfile, &padstat);
- }
+ char buf[256];
+ int padfile;
+ int seq = 1;
+ do {
+ snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
+ padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
+ unlink(buf);
+ if (padfile == -1 && errno != EEXIST) {
+ fprintf(stderr, "valgrind: couldn't open padfile\n");
+ exit(44);
+ }
+ } while(padfile == -1);
+
+ return padfile;
+}
- fillgap_addr = start;
- fillgap_end = end;
+// Pad all the empty spaces in a range of address space to stop interlopers.
+void as_pad(void *start, void *end, int padfile)
+{
+ fillgap_extra extra;
+ extra.fillgap_start = start;
+ extra.fillgap_end = end;
+ extra.fillgap_padfile = padfile;
- foreach_map(fillgap);
+ foreach_map(fillgap, &extra);
- if (fillgap_addr < fillgap_end) {
- void* res = mmap(fillgap_addr, fillgap_end-fillgap_addr, PROT_NONE,
- MAP_FIXED|MAP_PRIVATE, padfile, 0);
- check_mmap(res, fillgap_addr, fillgap_end - fillgap_addr);
+ if (extra.fillgap_start < extra.fillgap_end) {
+ void* res = mmap(extra.fillgap_start,
+ extra.fillgap_end - extra.fillgap_start,
+ PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
+ check_mmap(res, extra.fillgap_start,
+ extra.fillgap_end - extra.fillgap_start);
}
}
-static void *killpad_start;
-static void *killpad_end;
+typedef struct {
+ char* killpad_start;
+ char* killpad_end;
+ struct stat* killpad_padstat;
+} killpad_extra;
-static int killpad(void *segstart, void *segend, const char *perm, off_t off,
- int maj, int min, int ino)
+static int killpad(char *segstart, char *segend, const char *perm, off_t off,
+ int maj, int min, int ino, void* ex)
{
+ killpad_extra* extra = ex;
void *b, *e;
int res;
- if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
+ assert(NULL != extra->killpad_padstat);
+
+ if (extra->killpad_padstat->st_dev != makedev(maj, min) ||
+ extra->killpad_padstat->st_ino != ino)
return 1;
- if (segend <= killpad_start || segstart >= killpad_end)
+ if (segend <= extra->killpad_start || segstart >= extra->killpad_end)
return 1;
- if (segstart <= killpad_start)
- b = killpad_start;
+ if (segstart <= extra->killpad_start)
+ b = extra->killpad_start;
else
b = segstart;
- if (segend >= killpad_end)
- e = killpad_end;
+ if (segend >= extra->killpad_end)
+ e = extra->killpad_end;
else
e = segend;
return 1;
}
-/* remove padding from a range of address space - padding is always a
- mapping of padfile*/
-void as_unpad(void *start, void *end)
+// Remove padding of 'padfile' from a range of address space.
+void as_unpad(void *start, void *end, int padfile)
{
- if (padfile == -1) /* no padfile, no padding */
- return;
-
- killpad_start = start;
- killpad_end = end;
-
- foreach_map(killpad);
-}
+ static struct stat padstat;
+ killpad_extra extra;
+ int res;
-void as_closepadfile(void)
-{
- /* don't unpad */
- close(padfile);
- padfile = -1;
+ assert(padfile > 0);
+
+ res = fstat(padfile, &padstat);
+ assert(0 == res);
+ extra.killpad_padstat = &padstat;
+ extra.killpad_start = start;
+ extra.killpad_end = end;
+ foreach_map(killpad, &extra);
}
-int as_getpadfd(void)
+void as_closepadfile(int padfile)
{
- return padfile;
+ int res = close(padfile);
+ assert(0 == res);
}
-void as_setpadfd(int fd)
-{
- as_closepadfile();
- padfile = fd;
- fstat(padfile, &padstat);
-}
+/*------------------------------------------------------------*/
+/*--- Finding auxv on the stack ---*/
+/*------------------------------------------------------------*/
struct ume_auxv *find_auxv(int *esp)
{
return (struct ume_auxv *)esp;
}
+/*------------------------------------------------------------*/
+/*--- Loading ELF files ---*/
+/*------------------------------------------------------------*/
struct elfinfo *readelf(int fd, const char *filename)
{
return e;
}
-#define REMAINS(x, a) ((x) & ((a)-1))
-
/* Map an ELF file. Returns the brk address. */
ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
{
return elfbrk;
}
-
+// Forward declaration.
static int do_exec_inner(const char *exe, struct exeinfo *info);
-
static int match_ELF(const char *hdr, int len)
{
ESZ(Ehdr) *e = (ESZ(Ehdr) *)hdr;
return (len > sizeof(*e)) && memcmp(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
}
-static int load_ELF(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
+static int load_ELF(char *hdr, int len, int fd, const char *name,
+ struct exeinfo *info)
{
struct elfinfo *e;
struct elfinfo *interp = NULL;
return (len > 2) && memcmp(hdr, "#!", 2) == 0;
}
-static int load_script(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
+static int load_script(char *hdr, int len, int fd, const char *name,
+ struct exeinfo *info)
{
char *interp;
char *const end = hdr+len;
return do_exec_inner(interp, info);
}
-struct binfmt {
- int (*match)(const char *hdr, int len);
- int (*load) ( char *hdr, int len, int fd, const char *name, struct exeinfo *);
-};
-
-static const struct binfmt formats[] = {
- { match_ELF, load_ELF },
- { match_script, load_script },
-};
-
-
static int do_exec_inner(const char *exe, struct exeinfo *info)
{
int fd;
int i;
int ret;
struct stat st;
+ static const struct {
+ int (*match)(const char *hdr, int len);
+ int (*load) ( char *hdr, int len, int fd2, const char *name,
+ struct exeinfo *);
+ } formats[] = {
+ { match_ELF, load_ELF },
+ { match_script, load_script },
+ };
fd = open(exe, O_RDONLY);
if (fd == -1) {
/*====================================================================*/
/* Look for our AUXV table */
-static void scan_auxv(void)
+int scan_auxv(void)
{
const struct ume_auxv *auxv = find_auxv((int *)ume_exec_esp);
- int found = 0;
+ int padfile = -1, found = 0;
for (; auxv->a_type != AT_NULL; auxv++)
switch(auxv->a_type) {
case AT_UME_PADFD:
- as_setpadfd(auxv->u.a_val);
+ padfile = auxv->u.a_val;
found |= 1;
break;
fprintf(stderr, "valgrind: stage2 must be launched by stage1\n");
exit(127);
}
+ vg_assert(padfile >= 0);
+ return padfile;
}
/*=== Address space determination ===*/
/*====================================================================*/
-/* Pad client space so it doesn't get filled in before the right time */
-static void layout_client_space(Addr argc_addr)
+static void layout_remaining_space(Addr argc_addr, float ratio)
{
- VG_(client_base) = CLIENT_BASE;
- VG_(valgrind_base) = (addr_t)&kickstart_base;
- VG_(valgrind_end) = ROUNDUP(argc_addr, 0x10000); /* stack */
+ Int ires;
+ void* vres;
+ addr_t client_size, shadow_size;
- as_pad((void *)VG_(client_base), (void *)VG_(valgrind_base));
-}
+ VG_(valgrind_base) = (addr_t)&kickstart_base;
+ VG_(valgrind_end) = ROUNDUP(argc_addr, 0x10000); // stack
-static void layout_remaining_space(float ratio)
-{
- Int ires;
- void* vres;
-
- /* This tries to give the client as large as possible address space while
- * taking into account the tool's shadow needs. */
- addr_t client_size = ROUNDDN((VG_(valgrind_base) - REDZONE_SIZE) / (1. + ratio),
+ // This gives the client the largest possible address space while
+ // taking into account the tool's shadow needs.
+ client_size = ROUNDDN((VG_(valgrind_base)-REDZONE_SIZE) / (1.+ratio),
CLIENT_SIZE_MULTIPLE);
- addr_t shadow_size = PGROUNDUP(client_size * ratio);
-
+ VG_(client_base) = CLIENT_BASE;
VG_(client_end) = VG_(client_base) + client_size;
/* where !FIXED mmap goes */
VG_(client_mapbase) = VG_(client_base) +
PGROUNDDN((addr_t)(client_size * CLIENT_HEAP_PROPORTION));
- VG_(shadow_base) = VG_(client_end) + REDZONE_SIZE;
- VG_(shadow_end) = VG_(shadow_base) + shadow_size;
+ shadow_size = PGROUNDUP(client_size * ratio);
+ VG_(shadow_base) = VG_(client_end) + REDZONE_SIZE;
+ VG_(shadow_end) = VG_(shadow_base) + shadow_size;
#define SEGSIZE(a,b) ((VG_(b) - VG_(a))/(1024*1024))
build the segment skip-list.
*/
-static int prmap(void *start, void *end, const char *perm, off_t off,
- int maj, int min, int ino) {
+static int prmap(char *start, char *end, const char *perm, off_t off,
+ int maj, int min, int ino, void* dummy) {
printf("mapping %10p-%10p %s %02x:%02x %d\n",
start, end, perm, maj, min, ino);
return True;
VgSchedReturnCode src;
Int exitcode = 0;
vki_rlimit zero = { 0, 0 };
+ Int padfile;
//============================================================
// Nb: startup is complex. Prerequisites are shown at every step.
// Check we were launched by stage1
// p: n/a
//--------------------------------------------------------------
- scan_auxv();
+ padfile = scan_auxv();
if (0) {
printf("========== main() ==========\n");
- foreach_map(prmap);
+ foreach_map(prmap, /*dummy*/NULL);
}
//--------------------------------------------------------------
VG_(libdir) = cp;
}
- //--------------------------------------------------------------
- // Begin working out address space layout
- // p: n/a
- //--------------------------------------------------------------
- layout_client_space( (Addr) & argc );
-
//--------------------------------------------------------------
// Get valgrind args + client args (inc. from VALGRIND_OPTS/.valgrindrc).
// Pre-process the command line.
//--------------------------------------------------------------
// With client padded out, map in tool
- // p: layout_client_space() [for padding]
// p: set-libdir [for VG_(libdir)]
// p: pre_process_cmd_line_options() [for 'tool']
//--------------------------------------------------------------
//--------------------------------------------------------------
// Finalise address space layout
- // p: layout_client_space(), load_tool() [for 'toolinfo']
+ // p: load_tool() [for 'toolinfo']
//--------------------------------------------------------------
- layout_remaining_space( toolinfo->shadow_ratio );
+ layout_remaining_space( (Addr) & argc, toolinfo->shadow_ratio );
//--------------------------------------------------------------
// Load client executable, finding in $PATH if necessary
- // p: layout_client_space() [so there's space]
// p: pre_process_cmd_line_options() [for 'exec', 'need_help']
// p: layout_remaining_space [so there's space]
//--------------------------------------------------------------
// p: layout_remaining_space() [everything must be mapped in before now]
// p: load_client() [ditto]
//--------------------------------------------------------------
- as_unpad((void *)VG_(shadow_end), (void *)~0);
- as_closepadfile(); /* no more padding */
+ as_unpad((void *)VG_(shadow_end), (void *)~0, padfile);
+ as_closepadfile(padfile); // no more padding
//--------------------------------------------------------------
// Set up client's environment