This commit merges in changes from branches/ASPACEM (specifically,
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 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 9bd8a33..f03e96f 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -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 @@
 	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 @@
 	vki_unistd.h		\
 	vki_unistd-amd64-linux.h\
 	vki_unistd-ppc32-linux.h\
-	vki_unistd-x86-linux.h
+	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 = stage2.lds
-CLEANFILES = stage2.lds
+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 @@
 	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 @@
 	m_trampoline.S \
 	m_translate.c \
 	m_transtab.c \
-	m_ume.c
+	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
 
-## 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
+libreplacemalloc_toolpreload_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_a_CFLAGS = $(PIC_AM_CFLAGS)
 
-## 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
+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
 
-## 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)
+libvex_guest_offsets.h:
+	$(MAKE) -C @VEX_DIR@ pub/libvex_guest_offsets.h
 
-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 = \
+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
index 0da1180..0000000
--- a/coregrind/m_aspacemgr/Makefile.am
+++ /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
diff --git a/coregrind/m_aspacemgr/aspacemgr.c b/coregrind/m_aspacemgr/aspacemgr.c
index 46a8a64..97ac760 100644
--- a/coregrind/m_aspacemgr/aspacemgr.c
+++ b/coregrind/m_aspacemgr/aspacemgr.c
@@ -30,92 +30,36 @@
    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
+
+#include "pub_core_debuglog.h"   // VG_(debugLog)
+
+#include "pub_core_libcbase.h"   // VG_(strlen), VG_(strcmp)
+                                 // VG_IS_PAGE_ALIGNED
+                                 // VG_PGROUNDDN, VG_PGROUNDUP
+
+#include "pub_core_syscall.h"    // VG_(do_syscallN)
+                                 // VG_(mk_SysRes_Error)
+                                 // VG_(mk_SysRes_Success)
+
+#include "pub_core_options.h"    // VG_(clo_sanity_level)
+
+#include "vki_unistd.h"          // __NR_* constants
+
+#include "pub_core_aspacemgr.h"  // self
 
 
-/* Define to debug the memory-leak-detector. */
-/* #define VG_DEBUG_LEAKCHECK */
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- The Address Space Manager's state.                        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
 
-static const Bool mem_debug = False;
-
-/*--------------------------------------------------------------*/
-/*--- Basic globals about the address space.                 ---*/
-/*--------------------------------------------------------------*/
-
-/* 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);
-
-Addr VG_(brk_base);	         /* start of brk */
-Addr VG_(brk_limit);	         /* current brk */
-
-Addr VG_(shadow_base);	         /* tool's shadow memory */
-Addr VG_(shadow_end);
-
-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 raw mman syscalls                                  ---*/
-/*--------------------------------------------------------------*/
-
-SysRes VG_(mmap_native)(void *start, SizeT length, UInt prot, UInt flags,
-                        UInt fd, OffT offset)
-{
-   SysRes res;
-#if defined(VGP_x86_linux)
-   { 
-      UWord args[6];
-      args[0] = (UWord)start;
-      args[1] = length;
-      args[2] = prot;
-      args[3] = flags;
-      args[4] = fd;
-      args[5] = offset;
-      res = VG_(do_syscall1)(__NR_mmap, (UWord)args );
-   }
-#elif defined(VGP_amd64_linux)
-   res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, 
-                         prot, flags, fd, offset);
-#elif defined(VGP_ppc32_linux)
-   res = VG_(do_syscall6)(__NR_mmap, (UWord)(start), (length),
-			  prot, flags, fd, offset);
-#else
-#  error Unknown platform
-#endif
-   return res;
-}
-
-SysRes VG_(munmap_native)(void *start, SizeT length)
-{
-   return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
-}
-
-SysRes VG_(mprotect_native)( void *start, SizeT length, UInt prot )
-{
-   return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
-}
-
-/*--------------------------------------------------------------*/
-/*--- A simple, self-contained ordered array of segments.    ---*/
-/*--------------------------------------------------------------*/
+/* ------ start of STATE for the address-space manager ------ */
 
 /* Max number of segments we can track. */
 #define VG_N_SEGMENTS 2000
@@ -127,17 +71,6 @@
 #define VG_MAX_SEGNAMELEN 1000
 
 
-/* ------ STATE for the address-space manager ------ */
-
-/* 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;
-
 typedef
    struct {
       Bool  inUse;
@@ -154,8 +87,269 @@
 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)
+   { 
+      UWord args[6];
+      args[0] = (UWord)start;
+      args[1] = length;
+      args[2] = prot;
+      args[3] = flags;
+      args[4] = fd;
+      args[5] = offset;
+      res = VG_(do_syscall1)(__NR_mmap, (UWord)args );
+   }
+#  elif defined(VGP_amd64_linux)
+   res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, 
+                         prot, flags, fd, offset);
+#  elif defined(VGP_ppc32_linux)
+   res = VG_(do_syscall6)(__NR_mmap, (UWord)(start), (length),
+                          prot, flags, fd, offset);
+#  else
+#    error Unknown platform
+#  endif
+   return res;
+}
+
+static SysRes do_mprotect_NO_NOTIFY(Addr start, SizeT length, UInt prot)
+{
+   return VG_(do_syscall3)(__NR_mprotect, (UWord)start, length, prot );
+}
+
+static SysRes do_munmap_NO_NOTIFY(Addr start, SizeT length)
+{
+   return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
+}
+
+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*/
+          );
+}
+
+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
+          );
+}
+
+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;
+}
+
+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);
+}
+
+
+//--------------------------------------------------------------
+// Functions for extracting information about file descriptors.
+
+/* 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;
+   }
+   return False;
+}
+
+/* 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;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- 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 @@
 {
    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 @@
          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,343 +397,407 @@
    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.
 */
-static inline Int compare_addr_with_seg ( Addr a, Segment* seg )
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Displaying the segment array.                             ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+static HChar* show_SegKind ( SegKind sk )
 {
-   if (a < seg->addr) 
-      return -1;
-   if (a >= seg->addr + seg->len) 
-      return 1;
-   return 0;
+   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);
 }
 
 
-/* Find the (index of the) segment that contains 'a', or -1 if
-   none. 
-*/
-static Int find_segment ( Addr 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;
-   for (i = 0; i < segments_used; i++) {
-      if (compare_addr_with_seg(a, &segments[i]) == 0)
-         return i;
-   }
-   return -1;
-}
-
-
-/* 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)
-         continue;
-      vg_assert(r == -1);
-      break;
-   }
-
-   if (i == segments_used)
-      return -1; /* not found */
-   else
-      return i;
-}
-
-
-/* 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*/
-   }
-
-   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);
-   }
-   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);
-
-/* 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];
-   }
-   segments_used--;
-   vg_assert(segments_used >= 0 && segments_used < VG_N_SEGMENTS);
-}
-
-
-/* Fill the i'th record all with zeroes. */
-static void zeroise_segment ( Int i )
-{
-   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;
-}
-
-
-/* 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;
-}
-
-
-/* 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 )
-{
-   Int i;
-   VG_(printf)("<<< SHOW_SEGMENTS: %s (%d segments, %d segnames)\n", 
-               who, segments_used, segnames_used);
+   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_(printf)("(%2d) %s\n", i, segnames[i].fname);
+      VG_(debugLog)(logLevel, "aspacem",
+                    "(%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);
-   }
-   VG_(printf)(">>>\n");
+   for (i = 0; i < nsegments_used; i++)
+     show_nsegment( logLevel, i, &nsegments[i] );
+   VG_(debugLog)(logLevel, "aspacem",
+                 ">>>\n");
 }
 
 
-/* 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.
-
-   If 'a' is not found, or if no splitting happens, -1 is returned.
-
-   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 )
+/* 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 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;
+   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];
+}
 
-   /* 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;
+/* 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;
 }
 
 
-/* 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)
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Sanity checking and preening of the segment array.        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* Check representational invariants for NSegments. */
+
+static Bool sane_NSegment ( NSegment* s )
 {
-   if (s1->addr+s1->len != s2->addr)
-      return False;
+   if (s == NULL) return False;
 
-   if (s1->flags != s2->flags)
-      return False;
+   /* No zero sized segments and no wraparounds. */
+   if (s->start >= s->end) return False;
 
-   if (s1->prot != s2->prot)
-      return False;
+   /* .mark is used for admin purposes only. */
+   if (s->mark) return False;
 
-   if (s1->seginfo != s2->seginfo)
-      return False;
+   /* require page alignment */
+   if (!VG_IS_PAGE_ALIGNED(s->start)) return False;
+   if (!VG_IS_PAGE_ALIGNED(s->end+1)) return False;
 
-   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)
+   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;
    }
-   
-   return True;
 }
 
 
