]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
This commit merges in changes from branches/ASPACEM (specifically,
authorJulian Seward <jseward@acm.org>
Tue, 27 Sep 2005 19:20:21 +0000 (19:20 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 27 Sep 2005 19:20:21 +0000 (19:20 +0000)
changes from r4341 through r4787 inclusive).  That branch is now dead.
Please do not commit anything else to it.

For the most part the merge was not troublesome.  The main areas of
uncertainty are:

- build system: I had to import by hand Makefile.core-AM_CPPFLAGS.am
  and include it in a couple of places.  Building etc seems to still
  work, but I haven't tried building the documentation.

- syscall wrappers: Following analysis by Greg & Nick, a whole lot of
  stuff was moved from -generic to -linux after the branch was created.
  I think that is satisfactorily glued back together now.

- Regtests: although this appears to work, no .out files appear, which
  is strange, and makes it hard to diagnose regtest failures.  In
  particular memcheck/tests/x86/scalar.stderr.exp remains in a
  conflicted state.

- amd64 is broken (slightly), and ppc32 will be unbuildable.  I'll
  attend to the former shortly.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@4789

125 files changed:
Makefile.am
Makefile.core-AM_CPPFLAGS.am [new file with mode: 0644]
Makefile.tool.am
README_DEVELOPERS
auxprogs/Makefile.am
cachegrind/Makefile.am
cachegrind/cg_annotate.in
cachegrind/cg_main.c
configure.in
coregrind/Makefile.am
coregrind/m_aspacemgr/Makefile.am [deleted file]
coregrind/m_aspacemgr/aspacemgr.c
coregrind/m_aspacemgr/read_procselfmaps.c
coregrind/m_clientstate.c [new file with mode: 0644]
coregrind/m_commandline.c [new file with mode: 0644]
coregrind/m_cpuid.S
coregrind/m_debugger.c
coregrind/m_debuginfo/Makefile.am [deleted file]
coregrind/m_debuginfo/symtab.c
coregrind/m_debuginfo/symtypes.c
coregrind/m_debuglog.c
coregrind/m_demangle/Makefile.am [deleted file]
coregrind/m_demangle/cp-demangle.c
coregrind/m_demangle/cplus-dem.c
coregrind/m_demangle/safe-ctype.c
coregrind/m_dispatch/Makefile.am [deleted file]
coregrind/m_dispatch/dispatch-amd64.S
coregrind/m_dispatch/dispatch-ppc32.S
coregrind/m_dispatch/dispatch-x86.S
coregrind/m_launcher.c [new file with mode: 0644]
coregrind/m_libcassert.c
coregrind/m_libcbase.c
coregrind/m_libcfile.c
coregrind/m_libcmman.c [deleted file]
coregrind/m_libcprint.c
coregrind/m_libcproc.c
coregrind/m_main.c
coregrind/m_mallocfree.c
coregrind/m_redir.c
coregrind/m_replacemalloc/Makefile.am [deleted file]
coregrind/m_scheduler/Makefile.am [deleted file]
coregrind/m_scheduler/scheduler.c
coregrind/m_sigframe/Makefile.am [deleted file]
coregrind/m_sigframe/sigframe-amd64-linux.c
coregrind/m_sigframe/sigframe-ppc32-linux.c
coregrind/m_sigframe/sigframe-x86-linux.c
coregrind/m_signals.c
coregrind/m_skiplist.c
coregrind/m_stacks.c
coregrind/m_stacktrace.c
coregrind/m_syscall.c
coregrind/m_syswrap/Makefile.am [deleted file]
coregrind/m_syswrap/priv_syswrap-generic.h
coregrind/m_syswrap/syscall-amd64-linux.S
coregrind/m_syswrap/syscall-ppc32-linux.S
coregrind/m_syswrap/syscall-x86-linux.S
coregrind/m_syswrap/syswrap-amd64-linux.c
coregrind/m_syswrap/syswrap-generic.c
coregrind/m_syswrap/syswrap-linux.c
coregrind/m_syswrap/syswrap-main.c
coregrind/m_syswrap/syswrap-ppc32-linux.c
coregrind/m_syswrap/syswrap-x86-linux.c
coregrind/m_tooliface.c
coregrind/m_trampoline.S
coregrind/m_translate.c
coregrind/m_transtab.c
coregrind/m_ume.c
coregrind/pub_core_aspacemgr.h
coregrind/pub_core_basics.h
coregrind/pub_core_basics_asm.h [moved from coregrind/pub_core_libcmman.h with 68% similarity]
coregrind/pub_core_clientstate.h [new file with mode: 0644]
coregrind/pub_core_commandline.h [moved from include/pub_tool_libcmman.h with 70% similarity]
coregrind/pub_core_debuginfo.h
coregrind/pub_core_libcfile.h
coregrind/pub_core_libcproc.h
coregrind/pub_core_main.h
coregrind/pub_core_mallocfree.h
coregrind/pub_core_redir.h
coregrind/pub_core_replacemalloc.h
coregrind/pub_core_scheduler.h
coregrind/pub_core_syscall.h
coregrind/pub_core_syswrap.h
coregrind/pub_core_threadstate.h
coregrind/pub_core_tooliface.h
coregrind/pub_core_transtab.h
coregrind/pub_core_ume.h
coregrind/stage1.c [deleted file]
helgrind/hg_main.c
include/Makefile.am
include/pub_tool_aspacemgr.h
include/pub_tool_basics.h
include/pub_tool_basics_asm.h
include/pub_tool_clientstate.h [new file with mode: 0644]
include/pub_tool_libcbase.h
include/pub_tool_libcfile.h
include/pub_tool_libcprint.h
include/pub_tool_libcproc.h
include/pub_tool_mallocfree.h
include/pub_tool_tooliface.h
include/vki-amd64-linux.h
include/vki-linux.h
lackey/Makefile.am
lackey/lk_main.c
massif/Makefile.am
massif/ms_main.c
memcheck/Makefile.am
memcheck/mac_leakcheck.c
memcheck/mc_main.c
memcheck/tests/Makefile.am
memcheck/tests/execve2.c
memcheck/tests/filter_xml
memcheck/tests/vgtest_ume.c
memcheck/tests/x86/scalar.stderr.exp
none/Makefile.am
none/nl_main.c
none/tests/Makefile.am
none/tests/as_mmap.stderr.exp
none/tests/as_shm.stderr.exp
none/tests/map_unmap.c
none/tests/mremap2.c [new file with mode: 0644]
none/tests/mremap2.stderr.exp [new file with mode: 0644]
none/tests/mremap2.stdout.exp [new file with mode: 0644]
none/tests/mremap2.vgtest [new file with mode: 0644]
tests/filter_stderr_basic
tests/vg_regtest.in

index 2cdcc0e9b4dc0bd98c16ecf804b61dbb677c7cb5..95f29cfcdd8b86efbaa0824f4bd61d50e6444af0 100644 (file)
@@ -11,15 +11,13 @@ TOOLS =             memcheck \
                none
 
 ##             addrcheck \
-##             helgrind \
 
-# Temporary: we want to compile Helgrind and Addrcheck and include them in
-# the distro, but not regtest them.  So they are in $TOOLS but not in
-# $SUBDIRS.
-#
+# Temporary: we want to compile Helgrind, but not regtest it.
+# And we want to include Addrcheck in the distro, but not compile/test it.
 # Put docs last because building the HTML is slow and we want to get
 # everything else working before we try it.
-SUBDIRS = include coregrind . tests auxprogs $(TOOLS) helgrind addrcheck docs
+SUBDIRS = include coregrind . tests auxprogs $(TOOLS) helgrind docs
+DIST_SUBDIRS  = $(SUBDIRS) addrcheck
 
 SUPP_FILES = \
        glibc-2.2.supp glibc-2.3.supp glibc-2.4.supp \
@@ -33,8 +31,8 @@ pkgconfig_DATA = valgrind.pc
 incincdir = $(includedir)/valgrind
 nodist_incinc_HEADERS = $(VEX_PUBLIC_HDRS)
 
-BUILT_SOURCES = default.supp valgrind.pc
-
+BUILT_SOURCES  = default.supp valgrind.pc valt_load_address.lds
+CLEANFILES     = valt_load_address.lds
 DISTCLEANFILES = default.supp
 
 default.supp: $(SUPP_FILES)
@@ -142,3 +140,32 @@ VEX_PRIMARY_SOURCES = \
        VEX/priv/host-amd64/isel.c \
        VEX/priv/host-amd64/hdefs.c \
        VEX/priv/host-amd64/hdefs.h
+
+
+# Generate a linker script for linking the binaries.  This is the
+# standard gcc linker script, except hacked so that an alternative
+# load address can be specified by (1) asking gcc to use this script
+# (-Wl,-T,valt_load_address.lds) and (2) setting the symbol
+# valt_load_address to the required value
+# (-Wl,-defsym,valt_load_address=0x70000000).
+#
+# Extract ld's default linker script and hack it to our needs.
+# First we cut everything above and below the "=====..." lines at the top
+# and bottom.
+# Then we have to replace the load address with "valt_load_address".
+# The line to replace in has one of the following two forms:
+#
+#   . = 0x08048000 + SIZEOF_HEADERS;
+#
+# or
+#   PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS;
+#
+# So we search for the line with a hex value "+ SIZEOF_HEADERS", and replace
+# all the hex values in that line with "valt_load_address".
+valt_load_address.lds: Makefile
+       $(CC) -Wl,--verbose -nostdlib 2>&1 | sed \
+               -e '1,/^=====\+$$/d' \
+               -e '/^=====\+$$/d' \
+               -e '/\. = 0x[0-9A-Fa-f]\+ + SIZEOF_HEADERS/s/0x[0-9A-Fa-f]\+/valt_load_address/g' > $@ \
+       || rm -f $@
+
diff --git a/Makefile.core-AM_CPPFLAGS.am b/Makefile.core-AM_CPPFLAGS.am
new file mode 100644 (file)
index 0000000..1859e0c
--- /dev/null
@@ -0,0 +1,19 @@
+add_includes = -I$(top_srcdir)/coregrind \
+               -I$(top_srcdir) \
+               -I$(top_srcdir)/coregrind/$(VG_ARCH) \
+               -I$(top_srcdir)/coregrind/$(VG_OS) \
+               -I$(top_srcdir)/coregrind/$(VG_PLATFORM) \
+               -I$(top_srcdir)/include \
+               -I@VEX_DIR@/pub \
+               -DVGA_$(VG_ARCH)=1 \
+               -DVGO_$(VG_OS)=1 \
+               -DVGP_$(VG_ARCH)_$(VG_OS)=1
+
+BASE_AM_CFLAGS = @ARCH_CORE_AM_CFLAGS@ -Wmissing-prototypes -Winline -Wall -Wshadow -O -g
+
+PIC_AM_CFLAGS = $(BASE_AM_CFLAGS) -fpic -fno-omit-frame-pointer
+
+AM_CPPFLAGS = $(add_includes)
+AM_CFLAGS = $(WERROR) $(BASE_AM_CFLAGS)
+AM_CCASFLAGS = $(add_includes) @ARCH_CORE_AM_CCASFLAGS@ -Wa,-gstabs
+
index f835685066c97b4c5e1dcbe2efecf42384a34889..3d7e9fbf1829fb792b48c1016a77187e4c0d438a 100644 (file)
@@ -5,5 +5,26 @@ include $(top_srcdir)/Makefile.all.am
 include $(top_srcdir)/Makefile.tool-flags.am
 include $(top_srcdir)/Makefile.tool-inplace.am
 
-LIBREPLACEMALLOC = $(top_builddir)/coregrind/m_replacemalloc/libreplacemalloc_toolpreload.a
+LIBREPLACEMALLOC = $(top_builddir)/coregrind/libreplacemalloc_toolpreload.a
+
+COREGRIND_LIBS = \
+       $(top_builddir)/coregrind/libcoregrind.a \
+       @VEX_DIR@/libvex.a
+
+##.PHONY:  @VEX_DIR@/libvex.a
+
+@VEX_DIR@/libvex.a: @VEX_DIR@/priv/main/vex_svnversion.h
+       $(MAKE) -C @VEX_DIR@ CC="$(CC)" libvex.a EXTRA_CFLAGS="@ARCH_CORE_AM_CFLAGS@"
+
+@VEX_DIR@/priv/main/vex_svnversion.h:
+       $(MAKE) -C @VEX_DIR@ CC="$(CC)" version
+
+## Nb: do not call this variables "TOOL_LINKADD" and "TOOL_LDFLAGS" -- that
+## makes automake think we are building something called "TOOLS".
+TOOL_LINKADD = $(COREGRIND_LIBS) -lgcc
+TOOL_LINKFLAGS = \
+       -static \
+       -Wl,-defsym,valt_load_address=@VALT_LOAD_ADDRESS@ \
+       -Wl,-T,$(top_builddir)/valt_load_address.lds \
+       -nodefaultlibs -nostartfiles -u _start
 
index 664029c58fb2f6205ed7cff258ff69116b85c448..f7cb502ee70523510b5d97abb9e9db58e3cbd0a3 100644 (file)
@@ -3,10 +3,10 @@ Building and not installing it
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 To run Valgrind without having to install it, run coregrind/valgrind
-with the VALGRINDLIB environment variable set, where <dir> is the root
+with the VALGRIND_LIB environment variable set, where <dir> is the root
 of the source tree (and must be an absolute path).  Eg:
 
-  VALGRINDLIB=~/grind/head4/.in_place ~/grind/head4/coregrind/valgrind 
+  VALGRIND_LIB=~/grind/head4/.in_place ~/grind/head4/coregrind/valgrind 
 
 This allows you to compile and run with "make" instead of "make install",
 saving you time.
index 20c883fd851483189d0a78e196ce98b8b7ee520e..5a0f7a0d2499d8a4a0f290244fd3e4637b4c2dba 100644 (file)
@@ -1,5 +1,5 @@
 include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
+include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am
 
 bin_PROGRAMS = valgrind-listener
 
index 7cbebe09aa9186153be09a57794337bd12bb26a2..71fc8c49ec5d90d532ed235b5eedfdb6ba35f202 100644 (file)
@@ -9,10 +9,9 @@ EXTRA_DIST = \
 
 noinst_HEADERS = cg_arch.h
 
-val_PROGRAMS = vgtool_cachegrind.so
-
-vgtool_cachegrind_so_SOURCES = \
-       cg_main.c \
-       cg-@VG_ARCH@.c
-vgtool_cachegrind_so_LDFLAGS = -shared
+val_PROGRAMS = cachegrind
 
+cachegrind_SOURCES      = cg_main.c cg-@VG_ARCH@.c
+cachegrind_DEPENDENCIES = $(COREGRIND_LIBS)
+cachegrind_LDADD        = $(TOOL_LINKADD)
+cachegrind_LDFLAGS      = $(TOOL_LINKFLAGS)
index c04a601bd8fa3dd9a63235d88624de5a56d685e0..6de74a304fd6e00672e5ab416b2b06a06bdd03ab 100644 (file)
@@ -155,7 +155,7 @@ usage: cg_annotate [options] --<pid> [source-files]
                           that helped reach the event count threshold [no]
     --context=N           print N lines of context before and after
                           annotated lines [8]
-    -I --include=<dir>    add <dir> to list of directories to search for 
+    -I<d> --include=<d>   add <d> to list of directories to search for 
                           source files
 
   Cachegrind is Copyright (C) 2002-2005 Nicholas Nethercote.
@@ -207,9 +207,10 @@ sub process_cmd_line()
                 ($1 >= 0 && $1 <= 100) or die($usage);
 
             # --auto=yes|no
-            } elsif ($arg =~ /^--auto=(yes|no)$/) {
-                $auto_annotate = 1 if ($1 eq "yes");
-                $auto_annotate = 0 if ($1 eq "no");
+            } elsif ($arg =~ /^--auto=yes$/) {
+                $auto_annotate = 1;
+            } elsif ($arg =~ /^--auto=no$/) {
+                $auto_annotate = 0;
 
             # --context=N
             } elsif ($arg =~ /^--context=([\d\.]+)$/) {
@@ -218,8 +219,12 @@ sub process_cmd_line()
                     die($usage);
                 }
 
-            # --include=A,B,C
-            } elsif ($arg =~ /^(-I|--include)=(.*)$/) {
+            # We don't handle "-I name" -- there can be no space.
+            } elsif ($arg =~ /^-I$/) {
+                die("Sorry, no space is allowed after a -I flag\n");
+            
+            # --include=A,B,C.  Allow -I=name for backwards compatibility.
+            } elsif ($arg =~ /^(-I=|-I|--include=)(.*)$/) {
                 my $inc = $2;
                 $inc =~ s|/$||;         # trim trailing '/'
                 push(@include_dirs, "$inc/");
index d85baff19f324dc2b05832bb7f476e96da28d99b..40940e31715f532c8d2c0809bc557125e4c9c66e 100644 (file)
@@ -42,6 +42,7 @@
 #include "pub_tool_options.h"
 #include "pub_tool_profile.h"
 #include "pub_tool_tooliface.h"
+#include "pub_tool_clientstate.h"
 
 #include "cg_arch.h"
 #include "cg_sim.c"
@@ -895,11 +896,17 @@ static void fprint_CC_table_and_calc_totals(void)
    // "cmd:" line
    VG_(strcpy)(buf, "cmd:");
    VG_(write)(fd, (void*)buf, VG_(strlen)(buf));
-   for (i = 0; i < VG_(client_argc); i++) {
-       if (VG_(client_argv)[i]) {
-          VG_(write)(fd, " ", 1);
-          VG_(write)(fd, VG_(client_argv)[i], VG_(strlen)(VG_(client_argv)[i]));
-       }
+   if (VG_(args_the_exename)) {
+      VG_(write)(fd, " ", 1);
+      VG_(write)(fd, VG_(args_the_exename), 
+                     VG_(strlen)( VG_(args_the_exename) ));
+   }
+   for (i = 0; i < VG_(args_for_client).used; i++) {
+      if (VG_(args_for_client).strs[i]) {
+         VG_(write)(fd, " ", 1);
+         VG_(write)(fd, VG_(args_for_client).strs[i], 
+                        VG_(strlen)(VG_(args_for_client).strs[i]));
+      }
    }
    // "events:" line
    VG_(sprintf)(buf, "\nevents: Ir I1mr I2mr Dr D1mr D2mr Dw D1mw D2mw\n");
@@ -1207,7 +1214,7 @@ static void cg_pre_clo_init(void)
    instr_info_table = VG_(HT_construct)( 4999 );   // prime, biggish
 }
 
-VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init, 0)
+VG_DETERMINE_INTERFACE_VERSION(cg_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
index 96bfeb2f071cf830257daa66b83c9ef986645542..6f20474ff9762a8e90e7c6d7a289e8741df33834 100644 (file)
@@ -1,5 +1,5 @@
 # Process this file with autoconf to produce a configure script.
-AC_INIT(Valgrind, 3.1.SVN, valgrind-users@lists.sourceforge.net)
+AC_INIT(Valgrind, 3.1.ASPACEM, valgrind-users@lists.sourceforge.net)
 AC_CONFIG_SRCDIR(coregrind/m_main.c)
 AM_CONFIG_HEADER(config.h)
 AM_INIT_AUTOMAKE
@@ -111,7 +111,7 @@ AC_MSG_CHECKING([for a supported CPU])
 AC_SUBST(VG_ARCH)
 AC_SUBST(VG_ARCH_ALL)
 VG_ARCH_ALL="amd64 ppc32 x86"
-AC_SUBST(KICKSTART_BASE)
+AC_SUBST(VALT_LOAD_ADDRESS)
 AC_SUBST(ARCH_CORE_AM_CFLAGS)
 AC_SUBST(ARCH_TOOL_AM_CFLAGS)
 AC_SUBST(ARCH_CORE_AM_CCASFLAGS)
@@ -120,7 +120,8 @@ case "${host_cpu}" in
      i?86) 
        AC_MSG_RESULT([ok (${host_cpu})])
         VG_ARCH="x86"
-        KICKSTART_BASE="0xb0000000"
+        valt_load_address_normal="0xb0000000"
+        valt_load_address_inner="0xa0000000"
         ARCH_CORE_AM_CFLAGS="@FLAG_M32@ @PREFERRED_STACK_BOUNDARY@"
         ARCH_TOOL_AM_CFLAGS="@FLAG_M32@ @PREFERRED_STACK_BOUNDARY@"
         ARCH_CORE_AM_CCASFLAGS="@FLAG_M32@"
@@ -132,7 +133,8 @@ case "${host_cpu}" in
         # XXX: relocations under amd64's "small model" are 32-bit signed
         # quantities; therefore going above 0x7fffffff doesn't work... this is
         # a problem.
-        KICKSTART_BASE="0x70000000"
+        valt_load_address_normal="0x70000000"
+        valt_load_address_inner="0x60000000"
         ARCH_CORE_AM_CFLAGS="-m64 -fomit-frame-pointer @PREFERRED_STACK_BOUNDARY@" 
         # XXX: need to use -fpic, otherwise when linking tools I get this error
         # message:
@@ -147,7 +149,8 @@ case "${host_cpu}" in
      powerpc*)
         AC_MSG_RESULT([ok (${host_cpu})])
         VG_ARCH="ppc32"
-        KICKSTART_BASE="0x70000000"
+        valt_load_address_normal="0x70000000"
+        valt_load_address_inner="0x60000000"
         ARCH_CORE_AM_CFLAGS=""
         ARCH_TOOL_AM_CFLAGS="-fpic"
         ARCH_CORE_AM_CCASFLAGS="-Wa,-maltivec"
@@ -159,6 +162,19 @@ case "${host_cpu}" in
        ;;
 esac
 
+# Check if this should be built as an inner Valgrind, to be run within
+# another Valgrind.  Choose the load address accordingly.
+AC_CACHE_CHECK([enable use as an inner Valgrind], vg_cv_inner,
+              [AC_ARG_ENABLE(inner, [  --enable-inner          enables self-hosting],
+               [vg_cv_inner=$enableval],
+                       [vg_cv_inner=no])])
+if test "$vg_cv_inner" = yes; then
+    AC_DEFINE([ENABLE_INNER], 1, [configured to run as an inner Valgrind])
+    VALT_LOAD_ADDRESS=$valt_load_address_inner
+else
+    VALT_LOAD_ADDRESS=$valt_load_address_normal
+fi
+
 AC_MSG_CHECKING([for a supported OS])
 AC_SUBST(VG_OS)
 AC_SUBST(VG_OS_ALL)
@@ -416,19 +432,6 @@ AC_DEFINE([HAVE_TLS], 1, [can use __thread to define thread-local variables])
 fi
 
 
-# Check for PIE support in the compiler and linker
-AC_SUBST(PIE_AM_CFLAGS)
-AC_CACHE_CHECK([for PIE support], vg_cv_pie,
-              [AC_ARG_ENABLE(pie, [  --enable-pie            platform supports PIE linking],
-               [vg_cv_pie=$enableval],
-                       [vg_cv_pie=no] )])
-if test "$vg_cv_pie" = yes; then
-AC_DEFINE([HAVE_PIE], 1, [can create position-independent executables])
-PIE_AM_CFLAGS="-fpie"
-fi
-AM_CONDITIONAL(USE_PIE, test "$vg_cv_pie" = "yes")
-
-
 # Checks for header files.
 AC_HEADER_STDC
 AC_CHECK_HEADERS([sys/endian.h endian.h mqueue.h])
@@ -463,14 +466,6 @@ AC_OUTPUT(
    include/Makefile 
    auxprogs/Makefile
    coregrind/Makefile 
-   coregrind/m_aspacemgr/Makefile 
-   coregrind/m_debuginfo/Makefile 
-   coregrind/m_demangle/Makefile 
-   coregrind/m_dispatch/Makefile 
-   coregrind/m_replacemalloc/Makefile 
-   coregrind/m_scheduler/Makefile 
-   coregrind/m_sigframe/Makefile 
-   coregrind/m_syswrap/Makefile 
    addrcheck/Makefile
    addrcheck/tests/Makefile
    addrcheck/docs/Makefile
index 9bd8a33dff7baa9e0dc870e9e0fe7f5c288a7f34..f03e96f02c51fc74f886c08da6a321b21eb5f6a4 100644 (file)
@@ -1,42 +1,36 @@
 include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-.PHONY: @VEX_DIR@/libvex.a
-
-MODULES = \
-       m_aspacemgr \
-       m_debuginfo \
-       m_demangle \
-       m_dispatch \
-       m_replacemalloc \
-       m_scheduler \
-       m_sigframe \
-       m_syswrap
-
-## When building, we are only interested in the current arch/OS/platform.
-## But when doing 'make dist', we are interested in every arch/OS/platform.
-## That's what DIST_SUBDIRS specifies.
-SUBDIRS = $(MODULES) .
-
-DIST_SUBDIRS = $(MODULES) .
+include $(top_srcdir)/Makefile.core-AM_CPPFLAGS.am
 
 AM_CPPFLAGS += -DVG_LIBDIR="\"$(valdir)"\" \
                -DKICKSTART_BASE=@KICKSTART_BASE@
 
 default.supp: $(SUPP_FILES)
 
+noinst_LIBRARIES = \
+    libcoregrind.a \
+    libreplacemalloc_toolpreload.a
+
 bin_PROGRAMS = \
        valgrind
 
 val_PROGRAMS = \
-       stage2 \
-       vgpreload_core.so
+       vg_preload_core.so
+
+# Remember to include all the arch-specific files in the distribution.
+EXTRA_DIST = \
+        $(addsuffix .S,$(addprefix m_dispatch/dispatch-,$(VG_ARCH_ALL))) \
+        $(addsuffix .c,$(addprefix m_sigframe/sigframe-,$(VG_PLATFORM_ALL))) \
+        $(addsuffix .S,$(addprefix m_syswrap/syscall-,$(VG_PLATFORM_ALL))) \
+        $(addsuffix .c,$(addprefix m_syswrap/syswrap-,$(VG_OS_ALL))) \
+        $(addsuffix .c,$(addprefix m_syswrap/syswrap-,$(VG_PLATFORM_ALL)))
 
 noinst_HEADERS = \
        coregrind.h             \
        pub_core_aspacemgr.h    \
        pub_core_basics.h       \
-       pub_core_coredump.h     \
+       pub_core_basics_asm.h   \
+       pub_core_clientstate.h  \
+       pub_core_commandline.h  \
        pub_core_cpuid.h        \
        pub_core_debuginfo.h    \
        pub_core_debugger.h     \
@@ -50,7 +44,6 @@ noinst_HEADERS = \
        pub_core_libcbase.h     \
        pub_core_libcassert.h   \
        pub_core_libcfile.h     \
-       pub_core_libcmman.h     \
        pub_core_libcprint.h    \
        pub_core_libcproc.h     \
        pub_core_libcsignal.h   \
@@ -82,22 +75,31 @@ noinst_HEADERS = \
        vki_unistd.h            \
        vki_unistd-amd64-linux.h\
        vki_unistd-ppc32-linux.h\
-       vki_unistd-x86-linux.h
-
-BUILT_SOURCES = stage2.lds
-CLEANFILES = stage2.lds
+       vki_unistd-x86-linux.h  \
+       m_debuginfo/priv_symtab.h       \
+       m_debuginfo/priv_symtypes.h     \
+       m_demangle/ansidecl.h   \
+       m_demangle/dyn-string.h \
+       m_demangle/demangle.h   \
+       m_demangle/safe-ctype.h \
+       m_scheduler/priv_sema.h \
+       m_syswrap/priv_types_n_macros.h \
+       m_syswrap/priv_syswrap-generic.h \
+       m_syswrap/priv_syswrap-linux.h \
+       m_syswrap/priv_syswrap-main.h
+
+BUILT_SOURCES = 
+CLEANFILES = 
 
 valgrind_SOURCES = \
-       stage1.c \
-       m_debuglog.c \
-       m_ume.c
-valgrind_DEPENDENCIES =
-valgrind_LDFLAGS=-static -g
-valgrind_LDADD=
+       m_launcher.c \
+       m_debuglog.c
 
-stage2_SOURCES = \
+libcoregrind_a_SOURCES = \
+       m_commandline.c \
        m_coredump.c \
        m_cpuid.S \
+       m_clientstate.c \
        m_debugger.c \
        m_debuglog.c \
        m_errormgr.c \
@@ -106,7 +108,6 @@ stage2_SOURCES = \
        m_libcbase.c \
        m_libcassert.c \
        m_libcfile.c \
-       m_libcmman.c \
        m_libcprint.c \
        m_libcproc.c \
        m_libcsignal.c \
@@ -129,84 +130,47 @@ stage2_SOURCES = \
        m_trampoline.S \
        m_translate.c \
        m_transtab.c \
-       m_ume.c
-
-## Nb: libscheduler.a must precede libdispatch.a in this list.
-stage2_extra= \
-       m_debuginfo/libdebuginfo.a \
-       m_demangle/libdemangle.a \
-       m_scheduler/libscheduler.a \
-       m_dispatch/libdispatch.a \
-       m_aspacemgr/libaspacemgr.a \
-       m_sigframe/libsigframe.a \
-       m_syswrap/libsyswrap.a \
-       @VEX_DIR@/libvex.a
-
-## These ones must be linked in with the --whole-archive flag, because they
-## wouldn't get pulled into stage2 otherwise (because they contain symbols
-## only referred to by tool shared objects).
-stage2_extra2 = \
-       m_replacemalloc/libreplacemalloc_core.a
-
-## Nb: older versions of automake don't seem to like having += within an
-## if-then-else, so we have to use these variables for the common parts.
-st2_DEPS_common = \
-       $(stage2_extra) \
-       $(stage2_extra2)
-
-st2_LDFLAGS_common = \
-       -Wl,--export-dynamic -g \
-       -Wl,--whole-archive $(stage2_extra2) -Wl,--no-whole-archive
-
-if USE_PIE
-stage2_DEPENDENCIES = $(st2_DEPS_common)
-stage2_LDFLAGS = \
-       $(st2_LDFLAGS_common) \
-       -pie
-else
-stage2_DEPENDENCIES = $(st2_DEPS_common) stage2.lds
-stage2_LDFLAGS = \
-       $(st2_LDFLAGS_common) \
-       -Wl,-defsym,kickstart_base=@KICKSTART_BASE@ -Wl,-T,stage2.lds
-endif
-
-stage2_LDADD= $(stage2_extra) \
-       -ldl
-
-vgpreload_core_so_SOURCES = vg_preloaded.c
-vgpreload_core_so_CFLAGS = $(AM_CFLAGS) -fpic
-vgpreload_core_so_LDADD = -ldl
-vgpreload_core_so_LDFLAGS = \
+       m_ume.c \
+       m_aspacemgr/read_procselfmaps.c \
+       m_aspacemgr/aspacemgr.c \
+       m_debuginfo/dwarf.c \
+       m_debuginfo/stabs.c \
+       m_debuginfo/symtab.c \
+       m_debuginfo/symtypes.c \
+       m_demangle/cp-demangle.c \
+       m_demangle/cplus-dem.c \
+       m_demangle/demangle.c \
+       m_demangle/dyn-string.c \
+       m_demangle/safe-ctype.c \
+       m_dispatch/dispatch-@VG_ARCH@.S \
+       m_replacemalloc/replacemalloc_core.c \
+       m_scheduler/scheduler.c \
+       m_scheduler/sema.c \
+       m_sigframe/sigframe-@VG_PLATFORM@.c \
+       m_syswrap/syscall-@VG_PLATFORM@.S \
+       m_syswrap/syswrap-generic.c \
+       m_syswrap/syswrap-@VG_OS@.c \
+       m_syswrap/syswrap-@VG_PLATFORM@.c \
+       m_syswrap/syswrap-main.c
+
+libreplacemalloc_toolpreload_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_a_CFLAGS = $(PIC_AM_CFLAGS)
+
+m_dispatch/dispatch-@VG_ARCH@.S:   libvex_guest_offsets.h
+m_syswrap/syscall-@VG_PLATFORM@.S: libvex_guest_offsets.h
+m_syswrap/syswrap-main.c:         libvex_guest_offsets.h
+
+libvex_guest_offsets.h:
+       $(MAKE) -C @VEX_DIR@ pub/libvex_guest_offsets.h
+
+vg_preload_core_so_SOURCES = vg_preloaded.c
+vg_preload_core_so_CFLAGS = $(AM_CFLAGS) -fpic
+vg_preload_core_so_LDADD = -ldl
+vg_preload_core_so_LDFLAGS = \
        -shared \
-       -Wl,--soname,vgpreload_core.so \
+       -Wl,--soname,vg_preload_core.so \
        -Wl,-z,initfirst
 
-# Extract ld's default linker script and hack it to our needs.
-# First we cut everything above and below the "=====..." lines at the top
-# and bottom.
-# Then we have to replace the load address with "kickstart_base".
-# The line to replace in has one of the following two forms:
-#
-#   . = 0x08048000 + SIZEOF_HEADERS;
-#
-# or
-#   PROVIDE (__executable_start = 0x08048000); . = 0x08048000 + SIZEOF_HEADERS;
-#
-# So we search for the line with a hex value "+ SIZEOF_HEADERS", and replace
-# all the hex values in that line with "kickstart_base".
-stage2.lds: Makefile
-       $(CC) $(AM_CFLAGS) -Wl,--verbose -nostdlib 2>&1 | sed \
-               -e '1,/^=====\+$$/d' \
-               -e '/^=====\+$$/d' \
-               -e '/\. = 0x[0-9A-Fa-f]\+ + SIZEOF_HEADERS/s/0x[0-9A-Fa-f]\+/kickstart_base/g' > $@ \
-       || rm -f $@
-
-@VEX_DIR@/libvex.a: @VEX_DIR@/priv/main/vex_svnversion.h
-       $(MAKE) -C @VEX_DIR@ CC="$(CC)" libvex.a EXTRA_CFLAGS="@ARCH_CORE_AM_CFLAGS@ @PIE_AM_CFLAGS@"
-
-@VEX_DIR@/priv/main/vex_svnversion.h: $(wildcard @VEX_DIR@/.svn/entries)
-       $(MAKE) -C @VEX_DIR@ CC="$(CC)" version
-
 clean-local:
        $(MAKE) -C @VEX_DIR@ CC="$(CC)" clean
 
diff --git a/coregrind/m_aspacemgr/Makefile.am b/coregrind/m_aspacemgr/Makefile.am
deleted file mode 100644 (file)
index 0da1180..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_LIBRARIES = libaspacemgr.a
-
-libaspacemgr_a_SOURCES = \
-       read_procselfmaps.c \
-       aspacemgr.c
index 46a8a644b8b8a934c4c7fd8f5fbd3dfaffd71871..97ac7604261a59c4ecd31e1ec299a1f55ade9543 100644 (file)
    The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_core_basics.h"
-#include "pub_core_debuginfo.h"  // Needed for pub_core_aspacemgr.h :(
-#include "pub_core_aspacemgr.h"
-#include "pub_core_libcbase.h"
-#include "pub_core_libcassert.h"
-#include "pub_core_libcfile.h"   // For VG_(fstat), VG_(resolve_filename_nodup)
-#include "pub_core_libcprint.h"
-#include "pub_core_syscall.h"
-#include "pub_core_tooliface.h"
-#include "pub_core_transtab.h"   // For VG_(discard_translations)
-#include "vki_unistd.h"
+/* One of the important design goals of the address space manager is
+   to minimise dependence on other modules.  Hence the following
+   minimal set of imports. */
 
+#include "pub_core_basics.h"     // types
 
-/* Define to debug the memory-leak-detector. */
-/* #define VG_DEBUG_LEAKCHECK */
+#include "pub_core_debuglog.h"   // VG_(debugLog)
 
-static const Bool mem_debug = False;
+#include "pub_core_libcbase.h"   // VG_(strlen), VG_(strcmp)
+                                 // VG_IS_PAGE_ALIGNED
+                                 // VG_PGROUNDDN, VG_PGROUNDUP
 
-/*--------------------------------------------------------------*/
-/*--- Basic globals about the address space.                 ---*/
-/*--------------------------------------------------------------*/
+#include "pub_core_syscall.h"    // VG_(do_syscallN)
+                                 // VG_(mk_SysRes_Error)
+                                 // VG_(mk_SysRes_Success)
 
-/* Client address space, lowest to highest (see top of ume.c) */
-Addr VG_(client_base);           /* client address space limits */
-Addr VG_(client_end);
-Addr VG_(client_mapbase);
-Addr VG_(clstk_base);
-Addr VG_(clstk_end);
-UWord VG_(clstk_id);
+#include "pub_core_options.h"    // VG_(clo_sanity_level)
 
-Addr VG_(brk_base);             /* start of brk */
-Addr VG_(brk_limit);            /* current brk */
+#include "vki_unistd.h"          // __NR_* constants
 
-Addr VG_(shadow_base);          /* tool's shadow memory */
-Addr VG_(shadow_end);
+#include "pub_core_aspacemgr.h"  // self
 
-Addr VG_(valgrind_base);        /* valgrind's address range */
 
-// Note that VG_(valgrind_last) names the last byte of the section, whereas
-// the VG_(*_end) vars name the byte one past the end of the section.
-Addr VG_(valgrind_last);
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- The Address Space Manager's state.                        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
 
-/*--------------------------------------------------------------*/
-/*--- The raw mman syscalls                                  ---*/
-/*--------------------------------------------------------------*/
+/* ------ start of STATE for the address-space manager ------ */
 
-SysRes VG_(mmap_native)(void *start, SizeT length, UInt prot, UInt flags,
-                        UInt fd, OffT offset)
+/* Max number of segments we can track. */
+#define VG_N_SEGMENTS 2000
+
+/* Max number of segment file names we can track. */
+#define VG_N_SEGNAMES 400
+
+/* Max length of a segment file name. */
+#define VG_MAX_SEGNAMELEN 1000
+
+
+typedef
+   struct {
+      Bool  inUse;
+      Bool  mark;
+      HChar fname[VG_MAX_SEGNAMELEN];
+   }
+   SegName;
+
+/* Filename table.  _used is the high water mark; an entry is only
+   valid if its index >= 0, < _used, and its .inUse field == True.
+   The .mark field is used to garbage-collect dead entries.
+*/
+static SegName segnames[VG_N_SEGNAMES];
+static Int     segnames_used = 0;
+
+
+/* Array [0 .. nsegments_used-1] of all mappings. */
+/* Sorted by .addr field. */
+/* I: len may not be zero. */
+/* I: overlapping segments are not allowed. */
+/* I: the segments cover the entire address space precisely. */
+/* Each segment can optionally hold an index into the filename table. */
+
+static NSegment nsegments[VG_N_SEGMENTS];
+static Int      nsegments_used = 0;
+
+#define Addr_MIN ((Addr)0)
+#define Addr_MAX ((Addr)(-1ULL))
+
+/* Limits etc */
+
+// The smallest address that aspacem will try to allocate
+static Addr aspacem_minAddr = 0;
+
+// The largest address that aspacem will try to allocate
+static Addr aspacem_maxAddr = 0;
+
+// Where aspacem will start looking for client space
+static Addr aspacem_cStart = 0;
+
+// Where aspacem will start looking for Valgrind space
+static Addr aspacem_vStart = 0;
+
+
+#define AM_SANITY_CHECK                                      \
+   do {                                                      \
+      if (VG_(clo_sanity_level >= 3))                        \
+         aspacem_assert(VG_(am_do_sync_check)                \
+            (__PRETTY_FUNCTION__,__FILE__,__LINE__));        \
+   } while (0) 
+
+/* ------ end of STATE for the address-space manager ------ */
+
+// Forwards decls
+static void aspacem_exit ( Int );
+static Int  find_nsegment_idx ( Addr a );
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Stuff to make aspacem almost completely independent of    ---*/
+/*--- the rest of Valgrind.                                     ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+//--------------------------------------------------------------
+// Simple assert and assert-like fns, which avoid dependence on
+// m_libcassert, and hence on the entire debug-info reader swamp
+
+static void aspacem_barf ( HChar* what )
+{
+  VG_(debugLog)(0, "aspacem", "Valgrind: FATAL: %s\n", what);
+  VG_(debugLog)(0, "aspacem", "Exiting now.\n");
+  aspacem_exit(1);
+}
+
+static void aspacem_barf_toolow ( HChar* what )
+{
+  VG_(debugLog)(0, "aspacem", "Valgrind: FATAL: %s is too low.\n", what);
+  VG_(debugLog)(0, "aspacem", "  Increase it and rebuild.  "
+                              "Exiting now.\n");
+  aspacem_exit(1);
+}
+
+static void aspacem_assert_fail( const HChar* expr,
+                                 const Char* file,
+                                 Int line, 
+                                 const Char* fn )
+{
+  VG_(debugLog)(0, "aspacem", "Valgrind: FATAL: aspacem assertion failed:\n");
+  VG_(debugLog)(0, "aspacem", "  %s\n", expr);
+  VG_(debugLog)(0, "aspacem", "  at %s:%d (%s)\n", file,line,fn);
+  VG_(debugLog)(0, "aspacem", "Exiting now.\n");
+  aspacem_exit(1);
+}
+
+#define aspacem_assert(expr)                             \
+  ((void) ((expr) ? 0 :                                  \
+           (aspacem_assert_fail(#expr,                   \
+                                __FILE__, __LINE__,      \
+                                __PRETTY_FUNCTION__))))
+
+
+//--------------------------------------------------------------
+// A simple sprintf implementation, so as to avoid dependence on
+// m_libcprint.
+
+static void add_to_aspacem_sprintf_buf ( HChar c, void *p )
+{
+   HChar** aspacem_sprintf_ptr = p;
+   *(*aspacem_sprintf_ptr)++ = c;
+}
+
+static
+UInt aspacem_vsprintf ( HChar* buf, const HChar *format, va_list vargs )
+{
+   Int ret;
+   Char *aspacem_sprintf_ptr = buf;
+
+   ret = VG_(debugLog_vprintf)
+            ( add_to_aspacem_sprintf_buf, 
+              &aspacem_sprintf_ptr, format, vargs );
+   add_to_aspacem_sprintf_buf('\0', &aspacem_sprintf_ptr);
+
+   return ret;
+}
+
+static
+UInt aspacem_sprintf ( HChar* buf, const HChar *format, ... )
+{
+   UInt ret;
+   va_list vargs;
+
+   va_start(vargs,format);
+   ret = aspacem_vsprintf(buf, format, vargs);
+   va_end(vargs);
+
+   return ret;
+}
+
+
+//--------------------------------------------------------------
+// Direct access to a handful of syscalls.  This avoids dependence on
+// m_libc*.  THESE DO NOT UPDATE THE SEGMENT LIST.  DO NOT USE THEM
+// UNLESS YOU KNOW WHAT YOU ARE DOING.
+
+SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot, 
+                                  UInt flags, UInt fd, OffT offset)
 {
    SysRes res;
-#if defined(VGP_x86_linux)
+#  if defined(VGP_x86_linux)
    { 
       UWord args[6];
       args[0] = (UWord)start;
@@ -91,71 +232,124 @@ SysRes VG_(mmap_native)(void *start, SizeT length, UInt prot, UInt flags,
       args[5] = offset;
       res = VG_(do_syscall1)(__NR_mmap, (UWord)args );
    }
-#elif defined(VGP_amd64_linux)
+#  elif defined(VGP_amd64_linux)
    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, 
                          prot, flags, fd, offset);
-#elif defined(VGP_ppc32_linux)
+#  elif defined(VGP_ppc32_linux)
    res = VG_(do_syscall6)(__NR_mmap, (UWord)(start), (length),
-                         prot, flags, fd, offset);
-#else
-#  error Unknown platform
-#endif
+                          prot, flags, fd, offset);
+#  else
+#    error Unknown platform
+#  endif
    return res;
 }
 
-SysRes VG_(munmap_native)(void *start, SizeT length)
+static SysRes do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
 {
-   return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
+   return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
 }
 
-SysRes VG_(mprotect_native)( void *start, SizeT length, UInt prot )
+static SysRes do_munmap_NO_NOTIFY(Addr start, SizeT length)
 {
-   return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
+   return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
 }
 
-/*--------------------------------------------------------------*/
-/*--- A simple, self-contained ordered array of segments.    ---*/
-/*--------------------------------------------------------------*/
-
-/* Max number of segments we can track. */
-#define VG_N_SEGMENTS 2000
+static SysRes do_extend_mapping_NO_NOTIFY( Addr  old_addr, SizeT old_len,
+                                           SizeT new_len )
+{
+   /* Extend the mapping old_addr .. old_addr+old_len-1 to have length
+      new_len, WITHOUT moving it.  If it can't be extended in place,
+      fail. */
+   return VG_(do_syscall5)(
+             __NR_mremap, 
+             old_addr, old_len, new_len, 
+             0/*flags, meaning: must be at old_addr, else FAIL */,
+             0/*new_addr, is ignored*/
+          );
+}
 
-/* Max number of segment file names we can track. */
-#define VG_N_SEGNAMES 400
+static SysRes do_relocate_nooverlap_mapping_NO_NOTIFY( 
+                 Addr old_addr, Addr old_len, 
+                 Addr new_addr, Addr new_len 
+              )
+{
+   /* Move the mapping old_addr .. old_addr+old_len-1 to the new
+      location and with the new length.  Only needs to handle the case
+      where the two areas do not overlap, neither length is zero, and
+      all args are page aligned. */
+   return VG_(do_syscall5)(
+             __NR_mremap, 
+             old_addr, old_len, new_len, 
+             VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/,
+             new_addr
+          );
+}
 
-/* Max length of a segment file name. */
-#define VG_MAX_SEGNAMELEN 1000
+static Int aspacem_readlink(HChar* path, HChar* buf, UInt bufsiz)
+{
+   SysRes res;
+   res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
+   return res.isError ? -1 : res.val;
+}
 
+static Int aspacem_fstat( Int fd, struct vki_stat* buf )
+{
+   SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)buf);
+   return res.isError ? (-1) : 0;
+}
 
-/* ------ STATE for the address-space manager ------ */
+static void aspacem_exit( Int status )
+{
+   (void)VG_(do_syscall1)(__NR_exit_group, status );
+   (void)VG_(do_syscall1)(__NR_exit, status );
+   /* Why are we still alive here? */
+   /*NOTREACHED*/
+   *(volatile Int *)0 = 'x';
+   aspacem_assert(2+2 == 5);
+}
 
-/* Array [0 .. segments_used-1] of all mappings. */
-/* Sorted by .addr field. */
-/* I: len may not be zero. */
-/* I: overlapping segments are not allowed. */
-/* Each segment can optionally hold an index into the filename table. */
 
-static Segment segments[VG_N_SEGMENTS];
-static Int     segments_used = 0;
+//--------------------------------------------------------------
+// Functions for extracting information about file descriptors.
 
-typedef
-   struct {
-      Bool  inUse;
-      Bool  mark;
-      HChar fname[VG_MAX_SEGNAMELEN];
+/* Extract the device and inode numbers for a fd. */
+static 
+Bool get_inode_for_fd ( Int fd, /*OUT*/UInt* dev, /*OUT*/UInt* ino )
+{
+   struct vki_stat buf;
+   Int r = aspacem_fstat(fd, &buf);
+   if (r == 0) {
+      *dev = buf.st_dev;
+      *ino = buf.st_ino;
+      return True;
    }
-   SegName;
+   return False;
+}
 
-/* Filename table.  _used is the high water mark; an entry is only
-   valid if its index >= 0, < _used, and its .inUse field == True.
-   The .mark field is used to garbage-collect dead entries.
-*/
-static SegName segnames[VG_N_SEGNAMES];
-static Int     segnames_used = 0;
+/* Given a file descriptor, attempt to deduce its filename.  To do
+   this, we use /proc/self/fd/<FD>.  If this doesn't point to a file,
+   or if it doesn't exist, we return False. */
+static
+Bool get_name_for_fd ( Int fd, /*OUT*/HChar* buf, Int nbuf )
+{
+   Int   i;
+   HChar tmp[64];
 
+   aspacem_sprintf(tmp, "/proc/self/fd/%d", fd);
+   for (i = 0; i < nbuf; i++) buf[i] = 0;
+   
+   if (aspacem_readlink(tmp, buf, nbuf) > 0 && buf[0] == '/')
+      return True;
+   else
+      return False;
+}
 
-/* ------ end of STATE for the address-space manager ------ */
 
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- SegName array management.                                 ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
 
 /* Searches the filename table to find an index for the given name.
    If none is found, an index is allocated and the name stored.  If no
@@ -166,9 +360,9 @@ static Int allocate_segname ( const HChar* name )
 {
    Int i, j, len;
 
-   vg_assert(name);
+   aspacem_assert(name);
 
-   if (0) VG_(printf)("allocate_segname %s\n", name);
+   if (0) VG_(debugLog)(0,"aspacem","allocate_segname %s\n", name);
 
    len = VG_(strlen)(name);
    if (len >= VG_MAX_SEGNAMELEN-1) {
@@ -195,16 +389,7 @@ static Int allocate_segname ( const HChar* name )
          i = segnames_used;
          segnames_used++;
       } else {
-         VG_(printf)(
-            "coregrind/m_aspacemgr/aspacemgr.c:\n"
-            "   VG_N_SEGNAMES is too small: "
-            "increase it and rebuild Valgrind.\n"
-         );
-         VG_(printf)(
-            "coregrind/m_aspacemgr/aspacemgr.c:\n"
-            "   giving up now.\n\n"
-         );
-         VG_(exit)(0);
+         aspacem_barf_toolow("VG_N_SEGNAMES");
       }
    }
 
@@ -212,1114 +397,2315 @@ static Int allocate_segname ( const HChar* name )
    segnames[i].inUse = True;
    for (j = 0; j < len; j++)
       segnames[i].fname[j] = name[j];
-   vg_assert(len < VG_MAX_SEGNAMELEN);
+   aspacem_assert(len < VG_MAX_SEGNAMELEN);
    segnames[i].fname[len] = 0;
    return i;
 }
 
 
-/* Returns -1 if 'a' denotes an address prior to seg, 1 if it denotes
-   an address after it, and 0 if it denotes an address covered by
-   seg. 
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////
+
+
+/* Note: many of the exported functions implemented below are
+   described more fully in comments in pub_core_aspacemgr.h.
+*/
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Displaying the segment array.                             ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+static HChar* show_SegKind ( SegKind sk )
+{
+   switch (sk) {
+      case SkFree:  return "    ";
+      case SkAnonC: return "anon";
+      case SkAnonV: return "ANON";
+      case SkFileC: return "file";
+      case SkFileV: return "FILE";
+      case SkResvn: return "RSVN";
+      default:      return "????";
+   }
+}
+
+static HChar* show_ShrinkMode ( ShrinkMode sm )
+{
+   switch (sm) {
+      case SmLower: return "SmLower";
+      case SmUpper: return "SmUpper";
+      case SmFixed: return "SmFixed";
+      default: return "Sm?????";
+   }
+}
+
+static void show_Addr_concisely ( /*OUT*/HChar* buf, Addr aA )
+{
+   HChar* fmt;
+   ULong a = (ULong)aA;
+
+   if (a < 10*1000*1000ULL) {
+      fmt = "%7llu";
+   } 
+   else if (a < 999999ULL * (1ULL<<20)) {
+      fmt = "%6llum";
+      a >>= 20;
+   }
+   else if (a < 999999ULL * (1ULL<<30)) {
+      fmt = "%6llug";
+      a >>= 30;
+   }
+   else if (a < 999999ULL * (1ULL<<40)) {
+      fmt = "%6llut";
+      a >>= 40;
+   }
+   else {
+      fmt = "%6llue";
+      a >>= 50;
+   }
+   aspacem_sprintf(buf, fmt, a);
+}
+
+
+/* Show full details of an NSegment */
+
+static void __attribute__ ((unused))
+            show_nsegment_full ( Int logLevel, NSegment* seg )
+{
+   VG_(debugLog)(logLevel, "aspacem",
+      "NSegment{%s, start=0x%llx, end=0x%llx, smode=%s, dev=%llu, "
+      "ino=%llu, offset=%llu, fnIdx=%d, hasR=%d, hasW=%d, hasX=%d, "
+      "hasT=%d, mark=%d}\n",
+      show_SegKind(seg->kind),
+      (ULong)seg->start,
+      (ULong)seg->end,
+      show_ShrinkMode(seg->smode),
+      (ULong)seg->dev, (ULong)seg->ino, (ULong)seg->offset, seg->fnIdx,
+      (Int)seg->hasR, (Int)seg->hasW, (Int)seg->hasX, (Int)seg->hasT,
+      (Int)seg->mark
+   );
+}
+
+
+/* Show an NSegment in a user-friendly-ish way. */
+
+static void show_nsegment ( Int logLevel, Int segNo, NSegment* seg )
+{
+   HChar len_buf[20];
+   ULong len = ((ULong)seg->end) - ((ULong)seg->start) + 1;
+   show_Addr_concisely(len_buf, len);
+
+   switch (seg->kind) {
+
+      case SkFree:
+         VG_(debugLog)(
+            logLevel, "aspacem",
+            "%3d: %s %010llx-%010llx %s\n",
+            segNo, show_SegKind(seg->kind),
+            (ULong)seg->start, (ULong)seg->end, len_buf
+         );
+         break;
+
+      case SkAnonC: case SkAnonV:
+         VG_(debugLog)(
+            logLevel, "aspacem",
+            "%3d: %s %010llx-%010llx %s %c%c%c%c%c\n",
+            segNo, show_SegKind(seg->kind),
+            (ULong)seg->start, (ULong)seg->end, len_buf,
+            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 
+            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-',
+            seg->isCH ? 'H' : '-'
+         );
+         break;
+
+      case SkFileC: case SkFileV:
+         VG_(debugLog)(
+            logLevel, "aspacem",
+            "%3d: %s %010llx-%010llx %s %c%c%c%c%c d=0x%03llx "
+            "i=%-7lld o=%-7lld (%d)\n",
+            segNo, show_SegKind(seg->kind),
+            (ULong)seg->start, (ULong)seg->end, len_buf,
+            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 
+            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 
+            seg->isCH ? 'H' : '-',
+            (ULong)seg->dev, (ULong)seg->ino, (Long)seg->offset, seg->fnIdx
+         );
+         break;
+
+      case SkResvn:
+         VG_(debugLog)(
+            logLevel, "aspacem",
+            "%3d: %s %010llx-%010llx %s %c%c%c%c%c %s\n",
+            segNo, show_SegKind(seg->kind),
+            (ULong)seg->start, (ULong)seg->end, len_buf,
+            seg->hasR ? 'r' : '-', seg->hasW ? 'w' : '-', 
+            seg->hasX ? 'x' : '-', seg->hasT ? 'T' : '-', 
+            seg->isCH ? 'H' : '-',
+            show_ShrinkMode(seg->smode)
+         );
+         break;
+
+      default:
+         VG_(debugLog)(
+            logLevel, "aspacem",
+            "%3d: ???? UNKNOWN SEGMENT KIND\n", 
+            segNo 
+         );
+         break;
+   }
+}
+
+/* Print out the segment array (debugging only!). */
+void VG_(am_show_nsegments) ( Int logLevel, HChar* who )
+{
+   Int i;
+   VG_(debugLog)(logLevel, "aspacem",
+                 "<<< SHOW_SEGMENTS: %s (%d segments, %d segnames)\n", 
+                 who, nsegments_used, segnames_used);
+   for (i = 0; i < segnames_used; i++) {
+      if (!segnames[i].inUse)
+         continue;
+      VG_(debugLog)(logLevel, "aspacem",
+                    "(%2d) %s\n", i, segnames[i].fname);
+   }
+   for (i = 0; i < nsegments_used; i++)
+     show_nsegment( logLevel, i, &nsegments[i] );
+   VG_(debugLog)(logLevel, "aspacem",
+                 ">>>\n");
+}
+
+
+/* Get the filename corresponding to this segment, if known and if it
+   has one.  The returned name's storage cannot be assumed to be
+   persistent, so the caller should immediately copy the name
+   elsewhere. */
+HChar* VG_(am_get_filename)( NSegment* seg )
+{
+   Int i;
+   aspacem_assert(seg);
+   i = seg->fnIdx;
+   if (i < 0 || i >= segnames_used || !segnames[i].inUse)
+      return NULL;
+   else
+      return &segnames[i].fname[0];
+}
+
+/* Collect up the start addresses of all non-free, non-resvn segments.
+   The interface is a bit strange in order to avoid potential
+   segment-creation races caused by dynamic allocation of the result
+   buffer *starts.
+
+   The function first computes how many entries in the result
+   buffer *starts will be needed.  If this number <= nStarts,
+   they are placed in starts[0..], and the number is returned.
+   If nStarts is not large enough, nothing is written to
+   starts[0..], and the negation of the size is returned.
+
+   Correct use of this function may mean calling it multiple times in
+   order to establish a suitably-sized buffer. */
+
+Int VG_(am_get_segment_starts)( Addr* starts, Int nStarts )
+{
+   Int i, j, nSegs;
+
+   /* don't pass dumbass arguments */
+   aspacem_assert(nStarts >= 0);
+
+   nSegs = 0;
+   for (i = 0; i < nsegments_used; i++) {
+      if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn)
+         continue;
+      nSegs++;
+   }
+
+   if (nSegs > nStarts) {
+      /* The buffer isn't big enough.  Tell the caller how big it needs
+         to be. */
+      return -nSegs;
+   }
+
+   /* There's enough space.  So write into the result buffer. */
+   aspacem_assert(nSegs <= nStarts);
+
+   j = 0;
+   for (i = 0; i < nsegments_used; i++) {
+      if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn)
+         continue;
+      starts[j] = nsegments[i].start;
+      j++;
+   }
+
+   aspacem_assert(j == nSegs); /* this should not fail */
+   return nSegs;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Sanity checking and preening of the segment array.        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Check representational invariants for NSegments. */
+
+static Bool sane_NSegment ( NSegment* s )
+{
+   if (s == NULL) return False;
+
+   /* No zero sized segments and no wraparounds. */
+   if (s->start >= s->end) return False;
+
+   /* .mark is used for admin purposes only. */
+   if (s->mark) return False;
+
+   /* require page alignment */
+   if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
+   if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
+
+   switch (s->kind) {
+
+      case SkFree:
+         return 
+            s->smode == SmFixed
+            && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1 
+            && !s->hasR && !s->hasW && !s->hasX && !s->hasT
+            && !s->isCH;
+
+      case SkAnonC: case SkAnonV:
+         return 
+            s->smode == SmFixed 
+            && s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1
+            && (s->kind==SkAnonC ? True : !s->isCH);
+
+      case SkFileC: case SkFileV:
+         return 
+            s->smode == SmFixed
+            && !s->isCH;
+
+      case SkResvn: 
+         return 
+            s->dev == 0 && s->ino == 0 && s->offset == 0 && s->fnIdx == -1 
+            && !s->hasR && !s->hasW && !s->hasX && !s->hasT
+            && !s->isCH;
+
+      default:
+         return False;
+   }
+}
+
+
+/* Try merging s2 into s1, if possible.  If successful, s1 is
+   modified, and True is returned.  Otherwise s1 is unchanged and
+   False is returned. */
+
+static Bool maybe_merge_nsegments ( NSegment* s1, NSegment* s2 )
+{
+   if (s1->kind != s2->kind) 
+      return False;
+
+   if (s1->end+1 != s2->start)
+      return False;
+
+   /* reject cases which would cause wraparound */
+   if (s1->start > s2->end)
+      return False;
+
+   switch (s1->kind) {
+
+      case SkFree:
+         s1->end = s2->end;
+         return True;
+
+      case SkAnonC: case SkAnonV:
+         if (s1->hasR == s2->hasR && s1->hasW == s2->hasW 
+             && s1->hasX == s2->hasX && s1->isCH == s2->isCH) {
+            s1->end = s2->end;
+            s1->hasT |= s2->hasT;
+            return True;
+         }
+         break;
+
+      case SkFileC: case SkFileV:
+         if (s1->hasR == s2->hasR 
+             && s1->hasW == s2->hasW && s1->hasX == s2->hasX
+             && s1->dev == s2->dev && s1->ino == s2->ino
+             && s2->offset == s1->offset
+                              + ((ULong)s2->start) - ((ULong)s1->start) ) {
+            s1->end = s2->end;
+            s1->hasT |= s2->hasT;
+            return True;
+         }
+         break;
+
+      default:
+         break;
+   
+   }
+
+   return False;
+}
+
+
+/* Sanity-check and canonicalise the segment array (merge mergable
+   segments).  Returns True if any segments were merged. */
+
+static Bool preen_nsegments ( void )
+{
+   Int i, j, r, w, nsegments_used_old = nsegments_used;
+
+   /* Pass 1: check the segment array covers the entire address space
+      exactly once, and also that each segment is sane. */
+   aspacem_assert(nsegments_used > 0);
+   aspacem_assert(nsegments[0].start == Addr_MIN);
+   aspacem_assert(nsegments[nsegments_used-1].end == Addr_MAX);
+
+   aspacem_assert(sane_NSegment(&nsegments[0]));
+   for (i = 1; i < nsegments_used; i++) {
+      aspacem_assert(sane_NSegment(&nsegments[i]));
+      aspacem_assert(nsegments[i-1].end+1 == nsegments[i].start);
+   }
+
+   /* Pass 2: merge as much as possible, using
+      maybe_merge_segments. */
+   w = 0;
+   for (r = 1; r < nsegments_used; r++) {
+      if (maybe_merge_nsegments(&nsegments[w], &nsegments[r])) {
+         /* nothing */
+      } else {
+         w++;
+         if (w != r) 
+            nsegments[w] = nsegments[r];
+      }
+   }
+   w++;
+   aspacem_assert(w > 0 && w <= nsegments_used);
+   nsegments_used = w;
+
+   /* Pass 3: free up unused string table slots */
+   /* clear mark bits */
+   for (i = 0; i < segnames_used; i++)
+      segnames[i].mark = False;
+   /* mark */
+   for (i = 0; i < nsegments_used; i++) {
+     j = nsegments[i].fnIdx;
+      aspacem_assert(j >= -1 && j < segnames_used);
+      if (j >= 0) {
+         aspacem_assert(segnames[j].inUse);
+         segnames[j].mark = True;
+      }
+   }
+   /* release */
+   for (i = 0; i < segnames_used; i++) {
+      if (segnames[i].mark == False) {
+         segnames[i].inUse = False;
+         segnames[i].fname[0] = 0;
+      }
+   }
+
+   return nsegments_used != nsegments_used_old;
+}
+
+
+/* Check the segment array corresponds with the kernel's view of
+   memory layout.  sync_check_ok returns True if no anomalies were
+   found, else False.  In the latter case the mismatching segments are
+   displayed. 
+
+   The general idea is: we get the kernel to show us all its segments
+   and also the gaps in between.  For each such interval, try and find
+   a sequence of appropriate intervals in our segment array which
+   cover or more than cover the kernel's interval, and which all have
+   suitable kinds/permissions etc. 
+
+   Although any specific kernel interval is not matched exactly to a
+   valgrind interval or sequence thereof, eventually any disagreement
+   on mapping boundaries will be detected.  This is because, if for
+   example valgrind's intervals cover a greater range than the current
+   kernel interval, it must be the case that a neighbouring free-space
+   interval belonging to valgrind cannot cover the neighbouring
+   free-space interval belonging to the kernel.  So the disagreement
+   is detected.
+
+   In other words, we examine each kernel interval in turn, and check
+   we do not disagree over the range of that interval.  Because all of
+   the address space is examined, any disagreements must eventually be
+   detected.
 */
-static inline Int compare_addr_with_seg ( Addr a, Segment* seg )
+
+static Bool sync_check_ok = False;
+
+static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
+                                          UInt dev, UInt ino, ULong offset, 
+                                          const UChar* filename )
+{
+   Int iLo, iHi, i;
+
+   /* If a problem has already been detected, don't continue comparing
+      segments, so as to avoid flooding the output with error
+      messages. */
+   if (!sync_check_ok)
+      return;
+
+   if (len == 0)
+      return;
+
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
+
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
+
+   /* These 5 should be guaranteed by find_nsegment_idx. */
+   aspacem_assert(0 <= iLo && iLo < nsegments_used);
+   aspacem_assert(0 <= iHi && iHi < nsegments_used);
+   aspacem_assert(iLo <= iHi);
+   aspacem_assert(nsegments[iLo].start <= addr );
+   aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
+
+   /* NSegments iLo .. iHi inclusive should agree with the presented
+      data. */
+   for (i = iLo; i <= iHi; i++) {
+
+      Bool same, cmp_offsets, cmp_devino;
+   
+      /* compare the kernel's offering against ours. */
+      same = nsegments[i].kind == SkAnonC
+             || nsegments[i].kind == SkAnonV
+             || nsegments[i].kind == SkFileC
+             || nsegments[i].kind == SkFileV;
+
+      cmp_offsets
+         = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
+      cmp_devino
+         = nsegments[i].dev != 0 || nsegments[i].ino != 0;
+
+      same = same
+             && (cmp_devino
+                   ? (nsegments[i].dev == dev && nsegments[i].ino == ino)
+                   : True)
+             && (cmp_offsets 
+                   ? nsegments[i].start-nsegments[i].offset == addr-offset
+                   : True);
+      if (!same) {
+         sync_check_ok = False;
+         VG_(debugLog)(
+            0,"aspacem",
+              "sync_check_mapping_callback: segment mismatch: V's seg:\n");
+         show_nsegment_full( 0, &nsegments[i] );
+         goto show_kern_seg;
+      }
+   }
+
+   /* Looks harmless.  Keep going. */
+   return;
+
+  show_kern_seg:
+   VG_(debugLog)(0,"aspacem",
+                   "sync_check_mapping_callback: segment mismatch: kernel's seg:\n");
+   VG_(debugLog)(0,"aspacem", 
+                   "start=0x%llx end=0x%llx dev=%u ino=%u offset=%lld\n",
+                   (ULong)addr, ((ULong)addr) + ((ULong)len) - 1,
+                   dev, ino, offset );
+   return;
+}
+
+static void sync_check_gap_callback ( Addr addr, SizeT len )
+{
+   Int iLo, iHi, i;
+
+   /* If a problem has already been detected, don't continue comparing
+      segments, so as to avoid flooding the output with error
+      messages. */
+   if (!sync_check_ok)
+      return;
+
+   if (len == 0)
+      return;
+
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
+
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
+
+   /* These 5 should be guaranteed by find_nsegment_idx. */
+   aspacem_assert(0 <= iLo && iLo < nsegments_used);
+   aspacem_assert(0 <= iHi && iHi < nsegments_used);
+   aspacem_assert(iLo <= iHi);
+   aspacem_assert(nsegments[iLo].start <= addr );
+   aspacem_assert(nsegments[iHi].end   >= addr + len - 1 );
+
+   /* NSegments iLo .. iHi inclusive should agree with the presented
+      data. */
+   for (i = iLo; i <= iHi; i++) {
+
+      Bool same;
+   
+      /* compare the kernel's offering against ours. */
+      same = nsegments[i].kind == SkFree
+             || nsegments[i].kind == SkResvn;
+
+      if (!same) {
+         sync_check_ok = False;
+         VG_(debugLog)(
+            0,"aspacem",
+              "sync_check_mapping_callback: segment mismatch: V's gap:\n");
+         show_nsegment_full( 0, &nsegments[i] );
+         goto show_kern_gap;
+      }
+   }
+
+   /* Looks harmless.  Keep going. */
+   return;
+
+  show_kern_gap:
+   VG_(debugLog)(0,"aspacem",
+                   "sync_check_gap_callback: segment mismatch: kernel's gap:\n");
+   VG_(debugLog)(0,"aspacem", 
+                   "start=0x%llx end=0x%llx\n",
+                   (ULong)addr, ((ULong)addr) + ((ULong)len) - 1 );
+   return;
+}
+
+
+/* Sanity check: check that Valgrind and the kernel agree on the
+   address space layout.  Prints offending segments and call point if
+   a discrepancy is detected, but does not abort the system.  Returned
+   Bool is False if a discrepancy was found. */
+
+Bool VG_(am_do_sync_check) ( const HChar* fn, 
+                             const HChar* file, Int line )
+{
+   sync_check_ok = True;
+   if (0)
+      VG_(debugLog)(0,"aspacem", "do_sync_check %s:%d\n", file,line);
+   VG_(parse_procselfmaps)( sync_check_mapping_callback,
+                            sync_check_gap_callback );
+   if (!sync_check_ok) {
+      VG_(debugLog)(0,"aspacem", 
+                      "sync check at %s:%d (%s): FAILED\n",
+                      file, line, fn);
+      VG_(debugLog)(0,"aspacem", "\n");
+
+#     if 0
+      {
+         HChar buf[100];
+         VG_(am_show_nsegments)(0,"post syncheck failure");
+         VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
+         VG_(system)(buf);
+      }
+#     endif
+
+   }
+   return sync_check_ok;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Low level access / modification of the segment array.     ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Binary search the interval array for a given address.  Since the
+   array covers the entire address space the search cannot fail. */
+static Int find_nsegment_idx ( Addr a )
 {
-   if (a < seg->addr) 
+   Addr a_mid_lo, a_mid_hi;
+   Int  mid,
+        lo = 0,
+        hi = nsegments_used-1;
+   while (True) {
+      /* current unsearched space is from lo to hi, inclusive. */
+      if (lo > hi) {
+         /* Not found.  This can't happen. */
+         aspacem_barf("find_nsegment_idx: not found");
+      }
+      mid      = (lo + hi) / 2;
+      a_mid_lo = nsegments[mid].start;
+      a_mid_hi = nsegments[mid].end;
+
+      if (a < a_mid_lo) { hi = mid-1; continue; }
+      if (a > a_mid_hi) { lo = mid+1; continue; }
+      aspacem_assert(a >= a_mid_lo && a <= a_mid_hi);
+      aspacem_assert(0 <= mid && mid < nsegments_used);
+      return mid;
+   }
+}
+
+
+/* Finds the segment containing 'a'.  Only returns file/anon/resvn
+   segments. */
+NSegment* VG_(am_find_nsegment) ( Addr a )
+{
+   Int i = find_nsegment_idx(a);
+   aspacem_assert(i >= 0 && i < nsegments_used);
+   aspacem_assert(nsegments[i].start <= a);
+   aspacem_assert(a <= nsegments[i].end);
+   if (nsegments[i].kind == SkFree) 
+      return NULL;
+   else
+      return &nsegments[i];
+}
+
+
+/* Given a pointer to a seg, tries to figure out which one it is in
+   nsegments[..].  Very paranoid. */
+static Int segAddr_to_index ( NSegment* seg )
+{
+   Int i;
+   if (seg < &nsegments[0] || seg >= &nsegments[nsegments_used])
       return -1;
-   if (a >= seg->addr + seg->len) 
-      return 1;
-   return 0;
+   i = ((UChar*)seg - (UChar*)(&nsegments[0])) / sizeof(NSegment);
+   if (i < 0 || i >= nsegments_used)
+      return -1;
+   if (seg == &nsegments[i])
+      return i;
+   return -1;
+}
+
+
+/* Find the next segment along from 'here', if it is a file/anon/resvn
+   segment. */
+NSegment* VG_(am_next_nsegment) ( NSegment* here, Bool fwds )
+{
+   Int i = segAddr_to_index(here);
+   if (i < 0 || i >= nsegments_used)
+      return NULL;
+   if (fwds) {
+      i++;
+      if (i >= nsegments_used)
+         return NULL;
+   } else {
+      i--;
+      if (i < 0)
+         return NULL;
+   }
+   switch (nsegments[i].kind) {
+      case SkFileC: case SkFileV: 
+      case SkAnonC: case SkAnonV: case SkResvn:
+         return &nsegments[i];
+      default:
+         break;
+   }
+   return NULL;
+}
+
+
+/* Trivial fn: return the total amount of space in anonymous mappings,
+   both for V and the client.  Is used for printing stats in
+   out-of-memory messages. */
+ULong VG_(am_get_anonsize_total)( void )
+{
+   Int   i;
+   ULong total = 0;
+   for (i = 0; i < nsegments_used; i++) {
+      if (nsegments[i].kind == SkAnonC || nsegments[i].kind == SkAnonV) {
+         total += (ULong)nsegments[i].end 
+                  - (ULong)nsegments[i].start + 1ULL;
+      }
+   }
+   return total;
+}
+
+
+/* Test if a piece of memory is addressable by the client with at
+   least the "prot" protection permissions by examining the underlying
+   segments.  If freeOk is True then SkFree areas are also allowed.
+*/
+static
+Bool is_valid_for_client( Addr start, SizeT len, UInt prot, Bool freeOk )
+{
+   Int  i, iLo, iHi;
+   Bool needR, needW, needX;
+
+   if (len == 0)
+      return True; /* somewhat dubious case */
+   if (start + len < start)
+      return False; /* reject wraparounds */
+
+   needR = toBool(prot & VKI_PROT_READ);
+   needW = toBool(prot & VKI_PROT_WRITE);
+   needX = toBool(prot & VKI_PROT_EXEC);
+
+   iLo = find_nsegment_idx(start);
+   aspacem_assert(start >= nsegments[iLo].start);
+
+   if (start+len-1 <= nsegments[iLo].end) {
+      /* This is a speedup hack which avoids calling find_nsegment_idx
+         a second time when possible.  It is always correct to just
+         use the "else" clause below, but is_valid_for_client is
+         called a lot by the leak checker, so avoiding pointless calls
+         to find_nsegment_idx, which can be expensive, is helpful. */
+      iHi = iLo;
+   } else {
+      iHi = find_nsegment_idx(start + len - 1);
+   }
+
+   for (i = iLo; i <= iHi; i++) {
+      if ( (nsegments[i].kind == SkFileC 
+            || nsegments[i].kind == SkAnonC
+            || (nsegments[i].kind == SkFree  && freeOk)
+            || (nsegments[i].kind == SkResvn && freeOk))
+           && (needR ? nsegments[i].hasR : True)
+           && (needW ? nsegments[i].hasW : True)
+           && (needX ? nsegments[i].hasX : True) ) {
+         /* ok */
+      } else {
+         return False;
+      }
+   }
+   return True;
+}
+
+/* Test if a piece of memory is addressable by the client with at
+   least the "prot" protection permissions by examining the underlying
+   segments. */
+Bool VG_(am_is_valid_for_client)( Addr start, SizeT len, 
+                                  UInt prot )
+{
+   return is_valid_for_client( start, len, prot, False/*free not OK*/ );
+}
+
+/* Variant of VG_(am_is_valid_for_client) which allows free areas to
+   be consider part of the client's addressable space.  It also
+   considers reservations to be allowable, since from the client's
+   point of view they don't exist. */
+Bool VG_(am_is_valid_for_client_or_free_or_resvn)
+   ( Addr start, SizeT len, UInt prot )
+{
+   return is_valid_for_client( start, len, prot, True/*free is OK*/ );
+}
+
+
+/* Test if a piece of memory is addressable by valgrind with at least
+   PROT_NONE protection permissions by examining the underlying
+   segments. */
+static Bool is_valid_for_valgrind( Addr start, SizeT len )
+{
+   Int  i, iLo, iHi;
+
+   if (len == 0)
+      return True; /* somewhat dubious case */
+   if (start + len < start)
+      return False; /* reject wraparounds */
+
+   iLo = find_nsegment_idx(start);
+   iHi = find_nsegment_idx(start + len - 1);
+   for (i = iLo; i <= iHi; i++) {
+      if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkAnonV) {
+         /* ok */
+      } else {
+         return False;
+      }
+   }
+   return True;
+}
+
+
+/* Returns True if any part of the address range is marked as having
+   translations made from it.  This is used to determine when to
+   discard code, so if in doubt return True. */
+
+static Bool any_Ts_in_range ( Addr start, SizeT len )
+{
+   Int iLo, iHi, i;
+   aspacem_assert(len > 0);
+   aspacem_assert(start + len > start);
+   iLo = find_nsegment_idx(start);
+   iHi = find_nsegment_idx(start + len - 1);
+   for (i = iLo; i <= iHi; i++) {
+      if (nsegments[i].hasT)
+         return True;
+   }
+   return False;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Modifying the segment array, and constructing segments.   ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Split the segment containing 'a' into two, so that 'a' is
+   guaranteed to be the start of a new segment.  If 'a' is already the
+   start of a segment, do nothing. */
+
+static void split_nsegment_at ( Addr a )
+{
+   Int i, j;
+
+   aspacem_assert(a > 0);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(a));
+   i = find_nsegment_idx(a);
+   aspacem_assert(i >= 0 && i < nsegments_used);
+
+   if (nsegments[i].start == a)
+      /* 'a' is already the start point of a segment, so nothing to be
+         done. */
+      return;
+
+   /* else we have to slide the segments upwards to make a hole */
+   if (nsegments_used >= VG_N_SEGMENTS)
+      aspacem_barf_toolow("VG_N_SEGMENTS");
+   for (j = nsegments_used-1; j > i; j--)
+      nsegments[j+1] = nsegments[j];
+   nsegments_used++;
+
+   nsegments[i+1]       = nsegments[i];
+   nsegments[i+1].start = a;
+   nsegments[i].end     = a-1;
+
+   if (nsegments[i].kind == SkFileV || nsegments[i].kind == SkFileC)
+      nsegments[i+1].offset 
+         += ((ULong)nsegments[i+1].start) - ((ULong)nsegments[i].start);
+
+   aspacem_assert(sane_NSegment(&nsegments[i]));
+   aspacem_assert(sane_NSegment(&nsegments[i+1]));
+}
+
+
+/* Do the minimum amount of segment splitting necessary to ensure that
+   sLo is the first address denoted by some segment and sHi is the
+   highest address denoted by some other segment.  Returns the indices
+   of the lowest and highest segments in the range. */
+
+static 
+void split_nsegments_lo_and_hi ( Addr sLo, Addr sHi,
+                                 /*OUT*/Int* iLo,
+                                 /*OUT*/Int* iHi )
+{
+   aspacem_assert(sLo < sHi);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(sLo));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(sHi+1));
+
+   if (sLo > 0)
+      split_nsegment_at(sLo);
+   if (sHi < sHi+1)
+      split_nsegment_at(sHi+1);
+
+   *iLo = find_nsegment_idx(sLo);
+   *iHi = find_nsegment_idx(sHi);
+   aspacem_assert(0 <= *iLo && *iLo < nsegments_used);
+   aspacem_assert(0 <= *iHi && *iHi < nsegments_used);
+   aspacem_assert(*iLo <= *iHi);
+   aspacem_assert(nsegments[*iLo].start == sLo);
+   aspacem_assert(nsegments[*iHi].end == sHi);
+   /* Not that I'm overly paranoid or anything, definitely not :-) */
+}
+
+
+/* Add SEG to the collection, deleting/truncating any it overlaps.
+   This deals with all the tricky cases of splitting up segments as
+   needed. */
+
+static void add_segment ( NSegment* seg )
+{
+   Int  i, iLo, iHi, delta;
+   Bool segment_is_sane;
+
+   Addr sStart = seg->start;
+   Addr sEnd   = seg->end;
+
+   aspacem_assert(sStart <= sEnd);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(sStart));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(sEnd+1));
+
+   segment_is_sane = sane_NSegment(seg);
+   if (!segment_is_sane) show_nsegment_full(0,seg);
+   aspacem_assert(segment_is_sane);
+
+   split_nsegments_lo_and_hi( sStart, sEnd, &iLo, &iHi );
+
+   /* Now iLo .. iHi inclusive is the range of segment indices which
+      seg will replace.  If we're replacing more than one segment,
+      slide those above the range down to fill the hole. */
+   delta = iHi - iLo;
+   aspacem_assert(delta >= 0);
+   if (delta > 0) {
+      for (i = iLo; i < nsegments_used-delta; i++)
+         nsegments[i] = nsegments[i+delta];
+      nsegments_used -= delta;
+   }
+
+   nsegments[iLo] = *seg;
+
+   (void)preen_nsegments();
+   if (0) VG_(am_show_nsegments)(0,"AFTER preen (add_segment)");
+}
+
+
+/* Clear out an NSegment record. */
+
+static void init_nsegment ( /*OUT*/NSegment* seg )
+{
+   seg->kind     = SkFree;
+   seg->start    = 0;
+   seg->end      = 0;
+   seg->smode    = SmFixed;
+   seg->dev      = 0;
+   seg->ino      = 0;
+   seg->offset   = 0;
+   seg->fnIdx    = -1;
+   seg->hasR = seg->hasW = seg->hasX = seg->hasT = seg->isCH = False;
+   seg->mark = False;
+}
+
+/* Make an NSegment which holds a reservation. */
+
+static void init_resvn ( /*OUT*/NSegment* seg, Addr start, Addr end )
+{
+   aspacem_assert(start < end);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(end+1));
+   init_nsegment(seg);
+   seg->kind  = SkResvn;
+   seg->start = start;
+   seg->end   = end;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Startup, including reading /proc/self/maps.               ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
+                                 UInt dev, UInt ino, ULong offset, 
+                                 const UChar* filename )
+{
+   NSegment seg;
+   init_nsegment( &seg );
+   seg.start  = addr;
+   seg.end    = addr+len-1;
+   seg.dev    = dev;
+   seg.ino    = ino;
+   seg.offset = offset;
+   seg.hasR   = toBool(prot & VKI_PROT_READ);
+   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
+   seg.hasT   = False;
+
+   seg.kind = SkAnonV;
+   if (filename) { 
+      seg.kind  = SkFileV;
+      seg.fnIdx = allocate_segname( filename );
+   }
+
+   if (0) show_nsegment( 2,0, &seg );
+   add_segment( &seg );
 }
 
+/* Initialise the address space manager, setting up the initial
+   segment list, and reading /proc/self/maps into it.  This must
+   be called before any other function.
+
+   Takes a pointer to the SP at the time V gained control.  This is
+   taken to be the highest usable address (more or less).  Based on
+   that (and general consultation of tea leaves, etc) return a
+   suggested end address for the client's stack. */
+
+Addr VG_(am_startup) ( Addr sp_at_startup )
+{
+   NSegment seg;
+   Addr     suggested_clstack_top;
+
+   aspacem_assert(sizeof(Word)   == sizeof(void*));
+   aspacem_assert(sizeof(Addr)   == sizeof(void*));
+   aspacem_assert(sizeof(SizeT)  == sizeof(void*));
+   aspacem_assert(sizeof(SSizeT) == sizeof(void*));
+
+   { 
+      /* If these fail, we'd better change the type of dev and ino in
+         NSegment accordingly. */
+      struct vki_stat buf;
+      aspacem_assert(sizeof(buf.st_dev) == sizeof(seg.dev));
+      aspacem_assert(sizeof(buf.st_ino) == sizeof(seg.ino));
+   }
+
+   /* Add a single interval covering the entire address space. */
+   init_nsegment(&seg);
+   seg.kind        = SkFree;
+   seg.start       = Addr_MIN;
+   seg.end         = Addr_MAX;
+   nsegments[0]    = seg;
+   nsegments_used  = 1;
+
+   /* Establish address limits and block out unusable parts
+      accordingly. */
+
+   VG_(debugLog)(2, "aspacem", 
+                    "        sp_at_startup = 0x%llx (supplied)\n", 
+                    (ULong)sp_at_startup );
+
+   aspacem_minAddr = (Addr) 0x04000000; // 64M
+
+#  if VG_WORDSIZE == 8
+   aspacem_maxAddr = (Addr)0x400000000 - 1; // 16G
+#  else
+   aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1;
+#  endif
+
+   aspacem_cStart = aspacem_minAddr; // 64M
+   aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2);
+#  ifdef ENABLE_INNER
+   aspacem_vStart -= 0x10000000; // 256M
+#  endif
+
+   suggested_clstack_top = aspacem_maxAddr - 16*1024*1024ULL
+                                           + VKI_PAGE_SIZE;
+
+   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_vStart));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(suggested_clstack_top + 1));
+
+   VG_(debugLog)(2, "aspacem", 
+                    "              minAddr = 0x%010llx (computed)\n", 
+                    (ULong)aspacem_minAddr);
+   VG_(debugLog)(2, "aspacem", 
+                    "              maxAddr = 0x%010llx (computed)\n", 
+                    (ULong)aspacem_maxAddr);
+   VG_(debugLog)(2, "aspacem", 
+                    "               cStart = 0x%010llx (computed)\n", 
+                    (ULong)aspacem_cStart);
+   VG_(debugLog)(2, "aspacem", 
+                    "               vStart = 0x%010llx (computed)\n", 
+                    (ULong)aspacem_vStart);
+   VG_(debugLog)(2, "aspacem", 
+                    "suggested_clstack_top = 0x%010llx (computed)\n", 
+                    (ULong)suggested_clstack_top);
+
+   if (aspacem_cStart > Addr_MIN) {
+      init_resvn(&seg, Addr_MIN, aspacem_cStart-1);
+      add_segment(&seg);
+   }
+   if (aspacem_maxAddr < Addr_MAX) {
+      init_resvn(&seg, aspacem_maxAddr+1, Addr_MAX);
+      add_segment(&seg);
+   }
+
+   /* Create a 1-page reservation at the notional initial
+      client/valgrind boundary.  This isn't strictly necessary, but
+      because the advisor does first-fit and starts searches for
+      valgrind allocations at the boundary, this is kind of necessary
+      in order to get it to start allocating in the right place. */
+   init_resvn(&seg, aspacem_vStart,  aspacem_vStart + VKI_PAGE_SIZE - 1);
+   add_segment(&seg);
+
+   VG_(am_show_nsegments)(2, "Initial layout");
+
+   VG_(debugLog)(2, "aspacem", "Reading /proc/self/maps\n");
+   VG_(parse_procselfmaps) ( read_maps_callback, NULL );
+
+   VG_(am_show_nsegments)(2, "With contents of /proc/self/maps");
+
+   AM_SANITY_CHECK;
+   return suggested_clstack_top;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- The core query-notify mechanism.                          ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Query aspacem to ask where a mapping should go. */
+
+Addr VG_(am_get_advisory) ( MapRequest*  req, 
+                            Bool         forClient, 
+                            /*OUT*/Bool* ok )
+{
+   /* This function implements allocation policy.
+
+      The nature of the allocation request is determined by req, which
+      specifies the start and length of the request and indicates
+      whether the start address is mandatory, a hint, or irrelevant,
+      and by forClient, which says whether this is for the client or
+      for V. 
+
+      Return values: the request can be vetoed (*ok is set to False),
+      in which case the caller should not attempt to proceed with
+      making the mapping.  Otherwise, *ok is set to True, the caller
+      may proceed, and the preferred address at which the mapping
+      should happen is returned.
+
+      Note that this is an advisory system only: the kernel can in
+      fact do whatever it likes as far as placement goes, and we have
+      no absolute control over it.
+
+      Allocations will never be granted in a reserved area.
+
+      The Default Policy is:
+
+        Search the address space for two free intervals: one of them
+        big enough to contain the request without regard to the
+        specified address (viz, as if it was a floating request) and
+        the other being able to contain the request at the specified
+        address (viz, as if were a fixed request).  Then, depending on
+        the outcome of the search and the kind of request made, decide
+        whether the request is allowable and what address to advise.
+
+      The Default Policy is overriden by Policy Exception #1:
+
+        If the request is for a fixed client map, we are prepared to
+        grant it providing all areas inside the request are either
+        free, reservations, or mappings belonging to the client.  In
+        other words we are prepared to let the client trash its own
+        mappings if it wants to.
+
+        Similarly, a hinted client map will be granted at the
+        requested address providing the same conditions hold.
+
+   */
+   Int  i, j;
+   Addr holeStart, holeEnd, holeLen;
+   Bool fixed_not_required;
+
+   Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
+
+   Addr reqStart = req->rkind==MAny ? 0 : req->start;
+   Addr reqEnd   = reqStart + req->len - 1;
+   Addr reqLen   = req->len;
+
+   /* These hold indices for segments found during search, or -1 if not
+      found. */
+   Int floatIdx = -1;
+   Int fixedIdx = -1;
+
+   aspacem_assert(nsegments_used > 0);
+
+   if (0) {
+      VG_(am_show_nsegments)(0,"getAdvisory");
+      VG_(debugLog)(0,"aspacem", "getAdvisory 0x%llx %lld\n", 
+                      (ULong)req->start, (ULong)req->len);
+   }
+
+   /* Reject zero-length requests */
+   if (req->len == 0) {
+      *ok = False;
+      return 0;
+   }
+
+   /* Reject wraparounds */
+   if ((req->rkind==MFixed || req->rkind==MHint)
+       && req->start + req->len < req->start) {
+      *ok = False;
+      return 0;
+   }
 
-/* Find the (index of the) segment that contains 'a', or -1 if
-   none. 
-*/
-static Int find_segment ( Addr a )
-{
-   Int i;
-   for (i = 0; i < segments_used; i++) {
-      if (compare_addr_with_seg(a, &segments[i]) == 0)
-         return i;
+   /* ------ Implement Policy Exception #1 ------ */
+
+   if (forClient && (req->rkind == MFixed || req->rkind == MHint)) {
+      Int  iLo   = find_nsegment_idx(reqStart);
+      Int  iHi   = find_nsegment_idx(reqEnd);
+      Bool allow = True;
+      for (i = iLo; i <= iHi; i++) {
+         if (nsegments[i].kind == SkFree
+             || nsegments[i].kind == SkFileC
+             || nsegments[i].kind == SkAnonC
+             || nsegments[i].kind == SkResvn) {
+            /* ok */
+         } else {
+            allow = False;
+            break;
+         }
+      }
+      if (allow) {
+         /* Acceptable.  Granted. */
+         *ok = True;
+         return reqStart;
+      }
+      /* Not acceptable.  Fixed fails, Hint is now attempted by the
+         default policy. */
+      if (req->rkind == MFixed) {
+         *ok = False;
+         return 0;
+      }
    }
-   return -1;
-}
 
+   /* ------ Implement the Default Policy ------ */
 
-/* Assumes that 'a' is not in any segment.  Finds the index of the
-   lowest-addressed segment above 'a', or -1 if none.  Passing 'a'
-   which is in fact in a segment is a checked error. 
-*/
-static Int find_segment_above_unmapped ( Addr a )
-{
-   Int i, r;
-   for (i = 0; i < segments_used; i++) {
-      r = compare_addr_with_seg(a, &segments[i]);
-      vg_assert(r != 0); /* 'a' should not be in any segment. */
-      if (r == 1)
+   /* Don't waste time looking for a fixed match if not requested to. */
+   fixed_not_required = req->rkind == MAny;
+
+   i = find_nsegment_idx(startPoint);
+
+   /* Examine holes from index i back round to i-1.  Record the
+      index first fixed hole and the first floating hole which would
+      satisfy the request. */
+   for (j = 0; j < nsegments_used; j++) {
+
+      if (nsegments[i].kind != SkFree) {
+         i++;
+         if (i >= nsegments_used) i = 0;
          continue;
-      vg_assert(r == -1);
-      break;
-   }
+      }
 
-   if (i == segments_used)
-      return -1; /* not found */
-   else
-      return i;
-}
+      holeStart = nsegments[i].start;
+      holeEnd   = nsegments[i].end;
 
+      /* Stay sane .. */
+      aspacem_assert(holeStart <= holeEnd);
+      aspacem_assert(aspacem_minAddr <= holeStart);
+      aspacem_assert(holeEnd <= aspacem_maxAddr);
 
-/* Assumes that 'a' is in some segment.  Finds the next segment along,
-   or NULL if none.  Passing 'a' which is in fact not in a segment is
-   a checked error.
-*/
-static Int find_segment_above_mapped ( Addr a )
-{
-   Int i, r;
-   for (i = 0; i < segments_used; i++) {
-      r = compare_addr_with_seg(a, &segments[i]);
-      if (r == 1)
-         continue; /* not yet there */
-      if (r == 0)
-         break; /* found it */
-      vg_assert(0);
-      /* we shouldn't get here -- r == -1 and so it means we went past 
-         'a' without seeing it -- it is therefore unmapped. */
-      /*NOTREACHED*/
-   }
+      /* See if it's any use to us. */
+      holeLen = holeEnd - holeStart + 1;
 
-   vg_assert(i < segments_used);
-   if (i == segments_used-1)
-      return -1; /* not found */
-   else
-      return i+1;
-}
-
-
-/* Shift segments[i .. segments_used-1] up by one. */
-static void make_space_at ( Int i )
-{
-   Int j;
-   vg_assert(i >= 0 && i <= segments_used);
-   vg_assert(segments_used >= 0);
-   if (segments_used+1 == VG_N_SEGMENTS) {
-      VG_(printf)(
-         "coregrind/m_aspacemgr/aspacemgr.c:\n"
-         "   VG_N_SEGMENTS is too small: "
-         "increase it and rebuild Valgrind.\n"
-      );
-      VG_(printf)(
-         "coregrind/m_aspacemgr/aspacemgr.c:\n"
-         "   giving up now.\n\n"
-      );
-      VG_(exit)(0);
+      if (fixedIdx == -1 && holeStart <= reqStart && reqEnd <= holeEnd)
+         fixedIdx = i;
+
+      if (floatIdx == -1 && holeLen >= reqLen)
+         floatIdx = i;
+  
+      /* Don't waste time searching once we've found what we wanted. */
+      if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
+         break;
+
+      i++;
+      if (i >= nsegments_used) i = 0;
    }
-   vg_assert(segments_used+1 < VG_N_SEGMENTS);
-   for (j = segments_used; j > i; j--)
-      segments[j] = segments[j-1];
-   segments_used++;
-}
 
-// Forward declaration
-static void dealloc_seg_memory(Segment *s);
+   aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
+   if (fixedIdx >= 0) 
+      aspacem_assert(nsegments[fixedIdx].kind == SkFree);
 
-/* Shift segments [i+1 .. segments_used-1] down by one, and decrement
-   segments_used. 
-*/
-static void delete_segment_at ( Int i )
-{
-   Int j;
-   vg_assert(i >= 0 && i < segments_used);
-   dealloc_seg_memory(&segments[i]);
-   for (j = i+1; j < segments_used; j++) {
-      segments[j-1] = segments[j];
+   aspacem_assert(floatIdx >= -1 && floatIdx < nsegments_used);
+   if (floatIdx >= 0) 
+      aspacem_assert(nsegments[floatIdx].kind == SkFree);
+
+   AM_SANITY_CHECK;
+
+   /* Now see if we found anything which can satisfy the request. */
+   switch (req->rkind) {
+      case MFixed:
+         if (fixedIdx >= 0) {
+            *ok = True;
+            return req->start;
+         } else {
+            *ok = False;
+            return 0;
+         }
+         break;
+      case MHint:
+         if (fixedIdx >= 0) {
+            *ok = True;
+            return req->start;
+         }
+         if (floatIdx >= 0) {
+            *ok = True;
+            return nsegments[floatIdx].start;
+         }
+         *ok = False;
+         return 0;
+      case MAny:
+         if (floatIdx >= 0) {
+            *ok = True;
+            return nsegments[floatIdx].start;
+         }
+         *ok = False;
+         return 0;
+      default: 
+         break;
    }
-   segments_used--;
-   vg_assert(segments_used >= 0 && segments_used < VG_N_SEGMENTS);
+
+   /*NOTREACHED*/
+   aspacem_barf("getAdvisory: unknown request kind");
+   *ok = False;
+   return 0;
 }
 
+/* Convenience wrapper for VG_(am_get_advisory) for client floating or
+   fixed requests.  If start is zero, a floating request is issued; if
+   nonzero, a fixed request at that address is issued.  Same comments
+   about return values apply. */
 
-/* Fill the i'th record all with zeroes. */
-static void zeroise_segment ( Int i )
+Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len, 
+                                          /*OUT*/Bool* ok )
 {
-   vg_assert(i >= 0 && i < segments_used);
-   segments[i].prot     = 0;
-   segments[i].flags    = 0;
-   segments[i].addr     = 0;
-   segments[i].len      = 0;
-   segments[i].offset   = 0;
-   segments[i].filename = NULL;
-   segments[i].fnIdx    = -1;
-   segments[i].dev      = 0;
-   segments[i].ino      = 0;
-   segments[i].seginfo  = NULL;
+   MapRequest mreq;
+   mreq.rkind = start==0 ? MAny : MFixed;
+   mreq.start = start;
+   mreq.len   = len;
+   return VG_(am_get_advisory)( &mreq, True/*client*/, ok );
 }
 
 
-/* Create a segment to contain 'a', and return its index.  Or -1 if
-   this failed because some other segment already contains 'a'.  If
-   successful, fill in the segment's .addr field with 'a' but leave
-   all other fields alone. 
-*/
-static Int create_segment ( Addr a )
-{
-   Int i, r;
-   for (i = 0; i < segments_used; i++) {
-      r = compare_addr_with_seg( a, &segments[i] );
-      if (r == 1)
-         continue; /* seg[i] precedes a */
-      if (r == 0)
-         return -1; /* seg[i] contains a.  Give up */
-      vg_assert(r == -1);
-      break;
-   }
-   /* a precedes seg[i].  Shift segs at i and above up one, and use
-      this slot. */
-   make_space_at(i);
-   zeroise_segment(i);
-   segments[i].addr = a;
-   return i;
-}
-
+/* Notifies aspacem that the client completed an mmap successfully.
+   The segment array is updated accordingly.  If the returned Bool is
+   True, the caller should immediately discard translations from the
+   specified address range. */
 
-/* Print out the segment array (debugging only!).  Note, this calls
-   VG_(printf), and I'm not 100% clear that that wouldn't require
-   dynamic memory allocation and hence more segments to be allocated.
-*/
-void VG_(show_segments) ( HChar* who )
+Bool
+VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
+                            Int fd, SizeT offset )
 {
-   Int i;
-   VG_(printf)("<<< SHOW_SEGMENTS: %s (%d segments, %d segnames)\n", 
-               who, segments_used, segnames_used);
-   for (i = 0; i < segnames_used; i++) {
-      if (!segnames[i].inUse)
-         continue;
-      VG_(printf)("(%2d) %s\n", i, segnames[i].fname);
-   }
-   for (i = 0; i < segments_used; i++) {
-      VG_(printf)(
-         "%3d: %08p-%08p %7llu pr=0x%x fl=0x%04x d=0x%03x i=%-7d o=%-7lld (%d)\n",
-         i,
-         segments[i].addr, segments[i].addr + segments[i].len,
-         (ULong)segments[i].len, segments[i].prot, 
-         segments[i].flags, segments[i].dev, segments[i].ino, 
-         (Long)segments[i].offset, 
-         segments[i].fnIdx);
+   HChar    buf[VKI_PATH_MAX];
+   UInt     dev, ino;
+   NSegment seg;
+   Bool     needDiscard;
+
+   aspacem_assert(len > 0);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(a));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
+
+   /* Discard is needed if any of the just-trashed range had T. */
+   needDiscard = any_Ts_in_range( a, len );
+
+   init_nsegment( &seg );
+   seg.kind   = (flags & VKI_MAP_ANONYMOUS) ? SkAnonC : SkFileC;
+   seg.start  = a;
+   seg.end    = a + len - 1;
+   seg.offset = offset;
+   seg.hasR   = toBool(prot & VKI_PROT_READ);
+   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
+   if (!(flags & VKI_MAP_ANONYMOUS)) {
+      if (get_inode_for_fd(fd, &dev, &ino)) {
+         seg.dev = dev;
+         seg.ino = ino;
+      }
+      if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
+         seg.fnIdx = allocate_segname( buf );
+      }
    }
-   VG_(printf)(">>>\n");
+   add_segment( &seg );
+   AM_SANITY_CHECK;
+   return needDiscard;
 }
 
+/* Notifies aspacem that an mprotect was completed successfully.  The
+   segment array is updated accordingly.  Note, as with
+   VG_(am_notify_munmap), it is not the job of this function to reject
+   stupid mprotects, for example the client doing mprotect of
+   non-client areas.  Such requests should be intercepted earlier, by
+   the syscall wrapper for mprotect.  This function merely records
+   whatever it is told.  If the returned Bool is True, the caller
+   should immediately discard translations from the specified address
+   range. */
+
+Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot )
+{
+   Int  i, iLo, iHi;
+   Bool newR, newW, newX, needDiscard;
 
-/* Find the segment containing 'a' and split it into two pieces at
-   'a'.  Does nothing if no segment contains 'a', or if the split
-   would cause either of the pieces to have zero size.
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
 
-   If 'a' is not found, or if no splitting happens, -1 is returned.
+   if (len == 0)
+      return False;
 
-   If a value 'r' other than -1 is returned, this is the index of the
-   higher-addressed segment resulting from the split, and the index of
-   the lower-addressed segment is r-1.
-*/
-static Int split_segment ( Addr a )
-{
-   Int r;
-   HWord delta;
-   vg_assert(VG_IS_PAGE_ALIGNED(a));
-   r = find_segment(a);
-   if (r == -1)
-      /* not found */
-      return -1;
-   if (segments[r].addr == a)
-      /* segment starts at 'a', so splitting it would create a
-         zero-sized segment */
-      return -1;
+   newR = toBool(prot & VKI_PROT_READ);
+   newW = toBool(prot & VKI_PROT_WRITE);
+   newX = toBool(prot & VKI_PROT_EXEC);
+
+   /* Discard is needed if we're dumping X permission */
+   needDiscard = any_Ts_in_range( start, len ) && !newX;
+
+   split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
+
+   iLo = find_nsegment_idx(start);
+   iHi = find_nsegment_idx(start + len - 1);
+
+   for (i = iLo; i <= iHi; i++) {
+      /* Apply the permissions to all relevant segments. */
+      switch (nsegments[i].kind) {
+         case SkAnonC: case SkAnonV: case SkFileC: case SkFileV:
+            nsegments[i].hasR = newR;
+            nsegments[i].hasW = newW;
+            nsegments[i].hasX = newX;
+            aspacem_assert(sane_NSegment(&nsegments[i]));
+            break;
+         default:
+            break;
+      }
+   }
 
-   /* copy original; make adjustments. */
-   vg_assert(a > segments[r].addr);
-   delta = a - segments[r].addr;
-   make_space_at(r);
-   
-   segments[r] = segments[r+1];
-   segments[r].len = delta;
-   if (segments[r].seginfo)
-      VG_(seginfo_incref)(segments[r].seginfo);
-   
-   segments[r+1].len -= delta;
-   segments[r+1].addr += delta;
-   segments[r+1].offset += delta;
-   return r+1;
+   /* Changing permissions could have made previously un-mergable
+      segments mergeable.  Therefore have to re-preen them. */
+   (void)preen_nsegments();
+   AM_SANITY_CHECK;
+   return needDiscard;
 }
 
 
-/* Return true if two segments are adjacent and mergable (s1 is
-   assumed to have a lower ->addr than s2) */
-static inline Bool segments_are_mergeable(Segment *s1, Segment *s2)
+/* Notifies aspacem that an munmap completed successfully.  The
+   segment array is updated accordingly.  As with
+   VG_(am_notify_munmap), we merely record the given info, and don't
+   check it for sensibleness.  If the returned Bool is True, the
+   caller should immediately discard translations from the specified
+   address range. */
+
+Bool VG_(am_notify_munmap)( Addr start, SizeT len )
 {
-   if (s1->addr+s1->len != s2->addr)
-      return False;
+   NSegment seg;
+   Bool     needDiscard;
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
 
-   if (s1->flags != s2->flags)
+   if (len == 0)
       return False;
 
-   if (s1->prot != s2->prot)
-      return False;
+   needDiscard = any_Ts_in_range( start, len );
 
-   if (s1->seginfo != s2->seginfo)
-      return False;
+   init_nsegment( &seg );
+   seg.kind  = SkFree;
+   seg.start = start;
+   seg.end   = start + len - 1;
+   add_segment( &seg );
 
-   if (s1->flags & SF_FILE){
-      if ((s1->offset + s1->len) != s2->offset)
-        return False;
-      if (s1->dev != s2->dev)
-        return False;
-      if (s1->ino != s2->ino)
-        return False;
-      if (s1->fnIdx != s2->fnIdx)
-         return False;
-   }
-   
-   return True;
+   /* Unmapping could create two adjacent free segments, so a preen is
+      needed.  add_segment() will do that, so no need to here. */
+   AM_SANITY_CHECK;
+   return needDiscard;
 }
 
 
-/* Clean up and sanity check the segment array:
-   - check segments are in ascending order
-   - check segments do not overlap
-   - check no segment has zero size
-   - merge adjacent where possible
-   - perform checks on the filename table, and reclaim dead entries
-*/
-static void preen_segments ( void )
-{
-   Int i, j, rd, wr;
-   Segment *s, *s1;
-   vg_assert(segments_used >= 0 && segments_used < VG_N_SEGMENTS);
-   vg_assert(segnames_used >= 0 && segnames_used < VG_N_SEGNAMES);
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Handling mappings which do not arise directly from the    ---*/
+/*--- simulation of the client.                                 ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
 
-   if (0) VG_(show_segments)("before preen");
-
-   /* clear string table mark bits */
-   for (i = 0; i < segnames_used; i++)
-      segnames[i].mark = False;
+/* --- --- --- map, unmap, protect  --- --- --- */
 
-   /* check for non-zero size, and set mark bits for any used strings */
-   for (i = 0; i < segments_used; i++) {
-      vg_assert(segments[i].len > 0);
-      j = segments[i].fnIdx;
-      vg_assert(j >= -1 && j < segnames_used);
-      if (j >= 0) {
-         vg_assert(segnames[j].inUse);
-         segnames[j].mark = True;
-      }
-   }
+/* Map a file at a fixed address for the client, and update the
+   segment array accordingly. */
 
-   /* check ascendingness and non-overlap */
-   for (i = 0; i < segments_used-1; i++) {
-      s = &segments[i];
-      s1 = &segments[i+1];
-      vg_assert(s->addr < s1->addr);
-      vg_assert(s->addr + s->len <= s1->addr);
+SysRes VG_(am_mmap_file_fixed_client)
+     ( Addr start, SizeT length, UInt prot, Int fd, SizeT offset )
+{
+   SysRes     sres;
+   NSegment   seg;
+   Addr       advised;
+   Bool       ok;
+   MapRequest req;
+   UInt       dev, ino;
+   HChar      buf[VKI_PATH_MAX];
+
+   /* Not allowable. */
+   if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* Ask for an advisory.  If it's negative, fail immediately. */
+   req.rkind = MFixed;
+   req.start = start;
+   req.len   = length;
+   advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
+   if (!ok || advised != start)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* We have been advised that the mapping is allowable at the
+      specified address.  So hand it off to the kernel, and propagate
+      any resulting failure immediately. */
+   sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             start, length, prot, 
+             VKI_MAP_FIXED|VKI_MAP_PRIVATE, 
+             fd, offset 
+          );
+   if (sres.isError)
+      return sres;
+
+   if (sres.val != start) {
+      /* I don't think this can happen.  It means the kernel made a
+         fixed map succeed but not at the requested location.  Try to
+         repair the damage, then return saying the mapping failed. */
+      (void)do_munmap_NO_NOTIFY( sres.val, length );
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
    }
 
-   /* merge */
-   if (segments_used < 1)
-      return;
-
-   wr = 1;
-   for (rd = 1; rd < segments_used; rd++) {
-      s = &segments[wr-1];
-      s1 = &segments[rd];
-      if (segments_are_mergeable(s,s1)) {
-         if (0)
-            VG_(printf)("merge %p-%p with %p-%p\n",
-                        s->addr, s->addr+s->len,
-                        s1->addr, s1->addr+s1->len);
-         s->len += s1->len;
-
-         vg_assert(s->seginfo == s1->seginfo);
-         dealloc_seg_memory(s1);
-         
-         continue;
-      }
-      if (wr < rd)
-         segments[wr] = segments[rd];
-      wr++;
+   /* Ok, the mapping succeeded.  Now notify the interval map. */
+   init_nsegment( &seg );
+   seg.kind   = SkFileC;
+   seg.start  = start;
+   seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
+   seg.offset = offset;
+   seg.hasR   = toBool(prot & VKI_PROT_READ);
+   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
+   if (get_inode_for_fd(fd, &dev, &ino)) {
+      seg.dev = dev;
+      seg.ino = ino;
    }
-   vg_assert(wr >= 0 && wr <= segments_used);
-   segments_used = wr;
-
-   /* Free up any strings which are no longer referenced. */
-   for (i = 0; i < segnames_used; i++) {
-      if (segnames[i].mark == False) {
-         segnames[i].inUse = False;
-         segnames[i].fname[0] = 0;
-      }
+   if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
+      seg.fnIdx = allocate_segname( buf );
    }
+   add_segment( &seg );
 
-   if (0) VG_(show_segments)("after preen");
+   AM_SANITY_CHECK;
+   return sres;
 }
 
 
-/*--------------------------------------------------------------*/
-/*--- Maintain an ordered list of all the client's mappings  ---*/
-/*--------------------------------------------------------------*/
+/* Map anonymously at a fixed address for the client, and update
+   the segment array accordingly. */
 
-Bool VG_(seg_contains)(const Segment *s, Addr p, SizeT len)
+SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
 {
-   Addr se = s->addr+s->len;
-   Addr pe = p+len;
-   vg_assert(pe >= p);
+   SysRes     sres;
+   NSegment   seg;
+   Addr       advised;
+   Bool       ok;
+   MapRequest req;
+   /* Not allowable. */
+   if (length == 0 || !VG_IS_PAGE_ALIGNED(start))
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* Ask for an advisory.  If it's negative, fail immediately. */
+   req.rkind = MFixed;
+   req.start = start;
+   req.len   = length;
+   advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
+   if (!ok || advised != start)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* We have been advised that the mapping is allowable at the
+      specified address.  So hand it off to the kernel, and propagate
+      any resulting failure immediately. */
+   sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             start, length, prot, 
+             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+             0, 0 
+          );
+   if (sres.isError)
+      return sres;
+
+   if (sres.val != start) {
+      /* I don't think this can happen.  It means the kernel made a
+         fixed map succeed but not at the requested location.  Try to
+         repair the damage, then return saying the mapping failed. */
+      (void)do_munmap_NO_NOTIFY( sres.val, length );
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   }
 
-   return (p >= s->addr && pe <= se);
+   /* Ok, the mapping succeeded.  Now notify the interval map. */
+   init_nsegment( &seg );
+   seg.kind  = SkAnonC;
+   seg.start = start;
+   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
+   seg.hasR  = toBool(prot & VKI_PROT_READ);
+   seg.hasW  = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX  = toBool(prot & VKI_PROT_EXEC);
+   add_segment( &seg );
+
+   AM_SANITY_CHECK;
+   return sres;
 }
 
-Bool VG_(seg_overlaps)(const Segment *s, Addr p, SizeT len)
-{
-   Addr se = s->addr+s->len;
-   Addr pe = p+len;
-   vg_assert(pe >= p);
 
-   return (p < se && pe > s->addr);
-}
+/* Map anonymously at an unconstrained address for the client, and
+   update the segment array accordingly.  */
 
-/* When freeing a Segment, also clean up every one else's ideas of
-   what was going on in that range of memory */
-static void dealloc_seg_memory(Segment *s)
+SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
 {
-   if (s->seginfo != NULL) {
-      VG_(seginfo_decref)(s->seginfo, s->addr);
-      s->seginfo = NULL;
+   SysRes     sres;
+   NSegment   seg;
+   Addr       advised;
+   Bool       ok;
+   MapRequest req;
+   /* Not allowable. */
+   if (length == 0)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* Ask for an advisory.  If it's negative, fail immediately. */
+   req.rkind = MAny;
+   req.start = 0;
+   req.len   = length;
+   advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
+   if (!ok)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* We have been advised that the mapping is allowable at the
+      advised address.  So hand it off to the kernel, and propagate
+      any resulting failure immediately. */
+   sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             advised, length, prot, 
+             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+             0, 0 
+          );
+   if (sres.isError)
+      return sres;
+
+   if (sres.val != advised) {
+      /* I don't think this can happen.  It means the kernel made a
+         fixed map succeed but not at the requested location.  Try to
+         repair the damage, then return saying the mapping failed. */
+      (void)do_munmap_NO_NOTIFY( sres.val, length );
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
    }
+
+   /* Ok, the mapping succeeded.  Now notify the interval map. */
+   init_nsegment( &seg );
+   seg.kind  = SkAnonC;
+   seg.start = advised;
+   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
+   seg.hasR  = toBool(prot & VKI_PROT_READ);
+   seg.hasW  = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX  = toBool(prot & VKI_PROT_EXEC);
+   add_segment( &seg );
+
+   AM_SANITY_CHECK;
+   return sres;
 }
 
-/* Get rid of any translations arising from s. */
-/* Note, this is not really the job of the low level memory manager.
-   When it comes time to rewrite this subsystem, clean this up. */
-static void dump_translations_from ( Segment* s )
+
+/* Map anonymously at an unconstrained address for V, and update the
+   segment array accordingly.  This is fundamentally how V allocates
+   itself more address space when needed. */
+
+SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
 {
-   if (s->flags & SF_CODE) {
-      VG_(discard_translations)(s->addr, s->len);
-      if (0)
-         VG_(printf)("dumping translations in %p .. %p\n",
-                     s->addr, s->addr+s->len);
+   SysRes     sres;
+   NSegment   seg;
+   Addr       advised;
+   Bool       ok;
+   MapRequest req;
+   /* Not allowable. */
+   if (length == 0)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* Ask for an advisory.  If it's negative, fail immediately. */
+   req.rkind = MAny;
+   req.start = 0;
+   req.len   = length;
+   advised = VG_(am_get_advisory)( &req, False/*valgrind*/, &ok );
+   if (!ok)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* We have been advised that the mapping is allowable at the
+      specified address.  So hand it off to the kernel, and propagate
+      any resulting failure immediately. */
+   sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             advised, length, 
+             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 
+             VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+             0, 0 
+          );
+   if (sres.isError)
+      return sres;
+
+   if (sres.val != advised) {
+      /* I don't think this can happen.  It means the kernel made a
+         fixed map succeed but not at the requested location.  Try to
+         repair the damage, then return saying the mapping failed. */
+      (void)do_munmap_NO_NOTIFY( sres.val, length );
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
    }
+
+   /* Ok, the mapping succeeded.  Now notify the interval map. */
+   init_nsegment( &seg );
+   seg.kind  = SkAnonV;
+   seg.start = advised;
+   seg.end   = seg.start + VG_PGROUNDUP(length) - 1;
+   seg.hasR  = True;
+   seg.hasW  = True;
+   seg.hasX  = True;
+   add_segment( &seg );
+
+   AM_SANITY_CHECK;
+   return sres;
 }
 
+/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
 
-/* This unmaps all the segments in the range [addr, addr+len); any
-   partial mappings at the ends are truncated. */
-void VG_(unmap_range)(Addr addr, SizeT len)
+void* VG_(am_shadow_alloc)(SizeT size)
 {
-   const Bool debug = False || mem_debug;
-   Segment* s;
-   Addr     end, s_end;
-   Int      i;
-   Bool     deleted;
+   SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
+   return sres.isError ? NULL : (void*)sres.val;
+}
 
-   if (len == 0)
-      return;
 
-   len = VG_PGROUNDUP(len);
 
-   if (debug)
-      VG_(printf)("unmap_range(%p, %llu)\n", addr, (ULong)len);
-   if (0) VG_(show_segments)("unmap_range(BEFORE)");
-   end = addr+len;
+/* Map a file at an unconstrained address for V, and update the
+   segment array accordingly.  This is used by V for transiently
+   mapping in object files to read their debug info.  */
 
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(addr));
-   vg_assert(VG_IS_PAGE_ALIGNED(len));
+SysRes VG_(am_mmap_file_float_valgrind) ( SizeT length, UInt prot, 
+                                          Int fd, SizeT offset )
+{
+   SysRes     sres;
+   NSegment   seg;
+   Addr       advised;
+   Bool       ok;
+   MapRequest req;
+   UInt       dev, ino;
+   HChar      buf[VKI_PATH_MAX];
+   /* Not allowable. */
+   if (length == 0)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* Ask for an advisory.  If it's negative, fail immediately. */
+   req.rkind = MAny;
+   req.start = 0;
+   req.len   = length;
+   advised = VG_(am_get_advisory)( &req, True/*client*/, &ok );
+   if (!ok)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+
+   /* We have been advised that the mapping is allowable at the
+      specified address.  So hand it off to the kernel, and propagate
+      any resulting failure immediately. */
+   sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             advised, length, prot, 
+             VKI_MAP_FIXED|VKI_MAP_PRIVATE, 
+             fd, offset 
+          );
+   if (sres.isError)
+      return sres;
+
+   if (sres.val != advised) {
+      /* I don't think this can happen.  It means the kernel made a
+         fixed map succeed but not at the requested location.  Try to
+         repair the damage, then return saying the mapping failed. */
+      (void)do_munmap_NO_NOTIFY( sres.val, length );
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   }
 
-   for (i = 0; i < segments_used; i++) {
+   /* Ok, the mapping succeeded.  Now notify the interval map. */
+   init_nsegment( &seg );
+   seg.kind   = SkFileV;
+   seg.start  = sres.val;
+   seg.end    = seg.start + VG_PGROUNDUP(length) - 1;
+   seg.offset = offset;
+   seg.hasR   = toBool(prot & VKI_PROT_READ);
+   seg.hasW   = toBool(prot & VKI_PROT_WRITE);
+   seg.hasX   = toBool(prot & VKI_PROT_EXEC);
+   if (get_inode_for_fd(fd, &dev, &ino)) {
+      seg.dev = dev;
+      seg.ino = ino;
+   }
+   if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
+      seg.fnIdx = allocate_segname( buf );
+   }
+   add_segment( &seg );
 
-      /* do not delete .. even though it looks stupid */
-      vg_assert(i >= 0);
+   AM_SANITY_CHECK;
+   return sres;
+}
 
-      deleted = False;
-      s = &segments[i];
-      s_end = s->addr + s->len;
 
-      if (0 && debug)
-        VG_(printf)("unmap: addr=%p-%p s=%p ->addr=%p-%p len=%d\n",
-                    addr, end, s, s->addr, s_end, s->len);
+/* --- --- munmap helper --- --- */
 
-      if (!VG_(seg_overlaps)(s, addr, len)) {
-        if (0 && debug)
-           VG_(printf)("   (no overlap)\n");
-        continue;
-      }
+static 
+SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
+                            Addr start, SizeT len, Bool forClient )
+{
+   Bool   d;
+   SysRes sres;
 
-      /* 4 cases: */
-      if (addr > s->addr &&
-         addr < s_end &&
-         end >= s_end) {
-        /* this segment's tail is truncated by [addr, addr+len)
-           -> truncate tail
-        */
-         dump_translations_from(s);
-        s->len = addr - s->addr;
-
-        if (debug)
-           VG_(printf)("  case 1: s->len=%lu\n", s->len);
-      } else if (addr <= s->addr && end > s->addr && end < s_end) {
-        /* this segment's head is truncated by [addr, addr+len)
-           -> truncate head
-        */
-        Word delta = end - s->addr;
-
-        if (debug)
-           VG_(printf)("  case 2: s->addr=%p s->len=%lu delta=%d\n", 
-                        s->addr, s->len, delta);
-
-         dump_translations_from(s);
-        s->addr += delta;
-        s->offset += delta;
-        s->len -= delta;
-
-        vg_assert(s->len != 0);
-      } else if (addr <= s->addr && end >= s_end) {
-        /* this segment is completely contained within [addr, addr+len)
-           -> delete segment
-        */
-         dump_translations_from(s);
-         delete_segment_at(i);
-         deleted = True;
-
-        if (debug)
-           VG_(printf)("  case 3: seg %d deleted\n", i);
-      } else if (addr > s->addr && end < s_end) {
-        /* [addr, addr+len) is contained within a single segment
-           -> split segment into 3, delete middle portion
-         */
-         Int i_middle;
-         dump_translations_from(s);
-         i_middle = split_segment(addr);
-        vg_assert(i_middle != -1);
-        (void)split_segment(addr+len);
-        vg_assert(segments[i_middle].addr == addr);
-        delete_segment_at(i_middle);
-        deleted = True;
-
-        if (debug)
-           VG_(printf)("  case 4: subrange %p-%p deleted\n",
-                       addr, addr+len);
-      }
+   if (!VG_IS_PAGE_ALIGNED(start))
+      goto eINVAL;
 
-      /* If we deleted this segment (or any above), those above will
-         have been moved down to fill in the hole in the segment
-         array.  In order that we don't miss them, we have to
-         re-consider this slot number; hence the i--. */
-      if (deleted)
-         i--;
+   if (len == 0) {
+      *need_discard = False;
+      return VG_(mk_SysRes_Success)( 0 );
    }
-   preen_segments();
-   if (0) VG_(show_segments)("unmap_range(AFTER)");
-}
-
-
-/* Add a binding of [addr,addr+len) to
-   (prot,flags,dev,ino,off,filename) in the segment array.
-   Delete/truncate any previous mapping(s) covering that range.
-*/
-void 
-VG_(map_file_segment)( Addr addr, SizeT len, 
-                       UInt prot, UInt flags, 
-                       UInt dev, UInt ino, ULong off, 
-                       const Char *filename)
-{
-   const Bool debug = False || mem_debug;
-   Segment* s;
-   Int      idx;
-   HChar*   stage2_suffix1 = "lib/valgrind/stage2";
-   HChar*   stage2_suffix2 = "coregrind/stage2";
-   Bool     is_stage2 = False;
-   
-   is_stage2 = is_stage2 || ( VG_(strstr)(filename, stage2_suffix1) != NULL );
-   is_stage2 = is_stage2 || ( VG_(strstr)(filename, stage2_suffix2) != NULL );
-
-   if (debug)
-      VG_(printf)(
-         "\n"
-         "map_file_segment(addr=%p len=%lu prot=0x%x flags=0x%x\n"
-         "                 dev=0x%4x ino=%d off=%lld\n"
-         "                 filename='%s')\n",
-         addr, len, prot, flags, dev, ino, off, filename);
 
-   if (0) VG_(show_segments)("before map_file_segment");
+   if (start + len < len)
+      goto eINVAL;
 
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(addr));
    len = VG_PGROUNDUP(len);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
 
-   /* Nuke/truncate any existing segment(s) covering [addr,addr+len) */
-   VG_(unmap_range)(addr, len);
-
-   /* and now install this one */
-   idx = create_segment(addr);
-   vg_assert(segments_used >= 0 && segments_used <= VG_N_SEGMENTS);
-   vg_assert(idx != -1);
-   vg_assert(idx >= 0 && idx < segments_used);
-
-   s = &segments[idx];
-   vg_assert(s->addr == addr);
-   s->prot     = prot;
-   s->flags    = flags;
-   s->len      = len;
-   s->offset   = off;
-   s->fnIdx    = filename==NULL ? -1 : allocate_segname(filename);
-   s->filename = s->fnIdx==-1 ? NULL : &segnames[s->fnIdx].fname[0];
-   s->dev      = dev;
-   s->ino      = ino;
-   s->seginfo  = NULL;
-
-   /* Clean up right now */
-   preen_segments();
-   if (0) VG_(show_segments)("after map_file_segment");
-
-   /* If this mapping is at the beginning of a file, isn't part of
-      Valgrind, is at least readable and seems to contain an object
-      file, then try reading symbols from it.
-
-      Getting this heuristic right is critical.  On x86-linux,
-      objects are typically mapped twice:
-
-      1b8fb000-1b8ff000 r-xp 00000000 08:02 4471477 vgpreload_memcheck.so
-      1b8ff000-1b900000 rw-p 00004000 08:02 4471477 vgpreload_memcheck.so
-
-      whereas ppc32-linux mysteriously does this:
-
-      118a6000-118ad000 r-xp 00000000 08:05 14209428 vgpreload_memcheck.so
-      118ad000-118b6000 ---p 00007000 08:05 14209428 vgpreload_memcheck.so
-      118b6000-118bd000 rwxp 00000000 08:05 14209428 vgpreload_memcheck.so
-
-      The third mapping should not be considered to have executable code in.
-      Therefore a test which works for both is: r and x and NOT w.  Reading
-      symbols from the rwx segment -- which overlaps the r-x segment in the
-      file -- causes the redirection mechanism to redirect to addresses in
-      that third segment, which is wrong and causes crashes.
-   */
-   if (s->seginfo == NULL
-       && ( (addr+len < VG_(valgrind_base) || addr > VG_(valgrind_last))
-            || is_stage2
-          )
-       && (flags & (SF_MMAP|SF_NOSYMS)) == SF_MMAP
-      ) {
-      if (off == 0
-         && s->fnIdx != -1
-         /* r, x are set */
-         && (prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == (VKI_PROT_READ|VKI_PROT_EXEC)
-         /* w is clear */
-         && (prot & VKI_PROT_WRITE) == 0
-         /* other checks .. */
-         && len >= VKI_PAGE_SIZE
-         && VG_(is_object_file)((void *)addr) ) {
-         s->seginfo = VG_(read_seg_symbols)(s->addr, s->len, s->offset,
-                                            s->filename);
-      }
-      else if (flags & SF_MMAP) 
-      {
-         const SegInfo *si;
-      
-         /* Otherwise see if an existing SegInfo applies to this Segment */
-         for (si = VG_(next_seginfo)(NULL);
-              si != NULL;
-              si = VG_(next_seginfo)(si)) 
-         {
-            if (VG_(seg_overlaps)(s, VG_(seginfo_start)(si), 
-                                     VG_(seginfo_size)(si)))
-            {
-               s->seginfo = (SegInfo *)si;
-               VG_(seginfo_incref)((SegInfo *)si);
-            }
-         }
-      }
+   if (forClient) {
+      if (!VG_(am_is_valid_for_client_or_free_or_resvn)
+            ( start, len, VKI_PROT_NONE ))
+         goto eINVAL;
+   } else {
+      if (!is_valid_for_valgrind( start, len ))
+         goto eINVAL;
    }
 
-   /* clean up */
-   preen_segments();
-}
-
-void VG_(map_fd_segment)(Addr addr, SizeT len, UInt prot, UInt flags, 
-                        Int fd, ULong off, const Char *filename)
-{
-   Char buf[VKI_PATH_MAX];
-   struct vki_stat st;
+   d = any_Ts_in_range( start, len );
 
-   st.st_dev = 0;
-   st.st_ino = 0;
+   sres = do_munmap_NO_NOTIFY( start, len );
+   if (sres.isError)
+      return sres;
 
-   if (fd != -1 && (flags & SF_FILE)) {
-      vg_assert((off & (VKI_PAGE_SIZE-1)) == 0);
+   VG_(am_notify_munmap)( start, len );
+   AM_SANITY_CHECK;
+   *need_discard = d;
+   return sres;
 
-      if (VG_(fstat)(fd, &st) < 0) {
-        flags &= ~SF_FILE;
-      } else {
-         // Note unusual mapping types
-         if (VKI_S_ISCHR(st.st_mode) || VKI_S_ISBLK(st.st_mode))
-            flags |= SF_DEVICE;
-      }
-   }
+  eINVAL:
+   return VG_(mk_SysRes_Error)( VKI_EINVAL );
+}
 
-   if ((flags & SF_FILE) && filename == NULL && fd != -1)
-      if (VG_(resolve_filename)(fd, buf, VKI_PATH_MAX))
-         filename = buf;
+/* Unmap the given address range and update the segment array
+   accordingly.  This fails if the range isn't valid for the client.
+   If *need_discard is True after a successful return, the caller
+   should immediately discard translations from the specified address
+   range. */
 
-   VG_(map_file_segment)(addr, len, prot, flags, 
-                         st.st_dev, st.st_ino, off, filename);
+SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
+                              Addr start, SizeT len )
+{
+   return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
 }
 
-void VG_(map_segment)(Addr addr, SizeT len, UInt prot, UInt flags)
-{
-   flags &= ~SF_FILE;
+/* Unmap the given address range and update the segment array
+   accordingly.  This fails if the range isn't valid for valgrind. */
 
-   VG_(map_file_segment)(addr, len, prot, flags, 0, 0, 0, 0);
+SysRes VG_(am_munmap_valgrind)( Addr start, SizeT len )
+{
+   Bool need_discard;
+   SysRes r = am_munmap_both_wrk( &need_discard, 
+                                  start, len, False/*valgrind*/ );
+   /* If this assertion fails, it means we allowed translations to be
+      made from a V-owned section.  Which shouldn't happen. */
+   if (!r.isError)
+      aspacem_assert(!need_discard);
+   return r;
 }
 
-/* set new protection flags on an address range */
-void VG_(mprotect_range)(Addr a, SizeT len, UInt prot)
+/* Let (start,len) denote an area within a single Valgrind-owned
+  segment (anon or file).  Change the ownership of [start, start+len)
+  to the client instead.  Fails if (start,len) does not denote a
+  suitable segment. */
+
+Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len )
 {
-   Int r;
-   const Bool debug = False || mem_debug;
+   Int i, iLo, iHi;
 
-   if (debug)
-      VG_(printf)("\nmprotect_range(%p, %lu, %x)\n", a, len, prot);
+   if (len == 0)
+      return True;
+   if (start + len < start)
+      return False;
+   if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
+      return False;
 
-   if (0) VG_(show_segments)( "mprotect_range(before)" );
+   i = find_nsegment_idx(start);
+   if (nsegments[i].kind != SkFileV && nsegments[i].kind != SkAnonV)
+      return False;
+   if (start+len-1 > nsegments[i].end)
+      return False;
 
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(a));
-   len = VG_PGROUNDUP(len);
+   aspacem_assert(start >= nsegments[i].start);
+   aspacem_assert(start+len-1 <= nsegments[i].end);
+
+   /* This scheme is like how mprotect works: split the to-be-changed
+      range into its own segment(s), then mess with them (it).  There
+      should be only one. */
+   split_nsegments_lo_and_hi( start, start+len-1, &iLo, &iHi );
+   aspacem_assert(iLo == iHi);
+   switch (nsegments[iLo].kind) {
+      case SkFileV: nsegments[iLo].kind = SkFileC; break;
+      case SkAnonV: nsegments[iLo].kind = SkAnonC; break;
+      default: aspacem_assert(0); /* can't happen - guarded above */
+   }
 
-   split_segment(a);
-   split_segment(a+len);
+   preen_nsegments();
+   return True;
+}
 
-   r = find_segment(a);
-   vg_assert(r != -1);
-   segments[r].prot = prot;
 
-   preen_segments();
+/* --- --- --- reservations --- --- --- */
 
-   if (0) VG_(show_segments)( "mprotect_range(after)");
-}
+/* Create a reservation from START .. START+LENGTH-1, with the given
+   ShrinkMode.  When checking whether the reservation can be created,
+   also ensure that at least abs(EXTRA) extra free bytes will remain
+   above (> 0) or below (< 0) the reservation.
 
+   The reservation will only be created if it, plus the extra-zone,
+   falls entirely within a single free segment.  The returned Bool
+   indicates whether the creation succeeded. */
 
-/* Try to find a map space for [addr,addr+len).  If addr==0, it means
-   the caller is prepared to accept a space at any location; if not,
-   we will try for addr, but fail if we can't get it.  This mimics
-   mmap fixed vs mmap not-fixed.
-*/
-Addr VG_(find_map_space)(Addr addr, SizeT len, Bool for_client)
-{
-   const Bool debug = False || mem_debug;
-   Addr ret;
-   Addr addrOrig = addr;
-   Addr limit = (for_client ? VG_(client_end)-1   : VG_(valgrind_last));
-   Addr base  = (for_client ? VG_(client_mapbase) : VG_(valgrind_base));
-   Addr hole_start, hole_end, hstart_any, hstart_fixed, hstart_final;
-   Int i, i_any, i_fixed, i_final;
-   SizeT hole_len;
-
-   Bool fixed;
-
-   if (debug) {
-      VG_(printf)("\n\n");
-      VG_(printf)("find_map_space(%p, %llu, %d) ...\n",
-                  addr, (ULong)len, for_client);
-   }
+Bool VG_(am_create_reservation) ( Addr start, SizeT length, 
+                                  ShrinkMode smode, SSizeT extra )
+{
+   Int      startI, endI;
+   NSegment seg;
 
-   if (0) VG_(show_segments)("find_map_space: start");
+   /* start and end, not taking into account the extra space. */
+   Addr start1 = start;
+   Addr end1   = start + length - 1;
 
-   if (addr == 0) {
-      fixed = False;
-   } else {
-      fixed = True;
-      /* leave space for redzone and still try to get the exact
-         address asked for */
-      addr -= VKI_PAGE_SIZE;
-   }
+   /* start and end, taking into account the extra space. */
+   Addr start2 = start1;
+   Addr end2   = end1;
 
-   /* Everything must be page-aligned */
-   vg_assert((addr & (VKI_PAGE_SIZE-1)) == 0);
-   len = VG_PGROUNDUP(len);
+   if (extra < 0) start2 += extra; // this moves it down :-)
+   if (extra > 0) end2 += extra;
 
-   len += VKI_PAGE_SIZE * 2; /* leave redzone gaps before and after mapping */
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start+length));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start2));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(end2+1));
 
-   /* Scan the segment list, looking for a hole which satisfies the
-      requirements.  At each point i we ask the question "can we use
-      the hole in between segments[i-1] and segments[i] ?" */
-   i_any = i_fixed = -1;
-   hstart_any = hstart_fixed = 0;
+   startI = find_nsegment_idx( start2 );
+   endI = find_nsegment_idx( end2 );
 
-   hole_start = hole_end = 0;
+   /* If the start and end points don't fall within the same (free)
+      segment, we're hosed.  This does rely on the assumption that all
+      mergeable adjacent segments can be merged, but add_segment()
+      should ensure that. */
+   if (startI != endI)
+      return False;
 
-   /* Iterate over all possible holes, generating them into
-      hole_start/hole_end.  Filter out invalid ones.  Then see if any
-      are usable; if so set i_fixed/i_any and hstart_fixed/hstart_any.  
-   */
-   for (i = 0; i <=/*yes,really*/ segments_used; i++) {
-      if (i == 0) {
-         hole_start = 0;
-         hole_end = segments[0].addr-1;
-      } 
-      else {
-         vg_assert(segments_used > 0);
-         if (i == segments_used) {
-            hole_start = segments[i-1].addr + segments[i-1].len;
-            hole_end = ~(Addr)0;
-         } else {
-            hole_start = segments[i-1].addr + segments[i-1].len;
-            hole_end = segments[i].addr - 1;
-         }
-      }
+   if (nsegments[startI].kind != SkFree)
+      return False;
 
-      vg_assert(hole_start <= hole_end || hole_start == hole_end+1);
+   /* Looks good - make the reservation. */
+   aspacem_assert(nsegments[startI].start <= start2);
+   aspacem_assert(end2 <= nsegments[startI].end);
 
-      /* ignore zero-sized holes */
-      if (hole_start == hole_end+1)
-         continue;
+   init_nsegment( &seg );
+   seg.kind  = SkResvn;
+   seg.start = start1;  /* NB: extra space is not included in the
+                           reservation. */
+   seg.end   = end1;
+   seg.smode = smode;
+   add_segment( &seg );
 
-      vg_assert(VG_IS_PAGE_ALIGNED(hole_start));
-      vg_assert(VG_IS_PAGE_ALIGNED(hole_end+1));
+   AM_SANITY_CHECK;
+   return True;
+}
 
-      /* ignore holes which fall outside the allowable area */
-      if (!(hole_start >= base && hole_end <= limit))
-         continue;
 
-      vg_assert(hole_end > hole_start);
-      hole_len = hole_end - hole_start + 1;
-      vg_assert(VG_IS_PAGE_ALIGNED(hole_len));
+/* Let SEG be an anonymous client mapping.  This fn extends the
+   mapping by DELTA bytes, taking the space from a reservation section
+   which must be adjacent.  If DELTA is positive, the segment is
+   extended forwards in the address space, and the reservation must be
+   the next one along.  If DELTA is negative, the segment is extended
+   backwards in the address space and the reservation must be the
+   previous one.  DELTA must be page aligned and must not exceed the
+   size of the reservation segment. */
 
-      if (hole_len >= len && i_any == -1) {
-         /* It will at least fit in this hole. */
-         i_any = i;
-         hstart_any = hole_start;
-      }
+Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg, 
+                                                       SSizeT    delta )
+{
+   Int    segA, segR;
+   UInt   prot;
+   SysRes sres;
 
-      if (fixed && hole_start <= addr 
-                && hole_start+hole_len >= addr+len) {
-         /* We were asked for a fixed mapping, and this hole works.
-            Bag it -- and stop searching as further searching is
-            pointless. */
-         i_fixed = i;
-         hstart_fixed = addr;
-         break;
+   /* Find the segment array index for SEG.  If the assertion fails it
+      probably means you passed in a bogus SEG. */
+   segA = segAddr_to_index( seg );
+   aspacem_assert(segA >= 0 && segA < nsegments_used);
+
+   if (nsegments[segA].kind != SkAnonC)
+      return False;
+
+   if (delta == 0)
+      return True;
+
+   prot =   (nsegments[segA].hasR ? VKI_PROT_READ : 0)
+          | (nsegments[segA].hasW ? VKI_PROT_WRITE : 0)
+          | (nsegments[segA].hasX ? VKI_PROT_EXEC : 0);
+
+   aspacem_assert(VG_IS_PAGE_ALIGNED(delta<0 ? -delta : delta));
+
+   if (delta > 0) {
+
+      /* Extending the segment forwards. */
+      segR = segA+1;
+      if (segR >= nsegments_used
+          || nsegments[segR].kind != SkResvn
+          || nsegments[segR].smode != SmLower
+          || nsegments[segR].start != nsegments[segA].end + 1
+          || delta > (nsegments[segR].end - nsegments[segR].start + 1))
+        return False;
+        
+      /* Extend the kernel's mapping. */
+      sres = VG_(am_do_mmap_NO_NOTIFY)( 
+                nsegments[segR].start, delta,
+                prot,
+                VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+                0, 0 
+             );
+      if (sres.isError)
+         return False; /* kernel bug if this happens? */
+      if (sres.val != nsegments[segR].start) {
+         /* kernel bug if this happens? */
+        (void)do_munmap_NO_NOTIFY( sres.val, delta );
+        return False;
       }
-   }
 
-   /* Summarise the final decision into i_final/hstart_final. */
-   i_final = -1;
-   hstart_final = 0;
+      /* Ok, success with the kernel.  Update our structures. */
+      nsegments[segR].start += delta;
+      nsegments[segA].end += delta;
+      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
 
-   if (fixed) {
-      i_final = i_fixed;
-      hstart_final = hstart_fixed + VKI_PAGE_SIZE;  /* skip leading redzone */
    } else {
-      i_final = i_any;
-      hstart_final = hstart_any;
-   }
 
+      /* Extending the segment backwards. */
+      delta = -delta;
+      aspacem_assert(delta > 0);
+
+      segR = segA-1;
+      if (segR < 0
+          || nsegments[segR].kind != SkResvn
+          || nsegments[segR].smode != SmUpper
+          || nsegments[segR].end + 1 != nsegments[segA].start
+          || delta > (nsegments[segR].end - nsegments[segR].start + 1))
+        return False;
+        
+      /* Extend the kernel's mapping. */
+      sres = VG_(am_do_mmap_NO_NOTIFY)( 
+                nsegments[segA].start-delta, delta,
+                prot,
+                VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+                0, 0 
+             );
+      if (sres.isError)
+         return False; /* kernel bug if this happens? */
+      if (sres.val != nsegments[segA].start-delta) {
+         /* kernel bug if this happens? */
+        (void)do_munmap_NO_NOTIFY( sres.val, delta );
+        return False;
+      }
 
-   if (i_final != -1)
-      ret = hstart_final;
-   else
-      ret = 0; /* not found */
-
-   if (debug)
-      VG_(printf)("find_map_space(%p, %llu, %d) -> %p\n\n",
-                  addr, (ULong)len, for_client, ret);
+      /* Ok, success with the kernel.  Update our structures. */
+      nsegments[segR].end -= delta;
+      nsegments[segA].start -= delta;
+      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
 
-   if (fixed) {
-      vg_assert(ret == 0 || ret == addrOrig);
    }
 
-   return ret;
+   AM_SANITY_CHECK;
+   return True;
 }
 
 
-/* Pad the entire process address space, from "start"
-   to VG_(valgrind_last) by creating an anonymous and inaccessible
-   mapping over any part of the address space which is not covered
-   by an entry in the segment list.
+/* --- --- --- resizing/move a mapping --- --- --- */
 
-   This is designed for use around system calls which allocate
-   memory in the process address space without providing a way to
-   control its location such as io_setup. By choosing a suitable
-   address with VG_(find_map_space) and then adding a segment for
-   it and padding the address space valgrind can ensure that the
-   kernel has no choice but to put the memory where we want it. */
-void VG_(pad_address_space)(Addr start)
-{
-   Addr     addr = (start == 0) ? VG_(client_base) : start;
-   SysRes   ret;
+/* Let SEG be a client mapping (anonymous or file).  This fn extends
+   the mapping forwards only by DELTA bytes, and trashes whatever was
+   in the new area.  Fails if SEG is not a single client mapping or if
+   the new area is not accessible to the client.  Fails if DELTA is
+   not page aligned.  *seg is invalid after a successful return.  If
+   *need_discard is True after a successful return, the caller should
+   immediately discard translations from the new area. */
 
-   Int      i = 0;
-   Segment* s = i >= segments_used ? NULL : &segments[i];
-   
-   while (s && addr <= VG_(valgrind_last)) {
-      if (addr < s->addr) {
-         ret = VG_(mmap_native)((void*)addr, s->addr - addr, 0,
-                     VKI_MAP_FIXED | VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS,
-                     -1, 0);
-         vg_assert(!ret.isError);
-      }
-      addr = s->addr + s->len;
-      i++;
-      s = i >= segments_used ? NULL : &segments[i];
-   }
+Bool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard,
+                                NSegment* seg, SizeT delta )
+{
+   Addr     xStart;
+   SysRes   sres;
+   NSegment seg_copy = *seg;
+   SizeT    seg_old_len = seg->end + 1 - seg->start;
 
-   if (addr <= VG_(valgrind_last)) {
-      ret = VG_(mmap_native)((void*)addr, VG_(valgrind_last) - addr + 1, 0,
-                  VKI_MAP_FIXED | VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS,
-                  -1, 0);
-      vg_assert(!ret.isError);
-   }
-}
+   if (seg->kind != SkFileC && seg->kind != SkAnonC)
+      return False;
 
-/* Remove the address space padding added by VG_(pad_address_space)
-   by removing any mappings that it created. */
-void VG_(unpad_address_space)(Addr start)
-{
-   Addr     addr = (start == 0) ? VG_(client_base) : start;
-   SysRes   ret;
+   if (delta == 0 || !VG_IS_PAGE_ALIGNED(delta)) 
+      return False;
 
-   Int      i = 0;
-   Segment* s = i >= segments_used ? NULL : &segments[i];
+   xStart = seg->end+1;
+   if (xStart + delta < delta)
+      return False;
 
-   while (s && addr <= VG_(valgrind_last)) {
-      if (addr < s->addr) {
-         //ret = VG_(do_syscall2)(__NR_munmap, addr, s->addr - addr);
-         ret = VG_(do_syscall2)(__NR_munmap, addr, s->addr - addr);
-      }
-      addr = s->addr + s->len;
-      i++;
-      s = i >= segments_used ? NULL : &segments[i];
-   }
+   if (!VG_(am_is_valid_for_client_or_free_or_resvn)( xStart, delta, 
+                                                      VKI_PROT_NONE ))
+      return False;
 
-   if (addr <= VG_(valgrind_last)) {
-      ret = VG_(do_syscall2)(__NR_munmap, addr, 
-                             (VG_(valgrind_last) - addr) + 1);
+   AM_SANITY_CHECK;
+   sres = do_extend_mapping_NO_NOTIFY( seg->start, 
+                                       seg_old_len,
+                                       seg_old_len + delta );
+   if (sres.isError) {
+      AM_SANITY_CHECK;
+      return False;
    }
-}
 
-/* Find the segment holding 'a', or NULL if none. */
-Segment *VG_(find_segment)(Addr a)
-{
-  Int r = find_segment(a);
-  if (0) VG_(show_segments)("find_segment");
-  if (r == -1) return NULL;
-  return &segments[r];
-}
+   *need_discard = any_Ts_in_range( seg_copy.end+1, delta );
 
-/* Assumes that 'a' is not in any segment.  Finds the lowest-addressed
-   segment above 'a', or NULL if none.  Passing 'a' which is in fact in
-   a segment is a checked error.
-*/
-Segment *VG_(find_segment_above_unmapped)(Addr a)
-{
-  Int r = find_segment_above_unmapped(a);
-  if (0) VG_(show_segments)("find_segment_above_unmapped");
-  if (r == -1) return NULL;
-  return &segments[r];
-}
+   seg_copy.end += delta;
+   add_segment( &seg_copy );
 
-/* Assumes that 'a' is in some segment.  Finds the next segment along,
-   or NULL if none.  Passing 'a' which is in fact not in a segment is
-   a checked error.
-*/
-Segment *VG_(find_segment_above_mapped)(Addr a)
-{
-  Int r = find_segment_above_mapped(a);
-  if (0) VG_(show_segments)("find_segment_above_mapped");
-  if (r == -1) return NULL;
-  return &segments[r];
+   AM_SANITY_CHECK;
+   return True;
 }
 
 
-/* 
-   Test if a piece of memory is addressable with at least the "prot"
-   protection permissions by examining the underlying segments.
+/* Remap the old address range to the new address range.  Fails if any
+   parameter is not page aligned, if the either size is zero, if any
+   wraparound is implied, if the old address range does not fall
+   entirely within a single segment, if the new address range overlaps
+   with the old one, or if the old address range is not a valid client
+   mapping.  If *need_discard is True after a successful return, the
+   caller should immediately discard translations from both specified
+   address ranges.  */
 
-   Really this is a very stupid algorithm and we could do much
-   better by iterating through the segment array instead of through
-   the address space.
- */
-Bool VG_(is_addressable)(Addr p, SizeT size, UInt prot)
+Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
+                                        Addr old_addr, SizeT old_len,
+                                        Addr new_addr, SizeT new_len )
 {
-   Segment *seg;
+   Int      iLo, iHi;
+   SysRes   sres;
+   NSegment seg, oldseg;
 
-   if ((p + size) < p)
-      return False; /* reject wraparounds */
-   if (size == 0)
-      return True; /* isn't this a bit of a strange case? */
+   if (old_len == 0 || new_len == 0)
+      return False;
 
-   p    = VG_PGROUNDDN(p);
-   size = VG_PGROUNDUP(size);
-   vg_assert(VG_IS_PAGE_ALIGNED(p));
-   vg_assert(VG_IS_PAGE_ALIGNED(size));
+   if (!VG_IS_PAGE_ALIGNED(old_addr) || !VG_IS_PAGE_ALIGNED(old_len)
+       || !VG_IS_PAGE_ALIGNED(new_addr) || !VG_IS_PAGE_ALIGNED(new_len))
+      return False;
 
-   for (; size > 0; size -= VKI_PAGE_SIZE) {
-      seg = VG_(find_segment)(p);
-      if (!seg)
-         return False;
-      if ((seg->prot & prot) != prot)
-         return False;
-      p += VKI_PAGE_SIZE;
-   }
+   if (old_addr + old_len < old_addr
+       || new_addr + new_len < new_addr)
+      return False;
 
-   return True;
-}
+   if (old_addr + old_len - 1 < new_addr
+       || new_addr + new_len - 1 < old_addr) {
+      /* no overlap */
+   } else
+      return False;
 
+   iLo = find_nsegment_idx( old_addr );
+   iHi = find_nsegment_idx( old_addr + old_len - 1 );
+   if (iLo != iHi)
+      return False;
 
-/*--------------------------------------------------------------------*/
-/*--- Random function that doesn't really belong here              ---*/
-/*--------------------------------------------------------------------*/
+   if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC)
+      return False;
 
-/* We'll call any RW mmaped memory segment, within the client address
-   range, which isn't SF_CORE, a root. 
-*/
-void VG_(find_root_memory)(void (*add_rootrange)(Addr a, SizeT sz))
-{
-   Int     i;
-   UInt    flags;
-   Segment *s;
+   sres = do_relocate_nooverlap_mapping_NO_NOTIFY( old_addr, old_len, 
+                                                   new_addr, new_len );
+   if (sres.isError) {
+      AM_SANITY_CHECK;
+      return False;
+   }
 
-   for (i = 0; i < segments_used; i++) {
-      s = &segments[i];
-      // Note that, for example, we don't want to touch a device page.
-      flags = s->flags & (SF_SHARED|SF_MMAP|SF_VALGRIND|SF_CORE|SF_STACK|SF_DEVICE);
-      if (flags != SF_MMAP && flags != SF_STACK && flags != (SF_MMAP|SF_STACK))
-         continue;
-      if ((s->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) 
-          != (VKI_PROT_READ|VKI_PROT_WRITE))
-         continue;
-      if (!VG_(is_client_addr)(s->addr) ||
-          !VG_(is_client_addr)(s->addr+s->len-1))
-         continue;
+   *need_discard = any_Ts_in_range( old_addr, old_len )
+                   || any_Ts_in_range( new_addr, new_len );
 
-      (*add_rootrange)(s->addr, s->len);
-   }
-}
+   oldseg = nsegments[iLo];
 
+   /* Create a free hole in the old location. */
+   init_nsegment( &seg );
+   seg.kind  = SkFree;
+   seg.start = old_addr;
+   seg.end   = old_addr + old_len - 1;
+   add_segment( &seg );
 
-/*--------------------------------------------------------------------*/
-/*--- Querying memory layout                                       ---*/
-/*--------------------------------------------------------------------*/
+   /* Mark the new area based on the old seg. */
+   if (oldseg.kind == SkFileC) {
+      oldseg.offset += ((ULong)old_addr) - ((ULong)oldseg.start);
+   } else {
+      aspacem_assert(oldseg.kind == SkAnonC);
+      aspacem_assert(oldseg.offset == 0);
+   }
+   oldseg.start = new_addr;
+   oldseg.end   = new_addr + new_len - 1;
+   add_segment( &oldseg );
 
-Bool VG_(is_client_addr)(Addr a)
-{
-   return a >= VG_(client_base) && a < VG_(client_end);
+   AM_SANITY_CHECK;
+   return True;
 }
 
-Bool VG_(is_shadow_addr)(Addr a)
-{
-   return a >= VG_(shadow_base) && a < VG_(shadow_end);
-}
 
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Manage stacks for Valgrind itself.                        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
 
-/*--------------------------------------------------------------------*/
-/*--- Handling shadow memory                                       ---*/
-/*--------------------------------------------------------------------*/
+/* Allocate and initialise a VgStack (anonymous client space).
+   Protect the stack active area and the guard areas appropriately.
+   Returns NULL on failure, else the address of the bottom of the
+   stack.  On success, also sets *initial_sp to what the stack pointer
+   should be set to. */
 
-void *VG_(shadow_alloc)(UInt size)
+VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
 {
-   static Addr shadow_alloc = 0;
-   Addr try_here;
-   SysRes r;
+   Int      szB;
+   SysRes   sres;
+   VgStack* stack;
+   UInt*    p;
+   Int      i;
 
-   if (0) VG_(show_segments)("shadow_alloc(before)");
+   /* Allocate the stack. */
+   szB = VG_STACK_GUARD_SZB 
+         + VG_STACK_ACTIVE_SZB + VG_STACK_GUARD_SZB;
 
-   vg_assert(VG_(needs).shadow_memory);
+   sres = VG_(am_mmap_anon_float_valgrind)( szB );
+   if (sres.isError)
+      return NULL;
 
-   size = VG_PGROUNDUP(size);
+   stack = (VgStack*)sres.val;
 
-   if (shadow_alloc == 0)
-      shadow_alloc = VG_(shadow_base);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(szB));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(stack));
+   
+   /* Protect the guard areas. */
+   sres = do_mprotect_NO_NOTIFY( 
+             (Addr) &stack[0], 
+             VG_STACK_GUARD_SZB, VKI_PROT_NONE 
+          );
+   if (sres.isError) goto protect_failed;
+   VG_(am_notify_mprotect)( 
+      (Addr) &stack->bytes[0], 
+      VG_STACK_GUARD_SZB, VKI_PROT_NONE 
+   );
+
+   sres = do_mprotect_NO_NOTIFY( 
+             (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB], 
+             VG_STACK_GUARD_SZB, VKI_PROT_NONE 
+          );
+   if (sres.isError) goto protect_failed;
+   VG_(am_notify_mprotect)( 
+      (Addr) &stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB],
+      VG_STACK_GUARD_SZB, VKI_PROT_NONE 
+   );
+
+   /* Looks good.  Fill the active area with junk so we can later
+      tell how much got used. */
+
+   p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
+   for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++)
+      p[i] = 0xDEADBEEF;
+
+   *initial_sp = (Addr)&stack->bytes[VG_STACK_GUARD_SZB + VG_STACK_ACTIVE_SZB];
+   *initial_sp -= 8;
+   *initial_sp &= ~((Addr)0xF);
+
+   VG_(debugLog)( 1,"aspacem","allocated thread stack at 0x%llx size %d\n",
+                  (ULong)(Addr)stack, szB);
+   AM_SANITY_CHECK;
+   return stack;
+
+  protect_failed:
+   /* The stack was allocated, but we can't protect it.  Unmap it and
+      return NULL (failure). */
+   (void)do_munmap_NO_NOTIFY( (Addr)stack, szB );
+   AM_SANITY_CHECK;
+   return NULL;
+}
 
-   if (shadow_alloc >= VG_(shadow_end))
-      goto failed;
 
-   try_here = shadow_alloc;
-   vg_assert(VG_IS_PAGE_ALIGNED(try_here));
-   vg_assert(VG_IS_PAGE_ALIGNED(size));
-   vg_assert(size > 0);
+/* Figure out how many bytes of the stack's active area have not
+   been used.  Used for estimating if we are close to overflowing it. */
 
-   if (0)
-      VG_(printf)("shadow_alloc: size %d, trying at %p\n", size, (void*)try_here);
-
-   /* this is big-bang allocated, so we don't expect to find a listed
-      segment for it. */
-   /* This is really an absolute disgrace.  Sometimes the big-bang
-      mapping is in the list (due to re-reads of /proc/self/maps,
-      presumably) and sometimes it isn't. */
-#if 0
-   r = find_segment(try_here);
-   vg_assert(r == -1);
-   r = find_segment(try_here+size-1);
-   vg_assert(r == -1);
-#endif
-
-   r = VG_(mprotect_native)( (void*)try_here, 
-                             size,  VKI_PROT_READ|VKI_PROT_WRITE );
-
-   if (r.isError)
-      goto failed;
-
-   shadow_alloc += size;
-   return (void*)try_here;
-
-  failed:
-   VG_(printf)(
-       "valgrind: Could not allocate address space (0x%x bytes)\n"
-       "valgrind:   for shadow memory chunk.\n",
-       size
-      ); 
-   VG_(exit)(1);
-}
-
-/*------------------------------------------------------------*/
-/*--- pointercheck                                         ---*/
-/*------------------------------------------------------------*/
-
-Bool VG_(setup_pointercheck)(Addr client_base, Addr client_end)
-{
-   vg_assert(0 != client_end);
-#if defined(VGP_x86_linux)
-   /* Client address space segment limit descriptor entry */
-   #define POINTERCHECK_SEGIDX  1
-
-   vki_modify_ldt_t ldt = { 
-      POINTERCHECK_SEGIDX,       // entry_number
-      client_base,               // base_addr
-      (client_end - client_base) / VKI_PAGE_SIZE, // limit
-      1,                         // seg_32bit
-      0,                         // contents: data, RW, non-expanding
-      0,                         // ! read_exec_only
-      1,                         // limit_in_pages
-      0,                         // ! seg not present
-      1,                         // useable
-   };
-   SysRes ret = VG_(do_syscall3)(__NR_modify_ldt, 1, (UWord)&ldt, sizeof(ldt));
-   if (ret.isError) {
-      VG_(message)(Vg_UserMsg,
-                   "Warning: ignoring --pointercheck=yes, "
-                   "because modify_ldt failed (errno=%d)", ret.val);
-      return False;
-   } else {
-      return True;
-   }
-#elif defined(VGP_amd64_linux)
-   if (0) 
-      VG_(message)(Vg_DebugMsg, "ignoring --pointercheck (unimplemented)");
-   return True;
-#elif defined(VGP_ppc32_linux)
-   if (0) 
-      VG_(message)(Vg_DebugMsg, "ignoring --pointercheck (unimplemented)");
-   return True;
-#else
-#  error Unknown architecture
-#endif
+Int VG_(am_get_VgStack_unused_szB)( VgStack* stack )
+{
+   Int i;
+   UInt* p;
+
+   p = (UInt*)&stack->bytes[VG_STACK_GUARD_SZB];
+   for (i = 0; i < VG_STACK_ACTIVE_SZB/sizeof(UInt); i++)
+      if (p[i] != 0xDEADBEEF)
+         break;
+
+   return i * sizeof(UInt);
 }
 
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
index 67373c8832798430911b867b4e62d709303642a4..559e9077e1348ef370cbbc3f36943057d48c1986 100644 (file)
 */
 
 #include "pub_core_basics.h"
-#include "pub_core_debuginfo.h"  // Needed for pub_core_aspacemgr :(
+#include "pub_core_debuglog.h"
 #include "pub_core_aspacemgr.h"
-#include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
-#include "pub_core_libcprint.h"
 
 /* Size of a smallish table used to read /proc/self/map entries. */
 #define M_PROCMAP_BUF 50000
@@ -46,6 +44,9 @@ static Char procmap_buf[M_PROCMAP_BUF];
 /* Records length of /proc/self/maps read into procmap_buf. */
 static Int  buf_n_tot;
 
+/* Minimum and maximum addresses */
+#define Addr_MIN ((Addr)0)
+#define Addr_MAX ((Addr)(-1ULL))
 
 /* Helper fns. */
 
@@ -104,7 +105,7 @@ static void read_procselfmaps ( void )
    /* Read the initial memory mapping from the /proc filesystem. */
    fd = VG_(open) ( "/proc/self/maps", VKI_O_RDONLY, 0 );
    if (fd.isError) {
-      VG_(message)(Vg_UserMsg, "FATAL: can't open /proc/self/maps");
+      VG_(debugLog)(0, "Valgrind:", "FATAL: can't open /proc/self/maps\n");
       VG_(exit)(1);
    }
    buf_n_tot = 0;
@@ -115,13 +116,13 @@ static void read_procselfmaps ( void )
    } while ( n_chunk > 0 && buf_n_tot < M_PROCMAP_BUF );
    VG_(close)(fd.val);
    if (buf_n_tot >= M_PROCMAP_BUF-5) {
-      VG_(message)(Vg_UserMsg, "FATAL: M_PROCMAP_BUF is too small; "
-                               "increase it and recompile");
-       VG_(exit)(1);
+      VG_(debugLog)(0, "Valgrind:", "FATAL: M_PROCMAP_BUF is too small;\n");
+      VG_(debugLog)(0, "Valgrind:", "       increase it and recompile.\n");
+      VG_(exit)(1);
    }
    if (buf_n_tot == 0) {
-      VG_(message)(Vg_UserMsg, "FATAL: I/O error on /proc/self/maps" );
-       VG_(exit)(1);
+      VG_(debugLog)(0, "Valgrind:", "FATAL: I/O error on /proc/self/maps\n");
+      VG_(exit)(1);
    }
    procmap_buf[buf_n_tot] = 0;
 }
@@ -150,11 +151,12 @@ static void read_procselfmaps ( void )
 */
 void VG_(parse_procselfmaps) (
    void (*record_mapping)( Addr addr, SizeT len, UInt prot,
-                          UInt dev, UInt ino, ULong foff, const UChar* filename )
+                          UInt dev, UInt ino, ULong foff, const UChar* filename ),
+   void (*record_gap)( Addr addr, SizeT len )
    )
 {
    Int    i, j, i_eol;
-   Addr   start, endPlusOne;
+   Addr   start, endPlusOne, gapStart;
    UChar* filename;
    UChar  rr, ww, xx, pp, ch, tmp;
    UInt          ino, prot;
@@ -165,10 +167,11 @@ void VG_(parse_procselfmaps) (
    tl_assert( '\0' != procmap_buf[0] && 0 != buf_n_tot);
 
    if (0)
-      VG_(message)(Vg_DebugMsg, "raw:\n%s", procmap_buf );
+      VG_(debugLog)(0, "procselfmaps", "raw:\n%s\n", procmap_buf);
 
    /* Ok, it's safely aboard.  Parse the entries. */
    i = 0;
+   gapStart = Addr_MIN;
    while (True) {
       if (i >= buf_n_tot) break;
 
@@ -219,11 +222,20 @@ void VG_(parse_procselfmaps) (
       goto read_line_ok;
 
     syntaxerror:
-      VG_(message)(Vg_UserMsg, "FATAL: syntax error reading /proc/self/maps");
-      { Int k;
-        VG_(printf)("last 50 chars: '");
-        for (k = i-50; k <= i; k++) VG_(printf)("%c", procmap_buf[k]);
-        VG_(printf)("'\n");
+      VG_(debugLog)(0, "Valgrind:", 
+                       "FATAL: syntax error reading /proc/self/maps\n");
+      { Int k, m;
+        HChar buf50[51];
+        m = 0;
+        buf50[m] = 0;
+        k = i - 50;
+        if (k < 0) k = 0;
+        for (; k <= i; k++) {
+           buf50[m] = procmap_buf[k];
+           buf50[m+1] = 0;
+           if (m < 50-1) m++;
+        }
+        VG_(debugLog)(0, "procselfmaps", "Last 50 chars: '%s'\n", buf50);
       }
       VG_(exit)(1);
 
@@ -258,7 +270,9 @@ void VG_(parse_procselfmaps) (
       if (ww == 'w') prot |= VKI_PROT_WRITE;
       if (xx == 'x') prot |= VKI_PROT_EXEC;
 
-      //if (start < VG_(valgrind_last))
+      if (record_gap && gapStart < start)
+         (*record_gap) ( gapStart, start-gapStart );
+
       (*record_mapping) ( start, endPlusOne-start, 
                           prot, maj * 256 + min, ino,
                           foffset, filename );
@@ -268,7 +282,11 @@ void VG_(parse_procselfmaps) (
       }
 
       i = i_eol + 1;
+      gapStart = endPlusOne;
    }
+
+   if (record_gap && gapStart < Addr_MAX)
+      (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
 }
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_clientstate.c b/coregrind/m_clientstate.c
new file mode 100644 (file)
index 0000000..6043053
--- /dev/null
@@ -0,0 +1,89 @@
+
+/*--------------------------------------------------------------------*/
+/*--- A home for miscellaneous bits of information which pertain   ---*/
+/*--- to the client's state.                                       ---*/
+/*---                                              m_clientstate.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 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.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_clientstate.h"
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Basic globals about the address space.                    ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Client address space, lowest to highest (see top of ume.c) */
+// TODO: get rid of as many of these as possible.
+
+Addr  VG_(client_base) = 0;       /* client address space limits */
+Addr  VG_(client_end)  = 0;
+
+Addr  VG_(clstk_base)  = 0;
+Addr  VG_(clstk_end)   = 0;
+UWord VG_(clstk_id)    = 0;
+
+Addr  VG_(brk_base)    = 0;       /* start of brk */
+Addr  VG_(brk_limit)   = 0;       /* current brk */
+
+/* A fd which refers to the client executable. */
+Int VG_(cl_exec_fd) = -1;
+
+/* A fd which refers to the fake /proc/<pid>/cmdline in /tmp. */
+Int VG_(cl_cmdline_fd) = -1;
+
+// Command line pieces, after they have been extracted from argv in
+// m_main.main().  The payload vectors are allocated in VG_AR_TOOL
+// (the default arena).  They are never freed.
+
+/* Args for the client. */
+XArrayStrings VG_(args_for_client) = {0,0,NULL};
+
+/* Args for V (augments, then those from the launcher). */
+XArrayStrings VG_(args_for_valgrind) = {0,0,NULL};
+
+/* How many of the above not to pass on at execve time? */
+Int VG_(args_for_valgrind_noexecpass) = 0;
+
+/* The name of the client executable, as specified on the command
+   line. */
+HChar* VG_(args_the_exename) = NULL;
+
+// Client's original rlimit data and rlimit stack
+struct vki_rlimit VG_(client_rlimit_data);
+struct vki_rlimit VG_(client_rlimit_stack);
+
+// Name of the launcher, as extracted from VALGRIND_LAUNCHER at
+// startup.
+HChar* VG_(name_of_launcher) = NULL;
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_commandline.c b/coregrind/m_commandline.c
new file mode 100644 (file)
index 0000000..d8e011e
--- /dev/null
@@ -0,0 +1,232 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Command line handling.                       m_commandline.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 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.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_commandline.h"
+
+
+/* Add a string to an expandable array of strings. */
+
+static void add_string ( XArrayStrings* xa, HChar* str )
+{
+   Int     i;
+   HChar** strs2;
+   vg_assert(xa->used >= 0);
+   vg_assert(xa->size >= 0);
+   vg_assert(xa->used <= xa->size);
+   if (xa->strs == NULL) vg_assert(xa->size == 0);
+
+   if (xa->used == xa->size) {
+      xa->size = xa->size==0 ? 2 : 2*xa->size;
+      strs2 = VG_(malloc)( xa->size * sizeof(HChar*) );
+      for (i = 0; i < xa->used; i++)
+         strs2[i] = xa->strs[i];
+      if (xa->strs) 
+         VG_(free)(xa->strs);
+      xa->strs = strs2;
+   }
+   vg_assert(xa->used < xa->size);
+   xa->strs[xa->used++] = str;
+}
+
+
+/* Read the contents of .valgrindrc in 'dir' into malloc'd memory. */
+// Note that we deliberately don't free the malloc'd memory.  See
+// comment at call site.
+
+static HChar* read_dot_valgrindrc ( HChar* dir )
+{
+   Int    n;
+   SysRes fd;
+   Int    size;
+   HChar* f_clo = NULL;
+   HChar  filename[VKI_PATH_MAX];
+
+   VG_(snprintf)(filename, VKI_PATH_MAX, "%s/.valgrindrc", 
+                           ( NULL == dir ? "" : dir ) );
+   fd = VG_(open)(filename, 0, VKI_S_IRUSR);
+   if ( !fd.isError ) {
+      size = VG_(fsize)(fd.val);
+      if (size > 0) {
+         f_clo = VG_(malloc)(size+1);
+         vg_assert(f_clo);
+         n = VG_(read)(fd.val, f_clo, size);
+         if (n == -1) n = 0;
+         vg_assert(n >= 0 && n <= size+1);
+         f_clo[n] = '\0';
+      }
+      VG_(close)(fd.val);
+   }
+   return f_clo;
+}
+
+
+// Add args from a string into VG_(args_for_valgrind), splitting the
+// string at whitespace and adding each component as a separate arg.
+
+static void add_args_from_string ( HChar* s )
+{
+   HChar* tmp;
+   HChar* cp = s;
+   vg_assert(cp);
+   while (True) {
+      // We have alternating sequences: blanks, non-blanks, blanks...
+      // copy the non-blanks sequences, and add terminating '\0'
+      while (VG_(isspace)(*cp)) cp++;
+      if (*cp == 0) break;
+      tmp = cp;
+      while ( !VG_(isspace)(*cp) && *cp != 0 ) cp++;
+      if ( *cp != 0 ) *cp++ = '\0';       // terminate if not the last
+      add_string( &VG_(args_for_valgrind), tmp );
+   }
+}
+
+
+/* Split up the args presented by the launcher to m_main.main(), and
+   park them in VG_(args_for_client) and VG_(args_for_valgrind).
+
+   The resulting arg list is the concatenation of the following:
+   - contents of ~/.valgrindrc
+   - contents of $VALGRIND_OPTS
+   - contents of ./.valgrindrc
+   - args from the command line
+   in the stated order.
+
+   VG_(args_for_valgrind_noexecpass) is set to be the number of items
+   in the first three categories.  They are not passed to child invokations
+   at exec, whereas the last group is.
+
+   If the last group contains --command-line-only=yes, then the 
+   first three groups are left empty.
+
+   Scheme: first examine the last group (the supplied argc/argv).
+   It should look like this.
+
+      args-for-v  exe_name  args-for-c
+
+   args-for-v are taken until either they don't start with '-' or
+   a "--" is seen.
+
+   The exe name and args-for-c are recorded without further ado.
+   Note that args-for-c[0] is the first real arg for the client, not
+   its executable name.
+
+   args-for-v are then copied into tmp_xarray.
+
+   if args-for-v does not include --command-line-only=yes:
+      contents of ~/.valgrindrc, $VALGRIND_OPTS and ./.valgrindrc
+      are copied into VG_(args_for_valgrind).
+   else
+      VG_(args_for_valgrind) is made empty.
+
+   Finally, tmp_xarray is copied onto the end of VG_(args_for_valgrind).
+*/
+
+void VG_(split_up_argv)( Int argc, HChar** argv )
+{
+          Int  i;
+          Bool augment = True;
+   static Bool already_called = False;
+
+   XArrayStrings tmp_xarray = {0,0,NULL};
+
+   /* This function should be called once, at startup, and then never
+      again. */
+   vg_assert(!already_called);
+   already_called = True;
+
+   /* Collect up the args-for-V. */
+   i = 1; /* skip the exe (stage2) name. */
+   for (; i < argc; i++) {
+      vg_assert(argv[i]);
+      if (0 == VG_(strcmp)(argv[i], "--")) {
+         i++;
+         break;
+      }
+      if (0 == VG_(strcmp)(argv[i], "--command-line-only=yes"))
+         augment = False;
+      if (argv[i][0] != '-')
+       break;
+      add_string( &tmp_xarray, argv[i] );
+   }
+
+   /* Should now be looking at the exe name. */
+   if (i < argc) {
+      vg_assert(argv[i]);
+      VG_(args_the_exename) = argv[i];
+      i++;
+   }
+
+   /* The rest are args for the client. */
+   for (; i < argc; i++) {
+      vg_assert(argv[i]);
+      add_string( &VG_(args_for_client), argv[i] );
+   }
+
+   VG_(args_for_valgrind).size = 0;
+   VG_(args_for_valgrind).used = 0;
+   VG_(args_for_valgrind).strs = NULL;
+
+   /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and
+      ./.valgrindrc into VG_(args_for_valgrind). */
+   if (augment) {
+      // read_dot_valgrindrc() allocates the return value with
+      // VG_(malloc)().  We do not free f1_clo and f2_clo as they get
+      // put into VG_(args_for_valgrind) and so must persist.
+      HChar* f1_clo  = read_dot_valgrindrc( VG_(getenv)("HOME") );
+      HChar* env_clo = VG_(strdup)( VG_(getenv)(VALGRIND_OPTS) );
+      HChar* f2_clo  = read_dot_valgrindrc(".");
+
+      if (f1_clo)  add_args_from_string( f1_clo );
+      if (env_clo) add_args_from_string( env_clo );
+      if (f2_clo)  add_args_from_string( f2_clo );
+   }
+
+   /* .. and record how many extras we got. */
+   VG_(args_for_valgrind_noexecpass) = VG_(args_for_valgrind).used;
+
+   /* Finally, copy tmp_xarray onto the end. */
+   for (i = 0; i < tmp_xarray.used; i++)
+      add_string( &VG_(args_for_valgrind), tmp_xarray.strs[i] );
+
+   if (tmp_xarray.strs)
+      VG_(free)(tmp_xarray.strs);
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
index 9c4bf2d073f5ddc80cff794c8c489b37738edd00..96307712c09c8b885e12962ff90453f6301005eb 100644 (file)
@@ -28,7 +28,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 
 /*
     Bool VG_(has_cpuid)(void)
index 8f6bc528214da1b43a123268e4d2b0c87cb5e451..6b46355db0d29d1ba486be9c331a5fac2e007980 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
+#include "pub_core_clientstate.h"
 #include "pub_core_debugger.h"
 #include "pub_core_libcbase.h"
-#include "pub_core_libcassert.h"    // For I_die_here
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
 #include "pub_core_options.h"
 
-// We can remove these easily by implementing our own VG_(ptrace)() and
-// VG_(fork)().
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-#include <unistd.h>
+#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+#define WSTOPSIG(status) (((status) & 0xff00) >> 8)
 
 static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
 {
@@ -65,7 +62,7 @@ static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
    regs.eflags = LibVEX_GuestX86_get_eflags(vex);
    regs.eip    = vex->guest_EIP;
 
-   return ptrace(PTRACE_SETREGS, pid, NULL, &regs);
+   return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, &regs);
 #elif defined(VGA_amd64)
    regs.rax    = vex->guest_RAX;
    regs.rbx    = vex->guest_RBX;
@@ -86,7 +83,7 @@ static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
    regs.eflags = LibVEX_GuestAMD64_get_rflags(vex);
    regs.rip    = vex->guest_RIP;
 
-   return ptrace(PTRACE_SETREGS, pid, NULL, &regs);
+   return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, &regs);
 #elif defined(VGA_ppc32)
    I_die_here;
    regs.gpr[0] = 0; // stop compiler complaints
@@ -102,10 +99,10 @@ static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
    continue, quit the debugger.  */
 void VG_(start_debugger) ( ThreadId tid )
 {
-   Int pid;
+  Int pid;
 
-   if ((pid = fork()) == 0) {
-      ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+  if ((pid = VG_(fork)()) == 0) {
+      VG_(ptrace)(VKI_PTRACE_TRACEME, 0, NULL, NULL);
       VG_(kill)(VG_(getpid)(), VKI_SIGSTOP);
 
    } else if (pid > 0) {
@@ -113,10 +110,10 @@ void VG_(start_debugger) ( ThreadId tid )
       Int res;
 
       if ((res = VG_(waitpid)(pid, &status, 0)) == pid &&
-          WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP &&
+          WIFSTOPPED(status) && WSTOPSIG(status) == VKI_SIGSTOP &&
           ptrace_setregs(pid, &(VG_(threads)[tid].arch.vex)) == 0 &&
-          VG_(kill)(pid, SIGSTOP) == 0 &&
-          ptrace(PTRACE_DETACH, pid, NULL, 0) == 0)
+          VG_(kill)(pid, VKI_SIGSTOP) == 0 &&
+          VG_(ptrace)(VKI_PTRACE_DETACH, pid, NULL, 0) == 0)
       {
          Char pidbuf[15];
          Char file[30];
@@ -125,7 +122,7 @@ void VG_(start_debugger) ( ThreadId tid )
          Char *cmdptr;
          
          VG_(sprintf)(pidbuf, "%d", pid);
-         VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(clexecfd));
+         VG_(sprintf)(file, "/proc/%d/fd/%d", pid, VG_(cl_exec_fd));
  
          bufptr = buf;
          cmdptr = VG_(clo_db_command);
diff --git a/coregrind/m_debuginfo/Makefile.am b/coregrind/m_debuginfo/Makefile.am
deleted file mode 100644 (file)
index e3fe111..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_HEADERS = \
-       priv_symtab.h \
-       priv_symtypes.h
-
-noinst_LIBRARIES = libdebuginfo.a
-
-libdebuginfo_a_SOURCES = \
-       dwarf.c         \
-       stabs.c         \
-       symtab.c        \
-       symtypes.c
index 577c36fb04d38ef47874127165e90ce48999695d..8b404b08a56d6072d7c25104430f70ab7ca31088 100644 (file)
@@ -36,7 +36,6 @@
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_machine.h"
 #include "pub_core_mallocfree.h"
@@ -45,6 +44,8 @@
 #include "pub_core_redir.h"
 #include "pub_core_tooliface.h"     // For VG_(needs).data_syms
 
+#include "pub_core_aspacemgr.h"
+
 #include "priv_symtypes.h"
 #include "priv_symtab.h"
 
@@ -94,6 +95,126 @@ static SegInfo* segInfo_list = NULL;
 #endif
 
 
+/*------------------------------------------------------------*/
+/*--- TOP LEVEL                                            ---*/
+/*------------------------------------------------------------*/
+
+/* If this mapping is at the beginning of a file, isn't part of
+   Valgrind, is at least readable and seems to contain an object
+   file, then try reading symbols from it.
+
+   Getting this heuristic right is critical.  On x86-linux,
+   objects are typically mapped twice:
+
+   1b8fb000-1b8ff000 r-xp 00000000 08:02 4471477 vgpreload_memcheck.so
+   1b8ff000-1b900000 rw-p 00004000 08:02 4471477 vgpreload_memcheck.so
+
+   whereas ppc32-linux mysteriously does this:
+
+   118a6000-118ad000 r-xp 00000000 08:05 14209428 vgpreload_memcheck.so
+   118ad000-118b6000 ---p 00007000 08:05 14209428 vgpreload_memcheck.so
+   118b6000-118bd000 rwxp 00000000 08:05 14209428 vgpreload_memcheck.so
+
+   The third mapping should not be considered to have executable code in.
+   Therefore a test which works for both is: r and x and NOT w.  Reading
+   symbols from the rwx segment -- which overlaps the r-x segment in the
+   file -- causes the redirection mechanism to redirect to addresses in
+   that third segment, which is wrong and causes crashes.
+*/
+
+static Bool is_self ( HChar* filename )
+{ 
+   return VG_(strstr)( filename, "/lib/valgrind/" ) != NULL;
+}
+
+////////////
+
+// fwds
+static void unload_symbols ( Addr start, SizeT length );
+
+static void nuke_syms_in_range ( Addr start, SizeT length )
+{
+   /* Repeatedly scan the segInfo list, looking for segInfos in this
+      range, and call unload_symbols on the segInfo's stated start
+      point.  This modifies the list, hence the multiple
+      iterations. */
+   Bool found;
+   SegInfo* curr;
+
+   while (True) {
+      found = False;
+
+      curr = segInfo_list;
+      while (True) {
+         if (curr == NULL) break;
+         if (start+length-1 < curr->start || curr->start+curr->size-1 < start) {
+          /* no overlap */
+        } else {
+          found = True;
+          break;
+        }
+        curr = curr->next;
+      }
+
+      if (!found) break;
+      unload_symbols( curr->start, curr->size );
+
+   }
+}
+
+void VG_(di_notify_mmap)( Addr a )
+{
+   NSegment* seg;
+   HChar*    filename;
+   Bool      ok;
+
+   seg = VG_(am_find_nsegment)(a);
+   vg_assert(seg);
+
+   filename = VG_(am_get_filename)( seg );
+   if (!filename)
+      return;
+
+   filename = VG_(arena_strdup)( VG_AR_SYMTAB, filename );
+
+   ok = (seg->kind == SkFileC || (seg->kind == SkFileV && is_self(filename)))
+         && seg->offset == 0
+         && seg->fnIdx != -1
+         && seg->hasR
+         && seg->hasX
+         && !seg->hasW
+         && VG_(is_object_file)( (const void*)seg->start );
+
+   if (!ok) {
+      VG_(arena_free)(VG_AR_SYMTAB, filename);
+      return;
+   }
+
+   nuke_syms_in_range( seg->start, seg->end + 1 - seg->start );
+   VG_(read_seg_symbols)( seg->start, seg->end + 1 - seg->start, 
+                          seg->offset, filename );
+
+   /* VG_(read_seg_symbols) makes its own copy of filename, so is safe
+      to free it. */
+   VG_(arena_free)(VG_AR_SYMTAB, filename);
+}
+
+void VG_(di_notify_munmap)( Addr a, SizeT len )
+{
+   nuke_syms_in_range(a, len);
+}
+
+void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
+{
+   Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
+#  if defined(VGP_x86_linux)
+   exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
+#  endif
+   if (0 && !exe_ok)
+      nuke_syms_in_range(a, len);
+}
+
+
 /*------------------------------------------------------------*/
 /*---                                                      ---*/
 /*------------------------------------------------------------*/
@@ -1185,9 +1306,8 @@ calc_gnu_debuglink_crc32(UInt crc, const UChar *buf, Int len)
 static
 Addr open_debug_file( Char* name, UInt crc, UInt* size )
 {
-   SysRes fd;
+   SysRes fd, sres;
    struct vki_stat stat_buf;
-   Addr addr;
    UInt calccrc;
 
    fd = VG_(open)(name, VKI_O_RDONLY, 0);
@@ -1204,26 +1324,24 @@ Addr open_debug_file( Char* name, UInt crc, UInt* size )
 
    *size = stat_buf.st_size;
    
-   if ((addr = (Addr)VG_(mmap)(NULL, *size, VKI_PROT_READ,
-                               VKI_MAP_PRIVATE|VKI_MAP_NOSYMS, 
-                               0, fd.val, 0)) == (Addr)-1) 
-   {
-      VG_(close)(fd.val);
-      return 0;
-   }
+   sres = VG_(am_mmap_file_float_valgrind)
+             ( *size, VKI_PROT_READ, fd.val, 0 );
 
    VG_(close)(fd.val);
    
-   calccrc = calc_gnu_debuglink_crc32(0, (UChar*)addr, *size);
+   if (sres.isError)
+      return 0;
+
+   calccrc = calc_gnu_debuglink_crc32(0, (UChar*)sres.val, *size);
    if (calccrc != crc) {
-      int res = VG_(munmap)((void*)addr, *size);
-      vg_assert(0 == res);
+      SysRes res = VG_(am_munmap_valgrind)(sres.val, *size);
+      vg_assert(!res.isError);
       if (VG_(clo_verbosity) > 1)
         VG_(message)(Vg_DebugMsg, "... CRC mismatch (computed %08x wanted %08x)", calccrc, crc);
       return 0;
    }
    
-   return addr;
+   return sres.val;
 }
 
 /*
@@ -1267,7 +1385,7 @@ Bool read_lib_symbols ( SegInfo* si )
    ElfXX_Ehdr*   ehdr;       /* The ELF header                          */
    ElfXX_Shdr*   shdr;       /* The section table                       */
    UChar*        sh_strtab;  /* The section table's string table        */
-   SysRes        fd;
+   SysRes        fd, sres;
    Int           i;
    Bool          ok;
    Addr          oimage;
@@ -1278,7 +1396,8 @@ Bool read_lib_symbols ( SegInfo* si )
 
    oimage = (Addr)NULL;
    if (VG_(clo_verbosity) > 1)
-      VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", si->filename, si->start );
+      VG_(message)(Vg_DebugMsg, "Reading syms from %s (%p)", 
+                                si->filename, si->start );
 
    /* mmap the object image aboard, so that we can read symbols and
       line number info out of it.  It will be munmapped immediately
@@ -1297,18 +1416,19 @@ Bool read_lib_symbols ( SegInfo* si )
       return False;
    }
 
-   oimage = (Addr)VG_(mmap)( NULL, n_oimage, 
-                             VKI_PROT_READ, VKI_MAP_PRIVATE|VKI_MAP_NOSYMS, 
-                             0, fd.val, 0 );
+   sres = VG_(am_mmap_file_float_valgrind)
+             ( n_oimage, VKI_PROT_READ, fd.val, 0 );
 
    VG_(close)(fd.val);
 
-   if (oimage == ((Addr)(-1))) {
+   if (sres.isError) {
       VG_(message)(Vg_UserMsg, "warning: mmap failed on %s", si->filename );
       VG_(message)(Vg_UserMsg, "         no symbols or debug info loaded" );
       return False;
    }
 
+   oimage = sres.val;
+
    /* Ok, the object image is safely in oimage[0 .. n_oimage-1]. 
       Now verify that it is a valid ELF .so or executable image.
    */
@@ -1637,14 +1757,14 @@ Bool read_lib_symbols ( SegInfo* si )
    res = True;
 
   out: {
-   Int m_res;
+   SysRes m_res;
    /* Last, but not least, heave the image(s) back overboard. */
    if (dimage) {
-      m_res = VG_(munmap) ( (void*)dimage, n_dimage );
-      vg_assert(0 == m_res);
+      m_res = VG_(am_munmap_valgrind) ( dimage, n_dimage );
+      vg_assert(!m_res.isError);
    }
-   m_res = VG_(munmap) ( (void*)oimage, n_oimage );
-   vg_assert(0 == m_res);
+   m_res = VG_(am_munmap_valgrind) ( oimage, n_oimage );
+   vg_assert(!m_res.isError);
    return res;
   } 
 }
index 6cc4786ae81c90d106984e4cc3dbf7e9932cfd46..b391fb9b28eb97f88a76952d75d0852a2353bb59 100644 (file)
@@ -33,7 +33,6 @@
 #include "pub_core_debuglog.h"    // For VG_(debugLog_vprintf)
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcsignal.h"
 #include "pub_core_machine.h"
index 2cde3d9789ff8b6c118b404ed09b06cf2a764161..48d5caf95927ad0ed0a913083c079c12bb082af7 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "pub_core_basics.h"     /* basic types */
 #include "pub_core_debuglog.h"   /* our own iface */
+#include "valgrind.h"            /* for RUNNING_ON_VALGRIND */
 
 /*------------------------------------------------------------*/
 /*--- Stuff to make us completely independent.             ---*/
@@ -61,15 +62,14 @@ static UInt local_sys_write_stderr ( HChar* buf, Int n )
 {
    UInt __res;
    __asm__ volatile (
+      "pushl %%ebx\n"        // ebx is callee-save
       "movl  $4, %%eax\n"    /* %eax = __NR_write */
-      "movl  $2, %%edi\n"    /* %edi = stderr */
+      "movl  $1, %%ebx\n"    /* %ebx = stderr */
       "movl  %1, %%ecx\n"    /* %ecx = buf */
       "movl  %2, %%edx\n"    /* %edx = n */
-      "pushl %%ebx\n"
-      "movl  %%edi, %%ebx\n"
       "int   $0x80\n"        /* write(stderr, buf, n) */
-      "popl  %%ebx\n"
       "movl  %%eax, %0\n"    /* __res = eax */
+      "popl  %%ebx\n"        // restore ebx
       : "=mr" (__res)
       : "g" (buf), "g" (n)
       : "eax", "edi", "ecx", "edx"
@@ -586,11 +586,10 @@ void VG_(debugLog) ( Int level, const HChar* modulename,
                                 const HChar* format, ... )
 {
    UInt ret, pid;
-   Int indent;
+   Int indent, depth, i;
    va_list vargs;
    printf_buf buf;
 
-   
    if (level > loglevel)
       return;
 
@@ -600,6 +599,14 @@ void VG_(debugLog) ( Int level, const HChar* modulename,
    buf.n = 0;
    buf.buf[0] = 0;
    pid = local_sys_getpid();
+
+   // Print one '>' in front of the messages for each level of self-hosting
+   // being performed.
+   depth = RUNNING_ON_VALGRIND;
+   for (i = 0; i < depth; i++) {
+      (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ">", False );
+   }
+   
    (void)myvprintf_str ( add_to_buf, &buf, 0, 2, "--", False );
    (void)myvprintf_int64 ( add_to_buf, &buf, 0, 10, 1, (ULong)pid );
    (void)myvprintf_str ( add_to_buf, &buf, 0, 1, ":", False );
diff --git a/coregrind/m_demangle/Makefile.am b/coregrind/m_demangle/Makefile.am
deleted file mode 100644 (file)
index be6bc5b..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_HEADERS = \
-       ansidecl.h     \
-       dyn-string.h   \
-       demangle.h     \
-       safe-ctype.h 
-
-noinst_LIBRARIES = libdemangle.a
-
-libdemangle_a_SOURCES = \
-       cp-demangle.c \
-       cplus-dem.c \
-       demangle.c \
-       dyn-string.c \
-       safe-ctype.c
-
-## Ignore harmless warnings for these ones
-cp-demangle.o: CFLAGS += -Wno-unused -Wno-shadow 
-cplus-dem.o: CFLAGS += -Wno-unused
-
index 0e22abcf06ea4cda47e52cfe09ff2925d1599cf7..8212fe267df39329cf7f41643891af06f2a9c257 100644 (file)
@@ -710,14 +710,14 @@ template_arg_list_add_arg (arg_list, arg)
    argument list ARG_LIST.  */
 
 static string_list_t
-template_arg_list_get_arg (arg_list, index)
+template_arg_list_get_arg (arg_list, index2)
      template_arg_list_t arg_list;
-     int index;
+     int index2;
 {
   string_list_t arg = arg_list->first_argument;
   /* Scan down the list of arguments to find the one at position
      INDEX.  */
-  while (index--)
+  while (index2--)
     {
       arg = arg->next;
       if (arg == NULL)
@@ -966,7 +966,7 @@ demangle_char (dm, c)
      demangling_t dm;
      int c;
 {
-  static char *error_message = NULL;
+  //static char *error_message = NULL;    // unused
 
   if (peek_char (dm) == c)
     {
@@ -2988,7 +2988,7 @@ static status_t
 demangle_template_args (dm)
      demangling_t dm;
 {
-  int first = 1;
+  //int first = 1;      // unused
   dyn_string_t old_last_source_name;
   dyn_string_t new_name;
   template_arg_list_t arg_list = template_arg_list_new ();
@@ -3894,6 +3894,7 @@ VG_(java_demangle_v3) (mangled)
 /* Demangle NAME in the G++ V3 ABI demangling style, and return either
    zero, indicating that some error occurred, or a demangling_t
    holding the results.  */
+__attribute__((unused))
 static demangling_t
 demangle_v3_with_details (name)
      const char *name;
index b8bcc9ad290d2b7e364085b98ed9435213303146..f8af1de68e25464dc14ad8d57e92382c5e2451a1 100644 (file)
@@ -54,7 +54,7 @@ char * malloc ();
 char * realloc ();
 #endif*/
 
-#include <demangle.h>
+#include "demangle.h"
 #include "dyn-string.h"
 #undef CURRENT_DEMANGLING_STYLE
 #define CURRENT_DEMANGLING_STYLE work->options
@@ -3852,7 +3852,7 @@ demangle_fund_type (work, mangled, result)
   int done = 0;
   int success = 1;
   char buf[10];
-  unsigned int dec = 0;
+  //unsigned int dec = 0;     // unused
   string btype;
   type_kind_t tk = tk_integral;
 
index 340abba2ba4ce0f5105a0d75c7bbee1732a5c1a2..c685be3e867f551bd357dded7cbfa3fb3b2dbf05 100644 (file)
@@ -30,7 +30,7 @@ Boston, MA 02111-1307, USA.  */
      unsigned char.  */
 
 #include "ansidecl.h"
-#include <safe-ctype.h>
+#include "safe-ctype.h"
 /*#include <stdio.h>*/  /* for EOF */
 
 /* Shorthand */
diff --git a/coregrind/m_dispatch/Makefile.am b/coregrind/m_dispatch/Makefile.am
deleted file mode 100644 (file)
index 7fcbc88..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_LIBRARIES = libdispatch.a
-
-# Remember to include all the arch-specific files in the distribution.
-EXTRA_DIST = \
-       $(addsuffix .S,$(addprefix dispatch-,$(VG_ARCH_ALL)))
-
-libdispatch_a_SOURCES = \
-       dispatch-@VG_ARCH@.S
-
-dispatch-@VG_ARCH@.S: libvex_guest_offsets.h
-
-libvex_guest_offsets.h:
-       $(MAKE) -C @VEX_DIR@ CC="$(CC)" pub/libvex_guest_offsets.h
index 64e85733a1b915d6d21fe43196d9c4d66843691d..2f661be5f8e4f126bb4c90bbf78f1b3e1127f0f2 100644 (file)
@@ -29,7 +29,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "pub_core_dispatch_asm.h"
 #include "pub_core_transtab_asm.h"
 #include "libvex_guest_offsets.h"      /* for OFFSET_amd64_RIP */
index 5147a9d5b121e883d6fdc6d0318d7ae79ec9fd8e..501e1efe4652b7c3f8c9b7b3837ce282bc6e2361 100644 (file)
@@ -28,7 +28,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "pub_core_dispatch_asm.h"
 #include "pub_core_transtab_asm.h"
 #include "libvex_guest_offsets.h"      /* for OFFSET_ppc32_CIA */
index 5b751c8ebd05fb7b8ec089d0c1beba64100250e4..e743a8c1329791c7375b28c969bd62db8cf8a980 100644 (file)
@@ -29,7 +29,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "pub_core_dispatch_asm.h"
 #include "pub_core_transtab_asm.h"
 #include "libvex_guest_offsets.h"      /* for OFFSET_x86_EIP */
@@ -133,6 +133,8 @@ run_innerloop_exit:
        /* We're leaving.  Check that nobody messed with
            %mxcsr or %fpucw.  We can't mess with %eax here as it
           holds the tentative return value, but any other is OK. */
+/* This fails for self-hosting, so skip in that case */
+#ifndef ENABLE_INNER
        pushl   $0
        fstcw   (%esp)
        cmpl    $0x027F, (%esp)
@@ -140,6 +142,7 @@ run_innerloop_exit:
        jnz     invariant_violation
        cmpl    $0, VG_(have_mxcsr_x86)
        jz      L2
+#endif
        pushl   $0
        stmxcsr (%esp)
        andl    $0xFFFFFFC0, (%esp)  /* mask out status flags */
diff --git a/coregrind/m_launcher.c b/coregrind/m_launcher.c
new file mode 100644 (file)
index 0000000..8c3c395
--- /dev/null
@@ -0,0 +1,145 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Launching valgrind                              m_launcher.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 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.
+*/
+
+/* Note: this is a "normal" program and not part of Valgrind proper,
+   and so it doesn't have to conform to Valgrind's arcane rules on
+   no-glibc-usage etc. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "pub_core_debuglog.h"
+#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
+
+
+
+#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno
+                         where it is defined */
+
+static void barf ( char* str )
+{
+   fprintf(stderr, "valgrind: Cannot continue: %s\n", str );
+   exit(1);
+}
+
+/* Where we expect to find all our aux files */
+static const char *valgrind_lib = VG_LIBDIR;
+
+int main(int argc, char** argv, char** envp)
+{
+   int i, j, loglevel, r;
+   const char *toolname = NULL;
+   const char *cp;
+   char *toolfile;
+   char launcher_name[PATH_MAX+1];
+   char* new_line;
+   char** new_env;
+
+   /* Start the debugging-log system ASAP.  First find out how many 
+      "-d"s were specified.  This is a pre-scan of the command line.
+      At the same time, look for the tool name. */
+   loglevel = 0;
+   for (i = 1; i < argc; i++) {
+      if (argv[i][0] != '-')
+         break;
+      if (0 == strcmp(argv[i], "--")) 
+         break;
+      if (0 == strcmp(argv[i], "-d")) 
+         loglevel++;
+      if (0 == strncmp(argv[i], "--tool=", 7)) 
+         toolname = argv[i] + 7;
+   }
+
+   /* ... and start the debug logger.  Now we can safely emit logging
+      messages all through startup. */
+   VG_(debugLog_startup)(loglevel, "Stage 1");
+
+   /* Make sure we know which tool we're using */
+   if (toolname) {
+      VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
+   } else {
+      VG_(debugLog)(1, "launcher", 
+                       "no tool requested, defaulting to 'memcheck'\n");
+      toolname = "memcheck";
+   }
+
+   /* Figure out the name of this executable (viz, the launcher), so
+      we can tell stage2.  stage2 will use the name for recursive
+      invokations of valgrind on child processes. */
+   memset(launcher_name, 0, PATH_MAX+1);
+   r = readlink("/proc/self/exe", launcher_name, PATH_MAX);
+   if (r == -1)
+      barf("readlink(\"/proc/self/exe\") failed.");
+
+   /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
+   new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1 
+                     + strlen(launcher_name) + 1);
+   if (new_line == NULL)
+      barf("malloc of new_line failed.");
+   strcpy(new_line, VALGRIND_LAUNCHER);
+   strcat(new_line, "=");
+   strcat(new_line, launcher_name);
+
+   for (j = 0; envp[j]; j++)
+      ;
+   new_env = malloc((j+2) * sizeof(char*));
+   if (new_env == NULL)
+      barf("malloc of new_env failed.");
+   for (i = 0; i < j; i++)
+      new_env[i] = envp[i];
+   new_env[i++] = new_line;
+   new_env[i++] = NULL;
+   assert(i == j+2);
+
+   /* Establish the correct VALGRIND_LIB. */
+   cp = getenv(VALGRIND_LIB);
+
+   if (cp != NULL)
+      valgrind_lib = cp;
+
+   /* Build the stage2 invokation, and execve it.  Bye! */
+   toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + 2);
+   if (toolfile == NULL)
+      barf("malloc of toolfile failed.");
+   sprintf(toolfile, "%s/%s", valgrind_lib, toolname);
+
+   VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
+
+   execve(toolfile, argv, new_env);
+
+   fprintf(stderr, "valgrind: failed to start tool '%s': %s\n",
+                   toolname, strerror(errno));
+
+   exit(1);
+}
index ae8f406680b9a64edd053f479324325d010af5a8..4d61668f83991e18806dc2bec5a2efbac4191725 100644 (file)
@@ -109,8 +109,7 @@ static void report_and_quit ( const Char* report,
        GET_REAL_SP_AND_FP(sp, fp);
    }
  
-   stacktop = tst->os_state.valgrind_stack_base + 
-              tst->os_state.valgrind_stack_szB;
+   stacktop = tst->os_state.valgrind_stack_init_SP;
  
    VG_(get_StackTrace2)(ips, BACKTRACE_DEPTH, ip, sp, fp, lr, sp, stacktop);
    VG_(pp_StackTrace)  (ips, BACKTRACE_DEPTH);
index f8c4275edd7ed7ce6880268ab7bd78604efcce6f..23901f43a405d1b9ac62f1d7454740e8c012aefe 100644 (file)
@@ -334,8 +334,34 @@ Bool VG_(string_match) ( const Char* pat, const Char* str )
 
 void* VG_(memcpy) ( void *dest, const void *src, SizeT sz )
 {
-   const Char *s = (const Char *)src;
-   Char *d = (Char *)dest;
+   const UChar* s  = (const UChar*)src;
+         UChar* d  =       (UChar*)dest;
+   const UInt*  sI = (const UInt*)src;
+         UInt*  dI =       (UInt*)dest;
+
+   if (VG_IS_4_ALIGNED(dI) && VG_IS_4_ALIGNED(sI)) {
+      while (sz >= 16) {
+         dI[0] = sI[0];
+         dI[1] = sI[1];
+         dI[2] = sI[2];
+         dI[3] = sI[3];
+         sz -= 16;
+         dI += 4;
+         sI += 4;
+      }
+      if (sz == 0) 
+         return dest;
+      while (sz >= 4) {
+         dI[0] = sI[0];
+         sz -= 4;
+         dI += 1;
+         sI += 1;
+      }
+      if (sz == 0) 
+         return dest;
+      s = (const UChar*)sI;
+      d = (UChar*)dI;
+   }
 
    while (sz--)
       *d++ = *s++;
@@ -471,19 +497,22 @@ void VG_(ssort)( void* base, SizeT nmemb, SizeT size,
    #undef SORT
 }
 
+// This random number generator is based on the one suggested in Kernighan
+// and Ritchie's "The C Programming Language".
+
+// A pseudo-random number generator returning a random UInt.  If pSeed
+// is NULL, it uses its own seed, which starts at zero.  If pSeed is
+// non-NULL, it uses and updates whatever pSeed points at.
+
 static UInt seed = 0;
 
-void VG_(srandom)(UInt s)
+UInt VG_(random)( /*MOD*/UInt* pSeed )
 {
-   seed = s;
-}
+   if (pSeed == NULL) 
+      pSeed = &seed;
 
-// This random number generator is based on the one suggested in Kernighan
-// and Ritchie's "The C Programming Language".
-UInt VG_(random)(void)
-{
-   seed = (1103515245*seed + 12345);
-   return seed;
+   *pSeed = (1103515245 * *pSeed + 12345);
+   return *pSeed;
 }
 
 /*--------------------------------------------------------------------*/
index ff20a31e47bd8e261ec2e72945275b5dd3f299ea..34e18c5603fbf625fb65dafd8415d89ce88e9d5b 100644 (file)
@@ -33,6 +33,7 @@
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
 #include "pub_core_libcprint.h"     // For VG_(sprintf)()
+#include "pub_core_libcproc.h"      // VG_(getpid), VG_(getppid)
 #include "pub_core_syscall.h"
 #include "vki_unistd.h"
 
@@ -78,7 +79,7 @@ Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
    VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
    VG_(memset)(buf, 0, n_buf);
 
-   if (VG_(readlink)(tmp, buf, VKI_PATH_MAX) > 0 && buf[0] == '/')
+   if (VG_(readlink)(tmp, buf, n_buf) > 0 && buf[0] == '/')
       return True;
    else
       return False;
@@ -113,10 +114,12 @@ Int VG_(pipe) ( Int fd[2] )
    return res.isError ? -1 : 0;
 }
 
-OffT VG_(lseek) ( Int fd, OffT offset, Int whence)
+OffT VG_(lseek) ( Int fd, OffT offset, Int whence )
 {
    SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
    return res.isError ? (-1) : 0;
+   /* if you change the error-reporting conventions of this, also
+      change VG_(pread) and all other usage points. */
 }
 
 SysRes VG_(stat) ( Char* file_name, struct vki_stat* buf )
@@ -131,10 +134,16 @@ Int VG_(fstat) ( Int fd, struct vki_stat* buf )
    return res.isError ? (-1) : 0;
 }
 
-Int VG_(dup2) ( Int oldfd, Int newfd )
+Int VG_(fsize) ( Int fd )
 {
-   SysRes res = VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
-   return res.isError ? (-1) : res.val;
+   struct vki_stat buf;
+   SysRes res = VG_(do_syscall2)(__NR_fstat, fd, (UWord)&buf);
+   return res.isError ? (-1) : buf.st_size;
+}
+
+SysRes VG_(dup) ( Int oldfd )
+{
+   return VG_(do_syscall1)(__NR_dup, oldfd);
 }
 
 /* Returns -1 on error. */
@@ -182,6 +191,76 @@ Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
    return res.isError ? -1 : res.val;
 }
 
+/* Check accessibility of a file.  Returns zero for access granted,
+   nonzero otherwise. */
+Int VG_(access) ( HChar* path, Bool irusr, Bool iwusr, Bool ixusr )
+{
+#if defined(VGO_linux)
+   /* Very annoyingly, I cannot find any definition for R_OK et al in
+      the kernel interfaces.  Therefore I reluctantly resort to
+      hardwiring in these magic numbers that I determined by
+      experimentation. */
+   UWord w = (irusr ? 4/*R_OK*/ : 0)
+             | (iwusr ? 2/*W_OK*/ : 0)
+             | (ixusr ? 1/*X_OK*/ : 0);
+   SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
+   return res.isError ? 1 : res.val;
+#else
+#  error "Don't know how to do VG_(access) on this OS"
+#endif
+}
+
+SysRes VG_(pread) ( Int fd, void* buf, Int count, Int offset )
+{
+   OffT off = VG_(lseek)( fd, (OffT)offset, VKI_SEEK_SET);
+   if (off != 0)
+      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count );
+   return res;
+}
+
+/* Create and open (-rw------) a tmp file name incorporating said arg.
+   Returns -1 on failure, else the fd of the file.  If fullname is
+   non-NULL, the file's name is written into it.  The number of bytes
+   written is guaranteed not to exceed 64+strlen(part_of_name). */
+
+Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname )
+{
+   HChar  buf[200];
+   Int    n, tries, fd;
+   UInt   seed;
+   SysRes sres;
+
+   vg_assert(part_of_name);
+   n = VG_(strlen)(part_of_name);
+   vg_assert(n > 0 && n < 100);
+
+   seed = (VG_(getpid)() << 9) ^ VG_(getppid)();
+
+   tries = 0;
+   while (True) {
+      if (tries > 10) 
+         return -1;
+      VG_(sprintf)( buf, "/tmp/valgrind_%s_%08x", 
+                         part_of_name, VG_(random)( &seed ));
+      if (0)
+         VG_(printf)("VG_(mkstemp): trying: %s\n", buf);
+
+      sres = VG_(open)(buf,
+                       VKI_O_CREAT|VKI_O_RDWR|VKI_O_EXCL|VKI_O_TRUNC,
+                       VKI_S_IRUSR|VKI_S_IWUSR);
+      if (sres.isError)
+         continue;
+      /* VG_(safe_fd) doesn't return if it fails. */
+      fd = VG_(safe_fd)( sres.val );
+      if (fullname)
+         VG_(strcpy)( fullname, buf );
+      return fd;
+   }
+   /* NOTREACHED */
+}
+
+
 /* ---------------------------------------------------------------------
    Socket-related stuff.  This is very Linux-kernel specific.
    ------------------------------------------------------------------ */
diff --git a/coregrind/m_libcmman.c b/coregrind/m_libcmman.c
deleted file mode 100644 (file)
index 420f25b..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Memory management libc stuff.                   m_libcmman.c ---*/
-/*--------------------------------------------------------------------*/
-/*
-   This file is part of Valgrind, a dynamic binary instrumentation
-   framework.
-
-   Copyright (C) 2000-2005 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.
-*/
-
-#include "pub_core_basics.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
-#include "pub_core_aspacemgr.h"
-#include "pub_core_libcbase.h"
-#include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
-#include "pub_core_libcprint.h"
-
-/* Returns -1 on failure. */
-void* VG_(mmap)( void* start, SizeT length,
-                 UInt prot, UInt flags, UInt sf_flags, UInt fd, OffT offset)
-{
-   SysRes res;
-
-   if (!(flags & VKI_MAP_FIXED)) {
-      start = (void *)VG_(find_map_space)((Addr)start, length, !!(flags & VKI_MAP_CLIENT));
-   }
-   if (start == 0)
-      return (void *)-1;
-
-   res = VG_(mmap_native)(start, length, prot, 
-                          (flags | VKI_MAP_FIXED) & ~(VKI_MAP_NOSYMS | VKI_MAP_CLIENT),
-                          fd, offset);
-
-   // Check it ended up in the right place.
-   if (!res.isError) {
-      if (flags & VKI_MAP_CLIENT) {
-         vg_assert(VG_(client_base) <= res.val 
-                   && res.val+length <= VG_(client_end));
-      } else {
-         vg_assert(VG_(valgrind_base) <= res.val 
-                   && res.val+length-1 <= VG_(valgrind_last));
-      }
-
-      sf_flags |= SF_MMAP;
-      if (  flags & VKI_MAP_SHARED)     sf_flags |= SF_SHARED;
-      if (!(flags & VKI_MAP_ANONYMOUS)) sf_flags |= SF_FILE;
-      if (!(flags & VKI_MAP_CLIENT))    sf_flags |= SF_VALGRIND;
-      if (  flags & VKI_MAP_NOSYMS)     sf_flags |= SF_NOSYMS;
-
-      VG_(map_fd_segment)(res.val, length, prot, sf_flags, fd, offset, NULL);
-   }
-
-   return res.isError ? (void*)-1 : (void*)res.val;
-}
-
-/* Returns -1 on failure. */
-Int VG_(munmap)( void* start, SizeT length )
-{
-   SysRes res = VG_(munmap_native)(start, length);
-   if (!res.isError) {
-      VG_(unmap_range)((Addr)start, length);
-      return 0;
-   } else {
-      return -1;
-   }
-}
-
-Int VG_(mprotect)( void *start, SizeT length, UInt prot )
-{
-   SysRes res = VG_(mprotect_native)(start, length, prot);
-   if (!res.isError) {
-      VG_(mprotect_range)((Addr)start, length, prot);
-      return 0;
-   } else {
-      return -1;
-   }
-}
-
-void* VG_(get_memory_from_mmap) ( SizeT nBytes, Char* who )
-{
-   static SizeT tot_alloc = 0;
-   void* p;
-   p = VG_(mmap)(0, nBytes,
-                 VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
-                 VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, SF_VALGRIND, -1, 0);
-
-   if (p != ((void*)(-1))) {
-      vg_assert((void*)VG_(valgrind_base) <= p && p <= (void*)VG_(valgrind_last));
-      tot_alloc += nBytes;
-      if (0)
-         VG_(printf)(
-            "get_memory_from_mmap: %llu tot, %llu req = %p .. %p, caller %s\n",
-            (ULong)tot_alloc, (ULong)nBytes, p, ((char*)p) + nBytes - 1, who );
-      return p;
-   }
-
-   VG_(printf)("\n");
-   VG_(printf)("VG_(get_memory_from_mmap): %s's request for %llu bytes failed.\n",
-               who, (ULong)nBytes);
-   VG_(printf)("VG_(get_memory_from_mmap): %llu bytes already allocated.\n", 
-               (ULong)tot_alloc);
-   VG_(printf)("\n");
-   VG_(printf)("Sorry.  You could try using a tool that uses less memory;\n");
-   VG_(printf)("eg. addrcheck instead of memcheck.\n");
-   VG_(printf)("\n");
-   VG_(printf)("---- Debugging information follows --------\n");
-   VG_(printf)("Valgrind's range is: %p .. %p\n",
-               (void*)VG_(valgrind_base), (void*)VG_(valgrind_last));
-   VG_(show_segments)("VG_(get_memory_from_mmap) failure");
-
-   VG_(exit)(1);
-}
-
-// Returns 0 on failure.
-Addr VG_(get_memory_from_mmap_for_client) (SizeT len)
-{
-   Addr addr;
-
-   len = VG_PGROUNDUP(len);
-
-   addr = (Addr)VG_(mmap)(NULL, len, 
-                          VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
-                          VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS|VKI_MAP_CLIENT,
-                          SF_CORE, -1, 0);
-   if ((Addr)-1 != addr)
-      return addr;
-   else
-      return 0;
-}
-
-
-/*--------------------------------------------------------------------*/
-/*--- end                                                          ---*/
-/*--------------------------------------------------------------------*/
-
index 5d435e328abd3ead54bc2129529a61ac70f01deb..c2aeb090fb5e44bff60c5265e69d76f4f643f9c8 100644 (file)
@@ -38,8 +38,6 @@
 #include "pub_core_options.h"
 #include "valgrind.h"            // For RUNNING_ON_VALGRIND
 
-#include <time.h>
-#include <sys/time.h>
 
 
 /* ---------------------------------------------------------------------
@@ -70,10 +68,12 @@ static void send_bytes_to_logging_sink ( Char* msg, Int nbytes )
    printf() and friends
    ------------------------------------------------------------------ */
 
-typedef struct {
-   char buf[100];
-   int n;
-} printf_buf;
+typedef 
+   struct {
+      HChar buf[100];
+      Int   n;
+   } 
+   printf_buf;
 
 // Adds a single char to the buffer.  When the buffer gets sufficiently
 // full, we write its contents to the logging sink.
@@ -151,6 +151,53 @@ UInt VG_(sprintf) ( Char* buf, const HChar *format, ... )
    return ret;
 }
 
+
+/* A replacement for snprintf. */
+typedef 
+   struct {
+      HChar* buf;
+      Int    buf_size;
+      Int    buf_used;
+   } 
+   snprintf_buf;
+
+static void add_to_vg_snprintf_buf ( HChar c, void* p )
+{
+   snprintf_buf* b = p;
+   if (b->buf_size > 0 && b->buf_used < b->buf_size) {
+      b->buf[b->buf_used++] = c;
+      if (b->buf_used < b->buf_size)
+         b->buf[b->buf_used] = 0;
+   } 
+}
+
+UInt VG_(vsnprintf) ( Char* buf, Int size, const HChar *format, va_list vargs )
+{
+   Int ret;
+   snprintf_buf b;
+   b.buf      = buf;
+   b.buf_size = size < 0 ? 0 : size;
+   b.buf_used = 0;
+
+   ret = VG_(debugLog_vprintf) 
+            ( add_to_vg_snprintf_buf, &b, format, vargs );
+
+   return b.buf_used;
+}
+
+UInt VG_(snprintf) ( Char* buf, Int size, const HChar *format, ... )
+{
+   UInt ret;
+   va_list vargs;
+
+   va_start(vargs,format);
+   ret = VG_(vsnprintf)(buf, size, format, vargs);
+   va_end(vargs);
+
+   return ret;
+}
+
+
 /* ---------------------------------------------------------------------
    percentify()
    ------------------------------------------------------------------ */
@@ -212,9 +259,10 @@ void VG_(percentify)(ULong n, ULong m, UInt d, Int n_buf, char buf[])
 
 void VG_(ctime) ( /*OUT*/HChar* buf )
 {
+#if 0
    struct timeval tv;
    struct tm tm;
-   buf[0] = 0;     
+   buf[0] = 0;
    if ( gettimeofday( &tv, NULL ) == 0
         && localtime_r( &tv.tv_sec, &tm ) == &tm )
    {
@@ -223,6 +271,9 @@ void VG_(ctime) ( /*OUT*/HChar* buf )
                     tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
                     tm.tm_hour, tm.tm_min, tm.tm_sec, tv.tv_usec / 1000 );
    }
+#else
+   VG_(strcpy)(buf, "VG_(ctime) HACK!");
+#endif
 }
 
 
@@ -232,10 +283,9 @@ void VG_(ctime) ( /*OUT*/HChar* buf )
 
 UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
 {
-   UInt  count = 0;
-   Char  c;
-   const Char* pfx_s;
-   static const Char pfx[] = ">>>>>>>>>>>>>>>>";
+   UInt count = 0;
+   Char c;
+   Int  i, depth;
 
    switch (kind) {
       case Vg_UserMsg:       c = '='; break;
@@ -245,16 +295,15 @@ UInt VG_(vmessage) ( VgMsgKind kind, const HChar* format, va_list vargs )
       default:               c = '?'; break;
    }
 
-   // The pfx trick prints one or more '>' characters in front of the
-   // messages when running Valgrind under Valgrind, one per level of
-   // self-hosting.
-   pfx_s = &pfx[sizeof(pfx)-1-RUNNING_ON_VALGRIND],
-
-   // Print the message
-   count = 0;
-
+   // Print one '>' in front of the messages for each level of self-hosting
+   // being performed.
+   depth = RUNNING_ON_VALGRIND;
+   for (i = 0; i < depth; i++) {
+      count += VG_(printf) (">");
+   }
+   
    if (!VG_(clo_xml))
-      count += VG_(printf) ("%s%c%c", pfx_s, c,c);
+      count += VG_(printf) ("%c%c", c,c);
 
    if (VG_(clo_time_stamp)) {
       HChar buf[50];
index a17959ec36efb0eb4076cd07848fd7ee5070c51a..067d47f85eb23521f9c5648175ad4f8e102ce74c 100644 (file)
@@ -35,6 +35,7 @@
 #include "pub_core_libcproc.h"
 #include "pub_core_mallocfree.h"
 #include "pub_core_syscall.h"
+#include "pub_core_clientstate.h"
 #include "vki_unistd.h"
 
 /* ---------------------------------------------------------------------
 
 /* As deduced from sp_at_startup, the client's argc, argv[] and
    envp[] as extracted from the client's stack at startup-time. */
-Int    VG_(client_argc);
-Char** VG_(client_argv);
 Char** VG_(client_envp);
 
-/* client executable file descriptor */
-Int VG_(clexecfd) = -1;
-
 /* Path to library directory */
 const Char *VG_(libdir) = VG_LIBDIR;
 
@@ -74,7 +70,7 @@ void  VG_(env_unsetenv) ( Char **env, const Char *varname )
    Char **to = NULL;
    Int len = VG_(strlen)(varname);
 
-   for(from = to = env; from && *from; from++) {
+   for (from = to = env; from && *from; from++) {
       if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
         *to = *from;
         to++;
@@ -94,7 +90,7 @@ Char **VG_(env_setenv) ( Char ***envp, const Char* varname, const Char *val )
 
    VG_(sprintf)(valstr, "%s=%s", varname, val);
 
-   for(cpp = env; cpp && *cpp; cpp++) {
+   for (cpp = env; cpp && *cpp; cpp++) {
       if (VG_(strncmp)(varname, *cpp, len) == 0 && (*cpp)[len] == '=') {
         *cpp = valstr;
         return oldenv;
@@ -112,7 +108,7 @@ Char **VG_(env_setenv) ( Char ***envp, const Char* varname, const Char *val )
       Int envlen = (cpp-env) + 2;
       Char **newenv = VG_(arena_malloc)(VG_AR_CORE, envlen * sizeof(Char **));
 
-      for(cpp = newenv; *env; )
+      for (cpp = newenv; *env; )
         *cpp++ = *env++;
       *cpp++ = valstr;
       *cpp++ = NULL;
@@ -213,8 +209,8 @@ void VG_(env_remove_valgrind_env_stuff)(Char** envp)
    VG_(sprintf)(buf, "%s*", VG_(libdir));
    mash_colon_env(ld_library_path_str, buf);
 
-   // Remove VALGRIND_CLO variable.
-   VG_(env_unsetenv)(envp, VALGRINDCLO);
+   // Remove VALGRIND_LAUNCHER variable.
+   VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER);
 
    // XXX if variable becomes empty, remove it completely?
 
@@ -308,9 +304,6 @@ Int VG_(system) ( Char* cmd )
    Resource limits
    ------------------------------------------------------------------ */
 
-struct vki_rlimit VG_(client_rlimit_data);
-struct vki_rlimit VG_(client_rlimit_stack);
-
 /* Support for getrlimit. */
 Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
 {
@@ -388,10 +381,75 @@ Int VG_(getppid) ( void )
    return VG_(do_syscall0)(__NR_getppid) . val;
 }
 
-Int VG_(setpgid) ( Int pid, Int pgrp )
+Int VG_(geteuid) ( void )
 {
    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
-   return VG_(do_syscall2)(__NR_setpgid, pid, pgrp) . val;
+   return VG_(do_syscall0)(__NR_geteuid) . val;
+}
+
+Int VG_(getegid) ( void )
+{
+   /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
+   return VG_(do_syscall0)(__NR_getegid) . val;
+}
+
+/* Get supplementary groups into list[0 .. size-1].  Returns the
+   number of groups written, or -1 if error.  Note that in order to be
+   portable, the groups are 32-bit unsigned ints regardless of the
+   platform. */
+Int VG_(getgroups)( Int size, UInt* list )
+{
+#  if defined(VGP_x86_linux)
+   Int    i;
+   SysRes sres;
+   UShort list16[32];
+   if (size < 0) return -1;
+   if (size > 32) size = 32;
+   sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list16);
+   if (sres.isError)
+      return -1;
+   if (sres.val != size)
+      return -1;
+   for (i = 0; i < size; i++)
+      list[i] = (UInt)list16[i];
+   return size;
+
+#  elif defined(VGP_amd64_linux)
+   SysRes sres;
+   sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
+   if (sres.isError)
+      return -1;
+   return sres.val;
+
+#  else
+#     error "VG_(getgroups): needs implementation on this platform"
+#  endif
+}
+
+/* ---------------------------------------------------------------------
+   Process tracing
+   ------------------------------------------------------------------ */
+
+Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data )
+{
+   SysRes res;
+   res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data);
+   if (res.isError)
+      return -1;
+   return res.val;
+}
+
+/* ---------------------------------------------------------------------
+   Fork
+   ------------------------------------------------------------------ */
+
+Int VG_(fork) ( void )
+{
+   SysRes res;
+   res = VG_(do_syscall0)(__NR_fork);
+   if (res.isError)
+      return -1;
+   return res.val;
 }
 
 /* ---------------------------------------------------------------------
index 71f4129821d0f6eadc9531e0a726a3e557ed57f4..e8ea6099dedcfba63f81fa07d418c3f071dba396 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
+#include "pub_core_clientstate.h"
 #include "pub_core_aspacemgr.h"
+#include "pub_core_commandline.h"
 #include "pub_core_debuglog.h"
 #include "pub_core_errormgr.h"
 #include "pub_core_execontext.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
+#include "pub_core_syscall.h"       // VG_(strerror)
 #include "pub_core_machine.h"
 #include "pub_core_main.h"
 #include "pub_core_mallocfree.h"
 #include "pub_core_options.h"
 #include "pub_core_profile.h"
+
+#include "pub_core_debuginfo.h"     // Needed for pub_core_redir
 #include "pub_core_redir.h"
+
 #include "pub_core_scheduler.h"
 #include "pub_core_signals.h"
 #include "pub_core_stacks.h"        // For VG_(register_stack)
 #include "pub_core_transtab.h"
 #include "pub_core_ume.h"
 
-#include <dirent.h>
-#include <dlfcn.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
 #include "memcheck/memcheck.h"
 
 #ifndef AT_DCACHEBSIZE
 #define AT_SECURE 23   /* secure mode boolean */
 #endif /* AT_SECURE */
 
-/* redzone gap between client address space and shadow */
-#define REDZONE_SIZE           (1 * 1024*1024)
-
-/* size multiple for client address space */
-#define CLIENT_SIZE_MULTIPLE   (1 * 1024*1024)
-
-/* Proportion of client space for its heap (rest is for mmaps + stack) */
-#define CLIENT_HEAP_PROPORTION   0.333
-
 /* Number of file descriptors that Valgrind tries to reserve for
    it's own use - just a small constant. */
 #define N_RESERVED_FDS (10)
 
+
+
 /*====================================================================*/
 /*=== Global entities not referenced from generated code           ===*/
 /*====================================================================*/
    Startup stuff                            
    ------------------------------------------------------------------ */
 
-/* stage1 (main) executable */
-static Int vgexecfd = -1;
-
-/* our argc/argv */
-static Int  vg_argc;
-static Char **vg_argv;
+/* This should get some address inside the stack on which we gained
+   control (eg, it could be the SP at startup).  It doesn't matter
+   exactly where in the stack it is.  This value is passed to the
+   address space manager at startup, which uses it to identify the
+   initial stack segment and hence the upper end of the usable address
+   space. */
+static Addr sp_at_startup_new = 0;
 
 
 /*====================================================================*/
@@ -151,369 +141,38 @@ static void print_all_stats ( void )
 /*====================================================================*/
 
 /* Look for our AUXV table */
-static int scan_auxv(void* init_sp)
+static void scan_auxv(void* init_sp)
 {
    struct ume_auxv *auxv = VG_(find_auxv)((UWord*)init_sp);
-   int padfile = -1, found = 0;
 
-   for (; auxv->a_type != AT_NULL; auxv++)
+   for (; auxv->a_type != AT_NULL; auxv++) {
       switch(auxv->a_type) {
-      case AT_UME_PADFD:
-        padfile = auxv->u.a_val;
-        found |= 1;
-        break;
-
-      case AT_UME_EXECFD:
-        vgexecfd = auxv->u.a_val;
-        found |= 2;
-        break;
-
-#     if defined(VGP_ppc32_linux)
-      case AT_DCACHEBSIZE:
-      case AT_ICACHEBSIZE:
-      case AT_UCACHEBSIZE:
-         if (auxv->u.a_val > 0) {
-            VG_(cache_line_size_ppc32) = auxv->u.a_val;
-            VG_(debugLog)(1, "main", 
-                             "PPC32 cache line size %u (type %u)\n", 
-                             (UInt)auxv->u.a_val, (UInt)auxv->a_type );
-         }
-         break;
-
-      case AT_HWCAP:
-         VG_(debugLog)(1, "main", "PPC32 hwcaps: 0x%x\n", (UInt)auxv->u.a_val);
-         if ((auxv->u.a_val & 0x10000000) > 0)
-            VG_(have_altivec_ppc) = 1;
-         VG_(debugLog)(1, "main", "PPC32 AltiVec support: %u\n", VG_(have_altivec_ppc));
-         break;
-#     endif
-
-      case AT_PHDR:
-         VG_(valgrind_base) = VG_PGROUNDDN(auxv->u.a_val);
-         break;
-
-      default:
-         break;
-      }
-
-   if ( found != (1|2) ) {
-      fprintf(stderr, "valgrind: stage2 must be launched by stage1\n");
-      exit(127);
-   }
-   vg_assert(padfile >= 0);
-   return padfile;
-}
-
-
-/*====================================================================*/
-/*=== Address space determination                                  ===*/
-/*====================================================================*/
-
-extern char _start[];
-
-static void layout_remaining_space(Addr argc_addr, float ratio)
-{
-   SysRes res;
-   Addr   client_size, shadow_size;
-
-   // VG_(valgrind_base) should have been set by scan_auxv, but if not,
-   // this is a workable approximation
-   if (VG_(valgrind_base) == 0) {
-      VG_(valgrind_base) = VG_PGROUNDDN(&_start);
-   }
-
-   VG_(valgrind_last)  = VG_ROUNDUP(argc_addr, 0x10000) - 1; // stack
-
-   // This gives the client the largest possible address space while
-   // taking into account the tool's shadow needs.
-   client_size         = VG_ROUNDDN((VG_(valgrind_base)-REDZONE_SIZE) / (1.+ratio),
-                         CLIENT_SIZE_MULTIPLE);
-   VG_(client_base)    = 0;
-   VG_(client_end)     = VG_(client_base) + client_size;
-   /* where !FIXED mmap goes */
-   VG_(client_mapbase) = VG_(client_base) +
-         VG_PGROUNDDN((Addr)(client_size * CLIENT_HEAP_PROPORTION));
-
-   VG_(shadow_base)    = VG_(client_end) + REDZONE_SIZE;
-   VG_(shadow_end)     = VG_(valgrind_base);
-   shadow_size         = VG_(shadow_end) - VG_(shadow_base);
-
-#define SEGSIZE(a,b) ((VG_(b) - VG_(a))/(1024*1024))
-
-   if (0)
-      VG_(printf)(
-         "client_base        %p (%dMB)\n"
-         "client_mapbase     %p (%dMB)\n"
-         "client_end         %p (%dMB)\n"
-         "shadow_base        %p (%dMB)\n"
-         "shadow_end         %p\n"
-         "valgrind_base      %p (%dMB)\n"
-         "valgrind_last      %p\n",
-         VG_(client_base),       SEGSIZE(client_base,       client_mapbase),
-         VG_(client_mapbase),    SEGSIZE(client_mapbase,    client_end),
-         VG_(client_end),        SEGSIZE(client_end,        shadow_base),
-         VG_(shadow_base),       SEGSIZE(shadow_base,       shadow_end),
-         VG_(shadow_end),
-         VG_(valgrind_base),     SEGSIZE(valgrind_base,     valgrind_last),
-         VG_(valgrind_last)
-      );
-
-#undef SEGSIZE
-
-   // Ban redzone
-   res = VG_(mmap_native)((void *)VG_(client_end), REDZONE_SIZE, VKI_PROT_NONE,
-               VKI_MAP_FIXED|VKI_MAP_ANONYMOUS|VKI_MAP_PRIVATE|VKI_MAP_NORESERVE,
-               -1, 0);
-   vg_assert(!res.isError);
-
-   // Make client hole
-   res = VG_(munmap_native)((void*)VG_(client_base), client_size);
-   vg_assert(!res.isError);
-
-   // Map shadow memory.
-   // Initially all inaccessible, incrementally initialized as it is used
-   if (shadow_size != 0) {
-      res = VG_(mmap_native)((char *)VG_(shadow_base), shadow_size,
-                  VKI_PROT_NONE,
-                  VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS|VKI_MAP_FIXED|VKI_MAP_NORESERVE,
-                  -1, 0);
-      if (res.isError) {
-         fprintf(stderr, 
-          "valgrind: Could not allocate address space (%p bytes)\n"
-          "valgrind:   for shadow memory\n"
-          "valgrind: Possible causes:\n"
-          "valgrind: - For some systems (especially under RedHat 8), Valgrind\n"
-          "valgrind:   needs at least 1.5GB swap space.\n"
-          "valgrind: - Or, your virtual memory size may be limited (check\n"
-          "valgrind:   with 'ulimit -v').\n"
-          "valgrind: - Or, your system may use a kernel that provides only a\n" 
-          "valgrind:   too-small (eg. 2GB) user address space.\n"
-          , (void*)shadow_size
-         ); 
-         exit(1);
-      }
-   }
-}
-
-/*====================================================================*/
-/*=== Command line setup                                           ===*/
-/*====================================================================*/
-
-// Note that we deliberately don't free the malloc'd memory.  See comment
-// at call site.
-static char* get_file_clo(char* dir)
-{
-#  define FLEN 512
-   Int    n;
-   SysRes fd;
-   struct vki_stat s1;
-   Char* f_clo = NULL;
-   Char  filename[FLEN];
-
-   snprintf(filename, FLEN, "%s/.valgrindrc", ( NULL == dir ? "" : dir ) );
-   fd = VG_(open)(filename, 0, VKI_S_IRUSR);
-   if ( !fd.isError ) {
-      if ( 0 == VG_(fstat)(fd.val, &s1) ) {
-         f_clo = malloc(s1.st_size+1);
-         vg_assert(f_clo);
-         n = VG_(read)(fd.val, f_clo, s1.st_size);
-         if (n == -1) n = 0;
-         f_clo[n] = '\0';
-      }
-      VG_(close)(fd.val);
-   }
-   return f_clo;
-#  undef FLEN
-}
-
-static Int count_args(char* s)
-{
-   Int n = 0;
-   if (s) {
-      char* cp = s;
-      while (True) {
-         // We have alternating sequences: blanks, non-blanks, blanks...
-         // count the non-blanks sequences.
-         while ( VG_(isspace)(*cp) )    cp++;
-         if    ( !*cp )                 break;
-         n++;
-         while ( !VG_(isspace)(*cp) && *cp ) cp++;
-      }
-   }
-   return n;
-}
+#        if defined(VGP_ppc32_linux)
+         case AT_DCACHEBSIZE:
+         case AT_ICACHEBSIZE:
+         case AT_UCACHEBSIZE:
+            if (auxv->u.a_val > 0) {
+               VG_(cache_line_size_ppc32) = auxv->u.a_val;
+               VG_(debugLog)(1, "main", 
+                                "PPC32 cache line size %u (type %u)\n", 
+                                (UInt)auxv->u.a_val, (UInt)auxv->a_type );
+            }
+            break;
+         case AT_HWCAP:
+            VG_(debugLog)(1, "main", "PPC32 hwcaps: 0x%x\n", (UInt)auxv->u.a_val);
+            if (auxv->u.a_val & 0x10000000)
+               VG_(have_altivec_ppc) = 1;
+            VG_(debugLog)(1, "main", "PPC32 AltiVec support: %u\n", 
+                                     VG_(have_altivec_ppc));
+            break;
+#        endif
+         case AT_PHDR:
+            break;
 
-// Add args out of environment, skipping multiple spaces and "--" args.
-// We split 's' into multiple strings by replacing whitespace with nuls,
-// eg. "--aa --bb --cc" --> "--aa\0--bb\0--cc".  And for each new string
-// carved out of 's', we put a pointer to it in 'to'.
-static char** copy_args( char* s, char** to )
-{
-   if (s) {
-      char* cp = s;
-      while (True) {
-         // We have alternating sequences: blanks, non-blanks, blanks...
-         // copy the non-blanks sequences, and add terminating '\0'
-         while ( VG_(isspace)(*cp) )    cp++;
-         if    ( !*cp )                 break;
-         *to++ = cp;
-         while ( !VG_(isspace)(*cp) && *cp ) cp++;
-         if ( *cp ) *cp++ = '\0';            // terminate if not the last
-         if (VG_STREQ(to[-1], "--")) to--;   // undo any '--' arg
+         default:
+            break;
       }
    }
-   return to;
-}
-
-// Augment command line with arguments from environment and .valgrindrc
-// files.
-static void augment_command_line(Int* vg_argc_inout, char*** vg_argv_inout)
-{
-   int    vg_argc0 = *vg_argc_inout;
-   char** vg_argv0 = *vg_argv_inout;
-
-   // get_file_clo() allocates the return value with malloc().  We do not
-   // free f1_clo and f2_clo as they get put into vg_argv[] which must persist.
-   char*  env_clo = getenv(VALGRINDOPTS);
-   char*  f1_clo  = get_file_clo( getenv("HOME") );
-   char*  f2_clo  = get_file_clo(".");
-
-   /* copy any extra args from file or environment, if present */
-   if ( (env_clo && *env_clo) || (f1_clo && *f1_clo) || (f2_clo && *f2_clo) ) {
-      /* ' ' separated extra options */
-      char **from;
-      char **to;
-      int orig_arg_count, env_arg_count, f1_arg_count, f2_arg_count;
-
-      for ( orig_arg_count = 0; vg_argv0[orig_arg_count]; orig_arg_count++ );
-
-      env_arg_count = count_args(env_clo);
-      f1_arg_count  = count_args(f1_clo);
-      f2_arg_count  = count_args(f2_clo);
-
-      if (0)
-        printf("extra-argc=%d %d %d\n",
-               env_arg_count, f1_arg_count, f2_arg_count);
-
-      /* +2: +1 for null-termination, +1 for added '--' */
-      from     = vg_argv0;
-      vg_argv0 = malloc( (orig_arg_count + env_arg_count + f1_arg_count 
-                          + f2_arg_count + 2) * sizeof(char **));
-      vg_assert(vg_argv0);
-      to      = vg_argv0;
-
-      /* copy argv[0] */
-      *to++ = *from++;
-
-      /* Copy extra args from env var and file, in the order: ~/.valgrindrc,
-       * $VALGRIND_OPTS, ./.valgrindrc -- more local options are put later
-       * to override less local ones. */
-      to = copy_args(f1_clo,  to);
-      to = copy_args(env_clo, to);
-      to = copy_args(f2_clo,  to);
-    
-      /* copy original arguments, stopping at command or -- */
-      while (*from) {
-        if (**from != '-')
-           break;
-        if (VG_STREQ(*from, "--")) {
-           from++;             /* skip -- */
-           break;
-        }
-        *to++ = *from++;
-      }
-
-      /* add -- */
-      *to++ = "--";
-
-      vg_argc0 = to - vg_argv0;
-
-      /* copy rest of original command line, then NULL */
-      while (*from) *to++ = *from++;
-      *to = NULL;
-   }
-
-   *vg_argc_inout = vg_argc0;
-   *vg_argv_inout = vg_argv0;
-}
-
-#define VG_CLO_SEP   '\01'
-
-static void get_command_line( int argc, char** argv,
-                              Int* vg_argc_out, Char*** vg_argv_out, 
-                                                char*** cl_argv_out )
-{
-   int    vg_argc0;
-   char** vg_argv0;
-   char** cl_argv;
-   char*  env_clo = getenv(VALGRINDCLO);
-
-   if (env_clo != NULL && *env_clo != '\0') {
-      char *cp;
-      char **cpp;
-
-      /* OK, VALGRINDCLO is set, which means we must be a child of another
-         Valgrind process using --trace-children, so we're getting all our
-         arguments from VALGRINDCLO, and the entire command line belongs to
-         the client (including argv[0]) */
-      vg_argc0 = 1;            /* argv[0] */
-      for (cp = env_clo; *cp; cp++)
-        if (*cp == VG_CLO_SEP)
-           vg_argc0++;
-
-      vg_argv0 = malloc(sizeof(char **) * (vg_argc0 + 1));
-      vg_assert(vg_argv0);
-
-      cpp = vg_argv0;
-
-      *cpp++ = "valgrind";     /* nominal argv[0] */
-      *cpp++ = env_clo;
-
-      // Replace the VG_CLO_SEP args separator with '\0'
-      for (cp = env_clo; *cp; cp++) {
-        if (*cp == VG_CLO_SEP) {
-           *cp++ = '\0';       /* chop it up in place */
-           *cpp++ = cp;
-        }
-      }
-      *cpp = NULL;
-      cl_argv = argv;
-
-   } else {
-      Bool noaugment = False;
-
-      /* Count the arguments on the command line. */
-      vg_argv0 = argv;
-
-      for (vg_argc0 = 1; vg_argc0 < argc; vg_argc0++) {
-         Char* arg = argv[vg_argc0];
-         if (arg[0] != '-') /* exe name */
-           break;
-        if (VG_STREQ(arg, "--")) { /* dummy arg */
-           vg_argc0++;
-           break;
-        }
-         VG_BOOL_CLO(arg, "--command-line-only", noaugment)
-      }
-      cl_argv = &argv[vg_argc0];
-
-      /* Get extra args from VALGRIND_OPTS and .valgrindrc files.
-         Note we don't do this if getting args from VALGRINDCLO, as 
-         those extra args will already be present in VALGRINDCLO.
-         (We also don't do it when --command-line-only=yes.) */
-      if (!noaugment)
-        augment_command_line(&vg_argc0, &vg_argv0);
-   }
-
-   if (0) {
-      Int i;
-      for (i = 0; i < vg_argc0; i++)
-         printf("vg_argv0[%d]=\"%s\"\n", i, vg_argv0[i]);
-   }
-
-   *vg_argc_out =         vg_argc0;
-   *vg_argv_out = (Char**)vg_argv0;
-   *cl_argv_out =         cl_argv;
 }
 
 
@@ -562,50 +221,68 @@ static Bool scan_colsep(char *colsep, Bool (*func)(const char *))
 
 /* Prepare the client's environment.  This is basically a copy of our
    environment, except:
-     LD_PRELOAD=$VALGRINDLIB/vgpreload_core.so:($VALGRINDLIB/vgpreload_TOOL.so:)?$LD_PRELOAD
+
+     LD_PRELOAD=$VALGRIND_LIB/vg_preload_core.so:
+                ($VALGRIND_LIB/vgpreload_TOOL.so:)?
+                $LD_PRELOAD
 
    If this is missing, then it is added.
 
-   Yummy.  String hacking in C.
+   Also, remove any binding for VALGRIND_LAUNCHER=.  The client should
+   not be able to see this.
 
    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)
+   into something table driven.  The copy is VG_(malloc)'d space.
+*/
+static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
 {
-   static const char preload_core_so[]    = "vgpreload_core.so";
-   static const char ld_preload[]         = "LD_PRELOAD=";
-   static const char valgrind_clo[]       = VALGRINDCLO "=";
-   static const int  ld_preload_len       = sizeof(ld_preload)-1;
-   static const int  valgrind_clo_len     = sizeof(valgrind_clo)-1;
-   int ld_preload_done       = 0;
-   char *preload_core_path;
-   int   preload_core_path_len;
-   int vgliblen = strlen(VG_(libdir));
-   char **cpp;
-   char **ret;
-   int envc;
-   const int preloadlen = (preload == NULL) ? 0 : strlen(preload);
-
-   // Find the vgpreload_core.so; also make room for the tool preload library
-   preload_core_path_len = sizeof(preload_core_so) + vgliblen + preloadlen + 16;
-   preload_core_path = malloc(preload_core_path_len);
-   vg_assert(preload_core_path);
-
-   if (preload)
-      snprintf(preload_core_path, preload_core_path_len, "%s/%s:%s", 
-              VG_(libdir), preload_core_so, preload);
-   else
-      snprintf(preload_core_path, preload_core_path_len, "%s/%s", 
-              VG_(libdir), preload_core_so);
-   
+   HChar* preload_core_so = "vg_preload_core.so";
+   HChar* ld_preload      = "LD_PRELOAD=";
+   HChar* v_launcher      = VALGRIND_LAUNCHER "=";
+   Int    ld_preload_len  = VG_(strlen)( ld_preload );
+   Int    v_launcher_len  = VG_(strlen)( v_launcher );
+   Bool   ld_preload_done = False;
+   Int    vglib_len       = VG_(strlen)(VG_(libdir));
+
+   HChar** cpp;
+   HChar** ret;
+   HChar*  preload_tool_path;;
+   Int     envc, i;
+
+   /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+      paths.  We might not need the space for vgpreload_<tool>.so, but it
+      doesn't hurt to over-allocate briefly.  The 16s are just cautious
+      slop. */
+   Int preload_core_path_len = vglib_len + sizeof(preload_core_so) + 16;
+   Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)   + 16;
+   Int preload_string_len    = preload_core_path_len + preload_tool_path_len;
+   HChar* preload_string     = VG_(malloc)(preload_string_len);
+   vg_assert(preload_string);
+
+   /* Determine if there's a vgpreload_<tool>.so file, and setup
+      preload_string. */
+   preload_tool_path = VG_(malloc)(preload_tool_path_len);
+   vg_assert(preload_tool_path);
+   VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+                 "%s/vgpreload_%s.so", VG_(libdir), toolname);
+   if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
+      VG_(snprintf)(preload_string, preload_string_len, "%s/%s:%s", 
+                    VG_(libdir), preload_core_so, preload_tool_path);
+   } else {
+      VG_(snprintf)(preload_string, preload_string_len, "%s/%s", 
+                    VG_(libdir), preload_core_so);
+   }
+   VG_(free)(preload_tool_path);
+
+   VG_(debugLog)(1, "main", "preload_string = %s\n", preload_string);
+
    /* Count the original size of the env */
-   envc = 0;                   /* trailing NULL */
+   envc = 0;
    for (cpp = origenv; cpp && *cpp; cpp++)
       envc++;
 
    /* Allocate a new space */
-   ret = malloc(sizeof(char *) * (envc+1+1)); /* 1 new entry + NULL */
+   ret = VG_(malloc) (sizeof(HChar *) * (envc+1+1)); /* 1 new entry + NULL */
    vg_assert(ret);
 
    /* copy it over */
@@ -617,40 +294,49 @@ static char **fix_environment(char **origenv, const char *preload)
 
    /* Walk over the new environment, mashing as we go */
    for (cpp = ret; cpp && *cpp; cpp++) {
-      if (memcmp(*cpp, ld_preload, ld_preload_len) == 0) {
-        int len = strlen(*cpp) + preload_core_path_len;
-        char *cp = malloc(len);
+      if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
+         Int len = VG_(strlen)(*cpp) + preload_string_len;
+         HChar *cp = VG_(malloc)(len);
          vg_assert(cp);
 
-        snprintf(cp, len, "%s%s:%s",
-                 ld_preload, preload_core_path, (*cpp)+ld_preload_len);
+         VG_(snprintf)(cp, len, "%s%s:%s",
+                       ld_preload, preload_string, (*cpp)+ld_preload_len);
 
-        *cpp = cp;
-        
-        ld_preload_done = 1;
-      } else if (memcmp(*cpp, valgrind_clo, valgrind_clo_len) == 0) {
-        *cpp = "";
+         *cpp = cp;
+
+         ld_preload_done = True;
       }
    }
 
    /* Add the missing bits */
    if (!ld_preload_done) {
-      int len = ld_preload_len + preload_core_path_len;
-      char *cp = malloc(len);
+      Int len = ld_preload_len + preload_string_len;
+      HChar *cp = VG_(malloc) (len);
       vg_assert(cp);
-      
-      snprintf(cp, len, "%s%s", ld_preload, preload_core_path);
-      
+
+      VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
       ret[envc++] = cp;
    }
 
-   free(preload_core_path);
+   /* ret[0 .. envc-1] is live now. */
+   /* Find and remove a binding for VALGRIND_LAUNCHER. */
+   for (i = 0; i < envc; i++)
+      if (0 == VG_(memcmp(ret[i], v_launcher, v_launcher_len)))
+         break;
+
+   if (i < envc) {
+      for (; i < envc-1; i++)
+         ret[i] = ret[i+1];
+      envc--;
+   }
+
+   VG_(free)(preload_string);
    ret[envc] = NULL;
 
    return ret;
 }
 
-extern char **environ;         /* our environment */
 
 /* Add a string onto the string table, and return its address */
 static char *copy_str(char **tab, const char *str)
@@ -663,7 +349,7 @@ static char *copy_str(char **tab, const char *str)
    *cp++ = '\0';
 
    if (0)
-      printf("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
+      VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
 
    *tab = cp;
 
@@ -676,7 +362,7 @@ static char *copy_str(char **tab, const char *str)
 
    The format of the stack is:
 
-   higher address +-----------------+
+   higher address +-----------------+ <- clstack_end
                  | Trampoline code |
                  +-----------------+
                   |                 |
@@ -700,10 +386,18 @@ static char *copy_str(char **tab, const char *str)
                   | undefined       |
                  :                 :
  */
-static Addr setup_client_stack(void* init_sp,
-                               char **orig_argv, char **orig_envp, 
-                              const struct exeinfo *info,
-                               UInt** client_auxv)
+
+/* Allocate and create the initial client stack.  It is allocated down
+   from clstack_end, which was previously determined by the address
+   space manager.  A modified version of our auxv is copied into the
+   new stack.  The returned value is the SP value for the client. */
+static 
+Addr setup_client_stack( void*  init_sp,
+                         char** orig_envp, 
+                         const struct exeinfo *info,
+                         UInt** client_auxv,
+                         Addr   clstack_end,
+                         SizeT  clstack_max_size )
 {
    SysRes res;
    char **cpp;
@@ -715,10 +409,15 @@ static Addr setup_client_stack(void* init_sp,
    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 */
+   Int argc;                   /* total argc */
+   Int envc;                   /* total number of env vars */
    unsigned stacksize;         /* total client stack size */
-   Addr cl_esp;                        /* client stack base (initial esp) */
+   Addr client_SP;             /* client stack base (initial SP) */
+   Addr clstack_start;
+   Int i;
+   Bool have_exename;
+
+   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
 
    /* use our own auxv as a prototype */
    orig_auxv = VG_(find_auxv)(init_sp);
@@ -726,38 +425,42 @@ static Addr setup_client_stack(void* init_sp,
    /* ==================== compute sizes ==================== */
 
    /* first of all, work out how big the client stack will be */
-   stringsize = 0;
+   stringsize   = 0;
+   have_exename = VG_(args_the_exename) != NULL;
 
    /* paste on the extra args if the loader needs them (ie, the #! 
       interpreter and its argument) */
    argc = 0;
    if (info->interp_name != NULL) {
       argc++;
-      stringsize += strlen(info->interp_name) + 1;
+      stringsize += VG_(strlen)(info->interp_name) + 1;
    }
    if (info->interp_args != NULL) {
       argc++;
-      stringsize += strlen(info->interp_args) + 1;
+      stringsize += VG_(strlen)(info->interp_args) + 1;
    }
 
    /* now scan the args we're given... */
-   for (cpp = orig_argv; *cpp; cpp++) {
+   if (have_exename)
+      stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
+
+   for (i = 0; i < VG_(args_for_client).used; i++) {
       argc++;
-      stringsize += strlen(*cpp) + 1;
+      stringsize += VG_(strlen)( VG_(args_for_client).strs[i] ) + 1;
    }
-   
+
    /* ...and the environment */
    envc = 0;
    for (cpp = orig_envp; cpp && *cpp; cpp++) {
       envc++;
-      stringsize += strlen(*cpp) + 1;
+      stringsize += VG_(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->u.a_ptr) + 1;
+        stringsize += VG_(strlen)(cauxv->u.a_ptr) + 1;
       auxsize += sizeof(*cauxv);
    }
 
@@ -767,64 +470,104 @@ static Addr setup_client_stack(void* init_sp,
 
    /* OK, now we know how big the client stack is */
    stacksize =
-      sizeof(Word) +                   /* argc */
-      sizeof(char **)*argc +           /* argv */
-      sizeof(char **) +                        /* terminal NULL */
-      sizeof(char **)*envc +           /* envp */
-      sizeof(char **) +                        /* terminal NULL */
-      auxsize +                                /* auxv */
-      VG_ROUNDUP(stringsize, sizeof(Word)) +/* strings (aligned) */
-      VKI_PAGE_SIZE;                   /* page for trampoline code */
+      sizeof(Word) +                          /* argc */
+      (have_exename ? sizeof(char **) : 0) +  /* argc[0] == exename */
+      sizeof(char **)*argc +                  /* argv */
+      sizeof(char **) +                              /* terminal NULL */
+      sizeof(char **)*envc +                  /* envp */
+      sizeof(char **) +                              /* terminal NULL */
+      auxsize +                               /* auxv */
+      VG_ROUNDUP(stringsize, sizeof(Word)) +  /* strings (aligned) */
+      VKI_PAGE_SIZE;                   /* page for trampoline code */
 
    if (0) VG_(printf)("stacksize = %d\n", stacksize);
 
-   // decide where stack goes!
-   VG_(clstk_end) = VG_(client_end);
-
-   /* cl_esp is the client's stack pointer */
-   cl_esp = VG_(clstk_end) - stacksize;
-   cl_esp = VG_ROUNDDN(cl_esp, 16); /* make stack 16 byte aligned */
+   /* client_SP is the client's stack pointer */
+   client_SP = clstack_end - stacksize;
+   client_SP = VG_ROUNDDN(client_SP, 16); /* make stack 16 byte aligned */
 
    /* base of the string table (aligned) */
-   stringbase = strtab = (char *)(VG_(clstk_end) 
-                         - VG_ROUNDUP(stringsize, sizeof(int)));
-
-   VG_(clstk_base) = VG_PGROUNDDN(cl_esp);
-
-   if (0)
-      printf("stringsize=%d auxsize=%d stacksize=%d\n"
-             "clstk_base %p\n"
-             "clstk_end  %p\n",
-            stringsize, auxsize, stacksize,
-             (void*)VG_(clstk_base), (void*)VG_(clstk_end));
+   stringbase = strtab = (char *)clstack_end 
+                         - VG_ROUNDUP(stringsize, sizeof(int));
 
-   /* ==================== allocate space ==================== */
+   clstack_start = VG_PGROUNDDN(client_SP);
 
-   /* allocate a stack - mmap enough space for the stack */
-   res = VG_(mmap_native)((void *)VG_PGROUNDDN(cl_esp), 
-              VG_(clstk_end) - VG_PGROUNDDN(cl_esp),
-             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 
-             VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS|VKI_MAP_FIXED, -1, 0);
-   vg_assert(!res.isError); 
+   /* The max stack size */
+   clstack_max_size = VG_PGROUNDUP(clstack_max_size);
 
-   /* ==================== copy client stack ==================== */
+   /* Record stack extent -- needed for stack-change code. */
+   VG_(clstk_base) = clstack_start;
+   VG_(clstk_end)  = clstack_end;
 
-   ptr = (Addr*)cl_esp;
+   if (0)
+      VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
+                  "clstack_start %p\n"
+                  "clstack_end   %p\n",
+                 stringsize, auxsize, stacksize, (Int)clstack_max_size,
+                  (void*)clstack_start, (void*)clstack_end);
 
-   /* --- argc --- */
-   *ptr++ = argc;              /* client argc */
+   /* ==================== allocate space ==================== */
 
-   /* --- argv --- */
+   { SizeT anon_size   = clstack_end - clstack_start + 1;
+     SizeT resvn_size  = clstack_max_size - anon_size;
+     Addr  anon_start  = clstack_start;
+     Addr  resvn_start = anon_start - resvn_size;
+     SizeT inner_HACK  = 0;
+
+     vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+     vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+     vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+     vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+     vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
+
+#    ifdef ENABLE_INNER
+     inner_HACK = 1024*1024; // create 1M non-fault-extending stack
+#    endif
+
+     if (0)
+        VG_(printf)("%p 0x%x  %p 0x%x\n", 
+                    resvn_start, resvn_size, anon_start, anon_size);
+
+     /* Create a shrinkable reservation followed by an anonymous
+        segment.  Together these constitute a growdown stack. */
+     Bool ok = VG_(am_create_reservation)(
+                  resvn_start,
+                  resvn_size -inner_HACK,
+                  SmUpper, 
+                  anon_size +inner_HACK
+               );
+     vg_assert(ok);
+     /* allocate a stack - mmap enough space for the stack */
+     res = VG_(am_mmap_anon_fixed_client)(
+              anon_start -inner_HACK,
+              anon_size +inner_HACK,
+             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC
+          );
+     vg_assert(!res.isError); 
+   }
+
+   /* ==================== create client stack ==================== */
+
+   ptr = (Addr*)client_SP;
+
+   /* --- client argc --- */
+   *ptr++ = argc + (have_exename ? 1 : 0);
+
+   /* --- client argv --- */
    if (info->interp_name) {
       *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
-      free(info->interp_name);
+      VG_(free)(info->interp_name);
    }
    if (info->interp_args) {
       *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
-      free(info->interp_args);
+      VG_(free)(info->interp_args);
    }
-   for (cpp = orig_argv; *cpp; ptr++, cpp++) {
-      *ptr = (Addr)copy_str(&strtab, *cpp);
+
+   if (have_exename)
+      *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
+
+   for (i = 0; i < VG_(args_for_client).used; i++) {
+      *ptr++ = (Addr)copy_str(&strtab, VG_(args_for_client).strs[i]);
    }
    *ptr++ = 0;
 
@@ -879,7 +622,6 @@ static Addr setup_client_stack(void* init_sp,
         break;
 
       case AT_IGNORE:
-      case AT_EXECFD:
       case AT_PHENT:
       case AT_PAGESZ:
       case AT_FLAGS:
@@ -926,7 +668,7 @@ static Addr setup_client_stack(void* init_sp,
       default:
         /* stomp out anything we don't know about */
         if (0)
-           printf("stomping auxv entry %lld\n", (ULong)auxv->a_type);
+           VG_(printf)("stomping auxv entry %lld\n", (ULong)auxv->a_type);
         auxv->a_type = AT_IGNORE;
         break;
         
@@ -937,173 +679,115 @@ static Addr setup_client_stack(void* init_sp,
 
    vg_assert((strtab-stringbase) == stringsize);
 
-   /* We know the initial ESP is pointing at argc/argv */
-   VG_(client_argc) = *(Int*)cl_esp;
-   VG_(client_argv) = (Char**)(cl_esp + sizeof(HWord));
+   /* client_SP is pointing at client's argc/argv */
 
-   if (0) VG_(printf)("startup SP = %p\n", cl_esp);
-   return cl_esp;
+   if (0) VG_(printf)("startup SP = %p\n", client_SP);
+   return client_SP;
 }
 
+
+/* Allocate the client data segment.  It is an expandable anonymous
+   mapping abutting a shrinkable reservation of size max_dseg_size.
+   The data segment starts at VG_(brk_base), which is page-aligned,
+   and runs up to VG_(brk_limit), which isn't. */
+
+static void setup_client_dataseg ( SizeT max_size )
+{
+   Bool   ok;
+   SysRes sres;
+   Addr   anon_start  = VG_(brk_base);
+   SizeT  anon_size   = VKI_PAGE_SIZE;
+   Addr   resvn_start = anon_start + anon_size;
+   SizeT  resvn_size  = max_size - anon_size;
+
+   vg_assert(VG_IS_PAGE_ALIGNED(anon_size));
+   vg_assert(VG_IS_PAGE_ALIGNED(resvn_size));
+   vg_assert(VG_IS_PAGE_ALIGNED(anon_start));
+   vg_assert(VG_IS_PAGE_ALIGNED(resvn_start));
+
+   /* Because there's been no brk activity yet: */
+   vg_assert(VG_(brk_base) == VG_(brk_limit));
+
+   /* Try to create the data seg and associated reservation where
+      VG_(brk_base) says. */
+   ok = VG_(am_create_reservation)( 
+           resvn_start, 
+           resvn_size, 
+           SmLower, 
+           anon_size
+        );
+
+   if (!ok) {
+      /* Hmm, that didn't work.  Well, let aspacem suggest an address
+         it likes better, and try again with that. */
+      anon_start = VG_(am_get_advisory_client_simple)
+                      ( 0/*floating*/, anon_size+resvn_size, &ok );
+      if (ok) {
+         resvn_start = anon_start + anon_size;
+         ok = VG_(am_create_reservation)( 
+                 resvn_start, 
+                 resvn_size, 
+                 SmLower, 
+                 anon_size
+              );
+         if (ok)
+            VG_(brk_base) = VG_(brk_limit) = anon_start;
+      }
+      /* that too might have failed, but if it has, we're hosed: there
+         is no Plan C. */
+   }
+   vg_assert(ok);
+
+   sres = VG_(am_mmap_anon_fixed_client)( 
+             anon_start, 
+             anon_size, 
+             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC 
+          );
+   vg_assert(!sres.isError);
+   vg_assert(sres.val == anon_start);
+}
+
+
+
 /*====================================================================*/
 /*=== Find executable                                              ===*/
 /*====================================================================*/
 
-static const char* executable_name;
+/* Need a static copy because can't use dynamic mem allocation yet */
+static HChar executable_name[VKI_PATH_MAX];
 
-static Bool match_executable(const char *entry) {
-   char buf[strlen(entry) + strlen(executable_name) + 3];
+static Bool match_executable(const char *entry) 
+{
+   HChar buf[VG_(strlen)(entry) + VG_(strlen)(executable_name) + 3];
 
    /* empty PATH element means . */
    if (*entry == '\0')
       entry = ".";
 
-   snprintf(buf, sizeof(buf), "%s/%s", entry, executable_name);
-   
-   if (access(buf, R_OK|X_OK) == 0) {
-      executable_name = strdup(buf);
-      vg_assert(NULL != executable_name);
+   VG_(snprintf)(buf, sizeof(buf), "%s/%s", entry, executable_name);
+   if (VG_(access)(buf, True/*r*/, False/*w*/, True/*x*/) == 0) {
+      VG_(strncpy)( executable_name, buf, VKI_PATH_MAX-1 );
+      executable_name[VKI_PATH_MAX-1] = 0;
       return True;
    }
    return False;
 }
 
-static const char* find_executable(const char* exec)
+static HChar* find_executable ( HChar* exec )
 {
    vg_assert(NULL != exec);
-   executable_name = exec;
-   if (strchr(executable_name, '/') == NULL) {
+   VG_(strncpy)( executable_name, exec, VKI_PATH_MAX-1 );
+   executable_name[VKI_PATH_MAX-1] = 0;
+
+   if (VG_(strchr)(executable_name, '/') == NULL) {
       /* no '/' - we need to search the path */
-      char *path = getenv("PATH");
+      HChar *path = VG_(getenv)("PATH");
       scan_colsep(path, match_executable);
    }
    return executable_name;
 }
 
 
-/*====================================================================*/
-/*=== Loading tools                                                ===*/
-/*====================================================================*/
-
-static void list_tools(void)
-{
-   DIR *dir = opendir(VG_(libdir));
-   struct dirent *de;
-   int first = 1;
-
-   if (dir == NULL) {
-      fprintf(stderr, "Can't open %s: %s (installation problem?)\n",
-              VG_(libdir), strerror(errno));
-      return;
-   }
-
-   while ((de = readdir(dir)) != NULL) {
-      int len = strlen(de->d_name);
-
-      /* look for vgtool_TOOL.so names */
-      if (len > (7+1+3) &&   /* "vgtool_" + at least 1-char toolname + ".so" */
-         strncmp(de->d_name, "vgtool_", 7) == 0 &&
-         VG_STREQ(de->d_name + len - 3, ".so")) {
-         if (first) {
-            fprintf(stderr, "Available tools:\n");
-            first = 0;
-         }
-         de->d_name[len-3] = '\0';
-         fprintf(stderr, "\t%s\n", de->d_name+7);
-      }
-   }
-
-   closedir(dir);
-
-   if (first)
-      fprintf(stderr, "No tools available in \"%s\" (installation problem?)\n",
-             VG_(libdir));
-}
-
-
-/* Find and load a tool, and check it looks ok.  Also looks to see if there's 
- * a matching vgpreload_*.so file, and returns its name in *preloadpath. */
-static void load_tool( const char *toolname,
-                       ToolInfo** toolinfo_out, char **preloadpath_out )
-{
-   Bool      ok;
-   int       len = strlen(VG_(libdir)) + strlen(toolname) + 16;
-   char      buf[len];
-   void*     handle;
-   ToolInfo* toolinfo;
-   char*     preloadpath = NULL;
-
-   // XXX: allowing full paths for --tool option -- does it make sense?
-   // Doesn't allow for vgpreload_<tool>.so.
-
-   if (strchr(toolname, '/') != 0) {
-      /* toolname contains '/', and so must be a pathname */
-      handle = dlopen(toolname, RTLD_NOW);
-   } else {
-      /* just try in the libdir */
-      snprintf(buf, len, "%s/vgtool_%s.so", VG_(libdir), toolname);
-      handle = dlopen(buf, RTLD_NOW);
-
-      if (handle != NULL) {
-        snprintf(buf, len, "%s/vgpreload_%s.so", VG_(libdir), toolname);
-        if (access(buf, R_OK) == 0) {
-           preloadpath = strdup(buf);
-            vg_assert(NULL != preloadpath);
-         }
-      }
-   }
-
-   ok = (NULL != handle);
-   if (!ok) {
-      fprintf(stderr, "Can't open tool \"%s\": %s\n", toolname, dlerror());
-      goto bad_load;
-   }
-
-   toolinfo = dlsym(handle, "vgPlain_tool_info");
-   ok = (NULL != toolinfo);
-   if (!ok) {
-      fprintf(stderr, "Tool \"%s\" doesn't define its ToolInfo - "
-                      "add VG_DETERMINE_INTERFACE_VERSION?\n", toolname);
-      goto bad_load;
-   }
-
-   ok = (toolinfo->sizeof_ToolInfo == sizeof(*toolinfo) &&
-         toolinfo->interface_version == VG_CORE_INTERFACE_VERSION &&
-         toolinfo->tl_pre_clo_init != NULL);
-   if (!ok) { 
-      fprintf(stderr, "Error:\n"
-              "  Tool and core interface versions do not match.\n"
-              "  Interface version used by core is: %d (size %d)\n"
-              "  Interface version used by tool is: %d (size %d)\n"
-              "  The version numbers must match.\n",
-              VG_CORE_INTERFACE_VERSION, 
-              (Int)sizeof(*toolinfo),
-              toolinfo->interface_version,
-              toolinfo->sizeof_ToolInfo);
-      fprintf(stderr, "  You need to at least recompile, and possibly update,\n");
-      if (VG_CORE_INTERFACE_VERSION > toolinfo->interface_version)
-         fprintf(stderr, "  your tool to work with this version of Valgrind.\n");
-      else
-         fprintf(stderr, "  your version of Valgrind to work with this tool.\n");
-      goto bad_load;
-   }
-
-   vg_assert(NULL != toolinfo);
-   *toolinfo_out    = toolinfo;
-   *preloadpath_out = preloadpath;
-   return;
-
-
- bad_load:
-   if (handle != NULL)
-      dlclose(handle);
-
-   fprintf(stderr, "valgrind: couldn't load tool\n");
-   list_tools();
-   exit(127);
-}
-
-
 /*====================================================================*/
 /*=== Command line errors                                          ===*/
 /*====================================================================*/
@@ -1143,110 +827,40 @@ static void config_error ( Char* msg )
 /*=== Loading the client                                           ===*/
 /*====================================================================*/
 
-static void load_client(char* cl_argv[], const char* exec, Int need_help,
-                 /*out*/struct exeinfo* info, /*out*/Addr* client_eip)
+/* Load the client whose name is VG_(argv_the_exename). */
+
+static void load_client ( /*OUT*/struct exeinfo* info, 
+                          /*OUT*/Addr* client_eip)
 {
-   // If they didn't specify an executable with --exec, and didn't specify 
-   // --help, then use client argv[0] (searching $PATH if necessary).
-   if (NULL == exec && !need_help) {
-      if (cl_argv[0] == NULL || 
-          ( NULL == (exec = find_executable(cl_argv[0])) ) )
-      {
-         missing_prog();
-      }
-   }
+   HChar* exec;
+   Int    ret;
+   SysRes res;
 
-   info->map_base = VG_(client_mapbase);
+   vg_assert( VG_(args_the_exename) != NULL);
+   exec = find_executable( VG_(args_the_exename) );
+
+   VG_(memset)(info, 0, sizeof(*info));
    info->exe_base = VG_(client_base);
    info->exe_end  = VG_(client_end);
-   info->argv     = cl_argv;
 
-   if (need_help) {
-      VG_(clexecfd) = -1;
-      // Totally zero 'info' before continuing.
-      VG_(memset)(info, 0, sizeof(*info));
-   } else {
-      Int ret;
-      /* HACK: assumes VG_(open) always succeeds */
-      VG_(clexecfd) = VG_(open)(exec, VKI_O_RDONLY, VKI_S_IRUSR)
-                      .val;
-      ret = VG_(do_exec)(exec, info);
-      if (ret != 0) {
-         fprintf(stderr, "valgrind: do_exec(%s) failed: %s\n",
-                         exec, strerror(ret));
-         exit(127);
-      }
+   ret = VG_(do_exec)(exec, info);
+   if (ret != 0) {
+      VG_(printf)("valgrind: do_exec(%s) failed: %s\n",
+                  exec, VG_(strerror)(ret));
+      VG_(exit)(127);
    }
 
+   /* Get hold of a file descriptor which refers to the client
+      executable.  This is needed for attaching to GDB. */
+   res = VG_(open)(exec, VKI_O_RDONLY, VKI_S_IRUSR);
+   if (!res.isError)
+      VG_(cl_exec_fd) = res.val;
+
    /* Copy necessary bits of 'info' that were filled in */
    *client_eip = info->init_eip;
-   VG_(brk_base) = VG_(brk_limit) = info->brkbase;
+   VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase);
 }
 
-/*====================================================================*/
-/*=== Address space unpadding                                      ===*/
-/*====================================================================*/
-
-typedef struct {
-   char*            killpad_start;
-   char*            killpad_end;
-   struct vki_stat* killpad_padstat;
-} killpad_extra;
-
-static int killpad(char *segstart, char *segend, const char *perm, off_t off, 
-                   int maj, int min, int ino, void* ex)
-{
-   killpad_extra* extra = ex;
-   void *b, *e;
-   SysRes res;
-
-   vg_assert(NULL != extra->killpad_padstat);
-
-   if (extra->killpad_padstat->st_dev != makedev(maj, min) || 
-       extra->killpad_padstat->st_ino != ino)
-      return 1;
-   
-   if (segend <= extra->killpad_start || segstart >= extra->killpad_end)
-      return 1;
-   
-   if (segstart <= extra->killpad_start)
-      b = extra->killpad_start;
-   else
-      b = segstart;
-   
-   if (segend >= extra->killpad_end)
-      e = extra->killpad_end;
-   else
-      e = segend;
-   
-   res = VG_(munmap_native)(b, (char *)e-(char *)b);
-   vg_assert(!res.isError);
-   
-   return 1;
-}
-
-// Remove padding of 'padfile' from a range of address space.
-static void as_unpad(void *start, void *end, int padfile)
-{
-   static struct vki_stat padstat;
-   killpad_extra extra;
-   int res;
-
-   vg_assert(padfile >= 0);
-   
-   res = VG_(fstat)(padfile, &padstat);
-   vg_assert(0 == res);
-   extra.killpad_padstat = &padstat;
-   extra.killpad_start   = start;
-   extra.killpad_end     = end;
-   VG_(foreach_map)(killpad, &extra);
-}
-
-static void as_closepadfile(int padfile)
-{
-   int res = close(padfile);
-   vg_assert(0 == res);
-}
 
 /*====================================================================*/
 /*=== Command-line: variables, processing, etc                     ===*/
@@ -1254,7 +868,7 @@ static void as_closepadfile(int padfile)
 
 // See pub_{core,tool}_options.h for explanations of all these.
 
-static void usage ( Bool debug_help )
+static void usage_NORETURN ( Bool debug_help )
 {
    Char* usage1 = 
 "usage: valgrind --tool=<toolname> [options] prog-and-args\n"
@@ -1277,7 +891,8 @@ static void usage ( Bool debug_help )
 "\n"
 "  uncommon user options for all Valgrind tools:\n"
 "    --run-libc-freeres=no|yes free up glibc memory at exit? [yes]\n"
-"    --weird-hacks=hack1,hack2,...  recognised hacks: lax-ioctls,ioctl-mmap [none]\n"
+"    --weird-hacks=hack1,hack2,...  known hacks: lax-ioctls,ioctl-mmap\n"
+"                                                enable-outer [none]\n"
 "    --pointercheck=no|yes     enforce client address space limits [yes]\n"
 "    --show-emwarns=no|yes     show warnings about emulation limits? [no]\n"
 "    --smc-check=none|stack|all  checks for self-modifying code: none,\n"
@@ -1380,37 +995,41 @@ static void usage ( Bool debug_help )
    VG_(exit)(0);
 }
 
-static void pre_process_cmd_line_options
-      ( Int* need_help, const char** tool, const char** exec )
-{
-   UInt i;
 
-   LibVEX_default_VexControl(& VG_(clo_vex_control));
+/* Peer at previously set up VG_(args_for_valgrind) and extract any
+   request for help and also the tool name. */
+
+static void get_helprequest_and_toolname ( Int* need_help, HChar** tool )
+{
+   UInt   i;
+   HChar* str;
 
    /* parse the options we have (only the options we care about now) */
-   for (i = 1; i < vg_argc; i++) {
+   for (i = 0; i < VG_(args_for_valgrind).used; i++) {
 
-      if (strcmp(vg_argv[i], "--version") == 0) {
-         printf("valgrind-" VERSION "\n");
-         exit(0);
+      str = VG_(args_for_valgrind).strs[i];
+      vg_assert(str);
 
-      } else if (VG_CLO_STREQ(vg_argv[i], "--help") ||
-                 VG_CLO_STREQ(vg_argv[i], "-h")) {
+      if (VG_STREQ(str, "--version")) {
+         VG_(printf)("valgrind-" VERSION "\n");
+         VG_(exit)(0);
+
+      } else if (VG_CLO_STREQ(str, "--help") ||
+                 VG_CLO_STREQ(str, "-h")) {
          *need_help = 1;
 
-      } else if (VG_CLO_STREQ(vg_argv[i], "--help-debug")) {
+      } else if (VG_CLO_STREQ(str, "--help-debug")) {
          *need_help = 2;
 
-      } else if (VG_CLO_STREQN(7, vg_argv[i], "--tool=")) {
-        *tool = &vg_argv[i][7];
-        
-      } else if (VG_CLO_STREQN(7, vg_argv[i], "--exec=")) {
-        *exec = &vg_argv[i][7];
+      // The tool has already been determined, but we need to know the name
+      // here.
+      } else if (VG_CLO_STREQN(7, str, "--tool=")) {
+         *tool = &str[7];
       }
    }
 }
 
-static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
+static Bool process_cmd_line_options( UInt* client_auxv, const char* toolname )
 {
    SysRes sres;
    Int    i, eventually_log_fd;
@@ -1430,10 +1049,10 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
      config_error("Please use absolute paths in "
                   "./configure --prefix=... or --libdir=...");
 
-   for (i = 1; i < vg_argc; i++) {
+   for (i = 0; i < VG_(args_for_valgrind).used; i++) {
 
-      Char* arg = vg_argv[i];
-      Char* colon = arg;
+      HChar* arg   = VG_(args_for_valgrind).strs[i];
+      HChar* colon = arg;
 
       /* Look for a colon in the switch name */
       while (*colon && *colon != ':' && *colon != '=')
@@ -1448,7 +1067,7 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
             // prefix matches, convert "--toolname:foo" to "--foo"
             if (0)
                VG_(printf)("tool-specific arg: %s\n", arg);
-            arg = strdup(arg + toolname_len + 1);
+            arg = VG_(strdup)(arg + toolname_len + 1);
             arg[0] = '-';
             arg[1] = '-';
 
@@ -1460,7 +1079,6 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
       
       /* Ignore these options - they've already been handled */
       if (VG_CLO_STREQN( 7, arg, "--tool="))              goto skip_arg;
-      if (VG_CLO_STREQN( 7, arg, "--exec="))              goto skip_arg;
       if (VG_CLO_STREQN(20, arg, "--command-line-only=")) goto skip_arg;
 
       if (     VG_CLO_STREQ(arg, "--"))                  goto skip_arg;
@@ -1630,8 +1248,9 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
          VG_(bad_option)(arg);
       }
     skip_arg:
-      if (arg != vg_argv[i])
-         free(arg);
+      if (arg != VG_(args_for_valgrind).strs[i]) {
+         VG_(free)(arg);
+      }
    }
 
    /* Make VEX control parameters sane */
@@ -1830,8 +1449,8 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
 
 
    /* Check that the requested tool actually supports XML output. */
-   if (VG_(clo_xml) && 0 != VG_(strcmp)(toolname, "memcheck")
-                    && 0 != VG_(strcmp)(toolname, "none")) {
+   if (VG_(clo_xml) && !VG_STREQ(toolname, "memcheck")
+                    && !VG_STREQ(toolname, "none")) {
       VG_(clo_xml) = False;
       VG_(message)(Vg_UserMsg, 
          "Currently only Memcheck|None supports XML output."); 
@@ -1852,11 +1471,34 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
       VG_(fcntl)(VG_(clo_log_fd), VKI_F_SETFD, VKI_FD_CLOEXEC);
    }
 
-   /* Ok, the logging sink is running now.  Print a suitable preamble.
-      If logging to file or a socket, write details of parent PID and
-      command line args, to help people trying to interpret the
-      results of a run which encompasses multiple processes. */
+   if (VG_(clo_n_suppressions) < VG_CLO_MAX_SFILES-1 &&
+       (VG_(needs).core_errors || VG_(needs).tool_errors)) {
+      /* If we haven't reached the max number of suppressions, load
+         the default one. */
+      static const Char default_supp[] = "default.supp";
+      Int len = VG_(strlen)(VG_(libdir)) + 1 + sizeof(default_supp);
+      Char *buf = VG_(arena_malloc)(VG_AR_CORE, len);
+      VG_(sprintf)(buf, "%s/%s", VG_(libdir), default_supp);
+      VG_(clo_suppressions)[VG_(clo_n_suppressions)] = buf;
+      VG_(clo_n_suppressions)++;
+   }
+
+   return (log_to == VgLogTo_Fd);
+}
+
 
+/*====================================================================*/
+/*=== Printing the preamble                                        ===*/
+/*====================================================================*/
+
+/* Ok, the logging sink is running now.  Print a suitable preamble.
+   If logging to file or a socket, write details of parent PID and
+   command line args, to help people trying to interpret the
+   results of a run which encompasses multiple processes. */
+static void print_preamble(Bool logging_to_fd, const char* toolname)
+{
+   Int i;
+   
    if (VG_(clo_xml)) {
       VG_(message)(Vg_UserMsg, "<?xml version=\"1.0\"?>");
       VG_(message)(Vg_UserMsg, "");
@@ -1900,17 +1542,20 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
          "%sCopyright (C) 2000-2005, and GNU GPL'd, by Julian Seward et al.%s",
          xpre, xpost );
 
+      if (VG_(clo_verbosity) == 1 && !VG_(clo_xml))
+         VG_(message)(Vg_UserMsg, "For more details, rerun with: -v");
+
       if (VG_(clo_xml))
          VG_(message)(Vg_UserMsg, "</preamble>");
    }
 
-   if (!VG_(clo_xml) && VG_(clo_verbosity) > 0 && log_to != VgLogTo_Fd) {
+   if (!VG_(clo_xml) && VG_(clo_verbosity) > 0 && !logging_to_fd) {
       VG_(message)(Vg_UserMsg, "");
       VG_(message)(Vg_UserMsg, 
          "My PID = %d, parent PID = %d.  Prog and args are:",
          VG_(getpid)(), VG_(getppid)() );
-      for (i = 0; i < VG_(client_argc); i++) 
-         VG_(message)(Vg_UserMsg, "   %s", VG_(client_argv)[i]);
+      for (i = 0; i < VG_(args_for_client).used; i++) 
+         VG_(message)(Vg_UserMsg, "   %s", VG_(args_for_client).strs[i]);
       if (VG_(clo_log_file_qualifier)) {
          HChar* val = VG_(getenv)(VG_(clo_log_file_qualifier));
          VG_(message)(Vg_UserMsg, "");
@@ -1941,35 +1586,50 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
       }
       VG_(message)(Vg_UserMsg, "");
       VG_(message)(Vg_UserMsg, "<args>");
+
       VG_(message)(Vg_UserMsg, "  <vargv>");
-      for (i = 0; i < vg_argc; i++) {
-         HChar* tag = i==0 ? "exe" : "arg";
-         VG_(message)(Vg_UserMsg, "    <%s>%t</%s>", 
-                                  tag, vg_argv[i], tag);
+      if (VG_(name_of_launcher))
+         VG_(message)(Vg_UserMsg, "    <exe>%t</exe>", 
+                                  VG_(name_of_launcher));
+      for (i = 0; i < VG_(args_for_valgrind).used; i++) {
+         VG_(message)(Vg_UserMsg, 
+                      "    <arg>%t</arg>", 
+                      VG_(args_for_valgrind).strs[i]);
       }
       VG_(message)(Vg_UserMsg, "  </vargv>");
+
       VG_(message)(Vg_UserMsg, "  <argv>");
-      for (i = 0; i < VG_(client_argc); i++) {
-         HChar* tag = i==0 ? "exe" : "arg";
-         VG_(message)(Vg_UserMsg, "    <%s>%t</%s>", 
-                                  tag, VG_(client_argv)[i], tag);
+      if (VG_(args_the_exename))
+         VG_(message)(Vg_UserMsg, "    <exe>%t</exe>", 
+                                  VG_(args_the_exename));
+      for (i = 0; i < VG_(args_for_client).used; i++) {
+         VG_(message)(Vg_UserMsg, "    <arg>%t</arg>", 
+                                  VG_(args_for_client).strs[i]);
       }
       VG_(message)(Vg_UserMsg, "  </argv>");
+
       VG_(message)(Vg_UserMsg, "</args>");
    }
 
+   // Empty line after the preamble
+   if (VG_(clo_verbosity) > 0)
+      VG_(message)(Vg_UserMsg, "");
+
    if (VG_(clo_verbosity) > 1) {
       SysRes fd;
-      if (log_to != VgLogTo_Fd)
+      if (!logging_to_fd)
          VG_(message)(Vg_DebugMsg, "");
       VG_(message)(Vg_DebugMsg, "Valgrind library directory: %s", VG_(libdir));
+
       VG_(message)(Vg_DebugMsg, "Command line");
-      for (i = 0; i < VG_(client_argc); i++)
-         VG_(message)(Vg_DebugMsg, "   %s", VG_(client_argv)[i]);
+      if (VG_(args_the_exename))
+         VG_(message)(Vg_DebugMsg, "   %s", VG_(args_the_exename));
+      for (i = 0; i < VG_(args_for_client).used; i++)
+         VG_(message)(Vg_DebugMsg, "   %s", VG_(args_for_client).strs[i]);
 
       VG_(message)(Vg_DebugMsg, "Startup, with flags:");
-      for (i = 1; i < vg_argc; i++) {
-         VG_(message)(Vg_DebugMsg, "   %s", vg_argv[i]);
+      for (i = 0; i < VG_(args_for_valgrind).used; i++) {
+         VG_(message)(Vg_DebugMsg, "   %s", VG_(args_for_valgrind).strs[i]);
       }
 
       VG_(message)(Vg_DebugMsg, "Contents of /proc/version:");
@@ -1991,87 +1651,6 @@ static void process_cmd_line_options( UInt* client_auxv, const char* toolname )
 #        undef BUF_LEN
       }
    }
-
-   if (VG_(clo_n_suppressions) < VG_CLO_MAX_SFILES-1 &&
-       (VG_(needs).core_errors || VG_(needs).tool_errors)) {
-      /* If we haven't reached the max number of suppressions, load
-         the default one. */
-      static const Char default_supp[] = "default.supp";
-      Int len = VG_(strlen)(VG_(libdir)) + 1 + sizeof(default_supp);
-      Char *buf = VG_(arena_malloc)(VG_AR_CORE, len);
-      VG_(sprintf)(buf, "%s/%s", VG_(libdir), default_supp);
-      VG_(clo_suppressions)[VG_(clo_n_suppressions)] = buf;
-      VG_(clo_n_suppressions)++;
-   }
-}
-
-// Build the string for VALGRINDCLO.
-Char* VG_(build_child_VALGRINDCLO)( Char* exename )
-{
-   /* If we're tracing the children, then we need to start it
-      with our starter+arguments, which are copied into VALGRINDCLO,
-      except the --exec= option is changed if present.
-   */
-   Int i;
-   Char *exec;
-   Char *cp;
-   Char *optvar;
-   Int  optlen, execlen;
-
-   // All these allocated blocks are not free - because we're either
-   // going to exec, or panic when we fail.
-
-   // Create --exec= option: "--exec=<exename>"
-   exec = VG_(arena_malloc)(VG_AR_CORE, 
-                            VG_(strlen)( exename ) + 7/*--exec=*/ + 1/*\0*/);
-   vg_assert(NULL != exec);
-   VG_(sprintf)(exec, "--exec=%s", exename);
-
-   // Allocate space for optvar (may overestimate by counting --exec twice,
-   // no matter)
-   optlen = 1;
-   for (i = 0; i < vg_argc; i++)
-      optlen += VG_(strlen)(vg_argv[i]) + 1;
-   optlen += VG_(strlen)(exec)+1;
-   optvar = VG_(arena_malloc)(VG_AR_CORE, optlen);
-
-   // Copy all valgrind args except the old --exec (if present)
-   // VG_CLO_SEP is the separator.
-   cp = optvar;
-   for (i = 1; i < vg_argc; i++) {
-      Char *arg = vg_argv[i];
-      
-      if (VG_(memcmp)(arg, "--exec=", 7) == 0) {
-         // don't copy existing --exec= arg
-      } else if (VG_(strcmp)(arg, "--") == 0) {
-         // stop at "--"
-         break;
-      } else {
-         // copy non "--exec" arg
-         Int len = VG_(strlen)(arg);
-         VG_(memcpy)(cp, arg, len);
-         cp += len;
-         *cp++ = VG_CLO_SEP;
-      }
-   }
-   // Add the new --exec= option
-   execlen = VG_(strlen)(exec);
-   VG_(memcpy)(cp, exec, execlen);
-   cp += execlen;
-   *cp++ = VG_CLO_SEP;
-
-   *cp = '\0';
-
-   return optvar;
-}
-
-// Build "/proc/self/fd/<execfd>".
-Char* VG_(build_child_exename)( void )
-{
-   Char* exename = VG_(arena_malloc)(VG_AR_CORE, 64);
-   vg_assert(NULL != exename);
-   VG_(sprintf)(exename, "/proc/self/fd/%d", vgexecfd);
-   return exename;
 }
 
 
@@ -2103,121 +1682,10 @@ static void setup_file_descriptors(void)
    /* Update the soft limit. */
    VG_(setrlimit)(VKI_RLIMIT_NOFILE, &rl);
 
-   if (vgexecfd != -1)
-      vgexecfd = VG_(safe_fd)( vgexecfd );
-   if (VG_(clexecfd) != -1)
-      VG_(clexecfd) = VG_(safe_fd)( VG_(clexecfd) );
+   if (VG_(cl_exec_fd) != -1)
+      VG_(cl_exec_fd) = VG_(safe_fd)( VG_(cl_exec_fd) );
 }
 
-/*====================================================================*/
-/*===  Initialise program data/text, etc.                          ===*/
-/*====================================================================*/
-
-static void build_valgrind_map_callback ( Addr start, SizeT size, UInt prot,
-                                         UInt dev, UInt ino, ULong foffset, 
-                                         const UChar* filename )
-{
-   /* Only record valgrind mappings for now, without loading any
-      symbols.  This is so we know where the free space is before we
-      start allocating more memory (note: heap is OK, it's just mmap
-      which is the problem here). */
-   if (start >= VG_(client_end) && start < VG_(valgrind_last)) {
-      VG_(debugLog)(2, "main",
-                    "valgrind-seg: %p-%p prot 0x%x file=%s\n",
-                    (void*)start, (void*)(start+size), prot, filename);
-      VG_(map_file_segment)(start, size, prot,
-                            SF_MMAP|SF_NOSYMS|SF_VALGRIND,
-                            dev, ino, foffset, filename);
-      /* update VG_(valgrind_last) if it looks wrong */
-      if (start+size > VG_(valgrind_last))
-         VG_(valgrind_last) = start+size-1;
-   }
-}
-
-// Global var used to pass local data to callback
-Addr sp_at_startup___global_arg = 0;
-
-/* 
-   This second pass adds in client mappings, and loads symbol tables
-   for all interesting mappings.  The trouble is that things can
-   change as we go, because we're calling the Tool to track memory as
-   we find it.
-
-   So for Valgrind mappings, we don't replace any mappings which
-   aren't still identical (which will include the .so mappings, so we
-   will load their symtabs)>
- */
-static void build_segment_map_callback ( Addr start, SizeT size, UInt prot,
-                                        UInt dev, UInt ino, ULong foffset,
-                                        const UChar* filename )
-{
-   UInt flags;
-   Bool is_stack_segment;
-   Addr r_esp;
-
-   is_stack_segment 
-      = (start == VG_(clstk_base) && (start+size) == VG_(clstk_end));
-
-   VG_(debugLog)(2, "main",
-                 "any-seg: %p-%p prot 0x%x stack=%d file=%s\n",
-                 (void*)start, (void*)(start+size), prot, is_stack_segment, 
-                 filename);
-
-   if (is_stack_segment)
-      flags = SF_STACK | SF_GROWDOWN;
-   else
-      flags = SF_MMAP;
-
-   if (filename != NULL)
-      flags |= SF_FILE;
-
-#if 0
-   // This needs to be fixed properly.   jrs 20050307
-   if (start >= VG_(client_end) && start < VG_(valgrind_last)) {
-      Segment *s = VG_(find_segment_before)(start);
-
-      /* We have to be a bit careful about inserting new mappings into
-        the Valgrind part of the address space.  We're actively
-        changing things as we parse these mappings, particularly in
-        shadow memory, and so we don't want to overwrite those
-        changes.  Therefore, we only insert/update a mapping if it is
-        mapped from a file or it exactly matches an existing mapping.
-
-        NOTE: we're only talking about the Segment list mapping
-        metadata; this doesn't actually mmap anything more. */
-      if (filename || (s && s->addr == start && s->len == size)) {
-        flags |= SF_VALGRIND;
-        VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
-      } else {
-        /* assert range is already mapped */
-        vg_assert(VG_(is_addressable)(start, size, VKI_PROT_NONE));
-      }
-   } else
-#endif
-      VG_(map_file_segment)(start, size, prot, flags, dev, ino, foffset, filename);
-
-   if (VG_(is_client_addr)(start) && VG_(is_client_addr)(start+size-1)) {
-          VG_TRACK( new_mem_startup, start, size,
-                    !!(prot & VKI_PROT_READ), 
-                     !!(prot & VKI_PROT_WRITE), 
-                     !!(prot & VKI_PROT_EXEC));
-   }
-
-   /* If this is the stack segment mark all below %esp as noaccess. */
-   r_esp = sp_at_startup___global_arg;
-   vg_assert(0 != r_esp);
-   if (is_stack_segment) {
-      if (0) {
-         VG_(message)(Vg_DebugMsg, "invalidating stack area: %p .. %p",
-                      start,r_esp);
-         VG_(message)(Vg_DebugMsg, "  validating stack area: %p .. %p",
-                      r_esp, start+size);
-      }
-      VG_TRACK( die_mem_stack, start, r_esp-start );
-      // what's this for?
-      //VG_TRACK( post_mem_write, r_esp, (start+size)-r_esp );
-   }
-}
 
 /*====================================================================*/
 /*===  Initialise the first thread.                                ===*/
@@ -2367,90 +1835,77 @@ void show_BB_profile ( BBProfEntry tops[], UInt n_tops, ULong score_total )
 /*=== main()                                                       ===*/
 /*====================================================================*/
 
-/*
-  This code decides on the layout of the client and Valgrind address
-  spaces, loads valgrind.so and the tool.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 tools :
-                | (may be 0 sized)        |
-  shadow_end     +-------------------------+
-  valgrind_base  +-------------------------+
-                 | kickstart executable    |
-                 | valgrind heap  vvvvvvvvv| (barely used)
-                 -                         -
-                 | valgrind .so files      |
-                | and mappings            |
-                 -                         -
-                 | valgrind stack ^^^^^^^^^|
-  valgrind_last  +-------------------------+
-                : kernel                  :
-
-  Nb: Before we can do general allocations with VG_(arena_malloc)() and
-  VG_(mmap)(), we need to build the segment skip-list, so we know where
-  we can put things.  However, building that structure requires
-  allocating memory.  So we need to a bootstrapping process.  It's done
-  by making VG_(arena_malloc)() have a special static superblock that's
-  used for the first 1MB's worth of allocations.  This is enough to
-  build the segment skip-list.
-*/
-
+/* TODO: GIVE THIS A PROPER HOME
+   TODO: MERGE THIS WITH DUPLICATE IN mac_leakcheck.c
+   Extract from aspacem a vector of the current segment start
+   addresses.  The vector is dynamically allocated and should be freed
+   by the caller when done.  REQUIRES m_mallocfree to be running.
+   Writes the number of addresses required into *n_acquired. */
 
-/* This may be needed before m_mylibc is OK to run. */
-static Int local_strcmp ( const HChar* s1, const HChar* s2 )
+static Addr* get_seg_starts ( /*OUT*/Int* n_acquired )
 {
-   while (True) {
-      if (*s1 == 0 && *s2 == 0) return 0;
-      if (*s1 == 0) return -1;
-      if (*s2 == 0) return 1;
+   Addr* starts;
+   Int   n_starts, r;
 
-      if (*(UChar*)s1 < *(UChar*)s2) return -1;
-      if (*(UChar*)s1 > *(UChar*)s2) return 1;
+   n_starts = 1;
+   while (True) {
+      starts = VG_(malloc)( n_starts * sizeof(Addr) );
+      if (starts == NULL)
+         break;
+      r = VG_(am_get_segment_starts)( starts, n_starts );
+      if (r >= 0)
+         break;
+      VG_(free)(starts);
+      n_starts *= 2;
+   }
 
-      s1++; s2++;
+   if (starts == NULL) {
+     *n_acquired = 0;
+     return NULL;
    }
+
+   *n_acquired = r;
+   return starts;
 }
 
 
-int main(int argc, char **argv, char **envp)
+/* When main() is entered, we should be on the following stack, not
+   the one the kernel gave us.  We will run on this stack until
+   simulation of the root thread is started, at which point a transfer
+   is made to a dynamically allocated stack.  This is for the sake of
+   uniform overflow detection for all Valgrind threads. */
+
+VgStack VG_(the_root_stack);
+
+
+Int main(Int argc, HChar **argv, HChar **envp)
 {
-   char **cl_argv;
-   const char *tool = "memcheck";   // default to Memcheck
-   const char *exec = NULL;
-   char *preload;          /* tool-specific LD_PRELOAD .so */
-   char **env;
-   Int need_help = 0;      // 0 = no, 1 = --help, 2 = --help-debug
-   struct exeinfo info;
-   ToolInfo *toolinfo = NULL;
-   Addr client_eip;
-   Addr sp_at_startup;     /* client's SP at the point we gained control. */
-   UInt * client_auxv;
+   HChar*  toolname          = "memcheck";    // default to Memcheck
+   HChar** env               = NULL;
+   Int     need_help         = 0; // 0 = no, 1 = --help, 2 = --help-debug
+   Addr    initial_client_IP = 0;
+   Addr    initial_client_SP = 0;
+   Addr    clstack_top       = 0;
+   SizeT   clstack_max_size  = 0;
+   UInt*   client_auxv;
+   Int     loglevel, i;
+   Bool    logging_to_fd;
    struct vki_rlimit zero = { 0, 0 };
-   Int padfile, loglevel, i;
+   struct exeinfo info;
 
    //============================================================
-   // Nb: startup is complex.  Prerequisites are shown at every step.
    //
+   // Nb: startup is complex.  Prerequisites are shown at every step.
    // *** Be very careful when messing with the order ***
+   //
+   // The first order of business is to get debug logging, the address
+   // space manager and the dynamic memory manager up and running.
+   // Once that's done, we can relax a bit.
+   //
    //============================================================
+   
+   /* This is needed to make VG_(getenv) usable early. */
+   VG_(client_envp) = (Char**)envp;
 
    //--------------------------------------------------------------
    // Start up the logging mechanism
@@ -2462,25 +1917,96 @@ int main(int argc, char **argv, char **envp)
    for (i = 1; i < argc; i++) {
       if (argv[i][0] != '-')
          break;
-      if (0 == local_strcmp(argv[i], "--")) 
+      if (VG_STREQ(argv[i], "--")) 
          break;
-      if (0 == local_strcmp(argv[i], "-d")) 
+      if (VG_STREQ(argv[i], "-d")) 
          loglevel++;
    }
 
    /* ... and start the debug logger.  Now we can safely emit logging
       messages all through startup. */
    VG_(debugLog_startup)(loglevel, "Stage 2 (main)");
+   VG_(debugLog)(1, "main", "Welcome to Valgrind version " 
+                            VERSION " debug logging\n");
+
+   //--------------------------------------------------------------
+   // Ensure we're on a plausible stack.
+   //   p: logging
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Checking current stack is plausible\n");
+   { HChar* limLo  = (HChar*)(&VG_(the_root_stack).bytes[0]);
+     HChar* limHi  = limLo + sizeof(VG_(the_root_stack));
+     HChar* aLocal = (HChar*)&zero; /* any auto local will do */
+     if (aLocal < limLo || aLocal >= limHi) {
+        /* something's wrong.  Stop. */
+        VG_(debugLog)(0, "main", "Root stack %p to %p, a local %p\n",
+                          limLo, limHi, aLocal );
+        VG_(debugLog)(0, "main", "Valgrind: FATAL: "
+                                 "Initial stack switched failed.\n");
+        VG_(debugLog)(0, "main", "   Cannot continue.  Sorry.\n");
+        VG_(exit)(1);
+     }
+   }
+
+   //--------------------------------------------------------------
+   // Ensure we have a plausible pointer to the stack on which
+   // we gained control (not the current stack!)
+   //   p: logging
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Checking initial stack was noted\n");
+   if (sp_at_startup_new == 0) {
+      VG_(debugLog)(0, "main", "Valgrind: FATAL: "
+                               "Initial stack was not noted.\n");
+      VG_(debugLog)(0, "main", "   Cannot continue.  Sorry.\n");
+      VG_(exit)(1);
+   }
+
+   //--------------------------------------------------------------
+   // Start up the address space manager, and determine the
+   // approximate location of the client's stack
+   //   p: logging, plausible-stack
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Starting the address space manager\n");
+   clstack_top = VG_(am_startup)( sp_at_startup_new );
+   VG_(debugLog)(1, "main", "Address space manager is running\n");
+
+   //--------------------------------------------------------------
+   // Start up the dynamic memory manager
+   //   p: address space management
+   //   In fact m_mallocfree is self-initialising, so there's no
+   //   initialisation call to do.  Instead, try a simple malloc/
+   //   free pair right now to check that nothing is broken.
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Starting the dynamic memory manager\n");
+   { void* p = VG_(malloc)( 12345 );
+     if (p) VG_(free)( p );
+   }
+   VG_(debugLog)(1, "main", "Dynamic memory manager is running\n");
 
    //============================================================
-   // Command line argument handling order:
-   // * If --help/--help-debug are present, show usage message 
-   //   (including the tool-specific usage)
-   // * (If no --tool option given, default to Memcheck)
-   // * Then, if client is missing, abort with error msg
-   // * Then, if any cmdline args are bad, abort with error msg
+   //
+   // Dynamic memory management is now available.
+   //
    //============================================================
 
+   //--------------------------------------------------------------
+   // Look for alternative libdir                                  
+   { HChar *cp = VG_(getenv)(VALGRIND_LIB);
+     if (cp != NULL)
+        VG_(libdir) = cp;
+   }
+
+   //--------------------------------------------------------------
+   // Extract the launcher name from the environment.
+   VG_(debugLog)(1, "main", "Getting stage1's name\n");
+   VG_(name_of_launcher) = VG_(getenv)(VALGRIND_LAUNCHER);
+   if (VG_(name_of_launcher) == NULL) {
+      VG_(printf)("valgrind: You cannot run '%s' directly.\n", argv[0]);
+      VG_(printf)("valgrind: You should use $prefix/bin/valgrind.\n");
+      VG_(exit)(1);
+   }
+
+   //--------------------------------------------------------------
    // Get the current process datasize rlimit, and set it to zero.
    // This prevents any internal uses of brk() from having any effect.
    // We remember the old value so we can restore it on exec, so that
@@ -2495,119 +2021,126 @@ int main(int argc, char **argv, char **envp)
    //--------------------------------------------------------------
    // Check we were launched by stage1
    //   p: none
+   // TODO: this is pretty pointless now.  Plus, we shouldn't be
+   // screwing with our own auxv: instead, when our own auxv is
+   // used as the basis for the client's one, make modifications
+   // at that point.
    //--------------------------------------------------------------
    VG_(debugLog)(1, "main", "Doing scan_auxv()\n");
-   {
-   void* init_sp = argv - 1;
-   padfile = scan_auxv(init_sp);
+   { void* init_sp = argv - 1;
+     scan_auxv(init_sp);
    }
 
-   //--------------------------------------------------------------
-   // Look for alternative libdir                                  
-   //   p: none
-   //--------------------------------------------------------------
-   {  HChar *cp = getenv(VALGRINDLIB);
-      if (cp != NULL)
-        VG_(libdir) = cp;
-   }
+   //============================================================
+   // Command line argument handling order:
+   // * If --help/--help-debug are present, show usage message 
+   //   (including the tool-specific usage)
+   // * (If no --tool option given, default to Memcheck)
+   // * Then, if client is missing, abort with error msg
+   // * Then, if any cmdline args are bad, abort with error msg
+   //============================================================
 
    //--------------------------------------------------------------
-   // Get valgrind args + client args (inc. from VALGRIND_OPTS/.valgrindrc).
-   // Pre-process the command line.
-   //   p: none
+   // Split up argv into: C args, V args, V extra args, and exename.
+   //   p: dynamic memory allocation
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Preprocess command line opts\n");
-   get_command_line(argc, argv, &vg_argc, &vg_argv, &cl_argv);
-   pre_process_cmd_line_options(&need_help, &tool, &exec);
-
-   /* If this process was created by exec done by another Valgrind
-      process, the arguments will only show up at this point.  Hence
-      we need to also snoop around in vg_argv to see if anyone is
-      asking for debug logging. */
-   if (loglevel == 0) {
-      for (i = 1; i < vg_argc; i++) {
-         if (vg_argv[i][0] != '-')
-            break;
-         if (0 == local_strcmp(vg_argv[i], "--")) 
-            break;
-         if (0 == local_strcmp(vg_argv[i], "-d")) 
-            loglevel++;
-      }
-      VG_(debugLog_startup)(loglevel, "Stage 2 (second go)");
+   VG_(debugLog)(1, "main", "Split up command line\n");
+   VG_(split_up_argv)( argc, argv );
+   if (0) {
+      for (i = 0; i < VG_(args_for_valgrind).used; i++)
+         VG_(printf)("varg %s\n", VG_(args_for_valgrind).strs[i]);
+      VG_(printf)(" exe %s\n", VG_(args_the_exename));
+      for (i = 0; i < VG_(args_for_client).used; i++)
+         VG_(printf)("carg %s\n", VG_(args_for_client).strs[i]);
    }
 
-   //==============================================================
-   // Nb: once a tool is specified, the tool.so must be loaded even if 
-   // they specified --help or didn't specify a client program.
-   //==============================================================
-
    //--------------------------------------------------------------
-   // With client padded out, map in tool
-   //   p: set-libdir                     [for VG_(libdir)]
-   //   p: pre_process_cmd_line_options() [for 'tool']
+   // Extract tool name and whether help has been requested.
+   // Note we can't print the help message yet, even if requested,
+   // because the tool has not been initialised.
+   //   p: split_up_argv [for VG_(args_for_valgrind)]
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Loading tool\n");
-   load_tool(tool, &toolinfo, &preload);
+   VG_(debugLog)(1, "main", "Preprocess command line opts\n");
+   get_helprequest_and_toolname(&need_help, &toolname);
 
-   //==============================================================
-   // Can use VG_(malloc)() and VG_(arena_malloc)() only after load_tool()
-   // -- redzone size is now set.  This is checked by vg_malloc2.c.
-   //==============================================================
-   
-   //--------------------------------------------------------------
-   // Finalise address space layout
-   //   p: load_tool()  [for 'toolinfo']
-   //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Laying out remaining space\n");
-   layout_remaining_space( (Addr) & argc, toolinfo->shadow_ratio );
+   // Set default vex control params
+   LibVEX_default_VexControl(& VG_(clo_vex_control));
 
    //--------------------------------------------------------------
    // Load client executable, finding in $PATH if necessary
-   //   p: pre_process_cmd_line_options()  [for 'exec', 'need_help']
+   //   p: get_helprequest_and_toolname()  [for 'exec', 'need_help']
    //   p: layout_remaining_space          [so there's space]
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Loading client\n");
-   load_client(cl_argv, exec, need_help, &info, &client_eip);
+   if (!need_help) {
+      VG_(debugLog)(1, "main", "Loading client\n");
 
-   //--------------------------------------------------------------
-   // Everything in place, remove padding done by stage1
-   //   p: layout_remaining_space()  [everything must be mapped in before now]  
-   //   p: load_client()             [ditto] 
-   //--------------------------------------------------------------
-   as_unpad((void *)VG_(shadow_end), (void *)~0, padfile);
-   as_closepadfile(padfile);  // no more padding
+      if (VG_(args_the_exename) == NULL)
+         missing_prog();
+
+      load_client(&info, &initial_client_IP);
+   }
 
    //--------------------------------------------------------------
    // Set up client's environment
-   //   p: set-libdir  [for VG_(libdir)]
-   //   p: load_tool() [for 'preload']
+   //   p: set-libdir                   [for VG_(libdir)]
+   //   p: get_helprequest_and_toolname [for toolname]
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Setup client env\n");
-   env = fix_environment(envp, preload);
+   if (!need_help) {
+      VG_(debugLog)(1, "main", "Setup client env\n");
+      env = setup_client_env(envp, toolname);
+   }
 
    //--------------------------------------------------------------
    // Setup client stack, eip, and VG_(client_arg[cv])
    //   p: load_client()     [for 'info']
    //   p: fix_environment() [for 'env']
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Setup client stack\n");
-   { 
-   void* init_sp = argv - 1;
+   if (!need_help) {
+      void* init_sp = argv - 1;
+      SizeT m1 = 1024 * 1024;
+      SizeT m8 = 8 * m1;
+      VG_(debugLog)(1, "main", "Setup client stack\n");
+      clstack_max_size = (SizeT)VG_(client_rlimit_stack).rlim_cur;
+      if (clstack_max_size < m1) clstack_max_size = m1;
+      if (clstack_max_size > m8) clstack_max_size = m8;
+      clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+      initial_client_SP
+         = setup_client_stack( init_sp, env, 
+                               &info, &client_auxv, 
+                               clstack_top, clstack_max_size );
+
+      VG_(free)(env);
 
-   sp_at_startup = setup_client_stack(init_sp, cl_argv, env, &info,
-                                      &client_auxv);
-   free(env);
+      VG_(debugLog)(2, "main",
+                       "Client info: "
+                       "entry=%p client_SP=%p brkbase=%p\n",
+                       (void*)initial_client_IP, 
+                       (void*)initial_client_SP,
+                       (void*)VG_(brk_base) );
    }
 
-   VG_(debugLog)(2, "main",
-                    "Client info: "
-                    "entry=%p client esp=%p vg_argc=%d brkbase=%p\n",
-                    (void*)client_eip, (void*)sp_at_startup, vg_argc, 
-                    (void*)VG_(brk_base) );
+   //--------------------------------------------------------------
+   // Setup client data (brk) segment.  Initially a 1-page segment
+   // which abuts a shrinkable reservation. 
+   //     p: load_client()     [for 'info' and hence VG_(brk_base)]
+   //--------------------------------------------------------------
+   if (!need_help) { 
+      SizeT m1 = 1024 * 1024;
+      SizeT m8 = 8 * m1;
+      SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur;
+      VG_(debugLog)(1, "main", "Setup client data (brk) segment\n");
+      if (dseg_max_size < m1) dseg_max_size = m1;
+      if (dseg_max_size > m8) dseg_max_size = m8;
+      dseg_max_size = VG_PGROUNDUP(dseg_max_size);
+
+      setup_client_dataseg( dseg_max_size );
+   }
 
    //==============================================================
-   // Finished setting up operating environment.  Now initialise
-   // Valgrind.  (This is where the old VG_(main)() started.)
+   //
+   // Finished loading/setting up the client address space.
+   //
    //==============================================================
 
    //--------------------------------------------------------------
@@ -2618,58 +2151,122 @@ int main(int argc, char **argv, char **envp)
    setup_file_descriptors();
 
    //--------------------------------------------------------------
-   // Build segment map (Valgrind segments only)
-   //   p: tl_pre_clo_init()  [to setup new_mem_startup tracker]
+   // create the fake /proc/<pid>/cmdline file and then unlink it,
+   // but hold onto the fd, so we can hand it out to the client
+   // when it tries to open /proc/<pid>/cmdline for itself.
+   //   p: setup file descriptors
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Parse /proc/self/maps (round 1)\n");
-   VG_(parse_procselfmaps) ( build_valgrind_map_callback );
+   if (!need_help) {
+      HChar  buf[50], buf2[50+64];
+      HChar  nul[1];
+      Int    fd, r;
+      HChar* exename;
+
+      VG_(debugLog)(1, "main", "Create fake /proc/<pid>/cmdline\n");
+
+      VG_(sprintf)(buf, "proc_%d_cmdline", VG_(getpid)());
+      fd = VG_(mkstemp)( buf, buf2 );
+      if (fd == -1)
+         config_error("Can't create client cmdline file in /tmp.");
+
+      nul[0] = 0;
+      exename = VG_(args_the_exename) ? VG_(args_the_exename)
+                                      : "unknown_exename";
+
+      VG_(write)(fd, VG_(args_the_exename), 
+                     VG_(strlen)( VG_(args_the_exename) ));
+      VG_(write)(fd, nul, 1);
+
+      for (i = 0; i < VG_(args_for_client).used; i++) {
+         VG_(write)(fd, VG_(args_for_client).strs[i],
+                        VG_(strlen)( VG_(args_for_client).strs[i] ));
+         VG_(write)(fd, nul, 1);
+      }
 
-   //==============================================================
-   // Can use VG_(arena_malloc)() with non-CORE arena after segments set up
-   //==============================================================
+      /* Don't bother to seek the file back to the start; instead do
+        it every time a copy of it is given out (by PRE(sys_open)). 
+        That is probably more robust across fork() etc. */
+
+      /* Now delete it, but hang on to the fd. */
+      r = VG_(unlink)( buf2 );
+      if (r)
+         config_error("Can't delete client cmdline file in /tmp.");
+
+      VG_(cl_cmdline_fd) = fd;
+   }
 
    //--------------------------------------------------------------
-   // Init tool: pre_clo_init, process cmd line, post_clo_init
+   // Init tool part 1: pre_clo_init
    //   p: setup_client_stack()      [for 'VG_(client_arg[cv]']
-   //   p: load_tool()               [for 'toolinfo']
    //   p: setup_file_descriptors()  [for 'VG_(fd_xxx_limit)']
-   //   p: parse_procselfmaps        [so VG segments are setup so tool can
-   //                                 call VG_(malloc)]
    //--------------------------------------------------------------
    {
       Char* s;
       Bool  ok;
-      VG_(debugLog)(1, "main", "Initialise the tool\n");
-      (*toolinfo->tl_pre_clo_init)();
-      ok = VG_(sanity_check_needs)( VG_(shadow_base) != VG_(shadow_end), &s );
+      VG_(debugLog)(1, "main", "Initialise the tool part 1 (pre_clo_init)\n");
+      (VG_(tool_info).tl_pre_clo_init)();
+      ok = VG_(sanity_check_needs)( &s );
       if (!ok) {
          VG_(tool_panic)(s);
       }
    }
 
+   //--------------------------------------------------------------
    // If --tool and --help/--help-debug was given, now give the core+tool
    // help message
+   //   p: get_helprequest_and_toolname() [for 'need_help']
+   //   p: tl_pre_clo_init                [for 'VG_(tdict).usage']
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Print help and quit, if requested\n");
    if (need_help) {
-      usage(/*--help-debug?*/2 == need_help);
+      usage_NORETURN(/*--help-debug?*/2 == need_help);
    }
-   process_cmd_line_options(client_auxv, tool);
 
+   //--------------------------------------------------------------
+   // Process command line options to Valgrind + tool
+   //   p: setup_client_stack()      [for 'VG_(client_arg[cv]']
+   //   p: setup_file_descriptors()  [for 'VG_(fd_xxx_limit)']
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Process Valgrind's command line options, "
+                            " setup logging\n");
+   logging_to_fd = process_cmd_line_options(client_auxv, toolname);
+
+   //--------------------------------------------------------------
+   // Print the preamble
+   //   p: tl_pre_clo_init            [for 'VG_(details).name' and friends]
+   //   p: process_cmd_line_options() [for VG_(clo_verbosity), VG_(clo_xml),
+   //                                      VG_(clo_log_file_qualifier),
+   //                                      logging_to_fd]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Print the preamble...\n");
+   print_preamble(logging_to_fd, toolname);
+   VG_(debugLog)(1, "main", "...finished the preamble\n");
+
+   //--------------------------------------------------------------
+   // Init tool part 2: post_clo_init
+   //   p: setup_client_stack()      [for 'VG_(client_arg[cv]']
+   //   p: setup_file_descriptors()  [for 'VG_(fd_xxx_limit)']
+   //   p: print_preamble()          [so any warnings printed in post_clo_init
+   //                                 are shown after the preamble]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Initialise the tool part 2 (post_clo_init)\n");
    VG_TDICT_CALL(tool_post_clo_init);
 
    //--------------------------------------------------------------
-   // Build segment map (all segments)
-   //   p: shadow/redzone segments
-   //   p: setup_client_stack()  [for 'sp_at_startup']
-   //   p: init tool             [for 'new_mem_startup']
+   // Initialise translation table and translation cache
+   //   p: aspacem         [??]
+   //   p: tl_pre_clo_init [for 'VG_(details).avg_translation_sizeB']
    //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Parse /proc/self/maps (round 2)\n");
-   sp_at_startup___global_arg = sp_at_startup;
-   VG_(parse_procselfmaps) ( build_segment_map_callback );  /* everything */
-   sp_at_startup___global_arg = 0;
+   VG_(debugLog)(1, "main", "Initialise TT/TC\n");
+   VG_(init_tt_tc)();
 
-   //==============================================================
-   // Can use VG_(map)() after segments set up
-   //==============================================================
+   //--------------------------------------------------------------
+   // Initialise the redirect table.
+   //   p: init_tt_tc [so it can call VG_(search_transtab) safely]
+   //   p: aspacem [so can change ownership of sysinfo pages]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Initialise redirects\n");
+   VG_(setup_code_redirect_table)();
 
    //--------------------------------------------------------------
    // Allow GDB attach
@@ -2711,12 +2308,114 @@ int main(int argc, char **argv, char **envp)
       VG_(init_preopened_fds)();
    }
 
+   //--------------------------------------------------------------
+   // Load debug info for the existing segments.
+   //   p: setup_code_redirect_table [so that redirs can be recorded]
+   //   p: mallocfree
+   //   p: probably: setup fds and process CLOs, so that logging works
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Load initial debug info\n");
+   { Addr* seg_starts;
+     Int   n_seg_starts;
+
+     seg_starts = get_seg_starts( &n_seg_starts );
+     vg_assert(seg_starts && n_seg_starts > 0);
+
+     /* show them all to the debug info reader */
+     for (i = 0; i < n_seg_starts; i++)
+        VG_(di_notify_mmap)( seg_starts[i] );
+
+     VG_(free)( seg_starts );
+   }
+
+   //--------------------------------------------------------------
+   // Tell aspacem of ownership change of the asm helpers, so that
+   // m_translate allows them to be translated.  However, only do this
+   // after the initial debug info read, since making a hole in the
+   // address range for the stage2 binary confuses the debug info reader.
+   //   p: aspacem
+   //--------------------------------------------------------------
+   { Bool change_ownership_v_c_OK;
+     Addr co_start   = VG_PGROUNDDN( (Addr)&VG_(trampoline_stuff_start) );
+     Addr co_endPlus = VG_PGROUNDUP( (Addr)&VG_(trampoline_stuff_end) );
+     VG_(debugLog)(1,"redir",
+                     "transfer ownership V -> C of 0x%llx .. 0x%llx\n",
+                     (ULong)co_start, (ULong)co_endPlus-1 );
+
+     change_ownership_v_c_OK 
+        = VG_(am_change_ownership_v_to_c)( co_start, co_endPlus - co_start );
+     vg_assert(change_ownership_v_c_OK);
+   }
+
+   //--------------------------------------------------------------
+   // Tell the tool about the initial client memory permissions
+   //   p: aspacem
+   //   p: mallocfree
+   //   p: setup_client_stack
+   //   p: setup_client_dataseg
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "Tell tool about initial permissions\n");
+   { Addr*     seg_starts;
+     Int       n_seg_starts;
+     NSegment* seg;
+
+     seg_starts = get_seg_starts( &n_seg_starts );
+     vg_assert(seg_starts && n_seg_starts > 0);
+
+     /* show interesting ones to the tool */
+     for (i = 0; i < n_seg_starts; i++) {
+        seg = VG_(am_find_nsegment)( seg_starts[i] );
+        vg_assert(seg);
+        if (seg->kind == SkFileC || seg->kind == SkAnonC) {
+           VG_(debugLog)(2, "main", 
+                            "tell tool about %010lx-%010lx %c%c%c\n",
+                             seg->start, seg->end,
+                             seg->hasR ? 'r' : '-',
+                             seg->hasW ? 'w' : '-',
+                             seg->hasX ? 'x' : '-' );
+           VG_TRACK( new_mem_startup, seg->start, seg->end+1-seg->start, 
+                                      seg->hasR, seg->hasW, seg->hasX );
+        }
+     }
+
+     VG_(free)( seg_starts );
+
+     /* Also do the initial stack permissions. */
+     seg = VG_(am_find_nsegment)( initial_client_SP );
+     vg_assert(seg);
+     vg_assert(seg->kind == SkAnonC);
+     vg_assert(initial_client_SP >= seg->start);
+     vg_assert(initial_client_SP <= seg->end);
+
+     /* Stuff below the initial SP is unaddressable. */
+     /* NB: shouldn't this take into account the VG_STACK_REDZONE_SZB
+        bytes below SP?  */
+     VG_TRACK( die_mem_stack, seg->start, initial_client_SP - seg->start );
+     VG_(debugLog)(2, "main", "mark stack inaccessible %010lx-%010lx\n",
+                      seg->start, initial_client_SP-1 );
+
+     /* Also the assembly helpers. */
+     VG_TRACK( new_mem_startup,
+               (Addr)&VG_(trampoline_stuff_start),
+               &VG_(trampoline_stuff_end) - &VG_(trampoline_stuff_start),
+               False, /* readable? */
+               False, /* writable? */
+               True   /* executable? */ );
+   }
+
    //--------------------------------------------------------------
    // Initialise the scheduler
    //   p: setup_file_descriptors() [else VG_(safe_fd)() breaks]
+   //   p: setup_client_stack
    //--------------------------------------------------------------
    VG_(debugLog)(1, "main", "Initialise scheduler\n");
-   VG_(scheduler_init)();
+   { NSegment* seg = VG_(am_find_nsegment)( initial_client_SP );
+     vg_assert(seg);
+     vg_assert(seg->kind == SkAnonC);
+     vg_assert(initial_client_SP >= seg->start);
+     vg_assert(initial_client_SP <= seg->end);
+     VG_(scheduler_init)( seg->end, clstack_max_size );
+   }
 
    //--------------------------------------------------------------
    // Initialise the pthread model
@@ -2726,7 +2425,8 @@ int main(int argc, char **argv, char **envp)
    //      setup_scheduler()      [for the rest of state 1 stuff]
    //--------------------------------------------------------------
    VG_(debugLog)(1, "main", "Initialise thread 1's state\n");
-   init_thread1state(client_eip, sp_at_startup, &VG_(threads)[1].arch);
+   init_thread1state( initial_client_IP, initial_client_SP, 
+                      &VG_(threads)[1].arch);
 
    //--------------------------------------------------------------
    // Initialise the pthread model
@@ -2753,7 +2453,7 @@ int main(int argc, char **argv, char **envp)
    // vg_dummy_profile.c's?
    //
    // XXX: want this as early as possible.  Looking for --profile
-   // in pre_process_cmd_line_options() could get it earlier.
+   // in get_helprequest_and_toolname() could get it earlier.
    //--------------------------------------------------------------
    if (VG_(clo_profile))
       VG_(init_profiling)();
@@ -2769,59 +2469,29 @@ int main(int argc, char **argv, char **envp)
       VG_(load_suppressions)();
    }
 
-   //--------------------------------------------------------------
-   // Initialise translation table and translation cache
-   //   p: read_procselfmaps  [so the anonymous mmaps for the TT/TC
-   //         aren't identified as part of the client, which would waste
-   //         > 20M of virtual address space.]
-   //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Initialise TT/TC\n");
-   VG_(init_tt_tc)();
-
-   //--------------------------------------------------------------
-   // Initialise the redirect table.
-   //   p: parse_procselfmaps? [XXX for debug info?]
-   //   p: init_tt_tc [so it can call VG_(search_transtab) safely]
-   //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Initialise redirects\n");
-   VG_(setup_code_redirect_table)();
-
-   //--------------------------------------------------------------
-   // Tell the tool about permissions in our handwritten assembly
-   // helpers.
-   //   p: init tool             [for 'new_mem_startup']
-   //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Tell tool about permissions for asm helpers\n");
-   VG_TRACK( new_mem_startup,
-             (Addr)&VG_(trampoline_stuff_start),
-             &VG_(trampoline_stuff_end) - &VG_(trampoline_stuff_start),
-             False, /* readable? */
-             False, /* writable? */
-             True   /* executable? */ );
-
-   //--------------------------------------------------------------
-   // Verbosity message
-   //   p: end_rdtsc_calibration [so startup message is printed first]
-   //--------------------------------------------------------------
-   if (VG_(clo_verbosity) == 1 && !VG_(clo_xml))
-      VG_(message)(Vg_UserMsg, "For more details, rerun with: -v");
-   if (VG_(clo_verbosity) > 0)
-      VG_(message)(Vg_UserMsg, "");
-
    //--------------------------------------------------------------
    // Setup pointercheck
    //   p: layout_remaining_space() [for VG_(client_{base,end})]
    //   p: process_cmd_line_options() [for VG_(clo_pointercheck)]
    //--------------------------------------------------------------
-   if (VG_(clo_pointercheck))
-      VG_(clo_pointercheck) =
-         VG_(setup_pointercheck)( VG_(client_base), VG_(client_end));
+   //if (VG_(clo_pointercheck))
+   //   VG_(clo_pointercheck) =
+   //      VG_(setup_pointercheck)( VG_(client_base), VG_(client_end));
 
    //--------------------------------------------------------------
    // register client stack
    //--------------------------------------------------------------
    VG_(clstk_id) = VG_(register_stack)(VG_(clstk_base), VG_(clstk_end));
 
+   //--------------------------------------------------------------
+   // Show the address space state so far
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "main", "\n");
+   VG_(debugLog)(1, "main", "\n");
+   VG_(am_show_nsegments)(1,"Memory layout at client startup");
+   VG_(debugLog)(1, "main", "\n");
+   VG_(debugLog)(1, "main", "\n");
+
    //--------------------------------------------------------------
    // Run!
    //--------------------------------------------------------------
@@ -3005,6 +2675,122 @@ void VG_(shutdown_actions_NORETURN) ( ThreadId tid,
    }
 }
 
+
+/*====================================================================*/
+/*=== Getting to main() alive                                      ===*/
+/*====================================================================*/
+
+/* If linking of the final executables is done with glibc present,
+   then Valgrind starts at main() above as usual, and all of the
+   following code is irrelevant.
+
+   However, this is not the intended mode of use.  The plan is to
+   avoid linking against glibc, by giving gcc the flags 
+   -nodefaultlibs -lgcc -nostartfiles at startup.
+
+   From this derive two requirements:
+
+   1. gcc may emit calls to memcpy and memset to deal with structure
+      assignments etc.  Since we have chosen to ignore all the
+      "normal" supporting libraries, we have to provide our own
+      implementations of them.  No problem.
+
+   2. We have to provide a symbol "_start", to which the kernel
+      hands control at startup.  Hence the code below.
+*/
+
+/* ---------------- Requirement 1 ---------------- */
+
+void* memcpy(void *dest, const void *src, size_t n);
+void* memcpy(void *dest, const void *src, size_t n) {
+   return VG_(memcpy)(dest,src,n);
+}
+void* memset(void *s, int c, size_t n);
+void* memset(void *s, int c, size_t n) {
+  return VG_(memset)(s,c,n);
+}
+
+/* ---------------- Requirement 2 ---------------- */
+
+/* Glibc's sysdeps/i386/elf/start.S has the following gem of a
+   comment, which explains how the stack looks right at process start
+   (when _start is jumped to).  Hence _start passes %esp to
+   _start_in_C, which extracts argc/argv/envp and starts up
+   correctly. */
+
+/* This is the canonical entry point, usually the first thing in the text
+   segment.  The SVR4/i386 ABI (pages 3-31, 3-32) says that when the entry
+   point runs, most registers' values are unspecified, except for:
+
+   %edx         Contains a function pointer to be registered with `atexit'.
+                This is how the dynamic linker arranges to have DT_FINI
+                functions called for shared libraries that have been loaded
+                before this code runs.
+
+   %esp         The stack contains the arguments and environment:
+                0(%esp)                 argc
+                4(%esp)                 argv[0]
+                ...
+                (4*argc)(%esp)          NULL
+                (4*(argc+1))(%esp)      envp[0]
+                ...
+                                        NULL
+*/
+
+/* The kernel hands control to _start, which extracts the initial
+   stack pointer and calls onwards to _start_in_C.  This also switches the new stack.  */
+#if defined(VGP_x86_linux)
+asm("\n"
+    "\t.globl _start\n"
+    "\t.type _start,@function\n"
+    "_start:\n"
+    /* set up the new stack in %eax */
+    "\tmovl  $vgPlain_the_root_stack, %eax\n"
+    "\taddl  $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %eax\n"
+    "\taddl  $"VG_STRINGIFY(VG_STACK_ACTIVE_SZB)", %eax\n"
+    "\tsubl  $16, %eax\n"
+    "\tandl  $~15, %eax\n"
+    /* install it, and collect the original one */
+    "\txchgl %eax, %esp\n"
+    /* call _start_in_C, passing it the startup %esp */
+    "\tpushl %eax\n"
+    "\tcall  _start_in_C\n"
+    "\thlt\n"
+);
+#elif defined(VGP_amd64_linux)
+asm("\n"
+    "\t.globl _start\n"
+    "\t.type _start,@function\n"
+    "_start:\n"
+    /* set up the new stack in %rdi */
+    "\tmovq  $vgPlain_the_root_stack, %rdi\n"
+    "\taddq  $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %rdi\n"
+    "\taddq  $"VG_STRINGIFY(VG_STACK_ACTIVE_SZB)", %rdi\n"
+    "\tandq  $~15, %rdi\n"
+    /* install it, and collect the original one */
+    "\txchgq %rdi, %rsp\n"
+    /* call _start_in_C, passing it the startup %rsp */
+    "\tcall  _start_in_C\n"
+    "\thlt\n"
+);
+#else
+#error "_start: needs implementation on this platform"
+#endif
+
+/* Avoid compiler warnings: this fn _is_ used, but labelling it
+   'static' causes gcc to complain it isn't. */
+void _start_in_C ( UWord* pArgc );
+void _start_in_C ( UWord* pArgc )
+{
+   Int     r;
+   Word    argc = pArgc[0];
+   HChar** argv = (HChar**)&pArgc[1];
+   HChar** envp = (HChar**)&pArgc[1+argc+1];
+   sp_at_startup_new = (Addr)pArgc;
+   r = main( (Int)argc, argv, envp );
+   VG_(exit)(r);
+}
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
index 0bd0136599163a374cae6a7330dcf19ed4e1b8c5..0be3f1b355684945006e286baf15eea68817c264 100644 (file)
 */
 
 #include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_libcbase.h"
+#include "pub_core_aspacemgr.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_mallocfree.h"
 #include "pub_core_options.h"
@@ -416,34 +417,20 @@ void VG_(print_all_arena_stats) ( void )
 /* This library is self-initialising, as it makes this more self-contained,
    less coupled with the outside world.  Hence VG_(arena_malloc)() and
    VG_(arena_free)() below always call ensure_mm_init() to ensure things are
-   correctly initialised.  */
+   correctly initialised.  
+
+   We initialise the client arena separately (and later) because the core
+   must do non-client allocation before the tool has a chance to set the
+   client arena's redzone size.
+*/
 static
-void ensure_mm_init ( void )
+void ensure_mm_init ( ArenaId aid )
 {
-   static Bool  init_done = False;
+   static Bool     client_inited = False;
+   static Bool  nonclient_inited = False;
    static SizeT client_redzone_szB = 8;   // default: be paranoid
 
-   if (init_done) {
-      // This assertion ensures that a tool cannot try to change the client
-      // redzone size with VG_(needs_malloc_replacement)() after this module
-      // has done its first allocation.
-      if (VG_(needs).malloc_replacement)
-         vg_assert(client_redzone_szB == VG_(tdict).tool_client_redzone_szB);
-      return;
-   }
-
-   if (VG_(needs).malloc_replacement) {
-      client_redzone_szB = VG_(tdict).tool_client_redzone_szB;
-      // 128 is no special figure, just something not too big
-      if (client_redzone_szB > 128) {
-         VG_(printf)( "\nTool error:\n"
-                      "  specified redzone size is too big (%llu)\n", 
-                      (ULong)client_redzone_szB);
-         VG_(exit)(1);
-      }
-   }
-
-   /* Use checked red zones (of various sizes) for our internal stuff,
+   /* We use checked red zones (of various sizes) for our internal stuff,
       and an unchecked zone of arbitrary size for the client.  Of
       course the client's red zone can be checked by the tool, eg. 
       by using addressibility maps, but not by the mechanism implemented
@@ -456,15 +443,45 @@ void ensure_mm_init ( void )
       stays as 16 --- the extra 4 bytes in both are accounted for by the
       larger prev/next ptr.
    */
-   arena_init ( VG_AR_CORE,      "core",     4,       CORE_ARENA_MIN_SZB );
-   arena_init ( VG_AR_TOOL,      "tool",     4,                  1048576 );
-   arena_init ( VG_AR_SYMTAB,    "symtab",   4,                  1048576 );
-   arena_init ( VG_AR_CLIENT,    "client",   client_redzone_szB, 1048576 );
-   arena_init ( VG_AR_DEMANGLE,  "demangle", 4,                    65536 );
-   arena_init ( VG_AR_EXECTXT,   "exectxt",  4,                    65536 );
-   arena_init ( VG_AR_ERRORS,    "errors",   4,                    65536 );
-
-   init_done = True;
+   if (VG_AR_CLIENT == aid) {
+      if (client_inited) {
+         // This assertion ensures that a tool cannot try to change the client
+         // redzone size with VG_(needs_malloc_replacement)() after this module
+         // has done its first allocation from the client arena.
+         if (VG_(needs).malloc_replacement)
+            vg_assert(client_redzone_szB == VG_(tdict).tool_client_redzone_szB);
+         return;
+      }
+
+      // Check and set the client arena redzone size
+      if (VG_(needs).malloc_replacement) {
+         client_redzone_szB = VG_(tdict).tool_client_redzone_szB;
+         // 128 is no special figure, just something not too big
+         if (client_redzone_szB > 128) {
+            VG_(printf)( "\nTool error:\n"
+                         "  specified redzone size is too big (%llu)\n", 
+                         (ULong)client_redzone_szB);
+            VG_(exit)(1);
+         }
+      }
+      // Initialise the client arena
+      arena_init ( VG_AR_CLIENT,    "client",   client_redzone_szB, 1048576 );
+      client_inited = True;
+
+   } else {
+      if (nonclient_inited) {
+         return;
+      }
+      // Initialise the non-client arenas
+      arena_init ( VG_AR_CORE,      "core",     4,       CORE_ARENA_MIN_SZB );
+      arena_init ( VG_AR_TOOL,      "tool",     4,                  1048576 );
+      arena_init ( VG_AR_SYMTAB,    "symtab",   4,                  1048576 );
+      arena_init ( VG_AR_DEMANGLE,  "demangle", 4,                    65536 );
+      arena_init ( VG_AR_EXECTXT,   "exectxt",  4,                   262144 );
+      arena_init ( VG_AR_ERRORS,    "errors",   4,                    65536 );
+      nonclient_inited = True;
+   }
+
 #  ifdef DEBUG_MALLOC
    VG_(sanity_check_malloc_all)();
 #  endif
@@ -475,6 +492,35 @@ void ensure_mm_init ( void )
 /*--- Superblock management                                ---*/
 /*------------------------------------------------------------*/
 
+void VG_(out_of_memory_NORETURN) ( HChar* who, SizeT szB )
+{
+   static Bool alreadyCrashing = False;
+   ULong tot_alloc = VG_(am_get_anonsize_total)();
+   if (!alreadyCrashing) {
+      alreadyCrashing = True;
+      VG_(printf)("\n"
+                  "Valgrind's memory management: out of memory:\n");
+      VG_(printf)("   %s's request for %llu bytes failed.\n", 
+                  who, (ULong)szB );
+      VG_(printf)("   %llu bytes have already been allocated.\n", 
+                  tot_alloc);
+      VG_(printf)("Valgrind cannot continue.  Sorry.\n\n");
+   } else {
+      VG_(debugLog)(0,"mallocfree","\n");
+      VG_(debugLog)(0,"mallocfree",
+                      "Valgrind's memory management: out of memory:\n");
+      VG_(debugLog)(0,"mallocfree",
+                      "   %s's request for %llu bytes failed.\n", 
+                      who, (ULong)szB );
+      VG_(debugLog)(0,"mallocfree",
+                      "   %llu bytes have already been allocated.\n", 
+                      tot_alloc);
+      VG_(debugLog)(0,"mallocfree","Valgrind cannot continue.  Sorry.\n\n");
+   }
+   VG_(exit)(1);
+}
+
+
 // Align ptr p upwards to an align-sized boundary.
 static
 void* align_upwards ( void* p, SizeT align )
@@ -489,10 +535,9 @@ void* align_upwards ( void* p, SizeT align )
 static
 Superblock* newSuperblock ( Arena* a, SizeT cszB )
 {
-   // The extra VG_MIN_MALLOC_SZB bytes are for possible alignment up.
-   static UByte bootstrap_superblock[CORE_ARENA_MIN_SZB+VG_MIN_MALLOC_SZB];
-   static Bool  called_before = True; //False;
    Superblock* sb;
+   SysRes      sres;
+   NSegment*   seg;
 
    // Take into account admin bytes in the Superblock.
    cszB += sizeof(Superblock);
@@ -500,32 +545,39 @@ Superblock* newSuperblock ( Arena* a, SizeT cszB )
    if (cszB < a->min_sblock_szB) cszB = a->min_sblock_szB;
    while ((cszB % VKI_PAGE_SIZE) > 0) cszB++;
 
-   if (!called_before) {
-      // First time we're called -- use the special static bootstrap
-      // superblock (see comment at top of main() for details).
-      called_before = True;
-      vg_assert(a == arenaId_to_ArenaP(VG_AR_CORE));
-      vg_assert(CORE_ARENA_MIN_SZB >= cszB);
-      // Ensure sb is suitably aligned.
-      sb = (Superblock*)align_upwards( bootstrap_superblock, 
-                                       VG_MIN_MALLOC_SZB );
-   } else if (a->clientmem) {
+   if (a->clientmem) {
       // client allocation -- return 0 to client if it fails
-      sb = (Superblock*)VG_(get_memory_from_mmap_for_client)(cszB);
-      if (NULL == sb)
+      sres = VG_(am_mmap_anon_float_client)
+                ( cszB, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC );
+      if (sres.isError)
          return 0;
+      sb = (Superblock*)sres.val;
+      // Mark this segment as containing client heap.  The leak
+      // checker needs to be able to identify such segments so as not
+      // to use them as sources of roots during leak checks.
+      seg = VG_(am_find_nsegment)( (Addr)sb );
+      vg_assert(seg && seg->kind == SkAnonC);
+      seg->isCH = True;
    } else {
-      // non-client allocation -- aborts if it fails
-      sb = VG_(get_memory_from_mmap) ( cszB, "newSuperblock" );
+      // non-client allocation -- abort if it fails
+      sres = VG_(am_mmap_anon_float_valgrind)( cszB );
+      if (sres.isError) {
+         VG_(out_of_memory_NORETURN)("newSuperblock", cszB);
+         /* NOTREACHED */
+         sb = NULL; /* keep gcc happy */
+      } else {
+         sb = (Superblock*)sres.val;
+      }
    }
    vg_assert(NULL != sb);
    //zzVALGRIND_MAKE_WRITABLE(sb, cszB);
    vg_assert(0 == (Addr)sb % VG_MIN_MALLOC_SZB);
    sb->n_payload_bytes = cszB - sizeof(Superblock);
    a->bytes_mmaped += cszB;
-   if (0)
-      VG_(message)(Vg_DebugMsg, "newSuperblock, %d payload bytes", 
-                                sb->n_payload_bytes);
+   VG_(debugLog)(1, "mallocfree",
+                    "newSuperblock at %p (pszB %7ld) owner %s/%s\n", 
+                    sb, sb->n_payload_bytes, 
+                    a->clientmem ? "CLIENT" : "VALGRIND", a->name );
    return sb;
 }
 
@@ -901,7 +953,7 @@ void* VG_(arena_malloc) ( ArenaId aid, SizeT req_pszB )
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    vg_assert(req_pszB < MAX_PSZB);
@@ -976,7 +1028,7 @@ void* VG_(arena_malloc) ( ArenaId aid, SizeT req_pszB )
    v = get_block_payload(a, b);
    vg_assert( (((Addr)v) & (VG_MIN_MALLOC_SZB-1)) == 0 );
 
-   VALGRIND_MALLOCLIKE_BLOCK(v, req_pszB, 0, False);
+   //zzVALGRIND_MALLOCLIKE_BLOCK(v, req_pszB, 0, False);
    return v;
 }
 
@@ -994,7 +1046,7 @@ void VG_(arena_free) ( ArenaId aid, void* ptr )
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    if (ptr == NULL) {
@@ -1070,7 +1122,7 @@ void VG_(arena_free) ( ArenaId aid, void* ptr )
    sanity_check_malloc_arena(aid);
 #  endif
 
-   VALGRIND_FREELIKE_BLOCK(ptr, 0);
+   //zzVALGRIND_FREELIKE_BLOCK(ptr, 0);
 
    VGP_POPCC(VgpMalloc);
 }
@@ -1118,7 +1170,7 @@ void* VG_(arena_memalign) ( ArenaId aid, SizeT req_alignB, SizeT req_pszB )
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    vg_assert(req_pszB < MAX_PSZB);
@@ -1193,7 +1245,7 @@ void* VG_(arena_memalign) ( ArenaId aid, SizeT req_alignB, SizeT req_pszB )
 
    vg_assert( (((Addr)align_p) % req_alignB) == 0 );
 
-   VALGRIND_MALLOCLIKE_BLOCK(align_p, req_pszB, 0, False);
+   //zzVALGRIND_MALLOCLIKE_BLOCK(align_p, req_pszB, 0, False);
 
    return align_p;
 }
@@ -1215,6 +1267,7 @@ void VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi )
    VG_(memset)(mi, 0x0, sizeof(struct vg_mallinfo));
 }
 
+
 /*------------------------------------------------------------*/
 /*--- Services layered on top of malloc/free.              ---*/
 /*------------------------------------------------------------*/
@@ -1233,7 +1286,7 @@ void* VG_(arena_calloc) ( ArenaId aid, SizeT nmemb, SizeT bytes_per_memb )
 
    VG_(memset)(p, 0, size);
 
-   VALGRIND_MALLOCLIKE_BLOCK(p, size, 0, True);
+   //zzVALGRIND_MALLOCLIKE_BLOCK(p, size, 0, True);
 
    VGP_POPCC(VgpMalloc);
    
@@ -1250,7 +1303,7 @@ void* VG_(arena_realloc) ( ArenaId aid, void* ptr, SizeT req_pszB )
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    vg_assert(req_pszB < MAX_PSZB);
index 40a3275e48d095ea2b423a464f5585682fe080ae..b69572fa4268e0f0309a7c36274243c2c39e8bae 100644 (file)
@@ -31,6 +31,7 @@
 */
 
 #include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_debuginfo.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
@@ -151,7 +152,8 @@ static void add_redir_to_resolved_list(CodeRedirect *redir, Bool need_discard)
          TRACE_REDIR("Discarding translation due to redirect of already loaded function" );
          TRACE_REDIR("   %s:%s(%p) -> %p)", redir->from_lib, redir->from_sym,
                                             redir->from_addr, redir->to_addr );
-         VG_(discard_translations)((Addr64)redir->from_addr, 1);
+         VG_(discard_translations)((Addr64)redir->from_addr, 1, 
+                                   "add_redir_to_resolved_list");
       }
 
       r = VG_(SkipList_Find_Exact)(&sk_resolved_redirs, &redir->from_addr);
diff --git a/coregrind/m_replacemalloc/Makefile.am b/coregrind/m_replacemalloc/Makefile.am
deleted file mode 100644 (file)
index e4e32a1..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_LIBRARIES = \
-       libreplacemalloc_core.a \
-       libreplacemalloc_toolpreload.a
-
-libreplacemalloc_core_a_SOURCES = \
-       replacemalloc_core.c
-
-libreplacemalloc_toolpreload_a_SOURCES = \
-       vg_replace_malloc.c
-libreplacemalloc_toolpreload_a_CFLAGS = \
-       $(PIC_AM_CFLAGS)
-
-
diff --git a/coregrind/m_scheduler/Makefile.am b/coregrind/m_scheduler/Makefile.am
deleted file mode 100644 (file)
index d865494..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-noinst_HEADERS = \
-       priv_sema.h
-
-noinst_LIBRARIES = libscheduler.a
-
-libscheduler_a_SOURCES = \
-       scheduler.c \
-       sema.c
-
index 09b1882f717872948a647db0793c5b1b73e16160..89e2f56e69d62177042608cacce4ad793609105a 100644 (file)
@@ -62,7 +62,6 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_dispatch.h"
 #include "pub_core_errormgr.h"      // For VG_(get_n_errs_found)()
@@ -332,7 +331,7 @@ static void block_signals(ThreadId tid)
    do {                                                                        \
       ThreadState * volatile _qq_tst = VG_(get_ThreadState)(tid);      \
                                                                        \
-      (jumped) = setjmp(_qq_tst->sched_jmpbuf);                         \
+      (jumped) = __builtin_setjmp(_qq_tst->sched_jmpbuf);               \
       if ((jumped) == 0) {                                             \
         vg_assert(!_qq_tst->sched_jmpbuf_valid);                       \
         _qq_tst->sched_jmpbuf_valid = True;                            \
@@ -454,15 +453,14 @@ UInt run_thread_for_a_while ( ThreadId tid )
 
 static void os_state_clear(ThreadState *tst)
 {
-   tst->os_state.lwpid = 0;
+   tst->os_state.lwpid       = 0;
    tst->os_state.threadgroup = 0;
 }
 
 static void os_state_init(ThreadState *tst)
 {
-   tst->os_state.valgrind_stack_base = 0;
-   tst->os_state.valgrind_stack_szB  = 0;
-
+   tst->os_state.valgrind_stack_base    = 0;
+   tst->os_state.valgrind_stack_init_SP = 0;
    os_state_clear(tst);
 }
 
@@ -540,11 +538,14 @@ static void sched_fork_cleanup(ThreadId me)
    caller subsequently initialises the guest state components of this
    main thread, thread 1.  
 */
-void VG_(scheduler_init) ( void )
+void VG_(scheduler_init) ( Addr clstack_end, SizeT clstack_size )
 {
    Int i;
    ThreadId tid_main;
 
+   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
+   vg_assert(VG_IS_PAGE_ALIGNED(clstack_size));
+
    ML_(sema_init)(&run_sema);
 
    for (i = 0 /* NB; not 1 */; i < VG_N_THREADS; i++) {
@@ -564,10 +565,10 @@ void VG_(scheduler_init) ( void )
 
    tid_main = VG_(alloc_ThreadState)();
 
-   /* Initial thread's stack is the original process stack */
    VG_(threads)[tid_main].client_stack_highest_word 
-                                            = VG_(clstk_end) - sizeof(UWord);
-   VG_(threads)[tid_main].client_stack_szB  = VG_(client_rlimit_stack).rlim_cur;
+      = clstack_end + 1 - sizeof(UWord);
+   VG_(threads)[tid_main].client_stack_szB 
+      = clstack_size;
 
    VG_(atfork_child)(sched_fork_cleanup);
 }
@@ -610,8 +611,15 @@ static void handle_syscall(ThreadId tid)
       complete by the time this call returns, and we'll be
       runnable again.  We could take a signal while the
       syscall runs. */
+
+   if (VG_(clo_sanity_level >= 3))
+      VG_(am_do_sync_check)("(BEFORE SYSCALL)",__FILE__,__LINE__);
+
    SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
 
+   if (VG_(clo_sanity_level >= 3))
+      VG_(am_do_sync_check)("(AFTER SYSCALL)",__FILE__,__LINE__);
+
    if (!VG_(is_running_thread)(tid))
       VG_(printf)("tid %d not running; VG_(running_tid)=%d, tid %d status %d\n",
                  tid, VG_(running_tid), tid, tst->status);
@@ -778,7 +786,8 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
       case VEX_TRC_JMP_TINVAL:
          VG_(discard_translations)(
             (Addr64)VG_(threads)[tid].arch.vex.guest_TISTART,
-            VG_(threads)[tid].arch.vex.guest_TILEN
+            VG_(threads)[tid].arch.vex.guest_TILEN,
+            "scheduler(VEX_TRC_JMP_TINVAL)"
          );
          if (0)
             VG_(printf)("dump translations done.\n");
@@ -1047,7 +1056,9 @@ void do_client_request ( ThreadId tid )
                          " addr %p,  len %d\n",
                          (void*)arg[1], arg[2] );
 
-         VG_(discard_translations)( arg[1], arg[2] );
+         VG_(discard_translations)( 
+            arg[1], arg[2], "scheduler(VG_USERREQ__DISCARD_TRANSLATIONS)" 
+         );
 
          SET_CLREQ_RETVAL( tid, 0 );     /* return value is meaningless */
         break;
@@ -1080,7 +1091,7 @@ void do_client_request ( ThreadId tid )
                if (c2 == 0) c2 = '_';
               VG_(message)(Vg_UserMsg, "Warning:\n"
                    "  unhandled client request: 0x%x (%c%c+0x%x).  Perhaps\n" 
-                  "  VG_(needs).client_requests should be set?\n",
+                  "  VG_(needs).client_requests should be set?",
                            arg[0], c1, c2, arg[0] & 0xffff);
               whined = True;
            }
@@ -1155,13 +1166,18 @@ void VG_(sanity_check_general) ( Bool force_expensive )
 
       /* Look for stack overruns.  Visit all threads. */
       for (tid = 1; tid < VG_N_THREADS; tid++) {
-        SSizeT remains;
+        SizeT    remains;
+         VgStack* stack;
 
         if (VG_(threads)[tid].status == VgTs_Empty ||
             VG_(threads)[tid].status == VgTs_Zombie)
            continue;
 
-        remains = VG_(stack_unused)(tid);
+         stack 
+            = (VgStack*)
+              VG_(get_ThreadState)(tid)->os_state.valgrind_stack_base;
+        remains 
+            = VG_(am_get_VgStack_unused_szB)(stack);
         if (remains < VKI_PAGE_SIZE)
            VG_(message)(Vg_DebugMsg, 
                          "WARNING: Thread %d is within %d bytes "
diff --git a/coregrind/m_sigframe/Makefile.am b/coregrind/m_sigframe/Makefile.am
deleted file mode 100644 (file)
index f265b03..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-# Remember to include all the platform-specific files in the distribution.
-EXTRA_DIST = \
-       $(addsuffix .c,$(addprefix sigframe-,$(VG_PLATFORM_ALL)))
-
-noinst_LIBRARIES = libsigframe.a
-
-libsigframe_a_SOURCES = \
-       sigframe-@VG_PLATFORM@.c
index 0e4b4febf950f4c70fa5e079f3de677b72dfe00d..cb44c3bad970de115ea36f14d287d470a5a4e827 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
@@ -376,17 +375,16 @@ void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
 static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
 {
    ThreadId tid = tst->tid;
-   Segment *stackseg = NULL;
+   NSegment *stackseg = NULL;
 
    if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
-      stackseg = VG_(find_segment)(addr);
+      stackseg = VG_(am_find_nsegment)(addr);
       if (0 && stackseg)
         VG_(printf)("frame=%p seg=%p-%p\n",
-                    addr, stackseg->addr, stackseg->addr+stackseg->len);
+                    addr, stackseg->start, stackseg->end);
    }
 
-   if (stackseg == NULL 
-       || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) {
+   if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
       VG_(message)(
          Vg_UserMsg,
          "Can't extend stack to %p during signal delivery for thread %d:",
index d99e8d2a49bb8a0d9d47e821bbe29b05628430e0..22af92a50a25c095fa8a1526678e1b89bf23e460 100644 (file)
@@ -33,7 +33,6 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
index 17026c97c5182071095018e6e719124adfc2e298..f0b82ddf315456f340397112bed3d080eaebcf37 100644 (file)
@@ -31,7 +31,6 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h" /* find_segment */
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
@@ -396,17 +395,16 @@ void synth_ucontext(ThreadId tid, const vki_siginfo_t *si,
 static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
 {
    ThreadId tid = tst->tid;
-   Segment *stackseg = NULL;
+   NSegment *stackseg = NULL;
 
    if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
-      stackseg = VG_(find_segment)(addr);
+      stackseg = VG_(am_find_nsegment)(addr);
       if (0 && stackseg)
         VG_(printf)("frame=%p seg=%p-%p\n",
-                    addr, stackseg->addr, stackseg->addr+stackseg->len);
+                    addr, stackseg->start, stackseg->end);
    }
 
-   if (stackseg == NULL 
-       || (stackseg->prot & (VKI_PROT_READ|VKI_PROT_WRITE)) == 0) {
+   if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
       VG_(message)(
          Vg_UserMsg,
          "Can't extend stack to %p during signal delivery for thread %d:",
index 253a7f129945c26ca963efb870f268baa14067d0..4a0542188c39d2c466ea5dea40a3e3ce9f90d703 100644 (file)
  */
 
 #include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_coredump.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
+#include "pub_core_clientstate.h"
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debugger.h"      // For VG_(start_debugger)
 #include "pub_core_errormgr.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
@@ -982,7 +981,8 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid)
 
    if (VG_(clo_verbosity) > 1 || (could_core && info->si_code > VKI_SI_USER)) {
       VG_(message)(Vg_UserMsg, "");
-      VG_(message)(Vg_UserMsg, "Process terminating with default action of signal %d (%s)%s", 
+      VG_(message)(Vg_UserMsg, 
+                   "Process terminating with default action of signal %d (%s)%s", 
                   sigNo, signame(sigNo), core ? ": dumping core" : "");
 
       /* Be helpful - decode some more details about this fault */
@@ -1008,6 +1008,14 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid)
               haveaddr = False;
               break;
            }
+#if 0
+            {
+              HChar buf[110];
+              VG_(am_show_nsegments)(0,"post segfault");
+              VG_(sprintf)(buf, "/bin/cat /proc/%d/maps", VG_(getpid)());
+              VG_(system)(buf);
+            }
+#endif
            break;
 
         case VKI_SIGILL:
@@ -1178,7 +1186,7 @@ static void resume_scheduler(ThreadId tid)
    if (tst->sched_jmpbuf_valid) {
       /* Can't continue; must longjmp back to the scheduler and thus
          enter the sighandler immediately. */
-      longjmp(tst->sched_jmpbuf, True);
+      __builtin_longjmp(tst->sched_jmpbuf, True);
    }
 }
 
@@ -1371,65 +1379,41 @@ void async_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *
  */
 Bool VG_(extend_stack)(Addr addr, UInt maxsize)
 {
-   Segment *seg;
-   Addr base;
-   UInt newsize;
+   SizeT udelta;
 
    /* Find the next Segment above addr */
-   seg = VG_(find_segment)(addr);
-   if (seg)
-      return True;
-
-   /* now we know addr is definitely unmapped */
-   seg = VG_(find_segment_above_unmapped)(addr);
-
-   /* If there isn't one, or it isn't growable, fail */
-   if (seg == NULL || 
-       !(seg->flags & SF_GROWDOWN) ||
-       VG_(seg_contains)(seg, addr, sizeof(void *)))
-      return False;
-       
-   vg_assert(seg->addr > addr);
+   NSegment* seg      = VG_(am_find_nsegment)(addr);
+   NSegment* seg_next = seg ? VG_(am_next_nsegment)( seg, True/*fwds*/ )
+                            : NULL;
 
-   /* Create the mapping */
-   base = VG_PGROUNDDN(addr);
-   newsize = seg->addr - base;
+   if (seg && seg->kind == SkAnonC)
+      /* addr is already mapped.  Nothing to do. */
+      return True;
 
-   if (seg->len + newsize >= maxsize)
+   /* Check that the requested new base is in a shrink-down
+      reservation section which abuts an anonymous mapping that
+      belongs to the client. */
+   if ( ! (seg
+           && seg->kind == SkResvn
+           && seg->smode == SmUpper
+           && seg_next
+           && seg_next->kind == SkAnonC
+           && seg->end+1 == seg_next->start))
       return False;
 
-   /* Nasty Hack.  The new segment will have SF_MMAP set because
-      that's what VG_(mmap) does.  But the existing stack segment
-      won't necessarily have it set, because the initial segment list
-      entry for the main thread's stack doesn't have it set.  That
-      means that the segment list preener won't merge the segments
-      together (because they have different flags).  That means the
-      segment list will in fact list two adjacent segments for the
-      main stack, which is wrong.  This means that the tests which
-      check if a translation is from a stack-like area and therefore
-      in need of a self-check will not work right.  Sigh.
-
-      So .. in lieu of fixing this properly (viz, rationalising all
-      the SF_ flags), just mark the original stack segment as having
-      SF_MMAP.  Then the preener will merge it into the new area.
-      This is a hack.  */
-   seg->flags |= SF_MMAP;
-   /* end of Nasty Hack */
-
-   if (VG_(mmap)((Char *)base, newsize,
-                seg->prot,
-                VKI_MAP_PRIVATE | VKI_MAP_FIXED | VKI_MAP_ANONYMOUS | VKI_MAP_CLIENT,
-                seg->flags,
-                -1, 0) == (void *)-1)
+   udelta = VG_PGROUNDUP(seg_next->start - addr);
+   VG_(debugLog)(1, "signals", 
+                    "extending a stack base 0x%llx down by %lld\n",
+                    (ULong)seg_next->start, (ULong)udelta);
+   if (! VG_(am_extend_into_adjacent_reservation_client)
+            ( seg_next, -(SSizeT)udelta )) {
+      VG_(debugLog)(1, "signals", "extending a stack base: FAILED\n");
       return False;
+   }
 
    /* When we change the main stack, we have to let the stack handling
       code know about it. */
-   VG_(change_stack)(VG_(clstk_id), base, VG_(clstk_end));
-
-   if (0)
-      VG_(printf)("extended stack: %p %d\n",
-                 base, newsize);
+   VG_(change_stack)(VG_(clstk_id), addr, VG_(clstk_end));
 
    if (VG_(clo_sanity_level) > 2)
       VG_(sanity_check_general)(False);
@@ -1535,7 +1519,8 @@ void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *u
    } 
 
    if (VG_(clo_trace_signals)) {
-      VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d, EIP=%p, eip=%p",
+      VG_(message)(Vg_DebugMsg, "signal %d arrived ... si_code=%d, "
+                                "EIP=%p, eip=%p",
                    sigNo, info->si_code, VG_(get_IP)(tid), 
                   VG_UCONTEXT_INSTR_PTR(uc) );
    }
@@ -1547,27 +1532,30 @@ void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *u
    if (info->si_signo == VKI_SIGSEGV) {
       Addr fault = (Addr)info->_sifields._sigfault._addr;
       Addr esp   =  VG_(get_SP)(tid);
-      Segment* seg;
-
-      seg = VG_(find_segment)(fault);
-      if (seg == NULL)
-         seg = VG_(find_segment_above_unmapped)(fault);
+      NSegment* seg      = VG_(am_find_nsegment)(fault);
+      NSegment* seg_next = seg ? VG_(am_next_nsegment)( seg, True/*fwds*/ )
+                               : NULL;
 
       if (VG_(clo_trace_signals)) {
         if (seg == NULL)
            VG_(message)(Vg_DebugMsg,
-                        "SIGSEGV: si_code=%d faultaddr=%p tid=%d ESP=%p seg=NULL shad=%p-%p",
-                        info->si_code, fault, tid, esp,
-                        VG_(shadow_base), VG_(shadow_end));
+                        "SIGSEGV: si_code=%d faultaddr=%p tid=%d ESP=%p "
+                         "seg=NULL",
+                        info->si_code, fault, tid, esp);
         else
            VG_(message)(Vg_DebugMsg,
-                        "SIGSEGV: si_code=%d faultaddr=%p tid=%d ESP=%p seg=%p-%p fl=%x shad=%p-%p",
-                        info->si_code, fault, tid, esp, seg->addr, seg->addr+seg->len, seg->flags,
-                        VG_(shadow_base), VG_(shadow_end));
+                        "SIGSEGV: si_code=%d faultaddr=%p tid=%d ESP=%p "
+                          "seg=%p-%p",
+                        info->si_code, fault, tid, esp, seg->start, seg->end);
       }
       if (info->si_code == 1 /* SEGV_MAPERR */
-         && fault >= (esp - VG_STACK_REDZONE_SZB)
-          && fault < VG_(client_end)) {
+          && seg
+          && seg->kind == SkResvn
+          && seg->smode == SmUpper
+          && seg_next
+          && seg_next->kind == SkAnonC
+          && seg->end+1 == seg_next->start
+         && fault >= (esp - VG_STACK_REDZONE_SZB)) {
         /* If the fault address is above esp but below the current known
            stack segment base, and it was a fault because there was
            nothing mapped there (as opposed to a permissions fault),
@@ -1577,10 +1565,12 @@ void sync_signalhandler ( Int sigNo, vki_siginfo_t *info, struct vki_ucontext *u
         if (VG_(extend_stack)(base, VG_(threads)[tid].client_stack_szB)) {
            if (VG_(clo_trace_signals))
               VG_(message)(Vg_DebugMsg, 
-                           "       -> extended stack base to %p", VG_PGROUNDDN(fault));
-           return;             // extension succeeded, restart instruction
+                           "       -> extended stack base to %p", 
+                            VG_PGROUNDDN(fault));
+           return; // extension succeeded, restart instruction
         } else
-           VG_(message)(Vg_UserMsg, "Stack overflow in thread %d: can't grow stack to %p", 
+           VG_(message)(Vg_UserMsg, 
+                         "Stack overflow in thread %d: can't grow stack to %p", 
                         tid, fault);
       }
       /* Fall into normal signal handling for all other cases */
index f9ca18806847e0e790650c84bf4888555d73ed8f..be64c45a3c467755ae051c1a13a216317664c954 100644 (file)
@@ -119,7 +119,7 @@ static inline Int get_height(void)
 {
    UInt ret = 0;
 
-   while((ret < SK_MAXHEIGHT - 1) && (VG_(random)() & 1))
+   while((ret < SK_MAXHEIGHT - 1) && (VG_(random)(NULL) & 1))
       ret++;
 
    return ret;
index 506aa192cda452e941dd73b1a490d4ddab208545..129174460278635ee120414fcf6b42bee145b0f8 100644 (file)
@@ -118,6 +118,9 @@ static Stack* find_stack_by_addr(Addr sp)
 UWord VG_(register_stack)(Addr start, Addr end)
 {
    Stack *i;
+
+   if (0) VG_(printf)("REGISTER STACK %p %p\n", start,end);
+
    if (start > end) {
       Addr t = end;
       end = start;
index bd17ee0b6ea0f1e46569dd932cd27d5e5666b167..e9824883bcbe8c1b1a110a063435288e2a445487 100644 (file)
@@ -77,7 +77,7 @@ UInt VG_(get_StackTrace2) ( Addr* ips, UInt n_ips,
    // JRS 2002-sep-17: hack, to round up fp_max to the end of the
    // current page, at least.  Dunno if it helps.
    // NJN 2002-sep-17: seems to -- stack traces look like 1.0.X again
-   fp_max = (fp_max_orig + VKI_PAGE_SIZE - 1) & ~(VKI_PAGE_SIZE - 1);
+   fp_max = VG_PGROUNDUP(fp_max_orig);
    fp_max -= sizeof(Addr);
 
    if (debug)
@@ -229,7 +229,7 @@ UInt VG_(get_StackTrace) ( ThreadId tid, StackTrace ips, UInt n_ips )
       useful.  */
    if (ip >= (Addr)&VG_(trampoline_stuff_start) 
        && ip < (Addr)&VG_(trampoline_stuff_end)
-       &&  VG_(is_addressable)(sp, sizeof(Addr), VKI_PROT_READ)) {
+       && VG_(am_is_valid_for_client)(sp, sizeof(Addr), VKI_PROT_READ)) {
       ip = *(Addr *)sp;
       sp += sizeof(Addr);
    }
index d6348e71917a725833d682e8c2122b9b6660985c..a0938d59eb841aba127842750669d0d46aaa852d 100644 (file)
@@ -215,6 +215,37 @@ SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
 #endif
 }
 
+/* ---------------------------------------------------------------------
+   Names of errors.
+   ------------------------------------------------------------------ */
+
+/* Return a string which gives the name of an error value.  Note,
+   unlike the standard C syserror fn, the returned string is not
+   malloc-allocated or writable -- treat it as a constant. 
+   TODO: implement this properly. */
+
+const HChar* VG_(strerror) ( UWord errnum )
+{
+   switch (errnum) {
+      case VKI_EPERM:       return "Operation not permitted";
+      case VKI_ENOENT:      return "No such file or directory";
+      case VKI_ESRCH:       return "No such process";
+      case VKI_EINTR:       return "Interrupted system call";
+      case VKI_EBADF:       return "Bad file number";
+      case VKI_EAGAIN:      return "Try again";
+      case VKI_ENOMEM:      return "Out of memory";
+      case VKI_EACCES:      return "Permission denied";
+      case VKI_EFAULT:      return "Bad address";
+      case VKI_EEXIST:      return "File exists";
+      case VKI_EINVAL:      return "Invalid argument";
+      case VKI_EMFILE:      return "Too many open files";
+      case VKI_ENOSYS:      return "Function not implemented";
+      case VKI_ERESTARTSYS: return "ERESTARTSYS";
+      default:              return "VG_(strerror): unknown error";
+   }
+}
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                        ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/Makefile.am b/coregrind/m_syswrap/Makefile.am
deleted file mode 100644 (file)
index b1033a4..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-include $(top_srcdir)/Makefile.all.am
-include $(top_srcdir)/Makefile.core.am
-
-# Remember to include all the OS/platform-specific files in the distribution.
-EXTRA_DIST = \
-       $(addsuffix .S,$(addprefix syscall-,$(VG_PLATFORM_ALL))) \
-       $(addsuffix .c,$(addprefix syswrap-,$(VG_OS_ALL))) \
-       $(addsuffix .c,$(addprefix syswrap-,$(VG_PLATFORM_ALL)))
-
-noinst_HEADERS = \
-       priv_types_n_macros.h \
-       priv_syswrap-generic.h \
-       priv_syswrap-linux.h \
-       priv_syswrap-main.h
-
-noinst_LIBRARIES = libsyswrap.a
-
-libsyswrap_a_SOURCES = \
-       syscall-@VG_PLATFORM@.S \
-       syswrap-generic.c \
-       syswrap-@VG_OS@.c \
-       syswrap-@VG_PLATFORM@.c \
-       syswrap-main.c
-
-syscall-@VG_PLATFORM@.S: libvex_guest_offsets.h
-syswrap-main.c: libvex_guest_offsets.h
-
-libvex_guest_offsets.h:
-       $(MAKE) -C @VEX_DIR@ CC="$(CC)" pub/libvex_guest_offsets.h
index ac7d038592318a1243ccd7c3d22bbc3e6daf785e..8a5b6fc9c9aea238999434c3547b1f6c7ec25133 100644 (file)
@@ -40,6 +40,11 @@ extern
 Bool ML_(valid_client_addr)(Addr start, SizeT size, ThreadId tid,
                             const Char *syscallname);
 
+/* Handy small function to help stop wrappers from segfaulting when
+   presented with bogus client addresses.  Is not used for generating
+   user-visible errors. */
+extern Bool ML_(safe_to_deref) ( void* start, SizeT size );
+
 // Returns True if the signal is OK for the client to use.
 extern Bool ML_(client_signal_OK)(Int sigNo);
 
@@ -57,9 +62,12 @@ extern
 Bool ML_(do_sigkill)(Int pid, Int tgid);
 
 /* So that it can be seen from syswrap-x86-linux.c. */
+/* When a client mmap has been successfully done, both aspacem and the
+   tool need to be notified of the new mapping.  Hence this fn. */
 extern 
-void ML_(mmap_segment) ( Addr a, SizeT len, UInt prot, 
-                         UInt mm_flags, Int fd, ULong offset );
+void 
+ML_(notify_aspacem_and_tool_of_mmap) ( Addr a, SizeT len, UInt prot, 
+                                       UInt mm_flags, Int fd, ULong offset );
 
 
 DECL_TEMPLATE(generic, sys_ni_syscall);            // * P -- unimplemented
index 04dbfa592fbe7dcbcb932b5f06ca046bfb655d41..04a1477c632ba6405473c92236ebc68b192dff3a 100644 (file)
@@ -28,7 +28,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "vki_unistd.h"
 #include "libvex_guest_offsets.h"
 
index e8298020746cc1efa9b2ff9d22473ea0622e4813..2511b74815f2590198f5f81afe8f86ce0e48a662 100644 (file)
@@ -27,7 +27,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "vki_unistd.h"
 #include "libvex_guest_offsets.h"
                
index 150a528aeb33fd73fcd35a5cb12cd19dbfe814a6..d6ff3437d10b5cacccba58e7c0a03750bd2c760e 100644 (file)
@@ -28,7 +28,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "vki_unistd.h"
 #include "libvex_guest_offsets.h"
                
index 66fb5021a2cd484e045daa16722dec586667eb6c..c6620031053568f2e426bc15d26b8f161f5bf7ee 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debuglog.h"
 #include "pub_core_options.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
    Note.  Why is this stuff here?
    ------------------------------------------------------------------ */
 
-/* 
-   Allocate a stack for this thread.
-
-   They're allocated lazily, but never freed.
- */
-#define FILL   0xdeadbeefcabafeed
+/* Allocate a stack for this thread.  They're allocated lazily, and
+   never freed. */
 
-// Valgrind's stack size, in words.
-#define STACK_SIZE_W      16384
+/* Allocate a stack for this thread, if it doesn't already have one.
+   Returns the initial stack pointer value to use, or 0 if allocation
+   failed. */
 
-static UWord* allocstack(ThreadId tid)
+static Addr allocstack(ThreadId tid)
 {
-   ThreadState *tst = VG_(get_ThreadState)(tid);
-   UWord* rsp;
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   VgStack*     stack;
+   Addr         initial_SP;
 
-   if (tst->os_state.valgrind_stack_base == 0) {
-      void *stk = VG_(mmap)(0, STACK_SIZE_W * sizeof(UWord) + VKI_PAGE_SIZE,
-                           VKI_PROT_READ|VKI_PROT_WRITE,
-                           VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
-                           SF_VALGRIND,
-                           -1, 0);
-
-      if (stk != (void *)-1) {
-        VG_(mprotect)(stk, VKI_PAGE_SIZE, VKI_PROT_NONE); /* guard page */
-        tst->os_state.valgrind_stack_base = ((Addr)stk) + VKI_PAGE_SIZE;
-        tst->os_state.valgrind_stack_szB  = STACK_SIZE_W * sizeof(UWord);
-      } else 
-        return (UWord*)-1;
-   }
+   /* Either the stack_base and stack_init_SP are both zero (in which
+      case a stack hasn't been allocated) or they are both non-zero,
+      in which case it has. */
 
-   for (rsp = (UWord*) tst->os_state.valgrind_stack_base; 
-        rsp < (UWord*)(tst->os_state.valgrind_stack_base +
-                       tst->os_state.valgrind_stack_szB); 
-        rsp++)
-      *rsp = FILL;
-   /* rsp is left at top of stack */
+   if (tst->os_state.valgrind_stack_base == 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
 
-   if (0)
-      VG_(printf)("stack for tid %d at %p (%llx); rsp=%p\n",
-                 tid, tst->os_state.valgrind_stack_base,
-                  *(UWord*)(tst->os_state.valgrind_stack_base), rsp);
+   if (tst->os_state.valgrind_stack_base != 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
 
-   return rsp;
-}
+   /* If no stack is present, allocate one. */
 
-/* NB: this is identical the the x86 version. */
-/* Return how many bytes of this stack have not been used */
-SSizeT VG_(stack_unused)(ThreadId tid)
-{
-   ThreadState *tst = VG_(get_ThreadState)(tid);
-   UWord* p;
-
-   for (p = (UWord*)tst->os_state.valgrind_stack_base; 
-       p && (p < (UWord*)(tst->os_state.valgrind_stack_base +
-                           tst->os_state.valgrind_stack_szB)); 
-       p++)
-      if (*p != FILL)
-        break;
+   if (tst->os_state.valgrind_stack_base == 0) {
+      stack = VG_(am_alloc_VgStack)( &initial_SP );
+      if (stack) {
+         tst->os_state.valgrind_stack_base    = (Addr)stack;
+         tst->os_state.valgrind_stack_init_SP = initial_SP;
+      }
+   }
 
    if (0)
-      VG_(printf)("p=%p %llx tst->os_state.valgrind_stack_base=%p\n",
-                  p, *p, tst->os_state.valgrind_stack_base);
-
-   return ((Addr)p) - tst->os_state.valgrind_stack_base;
+      VG_(printf)( "stack for tid %d at %p; init_SP=%p\n",
+                   tid, 
+                   (void*)tst->os_state.valgrind_stack_base, 
+                   (void*)tst->os_state.valgrind_stack_init_SP );
+                  
+   return tst->os_state.valgrind_stack_init_SP;
 }
 
 
@@ -247,7 +221,11 @@ void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
    VG_(debugLog)(1, "syswrap-amd64-linux", 
                     "entering VG_(main_thread_wrapper_NORETURN)\n");
 
-   UWord* rsp = allocstack(tid);
+   Addr rsp = allocstack(tid);
+
+   /* If we can't even allocate the first thread's stack, we're hosed.
+      Give up. */
+   vg_assert2(rsp != 0, "Cannot allocate main thread's stack.");
 
    /* shouldn't be any other threads around yet */
    vg_assert( VG_(count_living_threads)() == 1 );
@@ -388,7 +366,7 @@ static SysRes do_clone ( ThreadId ptid,
    ThreadState* ptst = VG_(get_ThreadState)(ptid);
    ThreadState* ctst = VG_(get_ThreadState)(ctid);
    UWord*       stack;
-   Segment*     seg;
+   NSegment*    seg;
    SysRes       res;
    Long         rax;
    vki_sigset_t blockall, savedmask;
@@ -398,7 +376,11 @@ static SysRes do_clone ( ThreadId ptid,
    vg_assert(VG_(is_running_thread)(ptid));
    vg_assert(VG_(is_valid_tid)(ctid));
 
-   stack = allocstack(ctid);
+   stack = (UWord*)allocstack(ctid);
+   if (stack == NULL) {
+      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
+      goto out;
+   }
 
    /* Copy register state
 
@@ -432,14 +414,14 @@ static SysRes do_clone ( ThreadId ptid,
       memory mappings and try to derive some useful information.  We
       assume that esp starts near its highest possible value, and can
       only go down to the start of the mmaped segment. */
-   seg = VG_(find_segment)((Addr)rsp);
-   if (seg) {
+   seg = VG_(am_find_nsegment)((Addr)rsp);
+   if (seg && seg->kind != SkResvn) {
       ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(rsp);
-      ctst->client_stack_szB  = ctst->client_stack_highest_word - seg->addr;
+      ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
 
       if (debug)
         VG_(printf)("tid %d: guessed client stack range %p-%p\n",
-                    ctid, seg->addr, VG_PGROUNDUP(rsp));
+                    ctid, seg->start, VG_PGROUNDUP(rsp));
    } else {
       VG_(message)(Vg_UserMsg, "!? New thread %d starts with RSP(%p) unmapped\n",
                   ctid, rsp);
@@ -466,6 +448,7 @@ static SysRes do_clone ( ThreadId ptid,
 
    VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
 
+  out:
    if (res.isError) {
       /* clone failed */
       VG_(cleanup_thread)(&ctst->arch);
@@ -604,14 +587,14 @@ PRE(sys_clone)
 
    if (ARG1 & VKI_CLONE_PARENT_SETTID) {
       PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(is_addressable)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
+      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
          SET_STATUS_Failure( VKI_EFAULT );
          return;
       }
    }
    if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
       PRE_MEM_WRITE("clone(child_tidptr)", ARG4, sizeof(Int));
-      if (!VG_(is_addressable)(ARG4, sizeof(Int), VKI_PROT_WRITE)) {
+      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(Int), VKI_PROT_WRITE)) {
          SET_STATUS_Failure( VKI_EFAULT );
          return;
       }
@@ -1185,8 +1168,13 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    GENXY(__NR_fstat,             sys_newfstat),       // 5 
    GENXY(__NR_lstat,             sys_newlstat),       // 6 
    GENXY(__NR_poll,              sys_poll),           // 7 
+<<<<<<< .working
    LINX_(__NR_lseek,             sys_lseek),          // 8 
    LINXY(__NR_mmap,              sys_mmap2),          // 9 
+=======
+   GENX_(__NR_lseek,             sys_lseek),          // 8 
+   GENX_(__NR_mmap,              sys_mmap2),          // 9 
+>>>>>>> .merge-right.r4787
 
    GENXY(__NR_mprotect,          sys_mprotect),       // 10 
    GENXY(__NR_munmap,            sys_munmap),         // 11 
@@ -1423,7 +1411,7 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    LINXY(__NR_sched_getaffinity, sys_sched_getaffinity), // 204 
 
    //   (__NR_set_thread_area,   sys_ni_syscall),     // 205 
-   LINX_(__NR_io_setup,          sys_io_setup),       // 206 
+   LINXY(__NR_io_setup,          sys_io_setup),       // 206 
    LINX_(__NR_io_destroy,        sys_io_destroy),     // 207 
    LINXY(__NR_io_getevents,      sys_io_getevents),   // 208 
    LINX_(__NR_io_submit,         sys_io_submit),      // 209 
index 61b94373466f21b8cbf6b721c0d302e4e6dcd536..eac7239561e26462442246a6f3b9cb26d40115fe 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
+#include "pub_core_debuginfo.h"     // VG_(di_notify_*)
 #include "pub_core_aspacemgr.h"
+#include "pub_core_transtab.h"      // VG_(discard_translations)
+#include "pub_core_clientstate.h"   // VG_(brk_base), VG_(brk_limit)
 #include "pub_core_debuglog.h"
 #include "pub_core_errormgr.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
 #include "pub_core_libcfile.h"
-#include "pub_core_libcmman.h"      // For VG_(mmap), VG_(munmap)()
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
 #include "vki_unistd.h"              /* for the __NR_* constants */
 
 
-/* return true if address range entirely contained within client
-   address space */
+/* Returns True iff address range is something the client can
+   plausibly mess with: all of it is either already belongs to the
+   client or is free or a reservation. */
+
 Bool ML_(valid_client_addr)(Addr start, SizeT size, ThreadId tid,
                                    const Char *syscallname)
 {
-   Addr end = start+size;
-   Addr cl_base = VG_(client_base);
    Bool ret;
 
    if (size == 0)
       return True;
 
-   if (0 && cl_base < 0x10000)
-      cl_base = 0x10000;
-
-   ret =
-      (end >= start) && 
-      start >= cl_base && start < VG_(client_end) &&
-      (end <= VG_(client_end));
+   ret = VG_(am_is_valid_for_client_or_free_or_resvn)
+            (start,size,VKI_PROT_NONE);
 
    if (0)
-      VG_(printf)("%s: test=%p-%p client=%p-%p ret=%d\n",
-                 syscallname, start, end, cl_base, VG_(client_end), ret);
+      VG_(printf)("%s: test=%p-%p ret=%d\n",
+                 syscallname, start, start+size-1, (Int)ret);
 
    if (!ret && syscallname != NULL) {
       VG_(message)(Vg_UserMsg, "Warning: client syscall %s tried "
                                "to modify addresses %p-%p",
-                               syscallname, start, end);
-
+                               syscallname, start, start+size-1);
       if (VG_(clo_verbosity) > 1) {
          VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
       }
@@ -94,6 +89,7 @@ Bool ML_(valid_client_addr)(Addr start, SizeT size, ThreadId tid,
    return ret;
 }
 
+
 Bool ML_(client_signal_OK)(Int sigNo)
 {
    /* signal 0 is OK for kill */
@@ -104,6 +100,17 @@ Bool ML_(client_signal_OK)(Int sigNo)
    return ret;
 }
 
+
+/* Handy small function to help stop wrappers from segfaulting when
+   presented with bogus client addresses.  Is not used for generating
+   user-visible errors. */
+
+Bool ML_(safe_to_deref) ( void* start, SizeT size )
+{
+   return VG_(am_is_valid_for_client)( (Addr)start, size, VKI_PROT_NONE );
+}
+
+
 /* ---------------------------------------------------------------------
    Doing mmap, mremap
    ------------------------------------------------------------------ */
@@ -122,7 +129,7 @@ Bool ML_(client_signal_OK)(Int sigNo)
    idea of addressible memory diverges from that of the
    kernel's, which causes the leak detector to crash. */
 static 
-void mash_addr_and_len( Addr* a, SizeT* len)
+void page_align_addr_and_len( Addr* a, SizeT* len)
 {
    Addr ra;
    
@@ -131,163 +138,278 @@ void mash_addr_and_len( Addr* a, SizeT* len)
    *a = ra;
 }
 
-void ML_(mmap_segment) ( Addr a, SizeT len, UInt prot, 
-                         UInt mm_flags, Int fd, ULong offset )
+/* When a client mmap has been successfully done, this function must
+   be called.  It notifies both aspacem and the tool of the new
+   mapping.
+*/
+void 
+ML_(notify_aspacem_and_tool_of_mmap) ( Addr a, SizeT len, UInt prot, 
+                                       UInt flags, Int fd, ULong offset )
 {
-   Bool rr, ww, xx;
-   UInt flags;
+   Bool rr, ww, xx, d;
 
-   flags = SF_MMAP;
-   
-   if (!(mm_flags & VKI_MAP_PRIVATE))
-      flags |= SF_SHARED;
-
-   if (fd != -1)
-      flags |= SF_FILE;
+   /* 'a' is the return value from a real kernel mmap, hence: */
+   vg_assert(VG_IS_PAGE_ALIGNED(a));
+   /* whereas len is whatever the syscall supplied.  So: */
+   len = VG_PGROUNDUP(len);
 
-   VG_(map_fd_segment)(a, len, prot, flags, fd, offset, NULL);
+   d = VG_(am_notify_client_mmap)( a, len, prot, flags, fd, offset );
 
-   rr = prot & VKI_PROT_READ;
-   ww = prot & VKI_PROT_WRITE;
-   xx = prot & VKI_PROT_EXEC;
+   rr = toBool(prot & VKI_PROT_READ);
+   ww = toBool(prot & VKI_PROT_WRITE);
+   xx = toBool(prot & VKI_PROT_EXEC);
 
    VG_TRACK( new_mem_mmap, a, len, rr, ww, xx );
+
+   if (d)
+      VG_(discard_translations)( (Addr64)a, (ULong)len,
+                                 "ML_(notify_aspacem_and_tool_of_mmap)" );
 }
 
-static 
-SysRes mremap_segment ( Addr old_addr, SizeT old_size,
-                        Addr new_addr, SizeT new_size,
-                        UInt flags, ThreadId tid)
+/* Expand (or shrink) an existing mapping, potentially moving it at
+   the same time (controlled by the MREMAP_MAYMOVE flag).  Nightmare.
+*/
+static
+SysRes do_mremap( Addr old_addr, SizeT old_len, 
+                  Addr new_addr, SizeT new_len,
+                  UWord flags, ThreadId tid )
 {
-   SysRes ret;
-   Segment *seg, *next;
-
-   old_size = VG_PGROUNDUP(old_size);
-   new_size = VG_PGROUNDUP(new_size);
+#  define MIN_SIZET(_aa,_bb) (_aa) < (_bb) ? (_aa) : (_bb)
 
-   if (VG_PGROUNDDN(old_addr) != old_addr)
-      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   Bool      ok, d;
+   NSegment* old_seg;
+   Addr      advised;
+   Bool      f_fixed   = toBool(flags & VKI_MREMAP_FIXED);
+   Bool      f_maymove = toBool(flags & VKI_MREMAP_MAYMOVE);
 
-   if (!ML_(valid_client_addr)(old_addr, old_size, tid, "mremap(old_addr)"))
-      return VG_(mk_SysRes_Error)( VKI_EFAULT );
+   if (0)
+      VG_(printf)("do_remap (old %p %d) (new %p %d) %s %s\n",
+                  old_addr,old_len,new_addr,new_len, 
+                  flags & VKI_MREMAP_MAYMOVE ? "MAYMOVE" : "",
+                  flags & VKI_MREMAP_FIXED ? "FIXED" : "");
 
-   /* fixed at the current address means we don't move it */
-   if ((flags & VKI_MREMAP_FIXED) && (old_addr == new_addr))
-      flags &= ~(VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE);
+   if (flags & ~(VKI_MREMAP_FIXED | VKI_MREMAP_MAYMOVE))
+      goto eINVAL;
 
-   if (flags & VKI_MREMAP_FIXED) {
-      if (VG_PGROUNDDN(new_addr) != new_addr)
-        return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   if (!VG_IS_PAGE_ALIGNED(old_addr))
+      goto eINVAL;
 
-      if (!ML_(valid_client_addr)(new_addr, new_size, tid, "mremap(new_addr)"))
-        return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+   old_len = VG_PGROUNDUP(old_len);
+   new_len = VG_PGROUNDUP(new_len);
 
-      /* check for overlaps */
-      if ((old_addr < (new_addr+new_size) &&
-          (old_addr+old_size) > new_addr) ||
-         (new_addr < (old_addr+new_size) &&
-          (new_addr+new_size) > old_addr))
-        return VG_(mk_SysRes_Error)( VKI_EINVAL );
-   }
+   if (new_len == 0)
+      goto eINVAL;
 
-   /* Do nothing */
-   if (!(flags & VKI_MREMAP_FIXED) && new_size == old_size)
-      return VG_(mk_SysRes_Success)( old_addr );
+   /* kernel doesn't reject this, but we do. */
+   if (old_len == 0)
+      goto eINVAL;
 
-   seg = VG_(find_segment)(old_addr);
+   /* reject wraparounds */
+   if (old_addr + old_len < old_addr
+       || new_addr + new_len < new_len)
+      goto eINVAL;
 
-   /* range must be contained within segment */
-   if (seg == NULL || !VG_(seg_contains)(seg, old_addr, old_size))
-      return VG_(mk_SysRes_Error)( VKI_EINVAL );
+   /* kernel rejects all fixed, no-move requests (which are
+      meaningless). */
+   if (f_fixed == True && f_maymove == False)
+      goto eINVAL;
 
-   next = VG_(find_segment_above_mapped)(old_addr);
+   /* Stay away from non-client areas. */
+   if (!ML_(valid_client_addr)(old_addr, old_len, tid, "mremap(old_addr)"))
+      goto eINVAL;
 
-   if (0)
-      VG_(printf)("mremap: old_addr+new_size=%p next->addr=%p flags=%d\n",
-                 old_addr+new_size, next->addr, flags);
-   
-   if ((flags & VKI_MREMAP_FIXED) ||
-       (next != NULL && (old_addr+new_size) > next->addr)) {
-      /* we're moving the block */
-      Addr a;
-      
-      if ((flags & (VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE)) == 0)
-         /* not allowed to move */
-        return VG_(mk_SysRes_Error)( VKI_ENOMEM ); 
+   /* In all remaining cases, if the old range does not fall within a
+      single segment, fail. */
+   old_seg = VG_(am_find_nsegment)( old_addr );
+   if (old_addr < old_seg->start || old_addr+old_len-1 > old_seg->end)
+      goto eINVAL;
+   if (old_seg->kind != SkAnonC && old_seg->kind != SkAnonV)
+      goto eINVAL;
 
-      if ((flags & VKI_MREMAP_FIXED) == 0)
-         new_addr = 0;
+   vg_assert(old_len > 0);
+   vg_assert(new_len > 0);
+   vg_assert(VG_IS_PAGE_ALIGNED(old_len));
+   vg_assert(VG_IS_PAGE_ALIGNED(new_len));
+   vg_assert(VG_IS_PAGE_ALIGNED(old_addr));
 
-      a = VG_(find_map_space)(new_addr, new_size, True);
+   /* There are 3 remaining cases:
 
-      if ((flags & VKI_MREMAP_FIXED) && a != new_addr)
-         /* didn't find the place we wanted */
-        return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+      * maymove == False
 
-      new_addr = a;
+        new space has to be at old address, so:
+            - shrink    -> unmap end
+            - same size -> do nothing
+            - grow      -> if can grow in-place, do so, else fail
 
-      /* we've nailed down the location */
-      flags |= VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE;
+      * maymove == True, fixed == False
 
-      ret = VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size, 
-                            flags, new_addr);
+        new space can be anywhere, so:
+            - shrink    -> unmap end
+            - same size -> do nothing
+            - grow      -> if can grow in-place, do so, else 
+                           move to anywhere large enough, else fail
 
-      if (ret.isError) {
-        return ret;
-      }
+      * maymove == True, fixed == True
 
-      VG_TRACK(copy_mem_remap, old_addr, new_addr, 
-              (old_size < new_size) ? old_size : new_size);
+        new space must be at new address, so:
 
-      if (new_size > old_size)
-        VG_TRACK(new_mem_mmap, new_addr+old_size, new_size-old_size,
-                 seg->prot & VKI_PROT_READ, 
-                 seg->prot & VKI_PROT_WRITE, 
-                 seg->prot & VKI_PROT_EXEC);
-      VG_TRACK(die_mem_munmap, old_addr, old_size);
+            - if new address is not page aligned, fail
+            - if new address range overlaps old one, fail
+            - if new address range cannot be allocated, fail
+            - else move to new address range with new size
+            - else fail
+   */
 
-      VG_(map_file_segment)(new_addr, new_size,
-                           seg->prot, 
-                           seg->flags,
-                           seg->dev, seg->ino,
-                           seg->offset, seg->filename);
+   if (f_maymove == False) {
+      /* new space has to be at old address */
+      if (new_len < old_len)
+         goto shrink_in_place;
+      if (new_len > old_len)
+         goto grow_in_place_or_fail;
+      goto same_in_place;
+   }
 
-      VG_(munmap)((void *)old_addr, old_size);
-   } else {
-      /* staying in place */
-      ret = VG_(mk_SysRes_Success)( old_addr );
+   if (f_maymove == True && f_fixed == False) {
+      /* new space can be anywhere */
+      if (new_len < old_len)
+         goto shrink_in_place;
+      if (new_len > old_len)
+         goto grow_in_place_or_move_anywhere_or_fail;
+      goto same_in_place;
+   }
 
-      if (new_size < old_size) {
-        VG_TRACK(die_mem_munmap, old_addr+new_size, old_size-new_size);
-        VG_(munmap)((void *)(old_addr+new_size), old_size-new_size);
+   if (f_maymove == True && f_fixed == True) {
+      /* new space can only be at the new address */
+      if (!VG_IS_PAGE_ALIGNED(new_addr)) 
+         goto eINVAL;
+      if (new_addr+new_len-1 < old_addr || new_addr > old_addr+old_len-1) {
+         /* no overlap */
       } else {
-        /* we've nailed down the location */
-        flags &= ~VKI_MREMAP_MAYMOVE;
-
-        if (0)
-           VG_(printf)("mremap: old_addr=%p old_size=%d new_size=%d flags=%d\n",
-                       old_addr, old_size, new_size, flags);
+         goto eINVAL;
+      }
+      if (new_addr == 0) 
+         goto eINVAL; 
+         /* VG_(am_get_advisory_client_simple) interprets zero to mean
+            non-fixed, which is not what we want */
+      advised = VG_(am_get_advisory_client_simple)(new_addr, new_len, &ok);
+      if (!ok || advised != new_addr)
+         goto eNOMEM;
+      ok = VG_(am_relocate_nooverlap_client)
+              ( &d, old_addr, old_len, new_addr, new_len );
+      if (ok) {
+         VG_TRACK( copy_mem_remap, old_addr, new_addr, 
+                                   MIN_SIZET(old_len,new_len) );
+         if (new_len > old_len)
+            VG_TRACK( new_mem_mmap, new_addr+old_len, new_len-old_len,
+                      old_seg->hasR, old_seg->hasW, old_seg->hasX );
+         VG_TRACK(die_mem_munmap, old_addr, old_len);
+         if (d) {
+            VG_(discard_translations)( old_addr, old_len, "do_remap(1)" );
+            VG_(discard_translations)( new_addr, new_len, "do_remap(2)" );
+         }
+         return VG_(mk_SysRes_Success)( new_addr );
+      }
+      goto eNOMEM;
+   }
 
-        ret = VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size, 
-                               flags, 0);
+   /* end of the 3 cases */
+   /*NOTREACHED*/ vg_assert(0);
+
+  grow_in_place_or_move_anywhere_or_fail: 
+   { 
+   /* try growing it in-place */
+   Addr   needA = old_addr + old_len;
+   SSizeT needL = new_len - old_len;
+
+   vg_assert(needL > 0);
+   if (needA == 0)
+      goto eINVAL; 
+      /* VG_(am_get_advisory_client_simple) interprets zero to mean
+         non-fixed, which is not what we want */
+   advised = VG_(am_get_advisory_client_simple)( needA, needL, &ok );
+   if (ok && advised == needA) {
+      ok = VG_(am_extend_map_client)( &d, old_seg, needL );
+      if (ok) {
+         VG_TRACK( new_mem_mmap, needA, needL, 
+                                 old_seg->hasR, 
+                                 old_seg->hasW, old_seg->hasX );
+         if (d) 
+            VG_(discard_translations)( needA, needL, "do_remap(3)" );
+         return VG_(mk_SysRes_Success)( old_addr );
+      }
+   }
 
-        if (ret.isError || (!ret.isError && ret.val != old_addr))
-           return ret;
+   /* that failed.  Look elsewhere. */
+   advised = VG_(am_get_advisory_client_simple)( 0, new_len, &ok );
+   if (ok) {
+      /* assert new area does not overlap old */
+      vg_assert(advised+new_len-1 < old_addr 
+                || advised > old_addr+old_len-1);
+      ok = VG_(am_relocate_nooverlap_client)
+              ( &d, old_addr, old_len, advised, new_len );
+      if (ok) {
+         VG_TRACK( copy_mem_remap, old_addr, advised, 
+                                   MIN_SIZET(old_len,new_len) );
+         if (new_len > old_len)
+            VG_TRACK( new_mem_mmap, advised+old_len, new_len-old_len,
+                      old_seg->hasR, old_seg->hasW, old_seg->hasX );
+         VG_TRACK(die_mem_munmap, old_addr, old_len);
+         if (d) {
+            VG_(discard_translations)( old_addr, old_len, "do_remap(4)" );
+            VG_(discard_translations)( advised, new_len, "do_remap(5)" );
+         }
+         return VG_(mk_SysRes_Success)( advised );
+      }
+   }
+   goto eNOMEM;
+   }
+   /*NOTREACHED*/ vg_assert(0);
 
-        VG_TRACK(new_mem_mmap, old_addr+old_size, new_size-old_size,
-                 seg->prot & VKI_PROT_READ, 
-                 seg->prot & VKI_PROT_WRITE, 
-                 seg->prot & VKI_PROT_EXEC);
+  grow_in_place_or_fail:
+   {
+   Addr  needA = old_addr + old_len;
+   SizeT needL = new_len - old_len;
+   if (needA == 0) 
+      goto eINVAL;
+      /* VG_(am_get_advisory_client_simple) interprets zero to mean
+         non-fixed, which is not what we want */
+   advised = VG_(am_get_advisory_client_simple)( needA, needL, &ok );
+   if (!ok || advised != needA)
+      goto eNOMEM;
+   ok = VG_(am_extend_map_client)( &d, old_seg, needL );
+   if (!ok)
+      goto eNOMEM;
+   VG_TRACK( new_mem_mmap, needA, needL, 
+                           old_seg->hasR, old_seg->hasW, old_seg->hasX );
+   if (d)
+      VG_(discard_translations)( needA, needL, "do_remap(6)" );
+   return VG_(mk_SysRes_Success)( old_addr );
+   }
+   /*NOTREACHED*/ vg_assert(0);
 
-        VG_(map_file_segment)(old_addr+old_size, new_size-old_size,
-                              seg->prot, 
-                              seg->flags,
-                              seg->dev, seg->ino,
-                              seg->offset, seg->filename);      
-      }
+  shrink_in_place:
+   {
+   SysRes sres = VG_(am_munmap_client)( &d, old_addr+new_len, old_len-new_len );
+   if (sres.isError)
+      return sres;
+   VG_TRACK( die_mem_munmap, old_addr+new_len, old_len-new_len );
+   if (d)
+      VG_(discard_translations)( old_addr+new_len, old_len-new_len, 
+                                 "do_remap(7)" );
+   return VG_(mk_SysRes_Success)( old_addr );
    }
+   /*NOTREACHED*/ vg_assert(0);
 
-   return ret;
+  same_in_place:
+   return VG_(mk_SysRes_Success)( old_addr );
+   /*NOTREACHED*/ vg_assert(0);
+
+  eINVAL:
+   return VG_(mk_SysRes_Error)( VKI_EINVAL );
+  eNOMEM:
+   return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+
+#  undef MIN_SIZET
 }
 
 
@@ -783,13 +905,29 @@ void buf_and_len_post_check( ThreadId tid, SysRes res,
    Data seg end, for brk()
    ------------------------------------------------------------------ */
 
-static Addr do_brk(Addr newbrk)
-{
-   Addr ret = VG_(brk_limit);
-   static const Bool debug = False;
-   Segment *seg;
-   Addr current, newaddr;
+/*   +--------+------------+
+     | anon   |    resvn   |
+     +--------+------------+
+
+     ^     ^  ^
+     |     |  boundary is page aligned
+     |     VG_(brk_limit) -- no alignment constraint
+     VG_(brk_base) -- page aligned -- does not move
+
+     Both the anon part and the reservation part are always at least
+     one page.  
+*/
 
+/* Set the new data segment end to NEWBRK.  If this succeeds, return
+   NEWBRK, else return the current data segment end. */
+
+static Addr do_brk ( Addr newbrk )
+{
+   NSegment *aseg, *rseg;
+   Addr newbrkP;
+   SizeT delta;
+   Bool ok;
+   Bool debug = False;
 
    if (debug)
       VG_(printf)("\ndo_brk: brk_base=%p brk_limit=%p newbrk=%p\n",
@@ -799,65 +937,59 @@ static Addr do_brk(Addr newbrk)
    if (0) show_segments("in_brk");
 #  endif
 
-   if (newbrk < VG_(brk_base) || newbrk >= VG_(client_end))
-      return VG_(brk_limit);
-
-   /* brk isn't allowed to grow over anything else */
-   seg = VG_(find_segment)(VG_(brk_limit) -1);
-
-   vg_assert(seg != NULL);
+   if (newbrk < VG_(brk_base))
+      /* Clearly impossible. */
+      goto bad;
+
+   if (newbrk >= VG_(brk_base) && newbrk < VG_(brk_limit)) {
+      /* shrinking the data segment.  Be lazy and don't munmap the
+         excess area. */
+      NSegment* seg = VG_(am_find_nsegment)(newbrk);
+      if (seg && seg->hasT)
+         VG_(discard_translations)( newbrk, VG_(brk_limit) - newbrk, 
+                                    "do_brk(shrink)" );
+      VG_(brk_limit) = newbrk;
+      return newbrk;
+   }
 
-   if (0)
-      VG_(printf)("brk_limit=%p seg->addr=%p seg->end=%p\n", 
-                 VG_(brk_limit), seg->addr, seg->addr+seg->len);
-   vg_assert(VG_(brk_limit) >= seg->addr && VG_(brk_limit) 
-             <= (seg->addr + seg->len));
-
-   seg = VG_(find_segment_above_mapped)(VG_(brk_limit)-1);
-   if (0 && seg) 
-      VG_(printf)("NEXT addr = %p\n", seg->addr);
-   if (seg != NULL && newbrk > seg->addr)
-      return VG_(brk_limit);
-
-   current = VG_PGROUNDUP(VG_(brk_limit));
-   newaddr = VG_PGROUNDUP(newbrk);
-   if (newaddr != current) {
-
-      /* new brk in a new page - fix the mappings */
-      if (newbrk > VG_(brk_limit)) {
-        
-        if (debug)
-           VG_(printf)("  extending brk: current=%p newaddr=%p delta=%d\n",
-                       current, newaddr, newaddr-current);
-
-        if (newaddr == current) {
-           ret = newbrk;
-         } else if ((void*)-1 != VG_(mmap)((void*)current, newaddr-current,
-               VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
-               VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS|VKI_MAP_FIXED|VKI_MAP_CLIENT,
-               0, -1, 0)) 
-         {
-           ret = newbrk;
-        }
-      } else {
-        vg_assert(newbrk < VG_(brk_limit));
+   /* otherwise we're expanding the brk segment. */
+   aseg = VG_(am_find_nsegment)( VG_(brk_base) );
+   rseg = VG_(am_next_nsegment)( aseg, True/*forwards*/ );
+
+   /* These should be assured by setup_client_dataseg in m_main. */
+   vg_assert(aseg);
+   vg_assert(rseg);
+   vg_assert(aseg->kind == SkAnonC);
+   vg_assert(rseg->kind == SkResvn);
+   vg_assert(aseg->end+1 == rseg->start);
+
+   vg_assert(newbrk >= VG_(brk_base));
+   if (newbrk <= rseg->start) {
+      /* still fits within the anon segment. */
+      VG_(brk_limit) = newbrk;
+      return newbrk;
+   }
 
-        if (debug)
-           VG_(printf)("  shrinking brk: current=%p newaddr=%p delta=%d\n",
-                       current, newaddr, current-newaddr);
+   if (newbrk >= rseg->end+1 - VKI_PAGE_SIZE) {
+      /* request is too large -- the resvn would fall below 1 page,
+         which isn't allowed. */
+      goto bad;
+   }
 
-        if (newaddr != current) {
-           Int res = VG_(munmap)((void *)newaddr, current - newaddr);
-            vg_assert(0 == res);
-        }
-        ret = newbrk;
-      }
-   } else
-      ret = newbrk;
+   newbrkP = VG_PGROUNDUP(newbrk);
+   vg_assert(newbrkP > rseg->start && newbrkP < rseg->end+1 - VKI_PAGE_SIZE);
+   delta = newbrkP - rseg->start;
+   vg_assert(delta > 0);
+   vg_assert(VG_IS_PAGE_ALIGNED(delta));
+   
+   ok = VG_(am_extend_into_adjacent_reservation_client)( aseg, delta );
+   if (!ok) goto bad;
 
-   VG_(brk_limit) = ret;
+   VG_(brk_limit) = newbrk;
+   return newbrk;
 
-   return ret;
+  bad:
+   return VG_(brk_limit);
 }
 
 
@@ -868,9 +1000,8 @@ static Addr do_brk(Addr newbrk)
 /* Return true if we're allowed to use or create this fd */
 Bool ML_(fd_allowed)(Int fd, const Char *syscallname, ThreadId tid, Bool soft)
 {
-   if ((fd < 0 || fd >= VG_(fd_hard_limit) || fd == VG_(clo_log_fd)) &&
-       VG_(showing_core_errors)())
-   {
+   if ( (fd < 0 || fd >= VG_(fd_hard_limit) || fd == VG_(clo_log_fd)) 
+        && VG_(showing_core_errors)() ) {
       VG_(message)(Vg_UserMsg, 
          "Warning: invalid file descriptor %d in syscall %s()",
          fd, syscallname);
@@ -1435,9 +1566,14 @@ ML_(generic_PRE_sys_shmat) ( ThreadId tid,
                              UWord arg0, UWord arg1, UWord arg2 )
 {
    /* void *shmat(int shmid, const void *shmaddr, int shmflg); */
-   UInt segmentSize = get_shm_size ( arg0 );
-   if (arg1 == 0)
-      arg1 = VG_(find_map_space)(0, segmentSize, True);
+   UInt  segmentSize = get_shm_size ( arg0 );
+   UWord tmp;
+   Bool  ok;
+   if (arg1 == 0) {
+      tmp = VG_(am_get_advisory_client_simple)(0, segmentSize, &ok);
+      if (ok)
+         arg1 = tmp;
+   }
    else if (!ML_(valid_client_addr)(arg1, segmentSize, tid, "shmat"))
       arg1 = 0;
    return arg1;
@@ -1451,13 +1587,30 @@ ML_(generic_POST_sys_shmat) ( ThreadId tid,
    UInt segmentSize = get_shm_size ( arg0 );
    if ( segmentSize > 0 ) {
       UInt prot = VKI_PROT_READ|VKI_PROT_WRITE;
-      /* we don't distinguish whether it's read-only or
-       * read-write -- it doesn't matter really. */
-      VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False );
+      Bool d;
 
       if (!(arg2 & 010000)) /* = SHM_RDONLY */
          prot &= ~VKI_PROT_WRITE;
-      VG_(map_segment)(res, segmentSize, prot, SF_SHARED|SF_SHM);
+      /* It isn't exactly correct to pass 0 for the fd and offset
+         here.  The kernel seems to think the corresponding section
+         does have dev/ino numbers:
+         
+         04e52000-04ec8000 rw-s 00000000 00:06 1966090  /SYSV00000000 (deleted)
+
+         However there is no obvious way to find them.  In order to
+         cope with the discrepancy, aspacem's sync checker omits the
+         dev/ino correspondence check in cases where V does not know
+         the dev/ino. */
+      d = VG_(am_notify_client_mmap)( res, VG_PGROUNDUP(segmentSize), 
+                                      prot, VKI_MAP_ANONYMOUS, 0,0);
+
+      /* we don't distinguish whether it's read-only or
+       * read-write -- it doesn't matter really. */
+      VG_TRACK( new_mem_mmap, res, segmentSize, True, True, False );
+      if (d)
+         VG_(discard_translations)( (Addr64)res, 
+                                    (ULong)VG_PGROUNDUP(segmentSize),
+                                    "ML_(generic_POST_sys_shmat)" );
    }
 }
 
@@ -1473,11 +1626,17 @@ ML_(generic_PRE_sys_shmdt) ( ThreadId tid, UWord arg0 )
 void
 ML_(generic_POST_sys_shmdt) ( ThreadId tid, UWord res, UWord arg0 )
 {
-   Segment *s = VG_(find_segment)(arg0);
-
-   if (s != NULL && (s->flags & SF_SHM) && VG_(seg_contains)(s, arg0, 1)) {
-      VG_TRACK( die_mem_munmap, s->addr, s->len );
-      VG_(unmap_range)(s->addr, s->len);
+   NSegment* s = VG_(am_find_nsegment)(arg0);
+
+   if (s != NULL /* && (s->flags & SF_SHM) */
+                 /* && Implied by defn of am_find_nsegment:
+                       VG_(seg_contains)(s, arg0, 1) */) {
+      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
+      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
+      if (d)
+         VG_(discard_translations)( (Addr64)(s->start),
+                                    (ULong)(s->end+1 - s->start),
+                                    "ML_(generic_POST_sys_shmdt)" );
    }
 }
 /* ------ */
@@ -1784,7 +1943,7 @@ PRE(sys_mremap)
                  unsigned long, new_size, unsigned long, flags,
                  unsigned long, new_addr);
    SET_STATUS_from_SysRes( 
-      mremap_segment((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid) 
+      do_mremap((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid) 
    );
 }
 
@@ -1967,9 +2126,13 @@ void VG_(reap_threads)(ThreadId self)
 // but it seems to work nonetheless...
 PRE(sys_execve)
 {
-   Char*        path;          /* path to executable */
+   Char*        path = NULL;       /* path to executable */
    Char**       envp = NULL;
+   Char**       argv = NULL;
+   Char**       arg2copy;
+   Char*        launcher_basename = NULL;
    ThreadState* tst;
+   Int          i, j, tot_args;
 
    PRINT("sys_execve ( %p(%s), %p, %p )", ARG1, ARG1, ARG2, ARG3);
    PRE_REG_READ3(vki_off_t, "execve",
@@ -1980,17 +2143,15 @@ PRE(sys_execve)
    if (ARG3 != 0)
       pre_argv_envp( ARG3, tid, "execve(envp)", "execve(envp[i])" );
 
-   path = (Char *)ARG1;
-
    vg_assert(VG_(is_valid_tid)(tid));
    tst = VG_(get_ThreadState)(tid);
 
    /* Erk.  If the exec fails, then the following will have made a
       mess of things which makes it hard for us to continue.  The
       right thing to do is piece everything together again in
-      POST(execve), but that's hard work.  Instead, we make an effort
-      to check that the execve will work before actually calling
-      exec. */
+      POST(execve), but that's close to impossible.  Instead, we make
+      an effort to check that the execve will work before actually
+      doing it. */
    {
       struct vki_stat st;
       SysRes r = VG_(stat)((Char *)ARG1, &st);
@@ -2009,44 +2170,113 @@ PRE(sys_execve)
       }
    }
 
+   /* Check more .. that the name at least begins in client-accessible
+      storage. */
+   if (!VG_(am_is_valid_for_client)( ARG1, 1, VKI_PROT_READ )) {
+      SET_STATUS_Failure( VKI_EFAULT );
+      return;
+   }
+
+   /* After this point, we can't recover if the execve fails. */
+   VG_(debugLog)(1, "syswrap", "Exec of %s\n", (Char*)ARG1);
+
    /* Resistance is futile.  Nuke all other threads.  POSIX mandates
       this. (Really, nuke them all, since the new process will make
       its own new thread.) */
    VG_(nuke_all_threads_except)( tid, VgSrc_ExitSyscall );
    VG_(reap_threads)(tid);
 
+   // Set up the child's exe path.
+   //
+   if (VG_(clo_trace_children)) {
+
+      // We want to exec the launcher.  Get its pre-remembered path.
+      path = VG_(name_of_launcher);
+      // VG_(name_of_launcher) should have been acquired by m_main at
+      // startup.
+      vg_assert(path);
+
+      launcher_basename = VG_(strrchr)(path, '/');
+      if (launcher_basename == NULL || launcher_basename[1] == 0) {
+         launcher_basename = path;  // hmm, tres dubious
+      } else {
+         launcher_basename++;
+      }
+
+   } else {
+      path = (Char*)ARG1;
+   }
+
+   // Set up the child's environment.
+   //
    // Remove the valgrind-specific stuff from the environment so the
    // child doesn't get vgpreload_core.so, vgpreload_<tool>.so, etc.  
    // This is done unconditionally, since if we are tracing the child,
-   // stage1/2 will set up the appropriate client environment.
+   // the child valgrind will set up the appropriate client environment.
    // Nb: we make a copy of the environment before trying to mangle it
    // as it might be in read-only memory (this was bug #101881).
-   if (ARG3 != 0) {
+   //
+   // Then, if tracing the child, set VALGRIND_LIB for it.
+   //
+   if (ARG3 == 0) {
+      envp = NULL;
+   } else {
       envp = VG_(env_clone)( (Char**)ARG3 );
+      if (envp == NULL) goto hosed;
       VG_(env_remove_valgrind_env_stuff)( envp );
    }
 
    if (VG_(clo_trace_children)) {
-      Char* optvar = VG_(build_child_VALGRINDCLO)( (Char*)ARG1 );
-
-      // Set VALGRINDCLO and VALGRINDLIB in ARG3 (the environment)
-      VG_(env_setenv)( (Char***)&ARG3, VALGRINDCLO, optvar);
-      VG_(env_setenv)( (Char***)&ARG3, VALGRINDLIB, VG_(libdir));
-
-      // Create executable name: "/proc/self/fd/<vgexecfd>", update ARG1
-      path = VG_(build_child_exename)();
+      // Set VALGRIND_LIB in ARG3 (the environment)
+      VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
    }
 
-   VG_(debugLog)(1, "syswrap", "Exec of %s\n", (HChar*)ARG1);
-
-   if (0) {
-      Char **cpp;
-
-      VG_(printf)("exec: %s\n", (Char *)ARG1);
-      for(cpp = (Char **)ARG2; cpp && *cpp; cpp++)
-         VG_(printf)("argv: %s\n", *cpp);
-      for(cpp = (Char **)ARG3; cpp && *cpp; cpp++)
-         VG_(printf)("env: %s\n", *cpp);
+   // Set up the child's args.  If not tracing it, they are
+   // simply ARG2.  Otherwise, they are
+   //
+   // [launcher_basename] ++ VG_(args_for_valgrind) ++ [ARG1] ++ ARG2[1..]
+   //
+   // except that the first VG_(args_for_valgrind_noexecpass) args
+   // are omitted.
+   //
+   if (!VG_(clo_trace_children)) {
+      argv = (Char**)ARG2;
+   } else {
+      vg_assert( VG_(args_for_valgrind_noexecpass) >= 0 );
+      vg_assert( VG_(args_for_valgrind_noexecpass) 
+                   <= VG_(args_for_valgrind).used );
+      /* how many args in total will there be? */
+      // launcher basename
+      tot_args = 1;
+      // V's args
+      tot_args += VG_(args_for_valgrind).used;
+      tot_args -= VG_(args_for_valgrind_noexecpass);
+      // name of client exe
+      tot_args++;
+      // args for client exe, skipping [0]
+      arg2copy = (Char**)ARG2;
+      if (arg2copy && arg2copy[0]) {
+         for (i = 1; arg2copy[i]; i++)
+            tot_args++;
+      }
+      // allocate
+      argv = VG_(malloc)( (tot_args+1) * sizeof(HChar*) );
+      if (argv == 0) goto hosed;
+      // copy
+      j = 0;
+      argv[j++] = launcher_basename;
+      for (i = 0; i < VG_(args_for_valgrind).used; i++) {
+         if (i < VG_(args_for_valgrind_noexecpass))
+            continue;
+         argv[j++] = VG_(args_for_valgrind).strs[i];
+      }
+      argv[j++] = (Char*)ARG1;
+      if (arg2copy && arg2copy[0])
+         for (i = 1; arg2copy[i]; i++)
+            argv[j++] = arg2copy[i];
+      argv[j++] = NULL;
+      // check
+      vg_assert(j == tot_args+1);
    }
 
    /* restore the DATA rlimit for the child */
@@ -2073,9 +2303,8 @@ PRE(sys_execve)
       vki_sigset_t allsigs;
       vki_siginfo_t info;
       static const struct vki_timespec zero = { 0, 0 };
-      Int i;
 
-      for(i = 1; i < VG_(max_signal); i++) {
+      for (i = 1; i < VG_(max_signal); i++) {
          struct vki_sigaction sa;
          VG_(do_sys_sigaction)(i, NULL, &sa);
          if (sa.ksa_handler == VKI_SIG_IGN)
@@ -2093,12 +2322,23 @@ PRE(sys_execve)
       VG_(sigprocmask)(VKI_SIG_SETMASK, &tst->sig_mask, NULL);
    }
 
+   if (0) {
+      Char **cpp;
+      VG_(printf)("exec: %s\n", path);
+      for (cpp = argv; cpp && *cpp; cpp++)
+         VG_(printf)("argv: %s\n", *cpp);
+      if (0)
+         for (cpp = envp; cpp && *cpp; cpp++)
+            VG_(printf)("env: %s\n", *cpp);
+   }
+
    SET_STATUS_from_SysRes( 
-      VG_(do_syscall3)(__NR_execve, (UWord)path, ARG2, ARG3
+      VG_(do_syscall3)(__NR_execve, (UWord)path, (UWord)argv, (UWord)envp
    );
 
-   /* If we got here, then the execve failed.  We've already made too
-      much of a mess of ourselves to continue, so we have to abort. */
+   /* If we got here, then the execve failed.  We've already made way
+      too much of a mess to continue, so we have to abort. */
+  hosed:
    vg_assert(FAILURE);
    VG_(message)(Vg_UserMsg, "execve(%p(%s), %p, %p) failed, errno %d",
                 ARG1, ARG1, ARG2, ARG3, RES_unchecked);
@@ -4164,13 +4404,18 @@ POST(sys_mprotect)
    Addr a    = ARG1;
    SizeT len = ARG2;
    Int  prot = ARG3;
-   Bool rr = prot & VKI_PROT_READ;
-   Bool ww = prot & VKI_PROT_WRITE;
-   Bool xx = prot & VKI_PROT_EXEC;
+   Bool rr = toBool(prot & VKI_PROT_READ);
+   Bool ww = toBool(prot & VKI_PROT_WRITE);
+   Bool xx = toBool(prot & VKI_PROT_EXEC);
+   Bool d;
 
-   mash_addr_and_len(&a, &len);
-   VG_(mprotect_range)(a, len, prot);
+   page_align_addr_and_len(&a, &len);
+   d = VG_(am_notify_mprotect)(a, len, prot);
    VG_TRACK( change_mem_mprotect, a, len, rr, ww, xx );
+   VG_(di_notify_mprotect)( a, len, prot );
+   if (d)
+      VG_(discard_translations)( (Addr64)a, (ULong)len, 
+                                 "POST(sys_mprotect)" );
 }
 
 PRE(sys_munmap)
@@ -4187,10 +4432,15 @@ POST(sys_munmap)
 {
    Addr  a   = ARG1;
    SizeT len = ARG2;
+   Bool  d;
 
-   mash_addr_and_len(&a, &len);
-   VG_(unmap_range)(a, len);
+   page_align_addr_and_len(&a, &len);
+   d = VG_(am_notify_munmap)(a, len);
    VG_TRACK( die_mem_munmap, a, len );
+   VG_(di_notify_munmap)( a, len );
+   if (d)
+      VG_(discard_translations)( (Addr64)a, (ULong)len,
+                                 "POST(sys_munmap)" );
 }
 
 PRE(sys_mincore)
@@ -4226,7 +4476,9 @@ POST(sys_nanosleep)
 
 PRE(sys_open)
 {
-   *flags |= SfMayBlock;
+   HChar  name[30];
+   SysRes sres;
+
    if (ARG2 & VKI_O_CREAT) {
       // 3-arg version
       PRINT("sys_open ( %p(%s), %d, %d )",ARG1,ARG1,ARG2,ARG3);
@@ -4239,6 +4491,28 @@ PRE(sys_open)
                     const char *, filename, int, flags);
    }
    PRE_MEM_RASCIIZ( "open(filename)", ARG1 );
+
+   /* Handle the case where the open is of /proc/self/cmdline or
+      /proc/<pid>/cmdline, and just give it a copy of the fd for the
+      fake file we cooked up at startup (in m_main).  Also, seek the
+      cloned fd back to the start. */
+
+   VG_(sprintf)(name, "/proc/%d/cmdline", VG_(getpid)());
+   if (ML_(safe_to_deref)( (void*)ARG1, 1 )
+       && (VG_(strcmp)((Char *)ARG1, name) == 0 
+           || VG_(strcmp)((Char *)ARG1, "/proc/self/cmdline") == 0)) {
+      sres = VG_(dup)( VG_(cl_cmdline_fd) );
+      SET_STATUS_from_SysRes( sres );
+      if (!sres.isError) {
+         OffT off = VG_(lseek)( sres.val, 0, VKI_SEEK_SET );
+         if (off)
+            SET_STATUS_Failure( VKI_EMFILE );
+      }
+      return;
+   }
+
+   /* Otherwise handle normally */
+   *flags |= SfMayBlock;
 }
 
 POST(sys_open)
@@ -4274,11 +4548,18 @@ POST(sys_read)
 
 PRE(sys_write)
 {
+   Bool ok;
    *flags |= SfMayBlock;
    PRINT("sys_write ( %d, %p, %llu )", ARG1, ARG2, (ULong)ARG3);
    PRE_REG_READ3(ssize_t, "write",
                  unsigned int, fd, const char *, buf, vki_size_t, count);
-   if (!ML_(fd_allowed)(ARG1, "write", tid, False))
+   /* check to see if it is allowed.  If not, try for an exemption from
+      --weird-hacks=enable-outer (used for self hosting). */
+   ok = ML_(fd_allowed)(ARG1, "write", tid, False);
+   if (!ok && ARG1 == 2/*stderr*/ 
+           && VG_(strstr)(VG_(clo_weird_hacks),"enable-outer"))
+      ok = True;
+   if (!ok)
       SET_STATUS_Failure( VKI_EBADF );
    else
       PRE_MEM_READ( "write(buf)", ARG2, ARG3 );
@@ -4366,7 +4647,7 @@ PRE(sys_readlink)
       VG_(sprintf)(name, "/proc/%d/exe", VG_(getpid)());
       if (VG_(strcmp)((Char *)ARG1, name) == 0 ||
           VG_(strcmp)((Char *)ARG1, "/proc/self/exe") == 0) {
-         VG_(sprintf)(name, "/proc/self/fd/%d", VG_(clexecfd));
+         VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd));
          SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name, ARG2, ARG3));
       }
    }
@@ -4785,3 +5066,4 @@ POST(sys_sigaltstack)
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
+
index 90920204f89809cdd1de7d6b412310400795dc76..86e7dcf500f631558110705e7161e61632c5b018 100644 (file)
@@ -30,8 +30,9 @@
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
+#include "pub_core_debuginfo.h"    // VG_(di_notify_*)
+#include "pub_core_transtab.h"     // VG_(discard_translations)
 #include "pub_core_debuglog.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
@@ -419,7 +420,8 @@ PRE(sys_sysctl)
    args = (struct __vki_sysctl_args *)ARG1;
    PRE_REG_READ1(long, "sysctl", struct __sysctl_args *, args);
    PRE_MEM_WRITE( "sysctl(args)", ARG1, sizeof(struct __vki_sysctl_args) );
-   if (!VG_(is_addressable)(ARG1, sizeof(struct __vki_sysctl_args), VKI_PROT_READ)) {
+   if (!VG_(am_is_valid_for_client)(ARG1, sizeof(struct __vki_sysctl_args), 
+                                          VKI_PROT_READ)) {
       SET_STATUS_Failure( VKI_EFAULT );
       return;
    }
@@ -548,6 +550,9 @@ POST(sys_futex)
 
 PRE(sys_mmap2)
 {
+   Addr   advised;
+   SysRes sres;
+
    // Exactly like old_mmap() in x86-linux except:
    //  - all 6 args are passed in regs, rather than in a memory-block.
    //  - the file offset is specified in pagesize units rather than bytes,
@@ -574,28 +579,63 @@ PRE(sys_mmap2)
       return;
    }
 
+   /* Figure out what kind of allocation constraints there are
+      (fixed/hint/any), and ask aspacem what we should do. */
    if (ARG4 & VKI_MAP_FIXED) {
-      if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mmap2"))
-        SET_STATUS_Failure( VKI_ENOMEM );
+      if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mmap2")) {
+         SET_STATUS_Failure( VKI_EINVAL );
+         return;
+      }
+
+      advised = ARG1;
    } else {
-      Addr a = VG_(find_map_space)(ARG1, ARG2, True);
-      if (a == 0 && ARG1 != 0)
-         a = VG_(find_map_space)(0, ARG2, True);
-      if (a == 0) {
-        SET_STATUS_Failure( VKI_ENOMEM );
+      MapRequest mreq;
+      Bool       mreq_ok;
+
+      mreq.start = ARG1;
+      mreq.len   = ARG2;
+
+      if (ARG1 != 0) {
+         mreq.rkind = MHint;
       } else {
-         ARG1 = a;
-         ARG4 |= VKI_MAP_FIXED;
+         mreq.rkind = MAny;
+      }
+
+      /* Enquire ... */
+      advised = VG_(am_get_advisory)( &mreq, True/*client*/, &mreq_ok );
+      if (!mreq_ok) {
+         /* Our request was bounced, so we'd better fail. */
+         SET_STATUS_Failure( VKI_EINVAL );
+         return;
       }
    }
+
+   vg_assert(! FAILURE);
+
+   /* Otherwise we're OK (so far).  Install aspacem's choice of
+      address, and let the mmap go through.  */
+   sres = VG_(am_do_mmap_NO_NOTIFY)(advised, ARG2, ARG3,
+                                    ARG4 | VKI_MAP_FIXED,
+                                    ARG5, ARG6);
+   SET_STATUS_from_SysRes(sres);
+
+   if (!sres.isError) {
+      /* Notify aspacem and the tool. */
+      ML_(notify_aspacem_and_tool_of_mmap)( 
+         (Addr)sres.val, /* addr kernel actually assigned */
+         ARG2, ARG3, 
+         ARG4, /* the original flags value */
+         ARG5, ARG6 
+      );
+      /* Load symbols? */
+      VG_(di_notify_mmap)( (Addr)sres.val );
+   }
+
+   /* Stay sane */
+   if (SUCCESS && (ARG4 & VKI_MAP_FIXED))
+      vg_assert(RES == ARG1);
 }
-POST(sys_mmap2)
-{
-   vg_assert(SUCCESS);
-   vg_assert(ML_(valid_client_addr)(RES, ARG2, tid, "mmap2"));
-   ML_(mmap_segment)( (Addr)RES, ARG2, ARG3, ARG4, ARG5,
-                      ARG6 * (ULong)VKI_PAGE_SIZE );
-}
+
 
 /* ---------------------------------------------------------------------
    epoll_* wrappers
@@ -747,43 +787,30 @@ PRE(sys_fadvise64_64)
 // Nb: this wrapper has to pad/unpad memory around the syscall itself,
 // and this allows us to control exactly the code that gets run while
 // the padding is in place.
+
 PRE(sys_io_setup)
 {
-   SizeT size;
-   Addr addr;
-
    PRINT("sys_io_setup ( %u, %p )", ARG1,ARG2);
    PRE_REG_READ2(long, "io_setup",
                  unsigned, nr_events, vki_aio_context_t *, ctxp);
    PRE_MEM_WRITE( "io_setup(ctxp)", ARG2, sizeof(vki_aio_context_t) );
-   
+}
+
+POST(sys_io_setup)
+{
+   SizeT size;
+   struct vki_aio_ring *r;
+           
    size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) +
                        ARG1*sizeof(struct vki_io_event));
-   addr = VG_(find_map_space)(0, size, True);
-   
-   if (addr == 0) {
-      SET_STATUS_Failure( VKI_ENOMEM );
-      return;
-   }
+   r = *(struct vki_aio_ring **)ARG2;
+   vg_assert(ML_(valid_client_addr)((Addr)r, size, tid, "io_setup"));
 
-   VG_(map_segment)(addr, size, VKI_PROT_READ|VKI_PROT_WRITE, 0);
-   
-   VG_(pad_address_space)(0);
-   SET_STATUS_from_SysRes( VG_(do_syscall2)(SYSNO, ARG1, ARG2) );
-   VG_(unpad_address_space)(0);
-
-   if (SUCCESS && RES == 0) {
-      struct vki_aio_ring *r = *(struct vki_aio_ring **)ARG2;
-        
-      vg_assert(addr == (Addr)r);
-      vg_assert(ML_(valid_client_addr)(addr, size, tid, "io_setup"));
-                
-      VG_TRACK( new_mem_mmap, addr, size, True, True, False );
-      POST_MEM_WRITE( ARG2, sizeof(vki_aio_context_t) );
-   }
-   else {
-      VG_(unmap_range)(addr, size);
-   }
+   ML_(notify_aspacem_and_tool_of_mmap)( (Addr)r, size,
+                                         VKI_PROT_READ | VKI_PROT_WRITE,
+                                         VKI_MAP_ANONYMOUS, -1, 0 );
+
+   POST_MEM_WRITE( ARG2, sizeof(vki_aio_context_t) );
 }
 
 // Nb: This wrapper is "Special" because we need 'size' to do the unmap
@@ -795,8 +822,7 @@ PRE(sys_io_setup)
 // XXX This segment can be implicitly unmapped when aio
 // file-descriptors are closed...
 PRE(sys_io_destroy)
-{     
-   Segment *s = VG_(find_segment)(ARG1);
+{
    struct vki_aio_ring *r;
    SizeT size;
       
@@ -805,15 +831,18 @@ PRE(sys_io_destroy)
 
    // If we are going to seg fault (due to a bogus ARG1) do it as late as
    // possible...
-   r = *(struct vki_aio_ring **)ARG1;
+   r = (struct vki_aio_ring *)ARG1;
    size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) + 
                        r->nr*sizeof(struct vki_io_event));
 
    SET_STATUS_from_SysRes( VG_(do_syscall1)(SYSNO, ARG1) );
 
-   if (SUCCESS && RES == 0 && s != NULL) { 
+   if (SUCCESS && RES == 0) { 
+      Bool d = VG_(am_notify_munmap)( ARG1, size );
       VG_TRACK( die_mem_munmap, ARG1, size );
-      VG_(unmap_range)(ARG1, size);
+      if (d)
+         VG_(discard_translations)( (Addr64)ARG1, (ULong)size, 
+                                    "PRE(sys_io_destroy)" );
    }  
 }  
 
index 7e0233e6c799562bd64a3b16ed48d869d407e07b..3bf1efcd5ff5d470885c1a7ce16e935621692640 100644 (file)
    build signal frames).  Do not do this.  If you want a signal poll
    after the syscall goes through, do "*flags |= SfPollAfter" and the
    driver logic will do it for you.
+
+   -----------
+
+   Another critical requirement following introduction of new address
+   space manager (JRS, 20050923):
+
+   In a situation where the mappedness of memory has changed, aspacem
+   should be notified BEFORE the tool.  Hence the following is
+   correct:
+
+      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
+      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
+      if (d)
+         VG_(discard_translations)(s->start, s->end+1 - s->start);
+
+   whilst this is wrong:
+
+      VG_TRACK( die_mem_munmap, s->start, s->end+1 - s->start );
+      Bool d = VG_(am_notify_munmap)(s->start, s->end+1 - s->start);
+      if (d)
+         VG_(discard_translations)(s->start, s->end+1 - s->start);
+
+   The reason is that the tool may itself ask aspacem for more shadow
+   memory as a result of the VG_TRACK call.  In such a situation it is
+   critical that aspacem's segment array is up to date -- hence the
+   need to notify aspacem first.
+
+   -----------
+
+   Also .. take care to call VG_(discard_translations) whenever
+   memory with execute permissions is unmapped.
 */
 
 
@@ -642,7 +673,7 @@ void VG_(client_syscall) ( ThreadId tid )
          success. */
       PRINT(" --> [pre-success] Success(0x%llx)\n", (Long)sci->status.val );
                                        
-      /* In this case thes allowable flag are to ask for a signal-poll
+      /* In this case the allowable flags are to ask for a signal-poll
          and/or a yield after the call.  Changing the args isn't
          allowed. */
       vg_assert(0 == (sci->flags & ~(SfPollAfter | SfYieldAfter)));
index b5dfb9d7c03d0608ad669f5ab9c59f95fe908d6b..648fb02f524df1cfec1f3584dd784306912516ae 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debuglog.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
@@ -438,6 +436,10 @@ static SysRes do_clone ( ThreadId ptid,
    vg_assert(VG_(is_valid_tid)(ctid));
 
    stack = allocstack(ctid);
+   if (stack == NULL) {
+      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
+      goto out;
+   }
 
 //?   /* make a stack frame */
 //?   stack -= 16;
@@ -2066,7 +2068,11 @@ const SyscallTableEntry ML_(syscall_table)[] = {
 //..    //   (__NR_reboot,            sys_reboot),            // 88 */Linux
 //..    //   (__NR_readdir,           old_readdir),           // 89 -- superseded
 
+<<<<<<< .working
    LINXY(__NR_mmap,              sys_mmap2),                  // 90
+=======
+   GENX_(__NR_mmap,              sys_mmap2),                  // 90
+>>>>>>> .merge-right.r4787
    GENXY(__NR_munmap,            sys_munmap),                 // 91
 //..    GENX_(__NR_truncate,          sys_truncate),          // 92
    GENX_(__NR_ftruncate,         sys_ftruncate),         // 93
@@ -2192,7 +2198,11 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    GENX_(__NR_vfork,             sys_fork),              // 189
    GENXY(__NR_ugetrlimit,        sys_getrlimit),         // 190
 //__NR_readahead      // 191 ppc/Linux only?
+<<<<<<< .working
    LINXY(__NR_mmap2,             sys_mmap2),             // 192
+=======
+   GENX_(__NR_mmap2,             sys_mmap2),             // 192
+>>>>>>> .merge-right.r4787
 //..    GENX_(__NR_truncate64,        sys_truncate64),        // 193
 //..    GENX_(__NR_ftruncate64,       sys_ftruncate64),       // 194
 //..    
index 57b0f07d39d2aac154a47864ae34628811d5e0d5..778f9b73848dd74fa190c2348e86542bb3b73b49 100644 (file)
 
 #include "pub_core_basics.h"
 #include "pub_core_threadstate.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
+#include "pub_core_debuginfo.h"     // VG_(di_notify_mmap)
 #include "pub_core_aspacemgr.h"
 #include "pub_core_debuglog.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
    Note.  Why is this stuff here?
    ------------------------------------------------------------------ */
 
-/* 
-   Allocate a stack for this thread.
-
-   They're allocated lazily, but never freed.
- */
-#define FILL   0xdeadbeef
+/* Allocate a stack for this thread.  They're allocated lazily, and
+   never freed. */
 
-// Valgrind's stack size, in words.
-#define STACK_SIZE_W      16384
+/* Allocate a stack for this thread, if it doesn't already have one.
+   Returns the initial stack pointer value to use, or 0 if allocation
+   failed. */
 
-static UWord* allocstack(ThreadId tid)
+static Addr allocstack ( ThreadId tid )
 {
-   ThreadState *tst = VG_(get_ThreadState)(tid);
-   UWord *esp;
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+   VgStack*     stack;
+   Addr         initial_SP;
 
-   if (tst->os_state.valgrind_stack_base == 0) {
-      void *stk = VG_(mmap)(0, STACK_SIZE_W * sizeof(UWord) + VKI_PAGE_SIZE,
-                           VKI_PROT_READ|VKI_PROT_WRITE,
-                           VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
-                           SF_VALGRIND,
-                           -1, 0);
-
-      if (stk != (void *)-1) {
-         VG_(mprotect)(stk, VKI_PAGE_SIZE, VKI_PROT_NONE); /* guard page */
-         tst->os_state.valgrind_stack_base = ((Addr)stk) + VKI_PAGE_SIZE;
-         tst->os_state.valgrind_stack_szB  = STACK_SIZE_W * sizeof(UWord);
-      } else 
-      return (UWord*)-1;
-   }
+   /* Either the stack_base and stack_init_SP are both zero (in which
+      case a stack hasn't been allocated) or they are both non-zero,
+      in which case it has. */
 
-   for (esp = (UWord*) tst->os_state.valgrind_stack_base;
-        esp < (UWord*)(tst->os_state.valgrind_stack_base + 
-                       tst->os_state.valgrind_stack_szB); 
-        esp++)
-      *esp = FILL;
-   /* esp is left at top of stack */
+   if (tst->os_state.valgrind_stack_base == 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
 
-   if (0)
-      VG_(printf)("stack for tid %d at %p (%x); esp=%p\n",
-                 tid, tst->os_state.valgrind_stack_base, 
-                  *(UWord*)(tst->os_state.valgrind_stack_base), esp);
+   if (tst->os_state.valgrind_stack_base != 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
 
-   return esp;
-}
+   /* If no stack is present, allocate one. */
 
-/* NB: this is identical the the amd64 version. */
-/* Return how many bytes of this stack have not been used */
-SSizeT VG_(stack_unused)(ThreadId tid)
-{
-   ThreadState *tst = VG_(get_ThreadState)(tid);
-   UWord* p;
-
-   for (p = (UWord*)tst->os_state.valgrind_stack_base; 
-       p && (p < (UWord*)(tst->os_state.valgrind_stack_base +
-                           tst->os_state.valgrind_stack_szB)); 
-       p++)
-      if (*p != FILL)
-        break;
+   if (tst->os_state.valgrind_stack_base == 0) {
+      stack = VG_(am_alloc_VgStack)( &initial_SP );
+      if (stack) {
+         tst->os_state.valgrind_stack_base    = (Addr)stack;
+         tst->os_state.valgrind_stack_init_SP = initial_SP;
+      }
+   }
 
    if (0)
-      VG_(printf)("p=%p %x tst->os_state.valgrind_stack_base=%p\n",
-                  p, *p, tst->os_state.valgrind_stack_base);
-
-   return ((Addr)p) - tst->os_state.valgrind_stack_base;
+      VG_(printf)( "stack for tid %d at %p; init_SP=%p\n",
+                   tid, 
+                   (void*)tst->os_state.valgrind_stack_base, 
+                   (void*)tst->os_state.valgrind_stack_init_SP );
+                  
+   return tst->os_state.valgrind_stack_init_SP;
 }
 
 
@@ -237,22 +212,27 @@ asm(
 );
 
 
-/*
-   Allocate a stack for the main thread, and run it all the way to the
-   end.  
+/* Allocate a stack for the main thread, and run it all the way to the
+   end.  Although we already have a working VgStack
+   (VG_(the_root_stack)) it's better to allocate a new one, so that
+   overflow detection works uniformly for all threads.
 */
 void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
 {
    VG_(debugLog)(1, "syswrap-x86-linux", 
                     "entering VG_(main_thread_wrapper_NORETURN)\n");
 
-   UWord* esp = allocstack(tid);
+   Addr esp = allocstack(tid);
+
+   /* If we can't even allocate the first thread's stack, we're hosed.
+      Give up. */
+   vg_assert2(esp != 0, "Cannot allocate main thread's stack.");
 
    /* shouldn't be any other threads around yet */
    vg_assert( VG_(count_living_threads)() == 1 );
 
    call_on_new_stack_0_1( 
-      (Addr)esp,              /* stack */
+      esp,                    /* stack */
       0,                      /*bogus return address*/
       run_a_thread_NORETURN,  /* fn to call */
       (Word)tid               /* arg to give it */
@@ -395,7 +375,7 @@ static SysRes do_clone ( ThreadId ptid,
    ThreadState* ptst = VG_(get_ThreadState)(ptid);
    ThreadState* ctst = VG_(get_ThreadState)(ctid);
    UWord*       stack;
-   Segment*     seg;
+   NSegment*    seg;
    SysRes       res;
    Int          eax;
    vki_sigset_t blockall, savedmask;
@@ -405,7 +385,11 @@ static SysRes do_clone ( ThreadId ptid,
    vg_assert(VG_(is_running_thread)(ptid));
    vg_assert(VG_(is_valid_tid)(ctid));
 
-   stack = allocstack(ctid);
+   stack = (UWord*)allocstack(ctid);
+   if (stack == NULL) {
+      res = VG_(mk_SysRes_Error)( VKI_ENOMEM );
+      goto out;
+   }
 
    /* Copy register state
 
@@ -443,14 +427,14 @@ static SysRes do_clone ( ThreadId ptid,
       memory mappings and try to derive some useful information.  We
       assume that esp starts near its highest possible value, and can
       only go down to the start of the mmaped segment. */
-   seg = VG_(find_segment)((Addr)esp);
-   if (seg) {
+   seg = VG_(am_find_nsegment)((Addr)esp);
+   if (seg && seg->kind != SkResvn) {
       ctst->client_stack_highest_word = (Addr)VG_PGROUNDUP(esp);
-      ctst->client_stack_szB  = ctst->client_stack_highest_word - seg->addr;
+      ctst->client_stack_szB = ctst->client_stack_highest_word - seg->start;
 
       if (debug)
         VG_(printf)("tid %d: guessed client stack range %p-%p\n",
-                    ctid, seg->addr, VG_PGROUNDUP(esp));
+                    ctid, seg->start, VG_PGROUNDUP(esp));
    } else {
       VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%p) unmapped\n",
                   ctid, esp);
@@ -1043,21 +1027,24 @@ PRE(sys_clone)
 
    if (ARG1 & VKI_CLONE_PARENT_SETTID) {
       PRE_MEM_WRITE("clone(parent_tidptr)", ARG3, sizeof(Int));
-      if (!VG_(is_addressable)(ARG3, sizeof(Int), VKI_PROT_WRITE)) {
+      if (!VG_(am_is_valid_for_client)(ARG3, sizeof(Int), 
+                                             VKI_PROT_WRITE)) {
          SET_STATUS_Failure( VKI_EFAULT );
          return;
       }
    }
    if (ARG1 & (VKI_CLONE_CHILD_SETTID | VKI_CLONE_CHILD_CLEARTID)) {
       PRE_MEM_WRITE("clone(child_tidptr)", ARG5, sizeof(Int));
-      if (!VG_(is_addressable)(ARG5, sizeof(Int), VKI_PROT_WRITE)) {
+      if (!VG_(am_is_valid_for_client)(ARG5, sizeof(Int), 
+                                             VKI_PROT_WRITE)) {
          SET_STATUS_Failure( VKI_EFAULT );
          return;
       }
    }
    if (ARG1 & VKI_CLONE_SETTLS) {
       PRE_MEM_READ("clone(tls_user_desc)", ARG4, sizeof(vki_modify_ldt_t));
-      if (!VG_(is_addressable)(ARG4, sizeof(vki_modify_ldt_t), VKI_PROT_READ)) {
+      if (!VG_(am_is_valid_for_client)(ARG4, sizeof(vki_modify_ldt_t), 
+                                             VKI_PROT_READ)) {
          SET_STATUS_Failure( VKI_EFAULT );
          return;
       }
@@ -1483,17 +1470,19 @@ PRE(old_mmap)
          unsigned long offset;
    }; */
    UWord a1, a2, a3, a4, a5, a6;
+   Addr       advised;
+   SysRes     sres;
 
    UWord* args = (UWord*)ARG1;
    PRE_REG_READ1(long, "old_mmap", struct mmap_arg_struct *, args);
    PRE_MEM_READ( "old_mmap(args)", (Addr)args, 6*sizeof(UWord) );
 
-   a1 = args[0];
-   a2 = args[1];
-   a3 = args[2];
-   a4 = args[3];
-   a5 = args[4];
-   a6 = args[5];
+   a1 = args[1-1];
+   a2 = args[2-1];
+   a3 = args[3-1];
+   a4 = args[4-1];
+   a5 = args[5-1];
+   a6 = args[6-1];
 
    PRINT("old_mmap ( %p, %llu, %d, %d, %d, %d )",
          a1, (ULong)a2, a3, a4, a5, a6 );
@@ -1505,48 +1494,65 @@ PRE(old_mmap)
       return;
    }
 
-   if (/*(a4 & VKI_MAP_FIXED) &&*/ (0 != (a1 & (VKI_PAGE_SIZE-1)))) {
+   if (/*(a4 & VKI_MAP_FIXED) &&*/ !VG_IS_PAGE_ALIGNED(a1)) {
       /* zap any misaligned addresses. */
       SET_STATUS_Failure( VKI_EINVAL );
       return;
    }
 
+   /* Figure out what kind of allocation constraints there are
+      (fixed/hint/any), and ask aspacem what we should do. */
    if (a4 & VKI_MAP_FIXED) {
-      if (!ML_(valid_client_addr)(a1, a2, tid, "old_mmap")) {
-         PRINT("old_mmap failing: %p-%p\n", a1, a1+a2);
-         SET_STATUS_Failure( VKI_ENOMEM );
+      if (!ML_(valid_client_addr)(a1, a2, tid, "mmap2")) {
+         SET_STATUS_Failure( VKI_EINVAL );
+         return;
       }
    } else {
-      Addr a = VG_(find_map_space)(a1, a2, True);
-      if (0) VG_(printf)("find_map_space(%p, %d) -> %p\n",a1,a2,a);
-      if (a == 0 && a1 != 0) {
-         a1 = VG_(find_map_space)(0, a2, True);
+      MapRequest mreq;
+      Bool       mreq_ok;
+
+      mreq.start = a1;
+      mreq.len   = a2;
+
+      if (a1 != 0) {
+         mreq.rkind = MHint;
+      } else {
+         mreq.rkind = MAny;
       }
-      else
-         a1 = a;
-      if (a1 == 0)
-         SET_STATUS_Failure( VKI_ENOMEM );
-      else
-         a4 |= VKI_MAP_FIXED;
-   }
 
-   if (! FAILURE) {
-      SysRes res = VG_(mmap_native)((void*)a1, a2, a3, a4, a5, a6);
-      SET_STATUS_from_SysRes(res);
-      if (!res.isError) {
-         vg_assert(ML_(valid_client_addr)(res.val, a2, tid, "old_mmap"));
-         ML_(mmap_segment)( (Addr)res.val, a2, a3, a4, a5, a6 );
+      /* Enquire ... */
+      advised = VG_(am_get_advisory)( &mreq, True/*client*/, &mreq_ok );
+      if (!mreq_ok) {
+         /* Our request was bounced, so we'd better fail. */
+         SET_STATUS_Failure( VKI_EINVAL );
+         return;
       }
+
+      /* Otherwise we're OK (so far).  Install aspacem's choice of
+         address, and let the mmap go through.  */
+      a1 = advised;
+      a4 |= VKI_MAP_FIXED;
    }
 
-   if (0)
-   VG_(printf)("old_mmap( %p, fixed %d ) -> %s(%p)\n", 
-               args[0], 
-               args[3]&VKI_MAP_FIXED, 
-               FAILURE ? "Fail" : "Success", RES_unchecked);
+   vg_assert(! FAILURE);
+
+   sres = VG_(am_do_mmap_NO_NOTIFY)(a1, a2, a3, a4, a5, a6);
+   SET_STATUS_from_SysRes(sres);
+
+   if (!sres.isError) {
+      /* Notify aspacem and the tool. */
+      ML_(notify_aspacem_and_tool_of_mmap)( 
+         (Addr)sres.val, /* addr kernel actually assigned */
+         a2, a3, 
+         args[4-1], /* the original flags value */
+         a5, a6 
+      );
+      /* Load symbols? */
+      VG_(di_notify_mmap)( (Addr)sres.val );
+   }
 
    /* Stay sane */
-   if (SUCCESS && (args[3] & VKI_MAP_FIXED))
+   if (SUCCESS && (args[4-1] & VKI_MAP_FIXED))
       vg_assert(RES == args[0]);
 }
 
@@ -1876,7 +1882,8 @@ PRE(sys_sigaction)
       PRE_MEM_READ( "sigaction(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
       PRE_MEM_READ( "sigaction(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
       PRE_MEM_READ( "sigaction(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
-      if (sa->sa_flags & VKI_SA_RESTORER)
+      if (ML_(safe_to_deref)(sa,sizeof(sa)) 
+          && (sa->sa_flags & VKI_SA_RESTORER))
          PRE_MEM_READ( "sigaction(act->sa_restorer)", (Addr)&sa->sa_restorer, sizeof(sa->sa_restorer));
    }
 
@@ -2173,7 +2180,7 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    // Nb: we treat vfork as fork
    GENX_(__NR_vfork,             sys_fork),           // 190
    GENXY(__NR_ugetrlimit,        sys_getrlimit),      // 191
-   LINXY(__NR_mmap2,             sys_mmap2),          // 192
+   LINX_(__NR_mmap2,             sys_mmap2),          // 192
    GENX_(__NR_truncate64,        sys_truncate64),     // 193
    GENX_(__NR_ftruncate64,       sys_ftruncate64),    // 194
    
@@ -2237,7 +2244,7 @@ const SyscallTableEntry ML_(syscall_table)[] = {
    PLAX_(__NR_set_thread_area,   sys_set_thread_area),   // 243
    PLAX_(__NR_get_thread_area,   sys_get_thread_area),   // 244
 
-   LINX_(__NR_io_setup,          sys_io_setup),       // 245
+   LINXY(__NR_io_setup,          sys_io_setup),       // 245
    LINX_(__NR_io_destroy,        sys_io_destroy),     // 246
    LINXY(__NR_io_getevents,      sys_io_getevents),   // 247
    LINX_(__NR_io_submit,         sys_io_submit),      // 248
index a13f3efd8ffadb164fd927057ec3e42e7c786ccc..7c9da50967602e44b6c484834876e2124c0f8e66 100644 (file)
@@ -96,7 +96,7 @@ VgNeeds VG_(needs) = {
 };
 
 /* static */
-Bool VG_(sanity_check_needs)(Bool non_zero_shadow_memory, Char** failmsg)
+Bool VG_(sanity_check_needs)(Char** failmsg)
 {
 #define CHECK_NOT(var, value)                                  \
    if ((var)==(value)) {                                       \
@@ -137,12 +137,6 @@ Bool VG_(sanity_check_needs)(Bool non_zero_shadow_memory, Char** failmsg)
       return False;
    }
 
-   if (VG_(needs).shadow_memory != non_zero_shadow_memory) {
-      *failmsg = "Tool error: VG_(needs).shadow_memory doesn't match\n"
-                 "   the 'shadow_ratio' set in VG_DETERMINE_INTERFACE_VERSION\n";
-      return False;
-   }
-
    return True;
 
 #undef CHECK_NOT
index 32614b9070151e91ff4fcef2c6e13017752acb90..5db984472f84673e096594183181b3687f4d87b2 100644 (file)
@@ -28,7 +28,7 @@
   The GNU General Public License is contained in the file COPYING.
 */
 
-#include "pub_tool_basics_asm.h"
+#include "pub_core_basics_asm.h"
 #include "vki_unistd.h"
 
 /* ------------------ SIMULATED CPU HELPERS ------------------ */
    This code runs on the simulated CPU.
 */
 
+#      define UD2_16     ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2
+#      define UD2_64     UD2_16   ; UD2_16   ; UD2_16   ; UD2_16
+#      define UD2_256    UD2_64   ; UD2_64   ; UD2_64   ; UD2_64
+#      define UD2_1024   UD2_256  ; UD2_256  ; UD2_256  ; UD2_256
+#      define UD2_PAGE   UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024  
+
+       /* a leading page of unexecutable code */
+       UD2_PAGE
+       
 /*---------------- x86-linux ----------------*/
 #if defined(VGP_x86_linux)
 
@@ -138,6 +147,15 @@ VG_(trampoline_stuff_end):
 #endif
 #endif
 
+       /* and a trailing page of unexecutable code */
+       UD2_PAGE
+
+#      undef UD2_16
+#      undef UD2_64
+#      undef UD2_256
+#      undef UD2_1024
+#      undef UD2_PAGE
+
 
 /* Let the linker know we don't need an executable stack */
 .section .note.GNU-stack,"",@progbits
index 9e7adfb5da73820fb2edf3ccca3a9a8b7f0c9f5b..3793eb739bf7e9b706142259ad0ee4189664447c 100644 (file)
@@ -30,7 +30,6 @@
 */
 
 #include "pub_core_basics.h"
-#include "pub_core_debuginfo.h"     // Needed for pub_core_aspacemgr :(
 #include "pub_core_aspacemgr.h"
 #include "pub_core_cpuid.h"
 #include "pub_core_machine.h"       // For VG_(cache_line_size_ppc32)
 #include "pub_core_libcprint.h"
 #include "pub_core_options.h"
 #include "pub_core_profile.h"
+
+#include "pub_core_debuginfo.h"     // Needed for pub_core_redir :(
 #include "pub_core_redir.h"         // For VG_(code_redirect)()
+
 #include "pub_core_signals.h"       // For VG_(synth_fault_{perms,mapping})()
 #include "pub_core_stacks.h"        // For VG_(unknown_SP_update)()
 #include "pub_core_tooliface.h"     // For VG_(tdict)
@@ -381,6 +383,24 @@ void log_bytes ( HChar* bytes, Int nbytes )
    'tid' is the identity of the thread needing this block.
 */
 
+/* Look for reasons to disallow making translations from the given
+   segment. */
+
+static Bool translations_allowable_from_seg ( NSegment* seg )
+{
+#  if defined(VGA_x86)
+   Bool allowR = True;
+#  else
+   Bool allowR = False;
+#  endif
+
+   return seg != NULL
+          && (seg->kind == SkAnonC || seg->kind == SkFileC)
+          && (seg->hasX || (seg->hasR && allowR));
+}
+
+
+
 /* This stops Vex from chasing into function entry points that we wish
    to redirect.  Chasing across them obviously defeats the redirect
    mechanism, with bad effects for Memcheck, Addrcheck, and possibly
@@ -397,6 +417,8 @@ void log_bytes ( HChar* bytes, Int nbytes )
 static ThreadId chase_into_ok__CLOSURE_tid;
 static Bool     chase_into_ok ( Addr64 addr64 )
 {
+   NSegment* seg;
+
    /* Work through a list of possibilities why we might not want to
       allow a chase. */
    Addr addr = (Addr)addr64;
@@ -405,15 +427,20 @@ static Bool     chase_into_ok ( Addr64 addr64 )
    if (VG_(clo_smc_check) == Vg_SmcAll)
       goto dontchase;
 
+   /* Check the segment permissions. */
+   seg = VG_(am_find_nsegment)(addr);
+   if (!translations_allowable_from_seg(seg))
+      goto dontchase;
+
    /* AAABBBCCC: if default self-checks are in force, reject if we
       would choose to have a self-check for the dest.  Note, this must
       match the logic at XXXYYYZZZ below. */
    if (VG_(clo_smc_check) == Vg_SmcStack) {
       ThreadId tid = chase_into_ok__CLOSURE_tid;
-      Segment* seg = VG_(find_segment)(addr);
-      if (seg 
-          && seg->addr <= VG_(get_SP)(tid)
-          && VG_(get_SP)(tid) < seg->addr+seg->len)
+      if (seg
+          && (seg->kind == SkAnonC || seg->kind == SkFileC)
+          && seg->start <= VG_(get_SP)(tid)
+          && VG_(get_SP)(tid)+sizeof(Word)-1 <= seg->end)
          goto dontchase;
    }
 
@@ -440,10 +467,10 @@ Bool VG_(translate) ( ThreadId tid,
                       ULong    bbs_done )
 {
    Addr64    redir, orig_addr0 = orig_addr;
-   Int       tmpbuf_used, verbosity;
+   Int       tmpbuf_used, verbosity, i;
    Bool      notrace_until_done, do_self_check;
    UInt      notrace_until_limit = 0;
-   Segment*  seg;
+   NSegment* seg;
    VexGuestExtents vge;
 
    /* Indicates what arch we are running on, and other important info
@@ -514,10 +541,9 @@ Bool VG_(translate) ( ThreadId tid,
    notrace_until_done
       = VG_(get_bbs_translated)() >= notrace_until_limit;
 
-   seg = VG_(find_segment)(orig_addr);
-
    if (!debugging_translation)
-      VG_TRACK( pre_mem_read, Vg_CoreTranslate, tid, "", orig_addr, 1 );
+      VG_TRACK( pre_mem_read, Vg_CoreTranslate, 
+                              tid, "(translator)", orig_addr, 1 );
 
    /* If doing any code printing, print a basic block start marker */
    if (VG_(clo_trace_flags) || debugging_translation) {
@@ -529,22 +555,25 @@ Bool VG_(translate) ( ThreadId tid,
               bbs_done);
    }
 
-   if (seg == NULL ||
-       !VG_(seg_contains)(seg, orig_addr, 1) || 
-       (seg->prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == 0) {
-      /* Code address is bad - deliver a signal instead */
-      vg_assert(!VG_(is_addressable)(orig_addr, 1, 
-                                     VKI_PROT_READ|VKI_PROT_EXEC));
+   /* Are we allowed to translate here? */
+
+   seg = VG_(am_find_nsegment)(orig_addr);
 
-      if (seg != NULL && VG_(seg_contains)(seg, orig_addr, 1)) {
-         vg_assert((seg->prot & VKI_PROT_EXEC) == 0);
+   if (!translations_allowable_from_seg(seg)) {
+      /* U R busted, sonny.  Place your hands on your head and step
+         away from the orig_addr. */
+      /* Code address is bad - deliver a signal instead */
+      if (seg != NULL) {
+         /* There's some kind of segment at the requested place, but we
+            aren't allowed to execute code here. */
          VG_(synth_fault_perms)(tid, orig_addr);
-      } else
+      } else {
+        /* There is no segment at all; we are attempting to execute in
+           the middle of nowhere. */
          VG_(synth_fault_mapping)(tid, orig_addr);
-
+      }
       return False;
-   } else
-      seg->flags |= SF_CODE;        /* contains cached code */
+   }
 
    /* Do we want a self-checking translation? */
    do_self_check = False;
@@ -556,8 +585,8 @@ Bool VG_(translate) ( ThreadId tid,
          do_self_check
             /* = seg ? toBool(seg->flags & SF_GROWDOWN) : False; */
             = seg 
-              ? (seg->addr <= VG_(get_SP)(tid)
-                 && VG_(get_SP)(tid) < seg->addr+seg->len)
+              ? (seg->start <= VG_(get_SP)(tid)
+                 && VG_(get_SP)(tid)+sizeof(Word)-1 <= seg->end)
               : False;
          break;
       default: 
@@ -608,6 +637,20 @@ Bool VG_(translate) ( ThreadId tid,
 
    VGP_POPCC(VgpVexTime);
 
+   /* Tell aspacem of all segments that have had translations taken
+      from them.  Optimisation: don't re-look up vge.base[0] since seg
+      should already point to it. */
+
+   vg_assert( vge.base[0] == (Addr64)orig_addr );
+   if (seg->kind == SkFileC || seg->kind == SkAnonC)
+      seg->hasT = True; /* has cached code */
+
+   for (i = 1; i < vge.n_used; i++) {
+      seg = VG_(am_find_nsegment)( vge.base[i] );
+      if (seg->kind == SkFileC || seg->kind == SkAnonC)
+         seg->hasT = True; /* has cached code */
+   }
+
    /* Copy data at trans_addr into the translation cache. */
    vg_assert(tmpbuf_used > 0 && tmpbuf_used < 65536);
 
index f83ea28bcf971a4f66f688a18541a30b8b8cf59e..459f8e617c7e4a858f0ed8ddbe2e900de06686ba 100644 (file)
 */
 
 #include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_machine.h"    // ppc32: VG_(cache_line_size_ppc32)
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
-#include "pub_core_libcmman.h"   // For VG_(get_memory_from_mmap)()
 #include "pub_core_libcprint.h"
 #include "pub_core_options.h"
 #include "pub_core_tooliface.h"  // For VG_(details).avg_translation_sizeB
 #include "pub_core_transtab.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_mallocfree.h" // VG_(out_of_memory_NORETURN)
 
 /* #define DEBUG_TRANSTAB */
 
@@ -288,7 +290,8 @@ static void invalidateFastCache ( void )
 
 static void initialiseSector ( Int sno )
 {
-   Int i;
+   Int    i;
+   SysRes sres;
    vg_assert(isValidSector(sno));
 
    if (sectors[sno].tc == NULL) {
@@ -297,16 +300,31 @@ static void initialiseSector ( Int sno )
       vg_assert(sectors[sno].tt == NULL);
       vg_assert(sectors[sno].tc_next == NULL);
       vg_assert(sectors[sno].tt_n_inuse == 0);
-      sectors[sno].tc 
-         = VG_(get_memory_from_mmap)
-              ( 8 * tc_sector_szQ, "sectors[sno].tc" );
-      sectors[sno].tt 
-         = VG_(get_memory_from_mmap) 
-              ( N_TTES_PER_SECTOR * sizeof(TTEntry), "sectors[sno].tt" );
+
+      VG_(debugLog)(1,"transtab", "allocate sector %d\n", sno);
+
+      sres = VG_(am_mmap_anon_float_valgrind)( 8 * tc_sector_szQ );
+      if (sres.isError) {
+         VG_(out_of_memory_NORETURN)("initialiseSector(TC)", 
+                                     8 * tc_sector_szQ );
+        /*NOTREACHED*/
+      }
+      sectors[sno].tc = (ULong*)sres.val;
+
+      sres = VG_(am_mmap_anon_float_valgrind)
+                ( N_TTES_PER_SECTOR * sizeof(TTEntry) );
+      if (sres.isError) {
+         VG_(out_of_memory_NORETURN)("initialiseSector(TT)", 
+                                     N_TTES_PER_SECTOR * sizeof(TTEntry) );
+        /*NOTREACHED*/
+      }
+      sectors[sno].tt = (TTEntry*)sres.val;
+
       if (VG_(clo_verbosity) > 2)
          VG_(message)(Vg_DebugMsg, "TT/TC: initialise sector %d", sno);
    } else {
       /* Sector has been used before. */
+      VG_(debugLog)(1,"transtab", "recycle sector %d\n", sno);
       vg_assert(sectors[sno].tt != NULL);
       vg_assert(sectors[sno].tc_next != NULL);
       n_dump_count += sectors[sno].tt_n_inuse;
@@ -563,13 +581,18 @@ Bool overlaps ( Addr64 start, ULong range, VexGuestExtents* vge )
 }
 
 
-void VG_(discard_translations) ( Addr64 guest_start, ULong range )
+void VG_(discard_translations) ( Addr64 guest_start, ULong range,
+                                 HChar* who )
 {
    Int sno, i;
    Bool anyDeleted = False;
 
    vg_assert(init_done);
 
+   VG_(debugLog)(1, "transtab",
+                    "discard_translations(0x%llx, %lld) req by %s\n",
+                    guest_start, range, who );
+
    for (sno = 0; sno < N_SECTORS; sno++) {
       if (sectors[sno].tc == NULL)
          continue;
@@ -641,6 +664,16 @@ void VG_(init_tt_tc) ( void )
          N_SECTORS * N_TTES_PER_SECTOR_USABLE, 
          SECTOR_TT_LIMIT_PERCENT );
    }
+
+   VG_(debugLog)(2, "transtab",
+      "cache: %d sectors of %d bytes each = %d total\n", 
+       N_SECTORS, 8 * tc_sector_szQ,
+       N_SECTORS * 8 * tc_sector_szQ );
+   VG_(debugLog)(2, "transtab",
+      "table: %d total entries, max occupancy %d (%d%%)\n",
+      N_SECTORS * N_TTES_PER_SECTOR,
+      N_SECTORS * N_TTES_PER_SECTOR_USABLE, 
+      SECTOR_TT_LIMIT_PERCENT );
 }
 
 
index c27a0037886f444bf9b9471e1f2509bea70a3585..09f47d92d180ab244b57a2130a76c6f3e9bfa5c9 100644 (file)
 // included ahead of the glibc ones.  This fix is a kludge;  the right
 // solution is to entirely remove the glibc dependency.
 #include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_machine.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcfile.h"    // VG_(close) et al
+#include "pub_core_libcproc.h"    // VG_(geteuid), VG_(getegid)
+#include "pub_core_libcassert.h"  // VG_(exit), vg_assert
+#include "pub_core_syscall.h"     // VG_(strerror)
+#include "pub_core_mallocfree.h"  // VG_(malloc), VG_(free)
+#include "pub_core_aspacemgr.h"   // various mapping fns
+#include "vki_unistd.h"           // mmap-related constants
+
 #include "pub_core_ume.h"
 
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
 
 #if    VG_WORDSIZE == 8
 #define ESZ(x) Elf64_##x
@@ -66,172 +68,173 @@ struct elfinfo
    int         fd;
 };
 
-static void check_mmap(void* res, void* base, int len)
-{
-   if ((void*)-1 == res) {
-      fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
-      exit(1);
-   }
-}
-
-// 'extra' allows the caller to pass in extra args to 'fn', like free
-// variables to a closure.
-void VG_(foreach_map)(int (*fn)(char *start, char *end,
-                                const char *perm, off_t offset,
-                                int maj, int min, int ino, void* extra),
-                      void* extra)
+static void check_mmap(SysRes res, Addr base, SizeT len)
 {
-   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];
-      ULong offset;
-      int maj, min;
-      int ino;
-      void *segstart, *segend;
-
-      sscanf(bufptr, "%p-%p %s %llx %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, extra))
-        break;
+   if (res.isError) {
+      VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME.\n", 
+                  (ULong)base, (Long)len);
+      VG_(exit)(1);
    }
 }
 
-/*------------------------------------------------------------*/
-/*--- Stack switching                                      ---*/
-/*------------------------------------------------------------*/
-
-// __attribute__((noreturn))
-// void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
-#if defined(VGA_x86)
-// 4(%esp) == stack
-// 8(%esp) == dst
-asm(
-".global vgPlain_jump_and_switch_stacks\n"
-"vgPlain_jump_and_switch_stacks:\n"
-"   movl   %esp, %esi\n"      // remember old stack pointer
-"   movl   4(%esi), %esp\n"   // set stack
-"   pushl  8(%esi)\n"         // dst to stack
-"   movl $0, %eax\n"          // zero all GP regs
-"   movl $0, %ebx\n"
-"   movl $0, %ecx\n"
-"   movl $0, %edx\n"
-"   movl $0, %esi\n"
-"   movl $0, %edi\n"
-"   movl $0, %ebp\n"
-"   ret\n"                    // jump to dst
-"   ud2\n"                    // should never get here
-);
-#elif defined(VGA_amd64)
-// %rdi == stack
-// %rsi == dst
-asm(
-".global vgPlain_jump_and_switch_stacks\n"
-"vgPlain_jump_and_switch_stacks:\n"
-"   movq   %rdi, %rsp\n"   // set stack
-"   pushq  %rsi\n"         // dst to stack
-"   movq $0, %rax\n"       // zero all GP regs
-"   movq $0, %rbx\n"
-"   movq $0, %rcx\n"
-"   movq $0, %rdx\n"
-"   movq $0, %rsi\n"
-"   movq $0, %rdi\n"
-"   movq $0, %rbp\n"
-"   movq $0, %r8\n"\
-"   movq $0, %r9\n"\
-"   movq $0, %r10\n"
-"   movq $0, %r11\n"
-"   movq $0, %r12\n"
-"   movq $0, %r13\n"
-"   movq $0, %r14\n"
-"   movq $0, %r15\n"
-"   ret\n"                 // jump to dst
-"   ud2\n"                 // should never get here
-);
-
-#elif defined(VGA_ppc32)
-/* Jump to 'dst', but first set the stack pointer to 'stack'.  Also,
-   clear all the integer registers before entering 'dst'.  It's
-   important that the stack pointer is set to exactly 'stack' and not
-   (eg) stack - apparently_harmless_looking_small_offset.  Basically
-   because the code at 'dst' might be wanting to scan the area above
-   'stack' (viz, the auxv array), and putting spurious words on the
-   stack confuses it.
-*/
-// %r3 == stack
-// %r4 == dst
-asm(
-".global vgPlain_jump_and_switch_stacks\n"
-"vgPlain_jump_and_switch_stacks:\n"
-"   mtctr %r4\n\t"         // dst to %ctr
-"   mr %r1,%r3\n\t"        // stack to %sp
-"   li 0,0\n\t"            // zero all GP regs
-"   li 3,0\n\t"
-"   li 4,0\n\t"
-"   li 5,0\n\t"
-"   li 6,0\n\t"
-"   li 7,0\n\t"
-"   li 8,0\n\t"
-"   li 9,0\n\t"
-"   li 10,0\n\t"
-"   li 11,0\n\t"
-"   li 12,0\n\t"
-"   li 13,0\n\t"           // CAB: This right? r13 = small data area ptr
-"   li 14,0\n\t"
-"   li 15,0\n\t"
-"   li 16,0\n\t"
-"   li 17,0\n\t"
-"   li 18,0\n\t"
-"   li 19,0\n\t"
-"   li 20,0\n\t"
-"   li 21,0\n\t"
-"   li 22,0\n\t"
-"   li 23,0\n\t"
-"   li 24,0\n\t"
-"   li 25,0\n\t"
-"   li 26,0\n\t"
-"   li 27,0\n\t"
-"   li 28,0\n\t"
-"   li 29,0\n\t"
-"   li 30,0\n\t"
-"   li 31,0\n\t"
-"   mtxer 0\n\t"
-"   mtcr 0\n\t"
-"   mtlr %r0\n\t"
-"   bctr\n\t"              // jump to dst
-"   trap\n"                // should never get here
-);
-
-#else
-#  error Unknown architecture
-#endif
+//zz // 'extra' allows the caller to pass in extra args to 'fn', like free
+//zz // variables to a closure.
+//zz void VG_(foreach_map)(int (*fn)(char *start, char *end,
+//zz                                 const char *perm, off_t offset,
+//zz                                 int maj, int min, int ino, void* extra),
+//zz                       void* extra)
+//zz {
+//zz    static char buf[10240];
+//zz    char *bufptr = buf;
+//zz    int ret, fd;
+//zz 
+//zz    fd = open("/proc/self/maps", O_RDONLY);
+//zz 
+//zz    if (fd == -1) {
+//zz       perror("open /proc/self/maps");
+//zz       return;
+//zz    }
+//zz 
+//zz    ret = read(fd, buf, sizeof(buf));
+//zz 
+//zz    if (ret == -1) {
+//zz       perror("read /proc/self/maps");
+//zz       close(fd);
+//zz       return;
+//zz    }
+//zz    close(fd);
+//zz 
+//zz    if (ret == sizeof(buf)) {
+//zz       VG_(printf)("coregrind/m_ume.c: buf too small\n");
+//zz       return;
+//zz    }
+//zz 
+//zz    while(bufptr && bufptr < buf+ret) {
+//zz       char perm[5];
+//zz       ULong offset;
+//zz       int maj, min;
+//zz       int ino;
+//zz       void *segstart, *segend;
+//zz 
+//zz       sscanf(bufptr, "%p-%p %s %llx %x:%x %d",
+//zz        &segstart, &segend, perm, &offset, &maj, &min, &ino);
+//zz       bufptr = strchr(bufptr, '\n');
+//zz       if (bufptr != NULL)
+//zz    bufptr++; /* skip \n */
+//zz 
+//zz       if (!(*fn)(segstart, segend, perm, offset, maj, min, ino, extra))
+//zz    break;
+//zz    }
+//zz }
+//zz 
+//zz /*------------------------------------------------------------*/
+//zz /*--- Stack switching                                      ---*/
+//zz /*------------------------------------------------------------*/
+//zz 
+//zz // __attribute__((noreturn))
+//zz // void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
+//zz #if defined(VGA_x86)
+//zz // 4(%esp) == stack
+//zz // 8(%esp) == dst
+//zz asm(
+//zz ".global vgPlain_jump_and_switch_stacks\n"
+//zz "vgPlain_jump_and_switch_stacks:\n"
+//zz "   movl   %esp, %esi\n"      // remember old stack pointer
+//zz "   movl   4(%esi), %esp\n"   // set stack
+//zz "   pushl  8(%esi)\n"         // dst to stack
+//zz "   movl $0, %eax\n"          // zero all GP regs
+//zz "   movl $0, %ebx\n"
+//zz "   movl $0, %ecx\n"
+//zz "   movl $0, %edx\n"
+//zz "   movl $0, %esi\n"
+//zz "   movl $0, %edi\n"
+//zz "   movl $0, %ebp\n"
+//zz "   ret\n"                    // jump to dst
+//zz "   ud2\n"                    // should never get here
+//zz );
+//zz #elif defined(VGA_amd64)
+//zz // %rdi == stack
+//zz // %rsi == dst
+//zz asm(
+//zz ".global vgPlain_jump_and_switch_stacks\n"
+//zz "vgPlain_jump_and_switch_stacks:\n"
+//zz "   movq   %rdi, %rsp\n"   // set stack
+//zz "   pushq  %rsi\n"         // dst to stack
+//zz "   movq $0, %rax\n"       // zero all GP regs
+//zz "   movq $0, %rbx\n"
+//zz "   movq $0, %rcx\n"
+//zz "   movq $0, %rdx\n"
+//zz "   movq $0, %rsi\n"
+//zz "   movq $0, %rdi\n"
+//zz "   movq $0, %rbp\n"
+//zz "   movq $0, %r8\n"
+//zz "   movq $0, %r9\n"
+//zz "   movq $0, %r10\n"
+//zz "   movq $0, %r11\n"
+//zz "   movq $0, %r12\n"
+//zz "   movq $0, %r13\n"
+//zz "   movq $0, %r14\n"
+//zz "   movq $0, %r15\n"
+//zz "   ret\n"                 // jump to dst
+//zz "   ud2\n"                 // should never get here
+//zz );
+//zz 
+//zz #elif defined(VGA_ppc32)
+//zz /* Jump to 'dst', but first set the stack pointer to 'stack'.  Also,
+//zz    clear all the integer registers before entering 'dst'.  It's
+//zz    important that the stack pointer is set to exactly 'stack' and not
+//zz    (eg) stack - apparently_harmless_looking_small_offset.  Basically
+//zz    because the code at 'dst' might be wanting to scan the area above
+//zz    'stack' (viz, the auxv array), and putting spurious words on the
+//zz    stack confuses it.
+//zz */
+//zz // %r3 == stack
+//zz // %r4 == dst
+//zz asm(
+//zz ".global vgPlain_jump_and_switch_stacks\n"
+//zz "vgPlain_jump_and_switch_stacks:\n"
+//zz "   mtctr %r4\n\t"         // dst to %ctr
+//zz "   mr %r1,%r3\n\t"        // stack to %sp
+//zz "   li 0,0\n\t"            // zero all GP regs
+//zz "   li 3,0\n\t"
+//zz "   li 4,0\n\t"
+//zz "   li 5,0\n\t"
+//zz "   li 6,0\n\t"
+//zz "   li 7,0\n\t"
+//zz "   li 8,0\n\t"
+//zz "   li 9,0\n\t"
+//zz "   li 10,0\n\t"
+//zz "   li 11,0\n\t"
+//zz "   li 12,0\n\t"
+//zz "   li 13,0\n\t"           // CAB: This right? r13 = small data area ptr
+//zz "   li 14,0\n\t"
+//zz "   li 15,0\n\t"
+//zz "   li 16,0\n\t"
+//zz "   li 17,0\n\t"
+//zz "   li 18,0\n\t"
+//zz "   li 19,0\n\t"
+//zz "   li 20,0\n\t"
+//zz "   li 21,0\n\t"
+//zz "   li 22,0\n\t"
+//zz "   li 23,0\n\t"
+//zz "   li 24,0\n\t"
+//zz "   li 25,0\n\t"
+//zz "   li 26,0\n\t"
+//zz "   li 27,0\n\t"
+//zz "   li 28,0\n\t"
+//zz "   li 29,0\n\t"
+//zz "   li 30,0\n\t"
+//zz "   li 31,0\n\t"
+//zz "   mtxer 0\n\t"
+//zz "   mtcr 0\n\t"
+//zz "   mtlr %r0\n\t"
+//zz "   bctr\n\t"              // jump to dst
+//zz "   trap\n"                // should never get here
+//zz );
+//zz 
+//zz #else
+//zz #  error Unknown architecture
+//zz #endif
 
 /*------------------------------------------------------------*/
 /*--- Finding auxv on the stack                            ---*/
@@ -266,62 +269,65 @@ struct ume_auxv *VG_(find_auxv)(UWord* sp)
 static 
 struct elfinfo *readelf(int fd, const char *filename)
 {
-   struct elfinfo *e = malloc(sizeof(*e));
+   SysRes sres;
+   struct elfinfo *e = VG_(malloc)(sizeof(*e));
    int phsz;
 
-   assert(e);
+   vg_assert(e);
    e->fd = fd;
 
-   if (pread(fd, &e->e, sizeof(e->e), 0) != sizeof(e->e)) {
-      fprintf(stderr, "valgrind: %s: can't read ELF header: %s\n", 
-             filename, strerror(errno));
+   sres = VG_(pread)(fd, &e->e, sizeof(e->e), 0);
+   if (sres.isError || sres.val != sizeof(e->e)) {
+      VG_(printf)("valgrind: %s: can't read ELF header: %s\n", 
+                  filename, VG_(strerror)(sres.val));
       goto bad;
    }
 
-   if (memcmp(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
-      fprintf(stderr, "valgrind: %s: bad ELF magic number\n", filename);
+   if (VG_(memcmp)(&e->e.e_ident[0], ELFMAG, SELFMAG) != 0) {
+      VG_(printf)("valgrind: %s: bad ELF magic number\n", filename);
       goto bad;
    }
    if (e->e.e_ident[EI_CLASS] != VG_ELF_CLASS) {
-      fprintf(stderr, 
-              "valgrind: wrong ELF executable class "
-              "(eg. 32-bit instead of 64-bit)\n");
+      VG_(printf)("valgrind: wrong ELF executable class "
+                  "(eg. 32-bit instead of 64-bit)\n");
       goto bad;
    }
    if (e->e.e_ident[EI_DATA] != VG_ELF_DATA2XXX) {
-      fprintf(stderr, "valgrind: executable has wrong endian-ness\n");
+      VG_(printf)("valgrind: executable has wrong endian-ness\n");
       goto bad;
    }
    if (!(e->e.e_type == ET_EXEC || e->e.e_type == ET_DYN)) {
-      fprintf(stderr, "valgrind: this is not an executable\n");
+      VG_(printf)("valgrind: this is not an executable\n");
       goto bad;
    }
 
    if (e->e.e_machine != VG_ELF_MACHINE) {
-      fprintf(stderr, "valgrind: executable is not for "
-                      "this architecture\n");
+      VG_(printf)("valgrind: executable is not for "
+                  "this architecture\n");
       goto bad;
    }
 
    if (e->e.e_phentsize != sizeof(ESZ(Phdr))) {
-      fprintf(stderr, "valgrind: sizeof ELF Phdr wrong\n");
+      VG_(printf)("valgrind: sizeof ELF Phdr wrong\n");
       goto bad;
    }
 
    phsz = sizeof(ESZ(Phdr)) * e->e.e_phnum;
-   e->p = malloc(phsz);
-   assert(e->p);
-
-   if (pread(fd, e->p, phsz, e->e.e_phoff) != phsz) {
-      fprintf(stderr, "valgrind: can't read phdr: %s\n", strerror(errno));
-      free(e->p);
+   e->p = VG_(malloc)(phsz);
+   vg_assert(e->p);
+
+   sres = VG_(pread)(fd, e->p, phsz, e->e.e_phoff);
+   if (sres.isError || sres.val != phsz) {
+      VG_(printf)("valgrind: can't read phdr: %s\n", 
+                  VG_(strerror)(sres.val));
+      VG_(free)(e->p);
       goto bad;
    }
 
    return e;
 
   bad:
-   free(e);
+   VG_(free)(e);
    return NULL;
 }
 
@@ -329,8 +335,8 @@ struct elfinfo *readelf(int fd, const char *filename)
 static
 ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
 {
-   int i;
-   void* res;
+   Int    i;
+   SysRes res;
    ESZ(Addr) elfbrk = 0;
 
    for(i = 0; i < e->e.e_phnum; i++) {
@@ -360,9 +366,9 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
       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;
+      if (ph->p_flags & PF_X) prot |= VKI_PROT_EXEC;
+      if (ph->p_flags & PF_W) prot |= VKI_PROT_WRITE;
+      if (ph->p_flags & PF_R) prot |= VKI_PROT_READ;
 
       addr    = ph->p_vaddr+base;
       off     = ph->p_offset;
@@ -378,11 +384,16 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
       //
       // The condition handles the case of a zero-length segment.
       if (VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr) > 0) {
-         res = mmap((char *)VG_PGROUNDDN(addr),
-                    VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
-                    prot, MAP_FIXED|MAP_PRIVATE, e->fd, VG_PGROUNDDN(off));
-         check_mmap(res, (char*)VG_PGROUNDDN(addr),
-                    VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
+         if (0) VG_(debugLog)(0,"ume","mmap_file_fixed_client #1\n");
+         res = VG_(am_mmap_file_fixed_client)(
+                  VG_PGROUNDDN(addr),
+                  VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr),
+                  prot, /*VKI_MAP_FIXED|VKI_MAP_PRIVATE, */
+                  e->fd, VG_PGROUNDDN(off)
+               );
+         if (0) VG_(am_show_nsegments)(0,"after #1");
+         check_mmap(res, VG_PGROUNDDN(addr),
+                         VG_PGROUNDUP(bss)-VG_PGROUNDDN(addr));
       }
 
       // if memsz > filesz, fill the remainder with zeroed pages
@@ -391,17 +402,21 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
 
         bytes = VG_PGROUNDUP(brkaddr)-VG_PGROUNDUP(bss);
         if (bytes > 0) {
-           res = mmap((char *)VG_PGROUNDUP(bss), bytes,
-                      prot, MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
-            check_mmap(res, (char*)VG_PGROUNDUP(bss), bytes);
+            if (0) VG_(debugLog)(0,"ume","mmap_anon_fixed_client #2\n");
+           res = VG_(am_mmap_anon_fixed_client)(
+                     VG_PGROUNDUP(bss), bytes,
+                    prot
+                  );
+            if (0) VG_(am_show_nsegments)(0,"after #2");
+            check_mmap(res, VG_PGROUNDUP(bss), bytes);
          }
 
         bytes = bss & (VKI_PAGE_SIZE - 1);
 
          // The 'prot' condition allows for a read-only bss
-         if ((prot & PROT_WRITE) && (bytes > 0)) {
+         if ((prot & VKI_PROT_WRITE) && (bytes > 0)) {
            bytes = VKI_PAGE_SIZE - bytes;
-           memset((char *)bss, 0, bytes);
+           VG_(memset)((char *)bss, 0, bytes);
         }
       }
    }
@@ -410,17 +425,63 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
 }
 
 // Forward declaration.
+/* returns: 0 = success, non-0 is failure */
 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;
+   return (len > sizeof(*e)) && VG_(memcmp)(&e->e_ident[0], ELFMAG, SELFMAG) == 0;
 }
 
+
+/* load_ELF pulls an ELF executable into the address space, prepares
+   it for execution, and writes info about it into INFO.  In
+   particular it fills in .init_eip, which is the starting point.
+
+   Returns zero on success, non-zero (a VKI_E.. value) on failure.
+
+   The sequence of activities is roughly as follows:
+
+   - use readelf() to extract program header info from the exe file.
+
+   - scan the program header, collecting info (not sure what all those
+     info-> fields are, or whether they are used, but still) and in
+     particular looking out fo the PT_INTERP header, which describes
+     the interpreter.  If such a field is found, the space needed to
+     hold the interpreter is computed into interp_size.
+
+   - map the executable in, by calling mapelf().  This maps in all
+     loadable sections, and I _think_ also creates any .bss areas
+     required.  mapelf() returns the address just beyond the end of
+     the furthest-along mapping it creates.  The executable is mapped
+     starting at EBASE, which is usually read from it (eg, 0x8048000
+     etc) except if it's a PIE, in which case I'm not sure what
+     happens.
+
+     The returned address is recorded in info->brkbase as the start
+     point of the brk (data) segment, as it is traditional to place
+     the data segment just after the executable.  Neither load_ELF nor
+     mapelf creates the brk segment, though: that is for the caller of
+     load_ELF to attend to.
+
+   - If the initial phdr scan didn't find any mention of an
+     interpreter (interp == NULL), this must be a statically linked
+     executable, and we're pretty much done.
+
+   - Otherwise, we need to use mapelf() a second time to load the
+     interpreter.  The interpreter can go anywhere, but mapelf() wants
+     to be told a specific address to put it at.  So an advisory query
+     is passed to aspacem, asking where it would put an anonymous
+     client mapping of size INTERP_SIZE.  That address is then used
+     as the mapping address for the interpreter.
+
+   - The entry point in INFO is set to the interpreter's entry point,
+     and we're done.  */
 static int load_ELF(char *hdr, int len, int fd, const char *name,
-                    struct exeinfo *info)
+                    /*MOD*/struct exeinfo *info)
 {
+   SysRes sres;
    struct elfinfo *e;
    struct elfinfo *interp = NULL;
    ESZ(Addr) minaddr = ~0;     /* lowest mapped address */
@@ -439,7 +500,7 @@ static int load_ELF(char *hdr, int len, int fd, const char *name,
    e = readelf(fd, name);
 
    if (e == NULL)
-      return ENOEXEC;
+      return VKI_ENOEXEC;
 
    /* The kernel maps position-independent executables at TASK_SIZE*2/3;
       duplicate this behavior as close as we can. */
@@ -467,27 +528,28 @@ static int load_ELF(char *hdr, int len, int fd, const char *name,
         break;
                        
       case PT_INTERP: {
-        char *buf = malloc(ph->p_filesz+1);
+        char *buf = VG_(malloc)(ph->p_filesz+1);
         int j;
         int intfd;
         int baseaddr_set;
 
-         assert(buf);
-        pread(fd, buf, ph->p_filesz, ph->p_offset);
+         vg_assert(buf);
+        VG_(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);
+        sres = VG_(open)(buf, VKI_O_RDONLY, 0);
+         if (sres.isError) {
+           VG_(printf)("valgrind: m_ume.c: can't open interpreter\n");
+           VG_(exit)(1);
         }
+         intfd = sres.val;
 
         interp = readelf(intfd, buf);
         if (interp == NULL) {
-           fprintf(stderr, "Can't read interpreter\n");
+           VG_(printf)("valgrind: m_ume.c: can't read interpreter\n");
            return 1;
         }
-        free(buf);
+        VG_(free)(buf);
 
         baseaddr_set = 0;
         for(j = 0; j < interp->e.e_phnum; j++) {
@@ -525,46 +587,50 @@ static int load_ELF(char *hdr, int len, int fd, const char *name,
       if (minaddr >= maxaddr ||
          (minaddr + ebase < info->exe_base ||
           maxaddr + ebase > info->exe_end)) {
-        fprintf(stderr, "Executable range %p-%p is outside the\n"
-                         "acceptable range %p-%p\n",
-                (void *)minaddr + ebase, (void *)maxaddr + ebase,
-                (void *)info->exe_base,  (void *)info->exe_end);
-        return ENOMEM;
+        VG_(printf)("Executable range %p-%p is outside the\n"
+                     "acceptable range %p-%p\n",
+                     (void *)minaddr + ebase, (void *)maxaddr + ebase,
+                     (void *)info->exe_base,  (void *)info->exe_end);
+        return VKI_ENOMEM;
       }
    }
 
    info->brkbase = mapelf(e, ebase);   /* map the executable */
 
    if (info->brkbase == 0)
-      return ENOMEM;
+      return VKI_ENOMEM;
 
    if (interp != NULL) {
       /* reserve a chunk of address space for interpreter */
-      void* res;
-      char* base = (char *)info->exe_base;
-      char* baseoff;
-      int flags = MAP_PRIVATE|MAP_ANONYMOUS;
-
-      if (info->map_base != 0) {
-        base = (char *)VG_ROUNDUP(info->map_base, interp_align);
-        flags |= MAP_FIXED;
+      Addr       advised;
+      Bool       ok;
+
+      /* Don't actually reserve the space.  Just get an advisory
+         indicating where it would be allocated, and pass that to
+         mapelf(), which in turn asks aspacem to do some fixed maps at
+         the specified address.  This is a bit of hack, but it should
+         work because there should be no intervening transactions with
+         aspacem which could cause those fixed maps to fail. */
+      advised = VG_(am_get_advisory_client_simple)( 
+                   (Addr)interp_addr, interp_size, &ok 
+                );
+      if (!ok) {
+         /* bomb out */
+         SysRes res = VG_(mk_SysRes_Error)(VKI_EINVAL);
+         if (0) VG_(printf)("reserve for interp: failed\n");
+         check_mmap(res, (Addr)interp_addr, interp_size);
+         /*NOTREACHED*/
       }
 
-      res = mmap(base, interp_size, PROT_NONE, flags, -1, 0);
-      check_mmap(res, base, interp_size);
-      base = res;
-
-      baseoff = base - interp_addr;
-
-      mapelf(interp, (ESZ(Addr))baseoff);
+      (void)mapelf(interp, (ESZ(Addr))advised - interp_addr);
 
-      close(interp->fd);
+      VG_(close)(interp->fd);
 
-      entry = baseoff + interp->e.e_entry;
-      info->interp_base = (ESZ(Addr))base;
+      entry = (void *)(advised - interp_addr + interp->e.e_entry);
+      info->interp_base = (ESZ(Addr))advised;
 
-      free(interp->p);
-      free(interp);
+      VG_(free)(interp->p);
+      VG_(free)(interp);
    } else
       entry = (void *)(ebase + e->e.e_entry);
 
@@ -573,8 +639,8 @@ static int load_ELF(char *hdr, int len, int fd, const char *name,
 
    info->init_eip = (Addr)entry;
 
-   free(e->p);
-   free(e);
+   VG_(free)(e->p);
+   VG_(free)(e);
 
    return 0;
 }
@@ -582,9 +648,10 @@ static int load_ELF(char *hdr, int len, int fd, const char *name,
 
 static int match_script(const char *hdr, Int len)
 {
-   return (len > 2) && memcmp(hdr, "#!", 2) == 0;
+   return (len > 2) && VG_(memcmp)(hdr, "#!", 2) == 0;
 }
 
+/* returns: 0 = success, non-0 is failure */
 static int load_script(char *hdr, int len, int fd, const char *name,
                        struct exeinfo *info)
 {
@@ -599,7 +666,7 @@ static int load_script(char *hdr, int len, int fd, const char *name,
       interp++;
 
    if (*interp != '/')
-      return ENOEXEC;          /* absolute path only for interpreter */
+      return VKI_ENOEXEC; /* absolute path only for interpreter */
 
    /* skip over interpreter name */
    for(cp = interp; cp < end && *cp != ' ' && *cp != '\t' && *cp != '\n'; cp++)
@@ -621,19 +688,19 @@ static int load_script(char *hdr, int len, int fd, const char *name,
       *cp = '\0';
    }
    
-   info->interp_name = strdup(interp);
-   assert(NULL != info->interp_name);
+   info->interp_name = VG_(strdup)(interp);
+   vg_assert(NULL != info->interp_name);
    if (arg != NULL && *arg != '\0') {
-      info->interp_args = strdup(arg);
-      assert(NULL != info->interp_args);
+      info->interp_args = VG_(strdup)(arg);
+      vg_assert(NULL != info->interp_args);
    }
 
    if (info->argv && info->argv[0] != NULL)
       info->argv[0] = (char *)name;
 
    if (0)
-      printf("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
-            info->interp_name, info->interp_args);
+      VG_(printf)("#! script: interp_name=\"%s\" interp_args=\"%s\"\n",
+                  info->interp_name, info->interp_args);
 
    return do_exec_inner(interp, info);
 }
@@ -649,50 +716,54 @@ static int load_script(char *hdr, int len, int fd, const char *name,
    (otherwise the executable may misbehave if it doesn't have the
    permissions it thinks it does).
 */
+/* returns: 0 = success, non-0 is failure */
 static int check_perms(int fd)
 {
-   struct stat st;
+   struct vki_stat st;
 
-   if (fstat(fd, &st) == -1) 
-      return errno;
+   if (VG_(fstat)(fd, &st) == -1) 
+      return VKI_EACCES;
 
-   if (st.st_mode & (S_ISUID | S_ISGID)) {
-      //fprintf(stderr, "Can't execute suid/sgid executable %s\n", exe);
-      return EACCES;
+   if (st.st_mode & (VKI_S_ISUID | VKI_S_ISGID)) {
+      //VG_(printf)("Can't execute suid/sgid executable %s\n", exe);
+      return VKI_EACCES;
    }
 
-   if (geteuid() == st.st_uid) {
-      if (!(st.st_mode & S_IXUSR))
-        return EACCES;
+   if (VG_(geteuid)() == st.st_uid) {
+      if (!(st.st_mode & VKI_S_IXUSR))
+        return VKI_EACCES;
    } else {
       int grpmatch = 0;
 
-      if (getegid() == st.st_gid)
+      if (VG_(getegid)() == st.st_gid)
         grpmatch = 1;
       else {
-        gid_t groups[32];
-        int ngrp = getgroups(32, groups);
-        int i;
-
-        for(i = 0; i < ngrp; i++)
+        UInt groups[32];
+        Int ngrp = VG_(getgroups)(32, groups);
+        Int i;
+         /* ngrp will be -1 if VG_(getgroups) failed. */
+         for (i = 0; i < ngrp; i++) {
            if (groups[i] == st.st_gid) {
               grpmatch = 1;
               break;
            }
+         }
       }
 
       if (grpmatch) {
-        if (!(st.st_mode & S_IXGRP))
-           return EACCES;
-      } else if (!(st.st_mode & S_IXOTH))
-        return EACCES;
+        if (!(st.st_mode & VKI_S_IXGRP))
+           return VKI_EACCES;
+      } else if (!(st.st_mode & VKI_S_IXOTH))
+        return VKI_EACCES;
    }
 
    return 0;
 }
 
+/* returns: 0 = success, non-0 is failure */
 static int do_exec_inner(const char *exe, struct exeinfo *info)
 {
+   SysRes sres;
    int fd;
    int err;
    char buf[VKI_PAGE_SIZE];
@@ -708,29 +779,31 @@ static int do_exec_inner(const char *exe, struct exeinfo *info)
       { match_script, load_script },
    };
 
-   fd = open(exe, O_RDONLY);
-   if (fd == -1) {
+   sres = VG_(open)(exe, VKI_O_RDONLY, 0);
+   if (sres.isError) {
       if (0)
-        fprintf(stderr, "Can't open executable %s: %s\n",
-                exe, strerror(errno));
-      return errno;
+        VG_(printf)("Can't open executable %s: %s\n",
+                     exe, VG_(strerror)(sres.val));
+      return sres.val;
    }
+   fd = sres.val;
 
    err = check_perms(fd);
    if (err != 0) {
-      close(fd);
+      VG_(close)(fd);
       return err;
    }
 
-   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;
+   sres = VG_(pread)(fd, buf, sizeof(buf), 0);
+   if (sres.isError || sres.val != sizeof(buf)) {
+      VG_(printf)("Can't read executable header: %s\n",
+                  VG_(strerror)(sres.val));
+      VG_(close)(fd);
+      return sres.val;
    }
+   bufsz = sres.val;
 
-   ret = ENOEXEC;
+   ret = VKI_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);
@@ -738,13 +811,14 @@ static int do_exec_inner(const char *exe, struct exeinfo *info)
       }
    }
 
-   close(fd);
+   VG_(close)(fd);
 
    return ret;
 }
 
 // See ume.h for an indication of which entries of 'info' are inputs, which
 // are outputs, and which are both.
+/* returns: 0 = success, non-0 is failure */
 int VG_(do_exec)(const char *exe, struct exeinfo *info)
 {
    info->interp_name = NULL;
index e3bd9a5cade41e9aee959bce9a6d3de7888cb600..b4fb4d859f55016c28c4b4decc2e72bd0e078da4 100644 (file)
 // memory management.  Hence this module is almost completely
 // standalone; the only module it uses is m_debuglog.  DO NOT CHANGE
 // THIS.
-// [XXX: actually, this is far from true... especially that to #include
-// this header, you have to #include pub_core_debuginfo in order to 
-// see the SegInfo type, which is very bad...]
 //--------------------------------------------------------------------
 
 #include "pub_tool_aspacemgr.h"
 
-// Address space globals
-extern Addr VG_(client_base);   // client address space limits
-extern Addr VG_(client_end);
-extern Addr VG_(client_mapbase); // base of mappings
-extern Addr VG_(clstk_base);    // client stack range
-extern Addr VG_(clstk_end);
-extern UWord VG_(clstk_id);      // client stack id
-
-extern Addr VG_(brk_base);      // start of brk
-extern Addr VG_(brk_limit);     // current brk
-extern Addr VG_(shadow_base);   // tool's shadow memory
-extern Addr VG_(shadow_end);
-extern Addr VG_(valgrind_base);         // valgrind's address range
-extern Addr VG_(valgrind_last);  // Nb: last byte, rather than one past the end
-
-// Direct access to these system calls.
-extern SysRes VG_(mmap_native)     ( void* start, SizeT length, UInt prot,
-                                     UInt flags, UInt fd, OffT offset );
-extern SysRes VG_(munmap_native)   ( void* start, SizeT length );
-extern SysRes VG_(mprotect_native) ( void *start, SizeT length, UInt prot );
-
-/* A Segment is mapped piece of client memory.  This covers all kinds
-   of mapped memory (exe, brk, mmap, .so, shm, stack, etc)
-
-   We encode relevant info about each segment with these constants.
-*/
-#define SF_SHARED   (1 <<  0) // shared
-#define SF_SHM      (1 <<  1) // SYSV SHM (also SF_SHARED)
-#define SF_MMAP     (1 <<  2) // mmap memory
-#define SF_FILE     (1 <<  3) // mapping is backed by a file
-#define SF_STACK    (1 <<  4) // is a stack
-#define SF_GROWDOWN (1 <<  5) // segment grows down
-#define SF_NOSYMS   (1 <<  6) // don't load syms, even if present
-#define SF_CORE     (1 <<  7) // allocated by core on behalf of the client
-#define SF_VALGRIND (1 <<  8) // a valgrind-internal mapping - not in client
-#define SF_CODE     (1 <<  9) // segment contains cached code
-#define SF_DEVICE   (1 << 10) // device mapping;  avoid careless touching
-
-typedef struct _Segment Segment;
-
-struct _Segment {
-   UInt         prot;         // VKI_PROT_*
-   UInt         flags;        // SF_*
-
-   Addr         addr;         // mapped addr (page aligned)
-   SizeT        len;          // size of mapping (page aligned)
-
-   // These are valid if (flags & SF_FILE)
-   OffT        offset;        // file offset
-   const Char* filename;      // filename (NULL if unknown)
-   Int         fnIdx;         // filename table index (-1 if unknown)
-   UInt        dev;           // device
-   UInt        ino;           // inode
-
-   SegInfo*    seginfo;       // symbol table, etc
-};
-
-/* segment mapped from a file descriptor */
-extern void VG_(map_fd_segment)  (Addr addr, SizeT len, UInt prot, UInt flags, 
-                                 Int fd, ULong off, const Char *filename);
-
-/* segment mapped from a file */
-extern void VG_(map_file_segment)(Addr addr, SizeT len, UInt prot, UInt flags, 
-                                 UInt dev, UInt ino, ULong off, const Char *filename);
-
-/* simple segment */
-extern void VG_(map_segment)     (Addr addr, SizeT len, UInt prot, UInt flags);
-
-extern void VG_(unmap_range)   (Addr addr, SizeT len);
-extern void VG_(mprotect_range)(Addr addr, SizeT len, UInt prot);
-extern Addr VG_(find_map_space)(Addr base, SizeT len, Bool for_client);
-
-/* Find the segment containing a, or NULL if none. */
-extern Segment *VG_(find_segment)(Addr a);
-
-/* a is an unmapped address (is checked).  Find the next segment 
-   along in the address space, or NULL if none. */
-extern Segment *VG_(find_segment_above_unmapped)(Addr a);
-
-/* a is a mapped address (in a segment, is checked).  Find the
-   next segment along. */
-extern Segment *VG_(find_segment_above_mapped)(Addr a);
-
-extern Bool VG_(seg_contains)(const Segment *s, Addr ptr, SizeT size);
-extern Bool VG_(seg_overlaps)(const Segment *s, Addr ptr, SizeT size);
-
-extern Segment *VG_(split_segment)(Addr a);
-
-extern void VG_(show_segments)(HChar* who);
-
-extern void VG_(pad_address_space)  (Addr start);
-extern void VG_(unpad_address_space)(Addr start);
-
-///* Search /proc/self/maps for changes which aren't reflected in the
-//   segment list */
-//extern void VG_(sync_segments)(UInt flags);
-
-/* Return string for prot */
-extern const HChar *VG_(prot_str)(UInt prot);
-
 /* Parses /proc/self/maps, calling `record_mapping' for each entry. */
 extern 
 void VG_(parse_procselfmaps) (
    void (*record_mapping)( Addr addr, SizeT len, UInt prot,
                           UInt dev, UInt ino, ULong foff,
-                           const UChar *filename ) );
+                           const UChar *filename ),
+   void (*record_gap)( Addr addr, SizeT len ) );
+
+//--------------------------------------------------------------
+// Definition of address-space segments
+
+/* types SegKind, ShrinkMode and NSegment are described in
+   the tool-visible header file, not here. */
+
+
+//--------------------------------------------------------------
+// Initialisation
+
+/* Initialise the address space manager, setting up the initial
+   segment list, and reading /proc/self/maps into it.  This must
+   be called before any other function.
+
+   Takes a pointer to the SP at the time V gained control.  This is
+   taken to be the highest usable address (more or less).  Based on
+   that (and general consultation of tea leaves, etc) return a
+   suggested end address for the client's stack. */
+extern Addr VG_(am_startup) ( Addr sp_at_startup );
+
+
+//--------------------------------------------------------------
+// Querying current status
+
+/* Finds the segment containing 'a'.  Only returns file/anon/resvn
+   segments. */
+// Is in tool-visible header file.
+// extern NSegment* VG_(am_find_nsegment) ( Addr a );
+
+/* Find the next segment along from 'here', if it is a file/anon/resvn
+   segment. */
+extern NSegment* VG_(am_next_nsegment) ( NSegment* here, Bool fwds );
+
+/* Is the area [start .. start+len-1] validly accessible by the 
+   client with at least the permissions 'prot' ?  To find out
+   simply if said area merely belongs to the client, pass 
+   VKI_PROT_NONE as 'prot'.  Will return False if any part of the
+   area does not belong to the client or does not have at least
+   the stated permissions. */
+// Is in tool-visible header file.
+// extern Bool VG_(am_is_valid_for_client)
+//   ( Addr start, SizeT len, UInt prot );
+
+/* Variant of VG_(am_is_valid_for_client) which allows free areas to
+   be consider part of the client's addressable space.  It also
+   considers reservations to be allowable, since from the client's
+   point of view they don't exist. */
+extern Bool VG_(am_is_valid_for_client_or_free_or_resvn)
+   ( Addr start, SizeT len, UInt prot );
+
+/* Trivial fn: return the total amount of space in anonymous mappings,
+   both for V and the client.  Is used for printing stats in
+   out-of-memory messages. */
+extern ULong VG_(am_get_anonsize_total)( void );
+
+/* Show the segment array on the debug log, at given loglevel. */
+extern void VG_(am_show_nsegments) ( Int logLevel, HChar* who );
+
+/* Get the filename corresponding to this segment, if known and if it
+   has one.  The returned name's storage cannot be assumed to be
+   persistent, so the caller should immediately copy the name
+   elsewhere. */
+extern HChar* VG_(am_get_filename)( NSegment* );
+
+/* VG_(am_get_segment_starts) is also part of this section, but its
+   prototype is tool-visible, hence not in this header file. */
+
+/* Sanity check: check that Valgrind and the kernel agree on the
+   address space layout.  Prints offending segments and call point if
+   a discrepancy is detected, but does not abort the system.  Returned
+   Bool is False if a discrepancy was found. */
+
+extern Bool VG_(am_do_sync_check) ( const HChar* fn, 
+                                    const HChar* file, Int line );
+
+
+//--------------------------------------------------------------
+// Functions pertaining to the central query-notify mechanism
+// used to handle mmap/munmap/mprotect resulting from client
+// syscalls.
+
+/* Describes a request for VG_(am_get_advisory). */
+typedef
+   struct {
+      enum { MFixed, MHint, MAny } rkind;
+      Addr start;
+      Addr len;
+   }
+   MapRequest;
+
+/* Query aspacem to ask where a mapping should go.  On success, the
+   advised placement is returned, and *ok is set to True.  On failure,
+   zero is returned and *ok is set to False.  Note that *ok must be
+   consulted by the caller to establish success or failure; that
+   cannot be established reliably from the returned value.  If *ok is
+   set to False, it means aspacem has vetoed the mapping, and so the
+   caller should not proceed with it. */
+extern Addr VG_(am_get_advisory)
+   ( MapRequest* req, Bool forClient, /*OUT*/Bool* ok );
+
+/* Convenience wrapper for VG_(am_get_advisory) for client floating or
+   fixed requests.  If start is zero, a floating request is issued; if
+   nonzero, a fixed request at that address is issued.  Same comments
+   about return values apply. */
+extern Addr VG_(am_get_advisory_client_simple) 
+   ( Addr start, SizeT len, /*OUT*/Bool* ok );
+
+/* Notifies aspacem that the client completed an mmap successfully.
+   The segment array is updated accordingly.  If the returned Bool is
+   True, the caller should immediately discard translations from the
+   specified address range. */
+extern Bool VG_(am_notify_client_mmap)
+   ( Addr a, SizeT len, UInt prot, UInt flags, Int fd, SizeT offset );
+
+/* Notifies aspacem that an mprotect was completed successfully.  The
+   segment array is updated accordingly.  Note, as with
+   VG_(am_notify_munmap), it is not the job of this function to reject
+   stupid mprotects, for example the client doing mprotect of
+   non-client areas.  Such requests should be intercepted earlier, by
+   the syscall wrapper for mprotect.  This function merely records
+   whatever it is told.  If the returned Bool is True, the caller
+   should immediately discard translations from the specified address
+   range. */
+extern Bool VG_(am_notify_mprotect)( Addr start, SizeT len, UInt prot );
+
+/* Notifies aspacem that an munmap completed successfully.  The
+   segment array is updated accordingly.  As with
+   VG_(am_notify_munmap), we merely record the given info, and don't
+   check it for sensibleness.  If the returned Bool is True, the
+   caller should immediately discard translations from the specified
+   address range. */
+extern Bool VG_(am_notify_munmap)( Addr start, SizeT len );
+
+
+/* Hand a raw mmap to the kernel, without aspacem updating the segment
+   array.  THIS FUNCTION IS DANGEROUS -- it will cause aspacem's view
+   of the address space to diverge from that of the kernel.  DO NOT
+   USE IT UNLESS YOU UNDERSTAND the request-notify model used by
+   aspacem.  In short, DO NOT USE THIS FUNCTION. */
+extern SysRes VG_(am_do_mmap_NO_NOTIFY)
+   ( Addr start, SizeT length, UInt prot, UInt flags, UInt fd, OffT offset);
+
+
+//--------------------------------------------------------------
+// Dealing with mappings which do not arise directly from the
+// simulation of the client.  These are typically used for
+// loading the client and building its stack/data segment, before
+// execution begins.  Also for V's own administrative use.
+
+/* --- --- --- map, unmap, protect  --- --- --- */
+
+/* Map a file at a fixed address for the client, and update the
+   segment array accordingly. */
+extern SysRes VG_(am_mmap_file_fixed_client)
+   ( Addr start, SizeT length, UInt prot, Int fd, SizeT offset );
+
+/* Map anonymously at a fixed address for the client, and update
+   the segment array accordingly. */
+extern SysRes VG_(am_mmap_anon_fixed_client)
+   ( Addr start, SizeT length, UInt prot );
+
+/* Map anonymously at an unconstrained address for the client, and
+   update the segment array accordingly.  */
+extern SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot );
+
+/* Map anonymously at an unconstrained address for V, and update the
+   segment array accordingly.  This is fundamentally how V allocates
+   itself more address space when needed. */
+extern SysRes VG_(am_mmap_anon_float_valgrind)( SizeT cszB );
+
+/* Map a file at an unconstrained address for V, and update the
+   segment array accordingly.  This is used by V for transiently
+   mapping in object files to read their debug info.  */
+extern SysRes VG_(am_mmap_file_float_valgrind)
+   ( SizeT length, UInt prot, Int fd, SizeT offset );
+
+/* Unmap the given address range and update the segment array
+   accordingly.  This fails if the range isn't valid for the client.
+   If *need_discard is True after a successful return, the caller
+   should immediately discard translations from the specified address
+   range. */
+extern SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
+                                     Addr start, SizeT length );
+
+/* Unmap the given address range and update the segment array
+   accordingly.  This fails if the range isn't valid for valgrind. */
+extern SysRes VG_(am_munmap_valgrind)( Addr start, SizeT length );
+
+/* Let (start,len) denote an area within a single Valgrind-owned
+  segment (anon or file).  Change the ownership of [start, start+len)
+  to the client instead.  Fails if (start,len) does not denote a
+  suitable segment. */
+extern Bool VG_(am_change_ownership_v_to_c)( Addr start, SizeT len );
+
+/* --- --- --- reservations --- --- --- */
+
+/* Create a reservation from START .. START+LENGTH-1, with the given
+   ShrinkMode.  When checking whether the reservation can be created,
+   also ensure that at least abs(EXTRA) extra free bytes will remain
+   above (> 0) or below (< 0) the reservation.
+
+   The reservation will only be created if it, plus the extra-zone,
+   falls entirely within a single free segment.  The returned Bool
+   indicates whether the creation succeeded. */
+extern Bool VG_(am_create_reservation) 
+   ( Addr start, SizeT length, ShrinkMode smode, SSizeT extra );
+
+/* Let SEG be an anonymous client mapping.  This fn extends the
+   mapping by DELTA bytes, taking the space from a reservation section
+   which must be adjacent.  If DELTA is positive, the segment is
+   extended forwards in the address space, and the reservation must be
+   the next one along.  If DELTA is negative, the segment is extended
+   backwards in the address space and the reservation must be the
+   previous one.  DELTA must be page aligned and must not exceed the
+   size of the reservation segment. */
+extern Bool VG_(am_extend_into_adjacent_reservation_client) 
+   ( NSegment* seg, SSizeT delta );
+
+/* --- --- --- resizing/move a mapping --- --- --- */
+
+/* Let SEG be a client mapping (anonymous or file).  This fn extends
+   the mapping forwards only by DELTA bytes, and trashes whatever was
+   in the new area.  Fails if SEG is not a single client mapping or if
+   the new area is not accessible to the client.  Fails if DELTA is
+   not page aligned.  *seg is invalid after a successful return.  If
+   *need_discard is True after a successful return, the caller should
+   immediately discard translations from the new area. */
+extern Bool VG_(am_extend_map_client)( /*OUT*/Bool* need_discard,
+                                       NSegment* seg, SizeT delta );
+
+/* Remap the old address range to the new address range.  Fails if any
+   parameter is not page aligned, if the either size is zero, if any
+   wraparound is implied, if the old address range does not fall
+   entirely within a single segment, if the new address range overlaps
+   with the old one, or if the old address range is not a valid client
+   mapping.  If *need_discard is True after a successful return, the
+   caller should immediately discard translations from both specified
+   address ranges.  */
+extern Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
+                                               Addr old_addr, SizeT old_len,
+                                               Addr new_addr, SizeT new_len );
+
+//--------------------------------------------------------------
+// Valgrind (non-client) thread stacks.  V itself runs on such
+// stacks.  The address space manager provides and suitably
+// protects such stacks.
+
+#define VG_STACK_GUARD_SZB  8192   // 2 pages
+#define VG_STACK_ACTIVE_SZB 65536  // 16 pages
+
+typedef
+   struct {
+      HChar bytes[VG_STACK_GUARD_SZB 
+                  + VG_STACK_ACTIVE_SZB 
+                  + VG_STACK_GUARD_SZB];
+   }
+   VgStack;
+
+
+/* Allocate and initialise a VgStack (anonymous client space).
+   Protect the stack active area and the guard areas appropriately.
+   Returns NULL on failure, else the address of the bottom of the
+   stack.  On success, also sets *initial_sp to what the stack pointer
+   should be set to. */
+
+extern VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp );
+
+/* Figure out how many bytes of the stack's active area have not
+   been used.  Used for estimating if we are close to overflowing it. */
+
+extern Int VG_(am_get_VgStack_unused_szB)( VgStack* stack ); 
 
-// Pointercheck
-extern Bool VG_(setup_pointercheck) ( Addr client_base, Addr client_end );
 
 #endif   // __PUB_CORE_ASPACEMGR_H
 
index 8d56e4adf317af07b6aa0a000d0d11d05c4ab6bf..c421b84ff06413f33928b868c8fe1177f90f4bc3 100644 (file)
@@ -37,6 +37,7 @@
 // everywhere.
 //--------------------------------------------------------------------
 
+#include "pub_core_basics_asm.h"
 #include "pub_tool_basics.h"
 
 /* ---------------------------------------------------------------------
@@ -61,9 +62,6 @@
 // For jmp_buf
 #include <setjmp.h>
 
-// Autoconf-generated settings
-#include "config.h"
-
 #endif   // __PUB_CORE_BASICS_H
 
 /*--------------------------------------------------------------------*/
similarity index 68%
rename from coregrind/pub_core_libcmman.h
rename to coregrind/pub_core_basics_asm.h
index ba2bed71ae5a3ea1bb28b9a39c9b84eb5dd4f451..fc625071d225518c09ef0461c3b56eea45efbd08 100644 (file)
@@ -1,13 +1,15 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Memory management libc stuff.            pub_core_libcmman.h ---*/
+/*--- Header imported directly by every core asm file, and         ---*/
+/*--- (via pub_core_basics.h) by every core C file.                ---*/
+/*---                                        pub_core_basics_asm.h ---*/
 /*--------------------------------------------------------------------*/
 
 /*
    This file is part of Valgrind, a dynamic binary instrumentation
    framework.
 
-   Copyright (C) 2000-2005 Julian Seward
+   Copyright (C) 2000-2005 Julian Seward 
       jseward@acm.org
 
    This program is free software; you can redistribute it and/or
    The GNU General Public License is contained in the file COPYING.
 */
 
-#ifndef __PUB_CORE_LIBCMMAN_H
-#define __PUB_CORE_LIBCMMAN_H
+#ifndef __PUB_CORE_BASICS_ASM_H
+#define __PUB_CORE_BASICS_ASM_H
 
 //--------------------------------------------------------------------
-// PURPOSE: This module contains libc code related to low-level
-// memory management, ie. mmap and friends.
+// PURPOSE: This header should be imported by every single asm and 
+// (indirectly) by every C file in the core.  It contains really basic
+// things needed everywhere.
 //--------------------------------------------------------------------
 
-#include "pub_tool_libcmman.h"
+#include "pub_tool_basics_asm.h"
 
-extern void* VG_(mmap)   ( void* start, SizeT length, UInt prot, UInt flags,
-                           UInt sf_flags, UInt fd, OffT offset );
-extern Int VG_(munmap)   ( void* start, SizeT length );
-extern Int VG_(mprotect) ( void *start, SizeT length, UInt prot );
+// Autoconf-generated settings
+#include "config.h"
 
-extern Addr VG_(get_memory_from_mmap_for_client)(SizeT len);
-
-#endif   // __PUB_CORE_LIBCMMAN_H
+#endif /* __PUB_CORE_BASICS_ASM_H */
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
+
diff --git a/coregrind/pub_core_clientstate.h b/coregrind/pub_core_clientstate.h
new file mode 100644 (file)
index 0000000..ec7a347
--- /dev/null
@@ -0,0 +1,81 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Misc client state info                pub_core_clientstate.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 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.
+*/
+
+#ifndef __PUB_CORE_CLIENTSTATE_H
+#define __PUB_CORE_CLIENTSTATE_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module holds various bits of client state which don't
+// live comfortably anywhere else.  Note that the ThreadStates for the
+// client don't live here; they instead live in m_threadstate.h.
+//--------------------------------------------------------------------
+
+#include "pub_tool_clientstate.h"
+
+// Address space globals
+
+extern Addr  VG_(client_base);  // client address space limits
+extern Addr  VG_(client_end);
+
+extern Addr  VG_(clstk_base);   // client stack range
+extern Addr  VG_(clstk_end);
+extern UWord VG_(clstk_id);      // client stack id
+
+extern Addr  VG_(brk_base);     // start of brk
+extern Addr  VG_(brk_limit);    // current brk
+
+/* A fd which refers to the client executable. */
+extern Int VG_(cl_exec_fd);
+
+/* A fd which refers to the fake /proc/<pid>/cmdline in /tmp.  The
+   idea is: make up the /proc/<pid>/cmdline file the client would
+   expect to see if it was running natively.  Copy into a file in
+   /tmp.  When the client then does an open of /proc/<pid>/cmdline or
+   /proc/self/cmdline, instead give it a file handle to the file in
+   /tmp.  The problem of deleting said file when Valgrind exits is
+   neatly sidestepped by unlinking it as soon as it has been created,
+   but holding on to the file handle.  That causes the kernel to keep
+   the file contents alive exactly until the process exits. */
+extern Int VG_(cl_cmdline_fd);
+
+// Client's original rlimit data and rlimit stack
+extern struct vki_rlimit VG_(client_rlimit_data);
+extern struct vki_rlimit VG_(client_rlimit_stack);
+
+// Name of the launcher, as extracted from VALGRIND_LAUNCHER at
+// startup.
+extern HChar* VG_(name_of_launcher);
+
+
+#endif   // __PUB_CORE_CLIENTSTATE_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
similarity index 70%
rename from include/pub_tool_libcmman.h
rename to coregrind/pub_core_commandline.h
index 75d6c672bc1d55a1a177184c671ac478b4e80276..a36469b6c82449aae9d071958102a4994dfb0829 100644 (file)
@@ -1,13 +1,13 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Memory management libc stuff.            pub_tool_libcmman.h ---*/
+/*--- Command line handling.                pub_core_commandline.h ---*/
 /*--------------------------------------------------------------------*/
 
 /*
    This file is part of Valgrind, a dynamic binary instrumentation
    framework.
 
-   Copyright (C) 2000-2005 Julian Seward
+   Copyright (C) 2000-2005 Julian Seward 
       jseward@acm.org
 
    This program is free software; you can redistribute it and/or
    The GNU General Public License is contained in the file COPYING.
 */
 
-#ifndef __PUB_TOOL_LIBCMMAN_H
-#define __PUB_TOOL_LIBCMMAN_H
+#ifndef __PUB_CORE_COMMANDLINE_H
+#define __PUB_CORE_COMMANDLINE_H
 
-/* Get memory by anonymous mmap. */
-extern void* VG_(get_memory_from_mmap) ( SizeT nBytes, Char* who );
 
-#endif   // __PUB_TOOL_LIBCMMAN_H
+/* Split up the args presented by the launcher to m_main.main(), and
+   park them in VG_(args_for_client), VG_(args_for_valgrind) and
+   VG_(args_for_valgrind_extras).  The latter are acquired from
+   $VALGRIND_OPTS, ./.valgrindrc and ~/.valgrindrc. */
+
+extern void VG_(split_up_argv)( Int argc, HChar** argv );
+
+
+#endif   // __PUB_CORE_COMMANDLINE_H
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
index f5de7f1ed3ee7f09575e9a50be6f81365897dddf..7034566c0c70c458b1cfc15d2001ed7b11418b7a 100644 (file)
 
 #include "pub_tool_debuginfo.h"
 
+extern void VG_(di_notify_mmap)( Addr a );
+extern void VG_(di_notify_munmap)( Addr a, SizeT len );
+extern void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot );
+
 extern Bool VG_(is_object_file)   ( const void *hdr );
 extern SegInfo *VG_(read_seg_symbols) ( Addr addr, SizeT len,
                                         OffT offset, const Char* filename);
index 1480da7923502a706cb70ad383842bf66113f31c..af621b12152f1cf5598fce3358349f6e51c8f0a9 100644 (file)
@@ -49,6 +49,9 @@ extern Int VG_(fcntl)   ( Int fd, Int cmd, Int arg );
 /* Convert an fd into a filename */
 extern Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf );
 
+/* Return the size of a file */
+extern Int VG_(fsize) ( Int fd );
+
 /* Default destination port to be used in logging over a network, if
    none specified. */
 #define VG_CLO_DEFAULT_LOGPORT 1500
@@ -60,6 +63,16 @@ extern Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen );
 extern Int VG_(getsockopt)  ( Int sd, Int level, Int optname, void *optval,
                               Int *optlen );
 
+extern Int VG_(access) ( HChar* path, Bool irusr, Bool iwusr, Bool ixusr );
+
+extern SysRes VG_(pread) ( Int fd, void* buf, Int count, Int offset );
+
+/* Create and open (-rw------) a tmp file name incorporating said arg.
+   Returns -1 on failure, else the fd of the file.  If fullname is
+   non-NULL, the file's name is written into it.  The number of bytes
+   written is guaranteed not to exceed 64+strlen(part_of_name). */
+extern Int VG_(mkstemp) ( HChar* part_of_name, /*OUT*/HChar* fullname );
+
 #endif   // __PUB_CORE_LIBCFILE_H
 
 /*--------------------------------------------------------------------*/
index 451539914f943932a5fe9a5f8e5ef2983e523c38..4742719c9f11076f362e657230c2e2abc2bdf43b 100644 (file)
 // It's a bit of a mixed bag.
 //--------------------------------------------------------------------
 
+#include "config.h"           // Crucial: ensure we get ENABLE_INNER
 #include "pub_tool_libcproc.h"
 
 /* The directory we look for all our auxillary files in.  Useful for
-   running Valgrind out of a build tree without having to do "make install". */
-#define VALGRINDLIB    "VALGRINDLIB"
+   running Valgrind out of a build tree without having to do "make
+   install".  Inner valgrinds require a different lib variable, else
+   they end up picking up .so's etc intended for the outer
+   valgrind. */
+#ifdef ENABLE_INNER
+#  define VALGRIND_LIB     "VALGRIND_LIB_INNER"
+#else
+#  define VALGRIND_LIB     "VALGRIND_LIB"
+#endif
 
 /* Additional command-line arguments; they are overridden by actual
    command-line option.  Each argument is separated by spaces.  There
    is no quoting mechanism.  */
-#define VALGRINDOPTS   "VALGRIND_OPTS"
+#define VALGRIND_OPTS    "VALGRIND_OPTS"
 
-/* If this variable is present in the environment, then valgrind will
-   not parse the command line for options at all; all options come
-   from this variable.  Arguments are terminated by ^A (\001).  There
-   is no quoting mechanism.
+/* The full name of Valgrind's stage1 (launcher) executable.  This is
+   set by stage1 and read by stage2, and is used for recursive
+   invocations of Valgrind on child processes. 
+   
+   For self-hosting, the inner and outer Valgrinds must use different
+   names to avoid collisions.  */
+#ifdef ENABLE_INNER
+#  define VALGRIND_LAUNCHER  "VALGRIND_LAUNCHER_INNER"
+#else
+#  define VALGRIND_LAUNCHER  "VALGRIND_LAUNCHER"
+#endif
 
-   This variable is not expected to be set by anything other than
-   Valgrind itself, as part of its handling of execve with
-   --trace-children=yes.  This variable should not be present in the
-   client environment.  */
-#define VALGRINDCLO    "_VALGRIND_CLO"
-
-// Client's executable file descriptor.
-extern Int VG_(clexecfd);
-
-// Client's original rlimit data and rlimit stack
-extern struct vki_rlimit VG_(client_rlimit_data);
-extern struct vki_rlimit VG_(client_rlimit_stack);
 
 // Environment manipulations
 extern Char **VG_(env_setenv)   ( Char ***envp, const Char* varname,
@@ -73,8 +76,11 @@ extern void   VG_(env_remove_valgrind_env_stuff) ( Char** env );
 extern Char **VG_(env_clone)    ( Char **env_clone );
 
 // misc
-extern Int VG_(poll)( struct vki_pollfd *, UInt nfds, Int timeout);
+extern Int  VG_(poll)( struct vki_pollfd *, UInt nfds, Int timeout);
 extern void VG_(nanosleep) ( struct vki_timespec * );
+extern Int  VG_(getgroups)( Int size, UInt* list );
+extern Int  VG_(ptrace)( Int request, Int pid, void *addr, void *data );
+extern Int  VG_(fork)( void );
 
 // atfork
 typedef void (*vg_atfork_t)(ThreadId);
index 2e80c8d95fa6fc85af1853094b2d16f5b420a1ce..c8bbec6f9b89366ed96a397729ca30fee15a80f4 100644 (file)
 // things.
 //--------------------------------------------------------------------
 
-// Help set up the child used when doing execve() with --trace-children=yes
-Char* VG_(build_child_VALGRINDCLO) ( Char* exename );
-Char* VG_(build_child_exename)     ( void );
-
 // Do everything which needs doing before the process finally ends,
 // like printing reports, etc
 extern void VG_(shutdown_actions_NORETURN) (
index 51670427912f557dece27c9dd838a70713a80ce0..d79dabc910204181726a44b98bf32259384c443e 100644 (file)
@@ -92,11 +92,7 @@ extern void* VG_(arena_memalign)( ArenaId aid, SizeT req_alignB,
                                                SizeT req_pszB );
 extern Char* VG_(arena_strdup)  ( ArenaId aid, const Char* s);
 
-/* Sets the size of the redzones at the start and end of heap blocks.  This
-   must be called before any of VG_(malloc) and friends are called. */
-extern void  VG_(set_client_malloc_redzone_szB) ( SizeT rz_szB );
-
-extern SizeT VG_(arena_payload_szB) ( ThreadId tid, ArenaId aid, void* p );
+extern SizeT VG_(arena_payload_szB) ( ThreadId tid, ArenaId aid, void* payload );
 
 extern void  VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi );
 
index 604e7c03f7447f190f6bffc1fdcd9e58e7138da3..664d79c3c19f24021b325329b2b4d8030a91eed7 100644 (file)
@@ -66,7 +66,7 @@ typedef struct _CodeRedirect CodeRedirect;
 // before translating a basic block.
 extern Addr VG_(code_redirect) ( Addr orig );
 
-/* Set up some default redirects */
+/* Set up some default redirects. */
 extern void VG_(setup_code_redirect_table) ( void );
 
 extern void VG_(resolve_existing_redirs_with_seginfo)(SegInfo *si);
index 7f27ce09bf89f28f3652d0edaab1b88fc92f7a2f..8f5dfbb9add813bc00092a4b204278d6fb331a67 100644 (file)
@@ -49,7 +49,6 @@ struct vg_mallocfunc_info {
    void  (*tl___builtin_delete)    (ThreadId tid, void* p);
    void  (*tl___builtin_vec_delete)(ThreadId tid, void* p);
    void* (*tl_realloc)             (ThreadId tid, void* p, SizeT size);
-
    SizeT (*arena_payload_szB)      (ThreadId tid, ArenaId aid, void* payload);
    void  (*mallinfo)               (ThreadId tid, struct vg_mallinfo* mi);
    Bool        clo_trace_malloc;
index 35574c509a47141c70ab9343d15b34a315fdc887..0ed25b61629c07960a4c110ecd80088009350777 100644 (file)
@@ -75,7 +75,8 @@ extern void VG_(vg_yield)(void);
 // The scheduler.
 extern VgSchedReturnCode VG_(scheduler) ( ThreadId tid );
 
-extern void VG_(scheduler_init) ( void );
+// Initialise.  Is passed the extent of the root thread's client stack.
+extern void VG_(scheduler_init) ( Addr clstack_end, SizeT clstack_size );
 
 /* Stats ... */
 extern void VG_(print_scheduler_stats) ( void );
index dec240397359ffd15902aa89c1ed5fc4a834eac1..d6be42804f0a13831e346b61dd835ac75ffa96c1 100644 (file)
@@ -67,9 +67,16 @@ extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt errflag );
 extern SysRes VG_(mk_SysRes_Error)       ( UWord val );
 extern SysRes VG_(mk_SysRes_Success)     ( UWord val );
 
+
+/* Return a string which gives the name of an error value.  Note,
+   unlike the standard C syserror fn, the returned string is not
+   malloc-allocated or writable -- treat it as a constant. */
+
+extern const HChar* VG_(strerror) ( UWord errnum );
+
+
 #endif   // __PUB_CORE_SYSCALL_H
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
-
index 8ca0fa9f8b802563800ca4bdddcad1b313dbdf37..2c03321ff4f01be9f6babe9709ded5ea4d940e06 100644 (file)
@@ -36,9 +36,6 @@
 // wrappers, but also the main syscall jacketing code.
 //--------------------------------------------------------------------
 
-// Return how many bytes of a thread's Valgrind stack are unused
-extern SSizeT VG_(stack_unused)(ThreadId tid);
-
 // Allocates a stack for the first thread, then runs it,
 // as if the thread had been set up by clone()
 extern void VG_(main_thread_wrapper_NORETURN)(ThreadId tid);
index b7c1ceb0b76181b85864e78e6c652b4305d29d5b..e58e0327d128d5be01ef96ce446bedaf0595c59f 100644 (file)
@@ -112,8 +112,8 @@ typedef struct {
    ThreadId parent;            // parent tid (if any)
 
    /* runtime details */
-   Addr  valgrind_stack_base;  // Valgrind's stack base
-   SizeT valgrind_stack_szB;   // stack size in bytes
+   Addr valgrind_stack_base;    // Valgrind's stack (VgStack*)
+   Addr valgrind_stack_init_SP; // starting value for SP
 
    /* exit details */
    Int  exitcode;              // in the case of exitgroup, set by someone else
index df9fe260ef6ea2b878ec3e2a5048121d63c79396..9aeaeaa4762542da8a048c8314b5e14705d4a3af 100644 (file)
@@ -158,7 +158,7 @@ typedef struct {
    void (*track_new_mem_brk)         (Addr, SizeT);
    void (*track_new_mem_mmap)        (Addr, SizeT, Bool, Bool, Bool);
 
-   void (*track_copy_mem_remap)      (Addr, Addr, SizeT);
+   void (*track_copy_mem_remap)      (Addr src, Addr dst, SizeT);
    void (*track_change_mem_mprotect) (Addr, SizeT, Bool, Bool, Bool);
    void (*track_die_mem_stack_signal)(Addr, SizeT);
    void (*track_die_mem_brk)         (Addr, SizeT);
@@ -209,7 +209,7 @@ extern VgToolInterface VG_(tdict);
    Miscellaneous functions
    ------------------------------------------------------------------ */
 
-Bool VG_(sanity_check_needs) ( Bool non_zero_shadow_memory, Char** failmsg );
+Bool VG_(sanity_check_needs) ( Char** failmsg );
 
 #endif   // __PUB_CORE_TOOLIFACE_H
 
index 6f1455945e103b73867bff262e88e72a5e089574..bd110d8499cb0bca549f0fd0b735263bd1ad1261 100644 (file)
@@ -56,7 +56,8 @@ extern Bool VG_(search_transtab) ( /*OUT*/AddrH* result,
                                    Addr64        guest_addr, 
                                    Bool          upd_cache );
 
-extern void VG_(discard_translations) ( Addr64 start, ULong range );
+extern void VG_(discard_translations) ( Addr64 start, ULong range,
+                                        HChar* who );
 
 extern void VG_(print_tt_tc_stats) ( void );
 
index 91a29ec08e87a7749f72da0e035cb2858545d9c0..fbf414f34ea980bc0fb8f44cd35bc9bc51d799cf 100644 (file)
 /*------------------------------------------------------------*/
 
 /* This is only here so it can be shared between stage1 and stage2 */
-extern
-void VG_(foreach_map)(int (*fn)(char *start, char *end,
-                               const char *perm, off_t offset,
-                               int maj, int min, int ino, void* extra),
-                      void* extra);
-
-/* Jump to 'dst', but first set the stack pointer to 'stack'.  Also,
-   clear all the integer registers before entering 'dst'.  It's
-   important that the stack pointer is set to exactly 'stack' and not
-   (eg) stack - apparently_harmless_looking_small_offset.  Basically
-   because the code at 'dst' might be wanting to scan the area above
-   'stack' (viz, the auxv array), and putting spurious words on the
-   stack confuses it.
-
-   This is only exported so that vgtest_ume.c can use it.
-*/
-extern
-__attribute__((noreturn))
-void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
+
+/* JRS 9 Aug 05: both of these are apparently unused, except by
+   memcheck/tests/vgtest_ume.c. */
+//zz extern
+//zz void VG_(foreach_map)(int (*fn)(char *start, char *end,
+//zz                           const char *perm, off_t offset,
+//zz                           int maj, int min, int ino, void* extra),
+//zz                       void* extra);
+//zz 
+//zz /* Jump to 'dst', but first set the stack pointer to 'stack'.  Also,
+//zz    clear all the integer registers before entering 'dst'.  It's
+//zz    important that the stack pointer is set to exactly 'stack' and not
+//zz    (eg) stack - apparently_harmless_looking_small_offset.  Basically
+//zz    because the code at 'dst' might be wanting to scan the area above
+//zz    'stack' (viz, the auxv array), and putting spurious words on the
+//zz    stack confuses it.
+//zz 
+//zz    This is only exported so that vgtest_ume.c can use it.
+//zz */
+//zz extern
+//zz __attribute__((noreturn))
+//zz void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
 
 
 /*------------------------------------------------------------*/
@@ -73,7 +76,6 @@ void VG_(jump_and_switch_stacks) ( Addr stack, Addr dst );
 // inputs/outputs of do_exec().
 struct exeinfo
 {
-   Addr map_base;       // IN: if non-zero, base address of mappings
    char** argv;         // IN: the original argv
 
    Addr exe_base;       // INOUT: lowest (allowed) address of exe
@@ -112,10 +114,6 @@ struct ume_auxv
 
 extern struct ume_auxv *VG_(find_auxv)(UWord* orig_esp);
 
-/* Our private auxv entries */
-#define AT_UME_PADFD   0xff01  /* padding file fd */
-#define AT_UME_EXECFD  0xff02  /* stage1 executable fd */
-
 #endif /* __PUB_CORE_UME_H */
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/stage1.c b/coregrind/stage1.c
deleted file mode 100644 (file)
index 9d7d00d..0000000
+++ /dev/null
@@ -1,372 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Startup: preliminaries                              stage1.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
-   This file is part of Valgrind, a dynamic binary instrumentation
-   framework.
-
-   Copyright (C) 2000-2005 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.
-*/
-
-#define _FILE_OFFSET_BITS      64
-
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <sys/resource.h>
-#include <unistd.h>
-
-#include "memcheck/memcheck.h"
-#include "pub_core_basics.h"
-#include "pub_core_debuglog.h"
-#include "pub_core_libcbase.h"   // For VG_PGROUNDUP, VG_PGROUNDDN
-#include "pub_core_libcproc.h"   // For VALGRINDLIB
-#include "pub_core_ume.h"
-
-
-static int stack[SIGSTKSZ*4];
-
-// Initial stack pointer, which points to argc.
-static void* init_sp;
-
-/* 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";
-
-/*------------------------------------------------------------*/
-/*--- Auxv modification                                    ---*/
-/*------------------------------------------------------------*/
-
-/* 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,
-                      int padfile)
-{
-   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 = VG_(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].u.a_val = padfile;
-
-   /* 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].u.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].u.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 %5lld: %lld %p\n",
-                auxv, (Long)auxv->a_type, (Long)auxv->u.a_val, auxv->u.a_ptr);
-
-      switch(auxv->a_type) {
-      case AT_PHDR:
-        seen |= 1;
-        auxv->u.a_val = info->phdr;
-        break;
-
-      case AT_PHNUM:
-        seen |= 2;
-        auxv->u.a_val = info->phnum;
-        break;
-
-      case AT_BASE:
-        seen |= 4;
-        auxv->u.a_val = info->interp_base;
-        break;
-
-      case AT_ENTRY:
-        seen |= 8;
-        auxv->u.a_val = info->entry;
-        break;
-
-#if (defined(AT_SYSINFO) || defined(AT_SYSINFO_EHDR))
-#ifdef AT_SYSINFO
-      case AT_SYSINFO:
-#endif
-#ifdef AT_SYSINFO_EHDR
-      case AT_SYSINFO_EHDR:
-#endif
-        auxv->a_type = AT_IGNORE;
-        break;
-#endif
-      }
-   }
-
-   /* 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, "valgrind: we didn't see enough auxv entries (seen=%x)\n", seen);
-      exit(1);
-   }
-
-   return v_init_esp;
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Address space padding                                ---*/
-/*------------------------------------------------------------*/
-
-static void check_mmap(void* res, void* base, int len)
-{
-   if ((void*)-1 == res) {
-      fprintf(stderr, "valgrind: padding mmap(%p, %d) failed during startup.\n"
-                      "valgrind: is there a hard virtual memory limit set?\n",
-                      base, len);
-      exit(1);
-   }
-}
-
-typedef struct {
-   char* fillgap_start;
-   char* fillgap_end;
-   int   fillgap_padfile;
-} fillgap_extra;
-
-static int fillgap(char *segstart, char *segend, const char *perm, off_t off, 
-                   int maj, int min, int ino, void* e)
-{
-   fillgap_extra* extra = e;
-
-   if (segstart >= extra->fillgap_end)
-      return 0;
-
-   if (segstart > extra->fillgap_start) {
-      void* res = mmap(extra->fillgap_start, segstart - extra->fillgap_start,
-                       PROT_NONE, MAP_FIXED|MAP_PRIVATE, 
-                       extra->fillgap_padfile, 0);
-      check_mmap(res, extra->fillgap_start, segstart - extra->fillgap_start);
-   }
-   extra->fillgap_start = segend;
-   
-   return 1;
-}
-
-// Choose a name for the padfile, open it.
-static 
-int as_openpadfile(void)
-{
-   char buf[256];
-   int padfile;
-   int seq = 1;
-   do {
-      snprintf(buf, 256, "/tmp/.pad.%d.%d", getpid(), seq++);
-      padfile = open(buf, O_RDWR|O_CREAT|O_EXCL, 0);
-      unlink(buf);
-      if (padfile == -1 && errno != EEXIST) {
-         fprintf(stderr, "valgrind: couldn't open padfile\n");
-         exit(44);
-      }
-   } while(padfile == -1);
-
-   return padfile;
-}
-
-// Pad all the empty spaces in a range of address space to stop interlopers.
-static
-void as_pad(void *start, void *end, int padfile)
-{
-   fillgap_extra extra;
-   extra.fillgap_start   = start;
-   extra.fillgap_end     = end;
-   extra.fillgap_padfile = padfile;
-
-   VG_(foreach_map)(fillgap, &extra);
-       
-   if (extra.fillgap_start < extra.fillgap_end) {
-      void* res = mmap(extra.fillgap_start, 
-                       extra.fillgap_end - extra.fillgap_start,
-                       PROT_NONE, MAP_FIXED|MAP_PRIVATE, padfile, 0);
-      check_mmap(res, extra.fillgap_start, 
-                 extra.fillgap_end - extra.fillgap_start);
-   }
-}
-
-
-/*------------------------------------------------------------*/
-/*--- main() and related pieces                            ---*/
-/*------------------------------------------------------------*/
-
-static int prmap(char *start, char *end, const char *perm, off_t off, int maj,
-                 int min, int ino, void* dummy) {
-   printf("mapping %10p-%10p %s %02x:%02x %d\n",
-          start, end, perm, maj, min, ino);
-   return 1;
-}
-
-
-static void main2(void)
-{
-   int err, padfile;
-   struct exeinfo info;
-   extern char _end;
-   int *esp;
-   char buf[strlen(valgrind_lib) + sizeof(stage2) + 16];
-   info.exe_end  = VG_PGROUNDDN(init_sp);
-#ifdef HAVE_PIE
-   info.exe_base = VG_ROUNDDN(info.exe_end - 0x02000000, 0x10000000);
-   assert(info.exe_base >= VG_PGROUNDUP(&_end));
-   info.map_base = info.exe_base + 0x01000000;
-#else
-   // If this system doesn't have PIE (position-independent executables),
-   // we have to choose a hardwired location for stage2.
-   info.exe_base = VG_PGROUNDUP(&_end);
-   info.map_base = KICKSTART_BASE + 0x01000000;
-#endif
-
-   info.argv = NULL;
-
-   snprintf(buf, sizeof(buf), "%s/%s", valgrind_lib, stage2);
-
-   err = VG_(do_exec)(buf, &info);
-
-   if (err != 0) {
-      fprintf(stderr, "valgrind: 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. */
-   padfile = as_openpadfile();
-   as_pad(0, (void *)info.map_base, padfile);
-   
-   esp = fix_auxv(init_sp, &info, padfile);
-
-   if (0) {
-      printf("---------- launch stage 2 ----------\n");
-      printf("eip=%p esp=%p\n", (void *)info.init_eip, esp);
-      VG_(foreach_map)(prmap, /*dummy*/NULL);
-   }
-
-   VG_(debugLog)(1, "stage1", "main2(): starting stage2\n");
-   VG_(jump_and_switch_stacks)(
-      (Addr) esp,           /* stack */
-      (Addr) info.init_eip  /* where to */
-   );
-
-   /*NOTREACHED*/
-   assert(0); 
-}
-
-
-int main(int argc, char** argv)
-{
-   struct rlimit rlim;
-   const char *cp;
-   int i, loglevel;
-
-   /* Start the debugging-log system ASAP.  First find out how many 
-      "-d"s were specified.  This is a pre-scan of the command line. */
-   loglevel = 0;
-   for (i = 1; i < argc; i++) {
-     if (argv[i][0] != '-')
-        break;
-     if (0 == strcmp(argv[i], "--")) 
-        break;
-     if (0 == strcmp(argv[i], "-d")) 
-        loglevel++;
-   }
-
-   /* ... and start the debug logger.  Now we can safely emit logging
-      messages all through startup. */
-   VG_(debugLog_startup)(loglevel, "Stage 1");
-
-   // Initial stack pointer is to argc, which is immediately before argv[0]
-   // on the stack.  Nb: Assumes argc is word-aligned.
-   init_sp = argv - 1;
-
-   /* The Linux libc startup sequence leaves this in an apparently
-      undefined state, but it really is defined, so mark it so. */
-   VALGRIND_MAKE_READABLE(init_sp, sizeof(Word));
-
-   cp = getenv(VALGRINDLIB);
-
-   if (cp != NULL)
-      valgrind_lib = cp;
-
-   /* Set the address space limit as high as it will go, since we make
-      a lot of very large mappings. */
-   getrlimit(RLIMIT_AS, &rlim);
-   rlim.rlim_cur = rlim.rlim_max;
-   setrlimit(RLIMIT_AS, &rlim);
-
-   /* move onto another stack so we can play with the main one */
-   VG_(debugLog)(1, "stage1", "main(): running main2() on new stack\n");
-   VG_(jump_and_switch_stacks)(
-      (Addr) stack + sizeof(stack),  /* stack */
-      (Addr) main2                   /* where to */
-   );
-
-   /*NOTREACHED*/
-   assert(0); 
-}
-
-/*--------------------------------------------------------------------*/
-/*--- end                                                 stage1.c ---*/
-/*--------------------------------------------------------------------*/
index 2d708af53d04e258430f27e42f495a8d72f5385c..6756353906697ba10393b84f551d3c24235d85f1 100644 (file)
@@ -511,7 +511,10 @@ ESecMap* alloc_secondary_map ( __attribute__ ((unused)) Char* caller )
    //PROF_EVENT(10); PPP
 
    // Mark all words as virgin.
-   map = (ESecMap *)VG_(shadow_alloc)(sizeof(ESecMap));
+   map = (ESecMap *)VG_(am_shadow_alloc)(sizeof(ESecMap));
+   if (map == NULL)
+      VG_(out_of_memory_NORETURN)( "helgrind:allocate new ESecMap", 
+                                   sizeof(ESecMap) );
    for (i = 0; i < ESEC_MAP_WORDS; i++)
       map->swords[i] = virgin_sword;
 
@@ -3469,8 +3472,7 @@ static void hg_pre_clo_init(void)
    hg_malloc_list = VG_(HT_construct)( 80021 );    // prime, big
 }
 
-/* Uses a 1:1 mapping */
-VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init, 1.0)
+VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                hg_main.c ---*/
index 5398ce9c404a6c893bff0becec78cbbf25868240..be65a1ad5755ff4052ce3b929c346015aa836428 100644 (file)
@@ -5,6 +5,7 @@ incinc_HEADERS = \
        pub_tool_basics.h               \
        pub_tool_basics_asm.h           \
        pub_tool_aspacemgr.h            \
+       pub_tool_clientstate.h          \
        pub_tool_cpuid.h                \
        pub_tool_debuginfo.h            \
        pub_tool_errormgr.h             \
@@ -13,7 +14,6 @@ incinc_HEADERS = \
        pub_tool_libcbase.h             \
        pub_tool_libcassert.h           \
        pub_tool_libcfile.h             \
-       pub_tool_libcmman.h             \
        pub_tool_libcprint.h            \
        pub_tool_libcproc.h             \
        pub_tool_libcsignal.h           \
index 92c102f87b2228510d81f5612d645e66e29e50bf..51240bb3d7a1c8c96b888e974a1f5b7c1c01b620 100644 (file)
 #ifndef __PUB_TOOL_ASPACEMGR_H
 #define __PUB_TOOL_ASPACEMGR_H
 
-extern Bool VG_(is_client_addr) (Addr a);
 
-extern Bool VG_(is_shadow_addr) (Addr a);
-
-extern void *VG_(shadow_alloc)(UInt size);
-
-extern Bool VG_(is_addressable)(Addr p, SizeT sz, UInt prot);
-
-/* Calls into the core used by leak-checking */
-
-/* Calls "add_rootrange" with each range of memory which looks like a
-   plausible source of root pointers.  This is very Memcheck-specific --
-   it's used in leak detection.
+//--------------------------------------------------------------
+// Definition of address-space segments
+
+/* Describes segment kinds. */
+typedef
+   enum {
+      SkFree,   // unmapped space
+      SkAnonC,  // anonymous mapping belonging to the client
+      SkAnonV,  // anonymous mapping belonging to valgrind
+      SkFileC,  // file mapping belonging to the client
+      SkFileV,  // file mapping belonging to valgrind
+      SkResvn   // reservation
+   }
+   SegKind;
+
+/* Describes how a reservation segment can be resized. */
+typedef
+   enum {
+      SmLower,  // lower end can move up
+      SmFixed,  // cannot be shrunk
+      SmUpper   // upper end can move down
+   }
+   ShrinkMode;
+
+/* Describes a segment.  Invariants:
+
+     kind == SkFree:
+        // the only meaningful fields are .start and .end
+
+     kind == SkAnon{C,V}:
+        // smode==SmFixed
+        // there's no associated file:
+        dev==ino==foff = 0, fnidx == -1
+        // segment may have permissions
+
+     kind == SkFile{C,V}:
+        // smode==SmFixed
+        moveLo == moveHi == NotMovable, maxlen == 0
+        // there is an associated file
+        // segment may have permissions
+
+     kind == SkResvn
+        // the segment may be resized if required
+        // there's no associated file:
+        dev==ino==foff = 0, fnidx == -1
+        // segment has no permissions
+        hasR==hasW==hasX==anyTranslated == False
+
+     Also: anyTranslated==True is only allowed in SkFileV and SkAnonV
+           (viz, not allowed to make translations from non-client areas)
 */
-extern void VG_(find_root_memory)(void (*add_rootrange)(Addr addr, SizeT sz));
+typedef
+   struct {
+      SegKind kind;
+      /* Extent (SkFree, SkAnon{C,V}, SkFile{C,V}, SkResvn) */
+      Addr    start;    // lowest address in range
+      Addr    end;      // highest address in range
+      /* Shrinkable? (SkResvn only) */
+      ShrinkMode smode;
+      /* Associated file (SkFile{C,V} only) */
+      UWord   dev;
+      UWord   ino;
+      ULong   offset;
+      Int     fnIdx;    // file name table index, if name is known
+      /* Permissions (SkAnon{C,V}, SkFile{C,V} only) */
+      Bool    hasR;
+      Bool    hasW;
+      Bool    hasX;
+      Bool    hasT;     // True --> translations have (or MAY have)
+                        // been taken from this segment
+      Bool    isCH;     // True --> is client heap (SkAnonC ONLY)
+      /* Admin */
+      Bool    mark;
+   }
+   NSegment;
+
+
+/* Collect up the start addresses of all non-free, non-resvn segments.
+   The interface is a bit strange in order to avoid potential
+   segment-creation races caused by dynamic allocation of the result
+   buffer *starts.
+
+   The function first computes how many entries in the result
+   buffer *starts will be needed.  If this number <= nStarts,
+   they are placed in starts[0..], and the number is returned.
+   If nStarts is not large enough, nothing is written to
+   starts[0..], and the negation of the size is returned.
+
+   Correct use of this function may mean calling it multiple times in
+   order to establish a suitably-sized buffer. */
+extern Int VG_(am_get_segment_starts)( Addr* starts, Int nStarts );
+
+
+// See pub_core_aspacemgr.h for description.
+extern NSegment* VG_(am_find_nsegment) ( Addr a ); 
+
+// See pub_core_aspacemgr.h for description.
+extern Bool VG_(am_is_valid_for_client) ( Addr start, SizeT len, 
+                                          UInt prot );
+
+// See pub_core_aspacemgr.h for description.
+/* Really just a wrapper around VG_(am_mmap_anon_float_valgrind). */
+extern void* VG_(am_shadow_alloc)(SizeT size);
 
 #endif   // __PUB_TOOL_ASPACEMGR_H
 
index f75b936225f6420d17834c404c758ed6483bf377..7af5240e93a850d9ce109b2b96466e1e2b81adeb 100644 (file)
@@ -106,7 +106,7 @@ typedef struct {
 SysRes;
 
 /* ---------------------------------------------------------------------
-   Miscellaneous (word size, endianness, regparmness)
+   Miscellaneous (word size, endianness, regparmness, stringification)
    ------------------------------------------------------------------ */
 
 /* Word size: this is going to be either 4 or 8. */
@@ -132,6 +132,10 @@ SysRes;
 #  error Unknown arch
 #endif
 
+/* Macro games */
+#define VG_STRINGIFZ(__str)  #__str
+#define VG_STRINGIFY(__str)  VG_STRINGIFZ(__str)
+
 #endif /* __PUB_TOOL_BASICS_H */
 
 /*--------------------------------------------------------------------*/
index 65f479976a7ca03882e818c5cc90aa11eede80dd..740eaba62fea5ec0d438002eb959a2368eb708a9 100644 (file)
@@ -1,7 +1,7 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Header imported directly by every asm file, and indirectly   ---*/
-/*--- (via pub_tool_basics.h) by every C file.                     ---*/
+/*--- Header imported directly by every tool asm file, and         ---*/
+/*--- (via pub_tool_basics.h) by every tool C file.                ---*/
 /*---                                        pub_tool_basics_asm.h ---*/
 /*--------------------------------------------------------------------*/
 
diff --git a/include/pub_tool_clientstate.h b/include/pub_tool_clientstate.h
new file mode 100644 (file)
index 0000000..065c2ba
--- /dev/null
@@ -0,0 +1,77 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Misc client state info                pub_tool_clientstate.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2005 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.
+*/
+
+#ifndef __PUB_TOOL_CLIENTSTATE_H
+#define __PUB_TOOL_CLIENTSTATE_H
+
+
+// Command line pieces, after they have been extracted from argv in
+// m_main.main().  These are all NULL-terminated vectors.
+
+/* Expandable arrays of strings. */
+typedef
+   struct {
+      Int     size;
+      Int     used;
+      HChar** strs;
+   }
+   XArrayStrings;
+
+/* Args for the client. */
+extern XArrayStrings VG_(args_for_client);
+
+/* Args for V.  This is the concatenation of the following:
+   - contents of ~/.valgrindrc
+   - contents of $VALGRIND_OPTS
+   - contents of ./.valgrindrc
+   - args from the command line
+   in the stated order.
+
+   Only the last of these is passed onwards to child Valgrinds at
+   client sys_execve, since the children will re-acquire the first 3
+   categories for themselves.  Therefore we also record the number of
+   these no-pass-at-execve arguments -- that is what
+   VG_(args_for_valgrind_noexecpass) is. */
+extern XArrayStrings VG_(args_for_valgrind);
+
+/* Number of leading args in VG_(args_for_valgrind) not to pass on at
+   exec time. */
+extern Int VG_(args_for_valgrind_noexecpass);
+
+/* The name of the client executable, as specified on the command
+   line. */
+extern HChar* VG_(args_the_exename);
+
+
+#endif   // __PUB_TOOL_CLIENTSTATE_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
index d1f7f5c1d15eceb24fb91074bd015d04fbacee7e..cc1a55e371a9407cfd1ba4bd90fbf465630c17fb 100644 (file)
@@ -114,10 +114,10 @@ extern void VG_(ssort)( void* base, SizeT nmemb, SizeT size,
 /* Returns the base-2 logarithm of x. */
 extern Int VG_(log2) ( Int x );
 
-// A pseudo-random number generator returning a random UInt,  and its
-// seed function.
-extern void VG_(srandom) ( UInt seed );
-extern UInt VG_(random)  ( void );
+// A pseudo-random number generator returning a random UInt.  If pSeed
+// is NULL, it uses its own seed, which starts at zero.  If pSeed is
+// non-NULL, it uses and updates whatever pSeed points at.
+extern UInt VG_(random) ( /*MOD*/UInt* pSeed );
 
 #endif   // __PUB_TOOL_LIBCBASE_H
 
index 2d89c5dc96e77a5d3eea5aaaf89d2cc2379d9310..41da4a37e2b51f824c0d0b08e4bbe1d36ad80e61 100644 (file)
@@ -40,19 +40,19 @@ extern void   VG_(close)  ( Int fd );
 extern Int    VG_(read)   ( Int fd, void* buf, Int count);
 extern Int    VG_(write)  ( Int fd, const void* buf, Int count);
 extern Int    VG_(pipe)   ( Int fd[2] );
-extern OffT   VG_(lseek)  ( Int fd, OffT offset, Int whence);
+extern OffT   VG_(lseek)  ( Int fd, OffT offset, Int whence );
 
 extern SysRes VG_(stat)   ( Char* file_name, struct vki_stat* buf );
 extern Int    VG_(fstat)  ( Int   fd,        struct vki_stat* buf );
-extern Int    VG_(dup2)   ( Int oldfd, Int newfd );
+extern SysRes VG_(dup)    ( Int oldfd );
 extern Int    VG_(rename) ( Char* old_name, Char* new_name );
 extern Int    VG_(unlink) ( Char* file_name );
 
 // Returns False on failure (eg. if the buffer isn't big enough).
-extern Bool VG_(getcwd) ( Char* buf, SizeT size );
+extern Bool   VG_(getcwd) ( Char* buf, SizeT size );
 
-extern Int  VG_(readlink)( Char* path, Char* buf, UInt bufsize );
-extern Int  VG_(getdents)( UInt fd, struct vki_dirent *dirp, UInt count );
+extern Int    VG_(readlink)( Char* path, Char* buf, UInt bufsize );
+extern Int    VG_(getdents)( UInt fd, struct vki_dirent *dirp, UInt count );
 
 #endif   // __PUB_TOOL_LIBCFILE_H
 
index 9a6ce995cd20b6e1303b55db421ac39ec1782b36..7fff4590d635566754052ca5922a38f214cc4583 100644 (file)
  * --log-fd/--log-file/--log-socket argument, which defaults to 2 (stderr).
  * Hence no need for VG_(fprintf)().
  */
-extern UInt VG_(printf)  ( const HChar *format, ... );
-extern UInt VG_(vprintf) ( const HChar *format, va_list vargs );
+extern UInt VG_(printf)   ( const HChar *format, ... );
+extern UInt VG_(vprintf)  ( const HChar *format, va_list vargs );
 /* too noisy ...  __attribute__ ((format (printf, 1, 2))) ; */
-extern UInt VG_(sprintf) ( Char* buf, const HChar* format, ... );
-extern UInt VG_(vsprintf)( Char* buf, const HChar* format, va_list vargs );
+
+extern UInt VG_(sprintf)  ( Char* buf, const HChar* format, ... );
+extern UInt VG_(vsprintf) ( Char* buf, const HChar* format, va_list vargs );
+
+extern UInt VG_(snprintf) ( Char* buf, Int size, 
+                                       const HChar *format, ... );
+extern UInt VG_(vsnprintf)( Char* buf, Int size, 
+                                       const HChar *format, va_list vargs );
 
 // Percentify n/m with d decimal places.  Includes the '%' symbol at the end.
 // Right justifies in 'buf'.
index b4e008010a91a4d407b44f1ee5e7c2b28ce538e0..d89f4fc8c06b2149f6b57b9d18b9cb7811798501 100644 (file)
@@ -38,8 +38,6 @@
 /* Client args and environment.  Note that VG_(client_argv)[] can be written
    to by the client, so you should check each entry is non-NULL before
    printing.  VG_(client_envp) can be inspected with VG_(getenv)(). */
-extern Int    VG_(client_argc);
-extern Char** VG_(client_argv);
 extern Char** VG_(client_envp);
 
 /* Looks up VG_(client_envp) */
@@ -66,11 +64,12 @@ extern Int VG_(setrlimit) ( Int resource, const struct vki_rlimit *rlim );
    pids, etc
    ------------------------------------------------------------------ */
 
-extern Int VG_(gettid)  ( void );
+extern Int VG_(gettid)  ( void );
 extern Int VG_(getpid)  ( void );
 extern Int VG_(getppid) ( void );
 extern Int VG_(getpgrp) ( void );
-extern Int VG_(setpgid) ( Int pid, Int pgrp );
+extern Int VG_(geteuid) ( void );
+extern Int VG_(getegid) ( void );
 
 /* ---------------------------------------------------------------------
    Timing
index 1fbf9f5c044a8ad952795b3ac581936ca60fd0aa..7a36c9e2082c0066b0c871d076b64987de0e16cf 100644 (file)
@@ -39,6 +39,10 @@ extern void* VG_(calloc)         ( SizeT n, SizeT bytes_per_elem );
 extern void* VG_(realloc)        ( void* p, SizeT size );
 extern Char* VG_(strdup)         ( const Char* s );
 
+// TODO: move somewhere else
+// Call here to bomb the system when out of memory (mmap anon fails)
+extern void VG_(out_of_memory_NORETURN) ( HChar* who, SizeT szB );
+
 #endif   // __PUB_TOOL_MALLOCFREE_H
 
 /*--------------------------------------------------------------------*/
index b5f74cde6ee545dd2c68dd96047d813a765165cd..e72a0298dd88e9625b34875cfb55238bdd406fb6 100644 (file)
@@ -58,19 +58,16 @@ typedef struct _ToolInfo {
       - any other tool-specific initialisation
    */
    void (*tl_pre_clo_init) ( void );
-
-   /* Specifies how big the shadow segment should be as a ratio to the
-      client address space.  0 for no shadow segment. */
-   float shadow_ratio;
 } ToolInfo;
 
+extern const ToolInfo VG_(tool_info);
+
 /* Every tool must include this macro somewhere, exactly once. */
-#define VG_DETERMINE_INTERFACE_VERSION(pre_clo_init, shadow)   \
+#define VG_DETERMINE_INTERFACE_VERSION(pre_clo_init)           \
    const ToolInfo VG_(tool_info) = {                           \
       .sizeof_ToolInfo   = sizeof(ToolInfo),                   \
       .interface_version = VG_CORE_INTERFACE_VERSION,          \
       .tl_pre_clo_init   = pre_clo_init,                       \
-      .shadow_ratio     = shadow,                             \
    };
 
 /* ------------------------------------------------------------------ */
index 7eb1906f3316215a41d35e81da9c1e4bad01d20f..611c57aa1fbf03b4223f8e4d4efd830079a17101 100644 (file)
@@ -229,6 +229,7 @@ struct vki_sigcontext {
 
 #define VKI_O_RDONLY        00
 #define VKI_O_WRONLY        01
+#define VKI_O_RDWR          02
 #define VKI_O_CREAT       0100 /* not fcntl */
 #define VKI_O_EXCL        0200 /* not fcntl */
 #define VKI_O_TRUNC      01000 /* not fcntl */
index 5d6df36c6772c7d46f99f1490509c26ed865c0f6..1cd05179394c063446a92c8233044b8f3df1bbc2 100644 (file)
@@ -1088,8 +1088,10 @@ struct  vki_seminfo {
 //----------------------------------------------------------------------
 
 #define        VKI_EPERM                1      /* Operation not permitted */
+#define        VKI_ENOENT               2      /* No such file or directory */
 #define        VKI_ESRCH                3      /* No such process */
 #define        VKI_EINTR                4      /* Interrupted system call */
+#define VKI_ENOEXEC              8      /* Exec format error */
 #define        VKI_EBADF                9      /* Bad file number */
 #define VKI_EAGAIN             11      /* Try again */
 #define VKI_EWOULDBLOCK                VKI_EAGAIN
@@ -1162,8 +1164,20 @@ struct  vki_seminfo {
 #define VKI_S_ISFIFO(m)        (((m) & VKI_S_IFMT) == VKI_S_IFIFO)
 #define VKI_S_ISSOCK(m)        (((m) & VKI_S_IFMT) == VKI_S_IFSOCK)
 
+#define VKI_S_IRWXU 00700
 #define VKI_S_IRUSR 00400
 #define VKI_S_IWUSR 00200
+#define VKI_S_IXUSR 00100
+
+#define VKI_S_IRWXG 00070
+#define VKI_S_IRGRP 00040
+#define VKI_S_IWGRP 00020
+#define VKI_S_IXGRP 00010
+
+#define VKI_S_IRWXO 00007
+#define VKI_S_IROTH 00004
+#define VKI_S_IWOTH 00002
+#define VKI_S_IXOTH 00001
 
 //----------------------------------------------------------------------
 // From linux-2.6.8.1/include/linux/dirent.h
@@ -2008,10 +2022,13 @@ typedef __vki_kernel_uid32_t vki_qid_t; /* Type in which we store ids in memory
 // From linux-2.6.9/include/linux/ptrace.h
 //----------------------------------------------------------------------
 
+#define VKI_PTRACE_TRACEME         0
 #define VKI_PTRACE_PEEKTEXT       1
 #define VKI_PTRACE_PEEKDATA       2
 #define VKI_PTRACE_PEEKUSR        3
 
+#define VKI_PTRACE_DETACH       0x11
+
 #endif // __VKI_LINUX_H
 
 /*--------------------------------------------------------------------*/
index 485ca0169b88a7bf5de58fa5660d155dceed86f8..a85a3db7aa850d1ff8e57728e196bb0497184d7e 100644 (file)
@@ -1,7 +1,8 @@
 include $(top_srcdir)/Makefile.tool.am
 
-val_PROGRAMS = vgtool_lackey.so
-
-vgtool_lackey_so_SOURCES = lk_main.c
-vgtool_lackey_so_LDFLAGS = -shared
+val_PROGRAMS = lackey
 
+lackey_SOURCES      = lk_main.c
+lackey_DEPENDENCIES = $(COREGRIND_LIBS)
+lackey_LDADD        = $(TOOL_LINKADD)
+lackey_LDFLAGS      = $(TOOL_LINKFLAGS)
index ccb4a4dfe16cbd15983bad567c17f66d63cad4b7..92843e05bdfd36bd1019ec7acca33e04be8a7a28 100644 (file)
@@ -288,7 +288,7 @@ static void lk_pre_clo_init(void)
                                    lk_fini);
 }
 
-VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init, 0)
+VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                lk_main.c ---*/
index ffe94d9127c57d3fb757c6c509f1ed0895b58c7e..f922a4c771cea41166ca88b65399a7e620c49e40 100644 (file)
@@ -2,17 +2,17 @@ include $(top_srcdir)/Makefile.tool.am
 
 SUBDIRS += hp2ps
 
-val_PROGRAMS = vgtool_massif.so vgpreload_massif.so
+val_PROGRAMS = massif vgpreload_massif.so
 
-vgtool_massif_so_SOURCES = ms_main.c
-vgtool_massif_so_LDFLAGS = -shared
-
-vgpreload_massif_so_SOURCES = 
-vgpreload_massif_so_DEPENDENCIES = \
-       $(LIBREPLACEMALLOC)
-vgpreload_massif_so_LDFLAGS = -shared -Wl,-z,interpose,-z,initfirst \
+vgpreload_massif_so_SOURCES      = 
+vgpreload_massif_so_DEPENDENCIES = $(LIBREPLACEMALLOC)
+vgpreload_massif_so_LDFLAGS      = \
+       -shared -Wl,-z,interpose,-z,initfirst \
        -Wl,--whole-archive \
        $(LIBREPLACEMALLOC) \
        -Wl,--no-whole-archive
 
-
+massif_SOURCES      = ms_main.c
+massif_DEPENDENCIES = $(COREGRIND_LIBS)
+massif_LDADD        = $(TOOL_LINKADD)
+massif_LDFLAGS             = $(TOOL_LINKFLAGS)
index 73c49d0dc8fc1310a24bacbdc654cbf25b0258d0..cc4c13831c84364e77c85f8f8536b5ef5d7de8dc 100644 (file)
 // structures below for more info on how things work.
 
 #include "pub_tool_basics.h"
+#include "pub_tool_aspacemgr.h"
 #include "pub_tool_debuginfo.h"
 #include "pub_tool_hashtable.h"
 #include "pub_tool_libcbase.h"
 #include "pub_tool_libcassert.h"
 #include "pub_tool_libcfile.h"
-#include "pub_tool_libcmman.h"
 #include "pub_tool_libcprint.h"
 #include "pub_tool_libcproc.h"
 #include "pub_tool_machine.h"
@@ -50,6 +50,7 @@
 #include "pub_tool_replacemalloc.h"
 #include "pub_tool_stacktrace.h"
 #include "pub_tool_tooliface.h"
+#include "pub_tool_clientstate.h"
 
 #include "valgrind.h"           // For {MALLOC,FREE}LIKE_BLOCK
 
@@ -367,7 +368,10 @@ static void* perm_malloc(SizeT n_bytes)
    #define SUPERBLOCK_SIZE  (1 << 20)         // 1 MB
 
    if (hp + n_bytes > hp_lim) {
-      hp     = (Addr)VG_(get_memory_from_mmap)(SUPERBLOCK_SIZE, "perm_malloc");
+      hp = (Addr)VG_(am_shadow_alloc)(SUPERBLOCK_SIZE);
+      if (hp == 0)
+         VG_(out_of_memory_NORETURN)( "massif:perm_malloc", 
+                                      SUPERBLOCK_SIZE);
       hp_lim = hp + SUPERBLOCK_SIZE - 1;
    }
 
@@ -1341,9 +1345,12 @@ static void write_hp_file(void)
 
    // File header, including command line
    SPRINTF(buf, "JOB         \"");
-   for (i = 0; i < VG_(client_argc); i++) {
-      if (VG_(client_argv)[i])
-         SPRINTF(buf, "%s ", VG_(client_argv)[i]);
+   if (VG_(args_the_exename)) {
+      SPRINTF(buf, "%s", VG_(args_the_exename));
+   }
+   for (i = 0; i < VG_(args_for_client).used; i++) {
+      if (VG_(args_for_client).strs[i])
+         SPRINTF(buf, " %s", VG_(args_for_client).strs[i]);
    }
    SPRINTF(buf, /*" (%d ms/sample)\"\n"*/ "\"\n"
                 "DATE        \"\"\n"
@@ -1665,10 +1672,13 @@ write_text_file(ULong total_ST, ULong heap_ST)
    }
 
    // Command line
-   SPRINTF(buf, "Command: ");
-   for (i = 0; i < VG_(client_argc); i++) {
-      if (VG_(client_argv)[i])
-         SPRINTF(buf, "%s ", VG_(client_argv)[i]);
+   SPRINTF(buf, "Command:");
+   if (VG_(args_the_exename)) {
+      SPRINTF(buf, " %s", VG_(args_the_exename));
+   }
+   for (i = 0; i < VG_(args_for_client).used; i++) {
+      if (VG_(args_for_client).strs[i])
+         SPRINTF(buf, " %s", VG_(args_for_client).strs[i]);
    }
    SPRINTF(buf, "\n%s\n", maybe_p);
 
@@ -1818,7 +1828,7 @@ static void ms_pre_clo_init()
    tl_assert( VG_(getcwd)(base_dir, VKI_PATH_MAX) );
 }
 
-VG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init, 0)
+VG_DETERMINE_INTERFACE_VERSION(ms_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
index a9db374fa02fc99eca6aa195607b7fddadcb5c0d..cf250847644f528799231a46a1175b941e379f69 100644 (file)
@@ -3,24 +3,25 @@ include $(top_srcdir)/Makefile.tool.am
 ## Build Memcheck at a higher optimisation level
 AM_CFLAGS += -O2
 
-val_PROGRAMS = vgtool_memcheck.so vgpreload_memcheck.so
+val_PROGRAMS = memcheck vgpreload_memcheck.so
 
-vgpreload_memcheck_so_SOURCES = \
-       mac_replace_strmem.c
-vgpreload_memcheck_so_DEPENDENCIES = \
-       $(LIBREPLACEMALLOC)
-vgpreload_memcheck_so_LDFLAGS = -shared -Wl,-z,interpose,-z,initfirst \
+vgpreload_memcheck_so_SOURCES      = mac_replace_strmem.c
+vgpreload_memcheck_so_DEPENDENCIES = $(LIBREPLACEMALLOC)
+vgpreload_memcheck_so_LDFLAGS      = \
+       -shared -Wl,-z,interpose,-z,initfirst \
        -Wl,--whole-archive \
        $(LIBREPLACEMALLOC) \
        -Wl,--no-whole-archive
 
-vgtool_memcheck_so_SOURCES = \
+memcheck_SOURCES = \
        mac_leakcheck.c \
        mac_malloc_wrappers.c \
        mc_main.c \
        mac_shared.c \
        mc_translate.c
-vgtool_memcheck_so_LDFLAGS = -shared
+memcheck_DEPENDENCIES = $(COREGRIND_LIBS)
+memcheck_LDADD        = $(TOOL_LINKADD)
+memcheck_LDFLAGS      = $(TOOL_LINKFLAGS)
 
 mcincludedir = $(includedir)/valgrind
 
index 5ae719ed7d6cc74c7c797882b071e4ffdc6362ef..1ca39b887e08222cd92562245141967b21ae90a5 100644 (file)
@@ -72,6 +72,41 @@ void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
       __builtin_longjmp(memscan_jmpbuf, 1);
 }
 
+
+/* TODO: GIVE THIS A PROPER HOME
+   TODO: MERGE THIS WITH DUPLICATE IN m_main.c
+   Extract from aspacem a vector of the current segment start
+   addresses.  The vector is dynamically allocated and should be freed
+   by the caller when done.  REQUIRES m_mallocfree to be running.
+   Writes the number of addresses required into *n_acquired. */
+
+static Addr* get_seg_starts ( /*OUT*/Int* n_acquired )
+{
+   Addr* starts;
+   Int   n_starts, r;
+
+   n_starts = 1;
+   while (True) {
+      starts = VG_(malloc)( n_starts * sizeof(Addr) );
+      if (starts == NULL)
+         break;
+      r = VG_(am_get_segment_starts)( starts, n_starts );
+      if (r >= 0)
+         break;
+      VG_(free)(starts);
+      n_starts *= 2;
+   }
+
+   if (starts == NULL) {
+     *n_acquired = 0;
+     return NULL;
+   }
+
+   *n_acquired = r;
+   return starts;
+}
+
+
 /*------------------------------------------------------------*/
 /*--- Detecting leaked (unreachable) malloc'd blocks.      ---*/
 /*------------------------------------------------------------*/
@@ -82,19 +117,23 @@ void scan_all_valid_memory_catcher ( Int sigNo, Addr addr )
    -- Unreached; so far, no pointers to any part of it have been found. 
    -- IndirectLeak; leaked, but referred to by another leaked block
 */
-typedef enum { 
-   Unreached, 
-   IndirectLeak,
-   Interior, 
-   Proper
- } Reachedness;
+typedef 
+   enum { 
+      Unreached, 
+      IndirectLeak,
+      Interior, 
+      Proper
+  }
+  Reachedness;
 
 /* An entry in the mark stack */
-typedef struct {
-   Int next:30;                /* Index of next in mark stack */
-   UInt        state:2;                /* Reachedness */
-   SizeT indirect;             /* if Unreached, how much is unreachable from here */
-} MarkStack;
+typedef 
+   struct {
+      Int   next:30;   /* Index of next in mark stack */
+      UInt  state:2;   /* Reachedness */
+      SizeT indirect;  /* if Unreached, how much is unreachable from here */
+   } 
+   MarkStack;
 
 /* A block record, used for generating err msgs. */
 typedef
@@ -112,11 +151,13 @@ typedef
    LossRecord;
 
 /* The 'extra' struct for leak errors. */
-typedef struct {
-   UInt        n_this_record;
-   UInt        n_total_records;
-   LossRecord* lossRecord;
-} LeakExtra;
+typedef 
+   struct {
+      UInt        n_this_record;
+      UInt        n_total_records;
+      LossRecord* lossRecord;
+   }
+   LeakExtra;
 
 /* Find the i such that ptr points at or inside the block described by
    shadows[i].  Return -1 if none found.  This assumes that shadows[]
@@ -289,11 +330,12 @@ static Int lc_compar(void* n1, void* n2)
 /* If ptr is pointing to a heap-allocated block which hasn't been seen
    before, push it onto the mark stack.  Clique is the index of the
    clique leader; -1 if none. */
-static void _lc_markstack_push(Addr ptr, Int clique)
+static void lc_markstack_push_WRK(Addr ptr, Int clique)
 {
    Int sh_no;
 
-   if (!VG_(is_client_addr)(ptr)) /* quick filter */
+   /* quick filter */
+   if (!VG_(am_is_valid_for_client)(ptr, 1, VKI_PROT_NONE))
       return;
 
    sh_no = find_shadow_for(ptr, lc_shadows, lc_n_shadows);
@@ -317,6 +359,8 @@ static void _lc_markstack_push(Addr ptr, Int clique)
       lc_markstack_top = sh_no;
    }
 
+   tl_assert(clique >= -1 && clique < lc_n_shadows);
+
    if (clique != -1) {
       if (0)
         VG_(printf)("mopup: %d: %p is %d\n", 
@@ -358,7 +402,7 @@ static void _lc_markstack_push(Addr ptr, Int clique)
 
 static void lc_markstack_push(Addr ptr)
 {
-   _lc_markstack_push(ptr, -1);
+   lc_markstack_push_WRK(ptr, -1);
 }
 
 /* Return the top of the mark stack, if any. */
@@ -380,7 +424,7 @@ static Int lc_markstack_pop(void)
 
    If clique != -1, it means we're gathering leaked memory into
    cliques, and clique is the index of the current clique leader. */
-static void _lc_scan_memory(Addr start, SizeT len, Int clique)
+static void lc_scan_memory_WRK(Addr start, SizeT len, Int clique)
 {
    Addr ptr = VG_ROUNDUP(start, sizeof(Addr));
    Addr end = VG_ROUNDDN(start+len, sizeof(Addr));
@@ -391,10 +435,9 @@ static void _lc_scan_memory(Addr start, SizeT len, Int clique)
    VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &sigmask);
    VG_(set_fault_catcher)(scan_all_valid_memory_catcher);
 
-   lc_scanned += end-ptr;
+   //   lc_scanned += end-ptr;
 
-   if (!VG_(is_client_addr)(ptr) ||
-       !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
+   if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
       ptr = VG_PGROUNDUP(ptr+1);       /* first page bad */
 
    while (ptr < end) {
@@ -408,15 +451,15 @@ static void _lc_scan_memory(Addr start, SizeT len, Int clique)
 
       /* Look to see if this page seems reasonble */
       if ((ptr % VKI_PAGE_SIZE) == 0) {
-        if (!VG_(is_client_addr)(ptr) ||
-            !VG_(is_addressable)(ptr, sizeof(Addr), VKI_PROT_READ))
+        if (!VG_(am_is_valid_for_client)(ptr, sizeof(Addr), VKI_PROT_READ))
            ptr += VKI_PAGE_SIZE; /* bad page - skip it */
       }
 
       if (__builtin_setjmp(memscan_jmpbuf) == 0) {
         if ((*lc_is_valid_aligned_word)(ptr)) {
+            lc_scanned += sizeof(Addr);
            addr = *(Addr *)ptr;
-           _lc_markstack_push(addr, clique);
+           lc_markstack_push_WRK(addr, clique);
         } else if (0 && VG_DEBUG_LEAKCHECK)
            VG_(printf)("%p not valid\n", ptr);
         ptr += sizeof(Addr);
@@ -436,7 +479,7 @@ static void _lc_scan_memory(Addr start, SizeT len, Int clique)
 
 static void lc_scan_memory(Addr start, SizeT len)
 {
-   _lc_scan_memory(start, len, -1);
+   lc_scan_memory_WRK(start, len, -1);
 }
 
 /* Process the mark stack until empty.  If mopup is true, then we're
@@ -450,7 +493,7 @@ static void lc_do_leakcheck(Int clique)
       tl_assert(top >= 0 && top < lc_n_shadows);      
       tl_assert(lc_markstack[top].state != Unreached);
 
-      _lc_scan_memory(lc_shadows[top]->data, lc_shadows[top]->size, clique);
+      lc_scan_memory_WRK(lc_shadows[top]->data, lc_shadows[top]->size, clique);
    }
 }
 
@@ -487,7 +530,7 @@ static void full_report(ThreadId tid)
       if (VG_DEBUG_CLIQUE)
         VG_(printf)("%d: gathering clique %p\n", i, lc_shadows[i]->data);
       
-      _lc_markstack_push(lc_shadows[i]->data, i);
+      lc_markstack_push_WRK(lc_shadows[i]->data, i);
 
       lc_do_leakcheck(i);
 
@@ -692,8 +735,36 @@ void MAC_(do_detect_memory_leaks) (
 
    lc_scanned = 0;
 
-   /* Do the scan of memory, pushing any pointers onto the mark stack */
-   VG_(find_root_memory)(lc_scan_memory);
+   /* Push roots onto the mark stack.  Roots are:
+      - the integer registers of all threads
+      - all mappings belonging to the client, including stacks
+      - .. but excluding any client heap segments.
+      Client heap segments are excluded because we wish to differentiate
+      client heap blocks which are referenced only from inside the heap
+      from those outside.  This facilitates the indirect vs direct loss
+      categorisation, which [if the users ever manage to understand it]
+      is really useful for detecting lost cycles.
+   */
+   { NSegment* seg;
+     Addr*     seg_starts;
+     Int       n_seg_starts;
+     seg_starts = get_seg_starts( &n_seg_starts );
+     tl_assert(seg_starts && n_seg_starts > 0);
+     /* VG_(am_show_nsegments)( 0,"leakcheck"); */
+     for (i = 0; i < n_seg_starts; i++) {
+        seg = VG_(am_find_nsegment)( seg_starts[i] );
+        tl_assert(seg);
+        if (seg->kind != SkFileC && seg->kind != SkAnonC) 
+           continue;
+        if (!(seg->hasR && seg->hasW))
+           continue;
+        if (seg->isCH)
+           continue;
+        if (0)
+           VG_(printf)("ACCEPT %2d  %p %p\n", i, seg->start, seg->end);
+        lc_scan_memory(seg->start, seg->end+1 - seg->start);
+     }
+   }
 
    /* Push registers onto mark stack */
    VG_(apply_to_GP_regs)(lc_markstack_push);
index db7e43882a917e347bc8754d5016a72f2f69c413..afe2493edc4bd242de971af97319342ab507b9b8 100644 (file)
@@ -190,7 +190,10 @@ static SecMap* copy_for_writing ( SecMap* dist_sm )
              || dist_sm == &sm_distinguished[1]
             || dist_sm == &sm_distinguished[2]);
 
-   new_sm = VG_(shadow_alloc)(sizeof(SecMap));
+   new_sm = VG_(am_shadow_alloc)(sizeof(SecMap));
+   if (new_sm == NULL)
+      VG_(out_of_memory_NORETURN)( "memcheck:allocate new SecMap", 
+                                   sizeof(SecMap) );
    VG_(memcpy)(new_sm, dist_sm, sizeof(SecMap));
    n_secmaps_issued++;
    return new_sm;
@@ -738,20 +741,34 @@ static void mc_make_readable ( Addr a, SizeT len )
 }
 
 
-/* --- Block-copy permissions (needed for implementing realloc()). --- */
+/* --- Block-copy permissions (needed for implementing realloc() and
+       sys_mremap). --- */
 
 static void mc_copy_address_range_state ( Addr src, Addr dst, SizeT len )
 {
-   SizeT i;
+   SizeT i, j;
    UWord abit, vbyte;
 
    DEBUG("mc_copy_address_range_state\n");
-
    PROF_EVENT(50, "mc_copy_address_range_state");
-   for (i = 0; i < len; i++) {
-      PROF_EVENT(51, "mc_copy_address_range_state(loop)");
-      get_abit_and_vbyte( &abit, &vbyte, src+i );
-      set_abit_and_vbyte( dst+i, abit, vbyte );
+
+   if (len == 0)
+      return;
+
+   if (src < dst) {
+      for (i = 0, j = len-1; i < len; i++, j--) {
+         PROF_EVENT(51, "mc_copy_address_range_state(loop)");
+         get_abit_and_vbyte( &abit, &vbyte, src+j );
+         set_abit_and_vbyte( dst+j, abit, vbyte );
+      }
+   }
+
+   if (src > dst) {
+      for (i = 0; i < len; i++) {
+         PROF_EVENT(51, "mc_copy_address_range_state(loop)");
+         get_abit_and_vbyte( &abit, &vbyte, src+i );
+         set_abit_and_vbyte( dst+i, abit, vbyte );
+      }
    }
 }
 
@@ -1187,12 +1204,15 @@ void mc_check_is_readable ( CorePart part, ThreadId tid, Char* s,
 
    VGP_PUSHCC(VgpCheckMem);
    
-   /* VG_(message)(Vg_DebugMsg,"check is readable: %x .. %x",
-                               base,base+size-1); */
    res = mc_check_readable ( base, size, &bad_addr );
+
+   if (0)
+      VG_(printf)("mc_check_is_readable(0x%x, %d, %s) -> %s\n",
+                  (UInt)base, (Int)size, s, res==MC_Ok ? "yes" : "no" );
+
    if (MC_Ok != res) {
       Bool isUnaddr = ( MC_AddrErr == res ? True : False );
-      
+
       switch (part) {
       case Vg_CoreSysCall:
          MAC_(record_param_error) ( tid, bad_addr, /*isReg*/False,
@@ -2636,7 +2656,7 @@ static void mc_pre_clo_init(void)
    tl_assert( mc_expensive_sanity_check() );
 }
 
-VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init, 9./8)
+VG_DETERMINE_INTERFACE_VERSION(mc_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                mc_main.c ---*/
index 7a01b45695239e32c772fc33714e820a784e79a8..ba7c16c2be6c498cf56b6f0559caf69839d59cce 100644 (file)
@@ -93,6 +93,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        zeropage.stderr.exp zeropage.stderr.exp2 zeropage.stdout.exp \
        zeropage.vgtest
 
+# vgtest_ume is not working
 check_PROGRAMS = \
        addressable \
        badaddrvalue badfree badjump badjump2 \
@@ -115,7 +116,7 @@ check_PROGRAMS = \
        stack_changes strchr str_tester supp_unknown supp1 supp2 suppfree \
        trivialleak weirdioctl  \
        mismatches new_override metadata \
-       vgtest_ume xml1 \
+       xml1 \
        writev zeropage
 
 
@@ -139,19 +140,11 @@ new_nothrow_SOURCES       = new_nothrow.cpp
 new_override_SOURCES   = new_override.cpp
 
 # Valgrind unit self-tests
-## If we support PIE, build hello as a PIE, otherwise vgtest_ume cannot load
-## (I'm not completely sure why, since stage2 can load both PIEs and non-PIEs,
-## maybe it's because stage2 is loaded up high;  anyway, it doesn't really
-## matter so long as vgtest_ume can load hello ok.  --njn)
-if USE_PIE
-hello_CFLAGS           = $(AM_CFLAGS) -fpie
-hello_LDFLAGS          = -pie
-else
-hello_LDFLAGS          = -Wl,-defsym,kickstart_base=0x50000000 \
-                         -Wl,-T,../../coregrind/stage2.lds
-hello_DEPENDENCIES     = ../../coregrind/stage2.lds
-endif
+hello_LDFLAGS          = -Wl,-defsym,valt_load_address=0x50000000 \
+                         -Wl,-T,$(top_builddir)/valt_load_address.lds
+hello_DEPENDENCIES     = $(top_builddir)/valt_load_address.lds
 
-vgtest_ume_CFLAGS      = -DVGA_$(VG_ARCH) -DVGO_$(VG_OS)
-vgtest_ume_LDADD       = ../../coregrind/m_ume.o
+# vgtest_ume is not working
+#vgtest_ume_CFLAGS     = -DVGA_$(VG_ARCH) -DVGO_$(VG_OS)
+#vgtest_ume_LDADD      = ../../coregrind/m_ume.o
 
index c3eae2c2faa59af46befb77f0f37653c3d08fe0c..07475d38c6df9616c2ce3eebba8e0c69ab752550 100644 (file)
@@ -1,9 +1,9 @@
 #include <assert.h>
 #include <unistd.h>
 
-int main(void)
+int main ( int argc, char** argv, char** envp )
 {
    execve(NULL,        NULL, NULL);
-   execve("../../tests/true", NULL, NULL);
+   execve("../../tests/true", NULL, envp);
    assert(0);  // shouldn't get here
 }
index 7044671e72fe4f68d96bf27800c177729e5de9d6..13ce0e13aa4630b1bf4c3ab0ab87ebc9458d613a 100755 (executable)
@@ -8,6 +8,7 @@ sed "s/<obj>.*<\/obj>/<obj>...<\/obj>/" |
 sed "s/<line>.*<\/line>/<line>...<\/line>/" |
 sed "s/<dir>.*<\/dir>/<dir>...<\/dir>/" |
 sed "s/<count>.*<\/count>/<count>...<\/count>/" |
+sed "s/\(m_replacemalloc\/\)\?vg_replace_malloc.c/vg_replace_malloc.c/" |
 perl -0 -p -e "s/<suppcounts>.*<\/suppcounts>/<suppcounts>...<\/suppcounts>/s" |
 perl    -p -e "s/<time>.*<\/time>/<time>...<\/time>/s" |
 perl -0 -p -e "s/<vargv>.*<\/vargv>/<vargv>...<\/vargv>/s"
index a310f0926883fcfa8f564913b9de631916d2ac74..0dcee7b55bd11ec1a98f1a965e20d2a5254c4e8a 100644 (file)
@@ -101,7 +101,6 @@ static void test__do_exec(void)
    info.argv     = NULL;
    info.exe_base = 0x50000000;
    info.exe_end  = 0x50ffffff;
-   info.map_base = 0x51000000;
    
    fprintf(stderr, "Calling VG_(do_exec)(\"hello\")\n");
    err = VG_(do_exec)("hello", &info);
index badeffc7ff318f243e4f9e36a01f37d35bfeaf07..4a527e7cd25187f0c00909a49dfc16ca35dfd277 100644 (file)
@@ -800,7 +800,11 @@ Syscall param sigaction(oldact) contains uninitialised byte(s)
    by 0x........: __libc_start_main (in /...libc...)
    by 0x........: ...
 
+<<<<<<< .working
 Syscall param sigaction(act->sa_handler) points to unaddressable byte(s)
+=======
+Syscall param rt_sigaction(act->sa_handler) points to unaddressable byte(s)
+>>>>>>> .merge-right.r4787
    at 0x........: syscall (in /...libc...)
    by 0x........: __libc_start_main (in /...libc...)
    by 0x........: ...
@@ -808,6 +812,7 @@ Syscall param sigaction(act->sa_handler) points to unaddressable byte(s)
    at 0x........: malloc (vg_replace_malloc.c:...)
    by 0x........: main (scalar.c:24)
 
+<<<<<<< .working
 Syscall param sigaction(act->sa_mask) points to unaddressable byte(s)
    at 0x........: syscall (in /...libc...)
    by 0x........: __libc_start_main (in /...libc...)
@@ -824,6 +829,24 @@ Syscall param sigaction(act->sa_flags) points to unaddressable byte(s)
    at 0x........: malloc (vg_replace_malloc.c:...)
    by 0x........: main (scalar.c:24)
 
+=======
+Syscall param rt_sigaction(act->sa_mask) points to unaddressable byte(s)
+   at 0x........: syscall (in /...libc...)
+   by 0x........: __libc_start_main (in /...libc...)
+   by 0x........: ...
+ Address 0x........ is 4 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (scalar.c:24)
+
+Syscall param rt_sigaction(act->sa_flags) points to unaddressable byte(s)
+   at 0x........: syscall (in /...libc...)
+   by 0x........: __libc_start_main (in /...libc...)
+   by 0x........: ...
+ Address 0x........ is 8 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (scalar.c:24)
+
+>>>>>>> .merge-right.r4787
 Syscall param sigaction(oldact) points to unaddressable byte(s)
    at 0x........: syscall (in /...libc...)
    by 0x........: __libc_start_main (in /...libc...)
@@ -2416,6 +2439,7 @@ Syscall param rt_sigaction(sigsetsize) contains uninitialised byte(s)
    by 0x........: __libc_start_main (in /...libc...)
    by 0x........: ...
 
+<<<<<<< .working
 Syscall param rt_sigaction(act->sa_handler) points to unaddressable byte(s)
    at 0x........: syscall (in /...libc...)
    by 0x........: __libc_start_main (in /...libc...)
@@ -2430,6 +2454,8 @@ Syscall param rt_sigaction(act->sa_mask) points to unaddressable byte(s)
    by 0x........: ...
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
+=======
+>>>>>>> .merge-right.r4787
 Syscall param rt_sigaction(act->sa_flags) points to unaddressable byte(s)
    at 0x........: syscall (in /...libc...)
    by 0x........: __libc_start_main (in /...libc...)
index ee3c16d8fcf3432b7f9e17889b8ea1dae9d3e9e5..34d6b4cdd6d0137e42214e25af5ac08f92d806e1 100644 (file)
@@ -1,7 +1,8 @@
 include $(top_srcdir)/Makefile.tool.am
 
-val_PROGRAMS = vgtool_none.so
-
-vgtool_none_so_SOURCES          = nl_main.c
-vgtool_none_so_LDFLAGS   = -shared
+val_PROGRAMS = none
 
+none_SOURCES      = nl_main.c
+none_DEPENDENCIES = $(COREGRIND_LIBS)
+none_LDADD        = $(TOOL_LINKADD)
+none_LDFLAGS      = $(TOOL_LINKFLAGS)
index 04f304f5dedf5cc0ca8620938e7885d52dc02dd6..3a5e57e897e92b0e7a8611db769d292ceede3b01 100644 (file)
@@ -62,7 +62,7 @@ static void nl_pre_clo_init(void)
    /* No needs, no core events to track */
 }
 
-VG_DETERMINE_INTERFACE_VERSION(nl_pre_clo_init, 0)
+VG_DETERMINE_INTERFACE_VERSION(nl_pre_clo_init)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
index 77b5dad92c43d7ad627969530a342f543f70c2ac..480220b2ef171dfbc75211a1b8619fb1f5193899 100644 (file)
@@ -56,6 +56,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        map_unmap.stderr.exp map_unmap.stdout.exp map_unmap.vgtest \
        mq.stderr.exp mq.vgtest \
        mremap.stderr.exp mremap.stdout.exp mremap.vgtest \
+       mremap2.stderr.exp mremap2.stdout.exp mremap2.vgtest \
        munmap_exe.stderr.exp munmap_exe.vgtest \
        nestedfns.stderr.exp nestedfns.stdout.exp nestedfns.vgtest \
        pending.stdout.exp pending.stderr.exp pending.vgtest \
@@ -107,7 +108,7 @@ check_PROGRAMS = \
        fdleak_fcntl fdleak_ipv4 fdleak_open fdleak_pipe \
        fdleak_socketpair \
        floored fork fucomip manythreads \
-       munmap_exe map_unaligned map_unmap mq mremap \
+       munmap_exe map_unaligned map_unmap mq mremap mremap2 \
        nestedfns \
        pending \
        pth_atfork1 pth_blockedsig pth_cancel1 pth_cancel2 pth_cvsimple \
index 2ec923ab785bca665efc355d7dfda661c15bce54..9a587e809f15c99229edeee969b3150d3cda51c8 100644 (file)
@@ -3,9 +3,7 @@
 2
 3
 4
-Warning: client syscall mmap2 tried to modify addresses 0x........-0x........
 mmap @ top
 5
-Warning: client syscall mmap2 tried to modify addresses 0x........-0x........
 mmap @ top+.5G
 
index 4d0f1b4cc3fbc7d2c7b13a890736251d914327fb..fe2a5d3115c9dc00cf6d8af025a17baa0dfabcb3 100644 (file)
@@ -1,4 +1,3 @@
 
-Warning: client syscall shmat tried to modify addresses 0x........-0x........
-shmat @ top: Invalid argument
+shmat @ top: Cannot allocate memory
 
index 695d91d9a12f7ed93c0b49f86b794a8acf22411e..7bf97904f9473b08934bd41c5862f87c384e0b4e 100644 (file)
@@ -56,7 +56,7 @@ int main()
        munmap(expect1, LEN);
        munmap(expect2, LEN);
 
-       for(i = 0; i < 100; i++) {
+       for(i = 0; i < 5; i++) {
                void *m1, *m2;
 
                m1 = domap();
diff --git a/none/tests/mremap2.c b/none/tests/mremap2.c
new file mode 100644 (file)
index 0000000..a27cc37
--- /dev/null
@@ -0,0 +1,163 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <syscall.h>
+
+
+#ifndef REMAP_FIXED
+#define MREMAP_FIXED 2
+#endif
+
+
+static int PAGE;
+
+void mapanon_fixed ( void* start, size_t length )
+{
+  void* r = mmap(start, length, PROT_NONE, 
+                 MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, 0,0);
+  assert(r != MAP_FAILED);
+  assert(r == start);
+}
+
+void unmap_and_check ( void* start, size_t length )
+{
+   int r = munmap( start, length );
+   assert(r == 0);
+}
+
+char* workingarea = NULL;
+char* try_dst     = NULL;
+
+// set up working area so expansion limit is 20*PAGE
+//
+//   |   10   |   20   |   10   |   60   |
+//   |  pre   |  src   |  FREE  |  post  |
+//
+//  A suitable attempted fixed dst is workingarea + 150*PAGE.
+
+char* setup ( void* other_stuff, int other_len )
+{
+  if (!workingarea) {
+     workingarea = mmap(0, 200*PAGE, PROT_NONE, 
+                           MAP_ANONYMOUS|MAP_PRIVATE, 0,0);
+     assert(workingarea);
+     try_dst = workingarea + 150*PAGE;
+     unmap_and_check(workingarea, 200*PAGE);
+  }
+
+  if (other_stuff) {
+    unmap_and_check(other_stuff, other_len);
+  }
+
+  // get rid of the old working area
+  unmap_and_check( workingarea, 200*PAGE);
+
+  // pre block
+  mapanon_fixed( workingarea + 0*PAGE, 9*PAGE);
+
+  // the area
+  mapanon_fixed( workingarea + 10*PAGE, 20*PAGE );
+
+  // upper half
+  mapanon_fixed( workingarea + 40*PAGE, 60*PAGE );
+
+  return workingarea + 10*PAGE;
+}
+
+/* show the working area */
+void show ( void )
+{
+  int i,r;
+  for (i = 0; i < 200; i++) {
+    r = mprotect( workingarea + i * PAGE, PAGE, PROT_NONE );
+    printf("%c", r == 0 ? 'X' : '.');
+    if (i == 49 || i == 99 || i == 149) printf("\n");
+  }
+  printf("\n");
+}
+
+
+char* dst = NULL;
+char* src = NULL;
+char* dst_impossible = NULL;
+
+
+char* identify ( char* p )
+{
+  if (p == dst)            return "dst";
+  if (p == src)            return "src";
+  if (p == dst_impossible) return "dst_imp!";
+  if (p == try_dst)        return "dst_poss";
+  return "other";
+}
+
+int main ( void )
+{
+  int alocal, maymove, fixed, nsi, dstpossible;
+  dst_impossible = (char*)(&alocal) + 500 * 1000 * 1000;
+  int newsizes[6] = { 19, 20, 21, 29, 30, 31 };
+
+  char* tidythis = NULL;
+  int  tidylen = 0;
+  int firsttime = 1;
+  char buf[100];
+
+  PAGE = sysconf(_SC_PAGESIZE);
+
+  for (maymove = 0; maymove <= 1 ; maymove++) {
+  for (fixed = 0; fixed <= 1; fixed++) {
+    printf("\n");
+  for (nsi = 0; nsi < 6; nsi++) {
+  for (dstpossible = 0; dstpossible <= 1; dstpossible++) {
+
+    int newsize = newsizes[nsi] * PAGE;
+    int flags = (maymove ? MREMAP_MAYMOVE : 0)  |
+                (fixed ? MREMAP_FIXED : 0);
+    dst = dstpossible ? try_dst : dst_impossible;
+    src = setup( tidythis, tidylen );
+
+    char* r;
+
+    if (firsttime) {
+       printf("dst_possible   = %p\n", try_dst );
+       printf("dst_impossible = %p\n", dst_impossible );
+       printf("           src = %p\n", src);
+       printf("\n");
+       sprintf(buf, "cat /proc/%d/maps", getpid());
+       if (0) system(buf);
+       firsttime = 0;
+    }
+
+    printf("maymv %d   fixed %d   newsz %2d   dstpo %d  dst %p ->  ",
+          maymove, fixed, newsizes[nsi], dstpossible, dst );
+    r = (char*)
+        syscall(__NR_mremap, src, 20*PAGE, newsize, flags, dst, 0 );
+    if (r == MAP_FAILED)
+      printf("error %d\n", errno);
+    else
+      printf("%p (== %s)\n", r, identify(r));
+
+    if (1) {
+       show();
+       printf("\n");
+    }
+
+    if (r != MAP_FAILED) {
+      if (r != src && r != try_dst && r != dst_impossible) {
+       tidythis = r;
+       tidylen = newsize;
+      }
+    }
+
+  }
+  }
+  }
+  }
+  return 0;
+}
diff --git a/none/tests/mremap2.stderr.exp b/none/tests/mremap2.stderr.exp
new file mode 100644 (file)
index 0000000..139597f
--- /dev/null
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/mremap2.stdout.exp b/none/tests/mremap2.stdout.exp
new file mode 100644 (file)
index 0000000..229a710
--- /dev/null
@@ -0,0 +1,296 @@
+
+dst_possible   = 0x........
+dst_impossible = 0x........
+           src = 0x........
+
+maymv 0   fixed 0   newsz 19   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXX...........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 19   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXX...........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 20   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 20   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 21   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXX.........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 21   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXX.........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 29   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 29   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 30   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 30   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 31   dstpo 0  dst 0x........ ->  error 12
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 0   newsz 31   dstpo 1  dst 0x........ ->  error 12
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+
+maymv 0   fixed 1   newsz 19   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 19   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 20   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 20   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 21   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 21   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 29   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 29   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 30   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 30   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 31   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 0   fixed 1   newsz 31   dstpo 1  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+
+maymv 1   fixed 0   newsz 19   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXX...........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 19   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXX...........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 20   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 20   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 21   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXX.........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 21   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXX.........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 29   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 29   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 30   dstpo 0  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 30   dstpo 1  dst 0x........ ->  0x........ (== src)
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 0   newsz 31   dstpo 0  dst 0x........ ->  0x........ (== other)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...................
+..................................................
+
+maymv 1   fixed 0   newsz 31   dstpo 1  dst 0x........ ->  0x........ (== other)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...................
+..................................................
+
+
+maymv 1   fixed 1   newsz 19   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 19   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXX...............................
+
+maymv 1   fixed 1   newsz 20   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 20   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXXX..............................
+
+maymv 1   fixed 1   newsz 21   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 21   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXXXX.............................
+
+maymv 1   fixed 1   newsz 29   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 29   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXX.....................
+
+maymv 1   fixed 1   newsz 30   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 30   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX....................
+
+maymv 1   fixed 1   newsz 31   dstpo 0  dst 0x........ ->  error 22
+XXXXXXXXX.XXXXXXXXXXXXXXXXXXXX..........XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+..................................................
+
+maymv 1   fixed 1   newsz 31   dstpo 1  dst 0x........ ->  0x........ (== dst)
+XXXXXXXXX...............................XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+..................................................
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...................
+
diff --git a/none/tests/mremap2.vgtest b/none/tests/mremap2.vgtest
new file mode 100644 (file)
index 0000000..9120adc
--- /dev/null
@@ -0,0 +1,2 @@
+prog: mremap2
+stdout_filter: ../../tests/filter_addresses
index ba32aeff8fbd0c0af6bf9c8bb2dafa03144dec69..a437948180889192e5b64af4c23572a246bbbafc 100755 (executable)
@@ -19,8 +19,8 @@ sed "/^Using LibVEX rev .*, a library for dynamic binary translation/ , /./ d" |
 sed "/Estimated CPU clock rate is [0-9]* MHz/d"                       |
 sed "/For more details, rerun with: -v/d"                             |
 
-# Anonymise line numbers in vg_replace_malloc.c
-sed "s/vg_replace_malloc.c:[0-9]*/vg_replace_malloc.c:.../"           |
+# Anonymise line numbers in vg_replace_malloc.c, remove dirname if present
+sed "s/\(m_replacemalloc\/\)\?vg_replace_malloc.c:[0-9]*/vg_replace_malloc.c:.../"           |
 
 # Anonymise vg_intercept lines
 #sed "s/vg_intercept.c:[0-9]*/vg_intercept.c:.../"                     |
index 9ba1f90f241359fab771d3a960dafc15f5c9cb7d..661b5f25206a60bc735970534a9876d6bfe561f8 100755 (executable)
@@ -280,7 +280,7 @@ sub do_one_test($$)
     # Pass the appropriate --tool option for the directory (can be overridden
     # by an "args:" line, though).  
     my $tool=determine_tool();
-    mysystem("VALGRINDLIB=$tests_dir/.in_place $valgrind --command-line-only=yes --memcheck:leak-check=no --addrcheck:leak-check=no --tool=$tool $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
+    mysystem("VALGRIND_LIB=$tests_dir/.in_place $valgrind --command-line-only=yes --memcheck:leak-check=no --addrcheck:leak-check=no --tool=$tool $vgopts $prog $args > $name.stdout.out 2> $name.stderr.out");
 
     if (defined $stdout_filter) {
         mysystem("$stdout_filter < $name.stdout.out > $tmp");