Add and delete all the files which need adding and deleting.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2119 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/corecheck/tests/as_mmap.c b/corecheck/tests/as_mmap.c
new file mode 100644
index 0000000..da40a86
--- /dev/null
+++ b/corecheck/tests/as_mmap.c
@@ -0,0 +1,26 @@
+#include <sys/mman.h>
+#include <stdio.h>
+
+int main()
+{
+ char local;
+ char *top = (char *)(((unsigned long)&local + 0x0fffffff) & ~0x0fffffff);
+
+ if (mmap((void *)0x00000000, 0x10000, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED)
+ perror("mmap @ 0x00000000");
+ if (mmap((void *)0x00010000, 0x10000, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED)
+ perror("mmap @ 0x00010000");
+ if (mmap((void *)0x50000000, 0x10000, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED)
+ perror("mmap @ 0x50000000");
+ if (mmap(top, 0x10000, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED)
+ perror("mmap @ top");
+ if (mmap(top+0x08000000, 0x10000, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0) == MAP_FAILED)
+ perror("mmap @ top+.5G");
+
+ return 0;
+}
diff --git a/corecheck/tests/as_mmap.stderr.exp b/corecheck/tests/as_mmap.stderr.exp
new file mode 100644
index 0000000..e5314c8
--- /dev/null
+++ b/corecheck/tests/as_mmap.stderr.exp
@@ -0,0 +1,9 @@
+
+Warning: client syscall mmap2 tried to modify addresses 0x0-0x10000
+mmap @ 0x00000000: Cannot allocate memory
+Warning: client syscall mmap2 tried to modify addresses 0xB0000000-0xB0010000
+mmap @ top: Cannot allocate memory
+Warning: client syscall mmap2 tried to modify addresses 0xB8000000-0xB8010000
+mmap @ top+.5G: Cannot allocate memory
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/corecheck/tests/as_mmap.vgtest b/corecheck/tests/as_mmap.vgtest
new file mode 100644
index 0000000..13cb451
--- /dev/null
+++ b/corecheck/tests/as_mmap.vgtest
@@ -0,0 +1 @@
+prog: as_mmap
diff --git a/corecheck/tests/as_shm.c b/corecheck/tests/as_shm.c
new file mode 100644
index 0000000..2c86cb6
--- /dev/null
+++ b/corecheck/tests/as_shm.c
@@ -0,0 +1,32 @@
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <stdio.h>
+
+int main()
+{
+ int shmid = shmget(IPC_PRIVATE, 0x10000, IPC_CREAT|IPC_EXCL|0777);
+ void *addr;
+ char local;
+ char *top = (char *)(((unsigned long)&local + 0x0fffffff) & ~0x0fffffff);
+
+ if (shmid == -1)
+ perror("shmget");
+
+ addr = shmat(shmid, 0, 0);
+
+ if (addr == (void *)-1)
+ perror("shmat @ 0");
+ else
+ printf("shmat 0: addr=%p\n", addr);
+
+ addr = shmat(shmid, top, 0);
+
+ if (addr == (void *)-1)
+ perror("shmat @ top");
+ else
+ printf("shmat 2: addr=%p\n", addr);
+
+ shmctl(shmid, IPC_RMID, NULL);
+
+ return 0;
+}
diff --git a/corecheck/tests/as_shm.stderr.exp b/corecheck/tests/as_shm.stderr.exp
new file mode 100644
index 0000000..ee51d43
--- /dev/null
+++ b/corecheck/tests/as_shm.stderr.exp
@@ -0,0 +1,5 @@
+
+Warning: client syscall shmat tried to modify addresses 0xB0000000-0xB0010000
+shmat @ top: Invalid argument
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/corecheck/tests/as_shm.stdout.exp b/corecheck/tests/as_shm.stdout.exp
new file mode 100644
index 0000000..d2dcf73
--- /dev/null
+++ b/corecheck/tests/as_shm.stdout.exp
@@ -0,0 +1 @@
+shmat 0: addr=0x81156000
diff --git a/corecheck/tests/as_shm.vgtest b/corecheck/tests/as_shm.vgtest
new file mode 100644
index 0000000..1263cea
--- /dev/null
+++ b/corecheck/tests/as_shm.vgtest
@@ -0,0 +1 @@
+prog: as_shm
diff --git a/coregrind/gen_toolint.pl b/coregrind/gen_toolint.pl
new file mode 100644
index 0000000..2738f92
--- /dev/null
+++ b/coregrind/gen_toolint.pl
@@ -0,0 +1,262 @@
+#!/usr/bin/perl
+
+my $output = shift @ARGV;
+my $indent = "";
+my $headerguard;
+my $include;
+my $passcomment = 1;
+
+my $struct = "VG_(tool_interface)";
+
+my %pfxmap = ("track" => "SK_",
+ "tool" => "SK_",
+ "malloc"=> "SK_",
+ );
+
+sub getargnames(@) {
+ my @args = @_;
+ my @ret;
+
+ foreach my $a (@args) {
+ my @pieces = split /\s+/, $a;
+ my $name = pop @pieces;
+ push @ret, $name unless $name eq "void";
+ }
+ return @ret;
+}
+
+sub getargtypes(@) {
+ my @args = @_;
+ my @ret;
+
+ foreach my $a (@args) {
+ my @pieces = split /\s+/, $a;
+ pop @pieces;
+ push @ret, (join " ", @pieces);
+ }
+ @ret = "void" if ($#ret == -1);
+ return @ret;
+}
+
+# Different output modes
+if ($output eq "callwrap") {
+ $include = "vg_include.h";
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ", ", @args;
+ my $argnames = join ", ", getargnames(@args);
+ print "$ret $pfxmap{$pfx}($func)($args)\n{\n";
+ print " return (*$struct.${pfx}_$func)($argnames);\n";
+ print "}\n";
+ }
+} elsif ($output eq "proto") {
+ $include = "vg_include.h";
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ', ', @args;
+
+ print "$ret $pfxmap{$pfx}($func)($args);\n";
+ print "Bool VG_(defined_$func)(void);\n";
+ }
+} elsif ($output eq "toolproto") {
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ', ', @args;
+
+ print "$ret $pfxmap{$pfx}($func)($args);\n";
+ }
+} elsif ($output eq "missingfuncs") {
+ $include = "vg_include.h";
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ", ", @args;
+
+ print "static $ret missing_${pfx}_$func($args) {\n";
+ print " VG_(missing_tool_func)(\"${pfx}_$func\");\n";
+ print "}\n";
+ print "Bool VG_(defined_$func)(void) {\n";
+ print " return $struct.${pfx}_$func != missing_${pfx}_$func;\n";
+ print "}\n\n";
+ };
+ $indent = " ";
+} elsif ($output eq "struct") {
+ $include = "vg_include.h";
+ $pre = sub () {
+ print "typedef struct {\n";
+ };
+ $post = sub () {
+ print "} VgToolInterface;\n\n";
+ print "extern VgToolInterface $struct;\n"
+ };
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ", ", @args;
+
+ print "$indent$ret (*${pfx}_$func)($args);\n";
+ };
+ $indent = " ";
+ $headerguard=$output;
+} elsif ($output eq "structdef") {
+ $include = "vg_toolint.h";
+ $pre = sub () {
+ print "VgToolInterface $struct = {\n";
+ };
+ $post = sub () {
+ print "};\n";
+ };
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+
+ print "$indent.${pfx}_$func = missing_${pfx}_$func,\n"
+ };
+ $indent = " ";
+} elsif ($output eq "initfunc") {
+ $include = "vg_skin.h";
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ", ", @args;
+ my $argnames = join ", ", getargnames(@args);
+
+ print <<EOF;
+void VG_(init_$func)($ret (*func)($args))
+{
+ if (func == NULL)
+ func = missing_${pfx}_$func;
+ if (VG_(defined_$func)())
+ VG_(printf)("Warning tool is redefining $func\\n");
+ if (func == SK_($func))
+ VG_(printf)("Warning tool is defining $func recursively\\n");
+ $struct.${pfx}_$func = func;
+}
+EOF
+ }
+} elsif ($output eq "initproto") {
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ', ', @args;
+ print "void VG_(init_$func)($ret (*func)($args));\n";
+ };
+ $headerguard=$output;
+} elsif ($output eq "initdlsym") {
+ $pre = sub () {
+ print <<EOF;
+#include <dlfcn.h>
+void VG_(tool_init_dlsym)(void *dlhandle)
+{
+ void *ret;
+
+EOF
+ };
+ $post = sub () {
+ print "}\n";
+ };
+ $generate = sub ($$$@) {
+ my ($pfx, $ret, $func, @args) = @_;
+ my $args = join ", ", getargtypes(@args);
+
+ print <<EOF;
+ ret = dlsym(dlhandle, "vgSkin_$func");
+ if (ret != NULL)
+ VG_(init_$func)(($ret (*)($args))ret);
+
+EOF
+ };
+
+ $passcomment = 0;
+}
+
+die "Unknown output format \"$output\"" unless defined $generate;
+
+print "/* Generated by \"gen_toolint.pl $output\" */\n";
+
+print <<EOF if defined $headerguard;
+
+#ifndef VG_toolint_$headerguard
+#define VG_toolint_$headerguard
+
+EOF
+
+print <<EOF if defined $include;
+#include \"$include\"
+EOF
+
+&$pre() if defined $pre; # preamble
+
+my $state = "idle";
+
+my $buf;
+my $lines;
+
+while(<STDIN>) {
+ # skip simple comments
+ next if (/^#[^#]/);
+
+ if (/^:/) {
+ s/^://;
+ chomp;
+ $prefix=$_;
+ next;
+ }
+
+ # look for inserted comments
+ if (/^##/) {
+ if ($state eq "idle") {
+ $state = "comment";
+ $lines = 1;
+ $_ =~ s,^## ,/* ,;
+ $buf = $_;
+ next;
+ } elsif ($state eq "comment") {
+ $lines++;
+ $_ =~ s,^## , ,;
+ print $indent.$buf if $passcomment;
+ $buf = $_;
+ next;
+ }
+ next;
+ }
+
+ # blank lines in a comment are part of the comment
+ if (/^\s*$/) {
+ if ($state eq "comment") {
+ $lines++;
+ print $indent.$buf if $passcomment;
+ $buf = "\n";
+ } else {
+ print "\n" if $passcomment;
+ }
+ next;
+ }
+
+ # coming out of a comment
+ if ($state eq "comment") {
+ chomp $buf;
+
+ if ($passcomment) {
+ if ($lines == 1) {
+ print "$indent$buf */\n";
+ } else {
+ print "$indent$buf\n$indent */\n";
+ }
+ }
+ $buf = "";
+ $state = "idle";
+ }
+
+ chomp;
+ my @func = split /,\s*/;
+
+ my $rettype = shift @func;
+ my $funcname = shift @func;
+
+ @func = "void" if scalar @func == 0;
+
+ &$generate ($prefix, $rettype, $funcname, @func);
+}
+
+&$post() if defined $post; # postamble
+
+print <<EOF if defined $headerguard;
+
+#endif /* VG_toolint_$headerguard */
+EOF
diff --git a/coregrind/stage1.c b/coregrind/stage1.c
new file mode 100644
index 0000000..4d6d5db
--- /dev/null
+++ b/coregrind/stage1.c
@@ -0,0 +1,183 @@
+#define _FILE_OFFSET_BITS 64
+
+#include <stdio.h>
+#include <elf.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "vg_include.h"
+
+#include "ume.h"
+#include "ume_arch.h"
+#include "ume_archdefs.h"
+
+static int stack[SIGSTKSZ*4];
+static int our_argc;
+
+/* Where we expect to find all our aux files (namely, stage2) */
+static const char *valgrind_lib = VG_LIBDIR;
+
+/* stage2's name */
+static const char stage2[] = "stage2";
+
+/* Modify the auxv the kernel gave us to make it look like we were
+ execed as the shared object.
+
+ This also inserts a new entry into the auxv table so we can
+ 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)
+{
+ struct ume_auxv *auxv;
+ int *newesp;
+ int seen;
+ int delta;
+ int i;
+ static const int new_entries = 2;
+
+ /* make sure we're running on the private stack */
+ assert(&delta >= stack && &delta < &stack[sizeof(stack)/sizeof(*stack)]);
+
+ /* find the beginning of the AUXV table */
+ auxv = find_auxv(v_init_esp);
+
+ /* Work out how we should move things to make space for the new
+ auxv entry. It seems that ld.so wants a 16-byte aligned stack on
+ entry, so make sure that's the case. */
+ newesp = (int *)(((unsigned long)v_init_esp - new_entries * sizeof(*auxv)) & ~0xf);
+ delta = (char *)v_init_esp - (char *)newesp;
+
+ memmove(newesp, v_init_esp, (char *)auxv - (char *)v_init_esp);
+
+ v_init_esp = (void *)newesp;
+ auxv -= delta/sizeof(*auxv);
+
+ /* 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].a_val = as_getpadfd();
+
+ /* This will be needed by valgrind itself so that it can
+ subsequently execve() children. This needs to be done here
+ because /proc/self/exe will go away once we unmap stage1. */
+ auxv[1].a_type = AT_UME_EXECFD;
+ auxv[1].a_val = open("/proc/self/exe", O_RDONLY);
+
+ /* make sure the rest are sane */
+ for(i = new_entries; i < delta/sizeof(*auxv); i++) {
+ auxv[i].a_type = AT_IGNORE;
+ auxv[i].a_val = 0;
+ }
+
+ /* OK, go through and patch up the auxv entries to match the new
+ executable */
+ seen = 0;
+ for(; auxv->a_type != AT_NULL; auxv++) {
+ if (0)
+ printf("doing auxv %p %4x: %d %p\n", auxv, auxv->a_type, auxv->a_val, auxv->a_ptr);
+
+ switch(auxv->a_type) {
+ case AT_PHDR:
+ seen |= 1;
+ auxv->a_val = info->phdr;
+ break;
+
+ case AT_PHNUM:
+ seen |= 2;
+ auxv->a_val = info->phnum;
+ break;
+
+ case AT_BASE:
+ seen |= 4;
+ auxv->a_val = info->interp_base;
+ break;
+
+ case AT_ENTRY:
+ seen |= 8;
+ auxv->a_val = info->entry;
+ break;
+ }
+ }
+
+ /* If we didn't see all the entries we need to fix up, then we
+ can't make the new executable viable. */
+ if (seen != 0xf) {
+ fprintf(stderr, "fix_auxv: we didn't see enough auxv entries (seen=%x)\n", seen);
+ exit(1);
+ }
+
+ return v_init_esp;
+}
+
+static void hoops(void)
+{
+ int err;
+ struct exeinfo info;
+ extern char _end;
+ int *esp;
+ char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
+
+ info.exe_base = PGROUNDUP(&_end);
+ info.exe_end = PGROUNDDN(ume_exec_esp);
+
+ /* XXX FIXME: how can stage1 know where stage2 wants things placed?
+ Options:
+ - we could look for a symbol
+ - it could have a special PHDR (v. ELF specific)
+ - something else?
+ */
+ info.map_base = 0xb0000000;
+ info.setbrk = 1; /* ask do_exec to move the brk-base */
+ info.argv = NULL;
+
+ strcpy(buf, valgrind_lib);
+ strcat(buf, "/");
+ strcat(buf, stage2);
+
+ err = do_exec(buf, &info);
+
+ if (err != 0) {
+ fprintf(stderr, "failed to load %s: %s\n",
+ buf, strerror(err));
+ exit(1);
+ }
+
+ /* Make sure stage2's dynamic linker can't tromp on the lower part
+ of the address space. */
+ as_pad(0, (void *)info.map_base);
+
+ esp = fix_auxv(ume_exec_esp, &info);
+
+ 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("---------- launch stage 2 ----------\n");
+ printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
+ foreach_map(prmap);
+ }
+
+ ume_go(info.init_eip, (addr_t)esp);
+}
+
+int main(int argc, char **argv)
+{
+ const char *cp = getenv(VALGRINDLIB);
+
+ if (cp != NULL)
+ valgrind_lib = cp;
+
+ assert(ume_exec_esp != NULL);
+
+ our_argc = argc;
+
+ /* move onto another stack so we can play with the main one */
+ ume_go((addr_t)hoops, (addr_t)stack + sizeof(stack));
+}
diff --git a/coregrind/stage2.c b/coregrind/stage2.c
new file mode 100644
index 0000000..c105bd8
--- /dev/null
+++ b/coregrind/stage2.c
@@ -0,0 +1,967 @@
+#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.execfd = 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(1);
+ }
+
+ 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(1);
+ }
+
+ /* 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;
+
+ {
+ int ret = do_exec(exec, &info);
+ if (ret != 0) {
+ fprintf(stderr, "do_exec(%s) failed: %s\n", exec, strerror(ret));
+ exit(1);
+ }
+ }
+
+ /* 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();
+}
diff --git a/coregrind/toolfuncs.def b/coregrind/toolfuncs.def
new file mode 100644
index 0000000..c4d9577
--- /dev/null
+++ b/coregrind/toolfuncs.def
@@ -0,0 +1,302 @@
+# Tool interface functions
+# The format for an interface function definition is:
+# return_type, func_name, type arg, type arg
+# If the function has no arguments, specify no arguments (rather than void)
+#
+# Comments starting with "##" are turned into C comments in the output
+#
+# Lines starting with : set the prefix
+
+## These are the parameterised functions in the core. The default definitions
+## are overridden by LD_PRELOADed skin version. At the very least, a skin
+## must define the fundamental template functions. Depending on what needs
+## are set, extra template functions will be used too. Functions are
+## grouped under the needs that govern their use.
+
+:tool
+## ------------------------------------------------------------------
+## Fundamental template functions
+
+## Do initialisation that can only be done after command line processing.
+void, post_clo_init
+
+## Instrument a basic block. Must be a true function, ie. the same input
+## always results in the same output, because basic blocks can be
+## retranslated. Unless you're doing something really strange...
+## 'orig_addr' is the address of the first instruction in the block.
+UCodeBlock*, instrument, UCodeBlock* cb, Addr orig_addr
+
+## Finish up, print out any results, etc. `exitcode' is program's exit
+## code. The shadow (if the `shadow_regs' need is set) can be found with
+## VG_(get_shadow_archreg)(R_EBX), since %ebx holds the argument to the
+## exit() syscall.
+void, fini, Int exitcode
+
+
+## ------------------------------------------------------------------
+## VG_(needs).core_errors
+
+## (none needed)
+
+## ------------------------------------------------------------------
+## VG_(needs).skin_errors
+
+## Identify if two errors are equal, or equal enough. `res' indicates how
+## close is "close enough". `res' should be passed on as necessary, eg. if
+## the Error's `extra' part contains an ExeContext, `res' should be
+## passed to VG_(eq_ExeContext)() if the ExeContexts are considered. Other
+## than that, probably don't worry about it unless you have lots of very
+## similar errors occurring.
+Bool, eq_SkinError, VgRes res, Error* e1, Error* e2
+
+## Print error context.
+void, pp_SkinError, Error* err
+
+## Should fill in any details that could be postponed until after the
+## decision whether to ignore the error (ie. details not affecting the
+## result of SK_(eq_SkinError)()). This saves time when errors are ignored.
+## Yuk.
+
+## Return value: must be the size of the `extra' part in bytes -- used by
+## the core to make a copy.
+UInt, update_extra, Error* err
+
+## Return value indicates recognition. If recognised, must set skind using
+## VG_(set_supp_kind)().
+Bool, recognised_suppression, Char* name, Supp* su
+
+## Read any extra info for this suppression kind. Most likely for filling
+## in the `extra' and `string' parts (with VG_(set_supp_{extra, string})())
+## of a suppression if necessary. Should return False if a syntax error
+## occurred, True otherwise.
+Bool, read_extra_suppression_info, Int fd, Char* buf, Int nBuf, Supp* su
+
+## This should just check the kinds match and maybe some stuff in the
+## `string' and `extra' field if appropriate (using VG_(get_supp_*)() to
+## get the relevant suppression parts).
+Bool, error_matches_suppression, Error* err, Supp* su
+
+## This should return the suppression name, for --gen-suppressions, or NULL
+## if that error type cannot be suppressed. This is the inverse of
+## SK_(recognised_suppression)().
+Char*, get_error_name, Error* err
+
+## This should print any extra info for the error, for --gen-suppressions,
+## including the newline. This is the inverse of
+## SK_(read_extra_suppression_info)().
+void, print_extra_suppression_info, Error* err
+
+
+## ------------------------------------------------------------------
+## VG_(needs).basic_block_discards
+
+## Should discard any information that pertains to specific basic blocks
+## or instructions within the address range given.
+void, discard_basic_block_info, Addr a, UInt size
+
+
+## ------------------------------------------------------------------
+## VG_(needs).shadow_regs
+
+## No functions must be defined, but the post_reg[s]_write_* events should
+## be tracked.
+
+## ------------------------------------------------------------------
+## VG_(needs).command_line_options
+
+## Return True if option was recognised. Presumably sets some state to
+## record the option as well.
+Bool, process_cmd_line_option, Char* argv
+
+## Print out command line usage for options for normal skin operation.
+void, print_usage
+
+## Print out command line usage for options for debugging the skin.
+void, print_debug_usage
+
+## ------------------------------------------------------------------
+## VG_(needs).client_requests
+
+## If using client requests, the number of the first request should be equal
+## to VG_USERREQ_SKIN_BASE('X', 'Y'), where 'X' and 'Y' form a suitable two
+## character identification for the string. The second and subsequent
+## requests should follow.
+
+## This function should use the VG_IS_SKIN_USERREQ macro (in
+## include/valgrind.h) to first check if it's a request for this skin. Then
+## should handle it if it's recognised (and return True), or return False if
+## not recognised. arg_block[0] holds the request number, any further args
+## from the request are in arg_block[1..]. 'ret' is for the return value...
+## it should probably be filled, if only with 0.
+Bool, handle_client_request, ThreadId tid, UInt* arg_block, UInt* ret
+
+
+## ------------------------------------------------------------------
+## VG_(needs).extends_UCode
+
+## 'X' prefix indicates eXtended UCode.
+Int, get_Xreg_usage, UInstr* u, Tag tag, Int* regs, Bool* isWrites
+void, emit_XUInstr, UInstr* u, RRegSet regs_live_before
+Bool, sane_XUInstr, Bool beforeRA, Bool beforeLiveness, UInstr* u
+Char *, name_XUOpcode, Opcode opc
+void, pp_XUInstr, UInstr* u
+
+
+## ------------------------------------------------------------------
+## VG_(needs).syscall_wrapper
+
+## If either of the pre_ functions malloc() something to return, the
+## corresponding post_ function had better free() it!
+
+void *, pre_syscall, ThreadId tid, UInt syscallno, Bool is_blocking
+void, post_syscall, ThreadId tid, UInt syscallno, void* pre_result, Int res, Bool is_blocking
+
+
+## ---------------------------------------------------------------------
+## VG_(needs).sanity_checks
+
+## Can be useful for ensuring a skin's correctness. SK_(cheap_sanity_check)
+## is called very frequently; SK_(expensive_sanity_check) is called less
+## frequently and can be more involved.
+Bool, cheap_sanity_check
+Bool, expensive_sanity_check
+
+
+## ================================================================================
+## Event tracking functions
+:track
+
+## Events happening in core to track. To be notified, pass a callback
+## function to the appropriate function. To ignore an event, don't do
+## anything (default is for events to be ignored).
+
+## Note that most events aren't passed a ThreadId. To find out the ThreadId
+## of the affected thread, use VG_(get_current_or_recent_tid)(). For the
+## ones passed a ThreadId, use that instead, since
+## VG_(get_current_or_recent_tid)() might not give the right ThreadId in
+## that case.
+
+## Memory events (Nb: to track heap allocation/freeing, a skin must replace
+## malloc() et al. See above how to do this.)
+
+## These ones occur at startup, upon some signals, and upon some syscalls
+void, new_mem_startup, Addr a, UInt len, Bool rr, Bool ww, Bool xx
+void, new_mem_stack_signal, Addr a, UInt len
+void, new_mem_brk, Addr a, UInt len
+void, new_mem_mmap, Addr a, UInt len, Bool rr, Bool ww, Bool xx
+
+void, copy_mem_remap, Addr from, Addr to, UInt len
+void, change_mem_mprotect, Addr a, UInt len, Bool rr, Bool ww, Bool xx
+void, die_mem_stack_signal, Addr a, UInt len
+void, die_mem_brk, Addr a, UInt len
+void, die_mem_munmap, Addr a, UInt len
+
+## These ones are called when %esp changes. A skin could track these itself
+## (except for ban_mem_stack) but it's much easier to use the core's help.
+
+## The specialised ones are called in preference to the general one, if they
+## are defined. These functions are called a lot if they are used, so
+## specialising can optimise things significantly. If any of the
+## specialised cases are defined, the general case must be defined too.
+
+## Nb: they must all use the __attribute__((regparm(n))) attribute.
+void, new_mem_stack_4, Addr new_ESP
+void, new_mem_stack_8, Addr new_ESP
+void, new_mem_stack_12, Addr new_ESP
+void, new_mem_stack_16, Addr new_ESP
+void, new_mem_stack_32, Addr new_ESP
+void, new_mem_stack, Addr a, UInt len
+
+void, die_mem_stack_4, Addr die_ESP
+void, die_mem_stack_8, Addr die_ESP
+void, die_mem_stack_12, Addr die_ESP
+void, die_mem_stack_16, Addr die_ESP
+void, die_mem_stack_32, Addr die_ESP
+void, die_mem_stack, Addr a, UInt len
+
+## Used for redzone at end of thread stacks
+void, ban_mem_stack, Addr a, UInt len
+
+## These ones occur around syscalls, signal handling, etc
+void, pre_mem_read, CorePart part, ThreadId tid, Char* s, Addr a, UInt size
+void, pre_mem_read_asciiz, CorePart part, ThreadId tid, Char* s, Addr a
+void, pre_mem_write, CorePart part, ThreadId tid, Char* s, Addr a, UInt size
+## Not implemented yet -- have to add in lots of places, which is a
+## pain. Won't bother unless/until there's a need.
+## void (*post_mem_read) ( ThreadState* tst, Char* s, Addr a, UInt size );
+void, post_mem_write, Addr a, UInt size
+
+
+## Register events -- if `shadow_regs' need is set, all should probably be
+## used. Use VG_(set_thread_shadow_archreg)() to set the shadow of the
+## changed register.
+
+## Use VG_(set_shadow_archreg)() to set the eight general purpose regs,
+## and use VG_(set_shadow_eflags)() to set eflags.
+void, post_regs_write_init, void
+
+## Use VG_(set_thread_shadow_archreg)() to set the shadow regs for these
+## events.
+void, post_reg_write_syscall_return, ThreadId tid, UInt reg
+void, post_reg_write_deliver_signal, ThreadId tid, UInt reg
+void, post_reg_write_pthread_return, ThreadId tid, UInt reg
+void, post_reg_write_clientreq_return, ThreadId tid, UInt reg
+## This one is called for malloc() et al if they are replaced by a skin.
+void, post_reg_write_clientcall_return, ThreadId tid, UInt reg, Addr f
+
+
+## Scheduler events (not exhaustive)
+void, thread_run, ThreadId tid
+
+
+## Thread events (not exhaustive)
+
+## Called during thread create, before the new thread has run any
+## instructions (or touched any memory).
+void, post_thread_create, ThreadId tid, ThreadId child
+void, post_thread_join, ThreadId joiner, ThreadId joinee
+
+
+## Mutex events (not exhaustive)
+## "void *mutex" is really a pthread_mutex *
+
+## Called before a thread can block while waiting for a mutex (called
+## regardless of whether the thread will block or not).
+void, pre_mutex_lock, ThreadId tid, void* mutex
+## Called once the thread actually holds the mutex (always paired with
+## pre_mutex_lock).
+void, post_mutex_lock, ThreadId tid, void* mutex
+## Called after a thread has released a mutex (no need for a corresponding
+## pre_mutex_unlock, because unlocking can't block).
+void, post_mutex_unlock, ThreadId tid, void* mutex
+
+## Signal events (not exhaustive)
+
+## ... pre_send_signal, post_send_signal ...
+
+## Called before a signal is delivered; `alt_stack' indicates if it is
+## delivered on an alternative stack.
+void, pre_deliver_signal, ThreadId tid, Int sigNo, Bool alt_stack
+## Called after a signal is delivered. Nb: unfortunately, if the signal
+## handler longjmps, this won't be called.
+void, post_deliver_signal, ThreadId tid, Int sigNo
+
+
+## Others... condition variable...
+## ...
+
+## Shadow memory management
+void, init_shadow_page, Addr p
+
+## ================================================================================
+## malloc and friends
+:malloc
+void*, malloc, Int n
+void*, __builtin_new, Int n
+void*, __builtin_vec_new, Int n
+void*, memalign, Int align, Int n
+void*, calloc, Int nmemb, Int n
+void, free, void* p
+void, __builtin_delete, void* p
+void, __builtin_vec_delete, void* p
+void*, realloc, void* p, Int size
diff --git a/coregrind/ume.c b/coregrind/ume.c
new file mode 100644
index 0000000..bf8fb15
--- /dev/null
+++ b/coregrind/ume.c
@@ -0,0 +1,652 @@
+/*
+ User-mode exec
+
+ This bootstraps Valgrind. This code decides on the layout of the
+ client and Valgrind address spaces, loads valgrind.so and the
+ skin.so into the valgrind part, loads the client executable (and the
+ dynamic linker, if necessary) into the client part, and calls into
+ Valgrind proper.
+
+ The code is careful not to allow spurious mappings to appear in the
+ wrong parts of the address space. In particular, to make sure
+ dlopen puts things in the right place, it will pad out the forbidden
+ chunks of address space so that dlopen is forced to put things where
+ we want them.
+
+ The memory map it creates is:
+
+ CLIENT_BASE +-------------------------+
+ | client address space |
+ : :
+ : :
+ | client stack |
+ client_end +-------------------------+
+ | redzone |
+ shadow_base +-------------------------+
+ | |
+ : shadow memory for skins :
+ | (may be 0 sized) |
+ shadow_end +-------------------------+
+ : gap (may be 0 sized) :
+ valgrind_base +-------------------------+
+ | valgrind .so files |
+ | and mappings |
+ valgrind_mmap_end -
+ | kickstart executable |
+ - -
+ | valgrind heap vvvvvvvvv|
+ valgrind_end - -
+ | valgrind stack ^^^^^^^^^|
+ +-------------------------+
+ : kernel :
+ */
+
+#define _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include "vg_include.h"
+
+#include <stddef.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <elf.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <dlfcn.h>
+#include <assert.h>
+
+#include "ume.h"
+
+static int padfile = -1;
+static struct stat padstat;
+
+extern int kickstart_base; /* linker created */
+
+void foreach_map(int (*fn)(void *start, void *end,
+ const char *perm, off_t offset,
+ int maj, int min, int ino))
+{
+ static char buf[10240];
+ char *bufptr = buf;
+ int ret, fd;
+
+ fd = open("/proc/self/maps", O_RDONLY);
+
+ if (fd == -1) {
+ perror("open /proc/self/maps");
+ return;
+ }
+
+ ret = read(fd, buf, sizeof(buf));
+
+ if (ret == -1) {
+ perror("read /proc/self/maps");
+ close(fd);
+ return;
+ }
+ close(fd);
+
+ if (ret == sizeof(buf)) {
+ fprintf(stderr, "buf too small\n");
+ return;
+ }
+
+ while(bufptr && bufptr < buf+ret) {
+ char perm[5];
+ off_t offset;
+ int maj, min;
+ int ino;
+ void *segstart, *segend;
+
+ sscanf(bufptr, "%p-%p %s %Lx %x:%x %d",
+ &segstart, &segend, perm, &offset, &maj, &min, &ino);
+ bufptr = strchr(bufptr, '\n');
+ if (bufptr != NULL)
+ bufptr++; /* skip \n */
+
+ if (!(*fn)(segstart, segend, perm, offset, maj, min, ino))
+ break;
+ }
+}
+
+/* pad all the empty spaces in a range of address space to stop
+ interlopers */
+void as_pad(void *start, void *end)
+{
+ char buf[1024];
+ char *addr;
+
+ int fillgap(void *segstart, void *segend, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ if (segstart >= end)
+ return 0;
+
+ if ((char *)segstart > addr)
+ mmap(addr, (char *)segstart-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
+ padfile, 0);
+ addr = segend;
+
+ return 1;
+ }
+
+ 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);
+ }
+
+ addr = start;
+
+ foreach_map(fillgap);
+
+ if (addr < (char *)end)
+ mmap(addr, (char *)end-addr, PROT_NONE, MAP_FIXED|MAP_PRIVATE,
+ padfile, 0);
+}
+
+/* remove padding from a range of address space - padding is always a
+ mapping of padfile*/
+void as_unpad(void *start, void *end)
+{
+ int killpad(void *segstart, void *segend, const char *perm, off_t off,
+ int maj, int min, int ino) {
+ void *b, *e;
+
+ if (padstat.st_dev != makedev(maj, min) || padstat.st_ino != ino)
+ return 1;
+
+ if (segend <= start || segstart >= end)
+ return 1;
+
+ if (segstart <= start)
+ b = start;
+ else
+ b = segstart;
+
+ if (segend >= end)
+ e = end;
+ else
+ e = segend;
+
+ munmap(b, (char *)e-(char *)b);
+
+ return 1;
+ }
+
+ if (padfile == -1) /* no padfile, no padding */
+ return;
+
+ foreach_map(killpad);
+}
+
+void as_closepadfile(void)
+{
+ /* don't unpad */
+ close(padfile);
+ padfile = -1;
+}
+
+int as_getpadfd(void)
+{
+ return padfile;
+}
+
+void as_setpadfd(int fd)
+{
+ as_closepadfile();
+ padfile = fd;
+ fstat(padfile, &padstat);
+}
+
+struct ume_auxv *find_auxv(int *esp)
+{
+ esp++; /* skip argc */
+
+ while(*esp != 0) /* skip argv */
+ esp++;
+ esp++;
+
+ while(*esp != 0) /* skip env */
+ esp++;
+ esp++;
+
+ return (struct ume_auxv *)esp;
+}
+
+
+struct elfinfo *readelf(int fd, const char *filename)
+{
+ struct elfinfo *e = malloc(sizeof(*e));
+ int phsz;
+
+ e->fd = fd;
+
+ if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
+ fprintf(stderr, "%s: can't read elf header: %s\n",
+ filename, strerror(errno));
+ return NULL;
+ }
+
+ if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
+ fprintf(stderr, "%s: bad ELF magic\n",
+ filename);
+ return NULL;
+ }
+ if (e->e.e_ident[EI_CLASS] != ELFCLASS32) {
+ fprintf(stderr, "Can only handle 32-bit executables\n");
+ return NULL;
+ }
+ if (e->e.e_ident[EI_DATA] != ELFDATA2LSB) {
+ fprintf(stderr, "Expecting little-endian\n");
+ return NULL;
+ }
+ if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
+ fprintf(stderr, "need executable\n");
+ return NULL;
+ }
+
+ if (e->e.e_machine != EM_386) {
+ fprintf(stderr, "need x86\n");
+ return NULL;
+ }
+
+ if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
+ fprintf(stderr, "sizeof Phdr wrong\n");
+ return NULL;
+ }
+
+ phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
+ e->p = malloc(phsz);
+
+ if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
+ fprintf(stderr, "can't read phdr: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ 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, int setbrk)
+{
+ int i;
+ ESZ(Addr) elfbrk = 0;
+
+ for(i = 0; i < e->e.e_phnum; i++) {
+ ESZ(Phdr) *ph = &e->p[i];
+ ESZ(Addr) addr, brkaddr;
+ ESZ(Word) memsz;
+
+ if (ph->p_type != PT_LOAD)
+ continue;
+
+ addr = ph->p_vaddr+base;
+ memsz = ph->p_memsz;
+ brkaddr = addr+memsz;
+
+ if (brkaddr > elfbrk)
+ elfbrk = brkaddr;
+ }
+
+ if (setbrk) {
+ /* sneaking up on the brk limit works better than actually
+ jumping directly there. Unfortunately, setting the brk is
+ tested against the datasize rlimit, even though we're not
+ actually using any memory. */
+ char *b = sbrk(0);
+ char *initb = (char *)PGROUNDUP(b);
+
+ while(b < (char *)elfbrk) {
+ unsigned delta = (char *)elfbrk - b;
+ static const unsigned limit = 256*1024*1024;
+ char *bb;
+
+ if (delta > limit)
+ delta = limit;
+ //printf("elfbrk=%p b=%p delta=%u\n", elfbrk, b, delta);
+ bb = sbrk(delta);
+ if (bb != b) {
+ fprintf(stderr, "sbrk failed while adjusting brk base: "
+ "perhaps we hit the datasize ulimit?\n");
+ break;
+ }
+ b += delta;
+ }
+ munmap(initb, (char *)PGROUNDDN(elfbrk)-initb);
+ }
+
+ for(i = 0; i < e->e.e_phnum; i++) {
+ ESZ(Phdr) *ph = &e->p[i];
+ ESZ(Addr) addr, bss, brkaddr;
+ ESZ(Off) off;
+ ESZ(Word) filesz;
+ ESZ(Word) memsz;
+ ESZ(Word) align;
+ unsigned prot = 0;
+
+ if (ph->p_type != PT_LOAD)
+ continue;
+
+ if (ph->p_flags & PF_X)
+ prot |= PROT_EXEC;
+ if (ph->p_flags & PF_W)
+ prot |= PROT_WRITE;
+ if (ph->p_flags & PF_R)
+ prot |= PROT_READ;
+
+ align = ph->p_align;
+
+ addr = ph->p_vaddr+base;
+ off = ph->p_offset;
+ filesz = ph->p_filesz;
+ bss = addr+filesz;
+ memsz = ph->p_memsz;
+ brkaddr = addr+memsz;
+
+ mmap((char *)ROUNDDN(addr, align), ROUNDUP(bss, align)-ROUNDDN(addr, align),
+ prot, MAP_FIXED|MAP_PRIVATE, e->fd, ROUNDDN(off, align));
+
+ /* if memsz > filesz, then we need to fill the remainder with zeroed pages */
+ if (memsz > filesz) {
+ UInt bytes;
+
+ bytes = ROUNDUP(brkaddr, align)-ROUNDUP(bss, align);
+ if (bytes > 0)
+ mmap((char *)ROUNDUP(bss, align), bytes,
+ prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+
+ bytes = bss & (VKI_BYTES_PER_PAGE - 1);
+ if (bytes > 0) {
+ bytes = VKI_BYTES_PER_PAGE - bytes;
+ memset((char *)bss, 0, bytes);
+ }
+ }
+ }
+
+ return elfbrk;
+}
+
+
+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)
+{
+ struct elfinfo *e;
+ struct elfinfo *interp = NULL;
+ ESZ(Addr) minaddr = ~0;
+ ESZ(Addr) maxaddr = 0;
+ ESZ(Addr) interp_addr = 0;
+ ESZ(Word) interp_size = 0;
+ int i;
+ void *entry;
+
+ e = readelf(fd, name);
+
+ if (e == NULL)
+ return ENOEXEC;
+
+ info->phnum = e->e.e_phnum;
+ info->entry = e->e.e_entry;
+
+ for(i = 0; i < e->e.e_phnum; i++) {
+ ESZ(Phdr) *ph = &e->p[i];
+
+ switch(ph->p_type) {
+ case PT_PHDR:
+ info->phdr = ph->p_vaddr;
+ break;
+
+ case PT_LOAD:
+ if (ph->p_vaddr < minaddr)
+ minaddr = ph->p_vaddr;
+ if (ph->p_vaddr+ph->p_memsz > maxaddr)
+ maxaddr = ph->p_vaddr+ph->p_memsz;
+ break;
+
+ case PT_INTERP: {
+ char *buf = malloc(ph->p_filesz+1);
+ int j;
+ int intfd;
+ int baseaddr_set;
+
+ pread(fd, buf, ph->p_filesz, ph->p_offset);
+ buf[ph->p_filesz] = '\0';
+
+ intfd = open(buf, O_RDONLY);
+ if (intfd == -1) {
+ perror("open interp");
+ exit(1);
+ }
+
+ interp = readelf(intfd, buf);
+ if (interp == NULL) {
+ fprintf(stderr, "Can't read interpreter\n");
+ return 1;
+ }
+ free(buf);
+
+ baseaddr_set = 0;
+ for(j = 0; j < interp->e.e_phnum; j++) {
+ ESZ(Phdr) *iph = &interp->p[j];
+ ESZ(Addr) end;
+
+ if (iph->p_type != PT_LOAD)
+ continue;
+
+ if (!baseaddr_set) {
+ interp_addr = iph->p_vaddr;
+ baseaddr_set = 1;
+ }
+
+ /* assumes that all segments in the interp are close */
+ end = (iph->p_vaddr - interp_addr) + iph->p_memsz;
+
+ if (end > interp_size)
+ interp_size = end;
+ }
+ break;
+ }
+ }
+ }
+
+ if (info->exe_base != info->exe_end) {
+ if (minaddr >= maxaddr ||
+ (minaddr < info->exe_base ||
+ maxaddr > info->exe_end)) {
+ fprintf(stderr, "Executable is mapped outside of range %p-%p\n",
+ (void *)info->exe_base, (void *)info->exe_end);
+ return ENOMEM;
+ }
+ }
+
+ info->brkbase = mapelf(e, 0, info->setbrk); /* map the executable */
+
+ if (interp != NULL) {
+ /* reserve a chunk of address space for interpreter */
+ char *base = (char *)info->exe_base;
+ char *baseoff;
+ int flags = MAP_PRIVATE|MAP_ANONYMOUS;
+
+ if (info->map_base != 0) {
+ base = (char *)info->map_base;
+ flags |= MAP_FIXED;
+ }
+
+ base = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
+
+ baseoff = base - interp_addr;
+
+ mapelf(interp, (ESZ(Addr))baseoff, 0);
+
+ close(interp->fd);
+ free(interp);
+
+ entry = baseoff + interp->e.e_entry;
+ info->interp_base = (ESZ(Addr))base;
+ } else
+ entry = (void *)e->e.e_entry;
+
+ info->exe_base = minaddr;
+ info->exe_end = maxaddr;
+
+ info->init_eip = (addr_t)entry;
+
+ free(e);
+
+ return 0;
+}
+
+
+static int match_script(const char *hdr, Int len)
+{
+ return (len > 2) && memcmp(hdr, "#!", 2) == 0;
+}
+
+static int load_script(char *hdr, int len, int fd, const char *name, struct exeinfo *info)
+{
+ char *interp;
+ char *const end = hdr+len;
+ char *cp;
+ char *arg = NULL;
+ int eol;
+
+ interp = hdr + 2;
+ while(interp < end && (*interp == ' ' || *interp == '\t'))
+ interp++;
+
+ if (*interp != '/')
+ return ENOEXEC; /* absolute path only for interpreter */
+
+ /* skip over interpreter name */
+ for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
+ ;
+
+ eol = (*cp == '\n');
+
+ *cp++ = '\0';
+
+ if (!eol && cp < end) {
+ /* skip space before arg */
+ while (cp < end && (*cp == '\t' || *cp == ' '))
+ cp++;
+
+ /* arg is from here to eol */
+ arg = cp;
+ while (cp < end && *cp != '\n')
+ cp++;
+ *cp = '\0';
+ }
+
+ info->argv0 = strdup(interp);
+ if (arg != NULL && *arg != '\0')
+ info->argv1 = strdup(arg);
+
+ if (info->argv && info->argv[0] != NULL)
+ info->argv[0] = (char *)name;
+
+ if (0)
+ printf("#! script: argv0=\"%s\" argv1=\"%s\"\n",
+ info->argv0, info->argv1);
+
+ 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;
+ char buf[VKI_BYTES_PER_PAGE];
+ int bufsz;
+ int i;
+ int ret;
+ struct stat st;
+
+ fd = open(exe, O_RDONLY);
+ if (fd == -1) {
+ if (0)
+ fprintf(stderr, "Can't open executable %s: %s\n",
+ exe, strerror(errno));
+ return errno;
+ }
+
+ if (fstat(fd, &st) == -1)
+ return errno;
+ else {
+ uid_t uid = geteuid();
+ gid_t gid = getegid();
+ gid_t groups[32];
+ int ngrp = getgroups(32, groups);
+
+ if (uid == st.st_uid && !(st.st_mode & S_IXUSR))
+ return EACCES;
+
+ if (gid == st.st_gid && !(st.st_mode & S_IXGRP))
+ return EACCES;
+
+ for(i = 0; i < ngrp; i++)
+ if (groups[i] == st.st_gid && !(st.st_mode & S_IXGRP))
+ return EACCES;
+
+ if (!(st.st_mode & S_IXOTH))
+ return EACCES;
+ }
+
+ bufsz = pread(fd, buf, sizeof(buf), 0);
+ if (bufsz < 0) {
+ fprintf(stderr, "Can't read executable header: %s\n",
+ strerror(errno));
+ close(fd);
+ return errno;
+ }
+
+ ret = ENOEXEC;
+ for(i = 0; i < sizeof(formats)/sizeof(*formats); i++) {
+ if ((formats[i].match)(buf, bufsz)) {
+ ret = (formats[i].load)(buf, bufsz, fd, exe, info);
+ break;
+ }
+ }
+
+ close(fd);
+
+ return ret;
+}
+
+int do_exec(const char *exe, struct exeinfo *info)
+{
+ info->argv0 = NULL;
+ info->argv1 = NULL;
+
+ return do_exec_inner(exe, info);
+}
diff --git a/coregrind/ume.h b/coregrind/ume.h
new file mode 100644
index 0000000..664c125
--- /dev/null
+++ b/coregrind/ume.h
@@ -0,0 +1,77 @@
+#ifndef _COREGRIND_UME_H
+#define _COREGRIND_UME_H
+
+#include <elf.h>
+#include <sys/types.h>
+
+#if ELFSZ == 64
+#define ESZ(x) Elf64_##x
+#elif ELFSZ == 32
+#define ESZ(x) Elf32_##x
+#else
+#error ELFSZ needs to ==32 or ==64
+#endif
+
+/* Integer type the same size as a pointer */
+typedef ESZ(Addr) addr_t;
+
+struct exeinfo
+{
+ int setbrk; /* INPUT: if true, set the brk segment base */
+ addr_t map_base; /* INPUT: if non-zero, base address of mappings */
+
+ addr_t exe_base; /* INOUT: lowest (allowed) address of exe */
+ addr_t exe_end; /* INOUT: highest (allowed) address */
+
+ addr_t phdr; /* address phdr was mapped at */
+ int phnum; /* number of phdrs */
+ addr_t interp_base; /* where interpreter (ld.so) was mapped */
+ addr_t entry; /* entrypoint in main executable */
+ addr_t init_eip; /* initial eip */
+ addr_t brkbase; /* base address of brk segment */
+
+ /* these are the extra args added by #! scripts */
+ char *argv0; /* the interpreter name */
+ char *argv1; /* the args for the interpreter */
+
+ char **argv; /* the original argv */
+};
+
+int do_exec(const char *exe, struct exeinfo *info);
+
+void foreach_map(int (*fn)(void *start, void *end,
+ const char *perm, off_t offset,
+ int maj, int min, int ino));
+void as_pad(void *start, void *end);
+void as_unpad(void *start, void *end);
+void as_closepadfile(void);
+int as_getpadfd(void);
+void as_setpadfd(int);
+
+struct elfinfo
+{
+ ESZ(Ehdr) e;
+ ESZ(Phdr) *p;
+ int fd;
+};
+
+struct elfinfo *readelf(int fd, const char *filename);
+ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base, int setbrk);
+
+struct ume_auxv
+{
+ int a_type;
+ union {
+ void *a_ptr;
+ int a_val;
+ void (*a_fcn)(void);
+ };
+};
+
+struct ume_auxv *find_auxv(int *orig_esp);
+
+/* Our private auxv entries */
+#define AT_UME_PADFD 0xff01 /* padding file fd */
+#define AT_UME_EXECFD 0xff02 /* stage1 executable fd */
+
+#endif /* _COREGRIND_UME_H */
diff --git a/coregrind/ume_arch.h b/coregrind/ume_arch.h
new file mode 100644
index 0000000..6c77fbc
--- /dev/null
+++ b/coregrind/ume_arch.h
@@ -0,0 +1,10 @@
+#ifndef UME_ARCH
+#define UME_ARCH
+
+#include "ume.h"
+
+void ume_go(addr_t eip, addr_t esp) __attribute__((noreturn));
+
+extern void *ume_exec_esp; /* esp on entry at exec time */
+
+#endif /* UME_ARCH */
diff --git a/coregrind/valgrind.in b/coregrind/valgrind.in
deleted file mode 100755
index 540af80..0000000
--- a/coregrind/valgrind.in
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/bin/sh
-##--------------------------------------------------------------------##
-##--- The startup script. valgrind ---##
-##--------------------------------------------------------------------##
-
-# This file is part of Valgrind, an extensible x86 protected-mode
-# emulator for monitoring program execution on x86-Unixes.
-#
-# Copyright (C) 2002-2003 Julian Seward
-# jseward@acm.org
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License as
-# published by the Free Software Foundation; either version 2 of the
-# License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-# 02111-1307, USA.
-#
-# The GNU General Public License is contained in the file COPYING.
-
-
-# Should point to the installation directory
-prefix="@prefix@"
-exec_prefix="@exec_prefix@"
-VALGRIND="@libdir@/valgrind"
-
-# Other stuff ...
-version="@VERSION@"
-emailto="jseward@acm.org"
-
-# The default name of the suppressions file
-vgsupp="--suppressions=$VALGRIND/default.supp"
-
-# Valgrind options
-vgopts=
-
-# Tool to use, chosen by --tool=<foo>, defaults to Memcheck
-tool=memcheck
-
-# --in-place=<dir> arg, for using non-installed version
-in_place_arg=
-
-# Default core+tool to use are the installed ones
-coredir=$VALGRIND
-tooldir=$VALGRIND
-
-# Collect up args for Valgrind. Only some are intercepted here;
-# the rest are passed to vg_main.c. Allow --skin for backwards compatibility.
-while [ $# != 0 ]
-do
- arg=$1
- case "$arg" in
- --version) echo "valgrind-$version"; exit 1 ;;
- --tool=*) tool=`echo $arg | sed 's/--tool=//'`; shift;;
- --skin=*) tool=`echo $arg | sed 's/--skin=//'`; shift;;
- --in-place=*) in_place_arg=$arg; shift;;
- -*) vgopts="$vgopts $arg"; shift;;
- *) break;;
- esac
-done
-
-
-# If running uninstalled version in-place...
-if [ z"$in_place_arg" != z ]; then
- in_place_dir=`echo $in_place_arg | sed 's/--in-place=//'`
- tooldir="$in_place_dir/$tool"
- coredir="$in_place_dir/coregrind/.in_place"
- vgsupp="--suppressions=$in_place_dir/default.supp"
-fi
-
-# Setup tool shared object.
-tool_so="vgskin_${tool}.so"
-if [ ! -r "$tooldir/$tool_so" ] ; then
- echo >&2
- echo "Tool error:" >&2
- echo " The shared library \`$tool_so' for the chosen" >&2
- echo " tool \`$tool' could not be found in" >&2
- echo " $tooldir" >&2
- echo >&2
- exit 1
-fi
-
-VG_ARGS="$VALGRIND_OPTS $vgsupp $vgopts"
-
-export VG_ARGS
-
-# Red Hat Linux 9 uses NPTL, which has a kernel interface
-# unlike the linuxthreads interface valgrind expects. We can
-# tell the dynamic loader to disable this interface using
-# an environment variable.
-
-if getconf GNU_LIBPTHREAD_VERSION 2>/dev/null | grep -qi NPTL 2>/dev/null; then
- LD_ASSUME_KERNEL=2.4.1
- export LD_ASSUME_KERNEL
-fi
-
-# Check that the program looks ok
-is_prog=0
-
-if [ $# != 0 ] ; then
-
- # Ensure the program exists. Ignore any error messages from 'which'.
- which_prog=`which $1 2> /dev/null`
- if [ z$which_prog = z ] && (echo "$1" | grep -q '/'); then
- which_prog=$1
- fi
-
- if [ z$which_prog = z ]; then
- echo "$0: '$1' not found in \$PATH, aborting." >&2
- exit 1
- fi
-
- if [ $# != 0 ] ; then
- case `file -L "$which_prog"` in # must follow symlinks, hence -L
- # Ensure the program isn't statically linked.
- *"statically linked"*)
- echo "\`$which_prog' is statically linked" >&2
- echo "Valgrind only works on dynamically linked executables; your" >&2
- echo "program must rely on at least one shared object for Valgrind" >&2
- echo "to work with it. Read FAQ #5 for more information." >&2
- exit 1 ;;
- # Ensure that there are no setuid or gid flags
- *:\ set?id\ ELF*)
- echo "\`$which_prog' is suid/sgid." >&2
- echo "Valgrind can't handle these executables, as it" >&2
- echo "requires the LD_PRELOAD feature in order to work." >&2
- echo "" >&2
- echo "Remove those flags and try again." >&2
- echo "" >&2
- exit 1
- ;;
- esac
- fi
-
- is_prog=1
-fi
-
-# A bit subtle. The LD_PRELOAD added entry must be absolute
-# and not depend on LD_LIBRARY_PATH. This is so that we can
-# mess with LD_LIBRARY_PATH for child processes, which makes
-# libpthread.so fall out of visibility, independently of
-# whether valgrind.so is visible.
-
-LD_LIBRARY_PATH=$coredir:$LD_LIBRARY_PATH
-export LD_LIBRARY_PATH
-
-# Insert tool .so before valgrind.so to override template functions.
-LD_PRELOAD=$tooldir/$tool_so:$coredir/valgrind.so:$LD_PRELOAD
-export LD_PRELOAD
-#LD_DEBUG=files
-#LD_DEBUG=symbols
-#export LD_DEBUG
-
-# Actually run the program, under Valgrind's control
-if [ $is_prog = 1 ] ; then
- exec "$@"
-else
- # If no command given, act like -h was given so vg_main.c prints out the
- # usage string. And pass to 'exec' the name of any program -- it doesn't
- # matter which -- because it won't be run anyway (we use 'true').
- VG_ARGS="$VG_ARGS -h"
- exec true
-fi
-
-##--------------------------------------------------------------------##
-##--- end valgrind ---##
-##--------------------------------------------------------------------##
diff --git a/coregrind/vg_skiplist.c b/coregrind/vg_skiplist.c
new file mode 100644
index 0000000..911e923
--- /dev/null
+++ b/coregrind/vg_skiplist.c
@@ -0,0 +1,317 @@
+#include "vg_include.h"
+
+#include <stdlib.h>
+
+#define SKIPLIST_DEBUG 0
+
+#define SK_MAXHEIGHT 20 /* 2^20 elements */
+#define SKIPLIST_MAGIC 0x5b1ff872
+#define SKIPLIST_HEAD_MAGIC (~SKIPLIST_MAGIC)
+
+
+#if SKIPLIST_DEBUG
+#define inline
+#endif /* SKIPLIST_DEBUG */
+
+struct _SkipNode {
+ UInt magic;
+ UShort level; /* level is the max level (level == 0 means 1 next pointer) */
+ SkipNode *next[0];
+};
+
+
+
+static inline Int get_height(void)
+{
+ UInt ret = 0;
+
+ while((ret < SK_MAXHEIGHT) && (random() & 1))
+ ret++;
+
+ return ret;
+}
+
+static inline void *key_of_data(const SkipList *l, void *d)
+{
+ return (void *)((Char *)d + l->keyoff);
+}
+
+static inline SkipNode *node_of_data(const SkipList *l, const void *d)
+{
+ SkipNode *n = (SkipNode *)((Char *)d + l->size);
+
+ if (SKIPLIST_DEBUG && n->magic != SKIPLIST_MAGIC)
+ VG_(printf)("bad magic on node %p = %x (not %x)\n",
+ n, n->magic, SKIPLIST_MAGIC);
+
+ vg_assert(n->magic == SKIPLIST_MAGIC);
+
+ return n;
+}
+
+static inline void *data_of_node(const SkipList *l, const SkipNode *n)
+{
+ if (SKIPLIST_DEBUG && n->magic != SKIPLIST_MAGIC)
+ VG_(printf)("bad magic on node %p = %x (not %x)\n",
+ n, n->magic, SKIPLIST_MAGIC);
+
+ vg_assert(n->magic == SKIPLIST_MAGIC);
+ return (void *)((Char *)n - l->size);
+}
+
+static inline void *key_of_node(const SkipList *l, const SkipNode *n)
+{
+ return key_of_data(l, data_of_node(l, n));
+}
+
+static inline void validate_skiplist(const SkipList *l, const Char *where)
+{
+#if SKIPLIST_DEBUG
+ const SkipNode *prev[SK_MAXHEIGHT];
+ Int i;
+ const SkipNode *n, *next;
+
+ VG_(printf)("---------------- %s ----------------\n", where);
+
+ if (l->head == NULL)
+ return;
+
+ for(i = 0; i <= l->head->level; i++) {
+ VG_(printf)("l->head->next[%d]=%p\n",
+ i, l->head->next[i]);
+ prev[i] = l->head->next[i];
+ }
+
+ for(n = l->head->next[0]; n != NULL; n = next) {
+ next = n->next[0];
+
+ VG_(printf)("n=%p next=%p, n->level=%d k=%s\n",
+ n, next, n->level, (*l->strkey)(key_of_node(l, n)));
+ for(i = 0; i <= n->level; i++) {
+ VG_(printf)(" n->next[%d] = %p\n",
+ i, n->next[i]);
+ VG_(printf)(" prev[%d] = %p\n",
+ i, prev[i]);
+ }
+
+ vg_assert(l->head->level >= n->level);
+
+ for(i = 0; i <= n->level; i++)
+ vg_assert(prev[i] == n);
+
+ for(i = 0; i <= n->level; i++)
+ prev[i] = n->next[i];
+
+ vg_assert(next == NULL || (l->cmp)(key_of_node(l, n), key_of_node(l, next)) < 0);
+ }
+#endif /* SKIPLIST_DEBUG */
+}
+
+void *VG_(SkipNode_Alloc)(const SkipList *l)
+{
+ UInt size = l->size;
+ Int h = get_height();
+ SkipNode *n;
+ Char *ret;
+
+ size += sizeof(SkipNode) + (h+1)*sizeof(SkipNode *);
+
+ if (l->arena == -1)
+ *(Short *)&l->arena = VG_AR_SKIN;
+
+ ret = VG_(arena_malloc)(l->arena, size);
+
+ if (ret == NULL)
+ return NULL;
+
+ n = (SkipNode *)(ret + l->size);
+ n->level = h;
+ n->magic = SKIPLIST_MAGIC;
+
+ while(h-- >= 0)
+ n->next[h] = NULL;
+
+ return ret;
+}
+
+void VG_(SkipNode_Free)(const SkipList *l, void *p)
+{
+ if (SKIPLIST_DEBUG) {
+ SkipNode *n = node_of_data(l, p);
+
+ VG_(printf)("SkipNode_Free: freeing %p (node %p)\n",
+ p, n);
+ n->magic = 0x55ffaabb;
+ }
+ VG_(arena_free)(l->arena, p);
+}
+
+void *VG_(SkipNode_First)(const SkipList *l)
+{
+ SkipNode *n = l->head ? l->head->next[0] : NULL;
+
+ if (n == NULL)
+ return NULL;
+ else
+ return data_of_node(l, n);
+}
+
+void *VG_(SkipNode_Next)(const SkipList *l, void *data)
+{
+ SkipNode *n = node_of_data(l, data);
+
+ n = n->next[0];
+
+ if (n == NULL)
+ return NULL;
+
+ return data_of_node(l, n);
+}
+
+
+
+static Int cmp(const SkipList *l, SkipNode *n, void *k2)
+{
+ void *k1 = key_of_node(l, n);
+
+ if (k1 == k2)
+ return 0;
+
+ if (l->head == n)
+ return -1;
+
+ return (l->cmp)(k1, k2);
+}
+
+/* Search the list for k; it either returns the k if it exists, or the
+ one before if not. */
+static SkipNode *SkipList__Find(const SkipList *l, void *k, SkipNode **prevs)
+{
+ SkipNode *n;
+ Int lvl;
+
+ if (SKIPLIST_DEBUG)
+ VG_(printf)("SkipList__Find: finding %s\n", (*l->strkey)(k));
+
+ validate_skiplist(l, "SkipList__Find");
+
+ if (l->head == NULL)
+ return NULL;
+
+ for(lvl = l->head->level, n = l->head; lvl >= 0; lvl--) {
+ while(n->next[lvl] != NULL && cmp(l, n->next[lvl], k) < 0) {
+ if (SKIPLIST_DEBUG)
+ VG_(printf)("SkipList__Find: n=%p n->next[%d]=%p\n",
+ n, lvl, n->next[lvl]);
+ n = n->next[lvl];
+ }
+ if (prevs)
+ prevs[lvl] = n;
+ }
+
+ /* XXX Is there a cleaner way of getting this?
+
+ If we get an exact match, return it.
+ If we get the head, return NULL.
+ Otherwise return the one before where the hit would be.
+ */
+ if (n->next[0] != NULL && cmp(l, n->next[0], k) == 0)
+ n = n->next[0];
+ if (n == l->head)
+ n = NULL;
+
+ if (SKIPLIST_DEBUG) {
+
+ VG_(printf)("SkipList__Find returning node %p\n", n);
+
+ if (n == NULL) {
+ SkipNode *nn;
+
+ for(nn = l->head->next[0]; nn != NULL; nn = nn->next[0])
+ vg_assert(cmp(l, nn, k) != 0);
+ } else
+ vg_assert(cmp(l, n, k) <= 0);
+ }
+
+ return n;
+}
+
+void *VG_(SkipList_Find)(const SkipList *l, void *k)
+{
+ SkipNode *n = SkipList__Find(l, k, NULL);
+
+ if (n != NULL)
+ return data_of_node(l, n);
+ return NULL;
+}
+
+void VG_(SkipList_Insert)(SkipList *l, void *data)
+{
+ SkipNode *update[SK_MAXHEIGHT];
+ SkipNode *n;
+ void *k = key_of_data(l, data);
+ Int i;
+
+ if (SKIPLIST_DEBUG)
+ VG_(printf)("inserting node %p, key %s, height %d\n",
+ data, (*l->strkey)(key_of_data(l, data)), node_of_data(l, data)->level);
+
+ validate_skiplist(l, "SkipList_Insert before");
+
+ if (l->head == NULL) {
+ Int size = sizeof(SkipNode) * sizeof(SkipNode *) * SK_MAXHEIGHT;
+
+ if (l->arena == -1)
+ *(Short *)&l->arena = VG_AR_SKIN;
+
+ l->head = VG_(arena_malloc)(l->arena, size);
+ VG_(memset)(l->head, 0, size);
+
+ l->head->magic = SKIPLIST_HEAD_MAGIC;
+ l->head->level = 0;
+ }
+
+ n = SkipList__Find(l, k, update);
+
+ vg_assert(n == NULL || (l->cmp)(key_of_node(l, n), k) != 0);
+
+ n = node_of_data(l, data);
+
+ vg_assert(l->head != NULL);
+ if (l->head->level < n->level) {
+ for(i = l->head->level+1; i <= n->level; i++)
+ l->head->next[i] = n;
+ l->head->level = n->level;
+ }
+
+ for(i = 0; i <= n->level; i++) {
+ n->next[i] = update[i]->next[i];
+ update[i]->next[i] = n;
+ }
+
+ validate_skiplist(l, "SkipList_Insert after");
+}
+
+void *VG_(SkipList_Remove)(SkipList *l, void *k)
+{
+ SkipNode *update[SK_MAXHEIGHT];
+ SkipNode *n;
+ Int i;
+
+ validate_skiplist(l, "SkipList_Remove before");
+
+ n = SkipList__Find(l, k, update);
+ if (n == NULL)
+ return NULL;
+
+ vg_assert((l->cmp)(k, key_of_node(l, n)) == 0);
+
+ for(i = 0; i <= n->level; i++) {
+ update[i]->next[i] = n->next[i];
+ n->next[i] = NULL;
+ }
+
+ validate_skiplist(l, "SkipList_Remove after");
+
+ return data_of_node(l, n);
+}
diff --git a/coregrind/x86/Makefile.am b/coregrind/x86/Makefile.am
new file mode 100644
index 0000000..1ef4d9c
--- /dev/null
+++ b/coregrind/x86/Makefile.am
@@ -0,0 +1,11 @@
+noinst_HEADERS = \
+ ume_archdefs.h
+
+EXTRA_DIST = \
+ Make.inc \
+ stage2.lds \
+ ume_archdefs.c \
+ ume_archdefs.h \
+ ume_entry.S \
+ ume_go.c
+
diff --git a/coregrind/x86/stage2.lds b/coregrind/x86/stage2.lds
new file mode 100644
index 0000000..7153162
--- /dev/null
+++ b/coregrind/x86/stage2.lds
@@ -0,0 +1,191 @@
+/* Linker script for kickstart - slightly modified from the output of ld --verbose */
+OUTPUT_FORMAT("elf32-i386", "elf32-i386",
+ "elf32-i386")
+OUTPUT_ARCH(i386)
+ENTRY(_ume_entry)
+SEARCH_DIR("/usr/i386-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = kickstart_base + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0x90909090
+ .plt : { *(.plt) }
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ } =0x90909090
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x90909090
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000);
+ /* For backward-compatibility with tools that don't support the
+ *_array_* sections below, our glibc's crt files contain weak
+ definitions of symbols that they reference. We don't want to use
+ them, though, unless they're strictly necessary, because they'd
+ bring us empty sections, unlike PROVIDE below, so we drop the
+ sections from the crt files here. */
+ /DISCARD/ : {
+ */crti.o(.init_array .fini_array .preinit_array)
+ */crtn.o(.init_array .fini_array .preinit_array)
+ }
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { *(.preinit_array) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { *(.init_array) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { *(.fini_array) }
+ PROVIDE (__fini_array_end = .);
+ .data :
+ {
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table) }
+ .dynamic : { *(.dynamic) }
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin.o(.ctors))
+ /* We don't want to include the .ctor section from
+ from the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .got : { *(.got.plt) *(.got) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ }
+ . = ALIGN(32 / 8);
+ _end = .;
+ PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+}
diff --git a/coregrind/x86/ume_archdefs.c b/coregrind/x86/ume_archdefs.c
new file mode 100644
index 0000000..b6641aa
--- /dev/null
+++ b/coregrind/x86/ume_archdefs.c
@@ -0,0 +1,3 @@
+#include "ume_archdefs.h"
+
+const unsigned long CLIENT_START = 0;
diff --git a/coregrind/x86/ume_archdefs.h b/coregrind/x86/ume_archdefs.h
new file mode 100644
index 0000000..8bf017f
--- /dev/null
+++ b/coregrind/x86/ume_archdefs.h
@@ -0,0 +1,6 @@
+#ifndef UME_ARCHDEFS_H
+#define UME_ARCHDEFS_H
+
+#define CLIENT_BASE 0x00000000ul /* base address of client address space */
+
+#endif /* UME_ARCHDEFS_H */
diff --git a/coregrind/x86/ume_entry.S b/coregrind/x86/ume_entry.S
new file mode 100644
index 0000000..6f2b2a3
--- /dev/null
+++ b/coregrind/x86/ume_entry.S
@@ -0,0 +1,12 @@
+ .text
+ .globl _ume_entry
+
+ /* Record the very initial value of %esp before starting the
+ rest of the executable */
+_ume_entry:
+ movl %esp, ume_exec_esp
+ jmp _start
+
+ .data
+ .globl ume_exec_esp
+ume_exec_esp: .long 0
diff --git a/coregrind/x86/ume_go.c b/coregrind/x86/ume_go.c
new file mode 100644
index 0000000..7370ac6
--- /dev/null
+++ b/coregrind/x86/ume_go.c
@@ -0,0 +1,20 @@
+#include "ume_arch.h"
+
+void ume_go(addr_t eip, addr_t esp)
+{
+ asm volatile ("movl %1, %%esp;"
+ "pushl %%eax;"
+ "xorl %%eax,%%eax;"
+ "xorl %%ebx,%%ebx;"
+ "xorl %%ecx,%%ecx;"
+ "xorl %%edx,%%edx;"
+ "xorl %%esi,%%esi;"
+ "xorl %%edi,%%edi;"
+ "xorl %%ebp,%%ebp;"
+
+ "ret" /* return into entry */
+ : : "a" (eip), "r" (esp));
+ /* we should never get here */
+ for(;;)
+ ;
+}
diff --git a/include/vg_skin.h b/include/vg_skin.h.base
similarity index 74%
rename from include/vg_skin.h
rename to include/vg_skin.h.base
index 8c328ed..1477f98 100644
--- a/include/vg_skin.h
+++ b/include/vg_skin.h.base
@@ -1870,651 +1870,3 @@
#endif /* NDEF __VG_SKIN_H */
/* gen_toolint.pl will put the VG_(init_*)() functions here: */
-/* Generated by "gen_toolint.pl toolproto" */
-
-/* These are the parameterised functions in the core. The default definitions
- are overridden by LD_PRELOADed skin version. At the very least, a skin
- must define the fundamental template functions. Depending on what needs
- are set, extra template functions will be used too. Functions are
- grouped under the needs that govern their use.
-
- ------------------------------------------------------------------
- Fundamental template functions
-
- Do initialisation that can only be done after command line processing.
- */
-void SK_(post_clo_init)(void);
-
-/* Instrument a basic block. Must be a true function, ie. the same input
- always results in the same output, because basic blocks can be
- retranslated. Unless you're doing something really strange...
- 'orig_addr' is the address of the first instruction in the block.
- */
-UCodeBlock* SK_(instrument)(UCodeBlock* cb, Addr orig_addr);
-
-/* Finish up, print out any results, etc. `exitcode' is program's exit
- code. The shadow (if the `shadow_regs' need is set) can be found with
- VG_(get_shadow_archreg)(R_EBX), since %ebx holds the argument to the
- exit() syscall.
- */
-void SK_(fini)(Int exitcode);
-
-
-/* ------------------------------------------------------------------
- VG_(needs).core_errors
-
- (none needed)
-
- ------------------------------------------------------------------
- VG_(needs).skin_errors
-
- Identify if two errors are equal, or equal enough. `res' indicates how
- close is "close enough". `res' should be passed on as necessary, eg. if
- the Error's `extra' part contains an ExeContext, `res' should be
- passed to VG_(eq_ExeContext)() if the ExeContexts are considered. Other
- than that, probably don't worry about it unless you have lots of very
- similar errors occurring.
- */
-Bool SK_(eq_SkinError)(VgRes res, Error* e1, Error* e2);
-
-/* Print error context. */
-void SK_(pp_SkinError)(Error* err);
-
-/* Should fill in any details that could be postponed until after the
- decision whether to ignore the error (ie. details not affecting the
- result of SK_(eq_SkinError)()). This saves time when errors are ignored.
- Yuk.
-
- Return value: must be the size of the `extra' part in bytes -- used by
- the core to make a copy.
- */
-UInt SK_(update_extra)(Error* err);
-
-/* Return value indicates recognition. If recognised, must set skind using
- VG_(set_supp_kind)().
- */
-Bool SK_(recognised_suppression)(Char* name, Supp* su);
-
-/* Read any extra info for this suppression kind. Most likely for filling
- in the `extra' and `string' parts (with VG_(set_supp_{extra, string})())
- of a suppression if necessary. Should return False if a syntax error
- occurred, True otherwise.
- */
-Bool SK_(read_extra_suppression_info)(Int fd, Char* buf, Int nBuf, Supp* su);
-
-/* This should just check the kinds match and maybe some stuff in the
- `string' and `extra' field if appropriate (using VG_(get_supp_*)() to
- get the relevant suppression parts).
- */
-Bool SK_(error_matches_suppression)(Error* err, Supp* su);
-
-/* This should return the suppression name, for --gen-suppressions, or NULL
- if that error type cannot be suppressed. This is the inverse of
- SK_(recognised_suppression)().
- */
-Char* SK_(get_error_name)(Error* err);
-
-/* This should print any extra info for the error, for --gen-suppressions,
- including the newline. This is the inverse of
- SK_(read_extra_suppression_info)().
- */
-void SK_(print_extra_suppression_info)(Error* err);
-
-
-/* ------------------------------------------------------------------
- VG_(needs).basic_block_discards
-
- Should discard any information that pertains to specific basic blocks
- or instructions within the address range given.
- */
-void SK_(discard_basic_block_info)(Addr a, UInt size);
-
-
-/* ------------------------------------------------------------------
- VG_(needs).shadow_regs
-
- No functions must be defined, but the post_reg[s]_write_* events should
- be tracked.
-
- ------------------------------------------------------------------
- VG_(needs).command_line_options
-
- Return True if option was recognised. Presumably sets some state to
- record the option as well.
- */
-Bool SK_(process_cmd_line_option)(Char* argv);
-
-/* Print out command line usage for options for normal skin operation. */
-void SK_(print_usage)(void);
-
-/* Print out command line usage for options for debugging the skin. */
-void SK_(print_debug_usage)(void);
-
-/* ------------------------------------------------------------------
- VG_(needs).client_requests
-
- If using client requests, the number of the first request should be equal
- to VG_USERREQ_SKIN_BASE('X', 'Y'), where 'X' and 'Y' form a suitable two
- character identification for the string. The second and subsequent
- requests should follow.
-
- This function should use the VG_IS_SKIN_USERREQ macro (in
- include/valgrind.h) to first check if it's a request for this skin. Then
- should handle it if it's recognised (and return True), or return False if
- not recognised. arg_block[0] holds the request number, any further args
- from the request are in arg_block[1..]. 'ret' is for the return value...
- it should probably be filled, if only with 0.
- */
-Bool SK_(handle_client_request)(ThreadId tid, UInt* arg_block, UInt* ret);
-
-
-/* ------------------------------------------------------------------
- VG_(needs).extends_UCode
-
- 'X' prefix indicates eXtended UCode.
- */
-Int SK_(get_Xreg_usage)(UInstr* u, Tag tag, Int* regs, Bool* isWrites);
-void SK_(emit_XUInstr)(UInstr* u, RRegSet regs_live_before);
-Bool SK_(sane_XUInstr)(Bool beforeRA, Bool beforeLiveness, UInstr* u);
-Char * SK_(name_XUOpcode)(Opcode opc);
-void SK_(pp_XUInstr)(UInstr* u);
-
-
-/* ------------------------------------------------------------------
- VG_(needs).syscall_wrapper
-
- If either of the pre_ functions malloc() something to return, the
- corresponding post_ function had better free() it!
-
- */
-void * SK_(pre_syscall)(ThreadId tid, UInt syscallno, Bool is_blocking);
-void SK_(post_syscall)(ThreadId tid, UInt syscallno, void* pre_result, Int res, Bool is_blocking);
-
-
-/* ---------------------------------------------------------------------
- VG_(needs).sanity_checks
-
- Can be useful for ensuring a skin's correctness. SK_(cheap_sanity_check)
- is called very frequently; SK_(expensive_sanity_check) is called less
- frequently and can be more involved.
- */
-Bool SK_(cheap_sanity_check)(void);
-Bool SK_(expensive_sanity_check)(void);
-
-
-/* ================================================================================
- Event tracking functions
-
- Events happening in core to track. To be notified, pass a callback
- function to the appropriate function. To ignore an event, don't do
- anything (default is for events to be ignored).
-
- Note that most events aren't passed a ThreadId. To find out the ThreadId
- of the affected thread, use VG_(get_current_or_recent_tid)(). For the
- ones passed a ThreadId, use that instead, since
- VG_(get_current_or_recent_tid)() might not give the right ThreadId in
- that case.
-
- Memory events (Nb: to track heap allocation/freeing, a skin must replace
- malloc() et al. See above how to do this.)
-
- These ones occur at startup, upon some signals, and upon some syscalls
- */
-void SK_(new_mem_startup)(Addr a, UInt len, Bool rr, Bool ww, Bool xx);
-void SK_(new_mem_stack_signal)(Addr a, UInt len);
-void SK_(new_mem_brk)(Addr a, UInt len);
-void SK_(new_mem_mmap)(Addr a, UInt len, Bool rr, Bool ww, Bool xx);
-
-void SK_(copy_mem_remap)(Addr from, Addr to, UInt len);
-void SK_(change_mem_mprotect)(Addr a, UInt len, Bool rr, Bool ww, Bool xx);
-void SK_(die_mem_stack_signal)(Addr a, UInt len);
-void SK_(die_mem_brk)(Addr a, UInt len);
-void SK_(die_mem_munmap)(Addr a, UInt len);
-
-/* These ones are called when %esp changes. A skin could track these itself
- (except for ban_mem_stack) but it's much easier to use the core's help.
-
- The specialised ones are called in preference to the general one, if they
- are defined. These functions are called a lot if they are used, so
- specialising can optimise things significantly. If any of the
- specialised cases are defined, the general case must be defined too.
-
- Nb: they must all use the __attribute__((regparm(n))) attribute.
- */
-void SK_(new_mem_stack_4)(Addr new_ESP);
-void SK_(new_mem_stack_8)(Addr new_ESP);
-void SK_(new_mem_stack_12)(Addr new_ESP);
-void SK_(new_mem_stack_16)(Addr new_ESP);
-void SK_(new_mem_stack_32)(Addr new_ESP);
-void SK_(new_mem_stack)(Addr a, UInt len);
-
-void SK_(die_mem_stack_4)(Addr die_ESP);
-void SK_(die_mem_stack_8)(Addr die_ESP);
-void SK_(die_mem_stack_12)(Addr die_ESP);
-void SK_(die_mem_stack_16)(Addr die_ESP);
-void SK_(die_mem_stack_32)(Addr die_ESP);
-void SK_(die_mem_stack)(Addr a, UInt len);
-
-/* Used for redzone at end of thread stacks */
-void SK_(ban_mem_stack)(Addr a, UInt len);
-
-/* These ones occur around syscalls, signal handling, etc */
-void SK_(pre_mem_read)(CorePart part, ThreadId tid, Char* s, Addr a, UInt size);
-void SK_(pre_mem_read_asciiz)(CorePart part, ThreadId tid, Char* s, Addr a);
-void SK_(pre_mem_write)(CorePart part, ThreadId tid, Char* s, Addr a, UInt size);
-/* Not implemented yet -- have to add in lots of places, which is a
- pain. Won't bother unless/until there's a need.
- void (*post_mem_read) ( ThreadState* tst, Char* s, Addr a, UInt size );
- */
-void SK_(post_mem_write)(Addr a, UInt size);
-
-
-/* Register events -- if `shadow_regs' need is set, all should probably be
- used. Use VG_(set_thread_shadow_archreg)() to set the shadow of the
- changed register.
-
- Use VG_(set_shadow_archreg)() to set the eight general purpose regs,
- and use VG_(set_shadow_eflags)() to set eflags.
- */
-void SK_(post_regs_write_init)(void);
-
-/* Use VG_(set_thread_shadow_archreg)() to set the shadow regs for these
- events.
- */
-void SK_(post_reg_write_syscall_return)(ThreadId tid, UInt reg);
-void SK_(post_reg_write_deliver_signal)(ThreadId tid, UInt reg);
-void SK_(post_reg_write_pthread_return)(ThreadId tid, UInt reg);
-void SK_(post_reg_write_clientreq_return)(ThreadId tid, UInt reg);
-/* This one is called for malloc() et al if they are replaced by a skin. */
-void SK_(post_reg_write_clientcall_return)(ThreadId tid, UInt reg, Addr f);
-
-
-/* Scheduler events (not exhaustive) */
-void SK_(thread_run)(ThreadId tid);
-
-
-/* Thread events (not exhaustive)
-
- Called during thread create, before the new thread has run any
- instructions (or touched any memory).
- */
-void SK_(post_thread_create)(ThreadId tid, ThreadId child);
-void SK_(post_thread_join)(ThreadId joiner, ThreadId joinee);
-
-
-/* Mutex events (not exhaustive)
- "void *mutex" is really a pthread_mutex *
-
- Called before a thread can block while waiting for a mutex (called
- regardless of whether the thread will block or not).
- */
-void SK_(pre_mutex_lock)(ThreadId tid, void* mutex);
-/* Called once the thread actually holds the mutex (always paired with
- pre_mutex_lock).
- */
-void SK_(post_mutex_lock)(ThreadId tid, void* mutex);
-/* Called after a thread has released a mutex (no need for a corresponding
- pre_mutex_unlock, because unlocking can't block).
- */
-void SK_(post_mutex_unlock)(ThreadId tid, void* mutex);
-
-/* Signal events (not exhaustive)
-
- ... pre_send_signal, post_send_signal ...
-
- Called before a signal is delivered; `alt_stack' indicates if it is
- delivered on an alternative stack.
- */
-void SK_(pre_deliver_signal)(ThreadId tid, Int sigNo, Bool alt_stack);
-/* Called after a signal is delivered. Nb: unfortunately, if the signal
- handler longjmps, this won't be called.
- */
-void SK_(post_deliver_signal)(ThreadId tid, Int sigNo);
-
-
-/* Others... condition variable...
- ...
-
- Shadow memory management
- */
-void SK_(init_shadow_page)(Addr p);
-
-/* ================================================================================
- malloc and friends
- */
-void* SK_(malloc)(Int n);
-void* SK_(__builtin_new)(Int n);
-void* SK_(__builtin_vec_new)(Int n);
-void* SK_(memalign)(Int align, Int n);
-void* SK_(calloc)(Int nmemb, Int n);
-void SK_(free)(void* p);
-void SK_(__builtin_delete)(void* p);
-void SK_(__builtin_vec_delete)(void* p);
-void* SK_(realloc)(void* p, Int size);
-/* Generated by "gen_toolint.pl initproto" */
-
-#ifndef VG_toolint_initproto
-#define VG_toolint_initproto
-
-
-/* These are the parameterised functions in the core. The default definitions
- are overridden by LD_PRELOADed skin version. At the very least, a skin
- must define the fundamental template functions. Depending on what needs
- are set, extra template functions will be used too. Functions are
- grouped under the needs that govern their use.
-
- ------------------------------------------------------------------
- Fundamental template functions
-
- Do initialisation that can only be done after command line processing.
- */
-void VG_(init_post_clo_init)(void (*func)(void));
-
-/* Instrument a basic block. Must be a true function, ie. the same input
- always results in the same output, because basic blocks can be
- retranslated. Unless you're doing something really strange...
- 'orig_addr' is the address of the first instruction in the block.
- */
-void VG_(init_instrument)(UCodeBlock* (*func)(UCodeBlock* cb, Addr orig_addr));
-
-/* Finish up, print out any results, etc. `exitcode' is program's exit
- code. The shadow (if the `shadow_regs' need is set) can be found with
- VG_(get_shadow_archreg)(R_EBX), since %ebx holds the argument to the
- exit() syscall.
- */
-void VG_(init_fini)(void (*func)(Int exitcode));
-
-
-/* ------------------------------------------------------------------
- VG_(needs).core_errors
-
- (none needed)
-
- ------------------------------------------------------------------
- VG_(needs).skin_errors
-
- Identify if two errors are equal, or equal enough. `res' indicates how
- close is "close enough". `res' should be passed on as necessary, eg. if
- the Error's `extra' part contains an ExeContext, `res' should be
- passed to VG_(eq_ExeContext)() if the ExeContexts are considered. Other
- than that, probably don't worry about it unless you have lots of very
- similar errors occurring.
- */
-void VG_(init_eq_SkinError)(Bool (*func)(VgRes res, Error* e1, Error* e2));
-
-/* Print error context. */
-void VG_(init_pp_SkinError)(void (*func)(Error* err));
-
-/* Should fill in any details that could be postponed until after the
- decision whether to ignore the error (ie. details not affecting the
- result of SK_(eq_SkinError)()). This saves time when errors are ignored.
- Yuk.
-
- Return value: must be the size of the `extra' part in bytes -- used by
- the core to make a copy.
- */
-void VG_(init_update_extra)(UInt (*func)(Error* err));
-
-/* Return value indicates recognition. If recognised, must set skind using
- VG_(set_supp_kind)().
- */
-void VG_(init_recognised_suppression)(Bool (*func)(Char* name, Supp* su));
-
-/* Read any extra info for this suppression kind. Most likely for filling
- in the `extra' and `string' parts (with VG_(set_supp_{extra, string})())
- of a suppression if necessary. Should return False if a syntax error
- occurred, True otherwise.
- */
-void VG_(init_read_extra_suppression_info)(Bool (*func)(Int fd, Char* buf, Int nBuf, Supp* su));
-
-/* This should just check the kinds match and maybe some stuff in the
- `string' and `extra' field if appropriate (using VG_(get_supp_*)() to
- get the relevant suppression parts).
- */
-void VG_(init_error_matches_suppression)(Bool (*func)(Error* err, Supp* su));
-
-/* This should return the suppression name, for --gen-suppressions, or NULL
- if that error type cannot be suppressed. This is the inverse of
- SK_(recognised_suppression)().
- */
-void VG_(init_get_error_name)(Char* (*func)(Error* err));
-
-/* This should print any extra info for the error, for --gen-suppressions,
- including the newline. This is the inverse of
- SK_(read_extra_suppression_info)().
- */
-void VG_(init_print_extra_suppression_info)(void (*func)(Error* err));
-
-
-/* ------------------------------------------------------------------
- VG_(needs).basic_block_discards
-
- Should discard any information that pertains to specific basic blocks
- or instructions within the address range given.
- */
-void VG_(init_discard_basic_block_info)(void (*func)(Addr a, UInt size));
-
-
-/* ------------------------------------------------------------------
- VG_(needs).shadow_regs
-
- No functions must be defined, but the post_reg[s]_write_* events should
- be tracked.
-
- ------------------------------------------------------------------
- VG_(needs).command_line_options
-
- Return True if option was recognised. Presumably sets some state to
- record the option as well.
- */
-void VG_(init_process_cmd_line_option)(Bool (*func)(Char* argv));
-
-/* Print out command line usage for options for normal skin operation. */
-void VG_(init_print_usage)(void (*func)(void));
-
-/* Print out command line usage for options for debugging the skin. */
-void VG_(init_print_debug_usage)(void (*func)(void));
-
-/* ------------------------------------------------------------------
- VG_(needs).client_requests
-
- If using client requests, the number of the first request should be equal
- to VG_USERREQ_SKIN_BASE('X', 'Y'), where 'X' and 'Y' form a suitable two
- character identification for the string. The second and subsequent
- requests should follow.
-
- This function should use the VG_IS_SKIN_USERREQ macro (in
- include/valgrind.h) to first check if it's a request for this skin. Then
- should handle it if it's recognised (and return True), or return False if
- not recognised. arg_block[0] holds the request number, any further args
- from the request are in arg_block[1..]. 'ret' is for the return value...
- it should probably be filled, if only with 0.
- */
-void VG_(init_handle_client_request)(Bool (*func)(ThreadId tid, UInt* arg_block, UInt* ret));
-
-
-/* ------------------------------------------------------------------
- VG_(needs).extends_UCode
-
- 'X' prefix indicates eXtended UCode.
- */
-void VG_(init_get_Xreg_usage)(Int (*func)(UInstr* u, Tag tag, Int* regs, Bool* isWrites));
-void VG_(init_emit_XUInstr)(void (*func)(UInstr* u, RRegSet regs_live_before));
-void VG_(init_sane_XUInstr)(Bool (*func)(Bool beforeRA, Bool beforeLiveness, UInstr* u));
-void VG_(init_name_XUOpcode)(Char * (*func)(Opcode opc));
-void VG_(init_pp_XUInstr)(void (*func)(UInstr* u));
-
-
-/* ------------------------------------------------------------------
- VG_(needs).syscall_wrapper
-
- If either of the pre_ functions malloc() something to return, the
- corresponding post_ function had better free() it!
-
- */
-void VG_(init_pre_syscall)(void * (*func)(ThreadId tid, UInt syscallno, Bool is_blocking));
-void VG_(init_post_syscall)(void (*func)(ThreadId tid, UInt syscallno, void* pre_result, Int res, Bool is_blocking));
-
-
-/* ---------------------------------------------------------------------
- VG_(needs).sanity_checks
-
- Can be useful for ensuring a skin's correctness. SK_(cheap_sanity_check)
- is called very frequently; SK_(expensive_sanity_check) is called less
- frequently and can be more involved.
- */
-void VG_(init_cheap_sanity_check)(Bool (*func)(void));
-void VG_(init_expensive_sanity_check)(Bool (*func)(void));
-
-
-/* ================================================================================
- Event tracking functions
-
- Events happening in core to track. To be notified, pass a callback
- function to the appropriate function. To ignore an event, don't do
- anything (default is for events to be ignored).
-
- Note that most events aren't passed a ThreadId. To find out the ThreadId
- of the affected thread, use VG_(get_current_or_recent_tid)(). For the
- ones passed a ThreadId, use that instead, since
- VG_(get_current_or_recent_tid)() might not give the right ThreadId in
- that case.
-
- Memory events (Nb: to track heap allocation/freeing, a skin must replace
- malloc() et al. See above how to do this.)
-
- These ones occur at startup, upon some signals, and upon some syscalls
- */
-void VG_(init_new_mem_startup)(void (*func)(Addr a, UInt len, Bool rr, Bool ww, Bool xx));
-void VG_(init_new_mem_stack_signal)(void (*func)(Addr a, UInt len));
-void VG_(init_new_mem_brk)(void (*func)(Addr a, UInt len));
-void VG_(init_new_mem_mmap)(void (*func)(Addr a, UInt len, Bool rr, Bool ww, Bool xx));
-
-void VG_(init_copy_mem_remap)(void (*func)(Addr from, Addr to, UInt len));
-void VG_(init_change_mem_mprotect)(void (*func)(Addr a, UInt len, Bool rr, Bool ww, Bool xx));
-void VG_(init_die_mem_stack_signal)(void (*func)(Addr a, UInt len));
-void VG_(init_die_mem_brk)(void (*func)(Addr a, UInt len));
-void VG_(init_die_mem_munmap)(void (*func)(Addr a, UInt len));
-
-/* These ones are called when %esp changes. A skin could track these itself
- (except for ban_mem_stack) but it's much easier to use the core's help.
-
- The specialised ones are called in preference to the general one, if they
- are defined. These functions are called a lot if they are used, so
- specialising can optimise things significantly. If any of the
- specialised cases are defined, the general case must be defined too.
-
- Nb: they must all use the __attribute__((regparm(n))) attribute.
- */
-void VG_(init_new_mem_stack_4)(void (*func)(Addr new_ESP));
-void VG_(init_new_mem_stack_8)(void (*func)(Addr new_ESP));
-void VG_(init_new_mem_stack_12)(void (*func)(Addr new_ESP));
-void VG_(init_new_mem_stack_16)(void (*func)(Addr new_ESP));
-void VG_(init_new_mem_stack_32)(void (*func)(Addr new_ESP));
-void VG_(init_new_mem_stack)(void (*func)(Addr a, UInt len));
-
-void VG_(init_die_mem_stack_4)(void (*func)(Addr die_ESP));
-void VG_(init_die_mem_stack_8)(void (*func)(Addr die_ESP));
-void VG_(init_die_mem_stack_12)(void (*func)(Addr die_ESP));
-void VG_(init_die_mem_stack_16)(void (*func)(Addr die_ESP));
-void VG_(init_die_mem_stack_32)(void (*func)(Addr die_ESP));
-void VG_(init_die_mem_stack)(void (*func)(Addr a, UInt len));
-
-/* Used for redzone at end of thread stacks */
-void VG_(init_ban_mem_stack)(void (*func)(Addr a, UInt len));
-
-/* These ones occur around syscalls, signal handling, etc */
-void VG_(init_pre_mem_read)(void (*func)(CorePart part, ThreadId tid, Char* s, Addr a, UInt size));
-void VG_(init_pre_mem_read_asciiz)(void (*func)(CorePart part, ThreadId tid, Char* s, Addr a));
-void VG_(init_pre_mem_write)(void (*func)(CorePart part, ThreadId tid, Char* s, Addr a, UInt size));
-/* Not implemented yet -- have to add in lots of places, which is a
- pain. Won't bother unless/until there's a need.
- void (*post_mem_read) ( ThreadState* tst, Char* s, Addr a, UInt size );
- */
-void VG_(init_post_mem_write)(void (*func)(Addr a, UInt size));
-
-
-/* Register events -- if `shadow_regs' need is set, all should probably be
- used. Use VG_(set_thread_shadow_archreg)() to set the shadow of the
- changed register.
-
- Use VG_(set_shadow_archreg)() to set the eight general purpose regs,
- and use VG_(set_shadow_eflags)() to set eflags.
- */
-void VG_(init_post_regs_write_init)(void (*func)(void));
-
-/* Use VG_(set_thread_shadow_archreg)() to set the shadow regs for these
- events.
- */
-void VG_(init_post_reg_write_syscall_return)(void (*func)(ThreadId tid, UInt reg));
-void VG_(init_post_reg_write_deliver_signal)(void (*func)(ThreadId tid, UInt reg));
-void VG_(init_post_reg_write_pthread_return)(void (*func)(ThreadId tid, UInt reg));
-void VG_(init_post_reg_write_clientreq_return)(void (*func)(ThreadId tid, UInt reg));
-/* This one is called for malloc() et al if they are replaced by a skin. */
-void VG_(init_post_reg_write_clientcall_return)(void (*func)(ThreadId tid, UInt reg, Addr f));
-
-
-/* Scheduler events (not exhaustive) */
-void VG_(init_thread_run)(void (*func)(ThreadId tid));
-
-
-/* Thread events (not exhaustive)
-
- Called during thread create, before the new thread has run any
- instructions (or touched any memory).
- */
-void VG_(init_post_thread_create)(void (*func)(ThreadId tid, ThreadId child));
-void VG_(init_post_thread_join)(void (*func)(ThreadId joiner, ThreadId joinee));
-
-
-/* Mutex events (not exhaustive)
- "void *mutex" is really a pthread_mutex *
-
- Called before a thread can block while waiting for a mutex (called
- regardless of whether the thread will block or not).
- */
-void VG_(init_pre_mutex_lock)(void (*func)(ThreadId tid, void* mutex));
-/* Called once the thread actually holds the mutex (always paired with
- pre_mutex_lock).
- */
-void VG_(init_post_mutex_lock)(void (*func)(ThreadId tid, void* mutex));
-/* Called after a thread has released a mutex (no need for a corresponding
- pre_mutex_unlock, because unlocking can't block).
- */
-void VG_(init_post_mutex_unlock)(void (*func)(ThreadId tid, void* mutex));
-
-/* Signal events (not exhaustive)
-
- ... pre_send_signal, post_send_signal ...
-
- Called before a signal is delivered; `alt_stack' indicates if it is
- delivered on an alternative stack.
- */
-void VG_(init_pre_deliver_signal)(void (*func)(ThreadId tid, Int sigNo, Bool alt_stack));
-/* Called after a signal is delivered. Nb: unfortunately, if the signal
- handler longjmps, this won't be called.
- */
-void VG_(init_post_deliver_signal)(void (*func)(ThreadId tid, Int sigNo));
-
-
-/* Others... condition variable...
- ...
-
- Shadow memory management
- */
-void VG_(init_init_shadow_page)(void (*func)(Addr p));
-
-/* ================================================================================
- malloc and friends
- */
-void VG_(init_malloc)(void* (*func)(Int n));
-void VG_(init___builtin_new)(void* (*func)(Int n));
-void VG_(init___builtin_vec_new)(void* (*func)(Int n));
-void VG_(init_memalign)(void* (*func)(Int align, Int n));
-void VG_(init_calloc)(void* (*func)(Int nmemb, Int n));
-void VG_(init_free)(void (*func)(void* p));
-void VG_(init___builtin_delete)(void (*func)(void* p));
-void VG_(init___builtin_vec_delete)(void (*func)(void* p));
-void VG_(init_realloc)(void* (*func)(void* p, Int size));
-
-#endif /* VG_toolint_initproto */