-/* 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 )
+/* 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 )
 {
-   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);
+   if (s1->kind != s2->kind) 
+      return False;
 
-   if (0) VG_(show_segments)("before preen");
+   if (s1->end+1 != s2->start)
+      return False;
 
-   /* clear string table mark bits */
+   /* 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;
-
-   /* 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);
+   /* mark */
+   for (i = 0; i < nsegments_used; i++) {
+     j = nsegments[i].fnIdx;
+      aspacem_assert(j >= -1 && j < segnames_used);
       if (j >= 0) {
-         vg_assert(segnames[j].inUse);
+         aspacem_assert(segnames[j].inUse);
          segnames[j].mark = True;
       }
    }
-
-   /* 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);
-   }
-
-   /* 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++;
-   }
-   vg_assert(wr >= 0 && wr <= segments_used);
-   segments_used = wr;
-
-   /* Free up any strings which are no longer referenced. */
+   /* release */
    for (i = 0; i < segnames_used; i++) {
       if (segnames[i].mark == False) {
          segnames[i].inUse = False;
@@ -556,770 +805,1907 @@
       }
    }
 
-   if (0) VG_(show_segments)("after preen");
+   return nsegments_used != nsegments_used_old;
 }
 
 
-/*--------------------------------------------------------------*/
-/*--- Maintain an ordered list of all the client's mappings  ---*/
-/*--------------------------------------------------------------*/
+/* 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. 
 
-Bool VG_(seg_contains)(const Segment *s, Addr p, SizeT len)
+   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 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 )
 {
-   Addr se = s->addr+s->len;
-   Addr pe = p+len;
-   vg_assert(pe >= p);
+   Int iLo, iHi, i;
 
-   return (p >= s->addr && pe <= se);
-}
-
-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);
-}
-
-/* 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)
-{
-   if (s->seginfo != NULL) {
-      VG_(seginfo_decref)(s->seginfo, s->addr);
-      s->seginfo = NULL;
-   }
-}
-
-/* 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 )
-{
-   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);
-   }
-}
-
-
-/* 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)
-{
-   const Bool debug = False || mem_debug;
-   Segment* s;
-   Addr     end, s_end;
-   Int      i;
-   Bool     deleted;
+   /* 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;
 
-   len = VG_PGROUNDUP(len);
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
 
-   if (debug)
-      VG_(printf)("unmap_range(%p, %llu)\n", addr, (ULong)len);
-   if (0) VG_(show_segments)("unmap_range(BEFORE)");
-   end = addr+len;
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
 
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(addr));
-   vg_assert(VG_IS_PAGE_ALIGNED(len));
+   /* 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 );
 
-   for (i = 0; i < segments_used; i++) {
+   /* NSegments iLo .. iHi inclusive should agree with the presented
+      data. */
+   for (i = iLo; i <= iHi; i++) {
 
-      /* do not delete .. even though it looks stupid */
-      vg_assert(i >= 0);
-
-      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);
-
-      if (!VG_(seg_overlaps)(s, addr, len)) {
-	 if (0 && debug)
-	    VG_(printf)("   (no overlap)\n");
-	 continue;
-      }
-
-      /* 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 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--;
-   }
-   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;
+      Bool same, cmp_offsets, cmp_devino;
    
-   is_stage2 = is_stage2 || ( VG_(strstr)(filename, stage2_suffix1) != NULL );
-   is_stage2 = is_stage2 || ( VG_(strstr)(filename, stage2_suffix2) != NULL );
+      /* compare the kernel's offering against ours. */
+      same = nsegments[i].kind == SkAnonC
+             || nsegments[i].kind == SkAnonV
+             || nsegments[i].kind == SkFileC
+             || nsegments[i].kind == SkFileV;
 
-   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);
+      cmp_offsets
+         = nsegments[i].kind == SkFileC || nsegments[i].kind == SkFileV;
+      cmp_devino
+         = nsegments[i].dev != 0 || nsegments[i].ino != 0;
 
-   if (0) VG_(show_segments)("before map_file_segment");
-
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(addr));
-   len = VG_PGROUNDUP(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);
-            }
-         }
+      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;
       }
    }
 
-   /* clean up */
-   preen_segments();
+   /* 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;
 }
 
-void VG_(map_fd_segment)(Addr addr, SizeT len, UInt prot, UInt flags, 
-			 Int fd, ULong off, const Char *filename)
+static void sync_check_gap_callback ( Addr addr, SizeT len )
 {
-   Char buf[VKI_PATH_MAX];
-   struct vki_stat st;
+   Int iLo, iHi, i;
 
-   st.st_dev = 0;
-   st.st_ino = 0;
+   /* 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 (fd != -1 && (flags & SF_FILE)) {
-      vg_assert((off & (VKI_PAGE_SIZE-1)) == 0);
+   if (len == 0)
+      return;
 
-      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;
-      }
-   }
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
 
-   if ((flags & SF_FILE) && filename == NULL && fd != -1)
-      if (VG_(resolve_filename)(fd, buf, VKI_PATH_MAX))
-         filename = buf;
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
 
-   VG_(map_file_segment)(addr, len, prot, flags, 
-                         st.st_dev, st.st_ino, off, filename);
-}
+   /* 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 );
 
-void VG_(map_segment)(Addr addr, SizeT len, UInt prot, UInt flags)
-{
-   flags &= ~SF_FILE;
+   /* NSegments iLo .. iHi inclusive should agree with the presented
+      data. */
+   for (i = iLo; i <= iHi; i++) {
 
-   VG_(map_file_segment)(addr, len, prot, flags, 0, 0, 0, 0);
-}
-
-/* set new protection flags on an address range */
-void VG_(mprotect_range)(Addr a, SizeT len, UInt prot)
-{
-   Int r;
-   const Bool debug = False || mem_debug;
-
-   if (debug)
-      VG_(printf)("\nmprotect_range(%p, %lu, %x)\n", a, len, prot);
-
-   if (0) VG_(show_segments)( "mprotect_range(before)" );
-
-   /* Everything must be page-aligned */
-   vg_assert(VG_IS_PAGE_ALIGNED(a));
-   len = VG_PGROUNDUP(len);
-
-   split_segment(a);
-   split_segment(a+len);
-
-   r = find_segment(a);
-   vg_assert(r != -1);
-   segments[r].prot = prot;
-
-   preen_segments();
-
-   if (0) VG_(show_segments)( "mprotect_range(after)");
-}
-
-
-/* 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);
-   }
-
-   if (0) VG_(show_segments)("find_map_space: start");
-
-   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;
-   }
-
-   /* Everything must be page-aligned */
-   vg_assert((addr & (VKI_PAGE_SIZE-1)) == 0);
-   len = VG_PGROUNDUP(len);
-
-   len += VKI_PAGE_SIZE * 2; /* leave redzone gaps before and after mapping */
-
-   /* 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;
-
-   hole_start = hole_end = 0;
-
-   /* 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;
-         }
-      }
-
-      vg_assert(hole_start <= hole_end || hole_start == hole_end+1);
-
-      /* ignore zero-sized holes */
-      if (hole_start == hole_end+1)
-         continue;
-
-      vg_assert(VG_IS_PAGE_ALIGNED(hole_start));
-      vg_assert(VG_IS_PAGE_ALIGNED(hole_end+1));
-
-      /* 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));
-
-      if (hole_len >= len && i_any == -1) {
-         /* It will at least fit in this hole. */
-         i_any = i;
-         hstart_any = hole_start;
-      }
-
-      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;
-      }
-   }
-
-   /* Summarise the final decision into i_final/hstart_final. */
-   i_final = -1;
-   hstart_final = 0;
-
-   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;
-   }
-
-
-   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);
-
-   if (fixed) {
-      vg_assert(ret == 0 || ret == addrOrig);
-   }
-
-   return ret;
-}
-
-
-/* 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.
-
-   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;
-
-   Int      i = 0;
-   Segment* s = i >= segments_used ? NULL : &segments[i];
+      Bool same;
    
-   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);
+      /* 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;
       }
-      addr = s->addr + s->len;
-      i++;
-      s = i >= segments_used ? NULL : &segments[i];
    }
 
-   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);
-   }
-}
+   /* Looks harmless.  Keep going. */
+   return;
 
-/* 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;
-
-   Int      i = 0;
-   Segment* s = i >= segments_used ? NULL : &segments[i];
-
-   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 (addr <= VG_(valgrind_last)) {
-      ret = VG_(do_syscall2)(__NR_munmap, addr, 
-                             (VG_(valgrind_last) - addr) + 1);
-   }
-}
-
-/* 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];
-}
-
-/* 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];
-}
-
-/* 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];
+  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;
 }
 
 
-/* 
-   Test if a piece of memory is addressable with at least the "prot"
-   protection permissions by examining the underlying segments.
+/* 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. */
 
-   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_do_sync_check) ( const HChar* fn, 
+                             const HChar* file, Int line )
 {
-   Segment *seg;
-
-   if ((p + size) < p)
-      return False; /* reject wraparounds */
-   if (size == 0)
-      return True; /* isn't this a bit of a strange case? */
-
-   p    = VG_PGROUNDDN(p);
-   size = VG_PGROUNDUP(size);
-   vg_assert(VG_IS_PAGE_ALIGNED(p));
-   vg_assert(VG_IS_PAGE_ALIGNED(size));
-
-   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;
-   }
-
-   return True;
-}
-
-
-/*--------------------------------------------------------------------*/
-/*--- Random function that doesn't really belong here              ---*/
-/*--------------------------------------------------------------------*/
-
-/* 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;
-
-   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;
-
-      (*add_rootrange)(s->addr, s->len);
-   }
-}
-
-
-/*--------------------------------------------------------------------*/
-/*--- Querying memory layout                                       ---*/
-/*--------------------------------------------------------------------*/
-
-Bool VG_(is_client_addr)(Addr a)
-{
-   return a >= VG_(client_base) && a < VG_(client_end);
-}
-
-Bool VG_(is_shadow_addr)(Addr a)
-{
-   return a >= VG_(shadow_base) && a < VG_(shadow_end);
-}
-
-
-/*--------------------------------------------------------------------*/
-/*--- Handling shadow memory                                       ---*/
-/*--------------------------------------------------------------------*/
-
-void *VG_(shadow_alloc)(UInt size)
-{
-   static Addr shadow_alloc = 0;
-   Addr try_here;
-   SysRes r;
-
-   if (0) VG_(show_segments)("shadow_alloc(before)");
-
-   vg_assert(VG_(needs).shadow_memory);
-
-   size = VG_PGROUNDUP(size);
-
-   if (shadow_alloc == 0)
-      shadow_alloc = VG_(shadow_base);
-
-   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);
-
+   sync_check_ok = True;
    if (0)
-      VG_(printf)("shadow_alloc: size %d, trying at %p\n", size, (void*)try_here);
+      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");
 
-   /* 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
+#     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
 
-   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
+   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 )
+{
+   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;
+   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;
+   }
+
+   /* ------ 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;
+      }
+   }
+
+   /* ------ Implement the Default Policy ------ */
+
+   /* 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;
+      }
+
+      holeStart = nsegments[i].start;
+      holeEnd   = nsegments[i].end;
+
+      /* Stay sane .. */
+      aspacem_assert(holeStart <= holeEnd);
+      aspacem_assert(aspacem_minAddr <= holeStart);
+      aspacem_assert(holeEnd <= aspacem_maxAddr);
+
+      /* See if it's any use to us. */
+      holeLen = holeEnd - holeStart + 1;
+
+      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;
+   }
+
+   aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
+   if (fixedIdx >= 0) 
+      aspacem_assert(nsegments[fixedIdx].kind == SkFree);
+
+   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;
+   }
+
+   /*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. */
+
+Addr VG_(am_get_advisory_client_simple) ( Addr start, SizeT len, 
+                                          /*OUT*/Bool* ok )
+{
+   MapRequest mreq;
+   mreq.rkind = start==0 ? MAny : MFixed;
+   mreq.start = start;
+   mreq.len   = len;
+   return VG_(am_get_advisory)( &mreq, True/*client*/, 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. */
+
+Bool
+VG_(am_notify_client_mmap)( Addr a, SizeT len, UInt prot, UInt flags,
+                            Int fd, SizeT offset )
+{
+   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 );
+      }
+   }
+   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;
+
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
+
+   if (len == 0)
+      return False;
+
+   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;
+      }
+   }
+
+   /* Changing permissions could have made previously un-mergable
+      segments mergeable.  Therefore have to re-preen them. */
+   (void)preen_nsegments();
+   AM_SANITY_CHECK;
+   return needDiscard;
+}
+
+
+/* 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 )
+{
+   NSegment seg;
+   Bool     needDiscard;
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
+
+   if (len == 0)
+      return False;
+
+   needDiscard = any_Ts_in_range( start, len );
+
+   init_nsegment( &seg );
+   seg.kind  = SkFree;
+   seg.start = start;
+   seg.end   = start + len - 1;
+   add_segment( &seg );
+
+   /* 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;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Handling mappings which do not arise directly from the    ---*/
+/*--- simulation of the client.                                 ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* --- --- --- map, unmap, protect  --- --- --- */
+
+/* Map a file at a fixed address for the client, and update the
+   segment array accordingly. */
+
+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 );
+   }
+
+   /* 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;
+   }
+   if (get_name_for_fd(fd, buf, VKI_PATH_MAX)) {
+      seg.fnIdx = allocate_segname( buf );
+   }
+   add_segment( &seg );
+
+   AM_SANITY_CHECK;
+   return sres;
+}
+
+
+/* Map anonymously at a fixed address for the client, and update
+   the segment array accordingly. */
+
+SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
+{
+   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 );
+   }
+
+   /* 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;
+}
+
+
+/* Map anonymously at an unconstrained address for the client, and
+   update the segment array accordingly.  */
+
+SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
+{
+   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;
+}
+
+
+/* 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 )
+{
+   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). */
+
+void* VG_(am_shadow_alloc)(SizeT size)
+{
+   SysRes sres = VG_(am_mmap_anon_float_valgrind)( size );
+   return sres.isError ? NULL : (void*)sres.val;
+}
+
+
+
+/* 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.  */
+
+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 );
+   }
+
+   /* 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 );
+
+   AM_SANITY_CHECK;
+   return sres;
+}
+
+
+/* --- --- munmap helper --- --- */
+
+static 
+SysRes am_munmap_both_wrk ( /*OUT*/Bool* need_discard,
+                            Addr start, SizeT len, Bool forClient )
+{
+   Bool   d;
+   SysRes sres;
+
+   if (!VG_IS_PAGE_ALIGNED(start))
+      goto eINVAL;
+
+   if (len == 0) {
+      *need_discard = False;
+      return VG_(mk_SysRes_Success)( 0 );
+   }
+
+   if (start + len < len)
+      goto eINVAL;
+
+   len = VG_PGROUNDUP(len);
+   aspacem_assert(VG_IS_PAGE_ALIGNED(start));
+   aspacem_assert(VG_IS_PAGE_ALIGNED(len));
+
+   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;
+   }
+
+   d = any_Ts_in_range( start, len );
+
+   sres = do_munmap_NO_NOTIFY( start, len );
+   if (sres.isError)
+      return sres;
+
+   VG_(am_notify_munmap)( start, len );
+   AM_SANITY_CHECK;
+   *need_discard = d;
+   return sres;
+
+  eINVAL:
+   return VG_(mk_SysRes_Error)( VKI_EINVAL );
+}
+
+/* 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. */
+
+SysRes VG_(am_munmap_client)( /*OUT*/Bool* need_discard,
+                              Addr start, SizeT len )
+{
+   return am_munmap_both_wrk( need_discard, start, len, True/*client*/ );
+}
+
+/* Unmap the given address range and update the segment array
+   accordingly.  This fails if the range isn't valid for valgrind. */
+
+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;
+}
+
+/* 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 i, iLo, iHi;
+
+   if (len == 0)
+      return True;
+   if (start + len < start)
+      return False;
+   if (!VG_IS_PAGE_ALIGNED(start) || !VG_IS_PAGE_ALIGNED(len))
+      return False;
+
+   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;
+
+   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 */
+   }
+
+   preen_nsegments();
+   return True;
+}
+
+
+/* --- --- --- 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. */
+
+Bool VG_(am_create_reservation) ( Addr start, SizeT length, 
+                                  ShrinkMode smode, SSizeT extra )
+{
+   Int      startI, endI;
+   NSegment seg;
+
+   /* start and end, not taking into account the extra space. */
+   Addr start1 = start;
+   Addr end1   = start + length - 1;
+
+   /* start and end, taking into account the extra space. */
+   Addr start2 = start1;
+   Addr end2   = end1;
+
+   if (extra < 0) start2 += extra; // this moves it down :-)
+   if (extra > 0) end2 += extra;
+
+   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));
+
+   startI = find_nsegment_idx( start2 );
+   endI = find_nsegment_idx( end2 );
+
+   /* 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;
+
+   if (nsegments[startI].kind != SkFree)
+      return False;
+
+   /* Looks good - make the reservation. */
+   aspacem_assert(nsegments[startI].start <= start2);
+   aspacem_assert(end2 <= nsegments[startI].end);
+
+   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 );
+
+   AM_SANITY_CHECK;
+   return True;
+}
+
+
+/* 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. */
+
+Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg, 
+                                                       SSizeT    delta )
+{
+   Int    segA, segR;
+   UInt   prot;
+   SysRes sres;
+
+   /* 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;
+      }
+
+      /* Ok, success with the kernel.  Update our structures. */
+      nsegments[segR].start += delta;
+      nsegments[segA].end += delta;
+      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
+
+   } else {
+
+      /* 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;
+      }
+
+      /* Ok, success with the kernel.  Update our structures. */
+      nsegments[segR].end -= delta;
+      nsegments[segA].start -= delta;
+      aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
+
+   }
+
+   AM_SANITY_CHECK;
+   return True;
+}
+
+
+/* --- --- --- 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. */
+
+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 (seg->kind != SkFileC && seg->kind != SkAnonC)
+      return False;
+
+   if (delta == 0 || !VG_IS_PAGE_ALIGNED(delta)) 
+      return False;
+
+   xStart = seg->end+1;
+   if (xStart + delta < delta)
+      return False;
+
+   if (!VG_(am_is_valid_for_client_or_free_or_resvn)( xStart, delta, 
+                                                      VKI_PROT_NONE ))
+      return False;
+
+   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;
+   }
+
+   *need_discard = any_Ts_in_range( seg_copy.end+1, delta );
+
+   seg_copy.end += delta;
+   add_segment( &seg_copy );
+
+   AM_SANITY_CHECK;
+   return True;
+}
+
+
+/* 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.  */
+
+Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
+                                        Addr old_addr, SizeT old_len,
+                                        Addr new_addr, SizeT new_len )
+{
+   Int      iLo, iHi;
+   SysRes   sres;
+   NSegment seg, oldseg;
+
+   if (old_len == 0 || new_len == 0)
+      return False;
+
+   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;
+
+   if (old_addr + old_len < old_addr
+       || new_addr + new_len < new_addr)
+      return False;
+
+   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;
+
+   if (nsegments[iLo].kind != SkFileC && nsegments[iLo].kind != SkAnonC)
+      return False;
+
+   sres = do_relocate_nooverlap_mapping_NO_NOTIFY( old_addr, old_len, 
+                                                   new_addr, new_len );
+   if (sres.isError) {
+      AM_SANITY_CHECK;
+      return False;
+   }
+
+   *need_discard = any_Ts_in_range( old_addr, old_len )
+                   || any_Ts_in_range( new_addr, new_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 );
+
+   /* 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 );
+
+   AM_SANITY_CHECK;
+   return True;
+}
+
+
+/*-----------------------------------------------------------------*/
+/*---                                                           ---*/
+/*--- Manage stacks for Valgrind itself.                        ---*/
+/*---                                                           ---*/
+/*-----------------------------------------------------------------*/
+
+/* 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. */
+
+VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp )
+{
+   Int      szB;
+   SysRes   sres;
+   VgStack* stack;
+   UInt*    p;
+   Int      i;
+
+   /* Allocate the stack. */
+   szB = VG_STACK_GUARD_SZB 
+         + VG_STACK_ACTIVE_SZB + VG_STACK_GUARD_SZB;
+
+   sres = VG_(am_mmap_anon_float_valgrind)( szB );
+   if (sres.isError)
+      return NULL;
+
+   stack = (VgStack*)sres.val;
+
+   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;
+}
+
+
+/* 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. */
+
+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                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_aspacemgr/read_procselfmaps.c b/coregrind/m_aspacemgr/read_procselfmaps.c
index 67373c8..559e907 100644
--- a/coregrind/m_aspacemgr/read_procselfmaps.c
+++ b/coregrind/m_aspacemgr/read_procselfmaps.c
@@ -30,12 +30,10 @@
 */
 
 #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 @@
 /* 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 @@
    /* 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 @@
    } 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 @@
 */
 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 @@
    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 @@
       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 @@
       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 @@
       }
 
       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
index 0000000..6043053
--- /dev/null
+++ b/coregrind/m_clientstate.c
@@ -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
index 0000000..d8e011e
--- /dev/null
+++ b/coregrind/m_commandline.c
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_cpuid.S b/coregrind/m_cpuid.S
index 9c4bf2d..9630771 100644
--- a/coregrind/m_cpuid.S
+++ b/coregrind/m_cpuid.S
@@ -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)
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index 8f6bc52..6b46355 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -30,19 +30,16 @@
 
 #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 @@
    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 @@
    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 @@
    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 @@
       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 @@
          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
index e3fe111..0000000
--- a/coregrind/m_debuginfo/Makefile.am
+++ /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
diff --git a/coregrind/m_debuginfo/symtab.c b/coregrind/m_debuginfo/symtab.c
index 577c36f..8b404b0 100644
--- a/coregrind/m_debuginfo/symtab.c
+++ b/coregrind/m_debuginfo/symtab.c
@@ -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"
 
@@ -95,6 +96,126 @@
 
 
 /*------------------------------------------------------------*/
+/*--- 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 @@
 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 @@
 
    *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 @@
    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 @@
 
    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 @@
       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 @@
    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;
   } 
 }
diff --git a/coregrind/m_debuginfo/symtypes.c b/coregrind/m_debuginfo/symtypes.c
index 6cc4786..b391fb9 100644
--- a/coregrind/m_debuginfo/symtypes.c
+++ b/coregrind/m_debuginfo/symtypes.c
@@ -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"
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 2cde3d9..48d5caf 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -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 @@
 {
    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 @@
                                 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 @@
    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
index be6bc5b..0000000
--- a/coregrind/m_demangle/Makefile.am
+++ /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
-
diff --git a/coregrind/m_demangle/cp-demangle.c b/coregrind/m_demangle/cp-demangle.c
index 0e22abc..8212fe2 100644
--- a/coregrind/m_demangle/cp-demangle.c
+++ b/coregrind/m_demangle/cp-demangle.c
@@ -710,14 +710,14 @@
    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 @@
      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 @@
 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 @@
 /* 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;
diff --git a/coregrind/m_demangle/cplus-dem.c b/coregrind/m_demangle/cplus-dem.c
index b8bcc9a..f8af1de 100644
--- a/coregrind/m_demangle/cplus-dem.c
+++ b/coregrind/m_demangle/cplus-dem.c
@@ -54,7 +54,7 @@
 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 @@
   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;
 
diff --git a/coregrind/m_demangle/safe-ctype.c b/coregrind/m_demangle/safe-ctype.c
index 340abba..c685be3 100644
--- a/coregrind/m_demangle/safe-ctype.c
+++ b/coregrind/m_demangle/safe-ctype.c
@@ -30,7 +30,7 @@
      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
index 7fcbc88..0000000
--- a/coregrind/m_dispatch/Makefile.am
+++ /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
diff --git a/coregrind/m_dispatch/dispatch-amd64.S b/coregrind/m_dispatch/dispatch-amd64.S
index 64e8573..2f661be 100644
--- a/coregrind/m_dispatch/dispatch-amd64.S
+++ b/coregrind/m_dispatch/dispatch-amd64.S
@@ -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 */
diff --git a/coregrind/m_dispatch/dispatch-ppc32.S b/coregrind/m_dispatch/dispatch-ppc32.S
index 5147a9d..501e1ef 100644
--- a/coregrind/m_dispatch/dispatch-ppc32.S
+++ b/coregrind/m_dispatch/dispatch-ppc32.S
@@ -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 */
diff --git a/coregrind/m_dispatch/dispatch-x86.S b/coregrind/m_dispatch/dispatch-x86.S
index 5b751c8..e743a8c 100644
--- a/coregrind/m_dispatch/dispatch-x86.S
+++ b/coregrind/m_dispatch/dispatch-x86.S
@@ -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 @@
 	/* 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 @@
 	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
index 0000000..8c3c395
--- /dev/null
+++ b/coregrind/m_launcher.c
@@ -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);
+}
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index ae8f406..4d61668 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -109,8 +109,7 @@
        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);
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index f8c4275..23901f4 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -334,8 +334,34 @@
 
 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 @@
    #undef SORT
 }
 
-static UInt seed = 0;
-
-void VG_(srandom)(UInt s)
-{
-   seed = s;
-}
-
 // This random number generator is based on the one suggested in Kernighan
 // and Ritchie's "The C Programming Language".
-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.
+
+static UInt seed = 0;
+
+UInt VG_(random)( /*MOD*/UInt* pSeed )
 {
-   seed = (1103515245*seed + 12345);
-   return seed;
+   if (pSeed == NULL) 
+      pSeed = &seed;
+
+   *pSeed = (1103515245 * *pSeed + 12345);
+   return *pSeed;
 }
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index ff20a31..34e18c5 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -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 @@
    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 @@
    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 @@
    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 @@
    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
index 420f25b..0000000
--- a/coregrind/m_libcmman.c
+++ /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                                                          ---*/
-/*--------------------------------------------------------------------*/
-
diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c
index 5d435e3..c2aeb09 100644
--- a/coregrind/m_libcprint.c
+++ b/coregrind/m_libcprint.c
@@ -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 @@
    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 @@
    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_(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 @@
                     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 @@
 
 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 @@
       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];
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index a17959e..067d47f 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -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"
 
 /* ---------------------------------------------------------------------
@@ -43,13 +44,8 @@
 
 /* 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 @@
    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 @@
 
    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 @@
       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 @@
    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 @@
    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 @@
    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;
 }
 
 /* ---------------------------------------------------------------------
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 71f4129..e8ea609 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -32,24 +32,28 @@
 
 #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)
@@ -60,14 +64,6 @@
 #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
@@ -94,19 +90,12 @@
 #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           ===*/
 /*====================================================================*/
@@ -115,12 +104,13 @@
    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,371 +141,40 @@
 /*====================================================================*/
 
 /* 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;
+#        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;
 
-      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);
+         default:
+            break;
       }
    }
 }
 
-/*====================================================================*/
-/*=== 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;
-}
-
-// 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
-      }
-   }
-   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;
-}
-
 
 /*====================================================================*/
 /*=== Environment and stack setup                                  ===*/
@@ -562,50 +221,68 @@
 
 /* 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);
+   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));
 
-   // 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);
+   HChar** cpp;
+   HChar** ret;
+   HChar*  preload_tool_path;;
+   Int     envc, i;
 
-   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);
-   
+   /* 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 @@
 
    /* 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 @@
    *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 @@
 
    The format of the stack is:
 
-   higher address +-----------------+
+   higher address +-----------------+ <- clstack_end
 		  | Trampoline code |
 		  +-----------------+
                   |                 |
@@ -700,10 +386,18 @@
                   | 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 @@
    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 @@
    /* ==================== 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 @@
 
    /* 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)));
+   stringbase = strtab = (char *)clstack_end 
+                         - VG_ROUNDUP(stringsize, sizeof(int));
 
-   VG_(clstk_base) = VG_PGROUNDDN(cl_esp);
+   clstack_start = VG_PGROUNDDN(client_SP);
+
+   /* The max stack size */
+   clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+   /* Record stack extent -- needed for stack-change code. */
+   VG_(clstk_base) = clstack_start;
+   VG_(clstk_end)  = clstack_end;
 
    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));
+      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);
 
    /* ==================== allocate space ==================== */
 
-   /* 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); 
+   { 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;
 
-   /* ==================== copy client stack ==================== */
+     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);
 
-   ptr = (Addr*)cl_esp;
+#    ifdef ENABLE_INNER
+     inner_HACK = 1024*1024; // create 1M non-fault-extending stack
+#    endif
 
-   /* --- argc --- */
-   *ptr++ = argc;		/* client argc */
+     if (0)
+        VG_(printf)("%p 0x%x  %p 0x%x\n", 
+                    resvn_start, resvn_size, anon_start, anon_size);
 
-   /* --- argv --- */
+     /* 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 @@
 	 break;
 
       case AT_IGNORE:
-      case AT_EXECFD:
       case AT_PHENT:
       case AT_PAGESZ:
       case AT_FLAGS:
@@ -926,7 +668,7 @@
       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,44 +679,109 @@
 
    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;
@@ -982,129 +789,6 @@
 
 
 /*====================================================================*/
-/*=== 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 @@
 /*=== Loading the client                                           ===*/
 /*====================================================================*/
 
-static void load_client(char* cl_argv[], const char* exec, Int need_help,
-                 /*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();
-      }
-   }
+/* Load the client whose name is VG_(argv_the_exename). */
 
-   info->map_base = VG_(client_mapbase);
+static void load_client ( /*OUT*/struct exeinfo* info, 
+                          /*OUT*/Addr* client_eip)
+{
+   HChar* exec;
+   Int    ret;
+   SysRes res;
+
+   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 @@
 
 // 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 @@
 "\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 @@
    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 @@
      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 @@
             // 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 @@
       
       /* 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 @@
          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 @@
 
 
    /* 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 @@
       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 @@
          "%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 @@
       }
       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 @@
 #        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 @@
    /* 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 @@
 /*=== 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.
+/* 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. */
 
-  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.
-*/
-
-
-/* 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 )
 {
+   Addr* starts;
+   Int   n_starts, r;
+
+   n_starts = 1;
    while (True) {
-      if (*s1 == 0 && *s2 == 0) return 0;
-      if (*s1 == 0) return -1;
-      if (*s2 == 0) return 1;
-
-      if (*(UChar*)s1 < *(UChar*)s2) return -1;
-      if (*(UChar*)s1 > *(UChar*)s2) return 1;
-
-      s1++; s2++;
+      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;
 }
 
 
-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 @@
    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 @@
    //--------------------------------------------------------------
    // 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);
+   }
+
+   //============================================================
+   // 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
+   //============================================================
+
+   //--------------------------------------------------------------
+   // Split up argv into: C args, V args, V extra args, and exename.
+   //   p: dynamic memory allocation
+   //--------------------------------------------------------------
+   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]);
    }
 
    //--------------------------------------------------------------
-   // Look for alternative libdir                                  
-   //   p: none
-   //--------------------------------------------------------------
-   {  HChar *cp = getenv(VALGRINDLIB);
-      if (cp != NULL)
-	 VG_(libdir) = cp;
-   }
-
-   //--------------------------------------------------------------
-   // Get valgrind args + client args (inc. from VALGRIND_OPTS/.valgrindrc).
-   // Pre-process the command line.
-   //   p: none
+   // 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", "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);
+   get_helprequest_and_toolname(&need_help, &toolname);
 
-   /* 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)");
-   }
-
-   //==============================================================
-   // 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']
-   //--------------------------------------------------------------
-   VG_(debugLog)(1, "main", "Loading tool\n");
-   load_tool(tool, &toolinfo, &preload);
-
-   //==============================================================
-   // 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);
 
-   sp_at_startup = setup_client_stack(init_sp, cl_argv, env, &info,
-                                      &client_auxv);
-   free(env);
+      initial_client_SP
+         = setup_client_stack( init_sp, env, 
+                               &info, &client_auxv, 
+                               clstack_top, clstack_max_size );
+
+      VG_(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 @@
    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;
 
-   //==============================================================
-   // Can use VG_(arena_malloc)() with non-CORE arena after segments set up
-   //==============================================================
+      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);
+      }
+
+      /* 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
@@ -2712,11 +2309,113 @@
    }
 
    //--------------------------------------------------------------
+   // 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 @@
    //      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 @@
    // 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)();
@@ -2770,52 +2470,13 @@
    }
 
    //--------------------------------------------------------------
-   // 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
@@ -2823,6 +2484,15 @@
    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!
    //--------------------------------------------------------------
    VGP_POPCC(VgpStartup);
@@ -3005,6 +2675,122 @@
    }
 }
 
+
+/*====================================================================*/
+/*=== 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                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mallocfree.c b/coregrind/m_mallocfree.c
index 0bd0136..0be3f1b 100644
--- a/coregrind/m_mallocfree.c
+++ b/coregrind/m_mallocfree.c
@@ -30,9 +30,10 @@
 */
 
 #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 @@
 /* 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 @@
       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 );
+   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;
+      }
 
-   init_done = True;
+      // 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 @@
 /*--- 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 @@
 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 @@
    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 @@
 
    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 @@
    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 @@
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    if (ptr == NULL) {
@@ -1070,7 +1122,7 @@
    sanity_check_malloc_arena(aid);
 #  endif
 
-   VALGRIND_FREELIKE_BLOCK(ptr, 0);
+   //zzVALGRIND_FREELIKE_BLOCK(ptr, 0);
 
    VGP_POPCC(VgpMalloc);
 }
@@ -1118,7 +1170,7 @@
 
    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 @@
 
    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 @@
    VG_(memset)(mi, 0x0, sizeof(struct vg_mallinfo));
 }
 
+
 /*------------------------------------------------------------*/
 /*--- Services layered on top of malloc/free.              ---*/
 /*------------------------------------------------------------*/
@@ -1233,7 +1286,7 @@
 
    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 @@
 
    VGP_PUSHCC(VgpMalloc);
 
-   ensure_mm_init();
+   ensure_mm_init(aid);
    a = arenaId_to_ArenaP(aid);
 
    vg_assert(req_pszB < MAX_PSZB);
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 40a3275..b69572f 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -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 @@
          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
index e4e32a1..0000000
--- a/coregrind/m_replacemalloc/Makefile.am
+++ /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
index d865494..0000000
--- a/coregrind/m_scheduler/Makefile.am
+++ /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
-
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 09b1882..89e2f56 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -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 @@
    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 @@
 
 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 @@
    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 @@
 
    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 @@
       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 @@
       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 @@
                          " 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 @@
                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 @@
 
       /* 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
index f265b03..0000000
--- a/coregrind/m_sigframe/Makefile.am
+++ /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
diff --git a/coregrind/m_sigframe/sigframe-amd64-linux.c b/coregrind/m_sigframe/sigframe-amd64-linux.c
index 0e4b4fe..cb44c3b 100644
--- a/coregrind/m_sigframe/sigframe-amd64-linux.c
+++ b/coregrind/m_sigframe/sigframe-amd64-linux.c
@@ -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 @@
 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:",
diff --git a/coregrind/m_sigframe/sigframe-ppc32-linux.c b/coregrind/m_sigframe/sigframe-ppc32-linux.c
index d99e8d2..22af92a 100644
--- a/coregrind/m_sigframe/sigframe-ppc32-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc32-linux.c
@@ -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"
diff --git a/coregrind/m_sigframe/sigframe-x86-linux.c b/coregrind/m_sigframe/sigframe-x86-linux.c
index 17026c9..f0b82dd 100644
--- a/coregrind/m_sigframe/sigframe-x86-linux.c
+++ b/coregrind/m_sigframe/sigframe-x86-linux.c
@@ -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 @@
 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:",
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 253a7f1..4a05421 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -80,15 +80,14 @@
  */
 
 #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 @@
 
    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 @@
 	       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 @@
    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 @@
  */
 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)
+   NSegment* seg      = VG_(am_find_nsegment)(addr);
+   NSegment* seg_next = seg ? VG_(am_next_nsegment)( seg, True/*fwds*/ )
+                            : NULL;
+
+   if (seg && seg->kind == SkAnonC)
+      /* addr is already mapped.  Nothing to do. */
       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);
-
-   /* Create the mapping */
-   base = VG_PGROUNDDN(addr);
-   newsize = seg->addr - base;
-
-   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 @@
    } 
 
    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 @@
    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 @@
 	 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 */
diff --git a/coregrind/m_skiplist.c b/coregrind/m_skiplist.c
index f9ca188..be64c45 100644
--- a/coregrind/m_skiplist.c
+++ b/coregrind/m_skiplist.c
@@ -119,7 +119,7 @@
 {
    UInt ret = 0;
 
-   while((ret < SK_MAXHEIGHT - 1) && (VG_(random)() & 1))
+   while((ret < SK_MAXHEIGHT - 1) && (VG_(random)(NULL) & 1))
       ret++;
 
    return ret;
diff --git a/coregrind/m_stacks.c b/coregrind/m_stacks.c
index 506aa19..1291744 100644
--- a/coregrind/m_stacks.c
+++ b/coregrind/m_stacks.c
@@ -118,6 +118,9 @@
 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;
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index bd17ee0..e982488 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -77,7 +77,7 @@
    // 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 @@
       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);
    }
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index d6348e7..a0938d5 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -215,6 +215,37 @@
 #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
index b1033a4..0000000
--- a/coregrind/m_syswrap/Makefile.am
+++ /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
diff --git a/coregrind/m_syswrap/priv_syswrap-generic.h b/coregrind/m_syswrap/priv_syswrap-generic.h
index ac7d038..8a5b6fc 100644
--- a/coregrind/m_syswrap/priv_syswrap-generic.h
+++ b/coregrind/m_syswrap/priv_syswrap-generic.h
@@ -40,6 +40,11 @@
 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 @@
 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
diff --git a/coregrind/m_syswrap/syscall-amd64-linux.S b/coregrind/m_syswrap/syscall-amd64-linux.S
index 04dbfa5..04a1477 100644
--- a/coregrind/m_syswrap/syscall-amd64-linux.S
+++ b/coregrind/m_syswrap/syscall-amd64-linux.S
@@ -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"
 
diff --git a/coregrind/m_syswrap/syscall-ppc32-linux.S b/coregrind/m_syswrap/syscall-ppc32-linux.S
index e829802..2511b74 100644
--- a/coregrind/m_syswrap/syscall-ppc32-linux.S
+++ b/coregrind/m_syswrap/syscall-ppc32-linux.S
@@ -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"
 		
diff --git a/coregrind/m_syswrap/syscall-x86-linux.S b/coregrind/m_syswrap/syscall-x86-linux.S
index 150a528..d6ff343 100644
--- a/coregrind/m_syswrap/syscall-x86-linux.S
+++ b/coregrind/m_syswrap/syscall-x86-linux.S
@@ -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"
 		
diff --git a/coregrind/m_syswrap/syswrap-amd64-linux.c b/coregrind/m_syswrap/syswrap-amd64-linux.c
index 66fb502..c662003 100644
--- a/coregrind/m_syswrap/syswrap-amd64-linux.c
+++ b/coregrind/m_syswrap/syswrap-amd64-linux.c
@@ -30,13 +30,11 @@
 
 #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"
@@ -61,70 +59,46 @@
    Note.  Why is this stuff here?
    ------------------------------------------------------------------ */
 
-/* 
-   Allocate a stack for this thread.
+/* Allocate a stack for this thread.  They're allocated lazily, and
+   never freed. */
 
-   They're allocated lazily, but never freed.
- */
-#define FILL	0xdeadbeefcabafeed
+/* 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. */
 
-// Valgrind's stack size, in words.
-#define STACK_SIZE_W      16384
-
-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;
+
+   /* 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. */
+
+   if (tst->os_state.valgrind_stack_base == 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
+
+   if (tst->os_state.valgrind_stack_base != 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
+
+   /* If no stack is present, allocate one. */
 
    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;
+      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;
+      }
    }
 
-   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 (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);
-
-   return rsp;
-}
-
-/* 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 (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 @@
    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 @@
    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 @@
    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 @@
       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 @@
 
    VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL);
 
+  out:
    if (res.isError) {
       /* clone failed */
       VG_(cleanup_thread)(&ctst->arch);
@@ -604,14 +587,14 @@
 
    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 @@
    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 @@
    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 
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 61b9437..eac7239 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -30,14 +30,15 @@
 
 #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"
@@ -57,35 +58,29 @@
 #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 @@
    return ret;
 }
 
+
 Bool ML_(client_signal_OK)(Int sigNo)
 {
    /* signal 0 is OK for kill */
@@ -104,6 +100,17 @@
    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 @@
    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 @@
    *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;
+   /* '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);
 
-   if (fd != -1)
-      flags |= SF_FILE;
+   d = VG_(am_notify_client_mmap)( a, len, prot, flags, fd, offset );
 
-   VG_(map_fd_segment)(a, len, prot, flags, fd, offset, NULL);
-
-   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;
+#  define MIN_SIZET(_aa,_bb) (_aa) < (_bb) ? (_aa) : (_bb)
 
-   old_size = VG_PGROUNDUP(old_size);
-   new_size = VG_PGROUNDUP(new_size);
-
-   if (VG_PGROUNDDN(old_addr) != old_addr)
-      return VG_(mk_SysRes_Error)( VKI_EINVAL );
-
-   if (!ML_(valid_client_addr)(old_addr, old_size, tid, "mremap(old_addr)"))
-      return VG_(mk_SysRes_Error)( VKI_EFAULT );
-
-   /* 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) {
-      if (VG_PGROUNDDN(new_addr) != new_addr)
-	 return VG_(mk_SysRes_Error)( VKI_EINVAL );
-
-      if (!ML_(valid_client_addr)(new_addr, new_size, tid, "mremap(new_addr)"))
-	 return VG_(mk_SysRes_Error)( VKI_ENOMEM );
-
-      /* 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 );
-   }
-
-   /* Do nothing */
-   if (!(flags & VKI_MREMAP_FIXED) && new_size == old_size)
-      return VG_(mk_SysRes_Success)( old_addr );
-
-   seg = VG_(find_segment)(old_addr);
-
-   /* range must be contained within segment */
-   if (seg == NULL || !VG_(seg_contains)(seg, old_addr, old_size))
-      return VG_(mk_SysRes_Error)( VKI_EINVAL );
-
-   next = VG_(find_segment_above_mapped)(old_addr);
+   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 (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 ); 
+      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" : "");
 
-      if ((flags & VKI_MREMAP_FIXED) == 0)
-	  new_addr = 0;
+   if (flags & ~(VKI_MREMAP_FIXED | VKI_MREMAP_MAYMOVE))
+      goto eINVAL;
 
-      a = VG_(find_map_space)(new_addr, new_size, True);
+   if (!VG_IS_PAGE_ALIGNED(old_addr))
+      goto eINVAL;
 
-      if ((flags & VKI_MREMAP_FIXED) && a != new_addr)
-         /* didn't find the place we wanted */
-	 return VG_(mk_SysRes_Error)( VKI_ENOMEM );
+   old_len = VG_PGROUNDUP(old_len);
+   new_len = VG_PGROUNDUP(new_len);
 
-      new_addr = a;
+   if (new_len == 0)
+      goto eINVAL;
 
-      /* we've nailed down the location */
-      flags |= VKI_MREMAP_FIXED|VKI_MREMAP_MAYMOVE;
+   /* kernel doesn't reject this, but we do. */
+   if (old_len == 0)
+      goto eINVAL;
 
-      ret = VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size, 
-			     flags, new_addr);
+   /* reject wraparounds */
+   if (old_addr + old_len < old_addr
+       || new_addr + new_len < new_len)
+      goto eINVAL;
 
-      if (ret.isError) {
-	 return ret;
-      }
+   /* kernel rejects all fixed, no-move requests (which are
+      meaningless). */
+   if (f_fixed == True && f_maymove == False)
+      goto eINVAL;
 
-      VG_TRACK(copy_mem_remap, old_addr, new_addr, 
-	       (old_size < new_size) ? old_size : new_size);
+   /* Stay away from non-client areas. */
+   if (!ML_(valid_client_addr)(old_addr, old_len, tid, "mremap(old_addr)"))
+      goto eINVAL;
 
-      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);
+   /* 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;
 
-      VG_(map_file_segment)(new_addr, new_size,
-			    seg->prot, 
-			    seg->flags,
-			    seg->dev, seg->ino,
-			    seg->offset, seg->filename);
+   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));
 
-      VG_(munmap)((void *)old_addr, old_size);
-   } else {
-      /* staying in place */
-      ret = VG_(mk_SysRes_Success)( old_addr );
+   /* There are 3 remaining cases:
 
-      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);
+      * maymove == False
+
+        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
+
+      * maymove == True, fixed == False
+
+        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
+
+      * maymove == True, fixed == True
+
+        new space must be at new address, so:
+
+            - 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
+   */
+
+   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;
+   }
+
+   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 (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;
+         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;
+   }
 
-	 if (0)
-	    VG_(printf)("mremap: old_addr=%p old_size=%d new_size=%d flags=%d\n",
-			old_addr, old_size, new_size, flags);
+   /* end of the 3 cases */
+   /*NOTREACHED*/ vg_assert(0);
 
-	 ret = VG_(do_syscall5)(__NR_mremap, old_addr, old_size, new_size, 
-			        flags, 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;
 
-	 if (ret.isError || (!ret.isError && ret.val != old_addr))
-	    return ret;
-
-	 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);
-
-	 VG_(map_file_segment)(old_addr+old_size, new_size-old_size,
-			       seg->prot, 
-			       seg->flags,
-			       seg->dev, seg->ino,
-			       seg->offset, seg->filename);	 
+   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 );
       }
    }
 
-   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);
+
+  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);
+
+  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);
+
+  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 @@
    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 @@
    if (0) show_segments("in_brk");
 #  endif
 
-   if (newbrk < VG_(brk_base) || newbrk >= VG_(client_end))
-      return VG_(brk_limit);
+   if (newbrk < VG_(brk_base))
+      /* Clearly impossible. */
+      goto bad;
 
-   /* brk isn't allowed to grow over anything else */
-   seg = VG_(find_segment)(VG_(brk_limit) -1);
+   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;
+   }
 
-   vg_assert(seg != NULL);
+   /* otherwise we're expanding the brk segment. */
+   aseg = VG_(am_find_nsegment)( VG_(brk_base) );
+   rseg = VG_(am_next_nsegment)( aseg, True/*forwards*/ );
 
-   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));
+   /* 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);
 
-   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);
+   vg_assert(newbrk >= VG_(brk_base));
+   if (newbrk <= rseg->start) {
+      /* still fits within the anon segment. */
+      VG_(brk_limit) = newbrk;
+      return newbrk;
+   }
 
-   current = VG_PGROUNDUP(VG_(brk_limit));
-   newaddr = VG_PGROUNDUP(newbrk);
-   if (newaddr != current) {
+   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;
+   }
 
-      /* 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);
+   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;
 
-	 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));
+   VG_(brk_limit) = newbrk;
+   return newbrk;
 
-	 if (debug)
-	    VG_(printf)("  shrinking brk: current=%p newaddr=%p delta=%d\n",
-			current, newaddr, current-newaddr);
-
-	 if (newaddr != current) {
-	    Int res = VG_(munmap)((void *)newaddr, current - newaddr);
-            vg_assert(0 == res);
-	 }
-	 ret = newbrk;
-      }
-   } else
-      ret = newbrk;
-
-   VG_(brk_limit) = ret;
-
-   return ret;
+  bad:
+   return VG_(brk_limit);
 }
 
 
@@ -868,9 +1000,8 @@
 /* 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 @@
                              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 @@
    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 @@
 void
 ML_(generic_POST_sys_shmdt) ( ThreadId tid, UWord res, UWord arg0 )
 {
-   Segment *s = VG_(find_segment)(arg0);
+   NSegment* s = VG_(am_find_nsegment)(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);
+   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 @@
                  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 @@
 // 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 @@
    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 @@
       }
    }
 
+   /* 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 @@
       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 @@
       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 @@
    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 @@
 {
    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 @@
 
 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 @@
                     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 @@
 
 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 @@
       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 @@
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
+
diff --git a/coregrind/m_syswrap/syswrap-linux.c b/coregrind/m_syswrap/syswrap-linux.c
index 9092020..86e7dcf 100644
--- a/coregrind/m_syswrap/syswrap-linux.c
+++ b/coregrind/m_syswrap/syswrap-linux.c
@@ -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 @@
    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 @@
 
 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 @@
       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 @@
 // 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);
+   ML_(notify_aspacem_and_tool_of_mmap)( (Addr)r, size,
+                                         VKI_PROT_READ | VKI_PROT_WRITE,
+                                         VKI_MAP_ANONYMOUS, -1, 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);
-   }
+   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 @@
 // 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 @@
 
    // 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)" );
    }  
 }  
 
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index 7e0233e..3bf1efc 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -170,6 +170,37 @@
    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 @@
          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)));
diff --git a/coregrind/m_syswrap/syswrap-ppc32-linux.c b/coregrind/m_syswrap/syswrap-ppc32-linux.c
index b5dfb9d..648fb02 100644
--- a/coregrind/m_syswrap/syswrap-ppc32-linux.c
+++ b/coregrind/m_syswrap/syswrap-ppc32-linux.c
@@ -30,12 +30,10 @@
 
 #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 @@
    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 @@
 //..    //   (__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 @@
    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
 //..    
diff --git a/coregrind/m_syswrap/syswrap-x86-linux.c b/coregrind/m_syswrap/syswrap-x86-linux.c
index 57b0f07..778f9b7 100644
--- a/coregrind/m_syswrap/syswrap-x86-linux.c
+++ b/coregrind/m_syswrap/syswrap-x86-linux.c
@@ -35,12 +35,11 @@
 
 #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"
@@ -67,70 +66,46 @@
    Note.  Why is this stuff here?
    ------------------------------------------------------------------ */
 
-/* 
-   Allocate a stack for this thread.
+/* Allocate a stack for this thread.  They're allocated lazily, and
+   never freed. */
 
-   They're allocated lazily, but never freed.
- */
-#define FILL	0xdeadbeef
+/* 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. */
 
-// Valgrind's stack size, in words.
-#define STACK_SIZE_W      16384
-
-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;
+
+   /* 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. */
+
+   if (tst->os_state.valgrind_stack_base == 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
+
+   if (tst->os_state.valgrind_stack_base != 0)
+      vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
+
+   /* If no stack is present, allocate one. */
 
    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;
+      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;
+      }
    }
 
-   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 (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);
-
-   return esp;
-}
-
-/* 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 (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 @@
 );
 
 
-/*
-   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 @@
    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 @@
    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 @@
       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 @@
 
    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 @@
          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 @@
       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;
+
+      /* 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 (! 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 );
-      }
-   }
+   vg_assert(! FAILURE);
 
-   if (0)
-   VG_(printf)("old_mmap( %p, fixed %d ) -> %s(%p)\n", 
-               args[0], 
-               args[3]&VKI_MAP_FIXED, 
-               FAILURE ? "Fail" : "Success", RES_unchecked);
+   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_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 @@
    // 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 @@
    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
diff --git a/coregrind/m_tooliface.c b/coregrind/m_tooliface.c
index a13f3ef..7c9da50 100644
--- a/coregrind/m_tooliface.c
+++ b/coregrind/m_tooliface.c
@@ -96,7 +96,7 @@
 };
 
 /* 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 @@
       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
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 32614b9..5db9844 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -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 ------------------ */
@@ -37,6 +37,15 @@
    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 @@
 #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
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index 9e7adfb..3793eb7 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -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)
@@ -42,7 +41,10 @@
 #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 @@
    '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 @@
 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 @@
    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 @@
                       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 @@
    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 @@
               bbs_done);
    }
 
-   if (seg == NULL ||
-       !VG_(seg_contains)(seg, orig_addr, 1) || 
-       (seg->prot & (VKI_PROT_READ|VKI_PROT_EXEC)) == 0) {
+   /* Are we allowed to translate here? */
+
+   seg = VG_(am_find_nsegment)(orig_addr);
+
+   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 */
-      vg_assert(!VG_(is_addressable)(orig_addr, 1, 
-                                     VKI_PROT_READ|VKI_PROT_EXEC));
-
-      if (seg != NULL && VG_(seg_contains)(seg, orig_addr, 1)) {
-         vg_assert((seg->prot & VKI_PROT_EXEC) == 0);
+      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 @@
          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 @@
 
    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);
 
diff --git a/coregrind/m_transtab.c b/coregrind/m_transtab.c
index f83ea28..459f8e6 100644
--- a/coregrind/m_transtab.c
+++ b/coregrind/m_transtab.c
@@ -30,14 +30,16 @@
 */
 
 #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 initialiseSector ( Int sno )
 {
-   Int i;
+   Int    i;
+   SysRes sres;
    vg_assert(isValidSector(sno));
 
    if (sectors[sno].tc == NULL) {
@@ -297,16 +300,31 @@
       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 @@
 }
 
 
-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 @@
          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 );
 }
 
 
diff --git a/coregrind/m_ume.c b/coregrind/m_ume.c
index c27a003..09f47d9 100644
--- a/coregrind/m_ume.c
+++ b/coregrind/m_ume.c
@@ -38,18 +38,20 @@
 // 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 @@
    int		fd;
 };
 
-static void check_mmap(void* res, void* base, int len)
+static void check_mmap(SysRes res, Addr base, SizeT len)
 {
-   if ((void*)-1 == res) {
-      fprintf(stderr, "valgrind: mmap(%p, %d) failed in UME.\n", base, len);
-      exit(1);
+   if (res.isError) {
+      VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME.\n", 
+                  (ULong)base, (Long)len);
+      VG_(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 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;
-   }
-}
-
-/*------------------------------------------------------------*/
-/*--- 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 @@
 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);
+   e->p = VG_(malloc)(phsz);
+   vg_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);
+   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 @@
 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 @@
       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 @@
       //
       // 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 @@
 
 	 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 @@
 }
 
 // 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 @@
    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 @@
 	 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 @@
       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;
+      Addr       advised;
+      Bool       ok;
 
-      if (info->map_base != 0) {
-	 base = (char *)VG_ROUNDUP(info->map_base, interp_align);
-	 flags |= MAP_FIXED;
+      /* 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;
+      (void)mapelf(interp, (ESZ(Addr))advised - interp_addr);
 
-      baseoff = base - interp_addr;
+      VG_(close)(interp->fd);
 
-      mapelf(interp, (ESZ(Addr))baseoff);
+      entry = (void *)(advised - interp_addr + interp->e.e_entry);
+      info->interp_base = (ESZ(Addr))advised;
 
-      close(interp->fd);
-
-      entry = baseoff + interp->e.e_entry;
-      info->interp_base = (ESZ(Addr))base;
-
-      free(interp->p);
-      free(interp);
+      VG_(free)(interp->p);
+      VG_(free)(interp);
    } else
       entry = (void *)(ebase + e->e.e_entry);
 
@@ -573,8 +639,8 @@
 
    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 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 @@
       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 @@
       *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 @@
    (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 @@
       { 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 @@
       }
    }
 
-   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;
diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h
index e3bd9a5..b4fb4d8 100644
--- a/coregrind/pub_core_aspacemgr.h
+++ b/coregrind/pub_core_aspacemgr.h
@@ -37,122 +37,290 @@
 // 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 ) );
 
-// Pointercheck
-extern Bool VG_(setup_pointercheck) ( Addr client_base, Addr client_end );
+//--------------------------------------------------------------
+// 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 ); 
+
 
 #endif   // __PUB_CORE_ASPACEMGR_H
 
diff --git a/coregrind/pub_core_basics.h b/coregrind/pub_core_basics.h
index 8d56e4a..c421b84 100644
--- a/coregrind/pub_core_basics.h
+++ b/coregrind/pub_core_basics.h
@@ -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
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_libcmman.h b/coregrind/pub_core_basics_asm.h
similarity index 67%
rename from coregrind/pub_core_libcmman.h
rename to coregrind/pub_core_basics_asm.h
index ba2bed7..fc62507 100644
--- a/coregrind/pub_core_libcmman.h
+++ b/coregrind/pub_core_basics_asm.h
@@ -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
@@ -28,25 +30,23 @@
    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
index 0000000..ec7a347
--- /dev/null
+++ b/coregrind/pub_core_clientstate.h
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_libcmman.h b/coregrind/pub_core_commandline.h
similarity index 61%
copy from coregrind/pub_core_libcmman.h
copy to coregrind/pub_core_commandline.h
index ba2bed7..a36469b 100644
--- a/coregrind/pub_core_libcmman.h
+++ b/coregrind/pub_core_commandline.h
@@ -1,13 +1,13 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Memory management libc stuff.            pub_core_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
@@ -28,24 +28,19 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#ifndef __PUB_CORE_LIBCMMAN_H
-#define __PUB_CORE_LIBCMMAN_H
+#ifndef __PUB_CORE_COMMANDLINE_H
+#define __PUB_CORE_COMMANDLINE_H
 
-//--------------------------------------------------------------------
-// PURPOSE: This module contains libc code related to low-level
-// memory management, ie. mmap and friends.
-//--------------------------------------------------------------------
 
-#include "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_(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 );
+extern void VG_(split_up_argv)( Int argc, HChar** argv );
 
-extern Addr VG_(get_memory_from_mmap_for_client)(SizeT len);
 
-#endif   // __PUB_CORE_LIBCMMAN_H
+#endif   // __PUB_CORE_COMMANDLINE_H
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index f5de7f1..7034566 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -41,6 +41,10 @@
 
 #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);
diff --git a/coregrind/pub_core_libcfile.h b/coregrind/pub_core_libcfile.h
index 1480da7..af621b1 100644
--- a/coregrind/pub_core_libcfile.h
+++ b/coregrind/pub_core_libcfile.h
@@ -49,6 +49,9 @@
 /* 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_(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
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h
index 4515399..4742719 100644
--- a/coregrind/pub_core_libcproc.h
+++ b/coregrind/pub_core_libcproc.h
@@ -36,34 +36,37 @@
 // 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 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);
diff --git a/coregrind/pub_core_main.h b/coregrind/pub_core_main.h
index 2e80c8d..c8bbec6 100644
--- a/coregrind/pub_core_main.h
+++ b/coregrind/pub_core_main.h
@@ -38,10 +38,6 @@
 // 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) (
diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h
index 5167042..d79dabc 100644
--- a/coregrind/pub_core_mallocfree.h
+++ b/coregrind/pub_core_mallocfree.h
@@ -92,11 +92,7 @@
                                                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 );
 
diff --git a/coregrind/pub_core_redir.h b/coregrind/pub_core_redir.h
index 604e7c0..664d79c 100644
--- a/coregrind/pub_core_redir.h
+++ b/coregrind/pub_core_redir.h
@@ -66,7 +66,7 @@
 // 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);
diff --git a/coregrind/pub_core_replacemalloc.h b/coregrind/pub_core_replacemalloc.h
index 7f27ce0..8f5dfbb 100644
--- a/coregrind/pub_core_replacemalloc.h
+++ b/coregrind/pub_core_replacemalloc.h
@@ -49,7 +49,6 @@
    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;
diff --git a/coregrind/pub_core_scheduler.h b/coregrind/pub_core_scheduler.h
index 35574c5..0ed25b6 100644
--- a/coregrind/pub_core_scheduler.h
+++ b/coregrind/pub_core_scheduler.h
@@ -75,7 +75,8 @@
 // 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 );
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index dec2403..d6be428 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -67,9 +67,16 @@
 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                                                          ---*/
 /*--------------------------------------------------------------------*/
-
diff --git a/coregrind/pub_core_syswrap.h b/coregrind/pub_core_syswrap.h
index 8ca0fa9..2c03321 100644
--- a/coregrind/pub_core_syswrap.h
+++ b/coregrind/pub_core_syswrap.h
@@ -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);
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index b7c1ceb..e58e032 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -112,8 +112,8 @@
    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
diff --git a/coregrind/pub_core_tooliface.h b/coregrind/pub_core_tooliface.h
index df9fe26..9aeaeaa 100644
--- a/coregrind/pub_core_tooliface.h
+++ b/coregrind/pub_core_tooliface.h
@@ -158,7 +158,7 @@
    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 @@
    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
 
diff --git a/coregrind/pub_core_transtab.h b/coregrind/pub_core_transtab.h
index 6f14559..bd110d8 100644
--- a/coregrind/pub_core_transtab.h
+++ b/coregrind/pub_core_transtab.h
@@ -56,7 +56,8 @@
                                    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 );
 
diff --git a/coregrind/pub_core_ume.h b/coregrind/pub_core_ume.h
index 91a29ec..fbf414f 100644
--- a/coregrind/pub_core_ume.h
+++ b/coregrind/pub_core_ume.h
@@ -44,25 +44,28 @@
 /*------------------------------------------------------------*/
 
 /* 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 @@
 // 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 @@
 
 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
index 9d7d00d..0000000
--- a/coregrind/stage1.c
+++ /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 ---*/
-/*--------------------------------------------------------------------*/