Bug 345248 - add support for Solaris OS in valgrind

Authors of this port:
    Petr Pavlu         setup@dagobah.cz
    Ivo Raisr          ivosh@ivosh.net
    Theo Schlossnagle  theo@omniti.com
            


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15426 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/Makefile.all.am b/Makefile.all.am
index 41f476f..3b62d24 100644
--- a/Makefile.all.am
+++ b/Makefile.all.am
@@ -241,6 +241,18 @@
 AM_CFLAGS_TILEGX_LINUX     = @FLAG_M64@ $(AM_CFLAGS_BASE)
 AM_CFLAGS_PSO_TILEGX_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE)
 
+AM_FLAG_M3264_X86_SOLARIS   = @FLAG_M32@
+AM_CFLAGS_X86_SOLARIS       = @FLAG_M32@ @PREFERRED_STACK_BOUNDARY_2@ \
+			 	$(AM_CFLAGS_BASE) -fomit-frame-pointer
+AM_CFLAGS_PSO_X86_SOLARIS   = @FLAG_M32@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE)
+AM_CCASFLAGS_X86_SOLARIS    = @FLAG_M32@ -g -D_ASM
+
+AM_FLAG_M3264_AMD64_SOLARIS = @FLAG_M64@
+AM_CFLAGS_AMD64_SOLARIS     = @FLAG_M64@ \
+				$(AM_CFLAGS_BASE) -fomit-frame-pointer
+AM_CFLAGS_PSO_AMD64_SOLARIS  = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE)
+AM_CCASFLAGS_AMD64_SOLARIS  = @FLAG_M64@ -g -D_ASM
+
 # Flags for the primary target.  These must be used to build the
 # regtests and performance tests.  In fact, these must be used to
 # build anything which is built only once on a dual-arch build.
@@ -261,6 +273,10 @@
 #
 PRELOAD_LDFLAGS_COMMON_LINUX  = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst
 PRELOAD_LDFLAGS_COMMON_DARWIN = -dynamic -dynamiclib -all_load
+PRELOAD_LDFLAGS_COMMON_SOLARIS = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst
+if SOLARIS_XPG_SYMBOLS_PRESENT
+PRELOAD_LDFLAGS_COMMON_SOLARIS += -Wl,-M,$(top_srcdir)/solaris/vgpreload-solaris.mapfile
+endif
 
 if VGCONF_PLATVARIANT_IS_ANDROID
 # The Android toolchain includes all kinds of stdlib helpers present in
@@ -282,4 +298,6 @@
 PRELOAD_LDFLAGS_MIPS32_LINUX   = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@
 PRELOAD_LDFLAGS_MIPS64_LINUX   = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
 PRELOAD_LDFLAGS_TILEGX_LINUX   = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
+PRELOAD_LDFLAGS_X86_SOLARIS    = $(PRELOAD_LDFLAGS_COMMON_SOLARIS) @FLAG_M32@
+PRELOAD_LDFLAGS_AMD64_SOLARIS  = $(PRELOAD_LDFLAGS_COMMON_SOLARIS) @FLAG_M64@
 
diff --git a/Makefile.am b/Makefile.am
index 426c1ea..4ad7b16 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -32,6 +32,7 @@
 	memcheck/tests/vbit-test \
 	auxprogs \
 	mpi \
+	solaris \
 	docs
 DIST_SUBDIRS  = $(SUBDIRS)
 
@@ -46,7 +47,8 @@
 	darwin9.supp darwin9-drd.supp \
 	darwin10.supp darwin10-drd.supp \
 	darwin11.supp darwin12.supp darwin13.supp darwin14.supp darwin15.supp \
-	bionic.supp
+	bionic.supp \
+	solaris11.supp solaris12.supp
 DEFAULT_SUPP_FILES = @DEFAULT_SUPP@
 
 # We include all the base .supp files in the distribution, but not
@@ -106,6 +108,7 @@
 	README.android_emulator \
 	README.mips \
 	README.aarch64 \
+	README.solaris \
 	NEWS.old \
 	valgrind.pc.in \
 	valgrind.spec.in \
diff --git a/Makefile.tool-tests.am b/Makefile.tool-tests.am
index ca9d9a6..eb359db 100644
--- a/Makefile.tool-tests.am
+++ b/Makefile.tool-tests.am
@@ -26,6 +26,11 @@
 # automake;  see comments in Makefile.all.am for more detail.
 AM_CCASFLAGS = $(AM_CPPFLAGS)
 
+if VGCONF_OS_IS_SOLARIS
+# Make sure that all test programs have threaded errno.
+AM_CFLAGS  += -D_REENTRANT
+endif
+
 if VGCONF_OS_IS_DARWIN
 noinst_DSYMS = $(check_PROGRAMS)
 endif
diff --git a/Makefile.tool.am b/Makefile.tool.am
index 41f5c97..d719882 100644
--- a/Makefile.tool.am
+++ b/Makefile.tool.am
@@ -36,6 +36,8 @@
 	-static -nodefaultlibs -nostartfiles -u _start @FLAG_NO_BUILD_ID@
 TOOL_LDFLAGS_COMMON_DARWIN = \
 	-nodefaultlibs -nostartfiles -Wl,-u,__start -Wl,-e,__start
+TOOL_LDFLAGS_COMMON_SOLARIS = \
+	-static -nodefaultlibs -nostartfiles -u _start
 
 TOOL_LDFLAGS_X86_LINUX = \
 	$(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M32@
@@ -79,6 +81,12 @@
 TOOL_LDFLAGS_TILEGX_LINUX = \
 	$(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M64@
 
+TOOL_LDFLAGS_X86_SOLARIS = \
+	$(TOOL_LDFLAGS_COMMON_SOLARIS) @FLAG_M32@
+
+TOOL_LDFLAGS_AMD64_SOLARIS = \
+	$(TOOL_LDFLAGS_COMMON_SOLARIS) @FLAG_M64@
+
 # On Android we must ask for non-executable stack, not sure why.
 if VGCONF_PLATFORMS_INCLUDE_ARM_LINUX
 if VGCONF_PLATVARIANT_IS_ANDROID
@@ -138,6 +146,12 @@
 LIBREPLACEMALLOC_TILEGX_LINUX = \
 	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-tilegx-linux.a
 
+LIBREPLACEMALLOC_X86_SOLARIS = \
+	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-solaris.a
+
+LIBREPLACEMALLOC_AMD64_SOLARIS = \
+	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-amd64-solaris.a
+
 LIBREPLACEMALLOC_LDFLAGS_X86_LINUX = \
 	-Wl,--whole-archive \
 	$(LIBREPLACEMALLOC_X86_LINUX) \
@@ -199,6 +213,16 @@
 	$(LIBREPLACEMALLOC_TILEGX_LINUX) \
 	-Wl,--no-whole-archive
 
+LIBREPLACEMALLOC_LDFLAGS_X86_SOLARIS = \
+	-Wl,--whole-archive \
+	$(LIBREPLACEMALLOC_X86_SOLARIS) \
+	-Wl,--no-whole-archive
+
+LIBREPLACEMALLOC_LDFLAGS_AMD64_SOLARIS = \
+	-Wl,--whole-archive \
+	$(LIBREPLACEMALLOC_AMD64_SOLARIS) \
+	-Wl,--no-whole-archive
+
 #----------------------------------------------------------------------------
 # General stuff
 #----------------------------------------------------------------------------
diff --git a/README.solaris b/README.solaris
new file mode 100644
index 0000000..95e6f0f
--- /dev/null
+++ b/README.solaris
@@ -0,0 +1,136 @@
+Requirements
+------------
+- You need a recent Solaris-like OS to compile this port. Solaris 11 or
+  any illumos-based distribution should work, Solaris 10 is not supported.
+  Running `uname -r` has to print '5.11'.
+- Recent GCC tools are required, GCC 3 will probably not work. GCC version
+  4.5 (or higher) is recommended.
+- Solaris ld has to be the first linker in the PATH. GNU ld cannot be used.
+  There is currently no linker check in the configure script but the linking
+  phase fails if GNU ld is used. Recent Solaris/illumos distributions are ok.
+- A working combination of autotools is required: aclocal, autoheader,
+  automake and autoconf have to be found in the PATH. You should be able to
+  install pkg:/developer/build/automake and pkg:/developer/build/autoconf
+  packages to fullfil this requirement.
+- System header files and GNU make is also required.
+- For remote debugging support, working GDB is required (see below).
+
+
+Compilation
+-----------
+Please follow the generic instructions in the README file.
+
+The configure script detects a canonical host to determine which version of
+Valgrind should be built. If the system compiler by default produces 32-bit
+binaries then only a 32-bit version of Valgrind will be built. To enable
+compilation of both 64-bit and 32-bit versions on such a system, issue the
+configure script as follows:
+./configure CC='gcc -m64' CXX='g++ -m64'
+
+
+Oracle Solaris and illumos support
+----------------------------------
+One of the main goal of this port is to support both Oracle Solaris and
+illumos kernels. This is a very hard task because Solaris kernel traditionally
+does not provide a stable syscall interface and because Valgrind contains
+several parts that are closely tied to the underlying kernel. For these
+reasons, the port needs to detect which syscall interfaces are present. This
+detection cannot be done easily at run time and is currently implemented as
+a set of configure tests. This means that a binary version of this port can be
+executed only on a kernel that is compatible with a kernel that was used
+during the configure and compilation time.
+
+Main currently-known incompatibilities:
+- Solaris 11 (released in November 2011) removed a large set of syscalls where
+  *at variant of the syscall was also present, for example, open() versus
+  openat(AT_FDCWD) [1]
+- syscall number for unlinkat() is 76 on Solaris 11, but 65 on illumos [2]
+- illumos (in April 2013) changed interface of the accept() and pipe()
+  syscalls [3]
+
+[1] http://docs.oracle.com/cd/E26502_01/html/E28556/gkzlf.html#gkzip
+[2] https://www.illumos.org/issues/521
+[3] https://github.com/illumos/illumos-gate/commit/5dbfd19ad5fcc2b779f40f80fa05c1bd28fd0b4e
+
+
+Limitations
+-----------
+- The port is Work-In-Progress, many things may not work or they can be subtly
+  broken.
+- Coredumps produced by Valgrind do not contain all information available,
+  especially microstate accounting and processor bindings.
+- Accessing contents of /proc/self/psinfo is not thread-safe.  That is because
+  Valgrind emulates this file on behalf of the client programs.  Entire
+  open() - read() - close() sequence on this file needs to be performed
+  atomically.
+- Fork limitations: vfork() is translated to fork(), forkall() is not
+  supported.
+- Valgrind does not track definedness of some eflags (OF, SF, ZF, AF, CF, PF)
+  individually for each flag. After a syscall is finished, when a carry flag
+  is set and defined, all other mentioned flags will be also defined even
+  though they might be undefined before making the syscall.
+- System call "execve" with a file descriptor which points to a hardlink
+  is currently not supported. That is because from the opened file descriptor
+  itself it is not possible to reverse map the intended pathname.
+  Examples are fexecve(3C) and isaexec(3C).
+- When a thread has no stack then all system calls will result in Valgrind
+  crash, even though such system calls use just parameters passed in registers.
+  This should happen only in pathological situations when a thread is created
+  with custom mmap'ed stack and this stack is then unmap'ed during thread
+  execution.
+
+
+Remote debugging support
+------------------------
+Solaris port of GDB has a major flaw which prevents remote debugging from
+working correctly. Fortunately this flaw has an easy fix [4]. Unfortunately
+it is not present in the current GDB 7.6.2. This boils down to several
+options:
+- Use GDB shipped with Solaris 11.2 which has this flaw fixed.
+- Wait until GDB 7.7 becomes available (there won't be other 7.6.x releases).
+- Build GDB 7.6.2 with the fix by yourself using the following steps:
+    # pkg install developer/gnu-binutils
+    $ wget http://ftp.gnu.org/gnu/gdb/gdb-7.6.2.tar.gz
+    $ gzip -dc gdb-7.6.2.tar.gz | tar xf -
+    $ cd gdb-7.6.2
+    $ patch -p1 -i /path/to/valgrind-solaris/solaris/gdb-sol-thread.patch
+    $ export LIBS="-lncurses"
+    $ export CC="gcc -m64"
+    $ ./configure --with-x=no --with-curses --with-libexpat-prefix=/usr/lib
+    $ gmake && gmake install
+
+[4] https://sourceware.org/ml/gdb-patches/2013-12/msg00573.html
+
+
+TODO list
+---------
+- Fix few remaining failing tests.
+- Add more Solaris-specific tests (especially for the door and spawn
+  syscalls).
+- Provide better error reporting for various subsyscalls.
+- Implement storing of extra register state in signal frame.
+- Performance comparison against other platforms.
+
+- Prevent SIGPIPE when writing to a socket (coregrind/m_libcfile.c).
+- Implement support for attaching a debugger (coregrind/m_debugger.c).  This
+  is a low priority task because this feature is going to be removed in
+  future versions of Valgrind in favor of using only gdbserver.
+- Implement ticket locking for fair scheduling (--fair-sched=yes).
+- Implement support in DRD and Helgrind tools for thr_join() with thread == 0.
+- Add support for accessing thread-local variables via gdb (auxprogs/getoff.c).
+  Requires research on internal libc TLS representation.
+- VEX supports AVX, BMI and AVX2. Investigate if they can be enabled on
+  Solaris/illumos.
+- Investigate support for more flags in AT_SUN_AUXFLAGS.
+- Fix Valgrind crash when a thread has no stack and syswrap-main.c accesses
+  all possible syscall parameters. Enable helgrind/tests/stackteardown.c
+  to see this in effect. Would require awareness of syscall parameter semantics.
+- Correctly print arguments of DW_CFA_ORCL_arg_loc in show_CF_instruction() when
+  it is implemented in libdwarf.
+
+
+Contacts
+--------
+Please send bug reports and any questions about the port to:
+Ivo Raisr <ivosh@ivosh.net>
+Petr Pavlu <setup@dagobah.cz>
diff --git a/README_MISSING_SYSCALL_OR_IOCTL b/README_MISSING_SYSCALL_OR_IOCTL
index 27d1ab0..ab78902 100644
--- a/README_MISSING_SYSCALL_OR_IOCTL
+++ b/README_MISSING_SYSCALL_OR_IOCTL
@@ -182,3 +182,54 @@
 As above, please create a bug report and attach the patch as described
 on http://www.valgrind.org.
 
+
+Writing your own door call wrappers (Solaris only)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Unlike syscalls or ioctls, door calls transfer data between two userspace
+programs, albeit through a kernel interface. Programs may use completely
+proprietary semantics in the data buffers passed between them.
+Therefore it may not be possible to capture these semantics within
+a Valgrind door call or door return wrapper.
+
+Nevertheless, for system or well-known door services it would be beneficial
+to have a door call and a door return wrapper. Writing such wrapper is pretty
+much the same as writing ioctl wrappers. Please take a few moments to study
+the following picture depicting how a door client and a door server interact
+through the kernel interface in a typical scenario:
+
+
+door client thread          kernel       door server thread
+invokes door_call()                     invokes door_return()
+-------------------------------------------------------------------
+                               <----  PRE(sys_door, DOOR_RETURN)
+PRE(sys_door, DOOR_CALL)  --->
+                               ---->  POST(sys_door, DOOR_RETURN)
+                                           ----> server_procedure()
+                                           <----
+                               <----  PRE(sys_door, DOOR_RETURN)
+POST(sys_door, DOOR_CALL) <---
+
+The first PRE(sys_door, DOOR_RETURN) is invoked with data_ptr=NULL
+and data_size=0. That's because it has not received any data from
+a door call, yet.
+
+Semantics are described by the following functions
+in coregring/m_syswrap/syswrap-solaris.c module:
+o For a door call wrapper the following attributes of 'params' argument:
+  - data_ptr (and associated data_size) as input buffer (request);
+      described in door_call_pre_mem_params_data()
+  - rbuf (and associated rsize) as output buffer (response);
+      described in door_call_post_mem_params_rbuf()
+o For a door return wrapper the following parameters:
+  - data_ptr (and associated data_size) as input buffer (request);
+      described in door_return_post_mem_data()
+  - data_ptr (and associated data_size) as output buffer (response);
+      described in door_return_pre_mem_data()
+
+There's a default case which may not be correct and you have to write a
+more specific case to get the right behaviour. Unless Valgrind's option
+'--sim-hints=lax-doors' is specified, the default case also spits a warning.
+
+As above, please create a bug report and attach the patch as described
+on http://www.valgrind.org.
diff --git a/auxprogs/Makefile.am b/auxprogs/Makefile.am
index 89ca89b..25391c2 100644
--- a/auxprogs/Makefile.am
+++ b/auxprogs/Makefile.am
@@ -39,6 +39,9 @@
 if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
 valgrind_listener_LDFLAGS   += -Wl,-read_only_relocs -Wl,suppress
 endif
+if VGCONF_OS_IS_SOLARIS
+valgrind_listener_LDADD      = -lsocket -lnsl
+endif
 
 valgrind_di_server_SOURCES   = valgrind-di-server.c
 valgrind_di_server_CPPFLAGS  = $(AM_CPPFLAGS_PRI) -I$(top_srcdir)/coregrind
@@ -51,6 +54,9 @@
 if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
 valgrind_di_server_LDFLAGS   += -Wl,-read_only_relocs -Wl,suppress
 endif
+if VGCONF_OS_IS_SOLARIS
+valgrind_di_server_LDADD     = -lsocket -lnsl
+endif
 
 #----------------------------------------------------------------------------
 # getoff-<platform>
diff --git a/auxprogs/valgrind-di-server.c b/auxprogs/valgrind-di-server.c
index 86c5882..5d4e157 100644
--- a/auxprogs/valgrind-di-server.c
+++ b/auxprogs/valgrind-di-server.c
@@ -90,7 +90,7 @@
 
 /* Needed to get a definition for pread() from unistd.h */
 #ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 500
+#define _XOPEN_SOURCE 600
 #endif
 
 #include <stdio.h>
diff --git a/callgrind/dump.c b/callgrind/dump.c
index 8f32138..044d69d 100644
--- a/callgrind/dump.c
+++ b/callgrind/dump.c
@@ -907,7 +907,7 @@
 
 static BBCC** qsort_start = 0;
 
-static void qsort(BBCC **a, int n, int (*cmp)(BBCC**,BBCC**))
+static void CLG_(qsort)(BBCC **a, int n, int (*cmp)(BBCC**,BBCC**))
 {
 	BBCC **pa, **pb, **pc, **pd, **pl, **pm, **pn, **pv;
 	int s, r;
@@ -1005,8 +1005,8 @@
 	    }
 	}
 
-	if ((s = pb+1-pa) > 1) qsort(a,     s, cmp);
-	if ((s = pd+1-pc) > 1) qsort(a+n-s, s, cmp);
+	if ((s = pb+1-pa) > 1) CLG_(qsort)(a,     s, cmp);
+	if ((s = pd+1-pc) > 1) CLG_(qsort)(a+n-s, s, cmp);
 }
 
 
@@ -1131,7 +1131,7 @@
     CLG_DEBUG(0,"             BBCCs inserted\n");
 
     qsort_start = array;
-    qsort(array, prepare_count, my_cmp);
+    CLG_(qsort)(array, prepare_count, my_cmp);
 
     CLG_DEBUG(0,"             BBCCs sorted\n");
 
diff --git a/configure.ac b/configure.ac
index 467d618..ff459ff 100644
--- a/configure.ac
+++ b/configure.ac
@@ -423,6 +423,18 @@
 	esac
         ;;
 
+     solaris2.11*)
+        AC_MSG_RESULT([ok (${host_os})])
+        VGCONF_OS="solaris"
+        DEFAULT_SUPP="solaris11.supp ${DEFAULT_SUPP}"
+        ;;
+
+     solaris2.12*)
+        AC_MSG_RESULT([ok (${host_os})])
+        VGCONF_OS="solaris"
+        DEFAULT_SUPP="solaris12.supp ${DEFAULT_SUPP}"
+        ;;
+
      *) 
 	AC_MSG_RESULT([no (${host_os})])
 	AC_MSG_ERROR([Valgrind is operating system specific. Sorry.])
@@ -436,7 +448,7 @@
 # does not support building 32 bit programs
 
 case "$ARCH_MAX-$VGCONF_OS" in
-     amd64-linux|ppc64be-linux|arm64-linux)
+     amd64-linux|ppc64be-linux|arm64-linux|amd64-solaris)
         AC_MSG_CHECKING([for 32 bit build support])
         safe_CFLAGS=$CFLAGS
         CFLAGS="-m32"
@@ -714,6 +726,46 @@
         valt_load_address_sec_inner="0xUNSET"
         AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
         ;;
+     x86-solaris)
+        VGCONF_ARCH_PRI="x86"
+        VGCONF_ARCH_SEC=""
+        VGCONF_PLATFORM_PRI_CAPS="X86_SOLARIS"
+        VGCONF_PLATFORM_SEC_CAPS=""
+        valt_load_address_pri_norml="0x38000000"
+        valt_load_address_pri_inner="0x28000000"
+        valt_load_address_sec_norml="0xUNSET"
+        valt_load_address_sec_inner="0xUNSET"
+        AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+        ;;
+     amd64-solaris)
+        valt_load_address_sec_norml="0xUNSET"
+        valt_load_address_sec_inner="0xUNSET"
+        if test x$vg_cv_only64bit = xyes; then
+           VGCONF_ARCH_PRI="amd64"
+           VGCONF_ARCH_SEC=""
+           VGCONF_PLATFORM_PRI_CAPS="AMD64_SOLARIS"
+           VGCONF_PLATFORM_SEC_CAPS=""
+           valt_load_address_pri_norml="0x38000000"
+           valt_load_address_pri_inner="0x28000000"
+        elif test x$vg_cv_only32bit = xyes; then
+           VGCONF_ARCH_PRI="x86"
+           VGCONF_ARCH_SEC=""
+           VGCONF_PLATFORM_PRI_CAPS="X86_SOLARIS"
+           VGCONF_PLATFORM_SEC_CAPS=""
+           valt_load_address_pri_norml="0x38000000"
+           valt_load_address_pri_inner="0x28000000"
+        else
+           VGCONF_ARCH_PRI="amd64"
+           VGCONF_ARCH_SEC="x86"
+           VGCONF_PLATFORM_PRI_CAPS="AMD64_SOLARIS"
+           VGCONF_PLATFORM_SEC_CAPS="X86_SOLARIS"
+           valt_load_address_pri_norml="0x38000000"
+           valt_load_address_pri_inner="0x28000000"
+           valt_load_address_sec_norml="0x38000000"
+           valt_load_address_sec_inner="0x28000000"
+        fi
+        AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+        ;;
     *)
         VGCONF_ARCH_PRI="unknown"
         VGCONF_ARCH_SEC="unknown"
@@ -736,10 +788,13 @@
                test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX \
                  -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
-                 -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN )
+                 -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN \
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS \
+                 -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_SOLARIS )
 AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \
-                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN )
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN \
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_SOLARIS )
 AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \ 
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX )
@@ -793,6 +848,11 @@
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN)
 AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_SOLARIS,
+               test x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS \
+                 -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_SOLARIS)
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_SOLARIS,
+               test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_SOLARIS)
 
 
 # Similarly, set up VGCONF_OS_IS_<os>.  Exactly one of these becomes defined.
@@ -813,6 +873,9 @@
 AM_CONDITIONAL(VGCONF_OS_IS_DARWIN,
                test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
                  -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
+AM_CONDITIONAL(VGCONF_OS_IS_SOLARIS,
+               test x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS \
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_SOLARIS)
 
 
 # Sometimes, in the Makefile.am files, it's useful to know whether or not
@@ -940,6 +1003,12 @@
 ],
 GLIBC_VERSION="bionic")
 
+# there is only one version of libc on Solaris
+if test x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS \
+     -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_SOLARIS; then
+    GLIBC_VERSION="solaris"
+fi
+
 
 AC_MSG_CHECKING([the glibc version])
 
@@ -990,25 +1059,32 @@
 	AC_DEFINE([BIONIC_LIBC], 1, [Define to 1 if you're using Bionic])
 	DEFAULT_SUPP="bionic.supp ${DEFAULT_SUPP}"
 	;;
+     solaris)
+	AC_MSG_RESULT(Solaris)
+	# DEFAULT_SUPP set in host_os switch-case above.
+	# No other suppression file is used.
+	;;
      2.0|2.1|*)
 	AC_MSG_RESULT([unsupported version ${GLIBC_VERSION}])
-	AC_MSG_ERROR([Valgrind requires glibc version 2.2 or later])
-	AC_MSG_ERROR([or Darwin or Bionic libc])
+	AC_MSG_ERROR([Valgrind requires glibc version 2.2 or later,])
+	AC_MSG_ERROR([Darwin libc, Bionic libc or Solaris libc])
 	;;
 esac
 
 AC_SUBST(GLIBC_VERSION)
 
 
-# Add default suppressions for the X client libraries.  Make no
-# attempt to detect whether such libraries are installed on the
-# build machine (or even if any X facilities are present); just
-# add the suppressions antidisirregardless.
-DEFAULT_SUPP="xfree-4.supp ${DEFAULT_SUPP}"
-DEFAULT_SUPP="xfree-3.supp ${DEFAULT_SUPP}"
+if test "$VGCONF_OS" != "solaris"; then
+    # Add default suppressions for the X client libraries.  Make no
+    # attempt to detect whether such libraries are installed on the
+    # build machine (or even if any X facilities are present); just
+    # add the suppressions antidisirregardless.
+    DEFAULT_SUPP="xfree-4.supp ${DEFAULT_SUPP}"
+    DEFAULT_SUPP="xfree-3.supp ${DEFAULT_SUPP}"
 
-# Add glibc and X11 suppressions for exp-sgcheck
-DEFAULT_SUPP="exp-sgcheck.supp ${DEFAULT_SUPP}"
+    # Add glibc and X11 suppressions for exp-sgcheck
+    DEFAULT_SUPP="exp-sgcheck.supp ${DEFAULT_SUPP}"
+fi
 
 
 #----------------------------------------------------------------------------
@@ -2522,6 +2598,712 @@
 
 
 #----------------------------------------------------------------------------
+# Solaris-specific checks.
+#----------------------------------------------------------------------------
+
+if test "$VGCONF_OS" = "solaris" ; then
+# Solaris-specific check determining if the Sun Studio Assembler is used to
+# build Valgrind.  The test checks if the x86/amd64 assembler understands the
+# cmovl.l instruction, if yes then it's Sun Assembler.
+#
+# C-level symbol: none
+# Automake-level symbol: SOLARIS_SUN_STUDIO_AS
+#
+AC_MSG_CHECKING([if x86/amd64 assembler speaks cmovl.l (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+]], [[
+  __asm__ __volatile__("cmovl.l %edx, %eax");
+]])], [
+solaris_have_sun_studio_as=yes
+AC_MSG_RESULT([yes])
+], [
+solaris_have_sun_studio_as=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_SUN_STUDIO_AS, test x$solaris_have_sun_studio_as = xyes)
+
+# Solaris-specific check determining if symbols __xpg4 and __xpg6
+# are present in linked elfs when gcc is invoked with -std=gnu99.
+# See solaris/vgpreload-solaris.mapfile for details.
+# gcc on Solaris instructs linker to include these symbols,
+# gcc on illumos does not.
+#
+# C-level symbol: none
+# Automake-level symbol: SOLARIS_XPG_SYMBOLS_PRESENT
+#
+save_CFLAGS="$CFLAGS"
+CFLAGS="$CFLAGS -std=gnu99"
+AC_MSG_CHECKING([if xpg symbols are present with -std=gnu99 (Solaris-specific)])
+AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, const char *argv[]) {
+    char command[PATH_MAX + 50];
+    snprintf(command, sizeof(command), "nm %s | egrep '__xpg[4,6]'", argv[0]);
+
+    FILE *output = popen(command, "r");
+    if (output == NULL) return -1;
+
+    char buf[100];
+    if (fgets(buf, sizeof(buf), output) != NULL) {
+        pclose(output);
+        return 0;
+    } else {
+        pclose(output);
+        return 1;
+    }
+}
+]])], [
+solaris_xpg_symbols_present=yes
+AC_MSG_RESULT([yes])
+], [
+solaris_xpg_symbols_present=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_XPG_SYMBOLS_PRESENT, test x$solaris_xpg_symbols_present = xyes)
+CFLAGS="$save_CFLAGS"
+
+
+# Solaris-specific check determining default platform for the Valgrind launcher.
+# Used in case the launcher cannot select platform by looking at the client
+# image (for example because the executable is a shell script).
+#
+# C-level symbol: SOLARIS_LAUNCHER_DEFAULT_PLATFORM
+# Automake-level symbol: none
+#
+AC_MSG_CHECKING([for default platform of Valgrind launcher (Solaris-specific)])
+# Get the ELF class of /bin/sh first.
+if ! test -f /bin/sh; then
+  AC_MSG_ERROR([Shell interpreter `/bin/sh' not found.])
+fi
+elf_class=$( /usr/bin/file /bin/sh | sed -n 's/.*ELF \(..\)-bit.*/\1/p' )
+case "$elf_class" in
+  64)
+    default_arch="$VGCONF_ARCH_PRI";
+    ;;
+  32)
+    if test "x$VGCONF_ARCH_SEC" != "x"; then
+      default_arch="$VGCONF_ARCH_SEC"
+    else
+      default_arch="$VGCONF_ARCH_PRI";
+    fi
+    ;;
+  *)
+    AC_MSG_ERROR([Cannot determine ELF class of `/bin/sh'.])
+    ;;
+esac
+default_platform="$default_arch-$VGCONF_OS"
+AC_MSG_RESULT([$default_platform])
+AC_DEFINE_UNQUOTED([SOLARIS_LAUNCHER_DEFAULT_PLATFORM], ["$default_platform"],
+                   [Default platform for Valgrind launcher.])
+
+
+# Solaris-specific check determining if the old syscalls are available.
+#
+# C-level symbol: SOLARIS_OLD_SYSCALLS
+# Automake-level symbol: SOLARIS_OLD_SYSCALLS
+#
+AC_MSG_CHECKING([for the old Solaris syscalls (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_open;
+]])], [
+solaris_old_syscalls=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_OLD_SYSCALLS], 1,
+          [Define to 1 if you have the old Solaris syscalls.])
+], [
+solaris_old_syscalls=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_OLD_SYSCALLS, test x$solaris_old_syscalls = xyes)
+
+
+# Solaris-specific check determining if the new accept() syscall is available.
+#
+# Old syscall:
+# int accept(int sock, struct sockaddr *name, socklen_t *namelenp,
+#            int version);
+#
+# New syscall (available on illumos):
+# int accept(int sock, struct sockaddr *name, socklen_t *namelenp,
+#            int version, int flags);
+#
+# If the old syscall is present then the following syscall will fail with
+# ENOTSOCK (because file descriptor 0 is not a socket), if the new syscall is
+# available then it will fail with EINVAL (because the flags parameter is
+# invalid).
+#
+# C-level symbol: SOLARIS_NEW_ACCEPT_SYSCALL
+# Automake-level symbol: none
+#
+AC_MSG_CHECKING([for the new `accept' syscall (Solaris-specific)])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+#include <errno.h>
+]], [[
+  errno = 0;
+  syscall(SYS_accept, 0, 0, 0, 0, -1);
+  return !(errno == EINVAL);
+]])], [
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_NEW_ACCEPT_SYSCALL], 1,
+          [Define to 1 if you have the new `accept' syscall.])
+], [
+AC_MSG_RESULT([no])
+])
+
+
+# Solaris-specific check determining if the new illumos pipe() syscall is
+# available.
+#
+# Old syscall:
+# longlong_t pipe();
+#
+# New syscall (available on illumos):
+# int pipe(intptr_t arg, int flags);
+#
+# If the old syscall is present then the following call will succeed, if the
+# new syscall is available then it will fail with EFAULT (because address 0
+# cannot be accessed).
+#
+# C-level symbol: SOLARIS_NEW_PIPE_SYSCALL
+# Automake-level symbol: none
+#
+AC_MSG_CHECKING([for the new `pipe' syscall (Solaris-specific)])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+#include <errno.h>
+]], [[
+  errno = 0;
+  syscall(SYS_pipe, 0, 0);
+  return !(errno == EFAULT);
+]])], [
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_NEW_PIPE_SYSCALL], 1,
+          [Define to 1 if you have the new `pipe' syscall.])
+], [
+AC_MSG_RESULT([no])
+])
+
+
+# Solaris-specific check determining if the new lwp_sigqueue() syscall is
+# available.
+#
+# Old syscall:
+# int lwp_kill(id_t lwpid, int sig);
+#
+# New syscall (available on Solaris 11):
+# int lwp_sigqueue(id_t lwpid, int sig, void *value,
+#                  int si_code, timespec_t *timeout);
+#
+# C-level symbol: SOLARIS_LWP_SIGQUEUE_SYSCALL
+# Automake-level symbol: SOLARIS_LWP_SIGQUEUE_SYSCALL
+#
+AC_MSG_CHECKING([for the new `lwp_sigqueue' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h> 
+]], [[
+  return !SYS_lwp_sigqueue;
+]])], [
+solaris_lwp_sigqueue_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_LWP_SIGQUEUE_SYSCALL], 1,
+          [Define to 1 if you have the new `lwp_sigqueue' syscall.])
+], [
+solaris_lwp_sigqueue_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_LWP_SIGQUEUE_SYSCALL, test x$solaris_lwp_sigqueue_syscall = xyes)
+
+
+# Solaris-specific check determining if the lwp_sigqueue() syscall
+# takes both pid and thread id arguments or just thread id.
+#
+# Old syscall (available on Solaris 11.x):
+# int lwp_sigqueue(id_t lwpid, int sig, void *value,
+#                  int si_code, timespec_t *timeout);
+#
+# New syscall (available on Solaris 12):
+# int lwp_sigqueue(pid_t pid, id_t lwpid, int sig, void *value,
+#                  int si_code, timespec_t *timeout);
+#
+# If the old syscall is present then the following syscall will fail with
+# EINVAL (because signal is out of range); if the new syscall is available
+# then it will fail with ESRCH (because it would not find such thread in the
+# current process).
+#
+# C-level symbol: SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID
+# Automake-level symbol: SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID
+#
+AM_COND_IF(SOLARIS_LWP_SIGQUEUE_SYSCALL,
+AC_MSG_CHECKING([if the `lwp_sigqueue' syscall accepts pid (Solaris-specific)])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+#include <errno.h>
+]], [[
+  errno = 0;
+  syscall(SYS_lwp_sigqueue, 0, 101, 0, 0, 0, 0);
+  return !(errno == ESRCH);
+]])], [
+solaris_lwp_sigqueue_syscall_takes_pid=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID], 1,
+          [Define to 1 if you have the new `lwp_sigqueue' syscall which accepts pid.])
+], [
+solaris_lwp_sigqueue_syscall_takes_pid=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID,
+               test x$solaris_lwp_sigqueue_syscall_takes_pid = xyes)
+,
+AM_CONDITIONAL(SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID, test x = y)
+)
+
+
+# Solaris-specific check determining if the new lwp_name() syscall is
+# available.
+#
+# New syscall (available on Solaris 11):
+# int lwp_name(int opcode, id_t lwpid, char *name, size_t len);
+#
+# C-level symbol: SOLARIS_LWP_NAME_SYSCALL
+# Automake-level symbol: SOLARIS_LWP_NAME_SYSCALL
+#
+AC_MSG_CHECKING([for the new `lwp_name' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_lwp_name;
+]])], [
+solaris_lwp_name_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_LWP_NAME_SYSCALL], 1,
+          [Define to 1 if you have the new `lwp_name' syscall.])
+], [
+solaris_lwp_name_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_LWP_NAME_SYSCALL, test x$solaris_lwp_name_syscall = xyes)
+
+
+# Solaris-specific check determining if the new zone() syscall subcodes
+# ZONE_LIST_DEFUNCT and ZONE_GETATTR_DEFUNCT are available.  These subcodes
+# were added in Solaris 11 but are missing on illumos.
+#
+# C-level symbol: SOLARIS_ZONE_DEFUNCT
+# Automake-level symbol: SOLARIS_ZONE_DEFUNCT
+#
+AC_MSG_CHECKING([for ZONE_LIST_DEFUNCT and ZONE_GETATTR_DEFUNCT (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/zone.h>
+]], [[
+  return !(ZONE_LIST_DEFUNCT && ZONE_GETATTR_DEFUNCT);
+]])], [
+solaris_zone_defunct=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_ZONE_DEFUNCT], 1,
+          [Define to 1 if you have the `ZONE_LIST_DEFUNCT' and `ZONE_GETATTR_DEFUNC' constants.])
+], [
+solaris_zone_defunct=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_ZONE_DEFUNCT, test x$solaris_zone_defunct = xyes)
+
+
+# Solaris-specific check determining if the new shmsys() syscall subcodes
+# IPC_XSTAT64, SHMADV, SHM_ADV_GET, SHM_ADV_SET and SHMGET_OSM are available.
+# These subcodes were added in Solaris 11 but are missing on illumos.
+#
+# C-level symbol: SOLARIS_SHM_NEW
+# Automake-level symbol: SOLARIS_SHM_NEW
+#
+AC_MSG_CHECKING([for SHMADV, SHM_ADV_GET, SHM_ADV_SET and SHMGET_OSM (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/ipc_impl.h>
+#include <sys/shm.h>
+#include <sys/shm_impl.h>
+]], [[
+  return !(IPC_XSTAT64 && SHMADV && SHM_ADV_GET && SHM_ADV_SET && SHMGET_OSM);
+]])], [
+solaris_shm_new=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_SHM_NEW], 1,
+          [Define to 1 if you have the `IPC_XSTAT64', `SHMADV', `SHM_ADV_GET', `SHM_ADV_SET' and `SHMGET_OSM' constants.])
+], [
+solaris_shm_new=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_SHM_NEW, test x$solaris_shm_new = xyes)
+
+
+# Solaris-specific check determining if prxregset_t is available.  Illumos
+# currently does not define it on the x86 platform.
+#
+# C-level symbol: SOLARIS_PRXREGSET_T
+# Automake-level symbol: SOLARIS_PRXREGSET_T
+#
+AC_MSG_CHECKING([for the `prxregset_t' type (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/procfs_isa.h>
+]], [[
+  return !sizeof(prxregset_t);
+]])], [
+solaris_prxregset_t=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_PRXREGSET_T], 1,
+          [Define to 1 if you have the `prxregset_t' type.])
+], [
+solaris_prxregset_t=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_PRXREGSET_T, test x$solaris_prxregset_t = xyes)
+
+
+# Solaris-specific check determining if the new frealpathat() syscall is
+# available.
+#
+# New syscall (available on Solaris 11.1):
+# int frealpathat(int fd, char *path, char *buf, size_t buflen);
+#
+# C-level symbol: SOLARIS_FREALPATHAT_SYSCALL
+# Automake-level symbol: SOLARIS_FREALPATHAT_SYSCALL
+#
+AC_MSG_CHECKING([for the new `frealpathat' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_frealpathat;
+]])], [
+solaris_frealpathat_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_FREALPATHAT_SYSCALL], 1,
+          [Define to 1 if you have the new `frealpathat' syscall.])
+], [
+solaris_frealpathat_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_FREALPATHAT_SYSCALL, test x$solaris_frealpathat_syscall = xyes)
+
+
+# Solaris-specific check determining if the new uuidsys() syscall is
+# available.
+#
+# New syscall (available on newer Solaris):
+# int uuidsys(struct uuid *uuid);
+#
+# C-level symbol: SOLARIS_UUIDSYS_SYSCALL
+# Automake-level symbol: SOLARIS_UUIDSYS_SYSCALL
+#
+AC_MSG_CHECKING([for the new `uuidsys' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_uuidsys;
+]])], [
+solaris_uuidsys_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_UUIDSYS_SYSCALL], 1,
+          [Define to 1 if you have the new `uuidsys' syscall.])
+], [
+solaris_uuidsys_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_UUIDSYS_SYSCALL, test x$solaris_uuidsys_syscall = xyes)
+
+
+# Solaris-specific check determining if the new labelsys() syscall subcode
+# TNDB_GET_TNIP is available.  This subcode was added in Solaris 11 but is
+# missing on illumos.
+#
+# C-level symbol: SOLARIS_TNDB_GET_TNIP
+# Automake-level symbol: SOLARIS_TNDB_GET_TNIP
+#
+AC_MSG_CHECKING([for TNDB_GET_TNIP (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/tsol/tndb.h>
+]], [[
+  return !TNDB_GET_TNIP;
+]])], [
+solaris_tndb_get_tnip=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_TNDB_GET_TNIP], 1,
+          [Define to 1 if you have the `TNDB_GET_TNIP' constant.])
+], [
+solaris_tndb_get_tnip=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_TNDB_GET_TNIP, test x$solaris_tndb_get_tnip = xyes)
+
+
+# Solaris-specific check determining if the new labelsys() syscall opcodes
+# TSOL_GETCLEARANCE and TSOL_SETCLEARANCE are available. These opcodes were
+# added in Solaris 11 but are missing on illumos.
+#
+# C-level symbol: SOLARIS_TSOL_CLEARANCE
+# Automake-level symbol: SOLARIS_TSOL_CLEARANCE
+#
+AC_MSG_CHECKING([for TSOL_GETCLEARANCE and TSOL_SETCLEARANCE (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/tsol/tsyscall.h>
+]], [[
+  return !(TSOL_GETCLEARANCE && TSOL_SETCLEARANCE);
+]])], [
+solaris_tsol_clearance=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_TSOL_CLEARANCE], 1,
+          [Define to 1 if you have the `TSOL_GETCLEARANCE' and `TSOL_SETCLEARANCE' constants.])
+], [
+solaris_tsol_clearance=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_TSOL_CLEARANCE, test x$solaris_tsol_clearance = xyes)
+
+
+# Solaris-specific check determining if the utimesys() syscall is
+# available (on illumos and older Solaris).
+#
+# C-level symbol: SOLARIS_UTIMESYS_SYSCALL
+# Automake-level symbol: SOLARIS_UTIMESYS_SYSCALL
+#
+AC_MSG_CHECKING([for the `utimesys' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_utimesys;
+]])], [
+solaris_utimesys_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_UTIMESYS_SYSCALL], 1,
+          [Define to 1 if you have the `utimesys' syscall.])
+], [
+solaris_utimesys_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_UTIMESYS_SYSCALL, test x$solaris_utimesys_syscall = xyes)
+
+
+# Solaris-specific check determining if the utimensat() syscall is
+# available (on newer Solaris).
+#
+# C-level symbol: SOLARIS_UTIMENSAT_SYSCALL
+# Automake-level symbol: SOLARIS_UTIMENSAT_SYSCALL
+#
+AC_MSG_CHECKING([for the `utimensat' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_utimensat;
+]])], [
+solaris_utimensat_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_UTIMENSAT_SYSCALL], 1,
+          [Define to 1 if you have the `utimensat' syscall.])
+], [
+solaris_utimensat_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_UTIMENSAT_SYSCALL, test x$solaris_utimensat_syscall = xyes)
+
+
+# Solaris-specific check determining if the spawn() syscall is available
+# (on newer Solaris).
+#
+# C-level symbol: SOLARIS_SPAWN_SYSCALL
+# Automake-level symbol: SOLARIS_SPAWN_SYSCALL
+#
+AC_MSG_CHECKING([for the `spawn' syscall (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+]], [[
+  return !SYS_spawn;
+]])], [
+solaris_spawn_syscall=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_SPAWN_SYSCALL], 1,
+          [Define to 1 if you have the `spawn' syscall.])
+], [
+solaris_spawn_syscall=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_SPAWN_SYSCALL, test x$solaris_spawn_syscall = xyes)
+
+
+# Solaris-specific check determining whether nscd (name switch cache daemon)
+# attaches its door at /system/volatile/name_service_door (Solaris)
+# or at /var/run/name_service_door (illumos).
+#
+# Note that /var/run is a symlink to /system/volatile on Solaris
+# but not vice versa on illumos.
+#
+# C-level symbol: SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE
+# Automake-level symbol: SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE
+#
+AC_MSG_CHECKING([for nscd door location (Solaris-specific)])
+if test -e /system/volatile/name_service_door; then
+    solaris_nscd_door_system_volatile=yes
+    AC_MSG_RESULT([/system/volatile/name_service_door])
+    AC_DEFINE([SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE], 1,
+              [Define to 1 if nscd attaches to /system/volatile/name_service_door.])
+else
+    solaris_nscd_door_system_volatile=no
+    AC_MSG_RESULT([/var/run/name_service_door])
+fi
+AM_CONDITIONAL(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE, test x$solaris_nscd_door_system_volatile = xyes)
+
+
+# Solaris-specific check determining if the new gethrt() fasttrap is available.
+#
+# New fasttrap (available on Solaris 11):
+# hrt_t *gethrt(void);
+#
+# C-level symbol: SOLARIS_GETHRT_FASTTRAP
+# Automake-level symbol: SOLARIS_GETHRT_FASTTRAP
+#
+AC_MSG_CHECKING([for the new `gethrt' fasttrap (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/trap.h>
+]], [[
+  return !T_GETHRT;
+]])], [
+solaris_gethrt_fasttrap=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_GETHRT_FASTTRAP], 1,
+          [Define to 1 if you have the new `gethrt' fasttrap.])
+], [
+solaris_gethrt_fasttrap=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_GETHRT_FASTTRAP, test x$solaris_gethrt_fasttrap = xyes)
+
+
+# Solaris-specific check determining if the new get_zone_offset() fasttrap
+# is available.
+#
+# New fasttrap (available on Solaris 11):
+# zonehrtoffset_t *get_zone_offset(void);
+#
+# C-level symbol: SOLARIS_GETZONEOFFSET_FASTTRAP
+# Automake-level symbol: SOLARIS_GETZONEOFFSET_FASTTRAP
+#
+AC_MSG_CHECKING([for the new `get_zone_offset' fasttrap (Solaris-specific)])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/trap.h>
+]], [[
+  return !T_GETZONEOFFSET;
+]])], [
+solaris_getzoneoffset_fasttrap=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_GETZONEOFFSET_FASTTRAP], 1,
+          [Define to 1 if you have the new `get_zone_offset' fasttrap.])
+], [
+solaris_getzoneoffset_fasttrap=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_GETZONEOFFSET_FASTTRAP, test x$solaris_getzoneoffset_fasttrap = xyes)
+
+
+# Solaris-specific check determining if the execve() syscall
+# takes fourth argument (flags) or not.
+#
+# Old syscall (available on illumos):
+# int execve(const char *fname, const char **argv, const char **envp);
+#
+# New syscall (available on Solaris):
+# int execve(uintptr_t file, const char **argv, const char **envp, int flags);
+#
+# If the new syscall is present then it will fail with EINVAL (because flags
+# are invalid); if the old syscall is available then it will fail with ENOENT
+# (because the file could not be found).
+#
+# C-level symbol: SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS
+# Automake-level symbol: SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS
+#
+AC_MSG_CHECKING([if the `execve' syscall accepts flags (Solaris-specific)])
+AC_RUN_IFELSE([AC_LANG_PROGRAM([[
+#include <sys/syscall.h>
+#include <errno.h>
+]], [[
+  errno = 0;
+  syscall(SYS_execve, "/no/existing/path", 0, 0, 0xdeadbeef, 0, 0);
+  return !(errno == EINVAL);
+]])], [
+solaris_execve_syscall_takes_flags=yes
+AC_MSG_RESULT([yes])
+AC_DEFINE([SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS], 1,
+          [Define to 1 if you have the new `execve' syscall which accepts flags.])
+], [
+solaris_execve_syscall_takes_flags=no
+AC_MSG_RESULT([no])
+])
+AM_CONDITIONAL(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS,
+               test x$solaris_execve_syscall_takes_flags = xyes)
+
+
+# Solaris-specific check determining version of the repository cache protocol.
+# Every Solaris version uses a different one, ranging from 21 to current 25.
+# The check is very ugly, though.
+#
+# C-level symbol: SOLARIS_REPCACHE_PROTOCOL_VERSION vv
+# Automake-level symbol: none
+#
+AC_PATH_PROG(DIS_PATH, dis, false)
+if test "x$DIS_PATH" = "xfalse"; then
+  AC_MSG_FAILURE([Object code disassembler (`dis') not found.])
+fi
+AC_CHECK_LIB(scf, scf_handle_bind, [], [
+  AC_MSG_WARN([Function `scf_handle_bind' was not found in `libscf'.])
+  AC_MSG_ERROR([Cannot determine version of the repository cache protocol.])
+])
+
+AC_MSG_CHECKING([for version of the repository cache protocol (Solaris-specific)])
+if test "X$VGCONF_ARCH_PRI" = "Xamd64"; then
+  libscf=/usr/lib/64/libscf.so.1
+else
+  libscf=/usr/lib/libscf.so.1
+fi
+if ! $DIS_PATH -F scf_handle_bind $libscf  | grep -q 0x526570; then
+  AC_MSG_WARN([Function `scf_handle_bind' does not contain repository cache protocol version.])
+  AC_MSG_ERROR([Cannot determine version of the repository cache protocol.])
+fi
+hex=$( $DIS_PATH -F scf_handle_bind $libscf  | sed -n 's/.*0x526570\(..\).*/\1/p' )
+if test -z "$hex"; then
+  AC_MSG_WARN([Version of the repository cache protocol is empty?!])
+  AC_MSG_ERROR([Cannot determine version of the repository cache protocol.])
+fi
+version=$( printf "%d\n" 0x$hex )
+AC_MSG_RESULT([$version])
+AC_DEFINE_UNQUOTED([SOLARIS_REPCACHE_PROTOCOL_VERSION], [$version],
+                   [Version number of the repository door cache protocol.])
+
+else
+AM_CONDITIONAL(SOLARIS_SUN_STUDIO_AS, false)
+AM_CONDITIONAL(SOLARIS_XPG_SYMBOLS_PRESENT, false)
+AM_CONDITIONAL(SOLARIS_OLD_SYSCALLS, false)
+AM_CONDITIONAL(SOLARIS_LWP_SIGQUEUE_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID, false)
+AM_CONDITIONAL(SOLARIS_LWP_NAME_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_ZONE_DEFUNCT, false)
+AM_CONDITIONAL(SOLARIS_SHM_NEW, false)
+AM_CONDITIONAL(SOLARIS_PRXREGSET_T, false)
+AM_CONDITIONAL(SOLARIS_FREALPATHAT_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_UUIDSYS_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_TNDB_GET_TNIP, false)
+AM_CONDITIONAL(SOLARIS_TSOL_CLEARANCE, false)
+AM_CONDITIONAL(SOLARIS_UTIMESYS_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_UTIMENSAT_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_SPAWN_SYSCALL, false)
+AM_CONDITIONAL(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE, false)
+AM_CONDITIONAL(SOLARIS_GETHRT_FASTTRAP, false)
+AM_CONDITIONAL(SOLARIS_GETZONEOFFSET_FASTTRAP, false)
+AM_CONDITIONAL(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS, false)
+fi # test "$VGCONF_OS" = "solaris"
+
+
+#----------------------------------------------------------------------------
 # Checks for C header files.
 #----------------------------------------------------------------------------
 
@@ -2535,6 +3317,7 @@
         sys/eventfd.h    \
         sys/klog.h       \
         sys/poll.h       \
+        sys/prctl.h      \
         sys/signal.h     \
         sys/signalfd.h   \
         sys/syscall.h    \
@@ -2651,7 +3434,8 @@
      -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
      -o x$VGCONF_PLATFORM_PRI_CAPS = xARM_LINUX \
      -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \
-     -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX ; then
+     -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \
+     -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS ; then
   mflag_primary=$FLAG_M32
 elif test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \
        -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX \
@@ -2666,7 +3450,8 @@
 
 mflag_secondary=
 if test x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX \
-     -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX ; then
+     -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX \
+     -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_SOLARIS ; then
   mflag_secondary=$FLAG_M32
 elif test x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN ; then
   mflag_secondary="$FLAG_M32 -arch i386"
@@ -2690,6 +3475,9 @@
 AM_COND_IF([VGCONF_OS_IS_DARWIN],
            [CFLAGS_MPI="-g -O -fno-omit-frame-pointer -Wall -dynamic"
             LDFLAGS_MPI="-dynamic -dynamiclib -all_load"])
+AM_COND_IF([VGCONF_OS_IS_SOLARIS],
+           [CFLAGS_MPI="-g -O -fno-omit-frame-pointer -Wall -fpic"
+            LDFLAGS_MPI="-fpic -shared"])
 
 AC_SUBST([CFLAGS_MPI])
 AC_SUBST([LDFLAGS_MPI])
@@ -3100,6 +3888,7 @@
    perf/Makefile 
    perf/vg_perf
    gdbserver_tests/Makefile
+   gdbserver_tests/solaris/Makefile
    include/Makefile 
    auxprogs/Makefile
    mpi/Makefile
@@ -3111,8 +3900,11 @@
    memcheck/tests/x86/Makefile
    memcheck/tests/linux/Makefile
    memcheck/tests/darwin/Makefile
+   memcheck/tests/solaris/Makefile
    memcheck/tests/amd64-linux/Makefile
    memcheck/tests/x86-linux/Makefile
+   memcheck/tests/amd64-solaris/Makefile
+   memcheck/tests/x86-solaris/Makefile
    memcheck/tests/ppc32/Makefile
    memcheck/tests/ppc64/Makefile
    memcheck/tests/s390x/Makefile
@@ -3148,10 +3940,13 @@
    none/tests/tilegx/Makefile
    none/tests/linux/Makefile
    none/tests/darwin/Makefile
+   none/tests/solaris/Makefile
    none/tests/amd64-linux/Makefile
    none/tests/x86-linux/Makefile
    none/tests/amd64-darwin/Makefile
    none/tests/x86-darwin/Makefile
+   none/tests/amd64-solaris/Makefile
+   none/tests/x86-solaris/Makefile
    exp-sgcheck/Makefile
    exp-sgcheck/tests/Makefile
    drd/Makefile
@@ -3167,11 +3962,14 @@
    exp-dhat/Makefile
    exp-dhat/tests/Makefile
    shared/Makefile
+   solaris/Makefile
 ])
 AC_CONFIG_FILES([coregrind/link_tool_exe_linux],
                 [chmod +x coregrind/link_tool_exe_linux])
 AC_CONFIG_FILES([coregrind/link_tool_exe_darwin],
                 [chmod +x coregrind/link_tool_exe_darwin])
+AC_CONFIG_FILES([coregrind/link_tool_exe_solaris],
+                [chmod +x coregrind/link_tool_exe_solaris])
 AC_OUTPUT
 
 cat<<EOF
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index a5491ea..934d99e 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -44,6 +44,11 @@
 	launcher-darwin.c \
 	m_debuglog.c
 endif
+if VGCONF_OS_IS_SOLARIS
+valgrind_SOURCES = \
+	launcher-linux.c \
+	m_debuglog.c
+endif
 
 valgrind_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
 valgrind_CFLAGS    = $(AM_CFLAGS_PRI)
@@ -73,6 +78,9 @@
 # having access to Darwin, 'none' implementation is used.
 vgdb_SOURCES += vgdb-invoker-none.c
 endif
+if VGCONF_OS_IS_SOLARIS
+vgdb_SOURCES += vgdb-invoker-solaris.c
+endif
 
 vgdb_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
 vgdb_CFLAGS    = $(AM_CFLAGS_PRI)
@@ -81,9 +89,13 @@
 if VGCONF_PLATVARIANT_IS_ANDROID
 vgdb_CFLAGS    += -static
 endif
+if VGCONF_OS_IS_SOLARIS
+vgdb_LDADD     = -lsocket
+else
 if !VGCONF_PLATVARIANT_IS_ANDROID
 vgdb_LDADD     = -lpthread
 endif
+endif
 if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
 vgdb_LDFLAGS   += -Wl,-read_only_relocs -Wl,suppress
 endif
@@ -249,6 +261,7 @@
 	m_syswrap/priv_syswrap-linux.h \
 	m_syswrap/priv_syswrap-linux-variants.h \
 	m_syswrap/priv_syswrap-darwin.h \
+	m_syswrap/priv_syswrap-solaris.h \
 	m_syswrap/priv_syswrap-main.h \
 	m_syswrap/priv_syswrap-xen.h \
 	m_ume/priv_ume.h \
@@ -316,6 +329,7 @@
 	m_aspacemgr/aspacemgr-segnames.c \
 	m_coredump/coredump-elf.c \
 	m_coredump/coredump-macho.c \
+	m_coredump/coredump-solaris.c \
 	m_debuginfo/misc.c \
 	m_debuginfo/d3basics.c \
 	m_debuginfo/debuginfo.c \
@@ -347,6 +361,8 @@
 	m_dispatch/dispatch-tilegx-linux.S \
 	m_dispatch/dispatch-x86-darwin.S \
 	m_dispatch/dispatch-amd64-darwin.S \
+	m_dispatch/dispatch-x86-solaris.S \
+	m_dispatch/dispatch-amd64-solaris.S \
 	m_gdbserver/inferiors.c \
 	m_gdbserver/m_gdbserver.c \
 	m_gdbserver/regcache.c \
@@ -368,6 +384,7 @@
 	m_gdbserver/version.c \
 	m_initimg/initimg-linux.c \
 	m_initimg/initimg-darwin.c \
+	m_initimg/initimg-solaris.c \
 	m_initimg/initimg-pathscan.c \
 	m_mach/mach_basics.c \
 	m_mach/mach_msg.c \
@@ -391,6 +408,7 @@
 	m_sigframe/sigframe-tilegx-linux.c \
 	m_sigframe/sigframe-x86-darwin.c \
 	m_sigframe/sigframe-amd64-darwin.c \
+	m_sigframe/sigframe-solaris.c \
 	m_syswrap/syscall-x86-linux.S \
 	m_syswrap/syscall-amd64-linux.S \
 	m_syswrap/syscall-ppc32-linux.S \
@@ -404,11 +422,14 @@
 	m_syswrap/syscall-tilegx-linux.S \
 	m_syswrap/syscall-x86-darwin.S \
 	m_syswrap/syscall-amd64-darwin.S \
+	m_syswrap/syscall-x86-solaris.S \
+	m_syswrap/syscall-amd64-solaris.S \
 	m_syswrap/syswrap-main.c \
 	m_syswrap/syswrap-generic.c \
 	m_syswrap/syswrap-linux.c \
 	m_syswrap/syswrap-linux-variants.c \
 	m_syswrap/syswrap-darwin.c \
+	m_syswrap/syswrap-solaris.c \
 	m_syswrap/syswrap-x86-linux.c \
 	m_syswrap/syswrap-amd64-linux.c \
 	m_syswrap/syswrap-ppc32-linux.c \
@@ -422,6 +443,8 @@
 	m_syswrap/syswrap-x86-darwin.c \
 	m_syswrap/syswrap-amd64-darwin.c \
 	m_syswrap/syswrap-xen.c \
+	m_syswrap/syswrap-x86-solaris.c \
+	m_syswrap/syswrap-amd64-solaris.c \
 	m_ume/elf.c \
 	m_ume/macho.c \
 	m_ume/main.c \
@@ -517,6 +540,17 @@
 	$(PRELOAD_LDFLAGS_@VGCONF_PLATFORM_SEC_CAPS@)
 endif
 
+if VGCONF_OS_IS_SOLARIS
+# Give the vgpreload_core library a proper soname so it can be easily
+# recognized during reading of debug information.
+vgpreload_core_@VGCONF_ARCH_PRI@_@VGCONF_OS@_so_LDFLAGS += \
+	-Wl,-soname -Wl,vgpreload_core.so.0
+if VGCONF_HAVE_PLATFORM_SEC
+vgpreload_core_@VGCONF_ARCH_SEC@_@VGCONF_OS@_so_LDFLAGS += \
+	-Wl,-soname -Wl,vgpreload_core.so.0
+endif
+endif
+
 #----------------------------------------------------------------------------
 # gdbserver xml target descriptions
 #----------------------------------------------------------------------------
diff --git a/coregrind/launcher-linux.c b/coregrind/launcher-linux.c
index a5ebb02..ceeb729 100644
--- a/coregrind/launcher-linux.c
+++ b/coregrind/launcher-linux.c
@@ -203,6 +203,14 @@
          const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
 
          if (header[EI_DATA] == ELFDATA2LSB) {
+#           if defined(VGO_solaris)
+            if (ehdr->e_machine == EM_386 &&
+                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
+                 ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS)) {
+               platform = "x86-solaris";
+            }
+            else
+#           endif
             if (ehdr->e_machine == EM_386 &&
                 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
                  ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
@@ -239,6 +247,14 @@
          const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header;
 
          if (header[EI_DATA] == ELFDATA2LSB) {
+#           if defined(VGO_solaris)
+            if (ehdr->e_machine == EM_X86_64 &&
+                (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
+                 ehdr->e_ident[EI_OSABI] == ELFOSABI_SOLARIS)) {
+               platform = "amd64-solaris";
+            }
+            else
+#           endif
             if (ehdr->e_machine == EM_X86_64 &&
                 (ehdr->e_ident[EI_OSABI] == ELFOSABI_SYSV ||
                  ehdr->e_ident[EI_OSABI] == ELFOSABI_LINUX)) {
@@ -302,6 +318,7 @@
    const char *platform;
    const char *default_platform;
    const char *cp;
+   const char *linkname;
    char *toolfile;
    const char *launcher_name;
    char* new_line;
@@ -346,6 +363,7 @@
       typically it is the primary build target. Unless the primary build
       target is not built is not built in which case VG_PLATFORM is the
       secondary build target. */
+#  if defined(VGO_linux)
    if ((0==strcmp(VG_PLATFORM,"x86-linux"))    ||
        (0==strcmp(VG_PLATFORM,"amd64-linux"))  ||
        (0==strcmp(VG_PLATFORM,"ppc32-linux"))  ||
@@ -358,6 +376,13 @@
        (0==strcmp(VG_PLATFORM,"mips32-linux")) ||
        (0==strcmp(VG_PLATFORM,"mips64-linux")))
       default_platform = VG_PLATFORM;
+#  elif defined(VGO_solaris)
+   if ((0==strcmp(VG_PLATFORM,"x86-solaris")) ||
+       (0==strcmp(VG_PLATFORM,"amd64-solaris")))
+      default_platform = SOLARIS_LAUNCHER_DEFAULT_PLATFORM;
+#  else
+#    error Unknown OS
+#  endif
    else
       barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM);
 
@@ -380,6 +405,13 @@
    /* Figure out the name of this executable (viz, the launcher), so
       we can tell stage2.  stage2 will use the name for recursive
       invocations of valgrind on child processes. */
+#  if defined(VGO_linux)
+   linkname = "/proc/self/exe";
+#  elif defined(VGO_solaris)
+   linkname = "/proc/self/path/a.out";
+#  else
+#    error Unknown OS
+#  endif
    unsigned bufsiz = 0;
    char *buf = NULL;
 
@@ -388,14 +420,14 @@
       buf = realloc(buf, bufsiz);
       if (buf == NULL)
          barf("realloc of buf failed.");
-      r = readlink("/proc/self/exe", buf, bufsiz);
+      r = readlink(linkname, buf, bufsiz);
       if (r == -1) {
-        /* If /proc/self/exe can't be followed, don't give up.  Instead
-           continue with an empty string for VALGRIND_LAUNCHER.  In the
-           sys_execve wrapper, this is tested, and if found to be empty,
+        /* If /proc/self/exe (/proc/self/path/a.out) can't be followed, don't
+           give up. Instead continue with an empty string for VALGRIND_LAUNCHER.
+           In the sys_execve wrapper, this is tested, and if found to be empty,
            fail the execve. */
         fprintf(stderr, "valgrind: warning (non-fatal): "
-                "readlink(\"/proc/self/exe\") failed.\n");
+                "readlink(\"%s\") failed.\n", linkname);
         fprintf(stderr, "valgrind: continuing, however --trace-children=yes "
                 "will not work.\n");
         launcher_name = "";
diff --git a/coregrind/link_tool_exe_solaris.in b/coregrind/link_tool_exe_solaris.in
new file mode 100644
index 0000000..795220f
--- /dev/null
+++ b/coregrind/link_tool_exe_solaris.in
@@ -0,0 +1,84 @@
+#! @PERL@
+
+# Generic information about a purpose of this script can be found in
+# link_tool_exe_linux.in.
+#
+# Solaris specific notes:
+#
+# - load address has to be specified in the mapfile, there is no command line
+#   option to achieve that
+#
+# - mapfile version 2 is used
+#
+# - information about Solaris linker can be found in its man page
+#   (http://download.oracle.com/docs/cd/E19253-01/816-5165/ld-1/index.html)
+#   and in Oracle's Linker and Libraries Guide
+#   (http://download.oracle.com/docs/cd/E19963-01/html/819-0690/index.html)
+#
+
+use warnings;
+use strict;
+use File::Temp qw/tempfile unlink0/;
+use Fcntl qw/F_SETFD/;
+
+# expect at least: alt-load-address gcc -o foo bar.o
+die "Not enough arguments"
+    if (($#ARGV + 1) < 5);
+
+my $ala = $ARGV[0];
+
+# check for plausible-ish alt load address
+die "Bogus alt-load address"
+    if (length($ala) < 3 || index($ala, "0x") != 0);
+
+# the cc invokation to do the final link
+my $cc = $ARGV[1];
+
+# and the 'restargs' are argv[2 ..]
+
+# create a temporary mapfile
+(my $fh, my $path) = tempfile();
+
+# reset FD_CLOEXEC flag
+fcntl($fh, F_SETFD, 0)
+    or die "Can't clear close-on-exec flag on temp fh: $!";
+
+# safely unlink the file
+unlink0($fh, $path)
+    or die "Error unlinking file $path safely";
+undef $path;
+
+# fill it with data
+#
+# this is a bit tricky, the problem is that the following condition has to be
+# true for both PT_LOAD segments:
+# (phdr->p_vaddr & PAGEOFFSET) == (phdr->p_offset & PAGEOFFSET)
+# if it doesn't hold then the kernel maps a segment as an anon mapping instead
+# of a file mapping (which, for example, breaks reading debug information)
+print $fh <<"END";
+\$mapfile_version 2
+LOAD_SEGMENT text { VADDR = $ala; ROUND = 0x1000 };
+LOAD_SEGMENT data { ROUND = 0x1000 };
+END
+
+# build up the complete command here:
+# 'cc' -Wl,-Mtmpfile 'restargs'
+
+my $cmd="$cc -Wl,-M/proc/$$/fd/" . fileno($fh);
+
+# add the rest of the parameters
+foreach my $n (2 .. $#ARGV) {
+    $cmd = "$cmd $ARGV[$n]";
+}
+
+#print "link_tool_exe_solaris: $cmd\n";
+
+
+# execute the command:
+my $r = system("$cmd");
+
+if ($r == 0) {
+    exit 0;
+} else {
+    exit 1;
+}
diff --git a/coregrind/m_addrinfo.c b/coregrind/m_addrinfo.c
index 46b4487..5ff0d28 100644
--- a/coregrind/m_addrinfo.c
+++ b/coregrind/m_addrinfo.c
@@ -265,7 +265,11 @@
 
       /* Special case to detect the brk data segment. */
       if (seg != NULL
+#if defined(VGO_solaris)
+          && (seg->kind == SkAnonC || seg->kind == SkFileC)
+#else
           && seg->kind == SkAnonC
+#endif /* VGO_solaris */
           && VG_(brk_limit) >= seg->start
           && VG_(brk_limit) <= seg->end+1) {
          /* Address a is in a Anon Client segment which contains
diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c
index a235875..987f97a 100644
--- a/coregrind/m_aspacemgr/aspacemgr-common.c
+++ b/coregrind/m_aspacemgr/aspacemgr-common.c
@@ -174,6 +174,18 @@
    }
    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
                           prot, flags, (UInt)fd, offset);
+#  elif defined(VGP_x86_solaris)
+   /* MAP_ANON with fd==0 is EINVAL. */
+   if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
+      fd = -1;
+   res = VG_(do_syscall7)(__NR_mmap64, (UWord)start, length, prot, flags,
+                          (UInt)fd, offset & 0xffffffff, offset >> 32);
+#  elif defined(VGP_amd64_solaris)
+   /* MAP_ANON with fd==0 is EINVAL. */
+   if (fd == 0 && (flags & VKI_MAP_ANONYMOUS))
+      fd = -1;
+   res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags,
+                          (UInt)fd, offset);
 #  else
 #    error Unknown platform
 #  endif
@@ -249,8 +261,13 @@
 #  elif defined(VGP_tilegx_linux)
    SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname,
                                  flags, mode);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname,
+                                 flags, mode);
+#  else
+#    error Unknown OS
 #  endif
    return res;
 }
@@ -275,15 +292,20 @@
 #  elif defined(VGP_tilegx_linux)
    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
                           (UWord)buf, bufsiz);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
+#  elif defined(VGO_solaris)
+   res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
+                          (UWord)buf, bufsiz);
+#  else
+#    error Unknown OS
 #  endif
    return sr_isError(res) ? -1 : sr_Res(res);
 }
 
 Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
@@ -299,6 +321,7 @@
                            /*OUT*/ULong* dev, 
                            /*OUT*/ULong* ino, /*OUT*/UInt* mode )
 {
+#  if defined(VGO_linux) || defined(VGO_darwin)
    SysRes          res;
    struct vki_stat buf;
 #  if defined(VGO_linux) && defined(__NR_fstat64)
@@ -322,6 +345,26 @@
       return True;
    }
    return False;
+#  elif defined(VGO_solaris)
+#  if defined(VGP_x86_solaris)
+   struct vki_stat64 buf64;
+   SysRes res = VG_(do_syscall4)(__NR_fstatat64, fd, 0, (UWord)&buf64, 0);
+#  elif defined(VGP_amd64_solaris)
+   struct vki_stat buf64;
+   SysRes res = VG_(do_syscall4)(__NR_fstatat, fd, 0, (UWord)&buf64, 0);
+#  else
+#    error "Unknown platform"
+#  endif
+   if (!sr_isError(res)) {
+      *dev  = (ULong)buf64.st_dev;
+      *ino  = (ULong)buf64.st_ino;
+      *mode = (UInt) buf64.st_mode;
+      return True;
+   }
+   return False;
+#  else
+#    error Unknown OS
+#  endif
 }
 
 Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
@@ -347,6 +390,16 @@
    }
    return False;
 
+#elif defined(VGO_solaris)
+   Int i;
+   HChar tmp[64];
+   for (i = 0; i < nbuf; i++) buf[i] = 0;
+   ML_(am_sprintf)(tmp, "/proc/self/path/%d", fd);
+   if (ML_(am_readlink)(tmp, buf, nbuf) > 0 && buf[0] == '/')
+      return True;
+   else
+      return False;
+
 #  else
 #     error Unknown OS
 #  endif
diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c
index 5ec5aee..9fe0dff 100644
--- a/coregrind/m_aspacemgr/aspacemgr-linux.c
+++ b/coregrind/m_aspacemgr/aspacemgr-linux.c
@@ -32,7 +32,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /* *************************************************************
    DO NOT INCLUDE ANY OTHER FILES HERE.
@@ -100,6 +100,15 @@
      clustered towards the start of available space, and Valgrind ones
      in the middle.
 
+     On Solaris, searches for client space start at (aspacem_vStart - 1)
+     and for Valgrind space start at (aspacem_maxAddr - 1) and go backwards.
+     This simulates what kernel does - brk limit grows from bottom and mmap'ed
+     objects from top. It is in contrary with Linux where data segment
+     and mmap'ed objects grow from bottom (leading to early data segment
+     exhaustion for tools which do not use m_replacemalloc). While Linux glibc
+     can cope with this problem by employing mmap, Solaris libc treats inability
+     to grow brk limit as a hard failure.
+
      The available space is delimited by aspacem_minAddr and
      aspacem_maxAddr.  aspacem is flexible and can operate with these
      at any (sane) setting.  For 32-bit Linux, aspacem_minAddr is set
@@ -297,14 +306,17 @@
 
 
 Addr VG_(clo_aspacem_minAddr)
-#if defined(VGO_darwin)
+#if defined(VGO_linux)
+   = (Addr) 0x04000000; // 64M
+#elif defined(VGO_darwin)
 # if VG_WORDSIZE == 4
    = (Addr) 0x00001000;
 # else
    = (Addr) 0x100000000;  // 4GB page zero
 # endif
+#elif defined(VGO_solaris)
+   = (Addr) 0x00100000; // 1MB
 #else
-   = (Addr) 0x04000000; // 64M
 #endif
 
 
@@ -1122,6 +1134,18 @@
       return &nsegments[i];
 }
 
+/* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
+NSegment const *VG_(am_find_anon_segment) ( 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 == SkAnonC || nsegments[i].kind == SkAnonV)
+      return &nsegments[i];
+   else
+      return NULL;
+}
 
 /* Map segment pointer to segment index. */
 static Int segAddr_to_index ( const NSegment* seg )
@@ -1593,7 +1617,96 @@
 
    suggested_clstack_end = -1; // ignored; Mach-O specifies its stack
 
-#else /* !defined(VGO_darwin) */
+#elif defined(VGO_solaris)
+#  if VG_WORDSIZE == 4
+   /*
+      Intended address space partitioning:
+
+      ,--------------------------------, 0x00000000
+      |                                |
+      |--------------------------------|
+      | initial stack given to V by OS |
+      |--------------------------------| 0x08000000
+      |          client text           |
+      |--------------------------------|
+      |                                |
+      |                                |
+      |--------------------------------|
+      |          client stack          |
+      |--------------------------------| 0x38000000
+      |            V's text            |
+      |--------------------------------|
+      |                                |
+      |                                |
+      |--------------------------------|
+      |     dynamic shared objects     |
+      '--------------------------------' 0xffffffff
+
+      */
+
+   /* Anonymous pages need to fit under user limit (USERLIMIT32)
+      which is 4KB + 16MB below the top of the 32-bit range. */
+#    ifdef ENABLE_INNER
+     aspacem_maxAddr = (Addr)0x4fffffff; // 1.25GB
+     aspacem_vStart  = (Addr)0x40000000; // 1GB
+#    else
+     aspacem_maxAddr = (Addr)0xfefff000 - 1; // 4GB - 16MB - 4KB
+     aspacem_vStart  = (Addr)0x50000000; // 1.25GB
+#    endif
+#  elif VG_WORDSIZE == 8
+   /*
+      Intended address space partitioning:
+
+      ,--------------------------------, 0x00000000_00000000
+      |                                |
+      |--------------------------------| 0x00000000_00400000
+      |          client text           |
+      |--------------------------------|
+      |                                |
+      |                                |
+      |--------------------------------|
+      |          client stack          |
+      |--------------------------------| 0x00000000_38000000
+      |            V's text            |
+      |--------------------------------|
+      |                                |
+      |--------------------------------|
+      |     dynamic shared objects     |
+      |--------------------------------| 0x0000000f_ffffffff
+      |                                |
+      |                                |
+      |--------------------------------|
+      | initial stack given to V by OS |
+      '--------------------------------' 0xffffffff_ffffffff
+
+      */
+
+   /* Kernel likes to place objects at the end of the address space.
+      However accessing memory beyond 64GB makes memcheck slow
+      (see memcheck/mc_main.c, internal representation). Therefore:
+      - mmapobj() syscall is emulated so that libraries are subject to
+        Valgrind's aspacemgr control
+      - Kernel shared pages (such as schedctl and hrt) are left as they are
+        because kernel cannot be told where they should be put */
+#    ifdef ENABLE_INNER
+     aspacem_maxAddr = (Addr) 0x00000007ffffffff; // 32GB
+     aspacem_vStart  = (Addr) 0x0000000400000000; // 16GB
+#    else
+     aspacem_maxAddr = (Addr) 0x0000000fffffffff; // 64GB
+     aspacem_vStart  = (Addr) 0x0000000800000000; // 32GB
+#    endif
+#  else
+#    error "Unknown word size"
+#  endif
+
+   aspacem_cStart = aspacem_minAddr;
+#  ifdef ENABLE_INNER
+   suggested_clstack_end = (Addr) 0x27ff0000 - 1; // 64kB below V's text
+#  else
+   suggested_clstack_end = (Addr) 0x37ff0000 - 1; // 64kB below V's text
+#  endif
+
+#else
 
    /* Establish address limits and block out unusable parts
       accordingly. */
@@ -1624,7 +1737,7 @@
    suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL
                                            + VKI_PAGE_SIZE;
 
-#endif /* #else of 'defined(VGO_darwin)' */
+#endif
 
    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
@@ -1749,9 +1862,13 @@
    Addr holeStart, holeEnd, holeLen;
    Bool fixed_not_required;
 
+#if defined(VGO_solaris)
+   Addr startPoint = forClient ? aspacem_vStart - 1 : aspacem_maxAddr - 1;
+#else
    Addr startPoint = forClient ? aspacem_cStart : aspacem_vStart;
+#endif /* VGO_solaris */
 
-   Addr reqStart = req->rkind==MAny ? 0 : req->start;
+   Addr reqStart = req->rkind==MFixed || req->rkind==MHint ? req->start : 0;
    Addr reqEnd   = reqStart + req->len - 1;
    Addr reqLen   = req->len;
 
@@ -1834,18 +1951,39 @@
    /* ------ Implement the Default Policy ------ */
 
    /* Don't waste time looking for a fixed match if not requested to. */
-   fixed_not_required = req->rkind == MAny;
+   fixed_not_required = req->rkind == MAny || req->rkind == MAlign;
 
    i = find_nsegment_idx(startPoint);
 
+#if defined(VGO_solaris)
+#  define UPDATE_INDEX(index)                               \
+      (index)--;                                            \
+      if ((index) <= 0)                                     \
+         (index) = nsegments_used - 1;
+#  define ADVISE_ADDRESS(segment)                           \
+       VG_PGROUNDDN((segment)->end + 1 - reqLen)
+#  define ADVISE_ADDRESS_ALIGNED(segment)                   \
+        VG_ROUNDDN((segment)->end + 1 - reqLen, req->start)
+
+#else
+
+#  define UPDATE_INDEX(index)                               \
+      (index)++;                                            \
+      if ((index) >= nsegments_used)                        \
+         (index) = 0;
+#  define ADVISE_ADDRESS(segment)                           \
+      (segment)->start
+#  define ADVISE_ADDRESS_ALIGNED(segment)                   \
+      VG_ROUNDUP((segment)->start, req->start)
+#endif /* VGO_solaris */
+
    /* 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;
+         UPDATE_INDEX(i);
          continue;
       }
 
@@ -1857,6 +1995,15 @@
       aspacem_assert(aspacem_minAddr <= holeStart);
       aspacem_assert(holeEnd <= aspacem_maxAddr);
 
+      if (req->rkind == MAlign) {
+         holeStart = VG_ROUNDUP(holeStart, req->start);
+         if (holeStart >= holeEnd) {
+            /* This hole can't be used. */
+            UPDATE_INDEX(i);
+            continue;
+         }
+      }
+
       /* See if it's any use to us. */
       holeLen = holeEnd - holeStart + 1;
 
@@ -1870,8 +2017,7 @@
       if ((fixed_not_required || fixedIdx >= 0) && floatIdx >= 0)
          break;
 
-      i++;
-      if (i >= nsegments_used) i = 0;
+      UPDATE_INDEX(i);
    }
 
    aspacem_assert(fixedIdx >= -1 && fixedIdx < nsegments_used);
@@ -1902,14 +2048,21 @@
          }
          if (floatIdx >= 0) {
             *ok = True;
-            return nsegments[floatIdx].start;
+            return ADVISE_ADDRESS(&nsegments[floatIdx]);
          }
          *ok = False;
          return 0;
       case MAny:
          if (floatIdx >= 0) {
             *ok = True;
-            return nsegments[floatIdx].start;
+            return ADVISE_ADDRESS(&nsegments[floatIdx]);
+         }
+         *ok = False;
+         return 0;
+      case MAlign:
+         if (floatIdx >= 0) {
+            *ok = True;
+            return ADVISE_ADDRESS_ALIGNED(&nsegments[floatIdx]);
          }
          *ok = False;
          return 0;
@@ -1921,6 +2074,10 @@
    ML_(am_barf)("getAdvisory: unknown request kind");
    *ok = False;
    return 0;
+
+#undef UPDATE_INDEX
+#undef ADVISE_ADDRESS
+#undef ADVISE_ADDRESS_ALIGNED
 }
 
 /* Convenience wrapper for VG_(am_get_advisory) for client floating or
@@ -2158,12 +2315,30 @@
 SysRes VG_(am_mmap_file_fixed_client)
      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
 {
-   return VG_(am_mmap_named_file_fixed_client)(start, length, prot, fd, offset, NULL);
+   UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
+   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
+                                                     fd, offset, NULL);
+}
+
+SysRes VG_(am_mmap_file_fixed_client_flags)
+     ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset )
+{
+   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
+                                                     fd, offset, NULL);
 }
 
 SysRes VG_(am_mmap_named_file_fixed_client)
      ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
 {
+   UInt flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE;
+   return VG_(am_mmap_named_file_fixed_client_flags)(start, length, prot, flags,
+                                                     fd, offset, name);
+}
+
+SysRes VG_(am_mmap_named_file_fixed_client_flags)
+     ( Addr start, SizeT length, UInt prot, UInt flags,
+       Int fd, Off64T offset, const HChar *name )
+{
    SysRes     sres;
    NSegment   seg;
    Addr       advised;
@@ -2192,8 +2367,7 @@
       any resulting failure immediately. */
    // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
    sres = VG_(am_do_mmap_NO_NOTIFY)( 
-             start, length, prot, 
-             VKI_MAP_FIXED|VKI_MAP_PRIVATE, 
+             start, length, prot, flags,
              fd, offset 
           );
    if (sr_isError(sres))
@@ -3603,7 +3777,274 @@
 
 /*------END-procmaps-parser-for-Darwin---------------------------*/
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+/*------BEGIN-procmaps-parser-for-Solaris------------------------*/
+
+#if defined(VGO_solaris)
+
+/* Note: /proc/self/xmap contains extended information about already
+   materialized mappings whereas /proc/self/rmap contains information about
+   all mappings including reserved but yet-to-materialize mappings (mmap'ed
+   with MAP_NORESERVE flag, such as thread stacks). But /proc/self/rmap does
+   not contain extended information found in /proc/self/xmap. Therefore
+   information from both sources need to be combined.
+ */
+
+typedef struct
+{
+   Addr   addr;
+   SizeT  size;
+   UInt   prot;
+   ULong  dev;
+   ULong  ino;
+   Off64T foffset;
+   HChar  filename[VKI_PATH_MAX];
+} Mapping;
+
+static SizeT read_proc_file(const HChar *filename, HChar *buf,
+                            SizeT buf_size, const HChar *buf_size_name,
+                            SizeT entry_size)
+{
+   SysRes res = ML_(am_open)(filename, VKI_O_RDONLY, 0);
+   if (sr_isError(res)) {
+      HChar message[100];
+      ML_(am_sprintf)(message, "Cannot open %s.", filename);
+      ML_(am_barf)(message);
+   }
+   Int fd = sr_Res(res);
+
+   Int r = ML_(am_read)(fd, buf, buf_size);
+   ML_(am_close)(fd);
+   if (r < 0) {
+      HChar message[100];
+      ML_(am_sprintf)(message, "I/O error on %s.", filename);
+      ML_(am_barf)(message);
+   }
+
+   if (r >= buf_size)
+      ML_(am_barf_toolow)(buf_size_name);
+
+   if (r % entry_size != 0) {
+      HChar message[100];
+      ML_(am_sprintf)(message, "Bogus values read from %s.", filename);
+      ML_(am_barf)(message);
+   }
+
+   return r / entry_size;
+}
+
+static Mapping *next_xmap(const HChar *buffer, SizeT entries, SizeT *idx,
+                          Mapping *mapping)
+{
+   aspacem_assert(idx);
+   aspacem_assert(mapping);
+
+   if (*idx >= entries)
+      return NULL; /* No more entries */
+
+   const vki_prxmap_t *map = (const vki_prxmap_t *)buffer + *idx;
+
+   mapping->addr = map->pr_vaddr;
+   mapping->size = map->pr_size;
+
+   mapping->prot = 0;
+   if (map->pr_mflags & VKI_MA_READ)
+      mapping->prot |= VKI_PROT_READ;
+   if (map->pr_mflags & VKI_MA_WRITE)
+      mapping->prot |= VKI_PROT_WRITE;
+   if (map->pr_mflags & VKI_MA_EXEC)
+      mapping->prot |= VKI_PROT_EXEC;
+
+   if (map->pr_dev != VKI_PRNODEV) {
+      mapping->dev = map->pr_dev;
+      mapping->ino = map->pr_ino;
+      mapping->foffset = map->pr_offset;
+   }
+   else {
+      mapping->dev = 0;
+      mapping->ino = 0;
+      mapping->foffset = 0;
+   }
+
+   /* Try to get the filename. */
+   mapping->filename[0] = '\0';
+   if (map->pr_mapname[0] != '\0') {
+      ML_(am_sprintf)(mapping->filename, "/proc/self/path/%s",
+                      map->pr_mapname);
+      Int r = ML_(am_readlink)(mapping->filename, mapping->filename,
+                               sizeof(mapping->filename) - 1);
+      if (r == -1) {
+         /* If Valgrind is executed in a non-global zone and the link in
+            /proc/self/path/ represents a file that is available through lofs
+            from a global zone then the kernel may not be able to resolve the
+            link.
+
+            In such a case, return a corresponding /proc/self/object/ file to
+            allow Valgrind to read the file if it is necessary.
+
+            This can create some discrepancy for the sanity check. For
+            instance, if a client program mmaps some file then the address
+            space manager will have a correct zone-local name of that file,
+            but the sanity check will receive a different file name from this
+            code. This currently does not represent a problem because the
+            sanity check ignores the file names (it uses device and inode
+            numbers for the comparison).
+          */
+         ML_(am_sprintf)(mapping->filename, "/proc/self/object/%s",
+                         map->pr_mapname);
+      }
+      else {
+         aspacem_assert(r >= 0);
+         mapping->filename[r] = '\0';
+      }
+   }
+
+   *idx += 1;
+   return mapping;
+}
+
+static Mapping *next_rmap(const HChar *buffer, SizeT entries, SizeT *idx,
+                          Mapping *mapping)
+{
+   aspacem_assert(idx);
+   aspacem_assert(mapping);
+
+   if (*idx >= entries)
+      return NULL; /* No more entries */
+
+   const vki_prmap_t *map = (const vki_prmap_t *)buffer + *idx;
+
+   mapping->addr = map->pr_vaddr;
+   mapping->size = map->pr_size;
+
+   mapping->prot = 0;
+   if (map->pr_mflags & VKI_MA_READ)
+      mapping->prot |= VKI_PROT_READ;
+   if (map->pr_mflags & VKI_MA_WRITE)
+      mapping->prot |= VKI_PROT_WRITE;
+   if (map->pr_mflags & VKI_MA_EXEC)
+      mapping->prot |= VKI_PROT_EXEC;
+
+   mapping->dev = 0;
+   mapping->ino = 0;
+   mapping->foffset = 0;
+   mapping->filename[0] = '\0';
+
+   *idx += 1;
+   return mapping;
+}
+
+/* Used for two purposes:
+   1. Establish initial mappings upon the process startup
+   2. Check mappings during aspacemgr sanity check
+ */
+static void parse_procselfmaps (
+      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
+                              ULong dev, ULong ino, Off64T offset,
+                              const HChar *filename ),
+      void (*record_gap)( Addr addr, SizeT len )
+   )
+{
+   Addr start = Addr_MIN;
+   Addr gap_start = Addr_MIN;
+
+#define M_XMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prxmap_t))
+   /* Static to keep it out of stack frame... */
+   static HChar xmap_buf[M_XMAP_BUF];
+   const Mapping *xmap = NULL;
+   SizeT xmap_index = 0; /* Current entry */
+   SizeT xmap_entries;
+   Mapping xmap_mapping;
+   Bool advance_xmap;
+
+#define M_RMAP_BUF (VG_N_SEGMENTS * sizeof(vki_prmap_t))
+   static HChar rmap_buf[M_RMAP_BUF];
+   const Mapping *rmap = NULL;
+   SizeT rmap_index = 0; /* Current entry */
+   SizeT rmap_entries;
+   Mapping rmap_mapping;
+   Bool advance_rmap;
+
+   /* Read fully /proc/self/xmap and /proc/self/rmap. */
+   xmap_entries = read_proc_file("/proc/self/xmap", xmap_buf, M_XMAP_BUF,
+                                 "M_XMAP_BUF", sizeof(vki_prxmap_t));
+
+   rmap_entries = read_proc_file("/proc/self/rmap", rmap_buf, M_RMAP_BUF,
+                                 "M_RMAP_BUF", sizeof(vki_prmap_t));
+
+   /* Get the first xmap and rmap. */
+   advance_xmap = True;
+   advance_rmap = True;
+
+   while (1) {
+      /* Get next xmap or rmap if necessary. */
+      if (advance_xmap) {
+         xmap = next_xmap(xmap_buf, xmap_entries, &xmap_index, &xmap_mapping);
+         advance_xmap = False;
+      }
+      if (advance_rmap) {
+         rmap = next_rmap(rmap_buf, rmap_entries, &rmap_index, &rmap_mapping);
+         advance_rmap = False;
+      }
+
+      /* Check if the end has been reached. */
+      if (rmap == NULL)
+         break;
+
+      /* Invariants */
+      if (xmap != NULL) {
+         aspacem_assert(start <= xmap->addr);
+         aspacem_assert(rmap->addr <= xmap->addr);
+      }
+
+      if (xmap != NULL && start == xmap->addr) {
+         /* xmap mapping reached. */
+         aspacem_assert(xmap->addr >= rmap->addr &&
+                        xmap->addr + xmap->size <= rmap->addr + rmap->size);
+         aspacem_assert(xmap->prot == rmap->prot);
+
+         if (record_mapping != NULL)
+            (*record_mapping)(xmap->addr, xmap->size, xmap->prot, xmap->dev,
+                              xmap->ino, xmap->foffset,
+                              (xmap->filename[0] != '\0') ?
+                               xmap->filename : NULL);
+
+         start = xmap->addr + xmap->size;
+         advance_xmap = True;
+      }
+      else if (start >= rmap->addr) {
+         /* Reserved-only part. */
+         /* First calculate size until the end of this reserved mapping... */
+         SizeT size = rmap->addr + rmap->size - start;
+         /* ... but shrink it if some xmap is in a way. */
+         if (xmap != NULL && size > xmap->addr - start)
+            size = xmap->addr - start;
+
+         if (record_mapping != NULL)
+            (*record_mapping)(start, size, rmap->prot, 0, 0, 0, NULL);
+         start += size;
+      }
+      else {
+         /* Gap. */
+         if (record_gap != NULL && gap_start < start)
+            (*record_gap)(gap_start, start - gap_start);
+         start = rmap->addr;
+      }
+
+      if (rmap->addr + rmap->size <= start)
+         advance_rmap = True;
+
+      gap_start = start;
+   }
+
+   if (record_gap != NULL && gap_start < Addr_MAX)
+      (*record_gap)(gap_start, Addr_MAX - gap_start + 1);
+}
+
+#endif // defined(VGO_solaris)
+
+/*------END-procmaps-parser-for-Solaris--------------------------*/
+
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_clientstate.c b/coregrind/m_clientstate.c
index e1a6040..35aee35 100644
--- a/coregrind/m_clientstate.c
+++ b/coregrind/m_clientstate.c
@@ -51,9 +51,13 @@
 /* Initial highest address of the stack segment of the main thread. */
 Addr  VG_(clstk_end)   = 0;
 UWord VG_(clstk_id)    = 0;
+/* Maximum size of the main thread's client stack. */
+SizeT VG_(clstk_max_size) = 0;
 
-/* linux only: where is the client auxv ? */
-/* This is set up as part of setup_client_stack in initimg-linux.c. */
+/* Solaris and Linux only, specifies where the client auxv is.
+
+   This is set up as part of setup_client_stack() in
+   initimg-{linux,solaris}.c. */
 UWord* VG_(client_auxv) = NULL;
 
 Addr  VG_(brk_base)    = 0;       /* start of brk */
@@ -68,6 +72,11 @@
 /* A fd which refers to the fake /proc/<pid>/auxv in /tmp. */
 Int VG_(cl_auxv_fd) = -1;
 
+#if defined(VGO_solaris)
+/* A fd which refers to the fake /proc/<pid>/psinfo in /tmp. */
+Int VG_(cl_psinfo_fd) = -1;
+#endif /* VGO_solaris */
+
 // Command line pieces, after they have been extracted from argv in
 // m_main.main().  The payload vectors are allocated in VG_AR_CORE
 // (the default arena).  They are never freed.
@@ -113,6 +122,12 @@
    in nptl/allocatestack.c */
 SizeT* VG_(client__stack_cache_actsize__addr) = 0;
 
+#if defined(VGO_solaris)
+/* Address of variable vg_vfork_fildes in vgpreload_core.so.0
+   (vg_preloaded.c). */
+Int* VG_(vfork_fildes_addr) = 0;
+#endif
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c
index 038b771..8b7871e 100644
--- a/coregrind/m_coredump/coredump-elf.c
+++ b/coregrind/m_coredump/coredump-elf.c
@@ -194,8 +194,6 @@
 static void fill_prpsinfo(const ThreadState *tst,
                           struct vki_elf_prpsinfo *prpsinfo)
 {
-   const HChar *name;
-
    VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
 
    switch(tst->status) {
@@ -221,16 +219,7 @@
    prpsinfo->pr_uid = 0;
    prpsinfo->pr_gid = 0;
    
-   if (VG_(resolve_filename)(VG_(cl_exec_fd), &name)) {
-      const HChar *n = name + VG_(strlen)(name) - 1;
-
-      while (n > name && *n != '/')
-	 n--;
-      if (n != name)
-	 n++;
-
-      VG_(strncpy)(prpsinfo->pr_fname, n, sizeof(prpsinfo->pr_fname));
-   }
+   VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), False);
 }
 
 static void fill_prstatus(const ThreadState *tst, 
diff --git a/coregrind/m_coredump/coredump-solaris.c b/coregrind/m_coredump/coredump-solaris.c
new file mode 100644
index 0000000..9b6473c
--- /dev/null
+++ b/coregrind/m_coredump/coredump-solaris.c
@@ -0,0 +1,1110 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Dumping core on Solaris.                  coredump-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+ 
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2013-2014 Ivo Raisr
+      ivosh@ivosh.net
+
+   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.
+*/
+
+#if defined(VGO_solaris)
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_aspacehl.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_coredump.h"
+#include "pub_core_debuglog.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_machine.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_syscall.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+
+typedef struct __attribute__ ((__packed__)) note {
+   struct note *next;
+   VKI_ESZ(Nhdr) nhdr;
+   HChar name[8];
+   HChar data[0];
+} note_t;
+
+static void add_note(note_t **list, UInt type, const void *data,
+                     UInt datasz);
+
+/* If true, then this Segment may be mentioned in the core */
+static Bool may_dump(const NSegment *seg)
+{
+   if ((seg->kind == SkAnonC) ||
+       (seg->kind == SkShmC) ||
+       ((seg->kind == SkFileC) &&
+        !VKI_S_ISCHR(seg->mode) && !VKI_S_ISBLK(seg->mode)))
+      return True;
+
+   return False;
+}
+
+/* If true, then this Segment's contents will be in the core */
+static Bool should_dump(const NSegment *seg)
+{
+   return may_dump(seg);
+}
+
+#if defined(SOLARIS_PRXREGSET_T)
+static Bool should_dump_xregs(const ThreadState *tst)
+{
+#if defined(VGP_x86_solaris)
+   return False;
+#elif defined(VGP_amd64_solaris)
+   const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
+
+   /* Dump 256-bit wide %ymm only when their upper half is non-zero. */
+   #define YMM_NON_ZERO(reg) \
+      ((reg[4] != 0) || (reg[5] != 0) || (reg[6] != 0) || (reg[7] != 0))
+   if (YMM_NON_ZERO(arch->vex.guest_YMM0) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM1) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM2) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM3) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM4) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM5) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM6) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM7) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM9) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM0) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM10) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM11) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM12) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM13) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM14) ||
+       YMM_NON_ZERO(arch->vex.guest_YMM15))
+      return True;
+
+   return False;
+
+   #undef YMM_NON_ZERO
+#else
+#  error Unknown ELF platform
+#endif
+}
+#endif /* SOLARIS_PRXREGSET_T */
+
+static void write_part(Int fd, const HChar *filename,
+                       void *buf, SizeT buf_size, const HChar *part)
+{
+   Int ret = VG_(write)(fd, buf, buf_size);
+   if (ret < 0) {
+      VG_(umsg)("Failed to write %s to coredump file %s, it may be "
+                "incomplete.\n", part, filename);
+      VG_(debugLog)(1, "coredump-solaris", "write_part: failed to write "
+                    "%s to file %s. Buffer address=%p, length=%lu. "
+                    "Error=%d.\n", part, filename, buf, buf_size, -ret);
+   }
+}
+
+/*====================================================================*/
+/*=== Miscellaneous getters                                        ===*/
+/*====================================================================*/
+
+static Int get_uid(void)
+{
+   return sr_Res(VG_(do_syscall0)(SYS_getuid));
+}
+
+static Int get_gid(void)
+{
+   return sr_Res(VG_(do_syscall0)(SYS_getgid));
+}
+
+static Int get_dmodel(void)
+{
+#if defined(VGP_x86_solaris)
+   return PR_MODEL_ILP32;
+#elif defined(VGP_amd64_solaris)
+   return PR_MODEL_LP64;
+#else
+#  error "Unknown platform"
+#endif
+}
+
+static vki_zoneid_t get_zoneid(void)
+{
+   SysRes sres = VG_(do_syscall2)(SYS_zone, VKI_ZONE_LOOKUP,
+                                  (UWord) NULL);
+   if (sr_isError(sres))
+       return 0;
+
+   return sr_Res(sres);
+}
+
+static UInt count_auxv(void)
+{
+   UInt count = 1;
+
+   vki_auxv_t *auxv = (vki_auxv_t *) VG_(client_auxv);
+   while (auxv->a_type != VKI_AT_NULL) {
+      count += 1;
+      auxv++;
+   }
+
+   return count;
+}
+
+static Addr compute_stkbase(const ThreadState *tst)
+{
+   return tst->client_stack_highest_byte + 1
+          - tst->client_stack_szB;
+}
+
+static Int get_wstat(const vki_siginfo_t *si)
+{
+   return (si->si_signo & 0xff) | WCOREFLG;
+}
+
+/*====================================================================*/
+/*=== Utility fillers                                              ===*/
+/*====================================================================*/
+
+static void fill_platform(HChar *buf, UInt buf_size)
+{
+   vg_assert(buf != NULL);
+   vg_assert(buf_size >= 1);
+
+   buf[0] = '\0';
+
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_PLATFORM,
+                    (UWord) buf, buf_size);
+}
+
+static void fill_zonename(HChar *buf, UInt buf_size)
+{
+   vg_assert(buf != NULL);
+   vg_assert(buf_size >= 1);
+
+   buf[0] = '\0';
+
+   VG_(do_syscall5)(SYS_zone, VKI_ZONE_GETATTR, get_zoneid(),
+                    VKI_ZONE_ATTR_NAME, (UWord) buf, buf_size);
+}
+
+static void fill_thread_state(const ThreadState *tst,
+                              HChar *state, HChar *sname)
+{
+   switch (tst->status) {
+   case VgTs_Runnable:
+   case VgTs_Yielding:
+      *state = VKI_SRUN;
+      *sname = 'R';
+      break;
+
+   case VgTs_WaitSys:
+      *state = VKI_SSLEEP;
+      *sname = 'S';
+      break;
+
+   case VgTs_Zombie:
+      *state = VKI_SZOMB;
+      *sname = 'Z';
+      break;
+
+   case VgTs_Empty:
+   case VgTs_Init:
+      *state = 0;
+      *sname = '?';
+      break;
+   }
+}
+
+static void fill_siginfo(const vki_siginfo_t *si, vki_siginfo_t *di,
+                         Short *signo)
+{
+   di->si_signo = si->si_signo;
+   di->si_code  = si->si_code;
+   di->si_errno = 0;
+   di->si_addr = si->si_addr;
+   *signo = si->si_signo;
+}
+
+static void fill_argv(Int *argc, Addr *argv)
+{
+   Addr *ptr = (Addr *) VG_(get_initial_client_SP)();
+   *argc = *ptr++;
+   *argv = (Addr) ptr;
+}
+
+static void fill_scheduling_class(HChar *buf, SizeT buf_size)
+{
+   vg_assert(buf != NULL);
+   vg_assert(buf_size >= 1);
+
+   /* Valgrind currently schedules one thread at time which
+      resembles the default timeshare class. */
+   VG_(strncpy)(buf, "TS", buf_size);
+}
+
+static void fill_regset(vki_prgregset_t *regs, const ThreadState *tst)
+{
+   const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
+
+#if defined(VGP_x86_solaris)
+   (*regs)[VKI_EIP]        = arch->vex.guest_EIP;
+   (*regs)[VKI_EAX]        = arch->vex.guest_EAX;
+   (*regs)[VKI_EBX]        = arch->vex.guest_EBX;
+   (*regs)[VKI_ECX]        = arch->vex.guest_ECX;
+   (*regs)[VKI_EDX]        = arch->vex.guest_EDX;
+   (*regs)[VKI_ESI]        = arch->vex.guest_ESI;
+   (*regs)[VKI_EDI]        = arch->vex.guest_EDI;
+   (*regs)[VKI_EBP]        = arch->vex.guest_EBP;
+   (*regs)[VKI_UESP]       = arch->vex.guest_ESP;
+   (*regs)[VKI_SS]         = arch->vex.guest_SS;
+   (*regs)[VKI_CS]         = arch->vex.guest_CS;
+   (*regs)[VKI_DS]         = arch->vex.guest_DS;
+   (*regs)[VKI_ES]         = arch->vex.guest_ES;
+   (*regs)[VKI_FS]         = arch->vex.guest_FS;
+   (*regs)[VKI_GS]         = arch->vex.guest_GS;
+   (*regs)[VKI_EFL]        = LibVEX_GuestX86_get_eflags(&arch->vex);
+#elif defined(VGP_amd64_solaris)
+   (*regs)[VKI_REG_RIP]    = arch->vex.guest_RIP;
+   (*regs)[VKI_REG_RAX]    = arch->vex.guest_RAX;
+   (*regs)[VKI_REG_RBX]    = arch->vex.guest_RBX;
+   (*regs)[VKI_REG_RCX]    = arch->vex.guest_RCX;
+   (*regs)[VKI_REG_RDX]    = arch->vex.guest_RDX;
+   (*regs)[VKI_REG_RBP]    = arch->vex.guest_RBP;
+   (*regs)[VKI_REG_RSI]    = arch->vex.guest_RSI;
+   (*regs)[VKI_REG_RDI]    = arch->vex.guest_RDI;
+   (*regs)[VKI_REG_R8]     = arch->vex.guest_R8;
+   (*regs)[VKI_REG_R9]     = arch->vex.guest_R9;
+   (*regs)[VKI_REG_R10]    = arch->vex.guest_R10;
+   (*regs)[VKI_REG_R11]    = arch->vex.guest_R11;
+   (*regs)[VKI_REG_R12]    = arch->vex.guest_R12;
+   (*regs)[VKI_REG_R13]    = arch->vex.guest_R13;
+   (*regs)[VKI_REG_R14]    = arch->vex.guest_R14;
+   (*regs)[VKI_REG_R15]    = arch->vex.guest_R15;
+   (*regs)[VKI_REG_RSP]    = arch->vex.guest_RSP;
+   (*regs)[VKI_REG_CS]     = VKI_UCS_SEL;
+   (*regs)[VKI_REG_DS]     = 0;
+   (*regs)[VKI_REG_ES]     = 0;
+   (*regs)[VKI_REG_FS]     = 0;
+   (*regs)[VKI_REG_GS]     = 0;
+   (*regs)[VKI_REG_SS]     = VKI_UDS_SEL;
+   (*regs)[VKI_REG_FSBASE] = arch->vex.guest_FS_CONST;
+   (*regs)[VKI_REG_GSBASE] = 0;
+   (*regs)[VKI_REG_RFL]    = LibVEX_GuestAMD64_get_rflags(&arch->vex);
+#else
+#  error "Unknown platform"
+#endif
+}
+
+static void fill_fpregset(vki_fpregset_t *fpu, const ThreadState *tst)
+{
+   const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
+
+#if defined(VGP_x86_solaris)
+   VG_(memset)(fpu, 0, sizeof(*fpu));
+
+   struct vki_fpchip_state *fs = &fpu->fp_reg_set.fpchip_state;
+   vg_assert(sizeof(fs->state) == 108);
+
+   LibVEX_GuestX86_get_x87(CONST_CAST(VexGuestX86State *, &arch->vex),
+                           (UChar *) &fs->state);
+
+   /* SSE */
+   UInt mxcsr = LibVEX_GuestX86_get_mxcsr(CONST_CAST(VexGuestX86State *,
+                                                     &arch->vex));
+   fs->mxcsr = mxcsr;
+
+   /* XMM registers */
+   #define COPY_OUT_XMM(dest, src) \
+      do {                      \
+         dest._l[0] = src[0];   \
+         dest._l[1] = src[1];   \
+         dest._l[2] = src[2];   \
+         dest._l[3] = src[3];   \
+      } while (0);
+   COPY_OUT_XMM(fs->xmm[0], arch->vex.guest_XMM0);
+   COPY_OUT_XMM(fs->xmm[1], arch->vex.guest_XMM1);
+   COPY_OUT_XMM(fs->xmm[2], arch->vex.guest_XMM2);
+   COPY_OUT_XMM(fs->xmm[3], arch->vex.guest_XMM3);
+   COPY_OUT_XMM(fs->xmm[4], arch->vex.guest_XMM4);
+   COPY_OUT_XMM(fs->xmm[5], arch->vex.guest_XMM5);
+   COPY_OUT_XMM(fs->xmm[6], arch->vex.guest_XMM6);
+   COPY_OUT_XMM(fs->xmm[7], arch->vex.guest_XMM7);
+   #undef COPY_OUT_XMM
+#elif defined(VGP_amd64_solaris)
+   VG_(memset)(fpu, 0, sizeof(*fpu));
+   struct vki_fpchip_state *fs = &fpu->fp_reg_set.fpchip_state;
+
+   /* LibVEX_GuestAMD64_fxsave() requires at least 416 bytes. */
+   vg_assert(sizeof(*fs) >= 416);
+   LibVEX_GuestAMD64_fxsave(CONST_CAST(VexGuestAMD64State *, &arch->vex),
+                            (Addr) fs);
+#else
+#  error Unknown platform
+#endif
+}
+
+/*====================================================================*/
+/*=== Header fillers                                               ===*/
+/*====================================================================*/
+
+static void fill_ehdr(VKI_ESZ(Ehdr) *ehdr, Int num_phdrs)
+{
+   VG_(memset)(ehdr, 0, sizeof(*ehdr));
+
+   VG_(memcpy)(ehdr->e_ident, VKI_ELFMAG, VKI_SELFMAG);
+   ehdr->e_ident[VKI_EI_CLASS]   = VG_ELF_CLASS;
+   ehdr->e_ident[VKI_EI_DATA]    = VG_ELF_DATA2XXX;
+   ehdr->e_ident[VKI_EI_VERSION] = VKI_EV_CURRENT;
+
+   ehdr->e_type = VKI_ET_CORE;
+   ehdr->e_machine = VG_ELF_MACHINE;
+   ehdr->e_version = VKI_EV_CURRENT;
+   ehdr->e_entry = 0;
+   ehdr->e_flags = 0;
+   ehdr->e_ehsize = sizeof(VKI_ESZ(Ehdr));
+
+   ehdr->e_phoff = sizeof(VKI_ESZ(Ehdr));
+   ehdr->e_phentsize = sizeof(VKI_ESZ(Phdr));
+
+   /* If the count of program headers can't fit in the mere 16 bits
+    * shortsightedly allotted to them in the ELF header, we use the
+    * extended formats and put the real values in the section header
+    * at index 0.
+    */
+   if (num_phdrs >= VKI_PN_XNUM) {
+      ehdr->e_phnum = VKI_PN_XNUM;
+      ehdr->e_shnum = 1;
+      ehdr->e_shoff = ehdr->e_phoff + ehdr->e_phentsize * num_phdrs;
+      ehdr->e_shentsize = sizeof(VKI_ESZ(Shdr));
+   } else {
+      ehdr->e_phnum = num_phdrs;
+      ehdr->e_shnum = 0;
+      ehdr->e_shoff = 0;
+      ehdr->e_shentsize = 0;
+   }
+
+   ehdr->e_shstrndx = 0;
+}
+
+static void fill_phdr(VKI_ESZ(Phdr) *phdr, const NSegment *seg, UInt off,
+                      Bool really_write)
+{
+   SizeT len = seg->end - seg->start + 1;
+
+   really_write = really_write && should_dump(seg);
+
+   VG_(memset)(phdr, 0, sizeof(*phdr));
+
+   phdr->p_type = PT_LOAD;
+   phdr->p_offset = off;
+   phdr->p_vaddr = seg->start;
+   phdr->p_paddr = 0;
+   phdr->p_filesz = really_write ? len : 0;
+   phdr->p_memsz = len;
+   phdr->p_flags = 0;
+
+   if (seg->hasR)
+      phdr->p_flags |= PF_R;
+   if (seg->hasW)
+      phdr->p_flags |= PF_W;
+   if (seg->hasX)
+      phdr->p_flags |= PF_X;
+
+   phdr->p_align = VKI_PAGE_SIZE;
+}
+
+/* Fills the section header at index zero when num_phdrs >= PN_XNUM. */
+static void fill_zero_shdr(VKI_ESZ(Shdr) *shdr, UInt num_phdrs)
+{
+   vg_assert(num_phdrs >= VKI_PN_XNUM);
+
+   VG_(memset)(shdr, 0, sizeof(*shdr));
+
+   shdr->sh_name = 0; // STR_NONE
+   shdr->sh_info = num_phdrs;
+}
+
+static void fill_prpsinfo(vki_elf_prpsinfo_t *prpsinfo,
+                          const ThreadState *tst,
+                          const vki_siginfo_t *si)
+{
+   VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo));
+
+   fill_thread_state(tst, &prpsinfo->pr_state, &prpsinfo->pr_sname);
+   prpsinfo->pr_uid = get_uid();
+   prpsinfo->pr_gid = get_gid();
+   prpsinfo->pr_pid = VG_(getpid)();
+   prpsinfo->pr_ppid = VG_(getppid)();
+   prpsinfo->pr_pgrp = VG_(getpgrp)();
+   prpsinfo->pr_sid = VG_(getpgrp)();
+   fill_scheduling_class(prpsinfo->pr_clname, sizeof(prpsinfo->pr_clname));
+   VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), True);
+   VG_(client_cmd_and_args)(prpsinfo->pr_psargs,
+                            sizeof(prpsinfo->pr_psargs));
+   fill_argv(&prpsinfo->pr_argc, (Addr *) &prpsinfo->pr_argv);
+   prpsinfo->pr_envp = (char **) VG_(client_envp);
+   prpsinfo->pr_wstat = get_wstat(si);
+   prpsinfo->pr_euid = VG_(geteuid)();
+   prpsinfo->pr_egid = VG_(getegid)();
+   prpsinfo->pr_dmodel = get_dmodel();
+}
+
+static void fill_prstatus(vki_elf_prstatus_t *prs,
+                          const ThreadState *tst,
+			  const vki_siginfo_t *si)
+{
+   VG_(memset)(prs, 0, sizeof(*prs));
+
+   prs->pr_flags = VKI_ELF_OLD_PR_PCINVAL;
+   fill_siginfo(si, &prs->pr_info, &prs->pr_cursig);
+   prs->pr_nlwp = VG_(count_living_threads)();
+   prs->pr_sighold = tst->sig_mask;
+   prs->pr_pid = VG_(getpid)();
+   prs->pr_ppid = VG_(getppid)();
+   prs->pr_pgrp = VG_(getpgrp)();
+   prs->pr_sid = VG_(getpgrp)();
+   fill_scheduling_class(prs->pr_clname, sizeof(prs->pr_clname));
+   prs->pr_who = tst->os_state.lwpid; 
+   prs->pr_brkbase = (vki_caddr_t) VG_(brk_base);
+   prs->pr_brksize = VG_(brk_limit) - VG_(brk_base);
+   prs->pr_stkbase = (vki_caddr_t) compute_stkbase(tst);
+   prs->pr_stksize = tst->client_stack_szB;
+   fill_regset(&prs->pr_reg, tst);
+}
+
+static void fill_psinfo(vki_psinfo_t *psinfo, const ThreadState *tst,
+                        const vki_siginfo_t *si)
+{
+   VG_(memset)(psinfo, 0, sizeof(*psinfo));
+
+   psinfo->pr_nlwp = VG_(count_living_threads)();
+   psinfo->pr_uid = get_uid();
+   psinfo->pr_gid = get_gid();
+   psinfo->pr_pid = VG_(getpid)();
+   psinfo->pr_ppid = VG_(getppid)();
+   psinfo->pr_pgid = VG_(getpgrp)();
+   psinfo->pr_sid = VG_(getpgrp)();
+   psinfo->pr_euid = VG_(geteuid)();
+   psinfo->pr_egid = VG_(getegid)();
+   VG_(client_fname)(psinfo->pr_fname, sizeof(psinfo->pr_fname), True);
+   psinfo->pr_wstat = get_wstat(si);
+   VG_(client_cmd_and_args)(psinfo->pr_psargs,
+                            sizeof(psinfo->pr_psargs));
+   fill_argv(&psinfo->pr_argc, (Addr *) &psinfo->pr_argv);
+   psinfo->pr_envp = (uintptr_t) VG_(client_envp);
+   psinfo->pr_dmodel = get_dmodel();
+   psinfo->pr_zoneid = get_zoneid();
+
+   psinfo->pr_lwp.pr_lwpid = tst->os_state.lwpid;
+   fill_thread_state(tst, &psinfo->pr_lwp.pr_state,
+                     &psinfo->pr_lwp.pr_sname);
+   fill_scheduling_class(psinfo->pr_lwp.pr_clname,
+                         sizeof(psinfo->pr_lwp.pr_clname));
+}
+
+static void fill_pstatus(vki_pstatus_t *pstatus,
+                         const ThreadState *tst,
+                         const vki_siginfo_t *si)
+{
+   VG_(memset)(pstatus, 0, sizeof(*pstatus));
+
+   pstatus->pr_flags = VKI_PR_PCINVAL;
+   pstatus->pr_nlwp = VG_(count_living_threads)();
+   pstatus->pr_pid = VG_(getpid)();
+   pstatus->pr_ppid = VG_(getppid)();
+   pstatus->pr_pgid = VG_(getpgrp)();
+   pstatus->pr_sid = VG_(getpgrp)();
+   pstatus->pr_brkbase = (uintptr_t) VG_(brk_base);
+   pstatus->pr_brksize = VG_(brk_limit) - VG_(brk_base);
+   pstatus->pr_stkbase = (uintptr_t) compute_stkbase(tst);
+   pstatus->pr_stksize = tst->client_stack_szB;
+   pstatus->pr_dmodel = get_dmodel();
+   pstatus->pr_zoneid = get_zoneid();
+
+   pstatus->pr_lwp.pr_flags = VKI_PR_PCINVAL;
+   pstatus->pr_lwp.pr_lwpid = tst->os_state.lwpid;
+   fill_siginfo(si, &pstatus->pr_lwp.pr_info,
+                &pstatus->pr_lwp.pr_cursig);
+   pstatus->pr_lwp.pr_lwphold = tst->sig_mask;
+   fill_scheduling_class(pstatus->pr_lwp.pr_clname,
+                         sizeof(pstatus->pr_lwp.pr_clname));
+   fill_regset(&pstatus->pr_lwp.pr_reg, tst);
+   fill_fpregset(&pstatus->pr_lwp.pr_fpreg, tst);
+}
+
+#if defined(SOLARIS_PRXREGSET_T)
+static void fill_xregs(vki_prxregset_t *xregs, const ThreadState *tst)
+{
+   const ThreadArchState *arch = (const ThreadArchState *) &tst->arch;
+
+#if defined(VGP_x86_solaris)
+   VG_(memset)(xregs, 0, sizeof(*xregs));
+   xregs->pr_xsize = sizeof(xregs->pr_un.pr_xsave);
+
+   /* SSE */
+   UInt mxcsr = LibVEX_GuestX86_get_mxcsr(CONST_CAST(VexGuestX86State *,
+                                                     &arch->vex));
+   xregs->pr_un.pr_xsave.pr_mxcsr = mxcsr;
+
+   /* XMM registers */
+   #define COPY_OUT_XMM(dest, src) \
+      do {                      \
+         dest._l[0] = src[0];   \
+         dest._l[1] = src[1];   \
+         dest._l[2] = src[2];   \
+         dest._l[3] = src[3];   \
+      } while (0);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[0], arch->vex.guest_XMM0);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[1], arch->vex.guest_XMM1);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[2], arch->vex.guest_XMM2);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[3], arch->vex.guest_XMM3);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[4], arch->vex.guest_XMM4);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[5], arch->vex.guest_XMM5);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[6], arch->vex.guest_XMM6);
+   COPY_OUT_XMM(xregs->pr_un.pr_xsave.pr_xmm[7], arch->vex.guest_XMM7);
+   #undef COPY_OUT_XMM
+
+#elif defined(VGP_amd64_solaris)
+   VG_(memset)(xregs, 0, sizeof(*xregs));
+   xregs->pr_xsize = sizeof(xregs->pr_un.pr_xsave);
+
+   /* LibVEX_GuestAMD64_fxsave() requires at least 416 bytes. */
+   vg_assert(sizeof(xregs->pr_un.pr_xsave) >= 416);
+   LibVEX_GuestAMD64_fxsave(CONST_CAST(VexGuestAMD64State *, &arch->vex),
+                            (Addr) &xregs->pr_un.pr_xsave);
+#else
+#  error "Unknown platform"
+#endif
+}
+#endif /* SOLARIS_PRXREGSET_T */
+
+static void fill_utsname(struct vki_utsname *uts)
+{
+   VG_(memset)(uts, 0, sizeof(*uts));
+
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_SYSNAME,
+                    (UWord) &uts->sysname, sizeof(uts->sysname));
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_HOSTNAME,
+                    (UWord) &uts->nodename, sizeof(uts->nodename));
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_RELEASE,
+                    (UWord) &uts->release, sizeof(uts->release));
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_VERSION,
+                    (UWord) &uts->version, sizeof(uts->version));
+   VG_(do_syscall3)(SYS_systeminfo, VKI_SI_MACHINE,
+                    (UWord) &uts->machine, sizeof(uts->machine));
+}
+
+static vki_prcred_t *create_prcred(SizeT *size)
+{
+   UInt group_list[VKI_NGROUPS_MAX];
+   Int ngroups = VG_(getgroups)(VKI_NGROUPS_MAX, group_list);
+   if (ngroups == -1)
+      ngroups = 0;
+
+   *size = sizeof(vki_prcred_t) + (ngroups - 1) * sizeof(gid_t);
+   vki_prcred_t *prcred = VG_(malloc)("coredump-elf.cp.1", *size);
+   VG_(memset)(prcred, 0, *size);
+
+   prcred->pr_euid = VG_(geteuid)();
+   prcred->pr_ruid = get_uid();
+   prcred->pr_suid = prcred->pr_euid;
+   prcred->pr_egid = VG_(getegid)();
+   prcred->pr_rgid = get_gid();
+   prcred->pr_sgid = prcred->pr_egid;
+   prcred->pr_ngroups = ngroups;
+
+   UInt i;
+   for (i = 0; i < ngroups; i++)
+      prcred->pr_groups[i] = group_list[i];
+
+   return prcred;
+}
+
+static void fill_core_content(vki_core_content_t *content)
+{
+   *content = VKI_CC_CONTENT_STACK | VKI_CC_CONTENT_HEAP
+              | VKI_CC_CONTENT_SHANON | VKI_CC_CONTENT_TEXT
+              | VKI_CC_CONTENT_DATA | VKI_CC_CONTENT_RODATA
+              | VKI_CC_CONTENT_ANON | VKI_CC_CONTENT_SHM
+              | VKI_CC_CONTENT_ISM | VKI_CC_CONTENT_DISM;
+}
+
+static vki_prpriv_t *create_prpriv(SizeT *size)
+{
+   Int fd = VG_(fd_open)("/proc/self/priv", O_RDONLY, 0);
+   if (fd < 0)
+      return NULL;
+
+   struct vg_stat stats;
+   if (VG_(fstat)(fd, &stats) != 0) {
+      VG_(close)(fd);
+      return NULL;
+   }
+
+   vki_prpriv_t *prpriv = VG_(malloc)("coredump-elf.cp.1", stats.size);
+
+   if (VG_(read)(fd, prpriv, stats.size) != stats.size) {
+      VG_(free)(prpriv);
+      VG_(close)(fd);
+      return NULL;
+   }
+
+   VG_(close)(fd);
+   *size = stats.size;
+   return prpriv;
+}
+
+static vki_priv_impl_info_t *create_priv_info(SizeT *size)
+{
+   /* Size of the returned priv_impl_info_t is apriori unkown. */
+   vki_priv_impl_info_t first_cut[100];
+   SysRes sres = VG_(do_syscall5)(SYS_privsys, VKI_PRIVSYS_GETIMPLINFO,
+                                  0, 0, (UWord) first_cut,
+                                  sizeof(first_cut));
+   if (sr_isError(sres))
+       return NULL;
+
+   SizeT real_size = first_cut[0].priv_headersize
+                     + first_cut[0].priv_globalinfosize;
+   vki_priv_impl_info_t *priv_info = VG_(malloc)("coredump-elf.cpi.1",
+                                                 real_size);
+
+   if (real_size <= sizeof(first_cut)) {
+      /* if the first_cut was large enough */
+      VG_(memcpy)(priv_info, first_cut, real_size);
+   } else {
+      /* otherwise repeat the syscall with buffer large enough */
+      sres = VG_(do_syscall5)(SYS_privsys, VKI_PRIVSYS_GETIMPLINFO,
+                              0, 0, (UWord) priv_info, real_size);
+      if (sr_isError(sres)) {
+          VG_(free)(priv_info);
+          return NULL;
+      }
+   }
+
+   *size = real_size;
+   return priv_info;
+}
+
+static void fill_lwpsinfo(vki_lwpsinfo_t *lwp,
+                          const ThreadState *tst)
+{
+   VG_(memset)(lwp, 0, sizeof(*lwp));
+
+   lwp->pr_lwpid = tst->os_state.lwpid;
+   fill_thread_state(tst, &lwp->pr_state, &lwp->pr_sname);
+   fill_scheduling_class(lwp->pr_clname, sizeof(lwp->pr_clname));
+}
+
+static void fill_lwpstatus(vki_lwpstatus_t *lwp,
+                           const ThreadState *tst,
+			   const vki_siginfo_t *si)
+{
+   VG_(memset)(lwp, 0, sizeof(*lwp));
+
+   lwp->pr_flags = VKI_PR_PCINVAL;
+   lwp->pr_lwpid = tst->os_state.lwpid;
+   fill_siginfo(si, &lwp->pr_info, &lwp->pr_cursig);
+   fill_scheduling_class(lwp->pr_clname, sizeof(lwp->pr_clname));
+   fill_regset(&lwp->pr_reg, tst);
+   fill_fpregset(&lwp->pr_fpreg, tst);
+}
+
+static void fill_old_note_for_thread(note_t **notes,
+                                     const ThreadState *tst,
+                                     const vki_siginfo_t *si)
+{
+   vki_elf_prstatus_t prstatus;
+   fill_prstatus(&prstatus, tst, si);
+   add_note(notes, VKI_NT_PRSTATUS, &prstatus, sizeof(vki_elf_prstatus_t));
+
+   vki_fpregset_t fpu;
+   fill_fpregset(&fpu, tst);
+   add_note(notes, VKI_NT_PRFPREG, &fpu, sizeof(vki_fpregset_t));
+
+#if defined(SOLARIS_PRXREGSET_T)
+   if (should_dump_xregs(tst)) {
+      vki_prxregset_t xregs;
+      fill_xregs(&xregs, tst);
+      add_note(notes, VKI_NT_PRXREG, &xregs, sizeof(vki_prxregset_t));
+   }
+#endif /* SOLARIS_PRXREGSET_T */
+}
+
+static void fill_new_note_for_thread(note_t **notes,
+                                     const ThreadState *tst,
+                                     const vki_siginfo_t *si)
+{
+   vki_lwpsinfo_t lwpsinfo;
+   fill_lwpsinfo(&lwpsinfo, tst);
+   add_note(notes, VKI_NT_LWPSINFO, &lwpsinfo, sizeof(vki_lwpsinfo_t));
+
+   vki_lwpstatus_t lwpstatus;
+   fill_lwpstatus(&lwpstatus, tst, si);
+   add_note(notes, VKI_NT_LWPSTATUS, &lwpstatus, sizeof(vki_lwpstatus_t));
+
+#if defined(SOLARIS_PRXREGSET_T)
+   if (should_dump_xregs(tst)) {
+      vki_prxregset_t xregs;
+      fill_xregs(&xregs, tst);
+      add_note(notes, VKI_NT_PRXREG, &xregs, sizeof(vki_prxregset_t));
+   }
+#endif /* SOLARIS_PRXREGSET_T */
+}
+
+/*====================================================================*/
+/*=== Note utility functions                                       ===*/
+/*====================================================================*/
+
+static void add_note(note_t **list, UInt type, const void *data,
+                     UInt datasz)
+{
+   UInt note_size = sizeof(note_t) + VG_ROUNDUP(datasz, 4);
+
+   note_t *n = VG_(malloc)("coredump-elf.an.1", note_size);
+
+   VG_(memset)(n, 0, note_size);
+   n->nhdr.n_type = type;
+   n->nhdr.n_namesz = 5;
+   n->nhdr.n_descsz = VG_ROUNDUP(datasz, 4);
+   VG_(memcpy)(n->name, "CORE", 4);
+   VG_(memcpy)(n->data, data, datasz);
+
+   if (*list == NULL) {
+      *list = n;
+      return;
+   }
+
+   note_t *tail = *list;
+   while (tail->next != NULL)
+      tail = tail->next;
+   tail->next = n;
+}
+
+static UInt note_size(const note_t *note)
+{
+   return sizeof(note_t) - sizeof(note_t *) + note->nhdr.n_descsz;
+}
+
+static UInt notes_size(const note_t *list)
+{
+   UInt size = 0;
+   const note_t *note;
+
+   for (note = list; note != NULL; note = note->next)
+      size += note_size(note);
+
+   return size;
+}
+
+static void fill_notes_phdr(VKI_ESZ(Phdr) *phdr, UInt offset,
+                            UInt size_of_notes)
+{
+   phdr->p_type = PT_NOTE;
+   phdr->p_offset = offset;
+   phdr->p_vaddr = 0;
+   phdr->p_paddr = 0;
+   phdr->p_filesz = size_of_notes;
+   phdr->p_memsz = 0;
+   phdr->p_flags = PF_R;
+   phdr->p_align = 0;
+}
+
+static void write_notes(Int fd, const HChar *filename,
+                        const note_t *list)
+{
+   const note_t *note;
+
+   for (note = list; note != NULL; note = note->next)
+      write_part(fd, filename, CONST_CAST(void *, &note->nhdr),
+                 note_size(note), "notes");
+}
+
+static void free_notes(note_t *list)
+{
+   while (list != NULL) {
+      note_t *next = list->next;
+      VG_(free)(list);
+      list = next;
+   }
+}
+
+/*====================================================================*/
+/*=== Main coredump function                                       ===*/
+/*====================================================================*/
+
+void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si,
+                        ULong max_size)
+{
+   const HChar *basename = "vgcore";
+   const HChar *coreext = "";
+   Int core_fd;
+
+   if (VG_(clo_log_fname_expanded) != NULL) {
+      coreext = ".core";
+      basename = VG_(expand_file_name)("--log-file",
+                                       VG_(clo_log_fname_expanded));
+   }
+
+   vg_assert(coreext != NULL);
+   vg_assert(basename != NULL);
+
+   UInt filename_size = VG_(strlen)(coreext) + VG_(strlen)(basename)
+                        + 100; /* for the two %d's */
+   HChar *filename = VG_(malloc)("coredump-elf.mc.1", filename_size);
+
+   /* Try to come with a non-existent coredump filename. */
+   UInt seq = 0;
+   for (;;) {
+      Int oflags = VKI_O_CREAT|VKI_O_WRONLY|VKI_O_EXCL|VKI_O_TRUNC;
+
+      if (seq == 0)
+	 VG_(snprintf)(filename, filename_size, "%s%s.%d",
+		      basename, coreext, VG_(getpid)());
+      else
+	 VG_(snprintf)(filename, filename_size, "%s%s.%d.%d",
+		      basename, coreext, VG_(getpid)(), seq);
+      seq++;
+
+#ifdef VKI_O_LARGEFILE
+      oflags |= VKI_O_LARGEFILE;
+#endif
+
+      SysRes sres = VG_(open)(filename, oflags,
+                              VKI_S_IRUSR|VKI_S_IWUSR);
+      if (!sr_isError(sres)) {
+         core_fd = sr_Res(sres);
+	 break;
+      }
+
+      if (sr_isError(sres) && sr_Err(sres) != VKI_EEXIST) {
+         VG_(umsg)("Cannot create coredump file %s (%lu)\n",
+                   filename, sr_Err(sres));
+         VG_(free)(filename);
+	 return;
+      }
+   }
+
+   /* Get the client segments. Free seg_starts after use. */
+   Int n_seg_starts;
+   Addr *seg_starts = VG_(get_segment_starts)(SkFileC | SkAnonC | SkShmC,
+                                              &n_seg_starts);
+
+   /* Count how many memory segments to dump. */
+   Int i;
+   UInt num_phdrs = 2;		/* two CORE note sections */
+   for (i = 0; i < n_seg_starts; i++) {
+      if (!may_dump(VG_(am_find_nsegment(seg_starts[i]))))
+	 continue;
+
+      num_phdrs++;
+   }
+
+   VKI_ESZ(Ehdr) ehdr;
+   fill_ehdr(&ehdr, num_phdrs);
+
+   VKI_ESZ(Shdr) shdr;
+   if (ehdr.e_shnum > 0)
+      fill_zero_shdr(&shdr, num_phdrs);
+   UInt phdrs_size = num_phdrs * ehdr.e_phentsize;
+
+   /* Construct the old-style notes. */
+   note_t *old_notes = NULL;
+
+   vki_elf_prpsinfo_t prpsinfo;
+   fill_prpsinfo(&prpsinfo, &VG_(threads)[tid], si);
+   add_note(&old_notes, VKI_NT_PRPSINFO, &prpsinfo,
+            sizeof(vki_elf_prpsinfo_t));
+
+   HChar platform[256 + 1];
+   fill_platform(platform, sizeof(platform));
+   add_note(&old_notes, VKI_NT_PLATFORM, platform,
+            VG_(strlen)(platform) + 1);
+
+   add_note(&old_notes, VKI_NT_AUXV, VG_(client_auxv),
+            count_auxv() * sizeof(auxv_t));
+
+   /* Add detail about the faulting thread as the first note.
+      This is how gdb determines which thread faulted. Note that
+      mdb does not need such aid. */
+   fill_old_note_for_thread(&old_notes, &VG_(threads)[tid], si);
+
+   /* Now add details for all threads except the one that faulted. */
+   ThreadId t_idx;
+   for (t_idx = 1; t_idx < VG_N_THREADS; t_idx++)
+      if ((VG_(threads)[t_idx].status != VgTs_Empty) &&
+            (VG_(threads)[t_idx].status != VgTs_Zombie)) {
+         if (t_idx == tid)
+            continue;
+
+         fill_old_note_for_thread(&old_notes, &VG_(threads)[t_idx], si);
+   }
+
+   /* Construct the new-style notes. */
+   note_t *new_notes = NULL;
+   vki_psinfo_t psinfo;
+   fill_psinfo(&psinfo, &VG_(threads)[tid], si);
+   add_note(&new_notes, VKI_NT_PSINFO, &psinfo, sizeof(vki_psinfo_t));
+
+   vki_pstatus_t pstatus;
+   fill_pstatus(&pstatus, &VG_(threads)[tid], si);
+   add_note(&new_notes, VKI_NT_PSTATUS, &pstatus, sizeof(vki_pstatus_t));
+
+   add_note(&new_notes, VKI_NT_PLATFORM, platform,
+            VG_(strlen)(platform) + 1);
+
+   add_note(&new_notes, VKI_NT_AUXV, VG_(client_auxv),
+            count_auxv() * sizeof(auxv_t));
+
+   struct vki_utsname uts;
+   fill_utsname(&uts);
+   add_note(&new_notes, VKI_NT_UTSNAME, &uts,
+            sizeof(struct vki_utsname));
+
+   SizeT prcred_size;
+   vki_prcred_t *prcred = create_prcred(&prcred_size);
+   if (prcred != NULL) {
+      add_note(&new_notes, VKI_NT_PRCRED, prcred, prcred_size);
+      VG_(free)(prcred);
+   }
+
+   vki_core_content_t core_content;
+   fill_core_content(&core_content);
+   add_note(&new_notes, VKI_NT_CONTENT, &core_content,
+            sizeof(vki_core_content_t));
+
+   SizeT priv_size;
+   vki_prpriv_t *prpriv = create_prpriv(&priv_size);
+   if (prpriv != NULL) {
+      add_note(&new_notes, VKI_NT_PRPRIV, prpriv, priv_size);
+      VG_(free)(prpriv);
+   }
+
+   vki_priv_impl_info_t *priv_info = create_priv_info(&priv_size);
+   if (priv_info != NULL) {
+      add_note(&new_notes, VKI_NT_PRPRIVINFO, priv_info, priv_size);
+      VG_(free)(priv_info);
+   }
+
+   HChar zonename[VKI_ZONENAME_MAX + 1];
+   fill_zonename(zonename, sizeof(zonename));
+   add_note(&new_notes, VKI_NT_ZONENAME, zonename,
+            VG_(strlen)(zonename) + 1);
+
+   /* Add detail about the faulting thread as the first note.
+      This is how gdb determines which thread faulted. Note that
+      mdb does not need such aid. */
+   fill_new_note_for_thread(&new_notes, &VG_(threads)[tid], si);
+
+   /* Now add details for all threads except the one that faulted. */
+   for (t_idx = 1; t_idx < VG_N_THREADS; t_idx++) {
+      if ((VG_(threads)[t_idx].status != VgTs_Empty) &&
+            (VG_(threads)[t_idx].status != VgTs_Zombie)) {
+         if (t_idx == tid)
+            continue;
+
+         fill_new_note_for_thread(&new_notes, &VG_(threads)[t_idx], si);
+      }
+   }
+
+   VKI_ESZ(Phdr) *phdrs = VG_(malloc)("coredump-elf.mc.2", phdrs_size);
+
+   UInt size_of_notes = notes_size(old_notes);
+   UInt offset = ehdr.e_ehsize + phdrs_size +
+                 (ehdr.e_shnum * ehdr.e_shentsize);
+
+   /* fill program header for old notes */
+   fill_notes_phdr(&phdrs[0], offset, size_of_notes);
+   offset += size_of_notes;
+
+   size_of_notes = notes_size(new_notes);
+   /* fill program header for new notes */
+   fill_notes_phdr(&phdrs[1], offset, size_of_notes);
+   offset += size_of_notes;
+
+   /* fill program headers for segments */
+   UInt idx;
+   for (i = 0, idx = 2; i < n_seg_starts; i++) {
+      NSegment const *seg = VG_(am_find_nsegment(seg_starts[i]));
+
+      if (!may_dump(seg))
+	 continue;
+
+      fill_phdr(&phdrs[idx], seg, offset,
+                (seg->end - seg->start + 1 + offset) < max_size);
+      
+      offset += phdrs[idx].p_filesz;
+
+      idx++;
+   }
+
+   /* write everything out */
+   write_part(core_fd, filename, &ehdr, sizeof(ehdr),
+             "elf headers");
+   write_part(core_fd, filename, phdrs, phdrs_size,
+              "program headers");
+   if (ehdr.e_shnum > 0)
+      write_part(core_fd, filename, &shdr, sizeof(shdr),
+                 "section headers");
+   write_notes(core_fd, filename, old_notes);
+   write_notes(core_fd, filename, new_notes);
+
+   VG_(lseek)(core_fd, phdrs[2].p_offset, VKI_SEEK_SET);
+
+   for (i = 0, idx = 2; i < n_seg_starts; i++) {
+      NSegment const *seg = VG_(am_find_nsegment(seg_starts[i]));
+
+      if (!should_dump(seg))
+	 continue;
+
+      if (phdrs[idx].p_filesz > 0) {
+         Off64T off = VG_(lseek)(core_fd, phdrs[idx].p_offset,
+                                 VKI_SEEK_SET);
+         vg_assert(off == phdrs[idx].p_offset);
+         vg_assert(seg->end - seg->start + 1 >= phdrs[idx].p_filesz);
+
+         write_part(core_fd, filename, (void *) seg->start,
+                    phdrs[idx].p_filesz, "program segment");
+      }
+      idx++;
+   }
+
+   VG_(close)(core_fd);
+   VG_(free)(filename);
+   VG_(free)(phdrs);
+   free_notes(old_notes);
+   free_notes(new_notes);
+   VG_(free)(seg_starts);
+}
+
+#endif
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index 4582db0..7bc809a 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -448,6 +448,12 @@
 
    return VG_(ptrace)(VKI_PTRACE_SETREGS, pid, NULL, &regs);
 
+#elif defined(VGP_x86_solaris)
+   I_die_here;
+
+#elif defined(VGP_amd64_solaris)
+   I_die_here;
+
 #else
 #  error Unknown arch
 #endif
diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c
index 09d1b12..9a6051a 100644
--- a/coregrind/m_debuginfo/d3basics.c
+++ b/coregrind/m_debuginfo/d3basics.c
@@ -400,10 +400,12 @@
 static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, const RegSummary* regs )
 {
    vg_assert(regs);
-#  if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
+#  if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \
+      || defined(VGP_x86_solaris)
    if (regno == 5/*EBP*/) { *a = regs->fp; return True; }
    if (regno == 4/*ESP*/) { *a = regs->sp; return True; }
-#  elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
+#  elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \
+        || defined(VGP_amd64_solaris)
    if (regno == 6/*RBP*/) { *a = regs->fp; return True; }
    if (regno == 7/*RSP*/) { *a = regs->sp; return True; }
 #  elif defined(VGP_ppc32_linux)
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index b69c1c8..21a2bb7 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -56,7 +56,7 @@
 #include "priv_tytypes.h"
 #include "priv_storage.h"
 #include "priv_readdwarf.h"
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 # include "priv_readelf.h"
 # include "priv_readdwarf3.h"
 # include "priv_readpdb.h"
@@ -597,7 +597,7 @@
 /*---                                                        ---*/
 /*--------------------------------------------------------------*/
 
-#if defined(VGO_linux)  ||  defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /* Helper (indirect) for di_notify_ACHIEVE_ACCEPT_STATE */
 static Bool overlaps_DebugInfoMappings ( const DebugInfoMapping* map1,
@@ -745,7 +745,7 @@
    truncate_DebugInfoMapping_overlaps( di, di->fsm.maps );
 
    /* And acquire new info. */
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    ok = ML_(read_elf_debug_info)( di );
 #  elif defined(VGO_darwin)
    ok = ML_(read_macho_debug_info)( di );
@@ -965,6 +965,11 @@
    is_ro_map = seg->hasR && !seg->hasW && !seg->hasX;
 #  endif
 
+#  if defined(VGO_solaris)
+   is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
+   is_rw_map = seg->hasR && seg->hasW;
+#  endif
+
    if (debug)
       VG_(printf)("di_notify_mmap-3: "
                   "is_rx_map %d, is_rw_map %d, is_ro_map %d\n",
@@ -1017,7 +1022,7 @@
    vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf1k) );
 
    /* We're only interested in mappings of object files. */
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    if (!ML_(is_elf_object_file)( buf1k, (SizeT)sr_Res(preadres), False ))
       return 0;
 #  elif defined(VGO_darwin)
@@ -1422,7 +1427,7 @@
    if (pdbname) ML_(dinfo_free)(pdbname);
 }
 
-#endif /* defined(VGO_linux) || defined(VGO_darwin) */
+#endif /* defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) */
 
 
 /*------------------------------------------------------------*/
@@ -1939,6 +1944,8 @@
 #      elif defined(VGO_darwin)
        // See readmacho.c for an explanation of this.
        VG_STREQ("start_according_to_valgrind", name) ||  // Darwin, darling
+#      elif defined(VGO_solaris)
+       VG_STREQ("_start", name) || // main() is called directly from _start
 #      else
 #        error "Unknown OS"
 #      endif
diff --git a/coregrind/m_debuginfo/priv_readpdb.h b/coregrind/m_debuginfo/priv_readpdb.h
index 117a8c5..50da29b 100644
--- a/coregrind/m_debuginfo/priv_readpdb.h
+++ b/coregrind/m_debuginfo/priv_readpdb.h
@@ -32,7 +32,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 #ifndef __PRIV_READPDB_H
 #define __PRIV_READPDB_H
@@ -59,7 +59,7 @@
 
 #endif /* ndef __PRIV_READPDB_H */
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 3909327..0111d6a 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -29,7 +29,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 #include "pub_core_basics.h"
 #include "pub_core_debuginfo.h"
@@ -1719,11 +1719,11 @@
 
 /* --------------- Decls --------------- */
 
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_solaris)
 #  define FP_REG         5
 #  define SP_REG         4
 #  define RA_REG_DEFAULT 8
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris)
 #  define FP_REG         6
 #  define SP_REG         7
 #  define RA_REG_DEFAULT 16
@@ -1825,6 +1825,7 @@
     DW_CFA_GNU_window_save    = 0x2d, /* GNU extension */
     DW_CFA_GNU_args_size      = 0x2e, /* GNU extension */
     DW_CFA_GNU_negative_offset_extended = 0x2f, /* GNU extension */
+    DW_CFA_ORCL_arg_loc       = 0x30, /* Oracle extension */
     DW_CFA_hi_user            = 0x3f
   };
 
@@ -2023,6 +2024,7 @@
       DiCursor ehframe_image;
       Addr     ehframe_avma;
       Addr     text_bias;
+      Addr     got_avma;
    }
    AddressDecodingInfo;
 
@@ -2650,6 +2652,7 @@
    UChar    encoding      = adi->encoding;
    DiCursor ehframe_image = adi->ehframe_image;
    Addr     ehframe_avma  = adi->ehframe_avma;
+   Addr     got_avma      = adi->got_avma;
 
    vg_assert((encoding & DW_EH_PE_indirect) == 0);
 
@@ -2661,8 +2664,7 @@
          base = ehframe_avma + ML_(cur_minus)(*data, ehframe_image);
          break;
       case DW_EH_PE_datarel:
-         vg_assert(0);
-         base = /* data base address */ 0;
+         base = got_avma;
          break;
       case DW_EH_PE_textrel:
          vg_assert(0);
@@ -3361,6 +3363,11 @@
          }
          break;
 
+      case DW_CFA_ORCL_arg_loc:
+         if (di->ddump_frames)
+            VG_(printf)("  DW_CFA_ORCL_arg_loc\n");
+         break;
+
       default: 
          VG_(message)(Vg_DebugMsg, "DWARF2 CFI reader: unhandled CFI "
                                    "instruction 0:%d\n", (Int)lo6); 
@@ -3574,6 +3581,11 @@
          VG_(printf)("  sci:DW_CFA_GNU_window_save\n");
          break;
 
+      case DW_CFA_ORCL_arg_loc:
+         /* :TODO: Print all arguments when implemented in libdwarf. */
+         VG_(printf)("  sci:DW_CFA_ORCL_arg_loc\n");
+         break;
+
       default: 
          VG_(printf)("  sci:0:%d\n", (Int)lo6); 
          break;
@@ -4008,6 +4020,7 @@
             adi.ehframe_image = frame_image;
             adi.ehframe_avma  = frame_avma;
             adi.text_bias     = di->text_debug_bias;
+            adi.got_avma      = di->got_avma;
             show_CF_instructions( the_CIEs[this_CIE].instrs, 
                                   the_CIEs[this_CIE].ilen, &adi,
                                   the_CIEs[this_CIE].code_a_f,
@@ -4058,6 +4071,7 @@
          adi.ehframe_image = frame_image;
          adi.ehframe_avma  = frame_avma;
          adi.text_bias     = di->text_debug_bias;
+         adi.got_avma      = di->got_avma;
          fde_initloc = step_encoded_Addr(&adi, &data);
          if (di->trace_cfi) 
             VG_(printf)("fde.initloc     = %#lx\n", fde_initloc);
@@ -4066,6 +4080,7 @@
          adi.ehframe_image = frame_image;
          adi.ehframe_avma  = frame_avma;
          adi.text_bias     = di->text_debug_bias;
+         adi.got_avma      = di->got_avma;
 
          /* WAS (incorrectly):
             fde_arange = read_encoded_Addr(&nbytes, &adi, data);
@@ -4158,6 +4173,7 @@
          adi.ehframe_image = frame_image;
          adi.ehframe_avma  = frame_avma;
          adi.text_bias     = di->text_debug_bias;
+         adi.got_avma      = di->got_avma;
 
          if (di->trace_cfi)
             show_CF_instructions( fde_instrs, fde_ilen, &adi,
@@ -4214,7 +4230,7 @@
     return;
 }
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index 85070e4..553ef7c 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -35,7 +35,7 @@
    without prior written permission.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /* REFERENCE (without which this code will not make much sense):
 
@@ -5268,7 +5268,7 @@
    TRACE_SYMTAB("\n");
 #endif
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index fda4161..c9498e8 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -29,7 +29,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
@@ -54,6 +54,9 @@
 
 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
 #include <elf.h>
+#if defined(VGO_solaris)
+#include <sys/link.h>              /* ElfXX_Dyn, DT_* */
+#endif
 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
 
 /*------------------------------------------------------------*/
@@ -1844,7 +1847,7 @@
       OffT   foff = a_shdr.sh_offset;
       UWord  size = a_shdr.sh_size; /* Do not change this to be signed. */
       UInt   alyn = a_shdr.sh_addralign;
-      Bool   bits = !(a_shdr.sh_type == SHT_NOBITS);
+      Bool   nobits = a_shdr.sh_type == SHT_NOBITS;
       /* Look through our collection of info obtained from the PT_LOAD
          headers, and make 'inrx' and 'inrw' point to the first entry
          in each that intersects 'avma'.  If in each case none is found,
@@ -1870,9 +1873,9 @@
                    foff, foff+size-1, (void*)svma, name);
 
       /* Check for sane-sized segments.  SHT_NOBITS sections have zero
-         size in the file. */
-      if ((foff >= ML_(img_size)(mimg)) 
-          || (foff + (bits ? size : 0) > ML_(img_size)(mimg))) {
+         size in the file and their offsets are just conceptual. */
+      if (!nobits &&
+          (foff >= ML_(img_size)(mimg) || foff + size > ML_(img_size)(mimg))) {
          ML_(symerr)(di, True, "ELF Section extends beyond image end");
          goto out;
       }
@@ -2161,7 +2164,8 @@
 #     if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
          || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \
          || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \
-         || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
+         || defined(VGP_arm64_linux) || defined(VGP_tilegx_linux) \
+         || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
       /* Accept .plt where mapped as rx (code) */
       if (0 == VG_(strcmp)(name, ".plt")) {
          if (inrx && !di->plt_present) {
@@ -2323,6 +2327,9 @@
       DiSlice symtab_escn         = DiSlice_INVALID; // .symtab
       DiSlice dynstr_escn         = DiSlice_INVALID; // .dynstr
       DiSlice dynsym_escn         = DiSlice_INVALID; // .dynsym
+#     if defined(VGO_solaris)
+      DiSlice ldynsym_escn        = DiSlice_INVALID; // .SUNW_ldynsym
+#     endif
       DiSlice debuglink_escn      = DiSlice_INVALID; // .gnu_debuglink
       DiSlice debugaltlink_escn   = DiSlice_INVALID; // .gnu_debugaltlink
       DiSlice debug_line_escn     = DiSlice_INVALID; // .debug_line   (dwarf2)
@@ -2385,8 +2392,8 @@
                              _sec_name, (ULong)_sec_escn.ioff, \
                              ((ULong)_sec_escn.ioff) + _sec_escn.szB - 1); \
                /* SHT_NOBITS sections have zero size in the file. */ \
-               if ( a_shdr.sh_offset \
-                    + (nobits ? 0 : _sec_escn.szB) > ML_(img_size)(mimg) ) { \
+               if (!nobits && \
+                   a_shdr.sh_offset + _sec_escn.szB > ML_(img_size)(mimg) ) { \
                   ML_(symerr)(di, True, \
                               "   section beyond image end?!"); \
                   goto out; \
@@ -2404,6 +2411,9 @@
          FIND(".dynstr",            dynstr_escn)
          FIND(".symtab",            symtab_escn)
          FIND(".strtab",            strtab_escn)
+#        if defined(VGO_solaris)
+         FIND(".SUNW_ldynsym",      ldynsym_escn)
+#        endif
 
          FIND(".gnu_debuglink",     debuglink_escn)
          FIND(".gnu_debugaltlink",  debugaltlink_escn)
@@ -2680,8 +2690,8 @@
                                 (ULong)_sec_escn.ioff, \
                                 ((ULong)_sec_escn.ioff) + _sec_escn.szB - 1); \
                   /* SHT_NOBITS sections have zero size in the file. */ \
-                  if (a_shdr.sh_offset \
-                      + (nobits ? 0 : _sec_escn.szB) > ML_(img_size)(dimg)) { \
+                  if (!nobits && a_shdr.sh_offset \
+                      + _sec_escn.szB > ML_(img_size)(dimg)) { \
                      ML_(symerr)(di, True, \
                                  "   section beyond image end?!"); \
                      goto out; \
@@ -2840,6 +2850,9 @@
       /* Check some sizes */
       vg_assert((dynsym_escn.szB % sizeof(ElfXX_Sym)) == 0);
       vg_assert((symtab_escn.szB % sizeof(ElfXX_Sym)) == 0);
+#     if defined(VGO_solaris)
+      vg_assert((ldynsym_escn.szB % sizeof(ElfXX_Sym)) == 0);
+#     endif
 
       /* TOPLEVEL */
       /* Read symbols */
@@ -2859,6 +2872,11 @@
          read_elf_symtab(di, "dynamic symbol table",
                          &dynsym_escn, &dynstr_escn, &opd_escn,
                          False);
+#        if defined(VGO_solaris)
+         read_elf_symtab(di, "local dynamic symbol table",
+                         &ldynsym_escn, &dynstr_escn, &opd_escn,
+                         False);
+#        endif
       }
 
       /* TOPLEVEL */
@@ -3010,7 +3028,7 @@
    /* NOTREACHED */
 }
 
-#endif // defined(VGO_linux)
+#endif // defined(VGO_linux) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c
index 3a0d422..cc81831 100644
--- a/coregrind/m_debuginfo/readpdb.c
+++ b/coregrind/m_debuginfo/readpdb.c
@@ -35,7 +35,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 #include "pub_core_basics.h"
 #include "pub_core_debuginfo.h"
@@ -2584,7 +2584,7 @@
    return res;
 }
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index f4b1d2f..c455ca3 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -1457,7 +1457,7 @@
    vlena = VG_(strlen)(a_name);
    vlenb = VG_(strlen)(b_name);
 
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
 #    define VERSION_CHAR '@'
 #  elif defined(VGO_darwin)
 #    define VERSION_CHAR '$'
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 469c694..66f567c 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -56,6 +56,9 @@
 #include "pub_core_vkiscnums.h"  /* for syscall numbers */
 #include "pub_core_debuglog.h"   /* our own iface */
 #include "pub_core_clreq.h"      /* for RUNNING_ON_VALGRIND */
+#if defined(VGO_solaris)
+#include "pub_core_vki.h"        /* for EINTR and ERESTART */
+#endif
 
 static Bool clo_xml;
 
@@ -556,6 +559,97 @@
   return __res;
 }
 
+#elif defined(VGP_x86_solaris)
+static UInt local_sys_write_stderr ( const HChar* buf, Int n )
+{
+   UInt res, err;
+   Bool restart;
+
+   do {
+      /* The Solaris kernel does not restart syscalls automatically so it is
+         done here. */
+      __asm__ __volatile__ (
+         "movl  %[n], %%eax\n"          /* push n */
+         "pushl %%eax\n"
+         "movl  %[buf], %%eax\n"        /* push buf */
+         "pushl %%eax\n"
+         "movl  $2, %%eax\n"            /* push stderr */
+         "pushl %%eax\n"
+         "movl  $"VG_STRINGIFY(__NR_write)", %%eax\n"
+         "pushl %%eax\n"                /* push fake return address */
+         "int   $0x91\n"                /* write(stderr, buf, n) */
+         "movl  $0, %%edx\n"            /* assume no error */
+         "jnc   1f\n"                   /* jump if no error */
+         "movl  $1, %%edx\n"            /* set error flag */
+         "1: "
+         "addl  $16, %%esp\n"           /* pop x4 */
+         : "=&a" (res), "=d" (err)
+         : [buf] "g" (buf), [n] "g" (n)
+         : "cc");
+      restart = err && (res == VKI_EINTR || res == VKI_ERESTART);
+   } while (restart);
+
+   return res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+   UInt res;
+
+   /* The getpid() syscall never returns EINTR or ERESTART so there is no need
+      for restarting it. */
+   __asm__ __volatile__ (
+      "movl $"VG_STRINGIFY(__NR_getpid)", %%eax\n"
+      "int  $0x91\n"                    /* getpid() */
+      : "=a" (res)
+      :
+      : "edx", "cc");
+
+   return res;
+}
+
+#elif defined(VGP_amd64_solaris)
+static UInt local_sys_write_stderr ( const HChar* buf, Int n )
+{
+   ULong res, err;
+   Bool restart;
+
+   do {
+      /* The Solaris kernel does not restart syscalls automatically so it is
+         done here. */
+      __asm__ __volatile__ (
+         "movq  $2, %%rdi\n"            /* push stderr */
+         "movq  $"VG_STRINGIFY(__NR_write)", %%rax\n"
+         "syscall\n"                    /* write(stderr, buf, n) */
+         "movq  $0, %%rdx\n"            /* assume no error */
+         "jnc   1f\n"                   /* jump if no error */
+         "movq  $1, %%rdx\n"            /* set error flag */
+         "1: "
+         : "=a" (res), "=d" (err)
+         : "S" (buf), "d" (n)
+         : "cc");
+      restart = err && (res == VKI_EINTR || res == VKI_ERESTART);
+   } while (restart);
+
+   return res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+   UInt res;
+
+   /* The getpid() syscall never returns EINTR or ERESTART so there is no need
+      for restarting it. */
+   __asm__ __volatile__ (
+      "movq $"VG_STRINGIFY(__NR_getpid)", %%rax\n"
+      "syscall\n"                       /* getpid() */
+      : "=a" (res)
+      :
+      : "edx", "cc");
+
+   return res;
+}
+
 #else
 # error Unknown platform
 #endif
diff --git a/coregrind/m_demangle/demangle.c b/coregrind/m_demangle/demangle.c
index 1054c14..883e164 100644
--- a/coregrind/m_demangle/demangle.c
+++ b/coregrind/m_demangle/demangle.c
@@ -282,6 +282,7 @@
          case 'D': EMITSO('$'); break;
          case 'L': EMITSO('('); break;
          case 'R': EMITSO(')'); break;
+         case 'S': EMITSO('/'); break;
          case 'Z': EMITSO('Z'); break;
          default: error = True; goto out;
       }
diff --git a/coregrind/m_dispatch/dispatch-amd64-solaris.S b/coregrind/m_dispatch/dispatch-amd64-solaris.S
new file mode 100644
index 0000000..740505d
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-amd64-solaris.S
@@ -0,0 +1,256 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                     dispatch-amd64-solaris.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2013 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.
+*/
+
+#if defined(VGP_amd64_solaris)
+
+#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 */
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- The dispatch loop.  VG_(disp_run_translations) is    ---*/
+/*--- used to run all translations,                        ---*/
+/*--- including no-redir ones.                             ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Entry and preamble (set everything up)       ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+void VG_(disp_run_translations)( UWord* two_words,
+                                 void*  guest_state, 
+                                 Addr   host_addr );
+*/
+.text
+.globl VG_(disp_run_translations)
+.type  VG_(disp_run_translations), @function
+VG_(disp_run_translations):
+        /* %rdi holds two_words    */
+	/* %rsi holds guest_state  */
+	/* %rdx holds host_addr    */
+
+        /* The preamble */
+
+        /* Save integer registers, since this is a pseudo-function. */
+        pushq   %rax
+	pushq	%rbx
+	pushq	%rcx
+        pushq   %rdx
+	pushq	%rsi
+	pushq	%rbp
+	pushq	%r8
+	pushq	%r9
+	pushq	%r10
+	pushq	%r11
+	pushq	%r12
+	pushq	%r13
+	pushq	%r14
+	pushq	%r15
+        /* %rdi must be saved last */
+	pushq	%rdi
+
+        /* Get the host CPU in the state expected by generated code. */
+
+	/* set host FPU control word to the default mode expected 
+           by VEX-generated code.  See comments in libvex.h for
+           more info. */
+	finit
+	pushq	$0x027F
+	fldcw	(%rsp)
+	addq	$8, %rsp
+	
+	/* set host SSE control word to the default mode expected 
+	   by VEX-generated code. */
+	pushq	$0x1F80
+	ldmxcsr	(%rsp)
+	addq	$8, %rsp
+
+	/* set dir flag to known value */
+	cld
+
+	/* Set up the guest state pointer */
+	movq	%rsi, %rbp
+
+        /* and jump into the code cache.  Chained translations in
+           the code cache run, until for whatever reason, they can't
+           continue.  When that happens, the translation in question
+           will jump (or call) to one of the continuation points
+           VG_(cp_...) below. */
+        jmpq    *%rdx
+       	/*NOTREACHED*/	
+
+/*----------------------------------------------------*/
+/*--- Postamble and exit.                          ---*/
+/*----------------------------------------------------*/
+
+postamble:
+        /* At this point, %rax and %rdx contain two
+           words to be returned to the caller.  %rax
+           holds a TRC value, and %rdx optionally may
+           hold another word (for CHAIN_ME exits, the
+           address of the place to patch.) */
+        
+	/* We're leaving.  Check that nobody messed with %mxcsr
+           or %fpucw.  We can't mess with %rax or %rdx here as they
+           hold the tentative return values, but any others are OK. */
+#if !defined(ENABLE_INNER)
+        /* This check fails for self-hosting, so skip in that case */
+	pushq	$0
+	fstcw	(%rsp)
+	cmpl	$0x027F, (%rsp)
+	popq	%r15 /* get rid of the word without trashing %rflags */
+	jnz	invariant_violation
+#endif
+	pushq	$0
+	stmxcsr	(%rsp)
+	andl	$0xFFFFFFC0, (%rsp)  /* mask out status flags */
+	cmpl	$0x1F80, (%rsp)
+	popq	%r15
+	jnz	invariant_violation
+	/* otherwise we're OK */
+	jmp	remove_frame
+invariant_violation:
+	movq	$VG_TRC_INVARIANT_FAILED, %rax
+        movq    $0, %rdx
+
+remove_frame:
+        /* Pop %rdi, stash return values */
+	popq	%rdi
+        movq    %rax, 0(%rdi)
+        movq    %rdx, 8(%rdi)
+        /* Now pop everything else */
+	popq	%r15
+	popq	%r14
+	popq	%r13
+	popq	%r12
+	popq	%r11
+	popq	%r10
+	popq	%r9
+	popq	%r8
+	popq	%rbp
+	popq	%rsi
+	popq	%rdx
+	popq	%rcx
+	popq	%rbx
+	popq	%rax
+	ret	
+        
+/*----------------------------------------------------*/
+/*--- Continuation points                          ---*/
+/*----------------------------------------------------*/
+
+/* ------ Chain me to slow entry point ------ */
+.global VG_(disp_cp_chain_me_to_slowEP)
+VG_(disp_cp_chain_me_to_slowEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_S, RA) */
+        movq    $VG_TRC_CHAIN_ME_TO_SLOW_EP, %rax
+        popq    %rdx
+        /* 10 = movabsq $VG_(disp_chain_me_to_slowEP), %r11;
+           3  = call *%r11 */
+        subq    $10+3, %rdx
+        jmp     postamble
+
+/* ------ Chain me to fast entry point ------ */
+.global VG_(disp_cp_chain_me_to_fastEP)
+VG_(disp_cp_chain_me_to_fastEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_F, RA) */
+        movq    $VG_TRC_CHAIN_ME_TO_FAST_EP, %rax
+        popq    %rdx
+        /* 10 = movabsq $VG_(disp_chain_me_to_fastEP), %r11;
+           3  = call *%r11 */
+        subq    $10+3, %rdx
+        jmp     postamble
+
+/* ------ Indirect but boring jump ------ */
+.global VG_(disp_cp_xindir)
+VG_(disp_cp_xindir):
+	/* Where are we going? */
+	movq	OFFSET_amd64_RIP(%rbp), %rax
+
+        /* stats only */
+        addl    $1, VG_(stats__n_xindirs_32)
+        
+	/* try a fast lookup in the translation cache */
+	movabsq $VG_(tt_fast), %rcx
+	movq	%rax, %rbx		/* next guest addr */
+	andq	$VG_TT_FAST_MASK, %rbx	/* entry# */
+	shlq	$4, %rbx		/* entry# * sizeof(FastCacheEntry) */
+	movq	0(%rcx,%rbx,1), %r10	/* .guest */
+	movq	8(%rcx,%rbx,1), %r11	/* .host */
+	cmpq	%rax, %r10
+	jnz	fast_lookup_failed
+
+        /* Found a match.  Jump to .host. */
+	jmp 	*%r11
+	ud2	/* persuade insn decoders not to speculate past here */
+
+fast_lookup_failed:
+        /* stats only */
+        addl    $1, VG_(stats__n_xindir_misses_32)
+
+	movq	$VG_TRC_INNER_FASTMISS, %rax
+        movq    $0, %rdx
+	jmp	postamble
+
+/* ------ Assisted jump ------ */
+.global VG_(disp_cp_xassisted)
+VG_(disp_cp_xassisted):
+        /* %rbp contains the TRC */
+        movq    %rbp, %rax
+        movq    $0, %rdx
+        jmp     postamble
+
+/* ------ Event check failed ------ */
+.global VG_(disp_cp_evcheck_fail)
+VG_(disp_cp_evcheck_fail):
+       	movq	$VG_TRC_INNER_COUNTERZERO, %rax
+        movq    $0, %rdx
+	jmp	postamble
+
+
+.size VG_(disp_run_translations), .-VG_(disp_run_translations)
+
+#endif // defined(VGP_amd64_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_dispatch/dispatch-x86-solaris.S b/coregrind/m_dispatch/dispatch-x86-solaris.S
new file mode 100644
index 0000000..3c7762b
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-x86-solaris.S
@@ -0,0 +1,247 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                       dispatch-x86-solaris.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2012 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.
+*/
+
+#if defined(VGP_x86_solaris)
+
+#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 */
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- The dispatch loop.  VG_(disp_run_translations) is    ---*/
+/*--- used to run all translations,                        ---*/
+/*--- including no-redir ones.                             ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Entry and preamble (set everything up)       ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+void VG_(disp_run_translations)( UWord* two_words,
+                                 void*  guest_state, 
+                                 Addr   host_addr );
+*/
+.text
+.globl VG_(disp_run_translations)
+.type  VG_(disp_run_translations), @function
+VG_(disp_run_translations):
+        /* 0(%esp) holds our return address. */
+	/* 4(%esp) holds two_words */
+	/* 8(%esp) holds guest_state */
+	/* 12(%esp) holds host_addr */
+
+        /* The preamble */
+
+        /* Save integer registers, since this is a pseudo-function. */
+        pushl   %eax
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+	
+	/* 28+4(%esp) holds two_words */
+	/* 28+8(%esp) holds guest_state */
+	/* 28+12(%esp) holds host_addr */
+
+        /* Get the host CPU in the state expected by generated code. */
+
+	/* set host FPU control word to the default mode expected 
+           by VEX-generated code.  See comments in libvex.h for
+           more info. */
+	finit
+	pushl	$0x027F
+	fldcw	(%esp)
+	addl	$4, %esp
+	
+	/* set host SSE control word to the default mode expected 
+	   by VEX-generated code. */
+	cmpl	$0, VG_(machine_x86_have_mxcsr)
+	jz	L1
+	pushl	$0x1F80
+	ldmxcsr	(%esp)
+	addl	$4, %esp
+L1:
+	/* set dir flag to known value */
+	cld
+
+	/* Set up the guest state pointer */
+	movl	28+8(%esp), %ebp
+
+        /* and jump into the code cache.  Chained translations in
+           the code cache run, until for whatever reason, they can't
+           continue.  When that happens, the translation in question
+           will jump (or call) to one of the continuation points
+           VG_(cp_...) below. */
+        jmpl    *28+12(%esp)
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- Postamble and exit.                          ---*/
+/*----------------------------------------------------*/
+
+postamble:
+        /* At this point, %eax and %edx contain two
+           words to be returned to the caller.  %eax
+           holds a TRC value, and %edx optionally may
+           hold another word (for CHAIN_ME exits, the
+           address of the place to patch.) */
+
+	/* We're leaving.  Check that nobody messed with %mxcsr
+           or %fpucw.  We can't mess with %eax or %edx here as they
+	   holds the tentative return value, but any others are OK. */
+#if !defined(ENABLE_INNER)
+        /* This check fails for self-hosting, so skip in that case */
+	pushl	$0
+	fstcw	(%esp)
+	cmpl	$0x027F, (%esp)
+	popl	%esi /* get rid of the word without trashing %eflags */
+	jnz	invariant_violation
+#endif
+#	cmpl	$0, VG_(machine_x86_have_mxcsr)
+	jz	L2
+	pushl	$0
+	stmxcsr	(%esp)
+	andl	$0xFFFFFFC0, (%esp)  /* mask out status flags */
+	cmpl	$0x1F80, (%esp)
+	popl	%esi
+	jnz	invariant_violation
+L2:	/* otherwise we're OK */
+	jmp	remove_frame
+invariant_violation:
+	movl	$VG_TRC_INVARIANT_FAILED, %eax
+        movl    $0, %edx
+
+remove_frame:
+        /* Stash return values */
+        movl    28+4(%esp), %edi        /* two_words */
+        movl    %eax, 0(%edi)
+        movl    %edx, 4(%edi)
+        /* Restore int regs and return. */
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	popl	%eax
+	ret	
+        
+/*----------------------------------------------------*/
+/*--- Continuation points                          ---*/
+/*----------------------------------------------------*/
+
+/* ------ Chain me to slow entry point ------ */
+.global VG_(disp_cp_chain_me_to_slowEP)
+VG_(disp_cp_chain_me_to_slowEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_S, RA) */
+        movl    $VG_TRC_CHAIN_ME_TO_SLOW_EP, %eax
+        popl    %edx
+        /* 5 = movl $VG_(disp_chain_me_to_slowEP), %edx;
+           2 = call *%edx */
+        subl    $5+2, %edx
+        jmp     postamble
+
+/* ------ Chain me to fast entry point ------ */
+.global VG_(disp_cp_chain_me_to_fastEP)
+VG_(disp_cp_chain_me_to_fastEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_F, RA) */
+        movl    $VG_TRC_CHAIN_ME_TO_FAST_EP, %eax
+        popl    %edx
+        /* 5 = movl $VG_(disp_chain_me_to_fastEP), %edx;
+           2 = call *%edx */
+        subl    $5+2, %edx
+        jmp     postamble
+
+/* ------ Indirect but boring jump ------ */
+.global VG_(disp_cp_xindir)
+VG_(disp_cp_xindir):
+	/* Where are we going? */
+	movl	OFFSET_x86_EIP(%ebp), %eax
+
+        /* stats only */
+        addl    $1, VG_(stats__n_xindirs_32)
+        
+        /* try a fast lookup in the translation cache */
+        movl    %eax, %ebx                      /* next guest addr */
+        andl    $VG_TT_FAST_MASK, %ebx          /* entry# */
+        movl    0+VG_(tt_fast)(,%ebx,8), %esi   /* .guest */
+        movl    4+VG_(tt_fast)(,%ebx,8), %edi   /* .host */
+        cmpl    %eax, %esi
+        jnz     fast_lookup_failed
+
+        /* Found a match.  Jump to .host. */
+	jmp 	*%edi
+	ud2	/* persuade insn decoders not to speculate past here */
+
+fast_lookup_failed:
+        /* stats only */
+        addl    $1, VG_(stats__n_xindir_misses_32)
+
+	movl	$VG_TRC_INNER_FASTMISS, %eax
+        movl    $0, %edx
+	jmp	postamble
+
+/* ------ Assisted jump ------ */
+.global VG_(disp_cp_xassisted)
+VG_(disp_cp_xassisted):
+        /* %ebp contains the TRC */
+        movl    %ebp, %eax
+        movl    $0, %edx
+        jmp     postamble
+
+/* ------ Event check failed ------ */
+.global VG_(disp_cp_evcheck_fail)
+VG_(disp_cp_evcheck_fail):
+       	movl	$VG_TRC_INNER_COUNTERZERO, %eax
+        movl    $0, %edx
+	jmp	postamble
+
+
+.size VG_(disp_run_translations), .-VG_(disp_run_translations)
+
+#endif // defined(VGP_x86_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_gdbserver/m_gdbserver.c b/coregrind/m_gdbserver/m_gdbserver.c
index 263bd4a..fba0a2b 100644
--- a/coregrind/m_gdbserver/m_gdbserver.c
+++ b/coregrind/m_gdbserver/m_gdbserver.c
@@ -828,6 +828,7 @@
 
 static void give_control_back_to_vgdb(void)
 {
+#if !defined(VGO_solaris)
    /* cause a SIGSTOP to be sent to ourself, so that vgdb takes control.
       vgdb will then restore the stack so as to resume the activity
       before the ptrace (typically do_syscall_WRK). */
@@ -842,6 +843,15 @@
               "vgdb did not took control. Did you kill vgdb ?\n"
               "busy %d vgdb_interrupted_tid %d\n",
               busy, vgdb_interrupted_tid);
+#else /* defined(VGO_solaris) */
+   /* On Solaris, this code is run within the context of an agent thread
+      (see vgdb-invoker-solaris.c and "PCAGENT" control message in
+      proc(4)). Exit the agent thread now.
+    */
+   SysRes sres = VG_(do_syscall0)(SYS_lwp_exit);
+   if (sr_isError(sres))
+      vg_assert2(0, "The agent thread could not be exited\n");
+#endif /* !defined(VGO_solaris) */
 }
 
 /* Using ptrace calls, vgdb will force an invocation of gdbserver.
diff --git a/coregrind/m_initimg/initimg-solaris.c b/coregrind/m_initimg/initimg-solaris.c
new file mode 100644
index 0000000..4db11a8
--- /dev/null
+++ b/coregrind/m_initimg/initimg-solaris.c
@@ -0,0 +1,1007 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Solaris             ---*/
+/*---                                            initimg-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2014 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+#if defined(VGO_solaris)
+
+/* Note: This file is based on initimg-linux.c. */
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_machine.h"
+#include "pub_core_ume.h"
+#include "pub_core_options.h"
+#include "pub_core_tooliface.h"       /* VG_TRACK */
+#include "pub_core_threadstate.h"     /* ThreadArchState */
+#include "priv_initimg_pathscan.h"
+#include "pub_core_initimg.h"         /* self */
+
+
+/*====================================================================*/
+/*=== Loading the client                                           ===*/
+/*====================================================================*/
+
+/* Load the client whose name is VG_(argv_the_exename). */
+static void load_client(/*OUT*/ExeInfo *info,
+                        /*OUT*/HChar *out_exe_name, SizeT out_exe_name_size)
+{
+   const HChar *exe_name;
+   Int ret;
+   SysRes res;
+
+   vg_assert(VG_(args_the_exename));
+   exe_name = ML_(find_executable)(VG_(args_the_exename));
+
+   if (!exe_name) {
+      VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
+      /* Return POSIX's NOTFOUND. */
+      VG_(exit)(127);
+      /*NOTREACHED*/
+   }
+
+   VG_(memset)(info, 0, sizeof(*info));
+   ret = VG_(do_exec)(exe_name, info);
+   if (ret < 0) {
+      VG_(printf)("valgrind: could not execute '%s'\n", exe_name);
+      VG_(exit)(1);
+      /*NOTREACHED*/
+   }
+
+   /* The client was successfully loaded!  Continue. */
+
+   /* Save resolved exename. */
+   if (VG_(strlen)(exe_name) + 1 > out_exe_name_size) {
+      /* This should not really happen. */
+      VG_(printf)("valgrind: execname %s is too long\n", exe_name);
+      VG_(exit)(1);
+      /*NOTREACHED*/
+   }
+   VG_(strcpy)(out_exe_name, exe_name);
+
+   /* Get hold of a file descriptor which refers to the client executable.
+      This is needed for attaching to GDB. */
+   res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
+   if (!sr_isError(res))
+      VG_(cl_exec_fd) = sr_Res(res);
+
+   /* Set initial brk values. */
+   VG_(brk_base) = VG_(brk_limit) = info->brkbase;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's environment                          ===*/
+/*====================================================================*/
+
+/* Prepare the client's environment.  This is basically a copy of our
+   environment, except:
+
+     LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
+                ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
+                $LD_PRELOAD
+
+   If this is missing, then it is added.
+
+   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.  The copy is VG_(malloc)'d space.
+*/
+static HChar **setup_client_env(HChar **origenv, const HChar *toolname)
+{
+   const HChar *ld_preload = "LD_PRELOAD=";
+   SizeT ld_preload_len = VG_(strlen)(ld_preload);
+   Bool ld_preload_done = False;
+   SizeT vglib_len = VG_(strlen)(VG_(libdir));
+
+   HChar **cpp;
+   HChar **ret;
+   HChar *preload_tool_path;
+   SizeT envc, i;
+
+   /* Alloc space for the
+        <path>/vgpreload_core-<platform>.so and
+        <path>/vgpreload_<tool>-<platform>.so
+      paths.  We might not need the space for the tool path, but it doesn't
+      hurt to over-allocate briefly.  */
+   SizeT preload_core_path_size = vglib_len + sizeof("/vgpreload_core-") - 1
+                                            + sizeof(VG_PLATFORM) - 1
+                                            + sizeof(".so");
+   SizeT preload_tool_path_size = vglib_len + sizeof("/vgpreload_") - 1
+                                            + VG_(strlen)(toolname) + 1 /*-*/
+                                            + sizeof(VG_PLATFORM) - 1
+                                            + sizeof(".so");
+   SizeT preload_string_size = preload_core_path_size
+                               + preload_tool_path_size;
+   HChar *preload_string = VG_(malloc)("initimg-solaris.sce.1",
+                                       preload_string_size);
+
+   /* Check that the parameters are sane. */
+   vg_assert(origenv);
+   vg_assert(toolname);
+
+   /* Determine if there's a vgpreload_<tool>-<platform>.so file, and setup
+      preload_string. */
+   preload_tool_path = VG_(malloc)("initimg-solaris.sce.2",
+                                   preload_tool_path_size);
+   VG_(sprintf)(preload_tool_path, "%s/vgpreload_%s-%s.so", VG_(libdir),
+                toolname, VG_PLATFORM);
+   if (!VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/)) {
+      /* The tool's .so exists, put it into LD_PRELOAD with the core's so. */
+      VG_(sprintf)(preload_string, "%s/vgpreload_core-%s.so:%s", VG_(libdir),
+                   VG_PLATFORM, preload_tool_path);
+   }
+   else {
+      /* The tool's .so doesn't exist, put only the core's .so into
+         LD_PRELOAD. */
+      VG_(sprintf)(preload_string, "%s/vgpreload_core-%s.so", VG_(libdir),
+                   VG_PLATFORM);
+   }
+   VG_(free)(preload_tool_path);
+
+   VG_(debugLog)(2, "initimg", "preload_string:\n");
+   VG_(debugLog)(2, "initimg", "  \"%s\"\n", preload_string);
+
+   /* Count the original size of the env. */
+   envc = 0;
+   for (cpp = origenv; *cpp; cpp++)
+      envc++;
+
+   /* Allocate a new space, envc + 1 new entry + NULL. */
+   ret = VG_(malloc)("initimg-solaris.sce.3", sizeof(HChar*) * (envc + 1 + 1));
+
+   /* Copy it over. */
+   for (cpp = ret; *origenv; )
+      *cpp++ = *origenv++;
+   *cpp = NULL;
+
+   vg_assert(envc == cpp - ret);
+
+   /* Walk over the new environment, mashing as we go. */
+   for (cpp = ret; *cpp; cpp++) {
+      if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len))
+         continue;
+
+      /* LD_PRELOAD entry found, smash it. */
+      SizeT size = VG_(strlen)(*cpp) + 1 /*:*/
+                                     + preload_string_size;
+      HChar *cp = VG_(malloc)("initimg-solaris.sce.4", size);
+
+      VG_(sprintf)(cp, "%s%s:%s", ld_preload, preload_string,
+                   (*cpp) + ld_preload_len);
+      *cpp = cp;
+
+      ld_preload_done = True;
+   }
+
+   /* Add the missing bits. */
+   if (!ld_preload_done) {
+      SizeT size = ld_preload_len + preload_string_size;
+      HChar *cp = VG_(malloc)("initimg-solaris.sce.5", size);
+
+      VG_(sprintf)(cp, "%s%s", ld_preload, preload_string);
+      ret[envc++] = cp;
+   }
+
+   /* We've got ret[0 .. envc-1] live now. */
+
+   /* Find and remove a binding for VALGRIND_LAUNCHER. */
+   {
+      const HChar *v_launcher = VALGRIND_LAUNCHER "=";
+      SizeT v_launcher_len = VG_(strlen)(v_launcher);
+
+      for (i = 0; i < envc; i++)
+         if (!VG_(memcmp(ret[i], v_launcher, v_launcher_len))) {
+            /* VALGRIND_LAUNCHER was found. */
+            break;
+         }
+
+      if (i < envc) {
+         /* VALGRIND_LAUNCHER was found, remove it. */
+         for (; i < envc - 1; i++)
+            ret[i] = ret[i + 1];
+         envc--;
+      }
+   }
+
+   VG_(free)(preload_string);
+   ret[envc] = NULL;
+
+   return ret;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's stack                                ===*/
+/*====================================================================*/
+
+/* Add a string onto the string table, and return its address. */
+static HChar *copy_str(HChar **tab, const HChar *str)
+{
+   HChar *cp = *tab;
+   HChar *orig = cp;
+
+   while (*str)
+      *cp++ = *str++;
+   *cp++ = '\0';
+
+   *tab = cp;
+
+   return orig;
+}
+
+
+/* This sets up the client's initial stack, containing the args,
+   environment and aux vector.
+
+   The format of the stack is:
+
+   higher address +-----------------+ <- clstack_end
+                  |                 |
+                  : string table    :
+                  |                 |
+                  +-----------------+
+                  | AT_NULL         |
+                  -                 -
+                  | auxv            |
+                  +-----------------+
+                  | NULL            |
+                  -                 -
+                  | envp            |
+                  +-----------------+
+                  | NULL            |
+                  -                 -
+                  | argv            |
+                  +-----------------+
+                  | argc            |
+   lower address  +-----------------+ <- sp
+                  | undefined       |
+                  :                 :
+
+   Allocate and create the initial client stack.  It is allocated down from
+   clstack_end, which was previously determined by the address space manager.
+   The returned value is the SP value for the client.
+
+   Note that no aux vector is created by kernel on Solaris if the program is
+   statically linked (which is our case).  That means we have to build auxv
+   from scratch. */
+
+static Addr setup_client_stack(void *init_sp,
+                               HChar **orig_envp,
+                               const ExeInfo *info,
+                               Addr clstack_end,
+                               SizeT clstack_max_size,
+                               const HChar *resolved_exe_name)
+{
+   SysRes res;
+   HChar **cpp;
+   HChar *strtab;       /* string table */
+   HChar *stringbase;
+   Addr *ptr;
+   vki_auxv_t *auxv;
+   SizeT stringsize;    /* total size of strings in bytes */
+   SizeT auxsize;       /* total size of auxv in bytes */
+   Int argc;            /* total argc */
+   Int envc;            /* total number of env vars */
+   SizeT stacksize;     /* total client stack size */
+   Addr client_SP;      /* client stack base (initial SP) */
+   Addr clstack_start;
+   Int i;
+
+   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end + 1));
+   vg_assert(VG_(args_the_exename));
+   vg_assert(VG_(args_for_client));
+
+   /* ==================== compute sizes ==================== */
+
+   /* First of all, work out how big the client stack will be. */
+   stringsize = 0;
+
+   /* Paste on the extra args if the loader needs them (i.e. the #!
+      interpreter and its argument). */
+   argc = 0;
+   if (info->interp_name) {
+      argc++;
+      stringsize += VG_(strlen)(info->interp_name) + 1;
+   }
+   if (info->interp_args) {
+      argc++;
+      stringsize += VG_(strlen)(info->interp_args) + 1;
+   }
+
+   /* Now scan the args we're given... */
+   argc++;
+   stringsize += VG_(strlen)(VG_(args_the_exename)) + 1;
+   for (i = 0; i < VG_(sizeXA)(VG_(args_for_client)); i++) {
+      argc++;
+      stringsize += VG_(strlen)(*(HChar**)
+                                  VG_(indexXA)(VG_(args_for_client), i)) + 1;
+   }
+
+   /* ...and the environment. */
+   envc = 0;
+   for (cpp = orig_envp; *cpp; cpp++) {
+      envc++;
+      stringsize += VG_(strlen)(*cpp) + 1;
+   }
+
+   /* Now, how big is the auxv?
+
+      AT_SUN_PLATFORM
+      AT_SUN_EXECNAME
+      AT_PHDR
+      AT_BASE
+      AT_FLAGS
+      AT_PAGESZ
+      AT_SUN_AUXFLAFGS
+      AT_SUN_HWCAP
+      AT_NULL
+
+      It would be possible to also add AT_PHENT, AT_PHNUM, AT_ENTRY,
+      AT_SUN_LDDATA, but they don't seem to be so important. */
+   auxsize = 9 * sizeof(*auxv);
+#  if defined(VGA_x86) || defined(VGA_amd64)
+   /* AT_SUN_PLATFORM string. */
+   stringsize += VG_(strlen)("i86pc") + 1;
+#  else
+#    error "Unknown architecture"
+#  endif
+   /* AT_SUN_EXECNAME string. */
+   stringsize += VG_(strlen)(resolved_exe_name) + 1;
+
+   /* Calculate how big the client stack is. */
+   stacksize =
+      sizeof(Word) +                            /* argc */
+      sizeof(HChar**) +                         /* argc[0] == exename */
+      sizeof(HChar**) * argc +                  /* argv */
+      sizeof(HChar**) +                         /* terminal NULL */
+      sizeof(HChar**) * envc +                  /* envp */
+      sizeof(HChar**) +                         /* terminal NULL */
+      auxsize +                                 /* auxv */
+      VG_ROUNDUP(stringsize, sizeof(Word));     /* strings (aligned) */
+
+   /* The variable 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. */
+
+   /* Calculate base of the string table (aligned). */
+   stringbase = (HChar*)clstack_end - VG_ROUNDUP(stringsize, sizeof(Int));
+   strtab = stringbase;
+
+   clstack_start = VG_PGROUNDDN(client_SP);
+
+   /* Calculate the max stack size. */
+   clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+   /* Record stack extent -- needed for stack-change code. */
+   VG_(clstk_start_base) = clstack_start;
+   VG_(clstk_end) = clstack_end;
+   VG_(clstk_max_size) = clstack_max_size;
+
+   if (0)
+      VG_(printf)("stringsize=%lu, auxsize=%lu, stacksize=%lu, maxsize=%#lx\n"
+                  "clstack_start %#lx\n"
+                  "clstack_end   %#lx\n",
+                  stringsize, auxsize, stacksize, clstack_max_size,
+                  clstack_start, clstack_end);
+
+   /* ==================== allocate space ==================== */
+
+   {
+      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;
+      Bool ok;
+
+      /* So far we've only accounted for space requirements down to the stack
+         pointer.  If this target's ABI requires a redzone below the stack
+         pointer, we need to allocate an extra page, to handle the worst case
+         in which the stack pointer is almost at the bottom of a page, and so
+         there is insufficient room left over to put the redzone in.  In this
+         case the simple thing to do is allocate an extra page, by shrinking
+         the reservation by one page and growing the anonymous area by a
+         corresponding page. */
+      vg_assert(VG_STACK_REDZONE_SZB >= 0);
+      vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE);
+      if (VG_STACK_REDZONE_SZB > 0) {
+         vg_assert(resvn_size > VKI_PAGE_SIZE);
+         resvn_size -= VKI_PAGE_SIZE;
+         anon_start -= VKI_PAGE_SIZE;
+         anon_size += VKI_PAGE_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));
+      vg_assert(resvn_start == clstack_end + 1 - clstack_max_size);
+
+#     ifdef ENABLE_INNER
+      /* Create 1M non-fault-extending stack. */
+      inner_HACK = 1024 * 1024;
+#     endif
+
+      if (0)
+         VG_(printf)("resvn_start=%#lx, resvn_size=%#lx\n"
+                     "anon_start=%#lx, anon_size=%#lx\n",
+                     resvn_start, resvn_size, anon_start, anon_size);
+
+      /* Create a shrinkable reservation followed by an anonymous segment.
+         Together these constitute a growdown stack. */
+      ok = VG_(am_create_reservation)(resvn_start,
+                                      resvn_size - inner_HACK,
+                                      SmUpper,
+                                      anon_size + inner_HACK);
+      if (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,
+                                              info->stack_prot);
+      }
+      if (!ok || sr_isError(res)) {
+         /* Allocation of the stack failed.  We have to stop. */
+         VG_(printf)("valgrind: "
+                     "I failed to allocate space for the application's stack.\n");
+         VG_(printf)("valgrind: "
+                     "This may be the result of a very large --main-stacksize=\n");
+         VG_(printf)("valgrind: setting.  Cannot continue.  Sorry.\n\n");
+         VG_(exit)(1);
+         /*NOTREACHED*/
+      }
+   }
+
+   /* ==================== create client stack ==================== */
+
+   ptr = (Addr*)client_SP;
+
+   /* Copy-out client argc. */
+   *ptr++ = argc;
+
+   /* Copy-out client argv. */
+   if (info->interp_name) {
+      *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
+      VG_(free)(info->interp_name);
+   }
+   if (info->interp_args) {
+      *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
+      VG_(free)(info->interp_args);
+   }
+
+   *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
+   for (i = 0; i < VG_(sizeXA)(VG_(args_for_client)); i++)
+      *ptr++ = (Addr)copy_str(
+                  &strtab, *(HChar**) VG_(indexXA)(VG_(args_for_client), i));
+   *ptr++ = 0;
+
+   /* Copy-out envp. */
+   VG_(client_envp) = (HChar**)ptr;
+   for (cpp = orig_envp; *cpp; ptr++, cpp++)
+      *ptr = (Addr)copy_str(&strtab, *cpp);
+   *ptr++ = 0;
+
+   /* Create aux vector. */
+   auxv = (auxv_t*)ptr;
+   VG_(client_auxv) = (UWord*)ptr;
+
+   /* AT_SUN_PLATFORM */
+   auxv->a_type = VKI_AT_SUN_PLATFORM;
+#  if defined(VGA_x86) || defined(VGA_amd64)
+   auxv->a_un.a_ptr = copy_str(&strtab, "i86pc");
+#  else
+#    error "Unknown architecture"
+#  endif
+   auxv++;
+
+   /* AT_SUN_EXECNAME */
+   auxv->a_type = VKI_AT_SUN_EXECNAME;
+   auxv->a_un.a_ptr = copy_str(&strtab, resolved_exe_name);
+   auxv++;
+
+   /* AT_PHDR */
+   if (info->phdr) {
+      auxv->a_type = VKI_AT_PHDR;
+      auxv->a_un.a_val = info->phdr;
+      auxv++;
+   }
+
+   /* AT_BASE */
+   auxv->a_type = VKI_AT_BASE;
+   auxv->a_un.a_val = info->interp_offset;
+   auxv++;
+
+   /* AT_FLAGS */
+   auxv->a_type = VKI_AT_FLAGS;
+#  if defined(VGA_x86) || defined(VGA_amd64)
+   auxv->a_un.a_val = 0; /* 0 on i86pc */
+#  else
+#    error "Unknown architecture"
+#  endif
+   auxv++;
+
+   /* AT_PAGESZ */
+   auxv->a_type = VKI_AT_PAGESZ;
+   auxv->a_un.a_val = VKI_PAGE_SIZE;
+   auxv++;
+
+   /* AT_SUN_AUXFLAFGS */
+   auxv->a_type = VKI_AT_SUN_AUXFLAGS;
+   /* XXX Handle AF_SUN_SETUGID? */
+   auxv->a_un.a_val = VKI_AF_SUN_HWCAPVERIFY;
+   auxv++;
+
+   /* AT_SUN_HWCAP */
+   {
+      VexArch vex_arch;
+      VexArchInfo vex_archinfo;
+      UInt hwcaps;
+
+      VG_(machine_get_VexArchInfo)(&vex_arch, &vex_archinfo);
+
+#     if defined(VGA_x86)
+      vg_assert(vex_arch == VexArchX86);
+
+      /* Set default hwcaps. */
+      hwcaps =
+           VKI_AV_386_FPU       /* x87-style floating point */
+         | VKI_AV_386_TSC       /* rdtsc insn */
+         | VKI_AV_386_CX8       /* cmpxchg8b insn */
+         | VKI_AV_386_SEP       /* sysenter and sysexit */
+         | VKI_AV_386_AMD_SYSC  /* AMD's syscall and sysret */
+         | VKI_AV_386_CMOV      /* conditional move insns */
+         | VKI_AV_386_MMX       /* MMX insn */
+         | VKI_AV_386_AHF;      /* lahf/sahf insns */
+
+      /* Handle additional hwcaps. */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_X86_SSE1)
+         hwcaps |=
+              VKI_AV_386_FXSR   /* fxsave and fxrstor */
+            | VKI_AV_386_SSE;   /* SSE insns and regs  */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_X86_SSE2) {
+         vg_assert(vex_archinfo.hwcaps & VEX_HWCAPS_X86_SSE1);
+         hwcaps |=
+              VKI_AV_386_SSE2;  /* SSE2 insns and regs */
+      }
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_X86_SSE3) {
+         vg_assert(vex_archinfo.hwcaps & VEX_HWCAPS_X86_SSE2);
+         hwcaps |=
+              VKI_AV_386_SSE3   /* SSE3 insns and regs */
+            | VKI_AV_386_SSSE3; /* Intel SSSE3 insns */
+      }
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_X86_LZCNT)
+         hwcaps |=
+              VKI_AV_386_AMD_LZCNT; /* AMD's LZCNT insn */
+
+      /* No support for:
+         AV_386_AMD_MMX         AMD's MMX insns
+         AV_386_AMD_3DNow       AMD's 3Dnow! insns
+         AV_386_AMD_3DNowx      AMD's 3Dnow! extended insns
+         AV_386_CX16            cmpxchg16b insn
+         AV_386_TSCP            rdtscp instruction
+         AV_386_AMD_SSE4A       AMD's SSE4A insns
+         AV_386_POPCNT          POPCNT insn
+         AV_386_SSE4_1          Intel SSE4.1 insns
+         AV_386_SSE4_2          Intel SSE4.2 insns
+         AV_386_MOVBE           Intel MOVBE insns
+         AV_386_AES             Intel AES insns
+         AV_386_PCLMULQDQ       Intel PCLMULQDQ insn
+         AV_386_XSAVE           Intel XSAVE/XRSTOR insns
+         AV_386_AVX             Intel AVX insns
+         illumos only:
+            AV_386_VMX          Intel VMX support
+            AV_386_AMD_SVM      AMD SVM support
+         solaris only:
+            AV_386_AMD_XOP      AMD XOP insns
+            AV_386_AMD_FMA4     AMD FMA4 insns */
+
+#     elif defined(VGA_amd64)
+      vg_assert(vex_arch == VexArchAMD64);
+
+      /* Set default hwcaps. */
+      hwcaps =
+           VKI_AV_386_FPU       /* x87-style floating point */
+         | VKI_AV_386_TSC       /* rdtsc insn */
+         | VKI_AV_386_CX8       /* cmpxchg8b insn */
+         | VKI_AV_386_AMD_SYSC  /* AMD's syscall and sysret */
+         | VKI_AV_386_CMOV      /* conditional move insns */
+         | VKI_AV_386_MMX       /* MMX insn */
+         | VKI_AV_386_AHF       /* lahf/sahf insns */
+         | VKI_AV_386_FXSR      /* fxsave and fxrstor */
+         | VKI_AV_386_SSE       /* SSE insns and regs  */
+         | VKI_AV_386_SSE2;     /* SSE2 insns and regs */
+
+      /* Handle additional hwcaps. */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_SSE3)
+         hwcaps |=
+              VKI_AV_386_SSE3   /* SSE3 insns and regs */
+            | VKI_AV_386_SSSE3; /* Intel SSSE3 insns */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_CX16)
+         hwcaps |=
+              VKI_AV_386_CX16;  /* cmpxchg16b insn */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_LZCNT)
+         hwcaps |=
+              VKI_AV_386_AMD_LZCNT; /* AMD's LZCNT insn */
+      if (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_RDTSCP)
+         hwcaps |=
+              VKI_AV_386_TSCP;  /* rdtscp instruction */
+      if ((vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_SSE3) &&
+          (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_CX16)) {
+         /* The CPUID simulation provided by VEX claims to have POPCNT, AES
+            and SSE4 (SSE4.1/SSE4.2) in the SSE3+CX16 configuration. */
+         hwcaps |=
+              VKI_AV_386_POPCNT /* POPCNT insn */
+            | VKI_AV_386_AES    /* Intel AES insns */
+            | VKI_AV_386_SSE4_1 /* Intel SSE4.1 insns */
+            | VKI_AV_386_SSE4_2; /* Intel SSE4.2 insns */
+      }
+      if ((vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_SSE3) &&
+          (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_CX16) &&
+          (vex_archinfo.hwcaps & VEX_HWCAPS_AMD64_AVX)) {
+         /* The CPUID simulation provided by VEX claims to have PCLMULQDQ and
+            XSAVE in the SSE3+CX16+AVX configuration. */
+         hwcaps |=
+              VKI_AV_386_PCLMULQDQ /* Intel PCLMULQDQ insn */
+            | VKI_AV_386_XSAVE; /* Intel XSAVE/XRSTOR insns */
+      }
+      /* No support for:
+         AV_386_SEP             sysenter and sysexit
+         AV_386_AMD_MMX         AMD's MMX insns
+         AV_386_AMD_3DNow       AMD's 3Dnow! insns
+         AV_386_AMD_3DNowx      AMD's 3Dnow! extended insns
+         AV_386_AMD_SSE4A       AMD's SSE4A insns
+         AV_386_MOVBE           Intel MOVBE insns
+         AV_386_AVX             Intel AVX insns
+         illumos only:
+            AV_386_VMX          Intel VMX support
+            AV_386_AMD_SVM      AMD SVM support
+         solaris only:
+            AV_386_AMD_XOP      AMD XOP insns
+            AV_386_AMD_FMA4     AMD FMA4 insns
+
+         TODO VEX supports AVX, BMI and AVX2. Investigate if they can be
+         enabled on Solaris/illumos.
+       */
+
+#     else
+#       error "Unknown architecture"
+#     endif
+
+      auxv->a_type = VKI_AT_SUN_HWCAP;
+      auxv->a_un.a_val = hwcaps;
+      auxv++;
+   }
+
+   /* AT_SUN_HWCAP2 */
+   {
+      /* No support for:
+         illumos only:
+            AV_386_2_F16C       F16C half percision extensions
+            AV_386_2_RDRAND     RDRAND insn
+         solaris only:
+            AV2_386_RDRAND      Intel RDRAND insns
+            AV2_386_FMA         Intel FMA insn
+            AV2_386_F16C        IEEE half precn(float) insn
+            AV2_386_AMD_TBM     AMD TBM insn
+            AV2_386_BMI1        Intel BMI1 insn
+            AV2_386_FSGSBASE    Intel RD/WR FS/GSBASE insn
+            AV2_386_AVX2        Intel AVX2 insns
+            AV2_386_BMI2        Intel BMI2 insns
+            AV2_386_HLE         Intel HLE insns
+            AV2_386_RTM         Intel RTM insns
+            AV2_386_EFS         Intel Enhanced Fast String
+            AV2_386_RDSEED      Intel RDSEED insn
+            AV2_386_ADX         Intel ADX insns
+            AV2_386_PRFCHW      Intel PREFETCHW hint
+       */
+   }
+
+   /* AT_NULL */
+   auxv->a_type = VKI_AT_NULL;
+   auxv->a_un.a_val = 0;
+
+   vg_assert(strtab - stringbase == stringsize);
+
+   /* The variable client_SP is now pointing at client's argc/argv. */
+
+   if (0)
+      VG_(printf)("startup SP = %#lx\n", client_SP);
+   return client_SP;
+}
+
+
+/* Allocate the client data segment. It is an expandable anonymous mapping
+   abutting a 1-page reservation. The data segment starts at VG_(brk_base)
+   and runs up to VG_(brk_limit). None of these two values have to be
+   page-aligned.
+   Reservation segment is used to protect the data segment merging with
+   a pre-existing segment. This should be no problem because address space
+   manager ensures that requests for client address space are satisfied from
+   the highest available addresses. However when memory is low, data segment
+   can meet with mmap'ed objects and the reservation segment separates these.
+   The page that contains VG_(brk_base) is already allocated by the program's
+   loaded data segment. The brk syscall wrapper handles this special case.
+   See the brk syscall wrapper for more information. */
+static void setup_client_dataseg(SizeT initial_size)
+{
+   Bool ok;
+   SysRes sres;
+   Addr anon_start = VG_PGROUNDUP(VG_(brk_base));
+   SizeT anon_size = VG_PGROUNDUP(initial_size);
+   Addr resvn_start = anon_start + anon_size;
+   SizeT resvn_size = VKI_PAGE_SIZE;
+   const NSegment *seg;
+   UInt prot;
+
+   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));
+
+   /* Stay sane (because there's been no brk activity yet). */
+   vg_assert(VG_(brk_base) == VG_(brk_limit));
+
+   /* Find the loaded data segment and remember its protection. */
+   seg = VG_(am_find_nsegment)(VG_(brk_base) - 1);
+   vg_assert(seg);
+   prot = (seg->hasR ? VKI_PROT_READ : 0)
+        | (seg->hasW ? VKI_PROT_WRITE : 0)
+        | (seg->hasX ? VKI_PROT_EXEC : 0);
+
+   /* Try to create the data segment and associated reservation where
+      VG_(brk_base) says. */
+   ok = VG_(am_create_reservation)(resvn_start, resvn_size, SmLower, anon_size);
+   if (!ok) {
+      /* That didn't work, we're hosed. */
+      VG_(printf)("valgrind: cannot initialize a brk segment\n");
+      VG_(exit)(1);
+      /*NOTREACHED*/
+   }
+   vg_assert(ok);
+
+   /* Map the data segment. */
+   sres = VG_(am_mmap_anon_fixed_client)(anon_start, anon_size, prot);
+   vg_assert(!sr_isError(sres));
+   vg_assert(sr_Res(sres) == anon_start);
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(setup_client_initial_image)                   ===*/
+/*====================================================================*/
+
+/* Create the client's initial memory image. */
+IIFinaliseImageInfo VG_(ii_create_image)(IICreateImageInfo iicii,
+                                         const VexArchInfo *vex_archinfo)
+{
+   ExeInfo info;
+   HChar **env = NULL;
+   HChar resolved_exe_name[VKI_PATH_MAX];
+
+   IIFinaliseImageInfo iifii;
+   VG_(memset)(&iifii, 0, sizeof(iifii));
+
+   //--------------------------------------------------------------
+   // Load client executable, finding in $PATH if necessary
+   //   p: early_process_cmd_line_options()  [for 'exec', 'need_help']
+   //   p: layout_remaining_space            [so there's space]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "initimg", "Loading client\n");
+
+   if (!VG_(args_the_exename)) {
+      VG_(err_missing_prog)();
+      /*NOTREACHED*/
+   }
+
+   load_client(&info, resolved_exe_name, sizeof(resolved_exe_name));
+   iifii.initial_client_IP = info.init_ip;
+   /* Note: TOC isn't available on Solaris. */
+   iifii.initial_client_TOC = info.init_toc;
+   iifii.initial_client_TP = info.init_thrptr;
+   /* Note that iifii.client_auxv is never set on Solaris, because it isn't
+      necessary to have this value in VG_(ii_finalise_image). */
+
+   //--------------------------------------------------------------
+   // Set up client's environment
+   //   p: set-libdir                       [for VG_(libdir)]
+   //   p: early_process_cmd_line_options() [for toolname]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "initimg", "Setup client env\n");
+   env = setup_client_env(iicii.envp, iicii.toolname);
+
+   //--------------------------------------------------------------
+   // Setup client stack and EIP
+   //   p: load_client()     [for 'info']
+   //   p: fix_environment() [for 'env']
+   //--------------------------------------------------------------
+   {
+      /* When allocating space for the client stack, take notice of the
+         --main-stacksize value.  This makes it possible to run programs with
+         very large (primary) stack requirements simply by specifying
+         --main-stacksize. */
+      /* Logic is as follows:
+         - By default, use the client's current stack rlimit.
+         - If that exceeds 16M, clamp to 16M.
+         - If a larger --main-stacksize value is specified, use that instead.
+         - In all situations, the minimum allowed stack size is 1M.
+      */
+      void *init_sp = iicii.argv - 1;
+      SizeT m1  = 1024 * 1024;
+      SizeT m16 = 16 * m1;
+      SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur;
+      if (szB < m1)
+         szB = m1;
+      if (szB > m16)
+         szB = m16;
+
+      if (VG_(clo_main_stacksize) > 0)
+         szB = VG_(clo_main_stacksize);
+      if (szB < m1)
+         szB = m1;
+
+      szB = VG_PGROUNDUP(szB);
+      VG_(debugLog)(1, "initimg",
+                       "Setup client stack: size will be %ld\n", szB);
+
+      iifii.clstack_max_size = szB;
+      iifii.initial_client_SP = setup_client_stack(init_sp, env, &info,
+                                                   iicii.clstack_end,
+                                                   iifii.clstack_max_size,
+                                                   resolved_exe_name);
+      VG_(free)(env);
+
+      VG_(debugLog)(2, "initimg", "Client info: "
+                       "initial_IP=%#lx, initial_TOC=%#lx, brk_base=%#lx\n",
+                       iifii.initial_client_IP, iifii.initial_client_TOC,
+                       VG_(brk_base));
+      VG_(debugLog)(2, "initimg", "Client info: "
+                       "initial_SP=%#lx, max_stack_size=%lu\n",
+                       iifii.initial_client_SP,
+                       iifii.clstack_max_size);
+   }
+
+   //--------------------------------------------------------------
+   // Setup client data (brk) segment.  Initially segment at least
+   // 1 MB and at most 8 MB large which abuts a 1-page reservation.
+   //     p: load_client()     [for 'info' and hence VG_(brk_base)]
+   //--------------------------------------------------------------
+   {
+      SizeT m1 = 1024 * 1024;
+      SizeT m8 = 8 * m1;
+      SizeT dseg_max_size = VG_(client_rlimit_data).rlim_cur;
+      VG_(debugLog)(1, "initimg", "Setup client data (brk) segment at %#lx\n",
+                                  VG_(brk_base));
+      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);
+   }
+
+   return iifii;
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(finalise_image)                               ===*/
+/*====================================================================*/
+
+/* Just before starting the client, we may need to make final adjustments to
+   its initial image.  Also we need to set up the VEX guest state for thread 1
+   (the root thread) and copy in essential starting values.  This is handed
+   the IIFinaliseImageInfo created by VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)(IIFinaliseImageInfo iifii)
+{
+   ThreadArchState *arch = &VG_(threads)[1].arch;
+   const NSegment *seg;
+
+#  if defined(VGA_x86)
+   vg_assert(0 == sizeof(VexGuestX86State) % LibVEX_GUEST_STATE_ALIGN);
+
+   /* Zero out the initial state, and set up the simulated FPU in a sane
+      way. */
+   LibVEX_GuestX86_initialise(&arch->vex);
+
+   /* Zero out the shadow areas. */
+   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
+   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
+
+   /* Put essential stuff into the new state. */
+   arch->vex.guest_ESP = iifii.initial_client_SP;
+   arch->vex.guest_EIP = iifii.initial_client_IP;
+   LibVEX_GuestX86_put_eflags(VKI_PSL_USER, &arch->vex);
+
+   /* Set %cs, %ds, %ss and %es to default values. */
+   __asm__ __volatile__ ("movw %%cs, %[cs]" : [cs] "=m" (arch->vex.guest_CS));
+   __asm__ __volatile__ ("movw %%ds, %[ds]" : [ds] "=m" (arch->vex.guest_DS));
+   __asm__ __volatile__ ("movw %%ss, %[ss]" : [ss] "=m" (arch->vex.guest_SS));
+   __asm__ __volatile__ ("movw %%es, %[es]" : [es] "=m" (arch->vex.guest_ES));
+
+   {
+      /* Initial thread pointer value will be saved in GDT when the thread is
+         started in the syswrap module and a thread's GDT is allocated. */
+      ThreadOSstate *os = &VG_(threads)[1].os_state;
+      os->thrptr = iifii.initial_client_TP;
+   }
+
+#  elif defined(VGA_amd64)
+   vg_assert(0 == sizeof(VexGuestAMD64State) % LibVEX_GUEST_STATE_ALIGN);
+
+   /* Zero out the initial state, and set up the simulated FPU in a sane
+      way. */
+   LibVEX_GuestAMD64_initialise(&arch->vex);
+
+   /* Zero out the shadow areas. */
+   VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
+   VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
+
+   /* Put essential stuff into the new state. */
+   arch->vex.guest_RSP = iifii.initial_client_SP;
+   arch->vex.guest_RIP = iifii.initial_client_IP;
+   arch->vex.guest_FS_CONST = iifii.initial_client_TP;
+   LibVEX_GuestAMD64_put_rflags(VKI_PSL_USER, &arch->vex);
+
+#  else
+#    error "Unknown platform"
+#  endif
+
+   /* Tell the tool that we just wrote to the registers. */
+   VG_TRACK(post_reg_write, Vg_CoreStartup, 1/*tid*/, 0/*offset*/,
+            sizeof(VexGuestArchState));
+
+   /* Tell the tool about the client data segment and then kill it which will
+      make it inaccessible/unaddressable. */
+   seg = VG_(am_find_nsegment)(VG_PGROUNDUP(VG_(brk_base)));
+   vg_assert(seg);
+   vg_assert(seg->kind == SkAnonC);
+   VG_TRACK(new_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base),
+            1/*tid*/);
+   VG_TRACK(die_mem_brk, VG_(brk_base), seg->end + 1 - VG_(brk_base));
+}
+
+#endif // defined(VGO_solaris)
+
+/*--------------------------------------------------------------------*/
+/*---                                                              ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index 566dd84..0545205 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -49,7 +49,8 @@
    Assertery.
    ------------------------------------------------------------------ */
 
-#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \
+    || defined(VGP_x86_solaris)
 #  define GET_STARTREGS(srP)                              \
       { UInt eip, esp, ebp;                               \
         __asm__ __volatile__(                             \
@@ -65,7 +66,8 @@
         (srP)->r_sp = (ULong)esp;                         \
         (srP)->misc.X86.r_ebp = ebp;                      \
       }
-#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \
+      || defined(VGP_amd64_solaris)
 #  define GET_STARTREGS(srP)                              \
       { ULong rip, rsp, rbp;                              \
         __asm__ __volatile__(                             \
@@ -291,7 +293,7 @@
 {
 #if defined(VGO_linux)
    (void)VG_(do_syscall1)(__NR_exit_group, status );
-#elif defined(VGO_darwin)
+#elif defined(VGO_darwin) || defined(VGO_solaris)
    (void)VG_(do_syscall1)(__NR_exit, status );
 #else
 #  error Unknown OS
@@ -505,8 +507,15 @@
 }
 
 /* Print some helpful-ish text about unimplemented things, and give up. */
-void VG_(unimplemented) ( const HChar* msg )
+void VG_(unimplemented) ( const HChar* format, ... )
 {
+   va_list vargs;
+   HChar msg[256];
+
+   va_start(vargs, format);
+   VG_(vsnprintf)(msg, sizeof(msg), format, vargs);
+   va_end(vargs);
+
    if (VG_(clo_xml))
       VG_(printf_xml)("</valgrindoutput>\n");
    VG_(umsg)("\n");
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index ce442ec..8eb9f2c 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -78,7 +78,7 @@
    cannot be deduced. */
 Bool VG_(resolve_filename) ( Int fd, const HChar** result )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    static HChar *buf = NULL;
    static SizeT  bufsiz = 0;
 
@@ -88,7 +88,13 @@
    }
 
    HChar tmp[64];   // large enough
-   VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
+   {
+#     if defined(VGO_linux)
+      VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
+#     elif defined(VGO_solaris)
+      VG_(sprintf)(tmp, "/proc/self/path/%d", fd);
+#     endif
+   }
 
    while (42) {
       SSizeT res = VG_(readlink)(tmp, buf, bufsiz);
@@ -139,6 +145,9 @@
 #  elif defined(VGO_linux) || defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_mknod,
                                  (UWord)pathname, mode, dev);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_mknodat,
+                                 VKI_AT_FDCWD, (UWord)pathname, mode, dev);
 #  else
 #    error Unknown OS
 #  endif
@@ -157,6 +166,9 @@
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
                                  (UWord)pathname, flags, mode);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_openat,
+                                 VKI_AT_FDCWD, (UWord)pathname, flags, mode);
 #  else
 #    error Unknown OS
 #  endif
@@ -176,7 +188,7 @@
 void VG_(close) ( Int fd )
 {
    /* Hmm.  Return value is not checked.  That's uncool. */
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    (void)VG_(do_syscall1)(__NR_close, fd);
 #  elif defined(VGO_darwin)
    (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
@@ -188,7 +200,7 @@
 Int VG_(read) ( Int fd, void* buf, Int count)
 {
    Int    ret;
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
@@ -208,7 +220,7 @@
 Int VG_(write) ( Int fd, const void* buf, Int count)
 {
    Int    ret;
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
@@ -252,6 +264,18 @@
       fd[1] = (Int)sr_ResHI(res);
    }
    return sr_isError(res) ? -1 : 0;
+#  elif defined(VGO_solaris)
+#  if defined(SOLARIS_NEW_PIPE_SYSCALL)
+   SysRes res = VG_(do_syscall2)(__NR_pipe, (UWord)fd, 0);
+   return sr_isError(res) ? -1 : 0;
+#  else
+   SysRes res = VG_(do_syscall0)(__NR_pipe);
+   if (!sr_isError(res)) {
+      fd[0] = (Int)sr_Res(res);
+      fd[1] = (Int)sr_ResHI(res);
+   }
+   return sr_isError(res) ? -1 : 0;
+#  endif
 #  else
 #    error "Unknown OS"
 #  endif
@@ -275,6 +299,14 @@
    SysRes res = VG_(do_syscall4)(__NR_lseek, fd, 
                                  offset & 0xffffffff, offset >> 32, whence);
    return sr_isError(res) ? (-1) : sr_Res(res);
+#  elif defined(VGP_x86_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_llseek, fd,
+                                 offset & 0xffffffff, offset >> 32, whence);
+   return sr_isError(res) ? (-1) : ((ULong)sr_ResHI(res) << 32 | sr_Res(res));
+#  elif defined(VGP_amd64_solaris)
+   SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
+   vg_assert(sizeof(Off64T) == sizeof(Word));
+   return sr_isError(res) ? (-1) : sr_Res(res);
 #  else
 #    error "Unknown plat"
 #  endif
@@ -338,7 +370,23 @@
         TRANSLATE_TO_vg_stat(vgbuf, &buf);
      return res;
    }
-
+#  elif defined(VGO_solaris)
+   {
+#     if defined(VGP_x86_solaris)
+      struct vki_stat64 buf64;
+      res = VG_(do_syscall4)(__NR_fstatat64, VKI_AT_FDCWD, (UWord)file_name,
+                             (UWord)&buf64, 0);
+#     elif defined(VGP_amd64_solaris)
+      struct vki_stat buf64;
+      res = VG_(do_syscall4)(__NR_fstatat, VKI_AT_FDCWD, (UWord)file_name,
+                             (UWord)&buf64, 0);
+#     else
+#        error "Unknown platform"
+#     endif
+      if (!sr_isError(res))
+         TRANSLATE_TO_vg_stat(vgbuf, &buf64);
+      return res;
+   }
 #  else
 #    error Unknown OS
 #  endif
@@ -349,7 +397,7 @@
    SysRes res;
    VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
 
-#  if defined(VGO_linux)  ||  defined(VGO_darwin)
+#  if defined(VGO_linux) || defined(VGO_darwin)
    /* First try with fstat64.  If that doesn't work out, fall back to
       the vanilla version. */
 #  if defined(__NR_fstat64)
@@ -369,7 +417,21 @@
         TRANSLATE_TO_vg_stat(vgbuf, &buf);
      return sr_isError(res) ? (-1) : 0;
    }
-
+#  elif defined(VGO_solaris)
+   { 
+#     if defined(VGP_x86_solaris)
+      struct vki_stat64 buf64;
+      res = VG_(do_syscall4)(__NR_fstatat64, (UWord)fd, 0, (UWord)&buf64, 0);
+#     elif defined(VGP_amd64_solaris)
+      struct vki_stat buf64;
+      res = VG_(do_syscall4)(__NR_fstatat, (UWord)fd, 0, (UWord)&buf64, 0);
+#     else
+#        error "Unknown platform"
+#     endif
+      if (!sr_isError(res))
+         TRANSLATE_TO_vg_stat(vgbuf, &buf64);
+      return sr_isError(res) ? (-1) : 0;
+   }
 #  else
 #    error Unknown OS
 #  endif
@@ -407,13 +469,21 @@
 
 SysRes VG_(dup) ( Int oldfd )
 {
+#  if defined(VGO_linux) || defined(VGO_darwin)
    return VG_(do_syscall1)(__NR_dup, oldfd);
+#  elif defined(VGO_solaris)
+   return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUPFD, 0);
+#  else
+#    error Unknown OS
+#  endif
 }
 
 SysRes VG_(dup2) ( Int oldfd, Int newfd )
 {
 #  if defined(VGO_linux) || defined(VGO_darwin)
    return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
+#  elif defined(VGO_solaris)
+   return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUP2FD, newfd);
 #  else
 #    error Unknown OS
 #  endif
@@ -422,7 +492,7 @@
 /* Returns -1 on error. */
 Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
@@ -437,8 +507,13 @@
 #  if defined(VGP_tilegx_linux)
    SysRes res = VG_(do_syscall3)(__NR_renameat, VKI_AT_FDCWD,
                                  (UWord)old_name, (UWord)new_name);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name,
+                                 VKI_AT_FDCWD, (UWord)new_name);
+#  else
+#    error "Unknown OS"
 #  endif
    return sr_isError(res) ? (-1) : 0;
 }
@@ -448,8 +523,13 @@
 #  if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
    SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD,
                                                 (UWord)file_name);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD,
+                                 (UWord)file_name, 0);
+#  else
+#    error "Unknown OS"
 #  endif
    return sr_isError(res) ? (-1) : 0;
 }
@@ -469,8 +549,7 @@
 Bool VG_(record_startup_wd) ( void )
 {
    vg_assert(!startup_wd_acquired);
-
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    /* Simple: just ask the kernel */
    SysRes res;
    SizeT szB = 0;
@@ -535,6 +614,19 @@
    res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout);
 #  elif defined(VGO_darwin)
    res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout);
+#  elif defined(VGO_solaris)
+   struct vki_timespec ts;
+   struct vki_timespec *tsp;
+
+   if (timeout < 0)
+      tsp = NULL;
+   else {  
+      ts.tv_sec = timeout / 1000;
+      ts.tv_nsec = (timeout % 1000) * 1000000;
+      tsp = &ts;
+   }
+
+   res = VG_(do_syscall4)(__NR_pollsys, (UWord)fds, nfds, (UWord)tsp, 0);
 #  else
 #    error "Unknown OS"
 #  endif
@@ -553,18 +645,29 @@
 #  if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
    res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD,
                                            (UWord)path, (UWord)buf, bufsiz);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz);
+#  elif defined(VGO_solaris)
+   res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path,
+                          (UWord)buf, bufsiz);
+#  else
+#    error "Unknown OS"
 #  endif
    return sr_isError(res) ? -1 : sr_Res(res);
 }
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 Int VG_(getdents64) (Int fd, struct vki_dirent64 *dirp, UInt count)
 {
    SysRes res;
    /* res = getdents( fd, dirp, count ); */
+#  if defined(VGP_amd64_solaris)
+   /* This silently assumes that dirent64 and dirent on amd64 are same, which
+      they should always be. */
+   res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
+#  else
    res = VG_(do_syscall3)(__NR_getdents64, fd, (UWord)dirp, count);
+#  endif
    return sr_isError(res) ? -1 : sr_Res(res);
 }
 #endif
@@ -588,8 +691,13 @@
              | (ixusr ? VKI_X_OK : 0);
 #  if defined(VGP_arm64_linux) || defined(VGP_tilegx_linux)
    SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w);
-#  else
+#  elif defined(VGO_linux) || defined(VGO_darwin)
    SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w);
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path,
+                                 w, 0);
+#  else
+#    error "Unknown OS"
 #  endif
    return sr_isError(res) ? 1 : 0;   
 
@@ -738,6 +846,14 @@
    res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count, 
                           offset & 0xffffffff, offset >> 32);
    return res;
+#  elif defined(VGP_x86_solaris)
+   vg_assert(sizeof(OffT) == 4);
+   res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
+   return res;
+#  elif defined(VGP_amd64_solaris)
+   vg_assert(sizeof(OffT) == 8);
+   res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset);
+   return res;
 #  else
 #    error "Unknown platform"
 #  endif
@@ -872,7 +988,7 @@
 */
 Int VG_(connect_via_socket)( const HChar* str )
 {
-#  if defined(VGO_linux) || defined(VGO_darwin)
+#  if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
    Int sd, res;
    struct vki_sockaddr_in servAddr;
    UInt   ip   = 0;
@@ -992,6 +1108,20 @@
    }
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   /* XXX There doesn't seem to be an easy way to convince the send syscall to
+      only return EPIPE instead of raising SIGPIPE. EPIPE is only returned if
+      SM_KERNEL is set on the socket. Without serious hackery it looks we
+      can't set this flag.
+
+      Should we wrap the send syscall below into sigprocmask calls to block
+      SIGPIPE?
+    */
+   SysRes res;
+   res = VG_(do_syscall5)(__NR_so_socket, domain, type, protocol,
+                          0 /*devpath*/, VKI_SOV_DEFAULT /*version*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown arch"
 #  endif
@@ -1025,6 +1155,12 @@
                           sockfd, (UWord)serv_addr, addrlen);
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall4)(__NR_connect, sockfd, (UWord)serv_addr, addrlen,
+                          VKI_SOV_DEFAULT /*version*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown arch"
 #  endif
@@ -1066,6 +1202,11 @@
    res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall4)(__NR_send, sd, (UWord)msg, count, 0 /*flags*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -1099,6 +1240,12 @@
                            (UWord)sd, (UWord)name, (UWord)namelen );
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall4)(__NR_getsockname, sd, (UWord)name, (UWord)namelen,
+                          VKI_SOV_DEFAULT /*version*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -1132,6 +1279,12 @@
                            (UWord)sd, (UWord)name, (UWord)namelen );
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall4)(__NR_getpeername, sd, (UWord)name, (UWord)namelen,
+                          VKI_SOV_DEFAULT /*version*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -1169,6 +1322,12 @@
                            (UWord)optval, (UWord)optlen );
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall6)(__NR_getsockopt, sd, level, optname, (UWord)optval,
+                          (UWord)optlen, VKI_SOV_DEFAULT /*version*/);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -1207,6 +1366,14 @@
                            (UWord)optval, (UWord)optlen );
    return sr_isError(res) ? -1 : sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+   res = VG_(do_syscall6)( __NR_setsockopt,
+                           (UWord)sd, (UWord)level, (UWord)optname,
+                           (UWord)optval, (UWord)optlen,
+                           VKI_SOV_DEFAULT /*version*/ );
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c
index 114467f..0ebc00c 100644
--- a/coregrind/m_libcprint.c
+++ b/coregrind/m_libcprint.c
@@ -660,7 +660,7 @@
    return buf;
 }
 
-#elif defined(VGO_darwin)
+#elif defined(VGO_darwin) || (VGO_solaris)
 
 const HChar *VG_(sr_as_string) ( SysRes sr )
 {
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 321fdf3..6e6f99b 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -34,6 +34,7 @@
 #include "pub_core_vkiscnums.h"
 #include "pub_core_libcbase.h"
 #include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
@@ -66,7 +67,7 @@
 const HChar *VG_(libdir) = VG_LIBDIR;
 
 const HChar *VG_(LD_PRELOAD_var_name) =
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
    "LD_PRELOAD";
 #elif defined(VGO_darwin)
    "DYLD_INSERT_LIBRARIES";
@@ -90,7 +91,9 @@
    return NULL;
 }
 
-void  VG_(env_unsetenv) ( HChar **env, const HChar *varname )
+/* If free_fn is not NULL, it is called on "unset" environment variable. */
+void  VG_(env_unsetenv) ( HChar **env, const HChar *varname,
+                          void (*free_fn) (void *) )
 {
    HChar **from, **to;
    vg_assert(env);
@@ -102,6 +105,8 @@
       if (!(VG_(strncmp)(varname, *from, len) == 0 && (*from)[len] == '=')) {
 	 *to = *from;
 	 to++;
+      } else if (free_fn != NULL) {
+         free_fn(*from);
       }
    }
    *to = *from;
@@ -216,9 +221,14 @@
 }
 
 
-// Removes all the Valgrind-added stuff from the passed environment.  Used
-// when starting child processes, so they don't see that added stuff.
-void VG_(env_remove_valgrind_env_stuff)(HChar** envp)
+/* Removes all the Valgrind-added stuff from the passed environment.  Used
+   when starting child processes, so they don't see that added stuff.
+   If the ro_strings option is set to True then all strings referenced by envp
+   are considered read-only, which means they will be duplicated before they
+   are modified.
+   If free_fn is not NULL, it is called on "unset" environment variables. */
+void VG_(env_remove_valgrind_env_stuff)(HChar** envp, Bool ro_strings,
+                                        void (*free_fn) (void *) )
 {
 
 #if defined(VGO_darwin)
@@ -241,15 +251,18 @@
    // - DYLD_INSERT_LIBRARIES and DYLD_SHARED_REGION are Darwin-only
    for (i = 0; envp[i] != NULL; i++) {
       if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0) {
-         envp[i] = VG_(strdup)("libcproc.erves.1", envp[i]);
+         if (ro_strings)
+            envp[i] = VG_(strdup)("libcproc.erves.1", envp[i]);
          ld_preload_str = &envp[i][11];
       }
       if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0) {
-         envp[i] = VG_(strdup)("libcproc.erves.2", envp[i]);
+         if (ro_strings)
+            envp[i] = VG_(strdup)("libcproc.erves.2", envp[i]);
          ld_library_path_str = &envp[i][16];
       }
       if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0) {
-         envp[i] = VG_(strdup)("libcproc.erves.3", envp[i]);
+         if (ro_strings)
+            envp[i] = VG_(strdup)("libcproc.erves.3", envp[i]);
          dyld_insert_libraries_str = &envp[i][22];
       }
    }
@@ -264,16 +277,79 @@
    mash_colon_env(ld_library_path_str, buf);
 
    // Remove VALGRIND_LAUNCHER variable.
-   VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER);
+   VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER, free_fn);
 
    // Remove DYLD_SHARED_REGION variable.
-   VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION");
+   VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION", free_fn);
 
    // XXX if variable becomes empty, remove it completely?
 
    VG_(free)(buf);
 }
 
+/* Resolves filename of VG_(cl_exec_fd) and copies it to the buffer.
+   Buffer must not be NULL and buf_size must be at least 1.
+   If buffer is not large enough it is terminated with '\0' only
+   when 'terminate_with_NUL == True'. */
+void VG_(client_fname)(HChar *buffer, SizeT buf_size, Bool terminate_with_NUL)
+{
+   vg_assert(buffer != NULL);
+   vg_assert(buf_size >= 1);
+
+   const HChar *name;
+   if (VG_(resolve_filename)(VG_(cl_exec_fd), &name)) {
+      const HChar *n = name + VG_(strlen)(name) - 1;
+
+      while (n > name && *n != '/')
+         n--;
+      if (n != name)
+         n++;
+
+      VG_(strncpy)(buffer, n, buf_size);
+      if (terminate_with_NUL)
+         buffer[buf_size - 1] = '\0';
+   } else {
+      buffer[0] = '\0';
+   }
+}
+
+static Bool add_string(HChar *buffer, SizeT *buf_size, const HChar *string)
+{
+   SizeT len = VG_(strlen)(string);
+   VG_(strncat)(buffer, string, *buf_size);
+   if (len >= *buf_size - 1) {
+      *buf_size = 0;
+      return False;
+   } else {
+      *buf_size -= len;
+      return True;
+   }
+}
+
+/* Concatenates client exename and command line arguments into
+   the buffer. Buffer must not be NULL and buf_size must be
+   at least 1. Buffer is always terminated with '\0'. */
+void VG_(client_cmd_and_args)(HChar *buffer, SizeT buf_size)
+{
+   vg_assert(buffer != NULL);
+   vg_assert(buf_size >= 1);
+
+   buffer[0] = '\0';
+
+   if (add_string(buffer, &buf_size, VG_(args_the_exename)) == False)
+      return;
+
+   Int i;
+   for (i = 0; i < VG_(sizeXA)(VG_(args_for_client)); i++) {
+      if (add_string(buffer, &buf_size, " ") == False)
+         return;
+
+      HChar *arg = *(HChar **) VG_(indexXA)(VG_(args_for_client), i);
+      if (add_string(buffer, &buf_size, arg) == False)
+         return;
+   }
+}
+
 /* ---------------------------------------------------------------------
    Various important syscall wrappers
    ------------------------------------------------------------------ */
@@ -288,6 +364,63 @@
    SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel,
                                  pid, (UWord)status, options, 0);
    return sr_isError(res) ? -1 : sr_Res(res);
+#  elif defined(VGO_solaris)
+   SysRes res;
+   vki_idtype_t idtype;
+   vki_id_t id;
+   vki_siginfo_t info;
+
+   /* We need to do a lot of work here. */
+
+   if (pid > 0) {
+      idtype = VKI_P_PID;
+      id = pid;
+   }
+   else if (pid < -1) {
+      idtype = VKI_P_PGID;
+      id = -pid;
+   }
+   else if (pid == -1) {
+      idtype = VKI_P_ALL;
+      id = 0;
+   }
+   else {
+      idtype = VKI_P_PGID;
+      res = VG_(do_syscall0)(__NR_getpid);
+      id = sr_ResHI(res);
+   }
+
+   options |= VKI_WEXITED | VKI_WTRAPPED;
+
+   res = VG_(do_syscall4)(__NR_waitsys, idtype, id, (UWord)&info, options);
+   if (sr_isError(res))
+      return -1;
+
+   if (status) {
+      Int s = info.si_status & 0xff;
+
+      switch (info.si_code) {
+         case VKI_CLD_EXITED:
+            s <<= 8;
+            break;
+         case VKI_CLD_DUMPED:
+            s |= VKI_WCOREFLG;
+            break;
+         case VKI_CLD_KILLED:
+            break;
+         case VKI_CLD_TRAPPED:
+         case VKI_CLD_STOPPED:
+            s <<= 8;
+            s |= VKI_WSTOPFLG;
+            break;
+         case VKI_CLD_CONTINUED:
+            s = VKI_WCONTFLG;
+            break;
+      }
+      *status = s;
+   }
+
+   return info.si_pid;
 #  else
 #    error Unknown OS
 #  endif
@@ -320,7 +453,7 @@
    return newenv;
 }
 
-void VG_(execv) ( const HChar* filename, HChar** argv )
+void VG_(execv) ( const HChar* filename, const HChar** argv )
 {
    HChar** envp;
    SysRes res;
@@ -329,7 +462,7 @@
    VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
 
    envp = VG_(env_clone)(VG_(client_envp));
-   VG_(env_remove_valgrind_env_stuff)( envp );
+   VG_(env_remove_valgrind_env_stuff)( envp, True /*ro_strings*/, NULL );
 
    res = VG_(do_syscall3)(__NR_execve,
                           (UWord)filename, (UWord)argv, (UWord)envp);
@@ -337,6 +470,93 @@
    VG_(printf)("EXEC failed, errno = %lld\n", (Long)sr_Err(res));
 }
 
+/* Spawns a new child. Uses either spawn syscall or fork+execv combo. */
+Int VG_(spawn) ( const HChar *filename, const HChar **argv )
+{
+   vg_assert(filename != NULL);
+   vg_assert(argv != NULL);
+
+#  if defined(VGO_solaris) && defined(SOLARIS_SPAWN_SYSCALL)
+   HChar **envp = VG_(env_clone)(VG_(client_envp));
+   for (HChar **p = envp; *p != NULL; p++) {
+      *p = VG_(strdup)("libcproc.s.1", *p);
+   }
+   VG_(env_remove_valgrind_env_stuff)(envp, /* ro_strings */ False, VG_(free));
+
+   /* Now combine argv and argp into argenv. */
+   SizeT argenv_size = 1 + 1;
+   for (const HChar **p = argv; *p != NULL; p++) {
+      argenv_size += VG_(strlen)(*p) + 2;
+   }
+   for (HChar **p = envp; *p != NULL; p++) {
+      argenv_size += VG_(strlen)(*p) + 2;
+   }
+
+   HChar *argenv = VG_(malloc)("libcproc.s.2", argenv_size);
+   HChar *current = argenv;
+#  define COPY_CHAR_TO_ARGENV(dst, character)  \
+      do {                                     \
+         *(dst) = character;                   \
+         (dst) += 1;                           \
+      } while (0)
+#  define COPY_STRING_TO_ARGENV(dst, src)        \
+      do {                                       \
+         COPY_CHAR_TO_ARGENV(dst, '\1');         \
+         SizeT src_len = VG_(strlen)((src)) + 1; \
+         VG_(memcpy)((dst), (src), src_len);     \
+         (dst) += src_len;                       \
+      } while (0)
+
+   for (const HChar **p = argv; *p != NULL; p++) {
+      COPY_STRING_TO_ARGENV(current, *p);
+   }
+   COPY_CHAR_TO_ARGENV(current, '\0');
+   for (HChar **p = envp; *p != NULL; p++) {
+      COPY_STRING_TO_ARGENV(current, *p);
+   }
+   COPY_CHAR_TO_ARGENV(current, '\0');
+   vg_assert(current == argenv + argenv_size);
+#  undef COPY_CHAR_TO_ARGENV
+#  undef COPY_STRING_TOARGENV
+
+   /* HACK: Temporarily restore the DATA rlimit for spawned child. */
+   VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
+   SysRes res = VG_(do_syscall5)(__NR_spawn, (UWord) filename, (UWord) NULL, 0,
+                                 (UWord) argenv, argenv_size);
+
+   /* Restore DATA rlimit back to its previous value set in m_main.c. */
+   struct vki_rlimit zero = { 0, 0 };
+   zero.rlim_max = VG_(client_rlimit_data).rlim_max;
+   VG_(setrlimit)(VKI_RLIMIT_DATA, &zero);
+
+   VG_(free)(argenv);
+   for (HChar **p = envp; *p != NULL; p++) {
+      VG_(free)(*p);
+   }
+   VG_(free)(envp);
+
+   if (sr_isError(res))
+      return -1;
+   return sr_Res(res);
+
+#  else
+
+   Int pid = VG_(fork)();
+   if (pid < 0)
+      return -1;
+   if (pid == 0) {
+      /* child */
+      VG_(execv)(argv[0], argv);
+
+      /* If we're still alive here, execv failed. */
+      VG_(exit)(1);
+   } else {
+      return pid;
+   }
+#  endif /* VGO_solaris && SOLARIS_SPAWN_SYSCALL */
+}
+
 /* Return -1 if error, else 0.  NOTE does not indicate return code of
    child! */
 Int VG_(system) ( const HChar* cmd )
@@ -344,47 +564,42 @@
    Int pid;
    if (cmd == NULL)
       return 1;
-   pid = VG_(fork)();
+
+   const HChar *argv[4] = { "/bin/sh", "-c", cmd, 0 };
+   pid = VG_(spawn)(argv[0], argv);
    if (pid < 0)
       return -1;
-   if (pid == 0) {
-      /* child */
-      const HChar* argv[4] = { "/bin/sh", "-c", cmd, 0 };
-      VG_(execv)(argv[0], CONST_CAST(HChar **,argv));
 
-      /* If we're still alive here, execv failed. */
-      VG_(exit)(1);
-   } else {
-      /* parent */
-      /* We have to set SIGCHLD to its default behaviour in order that
-         VG_(waitpid) works (at least on AIX).  According to the Linux
-         man page for waitpid:
+   vg_assert(pid > 0);
+   /* parent */
+   /* We have to set SIGCHLD to its default behaviour in order that
+      VG_(waitpid) works (at least on AIX).  According to the Linux
+      man page for waitpid:
 
-         POSIX.1-2001 specifies that if the disposition of SIGCHLD is
-         set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD
-         (see sigaction(2)), then children that terminate do not
-         become zombies and a call to wait() or waitpid() will block
-         until all children have terminated, and then fail with errno
-         set to ECHILD.  (The original POSIX standard left the
-         behaviour of setting SIGCHLD to SIG_IGN unspecified.)
-      */
-      Int ir, zzz;
-      vki_sigaction_toK_t sa, sa2;
-      vki_sigaction_fromK_t saved_sa;
-      VG_(memset)( &sa, 0, sizeof(sa) );
-      VG_(sigemptyset)(&sa.sa_mask);
-      sa.ksa_handler = VKI_SIG_DFL;
-      sa.sa_flags    = 0;
-      ir = VG_(sigaction)(VKI_SIGCHLD, &sa, &saved_sa);
-      vg_assert(ir == 0);
+      POSIX.1-2001 specifies that if the disposition of SIGCHLD is
+      set to SIG_IGN or the SA_NOCLDWAIT flag is set for SIGCHLD
+      (see sigaction(2)), then children that terminate do not
+      become zombies and a call to wait() or waitpid() will block
+      until all children have terminated, and then fail with errno
+      set to ECHILD.  (The original POSIX standard left the
+      behaviour of setting SIGCHLD to SIG_IGN unspecified.)
+   */
+   Int ir, zzz;
+   vki_sigaction_toK_t sa, sa2;
+   vki_sigaction_fromK_t saved_sa;
+   VG_(memset)( &sa, 0, sizeof(sa) );
+   VG_(sigemptyset)(&sa.sa_mask);
+   sa.ksa_handler = VKI_SIG_DFL;
+   sa.sa_flags    = 0;
+   ir = VG_(sigaction)(VKI_SIGCHLD, &sa, &saved_sa);
+   vg_assert(ir == 0);
 
-      zzz = VG_(waitpid)(pid, NULL, 0);
+   zzz = VG_(waitpid)(pid, NULL, 0);
 
-      VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &sa2 );
-      ir = VG_(sigaction)(VKI_SIGCHLD, &sa2, NULL);
-      vg_assert(ir == 0);
-      return zzz == -1 ? -1 : 0;
-   }
+   VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &sa2 );
+   ir = VG_(sigaction)(VKI_SIGCHLD, &sa2, NULL);
+   vg_assert(ir == 0);
+   return zzz == -1 ? -1 : 0;
 }
 
 Int VG_(sysctl)(Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen)
@@ -493,6 +708,10 @@
    // Use Mach thread ports for lwpid instead.
    return mach_thread_self();
 
+#  elif defined(VGO_solaris)
+   SysRes res = VG_(do_syscall0)(__NR_lwp_self);
+   return sr_Res(res);
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -508,36 +727,69 @@
 Int VG_(getpgrp) ( void )
 {
    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
+#  if defined(VGO_linux) || defined(VGO_darwin)
    return sr_Res( VG_(do_syscall0)(__NR_getpgrp) );
+#  elif defined(VGO_solaris)
+   /* Uses the shared pgrpsys syscall, 0 for the getpgrp variant. */
+   return sr_Res( VG_(do_syscall1)(__NR_pgrpsys, 0) );
+#  else
+#    error Unknown OS
+#  endif
 }
 
 Int VG_(getppid) ( void )
 {
    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
+#  if defined(VGO_linux) || defined(VGO_darwin)
    return sr_Res( VG_(do_syscall0)(__NR_getppid) );
+#  elif defined(VGO_solaris)
+   /* Uses the shared getpid/getppid syscall, val2 contains a parent pid. */
+   return sr_ResHI( VG_(do_syscall0)(__NR_getpid) );
+#  else
+#    error Unknown OS
+#  endif
 }
 
 Int VG_(geteuid) ( void )
 {
    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
-#  if defined(__NR_geteuid32)
-   // We use the 32-bit version if it's supported.  Otherwise, IDs greater
-   // than 65536 cause problems, as bug #151209 showed.
-   return sr_Res( VG_(do_syscall0)(__NR_geteuid32) );
+#  if defined(VGO_linux) || defined(VGO_darwin)
+   {
+#     if defined(__NR_geteuid32)
+      // We use the 32-bit version if it's supported.  Otherwise, IDs greater
+      // than 65536 cause problems, as bug #151209 showed.
+      return sr_Res( VG_(do_syscall0)(__NR_geteuid32) );
+#     else
+      return sr_Res( VG_(do_syscall0)(__NR_geteuid) );
+#     endif
+   }
+#  elif defined(VGO_solaris)
+   /* Uses the shared getuid/geteuid syscall, val2 contains the effective
+      uid. */
+   return sr_ResHI( VG_(do_syscall0)(__NR_getuid) );
 #  else
-   return sr_Res( VG_(do_syscall0)(__NR_geteuid) );
+#    error Unknown OS
 #  endif
 }
 
 Int VG_(getegid) ( void )
 {
+#  if defined(VGO_linux) || defined(VGO_darwin)
    /* ASSUMES SYSCALL ALWAYS SUCCEEDS */
-#  if defined(__NR_getegid32)
+#    if defined(__NR_getegid32)
    // We use the 32-bit version if it's supported.  Otherwise, IDs greater
    // than 65536 cause problems, as bug #151209 showed.
    return sr_Res( VG_(do_syscall0)(__NR_getegid32) );
-#  else
+#    else
    return sr_Res( VG_(do_syscall0)(__NR_getegid) );
+#    endif
+
+#  elif defined(VGO_solaris)
+   /* Uses the shared getgid/getegid syscall, val2 contains the effective
+      gid. */
+   return sr_ResHI( VG_(do_syscall0)(__NR_getgid) );
+#  else
+#    error Unknown OS
 #  endif
 }
 
@@ -568,7 +820,8 @@
 #  elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \
         || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux)  \
         || defined(VGO_darwin) || defined(VGP_s390x_linux)    \
-        || defined(VGP_mips32_linux) || defined(VGP_arm64_linux)
+        || defined(VGP_mips32_linux) || defined(VGP_arm64_linux) \
+        || defined(VGO_solaris)
    SysRes sres;
    sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
    if (sr_isError(sres))
@@ -587,7 +840,17 @@
 Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data )
 {
    SysRes res;
+#  if defined(VGO_linux) || defined(VGO_darwin)
    res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data);
+#  elif defined(VGO_solaris)
+   /* There is no ptrace syscall on Solaris.  Such requests has to be
+      implemented using the /proc interface.  Callers of VG_(ptrace) should
+      ensure that this function is not reached on Solaris, i.e. they must
+      provide a special code for Solaris for whatever feature they provide. */
+   I_die_here;
+#  else
+#    error Unknown OS
+#  endif
    if (sr_isError(res))
       return -1;
    return sr_Res(res);
@@ -625,6 +888,24 @@
    }
    return sr_Res(res);
 
+#  elif defined(VGO_solaris)
+   /* Using fork() on Solaris is not really the best thing to do. Solaris
+      does not do memory overcommitment so fork() can fail if there is not
+      enough memory to copy the current process into a new one.
+      Prefer to use VG_(spawn)() over VG_(fork)() + VG_(execv)(). */
+   SysRes res;
+   res = VG_(do_syscall2)(__NR_forksys, 0 /*subcode (fork)*/, 0 /*flags*/);
+   if (sr_isError(res))
+      return -1;
+   /* On success:
+        val = a pid of the child in the parent, a pid of the parent in the
+              child,
+        val2 = 0 in the parent process, 1 in the child process. */
+   if (sr_ResHI(res) != 0) {
+      return 0;
+   }
+   return sr_Res(res);
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -640,7 +921,7 @@
    static ULong base = 0;
    ULong  now;
 
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    { SysRes res;
      struct vki_timespec ts_now;
      res = VG_(do_syscall2)(__NR_clock_gettime, VKI_CLOCK_MONOTONIC,
@@ -649,6 +930,8 @@
         now = ts_now.tv_sec * 1000000ULL + ts_now.tv_nsec / 1000;
      } else {
        struct vki_timeval tv_now;
+       /* Note: On Solaris, this syscall takes only one parameter but the
+          extra dummy one does not cause any harm. */
        res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
        vg_assert(! sr_isError(res));
        now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c
index a380f05..b84bc08 100644
--- a/coregrind/m_libcsignal.c
+++ b/coregrind/m_libcsignal.c
@@ -37,6 +37,11 @@
 #include "pub_core_syscall.h"
 #include "pub_core_libcsignal.h"    /* self */
 
+#if !defined(VGO_solaris)
+#   define _VKI_MAXSIG (_VKI_NSIG - 1)
+#endif
+STATIC_ASSERT((_VKI_MAXSIG % _VKI_NSIG_BPW) != 0);
+
 /* IMPORTANT: on Darwin it is essential to use the _nocancel versions
    of syscalls rather than the vanilla version, if a _nocancel version
    is available.  See docs/internals/Darwin-notes.txt for the reason
@@ -49,6 +54,13 @@
    64-bits.  And which they are it doesn't necessarily follow from the
    host word size. */
 
+/* Functions VG_(isemptysigset) and VG_(isfullsigset) check only bits that
+   represent valid signals (i.e. signals <= _VKI_MAXSIG).  The same applies
+   for the comparison in VG_(iseqsigset).  This is important because when
+   a signal set is received from an operating system then bits which represent
+   signals > _VKI_MAXSIG can have unexpected values for Valgrind. This is
+   mainly specific to the Solaris kernel which clears these bits. */
+
 Int VG_(sigfillset)( vki_sigset_t* set )
 {
    Int i;
@@ -73,8 +85,18 @@
 {
    Int i;
    vg_assert(set != NULL);
-   for (i = 0; i < _VKI_NSIG_WORDS; i++)
-      if (set->sig[i] != 0) return False;
+   for (i = 0; i < _VKI_NSIG_WORDS; i++) {
+      if (_VKI_NSIG_BPW * (i + 1) <= (_VKI_MAXSIG + 1)) {
+         /* Full word check. */
+         if (set->sig[i] != 0) return False;
+      }
+      else {
+         /* Partial word check. */
+         ULong mask = (1UL << (_VKI_MAXSIG % _VKI_NSIG_BPW)) - 1;
+         if ((set->sig[i] & mask) != 0) return False;
+         break;
+      }
+   }
    return True;
 }
 
@@ -82,8 +104,18 @@
 {
    Int i;
    vg_assert(set != NULL);
-   for (i = 0; i < _VKI_NSIG_WORDS; i++)
-      if (set->sig[i] != ~0) return False;
+   for (i = 0; i < _VKI_NSIG_WORDS; i++) {
+      if (_VKI_NSIG_BPW * (i + 1) <= (_VKI_MAXSIG + 1)) {
+         /* Full word check. */
+         if (set->sig[i] != ~0) return False;
+      }
+      else {
+         /* Partial word check. */
+         ULong mask = (1UL << (_VKI_MAXSIG % _VKI_NSIG_BPW)) - 1;
+         if ((set->sig[i] & mask) != mask) return False;
+         break;
+      }
+   }
    return True;
 }
 
@@ -91,8 +123,18 @@
 {
    Int i;
    vg_assert(set1 != NULL && set2 != NULL);
-   for (i = 0; i < _VKI_NSIG_WORDS; i++)
-      if (set1->sig[i] != set2->sig[i]) return False;
+   for (i = 0; i < _VKI_NSIG_WORDS; i++) {
+      if (_VKI_NSIG_BPW * (i + 1) <= (_VKI_MAXSIG + 1)) {
+         /* Full word comparison. */
+         if (set1->sig[i] != set2->sig[i]) return False;
+      }
+      else {
+         /* Partial word comparison. */
+         ULong mask = (1UL << (_VKI_MAXSIG % _VKI_NSIG_BPW)) - 1;
+         if ((set1->sig[i] & mask) != (set1->sig[i] & mask)) return False;
+         break;
+      }
+   }
    return True;
 }
 
@@ -174,7 +216,7 @@
 */
 Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
 #  if defined(__NR_rt_sigprocmask)
    SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask, 
                                  how, (UWord)set, (UWord)oldset, 
@@ -272,6 +314,12 @@
    }
    return sr_isError(res) ? -1 : 0;
 
+#  elif defined(VGO_solaris)
+   /* vki_sigaction_toK_t and vki_sigaction_fromK_t are identical types. */
+   SysRes res = VG_(do_syscall3)(__NR_sigaction,
+                                 signum, (UWord)act, (UWord)oldact);
+   return sr_isError(res) ? -1 : 0;
+
 #  else
 #    error "Unsupported OS"
 #  endif
@@ -283,7 +331,7 @@
 VG_(convert_sigaction_fromK_to_toK)( const vki_sigaction_fromK_t* fromK,
                                      /*OUT*/vki_sigaction_toK_t* toK )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    *toK = *fromK;
 #  elif defined(VGO_darwin)
    toK->ksa_handler = fromK->ksa_handler;
@@ -298,7 +346,7 @@
 
 Int VG_(kill)( Int pid, Int signo )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo);
 #  elif defined(VGO_darwin)
    SysRes res = VG_(do_syscall3)(__NR_kill,
@@ -324,6 +372,21 @@
    res = VG_(do_syscall2)(__NR___pthread_kill, lwpid, signo);
    return sr_isError(res) ? -1 : 0;
 
+#  elif defined(VGO_solaris)
+   SysRes res;
+#     if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL)
+#        if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID)
+            res = VG_(do_syscall6)(__NR_lwp_sigqueue, 0, lwpid, signo,
+                                   0, VKI_SI_LWP, 0);
+#        else
+            res = VG_(do_syscall5)(__NR_lwp_sigqueue, lwpid, signo,
+                                   0, VKI_SI_LWP, 0);
+#        endif
+#     else
+         res = VG_(do_syscall2)(__NR_lwp_kill, lwpid, signo);
+#     endif
+   return sr_isError(res) ? -1 : 0;
+
 #  else
 #    error "Unsupported plat"
 #  endif
@@ -477,6 +540,16 @@
   return i;
 }
 
+#elif defined(VGO_solaris)
+Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, vki_siginfo_t *info )
+{
+   /* Trivial as on Linux. */
+   static const struct vki_timespec zero = { 0, 0 };
+   SysRes res = VG_(do_syscall3)(__NR_sigtimedwait, (UWord)set, (UWord)info,
+                                 (UWord)&zero);
+   return sr_isError(res) ? -1 : sr_Res(res);
+}
+
 #else
 #  error "Unknown OS"
 #endif
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index e7b826f..87473c6 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -1840,7 +1840,8 @@
       || defined(VGP_ppc32_linux) || defined(VGP_ppc64le_linux) \
       || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \
       || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \
-      || defined(VGP_tilegx_linux)
+      || defined(VGP_tilegx_linux) || defined(VGP_x86_solaris) \
+      || defined(VGP_amd64_solaris)
    return f;
 #  elif defined(VGP_ppc64be_linux)
    /* ppc64-linux uses the AIX scheme, in which f is a pointer to a
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index 39c03ab..9b491e5 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -181,7 +181,7 @@
 "    --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]\n"
 "    --sim-hints=hint1,hint2,...  activate unusual sim behaviours [none] \n"
 "         where hint is one of:\n"
-"           lax-ioctls fuse-compatible enable-outer\n"
+"           lax-ioctls lax-doors fuse-compatible enable-outer\n"
 "           no-inner-prefix no-nptl-pthread-stackcache none\n"
 "    --fair-sched=no|yes|try   schedule threads fairly on multicore systems [no]\n"
 "    --kernel-variant=variant1,variant2,...\n"
@@ -410,7 +410,7 @@
       // running in an outer, to have "no-inner-prefix" enabled
       // as early as possible.
       else if VG_USETX_CLO (str, "--sim-hints",
-                            "lax-ioctls,fuse-compatible,"
+                            "lax-ioctls,lax-doors,fuse-compatible,"
                             "enable-outer,no-inner-prefix,"
                             "no-nptl-pthread-stackcache",
                             VG_(clo_sim_hints)) {}
@@ -1443,7 +1443,7 @@
       VG_(umsg)("\n");
 
    if (VG_(clo_verbosity) > 1) {
-# if !defined(VGO_darwin)
+# if defined(VGO_linux)
       SysRes fd;
 # endif
       VexArch vex_arch;
@@ -1457,7 +1457,7 @@
                      * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i ));
       }
 
-# if !defined(VGO_darwin)
+# if defined(VGO_linux)
       VG_(message)(Vg_DebugMsg, "Contents of /proc/version:\n");
       fd = VG_(open) ( "/proc/version", VKI_O_RDONLY, 0 );
       if (sr_isError(fd)) {
@@ -1479,7 +1479,7 @@
          VG_(message)(Vg_DebugMsg, "\n");
          VG_(close)(fdno);
       }
-# else
+# elif defined(VGO_darwin)
       VG_(message)(Vg_DebugMsg, "Output from sysctl({CTL_KERN,KERN_VERSION}):\n");
       /* Note: preferable to use sysctlbyname("kern.version", kernelVersion, &len, NULL, 0)
          however that syscall is OS X 10.10+ only. */
@@ -1490,6 +1490,20 @@
       VG_(sysctl)(mib, sizeof(mib)/sizeof(Int), kernelVersion, &len, NULL, 0);
       VG_(message)(Vg_DebugMsg, "  %s\n", kernelVersion);
       VG_(free)( kernelVersion );
+# elif defined(VGO_solaris)
+      /* There is no /proc/version file on Solaris so we try to get some
+         system information using the uname(2) syscall. */
+      {
+         struct vki_utsname uts;
+
+         VG_(message)(Vg_DebugMsg, "System information:\n");
+         SysRes res = VG_(do_syscall1)(__NR_uname, (UWord)&uts);
+         if (sr_isError(res))
+            VG_(message)(Vg_DebugMsg, "  uname() failed\n");
+         else
+            VG_(message)(Vg_DebugMsg, "  %s %s %s %s\n",
+                         uts.sysname, uts.release, uts.version, uts.machine);
+      }
 # endif
 
       VG_(machine_get_VexArchInfo)( &vex_arch, &vex_archinfo );
@@ -1945,7 +1959,7 @@
    if (!need_help) {
       VG_(debugLog)(1, "main", "Create initial image\n");
 
-#     if defined(VGO_linux) || defined(VGO_darwin)
+#     if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
       the_iicii.argv              = argv;
       the_iicii.envp              = envp;
       the_iicii.toolname          = toolname;
@@ -1978,16 +1992,21 @@
    //   p: setup file descriptors
    //   p: ii_create_image for VG_(client_auxv) setup.
    //--------------------------------------------------------------
-#if !defined(VGO_linux)
-   // client shouldn't be using /proc!
    VG_(cl_cmdline_fd) = -1;
    VG_(cl_auxv_fd) = -1;
-#else
+#if defined(VGO_solaris)
+   VG_(cl_psinfo_fd) = -1;
+#endif
+
+#if defined(VGO_linux) || defined(VGO_solaris)
    if (!need_help) {
       HChar  buf[50];   // large enough
       HChar  buf2[VG_(mkstemp_fullname_bufsz)(sizeof buf - 1)];
-      HChar  nul[1];
       Int    fd, r;
+
+#if defined(VGO_linux)
+      /* Fake /proc/<pid>/cmdline only on Linux. */
+      HChar  nul[1];
       const HChar* exename;
 
       VG_(debugLog)(1, "main", "Create fake /proc/<pid>/cmdline\n");
@@ -2018,7 +2037,9 @@
          VG_(err_config_error)("Can't delete client cmdline file in %s\n", buf2);
 
       VG_(cl_cmdline_fd) = fd;
+#endif // defined(VGO_linux)
 
+      /* Fake /proc/<pid>/auxv on both Linux and Solaris. */
       VG_(debugLog)(1, "main", "Create fake /proc/<pid>/auxv\n");
 
       VG_(sprintf)(buf, "proc_%d_auxv", VG_(getpid)());
@@ -2047,6 +2068,24 @@
          VG_(err_config_error)("Can't delete client auxv file in %s\n", buf2);
 
       VG_(cl_auxv_fd) = fd;
+
+#if defined(VGO_solaris)
+      /* Fake /proc/<pid>/psinfo on Solaris.
+       * Contents will be fetched and partially faked later on the fly. */
+      VG_(debugLog)(1, "main", "Create fake /proc/<pid>/psinfo\n");
+
+      VG_(sprintf)(buf, "proc_%d_psinfo", VG_(getpid)());
+      fd = VG_(mkstemp)( buf, buf2 );
+      if (fd == -1)
+         VG_(err_config_error)("Can't create client psinfo file in %s\n", buf2);
+
+      /* Now delete it, but hang on to the fd. */
+      r = VG_(unlink)( buf2 );
+      if (r)
+         VG_(err_config_error)("Can't delete client psinfo file in %s\n", buf2);
+
+      VG_(cl_psinfo_fd) = fd;
+#endif /* VGO_solaris */
    }
 #endif
 
@@ -2165,6 +2204,8 @@
       iters = 10;
 #     elif defined(VGO_darwin)
       iters = 3;
+#     elif defined(VGO_solaris)
+      iters = 10;
 #     else
 #       error "Unknown plat"
 #     endif
@@ -2183,6 +2224,10 @@
       VG_(init_preopened_fds)();
    }
 
+#if defined(VGO_solaris)
+   VG_(syswrap_init)();
+#endif
+
    //--------------------------------------------------------------
    // Load debug info for the existing segments.
    //   p: setup_code_redirect_table [so that redirs can be recorded]
@@ -2207,7 +2252,7 @@
    addr2dihandle = VG_(newXA)( VG_(malloc), "main.vm.2",
                                VG_(free), sizeof(Addr_n_ULong) );
 
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    { Addr* seg_starts;
      Int   n_seg_starts;
      Addr_n_ULong anu;
@@ -2445,7 +2490,19 @@
    //      VG_(ii_create_image)   [for 'the_iicii' initial info]
    //--------------------------------------------------------------
    VG_(debugLog)(1, "main", "Finalise initial image\n");
-   VG_(ii_finalise_image)( the_iifii );
+   { /* Mark the main thread as running while we tell the tool about
+        the client memory which could be tracked during initial image
+        finalisation. So the tool can associate that memory with the
+        main thread. */
+     vg_assert(VG_(running_tid) == VG_INVALID_THREADID);
+     VG_(running_tid) = tid_main;
+
+     VG_(ii_finalise_image)( the_iifii );
+
+     /* Clear the running thread indicator */
+     VG_(running_tid) = VG_INVALID_THREADID;
+     vg_assert(VG_(running_tid) == VG_INVALID_THREADID);
+   }
 
    //--------------------------------------------------------------
    // Initialise the signal handling subsystem
@@ -2665,7 +2722,7 @@
                     "VG_(terminate_NORETURN)(tid=%lld)\n", (ULong)tid);
 
    switch (tids_schedretcode) {
-   case VgSrc_ExitThread:  /* the normal way out (Linux) */
+   case VgSrc_ExitThread:  /* the normal way out (Linux, Solaris) */
    case VgSrc_ExitProcess: /* the normal way out (Darwin) */
       /* Change the application return code to user's return code,
          if an error was found */
@@ -3431,13 +3488,92 @@
    VG_(exit)(r);
 }
 
+/*====================================================================*/
+/*=== Getting to main() alive: Solaris                             ===*/
+/*====================================================================*/
+#elif defined(VGO_solaris)
+#if defined(VGP_x86_solaris)
+/* The kernel hands control to _start, which extracts the initial stack
+   pointer and calls onwards to _start_in_C_solaris.  This also switches to
+   the new stack. */
+asm("\n"
+    "\t.text\n"
+    "\t.globl _start\n"
+    "\t.type _start, @function\n"
+    "_start:\n"
+    /* Set up the new stack in %eax. */
+    "\tmovl  $vgPlain_interim_stack, %eax\n"
+    "\taddl  $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %eax\n"
+    "\taddl  $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %eax\n"
+    "\tandl  $~15, %eax\n"
+    /* Install it, and collect the original one. */
+    "\txchgl %eax, %esp\n"
+    "\tsubl  $12, %esp\n"  /* Keep stack 16-byte aligned. */
+    /* Call _start_in_C_solaris, passing it the startup %esp. */
+    "\tpushl %eax\n"
+    "\tcall  _start_in_C_solaris\n"
+    /* NOTREACHED */
+    "\thlt\n"
+    "\t.previous\n"
+);
+#elif defined(VGP_amd64_solaris)
+asm("\n"
+    ".text\n"
+    "\t.globl _start\n"
+    "\t.type _start, @function\n"
+    "_start:\n"
+    /* Set up the new stack in %rdi. */
+    "\tmovq  $vgPlain_interim_stack, %rdi\n"
+    "\taddq  $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %rdi\n"
+    "\taddq  $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %rdi\n"
+    "\tandq  $~15, %rdi\n"
+    /* Install it, and collect the original one. */
+    "\txchgq %rdi, %rsp\n"
+    /* Call _start_in_C_solaris, passing it the startup %rsp. */
+    "\tcall  _start_in_C_solaris\n"
+    /* NOTREACHED */
+    "\thlt\n"
+    ".previous\n"
+);
+#else
+#  error "Unknown Solaris platform"
+#endif
+
+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);
+}
+
+__attribute__ ((used))
+void _start_in_C_solaris ( UWord* pArgc );
+__attribute__ ((used))
+void _start_in_C_solaris ( UWord* pArgc )
+{
+   Int     r;
+   Word    argc = pArgc[0];
+   HChar** argv = (HChar**)&pArgc[1];
+   HChar** envp = (HChar**)&pArgc[1 + argc + 1];
+
+   VG_(memset)( &the_iicii, 0, sizeof(the_iicii) );
+   VG_(memset)( &the_iifii, 0, sizeof(the_iifii) );
+
+   the_iicii.sp_at_startup = (Addr)pArgc;
+
+   r = valgrind_main((Int)argc, argv, envp);
+   /* NOTREACHED */
+   VG_(exit)(r);
+}
 
 #else
-
 #  error "Unknown OS"
 #endif
 
 
+Addr VG_(get_initial_client_SP)( void )
+{
+   return the_iifii.initial_client_SP;
+}
+
 /*====================================================================*/
 /*=== {u,}{div,mod}di3 replacements                                ===*/
 /*====================================================================*/
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 24938aa..300d620 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -300,7 +300,7 @@
    return c;
 }
 
-/* Should we trace into this child executable (across execve etc) ?
+/* Should we trace into this child executable (across execve, spawn etc) ?
    This involves considering --trace-children=,
    --trace-children-skip=, --trace-children-skip-by-arg=, and the name
    of the executable.  'child_argv' must not include the name of the
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index 09e6a9f..eaad1f8 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -406,6 +406,11 @@
    const HChar* const pthread_soname = "libpthread.so.0";
    const HChar* const pthread_stack_cache_actsize_varname
       = "stack_cache_actsize";
+#if defined(VGO_solaris)
+   Bool         vg_vfork_fildes_var_search = False;
+   const HChar* const vg_preload_core_soname = "vgpreload_core.so.0";
+   const HChar* const vg_vfork_fildes_varname = "vg_vfork_fildes";
+#endif
 
 #  if defined(VG_PLAT_USES_PPCTOC)
    check_ppcTOCs = True;
@@ -504,6 +509,11 @@
       SimHintiS(SimHint_no_nptl_pthread_stackcache, VG_(clo_sim_hints))
       && 0 == VG_(strcmp)(newdi_soname, pthread_soname);
 
+#if defined(VGO_solaris)
+   vg_vfork_fildes_var_search =
+      0 == VG_(strcmp)(newdi_soname, vg_preload_core_soname);
+#endif
+
    nsyms = VG_(DebugInfo_syms_howmany)( newdi );
    for (i = 0; i < nsyms; i++) {
       VG_(DebugInfo_syms_getidx)( newdi, i, &sym_avmas,
@@ -534,6 +544,18 @@
                VG_(client__stack_cache_actsize__addr) = (SizeT*) sym_avmas.main;
                dehacktivate_pthread_stack_cache_var_search = False;
             }
+#if defined(VGO_solaris)
+            if (vg_vfork_fildes_var_search
+                && 0 == VG_(strcmp)(*names, vg_vfork_fildes_varname)) {
+               if ( VG_(clo_verbosity) > 1 ) {
+                  VG_(message)( Vg_DebugMsg,
+                                "vfork kludge: found symbol %s at addr %p\n",
+                                *names, (void*) sym_avmas.main);
+               }
+               VG_(vfork_fildes_addr) = (Int*) sym_avmas.main;
+               vg_vfork_fildes_var_search = False;
+            }
+#endif
             continue;
          }
          if (!ok) {
@@ -617,6 +639,15 @@
       VG_(message)(Vg_DebugMsg,
                    "=> pthread stack cache cannot be disabled!\n");
    }
+#if defined(VGO_solaris)
+   if (vg_vfork_fildes_var_search) {
+      VG_(message)(Vg_DebugMsg,
+                   "WARNING: could not find symbol for var %s in %s\n",
+                   vg_vfork_fildes_varname, vg_preload_core_soname);
+      VG_(message)(Vg_DebugMsg,
+                   "=> posix_spawn() will not work correctly!\n");
+   }
+#endif
 
    if (check_ppcTOCs) {
       for (i = 0; i < nsyms; i++) {
@@ -1500,6 +1531,40 @@
       );
    }
 
+#  elif defined(VGP_x86_solaris)
+   /* If we're using memcheck, use these intercepts right from
+      the start, otherwise ld.so makes a lot of noise. */
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/ld.so.1", "strcmp",
+                         (Addr)&VG_(x86_solaris_REDIR_FOR_strcmp), NULL);
+   }
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/ld.so.1", "strlen",
+                         (Addr)&VG_(x86_solaris_REDIR_FOR_strlen), NULL);
+   }
+
+#  elif defined(VGP_amd64_solaris)
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/amd64/ld.so.1", "strcpy",
+                         (Addr)&VG_(amd64_solaris_REDIR_FOR_strcpy), NULL);
+   }
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/amd64/ld.so.1", "strncpy",
+                         (Addr)&VG_(amd64_solaris_REDIR_FOR_strncpy), NULL);
+   }
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/amd64/ld.so.1", "strcmp",
+                         (Addr)&VG_(amd64_solaris_REDIR_FOR_strcmp), NULL);
+   }
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/amd64/ld.so.1", "strcat",
+                         (Addr)&VG_(amd64_solaris_REDIR_FOR_strcat), NULL);
+   }
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("/lib/amd64/ld.so.1", "strlen",
+                         (Addr)&VG_(amd64_solaris_REDIR_FOR_strlen), NULL);
+   }
+
 #  else
 #    error Unknown platform
 #  endif
diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c
index fefb8e9..76efc10 100644
--- a/coregrind/m_replacemalloc/vg_replace_malloc.c
+++ b/coregrind/m_replacemalloc/vg_replace_malloc.c
@@ -305,6 +305,12 @@
  ZONEALLOC_or_NULL(VG_Z_LIBC_SONAME,  malloc_zone_malloc, malloc);
  ZONEALLOC_or_NULL(SO_SYN_MALLOC,     malloc_zone_malloc, malloc);
 
+#elif defined(VGO_solaris)
+ ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, malloc,      malloc);
+ ALLOC_or_NULL(VG_Z_LIBC_SONAME,      malloc,      malloc);
+ ALLOC_or_NULL(VG_Z_LIBUMEM_SO_1,     malloc,      malloc);
+ ALLOC_or_NULL(SO_SYN_MALLOC,         malloc,      malloc);
+
 #endif
 
 
@@ -341,6 +347,18 @@
   //ALLOC_or_BOMB(VG_Z_LIBC_SONAME,      _Znwm,          __builtin_new);
  #endif
 
+#elif defined(VGO_solaris)
+ // operator new(unsigned int), GNU mangling
+ #if VG_WORDSIZE == 4
+  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwj,          __builtin_new);
+  ALLOC_or_BOMB(SO_SYN_MALLOC,         _Znwj,          __builtin_new);
+ #endif
+ // operator new(unsigned long), GNU mangling
+ #if VG_WORDSIZE == 8
+  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwm,          __builtin_new);
+  ALLOC_or_BOMB(SO_SYN_MALLOC,         _Znwm,          __builtin_new);
+ #endif
+
 #endif
 
 
@@ -372,6 +390,18 @@
   //ALLOC_or_NULL(VG_Z_LIBC_SONAME,      _ZnwmRKSt9nothrow_t,  __builtin_new);
  #endif
 
+#elif defined(VGO_solaris)
+ // operator new(unsigned, std::nothrow_t const&), GNU mangling
+ #if VG_WORDSIZE == 4
+  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwjRKSt9nothrow_t,  __builtin_new);
+  ALLOC_or_NULL(SO_SYN_MALLOC,         _ZnwjRKSt9nothrow_t,  __builtin_new);
+ #endif
+ // operator new(unsigned long, std::nothrow_t const&), GNU mangling
+ #if VG_WORDSIZE == 8
+  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwmRKSt9nothrow_t,  __builtin_new);
+  ALLOC_or_NULL(SO_SYN_MALLOC,         _ZnwmRKSt9nothrow_t,  __builtin_new);
+ #endif
+
 #endif
 
 
@@ -406,6 +436,18 @@
   //ALLOC_or_BOMB(VG_Z_LIBC_SONAME,      _Znam,             __builtin_vec_new );
  #endif
 
+#elif defined(VGO_solaris)
+ // operator new[](unsigned int), GNU mangling
+ #if VG_WORDSIZE == 4
+  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znaj,             __builtin_vec_new );
+  ALLOC_or_BOMB(SO_SYN_MALLOC,         _Znaj,             __builtin_vec_new );
+ #endif
+ // operator new[](unsigned long), GNU mangling
+ #if VG_WORDSIZE == 8
+  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znam,             __builtin_vec_new );
+  ALLOC_or_BOMB(SO_SYN_MALLOC,         _Znam,             __builtin_vec_new );
+ #endif
+
 #endif
 
 
@@ -437,6 +479,18 @@
   //ALLOC_or_NULL(VG_Z_LIBC_SONAME,      _ZnamRKSt9nothrow_t, __builtin_vec_new );
  #endif
 
+#elif defined(VGO_solaris)
+ // operator new[](unsigned, std::nothrow_t const&), GNU mangling
+ #if VG_WORDSIZE == 4
+  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnajRKSt9nothrow_t, __builtin_vec_new );
+  ALLOC_or_NULL(SO_SYN_MALLOC,         _ZnajRKSt9nothrow_t, __builtin_vec_new );
+ #endif
+ // operator new[](unsigned long, std::nothrow_t const&), GNU mangling
+ #if VG_WORDSIZE == 8
+  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new );
+  ALLOC_or_NULL(SO_SYN_MALLOC,         _ZnamRKSt9nothrow_t, __builtin_vec_new );
+ #endif
+
 #endif
 
 
@@ -482,6 +536,11 @@
  ZONEFREE(VG_Z_LIBC_SONAME,   malloc_zone_free,     free );
  ZONEFREE(SO_SYN_MALLOC,      malloc_zone_free,     free );
 
+#elif defined(VGO_solaris)
+ FREE(VG_Z_LIBC_SONAME,       free,                 free );
+ FREE(VG_Z_LIBUMEM_SO_1,      free,                 free );
+ FREE(SO_SYN_MALLOC,          free,                 free );
+
 #endif
 
 
@@ -497,6 +556,12 @@
  //FREE(VG_Z_LIBSTDCXX_SONAME,  cfree,                free );
  //FREE(VG_Z_LIBC_SONAME,       cfree,                free );
 
+#elif defined(VGO_solaris)
+ FREE(VG_Z_LIBC_SONAME,       cfree,                free );
+ /* libumem does not implement cfree(). */
+ //FREE(VG_Z_LIBUMEM_SO_1,      cfree,                free );
+ FREE(SO_SYN_MALLOC,          cfree,                free );
+
 #endif
 
 
@@ -516,6 +581,11 @@
  //FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdlPv,               __builtin_delete );
  //FREE(VG_Z_LIBC_SONAME,       _ZdlPv,               __builtin_delete );
 
+#elif defined(VGO_solaris)
+ // operator delete(void*), GNU mangling
+ FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdlPv,               __builtin_delete );
+ FREE(SO_SYN_MALLOC,          _ZdlPv,               __builtin_delete );
+
 #endif
 
 
@@ -532,6 +602,11 @@
  //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t,  __builtin_delete );
  //FREE(VG_Z_LIBC_SONAME,      _ZdlPvRKSt9nothrow_t,  __builtin_delete );
 
+#elif defined(VGO_solaris)
+ // operator delete(void*, std::nothrow_t const&), GNU mangling
+ FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t,  __builtin_delete );
+ FREE(SO_SYN_MALLOC,         _ZdlPvRKSt9nothrow_t,  __builtin_delete );
+
 #endif
 
 
@@ -554,6 +629,11 @@
  //FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdaPv,               __builtin_vec_delete );
  //FREE(VG_Z_LIBC_SONAME,       _ZdaPv,               __builtin_vec_delete );
 
+#elif defined(VGO_solaris)
+ // operator delete[](void*), GNU mangling
+ FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdaPv,               __builtin_vec_delete );
+ FREE(SO_SYN_MALLOC,          _ZdaPv,               __builtin_vec_delete );
+
 #endif
 
 
@@ -570,6 +650,11 @@
  //FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
  //FREE(VG_Z_LIBC_SONAME,       _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
 
+#elif defined(VGO_solaris)
+ // operator delete[](void*, std::nothrow_t const&), GNU mangling
+ FREE(VG_Z_LIBSTDCXX_SONAME,  _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
+ FREE(SO_SYN_MALLOC,          _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
+
 #endif
 
 
@@ -632,6 +717,11 @@
  ZONECALLOC(VG_Z_LIBC_SONAME, malloc_zone_calloc);
  ZONECALLOC(SO_SYN_MALLOC,    malloc_zone_calloc);
 
+#elif defined(VGO_solaris)
+ CALLOC(VG_Z_LIBC_SONAME,      calloc);
+ CALLOC(VG_Z_LIBUMEM_SO_1,     calloc);
+ CALLOC(SO_SYN_MALLOC,         calloc);
+
 #endif
 
 
@@ -701,6 +791,11 @@
  ZONEREALLOC(VG_Z_LIBC_SONAME, malloc_zone_realloc);
  ZONEREALLOC(SO_SYN_MALLOC,    malloc_zone_realloc);
 
+#elif defined(VGO_solaris)
+ REALLOC(VG_Z_LIBC_SONAME,      realloc);
+ REALLOC(VG_Z_LIBUMEM_SO_1,     realloc);
+ REALLOC(SO_SYN_MALLOC,         realloc);
+
 #endif
 
 
@@ -769,6 +864,11 @@
  ZONEMEMALIGN(VG_Z_LIBC_SONAME, malloc_zone_memalign);
  ZONEMEMALIGN(SO_SYN_MALLOC,    malloc_zone_memalign);
 
+#elif defined(VGO_solaris)
+ MEMALIGN(VG_Z_LIBC_SONAME,      memalign);
+ MEMALIGN(VG_Z_LIBUMEM_SO_1,     memalign);
+ MEMALIGN(SO_SYN_MALLOC,         memalign);
+
 #endif
 
 
@@ -811,6 +911,11 @@
  ZONEVALLOC(VG_Z_LIBC_SONAME, malloc_zone_valloc);
  ZONEVALLOC(SO_SYN_MALLOC,    malloc_zone_valloc);
 
+#elif defined(VGO_solaris)
+ VALLOC(VG_Z_LIBC_SONAME,      valloc);
+ VALLOC(VG_Z_LIBUMEM_SO_1,     valloc);
+ VALLOC(SO_SYN_MALLOC,         valloc);
+
 #endif
 
 
@@ -919,6 +1024,10 @@
 #elif defined(VGO_darwin)
  //POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign);
 
+#elif defined(VGO_solaris)
+ POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign);
+ POSIX_MEMALIGN(SO_SYN_MALLOC,    posix_memalign);
+
 #endif
 
 
@@ -965,6 +1074,7 @@
 
 /* Bomb out if we get any of these. */
 
+static void panic(const char *str) __attribute__((unused));
 static void panic(const char *str)
 {
    VALGRIND_PRINTF_BACKTRACE("Program aborting because of call to %s\n", str);
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index 80fdf6a..62906ca 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -218,6 +218,8 @@
       case VEX_TRC_JMP_SYS_INT128:     return "INT128";
       case VEX_TRC_JMP_SYS_INT129:     return "INT129";
       case VEX_TRC_JMP_SYS_INT130:     return "INT130";
+      case VEX_TRC_JMP_SYS_INT145:     return "INT145";
+      case VEX_TRC_JMP_SYS_INT210:     return "INT210";
       case VEX_TRC_JMP_SYS_SYSENTER:   return "SYSENTER";
       case VEX_TRC_JMP_BORING:         return "VEX_BORING";
 
@@ -448,7 +450,13 @@
    /* 
       Tell the kernel we're yielding.
     */
+#  if defined(VGO_linux) || defined(VGO_darwin)
    VG_(do_syscall0)(__NR_sched_yield);
+#  elif defined(VGO_solaris)
+   VG_(do_syscall0)(__NR_yield);
+#  else
+#    error Unknown OS
+#  endif
 
    VG_(acquire_BigLock)(tid, "VG_(vg_yield)");
 }
@@ -492,6 +500,17 @@
    tst->os_state.remote_port       = 0;
    tst->os_state.msgh_id           = 0;
    VG_(memset)(&tst->os_state.mach_args, 0, sizeof(tst->os_state.mach_args));
+#  elif defined(VGO_solaris)
+#  if defined(VGP_x86_solaris)
+   tst->os_state.thrptr = 0;
+#  endif
+   tst->os_state.stk_id = (UWord)-1;
+   tst->os_state.ustack = NULL;
+   tst->os_state.in_door_return = False;
+   tst->os_state.door_return_procedure = 0;
+   tst->os_state.oldcontext = NULL;
+   tst->os_state.schedctl_data = 0;
+   tst->os_state.daemon_thread = False;
 #  else
 #    error "Unknown OS"
 #  endif
@@ -1409,7 +1428,10 @@
       case VEX_TRC_JMP_SYS_INT128:  /* x86-linux */
       case VEX_TRC_JMP_SYS_INT129:  /* x86-darwin */
       case VEX_TRC_JMP_SYS_INT130:  /* x86-darwin */
-      case VEX_TRC_JMP_SYS_SYSCALL: /* amd64-linux, ppc32-linux, amd64-darwin */
+      case VEX_TRC_JMP_SYS_INT145:  /* x86-solaris */
+      case VEX_TRC_JMP_SYS_INT210:  /* x86-solaris */
+      /* amd64-linux, ppc32-linux, amd64-darwin, amd64-solaris */
+      case VEX_TRC_JMP_SYS_SYSCALL:
 	 handle_syscall(tid, trc[0]);
 	 if (VG_(clo_sanity_level) > 2)
 	    VG_(sanity_check_general)(True); /* sanity-check every syscall */
@@ -1599,7 +1621,7 @@
 #        if defined(VGP_x86_linux)
          vg_assert2(0, "VG_(scheduler), phase 3: "
                        "sysenter_x86 on x86-linux is not supported");
-#        elif defined(VGP_x86_darwin)
+#        elif defined(VGP_x86_darwin) || defined(VGP_x86_solaris)
          /* return address in client edx */
          VG_(threads)[tid].arch.vex.guest_EIP
             = VG_(threads)[tid].arch.vex.guest_EDX;
diff --git a/coregrind/m_sigframe/sigframe-amd64-darwin.c b/coregrind/m_sigframe/sigframe-amd64-darwin.c
index 53014b8..803526b 100644
--- a/coregrind/m_sigframe/sigframe-amd64-darwin.c
+++ b/coregrind/m_sigframe/sigframe-amd64-darwin.c
@@ -145,6 +145,7 @@
    former case, the amd64 calling conventions will simply cause the
    extra 2 args to be ignored (inside the handler).  (We hope!) */
 void VG_(sigframe_create) ( ThreadId tid,
+                            Bool on_altstack,
                             Addr sp_top_of_frame,
                             const vki_siginfo_t *siginfo,
                             const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-amd64-linux.c b/coregrind/m_sigframe/sigframe-amd64-linux.c
index 0c1c7b4..761f9b4 100644
--- a/coregrind/m_sigframe/sigframe-amd64-linux.c
+++ b/coregrind/m_sigframe/sigframe-amd64-linux.c
@@ -451,6 +451,7 @@
 
 
 void VG_(sigframe_create)( ThreadId tid, 
+                            Bool on_altstack,
                             Addr rsp_top_of_frame,
                             const vki_siginfo_t *siginfo,
                             const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-arm-linux.c b/coregrind/m_sigframe/sigframe-arm-linux.c
index add7c82..01dbfbe 100644
--- a/coregrind/m_sigframe/sigframe-arm-linux.c
+++ b/coregrind/m_sigframe/sigframe-arm-linux.c
@@ -161,6 +161,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr sp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-arm64-linux.c b/coregrind/m_sigframe/sigframe-arm64-linux.c
index 6e80659..c248585 100644
--- a/coregrind/m_sigframe/sigframe-arm64-linux.c
+++ b/coregrind/m_sigframe/sigframe-arm64-linux.c
@@ -152,6 +152,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr sp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-common.c b/coregrind/m_sigframe/sigframe-common.c
index 48bd247..97419d6 100644
--- a/coregrind/m_sigframe/sigframe-common.c
+++ b/coregrind/m_sigframe/sigframe-common.c
@@ -49,7 +49,7 @@
    VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, size, tid );
 }
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 
 /* Extend the stack segment downwards if needed so as to ensure the
    new signal frames are mapped to something.  Return a Bool
diff --git a/coregrind/m_sigframe/sigframe-mips32-linux.c b/coregrind/m_sigframe/sigframe-mips32-linux.c
index 4b23dc7..1e4f9ac 100644
--- a/coregrind/m_sigframe/sigframe-mips32-linux.c
+++ b/coregrind/m_sigframe/sigframe-mips32-linux.c
@@ -121,6 +121,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr sp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-mips64-linux.c b/coregrind/m_sigframe/sigframe-mips64-linux.c
index 5e0f44a..c1f2637 100644
--- a/coregrind/m_sigframe/sigframe-mips64-linux.c
+++ b/coregrind/m_sigframe/sigframe-mips64-linux.c
@@ -116,6 +116,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create) ( ThreadId tid,
+                            Bool on_altstack,
                             Addr sp_top_of_frame,
                             const vki_siginfo_t *siginfo,
                             const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-ppc32-linux.c b/coregrind/m_sigframe/sigframe-ppc32-linux.c
index 8047f27..504480e 100644
--- a/coregrind/m_sigframe/sigframe-ppc32-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc32-linux.c
@@ -624,6 +624,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr sp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-ppc64-linux.c b/coregrind/m_sigframe/sigframe-ppc64-linux.c
index ec4d883..5a7fa89 100644
--- a/coregrind/m_sigframe/sigframe-ppc64-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc64-linux.c
@@ -134,6 +134,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr sp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-s390x-linux.c b/coregrind/m_sigframe/sigframe-s390x-linux.c
index fb70c76..2e1ad0c 100644
--- a/coregrind/m_sigframe/sigframe-s390x-linux.c
+++ b/coregrind/m_sigframe/sigframe-s390x-linux.c
@@ -403,6 +403,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid,
+			   Bool on_altstack,
 			   Addr sp_top_of_frame,
 			   const vki_siginfo_t *siginfo,
 			   const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-solaris.c b/coregrind/m_sigframe/sigframe-solaris.c
new file mode 100644
index 0000000..2e28bd5
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-solaris.c
@@ -0,0 +1,270 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames.                       ---*/
+/*---                                           sigframe-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2014 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+#if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_sigframe.h"      /* Self */
+#include "pub_core_syswrap.h"
+#include "priv_sigframe.h"
+
+/* This module creates and removes signal frames for signal deliveries
+   on x86/amd64-solaris. */
+
+/* Create a signal frame for thread 'tid'.  Make a 3-arg frame regardless of
+   whether the client originally requested a 1-arg version (no SA_SIGINFO) or
+   a 3-arg one (SA_SIGINFO) since in the former case, the x86/amd64 calling
+   conventions will simply cause the extra 2 args to be ignored (inside the
+   handler). */
+void VG_(sigframe_create)(ThreadId tid, Bool on_altstack,
+                          Addr sp_top_of_frame, const vki_siginfo_t *siginfo,
+                          const struct vki_ucontext *siguc,
+                          void *handler, UInt flags, const vki_sigset_t *mask,
+                          void *restorer)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Addr esp;
+   vki_sigframe_t *frame;
+   Int signo = siginfo->si_signo;
+
+   /* Calculate new stack pointer. */
+   esp = sp_top_of_frame - sizeof(vki_sigframe_t);
+   esp = VG_ROUNDDN(esp, 16) - sizeof(UWord);
+
+   if (!ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
+      return;
+
+   /* Fill in the frame. */
+   frame = (vki_sigframe_t*)esp;
+
+   /* Set a bogus return address.  This return address should be never used
+      because to return from a signal handler a program has to call
+      setcontext() explicitly. */
+   frame->return_addr = (void*)~0UL;
+
+   /* Save current context.  (This has to be done before the thread state is
+      modified in any way.) */
+   VG_(save_context)(tid, &frame->ucontext, Vg_CoreSignal);
+
+   /* Fill in the siginfo. */
+   frame->siginfo = *siginfo;
+   /* Set expected si_addr value.
+
+      Manual page siginfo.h(3HEAD) describes that some signals define si_addr
+      to be an address of the faulting instruction (SIGILL). Then it is needed
+      to change the real CPU address to the VCPU address. Some signals define
+      si_addr to be an address of the faulting memory reference (SIGSEGV,
+      SIGBUS). Then the address should be passed unmodified.
+
+      However documentation contained in the manpage does not reflect the
+      reality found in the Solaris kernel - uts/<arch>/os/trap.c. Here one can
+      observe that in some cases si_addr is set to address provided by the
+      underlying subsystem. In some cases si_addr is set to the current
+      program counter. Other signals are missing documentation altogether.
+      It is almost impossible to determine what value is stored in si_addr
+      based on the information provided by kernel to the signal handler.
+
+      POSIX.1-2008 says about si_addr:
+      SIGILL, SIGFPE ... Address of faulting instruction.
+      SIGSEGV, SIGBUS ... Address of faulting memory reference.
+      For some implementations, the value of si_addr may be inaccurate.
+
+      See tests none/tests/faultstatus and none/tests/x86/badseg for examples.
+      The code below simply follows the POSIX standard, but propagates any
+      possibly incorrect values from the kernel to the user.
+    */
+   switch (signo) {
+   case VKI_SIGSEGV:
+      switch (siginfo->si_code) {
+      case VKI_SEGV_ACCERR:
+      case VKI_SEGV_MAPERR:
+      default:
+         break;
+      case VKI_SEGV_MADE_UP_GPF:
+         /* Translate si_code synthesized by Valgrind to SEGV_MAPPER. */
+         frame->siginfo.si_code = VKI_SEGV_MAPERR;
+         break;
+      }
+      break;
+   case VKI_SIGBUS:
+      break;
+   case VKI_SIGFPE:
+   case VKI_SIGILL:
+   case VKI_SIGTRAP:
+      frame->siginfo.si_addr = (void*)VG_(get_IP)(tid);
+      break;
+   case VKI_SIGPROF:
+      frame->siginfo.si_faddr = (void*)VG_(get_IP)(tid);
+      break;
+   default:
+      break;
+   }
+   VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->siginfo,
+            sizeof(frame->siginfo));
+
+   /* Save the signal number in an unused slot.  Later, when a return from the
+      signal is made, this value is used to inform the tool that the
+      processing for the given signal has ended. */
+   VKI_UC_SIGNO(&frame->ucontext) = signo | ((~(UWord)signo & 0xFFFF) << 16);
+   /* Old context has to point to the saved ucontext. */
+   tst->os_state.oldcontext = &frame->ucontext;
+   /* Save ERR and TRAPNO if siguc is present. */
+   if (siguc) {
+      frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR]
+         = siguc->uc_mcontext.gregs[VKI_REG_ERR];
+      VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
+               (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_ERR],
+               sizeof(UWord));
+      frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO]
+         = siguc->uc_mcontext.gregs[VKI_REG_TRAPNO];
+      VG_TRACK(post_mem_write, Vg_CoreSignal, tid,
+               (Addr)&frame->ucontext.uc_mcontext.gregs[VKI_REG_TRAPNO],
+               sizeof(UWord));
+   }
+
+   /* Prepare parameters for a signal handler. */
+   frame->a1_signo = signo;
+   /* The first parameter has to be 16-byte aligned, resembling function
+      calls. */
+   {
+      /* Using
+         vg_assert(VG_IS_16_ALIGNED(&frame->a1_signo));
+         seems to get miscompiled on amd64 with GCC 4.7.2. */
+      Addr signo_addr = (Addr)&frame->a1_signo;
+      vg_assert(VG_IS_16_ALIGNED(signo_addr));
+   }
+   frame->a2_siginfo = &frame->siginfo;
+   VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a1_signo,
+            sizeof(frame->a1_signo) + sizeof(frame->a2_siginfo));
+#if defined(VGP_x86_solaris)
+   frame->a3_ucontext = &frame->ucontext;
+   VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)&frame->a3_ucontext,
+            sizeof(frame->a3_ucontext));
+#elif defined(VGP_amd64_solaris)
+   tst->arch.vex.guest_RDI = signo;
+   VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
+            guest_RDI), sizeof(ULong));
+   tst->arch.vex.guest_RSI = (Addr)&frame->siginfo;
+   VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
+            guest_RSI), sizeof(ULong));
+   tst->arch.vex.guest_RDX = (Addr)&frame->ucontext;
+   VG_TRACK(post_reg_write, Vg_CoreSignal, tid, offsetof(VexGuestAMD64State,
+            guest_RDX), sizeof(ULong));
+#endif
+
+   /* Set up the stack pointer. */
+   vg_assert(esp == (Addr)&frame->return_addr);
+   VG_(set_SP)(tid, esp);
+   VG_TRACK(post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr));
+
+   /* Set up the program counter. Note that we don't inform a tool about IP
+      write because IP is always defined. */
+   VG_(set_IP)(tid, (Addr)handler);
+
+   /* If the signal is delivered on the alternate stack, copy it out to
+      ustack.  This has to be done after setting a new IP so the SS_ONSTACK
+      flag is set by VG_(do_sys_sigaltstack)(). */
+   if (on_altstack && tst->os_state.ustack
+       && VG_(am_is_valid_for_client)((Addr)tst->os_state.ustack,
+                                      sizeof(*tst->os_state.ustack),
+                                      VKI_PROT_WRITE)) {
+      SysRes res;
+      vki_stack_t altstack;
+
+      /* Get information about alternate stack. */
+      res = VG_(do_sys_sigaltstack)(tid, NULL, &altstack);
+      vg_assert(!sr_isError(res));
+
+      /* Copy it to ustack. */
+      *tst->os_state.ustack = altstack;
+      VG_TRACK(post_mem_write, Vg_CoreSignal, tid, (Addr)tst->os_state.ustack,
+               sizeof(*tst->os_state.ustack));
+   }
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "sigframe_create (thread %d): next IP=%#lx, "
+                   "next SP=%#lx\n",
+                   tid, (Addr)handler, (Addr)frame);
+}
+
+void VG_(sigframe_destroy)(ThreadId tid, Bool isRT)
+{
+   /* Not used on Solaris. */
+   vg_assert(0);
+}
+
+void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc)
+{
+   Int signo;
+
+   /* Check if a signal number was saved in the restored context. */
+   signo = VKI_UC_SIGNO_CONST(uc) & 0xFFFF;
+   if (!signo || signo != ((~VKI_UC_SIGNO_CONST(uc) >> 16) & 0xFFFF))
+      return;
+
+   /* Note: The active tool should be informed here about the dead stack area.
+      However, this was already done when the original context was restored (in
+      VG_(restore_context)()) so it is not necessary to do it here again.
+
+      There is a small nuance though, VG_(restore_context)() triggers the
+      die_mem_stack event while in this case, it should really trigger the
+      die_mem_stack_signal event.  This is not currently a problem because all
+      official tools handle these two events in the same way.
+
+      If a return from an alternate stack is made then no die_mem_stack event
+      is currently triggered. */
+
+   /* Returning from a signal handler. */
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "sigframe_return (thread %d): IP=%#lx\n",
+                   tid, VG_(get_IP)(tid));
+
+   /* Tell the tool. */
+   VG_TRACK(post_deliver_signal, tid, signo);
+}
+
+#endif // defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_sigframe/sigframe-x86-darwin.c b/coregrind/m_sigframe/sigframe-x86-darwin.c
index 540378a..8e77f60 100644
--- a/coregrind/m_sigframe/sigframe-x86-darwin.c
+++ b/coregrind/m_sigframe/sigframe-x86-darwin.c
@@ -133,6 +133,7 @@
    former case, the x86 calling conventions will simply cause the
    extra 2 args to be ignored (inside the handler). */
 void VG_(sigframe_create) ( ThreadId tid,
+                            Bool on_altstack,
                             Addr sp_top_of_frame,
                             const vki_siginfo_t *siginfo,
                             const struct vki_ucontext *siguc,
diff --git a/coregrind/m_sigframe/sigframe-x86-linux.c b/coregrind/m_sigframe/sigframe-x86-linux.c
index 3db2251..ce33f73 100644
--- a/coregrind/m_sigframe/sigframe-x86-linux.c
+++ b/coregrind/m_sigframe/sigframe-x86-linux.c
@@ -535,6 +535,7 @@
 
 /* EXPORTED */
 void VG_(sigframe_create)( ThreadId tid, 
+                           Bool on_altstack,
                            Addr esp_top_of_frame,
                            const vki_siginfo_t *siginfo,
                            const struct vki_ucontext *siguc,
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 4aa24f5..e231f3d 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -566,6 +566,7 @@
         (srP)->misc.MIPS64.r31 = (uc)->uc_mcontext.sc_regs[31]; \
         (srP)->misc.MIPS64.r28 = (uc)->uc_mcontext.sc_regs[28]; \
       }
+
 #elif defined(VGP_tilegx_linux)
 #  define VG_UCONTEXT_INSTR_PTR(uc)       ((uc)->uc_mcontext.pc)
 #  define VG_UCONTEXT_STACK_PTR(uc)       ((uc)->uc_mcontext.sp)
@@ -580,6 +581,34 @@
         (srP)->misc.TILEGX.r52 = (uc)->uc_mcontext.gregs[52];  \
         (srP)->misc.TILEGX.r55 = (uc)->uc_mcontext.lr;         \
       }
+
+#elif defined(VGP_x86_solaris)
+#  define VG_UCONTEXT_INSTR_PTR(uc)       ((Addr)(uc)->uc_mcontext.gregs[VKI_EIP])
+#  define VG_UCONTEXT_STACK_PTR(uc)       ((Addr)(uc)->uc_mcontext.gregs[VKI_UESP])
+#  define VG_UCONTEXT_SYSCALL_SYSRES(uc)                               \
+      VG_(mk_SysRes_x86_solaris)((uc)->uc_mcontext.gregs[VKI_EFL] & 1, \
+                                 (uc)->uc_mcontext.gregs[VKI_EAX],     \
+                                 (uc)->uc_mcontext.gregs[VKI_EFL] & 1  \
+                                 ? 0 : (uc)->uc_mcontext.gregs[VKI_EDX])
+#  define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc)                      \
+      { (srP)->r_pc = (ULong)(uc)->uc_mcontext.gregs[VKI_EIP];         \
+        (srP)->r_sp = (ULong)(uc)->uc_mcontext.gregs[VKI_UESP];        \
+        (srP)->misc.X86.r_ebp = (uc)->uc_mcontext.gregs[VKI_EBP];      \
+      }
+
+#elif defined(VGP_amd64_solaris)
+#  define VG_UCONTEXT_INSTR_PTR(uc)       ((Addr)(uc)->uc_mcontext.gregs[VKI_REG_RIP])
+#  define VG_UCONTEXT_STACK_PTR(uc)       ((Addr)(uc)->uc_mcontext.gregs[VKI_REG_RSP])
+#  define VG_UCONTEXT_SYSCALL_SYSRES(uc)                                     \
+      VG_(mk_SysRes_amd64_solaris)((uc)->uc_mcontext.gregs[VKI_REG_RFL] & 1, \
+                                   (uc)->uc_mcontext.gregs[VKI_REG_RAX],     \
+                                   (uc)->uc_mcontext.gregs[VKI_REG_RFL] & 1  \
+                                   ? 0 : (uc)->uc_mcontext.gregs[VKI_REG_RDX])
+#  define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc)                            \
+      { (srP)->r_pc = (uc)->uc_mcontext.gregs[VKI_REG_RIP];                  \
+        (srP)->r_sp = (uc)->uc_mcontext.gregs[VKI_REG_RSP];                  \
+        (srP)->misc.AMD64.r_rbp = (uc)->uc_mcontext.gregs[VKI_REG_RBP];      \
+      }
 #else
 #  error Unknown platform
 #endif
@@ -592,7 +621,7 @@
 #if defined(VGO_linux)
 #  define VKI_SIGINFO_si_addr  _sifields._sigfault._addr
 #  define VKI_SIGINFO_si_pid   _sifields._kill._pid
-#elif defined(VGO_darwin)
+#elif defined(VGO_darwin) || defined(VGO_solaris)
 #  define VKI_SIGINFO_si_addr  si_addr
 #  define VKI_SIGINFO_si_pid   si_pid
 #else
@@ -667,6 +696,7 @@
      SA_NOCLDSTOP -- passed to kernel
      SA_ONESHOT or SA_RESETHAND -- pass through
      SA_RESTART -- we observe this but set our handlers to always restart
+                   (this doesn't apply to the Solaris port)
      SA_NOMASK or SA_NODEFER -- we observe this, but our handlers block everything
      SA_ONSTACK -- pass through
      SA_NOCLDWAIT -- pass through
@@ -796,12 +826,20 @@
 
       /* SA_ONESHOT: ignore client setting */
       
+#     if !defined(VGO_solaris)
       /* SA_RESTART: ignore client setting and always set it for us.
 	 Though we never rely on the kernel to restart a
 	 syscall, we observe whether it wanted to restart the syscall
 	 or not, which is needed by 
          VG_(fixup_guest_state_after_syscall_interrupted) */
       skss_flags |= VKI_SA_RESTART;
+#else
+      /* The above does not apply to the Solaris port, where the kernel does
+         not directly restart syscalls, but instead it checks SA_RESTART flag
+         and if it is set then it returns ERESTART to libc and the library
+         actually restarts the syscall. */
+      skss_flags |= scss_flags & VKI_SA_RESTART;
+#     endif
 
       /* SA_NOMASK: ignore it */
 
@@ -965,6 +1003,15 @@
    " swint1\n" \
    ".previous\n"
 
+#elif defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
+/* Not used on Solaris. */
+#  define _MY_SIGRETURN(name) \
+   ".text\n" \
+   ".globl my_sigreturn\n" \
+   "my_sigreturn:\n" \
+   "ud2\n" \
+   ".previous\n"
+
 #else
 #  error Unknown platform
 #endif
@@ -1008,7 +1055,7 @@
       ksa.sa_flags    = skss.skss_per_sig[sig].skss_flags;
 #     if !defined(VGP_ppc32_linux) && \
          !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
-         !defined(VGP_mips32_linux)
+         !defined(VGP_mips32_linux) && !defined(VGO_solaris)
       ksa.sa_restorer = my_sigreturn;
 #     endif
       /* Re above ifdef (also the assertion below), PaulM says:
@@ -1038,11 +1085,24 @@
       if (!force_update) {
          vg_assert(ksa_old.ksa_handler 
                    == skss_old.skss_per_sig[sig].skss_handler);
+#        if defined(VGO_solaris)
+         if (ksa_old.ksa_handler == VKI_SIG_DFL
+               || ksa_old.ksa_handler == VKI_SIG_IGN) {
+            /* The Solaris kernel ignores signal flags (except SA_NOCLDWAIT
+               and SA_NOCLDSTOP) and a signal mask if a handler is set to
+               SIG_DFL or SIG_IGN. */
+            skss_old.skss_per_sig[sig].skss_flags
+               &= (VKI_SA_NOCLDWAIT | VKI_SA_NOCLDSTOP);
+            vg_assert(VG_(isemptysigset)( &ksa_old.sa_mask ));
+            VG_(sigfillset)( &ksa_old.sa_mask );
+         }
+#        endif
          vg_assert(ksa_old.sa_flags 
                    == skss_old.skss_per_sig[sig].skss_flags);
 #        if !defined(VGP_ppc32_linux) && \
             !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
-            !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux)
+            !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux) && \
+            !defined(VGO_solaris)
          vg_assert(ksa_old.sa_restorer == my_sigreturn);
 #        endif
          VG_(sigaddset)( &ksa_old.sa_mask, VKI_SIGKILL );
@@ -1162,7 +1222,8 @@
       old_act->ksa_handler = scss.scss_per_sig[signo].scss_handler;
       old_act->sa_flags    = scss.scss_per_sig[signo].scss_flags;
       old_act->sa_mask     = scss.scss_per_sig[signo].scss_mask;
-#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+         !defined(VGO_solaris)
       old_act->sa_restorer = scss.scss_per_sig[signo].scss_restorer;
 #     endif
    }
@@ -1174,7 +1235,8 @@
       scss.scss_per_sig[signo].scss_mask     = new_act->sa_mask;
 
       scss.scss_per_sig[signo].scss_restorer = NULL;
-#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+         !defined(VGO_solaris)
       scss.scss_per_sig[signo].scss_restorer = new_act->sa_restorer;
 #     endif
 
@@ -1369,6 +1431,7 @@
 void push_signal_frame ( ThreadId tid, const vki_siginfo_t *siginfo,
                                        const struct vki_ucontext *uc )
 {
+   Bool         on_altstack;
    Addr         esp_top_of_frame;
    ThreadState* tst;
    Int		sigNo = siginfo->si_signo;
@@ -1389,6 +1452,7 @@
              arch/i386/kernel/signal.c. */
           sas_ss_flags(tid, VG_(get_SP)(tid)) == 0
       ) {
+      on_altstack = True;
       esp_top_of_frame 
          = (Addr)(tst->altstack.ss_sp) + tst->altstack.ss_size;
       if (VG_(clo_trace_signals))
@@ -1397,24 +1461,21 @@
                    sigNo, VG_(signame)(sigNo), tid, tst->altstack.ss_sp,
                    (UChar *)tst->altstack.ss_sp + tst->altstack.ss_size,
                    (Word)tst->altstack.ss_size );
-
-      /* Signal delivery to tools */
-      VG_TRACK( pre_deliver_signal, tid, sigNo, /*alt_stack*/True );
-      
    } else {
+      on_altstack = False;
       esp_top_of_frame = VG_(get_SP)(tid) - VG_STACK_REDZONE_SZB;
-
-      /* Signal delivery to tools */
-      VG_TRACK( pre_deliver_signal, tid, sigNo, /*alt_stack*/False );
    }
 
+   /* Signal delivery to tools */
+   VG_TRACK( pre_deliver_signal, tid, sigNo, on_altstack );
+
    vg_assert(scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_IGN);
    vg_assert(scss.scss_per_sig[sigNo].scss_handler != VKI_SIG_DFL);
 
    /* This may fail if the client stack is busted; if that happens,
       the whole process will exit rather than simply calling the
       signal handler. */
-   VG_(sigframe_create) (tid, esp_top_of_frame, siginfo, uc,
+   VG_(sigframe_create) (tid, on_altstack, esp_top_of_frame, siginfo, uc,
                          scss.scss_per_sig[sigNo].scss_handler,
                          scss.scss_per_sig[sigNo].scss_flags,
                          &tst->sig_mask,
@@ -1439,6 +1500,7 @@
       case VKI_SIGUSR1:   return "SIGUSR1";
       case VKI_SIGUSR2:   return "SIGUSR2";
       case VKI_SIGSEGV:   return "SIGSEGV";
+      case VKI_SIGSYS:    return "SIGSYS";
       case VKI_SIGPIPE:   return "SIGPIPE";
       case VKI_SIGALRM:   return "SIGALRM";
       case VKI_SIGTERM:   return "SIGTERM";
@@ -1461,10 +1523,42 @@
 #     if defined(VKI_SIGPWR)
       case VKI_SIGPWR:    return "SIGPWR";
 #     endif
-#     if defined(VKI_SIGUNUSED)
+#     if defined(VKI_SIGUNUSED) && (VKI_SIGUNUSED != VKI_SIGSYS)
       case VKI_SIGUNUSED: return "SIGUNUSED";
 #     endif
 
+      /* Solaris-specific signals. */
+#     if defined(VKI_SIGEMT)
+      case VKI_SIGEMT:    return "SIGEMT";
+#     endif
+#     if defined(VKI_SIGWAITING)
+      case VKI_SIGWAITING: return "SIGWAITING";
+#     endif
+#     if defined(VKI_SIGLWP)
+      case VKI_SIGLWP:    return "SIGLWP";
+#     endif
+#     if defined(VKI_SIGFREEZE)
+      case VKI_SIGFREEZE: return "SIGFREEZE";
+#     endif
+#     if defined(VKI_SIGTHAW)
+      case VKI_SIGTHAW:   return "SIGTHAW";
+#     endif
+#     if defined(VKI_SIGCANCEL)
+      case VKI_SIGCANCEL: return "SIGCANCEL";
+#     endif
+#     if defined(VKI_SIGLOST)
+      case VKI_SIGLOST:   return "SIGLOST";
+#     endif
+#     if defined(VKI_SIGXRES)
+      case VKI_SIGXRES:   return "SIGXRES";
+#     endif
+#     if defined(VKI_SIGJVM1)
+      case VKI_SIGJVM1:   return "SIGJVM1";
+#     endif
+#     if defined(VKI_SIGJVM2)
+      case VKI_SIGJVM2:   return "SIGJVM2";
+#     endif
+
 #  if defined(VKI_SIGRTMIN) && defined(VKI_SIGRTMAX)
    case VKI_SIGRTMIN ... VKI_SIGRTMAX:
       VG_(sprintf)(buf, "SIGRT%d", sigNo-VKI_SIGRTMIN);
@@ -1487,7 +1581,8 @@
 
    sa.ksa_handler = VKI_SIG_DFL;
    sa.sa_flags = 0;
-#  if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#  if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+      !defined(VGO_solaris)
    sa.sa_restorer = 0;
 #  endif
    VG_(sigemptyset)(&sa.sa_mask);
@@ -1499,7 +1594,7 @@
    VG_(sigprocmask)(VKI_SIG_UNBLOCK, &mask, &origmask);
 
    r = VG_(kill)(VG_(getpid)(), sigNo);
-#  if defined(VGO_linux)
+#  if !defined(VGO_darwin)
    /* This sometimes fails with EPERM on Darwin.  I don't know why. */
    vg_assert(r == 0);
 #  endif
@@ -1517,7 +1612,7 @@
 // pass in some other details that can help when si_code is unreliable.
 static Bool is_signal_from_kernel(ThreadId tid, int signum, int si_code)
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    // On Linux, SI_USER is zero, negative values are from the user, positive
    // values are from the kernel.  There are SI_FROMUSER and SI_FROMKERNEL
    // macros but we don't use them here because other platforms don't have
@@ -1558,11 +1653,6 @@
 #  endif
 }
 
-// This is an arbitrary si_code that we only use internally.  It corresponds
-// to the value SI_KERNEL on Linux, but that's not really of any significance
-// as far as I can determine.
-#define VKI_SEGV_MADE_UP_GPF    0x80
-
 /* 
    Perform the default action of a signal.  If the signal is fatal, it
    marks all threads as needing to exit, but it doesn't actually kill
@@ -1589,8 +1679,15 @@
       case VKI_SIGSEGV:	/* core */
       case VKI_SIGBUS:	/* core */
       case VKI_SIGTRAP:	/* core */
+      case VKI_SIGSYS:	/* core */
       case VKI_SIGXCPU:	/* core */
       case VKI_SIGXFSZ:	/* core */
+
+      /* Solaris-specific signals. */
+#     if defined(VKI_SIGEMT)
+      case VKI_SIGEMT:	/* core */
+#     endif
+
          terminate = True;
          core = True;
          break;
@@ -1607,12 +1704,17 @@
 #     if defined(VKI_SIGPWR)
       case VKI_SIGPWR:	/* term */
 #     endif
-      case VKI_SIGSYS:	/* term */
       case VKI_SIGPROF:	/* term */
       case VKI_SIGVTALRM:	/* term */
 #     if defined(VKI_SIGRTMIN) && defined(VKI_SIGRTMAX)
       case VKI_SIGRTMIN ... VKI_SIGRTMAX: /* term */
 #     endif
+
+      /* Solaris-specific signals. */
+#     if defined(VKI_SIGLOST)
+      case VKI_SIGLOST:	/* term */
+#     endif
+
          terminate = True;
          break;
    }
@@ -1702,6 +1804,11 @@
 	    case VKI_FPE_FLTRES: event = "FP inexact"; break;
 	    case VKI_FPE_FLTINV: event = "FP invalid operation"; break;
 	    case VKI_FPE_FLTSUB: event = "FP subscript out of range"; break;
+
+            /* Solaris-specific codes. */
+#           if defined(VKI_FPE_FLTDEN)
+	    case VKI_FPE_FLTDEN: event = "FP denormalize"; break;
+#           endif
 	    }
 	    break;
 
@@ -1727,7 +1834,7 @@
          likely cause a segfault. */
       if (VG_(is_valid_tid)(tid)) {
          Word first_ip_delta = 0;
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
          /* Make sure that the address stored in the stack pointer is 
             located in a mapped page. That is not necessarily so. E.g.
             consider the scenario where the stack pointer was decreased
@@ -2027,6 +2134,9 @@
    uc.uc_mcontext = &mc;
    uc.uc_mcontext->__es.__trapno = 3;
    uc.uc_mcontext->__es.__err = 0;
+#  elif defined(VGP_x86_solaris)
+   uc.uc_mcontext.gregs[VKI_ERR] = 0;
+   uc.uc_mcontext.gregs[VKI_TRAPNO] = VKI_T_BPTFLT;
 #  endif
 
    /* fixs390: do we need to do anything here for s390 ? */
@@ -2162,13 +2272,117 @@
       mask them off) sign extends them when exporting to user space so
       we do the same thing here. */
    return (Short)si_code;
-#elif defined(VGO_darwin)
+#elif defined(VGO_darwin) || defined(VGO_solaris)
    return si_code;
 #else
 #  error Unknown OS
 #endif
 }
 
+#if defined(VGO_solaris)
+/* Following function is used to switch Valgrind from a client stack back onto
+   a Valgrind stack.  It is used only when the door_return call was invoked by
+   the client because this is the only syscall which is executed directly on
+   the client stack (see syscall-{x86,amd64}-solaris.S).  The switch onto the
+   Valgrind stack has to be made as soon as possible because there is no
+   guarantee that there is enough space on the client stack to run the
+   complete signal machinery.  Also, Valgrind has to be switched back onto its
+   stack before a simulated signal frame is created because that will
+   overwrite the real sigframe built by the kernel. */
+static void async_signalhandler_solaris_preprocess(ThreadId tid, Int *signo,
+                                                   vki_siginfo_t *info,
+                                                   struct vki_ucontext *uc)
+{
+#  define RECURSION_BIT 0x1000
+   Addr sp;
+   vki_sigframe_t *frame;
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Int rec_signo;
+
+   /* If not doing door_return then return instantly. */
+   if (!tst->os_state.in_door_return)
+      return;
+
+   /* Check for the recursion:
+      v ...
+      | async_signalhandler - executed on the client stack
+      v async_signalhandler_solaris_preprocess - first call switches the
+      |   stacks and sets the RECURSION_BIT flag
+      v async_signalhandler - executed on the Valgrind stack
+      | async_signalhandler_solaris_preprocess - the RECURSION_BIT flag is
+      v   set, clear it and return
+    */
+   if (*signo & RECURSION_BIT) {
+      *signo &= ~RECURSION_BIT;
+      return;
+   }
+
+   rec_signo = *signo | RECURSION_BIT;
+
+#  if defined(VGP_x86_solaris)
+   /* Register %ebx/%rbx points to the top of the original V stack. */
+   sp = uc->uc_mcontext.gregs[VKI_EBX];
+#  elif defined(VGP_amd64_solaris)
+   sp = uc->uc_mcontext.gregs[VKI_REG_RBX];
+#  else
+#    error "Unknown platform"
+#  endif
+
+   /* Build a fake signal frame, similarly as in sigframe-solaris.c. */
+   /* Calculate a new stack pointer. */
+   sp -= sizeof(vki_sigframe_t);
+   sp = VG_ROUNDDN(sp, 16) - sizeof(UWord);
+
+   /* Fill in the frame. */
+   frame = (vki_sigframe_t*)sp;
+   /* Set a bogus return address. */
+   frame->return_addr = (void*)~0UL;
+   frame->a1_signo = rec_signo;
+   /* The first parameter has to be 16-byte aligned, resembling a function
+      call. */
+   {
+      /* Using
+         vg_assert(VG_IS_16_ALIGNED(&frame->a1_signo));
+         seems to get miscompiled on amd64 with GCC 4.7.2. */
+      Addr signo_addr = (Addr)&frame->a1_signo;
+      vg_assert(VG_IS_16_ALIGNED(signo_addr));
+   }
+   frame->a2_siginfo = &frame->siginfo;
+   frame->siginfo = *info;
+   frame->ucontext = *uc;
+
+#  if defined(VGP_x86_solaris)
+   frame->a3_ucontext = &frame->ucontext;
+
+   /* Switch onto the V stack and restart the signal processing. */
+   __asm__ __volatile__(
+      "xorl %%ebp, %%ebp\n"
+      "movl %[sp], %%esp\n"
+      "jmp async_signalhandler\n"
+      :
+      : [sp] "a" (sp)
+      : /*"ebp"*/);
+
+#  elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__(
+      "xorq %%rbp, %%rbp\n"
+      "movq %[sp], %%rsp\n"
+      "jmp async_signalhandler\n"
+      :
+      : [sp] "a" (sp), "D" (rec_signo), "S" (&frame->siginfo),
+        "d" (&frame->ucontext)
+      : /*"rbp"*/);
+#  else
+#    error "Unknown platform"
+#  endif
+
+   /* We should never get here. */
+   vg_assert(0);
+
+#  undef RECURSION_BIT
+}
+#endif
+
 /* 
    Receive an async signal from the kernel.
 
@@ -2183,8 +2397,13 @@
    ThreadState* tst = VG_(get_ThreadState)(tid);
    SysRes       sres;
 
-   /* The thread isn't currently running, make it so before going on */
    vg_assert(tst->status == VgTs_WaitSys);
+
+#  if defined(VGO_solaris)
+   async_signalhandler_solaris_preprocess(tid, &sigNo, info, uc);
+#  endif
+
+   /* The thread isn't currently running, make it so before going on */
    VG_(acquire_BigLock)(tid, "async_signalhandler");
 
    info->si_code = sanitize_si_code(info->si_code);
@@ -2234,7 +2453,8 @@
       tid, 
       VG_UCONTEXT_INSTR_PTR(uc), 
       sres,  
-      !!(scss.scss_per_sig[sigNo].scss_flags & VKI_SA_RESTART)
+      !!(scss.scss_per_sig[sigNo].scss_flags & VKI_SA_RESTART),
+      uc
    );
 
    /* (2) */
@@ -2345,7 +2565,13 @@
       of a faulting instruction), then how we treat it depends on when it
       arrives... */
 
-   if (VG_(threads)[tid].status == VgTs_WaitSys) {
+   if (VG_(threads)[tid].status == VgTs_WaitSys
+#     if defined(VGO_solaris)
+      /* Check if the signal was really received while doing a blocking
+         syscall.  Only then the async_signalhandler() path can be used. */
+       && VG_(is_ip_in_blocking_syscall)(tid, VG_UCONTEXT_INSTR_PTR(uc))
+#     endif
+         ) {
       /* Signal arrived while we're blocked in a syscall.  This means that
          the client's signal mask was applied.  In other words, so we can't
          get here unless the client wants this signal right now.  This means
@@ -2605,6 +2831,11 @@
    } else {
       sync_signalhandler_from_kernel(tid, sigNo, info, uc);
    }
+
+#  if defined(VGO_solaris)
+   /* On Solaris we have to return from signal handler manually. */
+   VG_(do_syscall2)(__NR_context, VKI_SETCONTEXT, (UWord)uc);
+#  endif
 }
 
 
@@ -2653,7 +2884,8 @@
    VG_(printf)("pp_ksigaction: handler %p, flags 0x%x, restorer %p\n", 
                sa->ksa_handler, 
                (UInt)sa->sa_flags, 
-#              if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#              if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+                  !defined(VGO_solaris)
                   sa->sa_restorer
 #              else
                   (void*)0
@@ -2675,7 +2907,8 @@
 
    sa.ksa_handler = VKI_SIG_DFL;
    sa.sa_flags = 0;
-#  if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#  if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+      !defined(VGO_solaris)
    sa.sa_restorer = 0;
 #  endif
    VG_(sigemptyset)(&sa.sa_mask);
@@ -2777,7 +3010,8 @@
 
 	 tsa.ksa_handler = (void *)sync_signalhandler;
 	 tsa.sa_flags = VKI_SA_SIGINFO;
-#        if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#        if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+            !defined(VGO_solaris)
 	 tsa.sa_restorer = 0;
 #        endif
 	 VG_(sigfillset)(&tsa.sa_mask);
@@ -2804,7 +3038,8 @@
       scss.scss_per_sig[i].scss_mask     = sa.sa_mask;
 
       scss.scss_per_sig[i].scss_restorer = NULL;
-#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
+#     if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \
+         !defined(VGO_solaris)
       scss.scss_per_sig[i].scss_restorer = sa.sa_restorer;
 #     endif
 
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index aca2d20..005765a 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -92,7 +92,8 @@
    
 /* ------------------------ x86 ------------------------- */
 
-#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \
+    || defined(VGP_x86_solaris)
 
 #define N_FP_CF_VERIF 1021
 // prime number so that size of fp_CF_verif is just below 4K or 8K
@@ -234,10 +235,18 @@
    /* vg_assert(fp_min <= fp_max);*/
    // On Darwin, this kicks in for pthread-related stack traces, so they're
    // only 1 entry long which is wrong.
-#  if !defined(VGO_darwin)
+#  if defined(VGO_linux)
    if (fp_min + 512 >= fp_max) {
       /* If the stack limits look bogus, don't poke around ... but
          don't bomb out either. */
+#  elif defined(VGO_solaris)
+   if (fp_max == 0) {
+      /* VG_(get_StackTrace)() can be called by tools very early when
+         various tracing options are enabled. Don't proceed further
+         if the stack limits look bogus.
+       */
+#  endif
+#  if defined(VGO_linux) || defined(VGO_solaris)
       if (sps) sps[0] = uregs.xsp;
       if (fps) fps[0] = uregs.xbp;
       ips[0] = uregs.xip;
@@ -473,7 +482,8 @@
 
 /* ----------------------- amd64 ------------------------ */
 
-#if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
+#if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \
+    || defined(VGP_amd64_solaris)
 
 UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
                                /*OUT*/Addr* ips, UInt max_n_ips,
@@ -518,10 +528,19 @@
    /* vg_assert(fp_min <= fp_max);*/
    // On Darwin, this kicks in for pthread-related stack traces, so they're
    // only 1 entry long which is wrong.
-#  if !defined(VGO_darwin)
+#  if defined(VGO_linux)
    if (fp_min + 256 >= fp_max) {
       /* If the stack limits look bogus, don't poke around ... but
          don't bomb out either. */
+#  elif defined(VGO_solaris)
+   if (fp_max == 0) {
+      /* VG_(get_StackTrace)() can be called by tools very early when
+         various tracing options are enabled. Don't proceed further
+         if the stack limits look bogus.
+       */
+#  endif
+#  if defined(VGO_linux) || defined(VGO_solaris)
+
       if (sps) sps[0] = uregs.xsp;
       if (fps) fps[0] = uregs.xbp;
       ips[0] = uregs.xip;
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index 3c71623..8cc0564 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -297,6 +297,51 @@
 }
 
 
+#elif defined(VGO_solaris)
+
+/* Generic constructors. */
+SysRes VG_(mk_SysRes_Error) ( UWord err ) {
+   SysRes r;
+   r._val     = err;
+   r._val2    = 0;
+   r._isError = True;
+   return r;
+}
+
+SysRes VG_(mk_SysRes_Success) ( UWord res ) {
+   SysRes r;
+   r._val     = res;
+   r._val2    = 0;
+   r._isError = False;
+   return r;
+}
+
+SysRes VG_(mk_SysRes_x86_solaris) ( Bool isErr, UInt val, UInt val2 )
+{
+   SysRes res;
+
+   // stay sane
+   vg_assert(isErr == True || isErr == False);
+
+   res._val  = val;
+   res._val2 = val2;
+   res._isError = isErr;
+   return res;
+}
+
+SysRes VG_(mk_SysRes_amd64_solaris) ( Bool isErr, ULong val, ULong val2 )
+{
+   SysRes res;
+
+   // stay sane
+   vg_assert(isErr == True || isErr == False);
+
+   res._val  = val;
+   res._val2 = val2;
+   res._isError = isErr;
+   return res;
+}
+
 #else
 #  error "Unknown OS"
 #endif
@@ -804,6 +849,93 @@
     ".previous\n"
     );
 
+#elif defined(VGP_x86_solaris)
+
+extern ULong
+do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* 4(esp)..12(esp) */
+               UWord a4, UWord a5, UWord a6,    /* 16(esp)..24(esp) */
+               UWord a7, UWord a8,              /* 28(esp)..32(esp) */
+               UWord syscall_no,                /* 36(esp) */
+               /*OUT*/UInt *errflag);           /* 40(esp) */
+/* Classic unix syscall.. parameters on the stack, an unused (by the kernel)
+   return address at 0(esp), a sysno in eax, a result in edx:eax, the carry
+   flag set on error. */
+__asm__ (
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+"       movl    40(%esp), %ecx\n"       /* assume syscall success */
+"       movl    $0, (%ecx)\n"
+"       movl    36(%esp), %eax\n"
+"       int     $0x91\n"
+"       jnc     1f\n"                   /* jump if success */
+"       movl    40(%esp), %ecx\n"       /* syscall failed - set *errflag */
+"       movl    $1, (%ecx)\n"
+"1:     ret\n"
+".previous\n"
+);
+
+extern ULong
+do_syscall_fast_WRK(UWord syscall_no);          /* 4(esp) */
+/* Fasttrap syscall.. no parameters, a sysno in eax, a result in edx:eax,
+   never fails (if the sysno is valid). */
+__asm__ (
+".text\n"
+".globl do_syscall_fast_WRK\n"
+"do_syscall_fast_WRK:\n"
+"       movl    4(%esp), %eax\n"
+"       int     $0xD2\n"
+"       ret\n"
+".previous\n"
+);
+
+#elif defined(VGP_amd64_solaris)
+
+extern ULong
+do_syscall_WRK(UWord a1, UWord a2, UWord a3,    /* rdi, rsi, rdx */
+               UWord a4, UWord a5, UWord a6,    /* rcx, r8, r9 */
+               UWord a7, UWord a8,              /* 8(rsp), 16(rsp) */
+               UWord syscall_no,                /* 24(rsp) */
+               /*OUT*/ULong *errflag,           /* 32(rsp) */
+               /*OUT*/ULong *res2);             /* 40(rsp) */
+/* First 6 parameters in registers rdi, rsi, rdx, r10, r8, r9, next
+   2 parameters on the stack, an unused (by the kernel) return address at
+   0(rsp), a sysno in rax, a result in rdx:rax, the carry flag set on
+   error. */
+__asm__ (
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+"       movq    %rcx, %r10\n"           /* pass rcx in r10 instead */
+"       movq    32(%rsp), %rcx\n"       /* assume syscall success */
+"       movq    $0, (%rcx)\n"
+"       movq    24(%rsp), %rax\n"
+"       syscall\n"
+"       jnc     1f\n"                   /* jump if success */
+"       movq    32(%rsp), %rcx\n"       /* syscall failed - set *errflag */
+"       movq    $1, (%rcx)\n"
+"1:     movq    40(%rsp), %rcx\n"       /* save 2nd result word */
+"       movq    %rdx, (%rcx)\n"
+"       ret\n"
+".previous\n"
+);
+
+extern ULong
+do_syscall_fast_WRK(UWord syscall_no,           /* rdi */
+                    /*OUT*/ULong *res2);        /* rsi */
+/* Fasttrap syscall.. no parameters, a sysno in rax, a result in rdx:rax,
+   never fails (if the sysno is valid). */
+__asm__ (
+".text\n"
+".globl do_syscall_fast_WRK\n"
+"do_syscall_fast_WRK:\n"
+"       movq    %rdi, %rax\n"
+"       int     $0xD2\n"
+"       movq    %rdx, (%rsi)\n"         /* save 2nd result word */
+"       ret\n"
+".previous\n"
+);
+
 #else
 #  error Unknown platform
 #endif
@@ -937,6 +1069,62 @@
 
    return VG_(mk_SysRes_tilegx_linux)( val );
 
+#  elif defined(VGP_x86_solaris)
+   UInt val, val2, err = False;
+   Bool restart;
+   ULong u64;
+   UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
+
+   switch (ssclass) {
+      case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
+         /* The Solaris kernel does not restart syscalls automatically so it
+            is done here. */
+         do {
+            u64 = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+                                 VG_SOLARIS_SYSNO_INDEX(sysno), &err);
+            val = (UInt)u64;
+            restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
+         } while (restart);
+         break;
+      case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
+         u64 = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno));
+         break;
+      default:
+         vg_assert(0);
+         break;
+   }
+
+   val = (UInt)u64;
+   val2 = (UInt)(u64 >> 32);
+   return VG_(mk_SysRes_x86_solaris)(err ? True : False, val,
+                                     err ? 0 : val2);
+
+#  elif defined(VGP_amd64_solaris)
+   ULong val, val2, err = False;
+   Bool restart;
+   UChar ssclass = VG_SOLARIS_SYSNO_CLASS(sysno);
+
+   switch (ssclass) {
+      case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
+         /* The Solaris kernel does not restart syscalls automatically so it
+            is done here. */
+         do {
+            val = do_syscall_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+                                 VG_SOLARIS_SYSNO_INDEX(sysno), &err, &val2);
+            restart = err && (val == VKI_EINTR || val == VKI_ERESTART);
+         } while (restart);
+         break;
+      case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
+         val = do_syscall_fast_WRK(VG_SOLARIS_SYSNO_INDEX(sysno), &val2);
+         break;
+      default:
+         vg_assert(0);
+         break;
+   }
+
+   return VG_(mk_SysRes_amd64_solaris)(err ? True : False, val,
+                                       err ? 0 : val2);
+
 #else
 #  error Unknown platform
 #endif
diff --git a/coregrind/m_syswrap/priv_syswrap-generic.h b/coregrind/m_syswrap/priv_syswrap-generic.h
index f014914..6dbcf12 100644
--- a/coregrind/m_syswrap/priv_syswrap-generic.h
+++ b/coregrind/m_syswrap/priv_syswrap-generic.h
@@ -51,7 +51,7 @@
 /* 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 );
+extern Bool ML_(safe_to_deref) ( const void *start, SizeT size );
 
 // Returns True if the signal is OK for the client to use.
 extern Bool ML_(client_signal_OK)(Int sigNo);
@@ -61,11 +61,18 @@
 Bool ML_(fd_allowed)(Int fd, const HChar *syscallname, ThreadId tid,
                      Bool isNewFD);
 
+extern void ML_(record_fd_close)               (Int fd);
 extern void ML_(record_fd_open_named)          (ThreadId tid, Int fd);
 extern void ML_(record_fd_open_nameless)       (ThreadId tid, Int fd);
 extern void ML_(record_fd_open_with_given_name)(ThreadId tid, Int fd,
                                                 const HChar *pathname);
 
+// Return true if a given file descriptor is already recorded.
+extern Bool ML_(fd_recorded)(Int fd);
+// Returns a pathname representing a recorded fd.
+// Returned string must not be modified nor free'd.
+extern const HChar *ML_(find_fd_recorded_by_fd)(Int fd);
+
 // Used when killing threads -- we must not kill a thread if it's the thread
 // that would do Valgrind's final cleanup and output.
 extern
@@ -94,6 +101,12 @@
 extern 
 void ML_(POST_unknown_ioctl)(ThreadId tid, UInt res, UWord request, UWord arg);
 
+extern
+void ML_(pre_argv_envp)(Addr a, ThreadId tid, const HChar *s1, const HChar *s2);
+
+extern Bool
+ML_(handle_auxv_open)(SyscallStatus *status, const HChar *filename,
+                      int flags);
 
 DECL_TEMPLATE(generic, sys_ni_syscall);            // * P -- unimplemented
 DECL_TEMPLATE(generic, sys_exit);
diff --git a/coregrind/m_syswrap/priv_syswrap-solaris.h b/coregrind/m_syswrap/priv_syswrap-solaris.h
new file mode 100644
index 0000000..1ea0aa8
--- /dev/null
+++ b/coregrind/m_syswrap/priv_syswrap-solaris.h
@@ -0,0 +1,92 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Solaris-specific syscalls stuff.      priv_syswrap-solaris.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2014 Petr Pavlu
+      setup@dagobah.cz
+
+   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 __PRIV_SYSWRAP_SOLARIS_H
+#define __PRIV_SYSWRAP_SOLARIS_H
+
+#include "pub_core_basics.h"        // VG_ macro
+#include "priv_types_n_macros.h"    // DECL_TEMPLATE
+#include "pub_core_tooliface.h"     // CorePart
+
+/* Macro to join a syscall name with a syscall variant. */
+#define SC2(name, subname) \
+   name "_" subname
+
+/* Macro to join a syscall name with its variant and sub-variant. */
+#define SC3(name, subname, subsubname) \
+   name "_" subname "_" subsubname
+
+extern void ML_(call_on_new_stack_0_1)(Addr stack, Addr retaddr,
+                                       void (*f)(Word), Word arg1);
+extern Word ML_(start_thread_NORETURN)(void *arg);
+extern Addr ML_(allocstack)           (ThreadId tid);
+extern void ML_(setup_start_thread_context)(ThreadId tid, vki_ucontext_t *uc);
+
+extern UInt ML_(fletcher32)(UShort *buf, SizeT blocks);
+extern ULong ML_(fletcher64)(UInt *buf, SizeT blocks);
+extern void ML_(save_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                                      CorePart part);
+extern void ML_(restore_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                                         CorePart part, Bool esp_is_thrptr);
+
+#if defined(VGP_x86_solaris)
+
+extern void ML_(setup_gdt)(VexGuestX86State *vex);
+extern void ML_(cleanup_gdt)(VexGuestX86State *vex);
+extern void ML_(update_gdt_lwpgs)(ThreadId tid);
+
+/* prototypes */
+DECL_TEMPLATE(x86_solaris, sys_fstatat64);
+DECL_TEMPLATE(x86_solaris, sys_openat64);
+DECL_TEMPLATE(x86_solaris, sys_llseek32);
+DECL_TEMPLATE(x86_solaris, sys_mmap64);
+DECL_TEMPLATE(x86_solaris, sys_stat64);
+DECL_TEMPLATE(x86_solaris, sys_lstat64);
+DECL_TEMPLATE(x86_solaris, sys_fstat64);
+DECL_TEMPLATE(x86_solaris, sys_statvfs64);
+DECL_TEMPLATE(x86_solaris, sys_fstatvfs64);
+DECL_TEMPLATE(x86_solaris, sys_setrlimit64);
+DECL_TEMPLATE(x86_solaris, sys_getrlimit64);
+DECL_TEMPLATE(x86_solaris, sys_pread64);
+DECL_TEMPLATE(x86_solaris, sys_pwrite64);
+DECL_TEMPLATE(x86_solaris, sys_open64);
+
+#elif defined(VGP_amd64_solaris)
+/* Nothing yet. */
+
+#else
+#  error "Unknown platform"
+#endif
+
+#endif   // __PRIV_SYSWRAP_SOLARIS_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h
index 26a82f7..16576d5 100644
--- a/coregrind/m_syswrap/priv_types_n_macros.h
+++ b/coregrind/m_syswrap/priv_types_n_macros.h
@@ -112,7 +112,7 @@
       Int s_arg6;
       Int uu_arg7;
       Int uu_arg8;
-#     elif defined(VGP_x86_darwin)
+#     elif defined(VGP_x86_darwin) || defined(VGP_x86_solaris)
       Int s_arg1;
       Int s_arg2;
       Int s_arg3;
@@ -121,7 +121,7 @@
       Int s_arg6;
       Int s_arg7;
       Int s_arg8;
-#     elif defined(VGP_amd64_darwin)
+#     elif defined(VGP_amd64_darwin) || defined(VGP_amd64_solaris)
       Int o_arg1;
       Int o_arg2;
       Int o_arg3;
@@ -203,6 +203,10 @@
 extern const SyscallTableEntry ML_(syscall_table)[];
 extern const UInt ML_(syscall_table_size);
 
+#elif defined(VGO_solaris)
+extern
+SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno );
+
 #else
 #  error Unknown OS
 #endif   
@@ -281,7 +285,7 @@
     vgSysWrap_##auxstr##_##name##_after
 
 /* Add a generic wrapper to a syscall table. */
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 #  define GENX_(sysno, name)  WRAPPER_ENTRY_X_(generic, sysno, name)
 #  define GENXY(sysno, name)  WRAPPER_ENTRY_XY(generic, sysno, name)
 #elif defined(VGO_darwin)
@@ -331,7 +335,7 @@
    return sr_Res(st->sres);
 }
 
-#if defined(VGO_darwin)
+#if defined(VGO_darwin) || defined(VGO_solaris)
 static inline UWord getRESHI ( SyscallStatus* st ) {
    vg_assert(st->what == SsComplete);
    vg_assert(!sr_isError(st->sres));
@@ -403,7 +407,7 @@
 #  define PRA5(s,t,a) PRRAn(5,s,t,a)
 #  define PRA6(s,t,a) PRRAn(6,s,t,a)
 
-#elif defined(VGP_x86_darwin)
+#elif defined(VGP_x86_darwin) || defined(VGP_x86_solaris)
    /* Up to 8 parameters, all on the stack. */
 #  define PRA1(s,t,a) PSRAn(1,s,t,a)
 #  define PRA2(s,t,a) PSRAn(2,s,t,a)
@@ -414,7 +418,7 @@
 #  define PRA7(s,t,a) PSRAn(7,s,t,a)
 #  define PRA8(s,t,a) PSRAn(8,s,t,a)
 
-#elif defined(VGP_amd64_darwin)
+#elif defined(VGP_amd64_darwin) || defined(VGP_amd64_solaris)
    /* Up to 8 parameters, 6 in registers, 2 on the stack. */
 #  define PRA1(s,t,a) PRRAn(1,s,t,a)
 #  define PRA2(s,t,a) PRRAn(2,s,t,a)
diff --git a/coregrind/m_syswrap/syscall-amd64-solaris.S b/coregrind/m_syswrap/syscall-amd64-solaris.S
new file mode 100644
index 0000000..f205223
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-amd64-solaris.S
@@ -0,0 +1,278 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls.      syscall-amd64-solaris.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2014-2014 Petr Pavlu
+     setup@dagobah.cz
+
+  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.
+*/
+
+#if defined(VGP_amd64_solaris)
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums_asm.h"
+#include "libvex_guest_offsets.h"
+
+/* From vki-solaris.h, checked at startup by m_vki.c. */
+#define VKI_SIG_SETMASK 3
+
+/* Prototype:
+   Int ML_(do_syscall_for_client_WRK)(
+      Int syscallno,			// %rdi = %rbp-48
+      void *guest_state,		// %rsi = %rbp-40
+      const vki_sigset_t *sysmask,	// %rdx = %rbp-32
+      const vki_sigset_t *postmask,	// %rcx = %rbp-24
+      UChar *cflag)			// %r8 = %rbp-16
+*/
+
+.macro ESTABLISH_STACKFRAME
+	/* Establish stack frame. */
+	pushq	%rbp
+	movq	%rsp, %rbp
+	pushq	%rbx				/* save %rbx */
+
+	/* We'll use %rbx instead of %rbp to address the stack frame after the
+	   door syscall is finished because %rbp is cleared by the syscall. */
+	movq	%rsp, %rbx			/* %rbx = %rbp - 8 */
+
+	/* Push the parameters on the stack. */
+	pushq	%r8				/* store %r8 at %rbp-16 */
+	pushq	%rcx				/* store %rcx at %rbp-24 */
+	pushq	%rdx				/* store %rdx at %rbp-32 */
+	pushq	%rsi				/* store %rsi at %rbp-40 */
+	pushq	%rdi				/* store %rdi at %rbp-48 */
+.endm
+
+.macro UNBLOCK_SIGNALS
+	/* Set the signal mask which should be current during the syscall. */
+	/* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
+	movq	-24(%rbp), %rdx
+	movq	-32(%rbp), %rsi
+	movq	$VKI_SIG_SETMASK, %rdi
+	movq	$__NR_sigprocmask, %rax
+	syscall
+	jc	sigprocmask_failed		/* sigprocmask failed */
+.endm
+
+.macro REBLOCK_SIGNALS
+	/* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
+	movq	$0, %rdx
+	movq	-24(%rbp), %rsi
+	movq	$VKI_SIG_SETMASK, %rdi
+	movq	$__NR_sigprocmask, %rax
+	syscall
+	/* The syscall above changes the carry flag.  This means that if the
+	   syscall fails and we receive an interrupt after it then we've got
+	   an invalid carry flag value in the fixup code.  We don't care about
+	   it because this syscall should never fail and if it does then we're
+	   going to stop Valgrind anyway. */
+	jc	sigprocmask_failed		/* sigprocmask failed */
+.endm
+
+.macro SIMPLE_RETURN
+	xorq	%rax, %rax			/* SUCCESS */
+	movq	-8(%rbp), %rbx			/* restore %rbx */
+	movq	%rbp, %rsp
+	popq	%rbp
+	ret
+.endm
+
+sigprocmask_failed:
+	/* Failure: return 0x8000 | error code. */
+	andq	$0x7FFF, %rax
+	orq	$0x8000, %rax
+	movq	-8(%rbp), %rbx			/* restore %rbx */
+	movq	%rbp, %rsp
+	popq	%rbp
+	ret
+
+.globl ML_(do_syscall_for_client_WRK)
+ML_(do_syscall_for_client_WRK):
+	ESTABLISH_STACKFRAME
+
+1:	/* Even though we can't take a signal until the sigprocmask completes,
+	   start the range early.  If %rip is in the range [1, 2), the syscall
+	   hasn't been started yet. */
+	UNBLOCK_SIGNALS
+
+	/* Copy syscall parameters. */
+	/* do_syscall8 */
+	/* 6 register parameters. */
+	movq	-40(%rbp), %rax
+	movq	OFFSET_amd64_RDI(%rax), %rdi
+	movq	OFFSET_amd64_RSI(%rax), %rsi
+	movq	OFFSET_amd64_RDX(%rax), %rdx
+	movq	OFFSET_amd64_R10(%rax), %r10
+	movq	OFFSET_amd64_R8(%rax), %r8
+	movq	OFFSET_amd64_R9(%rax), %r9
+	/* 2 stack parameters. */
+	movq	OFFSET_amd64_RSP(%rax), %rax
+	movq	16(%rax), %r11
+	pushq	%r11
+	movq	8(%rax), %r11
+	pushq	%r11
+	/* Return address. */
+	movq	0(%rax), %r11
+	pushq	%r11
+
+	/* Put syscall number in %rax. */
+	movq	-48(%rbp), %rax
+
+	/* Do the syscall.  Note that the Solaris kernel doesn't directly
+	   restart syscalls! */
+	syscall
+
+2:	/* In the range [2, 3), the syscall result is in %rax and %rdx and C,
+	   but hasn't been committed to the thread state.  If we get
+	   interrupted in this section then we'll just use values saved in the
+	   ucontext structure.
+
+	   Important note for this and the following section: Don't add here
+	   any code that alters the carry flag or worse, call any function.
+	   That would completely break the fixup after an interrupt. */
+	movq	-40(%rbp), %rcx
+	movq	%rax, OFFSET_amd64_RAX(%rcx)	/* save %rax to VEX */
+	movq	%rdx, OFFSET_amd64_RDX(%rcx)	/* save %rdx to VEX */
+	movq	-16(%rbp), %rcx
+	setc	0(%rcx)				/* save returned carry flag */
+
+3:	/* Re-block signals. If %rip is in [3, 4), then the syscall is
+	   complete and we do not need to worry about it.  We have to only
+	   correctly save the carry flag.  If we get interrupted in this
+	   section then we just have to propagate the carry flag from the
+	   ucontext structure to the thread state, %rax and %rdx values are
+	   already saved. */
+	REBLOCK_SIGNALS
+
+4:	/* Now safe from signals. */
+	SIMPLE_RETURN
+
+.section .rodata
+/* Export the ranges so that
+   VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
+
+.globl ML_(blksys_setup)
+.globl ML_(blksys_complete)
+.globl ML_(blksys_committed)
+.globl ML_(blksys_finished)
+ML_(blksys_setup):	.quad 1b
+ML_(blksys_complete):	.quad 2b
+ML_(blksys_committed):	.quad 3b
+ML_(blksys_finished):	.quad 4b
+.previous
+
+/* Prototype:
+   Int ML_(do_syscall_for_client_dret_WRK)(
+      Int syscallno,			// %rdi = %rbp-48 = %rbx-48+8
+      void *guest_state,		// %rsi = %rbp-40 = %rbx-40+8
+      const vki_sigset_t *sysmask,	// %rdx = %rbp-32 = %rbx-32+8
+      const vki_sigset_t *postmask,	// %rcx = %rbp-24 = %rbx-24+8
+      UChar *cflag)			// %r8 = %rbp-16 = %rbx-16+8
+*/
+
+/* Door_return is a very special call because the data are stored by the
+   kernel directly on the stack and the stack pointer is appropriately
+   modified by the kernel.  Therefore we switch to the client stack before
+   doing the syscall, this is relatively trivial but an extra care has to be
+   taken when we get interrupted at some point. */
+
+.globl ML_(do_syscall_for_client_dret_WRK)
+ML_(do_syscall_for_client_dret_WRK):
+	ESTABLISH_STACKFRAME
+
+1:	/* Even though we can't take a signal until the sigprocmask completes,
+	   start the range early.  If %rip is in the range [1, 2), the syscall
+	   hasn't been started yet. */
+	UNBLOCK_SIGNALS
+
+	/* Prepare 6 register parameters. */
+	movq	-40(%rbp), %rax
+	movq	OFFSET_amd64_RDI(%rax), %rdi
+	movq	OFFSET_amd64_RSI(%rax), %rsi
+	movq	OFFSET_amd64_RDX(%rax), %rdx
+	movq	OFFSET_amd64_R10(%rax), %r10
+	movq	OFFSET_amd64_R8(%rax), %r8
+	movq	OFFSET_amd64_R9(%rax), %r9
+
+	/* Switch to the client stack. */
+	movq	OFFSET_amd64_RSP(%rax), %rsp	/* %rsp = simulated RSP */
+	/* Change %rbp to a client value. It will always get committed by
+	   the fixup code for range [2, 3) so it needs to be set to what the
+	   client expects. */
+	movq	OFFSET_amd64_RBP(%rax), %rbp	/* %rbp = simulated RBP */
+
+	/* Put syscall number in %rax. */
+	movq	-48+8(%rbx), %rax
+
+	/* Do the syscall.  Note that the Solaris kernel doesn't directly
+	   restart syscalls! */
+	syscall
+
+2:	/* In the range [2, 3), the syscall result is in %rax, %rdx, %rsp and
+	   %rbp and C, but hasn't been committed to the thread state.  If we
+	   get interrupted in this section then we'll just use values saved in
+	   the ucontext structure.
+
+	   Important note for this and the following section: Don't add here
+	   any code that alters the carry flag or worse, call any function.
+	   That would completely break the fixup after an interrupt. */
+	movq	-40+8(%rbx), %rcx
+	movq	%rax, OFFSET_amd64_RAX(%rcx)	/* save %rax to VEX */
+	movq	%rdx, OFFSET_amd64_RDX(%rcx)	/* save %rdx to VEX */
+	movq	%rsp, OFFSET_amd64_RSP(%rcx)	/* save %rsp to VEX */
+	movq	%rbp, OFFSET_amd64_RBP(%rcx)	/* save %rbp to VEX */
+	movq	-16+8(%rbx), %rcx
+	setc	0(%rcx)				/* save returned carry flag */
+
+	movq	%rbx, %rsp			/* switch to V stack */
+
+3:	/* Re-block signals. If %rip is in [3, 4), then the syscall is
+	   complete and we do not need worry about it.  We have to only
+	   correctly save the carry flag.  If we get interrupted in this
+	   section then we just have to propagate the carry flag from the
+	   ucontext structure to the thread state, %rax, %rdx, %rsp and %rbp
+	   values are already saved. */
+	movq	%rbx, %rbp
+	addq	$8, %rbp
+	REBLOCK_SIGNALS
+
+4:	/* Now safe from signals. */
+	SIMPLE_RETURN
+
+.section .rodata
+.globl ML_(blksys_setup_DRET)
+.globl ML_(blksys_complete_DRET)
+.globl ML_(blksys_committed_DRET)
+.globl ML_(blksys_finished_DRET)
+ML_(blksys_setup_DRET):		.quad 1b
+ML_(blksys_complete_DRET):	.quad 2b
+ML_(blksys_committed_DRET):	.quad 3b
+ML_(blksys_finished_DRET):	.quad 4b
+.previous
+
+#endif // defined(VGP_amd64_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-x86-solaris.S b/coregrind/m_syswrap/syscall-x86-solaris.S
new file mode 100644
index 0000000..cb4346f
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-x86-solaris.S
@@ -0,0 +1,275 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls.        syscall-x86-solaris.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2011-2014 Petr Pavlu
+     setup@dagobah.cz
+
+  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.
+*/
+
+#if defined(VGP_x86_solaris)
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums_asm.h"
+#include "libvex_guest_offsets.h"
+
+/* From vki-solaris.h, checked at startup by m_vki.c. */
+#define VKI_SIG_SETMASK 3
+
+/* Prototype:
+   Int ML_(do_syscall_for_client_WRK)(
+      Int syscallno,			// %ebp+8
+      void *guest_state,		// %ebp+12
+      const vki_sigset_t *sysmask,	// %ebp+16
+      const vki_sigset_t *postmask,	// %ebp+20
+      UChar *cflag)			// %ebp+24
+*/
+
+.macro ESTABLISH_STACKFRAME
+	/* Establish stack frame. */
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%ebx				/* save %ebx */
+
+	/* We'll use %ebx instead of %ebp to address the stack frame after the
+	   door syscall is finished because %ebp is cleared by the syscall. */
+	movl	%esp, %ebx			/* %ebx = %ebp - 4 */
+.endm
+
+.macro UNBLOCK_SIGNALS
+	/* Set the signal mask which should be current during the syscall. */
+	/* Set up for sigprocmask(SIG_SETMASK, sysmask, postmask). */
+	pushl	20(%ebp)
+	pushl	16(%ebp)
+	pushl	$VKI_SIG_SETMASK
+	pushl	$0xcafebabe			/* totally fake return address */
+	movl	$__NR_sigprocmask, %eax
+	int	$0x91
+	jc	sigprocmask_failed		/* sigprocmask failed */
+	addl	$16, %esp
+.endm
+
+.macro REBLOCK_SIGNALS
+	/* Set up for sigprocmask(SIG_SETMASK, postmask, NULL). */
+	pushl	$0
+	pushl	20(%ebp)
+	pushl	$VKI_SIG_SETMASK
+	pushl	$0xcafef00d			/* totally fake return address */
+	movl	$__NR_sigprocmask, %eax
+	int	$0x91
+	/* The syscall above changes the carry flag.  This means that if the
+	   syscall fails and we receive an interrupt after it then we've got
+	   an invalid carry flag value in the fixup code.  We don't care about
+	   it because this syscall should never fail and if it does then we're
+	   going to stop Valgrind anyway. */
+	jc	sigprocmask_failed		/* sigprocmask failed */
+	addl	$16, %esp
+.endm
+
+.macro SIMPLE_RETURN
+	xorl	%eax, %eax			/* SUCCESS */
+	movl	-4(%ebp), %ebx			/* restore %ebx */
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+.endm
+
+sigprocmask_failed:
+	/* Failure: return 0x8000 | error code. */
+	/* Note that we enter here with %esp being 16 too low (4 extra words
+	   on the stack).  But because we're nuking the stack frame now, that
+	   doesn't matter. */
+	andl	$0x7FFF, %eax
+	orl	$0x8000, %eax
+	movl	-4(%ebp), %ebx			/* restore %ebx */
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+
+.globl ML_(do_syscall_for_client_WRK)
+ML_(do_syscall_for_client_WRK):
+	ESTABLISH_STACKFRAME
+
+1:	/* Even though we can't take a signal until the sigprocmask completes,
+	   start the range early.  If %eip is in the range [1, 2), the syscall
+	   hasn't been started yet. */
+	UNBLOCK_SIGNALS
+
+	/* Copy syscall parameters to the stack - assume no more than 8 plus
+	   the return address. */
+	/* do_syscall8 */
+	movl	12(%ebp), %edx
+	movl	OFFSET_x86_ESP(%edx), %edx	/* %edx = simulated ESP */
+	movl	28+4(%edx), %eax
+	pushl	%eax
+	movl	24+4(%edx), %eax
+	pushl	%eax
+	movl	20+4(%edx), %eax
+	pushl	%eax
+	movl	16+4(%edx), %eax
+	pushl	%eax
+	movl	12+4(%edx), %eax
+	pushl	%eax
+	movl	8+4(%edx), %eax
+	pushl	%eax
+	movl	4+4(%edx), %eax
+	pushl	%eax
+	movl	0+4(%edx), %eax
+	pushl	%eax
+	/* Return address. */
+	movl	0(%edx), %eax
+	pushl	%eax
+
+	/* Put syscall number in %eax. */
+	movl	8(%ebp), %eax
+
+	/* Do the syscall.  Note that the Solaris kernel doesn't directly
+	   restart syscalls! */
+	int	$0x91
+
+2:	/* In the range [2, 3), the syscall result is in %eax and %edx and C,
+	   but hasn't been committed to the thread state.  If we get
+	   interrupted in this section then we'll just use values saved in the
+	   ucontext structure.
+
+	   Important note for this and the following section: Don't add here
+	   any code that alters the carry flag or worse, call any function.
+	   That would completely break the fixup after an interrupt. */
+	movl	12(%ebp), %ecx
+	movl	%eax, OFFSET_x86_EAX(%ecx)	/* save %eax to VEX */
+	movl	%edx, OFFSET_x86_EDX(%ecx)	/* save %edx to VEX */
+	movl	24(%ebp), %ecx
+	setc	0(%ecx)				/* save returned carry flag */
+
+3:	/* Re-block signals. If %eip is in [3, 4), then the syscall is
+	   complete and we do not need to worry about it.  We have to only
+	   correctly save the carry flag.  If we get interrupted in this
+	   section then we just have to propagate the carry flag from the
+	   ucontext structure to the thread state, %eax and %edx values are
+	   already saved. */
+	REBLOCK_SIGNALS
+
+4:	/* Now safe from signals. */
+	SIMPLE_RETURN
+
+.section .rodata
+/* Export the ranges so that
+   VG_(fixup_guest_state_after_syscall_interrupted) can do the right thing. */
+
+.globl ML_(blksys_setup)
+.globl ML_(blksys_complete)
+.globl ML_(blksys_committed)
+.globl ML_(blksys_finished)
+ML_(blksys_setup):	.long 1b
+ML_(blksys_complete):	.long 2b
+ML_(blksys_committed):	.long 3b
+ML_(blksys_finished):	.long 4b
+.previous
+
+/* Prototype:
+   Int ML_(do_syscall_for_client_dret_WRK)(
+      Int syscallno,			// %ebp+8 = %ebx+8+4
+      void *guest_state,		// %ebp+12 = %ebx+12+4
+      const vki_sigset_t *sysmask,	// %ebp+16 = %ebx+16+4
+      const vki_sigset_t *postmask,	// %ebp+20 = %ebx+20+4
+      UChar *cflag)			// %ebp+24 = %ebx+24+4
+*/
+
+/* Door_return is a very special call because the data are stored by the
+   kernel directly on the stack and the stack pointer is appropriately
+   modified by the kernel.  Therefore we switch to the client stack before
+   doing the syscall, this is relatively trivial but an extra care has to be
+   taken when we get interrupted at some point. */
+
+.globl ML_(do_syscall_for_client_dret_WRK)
+ML_(do_syscall_for_client_dret_WRK):
+	ESTABLISH_STACKFRAME
+
+1:	/* Even though we can't take a signal until the sigprocmask completes,
+	   start the range early.  If %eip is in the range [1, 2), the syscall
+	   hasn't been started yet. */
+	UNBLOCK_SIGNALS
+
+	/* Switch to the client stack. */
+	movl	12(%ebp), %edx
+	movl	OFFSET_x86_ESP(%edx), %esp	/* %esp = simulated ESP */
+	/* Change %ebp to a client value. It will always get committed by
+	   the fixup code for range [2, 3) so it needs to be set to what the
+	   client expects. */
+	movl	OFFSET_x86_EBP(%edx), %ebp	/* %ebp = simulated EBP */
+
+	/* Put syscall number in %eax. */
+	movl	8+4(%ebx), %eax
+
+	/* Do the syscall.  Note that the Solaris kernel doesn't directly
+	   restart syscalls! */
+	int	$0x91
+
+2:	/* In the range [2, 3), the syscall result is in %eax, %edx, %esp and
+	   %ebp and C, but hasn't been committed to the thread state.  If we
+	   get interrupted in this section then we'll just use values saved in
+	   the ucontext structure.
+
+	   Important note for this and the following section: Don't add here
+	   any code that alters the carry flag or worse, call any function.
+	   That would completely break the fixup after an interrupt. */
+	movl	12+4(%ebx), %ecx
+	movl	%eax, OFFSET_x86_EAX(%ecx)	/* save %eax to VEX */
+	movl	%edx, OFFSET_x86_EDX(%ecx)	/* save %edx to VEX */
+	movl	%esp, OFFSET_x86_ESP(%ecx)	/* save %esp to VEX */
+	movl	%ebp, OFFSET_x86_EBP(%ecx)	/* save %ebp to VEX */
+	movl	24+4(%ebx), %ecx
+	setc	0(%ecx)				/* save returned carry flag */
+
+	movl	%ebx, %esp			/* switch to V stack */
+
+3:	/* Re-block signals. If %eip is in [3, 4), then the syscall is
+	   complete and we do not need worry about it.  We have to only
+	   correctly save the carry flag.  If we get interrupted in this
+	   section then we just have to propagate the carry flag from the
+	   ucontext structure to the thread state, %eax, %edx, %esp and %ebp
+	   values are already saved. */
+	movl	%ebx, %ebp
+	addl	$4, %ebp
+	REBLOCK_SIGNALS
+
+4:	/* Now safe from signals. */
+	SIMPLE_RETURN
+
+.section .rodata
+.globl ML_(blksys_setup_DRET)
+.globl ML_(blksys_complete_DRET)
+.globl ML_(blksys_committed_DRET)
+.globl ML_(blksys_finished_DRET)
+ML_(blksys_setup_DRET):		.long 1b
+ML_(blksys_complete_DRET):	.long 2b
+ML_(blksys_committed_DRET):	.long 3b
+ML_(blksys_finished_DRET):	.long 4b
+.previous
+
+#endif // defined(VGP_x86_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-amd64-solaris.c b/coregrind/m_syswrap/syswrap-amd64-solaris.c
new file mode 100644
index 0000000..2bc2cae
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-amd64-solaris.c
@@ -0,0 +1,564 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Platform-specific syscalls stuff.    syswrap-amd64-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2014-2014 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+#if defined(VGP_amd64_solaris)
+
+#include "libvex_guest_offsets.h"
+#include "pub_core_basics.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_vki.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_syswrap.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"
+#include "priv_syswrap-solaris.h"
+
+
+/* Call f(arg1), but first switch stacks, using 'stack' as the new stack, and
+   use 'retaddr' as f's return-to address.  Also, clear all the integer
+   registers before entering f. */
+__attribute__((noreturn))
+void ML_(call_on_new_stack_0_1)(Addr stack,             /* %rdi */
+                                Addr retaddr,           /* %rsi */
+                                void (*f)(Word),        /* %rdx */
+                                Word arg1);             /* %rcx */
+__asm__ (
+".text\n"
+".globl vgModuleLocal_call_on_new_stack_0_1\n"
+"vgModuleLocal_call_on_new_stack_0_1:\n"
+"   movq  %rdi, %rsp\n"         /* set stack */
+"   movq  %rcx, %rdi\n"         /* set arg1 */
+"   pushq %rsi\n"               /* retaddr to stack */
+"   pushq %rdx\n"               /* f to stack */
+"   movq  $0, %rax\n"           /* zero all GP regs (except %rdi) */
+"   movq  $0, %rbx\n"
+"   movq  $0, %rcx\n"
+"   movq  $0, %rdx\n"
+"   movq  $0, %rsi\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 f */
+"   ud2\n"                      /* should never get here */
+".previous\n"
+);
+
+/* This function is called to setup a context of a new Valgrind thread (which
+   will run the client code). */
+void ML_(setup_start_thread_context)(ThreadId tid, vki_ucontext_t *uc)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   UWord *stack = (UWord*)tst->os_state.valgrind_stack_init_SP;
+
+   VG_(memset)(uc, 0, sizeof(*uc));
+   uc->uc_flags = VKI_UC_CPU | VKI_UC_SIGMASK;
+
+   /* Start the thread with everything blocked. */
+   VG_(sigfillset)(&uc->uc_sigmask);
+
+   /* Set up the stack, it should be always 16-byte aligned before doing
+      a function call, i.e. the first parameter is also 16-byte aligned. */
+   vg_assert(VG_IS_16_ALIGNED(stack));
+   stack -= 1;
+   stack[0] = 0; /* bogus return value */
+
+   /* Set up the registers. */
+   uc->uc_mcontext.gregs[VKI_REG_RDI] = (UWord)tst; /* the parameter */
+   uc->uc_mcontext.gregs[VKI_REG_RIP] = (UWord)ML_(start_thread_NORETURN);
+   uc->uc_mcontext.gregs[VKI_REG_RSP] = (UWord)stack;
+}
+
+/* Architecture-specific part of VG_(save_context). */
+void ML_(save_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                               CorePart part)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_fpchip_state *fs
+      = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+   SizeT i;
+
+   /* CPU */
+   /* Common registers */
+   uc->uc_mcontext.gregs[VKI_REG_RIP] = tst->arch.vex.guest_RIP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RIP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RIP], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RAX] = tst->arch.vex.guest_RAX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RAX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RAX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RBX] = tst->arch.vex.guest_RBX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RBX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RCX] = tst->arch.vex.guest_RCX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RCX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RCX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RDX] = tst->arch.vex.guest_RDX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RDX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RBP] = tst->arch.vex.guest_RBP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RBP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBP], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RSI] = tst->arch.vex.guest_RSI;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RSI,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSI], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RDI] = tst->arch.vex.guest_RDI;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RDI,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDI], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R8] = tst->arch.vex.guest_R8;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R8,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R8], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R9] = tst->arch.vex.guest_R9;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R9,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R9], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R10] = tst->arch.vex.guest_R10;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R10,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R10], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R11] = tst->arch.vex.guest_R11;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R11,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R11], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R12] = tst->arch.vex.guest_R12;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R12,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R12], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R13] = tst->arch.vex.guest_R13;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R13,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R13], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R14] = tst->arch.vex.guest_R14;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R14,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R14], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_R15] = tst->arch.vex.guest_R15;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_R15,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_R15], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_RSP] = tst->arch.vex.guest_RSP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_amd64_RSP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSP], sizeof(UWord));
+
+   /* ERR and TRAPNO */
+   uc->uc_mcontext.gregs[VKI_REG_ERR] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_ERR], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_TRAPNO] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_TRAPNO], sizeof(UWord));
+
+   /* Segment registers */
+   /* Valgrind does not support moves from/to segment registers on AMD64.  The
+      values returned below are the ones that are set by the kernel when
+      a program is started. */
+   uc->uc_mcontext.gregs[VKI_REG_CS] = VKI_UCS_SEL;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_CS], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_DS] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_DS], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_SS] = VKI_UDS_SEL;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_SS], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_ES] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_ES], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_FS] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_FS], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_GS] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_GS], sizeof(UWord));
+
+   /* Segment bases */
+   uc->uc_mcontext.gregs[VKI_REG_FSBASE] = tst->arch.vex.guest_FS_CONST;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_FSBASE], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_REG_GSBASE] = 0;
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)&uc->uc_mcontext.gregs[VKI_REG_GSBASE], sizeof(UWord));
+
+   /* Handle rflags.  Refer to the x86-solaris variant of this code for
+      a detailed description. */
+   uc->uc_mcontext.gregs[VKI_REG_RFL] =
+      LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
+   VG_TRACK(post_mem_write, part, tid,
+         (Addr)&uc->uc_mcontext.gregs[VKI_REG_RFL], sizeof(UWord));
+   VKI_UC_GUEST_CC_OP(uc) = tst->arch.vex.guest_CC_OP;
+   VKI_UC_GUEST_CC_NDEP(uc) = tst->arch.vex.guest_CC_NDEP;
+   VKI_UC_GUEST_CC_DEP1(uc) = tst->arch.vex.guest_CC_DEP1;
+   VG_TRACK(copy_reg_to_mem, part, tid,
+            offsetof(VexGuestAMD64State, guest_CC_DEP1),
+            (Addr)&VKI_UC_GUEST_CC_DEP1(uc), sizeof(UWord));
+   VKI_UC_GUEST_CC_DEP2(uc) = tst->arch.vex.guest_CC_DEP2;
+   VG_TRACK(copy_reg_to_mem, part, tid,
+            offsetof(VexGuestAMD64State, guest_CC_DEP2),
+            (Addr)&VKI_UC_GUEST_CC_DEP2(uc), sizeof(UWord));
+   VKI_UC_GUEST_RFLAGS_NEG(uc) = ~uc->uc_mcontext.gregs[VKI_REG_RFL];
+   /* Calculate a checksum. */
+   {
+      ULong buf[5];
+      ULong checksum;
+
+      buf[0] = VKI_UC_GUEST_CC_OP(uc);
+      buf[1] = VKI_UC_GUEST_CC_NDEP(uc);
+      buf[2] = VKI_UC_GUEST_CC_DEP1(uc);
+      buf[3] = VKI_UC_GUEST_CC_DEP2(uc);
+      buf[4] = uc->uc_mcontext.gregs[VKI_REG_RFL];
+      checksum = ML_(fletcher64)((UInt*)&buf, sizeof(buf) / sizeof(UInt));
+      VKI_UC_GUEST_RFLAGS_CHECKSUM(uc) = checksum;
+   }
+
+   /* FPU */
+   /* The fpregset_t structure on amd64 follows the layout that is used by the
+      FXSAVE instruction, therefore it is only necessary to call a VEX
+      function that simulates this instruction. */
+   LibVEX_GuestAMD64_fxsave(&tst->arch.vex, (HWord)fs);
+
+   /* Control word */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->cw, sizeof(fs->cw));
+   /* Status word */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->sw, sizeof(fs->sw));
+   /* Compressed tag word */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->fctw, sizeof(fs->fctw));
+   /* Unused */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->__fx_rsvd,
+            sizeof(fs->__fx_rsvd));
+   vg_assert(fs->__fx_rsvd == 0);
+   /* Last x87 opcode */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->fop, sizeof(fs->fop));
+   vg_assert(fs->fop == 0);
+   /* Last x87 instruction pointer */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->rip, sizeof(fs->rip));
+   vg_assert(fs->rip == 0);
+   /* Last x87 data pointer */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->rdp, sizeof(fs->rdp));
+   vg_assert(fs->rdp == 0);
+   /* Media-instruction control and status register */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->mxcsr, sizeof(fs->mxcsr));
+   /* Supported features in MXCSR */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->mxcsr_mask,
+            sizeof(fs->mxcsr_mask));
+
+   /* ST registers */
+   for (i = 0; i < 8; i++) {
+      Addr addr = (Addr)&fs->st[i];
+      /* x87 uses 80b FP registers but VEX uses only 64b registers, thus we
+         have to lie here. :< */
+      VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+               guest_FPREG[i]), addr, sizeof(ULong));
+      VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+               guest_FPREG[i]), addr + 8, sizeof(UShort));
+   }
+
+   /* XMM registers */
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM0), (Addr)&fs->xmm[0], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM1), (Addr)&fs->xmm[1], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM2), (Addr)&fs->xmm[2], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM3), (Addr)&fs->xmm[3], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM4), (Addr)&fs->xmm[4], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM5), (Addr)&fs->xmm[5], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM6), (Addr)&fs->xmm[6], sizeof(U128));
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestAMD64State,
+            guest_YMM7), (Addr)&fs->xmm[7], sizeof(U128));
+
+   /* Status word (sw) at exception */
+   fs->status = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->status, sizeof(fs->status));
+
+   /* MXCSR at exception */
+   fs->xstatus = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->xstatus,
+            sizeof(fs->xstatus));
+}
+
+/* Architecture-specific part of VG_(restore_context). */
+void ML_(restore_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                                  CorePart part, Bool esp_is_thrptr)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_fpchip_state *fs
+      = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+
+   /* CPU */
+   if (uc->uc_flags & VKI_UC_CPU) {
+      /* Common registers */
+      tst->arch.vex.guest_RIP = uc->uc_mcontext.gregs[VKI_REG_RIP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RIP], OFFSET_amd64_RIP,
+               sizeof(UWord));
+      tst->arch.vex.guest_RAX = uc->uc_mcontext.gregs[VKI_REG_RAX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RAX], OFFSET_amd64_RAX,
+               sizeof(UWord));
+      tst->arch.vex.guest_RBX = uc->uc_mcontext.gregs[VKI_REG_RBX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBX], OFFSET_amd64_RBX,
+               sizeof(UWord));
+      tst->arch.vex.guest_RCX = uc->uc_mcontext.gregs[VKI_REG_RCX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RCX], OFFSET_amd64_RCX,
+               sizeof(UWord));
+      tst->arch.vex.guest_RDX = uc->uc_mcontext.gregs[VKI_REG_RDX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDX], OFFSET_amd64_RDX,
+               sizeof(UWord));
+      tst->arch.vex.guest_RBP = uc->uc_mcontext.gregs[VKI_REG_RBP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RBP], OFFSET_amd64_RBP,
+               sizeof(UWord));
+      tst->arch.vex.guest_RSI = uc->uc_mcontext.gregs[VKI_REG_RSI];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSI], OFFSET_amd64_RSI,
+               sizeof(UWord));
+      tst->arch.vex.guest_RDI = uc->uc_mcontext.gregs[VKI_REG_RDI];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RDI], OFFSET_amd64_RDI,
+               sizeof(UWord));
+      tst->arch.vex.guest_R8 = uc->uc_mcontext.gregs[VKI_REG_R8];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R8], OFFSET_amd64_R8,
+               sizeof(UWord));
+      tst->arch.vex.guest_R9 = uc->uc_mcontext.gregs[VKI_REG_R9];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R9], OFFSET_amd64_R9,
+               sizeof(UWord));
+      tst->arch.vex.guest_R10 = uc->uc_mcontext.gregs[VKI_REG_R10];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R10], OFFSET_amd64_R10,
+               sizeof(UWord));
+      tst->arch.vex.guest_R11 = uc->uc_mcontext.gregs[VKI_REG_R11];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R11], OFFSET_amd64_R11,
+               sizeof(UWord));
+      tst->arch.vex.guest_R12 = uc->uc_mcontext.gregs[VKI_REG_R12];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R12], OFFSET_amd64_R12,
+               sizeof(UWord));
+      tst->arch.vex.guest_R13 = uc->uc_mcontext.gregs[VKI_REG_R13];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R13], OFFSET_amd64_R13,
+               sizeof(UWord));
+      tst->arch.vex.guest_R14 = uc->uc_mcontext.gregs[VKI_REG_R14];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R14], OFFSET_amd64_R14,
+               sizeof(UWord));
+      tst->arch.vex.guest_R15 = uc->uc_mcontext.gregs[VKI_REG_R15];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_R15], OFFSET_amd64_R15,
+               sizeof(UWord));
+      tst->arch.vex.guest_RSP = uc->uc_mcontext.gregs[VKI_REG_RSP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_RSP], OFFSET_amd64_RSP,
+               sizeof(UWord));
+
+      /* Ignore ERR and TRAPNO. */
+
+      /* Ignore segment registers. */
+
+      /* Segment bases */
+      tst->arch.vex.guest_FS_CONST = uc->uc_mcontext.gregs[VKI_REG_FSBASE];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_REG_FSBASE],
+               offsetof(VexGuestAMD64State, guest_FS_CONST), sizeof(UWord));
+
+      /* Rflags.  Refer to the x86-solaris variant of this code for a detailed
+         description. */
+      {
+         ULong rflags;
+         ULong orig_rflags;
+         ULong new_rflags;
+         Bool ok_restore = False;
+
+         VG_TRACK(pre_mem_read, part, tid,
+                  "restore_machine_context(uc->uc_mcontext.gregs[VKI_REG_RFL])",
+                  (Addr)&uc->uc_mcontext.gregs[VKI_REG_RFL], sizeof(UWord));
+         rflags = uc->uc_mcontext.gregs[VKI_REG_RFL];
+         orig_rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex);
+         new_rflags = rflags;
+         /* The kernel disallows the ID flag to be changed via the setcontext
+            call, thus do the same. */
+         if (orig_rflags & VKI_RFLAGS_ID_BIT)
+            new_rflags |= VKI_RFLAGS_ID_BIT;
+         else
+            new_rflags &= ~VKI_RFLAGS_ID_BIT;
+         LibVEX_GuestAMD64_put_rflags(new_rflags, &tst->arch.vex);
+         VG_TRACK(post_reg_write, part, tid,
+                  offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(UWord));
+         VG_TRACK(post_reg_write, part, tid,
+                  offsetof(VexGuestAMD64State, guest_CC_DEP2), sizeof(UWord));
+
+         if (rflags != ~VKI_UC_GUEST_RFLAGS_NEG(uc)) {
+            VG_(debugLog)(1, "syswrap-solaris",
+                             "The rflags value was restored from an "
+                             "explicitly set value in thread %d.\n", tid);
+            ok_restore = True;
+         }
+         else {
+            ULong buf[5];
+            ULong checksum;
+
+            buf[0] = VKI_UC_GUEST_CC_OP(uc);
+            buf[1] = VKI_UC_GUEST_CC_NDEP(uc);
+            buf[2] = VKI_UC_GUEST_CC_DEP1(uc);
+            buf[3] = VKI_UC_GUEST_CC_DEP2(uc);
+            buf[4] = rflags;
+            checksum = ML_(fletcher64)((UInt*)&buf,
+                                       sizeof(buf) / sizeof(UInt));
+            if (checksum == VKI_UC_GUEST_RFLAGS_CHECKSUM(uc)) {
+               /* Check ok, the full restoration is possible. */
+               VG_(debugLog)(1, "syswrap-solaris",
+                                "The CC_* guest state values were fully "
+                                "restored in thread %d.\n", tid);
+               ok_restore = True;
+
+               tst->arch.vex.guest_CC_OP = VKI_UC_GUEST_CC_OP(uc);
+               tst->arch.vex.guest_CC_NDEP = VKI_UC_GUEST_CC_NDEP(uc);
+               tst->arch.vex.guest_CC_DEP1 = VKI_UC_GUEST_CC_DEP1(uc);
+               VG_TRACK(copy_mem_to_reg, part, tid,
+                        (Addr)&VKI_UC_GUEST_CC_DEP1(uc),
+                        offsetof(VexGuestAMD64State, guest_CC_DEP1),
+                        sizeof(UWord));
+               tst->arch.vex.guest_CC_DEP2 = VKI_UC_GUEST_CC_DEP2(uc);
+               VG_TRACK(copy_mem_to_reg, part, tid,
+                        (Addr)&VKI_UC_GUEST_CC_DEP2(uc),
+                        offsetof(VexGuestAMD64State, guest_CC_DEP2),
+                        sizeof(UWord));
+            }
+         }
+
+         if (!ok_restore)
+            VG_(debugLog)(1, "syswrap-solaris",
+                             "Cannot fully restore the CC_* guest state "
+                             "values, using approximate rflags in thread "
+                             "%d.\n", tid);
+      }
+   }
+
+   if (uc->uc_flags & VKI_UC_FPU) {
+      /* FPU */
+      VexEmNote note;
+      SizeT i;
+
+      /* x87 */
+      /* Control word */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..cw)",
+               (Addr)&fs->cw, sizeof(fs->cw));
+      /* Status word */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..sw)",
+               (Addr)&fs->sw, sizeof(fs->sw));
+      /* Compressed tag word */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..fctw)",
+               (Addr)&fs->fctw, sizeof(fs->fctw));
+      /* Last x87 opcode */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..fop)",
+               (Addr)&fs->fop, sizeof(fs->fop));
+      /* Last x87 instruction pointer */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..rip)",
+               (Addr)&fs->rip, sizeof(fs->rip));
+      /* Last x87 data pointer */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..rdp)",
+               (Addr)&fs->rdp, sizeof(fs->rdp));
+      /* Media-instruction control and status register */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..mxcsr)",
+               (Addr)&fs->mxcsr, sizeof(fs->mxcsr));
+      /* Supported features in MXCSR */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..mxcsr_mask)",
+               (Addr)&fs->mxcsr_mask, sizeof(fs->mxcsr_mask));
+
+      /* ST registers */
+      for (i = 0; i < 8; i++) {
+         Addr addr = (Addr)&fs->st[i];
+         VG_TRACK(copy_mem_to_reg, part, tid, addr,
+                  offsetof(VexGuestAMD64State, guest_FPREG[i]), sizeof(ULong));
+      }
+
+      /* XMM registers */
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[0],
+               offsetof(VexGuestAMD64State, guest_YMM0), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[1],
+               offsetof(VexGuestAMD64State, guest_YMM1), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[2],
+               offsetof(VexGuestAMD64State, guest_YMM2), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[3],
+               offsetof(VexGuestAMD64State, guest_YMM3), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[4],
+               offsetof(VexGuestAMD64State, guest_YMM4), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[5],
+               offsetof(VexGuestAMD64State, guest_YMM5), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[6],
+               offsetof(VexGuestAMD64State, guest_YMM6), sizeof(U128));
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[7],
+               offsetof(VexGuestAMD64State, guest_YMM7), sizeof(U128));
+
+      note = LibVEX_GuestAMD64_fxrstor((HWord)fs, &tst->arch.vex);
+      if (note != EmNote_NONE)
+         VG_(message)(Vg_UserMsg,
+                      "Error restoring FP state in thread %d: %s.\n",
+                      tid, LibVEX_EmNote_string(note));
+   }
+}
+
+
+/* ---------------------------------------------------------------------
+   PRE/POST wrappers for AMD64/Solaris-specific syscalls
+   ------------------------------------------------------------------ */
+
+#define PRE(name)       DEFN_PRE_TEMPLATE(amd64_solaris, name)
+#define POST(name)      DEFN_POST_TEMPLATE(amd64_solaris, name)
+
+/* implementation */
+
+#undef PRE
+#undef POST
+
+#endif // defined(VGP_amd64_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-darwin.c b/coregrind/m_syswrap/syswrap-darwin.c
index f804ade..b957b04 100644
--- a/coregrind/m_syswrap/syswrap-darwin.c
+++ b/coregrind/m_syswrap/syswrap-darwin.c
@@ -3451,7 +3451,7 @@
    } else {
       envp = VG_(env_clone)( (HChar**)ARG5 );
       vg_assert(envp);
-      VG_(env_remove_valgrind_env_stuff)( envp );
+      VG_(env_remove_valgrind_env_stuff)( envp, /* ro_strings */ False, NULL);
    }
 
    if (trace_this_child) {
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 3e1a826..10dd80a 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -30,7 +30,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
@@ -145,7 +145,7 @@
    presented with bogus client addresses.  Is not used for generating
    user-visible errors. */
 
-Bool ML_(safe_to_deref) ( void* start, SizeT size )
+Bool ML_(safe_to_deref) ( const void *start, SizeT size )
 {
    return VG_(am_is_valid_for_client)( (Addr)start, size, VKI_PROT_READ );
 }
@@ -549,8 +549,7 @@
 
 
 /* Note the fact that a file descriptor was just closed. */
-static
-void record_fd_close(Int fd)
+void ML_(record_fd_close)(Int fd)
 {
    OpenFd *i = allocated_fds;
 
@@ -634,6 +633,32 @@
    ML_(record_fd_open_with_given_name)(tid, fd, NULL);
 }
 
+// Return if a given file descriptor is already recorded.
+Bool ML_(fd_recorded)(Int fd)
+{
+   OpenFd *i = allocated_fds;
+   while (i) {
+      if (i->fd == fd)
+         return True;
+      i = i->next;
+   }
+   return False;
+}
+
+/* Returned string must not be modified nor free'd. */
+const HChar *ML_(find_fd_recorded_by_fd)(Int fd)
+{
+   OpenFd *i = allocated_fds;
+
+   while (i) {
+      if (i->fd == fd)
+         return i->pathname;
+      i = i->next;
+   }
+
+   return NULL;
+}
+
 static
 HChar *unix_to_name(struct vki_sockaddr_un *sa, UInt len, HChar *name)
 {
@@ -901,6 +926,44 @@
 #elif defined(VGO_darwin)
    init_preopened_fds_without_proc_self_fd();
 
+#elif defined(VGO_solaris)
+   Int ret;
+   Char buf[VKI_MAXGETDENTS_SIZE];
+   SysRes f;
+
+   f = VG_(open)("/proc/self/fd", VKI_O_RDONLY, 0);
+   if (sr_isError(f)) {
+      init_preopened_fds_without_proc_self_fd();
+      return;
+   }
+
+   while ((ret = VG_(getdents64)(sr_Res(f), (struct vki_dirent64 *) buf,
+                                 sizeof(buf))) > 0) {
+      Int i = 0;
+      while (i < ret) {
+         /* Proceed one entry. */
+         struct vki_dirent64 *d = (struct vki_dirent64 *) (buf + i);
+         if (VG_(strcmp)(d->d_name, ".") && VG_(strcmp)(d->d_name, "..")) {
+            HChar *s;
+            Int fno = VG_(strtoll10)(d->d_name, &s);
+            if (*s == '\0') {
+               if (fno != sr_Res(f))
+                  if (VG_(clo_track_fds))
+                     ML_(record_fd_open_named)(-1, fno);
+            } else {
+               VG_(message)(Vg_DebugMsg,
+                     "Warning: invalid file name in /proc/self/fd: %s\n",
+                     d->d_name);
+            }
+         }
+
+         /* Move on the next entry. */
+         i += d->d_reclen;
+      }
+   }
+
+   VG_(close)(sr_Res(f));
+
 #else
 #  error Unknown OS
 #endif
@@ -1046,7 +1109,7 @@
                              struct vki_sockaddr *sa, UInt salen )
 {
    HChar *outmsg;
-   struct vki_sockaddr_un*  sun  = (struct vki_sockaddr_un *)sa;
+   struct vki_sockaddr_un*  saun = (struct vki_sockaddr_un *)sa;
    struct vki_sockaddr_in*  sin  = (struct vki_sockaddr_in *)sa;
    struct vki_sockaddr_in6* sin6 = (struct vki_sockaddr_in6 *)sa;
 #  ifdef VKI_AF_BLUETOOTH
@@ -1069,7 +1132,7 @@
                   
       case VKI_AF_UNIX:
          VG_(sprintf) ( outmsg, description, "sun_path" );
-         PRE_MEM_RASCIIZ( outmsg, (Addr) sun->sun_path );
+         PRE_MEM_RASCIIZ( outmsg, (Addr) saun->sun_path );
          // GrP fixme max of sun_len-2? what about nul char?
          break;
                      
@@ -1717,8 +1780,11 @@
 
    arg.buf = &buf;
 
-#  ifdef __NR_semctl
+#  if defined(__NR_semctl)
    res = VG_(do_syscall4)(__NR_semctl, semid, 0, VKI_IPC_STAT, *(UWord *)&arg);
+#  elif defined(__NR_semsys) /* Solaris */
+   res = VG_(do_syscall5)(__NR_semsys, VKI_SEMCTL, semid, 0, VKI_IPC_STAT,
+                          *(UWord *)&arg);
 #  else
    res = VG_(do_syscall5)(__NR_ipc, 3 /* IPCOP_semctl */, semid, 0,
                           VKI_IPC_STAT, (UWord)&arg);
@@ -1761,6 +1827,11 @@
 #if defined(VKI_SEM_STAT)
    case VKI_SEM_STAT|VKI_IPC_64:
 #endif
+#endif
+#if defined(VKI_IPC_STAT64)
+   case VKI_IPC_STAT64:
+#endif
+#if defined(VKI_IPC_64) || defined(VKI_IPC_STAT64)
       PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
                      (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
@@ -1773,6 +1844,11 @@
 
 #if defined(VKI_IPC_64)
    case VKI_IPC_SET|VKI_IPC_64:
+#endif
+#if defined(VKI_IPC_SET64)
+   case VKI_IPC_SET64:
+#endif
+#if defined(VKI_IPC64) || defined(VKI_IPC_SET64)
       PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
                     (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
@@ -1826,6 +1902,11 @@
 #if defined(VKI_IPC_64)
    case VKI_IPC_STAT|VKI_IPC_64:
    case VKI_SEM_STAT|VKI_IPC_64:
+#endif
+#if defined(VKI_IPC_STAT64)
+   case VKI_IPC_STAT64:
+#endif
+#if defined(VKI_IPC_64) || defined(VKI_IPC_STAT64)
       POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
 #endif
@@ -1847,7 +1928,7 @@
 static
 SizeT get_shm_size ( Int shmid )
 {
-#ifdef __NR_shmctl
+#if defined(__NR_shmctl)
 #  ifdef VKI_IPC_64
    struct vki_shmid64_ds buf;
 #    if defined(VGP_amd64_linux) || defined(VGP_arm64_linux)
@@ -1862,6 +1943,10 @@
    struct vki_shmid_ds buf;
    SysRes __res = VG_(do_syscall3)(__NR_shmctl, shmid, VKI_IPC_STAT, (UWord)&buf);
 #  endif /* def VKI_IPC_64 */
+#elif defined(__NR_shmsys) /* Solaris */
+   struct vki_shmid_ds buf;
+   SysRes __res = VG_(do_syscall4)(__NR_shmsys, VKI_SHMCTL, shmid, VKI_IPC_STAT,
+                         (UWord)&buf);
 #else
    struct vki_shmid_ds buf;
    SysRes __res = VG_(do_syscall5)(__NR_ipc, 24 /* IPCOP_shmctl */, shmid,
@@ -2157,6 +2242,16 @@
    if (arg4 & VKI_MAP_FIXED) {
       mreq.rkind = MFixed;
    } else
+#if defined(VKI_MAP_ALIGN) /* Solaris specific */
+   if (arg4 & VKI_MAP_ALIGN) {
+      mreq.rkind = MAlign;
+      if (mreq.start == 0) {
+         mreq.start = VKI_PAGE_SIZE;
+      }
+      /* VKI_MAP_FIXED and VKI_MAP_ALIGN don't like each other. */
+      arg4 &= ~VKI_MAP_ALIGN;
+   } else
+#endif
    if (arg1 != 0) {
       mreq.rkind = MHint;
    } else {
@@ -2678,7 +2773,7 @@
 }
 
 // Pre_read a char** argument.
-static void pre_argv_envp(Addr a, ThreadId tid, const HChar* s1, const HChar* s2)
+void ML_(pre_argv_envp)(Addr a, ThreadId tid, const HChar *s1, const HChar *s2)
 {
    while (True) {
       Addr a_deref;
@@ -2729,9 +2824,9 @@
                  char *, filename, char **, argv, char **, envp);
    PRE_MEM_RASCIIZ( "execve(filename)", ARG1 );
    if (ARG2 != 0)
-      pre_argv_envp( ARG2, tid, "execve(argv)", "execve(argv[i])" );
+      ML_(pre_argv_envp)( ARG2, tid, "execve(argv)", "execve(argv[i])" );
    if (ARG3 != 0)
-      pre_argv_envp( ARG3, tid, "execve(envp)", "execve(envp[i])" );
+      ML_(pre_argv_envp)( ARG3, tid, "execve(envp)", "execve(envp[i])" );
 
    vg_assert(VG_(is_valid_tid)(tid));
    tst = VG_(get_ThreadState)(tid);
@@ -2850,7 +2945,7 @@
    } else {
       envp = VG_(env_clone)( (HChar**)ARG3 );
       if (envp == NULL) goto hosed;
-      VG_(env_remove_valgrind_env_stuff)( envp );
+      VG_(env_remove_valgrind_env_stuff)( envp, True /*ro_strings*/, NULL );
    }
 
    if (trace_this_child) {
@@ -3089,7 +3184,7 @@
 
 POST(sys_close)
 {
-   if (VG_(clo_track_fds)) record_fd_close(ARG1);
+   if (VG_(clo_track_fds)) ML_(record_fd_close)(ARG1);
 }
 
 PRE(sys_dup)
@@ -3160,6 +3255,7 @@
    POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
 }
 
+#if !defined(VGO_solaris)
 static vki_sigset_t fork_saved_mask;
 
 // In Linux, the sys_fork() function varies across architectures, but we
@@ -3178,6 +3274,8 @@
    VG_(sigfillset)(&mask);
    VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);
 
+   VG_(do_atfork_pre)(tid);
+
    SET_STATUS_from_SysRes( VG_(do_syscall0)(__NR_fork) );
 
    if (!SUCCESS) return;
@@ -3194,8 +3292,6 @@
 #  error Unknown OS
 #endif
 
-   VG_(do_atfork_pre)(tid);
-
    if (is_child) {
       VG_(do_atfork_child)(tid);
 
@@ -3222,6 +3318,7 @@
       VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
    }
 }
+#endif // !defined(VGO_solaris)
 
 PRE(sys_ftruncate)
 {
@@ -3499,9 +3596,15 @@
       According to Simon Hausmann, _IOC_READ means the kernel
       writes a value to the ioctl value passed from the user
       space and the other way around with _IOC_WRITE. */
-   
+
+#if defined(VGO_solaris)
+   /* Majority of Solaris ioctl requests does not honour direction hints. */
+   UInt dir  = _VKI_IOC_NONE;
+#else   
    UInt dir  = _VKI_IOC_DIR(request);
+#endif
    UInt size = _VKI_IOC_SIZE(request);
+
    if (SimHintiS(SimHint_lax_ioctls, VG_(clo_sim_hints))) {
       /* 
        * Be very lax about ioctl handling; the only
@@ -3620,7 +3723,7 @@
 PRE(sys_kill)
 {
    PRINT("sys_kill ( %ld, %ld )", ARG1,ARG2);
-   PRE_REG_READ2(long, "kill", int, pid, int, sig);
+   PRE_REG_READ2(long, "kill", int, pid, int, signal);
    if (!ML_(client_signal_OK)(ARG2)) {
       SET_STATUS_Failure( VKI_EINVAL );
       return;
@@ -3799,6 +3902,49 @@
       POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) );
 }
 
+#if defined(VGO_linux) || defined(VGO_solaris)
+/* Handles the case where the open is of /proc/self/auxv or
+   /proc/<pid>/auxv, and just gives out a copy of the fd for the
+   fake file we cooked up at startup (in m_main).  Also, seeks the
+   cloned fd back to the start.
+   Returns True if auxv open was handled (status is set). */
+Bool ML_(handle_auxv_open)(SyscallStatus *status, const HChar *filename,
+                           int flags)
+{
+   HChar  name[30];   // large enough
+
+   if (!ML_(safe_to_deref)((const void *) filename, 1))
+      return False;
+
+   /* Opening /proc/<pid>/auxv or /proc/self/auxv? */
+   VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
+   if (!VG_STREQ(filename, name) && !VG_STREQ(filename, "/proc/self/auxv"))
+      return False;
+
+   /* Allow to open the file only for reading. */
+   if (flags & (VKI_O_WRONLY | VKI_O_RDWR)) {
+      SET_STATUS_Failure(VKI_EACCES);
+      return True;
+   }
+
+#  if defined(VGO_solaris)
+   VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_auxv_fd));
+   SysRes sres = VG_(open)(name, flags, 0);
+   SET_STATUS_from_SysRes(sres);
+#  else
+   SysRes sres = VG_(dup)(VG_(cl_auxv_fd));
+   SET_STATUS_from_SysRes(sres);
+   if (!sr_isError(sres)) {
+      OffT off = VG_(lseek)(sr_Res(sres), 0, VKI_SEEK_SET);
+      if (off < 0)
+         SET_STATUS_Failure(VKI_EMFILE);
+   }
+#  endif
+
+   return True;
+}
+#endif // defined(VGO_linux) || defined(VGO_solaris)
+
 PRE(sys_open)
 {
    if (ARG2 & VKI_O_CREAT) {
@@ -3840,30 +3986,9 @@
       }
    }
 
-   /* Handle the case where the open is of /proc/self/auxv or
-      /proc/<pid>/auxv, 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. */
-   {
-      HChar  name[30];   // large enough
-      HChar* arg1s = (HChar*) ARG1;
-      SysRes sres;
-
-      VG_(sprintf)(name, "/proc/%d/auxv", VG_(getpid)());
-      if (ML_(safe_to_deref)( arg1s, 1 ) &&
-          (VG_STREQ(arg1s, name) || VG_STREQ(arg1s, "/proc/self/auxv"))
-         )
-      {
-         sres = VG_(dup)( VG_(cl_auxv_fd) );
-         SET_STATUS_from_SysRes( sres );
-         if (!sr_isError(sres)) {
-            OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
-            if (off < 0)
-               SET_STATUS_Failure( VKI_EMFILE );
-         }
-         return;
-      }
-   }
+   /* Handle also the case of /proc/self/auxv or /proc/<pid>/auxv. */
+   if (ML_(handle_auxv_open)(status, (const HChar *)ARG1, ARG2))
+      return;
 #endif // defined(VGO_linux)
 
    /* Otherwise handle normally */
@@ -3914,6 +4039,11 @@
    if (!ok && ARG1 == 2/*stderr*/ 
            && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints)))
       ok = True;
+#if defined(VGO_solaris)
+   if (!ok && VG_(vfork_fildes_addr) != NULL &&
+       *VG_(vfork_fildes_addr) >= 0 && *VG_(vfork_fildes_addr) == ARG1)
+      ok = True;
+#endif
    if (!ok)
       SET_STATUS_Failure( VKI_EBADF );
    else
@@ -4004,7 +4134,21 @@
          SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name, 
                                                          ARG2, ARG3));
       } else
-#endif // defined(VGO_linux)
+#elif defined(VGO_solaris)
+      /* Same for Solaris, but /proc/self/path/a.out and
+         /proc/<pid>/path/a.out. */
+      HChar  name[30];   // large enough
+      HChar* arg1s = (HChar*) ARG1;
+      VG_(sprintf)(name, "/proc/%d/path/a.out", VG_(getpid)());
+      if (ML_(safe_to_deref)(arg1s, 1) &&
+          (VG_STREQ(arg1s, name) || VG_STREQ(arg1s, "/proc/self/path/a.out"))
+         )
+      {
+         VG_(sprintf)(name, "/proc/self/path/%d", VG_(cl_exec_fd));
+         SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name,
+                                                         ARG2, ARG3));
+      } else
+#endif
       {
          /* Normal case */
          SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, ARG1, ARG2, ARG3));
@@ -4183,7 +4327,15 @@
          SET_STATUS_Failure( VKI_EPERM );
       }
       else {
-         VG_(threads)[tid].client_stack_szB = ((struct vki_rlimit *)ARG2)->rlim_cur;
+         /* Change the value of client_stack_szB to the rlim_cur value but
+            only if it is smaller than the size of the allocated stack for the
+            client.
+            TODO: All platforms should set VG_(clstk_max_size) as part of their
+                  setup_client_stack(). */
+         if ((VG_(clstk_max_size) == 0)
+             || (((struct vki_rlimit *) ARG2)->rlim_cur <= VG_(clstk_max_size)))
+            VG_(threads)[tid].client_stack_szB = ((struct vki_rlimit *)ARG2)->rlim_cur;
+
          VG_(client_rlimit_stack) = *(struct vki_rlimit *)ARG2;
          SET_STATUS_Success( 0 );
       }
@@ -4411,6 +4563,16 @@
       PRE_MEM_WRITE( "sigaltstack(oss)", ARG2, sizeof(vki_stack_t) );
    }
 
+   /* Be safe. */
+   if (ARG1 && !ML_(safe_to_deref((void*)ARG1, sizeof(vki_stack_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+   if (ARG2 && !ML_(safe_to_deref((void*)ARG2, sizeof(vki_stack_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+
    SET_STATUS_from_SysRes( 
       VG_(do_sys_sigaltstack) (tid, (vki_stack_t*)ARG1, 
                               (vki_stack_t*)ARG2)
@@ -4433,7 +4595,7 @@
 #undef PRE
 #undef POST
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index 71ef2b7..0479400 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -89,6 +89,14 @@
    amd64-darwin.  Apparently 0(%esp) is some kind of return address
    (perhaps for syscalls done with "sysenter"?)  I don't think it is
    relevant for syscalls done with "int $0x80/1/2".
+
+   SOLARIS:
+   x86    eax +4   +8   +12  +16  +20  +24  +28  +32  edx:eax, eflags.c
+   amd64  rax rdi  rsi  rdx  r10  r8   r9   +8   +16  rdx:rax, rflags.c
+
+   "+N" denotes "in memory at N(%esp)". Solaris also supports fasttrap
+   syscalls. Fasttraps do not take any parameters (except of the sysno in eax)
+   and never fail (if the sysno is valid).
 */
 
 /* This is the top level of the system-call handler module.  All
@@ -172,6 +180,11 @@
      s390x:  Success(N) ==>  r2 = N
              Fail(N)    ==>  r2 = -N
 
+     Solaris:
+     x86:    Success(N) ==>  edx:eax = N, cc = 0
+             Fail(N)    ==>      eax = N, cc = 1
+     Same applies for fasttraps except they never fail.
+
    * The post wrapper is called if:
 
      - it exists, and
@@ -297,6 +310,18 @@
                                            const vki_sigset_t *syscall_mask,
                                            const vki_sigset_t *restore_mask,
                                            Word sigsetSzB ); /* unused */
+#elif defined(VGO_solaris)
+extern
+UWord ML_(do_syscall_for_client_WRK)( Word syscallno,
+                                      void* guest_state,
+                                      const vki_sigset_t *syscall_mask,
+                                      const vki_sigset_t *restore_mask,
+                                      UChar *cflag);
+UWord ML_(do_syscall_for_client_dret_WRK)( Word syscallno,
+                                           void* guest_state,
+                                           const vki_sigset_t *syscall_mask,
+                                           const vki_sigset_t *restore_mask,
+                                           UChar *cflag);
 #else
 #  error "Unknown OS"
 #endif
@@ -339,6 +364,35 @@
          /*NOTREACHED*/
          break;
    }
+#  elif defined(VGO_solaris)
+   UChar cflag;
+
+   /* Fasttraps or anything else cannot go through this path. */
+   vg_assert(VG_SOLARIS_SYSNO_CLASS(syscallno)
+             == VG_SOLARIS_SYSCALL_CLASS_CLASSIC);
+
+   /* If the syscall is a door_return call then it has to be handled very
+      differently. */
+   if (tst->os_state.in_door_return)
+      err = ML_(do_syscall_for_client_dret_WRK)(
+                syscallno, &tst->arch.vex,
+                syscall_mask, &saved, &cflag
+            );
+   else
+      err = ML_(do_syscall_for_client_WRK)(
+                syscallno, &tst->arch.vex,
+                syscall_mask, &saved, &cflag
+            );
+
+   /* Save the carry flag. */
+#  if defined(VGP_x86_solaris)
+   LibVEX_GuestX86_put_eflag_c(cflag, &tst->arch.vex);
+#  elif defined(VGP_amd64_solaris)
+   LibVEX_GuestAMD64_put_rflag_c(cflag, &tst->arch.vex);
+#  else
+#    error "Unknown platform"
+#  endif
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -662,6 +716,69 @@
    canonical->arg7  = 0;
    canonical->arg8  = 0;
 
+#elif defined(VGP_x86_solaris)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_ESP;
+   canonical->sysno = gst->guest_EAX;
+   /* stack[0] is a return address. */
+   canonical->arg1  = stack[1];
+   canonical->arg2  = stack[2];
+   canonical->arg3  = stack[3];
+   canonical->arg4  = stack[4];
+   canonical->arg5  = stack[5];
+   canonical->arg6  = stack[6];
+   canonical->arg7  = stack[7];
+   canonical->arg8  = stack[8];
+
+   switch (trc) {
+   case VEX_TRC_JMP_SYS_INT145:
+   case VEX_TRC_JMP_SYS_SYSENTER:
+   case VEX_TRC_JMP_SYS_SYSCALL:
+   /* These three are not actually valid syscall instructions on Solaris.
+      Pretend for now that we handle them as normal syscalls. */
+   case VEX_TRC_JMP_SYS_INT128:
+   case VEX_TRC_JMP_SYS_INT129:
+   case VEX_TRC_JMP_SYS_INT130:
+      /* int $0x91, sysenter, syscall = normal syscall */
+      break;
+   case VEX_TRC_JMP_SYS_INT210:
+      /* int $0xD2 = fasttrap */
+      canonical->sysno
+         = VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(canonical->sysno);
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+
+#elif defined(VGP_amd64_solaris)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_RSP;
+   canonical->sysno = gst->guest_RAX;
+   /* stack[0] is a return address. */
+   canonical->arg1 = gst->guest_RDI;
+   canonical->arg2 = gst->guest_RSI;
+   canonical->arg3 = gst->guest_RDX;
+   canonical->arg4 = gst->guest_R10;  /* Not RCX with syscall. */
+   canonical->arg5 = gst->guest_R8;
+   canonical->arg6 = gst->guest_R9;
+   canonical->arg7 = stack[1];
+   canonical->arg8 = stack[2];
+
+   switch (trc) {
+   case VEX_TRC_JMP_SYS_SYSCALL:
+      /* syscall = normal syscall */
+      break;
+   case VEX_TRC_JMP_SYS_INT210:
+      /* int $0xD2 = fasttrap */
+      canonical->sysno
+         = VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(canonical->sysno);
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+
 #else
 #  error "getSyscallArgsFromGuestState: unknown arch"
 #endif
@@ -817,6 +934,42 @@
    gst->guest_r4 = canonical->arg5;
    gst->guest_r5 = canonical->arg6;
 
+#elif defined(VGP_x86_solaris)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_ESP;
+
+   /* Fasttraps or anything else cannot go through this way. */
+   vg_assert(VG_SOLARIS_SYSNO_CLASS(canonical->sysno)
+             == VG_SOLARIS_SYSCALL_CLASS_CLASSIC);
+   gst->guest_EAX = canonical->sysno;
+   /* stack[0] is a return address. */
+   stack[1] = canonical->arg1;
+   stack[2] = canonical->arg2;
+   stack[3] = canonical->arg3;
+   stack[4] = canonical->arg4;
+   stack[5] = canonical->arg5;
+   stack[6] = canonical->arg6;
+   stack[7] = canonical->arg7;
+   stack[8] = canonical->arg8;
+
+#elif defined(VGP_amd64_solaris)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_RSP;
+
+   /* Fasttraps or anything else cannot go through this way. */
+   vg_assert(VG_SOLARIS_SYSNO_CLASS(canonical->sysno)
+             == VG_SOLARIS_SYSCALL_CLASS_CLASSIC);
+   gst->guest_RAX = canonical->sysno;
+   /* stack[0] is a return address. */
+   gst->guest_RDI = canonical->arg1;
+   gst->guest_RSI = canonical->arg2;
+   gst->guest_RDX = canonical->arg3;
+   gst->guest_R10 = canonical->arg4;
+   gst->guest_R8  = canonical->arg5;
+   gst->guest_R9  = canonical->arg6;
+   stack[1] = canonical->arg7;
+   stack[2] = canonical->arg8;
+
 #else
 #  error "putSyscallArgsIntoGuestState: unknown arch"
 #endif
@@ -950,6 +1103,24 @@
    canonical->sres = VG_(mk_SysRes_tilegx_linux)( gst->guest_r0 );
    canonical->what = SsComplete;
 
+#  elif defined(VGP_x86_solaris)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UInt carry = 1 & LibVEX_GuestX86_get_eflags(gst);
+
+   canonical->sres = VG_(mk_SysRes_x86_solaris)(carry ? True : False,
+                                                gst->guest_EAX,
+                                                carry ? 0 : gst->guest_EDX);
+   canonical->what = SsComplete;
+
+#  elif defined(VGP_amd64_solaris)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   UInt carry = 1 & LibVEX_GuestAMD64_get_rflags(gst);
+
+   canonical->sres = VG_(mk_SysRes_amd64_solaris)(carry ? True : False,
+                                                  gst->guest_RAX,
+                                                  carry ? 0 : gst->guest_RDX);
+   canonical->what = SsComplete;
+
 #  else
 #    error "getSyscallStatusFromGuestState: unknown arch"
 #  endif
@@ -1175,6 +1346,60 @@
       gst->guest_r1 = 0;
    }
 
+#  elif defined(VGP_x86_solaris)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   SysRes sres = canonical->sres;
+   vg_assert(canonical->what == SsComplete);
+
+   if (sr_isError(sres)) {
+      gst->guest_EAX = sr_Err(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_x86_EAX,
+               sizeof(UInt));
+      LibVEX_GuestX86_put_eflag_c(1, gst);
+   }
+   else {
+      gst->guest_EAX = sr_Res(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_x86_EAX,
+               sizeof(UInt));
+      gst->guest_EDX = sr_ResHI(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_x86_EDX,
+               sizeof(UInt));
+      LibVEX_GuestX86_put_eflag_c(0, gst);
+   }
+   /* Make CC_DEP1 and CC_DEP2 defined.  This is inaccurate because it makes
+      other eflags defined too (see README.solaris). */
+   VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, offsetof(VexGuestX86State,
+            guest_CC_DEP1), sizeof(UInt));
+   VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, offsetof(VexGuestX86State,
+            guest_CC_DEP2), sizeof(UInt));
+
+#  elif defined(VGP_amd64_solaris)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   SysRes sres = canonical->sres;
+   vg_assert(canonical->what == SsComplete);
+
+   if (sr_isError(sres)) {
+      gst->guest_RAX = sr_Err(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_amd64_RAX,
+               sizeof(ULong));
+      LibVEX_GuestAMD64_put_rflag_c(1, gst);
+   }
+   else {
+      gst->guest_RAX = sr_Res(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_amd64_RAX,
+               sizeof(ULong));
+      gst->guest_RDX = sr_ResHI(sres);
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_amd64_RDX,
+               sizeof(ULong));
+      LibVEX_GuestAMD64_put_rflag_c(0, gst);
+   }
+   /* Make CC_DEP1 and CC_DEP2 defined.  This is inaccurate because it makes
+      other eflags defined too (see README.solaris). */
+   VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, offsetof(VexGuestAMD64State,
+            guest_CC_DEP1), sizeof(ULong));
+   VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, offsetof(VexGuestAMD64State,
+            guest_CC_DEP2), sizeof(ULong));
+
 #  else
 #    error "putSyscallStatusIntoGuestState: unknown arch"
 #  endif
@@ -1311,6 +1536,7 @@
    layout->o_arg6   = OFFSET_s390x_r7;
    layout->uu_arg7  = -1; /* impossible value */
    layout->uu_arg8  = -1; /* impossible value */
+
 #elif defined(VGP_tilegx_linux)
    layout->o_sysno  = OFFSET_tilegx_r(10);
    layout->o_arg1   = OFFSET_tilegx_r(0);
@@ -1322,6 +1548,29 @@
    layout->uu_arg7  = -1; /* impossible value */
    layout->uu_arg8  = -1; /* impossible value */
 
+#elif defined(VGP_x86_solaris)
+   layout->o_sysno  = OFFSET_x86_EAX;
+   /* Syscall parameters are on the stack. */
+   layout->s_arg1   = sizeof(UWord) * 1;
+   layout->s_arg2   = sizeof(UWord) * 2;
+   layout->s_arg3   = sizeof(UWord) * 3;
+   layout->s_arg4   = sizeof(UWord) * 4;
+   layout->s_arg5   = sizeof(UWord) * 5;
+   layout->s_arg6   = sizeof(UWord) * 6;
+   layout->s_arg7   = sizeof(UWord) * 7;
+   layout->s_arg8   = sizeof(UWord) * 8;
+
+#elif defined(VGP_amd64_solaris)
+   layout->o_sysno  = OFFSET_amd64_RAX;
+   layout->o_arg1   = OFFSET_amd64_RDI;
+   layout->o_arg2   = OFFSET_amd64_RSI;
+   layout->o_arg3   = OFFSET_amd64_RDX;
+   layout->o_arg4   = OFFSET_amd64_R10;
+   layout->o_arg5   = OFFSET_amd64_R8;
+   layout->o_arg6   = OFFSET_amd64_R9;
+   layout->s_arg7   = sizeof(UWord) * 1;
+   layout->s_arg8   = sizeof(UWord) * 2;
+
 #else
 #  error "getSyscallLayout: unknown arch"
 #endif
@@ -1353,6 +1602,10 @@
    VG_(dmsg)("it at http://valgrind.org/support/bug_reports.html.\n");
 
    SET_STATUS_Failure(VKI_ENOSYS);
+
+#  if defined(VGO_solaris)
+   VG_(exit)(1);
+#  endif
 }
 
 static SyscallTableEntry bad_sys =
@@ -1389,6 +1642,9 @@
       break;
    }
 
+#  elif defined(VGO_solaris)
+   sys = ML_(get_solaris_syscall_entry)(syscallno);
+
 #  else
 #    error Unknown OS
 #  endif
@@ -1731,6 +1987,10 @@
             go through anyway, with SfToBlock set, hence we end up here. */
          putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
 
+         /* SfNoWriteResult flag is invalid for blocking signals because
+            do_syscall_for_client() directly modifies the guest state. */
+         vg_assert(!(sci->flags & SfNoWriteResult));
+
          /* Drop the bigLock */
          VG_(release_BigLock)(tid, VgTs_WaitSys, "VG_(client_syscall)[async]");
          /* Urr.  We're now in a race against other threads trying to
@@ -1985,6 +2245,15 @@
   extern const Addr ML_(blksys_complete_UNIX);
   extern const Addr ML_(blksys_committed_UNIX);
   extern const Addr ML_(blksys_finished_UNIX);
+#elif defined(VGO_solaris)
+  extern const Addr ML_(blksys_setup);
+  extern const Addr ML_(blksys_complete);
+  extern const Addr ML_(blksys_committed);
+  extern const Addr ML_(blksys_finished);
+  extern const Addr ML_(blksys_setup_DRET);
+  extern const Addr ML_(blksys_complete_DRET);
+  extern const Addr ML_(blksys_committed_DRET);
+  extern const Addr ML_(blksys_finished_DRET);
 #else
 # error "Unknown OS"
 #endif
@@ -2223,6 +2492,57 @@
       vg_assert(p[0] == 0x286b180051485000ULL);
    }
 
+#elif defined(VGP_x86_solaris)
+   arch->vex.guest_EIP -= 2;   // sizeof(int $0x91) or sizeof(syscall)
+
+   /* Make sure our caller is actually sane, and we're really backing
+      back over a syscall.
+
+      int $0x91 == CD 91
+      syscall   == 0F 05
+      sysenter  == 0F 34
+
+      Handle also other syscall instructions because we also handle them in
+      the scheduler.
+      int $0x80 == CD 80
+      int $0x81 == CD 81
+      int $0x82 == CD 82
+   */
+   {
+      UChar *p = (UChar *)arch->vex.guest_EIP;
+
+      Bool  ok = (p[0] == 0xCD && p[1] == 0x91)
+                  || (p[0] == 0x0F && p[1] == 0x05)
+                  || (p[0] == 0x0F && p[1] == 0x34)
+                  || (p[0] == 0xCD && p[1] == 0x80)
+                  || (p[0] == 0xCD && p[1] == 0x81)
+                  || (p[0] == 0xCD && p[1] == 0x82);
+      if (!ok)
+         VG_(message)(Vg_DebugMsg,
+                      "?! restarting over syscall at %#x %02x %02x\n",
+                      arch->vex.guest_EIP, p[0], p[1]);
+      vg_assert(ok);
+   }
+
+#elif defined(VGP_amd64_solaris)
+   arch->vex.guest_RIP -= 2;   // sizeof(syscall)
+
+   /* Make sure our caller is actually sane, and we're really backing
+      back over a syscall.
+
+      syscall   == 0F 05
+   */
+   {
+      UChar *p = (UChar *)arch->vex.guest_RIP;
+
+      Bool  ok = (p[0] == 0x0F && p[1] == 0x05);
+      if (!ok)
+         VG_(message)(Vg_DebugMsg,
+                      "?! restarting over syscall at %#llx %02x %02x\n",
+                      arch->vex.guest_RIP, p[0], p[1]);
+      vg_assert(ok);
+   }
+
 #else
 #  error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
 #endif
@@ -2263,7 +2583,8 @@
 VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, 
                                                   Addr     ip, 
                                                   SysRes   sres,
-                                                  Bool     restart)
+                                                  Bool     restart,
+                                                  struct vki_ucontext *uc)
 {
    /* Note that we don't know the syscall number here, since (1) in
       general there's no reliable way to get hold of it short of
@@ -2288,6 +2609,24 @@
         in_complete_to_committed, // [3,4) in the .S files
         in_committed_to_finished; // [4,5) in the .S files
 
+   if (VG_(clo_trace_signals))
+      VG_(message)( Vg_DebugMsg,
+                    "interrupted_syscall: tid=%d, ip=0x%llx, "
+                    "restart=%s, sres.isErr=%s, sres.val=%lld\n",
+                    (Int)tid,
+                    (ULong)ip,
+                    restart ? "True" : "False",
+                    sr_isError(sres) ? "True" : "False",
+                    (Long)(sr_isError(sres) ? sr_Err(sres) : sr_Res(sres)) );
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   vg_assert(tid >= 1 && tid < VG_N_THREADS);
+   vg_assert(VG_(is_running_thread)(tid));
+
+   tst     = VG_(get_ThreadState)(tid);
+   th_regs = &tst->arch;
+   sci     = & syscallInfo[tid];
+
 #  if defined(VGO_linux)
    outside_range
       = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished);
@@ -2321,28 +2660,36 @@
       || (ip >= ML_(blksys_committed_MDEP) && ip < ML_(blksys_finished_MDEP))
       || (ip >= ML_(blksys_committed_UNIX) && ip < ML_(blksys_finished_UNIX));
    /* Wasn't that just So Much Fun?  Does your head hurt yet?  Mine does. */
+#  elif defined(VGO_solaris)
+   /* The solaris port is never outside the range. */
+   outside_range = False;
+   /* The Solaris kernel never restarts syscalls directly! */
+   at_restart = False;
+   if (tst->os_state.in_door_return) {
+      vg_assert(ip >= ML_(blksys_setup_DRET)
+                && ip < ML_(blksys_finished_DRET));
+
+      in_setup_to_restart
+         = ip >= ML_(blksys_setup_DRET) && ip < ML_(blksys_complete_DRET);
+      in_complete_to_committed
+         = ip >= ML_(blksys_complete_DRET) && ip < ML_(blksys_committed_DRET);
+      in_committed_to_finished
+         = ip >= ML_(blksys_committed_DRET) && ip < ML_(blksys_finished_DRET);
+   }
+   else {
+      vg_assert(ip >= ML_(blksys_setup) && ip < ML_(blksys_finished));
+
+      in_setup_to_restart
+         = ip >= ML_(blksys_setup) && ip < ML_(blksys_complete);
+      in_complete_to_committed
+         = ip >= ML_(blksys_complete) && ip < ML_(blksys_committed);
+      in_committed_to_finished
+         = ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
+   }
 #  else
 #    error "Unknown OS"
 #  endif
 
-   if (VG_(clo_trace_signals))
-      VG_(message)( Vg_DebugMsg,
-                    "interrupted_syscall: tid=%d, ip=0x%llx, "
-                    "restart=%s, sres.isErr=%s, sres.val=%lld\n", 
-                    (Int)tid,
-                    (ULong)ip, 
-                    restart ? "True" : "False", 
-                    sr_isError(sres) ? "True" : "False",
-                    (Long)(sr_isError(sres) ? sr_Err(sres) : sr_Res(sres)) );
-
-   vg_assert(VG_(is_valid_tid)(tid));
-   vg_assert(tid >= 1 && tid < VG_N_THREADS);
-   vg_assert(VG_(is_running_thread)(tid));
-
-   tst     = VG_(get_ThreadState)(tid);
-   th_regs = &tst->arch;
-   sci     = & syscallInfo[tid];
-
    /* Figure out what the state of the syscall was by examining the
       (real) IP at the time of the signal, and act accordingly. */
    if (outside_range) {
@@ -2372,6 +2719,11 @@
 
    else 
    if (at_restart) {
+#     if defined(VGO_solaris)
+      /* We should never hit this branch on Solaris, see the comment above. */
+      vg_assert(0);
+#     endif
+
       /* We're either about to run the syscall, or it was interrupted
          and the kernel restarted it.  Restart if asked, otherwise
          EINTR it. */
@@ -2401,8 +2753,20 @@
          VG_(message)( Vg_DebugMsg,
                        "  completed, but uncommitted: committing\n");
       canonical = convert_SysRes_to_SyscallStatus( sres );
-      if (!(sci->flags & SfNoWriteResult))
-         putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
+      vg_assert(!(sci->flags & SfNoWriteResult));
+      putSyscallStatusIntoGuestState( tid, &canonical, &th_regs->vex );
+#     if defined(VGO_solaris)
+      if (tst->os_state.in_door_return) {
+#        if defined(VGP_x86_solaris)
+         /* Registers %esp and %ebp were also modified by the syscall. */
+         tst->arch.vex.guest_ESP = uc->uc_mcontext.gregs[VKI_UESP];
+         tst->arch.vex.guest_EBP = uc->uc_mcontext.gregs[VKI_EBP];
+#        elif defined(VGP_amd64_solaris)
+         tst->arch.vex.guest_RSP = uc->uc_mcontext.gregs[VKI_REG_RSP];
+         tst->arch.vex.guest_RBP = uc->uc_mcontext.gregs[VKI_REG_RBP];
+#        endif
+      }
+#     endif
       sci->status = canonical;
       VG_(post_syscall)(tid);
    } 
@@ -2415,6 +2779,13 @@
       if (VG_(clo_trace_signals))
          VG_(message)( Vg_DebugMsg,
                        "  completed and committed: nothing to do\n");
+#     if defined(VGP_x86_solaris)
+      /* The %eax and %edx values are committed but the carry flag is still
+         uncommitted.  Save it now. */
+      LibVEX_GuestX86_put_eflag_c(sr_isError(sres), &th_regs->vex);
+#     elif defined(VGP_amd64_solaris)
+      LibVEX_GuestAMD64_put_rflag_c(sr_isError(sres), &th_regs->vex);
+#     endif
       getSyscallStatusFromGuestState( &sci->status, &th_regs->vex );
       vg_assert(sci->status.what == SsComplete);
       VG_(post_syscall)(tid);
@@ -2431,6 +2802,21 @@
 }
 
 
+#if defined(VGO_solaris)
+/* Returns True if ip is inside a fixable syscall code in syscall-*-*.S.  This
+   function can be called by a 'non-running' thread! */
+Bool VG_(is_ip_in_blocking_syscall)(ThreadId tid, Addr ip)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+
+   if (tst->os_state.in_door_return)
+      return ip >= ML_(blksys_setup_DRET) && ip < ML_(blksys_finished_DRET);
+   else
+      return ip >= ML_(blksys_setup) && ip < ML_(blksys_finished);
+}
+#endif
+
+
 #if defined(VGO_darwin)
 // Clean up after workq_ops(WQOPS_THREAD_RETURN) jumped to wqthread_hijack. 
 // This is similar to VG_(fixup_guest_state_after_syscall_interrupted).
diff --git a/coregrind/m_syswrap/syswrap-solaris.c b/coregrind/m_syswrap/syswrap-solaris.c
new file mode 100644
index 0000000..9a3e04d
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-solaris.c
@@ -0,0 +1,9978 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Solaris-specific syscalls, etc.            syswrap-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2015 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net>. */
+
+/* Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
+
+#if defined(VGO_solaris)
+
+#include "libvex_guest_offsets.h"
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_debuginfo.h"         // VG_(di_notify_*)
+#include "pub_core_debuglog.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_gdbserver.h"
+#include "pub_core_inner.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_libcsignal.h"
+#include "pub_core_machine.h"           // VG_(get_SP)
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_transtab.h"          // VG_(discard_translations)
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h"
+#include "pub_core_signals.h"
+#include "pub_core_stacks.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_ume.h"
+#if defined(ENABLE_INNER_CLIENT_REQUEST)
+#include "pub_core_clreq.h"
+#endif
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"
+#include "priv_syswrap-solaris.h"
+
+/* Return the number of non-dead and daemon threads.
+   count_daemon == True:  count daemon threads
+   count_daemon == False: count non-daemon threads */
+static UInt count_living_daemon_threads(Bool count_daemon)
+{
+   UInt count = 0;
+   for (ThreadId tid = 1; tid < VG_N_THREADS; tid++)
+      if (VG_(threads)[tid].status != VgTs_Empty &&
+         VG_(threads)[tid].status != VgTs_Zombie &&
+         VG_(threads)[tid].os_state.daemon_thread == count_daemon)
+         count++;
+
+   return count;
+}
+
+/* Note: The following functions (thread_wrapper, run_a_thread_NORETURN,
+   ML_(start_thread_NORETURN), ML_(allocstack) and
+   VG_(main_thread_wrapper_NORETURN)) are based on the code in
+   syswrap-linux.c.  Keep them synchronized! */
+
+/* Run a thread from beginning to end and return the thread's
+   scheduler-return-code. */
+static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
+{
+   VgSchedReturnCode ret;
+   ThreadId tid = (ThreadId)tidW;
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+
+   VG_(debugLog)(1, "syswrap-solaris",
+                    "thread_wrapper(tid=%lld): entry\n",
+                    (ULong)tidW);
+
+   vg_assert(tst->status == VgTs_Init);
+
+   /* Make sure we get the CPU lock before doing anything significant. */
+   VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)");
+
+   if (0)
+      VG_(printf)("thread tid %d started: stack = %p\n", tid, &tid);
+
+   /* Make sure error reporting is enabled in the new thread. */
+   tst->err_disablement_level = 0;
+
+   if (tid == 1)
+      VG_TRACK(pre_thread_first_insn, tid);
+   else {
+      /* For newly created threads, VG_TRACK(pre_thread_first_insn, tid) is
+         invoked later from PRE(sys_getsetcontext)() when setucontext()
+         called from _thrp_setup() concludes new thread setup. Invoking it
+         here would be way too early - new thread has no stack, yet. */
+   }
+
+   tst->os_state.lwpid = VG_(gettid)();
+   tst->os_state.threadgroup = VG_(getpid)();
+
+   /* Thread created with all signals blocked; scheduler will set the
+      appropriate mask. */
+
+   ret = VG_(scheduler)(tid);
+
+   vg_assert(VG_(is_exiting)(tid));
+
+   vg_assert(tst->status == VgTs_Runnable);
+   vg_assert(VG_(is_running_thread)(tid));
+
+   VG_(debugLog)(1, "syswrap-solaris",
+                    "thread_wrapper(tid=%lld): exit, schedreturncode %s\n",
+                    (ULong)tidW, VG_(name_of_VgSchedReturnCode)(ret));
+
+   /* Return to caller, still holding the lock. */
+   return ret;
+}
+
+/* Run a thread all the way to the end, then do appropriate exit actions
+   (this is the last-one-out-turn-off-the-lights bit). */
+static void run_a_thread_NORETURN(Word tidW)
+{
+   ThreadId tid = (ThreadId)tidW;
+   VgSchedReturnCode src;
+   Int c;
+   ThreadState *tst;
+#ifdef ENABLE_INNER_CLIENT_REQUEST
+   Int registered_vgstack_id;
+#endif
+
+   VG_(debugLog)(1, "syswrap-solaris",
+                    "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n",
+                    (ULong)tidW);
+
+   tst = VG_(get_ThreadState)(tid);
+   vg_assert(tst);
+
+   /* A thread has two stacks:
+      * the simulated stack (used by the synthetic cpu. Guest process
+        is using this stack).
+      * the valgrind stack (used by the real cpu. Valgrind code is running
+        on this stack).
+      When Valgrind runs as an inner, it must signal that its (real) stack
+      is the stack to use by the outer to e.g. do stacktraces.
+   */
+   INNER_REQUEST
+      (registered_vgstack_id
+       = VALGRIND_STACK_REGISTER(tst->os_state.valgrind_stack_base,
+                                 tst->os_state.valgrind_stack_init_SP));
+
+   /* Run the thread all the way through. */
+   src = thread_wrapper(tid);
+
+   VG_(debugLog)(1, "syswrap-solaris",
+                    "run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
+                    (ULong)tidW);
+
+   c = count_living_daemon_threads(False);
+   vg_assert(c >= 1); /* Stay sane. */
+
+   /* Tell the tool that schedctl data belonging to this thread are gone. */
+   Addr a = tst->os_state.schedctl_data;
+   if (a != 0)
+      VG_TRACK(die_mem_munmap, a, sizeof(struct vki_sc_shared));
+
+   /* Deregister thread's stack. */
+   if (tst->os_state.stk_id != (UWord)-1)
+      VG_(deregister_stack)(tst->os_state.stk_id);
+
+   /* Tell the tool this thread is exiting. */
+   VG_TRACK(pre_thread_ll_exit, tid);
+
+   /* If the thread is exiting with errors disabled, complain loudly;
+      doing so is bad (does the user know this has happened?)  Also, in all
+      cases, be paranoid and clear the flag anyway so that the thread slot is
+      safe in this respect if later reallocated.  This should be unnecessary
+      since the flag should be cleared when the slot is reallocated, in
+      thread_wrapper(). */
+   if (tst->err_disablement_level > 0) {
+      VG_(umsg)(
+         "WARNING: exiting thread has error reporting disabled.\n"
+         "WARNING: possibly as a result of some mistake in the use\n"
+         "WARNING: of the VALGRIND_DISABLE_ERROR_REPORTING macros.\n"
+      );
+      VG_(debugLog)(
+         1, "syswrap-solaris",
+            "run_a_thread_NORETURN(tid=%lld): "
+            "WARNING: exiting thread has err_disablement_level = %u\n",
+            (ULong)tidW, tst->err_disablement_level
+      );
+   }
+   tst->err_disablement_level = 0;
+
+   if (c == 1) {
+      UInt daemon_threads = count_living_daemon_threads(True);
+      if (daemon_threads == 0)
+         VG_(debugLog)(1, "syswrap-solaris",
+                          "run_a_thread_NORETURN(tid=%lld): "
+                          "last one standing\n",
+                          (ULong) tidW);
+      else
+         VG_(debugLog)(1, "syswrap-solaris",
+                          "run_a_thread_NORETURN(tid=%lld): "
+                          "last non-daemon thread standing "
+                          "[daemon threads=%u]\n",
+                          (ULong) tidW, daemon_threads);
+
+      /* We are the last non-daemon thread standing. Keep hold of the lock and
+         carry on to show final tool results, then exit the entire system.
+         Use the continuation pointer set at startup in m_main. */
+      if ((src == VgSrc_ExitThread) && (daemon_threads > 0))
+         src = VgSrc_ExitProcess;
+      (*VG_(address_of_m_main_shutdown_actions_NORETURN))(tid, src);
+   }
+   else {
+      VG_(debugLog)(1, "syswrap-solaris",
+                       "run_a_thread_NORETURN(tid=%lld): "
+                       "not last one standing\n",
+                       (ULong)tidW);
+
+      /* OK, thread is dead, but others still exist.  Just exit. */
+
+      /* This releases the run lock. */
+      VG_(exit_thread)(tid);
+      vg_assert(tst->status == VgTs_Zombie);
+      vg_assert(sizeof(tst->status) == 4);
+
+      INNER_REQUEST(VALGRIND_STACK_DEREGISTER(registered_vgstack_id));
+
+      /* We have to use this sequence to terminate the thread to
+         prevent a subtle race.  If VG_(exit_thread)() had left the
+         ThreadState as Empty, then it could have been reallocated, reusing
+         the stack while we're doing these last cleanups.  Instead,
+         VG_(exit_thread) leaves it as Zombie to prevent reallocation.  We
+         need to make sure we don't touch the stack between marking it Empty
+         and exiting.  Hence the assembler. */
+#if defined(VGP_x86_solaris)
+      /* Luckily lwp_exit doesn't take any arguments so we don't have to mess
+         with the stack. */
+      __asm__ __volatile__ (
+         "movl  %[EMPTY], %[status]\n"  /* set tst->status = VgTs_Empty */
+         "movl  $"VG_STRINGIFY(__NR_lwp_exit)", %%eax\n"
+         "int   $0x91\n"                /* lwp_exit() */
+         : [status] "=m" (tst->status)
+         : [EMPTY] "n" (VgTs_Empty)
+         : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+      __asm__ __volatile__ (
+         "movl  %[EMPTY], %[status]\n"  /* set tst->status = VgTs_Empty */
+         "movq  $"VG_STRINGIFY(__NR_lwp_exit)", %%rax\n"
+         "syscall\n"                    /* lwp_exit() */
+         : [status] "=m" (tst->status)
+         : [EMPTY] "n" (VgTs_Empty)
+         : "rax", "rdx", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+
+      VG_(core_panic)("Thread exit failed?\n");
+   }
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+Word ML_(start_thread_NORETURN)(void *arg)
+{
+   ThreadState *tst = (ThreadState*)arg;
+   ThreadId tid = tst->tid;
+
+   run_a_thread_NORETURN((Word)tid);
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+/* Allocate a stack for this thread, if it doesn't already have one.
+   They're allocated lazily, and never freed.  Returns the initial stack
+   pointer value to use, or 0 if allocation failed. */
+Addr ML_(allocstack)(ThreadId tid)
+{
+   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) {
+      stack = VG_(am_alloc_VgStack)( &initial_SP );
+      if (stack) {
+         tst->os_state.valgrind_stack_base = (Addr)stack;
+         tst->os_state.valgrind_stack_init_SP = initial_SP;
+      }
+   }
+
+   if (0)
+      VG_(printf)("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;
+}
+
+/* Allocate a stack for the main thread, and run it all the way to the
+   end.  Although we already have a working VgStack (VG_(interim_stack)) it's
+   better to allocate a new one, so that overflow detection works uniformly
+   for all threads.  Also initialize the GDT (for normal threads, this is done
+   in the PRE wrapper of lwp_create). */
+void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
+{
+   Addr sp;
+
+   VG_(debugLog)(1, "syswrap-solaris",
+                    "entering VG_(main_thread_wrapper_NORETURN)\n");
+
+   sp = ML_(allocstack)(tid);
+#if defined(ENABLE_INNER_CLIENT_REQUEST)
+   {
+      // we must register the main thread stack before the call
+      // to ML_(call_on_new_stack_0_1), otherwise the outer valgrind
+      // reports 'write error' on the non registered stack.
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      INNER_REQUEST
+         ((void) 
+          VALGRIND_STACK_REGISTER(tst->os_state.valgrind_stack_base,
+                                  tst->os_state.valgrind_stack_init_SP));
+   }
+#endif
+
+#if defined(VGP_x86_solaris)
+   {
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      ML_(setup_gdt)(&tst->arch.vex);
+      ML_(update_gdt_lwpgs)(tid);
+   }
+#elif defined(VGP_amd64_solaris)
+   /* Nothing to do. */
+#else
+#  error "Unknown platform"
+#endif
+
+   /* If we can't even allocate the first thread's stack, we're hosed.
+      Give up. */
+   vg_assert2(sp != 0, "Cannot allocate main thread's stack.");
+
+   /* Shouldn't be any other threads around yet. */
+   vg_assert(VG_(count_living_threads)() == 1);
+
+   ML_(call_on_new_stack_0_1)(
+      (Addr)sp,               /* stack */
+      0,                      /* bogus return address */
+      run_a_thread_NORETURN,  /* fn to call */
+      (Word)tid               /* arg to give it */
+   );
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+/* Deallocate the GDT for a thread. */
+void VG_(cleanup_thread)(ThreadArchState *arch)
+{
+#if defined(VGP_x86_solaris)
+   ML_(cleanup_gdt)(&arch->vex);
+#elif defined(VGP_amd64_solaris)
+   /* Nothing to do. */
+#else
+#  error "Unknown platform"
+#endif
+}
+
+/*
+ * Notify core about spring cleaning of schedctl data pages for all threads
+ * in child post-fork handler. Libc will issue new schedctl syscalls for threads
+ * in the child when needs arise.
+ *
+ * See also POST(schedctl) and run_a_thread_NORETURN() when a thread exits.
+ */
+static void clean_schedctl_data(ThreadId tid)
+{
+   UInt i;
+   for (i = 0; i < VG_N_THREADS; i++) {
+      ThreadState *tst = &VG_(threads)[i];
+      if (tst->status != VgTs_Empty) {
+         Addr a = tst->os_state.schedctl_data;
+         if (a != 0) {
+            tst->os_state.schedctl_data = 0;
+            a = VG_PGROUNDDN(a);
+            if (VG_(am_find_anon_segment(a)))
+               VG_(am_notify_munmap)(a, VKI_PAGE_SIZE);
+         }
+      }
+   }
+}
+
+void VG_(syswrap_init)(void)
+{
+   VG_(atfork)(NULL, NULL, clean_schedctl_data);
+}
+
+/* Calculate the Fletcher-32 checksum of a given buffer. */
+UInt ML_(fletcher32)(UShort *buf, SizeT blocks)
+{
+   UInt sum1 = 0;
+   UInt sum2 = 0;
+   SizeT i;
+
+   for (i = 0; i < blocks; i++) {
+      sum1 = (sum1 + buf[i]) % 0xffff;
+      sum2 = (sum2 + sum1) % 0xffff;
+   }
+
+   return (sum2 << 16) | sum1;
+}
+
+/* Calculate the Fletcher-64 checksum of a given buffer. */
+ULong ML_(fletcher64)(UInt *buf, SizeT blocks)
+{
+   ULong sum1 = 0;
+   ULong sum2 = 0;
+   SizeT i;
+
+   for (i = 0; i < blocks; i++) {
+      sum1 = (sum1 + buf[i]) % 0xffffffff;
+      sum2 = (sum2 + sum1) % 0xffffffff;
+   }
+   return (sum2 << 32) | sum1;
+}
+
+/* Save a complete context (VCPU state, sigmask) of a given client thread
+   into the vki_ucontext_t structure.  This structure is supposed to be
+   allocated in the client memory, a caller must make sure that the memory can
+   be dereferenced.  The active tool is informed about the save. */
+void VG_(save_context)(ThreadId tid, vki_ucontext_t *uc, CorePart part)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+
+   VG_TRACK(pre_mem_write, part, tid, "save_context(uc)", (Addr)uc,
+            sizeof(*uc));
+
+   uc->uc_flags = VKI_UC_ALL;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_flags,
+            sizeof(uc->uc_flags));
+
+   /* Old context */
+   uc->uc_link = tst->os_state.oldcontext;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_link,
+            sizeof(uc->uc_link));
+
+   /* Clear uc->vki_uc_signo.  This slot is used by the signal machinery to
+      store a signal number. */
+   VKI_UC_SIGNO(uc) = 0;
+
+   /* Sigmask */
+   uc->uc_sigmask = tst->sig_mask;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_sigmask,
+            sizeof(uc->uc_sigmask));
+
+   /* Stack */
+   {
+      if (tst->os_state.ustack
+          && ML_(safe_to_deref)(tst->os_state.ustack, sizeof(vki_stack_t))
+          && tst->os_state.ustack->ss_size) {
+         /* If ustack points to a valid stack copy it to ucontext. */
+         uc->uc_stack = *tst->os_state.ustack;
+      }
+      else {
+         /* Ustack is not valid.  A correct stack has to be figured out
+            manually. */
+         SysRes res;
+         vki_stack_t altstack;
+
+         /* Get information about alternate stack. */
+         res = VG_(do_sys_sigaltstack)(tid, NULL, &altstack);
+         vg_assert(!sr_isError(res));
+
+         if (altstack.ss_flags == VKI_SS_ONSTACK) {
+            /* If the alternate stack is active copy it to ucontext. */
+            uc->uc_stack = altstack;
+         }
+         else {
+            /* No information about stack is present, save information about
+               current main stack to ucontext.  This branch should be reached
+               only by the main thread. */
+            ThreadState *tst2 = VG_(get_ThreadState)(1);
+            uc->uc_stack.ss_sp = (void*)(tst2->client_stack_highest_byte + 1
+                                         - tst2->client_stack_szB);
+            uc->uc_stack.ss_size = tst2->client_stack_szB;
+            uc->uc_stack.ss_flags = 0;
+         }
+      }
+
+      VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_stack,
+               sizeof(uc->uc_stack));
+   }
+
+   /* Save the architecture-specific part of the context. */
+   ML_(save_machine_context)(tid, uc, part);
+}
+
+/* Set a complete context (VCPU state, sigmask) of a given client thread
+   according to values passed in the vki_ucontext_t structure.  This structure
+   is supposed to be allocated in the client memory, a caller must make sure
+   that the memory can be dereferenced.  The active tool is informed about
+   what parts of the structure are read.
+
+   This function is a counterpart to VG_(save_context)(). */
+void VG_(restore_context)(ThreadId tid, vki_ucontext_t *uc, CorePart part,
+                          Bool esp_is_thrptr)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Addr old_esp = VG_(get_SP)(tid);
+
+   VG_TRACK(pre_mem_read, part, tid, "restore_context(uc->uc_flags)",
+            (Addr)&uc->uc_flags, sizeof(uc->uc_flags));
+
+   /* Old context */
+   VG_TRACK(pre_mem_read, part, tid, "restore_context(uc->uc_link)",
+            (Addr)&uc->uc_link, sizeof(uc->uc_link));
+   tst->os_state.oldcontext = uc->uc_link;
+
+   /* Sigmask */
+   if (uc->uc_flags & VKI_UC_SIGMASK) {
+      SysRes res;
+
+      VG_TRACK(pre_mem_read, part, tid, "restore_context(uc->uc_sigmask)",
+               (Addr)&uc->uc_sigmask, sizeof(uc->uc_sigmask));
+      res = VG_(do_sys_sigprocmask)(tid, VKI_SIG_SETMASK, &uc->uc_sigmask,
+                                    NULL);
+      /* Setting signal mask should never fail. */
+      vg_assert(!sr_isError(res));
+   }
+
+   /* Stack */
+   if (uc->uc_flags & VKI_UC_STACK) {
+      VG_TRACK(pre_mem_read, part, tid, "restore_context(uc->uc_stack)",
+               (Addr)&uc->uc_stack, sizeof(uc->uc_stack));
+
+      if (uc->uc_stack.ss_flags == VKI_SS_ONSTACK) {
+         /* This seems to be a little bit dangerous but it is what the kernel
+            does. */
+         if (VG_(clo_trace_signals))
+            VG_(dmsg)("restore_context, sigaltstack: tid %d, "
+                      "ss %p{%p,sz=%lu,flags=%#x}\n",
+                      tid, &uc->uc_stack, uc->uc_stack.ss_sp,
+                      (SizeT)uc->uc_stack.ss_size, uc->uc_stack.ss_flags);
+
+         tst->altstack.ss_sp = uc->uc_stack.ss_sp;
+         tst->altstack.ss_size = uc->uc_stack.ss_size;
+         /* Do not copy ss_flags, they are calculated dynamically by
+            Valgrind. */
+      }
+
+      /* Copyout the new stack. */
+      if (tst->os_state.ustack
+          && VG_(am_is_valid_for_client)((Addr)tst->os_state.ustack,
+                                         sizeof(*tst->os_state.ustack),
+                                         VKI_PROT_WRITE))
+         *tst->os_state.ustack = uc->uc_stack;
+         VG_TRACK(post_mem_write, part, tid, (Addr)&tst->os_state.ustack,
+                  sizeof(tst->os_state.ustack));
+   }
+
+   /* Restore the architecture-specific part of the context. */
+   ML_(restore_machine_context)(tid, uc, part, esp_is_thrptr);
+
+   /* If the thread stack is already known, kill the deallocated stack area.
+      This is important when returning from a signal handler. */
+   if (tst->client_stack_highest_byte && tst->client_stack_szB) {
+      Addr end = tst->client_stack_highest_byte;
+      Addr start = end + 1 - tst->client_stack_szB;
+      Addr new_esp = VG_(get_SP)(tid);
+
+      /* Make sure that the old and new stack pointer are on the same (active)
+         stack.  Alternate stack is currently never affected by this code. */
+      if (start <= old_esp && old_esp <= end
+          && start <= new_esp && new_esp <= end
+          && new_esp > old_esp)
+         VG_TRACK(die_mem_stack, old_esp - VG_STACK_REDZONE_SZB,
+                  (new_esp - old_esp) + VG_STACK_REDZONE_SZB);
+   }
+}
+
+/* Set a client stack associated with a given thread id according to values
+   passed in the vki_stack_t structure. */
+static void set_stack(ThreadId tid, vki_stack_t *st)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Addr new_start, new_end;
+   SizeT new_size;
+   Addr cur_start;
+   SizeT cur_size;
+
+   VG_(debugLog)(2, "syswrap-solaris",
+                    "set stack: sp=%#lx, size=%#lx.\n",
+                    (Addr)st->ss_sp, (SizeT)st->ss_size);
+
+   /* Stay sane. */
+   vg_assert(st->ss_flags == 0);
+
+   new_start = (Addr)st->ss_sp;
+   new_end = new_start + st->ss_size - 1;
+   new_size = st->ss_size;
+   cur_start = tst->client_stack_highest_byte + 1
+               - tst->client_stack_szB;
+   cur_size = tst->client_stack_szB;
+
+   if (new_start == cur_start && new_size == cur_size) {
+      /* No change is requested, bail out. */
+      return;
+   }
+
+   if (tid == 1 && (new_size == 0 || new_size > VG_(clstk_max_size))) {
+      /* The main thread requests to use a stack without any size checking, or
+         too big stack.  Fallback to the maximum allocated client stack. */
+
+      /* TODO I think it is possible to give up on setting main stack anyway.
+         Valgrind knows where it is located and it is already registered as
+         VG_(clstk_id). */
+
+      new_size = VG_(clstk_max_size);
+      new_end = tst->client_stack_highest_byte;
+      new_start = new_end + 1 - new_size;
+   }
+
+   if (tst->os_state.stk_id == (UWord)-1) {
+      /* This thread doesn't have a stack set yet. */
+      VG_(debugLog)(2, "syswrap-solaris",
+                       "Stack set to %#lx-%#lx (new) for thread %d.\n",
+                       new_start, new_end, tid);
+      tst->os_state.stk_id = VG_(register_stack)(new_start, new_end);
+   }
+   else {
+      /* Change a thread stack. */
+      VG_(debugLog)(2, "syswrap-solaris",
+                       "Stack set to %#lx-%#lx (change) for thread %d.\n",
+                       new_start, new_end, tid);
+      VG_(change_stack)(tst->os_state.stk_id, new_start, new_end);
+   }
+   tst->client_stack_highest_byte = new_end;
+   tst->client_stack_szB = new_size;
+}
+
+/* ---------------------------------------------------------------------
+   Door tracking. Used mainly for server side where door_return()
+   parameters alone do not contain sufficient information.
+   Also used on client side when new door descriptors are passed via
+   door_call() in desc_ptr. Not used for tracking door descriptors
+   explicitly open()'ed [generic fd tracking is used in that case].
+   ------------------------------------------------------------------ */
+
+/* One of these is allocated for each created door. */
+typedef struct OpenDoor
+{
+   Bool server; /* TRUE = server door, FALSE = client door */
+   Int fd;      /* The file descriptor. */
+   union {
+      /* Server side. */
+      struct {
+         Addr server_procedure;  /* The door server procedure. */
+         HChar *pathname;        /* NULL if unknown. */
+      };
+      /* Client side. */
+      struct {
+         /* Hook called during PRE door_call()
+            to check contents of params->data_ptr. */
+         void (*pre_mem_hook)(ThreadId tid, Int fd,
+                              void *data_ptr, SizeT data_size);
+         /* Hook called during POST door_call()
+            to define contents of params->rbuf. */
+         void (*post_mem_hook)(ThreadId tid, Int fd,
+                               void *rbuf, SizeT rsize);
+      };
+   };
+   struct OpenDoor *next, *prev;
+} OpenDoor;
+
+/* List of allocated door fds. */
+static OpenDoor *doors_recorded = NULL;
+static UInt nr_doors_recorded = 0;
+
+static OpenDoor *door_record_create(void)
+{
+   OpenDoor *d = VG_(malloc)("syswrap.door_record_create.1", sizeof(OpenDoor));
+   d->prev = NULL;
+   d->next = doors_recorded;
+   if (doors_recorded != NULL)
+      doors_recorded->prev = d;
+   doors_recorded = d;
+   nr_doors_recorded += 1;
+
+   return d;
+}
+
+/* Records a server door. */
+static void door_record_server(ThreadId tid, Addr server_procedure, Int fd)
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if ((d->server == TRUE) && (d->server_procedure == server_procedure)) {
+         if (d->pathname) {
+            VG_(free)(d->pathname);
+         }
+         break;
+      }
+      d = d->next;
+   }
+
+   if (d == NULL)
+      d = door_record_create();
+   vg_assert(d != NULL);
+
+   d->server = TRUE;
+   d->fd = fd;
+   d->server_procedure = server_procedure;
+   d->pathname = NULL;
+}
+
+/* Records a client door. */
+static void door_record_client(ThreadId tid, Int fd,
+   void (*pre_mem_hook)(ThreadId tid, Int fd, void *data_ptr, SizeT data_size),
+   void (*post_mem_hook)(ThreadId tid, Int fd, void *rbuf, SizeT rsize))
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if ((d->server == FALSE) && (d->fd == fd))
+         break;
+      d = d->next;
+   }
+
+   if (d == NULL)
+      d = door_record_create();
+   vg_assert(d != NULL);
+
+   d->server = FALSE;
+   d->fd = fd;
+   d->pre_mem_hook = pre_mem_hook;
+   d->post_mem_hook = post_mem_hook;
+}
+
+/* Revokes an open door, be it server side or client side. */
+static void door_revoke(ThreadId tid, Int fd)
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if (d->fd == fd) {
+         if (d->prev != NULL)
+            d->prev->next = d->next;
+         else
+            doors_recorded = d->next;
+         if (d->next != NULL)
+            d->next->prev = d->prev;
+
+         if ((d->server == TRUE) && (d->pathname != NULL))
+            VG_(free)(d->pathname);
+         VG_(free)(d);
+         nr_doors_recorded -= 1;
+         return;
+      }
+      d = d->next;
+   }
+}
+
+/* Attaches a server door to a filename. */
+static void door_server_fattach(Int fd, HChar *pathname)
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if (d->fd == fd) {
+         vg_assert(d->server == TRUE);
+
+         if (d->pathname != NULL)
+            VG_(free)(d->pathname);
+         d->pathname = VG_(strdup)("syswrap.door_server_fattach.1", pathname);
+         return;
+      }
+      d = d->next;
+   }
+}
+
+/* Finds a server door based on server procedure. */
+static const OpenDoor *door_find_by_proc(Addr server_procedure)
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if ((d->server) && (d->server_procedure == server_procedure))
+         return d;
+      d = d->next;
+   }
+
+   return NULL;
+}
+
+/* Finds a client door based on fd. */
+static const OpenDoor *door_find_by_fd(Int fd)
+{
+   OpenDoor *d = doors_recorded;
+
+   while (d != NULL) {
+      if ((d->server == FALSE) && (d->fd == fd))
+         return d;
+      d = d->next;
+   }
+
+   return NULL;
+}
+
+/* ---------------------------------------------------------------------
+   PRE/POST wrappers for Solaris-specific syscalls
+   ------------------------------------------------------------------ */
+
+#define PRE(name)       DEFN_PRE_TEMPLATE(solaris, name)
+#define POST(name)      DEFN_POST_TEMPLATE(solaris, name)
+
+/* prototypes */
+DECL_TEMPLATE(solaris, sys_exit);
+#if defined(SOLARIS_SPAWN_SYSCALL)
+DECL_TEMPLATE(solaris, sys_spawn);
+#endif /* SOLARIS_SPAWN_SYSCALL */
+#if defined(SOLARIS_OLD_SYSCALLS)
+DECL_TEMPLATE(solaris, sys_open);
+#endif /* SOLARIS_OLD_SYSCALLS */
+DECL_TEMPLATE(solaris, sys_close);
+DECL_TEMPLATE(solaris, sys_linkat);
+DECL_TEMPLATE(solaris, sys_symlinkat);
+DECL_TEMPLATE(solaris, sys_time);
+DECL_TEMPLATE(solaris, sys_brk);
+DECL_TEMPLATE(solaris, sys_stat);
+DECL_TEMPLATE(solaris, sys_lseek);
+DECL_TEMPLATE(solaris, sys_mount);
+DECL_TEMPLATE(solaris, sys_readlinkat);
+DECL_TEMPLATE(solaris, sys_stime);
+DECL_TEMPLATE(solaris, sys_fstat);
+#if defined(SOLARIS_FREALPATHAT_SYSCALL)
+DECL_TEMPLATE(solaris, sys_frealpathat);
+#endif /* SOLARIS_FREALPATHAT_SYSCALL */
+DECL_TEMPLATE(solaris, sys_stty);
+DECL_TEMPLATE(solaris, sys_gtty);
+DECL_TEMPLATE(solaris, sys_pgrpsys);
+DECL_TEMPLATE(solaris, sys_pipe);
+DECL_TEMPLATE(solaris, sys_faccessat);
+DECL_TEMPLATE(solaris, sys_mknodat);
+DECL_TEMPLATE(solaris, sys_sysi86);
+DECL_TEMPLATE(solaris, sys_shmsys);
+DECL_TEMPLATE(solaris, sys_semsys);
+DECL_TEMPLATE(solaris, sys_ioctl);
+DECL_TEMPLATE(solaris, sys_fchownat);
+DECL_TEMPLATE(solaris, sys_fdsync);
+DECL_TEMPLATE(solaris, sys_execve);
+DECL_TEMPLATE(solaris, sys_fcntl);
+DECL_TEMPLATE(solaris, sys_renameat);
+DECL_TEMPLATE(solaris, sys_unlinkat);
+DECL_TEMPLATE(solaris, sys_fstatat);
+DECL_TEMPLATE(solaris, sys_openat);
+DECL_TEMPLATE(solaris, sys_tasksys);
+DECL_TEMPLATE(solaris, sys_getpagesizes);
+DECL_TEMPLATE(solaris, sys_lwp_park);
+DECL_TEMPLATE(solaris, sys_sendfilev);
+#if defined(SOLARIS_LWP_NAME_SYSCALL)
+DECL_TEMPLATE(solaris, sys_lwp_name);
+#endif /* SOLARIS_LWP_NAME_SYSCALL */
+DECL_TEMPLATE(solaris, sys_privsys);
+DECL_TEMPLATE(solaris, sys_ucredsys);
+DECL_TEMPLATE(solaris, sys_getmsg);
+DECL_TEMPLATE(solaris, sys_putmsg);
+DECL_TEMPLATE(solaris, sys_lstat);
+DECL_TEMPLATE(solaris, sys_sigprocmask);
+DECL_TEMPLATE(solaris, sys_sigaction);
+DECL_TEMPLATE(solaris, sys_sigpending);
+DECL_TEMPLATE(solaris, sys_getsetcontext);
+DECL_TEMPLATE(solaris, sys_fchmodat);
+DECL_TEMPLATE(solaris, sys_mkdirat);
+DECL_TEMPLATE(solaris, sys_statvfs);
+DECL_TEMPLATE(solaris, sys_fstatvfs);
+DECL_TEMPLATE(solaris, sys_nfssys);
+DECL_TEMPLATE(solaris, sys_waitid);
+#if defined(SOLARIS_UTIMESYS_SYSCALL)
+DECL_TEMPLATE(solaris, sys_utimesys);
+#endif /* SOLARIS_UTIMESYS_SYSCALL */
+#if defined(SOLARIS_UTIMENSAT_SYSCALL)
+DECL_TEMPLATE(solaris, sys_utimensat);
+#endif /* SOLARIS_UTIMENSAT_SYSCALL */
+DECL_TEMPLATE(solaris, sys_sigresend);
+DECL_TEMPLATE(solaris, sys_priocntlsys);
+DECL_TEMPLATE(solaris, sys_pathconf);
+DECL_TEMPLATE(solaris, sys_mmap);
+#if defined(SOLARIS_UUIDSYS_SYSCALL)
+DECL_TEMPLATE(solaris, sys_uuidsys);
+#endif /* SOLARIS_UUIDSYS_SYSCALL */
+DECL_TEMPLATE(solaris, sys_mmapobj);
+DECL_TEMPLATE(solaris, sys_memcntl);
+DECL_TEMPLATE(solaris, sys_getpmsg);
+DECL_TEMPLATE(solaris, sys_putpmsg);
+#if defined(SOLARIS_OLD_SYSCALLS)
+DECL_TEMPLATE(solaris, sys_rename);
+#endif /* SOLARIS_OLD_SYSCALLS */
+DECL_TEMPLATE(solaris, sys_uname);
+DECL_TEMPLATE(solaris, sys_setegid);
+DECL_TEMPLATE(solaris, sys_sysconfig);
+DECL_TEMPLATE(solaris, sys_systeminfo);
+DECL_TEMPLATE(solaris, sys_seteuid);
+DECL_TEMPLATE(solaris, sys_forksys);
+DECL_TEMPLATE(solaris, sys_sigtimedwait);
+DECL_TEMPLATE(solaris, sys_yield);
+DECL_TEMPLATE(solaris, sys_lwp_sema_post);
+DECL_TEMPLATE(solaris, sys_lwp_sema_trywait);
+DECL_TEMPLATE(solaris, sys_lwp_detach);
+DECL_TEMPLATE(solaris, sys_fchroot);
+DECL_TEMPLATE(solaris, sys_gettimeofday);
+DECL_TEMPLATE(solaris, sys_lwp_create);
+DECL_TEMPLATE(solaris, sys_lwp_exit);
+DECL_TEMPLATE(solaris, sys_lwp_suspend);
+DECL_TEMPLATE(solaris, sys_lwp_continue);
+#if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL)
+DECL_TEMPLATE(solaris, sys_lwp_sigqueue);
+#else
+DECL_TEMPLATE(solaris, sys_lwp_kill);
+#endif /* SOLARIS_LWP_SIGQUEUE_SYSCALL */
+DECL_TEMPLATE(solaris, sys_lwp_self);
+DECL_TEMPLATE(solaris, sys_lwp_sigmask);
+DECL_TEMPLATE(solaris, sys_lwp_private);
+DECL_TEMPLATE(solaris, sys_lwp_wait);
+DECL_TEMPLATE(solaris, sys_lwp_mutex_wakeup);
+DECL_TEMPLATE(solaris, sys_lwp_cond_broadcast);
+DECL_TEMPLATE(solaris, sys_pread);
+DECL_TEMPLATE(solaris, sys_pwrite);
+DECL_TEMPLATE(solaris, sys_rusagesys);
+DECL_TEMPLATE(solaris, sys_port);
+DECL_TEMPLATE(solaris, sys_pollsys);
+DECL_TEMPLATE(solaris, sys_labelsys);
+DECL_TEMPLATE(solaris, sys_acl);
+DECL_TEMPLATE(solaris, sys_auditsys);
+DECL_TEMPLATE(solaris, sys_p_online);
+DECL_TEMPLATE(solaris, sys_sigqueue);
+DECL_TEMPLATE(solaris, sys_clock_gettime);
+DECL_TEMPLATE(solaris, sys_clock_settime);
+DECL_TEMPLATE(solaris, sys_clock_getres);
+DECL_TEMPLATE(solaris, sys_timer_create);
+DECL_TEMPLATE(solaris, sys_timer_delete);
+DECL_TEMPLATE(solaris, sys_timer_settime);
+DECL_TEMPLATE(solaris, sys_timer_gettime);
+DECL_TEMPLATE(solaris, sys_timer_getoverrun);
+DECL_TEMPLATE(solaris, sys_facl);
+DECL_TEMPLATE(solaris, sys_door);
+DECL_TEMPLATE(solaris, sys_schedctl);
+DECL_TEMPLATE(solaris, sys_resolvepath);
+DECL_TEMPLATE(solaris, sys_lwp_mutex_timedlock);
+DECL_TEMPLATE(solaris, sys_lwp_rwlock_sys);
+DECL_TEMPLATE(solaris, sys_lwp_sema_timedwait);
+DECL_TEMPLATE(solaris, sys_zone);
+DECL_TEMPLATE(solaris, sys_getcwd);
+DECL_TEMPLATE(solaris, sys_so_socket);
+DECL_TEMPLATE(solaris, sys_so_socketpair);
+DECL_TEMPLATE(solaris, sys_bind);
+DECL_TEMPLATE(solaris, sys_listen);
+DECL_TEMPLATE(solaris, sys_accept);
+DECL_TEMPLATE(solaris, sys_connect);
+DECL_TEMPLATE(solaris, sys_shutdown);
+DECL_TEMPLATE(solaris, sys_recv);
+DECL_TEMPLATE(solaris, sys_recvfrom);
+DECL_TEMPLATE(solaris, sys_recvmsg);
+DECL_TEMPLATE(solaris, sys_send);
+DECL_TEMPLATE(solaris, sys_sendmsg);
+DECL_TEMPLATE(solaris, sys_sendto);
+DECL_TEMPLATE(solaris, sys_getpeername);
+DECL_TEMPLATE(solaris, sys_getsockname);
+DECL_TEMPLATE(solaris, sys_getsockopt);
+DECL_TEMPLATE(solaris, sys_setsockopt);
+DECL_TEMPLATE(solaris, sys_lwp_mutex_register);
+DECL_TEMPLATE(solaris, sys_uucopy);
+DECL_TEMPLATE(solaris, sys_umount2);
+
+DECL_TEMPLATE(solaris, fast_gethrtime);
+DECL_TEMPLATE(solaris, fast_gethrvtime);
+DECL_TEMPLATE(solaris, fast_gethrestime);
+#if defined(SOLARIS_GETHRT_FASTTRAP)
+DECL_TEMPLATE(solaris, fast_gethrt);
+#endif /* SOLARIS_GETHRT_FASTTRAP */
+#if defined(SOLARIS_GETZONEOFFSET_FASTTRAP)
+DECL_TEMPLATE(solaris, fast_getzoneoffset);
+#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
+
+/* implementation */
+PRE(sys_exit)
+{
+   /* void exit(int status); */
+   ThreadId t;
+
+   PRINT("sys_exit( %ld )", ARG1);
+   PRE_REG_READ1(void, "exit", int, status);
+
+   for (t = 1; t < VG_N_THREADS; t++) {
+      if (VG_(threads)[t].status == VgTs_Empty)
+         continue;
+
+      VG_(threads)[t].exitreason = VgSrc_ExitProcess;
+      VG_(threads)[t].os_state.exitcode = ARG1;
+
+      /* Unblock it, if blocked. */
+      if (t != tid)
+         VG_(get_thread_out_of_syscall)(t);
+   }
+
+   /* We have to claim the syscall already succeeded. */
+   SET_STATUS_Success(0);
+}
+
+#if defined(SOLARIS_SPAWN_SYSCALL)
+static Bool spawn_pre_check_kfa(ThreadId tid, SyscallStatus *status,
+                                vki_kfile_attr_t *kfa)
+{
+   PRE_FIELD_READ("spawn(attrs->kfa_size)", kfa->kfa_size);
+   PRE_FIELD_READ("spawn(attrs->kfa_type)", kfa->kfa_type);
+
+   if (ML_(safe_to_deref)(kfa, kfa->kfa_size)) {
+      switch (kfa->kfa_type) {
+      case VKI_FA_DUP2:
+         PRE_FIELD_READ("spawn(attrs->kfa_filedes)", kfa->kfa_filedes);
+         PRE_FIELD_READ("spawn(attrs->kfa_newfiledes)", kfa->kfa_newfiledes);
+         if (!ML_(fd_allowed)(kfa->kfa_filedes, "spawn(dup2)", tid, False) ||
+             !ML_(fd_allowed)(kfa->kfa_newfiledes, "spawn(dup2)", tid, False)) {
+            SET_STATUS_Failure(VKI_EBADF);
+            return False;
+         }
+         break;
+      case VKI_FA_CLOSE:
+         PRE_FIELD_READ("spawn(attrs->kfa_filedes)", kfa->kfa_filedes);
+         /* If doing -d style logging (which is to fd = 2 = stderr),
+            don't allow that filedes to be closed. See ML_(fd_allowed)(). */
+         if (!ML_(fd_allowed)(kfa->kfa_filedes, "spawn(close)", tid, False) ||
+             (kfa->kfa_filedes == 2 && VG_(debugLog_getLevel)() > 0)) {
+            SET_STATUS_Failure(VKI_EBADF);
+            return False;
+         }
+         break;
+      case VKI_FA_CLOSEFROM:
+         /* :TODO: All file descriptors greater than or equal to
+            kfa->kfa_filedes would have to be checked. */
+         VG_(unimplemented)("Support for spawn() with file attribute type "
+                            "FA_CLOSEFROM.");
+         break;
+      case VKI_FA_OPEN:
+         PRE_FIELD_READ("spawn(attrs->kfa_filedes)", kfa->kfa_filedes);
+         PRE_FIELD_READ("spawn(attrs->kfa_oflag)", kfa->kfa_oflag);
+         PRE_FIELD_READ("spawn(attrs->kfa_mode)", kfa->kfa_mode);
+         if (!ML_(fd_allowed)(kfa->kfa_filedes, "spawn(open)", tid, False)) {
+            SET_STATUS_Failure(VKI_EBADF);
+            return False;
+         }
+         /* fallthrough */
+      case VKI_FA_CHDIR:
+         PRE_FIELD_READ("spawn(attrs->kfa_pathsize)", kfa->kfa_pathsize);
+         if (kfa->kfa_pathsize != 0) {
+            PRE_MEM_RASCIIZ("spawn(attrs->kfa_data)", (Addr) kfa->kfa_data);
+         }
+         break;
+      default:
+         VG_(unimplemented)("Support for spawn() with file attribute type %u.",
+                            kfa->kfa_type);
+      }
+   }
+
+   return True;
+}
+
+PRE(sys_spawn)
+{
+   /* int spawn(char *path, void *attrs, size_t attrsize,
+                char *argenv, size_t aesize); */
+   PRINT("sys_spawn ( %#lx(%s), %#lx, %ld, %#lx, %ld )",
+         ARG1, (HChar *) ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "spawn", const char *, path, void *, attrs,
+                 size_t, attrsize, char *, argenv, size_t, aesize);
+
+   /* First check input arguments. */
+   PRE_MEM_RASCIIZ("spawn(path)", ARG1);
+   if (ARG3 > 0) {
+      /*  --- vki_kspawn_attr_t --
+          | ksa_version          |
+          | ksa_size             |
+          | ksa_attr_off         |  -----| (only if != 0)
+          | ksa_attr_size        |       |
+          | ksa_path_off         |  =====|====| (only if != 0)
+          | ksa_path_size        |       |    |
+          | ksa_shell_off        |  -----|----|----| (only if != 0)
+          | ksa_shell_size       |       |    |    |
+          | ksa_data[0]          |       |    |    |
+          ------------------------       |    |    |
+          | vki_spawn_attr_t     |  <----|    |    |
+          ------------------------            |    |
+          | path                 |  <---------|    |
+          ------------------------                 |
+          | shell                |  <---------------
+          ------------------------
+          | file actions         |  (not included in ksa_size, only in ARG3)
+          ------------------------
+
+          ksa_size = sizeof(vki_kspawn_attr_t) + ksa_attr_size + ksa_path_size +
+                     ksa_shell_size
+          attrs_size (ARG3) = ksa_size + file actions size */
+
+      vki_kspawn_attr_t *attrs = (vki_kspawn_attr_t *) ARG2;
+      PRE_FIELD_READ("spawn(attrs->ksa_version)", attrs->ksa_version);
+      PRE_FIELD_READ("spawn(attrs->ksa_size)", attrs->ksa_size);
+      PRE_FIELD_READ("spawn(attrs->ksa_attr_off)", attrs->ksa_attr_off);
+      PRE_FIELD_READ("spawn(attrs->ksa_path_off)", attrs->ksa_path_off);
+      PRE_FIELD_READ("spawn(attrs->ksa_shell_off)", attrs->ksa_shell_off);
+
+      if (ML_(safe_to_deref)(attrs, sizeof(vki_kspawn_attr_t))) {
+         if (attrs->ksa_version != VKI_SPAWN_VERSION) {
+            VG_(unimplemented)("Support for spawn() with attributes "
+                               "version %u.", attrs->ksa_version);
+         }
+
+         if (attrs->ksa_attr_off != 0) {
+            PRE_FIELD_READ("spawn(attrs->ksa_attr_size)", attrs->ksa_attr_size);
+            vki_spawn_attr_t *sap =
+                (vki_spawn_attr_t *) ((Addr) attrs + attrs->ksa_attr_off);
+            PRE_MEM_READ("spawn(attrs->ksa_attr)",
+                         (Addr) sap, attrs->ksa_attr_size);
+            if (ML_(safe_to_deref)(sap, sizeof(vki_spawn_attr_t))) {
+               if (sap->sa_psflags & VKI_POSIX_SPAWN_SETVAMASK_NP) {
+                  VG_(unimplemented)("Support for spawn() with attributes flag "
+                                     "including POSIX_SPAWN_SETVAMASK_NP.");
+               }
+               /* paranoia */
+               Int rem = sap->sa_psflags & ~(
+                  VKI_POSIX_SPAWN_RESETIDS      | VKI_POSIX_SPAWN_SETPGROUP |
+                  VKI_POSIX_SPAWN_SETSIGDEF     | VKI_POSIX_SPAWN_SETSIGMASK |
+                  VKI_POSIX_SPAWN_SETSCHEDPARAM | VKI_POSIX_SPAWN_SETSCHEDULER |
+                  VKI_POSIX_SPAWN_SETSID_NP     | VKI_POSIX_SPAWN_SETVAMASK_NP |
+                  VKI_POSIX_SPAWN_SETSIGIGN_NP  | VKI_POSIX_SPAWN_NOSIGCHLD_NP |
+                  VKI_POSIX_SPAWN_WAITPID_NP    | VKI_POSIX_SPAWN_NOEXECERR_NP);
+               if (rem != 0) {
+                  VG_(unimplemented)("Support for spawn() with attributes flag "
+                                     "%#x.", sap->sa_psflags);
+               }
+            }
+         }
+
+         if (attrs->ksa_path_off != 0) {
+            PRE_FIELD_READ("spawn(attrs->ksa_path_size)", attrs->ksa_path_size);
+            PRE_MEM_RASCIIZ("spawn(attrs->ksa_path)",
+                            (Addr) attrs + attrs->ksa_path_off);
+         }
+
+         if (attrs->ksa_shell_off != 0) {
+            PRE_FIELD_READ("spawn(attrs->ksa_shell_size)",
+                           attrs->ksa_shell_size);
+            PRE_MEM_RASCIIZ("spawn(attrs->ksa_shell)",
+                            (Addr) attrs + attrs->ksa_shell_off);
+         }
+
+         vki_kfile_attr_t *kfa = (vki_kfile_attr_t *) (ARG2 + attrs->ksa_size);
+         while ((Addr) kfa < ARG2 + ARG3) {
+            if (spawn_pre_check_kfa(tid, status, kfa) == False) {
+               return;
+            }
+            kfa = (vki_kfile_attr_t *) ((Addr) kfa + kfa->kfa_size);
+         }
+      }
+   }
+   PRE_MEM_READ("spawn(argenv)", ARG4, ARG5);
+
+   /* Check that the name at least begins in client-accessible storage. */
+   if ((ARG1 == 0) || !ML_(safe_to_deref)((HChar *) ARG1, 1)) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+
+   /* Check that attrs reside in client-accessible storage. */
+   if (ARG2 != 0) {
+      if (!VG_(am_is_valid_for_client)(ARG2, ARG3, VKI_PROT_READ)) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+   }
+
+   /* Check that the argenv reside in client-accessible storage.
+      Solaris disallows to perform spawn() without any arguments & environment
+      variables specified. */
+   if ((ARG4 == 0) /* obviously bogus */ ||
+       !VG_(am_is_valid_for_client)(ARG4, ARG5, VKI_PROT_READ)) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+
+   /* Copy existing attrs or create empty minimal ones. */
+   vki_kspawn_attr_t *attrs;
+   SizeT attrs_size;
+   if (ARG2 == 0) {
+      /* minimalistic kspawn_attr_t + spawn_attr_t */
+      attrs_size = sizeof(vki_kspawn_attr_t) + sizeof(vki_spawn_attr_t);
+      attrs = VG_(calloc)("syswrap.spawn.1", 1, attrs_size);
+      attrs->ksa_version = VKI_SPAWN_VERSION;
+      attrs->ksa_size = attrs_size;
+      attrs->ksa_attr_off = sizeof(vki_kspawn_attr_t);
+      attrs->ksa_attr_size = sizeof(vki_spawn_attr_t);
+   } else if (((vki_kspawn_attr_t *) ARG2)->ksa_attr_off == 0) {
+      /* existing kspawn_attr_t but missing spawn_attr_t */
+      attrs_size = ARG3 + sizeof(vki_spawn_attr_t);
+      attrs = VG_(calloc)("syswrap.spawn.2", 1, attrs_size);
+      VG_(memcpy)(attrs, (void *) ARG2, sizeof(vki_kspawn_attr_t));
+      SizeT file_actions_size = ARG3 - attrs->ksa_size;
+      attrs->ksa_size += sizeof(vki_spawn_attr_t);
+      attrs->ksa_attr_off = sizeof(vki_kspawn_attr_t);
+      attrs->ksa_attr_size = sizeof(vki_spawn_attr_t);
+      if (attrs->ksa_path_off != 0) {
+         VG_(memcpy)((HChar *) attrs + attrs->ksa_path_off +
+                     sizeof(vki_spawn_attr_t), (HChar *) ARG2 +
+                     attrs->ksa_path_off, attrs->ksa_path_size);
+         attrs->ksa_path_off += sizeof(vki_spawn_attr_t);
+      }
+      if (attrs->ksa_shell_off != 0) {
+         VG_(memcpy)((HChar *) attrs + attrs->ksa_shell_off +
+                     sizeof(vki_spawn_attr_t), (HChar *) ARG2 +
+                     attrs->ksa_shell_off, attrs->ksa_shell_size);
+         attrs->ksa_shell_off += sizeof(vki_spawn_attr_t);
+      }
+      if (file_actions_size > 0) {
+         VG_(memcpy)((HChar *) attrs + attrs_size - file_actions_size,
+                     (HChar *) ARG2 + ARG3 - file_actions_size,
+                     file_actions_size);
+      }
+   } else {
+      /* existing kspawn_attr_t + spawn_attr_t */
+      attrs_size = ARG3;
+      attrs = VG_(malloc)("syswrap.spawn.3", attrs_size);
+      VG_(memcpy)(attrs, (void *) ARG2, attrs_size);
+   }
+   vki_spawn_attr_t *spa = (vki_spawn_attr_t *) ((HChar *) attrs +
+                                                 attrs->ksa_attr_off);
+
+   /* Convert argv and envp parts of argenv into their separate XArray's.
+      Duplicate strings because argv and envp will be then modified. */
+   XArray *argv = VG_(newXA)(VG_(malloc), "syswrap.spawn.4",
+                             VG_(free), sizeof(HChar *));
+   XArray *envp = VG_(newXA)(VG_(malloc), "syswrap.spawn.5",
+                             VG_(free), sizeof(HChar *));
+
+   HChar *argenv = (HChar *) ARG4;
+   XArray *current_xa = argv;
+   while ((Addr) argenv < ARG4 + ARG5) {
+      if (*argenv == '\0') {
+         argenv += 1;
+         if (current_xa == argv) {
+            current_xa = envp;
+            if ((*argenv == '\0') && ((Addr) argenv == ARG4 + ARG5 - 1)) {
+               /* envp part is empty, it contained only {NULL}. */
+               break;
+            }
+         } else {
+            if ((Addr) argenv != ARG4 + ARG5) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "spawn: bogus argenv\n");
+               SET_STATUS_Failure(VKI_EINVAL);
+               goto exit;
+            }
+            break;
+         }
+      }
+
+      if (*argenv != '\1') {
+         if (VG_(clo_trace_syscalls))
+            VG_(debugLog)(3, "syswrap-solaris", "spawn: bogus argenv\n");
+         SET_STATUS_Failure(VKI_EINVAL);
+         goto exit;
+      }
+      argenv += 1;
+
+      HChar *duplicate = VG_(strdup)("syswrap.spawn.6", argenv);
+      VG_(addToXA)(current_xa, &duplicate);
+      argenv += VG_(strlen)(argenv) + 1;
+   }
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("\nARG1 = %#lx(%s)\n", ARG1, (HChar *) ARG1);
+      VG_(printf)("ARG4 (argv) = ");
+      for (Word i = 0; i < VG_(sizeXA)(argv); i++) {
+         VG_(printf)("%s ", *(HChar **) VG_(indexXA)(argv, i));
+      }
+
+      VG_(printf)("\nARG4 (envp) = ");
+      for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+         VG_(printf)("%s ", *(HChar **) VG_(indexXA)(envp, i));
+      }
+      VG_(printf)("\n");
+   }
+
+   /* Decide whether or not we want to trace the spawned child.
+      Omit the executable name itself from child_argv. */
+   const HChar **child_argv = VG_(malloc)("syswrap.spawn.7",
+                                     (VG_(sizeXA)(argv) - 1) * sizeof(HChar *));
+   for (Word i = 1; i < VG_(sizeXA)(argv); i++) {
+      child_argv[i - 1] = *(HChar **) VG_(indexXA)(argv, i);
+   }
+   Bool trace_this_child = VG_(should_we_trace_this_child)((HChar *) ARG1,
+                                                           child_argv);
+   VG_(free)(child_argv);
+
+   /* If we're tracing the child, and the launcher name looks bogus (possibly
+      because launcher.c couldn't figure it out, see comments therein) then we
+      have no option but to fail. */
+   if (trace_this_child &&
+       (!VG_(name_of_launcher) || VG_(name_of_launcher)[0] != '/')) {
+      SET_STATUS_Failure(VKI_ECHILD); /* "No child processes." */
+      goto exit;
+   }
+
+   /* Set up the child's exe path. */
+   const HChar *path = (const HChar *) ARG1;
+   const HChar *launcher_basename = NULL;
+   if (trace_this_child) {
+      /* We want to exec the launcher. */
+      path = VG_(name_of_launcher);
+      vg_assert(path != NULL);
+
+      launcher_basename = VG_(strrchr)(path, '/');
+      if ((launcher_basename == NULL) || (launcher_basename[1] == '\0')) {
+         launcher_basename = path;  /* hmm, tres dubious */
+      } else {
+         launcher_basename++;
+      }
+   }
+
+   /* 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, the child valgrind
+      will set up the appropriate client environment.
+
+      Then, if tracing the child, set VALGRIND_LIB for it. */
+   HChar **child_envp = VG_(calloc)("syswrap.spawn.8",
+                                    VG_(sizeXA)(envp) + 1, sizeof(HChar *));
+   for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+      child_envp[i] = *(HChar **) VG_(indexXA)(envp, i);
+   }
+   VG_(env_remove_valgrind_env_stuff)(child_envp, /* ro_strings */ False,
+                                      VG_(free));
+
+   /* Stuff was removed from child_envp, reflect that in envp XArray. */
+   VG_(dropTailXA)(envp, VG_(sizeXA)(envp));
+   for (UInt i = 0; child_envp[i] != NULL; i++) {
+      VG_(addToXA)(envp, &child_envp[i]);
+   }
+   VG_(free)(child_envp);
+
+   if (trace_this_child) {
+      /* Set VALGRIND_LIB in envp. */
+      SizeT len = VG_(strlen)(VALGRIND_LIB) + VG_(strlen)(VG_(libdir)) + 2;
+      HChar *valstr = VG_(malloc)("syswrap.spawn.9", len);
+      VG_(sprintf)(valstr, "%s=%s", VALGRIND_LIB, VG_(libdir));
+      VG_(addToXA)(envp, &valstr);
+   }
+
+   /* Set up the child's args. If not tracing it, they are left untouched.
+      Otherwise, they are:
+
+      [launcher_basename] ++ VG_(args_for_valgrind) ++ [ARG1] ++ ARG4[1..],
+
+      except that the first VG_(args_for_valgrind_noexecpass) args are
+      omitted. */
+   if (trace_this_child) {
+      vg_assert(VG_(args_for_valgrind) != NULL);
+      vg_assert(VG_(args_for_valgrind_noexecpass) >= 0);
+      vg_assert(VG_(args_for_valgrind_noexecpass)
+                   <= VG_(sizeXA)(VG_(args_for_valgrind)));
+
+      /* So what args will there be? Bear with me... */
+      /* ... launcher basename, ... */
+      HChar *duplicate = VG_(strdup)("syswrap.spawn.10", launcher_basename);
+      VG_(insertIndexXA)(argv, 0, &duplicate);
+
+      /* ... Valgrind's args, ... */
+      UInt v_args = VG_(sizeXA)(VG_(args_for_valgrind));
+      v_args -= VG_(args_for_valgrind_noexecpass);
+      for (Word i = VG_(args_for_valgrind_noexecpass);
+           i < VG_(sizeXA)(VG_(args_for_valgrind)); i++) {
+         duplicate = VG_(strdup)("syswrap.spawn.11",
+                           *(HChar **) VG_(indexXA)(VG_(args_for_valgrind), i));
+         VG_(insertIndexXA)(argv, 1 + i, &duplicate);
+      }
+
+      /* ... name of client executable, ... */
+      duplicate = VG_(strdup)("syswrap.spawn.12", (HChar *) ARG1);
+      VG_(insertIndexXA)(argv, 1 + v_args, &duplicate);
+
+      /* ... and args for client executable (without [0]). */
+      duplicate = *(HChar **) VG_(indexXA)(argv, 1 + v_args + 1);
+      VG_(free)(duplicate);
+      VG_(removeIndexXA)(argv, 1 + v_args + 1);
+   }
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("\npath = %s\n", path);
+      VG_(printf)("argv = ");
+      for (Word i = 0; i < VG_(sizeXA)(argv); i++) {
+         VG_(printf)("%s ", *(HChar **) VG_(indexXA)(argv, i));
+      }
+
+      VG_(printf)("\nenvp = ");
+      for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+         VG_(printf)("%s ", *(HChar **) VG_(indexXA)(envp, i));
+      }
+      VG_(printf)("\n");
+   }
+
+   /* Set the signal state up for spawned child.
+
+      Signals set to be caught are equivalent to signals set to the default
+      action, from the child's perspective.
+
+      Therefore query SCSS and prepare default (DFL) and ignore (IGN) signal
+      sets. Then combine these sets with those passed from client, if flags
+      POSIX_SPAWN_SETSIGDEF, or POSIX_SPAWN_SETSIGIGN_NP have been specified.
+   */
+   vki_sigset_t sig_default;
+   vki_sigset_t sig_ignore;
+   VG_(sigemptyset)(&sig_default);
+   VG_(sigemptyset)(&sig_ignore);
+   for (Int i = 1; i < VG_(max_signal); i++) {
+      vki_sigaction_fromK_t sa;
+      VG_(do_sys_sigaction)(i, NULL, &sa); /* query SCSS */
+      if (sa.sa_handler == VKI_SIG_IGN) {
+         VG_(sigaddset)(&sig_ignore, i);
+      } else {
+         VG_(sigaddset)(&sig_default, i);
+      }
+   }
+
+   if (spa->sa_psflags & VKI_POSIX_SPAWN_SETSIGDEF) {
+      VG_(sigaddset_from_set)(&spa->sa_sigdefault, &sig_default);
+   } else {
+      spa->sa_psflags |= VKI_POSIX_SPAWN_SETSIGDEF;
+      spa->sa_sigdefault = sig_default;
+   }
+
+   if (spa->sa_psflags & VKI_POSIX_SPAWN_SETSIGIGN_NP) {
+      VG_(sigaddset_from_set)(&spa->sa_sigignore, &sig_ignore);
+   } else {
+      spa->sa_psflags |= VKI_POSIX_SPAWN_SETSIGIGN_NP;
+      spa->sa_sigignore = sig_ignore;
+   }
+
+   /* Set the signal mask for spawned child.
+
+      Analogous to signal handlers: query SCSS for blocked signals mask
+      and combine this mask with that passed from client, if flag
+      POSIX_SPAWN_SETSIGMASK has been specified. */
+   vki_sigset_t *sigmask = &VG_(get_ThreadState)(tid)->sig_mask;
+   if (spa->sa_psflags & VKI_POSIX_SPAWN_SETSIGMASK) {
+      VG_(sigaddset_from_set)(&spa->sa_sigmask, sigmask);
+   } else {
+      spa->sa_psflags |= VKI_POSIX_SPAWN_SETSIGMASK;
+      spa->sa_sigmask = *sigmask;
+   }
+
+   /* Lastly, reconstruct argenv from argv + envp. */
+   SizeT argenv_size = 1 + 1;
+   for (Word i = 0; i < VG_(sizeXA)(argv); i++) {
+      argenv_size += VG_(strlen)(*(HChar **) VG_(indexXA)(argv, i)) + 2;
+   }
+   for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+      argenv_size += VG_(strlen)(*(HChar **) VG_(indexXA)(envp, i)) + 2;
+   }
+
+   argenv = VG_(malloc)("syswrap.spawn.13", argenv_size);
+   HChar *current = argenv;
+#define COPY_CHAR_TO_ARGENV(dst, character) \
+   do {                                     \
+      *(dst) = character;                   \
+      (dst) += 1;                           \
+   } while (0)
+#define COPY_STRING_TO_ARGENV(dst, src)       \
+   do {                                       \
+      COPY_CHAR_TO_ARGENV(dst, '\1');         \
+      SizeT src_len = VG_(strlen)((src)) + 1; \
+      VG_(memcpy)((dst), (src), src_len);     \
+      (dst) += src_len;                       \
+   } while (0)
+
+   for (Word i = 0; i < VG_(sizeXA)(argv); i++) {
+      COPY_STRING_TO_ARGENV(current, *(HChar **) VG_(indexXA)(argv, i));
+   }
+   COPY_CHAR_TO_ARGENV(current, '\0');
+   for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+      COPY_STRING_TO_ARGENV(current, *(HChar **) VG_(indexXA)(envp, i));
+   }
+   COPY_CHAR_TO_ARGENV(current, '\0');
+   vg_assert(current == argenv + argenv_size);
+#undef COPY_CHAR_TO_ARGENV
+#undef COPY_STRING_TOARGENV
+
+   /* HACK: Temporarily restore the DATA rlimit for spawned child.
+      This is a terrible hack to provide sensible brk limit for child. */
+   VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
+   /* Actual spawn() syscall. */
+   SysRes res = VG_(do_syscall5)(__NR_spawn, (UWord) path, (UWord) attrs,
+                                 attrs_size, (UWord) argenv, argenv_size);
+   SET_STATUS_from_SysRes(res);
+   VG_(free)(argenv);
+
+   /* Restore DATA rlimit back to its previous value set in m_main.c. */
+   struct vki_rlimit zero = { 0, 0 };
+   zero.rlim_max = VG_(client_rlimit_data).rlim_max;
+   VG_(setrlimit)(VKI_RLIMIT_DATA, &zero);
+
+   if (SUCCESS) {
+      PRINT("   spawn: process %d spawned child %ld\n", VG_(getpid)(), RES);
+   }
+
+exit:
+   VG_(free)(attrs);
+   for (Word i = 0; i < VG_(sizeXA)(argv); i++) {
+      VG_(free)(*(HChar **) VG_(indexXA)(argv, i));
+   }
+   for (Word i = 0; i < VG_(sizeXA)(envp); i++) {
+      VG_(free)(*(HChar **) VG_(indexXA)(envp, i));
+   }
+   VG_(deleteXA)(argv);
+   VG_(deleteXA)(envp);
+}
+#endif /* SOLARIS_SPAWN_SYSCALL */
+
+/* Handles the case where the open is of /proc/self/psinfo or
+   /proc/<pid>/psinfo. Fetch fresh contents into psinfo_t,
+   fake fname, psargs, argc and argv. Write the structure to the fake
+   file we cooked up at startup (in m_main) and give out a copy of this
+   fd. Also seek the cloned fd back to the start. */
+static Bool handle_psinfo_open(SyscallStatus *status,
+                               Bool use_openat,
+                               const HChar *filename,
+                               Int arg1, UWord arg3, UWord arg4)
+{
+   if (!ML_(safe_to_deref)((const void *) filename, 1))
+      return False;
+
+   HChar name[VKI_PATH_MAX];    // large enough
+   VG_(sprintf)(name, "/proc/%d/psinfo", VG_(getpid)());
+
+   if (!VG_STREQ(filename, name) && !VG_STREQ(filename, "/proc/self/psinfo"))
+      return False;
+
+   /* use original arguments to open or openat */
+   SysRes sres;
+#if defined(SOLARIS_OLD_SYSCALLS)
+   if (use_openat)
+      sres = VG_(do_syscall4)(SYS_openat, arg1, (UWord) filename,
+                              arg3, arg4);
+   else
+      sres = VG_(do_syscall3)(SYS_open, (UWord) filename, arg3, arg4);
+#else
+   vg_assert(use_openat == True);
+   sres = VG_(do_syscall4)(SYS_openat, arg1, (UWord) filename,
+                           arg3, arg4);
+#endif /* SOLARIS_OLD_SYSCALLS */
+
+   if (sr_isError(sres)) {
+      SET_STATUS_from_SysRes(sres);
+      return True;
+   }
+   Int fd = sr_Res(sres);
+
+   vki_psinfo_t psinfo;
+   sres = VG_(do_syscall3)(SYS_read, fd, (UWord) &psinfo, sizeof(psinfo));
+   if (sr_isError(sres)) {
+      SET_STATUS_from_SysRes(sres);
+      VG_(close)(fd);
+      return True;
+   }
+   if (sr_Res(sres) != sizeof(psinfo)) {
+      SET_STATUS_Failure(VKI_ENODATA);
+      VG_(close)(fd);
+      return True;
+   }
+
+   VG_(close)(fd);
+
+   VG_(client_fname)(psinfo.pr_fname, sizeof(psinfo.pr_fname), True);
+   VG_(client_cmd_and_args)(psinfo.pr_psargs, sizeof(psinfo.pr_psargs));
+
+   Addr *ptr = (Addr *) VG_(get_initial_client_SP)();
+   psinfo.pr_argc = *ptr++;
+   psinfo.pr_argv = (Addr) ptr;
+
+   sres = VG_(do_syscall4)(SYS_pwrite, VG_(cl_psinfo_fd),
+                           (UWord) &psinfo, sizeof(psinfo), 0);
+   if (sr_isError(sres)) {
+      SET_STATUS_from_SysRes(sres);
+      return True;
+   }
+
+   sres = VG_(dup)(VG_(cl_psinfo_fd));
+   SET_STATUS_from_SysRes(sres);
+   if (!sr_isError(sres)) {
+      OffT off = VG_(lseek)(sr_Res(sres), 0, VKI_SEEK_SET);
+      if (off < 0)
+         SET_STATUS_Failure(VKI_EMFILE);
+   }
+
+   return True;
+}
+
+#if defined(SOLARIS_OLD_SYSCALLS)
+PRE(sys_open)
+{
+   /* int open(const char *filename, int flags);
+      int open(const char *filename, int flags, mode_t mode); */
+
+   if (ARG2 & VKI_O_CREAT) {
+      /* 3-arg version */
+      PRINT("sys_open ( %#lx(%s), %ld, %ld )", ARG1, (HChar *) ARG1,
+            ARG2, ARG3);
+      PRE_REG_READ3(long, "open", const char *, filename,
+                    int, flags, vki_mode_t, mode);
+   } else {
+      /* 2-arg version */
+      PRINT("sys_open ( %#lx(%s), %ld )", ARG1, (HChar *) ARG1, ARG2);
+      PRE_REG_READ2(long, "open", const char *, filename, int, flags);
+   }
+
+   PRE_MEM_RASCIIZ("open(filename)", ARG1);
+
+   if (ML_(handle_auxv_open)(status, (const HChar*)ARG1, ARG2))
+      return;
+
+   if (handle_psinfo_open(status, False /*use_openat*/, (const HChar*)ARG1, 0,
+                          ARG2, ARG3))
+      return;
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_open)
+{
+   if (!ML_(fd_allowed)(RES, "open", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure(VKI_EMFILE);
+   } else if (VG_(clo_track_fds))
+      ML_(record_fd_open_with_given_name)(tid, RES, (HChar *) ARG1);
+}
+#endif /* SOLARIS_OLD_SYSCALLS */
+
+PRE(sys_close)
+{
+   WRAPPER_PRE_NAME(generic, sys_close)(tid, layout, arrghs, status,
+                                        flags);
+}
+
+POST(sys_close)
+{
+   WRAPPER_POST_NAME(generic, sys_close)(tid, arrghs, status);
+   door_revoke(tid, ARG1);
+   /* Possibly an explicitly open'ed client door fd was just closed.
+      Generic sys_close wrapper calls this only if VG_(clo_track_fds) = True. */
+   if (!VG_(clo_track_fds))
+      ML_(record_fd_close)(ARG1);
+}
+
+PRE(sys_linkat)
+{
+   /* int linkat(int fd1, const char *path1, int fd2,
+                 const char *path2, int flag);
+    */
+
+   /* Interpret the first and third arguments as 32-bit values even on 64-bit
+      architecture. This is different from Linux, for example, where glibc
+      sign-extends them. */
+   Int fd1 = (Int) ARG1;
+   Int fd2 = (Int) ARG3;
+
+   PRINT("sys_linkat ( %d, %#lx(%s), %d, %#lx(%s), %ld )",
+         fd1, ARG2, (HChar *) ARG2, fd2, ARG4, (HChar *) ARG4, ARG5);
+   PRE_REG_READ5(long, "linkat", int, fd1, const char *, path1,
+                 int, fd2, const char *, path2, int, flags);
+   PRE_MEM_RASCIIZ("linkat(path1)", ARG2);
+   PRE_MEM_RASCIIZ("linkat(path2)", ARG4);
+
+   /* Be strict but ignore fd1/fd2 for absolute path1/path2. */
+   if (fd1 != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd1, "linkat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   }
+   if (fd2 != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG4, 1)
+       && ((HChar *) ARG4)[0] != '/'
+       && !ML_(fd_allowed)(fd2, "linkat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   }
+
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_symlinkat)
+{
+   /* int symlinkat(const char *path1, int fd, const char *path2); */
+
+   /* Interpret the second argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG2;
+
+   PRINT("sys_symlinkat ( %#lx(%s), %d, %#lx(%s) )",
+         ARG1, (HChar *) ARG1, fd, ARG3, (HChar *) ARG3);
+   PRE_REG_READ3(long, "symlinkat", const char *, path1, int, fd,
+                 const char *, path2);
+   PRE_MEM_RASCIIZ("symlinkat(path1)", ARG1);
+   PRE_MEM_RASCIIZ("symlinkat(path2)", ARG3);
+
+   /* Be strict but ignore fd for absolute path2. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG3, 1)
+       && ((HChar *) ARG3)[0] != '/'
+       && !ML_(fd_allowed)(fd, "symlinkat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_time)
+{
+   /* time_t time(); */
+   PRINT("sys_time ( )");
+   PRE_REG_READ0(long, "time");
+}
+
+/* Data segment for brk (heap).
+   Initial data segment is established during image initialization
+   (initimg-solaris.c). Notable facts:
+   - VG_(brk_base) is not page aligned; does not move
+   - VG_(brk_limit) moves between [VG_(brk_base), data segment end]
+   - data segment end is always page aligned
+   - right after data segment end is 1-page reservation
+
+            |      heap           |
+     +------+------+--------------+-------+
+     | BSS  | anon |   anon       | resvn |
+     +------+------+--------------+-------+
+
+            ^      ^        ^    ^
+            |      |        |    |
+            |      |        |    data segment end
+            |      |        VG_(brk_limit) -- no alignment constraint
+            |      brk_base_pgup -- page aligned
+            VG_(brk_base) -- not page aligned -- does not move
+
+   Because VG_(brk_base) is not page-aligned and is initially located within
+   pre-established data segment, special care has to be taken in the code below
+   to handle this feature.
+*/
+
+PRE(sys_brk)
+{
+   /* unsigned long brk(caddr_t end_data_segment); */
+   /* The Solaris kernel returns 0 on success.
+      In addition to this, brk(0) returns current data segment end.  This is
+      very different from the Linux kernel, for example. */
+
+   Addr old_brk_limit = VG_(brk_limit);
+   /* If VG_(brk_base) is page-aligned then old_brk_base_pgup is equal to
+      VG_(brk_base). */
+   Addr old_brk_base_pgup = VG_PGROUNDUP(VG_(brk_base));
+   Addr new_brk = ARG1;
+   const NSegment *seg, *seg2;
+
+   PRINT("sys_brk ( %#lx )", ARG1);
+   PRE_REG_READ1(unsigned long, "brk", vki_caddr_t, end_data_segment);
+
+   if (!new_brk) {
+      /* brk(0) - specific to Solaris 11 only. */
+      SET_STATUS_Success(old_brk_limit);
+      return;
+   }
+
+   /* Handle some trivial cases. */
+   if (new_brk == old_brk_limit) {
+      SET_STATUS_Success(0);
+      return;
+   }
+   if (new_brk < VG_(brk_base)) {
+      /* Clearly impossible. */
+      SET_STATUS_Failure(VKI_ENOMEM);
+      return;
+   }
+   if (new_brk - VG_(brk_base) > VG_(client_rlimit_data).rlim_cur) {
+      SET_STATUS_Failure(VKI_ENOMEM);
+      return;
+   }
+
+   if (new_brk < old_brk_limit) {
+      /* Shrinking the data segment.  Be lazy and don't munmap the excess
+         area. */
+      if (old_brk_limit > old_brk_base_pgup) {
+         /* Calculate new local brk (=MAX(new_brk, old_brk_base_pgup)). */
+         Addr new_brk_local;
+         if (new_brk < old_brk_base_pgup)
+            new_brk_local = old_brk_base_pgup;
+         else
+            new_brk_local = new_brk;
+
+         /* Find a segment at the beginning and at the end of the shrinked
+            range. */
+         seg = VG_(am_find_nsegment)(new_brk_local);
+         seg2 = VG_(am_find_nsegment)(old_brk_limit - 1);
+         vg_assert(seg);
+         vg_assert(seg->kind == SkAnonC);
+         vg_assert(seg2);
+         vg_assert(seg == seg2);
+
+         /* Discard any translations and zero-out the area. */
+         if (seg->hasT)
+            VG_(discard_translations)(new_brk_local,
+                                      old_brk_limit - new_brk_local,
+                                      "do_brk(shrink)");
+        /* Since we're being lazy and not unmapping pages, we have to zero out
+           the area, so that if the area later comes back into circulation, it
+           will be filled with zeroes, as if it really had been unmapped and
+           later remapped.  Be a bit paranoid and try hard to ensure we're not
+           going to segfault by doing the write - check that segment is
+           writable. */
+         if (seg->hasW)
+            VG_(memset)((void*)new_brk_local, 0, old_brk_limit - new_brk_local);
+      }
+
+      /* Fixup code if the VG_(brk_base) is not page-aligned. */
+      if (new_brk < old_brk_base_pgup) {
+         /* Calculate old local brk (=MIN(old_brk_limit, old_brk_base_up)). */
+         Addr old_brk_local;
+         if (old_brk_limit < old_brk_base_pgup)
+            old_brk_local = old_brk_limit;
+         else
+            old_brk_local = old_brk_base_pgup;
+
+         /* Find a segment at the beginning and at the end of the shrinked
+            range. */
+         seg = VG_(am_find_nsegment)(new_brk);
+         seg2 = VG_(am_find_nsegment)(old_brk_local - 1);
+         vg_assert(seg);
+         vg_assert(seg2);
+         vg_assert(seg == seg2);
+
+         /* Discard any translations and zero-out the area. */
+         if (seg->hasT)
+            VG_(discard_translations)(new_brk, old_brk_local - new_brk,
+                                      "do_brk(shrink)");
+         if (seg->hasW)
+            VG_(memset)((void*)new_brk, 0, old_brk_local - new_brk);
+      }
+
+      /* We are done, update VG_(brk_limit), tell the tool about the changes,
+         and leave. */
+      VG_(brk_limit) = new_brk;
+      VG_TRACK(die_mem_brk, new_brk, old_brk_limit - new_brk);
+      SET_STATUS_Success(0);
+      return;
+   }
+
+   /* We are expanding the brk segment. */
+
+   /* Fixup code if the VG_(brk_base) is not page-aligned. */
+   if (old_brk_limit < old_brk_base_pgup) {
+      /* Calculate new local brk (=MIN(new_brk, old_brk_base_pgup)). */
+      Addr new_brk_local;
+      if (new_brk < old_brk_base_pgup)
+         new_brk_local = new_brk;
+      else
+         new_brk_local = old_brk_base_pgup;
+
+      /* Find a segment at the beginning and at the end of the expanded
+         range. */
+      seg = VG_(am_find_nsegment)(old_brk_limit);
+      seg2 = VG_(am_find_nsegment)(new_brk_local - 1);
+      vg_assert(seg);
+      vg_assert(seg2);
+      vg_assert(seg == seg2);
+
+      /* Nothing else to do. */
+   }
+
+   if (new_brk > old_brk_base_pgup) {
+      /* Calculate old local brk (=MAX(old_brk_limit, old_brk_base_pgup)). */
+      Addr old_brk_local;
+      if (old_brk_limit < old_brk_base_pgup)
+         old_brk_local = old_brk_base_pgup;
+      else
+         old_brk_local = old_brk_limit;
+
+      /* Find a segment at the beginning of the expanded range. */
+      if (old_brk_local > old_brk_base_pgup)
+         seg = VG_(am_find_nsegment)(old_brk_local - 1);
+      else
+         seg = VG_(am_find_nsegment)(old_brk_local);
+      vg_assert(seg);
+      vg_assert(seg->kind == SkAnonC);
+
+      /* Find the 1-page reservation segment. */
+      seg2 = VG_(am_next_nsegment)(seg, True/*forwards*/);
+      vg_assert(seg2);
+      vg_assert(seg2->kind == SkResvn);
+      vg_assert(seg->end + 1 == seg2->start);
+      vg_assert(seg2->end - seg2->start + 1 == VKI_PAGE_SIZE);
+
+      if (new_brk <= seg2->start) {
+         /* Still fits within the existing anon segment, nothing to do. */
+      } else {
+         /* Data segment limit was already checked. */
+         Addr anon_start = seg->end + 1;
+         Addr resvn_start = VG_PGROUNDUP(new_brk);
+         SizeT anon_size = resvn_start - anon_start;
+         SizeT resvn_size = VKI_PAGE_SIZE;
+         SysRes sres;
+
+         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(anon_size > 0);
+
+         /* Address space manager checks for free address space for us;
+            reservation would not be otherwise created. */
+         Bool ok = VG_(am_create_reservation)(resvn_start, resvn_size, SmLower,
+                                              anon_size);
+         if (!ok) {
+            VG_(umsg)("brk segment overflow in thread #%d: can't grow "
+                      "to %#lx\n", tid, new_brk);
+            SET_STATUS_Failure(VKI_ENOMEM);
+            return;
+         }
+
+         /* Establish protection from the existing segment. */
+         UInt prot = (seg->hasR ? VKI_PROT_READ : 0)
+                     | (seg->hasW ? VKI_PROT_WRITE : 0)
+                     | (seg->hasX ? VKI_PROT_EXEC : 0);
+
+         /* Address space manager will merge old and new data segments. */
+         sres = VG_(am_mmap_anon_fixed_client)(anon_start, anon_size, prot);
+         if (sr_isError(sres)) {
+            VG_(umsg)("Cannot map memory to grow brk segment in thread #%d "
+                      "to %#lx\n", tid, new_brk);
+            SET_STATUS_Failure(VKI_ENOMEM);
+            return;
+         }
+         vg_assert(sr_Res(sres) == anon_start);
+
+         seg = VG_(am_find_nsegment)(old_brk_base_pgup);
+         seg2 = VG_(am_find_nsegment)(VG_PGROUNDUP(new_brk) - 1);
+         vg_assert(seg);
+         vg_assert(seg2);
+         vg_assert(seg == seg2);
+         vg_assert(new_brk <= seg->end + 1);
+      }
+   }
+
+   /* We are done, update VG_(brk_limit), tell the tool about the changes, and
+      leave. */
+   VG_(brk_limit) = new_brk;
+   VG_TRACK(new_mem_brk, old_brk_limit, new_brk - old_brk_limit, tid);
+   SET_STATUS_Success(0);
+}
+
+PRE(sys_stat)
+{
+   /* int stat(const char *path, struct stat *buf); */
+   /* Note: We could use here the sys_newstat generic wrapper, but the 'new'
+      in its name is rather confusing in the Solaris context, thus we provide
+      our own wrapper. */
+   PRINT("sys_stat ( %#lx(%s), %#lx )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "stat", const char *, path, struct stat *, buf);
+
+   PRE_MEM_RASCIIZ("stat(path)", ARG1);
+   PRE_MEM_WRITE("stat(buf)", ARG2, sizeof(struct vki_stat));
+}
+
+POST(sys_stat)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat));
+}
+
+PRE(sys_lseek)
+{
+   /* off_t lseek(int fildes, off_t offset, int whence); */
+   PRINT("sys_lseek ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "lseek", int, fildes, vki_off_t, offset, int, whence);
+
+   /* Stay sane. */
+   if (!ML_(fd_allowed)(ARG1, "lseek", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_mount)
+{
+   /* int mount(const char *spec, const char *dir, int mflag, char *fstype,
+                char *dataptr, int datalen, char *optptr, int optlen); */
+   *flags |= SfMayBlock;
+   if (ARG3 & VKI_MS_OPTIONSTR) {
+      /* 8-argument mount */
+      PRINT("sys_mount ( %#lx(%s), %#lx(%s), %ld, %#lx(%s), %#lx, %ld, "
+            "%#lx(%s), %ld )", ARG1, (HChar *) ARG1, ARG2, (HChar *) ARG2, ARG3,
+            ARG4, (HChar *) ARG4, ARG5, ARG6, ARG7, (HChar *) ARG7, ARG8);
+      PRE_REG_READ8(long, "mount", const char *, spec, const char *, dir,
+                    int, mflag, char *, fstype, char *, dataptr, int, datalen,
+                    char *, optptr, int, optlen);
+   }
+   else if (ARG3 & VKI_MS_DATA) {
+      /* 6-argument mount */
+      PRINT("sys_mount ( %#lx(%s), %#lx(%s), %ld, %#lx(%s), %#lx, %ld )",
+            ARG1, (HChar *) ARG1, ARG2, (HChar *) ARG2, ARG3, ARG4,
+            (HChar *) ARG4, ARG5, ARG6);
+      PRE_REG_READ6(long, "mount", const char *, spec, const char *, dir,
+                    int, mflag, char *, fstype, char *, dataptr,
+                    int, datalen);
+   }
+   else {
+      /* 4-argument mount */
+      PRINT("sys_mount ( %#lx(%s), %#lx(%s), %ld, %#lx(%s) )", ARG1,
+            (HChar *) ARG1, ARG2, (HChar *) ARG2, ARG3, ARG4, (HChar *) ARG4);
+      PRE_REG_READ4(long, "mount", const char *, spec, const char *, dir,
+                    int, mflag, char *, fstype);
+   }
+   if (ARG1)
+      PRE_MEM_RASCIIZ("mount(spec)", ARG1);
+   PRE_MEM_RASCIIZ("mount(dir)", ARG2);
+   if (ARG4 && ARG4 >= 256) {
+      /* If ARG4 < 256, then it's an index to a fs table in the kernel. */
+      PRE_MEM_RASCIIZ("mount(fstype)", ARG4);
+   }
+   if (ARG3 & (VKI_MS_DATA | VKI_MS_OPTIONSTR)) {
+      if (ARG5)
+         PRE_MEM_READ("mount(dataptr)", ARG5, ARG6);
+      if ((ARG3 & VKI_MS_OPTIONSTR) && ARG7) {
+         /* in/out buffer */
+         PRE_MEM_RASCIIZ("mount(optptr)", ARG7);
+         PRE_MEM_WRITE("mount(optptr)", ARG7, ARG8);
+      }
+   }
+}
+
+POST(sys_mount)
+{
+   if (ARG3 & VKI_MS_OPTIONSTR) {
+      POST_MEM_WRITE(ARG7, VG_(strlen)((HChar*)ARG7) + 1);
+   } else if (ARG3 & VKI_MS_DATA) {
+      if ((ARG2) &&
+          (ARG3 & MS_NOMNTTAB) &&
+          (VG_STREQ((HChar *) ARG4, "namefs")) &&
+          (ARG6 == sizeof(struct vki_namefd)) &&
+          ML_(safe_to_deref)((void *) ARG5, ARG6)) {
+         /* Most likely an fattach() call for a door file descriptor. */
+         door_server_fattach(((struct vki_namefd *) ARG5)->fd, (HChar *) ARG2);
+      }
+   }
+}
+
+PRE(sys_readlinkat)
+{
+   /* ssize_t readlinkat(int dfd, const char *path, char *buf,
+                         size_t bufsiz); */
+   HChar name[30];    // large enough
+   Word saved = SYSNO;
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int dfd = (Int) ARG1;
+
+   PRINT("sys_readlinkat ( %d, %#lx(%s), %#lx, %lu )", dfd, ARG2,
+         (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "readlinkat", int, dfd, const char *, path,
+                 char *, buf, int, bufsiz);
+   PRE_MEM_RASCIIZ("readlinkat(path)", ARG2);
+   PRE_MEM_WRITE("readlinkat(buf)", ARG3, ARG4);
+
+   /* Be strict but ignore dfd for absolute path. */
+   if (dfd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(dfd, "readlinkat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+      return;
+   }
+
+   /* Handle the case where readlinkat is looking at /proc/self/path/a.out or
+      /proc/<pid>/path/a.out. */
+   VG_(sprintf)(name, "/proc/%d/path/a.out", VG_(getpid)());
+   if (ML_(safe_to_deref)((void*)ARG2, 1) &&
+       (!VG_(strcmp)((HChar*)ARG2, name) ||
+        !VG_(strcmp)((HChar*)ARG2, "/proc/self/path/a.out"))) {
+      VG_(sprintf)(name, "/proc/self/path/%d", VG_(cl_exec_fd));
+      SET_STATUS_from_SysRes(VG_(do_syscall4)(saved, dfd, (UWord)name, ARG3,
+                                              ARG4));
+   }
+}
+
+POST(sys_readlinkat)
+{
+   POST_MEM_WRITE(ARG3, RES);
+}
+
+PRE(sys_stime)
+{
+   /* Kernel: int stime(time_t time); */
+   PRINT("sys_stime ( %ld )", ARG1);
+   PRE_REG_READ1(long, "stime", vki_time_t, time);
+}
+
+PRE(sys_fstat)
+{
+   /* int fstat(int fildes, struct stat *buf); */
+   /* Note: We could use here the sys_newfstat generic wrapper, but the 'new'
+      in its name is rather confusing in the Solaris context, thus we provide
+      our own wrapper. */
+   PRINT("sys_fstat ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "fstat", int, fildes, struct stat *, buf);
+   PRE_MEM_WRITE("fstat(buf)", ARG2, sizeof(struct vki_stat));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fstat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstat)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat));
+}
+
+#if defined(SOLARIS_FREALPATHAT_SYSCALL)
+PRE(sys_frealpathat)
+{
+   /* int frealpathat(int fd, char *path, char *buf, size_t buflen); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_frealpathat ( %d, %#lx(%s), %#lx, %ld )",
+         fd, ARG2, (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "frealpathat", int, fd, char *, path,
+                 char *, buf, vki_size_t, buflen);
+   PRE_MEM_RASCIIZ("frealpathat(path)", ARG2);
+   PRE_MEM_WRITE("frealpathat(buf)", ARG3, ARG4);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "frealpathat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_frealpathat)
+{
+   POST_MEM_WRITE(ARG3, VG_(strlen)((HChar *) ARG3) + 1);
+}
+#endif /* SOLARIS_FREALPATHAT_SYSCALL */
+
+PRE(sys_stty)
+{
+   /* int stty(int fd, const struct sgttyb *tty); */
+   PRINT("sys_stty ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "stty", int, fd,
+                 const struct vki_sgttyb *, tty);
+   PRE_MEM_READ("stty(tty)", ARG2, sizeof(struct vki_sgttyb));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "stty", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_gtty)
+{
+   /* int gtty(int fd, struct sgttyb *tty); */
+   PRINT("sys_gtty ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "gtty", int, fd, struct vki_sgttyb *, tty);
+   PRE_MEM_WRITE("gtty(tty)", ARG2, sizeof(struct vki_sgttyb));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "gtty", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_gtty)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_sgttyb));
+}
+
+PRE(sys_pgrpsys)
+{
+   /* Kernel: int setpgrp(int flag, int pid, int pgid); */
+   switch (ARG1 /*flag*/) {
+   case 0:
+      /* Libc: pid_t getpgrp(void); */
+      PRINT("sys_pgrpsys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("pgrpsys", "getpgrp"), int, flag);
+      break;
+   case 1:
+      /* Libc: pid_t setpgrp(void); */
+      PRINT("sys_pgrpsys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("pgrpsys", "setpgrp"), int, flag);
+      break;
+   case 2:
+      /* Libc: pid_t getsid(pid_t pid); */
+      PRINT("sys_pgrpsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("pgrpsys", "getsid"), int, flag,
+                    vki_pid_t, pid);
+      break;
+   case 3:
+      /* Libc: pid_t setsid(void); */
+      PRINT("sys_pgrpsys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("pgrpsys", "setsid"), int, flag);
+      break;
+   case 4:
+      /* Libc: pid_t getpgid(pid_t pid); */
+      PRINT("sys_pgrpsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("pgrpsys", "getpgid"), int, flag,
+                    vki_pid_t, pid);
+      break;
+   case 5:
+      /* Libc: int setpgid(pid_t pid, pid_t pgid); */
+      PRINT("sys_pgrpsys ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("pgrpsys", "setpgid"), int, flag,
+                    vki_pid_t, pid, vki_pid_t, pgid);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the pgrpsys call with flag %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+PRE(sys_pipe)
+{
+#if defined(SOLARIS_NEW_PIPE_SYSCALL)
+   /* int pipe(int fildes[2], int flags); */
+   PRINT("sys_pipe ( %#lx, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "pipe", int *, fildes, int, flags);
+   PRE_MEM_WRITE("pipe(fildes)", ARG1, 2 * sizeof(int));
+#else
+   /* longlong_t pipe(); */
+   PRINT("sys_pipe ( )");
+   PRE_REG_READ0(long, "pipe");
+#endif /* SOLARIS_NEW_PIPE_SYSCALL */
+}
+
+POST(sys_pipe)
+{
+   Int p0, p1;
+
+#if defined(SOLARIS_NEW_PIPE_SYSCALL)
+   int *fds = (int*)ARG1;
+   p0 = fds[0];
+   p1 = fds[1];
+   POST_MEM_WRITE(ARG1, 2 * sizeof(int));
+#else
+   p0 = RES;
+   p1 = RESHI;
+#endif /* SOLARIS_NEW_PIPE_SYSCALL */
+
+   if (!ML_(fd_allowed)(p0, "pipe", tid, True) ||
+       !ML_(fd_allowed)(p1, "pipe", tid, True)) {
+      VG_(close)(p0);
+      VG_(close)(p1);
+      SET_STATUS_Failure(VKI_EMFILE);
+   }
+   else if (VG_(clo_track_fds)) {
+      ML_(record_fd_open_nameless)(tid, p0);
+      ML_(record_fd_open_nameless)(tid, p1);
+   }
+}
+
+PRE(sys_faccessat)
+{
+   /* int faccessat(int fd, const char *path, int amode, int flag); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_faccessat ( %d, %#lx(%s), %ld, %ld )", fd, ARG2,
+         (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "faccessat", int, fd, const char *, path,
+                 int, amode, int, flag);
+   PRE_MEM_RASCIIZ("faccessat(path)", ARG2);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "faccessat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_mknodat)
+{
+   /* int mknodat(int fd, char *fname, mode_t fmode, dev_t dev); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_mknodat ( %d, %#lx(%s), %ld, %ld )", fd, ARG2,
+         (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "mknodat", int, fd, const char *, fname,
+                 vki_mode_t, fmode, vki_dev_t, dev);
+   PRE_MEM_RASCIIZ("mknodat(fname)", ARG2);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "mknodat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_mknodat)
+{
+   if (!ML_(fd_allowed)(RES, "mknodat", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure(VKI_EMFILE);
+   } else if (VG_(clo_track_fds))
+      ML_(record_fd_open_with_given_name)(tid, RES, (HChar *) ARG2);
+}
+
+PRE(sys_sysi86)
+{
+   /* int sysi86(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3); */
+   PRINT("sys_sysi86 ( %ld, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "sysi86", int, cmd, uintptr_t, arg1, uintptr_t, arg2,
+                 uintptr_t, arg3);
+
+   switch (ARG1 /*cmd*/) {
+   case VKI_SI86FPSTART:
+      PRE_MEM_WRITE("sysi86(fp_hw)", ARG2, sizeof(vki_uint_t));
+      /* ARG3 is a desired x87 FCW value, ARG4 is a desired SSE MXCSR value.
+         They are passed to the kernel but V will change them later anyway
+         (this is a general Valgrind limitation described in the official
+         documentation). */
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the sysi86 call with cmd %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_sysi86)
+{
+   switch (ARG1 /*cmd*/) {
+   case VKI_SI86FPSTART:
+      POST_MEM_WRITE(ARG2, sizeof(vki_uint_t));
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_shmsys)
+{
+   /* Kernel: uintptr_t shmsys(int opcode, uintptr_t a0, uintptr_t a1,
+                               uintptr_t a2, uintptr_t a3);
+    */
+   *flags |= SfMayBlock;
+
+   switch (ARG1 /*opcode*/) {
+   case VKI_SHMAT:
+      /* Libc: void *shmat(int shmid, const void *shmaddr, int shmflg); */
+      PRINT("sys_shmsys ( %ld, %ld, %#lx, %ld )",
+            ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("shmsys", "shmat"), int, opcode,
+                    int, shmid, const void *, shmaddr, int, shmflg);
+
+      UWord addr = ML_(generic_PRE_sys_shmat)(tid, ARG2, ARG3, ARG4);
+      if (addr == 0)
+         SET_STATUS_Failure(VKI_EINVAL);
+      else
+         ARG3 = addr;
+      break;
+
+   case VKI_SHMCTL:
+      /* Libc: int shmctl(int shmid, int cmd, struct shmid_ds *buf); */
+      switch (ARG3 /* cmd */) {
+      case VKI_SHM_LOCK:
+         PRINT("sys_shmsys ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+         PRE_REG_READ3(long, SC3("shmsys", "shmctl", "lock"),
+                       int, opcode, int, shmid, int, cmd);
+         break;
+      case VKI_SHM_UNLOCK:
+         PRINT("sys_shmsys ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+         PRE_REG_READ3(long, SC3("shmsys", "shmctl", "unlock"),
+                       int, opcode, int, shmid, int, cmd);
+         break;
+      case VKI_IPC_RMID:
+         PRINT("sys_shmsys ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+         PRE_REG_READ3(long, SC3("shmsys", "shmctl", "rmid"),
+                       int, opcode, int, shmid, int, cmd);
+         break;
+      case VKI_IPC_SET:
+         PRINT("sys_shmsys ( %ld, %ld, %ld, %#lx )",
+               ARG1, ARG2, ARG3, ARG4);
+         PRE_REG_READ4(long, SC3("shmsys", "shmctl", "set"),
+                       int, opcode, int, shmid, int, cmd,
+                       struct vki_shmid_ds *, buf);
+
+         struct vki_shmid_ds *buf = (struct vki_shmid_ds *) ARG4;
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set, buf->shm_perm.uid)",
+                        buf->shm_perm.uid);
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set, buf->shm_perm.gid)",
+                        buf->shm_perm.gid);
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set, buf->shm_perm.mode)",
+                        buf->shm_perm.mode);
+         break;
+      case VKI_IPC_STAT:
+         PRINT("sys_shmsys ( %ld, %ld, %ld, %#lx )",
+               ARG1, ARG2, ARG3, ARG4);
+         PRE_REG_READ4(long, SC3("shmsys", "shmctl", "stat"),
+                       int, opcode, int, shmid, int, cmd,
+                       struct vki_shmid_ds *, buf);
+         PRE_MEM_WRITE("shmsys(shmctl, ipc_stat, buf)", ARG4,
+                       sizeof(struct vki_shmid_ds));
+        break;
+      case VKI_IPC_SET64:
+         PRINT("sys_shmsys ( %ld, %ld, %ld, %#lx )",
+               ARG1, ARG2, ARG3, ARG4);
+         PRE_REG_READ4(long, SC3("shmsys", "shmctl", "set64"),
+                       int, opcode, int, shmid, int, cmd,
+                       struct vki_shmid_ds64 *, buf);
+
+         struct vki_shmid_ds64 *buf64 = (struct vki_shmid_ds64 *) ARG4;
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set64, "
+                        "buf->shmx_perm.ipcx_uid)",
+                        buf64->shmx_perm.ipcx_uid);
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set64, "
+                        "buf->shmx_perm.ipcx_gid)",
+                        buf64->shmx_perm.ipcx_gid);
+         PRE_FIELD_READ("shmsys(shmctl, ipc_set64, "
+                        "buf->shmx_perm.ipcx_mode)",
+                        buf64->shmx_perm.ipcx_mode);
+         break;
+      case VKI_IPC_STAT64:
+         PRINT("sys_shmsys ( %ld, %ld, %ld, %#lx )",
+               ARG1, ARG2, ARG3, ARG4);
+         PRE_REG_READ4(long, SC3("shmsys", "shmctl", "stat64"),
+                       int, opcode, int, shmid, int, cmd,
+                       struct vki_shmid_ds64 *, buf);
+         PRE_MEM_WRITE("shmsys(shmctl, ipc_stat64, buf)", ARG4,
+                       sizeof(struct vki_shmid_ds64));
+         break;
+#if defined(SOLARIS_SHM_NEW)
+      case VKI_IPC_XSTAT64:
+         PRINT("sys_shmsys ( %ld, %ld, %ld, %#lx )",
+               ARG1, ARG2, ARG3, ARG4);
+         PRE_REG_READ4(long, SC3("shmsys", "shmctl", "xstat64"),
+                       int, opcode, int, shmid, int, cmd,
+                       struct vki_shmid_ds64 *, buf);
+         PRE_MEM_WRITE("shmsys(shmctl, ipc_xstat64, buf)", ARG4,
+                       sizeof(struct vki_shmid_xds64));
+         break;
+#endif /* SOLARIS_SHM_NEW */
+      default:
+         VG_(unimplemented)("Syswrap of the shmsys(shmctl) call with "
+                            "cmd %ld.", ARG3);
+         /*NOTREACHED*/
+         break;
+      }
+      break;
+
+   case VKI_SHMDT:
+      /* Libc: int shmdt(const void *shmaddr); */
+      PRINT("sys_shmsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("shmsys", "shmdt"), int, opcode,
+                    const void *, shmaddr);
+
+      if (!ML_(generic_PRE_sys_shmdt)(tid, ARG2))
+	 SET_STATUS_Failure(VKI_EINVAL);
+      break;
+
+   case VKI_SHMGET:
+      /* Libc: int shmget(key_t key, size_t size, int shmflg); */
+      PRINT("sys_shmsys ( %ld, %ld, %ld, %ld )",
+            ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("shmsys", "shmget"), int, opcode,
+                    vki_key_t, key, vki_size_t, size, int, shmflg);
+      break;
+
+   case VKI_SHMIDS:
+      /* Libc: int shmids(int *buf, uint_t nids, uint_t *pnids); */
+      PRINT("sys_shmsys ( %ld, %#lx, %ld, %#lx )",
+            ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("shmsys", "shmids"), int, opcode,
+                    int *, buf, vki_uint_t, nids, vki_uint_t *, pnids);
+
+      PRE_MEM_WRITE("shmsys(shmids, buf)", ARG2, ARG3 * sizeof(int *));
+      PRE_MEM_WRITE("shmsys(shmids, pnids)", ARG4, sizeof(vki_uint_t));
+      break;
+
+#if defined(SOLARIS_SHM_NEW)
+   case VKI_SHMADV:
+      /* Libc: int shmadv(int shmid, uint_t cmd, uint_t *advice); */
+      PRINT("sys_shmsys ( %ld, %ld, %ld, %ld )",
+            ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("shmsys", "shmadv"), int, opcode,
+                    int, shmid, vki_uint_t, cmd, vki_uint_t *, advice);
+
+      switch (ARG3 /*cmd*/) {
+      case VKI_SHM_ADV_GET:
+         PRE_MEM_WRITE("shmsys(shmadv, advice)", ARG4,
+                       sizeof(vki_uint_t));
+         break;
+      case VKI_SHM_ADV_SET:
+         PRE_MEM_READ("shmsys(shmadv, advice)", ARG4,
+                       sizeof(vki_uint_t));
+         break;
+      default:
+         VG_(unimplemented)("Syswrap of the shmsys(shmadv) call with "
+                            "cmd %ld.", ARG3);
+         /*NOTREACHED*/
+         break;
+      }
+      break;
+
+   case VKI_SHMGET_OSM:
+      /* Libc: int shmget_osm(key_t key, size_t size, int shmflg,
+                              size_t granule_sz);
+       */
+      PRINT("sys_shmsys ( %ld, %ld, %ld, %ld, %ld )",
+            ARG1, ARG2, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("shmsys", "shmget_osm"), int, opcode,
+                    vki_key_t, key, vki_size_t, size, int, shmflg,
+                    vki_size_t, granule_sz);
+      break;
+#endif /* SOLARIS_SHM_NEW */
+
+   default:
+      VG_(unimplemented)("Syswrap of the shmsys call with opcode %ld.",
+                         ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_shmsys)
+{
+   switch (ARG1 /*opcode*/) {
+   case VKI_SHMAT:
+      ML_(generic_POST_sys_shmat)(tid, RES, ARG2, ARG3, ARG4);
+      break;
+
+   case VKI_SHMCTL:
+      switch (ARG3 /*cmd*/) {
+      case VKI_SHM_LOCK:
+      case VKI_SHM_UNLOCK:
+      case VKI_IPC_RMID:
+      case VKI_IPC_SET:
+         break;
+      case VKI_IPC_STAT:
+         POST_MEM_WRITE(ARG4, sizeof(struct vki_shmid_ds));
+         break;
+      case VKI_IPC_SET64:
+         break;
+      case VKI_IPC_STAT64:
+         POST_MEM_WRITE(ARG4, sizeof(struct vki_shmid_ds64));
+         break;
+#if defined(SOLARIS_SHM_NEW)
+      case VKI_IPC_XSTAT64:
+         POST_MEM_WRITE(ARG4, sizeof(struct vki_shmid_xds64));
+         break;
+#endif /* SOLARIS_SHM_NEW */
+      default:
+         vg_assert(0);
+         break;
+      }
+      break;
+
+   case VKI_SHMDT:
+      ML_(generic_POST_sys_shmdt)(tid, RES, ARG2);
+      break;
+
+   case VKI_SHMGET:
+      break;
+
+   case VKI_SHMIDS:
+      {
+         POST_MEM_WRITE(ARG4, sizeof(vki_uint_t));
+
+         uint_t *pnids = (vki_uint_t *) ARG4;
+         if (*pnids <= ARG3)
+            POST_MEM_WRITE(ARG2, *pnids * sizeof(int *));
+      }
+      break;
+
+#if defined(SOLARIS_SHM_NEW)
+   case VKI_SHMADV:
+      switch (ARG3 /*cmd*/) {
+      case VKI_SHM_ADV_GET:
+         POST_MEM_WRITE(ARG4, sizeof(vki_uint_t));
+         break;
+      case VKI_SHM_ADV_SET:
+         break;
+      default:
+         vg_assert(0);
+         break;
+      }
+      break;
+
+   case VKI_SHMGET_OSM:
+      break;
+#endif /* SOLARIS_SHM_NEW */
+
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_semsys)
+{
+   /* Kernel: int semsys(int opcode, uintptr_t a1, uintptr_t a2, uintptr_t a3,
+                         uintptr_t a4);
+    */
+   *flags |= SfMayBlock;
+
+   switch (ARG1 /*opcode*/) {
+   case VKI_SEMCTL:
+      /* Libc: int semctl(int semid, int semnum, int cmd...); */
+      switch (ARG4) {
+         case VKI_IPC_STAT:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG3, ARG4, ARG5);
+            PRE_REG_READ5(long, SC3("semsys", "semctl", "stat"), int, opcode,
+                          int, semid, int, semnum, int, cmd,
+                          struct vki_semid_ds *, arg);
+            break;
+         case VKI_IPC_SET:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG3, ARG4, ARG5);
+            PRE_REG_READ5(long, SC3("semsys", "semctl", "set"), int, opcode,
+                          int, semid, int, semnum, int, cmd,
+                          struct vki_semid_ds *, arg);
+            break;
+         case VKI_IPC_STAT64:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG3, ARG4, ARG5);
+            PRE_REG_READ5(long, SC3("semsys", "semctl", "stat64"), int, opcode,
+                          int, semid, int, semnum, int, cmd,
+                          struct vki_semid64_ds *, arg);
+            break;
+         case VKI_IPC_SET64:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG3, ARG4, ARG5);
+            PRE_REG_READ5(long, SC3("semsys", "semctl", "set64"), int, opcode,
+                          int, semid, int, semnum, int, cmd,
+                          struct vki_semid64_ds *, arg);
+            break;
+         case VKI_IPC_RMID:
+            PRINT("sys_semsys ( %ld, %ld, %ld )", ARG1, ARG3, ARG4);
+            PRE_REG_READ3(long, SC3("semsys", "semctl", "rmid"), int, opcode,
+                          int, semid, int, cmd);
+            break;
+         case VKI_GETALL:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG4, ARG5);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "getall"), int, opcode,
+                          int, semid, int, cmd, ushort_t *, arg);
+            break;
+         case VKI_SETALL:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG4, ARG5);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "setall"), int, opcode,
+                          int, semid, int, cmd, ushort_t *, arg);
+            break;
+         case VKI_GETVAL:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld )",
+                  ARG1, ARG2, ARG3, ARG4);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "getval"), int, opcode,
+                          int, semid, int, semnum, int, cmd);
+            break;
+         case VKI_SETVAL:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld, %#lx )",
+                  ARG1, ARG2, ARG3, ARG4, ARG5);
+            PRE_REG_READ5(long, SC3("semsys", "semctl", "setval"), int, opcode,
+                          int, semid, int, semnum, int, cmd,
+                          union vki_semun *, arg);
+            break;
+         case VKI_GETPID:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld )",
+                  ARG1, ARG2, ARG3, ARG4);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "getpid"), int, opcode,
+                          int, semid, int, semnum, int, cmd);
+            break;
+         case VKI_GETNCNT:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld )",
+                  ARG1, ARG2, ARG3, ARG4);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "getncnt"),
+                          int, opcode, int, semid, int, semnum, int, cmd);
+            break;
+         case VKI_GETZCNT:
+            PRINT("sys_semsys ( %ld, %ld, %ld, %ld )",
+                  ARG1, ARG2, ARG3, ARG4);
+            PRE_REG_READ4(long, SC3("semsys", "semctl", "getzcnt"),
+                          int, opcode, int, semid, int, semnum, int, cmd);
+            break;
+         default:
+            VG_(unimplemented)("Syswrap of the semsys(semctl) call "
+                               "with cmd %ld.", ARG4);
+            /*NOTREACHED*/
+            break;
+      }
+      ML_(generic_PRE_sys_semctl)(tid, ARG2, ARG3, ARG4, ARG5);
+      break;
+   case VKI_SEMGET:
+      /* Libc: int semget(key_t key, int nsems, int semflg); */
+      PRINT("sys_semsys ( %ld, %ld, %ld, %ld )", ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("semsys", "semget"), int, opcode,
+                    vki_key_t, key, int, nsems, int, semflg);
+      break;
+   case VKI_SEMOP:
+      /* Libc: int semop(int semid, struct sembuf *sops, size_t nsops); */
+      PRINT("sys_semsys ( %ld, %ld, %#lx, %lu )", ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("semsys", "semop"), int, opcode, int, semid,
+                    struct vki_sembuf *, sops, vki_size_t, nsops);
+      ML_(generic_PRE_sys_semop)(tid, ARG2, ARG3, ARG4);
+      break;
+   case VKI_SEMIDS:
+      /* Libc: int semids(int *buf, uint_t nids, uint_t *pnids); */
+      PRINT("sys_semsys ( %ld, %#lx, %ld, %#lx )", ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("semsys", "semids"), int, opcode, int *, buf,
+                   vki_uint_t, nids, vki_uint_t *, pnids);
+
+      PRE_MEM_WRITE("semsys(semids, buf)", ARG2, ARG3 * sizeof(int *));
+      PRE_MEM_WRITE("semsys(semids, pnids)", ARG4, sizeof(vki_uint_t));
+      break;
+   case VKI_SEMTIMEDOP:
+      /* Libc: int semtimedop(int semid, struct sembuf *sops, size_t nsops,
+                              const struct timespec *timeout);
+       */
+      PRINT("sys_semsys ( %ld, %ld, %#lx, %lu, %#lx )", ARG1, ARG2, ARG3,
+            ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("semsys", "semtimedop"), int, opcode,
+                    int, semid, struct vki_sembuf *, sops, vki_size_t, nsops,
+                    struct vki_timespec *, timeout);
+      ML_(generic_PRE_sys_semtimedop)(tid, ARG2, ARG3, ARG4, ARG5);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the semsys call with opcode %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_semsys)
+{
+   switch (ARG1 /*opcode*/) {
+   case VKI_SEMCTL:
+      ML_(generic_POST_sys_semctl)(tid, RES, ARG2, ARG3, ARG4, ARG5);
+      break;
+   case VKI_SEMGET:
+   case VKI_SEMOP:
+      break;
+   case VKI_SEMIDS:
+      {
+         POST_MEM_WRITE(ARG4, sizeof(vki_uint_t));
+
+         uint_t *pnids = (uint_t *)ARG4;
+         if (*pnids <= ARG3)
+            POST_MEM_WRITE(ARG2, *pnids * sizeof(int *));
+      }
+      break;
+   case VKI_SEMTIMEDOP:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+/* ---------------------------------------------------------------------
+   ioctl wrappers
+   ------------------------------------------------------------------ */
+
+PRE(sys_ioctl)
+{
+   /* int ioctl(int fildes, int request, ...); */
+   *flags |= SfMayBlock;
+
+   /* Prevent sign extending the switch case values to 64-bits on 64-bits
+      architectures. */
+   Int cmd = (Int) ARG2;
+
+   switch (cmd /*request*/) {
+      /* Handle 2-arg specially here (they do not use ARG3 at all). */
+   case VKI_TIOCNOTTY:
+   case VKI_TIOCSCTTY:
+      PRINT("sys_ioctl ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, "ioctl", int, fd, int, request);
+      break;
+      /* And now come the 3-arg ones. */
+   default:
+      PRINT("sys_ioctl ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "ioctl", int, fd, int, request, intptr_t, arg);
+      break;
+   }
+
+   switch (cmd /*request*/) {
+   /* pools */
+   case VKI_POOL_STATUSQ:
+      PRE_MEM_WRITE("ioctl(POOL_STATUSQ)", ARG3, sizeof(vki_pool_status_t));
+      break;
+
+   /* mntio */
+   case VKI_MNTIOC_GETMNTANY:
+      {
+         PRE_MEM_READ("ioctl(MNTIOC_GETMNTANY)",
+                      ARG3, sizeof(struct vki_mntentbuf));
+
+         struct vki_mntentbuf *embuf = (struct vki_mntentbuf *) ARG3;
+         if (ML_(safe_to_deref(embuf, sizeof(*embuf)))) {
+            PRE_MEM_READ("ioctl(MNTIOC_GETMNTANY, embuf->mbuf_emp)",
+                         (Addr) embuf->mbuf_emp,
+                         sizeof(struct vki_mnttab));
+            PRE_MEM_WRITE("ioctl(MNTIOC_GETMNTANY, embuf->mbuf_buf)",
+                          (Addr) embuf->mbuf_buf,
+                          embuf->mbuf_bufsize);
+            struct vki_mnttab *mnt
+               = (struct vki_mnttab *) embuf->mbuf_emp;
+            if (ML_(safe_to_deref(mnt, sizeof(struct vki_mnttab)))) {
+               if (mnt->mnt_special != NULL)
+                  PRE_MEM_RASCIIZ("ioctl(MNTIOC_GETMNTANY, mnt->mnt_special)",
+                                  (Addr) mnt->mnt_special);
+               if (mnt->mnt_mountp != NULL)
+                  PRE_MEM_RASCIIZ("ioctl(MNTIOC_GETMNTANY, mnt->mnt_mountp)",
+                                  (Addr) mnt->mnt_mountp);
+               if (mnt->mnt_fstype != NULL)
+                  PRE_MEM_RASCIIZ("ioctl(MNTIOC_GETMNTANY, mnt->mnt_fstype)",
+                                  (Addr) mnt->mnt_fstype);
+               if (mnt->mnt_mntopts != NULL)
+                  PRE_MEM_RASCIIZ("ioctl(MNTIOC_GETMNTANY, mnt->mnt_mntopts)",
+                                  (Addr) mnt->mnt_mntopts);
+               if (mnt->mnt_time != NULL)
+                  PRE_MEM_RASCIIZ("ioctl(MNTIOC_GETMNTANY, mnt->mnt_time)",
+                                  (Addr) mnt->mnt_time);
+            }
+         }
+      }
+      break;
+
+   /* termio/termios */
+   case VKI_TCGETA:
+      PRE_MEM_WRITE("ioctl(TCGETA)", ARG3, sizeof(struct vki_termio));
+      break;
+   case VKI_TCGETS:
+      PRE_MEM_WRITE("ioctl(TCGETS)", ARG3, sizeof(struct vki_termios));
+      break;
+   case VKI_TCSETS:
+      PRE_MEM_READ("ioctl(TCSETS)", ARG3, sizeof(struct vki_termios));
+      break;
+   case VKI_TCSETSW:
+      PRE_MEM_READ("ioctl(TCSETSW)", ARG3, sizeof(struct vki_termios));
+      break;
+   case VKI_TCSETSF:
+      PRE_MEM_READ("ioctl(TCSETSF)", ARG3, sizeof(struct vki_termios));
+      break;
+   case VKI_TIOCGWINSZ:
+      PRE_MEM_WRITE("ioctl(TIOCGWINSZ)", ARG3, sizeof(struct vki_winsize));
+      break;
+   case VKI_TIOCSWINSZ:
+      PRE_MEM_READ("ioctl(TIOCSWINSZ)", ARG3, sizeof(struct vki_winsize));
+      break;
+   case VKI_TIOCGPGRP:
+      PRE_MEM_WRITE("ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_TIOCSPGRP:
+      PRE_MEM_READ("ioctl(TIOCSPGRP)", ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_TIOCGSID:
+      PRE_MEM_WRITE("ioctl(TIOCGSID)", ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_TIOCNOTTY:
+   case VKI_TIOCSCTTY:
+      break;
+
+   /* STREAMS */
+   case VKI_I_PUSH:
+      PRE_MEM_RASCIIZ("ioctl(I_PUSH)", ARG3);
+      break;
+   case VKI_I_STR:
+      {
+         PRE_MEM_READ("ioctl(I_STR)", ARG3, sizeof(struct vki_strioctl));
+
+         struct vki_strioctl *p = (struct vki_strioctl *) ARG3;
+         if (ML_(safe_to_deref(p, sizeof(*p)))) {
+            if ((p->ic_dp != NULL) && (p->ic_len > 0)) {
+               PRE_MEM_READ("ioctl(I_STR, strioctl->ic_dp)",
+                            (Addr) p->ic_dp, p->ic_len);
+            }
+         }
+      }
+      break;
+   case VKI_I_PEEK:
+      {
+         /* Try hard not to mark strpeek->*buf.len members as being read. */
+         struct vki_strpeek *p = (struct vki_strpeek*)ARG3;
+
+         PRE_FIELD_READ("ioctl(I_PEEK, strpeek->ctlbuf.maxlen)",
+                        p->ctlbuf.maxlen);
+         PRE_FIELD_WRITE("ioctl(I_PEEK, strpeek->ctlbuf.len)",
+                         p->ctlbuf.len);
+         PRE_FIELD_READ("ioctl(I_PEEK, strpeek->ctlbuf.buf)",
+                        p->ctlbuf.buf);
+         PRE_FIELD_READ("ioctl(I_PEEK, strpeek->databuf.maxlen)",
+                        p->databuf.maxlen);
+         PRE_FIELD_WRITE("ioctl(I_PEEK, strpeek->databuf.len)",
+                         p->databuf.len);
+         PRE_FIELD_READ("ioctl(I_PEEK, strpeek->databuf.buf)",
+                        p->databuf.buf);
+         PRE_FIELD_READ("ioctl(I_PEEK, strpeek->flags)", p->flags);
+         /*PRE_FIELD_WRITE("ioctl(I_PEEK, strpeek->flags)", p->flags);*/
+
+         if (ML_(safe_to_deref(p, sizeof(*p)))) {
+            if (p->ctlbuf.buf && p->ctlbuf.maxlen > 0)
+               PRE_MEM_WRITE("ioctl(I_PEEK, strpeek->ctlbuf.buf)",
+                             (Addr)p->ctlbuf.buf, p->ctlbuf.maxlen);
+            if (p->databuf.buf && p->databuf.maxlen > 0)
+               PRE_MEM_WRITE("ioctl(I_PEEK, strpeek->databuf.buf)",
+                             (Addr)p->databuf.buf, p->databuf.maxlen);
+         }
+      }
+      break;
+   case VKI_I_CANPUT:
+      break;
+
+   /* sockio */
+   case VKI_SIOCGLIFNUM:
+      {
+         struct vki_lifnum *p = (struct vki_lifnum *) ARG3;
+         PRE_FIELD_READ("ioctl(SIOCGLIFNUM, lifn->lifn_family)",
+                        p->lifn_family);
+         PRE_FIELD_READ("ioctl(SIOCGLIFNUM, lifn->lifn_flags)",
+                        p->lifn_flags);
+         PRE_FIELD_WRITE("ioctl(SIOCGLIFNUM, lifn->lifn_count)",
+                         p->lifn_count);
+      }
+      break;  
+
+   /* filio */
+   case VKI_FIOSETOWN:
+      PRE_MEM_READ("ioctl(FIOSETOWN)", ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_FIOGETOWN:
+      PRE_MEM_WRITE("ioctl(FIOGETOWN)", ARG3, sizeof(vki_pid_t));
+      break;
+
+   /* CRYPTO */
+   case VKI_CRYPTO_GET_PROVIDER_LIST:
+      {
+         vki_crypto_get_provider_list_t *pl =
+            (vki_crypto_get_provider_list_t *) ARG3;
+         PRE_FIELD_READ("ioctl(CRYPTO_GET_PROVIDER_LIST, pl->pl_count)",
+                        pl->pl_count);
+
+         if (ML_(safe_to_deref)(pl, sizeof(*pl))) {
+            PRE_MEM_WRITE("ioctl(CRYPTO_GET_PROVIDER_LIST)", ARG3,
+                          MAX(1, pl->pl_count) *
+                          sizeof(vki_crypto_get_provider_list_t));
+         }
+         /* Save the requested count to unused ARG4 below,
+            when we know pre-handler succeeded.
+          */
+      }
+      break; 
+
+   /* dtrace */
+   case VKI_DTRACEHIOC_REMOVE:
+      break;
+   case VKI_DTRACEHIOC_ADDDOF:
+      {
+         vki_dof_helper_t *dh = (vki_dof_helper_t *) ARG3;
+         PRE_MEM_RASCIIZ("ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_mod)",
+                         (Addr) dh->dofhp_mod);
+         PRE_FIELD_READ("ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_addr",
+                        dh->dofhp_addr);
+         PRE_FIELD_READ("ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_dof",
+                        dh->dofhp_dof);
+      }
+      break;
+
+   default:
+      ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
+      break;
+   }
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "ioctl", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   } else if (ARG2 == VKI_CRYPTO_GET_PROVIDER_LIST) {
+      /* Save the requested count to unused ARG4 now. */
+      ARG4 = ARG3;
+   }
+}
+
+POST(sys_ioctl)
+{
+   /* Prevent sign extending the switch case values to 64-bits on 64-bits
+      architectures. */
+   Int cmd = (Int) ARG2;
+
+   switch (cmd /*request*/) {
+   /* pools */
+   case VKI_POOL_STATUSQ:
+      POST_MEM_WRITE(ARG3, sizeof(vki_pool_status_t));
+      break;
+
+   /* mntio */
+   case VKI_MNTIOC_GETMNTANY:
+      {
+         struct vki_mntentbuf *embuf = (struct vki_mntentbuf *) ARG3;
+         struct vki_mnttab *mnt = (struct vki_mnttab *) embuf->mbuf_emp;
+
+         POST_MEM_WRITE((Addr) mnt, sizeof(struct vki_mnttab));
+         if (mnt != NULL) {
+            if (mnt->mnt_special != NULL)
+               POST_MEM_WRITE((Addr) mnt->mnt_special,
+                              VG_(strlen)(mnt->mnt_special) + 1);
+            if (mnt->mnt_mountp != NULL)
+               POST_MEM_WRITE((Addr) mnt->mnt_mountp,
+                              VG_(strlen)(mnt->mnt_mountp) + 1);
+            if (mnt->mnt_fstype != NULL)
+               POST_MEM_WRITE((Addr) mnt->mnt_fstype,
+                              VG_(strlen)(mnt->mnt_fstype) + 1);
+            if (mnt->mnt_mntopts != NULL)
+               POST_MEM_WRITE((Addr) mnt->mnt_mntopts,
+                              VG_(strlen)(mnt->mnt_mntopts) + 1);
+            if (mnt->mnt_time != NULL)
+               POST_MEM_WRITE((Addr) mnt->mnt_time,
+                              VG_(strlen)(mnt->mnt_time) + 1);
+         }
+      }
+      break;
+
+   /* termio/termios */
+   case VKI_TCGETA:
+      POST_MEM_WRITE(ARG3, sizeof(struct vki_termio));
+      break;
+   case VKI_TCGETS:
+      POST_MEM_WRITE(ARG3, sizeof(struct vki_termios));
+      break;
+   case VKI_TCSETS:
+      break;
+   case VKI_TCSETSW:
+      break;
+   case VKI_TCSETSF:
+      break;
+   case VKI_TIOCGWINSZ:
+      POST_MEM_WRITE(ARG3, sizeof(struct vki_winsize));
+      break;
+   case VKI_TIOCSWINSZ:
+      break;
+   case VKI_TIOCGPGRP:
+      POST_MEM_WRITE(ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_TIOCSPGRP:
+      break;
+   case VKI_TIOCGSID:
+      POST_MEM_WRITE(ARG3, sizeof(vki_pid_t));
+      break;
+   case VKI_TIOCNOTTY:
+   case VKI_TIOCSCTTY:
+      break;
+
+   /* STREAMS */
+   case VKI_I_PUSH:
+      break;
+   case VKI_I_STR:
+      {
+         struct vki_strioctl *p = (struct vki_strioctl *) ARG3;
+
+         POST_FIELD_WRITE(p->ic_len);
+         if ((p->ic_dp != NULL) && (p->ic_len > 0))
+            POST_MEM_WRITE((Addr) p->ic_dp, p->ic_len);
+      }
+      break;
+   case VKI_I_PEEK:
+      {
+         struct vki_strpeek *p = (struct vki_strpeek*)ARG3;
+
+         POST_FIELD_WRITE(p->ctlbuf.len);
+         POST_FIELD_WRITE(p->databuf.len);
+         POST_FIELD_WRITE(p->flags);
+
+         if (p->ctlbuf.buf && p->ctlbuf.len > 0)
+            POST_MEM_WRITE((Addr)p->ctlbuf.buf, p->ctlbuf.len);
+         if (p->databuf.buf && p->databuf.len > 0)
+            POST_MEM_WRITE((Addr)p->databuf.buf, p->databuf.len);
+      }
+      break;
+   case VKI_I_CANPUT:
+      break;
+
+   /* sockio */
+   case VKI_SIOCGLIFNUM:
+      {
+         struct vki_lifnum *p = (struct vki_lifnum *) ARG3;
+         POST_FIELD_WRITE(p->lifn_count);
+      }
+      break;  
+
+   /* filio */
+   case VKI_FIOSETOWN:
+      break;
+   case VKI_FIOGETOWN:
+      POST_MEM_WRITE(ARG3, sizeof(vki_pid_t));
+      break;
+
+   /* CRYPTO */
+   case VKI_CRYPTO_GET_PROVIDER_LIST:
+      {
+         vki_crypto_get_provider_list_t *pl =
+            (vki_crypto_get_provider_list_t *) ARG3;
+
+         POST_FIELD_WRITE(pl->pl_count);
+         POST_FIELD_WRITE(pl->pl_return_value);
+
+         if ((ARG4 > 0) && (pl->pl_return_value == VKI_CRYPTO_SUCCESS))
+            POST_MEM_WRITE((Addr) pl->pl_list, pl->pl_count *
+                           sizeof(vki_crypto_provider_entry_t));
+      }
+      break;
+
+   /* dtrace */
+   case VKI_DTRACEHIOC_REMOVE:
+   case VKI_DTRACEHIOC_ADDDOF:
+      break;
+
+   default:
+      /* Not really anything to do since ioctl direction hints are hardly used
+         on Solaris. */
+      break;
+   }
+}
+
+PRE(sys_fchownat)
+{
+   /* int fchownat(int fd, const char *path, uid_t owner, gid_t group,
+                   int flag); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_fchownat ( %d, %#lx(%s), %ld, %ld, %ld )", fd,
+         ARG2, (HChar *) ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "fchownat", int, fd, const char *, path,
+                 vki_uid_t, owner, vki_gid_t, group, int, flag);
+
+   if (ARG2)
+      PRE_MEM_RASCIIZ("fchownat(path)", ARG2);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "fchownat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_fdsync)
+{
+   /* int fdsync(int fd, int flag); */
+   PRINT("sys_fdsync ( %ld, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "fdsync", int, fd, int, flag);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fdsync", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_execve)
+{
+   Int i, j;
+   /* This is a Solaris specific version of the generic pre-execve wrapper. */
+
+#if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
+   /* int execve(uintptr_t file, const char **argv, const char **envp,
+                 int flags); */
+   PRINT("sys_execve ( %#lx, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "execve", uintptr_t, file, const char **, argv,
+                 const char **, envp, int, flags);
+
+#else
+
+   /* int execve(const char *fname, const char **argv, const char **envp); */
+   PRINT("sys_execve ( %#lx(%s), %#lx, %#lx )",
+         ARG1, (HChar *) ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "execve", const char *, file, const char **, argv,
+                 const char **, envp);
+#endif /* SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS */
+
+   Bool ARG1_is_fd = False;
+#if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
+   if (ARG4 & VKI_EXEC_DESCRIPTOR) {
+      ARG1_is_fd = True;
+   }
+#endif /* SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS */
+
+   if (ARG1_is_fd == False)
+      PRE_MEM_RASCIIZ("execve(filename)", ARG1);
+   if (ARG2)
+      ML_(pre_argv_envp)(ARG2, tid, "execve(argv)", "execve(argv[i])");
+   if (ARG3)
+      ML_(pre_argv_envp)(ARG3, tid, "execve(envp)", "execve(envp[i])");
+
+   /* 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 close to
+      impossible.  Instead, we make an effort to check that the execve will
+      work before actually doing it. */
+
+   const HChar *fname = (const HChar *) ARG1;
+   if (ARG1_is_fd) {
+      if (!ML_(fd_allowed)(ARG1, "execve", tid, False)) {
+         SET_STATUS_Failure(VKI_EBADF);
+         return;
+      }
+
+      if (VG_(resolve_filename)(ARG1, &fname) == False) {
+         SET_STATUS_Failure(VKI_EBADF);
+         return;
+      }
+
+      struct vg_stat stats;
+      if (VG_(fstat)(ARG1, &stats) != 0) {
+         SET_STATUS_Failure(VKI_EBADF);
+         return;
+      }
+
+      if (stats.nlink > 1)
+         VG_(unimplemented)("Syswrap of execve where fd points to a hardlink.");
+   }
+
+   /* Check that the name at least begins in client-accessible storage. */
+   if (ARG1_is_fd == False) {
+      if ((fname == NULL) || !ML_(safe_to_deref)(fname, 1)) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+   }
+
+   /* Check that the args at least begin in client-accessible storage.
+      Solaris disallows to perform the exec without any arguments specified.
+    */
+   if (!ARG2 /* obviously bogus */ ||
+       !VG_(am_is_valid_for_client)(ARG2, 1, VKI_PROT_READ)) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("ARG1 = %#lx(%s)\n", ARG1, fname);
+      if (ARG2) {
+         Int q;
+         HChar** vec = (HChar**)ARG2;
+
+         VG_(printf)("ARG2 = ");
+         for (q = 0; vec[q]; q++)
+            VG_(printf)("%p(%s) ", vec[q], vec[q]);
+         VG_(printf)("\n");
+      }
+      else
+         VG_(printf)("ARG2 = null\n");
+   }
+
+   /* Decide whether or not we want to follow along. */
+   /* Make 'child_argv' be a pointer to the child's arg vector (skipping the
+      exe name) */
+   const HChar **child_argv = (const HChar **) ARG2;
+   if (child_argv[0] == NULL)
+      child_argv = NULL;
+   Bool trace_this_child = VG_(should_we_trace_this_child)(fname, child_argv);
+
+   /* Do the important checks:  it is a file, is executable, permissions are
+      ok, etc.  We allow setuid executables to run only in the case when
+      we are not simulating them, that is, they to be run natively. */
+   Bool setuid_allowed = trace_this_child ? False : True;
+   SysRes res = VG_(pre_exec_check)(fname, NULL, setuid_allowed);
+   if (sr_isError(res)) {
+      SET_STATUS_Failure(sr_Err(res));
+      return;
+   }
+
+   /* If we're tracing the child, and the launcher name looks bogus (possibly
+      because launcher.c couldn't figure it out, see comments therein) then we
+      have no option but to fail. */
+   if (trace_this_child &&
+       (!VG_(name_of_launcher) || VG_(name_of_launcher)[0] != '/')) {
+      SET_STATUS_Failure(VKI_ECHILD); /* "No child processes." */
+      return;
+   }
+
+   /* After this point, we can't recover if the execve fails. */
+   VG_(debugLog)(1, "syswrap", "Exec of %s\n", fname);
+
+   /* Terminate gdbserver if it is active. */
+   if (VG_(clo_vgdb) != Vg_VgdbNo) {
+      /* If the child will not be traced, we need to terminate gdbserver to
+         cleanup the gdbserver resources (e.g. the FIFO files). If child will
+         be traced, we also terminate gdbserver: the new Valgrind will start a
+         fresh gdbserver after exec. */
+      VG_(gdbserver)(0);
+   }
+
+   /* 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_ExitThread);
+   VG_(reap_threads)(tid);
+
+   /* Set up the child's exe path. */
+   const HChar *path = fname;
+   const HChar *launcher_basename = NULL;
+   if (trace_this_child) {
+      /* 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 || launcher_basename[1] == '\0')
+         launcher_basename = path;  /* hmm, tres dubious */
+      else
+         launcher_basename++;
+   }
+
+   /* 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, 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 (bug #101881).
+
+      Then, if tracing the child, set VALGRIND_LIB for it. */
+   HChar **envp = NULL;
+   if (ARG3 != 0) {
+      envp = VG_(env_clone)((HChar**)ARG3);
+      vg_assert(envp != NULL);
+      VG_(env_remove_valgrind_env_stuff)(envp, True /*ro_strings*/, NULL);
+   }
+
+   if (trace_this_child) {
+      /* Set VALGRIND_LIB in ARG3 (the environment). */
+      VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
+   }
+
+   /* 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. */
+   HChar **argv = NULL;
+   if (!trace_this_child)
+      argv = (HChar **) ARG2;
+   else {
+      Int tot_args;
+
+      vg_assert(VG_(args_for_valgrind));
+      vg_assert(VG_(args_for_valgrind_noexecpass) >= 0);
+      vg_assert(VG_(args_for_valgrind_noexecpass)
+                   <= VG_(sizeXA)(VG_(args_for_valgrind)));
+
+      /* How many args in total will there be? */
+      /* launcher basename */
+      tot_args = 1;
+      /* V's args */
+      tot_args += VG_(sizeXA)(VG_(args_for_valgrind));
+      tot_args -= VG_(args_for_valgrind_noexecpass);
+      /* name of client exe */
+      tot_args++;
+      /* args for client exe, skipping [0] */
+      HChar **arg2copy = (HChar **) ARG2;
+      if (arg2copy[0] != NULL)
+         for (i = 1; arg2copy[i]; i++)
+            tot_args++;
+      /* allocate */
+      argv = VG_(malloc)("syswrap.exec.5", (tot_args + 1) * sizeof(HChar*));
+      /* copy */
+      j = 0;
+      argv[j++] = CONST_CAST(HChar *, launcher_basename);
+      for (i = 0; i < VG_(sizeXA)(VG_(args_for_valgrind)); i++) {
+         if (i < VG_(args_for_valgrind_noexecpass))
+            continue;
+         argv[j++] = *(HChar**)VG_(indexXA)(VG_(args_for_valgrind), i);
+      }
+      argv[j++] = CONST_CAST(HChar *, fname);
+      if (arg2copy[0] != NULL)
+         for (i = 1; arg2copy[i]; i++)
+            argv[j++] = arg2copy[i];
+      argv[j++] = NULL;
+      /* check */
+      vg_assert(j == tot_args + 1);
+   }
+
+   /* Set the signal state up for exec.
+
+      We need to set the real signal state to make sure the exec'd process
+      gets SIG_IGN properly.
+
+      Also set our real sigmask to match the client's sigmask so that the
+      exec'd child will get the right mask.  First we need to clear out any
+      pending signals so they they don't get delivered, which would confuse
+      things.
+
+      XXX This is a bug - the signals should remain pending, and be delivered
+      to the new process after exec.  There's also a race-condition, since if
+      someone delivers us a signal between the sigprocmask and the execve,
+      we'll still get the signal. Oh well.
+   */
+   {
+      vki_sigset_t allsigs;
+      vki_siginfo_t info;
+
+      /* What this loop does: it queries SCSS (the signal state that the
+         client _thinks_ the kernel is in) by calling VG_(do_sys_sigaction),
+         and modifies the real kernel signal state accordingly. */
+      for (i = 1; i < VG_(max_signal); i++) {
+         vki_sigaction_fromK_t sa_f;
+         vki_sigaction_toK_t   sa_t;
+         VG_(do_sys_sigaction)(i, NULL, &sa_f);
+         VG_(convert_sigaction_fromK_to_toK)(&sa_f, &sa_t);
+         VG_(sigaction)(i, &sa_t, NULL);
+      }
+
+      VG_(sigfillset)(&allsigs);
+      while (VG_(sigtimedwait_zero)(&allsigs, &info) > 0)
+         ;
+
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      VG_(sigprocmask)(VKI_SIG_SETMASK, &tst->sig_mask, NULL);
+   }
+
+   /* Restore the DATA rlimit for the child. */
+   VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
+   /* Debug-only printing. */
+   if (0) {
+      HChar **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);
+   }
+
+#if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
+   res = VG_(do_syscall4)(__NR_execve, (UWord) path, (UWord) argv,
+                          (UWord) envp, ARG4 & ~VKI_EXEC_DESCRIPTOR);
+#else
+   res = VG_(do_syscall3)(__NR_execve, (UWord) path, (UWord) argv,
+                          (UWord) envp);
+#endif /* SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS */
+   SET_STATUS_from_SysRes(res);
+
+   /* 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. */
+   vg_assert(FAILURE);
+#if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
+   if (ARG1_is_fd)
+      VG_(message)(Vg_UserMsg, "execve(%ld, %#lx, %#lx, %ld) failed, "
+                   "errno %ld\n", ARG1, ARG2, ARG3, ARG4, ERR);
+   else
+      VG_(message)(Vg_UserMsg, "execve(%#lx(%s), %#lx, %#lx, %ld) failed, errno"
+                   " %ld\n", ARG1, (HChar *) ARG1, ARG2, ARG3, ARG4, ERR);
+#else
+   VG_(message)(Vg_UserMsg, "execve(%#lx(%s), %#lx, %#lx) failed, errno %ld\n",
+                ARG1, (HChar *) ARG1, ARG2, ARG3, ERR);
+#endif /* SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS */
+   VG_(message)(Vg_UserMsg, "EXEC FAILED: I can't recover from "
+                            "execve() failing, so I'm dying.\n");
+   VG_(message)(Vg_UserMsg, "Add more stringent tests in PRE(sys_execve), "
+                            "or work out how to recover.\n");
+   VG_(exit)(101);
+   /*NOTREACHED*/
+}
+
+static void pre_mem_read_flock(ThreadId tid, struct vki_flock *lock)
+{
+   PRE_FIELD_READ("fcntl(lock->l_type)", lock->l_type);
+   PRE_FIELD_READ("fcntl(lock->l_whence)", lock->l_whence);
+   PRE_FIELD_READ("fcntl(lock->l_start)", lock->l_start);
+   PRE_FIELD_READ("fcntl(lock->l_len)", lock->l_len);
+}
+
+#if defined(VGP_x86_solaris)
+static void pre_mem_read_flock64(ThreadId tid, struct vki_flock64 *lock)
+{
+   PRE_FIELD_READ("fcntl(lock->l_type)", lock->l_type);
+   PRE_FIELD_READ("fcntl(lock->l_whence)", lock->l_whence);
+   PRE_FIELD_READ("fcntl(lock->l_start)", lock->l_start);
+   PRE_FIELD_READ("fcntl(lock->l_len)", lock->l_len);
+}
+#endif /* VGP_x86_solaris */
+
+PRE(sys_fcntl)
+{
+   /* int fcntl(int fildes, int cmd, ...); */
+
+   switch (ARG2 /*cmd*/) {
+   /* These ones ignore ARG3. */
+   case VKI_F_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETXFL:
+      PRINT("sys_fcntl ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, "fcntl", int, fildes, int, cmd);
+      break;
+
+   /* These ones use ARG3 as "arg". */
+   case VKI_F_DUPFD:
+   case VKI_F_SETFD:
+   case VKI_F_SETFL:
+   case VKI_F_DUP2FD:
+   case VKI_F_BADFD:
+      PRINT("sys_fcntl ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd, int, arg);
+      /* Check if a client program isn't going to poison any of V's output
+         fds. */
+      if (ARG2 == VKI_F_DUP2FD &&
+          !ML_(fd_allowed)(ARG3, "fcntl(F_DUP2FD)", tid, False)) {
+         SET_STATUS_Failure(VKI_EBADF);
+         return;
+      }
+      break;
+
+   /* These ones use ARG3 as "native lock" (input only). */
+   case VKI_F_SETLK:
+   case VKI_F_SETLKW:
+   case VKI_F_ALLOCSP:
+   case VKI_F_FREESP:
+   case VKI_F_SETLK_NBMAND:
+      PRINT("sys_fcntl ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd,
+                    struct flock *, lock);
+      pre_mem_read_flock(tid, (struct vki_flock*)ARG3);
+      break;
+
+   /* This one uses ARG3 as "native lock" (input&output). */
+   case VKI_F_GETLK:
+      PRINT("sys_fcntl ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd,
+                    struct flock *, lock);
+      pre_mem_read_flock(tid, (struct vki_flock*)ARG3);
+      PRE_MEM_WRITE("fcntl(lock)", ARG3, sizeof(struct vki_flock));
+      break;
+
+#if defined(VGP_x86_solaris)
+   /* These ones use ARG3 as "transitional 64b lock" (input only). */
+   case VKI_F_SETLK64:
+   case VKI_F_SETLKW64:
+   case VKI_F_ALLOCSP64:
+   case VKI_F_FREESP64:
+   case VKI_F_SETLK64_NBMAND:
+      PRINT("sys_fcntl ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd,
+                    struct flock64 *, lock);
+      pre_mem_read_flock64(tid, (struct vki_flock64*)ARG3);
+      break;
+
+   /* This one uses ARG3 as "transitional 64b lock" (input&output). */
+   case VKI_F_GETLK64:
+      PRINT("sys_fcntl ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd,
+                    struct flock64 *, lock);
+      pre_mem_read_flock64(tid, (struct vki_flock64*)ARG3);
+      PRE_MEM_WRITE("fcntl(lock)", ARG3, sizeof(struct vki_flock64));
+      break;
+#endif /* VGP_x86_solaris */
+
+   /* These ones use ARG3 as "fshare". */
+   case VKI_F_SHARE:
+   case VKI_F_UNSHARE:
+   case VKI_F_SHARE_NBMAND:
+      PRINT("sys_fcntl[ARG3=='fshare'] ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "fcntl", int, fildes, int, cmd,
+                    struct fshare *, sh);
+      PRE_MEM_READ("fcntl(fshare)", ARG3, sizeof(struct vki_fshare));
+      break;
+
+   default:
+      VG_(unimplemented)("Syswrap of the fcntl call with cmd %ld.", ARG2);
+      /*NOTREACHED*/
+      break;
+   }
+
+   if (ARG2 == VKI_F_SETLKW
+#if defined(VGP_x86_solaris)
+       || ARG2 == VKI_F_SETLKW64
+#endif /* VGP_x86_solaris */
+       )
+      *flags |= SfMayBlock;
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fcntl", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fcntl)
+{
+   switch (ARG2 /*cmd*/) {
+   case VKI_F_DUPFD:
+      if (!ML_(fd_allowed)(RES, "fcntl(F_DUPFD)", tid, True)) {
+         VG_(close)(RES);
+         SET_STATUS_Failure(VKI_EMFILE);
+      }
+      else if (VG_(clo_track_fds))
+         ML_(record_fd_open_named)(tid, RES);
+      break;
+
+   case VKI_F_DUP2FD:
+      if (!ML_(fd_allowed)(RES, "fcntl(F_DUP2FD)", tid, True)) {
+         VG_(close)(RES);
+         SET_STATUS_Failure(VKI_EMFILE);
+      }
+      else if (VG_(clo_track_fds))
+         ML_(record_fd_open_named)(tid, RES);
+      break;
+
+   /* This one uses ARG3 as "native lock" (input&output). */
+   case VKI_F_GETLK:
+      POST_MEM_WRITE(ARG3, sizeof(struct vki_flock));
+      break;
+
+#if defined(VGP_x86_solaris)
+   /* This one uses ARG3 as "transitional 64b lock" (input&output). */
+   case VKI_F_GETLK64:
+      POST_MEM_WRITE(ARG3, sizeof(struct vki_flock64));
+      break;
+#endif /* VGP_x86_solaris */
+
+   default:
+      break;
+   }
+}
+
+PRE(sys_renameat)
+{
+   /* int renameat(int fromfd, const char *old, int tofd, const char *new); */
+
+   /* Interpret the first and third arguments as 32-bit values even on 64-bit
+      architecture. This is different from Linux, for example, where glibc
+      sign-extends them. */
+   Int fromfd = (Int) ARG1;
+   Int tofd = (Int) ARG3;
+
+   *flags |= SfMayBlock;
+   PRINT("sys_renameat ( %d, %#lx(%s), %d, %#lx(%s) )", fromfd,
+         ARG2, (HChar *) ARG2, tofd, ARG4, (HChar *) ARG4);
+   PRE_REG_READ4(long, "renameat", int, fromfd, const char *, old,
+                 int, tofd, const char *, new);
+
+   PRE_MEM_RASCIIZ("renameat(old)", ARG2);
+   PRE_MEM_RASCIIZ("renameat(new)", ARG4);
+
+   /* Be strict but ignore fromfd/tofd for absolute old/new. */
+   if (fromfd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fromfd, "renameat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   }
+   if (tofd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG4, 1)
+       && ((HChar *) ARG4)[0] != '/'
+       && !ML_(fd_allowed)(tofd, "renameat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+   }
+}
+
+PRE(sys_unlinkat)
+{
+   /* int unlinkat(int dirfd, const char *pathname, int flags); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int dfd = (Int) ARG1;
+
+   *flags |= SfMayBlock;
+   PRINT("sys_unlinkat ( %d, %#lx(%s), %ld )", dfd, ARG2, (HChar *) ARG2,
+         ARG3);
+   PRE_REG_READ3(long, "unlinkat", int, dirfd, const char *, pathname,
+                 int, flags);
+   PRE_MEM_RASCIIZ("unlinkat(pathname)", ARG2);
+
+   /* Be strict but ignore dfd for absolute pathname. */
+   if (dfd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(dfd, "unlinkat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_fstatat)
+{
+   /* int fstatat(int fildes, const char *path, struct stat *buf,
+                    int flag); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_fstatat ( %d, %#lx(%s), %#lx, %ld )", fd, ARG2,
+         (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "fstatat", int, fildes, const char *, path,
+                 struct stat *, buf, int, flag);
+   if (ARG2) {
+      /* Only test ARG2 if it isn't NULL.  The kernel treats the NULL-case as
+         fstat(fildes, buf). */
+      PRE_MEM_RASCIIZ("fstatat(path)", ARG2);
+   }
+   PRE_MEM_WRITE("fstatat(buf)", ARG3, sizeof(struct vki_stat));
+
+   /* Be strict but ignore fildes for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "fstatat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstatat)
+{
+   POST_MEM_WRITE(ARG3, sizeof(struct vki_stat));
+}
+
+PRE(sys_openat)
+{
+   /* int openat(int fildes, const char *filename, int flags);
+      int openat(int fildes, const char *filename, int flags, mode_t mode); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   if (ARG3 & VKI_O_CREAT) {
+      /* 4-arg version */
+      PRINT("sys_openat ( %d, %#lx(%s), %ld, %ld )", fd, ARG2, (HChar *) ARG2,
+            ARG3, ARG4);
+      PRE_REG_READ4(long, "openat", int, fildes, const char *, filename,
+                    int, flags, vki_mode_t, mode);
+   }
+   else {
+      /* 3-arg version */
+      PRINT("sys_openat ( %d, %#lx(%s), %ld )", fd, ARG2, (HChar *) ARG2,
+            ARG3);
+      PRE_REG_READ3(long, "openat", int, fildes, const char *, filename,
+                    int, flags);
+   }
+
+   PRE_MEM_RASCIIZ("openat(filename)", ARG2);
+
+   /* Be strict but ignore fildes for absolute pathname. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "openat", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+      return;
+   }
+
+   if (ML_(handle_auxv_open)(status, (const HChar*)ARG2, ARG3))
+      return;
+
+   if (handle_psinfo_open(status, True /*use_openat*/, (const HChar*)ARG2,
+                          fd, ARG3, ARG4))
+      return;
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_openat)
+{
+   if (!ML_(fd_allowed)(RES, "openat", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure(VKI_EMFILE);
+   }
+   else if (VG_(clo_track_fds))
+      ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG2);
+}
+
+PRE(sys_tasksys)
+{
+   /* Kernel: long tasksys(int code, projid_t projid, uint_t flags,
+                           void *projidbuf, size_t pbufsz);
+    */
+   switch (ARG1 /*code*/) {
+   case 0:
+      /* Libc: taskid_t settaskid(projid_t project, uint_t flags); */
+      PRINT("sys_tasksys ( %ld, %ld, %lu )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("tasksys", "settaskid"), int, code,
+                    vki_projid_t, projid, vki_uint_t, flags);
+      break;
+   case 1:
+      /* Libc: taskid_t gettaskid(void); */
+      PRINT("sys_tasksys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("tasksys", "gettaskid"), int, code);
+      break;
+   case 2:
+      /* Libc: projid_t getprojid(void); */
+      PRINT("sys_tasksys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("tasksys", "getprojid"), int, code);
+      break;
+   case 3:
+      /* Libproject: size_t projlist(id_t *idbuf, size_t idbufsz); */
+      PRINT("sys_tasksys ( %ld, %#lx, %lu )", ARG1, ARG4, ARG5);
+      PRE_REG_READ3(long, SC2("tasksys", "projlist"), int, code,
+                    vki_id_t *, idbuf, vki_size_t, idbufsz);
+      PRE_MEM_WRITE("tasksys(idbuf)", ARG4, ARG5);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the tasksys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_tasksys)
+{
+   switch (ARG1 /*code*/) {
+   case 0:
+   case 1:
+   case 2:
+      break;
+   case 3:
+      if ((ARG4 != 0) && (ARG5 != 0))
+         POST_MEM_WRITE(ARG4, MIN(RES, ARG5));
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_lwp_park)
+{
+   /* Kernel: int lwp_park(int which, uintptr_t arg1, uintptr_t arg2);
+    */
+   *flags |= SfMayBlock;
+   switch (ARG1 /*which*/) {
+   case 0:
+      /* Libc: int lwp_park(timespec_t *timeout, id_t lwpid); */
+      PRINT("sys_lwp_park ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("lwp_park", "lwp_park"), int, which,
+                    timespec_t *, timeout, vki_id_t, lwpid);
+      if (ARG2) {
+         PRE_MEM_READ("lwp_park(timeout)", ARG2, sizeof(vki_timespec_t));
+         /*PRE_MEM_WRITE("lwp_park(timeout)", ARG2,
+                         sizeof(vki_timespec_t));*/
+      }
+      break;
+   case 1:
+      /* Libc: int lwp_unpark(id_t lwpid); */
+      PRINT("sys_lwp_park ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("lwp_park", "lwp_unpark"), int, which,
+                    vki_id_t, lwpid);
+      break;
+   case 2:
+      /* Libc: int lwp_unpark_all(id_t *lwpid, int nids); */
+      PRINT("sys_lwp_park ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("lwp_park", "lwp_unpark_all"), int, which,
+                    id_t *, lwpid, int, nids);
+      PRE_MEM_READ("lwp_park(lwpid)", ARG2, ARG3 * sizeof(vki_id_t));
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the lwp_park call with which %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_lwp_park)
+{
+   switch (ARG1 /*which*/) {
+   case 0:
+      if (ARG2)
+         POST_MEM_WRITE(ARG2, sizeof(vki_timespec_t));
+      break;
+   case 1:
+   case 2:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_sendfilev)
+{
+   /* Kernel: ssize_t sendfilev(int opcode, int fd,
+                                const struct sendfilevec *vec,
+                                int sfvcnt, size_t *xferred);
+    */
+   PRINT("sys_sendfilev ( %ld, %ld, %#lx, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+
+   switch (ARG1 /*opcode*/) {
+   case VKI_SENDFILEV:
+      {
+         PRE_REG_READ5(long, "sendfilev", int, opcode, int, fd,
+                       const struct vki_sendfilevec *, vec,
+                       int, sfvcnt, vki_size_t *, xferred);
+
+         PRE_MEM_READ("sendfilev(vec)", ARG3,
+                      ARG4 * sizeof(struct vki_sendfilevec));
+         PRE_MEM_WRITE("sendfilev(xferred)", ARG5, sizeof(vki_size_t));
+
+         struct vki_sendfilevec *vec = (struct vki_sendfilevec *) ARG3;
+         if (ML_(safe_to_deref)(vec, ARG4 *
+                                sizeof(struct vki_sendfilevec))) {
+            UInt i;
+            for (i = 0; i < ARG4; i++) {
+               HChar desc[35];    // large enough
+               if (vec[i].sfv_fd == VKI_SFV_FD_SELF) {
+                  VG_(snprintf)(desc, sizeof(desc),
+                                "sendfilev(vec[%u].sfv_off", i);
+                  PRE_MEM_READ(desc, vec[i].sfv_off, vec[i].sfv_len);
+               } else {
+                  VG_(snprintf)(desc, sizeof(desc),
+                                "sendfilev(vec[%u].sfv_fd)", i);
+                  if (!ML_(fd_allowed)(vec[i].sfv_fd, desc, tid, False))
+                     SET_STATUS_Failure(VKI_EBADF);
+               }
+            }
+         }
+      }
+      break;
+   case VKI_SENDFILEV64:
+      {
+         PRE_REG_READ5(long, "sendfilev", int, opcode, int, fd,
+                       const struct vki_sendfilevec64 *, vec,
+                       int, sfvcnt, vki_size_t *, xferred);
+
+         PRE_MEM_READ("sendfilev(vec)", ARG3,
+                      ARG4 * sizeof(struct vki_sendfilevec64));
+         PRE_MEM_WRITE("sendfilev(xferred)", ARG5, sizeof(vki_size_t));
+
+         struct vki_sendfilevec64 *vec64 =
+            (struct vki_sendfilevec64 *) ARG3;
+         if (ML_(safe_to_deref)(vec64, ARG4 *
+                                sizeof(struct vki_sendfilevec64))) {
+            UInt i;
+            for (i = 0; i < ARG4; i++) {
+               HChar desc[35];    // large enough
+               if (vec64[i].sfv_fd == VKI_SFV_FD_SELF) {
+                  VG_(snprintf)(desc, sizeof(desc),
+                                "sendfilev(vec[%u].sfv_off", i);
+                  PRE_MEM_READ(desc, vec64[i].sfv_off, vec64[i].sfv_len);
+               } else {
+                  VG_(snprintf)(desc, sizeof(desc),
+                                "sendfilev(vec[%u].sfv_fd)", i);
+                  if (!ML_(fd_allowed)(vec64[i].sfv_fd, desc,
+                                       tid, False))
+                     SET_STATUS_Failure(VKI_EBADF);
+               }
+            }
+         }
+      }
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the sendfilev call with "
+                         "opcode %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG2, "sendfilev(fd)", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_sendfilev)
+{
+   POST_MEM_WRITE(ARG5, sizeof(vki_size_t));
+}
+
+#if defined(SOLARIS_LWP_NAME_SYSCALL)
+PRE(sys_lwp_name)
+{
+   /* int lwp_name(int opcode, id_t lwpid, char *name, size_t len); */
+   PRINT("sys_lwp_name ( %ld, %ld, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+
+   switch (ARG1 /*opcode*/) {
+   case 0:
+      /* lwp_setname */
+      PRE_REG_READ3(long, "lwp_name", int, opcode, vki_id_t, lwpid,
+                    char *, name);
+      PRE_MEM_RASCIIZ("lwp_name(name)", ARG3);
+      break;
+   case 1:
+      /* lwp_getname */
+      PRE_REG_READ4(long, "lwp_name", int, opcode, vki_id_t, lwpid,
+                    char *, name, vki_size_t, len);
+      PRE_MEM_WRITE("lwp_name(name)", ARG3, ARG4);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the lwp_name call with opcode %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_lwp_name)
+{
+   switch (ARG1 /*opcode*/) {
+   case 0:
+      if (ARG3) { // Paranoia
+         const HChar *new_name = (const HChar *) ARG3;
+         ThreadState *tst = VG_(get_ThreadState)(tid);
+         SizeT new_len = VG_(strlen)(new_name);
+
+         /* Don't bother reusing the memory. This is a rare event. */
+         tst->thread_name = VG_(realloc)("syswrap.lwp_name", tst->thread_name,
+                                         new_len + 1);
+         VG_(strcpy)(tst->thread_name, new_name);
+      }
+      break;
+   case 1:
+      POST_MEM_WRITE(ARG3, VG_(strlen)((HChar *) ARG3) + 1);
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+#endif /* SOLARIS_LWP_NAME_SYSCALL */
+
+PRE(sys_privsys)
+{
+   /* Kernel: int privsys(int code, priv_op_t op, priv_ptype_t type,
+                          void *buf, size_t bufsize, int itype);
+    */
+   switch (ARG1 /*code*/) {
+   case VKI_PRIVSYS_SETPPRIV:
+      /* Libc: int setppriv(priv_op_t op, priv_ptype_t type,
+                            const priv_set_t *pset);
+       */
+      PRINT("sys_privsys ( %ld, %ld, %ld, %#lx, %lu )", ARG1, ARG2, ARG3,
+            ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("privsys", "setppriv"), int, code,
+                    vki_priv_op_t, op, vki_priv_ptype_t, type,
+                    const priv_set_t *, pset, vki_size_t, bufsize);
+      PRE_MEM_READ("privsys(pset)", ARG4, ARG5);
+      break;
+   case VKI_PRIVSYS_GETPPRIV:
+      /* Libc: int getppriv(priv_ptype_t type, priv_set_t *pset);
+               priv_set_t *pset -> void *buf
+       */
+      PRINT("sys_privsys ( %ld, %ld, %ld, %#lx, %lu )", ARG1, ARG2, ARG3,
+            ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("privsys", "getppriv"), int, code,
+            vki_priv_op_t, op, vki_priv_ptype_t, type, priv_set_t *, pset,
+            vki_size_t, bufsize);
+      PRE_MEM_WRITE("privsys(pset)", ARG4, ARG5);
+      break;
+   case VKI_PRIVSYS_GETIMPLINFO:
+      /* Libc: int getprivinfo(priv_impl_info_t *buf, size_t bufsize);
+               priv_impl_info_t *buf -> void *buf
+       */
+      PRINT("sys_privsys ( %ld, %ld, %ld, %#lx, %ld )", ARG1, ARG2, ARG3,
+            ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("privsys", "getprivinfo"), int, code,
+            vki_priv_op_t, op, vki_priv_ptype_t, type,
+            priv_impl_info_t *, buf, vki_size_t, bufsize);
+      PRE_MEM_WRITE("privsys(buf)", ARG4, ARG5);
+      break;
+   case VKI_PRIVSYS_SETPFLAGS:
+      /* Libc: int setpflags(uint_t flag, uint_t val);
+               uint_t flag -> priv_op_t op
+               uint_t val -> priv_ptype_t type
+       */
+      PRINT("sys_privsys ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("privsys", "setpflags"), int, code,
+                    vki_uint_t, flag, vki_uint_t, val);
+      break;
+   case VKI_PRIVSYS_GETPFLAGS:
+      /* Libc: uint_t getpflags(uint_t flag);
+               uint_t flag -> priv_op_t op
+       */
+      PRINT("sys_privsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("privsys", "setpflags"), int, code,
+                    vki_uint_t, flag);
+      break;
+   case VKI_PRIVSYS_ISSETUGID:
+      /* Libc: int issetugid(void); */
+      PRINT("sys_privsys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("privsys", "issetugid"), int, code);
+      break;
+   case VKI_PRIVSYS_PFEXEC_REG:
+      /* Libc: int register_pfexec(int did);
+               int did -> priv_op_t op
+       */
+      PRINT("sys_privsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("privsys", "register_pfexec"), int, code,
+                    int, did);
+      break;
+   case VKI_PRIVSYS_PFEXEC_UNREG:
+      /* Libc: int unregister_pfexec(int did); */
+      PRINT("sys_privsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("privsys", "unregister_pfexec"), int, code,
+                    int, did);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the privsys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+
+   /* Be strict. */
+   if ((ARG1 == VKI_PRIVSYS_PFEXEC_REG ||
+        ARG1 == VKI_PRIVSYS_PFEXEC_UNREG) &&
+       !ML_(fd_allowed)(ARG2, "privsys", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_privsys)
+{
+   switch (ARG1 /*code*/) {
+   case VKI_PRIVSYS_SETPPRIV:
+      break;
+   case VKI_PRIVSYS_GETPPRIV:
+      POST_MEM_WRITE(ARG4, sizeof(vki_priv_set_t));
+      break;
+   case VKI_PRIVSYS_GETIMPLINFO:
+      /* The kernel copy outs data of size min(bufsize, privinfosize).
+         Unfortunately, it does not seem to be possible to easily obtain the
+         privinfosize value.  The code below optimistically marks all ARG5
+         bytes (aka bufsize) as written by the kernel. */
+      POST_MEM_WRITE(ARG4, ARG5);
+      break;
+   case VKI_PRIVSYS_SETPFLAGS:
+   case VKI_PRIVSYS_GETPFLAGS:
+   case VKI_PRIVSYS_ISSETUGID:
+   case VKI_PRIVSYS_PFEXEC_REG:
+   case VKI_PRIVSYS_PFEXEC_UNREG:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_ucredsys)
+{
+   /* Kernel: int ucredsys(int code, int obj, void *buf); */
+   PRINT("sys_ucredsys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+
+   switch (ARG1 /*code*/) {
+   case VKI_UCREDSYS_UCREDGET:
+      /* Libc: ucred_t *ucred_get(pid_t pid); */
+      PRE_REG_READ3(long, SC2("ucredsys", "ucredget"), int, code,
+                    vki_pid_t, pid, vki_ucred_t *, buf);
+      PRE_MEM_WRITE("ucredsys(buf)", ARG3, sizeof(vki_ucred_t));
+      break;
+
+   case VKI_UCREDSYS_GETPEERUCRED:
+      /* Libc: int getpeerucred(int fd, ucred_t **ucred); */
+      PRE_REG_READ3(long, SC2("ucredsys", "getpeerucred"), int, code,
+                    int, fd, vki_ucred_t *, buf);
+      PRE_MEM_WRITE("ucredsys(buf)", ARG3, sizeof(vki_ucred_t));
+
+      /* Be strict. */
+      if (!ML_(fd_allowed)(ARG2, "ucredsys", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      break;
+
+   default:
+      VG_(unimplemented)("Syswrap of the ucredsys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_ucredsys)
+{
+   switch (ARG1 /*code*/) {
+   case VKI_UCREDSYS_UCREDGET:
+   case VKI_UCREDSYS_GETPEERUCRED:
+      vg_assert(ARG3 != 0);
+      POST_MEM_WRITE(ARG3, ((vki_ucred_t *) ARG3)->uc_size);
+      break;
+
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_getmsg)
+{
+   /* int getmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr,
+                 int *flagsp); */
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+   *flags |= SfMayBlock;
+   PRINT("sys_getmsg ( %ld, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "getmsg", int, fildes, struct vki_strbuf *, ctlptr,
+                 struct vki_strbuf *, dataptr, int *, flagsp);
+   if (ctrlptr) {
+      PRE_FIELD_READ("getmsg(ctrlptr->maxlen)", ctrlptr->maxlen);
+      PRE_FIELD_WRITE("getmsg(ctrlptr->len)", ctrlptr->len);
+      PRE_FIELD_READ("getmsg(ctrlptr->buf)", ctrlptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG2, sizeof(struct vki_strbuf))
+          && ctrlptr->maxlen > 0)
+         PRE_MEM_WRITE("getmsg(ctrlptr->buf)", (Addr)ctrlptr->buf,
+                       ctrlptr->maxlen);
+   }
+   if (dataptr) {
+      PRE_FIELD_READ("getmsg(dataptr->maxlen)", dataptr->maxlen);
+      PRE_FIELD_WRITE("getmsg(dataptr->len)", dataptr->len);
+      PRE_FIELD_READ("getmsg(dataptr->buf)", dataptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG3, sizeof(struct vki_strbuf))
+          && dataptr->maxlen > 0)
+         PRE_MEM_WRITE("getmsg(dataptr->buf)", (Addr)dataptr->buf,
+                       dataptr->maxlen);
+   }
+   PRE_MEM_READ("getmsg(flagsp)", ARG4, sizeof(int));
+   /*PRE_MEM_WRITE("getmsg(flagsp)", ARG4, sizeof(int));*/
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "getmsg", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_getmsg)
+{
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+
+   if (ctrlptr && ctrlptr->len > 0)
+      POST_MEM_WRITE((Addr)ctrlptr->buf, ctrlptr->len);
+   if (dataptr && dataptr->len > 0)
+      POST_MEM_WRITE((Addr)dataptr->buf, dataptr->len);
+   POST_MEM_WRITE(ARG4, sizeof(int));
+}
+
+PRE(sys_putmsg)
+{
+   /* int putmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr,
+                 int flags); */
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+   *flags |= SfMayBlock;
+   PRINT("sys_putmsg ( %ld, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "putmsg", int, fildes, struct vki_strbuf *, ctrlptr,
+                 struct vki_strbuf *, dataptr, int, flags);
+   if (ctrlptr) {
+      PRE_FIELD_READ("putmsg(ctrlptr->len)", ctrlptr->len);
+      PRE_FIELD_READ("putmsg(ctrlptr->buf)", ctrlptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG2, sizeof(struct vki_strbuf))
+          && ctrlptr->len > 0)
+         PRE_MEM_READ("putmsg(ctrlptr->buf)", (Addr)ctrlptr->buf,
+                      ctrlptr->len);
+   }
+   if (dataptr) {
+      PRE_FIELD_READ("putmsg(dataptr->len)", dataptr->len);
+      PRE_FIELD_READ("putmsg(dataptr->buf)", dataptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG3, sizeof(struct vki_strbuf))
+          && dataptr->len > 0)
+         PRE_MEM_READ("putmsg(dataptr->buf)", (Addr)dataptr->buf,
+                      dataptr->len);
+   }
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "putmsg", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_lstat)
+{
+   /* int lstat(const char *path, struct stat *buf); */
+   /* Note: We could use here the sys_newlstat generic wrapper, but the 'new'
+      in its name is rather confusing in the Solaris context, thus we provide
+      our own wrapper. */
+   PRINT("sys_lstat ( %#lx(%s), %#lx )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "lstat", const char *, path, struct stat *, buf);
+
+   PRE_MEM_RASCIIZ("lstat(path)", ARG1);
+   PRE_MEM_WRITE("lstat(buf)", ARG2, sizeof(struct vki_stat));
+}
+
+POST(sys_lstat)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat));
+}
+
+PRE(sys_sigprocmask)
+{
+   /* int sigprocmask(int how, const sigset_t *set, sigset_t *oset); */
+   PRINT("sys_sigprocmask ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sigprocmask",
+                 int, how, vki_sigset_t *, set, vki_sigset_t *, oset);
+   if (ARG2)
+      PRE_MEM_READ("sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
+   if (ARG3)
+      PRE_MEM_WRITE("sigprocmask(oset)", ARG3, sizeof(vki_sigset_t));
+
+   /* Be safe. */
+   if (ARG2 && !ML_(safe_to_deref((void*)ARG2, sizeof(vki_sigset_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+   if (ARG3 && !ML_(safe_to_deref((void*)ARG3, sizeof(vki_sigset_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+
+   if (!FAILURE)
+      SET_STATUS_from_SysRes(
+         VG_(do_sys_sigprocmask)(tid, ARG1 /*how*/, (vki_sigset_t*)ARG2,
+                                 (vki_sigset_t*)ARG3)
+      );
+
+   if (SUCCESS)
+      *flags |= SfPollAfter;
+}
+
+POST(sys_sigprocmask)
+{
+   if (ARG3)
+      POST_MEM_WRITE(ARG3, sizeof(vki_sigset_t));
+}
+
+PRE(sys_sigaction)
+{
+   /* int sigaction(int signal, const struct sigaction *act,
+                    struct sigaction *oact); */
+   PRINT("sys_sigaction ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sigaction", int, signal,
+                 const struct sigaction *, act, struct sigaction *, oact);
+
+   /* Note that on Solaris, vki_sigaction_toK_t and vki_sigaction_fromK_t are
+      both typedefs of 'struct sigaction'. */
+
+   if (ARG2) {
+      vki_sigaction_toK_t *sa = (vki_sigaction_toK_t*)ARG2;
+      PRE_FIELD_READ("sigaction(act->sa_flags)", sa->sa_flags);
+      PRE_FIELD_READ("sigaction(act->sa_handler)", sa->ksa_handler);
+      PRE_FIELD_READ("sigaction(act->sa_mask)", sa->sa_mask);
+   }
+   if (ARG3)
+      PRE_MEM_WRITE("sigaction(oact)", ARG3, sizeof(vki_sigaction_fromK_t));
+
+   /* Be safe. */
+   if (ARG2 && !ML_(safe_to_deref((void*)ARG2,
+                                  sizeof(vki_sigaction_toK_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+   if (ARG3 && !ML_(safe_to_deref((void*)ARG3,
+                                   sizeof(vki_sigaction_fromK_t)))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+
+   if (!FAILURE)
+      SET_STATUS_from_SysRes(
+         VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t*)ARG2,
+                              (vki_sigaction_fromK_t*)ARG3));
+}
+
+POST(sys_sigaction)
+{
+   if (ARG3)
+      POST_MEM_WRITE(ARG3, sizeof(vki_sigaction_fromK_t));
+}
+
+PRE(sys_sigpending)
+{
+   /* int sigpending(int flag, sigset_t *setp); */
+   PRINT("sys_sigpending ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "sigpending", int, flag, sigset_t *, setp);
+   PRE_MEM_WRITE("sigpending(setp)", ARG2, sizeof(vki_sigset_t));
+}
+
+POST(sys_sigpending)
+{
+   POST_MEM_WRITE(ARG2, sizeof(vki_sigset_t));
+}
+
+PRE(sys_getsetcontext)
+{
+   /* Kernel: int getsetcontext(int flag, void *arg) */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   PRINT("sys_getsetcontext ( %ld, %#lx )", ARG1, ARG2);
+   switch (ARG1 /*flag*/) {
+   case VKI_GETCONTEXT:
+      /* Libc: int getcontext(ucontext_t *ucp); */
+      PRE_REG_READ2(long, SC2("getsetcontext", "getcontext"), int, flag,
+                    ucontext_t *, ucp);
+      PRE_MEM_WRITE("getsetcontext(ucp)", ARG2, sizeof(vki_ucontext_t));
+
+      if (!ML_(safe_to_deref((void*)ARG2, sizeof(vki_ucontext_t)))) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+      VG_(save_context)(tid, (vki_ucontext_t*)ARG2, Vg_CoreSysCall);
+      SET_STATUS_Success(0);
+      break;
+   case VKI_SETCONTEXT:
+      /* Libc: int setcontext(const ucontext_t *ucp); */
+      PRE_REG_READ2(long, SC2("getsetcontext", "setcontext"), int, flag,
+                    const ucontext_t *, ucp);
+
+      if (!ARG2) {
+         /* Setting NULL context causes thread exit. */
+         tst->exitreason = VgSrc_ExitThread;
+         tst->os_state.exitcode = 0;
+         SET_STATUS_Success(0);
+         return;
+      }
+
+      if (!ML_(safe_to_deref((void*)ARG2, sizeof(vki_ucontext_t)))) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+
+      VG_(restore_context)(tid, (vki_ucontext_t*)ARG2,
+                           Vg_CoreSysCall, False/*esp_is_thrptr*/);
+      /* Tell the driver not to update the guest state with the "result". */
+      *flags |= SfNoWriteResult;
+      /* Check to see if any signals arose as a result of this. */
+      *flags |= SfPollAfter;
+
+      /* Check if this is a possible return from a signal handler. */
+      VG_(sigframe_return)(tid, (vki_ucontext_t*)ARG2);
+
+      SET_STATUS_Success(0);
+      break;
+   case VKI_GETUSTACK:
+      /* Libc: int getustack(stack_t **spp); */
+      PRE_REG_READ2(long, SC2("getsetcontext", "getustack"), int, flag,
+                    stack_t **, spp);
+      PRE_MEM_WRITE("getsetcontext(spp)", ARG2, sizeof(vki_stack_t*));
+
+      if (!ML_(safe_to_deref((void*)ARG2, sizeof(vki_stack_t*)))) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+
+      *(vki_stack_t**)ARG2 = tst->os_state.ustack;
+      POST_MEM_WRITE(ARG2, sizeof(vki_stack_t*));
+      SET_STATUS_Success(0);
+      break;
+   case VKI_SETUSTACK:
+      {
+         /* Libc: int setustack(stack_t *sp); */
+         PRE_REG_READ2(long, SC2("getsetcontext", "setustack"), int, flag,
+                       stack_t *, sp);
+
+         /* The kernel does not read the stack data instantly but it can read
+            them later so it is better to make sure the data are defined. */
+         PRE_MEM_READ("getsetcontext_setustack(sp)", ARG2, sizeof(vki_stack_t));
+
+         if (!ML_(safe_to_deref((void*)ARG2, sizeof(vki_stack_t)))) {
+            SET_STATUS_Failure(VKI_EFAULT);
+            return;
+         }
+
+         vki_stack_t *old_stack = tst->os_state.ustack;
+         tst->os_state.ustack = (vki_stack_t*)ARG2;
+
+         /* The thread is setting the ustack pointer.  It is a good time to get
+            information about its stack. */
+         if (tst->os_state.ustack->ss_flags == 0) {
+            /* If the sanity check of ss_flags passed set the stack. */
+            set_stack(tid, tst->os_state.ustack);
+
+            if ((old_stack == NULL) && (tid > 1)) {
+               /* New thread creation is now completed. Inform the tool. */
+               VG_TRACK(pre_thread_first_insn, tid);
+            }
+         }
+
+         SET_STATUS_Success(0);
+      }
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the context call with flag %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+PRE(sys_fchmodat)
+{
+   /* int fchmodat(int fd, const char *path, mode_t mode, int flag); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_fchmodat ( %d, %#lx(%s), %ld, %ld )",
+         fd, ARG2, (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "fchmodat",
+                 int, fd, const char *, path, vki_mode_t, mode, int, flag);
+
+   if (ARG2)
+      PRE_MEM_RASCIIZ("fchmodat(path)", ARG2);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "fchmodat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_mkdirat)
+{
+   /* int mkdirat(int fd, const char *path, mode_t mode); */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   *flags |= SfMayBlock;
+   PRINT("sys_mkdirat ( %d, %#lx(%s), %ld )", fd, ARG2, (HChar *) ARG2, ARG3);
+   PRE_REG_READ3(long, "mkdirat", int, fd, const char *, path,
+                 vki_mode_t, mode);
+   PRE_MEM_RASCIIZ("mkdirat(path)", ARG2);
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "mkdirat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+static void do_statvfs_post(struct vki_statvfs *stats, ThreadId tid)
+{
+   POST_FIELD_WRITE(stats->f_bsize);
+   POST_FIELD_WRITE(stats->f_frsize);
+   POST_FIELD_WRITE(stats->f_blocks);
+   POST_FIELD_WRITE(stats->f_bfree);
+   POST_FIELD_WRITE(stats->f_bavail);
+   POST_FIELD_WRITE(stats->f_files);
+   POST_FIELD_WRITE(stats->f_ffree);
+   POST_FIELD_WRITE(stats->f_favail);
+   POST_FIELD_WRITE(stats->f_fsid);
+   POST_MEM_WRITE((Addr) stats->f_basetype, VG_(strlen)(stats->f_basetype) + 1);
+   POST_FIELD_WRITE(stats->f_flag);
+   POST_FIELD_WRITE(stats->f_namemax);
+   POST_MEM_WRITE((Addr) stats->f_fstr, VG_(strlen)(stats->f_fstr) + 1);
+}
+
+PRE(sys_statvfs)
+{
+   /* int statvfs(const char *path, struct statvfs *buf); */
+   *flags |= SfMayBlock;
+   PRINT("sys_statvfs ( %#lx(%s), %#lx )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "statvfs", const char *, path,
+                 struct vki_statvfs *, buf);
+   PRE_MEM_RASCIIZ("statvfs(path)", ARG1);
+   PRE_MEM_WRITE("statvfs(buf)", ARG2, sizeof(struct vki_statvfs));
+}
+
+POST(sys_statvfs)
+{
+   do_statvfs_post((struct vki_statvfs *) ARG2, tid);
+}
+
+PRE(sys_fstatvfs)
+{
+   /* int fstatvfs(int fd, struct statvfs *buf); */
+   *flags |= SfMayBlock;
+   PRINT("sys_fstatvfs ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "fstatvfs", int, fd, struct vki_statvfs *, buf);
+   PRE_MEM_WRITE("fstatvfs(buf)", ARG2, sizeof(struct vki_statvfs));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fstatvfs", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstatvfs)
+{
+   do_statvfs_post((struct vki_statvfs *) ARG2, tid);
+}
+
+PRE(sys_nfssys)
+{
+   /* int nfssys(enum nfssys_op opcode, void *arg); */
+   *flags |= SfMayBlock;
+   PRINT("sys_nfssys ( %ld, %#lx )", ARG1, ARG2);
+
+   switch (ARG1 /*opcode*/) {
+   case VKI_NFS_REVAUTH:
+      PRE_REG_READ2(long, SC2("nfssys", "nfs_revauth"), int, opcode,
+                    struct vki_nfs_revauth_args *, args);
+      PRE_MEM_READ("nfssys(arg)", ARG2,
+                   sizeof(struct vki_nfs_revauth_args));
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the nfssys call with opcode %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_nfssys)
+{
+   switch (ARG1 /*opcode*/) {
+   case VKI_NFS_REVAUTH:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_waitid)
+{
+   /* int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); */
+   *flags |= SfMayBlock;
+   PRINT("sys_waitid( %ld, %ld, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "waitid", vki_idtype_t, idtype, vki_id_t, id,
+                 siginfo_t *, infop, int, options);
+   PRE_MEM_WRITE("waitid(infop)", ARG3, sizeof(vki_siginfo_t));
+}
+
+POST(sys_waitid)
+{
+   POST_MEM_WRITE(ARG3, sizeof(vki_siginfo_t));
+}
+
+#if defined(SOLARIS_UTIMESYS_SYSCALL)
+PRE(sys_utimesys)
+{
+   /* Kernel: int utimesys(int code, uintptr_t arg1, uintptr_t arg2,
+                           uintptr_t arg3, uintptr_t arg4);
+    */
+
+   switch (ARG1 /*code*/) {
+   case 0:
+      /* Libc: int futimens(int fd, const timespec_t times[2]); */
+      PRINT("sys_utimesys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, "utimesys", int, code, int, fd,
+                    const vki_timespec_t *, times);
+      if (ARG3)
+         PRE_MEM_READ("utimesys(times)", ARG3, 2 * sizeof(vki_timespec_t));
+
+      /* Be strict. */
+      if (!ML_(fd_allowed)(ARG2, "utimesys", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      break;
+   case 1:
+      {
+         /* Libc: int utimensat(int fd, const char *path,
+                                const timespec_t times[2], int flag);
+          */
+
+         /* Interpret the second argument as 32-bit value even on 64-bit
+            architecture. This is different from Linux, for example, where glibc
+            sign-extends it. */
+         Int fd = (Int) ARG2;
+
+         PRINT("sys_utimesys ( %ld, %d, %#lx(%s), %#lx, %ld )",
+               ARG1, fd, ARG3, (HChar *) ARG3, ARG4, ARG5);
+         PRE_REG_READ5(long, "utimesys", int, code, int, fd, const char *, path,
+                       const vki_timespec_t *, times, int, flag);
+         if (ARG3)
+            PRE_MEM_RASCIIZ("utimesys(path)", ARG3);
+         if (ARG4)
+            PRE_MEM_READ("utimesys(times)", ARG4, 2 * sizeof(vki_timespec_t));
+
+         /* Be strict but ignore fd for absolute path. */
+         if (fd != VKI_AT_FDCWD
+             && ML_(safe_to_deref)((void *) ARG3, 1)
+             && ((HChar *) ARG3)[0] != '/'
+             && !ML_(fd_allowed)(fd, "utimesys", tid, False))
+            SET_STATUS_Failure(VKI_EBADF);
+         break;
+      }
+   default:
+      VG_(unimplemented)("Syswrap of the utimesys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+#endif /* SOLARIS_UTIMESYS_SYSCALL */
+
+#if defined(SOLARIS_UTIMENSAT_SYSCALL)
+PRE(sys_utimensat)
+{
+   /* int utimensat(int fd, const char *path, const timespec_t times[2],
+                    int flag);
+    */
+
+   /* Interpret the first argument as 32-bit value even on 64-bit architecture.
+      This is different from Linux, for example, where glibc sign-extends it. */
+   Int fd = (Int) ARG1;
+
+   PRINT("sys_utimensat ( %d, %#lx(%s), %#lx, %ld )",
+         fd, ARG2, (HChar *) ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "utimensat", int, fd, const char *, path,
+                 const vki_timespec_t *, times, int, flag);
+   if (ARG2)
+      PRE_MEM_RASCIIZ("utimensat(path)", ARG2);
+   if (ARG3)
+      PRE_MEM_READ("utimensat(times)", ARG3, 2 * sizeof(vki_timespec_t));
+
+   /* Be strict but ignore fd for absolute path. */
+   if (fd != VKI_AT_FDCWD
+       && ML_(safe_to_deref)((void *) ARG2, 1)
+       && ((HChar *) ARG2)[0] != '/'
+       && !ML_(fd_allowed)(fd, "utimensat", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+#endif /* SOLARIS_UTIMENSAT_SYSCALL */
+
+PRE(sys_sigresend)
+{
+   /* int sigresend(int signal, siginfo_t *siginfo, sigset_t *mask); */
+   /* Sends a signal to the calling thread, the mask parameter specifies a new
+      signal mask. */
+
+   /* Static (const) mask accessible from outside of this function. */
+   static vki_sigset_t block_all;
+
+   PRINT("sys_sigresend( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sigresend", int, signal, vki_siginfo_t *, siginfo,
+                 vki_sigset_t *, mask);
+
+   if (ARG2)
+      PRE_MEM_READ("sigresend(siginfo)", ARG2, sizeof(vki_siginfo_t));
+   PRE_MEM_WRITE("sigresend(mask)", ARG3, sizeof(vki_sigset_t));
+
+   /* Check the signal and mask. */
+   if (!ML_(client_signal_OK)(ARG1)) {
+      SET_STATUS_Failure(VKI_EINVAL);
+   }
+   if (!ML_(safe_to_deref)((void*)ARG3, sizeof(vki_sigset_t))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+   
+   /* Exit early if there are problems. */
+   if (FAILURE)
+      return;
+
+   /* Save the requested mask to unused ARG4. */
+   ARG4 = ARG3;
+
+   /* Fake the requested sigmask with a block-all mask.  If the syscall
+      suceeds then we will block "all" signals for a few instructions (in
+      syscall-x86-solaris.S) but the correct mask will be almost instantly set
+      again by a call to sigprocmask (also in syscall-x86-solaris.S).  If the
+      syscall fails then the mask is not changed, so everything is ok too. */
+   VG_(sigfillset)(&block_all);
+   ARG3 = (UWord)&block_all;
+
+   /* Check to see if this gave us a pending signal. */
+   *flags |= SfPollAfter;
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "sigresend: resending signal %ld\n", ARG1);
+
+   /* Handle SIGKILL specially. */
+   if (ARG1 == VKI_SIGKILL && ML_(do_sigkill)(tid, -1)) {
+      SET_STATUS_Success(0);
+      return;
+   }
+
+   /* Ask to handle this syscall via the slow route, since that's the only one
+      that sets tst->status to VgTs_WaitSys.  If the result of doing the
+      syscall is an immediate run of async_signalhandler() in m_signals.c,
+      then we need the thread to be properly tidied away. */
+   *flags |= SfMayBlock;
+}
+
+POST(sys_sigresend)
+{
+   /* The syscall succeeded, set the requested mask. */
+   VG_(do_sys_sigprocmask)(tid, VKI_SIG_SETMASK, (vki_sigset_t*)ARG4, NULL);
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "sigresend: resent signal %ld\n", ARG1);
+}
+
+static void mem_priocntlsys_parm_ok(ThreadId tid, Bool pre, Bool reade,
+                                    vki_pc_vaparm_t *parm)
+{
+   if (reade)
+      return;
+
+   if (pre)
+      PRE_FIELD_WRITE("priocntlsys(parm)", parm->pc_parm);
+   else
+      POST_FIELD_WRITE(parm->pc_parm);
+}
+
+static void mem_priocntlsys_parm(ThreadId tid, Bool pre, Bool reade,
+                                 const HChar *clname,
+                                 vki_pc_vaparm_t *parm)
+{
+   /* This function is used to handle the PC_SETXPARMS and PC_GETXPARMS
+      parameters.  In the case of PC_SETXPARMS, the code below merely checks
+      if all parameters are scalar, PRE_MEM_READ() for these parameters is
+      already done by the PC_SETXPARMS handler in PRE(sys_priocntlsys).
+
+      A caller of this function is responsible for checking that clname and
+      &parm->key can be dereferenced. */
+
+   if (VG_STREQ(clname, "RT")) {
+      switch (parm->pc_key) {
+      case VKI_RT_KY_PRI:
+      case VKI_RT_KY_TQSECS:
+      case VKI_RT_KY_TQNSECS:
+      case VKI_RT_KY_TQSIG:
+         /* Scalar values that are stored directly in pc_parm. */
+         mem_priocntlsys_parm_ok(tid, pre, reade, parm);
+         return;
+      }
+   }
+   else if (VG_STREQ(clname, "TS")) {
+      switch (parm->pc_key) {
+      case VKI_TS_KY_UPRILIM:
+      case VKI_TS_KY_UPRI:
+         /* Scalar values that are stored directly in pc_parm. */
+         mem_priocntlsys_parm_ok(tid, pre, reade, parm);
+         return;
+      }
+   }
+   else if (VG_STREQ(clname, "IA")) {
+      switch (parm->pc_key) {
+      case VKI_IA_KY_UPRILIM:
+      case VKI_IA_KY_UPRI:
+      case VKI_IA_KY_MODE:
+         /* Scalar values that are stored directly in pc_parm. */
+         mem_priocntlsys_parm_ok(tid, pre, reade, parm);
+         return;
+      }
+   }
+   else if (VG_STREQ(clname, "FSS")) {
+      switch (parm->pc_key) {
+      case VKI_FSS_KY_UPRILIM:
+      case VKI_FSS_KY_UPRI:
+         /* Scalar values that are stored directly in pc_parm. */
+         mem_priocntlsys_parm_ok(tid, pre, reade, parm);
+         return;
+      }
+   }
+   else if (VG_STREQ(clname, "FX")) {
+      switch (parm->pc_key) {
+      case VKI_FX_KY_UPRILIM:
+      case VKI_FX_KY_UPRI:
+      case VKI_FX_KY_TQSECS:
+      case VKI_FX_KY_TQNSECS:
+         /* Scalar values that are stored directly in pc_parm. */
+         mem_priocntlsys_parm_ok(tid, pre, reade, parm);
+         return;
+      }
+   }
+   else {
+      /* Unknown class. */
+      VG_(unimplemented)("Syswrap of the priocntlsys call where clname=%s.",
+                         clname);
+      /*NOTREACHED*/
+   }
+
+   /* The class is known but pc_key is unknown. */
+   VG_(unimplemented)("Syswrap of the priocntlsys call where clname=%s "
+                      "and pc_key=%d.", clname, parm->pc_key);
+   /*NOTREACHED*/
+}
+
+PRE(sys_priocntlsys)
+{
+   /* long priocntlsys(int pc_version, procset_t *psp, int cmd, caddr_t arg,
+                       caddr_t arg2); */
+
+   if (ARG1 != 1) {
+      /* Only the first version of priocntlsys is supported by the code below.
+       */
+      VG_(unimplemented)("Syswrap of the priocntlsys where pc_version=%ld.",
+                         ARG1);
+      /*NOTREACHED*/
+   }
+
+   PRINT("sys_priocntlsys ( %ld, %#lx, %ld, %#lx, %#lx )", ARG1, ARG2, ARG3,
+         ARG4, ARG5);
+   PRE_REG_READ5(long, "priocntlsys", int, pc_version, procset_t *, psp,
+                 int, cmd, void *, arg, void *, arg2);
+
+   switch (ARG3 /*cmd*/) {
+   case VKI_PC_GETCID:
+      if (ARG4) {
+         vki_pcinfo_t *info = (vki_pcinfo_t*)ARG4;
+         PRE_MEM_RASCIIZ("priocntlsys(clname)", (Addr)info->pc_clname);
+         /* The next line says that the complete pcinfo_t structure can be
+            written, but this actually isn't true for pc_clname which is
+            always only read. */
+         PRE_MEM_WRITE("priocntlsys(pcinfo)", ARG4, sizeof(vki_pcinfo_t));
+      }
+      break;
+   case VKI_PC_GETCLINFO:
+      if (ARG4) {
+         vki_pcinfo_t *info = (vki_pcinfo_t*)ARG4;
+         PRE_FIELD_READ("priocntlsys(cid)", info->pc_cid);
+         /* The next line says that the complete pcinfo_t structure can be
+            written, but this actually isn't true for pc_cid which is
+            always only read. */
+         PRE_MEM_WRITE("priocntlsys(pcinfo)", ARG4, sizeof(vki_pcinfo_t));
+      }
+      break;
+   case VKI_PC_SETPARMS:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      /* The next line says that the complete pcparms_t structure is read
+         which is never actually true (we are too pessimistic here).
+         Unfortunately we can't do better because we don't know what
+         process class is involved. */
+      PRE_MEM_READ("priocntlsys(parms)", ARG4, sizeof(vki_pcparms_t));
+      break;
+   case VKI_PC_GETPARMS:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      PRE_MEM_WRITE("priocntlsys(parms)", ARG4, sizeof(vki_pcparms_t));
+      break;
+   case VKI_PC_GETPRIRANGE:
+      {
+         vki_pcpri_t *pcpri = (vki_pcpri_t*)ARG4;
+         PRE_FIELD_READ("priocntlsys(cid)", pcpri->pc_cid);
+      }
+      PRE_MEM_WRITE("priocntlsys(pri)", ARG4, sizeof(vki_pcpri_t));
+      break;
+   case VKI_PC_DONICE:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      {
+         vki_pcnice_t *nicee = (vki_pcnice_t*)ARG4;
+         PRE_FIELD_READ("priocntlsys(op)", nicee->pc_op);
+         if (ML_(safe_to_deref)(&nicee->pc_op, sizeof(nicee->pc_op))) {
+            switch (nicee->pc_op) {
+            case VKI_PC_GETNICE:
+               PRE_FIELD_WRITE("priocntlsys(val)", nicee->pc_val);
+               break;
+            case VKI_PC_SETNICE:
+               PRE_FIELD_READ("priocntlsys(val)", nicee->pc_val);
+               break;
+            default:
+               VG_(unimplemented)("Syswrap of the priocntlsys call where "
+                                  "cmd=PC_DONICE and pc_op=%d", nicee->pc_op);
+               /*NOTREACHED*/
+               break;
+            }
+         }
+      }
+      break;
+   case VKI_PC_SETXPARMS:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      PRE_MEM_RASCIIZ("priocntlsys(clname)", ARG4);
+      if (ARG5) {
+         vki_pc_vaparms_t *parms = (vki_pc_vaparms_t*)ARG5;
+         PRE_FIELD_READ("priocntlsys(vaparmscnt)", parms->pc_vaparmscnt);
+         if (ML_(safe_to_deref)(&parms->pc_vaparmscnt,
+                                sizeof(parms->pc_vaparmscnt))) {
+            vki_uint_t i;
+            PRE_MEM_READ("priocntlsys(parms)", (Addr)parms->pc_parms,
+                         parms->pc_vaparmscnt * sizeof(parms->pc_parms[0]));
+            for (i = 0; i < parms->pc_vaparmscnt; i++) {
+               vki_pc_vaparm_t *parm = &parms->pc_parms[i];
+               if (ML_(safe_to_deref)(parm, sizeof(*parm)) &&
+                   ML_(safe_to_deref)((void*)ARG4, 1))
+                  mem_priocntlsys_parm(tid, True /*pre*/, True /*read*/,
+                                       (HChar*)ARG4, parm);
+            }
+         }
+      }
+      break;
+   case VKI_PC_GETXPARMS:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      if (ARG4)
+         PRE_MEM_RASCIIZ("priocntlsys(clname)", ARG4);
+      if (ARG5) {
+         vki_pc_vaparms_t *parms = (vki_pc_vaparms_t*)ARG5;
+         PRE_FIELD_READ("priocntlsys(vaparmscnt)", parms->pc_vaparmscnt);
+         if (ML_(safe_to_deref)(&parms->pc_vaparmscnt,
+                                sizeof(parms->pc_vaparmscnt))) {
+            vki_uint_t i;
+            for (i = 0; i < parms->pc_vaparmscnt; i++) {
+               vki_pc_vaparm_t *parm = &parms->pc_parms[i];
+               PRE_MEM_READ("priocntlsys(parms)", (Addr)&parm->pc_key,
+                            parms->pc_vaparmscnt * sizeof(parm->pc_key));
+               if (ML_(safe_to_deref)(&parm->pc_key,
+                                      sizeof(parm->pc_key))) {
+                  /* First handle PC_KY_CLNAME, then class specific keys.
+                     Note that PC_KY_CLNAME can be used only with
+                     ARG4==NULL && parms->pc_vaparmscnt==1.  We are not so
+                     strict here and handle this special case as a regular
+                     one which makes the code simpler. */
+                  if (parm->pc_key == VKI_PC_KY_CLNAME)
+                     PRE_MEM_WRITE("priocntlsys(clname)", parm->pc_parm,
+                                   VKI_PC_CLNMSZ);
+                  else if (ARG4 && ML_(safe_to_deref)((void*)ARG4, 1))
+                     mem_priocntlsys_parm(tid, True /*pre*/,
+                                          False /*read*/, (HChar*)ARG4,
+                                          parm);
+               }
+            }
+         }
+      }
+      break;
+   case VKI_PC_SETDFLCL:
+      PRE_MEM_RASCIIZ("priocntlsys(clname)", ARG4);
+      break;
+   case VKI_PC_GETDFLCL:
+      if (ARG4) {
+         /* GETDFLCL writes to the ARG4 buffer only if ARG4 isn't NULL.  Also
+            note that if ARG4 is NULL then the syscall succeeds. */
+         PRE_MEM_WRITE("priocntlsys(clname)", ARG4, VKI_PC_CLNMSZ);
+      }
+      break;
+   case VKI_PC_DOPRIO:
+      PRE_MEM_READ("priocntlsys(psp)", ARG2, sizeof(vki_procset_t));
+      {
+         vki_pcprio_t *prio = (vki_pcprio_t*)ARG4;
+         PRE_FIELD_READ("priocntlsys(op)", prio->pc_op);
+         if (ML_(safe_to_deref)(&prio->pc_op, sizeof(prio->pc_op))) {
+            switch (prio->pc_op) {
+            case VKI_PC_GETPRIO:
+               PRE_FIELD_WRITE("priocntlsys(cid)", prio->pc_cid);
+               PRE_FIELD_WRITE("priocntlsys(val)", prio->pc_val);
+               break;
+            case VKI_PC_SETPRIO:
+               PRE_FIELD_READ("priocntlsys(cid)", prio->pc_cid);
+               PRE_FIELD_READ("priocntlsys(val)", prio->pc_val);
+               break;
+            default:
+               VG_(unimplemented)("Syswrap of the priocntlsys call where "
+                                  "cmd=PC_DOPRIO and pc_op=%d", prio->pc_op);
+               /*NOTREACHED*/
+               break;
+            }
+         }
+      }
+      break;
+   case VKI_PC_ADMIN:
+   default:
+      VG_(unimplemented)("Syswrap of the priocntlsys call with cmd %ld.", ARG3);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+static void post_mem_write_priocntlsys_clinfo(ThreadId tid,
+                                              const HChar *clname, Addr clinfo)
+{
+   if (VG_STREQ(clname, "RT"))
+      POST_MEM_WRITE(clinfo, sizeof(vki_rtinfo_t));
+   else if (VG_STREQ(clname, "TS"))
+      POST_MEM_WRITE(clinfo, sizeof(vki_tsinfo_t));
+   else if (VG_STREQ(clname, "IA"))
+      POST_MEM_WRITE(clinfo, sizeof(vki_iainfo_t));
+   else if (VG_STREQ(clname, "FSS"))
+      POST_MEM_WRITE(clinfo, sizeof(vki_fssinfo_t));
+   else if (VG_STREQ(clname, "FX"))
+      POST_MEM_WRITE(clinfo, sizeof(vki_fxinfo_t));
+   else if (VG_STREQ(clname, "SDC")) {
+      /* Relax. */
+   }
+   else {
+      VG_(unimplemented)("Syswrap of the priocntlsys call where clname=%s.",
+                         clname);
+      /*NOTREACHED*/
+   }
+}
+
+POST(sys_priocntlsys)
+{
+   switch (ARG3 /*cmd*/) {
+   case VKI_PC_GETCID:
+      if (ARG4) {
+         vki_pcinfo_t *info = (vki_pcinfo_t*)ARG4;
+         POST_FIELD_WRITE(info->pc_cid);
+         post_mem_write_priocntlsys_clinfo(tid, info->pc_clname,
+                                           (Addr)&info->pc_clinfo);
+      }
+      break;
+   case VKI_PC_GETCLINFO:
+      if (ARG4) {
+         vki_pcinfo_t *info = (vki_pcinfo_t*)ARG4;
+         POST_MEM_WRITE((Addr)info->pc_clname,
+                        VG_(strlen)((HChar*)info->pc_clname) + 1);
+         post_mem_write_priocntlsys_clinfo(tid, info->pc_clname,
+                                           (Addr)&info->pc_clinfo);
+      }
+      break;
+   case VKI_PC_SETPARMS:
+      /* Relax. */
+      break;
+   case VKI_PC_GETPARMS:
+      /* The next line says that the complete pcparms_t structure is
+         written which is never actually true (we are too optimistic here).
+         Unfortunately we can't do better because we don't know what
+         process class is involved. */
+      POST_MEM_WRITE(ARG4, sizeof(vki_pcparms_t));
+      break;
+   case VKI_PC_GETPRIRANGE:
+      POST_MEM_WRITE(ARG4, sizeof(vki_pcpri_t));
+      break;
+   case VKI_PC_DONICE:
+      {
+         vki_pcnice_t *nicee = (vki_pcnice_t*)ARG4;
+         if (nicee->pc_op == VKI_PC_GETNICE)
+            POST_FIELD_WRITE(nicee->pc_val);
+      }
+      break;
+   case VKI_PC_SETXPARMS:
+      /* Relax. */
+      break;
+   case VKI_PC_GETXPARMS:
+      {
+         vki_pc_vaparms_t *parms = (vki_pc_vaparms_t*)ARG5;
+         vki_uint_t i;
+         for (i = 0; i < parms->pc_vaparmscnt; i++) {
+            vki_pc_vaparm_t *parm = &parms->pc_parms[i];
+            if (parm->pc_key == VKI_PC_KY_CLNAME)
+               POST_MEM_WRITE(parm->pc_parm,
+                              VG_(strlen)((HChar*)(Addr)parm->pc_parm) + 1);
+            else if (ARG4)
+               mem_priocntlsys_parm(tid, False /*pre*/, False /*read*/,
+                                    (HChar*)ARG4, parm);
+         }
+      }
+      break;
+   case VKI_PC_SETDFLCL:
+      /* Relax. */
+      break;
+   case VKI_PC_GETDFLCL:
+      if (ARG4)
+         POST_MEM_WRITE(ARG4, VG_(strlen)((HChar*)ARG4) + 1);
+      break;
+   case VKI_PC_DOPRIO:
+      {
+         vki_pcprio_t *prio = (vki_pcprio_t*)ARG4;
+         if (prio->pc_op == VKI_PC_GETPRIO) {
+            POST_FIELD_WRITE(prio->pc_cid);
+            POST_FIELD_WRITE(prio->pc_val);
+         }
+      }
+      break;
+   case VKI_PC_ADMIN:
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_pathconf)
+{
+   /* long pathconf(const char *path, int name); */
+   PRINT("sys_pathconf ( %#lx(%s), %ld )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "pathconf", const char *, path, int, name);
+   PRE_MEM_RASCIIZ("pathconf(path)", ARG1);
+}
+
+PRE(sys_mmap)
+{
+   /* void *mmap(void *addr, size_t len, int prot, int flags,
+                 int fildes, off_t off); */
+   SysRes r;
+   OffT offset;
+
+   /* Stay sane. */
+   vg_assert(VKI_PAGE_SIZE == 4096);
+   vg_assert(sizeof(offset) == sizeof(ARG6));
+
+   PRINT("sys_mmap ( %#lx, %#lx, %#lx, %#lx, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "mmap", void *, start, vki_size_t, length,
+                 int, prot, int, flags, int, fd, vki_off_t, offset);
+
+   /* Make sure that if off < 0 then it's passed correctly to the generic mmap
+      wraper. */
+   offset = *(OffT*)&ARG6;
+
+   r = ML_(generic_PRE_sys_mmap)(tid, ARG1, ARG2, ARG3, ARG4, ARG5, offset);
+   SET_STATUS_from_SysRes(r);
+}
+
+#if defined(SOLARIS_UUIDSYS_SYSCALL)
+PRE(sys_uuidsys)
+{
+   /* int uuidsys(struct uuid *uuid); */
+   PRINT("sys_uuidsys ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "uuidsys", struct vki_uuid *, uuid);
+   PRE_MEM_WRITE("uuidsys(uuid)", ARG1, sizeof(struct vki_uuid));
+}
+
+POST(sys_uuidsys)
+{
+   POST_MEM_WRITE(ARG1, sizeof(struct vki_uuid));
+}
+#endif /* SOLARIS_UUIDSYS_SYSCALL */
+
+/* Syscall mmapobj emulation. Processes ELF program headers
+   and maps them into correct place in memory. Not an easy task, though.
+   ELF program header of PT_LOAD/PT_SUNWBSS type specifies:
+   o p_vaddr  - actually a memory offset
+   o p_memsz  - total segment size, including text, data and BSS
+   o p_filesz - file-based segment size mapping (includes only text and data);
+                p_memsz - p_filesz is the size of BSS
+   o p_offset - offset into the ELF file where the file-based mapping starts
+ 
+   Several problematic areas to cover here:
+   1. p_offset can contain a value which is not page-aligned. In that case
+      we mmap a part of the file prior to p_offset to make the start address
+      page-aligned.
+   2. Partially unused page after the file-based mapping must be zeroed.
+   3. The first mapping is flagged with MR_HDR_ELF and needs to contain
+      the ELF header. This information is used and verified by the dynamic
+      linker (ld.so.1). */
+static SysRes mmapobj_process_phdrs(ThreadId tid, Int fd,
+                                    vki_mmapobj_result_t *storage,
+                                    vki_uint_t *elements,
+                                    const VKI_ESZ(Ehdr) *ehdr,
+                                    const VKI_ESZ(Phdr) *phdrs)
+{
+#define ADVANCE_PHDR(ehdr, phdr) \
+   (const VKI_ESZ(Phdr) *) ((const HChar *) (phdr) + (ehdr)->e_phentsize)
+
+   SysRes res;
+   Int i;
+   Int first_segment_idx = -1;
+   UInt idx;
+   UInt segments = 0; /* loadable segments */
+   Addr start_addr = 0;
+   Addr end_addr = 0;
+   SizeT max_align = VKI_PAGE_SIZE;
+
+   /* 1. First pass over phdrs - determine number, span and max alignment. */
+   const VKI_ESZ(Phdr) *phdr = phdrs;
+   for (idx = 0; idx < ehdr->e_phnum; idx++, phdr = ADVANCE_PHDR(ehdr, phdr)) {
+      /* Skip this header if no memory is requested. */
+      if (phdr->p_memsz == 0)
+         continue;
+
+      if ((phdr->p_type == VKI_PT_LOAD) || (phdr->p_type == VKI_PT_SUNWBSS)) {
+         Off64T offset = 0;
+
+         if (VG_(clo_trace_syscalls))
+            VG_(debugLog)(2, "syswrap-solaris", "mmapobj_process_phdrs: "
+                             "program header #%u: addr=%#lx type=%#lx "
+                             "prot=%#lx memsz=%#lx filesz=%#lx file "
+                             "offset=%#lx\n", idx, phdr->p_vaddr,
+                             (UWord) phdr->p_type, (UWord) phdr->p_flags,
+                             phdr->p_memsz, phdr->p_filesz, phdr->p_offset);
+
+         if (segments == 0) {
+            first_segment_idx = idx;
+
+            if (phdr->p_filesz == 0) {
+               VG_(unimplemented)("Syswrap of the mmapobj call with the first "
+                                  "loadable ELF program header specifying "
+                                  "p_filesz == 0");
+              /*NOTREACHED*/
+              return res;
+            }
+
+            /* Address of the first segment must be either NULL or within the
+               first page. */
+            if ((ehdr->e_type == VKI_ET_DYN) &&
+                ((phdr->p_vaddr & VKI_PAGEMASK) != 0)) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                   "ELF program header #%u does not land on "
+                                   "the first page (vaddr=%#lx)\n", idx,
+                                   phdr->p_vaddr);
+               return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+            }
+
+            start_addr = phdr->p_vaddr;
+            /* The first segment is mapped from the beginning of the file (to
+               include also the ELF header), so include this memory as well.
+               Later on we flag this mapping with MR_HDR_ELF. */
+            offset = phdr->p_offset;
+         }
+
+         if (phdr->p_align > 1) {
+            if ((phdr->p_vaddr % phdr->p_align) !=
+                (phdr->p_offset % phdr->p_align)) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                   "ELF program header #%u does not have "
+                                   "congruent offset and vaddr (vaddr=%#lx "
+                                   "file offset=%#lx align=%#lx)\n", idx,
+                                   phdr->p_vaddr, phdr->p_offset,
+                                   phdr->p_align);
+               return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+            }
+         }
+
+         if (phdr->p_vaddr < end_addr) {
+            if (VG_(clo_trace_syscalls))
+               VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                "ELF program header #%u specifies overlaping "
+                                "address (vaddr=%#lx end_addr=%#lx)\n",
+                                idx, phdr->p_vaddr, end_addr);
+            return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+         }
+
+         end_addr = phdr->p_vaddr + phdr->p_memsz + offset;
+         end_addr = VG_PGROUNDUP(end_addr);
+         if (phdr->p_align > max_align) {
+            max_align = phdr->p_align;
+         }
+
+         segments += 1;
+      }
+   }
+
+   /* Alignment check - it should be power of two. */
+   if ((max_align & (max_align - 1)) != 0) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: alignment "
+                          "is not a power of 2 (%#lx)\n", max_align);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+   vg_assert(max_align >= VKI_PAGE_SIZE);
+
+#if defined(VGP_x86_solaris)
+   if (max_align > VKI_UINT_MAX) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: alignment "
+                          "for 32-bit ELF is >32-bits (%#lx)\n", max_align);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+#endif /* VGP_x86_solaris */
+
+   if (segments == 0) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: nothing "
+                          "to map (0 loadable segments)");
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   vg_assert(end_addr >= start_addr);
+   SizeT span = end_addr - start_addr;
+   if (span == 0) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: nothing "
+                          "to map (%u loadable segments spanning 0 bytes)\n",
+                          segments);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+   vg_assert(first_segment_idx >= 0);
+
+   if (segments > *elements) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: too many "
+                          "segments (%u)\n", segments);
+      return VG_(mk_SysRes_Error)(VKI_E2BIG);
+   }
+
+   if (VG_(clo_trace_syscalls))
+      VG_(debugLog)(2, "syswrap-solaris", "mmapobj_process_phdrs: there "
+                       "are %u loadable segments spanning %#lx bytes; max "
+                       "align is %#lx\n", segments, span, max_align);
+
+   /* Now get the aspacemgr oraculum advisory.
+      Later on we mmap file-based and BSS mappings into this address space area
+      as required and leave the holes unmapped. */
+   MapRequest mreq = {MAlign, max_align, span};
+   Bool ok;
+   start_addr = VG_(am_get_advisory)(&mreq, True /* forClient */, &ok);
+   if (!ok) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                          "failed to reserve address space of %#lx bytes "
+                          "with alignment %#lx\n", span, max_align);
+      return VG_(mk_SysRes_Error)(VKI_ENOMEM);
+   }
+   vg_assert(VG_ROUNDUP(start_addr, max_align) == start_addr);
+
+   if (VG_(clo_trace_syscalls))
+      VG_(debugLog)(2, "syswrap-solaris", "PRE(sys_mmapobj): address space "
+                       "reserved at: vaddr=%#lx size=%#lx\n", start_addr, span);
+
+   /* This is an utterly ugly hack, the aspacemgr assumes that only one
+      segment is added at the time. However we add here multiple segments so
+      AM_SANITY_CHECK inside the aspacemgr can easily fail. We want to
+      prevent that thus we disable these checks. The scheduler will check the
+      aspacemgr sanity after the syscall. */
+   UInt sanity_level = VG_(clo_sanity_level);
+   VG_(clo_sanity_level) = 1;
+
+   /* 2. Second pass over phdrs - map the program headers and fill in
+         the mmapobj_result_t array. */
+   phdr = phdrs;
+   *elements = 0;
+   for (idx = 0; idx < ehdr->e_phnum; idx++, phdr = ADVANCE_PHDR(ehdr, phdr)) {
+      /* Skip this header if no memory is requested. */
+      if (phdr->p_memsz == 0)
+         continue;
+
+      if ((phdr->p_type == VKI_PT_LOAD) || (phdr->p_type == VKI_PT_SUNWBSS)) {
+         UInt prot = 0;
+         if (phdr->p_flags & VKI_PF_R)
+            prot |= VKI_PROT_READ;
+         if (phdr->p_flags & VKI_PF_W)
+            prot |= VKI_PROT_WRITE;
+         if (phdr->p_flags & VKI_PF_X)
+            prot |= VKI_PROT_EXEC;
+
+         vki_mmapobj_result_t *mrp = &storage[*elements];
+         mrp->mr_addr = (vki_caddr_t) (start_addr + phdr->p_vaddr);
+         mrp->mr_msize = phdr->p_memsz;
+         mrp->mr_fsize = phdr->p_filesz;
+         mrp->mr_offset = 0;
+         mrp->mr_prot = prot;
+         mrp->mr_flags = 0;
+         Off64T file_offset = phdr->p_offset;
+         if (idx == first_segment_idx) {
+            mrp->mr_flags = VKI_MR_HDR_ELF;
+            if (phdr->p_offset > 0) {
+               /* Include the ELF header into the first segment.
+                  This means we ignore p_offset from the program header
+                  and map from file offset 0. */
+               mrp->mr_msize += phdr->p_offset;
+               mrp->mr_fsize += phdr->p_offset;
+               file_offset = 0;
+            }
+         }
+
+         SizeT page_offset = (Addr) mrp->mr_addr & VKI_PAGEOFFSET;
+         if (page_offset > 0) {
+            vg_assert(file_offset >= page_offset);
+            /* Mapping address does not start at the beginning of a page.
+               Therefore include some bytes before to make it page aligned. */
+            mrp->mr_addr -= page_offset;
+            mrp->mr_msize += page_offset;
+            mrp->mr_offset = page_offset;
+            file_offset -= page_offset;
+         }
+         SizeT file_size = mrp->mr_fsize + mrp->mr_offset;
+         if (VG_(clo_trace_syscalls))
+            VG_(debugLog)(2, "syswrap-solaris", "mmapobj_process_phdrs: "
+                             "mmapobj result #%u: addr=%#lx msize=%#lx "
+                             "fsize=%#lx mr_offset=%#lx prot=%#x flags=%#x\n",
+                             *elements, (Addr) mrp->mr_addr,
+                             (UWord) mrp->mr_msize, (UWord) mrp->mr_fsize,
+                             (UWord) mrp->mr_offset, mrp->mr_prot,
+                             mrp->mr_flags);
+
+         UInt flags = VKI_MAP_PRIVATE | VKI_MAP_FIXED;
+         if ((mrp->mr_prot & (VKI_PROT_WRITE | VKI_PROT_EXEC)) ==
+                                                               VKI_PROT_EXEC) {
+            flags |= VKI_MAP_TEXT;
+         } else {
+            flags |= VKI_MAP_INITDATA;
+         }
+
+         /* Determine if there will be partially unused page after file-based
+            mapping. If so, then we need to zero it explicitly afterwards. */
+         Addr mapping_end = (Addr) mrp->mr_addr + file_size;
+         SizeT zeroed_size = VG_PGROUNDUP(mapping_end) - mapping_end;
+         Bool mprotect_needed = False;
+         if ((zeroed_size > 0) && ((prot & VKI_PROT_WRITE) == 0)) {
+            prot |= VKI_PROT_WRITE;
+            mprotect_needed = True;
+         }
+
+         if (file_size > 0) {
+            res = VG_(am_mmap_file_fixed_client_flags)((Addr) mrp->mr_addr,
+                                       file_size, prot, flags, fd, file_offset);
+            if (sr_isError(res)) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                   "mmap failed: addr=%#lx size=%#lx prot=%#x "
+                                   "flags=%#x fd=%d file offset=%#llx\n",
+                                   (Addr) mrp->mr_addr, file_size,
+                                   prot, flags, fd, file_offset);
+               goto mmap_error;
+            }
+
+            VG_(debugLog)(1, "syswrap-solaris", "PRE(sys_mmapobj): new "
+                             "segment: vaddr=%#lx size=%#lx prot=%#x "
+                             "flags=%#x fd=%d file offset=%#llx\n",
+                             (Addr) mrp->mr_addr, file_size, mrp->mr_prot,
+                             flags, fd, file_offset);
+         }
+
+         if (zeroed_size > 0) {
+            /* Now zero out the end of partially used page. */
+            VG_(memset)((void *) mapping_end, 0, zeroed_size);
+            if (mprotect_needed) {
+               prot &= ~VKI_PROT_WRITE;
+               res = VG_(do_syscall3)(SYS_mprotect, (Addr) mrp->mr_addr,
+                                      file_size, prot);
+               if (sr_isError(res)) {
+                  if (VG_(clo_trace_syscalls))
+                     VG_(debugLog)(3, "syswrap-solaris",
+                                      "mmapobj_process_phdrs: mprotect failed: "
+                                      "addr=%#lx size=%#lx prot=%#x",
+                                      (Addr) mrp->mr_addr, file_size, prot);
+                  /* Mapping for this segment was already established. */
+                  idx += 1;
+                  goto mmap_error;
+               }
+            }
+         }
+
+         if (file_size > 0) {
+            ML_(notify_core_and_tool_of_mmap)((Addr) mrp->mr_addr, file_size,
+                                              prot, flags, fd, file_offset);
+         }
+
+         /* Page(s) after the mapping backed up by the file are part of BSS.
+            They need to be mmap'ed over with correct flags and will be
+            implicitly zeroed. */
+         mapping_end = VG_PGROUNDUP(mrp->mr_addr + mrp->mr_msize);
+         Addr page_end = VG_PGROUNDUP(mrp->mr_addr + file_size);
+         vg_assert(mapping_end >= page_end);
+         zeroed_size = mapping_end - page_end;
+         if (zeroed_size > 0) {
+            flags = VKI_MAP_FIXED | VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS;
+            res = VG_(am_mmap_anon_fixed_client)(page_end, zeroed_size, prot);
+            if (sr_isError(res)) {
+               if (VG_(clo_trace_syscalls))
+                  VG_(debugLog)(3, "syswrap-solaris", "mmapobj_process_phdrs: "
+                                   "mmap_anon failed: addr=%#lx size=%#lx "
+                                   "prot=%#x\n", page_end, zeroed_size, prot);
+               idx += 1; /* mapping for this segment was already established */
+               goto mmap_error;
+            }
+
+            VG_(debugLog)(1, "syswrap-solaris", "PRE(sys_mmapobj): new "
+                             "anonymous segment (BSS): vaddr=%#lx size=%#lx "
+                             "prot=%#x\n", page_end, zeroed_size, prot);
+            ML_(notify_core_and_tool_of_mmap)(page_end, zeroed_size,
+                                              prot, flags, -1, 0);
+         }
+
+         VG_(di_notify_mmap)((Addr) mrp->mr_addr, False /*allow_SkFileV*/, fd);
+
+         *elements += 1;
+         vg_assert(*elements <= segments);
+      }
+   }
+
+   /* Restore VG_(clo_sanity_level). The scheduler will perform the aspacemgr
+      sanity check after the syscall. */
+   VG_(clo_sanity_level) = sanity_level;
+
+   return VG_(mk_SysRes_Success)(0);
+
+mmap_error:
+   for (i = idx - 1; i > 0; i--) {
+      Bool discard_translations;
+      Addr addr = (Addr) storage[i].mr_addr;
+
+      VG_(am_munmap_client)(&discard_translations, addr, storage[i].mr_msize);
+      ML_(notify_core_and_tool_of_munmap)(addr, storage[i].mr_msize);
+   }
+   *elements = 0;
+   return res;
+
+#undef ADVANCE_PHDR
+}
+
+static SysRes mmapobj_interpret(ThreadId tid, Int fd,
+                                vki_mmapobj_result_t *storage,
+                                vki_uint_t *elements)
+{
+   SysRes res;
+
+   struct vg_stat stats;
+   if (VG_(fstat)(fd, &stats) != 0) {
+      return VG_(mk_SysRes_Error)(VKI_EBADF);
+   }
+
+   if (stats.size < sizeof(VKI_ESZ(Ehdr))) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: insufficient "
+                          "file size (%lld)\n", stats.size);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   /* Align the header buffer appropriately. */
+   vki_ulong_t lheader[sizeof(VKI_ESZ(Ehdr)) / sizeof(vki_ulong_t) + 1];
+   HChar *header = (HChar *) &lheader;
+
+   res = VG_(pread)(fd, header, sizeof(VKI_ESZ(Ehdr)), 0);
+   if (sr_isError(res)) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: read of ELF "
+                          "header failed\n");
+      return res;
+   } else if (sr_Res(res) != sizeof(VKI_ESZ(Ehdr))) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: read of ELF "
+                          "header failed - only %lu bytes out of %lu\n",
+                          sr_Res(res), (UWord) sizeof(VKI_ESZ(Ehdr)));
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   /* Verify file type is ELF. */
+   if ((header[VKI_EI_MAG0] != VKI_ELFMAG0) ||
+       (header[VKI_EI_MAG1] != VKI_ELFMAG1) ||
+       (header[VKI_EI_MAG2] != VKI_ELFMAG2) ||
+       (header[VKI_EI_MAG3] != VKI_ELFMAG3)) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: ELF header "
+                          "missing magic\n");
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   if (header[VKI_EI_CLASS] != VG_ELF_CLASS) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: ELF class "
+                          "mismatch (%u vs %u)\n", header[VKI_EI_CLASS],
+                          VG_ELF_CLASS);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   VKI_ESZ(Ehdr) *ehdr = (VKI_ESZ(Ehdr) *) header;
+   if (ehdr->e_type != VKI_ET_DYN) {
+      VG_(unimplemented)("Syswrap of the mmapobj call with ELF type %u.",
+                         ehdr->e_type);
+      /*NOTREACHED*/
+      return res;
+   }
+
+   if (ehdr->e_phnum == VKI_PN_XNUM) {
+      VG_(unimplemented)("Syswrap of the mmapobj call with number of ELF "
+                         "program headers == PN_XNUM");
+      /*NOTREACHED*/
+      return res;
+   }
+
+   /* Check alignment. */
+#if defined(VGP_x86_solaris)
+   if (!VG_IS_4_ALIGNED(ehdr->e_phentsize)) {
+#elif defined(VGP_amd64_solaris)
+   if (!VG_IS_8_ALIGNED(ehdr->e_phentsize)) {
+#else
+#  error "Unknown platform"
+#endif
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: ELF header "
+                          "phentsize not aligned properly (%u)\n",
+                          ehdr->e_phentsize);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   SizeT phdrs_size = ehdr->e_phnum * ehdr->e_phentsize;
+   if (phdrs_size == 0) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: no ELF "
+                          "program headers\n");
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   VKI_ESZ(Phdr) *phdrs = VG_(malloc)("syswrap.mi.1", phdrs_size);
+   res = VG_(pread)(fd, phdrs, phdrs_size, ehdr->e_phoff);
+   if (sr_isError(res)) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: read of ELF "
+                          "program headers failed\n");
+      VG_(free)(phdrs);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   } else if (sr_Res(res) != phdrs_size) {
+      if (VG_(clo_trace_syscalls))
+         VG_(debugLog)(3, "syswrap-solaris", "mmapobj_interpret: read of ELF "
+                          "program headers failed - only %lu bytes out of %lu\n",
+                          sr_Res(res), phdrs_size);
+      VG_(free)(phdrs);
+      return VG_(mk_SysRes_Error)(VKI_ENOTSUP);
+   }
+
+   if (VG_(clo_trace_syscalls))
+      VG_(debugLog)(2, "syswrap-solaris", "mmapobj_interpret: %u ELF "
+                       "program headers with total size of %lu bytes\n",
+                       ehdr->e_phnum, phdrs_size);
+
+   /* Now process the program headers. */
+   res = mmapobj_process_phdrs(tid, fd, storage, elements, ehdr, phdrs);
+   VG_(free)(phdrs);
+   return res;
+}
+
+PRE(sys_mmapobj)
+{
+   /* int mmapobj(int fd, uint_t flags, mmapobj_result_t *storage,
+                  uint_t *elements, void *arg); */
+   PRINT("sys_mmapobj ( %ld, %#lx, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3,
+         ARG4, ARG5);
+   PRE_REG_READ5(long, "mmapobj", int, fd, vki_uint_t, flags,
+                 mmapobj_result_t *, storage, uint_t *, elements,
+                 void *, arg);
+
+   PRE_MEM_READ("mmapobj(elements)", ARG4, sizeof(vki_uint_t));
+   /*PRE_MEM_WRITE("mmapobj(elements)", ARG4, sizeof(vki_uint_t));*/
+   if (ML_(safe_to_deref)((void*)ARG4, sizeof(vki_uint_t))) {
+      vki_uint_t *u = (vki_uint_t*)ARG4;
+      PRE_MEM_WRITE("mmapobj(storage)", ARG3,
+                    *u * sizeof(vki_mmapobj_result_t));
+   }
+
+   if (ARG2 & VKI_MMOBJ_PADDING)
+      PRE_MEM_READ("mmapobj(arg)", ARG5, sizeof(vki_size_t));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "mmapobj", tid, False)) {
+      SET_STATUS_Failure(VKI_EBADF);
+      return;
+   }
+
+   /* We cannot advise mmapobj about desired address(es). Unfortunately
+      kernel places mappings from mmapobj at the end of process address
+      space, defeating memcheck's optimized fast 2-level array algorithm.
+      So we need to emulate what mmapobj does in the kernel. */
+
+   /* Sanity check on parameters. */
+   if ((ARG2 & ~VKI_MMOBJ_ALL_FLAGS) != 0) {
+      SET_STATUS_Failure(VKI_EINVAL);
+      return;
+   }
+
+   if (!ML_(safe_to_deref)((void *) ARG4, sizeof(vki_uint_t))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+   vki_uint_t *elements = (vki_uint_t *) ARG4;
+
+   if (*elements > 0) {
+      if (!ML_(safe_to_deref)((void *) ARG3,
+                              *elements * sizeof(vki_mmapobj_result_t))) {
+         SET_STATUS_Failure(VKI_EFAULT);
+         return;
+      }
+   }
+
+   /* For now, supported is only MMOBJ_INTERPRET and no MMOBJ_PADDING. */
+   if (ARG2 != VKI_MMOBJ_INTERPRET) {
+      VG_(unimplemented)("Syswrap of the mmapobj call with flags %ld.", ARG2);
+      /*NOTREACHED*/
+      return;
+   }
+
+   SysRes res = mmapobj_interpret(tid, (Int) ARG1,
+                                  (vki_mmapobj_result_t *) ARG3, elements);
+   SET_STATUS_from_SysRes(res);
+
+   if (!sr_isError(res)) {
+      POST_MEM_WRITE(ARG4, sizeof(vki_uint_t));
+
+      UInt idx;
+      for (idx = 0; idx < *(vki_uint_t *) ARG4; idx++) {
+         vki_mmapobj_result_t *mrp = &((vki_mmapobj_result_t *) ARG3)[idx];
+         POST_FIELD_WRITE(mrp->mr_addr);
+         POST_FIELD_WRITE(mrp->mr_msize);
+         POST_FIELD_WRITE(mrp->mr_fsize);
+         POST_FIELD_WRITE(mrp->mr_prot);
+         POST_FIELD_WRITE(mrp->mr_flags);
+         POST_FIELD_WRITE(mrp->mr_offset);
+      }
+   }
+}
+
+PRE(sys_memcntl)
+{
+   /* int memcntl(caddr_t addr, size_t len, int cmd, caddr_t arg,
+                  int attr, int mask); */
+   PRINT("sys_memcntl ( %#lx, %#lx, %ld, %#lx, %#lx, %#lx )", ARG1, ARG2,
+         ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "memcntl", void *, addr, vki_size_t, len, int, cmd,
+                 void *, arg, int, attr, int, mask);
+
+   if (ARG3 != VKI_MC_LOCKAS && ARG3 != VKI_MC_UNLOCKAS &&
+       !ML_(valid_client_addr)(ARG1, ARG2, tid, "memcntl")) {
+      /* MC_LOCKAS and MC_UNLOCKAS work on the complete address space thus we
+         don't check the address range validity if these commands are
+         requested. */
+      SET_STATUS_Failure(VKI_ENOMEM);
+      return;
+   }
+
+   if (ARG3 == VKI_MC_HAT_ADVISE)
+      PRE_MEM_READ("memcntl(arg)", ARG4, sizeof(struct vki_memcntl_mha));
+}
+
+PRE(sys_getpmsg)
+{
+   /* int getpmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr,
+                  int *bandp, int *flagsp); */
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+   *flags |= SfMayBlock;
+   PRINT("sys_getpmsg ( %ld, %#lx, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3,
+         ARG4, ARG5);
+   PRE_REG_READ5(long, "getpmsg", int, fildes, struct vki_strbuf *, ctlptr,
+                 struct vki_strbuf *, dataptr, int *, bandp, int *, flagsp);
+   if (ctrlptr) {
+      PRE_FIELD_READ("getpmsg(ctrlptr->maxlen)", ctrlptr->maxlen);
+      PRE_FIELD_WRITE("getpmsg(ctrlptr->len)", ctrlptr->len);
+      PRE_FIELD_READ("getpmsg(ctrlptr->buf)", ctrlptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG2, sizeof(struct vki_strbuf))
+          && ctrlptr->maxlen > 0)
+         PRE_MEM_WRITE("getpmsg(ctrlptr->buf)", (Addr)ctrlptr->buf,
+                       ctrlptr->maxlen);
+   }
+   if (dataptr) {
+      PRE_FIELD_READ("getpmsg(dataptr->maxlen)", dataptr->maxlen);
+      PRE_FIELD_WRITE("getpmsg(dataptr->len)", dataptr->len);
+      PRE_FIELD_READ("getpmsg(dataptr->buf)", dataptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG3, sizeof(struct vki_strbuf))
+          && dataptr->maxlen > 0)
+         PRE_MEM_WRITE("getpmsg(dataptr->buf)", (Addr)dataptr->buf,
+                       dataptr->maxlen);
+   }
+   PRE_MEM_READ("getpmsg(bandp)", ARG4, sizeof(int));
+   /*PRE_MEM_WRITE("getpmsg(bandp)", ARG4, sizeof(int));*/
+   PRE_MEM_READ("getpmsg(flagsp)", ARG5, sizeof(int));
+   /*PRE_MEM_WRITE("getpmsg(flagsp)", ARG5, sizeof(int));*/
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "getpmsg", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_getpmsg)
+{
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+
+   if (ctrlptr && ctrlptr->len > 0)
+      POST_MEM_WRITE((Addr)ctrlptr->buf, ctrlptr->len);
+   if (dataptr && dataptr->len > 0)
+      POST_MEM_WRITE((Addr)dataptr->buf, dataptr->len);
+   POST_MEM_WRITE(ARG4, sizeof(int));
+   POST_MEM_WRITE(ARG5, sizeof(int));
+}
+
+PRE(sys_putpmsg)
+{
+   /* int putpmsg(int fildes, const struct strbuf *ctlptr,
+                  const struct strbuf *dataptr, int band, int flags); */
+   struct vki_strbuf *ctrlptr = (struct vki_strbuf *)ARG2;
+   struct vki_strbuf *dataptr = (struct vki_strbuf *)ARG3;
+   *flags |= SfMayBlock;
+   PRINT("sys_putpmsg ( %ld, %#lx, %#lx, %ld, %ld )", ARG1, ARG2, ARG3, ARG4,
+         ARG5);
+   PRE_REG_READ5(long, "putpmsg", int, fildes, struct vki_strbuf *, ctrlptr,
+                 struct vki_strbuf *, dataptr, int, band, int, flags);
+   if (ctrlptr) {
+      PRE_FIELD_READ("putpmsg(ctrlptr->len)", ctrlptr->len);
+      PRE_FIELD_READ("putpmsg(ctrlptr->buf)", ctrlptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG2, sizeof(struct vki_strbuf))
+          && ctrlptr->len > 0)
+         PRE_MEM_READ("putpmsg(ctrlptr->buf)", (Addr)ctrlptr->buf,
+                      ctrlptr->len);
+   }
+   if (dataptr) {
+      PRE_FIELD_READ("putpmsg(dataptr->len)", dataptr->len);
+      PRE_FIELD_READ("putpmsg(dataptr->buf)", dataptr->buf);
+      if (ML_(safe_to_deref)((void*)ARG3, sizeof(struct vki_strbuf))
+          && dataptr->len > 0)
+         PRE_MEM_READ("putpmsg(dataptr->buf)", (Addr)dataptr->buf,
+                      dataptr->len);
+   }
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "putpmsg", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+#if defined(SOLARIS_OLD_SYSCALLS)
+PRE(sys_rename)
+{
+   /* int rename(const char *from, const char *to); */
+
+   *flags |= SfMayBlock;
+   PRINT("sys_rename ( %#lx(%s), %#lx(%s) )",
+         ARG1, (HChar *) ARG1, ARG2, (char *) ARG2);
+   PRE_REG_READ2(long, "rename", const char *, from, const char *, to);
+
+   PRE_MEM_RASCIIZ("rename(from)", ARG1);
+   PRE_MEM_RASCIIZ("rename(to)", ARG2);
+}
+#endif /* SOLARIS_OLD_SYSCALLS */
+
+PRE(sys_uname)
+{
+   /* int uname(struct utsname *name); */
+   PRINT("sys_uname ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "uname", struct vki_utsname *, name);
+   PRE_MEM_WRITE("uname(name)", ARG1, sizeof(struct vki_utsname));
+}
+
+POST(sys_uname)
+{
+   struct vki_utsname *name = (struct vki_utsname *) ARG1;
+   POST_MEM_WRITE((Addr) name->sysname, VG_(strlen)(name->sysname) + 1);
+   POST_MEM_WRITE((Addr) name->nodename, VG_(strlen)(name->nodename) + 1);
+   POST_MEM_WRITE((Addr) name->release, VG_(strlen)(name->release) + 1);
+   POST_MEM_WRITE((Addr) name->version, VG_(strlen)(name->version) + 1);
+   POST_MEM_WRITE((Addr) name->machine, VG_(strlen)(name->machine) + 1);
+}
+
+PRE(sys_setegid)
+{
+   /* int setegid(gid_t egid); */
+   PRINT("sys_setegid ( %ld )", ARG1);
+   PRE_REG_READ1(long, "setegid", vki_gid_t, egid);
+}
+
+PRE(sys_sysconfig)
+{
+   /* long sysconf(int name); */
+   PRINT("sys_sysconfig ( %ld )", ARG1);
+   PRE_REG_READ1(long, "sysconf", int, name);
+
+   if (ARG1 == VKI_CONFIG_OPEN_FILES)
+      SET_STATUS_Success(VG_(fd_soft_limit));
+}
+
+PRE(sys_systeminfo)
+{
+   /* int sysinfo(int command, char *buf, long count); */
+   PRINT("sys_systeminfo ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sysinfo", int, command, char *, buf, long, count);
+
+   switch (ARG1 /*command*/) {
+   case VKI_SI_SYSNAME:
+   case VKI_SI_HOSTNAME:
+   case VKI_SI_RELEASE:
+   case VKI_SI_VERSION:
+   case VKI_SI_MACHINE:
+   case VKI_SI_ARCHITECTURE:
+   case VKI_SI_HW_SERIAL:
+   case VKI_SI_HW_PROVIDER:
+   case VKI_SI_SRPC_DOMAIN:
+   case VKI_SI_PLATFORM:
+   case VKI_SI_ISALIST:
+   case VKI_SI_DHCP_CACHE:
+   case VKI_SI_ARCHITECTURE_32:
+   case VKI_SI_ARCHITECTURE_64:
+   case VKI_SI_ARCHITECTURE_K:
+   case VKI_SI_ARCHITECTURE_NATIVE:
+      PRE_MEM_WRITE("sysinfo(buf)", ARG2, ARG3);
+      break;
+
+   case VKI_SI_SET_HOSTNAME:
+   case VKI_SI_SET_SRCP_DOMAIN:
+      PRE_MEM_RASCIIZ("sysinfo(buf)", ARG2);
+      break;
+
+   default:
+      VG_(unimplemented)("Syswrap of the sysinfo call with command %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_systeminfo)
+{
+   if (ARG1 != VKI_SI_SET_HOSTNAME && ARG1 != VKI_SI_SET_SRCP_DOMAIN)
+      POST_MEM_WRITE(ARG2, MIN(RES, ARG3));
+}
+
+PRE(sys_seteuid)
+{
+   /* int seteuid(uid_t euid); */
+   PRINT("sys_seteuid ( %ld )", ARG1);
+   PRE_REG_READ1(long, "seteuid", vki_uid_t, euid);
+}
+
+PRE(sys_forksys)
+{
+   /* int64_t forksys(int subcode, int flags); */
+   Int fds[2];
+   Int res;
+   PRINT("sys_forksys ( %ld, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "forksys", int, subcode, int, flags);
+
+   if (ARG1 == 1) {
+      /* Support for forkall() requires changes to the big lock processing
+         which are not yet implemented. */
+      VG_(unimplemented)("Support for forkall().");
+      /*NOTREACHED*/
+      return;
+   }
+
+   if (ARG1 != 0 && ARG1 != 2) {
+      VG_(unimplemented)("Syswrap of the forksys call where subcode=%ld.",
+                         ARG1);
+      /*NOTREACHED*/
+   }
+
+   if (ARG1 == 2) {
+      /* vfork() is requested. Translate it to a normal fork() but work around
+         a problem with posix_spawn() which relies on the real vfork()
+         behaviour. See a description in vg_preloaded.c for details. */
+      res = VG_(pipe)(fds);
+      vg_assert(res == 0);
+
+      vg_assert(fds[0] != fds[1]);
+
+      /* Move to Valgrind fds and set close-on-exec flag on both of them (done
+         by VG_(safe_fd). */
+      fds[0] = VG_(safe_fd)(fds[0]);
+      fds[1] = VG_(safe_fd)(fds[1]);
+      vg_assert(fds[0] != fds[1]);
+
+      vg_assert(VG_(vfork_fildes_addr) != NULL);
+      vg_assert(*VG_(vfork_fildes_addr) == -1);
+      *VG_(vfork_fildes_addr) = fds[0];
+   }
+
+   VG_(do_atfork_pre)(tid);
+   SET_STATUS_from_SysRes(VG_(do_syscall2)(__NR_forksys, 0, ARG2));
+
+   if (!SUCCESS) {
+      /* vfork */
+      if (ARG1 == 2) {
+         VG_(close)(fds[0]);
+         VG_(close)(fds[1]);
+      }
+
+      return;
+   }
+
+   if (RESHI) {
+      VG_(do_atfork_child)(tid);
+
+      /* If --child-silent-after-fork=yes was specified, set the output file
+         descriptors to 'impossible' values.  This is noticed by
+         send_bytes_to_logging_sink() in m_libcprint.c, which duly stops
+         writing any further output. */
+      if (VG_(clo_child_silent_after_fork)) {
+         if (!VG_(log_output_sink).is_socket)
+            VG_(log_output_sink).fd = -1;
+         if (!VG_(xml_output_sink).is_socket)
+            VG_(xml_output_sink).fd = -1;
+      }
+
+      /* vfork */
+      if (ARG1 == 2)
+         VG_(close)(fds[1]);
+   }
+   else {
+      VG_(do_atfork_parent)(tid);
+
+      /* Print information about the fork. */
+      PRINT("   fork: process %d created child %d\n", VG_(getpid)(),
+            (Int)RES);
+
+      /* vfork */
+      if (ARG1 == 2) {
+         /* Wait for the child to finish (exec or exit). */
+         UChar w;
+
+         VG_(close)(fds[0]);
+
+         res = VG_(read)(fds[1], &w, 1);
+         if (res == 1)
+            SET_STATUS_Failure(w);
+         VG_(close)(fds[1]);
+
+         *VG_(vfork_fildes_addr) = -1;
+      }
+   }
+}
+
+PRE(sys_sigtimedwait)
+{
+   /* int sigtimedwait(const sigset_t *set, siginfo_t *info,
+                       const timespec_t *timeout); */
+   *flags |= SfMayBlock;
+   PRINT("sys_sigtimedwait ( %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sigtimedwait", vki_sigset_t *, set,
+                 vki_siginfo_t *, info, vki_timespec_t *, timeout);
+   PRE_MEM_READ("sigtimewait(set)", ARG1, sizeof(vki_sigset_t));
+   if (ARG2)
+      PRE_MEM_WRITE("sigtimedwait(info)", ARG2, sizeof(vki_siginfo_t));
+   if (ARG3)
+      PRE_MEM_READ("sigtimedwait(timeout)", ARG3, sizeof(vki_timespec_t));
+}
+
+POST(sys_sigtimedwait)
+{
+   if (ARG2)
+      POST_MEM_WRITE(ARG2, sizeof(vki_siginfo_t));
+}
+
+PRE(sys_yield)
+{
+   /* void yield(void); */
+   *flags |= SfMayBlock;
+   PRINT("sys_yield ( )");
+   PRE_REG_READ0(long, "yield");
+}
+
+PRE(sys_lwp_sema_post)
+{
+   /* int lwp_sema_post(lwp_sema_t *sema); */
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   *flags |= SfMayBlock;
+   PRINT("sys_lwp_sema_post ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "lwp_sema_post", lwp_sema_t *, sema);
+
+   PRE_FIELD_READ("lwp_sema_post(sema->type)", sema->vki_sema_type);
+   PRE_FIELD_READ("lwp_sema_post(sema->count)", sema->vki_sema_count);
+   /*PRE_FIELD_WRITE("lwp_sema_post(sema->count)", sema->vki_sema_count);*/
+   PRE_FIELD_READ("lwp_sema_post(sema->waiters)", sema->vki_sema_waiters);
+   /*PRE_FIELD_WRITE("lwp_sema_post(sema->waiters)", sema->vki_sema_waiters);*/
+}
+
+POST(sys_lwp_sema_post)
+{
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   POST_FIELD_WRITE(sema->vki_sema_count);
+   POST_FIELD_WRITE(sema->vki_sema_waiters);
+}
+
+PRE(sys_lwp_sema_trywait)
+{
+   /* int lwp_sema_trywait(lwp_sema_t *sema); */
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   PRINT("sys_lwp_sema_trywait ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "lwp_sema_trywait", lwp_sema_t *, sema);
+
+   PRE_FIELD_READ("lwp_sema_trywait(sema->type)", sema->vki_sema_type);
+   PRE_FIELD_READ("lwp_sema_trywait(sema->count)", sema->vki_sema_count);
+   /*PRE_FIELD_WRITE("lwp_sema_trywait(sema->count)", sema->vki_sema_count);*/
+   PRE_FIELD_READ("lwp_sema_trywait(sema->waiters)", sema->vki_sema_waiters);
+   /*PRE_FIELD_WRITE("lwp_sema_trywait(sema->waiters)",
+     sema->vki_sema_waiters);*/
+}
+
+POST(sys_lwp_sema_trywait)
+{
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   POST_FIELD_WRITE(sema->vki_sema_count);
+   POST_FIELD_WRITE(sema->vki_sema_waiters);
+}
+
+PRE(sys_lwp_detach)
+{
+   /* int lwp_detach(id_t lwpid); */
+   PRINT("sys_lwp_detach ( %ld )", ARG1);
+   PRE_REG_READ1(long, "lwp_detach", vki_id_t, lwpid);
+}
+
+PRE(sys_fchroot)
+{
+   /* int fchroot(int fd); */
+   PRINT("sys_fchroot ( %ld )", ARG1);
+   PRE_REG_READ1(long, "fchroot", int, fd);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fchroot", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_gettimeofday)
+{
+   /* Kernel: int gettimeofday(struct timeval *tp); */
+   PRINT("sys_gettimeofday ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "gettimeofday", struct timeval *, tp);
+   if (ARG1)
+      PRE_timeval_WRITE("gettimeofday(tp)", ARG1);
+}
+
+POST(sys_gettimeofday)
+{
+   if (ARG1)
+      POST_timeval_WRITE(ARG1);
+}
+
+PRE(sys_lwp_create)
+{
+   /* int lwp_create(ucontext_t *ucp, int flags, id_t *new_lwp) */
+
+   ThreadId ctid;
+   ThreadState *ptst;
+   ThreadState *ctst;
+   Addr stack;
+   SysRes res;
+   vki_ucontext_t uc;
+   Bool tool_informed = False;
+
+   PRINT("sys_lwp_create ( %#lx, %ld, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "lwp_create", ucontext_t *, ucp, int, flags,
+                 id_t *, new_lwp);
+
+   if (ARG3 != 0)
+      PRE_MEM_WRITE("lwp_create(new_lwp)", ARG3, sizeof(vki_id_t));
+
+   /* If we can't deref ucontext_t then we can't do anything. */
+   if (!ML_(safe_to_deref)((void*)ARG1, sizeof(vki_ucontext_t))) {
+      SET_STATUS_Failure(VKI_EINVAL);
+      return;
+   }
+
+   ctid = VG_(alloc_ThreadState)();
+   ptst = VG_(get_ThreadState)(tid);
+   ctst = VG_(get_ThreadState)(ctid);
+
+   /* Stay sane. */
+   vg_assert(VG_(is_running_thread)(tid));
+   vg_assert(VG_(is_valid_tid)(ctid));
+
+   stack = ML_(allocstack)(ctid);
+   if (!stack) {
+      res = VG_(mk_SysRes_Error)(VKI_ENOMEM);
+      goto out;
+   }
+
+   /* First inherit parent's guest state */
+   ctst->arch.vex = ptst->arch.vex;
+   ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1;
+   ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2;
+
+   /* Set up some values. */
+   ctst->os_state.parent = tid;
+   ctst->os_state.threadgroup = ptst->os_state.threadgroup;
+   ctst->sig_mask = ptst->sig_mask;
+   ctst->tmp_sig_mask = ptst->sig_mask;
+
+   /* No stack definition should be currently present.  The stack will be set
+      later by libc by a setustack() call (the getsetcontext syscall). */
+   ctst->client_stack_highest_byte = 0;
+   ctst->client_stack_szB = 0;
+   vg_assert(ctst->os_state.stk_id == (UWord)(-1));
+
+   /* Inform a tool that a new thread is created.  This has to be done before
+      any other core->tool event is sent. */
+   vg_assert(VG_(owns_BigLock_LL)(tid));
+   VG_TRACK(pre_thread_ll_create, tid, ctid);
+   tool_informed = True;
+
+#if defined(VGP_x86_solaris)
+   /* Set up GDT (this has to be done before calling
+      VG_(restore_context)(). */
+   ML_(setup_gdt)(&ctst->arch.vex);
+#elif defined(VGP_amd64_solaris)
+   /* Nothing to do. */
+#else
+#  error "Unknown platform"
+#endif
+
+   /* Now set up the new thread according to ucontext_t. */
+   VG_(restore_context)(ctid, (vki_ucontext_t*)ARG1, Vg_CoreSysCall,
+                        True/*esp_is_thrptr*/);
+
+   /* Set up V thread (this also tells the kernel to block all signals in the
+      thread). */
+   ML_(setup_start_thread_context)(ctid, &uc);
+
+   /* Actually create the new thread. */
+   res = VG_(do_syscall3)(__NR_lwp_create, (UWord)&uc, ARG2, ARG3);
+
+   if (!sr_isError(res)) {
+      if (ARG3 != 0)
+         POST_MEM_WRITE(ARG3, sizeof(vki_id_t));
+      if (ARG2 & VKI_LWP_DAEMON)
+         ctst->os_state.daemon_thread = True;
+   }
+
+out:
+   if (sr_isError(res)) {
+      if (tool_informed) {
+         /* Tell a tool the thread exited in a hurry. */
+         VG_TRACK(pre_thread_ll_exit, ctid);
+      }
+
+      /* lwp_create failed. */
+      VG_(cleanup_thread)(&ctst->arch);
+      ctst->status = VgTs_Empty;
+   }
+
+   SET_STATUS_from_SysRes(res);
+}
+
+PRE(sys_lwp_exit)
+{
+   /* void syslwp_exit(); */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   PRINT("sys_lwp_exit ( )");
+   PRE_REG_READ0(long, "lwp_exit");
+
+   /* Set the thread's status to be exiting, then claim that the syscall
+      succeeded. */
+   tst->exitreason = VgSrc_ExitThread;
+   tst->os_state.exitcode = 0;
+   SET_STATUS_Success(0);
+}
+
+PRE(sys_lwp_suspend)
+{
+   /* int lwp_suspend(id_t lwpid); */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   PRINT("sys_lwp_suspend ( %ld )", ARG1);
+   PRE_REG_READ1(long, "lwp_suspend", vki_id_t, lwpid);
+
+   if (ARG1 == tst->os_state.lwpid) {
+      /* Set the SfMayBlock flag only if the currently running thread should
+         be suspended. If this flag was used also when suspending other
+         threads then it could happen that a thread holding the_BigLock would
+         be suspended and Valgrind would hang. */
+      *flags |= SfMayBlock;
+   }
+}
+
+PRE(sys_lwp_continue)
+{
+   /* int lwp_continue(id_t target_lwp); */
+   PRINT("sys_lwp_continue ( %ld )", ARG1);
+   PRE_REG_READ1(long, "lwp_continue", vki_id_t, target_lwp);
+}
+
+static void
+do_lwp_sigqueue(const HChar *syscall_name, UWord target_lwp, UWord signo,
+                SyscallStatus *status, UWord *flags)
+{
+   if (!ML_(client_signal_OK)(signo)) {
+      SET_STATUS_Failure(VKI_EINVAL);
+      return;
+   }
+
+   /* Check to see if this gave us a pending signal. */
+   *flags |= SfPollAfter;
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "%s: sending signal %ld to thread %ld\n",
+                   syscall_name, signo, target_lwp);
+
+   /* If we're sending SIGKILL, check to see if the target is one of our
+      threads and handle it specially. */
+   if (signo == VKI_SIGKILL && ML_(do_sigkill)(target_lwp, -1)) {
+      SET_STATUS_Success(0);
+      return;
+   }
+
+   /* Ask to handle this syscall via the slow route, since that's the only one
+      that sets tst->status to VgTs_WaitSys.  If the result of doing the
+      syscall is an immediate run of async_signalhandler() in m_signals.c,
+      then we need the thread to be properly tidied away. */
+   *flags |= SfMayBlock;
+}
+
+#if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL)
+#if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID)
+PRE(sys_lwp_sigqueue)
+{
+   /* int lwp_sigqueue(pid_t target_pid, id_t target_lwp, int signal,
+                       void *value, int si_code, timespec_t *timeout);
+    */
+   PRINT("sys_lwp_sigqueue ( %ld, %ld, %ld, %#lx, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "lwp_sigqueue", vki_pid_t, target_pid,
+                 vki_id_t, target_lwp, int, signal, void *, value, int, si_code,
+                 vki_timespec_t *, timeout);
+
+   if (ARG6)
+      PRE_MEM_READ("lwp_sigqueue(timeout)", ARG6, sizeof(vki_timespec_t));
+
+   if ((ARG1 == 0) || (ARG1 == VG_(getpid)())) {
+      do_lwp_sigqueue("lwp_sigqueue", ARG2, ARG3, status, flags);
+   } else {
+      /* Signal is sent to a different process. */
+      if (VG_(clo_trace_signals))
+         VG_(message)(Vg_DebugMsg, "lwp_sigqueue: sending signal %ld to "
+                      "process %ld, thread %ld\n", ARG3, ARG1, ARG2);
+     *flags |= SfMayBlock;
+   }
+}
+
+POST(sys_lwp_sigqueue)
+{
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "lwp_sigqueue: sent signal %ld to process %ld, "
+                   "thread %ld\n", ARG3, ARG1, ARG2);
+}
+
+#else
+
+PRE(sys_lwp_sigqueue)
+{
+   /* int lwp_sigqueue(id_t target_lwp, int signal, void *value,
+                       int si_code, timespec_t *timeout);
+    */
+   PRINT("sys_lwp_sigqueue ( %ld, %ld, %#lx, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "lwp_sigqueue", vki_id_t, target_lwp, int, signal,
+                 void *, value, int, si_code, vki_timespec_t *, timeout);
+
+   if (ARG5)
+      PRE_MEM_READ("lwp_sigqueue(timeout)", ARG5, sizeof(vki_timespec_t));
+
+   do_lwp_sigqueue("lwp_sigqueue", ARG1, ARG2, status, flags);
+}
+
+POST(sys_lwp_sigqueue)
+{
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "lwp_sigqueue: sent signal %ld to thread %ld\n",
+                   ARG2, ARG1);
+}
+
+
+#endif /* SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID */
+
+#else
+
+PRE(sys_lwp_kill)
+{
+   /* int lwp_kill(id_t target_lwp, int signal); */
+   PRINT("sys_lwp_kill ( %ld, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "lwp_kill", vki_id_t, target_lwp, int, signal);
+
+   do_lwp_sigqueue("lwp_kill", ARG1, ARG2, status, flags);
+}
+
+POST(sys_lwp_kill)
+{
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "lwp_kill: sent signal %ld to thread %ld\n",
+                   ARG2, ARG1);
+}
+#endif /* SOLARIS_LWP_SIGQUEUE_SYSCALL */
+
+PRE(sys_lwp_self)
+{
+   /* id_t lwp_self(void); */
+   PRINT("sys_lwp_self ( )");
+   PRE_REG_READ0(long, "lwp_self");
+}
+
+PRE(sys_lwp_sigmask)
+{
+   /* int64_t lwp_sigmask(int how, uint_t bits0, uint_t bits1, uint_t bits2,
+                          uint_t bits3); */
+   vki_sigset_t sigset;
+   PRINT("sys_lwp_sigmask ( %ld, %#lx, %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3,
+         ARG4, ARG5);
+   PRE_REG_READ5(long, "lwp_sigmask", int, how, vki_uint_t, bits0,
+                 vki_uint_t, bits1, vki_uint_t, bits2, vki_uint_t, bits3);
+
+   sigset.__sigbits[0] = ARG2;
+   sigset.__sigbits[1] = ARG3;
+   sigset.__sigbits[2] = ARG4;
+   sigset.__sigbits[3] = ARG5;
+
+   SET_STATUS_from_SysRes(
+      VG_(do_sys_sigprocmask)(tid, ARG1 /*how*/, &sigset, NULL)
+   );
+
+   if (SUCCESS)
+      *flags |= SfPollAfter;
+}
+
+PRE(sys_lwp_private)
+{
+   /* int lwp_private(int cmd, int which, uintptr_t base); */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Int supported_base, supported_sel;
+   PRINT("sys_lwp_private ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "lwp_private", int, cmd, int, which,
+                 uintptr_t, base);
+
+   /* Note: Only the %gs base is currently supported on x86 and the %fs base
+      on amd64.  Support for the %fs base on x86 and for the %gs base on amd64
+      should be added.  Anything else is probably a client program error. */
+#if defined(VGP_x86_solaris)
+   supported_base = VKI_LWP_GSBASE;
+   supported_sel = VKI_LWPGS_SEL;
+#elif defined(VGP_amd64_solaris)
+   supported_base = VKI_LWP_FSBASE;
+   supported_sel = 0;
+#else
+#error "Unknown platform"
+#endif
+   if (ARG2 != supported_base) {
+      VG_(unimplemented)("Syswrap of the lwp_private call where which=%ld.",
+                         ARG2);
+      /*NOTREACHED*/
+   }
+
+   switch (ARG1 /*cmd*/) {
+   case VKI_LWP_SETPRIVATE:
+#if defined(VGP_x86_solaris)
+      tst->os_state.thrptr = ARG3;
+      ML_(update_gdt_lwpgs)(tid);
+#elif defined(VGP_amd64_solaris)
+      tst->arch.vex.guest_FS_CONST = ARG3;
+#else
+#error "Unknown platform"
+#endif
+      SET_STATUS_Success(supported_sel);
+      break;
+   case VKI_LWP_GETPRIVATE:
+      {
+         int thrptr;
+#if defined(VGP_x86_solaris)
+         thrptr = tst->os_state.thrptr;
+#elif defined(VGP_amd64_solaris)
+         thrptr = tst->arch.vex.guest_FS_CONST;
+#else
+#error "Unknown platform"
+#endif
+
+         if (thrptr == 0) {
+            SET_STATUS_Failure(VKI_EINVAL);
+            return;
+         }
+
+#if defined(VGP_x86_solaris)
+         if (tst->arch.vex.guest_GS != supported_sel) {
+            SET_STATUS_Failure(VKI_EINVAL);
+            return;
+         }
+#elif defined(VGP_amd64_solaris)
+         /* Valgrind on amd64 does not allow to change the gs register so
+            a check that guest_GS is equal to supported_sel is not needed
+            here. */
+#else
+#error "Unknown platform"
+#endif
+
+         PRE_MEM_WRITE("lwp_private(base)", ARG3, sizeof(Addr));
+         if (!ML_(safe_to_deref((void*)ARG3, sizeof(Addr)))) {
+            SET_STATUS_Failure(VKI_EFAULT);
+            return;
+         }
+         *(Addr*)ARG3 = thrptr;
+         POST_MEM_WRITE((Addr)ARG3, sizeof(Addr));
+         SET_STATUS_Success(0);
+         break;
+      }
+   default:
+      VG_(unimplemented)("Syswrap of the lwp_private call where cmd=%ld.",
+                         ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+PRE(sys_lwp_wait)
+{
+   /* int lwp_wait(id_t lwpid, id_t *departed); */
+   *flags |= SfMayBlock;
+   PRINT("sys_lwp_wait ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "lwp_wait", vki_id_t, lwpid, id_t *, departed);
+   if (ARG2)
+      PRE_MEM_WRITE("lwp_wait(departed)", ARG2, sizeof(vki_id_t));
+}
+
+POST(sys_lwp_wait)
+{
+   POST_MEM_WRITE(ARG2, sizeof(vki_id_t));
+}
+
+PRE(sys_lwp_mutex_wakeup)
+{
+   /* int lwp_mutex_wakeup(lwp_mutex_t *lp, int release_all); */
+   vki_lwp_mutex_t *lp = (vki_lwp_mutex_t*)ARG1;
+   *flags |= SfMayBlock;
+   PRINT("sys_lwp_mutex_wakeup ( %#lx, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "lwp_mutex_wakeup", lwp_mutex_t *, lp,
+                 int, release_all);
+   PRE_FIELD_READ("lwp_mutex_wakeup(lp->mutex_type)", lp->vki_mutex_type);
+   PRE_FIELD_WRITE("lwp_mutex_wakeup(lp->mutex_waiters)",
+                   lp->vki_mutex_waiters);
+}
+
+POST(sys_lwp_mutex_wakeup)
+{
+   vki_lwp_mutex_t *lp = (vki_lwp_mutex_t*)ARG1;
+   POST_FIELD_WRITE(lp->vki_mutex_waiters);
+}
+
+PRE(sys_lwp_cond_broadcast)
+{
+   /* int lwp_cond_broadcast(lwp_cond_t *cvp); */
+   vki_lwp_cond_t *cvp = (vki_lwp_cond_t*)ARG1;
+   *flags |= SfMayBlock;
+   PRINT("sys_lwp_cond_broadcast ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "lwp_cond_broadcast", lwp_cond_t *, cvp);
+
+   PRE_FIELD_READ("lwp_cond_broadcast(cvp->type)", cvp->vki_cond_type);
+   PRE_FIELD_READ("lwp_cond_broadcast(cvp->waiters_kernel)",
+                  cvp->vki_cond_waiters_kernel);
+   /*PRE_FIELD_WRITE("lwp_cond_broadcast(cvp->waiters_kernel)",
+                     cvp->vki_cond_waiters_kernel);*/
+}
+
+POST(sys_lwp_cond_broadcast)
+{
+   vki_lwp_cond_t *cvp = (vki_lwp_cond_t*)ARG1;
+   POST_FIELD_WRITE(cvp->vki_cond_waiters_kernel);
+}
+
+PRE(sys_pread)
+{
+   /* ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset); */
+   *flags |= SfMayBlock;
+   PRINT("sys_pread ( %ld, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "pread", int, fildes, void *, buf,
+                 vki_size_t, nbyte, vki_off_t, offset);
+   PRE_MEM_WRITE("pread(buf)", ARG2, ARG3);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "pread", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_pread)
+{
+   POST_MEM_WRITE(ARG2, RES);
+}
+
+PRE(sys_pwrite)
+{
+   /* ssize_t pwrite(int fildes, const void *buf, size_t nbyte,
+                     off_t offset); */
+   *flags |= SfMayBlock;
+   PRINT("sys_pwrite ( %ld, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "pwrite", int, fildes, const void *, buf,
+                 vki_size_t, nbyte, vki_off_t, offset);
+   PRE_MEM_READ("pwrite(buf)", ARG2, ARG3);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "pwrite", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_getpagesizes)
+{
+   /* int getpagesizes(int legacy, size_t *buf, int nelem); */
+   PRINT("sys_getpagesizes ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "getpagesizes", int, legacy, size_t *, buf,
+                 int, nelem);
+   if (ARG2)
+      PRE_MEM_WRITE("getpagesizes(buf)", ARG2, ARG3 * sizeof(vki_size_t));
+}
+
+POST(sys_getpagesizes)
+{
+   if (ARG2)
+      POST_MEM_WRITE(ARG2, RES * sizeof(vki_size_t));
+}
+
+PRE(sys_rusagesys)
+{
+   /* Kernel: int rusagesys(int code, void *arg1, void *arg2,
+                            void *arg3, void *arg4); */
+   switch (ARG1 /*code*/) {
+   case VKI__RUSAGESYS_GETRUSAGE:
+   case VKI__RUSAGESYS_GETRUSAGE_CHLD:
+   case VKI__RUSAGESYS_GETRUSAGE_LWP:
+      /* Libc: int getrusage(int who, struct rusage *r_usage); */
+      PRINT("sys_rusagesys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("rusagesys", "getrusage"), int, code,
+                    struct vki_rusage *, r_usage);
+      PRE_MEM_WRITE("rusagesys(r_usage)", ARG2, sizeof(struct vki_rusage));
+      break;
+
+   case VKI__RUSAGESYS_GETVMUSAGE:
+      /* Libc: int getvmusage(uint_t flags, time_t age,
+                              vmusage_t *buf, size_t *nres); */
+      PRINT("sys_rusagesys ( %ld, %ld, %ld, %#lx, %#lx )",
+            ARG1, ARG2, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("rusagesys", "getvmusage"), int, code,
+                    vki_uint_t, flags, vki_time_t, age,
+                    vki_vmusage_t *, buf, vki_size_t *, nres);
+      PRE_MEM_READ("rusagesys(nres)", ARG5, sizeof(vki_size_t));
+      /* PRE_MEM_WRITE("rusagesys(nres)", ARG5, sizeof(vki_size_t)); */
+
+      if (ML_(safe_to_deref)((void *) ARG5, sizeof(vki_size_t))) {
+         vki_size_t *nres = (vki_size_t *) ARG5;
+         PRE_MEM_WRITE("rusagesys(buf)", ARG4,
+                       *nres * sizeof(vki_vmusage_t));
+      }
+      *flags |= SfMayBlock;
+      break;
+
+   default:
+      VG_(unimplemented)("Syswrap of the rusagesys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_rusagesys)
+{
+   switch (ARG1 /*code*/) {
+   case VKI__RUSAGESYS_GETRUSAGE:
+   case VKI__RUSAGESYS_GETRUSAGE_CHLD:
+   case VKI__RUSAGESYS_GETRUSAGE_LWP:
+      POST_MEM_WRITE(ARG2, sizeof(struct vki_rusage));
+      break;
+   case VKI__RUSAGESYS_GETVMUSAGE:
+      {
+         vki_size_t *nres = (vki_size_t *) ARG5;
+         POST_MEM_WRITE(ARG5, sizeof(vki_size_t));
+         POST_MEM_WRITE(ARG4, *nres * sizeof(vki_vmusage_t));
+      }
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+
+}
+
+PRE(sys_port)
+{
+   /* Kernel: int64_t portfs(int opcode, uintptr_t a0, uintptr_t a1,
+                             uintptr_t a2, uintptr_t a3, uintptr_t a4); */
+   Int opcode = ARG1 & VKI_PORT_CODE_MASK;
+   *flags |= SfMayBlock;
+   switch (opcode) {
+   case VKI_PORT_CREATE:
+      PRINT("sys_port ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("port", "create"), int, opcode);
+      break;
+   case VKI_PORT_ASSOCIATE:
+   case VKI_PORT_DISSOCIATE:
+      PRINT("sys_port ( %ld, %ld, %ld, %#lx, %ld, %#lx )", ARG1, ARG2, ARG3,
+            ARG4, ARG5, ARG6);
+      if (opcode == VKI_PORT_ASSOCIATE) {
+         PRE_REG_READ6(long, SC2("port", "associate"), int, opcode, int, a0,
+                       int, a1, uintptr_t, a2, int, a3, void *, a4);
+      }
+      else {
+         PRE_REG_READ6(long, SC2("port", "dissociate"), int, opcode, int, a0,
+                       int, a1, uintptr_t, a2, int, a3, void *, a4);
+      }
+
+      switch (ARG3 /*source*/) {
+      case VKI_PORT_SOURCE_FD:
+         if (!ML_(fd_allowed)(ARG4, "port", tid, False)) {
+            SET_STATUS_Failure(VKI_EBADF);
+         }
+         break;
+      case VKI_PORT_SOURCE_FILE:
+         {
+            struct vki_file_obj *fo = (struct vki_file_obj *)ARG4;
+            PRE_MEM_READ("port(file_obj)", ARG4, sizeof(struct vki_file_obj));
+            if (ML_(safe_to_deref)(&fo->fo_name, sizeof(fo->fo_name)))
+               PRE_MEM_RASCIIZ("port(file_obj->fo_name)", (Addr)fo->fo_name);
+         }
+         break;
+      default:
+         VG_(unimplemented)("Syswrap of the port_associate/dissociate call "
+                            "type %ld.", ARG3);
+         /*NOTREACHED*/
+         break;
+      }
+      break;
+   case VKI_PORT_SEND:
+      PRINT("sys_port ( %ld, %ld, %ld, %#lx )", ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("port", "send"), int, opcode, int, a0, int, a1,
+                    void *, a2);
+      break;
+   case VKI_PORT_SENDN:
+      PRINT("sys_port ( %ld, %#lx, %#lx, %lu, %lx, %#lx)", ARG1, ARG2, ARG3,
+            ARG4, ARG5, ARG6);
+      PRE_REG_READ6(long, SC2("port", "sendn"), int, opcode, int *, a0,
+                    int *, a1, vki_uint_t, a2, int, a3, void *, a4);
+      PRE_MEM_READ("port(ports)", ARG2, ARG4 * sizeof(int));
+      PRE_MEM_WRITE("port(errors)", ARG3, ARG4 * sizeof(int));
+      break;
+   case VKI_PORT_GET:
+      PRINT("sys_port ( %ld, %ld, %#lx, %ld, %ld, %#lx )", ARG1, ARG2, ARG3,
+            ARG4, ARG5, ARG6);
+      PRE_REG_READ6(long, SC2("port", "get"), int, opcode, int, a0,
+                    port_event_t *, a1, vki_time_t, a2, long, a3,
+                    timespec_t *, a4);
+      PRE_MEM_WRITE("port(uevp)", ARG3, sizeof(vki_port_event_t));
+      break;
+   case VKI_PORT_GETN:
+      PRINT("sys_port ( %ld, %ld, %#lx, %lu, %lu, %#lx )", ARG1, ARG2, ARG3,
+            ARG4, ARG5, ARG6);
+      PRE_REG_READ6(long, SC2("port", "getn"), int, opcode, int, a0,
+                    port_event_t *, a1, vki_uint_t, a2, vki_uint_t, a3,
+                    timespec_t *, a4);
+      if (ARG6)
+         PRE_MEM_READ("port(timeout)", ARG6, sizeof(vki_timespec_t));
+      PRE_MEM_WRITE("port(uevp)", ARG3, ARG4 * sizeof(vki_port_event_t));
+      break;
+   case VKI_PORT_ALERT:
+      PRINT("sys_port ( %ld, %ld, %ld, %ld, %#lx )", ARG1, ARG2, ARG3, ARG4,
+            ARG5);
+      PRE_REG_READ5(long, SC2("port", "alert"), int, opcode, int, a0, int, a1,
+                    int, a2, void *, a3);
+      break;
+   case VKI_PORT_DISPATCH:
+      PRINT("sys_port ( %ld, %ld, %ld, %ld, %#lx, %#lx )", ARG2, ARG1, ARG3,
+            ARG4, ARG5, ARG6);
+      PRE_REG_READ6(long, SC2("port", "dispatch"), int, opcode, int, a0,
+                    int, a1, int, a2, uintptr_t, a3, void *, a4);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the port call with opcode %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+
+   /* Be strict. */
+   if ((opcode != VKI_PORT_CREATE && opcode != VKI_PORT_SENDN) &&
+       !ML_(fd_allowed)(ARG2, "port", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_port)
+{
+   Int opcode = ARG1 & VKI_PORT_CODE_MASK;
+   switch (opcode) {
+   case VKI_PORT_CREATE:
+      if (!ML_(fd_allowed)(RES, "port", tid, True)) {
+         VG_(close)(RES);
+         SET_STATUS_Failure(VKI_EMFILE);
+      }
+      else if (VG_(clo_track_fds))
+         ML_(record_fd_open_named)(tid, RES);
+      break;
+   case VKI_PORT_ASSOCIATE:
+   case VKI_PORT_DISSOCIATE:
+   case VKI_PORT_SEND:
+      break;
+   case VKI_PORT_SENDN:
+      if (RES != ARG4) {
+         /* If there is any error then the whole errors area is written. */
+         POST_MEM_WRITE(ARG3, ARG4 * sizeof(int));
+      }
+      break;
+   case VKI_PORT_GET:
+      POST_MEM_WRITE(ARG3, sizeof(vki_port_event_t));
+      break;
+   case VKI_PORT_GETN:
+      POST_MEM_WRITE(ARG3, RES * sizeof(vki_port_event_t));
+      break;
+   case VKI_PORT_ALERT:
+   case VKI_PORT_DISPATCH:
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the port call with opcode %ld.", ARG2);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+PRE(sys_pollsys)
+{
+   /* int pollsys(pollfd_t *fds, nfds_t nfds, timespec_t *timeout,
+                  sigset_t *set); */
+   UWord i;
+   struct vki_pollfd *ufds = (struct vki_pollfd *)ARG1;
+
+   *flags |= SfMayBlock;
+
+   PRINT("sys_pollsys ( %#lx, %lu, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "poll", pollfd_t *, fds, vki_nfds_t, nfds,
+                 timespec_t *, timeout, sigset_t *, set);
+
+   for (i = 0; i < ARG2; i++) {
+      vki_pollfd_t *u = &ufds[i];
+      PRE_FIELD_READ("poll(ufds.fd)", u->fd);
+      /* XXX Check if it's valid? */
+      PRE_FIELD_READ("poll(ufds.events)", u->events);
+      PRE_FIELD_WRITE("poll(ufds.revents)", u->revents);
+   }
+
+   if (ARG3)
+      PRE_MEM_READ("poll(timeout)", ARG3, sizeof(vki_timespec_t));
+   if (ARG4)
+      PRE_MEM_READ("poll(set)", ARG4, sizeof(vki_sigset_t));
+}
+
+POST(sys_pollsys)
+{
+   if (RES >= 0) {
+      UWord i;
+      vki_pollfd_t *ufds = (vki_pollfd_t*)ARG1;
+      for (i = 0; i < ARG2; i++)
+         POST_FIELD_WRITE(ufds[i].revents);
+   }
+}
+
+PRE(sys_labelsys)
+{
+   /* Kernel: int labelsys(int op, void *a1, void *a2, void *a3,
+                           void *a4, void *a5); */
+
+   switch (ARG1 /*op*/) {
+   case VKI_TSOL_SYSLABELING:
+      /* Libc: int is_system_labeled(void); */
+      PRINT("sys_labelsys ( %ld )", ARG1);
+      PRE_REG_READ1(long, SC2("labelsys", "syslabeling"), int, op);
+      break;
+
+   case VKI_TSOL_TNRH:
+      /* Libtsnet: int tnrh(int cmd, tsol_rhent_t *buf); */
+      PRINT("sys_labelsys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("labelsys", "tnrh"), int, op, int, cmd,
+                    vki_tsol_rhent_t *, buf);
+      if (ARG2 != VKI_TNDB_FLUSH)
+         PRE_MEM_READ("labelsys(buf)", ARG3, sizeof(vki_tsol_rhent_t));
+      break;
+
+   case VKI_TSOL_TNRHTP:
+      /* Libtsnet: int tnrhtp(int cmd, tsol_tpent_t *buf); */
+      PRINT("sys_labelsys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("labelsys", "tnrhtp"), int, op, int, cmd,
+                    vki_tsol_tpent_t *, buf);
+      if (ARG2 != VKI_TNDB_FLUSH)
+         PRE_MEM_READ("labelsys(buf)", ARG3, sizeof(vki_tsol_tpent_t));
+      break;
+
+   case VKI_TSOL_TNMLP:
+      /* Libtsnet: int tnmlp(int cmd, tsol_mlpent_t *buf); */
+      PRINT("sys_labelsys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("labelsys", "tnmlp"), int, op, int, cmd,
+                    vki_tsol_mlpent_t *, buf);
+      PRE_MEM_READ("labelsys(buf)", ARG3, sizeof(vki_tsol_mlpent_t));
+      break;
+
+   case VKI_TSOL_GETLABEL:
+      /* Libtsol: int getlabel(const char *path, bslabel_t *label); */
+      PRINT("sys_labelsys ( %ld, %#lx(%s), %#lx )",
+            ARG1, ARG2, (HChar *) ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("labelsys", "getlabel"), int, op,
+                    const char *, path, vki_bslabel_t *, label);
+      PRE_MEM_RASCIIZ("labelsys(path)", ARG2);
+      PRE_MEM_WRITE("labelsys(label)", ARG3, sizeof(vki_bslabel_t));
+      break;
+
+   case VKI_TSOL_FGETLABEL:
+      /* Libtsol: int fgetlabel(int fd, bslabel_t *label); */
+      PRINT("sys_labelsys ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("labelsys", "fgetlabel"), int, op,
+                    int, fd, vki_bslabel_t *, label);
+      /* Be strict. */
+      if (!ML_(fd_allowed)(ARG2, "labelsys(fgetlabel)", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      PRE_MEM_WRITE("labelsys(label)", ARG3, sizeof(vki_bslabel_t));
+      break;
+
+#if defined(SOLARIS_TSOL_CLEARANCE)
+   case VKI_TSOL_GETCLEARANCE:
+      /* Libtsol: int getclearance(bslabel_t *clearance); */
+      PRINT("sys_labelsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("labelsys", "getclearance"), int, op,
+                    vki_bslabel_t *, clearance);
+      PRE_MEM_WRITE("labelsys(clearance)", ARG2, sizeof(vki_bslabel_t));
+      break;
+
+   case VKI_TSOL_SETCLEARANCE:
+      /* Libtsol: int setclearance(bslabel_t *clearance); */
+      PRINT("sys_labelsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("labelsys", "setclearance"), int, op,
+                    vki_bslabel_t *, clearance);
+      PRE_MEM_READ("labelsys(clearance)", ARG2, sizeof(vki_bslabel_t));
+      break;
+#endif /* SOLARIS_TSOL_CLEARANCE */
+
+   default:
+      VG_(unimplemented)("Syswrap of the labelsys call with op %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_labelsys)
+{
+   switch (ARG1 /*op*/) {
+   case VKI_TSOL_SYSLABELING:
+      break;
+
+   case VKI_TSOL_TNRH:
+      switch (ARG2 /*cmd*/) {
+      case VKI_TNDB_LOAD:
+      case VKI_TNDB_DELETE:
+      case VKI_TNDB_FLUSH:
+         break;
+#if defined(SOLARIS_TNDB_GET_TNIP)
+      case TNDB_GET_TNIP:
+#endif /* SOLARIS_TNDB_GET_TNIP */
+      case VKI_TNDB_GET:
+         POST_MEM_WRITE(ARG3, sizeof(vki_tsol_rhent_t));
+         break;
+      default:
+         vg_assert(0);
+         break;
+      }
+      break;
+
+   case VKI_TSOL_TNRHTP:
+      switch (ARG2 /*cmd*/) {
+      case VKI_TNDB_LOAD:
+      case VKI_TNDB_DELETE:
+      case VKI_TNDB_FLUSH:
+         break;
+      case VKI_TNDB_GET:
+         POST_MEM_WRITE(ARG3, sizeof(vki_tsol_tpent_t));
+         break;
+      default:
+         vg_assert(0);
+         break;
+      }
+      break;
+
+   case VKI_TSOL_TNMLP:
+      switch (ARG2 /*cmd*/) {
+      case VKI_TNDB_LOAD:
+      case VKI_TNDB_DELETE:
+      case VKI_TNDB_FLUSH:
+         break;
+      case VKI_TNDB_GET:
+         POST_MEM_WRITE(ARG3, sizeof(vki_tsol_mlpent_t));
+         break;
+      default:
+         vg_assert(0);
+         break;
+      }
+      break;
+
+   case VKI_TSOL_GETLABEL:
+   case VKI_TSOL_FGETLABEL:
+      POST_MEM_WRITE(ARG3, sizeof(vki_bslabel_t));
+      break;
+
+#if defined(SOLARIS_TSOL_CLEARANCE)
+   case VKI_TSOL_GETCLEARANCE:
+      POST_MEM_WRITE(ARG2, sizeof(vki_bslabel_t));
+      break;
+
+   case VKI_TSOL_SETCLEARANCE:
+      break;
+#endif /* SOLARIS_TSOL_CLEARANCE */
+
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_acl)
+{
+   /* int acl(char *pathp, int cmd, int nentries, void *aclbufp); */
+   PRINT("sys_acl ( %#lx(%s), %ld, %ld, %#lx )", ARG1, (HChar *) ARG1, ARG2,
+         ARG3, ARG4);
+
+   PRE_REG_READ4(long, "acl", char *, pathp, int, cmd,
+                 int, nentries, void *, aclbufp);
+   PRE_MEM_RASCIIZ("acl(pathp)", ARG1);
+
+   switch (ARG2 /*cmd*/) {
+   case VKI_SETACL:
+      if (ARG4)
+         PRE_MEM_READ("acl(aclbufp)", ARG4, ARG3 * sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACL:
+      PRE_MEM_WRITE("acl(aclbufp)", ARG4, ARG3 * sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACLCNT:
+      break;
+   case VKI_ACE_SETACL:
+      if (ARG4)
+         PRE_MEM_READ("acl(aclbufp)", ARG4, ARG3 * sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACL:
+      PRE_MEM_WRITE("acl(aclbufp)", ARG4, ARG3 * sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACLCNT:
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the acl call with cmd %ld.", ARG2);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_acl)
+{
+   switch (ARG2 /*cmd*/) {
+   case VKI_SETACL:
+      break;
+   case VKI_GETACL:
+      POST_MEM_WRITE(ARG4, ARG3 * sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACLCNT:
+      break;
+   case VKI_ACE_SETACL:
+      break;
+   case VKI_ACE_GETACL:
+      POST_MEM_WRITE(ARG4, ARG3 * sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACLCNT:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_auditsys)
+{
+   /* Kernel: int auditsys(long code, long a1, long a2, long a3, long a4); */
+   switch (ARG1 /*code*/) {
+   case VKI_BSM_GETAUID:
+      /* Libbsm: int getauid(au_id_t *auid); */
+      PRINT("sys_auditsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("auditsys", "getauid"), long, code,
+                    vki_au_id_t *, auid);
+      PRE_MEM_WRITE("auditsys(auid)", ARG2, sizeof(vki_au_id_t));
+      break;
+   case VKI_BSM_SETAUID:
+      /* Libbsm: int setauid(au_id_t *auid); */
+      PRINT("sys_auditsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("auditsys", "setauid"), long, code,
+                    vki_au_id_t *, auid);
+      PRE_MEM_READ("auditsys(auid)", ARG2, sizeof(vki_au_id_t));
+      break;
+   case VKI_BSM_GETAUDIT:
+      /* Libbsm: int getaudit(auditinfo_t *ai); */
+      PRINT("sys_auditsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("auditsys", "getaudit"), long, code,
+                    vki_auditinfo_t *, ai);
+      PRE_MEM_WRITE("auditsys(ai)", ARG2, sizeof(vki_auditinfo_t));
+      break;
+   case VKI_BSM_SETAUDIT:
+      /* Libbsm: int setaudit(auditinfo_t *ai); */
+      PRINT("sys_auditsys ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("auditsys", "setaudit"), long, code,
+                    vki_auditinfo_t *, ai);
+      PRE_MEM_READ("auditsys(ai)", ARG2, sizeof(vki_auditinfo_t));
+      break;
+   case VKI_BSM_AUDIT:
+      /* Libbsm: int audit(void *record, int length); */
+      PRINT("sys_auditsys ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("auditsys", "audit"), long, code,
+                    void *, record, int, length);
+      PRE_MEM_READ("auditsys(record)", ARG2, ARG3);
+      break;
+   case VKI_BSM_AUDITCTL:
+      /* Libbsm: int auditon(int cmd, caddr_t data, int length); */
+      PRINT("sys_auditsys ( %ld, %ld, %#lx, %ld )",
+            ARG1, ARG2, ARG3, ARG4);
+
+      switch (ARG2 /*cmd*/) {
+      case VKI_A_GETPOLICY:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getpolicy"),
+                       long, code, int, cmd, vki_uint32_t *, policy);
+         PRE_MEM_WRITE("auditsys(policy)", ARG3, sizeof(vki_uint32_t));
+         break;
+      case VKI_A_SETPOLICY:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setpolicy"),
+                       long, code, int, cmd, vki_uint32_t *, policy);
+         PRE_MEM_READ("auditsys(policy)", ARG3, sizeof(vki_uint32_t));
+         break;
+      case VKI_A_GETKMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getkmask"),
+                       long, code, int, cmd, vki_au_mask_t *, kmask);
+         PRE_MEM_WRITE("auditsys(kmask)", ARG3, sizeof(vki_au_mask_t));
+         break;
+      case VKI_A_SETKMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setkmask"),
+                       long, code, int, cmd, vki_au_mask_t *, kmask);
+         PRE_MEM_READ("auditsys(kmask)", ARG3, sizeof(vki_au_mask_t));
+         break;
+      case VKI_A_GETQCTRL:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getqctrl"),
+                       long, code, int, cmd,
+                       struct vki_au_qctrl *, qctrl);
+         PRE_MEM_WRITE("auditsys(qctrl)", ARG3,
+                       sizeof(struct vki_au_qctrl));
+         break;
+      case VKI_A_SETQCTRL:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setqctrl"),
+                       long, code, int, cmd,
+                       struct vki_au_qctrl *, qctrl);
+         PRE_MEM_READ("auditsys(qctrl)", ARG3,
+                      sizeof(struct vki_au_qctrl));
+         break;
+      case VKI_A_GETCWD:
+         PRE_REG_READ4(long, SC3("auditsys", "auditctl", "getcwd"),
+                       long, code, int, cmd, char *, data, int, length);
+         PRE_MEM_WRITE("auditsys(data)", ARG3, ARG4);
+         break;
+      case VKI_A_GETCAR:
+         PRE_REG_READ4(long, SC3("auditsys", "auditctl", "getcar"),
+                       long, code, int, cmd, char *, data, int, length);
+         PRE_MEM_WRITE("auditsys(data)", ARG3, ARG4);
+         break;
+      case VKI_A_GETSTAT:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getstat"),
+                       long, code, int, cmd, vki_au_stat_t *, stats);
+         PRE_MEM_WRITE("auditsys(stats)", ARG3, sizeof(vki_au_stat_t));
+         break;
+      case VKI_A_SETSTAT:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setstat"),
+                       long, code, int, cmd, vki_au_stat_t *, stats);
+         PRE_MEM_READ("auditsys(stats)", ARG3, sizeof(vki_au_stat_t));
+         break;
+      case VKI_A_SETUMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setumask"),
+                       long, code, int, cmd, vki_auditinfo_t *, umask);
+         PRE_MEM_READ("auditsys(umask)", ARG3, sizeof(vki_auditinfo_t));
+         break;
+      case VKI_A_SETSMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setsmask"),
+                       long, code, int, cmd, vki_auditinfo_t *, smask);
+         PRE_MEM_READ("auditsys(smask)", ARG3, sizeof(vki_auditinfo_t));
+         break;
+      case VKI_A_GETCOND:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getcond"),
+                       long, code, int, cmd, int *, cond);
+         PRE_MEM_WRITE("auditsys(cond)", ARG3, sizeof(int));
+         break;
+      case VKI_A_SETCOND:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setcond"),
+                       long, code, int, cmd, int *, state);
+         PRE_MEM_READ("auditsys(cond)", ARG3, sizeof(int));
+         break;
+      case VKI_A_GETCLASS:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getclass"),
+                       long, code, int, cmd,
+                       vki_au_evclass_map_t *, classmap);
+
+         if (ML_(safe_to_deref((void *) ARG3,
+                               sizeof(vki_au_evclass_map_t)))) {
+            vki_au_evclass_map_t *classmap =
+               (vki_au_evclass_map_t *) ARG3;
+            PRE_FIELD_READ("auditsys(classmap.ec_number)",
+                           classmap->ec_number);
+            PRE_MEM_WRITE("auditsys(classmap)", ARG3,
+                          sizeof(vki_au_evclass_map_t));
+         }
+         break;
+      case VKI_A_SETCLASS:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setclass"),
+                       long, code, int, cmd,
+                       vki_au_evclass_map_t *, classmap);
+
+         if (ML_(safe_to_deref((void *) ARG3, 
+                               sizeof(vki_au_evclass_map_t)))) {
+            vki_au_evclass_map_t *classmap =
+               (vki_au_evclass_map_t *) ARG3;
+            PRE_FIELD_READ("auditsys(classmap.ec_number)", 
+                           classmap->ec_number);  
+            PRE_FIELD_READ("auditsys(classmap.ec_class)", 
+                           classmap->ec_class);
+         }
+         break;
+      case VKI_A_GETPINFO:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getpinfo"),
+                       long, code, int, cmd,
+                       struct vki_auditpinfo *, apinfo);
+
+         if (ML_(safe_to_deref((void *) ARG3,
+                               sizeof(struct vki_auditpinfo)))) {
+            struct vki_auditpinfo *apinfo =
+               (struct vki_auditpinfo *) ARG3;
+            PRE_FIELD_READ("auditsys(apinfo.ap_pid)", apinfo->ap_pid);
+            PRE_MEM_WRITE("auditsys(apinfo)", ARG3,
+                          sizeof(struct vki_auditpinfo));
+         }
+         break;
+      case VKI_A_SETPMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setpmask"),
+                       long, code, int, cmd,
+                       struct vki_auditpinfo *, apinfo);
+         PRE_MEM_WRITE("auditsys(apinfo)", ARG3,
+                       sizeof(struct vki_auditpinfo));
+         break;
+      case VKI_A_GETPINFO_ADDR:
+         PRE_REG_READ4(long, SC3("auditsys", "auditctl", "getpinfo_addr"),
+                       long, code, int, cmd,
+                       struct vki_auditpinfo_addr *, apinfo, int, length);
+
+         if (ML_(safe_to_deref((void *) ARG3,
+                               sizeof(struct vki_auditpinfo_addr)))) {
+            struct vki_auditpinfo_addr *apinfo_addr =
+               (struct vki_auditpinfo_addr *) ARG3;
+            PRE_FIELD_READ("auditsys(apinfo_addr.ap_pid)",
+                           apinfo_addr->ap_pid);
+            PRE_MEM_WRITE("auditsys(apinfo_addr)", ARG3, ARG4);
+         }
+         break;
+      case VKI_A_GETKAUDIT:
+         PRE_REG_READ4(long, SC3("auditsys", "auditctl", "getkaudit"),
+                       long, code, int, cmd,
+                       vki_auditinfo_addr_t *, kaudit, int, length);
+         PRE_MEM_WRITE("auditsys(kaudit)", ARG3, ARG4);
+         break;
+      case VKI_A_SETKAUDIT:
+         PRE_REG_READ4(long, SC3("auditsys", "auditctl", "setkaudit"),
+                       long, code, int, cmd,
+                       vki_auditinfo_addr_t *, kaudit, int, length);
+         PRE_MEM_READ("auditsys(kaudit)", ARG3, ARG4);
+         break;
+      case VKI_A_GETAMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "getamask"),
+                       long, code, int, cmd, vki_au_mask_t *, amask);
+         PRE_MEM_WRITE("auditsys(amask)", ARG3, sizeof(vki_au_mask_t));
+         break;
+      case VKI_A_SETAMASK:
+         PRE_REG_READ3(long, SC3("auditsys", "auditctl", "setamask"),
+                       long, code, int, cmd, vki_au_mask_t *, amask);
+         PRE_MEM_READ("auditsys(amask)", ARG3, sizeof(vki_au_mask_t));
+         break;
+      default:
+         VG_(unimplemented)("Syswrap of the auditsys(auditctl) call "
+                            "with cmd %ld.", ARG2);
+         /*NOTREACHED*/
+         break;
+      }
+      break;
+   case VKI_BSM_GETAUDIT_ADDR:
+      /* Libbsm: int getaudit_addr(auditinfo_addr_t *ai, int len); */
+      PRINT("sys_auditsys ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("auditsys", "getaudit_addr"), long, code,
+                    vki_auditinfo_addr_t *, ai, int, len);
+      PRE_MEM_WRITE("auditsys(ai)", ARG2, ARG3);
+      break;
+   case VKI_BSM_SETAUDIT_ADDR:
+      /* Libbsm: int setaudit_addr(auditinfo_addr_t *ai, int len); */
+      PRINT("sys_auditsys ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("auditsys", "setaudit_addr"), long, code,
+                    vki_auditinfo_addr_t *, ai, int, len);
+      PRE_MEM_READ("auditsys(ai)", ARG2, ARG3);
+      break;
+   case VKI_BSM_AUDITDOOR:
+      /* Libbsm: int auditdoor(int fd); */
+      PRINT("sys_auditsys ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("auditsys", "door"), long, code, int, fd);
+
+      /* Be strict. */
+      if (!ML_(fd_allowed)(ARG2, SC2("auditsys", "door")"(fd)",
+                           tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the auditsys call with code %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_auditsys)
+{
+   switch (ARG1 /*code*/) {
+   case VKI_BSM_GETAUID:
+      POST_MEM_WRITE(ARG2, sizeof(vki_au_id_t));
+      break;
+   case VKI_BSM_SETAUID:
+      break;
+   case VKI_BSM_GETAUDIT:
+      POST_MEM_WRITE(ARG2, sizeof(vki_auditinfo_t));
+      break;
+   case VKI_BSM_SETAUDIT:
+   case VKI_BSM_AUDIT:
+      break;
+   case VKI_BSM_AUDITCTL:
+      switch (ARG2 /*cmd*/) {
+         case VKI_A_GETPOLICY:
+            POST_MEM_WRITE(ARG3, sizeof(vki_uint32_t));
+            break;
+         case VKI_A_SETPOLICY:
+            break;
+         case VKI_A_GETKMASK:
+            POST_MEM_WRITE(ARG3, sizeof(vki_au_mask_t));
+            break;
+         case VKI_A_SETKMASK:
+            break;
+         case VKI_A_GETQCTRL:
+            POST_MEM_WRITE(ARG3, sizeof(struct vki_au_qctrl));
+            break;
+         case VKI_A_SETQCTRL:
+            break;
+         case VKI_A_GETCWD:
+         case VKI_A_GETCAR:
+            POST_MEM_WRITE(ARG3, VG_(strlen)((HChar *) ARG3) + 1);
+            break;
+         case VKI_A_GETSTAT:
+            POST_MEM_WRITE(ARG3, sizeof(vki_au_stat_t));
+            break;
+         case VKI_A_SETSTAT:
+         case VKI_A_SETUMASK:
+         case VKI_A_SETSMASK:
+            break;
+         case VKI_A_GETCOND:
+            POST_MEM_WRITE(ARG3, sizeof(int));
+            break;
+         case VKI_A_SETCOND:
+            break;
+         case VKI_A_GETCLASS:
+            POST_MEM_WRITE(ARG3, sizeof(vki_au_evclass_map_t));
+            break;
+         case VKI_A_SETCLASS:
+            break;
+         case VKI_A_GETPINFO:
+            POST_MEM_WRITE(ARG3, sizeof(struct vki_auditpinfo));
+            break;
+         case VKI_A_SETPMASK:
+            break;
+         case VKI_A_GETPINFO_ADDR:
+            POST_MEM_WRITE(ARG3, sizeof(struct auditpinfo_addr));
+            break;
+         case VKI_A_GETKAUDIT:
+            POST_MEM_WRITE(ARG3, sizeof(vki_auditinfo_addr_t));
+            break;
+         case VKI_A_SETKAUDIT:
+            break;
+         case VKI_A_GETAMASK:
+            POST_MEM_WRITE(ARG3, sizeof(vki_au_mask_t));
+            break;
+         case VKI_A_SETAMASK:
+            break;
+      }
+      break;
+   case VKI_BSM_GETAUDIT_ADDR:
+      POST_MEM_WRITE(ARG2, sizeof(vki_auditinfo_addr_t));
+      break;
+   case VKI_BSM_SETAUDIT_ADDR:
+      break;
+   case VKI_BSM_AUDITDOOR:
+      break;
+   }
+}
+
+PRE(sys_p_online)
+{
+   /* int p_online(processorid_t processorid, int flag); */
+   PRINT("sys_p_online ( %ld, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "p_online", vki_processorid_t, processorid, int, flag);
+}
+
+PRE(sys_sigqueue)
+{
+   /* int sigqueue(pid_t pid, int signo, void *value,
+                   int si_code, timespec_t *timeout);
+    */
+   PRINT("sys_sigqueue ( %ld, %ld, %#lx, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "sigqueue", vki_pid_t, pid, int, signo,
+                 void *, value, int, si_code,
+                 vki_timespec_t *, timeout);
+
+   if (ARG5)
+      PRE_MEM_READ("sigqueue(timeout)", ARG5, sizeof(vki_timespec_t));
+
+   if (!ML_(client_signal_OK)(ARG2)) {
+      SET_STATUS_Failure(VKI_EINVAL);
+      return;
+   }
+
+   /* If we're sending SIGKILL, check to see if the target is one of
+      our threads and handle it specially. */
+   if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) {
+      SET_STATUS_Success(0);
+   } else {
+      SysRes res = VG_(do_syscall5)(SYSNO, ARG1, ARG2, ARG3, ARG4,
+                                    ARG5);
+      SET_STATUS_from_SysRes(res);
+   }
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "sigqueue: signal %ld queued for pid %ld\n",
+                   ARG2, ARG1);
+
+   /* Check to see if this gave us a pending signal. */
+   *flags |= SfPollAfter;
+}
+
+PRE(sys_clock_gettime)
+{
+   /* int clock_gettime(clockid_t clock_id, struct timespec *tp); */
+   PRINT("sys_clock_gettime ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "clock_gettime", vki_clockid_t, clock_id,
+                 struct timespec *, tp);
+   PRE_MEM_WRITE("clock_gettime(tp)", ARG2, sizeof(struct vki_timespec));
+}
+
+POST(sys_clock_gettime)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec));
+}
+
+PRE(sys_clock_settime)
+{
+   /* int clock_settime(clockid_t clock_id, const struct timespec *tp); */
+   PRINT("sys_clock_settime ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "clock_settime", vki_clockid_t, clock_id,
+                 const struct timespec *, tp);
+   PRE_MEM_READ("clock_settime(tp)", ARG2, sizeof(struct vki_timespec));
+}
+
+PRE(sys_clock_getres)
+{
+   /* int clock_getres(clockid_t clock_id, struct timespec *res); */
+   PRINT("sys_clock_getres ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "clock_getres", vki_clockid_t, clock_id,
+                 struct timespec *, res);
+
+   if (ARG2)
+      PRE_MEM_WRITE("clock_getres(res)", ARG2, sizeof(struct vki_timespec));
+}
+
+POST(sys_clock_getres)
+{
+   if (ARG2)
+      POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec));
+}
+
+PRE(sys_timer_create)
+{
+   /* int timer_create(clockid_t clock_id,
+                       struct sigevent *evp, timer_t *timerid);
+    */
+   PRINT("sys_timer_create ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "timer_create", vki_clockid_t, clock_id,
+                 struct vki_sigevent *, evp, vki_timer_t *, timerid);
+
+   if (ARG2) {
+      struct vki_sigevent *evp = (struct vki_sigevent *) ARG2;
+      PRE_FIELD_READ("timer_create(evp.sigev_notify)", evp->sigev_notify);
+      PRE_FIELD_READ("timer_create(evp.sigev_signo)", evp->sigev_signo);
+      PRE_FIELD_READ("timer_create(evp.sigev_value.sival_int)",
+         evp->sigev_value.sival_int);
+
+      /* Be safe. */
+      if (ML_(safe_to_deref(evp, sizeof(struct vki_sigevent)))) {
+         if ((evp->sigev_notify == VKI_SIGEV_PORT) ||
+             (evp->sigev_notify == VKI_SIGEV_THREAD))
+            PRE_MEM_READ("timer_create(evp.sigev_value.sival_ptr)", 
+                         (Addr) evp->sigev_value.sival_ptr,
+                         sizeof(vki_port_notify_t));
+      }
+   }
+
+   PRE_MEM_WRITE("timer_create(timerid)", ARG3, sizeof(vki_timer_t));
+}
+
+POST(sys_timer_create)
+{
+   POST_MEM_WRITE(ARG3, sizeof(vki_timer_t));
+}
+
+PRE(sys_timer_delete)
+{
+   /* int timer_delete(timer_t timerid); */
+   PRINT("sys_timer_delete ( %ld )", ARG1);
+   PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
+}
+
+PRE(sys_timer_settime)
+{
+   /* int timer_settime(timer_t timerid, int flags,
+                        const struct itimerspec *value,
+                        struct itimerspec *ovalue);
+    */
+   PRINT("sys_timer_settime ( %ld, %ld, %#lx, %#lx )",
+         ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "timer_settime", vki_timer_t, timerid,
+                 int, flags, const struct vki_itimerspec *, value,
+                 struct vki_itimerspec *, ovalue);
+   PRE_MEM_READ("timer_settime(value)",
+                ARG3, sizeof(struct vki_itimerspec));
+   if (ARG4)
+      PRE_MEM_WRITE("timer_settime(ovalue)",
+                    ARG4, sizeof(struct vki_itimerspec));
+}
+
+POST(sys_timer_settime)
+{
+   if (ARG4)
+      POST_MEM_WRITE(ARG4, sizeof(struct vki_itimerspec));
+}
+
+PRE(sys_timer_gettime)
+{
+   /* int timer_gettime(timer_t timerid, struct itimerspec *value); */
+   PRINT("sys_timer_gettime ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "timer_gettime", vki_timer_t, timerid,
+                 struct vki_itimerspec *, value);
+   PRE_MEM_WRITE("timer_gettime(value)",
+                 ARG2, sizeof(struct vki_itimerspec));
+}
+
+POST(sys_timer_gettime)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_itimerspec));
+}
+
+PRE(sys_timer_getoverrun)
+{
+   /* int timer_getoverrun(timer_t timerid); */
+   PRINT("sys_timer_getoverrun ( %ld )", ARG1);
+   PRE_REG_READ1(long, "timer_getoverrun", vki_timer_t, timerid);
+}
+
+PRE(sys_facl)
+{
+   /* int facl(int fildes, int cmd, int nentries, void *aclbufp); */
+   PRINT("sys_facl ( %ld, %ld, %ld, %#lx )", ARG1, ARG2, ARG3, ARG4);
+
+   PRE_REG_READ4(long, "facl", int, fildes, int, cmd,
+                 int, nentries, void *, aclbufp);
+
+   switch (ARG2 /*cmd*/) {
+   case VKI_SETACL:
+      if (ARG4)
+         PRE_MEM_READ("facl(aclbufp)", ARG4, sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACL:
+      PRE_MEM_WRITE("facl(aclbufp)", ARG4, ARG3 * sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACLCNT:
+      break;
+   case VKI_ACE_SETACL:
+      if (ARG4)
+         PRE_MEM_READ("facl(aclbufp)", ARG4, sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACL:
+      PRE_MEM_WRITE("facl(aclbufp)", ARG4, ARG3 * sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACLCNT:
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the facl call with cmd %ld.", ARG2);
+      /*NOTREACHED*/
+      break;
+   }
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "facl", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_facl)
+{
+   switch (ARG2 /*cmd*/) {
+   case VKI_SETACL:
+      break;
+   case VKI_GETACL:
+      POST_MEM_WRITE(ARG4, ARG3 * sizeof(vki_aclent_t));
+      break;
+   case VKI_GETACLCNT:
+      break;
+   case VKI_ACE_SETACL:
+      break;
+   case VKI_ACE_GETACL:
+      POST_MEM_WRITE(ARG4, ARG3 * sizeof(vki_ace_t));
+      break;
+   case VKI_ACE_GETACLCNT:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+static Int pre_check_and_close_fds(ThreadId tid, const HChar *name,
+                                   vki_door_desc_t *desc_ptr,
+                                   vki_uint_t desc_num)
+{
+   vki_uint_t i;
+
+   /* Verify passed file descriptors. */
+   for (i = 0; i < desc_num; i++) {
+      vki_door_desc_t *desc = &desc_ptr[i];
+      if ((desc->d_attributes & DOOR_DESCRIPTOR) &&
+          (desc->d_attributes & DOOR_RELEASE)) {
+         Int fd = desc->d_data.d_desc.d_descriptor;
+
+         /* Detect and negate attempts by the client to close Valgrind's fds.
+            Also if doing -d style logging (which is to fd = 2 = stderr),
+            don't allow that to be closed either. */
+         if (!ML_(fd_allowed)(fd, name, tid, False) ||
+             (fd == 2 && VG_(debugLog_getLevel)() > 0))
+            return VKI_EBADF;
+      }
+   }
+
+   /* All fds are allowed, record information about the closed ones.
+
+      Note: Recording information about any closed fds should generally happen
+      in a post wrapper but it is not possible in this case because door calls
+      are "very blocking", if the information was recorded after the syscall
+      finishes then it would be out-of-date during the call, i.e. while the
+      syscall is blocked in the kernel.  Therefore, we record closed fds for
+      this specific syscall in the PRE wrapper.  Unfortunately, this creates
+      a problem when the syscall fails, for example, door_call() can fail with
+      EBADF or EFAULT and then no fds are released.  If that happens the
+      information about opened fds is incorrect.  This should be very rare (I
+      hope) and such a condition is also reported in the post wrapper. */
+   if (VG_(clo_track_fds)) {
+      for (i = 0; i < desc_num; i++) {
+         vki_door_desc_t *desc = &desc_ptr[i];
+         if ((desc->d_attributes & DOOR_DESCRIPTOR) &&
+             (desc->d_attributes & DOOR_RELEASE)) {
+            Int fd = desc->d_data.d_desc.d_descriptor;
+            ML_(record_fd_close)(fd);
+         }
+      }
+   }
+
+   return 0;
+}
+
+static void post_record_fds(ThreadId tid, const HChar *name,
+                            vki_door_desc_t *desc_ptr, vki_uint_t desc_num)
+{
+   vki_uint_t i;
+
+   /* Record returned file descriptors. */
+   for (i = 0; i < desc_num; i++) {
+      vki_door_desc_t *desc = &desc_ptr[i];
+      if (desc->d_attributes & DOOR_DESCRIPTOR) {
+         Int fd = desc->d_data.d_desc.d_descriptor;
+         if (!ML_(fd_allowed)(fd, name, tid, True)) {
+            /* Unfortunately, we cannot recover at this point and have to fail
+               hard. */
+            VG_(message)(Vg_UserMsg, "The %s syscall returned an unallowed"
+                                     "file descriptor %d.\n", name, fd);
+            VG_(exit)(101);
+         }
+         else if (VG_(clo_track_fds))
+            ML_(record_fd_open_named)(tid, fd);
+      }
+   }
+}
+
+/* Handles repository door protocol request over client door fd. */
+static void repository_door_pre_mem_door_call_hook(ThreadId tid, Int fd,
+                                                   void *data_ptr,
+                                                   SizeT data_size)
+{
+   vki_rep_protocol_request_t *p = (vki_rep_protocol_request_t *) data_ptr;
+   PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                  "request->rpr_request)", p->rpr_request);
+
+   if (ML_(safe_to_deref)(p, sizeof(vki_rep_protocol_request_t))) {
+      switch (p->rpr_request) {
+      case VKI_REP_PROTOCOL_CLOSE:
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_SETUP:
+         {
+            struct vki_rep_protocol_entity_setup *r =
+               (struct vki_rep_protocol_entity_setup *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_setup->rpr_entityid)", r->rpr_entityid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_setup->rpr_entitytype)", r->rpr_entitytype);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_NAME:
+         {
+            struct vki_rep_protocol_entity_name *r =
+               (struct vki_rep_protocol_entity_name *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_name->rpr_entityid)", r->rpr_entityid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_name->rpr_answertype)", r->rpr_answertype);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_GET:
+         {
+            struct vki_rep_protocol_entity_get *r =
+               (struct vki_rep_protocol_entity_get *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get->rpr_entityid)", r->rpr_entityid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get->rpr_object)", r->rpr_object);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_GET_CHILD:
+         {
+            struct vki_rep_protocol_entity_get_child *r =
+               (struct vki_rep_protocol_entity_get_child *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get_child->rpr_entityid)", r->rpr_entityid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get_child->rpr_childid)", r->rpr_childid);
+            PRE_MEM_RASCIIZ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                            "entity_get_child->rpr_name)", (Addr) r->rpr_name);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_GET_PARENT:
+         {
+            struct vki_rep_protocol_entity_parent *r =
+               (struct vki_rep_protocol_entity_parent *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get_parent->rpr_entityid)", r->rpr_entityid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_get_parent->rpr_outid)", r->rpr_outid);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_RESET:
+         {
+            struct vki_rep_protocol_entity_reset *r =
+               (struct vki_rep_protocol_entity_reset *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_reset->rpr_entityid)", r->rpr_entityid);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ENTITY_TEARDOWN:
+         {
+            struct vki_rep_protocol_entity_teardown *r =
+               (struct vki_rep_protocol_entity_teardown *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "entity_teardown->rpr_entityid)", r->rpr_entityid);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ITER_READ:
+         {
+            struct vki_rep_protocol_iter_read *r =
+               (struct vki_rep_protocol_iter_read *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_read->rpr_iterid)", r->rpr_iterid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_read->rpr_sequence)", r->rpr_sequence);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_read->rpr_entityid)", r->rpr_entityid);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ITER_READ_VALUE:
+         {
+            struct vki_rep_protocol_iter_read_value *r =
+               (struct vki_rep_protocol_iter_read_value *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_read_value->rpr_iterid)", r->rpr_iterid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_read_value->rpr_sequence)", r->rpr_sequence);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ITER_RESET:
+      case VKI_REP_PROTOCOL_ITER_SETUP:
+      case VKI_REP_PROTOCOL_ITER_TEARDOWN:
+         {
+            struct vki_rep_protocol_iter_request *r =
+               (struct vki_rep_protocol_iter_request *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_request->rpr_iterid)", r->rpr_iterid);
+         }
+         break;
+      case VKI_REP_PROTOCOL_ITER_START:
+         {
+            struct vki_rep_protocol_iter_start *r =
+               (struct vki_rep_protocol_iter_start *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_start->rpr_iterid)", r->rpr_iterid);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_start->rpr_entity)", r->rpr_entity);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_start->rpr_itertype)", r->rpr_itertype);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "iter_start->rpr_flags)", r->rpr_flags);
+            PRE_MEM_RASCIIZ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                            "iter_start->rpr_pattern)", (Addr) r->rpr_pattern);
+         }
+         break;
+      case VKI_REP_PROTOCOL_PROPERTY_GET_TYPE:
+      case VKI_REP_PROTOCOL_PROPERTY_GET_VALUE:
+         {
+            struct vki_rep_protocol_property_request *r =
+               (struct vki_rep_protocol_property_request *) p;
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "property_request->rpr_entityid)", r->rpr_entityid);
+         }
+         break;
+      default:
+         VG_(unimplemented)("Door wrapper of " VKI_REPOSITORY_DOOR_NAME
+                            " where rpr_request=%u.", p->rpr_request);
+         /* NOTREACHED */
+         break;
+      }        
+   }
+}
+
+/* Handles repository door protocol response over client door fd. */
+static void repository_door_post_mem_door_call_hook(ThreadId tid, Int fd,
+                                                    void *rbuf, SizeT rsize)
+{
+   /* :TODO: Ideally we would need to match the response type with the
+      previous request because response itself does not contain any
+      type identification.
+      For now simply make defined whole response buffer. */
+   POST_MEM_WRITE((Addr) rbuf, rsize);
+}
+
+/* Pre-syscall checks for params->data_ptr contents of a door_call(). */
+static void door_call_pre_mem_params_data(ThreadId tid, Int fd,
+                                          void *data_ptr, SizeT data_size)
+{
+   const HChar *pathname;
+
+   /* Get pathname of the door file descriptor, if not already done.
+      Needed to dissect door service on the pathname below. */
+   if (!VG_(clo_track_fds) && !ML_(fd_recorded)(fd)) {
+      ML_(record_fd_open_named)(tid, fd);
+   }
+   pathname = ML_(find_fd_recorded_by_fd)(fd);
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("PRE(door_call) with fd=%d and filename=%s\n",
+                  fd, pathname);
+   }
+
+   if (VG_STREQ(pathname, VKI__PATH_KCFD_DOOR)) {
+      vki_kcf_door_arg_t *p = (vki_kcf_door_arg_t *) data_ptr;
+
+      PRE_FIELD_READ("door_call(\"" VKI__PATH_KCFD_DOOR "\", "
+                     "kcf_door_arg_t->da_version)", p->da_version);
+      PRE_FIELD_READ("door_call(\"" VKI__PATH_KCFD_DOOR "\", "
+                     "kcf_door_arg_t->da_iskernel)", p->da_iskernel);
+      PRE_MEM_RASCIIZ("door_call(\"" VKI__PATH_KCFD_DOOR "\", "
+                      "kcf_door_arg_t->da_u.filename)",
+                      (Addr) p->vki_da_u.filename);
+   } else if (VG_STREQ(pathname, VKI_NAME_SERVICE_DOOR)) {
+      vki_nss_pheader_t *p = (vki_nss_pheader_t *) data_ptr;
+
+      PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                     "nss_pheader->nsc_callnumber)", p->nsc_callnumber);
+      if (ML_(safe_to_deref)(p, sizeof(vki_nss_pheader_t))) {
+         if ((p->nsc_callnumber & VKI_NSCDV2CATMASK) == VKI_NSCD_CALLCAT_APP) {
+            /* request from an application towards nscd */
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->p_version)", p->p_version);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->dbd_off)", p->dbd_off);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->dbd_len)", p->dbd_len);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->key_off)", p->key_off);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->key_len)", p->key_len);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->data_off)", p->data_off);
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->data_len)", p->data_len);
+            /* Fields ext_off and ext_len are set only sporadically. */
+            PRE_FIELD_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->pbufsiz)", p->pbufsiz);
+            PRE_MEM_WRITE("door_call(\"" VKI_NAME_SERVICE_DOOR "\", pbuf)",
+                          (Addr) p, p->pbufsiz);
+
+            if (p->dbd_len > 0) {
+               vki_nss_dbd_t *dbd
+                  = (vki_nss_dbd_t *) ((HChar *) p + p->dbd_off);
+
+               PRE_MEM_READ("door_call(\"" VKI_NAME_SERVICE_DOOR
+                            "\", nss_dbd)", (Addr) dbd, sizeof(vki_nss_dbd_t));
+               if (ML_(safe_to_deref)(dbd, sizeof(vki_nss_dbd_t))) {
+                  if (dbd->o_name != 0)
+                     PRE_MEM_RASCIIZ("door_call(\"" VKI_NAME_SERVICE_DOOR
+                                     "\", nss_dbd->o_name)", (Addr) ((HChar *) p
+                                     + p->dbd_off + dbd->o_name));
+                  if (dbd->o_config_name != 0)
+                     PRE_MEM_RASCIIZ("door_call(\"" VKI_NAME_SERVICE_DOOR
+                                     "\", nss_dbd->o_config_name)",
+                                     (Addr) ((HChar *) p + p->dbd_off
+                                     + dbd->o_config_name));
+                  if (dbd->o_default_config != 0)
+                     PRE_MEM_RASCIIZ("door_call(\"" VKI_NAME_SERVICE_DOOR
+                                     "\", nss_dbd->o_default_config)",
+                                     (Addr) ((HChar *) p + p->dbd_off +
+                                     dbd->o_default_config));
+              }
+           }
+
+           PRE_MEM_READ("door_call(\"" VKI_NAME_SERVICE_DOOR "\", nss->key)",
+                        (Addr) ((HChar *) p + p->key_off), p->key_len);
+         } else {
+            /* request from a child nscd towards parent nscd */
+            VG_(unimplemented)("Door wrapper of child/parent nscd.");
+         }
+      }
+   } else if (VG_STREQ(pathname, VKI_REPOSITORY_DOOR_NAME)) {
+      vki_repository_door_request_t *p =	
+         (vki_repository_door_request_t *) data_ptr;
+
+      PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                     "request->rdr_version)", p->rdr_version);
+      PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                     "request->rdr_request)", p->rdr_request);
+      if (ML_(safe_to_deref)(p, sizeof(vki_repository_door_request_t))) {
+         if (p->rdr_version == VKI_REPOSITORY_DOOR_VERSION) {
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "request->rdr_flags)", p->rdr_flags);
+            PRE_FIELD_READ("door_call(\"" VKI_REPOSITORY_DOOR_NAME "\", "
+                           "request->rdr_debug)", p->rdr_debug);
+         } else {
+            VG_(unimplemented)("Door wrapper of " VKI_REPOSITORY_DOOR_NAME
+                               " where version=%u.", p->rdr_version);
+         }
+      }
+   } else {
+      const OpenDoor *open_door = door_find_by_fd(fd);
+      if ((open_door != NULL) && (open_door->pre_mem_hook != NULL)) {
+         open_door->pre_mem_hook(tid, fd, data_ptr, data_size);
+      } else {
+         if (SimHintiS(SimHint_lax_doors, VG_(clo_sim_hints))) {
+            /*
+             * Be very lax about door syscall handling over unrecognized
+             * door file descriptors. Does not require that full buffer
+             * is initialized when writing. Without this, programs using
+             * libdoor(3LIB) functionality with completely proprietary
+             * semantics may report large number of false positives.
+             */
+         } else {
+            static Int moans = 3;
+
+            /* generic default */
+            if (moans > 0 && !VG_(clo_xml)) {
+               moans--;
+               VG_(umsg)(
+"Warning: noted and generically handled door call\n"
+"   on file descriptor %d (filename: %s).\n"
+"   This could cause spurious value errors to appear.\n"
+"   See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing a proper wrapper.\n"
+"   Alternatively you may find '--sim-hints=lax-doors' option useful.\n",
+                         fd, pathname);
+            }
+            PRE_MEM_READ("door_call(params->data_ptr)",
+                         (Addr) data_ptr, data_size);
+         }
+      }
+   }
+}
+
+/* Post-syscall checks for params->rbuf contents of a door_call(). */
+static void door_call_post_mem_params_rbuf(ThreadId tid, Int fd,
+                                           void *rbuf, SizeT rsize,
+                                           const vki_door_desc_t *desc_ptr,
+                                           vki_uint_t desc_num)
+{
+   const HChar *pathname = ML_(find_fd_recorded_by_fd)(fd);
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("POST(door_call) with fd=%d and filename=%s\n",
+                  fd, pathname);
+   }
+
+   if (VG_STREQ(pathname, VKI__PATH_KCFD_DOOR)) {
+      vki_kcf_door_arg_t *p = (vki_kcf_door_arg_t *) rbuf;
+
+      POST_FIELD_WRITE(p->da_version);
+      POST_FIELD_WRITE(p->vki_da_u.result.status);
+      POST_MEM_WRITE((Addr) p->vki_da_u.result.signature,
+                     p->vki_da_u.result.siglen);
+   } else if (VG_STREQ(pathname, VKI_NAME_SERVICE_DOOR)) {
+      vki_nss_pheader_t *p = (vki_nss_pheader_t *) rbuf;
+
+      POST_FIELD_WRITE(p->nsc_callnumber);
+      if (ML_(safe_to_deref)(p, sizeof(vki_nss_pheader_t))) {
+         if ((p->nsc_callnumber & VKI_NSCDV2CATMASK) == VKI_NSCD_CALLCAT_APP) {
+            /* response from nscd to an application */
+            POST_FIELD_WRITE(p->p_status);
+            POST_FIELD_WRITE(p->p_errno);
+            POST_FIELD_WRITE(p->p_herrno);
+            POST_FIELD_WRITE(p->dbd_off);
+            POST_FIELD_WRITE(p->dbd_len);
+            POST_FIELD_WRITE(p->key_off);
+            POST_FIELD_WRITE(p->key_len);
+            POST_FIELD_WRITE(p->data_off);
+            POST_FIELD_WRITE(p->data_len);
+            POST_FIELD_WRITE(p->ext_off);
+            POST_FIELD_WRITE(p->ext_len);
+            POST_FIELD_WRITE(p->pbufsiz);
+
+            if (p->pbufsiz <= rsize) {
+               if (p->dbd_off < p->pbufsiz - sizeof(vki_nss_pheader_t)) {
+                  SizeT len = MIN(p->dbd_len, p->pbufsiz - p->dbd_off);
+                  POST_MEM_WRITE((Addr) ((HChar *) p + p->dbd_off), len);
+               }
+
+               if (p->key_off < p->pbufsiz - sizeof(vki_nss_pheader_t)) {
+                  SizeT len = MIN(p->key_len, p->pbufsiz - p->key_off);
+                  POST_MEM_WRITE((Addr) ((HChar *) p + p->key_off), len);
+               }
+
+               if (p->data_off < p->pbufsiz - sizeof(vki_nss_pheader_t)) {
+                  SizeT len = MIN(p->data_len, p->pbufsiz - p->data_off);
+                  POST_MEM_WRITE((Addr) ((HChar *) p + p->data_off), len);
+               }
+
+               if (p->ext_off < p->pbufsiz - sizeof(vki_nss_pheader_t)) {
+                  SizeT len = MIN(p->ext_len, p->pbufsiz - p->ext_off);
+                  POST_MEM_WRITE((Addr) ((HChar *) p + p->ext_off), len);
+               }
+            }
+         } else {
+            /* response from parent nscd to a child nscd */
+            VG_(unimplemented)("Door wrapper of child/parent nscd.");
+         }
+      }
+   } else if (VG_STREQ(pathname, VKI_REPOSITORY_DOOR_NAME)) {
+      POST_FIELD_WRITE(((vki_repository_door_response_t *) rbuf)->rdr_status);
+      /* A new client door fd is passed over the global repository door. */
+      if ((desc_ptr != NULL) && (desc_num > 0)) {
+         if (desc_ptr[0].d_attributes & DOOR_DESCRIPTOR) {
+            door_record_client(tid, desc_ptr[0].d_data.d_desc.d_descriptor,
+                               repository_door_pre_mem_door_call_hook,
+                               repository_door_post_mem_door_call_hook);
+         }
+      }
+   } else {
+      const OpenDoor *open_door = door_find_by_fd(fd);
+      if ((open_door != NULL) && (open_door->post_mem_hook != NULL)) {
+         open_door->post_mem_hook(tid, fd, rbuf, rsize);
+      } else {
+         /* generic default */
+         POST_MEM_WRITE((Addr) rbuf, rsize);
+      }
+   }
+}
+
+/* Pre-syscall checks for data_ptr contents in a door_return(). */
+static void door_return_pre_mem_data(ThreadId tid, Addr server_procedure,
+                                     void *data_ptr, SizeT data_size)
+{
+   if ((data_size == 0) || (server_procedure == 0)) {
+      /* There is nothing to check. This usually happens during thread's
+         first call to door_return(). */
+      return;
+   }
+
+   /* Get pathname of the door file descriptor based on the
+      door server procedure (that's all we have).
+      Needed to dissect door service on the pathname below. */
+   const OpenDoor *open_door = door_find_by_proc(server_procedure);
+   const HChar *pathname = (open_door != NULL) ? open_door->pathname : NULL;
+   Int fd = (open_door != NULL) ? open_door->fd : -1;
+
+   /* Debug-only printing. */
+   if (0) {
+      VG_(printf)("PRE(door_return) with fd=%d and filename=%s "
+                  "(nr_doors_recorded=%u)\n",
+                  fd, pathname, nr_doors_recorded);
+   }
+
+   if (VG_STREQ(pathname, VKI__PATH_KCFD_DOOR)) {
+      vki_kcf_door_arg_t *p = (vki_kcf_door_arg_t *) data_ptr;
+
+      PRE_FIELD_READ("door_return(\"" VKI__PATH_KCFD_DOOR "\", "
+                     "kcf_door_arg_t->da_version)", p->da_version);
+      PRE_FIELD_READ("door_return(\"" VKI__PATH_KCFD_DOOR "\", "
+                     "kcf_door_arg_t->da_u.result.status)",
+                     p->vki_da_u.result.status);
+      PRE_MEM_READ("door_return(\"" VKI__PATH_KCFD_DOOR "\", "
+                   "kcf_door_arg_t->da_u.result.signature)",
+                   (Addr) p->vki_da_u.result.signature,
+                   p->vki_da_u.result.siglen);
+   } else if (VG_STREQ(pathname, VKI_NAME_SERVICE_DOOR)) {
+      vki_nss_pheader_t *p = (vki_nss_pheader_t *) data_ptr;
+
+      PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                     "nss_pheader->nsc_callnumber)", p->nsc_callnumber);
+      if (ML_(safe_to_deref)(p, sizeof(vki_nss_pheader_t))) {
+         if ((p->nsc_callnumber & VKI_NSCDV2CATMASK) == VKI_NSCD_CALLCAT_APP) {
+            /* response from nscd to an application */
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->p_status)", p->p_status);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->p_errno)", p->p_errno);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->p_herrno)", p->p_herrno);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->dbd_off)", p->dbd_off);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->dbd_len)", p->dbd_len);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->data_off)", p->data_off);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->data_len)", p->data_len);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->ext_off)", p->ext_off);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->ext_len)", p->ext_len);
+            PRE_FIELD_READ("door_return(\"" VKI_NAME_SERVICE_DOOR "\", "
+                           "nss_pheader->pbufsiz)", p->pbufsiz);
+            PRE_MEM_WRITE("door_return(\"" VKI_NAME_SERVICE_DOOR "\", pbuf)",
+                          (Addr) p, p->pbufsiz);
+            PRE_MEM_READ("door_return(\"" VKI_NAME_SERVICE_DOOR
+                         "\", nss->data)",
+                         (Addr) ((HChar *) p + p->data_off), p->data_len);
+            PRE_MEM_READ("door_return(\"" VKI_NAME_SERVICE_DOOR
+                         "\", nss->ext)",
+                         (Addr) ((HChar *) p + p->ext_off), p->ext_len);
+         } else {
+            /* response from parent nscd to a child nscd */
+            VG_(unimplemented)("Door wrapper of child/parent nscd.");
+         }
+      }
+   } else if (VG_STREQ(pathname, VKI_REPOSITORY_DOOR_NAME)) {
+            VG_(unimplemented)("Door wrapper of " VKI_REPOSITORY_DOOR_NAME);
+   } else {
+      if (SimHintiS(SimHint_lax_doors, VG_(clo_sim_hints))) {
+         /*
+          * Be very lax about door syscall handling over unrecognized
+          * door file descriptors. Does not require that full buffer
+          * is initialized when writing. Without this, programs using
+          * libdoor(3LIB) functionality with completely proprietary
+          * semantics may report large number of false positives.
+          */
+      } else {
+         static Int moans = 3;
+
+         /* generic default */
+         if (moans > 0 && !VG_(clo_xml)) {
+            moans--;
+            VG_(umsg)(
+"Warning: noted and generically handled door return\n"
+"   on file descriptor %d (filename: %s).\n"
+"   This could cause spurious value errors to appear.\n"
+"   See README_MISSING_SYSCALL_OR_IOCTL for guidance on writing a proper wrapper.\n"
+"   Alternatively you may find '--sim-hints=lax-doors' option useful.\n",
+                   fd, pathname);
+         }
+         PRE_MEM_READ("door_return(data_ptr)",
+                      (Addr) data_ptr, data_size);
+      }
+   }
+}
+
+/* Post-syscall checks for data_ptr contents in a door_return(). */
+static void door_return_post_mem_data(ThreadId tid, Addr server_procedure,
+                                      void *data_ptr, SizeT data_size)
+{
+   const OpenDoor *open_door = door_find_by_proc(server_procedure);
+   const HChar *pathname = (open_door != NULL) ? open_door->pathname : NULL;
+
+   /* Debug-only printing. */
+   if (0) {
+      Int fd = (open_door != NULL) ? open_door->fd : -1;
+      VG_(printf)("POST(door_return) with fd=%d and filename=%s "
+                  "(nr_doors_recorded=%u)\n",
+                  fd, pathname, nr_doors_recorded);
+   }
+
+   if (VG_STREQ(pathname, VKI__PATH_KCFD_DOOR)) {
+      vki_kcf_door_arg_t *p = (vki_kcf_door_arg_t *) data_ptr;
+
+      POST_FIELD_WRITE(p->da_version);
+      POST_FIELD_WRITE(p->da_iskernel);
+      POST_MEM_WRITE((Addr) p->vki_da_u.filename,
+                     VG_(strlen)(p->vki_da_u.filename) + 1);
+   } else if (VG_STREQ(pathname, VKI_NAME_SERVICE_DOOR)) {
+      vki_nss_pheader_t *p = (vki_nss_pheader_t *) data_ptr;
+
+      POST_FIELD_WRITE(p->nsc_callnumber);
+      if (ML_(safe_to_deref)(p, sizeof(vki_nss_pheader_t))) {
+         if ((p->nsc_callnumber & VKI_NSCDV2CATMASK) == VKI_NSCD_CALLCAT_APP) {
+            /* request from an application towards nscd */
+            POST_FIELD_WRITE(p->p_version);
+            POST_FIELD_WRITE(p->dbd_off);
+            POST_FIELD_WRITE(p->dbd_len);
+            POST_FIELD_WRITE(p->key_off);
+            POST_FIELD_WRITE(p->key_len);
+            POST_FIELD_WRITE(p->data_off);
+            POST_FIELD_WRITE(p->data_len);
+            POST_FIELD_WRITE(p->ext_off);
+            POST_FIELD_WRITE(p->ext_len);
+            POST_FIELD_WRITE(p->pbufsiz);
+
+            if (p->dbd_len > 0) {
+               vki_nss_dbd_t *dbd
+                  = (vki_nss_dbd_t *) ((HChar *) p + p->dbd_off);
+
+               POST_MEM_WRITE((Addr) dbd, sizeof(vki_nss_dbd_t));
+               if (ML_(safe_to_deref)(dbd, sizeof(vki_nss_dbd_t))) {
+                  SizeT headers_size = sizeof(vki_nss_pheader_t)
+                     + sizeof(vki_nss_dbd_t);
+
+                  if (dbd->o_name != 0) {
+                     HChar *name = (HChar *) p + p->dbd_off + dbd->o_name;
+                     SizeT name_len = VG_(strlen)(name) + 1;
+                     if (name_len <= data_size - headers_size)
+                        POST_MEM_WRITE((Addr) name, name_len);
+                  }
+                  if (dbd->o_config_name != 0) {
+                     HChar *name = (HChar *) p + p->dbd_off + dbd->o_config_name;
+                     SizeT name_len = VG_(strlen)(name) + 1;
+                     if (name_len <= data_size - headers_size)
+                        POST_MEM_WRITE((Addr) name, name_len);
+                  }
+                  if (dbd->o_default_config != 0) {
+                     HChar *name = (HChar *) p + p->dbd_off
+                        + dbd->o_default_config;
+                     SizeT name_len = VG_(strlen)(name) + 1;
+                     if (name_len <= data_size - headers_size)
+                        POST_MEM_WRITE((Addr) name, name_len);
+                  }
+              }
+           }
+
+           if (p->key_len <= data_size - p->key_off)
+              POST_MEM_WRITE((Addr) ((HChar *) p + p->key_off), p->key_len);
+         } else {
+            /* request from a child nscd towards parent nscd */
+            VG_(unimplemented)("Door wrapper of child/parent nscd.");
+         }
+      }
+   } else if (VG_STREQ(pathname, VKI_REPOSITORY_DOOR_NAME)) {
+            VG_(unimplemented)("Door wrapper of " VKI_REPOSITORY_DOOR_NAME);
+   } else {
+      /* generic default */
+      POST_MEM_WRITE((Addr) data_ptr, data_size);
+   }
+}
+
+PRE(sys_door)
+{
+   /* int doorfs(long arg1, long arg2, long arg3, long arg4, long arg5,
+                 long subcode); */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   *flags |= SfMayBlock | SfPostOnFail;
+
+   PRINT("sys_door ( %#lx, %#lx, %#lx, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3,
+         ARG4, ARG5, ARG6);
+
+   /* Macro PRE_REG_READ6 cannot be simply used because not all ARGs are used
+      in door() syscall variants. Note that ARG6 (subcode) is used always. */
+#define PRE_REG_READ_SIXTH_ONLY         \
+   if (VG_(tdict).track_pre_reg_read) { \
+      PRA6("door", long, subcode);      \
+   }
+
+   switch (ARG6 /*subcode*/) {
+   case VKI_DOOR_CREATE:
+      PRE_REG_READ3(long, "door", long, arg1, long, arg2, long, arg3);
+      PRE_REG_READ_SIXTH_ONLY;
+      /* Note: the first argument to DOOR_CREATE is a server procedure.
+         This could lead to a problem if the kernel tries to force the
+         execution of this procedure, similarly to how signal handlers are
+         executed.   Fortunately, the kernel never does that (for user-space
+         server procedures).  The procedure is always executed by the standard
+         library. */
+      break;
+   case VKI_DOOR_REVOKE:
+      PRE_REG_READ1(long, "door", long, arg1);
+      PRE_REG_READ_SIXTH_ONLY;
+      if (!ML_(fd_allowed)(ARG1, "door_revoke", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      break;
+   case VKI_DOOR_INFO:
+      PRE_REG_READ2(long, "door", long, arg1, long, arg2);
+      PRE_REG_READ_SIXTH_ONLY;
+      PRE_MEM_WRITE("door_info(info)", ARG2, sizeof(vki_door_info_t));
+      break;
+   case VKI_DOOR_CALL:
+      {
+         PRE_REG_READ2(long, "door", long, arg1, long, arg2);
+         PRE_REG_READ_SIXTH_ONLY;
+
+         Int rval = 0;
+         vki_door_arg_t *params = (vki_door_arg_t*)ARG2;
+
+         if (!ML_(fd_allowed)(ARG1, "door_call", tid, False))
+            rval = VKI_EBADF;
+
+         PRE_FIELD_READ("door_call(params->data_ptr)", params->data_ptr);
+         PRE_FIELD_READ("door_call(params->data_size)", params->data_size);
+         PRE_FIELD_READ("door_call(params->desc_ptr)", params->desc_ptr);
+         PRE_FIELD_READ("door_call(params->desc_num)", params->desc_num);
+         PRE_FIELD_READ("door_call(params->rbuf)", params->rbuf);
+         PRE_FIELD_READ("door_call(params->rsize)", params->rsize);
+
+         if (ML_(safe_to_deref)(params, sizeof(*params))) {
+            if (params->data_ptr)
+               door_call_pre_mem_params_data(tid, ARG1, params->data_ptr,
+                                             params->data_size);
+
+            if (params->desc_ptr) {
+               SizeT desc_size = params->desc_num * sizeof(*params->desc_ptr);
+               PRE_MEM_READ("door_call(params->desc_ptr)",
+                            (Addr)params->desc_ptr, desc_size);
+
+               /* Do not record information about closed fds if we are going
+                  to fail the syscall and so no fds will be closed. */
+               if ((rval == 0) &&
+                   (ML_(safe_to_deref)(params->desc_ptr, desc_size))) {
+                     rval = pre_check_and_close_fds(tid, "door_call",
+                                                    params->desc_ptr,
+                                                    params->desc_num);
+               }
+            }
+
+            if (params->rbuf)
+               PRE_MEM_WRITE("door_call(params->rbuf)", (Addr)params->rbuf,
+                             params->rsize);
+         }
+
+         if (rval)
+            SET_STATUS_Failure(rval);
+      }
+      break;
+   case VKI_DOOR_BIND:
+      PRE_REG_READ1(long, "door", long, arg1);
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_BIND");
+      break;
+   case VKI_DOOR_UNBIND:
+      PRE_REG_READ0(long, "door");
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_UNBIND");
+      break;
+   case VKI_DOOR_UNREFSYS:
+      PRE_REG_READ0(long, "door");
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_UNREFSYS");
+      break;
+   case VKI_DOOR_UCRED:
+      PRE_REG_READ1(long, "door", long, arg1);
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_UCRED");
+      break;
+   case VKI_DOOR_RETURN:
+      PRE_REG_READ6(long, "door", long, arg1, long, arg2, long, arg3,
+                    long, arg4, long, arg5, long, subcode);
+
+      /* Register %esp/%rsp is read and modified by the syscall. */
+      VG_TRACK(pre_reg_read, Vg_CoreSysCall, tid, "door_return(sp)",
+               VG_O_STACK_PTR, sizeof(UWord));
+      /* Register %ebp/%rbp is not really read by the syscall, it is only
+         written by it, but it is hard to determine when it is written so we
+         make sure it is always valid prior to making the syscall. */
+      VG_TRACK(pre_reg_read, Vg_CoreSysCall, tid, "door_return(bp)",
+               VG_O_FRAME_PTR, sizeof(UWord));
+
+      door_return_pre_mem_data(tid, tst->os_state.door_return_procedure,
+                               (void *) ARG1, ARG2);
+
+      /* Do not tell the tool where the syscall is going to write the
+         resulting data.  It is necessary to skip this check because the data
+         area starting at ARG4-ARG5 (of length ARG5) is usually on a client
+         thread stack below the stack pointer and therefore it can be marked
+         by a tool (for example, Memcheck) as inaccessible.  It is ok to skip
+         this check in this case because if there is something wrong with the
+         data area then the syscall will fail or the error will be handled by
+         POST_MEM_WRITE() in the post wrapper. */
+      /*PRE_MEM_WRITE("door_return(sp)", ARG4 - ARG5, ARG5);*/
+
+      if (ARG3) {
+         vki_door_return_desc_t *desc_env = (vki_door_return_desc_t*)ARG3;
+
+         PRE_MEM_READ("door_return(desc_env)", ARG3,
+                      sizeof(vki_door_return_desc_t));
+
+         if (ML_(safe_to_deref)(desc_env, sizeof(*desc_env)) &&
+             desc_env->desc_ptr) {
+            Int rval;
+
+            PRE_MEM_READ("door_return(desc_env->desc_ptr)",
+                         (Addr)desc_env->desc_ptr,
+                         desc_env->desc_num * sizeof(*desc_env->desc_ptr));
+
+            rval = pre_check_and_close_fds(tid, "door_return",
+                                           desc_env->desc_ptr,
+                                           desc_env->desc_num);
+            if (rval)
+               SET_STATUS_Failure(rval);
+         }
+      }
+      tst->os_state.in_door_return = True;
+      tst->os_state.door_return_procedure = 0;
+      break;
+   case VKI_DOOR_GETPARAM:
+      PRE_REG_READ3(long, "door", long, arg1, long, arg2, long, arg3);
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_GETPARAM");
+      break;
+   case VKI_DOOR_SETPARAM:
+      PRE_REG_READ3(long, "door", long, arg1, long, arg2, long, arg3);
+      PRE_REG_READ_SIXTH_ONLY;
+      VG_(unimplemented)("DOOR_SETPARAM");
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the door call with subcode %ld.", ARG6);
+      /*NOTREACHED*/
+      break;
+   }
+
+#undef PRE_REG_READ_SIXTH_ONLY
+}
+
+POST(sys_door)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+
+   vg_assert(SUCCESS || FAILURE);
+
+   /* Alter the tst->os_state.in_door_return flag. */
+   if (ARG6 == VKI_DOOR_RETURN) {
+      vg_assert(tst->os_state.in_door_return == True);
+      tst->os_state.in_door_return = False;
+
+      /* Inform the tool that %esp/%rsp and %ebp/%rbp were (potentially)
+         modified. */
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, VG_O_STACK_PTR,
+               sizeof(UWord));
+      VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, VG_O_FRAME_PTR,
+               sizeof(UWord));
+   }
+   else
+      vg_assert(tst->os_state.in_door_return == False);
+
+   if (FAILURE) {
+      if (VG_(clo_track_fds)) {
+         /* See the discussion in pre_check_and_close_fds() to understand this
+            part. */
+         Bool loss = False;
+         switch (ARG6 /*subcode*/) {
+         case VKI_DOOR_CALL:
+            if (ERR == VKI_EFAULT || ERR == VKI_EBADF)
+               loss = True;
+            break;
+         case VKI_DOOR_RETURN:
+            if (ERR == VKI_EFAULT || ERR == VKI_EINVAL)
+               loss = True;
+            break;
+         default:
+            break;
+         }
+         if (loss)
+            VG_(message)(Vg_UserMsg, "The door call failed with an "
+                                     "unexpected error and information "
+                                     "about open file descriptors can be "
+                                     "now imprecise.\n");
+      }
+
+      return;
+   }
+
+   vg_assert(SUCCESS);
+
+   switch (ARG6 /*subcode*/) {
+   case VKI_DOOR_CREATE:
+      door_record_server(tid, ARG1, RES);
+      break;
+   case VKI_DOOR_REVOKE:
+      door_revoke(tid, ARG1);
+      if (VG_(clo_track_fds))
+         ML_(record_fd_close)(ARG1);
+      break;
+   case VKI_DOOR_INFO:
+      POST_MEM_WRITE(ARG2, sizeof(vki_door_info_t));
+      break;
+   case VKI_DOOR_CALL:
+      {
+         /* Note that all returned values are stored in the rbuf, i.e.
+            data_ptr and desc_ptr points into this buffer. */
+         vki_door_arg_t *params = (vki_door_arg_t*)ARG2;
+
+         if (params->rbuf) {
+            Addr addr = (Addr)params->rbuf;
+            if (!VG_(am_find_anon_segment(addr))) {
+               /* This segment is new and was mapped by the kernel. */
+               UInt prot, flags;
+               SizeT size;
+
+               prot = VKI_PROT_READ | VKI_PROT_WRITE | VKI_PROT_EXEC;
+               flags = VKI_MAP_ANONYMOUS;
+               size = VG_PGROUNDUP(params->rsize);
+
+               VG_(debugLog)(1, "syswrap-solaris", "POST(sys_door), "
+                                "new segment: vaddr=%#lx, size=%#lx, "
+                                "prot=%#x, flags=%#x, fd=%ld, offset=%#llx\n",
+                                addr, size, prot, flags, (UWord)-1, (ULong)0);
+
+               ML_(notify_core_and_tool_of_mmap)(addr, size, prot, flags,
+                                                 -1, 0);
+
+               /* Note: We don't notify the debuginfo reader about this
+                  mapping because there are no debug information stored in
+                  this segment. */
+            }
+
+            door_call_post_mem_params_rbuf(tid, ARG1, (void *) addr,
+                                           params->rsize, params->desc_ptr,
+                                           params->desc_num);
+         }
+
+         if (params->desc_ptr) {
+            POST_MEM_WRITE((Addr)params->desc_ptr,
+                           params->desc_num * sizeof(vki_door_desc_t));
+            post_record_fds(tid, "door_call", params->desc_ptr,
+                            params->desc_num);
+         }
+      }
+      break;
+   case VKI_DOOR_BIND:
+      break;
+   case VKI_DOOR_UNBIND:
+      break;
+   case VKI_DOOR_UNREFSYS:
+      break;
+   case VKI_DOOR_UCRED:
+      break;
+   case VKI_DOOR_RETURN:
+      {
+         struct vki_door_results *results
+            = (struct vki_door_results*)VG_(get_SP)(tid);
+
+         tst->os_state.door_return_procedure = (Addr)results->pc;
+
+         POST_MEM_WRITE((Addr)results, sizeof(*results));
+         if (results->data_ptr)
+            door_return_post_mem_data(tid,
+                                      tst->os_state.door_return_procedure,
+                                      results->data_ptr,
+                                      results->data_size);
+         if (results->desc_ptr) {
+            POST_MEM_WRITE((Addr)results->desc_ptr,
+                           results->desc_num * sizeof(vki_door_desc_t));
+            post_record_fds(tid, "door_return", results->desc_ptr,
+                            results->desc_num);
+         }
+
+         POST_MEM_WRITE((Addr)results->door_info,
+                        sizeof(*results->door_info));
+      }
+      break;
+   case VKI_DOOR_GETPARAM:
+      break;
+   case VKI_DOOR_SETPARAM:
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_schedctl)
+{
+   /* caddr_t schedctl(void); */
+   /* This syscall returns an address that points to struct sc_shared.
+      This per-thread structure is used as an interface between the libc and
+      the kernel. */
+   PRINT("sys_schedctl ( )");
+   PRE_REG_READ0(long, "schedctl");
+}
+
+POST(sys_schedctl)
+{
+   Addr a = RES;
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+
+   /* Stay sane. */
+   vg_assert((tst->os_state.schedctl_data == 0) ||
+             (tst->os_state.schedctl_data == a));
+   tst->os_state.schedctl_data = a;
+
+   /* Returned address points to a block in a mapped page. */
+   if (!VG_(am_find_anon_segment(a))) {
+      Addr page = VG_PGROUNDDN(a);
+      UInt prot = VKI_PROT_READ | VKI_PROT_WRITE | VKI_PROT_EXEC;
+      UInt flags = VKI_MAP_ANONYMOUS;
+      /* The kernel always allocates one page for the sc_shared struct. */
+      SizeT size = VKI_PAGE_SIZE;
+
+      VG_(debugLog)(1, "syswrap-solaris", "POST(sys_schedctl), new segment: "
+                    "vaddr=%#lx, size=%#lx, prot=%#x, flags=%#x, fd=-1, "
+                    "offset=0\n", page, size, prot, flags);
+
+      /* The kernel always places redzone before and after the allocated page.
+         Check this assertion now; the tool can later request to allocate
+         a Valgrind segment and aspacemgr will place it adjacent. */
+      const NSegment *seg = VG_(am_find_nsegment(page - 1));
+      vg_assert(seg == NULL || seg->kind == SkResvn);
+      seg = VG_(am_find_nsegment(page + VKI_PAGE_SIZE));
+      vg_assert(seg == NULL || seg->kind == SkResvn);
+
+      /* The address space manager works with whole pages. */
+      VG_(am_notify_client_mmap)(page, size, prot, flags, -1, 0);
+
+      /* Note: It isn't needed to notify debuginfo about the new mapping
+         because it's only an anonymous mapping. */
+      /* Note: schedctl data are cleaned in two places:
+         - for the tool when the thread exits
+         - for the core in child's post-fork handler clean_schedctl_data(). */
+   }
+
+   /* The tool needs per-thread granularity, not whole pages. */
+   VG_TRACK(new_mem_mmap, a, sizeof(struct vki_sc_shared), True, True, True, 0);
+   POST_MEM_WRITE(a, sizeof(struct vki_sc_shared));
+}
+
+PRE(sys_resolvepath)
+{
+   /* int resolvepath(const char *path, char *buf, size_t bufsiz); */
+   PRINT("sys_resolvepath ( %#lx(%s), %#lx, %lu )", ARG1, (HChar *) ARG1, ARG2,
+         ARG3);
+   PRE_REG_READ3(long, "resolvepath", const char *, path, char *, buf,
+                 vki_size_t, bufsiz);
+
+   PRE_MEM_RASCIIZ("resolvepath(path)", ARG1);
+   PRE_MEM_WRITE("resolvepath(buf)", ARG2, ARG3);
+}
+
+POST(sys_resolvepath)
+{
+   POST_MEM_WRITE(ARG2, RES);
+}
+
+PRE(sys_lwp_mutex_timedlock)
+{
+   /* int lwp_mutex_timedlock(lwp_mutex_t *lp, timespec_t *tsp,
+                              uintptr_t owner); */
+   vki_lwp_mutex_t *lp = (vki_lwp_mutex_t *)ARG1;
+   *flags |= SfMayBlock;
+   PRINT("lwp_mutex_timedlock ( %#lx, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "lwp_mutex_timedlock", lwp_mutex_t *, lp,
+                 timespec_t *, tsp, uintptr_t, owner);
+
+   PRE_FIELD_READ("lwp_mutex_timedlock(lp->mutex_flag)", lp->vki_mutex_flag);
+   PRE_FIELD_READ("lwp_mutex_timedlock(lp->mutex_type)", lp->vki_mutex_type);
+   PRE_FIELD_WRITE("lwp_mutex_timedlock(lp->mutex_owner)",
+                   lp->vki_mutex_owner);
+   PRE_FIELD_WRITE("lwp_mutex_timedlock(lp->mutex_ownerpid)",
+                   lp->vki_mutex_ownerpid);
+   PRE_FIELD_READ("lwp_mutex_timedlock(lp->mutex_lockw)", lp->vki_mutex_lockw);
+   /*PRE_FIELD_WRITE("lwp_mutex_timedlock(lp->mutex_lockw)",
+                     lp->vki_mutex_lockw);*/
+   PRE_FIELD_READ("lwp_mutex_timedlock(lp->mutex_waiters)",
+                  lp->vki_mutex_waiters);
+   /*PRE_FIELD_WRITE("lwp_mutex_timedlock(lp->mutex_waiters)",
+                     lp->vki_mutex_waiters);*/
+   if (ARG2) {
+      PRE_MEM_READ("lwp_mutex_timedlock(tsp)", ARG2, sizeof(vki_timespec_t));
+      /*PRE_MEM_WRITE("lwp_mutex_timedlock(tsp)", ARG2,
+                      sizeof(vki_timespec_t));*/
+   }
+}
+
+POST(sys_lwp_mutex_timedlock)
+{
+   vki_lwp_mutex_t *lp = (vki_lwp_mutex_t *)ARG1;
+   POST_FIELD_WRITE(lp->vki_mutex_owner);
+   POST_FIELD_WRITE(lp->vki_mutex_ownerpid);
+   POST_FIELD_WRITE(lp->vki_mutex_lockw);
+   POST_FIELD_WRITE(lp->vki_mutex_waiters);
+   if (ARG2)
+      POST_MEM_WRITE(ARG2, sizeof(vki_timespec_t));
+}
+
+PRE(sys_lwp_rwlock_sys)
+{
+   /* int lwp_rwlock_sys(int subcode, lwp_rwlock_t *rwlp, timespec_t *tsp); */
+   vki_lwp_rwlock_t *rwlp = (vki_lwp_rwlock_t *)ARG2;
+   switch (ARG1 /*subcode*/) {
+   case 0:
+   case 1:
+   case 2:
+   case 3:
+      *flags |= SfMayBlock;
+      switch (ARG1 /*subcode*/) {
+      case 0:
+         PRINT("sys_lwp_rwlock ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+         PRE_REG_READ3(long, SC2("lwp_rwlock", "rdlock"), int, subcode,
+                       lwp_rwlock_t *, rwlp, timespec_t *, tsp);
+         break;
+      case 1:
+         PRINT("sys_lwp_rwlock ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+         PRE_REG_READ3(long, SC2("lwp_rwlock", "wrlock"), int, subcode,
+                       lwp_rwlock_t *, rwlp, timespec_t *, tsp);
+         break;
+      case 2:
+         PRINT("sys_lwp_rwlock ( %ld, %#lx )", ARG1, ARG2);
+         PRE_REG_READ2(long, SC2("lwp_rwlock", "tryrdlock"), int, subcode,
+                       lwp_rwlock_t *, rwlp);
+         break;
+      case 3:
+         PRINT("sys_lwp_rwlock ( %ld, %#lx )", ARG1, ARG2);
+         PRE_REG_READ2(long, SC2("lwp_rwlock", "trywrlock"), int, subcode,
+                       lwp_rwlock_t *, rwlp);
+         break;
+      default:
+         vg_assert(0);
+         break;
+      }
+
+      PRE_FIELD_READ("lwp_rwlock(rwlp->rwlock_type)", rwlp->vki_rwlock_type);
+      PRE_FIELD_READ("lwp_rwlock(rwlp->rwlock_readers)",
+                     rwlp->vki_rwlock_readers);
+      /*PRE_FIELD_WRITE("lwp_rwlock(rwlp->rwlock_readers)",
+                        rwlp->vki_rwlock_readers);*/
+
+      PRE_FIELD_READ("lwp_rwlock(rwlp->mutex.mutex_type)",
+                     rwlp->mutex.vki_mutex_type);
+      PRE_FIELD_WRITE("lwp_rwlock(rwlp->mutex.mutex_owner)",
+                      rwlp->mutex.vki_mutex_owner);
+      PRE_FIELD_WRITE("lwp_rwlock(rwlp->mutex.mutex_ownerpid)",
+                      rwlp->mutex.vki_mutex_ownerpid);
+      /* The mutex_lockw member is not really read by the kernel for this
+         syscall but it seems better to mark it that way because when locking
+         an rwlock the associated mutex has to be locked. */
+      PRE_FIELD_READ("lwp_rwlock(rwlp->mutex.mutex_lockw)",
+                     rwlp->mutex.vki_mutex_lockw);
+      /*PRE_FIELD_WRITE("lwp_rwlock(rwlp->mutex.mutex_lockw)",
+                        rwlp->mutex.vki_mutex_lockw);*/
+      PRE_FIELD_READ("lwp_rwlock(rwlp->mutex.mutex_waiters)",
+                     rwlp->mutex.vki_mutex_waiters);
+      /*PRE_FIELD_WRITE("lwp_rwlock(rwlp->mutex.mutex_waiters)",
+                        rwlp->mutex.vki_mutex_waiters);*/
+
+      if ((ARG1 == 0 || ARG1 == 1) && ARG3)
+         PRE_MEM_READ("lwp_rwlock(tsp)", ARG3, sizeof(vki_timespec_t));
+      break;
+   case 4:
+      PRINT("sys_lwp_rwlock( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("lwp_rwlock", "unlock"), int, subcode,
+                    lwp_rwlock_t *, rwlp);
+      PRE_FIELD_READ("lwp_rwlock(rwlp->mutex.mutex_type)",
+                     rwlp->mutex.vki_mutex_type);
+      PRE_FIELD_READ("lwp_rwlock(rwlp->rwlock_readers)",
+                     rwlp->vki_rwlock_readers);
+      /*PRE_FIELD_WRITE("lwp_rwlock(rwlp->rwlock_readers)",
+                        rwlp->vki_rwlock_readers);*/
+      break;
+   default:
+      VG_(unimplemented)("Syswrap of the lwp_rwlock_sys call with subcode %ld.",
+                         ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+}
+
+POST(sys_lwp_rwlock_sys)
+{
+   vki_lwp_rwlock_t *rwlp = (vki_lwp_rwlock_t *)ARG2;
+   switch (ARG1 /*subcode*/) {
+   case 0:
+   case 1:
+   case 2:
+   case 3:
+      POST_FIELD_WRITE(rwlp->vki_rwlock_readers);
+      POST_FIELD_WRITE(rwlp->vki_rwlock_owner);
+      POST_FIELD_WRITE(rwlp->vki_rwlock_ownerpid);
+      POST_FIELD_WRITE(rwlp->mutex.vki_mutex_lockw);
+      POST_FIELD_WRITE(rwlp->mutex.vki_mutex_waiters);
+      break;
+   case 4:
+      POST_FIELD_WRITE(rwlp->vki_rwlock_readers);
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_lwp_sema_timedwait)
+{
+   /* int lwp_sema_timedwait(lwp_sema_t *sema, timespec_t *timeout,
+                             int check_park); */
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   *flags |= SfMayBlock;
+   PRINT("sys_lwp_sema_timewait ( %#lx, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "lwp_sema_timedwait", lwp_sema_t *, sema,
+                 timespec_t *, timeout, int, check_park);
+
+   PRE_FIELD_READ("lwp_sema_timedwait(sema->type)", sema->vki_sema_type);
+   PRE_FIELD_READ("lwp_sema_timedwait(sema->count)", sema->vki_sema_count);
+   /*PRE_FIELD_WRITE("lwp_sema_timedwait(sema->count)",
+                     sema->vki_sema_count);*/
+   PRE_FIELD_READ("lwp_sema_timedwait(sema->waiters)", sema->vki_sema_waiters);
+   /*PRE_FIELD_WRITE("lwp_sema_timedwait(sema->waiters)",
+                     sema->vki_sema_waiters);*/
+   if (ARG2) {
+      PRE_MEM_READ("lwp_sema_timedwait(timeout)", ARG2,
+                   sizeof(vki_timespec_t));
+      /*PRE_MEM_WRITE("lwp_sema_timedwait(timeout)", ARG2,
+                      sizeof(vki_timespec_t));*/
+   }
+}
+
+POST(sys_lwp_sema_timedwait)
+{
+   vki_lwp_sema_t *sema = (vki_lwp_sema_t*)ARG1;
+   POST_FIELD_WRITE(sema->vki_sema_count);
+   POST_FIELD_WRITE(sema->vki_sema_waiters);
+   if (ARG2)
+      POST_MEM_WRITE(ARG2, sizeof(vki_timespec_t));
+}
+
+PRE(sys_zone)
+{
+   /* Kernel: long zone(int cmd, void *arg1, void *arg2, void *arg3,
+                        void *arg4);
+    */
+   switch (ARG1 /*cmd*/) {
+   case VKI_ZONE_CREATE:
+      /* Libc: zoneid_t zone_create(const char *name, const char *root,
+                                    const struct priv_set *privs,
+                                    const char *rctls, size_t rctlsz,
+                                    const char *zfs, size_t zfssz,
+                                    int *extended_error, int match,
+                                    int doi, const bslabel_t *label,
+                                    int flags);
+        Kernel: zoneid_t zone_create(zone_def *zd);
+       */
+      PRINT("sys_zone ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "create"), int, cmd,
+                    vki_zone_def *, zd);
+
+      vki_zone_def *zd = (vki_zone_def *) ARG2;
+      PRE_FIELD_READ("zone(zd.zone_name)", zd->zone_name);
+      PRE_FIELD_READ("zone(zd.zone_root)", zd->zone_root);
+      PRE_FIELD_READ("zone(zd.zone_privs)", zd->zone_privs);
+      PRE_FIELD_READ("zone(zd.zone_privssz)", zd->zone_privssz);
+      PRE_FIELD_READ("zone(zd.rctlbuf)", zd->rctlbuf);
+      PRE_FIELD_READ("zone(zd.rctlbufsz)", zd->rctlbufsz);
+      PRE_FIELD_READ("zone(zd.zfsbuf)", zd->zfsbuf);
+      PRE_FIELD_READ("zone(zd.zfsbufsz)", zd->zfsbufsz);
+      PRE_FIELD_READ("zone(zd.extended_error)", zd->extended_error);
+      PRE_FIELD_READ("zone(zd.match)", zd->match);
+      PRE_FIELD_READ("zone(zd.doi)", zd->doi);
+      PRE_FIELD_READ("zone(zd.label)", zd->label);
+      PRE_FIELD_READ("zone(zd.flags)", zd->flags);
+
+      if (ML_(safe_to_deref((void *)ARG2, sizeof(vki_zone_def)))) {
+         if (zd->zone_name)
+            PRE_MEM_RASCIIZ("zone(zd.zone_name)", (Addr) zd->zone_name);
+         if (zd->zone_root)
+            PRE_MEM_RASCIIZ("zone(zd.zone_root)", (Addr) zd->zone_root);
+         PRE_MEM_READ("zone(zd.zone_privs)", (Addr) zd->zone_privs,
+                      zd->zone_privssz);
+         PRE_MEM_READ("zone(zd.rctlbuf)", (Addr) zd->rctlbuf,
+                      zd->rctlbufsz);
+         PRE_MEM_READ("zone(zd.zfsbuf)",
+                      (Addr) zd->zfsbuf, zd->zfsbufsz);
+         if (zd->label)
+            PRE_MEM_READ("zone(zd.label)", (Addr) zd->label,
+                         sizeof(vki_bslabel_t));
+      }
+      break;
+   case VKI_ZONE_DESTROY:
+      /* Libc: int zone_destroy(zoneid_t zoneid); */
+      PRINT("sys_zone ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "destroy"), int, cmd,
+                    vki_zoneid_t, zoneid);
+      break;
+   case VKI_ZONE_GETATTR:
+      /* Libc: ssize_t zone_getattr(zoneid_t zoneid, int attr,
+                                    void *valp, size_t size);
+       */
+      PRINT("sys_zone ( %ld, %ld, %ld, %#lx, %ld )",
+            ARG1, ARG2, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("zone", "getattr"), int, cmd,
+                    vki_zoneid_t, zoneid, int, attr, void *, valp,
+                    vki_size_t, size);
+      PRE_MEM_WRITE("zone(valp)", ARG4, ARG5);
+      break;
+   case VKI_ZONE_ENTER:
+      /* Libc: int zone_enter(zoneid_t zoneid); */
+      PRINT("sys_zone ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "enter"), int, cmd,
+                    vki_zoneid_t, zoneid);
+      break;
+   case VKI_ZONE_LIST:
+      /* Libc: int zone_list(zoneid_t *zonelist, uint_t *numzones); */
+      PRINT("sys_zone ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("zone", "list"), int, cmd,
+                    vki_zoneid_t *, zonelist, vki_uint_t *, numzones);
+
+      PRE_MEM_WRITE("zone(numzones)", ARG3, sizeof(vki_uint_t));
+
+      if (ML_(safe_to_deref((void *) ARG3, sizeof(vki_uint_t)))) {
+         if (ARG2)
+            PRE_MEM_WRITE("zone(zonelist)", ARG2,
+                          *(vki_uint_t *) ARG3 * sizeof(vki_zoneid_t));
+      }
+      break;
+   case VKI_ZONE_SHUTDOWN:
+      /* Libc: int zone_shutdown(zoneid_t zoneid); */
+      PRINT("sys_zone ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "shutdown"), int, cmd,
+                    vki_zoneid_t, zoneid);
+      break;
+   case VKI_ZONE_LOOKUP:
+      /* Libc: zoneid_t zone_lookup(const char *name); */
+      PRINT("sys_zone ( %ld, %#lx )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "lookup"), int, cmd,
+                    const char *, name);
+      if (ARG2)
+         PRE_MEM_RASCIIZ("zone(name)", ARG2);
+      break;
+   case VKI_ZONE_BOOT:
+      /* Libc: int zone_boot(zoneid_t zoneid); */
+      PRINT("sys_zone ( %ld, %ld )", ARG1, ARG2);
+      PRE_REG_READ2(long, SC2("zone", "boot"), int, cmd,
+                    vki_zoneid_t, zoneid);
+      break;
+   case VKI_ZONE_SETATTR:
+      /* Libc: int zone_setattr(zoneid_t zoneid, int attr, void *valp,
+                                size_t size);
+       */
+      PRINT("sys_zone ( %ld, %ld, %ld, %#lx, %ld )",
+            ARG1, ARG2, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("zone", "setattr"), int, cmd,
+                    vki_zoneid_t, zoneid, int, attr, void *, valp,
+                    vki_size_t, size);
+      PRE_MEM_READ("zone(valp)", ARG4, ARG5);
+      break;
+   case VKI_ZONE_ADD_DATALINK:
+      /* Libc: int zone_add_datalink(zoneid_t zoneid,
+                                     datalink_id_t linkid);
+       */
+      PRINT("sys_zone ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("zone", "add_datalink"), int, cmd,
+                    vki_zoneid_t, zoneid, vki_datalink_id_t, linkid);
+      break;
+   case VKI_ZONE_DEL_DATALINK:
+      /* Libc: int zone_remove_datalink(zoneid_t zoneid,
+                                        datalink_id_t linkid);
+       */
+      PRINT("sys_zone ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("zone", "del_datalink"), int, cmd,
+                    vki_zoneid_t, zoneid, vki_datalink_id_t, linkid);
+      break;
+   case VKI_ZONE_CHECK_DATALINK:
+      /* Libc: int zone_check_datalink(zoneid_t *zoneidp,
+                                       datalink_id_t linkid);
+      */
+      PRINT("sys_zone ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("zone", "check_datalink"), int, cmd,
+                    vki_zoneid_t *, zoneidp, vki_datalink_id_t, linkid);
+      PRE_MEM_WRITE("zone(zoneidp)", ARG2, sizeof(vki_zoneid_t));
+      break;
+   case VKI_ZONE_LIST_DATALINK:
+      /* Libc: int zone_list_datalink(zoneid_t zoneid, int *dlnump,
+                                      datalink_id_t *linkids);
+       */
+      PRINT("sys_zone ( %ld, %ld, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, SC2("zone", "list_datalink"), int, cmd,
+                    vki_zoneid_t, zoneid, int *, dlnump,
+                    vki_datalink_id_t *, linkids);
+
+      PRE_MEM_WRITE("zone(dlnump)", ARG3, sizeof(int));
+      if (ML_(safe_to_deref((void *) ARG3, sizeof(int)))) {
+         if (ARG4)
+            PRE_MEM_WRITE("zone(linkids)", ARG4,
+                          *(int *) ARG3 * sizeof(vki_datalink_id_t));
+      }
+      break;
+#if defined(SOLARIS_ZONE_DEFUNCT)
+   case VKI_ZONE_LIST_DEFUNCT:
+      /* Libc: int zone_list_defunct(uint64_t *uniqidlist,
+                                     uint_t *numzones);
+       */
+      PRINT("sys_zone ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+      PRE_REG_READ3(long, SC2("zone", "list_defunct"), int, cmd,
+                    vki_uint64_t *, uniqidlist, vki_uint_t *, numzones);
+
+      PRE_MEM_WRITE("zone(numzones)", ARG3, sizeof(vki_uint_t));
+
+      if (ML_(safe_to_deref((void *) ARG3, sizeof(vki_uint_t)))) {
+         if (ARG2)
+            PRE_MEM_WRITE("zone(uniqidlist)", ARG2,
+                          *(vki_uint_t *) ARG3 * sizeof(vki_uint64_t));
+      }
+      break;
+   case VKI_ZONE_GETATTR_DEFUNCT:
+      /* Libc: ssize_t zone_getattr_defunct(uint64_t uniqid, int attr,
+                                            void *valp, size_t size);
+         Kernel: ssize_t zone_getattr_defunct(uint64_t *uniqid, int attr,
+                                              void *valp, size_t size);
+       */
+      PRINT("sys_zone ( %ld, %#lx, %ld, %#lx, %ld )",
+            ARG1, ARG2, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, SC2("zone", "getattr_defunct"), int, cmd,
+                    vki_uint64_t *, uniqid, int, attr,
+                    void *, valp, vki_size_t, size);
+
+      PRE_MEM_READ("zone(uniqid)", ARG2, sizeof(vki_uint64_t));
+      PRE_MEM_WRITE("zone(valp)", ARG4, ARG5);
+      break;
+#endif /* SOLARIS_ZONE_DEFUNCT */
+   default:
+      VG_(unimplemented)("Syswrap of the zone call with cmd %ld.", ARG1);
+      /*NOTREACHED*/
+      break;
+   }
+
+}
+
+POST(sys_zone)
+{
+   switch (ARG1 /*cmd*/) {
+   case VKI_ZONE_CREATE:
+   case VKI_ZONE_DESTROY:
+      break;
+   case VKI_ZONE_GETATTR:
+      POST_MEM_WRITE(ARG4, MIN(RES, ARG5));
+      break;
+   case VKI_ZONE_ENTER:
+      break;
+   case VKI_ZONE_LIST:
+      POST_MEM_WRITE(ARG2, *(vki_uint_t *) ARG3 * sizeof(vki_zoneid_t));
+      break;
+   case VKI_ZONE_SHUTDOWN:
+   case VKI_ZONE_LOOKUP:
+   case VKI_ZONE_BOOT:
+   case VKI_ZONE_SETATTR:
+   case VKI_ZONE_ADD_DATALINK:
+   case VKI_ZONE_DEL_DATALINK:
+      break;
+   case VKI_ZONE_CHECK_DATALINK:
+      POST_MEM_WRITE(ARG2, sizeof(vki_zoneid_t));
+      break;
+   case VKI_ZONE_LIST_DATALINK:
+      POST_MEM_WRITE(ARG4, *(int *) ARG3 * sizeof(vki_datalink_id_t));
+      break;
+#if defined(SOLARIS_ZONE_DEFUNCT)
+   case VKI_ZONE_LIST_DEFUNCT:
+      POST_MEM_WRITE(ARG2, *(vki_uint_t *) ARG3 * sizeof(vki_uint64_t));
+      break;
+   case VKI_ZONE_GETATTR_DEFUNCT:
+      POST_MEM_WRITE(ARG4, MIN(RES, ARG5));
+      break;
+#endif /* SOLARIS_ZONE_DEFUNCT */
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+PRE(sys_getcwd)
+{
+   /* int getcwd(char *buf, size_t size); */
+   /* Note: Generic getcwd() syswrap can't be used because it expects
+      a different return value. */
+   PRINT("sys_getcwd ( %#lx, %lu )", ARG1, ARG2);
+   PRE_REG_READ2(long, "getcwd", char *, buf, vki_size_t, size);
+   PRE_MEM_WRITE("getcwd(buf)", ARG1, ARG2);
+}
+
+POST(sys_getcwd)
+{
+   POST_MEM_WRITE(ARG1, VG_(strlen)((HChar*)ARG1) + 1);
+}
+
+PRE(sys_so_socket)
+{
+   /* int so_socket(int family, int type, int protocol, char *devpath,
+                    int version); */
+   PRINT("sys_so_socket ( %ld, %ld, %ld, %#lx(%s), %ld)", ARG1, ARG2, ARG3,
+         ARG4, (HChar *) ARG4, ARG5);
+   PRE_REG_READ5(long, "socket", int, family, int, type, int, protocol,
+                 char *, devpath, int, version);
+   if (ARG4)
+      PRE_MEM_RASCIIZ("socket(devpath)", ARG4);
+}
+
+POST(sys_so_socket)
+{
+   SysRes r;
+   r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES));
+   SET_STATUS_from_SysRes(r);
+}
+
+PRE(sys_so_socketpair)
+{
+   /* int so_socketpair(int sv[2]); */
+   /* This syscall is used to connect two already created sockets together. */
+   PRINT("sys_so_socketpair ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "socketpair", int *, sv);
+   PRE_MEM_READ("socketpair(sv)", ARG1, 2 * sizeof(int));
+   /*PRE_MEM_WRITE("socketpair(sv)", ARG1, 2 * sizeof(int));*/
+   if (ML_(safe_to_deref)((void*)ARG1, 2 * sizeof(int))) {
+      int *fds = (int*)ARG1;
+      if (!ML_(fd_allowed)(fds[0], "socketpair", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+      else if (!ML_(fd_allowed)(fds[1], "socketpair", tid, False))
+         SET_STATUS_Failure(VKI_EBADF);
+   }
+}
+
+POST(sys_so_socketpair)
+{
+   /* The kernel can return new file descriptors, in such a case we have to
+      validate them. */
+   int *fds = (int*)ARG1;
+   POST_MEM_WRITE(ARG1, 2 * sizeof(int));
+   if (!ML_(fd_allowed)(fds[0], "socketpair", tid, True))
+      SET_STATUS_Failure(VKI_EMFILE);
+   if (!ML_(fd_allowed)(fds[1], "socketpair", tid, True))
+      SET_STATUS_Failure(VKI_EMFILE);
+   if (FAILURE) {
+      /* One or both of the file descriptors weren't allowed, close newly
+         created file descriptors but don't close the already recorded
+         ones. */
+      if (!ML_(fd_recorded)(fds[0]))
+         VG_(close)(fds[0]);
+      if (!ML_(fd_recorded)(fds[1]))
+         VG_(close)(fds[1]);
+   }
+   else if (VG_(clo_track_fds)) {
+      /* Everything went better than expected, record the newly created file
+         descriptors.  Note: If the kernel actually returns the original file
+         descriptors, then ML_(record_fd_open_nameless) notices that these
+         file descriptors have been already recorded. */
+      ML_(record_fd_open_nameless)(tid, fds[0]);
+      ML_(record_fd_open_nameless)(tid, fds[1]);
+   }
+}
+
+PRE(sys_bind)
+{
+   /* int bind(int s, struct sockaddr *name, socklen_t namelen,
+               int version); */
+   PRINT("sys_bind ( %ld, %#lx, %lu, %ld )",ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "bind", int, s, struct sockaddr *, name,
+                 vki_socklen_t, namelen, int, version);
+   ML_(generic_PRE_sys_bind)(tid, ARG1, ARG2, ARG3);
+}
+
+PRE(sys_listen)
+{
+   /* int listen(int s, int backlog, int version); */
+   PRINT("sys_listen ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "listen", int, s, int, backlog, int, version);
+}
+
+PRE(sys_accept)
+{
+#if defined(SOLARIS_NEW_ACCEPT_SYSCALL)
+   /* int accept(int s, struct sockaddr *addr, socklen_t *addrlen,
+                 int version, int flags); */
+   *flags |= SfMayBlock;
+   PRINT("sys_accept ( %ld, %#lx, %#lx, %ld, %ld )", ARG1, ARG2, ARG3, ARG4,
+         ARG5);
+   PRE_REG_READ5(long, "accept", int, s, struct sockaddr *, addr,
+                 socklen_t *, addrlen, int, version, int, flags);
+#else
+   /* int accept(int s, struct sockaddr *addr, socklen_t *addrlen,
+                 int version); */
+   *flags |= SfMayBlock;
+   PRINT("sys_accept ( %ld, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "accept", int, s, struct sockaddr *, addr,
+                 socklen_t *, addrlen, int, version);
+#endif /* SOLARIS_NEW_ACCEPT_SYSCALL */
+   ML_(generic_PRE_sys_accept)(tid, ARG1, ARG2, ARG3);
+}
+
+POST(sys_accept)
+{
+   SysRes r;
+   r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
+                                    ARG1, ARG2, ARG3);
+   SET_STATUS_from_SysRes(r);
+}
+
+PRE(sys_connect)
+{
+   /* int connect(int s, struct sockaddr *name, socklen_t namelen,
+                  int version); */
+   *flags |= SfMayBlock;
+   PRINT("sys_connect ( %ld, %#lx, %lu, %ld )",ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "connect", int, s, struct sockaddr *, name,
+                 vki_socklen_t, namelen, int, version);
+   ML_(generic_PRE_sys_connect)(tid, ARG1, ARG2, ARG3);
+}
+
+PRE(sys_shutdown)
+{
+   /* Kernel: int shutdown(int sock, int how, int version);
+      Libc:   int shutdown(int sock, int how);
+    */
+   *flags |= SfMayBlock;
+   PRINT("sys_shutdown ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "shutdown", int, sock, int, how, int, version);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "shutdown", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_recv)
+{
+   /* ssize_t recv(int s, void *buf, size_t len, int flags); */
+   *flags |= SfMayBlock;
+   PRINT("sys_recv ( %ld, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "recv", int, s, void *, buf, vki_size_t, len,
+                 int, flags);
+   ML_(generic_PRE_sys_recv)(tid, ARG1, ARG2, ARG3);
+}
+
+POST(sys_recv)
+{
+   ML_(generic_POST_sys_recv)(tid, RES, ARG1, ARG2, ARG3);
+}
+
+PRE(sys_recvfrom)
+{
+   /* ssize_t recvfrom(int s, void *buf, size_t len, int flags,
+                       struct sockaddr *from, socklen_t *fromlen); */
+   *flags |= SfMayBlock;
+   PRINT("sys_recvfrom ( %ld, %#lx, %lu, %ld, %#lx, %#lx )", ARG1, ARG2, ARG3,
+         ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "recvfrom", int, s, void *, buf, vki_size_t, len,
+                 int, flags, struct sockaddr *, from, socklen_t *, fromlen);
+   ML_(generic_PRE_sys_recvfrom)(tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+}
+
+POST(sys_recvfrom)
+{
+   ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES),
+                                  ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+}
+
+PRE(sys_recvmsg)
+{
+   /* ssize_t recvmsg(int s, struct msghdr *msg, int flags); */
+   *flags |= SfMayBlock;
+   PRINT("sys_recvmsg ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "recvmsg", int, s, struct msghdr *, msg, int, flags);
+   ML_(generic_PRE_sys_recvmsg)(tid, "msg", (struct vki_msghdr*)ARG2);
+}
+
+POST(sys_recvmsg)
+{
+   ML_(generic_POST_sys_recvmsg)(tid, "msg", (struct vki_msghdr*)ARG2, RES);
+}
+
+PRE(sys_send)
+{
+   /* ssize_t send(int s, const void *msg, size_t len, int flags); */
+   *flags |= SfMayBlock;
+   PRINT("sys_send ( %ld, %#lx, %lu, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "send", int, s, const void *, msg, vki_size_t, len,
+                 int, flags);
+   ML_(generic_PRE_sys_send)(tid, ARG1, ARG2, ARG3);
+}
+
+PRE(sys_sendmsg)
+{
+   /* ssize_t sendmsg(int s, const struct msghdr *msg, int flags); */
+   *flags |= SfMayBlock;
+   PRINT("sys_sendmsg ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sendmsg", int, s, const struct msghdr *, msg,
+                 int, flags);
+   ML_(generic_PRE_sys_sendmsg)(tid, "msg", (struct vki_msghdr*)ARG2);
+}
+
+PRE(sys_sendto)
+{
+   /* ssize_t sendto(int s, const void *msg, size_t len, int flags,
+                     const struct sockaddr *to, int tolen); */
+   *flags |= SfMayBlock;
+   PRINT("sys_sendto ( %ld, %#lx, %lu, %ld, %#lx, %ld )", ARG1, ARG2, ARG3,
+         ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "sendto", int, s, const void *, msg, vki_size_t, len,
+                 int, flags, const struct sockaddr *, to, int, tolen);
+   ML_(generic_PRE_sys_sendto)(tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+}
+
+PRE(sys_getpeername)
+{
+   /* Kernel: int getpeername(int s, struct sockaddr *name,
+                              socklen_t *namelen, int version);
+      Libc:   int getpeername(int s, struct sockaddr *name,
+                              socklen_t *namelen);
+    */
+   *flags |= SfMayBlock;
+   PRINT("sys_getpeername ( %ld, %#lx, %#lx, %ld )",
+         ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "getpeername", int, s, struct vki_sockaddr *, name,
+                 vki_socklen_t *, namelen, int, version);
+   ML_(buf_and_len_pre_check)(tid, ARG2, ARG3, "getpeername(name)",
+                              "getpeername(namelen)");
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "getpeername", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_getpeername)
+{
+   ML_(buf_and_len_post_check)(tid, VG_(mk_SysRes_Success)(RES),
+                               ARG2, ARG3, "getpeername(namelen)");
+}
+
+PRE(sys_getsockname)
+{
+   /* int getsockname(int s, struct sockaddr *name, socklen_t *namelen,
+                      int version); */
+   PRINT("sys_getsockname ( %ld, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "getsockname", int, s, struct sockaddr *, name,
+                 socklen_t *, namelen, int, version);
+   ML_(generic_PRE_sys_getsockname)(tid, ARG1, ARG2, ARG3);
+}
+
+POST(sys_getsockname)
+{
+   ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES),
+                                     ARG1, ARG2, ARG3);
+}
+
+PRE(sys_getsockopt)
+{
+   /* int getsockopt(int s, int level, int optname, void *optval,
+                     socklen_t *optlen, int version); */
+   PRINT("sys_getsockopt ( %ld, %ld, %ld, %#lx, %#lx, %ld )", ARG1, ARG2,
+         ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "getsockopt", int, s, int, level, int, optname,
+                 void *, optval, socklen_t *, option, int, version);
+   if (ARG4)
+      ML_(buf_and_len_pre_check)(tid, ARG4, ARG5, "getsockopt(optval)",
+                                 "getsockopt(optlen)");
+}
+
+POST(sys_getsockopt)
+{
+   if (ARG4)
+      ML_(buf_and_len_post_check)(tid, VG_(mk_SysRes_Success)(RES), ARG4,
+                                  ARG5, "getsockopt(optlen_out)");
+}
+
+PRE(sys_setsockopt)
+{
+   /* int setsockopt(int s, int level, int optname, const void *optval,
+                     socklen_t optlen, int version); */
+   PRINT("sys_setsockopt ( %ld, %ld, %ld, %#lx, %lu, %ld )", ARG1, ARG2, ARG3,
+         ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "setsockopt", int, s, int, level, int, optname,
+                 const void *, optval, vki_socklen_t, optlen, int, version);
+   ML_(generic_PRE_sys_setsockopt)(tid, ARG1, ARG2, ARG3, ARG4, ARG5);
+}
+
+PRE(sys_lwp_mutex_register)
+{
+   /* int lwp_mutex_register(lwp_mutex_t *mp, caddr_t uaddr); */
+   vki_lwp_mutex_t *mp = (vki_lwp_mutex_t*)ARG1;
+   PRINT("sys_lwp_mutex_register ( %#lx, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "lwp_mutex_register", lwp_mutex_t *, mp,
+                 void *, uaddr);
+   PRE_FIELD_READ("lwp_mutex_register(mp->mutex_type)", mp->vki_mutex_type);
+}
+
+PRE(sys_uucopy)
+{
+   /* int uucopy(const void *s1, void *s2, size_t n); */
+   PRINT("sys_uucopy ( %#lx, %#lx, %lu )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "uucopy", const void *, s1, void *, s2, vki_size_t, n);
+
+   /* Stay away from V segments. */
+   if (!ML_(valid_client_addr)(ARG1, ARG3, tid, "uucopy(s1)")) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+   if (!ML_(valid_client_addr)(ARG2, ARG3, tid, "uucopy(s2)")) {
+      SET_STATUS_Failure(VKI_EFAULT);
+   }
+
+   if (FAILURE)
+      return;
+
+   /* XXX This is actually incorrect, we should be able to copy undefined
+      values through to their new destination. */
+   PRE_MEM_READ("uucopy(s1)", ARG1, ARG3);
+   PRE_MEM_WRITE("uucopy(s2)", ARG2, ARG3);
+}
+
+POST(sys_uucopy)
+{
+   POST_MEM_WRITE(ARG2, ARG3);
+}
+
+PRE(sys_umount2)
+{
+   /* int umount2(const char *file, int mflag); */
+   *flags |= SfMayBlock;
+   PRINT("sys_umount2 ( %#lx(%s), %ld )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "umount2", const char *, file, int, mflag);
+   PRE_MEM_RASCIIZ("umount2(file)", ARG1);
+}
+
+PRE(fast_gethrtime)
+{
+   PRINT("fast_gethrtime ( )");
+   PRE_REG_READ0(long, "gethrtime");
+}
+
+PRE(fast_gethrvtime)
+{
+   PRINT("fast_gethrvtime ( )");
+   PRE_REG_READ0(long, "gethrvtime");
+}
+
+PRE(fast_gethrestime)
+{
+   /* Used by gettimeofday(3C). */
+   PRINT("fast_gethrestime ( )");
+   PRE_REG_READ0(long, "gethrestime");
+}
+
+#if defined(SOLARIS_GETHRT_FASTTRAP)
+PRE(fast_gethrt)
+{
+   /* Used by gethrtime(3C) when tsp & tscp HWCAPs are present. */
+   PRINT("fast_gethrt ( )");
+   PRE_REG_READ0(long, "gethrt");
+}
+
+POST(fast_gethrt)
+{
+   if (RES == 0)
+      return;
+
+   /* Returned address points to a memory mapping shared between kernel
+      and the process. This was already pre-arranged during process address
+      space initialization happening in kernel. Valgrind on startup created
+      a segment for this mapping categorized as Valgrind's owned anonymous.
+      Size of this mapping varies among Solaris versions but should be
+      page aligned. */
+   const NSegment *seg = VG_(am_find_anon_segment)(RES);
+   vg_assert(seg != NULL);
+   vg_assert(seg->start == RES);
+   vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
+   vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
+   SizeT size = seg->end - seg->start + 1;
+   vg_assert(size > 0);
+
+   if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
+      Bool change_ownership_v_c_OK
+         = VG_(am_change_ownership_v_to_c)(RES, size);
+      vg_assert(change_ownership_v_c_OK);
+
+      /* Tell the tool about just discovered mapping. */
+      VG_TRACK(new_mem_startup,
+               RES, size,
+               True  /* readable? */,
+               False /* writable? */,
+               False /* executable? */,
+               0     /* di_handle */);
+   }
+}
+#endif /* SOLARIS_GETHRT_FASTTRAP */
+
+#if defined(SOLARIS_GETZONEOFFSET_FASTTRAP)
+PRE(fast_getzoneoffset)
+{
+   /* Returns kernel's time zone offset data. */
+   PRINT("fast_getzoneoffset ( )");
+   PRE_REG_READ0(long, "get_zone_offset");
+}
+
+POST(fast_getzoneoffset)
+{
+   if (RES == 0)
+      return;
+
+   /* Returned address points to a memory mapping shared between kernel
+      and the process. This was already pre-arranged during process address
+      space initialization happening in kernel. Valgrind on startup created
+      a segment for this mapping categorized as Valgrind's owned anonymous.
+      Size of this mapping varies among Solaris versions but should be
+      page aligned. */
+   const NSegment *seg = VG_(am_find_anon_segment)(RES);
+   vg_assert(seg != NULL);
+   vg_assert(seg->start == RES);
+   vg_assert(VG_IS_PAGE_ALIGNED(seg->start));
+   vg_assert(VG_IS_PAGE_ALIGNED(seg->end + 1));
+   SizeT size = seg->end - seg->start + 1;
+   vg_assert(size > 0);
+
+   if (!VG_(am_is_valid_for_client)(RES, size, VKI_PROT_READ)) {
+      Bool change_ownership_v_c_OK
+         = VG_(am_change_ownership_v_to_c)(RES, size);
+      vg_assert(change_ownership_v_c_OK);
+
+      /* Tell the tool about just discovered mapping. */
+      VG_TRACK(new_mem_startup,
+               RES, size,
+               True  /* readable? */,
+               False /* writable? */,
+               False /* executable? */,
+               0     /* di_handle */);
+   }
+}
+#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
+
+#undef PRE
+#undef POST
+
+/* ---------------------------------------------------------------------
+   The Solaris syscall table
+   ------------------------------------------------------------------ */
+
+/* Add a Solaris-specific, arch-independent wrapper to a syscall table. */
+#define SOLX_(sysno, name) \
+   WRAPPER_ENTRY_X_(solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+#define SOLXY(sysno, name) \
+   WRAPPER_ENTRY_XY(solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+
+#if defined(VGP_x86_solaris)
+/* Add an x86-solaris specific wrapper to a syscall table. */
+#define PLAX_(sysno, name) \
+   WRAPPER_ENTRY_X_(x86_solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+#define PLAXY(sysno, name) \
+   WRAPPER_ENTRY_XY(x86_solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+
+#elif defined(VGP_amd64_solaris)
+/* Add an amd64-solaris specific wrapper to a syscall table. */
+#define PLAX_(sysno, name) \
+   WRAPPER_ENTRY_X_(amd64_solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+#define PLAXY(sysno, name) \
+   WRAPPER_ENTRY_XY(amd64_solaris, VG_SOLARIS_SYSNO_INDEX(sysno), name)
+
+#else
+#  error "Unknown platform"
+#endif
+
+/*
+   GEN   : handlers are in syswrap-generic.c
+   SOL   : handlers are in this file
+      X_ : PRE handler only
+      XY : PRE and POST handlers
+*/
+
+static SyscallTableEntry syscall_table[] = {
+   SOLX_(__NR_exit,                 sys_exit),                  /*   1 */
+#if defined(SOLARIS_SPAWN_SYSCALL)
+   SOLX_(__NR_spawn,                sys_spawn),                 /*   2 */
+#endif /* SOLARIS_SPAWN_SYSCALL */
+   GENXY(__NR_read,                 sys_read),                  /*   3 */
+   GENX_(__NR_write,                sys_write),                 /*   4 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   SOLXY(__NR_open,                 sys_open),                  /*   5 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLXY(__NR_close,                sys_close),                 /*   6 */
+   SOLX_(__NR_linkat,               sys_linkat),                /*   7 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_link,                 sys_link),                  /*   9 */
+   GENX_(__NR_unlink,               sys_unlink),                /*  10 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLX_(__NR_symlinkat,            sys_symlinkat),             /*  11 */
+   GENX_(__NR_chdir,                sys_chdir),                 /*  12 */
+   SOLX_(__NR_time,                 sys_time),                  /*  13 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_chmod,                sys_chmod),                 /*  15 */
+   GENX_(__NR_chown,                sys_chown),                 /*  16 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLX_(__NR_brk,                  sys_brk),                   /*  17 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   SOLXY(__NR_stat,                 sys_stat),                  /*  18 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLX_(__NR_lseek,                sys_lseek),                 /*  19 */
+   GENX_(__NR_getpid,               sys_getpid),                /*  20 */
+   SOLXY(__NR_mount,                sys_mount),                 /*  21 */
+   SOLXY(__NR_readlinkat,           sys_readlinkat),            /*  22 */
+   GENX_(__NR_setuid,               sys_setuid),                /*  23 */
+   GENX_(__NR_getuid,               sys_getuid),                /*  24 */
+   SOLX_(__NR_stime,                sys_stime),                 /*  25 */
+   GENX_(__NR_alarm,                sys_alarm),                 /*  27 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   SOLXY(__NR_fstat,                sys_fstat),                 /*  28 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   GENX_(__NR_pause,                sys_pause),                 /*  29 */
+#if defined(SOLARIS_FREALPATHAT_SYSCALL)
+   SOLXY(__NR_frealpathat,          sys_frealpathat),           /*  30 */
+#endif /* SOLARIS_FREALPATHAT_SYSCALL */
+   SOLX_(__NR_stty,                 sys_stty),                  /*  31 */
+   SOLXY(__NR_gtty,                 sys_gtty),                  /*  32 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_access,               sys_access),                /*  33 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   GENX_(__NR_kill,                 sys_kill),                  /*  37 */
+   SOLX_(__NR_pgrpsys,              sys_pgrpsys),               /*  39 */
+   SOLXY(__NR_pipe,                 sys_pipe),                  /*  42 */
+   GENXY(__NR_times,                sys_times),                 /*  43 */
+   SOLX_(__NR_faccessat,            sys_faccessat),             /*  45 */
+   GENX_(__NR_setgid,               sys_setgid),                /*  46 */
+   GENX_(__NR_getgid,               sys_getgid),                /*  47 */
+   SOLXY(__NR_mknodat,              sys_mknodat),               /*  48 */
+   SOLXY(__NR_sysi86,               sys_sysi86),                /*  50 */
+   SOLXY(__NR_shmsys,               sys_shmsys),                /*  52 */
+   SOLXY(__NR_semsys,               sys_semsys),                /*  53 */
+   SOLXY(__NR_ioctl,                sys_ioctl),                 /*  54 */
+   SOLX_(__NR_fchownat,             sys_fchownat),              /*  56 */
+   SOLX_(__NR_fdsync,               sys_fdsync),                /*  58 */
+   SOLX_(__NR_execve,               sys_execve),                /*  59 */
+   GENX_(__NR_umask,                sys_umask),                 /*  60 */
+   GENX_(__NR_chroot,               sys_chroot),                /*  61 */
+   SOLXY(__NR_fcntl,                sys_fcntl),                 /*  62 */
+   SOLX_(__NR_renameat,             sys_renameat),              /*  64 */
+   SOLX_(__NR_unlinkat,             sys_unlinkat),              /*  65 */
+   SOLXY(__NR_fstatat,              sys_fstatat),               /*  66 */
+#if defined(VGP_x86_solaris)
+   PLAXY(__NR_fstatat64,            sys_fstatat64),             /*  67 */
+#endif /* VGP_x86_solaris */
+   SOLXY(__NR_openat,               sys_openat),                /*  68 */
+#if defined(VGP_x86_solaris)
+   PLAXY(__NR_openat64,             sys_openat64),              /*  69 */
+#endif /* VGP_x86_solaris */
+   SOLXY(__NR_tasksys,              sys_tasksys),               /*  70 */
+   SOLXY(__NR_getpagesizes,         sys_getpagesizes),          /*  73 */
+   SOLXY(__NR_lwp_park,             sys_lwp_park),              /*  77 */
+   SOLXY(__NR_sendfilev,            sys_sendfilev),             /*  78 */
+#if defined(SOLARIS_LWP_NAME_SYSCALL)
+   SOLXY(__NR_lwp_name,             sys_lwp_name),              /*  79 */
+#endif /* SOLARIS_LWP_NAME_SYSCALL */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_rmdir,                sys_rmdir),                 /*  79 */
+   GENX_(__NR_mkdir,                sys_mkdir),                 /*  80 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   GENXY(__NR_getdents,             sys_getdents),              /*  81 */
+   SOLXY(__NR_privsys,              sys_privsys),               /*  82 */
+   SOLXY(__NR_ucredsys,             sys_ucredsys),              /*  83 */
+   SOLXY(__NR_getmsg,               sys_getmsg),                /*  85 */
+   SOLX_(__NR_putmsg,               sys_putmsg),                /*  86 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   SOLXY(__NR_lstat,                sys_lstat),                 /*  88 */
+   GENX_(__NR_symlink,              sys_symlink),               /*  89 */
+   GENX_(__NR_readlink,             sys_readlink),              /*  90 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   GENX_(__NR_setgroups,            sys_setgroups),             /*  91 */
+   GENXY(__NR_getgroups,            sys_getgroups),             /*  92 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_fchmod,               sys_fchmod),                /*  93 */
+   GENX_(__NR_fchown,               sys_fchown),                /*  94 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLXY(__NR_sigprocmask,          sys_sigprocmask),           /*  95 */
+   GENXY(__NR_sigaltstack,          sys_sigaltstack),           /*  97 */
+   SOLXY(__NR_sigaction,            sys_sigaction),             /*  98 */
+   SOLXY(__NR_sigpending,           sys_sigpending),            /*  99 */
+   SOLX_(__NR_context,              sys_getsetcontext),         /* 100 */
+   SOLX_(__NR_fchmodat,             sys_fchmodat),              /* 101 */
+   SOLX_(__NR_mkdirat,              sys_mkdirat),               /* 102 */
+   SOLXY(__NR_statvfs,              sys_statvfs),               /* 103 */
+   SOLXY(__NR_fstatvfs,             sys_fstatvfs),              /* 104 */
+   SOLXY(__NR_nfssys,               sys_nfssys),                /* 106 */
+   SOLXY(__NR_waitid,               sys_waitid),                /* 107 */
+#if defined(SOLARIS_UTIMESYS_SYSCALL)
+   SOLX_(__NR_utimesys,             sys_utimesys),              /* 110 */
+#endif /* SOLARIS_UTIMESYS_SYSCALL */
+#if defined(SOLARIS_UTIMENSAT_SYSCALL)
+   SOLX_(__NR_utimensat,            sys_utimensat),             /* 110 */
+#endif /* SOLARIS_UTIMENSAT_SYSCALL */
+   SOLXY(__NR_sigresend,            sys_sigresend),             /* 111 */
+   SOLXY(__NR_priocntlsys,          sys_priocntlsys),           /* 112 */
+   SOLX_(__NR_pathconf,             sys_pathconf),              /* 113 */
+   SOLX_(__NR_mmap,                 sys_mmap),                  /* 115 */
+   GENXY(__NR_mprotect,             sys_mprotect),              /* 116 */
+   GENXY(__NR_munmap,               sys_munmap),                /* 117 */
+   GENXY(__NR_readv,                sys_readv),                 /* 121 */
+   GENX_(__NR_writev,               sys_writev),                /* 122 */
+#if defined(SOLARIS_UUIDSYS_SYSCALL)
+   SOLXY(__NR_uuidsys,              sys_uuidsys),               /* 124 */
+#endif /* SOLARIS_UUIDSYS_SYSCALL */
+   SOLX_(__NR_mmapobj,              sys_mmapobj),               /* 127 */
+   GENX_(__NR_setrlimit,            sys_setrlimit),             /* 128 */
+   GENXY(__NR_getrlimit,            sys_getrlimit),             /* 129 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   GENX_(__NR_lchown,               sys_lchown),                /* 130 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLX_(__NR_memcntl,              sys_memcntl),               /* 131 */
+   SOLXY(__NR_getpmsg,              sys_getpmsg),               /* 132 */
+   SOLX_(__NR_putpmsg,              sys_putpmsg),               /* 133 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   SOLX_(__NR_rename,               sys_rename),                /* 134 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   SOLXY(__NR_uname,                sys_uname),                 /* 135 */
+   SOLX_(__NR_setegid,              sys_setegid),               /* 136 */
+   SOLX_(__NR_sysconfig,            sys_sysconfig),             /* 137 */
+   SOLXY(__NR_systeminfo,           sys_systeminfo),            /* 139 */
+   SOLX_(__NR_seteuid,              sys_seteuid),               /* 141 */
+   SOLX_(__NR_forksys,              sys_forksys),               /* 142 */
+   SOLXY(__NR_sigtimedwait,         sys_sigtimedwait),          /* 144 */
+   SOLX_(__NR_yield,                sys_yield),                 /* 146 */
+   SOLXY(__NR_lwp_sema_post,        sys_lwp_sema_post),         /* 148 */
+   SOLXY(__NR_lwp_sema_trywait,     sys_lwp_sema_trywait),      /* 149 */
+   SOLX_(__NR_lwp_detach,           sys_lwp_detach),            /* 150 */
+   SOLX_(__NR_fchroot,              sys_fchroot),               /* 153 */
+   SOLXY(__NR_gettimeofday,         sys_gettimeofday),          /* 156 */
+   GENXY(__NR_getitimer,            sys_getitimer),             /* 157 */
+   GENXY(__NR_setitimer,            sys_setitimer),             /* 158 */
+   SOLX_(__NR_lwp_create,           sys_lwp_create),            /* 159 */
+   SOLX_(__NR_lwp_exit,             sys_lwp_exit),              /* 160 */
+   SOLX_(__NR_lwp_suspend,          sys_lwp_suspend),           /* 161 */
+   SOLX_(__NR_lwp_continue,         sys_lwp_continue),          /* 162 */
+#if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL)
+   SOLXY(__NR_lwp_sigqueue,         sys_lwp_sigqueue),          /* 163 */
+#else
+   SOLXY(__NR_lwp_kill,             sys_lwp_kill),              /* 163 */
+#endif /* SOLARIS_LWP_SIGQUEUE_SYSCALL */
+   SOLX_(__NR_lwp_self,             sys_lwp_self),              /* 164 */
+   SOLX_(__NR_lwp_sigmask,          sys_lwp_sigmask),           /* 165 */
+   SOLX_(__NR_lwp_private,          sys_lwp_private),           /* 166 */
+   SOLXY(__NR_lwp_wait,             sys_lwp_wait),              /* 167 */
+   SOLXY(__NR_lwp_mutex_wakeup,     sys_lwp_mutex_wakeup),      /* 168 */
+   SOLX_(__NR_lwp_cond_broadcast,   sys_lwp_cond_broadcast),    /* 172 */
+   SOLXY(__NR_pread,                sys_pread),                 /* 173 */
+   SOLX_(__NR_pwrite,               sys_pwrite),                /* 174 */
+#if defined(VGP_x86_solaris)
+   PLAX_(__NR_llseek,               sys_llseek32),              /* 175 */
+#endif /* VGP_x86_solaris */
+   SOLXY(__NR_rusagesys,            sys_rusagesys),             /* 181 */
+   SOLXY(__NR_port,                 sys_port),                  /* 182 */
+   SOLXY(__NR_pollsys,              sys_pollsys),               /* 183 */
+   SOLXY(__NR_labelsys,             sys_labelsys),              /* 184 */
+   SOLXY(__NR_acl,                  sys_acl),                   /* 185 */
+   SOLXY(__NR_auditsys,             sys_auditsys),              /* 186 */
+   SOLX_(__NR_p_online,             sys_p_online),              /* 189 */
+   SOLX_(__NR_sigqueue,             sys_sigqueue),              /* 190 */
+   SOLX_(__NR_clock_gettime,        sys_clock_gettime),         /* 191 */
+   SOLX_(__NR_clock_settime,        sys_clock_settime),         /* 192 */
+   SOLXY(__NR_clock_getres,         sys_clock_getres),          /* 193 */
+   SOLXY(__NR_timer_create,         sys_timer_create),          /* 194 */
+   SOLX_(__NR_timer_delete,         sys_timer_delete),          /* 195 */
+   SOLXY(__NR_timer_settime,        sys_timer_settime),         /* 196 */
+   SOLXY(__NR_timer_gettime,        sys_timer_gettime),         /* 197 */
+   SOLX_(__NR_timer_getoverrun,     sys_timer_getoverrun),      /* 198 */
+   GENXY(__NR_nanosleep,            sys_nanosleep),             /* 199 */
+   SOLXY(__NR_facl,                 sys_facl),                  /* 200 */
+   SOLXY(__NR_door,                 sys_door),                  /* 201 */
+   GENX_(__NR_setreuid,             sys_setreuid),              /* 202 */
+   GENX_(__NR_setregid,             sys_setregid),              /* 202 */
+   SOLXY(__NR_schedctl,             sys_schedctl),              /* 206 */
+   SOLXY(__NR_resolvepath,          sys_resolvepath),           /* 209 */
+   SOLXY(__NR_lwp_mutex_timedlock,  sys_lwp_mutex_timedlock),   /* 210 */
+   SOLXY(__NR_lwp_sema_timedwait,   sys_lwp_sema_timedwait),    /* 211 */
+   SOLXY(__NR_lwp_rwlock_sys,       sys_lwp_rwlock_sys),        /* 212 */
+#if defined(VGP_x86_solaris)
+   GENXY(__NR_getdents64,           sys_getdents64),            /* 213 */
+   PLAX_(__NR_mmap64,               sys_mmap64),                /* 214 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   PLAXY(__NR_stat64,               sys_stat64),                /* 215 */
+   PLAXY(__NR_lstat64,              sys_lstat64),               /* 216 */
+   PLAXY(__NR_fstat64,              sys_fstat64),               /* 217 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+   PLAXY(__NR_statvfs64,            sys_statvfs64),             /* 218 */
+   PLAXY(__NR_fstatvfs64,           sys_fstatvfs64),            /* 219 */
+#endif /* VGP_x86_solaris */
+#if defined(VGP_x86_solaris)
+   PLAX_(__NR_setrlimit64,          sys_setrlimit64),           /* 220 */
+   PLAXY(__NR_getrlimit64,          sys_getrlimit64),           /* 221 */
+   PLAXY(__NR_pread64,              sys_pread64),               /* 222 */
+   PLAX_(__NR_pwrite64,             sys_pwrite64),              /* 223 */
+#if defined(SOLARIS_OLD_SYSCALLS)
+   PLAXY(__NR_open64,               sys_open64),                /* 225 */
+#endif /* SOLARIS_OLD_SYSCALLS */
+#endif /* VGP_x86_solaris */
+   SOLXY(__NR_zone,                 sys_zone),                  /* 227 */
+   SOLXY(__NR_getcwd,               sys_getcwd),                /* 229 */
+   SOLXY(__NR_so_socket,            sys_so_socket),             /* 230 */
+   SOLXY(__NR_so_socketpair,        sys_so_socketpair),         /* 231 */
+   SOLX_(__NR_bind,                 sys_bind),                  /* 232 */
+   SOLX_(__NR_listen,               sys_listen),                /* 233 */
+   SOLXY(__NR_accept,               sys_accept),                /* 234 */
+   SOLX_(__NR_connect,              sys_connect),               /* 235 */
+   SOLX_(__NR_shutdown,             sys_shutdown),              /* 236 */
+   SOLXY(__NR_recv,                 sys_recv),                  /* 237 */
+   SOLXY(__NR_recvfrom,             sys_recvfrom),              /* 238 */
+   SOLXY(__NR_recvmsg,              sys_recvmsg),               /* 239 */
+   SOLX_(__NR_send,                 sys_send),                  /* 240 */
+   SOLX_(__NR_sendmsg,              sys_sendmsg),               /* 241 */
+   SOLX_(__NR_sendto,               sys_sendto),                /* 242 */
+   SOLXY(__NR_getpeername,          sys_getpeername),           /* 243 */
+   SOLXY(__NR_getsockname,          sys_getsockname),           /* 244 */
+   SOLXY(__NR_getsockopt,           sys_getsockopt),            /* 245 */
+   SOLX_(__NR_setsockopt,           sys_setsockopt),            /* 246 */
+   SOLX_(__NR_lwp_mutex_register,   sys_lwp_mutex_register),    /* 252 */
+   SOLXY(__NR_uucopy,               sys_uucopy),                /* 254 */
+   SOLX_(__NR_umount2,              sys_umount2)                /* 255 */
+};
+
+static SyscallTableEntry fasttrap_table[] = {
+   SOLX_(__NR_gethrtime,            fast_gethrtime),            /*   3 */
+   SOLX_(__NR_gethrvtime,           fast_gethrvtime),           /*   4 */
+   SOLX_(__NR_gethrestime,          fast_gethrestime)           /*   5 */
+#if defined(SOLARIS_GETHRT_FASTTRAP)
+   ,
+   SOLXY(__NR_gethrt,               fast_gethrt)                /*   7 */
+#endif /* SOLARIS_GETHRT_FASTTRAP */
+#if defined(SOLARIS_GETZONEOFFSET_FASTTRAP)
+   ,
+   SOLXY(__NR_getzoneoffset,        fast_getzoneoffset)         /*   8 */
+#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
+
+};
+
+SyscallTableEntry *ML_(get_solaris_syscall_entry)(UInt sysno)
+{
+   const UInt syscall_table_size
+      = sizeof(syscall_table) / sizeof(syscall_table[0]);
+   const UInt fasttrap_table_size
+      = sizeof(fasttrap_table) / sizeof(fasttrap_table[0]);
+
+   SyscallTableEntry *table;
+   Int size;
+
+   switch (VG_SOLARIS_SYSNO_CLASS(sysno)) {
+   case VG_SOLARIS_SYSCALL_CLASS_CLASSIC:
+      table = syscall_table;
+      size = syscall_table_size;
+      break;
+   case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP:
+      table = fasttrap_table;
+      size = fasttrap_table_size;
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+   sysno = VG_SOLARIS_SYSNO_INDEX(sysno);
+   if (sysno < size) {
+      SyscallTableEntry *sys = &table[sysno];
+      if (!sys->before)
+         return NULL; /* no entry */
+      return sys;
+   }
+
+   /* Can't find a wrapper. */
+   return NULL;
+}
+
+#endif // defined(VGO_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-x86-solaris.c b/coregrind/m_syswrap/syswrap-x86-solaris.c
new file mode 100644
index 0000000..81a082c
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-x86-solaris.c
@@ -0,0 +1,990 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Platform-specific syscalls stuff.      syswrap-x86-solaris.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2014 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+#if defined(VGP_x86_solaris)
+
+#include "libvex_guest_offsets.h"
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_machine.h"           // VG_(get_SP)
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"
+#include "priv_syswrap-solaris.h"
+
+/* Call f(arg1), but first switch stacks, using 'stack' as the new stack, and
+   use 'retaddr' as f's return-to address.  Also, clear all the integer
+   registers before entering f. */
+__attribute__((noreturn))
+void ML_(call_on_new_stack_0_1)(Addr stack,             /* 4(%esp) */
+                                Addr retaddr,           /* 8(%esp) */
+                                void (*f)(Word),        /* 12(%esp) */
+                                Word arg1);             /* 16(%esp) */
+__asm__ (
+".text\n"
+".globl vgModuleLocal_call_on_new_stack_0_1\n"
+"vgModuleLocal_call_on_new_stack_0_1:\n"
+"   movl  %esp, %esi\n"         /* remember old stack pointer */
+"   movl  4(%esi), %esp\n"      /* set stack */
+"   pushl $0\n"                 /* align stack */
+"   pushl $0\n"                 /* align stack */
+"   pushl $0\n"                 /* align stack */
+"   pushl 16(%esi)\n"           /* arg1 to stack */
+"   pushl 8(%esi)\n"            /* retaddr to stack */
+"   pushl 12(%esi)\n"           /* f 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 f */
+"   ud2\n"                      /* should never get here */
+".previous\n"
+);
+
+/* This function is called to setup a context of a new Valgrind thread (which
+   will run the client code). */
+void ML_(setup_start_thread_context)(ThreadId tid, vki_ucontext_t *uc)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   UWord *stack = (UWord*)tst->os_state.valgrind_stack_init_SP;
+   UShort cs, ds, ss, es, fs, gs;
+
+   VG_(memset)(uc, 0, sizeof(*uc));
+   uc->uc_flags = VKI_UC_CPU | VKI_UC_SIGMASK;
+
+   /* Start the thread with everything blocked. */
+   VG_(sigfillset)(&uc->uc_sigmask);
+
+   /* Set up the stack, it should be always 16-byte aligned before doing
+      a function call, i.e. the first parameter is also 16-byte aligned. */
+   vg_assert(VG_IS_16_ALIGNED(stack));
+   stack -= 1;
+   stack[0] = 0; /* bogus return value */
+   stack[1] = (UWord)tst; /* the parameter */
+
+   /* Set up the registers. */
+   uc->uc_mcontext.gregs[VKI_EIP] = (UWord)ML_(start_thread_NORETURN);
+   uc->uc_mcontext.gregs[VKI_UESP] = (UWord)stack;
+
+   /* Copy segment registers. */
+   __asm__ __volatile__(
+      "movw %%cs, %[cs]\n"
+      "movw %%ds, %[ds]\n"
+      "movw %%ss, %[ss]\n"
+      "movw %%es, %[es]\n"
+      "movw %%fs, %[fs]\n"
+      "movw %%gs, %[gs]\n"
+      : [cs] "=m" (cs), [ds] "=m" (ds), [ss] "=m" (ss), [es] "=m" (es),
+        [fs] "=m" (fs), [gs] "=m" (gs));
+   uc->uc_mcontext.gregs[VKI_CS] = cs;
+   uc->uc_mcontext.gregs[VKI_DS] = ds;
+   uc->uc_mcontext.gregs[VKI_SS] = ss;
+   uc->uc_mcontext.gregs[VKI_ES] = es;
+   uc->uc_mcontext.gregs[VKI_FS] = fs;
+   uc->uc_mcontext.gregs[VKI_GS] = gs;
+}
+
+/* Architecture-specific part of VG_(save_context). */
+void ML_(save_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                               CorePart part)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_fpchip_state *fs
+      = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+   SizeT i;
+
+   /* CPU */
+   /* Common registers */
+   uc->uc_mcontext.gregs[VKI_EIP] = tst->arch.vex.guest_EIP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EIP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EIP], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_EAX] = tst->arch.vex.guest_EAX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EAX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EAX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_EBX] = tst->arch.vex.guest_EBX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EBX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EBX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_ECX] = tst->arch.vex.guest_ECX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_ECX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_ECX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_EDX] = tst->arch.vex.guest_EDX;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EDX,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EDX], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_EBP] = tst->arch.vex.guest_EBP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EBP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EBP], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_ESI] = tst->arch.vex.guest_ESI;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_ESI,
+            (Addr)&uc->uc_mcontext.gregs[VKI_ESI], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_EDI] = tst->arch.vex.guest_EDI;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_EDI,
+            (Addr)&uc->uc_mcontext.gregs[VKI_EDI], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_UESP] = tst->arch.vex.guest_ESP;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_ESP,
+            (Addr)&uc->uc_mcontext.gregs[VKI_UESP], sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_ESP] = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_mcontext.gregs[VKI_ESP],
+            sizeof(UWord));
+
+   /* ERR and TRAPNO */
+   uc->uc_mcontext.gregs[VKI_ERR] = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_mcontext.gregs[VKI_ERR],
+            sizeof(UWord));
+   uc->uc_mcontext.gregs[VKI_TRAPNO] = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_mcontext.gregs[VKI_TRAPNO],
+            sizeof(UWord));
+
+   /* Segment registers */
+   /* Note that segment registers are 16b in VEX, but 32b in mcontext.  Thus
+      we tell a tool that the lower 16 bits were copied and that the higher 16
+      bits were set (to zero).  (This assumes a little-endian
+      architecture.) */
+   uc->uc_mcontext.gregs[VKI_CS] = tst->arch.vex.guest_CS;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_CS,
+            (Addr)&uc->uc_mcontext.gregs[VKI_CS], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_CS]) + 2, sizeof(UShort));
+   uc->uc_mcontext.gregs[VKI_DS] = tst->arch.vex.guest_DS;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_DS,
+            (Addr)&uc->uc_mcontext.gregs[VKI_DS], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_DS]) + 2, sizeof(UShort));
+   uc->uc_mcontext.gregs[VKI_SS] = tst->arch.vex.guest_SS;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_SS,
+            (Addr)&uc->uc_mcontext.gregs[VKI_SS], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_SS]) + 2, sizeof(UShort));
+   uc->uc_mcontext.gregs[VKI_ES] = tst->arch.vex.guest_ES;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_ES,
+            (Addr)&uc->uc_mcontext.gregs[VKI_ES], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_ES]) + 2, sizeof(UShort));
+   uc->uc_mcontext.gregs[VKI_FS] = tst->arch.vex.guest_FS;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_FS,
+            (Addr)&uc->uc_mcontext.gregs[VKI_FS], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_FS]) + 2, sizeof(UShort));
+   uc->uc_mcontext.gregs[VKI_GS] = tst->arch.vex.guest_GS;
+   VG_TRACK(copy_reg_to_mem, part, tid, OFFSET_x86_GS,
+            (Addr)&uc->uc_mcontext.gregs[VKI_GS], sizeof(UShort));
+   VG_TRACK(post_mem_write, part, tid,
+            (Addr)(&uc->uc_mcontext.gregs[VKI_GS]) + 2, sizeof(UShort));
+
+   /* Handle eflags (optimistically make all flags defined). */
+   uc->uc_mcontext.gregs[VKI_EFL] =
+      LibVEX_GuestX86_get_eflags(&tst->arch.vex);
+   VG_TRACK(post_mem_write, part, tid, (Addr)&uc->uc_mcontext.gregs[VKI_EFL],
+         sizeof(UWord));
+   /* The LibVEX_GuestX86_get_eflags() call calculates eflags value from the
+      CC_OP, CC_DEP1, CC_DEP2, CC_NDEP, DFLAG, IDFLAG and ACFLAG guest state
+      values.  The *FLAG values represent one-bit information and are saved
+      without loss of precision into eflags.  However when CC_* values are
+      converted into eflags then precision is lost.  What we do here is to
+      save unmodified CC_* values into unused ucontext members (the 'long
+      uc_filler[5] and 'int fs->__pad[2]' arrays) so we can then restore the
+      context in ML_(restore_machine_context)() without the loss of precision.
+      This imposes a requirement on client programs to not use these two
+      members. Luckily this is never a case in Solaris-gate programs and
+      libraries. */
+   /* CC_OP and CC_NDEP are always defined, but we don't want to tell a tool
+      that we just defined uc_filler[0,1].  This helps if someone uses an
+      uninitialized ucontext and tries to read (use) uc_filler[0,1].  Memcheck
+      in such a case should detect this error. */
+   VKI_UC_GUEST_CC_OP(uc) = tst->arch.vex.guest_CC_OP;
+   VKI_UC_GUEST_CC_NDEP(uc) = tst->arch.vex.guest_CC_NDEP;
+   /* We want to copy shadow values of CC_DEP1 and CC_DEP2 so we have to tell
+      a tool about this copy. */
+   VKI_UC_GUEST_CC_DEP1(uc) = tst->arch.vex.guest_CC_DEP1;
+   VG_TRACK(copy_reg_to_mem, part, tid,
+            offsetof(VexGuestX86State, guest_CC_DEP1),
+            (Addr)&VKI_UC_GUEST_CC_DEP1(uc), sizeof(UWord));
+   VKI_UC_GUEST_CC_DEP2(uc) = tst->arch.vex.guest_CC_DEP2;
+   VG_TRACK(copy_reg_to_mem, part, tid,
+            offsetof(VexGuestX86State, guest_CC_DEP2),
+            (Addr)&VKI_UC_GUEST_CC_DEP2(uc), sizeof(UWord));
+   /* Make another copy of eflags. */
+   VKI_UC_GUEST_EFLAGS_NEG(uc) = ~uc->uc_mcontext.gregs[VKI_EFL];
+   /* Calculate a checksum. */
+   {
+      UInt buf[5];
+      UInt checksum;
+
+      buf[0] = VKI_UC_GUEST_CC_OP(uc);
+      buf[1] = VKI_UC_GUEST_CC_NDEP(uc);
+      buf[2] = VKI_UC_GUEST_CC_DEP1(uc);
+      buf[3] = VKI_UC_GUEST_CC_DEP2(uc);
+      buf[4] = uc->uc_mcontext.gregs[VKI_EFL];
+      checksum = ML_(fletcher32)((UShort*)&buf, sizeof(buf) / sizeof(UShort));
+      /* Store the checksum. */
+      VKI_UC_GUEST_EFLAGS_CHECKSUM(uc) = checksum;
+   }
+
+   /* FPU */
+   /* x87 */
+   vg_assert(sizeof(fs->state) == 108);
+   LibVEX_GuestX86_get_x87(&tst->arch.vex, (UChar*)&fs->state);
+
+   /* Flags and control words */
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->state, 28);
+   /* ST registers */
+   for (i = 0; i < 8; i++) {
+      Addr addr = (Addr)&fs->state + 28 + i * 10;
+      /* x87 uses 80b FP registers but VEX uses only 64b registers, thus we
+         have to lie here. :< */
+      VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+               guest_FPREG[i]), addr, sizeof(ULong));
+      VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+               guest_FPREG[i]), addr + 8, sizeof(UShort));
+      }
+
+   /* Status word (sw) at exception */
+   fs->status = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->status, sizeof(fs->status));
+
+   /* SSE */
+   fs->mxcsr = LibVEX_GuestX86_get_mxcsr(&tst->arch.vex);
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->mxcsr, sizeof(fs->mxcsr));
+
+   /* MXCSR at exception */
+   fs->xstatus = 0;
+   VG_TRACK(post_mem_write, part, tid, (Addr)&fs->xstatus,
+            sizeof(fs->xstatus));
+
+   /* XMM registers */
+#define COPY_OUT_XMM(dest, src) \
+   do {                         \
+      dest._l[0] = src[0];      \
+      dest._l[1] = src[1];      \
+      dest._l[2] = src[2];      \
+      dest._l[3] = src[3];      \
+   } while (0)
+   COPY_OUT_XMM(fs->xmm[0], tst->arch.vex.guest_XMM0);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM0), (Addr)&fs->xmm[0], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[1], tst->arch.vex.guest_XMM1);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM1), (Addr)&fs->xmm[1], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[2], tst->arch.vex.guest_XMM2);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM2), (Addr)&fs->xmm[2], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[3], tst->arch.vex.guest_XMM3);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM3), (Addr)&fs->xmm[3], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[4], tst->arch.vex.guest_XMM4);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM4), (Addr)&fs->xmm[4], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[5], tst->arch.vex.guest_XMM5);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM5), (Addr)&fs->xmm[5], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[6], tst->arch.vex.guest_XMM6);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM6), (Addr)&fs->xmm[6], sizeof(U128));
+   COPY_OUT_XMM(fs->xmm[7], tst->arch.vex.guest_XMM7);
+   VG_TRACK(copy_reg_to_mem, part, tid, offsetof(VexGuestX86State,
+            guest_XMM7), (Addr)&fs->xmm[7], sizeof(U128));
+#undef COPY_OUT_XMM
+}
+
+/* Architecture-specific part of VG_(restore_context). */
+void ML_(restore_machine_context)(ThreadId tid, vki_ucontext_t *uc,
+                                  CorePart part, Bool esp_is_thrptr)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_fpchip_state *fs
+      = &uc->uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+
+   /* CPU */
+   if (uc->uc_flags & VKI_UC_CPU) {
+      /* Common registers */
+      tst->arch.vex.guest_EIP = uc->uc_mcontext.gregs[VKI_EIP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EIP], OFFSET_x86_EIP,
+               sizeof(UWord));
+      tst->arch.vex.guest_EAX = uc->uc_mcontext.gregs[VKI_EAX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EAX], OFFSET_x86_EAX,
+               sizeof(UWord));
+      tst->arch.vex.guest_EBX = uc->uc_mcontext.gregs[VKI_EBX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EBX], OFFSET_x86_EBX,
+               sizeof(UWord));
+      tst->arch.vex.guest_ECX = uc->uc_mcontext.gregs[VKI_ECX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_ECX], OFFSET_x86_ECX,
+               sizeof(UWord));
+      tst->arch.vex.guest_EDX = uc->uc_mcontext.gregs[VKI_EDX];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EDX], OFFSET_x86_EDX,
+               sizeof(UWord));
+      tst->arch.vex.guest_EBP = uc->uc_mcontext.gregs[VKI_EBP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EBP], OFFSET_x86_EBP,
+               sizeof(UWord));
+      tst->arch.vex.guest_ESI = uc->uc_mcontext.gregs[VKI_ESI];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_ESI], OFFSET_x86_ESI,
+               sizeof(UWord));
+      tst->arch.vex.guest_EDI = uc->uc_mcontext.gregs[VKI_EDI];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_EDI], OFFSET_x86_EDI,
+               sizeof(UWord));
+      tst->arch.vex.guest_ESP = uc->uc_mcontext.gregs[VKI_UESP];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_UESP], OFFSET_x86_ESP,
+               sizeof(UWord));
+
+      if (esp_is_thrptr) {
+         /* The thrptr value is passed by libc to the kernel in the otherwise
+            unused ESP field.  This is used when a new thread is created. */
+         VG_TRACK(pre_mem_read, part, tid,
+                  "restore_machine_context(uc->uc_mcontext.gregs[VKI_ESP])",
+                  (Addr)&uc->uc_mcontext.gregs[VKI_ESP], sizeof(UWord));
+         if (uc->uc_mcontext.gregs[VKI_ESP]) {
+            tst->os_state.thrptr = uc->uc_mcontext.gregs[VKI_ESP];
+            ML_(update_gdt_lwpgs)(tid);
+         }
+      }
+
+      /* Ignore ERR and TRAPNO. */
+
+      /* Segment registers */
+      tst->arch.vex.guest_CS = uc->uc_mcontext.gregs[VKI_CS];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_CS], OFFSET_x86_CS,
+               sizeof(UShort));
+      tst->arch.vex.guest_DS = uc->uc_mcontext.gregs[VKI_DS];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_DS], OFFSET_x86_DS,
+               sizeof(UShort));
+      tst->arch.vex.guest_SS = uc->uc_mcontext.gregs[VKI_SS];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_SS], OFFSET_x86_SS,
+               sizeof(UShort));
+      tst->arch.vex.guest_ES = uc->uc_mcontext.gregs[VKI_ES];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_ES], OFFSET_x86_ES,
+               sizeof(UShort));
+      tst->arch.vex.guest_FS = uc->uc_mcontext.gregs[VKI_FS];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_FS], OFFSET_x86_FS,
+               sizeof(UShort));
+      tst->arch.vex.guest_GS = uc->uc_mcontext.gregs[VKI_GS];
+      VG_TRACK(copy_mem_to_reg, part, tid,
+               (Addr)&uc->uc_mcontext.gregs[VKI_GS], OFFSET_x86_GS,
+               sizeof(UShort));
+
+      /* Eflags */
+      {
+         UInt eflags;
+         UInt orig_eflags;
+         UInt new_eflags;
+         Bool ok_restore = False;
+
+         VG_TRACK(pre_mem_read, part, tid,
+                  "restore_machine_context(uc->uc_mcontext.gregs[VKI_EFL])",
+                  (Addr)&uc->uc_mcontext.gregs[VKI_EFL], sizeof(UWord));
+         eflags = uc->uc_mcontext.gregs[VKI_EFL];
+         orig_eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
+         new_eflags = eflags;
+         /* The kernel disallows the ID flag to be changed via the setcontext
+            call, thus do the same. */
+         if (orig_eflags & VKI_EFLAGS_ID_BIT)
+            new_eflags |= VKI_EFLAGS_ID_BIT;
+         else
+            new_eflags &= ~VKI_EFLAGS_ID_BIT;
+         LibVEX_GuestX86_put_eflags(new_eflags, &tst->arch.vex);
+         VG_TRACK(post_reg_write, part, tid,
+                  offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UWord));
+         VG_TRACK(post_reg_write, part, tid,
+                  offsetof(VexGuestX86State, guest_CC_DEP2), sizeof(UWord));
+
+         /* Check if this context was created by us in VG_(save_context). In
+            that case, try to restore the CC_OP, CC_DEP1, CC_DEP2 and CC_NDEP
+            values which we previously stashed into unused members of the
+            context. */
+         if (eflags != ~VKI_UC_GUEST_EFLAGS_NEG(uc)) {
+            VG_(debugLog)(1, "syswrap-solaris",
+                             "The eflags value was restored from an "
+                             "explicitly set value in thread %d.\n", tid);
+            ok_restore = True;
+         }
+         else {
+            UInt buf[5];
+            UInt checksum;
+
+            buf[0] = VKI_UC_GUEST_CC_OP(uc);
+            buf[1] = VKI_UC_GUEST_CC_NDEP(uc);
+            buf[2] = VKI_UC_GUEST_CC_DEP1(uc);
+            buf[3] = VKI_UC_GUEST_CC_DEP2(uc);
+            buf[4] = eflags;
+            checksum = ML_(fletcher32)((UShort*)&buf,
+                                       sizeof(buf) / sizeof(UShort));
+            if (checksum == VKI_UC_GUEST_EFLAGS_CHECKSUM(uc)) {
+               /* Check ok, the full restoration is possible. */
+               VG_(debugLog)(1, "syswrap-solaris",
+                                "The CC_* guest state values were fully "
+                                "restored in thread %d.\n", tid);
+               ok_restore = True;
+
+               tst->arch.vex.guest_CC_OP = VKI_UC_GUEST_CC_OP(uc);
+               tst->arch.vex.guest_CC_NDEP = VKI_UC_GUEST_CC_NDEP(uc);
+               tst->arch.vex.guest_CC_DEP1 = VKI_UC_GUEST_CC_DEP1(uc);
+               VG_TRACK(copy_mem_to_reg, part, tid,
+                        (Addr)&VKI_UC_GUEST_CC_DEP1(uc),
+                        offsetof(VexGuestX86State, guest_CC_DEP1),
+                        sizeof(UWord));
+               tst->arch.vex.guest_CC_DEP2 = VKI_UC_GUEST_CC_DEP2(uc);
+               VG_TRACK(copy_mem_to_reg, part, tid,
+                        (Addr)&VKI_UC_GUEST_CC_DEP2(uc),
+                        offsetof(VexGuestX86State, guest_CC_DEP2),
+                        sizeof(UWord));
+            }
+         }
+
+         if (!ok_restore)
+            VG_(debugLog)(1, "syswrap-solaris",
+                             "Cannot fully restore the CC_* guest state "
+                             "values, using approximate eflags in thread "
+                             "%d.\n", tid);
+      }
+   }
+
+   if (uc->uc_flags & VKI_UC_FPU) {
+      /* FPU */
+      VexEmNote note;
+      SizeT i;
+
+      /* x87 */
+      /* Flags and control words */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..x87_state)",
+               (Addr)&fs->state, 28);
+      /* ST registers */
+      for (i = 0; i < 8; i++) {
+         Addr addr = (Addr)&fs->state + 28 + i * 10;
+         VG_TRACK(copy_mem_to_reg, part, tid, addr,
+                  offsetof(VexGuestX86State, guest_FPREG[i]), sizeof(ULong));
+      }
+      note = LibVEX_GuestX86_put_x87((UChar*)&fs->state, &tst->arch.vex);
+      if (note != EmNote_NONE)
+         VG_(message)(Vg_UserMsg,
+                      "Error restoring x87 state in thread %d: %s.\n",
+                      tid, LibVEX_EmNote_string(note));
+
+      /* SSE */
+      VG_TRACK(pre_mem_read, part, tid,
+               "restore_machine_context(uc->uc_mcontext.fpregs..mxcsr)",
+               (Addr)&fs->mxcsr, sizeof(fs->mxcsr));
+      note = LibVEX_GuestX86_put_mxcsr(fs->mxcsr, &tst->arch.vex);
+      if (note != EmNote_NONE)
+         VG_(message)(Vg_UserMsg,
+                      "Error restoring mxcsr state in thread %d: %s.\n",
+                      tid, LibVEX_EmNote_string(note));
+      /* XMM registers */
+#define COPY_IN_XMM(src, dest) \
+      do {                     \
+         dest[0] = src._l[0];  \
+         dest[1] = src._l[1];  \
+         dest[2] = src._l[2];  \
+         dest[3] = src._l[3];  \
+      } while (0)
+      COPY_IN_XMM(fs->xmm[0], tst->arch.vex.guest_XMM0);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[0],
+               offsetof(VexGuestX86State, guest_XMM0), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[1], tst->arch.vex.guest_XMM1);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[1],
+               offsetof(VexGuestX86State, guest_XMM1), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[2], tst->arch.vex.guest_XMM2);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[2],
+               offsetof(VexGuestX86State, guest_XMM2), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[3], tst->arch.vex.guest_XMM3);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[3],
+               offsetof(VexGuestX86State, guest_XMM3), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[4], tst->arch.vex.guest_XMM4);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[4],
+               offsetof(VexGuestX86State, guest_XMM4), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[5], tst->arch.vex.guest_XMM5);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[5],
+               offsetof(VexGuestX86State, guest_XMM5), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[6], tst->arch.vex.guest_XMM6);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[6],
+               offsetof(VexGuestX86State, guest_XMM6), sizeof(U128));
+      COPY_IN_XMM(fs->xmm[7], tst->arch.vex.guest_XMM7);
+      VG_TRACK(copy_mem_to_reg, part, tid, (Addr)&fs->xmm[7],
+               offsetof(VexGuestX86State, guest_XMM7), sizeof(U128));
+#undef COPY_IN_XMM
+   }
+}
+
+/* Allocate GDT for a given thread. */
+void ML_(setup_gdt)(VexGuestX86State *vex)
+{
+   Addr gdt = (Addr)VG_(calloc)("syswrap-solaris-x86.gdt",
+                                VEX_GUEST_X86_GDT_NENT,
+                                sizeof(VexGuestX86SegDescr));
+   vex->guest_GDT = gdt;
+}
+
+/* Deallocate GDT for a given thread. */
+void ML_(cleanup_gdt)(VexGuestX86State *vex)
+{
+   if (!vex->guest_GDT)
+      return;
+   VG_(free)((void*)vex->guest_GDT);
+   vex->guest_GDT = 0;
+}
+
+/* For a given thread, update the LWPGS descriptor in the thread's GDT
+   according to the thread pointer. */
+void ML_(update_gdt_lwpgs)(ThreadId tid)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   Addr base = tst->os_state.thrptr;
+   VexGuestX86SegDescr *gdt = (VexGuestX86SegDescr*)tst->arch.vex.guest_GDT;
+   VexGuestX86SegDescr desc;
+
+   vg_assert(gdt);
+
+   VG_(memset)(&desc, 0, sizeof(desc));
+   if (base) {
+      desc.LdtEnt.Bits.LimitLow = -1;
+      desc.LdtEnt.Bits.LimitHi = -1;
+      desc.LdtEnt.Bits.BaseLow = base & 0xffff;
+      desc.LdtEnt.Bits.BaseMid = (base >> 16) & 0xff;
+      desc.LdtEnt.Bits.BaseHi = (base >> 24) & 0xff;
+      desc.LdtEnt.Bits.Pres = 1;
+      desc.LdtEnt.Bits.Dpl = 3; /* SEL_UPL */
+      desc.LdtEnt.Bits.Type = 19; /* SDT_MEMRWA */
+      desc.LdtEnt.Bits.Granularity = 1; /* SDP_PAGES */
+      desc.LdtEnt.Bits.Default_Big = 1; /* SDP_OP32 */
+   }
+
+   gdt[VKI_GDT_LWPGS] = desc;
+
+   /* Write %gs. */
+   tst->arch.vex.guest_GS = VKI_LWPGS_SEL;
+   VG_TRACK(post_reg_write, Vg_CoreSysCall, tid, OFFSET_x86_GS,
+            sizeof(UShort));
+}
+
+
+/* ---------------------------------------------------------------------
+   PRE/POST wrappers for x86/Solaris-specific syscalls
+   ------------------------------------------------------------------ */
+
+#define PRE(name)       DEFN_PRE_TEMPLATE(x86_solaris, name)
+#define POST(name)      DEFN_POST_TEMPLATE(x86_solaris, name)
+
+/* implementation */
+
+PRE(sys_fstatat64)
+{
+   /* int fstatat64(int fildes, const char *path, struct stat64 *buf,
+                    int flag); */
+   PRINT("sys_fstatat64 ( %ld, %#lx(%s), %#lx, %ld )", ARG1, ARG2,
+         (char*)ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "fstatat64", int, fildes, const char *, path,
+                 struct stat64 *, buf, int, flag);
+   if (ARG2)
+      PRE_MEM_RASCIIZ("fstatat64(path)", ARG2);
+   PRE_MEM_WRITE("fstatat64(buf)", ARG3, sizeof(struct vki_stat64));
+
+   /* Be strict. */
+   if (ARG1 != VKI_AT_FDCWD &&
+       !ML_(fd_allowed)(ARG1, "fstatat64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstatat64)
+{
+   POST_MEM_WRITE(ARG3, sizeof(struct vki_stat64));
+}
+
+PRE(sys_openat64)
+{
+   /* int openat64(int fildes, const char *filename, int flags);
+      int openat64(int fildes, const char *filename, int flags, mode_t mode);
+    */
+   *flags |= SfMayBlock;
+
+   if (ARG3 & VKI_O_CREAT) {
+      /* 4-arg version */
+      PRINT("sys_openat64 ( %ld, %#lx(%s), %ld, %ld )", ARG1, ARG2,
+            (char*)ARG2, ARG3, ARG4);
+      PRE_REG_READ4(long, "openat64", int, fildes, const char *, filename,
+                    int, flags, vki_mode_t, mode);
+   }
+   else {
+      /* 3-arg version */
+      PRINT("sys_openat64 ( %ld, %#lx(%s), %ld )", ARG1, ARG2, (char*)ARG2,
+            ARG3);
+      PRE_REG_READ3(long, "openat64", int, fildes, const char *, filename,
+                    int, flags);
+   }
+
+   PRE_MEM_RASCIIZ("openat64(filename)", ARG2);
+
+   /* Be strict. */
+   if (ARG1 != VKI_AT_FDCWD && !ML_(fd_allowed)(ARG1, "openat64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_openat64)
+{
+   if (!ML_(fd_allowed)(RES, "openat64", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure(VKI_EMFILE);
+   }
+   else if (VG_(clo_track_fds))
+      ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG2);
+}
+
+PRE(sys_llseek32)
+{
+   /* offset_t llseek(int fildes, offset_t offset, int whence); */
+   PRINT("sys_llseek32 ( %ld, %#lx, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "llseek", int, fildes, vki_u32, offset_low,
+                 vki_u32, offset_high, int, whence);
+
+   /* Stay sane. */
+   if (!ML_(fd_allowed)(ARG1, "llseek", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_mmap64)
+{
+   /* void *mmap64(void *addr, size_t len, int prot, int flags,
+                   int fildes, uint32_t offlo, uint32_t offhi); */
+   /* Note this wrapper assumes a little-endian architecture, offlo and offhi
+      have to be swapped if a big-endian architecture is present. */
+#if !defined(VG_LITTLEENDIAN)
+#error "Unexpected endianness."
+#endif /* !VG_LITTLEENDIAN */
+
+   SysRes r;
+   ULong u;
+   Off64T offset;
+
+   /* Stay sane. */
+   vg_assert(VKI_PAGE_SIZE == 4096);
+   vg_assert(sizeof(u) == sizeof(offset));
+
+   PRINT("sys_mmap ( %#lx, %#lx, %#lx, %#lx, %ld, %#lx, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+   PRE_REG_READ7(long, "mmap", void *, start, vki_size_t, length,
+                 int, prot, int, flags, int, fd, uint32_t, offlo,
+                 uint32_t, offhi);
+
+   /* The offlo and offhi values can actually represent a negative value.
+      Make sure it's passed correctly to the generic mmap wrapper. */
+   u = ((ULong)ARG7 << 32) + ARG6;
+   offset = *(Off64T*)&u;
+
+   r = ML_(generic_PRE_sys_mmap)(tid, ARG1, ARG2, ARG3, ARG4, ARG5, offset);
+   SET_STATUS_from_SysRes(r);
+}
+
+PRE(sys_stat64)
+{
+   /* int stat64(const char *path, struct stat64 *buf); */
+   PRINT("sys_stat64 ( %#lx(%s), %#lx )", ARG1, (char*)ARG1, ARG2);
+   PRE_REG_READ2(long, "stat64", const char *, path, struct stat64 *, buf);
+
+   PRE_MEM_RASCIIZ("stat64(path)", ARG1);
+   PRE_MEM_WRITE("stat64(buf)", ARG2, sizeof(struct vki_stat64));
+}
+
+POST(sys_stat64)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat64));
+}
+
+PRE(sys_lstat64)
+{
+   /* int lstat64(const char *path, struct stat64 *buf); */
+   PRINT("sys_lstat64 ( %#lx(%s), %#lx )", ARG1, (char*)ARG1, ARG2);
+   PRE_REG_READ2(long, "lstat64", const char *, path, struct stat64 *, buf);
+
+   PRE_MEM_RASCIIZ("lstat64(path)", ARG1);
+   PRE_MEM_WRITE("lstat64(buf)", ARG2, sizeof(struct vki_stat64));
+}
+
+POST(sys_lstat64)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat64));
+}
+
+PRE(sys_fstat64)
+{
+   /* int fstat64(int fildes, struct stat64 *buf); */
+   PRINT("sys_fstat64 ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "fstat64", int, fildes, struct stat64 *, buf);
+   PRE_MEM_WRITE("fstat64(buf)", ARG2, sizeof(struct vki_stat64));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fstat64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstat64)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_stat64));
+}
+
+static void do_statvfs64_post(struct vki_statvfs64 *stats, ThreadId tid)
+{
+   POST_FIELD_WRITE(stats->f_bsize);
+   POST_FIELD_WRITE(stats->f_frsize);
+   POST_FIELD_WRITE(stats->f_blocks);
+   POST_FIELD_WRITE(stats->f_bfree);
+   POST_FIELD_WRITE(stats->f_bavail);
+   POST_FIELD_WRITE(stats->f_files);
+   POST_FIELD_WRITE(stats->f_ffree);
+   POST_FIELD_WRITE(stats->f_favail);
+   POST_FIELD_WRITE(stats->f_fsid);
+   POST_MEM_WRITE((Addr) stats->f_basetype, VG_(strlen)(stats->f_basetype) + 1);
+   POST_FIELD_WRITE(stats->f_flag);
+   POST_FIELD_WRITE(stats->f_namemax);
+   POST_MEM_WRITE((Addr) stats->f_fstr, VG_(strlen)(stats->f_fstr) + 1);
+}
+
+PRE(sys_statvfs64)
+{
+   /* int statvfs64(const char *path, struct statvfs64 *buf); */
+   *flags |= SfMayBlock;
+   PRINT("sys_statvfs64 ( %#lx(%s), %#lx )", ARG1, (HChar *) ARG1, ARG2);
+   PRE_REG_READ2(long, "statvfs64", const char *, path,
+                 struct vki_statvfs64 *, buf);
+   PRE_MEM_RASCIIZ("statvfs64(path)", ARG1);
+   PRE_MEM_WRITE("statvfs64(buf)", ARG2, sizeof(struct vki_statvfs64));
+}
+
+POST(sys_statvfs64)
+{
+   do_statvfs64_post((struct vki_statvfs64 *) ARG2, tid);
+}
+
+PRE(sys_fstatvfs64)
+{
+   /* int fstatvfs64(int fd, struct statvfs64 *buf); */
+   *flags |= SfMayBlock;
+   PRINT("sys_fstatvfs64 ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "fstatvfs64", int, fd, struct vki_statvfs64 *, buf);
+   PRE_MEM_WRITE("fstatvfs64(buf)", ARG2, sizeof(struct vki_statvfs64));
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "fstatvfs64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_fstatvfs64)
+{
+   do_statvfs64_post((struct vki_statvfs64 *) ARG2, tid);
+}
+
+PRE(sys_setrlimit64)
+{
+   /* int setrlimit64(int resource, struct rlimit64 *rlim); */
+   struct vki_rlimit64 *limit = (struct vki_rlimit64 *)ARG2;
+   PRINT("sys_setrlimit64 ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "setrlimit64", int, resource, struct rlimit64 *, rlim);
+   PRE_MEM_READ("setrlimit64(rlim)", ARG2, sizeof(struct vki_rlimit64));
+
+   if (limit && limit->rlim_cur > limit->rlim_max)
+      SET_STATUS_Failure(VKI_EINVAL);
+   else if (ARG1 == VKI_RLIMIT_NOFILE) {
+      if (limit->rlim_cur > VG_(fd_hard_limit) ||
+          limit->rlim_max != VG_(fd_hard_limit)) {
+         SET_STATUS_Failure(VKI_EPERM);
+      }
+      else {
+         VG_(fd_soft_limit) = limit->rlim_cur;
+         SET_STATUS_Success(0);
+      }
+   }
+   else if (ARG1 == VKI_RLIMIT_DATA) {
+      if (limit->rlim_cur > VG_(client_rlimit_data).rlim_max ||
+          limit->rlim_max > VG_(client_rlimit_data).rlim_max) {
+         SET_STATUS_Failure(VKI_EPERM);
+      }
+      else {
+         VG_(client_rlimit_data).rlim_max = limit->rlim_max;
+         VG_(client_rlimit_data).rlim_cur = limit->rlim_cur;
+         SET_STATUS_Success(0);
+      }
+   }
+   else if (ARG1 == VKI_RLIMIT_STACK && tid == 1) {
+      if (limit->rlim_cur > VG_(client_rlimit_stack).rlim_max ||
+          limit->rlim_max > VG_(client_rlimit_stack).rlim_max) {
+         SET_STATUS_Failure(VKI_EPERM);
+      }
+      else {
+         /* Change the value of client_stack_szB to the rlim_cur value but
+            only if it is smaller than the size of the allocated stack for the
+            client. */
+         if (limit->rlim_cur <= VG_(clstk_max_size))
+            VG_(threads)[tid].client_stack_szB = limit->rlim_cur;
+
+         VG_(client_rlimit_stack).rlim_max = limit->rlim_max;
+         VG_(client_rlimit_stack).rlim_cur = limit->rlim_cur;
+         SET_STATUS_Success(0);
+      }
+   }
+}
+
+PRE(sys_getrlimit64)
+{
+   /* int getrlimit64(int resource, struct rlimit64 *rlim); */
+   PRINT("sys_getrlimit64 ( %ld, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(long, "getrlimit64",
+                 int, resource, struct rlimit64 *, rlim);
+   PRE_MEM_WRITE("getrlimit64(rlim)", ARG2, sizeof(struct vki_rlimit64));
+}
+
+POST(sys_getrlimit64)
+{
+   /* Based on common_post_getrlimit() from syswrap-generic.c. */
+   struct vki_rlimit64 *rlim = (struct vki_rlimit64*)ARG2;
+
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_rlimit64));
+
+   switch (ARG1 /*resource*/) {
+   case VKI_RLIMIT_NOFILE:
+      rlim->rlim_cur = VG_(fd_soft_limit);
+      rlim->rlim_max = VG_(fd_hard_limit);
+      break;
+   case VKI_RLIMIT_DATA:
+      rlim->rlim_cur = VG_(client_rlimit_data).rlim_cur;
+      rlim->rlim_max = VG_(client_rlimit_data).rlim_max;
+      break;
+   case VKI_RLIMIT_STACK:
+      rlim->rlim_cur = VG_(client_rlimit_stack).rlim_cur;
+      rlim->rlim_max = VG_(client_rlimit_stack).rlim_max;
+      break;
+   }
+}
+
+PRE(sys_pread64)
+{
+   /* ssize32_t pread64(int fd, void *buf, size32_t count,
+                        uint32_t offset_1, uint32_t offset_2);
+    */
+   *flags |= SfMayBlock;
+   PRINT("sys_pread64 ( %ld, %#lx, %ld, %ld, %ld )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "pread64", int, fd, void *, buf, vki_size32_t, count,
+                 vki_uint32_t, offset_1, vki_uint32_t, offset_2);
+   PRE_MEM_WRITE("pread64(buf)", ARG2, ARG3);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "pread64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+POST(sys_pread64)
+{
+   POST_MEM_WRITE(ARG2, RES);
+}
+
+PRE(sys_pwrite64)
+{
+   /* ssize32_t pwrite64(int fd, void *buf, size32_t count,
+                         uint32_t offset_1, uint32_t offset_2);
+    */
+   *flags |= SfMayBlock;
+   PRINT("sys_pwrite64 ( %ld, %#lx, %ld, %ld, %ld )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "pwrite64", int, fd, void *, buf, vki_size32_t, count,
+                 vki_uint32_t, offset_1, vki_uint32_t, offset_2);
+   PRE_MEM_READ("pwrite64(buf)", ARG2, ARG3);
+
+   /* Be strict. */
+   if (!ML_(fd_allowed)(ARG1, "pwrite64", tid, False))
+      SET_STATUS_Failure(VKI_EBADF);
+}
+
+PRE(sys_open64)
+{
+   /* int open64(const char *filename, int flags);
+      int open64(const char *filename, int flags, mode_t mode); */
+   *flags |= SfMayBlock;
+
+   if (ARG2 & VKI_O_CREAT) {
+      /* 3-arg version */
+      PRINT("sys_open64 ( %#lx(%s), %ld, %ld )", ARG1, (char*)ARG1, ARG2,
+            ARG3);
+      PRE_REG_READ3(long, "open64", const char *, filename, int, flags,
+                    vki_mode_t, mode);
+   }
+   else {
+      /* 2-arg version */
+      PRINT("sys_open64 ( %#lx(%s), %ld )", ARG1, (char*)ARG1, ARG2);
+      PRE_REG_READ2(long, "open64", const char *, filename, int, flags);
+   }
+   PRE_MEM_RASCIIZ("open(filename)", ARG1);
+}
+
+POST(sys_open64)
+{
+   if (!ML_(fd_allowed)(RES, "open64", tid, True)) {
+      VG_(close)(RES);
+      SET_STATUS_Failure(VKI_EMFILE);
+   }
+   else if (VG_(clo_track_fds))
+      ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG1);
+}
+
+#undef PRE
+#undef POST
+
+#endif // defined(VGP_x86_solaris)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_tooliface.c b/coregrind/m_tooliface.c
index 40d8325..2932849 100644
--- a/coregrind/m_tooliface.c
+++ b/coregrind/m_tooliface.c
@@ -441,6 +441,9 @@
 DEF0(track_pre_reg_read,          CorePart, ThreadId, const HChar*, PtrdiffT, SizeT)
 DEF0(track_post_reg_write,        CorePart, ThreadId,               PtrdiffT, SizeT)
 
+DEF0(track_copy_mem_to_reg,       CorePart, ThreadId, Addr, PtrdiffT, SizeT)
+DEF0(track_copy_reg_to_mem,       CorePart, ThreadId, PtrdiffT, Addr, SizeT)
+
 DEF0(track_post_reg_write_clientcall_return, ThreadId, PtrdiffT, SizeT, Addr)
 
 DEF0(track_start_client_code,     ThreadId, ULong)
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index 027f9f6..189479c 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -1329,6 +1329,7 @@
 #	undef UD2_1024
 #	undef UD2_PAGE
 
+/*---------------------- tilegx-linux ----------------------*/
 #else
 #if defined(VGP_tilegx_linux)
 
@@ -1399,6 +1400,186 @@
 #	undef UD2_4K
 #	undef UD2_16K
 #	undef UD2_PAGE
+
+/*---------------- x86-solaris ----------------*/
+#else
+#if defined(VGP_x86_solaris)
+
+.global VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+/* int strcmp(const char *s1, const char *s2); */
+.global VG_(x86_solaris_REDIR_FOR_strcmp)
+.type   VG_(x86_solaris_REDIR_FOR_strcmp), @function
+VG_(x86_solaris_REDIR_FOR_strcmp):
+        pushl   %ebp                    /* establish a stack frame */
+        movl    %esp, %ebp
+        movl    8(%ebp), %edx           /* get s1 */
+        movl    12(%esp), %ecx          /* get s2 */
+        jmp     2f                      /* go compare the first characters */
+1:
+        incl    %edx                    /* skip to the next s1 character */
+        incl    %ecx                    /* skip to the next s2 character */
+2:
+        movzbl  (%edx), %eax            /* load a character from s1 */
+        testb   %al, %al                /* is it null? */
+        jz      3f                      /* yes, exit */
+        cmpb    (%ecx), %al             /* are the characters equal? */
+        je      1b                      /* yes, proceed with next characters */
+3:
+        movzbl  (%ecx), %edx            /* load a character from s2 */
+        subl    %edx, %eax              /* calculate the return value */
+        popl    %ebp                    /* destroy the stack frame */
+        ret                             /* return to the caller */
+.size VG_(x86_solaris_REDIR_FOR_strcmp), .-VG_(x86_solaris_REDIR_FOR_strcmp)
+
+/* size_t strlen(const char *s); */
+.global VG_(x86_solaris_REDIR_FOR_strlen)
+.type   VG_(x86_solaris_REDIR_FOR_strlen), @function
+VG_(x86_solaris_REDIR_FOR_strlen):
+        pushl   %ebp                    /* establish a stack frame */
+        movl    %esp, %ebp
+        movl    8(%ebp), %edx           /* get s */
+        movl    %edx, %eax              /* copy s */
+        jmp     2f                      /* go handle the first character */
+1:
+        incl    %eax                    /* skip to the next s character */
+2:
+        cmpb    $0, (%eax)              /* is the s character null? */
+        jne     1b                      /* no, go process the next character */
+        subl    %edx, %eax              /* calculate the return value */
+        popl    %ebp                    /* destroy the stack frame */
+        ret                             /* return to the caller */
+.size VG_(x86_solaris_REDIR_FOR_strlen), .-VG_(x86_solaris_REDIR_FOR_strlen)
+
+.global VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+/*---------------- amd64-solaris ----------------*/
+#else
+#if defined(VGP_amd64_solaris)
+
+.global VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+/* char *strcpy(char *restrict s1, const char *restrict s2); */
+.global VG_(amd64_solaris_REDIR_FOR_strcpy)
+.type   VG_(amd64_solaris_REDIR_FOR_strcpy), @function
+VG_(amd64_solaris_REDIR_FOR_strcpy):
+        pushq   %rbp                    /* establish a stack frame */
+        movq    %rsp, %rbp
+        movq    %rdi, %rdx              /* copy s1 */
+1:
+        movzbl  (%rsi), %eax            /* load one input character */
+        movb    %al, (%rdx)             /* copy to output/s2 */
+        incq    %rsi                    /* skip to the next output character */
+        incq    %rdx                    /* skip to the next input character */
+        testb   %al, %al                /* is the copied character null? */
+        jnz     1b                      /* no, copy the next character */
+        leave                           /* destroy the stack frame */
+        movq    %rdi, %rax              /* set s1 as the return value */
+        ret                             /* return to the caller */
+.size VG_(amd64_solaris_REDIR_FOR_strcpy), .-VG_(amd64_solaris_REDIR_FOR_strcpy)
+
+/* char *strncpy(char *restrict s1, const char *restrict s2, size_t n); */
+.global VG_(amd64_solaris_REDIR_FOR_strncpy)
+.type   VG_(amd64_solaris_REDIR_FOR_strncpy), @function
+VG_(amd64_solaris_REDIR_FOR_strncpy):
+        pushq   %rbp                    /* establish a stack frame */
+        movq    %rsp, %rbp
+        movq    %rdi, %rcx              /* copy s1 */
+1:
+        testq   %rdx, %rdx              /* is the remaining size zero? */
+        jz      3f                      /* yes, all done */
+        movzbl  (%rsi), %eax            /* load one input character */
+        movb    %al, (%rcx)             /* copy to output/s2 */
+        decq    %rdx                    /* decrement the remaining size */
+        incq    %rsi                    /* skip to the next output character */
+        incq    %rcx                    /* skip to the next input character */
+        testb   %al, %al                /* is the copied character null? */
+        jnz     1b                      /* no, copy the next character */
+2:
+        testq   %rdx, %rdx              /* is the remaining size zero? */
+        jz      3f                      /* yes, all done */
+        movb    $0, (%rdx)              /* copy null to output/s2 */
+        decq    %rdx                    /* decrement the remaining size */
+        incq    %rsi                    /* skip to next output character */
+        jmp     2b                      /* proceed with the next character */
+3:
+        leave                           /* destroy the stack frame */
+        movq    %rdi, %rax              /* set s1 as the return value */
+        ret                             /* return to the caller */
+.size VG_(amd64_solaris_REDIR_FOR_strncpy), .-VG_(amd64_solaris_REDIR_FOR_strncpy)
+
+/* int strcmp(const char *s1, const char *s2); */
+.global VG_(amd64_solaris_REDIR_FOR_strcmp)
+.type   VG_(amd64_solaris_REDIR_FOR_strcmp), @function
+VG_(amd64_solaris_REDIR_FOR_strcmp):
+        pushq   %rbp                    /* establish a stack frame */
+        movq    %rsp, %rbp
+        jmp     2f                      /* go compare the first characters */
+1:
+        incq    %rdi                    /* skip to the next s1 character */
+        incq    %rsi                    /* skip to the next s2 character */
+2:
+        movzbl  (%rdi), %eax            /* load a character from s1 */
+        testb   %al, %al                /* is it null? */
+        jz      3f                      /* yes, exit */
+        cmpb    (%rsi), %al             /* are the characters equal? */
+        je      1b                      /* yes, proceed with next characters */
+3:
+        movzbl  (%rsi), %edx            /* load a character from s2 */
+        subl    %edx, %eax              /* calculate the return value */
+        leave                           /* destroy the stack frame */
+        ret                             /* return to the caller */
+.size VG_(amd64_solaris_REDIR_FOR_strcmp), .-VG_(amd64_solaris_REDIR_FOR_strcmp)
+
+/* char *strcat(char *restrict s1, const char *restrict s2); */
+.global VG_(amd64_solaris_REDIR_FOR_strcat)
+.type   VG_(amd64_solaris_REDIR_FOR_strcat), @function
+VG_(amd64_solaris_REDIR_FOR_strcat):
+        pushq   %rbp                    /* establish a stack frame */
+        movq    %rsp, %rbp
+        movq    %rdi, %rdx              /* copy s1 */
+        jmp     2f                      /* go handle the first character */
+1:
+        incq    %rdx                    /* skip to the next s1 character */
+2:
+        cmpb    $0, (%rdx)              /* is the s1 character null? */
+        jne     1b                      /* no, go check the next character */
+3:
+        movzbl  (%rsi), %eax            /* load a character from s2 */
+        movb    %al, (%rdx)             /* copy the s2 character to s1 */
+        incq    %rdx                    /* skip to the next s1 character */
+        incq    %rsi                    /* skip to the next s2 character */
+        testb   %al, %al                /* was the character null? */
+        jnz     3b                      /* no, go copy the next character */
+        movq    %rdi, %rax              /* set s1 as the return value */
+        leave                           /* destroy the stack frame */
+        ret                             /* return to the caller */
+.size VG_(amd64_solaris_REDIR_FOR_strcat), .-VG_(amd64_solaris_REDIR_FOR_strcat)
+
+/* size_t strlen(const char *s); */
+.global VG_(amd64_solaris_REDIR_FOR_strlen)
+.type   VG_(amd64_solaris_REDIR_FOR_strlen), @function
+VG_(amd64_solaris_REDIR_FOR_strlen):
+        pushq   %rbp                    /* establish a stack frame */
+        movq    %rsp, %rbp
+        movq    %rdi, %rax              /* copy s */
+        jmp     2f                      /* go handle the first character */
+1:
+        incq    %rax                    /* skip to the next s character */
+2:
+        cmpb    $0, (%rax)              /* is the s character null? */
+        jne     1b                      /* no, go process the next character */
+        subq    %rdi, %rax              /* calculate the return value */
+        leave                           /* destroy the stack frame */
+        ret                             /* return to the caller */
+.size VG_(amd64_solaris_REDIR_FOR_strlen), .-VG_(amd64_solaris_REDIR_FOR_strlen)
+
+.global VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
 /*---------------- unknown ----------------*/
 #else
 #  error Unknown platform
@@ -1415,6 +1596,8 @@
 #endif
 #endif
 #endif
+#endif
+#endif
 
 #if defined(VGO_linux)
 /* Let the linker know we don't need an executable stack */
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index 86a3f4a..d277a24 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -1679,6 +1679,9 @@
    vex_abiinfo.guest_ppc_zap_RZ_at_bl         = const_True;
    vex_abiinfo.host_ppc_calls_use_fndescrs    = False;
 #  endif
+#  if defined(VGP_amd64_solaris)
+   vex_abiinfo.guest_amd64_assume_fs_is_const = True;
+#  endif
 
    /* Set up closure args. */
    closure.tid    = tid;
diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c
index 0e4c1cd..0516701 100644
--- a/coregrind/m_ume/elf.c
+++ b/coregrind/m_ume/elf.c
@@ -28,7 +28,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 
 #include "pub_core_basics.h"
 #include "pub_core_vki.h"
@@ -47,10 +47,15 @@
 #include "priv_ume.h"
 
 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
-#define _GNU_SOURCE
-#define _FILE_OFFSET_BITS 64
+#if defined(VGO_linux)
+#  define _GNU_SOURCE
+#  define _FILE_OFFSET_BITS 64
+#endif
 /* This is for ELF types etc, and also the AT_ constants. */
 #include <elf.h>
+#if defined(VGO_solaris)
+#  include <sys/fasttrap.h> // PT_SUNWDTRACE_SIZE
+#endif
 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
 
 
@@ -307,6 +312,9 @@
    Int i;
    void *entry;
    ESZ(Addr) ebase = 0;
+#  if defined(VGO_solaris)
+   ESZ(Addr) thrptr_addr = 0;
+#  endif
 
 #  if defined(HAVE_PIE)
    ebase = info->exe_base;
@@ -363,6 +371,18 @@
          if (ph->p_vaddr+ph->p_memsz > maxaddr)
             maxaddr = ph->p_vaddr+ph->p_memsz;
          break;
+
+#     if defined(VGO_solaris)
+      case PT_SUNWDTRACE:
+         if (ph->p_memsz < PT_SUNWDTRACE_SIZE ||
+             (ph->p_flags & (PF_R | PF_W | PF_X)) != (PF_R | PF_W | PF_X)) {
+            VG_(printf)("valgrind: m_ume.c: too small SUNWDTRACE size\n");
+            return VKI_ENOEXEC;
+         }
+
+         info->init_thrptr = ph->p_vaddr + ebase;
+         break;
+#     endif
                         
       case PT_INTERP: {
          HChar *buf = VG_(malloc)("ume.LE.1", ph->p_filesz+1);
@@ -392,6 +412,21 @@
             ESZ(Phdr) *iph = &interp->p[j];
             ESZ(Addr) end;
 
+#           if defined(VGO_solaris)
+            if (iph->p_type == PT_SUNWDTRACE) {
+               if (iph->p_memsz < PT_SUNWDTRACE_SIZE ||
+                   (iph->p_flags & (PF_R | PF_W | PF_X))
+                      != (PF_R | PF_W | PF_X)) {
+                  VG_(printf)("valgrind: m_ume.c: too small SUNWDTRACE size\n");
+                  return VKI_ENOEXEC;
+               }
+
+               /* Store the thrptr value into a temporary because we do not
+                  know yet where the interpreter is mapped. */
+               thrptr_addr = iph->p_vaddr;
+            }
+#           endif
+
             if (iph->p_type != PT_LOAD || iph->p_memsz == 0)
                continue;
             
@@ -409,9 +444,15 @@
          }
          break;
 
+#     if defined(PT_GNU_STACK) || defined(PT_SUNWSTACK)
 #     if defined(PT_GNU_STACK)
       /* Android's elf.h doesn't appear to have PT_GNU_STACK. */
       case PT_GNU_STACK:
+#     endif
+#     if defined(PT_SUNWSTACK)
+      /* Solaris-specific program header. */
+      case PT_SUNWSTACK:
+#     endif
          if ((ph->p_flags & PF_X) == 0) info->stack_prot &= ~VKI_PROT_EXEC;
          if ((ph->p_flags & PF_W) == 0) info->stack_prot &= ~VKI_PROT_WRITE;
          if ((ph->p_flags & PF_R) == 0) info->stack_prot &= ~VKI_PROT_READ;
@@ -494,6 +535,10 @@
       entry = (void *)(advised - interp_addr + interp->e.e_entry);
 
       info->interp_offset = advised - interp_addr;
+#     if defined(VGO_solaris)
+      if (thrptr_addr)
+         info->init_thrptr = thrptr_addr + info->interp_offset;
+#     endif
 
       VG_(free)(interp->p);
       VG_(free)(interp);
@@ -526,7 +571,7 @@
    return 0;
 }
 
-#endif // defined(VGO_linux)
+#endif // defined(VGO_linux) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c
index 11c6cc6..40dd460 100644
--- a/coregrind/m_ume/main.c
+++ b/coregrind/m_ume/main.c
@@ -51,7 +51,7 @@
 } ExeHandler;
 
 static ExeHandler exe_handlers[] = {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    { VG_(match_ELF),    VG_(load_ELF) },
 #  elif defined(VGO_darwin)
    { VG_(match_macho),  VG_(load_macho) },
diff --git a/coregrind/m_ume/priv_ume.h b/coregrind/m_ume/priv_ume.h
index 4f78190..30e3975 100644
--- a/coregrind/m_ume/priv_ume.h
+++ b/coregrind/m_ume/priv_ume.h
@@ -27,7 +27,7 @@
    The GNU General Public License is contained in the file COPYING.
 */
 
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 #ifndef __PRIV_UME_H
 #define __PRIV_UME_H
@@ -36,7 +36,7 @@
 
 extern Int VG_(do_exec_inner)(const HChar *exe, ExeInfo *info);
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 extern Bool VG_(match_ELF) ( const void *hdr, SizeT len );
 extern Int  VG_(load_ELF)  ( Int fd, const HChar *name, ExeInfo *info );
 #elif defined(VGO_darwin)
@@ -52,7 +52,7 @@
 
 #endif // __PRIV_UME_H
 
-#endif // defined(VGO_linux) || defined(VGO_darwin)
+#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/coregrind/m_vki.c b/coregrind/m_vki.c
index 2e1626b..8a83b05 100644
--- a/coregrind/m_vki.c
+++ b/coregrind/m_vki.c
@@ -76,7 +76,7 @@
 
    /* --- Platform-specific checks on signal sets --- */
 
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_solaris)
    /* nothing to check */
 #  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
    vg_assert(_VKI_NSIG == NSIG);
@@ -128,6 +128,14 @@
       syscall-amd64-darwin.S */
    vg_assert(VKI_SIG_SETMASK == 3);
 
+#  elif defined(VGO_solaris)
+   /* the toK- and fromK- forms are identical */
+   vg_assert(sizeof(vki_sigaction_toK_t)
+             == sizeof(vki_sigaction_fromK_t));
+   /* VKI_SET_SIGMASK is hardwired into syscall-x86-solaris.S
+      and syscall-amd64-solaris.S */
+   vg_assert(VKI_SIG_SETMASK == 3);
+
 #  else
 #     error "Unknown OS" 
 #  endif
diff --git a/coregrind/m_vkiscnums.c b/coregrind/m_vkiscnums.c
index 2e36551..e805248 100644
--- a/coregrind/m_vkiscnums.c
+++ b/coregrind/m_vkiscnums.c
@@ -86,6 +86,24 @@
 }
 
 //---------------------------------------------------------------------------
+#elif defined(VGO_solaris)
+//---------------------------------------------------------------------------
+
+const HChar *VG_(sysnum_string)(Word sysnum)
+{
+   static HChar buf[8+20+1];   // large enough
+
+   const HChar* classname = NULL;
+   switch (VG_SOLARIS_SYSNO_CLASS(sysnum)) {
+      case VG_SOLARIS_SYSCALL_CLASS_CLASSIC: classname = ""; break;
+      case VG_SOLARIS_SYSCALL_CLASS_FASTTRAP: classname = "fast:"; break;
+      default: classname = "UNKNOWN:"; break;
+   }
+   VG_(sprintf)(buf, "%s%ld", classname, VG_SOLARIS_SYSNO_INDEX(sysnum));
+   return buf;
+}
+
+//---------------------------------------------------------------------------
 #else
 //---------------------------------------------------------------------------
 #  error Unknown OS
diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h
index aefb43e..3f58d81 100644
--- a/coregrind/pub_core_aspacemgr.h
+++ b/coregrind/pub_core_aspacemgr.h
@@ -70,6 +70,9 @@
 // Querying current status
 
 
+/* Finds an anonymous segment containing 'a'. Returned pointer is read only. */
+extern NSegment const *VG_(am_find_anon_segment) ( Addr a );
+
 /* Find the next segment along from 'here', if it is a file/anon/resvn
    segment. */
 extern NSegment const* VG_(am_next_nsegment) ( const NSegment* here,
@@ -122,7 +125,9 @@
 /* Describes a request for VG_(am_get_advisory). */
 typedef
    struct {
-      enum { MFixed, MHint, MAny } rkind;
+      /* Note: if rkind == MAlign then start specifies alignment. This is
+         Solaris specific. */
+      enum { MFixed, MHint, MAny, MAlign } rkind;
       Addr start;
       Addr len;
    }
@@ -209,8 +214,14 @@
    segment array accordingly. */
 extern SysRes VG_(am_mmap_file_fixed_client)
    ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset );
+extern SysRes VG_(am_mmap_file_fixed_client_flags)
+   ( Addr start, SizeT length, UInt prot, UInt flags, Int fd, Off64T offset );
 extern SysRes VG_(am_mmap_named_file_fixed_client)
-   ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name );
+   ( Addr start, SizeT length, UInt prot, Int fd,
+     Off64T offset, const HChar *name );
+extern SysRes VG_(am_mmap_named_file_fixed_client_flags)
+   ( Addr start, SizeT length, UInt prot, UInt flags, Int fd,
+     Off64T offset, const HChar *name );
 
 /* Map anonymously at a fixed address for the client, and update
    the segment array accordingly. */
diff --git a/coregrind/pub_core_clientstate.h b/coregrind/pub_core_clientstate.h
index dc93d1f..7087fbe 100644
--- a/coregrind/pub_core_clientstate.h
+++ b/coregrind/pub_core_clientstate.h
@@ -46,9 +46,11 @@
 extern Addr  VG_(clstk_start_base); // *Initial* lowest byte address
 extern Addr  VG_(clstk_end);        // Highest byte address
 extern UWord VG_(clstk_id);      // client stack id
+extern SizeT VG_(clstk_max_size); // max size of the main threads's client stack
 
-/* linux only: where is the client auxv ? */
-/* This is setup as part of setup_client_stack in initimg-linux.c. */
+/* Linux and Solaris only: where is the client auxv? */
+/* This is setup as part of setup_client_stack in initimg-linux.c
+   or initimg-solaris.c, respectively. */
 extern UWord* VG_(client_auxv);
 
 extern Addr  VG_(brk_base);	 // start of brk
@@ -71,6 +73,11 @@
 /* Same as above, but for /proc/<pid>/auxv. */
 extern Int VG_(cl_auxv_fd);
 
+#if defined(VGO_solaris)
+/* Same as above, but for /proc/<pid>/psinfo. */
+extern Int VG_(cl_psinfo_fd);
+#endif /* VGO_solaris */
+
 // Client's original rlimit data and rlimit stack
 extern struct vki_rlimit VG_(client_rlimit_data);
 extern struct vki_rlimit VG_(client_rlimit_stack);
@@ -93,6 +100,8 @@
    VG_(get_StackTrace) in m_stacktrace.c for further info. */
 extern Addr VG_(client__dl_sysinfo_int80);
 
+/* Obtains the initial client stack pointer from the finalised image info. */
+extern Addr VG_(get_initial_client_SP)(void);
 
 /* glibc nptl pthread systems only, when no-nptl-pthread-stackcache
    was given in --sim-hints.
@@ -112,6 +121,12 @@
    way to disable the pthread stack cache. */
 extern SizeT* VG_(client__stack_cache_actsize__addr);
 
+#if defined(VGO_solaris)
+/* Address of variable vg_vfork_fildes in vgpreload_core.so.0
+   (vg_preloaded.c). */
+extern Int* VG_(vfork_fildes_addr);
+#endif
+
 #endif   // __PUB_CORE_CLIENTSTATE_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index bb57b33..5a99d15 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -62,7 +62,7 @@
    released by simply re-opening and closing the same file (even via
    different fd!).
 */
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
 extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd );
 
 extern void VG_(di_notify_munmap)( Addr a, SizeT len );
diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h
index 428b0c2..7a20c03 100644
--- a/coregrind/pub_core_initimg.h
+++ b/coregrind/pub_core_initimg.h
@@ -119,6 +119,30 @@
    Addr  initial_client_IP;
 };
 
+/* ------------------------- Solaris ------------------------- */
+
+#elif defined(VGO_solaris)
+
+struct _IICreateImageInfo {
+   /* ------ Mandatory fields ------ */
+   const HChar* toolname;
+   Addr    sp_at_startup;
+   Addr    clstack_end; /* highest stack addressable byte */
+   /* ------ Per-OS fields ------ */
+   HChar** argv;
+   HChar** envp;
+};
+
+struct _IIFinaliseImageInfo {
+   /* ------ Mandatory fields ------ */
+   SizeT clstack_max_size;
+   Addr  initial_client_SP;
+   /* ------ Per-OS fields ------ */
+   Addr  initial_client_IP;
+   Addr  initial_client_TOC;
+   UInt* client_auxv;
+   Addr  initial_client_TP; /* thread pointer */
+};
 
 #else
 #  error "Unknown OS"
diff --git a/coregrind/pub_core_libcassert.h b/coregrind/pub_core_libcassert.h
index 32cfc50..5a7931a 100644
--- a/coregrind/pub_core_libcassert.h
+++ b/coregrind/pub_core_libcassert.h
@@ -75,8 +75,9 @@
 
 /* Called when some unhandleable client behaviour is detected.
    Prints a msg and aborts. */
-extern void VG_(unimplemented) ( const HChar* msg )
-            __attribute__((__noreturn__));
+extern void VG_(unimplemented) ( const HChar* format, ... )
+            __attribute__((__noreturn__))
+            PRINTF_CHECK(1, 2);
 
 /* Show the state of various threads related information, such
    as the guest stacktrace for each thread.
diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h
index a1f1e9a..8c16b67 100644
--- a/coregrind/pub_core_libcproc.h
+++ b/coregrind/pub_core_libcproc.h
@@ -71,8 +71,11 @@
 // Environment manipulations
 extern HChar **VG_(env_setenv)   ( HChar ***envp, const HChar* varname,
                                    const HChar *val );
-extern void    VG_(env_unsetenv) ( HChar **env, const HChar *varname );
-extern void    VG_(env_remove_valgrind_env_stuff) ( HChar** env ); 
+extern void    VG_(env_unsetenv) ( HChar **env, const HChar *varname,
+                                   void (*free_fn) ( void *) );
+extern void    VG_(env_remove_valgrind_env_stuff) ( HChar** env,
+                                                    Bool ro_strings,
+                                                    void (*free_fn) (void *) );
 extern HChar **VG_(env_clone)    ( HChar **env_clone );
 
 // misc
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index 7fb7afe..a20681f 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -41,12 +41,12 @@
 #include "pub_core_basics.h"      // UnwindStartRegs
 
 // XXX: this is *really* the wrong spot for these things
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_solaris)
 #  define VG_ELF_DATA2XXX     ELFDATA2LSB
 #  define VG_ELF_MACHINE      EM_386
 #  define VG_ELF_CLASS        ELFCLASS32
 #  undef  VG_PLAT_USES_PPCTOC
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris)
 #  define VG_ELF_DATA2XXX     ELFDATA2LSB
 #  define VG_ELF_MACHINE      EM_X86_64
 #  define VG_ELF_CLASS        ELFCLASS64
@@ -169,6 +169,7 @@
 // Offsets for the Vex state
 #define VG_O_STACK_PTR        (offsetof(VexGuestArchState, VG_STACK_PTR))
 #define VG_O_INSTR_PTR        (offsetof(VexGuestArchState, VG_INSTR_PTR))
+#define VG_O_FRAME_PTR        (offsetof(VexGuestArchState, VG_FRAME_PTR))
 #define VG_O_FPC_REG          (offsetof(VexGuestArchState, VG_FPC_REG))
 
 
diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h
index eeb4aa1..e3f0820 100644
--- a/coregrind/pub_core_mallocfree.h
+++ b/coregrind/pub_core_mallocfree.h
@@ -63,9 +63,10 @@
 // This is both the minimum payload size of a malloc'd block, and its
 // minimum alignment.  Must be a power of 2 greater than 4, and should be
 // greater than 8.
-#if   defined(VGP_x86_linux)   || \
-      defined(VGP_arm_linux)   || \
-      defined(VGP_mips32_linux)
+#if   defined(VGP_x86_linux)    || \
+      defined(VGP_arm_linux)    || \
+      defined(VGP_mips32_linux) || \
+      defined(VGP_x86_solaris)
 #  define VG_MIN_MALLOC_SZB        8
 // Nb: We always use 16 bytes for Darwin, even on 32-bits, so it can be used
 // for any AltiVec- or SSE-related type.  This matches the Darwin libc.
@@ -80,7 +81,8 @@
       defined(VGP_x86_darwin)     || \
       defined(VGP_amd64_darwin)   || \
       defined(VGP_arm64_linux)    || \
-      defined(VGP_tilegx_linux)
+      defined(VGP_tilegx_linux)   || \
+      defined(VGP_amd64_solaris)
 #  define VG_MIN_MALLOC_SZB       16
 #else
 #  error Unknown platform
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 53ccfc0..a1239f8 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -220,6 +220,7 @@
 typedef
    enum {
       SimHint_lax_ioctls,
+      SimHint_lax_doors,
       SimHint_fuse_compatible,
       SimHint_enable_outer,
       SimHint_no_inner_prefix,
diff --git a/coregrind/pub_core_sigframe.h b/coregrind/pub_core_sigframe.h
index b1f385c..74f0d1b 100644
--- a/coregrind/pub_core_sigframe.h
+++ b/coregrind/pub_core_sigframe.h
@@ -41,9 +41,15 @@
 // frame appropriately.
 //--------------------------------------------------------------------
 
+/* This is an arbitrary si_code that we only use internally for SIGSEGV.
+   It corresponds to the value SI_KERNEL on Linux, but that's not really
+   of any significance. */
+#define VKI_SEGV_MADE_UP_GPF 0x80
+
 /* Create a signal frame for thread 'tid'. */
 extern 
 void VG_(sigframe_create) ( ThreadId tid, 
+                            Bool on_altstack,
                             Addr sp_top_of_frame,
                             const vki_siginfo_t *siginfo,
                             const struct vki_ucontext *uc,
@@ -57,6 +63,11 @@
 extern 
 void VG_(sigframe_destroy)( ThreadId tid, Bool isRT );
 
+#if defined(VGO_solaris)
+extern
+void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc);
+#endif
+
 #endif   // __PUB_CORE_SIGFRAME_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index e1563b4..b7ff146 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -87,6 +87,8 @@
 extern SysRes VG_(mk_SysRes_mips64_linux)( ULong v0, ULong v1,
                                            ULong a3 );
 extern SysRes VG_(mk_SysRes_tilegx_linux)( Long val );
+extern SysRes VG_(mk_SysRes_x86_solaris) ( Bool isErr, UInt val, UInt val2 );
+extern SysRes VG_(mk_SysRes_amd64_solaris) ( Bool isErr, ULong val, ULong val2 );
 extern SysRes VG_(mk_SysRes_Error)       ( UWord val );
 extern SysRes VG_(mk_SysRes_Success)     ( UWord val );
 
diff --git a/coregrind/pub_core_syswrap.h b/coregrind/pub_core_syswrap.h
index 49dbc1e..3c8047c 100644
--- a/coregrind/pub_core_syswrap.h
+++ b/coregrind/pub_core_syswrap.h
@@ -33,6 +33,7 @@
 
 #include "pub_core_basics.h"        // VG_ macro
 #include "pub_core_threadstate.h"   // ThreadArchState
+#include "pub_core_tooliface.h"     // CorePart
 
 //--------------------------------------------------------------------
 // PURPOSE: This module contains all the syscall junk:  mostly PRE/POST
@@ -58,9 +59,15 @@
                ThreadId tid,
                Addr     ip, 
                SysRes   sysret,
-               Bool     restart
+               Bool     restart,
+               struct vki_ucontext *uc
             );
 
+#if defined(VGO_solaris)
+// Determine if in a blocking syscall.
+extern Bool VG_(is_ip_in_blocking_syscall)(ThreadId tid, Addr ip);
+#endif
+
 // Wait until all other threads are dead
 extern void VG_(reap_threads)(ThreadId self);
 
@@ -80,6 +87,14 @@
 extern void (* VG_(address_of_m_main_shutdown_actions_NORETURN) )
             (ThreadId,VgSchedReturnCode);
 
+#if defined(VGO_solaris)
+extern void VG_(save_context)(ThreadId tid, vki_ucontext_t *uc,
+                              CorePart part);
+extern void VG_(restore_context)(ThreadId tid, vki_ucontext_t *uc,
+                                 CorePart part, Bool esp_is_thrptr);
+extern void VG_(syswrap_init)(void);
+#endif
+
 #endif   // __PUB_CORE_SYSWRAP_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index 28d8cb8..935ab3e 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -266,6 +266,53 @@
             char *path;
          } io_registry_entry_from_path;
       } mach_args;
+
+#     elif defined(VGO_solaris)
+#     if defined(VGP_x86_solaris)
+      /* A pointer to thread related data. The pointer is used to set up
+         a segment descriptor (GDT[VKI_GDT_LWPGS]) when the thread is about to
+         be run. A client program sets this value explicitly by calling the
+         lwp_private syscall or it can be passed as a part of ucontext_t when
+         a new thread is created (the lwp_create syscall). */
+      Addr thrptr;
+#     elif defined(VGP_amd64_solaris)
+      /* GDT is not fully simulated by AMD64/Solaris. The %fs segment
+         register is assumed to be always zero and vex->guest_FS_CONST holds
+         the 64-bit offset associated with a %fs value of zero. */
+#     endif
+
+      /* Stack id (value (UWord)(-1) means that there is no stack). This
+         tracks a stack that is set in restore_stack(). */
+      UWord stk_id;
+
+      /* Simulation of the kernel's lwp->lwp_ustack. Set in the PRE wrapper
+         of the getsetcontext syscall, for SETUSTACK. Used in
+         VG_(save_context)(), VG_(restore_context)() and
+         VG_(sigframe_create)(). */
+      vki_stack_t *ustack;
+
+      /* Flag saying if the current call is in the door_return() variant of
+         the door() syscall. */
+      Bool in_door_return;
+
+      /* Address of the door server procedure corresponding to the current
+         thread. Used to keep track which door call the current thread
+         services. Valid only between subsequent door_return() invocations. */
+      Addr door_return_procedure;
+
+      /* Simulation of the kernel's lwp->lwp_oldcontext. Set in
+         VG_(restore_context)() and VG_(sigframe_create)(). Used in
+         VG_(save_context)(). */
+      vki_ucontext_t *oldcontext;
+
+      /* Address of sc_shared_t struct shared between kernel and libc.
+         Set in POST(sys_schedctl). Every thread gets its own address
+         but typically many are squeezed on a singled mapped page.
+         Cleaned in the child atfork handler. */
+      Addr schedctl_data;
+
+      /* True if this is daemon thread. */
+      Bool daemon_thread;
 #     endif
 
    }
diff --git a/coregrind/pub_core_tooliface.h b/coregrind/pub_core_tooliface.h
index 6968a18..a2f1939 100644
--- a/coregrind/pub_core_tooliface.h
+++ b/coregrind/pub_core_tooliface.h
@@ -233,6 +233,9 @@
    void (*track_post_reg_write_clientcall_return)(ThreadId, PtrdiffT, SizeT,
                                                   Addr);
 
+   void (*track_copy_mem_to_reg)(CorePart, ThreadId, Addr, PtrdiffT, SizeT);
+   void (*track_copy_reg_to_mem)(CorePart, ThreadId, PtrdiffT, Addr, SizeT);
+
    void (*track_start_client_code)(ThreadId, ULong);
    void (*track_stop_client_code) (ThreadId, ULong);
 
diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h
index 7630729..ff96137 100644
--- a/coregrind/pub_core_trampoline.h
+++ b/coregrind/pub_core_trampoline.h
@@ -161,6 +161,20 @@
 extern UInt  VG_(mips64_linux_REDIR_FOR_strlen)( void* );
 #endif
 
+#if defined(VGP_x86_solaris)
+extern SizeT VG_(x86_solaris_REDIR_FOR_strcmp)(const HChar *, const HChar *);
+extern SizeT VG_(x86_solaris_REDIR_FOR_strlen)(const HChar *);
+#endif
+
+#if defined(VGP_amd64_solaris)
+extern HChar *VG_(amd64_solaris_REDIR_FOR_strcpy)(HChar *, const HChar *);
+extern HChar *VG_(amd64_solaris_REDIR_FOR_strncpy)(HChar *, const HChar *,
+                                                  SizeT);
+extern Int VG_(amd64_solaris_REDIR_FOR_strcmp)(const HChar *, const HChar *);
+extern HChar *VG_(amd64_solaris_REDIR_FOR_strcat)(HChar *, const HChar *);
+extern SizeT VG_(amd64_solaris_REDIR_FOR_strlen)(const HChar *);
+#endif
+
 #endif   // __PUB_CORE_TRAMPOLINE_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_ume.h b/coregrind/pub_core_ume.h
index 937778f..d9f6491 100644
--- a/coregrind/pub_core_ume.h
+++ b/coregrind/pub_core_ume.h
@@ -64,6 +64,10 @@
       HChar* executable_path; // OUT: path passed to execve()
 #endif
 
+#if defined(VGO_solaris)
+      Addr  init_thrptr; // OUT: architecture-specific user per-thread location
+#endif
+
       Addr entry;        // OUT: entrypoint in main executable
       Addr init_ip;      // OUT: address of first instruction to execute
       Addr brkbase;      // OUT: base address of brk segment
diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c
index fbb2e28..576e70f 100644
--- a/coregrind/vg_preloaded.c
+++ b/coregrind/vg_preloaded.c
@@ -192,8 +192,167 @@
     // but don't care if it's initialized
 }
 
-#else
+#elif defined(VGO_solaris)
 
+/* Declare the errno and environ symbols weakly in case the client is not
+   linked against libc. In such a case it also cannot run replacement
+   functions for set_error() and spawnveg() where these two variables are
+   needed so this is ok. */
+__attribute__((weak)) extern int errno;
+__attribute__((weak)) extern char **environ;
+
+#include <assert.h>
+#include <errno.h>
+#include <spawn.h>
+#include <sys/syscall.h>
+#include <sys/signal.h>
+#include <unistd.h>
+
+/* Replace function block_all_signals() from libc. When the client program is
+   not running under valgrind, the function blocks all signals by setting
+   sc_sigblock flag in the schedctl control block. When run under Valgrind
+   this would bypass Valgrind's syscall and signal machinery.
+   Valgrind's signal machinery needs to retain control over which signals are
+   blocked and which not (see m_signals.c and m_scheduler/scheduler.c for more
+   information - typically synchronous signals should not be blocked).
+   Therefore this function replacement emulates lwp_sigmask syscall.
+*/
+void VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, block_all_signals)(/*ulwp_t*/ void *self);
+void VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, block_all_signals)(/*ulwp_t*/ void *self)
+{
+   syscall(SYS_lwp_sigmask, SIG_SETMASK, ~0U, ~0U, ~0U, ~0U);
+}
+
+/* Replace functions get_error() and set_error() in libc. These functions are
+   internal to the library and are used to work with an error value returned
+   by posix_spawn() (when it is implemented using vfork()). A child calls
+   set_error() to set an error code and the parent then calls get_error() to
+   read it. Accessor functions are used so these trivial store+load operations
+   are not changed by the compiler in any way.
+
+   Since Valgrind translates vfork() to a normal fork(), calling set_error()
+   by the child would have no effect on the error value in the parent so
+   something must be done to fix this problem.
+
+   A pipe is created between a child and its parent in the forksys pre-wrapper
+   when a vfork() is encountered. The child's end of the pipe is closed when
+   the child exits or execs (because close-on-exec is set on the file
+   descriptor). Valgrind (the parent) waits on the child's end of the pipe to
+   be closed which preserves the vfork() behaviour that the parent process is
+   suspended while the child is using its resources.
+
+   The pipe is then used to send an eventual error code set by the child in
+   posix_spawn() to the parent. If there is any error Valgrind returns it as
+   an error from the vfork() syscall. This means the syscall can return errors
+   that it would normally never return but this is not a problem in practice
+   because any error is directly propagated as a return code from
+   posix_spawn().
+
+   Address of vg_vfork_fildes is found by Valgrind when debug information for
+   vgpreload_core.so is being processed. A value of this variable is set in
+   the forksys pre-wrapper before a fork() call is made and set back to -1
+   before returning from the wrapper by the parent.
+
+   Newer Solaris versions introduce the spawn syscall and posix_spawn() is
+   implemented using it. The redirect is not needed for these versions.
+*/
+int vg_vfork_fildes = -1;
+
+int VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, get_error)(int *errp);
+int VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, get_error)(int *errp)
+{
+   /* Always return 0 when the parent tries to call get_error(). Any error
+      from the child is returned directly as an error from the vfork child.
+      Value pointed by errp is initialized only by the child so not
+      redirecting this function would mean that the parent gets an
+      uninitialized/garbage value when it calls this function. */
+   return 0;
+}
+
+int VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, set_error)(int *errp, int err);
+int VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, set_error)(int *errp, int err)
+{
+   *errp = err;
+
+   /* Libc should always call set_error() only after doing a vfork() syscall
+      in posix_spawn(). The forksys pre-wrapper saves a descriptor of the
+      child's end of the pipe in vg_vfork_fildes so it is an error if it is
+      not a valid file descriptor at this point. */
+   assert(vg_vfork_fildes >= 0);
+   /* Current protocol between this function and the forksys pre-wrapper
+      allows to send only errors in range [0, 255] (one byte values). */
+   assert(err >= 0 && err <= 0xff);
+
+   if (err != 0) {
+      unsigned char w = (unsigned char)(err & 0xff);
+      ssize_t res;
+      do {
+         res = write(vg_vfork_fildes, &w, 1);
+         assert(res == 1 || (errno == EINTR || errno == ERESTART));
+      } while (res != 1);
+   }
+
+   return err;
+}
+
+/* Replace spawnveg() in libast.so.1. This function is used by ksh to spawn
+   new processes. The library has a build time option to select between
+   several variants of this function based on behaviour of vfork() and
+   posix_spawn() on the system for which the library is being compiled.
+   Unfortunately, Solaris and illumos use the real vfork() variant which does
+   not work correctly with the vfork() -> fork() translation done by Valgrind
+   (see the forksys pre-wrapper for details). Therefore the function is
+   replaced here with an implementation that uses posix_spawn(). This
+   replacement can be removed when a configuration of libast in Solaris and
+   illumos is changed to use the posix_spawn() implementation.
+*/
+pid_t VG_REPLACE_FUNCTION_ZU(libastZdsoZd1, spawnveg)(const char *command,
+                                                      char **argv,
+                                                      char **envv,
+                                                      pid_t pgid);
+pid_t VG_REPLACE_FUNCTION_ZU(libastZdsoZd1, spawnveg)(const char *command,
+                                                      char **argv,
+                                                      char **envp,
+                                                      pid_t pgid)
+{
+   int err = 0;
+   pid_t pid;
+   posix_spawnattr_t attr;
+   int attr_init_done = 0;
+
+   err = posix_spawnattr_init(&attr);
+   if (err != 0)
+      goto out;
+   attr_init_done = 1;
+
+   err = posix_spawnattr_init(&attr);
+   if (err != 0)
+      goto out;
+
+   if (pgid != 0) {
+      if (pgid <= 1)
+         pgid = 0;
+      err = posix_spawnattr_setpgroup(&attr, pgid);
+      if (err != 0)
+         goto out;
+      err = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETPGROUP);
+      if (err != 0)
+         goto out;
+   }
+
+   err = posix_spawn(&pid, command, NULL, &attr, argv, envp ? envp : environ);
+
+out:
+   if (attr_init_done)
+      posix_spawnattr_destroy(&attr);
+   if (err != 0) {
+      errno = err;
+      return -1;
+   }
+   return pid;
+}
+
+#else
 #  error Unknown OS
 #endif
 
diff --git a/coregrind/vgdb-invoker-solaris.c b/coregrind/vgdb-invoker-solaris.c
new file mode 100644
index 0000000..019441b
--- /dev/null
+++ b/coregrind/vgdb-invoker-solaris.c
@@ -0,0 +1,530 @@
+/*--------------------------------------------------------------------*/
+/*--- Implementation of vgdb invoker subsystem on Solaris             */
+/*                      via /proc filesystem and control messages. ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2014-2015 Ivo Raisr <ivosh@ivosh.net>
+
+   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.
+*/
+
+/* This module implements vgdb-invoker subsystem as per vgdb.h
+   on Solaris. It differs significantly from the other ptrace-based
+   implementation found in vgdb-invoker-ptrace.c. However the goal
+   is the same - to work on the following scenario:
+
+   - A valgrind process (referred to also as an inferior process)
+     is remotely debugged with gdb.
+   - All threads of the inferior process are stuck in blocking
+     syscalls.
+   - Therefore no thread can process packets received from gdb.
+
+   When module vgdb.c detects this situation then it calls
+   function invoker_invoke_gdbserver() within the context of
+   invoke_gdbserver_in_valgrind_thread thread. The steps of
+   interaction between vgdb and m_gdbserver module are as follows:
+
+   1. Function invoker_invoke_gdbserver() attaches to the inferior
+      process and stops all threads.
+   2. It gets registers of the first thread and modifies them
+      and the stack so that a call to "invoke_gdbserver" function
+      is arranged along with a function parameter.
+   3. Then it creates an agent thread within the inferior process
+      with these modified registers and waits until the agent thread
+      exits.
+   4. Meanwhile in the inferior process function
+      VG_(invoke_gdbserver)() is invoked within the context of the
+      agent thread; all other threads are still stopped.
+   5. The agent thread processes packets from gdb relayed by vgdb.
+   6. Eventually processing is finished and the agent thread exits
+      in function give_control_back_to_vgdb().
+   7. vgdb then detaches from the inferior process and thus resumes
+      all the stopped threads.
+ */
+
+#include "vgdb.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+typedef Addr CORE_ADDR;
+
+typedef struct {
+   long cmd;
+   union {
+       long flags;
+       prgregset_t regs;
+   } arg;
+} ctl_t;
+
+/* Process control file /proc/<pid>/ctl.
+   Once this file is closed, PR_RLC flag takes effect and
+   inferior process resumes automatically. */
+static int ctl_fd = -1;
+
+/* Copy LEN bytes of data from vgdb memory at MYADDR
+   to valgrind memory at MEMADDR.
+   On failure (cannot write the valgrind memory)
+   returns the value of errno. */
+static int write_memory(pid_t pid, CORE_ADDR memaddr,
+                        const void *myaddr, size_t len)
+{
+   char procname[PATH_MAX];
+   snprintf(procname, sizeof(procname), "/proc/%d/as", pid);
+
+   /* Open the process address-space file. */
+   int as_fd = open(procname, O_WRONLY, 0);
+   if (as_fd < 0) {
+      int error = errno;
+      ERROR(error, "Failed to open %s.\n", procname);
+      return error;
+   }
+
+   if (debuglevel >= 1) {
+      DEBUG(1, "Writing bytes '");
+      size_t i;
+      for (i = 0; i < len; i++)
+         PDEBUG(1, "%02x", ((const unsigned char *) myaddr)[i]);
+      PDEBUG(1, "' to address %#lx.\n", memaddr);
+   }
+
+   ssize_t written = pwrite(as_fd, myaddr, len, memaddr);
+   if ((written < 0) || (written != len)) {
+      int error = errno;
+      ERROR(error, "Failed to write to file %s, memory block of %zu"
+            " bytes at %#lx to %#lx.\n",
+            procname, len, (Addr) myaddr, memaddr);
+      close(as_fd);
+      return error;
+   }
+
+   DEBUG(1, "Written ok.\n");
+   close(as_fd);
+   return 0;
+}
+
+/* Attaches to a process identified by pid and stops all threads. */
+static Bool attach(pid_t pid)
+{
+   char procname[PATH_MAX];
+   snprintf(procname, sizeof(procname), "/proc/%d/ctl", pid);
+
+   DEBUG(1, "Attaching to pid %d.\n", pid);
+
+   /* Open the process control file. */
+   ctl_fd = open(procname, O_WRONLY, 0);
+   if (ctl_fd < 0) {
+      ERROR(errno, "Failed to open %s.\n", procname);
+      return False;
+   }
+
+   DEBUG(1, "Setting run-on-last-close-flag (PR_RLC) to pid %d.\n", pid);
+
+   /* Set run-on-last-close flag. */
+   ctl_t ctl;
+   ctl.cmd = PCSET;
+   ctl.arg.flags = PR_RLC;
+   size_t bytes = sizeof(ctl.cmd) + sizeof(ctl.arg.flags);
+   ssize_t written = write(ctl_fd, (void *) &ctl, bytes);
+   if ((written < 0) || (written != bytes)) {
+      ERROR(errno, "Failed to write to ctl_fd: PCSET + PR_RLC.\n");
+      return False;
+   }
+
+   DEBUG(1, "Stopping process %d.\n", pid);
+
+   /* Stop the whole process - all threads. */
+   ctl.cmd = PCSTOP;
+   bytes = sizeof(ctl.cmd);
+   written = write(ctl_fd, (void *) &ctl, bytes);
+   if ((written < 0) || (written != bytes)) {
+      ERROR(errno, "Failed to write to ctl_fd: PCSTOP.\n");
+      return False;
+   }
+
+   DEBUG(1, "Process %d stopped.\n", pid);
+
+   /* Now confirm it is actually the case. */
+   snprintf(procname, sizeof(procname), "/proc/%d/status", pid);
+   int status_fd = open(procname, O_RDONLY, 0);
+   if (status_fd < 0) {
+      ERROR(errno, "Failed to open %s.\n", procname);
+      return False;
+   }
+
+   pstatus_t pstatus;
+   bytes = read(status_fd, &pstatus, sizeof(pstatus));
+   if ((bytes < 0) || (bytes != sizeof(pstatus))) {
+      ERROR(errno, "Failed to read from %s.\n", procname);
+      close(status_fd);
+      return False;
+   }
+
+   if (pstatus.pr_flags & PR_RLC) {
+      DEBUG(2, "Process %d has run-on-last-close flag set. Good.\n", pid);
+   } else {
+      ERROR(0, "Process %d does not have run-on-last-close flag set!\n", pid);
+      close(status_fd);
+      return False;
+   }
+
+   if (pstatus.pr_lwp.pr_flags & PR_STOPPED) {
+      DEBUG(3, "Process %d seems to be stopped. Good.\n", pid);
+   } else {
+      ERROR(0, "Process %d is not stopped!\n", pid);
+      close(status_fd);
+      return False;
+   }
+
+   close(status_fd);
+   return True;
+}
+
+static void detach(pid_t pid)
+{
+   if (ctl_fd != -1) {
+      close(ctl_fd);
+      ctl_fd = -1;
+   }
+
+   DEBUG(1, "Detached from pid %d.\n", pid);
+}
+
+/* Gets the registers of the first thread. */
+static Bool get_regs(pid_t pid, prgregset_t *regs)
+{
+   char procname[PATH_MAX];
+   snprintf(procname, sizeof(procname), "/proc/%d/lwp/1/lwpstatus", pid);
+
+   DEBUG(1, "Getting registers from the first thread of process %d.\n", pid);
+
+   /* Open the first thread's status file. */
+   int status_fd = open(procname, O_RDONLY, 0);
+   if (status_fd < 0) {
+      ERROR(errno, "Failed to open file %s.\n", procname);
+      return False;
+   }
+
+   lwpstatus_t status;
+   ssize_t bytes = read(status_fd, &status, sizeof(status));
+   if ((bytes < 0) || (bytes != sizeof(status))) {
+      ERROR(errno, "Failed to read from %s.\n", procname);
+      close(status_fd);
+      return False;
+   }
+
+   DEBUG(3, "Registers of thread %d from process %d: ", status.pr_lwpid, pid);
+   unsigned int i;
+   for (i = 0; i < _NGREG; i++) {
+      PDEBUG(3, "%u: %#lx, ", i, (unsigned long) status.pr_reg[i]);
+   }
+   PDEBUG(3, "\n");
+
+   memcpy(regs, &status.pr_reg, sizeof(prgregset_t));
+   close(status_fd);
+   return True;
+}
+
+/* Modifies the register set so that a new stack frame is created
+   for "invoke_gdbserver" function with an extra argument.
+   The argument is written to the stack of the first thread.
+ */
+static Bool setup_stack_frame(pid_t pid, prgregset_t *regs)
+{
+   DEBUG(1, "Setting up new stack frame of process %d.\n", pid);
+
+   /* A specific int value is passed to invoke_gdbserver(), to check
+      everything goes according to the plan. */
+   const int check = 0x8BADF00D; // ate bad food.
+
+   /* A bad return address will be pushed on the stack.
+      Function invoke_gdbserver() cannot return. If it ever returns,
+      a NULL address pushed on the stack should ensure this is
+      detected. */
+   const Addr bad_return = 0;
+
+#if defined(VGA_x86)
+   Addr sp = (*regs)[UESP];
+#elif defined(VGA_amd64)
+   Addr sp = (*regs)[REG_RSP];
+#else
+   I_die_here : (sp) architecture missing in vgdb-invoker-solaris.c
+#endif
+
+   if (shared32 != NULL) {
+      /* vgdb speaking with a 32bit executable. */
+#if   defined(VGA_x86) || defined(VGA_amd64)
+      const size_t regsize = 4;
+
+      /* Push check argument on the stack - according to C/ia32 ABI. */
+      sp = sp - regsize;
+      DEBUG(1, "Pushing check argument to process %d memory.\n", pid);
+      assert(regsize == sizeof(check));
+      int error = write_memory(pid, sp, &check, regsize);
+      if (error != 0) {
+         ERROR(error, "Failed to push check argument to process %d memory.\n",
+                      pid);
+         detach(pid);
+         return False;
+      }
+
+      sp = sp - regsize;
+      DEBUG(1, "Pushing bad_return return address to process %d memory.\n",
+               pid);
+      /* Note that even for a 64 bits vgdb, only 4 bytes
+         of NULL bad_return are written. */
+      error = write_memory(pid, sp, &bad_return, regsize);
+      if (error != 0) {
+         ERROR(error, "Failed to push bad_return return address to process %d "
+                      "memory.\n", pid);
+         detach(pid);
+         return False;
+      }
+
+#if   defined(VGA_x86)
+      /* Set EBP, ESP, EIP to invoke gdbserver.
+         vgdb is 32bits, speaking with a 32bits process. */
+      (*regs)[EBP] = sp; // bp set to sp
+      (*regs)[UESP] = sp;
+      (*regs)[EIP] = shared32->invoke_gdbserver;
+#elif defined(VGA_amd64)
+      /* Set RBP, RSP, RIP to invoke gdbserver.
+         vgdb is 64bits, speaking with a 32bits process. */
+      (*regs)[REG_RBP] = sp; // bp set to sp
+      (*regs)[REG_RSP] = sp;
+      (*regs)[REG_RIP] = shared32->invoke_gdbserver;
+#else
+      I_die_here : not x86 or amd64 in x86/amd64 section/
+#endif
+
+#else
+      I_die_here : architecture missing in vgdb-invoker-solaris.c
+#endif
+
+   } else if (shared64 != NULL) {
+#if defined(VGA_x86)
+      assert(0); /* 64bits process with a 32bits vgdb - no way */
+#elif defined(VGA_amd64)
+      /* 64bits vgdb speaking with a 64 bit process. */
+      const int regsize = 8;
+
+      /* Give check argument in rdi - according to C/amd64 ABI. */
+      (*regs)[REG_RDI] = check;
+
+      /* Push return address on stack: return to breakaddr. */
+      sp = sp - regsize;
+      DEBUG(1, "Pushing bad_return return address to process %d memory.\n",
+               pid);
+      int error = write_memory(pid, sp, &bad_return,
+                               sizeof(bad_return));
+      if (error != 0) {
+         ERROR(error, "Failed to push bad_return return address to process %d "
+                      "memory.\n", pid);
+         detach(pid);
+         return False;
+      }
+
+      /* set RBP, RSP, RIP to invoke gdbserver */
+      (*regs)[REG_RBP] = sp; // bp set to sp
+      (*regs)[REG_RSP] = sp;
+      (*regs)[REG_RIP] = shared64->invoke_gdbserver;
+#else
+      I_die_here: architecture missing in vgdb-invoker-solaris.c
+#endif
+   } else {
+      assert(0);
+   }
+
+   DEBUG(1, "New stack frame set up for process %d.\n", pid);
+   return True;
+}
+
+/* Creates and starts an agent thread within the inferior process.
+   The agent thread is created stopped and with its held signal set
+   (the signal mask) having all signals except SIGKILL and SIGSTOP
+   blocked. All these signals need to remain blocked while the agent
+   thread is running because valgrind syscall/signal machinery expects
+   that (remember: all valgrind threads are blocked in VgTs_WaitSys
+   - that is the reason why we are invoking the agent, after all).
+   It is necessary to resume the agent thread afterwards.
+ */
+static Bool invoke_agent(pid_t pid, prgregset_t *regs, id_t *agent_lwpid)
+{
+   assert(ctl_fd != -1);
+
+   DEBUG(1, "Creating an agent thread within process %d.\n", pid);
+
+   /* Create the agent thread. */
+   ctl_t ctl;
+   ctl.cmd = PCAGENT;
+   memcpy(&ctl.arg.regs, regs, sizeof(prgregset_t));
+   size_t bytes = sizeof(ctl.cmd) + sizeof(ctl.arg.regs);
+   ssize_t written = write(ctl_fd, (void *) &ctl, bytes);
+   if ((written < 0) || (written != bytes)) {
+      ERROR(errno, "Failed to write to ctl_fd: PCAGENT.\n");
+      return False;
+   }
+
+   DEBUG(1, "Obtaining agent thread lwpid for process %d.\n", pid);
+
+   char procname[PATH_MAX];
+   snprintf(procname, sizeof(procname),
+            "/proc/%d/lwp/agent/lwpstatus", pid);
+
+   int status_fd = open(procname, O_RDONLY, 0);
+   if (status_fd < 0) {
+      /* Operation failed but there is no way to get rid of the agent
+         thread from outside. We are doomed... */
+      ERROR(errno, "Failed to open file %s.\n", procname);
+      return False;
+   }
+
+   lwpstatus_t status;
+   bytes = read(status_fd, &status, sizeof(status));
+   if ((bytes < 0) || (bytes != sizeof(status))) {
+      ERROR(errno, "Failed to read from %s.\n", procname);
+      close(status_fd);
+      return False;
+   }
+
+   close(status_fd);
+   *agent_lwpid = status.pr_lwpid;
+
+   snprintf(procname, sizeof(procname),
+            "/proc/%d/lwp/agent/lwpctl", pid);
+
+   int agent_ctl_fd = open(procname, O_WRONLY, 0);
+   if (agent_ctl_fd < 0) {
+      /* Resuming failed but there is no way to get rid of the agent
+         thread from outside. We are doomed... */
+      ERROR(errno, "Failed to open file %s.\n", procname);
+      return False;
+   }
+
+   DEBUG(1, "Resuming the agent thread for process %d.\n", pid);
+
+   /* Resume the agent thread. */
+   ctl.cmd = PCRUN;
+   ctl.arg.flags = 0;
+   bytes = sizeof(ctl.cmd) + sizeof(ctl.arg.flags);
+   written = write(agent_ctl_fd, (void *) &ctl, bytes);
+   if ((written < 0) || (written != bytes)) {
+      /* Resuming failed but there is no way to get rid of the agent
+         thread from outside. We are doomed... */
+      ERROR(errno, "Failed to write to agent_ctl_fd: PCRUN 0.\n");
+      close(agent_ctl_fd);
+      return False;
+   }
+
+   DEBUG(1, "Agent thread lwpid %d now running within process %d.\n",
+         *agent_lwpid, pid);
+   close(agent_ctl_fd);
+   return True;
+}
+
+/* Waits until the agent thread running inside the inferior
+   process exits. */
+static Bool wait_for_agent_exit(pid_t pid, id_t agent_lwpid)
+{
+   char procname[PATH_MAX];
+   snprintf(procname, sizeof(procname), "/proc/%d/lwp/agent/lwpctl", pid);
+
+   int agent_ctl_fd = open(procname, O_WRONLY, 0);
+   if (agent_ctl_fd < 0) {
+      if (errno == ENOENT) {
+         DEBUG(1, "Agent control file %s no longer exists. This means "
+               "agent thread %d exited meanwhile.\n",
+               procname, agent_lwpid);
+         return True;
+      }
+      ERROR(errno, "Failed to open agent control file %s.\n", procname);
+      return False;
+   }
+
+   DEBUG(1, "Waiting for agent thread %d to exit.\n", agent_lwpid);
+
+   /* Wait until the agent thread stops. This covers also the case
+      when the thread exited. */
+   ctl_t ctl;
+   ctl.cmd = PCWSTOP;
+   size_t bytes = sizeof(ctl.cmd);
+   ssize_t written = write(agent_ctl_fd, (void *) &ctl, bytes);
+   if ((written < 0) || (written != bytes)) {
+      if (errno == ENOENT) {
+         DEBUG(1, "Agent thread lwpid %d has now exited in process %d.\n",
+                  agent_lwpid, pid);
+      } else {
+         ERROR(errno, "Failed to write to agent_ctl_fd: PCWSTOP.\n");
+         close(agent_ctl_fd);
+         return False;
+      }
+   }
+
+   close(agent_ctl_fd);
+   return True;
+}
+
+Bool invoker_invoke_gdbserver(pid_t pid)
+{
+   if (attach(pid) != True) {
+      return False;
+   }
+
+   prgregset_t regs;
+   if (get_regs(pid, &regs) != True) {
+      detach(pid);
+      return False;
+   }
+
+   if (setup_stack_frame(pid, &regs) != True) {
+      detach(pid);
+      return False;
+   }
+
+   id_t agent_lwpid;
+   if (invoke_agent(pid, &regs, &agent_lwpid) != True) {
+      detach(pid);
+      return False;
+   }
+
+   if (wait_for_agent_exit(pid, agent_lwpid) != True) {
+      detach(pid);
+      return False;
+   }
+
+   detach(pid);
+   return True;
+}
+
+void invoker_cleanup_restore_and_detach(void *v_pid)
+{
+   detach(*(int *) v_pid);
+}
+
+void invoker_restrictions_msg(void)
+{
+}
+
+void invoker_valgrind_dying(void)
+{
+}
diff --git a/docs/xml/dist-docs.xml b/docs/xml/dist-docs.xml
index 37b2ce3..e4021ed 100644
--- a/docs/xml/dist-docs.xml
+++ b/docs/xml/dist-docs.xml
@@ -121,4 +121,14 @@
           xmlns:xi="http://www.w3.org/2001/XInclude" />
     </literallayout>
     </chapter>
+
+  <chapter id="dist.readme-solaris"
+             xreflabel="Readme Solaris">
+    <title>README.solaris</title>
+    <literallayout>
+      <xi:include href="../../README.solaris"
+          parse="text"
+          xmlns:xi="http://www.w3.org/2001/XInclude" />
+    </literallayout>
+    </chapter>
 </book>
diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml
index 5437bd5..c79f271 100644
--- a/docs/xml/manual-core.xml
+++ b/docs/xml/manual-core.xml
@@ -2005,7 +2005,7 @@
         <listitem>
           <para><option>lax-ioctls: </option> Be very lax about ioctl
           handling; the only assumption is that the size is
-          correct. Doesn't require the full buffer to be initialized
+          correct. Doesn't require the full buffer to be initialised
           when writing.  Without this, using some device drivers with a
           large number of strange ioctl commands becomes very
           tiresome.</para>
@@ -2071,6 +2071,14 @@
             tested with various glibc versions (e.g. 2.11, 2.16, 2.18)
             on various platforms.</para>
         </listitem>
+        <listitem>
+          <para><option>lax-doors: </option> (Solaris only) Be very lax
+          about door syscall handling over unrecognised door file
+          descriptors. Does not require that full buffer is initialised
+          when writing. Without this, programs using libdoor(3LIB)
+          functionality with completely proprietary semantics may report
+          large number of false positives.</para>
+        </listitem>
       </itemizedlist>
     </listitem>
   </varlistentry>
diff --git a/drd/docs/drd-manual.xml b/drd/docs/drd-manual.xml
index e0c407c..7692dac 100644
--- a/drd/docs/drd-manual.xml
+++ b/drd/docs/drd-manual.xml
@@ -505,6 +505,42 @@
       </para>
     </listitem>
   </varlistentry>
+  <varlistentry>
+    <term>
+      <option><![CDATA[--ignore-thread-creation=<yes|no> [default: no]]]></option>
+    </term>
+    <listitem>
+      <para>
+        Controls whether all activities during thread creation should be
+        ignored. By default enabled only on Solaris.
+        Solaris provides higher throughput, parallelism and scalability than
+        other operating systems, at the cost of more fine-grained locking
+        activity. This means for example that when a thread is created under
+        glibc, just one big lock is used for all thread setup. Solaris libc
+        uses several fine-grained locks and the creator thread resumes its
+        activities as soon as possible, leaving for example stack and TLS setup
+        sequence to the created thread.
+        This situation confuses DRD as it assumes there is some false ordering
+        in place between creator and created thread; and therefore many types
+        of race conditions in the application would not be reported. To prevent
+        such false ordering, this command line option is set to
+        <computeroutput>yes</computeroutput> by default on Solaris.
+        All activity (loads, stores, client requests) is therefore ignored
+        during:</para>
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    pthread_create() call in the creator thread
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    thread creation phase (stack and TLS setup) in the created thread
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </listitem>
+  </varlistentry>
 </variablelist>
 <!-- end of xi:include in the manpage -->
 
diff --git a/drd/drd_clientreq.c b/drd/drd_clientreq.c
index bed68aa..ed8ba7d 100644
--- a/drd/drd_clientreq.c
+++ b/drd/drd_clientreq.c
@@ -615,6 +615,16 @@
       }
       break;
 
+#if defined(VGO_solaris)
+   case VG_USERREQ__RTLD_BIND_GUARD:
+      DRD_(thread_entering_rtld_bind_guard)(drd_tid, arg[1]);
+      break;
+
+   case VG_USERREQ__RTLD_BIND_CLEAR:
+      DRD_(thread_leaving_rtld_bind_clear)(drd_tid, arg[1]);
+      break;
+#endif /* VGO_solaris */
+
    default:
 #if 0
       VG_(message)(Vg_DebugMsg, "Unrecognized client request 0x%lx 0x%lx",
diff --git a/drd/drd_clientreq.h b/drd/drd_clientreq.h
index 929b60d..3e34fc8 100644
--- a/drd/drd_clientreq.h
+++ b/drd/drd_clientreq.h
@@ -226,6 +226,15 @@
    VG_USERREQ__POST_RWLOCK_UNLOCK
    /* args: Addr rwlock, RwLockT, Bool unlocked */
 
+#if defined(VGO_solaris)
+   ,
+   /* To notify the drd tool of a bind_guard call from runtime linker. */
+   VG_USERREQ__RTLD_BIND_GUARD,
+   /* args: Int flags */
+   /* To notify the drd tool of a bind_clear call from runtime linker. */
+   VG_USERREQ__RTLD_BIND_CLEAR
+   /* args: Int flags */
+#endif /* VGO_solaris */
 };
 
 /**
diff --git a/drd/drd_main.c b/drd/drd_main.c
index 0960fe5..504aa6a 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -104,6 +104,8 @@
    {}
    else if VG_BOOL_CLO(arg, "--show-confl-seg",      show_confl_seg) {}
    else if VG_BOOL_CLO(arg, "--show-stack-usage",    s_show_stack_usage) {}
+   else if VG_BOOL_CLO(arg, "--ignore-thread-creation",
+   DRD_(ignore_thread_creation)) {}
    else if VG_BOOL_CLO(arg, "--trace-alloc",         s_trace_alloc) {}
    else if VG_BOOL_CLO(arg, "--trace-barrier",       trace_barrier) {}
    else if VG_BOOL_CLO(arg, "--trace-clientobj",     trace_clientobj) {}
@@ -228,6 +230,8 @@
 "                              milliseconds) [off]\n"
 "    --show-confl-seg=yes|no   Show conflicting segments in race reports [yes].\n"
 "    --show-stack-usage=yes|no Print stack usage at thread exit time [no].\n"
+"    --ignore-thread-creation=yes|no Ignore activities during thread \n"
+"                              creation [%s].\n"
 "\n"
 "  drd options for monitoring process behavior:\n"
 "    --ptrace-addr=<address>[+<length>] Trace all load and store activity for\n"
@@ -245,7 +249,8 @@
 "    --trace-mutex=yes|no      Trace all mutex activity [no].\n"
 "    --trace-rwlock=yes|no     Trace all reader-writer lock activity[no].\n"
 "    --trace-semaphore=yes|no  Trace all semaphore activity [no].\n",
-DRD_(thread_get_segment_merge_interval)()
+DRD_(thread_get_segment_merge_interval)(),
+DRD_(ignore_thread_creation) ? "yes" : "no"
 );
 }
 
@@ -735,7 +740,7 @@
 
 static void DRD_(post_clo_init)(void)
 {
-#if defined(VGO_linux) || defined(VGO_darwin)
+#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
    /* fine */
 #else
    VG_(printf)("\nWARNING: DRD has not yet been tested on this operating system.\n\n");
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
index a3119de..ea14fa4 100644
--- a/drd/drd_pthread_intercepts.c
+++ b/drd/drd_pthread_intercepts.c
@@ -66,6 +66,78 @@
 #include "drd_clientreq.h"
 #include "pub_tool_redir.h" /* VG_WRAP_FUNCTION_ZZ() */
 
+#if defined(VGO_solaris)
+/*
+ * Solaris usually provides pthread_* functions on top of Solaris threading
+ * and synchronization functions. Usually both need to be intercepted because
+ * pthread_* ones might not call the Solaris ones (see for example sem_wait()).
+ * Such approach is required to correctly report misuse of the POSIX threads
+ * API.
+ * Therefore DRD intercepts and instruments all such functions but due to
+ * DRD_(thread_enter_synchr)() and DRD_(thread_leave_synchr)() guards in
+ * handle_client_request(), only the top-most function is handled.
+ * So the right thing(TM) happens, as expected.
+ * The only exception is when pthread_* function is a weak alias to the Solaris
+ * threading/synchronization function. In such case only one needs to be
+ * intercepted to avoid redirection ambiguity.
+ *
+ * Intercepted functions rely on the fact that:
+ *  - pthread_mutex_t  == mutex_t
+ *  - pthread_cond_t   == cond_t
+ *  - sem_t            == sema_t
+ *  - pthread_rwlock_t == rwlock_t
+ *
+ * It is necessary to intercept also internal libc synchronization functions
+ * for two reasons:
+ *  - For read-write locks the unlocking function is shared
+ *  - Functions lmutex_lock/lmutex_unlock guard many critical sections in libc
+ *    which will be otherwise reported by DRD
+ */
+#include <synch.h>
+#include <thread.h>
+#include "pub_tool_vki.h"
+
+/*
+ * Solaris provides higher throughput, parallelism and scalability than other
+ * operating systems, at the cost of more fine-grained locking activity.
+ * This means for example that when a thread is created under Linux, just one
+ * big lock in glibc is used for all thread setup. Solaris libc uses several
+ * fine-grained locks and the creator thread resumes its activities as soon
+ * as possible, leaving for example stack and TLS setup activities to the
+ * created thread.
+ *
+ * This situation confuses DRD as it assumes there is some false ordering
+ * in place between creator and created thread; and therefore many types of
+ * race conditions in the application would not be reported. To prevent such
+ * false ordering, command line option --ignore-thread-creation is set to
+ * 'yes' by default on Solaris. All activity (loads, stores, client requests)
+ * is therefore ignored during:
+ * - pthread_create() call in the creator thread [libc.so]
+ * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
+ *
+ * As explained in the comments for _ti_bind_guard(), whenever the runtime
+ * linker has to perform any activity (such as resolving a symbol), it protects
+ * its data structures by calling into rt_bind_guard() which in turn invokes
+ * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
+ * are passed from libc to runtime linker in _ld_libc() call during libc_init().
+ * All activity is also ignored during:
+ * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
+ *   calls [ld.so]
+ *
+ * This also means that DRD does not report race conditions in libc (when
+ * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
+ * during these ignored sequences.
+ */
+
+/*
+ * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
+ * from libc. They are intercepted in function wrapper of _ld_libc().
+ */
+typedef int (*drd_rtld_guard_fn)(int flags);
+static drd_rtld_guard_fn DRD_(rtld_bind_guard) = NULL;
+static drd_rtld_guard_fn DRD_(rtld_bind_clear) = NULL;
+#endif
+
 
 /*
  * Notes regarding thread creation:
@@ -101,6 +173,15 @@
 	 fflush(stdout);						\
       return pth_func_result;						\
    }
+#elif defined(VGO_solaris)
+/* On Solaris, libpthread is just a filter library on top of libc.
+ * Threading and synchronization functions in runtime linker are not
+ * intercepted.
+ */
+#define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
+   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl;           \
+   ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBC_SONAME,zf) argl_decl            \
+   { return implf argl; }
 #else
 #define PTH_FUNC(ret_ty, zf, implf, argl_decl, argl)                    \
    ret_ty VG_WRAP_FUNCTION_ZZ(VG_Z_LIBPTHREAD_SONAME,zf) argl_decl;     \
@@ -177,6 +258,15 @@
 {
    DRD_(check_threading_library)();
    DRD_(set_main_thread_state)();
+#if defined(VGO_solaris)
+   if ((DRD_(rtld_bind_guard) == NULL) || (DRD_(rtld_bind_clear) == NULL)) {
+      fprintf(stderr,
+"Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
+"This means the interface between libc and runtime linker changed and DRD\n"
+"needs to be ported properly. Giving up.\n");
+      abort();
+   }
+#endif
 }
 
 static __always_inline void DRD_(ignore_mutex_ordering)(pthread_mutex_t *mutex)
@@ -275,6 +365,23 @@
       return mutex_type_invalid_mutex;
 }
 
+#if defined(VGO_solaris)
+/**
+ * Solaris threads and DRD each have their own mutex type identification.
+ * Convert Solaris threads' mutex type to DRD's mutex type.
+ */
+static MutexT DRD_(thread_to_drd_mutex_type)(int type)
+{
+   if (type & LOCK_RECURSIVE) {
+      return mutex_type_recursive_mutex;
+   } else if (type & LOCK_ERRORCHECK) {
+      return mutex_type_errorcheck_mutex;
+   } else {
+      return mutex_type_default_mutex;
+   }
+}
+#endif /* VGO_solaris */
+
 #define IS_ALIGNED(p) (((uintptr_t)(p) & (sizeof(*(p)) - 1)) == 0)
 
 /**
@@ -306,6 +413,9 @@
       const int kind = mutex->__data.__kind & 3;
       return DRD_(pthread_to_drd_mutex_type)(kind);
    }
+#elif defined(VGO_solaris)
+      const int type = ((mutex_t *) mutex)->vki_mutex_type;
+      return DRD_(thread_to_drd_mutex_type)(type);
 #else
    /*
     * Another POSIX threads implementation. The mutex type won't be printed
@@ -503,6 +613,113 @@
            void *(*start) (void *), void *arg),
           (thread, attr, start, arg));
 
+#if defined(VGO_solaris)
+/* Solaris also provides thr_create() in addition to pthread_create().
+ * Both pthread_create(3C) and thr_create(3C) are based on private
+ * _thrp_create().
+ */
+static __always_inline
+int thr_create_intercept(void *stk, size_t stksize, void *(*start)(void *),
+                         void *arg, long flags, thread_t *new_thread)
+{
+   int                ret;
+   OrigFn             fn;
+   DrdSema            wrapper_started;
+   DrdPosixThreadArgs thread_args;
+
+   VALGRIND_GET_ORIG_FN(fn);
+
+   DRD_(sema_init)(&wrapper_started);
+   thread_args.start           = start;
+   thread_args.arg             = arg;
+   thread_args.wrapper_started = &wrapper_started;
+   /*
+    * Find out whether the thread will be started as a joinable thread
+    * or as a detached thread.
+    */
+   if (flags & THR_DETACHED)
+      thread_args.detachstate = PTHREAD_CREATE_DETACHED;
+   else
+      thread_args.detachstate = PTHREAD_CREATE_JOINABLE;
+
+   DRD_(entering_pthread_create)();
+   CALL_FN_W_6W(ret, fn, stk, stksize, DRD_(thread_wrapper), &thread_args,
+                flags, new_thread);
+   DRD_(left_pthread_create)();
+
+   if (ret == 0) {
+      /* Wait until the thread wrapper started. */
+      DRD_(sema_down)(&wrapper_started);
+   }
+
+   DRD_(sema_destroy)(&wrapper_started);
+
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__DRD_START_NEW_SEGMENT,
+                                   pthread_self(), 0, 0, 0, 0);
+
+   return ret;
+}
+
+PTH_FUNCS(int, thrZucreate, thr_create_intercept,
+          (void *stk, size_t stksize, void *(*start)(void *), void *arg,
+           long flags, thread_t *new_thread),
+          (stk, stksize, start, arg, flags, new_thread));
+#endif /* VGO_solaris */
+
+#if defined(VGO_solaris)
+/*
+ * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
+ * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
+ * and CI_BIND_CLEAR, to provide resilience against function renaming.
+ */
+static __always_inline
+int DRD_(_ti_bind_guard_intercept)(int flags) {
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_GUARD,
+                                   flags, 0, 0, 0, 0);
+   return DRD_(rtld_bind_guard)(flags);
+}
+
+static __always_inline
+int DRD_(_ti_bind_clear_intercept)(int flags) {
+   int ret = DRD_(rtld_bind_clear)(flags);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__RTLD_BIND_CLEAR,
+                                   flags, 0, 0, 0, 0);
+   return ret;
+}
+
+/*
+ * Wrapped _ld_libc() from the runtime linker ld.so.1.
+ */
+void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
+void VG_WRAP_FUNCTION_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
+{
+   OrigFn fn;
+   int    tag;
+
+   VALGRIND_GET_ORIG_FN(fn);
+
+   vki_Lc_interface *funcs = ptr;
+   for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
+      switch (tag) {
+      case VKI_CI_BIND_GUARD:
+         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_guard_intercept)) {
+            DRD_(rtld_bind_guard) = funcs->vki_ci_un.ci_func;
+            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_guard_intercept);
+         }
+         break;
+      case VKI_CI_BIND_CLEAR:
+         if (funcs->vki_ci_un.ci_func != DRD_(_ti_bind_clear_intercept)) {
+            DRD_(rtld_bind_clear) = funcs->vki_ci_un.ci_func;
+            funcs->vki_ci_un.ci_func = DRD_(_ti_bind_clear_intercept);
+         }
+         break;
+      }
+   }
+
+   CALL_FN_v_W(fn, ptr);
+}
+#endif /* VGO_solaris */
+
 static __always_inline
 int pthread_join_intercept(pthread_t pt_joinee, void **thread_return)
 {
@@ -529,6 +746,34 @@
           (pthread_t pt_joinee, void **thread_return),
           (pt_joinee, thread_return));
 
+#if defined(VGO_solaris)
+/* Solaris also provides thr_join() in addition to pthread_join().
+ * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
+ *
+ * :TODO: No functionality is currently provided for joinee == 0 and departed.
+ *        This would require another client request, of course.
+ */
+static __always_inline
+int thr_join_intercept(thread_t joinee, thread_t *departed, void **thread_return)
+{
+   int      ret;
+   OrigFn   fn;
+
+   VALGRIND_GET_ORIG_FN(fn);
+   CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
+   if (ret == 0)
+   {
+      VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_THREAD_JOIN,
+                                      joinee, 0, 0, 0, 0);
+   }
+   return ret;
+}
+
+PTH_FUNCS(int, thrZujoin, thr_join_intercept,
+          (thread_t joinee, thread_t *departed, void **thread_return),
+          (joinee, departed, thread_return));
+#endif /* VGO_solaris */
+
 static __always_inline
 int pthread_detach_intercept(pthread_t pt_thread)
 {
@@ -613,6 +858,28 @@
           (pthread_mutex_t *mutex, const pthread_mutexattr_t* attr),
           (mutex, attr));
 
+#if defined(VGO_solaris)
+static __always_inline
+int mutex_init_intercept(mutex_t *mutex, int type, void *arg)
+{
+   int ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_INIT,
+                                   mutex, DRD_(thread_to_drd_mutex_type)(type),
+                                   0, 0, 0);
+   CALL_FN_W_WWW(ret, fn, mutex, type, arg);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_INIT,
+                                   mutex, 0, 0, 0, 0);
+   return ret;
+}
+
+PTH_FUNCS(int, mutexZuinit, mutex_init_intercept,
+          (mutex_t *mutex, int type, void *arg),
+          (mutex, type, arg));
+#endif /* VGO_solaris */
+
 static __always_inline
 int pthread_mutex_destroy_intercept(pthread_mutex_t* mutex)
 {
@@ -627,8 +894,14 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_mutex_destroy is a weak alias to mutex_destroy. */
+PTH_FUNCS(int, mutexZudestroy, pthread_mutex_destroy_intercept,
+          (pthread_mutex_t *mutex), (mutex));
+#else
 PTH_FUNCS(int, pthreadZumutexZudestroy, pthread_mutex_destroy_intercept,
           (pthread_mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_mutex_lock_intercept(pthread_mutex_t* mutex)
@@ -644,8 +917,36 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_mutex_lock is a weak alias to mutex_lock. */
+PTH_FUNCS(int, mutexZulock, pthread_mutex_lock_intercept,
+          (pthread_mutex_t *mutex), (mutex));
+#else
 PTH_FUNCS(int, pthreadZumutexZulock, pthread_mutex_lock_intercept,
           (pthread_mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
+
+#if defined(VGO_solaris)
+/* Internal to libc. Mutex is usually initialized only implicitly,
+ * by zeroing mutex_t structure.
+ */
+static __always_inline
+void lmutex_lock_intercept(mutex_t *mutex)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_LOCK,
+                                   mutex,
+                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
+                                   False /* try_lock */, 0, 0);
+   CALL_FN_v_W(fn, mutex);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_LOCK,
+                                   mutex, True /* took_lock */, 0, 0, 0);
+}
+
+PTH_FUNCS(void, lmutexZulock, lmutex_lock_intercept,
+          (mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_mutex_trylock_intercept(pthread_mutex_t* mutex)
@@ -661,8 +962,14 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_mutex_trylock is a weak alias to mutex_trylock. */
+PTH_FUNCS(int, mutexZutrylock, pthread_mutex_trylock_intercept,
+          (pthread_mutex_t *mutex), (mutex));
+#else
 PTH_FUNCS(int, pthreadZumutexZutrylock, pthread_mutex_trylock_intercept,
           (pthread_mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_mutex_timedlock_intercept(pthread_mutex_t *mutex,
@@ -682,6 +989,12 @@
 PTH_FUNCS(int, pthreadZumutexZutimedlock, pthread_mutex_timedlock_intercept,
           (pthread_mutex_t *mutex, const struct timespec *abs_timeout),
           (mutex, abs_timeout));
+#if defined(VGO_solaris)
+PTH_FUNCS(int,
+          pthreadZumutexZureltimedlockZunp, pthread_mutex_timedlock_intercept,
+          (pthread_mutex_t *mutex, const struct timespec *timeout),
+          (mutex, timeout));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_mutex_unlock_intercept(pthread_mutex_t *mutex)
@@ -697,8 +1010,34 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_mutex_unlock is a weak alias to mutex_unlock. */
+PTH_FUNCS(int, mutexZuunlock, pthread_mutex_unlock_intercept,
+          (pthread_mutex_t *mutex), (mutex));
+#else
 PTH_FUNCS(int, pthreadZumutexZuunlock, pthread_mutex_unlock_intercept,
           (pthread_mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
+
+#if defined(VGO_solaris)
+/* Internal to libc. */
+static __always_inline
+void lmutex_unlock_intercept(mutex_t *mutex)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_MUTEX_UNLOCK,
+                                   mutex,
+                                   DRD_(mutex_type)((pthread_mutex_t *) mutex),
+                                   0, 0, 0);
+   CALL_FN_v_W(fn, mutex);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_MUTEX_UNLOCK,
+                                   mutex, 0, 0, 0, 0);
+}
+
+PTH_FUNCS(void, lmutexZuunlock, lmutex_unlock_intercept,
+          (mutex_t *mutex), (mutex));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_cond_init_intercept(pthread_cond_t* cond,
@@ -719,6 +1058,26 @@
           (pthread_cond_t* cond, const pthread_condattr_t* attr),
           (cond, attr));
 
+#if defined(VGO_solaris)
+static __always_inline
+int cond_init_intercept(cond_t *cond, int type, void *arg)
+{
+   int ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_INIT,
+                                   cond, 0, 0, 0, 0);
+   CALL_FN_W_WWW(ret, fn, cond, type, arg);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_INIT,
+                                   cond, 0, 0, 0, 0);
+   return ret;
+}
+
+PTH_FUNCS(int, condZuinit, cond_init_intercept,
+          (cond_t *cond, int type, void *arg),
+          (cond, type, arg));
+#endif /* VGO_solaris */
+
 static __always_inline
 int pthread_cond_destroy_intercept(pthread_cond_t* cond)
 {
@@ -733,8 +1092,14 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_cond_destroy is a weak alias to cond_destroy. */
+PTH_FUNCS(int, condZudestroy, pthread_cond_destroy_intercept,
+          (pthread_cond_t *cond), (cond));
+#else
 PTH_FUNCS(int, pthreadZucondZudestroy, pthread_cond_destroy_intercept,
           (pthread_cond_t* cond), (cond));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_cond_wait_intercept(pthread_cond_t *cond, pthread_mutex_t *mutex)
@@ -753,6 +1118,11 @@
 PTH_FUNCS(int, pthreadZucondZuwait, pthread_cond_wait_intercept,
           (pthread_cond_t *cond, pthread_mutex_t *mutex),
           (cond, mutex));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, condZuwait, pthread_cond_wait_intercept,
+          (pthread_cond_t *cond, pthread_mutex_t *mutex),
+          (cond, mutex));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_cond_timedwait_intercept(pthread_cond_t *cond,
@@ -774,6 +1144,16 @@
           (pthread_cond_t *cond, pthread_mutex_t *mutex,
            const struct timespec* abstime),
           (cond, mutex, abstime));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, condZutimedwait, pthread_cond_timedwait_intercept,
+          (pthread_cond_t *cond, pthread_mutex_t *mutex,
+           const struct timespec *timeout),
+          (cond, mutex, timeout));
+PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
+          (pthread_cond_t *cond, pthread_mutex_t *mutex,
+           const struct timespec *timeout),
+          (cond, mutex, timeout));
+#endif /* VGO_solaris */
 
 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
@@ -795,8 +1175,14 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_cond_signal is a weak alias to cond_signal. */
+PTH_FUNCS(int, condZusignal, pthread_cond_signal_intercept,
+          (pthread_cond_t *cond), (cond));
+#else
 PTH_FUNCS(int, pthreadZucondZusignal, pthread_cond_signal_intercept,
           (pthread_cond_t* cond), (cond));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_cond_broadcast_intercept(pthread_cond_t* cond)
@@ -812,8 +1198,14 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_cond_broadcast is a weak alias to cond_broadcast. */
+PTH_FUNCS(int, condZubroadcast, pthread_cond_broadcast_intercept,
+          (pthread_cond_t *cond), (cond));
+#else
 PTH_FUNCS(int, pthreadZucondZubroadcast, pthread_cond_broadcast_intercept,
           (pthread_cond_t* cond), (cond));
+#endif /* VGO_solaris */
 
 #if defined(HAVE_PTHREAD_SPIN_LOCK) \
     && !defined(DISABLE_PTHREAD_SPINLOCK_INTERCEPT)
@@ -980,6 +1372,27 @@
 PTH_FUNCS(int, semZuinit, sem_init_intercept,
           (sem_t *sem, int pshared, unsigned int value), (sem, pshared, value));
 
+#if defined(VGO_solaris)
+static __always_inline
+int sema_init_intercept(sema_t *sem, unsigned int value, int type, void *arg)
+{
+   int   ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_SEM_INIT,
+                                   sem, type == USYNC_PROCESS ? 1 : 0,
+                                   value, 0, 0);
+   CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_SEM_INIT,
+                                   sem, 0, 0, 0, 0);
+   return ret;
+}
+
+PTH_FUNCS(int, semaZuinit, sema_init_intercept,
+          (sema_t *sem, unsigned int value, int type, void *arg),
+          (sem, value, type, arg));
+#endif /* VGO_solaris */
+
 static __always_inline
 int sem_destroy_intercept(sem_t *sem)
 {
@@ -995,6 +1408,9 @@
 }
 
 PTH_FUNCS(int, semZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, semaZudestroy, sem_destroy_intercept, (sem_t *sem), (sem));
+#endif /* VGO_solaris */
 
 static __always_inline
 sem_t* sem_open_intercept(const char *name, int oflag, mode_t mode,
@@ -1045,6 +1461,9 @@
 }
 
 PTH_FUNCS(int, semZuwait, sem_wait_intercept, (sem_t *sem), (sem));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, semaZuwait, sem_wait_intercept, (sem_t *sem), (sem));
+#endif /* VGO_solaris */
 
 static __always_inline int sem_trywait_intercept(sem_t *sem)
 {
@@ -1060,6 +1479,9 @@
 }
 
 PTH_FUNCS(int, semZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, semaZutrywait, sem_trywait_intercept, (sem_t *sem), (sem));
+#endif /* VGO_solaris */
 
 static __always_inline
 int sem_timedwait_intercept(sem_t *sem, const struct timespec *abs_timeout)
@@ -1078,6 +1500,14 @@
 PTH_FUNCS(int, semZutimedwait, sem_timedwait_intercept,
           (sem_t *sem, const struct timespec *abs_timeout),
           (sem, abs_timeout));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, semaZutimedwait, sem_timedwait_intercept,
+          (sem_t *sem, const struct timespec *timeout),
+          (sem, timeout));
+PTH_FUNCS(int, semaZureltimedwait, sem_timedwait_intercept,
+          (sem_t *sem, const struct timespec *timeout),
+          (sem, timeout));
+#endif /* VGO_solaris */
 
 static __always_inline int sem_post_intercept(sem_t *sem)
 {
@@ -1093,6 +1523,9 @@
 }
 
 PTH_FUNCS(int, semZupost, sem_post_intercept, (sem_t *sem), (sem));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, semaZupost, sem_post_intercept, (sem_t *sem), (sem));
+#endif /* VGO_solaris */
 
 /* Android's pthread.h doesn't say anything about rwlocks, hence these
    functions have to be conditionally compiled. */
@@ -1118,6 +1551,26 @@
           (pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr),
           (rwlock, attr));
 
+#if defined(VGO_solaris)
+static __always_inline
+int rwlock_init_intercept(rwlock_t *rwlock, int type, void *arg)
+{
+   int   ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_INIT,
+                                   rwlock, 0, 0, 0, 0);
+   CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_INIT,
+                                   rwlock, 0, 0, 0, 0);
+   return ret;
+}
+
+PTH_FUNCS(int, rwlockZuinit, rwlock_init_intercept,
+          (rwlock_t *rwlock, int type, void *arg),
+          (rwlock, type, arg));
+#endif /* VGO_solaris */
+
 static __always_inline
 int pthread_rwlock_destroy_intercept(pthread_rwlock_t* rwlock)
 {
@@ -1132,9 +1585,16 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_destroy is a weak alias to rwlock_destroy. */
+PTH_FUNCS(int,
+          rwlockZudestroy, pthread_rwlock_destroy_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZudestroy, pthread_rwlock_destroy_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_rdlock_intercept(pthread_rwlock_t* rwlock)
@@ -1150,9 +1610,34 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_rdlock is a weak alias to rw_rdlock. */
+PTH_FUNCS(int,
+          rwZurdlock, pthread_rwlock_rdlock_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZurdlock, pthread_rwlock_rdlock_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
+
+#if defined(VGO_solaris)
+/* Internal to libc. */
+static __always_inline
+void lrw_rdlock_intercept(rwlock_t *rwlock)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_RDLOCK,
+                                   rwlock, 0, 0, 0, 0);
+   CALL_FN_v_W(fn, rwlock);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_RDLOCK,
+                                   rwlock, True /* took_lock */, 0, 0, 0);
+}
+
+PTH_FUNCS(void, lrwZurdlock, lrw_rdlock_intercept,
+          (rwlock_t *rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_wrlock_intercept(pthread_rwlock_t* rwlock)
@@ -1168,9 +1653,34 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_wrlock is a weak alias to rw_wrlock. */
+PTH_FUNCS(int,
+          rwZuwrlock, pthread_rwlock_wrlock_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZuwrlock, pthread_rwlock_wrlock_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
+
+#if defined(VGO_solaris)
+/* Internal to libc. */
+static __always_inline
+void lrw_wrlock_intercept(rwlock_t *rwlock)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_RWLOCK_WRLOCK,
+                                   rwlock, 0, 0, 0, 0);
+   CALL_FN_v_W(fn, rwlock);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_RWLOCK_WRLOCK,
+                                   rwlock, True /* took_lock */, 0, 0, 0);
+}
+
+PTH_FUNCS(void, lrwZuwrlock, lrw_wrlock_intercept,
+          (rwlock_t *rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_timedrdlock_intercept(pthread_rwlock_t* rwlock,
@@ -1191,6 +1701,12 @@
           pthreadZurwlockZutimedrdlock, pthread_rwlock_timedrdlock_intercept,
           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
           (rwlock, timeout));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, pthreadZurwlockZureltimedrdlockZunp,
+          pthread_rwlock_timedrdlock_intercept,
+          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
+          (rwlock, timeout));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_timedwrlock_intercept(pthread_rwlock_t* rwlock,
@@ -1211,6 +1727,12 @@
           pthreadZurwlockZutimedwrlock, pthread_rwlock_timedwrlock_intercept,
           (pthread_rwlock_t* rwlock, const struct timespec *timeout),
           (rwlock, timeout));
+#if defined(VGO_solaris)
+PTH_FUNCS(int, pthreadZurwlockZureltimedwrlockZunp,
+          pthread_rwlock_timedwrlock_intercept,
+          (pthread_rwlock_t *rwlock, const struct timespec *timeout),
+          (rwlock, timeout));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_tryrdlock_intercept(pthread_rwlock_t* rwlock)
@@ -1226,9 +1748,16 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_tryrdlock is a weak alias to rw_tryrdlock. */
+PTH_FUNCS(int,
+          rwZutryrdlock, pthread_rwlock_tryrdlock_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZutryrdlock, pthread_rwlock_tryrdlock_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_trywrlock_intercept(pthread_rwlock_t* rwlock)
@@ -1244,9 +1773,16 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_trywrlock is a weak alias to rw_trywrlock. */
+PTH_FUNCS(int,
+          rwZutrywrlock, pthread_rwlock_trywrlock_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZutrywrlock, pthread_rwlock_trywrlock_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 static __always_inline
 int pthread_rwlock_unlock_intercept(pthread_rwlock_t* rwlock)
@@ -1262,8 +1798,15 @@
    return ret;
 }
 
+#if defined(VGO_solaris)
+/* On Solaris, pthread_rwlock_unlock is a weak alias to rw_unlock. */
+PTH_FUNCS(int,
+          rwZuunlock, pthread_rwlock_unlock_intercept,
+          (pthread_rwlock_t *rwlock), (rwlock));
+#else
 PTH_FUNCS(int,
           pthreadZurwlockZuunlock, pthread_rwlock_unlock_intercept,
           (pthread_rwlock_t* rwlock), (rwlock));
+#endif /* VGO_solaris */
 
 #endif /* defined(HAVE_PTHREAD_RWLOCK_T) */
diff --git a/drd/drd_thread.c b/drd/drd_thread.c
index ede5b82..f0f39f8 100644
--- a/drd/drd_thread.c
+++ b/drd/drd_thread.c
@@ -78,6 +78,11 @@
 static unsigned s_join_list_vol = 10;
 static unsigned s_deletion_head;
 static unsigned s_deletion_tail;
+#if defined(VGO_solaris)
+Bool DRD_(ignore_thread_creation) = True;
+#else
+Bool DRD_(ignore_thread_creation) = False;
+#endif /* VGO_solaris */
 
 
 /* Function definitions. */
@@ -203,6 +208,11 @@
          DRD_(g_threadinfo)[i].pthread_create_nesting_level = 0;
          DRD_(g_threadinfo)[i].synchr_nesting = 0;
          DRD_(g_threadinfo)[i].deletion_seq = s_deletion_tail - 1;
+         DRD_(g_threadinfo)[i].creator_thread = DRD_INVALID_THREADID;
+#if defined (VGO_solaris)
+         DRD_(g_threadinfo)[i].bind_guard_flag = 0;
+#endif /* VGO_solaris */
+
          tl_assert(DRD_(g_threadinfo)[i].sg_first == NULL);
          tl_assert(DRD_(g_threadinfo)[i].sg_last == NULL);
 
@@ -302,6 +312,16 @@
 
    tl_assert(DRD_(g_threadinfo)[created].sg_first == NULL);
    tl_assert(DRD_(g_threadinfo)[created].sg_last == NULL);
+
+   if (creator != DRD_INVALID_THREADID) {
+      if (DRD_(ignore_thread_creation)) {
+         tl_assert(DRD_(thread_get_synchr_nesting_count)(created) == 0);
+         DRD_(thread_enter_synchr)(created);
+         /* Counterpart in DRD_(thread_set_pthreadid)(). */
+      }
+   }
+   DRD_(g_threadinfo)[created].creator_thread = creator;
+
    /* Create an initial segment for the newly created thread. */
    thread_append_segment(created, DRD_(sg_new)(creator, created));
 
@@ -595,6 +615,13 @@
    tl_assert(ptid != INVALID_POSIX_THREADID);
    DRD_(g_threadinfo)[tid].posix_thread_exists = True;
    DRD_(g_threadinfo)[tid].pt_threadid         = ptid;
+
+   if (DRD_(g_threadinfo)[tid].creator_thread != DRD_INVALID_THREADID) {
+      if (DRD_(ignore_thread_creation)) {
+         DRD_(thread_leave_synchr)(tid);
+         tl_assert(DRD_(thread_get_synchr_nesting_count)(tid) == 0);
+      }
+   }
 }
 
 /** Returns true for joinable threads and false for detached threads. */
@@ -631,6 +658,11 @@
    tl_assert(DRD_(g_threadinfo)[tid].pthread_create_nesting_level >= 0);
 
    DRD_(g_threadinfo)[tid].pthread_create_nesting_level++;
+
+   if (DRD_(ignore_thread_creation)) {
+      tl_assert(DRD_(thread_get_synchr_nesting_count)(tid) == 0);
+      DRD_(thread_enter_synchr)(tid);
+   }
 }
 
 /** Tells DRD that the calling thread has left pthread_create(). */
@@ -642,8 +674,44 @@
    tl_assert(DRD_(g_threadinfo)[tid].pthread_create_nesting_level > 0);
 
    DRD_(g_threadinfo)[tid].pthread_create_nesting_level--;
+
+   if (DRD_(ignore_thread_creation)) {
+      DRD_(thread_leave_synchr)(tid);
+      tl_assert(DRD_(thread_get_synchr_nesting_count)(tid) == 0);
+   }
 }
 
+#if defined(VGO_solaris)
+/** Handles the bind_guard() intercept. */
+void DRD_(thread_entering_rtld_bind_guard)(const DrdThreadId tid, int flags)
+{
+   tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
+             && tid != DRD_INVALID_THREADID);
+
+   Int bindflag = (flags & VKI_THR_FLG_RTLD);
+   if ((bindflag & DRD_(g_threadinfo)[tid].bind_guard_flag) == 0) {
+      DRD_(g_threadinfo)[tid].bind_guard_flag |= bindflag;
+      DRD_(thread_enter_synchr)(tid);
+   }
+}
+
+/**
+ * Handles the bind_clear() intercept.
+ * Call to bind_clear(0) is typically used to determine value of bind_flags.
+ */
+void DRD_(thread_leaving_rtld_bind_clear)(const DrdThreadId tid, int flags)
+{
+   tl_assert(0 <= (int)tid && tid < DRD_N_THREADS
+             && tid != DRD_INVALID_THREADID);
+
+   Int bindflag = (flags & VKI_THR_FLG_RTLD);
+   if ((DRD_(g_threadinfo)[tid].bind_guard_flag & bindflag) != 0) {
+      DRD_(g_threadinfo)[tid].bind_guard_flag &= ~bindflag;
+      DRD_(thread_leave_synchr)(tid);
+   }
+}
+#endif /* VGO_solaris */
+
 /** Obtain the thread number and the user-assigned thread name. */
 const HChar* DRD_(thread_get_name)(const DrdThreadId tid)
 {
diff --git a/drd/drd_thread.h b/drd/drd_thread.h
index 28068a7..8e20961 100644
--- a/drd/drd_thread.h
+++ b/drd/drd_thread.h
@@ -98,6 +98,15 @@
    Int       synchr_nesting;
    /** Delayed thread deletion sequence number. */
    unsigned  deletion_seq;
+   /**
+    * ID of the creator thread. It can be safely accessed only until the
+    * thread is fully created. Then the creator thread lives its own life again.
+    */
+   DrdThreadId creator_thread;
+
+#if defined(VGO_solaris)
+   Int       bind_guard_flag; /**< Bind flag from the runtime linker. */
+#endif /* VGO_solaris */
 } ThreadInfo;
 
 
@@ -117,6 +126,8 @@
 /** Conflict set for the currently running thread. */
 extern struct bitmap* DRD_(g_conflict_set);
 extern Bool           DRD_(verify_conflict_set);
+/** Whether activities during thread creation should be ignored. */
+extern Bool           DRD_(ignore_thread_creation);
 
 
 /* Function declarations. */
@@ -159,6 +170,10 @@
 void DRD_(thread_set_joinable)(const DrdThreadId tid, const Bool joinable);
 void DRD_(thread_entering_pthread_create)(const DrdThreadId tid);
 void DRD_(thread_left_pthread_create)(const DrdThreadId tid);
+#if defined(VGO_solaris)
+void DRD_(thread_entering_rtld_bind_guard)(const DrdThreadId tid, int flags);
+void DRD_(thread_leaving_rtld_bind_clear)(const DrdThreadId tid, int flags);
+#endif /* VGO_solaris */
 const HChar* DRD_(thread_get_name)(const DrdThreadId tid);
 void DRD_(thread_set_name)(const DrdThreadId tid, const HChar* const name);
 void DRD_(thread_set_vg_running_tid)(const ThreadId vg_tid);
diff --git a/drd/tests/Makefile.am b/drd/tests/Makefile.am
index 7b6479f..dcd79cb 100644
--- a/drd/tests/Makefile.am
+++ b/drd/tests/Makefile.am
@@ -9,7 +9,9 @@
 	filter_stderr               \
 	filter_stderr_and_thread_no \
 	filter_stderr_and_thread_no_and_offset \
+	filter_stderr_solaris       \
 	filter_thread_no	    \
+	filter_thread_name_xml      \
 	filter_xml_and_thread_no    \
 	run_openmp_test             \
 	supported_libpthread	    \
@@ -38,6 +40,8 @@
 	annotate_order_3.vgtest			    \
 	annotate_publish_hg.stderr.exp		    \
 	annotate_publish_hg.vgtest		    \
+	annotate_sem.stderr.exp                     \
+	annotate_sem.vgtest                         \
 	annotate_smart_pointer.stderr.exp	    \
 	annotate_smart_pointer.vgtest		    \
 	annotate_smart_pointer2.stderr.exp	    \
@@ -54,10 +58,13 @@
 	annotate_ignore_rw.stderr.exp		    \
 	annotate_ignore_rw.vgtest		    \
 	annotate_ignore_rw2.stderr.exp		    \
+	annotate_ignore_rw2.stderr.exp-solaris	    \
 	annotate_ignore_rw2.vgtest		    \
 	annotate_ignore_write.stderr.exp	    \
+	annotate_ignore_write.stderr.exp-solaris    \
 	annotate_ignore_write.vgtest		    \
 	annotate_ignore_write2.stderr.exp	    \
+	annotate_ignore_write2.stderr.exp-solaris   \
 	annotate_ignore_write2.vgtest		    \
 	annotate_trace_memory.stderr.exp-32bit	    \
 	annotate_trace_memory.stderr.exp-64bit	    \
@@ -101,6 +108,7 @@
 	fp_race_xml.stderr.exp                      \
 	fp_race_xml.stderr.exp-mips32-be            \
 	fp_race_xml.stderr.exp-mips32-le            \
+	fp_race_xml.stderr.exp-solaris              \
 	fp_race_xml.vgtest                          \
 	free_is_write.stderr.exp		    \
 	free_is_write.vgtest			    \
@@ -170,6 +178,7 @@
 	pth_cleanup_handler.stderr.exp		    \
 	pth_cleanup_handler.vgtest		    \
 	pth_cond_destroy_busy.stderr.exp            \
+	pth_cond_destroy_busy.stderr.exp-solaris    \
 	pth_cond_destroy_busy.vgtest                \
 	pth_cond_race.stderr.exp                    \
 	pth_cond_race.vgtest                        \
@@ -210,6 +219,7 @@
 	read_and_free_race.vgtest		    \
 	recursive_mutex.stderr.exp-linux            \
 	recursive_mutex.stderr.exp-darwin           \
+	recursive_mutex.stderr.exp-solaris          \
 	recursive_mutex.vgtest                      \
 	rwlock_race.stderr.exp	                    \
 	rwlock_race.stderr.exp2	                    \
@@ -283,6 +293,7 @@
 	tc09_bad_unlock.stderr.exp-ppc              \
 	tc09_bad_unlock.stderr.exp-glibc2.8         \
 	tc09_bad_unlock.stderr.exp-s390             \
+	tc09_bad_unlock.stderr.exp-solaris          \
 	tc09_bad_unlock.vgtest                      \
 	tc10_rec_lock.stderr.exp                    \
 	tc10_rec_lock.vgtest                        \
@@ -299,6 +310,7 @@
 	tc17_sembar.stderr.exp                      \
 	tc17_sembar.vgtest                          \
 	tc18_semabuse.stderr.exp                    \
+	tc18_semabuse.stderr.exp-solaris            \
 	tc18_semabuse.vgtest                        \
 	tc19_shadowmem.stderr.exp-32bit             \
 	tc19_shadowmem.stderr.exp-64bit             \
@@ -442,6 +454,20 @@
 monitor_example_SOURCES     = monitor_example.cpp
 new_delete_SOURCES          = new_delete.cpp
 
+free_is_write_CFLAGS        = $(AM_CFLAGS)
+pth_barrier_CFLAGS          = $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+free_is_write_CFLAGS        += -D__EXTENSIONS__
+pth_barrier_CFLAGS          += -D__EXTENSIONS__
+endif
+
+pth_create_chain_CFLAGS     = $(AM_CFLAGS)
+pth_detached_CFLAGS         = $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+pth_create_chain_CFLAGS     += -D__EXTENSIONS__
+pth_detached_CFLAGS         += -D__EXTENSIONS__
+endif
+
 tsan_unittest_SOURCES       = tsan_unittest.cpp
 tsan_unittest_CXXFLAGS      = $(AM_CXXFLAGS) \
 			-DTHREAD_WRAPPERS='"tsan_thread_wrappers_pthread.h"'
@@ -474,6 +500,10 @@
 omp_matinv_LDFLAGS          = -fopenmp
 omp_matinv_LDADD            = $(LDADD) -lm
 
+if VGCONF_OS_IS_SOLARIS
+omp_matinv_CFLAGS           += -std=gnu99
+endif
+
 omp_prime_CFLAGS            = $(AM_CFLAGS) -fopenmp
 omp_prime_LDFLAGS           = -fopenmp
 omp_prime_LDADD             = $(LDADD) -lm
@@ -483,10 +513,19 @@
 omp_printf_LDADD            = $(LDADD) -lm
 endif
 
+matinv_CFLAGS               = $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+matinv_CFLAGS               += -std=gnu99 -D__EXTENSIONS__
+endif
 if HAVE_PTHREAD_BARRIER
 matinv_LDADD                = $(LDADD) -lm
 endif
 
+rwlock_test_CFLAGS          = $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+rwlock_test_CFLAGS          += -D__EXTENSIONS__
+endif
+
 std_atomic_SOURCES          = std_atomic.cpp
 std_atomic_CXXFLAGS         = $(AM_CXXFLAGS) -std=c++0x -Wno-sign-compare
 
@@ -501,10 +540,14 @@
 
 std_thread_SOURCES          = std_thread.cpp
 std_thread_CXXFLAGS         = $(AM_CXXFLAGS) -std=c++0x
+if !VGCONF_OS_IS_SOLARIS
 std_thread_LDFLAGS          = -Wl,--no-as-needed
+endif
 
 std_thread2_SOURCES          = std_thread2.cpp
 std_thread2_CXXFLAGS         = $(AM_CXXFLAGS) -std=c++0x
+if !VGCONF_OS_IS_SOLARIS
 std_thread2_LDFLAGS          = -Wl,--no-as-needed
+endif
 
 sem_wait_SOURCES            = sem_wait.cpp
diff --git a/drd/tests/annotate_ignore_rw2.stderr.exp-solaris b/drd/tests/annotate_ignore_rw2.stderr.exp-solaris
new file mode 100644
index 0000000..a35389f
--- /dev/null
+++ b/drd/tests/annotate_ignore_rw2.stderr.exp-solaris
@@ -0,0 +1,25 @@
+
+Thread 2:
+Conflicting load by thread 2 at 0x........ size 1
+   at 0x........: thread_func (annotate_ignore_rw.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+Location 0x........ is 0 bytes inside global var "s_a"
+declared at annotate_ignore_rw.c:10
+
+Conflicting store by thread 2 at 0x........ size 1
+   at 0x........: thread_func (annotate_ignore_rw.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+Location 0x........ is 0 bytes inside global var "s_b"
+declared at annotate_ignore_rw.c:11
+
+Thread 1:
+Conflicting load by thread 1 at 0x........ size 1
+   at 0x........: main (annotate_ignore_rw.c:?)
+Location 0x........ is 0 bytes inside global var "s_c"
+declared at annotate_ignore_rw.c:12
+
+Finished.
+
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/annotate_ignore_write.stderr.exp-solaris b/drd/tests/annotate_ignore_write.stderr.exp-solaris
new file mode 100644
index 0000000..fa61979
--- /dev/null
+++ b/drd/tests/annotate_ignore_write.stderr.exp-solaris
@@ -0,0 +1,23 @@
+
+Thread 2:
+Conflicting store by thread 2 at 0x........ size 1
+   at 0x........: thread_func (annotate_ignore_write.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+Location 0x........ is 0 bytes inside global var "s_b"
+declared at annotate_ignore_write.c:11
+
+Thread 1:
+Conflicting load by thread 1 at 0x........ size 1
+   at 0x........: main (annotate_ignore_write.c:?)
+Location 0x........ is 0 bytes inside global var "s_c"
+declared at annotate_ignore_write.c:12
+
+Conflicting store by thread 1 at 0x........ size 1
+   at 0x........: main (annotate_ignore_write.c:?)
+Location 0x........ is 0 bytes inside global var "s_a"
+declared at annotate_ignore_write.c:10
+
+Finished.
+
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/annotate_ignore_write2.stderr.exp-solaris b/drd/tests/annotate_ignore_write2.stderr.exp-solaris
new file mode 100644
index 0000000..2511ff1
--- /dev/null
+++ b/drd/tests/annotate_ignore_write2.stderr.exp-solaris
@@ -0,0 +1,30 @@
+
+Thread 2:
+Conflicting load by thread 2 at 0x........ size 1
+   at 0x........: thread_func (annotate_ignore_write.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+Location 0x........ is 0 bytes inside global var "s_a"
+declared at annotate_ignore_write.c:10
+
+Conflicting store by thread 2 at 0x........ size 1
+   at 0x........: thread_func (annotate_ignore_write.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+Location 0x........ is 0 bytes inside global var "s_b"
+declared at annotate_ignore_write.c:11
+
+Thread 1:
+Conflicting load by thread 1 at 0x........ size 1
+   at 0x........: main (annotate_ignore_write.c:?)
+Location 0x........ is 0 bytes inside global var "s_c"
+declared at annotate_ignore_write.c:12
+
+Conflicting store by thread 1 at 0x........ size 1
+   at 0x........: main (annotate_ignore_write.c:?)
+Location 0x........ is 0 bytes inside global var "s_a"
+declared at annotate_ignore_write.c:10
+
+Finished.
+
+ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/filter_stderr b/drd/tests/filter_stderr
index a66a149..9347e4e 100755
--- a/drd/tests/filter_stderr
+++ b/drd/tests/filter_stderr
@@ -6,6 +6,13 @@
 
 $dir/../../tests/filter_stderr_basic |
 
+# Perform Solaris-specific filtering.
+if $dir/../../tests/os_test solaris; then
+   perl -p $dir/filter_stderr_solaris
+else
+   cat
+fi |
+
 # Remove "drd, ..." line and the following copyright line.
 # Remove line numbers referring to drd's source code.
 # Remove libpthread's version number.
diff --git a/drd/tests/filter_stderr_solaris b/drd/tests/filter_stderr_solaris
new file mode 100755
index 0000000..781f97e
--- /dev/null
+++ b/drd/tests/filter_stderr_solaris
@@ -0,0 +1,55 @@
+#!/usr/bin/perl
+
+# Replace stack frame for a thread created by pthread_create():
+#     by 0x........: _thrp_setup (in /lib/libc.so.1)
+# with a stack frame expected on Linux:
+#     by 0x........: start_thread (pthread_create.c:123)
+# It will be further reduced and mangled by the main filter_stderr script.
+# This needs to be done first.
+s/_thrp_setup \(in .*libc.*\)/start_thread \(pthread_create.c:123\)/g;
+
+# We need to filter out the Solaris libc's stack frame which looks like:
+#     by 0x........: pthread_mutex_init (in /...libc...)
+# to be consistent with the expected output of test cases.
+#
+# Stack frames for synchronization functions are missing on Linux because
+# of optimalization. 
+# 
+s/.*\(in \/...libc...\)\R//m;
+
+# We need to replace Solaris threading and sychronization function
+# names with POSIX ones for drd_pthread_intercepts.c stack frame:
+#     by 0x........: cond_init (drd_pthread_intercepts.c:123)
+# See also comments in drd_pthread_intercepts.c.
+my %regex = (
+    'thr_create'     => 'pthread_create',
+    'thr_join'       => 'pthread_join',
+    'mutex_init'     => 'pthread_mutex_init',
+    'mutex_destroy'  => 'pthread_mutex_destroy',
+    'mutex_lock'     => 'pthread_mutex_lock',
+    'mutex_trylock'  => 'pthread_mutex_trylock',
+    'mutex_unlock'   => 'pthread_mutex_unlock',
+    'cond_init'      => 'pthread_cond_init',
+    'cond_destroy'   => 'pthread_cond_destroy',
+    'cond_wait'      => 'pthread_cond_wait',
+    'cond_timedwait' => 'pthread_cond_timedwait',
+    'cond_signal'    => 'pthread_cond_signal',
+    'cond_broadcast' => 'pthread_cond_broadcast',
+    'sema_init'      => 'sem_init',
+    'sema_destroy'   => 'sem_destroy',
+    'sema_wait'      => 'sem_wait',
+    'sema_trywait'   => 'sem_trywait',
+    'sema_timedwait' => 'sem_timedwait',
+    'sema_post'      => 'sem_post',
+    'rwlock_init'    => 'pthread_rwlock_init',
+    'rwlock_destroy' => 'pthread_rwlock_destroy',
+    'rw_rdlock'      => 'pthread_rwlock_rdlock',
+    'rw_wrlock'      => 'pthread_rwlock_wrlock',
+    'rw_tryrdlock'   => 'pthread_rwlock_tryrdlock',
+    'rw_trywrlock'   => 'pthread_rwlock_trywrlock',
+    'rw_unlock'      => 'pthread_rwlock_unlock'
+);
+my $check = join "|", keys %regex;
+if (! /: pthread_/) {
+    s/($check)(.*drd_pthread_intercepts.c)/$regex{$1}$2/g;
+}
diff --git a/drd/tests/filter_thread_name_xml b/drd/tests/filter_thread_name_xml
new file mode 100755
index 0000000..458b5b6
--- /dev/null
+++ b/drd/tests/filter_thread_name_xml
@@ -0,0 +1,12 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+$dir/../../memcheck/tests/filter_xml |
+
+# Perform Solaris-specific filtering (see filter_stderr_solaris).
+if $dir/../../tests/os_test solaris; then
+   sed -e 's/mutex_unlock/pthread_mutex_unlock/'
+else
+   cat
+fi
diff --git a/drd/tests/fp_race_xml.stderr.exp-solaris b/drd/tests/fp_race_xml.stderr.exp-solaris
new file mode 100644
index 0000000..05ffe71
--- /dev/null
+++ b/drd/tests/fp_race_xml.stderr.exp-solaris
@@ -0,0 +1,104 @@
+<?xml version="1.0"?>
+
+<valgrindoutput>
+
+<protocolversion>4</protocolversion>
+<protocoltool>drd</protocoltool>
+
+<preamble>
+  <line>...</line>
+  <line>...</line>
+  <line>...</line>
+  <line>...</line>
+</preamble>
+
+<pid>...</pid>
+<ppid>...</ppid>
+<tool>drd</tool>
+
+<args>
+  <vargv>...</vargv>
+  <argv>
+    <exe>./fp_race</exe>
+  </argv>
+</args>
+
+<status>
+  <state>RUNNING</state>
+  <time>...</time>
+</status>
+
+  <trace><text>drd_pre_thread_create creator = 0, created = 1</text></trace>
+  <trace><text>drd_post_thread_create created = 1</text></trace>
+  <trace><text>drd_pre_thread_create creator = 1, created = 2</text></trace>
+  <trace><text>drd_post_thread_create created = 2</text></trace>
+  <trace><text>drd_thread_finished tid = 2</text></trace>
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <kind>ConflictingAccess</kind>
+  <what>Conflicting load by thread x at 0x........ size 8</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>fp_race.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Location 0x........ is 0 bytes inside global var "s_d3"</auxwhat>
+  <xauxwhat><text>declared at fp_race.c:24</text> <file>fp_race.c</file> <line>...</line> </xauxwhat>
+  <other_segment_start>
+  </other_segment_start>
+  <other_segment_end>
+  </other_segment_end>
+</error>
+
+<error>
+  <unique>0x........</unique>
+  <tid>...</tid>
+  <kind>ConflictingAccess</kind>
+  <what>Conflicting store by thread x at 0x........ size 8</what>
+  <stack>
+    <frame>
+      <ip>0x........</ip>
+      <obj>...</obj>
+      <fn>main</fn>
+      <dir>...</dir>
+      <file>fp_race.c</file>
+      <line>...</line>
+    </frame>
+  </stack>
+  <auxwhat>Location 0x........ is 0 bytes inside global var "s_d3"</auxwhat>
+  <xauxwhat><text>declared at fp_race.c:24</text> <file>fp_race.c</file> <line>...</line> </xauxwhat>
+  <other_segment_start>
+  </other_segment_start>
+  <other_segment_end>
+  </other_segment_end>
+</error>
+
+  <trace><text>drd_post_thread_join joiner = 1, joinee = 2, new vc: [ ... ]</text></trace>
+  <trace><text>drd_thread_finished tid = 1</text></trace>
+
+<status>
+  <state>FINISHED</state>
+  <time>...</time>
+</status>
+
+<errorcounts>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+  <pair>
+    <count>...</count>
+    <unique>0x........</unique>
+  </pair>
+</errorcounts>
+
+<suppcounts>...</suppcounts>
+
+</valgrindoutput>
+
diff --git a/drd/tests/matinv.vgtest b/drd/tests/matinv.vgtest
index da2a6e4..4deae67 100644
--- a/drd/tests/matinv.vgtest
+++ b/drd/tests/matinv.vgtest
@@ -1,3 +1,3 @@
 prereq: test -e matinv && ./supported_libpthread
 prog: matinv
-args: 30 -t 15 -q
+args: -t 15 -q 30
diff --git a/drd/tests/omp_matinv.vgtest b/drd/tests/omp_matinv.vgtest
index c9d5ec1..5a32480 100644
--- a/drd/tests/omp_matinv.vgtest
+++ b/drd/tests/omp_matinv.vgtest
@@ -1,4 +1,4 @@
 prereq: ./run_openmp_test ./omp_matinv
 prog: omp_matinv
 vgopts: --check-stack-var=yes --read-var-info=yes
-args: 30 -t 15 -q
+args: -t 15 -q 30
diff --git a/drd/tests/omp_matinv_racy.vgtest b/drd/tests/omp_matinv_racy.vgtest
index 96a0f0f..327bccc 100644
--- a/drd/tests/omp_matinv_racy.vgtest
+++ b/drd/tests/omp_matinv_racy.vgtest
@@ -1,5 +1,5 @@
 prereq: ./run_openmp_test ./omp_matinv
 prog: omp_matinv
 vgopts: --check-stack-var=yes --read-var-info=yes
-args: 3 -t 2 -q -r
+args: -t 2 -q -r 3
 stderr_filter: filter_error_summary
diff --git a/drd/tests/omp_prime_racy.vgtest b/drd/tests/omp_prime_racy.vgtest
index 59381c9..e4f727b 100644
--- a/drd/tests/omp_prime_racy.vgtest
+++ b/drd/tests/omp_prime_racy.vgtest
@@ -1,5 +1,5 @@
 prereq: ./run_openmp_test ./omp_prime
 prog: omp_prime
 vgopts: --check-stack-var=yes --read-var-info=yes
-args: 4 -q
+args: -q 4
 stderr_filter: filter_error_summary
diff --git a/drd/tests/pth_barrier.c b/drd/tests/pth_barrier.c
index 854ee34..7fdffe1 100644
--- a/drd/tests/pth_barrier.c
+++ b/drd/tests/pth_barrier.c
@@ -50,13 +50,13 @@
   int8_t* const array = p->array;
   pthread_barrier_t* const b = p->b;
   if (! s_silent)
-    printf("thread %lx iteration 0\n", pthread_self());
+    printf("thread %lx iteration 0\n", (long) pthread_self());
   pthread_barrier_wait(b);
   for (i = 0; i < p->iterations; i++)
   {
     if (! s_silent)
       printf("thread %lx iteration %d; writing to %p\n",
-             pthread_self(), i + 1, &array[i]);
+             (long) pthread_self(), i + 1, &array[i]);
     array[i] = i;
     pthread_barrier_wait(b);
   }
diff --git a/drd/tests/pth_cond_destroy_busy.stderr.exp-solaris b/drd/tests/pth_cond_destroy_busy.stderr.exp-solaris
new file mode 100644
index 0000000..392bc1d
--- /dev/null
+++ b/drd/tests/pth_cond_destroy_busy.stderr.exp-solaris
@@ -0,0 +1,35 @@
+
+destruction of condition variable being waited upon: cond 0x........
+   at 0x........: pthread_cond_destroy (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+cond 0x........ was first observed at:
+   at 0x........: pthread_cond_init (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+
+Destroying condition variable that is being waited upon: cond 0x........, mutex 0x........ locked by thread 1
+   at 0x........: pthread_cond_destroy (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+
+First pthread_cond_destroy() call returned success.
+condition variable has not been initialized: cond 0x........
+   at 0x........: pthread_cond_signal (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+
+Thread 2:
+condition variable has been destroyed while being waited upon: cond 0x........, mutex 0x........ locked by thread 0
+   at 0x........: pthread_cond_wait (drd_pthread_intercepts.c:?)
+   by 0x........: thread_func (pth_cond_destroy_busy.c:?)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+   by 0x........: (within libpthread-?.?.so)
+
+Thread 1:
+not a condition variable: cond 0x........
+   at 0x........: pthread_cond_destroy (drd_pthread_intercepts.c:?)
+   by 0x........: main (pth_cond_destroy_busy.c:?)
+
+Second pthread_cond_destroy() call returned success.
+
+ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/pth_inconsistent_cond_wait.c b/drd/tests/pth_inconsistent_cond_wait.c
index fb95fd8..6691e84 100644
--- a/drd/tests/pth_inconsistent_cond_wait.c
+++ b/drd/tests/pth_inconsistent_cond_wait.c
@@ -107,7 +107,8 @@
   }
 
   /* Initialize synchronization objects. */
-  snprintf(semaphore_name, sizeof(semaphore_name), "semaphore-%d", getpid());
+  snprintf(semaphore_name, sizeof(semaphore_name), "semaphore-%ld",
+           (long) getpid());
   s_sem = create_semaphore(semaphore_name);
   PTH_CALL(pthread_cond_init(&s_cond, 0));
   PTH_CALL(pthread_mutex_init(&s_mutex1, 0));
diff --git a/drd/tests/recursive_mutex.stderr.exp-solaris b/drd/tests/recursive_mutex.stderr.exp-solaris
new file mode 100644
index 0000000..146b095
--- /dev/null
+++ b/drd/tests/recursive_mutex.stderr.exp-solaris
@@ -0,0 +1,18 @@
+
+Recursive mutex (statically initialized).
+
+Non-recursive mutex.
+second lock call failed !
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: lock_twice (recursive_mutex.c:?)
+   by 0x........: main (recursive_mutex.c:?)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_trylock (drd_pthread_intercepts.c:?)
+   by 0x........: lock_twice (recursive_mutex.c:?)
+   by 0x........: main (recursive_mutex.c:?)
+
+
+Done.
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/sem_open.c b/drd/tests/sem_open.c
index 958bc6b..7f00ca0 100644
--- a/drd/tests/sem_open.c
+++ b/drd/tests/sem_open.c
@@ -58,8 +58,8 @@
    * Use the ipcs and ipcrm commands to clean up named semaphores left by
    * aborted instances of this process.
    */
-  snprintf(semaphore_name, sizeof(semaphore_name), "/drd-sem-open-test-%d",
-	   getpid());
+  snprintf(semaphore_name, sizeof(semaphore_name), "/drd-sem-open-test-%ld",
+	   (long) getpid());
   s_sem = sem_open(semaphore_name, O_CREAT | O_EXCL, 0600, 1);
   if (s_sem == SEM_FAILED)
   {
diff --git a/drd/tests/sigalrm.c b/drd/tests/sigalrm.c
index 85987ab..2484a6d 100644
--- a/drd/tests/sigalrm.c
+++ b/drd/tests/sigalrm.c
@@ -32,8 +32,8 @@
   {
     char msg[256];
     snprintf(msg, sizeof(msg),
-             "%spid %d / kernel thread ID %d / Valgrind thread ID %d\n",
-             label, getpid(), getktid(), DRD_GET_VALGRIND_THREADID);
+             "%spid %ld / kernel thread ID %d / Valgrind thread ID %d\n",
+             label, (long) getpid(), getktid(), DRD_GET_VALGRIND_THREADID);
     write(STDOUT_FILENO, msg, strlen(msg));
   }
 }
diff --git a/drd/tests/std_string.cpp b/drd/tests/std_string.cpp
index 8a35fb3..266c93f 100644
--- a/drd/tests/std_string.cpp
+++ b/drd/tests/std_string.cpp
@@ -8,6 +8,7 @@
 #include <string>
 #include <cstring>
 #include <pthread.h>
+#include <stdlib.h>
 #include <unistd.h>
 
 char* list2byteArray()
diff --git a/drd/tests/tc09_bad_unlock.stderr.exp-solaris b/drd/tests/tc09_bad_unlock.stderr.exp-solaris
new file mode 100644
index 0000000..a517b71
--- /dev/null
+++ b/drd/tests/tc09_bad_unlock.stderr.exp-solaris
@@ -0,0 +1,54 @@
+
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:27)
+   by 0x........: main (tc09_bad_unlock.c:49)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:23)
+
+Thread 2:
+Mutex not locked by calling thread: mutex 0x........, recursion count 1, owner 1.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: child_fn (tc09_bad_unlock.c:11)
+   by 0x........: vgDrd_thread_wrapper (drd_pthread_intercepts.c:?)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:31)
+
+Thread 1:
+The object at address 0x........ is not a mutex.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:49)
+
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
+   at 0x........: nearly_main (tc09_bad_unlock.c:45)
+   by 0x........: main (tc09_bad_unlock.c:49)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:31)
+
+---------------------
+Mutex not locked by calling thread: mutex 0x........, recursion count 0, owner 1.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:27)
+   by 0x........: main (tc09_bad_unlock.c:50)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:23)
+
+The object at address 0x........ is not a mutex.
+   at 0x........: pthread_mutex_unlock (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:50)
+
+Destroying locked mutex: mutex 0x........, recursion count 1, owner 1.
+   at 0x........: nearly_main (tc09_bad_unlock.c:45)
+   by 0x........: main (tc09_bad_unlock.c:50)
+mutex 0x........ was first observed at:
+   at 0x........: pthread_mutex_init (drd_pthread_intercepts.c:?)
+   by 0x........: nearly_main (tc09_bad_unlock.c:31)
+
+
+ERROR SUMMARY: 8 errors from 7 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/tc12_rwl_trivial.stderr.exp b/drd/tests/tc12_rwl_trivial.stderr.exp
index 6ba7b18..554515d 100644
--- a/drd/tests/tc12_rwl_trivial.stderr.exp
+++ b/drd/tests/tc12_rwl_trivial.stderr.exp
@@ -1,10 +1,10 @@
 
 Reader-writer lock not locked by calling thread: rwlock 0x.........
    at 0x........: pthread_rwlock_unlock (drd_pthread_intercepts.c:?)
-   by 0x........: main (tc12_rwl_trivial.c:35)
+   by 0x........: main (tc12_rwl_trivial.c:29)
 rwlock 0x........ was first observed at:
    at 0x........: pthread_rwlock_init (drd_pthread_intercepts.c:?)
-   by 0x........: main (tc12_rwl_trivial.c:24)
+   by 0x........: main (tc12_rwl_trivial.c:18)
 
 
 ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/tc18_semabuse.stderr.exp-solaris b/drd/tests/tc18_semabuse.stderr.exp-solaris
new file mode 100644
index 0000000..9c2b278
--- /dev/null
+++ b/drd/tests/tc18_semabuse.stderr.exp-solaris
@@ -0,0 +1,10 @@
+
+Semaphore reinitialization: semaphore 0x........
+   at 0x........: sem_init (drd_pthread_intercepts.c:?)
+   by 0x........: main (tc18_semabuse.c:26)
+semaphore 0x........ was first observed at:
+   at 0x........: sem_init (drd_pthread_intercepts.c:?)
+   by 0x........: main (tc18_semabuse.c:23)
+
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/thread_name_xml.vgtest b/drd/tests/thread_name_xml.vgtest
index f931e48..c6cd1ca 100644
--- a/drd/tests/thread_name_xml.vgtest
+++ b/drd/tests/thread_name_xml.vgtest
@@ -1,4 +1,4 @@
 prereq: test -e thread_name && ./supported_libpthread
 vgopts: --read-var-info=yes --check-stack-var=yes --num-callers=3 --xml=yes --xml-fd=2
 prog: thread_name
-stderr_filter: ../../memcheck/tests/filter_xml
+stderr_filter: filter_thread_name_xml
diff --git a/drd/tests/tsan_unittest.cpp b/drd/tests/tsan_unittest.cpp
index 57bb310..79fea6b 100644
--- a/drd/tests/tsan_unittest.cpp
+++ b/drd/tests/tsan_unittest.cpp
@@ -97,6 +97,10 @@
 #include <malloc.h>
 #endif
 
+#ifdef VGO_solaris
+#include <strings.h> // index(), rindex()
+#endif
+
 // The tests are
 // - Stability tests (marked STAB)
 // - Performance tests (marked PERF)
@@ -4786,13 +4790,13 @@
   char out_name[100];
   // we open two files, on for reading and one for writing, 
   // but the files are actually the same (symlinked).
-  sprintf(out_name, "/tmp/racecheck_unittest_out.%d", getpid());
+  sprintf(out_name, "/tmp/racecheck_unittest_out.%ld", (long) getpid());
   fd_out = creat(out_name, O_WRONLY | S_IRWXU);
 #ifdef VGO_darwin
   // symlink() is not supported on Darwin. Copy the output file name.
   strcpy(in_name, out_name);
 #else
-  sprintf(in_name,  "/tmp/racecheck_unittest_in.%d", getpid());
+  sprintf(in_name,  "/tmp/racecheck_unittest_in.%ld", (long) getpid());
   IGNORE_RETURN_VALUE(symlink(out_name, in_name));
 #endif
   fd_in  = open(in_name, 0, O_RDONLY);
diff --git a/exp-bbv/tests/x86/complex_rep.S b/exp-bbv/tests/x86/complex_rep.S
index fca36e5..595f369 100644
--- a/exp-bbv/tests/x86/complex_rep.S
+++ b/exp-bbv/tests/x86/complex_rep.S
@@ -48,12 +48,18 @@
 	#================================
 exit:
      	mov	$1,%eax
-#ifdef VGO_darwin
-	pushl	$0
-#else	
+#if defined(VGO_darwin)
+	pushl   $0			# we return 0
+	int     $0x80          		# and exit
+#elif defined(VGO_linux)
 	xor     %ebx,%ebx		# we return 0
-#endif	
 	int	$0x80          		# and exit
+#elif defined(VGO_solaris)
+	pushl   $0			# we return 0
+	int     $0x91          		# and exit
+#else
+#  error "Unknown OS"
+#endif
 
 
 #.bss
diff --git a/exp-bbv/tests/x86/fldcw_check.S b/exp-bbv/tests/x86/fldcw_check.S
index ef4c3a7..52f9433 100644
--- a/exp-bbv/tests/x86/fldcw_check.S
+++ b/exp-bbv/tests/x86/fldcw_check.S
@@ -99,26 +99,39 @@
 	
 print_error:
 	mov 	$4,%eax			# write syscall
-#ifdef VGO_darwin
-	pushl	$1
-	pushl	$error
+#if defined(VGO_darwin)
 	pushl	$22
-#else	
+	pushl	$error
+	pushl	$1
+	int 	$0x80
+#elif defined(VGO_linux)
 	mov	$1,%ebx			# stdout
 	mov	$error,%ecx		# string	
 	mov 	$22,%edx		# length of string
-#endif	
 	int 	$0x80
-	
+#elif defined(VGO_solaris)
+	pushl	$22
+	pushl	$error
+	pushl	$1
+	int 	$0x91
+#else
+#  error "Unknown OS"
+#endif
+
 exit:
-#ifdef VGO_darwin
-	pushl	result
-#else	
-	movl	result, %ebx		# load converted value
-#endif	
 	movl	$1,	%eax		# SYSCALL_EXIT
+#if defined(VGO_darwin)
+	pushl	result
 	int	$0x80
-	
+#elif defined(VGO_linux)
+	movl	result, %ebx		# load converted value
+	int	$0x80
+#elif defined(VGO_solaris)
+	pushl	result
+	int	$0x91
+#else
+#  error "Unknown OS"
+#endif
 
 
 .data
@@ -127,4 +140,4 @@
 result: .long	0
 three:	.long	0			# a floating point 3.0
 	.long	1074266112
-error:	.asciz  "Error!  Wrong result!\n"
+error:	.ascii  "Error!  Wrong result!\n\0"
diff --git a/exp-bbv/tests/x86/million.S b/exp-bbv/tests/x86/million.S
index 0d72b00..e034cc8 100644
--- a/exp-bbv/tests/x86/million.S
+++ b/exp-bbv/tests/x86/million.S
@@ -20,14 +20,17 @@
 	#                 in arc/x86/include/asm/unistd_32.h on Linux
 	# disassemble on OSX otool -tV
 exit:
-#ifdef VGO_darwin
-	pushl   $0			# we return 0
 	xor	%eax,%eax
 	inc	%eax	 		# put exit syscall number (1) in eax
-	int     $0x80             	# and exit
-#else	
+#if defined(VGO_darwin)
+	pushl	$0			# we return 0
+	int     $0x80			# and exit
+#elif defined(VGO_linux)
 	xor     %ebx,%ebx		# we return 0
-	xor	%eax,%eax
-	inc	%eax	 		# put exit syscall number (1) in eax
-	int     $0x80             	# and exit
+	int     $0x80			# and exit
+#elif defined(VGO_solaris)
+	pushl	$0			# we return 0
+	int     $0x91			# and exit
+#else
+#  error "Unknown OS"
 #endif
diff --git a/exp-bbv/tests/x86/rep_prefix.S b/exp-bbv/tests/x86/rep_prefix.S
index 346248c..4588815 100644
--- a/exp-bbv/tests/x86/rep_prefix.S
+++ b/exp-bbv/tests/x86/rep_prefix.S
@@ -246,33 +246,47 @@
 print_error:
 	    
 	mov 	$4, %eax		# Write syscall
-#ifdef VGO_darwin
-	pushl	$1
-	pushl	$error_string
+#if defined(VGO_darwin)
 	pushl	$16
-#else	
+	pushl	$error_string
+	pushl	$1
+	int 	$0x80
+#elif defined(VGO_linux)
 	mov	$1, %ebx		# print to stdout
 	mov	$error_string, %ecx	# string to print
 	mov	$16, %edx      	   	# strlen
-#endif	
-	int	$0x80	 		# call syscall
+	int 	$0x80
+#elif defined(VGO_solaris)
+	pushl	$16
+	pushl	$error_string
+	pushl	$1
+	int 	$0x91
+#else
+#  error "Unknown OS"
+#endif
 
 	#================================
 	# Exit
 	#================================
 exit:
-#ifdef VGO_darwin	
-	xor     %ebx,%ebx		# we return 0
-#else
-	pushl	$0			# we return 0
-#endif	
 	xor	%eax,%eax
 	inc	%eax	 		# put exit syscall number (1) in eax
+#if defined(VGO_darwin)
+	pushl   $0			# we return 0
 	int     $0x80             	# and exit
+#elif defined(VGO_linux)
+	xor     %ebx,%ebx		# we return 0
+	int     $0x80             	# and exit
+#elif defined(VGO_solaris)
+	pushl   $0			# we return 0
+	int     $0x91             	# and exit
+#else
+#  error "Unknown OS"
+#endif
 
 
 .data
-error_string:	.asciz "Error detected!\n"
+error_string:	.ascii "Error detected!\n\0"
 
 #.bss
 
diff --git a/exp-sgcheck/h_intercepts.c b/exp-sgcheck/h_intercepts.c
index 64bc7f7..8555e17 100644
--- a/exp-sgcheck/h_intercepts.c
+++ b/exp-sgcheck/h_intercepts.c
@@ -68,6 +68,8 @@
 #elif defined(VGO_darwin)
 STRRCHR(VG_Z_DYLD,          strrchr)
 STRRCHR(VG_Z_DYLD,          rindex)
+#elif defined(VGO_solaris)
+STRRCHR(VG_Z_LD_SO_1,       strrchr)
 #endif
 
 
@@ -96,6 +98,8 @@
 #elif defined(VGO_darwin)
 STRCHR(VG_Z_DYLD,                 strchr)
 STRCHR(VG_Z_DYLD,                 index)
+#elif defined(VGO_solaris)
+STRCHR(VG_Z_LD_SO_1,              strchr)
 #endif
 
 
@@ -130,6 +134,8 @@
 STRLEN(VG_Z_LD_LINUX_SO_2,        strlen)
 STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
 STRLEN(VG_Z_LD_SO_1,              strlen)
+#elif defined(VGO_solaris)
+STRLEN(VG_Z_LD_SO_1,              strlen)
 #endif
 
 
@@ -150,6 +156,8 @@
 STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy)
 #elif defined(VGO_darwin)
 STRCPY(VG_Z_DYLD,        strcpy)
+#elif defined(VGO_solaris)
+STRCPY(VG_Z_LD_SO_1,     strcpy)
 #endif
 
 
@@ -206,6 +214,8 @@
 STRCMP(VG_Z_LIBC_SONAME,          __GI_strcmp)
 STRCMP(VG_Z_LD_LINUX_X86_64_SO_2, strcmp)
 STRCMP(VG_Z_LD64_SO_1,            strcmp)
+#elif defined(VGO_solaris)
+STRCMP(VG_Z_LD_SO_1,              strcmp)
 #endif
 
 
@@ -301,6 +311,8 @@
 #if defined(VGO_linux)
 MEMCPY(VG_Z_LD_SO_1,     memcpy) /* ld.so.1 */
 MEMCPY(VG_Z_LD64_SO_1,   memcpy) /* ld64.so.1 */
+#elif defined(VGO_solaris)
+MEMCPY(VG_Z_LD_SO_1,      memcpy)
 #endif
 
 
@@ -381,6 +393,8 @@
 
 #if defined(VGO_linux)
 STRSTR(VG_Z_LIBC_SONAME,          strstr)
+#elif defined(VGO_solaris)
+STRSTR(VG_Z_LIBC_SONAME,          strstr)
 #endif
 
 
@@ -418,6 +432,8 @@
 
 #if defined(VGO_linux)
 STRPBRK(VG_Z_LIBC_SONAME,          strpbrk)
+#elif defined(VGO_solaris)
+STRPBRK(VG_Z_LIBC_SONAME,          strpbrk)
 #endif
 
 
diff --git a/exp-sgcheck/tests/bad_percentify.vgtest b/exp-sgcheck/tests/bad_percentify.vgtest
index fbc0a83..a0e50bf 100644
--- a/exp-sgcheck/tests/bad_percentify.vgtest
+++ b/exp-sgcheck/tests/bad_percentify.vgtest
@@ -1,2 +1,2 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 prog: bad_percentify
diff --git a/exp-sgcheck/tests/globalerr.vgtest b/exp-sgcheck/tests/globalerr.vgtest
index a679a82..0f92ab3 100644
--- a/exp-sgcheck/tests/globalerr.vgtest
+++ b/exp-sgcheck/tests/globalerr.vgtest
@@ -1,2 +1,2 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 prog: globalerr
diff --git a/exp-sgcheck/tests/hackedbz2.vgtest b/exp-sgcheck/tests/hackedbz2.vgtest
index b84d395..95a2829 100644
--- a/exp-sgcheck/tests/hackedbz2.vgtest
+++ b/exp-sgcheck/tests/hackedbz2.vgtest
@@ -1,2 +1,2 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 prog: hackedbz2
diff --git a/exp-sgcheck/tests/hsg.vgtest b/exp-sgcheck/tests/hsg.vgtest
index b03f438..cdf35ba 100644
--- a/exp-sgcheck/tests/hsg.vgtest
+++ b/exp-sgcheck/tests/hsg.vgtest
@@ -1,4 +1,4 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 prog: hsg
 vgopts: --xml=yes --xml-fd=2 --log-file=/dev/null
 stderr_filter: ../../memcheck/tests/filter_xml
diff --git a/exp-sgcheck/tests/preen_invars.vgtest b/exp-sgcheck/tests/preen_invars.vgtest
index 3c880bc..cbd0d52 100644
--- a/exp-sgcheck/tests/preen_invars.vgtest
+++ b/exp-sgcheck/tests/preen_invars.vgtest
@@ -1,2 +1,2 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 prog: preen_invars
diff --git a/exp-sgcheck/tests/stackerr.vgtest b/exp-sgcheck/tests/stackerr.vgtest
index 80481eb..8f20a4f 100644
--- a/exp-sgcheck/tests/stackerr.vgtest
+++ b/exp-sgcheck/tests/stackerr.vgtest
@@ -1,3 +1,3 @@
-prereq: ./is_arch_supported && ../../tests/os_test linux
+prereq: ./is_arch_supported && (../../tests/os_test linux || ../../tests/os_test solaris)
 vgopts: --num-callers=3
 prog: stackerr
diff --git a/gdbserver_tests/Makefile.am b/gdbserver_tests/Makefile.am
index d5a0306..bdf0c5b 100644
--- a/gdbserver_tests/Makefile.am
+++ b/gdbserver_tests/Makefile.am
@@ -1,11 +1,22 @@
 
 include $(top_srcdir)/Makefile.tool-tests.am
 
+SUBDIRS = .
+
+# OS-specific tests 
+if VGCONF_OS_IS_SOLARIS
+SUBDIRS += solaris
+endif
+
+DIST_SUBDIRS = solaris
+
 dist_noinst_SCRIPTS = \
 	invoker simulate_control_c make_local_links \
 	filter_gdb filter_make_empty \
 	filter_memcheck_monitor filter_stderr filter_vgdb \
-	filter_helgrind_monitor send_signal
+	filter_helgrind_monitor filter_helgrind_monitor_solaris \
+	filter_passsigalrm \
+	send_signal
 
 EXTRA_DIST = \
 	README_DEVELOPERS \
@@ -61,6 +72,7 @@
 	mcleak.vgtest \
 	mcmain_pic.stderrB.exp \
 	mcmain_pic.stderr.exp \
+	mcmain_pic.stderr.exp-solaris \
 	mcmain_pic.stdinB.gdb \
 	mcmain_pic.stdoutB.exp \
 	mcmain_pic.stdout.exp \
@@ -135,7 +147,9 @@
 	nlvgdbsigqueue.stderrB.exp \
 	nlvgdbsigqueue.stderr.exp \
 	nlvgdbsigqueue.stdinB.gdb \
-	nlvgdbsigqueue.stdoutB.exp
+	nlvgdbsigqueue.stdoutB.exp \
+	nlvgdbsigqueue.stdoutB.exp-solaris1 \
+	nlvgdbsigqueue.stdoutB.exp-solaris2
 
 check_PROGRAMS = \
 	clean_after_fork \
diff --git a/gdbserver_tests/filter_gdb b/gdbserver_tests/filter_gdb
index 28bbf0b..df9479f 100755
--- a/gdbserver_tests/filter_gdb
+++ b/gdbserver_tests/filter_gdb
@@ -44,6 +44,8 @@
 #       and cleanup some lines for a system call (on ubuntu 10 64 bits)
 #           (pay attention : there are tab characters there in)
 #           + yet another way to get a select system call
+#       and yet another (Solaris way) to get a poll system call
+#             (on 32 bits, we have /lib/libc.so.*, on 64 bits, /lib/64/libc.so.*)
 #       which registers can't be modified
 #       special transform for arm/ppc watchpoints which have an additional address
 #              at the beginning
@@ -73,7 +75,7 @@
     -e 's/\(\[Switching to thread [1234] (Thread ....)\]\)#0/\1\n#0/'                                 \
     -e 's/^\([ \* ] [0-9] Thread .... (tid [0-9] VgTs_WaitSys)  0x........ in\).*$/\1 syscall .../'   \
     -e 's/#[0-9]\(  0x........ in sleeper_or_burner\)/#.\1/'                                          \
-    -e 's/\(#0  0x........ in do_burn ()\) at sleepers.c:39/\1/'                                      \
+    -e 's/\(#0  0x........ in do_burn ()\) at sleepers.c:41/\1/'                                      \
     -e '/^Reading symbols from .*\.\.\.done\./d'                                                      \
     -e '/^Loaded symbols for .*$/d'                                                                   \
     -e '/^Current language.*/d'                                                                       \
@@ -102,6 +104,8 @@
     -e '/^[1-9][0-9]*[ 	]*\.\.\/sysdeps\/unix\/syscall-template\.S/d'                                 \
     -e '/^[1-9][0-9]*[ 	]in *\.\.\/sysdeps\/unix\/syscall-template\.S/d'                              \
     -e '/^[1-9][0-9]*[ 	]T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)/d'                    \
+    -e 's/in __pollsys () from \/.*$/in syscall .../'                                                 \
+    -e '/^   from \/lib\/64\/libc.so.*$/d'                                                            \
     -e 's/\(Could not write register \)".*"/\1 "xxx"/'                                                \
     -e 's/\(ERROR changing register \).*$/\1 xxx regno y/'                                            \
     -e 's/0x........ in \(main (argc=1, argv=0x........) at watchpoints.c:[24][3689]\)/\1/'           \
diff --git a/gdbserver_tests/filter_helgrind_monitor b/gdbserver_tests/filter_helgrind_monitor
index bba9454..dc86480 100755
--- a/gdbserver_tests/filter_helgrind_monitor
+++ b/gdbserver_tests/filter_helgrind_monitor
@@ -9,5 +9,12 @@
 # filter vgdb messages
 $dir/filter_vgdb |
 
+# Perform Solaris-specific filtering.
+if $dir/../tests/os_test solaris; then
+   $dir/filter_helgrind_monitor_solaris
+else
+   cat
+fi |
+
 # and remove any remaining empty lines
 sed -e '/^$/d'
diff --git a/gdbserver_tests/filter_helgrind_monitor_solaris b/gdbserver_tests/filter_helgrind_monitor_solaris
new file mode 100755
index 0000000..f3cded0
--- /dev/null
+++ b/gdbserver_tests/filter_helgrind_monitor_solaris
@@ -0,0 +1,42 @@
+#!/usr/bin/env perl
+
+#
+# Filter out all helgrind information about locks except the one named "mx".
+# One lock record looks like:
+# Lock ga 0x........ {
+#  Address 0x........ is 9728 bytes inside data symbol "_uberdata"
+#   kind   mbRec
+# }
+
+use strict;
+use warnings;
+
+my $lock_start_line = undef;
+my $skip_to_closing_line = 0;
+while (<STDIN>) {
+    my $line = $_;
+    chomp($line);
+    if ($line =~ /^Lock ga 0x[\.]+\s+{$/) {
+        $lock_start_line = $line;
+        $skip_to_closing_line = 1;
+    } elsif (($lock_start_line) &&
+             ($line =~ /\s*Address 0x[\.]+ is \d+ bytes inside data symbol "(\S+)"/)) {
+        if ($1 eq "mx") {
+           print "$lock_start_line\n";
+           print "$line\n";
+           $skip_to_closing_line = 0;
+        }
+    } elsif ($line =~ /^}$/) {
+        if ($skip_to_closing_line == 0) {
+            print "$line\n";
+        }
+        undef($lock_start_line);
+        $skip_to_closing_line = 0;
+    } else {
+        if ($skip_to_closing_line == 0) {
+            print "$line\n";
+        }
+    }
+}
+
+exit 0;
diff --git a/gdbserver_tests/filter_passsigalrm b/gdbserver_tests/filter_passsigalrm
new file mode 100755
index 0000000..6b86f38
--- /dev/null
+++ b/gdbserver_tests/filter_passsigalrm
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+$dir/filter_gdb |
+
+# Filter the number of real-time signal SIGRTMIN which
+# varies accross systems.
+
+sed 's/Program received signal SIG[0-9]*, Real-time event [0-9]*./Program received signal SIGxx, Real-time event xx./'
diff --git a/gdbserver_tests/main_pic.c b/gdbserver_tests/main_pic.c
index e452b30..6d7e3bb 100644
--- a/gdbserver_tests/main_pic.c
+++ b/gdbserver_tests/main_pic.c
@@ -1,3 +1,4 @@
+#include <inttypes.h>
 #include <stdio.h>
 
 static void another_func(char *msg)
@@ -7,8 +8,8 @@
 
 int main (int argc, char *argv[])
 {
-   printf("address of main %p\n", &main);
-   printf("address of another_func %p\n", &another_func);
+   printf("address of main %#" PRIxPTR "\n", (uintptr_t) main);
+   printf("address of another_func %#" PRIxPTR "\n", (uintptr_t) another_func);
    another_func("called from main");
    return 0;
 }
diff --git a/gdbserver_tests/make_local_links b/gdbserver_tests/make_local_links
index cbdfef5..001609a 100755
--- a/gdbserver_tests/make_local_links
+++ b/gdbserver_tests/make_local_links
@@ -95,6 +95,7 @@
 fi
 
 ln -f -s ../coregrind/vgdb gdbserver_tests/vgdb
+ln -f -s ../../coregrind/vgdb gdbserver_tests/solaris/vgdb
 
 # if ptrace not implemented in vgdb or OS restricts the initial attach,
 # some tests would block for a loooonnnng time.
@@ -108,3 +109,4 @@
 
 # cleanup the possibly big garbage previously collected output
 rm -f gdbserver_tests/garbage.filtered.out
+rm -f gdbserver_tests/solaris/garbage.filtered.out 
diff --git a/gdbserver_tests/mcbreak.stdinB.gdb b/gdbserver_tests/mcbreak.stdinB.gdb
index 4f932e6..38285a7 100644
--- a/gdbserver_tests/mcbreak.stdinB.gdb
+++ b/gdbserver_tests/mcbreak.stdinB.gdb
@@ -16,8 +16,8 @@
 end
 #
 # break1 and break2
-break t.c:112
-break t.c:117
+break t.c:113
+break t.c:118
 #
 continue
 # first break encountered.
diff --git a/gdbserver_tests/mcbreak.stdoutB.exp b/gdbserver_tests/mcbreak.stdoutB.exp
index e12d2e4..c2e2e19 100644
--- a/gdbserver_tests/mcbreak.stdoutB.exp
+++ b/gdbserver_tests/mcbreak.stdoutB.exp
@@ -1,54 +1,54 @@
-Breakpoint 1 at 0x........: file t.c, line 112.
-Breakpoint 2 at 0x........: file t.c, line 117.
+Breakpoint 1 at 0x........: file t.c, line 113.
+Breakpoint 2 at 0x........: file t.c, line 118.
 Continuing.
-Breakpoint 1, main (argc=1, argv=0x........) at t.c:112
-112	  breakme(__LINE__); //break1
-breakme (line=112) at t.c:100
-100	   if (line > 1000)
+Breakpoint 1, main (argc=1, argv=0x........) at t.c:113
+113	  breakme(__LINE__); //break1
+breakme (line=113) at t.c:101
+101	   if (line > 1000)
 old_pc has changed after step
-102	}
+103	}
 old_pc has changed after step
-main (argc=1, argv=0x........) at t.c:113
-113	  for (i = len-1; i >= 0; i=i-2)
+main (argc=1, argv=0x........) at t.c:114
+114	  for (i = len-1; i >= 0; i=i-2)
 old_pc has changed after step
-114	     undefined[i] = undef;
+115	     undefined[i] = undef;
 $1 = void
 $2 = "undefined"
 $3 = 8
-113	  for (i = len-1; i >= 0; i=i-2)
+114	  for (i = len-1; i >= 0; i=i-2)
 old_pc has changed after step
-114	     undefined[i] = undef;
+115	     undefined[i] = undef;
 old_pc has changed after step
-113	  for (i = len-1; i >= 0; i=i-2)
+114	  for (i = len-1; i >= 0; i=i-2)
 $4 = void
 $5 = "undefi?e?"
 $6 = 6
-114	     undefined[i] = undef;
+115	     undefined[i] = undef;
 $7 = void
 $8 = "undefi?e?"
 $9 = 4
-113	  for (i = len-1; i >= 0; i=i-2)
+114	  for (i = len-1; i >= 0; i=i-2)
 $10 = void
 $11 = "unde?i?e?"
 $12 = 4
 $13 = 1
 $14 = void
 Continuing.
-Breakpoint 2, main (argc=1, argv=0x........) at t.c:117
-117	  breakme(__LINE__); //break2
-breakme (line=117) at t.c:100
-100	   if (line > 1000)
-Run till exit from #0  breakme (line=117) at t.c:100
-main (argc=1, argv=0x........) at t.c:119
-119	  if (argc > 1)
+Breakpoint 2, main (argc=1, argv=0x........) at t.c:118
+118	  breakme(__LINE__); //break2
+breakme (line=118) at t.c:101
+101	   if (line > 1000)
+Run till exit from #0  breakme (line=118) at t.c:101
+main (argc=1, argv=0x........) at t.c:120
+120	  if (argc > 1)
 Delete all breakpoints? (y or n) [answered Y; input not from terminal]
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
-0x........ in make_error (s=0x........ "called from level") at t.c:40
-40	  if (int_und == 0)
-43	     printf ("%s int_und is not zero\n", s);
+0x........ in make_error (s=0x........ "called from level") at t.c:41
+41	  if (int_und == 0)
+44	     printf ("%s int_und is not zero\n", s);
 old_pc has changed after step
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
-0x........ in make_error (s=0x........ "called from main") at t.c:40
-40	  if (int_und == 0)
+0x........ in make_error (s=0x........ "called from main") at t.c:41
+41	  if (int_und == 0)
diff --git a/gdbserver_tests/mcinfcallRU.vgtest b/gdbserver_tests/mcinfcallRU.vgtest
index a193acf..0c7b079 100644
--- a/gdbserver_tests/mcinfcallRU.vgtest
+++ b/gdbserver_tests/mcinfcallRU.vgtest
@@ -7,7 +7,7 @@
 # filter_gdb to replace pid and Thread numbers in the output of the program:
 stderr_filter: filter_gdb
 # Disable on Darwin: inferior call rejected as it cannot find malloc.
-prereq: test -e gdb && ../tests/os_test linux
+prereq: test -e gdb && ! ../tests/os_test darwin
 progB: gdb
 argsB:  --quiet -l 60 --nx ./sleepers
 stdinB: mcinfcallRU.stdinB.gdb
diff --git a/gdbserver_tests/mcinfcallWSRU.stderrB.exp b/gdbserver_tests/mcinfcallWSRU.stderrB.exp
index bc88ef7..7789123 100644
--- a/gdbserver_tests/mcinfcallWSRU.stderrB.exp
+++ b/gdbserver_tests/mcinfcallWSRU.stderrB.exp
@@ -1,25 +1,25 @@
 relaying data between gdb and process ....
 vgdb-error value changed from 0 to 999999
-Breakpoint 1 at 0x........: file sleepers.c, line 72.
+Breakpoint 1 at 0x........: file sleepers.c, line 74.
 Continuing.
-Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
-72	   int i = 0;
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:74
+74	   int i = 0;
 Continuing.
-Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
-72	   int i = 0;
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:74
+74	   int i = 0;
 Continuing.
-Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
-72	   int i = 0;
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:74
+74	   int i = 0;
 Continuing.
-Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:72
-72	   int i = 0;
+Breakpoint 1, sleeper_or_burner (v=0x........) at sleepers.c:74
+74	   int i = 0;
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
-0x........ in do_burn () at sleepers.c:39
-39	   for (i = 0; i < burn; i++) loopnr++;
+0x........ in do_burn () at sleepers.c:41
+41	   for (i = 0; i < burn; i++) loopnr++;
 [Switching to thread 1 (Thread ....)]
 #0  0x........ in do_burn ()
-39	   for (i = 0; i < burn; i++) loopnr++;
+41	   for (i = 0; i < burn; i++) loopnr++;
 $1 = void
 [Switching to thread 2 (Thread ....)]
 #0  0x........ in syscall ...
diff --git a/gdbserver_tests/mcinfcallWSRU.vgtest b/gdbserver_tests/mcinfcallWSRU.vgtest
index f9c1983..fd3922f 100644
--- a/gdbserver_tests/mcinfcallWSRU.vgtest
+++ b/gdbserver_tests/mcinfcallWSRU.vgtest
@@ -7,7 +7,7 @@
 vgopts: --tool=memcheck --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-mcinfcallWSRU
 # We need a non buggy gdb.step on arm thumb.
 # Disable on Darwin: inferior call rejected as it cannot find malloc.
-prereq: test -e gdb -a -f gdb.step && ../tests/os_test linux
+prereq: test -e gdb -a -f gdb.step && ! ../tests/os_test darwin
 # filter_gdb to replace pid and Thread numbers in the output of the program:
 stderr_filter: filter_gdb
 progB: gdb
diff --git a/gdbserver_tests/mcmain_pic.stderr.exp-solaris b/gdbserver_tests/mcmain_pic.stderr.exp-solaris
new file mode 100644
index 0000000..cd16393
--- /dev/null
+++ b/gdbserver_tests/mcmain_pic.stderr.exp-solaris
@@ -0,0 +1,7 @@
+(action at startup) vgdb me ... 
+HEAP SUMMARY:
+    in use at exit: 131,080 bytes in 1 blocks
+  total heap usage: 1 allocs, 0 frees, 131,080 bytes allocated
+For a detailed leak analysis, rerun with: --leak-check=full
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/gdbserver_tests/mcmain_pic.stdinB.gdb b/gdbserver_tests/mcmain_pic.stdinB.gdb
index 46e19f9..8ec0a6f 100644
--- a/gdbserver_tests/mcmain_pic.stdinB.gdb
+++ b/gdbserver_tests/mcmain_pic.stdinB.gdb
@@ -4,7 +4,7 @@
 monitor v.set vgdb-error 999999
 #
 # break
-break main_pic.c:11
+break main_pic.c:12
 #
 continue
 # first break encountered.
diff --git a/gdbserver_tests/mcmain_pic.stdoutB.exp b/gdbserver_tests/mcmain_pic.stdoutB.exp
index ffac737..e0a46c5 100644
--- a/gdbserver_tests/mcmain_pic.stdoutB.exp
+++ b/gdbserver_tests/mcmain_pic.stdoutB.exp
@@ -1,7 +1,7 @@
-Breakpoint 1 at 0x........: file main_pic.c, line 11.
+Breakpoint 1 at 0x........: file main_pic.c, line 12.
 Continuing.
-Breakpoint 1, main (argc=1, argv=0x........) at main_pic.c:11
-11	   printf("address of another_func %p\n", &another_func);
+Breakpoint 1, main (argc=1, argv=0x........) at main_pic.c:12
+12	   printf("address of another_func %#" PRIxPTR "\n", (uintptr_t) another_func);
 $1 = void
 $2 = (int (*)(int, char **)) 0x........ <main>
 $3 = (void (*)(char *)) 0x........ <another_func>
diff --git a/gdbserver_tests/mcsignopass.stderr.exp b/gdbserver_tests/mcsignopass.stderr.exp
index 3708ffb..7b0a80e 100644
--- a/gdbserver_tests/mcsignopass.stderr.exp
+++ b/gdbserver_tests/mcsignopass.stderr.exp
@@ -1,7 +1,7 @@
 (action at startup) vgdb me ... 
 Test 1: Invalid write of size 4
-   at 0x........: test1 (faultstatus.c:105)
-   by 0x........: main (faultstatus.c:168)
+   at 0x........: test1 (faultstatus.c:116)
+   by 0x........: main (faultstatus.c:179)
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
   PASS
 Test 2:   PASS
diff --git a/gdbserver_tests/mcsignopass.stdoutB.exp b/gdbserver_tests/mcsignopass.stdoutB.exp
index e349941..d77f983 100644
--- a/gdbserver_tests/mcsignopass.stdoutB.exp
+++ b/gdbserver_tests/mcsignopass.stdoutB.exp
@@ -6,54 +6,54 @@
 SIGFPE        Yes	Yes	Yes		Arithmetic exception
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Signal        Stop	Print	Pass to program	Description
 SIGSEGV       No	Yes	Yes		Segmentation fault
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
 Program received signal SIGBUS, Bus error.
-0x........ in test3 () at faultstatus.c:115
-115		mapping[FILESIZE+10];
+0x........ in test3 () at faultstatus.c:126
+126		mapping[FILESIZE+10];
 Continuing.
 Program received signal SIGFPE, Arithmetic exception.
diff --git a/gdbserver_tests/mcsigpass.stderr.exp b/gdbserver_tests/mcsigpass.stderr.exp
index 80659b8..bd67a7e 100644
--- a/gdbserver_tests/mcsigpass.stderr.exp
+++ b/gdbserver_tests/mcsigpass.stderr.exp
@@ -1,7 +1,7 @@
 (action at startup) vgdb me ... 
 Test 1: Invalid write of size 4
-   at 0x........: test1 (faultstatus.c:105)
-   by 0x........: main (faultstatus.c:168)
+   at 0x........: test1 (faultstatus.c:116)
+   by 0x........: main (faultstatus.c:179)
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
   PASS
 Test 2:   PASS
diff --git a/gdbserver_tests/mcsigpass.stdoutB.exp b/gdbserver_tests/mcsigpass.stdoutB.exp
index 4c2d799..de6c263 100644
--- a/gdbserver_tests/mcsigpass.stdoutB.exp
+++ b/gdbserver_tests/mcsigpass.stdoutB.exp
@@ -1,14 +1,14 @@
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test1 () at faultstatus.c:105
-105		*BADADDR = 'x';
+0x........ in test1 () at faultstatus.c:116
+116		*BADADDR = 'x';
 Continuing.
 Program received signal SIGSEGV, Segmentation fault.
-0x........ in test2 () at faultstatus.c:110
-110		mapping[0] = 'x';
+0x........ in test2 () at faultstatus.c:121
+121		mapping[0] = 'x';
 Continuing.
 Program received signal SIGBUS, Bus error.
-0x........ in test3 () at faultstatus.c:115
-115		mapping[FILESIZE+10];
+0x........ in test3 () at faultstatus.c:126
+126		mapping[FILESIZE+10];
 Continuing.
 Program received signal SIGFPE, Arithmetic exception.
diff --git a/gdbserver_tests/mcvabits.stdoutB.exp b/gdbserver_tests/mcvabits.stdoutB.exp
index e8d3661..c0aadc8 100644
--- a/gdbserver_tests/mcvabits.stdoutB.exp
+++ b/gdbserver_tests/mcvabits.stdoutB.exp
@@ -1,11 +1,11 @@
-Breakpoint 1 at 0x........: file t.c, line 100.
+Breakpoint 1 at 0x........: file t.c, line 101.
 Continuing.
-Breakpoint 1, breakme (line=112) at t.c:100
-100	   if (line > 1000)
-#1  0x........ in main (argc=1, argv=0x........) at t.c:112
-112	  breakme(__LINE__); //break1
+Breakpoint 1, breakme (line=113) at t.c:101
+101	   if (line > 1000)
+#1  0x........ in main (argc=1, argv=0x........) at t.c:113
+113	  breakme(__LINE__); //break1
 $1 = 0x........ "main name"
 $2 = "undefined"
 Continuing.
-Breakpoint 1, breakme (line=117) at t.c:100
-100	   if (line > 1000)
+Breakpoint 1, breakme (line=118) at t.c:101
+101	   if (line > 1000)
diff --git a/gdbserver_tests/mssnapshot.stdoutB.exp b/gdbserver_tests/mssnapshot.stdoutB.exp
index a2a7c55..ba43997 100644
--- a/gdbserver_tests/mssnapshot.stdoutB.exp
+++ b/gdbserver_tests/mssnapshot.stdoutB.exp
@@ -1,4 +1,4 @@
-Breakpoint 1 at 0x........: file t.c, line 105.
+Breakpoint 1 at 0x........: file t.c, line 106.
 Continuing.
-Breakpoint 1, main (argc=1, argv=0x........) at t.c:105
-105	  char *main_name __attribute__((unused)) = "main name";
+Breakpoint 1, main (argc=1, argv=0x........) at t.c:106
+106	  char *main_name __attribute__((unused)) = "main name";
diff --git a/gdbserver_tests/nlcontrolc.stdoutB.exp b/gdbserver_tests/nlcontrolc.stdoutB.exp
index 7336633..a1013ce 100644
--- a/gdbserver_tests/nlcontrolc.stdoutB.exp
+++ b/gdbserver_tests/nlcontrolc.stdoutB.exp
@@ -12,8 +12,8 @@
 changed burning parameters
 Continuing.
 Program received signal SIGTRAP, Trace/breakpoint trap.
-0x........ in do_burn () at sleepers.c:39
-39	   for (i = 0; i < burn; i++) loopnr++;
+0x........ in do_burn () at sleepers.c:41
+41	   for (i = 0; i < burn; i++) loopnr++;
 $5 = 0
 $6 = 0
 $7 = 0
diff --git a/gdbserver_tests/nlcontrolc.vgtest b/gdbserver_tests/nlcontrolc.vgtest
index e18c468..077b2bb 100644
--- a/gdbserver_tests/nlcontrolc.vgtest
+++ b/gdbserver_tests/nlcontrolc.vgtest
@@ -6,12 +6,14 @@
 #          and modify some variables
 # sleepers is started with argument so that it will compute during ages.
 # The variable modifications means it will exit in a reasonable time.
+# This test is disabled on Solaris because modifying select/poll/ppoll timeout
+# has no effect if a thread is already blocked in that syscall.
 prog: sleepers
 args: 1000000000 1000000000 1000000000 BSBSBSBS
 vgopts: --tool=none --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-nlcontrolc
 stderr_filter: filter_stderr
 # Bug 338633 nlcontrol hangs on arm64 currently.
-prereq: test -e gdb -a -f vgdb.invoker && ! ../tests/arch_test arm64 && ! ../tests/arch_test tilegx
+prereq: test -e gdb -a -f vgdb.invoker && ! ../tests/arch_test arm64 && ! ../tests/arch_test tilegx && ! ../tests/os_test solaris
 progB: gdb
 argsB: --quiet -l 60 --nx ./sleepers
 stdinB: nlcontrolc.stdinB.gdb
diff --git a/gdbserver_tests/nlpasssigalrm.stdoutB.exp b/gdbserver_tests/nlpasssigalrm.stdoutB.exp
index 708a3a3..625883e 100644
--- a/gdbserver_tests/nlpasssigalrm.stdoutB.exp
+++ b/gdbserver_tests/nlpasssigalrm.stdoutB.exp
@@ -16,7 +16,7 @@
 55	   sa.sa_handler = sigrtmin_handler;
 $2 = 1
 Continuing.
-Program received signal SIG34, Real-time event 34.
+Program received signal SIGxx, Real-time event xx.
 0x........ in syscall ...
 Continuing.
 Program exited normally.
diff --git a/gdbserver_tests/nlpasssigalrm.vgtest b/gdbserver_tests/nlpasssigalrm.vgtest
index 5c4e395..0450207 100644
--- a/gdbserver_tests/nlpasssigalrm.vgtest
+++ b/gdbserver_tests/nlpasssigalrm.vgtest
@@ -11,5 +11,5 @@
 progB: gdb
 argsB: --quiet -l 60 --nx ./passsigalrm
 stdinB: nlpasssigalrm.stdinB.gdb
-stdoutB_filter: filter_gdb
+stdoutB_filter: filter_passsigalrm
 stderrB_filter: filter_gdb
diff --git a/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris1 b/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris1
new file mode 100644
index 0000000..5cd0e75
--- /dev/null
+++ b/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris1
@@ -0,0 +1,16 @@
+continuing to have vgdb interrupted by simulate_control_c
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+attachedwaitingforsigusr1
+sending signal
+sending signal
+continuing to receive first SIGUSR1
+Continuing.
+Program received signal SIGUSR1, User defined signal 1.
+0x........ in syscall ...
+continuing to receive second SIGUSR1
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+Kill the program being debugged? (y or n) [answered Y; input not from terminal]
diff --git a/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris2 b/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris2
new file mode 100644
index 0000000..2eca10b
--- /dev/null
+++ b/gdbserver_tests/nlvgdbsigqueue.stdoutB.exp-solaris2
@@ -0,0 +1,17 @@
+continuing to have vgdb interrupted by simulate_control_c
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+attachedwaitingforsigusr1
+sending signal
+sending signal
+continuing to receive first SIGUSR1
+Continuing.
+[New Thread ....]
+Program received signal SIGUSR1, User defined signal 1.
+0x........ in syscall ...
+continuing to receive second SIGUSR1
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+Kill the program being debugged? (y or n) [answered Y; input not from terminal]
diff --git a/gdbserver_tests/sleepers.c b/gdbserver_tests/sleepers.c
index e06e0cd..64ab0ea 100644
--- a/gdbserver_tests/sleepers.c
+++ b/gdbserver_tests/sleepers.c
@@ -1,4 +1,5 @@
 #define _GNU_SOURCE
+#include <errno.h>
 #include <string.h>
 #include <pthread.h>
 #include <stdlib.h>
@@ -26,7 +27,8 @@
 static void whoami(char *msg) __attribute__((unused));
 static void whoami(char *msg)
 {
-   fprintf(stderr, "pid %d Thread %d %s\n", getpid(), gettid(), msg);
+   fprintf(stderr, "pid %ld Thread %ld %s\n", (long) getpid(), (long) gettid(),
+           msg);
    fflush(stderr);
 }
 
@@ -82,8 +84,8 @@
          t[s->t].tv_sec = sleepms / 1000;
          t[s->t].tv_usec = (sleepms % 1000) * 1000;
          ret = select (0, NULL, NULL, NULL, &t[s->t]);
-         /* We only expect a timeout result from the above. */
-         if (ret != 0)
+         /* We only expect a timeout result or EINTR from the above. */
+         if (ret != 0 && errno != EINTR)
             perror("unexpected result from select");
       }
       if (burn > 0 && s->burn)
diff --git a/gdbserver_tests/solaris/Makefile.am b/gdbserver_tests/solaris/Makefile.am
new file mode 100644
index 0000000..e9ebcc8
--- /dev/null
+++ b/gdbserver_tests/solaris/Makefile.am
@@ -0,0 +1,12 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+	filter_stderr
+
+EXTRA_DIST = \
+	nlcontrolc.stderrB.exp \
+	nlcontrolc.stderr.exp \
+	nlcontrolc.stdinB.gdb \
+	nlcontrolc.stdoutB.exp \
+	nlcontrolc.vgtest
diff --git a/gdbserver_tests/solaris/filter_stderr b/gdbserver_tests/solaris/filter_stderr
new file mode 100755
index 0000000..0ae9313
--- /dev/null
+++ b/gdbserver_tests/solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/gdbserver_tests/solaris/nlcontrolc.stderr.exp b/gdbserver_tests/solaris/nlcontrolc.stderr.exp
new file mode 100644
index 0000000..3f06448
--- /dev/null
+++ b/gdbserver_tests/solaris/nlcontrolc.stderr.exp
@@ -0,0 +1,11 @@
+Nulgrind, the minimal Valgrind tool
+
+(action at startup) vgdb me ... 
+
+
+loops/sleep_ms/burn/threads_spec:  1000000000 5000 1000000000 BSBSBSBS
+Brussels ready to sleep and/or burn
+London ready to sleep and/or burn
+Petaouchnok ready to sleep and/or burn
+main ready to sleep and/or burn
+
diff --git a/gdbserver_tests/solaris/nlcontrolc.stderrB.exp b/gdbserver_tests/solaris/nlcontrolc.stderrB.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gdbserver_tests/solaris/nlcontrolc.stderrB.exp
diff --git a/gdbserver_tests/solaris/nlcontrolc.stdinB.gdb b/gdbserver_tests/solaris/nlcontrolc.stdinB.gdb
new file mode 100644
index 0000000..182834f
--- /dev/null
+++ b/gdbserver_tests/solaris/nlcontrolc.stdinB.gdb
@@ -0,0 +1,31 @@
+# connect gdb to Valgrind gdbserver:
+target remote | ../vgdb --wait=60 --vgdb-prefix=./vgdb-prefix-solaris-nlcontrolc
+echo vgdb launched process attached\n
+monitor v.set vgdb-error 999999
+#
+#
+# simulate control-c in a few seconds
+shell ../simulate_control_c --vgdb-prefix=./vgdb-prefix-solaris-nlcontrolc 1 grep main nlcontrolc.stderr.out
+#
+continue
+#
+# Here, all tasks should be blocked in a loooonnnng select, all in WaitSys
+info threads
+# After the timeout expires, threads will unblock.
+#
+# We will change the burning parameters in a few seconds
+shell ../simulate_control_c --vgdb-prefix=./vgdb-prefix-solaris-nlcontrolc 6 grep CPU nlcontrolc.stdoutB.out
+#
+echo Now threads are burning CPU\n
+continue
+#
+# Threads are burning cpu now
+# We would like to test info threads here, but which thread are Runnable or Yielding
+# is unpredictable.
+# info threads
+p burn = 0
+p loops = 0
+p report_finished = 0
+continue
+# and the process should stop very quickly now
+quit
diff --git a/gdbserver_tests/solaris/nlcontrolc.stdoutB.exp b/gdbserver_tests/solaris/nlcontrolc.stdoutB.exp
new file mode 100644
index 0000000..e952c50
--- /dev/null
+++ b/gdbserver_tests/solaris/nlcontrolc.stdoutB.exp
@@ -0,0 +1,17 @@
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in syscall ...
+  4 Thread .... (tid 4 VgTs_WaitSys)  0x........ in __pollsys ()
+  3 Thread .... (tid 3 VgTs_WaitSys)  0x........ in __pollsys ()
+  2 Thread .... (tid 2 VgTs_WaitSys)  0x........ in __pollsys ()
+* 1 Thread .... (tid 1 VgTs_WaitSys)  0x........ in __pollsys ()
+Now threads are burning CPU
+Continuing.
+Program received signal SIGTRAP, Trace/breakpoint trap.
+0x........ in do_burn () at sleepers.c:41
+41	   for (i = 0; i < burn; i++) loopnr++;
+$1 = 0
+$2 = 0
+$3 = 0
+Continuing.
+Program exited normally.
diff --git a/gdbserver_tests/solaris/nlcontrolc.vgtest b/gdbserver_tests/solaris/nlcontrolc.vgtest
new file mode 100644
index 0000000..2723570
--- /dev/null
+++ b/gdbserver_tests/solaris/nlcontrolc.vgtest
@@ -0,0 +1,17 @@
+# test :
+#   info threads valgrind specific output
+#   the user can control-c a process with all threads in WaitSys
+#   the user can control-c a process with all threads in Running/Yielding
+#          and modify some variables
+# sleepers is started with argument so that it will compute during ages.
+# The variable modifications means it will exit in a reasonable time.
+prog: ../sleepers
+args: 1000000000 5000 1000000000 BSBSBSBS
+vgopts: --tool=none --vgdb=yes --vgdb-error=0 --vgdb-prefix=./vgdb-prefix-solaris-nlcontrolc
+stderr_filter: filter_stderr
+prereq: test -e ../gdb -a -f ../vgdb.invoker
+progB: ../gdb
+argsB: --quiet -l 60 --nx ../sleepers
+stdinB: nlcontrolc.stdinB.gdb
+stdoutB_filter: ../filter_gdb
+stderrB_filter: ../filter_make_empty
diff --git a/gdbserver_tests/t.c b/gdbserver_tests/t.c
index 89ce57d..228d4a4 100644
--- a/gdbserver_tests/t.c
+++ b/gdbserver_tests/t.c
@@ -26,7 +26,8 @@
 }
 static void whoami(char *msg)
 {
-   printf("pid %d Thread %d %s\n", getpid(), gettid(), msg); fflush(stdout);
+   printf("pid %ld Thread %ld %s\n", (long) getpid(), (long) gettid(), msg);
+   fflush(stdout);
 }
 
 static int int_und;
diff --git a/helgrind/docs/hg-manual.xml b/helgrind/docs/hg-manual.xml
index c6839fd..28d4d9b 100644
--- a/helgrind/docs/hg-manual.xml
+++ b/helgrind/docs/hg-manual.xml
@@ -1190,6 +1190,51 @@
     </listitem>
   </varlistentry>
 
+  <varlistentry id="opt.ignore-thread-creation"
+                xreflabel="--ignore-thread-creation">
+    <term>
+      <option><![CDATA[--ignore-thread-creation=<yes|no>
+      [default: no]]]></option>
+    </term>
+    <listitem>
+      <para>
+        Controls whether all activities during thread creation should be
+        ignored. By default enabled only on Solaris.
+        Solaris provides higher throughput, parallelism and scalability than
+        other operating systems, at the cost of more fine-grained locking
+        activity. This means for example that when a thread is created under
+        glibc, just one big lock is used for all thread setup. Solaris libc
+        uses several fine-grained locks and the creator thread resumes its
+        activities as soon as possible, leaving for example stack and TLS setup
+        sequence to the created thread.
+        This situation confuses Helgrind as it assumes there is some false
+        ordering in place between creator and created thread; and therefore many
+        types of race conditions in the application would not be reported.
+        To prevent such false ordering, this command line option is set to
+        <computeroutput>yes</computeroutput> by default on Solaris.
+        All activity (loads, stores, client requests) is therefore ignored
+        during:</para>
+      <itemizedlist>
+        <listitem>
+          <para>
+            pthread_create() call in the creator thread
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            thread creation phase (stack and TLS setup) in the created thread
+          </para>
+        </listitem>
+      </itemizedlist>
+      <para>
+         Also new memory allocated during thread creation is untracked,
+         that is race reporting is suppressed there. DRD does the same thing
+         implicitly. This is necessary because Solaris libc caches many objects
+         and reuses them for different threads and that confuses
+         Helgrind.</para>
+    </listitem>
+  </varlistentry>
+
 
 </variablelist>
 <!-- end of xi:include in the manpage -->
diff --git a/helgrind/helgrind.h b/helgrind/helgrind.h
index 7e27f5c..fc156f4 100644
--- a/helgrind/helgrind.h
+++ b/helgrind/helgrind.h
@@ -80,8 +80,8 @@
       _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE,  /* pth_mx_t*, long isInit */
       _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,   /* pth_mx_t* */
       _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,  /* pth_mx_t* */
-      _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE, /* pth_mx_t*, long isTryLock */
-      _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,    /* pth_mx_t* */
+      _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE,  /* void*, long isTryLock */
+      _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST, /* void* */
       _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE,    /* pth_cond_t* */
       _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE, /* pth_cond_t* */
       _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,     /* pth_cond_t*, pth_mx_t* */
@@ -90,13 +90,13 @@
       _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,   /* pth_rwlk_t* */
       _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE, /* pth_rwlk_t* */
       _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,    /* pth_rwlk_t*, long isW */
-      _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,   /* pth_rwlk_t*, long isW */
-      _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,  /* pth_rwlk_t* */
+      _VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED,    /* void*, long isW */
+      _VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED,    /* void* */
       _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST, /* pth_rwlk_t* */
       _VG_USERREQ__HG_POSIX_SEM_INIT_POST,        /* sem_t*, ulong value */
       _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE,      /* sem_t* */
-      _VG_USERREQ__HG_POSIX_SEM_POST_PRE,         /* sem_t* */
-      _VG_USERREQ__HG_POSIX_SEM_WAIT_POST,        /* sem_t* */
+      _VG_USERREQ__HG_POSIX_SEM_RELEASED,         /* void* */
+      _VG_USERREQ__HG_POSIX_SEM_ACQUIRED,         /* void* */
       _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE,   /* pth_bar_t*, ulong, ulong */
       _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE,   /* pth_bar_t* */
       _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE, /* pth_bar_t* */
@@ -118,8 +118,22 @@
       _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK, /* Addr start_of_block */
       _VG_USERREQ__HG_PTHREAD_COND_INIT_POST,  /* pth_cond_t*, pth_cond_attr_t*/
       _VG_USERREQ__HG_GNAT_MASTER_HOOK,       /* void*d,void*m,Word ml */
-      _VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK,/* void*s,Word ml */
-      _VG_USERREQ__HG_GET_ABITS               /* Addr a,Addr abits, ulong len */
+      _VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK, /* void*s,Word ml */
+      _VG_USERREQ__HG_GET_ABITS,              /* Addr a,Addr abits, ulong len */
+      _VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
+      _VG_USERREQ__HG_PTHREAD_CREATE_END,
+      _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,     /* pth_mx_t*,long isTryLock */
+      _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,    /* pth_mx_t *,long tookLock */
+      _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,  /* pth_rwlk_t*,long isW,long */
+      _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,  /* pth_rwlk_t* */
+      _VG_USERREQ__HG_POSIX_SEM_POST_PRE,         /* sem_t* */
+      _VG_USERREQ__HG_POSIX_SEM_POST_POST,        /* sem_t* */
+      _VG_USERREQ__HG_POSIX_SEM_WAIT_PRE,         /* sem_t* */
+      _VG_USERREQ__HG_POSIX_SEM_WAIT_POST,        /* sem_t*, long tookLock */
+      _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,   /* pth_cond_t* */
+      _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,/* pth_cond_t* */
+      _VG_USERREQ__HG_RTLD_BIND_GUARD,            /* int flags */
+      _VG_USERREQ__HG_RTLD_BIND_CLEAR             /* int flags */
    } Vg_TCheckClientRequest;
 
 
@@ -239,12 +253,12 @@
 /* Notify here immediately before mutex acquisition.  _isTryLock == 0
    for a normal acquisition, 1 for a "try" style acquisition. */
 #define VALGRIND_HG_MUTEX_LOCK_PRE(_mutex, _isTryLock)       \
-   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,      \
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE,   \
                 void*,(_mutex), long,(_isTryLock))
 
 /* Notify here immediately after a successful mutex acquisition. */
 #define VALGRIND_HG_MUTEX_LOCK_POST(_mutex)                  \
-   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,      \
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST,   \
                void*,(_mutex))
 
 /* Notify here immediately before a mutex release. */
@@ -274,13 +288,13 @@
 /* Notify here immediately after a semaphore wait (an acquire-style
    operation) */
 #define VALGRIND_HG_SEM_WAIT_POST(_sem)                      \
-   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST,          \
+   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_ACQUIRED,           \
                void*,(_sem))
 
 /* Notify here immediately before semaphore post (a release-style
    operation) */
 #define VALGRIND_HG_SEM_POST_PRE(_sem)                       \
-   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_PRE,           \
+   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_RELEASED,           \
                void*,(_sem))
 
 /* Notify here immediately before semaphore destruction. */
@@ -733,12 +747,12 @@
 /* Report that the lock at address LOCK has just been acquired.
    is_w=1 for writer lock, is_w=0 for reader lock. */
 #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w)                 \
-  DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,     \
+  DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED,      \
                void*,(lock), unsigned long,(is_w))
 
 /* Report that the lock at address LOCK is about to be released. */
 #define ANNOTATE_RWLOCK_RELEASED(lock, is_w)                 \
-  DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE,     \
+  DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED,       \
               void*,(lock)) /* is_w is ignored */
 
 
diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c
index f109bf3..9bd840f 100644
--- a/helgrind/hg_intercepts.c
+++ b/helgrind/hg_intercepts.c
@@ -58,6 +58,18 @@
 #include "helgrind.h"
 #include "config.h"
 
+
+#if defined(VGO_solaris)
+/* See porting comments in drd/drd_pthread_intercepts.c
+   However when a POSIX threads API function (for example pthread_cond_init)
+   is built upon the Solaris one (cond_init), intercept only the bottom one.
+   Helgrind does not contain generic synchronization nesting like DRD
+   and double intercept confuses it. */
+#include <synch.h>
+#include <thread.h>
+#endif /* VGO_solaris */
+
+
 #define TRACE_PTH_FNS 0
 #define TRACE_QT4_FNS 0
 #define TRACE_GNAT_FNS 0
@@ -67,9 +79,26 @@
 /*---                                                          ---*/
 /*----------------------------------------------------------------*/
 
+#if defined(VGO_solaris)
+/* On Solaris, libpthread is just a filter library on top of libc.
+ * Threading and synchronization functions in runtime linker are not
+ * intercepted.
+ */
+#define PTH_FUNC(ret_ty, f, args...) \
+   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args); \
+   ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBC_SONAME,f)(args)
+
+/* pthread_t is typedef'd to 'unsigned int' but in DO_CREQ_* macros
+   sizeof(Word) is expected. */
+#define CREQ_PTHREAD_T Word
+#define SEM_ERROR ret
+#else
 #define PTH_FUNC(ret_ty, f, args...) \
    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args); \
    ret_ty I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LIBPTHREAD_SONAME,f)(args)
+#define CREQ_PTHREAD_T pthread_t
+#define SEM_ERROR errno
+#endif /* VGO_solaris */
 
 // Do a client request.  These are macros rather than a functions so
 // as to avoid having an extra frame in stack traces.
@@ -133,6 +162,22 @@
                                  _arg1,_arg2,_arg3,0,0); \
    } while (0)
 
+#define DO_CREQ_v_WWWW(_creqF, _ty1F,_arg1F,             \
+                       _ty2F, _arg2F, _ty3F, _arg3F,     \
+                       _ty4F, _arg4F)                    \
+   do {                                                  \
+      Word _arg1, _arg2, _arg3, _arg4;                   \
+      assert(sizeof(_ty1F) == sizeof(Word));             \
+      assert(sizeof(_ty2F) == sizeof(Word));             \
+      assert(sizeof(_ty3F) == sizeof(Word));             \
+      assert(sizeof(_ty4F) == sizeof(Word));             \
+      _arg1 = (Word)(_arg1F);                            \
+      _arg2 = (Word)(_arg2F);                            \
+      _arg3 = (Word)(_arg3F);                            \
+      _arg4 = (Word)(_arg4F);                            \
+      VALGRIND_DO_CLIENT_REQUEST_STMT((_creqF),          \
+                             _arg1,_arg2,_arg3,_arg4,0); \
+   } while (0)
 
 #define DO_PthAPIerror(_fnnameF, _errF)                  \
    do {                                                  \
@@ -196,11 +241,121 @@
       case EDEADLK:     return "EDEADLK: Resource deadlock would occur";
       case EOPNOTSUPP:  return "EOPNOTSUPP: Operation not supported on "
                                "transport endpoint"; /* honest, guv */
-      default:          return "tc_intercepts.c: lame_strerror(): "
+      case ETIME:       return "ETIME: Timer expired";
+      default:          return "hg_intercepts.c: lame_strerror(): "
                                "unhandled case -- please fix me!";
    }
 }
 
+#if defined(VGO_solaris)
+/*
+ * Solaris provides higher throughput, parallelism and scalability than other
+ * operating systems, at the cost of more fine-grained locking activity.
+ * This means for example that when a thread is created under Linux, just one
+ * big lock in glibc is used for all thread setup. Solaris libc uses several
+ * fine-grained locks and the creator thread resumes its activities as soon
+ * as possible, leaving for example stack and TLS setup activities to the
+ * created thread.
+ *
+ * This situation confuses Helgrind as it assumes there is some false ordering
+ * in place between creator and created thread; and therefore many types of
+ * race conditions in the application would not be reported. To prevent such
+ * false ordering, command line option --ignore-thread-creation is set to
+ * 'yes' by default on Solaris. All activity (loads, stores, client requests)
+ * is therefore ignored during:
+ * - pthread_create() call in the creator thread [libc.so]
+ * - thread creation phase (stack and TLS setup) in the created thread [libc.so]
+ *
+ * As explained in the comments for _ti_bind_guard(), whenever the runtime
+ * linker has to perform any activity (such as resolving a symbol), it protects
+ * its data structures by calling into rt_bind_guard() which in turn invokes
+ * _ti_bind_guard() in libc. Pointers to _ti_bind_guard() and _ti_bind_clear()
+ * are passed from libc to runtime linker in _ld_libc() call during libc_init().
+ * All activity is also ignored during:
+ * - runtime dynamic linker work between rt_bind_guard() and rt_bind_clear()
+ *   calls [ld.so]
+ *
+ * This also means that Helgrind does not report race conditions in libc (when
+ * --ignore-thread-creation=yes) and runtime linker itself (unconditionally)
+ * during these ignored sequences.
+ */
+
+#include "pub_tool_libcassert.h"
+#include "pub_tool_vki.h"
+
+/*
+ * Original function pointers for _ti_bind_guard() and _ti_bind_clear()
+ * from libc. They are intercepted in function wrapper of _ld_libc().
+ */
+typedef int (*hg_rtld_guard_fn)(int flags);
+static hg_rtld_guard_fn hg_rtld_bind_guard = NULL;
+static hg_rtld_guard_fn hg_rtld_bind_clear = NULL;
+
+static void hg_init(void) __attribute__((constructor));
+static void hg_init(void)
+{
+   if ((hg_rtld_bind_guard == NULL) || (hg_rtld_bind_clear == NULL)) {
+      fprintf(stderr,
+"Bind guard functions for the runtime linker (ld.so.1) were not intercepted.\n"
+"This means the interface between libc and runtime linker changed\n"
+"and Helgrind needs to be ported properly. Giving up.\n");
+      tl_assert(0);
+   }
+}
+
+/*
+ * Intercepts for _ti_bind_guard() and _ti_bind_clear() functions from libc.
+ * These are intercepted during _ld_libc() call by identifying CI_BIND_GUARD
+ * and CI_BIND_CLEAR, to provide resilience against function renaming.
+ */
+static int _ti_bind_guard_intercept_WRK(int flags)
+{
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_GUARD,
+                                   flags, 0, 0, 0, 0);
+   return hg_rtld_bind_guard(flags);
+}
+
+static int _ti_bind_clear_intercept_WRK(int flags)
+{
+   int ret = hg_rtld_bind_clear(flags);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_RTLD_BIND_CLEAR,
+                                   flags, 0, 0, 0, 0);
+   return ret;
+}
+
+/*
+ * Wrapped _ld_libc() from the runtime linker ld.so.1.
+ */
+void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr);
+void I_WRAP_SONAME_FNNAME_ZZ(VG_Z_LD_SO_1, ZuldZulibc)(vki_Lc_interface *ptr)
+{
+   OrigFn fn;
+   int    tag;
+
+   VALGRIND_GET_ORIG_FN(fn);
+
+   vki_Lc_interface *funcs = ptr;
+   for (tag = funcs->ci_tag; tag != 0; tag = (++funcs)->ci_tag) {
+      switch (tag) {
+      case VKI_CI_BIND_GUARD:
+         if (funcs->vki_ci_un.ci_func != _ti_bind_guard_intercept_WRK) {
+            hg_rtld_bind_guard = funcs->vki_ci_un.ci_func;
+            funcs->vki_ci_un.ci_func = _ti_bind_guard_intercept_WRK;
+         }
+         break;
+      case VKI_CI_BIND_CLEAR:
+         if (funcs->vki_ci_un.ci_func != _ti_bind_clear_intercept_WRK) {
+            hg_rtld_bind_clear = funcs->vki_ci_un.ci_func;
+            funcs->vki_ci_un.ci_func = _ti_bind_clear_intercept_WRK;
+         }
+         break;
+      }
+   }
+
+   CALL_FN_v_W(fn, ptr);
+}
+#endif /* VGO_solaris */
+
 
 /*----------------------------------------------------------------*/
 /*--- pthread_create, pthread_join, pthread_exit               ---*/
@@ -213,7 +368,7 @@
    void* arg         = (void*)xargs[1];
    pthread_t me = pthread_self();
    /* Tell the tool what my pthread_t is. */
-   DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, pthread_t,me);
+   DO_CREQ_v_W(_VG_USERREQ__HG_SET_MY_PTHREAD_T, CREQ_PTHREAD_T, me);
    /* allow the parent to proceed.  We can't let it proceed until
       we're ready because (1) we need to make sure it doesn't exit and
       hence deallocate xargs[] while we still need it, and (2) we
@@ -267,7 +422,11 @@
       comes to re-use this piece of stack in some other frame. */
    VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
 
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
+                                   0, 0, 0, 0, 0);
    CALL_FN_W_WWWW(ret, fn, thread,attr,mythread_wrapper,&xargs[0]);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
+                                   0, 0, 0, 0, 0);
 
    if (ret == 0) {
       /* we have to wait for the child to notify the tool of its
@@ -312,10 +471,69 @@
       // trap anything else
       assert(0);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZucreate, // pthread_create
+                 pthread_t *thread, const pthread_attr_t *attr,
+                 void *(*start) (void *), void *arg) {
+      return pthread_create_WRK(thread, attr, start, arg);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
+#if defined(VGO_solaris)
+/* Solaris also provides thr_create() in addition to pthread_create().
+ * Both pthread_create(3C) and thr_create(3C) are based on private
+ * _thrp_create().
+ */
+__attribute__((noinline))
+static int thr_create_WRK(void *stk, size_t stksize, void *(*start)(void *),
+                          void *arg, long flags, thread_t *new_thread)
+{
+   int    ret;
+   OrigFn fn;
+   volatile Word xargs[3];
+
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< thr_create wrapper"); fflush(stderr);
+   }
+   xargs[0] = (Word)start;
+   xargs[1] = (Word)arg;
+   xargs[2] = 1; /* serves as a spinlock -- sigh */
+   /* See comments in pthread_create_WRK() */
+   VALGRIND_HG_DISABLE_CHECKING(&xargs, sizeof(xargs));
+
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_BEGIN,
+                                   0, 0, 0, 0, 0);
+   CALL_FN_W_6W(ret, fn, stk, stksize, mythread_wrapper, start, flags,
+                new_thread);
+   VALGRIND_DO_CLIENT_REQUEST_STMT(_VG_USERREQ__HG_PTHREAD_CREATE_END,
+                                   0, 0, 0, 0, 0);
+
+   if (ret == 0) {
+      while (xargs[2] != 0) {
+         /* See comments in pthread_create_WRK(). */
+         sched_yield();
+      }
+   } else {
+      DO_PthAPIerror("thr_create", ret);
+   }
+
+   VALGRIND_HG_ENABLE_CHECKING(&xargs, sizeof(xargs));
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: thr_create -> %d >>\n", ret);
+   }
+   return ret;
+}
+   PTH_FUNC(int, thrZucreate, // thr_create
+                 void *stk, size_t stksize, void *(*start)(void *),
+                 void *arg, long flags, thread_t *new_thread) {
+      return thr_create_WRK(stk, stksize, start, arg, flags, new_thread);
+   }
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
 // glibc:  pthread_join
@@ -338,7 +556,7 @@
       it is guaranteed (by NPTL) that the joiner will completely gone
       before pthread_join (the original) returns.  See email below.*/
    if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, pthread_t,thread);
+      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, thread);
    } else { 
       DO_PthAPIerror( "pthread_join", ret );
    }
@@ -358,6 +576,11 @@
             pthread_t thread, void** value_pointer) {
       return pthread_join_WRK(thread, value_pointer);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZujoin, // pthread_join
+            pthread_t thread, void** value_pointer) {
+      return pthread_join_WRK(thread, value_pointer);
+   }
 #else
 #  error "Unsupported OS"
 #endif
@@ -404,6 +627,43 @@
 done.  No way the joiner can return before the thread is gone.
 */
 
+#if defined(VGO_solaris)
+/* Solaris also provides thr_join() in addition to pthread_join().
+ * Both pthread_join(3C) and thr_join(3C) are based on private _thrp_join().
+ *
+ * :TODO: No functionality is currently provided for joinee == 0 and departed.
+ *        This would require another client request, of course.
+ */
+__attribute__((noinline))
+static int thr_join_WRK(thread_t joinee, thread_t *departed, void **thread_return)
+{
+   int ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< thr_join wrapper"); fflush(stderr);
+   }
+
+   CALL_FN_W_WWW(ret, fn, joinee, departed, thread_return);
+
+   if (ret == 0 /*success*/) {
+      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_JOIN_POST, CREQ_PTHREAD_T, joinee);
+   } else {
+      DO_PthAPIerror("thr_join", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: thr_join -> %d >>\n", ret);
+   }
+   return ret;
+}
+   PTH_FUNC(int, thrZujoin, // thr_join
+            thread_t joinee, thread_t *departed, void **thread_return) {
+      return thr_join_WRK(joinee, departed, thread_return);
+   }
+#endif /* VGO_solaris */
+
+
 //-----------------------------------------------------------
 // Ada gcc gnat runtime:
 // The gnat gcc Ada runtime does not use pthread_join. Instead, it uses
@@ -490,6 +750,7 @@
 */
 
 //-----------------------------------------------------------
+#if !defined(VGO_solaris)
 // glibc:  pthread_mutex_init
 // darwin: pthread_mutex_init
 PTH_FUNC(int, pthreadZumutexZuinit, // pthread_mutex_init
@@ -527,12 +788,45 @@
    return ret;
 }
 
+#else /* VGO_solaris */
+
+// Solaris: mutex_init (pthread_mutex_init calls here)
+PTH_FUNC(int, mutexZuinit, // mutex_init
+              mutex_t *mutex, int type, void *arg)
+{
+   int    ret;
+   long   mbRec;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< mxinit %p", mutex); fflush(stderr);
+   }
+
+   mbRec = ((type & LOCK_RECURSIVE) != 0) ? 1 : 0;
+
+   CALL_FN_W_WWW(ret, fn, mutex, type, arg);
+
+   if (ret == 0 /*success*/) {
+      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST,
+                   mutex_t *, mutex, long, mbRec);
+   } else {
+      DO_PthAPIerror("mutex_init", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: mxinit -> %d >>\n", ret);
+   }
+   return ret;
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_mutex_destroy
-// darwin: pthread_mutex_destroy
-PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
-              pthread_mutex_t *mutex)
+// glibc:   pthread_mutex_destroy
+// darwin:  pthread_mutex_destroy
+// Solaris: mutex_destroy (pthread_mutex_destroy is a weak alias)
+__attribute__((noinline))
+static int mutex_destroy_WRK(pthread_mutex_t *mutex)
 {
    int    ret;
    unsigned long mutex_is_init;
@@ -565,12 +859,27 @@
    return ret;
 }
 
+#if defined(VGO_linux) || defined(VGO_darwin)
+   PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy
+            pthread_mutex_t *mutex) {
+      return mutex_destroy_WRK(mutex);
+   }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, mutexZudestroy, // mutex_destroy
+            pthread_mutex_t *mutex) {
+      return mutex_destroy_WRK(mutex);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_mutex_lock
-// darwin: pthread_mutex_lock
-PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
-              pthread_mutex_t *mutex)
+// glibc:   pthread_mutex_lock
+// darwin:  pthread_mutex_lock
+// Solaris: mutex_lock (pthread_mutex_lock is a weak alias)
+__attribute__((noinline))
+static int mutex_lock_WRK(pthread_mutex_t *mutex)
 {
    int    ret;
    OrigFn fn;
@@ -589,10 +898,10 @@
       that the lock has been acquired by someone (this thread).  Does
       this matter?  Not sure, but I don't think so. */
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  pthread_mutex_t*,mutex);
-   } else { 
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
+
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_mutex_lock", ret );
    }
 
@@ -602,10 +911,51 @@
    return ret;
 }
 
+#if defined(VGO_linux) || defined(VGO_darwin)
+   PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
+            pthread_mutex_t *mutex) {
+      return mutex_lock_WRK(mutex);
+   }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, mutexZulock, // mutex_lock
+            pthread_mutex_t *mutex) {
+      return mutex_lock_WRK(mutex);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
+#if defined(VGO_solaris)
+/* Internal to libc. Mutex is usually initialized only implicitly,
+ * by zeroing mutex_t structure.
+ */
+__attribute__((noinline))
+PTH_FUNC(void, lmutexZulock, // lmutex_lock
+               mutex_t *mutex)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< lmxlock %p", mutex); fflush(stderr);
+   }
+
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE,
+                mutex_t *, mutex, long, 0 /*!isTryLock*/);
+   CALL_FN_v_W(fn, mutex);
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                mutex_t *, mutex, long, True);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: lmxlock >>\n");
+   }
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_mutex_trylock
-// darwin: pthread_mutex_trylock
+// glibc:   pthread_mutex_trylock
+// darwin:  pthread_mutex_trylock
+// Solaris: mutex_trylock (pthread_mutex_trylock is a weak alias)
 //
 // pthread_mutex_trylock.  The handling needed here is very similar
 // to that for pthread_mutex_lock, except that we need to tell
@@ -613,8 +963,8 @@
 // therefore not to complain if the lock is nonrecursive and 
 // already locked by this thread -- because then it'll just fail
 // immediately with EBUSY.
-PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
-              pthread_mutex_t *mutex)
+__attribute__((noinline))
+static int mutex_trylock_WRK(pthread_mutex_t *mutex)
 {
    int    ret;
    OrigFn fn;
@@ -633,10 +983,10 @@
       that the lock has been acquired by someone (this thread).  Does
       this matter?  Not sure, but I don't think so. */
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  pthread_mutex_t*,mutex);
-   } else { 
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+               pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
+
+   if (ret != 0) {
       if (ret != EBUSY)
          DO_PthAPIerror( "pthread_mutex_trylock", ret );
    }
@@ -647,15 +997,30 @@
    return ret;
 }
 
+#if defined(VGO_linux) || defined(VGO_darwin)
+   PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
+            pthread_mutex_t *mutex) {
+      return mutex_trylock_WRK(mutex);
+   }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, mutexZutrylock, // mutex_trylock
+            pthread_mutex_t *mutex) {
+      return mutex_trylock_WRK(mutex);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_mutex_timedlock
-// darwin: (doesn't appear to exist)
+// glibc:   pthread_mutex_timedlock
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_mutex_timedlock
 //
 // pthread_mutex_timedlock.  Identical logic to pthread_mutex_trylock.
-PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
-         pthread_mutex_t *mutex,
-         void* timeout)
+__attribute__((noinline))
+static int mutex_timedlock_WRK(pthread_mutex_t *mutex,
+                               void *timeout)
 {
    int    ret;
    OrigFn fn;
@@ -675,10 +1040,10 @@
       that the lock has been acquired by someone (this thread).  Does
       this matter?  Not sure, but I don't think so. */
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  pthread_mutex_t*,mutex);
-   } else { 
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
+
+   if (ret != 0) {
       if (ret != ETIMEDOUT)
          DO_PthAPIerror( "pthread_mutex_timedlock", ret );
    }
@@ -689,12 +1054,26 @@
    return ret;
 }
 
+PTH_FUNC(int, pthreadZumutexZutimedlock, // pthread_mutex_timedlock
+         pthread_mutex_t *mutex,
+         void *timeout) {
+   return mutex_timedlock_WRK(mutex, timeout);
+}
+#if defined(VGO_solaris)
+PTH_FUNC(int, pthreadZumutexZureltimedlock, // pthread_mutex_reltimedlock
+         pthread_mutex_t *mutex,
+         void *timeout) {
+   return mutex_timedlock_WRK(mutex, timeout);
+}
+#endif
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_mutex_unlock
-// darwin: pthread_mutex_unlock
-PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
-              pthread_mutex_t *mutex)
+// glibc:   pthread_mutex_unlock
+// darwin:  pthread_mutex_unlock
+// Solaris: mutex_unlock (pthread_mutex_unlock is a weak alias)
+__attribute__((noinline))
+static int mutex_unlock_WRK(pthread_mutex_t *mutex)
 {
    int    ret;
    OrigFn fn;
@@ -709,10 +1088,10 @@
 
    CALL_FN_W_W(ret, fn, mutex);
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
-                  pthread_mutex_t*,mutex);
-   } else { 
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
+               pthread_mutex_t*,mutex);
+
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_mutex_unlock", ret );
    }
 
@@ -722,6 +1101,46 @@
    return ret;
 }
 
+#if defined(VGO_linux) || defined(VGO_darwin)
+   PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
+            pthread_mutex_t *mutex) {
+      return mutex_unlock_WRK(mutex);
+   }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, mutexZuunlock, // mutex_unlock
+            pthread_mutex_t *mutex) {
+      return mutex_unlock_WRK(mutex);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
+
+#if defined(VGO_solaris)
+/* Internal to libc. */
+__attribute__((noinline))
+PTH_FUNC(void, lmutexZuunlock, // lmutex_unlock
+               mutex_t *mutex)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< lmxunlk %p", mutex); fflush(stderr);
+   }
+
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
+               mutex_t *, mutex);
+   CALL_FN_v_W(fn, mutex);
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST,
+               mutex_t*, mutex);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " lmxunlk >>\n");
+   }
+}
+#endif /* VGO_solaris */
+
 
 /*----------------------------------------------------------------*/
 /*--- pthread_cond_t functions                                 ---*/
@@ -734,11 +1153,12 @@
 */
 
 //-----------------------------------------------------------
-// glibc:  pthread_cond_wait@GLIBC_2.2.5
-// glibc:  pthread_cond_wait@@GLIBC_2.3.2
-// darwin: pthread_cond_wait
-// darwin: pthread_cond_wait$NOCANCEL$UNIX2003
-// darwin: pthread_cond_wait$UNIX2003
+// glibc:   pthread_cond_wait@GLIBC_2.2.5
+// glibc:   pthread_cond_wait@@GLIBC_2.3.2
+// darwin:  pthread_cond_wait
+// darwin:  pthread_cond_wait$NOCANCEL$UNIX2003
+// darwin:  pthread_cond_wait$UNIX2003
+// Solaris: cond_wait (pthread_cond_wait is built atop of cond_wait)
 //
 __attribute__((noinline))
 static int pthread_cond_wait_WRK(pthread_cond_t* cond,
@@ -774,18 +1194,17 @@
 
    CALL_FN_W_WW(ret, fn, cond,mutex);
 
-   /* these conditionals look stupid, but compare w/ same logic for
+   /* this conditional look stupid, but compare w/ same logic for
       pthread_cond_timedwait below */
-   if (ret == 0 && mutex_is_valid) {
-      /* and now we have the mutex again */
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  pthread_mutex_t*,mutex);
+   if (mutex_is_valid) {
+      /* and now we have the mutex again if (ret == 0) */
+      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                   pthread_mutex_t *, mutex, long, (ret == 0) ? True : False);
    }
 
-   if (ret == 0 && mutex_is_valid) {
-      DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
-                    pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0);
-   }
+   DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
+                  pthread_cond_t*,cond, pthread_mutex_t*,mutex, long,0,
+                  long, (ret == 0 && mutex_is_valid) ? True : False);
 
    if (ret != 0) {
       DO_PthAPIerror( "pthread_cond_wait", ret );
@@ -807,24 +1226,32 @@
                  pthread_cond_t* cond, pthread_mutex_t* mutex) {
       return pthread_cond_wait_WRK(cond, mutex);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, condZuwait, // cond_wait
+                 pthread_cond_t *cond, pthread_mutex_t *mutex) {
+      return pthread_cond_wait_WRK(cond, mutex);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_cond_timedwait@@GLIBC_2.3.2
-// glibc:  pthread_cond_timedwait@GLIBC_2.2.5
-// glibc:  pthread_cond_timedwait@GLIBC_2.0
-// darwin: pthread_cond_timedwait
-// darwin: pthread_cond_timedwait$NOCANCEL$UNIX2003
-// darwin: pthread_cond_timedwait$UNIX2003
-// darwin: pthread_cond_timedwait_relative_np (trapped)
+// glibc:   pthread_cond_timedwait@@GLIBC_2.3.2
+// glibc:   pthread_cond_timedwait@GLIBC_2.2.5
+// glibc:   pthread_cond_timedwait@GLIBC_2.0
+// darwin:  pthread_cond_timedwait
+// darwin:  pthread_cond_timedwait$NOCANCEL$UNIX2003
+// darwin:  pthread_cond_timedwait$UNIX2003
+// darwin:  pthread_cond_timedwait_relative_np (trapped)
+// Solaris: cond_timedwait (pthread_cond_timedwait is built on cond_timedwait)
+// Solaris: cond_reltimedwait (pthread_cond_reltimedwait_np is built on this)
 //
 __attribute__((noinline))
 static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
                                       pthread_mutex_t* mutex, 
-                                      struct timespec* abstime)
+                                      struct timespec* abstime,
+                                      int timeout_error)
 {
    int ret;
    OrigFn fn;
@@ -859,25 +1286,26 @@
 
    CALL_FN_W_WWW(ret, fn, cond,mutex,abstime);
 
-   if (!abstime_is_valid && ret != EINVAL) {
+   if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
       DO_PthAPIerror("Bug in libpthread: pthread_cond_timedwait "
                      "invalid abstime did not cause"
                      " EINVAL", ret);
    }
 
-   if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
-      /* and now we have the mutex again */
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  pthread_mutex_t*,mutex);
+   if (mutex_is_valid && abstime_is_valid) {
+      /* and now we have the mutex again if (ret == 0 || ret == timeout) */
+      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                   pthread_mutex_t *, mutex,
+                   long, (ret == 0 || ret == timeout_error) ? True : False);
    }
 
-   if ((ret == 0 || ret == ETIMEDOUT) && mutex_is_valid) {
-      DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
-                    pthread_cond_t*,cond, pthread_mutex_t*,mutex,
-                    long,ret == ETIMEDOUT);
-   }
+   DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
+                  pthread_cond_t*,cond, pthread_mutex_t*,mutex,
+                  long,ret == timeout_error,
+                  long, (ret == 0 || ret == timeout_error) && mutex_is_valid
+                        ? True : False);
 
-   if (ret != 0 && ret != ETIMEDOUT) {
+   if (ret != 0 && ret != timeout_error) {
       DO_PthAPIerror( "pthread_cond_timedwait", ret );
    }
 
@@ -891,35 +1319,47 @@
    PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
                  pthread_cond_t* cond, pthread_mutex_t* mutex, 
                  struct timespec* abstime) {
-      return pthread_cond_timedwait_WRK(cond, mutex, abstime);
+      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
    }
 #elif defined(VGO_darwin)
    PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait
                  pthread_cond_t* cond, pthread_mutex_t* mutex, 
                  struct timespec* abstime) {
-      return pthread_cond_timedwait_WRK(cond, mutex, abstime);
+      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
    }
    PTH_FUNC(int, pthreadZucondZutimedwaitZDZa, // pthread_cond_timedwait$*
                  pthread_cond_t* cond, pthread_mutex_t* mutex, 
                  struct timespec* abstime) {
-      return pthread_cond_timedwait_WRK(cond, mutex, abstime);
+      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT);
    }
    PTH_FUNC(int, pthreadZucondZutimedwaitZuZa, // pthread_cond_timedwait_*
                  pthread_cond_t* cond, pthread_mutex_t* mutex, 
                  struct timespec* abstime) {
       assert(0);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, condZutimedwait, // cond_timedwait
+                 pthread_cond_t *cond, pthread_mutex_t *mutex,
+                 struct timespec *abstime) {
+      return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIME);
+   }
+   PTH_FUNC(int, condZureltimedwait, // cond_reltimedwait
+                 pthread_cond_t *cond, pthread_mutex_t *mutex,
+                 struct timespec *reltime) {
+      return pthread_cond_timedwait_WRK(cond, mutex, reltime, ETIME);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_cond_signal@GLIBC_2.0
-// glibc:  pthread_cond_signal@GLIBC_2.2.5
-// glibc:  pthread_cond_signal@@GLIBC_2.3.2
-// darwin: pthread_cond_signal
-// darwin: pthread_cond_signal_thread_np (don't intercept this)
+// glibc:   pthread_cond_signal@GLIBC_2.0
+// glibc:   pthread_cond_signal@GLIBC_2.2.5
+// glibc:   pthread_cond_signal@@GLIBC_2.3.2
+// darwin:  pthread_cond_signal
+// darwin:  pthread_cond_signal_thread_np (don't intercept this)
+// Solaris: cond_signal (pthread_cond_signal is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_cond_signal_WRK(pthread_cond_t* cond)
@@ -938,6 +1378,9 @@
 
    CALL_FN_W_W(ret, fn, cond);
 
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST,
+               pthread_cond_t*,cond);
+
    if (ret != 0) {
       DO_PthAPIerror( "pthread_cond_signal", ret );
    }
@@ -958,16 +1401,22 @@
                  pthread_cond_t* cond) {
       return pthread_cond_signal_WRK(cond);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, condZusignal, // cond_signal
+                 pthread_cond_t *cond) {
+      return pthread_cond_signal_WRK(cond);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_cond_broadcast@GLIBC_2.0
-// glibc:  pthread_cond_broadcast@GLIBC_2.2.5
-// glibc:  pthread_cond_broadcast@@GLIBC_2.3.2
-// darwin: pthread_cond_broadcast
+// glibc:   pthread_cond_broadcast@GLIBC_2.0
+// glibc:   pthread_cond_broadcast@GLIBC_2.2.5
+// glibc:   pthread_cond_broadcast@@GLIBC_2.3.2
+// darwin:  pthread_cond_broadcast
+// Solaris: cond_broadcast (pthread_cond_broadcast is a weak alias)
 //
 // Note, this is pretty much identical, from a dependency-graph
 // point of view, with cond_signal, so the code is duplicated.
@@ -990,6 +1439,9 @@
 
    CALL_FN_W_W(ret, fn, cond);
 
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST,
+               pthread_cond_t*,cond);
+
    if (ret != 0) { 
       DO_PthAPIerror( "pthread_cond_broadcast", ret );
    }
@@ -1010,18 +1462,25 @@
                  pthread_cond_t* cond) {
       return pthread_cond_broadcast_WRK(cond);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, condZubroadcast, // cond_broadcast
+                 pthread_cond_t *cond) {
+      return pthread_cond_broadcast_WRK(cond);
+   }
 #else
 #   error "Unsupported OS"
 #endif
 
-// glibc:  pthread_cond_init@GLIBC_2.0
-// glibc:  pthread_cond_init@GLIBC_2.2.5
-// glibc:  pthread_cond_init@@GLIBC_2.3.2
-// darwin: pthread_cond_init
+// glibc:   pthread_cond_init@GLIBC_2.0
+// glibc:   pthread_cond_init@GLIBC_2.2.5
+// glibc:   pthread_cond_init@@GLIBC_2.3.2
+// darwin:  pthread_cond_init
+// Solaris: cond_init (pthread_cond_init is built atop on this function)
 // Easy way out: Handling of attr could have been messier.
 // It turns out that pthread_cond_init under linux ignores
 // all information in cond_attr, so do we.
 // FIXME: MacOS X?
+#if !defined(VGO_solaris)
 __attribute__((noinline))
 static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_attr)
 {
@@ -1063,12 +1522,45 @@
 #  error "Unsupported OS"
 #endif
 
+#else /* VGO_solaris */
+__attribute__((noinline))
+PTH_FUNC(int, condZuinit, // cond_init
+              cond_t *cond, int type, void *arg)
+{
+   int ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< cond_init %p", cond); fflush(stderr);
+   }
+
+   CALL_FN_W_WWW(ret, fn, cond, type, arg);
+
+   if (ret == 0) {
+      /* Luckily evh__HG_PTHREAD_COND_INIT_POST() ignores cond_attr.
+         See also comment for pthread_cond_init_WRK(). */
+      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_COND_INIT_POST,
+                   cond_t *, cond, void *, NULL);
+   } else {
+      DO_PthAPIerror("cond_init", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " cond_init -> %d >>\n", ret);
+   }
+
+   return ret;
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_cond_destroy@@GLIBC_2.3.2
-// glibc:  pthread_cond_destroy@GLIBC_2.2.5
-// glibc:  pthread_cond_destroy@GLIBC_2.0
-// darwin: pthread_cond_destroy
+// glibc:   pthread_cond_destroy@@GLIBC_2.3.2
+// glibc:   pthread_cond_destroy@GLIBC_2.2.5
+// glibc:   pthread_cond_destroy@GLIBC_2.0
+// darwin:  pthread_cond_destroy
+// Solaris: cond_destroy (pthread_cond_destroy is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_cond_destroy_WRK(pthread_cond_t* cond)
@@ -1116,6 +1608,11 @@
                  pthread_cond_t* cond) {
       return pthread_cond_destroy_WRK(cond);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, condZudestroy, // cond_destroy
+                 pthread_cond_t *cond) {
+      return pthread_cond_destroy_WRK(cond);
+   }
 #else
 #  error "Unsupported OS"
 #endif
@@ -1139,8 +1636,9 @@
 */
 
 //-----------------------------------------------------------
-// glibc:  pthread_barrier_init
-// darwin: (doesn't appear to exist)
+// glibc:   pthread_barrier_init
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_barrier_init
 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
          pthread_barrier_t* bar,
          pthread_barrierattr_t* attr, unsigned long count)
@@ -1175,8 +1673,9 @@
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_barrier_wait
-// darwin: (doesn't appear to exist)
+// glibc:   pthread_barrier_wait
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_barrier_wait
 PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
               pthread_barrier_t* bar)
 {
@@ -1212,8 +1711,9 @@
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_barrier_destroy
-// darwin: (doesn't appear to exist)
+// glibc:   pthread_barrier_destroy
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_barrier_destroy
 PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
          pthread_barrier_t* bar)
 {
@@ -1262,12 +1762,16 @@
 /* This is a nasty kludge, in that glibc "knows" that initialising a
    spin lock unlocks it, and pthread_spin_{init,unlock} are names for
    the same function.  Hence we have to have a wrapper which does both
-   things, without knowing which the user intended to happen. */
+   things, without knowing which the user intended to happen.
+   Solaris has distinct functions for init/unlock but client requests
+   are immutable in helgrind.h so follow the glibc lead. */
 
 //-----------------------------------------------------------
-// glibc:  pthread_spin_init
-// glibc:  pthread_spin_unlock
-// darwin: (doesn't appear to exist)
+// glibc:   pthread_spin_init
+// glibc:   pthread_spin_unlock
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_spin_init
+// Solaris: pthread_spin_unlock
 __attribute__((noinline))
 static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock,
                                            int pshared) {
@@ -1306,18 +1810,26 @@
       return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
    }
 #elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
+            pthread_spinlock_t *lock, int pshared) {
+      return pthread_spin_init_or_unlock_WRK(lock, pshared);
+   }
+   PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
+            pthread_spinlock_t *lock) {
+      return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_spin_destroy
-// darwin: (doesn't appear to exist)
-#if defined(VGO_linux)
-
-PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
-              pthread_spinlock_t* lock)
+// glibc:   pthread_spin_destroy
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_spin_destroy
+__attribute__((noinline))
+static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock)
 {
    int    ret;
    OrigFn fn;
@@ -1341,20 +1853,28 @@
    }
    return ret;
 }
-
+#if defined(VGO_linux)
+   PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy
+            pthread_spinlock_t *lock) {
+      return pthread_spin_destroy_WRK(lock);
+   }
 #elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZuspinZusdestroy, // pthread_spin_destroy
+            pthread_spinlock_t *lock) {
+      return pthread_spin_destroy_WRK(lock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_spin_lock
-// darwin: (doesn't appear to exist)
-#if defined(VGO_linux)
-
-PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
-              pthread_spinlock_t* lock)
+// glibc:   pthread_spin_lock
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_spin_lock
+__attribute__((noinline))
+static int pthread_spin_lock_WRK(pthread_spinlock_t *lock)
 {
    int    ret;
    OrigFn fn;
@@ -1386,20 +1906,28 @@
    }
    return ret;
 }
-
+#if defined(VGO_linux)
+   PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
+                 pthread_spinlock_t *lock) {
+      return pthread_spin_lock_WRK(lock);
+   }
 #elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
+                 pthread_spinlock_t *lock) {
+      return pthread_spin_lock_WRK(lock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_spin_trylock
-// darwin: (doesn't appear to exist)
-#if defined(VGO_linux)
-
-PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
-              pthread_spinlock_t* lock)
+// glibc:   pthread_spin_trylock
+// darwin:  (doesn't appear to exist)
+// Solaris: pthread_spin_trylock
+__attribute__((noinline))
+static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock)
 {
    int    ret;
    OrigFn fn;
@@ -1432,8 +1960,17 @@
    }
    return ret;
 }
-
+#if defined(VGO_linux)
+   PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
+                 pthread_spinlock_t *lock) {
+      return pthread_spin_trylock_WRK(lock);
+   }
 #elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
+                 pthread_spinlock_t *lock) {
+      return pthread_spin_trylock_WRK(lock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
@@ -1453,18 +1990,18 @@
               pthread_rwlock_rdlock 
               pthread_rwlock_wrlock
               pthread_rwlock_unlock
+              pthread_rwlock_tryrdlock
+              pthread_rwlock_trywrlock
 
    Unhandled: pthread_rwlock_timedrdlock
-              pthread_rwlock_tryrdlock
-
               pthread_rwlock_timedwrlock
-              pthread_rwlock_trywrlock
 */
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_init
-// darwin: pthread_rwlock_init
-// darwin: pthread_rwlock_init$UNIX2003
+// glibc:   pthread_rwlock_init
+// darwin:  pthread_rwlock_init
+// darwin:  pthread_rwlock_init$UNIX2003
+// Solaris: rwlock_init (pthread_rwlock_init is built atop of rwlock_init)
 __attribute__((noinline))
 static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
                                    pthread_rwlockattr_t* attr)
@@ -1502,15 +2039,49 @@
                  pthread_rwlockattr_t* attr) {
       return pthread_rwlock_init_WRK(rwl, attr);
    }
+#elif defined(VGO_solaris)
+static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl,
+                                   pthread_rwlockattr_t* attr)
+                                   __attribute__((unused));
 #else
 #  error "Unsupported OS"
 #endif
 
+#if defined(VGO_solaris)
+PTH_FUNC(int, rwlockZuinit, // rwlock_init
+              rwlock_t *rwlock,
+              int type,
+              void *arg)
+{
+   int    ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< rwl_init %p", rwlock); fflush(stderr);
+   }
+
+   CALL_FN_W_WWW(ret, fn, rwlock, type, arg);
+
+   if (ret == 0 /*success*/) {
+      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST,
+                  rwlock_t *, rwlock);
+   } else {
+      DO_PthAPIerror("rwlock_init", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: rwl_init -> %d >>\n", ret);
+   }
+   return ret;
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_destroy
-// darwin: pthread_rwlock_destroy
-// darwin: pthread_rwlock_destroy$UNIX2003
+// glibc:   pthread_rwlock_destroy
+// darwin:  pthread_rwlock_destroy
+// darwin:  pthread_rwlock_destroy$UNIX2003
+// Solaris: rwlock_destroy (pthread_rwlock_destroy is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl)
@@ -1546,15 +2117,21 @@
                  pthread_rwlock_t *rwl) {
       return pthread_rwlock_destroy_WRK(rwl);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwlockZudestroy, // rwlock_destroy
+                 pthread_rwlock_t *rwl) {
+      return pthread_rwlock_destroy_WRK(rwl);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_wrlock
-// darwin: pthread_rwlock_wrlock
-// darwin: pthread_rwlock_wrlock$UNIX2003
+// glibc:   pthread_rwlock_wrlock
+// darwin:  pthread_rwlock_wrlock
+// darwin:  pthread_rwlock_wrlock$UNIX2003
+// Solaris: rw_wrlock (pthread_rwlock_wrlock is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock)
@@ -1572,10 +2149,10 @@
 
    CALL_FN_W_W(ret, fn, rwlock);
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-                   pthread_rwlock_t*,rwlock, long,1/*isW*/);
-   } else { 
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t*,rwlock, long,1/*isW*/,
+                 long, (ret == 0) ? True : False);
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_rwlock_wrlock", ret );
    }
 
@@ -1594,15 +2171,47 @@
                  pthread_rwlock_t* rwlock) {
       return pthread_rwlock_wrlock_WRK(rwlock);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwZuwrlock, // rw_wrlock
+                 pthread_rwlock_t *rwlock) {
+      return pthread_rwlock_wrlock_WRK(rwlock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
+#if defined(VGO_solaris)
+/* Internal to libc. */
+PTH_FUNC(void, lrwZuwrlock, // lrw_wrlock
+               rwlock_t *rwlock)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< lrw_wlk %p", rwlock); fflush(stderr);
+   }
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
+                 pthread_rwlock_t *, rwlock,
+                 long, 1/*isW*/, long, 0/*!isTryLock*/);
+
+   CALL_FN_v_W(fn, rwlock);
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t *, rwlock, long, 1/*isW*/, long, True);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: lrw_wlk >>\n");
+   }
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_rdlock
-// darwin: pthread_rwlock_rdlock
-// darwin: pthread_rwlock_rdlock$UNIX2003
+// glibc:   pthread_rwlock_rdlock
+// darwin:  pthread_rwlock_rdlock
+// darwin:  pthread_rwlock_rdlock$UNIX2003
+// Solaris: rw_rdlock (pthread_rwlock_rdlock is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock)
@@ -1620,10 +2229,10 @@
 
    CALL_FN_W_W(ret, fn, rwlock);
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-                   pthread_rwlock_t*,rwlock, long,0/*!isW*/);
-   } else { 
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t*,rwlock, long,0/*!isW*/,
+                 long, (ret == 0) ? True : False);
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_rwlock_rdlock", ret );
    }
 
@@ -1642,15 +2251,47 @@
                  pthread_rwlock_t* rwlock) {
       return pthread_rwlock_rdlock_WRK(rwlock);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwZurdlock, // rw_rdlock
+                 pthread_rwlock_t *rwlock) {
+      return pthread_rwlock_rdlock_WRK(rwlock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
+#if defined(VGO_solaris)
+/* Internal to libc. */
+PTH_FUNC(void, lrwZurdlock, // lrw_rdlock
+               rwlock_t *rwlock)
+{
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< lrw_rlk %p", rwlock); fflush(stderr);
+   }
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
+                 pthread_rwlock_t *, rwlock,
+                 long, 0/*!isW*/, long, 0/*!isTryLock*/);
+
+   CALL_FN_v_W(fn, rwlock);
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t *, rwlock, long, 0/*!isW*/, long, True);
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: lrw_rlk ->>\n");
+   }
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_trywrlock
-// darwin: pthread_rwlock_trywrlock
-// darwin: pthread_rwlock_trywrlock$UNIX2003
+// glibc:   pthread_rwlock_trywrlock
+// darwin:  pthread_rwlock_trywrlock
+// darwin:  pthread_rwlock_trywrlock$UNIX2003
+// Solaris: rw_trywrlock (pthread_rwlock_trywrlock is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock)
@@ -1673,10 +2314,10 @@
       that the lock has been acquired by someone (this thread).  Does
       this matter?  Not sure, but I don't think so. */
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-                   pthread_rwlock_t*,rwlock, long,1/*isW*/);
-   } else { 
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t*,rwlock, long,1/*isW*/,
+                 long, (ret == 0) ? True : False);
+   if (ret != 0) {
       if (ret != EBUSY)
          DO_PthAPIerror( "pthread_rwlock_trywrlock", ret );
    }
@@ -1696,15 +2337,21 @@
                  pthread_rwlock_t* rwlock) {
       return pthread_rwlock_trywrlock_WRK(rwlock);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwZutrywrlock, // rw_trywrlock
+                 pthread_rwlock_t *rwlock) {
+      return pthread_rwlock_trywrlock_WRK(rwlock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_tryrdlock
-// darwin: pthread_rwlock_trywrlock
-// darwin: pthread_rwlock_trywrlock$UNIX2003
+// glibc:   pthread_rwlock_tryrdlock
+// darwin:  pthread_rwlock_tryrdlock
+// darwin:  pthread_rwlock_tryrdlock$UNIX2003
+// Solaris: rw_tryrdlock (pthread_rwlock_tryrdlock is a weak alias)
 //
 __attribute__((noinline))
 static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock)
@@ -1727,10 +2374,11 @@
       that the lock has been acquired by someone (this thread).  Does
       this matter?  Not sure, but I don't think so. */
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-                   pthread_rwlock_t*,rwlock, long,0/*!isW*/);
-   } else { 
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                pthread_rwlock_t*,rwlock, long,0/*!isW*/,
+                long, (ret == 0) ? True : False);
+
+   if (ret != 0) {
       if (ret != EBUSY)
          DO_PthAPIerror( "pthread_rwlock_tryrdlock", ret );
    }
@@ -1750,15 +2398,127 @@
                  pthread_rwlock_t* rwlock) {
       return pthread_rwlock_tryrdlock_WRK(rwlock);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwZutryrdlock, // rw_tryrdlock
+                 pthread_rwlock_t *rwlock) {
+      return pthread_rwlock_tryrdlock_WRK(rwlock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  pthread_rwlock_unlock
-// darwin: pthread_rwlock_unlock
-// darwin: pthread_rwlock_unlock$UNIX2003
+// glibc:   Unhandled
+// darwin:  Unhandled
+// Solaris: pthread_rwlock_timedrdlock
+// Solaris: pthread_rwlock_reltimedrdlock_np
+//
+__attribute__((noinline)) __attribute__((unused))
+static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock,
+                                          const struct timespec *timeout)
+{
+   int    ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< pthread_rwl_timedrdl %p", rwlock); fflush(stderr);
+   }
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
+                 pthread_rwlock_t *, rwlock,
+                 long, 0/*isW*/, long, 0/*isTryLock*/);
+
+   CALL_FN_W_WW(ret, fn, rwlock, timeout);
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t *, rwlock, long, 0/*isW*/,
+                 long, (ret == 0) ? True : False);
+   if (ret != 0) {
+      DO_PthAPIerror("pthread_rwlock_timedrdlock", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: rwl_timedrdl -> %d >>\n", ret);
+   }
+   return ret;
+}
+#if defined(VGO_linux)
+#elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock
+                 pthread_rwlock_t *rwlock,
+                 const struct timespec *timeout) {
+      return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
+   }
+   PTH_FUNC(int, pthreadZurwlockZureltimedrdlockZunp, // pthread_rwlock_timedrdlock_np
+                 pthread_rwlock_t *rwlock,
+                 const struct timespec *timeout) {
+      return pthread_rwlock_timedrdlock_WRK(rwlock, timeout);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
+
+//-----------------------------------------------------------
+// glibc:   Unhandled
+// darwin:  Unhandled
+// Solaris: pthread_rwlock_timedwrlock
+// Solaris: pthread_rwlock_reltimedwrlock_np
+//
+__attribute__((noinline)) __attribute__((unused))
+static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock,
+                                          const struct timespec *timeout)
+{
+   int    ret;
+   OrigFn fn;
+   VALGRIND_GET_ORIG_FN(fn);
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, "<< pthread_rwl_timedwrl %p", rwlock); fflush(stderr);
+   }
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE,
+                 pthread_rwlock_t *, rwlock,
+                 long, 1/*isW*/, long, 0/*isTryLock*/);
+
+   CALL_FN_W_WW(ret, fn, rwlock, timeout);
+
+   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+                 pthread_rwlock_t *, rwlock, long, 1/*isW*/,
+                 long, (ret == 0) ? True : False);
+   if (ret != 0) {
+      DO_PthAPIerror("pthread_rwlock_timedwrlock", ret);
+   }
+
+   if (TRACE_PTH_FNS) {
+      fprintf(stderr, " :: rwl_timedwrl -> %d >>\n", ret);
+   }
+   return ret;
+}
+#if defined(VGO_linux)
+#elif defined(VGO_darwin)
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock
+                 pthread_rwlock_t *rwlock,
+                 const struct timespec *timeout) {
+      return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
+   }
+   PTH_FUNC(int, pthreadZurwlockZureltimedwrlockZunp, // pthread_rwlock_timedwrlock_np
+                 pthread_rwlock_t *rwlock,
+                 const struct timespec *timeout) {
+      return pthread_rwlock_timedwrlock_WRK(rwlock, timeout);
+   }
+#else
+#  error "Unsupported OS"
+#endif
+
+
+//-----------------------------------------------------------
+// glibc:   pthread_rwlock_unlock
+// darwin:  pthread_rwlock_unlock
+// darwin:  pthread_rwlock_unlock$UNIX2003
+// Solaris: rw_unlock (pthread_rwlock_unlock is a weak alias)
 __attribute__((noinline))
 static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock)
 {
@@ -1774,10 +2534,9 @@
 
    CALL_FN_W_W(ret, fn, rwlock);
 
-   if (ret == 0 /*success*/) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
-                  pthread_rwlock_t*,rwlock);
-   } else { 
+   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST,
+               pthread_rwlock_t*,rwlock);
+   if (ret != 0) {
       DO_PthAPIerror( "pthread_rwlock_unlock", ret );
    }
 
@@ -1796,6 +2555,11 @@
                  pthread_rwlock_t* rwlock) {
       return pthread_rwlock_unlock_WRK(rwlock);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, rwZuunlock, // rw_unlock
+                 pthread_rwlock_t *rwlock) {
+      return pthread_rwlock_unlock_WRK(rwlock);
+   }
 #else
 #  error "Unsupported OS"
 #endif
@@ -1829,11 +2593,13 @@
 */
 
 //-----------------------------------------------------------
-// glibc:  sem_init@@GLIBC_2.2.5
-// glibc:  sem_init@@GLIBC_2.1
-// glibc:  sem_init@GLIBC_2.0
-// darwin: sem_init
+// glibc:   sem_init@@GLIBC_2.2.5
+// glibc:   sem_init@@GLIBC_2.1
+// glibc:   sem_init@GLIBC_2.0
+// darwin:  sem_init
+// Solaris: sema_init (sem_init is built on top of sem_init)
 //
+#if !defined(VGO_solaris)
 __attribute__((noinline))
 static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value)
 {
@@ -1876,12 +2642,47 @@
 #  error "Unsupported OS"
 #endif
 
+#else /* VGO_solaris */
+PTH_FUNC(int, semaZuinit, // sema_init
+              sema_t *sem,
+              unsigned int value,
+              int type,
+              void *arg)
+{
+   OrigFn fn;
+   int    ret;
+   VALGRIND_GET_ORIG_FN(fn);
+
+   if (TRACE_SEM_FNS) {
+      fprintf(stderr, "<< sema_init(%p, %d, %u) ", sem, type, value);
+      fflush(stderr);
+   }
+
+   CALL_FN_W_WWWW(ret, fn, sem, value, type, arg);
+
+   if (ret == 0) {
+      DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_INIT_POST,
+                   sema_t *, sem, Word, value);
+   } else {
+      DO_PthAPIerror("sema_init", ret);
+   }
+
+   if (TRACE_SEM_FNS) {
+      fprintf(stderr, " sema_init -> %d >>\n", ret);
+      fflush(stderr);
+   }
+
+   return ret;
+}
+#endif /* VGO_solaris */
+
 
 //-----------------------------------------------------------
-// glibc:  sem_destroy@GLIBC_2.0
-// glibc:  sem_destroy@@GLIBC_2.1
-// glibc:  sem_destroy@@GLIBC_2.2.5
-// darwin: sem_destroy
+// glibc:   sem_destroy@GLIBC_2.0
+// glibc:   sem_destroy@@GLIBC_2.1
+// glibc:   sem_destroy@@GLIBC_2.2.5
+// darwin:  sem_destroy
+// Solaris: sema_destroy (sem_destroy is built on top of sema_destroy)
 __attribute__((noinline))
 static int sem_destroy_WRK(sem_t* sem)
 {
@@ -1899,7 +2700,7 @@
    CALL_FN_W_W(ret, fn, sem);
 
    if (ret != 0) {
-      DO_PthAPIerror( "sem_destroy", errno );
+      DO_PthAPIerror( "sem_destroy", SEM_ERROR );
    }
 
    if (TRACE_SEM_FNS) {
@@ -1919,18 +2720,24 @@
                  sem_t* sem) {
       return sem_destroy_WRK(sem);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, semaZudestroy,  // sema_destroy
+                 sem_t *sem) {
+      return sem_destroy_WRK(sem);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  sem_wait
-// glibc:  sem_wait@GLIBC_2.0
-// glibc:  sem_wait@@GLIBC_2.1
-// darwin: sem_wait
-// darwin: sem_wait$NOCANCEL$UNIX2003
-// darwin: sem_wait$UNIX2003
+// glibc:   sem_wait
+// glibc:   sem_wait@GLIBC_2.0
+// glibc:   sem_wait@@GLIBC_2.1
+// darwin:  sem_wait
+// darwin:  sem_wait$NOCANCEL$UNIX2003
+// darwin:  sem_wait$UNIX2003
+// Solaris: sema_wait (sem_wait is built on top of sema_wait)
 //
 /* wait: decrement semaphore - acquire lockage */
 __attribute__((noinline))
@@ -1945,12 +2752,15 @@
       fflush(stderr);
    }
 
+   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_PRE, sem_t*,sem);
+
    CALL_FN_W_W(ret, fn, sem);
 
-   if (ret == 0) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem);
-   } else {
-      DO_PthAPIerror( "sem_wait", errno );
+   DO_CREQ_v_WW(_VG_USERREQ__HG_POSIX_SEM_WAIT_POST, sem_t*,sem,
+                long, (ret == 0) ? True : False);
+
+   if (ret != 0) {
+      DO_PthAPIerror( "sem_wait", SEM_ERROR );
    }
 
    if (TRACE_SEM_FNS) {
@@ -1974,16 +2784,21 @@
    PTH_FUNC(int, semZuwaitZDZa, sem_t* sem) { /* sem_wait$* */
       return sem_wait_WRK(sem);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, semaZuwait, sem_t *sem) { /* sema_wait */
+      return sem_wait_WRK(sem);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  sem_post
-// glibc:  sem_post@GLIBC_2.0
-// glibc:  sem_post@@GLIBC_2.1
-// darwin: sem_post
+// glibc:   sem_post
+// glibc:   sem_post@GLIBC_2.0
+// glibc:   sem_post@@GLIBC_2.1
+// darwin:  sem_post
+// Solaris: sema_post (sem_post is built on top of sema_post)
 //
 /* post: increment semaphore - release lockage */
 __attribute__((noinline))
@@ -2003,8 +2818,10 @@
 
    CALL_FN_W_W(ret, fn, sem);
 
+   DO_CREQ_v_W(_VG_USERREQ__HG_POSIX_SEM_POST_POST, sem_t*,sem);
+
    if (ret != 0) {
-      DO_PthAPIerror( "sem_post", errno );
+      DO_PthAPIerror( "sem_post", SEM_ERROR );
    }
 
    if (TRACE_SEM_FNS) {
@@ -2025,14 +2842,19 @@
    PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */
       return sem_post_WRK(sem);
    }
+#elif defined(VGO_solaris)
+   PTH_FUNC(int, semaZupost, sem_t *sem) { /* sema_post */
+      return sem_post_WRK(sem);
+   }
 #else
 #  error "Unsupported OS"
 #endif
 
 
 //-----------------------------------------------------------
-// glibc:  sem_open
-// darwin: sem_open
+// glibc:   sem_open
+// darwin:  sem_open
+// Solaris: sem_open
 //
 PTH_FUNC(sem_t*, semZuopen,
                  const char* name, long oflag,
@@ -2069,8 +2891,9 @@
 
 
 //-----------------------------------------------------------
-// glibc:  sem_close
-// darwin: sem_close
+// glibc:   sem_close
+// darwin:  sem_close
+// Solaris: sem_close
 PTH_FUNC(int, sem_close, sem_t* sem)
 {
    OrigFn fn;
@@ -2209,8 +3032,8 @@
 
    CALL_FN_v_W(fn, self);
 
-   DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-               void*, self);
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                void *, self, long, True);
 
    if (TRACE_QT4_FNS) {
       fprintf(stderr, " :: Q::lock done >>\n");
@@ -2275,10 +3098,8 @@
    CALL_FN_W_W(ret, fn, self);
 
    // assumes that only the low 8 bits of the 'bool' are significant
-   if (ret & 0xFF) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  void*, self);
-   }
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+                void *, self, long, (ret & 0xFF) ? True : False);
 
    if (TRACE_QT4_FNS) {
       fprintf(stderr, " :: Q::tryLock -> %lu >>\n", ret);
@@ -2314,10 +3135,8 @@
    CALL_FN_W_WW(ret, fn, self,arg2);
 
    // assumes that only the low 8 bits of the 'bool' are significant
-   if (ret & 0xFF) {
-      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
-                  void*, self);
-   }
+   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
+               void *, self, long, (ret & 0xFF) ? True : False);
 
    if (TRACE_QT4_FNS) {
       fprintf(stderr, " :: Q::tryLock(int) -> %lu >>\n", ret);
@@ -2442,8 +3261,8 @@
 //
 //   CALL_FN_v_W(fn, self);
 //
-//   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-//                void*,self, long,0/*!isW*/);
+//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+//                 void*,self, long,0/*!isW*/, long, True);
 //
 //   if (TRACE_QT4_FNS) {
 //      fprintf(stderr, " :: Q::lockForRead :: done >>\n");
@@ -2469,8 +3288,8 @@
 //
 //   CALL_FN_v_W(fn, self);
 //
-//   DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
-//                void*,self, long,1/*isW*/);
+//   DO_CREQ_v_WWW(_VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST,
+//                 void*,self, long,1/*isW*/, long, True);
 //
 //   if (TRACE_QT4_FNS) {
 //      fprintf(stderr, " :: Q::lockForWrite :: done >>\n");
diff --git a/helgrind/hg_lock_n_thread.h b/helgrind/hg_lock_n_thread.h
index 7626191..ff07d05 100644
--- a/helgrind/hg_lock_n_thread.h
+++ b/helgrind/hg_lock_n_thread.h
@@ -94,6 +94,29 @@
       Bool        announced;
       /* Index for generating references in error messages. */
       Int         errmsg_index;
+
+      /* Nesting level of pthread_create(). New memory allocated is untracked
+         when this value is > 0: race reporting is suppressed there. DRD does
+         the same thing implicitly. This is necessary because for example
+         Solaris libc caches many objects and reuses them for different threads
+         and that confuses Helgrind. With libvki it would be possible to
+         explictly use VG_USERREQ__HG_CLEAN_MEMORY on such objects.
+         Also mutex activity is ignored so that they do not impose false
+         ordering between creator and created thread. */
+      Int pthread_create_nesting_level;
+
+      /* Nesting level of synchronization functions called by the client.
+         Loads and stores are ignored when its value > 0.
+         Currently this is used solely for suppressing races of primitive
+         synchronization objects themselves - mutexes, condition variables,
+         read-write locks and their associated sleep queues.
+         See also documentation for command line option
+         --ignore-thread-creation. */
+      Int synchr_nesting;
+
+#if defined(VGO_solaris)
+      Int      bind_guard_flag; /* Bind flag from the runtime linker. */
+#endif /* VGO_solaris */
    }
    Thread;
 
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index b1a0aa3..2550613 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -53,7 +53,7 @@
 #include "pub_tool_debuginfo.h" // VG_(find_seginfo), VG_(seginfo_soname)
 #include "pub_tool_redir.h"     // sonames for the dynamic linkers
 #include "pub_tool_vki.h"       // VKI_PAGE_SIZE
-#include "pub_tool_libcproc.h"  // VG_(atfork)
+#include "pub_tool_libcproc.h"
 #include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
 #include "pub_tool_poolalloc.h"
 #include "pub_tool_addrinfo.h"
@@ -160,6 +160,12 @@
 static UWord stats__lockN_acquires = 0;
 static UWord stats__lockN_releases = 0;
 
+#if defined(VGO_solaris)
+Bool HG_(clo_ignore_thread_creation) = True;
+#else
+Bool HG_(clo_ignore_thread_creation) = False;
+#endif /* VGO_solaris */
+
 static
 ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr ); /*fwds*/
 
@@ -177,6 +183,12 @@
    thread->announced    = False;
    thread->errmsg_index = indx++;
    thread->admin        = admin_threads;
+   thread->synchr_nesting = 0;
+   thread->pthread_create_nesting_level = 0;
+#if defined(VGO_solaris)
+   thread->bind_guard_flag = 0;
+#endif /* VGO_solaris */
+
    admin_threads        = thread;
    return thread;
 }
@@ -698,6 +710,34 @@
    map_threads[coretid] = NULL;
 }
 
+static void HG_(thread_enter_synchr)(Thread *thr) {
+   tl_assert(thr->synchr_nesting >= 0);
+#if defined(VGO_solaris)
+   thr->synchr_nesting += 1;
+#endif /* VGO_solaris */
+}
+
+static void HG_(thread_leave_synchr)(Thread *thr) {
+#if defined(VGO_solaris)
+   thr->synchr_nesting -= 1;
+#endif /* VGO_solaris */
+   tl_assert(thr->synchr_nesting >= 0);
+}
+
+static void HG_(thread_enter_pthread_create)(Thread *thr) {
+   tl_assert(thr->pthread_create_nesting_level >= 0);
+   thr->pthread_create_nesting_level += 1;
+}
+
+static void HG_(thread_leave_pthread_create)(Thread *thr) {
+   tl_assert(thr->pthread_create_nesting_level > 0);
+   thr->pthread_create_nesting_level -= 1;
+}
+
+static Int HG_(get_pthread_create_nesting_level)(ThreadId tid) {
+   Thread *thr = map_threads_maybe_lookup(tid);
+   return thr->pthread_create_nesting_level;
+}
 
 /*----------------------------------------------------------------*/
 /*--- map_locks :: WordFM guest-Addr-of-lock Lock*             ---*/
@@ -1423,40 +1463,52 @@
 
 static
 void evh__new_mem ( Addr a, SizeT len ) {
+   Thread *thr = get_current_Thread();
    if (SHOW_EVENTS >= 2)
       VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
-   shadow_mem_make_New( get_current_Thread(), a, len );
+   shadow_mem_make_New( thr, a, len );
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__new_mem-post");
+   if (UNLIKELY(thr->pthread_create_nesting_level > 0))
+      shadow_mem_make_Untracked( thr, a, len );
 }
 
 static
 void evh__new_mem_stack ( Addr a, SizeT len ) {
+   Thread *thr = get_current_Thread();
    if (SHOW_EVENTS >= 2)
       VG_(printf)("evh__new_mem_stack(%p, %lu)\n", (void*)a, len );
-   shadow_mem_make_New( get_current_Thread(),
-                        -VG_STACK_REDZONE_SZB + a, len );
+   shadow_mem_make_New( thr, -VG_STACK_REDZONE_SZB + a, len );
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__new_mem_stack-post");
+   if (UNLIKELY(thr->pthread_create_nesting_level > 0))
+      shadow_mem_make_Untracked( thr, a, len );
 }
 
 static
 void evh__new_mem_w_tid ( Addr a, SizeT len, ThreadId tid ) {
+   Thread *thr = get_current_Thread();
    if (SHOW_EVENTS >= 2)
       VG_(printf)("evh__new_mem_w_tid(%p, %lu)\n", (void*)a, len );
-   shadow_mem_make_New( get_current_Thread(), a, len );
+   shadow_mem_make_New( thr, a, len );
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__new_mem_w_tid-post");
+   if (UNLIKELY(thr->pthread_create_nesting_level > 0))
+      shadow_mem_make_Untracked( thr, a, len );
 }
 
 static
 void evh__new_mem_w_perms ( Addr a, SizeT len, 
                             Bool rr, Bool ww, Bool xx, ULong di_handle ) {
+   Thread *thr = get_current_Thread();
    if (SHOW_EVENTS >= 1)
       VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
                   (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
-   if (rr || ww || xx)
-      shadow_mem_make_New( get_current_Thread(), a, len );
+   if (rr || ww || xx) {
+      shadow_mem_make_New( thr, a, len );
+      if (UNLIKELY(thr->pthread_create_nesting_level > 0))
+         shadow_mem_make_Untracked( thr, a, len );
+   }
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__new_mem_w_perms-post");
 }
@@ -1518,7 +1570,9 @@
 void evh__copy_mem ( Addr src, Addr dst, SizeT len ) {
    if (SHOW_EVENTS >= 2)
       VG_(printf)("evh__copy_mem(%p, %p, %lu)\n", (void*)src, (void*)dst, len );
-   shadow_mem_scopy_range( get_current_Thread(), src, dst, len );
+   Thread *thr = get_current_Thread();
+   if (LIKELY(thr->synchr_nesting == 0))
+      shadow_mem_scopy_range( thr , src, dst, len );
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__copy_mem-post");
 }
@@ -1582,6 +1636,13 @@
 #       endif
         thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
       }
+
+      if (HG_(clo_ignore_thread_creation)) {
+         HG_(thread_enter_pthread_create)(thr_c);
+         tl_assert(thr_c->synchr_nesting == 0);
+         HG_(thread_enter_synchr)(thr_c);
+         /* Counterpart in _VG_USERREQ__HG_SET_MY_PTHREAD_T. */
+      }
    }
 
    if (HG_(clo_sanity_flags) & SCE_THREADS)
@@ -1752,7 +1813,9 @@
        || (SHOW_EVENTS >= 1 && size != 1))
       VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n", 
                   (Int)tid, s, (void*)a, size );
-   shadow_mem_cread_range( map_threads_lookup(tid), a, size);
+   Thread *thr = map_threads_lookup(tid);
+   if (LIKELY(thr->synchr_nesting == 0))
+      shadow_mem_cread_range(thr, a, size);
    if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__pre_mem_read-post");
 }
@@ -1770,8 +1833,10 @@
    // checking the first byte is better than nothing.  See #255009.
    if (!VG_(am_is_valid_for_client) (a, 1, VKI_PROT_READ))
       return;
+   Thread *thr = map_threads_lookup(tid);
    len = VG_(strlen)( (HChar*) a );
-   shadow_mem_cread_range( map_threads_lookup(tid), a, len+1 );
+   if (LIKELY(thr->synchr_nesting == 0))
+      shadow_mem_cread_range( thr, a, len+1 );
    if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__pre_mem_read_asciiz-post");
 }
@@ -1782,7 +1847,9 @@
    if (SHOW_EVENTS >= 1)
       VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n", 
                   (Int)tid, s, (void*)a, size );
-   shadow_mem_cwrite_range( map_threads_lookup(tid), a, size);
+   Thread *thr = map_threads_lookup(tid);
+   if (LIKELY(thr->synchr_nesting == 0))
+      shadow_mem_cwrite_range(thr, a, size);
    if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
       all__sanity_check("evh__pre_mem_write-post");
 }
@@ -1811,7 +1878,8 @@
          where memory is referenced by one thread, and freed by
          another, and there's no observable synchronisation event to
          guarantee that the reference happens before the free. */
-      shadow_mem_cwrite_range(thr, a, len);
+      if (LIKELY(thr->synchr_nesting == 0))
+         shadow_mem_cwrite_range(thr, a, len);
    }
    shadow_mem_make_NoAccess_AHAE( thr, a, len );
    /* We used to call instead
@@ -1845,70 +1913,80 @@
 void evh__mem_help_cread_1(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CREAD_1(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CREAD_1(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cread_2(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CREAD_2(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CREAD_2(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cread_4(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CREAD_4(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CREAD_4(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cread_8(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CREAD_8(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CREAD_8(hbthr, a);
 }
 
 static VG_REGPARM(2)
 void evh__mem_help_cread_N(Addr a, SizeT size) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CREAD_N(hbthr, a, size);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CREAD_N(hbthr, a, size);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cwrite_1(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CWRITE_1(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CWRITE_1(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cwrite_2(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CWRITE_2(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CWRITE_2(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cwrite_4(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CWRITE_4(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CWRITE_4(hbthr, a);
 }
 
 static VG_REGPARM(1)
 void evh__mem_help_cwrite_8(Addr a) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CWRITE_8(hbthr, a);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CWRITE_8(hbthr, a);
 }
 
 static VG_REGPARM(2)
 void evh__mem_help_cwrite_N(Addr a, SizeT size) {
    Thread*  thr = get_current_Thread_in_C_C();
    Thr*     hbthr = thr->hbthr;
-   LIBHB_CWRITE_N(hbthr, a, size);
+   if (LIKELY(thr->synchr_nesting == 0))
+      LIBHB_CWRITE_N(hbthr, a, size);
 }
 
 
@@ -3321,6 +3399,52 @@
 }
 
 
+#if defined(VGO_solaris)
+/* ----------------------------------------------------- */
+/* --- events to do with bind guard/clear intercepts --- */
+/* ----------------------------------------------------- */
+
+static
+void evh__HG_RTLD_BIND_GUARD(ThreadId tid, Int flags)
+{
+   if (SHOW_EVENTS >= 1)
+      VG_(printf)("evh__HG_RTLD_BIND_GUARD"
+                  "(tid=%d, flags=%d)\n",
+                  (Int)tid, flags);
+
+   Thread *thr = map_threads_maybe_lookup(tid);
+   tl_assert(thr != NULL);
+
+   Int bindflag = (flags & VKI_THR_FLG_RTLD);
+   if ((bindflag & thr->bind_guard_flag) == 0) {
+      thr->bind_guard_flag |= bindflag;
+      HG_(thread_enter_synchr)(thr);
+      /* Misuse pthread_create_nesting_level for ignoring mutex activity. */
+      HG_(thread_enter_pthread_create)(thr);
+   }
+}
+
+static
+void evh__HG_RTLD_BIND_CLEAR(ThreadId tid, Int flags)
+{
+   if (SHOW_EVENTS >= 1)
+      VG_(printf)("evh__HG_RTLD_BIND_CLEAR"
+                  "(tid=%d, flags=%d)\n",
+                  (Int)tid, flags);
+
+   Thread *thr = map_threads_maybe_lookup(tid);
+   tl_assert(thr != NULL);
+
+   Int bindflag = (flags & VKI_THR_FLG_RTLD);
+   if ((thr->bind_guard_flag & bindflag) != 0) {
+      thr->bind_guard_flag &= ~bindflag;
+      HG_(thread_leave_synchr)(thr);
+      HG_(thread_leave_pthread_create)(thr);
+   }
+}
+#endif /* VGO_solaris */
+
+
 /*--------------------------------------------------------------*/
 /*--- Lock acquisition order monitoring                      ---*/
 /*--------------------------------------------------------------*/
@@ -4485,6 +4609,8 @@
    if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3))  return True;
 #  elif defined(VGO_darwin)
    if (VG_STREQ(soname, VG_U_DYLD)) return True;
+#  elif defined(VGO_solaris)
+   if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
 #  else
 #    error "Unsupported OS"
 #  endif
@@ -4983,6 +5109,15 @@
          VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
                      (void*)args[1], (void*)my_thr );
          VG_(addToFM)( map_pthread_t_to_Thread, (UWord)args[1], (UWord)my_thr );
+
+         if (my_thr->coretid != 1) {
+            /* FIXME: hardwires assumption about identity of the root thread. */
+            if (HG_(clo_ignore_thread_creation)) {
+               HG_(thread_leave_pthread_create)(my_thr);
+               HG_(thread_leave_synchr)(my_thr);
+               tl_assert(my_thr->synchr_nesting == 0);
+            }
+         }
          break;
       }
 
@@ -5092,32 +5227,48 @@
          break;
 
       case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE:   // pth_mx_t*
-         evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
          break;
 
       case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST:  // pth_mx_t*
-         evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
-      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE:     // pth_mx_t*, Word
-         evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
+      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE:     // pth_mx_t*
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
          break;
 
-      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST:    // pth_mx_t*
-         evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
+      case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST:    // pth_mx_t*, long
+         if ((args[2] == True) // lock actually taken
+             && (HG_(get_pthread_create_nesting_level)(tid) == 0))
+            evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
       /* This thread is about to do pthread_cond_signal on the
          pthread_cond_t* in arg[1].  Ditto pthread_cond_broadcast. */
       case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
       case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
          evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
          break;
 
+      case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_POST:
+      case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_POST:
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
+         break;
+
       /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
          Returns a flag indicating whether or not the mutex is believed to be
          valid for this operation. */
       case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
          Bool mutex_is_valid
             = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1], 
                                                   (void*)args[2] );
@@ -5137,12 +5288,14 @@
          evh__HG_PTHREAD_COND_DESTROY_PRE( tid, (void*)args[1], args[2] != 0 );
          break;
 
-      /* Thread successfully completed pthread_cond_wait, cond=arg[1],
-         mutex=arg[2] */
+      /* Thread completed pthread_cond_wait, cond=arg[1],
+         mutex=arg[2], timeout=arg[3], successful=arg[4] */
       case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
-         evh__HG_PTHREAD_COND_WAIT_POST( tid,
-                                         (void*)args[1], (void*)args[2],
-                                         (Bool)args[3] );
+         if (args[4] == True)
+            evh__HG_PTHREAD_COND_WAIT_POST( tid,
+                                            (void*)args[1], (void*)args[2],
+                                            (Bool)args[3] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
       case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
@@ -5155,21 +5308,30 @@
 
       /* rwlock=arg[1], isW=arg[2], isTryLock=arg[3] */
       case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
-         evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
-                                               args[2], args[3] );
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
+                                             args[2], args[3] );
          break;
 
-      /* rwlock=arg[1], isW=arg[2] */
+      /* rwlock=arg[1], isW=arg[2], tookLock=arg[3] */
       case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
-         evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
+         if ((args[3] == True)
+             && (HG_(get_pthread_create_nesting_level)(tid) == 0))
+            evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
       case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
-         evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
          break;
 
       case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
-         evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
+         if (HG_(get_pthread_create_nesting_level)(tid) == 0)
+            evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
       case _VG_USERREQ__HG_POSIX_SEM_INIT_POST: /* sem_t*, unsigned long */
@@ -5181,11 +5343,22 @@
          break;
 
       case _VG_USERREQ__HG_POSIX_SEM_POST_PRE: /* sem_t* */
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
          evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
          break;
 
-      case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t* */
-         evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
+      case _VG_USERREQ__HG_POSIX_SEM_POST_POST: /* sem_t* */
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
+         break;
+
+      case _VG_USERREQ__HG_POSIX_SEM_WAIT_PRE: /* sem_t* */
+         HG_(thread_enter_synchr)(map_threads_maybe_lookup(tid));
+         break;
+
+      case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t*, long tookLock */
+         if (args[2] == True)
+            evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
+         HG_(thread_leave_synchr)(map_threads_maybe_lookup(tid));
          break;
 
       case _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE:
@@ -5273,6 +5446,58 @@
          return handled;
       }
 
+      case _VG_USERREQ__HG_PTHREAD_CREATE_BEGIN: {
+         Thread *thr = map_threads_maybe_lookup(tid);
+         if (HG_(clo_ignore_thread_creation)) {
+            HG_(thread_enter_pthread_create)(thr);
+            HG_(thread_enter_synchr)(thr);
+         }
+         break;
+      }
+
+      case _VG_USERREQ__HG_PTHREAD_CREATE_END: {
+         Thread *thr = map_threads_maybe_lookup(tid);
+         if (HG_(clo_ignore_thread_creation)) {
+            HG_(thread_leave_pthread_create)(thr);
+            HG_(thread_leave_synchr)(thr);
+         }
+         break;
+      }
+
+      case _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_PRE: // pth_mx_t*, long tryLock
+         evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
+         break;
+
+      case _VG_USERREQ__HG_PTHREAD_MUTEX_ACQUIRE_POST:    // pth_mx_t*
+         evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
+         break;
+
+      case _VG_USERREQ__HG_PTHREAD_RWLOCK_ACQUIRED:       // void*, long isW
+         evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
+         break;
+
+      case _VG_USERREQ__HG_PTHREAD_RWLOCK_RELEASED:       // void*
+         evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
+         break;
+
+      case _VG_USERREQ__HG_POSIX_SEM_RELEASED: /* sem_t* */
+         evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
+         break;
+
+      case _VG_USERREQ__HG_POSIX_SEM_ACQUIRED: /* sem_t* */
+         evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
+         break;
+
+#if defined(VGO_solaris)
+      case _VG_USERREQ__HG_RTLD_BIND_GUARD:
+         evh__HG_RTLD_BIND_GUARD(tid, args[1]);
+         break;
+
+      case _VG_USERREQ__HG_RTLD_BIND_CLEAR:
+         evh__HG_RTLD_BIND_CLEAR(tid, args[1]);
+         break;
+#endif /* VGO_solaris */
+
       default:
          /* Unhandled Helgrind client request! */
          tl_assert2(0, "unhandled Helgrind client request 0x%lx",
@@ -5339,6 +5564,8 @@
 
    else if VG_BOOL_CLO(arg, "--check-stack-refs",
                             HG_(clo_check_stack_refs)) {}
+   else if VG_BOOL_CLO(arg, "--ignore-thread-creation",
+                            HG_(clo_ignore_thread_creation)) {}
 
    else 
       return VG_(replacement_malloc_process_cmd_line_option)(arg);
@@ -5358,6 +5585,9 @@
 "    --conflict-cache-size=N   size of 'full' history cache [2000000]\n"
 "    --check-stack-refs=no|yes race-check reads and writes on the\n"
 "                              main stack and thread stacks? [yes]\n"
+"    --ignore-thread-creation=yes|no Ignore activities during thread\n"
+"                              creation [%s]\n",
+HG_(clo_ignore_thread_creation) ? "yes" : "no"
    );
 }
 
diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am
index 0528fbc..e5d8d6f 100644
--- a/helgrind/tests/Makefile.am
+++ b/helgrind/tests/Makefile.am
@@ -2,6 +2,7 @@
 include $(top_srcdir)/Makefile.tool-tests.am
 
 dist_noinst_SCRIPTS = filter_stderr   \
+		      filter_stderr_solaris \
 		      filter_helgrind \
 		      filter_xml
 
@@ -46,7 +47,8 @@
 	pth_destroy_cond.vgtest \
 		pth_destroy_cond.stdout.exp pth_destroy_cond.stderr.exp \
 	pth_cond_destroy_busy.vgtest pth_cond_destroy_busy.stderr.exp \
-	pth_cond_destroy_busy.stderr.exp-ppc64 \
+		pth_cond_destroy_busy.stderr.exp-ppc64 \
+		pth_cond_destroy_busy.stderr.exp-solaris \
 	pth_spinlock.vgtest pth_spinlock.stdout.exp pth_spinlock.stderr.exp \
 	rwlock_race.vgtest rwlock_race.stdout.exp rwlock_race.stderr.exp \
 	rwlock_test.vgtest rwlock_test.stdout.exp rwlock_test.stderr.exp \
@@ -70,12 +72,13 @@
 	tc07_hbl1.vgtest tc07_hbl1.stdout.exp tc07_hbl1.stderr.exp \
 	tc08_hbl2.vgtest tc08_hbl2.stdout.exp tc08_hbl2.stderr.exp \
 	tc09_bad_unlock.vgtest tc09_bad_unlock.stdout.exp \
-		tc09_bad_unlock.stderr.exp \
+		tc09_bad_unlock.stderr.exp tc09_bad_unlock.stderr.exp-solaris \
 	tc10_rec_lock.vgtest tc10_rec_lock.stdout.exp tc10_rec_lock.stderr.exp \
 	tc11_XCHG.vgtest tc11_XCHG.stdout.exp tc11_XCHG.stderr.exp \
 	tc12_rwl_trivial.vgtest tc12_rwl_trivial.stdout.exp \
 		tc12_rwl_trivial.stderr.exp \
 		tc12_rwl_trivial.stderr.exp-darwin970 \
+		tc12_rwl_trivial.stderr.exp-solaris \
 	tc13_laog1.vgtest tc13_laog1.stdout.exp tc13_laog1.stderr.exp \
 	tc14_laog_dinphils.vgtest tc14_laog_dinphils.stdout.exp \
 		tc14_laog_dinphils.stderr.exp \
@@ -89,6 +92,7 @@
 		tc18_semabuse.stderr.exp \
 		tc18_semabuse.stderr.exp-linux-mips32 \
 		tc18_semabuse.stderr.exp-linux-mips32-b \
+		tc18_semabuse.stderr.exp-solaris \
 	tc19_shadowmem.vgtest tc19_shadowmem.stdout.exp \
 		tc19_shadowmem.stderr.exp tc19_shadowmem.stderr.exp-mips32 \
 	tc20_verifywrap.vgtest tc20_verifywrap.stdout.exp \
@@ -97,10 +101,12 @@
 		tc20_verifywrap.stderr.exp-mips32 \
 		tc20_verifywrap.stderr.exp-mips32-b \
 		tc20_verifywrap.stderr.exp-s390x \
+		tc20_verifywrap.stderr.exp-solaris \
 	tc21_pthonce.vgtest tc21_pthonce.stdout.exp tc21_pthonce.stderr.exp \
 	tc22_exit_w_lock.vgtest tc22_exit_w_lock.stdout.exp \
 		tc22_exit_w_lock.stderr.exp \
 		tc22_exit_w_lock.stderr.exp-kfail-x86 \
+		tc22_exit_w_lock.stderr.exp-solaris \
 	tc23_bogus_condwait.vgtest tc23_bogus_condwait.stdout.exp \
 		tc23_bogus_condwait.stderr.exp \
 		tc23_bogus_condwait.stderr.exp-mips32 \
diff --git a/helgrind/tests/annotate_rwlock.c b/helgrind/tests/annotate_rwlock.c
index 8842b3c..8961f3c 100644
--- a/helgrind/tests/annotate_rwlock.c
+++ b/helgrind/tests/annotate_rwlock.c
@@ -74,7 +74,7 @@
     /* Darwin doesn't have an implementation of pthread_yield(). */
     usleep(100 * 1000);
 #else
-    pthread_yield();
+    sched_yield();
 #endif
     (void) __sync_fetch_and_sub(&p->locked, 1);
   }
@@ -99,7 +99,7 @@
     /* Darwin doesn't have an implementation of pthread_yield(). */
     usleep(100 * 1000);
 #else
-    pthread_yield();
+    sched_yield();
 #endif
     (void) __sync_fetch_and_sub(&p->locked, 1);
   }
diff --git a/helgrind/tests/filter_stderr b/helgrind/tests/filter_stderr
index 7b3003d..cfdd894 100755
--- a/helgrind/tests/filter_stderr
+++ b/helgrind/tests/filter_stderr
@@ -7,6 +7,13 @@
 # Anonymise addresses
 $dir/../../tests/filter_addresses                       |
 
+# Perform Solaris-specific filtering.
+if $dir/../../tests/os_test solaris; then
+   perl -p $dir/filter_stderr_solaris
+else
+   cat
+fi |
+
 # get rid of the numbers in bits of text "Thread #n", "thread #n",
 # "Thread n" and "thread n", "tid n"
 # as these make some tests more scheduling sensitive -- those where
@@ -19,6 +26,10 @@
 # Likewise for frame numbers, which depend on compilation.
 sed -e "s/frame #[0-9][0-9]*/frame #x/g" | \
 
+# Remove the message that more than hundred errors have been detected
+# (consists of two lines) and also the empty line above it.
+awk 'BEGIN{begin=1} {if ($0 == "More than 100 errors detected.  Subsequent errors") { getline; getline; } else { if (begin) begin = 0; else print last_line; }; last_line = $0; } END { if (! begin) print last_line; }' |
+
 # Merge sem_wait and sem_wait@*, as either could be used.  Likewise for
 # sem_post.
 sed \
diff --git a/helgrind/tests/filter_stderr_solaris b/helgrind/tests/filter_stderr_solaris
new file mode 100755
index 0000000..41d1f1e
--- /dev/null
+++ b/helgrind/tests/filter_stderr_solaris
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+# Replace pthread_create with pthread_create@* which is expected on Linux
+s/pthread_create \(hg_intercepts.c:/pthread_create@* \(hg_intercepts.c:/g;
+
+# We need to remove stack frames containing redundant function
+# names from libc, for example
+#     by 0x........: pthread_mutex_init (in /...libc...)
+my $check = join "|", ('pthread_mutex_init', 'pthread_cond_wait', 'pthread_cond_timedwait');
+s/^\s*by 0x........: (?:$check) \(in \/...libc...\)\s*//;
+
+# We also need to replace Solaris threading and sychronization function
+# names with POSIX ones for hg_intercepts.c stack frame:
+#     at 0x........: mutex_lock (hg_intercepts.c:1234)
+# See also comments in hg_intercepts.c.
+my %regex = (
+    'cond_broadcast' => 'pthread_cond_broadcast@*',
+    'cond_destroy'   => 'pthread_cond_destroy@*',
+    'cond_signal'    => 'pthread_cond_signal@*',
+    'cond_wait'      => 'pthread_cond_wait@*',
+    'cond_timedwait' => 'pthread_cond_timedwait@*',
+    'mutex_destroy'  => 'pthread_mutex_destroy',
+    'mutex_init'     => 'pthread_mutex_init',
+    'mutex_lock'     => 'pthread_mutex_lock',
+    'mutex_trylock'  => 'pthread_mutex_trylock',
+    'mutex_unlock'   => 'pthread_mutex_unlock',
+    'rwlock_init'    => 'pthread_rwlock_init',
+    'rw_unlock'      => 'pthread_rwlock_unlock'
+);
+my $check = join "|", keys %regex;
+if (! /: pthread_/ && ! /WRK/) {
+    s/($check)(.*hg_intercepts.c)/$regex{$1}$2/g;
+}
diff --git a/helgrind/tests/filter_xml b/helgrind/tests/filter_xml
index 282de5c..6de080a 100755
--- a/helgrind/tests/filter_xml
+++ b/helgrind/tests/filter_xml
@@ -39,7 +39,8 @@
     "thread #([0-9]+)"      => "x",
     "0x([0-9a-zA-Z]+)"      => "........",
     "Using Valgrind-([^\\s]*)"    => "X.Y.X",
-    "Copyright \\(C\\) ([0-9]{4}-[0-9]{4}).*" => "XXXX-YYYY"
+    "Copyright \\(C\\) ([0-9]{4}-[0-9]{4}).*" => "XXXX-YYYY",
+    '<fn>pthread_.*(@\*)</fn>'  => ""
 );
 
 # List of XML sections to be ignored.
@@ -97,7 +98,8 @@
 # Massage line by applying PATTERNS.
     foreach my $key (keys %patterns) {
         if ($line =~ $key) {
-                $line =~ s/$1/$patterns{$key}/g;
+           my $matched = quotemeta($1);
+           $line =~ s/$matched/$patterns{$key}/g;
         }
     }
 
diff --git a/helgrind/tests/hg02_deadlock.stderr.exp b/helgrind/tests/hg02_deadlock.stderr.exp
index 9ec5a8b..d9af78c 100644
--- a/helgrind/tests/hg02_deadlock.stderr.exp
+++ b/helgrind/tests/hg02_deadlock.stderr.exp
@@ -11,36 +11,42 @@
 Thread #x: lock order "0x........ before 0x........" violated
 
 Observed (incorrect) order is: acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: t2 (hg02_deadlock.c:19)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: t2 (hg02_deadlock.c:20)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
 Required order was established by acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: t1 (hg02_deadlock.c:9)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: t1 (hg02_deadlock.c:10)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
  Lock at 0x........ was first observed
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (hg02_deadlock.c:32)
  Address 0x........ is 0 bytes inside data symbol "m1"
 
  Lock at 0x........ was first observed
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: t1 (hg02_deadlock.c:10)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
diff --git a/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp b/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp
index 42ff5aa..abe7483 100644
--- a/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp
+++ b/helgrind/tests/locked_vs_unlocked1_fwd.stderr.exp
@@ -15,7 +15,8 @@
 ----------------------------------------------------------------
 
  Lock at 0x........ was first observed
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: child_fn (locked_vs_unlocked1.c:18)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
diff --git a/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp b/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp
index 4eec562..5aebd88 100644
--- a/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp
+++ b/helgrind/tests/locked_vs_unlocked1_rev.stderr.exp
@@ -15,7 +15,8 @@
 ----------------------------------------------------------------
 
  Lock at 0x........ was first observed
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: child_fn (locked_vs_unlocked1.c:18)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
diff --git a/helgrind/tests/pth_cond_destroy_busy.stderr.exp-solaris b/helgrind/tests/pth_cond_destroy_busy.stderr.exp-solaris
new file mode 100644
index 0000000..1135d4e
--- /dev/null
+++ b/helgrind/tests/pth_cond_destroy_busy.stderr.exp-solaris
@@ -0,0 +1,16 @@
+
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_destroy: destruction of condition variable being waited upon
+   at 0x........: pthread_cond_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_destroy@* (hg_intercepts.c:...)
+   by 0x........: main (pth_cond_destroy_busy.c:52)
+
+First pthread_cond_destroy() call returned success.
+Second pthread_cond_destroy() call returned success.
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc06_two_races_xml.stderr.exp b/helgrind/tests/tc06_two_races_xml.stderr.exp
index 0fd5cd4..e59809b 100644
--- a/helgrind/tests/tc06_two_races_xml.stderr.exp
+++ b/helgrind/tests/tc06_two_races_xml.stderr.exp
@@ -57,7 +57,7 @@
     <frame>
       <ip>0x........</ip>
       <obj>...</obj>
-      <fn>pthread_create@*</fn>
+      <fn>pthread_create</fn>
       <dir>...</dir>
       <file>hg_intercepts.c</file>
       <line>...</line>
diff --git a/helgrind/tests/tc07_hbl1.c b/helgrind/tests/tc07_hbl1.c
index c66b8ec..e46a405 100644
--- a/helgrind/tests/tc07_hbl1.c
+++ b/helgrind/tests/tc07_hbl1.c
@@ -17,6 +17,8 @@
 #undef PLAT_s390x_linux
 #undef PLAT_mips32_linux
 #undef PLAT_tilegx_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
 
 #if defined(__APPLE__) && defined(__i386__)
 #  define PLAT_x86_darwin 1
@@ -40,10 +42,15 @@
 #  define PLAT_mips32_linux 1
 #elif defined(__linux__) && defined(__tilegx__)
 #  define PLAT_tilegx_linux 1
+#elif defined(__sun__) && defined(__i386__)
+#  define PLAT_x86_solaris 1
+#elif defined(__sun__) && defined(__x86_64__)
+#  define PLAT_amd64_solaris 1
 #endif
 
 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
-    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin)
+    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
+    || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
 #  define INC(_lval,_lqual) \
       __asm__ __volatile__ ( \
       "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" )
diff --git a/helgrind/tests/tc08_hbl2.c b/helgrind/tests/tc08_hbl2.c
index dde93e8..c3ea44c 100644
--- a/helgrind/tests/tc08_hbl2.c
+++ b/helgrind/tests/tc08_hbl2.c
@@ -34,6 +34,8 @@
 #undef PLAT_mips32_linux
 #undef PLAT_mips64_linux
 #undef PLAT_tilegx_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
 
 #if defined(__APPLE__) && defined(__i386__)
 #  define PLAT_x86_darwin 1
@@ -61,11 +63,16 @@
 #endif
 #elif defined(__linux__) && defined(__tilegx__)
 #  define PLAT_tilegx_linux 1
+#elif defined(__sun__) && defined(__i386__)
+#  define PLAT_x86_solaris 1
+#elif defined(__sun__) && defined(__x86_64__)
+#  define PLAT_amd64_solaris 1
 #endif
 
 
 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
-    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin)
+    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
+    || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
 #  define INC(_lval,_lqual)	     \
       __asm__ __volatile__ ( \
       "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" )
diff --git a/helgrind/tests/tc09_bad_unlock.stderr.exp b/helgrind/tests/tc09_bad_unlock.stderr.exp
index bb49324..a18450b 100644
--- a/helgrind/tests/tc09_bad_unlock.stderr.exp
+++ b/helgrind/tests/tc09_bad_unlock.stderr.exp
@@ -6,7 +6,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked a not-locked lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:27)
    by 0x........: main (tc09_bad_unlock.c:49)
  Lock at 0x........ was first observed
@@ -28,7 +29,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked lock at 0x........ currently held by thread #x
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: child_fn (tc09_bad_unlock.c:11)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
@@ -43,7 +45,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:41)
    by 0x........: main (tc09_bad_unlock.c:49)
 
@@ -51,7 +54,8 @@
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:41)
    by 0x........: main (tc09_bad_unlock.c:49)
 
@@ -59,7 +63,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked a not-locked lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:27)
    by 0x........: main (tc09_bad_unlock.c:50)
  Lock at 0x........ was first observed
@@ -73,18 +78,21 @@
 ----------------------------------------------------------------
 
 Thread #x: Attempt to re-lock a non-recursive lock I already hold
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:32)
    by 0x........: main (tc09_bad_unlock.c:50)
  Lock was previously acquired
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:32)
    by 0x........: main (tc09_bad_unlock.c:49)
 
 ----------------------------------------------------------------
 
 Thread #x: Bug in libpthread: recursive write lock granted on mutex/wrlock which does not support recursion
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:32)
    by 0x........: main (tc09_bad_unlock.c:50)
 
@@ -99,7 +107,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked lock at 0x........ currently held by thread #x
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: child_fn (tc09_bad_unlock.c:11)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
@@ -114,7 +123,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:41)
    by 0x........: main (tc09_bad_unlock.c:50)
 
@@ -122,7 +132,8 @@
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc09_bad_unlock.c:41)
    by 0x........: main (tc09_bad_unlock.c:50)
 
diff --git a/helgrind/tests/tc09_bad_unlock.stderr.exp-solaris b/helgrind/tests/tc09_bad_unlock.stderr.exp-solaris
new file mode 100644
index 0000000..8baa420
--- /dev/null
+++ b/helgrind/tests/tc09_bad_unlock.stderr.exp-solaris
@@ -0,0 +1,146 @@
+
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:27)
+   by 0x........: main (tc09_bad_unlock.c:49)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_mutex_init (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:23)
+   by 0x........: main (tc09_bad_unlock.c:49)
+ Address 0x........ is on thread #x's stack
+ in frame #x, created by nearly_main (tc09_bad_unlock.c:16)
+
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+   ...
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:35)
+   by 0x........: main (tc09_bad_unlock.c:49)
+
+----------------------------------------------------------------
+
+Thread #x unlocked lock at 0x........ currently held by thread #x
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: child_fn (tc09_bad_unlock.c:11)
+   by 0x........: mythread_wrapper (hg_intercepts.c:...)
+   ...
+ Lock at 0x........ was first observed
+   at 0x........: pthread_mutex_init (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:31)
+   by 0x........: main (tc09_bad_unlock.c:49)
+ Address 0x........ is on thread #x's stack
+ in frame #x, created by nearly_main (tc09_bad_unlock.c:16)
+
+
+----------------------------------------------------------------
+
+Thread #x unlocked an invalid lock at 0x........
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:49)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:49)
+
+---------------------
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:27)
+   by 0x........: main (tc09_bad_unlock.c:50)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_mutex_init (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:23)
+   by 0x........: main (tc09_bad_unlock.c:49)
+ Address 0x........ is on thread #x's stack
+ in frame #x, created by nearly_main (tc09_bad_unlock.c:16)
+
+
+----------------------------------------------------------------
+
+Thread #x: Attempt to re-lock a non-recursive lock I already hold
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:32)
+   by 0x........: main (tc09_bad_unlock.c:50)
+ Lock was previously acquired
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:32)
+   by 0x........: main (tc09_bad_unlock.c:49)
+
+----------------------------------------------------------------
+
+Thread #x: Bug in libpthread: recursive write lock granted on mutex/wrlock which does not support recursion
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:32)
+   by 0x........: main (tc09_bad_unlock.c:50)
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+   ...
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:35)
+   by 0x........: main (tc09_bad_unlock.c:50)
+
+----------------------------------------------------------------
+
+Thread #x unlocked lock at 0x........ currently held by thread #x
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: child_fn (tc09_bad_unlock.c:11)
+   by 0x........: mythread_wrapper (hg_intercepts.c:...)
+   ...
+ Lock at 0x........ was first observed
+   at 0x........: pthread_mutex_init (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:31)
+   by 0x........: main (tc09_bad_unlock.c:49)
+ Address 0x........ is on thread #x's stack
+ in frame #x, created by nearly_main (tc09_bad_unlock.c:16)
+
+
+----------------------------------------------------------------
+
+Thread #x unlocked an invalid lock at 0x........
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:50)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: nearly_main (tc09_bad_unlock.c:41)
+   by 0x........: main (tc09_bad_unlock.c:50)
+
+----------------------------------------------------------------
+
+Thread #x: Exiting thread still holds 1 lock
+   ...
+
+
+ERROR SUMMARY: 11 errors from 11 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc10_rec_lock.stderr.exp b/helgrind/tests/tc10_rec_lock.stderr.exp
index 0f52b3f..08e9789 100644
--- a/helgrind/tests/tc10_rec_lock.stderr.exp
+++ b/helgrind/tests/tc10_rec_lock.stderr.exp
@@ -13,7 +13,8 @@
 ----------------------------------------------------------------
 
 Thread #x unlocked a not-locked lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc10_rec_lock.c:42)
    by 0x........: main (tc10_rec_lock.c:47)
  Lock at 0x........ was first observed
@@ -28,7 +29,8 @@
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 1 (EPERM: Operation not permitted)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
    by 0x........: nearly_main (tc10_rec_lock.c:42)
    by 0x........: main (tc10_rec_lock.c:47)
 
diff --git a/helgrind/tests/tc11_XCHG.c b/helgrind/tests/tc11_XCHG.c
index 481f916..30fccee 100644
--- a/helgrind/tests/tc11_XCHG.c
+++ b/helgrind/tests/tc11_XCHG.c
@@ -19,6 +19,8 @@
 #undef PLAT_s390x_linux
 #undef PLAT_mips32_linux
 #undef PLAT_tilegx_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
 
 #if defined(__APPLE__) && defined(__i386__)
 #  define PLAT_x86_darwin 1
@@ -42,11 +44,16 @@
 #  define PLAT_mips32_linux 1
 #elif defined(__linux__) && defined(__tilegx__)
 #  define PLAT_tilegx_linux 1
+#elif defined(__sun__) && defined(__i386__)
+#  define PLAT_x86_solaris 1
+#elif defined(__sun__) && defined(__x86_64__)
+#  define PLAT_amd64_solaris 1
 #endif
 
 
 #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
-    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin)
+    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
+    || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
 #  define XCHG_M_R(_addr,_lval) \
      __asm__ __volatile__( \
         "xchgl %0, %1" \
diff --git a/helgrind/tests/tc12_rwl_trivial.c b/helgrind/tests/tc12_rwl_trivial.c
index 3fd64c5..c9c8398 100644
--- a/helgrind/tests/tc12_rwl_trivial.c
+++ b/helgrind/tests/tc12_rwl_trivial.c
@@ -8,12 +8,6 @@
 #include <pthread.h>
 #include <assert.h>
 
-#if defined(VGO_darwin)
-#define OS_IS_DARWIN 1
-#else
-#define OS_IS_DARWIN 0
-#endif
-
 /* Do trivial stuff with a reader-writer lock. */
 
 int main ( void )
@@ -32,7 +26,12 @@
   r = pthread_rwlock_unlock( &rwl );      assert(r == 0);
 
   /* this should fail - lock is unowned now */
-  r = pthread_rwlock_unlock( &rwl );      assert(OS_IS_DARWIN || r == 0);
+  r = pthread_rwlock_unlock( &rwl );
+#if defined(VGO_darwin) || defined(VGO_solaris)
+  assert(r != 0);
+#else
+  assert(r == 0);
+#endif
 
   r = pthread_rwlock_destroy( &rwl );     assert(r == 0);
 
diff --git a/helgrind/tests/tc12_rwl_trivial.stderr.exp b/helgrind/tests/tc12_rwl_trivial.stderr.exp
index 361a4d6..db33a08 100644
--- a/helgrind/tests/tc12_rwl_trivial.stderr.exp
+++ b/helgrind/tests/tc12_rwl_trivial.stderr.exp
@@ -8,13 +8,13 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc12_rwl_trivial.c:35)
+   by 0x........: main (tc12_rwl_trivial.c:29)
  Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc12_rwl_trivial.c:24)
+   by 0x........: main (tc12_rwl_trivial.c:18)
  Address 0x........ is on thread #x's stack
- in frame #x, created by main (tc12_rwl_trivial.c:20)
+ in frame #x, created by main (tc12_rwl_trivial.c:14)
 
 
 
diff --git a/helgrind/tests/tc12_rwl_trivial.stderr.exp-solaris b/helgrind/tests/tc12_rwl_trivial.stderr.exp-solaris
new file mode 100644
index 0000000..aa16b57
--- /dev/null
+++ b/helgrind/tests/tc12_rwl_trivial.stderr.exp-solaris
@@ -0,0 +1,29 @@
+
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc12_rwl_trivial.c:29)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_rwlock_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc12_rwl_trivial.c:18)
+ Address 0x........ is on thread #x's stack
+ in frame #x, created by main (tc12_rwl_trivial.c:14)
+
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_rwlock_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc12_rwl_trivial.c:29)
+
+
+ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc13_laog1.stderr.exp b/helgrind/tests/tc13_laog1.stderr.exp
index 3e56f25..d865270 100644
--- a/helgrind/tests/tc13_laog1.stderr.exp
+++ b/helgrind/tests/tc13_laog1.stderr.exp
@@ -8,19 +8,23 @@
 Thread #x: lock order "0x........ before 0x........" violated
 
 Observed (incorrect) order is: acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc13_laog1.c:23)
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc13_laog1.c:24)
 
 Required order was established by acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc13_laog1.c:17)
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc13_laog1.c:18)
 
  Lock at 0x........ was first observed
diff --git a/helgrind/tests/tc14_laog_dinphils.stderr.exp b/helgrind/tests/tc14_laog_dinphils.stderr.exp
index 3bf02bf..da07ff9 100644
--- a/helgrind/tests/tc14_laog_dinphils.stderr.exp
+++ b/helgrind/tests/tc14_laog_dinphils.stderr.exp
@@ -11,13 +11,15 @@
 Thread #x: lock order "0x........ before 0x........" violated
 
 Observed (incorrect) order is: acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: dine (tc14_laog_dinphils.c:21)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: dine (tc14_laog_dinphils.c:22)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
diff --git a/helgrind/tests/tc15_laog_lockdel.stderr.exp b/helgrind/tests/tc15_laog_lockdel.stderr.exp
index 945010e..2644e37 100644
--- a/helgrind/tests/tc15_laog_lockdel.stderr.exp
+++ b/helgrind/tests/tc15_laog_lockdel.stderr.exp
@@ -10,19 +10,23 @@
 Thread #x: lock order "0x........ before 0x........" violated
 
 Observed (incorrect) order is: acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc15_laog_lockdel.c:35)
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc15_laog_lockdel.c:36)
 
 Required order was established by acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc15_laog_lockdel.c:27)
 
  followed by a later acquisition of lock at 0x........
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
    by 0x........: main (tc15_laog_lockdel.c:28)
 
  Lock at 0x........ was first observed
diff --git a/helgrind/tests/tc17_sembar.c b/helgrind/tests/tc17_sembar.c
index 7b22816..635cfcf 100644
--- a/helgrind/tests/tc17_sembar.c
+++ b/helgrind/tests/tc17_sembar.c
@@ -222,7 +222,7 @@
 {
    sem_t* s;
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
    s = malloc(sizeof(*s));
    if (s) {
       if (sem_init(s, pshared, count) < 0) {
diff --git a/helgrind/tests/tc18_semabuse.c b/helgrind/tests/tc18_semabuse.c
index 7395251..eab308c 100644
--- a/helgrind/tests/tc18_semabuse.c
+++ b/helgrind/tests/tc18_semabuse.c
@@ -32,6 +32,9 @@
      it succeeds. */
   memset(&s1, 0x55, sizeof(s1));
   r= sem_wait(&s1); /* assert(r != 0); */
+#if defined(VGO_solaris)
+  assert(r != 0);
+#endif
 
   /* this only fails with glibc 2.7 and later. */
   r= sem_post(&s1);
diff --git a/helgrind/tests/tc18_semabuse.stderr.exp b/helgrind/tests/tc18_semabuse.stderr.exp
index 95b22e7..ffeb7cd 100644
--- a/helgrind/tests/tc18_semabuse.stderr.exp
+++ b/helgrind/tests/tc18_semabuse.stderr.exp
@@ -24,7 +24,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_post_WRK (hg_intercepts.c:...)
    by 0x........: sem_post (hg_intercepts.c:...)
-   by 0x........: main (tc18_semabuse.c:37)
+   by 0x........: main (tc18_semabuse.c:40)
 
 
 ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc18_semabuse.stderr.exp-linux-mips32-b b/helgrind/tests/tc18_semabuse.stderr.exp-linux-mips32-b
index ce83a9b..4e46e5e 100644
--- a/helgrind/tests/tc18_semabuse.stderr.exp-linux-mips32-b
+++ b/helgrind/tests/tc18_semabuse.stderr.exp-linux-mips32-b
@@ -24,7 +24,7 @@
    with error code 89 (ENOSYS: Function not implemented)
    at 0x........: sem_post_WRK (hg_intercepts.c:...)
    by 0x........: sem_post (hg_intercepts.c:...)
-   by 0x........: main (tc18_semabuse.c:37)
+   by 0x........: main (tc18_semabuse.c:40)
 
 
 ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc18_semabuse.stderr.exp-solaris b/helgrind/tests/tc18_semabuse.stderr.exp-solaris
new file mode 100644
index 0000000..2f74eb8
--- /dev/null
+++ b/helgrind/tests/tc18_semabuse.stderr.exp-solaris
@@ -0,0 +1,15 @@
+
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x's call to sema_init failed
+   with error code 22 (EINVAL: Invalid argument)
+   at 0x........: sema_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc18_semabuse.c:23)
+
+
+ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc19_shadowmem.stderr.exp b/helgrind/tests/tc19_shadowmem.stderr.exp
index c113ed6..e5fab6a 100644
--- a/helgrind/tests/tc19_shadowmem.stderr.exp
+++ b/helgrind/tests/tc19_shadowmem.stderr.exp
@@ -3513,9 +3513,6 @@
    by 0x........: main (tc19_shadowmem.c:144)
  Block was alloc'd by thread #x
 
-
-More than 100 errors detected.  Subsequent errors
-will still be recorded, but in less detail than before.
 ---------- short gran, 1 .. 98, skip 1 ----------
 ---Thread-Announcement------------------------------------------
 
diff --git a/helgrind/tests/tc19_shadowmem.stderr.exp-mips32 b/helgrind/tests/tc19_shadowmem.stderr.exp-mips32
index 5d1d896..e652d68 100644
--- a/helgrind/tests/tc19_shadowmem.stderr.exp-mips32
+++ b/helgrind/tests/tc19_shadowmem.stderr.exp-mips32
@@ -3709,9 +3709,6 @@
    at 0x........: malloc (vg_replace_malloc.c:...)
    by 0x........: main (tc19_shadowmem.c:144)
 
-
-More than 100 errors detected.  Subsequent errors
-will still be recorded, but in less detail than before.
 ---------- short gran, 1 .. 98, skip 1 ----------
 ---Thread-Announcement------------------------------------------
 
diff --git a/helgrind/tests/tc20_verifywrap.c b/helgrind/tests/tc20_verifywrap.c
index 8718d0b..899a285 100644
--- a/helgrind/tests/tc20_verifywrap.c
+++ b/helgrind/tests/tc20_verifywrap.c
@@ -20,9 +20,14 @@
 
 #if !defined(__APPLE__)
 
+#if defined(__sun__)
+/* Fake __GLIBC_PREREQ on Solaris. Pretend glibc >= 2.4. */
+# define __GLIBC_PREREQ
+#else
 #if !defined(__GLIBC_PREREQ)
 # error "This program needs __GLIBC_PREREQ (in /usr/include/features.h)"
 #endif
+#endif /* __sun__ */
 
 short unprotected = 0;
 
@@ -88,7 +93,12 @@
    "\n---------------- pthread_mutex_lock et al ----------------\n\n");
 
    /* make pthread_mutex_init fail */
+#if defined(__sun__)
+   pthread_mutexattr_init( &mxa );
+   memset( mxa.__pthread_mutexattrp, 0xFF, 5 * sizeof(int) );
+#else
    memset( &mxa, 0xFF, sizeof(mxa) );
+#endif
    r= pthread_mutex_init( &mx, &mxa );
 #  if __GLIBC_PREREQ(2,4)
    assert(r); /* glibc >= 2.4: the call should fail */
@@ -193,7 +203,12 @@
    r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
    /* unlock it again, get an error */
    fprintf(stderr, "(3)    ERROR on next line\n");
-   r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+   r= pthread_rwlock_unlock( &rwl2 );
+#if defined(__sun__)
+   assert(r);
+#else
+   assert(!r);
+#endif
 
    /* same game with r-locks */
    r= pthread_rwlock_init( &rwl2, NULL ); assert(!r);
@@ -209,7 +224,12 @@
    r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
    /* unlock it again, get an error */
    fprintf(stderr, "(8)    ERROR on next line\n");
-   r= pthread_rwlock_unlock( &rwl2 ); assert(!r);
+   r= pthread_rwlock_unlock( &rwl2 );
+#if defined(__sun__)
+   assert(r);
+#else
+   assert(!r);
+#endif
 
    /* Lock rwl3 so the locked-lock-at-dealloc check can complain about
       it. */
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp b/helgrind/tests/tc20_verifywrap.stderr.exp
index 4d9f4c4..97c09f4 100644
--- a/helgrind/tests/tc20_verifywrap.stderr.exp
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp
@@ -14,21 +14,21 @@
 Thread #x was created
    ...
    by 0x........: pthread_create@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:76)
+   by 0x........: main (tc20_verifywrap.c:81)
 
 ----------------------------------------------------------------
 
 Possible data race during write of size 2 at 0x........ by thread #x
 Locks held: none
-   at 0x........: main (tc20_verifywrap.c:78)
+   at 0x........: main (tc20_verifywrap.c:83)
 
 This conflicts with a previous write of size 2 by thread #x
 Locks held: none
-   at 0x........: racy_child (tc20_verifywrap.c:34)
+   at 0x........: racy_child (tc20_verifywrap.c:39)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
  Location 0x........ is 0 bytes inside global var "unprotected"
- declared at tc20_verifywrap.c:27
+ declared at tc20_verifywrap.c:32
 
 ----------------------------------------------------------------
 
@@ -36,7 +36,7 @@
    with error code 35 (EDEADLK: Resource deadlock would occur)
    at 0x........: pthread_join_WRK (hg_intercepts.c:...)
    by 0x........: pthread_join (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:83)
+   by 0x........: main (tc20_verifywrap.c:88)
 
 
 ---------------- pthread_mutex_lock et al ----------------
@@ -46,54 +46,61 @@
 Thread #x's call to pthread_mutex_init failed
    with error code 95 (EOPNOTSUPP: Operation not supported on transport endpoint)
    at 0x........: pthread_mutex_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:92)
+   by 0x........: main (tc20_verifywrap.c:102)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_mutex_destroy of a locked mutex
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_destroy failed
    with error code 16 (EBUSY: Device or resource busy)
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_lock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:108)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_trylock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:116)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_timedlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:121)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
 
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 
 ---------------- pthread_cond_wait et al ----------------
@@ -103,7 +110,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
@@ -111,14 +118,14 @@
    with error code 1 (EPERM: Operation not permitted)
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:152)
+   by 0x........: main (tc20_verifywrap.c:162)
 
 
 FIXME: can't figure out how to verify wrap of pthread_cond_signal
@@ -128,7 +135,7 @@
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:158)
+   by 0x........: main (tc20_verifywrap.c:168)
 
 
 FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
@@ -138,7 +145,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 ----------------------------------------------------------------
 
@@ -146,7 +153,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 
 ---------------- pthread_rwlock_* ----------------
@@ -156,13 +163,13 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:179)
+   by 0x........: main (tc20_verifywrap.c:189)
  Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:178)
+   by 0x........: main (tc20_verifywrap.c:188)
  Location 0x........ is 0 bytes inside local var "rwl"
- declared at tc20_verifywrap.c:47, in frame #x of thread x
+ declared at tc20_verifywrap.c:52, in frame #x of thread x
 
 
 (1) no error on next line
@@ -173,13 +180,13 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:196)
+   by 0x........: main (tc20_verifywrap.c:206)
  Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
  Location 0x........ is 0 bytes inside local var "rwl2"
- declared at tc20_verifywrap.c:48, in frame #x of thread x
+ declared at tc20_verifywrap.c:53, in frame #x of thread x
 
 
 (4) no error on next line
@@ -192,13 +199,13 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:212)
+   by 0x........: main (tc20_verifywrap.c:227)
  Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
  Location 0x........ is 0 bytes inside local var "rwl2"
- declared at tc20_verifywrap.c:48, in frame #x of thread x
+ declared at tc20_verifywrap.c:53, in frame #x of thread x
 
 
 
@@ -210,7 +217,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_init_WRK (hg_intercepts.c:...)
    by 0x........: sem_init@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:228)
+   by 0x........: main (tc20_verifywrap.c:248)
 
 
 FIXME: can't figure out how to verify wrap of sem_destroy
@@ -220,7 +227,7 @@
 Thread #x: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
    at 0x........: sem_wait_WRK (hg_intercepts.c:...)
    by 0x........: sem_wait (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:242)
+   by 0x........: main (tc20_verifywrap.c:262)
 
 ----------------------------------------------------------------
 
@@ -228,7 +235,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_post_WRK (hg_intercepts.c:...)
    by 0x........: sem_post (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:245)
+   by 0x........: main (tc20_verifywrap.c:265)
 
 
 FIXME: can't figure out how to verify wrap of sem_post
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc-2.18 b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc-2.18
index 7df3fa1..8869b71 100644
--- a/helgrind/tests/tc20_verifywrap.stderr.exp-glibc-2.18
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp-glibc-2.18
@@ -14,21 +14,21 @@
 Thread #x was created
    ...
    by 0x........: pthread_create@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:76)
+   by 0x........: main (tc20_verifywrap.c:81)
 
 ----------------------------------------------------------------
 
 Possible data race during write of size 2 at 0x........ by thread #x
 Locks held: none
-   at 0x........: main (tc20_verifywrap.c:78)
+   at 0x........: main (tc20_verifywrap.c:83)
 
 This conflicts with a previous write of size 2 by thread #x
 Locks held: none
-   at 0x........: racy_child (tc20_verifywrap.c:34)
+   at 0x........: racy_child (tc20_verifywrap.c:39)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
  Location 0x........ is 0 bytes inside global var "unprotected"
- declared at tc20_verifywrap.c:27
+ declared at tc20_verifywrap.c:32
 
 ----------------------------------------------------------------
 
@@ -36,7 +36,7 @@
    with error code 35 (EDEADLK: Resource deadlock would occur)
    at 0x........: pthread_join_WRK (hg_intercepts.c:...)
    by 0x........: pthread_join (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:83)
+   by 0x........: main (tc20_verifywrap.c:88)
 
 
 ---------------- pthread_mutex_lock et al ----------------
@@ -46,47 +46,53 @@
 Thread #x's call to pthread_mutex_init failed
    with error code 95 (EOPNOTSUPP: Operation not supported on transport endpoint)
    at 0x........: pthread_mutex_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:92)
+   by 0x........: main (tc20_verifywrap.c:102)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_mutex_destroy of a locked mutex
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_lock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:108)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_trylock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:116)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_timedlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:121)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
 
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 
 ---------------- pthread_cond_wait et al ----------------
@@ -96,7 +102,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
@@ -104,14 +110,14 @@
    with error code 1 (EPERM: Operation not permitted)
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:152)
+   by 0x........: main (tc20_verifywrap.c:162)
 
 
 FIXME: can't figure out how to verify wrap of pthread_cond_signal
@@ -121,7 +127,7 @@
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:158)
+   by 0x........: main (tc20_verifywrap.c:168)
 
 
 FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
@@ -131,7 +137,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 ----------------------------------------------------------------
 
@@ -139,7 +145,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 
 ---------------- pthread_rwlock_* ----------------
@@ -149,11 +155,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:179)
+   by 0x........: main (tc20_verifywrap.c:189)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:178)
+   by 0x........: main (tc20_verifywrap.c:188)
 
 (1) no error on next line
 (2) no error on next line
@@ -163,11 +169,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:196)
+   by 0x........: main (tc20_verifywrap.c:206)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 (4) no error on next line
 (5) no error on next line
@@ -179,11 +185,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:212)
+   by 0x........: main (tc20_verifywrap.c:227)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 
 ---------------- sem_* ----------------
@@ -194,7 +200,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_init_WRK (hg_intercepts.c:...)
    by 0x........: sem_init@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:228)
+   by 0x........: main (tc20_verifywrap.c:243)
 
 
 FIXME: can't figure out how to verify wrap of sem_destroy
@@ -204,7 +210,7 @@
 Thread #x: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
    at 0x........: sem_wait_WRK (hg_intercepts.c:...)
    by 0x........: sem_wait (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:242)
+   by 0x........: main (tc20_verifywrap.c:257)
 
 ----------------------------------------------------------------
 
@@ -212,7 +218,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_post_WRK (hg_intercepts.c:...)
    by 0x........: sem_post (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:245)
+   by 0x........: main (tc20_verifywrap.c:260)
 
 
 FIXME: can't figure out how to verify wrap of sem_post
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-mips32 b/helgrind/tests/tc20_verifywrap.stderr.exp-mips32
index 8628498..e0e587b 100644
--- a/helgrind/tests/tc20_verifywrap.stderr.exp-mips32
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp-mips32
@@ -15,22 +15,22 @@
    ...
    by 0x........: pthread_create_WRK (hg_intercepts.c:...)
    by 0x........: pthread_create@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:76)
+   by 0x........: main (tc20_verifywrap.c:81)
 
 ----------------------------------------------------------------
 
 Possible data race during write of size 2 at 0x........ by thread #x
 Locks held: none
-   at 0x........: main (tc20_verifywrap.c:78)
+   at 0x........: main (tc20_verifywrap.c:83)
 
 This conflicts with a previous write of size 2 by thread #x
 Locks held: none
-   at 0x........: racy_child (tc20_verifywrap.c:34)
+   at 0x........: racy_child (tc20_verifywrap.c:39)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
 Location 0x........ is 0 bytes inside global var "unprotected"
-declared at tc20_verifywrap.c:27
+declared at tc20_verifywrap.c:32
 
 ----------------------------------------------------------------
 
@@ -38,7 +38,7 @@
    with error code 45 (EDEADLK: Resource deadlock would occur)
    at 0x........: pthread_join_WRK (hg_intercepts.c:...)
    by 0x........: pthread_join (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:83)
+   by 0x........: main (tc20_verifywrap.c:88)
 
 
 ---------------- pthread_mutex_lock et al ----------------
@@ -48,54 +48,61 @@
 Thread #x's call to pthread_mutex_init failed
    with error code 122 (EOPNOTSUPP: Operation not supported on transport endpoint)
    at 0x........: pthread_mutex_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:92)
+   by 0x........: main (tc20_verifywrap.c:102)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_mutex_destroy of a locked mutex
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_destroy failed
    with error code 16 (EBUSY: Device or resource busy)
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_lock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:108)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_trylock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:116)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_timedlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:121)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
 
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 
 ---------------- pthread_cond_wait et al ----------------
@@ -105,7 +112,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
@@ -113,14 +120,14 @@
    with error code 1 (EPERM: Operation not permitted)
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:152)
+   by 0x........: main (tc20_verifywrap.c:162)
 
 
 FIXME: can't figure out how to verify wrap of pthread_cond_signal
@@ -130,7 +137,7 @@
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:158)
+   by 0x........: main (tc20_verifywrap.c:168)
 
 
 FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
@@ -140,7 +147,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 ----------------------------------------------------------------
 
@@ -148,7 +155,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 
 ---------------- pthread_rwlock_* ----------------
@@ -158,11 +165,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:179)
+   by 0x........: main (tc20_verifywrap.c:189)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:178)
+   by 0x........: main (tc20_verifywrap.c:188)
 
 (1) no error on next line
 (2) no error on next line
@@ -172,11 +179,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:196)
+   by 0x........: main (tc20_verifywrap.c:206)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 (4) no error on next line
 (5) no error on next line
@@ -188,11 +195,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:212)
+   by 0x........: main (tc20_verifywrap.c:227)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 
 ---------------- sem_* ----------------
@@ -203,7 +210,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_init_WRK (hg_intercepts.c:...)
    by 0x........: sem_init@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:228)
+   by 0x........: main (tc20_verifywrap.c:243)
 
 
 FIXME: can't figure out how to verify wrap of sem_destroy
@@ -213,7 +220,7 @@
 Thread #x: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
    at 0x........: sem_wait_WRK (hg_intercepts.c:...)
    by 0x........: sem_wait (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:242)
+   by 0x........: main (tc20_verifywrap.c:257)
 
 
 FIXME: can't figure out how to verify wrap of sem_post
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-mips32-b b/helgrind/tests/tc20_verifywrap.stderr.exp-mips32-b
index 2a44528..01ccd00 100644
--- a/helgrind/tests/tc20_verifywrap.stderr.exp-mips32-b
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp-mips32-b
@@ -15,22 +15,22 @@
    ...
    by 0x........: pthread_create_WRK (hg_intercepts.c:...)
    by 0x........: pthread_create@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:76)
+   by 0x........: main (tc20_verifywrap.c:81)
 
 ----------------------------------------------------------------
 
 Possible data race during write of size 2 at 0x........ by thread #x
 Locks held: none
-   at 0x........: main (tc20_verifywrap.c:78)
+   at 0x........: main (tc20_verifywrap.c:83)
 
 This conflicts with a previous write of size 2 by thread #x
 Locks held: none
-   at 0x........: racy_child (tc20_verifywrap.c:34)
+   at 0x........: racy_child (tc20_verifywrap.c:39)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
 Location 0x........ is 0 bytes inside global var "unprotected"
-declared at tc20_verifywrap.c:27
+declared at tc20_verifywrap.c:32
 
 ----------------------------------------------------------------
 
@@ -38,7 +38,7 @@
    with error code 45 (EDEADLK: Resource deadlock would occur)
    at 0x........: pthread_join_WRK (hg_intercepts.c:...)
    by 0x........: pthread_join (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:83)
+   by 0x........: main (tc20_verifywrap.c:88)
 
 
 ---------------- pthread_mutex_lock et al ----------------
@@ -48,54 +48,61 @@
 Thread #x's call to pthread_mutex_init failed
    with error code 122 (EOPNOTSUPP: Operation not supported on transport endpoint)
    at 0x........: pthread_mutex_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:92)
+   by 0x........: main (tc20_verifywrap.c:102)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_mutex_destroy of a locked mutex
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_destroy failed
    with error code 16 (EBUSY: Device or resource busy)
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_lock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:108)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_trylock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:116)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_timedlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:121)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
 
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 
 ---------------- pthread_cond_wait et al ----------------
@@ -105,7 +112,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
@@ -113,14 +120,14 @@
    with error code 1 (EPERM: Operation not permitted)
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:152)
+   by 0x........: main (tc20_verifywrap.c:162)
 
 
 FIXME: can't figure out how to verify wrap of pthread_cond_signal
@@ -130,7 +137,7 @@
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:158)
+   by 0x........: main (tc20_verifywrap.c:168)
 
 
 FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
@@ -140,7 +147,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 ----------------------------------------------------------------
 
@@ -148,7 +155,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 
 ---------------- pthread_rwlock_* ----------------
@@ -158,11 +165,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:179)
+   by 0x........: main (tc20_verifywrap.c:189)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:178)
+   by 0x........: main (tc20_verifywrap.c:188)
 
 (1) no error on next line
 (2) no error on next line
@@ -172,11 +179,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:196)
+   by 0x........: main (tc20_verifywrap.c:206)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 (4) no error on next line
 (5) no error on next line
@@ -188,11 +195,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:212)
+   by 0x........: main (tc20_verifywrap.c:227)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 
 ---------------- sem_* ----------------
@@ -203,7 +210,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_init_WRK (hg_intercepts.c:...)
    by 0x........: sem_init@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:228)
+   by 0x........: main (tc20_verifywrap.c:243)
 
 
 FIXME: can't figure out how to verify wrap of sem_destroy
@@ -213,7 +220,7 @@
 Thread #x: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
    at 0x........: sem_wait_WRK (hg_intercepts.c:...)
    by 0x........: sem_wait (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:242)
+   by 0x........: main (tc20_verifywrap.c:257)
 
 ----------------------------------------------------------------
 
@@ -221,7 +228,7 @@
    with error code 89 (ENOSYS: Function not implemented)
    at 0x........: sem_post_WRK (hg_intercepts.c:...)
    by 0x........: sem_post (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:245)
+   by 0x........: main (tc20_verifywrap.c:260)
 
 
 FIXME: can't figure out how to verify wrap of sem_post
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-s390x b/helgrind/tests/tc20_verifywrap.stderr.exp-s390x
index a717d99..d510cdd 100644
--- a/helgrind/tests/tc20_verifywrap.stderr.exp-s390x
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp-s390x
@@ -15,22 +15,22 @@
    ...
    by 0x........: pthread_create_WRK (hg_intercepts.c:...)
    by 0x........: pthread_create@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:76)
+   by 0x........: main (tc20_verifywrap.c:81)
 
 ----------------------------------------------------------------
 
 Possible data race during write of size 2 at 0x........ by thread #x
 Locks held: none
-   at 0x........: main (tc20_verifywrap.c:78)
+   at 0x........: main (tc20_verifywrap.c:83)
 
 This conflicts with a previous write of size 2 by thread #x
 Locks held: none
-   at 0x........: racy_child (tc20_verifywrap.c:34)
+   at 0x........: racy_child (tc20_verifywrap.c:39)
    by 0x........: mythread_wrapper (hg_intercepts.c:...)
    ...
 
 Location 0x........ is 0 bytes inside global var "unprotected"
-declared at tc20_verifywrap.c:27
+declared at tc20_verifywrap.c:32
 
 ----------------------------------------------------------------
 
@@ -38,7 +38,7 @@
    with error code 35 (EDEADLK: Resource deadlock would occur)
    at 0x........: pthread_join_WRK (hg_intercepts.c:...)
    by 0x........: pthread_join (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:83)
+   by 0x........: main (tc20_verifywrap.c:88)
 
 
 ---------------- pthread_mutex_lock et al ----------------
@@ -48,54 +48,61 @@
 Thread #x's call to pthread_mutex_init failed
    with error code 95 (EOPNOTSUPP: Operation not supported on transport endpoint)
    at 0x........: pthread_mutex_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:92)
+   by 0x........: main (tc20_verifywrap.c:102)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_mutex_destroy of a locked mutex
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_destroy failed
    with error code 16 (EBUSY: Device or resource busy)
-   at 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:102)
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_lock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_lock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:108)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_trylock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:116)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_timedlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:121)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
 
 ----------------------------------------------------------------
 
 Thread #x unlocked an invalid lock at 0x........
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 ----------------------------------------------------------------
 
 Thread #x's call to pthread_mutex_unlock failed
    with error code 22 (EINVAL: Invalid argument)
-   at 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:125)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
 
 
 ---------------- pthread_cond_wait et al ----------------
@@ -105,7 +112,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
@@ -113,14 +120,14 @@
    with error code 1 (EPERM: Operation not permitted)
    at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:147)
+   by 0x........: main (tc20_verifywrap.c:157)
 
 ----------------------------------------------------------------
 
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:152)
+   by 0x........: main (tc20_verifywrap.c:162)
 
 
 FIXME: can't figure out how to verify wrap of pthread_cond_signal
@@ -130,7 +137,7 @@
 Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
    at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:158)
+   by 0x........: main (tc20_verifywrap.c:168)
 
 
 FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
@@ -140,7 +147,7 @@
 Thread #x: pthread_cond_{timed}wait called with un-held mutex
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 ----------------------------------------------------------------
 
@@ -148,7 +155,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
    by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:165)
+   by 0x........: main (tc20_verifywrap.c:175)
 
 
 ---------------- pthread_rwlock_* ----------------
@@ -158,11 +165,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:179)
+   by 0x........: main (tc20_verifywrap.c:189)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:178)
+   by 0x........: main (tc20_verifywrap.c:188)
 
 (1) no error on next line
 (2) no error on next line
@@ -172,11 +179,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:196)
+   by 0x........: main (tc20_verifywrap.c:206)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 (4) no error on next line
 (5) no error on next line
@@ -188,11 +195,11 @@
 Thread #x unlocked a not-locked lock at 0x........
    at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:212)
+   by 0x........: main (tc20_verifywrap.c:227)
   Lock at 0x........ was first observed
    at 0x........: pthread_rwlock_init_WRK (hg_intercepts.c:...)
    by 0x........: pthread_rwlock_init (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:186)
+   by 0x........: main (tc20_verifywrap.c:196)
 
 
 ---------------- sem_* ----------------
@@ -203,7 +210,7 @@
    with error code 22 (EINVAL: Invalid argument)
    at 0x........: sem_init_WRK (hg_intercepts.c:...)
    by 0x........: sem_init@* (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:228)
+   by 0x........: main (tc20_verifywrap.c:243)
 
 
 FIXME: can't figure out how to verify wrap of sem_destroy
@@ -213,7 +220,7 @@
 Thread #x: Bug in libpthread: sem_wait succeeded on semaphore without prior sem_post
    at 0x........: sem_wait_WRK (hg_intercepts.c:...)
    by 0x........: sem_wait (hg_intercepts.c:...)
-   by 0x........: main (tc20_verifywrap.c:242)
+   by 0x........: main (tc20_verifywrap.c:257)
 
 
 FIXME: can't figure out how to verify wrap of sem_post
diff --git a/helgrind/tests/tc20_verifywrap.stderr.exp-solaris b/helgrind/tests/tc20_verifywrap.stderr.exp-solaris
new file mode 100644
index 0000000..b869be7
--- /dev/null
+++ b/helgrind/tests/tc20_verifywrap.stderr.exp-solaris
@@ -0,0 +1,253 @@
+
+
+
+------ This is output for >= glibc 2.4 ------
+
+---------------- pthread_create/join ----------------
+
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+   ...
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:81)
+
+----------------------------------------------------------------
+
+Possible data race during write of size 2 at 0x........ by thread #x
+Locks held: none
+   at 0x........: main (tc20_verifywrap.c:83)
+
+This conflicts with a previous write of size 2 by thread #x
+Locks held: none
+   at 0x........: racy_child (tc20_verifywrap.c:39)
+   by 0x........: mythread_wrapper (hg_intercepts.c:...)
+   ...
+ Location 0x........ is 0 bytes inside global var "unprotected"
+ declared at tc20_verifywrap.c:32
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_join failed
+   with error code 45 (EDEADLK: Resource deadlock would occur)
+   at 0x........: pthread_join_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_join (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:88)
+
+
+---------------- pthread_mutex_lock et al ----------------
+
+----------------------------------------------------------------
+
+Thread #x's call to mutex_init failed
+   with error code 22 (EINVAL: Invalid argument)
+   at 0x........: pthread_mutex_init (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:102)
+
+----------------------------------------------------------------
+
+Thread #x: pthread_mutex_destroy of a locked mutex
+   at 0x........: mutex_destroy_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_destroy (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:112)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_lock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_lock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_lock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:118)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_trylock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_trylock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_trylock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:126)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_timedlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_timedlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_timedlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:131)
+
+----------------------------------------------------------------
+
+Thread #x unlocked an invalid lock at 0x........
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_mutex_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: mutex_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_mutex_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:135)
+
+
+---------------- pthread_cond_wait et al ----------------
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{timed}wait called with un-held mutex
+   at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:157)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_cond_wait failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_cond_wait_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_wait@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:157)
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
+   at 0x........: pthread_cond_signal_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_signal@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:162)
+
+
+FIXME: can't figure out how to verify wrap of pthread_cond_signal
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{signal,broadcast}: dubious: associated lock is not held by any thread
+   at 0x........: pthread_cond_broadcast_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_broadcast@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:168)
+
+
+FIXME: can't figure out how to verify wrap of pthread_broadcast_signal
+
+----------------------------------------------------------------
+
+Thread #x: pthread_cond_{timed}wait called with un-held mutex
+   at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:175)
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_cond_timedwait failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_cond_timedwait_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_cond_timedwait@* (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:175)
+
+
+---------------- pthread_rwlock_* ----------------
+
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:189)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_rwlock_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc20_verifywrap.c:188)
+ Location 0x........ is 0 bytes inside rwl.__pthread_rwlock_readers,
+ declared at tc20_verifywrap.c:52, in frame #x of thread x
+
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_rwlock_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:189)
+
+(1) no error on next line
+(2) no error on next line
+(3)    ERROR on next line
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:206)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_rwlock_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc20_verifywrap.c:196)
+ Location 0x........ is 0 bytes inside rwl2.__pthread_rwlock_readers,
+ declared at tc20_verifywrap.c:53, in frame #x of thread x
+
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_rwlock_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:206)
+
+(4) no error on next line
+(5) no error on next line
+(6) no error on next line
+(7) no error on next line
+(8)    ERROR on next line
+----------------------------------------------------------------
+
+Thread #x unlocked a not-locked lock at 0x........
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:227)
+ Lock at 0x........ was first observed
+   at 0x........: pthread_rwlock_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc20_verifywrap.c:196)
+ Location 0x........ is 0 bytes inside rwl2.__pthread_rwlock_readers,
+ declared at tc20_verifywrap.c:53, in frame #x of thread x
+
+
+----------------------------------------------------------------
+
+Thread #x's call to pthread_rwlock_unlock failed
+   with error code 1 (EPERM: Operation not permitted)
+   at 0x........: pthread_rwlock_unlock_WRK (hg_intercepts.c:...)
+   by 0x........: pthread_rwlock_unlock (hg_intercepts.c:...)
+   by 0x........: main (tc20_verifywrap.c:227)
+
+
+---------------- sem_* ----------------
+
+----------------------------------------------------------------
+
+Thread #x's call to sema_init failed
+   with error code 22 (EINVAL: Invalid argument)
+   at 0x........: sema_init (hg_intercepts.c:...)
+   ...
+   by 0x........: main (tc20_verifywrap.c:248)
+
+
+FIXME: can't figure out how to verify wrap of sem_destroy
+
+
+FIXME: can't figure out how to verify wrap of sem_post
+
+
+------------ dealloc of mem holding locks ------------
+
+----------------------------------------------------------------
+
+Thread #x: Exiting thread still holds 1 lock
+   ...
+
+
+ERROR SUMMARY: 23 errors from 23 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc22_exit_w_lock.stderr.exp-solaris b/helgrind/tests/tc22_exit_w_lock.stderr.exp-solaris
new file mode 100644
index 0000000..7c1256e
--- /dev/null
+++ b/helgrind/tests/tc22_exit_w_lock.stderr.exp-solaris
@@ -0,0 +1,39 @@
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+   ...
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
+   by 0x........: main (tc22_exit_w_lock.c:39)
+
+----------------------------------------------------------------
+
+Thread #x: Exiting thread still holds 2 locks
+   ...
+
+---Thread-Announcement------------------------------------------
+
+Thread #x was created
+   ...
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
+   by 0x........: main (tc22_exit_w_lock.c:42)
+
+----------------------------------------------------------------
+
+Thread #x: Exiting thread still holds 1 lock
+   ...
+
+
+Process terminating with default action of signal 6 (SIGABRT)
+   ...
+---Thread-Announcement------------------------------------------
+
+Thread #x is the program's root thread
+
+----------------------------------------------------------------
+
+Thread #x: Exiting thread still holds 1 lock
+   ...
+
+
+ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
diff --git a/helgrind/tests/tc23_bogus_condwait.c b/helgrind/tests/tc23_bogus_condwait.c
index 6e39768..0a1b5f3 100644
--- a/helgrind/tests/tc23_bogus_condwait.c
+++ b/helgrind/tests/tc23_bogus_condwait.c
@@ -98,7 +98,7 @@
 {
    sem_t* s;
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
    s = malloc(sizeof(*s));
    if (s) {
       if (sem_init(s, pshared, count) < 0) {
diff --git a/helgrind/tests/tc24_nonzero_sem.c b/helgrind/tests/tc24_nonzero_sem.c
index 5e990f5..bcd467c 100644
--- a/helgrind/tests/tc24_nonzero_sem.c
+++ b/helgrind/tests/tc24_nonzero_sem.c
@@ -50,7 +50,7 @@
 {
    sem_t* s;
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
    s = malloc(sizeof(*s));
    if (s) {
       if (sem_init(s, pshared, count) < 0) {
diff --git a/include/Makefile.am b/include/Makefile.am
index 9e5d2b4..e7c3e25 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -46,6 +46,8 @@
 	valgrind.h			\
 	vki/vki-linux.h			\
 	vki/vki-darwin.h		\
+	vki/vki-solaris.h		\
+	vki/vki-solaris-repcache.h	\
 	vki/vki-posixtypes-amd64-linux.h \
 	vki/vki-posixtypes-arm64-linux.h \
 	vki/vki-posixtypes-ppc32-linux.h \
@@ -74,6 +76,7 @@
 	vki/vki-scnums-mips32-linux.h	\
 	vki/vki-scnums-mips64-linux.h	\
 	vki/vki-scnums-darwin.h         \
+	vki/vki-scnums-solaris.h	\
 	vki/vki-xen.h                   \
 	vki/vki-xen-domctl.h		\
 	vki/vki-xen-evtchn.h		\
diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h
index 82d1390..763f685 100644
--- a/include/pub_tool_basics.h
+++ b/include/pub_tool_basics.h
@@ -102,7 +102,7 @@
 // used in those cases.
 // Nb: on Linux, off_t is a signed word-sized int.  On Darwin it's
 // always a signed 64-bit int.  So we defined our own Off64T as well.
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 typedef Word                   OffT;      // 32             64
 #elif defined(VGO_darwin)
 typedef Long                   OffT;      // 64             64
@@ -157,6 +157,12 @@
          userspace, but we have to record it, so that we can correctly
          update both {R,E}DX and {R,E}AX (in guest state) given a SysRes,
          if we're required to.
+
+   Solaris:
+      When _isError == False,
+         _val and _val2 hold the return value.
+      When _isError == True,
+         _val holds the error code.
 */
 #if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
 typedef
@@ -193,6 +199,15 @@
    }
    SysRes;
 
+#elif defined(VGO_solaris)
+typedef
+   struct {
+      UWord _val;
+      UWord _val2;
+      Bool  _isError;
+   }
+   SysRes;
+
 #else
 #  error "Unknown OS"
 #endif
@@ -316,6 +331,27 @@
           && sr1._wLO == sr2._wLO && sr1._wHI == sr2._wHI;
 }
 
+#elif defined(VGO_solaris)
+
+static inline Bool sr_isError ( SysRes sr ) {
+   return sr._isError;
+}
+static inline UWord sr_Res ( SysRes sr ) {
+   return sr._isError ? 0 : sr._val;
+}
+static inline UWord sr_ResHI ( SysRes sr ) {
+   return sr._isError ? 0 : sr._val2;
+}
+static inline UWord sr_Err ( SysRes sr ) {
+   return sr._isError ? sr._val : 0;
+}
+static inline Bool sr_EQ ( UInt sysno, SysRes sr1, SysRes sr2 ) {
+   /* sysno is ignored for Solaris */
+   return sr1._val == sr2._val
+       && sr1._val2 == sr2._val2
+       && sr1._isError == sr2._isError;
+}
+
 #else
 #  error "Unknown OS"
 #endif
diff --git a/include/pub_tool_basics_asm.h b/include/pub_tool_basics_asm.h
index 0173e68..2d63c47 100644
--- a/include/pub_tool_basics_asm.h
+++ b/include/pub_tool_basics_asm.h
@@ -48,7 +48,7 @@
 
 #define VGAPPEND(str1,str2) str1##str2
  
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 #  define VG_(str)    VGAPPEND( vgPlain_,          str)
 #  define ML_(str)    VGAPPEND( vgModuleLocal_,    str)
 #elif defined(VGO_darwin)
diff --git a/include/pub_tool_libcfile.h b/include/pub_tool_libcfile.h
index 3df5be5..7ebdaf6 100644
--- a/include/pub_tool_libcfile.h
+++ b/include/pub_tool_libcfile.h
@@ -93,7 +93,7 @@
 
 extern SSizeT VG_(readlink)( const HChar* path, HChar* buf, SizeT bufsiz);
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 extern Int    VG_(getdents64)( Int fd, struct vki_dirent64 *dirp, UInt count );
 #endif
 
diff --git a/include/pub_tool_libcproc.h b/include/pub_tool_libcproc.h
index 0e2afdc..f11cc74 100644
--- a/include/pub_tool_libcproc.h
+++ b/include/pub_tool_libcproc.h
@@ -51,14 +51,27 @@
 // platforms.
 extern const HChar* VG_(LD_PRELOAD_var_name);
 
+/* Resolves filename of VG_(cl_exec_fd) and copies it to the buffer. 
+   Buffer must not be NULL and buf_size must be at least 1.
+   If buffer is not large enough it is terminated with '\0' only
+   when 'terminate_with_NUL == True'. */
+extern void VG_(client_fname)(HChar *buffer, SizeT buf_size,
+                              Bool terminate_with_NUL);
+
+/* Concatenates client exename and command line arguments into
+   the buffer. Buffer must not be NULL and buf_size must be
+   at least 1. Buffer is always terminated with '\0'. */
+extern void VG_(client_cmd_and_args)(HChar *buffer, SizeT buf_size);
+
 /* ---------------------------------------------------------------------
    Important syscalls
    ------------------------------------------------------------------ */
 
 extern Int  VG_(waitpid)( Int pid, Int *status, Int options );
 extern Int  VG_(system) ( const HChar* cmd );
+extern Int  VG_(spawn)  ( const HChar *filename, const HChar **argv );
 extern Int  VG_(fork)   ( void);
-extern void VG_(execv)  ( const HChar* filename, HChar** argv );
+extern void VG_(execv)  ( const HChar* filename, const HChar** argv );
 extern Int  VG_(sysctl) ( Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen );
 
 /* ---------------------------------------------------------------------
diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h
index 1e31179..899b3e9 100644
--- a/include/pub_tool_machine.h
+++ b/include/pub_tool_machine.h
@@ -34,14 +34,14 @@
 #include "pub_tool_basics.h"           // ThreadID
 #include "libvex.h"                    // VexArchInfo
 
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_solaris)
 #  define VG_MIN_INSTR_SZB          1  // min length of native instruction
 #  define VG_MAX_INSTR_SZB         16  // max length of native instruction
 #  define VG_CLREQ_SZB             14  // length of a client request, may
                                        //   be larger than VG_MAX_INSTR_SZB
 #  define VG_STACK_REDZONE_SZB      0  // number of addressable bytes below %RSP
 
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris)
 #  define VG_MIN_INSTR_SZB          1
 #  define VG_MAX_INSTR_SZB         16
 #  define VG_CLREQ_SZB             19
diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h
index f99ffb7..2afca47 100644
--- a/include/pub_tool_redir.h
+++ b/include/pub_tool_redir.h
@@ -186,6 +186,7 @@
      (         -->  ZL    (left)
      )         -->  ZR    (right)
      Z         -->  ZZ    (Z)
+     /         -->  ZS    (slash)
 
    Everything else is left unchanged.
 */
@@ -240,7 +241,7 @@
 
 /* --- Soname of the standard C library. --- */
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 #  define  VG_Z_LIBC_SONAME  libcZdsoZa              // libc.so*
 
 #elif defined(VGO_darwin) && (DARWIN_VERS <= DARWIN_10_6)
@@ -276,6 +277,8 @@
 #  define  VG_Z_LIBPTHREAD_SONAME  libpthreadZdsoZd0     // libpthread.so.0
 #elif defined(VGO_darwin)
 #  define  VG_Z_LIBPTHREAD_SONAME  libSystemZdZaZddylib  // libSystem.*.dylib
+#elif defined(VGO_solaris)
+#  define  VG_Z_LIBPTHREAD_SONAME  libpthreadZdsoZd1     // libpthread.so.1
 #else
 #  error "Unknown platform"
 #endif
@@ -315,6 +318,27 @@
 
 #endif
 
+/* --- Soname for Solaris run-time linker. --- */
+// Note: run-time linker contains absolute pathname in the SONAME.
+
+#if defined(VGO_solaris)
+
+#if defined(VGP_x86_solaris)
+#  define  VG_Z_LD_SO_1           ZSlibZSldZdsoZd1         // /lib/ld.so.1
+#  define  VG_U_LD_SO_1           "/lib/ld.so.1"
+#elif defined(VGP_amd64_solaris)
+#  define  VG_Z_LD_SO_1           ZSlibZSamd64ZSldZdsoZd1  // /lib/amd64/ld.so.1
+#  define  VG_U_LD_SO_1           "/lib/amd64/ld.so.1"
+#else
+#  error "Unknown platform"
+#endif
+
+/* --- Soname for Solaris libumem allocation interposition. --- */
+
+#define  VG_Z_LIBUMEM_SO_1          libumemZdsoZd1             // libumem.so.1
+#define  VG_U_LIBUMEM_SO_1          "libumem.so.1"
+
+#endif
 
 // Prefix for synonym soname synonym handling
 #define VG_SO_SYN(name)       VgSoSyn##name
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index 3952f29..c9419c4 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -631,6 +631,16 @@
 void VG_(track_post_reg_write_clientcall_return)(
       void(*f)(ThreadId tid, PtrdiffT guest_state_offset, SizeT size, Addr f));
 
+/* Mem-to-reg or reg-to-mem copy functions, these ones occur around syscalls
+   and signal handling when the VCPU state is saved to (or restored from) the
+   client memory. */
+void VG_(track_copy_mem_to_reg)(void(*f)(CorePart part, ThreadId tid,
+                                         Addr a, PtrdiffT guest_state_offset,
+                                         SizeT size));
+void VG_(track_copy_reg_to_mem)(void(*f)(CorePart part, ThreadId tid,
+                                         PtrdiffT guest_state_offset,
+                                         Addr a, SizeT size));
+
 
 /* Scheduler events (not exhaustive) */
 
diff --git a/include/pub_tool_vki.h b/include/pub_tool_vki.h
index 2966ce3..9c30954 100644
--- a/include/pub_tool_vki.h
+++ b/include/pub_tool_vki.h
@@ -50,6 +50,8 @@
 #  include "vki/vki-linux-drm.h"
 #elif defined(VGO_darwin)
 #  include "vki/vki-darwin.h"
+#elif defined(VGO_solaris)
+#  include "vki/vki-solaris.h"
 #else
 #  error Unknown Plat/OS
 #endif
diff --git a/include/pub_tool_vkiscnums_asm.h b/include/pub_tool_vkiscnums_asm.h
index 860e8d0..d7bf49b 100644
--- a/include/pub_tool_vkiscnums_asm.h
+++ b/include/pub_tool_vkiscnums_asm.h
@@ -66,6 +66,9 @@
 #elif defined(VGP_tilegx_linux)
 #  include "vki/vki-scnums-tilegx-linux.h"
 
+#elif defined(VGP_x86_solaris) || (VGP_amd64_solaris)
+#  include "vki/vki-scnums-solaris.h"
+
 #else
 #  error Unknown platform
 #endif
diff --git a/include/valgrind.h b/include/valgrind.h
index 4baf855..c4e347d 100644
--- a/include/valgrind.h
+++ b/include/valgrind.h
@@ -123,6 +123,8 @@
 #undef PLAT_mips32_linux
 #undef PLAT_mips64_linux
 #undef PLAT_tilegx_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
 
 
 #if defined(__APPLE__) && defined(__i386__)
@@ -160,6 +162,10 @@
 #  define PLAT_mips32_linux 1
 #elif defined(__linux__) && defined(__tilegx__)
 #  define PLAT_tilegx_linux 1
+#elif defined(__sun) && defined(__i386__)
+#  define PLAT_x86_solaris 1
+#elif defined(__sun) && defined(__x86_64__)
+#  define PLAT_amd64_solaris 1
 #else
 /* If we're not compiling for our target platform, don't generate
    any inline asms.  */
@@ -247,10 +253,11 @@
    inline asm stuff to be useful.
 */
 
-/* ------------------------- x86-{linux,darwin} ---------------- */
+/* ----------------- x86-{linux,darwin,solaris} ---------------- */
 
 #if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)  \
-    ||  (defined(PLAT_x86_win32) && defined(__GNUC__))
+    ||  (defined(PLAT_x86_win32) && defined(__GNUC__)) \
+    ||  defined(PLAT_x86_solaris)
 
 typedef
    struct { 
@@ -310,7 +317,8 @@
                     );                                           \
  } while (0)
 
-#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__)
+          || PLAT_x86_solaris */
 
 /* ------------------------- x86-Win32 ------------------------- */
 
@@ -385,9 +393,10 @@
 
 #endif /* PLAT_x86_win32 */
 
-/* ------------------------ amd64-{linux,darwin} --------------- */
+/* ----------------- amd64-{linux,darwin,solaris} --------------- */
 
 #if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin) \
+    ||  defined(PLAT_amd64_solaris) \
     ||  (defined(PLAT_amd64_win64) && defined(__GNUC__))
 
 typedef
@@ -448,7 +457,7 @@
                     );                                           \
  } while (0)
 
-#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
 
 /* ------------------------- amd64-Win64 ------------------------- */
 
@@ -1202,9 +1211,10 @@
    do { volatile unsigned long _junk;                             \
         CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
 
-/* ------------------------- x86-{linux,darwin} ---------------- */
+/* ----------------- x86-{linux,darwin,solaris} ---------------- */
 
-#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin) \
+    ||  defined(PLAT_x86_solaris)
 
 /* These regs are trashed by the hidden call.  No need to mention eax
    as gcc can already see that, plus causes gcc to bomb. */
@@ -1631,11 +1641,12 @@
       lval = (__typeof__(lval)) _res;                             \
    } while (0)
 
-#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || PLAT_x86_solaris */
 
-/* ------------------------ amd64-{linux,darwin} --------------- */
+/* ---------------- amd64-{linux,darwin,solaris} --------------- */
 
-#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin) \
+    ||  defined(PLAT_amd64_solaris)
 
 /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
 
@@ -2184,7 +2195,7 @@
       lval = (__typeof__(lval)) _res;                                  \
    } while (0)
 
-#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin || PLAT_amd64_solaris */
 
 /* ------------------------ ppc32-linux ------------------------ */
 
@@ -7108,5 +7119,7 @@
 #undef PLAT_mips32_linux
 #undef PLAT_mips64_linux
 #undef PLAT_tilegx_linux
+#undef PLAT_x86_solaris
+#undef PLAT_amd64_solaris
 
 #endif   /* __VALGRIND_H */
diff --git a/include/vki/vki-scnums-solaris.h b/include/vki/vki-scnums-solaris.h
new file mode 100644
index 0000000..e1f5b9c
--- /dev/null
+++ b/include/vki/vki-scnums-solaris.h
@@ -0,0 +1,368 @@
+
+/*--------------------------------------------------------------------*/
+/*--- System call numbers for Solaris.        vki-scnums-solaris.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2015 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+/* Copyright 2013-2014, Ivo Raisr <ivosh@ivosh.net>. */
+
+/* Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
+
+#ifndef __VKI_SCNUMS_SOLARIS_H
+#define __VKI_SCNUMS_SOLARIS_H
+
+/* Note: Basic information about Solaris syscalls can be found in the kernel
+   source file uts/common/os/sysent.c.
+ */
+
+/* Include sys/syscall.h to get SYS_* constants (and sys/trap.h to get T_*) to
+   avoid any copyright issues connected with their potential copying out of
+   the header file.
+ */
+#include <sys/syscall.h>
+#include <sys/trap.h>
+
+/* normal syscall (int $0x91) */
+#define VG_SOLARIS_SYSCALL_CLASS_CLASSIC        0
+/* fasttrap syscall (int $0xD2) */
+#define VG_SOLARIS_SYSCALL_CLASS_FASTTRAP       1
+
+#define VG_SOLARIS_SYSCALL_CLASS_SHIFT 24
+#define VG_SOLARIS_SYSCALL_NUMBER_MASK 0x00FFFFFF
+
+#define VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(sysno) \
+   ((VG_SOLARIS_SYSCALL_CLASS_FASTTRAP << VG_SOLARIS_SYSCALL_CLASS_SHIFT) \
+    | (sysno))
+#define VG_SOLARIS_SYSNO_CLASS(sysno) \
+   ((sysno) >> VG_SOLARIS_SYSCALL_CLASS_SHIFT)
+#define VG_SOLARIS_SYSNO_INDEX(sysno) \
+   ((sysno) & VG_SOLARIS_SYSCALL_NUMBER_MASK)
+
+#define __NR_exit                       SYS_exit
+#if defined(SOLARIS_SPAWN_SYSCALL)
+#define __NR_spawn                      SYS_spawn
+#endif /* SOLARIS_SPAWN_SYSCALL */
+#define __NR_read                       SYS_read
+#define __NR_write                      SYS_write
+#define __NR_close                      SYS_close
+#define __NR_linkat                     SYS_linkat
+#define __NR_symlinkat                  SYS_symlinkat
+#define __NR_chdir                      SYS_chdir
+#define __NR_time                       SYS_time
+#define __NR_brk                        SYS_brk
+#define __NR_lseek                      SYS_lseek
+#define __NR_getpid                     SYS_getpid
+#define __NR_mount                      SYS_mount
+#define __NR_readlinkat                 SYS_readlinkat
+#define __NR_setuid                     SYS_setuid
+#define __NR_getuid                     SYS_getuid
+#define __NR_stime                      SYS_stime
+//#define __NR_pcsample                   SYS_pcsample
+#define __NR_alarm                      SYS_alarm
+#define __NR_pause                      SYS_pause
+#if defined(SOLARIS_FREALPATHAT_SYSCALL)
+#define __NR_frealpathat                SYS_frealpathat
+#endif /* SOLARIS_FREALPATHAT_SYSCALL */
+#define __NR_stty                       SYS_stty
+#define __NR_gtty                       SYS_gtty
+//#define __NR_nice                       SYS_nice
+//#define __NR_statfs                     SYS_statfs
+//#define __NR_sync                       SYS_sync
+#define __NR_kill                       SYS_kill
+//#define __NR_fstatfs                    SYS_fstatfs
+#define __NR_pgrpsys                    SYS_pgrpsys
+//#define __NR_uucopystr                  SYS_uucopystr
+#define __NR_pipe                       SYS_pipe
+#define __NR_times                      SYS_times
+//#define __NR_profil                     SYS_profil
+#define __NR_faccessat                  SYS_faccessat
+#define __NR_setgid                     SYS_setgid
+#define __NR_getgid                     SYS_getgid
+#define __NR_mknodat                    SYS_mknodat
+//#define __NR_msgsys                     SYS_msgsys
+#define __NR_sysi86                     SYS_sysi86
+//#define __NR_acct                       SYS_acct
+#define __NR_shmsys                     SYS_shmsys
+#define __NR_semsys                     SYS_semsys
+#define __NR_ioctl                      SYS_ioctl
+//#define __NR_uadmin                     SYS_uadmin
+#define __NR_fchownat                   SYS_fchownat
+//#define __NR_utssys                     SYS_utssys
+#define __NR_fdsync                     SYS_fdsync
+#define __NR_execve                     SYS_execve
+#define __NR_umask                      SYS_umask
+#define __NR_chroot                     SYS_chroot
+#define __NR_fcntl                      SYS_fcntl
+//#define __NR_ulimit                     SYS_ulimit
+#define __NR_renameat                   SYS_renameat
+#define __NR_unlinkat                   SYS_unlinkat
+#define __NR_fstatat                    SYS_fstatat
+#define __NR_fstatat64                  SYS_fstatat64
+#define __NR_openat                     SYS_openat
+#define __NR_openat64                   SYS_openat64
+#define __NR_tasksys                    SYS_tasksys
+//#define __NR_acctctl                    SYS_acctctl
+//#define __NR_exacctsys                  SYS_exacctsys
+#define __NR_getpagesizes               SYS_getpagesizes
+//#define __NR_rctlsys                    SYS_rctlsys
+//#define __NR_sidsys                     SYS_sidsys
+#define __NR_lwp_park                   SYS_lwp_park
+#define __NR_sendfilev                  SYS_sendfilev
+#if defined(SOLARIS_LWP_NAME_SYSCALL)
+#define __NR_lwp_name                   SYS_lwp_name
+#endif /* SOLARIS_LWP_NAME_SYSCALL */
+#define __NR_getdents                   SYS_getdents
+#define __NR_privsys                    SYS_privsys
+#define __NR_ucredsys                   SYS_ucredsys
+//#define __NR_sysfs                      SYS_sysfs
+#define __NR_getmsg                     SYS_getmsg
+#define __NR_putmsg                     SYS_putmsg
+#define __NR_setgroups                  SYS_setgroups
+#define __NR_getgroups                  SYS_getgroups
+#define __NR_sigprocmask                SYS_sigprocmask
+//#define __NR_sigsuspend                 SYS_sigsuspend
+#define __NR_sigaltstack                SYS_sigaltstack
+#define __NR_sigaction                  SYS_sigaction
+#define __NR_sigpending                 SYS_sigpending
+#define __NR_context                    SYS_context
+#define __NR_fchmodat                   SYS_fchmodat
+#define __NR_mkdirat                    SYS_mkdirat
+#define __NR_statvfs                    SYS_statvfs
+#define __NR_fstatvfs                   SYS_fstatvfs
+//#define __NR_getloadavg                 SYS_getloadavg
+#define __NR_nfssys                     SYS_nfssys
+#define __NR_waitid                     SYS_waitid
+#define __NR_waitsys                    SYS_waitsys /* = SYS_waitid (historical) */
+//#define __NR_sigsendsys                 SYS_sigsendsys
+//#define __NR_hrtsys                     SYS_hrtsys
+#if defined(SOLARIS_UTIMESYS_SYSCALL)
+#define __NR_utimesys                   SYS_utimesys
+#endif /* SOLARIS_UTIMESYS_SYSCALL */
+#if defined(SOLARIS_UTIMENSAT_SYSCALL)
+#define __NR_utimensat                  SYS_utimensat
+#endif /* SOLARIS_UTIMENSAT_SYSCALL */
+#define __NR_sigresend                  SYS_sigresend
+#define __NR_priocntlsys                SYS_priocntlsys
+#define __NR_pathconf                   SYS_pathconf
+//#define __NR_mincore                    SYS_mincore
+#define __NR_mmap                       SYS_mmap
+#define __NR_mprotect                   SYS_mprotect
+#define __NR_munmap                     SYS_munmap
+//#define __NR_fpathconf                  SYS_fpathconf
+//#define __NR_vfork                      SYS_vfork
+//#define __NR_fchdir                     SYS_fchdir
+#define __NR_readv                      SYS_readv
+#define __NR_writev                     SYS_writev
+#if defined(SOLARIS_UUIDSYS_SYSCALL)
+#define __NR_uuidsys                    SYS_uuidsys
+#endif /* SOLARIS_UUIDSYS_SYSCALL */
+#define __NR_mmapobj                    SYS_mmapobj
+#define __NR_setrlimit                  SYS_setrlimit
+#define __NR_getrlimit                  SYS_getrlimit
+#define __NR_memcntl                    SYS_memcntl
+#define __NR_getpmsg                    SYS_getpmsg
+#define __NR_putpmsg                    SYS_putpmsg
+#define __NR_uname                      SYS_uname
+#define __NR_setegid                    SYS_setegid
+#define __NR_sysconfig                  SYS_sysconfig
+//#define __NR_adjtime                    SYS_adjtime
+#define __NR_systeminfo                 SYS_systeminfo
+//#define __NR_sharefs                    SYS_sharefs
+#define __NR_seteuid                    SYS_seteuid
+#define __NR_forksys                    SYS_forksys
+#define __NR_sigtimedwait               SYS_sigtimedwait
+//#define __NR_lwp_info                   SYS_lwp_info
+#define __NR_yield                      SYS_yield
+#define __NR_lwp_sema_post              SYS_lwp_sema_post
+#define __NR_lwp_sema_trywait           SYS_lwp_sema_trywait
+#define __NR_lwp_detach                 SYS_lwp_detach
+//#define __NR_corectl                    SYS_corectl
+//#define __NR_modctl                     SYS_modctl
+#define __NR_fchroot                    SYS_fchroot
+//#define __NR_vhangup                    SYS_vhangup
+#define __NR_gettimeofday               SYS_gettimeofday
+#define __NR_getitimer                  SYS_getitimer
+#define __NR_setitimer                  SYS_setitimer
+#define __NR_lwp_create                 SYS_lwp_create
+#define __NR_lwp_exit                   SYS_lwp_exit
+#define __NR_lwp_suspend                SYS_lwp_suspend
+#define __NR_lwp_continue               SYS_lwp_continue
+#if defined(SOLARIS_LWP_SIGQUEUE_SYSCALL)
+#define __NR_lwp_sigqueue               SYS_lwp_sigqueue
+#else
+#define __NR_lwp_kill                   SYS_lwp_kill
+#endif /* SOLARIS_LWP_SIGQUEUE_SYSCALL */
+#define __NR_lwp_self                   SYS_lwp_self
+#define __NR_lwp_sigmask                SYS_lwp_sigmask
+#define __NR_lwp_private                SYS_lwp_private
+#define __NR_lwp_wait                   SYS_lwp_wait
+#define __NR_lwp_mutex_wakeup           SYS_lwp_mutex_wakeup
+//#define __NR_lwp_cond_wait              SYS_lwp_cond_wait
+//#define __NR_lwp_cond_signal            SYS_lwp_cond_signal
+#define __NR_lwp_cond_broadcast         SYS_lwp_cond_broadcast
+#define __NR_pread                      SYS_pread
+#define __NR_pwrite                     SYS_pwrite
+#define __NR_llseek                     SYS_llseek
+//#define __NR_inst_sync                  SYS_inst_sync
+//#define __NR_brand                      SYS_brand
+//#define __NR_kaio                       SYS_kaio
+//#define __NR_cpc                        SYS_cpc
+//#define __NR_lgrpsys                    SYS_lgrpsys
+//#define __NR_meminfosys                 SYS_meminfosys /* = SYS_lgrpsys */
+#define __NR_rusagesys                  SYS_rusagesys
+#define __NR_port                       SYS_port
+#define __NR_pollsys                    SYS_pollsys
+#define __NR_labelsys                   SYS_labelsys
+#define __NR_acl                        SYS_acl
+#define __NR_auditsys                   SYS_auditsys
+//#define __NR_processor_bind             SYS_processor_bind
+//#define __NR_processor_info             SYS_processor_info
+#define __NR_p_online                   SYS_p_online
+#define __NR_sigqueue                   SYS_sigqueue
+#define __NR_clock_gettime              SYS_clock_gettime
+#define __NR_clock_settime              SYS_clock_settime
+#define __NR_clock_getres               SYS_clock_getres
+#define __NR_timer_create               SYS_timer_create
+#define __NR_timer_delete               SYS_timer_delete
+#define __NR_timer_settime              SYS_timer_settime
+#define __NR_timer_gettime              SYS_timer_gettime
+#define __NR_timer_getoverrun           SYS_timer_getoverrun
+#define __NR_nanosleep                  SYS_nanosleep
+#define __NR_facl                       SYS_facl
+#define __NR_door                       SYS_door
+#define __NR_setreuid                   SYS_setreuid
+#define __NR_setregid                   SYS_setregid
+//#define __NR_install_utrap              SYS_install_utrap
+//#define __NR_signotify                  SYS_signotify
+#define __NR_schedctl                   SYS_schedctl
+//#define __NR_pset                       SYS_pset
+//#define SYS_sparc_utrap_install
+#define __NR_resolvepath                SYS_resolvepath
+#define __NR_lwp_mutex_timedlock        SYS_lwp_mutex_timedlock
+#define __NR_lwp_sema_timedwait         SYS_lwp_sema_timedwait
+#define __NR_lwp_rwlock_sys             SYS_lwp_rwlock_sys
+#define __NR_getdents64                 SYS_getdents64
+#define __NR_mmap64                     SYS_mmap64
+#define __NR_statvfs64                  SYS_statvfs64
+#define __NR_fstatvfs64                 SYS_fstatvfs64
+#define __NR_setrlimit64                SYS_setrlimit64
+#define __NR_getrlimit64                SYS_getrlimit64
+#define __NR_pread64                    SYS_pread64
+#define __NR_pwrite64                   SYS_pwrite64
+//#define __NR_rpcsys                     SYS_rpcsys
+#define __NR_zone                       SYS_zone
+//#define __NR_autofssys                  SYS_autofssys
+#define __NR_getcwd                     SYS_getcwd
+#define __NR_so_socket                  SYS_so_socket
+#define __NR_so_socketpair              SYS_so_socketpair
+#define __NR_bind                       SYS_bind
+#define __NR_listen                     SYS_listen
+#define __NR_accept                     SYS_accept
+#define __NR_connect                    SYS_connect
+#define __NR_shutdown                   SYS_shutdown
+#define __NR_recv                       SYS_recv
+#define __NR_recvfrom                   SYS_recvfrom
+#define __NR_recvmsg                    SYS_recvmsg
+#define __NR_send                       SYS_send
+#define __NR_sendmsg                    SYS_sendmsg
+#define __NR_sendto                     SYS_sendto
+#define __NR_getpeername                SYS_getpeername
+#define __NR_getsockname                SYS_getsockname
+#define __NR_getsockopt                 SYS_getsockopt
+#define __NR_setsockopt                 SYS_setsockopt
+//#define __NR_sockconfig                 SYS_sockconfig
+//#define __NR_ntp_gettime                SYS_ntp_gettime
+//#define __NR_ntp_adjtime                SYS_ntp_adjtime
+//#define __NR_lwp_mutex_unlock           SYS_lwp_mutex_unlock
+//#define __NR_lwp_mutex_trylock          SYS_lwp_mutex_trylock
+#define __NR_lwp_mutex_register         SYS_lwp_mutex_register
+//#define __NR_cladm                      SYS_cladm
+#define __NR_uucopy                     SYS_uucopy
+#define __NR_umount2                    SYS_umount2
+
+/* The following syscalls were removed in Solaris 11 (see
+   https://wikis.oracle.com/display/DTrace/syscall+Provider). Valgrind's core
+   cannot use these syscalls but wrappers have to be provided for them because
+   they are still in use on illumos.
+*/
+#if defined(SOLARIS_OLD_SYSCALLS)
+#define __NR_open                       SYS_open
+#define __NR_link                       SYS_link
+#define __NR_unlink                     SYS_unlink
+#define __NR_mknod                      SYS_mknod
+#define __NR_chmod                      SYS_chmod
+#define __NR_chown                      SYS_chown
+#define __NR_stat                       SYS_stat
+#define __NR_fstat                      SYS_fstat
+#define __NR_access                     SYS_access
+#define __NR_rmdir                      SYS_rmdir
+#define __NR_mkdir                      SYS_mkdir
+#define __NR_lstat                      SYS_lstat
+#define __NR_symlink                    SYS_symlink
+#define __NR_readlink                   SYS_readlink
+#define __NR_fchmod                     SYS_fchmod
+#define __NR_fchown                     SYS_fchown
+#define __NR_lchown                     SYS_lchown
+#define __NR_rename                     SYS_rename
+#define __NR_stat64                     SYS_stat64
+#define __NR_lstat64                    SYS_lstat64
+#define __NR_fstat64                    SYS_fstat64
+#define __NR_open64                     SYS_open64
+#endif /* SOLARIS_OLD_SYSCALLS */
+
+/*
+#define __NR_null \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_FNULL)
+#define __NR_fgetfp \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_FGETFP)
+#define __NR_fsetfp \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_FSETFP)
+*/
+#define __NR_gethrtime \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETHRTIME)
+#define __NR_gethrvtime \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETHRVTIME)
+#define __NR_gethrestime \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETHRESTIME)
+/*
+#define __NR_getlgrp \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETLGRP)
+*/
+#if defined(SOLARIS_GETHRT_FASTTRAP)
+#define __NR_gethrt \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETHRT)
+#endif /* SOLARIS_GETHRT_FASTTRAP */
+#if defined(SOLARIS_GETZONEOFFSET_FASTTRAP)
+#define __NR_getzoneoffset \
+   VG_SOLARIS_SYSCALL_CONSTRUCT_FASTTRAP(T_GETZONEOFFSET)
+#endif /* SOLARIS_GETZONEOFFSET_FASTTRAP */
+
+#endif /* __VKI_SCNUMS_SOLARIS_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/include/vki/vki-solaris-repcache.h b/include/vki/vki-solaris-repcache.h
new file mode 100644
index 0000000..3d47095
--- /dev/null
+++ b/include/vki/vki-solaris-repcache.h
@@ -0,0 +1,272 @@
+/*--------------------------------------------------------------------*/
+/*--- Solaris-specific kernel interface for the repository cache   ---*/
+/*--- protocol.                             vki-solaris-repcache.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2015-2015 Ivo Raisr
+      ivosh@ivosh.net
+
+   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 __VKI_SOLARIS_REPCACHE_H
+#define __VKI_SOLARIS_REPCACHE_H
+
+/* From <repcache_protocol.h> which is consolidation private. */
+#define VKI_REPOSITORY_DOOR_BASEVER (('R' << 24) | ('e' << 16) | ('p' << 8))
+
+#if (SOLARIS_REPCACHE_PROTOCOL_VERSION == 21)
+#define VKI_REPOSITORY_DOOR_VERSION (21 + VKI_REPOSITORY_DOOR_BASEVER)
+enum vki_rep_protocol_requestid {
+   VKI_REP_PROTOCOL_CLOSE = ('C' << 8),
+   VKI_REP_PROTOCOL_ENTITY_SETUP,
+   VKI_REP_PROTOCOL_ENTITY_NAME,
+   VKI_REP_PROTOCOL_ENTITY_PARENT_TYPE,
+   VKI_REP_PROTOCOL_ENTITY_GET_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_GET_PARENT,
+   VKI_REP_PROTOCOL_ENTITY_GET,
+   VKI_REP_PROTOCOL_ENTITY_UPDATE,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_PG,
+   VKI_REP_PROTOCOL_ENTITY_DELETE,
+   VKI_REP_PROTOCOL_ENTITY_RESET,
+   VKI_REP_PROTOCOL_ENTITY_TEARDOWN,
+   VKI_REP_PROTOCOL_ITER_SETUP,
+   VKI_REP_PROTOCOL_ITER_START,
+   VKI_REP_PROTOCOL_ITER_READ,
+   VKI_REP_PROTOCOL_ITER_READ_VALUE,
+   VKI_REP_PROTOCOL_ITER_RESET,
+   VKI_REP_PROTOCOL_ITER_TEARDOWN,
+   VKI_REP_PROTOCOL_NEXT_SNAPLEVEL,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,
+   VKI_REP_PROTOCOL_SNAPSHOT_ATTACH,
+   VKI_REP_PROTOCOL_PROPERTY_GET_TYPE,
+   VKI_REP_PROTOCOL_PROPERTY_GET_VALUE,
+   VKI_REP_PROTOCOL_PROPERTYGRP_SETUP_WAIT,
+   VKI_REP_PROTOCOL_PROPERTYGRP_TX_START,
+   VKI_REP_PROTOCOL_PROPERTYGRP_TX_COMMIT,
+   VKI_REP_PROTOCOL_CLIENT_ADD_NOTIFY,
+   VKI_REP_PROTOCOL_CLIENT_WAIT,
+   VKI_REP_PROTOCOL_BACKUP,
+   VKI_REP_PROTOCOL_SET_AUDIT_ANNOTATION,
+   VKI_REP_PROTOCOL_SWITCH,
+};
+#elif (SOLARIS_REPCACHE_PROTOCOL_VERSION == 23)
+#define VKI_REPOSITORY_DOOR_VERSION (23 + VKI_REPOSITORY_DOOR_BASEVER)
+enum vki_rep_protocol_requestid {
+   VKI_REP_PROTOCOL_CLOSE = ('C' << 8),
+   VKI_REP_PROTOCOL_ENTITY_SETUP,
+   VKI_REP_PROTOCOL_ENTITY_NAME,
+   VKI_REP_PROTOCOL_ENTITY_PARENT_TYPE,
+   VKI_REP_PROTOCOL_ENTITY_GET_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_GET_PARENT,
+   VKI_REP_PROTOCOL_ENTITY_GET,
+   VKI_REP_PROTOCOL_ENTITY_UPDATE,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_PG,
+   VKI_REP_PROTOCOL_ENTITY_DELETE,
+   VKI_REP_PROTOCOL_ENTITY_UNDELETE,
+   VKI_REP_PROTOCOL_ENTITY_REMOVE,
+   VKI_REP_PROTOCOL_ENTITY_DELCUST,
+   VKI_REP_PROTOCOL_BUNDLE_REMOVE,
+   VKI_REP_PROTOCOL_ENTITY_RESET,
+   VKI_REP_PROTOCOL_ENTITY_TEARDOWN,
+   VKI_REP_PROTOCOL_ITER_SETUP,
+   VKI_REP_PROTOCOL_ITER_START,
+   VKI_REP_PROTOCOL_ITER_READ,
+   VKI_REP_PROTOCOL_ITER_READ_VALUE,
+   VKI_REP_PROTOCOL_ITER_RESET,
+   VKI_REP_PROTOCOL_ITER_TEARDOWN,
+   VKI_REP_PROTOCOL_NEXT_SNAPLEVEL,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,
+   VKI_REP_PROTOCOL_SNAPSHOT_ATTACH,
+   VKI_REP_PROTOCOL_PROPERTY_GET_TYPE,
+   VKI_REP_PROTOCOL_PROPERTY_GET_VALUE,
+   VKI_REP_PROTOCOL_PG_SETUP_WAIT,
+   VKI_REP_PROTOCOL_PG_TX_START,
+   VKI_REP_PROTOCOL_PG_TX_COMMIT,
+   VKI_REP_PROTOCOL_PROP_BUNDLE_REMOVE,
+   VKI_REP_PROTOCOL_CLIENT_ADD_NOTIFY,
+   VKI_REP_PROTOCOL_CLIENT_WAIT,
+   VKI_REP_PROTOCOL_BACKUP,
+   VKI_REP_PROTOCOL_SET_AUDIT_ANNOTATION,
+   VKI_REP_PROTOCOL_UNSET_AUDIT_ANNOTATION,
+   VKI_REP_PROTOCOL_SET_TX_DECORATION,
+   VKI_REP_PROTOCOL_SWITCH,
+   VKI_REP_PROTOCOL_DECORATION_GET_LAYER,
+   VKI_REP_PROTOCOL_DECORATION_GET_TYPE,
+   VKI_REP_PROTOCOL_DECORATION_GET_VALUE,
+   VKI_REP_PROTOCOL_DECORATION_GET_BUNDLE,
+   VKI_REP_PROTOCOL_ENTITY_INCONFLICT,
+   VKI_REP_PROTOCOL_ENTITY_IS_MASKED,
+   VKI_REP_PROTOCOL_CLIENT_REMOVE_NOTIFY,
+};
+#elif (SOLARIS_REPCACHE_PROTOCOL_VERSION == 25)
+#define VKI_REPOSITORY_DOOR_VERSION (25 + VKI_REPOSITORY_DOOR_BASEVER)
+enum vki_rep_protocol_requestid {
+   VKI_REP_PROTOCOL_CLOSE = ('C' << 8),
+   VKI_REP_PROTOCOL_ENTITY_SETUP,
+   VKI_REP_PROTOCOL_ENTITY_NAME,
+   VKI_REP_PROTOCOL_ENTITY_FMRI,
+   VKI_REP_PROTOCOL_ENTITY_PARENT_TYPE,
+   VKI_REP_PROTOCOL_ENTITY_GET_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_GET_PARENT,
+   VKI_REP_PROTOCOL_ENTITY_GET_ROOT,
+   VKI_REP_PROTOCOL_ENTITY_GET,
+   VKI_REP_PROTOCOL_ENTITY_UPDATE,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_CHILD,
+   VKI_REP_PROTOCOL_ENTITY_CREATE_PG,
+   VKI_REP_PROTOCOL_ENTITY_DELETE,
+   VKI_REP_PROTOCOL_ENTITY_UNDELETE,
+   VKI_REP_PROTOCOL_ENTITY_REMOVE,
+   VKI_REP_PROTOCOL_ENTITY_DELCUST,
+   VKI_REP_PROTOCOL_BUNDLE_REMOVE,
+   VKI_REP_PROTOCOL_ENTITY_RESET,
+   VKI_REP_PROTOCOL_ENTITY_TEARDOWN,
+   VKI_REP_PROTOCOL_ITER_SETUP,
+   VKI_REP_PROTOCOL_ITER_START,
+   VKI_REP_PROTOCOL_ITER_READ,
+   VKI_REP_PROTOCOL_ITER_READ_VALUE,
+   VKI_REP_PROTOCOL_ITER_RESET,
+   VKI_REP_PROTOCOL_ITER_TEARDOWN,
+   VKI_REP_PROTOCOL_NEXT_SNAPLEVEL,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE,
+   VKI_REP_PROTOCOL_SNAPSHOT_TAKE_NAMED,
+   VKI_REP_PROTOCOL_SNAPSHOT_ATTACH,
+   VKI_REP_PROTOCOL_PROPERTY_GET_TYPE,
+   VKI_REP_PROTOCOL_PROPERTY_GET_VALUE,
+   VKI_REP_PROTOCOL_PG_SETUP_WAIT,
+   VKI_REP_PROTOCOL_PG_TX_START,
+   VKI_REP_PROTOCOL_PG_TX_COMMIT,
+   VKI_REP_PROTOCOL_PROP_BUNDLE_REMOVE,
+   VKI_REP_PROTOCOL_CLIENT_ADD_NOTIFY,
+   VKI_REP_PROTOCOL_CLIENT_WAIT,
+   VKI_REP_PROTOCOL_BACKUP,
+   VKI_REP_PROTOCOL_SET_AUDIT_ANNOTATION,
+   VKI_REP_PROTOCOL_UNSET_AUDIT_ANNOTATION,
+   VKI_REP_PROTOCOL_SET_TX_DECORATION,
+   VKI_REP_PROTOCOL_SWITCH,
+   VKI_REP_PROTOCOL_DECORATION_GET_LAYER,
+   VKI_REP_PROTOCOL_DECORATION_GET_TYPE,
+   VKI_REP_PROTOCOL_DECORATION_GET_VALUE,
+   VKI_REP_PROTOCOL_DECORATION_GET_BUNDLE,
+   VKI_REP_PROTOCOL_ENTITY_INCONFLICT,
+   VKI_REP_PROTOCOL_ENTITY_IS_MASKED,
+   VKI_REP_PROTOCOL_CLIENT_REMOVE_NOTIFY,
+};
+#else
+#error Unsupported repcache protocol version
+#endif
+
+#define VKI_REPOSITORY_DOOR_NAME "/system/volatile/repository_door"
+#define VKI_REP_PROTOCOL_NAME_LEN 120
+enum vki_repository_door_requestid {
+   VKI_REPOSITORY_DOOR_REQUEST_CONNECT = (('M' << 8) | 1)
+};
+enum vki_repository_door_statusid {
+   VKI_REPOSITORY_DOOR_SUCCESS                = 0,
+   VKI_REPOSITORY_DOOR_FAIL_BAD_REQUEST       = 1,
+   VKI_REPOSITORY_DOOR_FAIL_VERSION_MISMATCH  = 2,
+   VKI_REPOSITORY_DOOR_FAIL_BAD_FLAG          = 3,
+   VKI_REPOSITORY_DOOR_FAIL_NO_RESOURCES      = 4,
+   VKI_REPOSITORY_DOOR_FAIL_PERMISSION_DENIED = 5
+};
+typedef struct vki_repository_door_request {
+   vki_uint32_t rdr_version;
+   enum vki_repository_door_requestid rdr_request;
+   vki_uint32_t rdr_flags;
+   vki_uint32_t rdr_debug;
+} vki_repository_door_request_t;
+typedef struct vki_repository_door_response {
+   enum vki_repository_door_statusid rdr_status;
+} vki_repository_door_response_t;
+typedef struct vki_rep_protocol_request {
+   enum vki_rep_protocol_requestid rpr_request;
+} vki_rep_protocol_request_t;
+struct vki_rep_protocol_entity_setup {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+   vki_uint32_t rpr_entitytype;
+};
+struct vki_rep_protocol_entity_name {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+   vki_uint32_t rpr_answertype;
+};
+struct vki_rep_protocol_entity_get {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+   vki_uint32_t rpr_object;
+};
+struct vki_rep_protocol_entity_get_child {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+   vki_uint32_t rpr_childid;
+   char rpr_name[VKI_REP_PROTOCOL_NAME_LEN];
+};
+struct vki_rep_protocol_entity_parent {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+   vki_uint32_t rpr_outid;
+};
+struct vki_rep_protocol_entity_reset {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+};
+struct vki_rep_protocol_entity_teardown {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+};
+struct vki_rep_protocol_iter_read {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_iterid;
+   vki_uint32_t rpr_sequence;
+   vki_uint32_t rpr_entityid;
+};
+struct vki_rep_protocol_iter_read_value {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_iterid;
+   vki_uint32_t rpr_sequence;
+};
+struct vki_rep_protocol_iter_request {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_iterid;
+};
+struct vki_rep_protocol_iter_start {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_iterid;
+   vki_uint32_t rpr_entity;
+   vki_uint32_t rpr_itertype;
+   vki_uint32_t rpr_flags;
+   char rpr_pattern[VKI_REP_PROTOCOL_NAME_LEN];
+};
+struct vki_rep_protocol_property_request {
+   enum vki_rep_protocol_requestid rpr_request;
+   vki_uint32_t rpr_entityid;
+};
+
+
+
+
+#endif /* __VKI_SOLARIS_REPCACHE_21_H */
diff --git a/include/vki/vki-solaris.h b/include/vki/vki-solaris.h
new file mode 100644
index 0000000..ba2631e
--- /dev/null
+++ b/include/vki/vki-solaris.h
@@ -0,0 +1,1610 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Solaris-specific kernel interface.             vki-solaris.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2011-2015 Petr Pavlu
+      setup@dagobah.cz
+
+   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.
+*/
+
+/* Copyright 2013-2015, Ivo Raisr <ivosh@ivosh.net> */
+
+/* Copyright 2013, OmniTI Computer Consulting, Inc. All rights reserved. */
+
+/* The purpose of this file is described in vki-linux.h.
+
+   To avoid any copyright issues, vki-solaris.h follows the same approach as
+   vki-darwin.h (not copying anything from kernel header files but instead
+   just including them).
+ */
+
+#ifndef __VKI_SOLARIS_H
+#define __VKI_SOLARIS_H
+
+#include "../../config.h"
+
+/* _XOPEN_SOURCE equal to at least '500' is required so that various system
+   structures have all necessary attributes (for example struct msghdr). */
+#if !defined(_XOPEN_SOURCE)
+/* Compiler versions c99 and higher require _XOPEN_SOURCE at least '600'. */
+#   if (__STDC_VERSION__ - 0 >= 199901L)
+#      define _XOPEN_SOURCE 600
+#   else
+#      define _XOPEN_SOURCE 500
+#   endif
+#elif (_XOPEN_SOURCE - 0 != 500) && (_XOPEN_SOURCE - 0 != 600) && (_XOPEN_SOURCE - 0 != 700)
+#   error "Compiler or options invalid for including this header file."
+#endif /* _XOPEN_SOURCE */
+
+#define __EXTENSIONS__ 1
+/* assert _FILE_OFFSET_BITS == 32 */
+
+/* XXX These two PTRACE defines are currently used only in m_debugger.c for
+   legacy 'attach debugger' functionality. This is going to be removed
+   in future Valgrind version and so can these two as well. */
+#define VKI_PTRACE_TRACEME 0
+#define VKI_PTRACE_DETACH -1
+
+#define VKI_PAGE_SHIFT 12
+#define VKI_PAGE_SIZE (1UL << VKI_PAGE_SHIFT)
+#define VKI_PAGEMASK (~VKI_PAGEOFFSET)
+#define VKI_PAGEOFFSET (VKI_PAGE_SIZE - 1)
+#define VKI_MAX_PAGE_SHIFT VKI_PAGE_SHIFT
+#define VKI_MAX_PAGE_SIZE VKI_PAGE_SIZE
+
+
+#include <sys/types.h>
+#define VKI_UINT_MAX UINT_MAX
+#define vki_boolean_t boolean_t
+#define vki_datalink_id_t datalink_id_t
+#define vki_uint_t uint_t
+#define vki_uint32_t uint32_t
+#define vki_uint64_t uint64_t
+#define vki_ulong_t ulong_t
+#define vki_caddr_t caddr_t
+#define vki_dev_t dev_t
+#define vki_off_t off_t
+#define vki_id_t id_t
+#define vki_key_t key_t
+#define vki_mode_t mode_t
+#define vki_o_dev_t o_dev_t
+#define vki_projid_t projid_t
+#define vki_uid_t uid_t
+#define vki_gid_t gid_t
+#define vki_pid_t pid_t
+#define vki_size_t size_t
+#define vki_time_t time_t
+#define vki_timer_t timer_t
+#define vki_uchar_t uchar_t
+
+typedef uint32_t vki_u32;
+
+
+#include <sys/types32.h>
+#define vki_size32_t size32_t
+
+
+#include <fcntl.h>
+#define VKI_SEEK_SET SEEK_SET
+
+
+#include <limits.h>
+#define VKI_NGROUPS_MAX NGROUPS_MAX
+#define VKI_PATH_MAX PATH_MAX
+/* Used in launcher-linux.c which we share with Linux port. */
+#define VKI_BINPRM_BUF_SIZE VKI_PATH_MAX
+
+
+#include <ucred.h>
+#define vki_ucred_t ucred_t
+
+
+#include <unistd.h>
+#define VKI_R_OK R_OK
+#define VKI_W_OK W_OK
+#define VKI_X_OK X_OK
+
+
+#include <bsm/audit.h>
+#define VKI_A_GETAMASK A_GETAMASK
+#define VKI_A_GETCAR A_GETCAR
+#define VKI_A_GETCLASS A_GETCLASS
+#define VKI_A_GETCOND A_GETCOND
+#define VKI_A_GETCWD A_GETCWD
+#define VKI_A_GETKAUDIT A_GETKAUDIT
+#define VKI_A_GETKMASK A_GETKMASK
+#define VKI_A_GETPINFO A_GETPINFO
+#define VKI_A_GETPINFO_ADDR A_GETPINFO_ADDR
+#define VKI_A_GETPOLICY A_GETPOLICY
+#define VKI_A_GETQCTRL A_GETQCTRL
+#define VKI_A_GETSTAT A_GETSTAT
+#define VKI_A_SETAMASK A_SETAMASK
+#define VKI_A_SETCLASS A_SETCLASS
+#define VKI_A_SETCOND A_SETCOND
+#define VKI_A_SETKAUDIT A_SETKAUDIT
+#define VKI_A_SETKMASK A_SETKMASK
+#define VKI_A_SETPMASK A_SETPMASK
+#define VKI_A_SETPOLICY A_SETPOLICY
+#define VKI_A_SETQCTRL A_SETQCTRL
+#define VKI_A_SETSMASK A_SETSMASK
+#define VKI_A_SETSTAT A_SETSTAT
+#define VKI_A_SETUMASK A_SETUMASK
+#define VKI_BSM_AUDIT BSM_AUDIT
+#define VKI_BSM_AUDITCTL BSM_AUDITCTL
+#define VKI_BSM_AUDITDOOR BSM_AUDITDOOR
+#define VKI_BSM_GETAUDIT BSM_GETAUDIT
+#define VKI_BSM_GETAUDIT_ADDR BSM_GETAUDIT_ADDR
+#define VKI_BSM_GETAUID BSM_GETAUID
+#define VKI_BSM_SETAUDIT BSM_SETAUDIT
+#define VKI_BSM_SETAUDIT_ADDR BSM_SETAUDIT_ADDR
+#define VKI_BSM_SETAUID BSM_SETAUID
+#define vki_au_evclass_map_t au_evclass_map_t
+#define vki_au_id_t au_id_t
+#define vki_au_mask_t au_mask_t
+#define vki_au_qctrl au_qctrl
+#define vki_au_stat_t au_stat_t
+#define vki_auditinfo_t auditinfo_t
+#define vki_auditinfo_addr_t auditinfo_addr_t
+#define vki_auditpinfo auditpinfo
+#define vki_auditpinfo_addr auditpinfo_addr
+
+
+#include <sys/psw.h>
+#define VKI_PSL_USER PSL_USER
+
+
+#include <ia32/sys/trap.h>
+#define VKI_T_BPTFLT T_BPTFLT
+
+
+/* From <libc/inc/libc_int.h> which is consolidation private. */
+#define VKI_CI_BIND_GUARD 4
+#define VKI_CI_BIND_CLEAR 5
+#define VKI_THR_FLG_RTLD 0x01
+
+typedef struct {
+   int ci_tag;
+   union {
+      int (*ci_func)(int);
+      long ci_val;
+      char *ci_ptr;
+   } vki_ci_un;
+} vki_Lc_interface;
+
+
+/* From <libc/port/gen/getxby_door.h> which is consolidation private. */
+#if defined(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE)
+#define VKI_NAME_SERVICE_DOOR "/system/volatile/name_service_door"
+#else
+#define VKI_NAME_SERVICE_DOOR "/var/run/name_service_door"
+#endif /* SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE */
+
+
+#include <nfs/nfs.h>
+#include <nfs/nfssys.h>
+#define VKI_NFS_REVAUTH NFS_REVAUTH
+#define vki_nfs_revauth_args nfs_revauth_args
+
+
+#include <net/if.h>
+#define vki_lifnum lifnum
+
+
+#include <netinet/in.h>
+#define VKI_IPPROTO_TCP IPPROTO_TCP
+#define vki_in_addr in_addr
+#define vki_sockaddr_in sockaddr_in
+#define vki_sockaddr_in6 sockaddr_in6
+
+#include <netinet/tcp.h>
+#define VKI_TCP_NODELAY TCP_NODELAY
+
+
+/* Do not include nss_dbdefs.h if a C++ compiler is used to build a file
+   which includes vki-solaris.h. This cannot be done because the nss_dbdefs.h
+   header file uses 'delete' keyword as a method name. */
+#if !defined(__cplusplus)
+#include <nss_dbdefs.h>
+#define VKI_NSCD_CALLCAT_APP NSCD_CALLCAT_APP
+#define VKI_NSCDV2CATMASK NSCDV2CATMASK
+#define vki_nss_dbd_t nss_dbd_t
+#define vki_nss_pheader_t nss_pheader_t
+#endif /* !__cplusplus */
+
+
+/* From <repcache_protocol.h> which is consolidation private. */
+#include "vki-solaris-repcache.h"
+
+#include <sys/acl.h>
+#define vki_aclent_t aclent_t
+#define vki_ace_t ace_t
+#define VKI_GETACL GETACL
+#define VKI_SETACL SETACL
+#define VKI_GETACLCNT GETACLCNT
+#define VKI_ACE_GETACL ACE_GETACL
+#define VKI_ACE_SETACL ACE_SETACL
+#define VKI_ACE_GETACLCNT ACE_GETACLCNT
+
+
+#include <sys/auxv.h>
+#define vki_auxv_t auxv_t
+#define VKI_AT_NULL AT_NULL
+#define VKI_AT_PHDR AT_PHDR
+#define VKI_AT_PAGESZ AT_PAGESZ
+#define VKI_AT_BASE AT_BASE
+#define VKI_AT_FLAGS AT_FLAGS
+#define VKI_AT_SUN_PLATFORM AT_SUN_PLATFORM
+#define VKI_AT_SUN_HWCAP AT_SUN_HWCAP
+#define VKI_AT_SUN_EXECNAME AT_SUN_EXECNAME
+#define VKI_AT_SUN_AUXFLAGS AT_SUN_AUXFLAGS
+
+#define VKI_AF_SUN_HWCAPVERIFY AF_SUN_HWCAPVERIFY
+
+
+#include <sys/auxv_386.h>
+#define VKI_AV_386_FPU AV_386_FPU
+#define VKI_AV_386_TSC AV_386_TSC
+#define VKI_AV_386_CX8 AV_386_CX8
+#define VKI_AV_386_SEP AV_386_SEP
+#define VKI_AV_386_AMD_SYSC AV_386_AMD_SYSC
+#define VKI_AV_386_CMOV AV_386_CMOV
+#define VKI_AV_386_MMX AV_386_MMX
+#define VKI_AV_386_FXSR AV_386_FXSR
+#define VKI_AV_386_SSE AV_386_SSE
+#define VKI_AV_386_SSE2 AV_386_SSE2
+#define VKI_AV_386_SSE3 AV_386_SSE3
+#define VKI_AV_386_CX16 AV_386_CX16
+#define VKI_AV_386_AHF AV_386_AHF
+#define VKI_AV_386_TSCP AV_386_TSCP
+#define VKI_AV_386_POPCNT AV_386_POPCNT
+#define VKI_AV_386_AMD_LZCNT AV_386_AMD_LZCNT
+#define VKI_AV_386_SSSE3 AV_386_SSSE3
+#define VKI_AV_386_SSE4_1 AV_386_SSE4_1
+#define VKI_AV_386_SSE4_2 AV_386_SSE4_2
+#define VKI_AV_386_AES AV_386_AES
+#define VKI_AV_386_PCLMULQDQ AV_386_PCLMULQDQ
+#define VKI_AV_386_XSAVE AV_386_XSAVE
+
+
+#include <sys/corectl.h>
+#define VKI_CC_CONTENT_ANON CC_CONTENT_ANON
+#define VKI_CC_CONTENT_DATA CC_CONTENT_DATA
+#define VKI_CC_CONTENT_DISM CC_CONTENT_DISM
+#define VKI_CC_CONTENT_HEAP CC_CONTENT_HEAP
+#define VKI_CC_CONTENT_ISM CC_CONTENT_ISM
+#define VKI_CC_CONTENT_RODATA CC_CONTENT_RODATA
+#define VKI_CC_CONTENT_SHANON CC_CONTENT_SHANON
+#define VKI_CC_CONTENT_SHM CC_CONTENT_SHM
+#define VKI_CC_CONTENT_STACK CC_CONTENT_STACK
+#define VKI_CC_CONTENT_TEXT CC_CONTENT_TEXT
+#define vki_core_content_t core_content_t
+
+
+/* From <sys/crypto/elfsign.h> which is consolidation private. */
+#define VKI__PATH_KCFD_DOOR "/system/volatile/kcfd_door"
+typedef enum vki_ELFsign_status_e {
+   VKI_ELFSIGN_UNKNOWN,
+   VKI_ELFSIGN_SUCCESS,
+   VKI_ELFSIGN_FAILED,
+   VKI_ELFSIGN_NOTSIGNED,
+   VKI_ELFSIGN_INVALID_CERTPATH,
+   VKI_ELFSIGN_INVALID_ELFOBJ,
+   VKI_ELFSIGN_UNAVAILABLE
+} vki_ELFsign_status_t;
+typedef struct vki_kcf_door_arg_s {
+   short         da_version;
+   vki_boolean_t da_iskernel;
+   union {
+      char filename[MAXPATHLEN];	/* For request */
+
+      struct vki_kcf_door_result_s {	/* For response */
+         vki_ELFsign_status_t status;
+         vki_uint32_t         siglen;
+         vki_uchar_t          signature[1];
+      } result;
+   } vki_da_u;
+} vki_kcf_door_arg_t;
+
+
+#include <sys/crypto/ioctl.h>
+#define VKI_CRYPTO_SUCCESS CRYPTO_SUCCESS
+#define VKI_CRYPTO_GET_PROVIDER_LIST CRYPTO_GET_PROVIDER_LIST
+#define vki_crypto_provider_id_t crypto_provider_id_t
+#define vki_crypto_provider_entry_t crypto_provider_entry_t
+#define vki_crypto_get_provider_list_t crypto_get_provider_list_t
+
+
+#include <sys/dirent.h>
+#define VKI_MAXGETDENTS_SIZE MAXGETDENTS_SIZE
+#define vki_dirent dirent
+#define vki_dirent64 dirent64
+
+
+#include <sys/door.h>
+#define vki_door_desc_t door_desc_t
+#define vki_door_info_t door_info_t
+#define vki_door_arg_t door_arg_t
+#define vki_door_results door_results
+#define vki_door_return_desc_t door_return_desc_t
+
+#define VKI_DOOR_CREATE DOOR_CREATE
+#define VKI_DOOR_REVOKE DOOR_REVOKE
+#define VKI_DOOR_INFO DOOR_INFO
+#define VKI_DOOR_CALL DOOR_CALL
+#define VKI_DOOR_BIND DOOR_BIND
+#define VKI_DOOR_UNBIND DOOR_UNBIND
+#define VKI_DOOR_UNREFSYS DOOR_UNREFSYS
+#define VKI_DOOR_UCRED DOOR_UCRED
+#define VKI_DOOR_RETURN DOOR_RETURN
+#define VKI_DOOR_GETPARAM DOOR_GETPARAM
+#define VKI_DOOR_SETPARAM DOOR_SETPARAM
+
+
+#include <sys/dtrace.h>
+#define VKI_DTRACEHIOC_REMOVE DTRACEHIOC_REMOVE
+#define VKI_DTRACEHIOC_ADDDOF DTRACEHIOC_ADDDOF
+#define vki_dof_helper_t dof_helper_t
+
+
+#include <sys/elf.h>
+#define VKI_EI_CLASS EI_CLASS
+#define VKI_EI_DATA EI_DATA
+#define VKI_EI_MAG0 EI_MAG0
+#define VKI_EI_MAG1 EI_MAG1
+#define VKI_EI_MAG2 EI_MAG2
+#define VKI_EI_MAG3 EI_MAG3
+#define VKI_EI_VERSION EI_VERSION
+#define VKI_ELFMAG ELFMAG
+#define VKI_ELFMAG ELFMAG
+#define VKI_ELFMAG0 ELFMAG0
+#define VKI_ELFMAG1 ELFMAG1
+#define VKI_ELFMAG2 ELFMAG2
+#define VKI_ELFMAG3 ELFMAG3
+#define VKI_ET_CORE ET_CORE
+#define VKI_ET_DYN ET_DYN
+#define VKI_ET_EXEC ET_EXEC
+#define VKI_EV_CURRENT EV_CURRENT
+#define VKI_NT_AUXV NT_AUXV
+#define VKI_NT_CONTENT NT_CONTENT
+#define VKI_NT_LWPSINFO NT_LWPSINFO
+#define VKI_NT_LWPSTATUS NT_LWPSTATUS
+#define VKI_NT_PLATFORM NT_PLATFORM
+#define VKI_NT_PRCRED NT_PRCRED
+#define VKI_NT_PRFPREG NT_PRFPREG
+#define VKI_NT_PRPRIV NT_PRPRIV
+#define VKI_NT_PRPRIVINFO NT_PRPRIVINFO
+#define VKI_NT_PRPSINFO NT_PRPSINFO
+#define VKI_NT_PRSTATUS NT_PRSTATUS
+#define VKI_NT_PRXREG NT_PRXREG
+#define VKI_NT_PSINFO NT_PSINFO
+#define VKI_NT_PSTATUS NT_PSTATUS
+#define VKI_NT_UTSNAME NT_UTSNAME
+#define VKI_NT_ZONENAME NT_ZONENAME
+#define VKI_PF_R PF_R
+#define VKI_PF_W PF_W
+#define VKI_PF_X PF_X
+#define VKI_PN_XNUM PN_XNUM
+#define VKI_PT_LOAD PT_LOAD
+#define VKI_PT_SUNWBSS PT_SUNWBSS
+#define VKI_SELFMAG SELFMAG
+
+#if	VG_WORDSIZE == 8
+#define VKI_ESZ(x) Elf64_##x
+#elif	VG_WORDSIZE == 4
+#define VKI_ESZ(x) Elf32_##x
+#else
+#error VG_WORDSIZE needs to ==4 or ==8
+#endif
+
+
+#include <sys/errno.h>
+#define VKI_EPERM EPERM
+#define VKI_ENOENT ENOENT
+#define VKI_ESRCH ESRCH
+#define VKI_EINTR EINTR
+#define VKI_EIO EIO
+#define VKI_ENXIO ENXIO
+#define VKI_E2BIG E2BIG
+#define VKI_EBADF EBADF
+#define VKI_ECHILD ECHILD
+#define VKI_ENOEXEC ENOEXEC
+#define VKI_EAGAIN EAGAIN
+#define VKI_ENOMEM ENOMEM
+#define VKI_EACCES EACCES
+#define VKI_EFAULT EFAULT
+#define VKI_ENOTBLK ENOTBLK
+#define VKI_EBUSY EBUSY
+#define VKI_EEXIST EEXIST
+#define VKI_EXDEV EXDEV
+#define VKI_ENODEV ENODEV
+#define VKI_ENOTDIR ENOTDIR
+#define VKI_EISDIR EISDIR
+#define VKI_EINVAL EINVAL
+#define VKI_ENFILE ENFILE
+#define VKI_EMFILE EMFILE
+#define VKI_ENOTTY ENOTTY
+#define VKI_ETXTBSY ETXTBSY
+#define VKI_EFBIG EFBIG
+#define VKI_ENOSPC ENOSPC
+#define VKI_ESPIPE ESPIPE
+#define VKI_EROFS EROFS
+#define VKI_EMLINK EMLINK
+#define VKI_EPIPE EPIPE
+#define VKI_EDOM EDOM
+#define VKI_ERANGE ERANGE
+#define VKI_ENOTSUP ENOTSUP
+#define VKI_ENODATA ENODATA
+#define VKI_EOVERFLOW EOVERFLOW
+#define VKI_ENOSYS ENOSYS
+#define VKI_ERESTART ERESTART
+
+
+#if defined(SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS)
+#include <sys/execx.h>
+#define VKI_EXEC_DESCRIPTOR EXEC_DESCRIPTOR
+#endif /* SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS */
+
+
+#include <sys/fcntl.h>
+#define VKI_O_RDONLY O_RDONLY
+#define VKI_O_WRONLY O_WRONLY
+#define VKI_O_RDWR O_RDWR
+#define VKI_O_APPEND O_APPEND
+#define VKI_O_NONBLOCK O_NONBLOCK
+
+#define VKI_O_CREAT O_CREAT
+#define VKI_O_TRUNC O_TRUNC
+#define VKI_O_EXCL O_EXCL
+#define VKI_O_LARGEFILE O_LARGEFILE
+
+#define VKI_F_DUPFD F_DUPFD
+#define VKI_F_GETFD F_GETFD
+#define VKI_F_SETFD F_SETFD
+#define VKI_F_GETFL F_GETFL
+#define VKI_F_GETXFL F_GETXFL
+#define VKI_F_SETFL F_SETFL
+
+/* SVR3 rfs compability const, declared only if _KERNEL or _KMEMUSER is
+   defined. */
+#if 0
+#define VKI_F_O_GETLK F_O_GETLK
+#endif // 0
+
+#define VKI_F_DUP2FD F_DUP2FD
+
+/* Mostly unused and kernel-unimplemented commands. In case of F_GETOWN and
+   F_GETOWN, they are translated by libc in __fcntl() into other syscalls,
+   that means these two values are never passed to the fcntl handler in the
+   kernel. F_HASREMOTELOCKS is also special, the fcntl kernel handler doesn't
+   know about it but it's used inside the kernel. */
+#if 0
+#define VKI_F_ISSTREAM F_ISSTREAM
+#define VKI_F_PRIV F_PRIV
+#define VKI_F_NPRIV F_NPRIV
+#define VKI_F_QUATACTL F_QUOTACTL
+#define VKI_F_BLOCKS F_BLOCKS
+#define VKI_F_BLKSIZE F_BLKSIZE
+#define VKI_F_GETOWN F_GETOWN
+#define VKI_F_SETOWN F_SETOWN
+#define VKI_F_REVOKE F_REVOKE
+#define VKI_F_HASREMOTELOCKS F_HASREMOTELOCKS
+#endif // 0
+
+#define VKI_F_SETLK F_SETLK
+#define VKI_F_SETLKW F_SETLKW
+#define VKI_F_ALLOCSP F_ALLOCSP
+#define VKI_F_FREESP F_FREESP
+#define VKI_F_GETLK F_GETLK
+#define VKI_F_SETLK_NBMAND F_SETLK_NBMAND
+#if defined(VGP_x86_solaris)
+#define VKI_F_SETLK64 F_SETLK64
+#define VKI_F_SETLKW64 F_SETLKW64
+#define VKI_F_ALLOCSP64 F_ALLOCSP64
+#define VKI_F_FREESP64 F_FREESP64
+#define VKI_F_GETLK64 F_GETLK64
+#define VKI_F_SETLK64_NBMAND F_SETLK64_NBMAND
+#endif // defined(VGP_x86_solaris)
+
+#define VKI_F_SHARE F_SHARE
+#define VKI_F_UNSHARE F_UNSHARE
+#define VKI_F_SHARE_NBMAND F_SHARE_NBMAND
+
+#define VKI_F_BADFD F_BADFD
+
+#define vki_flock flock
+#if defined(VGP_x86_solaris)
+#define vki_flock64 flock64
+#endif // defined(VGP_x86_solaris)
+
+#define VKI_FD_CLOEXEC FD_CLOEXEC
+
+#define vki_fshare fshare
+
+#define VKI_AT_FDCWD AT_FDCWD
+
+
+#include <sys/filio.h>
+#define VKI_FIOSETOWN FIOSETOWN
+#define VKI_FIOGETOWN FIOGETOWN
+
+
+#include <sys/fs/namenode.h>
+#define vki_namefd namefd
+
+
+#include <sys/ioccom.h>
+#define _VKI_IOC_DIR(x) ((x) & (IOC_VOID | IOC_OUT | IOC_IN))
+#define _VKI_IOC_SIZE(x) (((x) >> 16) & IOCPARM_MASK)
+#define _VKI_IOC_NONE 0
+#define _VKI_IOC_READ IOC_OUT
+#define _VKI_IOC_WRITE IOC_IN
+
+
+#include <sys/ipc.h>
+#include <sys/ipc_impl.h>
+#define VKI_IPC_RMID IPC_RMID
+#define VKI_IPC_SET IPC_SET
+#define VKI_IPC_SET64 IPC_SET64
+#define VKI_IPC_STAT IPC_STAT
+#define VKI_IPC_STAT64 IPC_STAT64
+#if defined(SOLARIS_SHM_NEW)
+#define VKI_IPC_XSTAT64 IPC_XSTAT64
+#endif /* SOLARIS_SHM_NEW */
+
+#define vki_semid64_ds semid_ds64
+
+
+#include <sys/lwp.h>
+#define VKI_LWP_DAEMON LWP_DAEMON
+#define VKI_LWP_FSBASE _LWP_FSBASE
+#define VKI_LWP_GSBASE _LWP_GSBASE
+#define VKI_LWP_SETPRIVATE _LWP_SETPRIVATE
+#define VKI_LWP_GETPRIVATE _LWP_GETPRIVATE
+
+
+#include <sys/mman.h>
+#define VKI_PROT_READ PROT_READ
+#define VKI_PROT_WRITE PROT_WRITE
+#define VKI_PROT_EXEC PROT_EXEC
+#define VKI_PROT_NONE PROT_NONE
+
+#define VKI_MAP_SHARED MAP_SHARED
+#define VKI_MAP_PRIVATE MAP_PRIVATE
+#define VKI_MAP_FIXED MAP_FIXED
+#define VKI_MAP_ANONYMOUS MAP_ANONYMOUS
+#define VKI_MAP_ALIGN MAP_ALIGN
+#define VKI_MAP_TEXT MAP_TEXT
+#define VKI_MAP_INITDATA MAP_INITDATA
+
+#define VKI_MMOBJ_ALL_FLAGS MMOBJ_ALL_FLAGS
+#define VKI_MMOBJ_INTERPRET MMOBJ_INTERPRET
+#define VKI_MMOBJ_PADDING MMOBJ_PADDING
+#define VKI_MR_PADDING MR_PADDING
+#define VKI_MR_HDR_ELF MR_HDR_ELF
+#define VKI_MR_GET_TYPE(val) MR_GET_TYPE(val)
+#define vki_mmapobj_result_t mmapobj_result_t
+
+#define vki_memcntl_mha memcntl_mha
+#define VKI_MC_LOCKAS MC_LOCKAS
+#define VKI_MC_UNLOCKAS MC_UNLOCKAS
+#define VKI_MC_HAT_ADVISE MC_HAT_ADVISE
+
+
+#include <sys/mntio.h>
+#define VKI_MNTIOC_GETMNTANY MNTIOC_GETMNTANY
+
+
+#include <sys/mnttab.h>
+#define vki_mntentbuf mntentbuf
+#define vki_mnttab mnttab
+
+
+#include <sys/mount.h>
+#define	VKI_MS_DATA MS_DATA
+#define	VKI_MS_OPTIONSTR MS_OPTIONSTR
+
+
+#include <sys/poll.h>
+#define vki_pollfd pollfd
+#define vki_pollfd_t pollfd_t
+#define vki_nfds_t nfds_t
+
+
+#include <sys/pool_impl.h>
+#define VKI_POOL_STATUSQ POOL_STATUSQ
+#define vki_pool_status_t pool_status_t
+
+
+#include <sys/port.h>
+#include <sys/port_impl.h>
+#define VKI_PORT_SOURCE_FD PORT_SOURCE_FD
+#define VKI_PORT_SOURCE_FILE PORT_SOURCE_FILE
+
+#define vki_port_event_t port_event_t
+#define vki_port_notify_t port_notify_t
+#define vki_file_obj file_obj
+
+#define VKI_PORT_CREATE PORT_CREATE
+#define VKI_PORT_ASSOCIATE PORT_ASSOCIATE
+#define VKI_PORT_DISSOCIATE PORT_DISSOCIATE
+#define VKI_PORT_SEND PORT_SEND
+#define VKI_PORT_SENDN PORT_SENDN
+#define VKI_PORT_GET PORT_GET
+#define VKI_PORT_GETN PORT_GETN
+#define VKI_PORT_ALERT PORT_ALERT
+#define VKI_PORT_DISPATCH PORT_DISPATCH
+
+#define VKI_PORT_SYS_NOPORT PORT_SYS_NOPORT
+#define VKI_PORT_CODE_MASK PORT_CODE_MASK
+
+
+#include <sys/priocntl.h>
+#include <sys/rtpriocntl.h>
+#include <sys/tspriocntl.h>
+#include <sys/iapriocntl.h>
+#include <sys/fsspriocntl.h>
+#include <sys/fxpriocntl.h>
+#define VKI_PC_GETCID PC_GETCID
+#define VKI_PC_GETCLINFO PC_GETCLINFO
+#define VKI_PC_SETPARMS PC_SETPARMS
+#define VKI_PC_GETPARMS PC_GETPARMS
+#define VKI_PC_ADMIN PC_ADMIN
+#define VKI_PC_GETPRIRANGE PC_GETPRIRANGE
+#define VKI_PC_DONICE PC_DONICE
+#define VKI_PC_SETXPARMS PC_SETXPARMS
+#define VKI_PC_GETXPARMS PC_GETXPARMS
+#define VKI_PC_SETDFLCL PC_SETDFLCL
+#define VKI_PC_GETDFLCL PC_GETDFLCL
+#define VKI_PC_DOPRIO PC_DOPRIO
+
+#define VKI_PC_CLNMSZ PC_CLNMSZ
+
+#define VKI_PC_GETNICE PC_GETNICE
+#define VKI_PC_SETNICE PC_SETNICE
+
+#define VKI_PC_GETPRIO PC_GETPRIO
+#define VKI_PC_SETPRIO PC_SETPRIO
+
+#define vki_pcinfo_t pcinfo_t
+#define vki_rtinfo_t rtinfo_t
+#define vki_tsinfo_t tsinfo_t
+#define vki_iainfo_t iainfo_t
+#define vki_fssinfo_t fssinfo_t
+#define vki_fxinfo_t fxinfo_t
+
+#define vki_pcparms_t pcparms_t
+#define vki_pcnice_t pcnice_t
+#define vki_pcprio_t pcprio_t
+#define vki_pc_vaparm_t pc_vaparm_t
+#define vki_pc_vaparms_t pc_vaparms_t
+#define vki_pcpri_t pcpri_t
+
+#define VKI_PC_KY_CLNAME PC_KY_CLNAME
+#define VKI_RT_KY_PRI RT_KY_PRI
+#define VKI_RT_KY_TQSECS RT_KY_TQSECS
+#define VKI_RT_KY_TQNSECS RT_KY_TQNSECS
+#define VKI_RT_KY_TQSIG RT_KY_TQSIG
+#define VKI_TS_KY_UPRILIM TS_KY_UPRILIM
+#define VKI_TS_KY_UPRI TS_KY_UPRI
+#define VKI_IA_KY_UPRILIM IA_KY_UPRILIM
+#define VKI_IA_KY_UPRI IA_KY_UPRI
+#define VKI_IA_KY_MODE IA_KY_MODE
+#define VKI_FSS_KY_UPRILIM FSS_KY_UPRILIM
+#define VKI_FSS_KY_UPRI FSS_KY_UPRI
+#define VKI_FX_KY_UPRILIM FX_KY_UPRILIM
+#define VKI_FX_KY_UPRI FX_KY_UPRI
+#define VKI_FX_KY_TQSECS FX_KY_TQSECS
+#define VKI_FX_KY_TQNSECS FX_KY_TQNSECS
+
+
+#include <sys/priv.h>
+#define vki_priv_impl_info_t priv_impl_info_t
+
+
+#include <sys/proc.h>
+#define VKI_SRUN SRUN
+#define VKI_SSLEEP SSLEEP
+#define VKI_SZOMB SZOMB
+
+
+#include <sys/processor.h>
+#define vki_processorid_t processorid_t
+
+
+/* We want the new /proc definitions. */
+#define _STRUCTURED_PROC 1
+#include <sys/procfs.h>
+#define VKI_MA_READ MA_READ
+#define VKI_MA_WRITE MA_WRITE
+#define VKI_MA_EXEC MA_EXEC
+#define VKI_PRNODEV PRNODEV
+#define VKI_PR_PCINVAL PR_PCINVAL
+#define vki_lwpsinfo_t lwpsinfo_t
+#define vki_lwpstatus_t lwpstatus_t
+#define vki_prcred_t prcred_t
+#define vki_prmap_t prmap_t
+#define vki_prpriv_t prpriv_t
+#define vki_prxmap_t prxmap_t
+#define vki_pstatus_t pstatus_t
+#define vki_psinfo_t psinfo_t
+
+
+#include <sys/procfs_isa.h>
+#if defined(SOLARIS_PRXREGSET_T)
+#define vki_prxregset_t prxregset_t
+#endif /* SOLARIS_PRXREGSET_T */
+
+
+#include <sys/procset.h>
+#define vki_idtype_t idtype_t
+#define VKI_P_PID P_PID
+#define VKI_P_PGID P_PGID
+#define VKI_P_ALL P_ALL
+#define vki_procset_t procset_t
+
+
+#include <sys/regset.h>
+#define vki_prgregset_t prgregset_t
+
+
+#include <sys/resource.h>
+#define VKI_RLIMIT_DATA RLIMIT_DATA
+#define VKI_RLIMIT_STACK RLIMIT_STACK
+#define VKI_RLIMIT_CORE RLIMIT_CORE
+#define VKI_RLIMIT_NOFILE RLIMIT_NOFILE
+#define VKI__RUSAGESYS_GETRUSAGE _RUSAGESYS_GETRUSAGE
+#define VKI__RUSAGESYS_GETRUSAGE_CHLD _RUSAGESYS_GETRUSAGE_CHLD
+#define VKI__RUSAGESYS_GETRUSAGE_LWP _RUSAGESYS_GETRUSAGE_LWP
+#define VKI__RUSAGESYS_GETVMUSAGE _RUSAGESYS_GETVMUSAGE
+#define vki_rlimit rlimit
+#define vki_rlimit64 rlimit64
+#define vki_rusage rusage
+
+
+#include <sys/schedctl.h>
+#define vki_sc_shared sc_shared
+
+
+#include <sys/segments.h>
+#define VKI_GDT_LWPGS GDT_LWPGS
+#if defined(VGP_amd64_solaris)
+/* Values VKI_UCS_SEL/VKI_UDS_SEL can be used only on amd64. On x86, correct
+   %cs/%ds values for a client need to be obtained from the host registers
+   because they are different depending on the running kernel (x86 or amd64).
+ */
+#define VKI_UCS_SEL UCS_SEL
+#define VKI_UDS_SEL UDS_SEL
+#endif
+#define VKI_LWPGS_SEL LWPGS_SEL
+
+
+#include <sys/select.h>
+#define vki_fd_set fd_set
+
+
+#include <sys/priv.h>
+/* Define _KMEMUSER so priv_set is pulled in. */
+#define _KMEMUSER
+#include <sys/priv_impl.h>
+#undef _KMEMUSER
+#define vki_priv_set_t priv_set_t
+#define vki_priv_ptype_t priv_ptype_t
+#define vki_priv_op_t priv_op_t
+
+#define VKI_PRIVSYS_SETPPRIV PRIVSYS_SETPPRIV
+#define VKI_PRIVSYS_GETPPRIV PRIVSYS_GETPPRIV
+#define VKI_PRIVSYS_GETIMPLINFO PRIVSYS_GETIMPLINFO
+#define VKI_PRIVSYS_SETPFLAGS PRIVSYS_SETPFLAGS
+#define VKI_PRIVSYS_GETPFLAGS PRIVSYS_GETPFLAGS
+#define VKI_PRIVSYS_ISSETUGID PRIVSYS_ISSETUGID
+#define VKI_PRIVSYS_PFEXEC_REG PRIVSYS_PFEXEC_REG
+#define VKI_PRIVSYS_PFEXEC_UNREG PRIVSYS_PFEXEC_UNREG
+
+#define vki_priv_impl_info_t priv_impl_info_t
+
+
+#include <sys/sem.h>
+#include <sys/sem_impl.h>
+#define VKI_GETALL GETALL
+#define VKI_GETPID GETPID
+#define VKI_GETNCNT GETNCNT
+#define VKI_GETZCNT GETZCNT
+#define VKI_GETVAL GETVAL
+#define VKI_SEMCTL SEMCTL
+#define VKI_SEMGET SEMGET
+#define VKI_SEMIDS SEMIDS
+#define VKI_SEMOP SEMOP
+#define VKI_SEMTIMEDOP SEMTIMEDOP
+#define VKI_SETALL SETALL
+#define VKI_SETVAL SETVAL
+
+#define vki_semid_ds semid_ds
+#define vki_sembuf sembuf
+
+/* The semun union has to be explicitly declared by the application program
+   (see semctl(2)). */
+union vki_semun {
+   int val;
+   struct semid_ds *buf;
+   ushort_t *array;
+};
+
+
+#include <sys/sendfile.h>
+#define VKI_SENDFILEV SENDFILEV
+#define VKI_SENDFILEV64 SENDFILEV64
+#define VKI_SFV_FD_SELF SFV_FD_SELF
+#define vki_sendfilevec sendfilevec
+#define vki_sendfilevec64 sendfilevec64
+
+
+#include <sys/shm.h>
+#include <sys/shm_impl.h>
+#define VKI_SHMAT SHMAT
+#define VKI_SHMCTL SHMCTL
+#define VKI_SHMDT SHMDT
+#define VKI_SHMGET SHMGET
+#define VKI_SHMIDS SHMIDS
+#if defined(SOLARIS_SHM_NEW)
+#define VKI_SHMADV SHMADV
+#define VKI_SHMGET_OSM SHMGET_OSM
+#define VKI_SHM_ADV_GET SHM_ADV_GET
+#define VKI_SHM_ADV_SET SHM_ADV_SET
+#endif /* SOLARIS_SHM_NEW */
+#define VKI_SHM_LOCK SHM_LOCK
+#define VKI_SHM_RDONLY SHM_RDONLY
+#define VKI_SHM_UNLOCK SHM_UNLOCK
+/* Should be correct, but not really neat. */
+#define VKI_SHMLBA VKI_PAGE_SIZE
+
+#define vki_shmid_ds shmid_ds
+#define vki_shmid_ds64 shmid_ds64
+#define vki_shmid_xds64 shmid_xds64
+
+
+#include <sys/siginfo.h>
+/* This section also contains items defined in sys/machsig.h, this file
+   is directly included in sys/siginfo.h. */
+#define vki_sigevent sigevent
+#define vki_siginfo_t siginfo_t
+
+#define VKI_SI_LWP SI_LWP
+#define VKI_SI_USER SI_USER
+#define VKI_SIGEV_PORT SIGEV_PORT
+#define VKI_SIGEV_THREAD SIGEV_THREAD
+
+/* SIGTRAP signal codes */
+#define VKI_TRAP_BRKPT TRAP_BRKPT
+
+/* SIGCLD signal codes */
+#define VKI_CLD_EXITED CLD_EXITED
+#define VKI_CLD_KILLED CLD_KILLED
+#define VKI_CLD_DUMPED CLD_DUMPED
+#define VKI_CLD_TRAPPED CLD_TRAPPED
+#define VKI_CLD_STOPPED CLD_STOPPED
+#define VKI_CLD_CONTINUED CLD_CONTINUED
+
+/* SIGILL signal codes */
+#define VKI_ILL_ILLOPC ILL_ILLOPC
+#define VKI_ILL_ILLOPN ILL_ILLOPN
+#define VKI_ILL_ILLADR ILL_ILLADR
+#define VKI_ILL_ILLTRP ILL_ILLTRP
+#define VKI_ILL_PRVOPC ILL_PRVOPC
+#define VKI_ILL_PRVREG ILL_PRVREG
+#define VKI_ILL_COPROC ILL_COPROC
+#define VKI_ILL_BADSTK ILL_BADSTK
+
+/* SIGFPE signal codes */
+#define VKI_FPE_INTDIV FPE_INTDIV
+#define VKI_FPE_INTOVF FPE_INTOVF
+#define VKI_FPE_FLTDIV FPE_FLTDIV
+#define VKI_FPE_FLTOVF FPE_FLTOVF
+#define VKI_FPE_FLTUND FPE_FLTUND
+#define VKI_FPE_FLTRES FPE_FLTRES
+#define VKI_FPE_FLTINV FPE_FLTINV
+#define VKI_FPE_FLTSUB FPE_FLTSUB
+#define VKI_FPE_FLTDEN FPE_FLTDEN
+
+/* SIGSEV signal codes */
+#define VKI_SEGV_MAPERR SEGV_MAPERR
+#define VKI_SEGV_ACCERR SEGV_ACCERR
+
+/* SIGBUS signal codes */
+#define VKI_BUS_ADRALN BUS_ADRALN
+#define VKI_BUS_ADRERR BUS_ADRERR
+#define VKI_BUS_OBJERR BUS_OBJERR
+
+
+#include <sys/signal.h>
+/* This section also contains items defined in sys/iso/signal_iso.h, this file
+   is directly included in sys/signal.h. */
+
+/* Next three constants describe the internal representation of sigset_t,
+   there are checks in coregrind/m_vki.c to make sure they are correct. */
+#define _VKI_NSIG 128
+#define _VKI_MAXSIG MAXSIG
+#define _VKI_NSIG_BPW 32
+#define _VKI_NSIG_WORDS (_VKI_NSIG / _VKI_NSIG_BPW)
+#define vki_sigset_t sigset_t
+#define vki_sigaltstack sigaltstack
+/* sigset_t accessor */
+#define sig __sigbits
+
+/* On Solaris we use the same type for passing sigactions to
+   and from the kernel. Hence: */
+typedef struct sigaction vki_sigaction_toK_t;
+typedef struct sigaction vki_sigaction_fromK_t;
+/* sigaction_t accessor */
+#define ksa_handler sa_handler
+
+#define VKI_SA_ONSTACK SA_ONSTACK
+#define VKI_SA_ONESHOT SA_RESETHAND
+#define VKI_SA_NOMASK SA_NODEFER
+
+#define VKI_MINSIGSTKSZ MINSIGSTKSZ
+
+#define VKI_SS_ONSTACK SS_ONSTACK
+#define VKI_SS_DISABLE SS_DISABLE
+
+#define vki_stack_t stack_t
+
+#define VKI_SA_NOCLDSTOP SA_NOCLDSTOP
+#define VKI_SA_RESTART SA_RESTART
+#define VKI_SA_SIGINFO SA_SIGINFO
+#define VKI_SA_NOCLDWAIT SA_NOCLDWAIT
+#define VKI_SA_RESTORER 0 /* Solaris doesn't have this */
+
+#define VKI_SIGHUP SIGHUP               /*  1 */
+#define VKI_SIGINT SIGINT               /*  2 */
+#define VKI_SIGQUIT SIGQUIT             /*  3 */
+#define VKI_SIGILL SIGILL               /*  4 */
+#define VKI_SIGTRAP SIGTRAP             /*  5 */
+#define VKI_SIGABRT SIGABRT             /*  6 */
+#define VKI_SIGEMT SIGEMT               /*  7 */
+#define VKI_SIGFPE SIGFPE               /*  8 */
+#define VKI_SIGKILL SIGKILL             /*  9 */
+#define VKI_SIGBUS SIGBUS               /* 10 */
+#define VKI_SIGSEGV SIGSEGV             /* 11 */
+#define VKI_SIGSYS SIGSYS               /* 12 */
+#define VKI_SIGPIPE SIGPIPE             /* 13 */
+#define VKI_SIGALRM SIGALRM             /* 14 */
+#define VKI_SIGTERM SIGTERM             /* 15 */
+#define VKI_SIGUSR1 SIGUSR1             /* 16 */
+#define VKI_SIGUSR2 SIGUSR2             /* 17 */
+#define VKI_SIGCHLD SIGCHLD             /* 18 */
+#define VKI_SIGPWR SIGPWR               /* 19 */
+#define VKI_SIGWINCH SIGWINCH           /* 20 */
+#define VKI_SIGURG SIGURG               /* 21 */
+#define VKI_SIGIO SIGIO                 /* 22 */
+#define VKI_SIGSTOP SIGSTOP             /* 23 */
+#define VKI_SIGTSTP SIGTSTP             /* 24 */
+#define VKI_SIGCONT SIGCONT             /* 25 */
+#define VKI_SIGTTIN SIGTTIN             /* 26 */
+#define VKI_SIGTTOU SIGTTOU             /* 27 */
+#define VKI_SIGVTALRM SIGVTALRM         /* 28 */
+#define VKI_SIGPROF SIGPROF             /* 29 */
+#define VKI_SIGXCPU SIGXCPU             /* 30 */
+#define VKI_SIGXFSZ SIGXFSZ             /* 31 */
+#define VKI_SIGWAITING SIGWAITING       /* 32 */
+#define VKI_SIGLWP SIGLWP               /* 33 */
+#define VKI_SIGFREEZE SIGFREEZE         /* 34 */
+#define VKI_SIGTHAW SIGTHAW             /* 35 */
+#define VKI_SIGCANCEL SIGCANCEL         /* 36 */
+#define VKI_SIGLOST SIGLOST             /* 37 */
+#define VKI_SIGXRES SIGXRES             /* 38 */
+#define VKI_SIGJVM1 SIGJVM1             /* 39 */
+#define VKI_SIGJVM2 SIGJVM2             /* 40 */
+/* Note that SIGRTMIN and SIGRTMAX are actually macros calling into
+   libc's sysconf() which in turn calls into kernel. And it returns
+   these _SIGRTM* values. So we are safe until someone rebuilds Solaris
+   kernel with different values... */
+#define VKI_SIGRTMIN _SIGRTMIN          /* 41 */
+#define VKI_SIGRTMAX _SIGRTMAX          /* 72 */
+
+#define VKI_SIG_DFL SIG_DFL
+#define VKI_SIG_IGN SIG_IGN
+
+#define VKI_SIG_BLOCK SIG_BLOCK
+#define VKI_SIG_UNBLOCK SIG_UNBLOCK
+#define VKI_SIG_SETMASK SIG_SETMASK
+
+
+#include <sys/socket.h>
+#define vki_sa_family_t sa_family_t
+#define vki_sockaddr sockaddr
+
+#define vki_socklen_t socklen_t
+
+#define VKI_SOCK_STREAM SOCK_STREAM
+
+#define VKI_SO_TYPE SO_TYPE
+#define VKI_SCM_RIGHTS SCM_RIGHTS
+#define VKI_SOL_SOCKET SOL_SOCKET
+
+#define VKI_AF_UNIX AF_UNIX
+#define VKI_AF_INET AF_INET
+#define VKI_AF_INET6 AF_INET6
+
+#define vki_msghdr msghdr
+#define vki_cmsghdr cmsghdr
+
+#define VKI_CMSG_ALIGN(a) _CMSG_DATA_ALIGN(a)
+#define VKI_CMSG_DATA(cmsg) CMSG_DATA(cmsg)
+#define VKI_CMSG_FIRSTHDR(mhdr) CMSG_FIRSTHDR(mhdr)
+#define VKI_CMSG_NXTHDR(mhdr, cmsg) CMSG_NXTHDR(mhdr, cmsg)
+
+
+#include <sys/socketvar.h>
+#define VKI_SOV_DEFAULT SOV_DEFAULT
+
+
+#include <sys/sockio.h>
+#define VKI_SIOCGLIFNUM SIOCGLIFNUM
+
+
+#if defined(SOLARIS_SPAWN_SYSCALL)
+#include <sys/spawn_impl.h>
+#define VKI_FA_CHDIR FA_CHDIR
+#define VKI_FA_CLOSE FA_CLOSE
+#define VKI_FA_CLOSEFROM FA_CLOSEFROM
+#define VKI_FA_DUP2 FA_DUP2
+#define VKI_FA_OPEN FA_OPEN
+#define VKI_POSIX_SPAWN_NOEXECERR_NP POSIX_SPAWN_NOEXECERR_NP
+#define VKI_POSIX_SPAWN_NOSIGCHLD_NP POSIX_SPAWN_NOSIGCHLD_NP
+#define VKI_POSIX_SPAWN_RESETIDS POSIX_SPAWN_RESETIDS
+#define VKI_POSIX_SPAWN_SETPGROUP POSIX_SPAWN_SETPGROUP
+#define VKI_POSIX_SPAWN_SETSCHEDPARAM POSIX_SPAWN_SETSCHEDPARAM
+#define VKI_POSIX_SPAWN_SETSCHEDULER POSIX_SPAWN_SETSCHEDULER
+#define VKI_POSIX_SPAWN_SETSID_NP POSIX_SPAWN_SETSID_NP
+#define VKI_POSIX_SPAWN_SETSIGDEF POSIX_SPAWN_SETSIGDEF
+#define VKI_POSIX_SPAWN_SETSIGIGN_NP POSIX_SPAWN_SETSIGIGN_NP
+#define VKI_POSIX_SPAWN_SETSIGMASK POSIX_SPAWN_SETSIGMASK
+#define VKI_POSIX_SPAWN_SETVAMASK_NP POSIX_SPAWN_SETVAMASK_NP
+#define VKI_POSIX_SPAWN_WAITPID_NP POSIX_SPAWN_WAITPID_NP
+#define VKI_SPAWN_VERSION SPAWN_VERSION
+#define vki_kfile_attr_t kfile_attr_t
+#define vki_kspawn_attr_t kspawn_attr_t
+#define vki_spawn_attr_t spawn_attr_t
+#endif /* SOLARIS_SPAWN_SYSCALL */
+
+
+#include <sys/stat.h>
+#define vki_stat stat
+#define vki_stat64 stat64
+
+#define st_atime_nsec st_atim.tv_nsec
+#define st_mtime_nsec st_mtim.tv_nsec
+#define st_ctime_nsec st_ctim.tv_nsec
+
+#define VKI_S_IFIFO S_IFIFO
+#define VKI_S_ISUID S_ISUID
+#define VKI_S_ISGID S_ISGID
+
+#define VKI_S_IRUSR S_IRUSR
+#define VKI_S_IWUSR S_IWUSR
+#define VKI_S_IXUSR S_IXUSR
+#define VKI_S_IRGRP S_IRGRP
+#define VKI_S_IWGRP S_IWGRP
+#define VKI_S_IXGRP S_IXGRP
+#define VKI_S_IROTH S_IROTH
+#define VKI_S_IWOTH S_IWOTH
+#define VKI_S_IXOTH S_IXOTH
+
+#define VKI_S_ISCHR S_ISCHR
+#define VKI_S_ISDIR S_ISDIR
+#define VKI_S_ISBLK S_ISBLK
+#define VKI_S_ISREG S_ISREG
+#define VKI_S_ISLNK S_ISLNK
+
+
+#include <sys/statfs.h>
+#define vki_statfs statfs
+
+
+#include <sys/statvfs.h>
+#define vki_statvfs statvfs
+#define vki_statvfs64 statvfs64
+
+
+#include <sys/stropts.h>
+#define VKI_I_CANPUT I_CANPUT
+#define VKI_I_PEEK I_PEEK
+#define VKI_I_PUSH I_PUSH
+#define VKI_I_STR I_STR
+#define vki_strbuf strbuf
+#define vki_strioctl strioctl
+#define vki_strpeek strpeek
+
+
+#include <sys/synch.h>
+#define vki_lwp_mutex_t lwp_mutex_t
+#define vki_lwp_cond_t lwp_cond_t
+#define vki_lwp_sema_t lwp_sema_t
+#define vki_lwp_rwlock_t lwp_rwlock_t
+
+/* Defines from the private sys/synch32.h header. */
+#define vki_mutex_flag flags.flag1
+#define vki_mutex_type flags.mbcp_type_un.mtype_rcount.count_type1
+#define vki_mutex_rcount flags.mbcp_type_un.mtype_rcount.count_type2
+#define vki_mutex_owner data
+#define vki_mutex_lockw lock.lock64.pad[7]
+#define vki_mutex_waiters lock.lock64.pad[6]
+#define vki_mutex_ownerpid lock.lock32.ownerpid
+
+#define vki_cond_type flags.type
+#define vki_cond_waiters_kernel flags.flag[3]
+
+#define vki_sema_count count
+#define vki_sema_type type
+#define vki_sema_waiters flags[7]
+
+#define vki_rwlock_readers readers
+#define vki_rwlock_type type
+#define vki_rwlock_owner readercv.data
+#define vki_rwlock_ownerpid writercv.data
+
+
+#include <sys/sysconfig.h>
+#define VKI_CONFIG_OPEN_FILES _CONFIG_OPEN_FILES
+
+
+#include <sys/sysi86.h>
+#define VKI_SI86FPSTART SI86FPSTART
+
+
+#include <sys/systeminfo.h>
+#define VKI_SI_SYSNAME SI_SYSNAME
+#define VKI_SI_HOSTNAME SI_HOSTNAME
+#define VKI_SI_RELEASE SI_RELEASE
+#define VKI_SI_VERSION SI_VERSION
+#define VKI_SI_MACHINE SI_MACHINE
+#define VKI_SI_ARCHITECTURE SI_ARCHITECTURE
+#define VKI_SI_HW_SERIAL SI_HW_SERIAL
+#define VKI_SI_HW_PROVIDER SI_HW_PROVIDER
+#define VKI_SI_SRPC_DOMAIN SI_SRPC_DOMAIN
+
+#define VKI_SI_SET_HOSTNAME SI_SET_HOSTNAME
+#define VKI_SI_SET_SRCP_DOMAIN SI_SET_SRPC_DOMAIN
+
+#define VKI_SI_PLATFORM SI_PLATFORM
+#define VKI_SI_ISALIST SI_ISALIST
+#define VKI_SI_DHCP_CACHE SI_DHCP_CACHE
+#define VKI_SI_ARCHITECTURE_32 SI_ARCHITECTURE_32
+#define VKI_SI_ARCHITECTURE_64 SI_ARCHITECTURE_64
+#define VKI_SI_ARCHITECTURE_K SI_ARCHITECTURE_K
+#define VKI_SI_ARCHITECTURE_NATIVE SI_ARCHITECTURE_NATIVE
+
+
+#include <sys/termio.h>
+#define vki_termio termio
+
+
+#include <sys/termios.h>
+#define vki_termios termios
+#define VKI_TCGETA TCGETA
+#define VKI_TCGETS TCGETS
+#define VKI_TCSETS TCSETS
+#define VKI_TCSETSF TCSETSF
+#define VKI_TCSETSW TCSETSW
+#define VKI_TIOCGPGRP TIOCGPGRP
+#define VKI_TIOCGSID TIOCGSID
+#define VKI_TIOCGWINSZ TIOCGWINSZ
+#define VKI_TIOCNOTTY TIOCNOTTY
+#define VKI_TIOCSCTTY TIOCSCTTY
+#define VKI_TIOCSPGRP TIOCSPGRP
+#define VKI_TIOCSWINSZ TIOCSWINSZ
+#define vki_winsize winsize
+
+
+#include <sys/time.h>
+#define VKI_CLOCK_MONOTONIC CLOCK_MONOTONIC
+
+#define vki_clockid_t clockid_t
+#define vki_timespec timespec
+#define vki_timespec_t timespec_t
+#define vki_timeval timeval
+#define vki_timezone timezone
+#define vki_itimerspec itimerspec
+#define vki_itimerval itimerval
+
+
+#include <sys/times.h>
+#define vki_tms tms
+
+
+#include <sys/tsol/label_macro.h>
+#define vki_bslabel_t bslabel_t
+
+
+/* Do not include sys/tsol/tndb.h if a C++ compiler is used to build a file
+   which includes vki-solaris.h.  This cannot be done because the tndb.h
+   header file uses the template keyword as a member name (on illumos). */
+#if !defined(__cplusplus)
+#include <sys/tsol/tndb.h>
+#define VKI_TNDB_DELETE TNDB_DELETE
+#define VKI_TNDB_FLUSH TNDB_FLUSH
+#define VKI_TNDB_GET TNDB_GET
+#if defined(SOLARIS_TNDB_GET_TNIP)
+#define VKI_TNDB_GET_TNIP TNDB_GET_TNIP
+#endif /* SOLARIS_TNDB_GET_TNIP */
+#define VKI_TNDB_LOAD TNDB_LOAD
+#define vki_tsol_mlpent_t tsol_mlpent_t
+#define vki_tsol_rhent_t tsol_rhent_t
+#define vki_tsol_tpent_t tsol_tpent_t
+#endif /* !__cplusplus */
+
+
+#include <sys/tsol/tsyscall.h>
+#define VKI_TSOL_FGETLABEL TSOL_FGETLABEL
+#define VKI_TSOL_GETLABEL TSOL_GETLABEL
+#define VKI_TSOL_TNMLP TSOL_TNMLP
+#define VKI_TSOL_TNRH TSOL_TNRH
+#define VKI_TSOL_TNRHTP TSOL_TNRHTP
+#define VKI_TSOL_SYSLABELING TSOL_SYSLABELING
+#if defined(SOLARIS_TSOL_CLEARANCE)
+#define VKI_TSOL_GETCLEARANCE TSOL_GETCLEARANCE
+#define VKI_TSOL_SETCLEARANCE TSOL_SETCLEARANCE
+#endif /* SOLARIS_TSOL_CLEARANCE */
+
+
+#include <sys/ttold.h>
+#define vki_sgttyb sgttyb
+
+
+#include <sys/ucontext.h>
+/* This section also contains items defined in sys/regset.h, this file
+   is directly included in sys/ucontext.h. */
+#if defined(VGP_x86_solaris)
+#define VKI_SS SS
+#define VKI_UESP UESP
+#define VKI_EFL EFL
+#define VKI_CS CS
+#define VKI_EIP EIP
+#define VKI_ERR 13 /* ERR */
+#define VKI_TRAPNO TRAPNO
+#define VKI_EAX EAX
+#define VKI_ECX ECX
+#define VKI_EDX EDX
+#define VKI_EBX EBX
+#define VKI_ESP ESP
+#define VKI_EBP EBP
+#define VKI_ESI ESI
+#define VKI_EDI EDI
+#define VKI_DS DS
+#define VKI_ES ES
+#define VKI_FS FS
+#define VKI_GS GS
+
+/* Definitions for compatibility with amd64-solaris. */
+#define VKI_REG_ERR VKI_ERR
+#define VKI_REG_TRAPNO VKI_TRAPNO
+
+#define VKI_EFLAGS_ID_BIT (1 << 21)
+
+#elif defined(VGP_amd64_solaris)
+#define VKI_REG_GSBASE REG_GSBASE
+#define VKI_REG_FSBASE REG_FSBASE
+#define VKI_REG_DS REG_DS
+#define VKI_REG_ES REG_ES
+#define VKI_REG_GS REG_GS
+#define VKI_REG_FS REG_FS
+#define VKI_REG_SS REG_SS
+#define VKI_REG_RSP REG_RSP
+#define VKI_REG_RFL REG_RFL
+#define VKI_REG_CS REG_CS
+#define VKI_REG_RIP REG_RIP
+#define VKI_REG_ERR REG_ERR
+#define VKI_REG_TRAPNO REG_TRAPNO
+#define VKI_REG_RAX REG_RAX
+#define VKI_REG_RCX REG_RCX
+#define VKI_REG_RDX REG_RDX
+#define VKI_REG_RBX REG_RBX
+#define VKI_REG_RBP REG_RBP
+#define VKI_REG_RSI REG_RSI
+#define VKI_REG_RDI REG_RDI
+#define VKI_REG_R8 REG_R8
+#define VKI_REG_R9 REG_R9
+#define VKI_REG_R10 REG_R10
+#define VKI_REG_R11 REG_R11
+#define VKI_REG_R12 REG_R12
+#define VKI_REG_R13 REG_R13
+#define VKI_REG_R14 REG_R14
+#define VKI_REG_R15 REG_R15
+
+#define VKI_RFLAGS_ID_BIT (1 << 21)
+
+#else
+#error "Unknown platform"
+#endif
+
+#define vki_fpregset_t fpregset_t
+
+/* Don't polute global namespace so much. */
+#undef r_r0
+#undef r_r1
+#undef r_fp
+#undef r_sp
+#undef r_pc
+#undef r_ps
+#undef ERR
+
+#if defined(VGP_x86_solaris)
+/* The ucontext structure as defined in the SYSV ABI for Intel386. Illumos
+   contains exactly this definition. Solaris 11 utilizes two uc_filler values
+   -> "xrs_t uc_xrs; long uc_filler[3];". The xrs_t structure is used for the
+   AVX support. We define our own ucontext structure because all five
+   uc_filler values need to be available in VG_(save_context). Note that
+   Valgrind doesn't support AVX on the x86 platform. */
+typedef struct sysv_ucontext sysv_ucontext_t;
+struct sysv_ucontext {
+   unsigned long uc_flags;
+   sysv_ucontext_t *uc_link;
+   sigset_t uc_sigmask;
+   stack_t uc_stack;
+   mcontext_t uc_mcontext;
+   long uc_filler[5];
+};
+#define VKI_UC_GUEST_CC_OP(uc) (*(UWord*)&(uc)->uc_filler[0])
+#define VKI_UC_GUEST_CC_NDEP(uc) (*(UWord*)&(uc)->uc_filler[1])
+#define VKI_UC_GUEST_CC_DEP1(uc) (*(UWord*)&(uc)->uc_filler[2])
+#define VKI_UC_GUEST_CC_DEP2(uc) (*(UWord*)&(uc)->uc_filler[3])
+#define VKI_UC_GUEST_EFLAGS_NEG(uc) \
+   (*(UWord*)&(uc)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.__pad[0])
+#define VKI_UC_GUEST_EFLAGS_CHECKSUM(uc) \
+   (*(UWord*)&(uc)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.__pad[1])
+#define VKI_UC_SIGNO(uc) (*(UWord*)&(uc)->uc_filler[4])
+#define VKI_UC_SIGNO_CONST(uc) (*(const UWord*)&(uc)->uc_filler[4])
+
+#define vki_ucontext_t sysv_ucontext_t
+#define vki_ucontext sysv_ucontext
+
+#elif defined(VGP_amd64_solaris)
+/* The ucontext structure on Solaris has only 3 elements available in uc_filler
+   which is not enough to store all required information. Therefore padding
+   area in mcontext's FPU regset is used. */
+#define vki_ucontext ucontext
+#define vki_ucontext_t ucontext_t
+#define VKI_UC_MC_FP_FX_IGN2(uc) \
+    (uc)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.__fx_ign2
+#define VKI_UC_GUEST_CC_OP(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[0])
+#define VKI_UC_GUEST_CC_NDEP(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[1])
+#define VKI_UC_GUEST_CC_DEP1(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[2])
+#define VKI_UC_GUEST_CC_DEP2(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[3])
+#define VKI_UC_GUEST_RFLAGS_NEG(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[4])
+#define VKI_UC_GUEST_RFLAGS_CHECKSUM(uc) \
+   (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[5])
+#define VKI_UC_SIGNO(uc) (*(UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[6])
+#define VKI_UC_SIGNO_CONST(uc) (*(const UWord *) &VKI_UC_MC_FP_FX_IGN2(uc)[6])
+
+#else
+#error "Unknown platform"
+#endif
+
+#define vki_fpchip_state fpchip_state
+
+#define VKI_GETCONTEXT GETCONTEXT
+#define VKI_SETCONTEXT SETCONTEXT
+#define VKI_GETUSTACK GETUSTACK
+#define VKI_SETUSTACK SETUSTACK
+
+#define VKI_UC_SIGMASK UC_SIGMASK
+#define VKI_UC_STACK UC_STACK
+#define VKI_UC_CPU UC_CPU
+#define VKI_UC_FPU UC_FPU
+#define VKI_UC_ALL UC_ALL
+
+#include <sys/uio.h>
+#define vki_iovec iovec
+
+
+#include <sys/un.h>
+#define vki_sockaddr_un sockaddr_un
+
+
+#if defined(SOLARIS_UUIDSYS_SYSCALL)
+#include <sys/uuid.h>
+#define vki_uuid uuid
+#endif /* SOLARIS_UUIDSYS_SYSCALL */
+
+
+#include <sys/utsname.h>
+#define vki_utsname utsname
+/* Add another alias for utsname, used in syswrap-generic.c. */
+#define vki_new_utsname utsname
+
+
+#include <sys/vm_usage.h>
+#define vki_vmusage_t vmusage_t
+
+
+#include <sys/wait.h>
+#define VKI_WEXITED WEXITED
+#define VKI_WTRAPPED WTRAPPED
+
+#define VKI_WSTOPFLG WSTOPFLG
+#define VKI_WCONTFLG WCONTFLG
+#define VKI_WCOREFLG WCOREFLG
+
+
+#include <sys/zone.h>
+#define VKI_ZONE_ADD_DATALINK ZONE_ADD_DATALINK
+#define VKI_ZONE_ATTR_NAME ZONE_ATTR_NAME
+#define VKI_ZONE_BOOT ZONE_BOOT
+#define VKI_ZONE_CHECK_DATALINK ZONE_CHECK_DATALINK
+#define VKI_ZONE_CREATE ZONE_CREATE
+#define VKI_ZONE_DEL_DATALINK ZONE_DEL_DATALINK
+#define VKI_ZONE_DESTROY ZONE_DESTROY
+#define VKI_ZONE_ENTER ZONE_ENTER
+#define VKI_ZONE_GETATTR ZONE_GETATTR
+#define VKI_ZONE_LIST ZONE_LIST
+#define VKI_ZONE_LIST_DATALINK ZONE_LIST_DATALINK
+#define VKI_ZONE_LOOKUP ZONE_LOOKUP
+#define VKI_ZONE_SETATTR ZONE_SETATTR
+#define VKI_ZONE_SHUTDOWN ZONE_SHUTDOWN
+#if defined(SOLARIS_ZONE_DEFUNCT)
+#define VKI_ZONE_GETATTR_DEFUNCT ZONE_GETATTR_DEFUNCT
+#define VKI_ZONE_LIST_DEFUNCT ZONE_LIST_DEFUNCT
+#endif /* SOLARIS_ZONE_DEFUNCT */
+#define VKI_ZONENAME_MAX ZONENAME_MAX
+#define vki_zone_def zone_def
+#define vki_zoneid_t zoneid_t
+
+
+/* from <sys/ucred.h> which is consolidation private */
+#define VKI_UCREDSYS_UCREDGET 0
+#define VKI_UCREDSYS_GETPEERUCRED 1
+struct ucred_s {
+   vki_uint32_t uc_size;     /* Size of the full structure */
+   vki_uint32_t uc_credoff;  /* Credential offset */
+   vki_uint32_t uc_privoff;  /* Privilege offset */
+   vki_pid_t    uc_pid;      /* Process id */
+   vki_uint32_t uc_audoff;   /* Audit info offset */
+   vki_zoneid_t uc_zoneid;   /* Zone id */
+   vki_projid_t uc_projid;   /* Project id */
+   vki_uint32_t uc_labeloff; /* label offset */
+};
+
+
+/* from sys/old_procfs.h which clashes with sys/procfs.h */
+
+#define VKI_ELF_OLD_PR_PCINVAL 0x0080
+
+typedef struct vki_elf_prpsinfo {
+   char		pr_state;	/* numeric process state (see pr_sname) */
+   char		pr_sname;	/* printable character representing pr_state */
+   char		pr_zomb;	/* !=0: process terminated but not waited for */
+   char		pr_nice;	/* nice for cpu usage */
+   vki_uint_t	pr_flag;	/* process flags */
+   vki_uid_t	pr_uid;		/* real user id */
+   vki_gid_t	pr_gid;		/* real group id */
+   vki_pid_t	pr_pid;		/* unique process id */
+   vki_pid_t	pr_ppid;	/* process id of parent */
+   vki_pid_t	pr_pgrp;	/* pid of process group leader */
+   vki_pid_t	pr_sid;		/* session id */
+   vki_caddr_t	pr_addr;	/* physical address of process */
+   vki_size_t	pr_size;	/* size of process image in pages */
+   vki_size_t	pr_rssize;	/* resident set size in pages */
+   vki_caddr_t	pr_wchan;	/* wait addr for sleeping process */
+   vki_timespec_t pr_start;	/* process start time, sec+nsec since epoch */
+   vki_timespec_t pr_time;	/* usr+sys cpu time for this process */
+   int		pr_pri;		/* priority, high value is high priority */
+   char		pr_oldpri;	/* pre-SVR4, low value is high priority */
+   char		pr_cpu;		/* pre-SVR4, cpu usage for scheduling */
+   vki_o_dev_t	pr_ottydev;	/* short tty device number */
+   vki_dev_t	pr_lttydev;	/* controlling tty device (PRNODEV if none) */
+   char		pr_clname[8];	/* scheduling class name */
+   char		pr_fname[16];	/* last component of execed pathname */
+   char		pr_psargs[80];	/* initial characters of arg list */
+   short	pr_syscall;	/* system call number (if in syscall) */
+   short	pr_fill;
+   vki_timespec_t pr_ctime;	/* usr+sys cpu time for reaped children */
+   vki_size_t	pr_bysize;	/* size of process image in bytes */
+   vki_size_t	pr_byrssize;	/* resident set size in bytes */
+   int		pr_argc;	/* initial argument count */
+   char		**pr_argv;	/* initial argument vector */
+   char		**pr_envp;	/* initial environment vector */
+   int		pr_wstat;	/* if zombie, the wait() status */
+                	        /* The following percent numbers are 16-bit binary */
+                	        /* fractions [0 .. 1] with the binary point to the */
+                	        /* right of the high-order bit (one == 0x8000) */
+   ushort_t 	pr_pctcpu;	/* % of recent cpu time, one or all lwps */
+   ushort_t 	pr_pctmem;	/* % of of system memory used by the process */
+   vki_uid_t	pr_euid;	/* effective user id */
+   vki_gid_t	pr_egid;	/* effective group id */
+   vki_id_t	pr_aslwpid;	/* historical; now always zero */
+   char		pr_dmodel;	/* data model of the process */
+   char		pr_pad[3];
+   int		pr_filler[6];	/* for future expansion */
+} vki_elf_prpsinfo_t;
+
+typedef struct vki_elf_prstatus {
+   int		pr_flags;	/* Flags (see below) */
+   short	pr_why;		/* Reason for process stop (if stopped) */
+   short	pr_what;	/* More detailed reason */
+   vki_siginfo_t pr_info;	/* Info associated with signal or fault */
+   short	pr_cursig;	/* Current signal */
+   ushort_t 	pr_nlwp;	/* Number of lwps in the process */
+   vki_sigset_t pr_sigpend;	/* Set of signals pending to the process */
+   vki_sigset_t pr_sighold;	/* Set of signals held (blocked) by the lwp */
+   struct vki_sigaltstack pr_altstack; /* Alternate signal stack info */
+   struct sigaction pr_action;	/* Signal action for current signal */
+   vki_pid_t	pr_pid;		/* Process id */
+   vki_pid_t	pr_ppid;	/* Parent process id */
+   vki_pid_t	pr_pgrp;	/* Process group id */
+   vki_pid_t	pr_sid;		/* Session id */
+   vki_timespec_t pr_utime;	/* Process user cpu time */
+   vki_timespec_t pr_stime;	/* Process system cpu time */
+   vki_timespec_t pr_cutime;	/* Sum of children's user times */
+   vki_timespec_t pr_cstime;	/* Sum of children's system times */
+   char	pr_clname[PRCLSZ]; 	/* Scheduling class name */
+   short	pr_syscall;	/* System call number (if in syscall) */
+   short	pr_nsysarg;	/* Number of arguments to this syscall */
+   long	pr_sysarg[PRSYSARGS];	/* Arguments to this syscall */
+   vki_id_t	pr_who;		/* Specific lwp identifier */
+   vki_sigset_t pr_lwppend;	/* Set of signals pending to the lwp */
+   struct vki_ucontext *pr_oldcontext; /* Address of previous ucontext */
+   vki_caddr_t	pr_brkbase;	/* Address of the process heap */
+   vki_size_t	pr_brksize;	/* Size of the process heap, in bytes */
+   vki_caddr_t	pr_stkbase;	/* Address of the process stack */
+   vki_size_t	pr_stksize;	/* Size of the process stack, in bytes */
+   short	pr_processor;	/* processor which last ran this LWP */
+   short	pr_bind;	/* processor LWP bound to or PBIND_NONE */
+   long		pr_instr;	/* Current instruction */
+   vki_prgregset_t pr_reg;	/* General registers */
+} vki_elf_prstatus_t;
+
+
+/* Signal frames. */
+#if defined(VGP_x86_solaris)
+struct vki_sigframe {
+   /* First four words look like a call to a 3-arg x86 function. */
+   void *return_addr;
+   int a1_signo;
+   vki_siginfo_t *a2_siginfo;
+   vki_ucontext_t *a3_ucontext;
+   /* Saved ucontext and siginfo. */
+   vki_ucontext_t ucontext;
+   vki_siginfo_t siginfo;
+};
+
+#elif defined(VGP_amd64_solaris)
+struct vki_sigframe {
+   void *return_addr;
+   long a1_signo;
+   vki_siginfo_t *a2_siginfo;
+   /* Saved ucontext and siginfo. */
+   vki_ucontext_t ucontext;
+   vki_siginfo_t siginfo;
+};
+
+#else
+#error "Unknown platform"
+#endif
+typedef struct vki_sigframe vki_sigframe_t;
+
+#endif // __VKI_SOLARIS_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/massif/tests/malloc_usable.c b/massif/tests/malloc_usable.c
index 1a8b863..0182e6c 100644
--- a/massif/tests/malloc_usable.c
+++ b/massif/tests/malloc_usable.c
@@ -5,7 +5,7 @@
 
 int main(void)
 {
-#  if !defined(VGO_darwin)
+#  if !defined(VGO_darwin) && !defined(VGO_solaris)
    // Because our allocations are in multiples of 8 or 16, 99 will round up
    // to 104 or 112.
    int* x = malloc(99);
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index dc7b5ae..db235a8 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -1844,6 +1844,12 @@
       ocache_sarp_Clear_Origins ( a, len );
 }
 
+__attribute__((unused))
+static void make_mem_defined_w_tid ( Addr a, SizeT len, ThreadId tid )
+{
+   MC_(make_mem_defined)(a, len);
+}
+
 /* For each byte in [a,a+len), if the byte is addressable, make it be
    defined, but if it isn't addressible, leave it alone.  In other
    words a version of MC_(make_mem_defined) that doesn't mess with
@@ -4199,6 +4205,109 @@
 
 
 /*------------------------------------------------------------*/
+/*--- Register-memory event handlers                       ---*/
+/*------------------------------------------------------------*/
+
+static void mc_copy_mem_to_reg ( CorePart part, ThreadId tid, Addr a,
+                                 PtrdiffT guest_state_offset, SizeT size )
+{
+   SizeT i;
+   UChar vbits8;
+   Int offset;
+   UInt d32;
+
+   /* Slow loop. */
+   for (i = 0; i < size; i++) {
+      get_vbits8( a+i, &vbits8 );
+      VG_(set_shadow_regs_area)( tid, 1/*shadowNo*/, guest_state_offset+i,
+                                 1, &vbits8 );
+   }
+
+   if (MC_(clo_mc_level) != 3)
+      return;
+
+   /* Track origins. */
+   offset = MC_(get_otrack_shadow_offset)( guest_state_offset, size );
+   if (offset == -1)
+      return;
+
+   switch (size) {
+   case 1:
+      d32 = MC_(helperc_b_load1)( a );
+      break;
+   case 2:
+      d32 = MC_(helperc_b_load2)( a );
+      break;
+   case 4:
+      d32 = MC_(helperc_b_load4)( a );
+      break;
+   case 8:
+      d32 = MC_(helperc_b_load8)( a );
+      break;
+   case 16:
+      d32 = MC_(helperc_b_load16)( a );
+      break;
+   case 32:
+      d32 = MC_(helperc_b_load32)( a );
+      break;
+   default:
+      tl_assert(0);
+   }
+
+   VG_(set_shadow_regs_area)( tid, 2/*shadowNo*/, offset, 4, (UChar*)&d32 );
+}
+
+static void mc_copy_reg_to_mem ( CorePart part, ThreadId tid,
+                                 PtrdiffT guest_state_offset, Addr a,
+                                 SizeT size )
+{
+   SizeT i;
+   UChar vbits8;
+   Int offset;
+   UInt d32;
+
+   /* Slow loop. */
+   for (i = 0; i < size; i++) {
+      VG_(get_shadow_regs_area)( tid, &vbits8, 1/*shadowNo*/,
+                                 guest_state_offset+i, 1 );
+      set_vbits8( a+i, vbits8 );
+   }
+
+   if (MC_(clo_mc_level) != 3)
+      return;
+
+   /* Track origins. */
+   offset = MC_(get_otrack_shadow_offset)( guest_state_offset, size );
+   if (offset == -1)
+      return;
+
+   VG_(get_shadow_regs_area)( tid, (UChar*)&d32, 2/*shadowNo*/, offset, 4 );
+   switch (size) {
+   case 1:
+      MC_(helperc_b_store1)( a, d32 );
+      break;
+   case 2:
+      MC_(helperc_b_store2)( a, d32 );
+      break;
+   case 4:
+      MC_(helperc_b_store4)( a, d32 );
+      break;
+   case 8:
+      MC_(helperc_b_store8)( a, d32 );
+      break;
+   case 16:
+      MC_(helperc_b_store16)( a, d32 );
+      break;
+   case 32:
+      MC_(helperc_b_store32)( a, d32 );
+      break;
+   default:
+      tl_assert(0);
+   }
+}
+
+
+/*------------------------------------------------------------*/
 /*--- Some static assertions                               ---*/
 /*------------------------------------------------------------*/
 
@@ -7046,10 +7155,16 @@
    // directly with brk(), not with sbrk(), perhaps it would be reasonable to
    // just mark all memory it allocates as defined.]
    //
+#  if !defined(VGO_solaris)
    if (MC_(clo_mc_level) == 3)
       VG_(track_new_mem_brk)         ( mc_new_mem_w_tid_make_ECU );
    else
       VG_(track_new_mem_brk)         ( mc_new_mem_w_tid_no_ECU );
+#  else
+   // On Solaris, brk memory has to be marked as defined, otherwise we get
+   // many false positives.
+   VG_(track_new_mem_brk)         ( make_mem_defined_w_tid );
+#  endif
 
    /* This origin tracking cache is huge (~100M), so only initialise
       if we need it. */
@@ -7371,6 +7486,11 @@
    VG_(track_post_reg_write)                  ( mc_post_reg_write );
    VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
 
+   if (MC_(clo_mc_level) >= 2) {
+      VG_(track_copy_mem_to_reg)  ( mc_copy_mem_to_reg );
+      VG_(track_copy_reg_to_mem)  ( mc_copy_reg_to_mem );
+   }
+
    VG_(needs_watchpoint)          ( mc_mark_unaddressable_for_watchpoint );
 
    init_shadow_memory();
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index f177167..86967b6 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -27,6 +27,9 @@
 if VGCONF_OS_IS_DARWIN
 SUBDIRS += darwin
 endif
+if VGCONF_OS_IS_SOLARIS
+SUBDIRS += solaris
+endif
 
 # Platform-specific tests
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
@@ -35,9 +38,16 @@
 if VGCONF_PLATFORMS_INCLUDE_AMD64_LINUX
 SUBDIRS += amd64-linux
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_SOLARIS
+SUBDIRS += x86-solaris
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_SOLARIS
+SUBDIRS += amd64-solaris
+endif
 
 DIST_SUBDIRS = x86 amd64 ppc32 ppc64 s390x linux \
-		darwin x86-linux amd64-linux common .
+		darwin solaris x86-linux amd64-linux x86-solaris amd64-solaris \
+		common .
 
 dist_noinst_SCRIPTS = \
 	filter_addressable \
@@ -98,7 +108,7 @@
 	describe-block.stderr.exp describe-block.vgtest \
 	descr_belowsp.vgtest descr_belowsp.stderr.exp \
 	doublefree.stderr.exp doublefree.vgtest \
-	dw4.vgtest dw4.stderr.exp dw4.stdout.exp \
+	dw4.vgtest dw4.stderr.exp dw4.stderr.exp-solaris dw4.stdout.exp \
 	err_disable1.vgtest err_disable1.stderr.exp \
 	err_disable2.vgtest err_disable2.stderr.exp \
 	err_disable3.vgtest err_disable3.stderr.exp \
@@ -219,13 +229,13 @@
 	resvn_stack.stderr.exp resvn_stack.vgtest \
 	sbfragment.stdout.exp sbfragment.stderr.exp sbfragment.vgtest \
 	sem.stderr.exp sem.vgtest \
-	sendmsg.stderr.exp sendmsg.vgtest \
+	sendmsg.stderr.exp sendmsg.stderr.exp-solaris sendmsg.vgtest \
 	sh-mem.stderr.exp sh-mem.vgtest \
 	sh-mem-random.stderr.exp sh-mem-random.stdout.exp64 \
 	sh-mem-random.stdout.exp sh-mem-random.vgtest \
 	sigaltstack.stderr.exp sigaltstack.vgtest \
 	sigkill.stderr.exp sigkill.stderr.exp-darwin sigkill.stderr.exp-mips32 \
-	sigkill.vgtest \
+	    sigkill.stderr.exp-solaris sigkill.vgtest \
 	signal2.stderr.exp signal2.stdout.exp signal2.vgtest \
 	sigprocmask.stderr.exp sigprocmask.stderr.exp2 sigprocmask.vgtest \
 	static_malloc.stderr.exp static_malloc.vgtest \
@@ -268,7 +278,8 @@
 	vcpu_bz2.stdout.exp vcpu_bz2.stderr.exp vcpu_bz2.vgtest \
 	vcpu_fbench.stdout.exp vcpu_fbench.stderr.exp vcpu_fbench.vgtest \
 	vcpu_fnfns.stdout.exp vcpu_fnfns.stdout.exp-glibc28-amd64 \
-	vcpu_fnfns.stdout.exp-darwin vcpu_fnfns.stderr.exp vcpu_fnfns.vgtest \
+	vcpu_fnfns.stdout.exp-darwin vcpu_fnfns.stdout.exp-solaris \
+	vcpu_fnfns.stderr.exp vcpu_fnfns.vgtest \
 	wcs.vgtest wcs.stderr.exp wcs.stdout.exp \
 	wrap1.vgtest wrap1.stdout.exp wrap1.stderr.exp \
 	wrap2.vgtest wrap2.stdout.exp wrap2.stderr.exp \
@@ -279,7 +290,7 @@
 	wrap7.vgtest wrap7.stdout.exp wrap7.stderr.exp \
 	wrap8.vgtest wrap8.stdout.exp wrap8.stderr.exp \
 	wrap8.stdout.exp-ppc64 wrap8.stderr.exp-ppc64 \
-	writev1.stderr.exp writev1.vgtest \
+	writev1.stderr.exp writev1.stderr.exp-solaris writev1.vgtest \
 	xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \
 	threadname.vgtest threadname.stderr.exp \
 	threadname_xml.vgtest threadname_xml.stderr.exp
@@ -323,7 +334,6 @@
 	leak-pool \
 	leak-tree \
 	leak-segv-jmp \
-	long_namespace_xml \
 	long-supps \
 	mallinfo \
 	malloc_free_fill \
@@ -365,6 +375,11 @@
 	wrap1 wrap2 wrap3 wrap4 wrap5 wrap6 wrap7 wrap7so.so wrap8 \
 	writev1
 
+if !SOLARIS_SUN_STUDIO_AS
+# Sun Studio assembler fails on "IDENT too long"
+check_PROGRAMS += long_namespace_xml
+endif
+
 if DWARF4
 check_PROGRAMS += dw4
 endif
@@ -395,6 +410,10 @@
 atomic_incs_CFLAGS = $(AM_CFLAGS)
 endif
 
+if VGCONF_OS_IS_SOLARIS
+buflen_check_LDADD	= -lsocket -lnsl
+endif
+
 leak_cpp_interior_SOURCES	= leak_cpp_interior.cpp
 
 demangle_SOURCES = demangle.cpp
@@ -404,8 +423,12 @@
 descr_belowsp_LDADD     = -lpthread
 err_disable3_LDADD 	= -lpthread
 err_disable4_LDADD 	= -lpthread
+err_disable4_CFLAGS	= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+err_disable4_CFLAGS	+= -D_XOPEN_SOURCE=500
+endif
 reach_thread_register_CFLAGS	= $(AM_CFLAGS) -O2
-reach_thread_register_LDADD     = -lpthread
+reach_thread_register_LDADD	= -lpthread
 thread_alloca_LDADD     = -lpthread
 threadname_LDADD 	= -lpthread
 
@@ -428,6 +451,11 @@
 
 manuel1_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
 
+memalign2_CFLAGS	= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+memalign2_CFLAGS	+= -std=c99 -D__EXTENSIONS__
+endif
+
 memcmptest_CFLAGS	= $(AM_CFLAGS) -fno-builtin-memcmp
 
 mismatches_SOURCES	= mismatches.cpp
@@ -435,6 +463,10 @@
 new_nothrow_SOURCES 	= new_nothrow.cpp
 new_override_SOURCES 	= new_override.cpp
 
+if VGCONF_OS_IS_SOLARIS
+null_socket_LDADD	= -lsocket -lnsl
+endif
+
 origin1_yes_CFLAGS      = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
 
 origin2_not_quite_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
@@ -452,6 +484,12 @@
 # because then we can't intercept it
 overlap_CFLAGS		= $(AM_CFLAGS) -fno-builtin-memcpy -fno-builtin-strcpy
 
+sendmsg_CFLAGS		= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+sendmsg_CFLAGS		+= -D_XOPEN_SOURCE=500
+sendmsg_LDADD		= -lsocket -lnsl
+endif
+
 str_tester_CFLAGS	= $(AM_CFLAGS) -Wno-shadow
 
 supp_CFLAGS             = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@
@@ -525,3 +563,4 @@
 				-Wl,-soname -Wl,wrap7so.so
 endif
 
+xml1_CFLAGS             = $(AM_CFLAGS) -D_GNU_SOURCE
diff --git a/memcheck/tests/amd64-solaris/Makefile.am b/memcheck/tests/amd64-solaris/Makefile.am
new file mode 100644
index 0000000..c44ec21
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/Makefile.am
@@ -0,0 +1,23 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = filter_stderr
+
+EXTRA_DIST = \
+	context_fpu.stderr.exp context_fpu.stdout.exp context_fpu.vgtest \
+	context_gpr.stderr.exp context_gpr.stdout.exp context_gpr.vgtest \
+	context_rflags.stderr.exp context_rflags.stdout.exp context_rflags.vgtest \
+	context_rflags2.stderr.exp context_rflags2.stdout.exp context_rflags2.vgtest \
+	context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest
+
+check_PROGRAMS = \
+	context_fpu \
+	context_gpr \
+	context_rflags \
+	context_rflags2 \
+	context_sse
+
+AM_CFLAGS    += @FLAG_M64@
+AM_CXXFLAGS  += @FLAG_M64@
+AM_CCASFLAGS += @FLAG_M64@
+
diff --git a/memcheck/tests/amd64-solaris/context_fpu.c b/memcheck/tests/amd64-solaris/context_fpu.c
new file mode 100644
index 0000000..08f8347
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_fpu.c
@@ -0,0 +1,109 @@
+/* Test if x87 FP valus are correctly propagated in and out of a signal
+   handler and also check that the same applies for uninitialised values and
+   their origins. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+static float inhandler[8];
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   int i;
+
+   si = *sip;
+   uc = *ucp;
+
+   /* Reset the FP stack so it's possible to push other values onto it.  (It
+      is fully filled in main() before triggering the signal handler).  Note
+      that VEX also clears all FP values when the finit instruction is
+      executed.  This provides another level of validation that the restore
+      code is correct. */
+   __asm__ __volatile__(
+      "finit\n");
+
+   /* Convert 80b values in mcontext to 32b values in the inhandler array. */
+   for (i = 0; i < 8; i++) {
+      __asm__ __volatile__(
+         "fldt   %[in]\n"
+         "fstps  %[out]\n"
+         : [out] "=m" (inhandler[i])
+         : [in] "m" (*(char*)&ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st[i]));
+   }
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   float out[8];
+   float x0;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   float *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set values in the FP stack. */
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+
+      /* Trigger the signal handler. */
+      "syscall\n"
+      "fstps  0x00 + %[out]\n"
+      "fstps  0x04 + %[out]\n"
+      "fstps  0x08 + %[out]\n"
+      "fstps  0x0c + %[out]\n"
+      "fstps  0x10 + %[out]\n"
+      "fstps  0x14 + %[out]\n"
+      "fstps  0x18 + %[out]\n"
+      "fstps  0x1c + %[out]\n"
+      : [out] "=m" (out[0])
+      : "a" (SYS_kill), "D" (pid), "S" (SIGUSR1), [x0] "m" (x0)
+      : "rdx", "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
+          inhandler[0], inhandler[2], inhandler[4], inhandler[6]);
+   /* Check that inhandler[1], inhandler[3], inhandler[5] and inhandler[7]
+      contain uninitialised values (origin is px[0]). */
+   if (inhandler[1] || inhandler[3] || inhandler[5] || inhandler[7])
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
+          out[0], out[2], out[4], out[6]);
+   /* Check that out[1], out[3], out[5] and out[7] contain uninitialised
+      values (origin is px[0]). */
+   if (out[1] || out[3] || out[5] || out[7])
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/amd64-solaris/context_fpu.stderr.exp b/memcheck/tests/amd64-solaris/context_fpu.stderr.exp
new file mode 100644
index 0000000..46c8731
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_fpu.stderr.exp
@@ -0,0 +1,96 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:96)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:104)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:50)
+
diff --git a/memcheck/tests/amd64-solaris/context_fpu.stdout.exp b/memcheck/tests/amd64-solaris/context_fpu.stdout.exp
new file mode 100644
index 0000000..2c3bf1d
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_fpu.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  fp[0]=1.000000, fp[2]=1.000000, fp[4]=1.000000, fp[6]=1.000000
+Values after the return from the signal handler:
+  fp[0]=1.000000, fp[2]=1.000000, fp[4]=1.000000, fp[6]=1.000000
diff --git a/memcheck/tests/amd64-solaris/context_fpu.vgtest b/memcheck/tests/amd64-solaris/context_fpu.vgtest
new file mode 100644
index 0000000..8a3955d
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_fpu.vgtest
@@ -0,0 +1,2 @@
+prog: context_fpu
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/amd64-solaris/context_gpr.c b/memcheck/tests/amd64-solaris/context_gpr.c
new file mode 100644
index 0000000..d955118
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_gpr.c
@@ -0,0 +1,95 @@
+/* Test if values in rax, rbx, rcx, rdx, rsi and rdi are correctly propagated
+   into and out of a signal handler and also check that the same applies for
+   uninitialised values and their origins. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+/* x0 is always zero, but is visible to Valgrind as uninitialised. */
+static long x0;
+
+void break_out(void);
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   ucp->uc_mcontext.gregs[REG_RCX] = x0;
+
+   /* Break out of the endless loop. */
+   *(uintptr_t*)&ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t)break_out;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   long rax, rbx, rcx, rdx, rsi, rdi;
+   long y0;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   /* Uninitialised, but we know py[0] is 0x0. */
+   long *py = malloc(sizeof(*py));
+   y0 = py[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGALRM, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   alarm(2);
+
+   __asm__ __volatile__(
+      /* Set values in general purpose registers. */
+      "movq   $0xf0, %%rax\n"
+      "movq   %[y0], %%rbx\n"
+      "movq   $0xf1, %%rcx\n"
+      "movq   $0xf2, %%rdx\n"
+      "movq   $0xf3, %%rsi\n"
+      "movq   $0xf4, %%rdi\n"
+
+      /* Loopity loop, this is where the SIGALRM is triggered. */
+      "1:\n"
+      "jmp    1b\n"
+
+      "break_out:\n"
+      : "=a" (rax), "=b" (rbx), "=c" (rcx), "=d" (rdx), "=S" (rsi),
+        "=D" (rdi)
+      : [y0] "m" (y0)
+      : "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  rax=%#lx, rcx=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n",
+          uc.uc_mcontext.gregs[REG_RAX], uc.uc_mcontext.gregs[REG_RCX],
+          uc.uc_mcontext.gregs[REG_RDX], uc.uc_mcontext.gregs[REG_RSI],
+          uc.uc_mcontext.gregs[REG_RDI]);
+   /* Check that rbx contains an uninitialised value (origin is py[0]). */
+   if (uc.uc_mcontext.gregs[REG_RBX])
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  rax=%#lx, rdx=%#lx, rsi=%#lx, rdi=%#lx\n", rax, rdx, rsi, rdi);
+   /* Check that rbx and rcx contain uninitialised values (origin is py[0]
+      and px[0], respectively). */
+   if (rbx || rcx)
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/amd64-solaris/context_gpr.stderr.exp b/memcheck/tests/amd64-solaris/context_gpr.stderr.exp
new file mode 100644
index 0000000..d17f7a3
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_gpr.stderr.exp
@@ -0,0 +1,18 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:83)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:42)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:90)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:42)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:90)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:38)
+
diff --git a/memcheck/tests/amd64-solaris/context_gpr.stdout.exp b/memcheck/tests/amd64-solaris/context_gpr.stdout.exp
new file mode 100644
index 0000000..199db7a
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_gpr.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  rax=0xf0, rcx=0xf1, rdx=0xf2, rsi=0xf3, rdi=0xf4
+Values after the return from the signal handler:
+  rax=0xf0, rdx=0xf2, rsi=0xf3, rdi=0xf4
diff --git a/memcheck/tests/amd64-solaris/context_gpr.vgtest b/memcheck/tests/amd64-solaris/context_gpr.vgtest
new file mode 100644
index 0000000..df56f58
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_gpr.vgtest
@@ -0,0 +1,2 @@
+prog: context_gpr
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/amd64-solaris/context_rflags.c b/memcheck/tests/amd64-solaris/context_rflags.c
new file mode 100644
index 0000000..b67f039
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags.c
@@ -0,0 +1,67 @@
+/* Test if rflags values are correctly propagated in and out of a signal
+   handler.  Note that we actually test only the propagation of the overflow
+   and sign flags. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+#define OBIT(rflags) (!!((rflags) & (1 << 11)))
+#define SBIT(rflags) (!!((rflags) & (1 << 7)))
+
+static siginfo_t si;
+static ucontext_t uc;
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   long rflags;
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set overflow and sign flags. */
+      "movl   $1, %%edx\n"
+      "addl   $0x7fffffff, %%edx\n"
+
+      /* Trigger the signal handler. */
+      "syscall\n"
+      "pushfq\n"
+      "popq   %%rdx\n"
+      : "=d" (rflags)
+      : "a" (SYS_kill), "D" (pid), "S" (SIGUSR1)
+      : "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  overflow=%d, sign=%d\n",
+          OBIT(uc.uc_mcontext.gregs[REG_RFL]),
+          SBIT(uc.uc_mcontext.gregs[REG_RFL]));
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  overflow=%d, sign=%d\n", OBIT(rflags), SBIT(rflags));
+
+   return 0;
+}
+
diff --git a/memcheck/tests/amd64-solaris/context_rflags.stderr.exp b/memcheck/tests/amd64-solaris/context_rflags.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags.stderr.exp
diff --git a/memcheck/tests/amd64-solaris/context_rflags.stdout.exp b/memcheck/tests/amd64-solaris/context_rflags.stdout.exp
new file mode 100644
index 0000000..8ad7bac
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  overflow=1, sign=1
+Values after the return from the signal handler:
+  overflow=1, sign=1
diff --git a/memcheck/tests/amd64-solaris/context_rflags.vgtest b/memcheck/tests/amd64-solaris/context_rflags.vgtest
new file mode 100644
index 0000000..506f6a3
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags.vgtest
@@ -0,0 +1,2 @@
+prog: context_rflags
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/amd64-solaris/context_rflags2.c b/memcheck/tests/amd64-solaris/context_rflags2.c
new file mode 100644
index 0000000..9afceca
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags2.c
@@ -0,0 +1,90 @@
+/* Test if definedness of rflags values is correctly propagated in and out
+   of a signal handler.  Note that actually only the propagation of the
+   overflow and sign flags is tested.
+
+   This test must use alarm(2) to trigger the signal and not kill(2) as other
+   tests do because in the latter case the signal is actually delivered after
+   the syscall finished.  This means that Valgrind had to save a correct carry
+   flag value (indicating if the syscall succeeded) in the rflags.  This save
+   operation unfortunately makes all rflags initialised (due to imprecise
+   simulation). */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+#define OBIT(rflags) (!!((rflags) & (1 << 11)))
+#define SBIT(rflags) (!!((rflags) & (1 << 7)))
+
+static siginfo_t si;
+static ucontext_t uc;
+
+void break_out(void);
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   /* Break out of the endless loop. */
+   *(uintptr_t*)&ucp->uc_mcontext.gregs[REG_RIP] = (uintptr_t)break_out;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   long rflags;
+   int x1;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   int *px = malloc(sizeof(*px));
+   x1 = px[0] + 1;
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGALRM, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   alarm(2);
+
+   __asm__ __volatile__(
+      /* Set overflow and sign flags. */
+      "movl   %[x1], %%edx\n"
+      "addl   $0x7fffffff, %%edx\n"
+
+      /* Loopity loop, this is where the SIGALRM is triggered. */
+      "1:\n"
+      "jmp    1b\n"
+
+      "break_out:\n"
+      "pushfq\n"
+      "popq   %%rdx\n"
+      : "=d" (rflags)
+      : [x1] "m" (x1)
+      : "cc", "memory");
+
+   /* Check that the overflow and sign flags are uninitialised.
+
+      Note: This actually fails because the rflags are only approximate
+      (always initialised) in the signal handler. */
+   if (!OBIT(uc.uc_mcontext.gregs[REG_RFL]) ||
+       !SBIT(uc.uc_mcontext.gregs[REG_RFL]))
+      assert(0);
+
+   /* Check that the overflow and sign flags are uninitialised. */
+   if (!OBIT(rflags) || !SBIT(rflags))
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/amd64-solaris/context_rflags2.stderr.exp b/memcheck/tests/amd64-solaris/context_rflags2.stderr.exp
new file mode 100644
index 0000000..5b94f9c
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags2.stderr.exp
@@ -0,0 +1,12 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_rflags2.c:85)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_rflags2.c:44)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_rflags2.c:85)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_rflags2.c:44)
+
diff --git a/memcheck/tests/amd64-solaris/context_rflags2.stdout.exp b/memcheck/tests/amd64-solaris/context_rflags2.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags2.stdout.exp
diff --git a/memcheck/tests/amd64-solaris/context_rflags2.vgtest b/memcheck/tests/amd64-solaris/context_rflags2.vgtest
new file mode 100644
index 0000000..e42f53f
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_rflags2.vgtest
@@ -0,0 +1,2 @@
+prog: context_rflags2
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/amd64-solaris/context_sse.c b/memcheck/tests/amd64-solaris/context_sse.c
new file mode 100644
index 0000000..f1e381b
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_sse.c
@@ -0,0 +1,100 @@
+/* Test if SSE valus are correctly propagated into and out of a signal handler
+   and also check that the same applies for uninitialised values and their
+   origins. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+/* x0 is always zero, but is visible to Valgrind as uninitialised. */
+static upad128_t x0;
+static upad128_t d0 = {0};
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[0] = d0;
+   ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[1] = x0;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   upad128_t out[8];
+   upad128_t y0;
+   struct fpchip_state *fs = &uc.uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   upad128_t *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   /* Uninitialised, but we know py[0] is 0x0. */
+   upad128_t *py = malloc(sizeof(*py));
+   y0 = py[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set values in the SSE registers. */
+      "movups %[y0], %%xmm0\n"
+      "movups %[d0], %%xmm1\n"
+      "movups %[d0], %%xmm2\n"
+      "movups %[y0], %%xmm3\n"
+      "movups %[y0], %%xmm4\n"
+      "movups %[d0], %%xmm5\n"
+      "movups %[d0], %%xmm6\n"
+      "movups %[y0], %%xmm7\n"
+
+      /* Trigger the signal handler. */
+      "syscall\n"
+      "movups %%xmm0, 0x00 + %[out]\n"
+      "movups %%xmm1, 0x10 + %[out]\n"
+      "movups %%xmm2, 0x20 + %[out]\n"
+      "movups %%xmm3, 0x30 + %[out]\n"
+      "movups %%xmm4, 0x40 + %[out]\n"
+      "movups %%xmm5, 0x50 + %[out]\n"
+      "movups %%xmm6, 0x60 + %[out]\n"
+      "movups %%xmm7, 0x70 + %[out]\n"
+      : [out] "=m" (out[0])
+      : "a" (SYS_kill), "D" (pid), "S" (SIGUSR1), [y0] "m" (y0), [d0] "m" (d0)
+      : "rdx", "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  xmm1=%Lf, xmm2=%Lf, xmm5=%Lf, xmm6=%Lf\n",
+          fs->xmm[1]._q, fs->xmm[2]._q, fs->xmm[5]._q, fs->xmm[6]._q);
+   /* Check that fs->xmm[0], fs->xmm[3], fs->xmm[4] and fs->xmm[7] contain
+      uninitialised values (origin is py[0]). */
+   if (fs->xmm[0]._q || fs->xmm[3]._q || fs->xmm[4]._q || fs->xmm[7]._q)
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  xmm0=%Lf, xmm2=%Lf, xmm5=%Lf, xmm6=%Lf\n",
+          out[0]._q, out[2]._q, out[5]._q, out[6]._q);
+   /* Check that out[1], out[3], out[4] and out[7] contain uninitialised
+      values (origin is px[0]). */
+   if (out[1]._q || out[3]._q || out[4]._q || out[7]._q)
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/amd64-solaris/context_sse.stderr.exp b/memcheck/tests/amd64-solaris/context_sse.stderr.exp
new file mode 100644
index 0000000..bee96ca
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_sse.stderr.exp
@@ -0,0 +1,96 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:37)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:37)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:95)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:41)
+
diff --git a/memcheck/tests/amd64-solaris/context_sse.stdout.exp b/memcheck/tests/amd64-solaris/context_sse.stdout.exp
new file mode 100644
index 0000000..2cefcc8
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_sse.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  xmm1=0.000000, xmm2=0.000000, xmm5=0.000000, xmm6=0.000000
+Values after the return from the signal handler:
+  xmm0=0.000000, xmm2=0.000000, xmm5=0.000000, xmm6=0.000000
diff --git a/memcheck/tests/amd64-solaris/context_sse.vgtest b/memcheck/tests/amd64-solaris/context_sse.vgtest
new file mode 100644
index 0000000..97d6be1
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/context_sse.vgtest
@@ -0,0 +1,2 @@
+prog: context_sse
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/amd64-solaris/filter_stderr b/memcheck/tests/amd64-solaris/filter_stderr
new file mode 100755
index 0000000..a778e97
--- /dev/null
+++ b/memcheck/tests/amd64-solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr "$@"
diff --git a/memcheck/tests/amd64/Makefile.am b/memcheck/tests/amd64/Makefile.am
index 0e72521..5cfb67c 100644
--- a/memcheck/tests/amd64/Makefile.am
+++ b/memcheck/tests/amd64/Makefile.am
@@ -59,6 +59,10 @@
 AM_CXXFLAGS  += @FLAG_M64@
 AM_CCASFLAGS += @FLAG_M64@
 
+insn_pcmpistri_CFLAGS	= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+insn_pcmpistri_CFLAGS	+= --std=c99
+endif
 more_x87_fp_CFLAGS	= $(AM_CFLAGS) -O -ffast-math -mfpmath=387 \
 				-mfancy-math-387
 more_x87_fp_LDADD	= -lm
diff --git a/memcheck/tests/amd64/bt_everything.c b/memcheck/tests/amd64/bt_everything.c
index a010b04..57624a1 100644
--- a/memcheck/tests/amd64/bt_everything.c
+++ b/memcheck/tests/amd64/bt_everything.c
@@ -13,6 +13,18 @@
 
 typedef signed long int  Word;
 
+unsigned long myrandom(void)
+{
+   /* Simple multiply-with-carry random generator. */
+   static unsigned long m_w = 11;
+   static unsigned long m_z = 13;
+
+   m_z = 36969 * (m_z & 65535) + (m_z >> 16);
+   m_w = 18000 * (m_w & 65535) + (m_w >> 16);
+
+   return (m_z << 16) + m_w;
+}
+
 /* ------------ MEM, Q ------------ */
 
 ULong btsq_mem ( char* base, Word bitno )
@@ -418,8 +430,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 12;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 12;
       c = 2;
       switch (op) {
          case  0: c = btsl_mem(block, bitoff); break;
@@ -457,8 +469,8 @@
    reg = 0;
 
    for (n = 0; n < 1000; n++) {
-      bitoff = (random() % 100) - 50;
-      op = random() % 12;
+      bitoff = (myrandom() % 100) - 50;
+      op = myrandom() % 12;
       c = 2;
       switch (op) {
          case  0: c = btsl_reg(reg, bitoff, &reg); break;
diff --git a/memcheck/tests/amd64/bt_everything.stdout.exp b/memcheck/tests/amd64/bt_everything.stdout.exp
index f22a0a7..370553f 100644
--- a/memcheck/tests/amd64/bt_everything.stdout.exp
+++ b/memcheck/tests/amd64/bt_everything.stdout.exp
@@ -1,2 +1,2 @@
-MEM-L: final res 0xbb05dc8f69ba36dc, carrydep 0x818f336625f01277
-REG-L: final res 0xa15f293e, carrydep 0x6082b5e5befc6a40
+MEM-L: final res 0xf7fadd6c64517c70, carrydep 0x8176a65abd735847
+REG-L: final res 0x35c459ff, carrydep 0x5d837ee10c6c390
diff --git a/memcheck/tests/amd64/fxsave-amd64.c b/memcheck/tests/amd64/fxsave-amd64.c
index de04037..1766e29 100644
--- a/memcheck/tests/amd64/fxsave-amd64.c
+++ b/memcheck/tests/amd64/fxsave-amd64.c
@@ -17,7 +17,7 @@
 __attribute__((noinline))
 void do_fxsave ( void* p, int rexw ) {
    if (rexw) {
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
       asm __volatile__("fxsave64 (%0)" : : "r" (p) : "memory" );
 #else
       asm __volatile__("rex64/fxsave (%0)" : : "r" (p) : "memory" );
@@ -30,7 +30,7 @@
 __attribute__((noinline))
 void do_fxrstor ( void* p, int rexw ) {
    if (rexw) {
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
       asm __volatile__("fxrstor64 (%0)" : : "r" (p) : "memory" );
 #else
       asm __volatile__("rex64/fxrstor (%0)" : : "r" (p) : "memory" );
diff --git a/memcheck/tests/badjump2.c b/memcheck/tests/badjump2.c
index 7e09af5..2085a30 100644
--- a/memcheck/tests/badjump2.c
+++ b/memcheck/tests/badjump2.c
@@ -24,7 +24,7 @@
    /* Install own SIGSEGV handler */
    sigsegv_new.sa_handler  = SIGSEGV_handler;
    sigsegv_new.sa_flags    = 0;
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__sun)
    sigsegv_new.sa_restorer = NULL;
 #endif
    res = sigemptyset( &sigsegv_new.sa_mask );
diff --git a/memcheck/tests/clo_redzone.c b/memcheck/tests/clo_redzone.c
index 5733ffa..78bd119 100644
--- a/memcheck/tests/clo_redzone.c
+++ b/memcheck/tests/clo_redzone.c
@@ -1,3 +1,4 @@
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 int main()
@@ -5,7 +6,8 @@
    __attribute__((unused)) char *p = malloc (1);
    char *b1 = malloc (128);
    char *b2 = malloc (128);
-   fprintf (stderr, "b1 %p b2 %p\n", b1, b2);
+   fprintf (stderr, "b1 %#" PRIxPTR " b2 %#" PRIxPTR "\n",
+                    (uintptr_t)b1, (uintptr_t)b2);
 
    // Try to land in b2 from b1, causing no error
    // with the default redzone-size, but having
diff --git a/memcheck/tests/dw4.c b/memcheck/tests/dw4.c
index 574f97c..7d981b6 100644
--- a/memcheck/tests/dw4.c
+++ b/memcheck/tests/dw4.c
@@ -68,8 +68,8 @@
   croak( p);
 
   /* Describe file mmap-ed */
-  snprintf(filename, sizeof(filename), "./valgrind-dw4-test.%d",
-           getpid());
+  snprintf(filename, sizeof(filename), "./valgrind-dw4-test.%ld",
+           (long) getpid());
 
   unlink(filename);
 
diff --git a/memcheck/tests/dw4.stderr.exp-solaris b/memcheck/tests/dw4.stderr.exp-solaris
new file mode 100644
index 0000000..917dcb5
--- /dev/null
+++ b/memcheck/tests/dw4.stderr.exp-solaris
@@ -0,0 +1,49 @@
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:59)
+ Address 0x........ is 4 bytes inside a block of size ... alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (dw4.c:52)
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:61)
+ Location 0x........ is 0 bytes inside S2[0].i,
+ a global variable declared at dw4.c:47
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:62)
+ Location 0x........ is 0 bytes inside local.i,
+ declared at dw4.c:51, in frame #1 of thread 1
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:68)
+ Address 0x........ is in a rw- anonymous segment
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:82)
+ Address 0x........ is in a rw- mapped file valgrind-dw4-test.PID segment
+
+Unaddressable byte(s) found during client check request
+   at 0x........: croak (dw4.c:25)
+   by 0x........: main (dw4.c:87)
+ Address 0x........ is 0 bytes after the brk data segment limit 0x........
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:89)
+ Address 0x........ is in the brk data segment 0x........-0x........
+
+Uninitialised byte(s) found during client check request
+   at 0x........: croak (dw4.c:32)
+   by 0x........: main (dw4.c:91)
+ Address 0x........ is in the brk data segment 0x........-0x........
+
+Unaddressable byte(s) found during client check request
+   at 0x........: croak (dw4.c:25)
+   by 0x........: main (dw4.c:93)
+ Address 0x........ is 1024 bytes after the brk data segment limit 0x........
+
diff --git a/memcheck/tests/execve2.c b/memcheck/tests/execve2.c
index b3d44ec..a5d80f1 100644
--- a/memcheck/tests/execve2.c
+++ b/memcheck/tests/execve2.c
@@ -4,8 +4,10 @@
 int main ( int argc, char** argv, char** envp )
 {
    char* null_filename = NULL;
+   char *const argv_exe[] = {"true", NULL};
 
-   execve(null_filename,      NULL, NULL);
-   execve("../../tests/true", NULL, envp);
+   execve(null_filename, NULL, NULL);
+   // Solaris requires non-NULL argv param (this is not necessary on Linux)
+   execve("../../tests/true", argv_exe, envp);
    assert(0);  // shouldn't get here
 }
diff --git a/memcheck/tests/execve2.stderr.exp b/memcheck/tests/execve2.stderr.exp
index b87bff8..cd98593 100644
--- a/memcheck/tests/execve2.stderr.exp
+++ b/memcheck/tests/execve2.stderr.exp
@@ -1,5 +1,5 @@
 Syscall param execve(filename) points to unaddressable byte(s)
    ...
-   by 0x........: main (execve2.c:8)
+   by 0x........: main (execve2.c:9)
  Address 0x........ is not stack'd, malloc'd or (recently) free'd
 
diff --git a/memcheck/tests/file_locking.c b/memcheck/tests/file_locking.c
index d99f6b5..35f2995 100644
--- a/memcheck/tests/file_locking.c
+++ b/memcheck/tests/file_locking.c
@@ -81,8 +81,8 @@
   int exitcode = 1;
   char filename[256];
 
-  snprintf(filename, sizeof(filename), "/tmp/valgrind-file-locking-test.%d",
-           getpid());
+  snprintf(filename, sizeof(filename), "/tmp/valgrind-file-locking-test.%ld",
+           (long) getpid());
 
   unlink(filename);
 
diff --git a/memcheck/tests/fprw.c b/memcheck/tests/fprw.c
index 6eb304d..4ef74c7 100644
--- a/memcheck/tests/fprw.c
+++ b/memcheck/tests/fprw.c
@@ -10,7 +10,7 @@
    volatile float f;
    double* dp = malloc(sizeof(double));
    float* fp = malloc(sizeof(float));
-   int* ip = (int*)0x1234567;
+   int* ip = (int*)0x12345678;
    d += 1.0;
    f += 10.0;
    *dp += ( d > 0.1  ? 2.0 : 3.0 );
diff --git a/memcheck/tests/leak-segv-jmp.c b/memcheck/tests/leak-segv-jmp.c
index 50ad27b..f3380e9 100644
--- a/memcheck/tests/leak-segv-jmp.c
+++ b/memcheck/tests/leak-segv-jmp.c
@@ -7,12 +7,14 @@
 #include <sys/mman.h>
 #include <sys/syscall.h>
 
+typedef unsigned int             UInt;
 typedef unsigned long            UWord;
 typedef unsigned long long int   ULong;
+
 // Below code is copied from m_syscall.c
 // Refer to this file for syscall convention.
 #if defined(VGP_x86_linux)
-extern UWord do_syscall_WRK (UWord syscall_no, 
+extern UWord do_syscall_WRK (UWord syscall_no,
                              UWord a1, UWord a2, UWord a3,
                              UWord a4, UWord a5, UWord a6
                              );
@@ -39,6 +41,7 @@
 "	ret\n"
 ".previous\n"
 );
+
 #elif defined(VGP_amd64_linux)
 extern UWord do_syscall_WRK (
           UWord syscall_no, 
@@ -104,6 +107,7 @@
 "         bx      lr\n"
 ".previous\n"
 );
+
 #elif defined(VGP_s390x_linux)
 UWord do_syscall_WRK (
    UWord syscall_no,
@@ -184,6 +188,51 @@
    return out;
 }
 
+#elif defined(VGP_x86_solaris)
+extern ULong
+do_syscall_WRK(UWord a1, UWord a2, UWord a3,
+               UWord a4, UWord a5, UWord a6,
+               UWord a7, UWord a8,
+               UWord syscall_no,
+               UInt *errflag);
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+"        movl    40(%esp), %ecx\n"      /* assume syscall success */
+"        movl    $0, (%ecx)\n"
+"        movl    36(%esp), %eax\n"
+"        int     $0x91\n"
+"        jnc     1f\n"                  /* jump if success */
+"        movl    40(%esp), %ecx\n"      /* syscall failed - set *errflag */
+"        movl    $1, (%ecx)\n"
+"1:      ret\n"
+".previous\n"
+);
+
+#elif defined(VGP_amd64_solaris)
+extern ULong
+do_syscall_WRK(UWord a1, UWord a2, UWord a3,
+               UWord a4, UWord a5, UWord a6,
+               UWord a7, UWord a8,
+               UWord syscall_no,
+               UInt *errflag);
+asm(
+".text\n"
+".globl do_syscall_WRK\n"
+"do_syscall_WRK:\n"
+"       movq    %rcx, %r10\n"           /* pass rcx in r10 instead */
+"       movq    32(%rsp), %rcx\n"       /* assume syscall success */
+"       movl    $0, (%rcx)\n"
+"       movq    24(%rsp), %rax\n"
+"       syscall\n"
+"       jnc     1f\n"                   /* jump if success */
+"       movq    32(%rsp), %rcx\n"       /* syscall failed - set *errflag */
+"       movl    $1, (%rcx)\n"
+"1:     ret\n"
+".previous\n"
+);
+
 #else
 // Ensure the file compiles even if the syscall nr is not defined.
 #ifndef __NR_mprotect
@@ -205,9 +254,18 @@
 int mprotect_result = 0;
 static void non_simd_mprotect (long tid, void* addr, long len)
 {
+#if defined(VGP_x86_solaris) || defined(VGP_amd64_solaris)
+   UInt err = 0;
+   mprotect_result = do_syscall_WRK((UWord) addr, len, PROT_NONE,
+                                    0, 0, 0, 0, 0, SYS_mprotect, 
+                                    &err);
+   if (err)
+      mprotect_result = -1;
+#else
    mprotect_result = do_syscall_WRK(__NR_mprotect,
                                     (UWord) addr, len, PROT_NONE,
                                     0, 0, 0);
+#endif
 }
 
 void f(void)
diff --git a/memcheck/tests/leak-segv-jmp.stderr.exp b/memcheck/tests/leak-segv-jmp.stderr.exp
index 73f4e11..ba51e4d 100644
--- a/memcheck/tests/leak-segv-jmp.stderr.exp
+++ b/memcheck/tests/leak-segv-jmp.stderr.exp
@@ -14,8 +14,8 @@
 expecting a leak
 1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: f (leak-segv-jmp.c:223)
-   by 0x........: main (leak-segv-jmp.c:286)
+   by 0x........: f (leak-segv-jmp.c:281)
+   by 0x........: main (leak-segv-jmp.c:344)
 
 LEAK SUMMARY:
    definitely lost: 1,000 bytes in 1 blocks
@@ -30,8 +30,8 @@
 expecting a leak again
 1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: f (leak-segv-jmp.c:223)
-   by 0x........: main (leak-segv-jmp.c:286)
+   by 0x........: f (leak-segv-jmp.c:281)
+   by 0x........: main (leak-segv-jmp.c:344)
 
 LEAK SUMMARY:
    definitely lost: 1,000 bytes in 1 blocks
@@ -46,8 +46,8 @@
 expecting a leak again after full mprotect
 1,000 bytes in 1 blocks are definitely lost in loss record ... of ...
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: f (leak-segv-jmp.c:223)
-   by 0x........: main (leak-segv-jmp.c:286)
+   by 0x........: f (leak-segv-jmp.c:281)
+   by 0x........: main (leak-segv-jmp.c:344)
 
 LEAK SUMMARY:
    definitely lost: 1,000 bytes in 1 blocks
diff --git a/memcheck/tests/leak_cpp_interior.cpp b/memcheck/tests/leak_cpp_interior.cpp
index f599eae..497fa87 100644
--- a/memcheck/tests/leak_cpp_interior.cpp
+++ b/memcheck/tests/leak_cpp_interior.cpp
@@ -1,3 +1,4 @@
+#include <inttypes.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <stdint.h>
@@ -107,7 +108,8 @@
   
   // prepare the who_points_at cmd we will run.
   // Do it here to avoid having ptr or its exterior ptr kept in a register.
-  sprintf(who_points_at_cmd, "who_points_at %p 20", (char*)ptr - sizeof(void*));
+  sprintf(who_points_at_cmd, "who_points_at %#" PRIxPTR " 20",
+          (uintptr_t) (char*)ptr - sizeof(void*));
 
   ptr2 = new MyClass[0]; // "interior but exterior ptr".
   // ptr2 points after the chunk, is wrongly considered by memcheck as definitely leaked.
diff --git a/memcheck/tests/leak_cpp_interior.stderr.exp b/memcheck/tests/leak_cpp_interior.stderr.exp
index 8531c4e..2ab2787 100644
--- a/memcheck/tests/leak_cpp_interior.stderr.exp
+++ b/memcheck/tests/leak_cpp_interior.stderr.exp
@@ -2,8 +2,8 @@
 valgrind output will go to log
 VALGRIND_DO_LEAK_CHECK
 4 bytes in 1 blocks are definitely lost in loss record ... of ...
-   by 0x........: doit() (leak_cpp_interior.cpp:112)
-   by 0x........: main (leak_cpp_interior.cpp:127)
+   by 0x........: doit() (leak_cpp_interior.cpp:114)
+   by 0x........: main (leak_cpp_interior.cpp:129)
 
 LEAK SUMMARY:
    definitely lost: 4 bytes in 1 blocks
diff --git a/memcheck/tests/leak_cpp_interior.stderr.exp-64bit b/memcheck/tests/leak_cpp_interior.stderr.exp-64bit
index 8a025a9..8bc77a4 100644
--- a/memcheck/tests/leak_cpp_interior.stderr.exp-64bit
+++ b/memcheck/tests/leak_cpp_interior.stderr.exp-64bit
@@ -2,8 +2,8 @@
 valgrind output will go to log
 VALGRIND_DO_LEAK_CHECK
 8 bytes in 1 blocks are definitely lost in loss record ... of ...
-   by 0x........: doit() (leak_cpp_interior.cpp:112)
-   by 0x........: main (leak_cpp_interior.cpp:127)
+   by 0x........: doit() (leak_cpp_interior.cpp:114)
+   by 0x........: main (leak_cpp_interior.cpp:129)
 
 LEAK SUMMARY:
    definitely lost: 8 bytes in 1 blocks
diff --git a/memcheck/tests/long_namespace_xml.cpp b/memcheck/tests/long_namespace_xml.cpp
index 91bdeaf..fb8a3dd 100644
--- a/memcheck/tests/long_namespace_xml.cpp
+++ b/memcheck/tests/long_namespace_xml.cpp
@@ -19,6 +19,7 @@
 #define N2 ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ
 
 #include <iostream>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
 
@@ -42,5 +43,8 @@
 
 int main() {
   N1::N2::f();
+#if defined(VGO_solaris)
+  fcloseall();
+#endif
   return 0;
 }
diff --git a/memcheck/tests/malloc2.c b/memcheck/tests/malloc2.c
index 44cc7bb..496fdff 100644
--- a/memcheck/tests/malloc2.c
+++ b/memcheck/tests/malloc2.c
@@ -10,6 +10,17 @@
 
 void* test_arr[N_TEST_ARR];
 
+unsigned myrandom(void)
+{
+   /* Simple multiply-with-carry random generator. */
+   static unsigned m_w = 11;
+   static unsigned m_z = 13;
+
+   m_z = 36969 * (m_z & 65535) + (m_z >> 16);
+   m_w = 18000 * (m_w & 65535) + (m_w >> 16);
+   return (m_z << 16) + m_w;
+}
+
 int main ( int argc, char** argv )
 {
    int i, j, k, nbytes;
@@ -19,13 +30,13 @@
       test_arr[i] = NULL;
 
    for (i = 0; i < N_TEST_TRANSACTIONS; i++) {
-      j = random() % N_TEST_ARR;
+      j = myrandom() % N_TEST_ARR;
       if (test_arr[j]) {
          free(test_arr[j]);
          test_arr[j] = NULL;
       } else {
-         nbytes = 1 + random() % M_TEST_MALLOC;
-         if (random()%64 == 32) 
+         nbytes = 1 + myrandom() % M_TEST_MALLOC;
+         if (myrandom()%64 == 32)
             nbytes *= 17;
          test_arr[j] = malloc( nbytes );
          chp = test_arr[j];
diff --git a/memcheck/tests/malloc2.stderr.exp b/memcheck/tests/malloc2.stderr.exp
index 7ba0426..f1a075b 100644
--- a/memcheck/tests/malloc2.stderr.exp
+++ b/memcheck/tests/malloc2.stderr.exp
@@ -1,13 +1,13 @@
 Invalid write of size 1
-   at 0x........: main (malloc2.c:39)
- Address 0x........ is 0 bytes inside a block of size 429 free'd
+   at 0x........: main (malloc2.c:50)
+ Address 0x........ is 0 bytes inside a block of size 772 free'd
    at 0x........: free (vg_replace_malloc.c:...)
-   by 0x........: main (malloc2.c:38)
+   by 0x........: main (malloc2.c:49)
 
 Invalid free() / delete / delete[] / realloc()
    at 0x........: free (vg_replace_malloc.c:...)
-   by 0x........: main (malloc2.c:43)
- Address 0x........ is 0 bytes inside a block of size 429 free'd
+   by 0x........: main (malloc2.c:54)
+ Address 0x........ is 0 bytes inside a block of size 772 free'd
    at 0x........: free (vg_replace_malloc.c:...)
-   by 0x........: main (malloc2.c:38)
+   by 0x........: main (malloc2.c:49)
 
diff --git a/memcheck/tests/malloc_usable.c b/memcheck/tests/malloc_usable.c
index b036b10..78ab8f1 100644
--- a/memcheck/tests/malloc_usable.c
+++ b/memcheck/tests/malloc_usable.c
@@ -5,7 +5,7 @@
 
 int main(void)
 {
-#  if !defined(VGO_darwin)
+#  if !defined(VGO_darwin) && !defined(VGO_solaris)
    // Because Memcheck marks any slop as inaccessible, it doesn't round up
    // sizes for malloc_usable_size().
    int* x = malloc(99);
diff --git a/memcheck/tests/sendmsg.c b/memcheck/tests/sendmsg.c
index bd005c8..cbbe181 100644
--- a/memcheck/tests/sendmsg.c
+++ b/memcheck/tests/sendmsg.c
@@ -1,9 +1,10 @@
-#include <netinet/ip.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
 
 #define PORT 12345
 
diff --git a/memcheck/tests/sendmsg.stderr.exp b/memcheck/tests/sendmsg.stderr.exp
index 3a6d156..397a579 100644
--- a/memcheck/tests/sendmsg.stderr.exp
+++ b/memcheck/tests/sendmsg.stderr.exp
@@ -1,7 +1,7 @@
 Syscall param sendmsg(msg) points to uninitialised byte(s)
    at 0x........: sendmsg (in /...libc...)
-   by 0x........: main (sendmsg.c:45)
+   by 0x........: main (sendmsg.c:46)
  Address 0x........ is on thread 1's stack
- in frame #1, created by main (sendmsg.c:12)
+ in frame #1, created by main (sendmsg.c:13)
 
 sendmsg: 6
diff --git a/memcheck/tests/sendmsg.stderr.exp-solaris b/memcheck/tests/sendmsg.stderr.exp-solaris
new file mode 100644
index 0000000..f00e76e
--- /dev/null
+++ b/memcheck/tests/sendmsg.stderr.exp-solaris
@@ -0,0 +1,8 @@
+Syscall param sendmsg(msg) points to uninitialised byte(s)
+   at 0x........: __so_sendmsg (in /...libc...)
+   by 0x........: __xnet_sendmsg (in /...libc...)
+   by 0x........: main (sendmsg.c:46)
+ Address 0x........ is on thread 1's stack
+ in frame #2, created by main (sendmsg.c:13)
+
+sendmsg: 6
diff --git a/memcheck/tests/sigaltstack.c b/memcheck/tests/sigaltstack.c
index 526a99a..2892ebb 100644
--- a/memcheck/tests/sigaltstack.c
+++ b/memcheck/tests/sigaltstack.c
@@ -1,5 +1,4 @@
-
-
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <signal.h>
@@ -7,7 +6,8 @@
 
 void sig_handler(int sig){
   int var;
-  fprintf(stderr, "caught signal, local var is on %p\n", &var);
+  fprintf(stderr, "caught signal, local var is on %#" PRIxPTR "\n",
+          (uintptr_t)&var);
 }
 
 int main(int argv, char** argc) {
@@ -24,7 +24,8 @@
 
   sigstk.ss_size = size;
   sigstk.ss_flags = 0;
-  fprintf(stderr, "calling sigaltstack, stack base is %p\n", sigstk.ss_sp);
+  fprintf(stderr, "calling sigaltstack, stack base is %#" PRIxPTR "\n",
+          (uintptr_t)sigstk.ss_sp);
   if (sigaltstack(&sigstk,0)<0) perror("sigaltstack");
 
   fprintf(stderr,"setting sigaction\n");
diff --git a/memcheck/tests/sigkill.stderr.exp-solaris b/memcheck/tests/sigkill.stderr.exp-solaris
new file mode 100644
index 0000000..de4a860
--- /dev/null
+++ b/memcheck/tests/sigkill.stderr.exp-solaris
@@ -0,0 +1,197 @@
+
+setting signal 1: Success
+getting signal 1: Success
+
+setting signal 2: Success
+getting signal 2: Success
+
+setting signal 3: Success
+getting signal 3: Success
+
+setting signal 4: Success
+getting signal 4: Success
+
+setting signal 5: Success
+getting signal 5: Success
+
+setting signal 6: Success
+getting signal 6: Success
+
+setting signal 7: Success
+getting signal 7: Success
+
+setting signal 8: Success
+getting signal 8: Success
+
+setting signal 9: Warning: ignored attempt to set SIGKILL handler in sigaction();
+         the SIGKILL signal is uncatchable
+Invalid argument
+getting signal 9: Success
+
+setting signal 10: Success
+getting signal 10: Success
+
+setting signal 11: Success
+getting signal 11: Success
+
+setting signal 12: Success
+getting signal 12: Success
+
+setting signal 13: Success
+getting signal 13: Success
+
+setting signal 14: Success
+getting signal 14: Success
+
+setting signal 15: Success
+getting signal 15: Success
+
+setting signal 16: Success
+getting signal 16: Success
+
+setting signal 17: Success
+getting signal 17: Success
+
+setting signal 18: Success
+getting signal 18: Success
+
+setting signal 19: Success
+getting signal 19: Success
+
+setting signal 20: Success
+getting signal 20: Success
+
+setting signal 21: Success
+getting signal 21: Success
+
+setting signal 22: Success
+getting signal 22: Success
+
+setting signal 23: Warning: ignored attempt to set SIGSTOP handler in sigaction();
+         the SIGSTOP signal is uncatchable
+Invalid argument
+getting signal 23: Success
+
+setting signal 24: Success
+getting signal 24: Success
+
+setting signal 25: Success
+getting signal 25: Success
+
+setting signal 26: Success
+getting signal 26: Success
+
+setting signal 27: Success
+getting signal 27: Success
+
+setting signal 28: Success
+getting signal 28: Success
+
+setting signal 29: Success
+getting signal 29: Success
+
+setting signal 30: Success
+getting signal 30: Success
+
+setting signal 31: Success
+getting signal 31: Success
+
+setting signal 34: Success
+getting signal 34: Success
+
+setting signal 35: Success
+getting signal 35: Success
+
+setting signal 36: Success
+getting signal 36: Success
+
+setting signal 37: Success
+getting signal 37: Success
+
+setting signal 38: Success
+getting signal 38: Success
+
+setting signal 39: Success
+getting signal 39: Success
+
+setting signal 40: Success
+getting signal 40: Success
+
+setting signal 41: Success
+getting signal 41: Success
+
+setting signal 42: Success
+getting signal 42: Success
+
+setting signal 43: Success
+getting signal 43: Success
+
+setting signal 44: Success
+getting signal 44: Success
+
+setting signal 45: Success
+getting signal 45: Success
+
+setting signal 46: Success
+getting signal 46: Success
+
+setting signal 47: Success
+getting signal 47: Success
+
+setting signal 48: Success
+getting signal 48: Success
+
+setting signal 49: Success
+getting signal 49: Success
+
+setting signal 50: Success
+getting signal 50: Success
+
+setting signal 51: Success
+getting signal 51: Success
+
+setting signal 52: Success
+getting signal 52: Success
+
+setting signal 53: Success
+getting signal 53: Success
+
+setting signal 54: Success
+getting signal 54: Success
+
+setting signal 55: Success
+getting signal 55: Success
+
+setting signal 56: Success
+getting signal 56: Success
+
+setting signal 57: Success
+getting signal 57: Success
+
+setting signal 58: Success
+getting signal 58: Success
+
+setting signal 59: Success
+getting signal 59: Success
+
+setting signal 60: Success
+getting signal 60: Success
+
+setting signal 61: Success
+getting signal 61: Success
+
+setting signal 62: Success
+getting signal 62: Success
+
+setting signal 65: Success
+getting signal 65: Success
+
+
+HEAP SUMMARY:
+    in use at exit: ... bytes in ... blocks
+  total heap usage: ... allocs, ... frees, ... bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/solaris/Makefile.am b/memcheck/tests/solaris/Makefile.am
new file mode 100644
index 0000000..0adfa6a
--- /dev/null
+++ b/memcheck/tests/solaris/Makefile.am
@@ -0,0 +1,160 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+	filter_ldynsym \
+	filter_name_service_door \
+	filter_scalar \
+	filter_sendfilev \
+	filter_stderr \
+	filter_syscall_at
+
+noinst_HEADERS = scalar.h
+
+EXTRA_DIST = \
+	brk.stderr.exp brk.stdout.exp brk.vgtest \
+	context_stack_die.stderr.exp context_stack_die.stdout.exp context_stack_die.vgtest \
+	door_data.stderr.exp door_data.stdout.exp door_data.vgtest \
+	door_kill.stderr.exp door_kill.stdout.exp door_kill.vgtest \
+	execx.stderr.exp execx.stdout.exp execx.vgtest \
+	getzoneoffset.stderr.exp getzoneoffset.vgtest \
+	gethrtime.stderr.exp gethrtime.stdout.exp gethrtime.vgtest \
+	ldynsym.stderr.exp ldynsym.stdout.exp ldynsym.vgtest \
+	lsframe1.stderr.exp lsframe1.stdout.exp lsframe1.vgtest \
+	lsframe2.stderr.exp lsframe2.stdout.exp lsframe2.vgtest \
+	mmapobj_bssonly.stderr.exp mmapobj_bssonly.stdout.exp mmapobj_bssonly.vgtest \
+	name_service_door.stderr.exp-amd64 name_service_door.stderr.exp-x86 \
+	name_service_door.stdout.exp name_service_door.vgtest \
+	pkcs11.stderr.exp-illumos pkcs11.stderr.exp-solaris pkcs11.stdout.exp pkcs11.vgtest \
+	scalar.stderr.exp scalar.stdout.exp scalar.vgtest \
+	scalar_frealpathat.stderr.exp scalar_frealpathat.stdout.exp scalar_frealpathat.vgtest \
+	scalar_ioctl.stderr.exp scalar_ioctl.stdout.exp scalar_ioctl.vgtest \
+	scalar_lwp_kill.stderr.exp scalar_lwp_kill.stdout.exp scalar_lwp_kill.vgtest \
+	scalar_lwp_name.stderr.exp scalar_lwp_name.stdout.exp scalar_lwp_name.vgtest \
+	scalar_lwp_sigqueue.stderr.exp scalar_lwp_sigqueue.stdout.exp scalar_lwp_sigqueue.vgtest \
+	scalar_lwp_sigqueue_pid.stderr.exp scalar_lwp_sigqueue_pid.vgtest \
+	scalar_obsolete.stderr.exp scalar_obsolete.stdout.exp scalar_obsolete.vgtest \
+	scalar_shm_new.stderr.exp scalar_shm_new.stdout.exp scalar_shm_new.vgtest \
+	scalar_spawn.stderr.exp scalar_spawn.stdout.exp scalar_spawn.vgtest \
+	scalar_tsol_clearance.stderr.exp scalar_tsol_clearance.vgtest \
+	scalar_utimensat.stderr.exp scalar_utimensat.stdout.exp scalar_utimensat.vgtest \
+	scalar_utimesys.stderr.exp scalar_utimesys.stdout.exp scalar_utimesys.vgtest \
+	scalar_uuidsys.stderr.exp scalar_uuidsys.stdout.exp scalar_uuidsys.vgtest \
+	scalar_zone_defunct.stderr.exp scalar_zone_defunct.stdout.exp scalar_zone_defunct.vgtest \
+	sendfilev.stderr.exp sendfilev.stdout.exp sendfilev.vgtest \
+	shmat.stderr.exp shmat.stdout.exp shmat.vgtest \
+	spawn.stderr.exp spawn.stdout.exp spawn.vgtest \
+	strlcpy.stderr.exp strlcpy.stdout.exp strlcpy.vgtest \
+	supponlyobj.stderr.exp supponlyobj.supp supponlyobj.vgtest \
+	syscall_at.stderr.exp syscall_at.stdout.exp syscall_at.vgtest \
+	thr_daemon_exit_libc.stderr.exp thr_daemon_exit_libc.stdout.exp thr_daemon_exit_libc.vgtest \
+	thr_daemon_exit_standalone.stderr.exp thr_daemon_exit_standalone.stdout.exp thr_daemon_exit_standalone.vgtest
+
+check_PROGRAMS = \
+	brk \
+	context_stack_die \
+	door_data \
+	door_kill \
+	gethrtime \
+	inlinfo \
+	inlinfo_nested.so \
+	ldynsym \
+	lsframe1 \
+	lsframe2 \
+	mmapobj_bssonly \
+	mmapobj_bssonly.so \
+	name_service_door \
+	pkcs11 \
+	scalar \
+	scalar_ioctl \
+	sendfilev \
+	shmat \
+	strlcpy \
+	syscall_at \
+	thr_daemon_exit_libc \
+	thr_daemon_exit_standalone
+
+if SOLARIS_EXECVE_SYSCALL_TAKES_FLAGS
+check_PROGRAMS += execx
+endif
+
+if SOLARIS_GETZONEOFFSET_FASTTRAP
+check_PROGRAMS += getzoneoffset
+endif
+
+if SOLARIS_OLD_SYSCALLS
+check_PROGRAMS += scalar_obsolete
+endif
+
+if SOLARIS_FREALPATHAT_SYSCALL
+check_PROGRAMS += scalar_frealpathat
+endif
+
+if SOLARIS_LWP_NAME_SYSCALL
+check_PROGRAMS += scalar_lwp_name
+endif
+
+if SOLARIS_LWP_SIGQUEUE_SYSCALL
+if SOLARIS_LWP_SIGQUEUE_SYSCALL_TAKES_PID
+check_PROGRAMS += scalar_lwp_sigqueue_pid
+else
+check_PROGRAMS += scalar_lwp_sigqueue
+endif
+else
+check_PROGRAMS += scalar_lwp_kill
+endif
+
+if SOLARIS_SHM_NEW
+check_PROGRAMS += scalar_shm_new
+endif
+
+if SOLARIS_SPAWN_SYSCALL
+check_PROGRAMS += scalar_spawn spawn
+endif
+
+if SOLARIS_TSOL_CLEARANCE
+check_PROGRAMS += scalar_tsol_clearance
+scalar_tsol_clearance_LDADD = -ltsol
+endif
+
+if SOLARIS_UTIMENSAT_SYSCALL
+check_PROGRAMS += scalar_utimensat
+endif
+
+if SOLARIS_UTIMESYS_SYSCALL
+check_PROGRAMS += scalar_utimesys
+endif
+
+if SOLARIS_UUIDSYS_SYSCALL
+check_PROGRAMS += scalar_uuidsys
+endif
+
+if SOLARIS_ZONE_DEFUNCT 
+check_PROGRAMS += scalar_zone_defunct
+endif
+
+AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
+door_kill_LDADD = -lpthread
+ldynsym_LDFLAGS = -Wl,--strip-all
+pkcs11_LDADD = -lpkcs11
+sendfilev_LDADD = -lsendfile
+
+inlinfo_SOURCES = inlinfo.c
+inlinfo_DEPENDENCIES = inlinfo_nested.so
+inlinfo_LDFLAGS = -Wl,-rpath,$(top_builddir)/memcheck/tests/solaris
+inlinfo_LDADD = inlinfo_nested.so
+inlinfo_nested_so_SOURCES = inlinfo_nested.c
+inlinfo_nested_so_CFLAGS = $(AM_CFLAGS) -fPIC
+inlinfo_nested_so_LDFLAGS = -Wl,-rpath,$(top_builddir)/memcheck/tests/solaris -shared -fPIC
+
+mmapobj_bssonly_SOURCES = mmapobj_bssonly.c
+mmapobj_bssonly_DEPENDENCIES = mmapobj_bssonly.so
+mmapobj_bssonly_LDFLAGS = -Wl,-rpath,$(top_builddir)/memcheck/tests/solaris
+mmapobj_bssonly_LDADD = mmapobj_bssonly.so
+mmapobj_bssonly_so_SOURCES = mmapobj_bssonly_lib.c
+mmapobj_bssonly_so_CFLAGS = $(AM_CFLAGS) -fPIC
+mmapobj_bssonly_so_LDFLAGS = -nostartfiles -nodefaultlibs -shared
+
+thr_daemon_exit_standalone_LDFLAGS = -nostartfiles -nodefaultlibs
diff --git a/memcheck/tests/solaris/brk.c b/memcheck/tests/solaris/brk.c
new file mode 100644
index 0000000..4ec6bf5
--- /dev/null
+++ b/memcheck/tests/solaris/brk.c
@@ -0,0 +1,83 @@
+/* Test for the brk syscall wrapper. */
+
+#include <assert.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/syscall.h>
+
+/* Data segment end. */
+extern int _end;
+static char *begin = (char *)&_end;
+
+__attribute__((noinline))
+static int test_begin(void)
+{
+   int res = 0;
+   int tmp;
+
+   /* Check that a value at the break is inaccessible. */
+   if (*begin)
+      res++;
+
+   /* Allocate one byte and check that the last byte is accessible and
+      initialized. */
+   tmp = syscall(SYS_brk, begin + 1);
+   assert(tmp != -1);
+   if (*begin)
+      res++;
+
+   /* Deallocate one byte and check that the last byte is now inaccessible. */
+   tmp = syscall(SYS_brk, begin);
+   assert(tmp != -1);
+   if (*begin)
+      res++;
+
+   return res;
+}
+
+__attribute__((noinline))
+static void test_updown(void)
+{
+   int tmp;
+   size_t i;
+
+#define MAX_SIZE 8192
+   /* Run up phase. */
+   for (i = 0; i < MAX_SIZE; i++) {
+      tmp = syscall(SYS_brk, begin + i);
+      assert(tmp != -1);
+   }
+
+   /* Run down phase. */
+   for (i = 0; i < MAX_SIZE; i++) {
+      tmp = syscall(SYS_brk, begin + MAX_SIZE - 1 - i);
+      assert(tmp != -1);
+   }
+#undef MAX_SIZE
+}
+
+__attribute__((noinline))
+static void test_range(void)
+{
+   int tmp;
+
+   tmp = syscall(SYS_brk, begin - 1);
+   assert(tmp == -1);
+   assert(errno == ENOMEM);
+
+   /* Unified limit for 64-bit and 32-bit version. */
+   unsigned long long impossible_limit = 0xffffff4fffffffULL;
+   tmp = syscall(SYS_brk, impossible_limit);
+   assert(tmp == -1);
+   assert(errno == ENOMEM);
+}
+
+int main(void)
+{
+   int res;
+   res = test_begin();
+   test_updown();
+   test_range();
+   return res;
+}
+
diff --git a/memcheck/tests/solaris/brk.stderr.exp b/memcheck/tests/solaris/brk.stderr.exp
new file mode 100644
index 0000000..3e981d5
--- /dev/null
+++ b/memcheck/tests/solaris/brk.stderr.exp
@@ -0,0 +1,11 @@
+Invalid read of size 1
+   at 0x........: test_begin (brk.c:19)
+   by 0x........: main (brk.c:78)
+ Address 0x........ is 0 bytes after the brk data segment limit 0x........
+
+Invalid read of size 1
+   at 0x........: test_begin (brk.c:32)
+   by 0x........: main (brk.c:78)
+ Address 0x........ is 0 bytes after the brk data segment limit 0x........
+
+brk segment overflow in thread #1: can't grow to 0x........
diff --git a/memcheck/tests/solaris/brk.stdout.exp b/memcheck/tests/solaris/brk.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/brk.stdout.exp
diff --git a/memcheck/tests/solaris/brk.vgtest b/memcheck/tests/solaris/brk.vgtest
new file mode 100644
index 0000000..1306b77
--- /dev/null
+++ b/memcheck/tests/solaris/brk.vgtest
@@ -0,0 +1,2 @@
+prog: brk
+vgopts: -q
diff --git a/memcheck/tests/solaris/context_stack_die.c b/memcheck/tests/solaris/context_stack_die.c
new file mode 100644
index 0000000..8673a91
--- /dev/null
+++ b/memcheck/tests/solaris/context_stack_die.c
@@ -0,0 +1,43 @@
+/* Test that the stack correctly dies after a setcontext(2) call. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+static volatile int *sp;
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   sp = (int *) &ucp->uc_mcontext.gregs[0];
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   /* Always-null value that is used to prevent any possible compiler
+      optimizations. */
+   volatile int zero = 0;
+
+   /* Setup a signal handler. */
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   /* Raise a signal. */
+   raise(SIGUSR1);
+
+   /* Value pointed by sp should be at this point uninitialized. */
+   if (*sp && zero)
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/context_stack_die.stderr.exp b/memcheck/tests/solaris/context_stack_die.stderr.exp
new file mode 100644
index 0000000..556123e
--- /dev/null
+++ b/memcheck/tests/solaris/context_stack_die.stderr.exp
@@ -0,0 +1,5 @@
+Invalid read of size 4
+   at 0x........: main (context_stack_die.c:38)
+ Address 0x........ is on thread 1's stack
+ .... bytes below stack pointer
+
diff --git a/memcheck/tests/solaris/context_stack_die.stdout.exp b/memcheck/tests/solaris/context_stack_die.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/context_stack_die.stdout.exp
diff --git a/memcheck/tests/solaris/context_stack_die.vgtest b/memcheck/tests/solaris/context_stack_die.vgtest
new file mode 100644
index 0000000..f5c8604
--- /dev/null
+++ b/memcheck/tests/solaris/context_stack_die.vgtest
@@ -0,0 +1,2 @@
+prog: context_stack_die
+vgopts: -q
diff --git a/memcheck/tests/solaris/door_data.c b/memcheck/tests/solaris/door_data.c
new file mode 100644
index 0000000..85209f0
--- /dev/null
+++ b/memcheck/tests/solaris/door_data.c
@@ -0,0 +1,208 @@
+/* Simple door test. */
+
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+static char door_file[] = "/tmp/vgtest_door_data.XXXXXX";
+static volatile int exit_now = 0;
+
+static void child_handler(int sig)
+{
+   if (!exit_now) {
+      fprintf(stderr, "Received premature SIGCHLD.\n");
+      unlink(door_file);
+      exit(1);
+   }
+}
+
+/* SERVER CODE */
+static void server_procedure(void *cookie, char *argp, size_t arg_size,
+                             door_desc_t *dp, uint_t n_desc)
+{
+   char data[] = "Hello from server";
+
+   if (!argp)
+      goto out;
+
+   if (arg_size > INT_MAX) {
+      fprintf(stderr, "Value received from a client is too big.\n");
+      goto out;
+   }
+
+   printf("SERVER: %.*s\n", (int)arg_size, argp);
+   fflush(stdout);
+
+out:
+   /* Let server_main() know that we should exit. */
+   *(int*)cookie = 1;
+
+   door_return(data, strlen(data) + 1, NULL, 0);
+
+   /* Function door_return() should never return. */
+   perror("door_return");
+   exit(1);
+}
+
+static int server_main(void)
+{
+   int res = 1;
+   int did = -1;
+   int attached = 0;
+
+   /* Make sure nothing else is attached. */
+   fdetach(door_file);
+
+   if ((did = door_create(server_procedure, (void*)&exit_now, 0)) < 0) {
+      perror("door_create");
+      return 1;
+   }
+
+   /* Attach to file system. */
+   if (fattach(did, door_file) < 0) {
+      char str[100];
+      snprintf(str, sizeof(str), "fattach %s", door_file);
+      perror(str);
+      goto out;
+   }
+   attached = 1;
+
+   /* Poor man's termination. */
+   while (!exit_now)
+      sleep(1);
+
+   res = 0;
+
+out:
+   if (attached && unlink(door_file)) {
+      char str[100];
+      snprintf(str, sizeof(str), "unlink %s", door_file);
+      perror(str);
+   }
+   if (did >= 0 && door_revoke(did))
+      perror("door_revoke");
+
+   return res;
+}
+
+/* CLIENT CODE */
+static int client_main(void)
+{
+   int did;
+   char buf[128];
+   int tries;
+   door_arg_t params;
+   struct door_info info;
+
+   tries = 0;
+   while (1) {
+      /* Open the door file. */
+      if ((did = open(door_file, O_RDWR)) >= 0)
+         if (!door_info(did, &info))
+            break;
+
+      close(did);
+
+      if (tries > 10) {
+         char str[100];
+         snprintf(str, sizeof(str), "door_info %s", door_file);
+         perror(str);
+         return 1;
+      }
+
+      tries++;
+      sleep(1);
+   }
+
+   /* Set call parameters. */
+   snprintf(buf, sizeof(buf), "Hello from client");
+   params.data_ptr = buf;
+   params.data_size = strlen(buf) + 1;
+   params.desc_ptr = NULL;
+   params.desc_num = 0;
+   params.rbuf = buf;
+   params.rsize = sizeof(buf);
+
+   /* Make the call. */
+   if (door_call(did, &params)) {
+      perror("door_call");
+      close(did);
+      return 1;
+   }
+
+   close(did);
+
+   /* Print a result of the call. */
+   printf("CLIENT: %.*s\n", (int)params.rsize, params.rbuf);
+   fflush(stdout);
+
+   /* It's possible that the system allocated a new memory for rbuf.  Unmap it
+      if it's the case */
+   if (params.rbuf != buf)
+      if (munmap(params.rbuf, params.rsize) != 0) {
+         perror("munmap");
+         return 1;
+      }
+
+   return 0;
+}
+
+/* MAIN CODE */
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   int door_fd;
+
+   /* Establish handler for client error exit. */
+   sa.sa_handler = child_handler;
+   sa.sa_flags = SA_NOCLDSTOP;
+   if (sigemptyset(&sa.sa_mask)) {
+      perror("sigemptyset");
+      return 1;
+   }
+   if (sigaction(SIGCHLD, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   door_fd = mkstemp(door_file);
+   if (door_fd < 0) {
+      perror("mkstemp");
+      return 1;
+   }
+   close(door_fd);
+
+   pid = fork();
+   if (pid == -1) {
+      perror("fork");
+      return 1;
+   }
+
+   if (pid == 0) {
+      return client_main();
+   } else {
+      int res = server_main();
+      if (res == 0) {
+         do {
+            if (wait(NULL) == pid)
+               break;
+            if (errno != EINTR) {
+               perror("wait");
+               res = 1;
+            }
+         } while (errno == EINTR);
+      }
+      return res;
+   }
+}
diff --git a/memcheck/tests/solaris/door_data.stderr.exp b/memcheck/tests/solaris/door_data.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/door_data.stderr.exp
diff --git a/memcheck/tests/solaris/door_data.stdout.exp b/memcheck/tests/solaris/door_data.stdout.exp
new file mode 100644
index 0000000..0d0ccc3
--- /dev/null
+++ b/memcheck/tests/solaris/door_data.stdout.exp
@@ -0,0 +1,2 @@
+SERVER: Hello from client
+CLIENT: Hello from server
diff --git a/memcheck/tests/solaris/door_data.vgtest b/memcheck/tests/solaris/door_data.vgtest
new file mode 100644
index 0000000..bf93b36
--- /dev/null
+++ b/memcheck/tests/solaris/door_data.vgtest
@@ -0,0 +1,2 @@
+prog: door_data
+vgopts: -q --sim-hints=lax-doors
diff --git a/memcheck/tests/solaris/door_kill.c b/memcheck/tests/solaris/door_kill.c
new file mode 100644
index 0000000..06874c0
--- /dev/null
+++ b/memcheck/tests/solaris/door_kill.c
@@ -0,0 +1,102 @@
+/* Test cancellation of a door_return call. */
+
+#include <assert.h>
+#include <door.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/lwp.h>
+#include <unistd.h>
+
+static volatile lwpid_t server_lwpid = 0;
+
+static void server_procedure(void *cookie, char *argp, size_t arg_size,
+                             door_desc_t *dp, uint_t n_desc)
+{
+   assert(0);
+}
+
+static void *my_server_thread(void *arg)
+{
+   server_lwpid = _lwp_self();
+   door_return(NULL, 0, NULL, 0);
+   return NULL;
+}
+
+static void create_door_thread(door_info_t *info)
+{
+   static int called = 0;
+   pthread_t thread;
+   int res;
+
+   /* Allow to create only one server door thread. */
+   assert(!called);
+   called = 1;
+
+   res = pthread_create(&thread, NULL, my_server_thread, NULL);
+   if (res) {
+      errno = res;
+      perror("pthread_create");
+      exit(1);
+   }
+}
+
+static void signal_handler(int signo, siginfo_t *info, void *uc)
+{
+   const char str[] = "Signal caught.\n";
+   size_t len = sizeof(str) - 1;
+   ssize_t res;
+
+   res = write(STDOUT_FILENO, str, len);
+   assert(res == len);
+}
+
+int main(void)
+{
+   int res = 1;
+   int did = -1;
+   struct sigaction sa;
+
+   sa.sa_sigaction = signal_handler;
+   sa.sa_flags = SA_RESTART;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGINT, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   door_server_create(create_door_thread);
+
+   if ((did = door_create(server_procedure, NULL, 0)) < 0) {
+      perror("door_create");
+      return 1;
+   }
+
+   /* Let the server thread to run. */
+   sleep(2);
+
+   /* Send a signal to the server thread that should be already created and
+      blocked in door_return. */
+   if (_lwp_kill(server_lwpid, SIGINT)) {
+      perror("_lwp_kill");
+      goto out;
+   }
+
+   /* Let the other thread to run. */
+   sleep(2);
+
+   res = 0;
+
+out:
+   if (did >= 0 && door_revoke(did))
+      perror("door_revoke");
+
+   return res;
+}
+
diff --git a/memcheck/tests/solaris/door_kill.stderr.exp b/memcheck/tests/solaris/door_kill.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/door_kill.stderr.exp
diff --git a/memcheck/tests/solaris/door_kill.stdout.exp b/memcheck/tests/solaris/door_kill.stdout.exp
new file mode 100644
index 0000000..a49633f
--- /dev/null
+++ b/memcheck/tests/solaris/door_kill.stdout.exp
@@ -0,0 +1 @@
+Signal caught.
diff --git a/memcheck/tests/solaris/door_kill.vgtest b/memcheck/tests/solaris/door_kill.vgtest
new file mode 100644
index 0000000..1c1f58f
--- /dev/null
+++ b/memcheck/tests/solaris/door_kill.vgtest
@@ -0,0 +1,2 @@
+prog: door_kill
+vgopts: -q
diff --git a/memcheck/tests/solaris/execx.c b/memcheck/tests/solaris/execx.c
new file mode 100644
index 0000000..f15d3aa
--- /dev/null
+++ b/memcheck/tests/solaris/execx.c
@@ -0,0 +1,58 @@
+/* Tests variant of SYS_execve where the first argument is a file descriptor. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/execx.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+
+static void test_EFAULT(void) {
+   int ret = syscall(SYS_execve, -1, 0, 0, 0);
+   int error = errno;
+   if ((ret != -1) || (error != EFAULT))
+      fprintf(stderr, "Expecting EFAULT\n");
+}
+
+static void test_EBADF(void) {
+   int ret = syscall(SYS_execve, -1, 0, 0, EXEC_DESCRIPTOR);
+   int error = errno;
+   if ((ret != -1) || (error != EBADF))
+      fprintf(stderr, "Expecting EBADF\n");
+}
+
+static int test_fexecve(char * const *envp) {
+   int fd = open("/usr/bin/printf", O_EXEC);
+   if (fd < 0) {
+      perror("open");
+      return 1;
+   }
+
+   pid_t pid = fork();
+   if (pid == -1) {
+      perror("fork");
+      return 1;
+   } else if (pid > 0) {
+      /* parent */
+   } else {
+      char *argv[] = {"printf", "PASSED\n", NULL};
+
+      if (fexecve(fd, argv, envp) < 0) {
+         perror("fexecve");
+         _exit(1);
+      }
+
+   }
+
+   wait(NULL);
+   return 0;
+}
+
+int main(int argc, const char *argv[], char * const *envp) {
+   /* First exercise the syscall with some invalid input. */
+   test_EFAULT();
+   test_EBADF();
+
+   return test_fexecve(envp);
+}
diff --git a/memcheck/tests/solaris/execx.stderr.exp b/memcheck/tests/solaris/execx.stderr.exp
new file mode 100644
index 0000000..9e86cbd
--- /dev/null
+++ b/memcheck/tests/solaris/execx.stderr.exp
@@ -0,0 +1,4 @@
+Syscall param execve(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/execx.stdout.exp b/memcheck/tests/solaris/execx.stdout.exp
new file mode 100644
index 0000000..53cdf1e
--- /dev/null
+++ b/memcheck/tests/solaris/execx.stdout.exp
@@ -0,0 +1 @@
+PASSED
diff --git a/memcheck/tests/solaris/execx.vgtest b/memcheck/tests/solaris/execx.vgtest
new file mode 100644
index 0000000..3c81690
--- /dev/null
+++ b/memcheck/tests/solaris/execx.vgtest
@@ -0,0 +1,3 @@
+prereq: test -e execx
+prog: execx
+vgopts: -q --trace-children=yes --num-callers=1
diff --git a/memcheck/tests/solaris/filter_ldynsym b/memcheck/tests/solaris/filter_ldynsym
new file mode 100755
index 0000000..6859692
--- /dev/null
+++ b/memcheck/tests/solaris/filter_ldynsym
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+# remove path to ldynsym
+sed "s/(in .*ldynsym)/(in ldynsym)/" |
+
+../filter_stderr "$@"
+
diff --git a/memcheck/tests/solaris/filter_name_service_door b/memcheck/tests/solaris/filter_name_service_door
new file mode 100755
index 0000000..25e5b91
--- /dev/null
+++ b/memcheck/tests/solaris/filter_name_service_door
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+# unify name_service_door location
+sed "s|/system/volatile|...|" |
+sed "s|/var/run|...|" |
+
+./filter_stderr "$@"
+
diff --git a/memcheck/tests/solaris/filter_scalar b/memcheck/tests/solaris/filter_scalar
new file mode 100755
index 0000000..1a3a6eb
--- /dev/null
+++ b/memcheck/tests/solaris/filter_scalar
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+# 'unlinkat' syscall number differs between Illumos and Solaris
+sed "s/[0-9]*:            SYS_unlinkat/xx:            SYS_unlinkat/" |
+
+# Filter out "in frame #x, created by" lines as they differ between x86/amd64.
+# on x86:   in frame #0, created by syscall (???)
+# on amd64: in frame #1, created by *function* (scalar.c:272)
+sed '/in frame #., created by/d' |
+
+./filter_stderr "$@" |
+
+# And finally remove temporary line with frame #0 present to unify
+# stack traces between x86 and amd64.
+sed '/at 0x........: syscall (in \/...libc...)/d'
diff --git a/memcheck/tests/solaris/filter_sendfilev b/memcheck/tests/solaris/filter_sendfilev
new file mode 100755
index 0000000..24a59d8
--- /dev/null
+++ b/memcheck/tests/solaris/filter_sendfilev
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+# Filter the frame number which differs between x86 and amd64
+sed "s/in frame #[0-9]/in frame #./" |
+
+./filter_stderr "$@"
+
diff --git a/memcheck/tests/solaris/filter_stderr b/memcheck/tests/solaris/filter_stderr
new file mode 100755
index 0000000..a778e97
--- /dev/null
+++ b/memcheck/tests/solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr "$@"
diff --git a/memcheck/tests/solaris/filter_syscall_at b/memcheck/tests/solaris/filter_syscall_at
new file mode 100755
index 0000000..7a074ee
--- /dev/null
+++ b/memcheck/tests/solaris/filter_syscall_at
@@ -0,0 +1,8 @@
+#! /bin/sh
+
+# unify utimesys() and utimensat() syscall names
+sed "s/utimesys/utimeXXX/" |
+sed "s/utimensat/utimeXXX/" |
+
+./filter_stderr "$@"
+
diff --git a/memcheck/tests/solaris/gethrtime.c b/memcheck/tests/solaris/gethrtime.c
new file mode 100644
index 0000000..26bb078
--- /dev/null
+++ b/memcheck/tests/solaris/gethrtime.c
@@ -0,0 +1,39 @@
+/* Test for gethrtime which either issues a classic syscall
+   or leverages fasttrap available on Solaris with tscp hwcap. */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/trap.h>
+
+int main(void)
+{
+   hrtime_t hrt = gethrtime();
+   if (hrt > 0)
+      printf("PASS\n");
+
+/* Exercise the fasttrap directly if available. When tscp hwcap
+   is not supported, it simply returns NULL. */
+#if defined(SOLARIS_GETHRT_FASTTRAP)
+#if defined(VGP_x86_solaris)
+   __asm__ ( \
+      "movl %[FASTTRAP],%%eax\n"
+      "int $0xd2\n"
+      :
+      : [FASTTRAP] "i" (T_GETHRT)
+      : "eax", "edx", "cc");
+#elif defined(VGP_amd64_solaris)
+   __asm__ ( \
+      "movq %[FASTTRAP],%%rax\n"
+      "int $0xd2\n"
+      :
+      : [FASTTRAP] "i" (T_GETHRT)
+      : "rax", "rdx", "cc");
+#else
+#  error "Unknown platform"
+#endif
+#endif /* SOLARIS_GETHRT_FASTTRAP */
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/gethrtime.stderr.exp b/memcheck/tests/solaris/gethrtime.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/gethrtime.stderr.exp
diff --git a/memcheck/tests/solaris/gethrtime.stdout.exp b/memcheck/tests/solaris/gethrtime.stdout.exp
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/memcheck/tests/solaris/gethrtime.stdout.exp
@@ -0,0 +1 @@
+PASS
diff --git a/memcheck/tests/solaris/gethrtime.vgtest b/memcheck/tests/solaris/gethrtime.vgtest
new file mode 100644
index 0000000..c10414c
--- /dev/null
+++ b/memcheck/tests/solaris/gethrtime.vgtest
@@ -0,0 +1,2 @@
+prog: gethrtime
+vgopts: -q
diff --git a/memcheck/tests/solaris/getzoneoffset.c b/memcheck/tests/solaris/getzoneoffset.c
new file mode 100644
index 0000000..eac0724
--- /dev/null
+++ b/memcheck/tests/solaris/getzoneoffset.c
@@ -0,0 +1,30 @@
+/* Test for get_zone_offset fasttrap. */
+
+#include "config.h"
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/trap.h>
+
+int main(void)
+{
+#if defined(VGP_x86_solaris)
+   __asm__ ( \
+      "movl %[FASTTRAP],%%eax\n"
+      "int $0xd2\n"
+      :
+      : [FASTTRAP] "i" (T_GETZONEOFFSET)
+      : "eax", "edx", "cc");
+#elif defined(VGP_amd64_solaris)
+   __asm__ ( \
+      "movq %[FASTTRAP],%%rax\n"
+      "int $0xd2\n"
+      :
+      : [FASTTRAP] "i" (T_GETZONEOFFSET)
+      : "rax", "rdx", "cc");
+#else
+#  error "Unknown platform"
+#endif
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/getzoneoffset.stderr.exp b/memcheck/tests/solaris/getzoneoffset.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/getzoneoffset.stderr.exp
diff --git a/memcheck/tests/solaris/getzoneoffset.vgtest b/memcheck/tests/solaris/getzoneoffset.vgtest
new file mode 100644
index 0000000..124b643
--- /dev/null
+++ b/memcheck/tests/solaris/getzoneoffset.vgtest
@@ -0,0 +1,3 @@
+prereq: test -e getzoneoffset
+prog: getzoneoffset
+vgopts: -q
diff --git a/memcheck/tests/solaris/inlinfo.c b/memcheck/tests/solaris/inlinfo.c
new file mode 100644
index 0000000..113b0f8
--- /dev/null
+++ b/memcheck/tests/solaris/inlinfo.c
@@ -0,0 +1,11 @@
+/* Function below main (_start) is part of this object.
+ * So we use main() in this object as a marker for
+ * functions in inlinfo_nested.so.
+ */
+
+extern int main_nested(void);
+
+int main() {
+   return main_nested();
+}
+
diff --git a/memcheck/tests/solaris/inlinfo_nested.c b/memcheck/tests/solaris/inlinfo_nested.c
new file mode 100644
index 0000000..88fe09b
--- /dev/null
+++ b/memcheck/tests/solaris/inlinfo_nested.c
@@ -0,0 +1,78 @@
+/* Taken from memcheck/tests/inlinfo.c almost verbatim;
+ * only main() renamed to main_nested().
+ */
+
+#include "../../memcheck.h"
+#define INLINE    inline __attribute__((always_inline))
+
+INLINE int fun_d(int argd) {
+   static int locd = 0;
+   if (argd > 0)
+      locd += argd;
+   return locd;
+}
+
+INLINE int fun_c(int argc) {
+   static int locc = 0;
+   locc += argc;
+   return fun_d(locc);
+}
+
+INLINE int fun_b(int argb) {
+   static int locb = 0;
+   locb += argb;
+   return fun_c(locb);
+}
+
+INLINE int fun_a(int arga) {
+   static int loca = 0;
+   loca += arga;
+   return fun_b(loca);
+}
+
+__attribute__((noinline))
+static int fun_noninline_m(int argm)
+{
+   return fun_d(argm);
+}
+
+__attribute__((noinline))
+static int fun_noninline_o(int argo)
+{
+   static int loco = 0;
+   if (argo > 0)
+      loco += argo;
+   return loco;
+}
+
+INLINE int fun_f(int argf) {
+   static int locf = 0;
+   locf += argf;
+   return fun_noninline_o(locf);
+}
+
+INLINE int fun_e(int arge) {
+   static int loce = 0;
+   loce += arge;
+   return fun_f(loce);
+}
+
+__attribute__((noinline))
+static int fun_noninline_n(int argn)
+{
+   return fun_e(argn);
+}
+
+
+int main_nested(void) {
+   int result;
+   result = fun_a(result);
+   VALGRIND_MAKE_MEM_UNDEFINED(&result, sizeof(result));
+   result += fun_noninline_m(result);
+   VALGRIND_MAKE_MEM_UNDEFINED(&result, sizeof(result));
+   result += fun_d(result);
+   VALGRIND_MAKE_MEM_UNDEFINED(&result, sizeof(result));
+   result += fun_noninline_n(result);
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/ldynsym.c b/memcheck/tests/solaris/ldynsym.c
new file mode 100644
index 0000000..df4f8e0
--- /dev/null
+++ b/memcheck/tests/solaris/ldynsym.c
@@ -0,0 +1,29 @@
+/* Test that the .SUNW_ldynsym section is correctly read. */
+
+#include <stdlib.h>
+
+__attribute__((noinline))
+static void function3(size_t size)
+{
+   malloc(size);
+}
+
+__attribute__((noinline))
+static void function2(size_t size)
+{
+   function3(size);
+}
+
+__attribute__((noinline))
+static void function(size_t size)
+{
+   function2(size);
+}
+
+int main(void)
+{
+   function(10);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/ldynsym.stderr.exp b/memcheck/tests/solaris/ldynsym.stderr.exp
new file mode 100644
index 0000000..247b504
--- /dev/null
+++ b/memcheck/tests/solaris/ldynsym.stderr.exp
@@ -0,0 +1,7 @@
+10 bytes in 1 blocks are definitely lost in loss record ... of ...
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: function3 (in ldynsym)
+   by 0x........: function2 (in ldynsym)
+   by 0x........: function (in ldynsym)
+   by 0x........: main (in ldynsym)
+
diff --git a/memcheck/tests/solaris/ldynsym.stdout.exp b/memcheck/tests/solaris/ldynsym.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/ldynsym.stdout.exp
diff --git a/memcheck/tests/solaris/ldynsym.vgtest b/memcheck/tests/solaris/ldynsym.vgtest
new file mode 100644
index 0000000..71c2820
--- /dev/null
+++ b/memcheck/tests/solaris/ldynsym.vgtest
@@ -0,0 +1,3 @@
+prog: ldynsym
+vgopts: -q --leak-check=yes
+stderr_filter: filter_ldynsym
diff --git a/memcheck/tests/solaris/lsframe1.c b/memcheck/tests/solaris/lsframe1.c
new file mode 100644
index 0000000..71fc9d8
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe1.c
@@ -0,0 +1,23 @@
+/* Demonstrate Memcheck correctly handling a 64M array on the stack.
+   Requires --max-stackframe=67108884 or above.  And since it
+   generates a very large stack, --main-stacksize=67200000
+   (approximately) is also required. */
+
+#include <stdio.h>
+
+#define N_MBYTES 64
+#define N_INTS ((N_MBYTES * 1048576) / sizeof(int))
+
+int main(void)
+{
+   int i, sum;
+   int arr[N_INTS];
+   printf("lsframe1: start\n");
+   for (i = 0; i < N_INTS; i++)
+      arr[i] = i;
+   sum = 0;
+   for (i = 0; i < N_INTS; i++)
+      sum += arr[i];
+   printf("lsframe1: done, result is %d\n", sum);
+   return 0;
+}
diff --git a/memcheck/tests/solaris/lsframe1.stderr.exp b/memcheck/tests/solaris/lsframe1.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe1.stderr.exp
diff --git a/memcheck/tests/solaris/lsframe1.stdout.exp b/memcheck/tests/solaris/lsframe1.stdout.exp
new file mode 100644
index 0000000..e2cb30d
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe1.stdout.exp
@@ -0,0 +1,2 @@
+lsframe1: start
+lsframe1: done, result is -8388608
diff --git a/memcheck/tests/solaris/lsframe1.vgtest b/memcheck/tests/solaris/lsframe1.vgtest
new file mode 100644
index 0000000..ac49677
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe1.vgtest
@@ -0,0 +1,3 @@
+prog: lsframe1
+vgopts: -q --main-stacksize=67200000 --max-stackframe=67200000
+stderr_filter: ../filter_allocs
diff --git a/memcheck/tests/solaris/lsframe2.c b/memcheck/tests/solaris/lsframe2.c
new file mode 100644
index 0000000..db7f1a0
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe2.c
@@ -0,0 +1,31 @@
+/* Demonstrate Memcheck correctly handling chain of 64 recursive
+   calls, each of which allocates a 1 M array on the stack.  Requires
+   --main-stacksize=67117057 (on amd64-linux) or above, but works fine
+   if you specify that. */
+
+#include <stdio.h>
+
+#define N_MBYTES 64
+#define N_INTS_PER_MBYTE (1048576 / sizeof(int))
+
+int rec(int depth)
+{
+   int i, zzz;
+   int arr[N_INTS_PER_MBYTE];
+   if (depth == 0) return 0;
+   for (i = 0; i < N_INTS_PER_MBYTE; i++)
+      arr[i] = i * depth;
+   zzz = rec(depth-1);
+   for (i = 0; i < N_INTS_PER_MBYTE; i++)
+       zzz += arr[i];
+   return zzz;
+}
+
+int main(void)
+{
+   int sum;
+   printf("lsframe2: start\n");
+   sum = rec(N_MBYTES);
+   printf("lsframe2: done, result is %d\n", sum);
+   return 0;
+}
diff --git a/memcheck/tests/solaris/lsframe2.stderr.exp b/memcheck/tests/solaris/lsframe2.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe2.stderr.exp
diff --git a/memcheck/tests/solaris/lsframe2.stdout.exp b/memcheck/tests/solaris/lsframe2.stdout.exp
new file mode 100644
index 0000000..9905a0d
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe2.stdout.exp
@@ -0,0 +1,2 @@
+lsframe2: start
+lsframe2: done, result is -272629760
diff --git a/memcheck/tests/solaris/lsframe2.vgtest b/memcheck/tests/solaris/lsframe2.vgtest
new file mode 100644
index 0000000..7b1ee56
--- /dev/null
+++ b/memcheck/tests/solaris/lsframe2.vgtest
@@ -0,0 +1,3 @@
+prog: lsframe2
+vgopts: -q --main-stacksize=68500000
+stderr_filter: ../filter_allocs
diff --git a/memcheck/tests/solaris/mmapobj_bssonly.c b/memcheck/tests/solaris/mmapobj_bssonly.c
new file mode 100644
index 0000000..ba702f5
--- /dev/null
+++ b/memcheck/tests/solaris/mmapobj_bssonly.c
@@ -0,0 +1,9 @@
+/* Tests loading of a shared library which contains only BSS section. */
+
+#include <stdio.h>
+
+int main(void)
+{
+   printf("PASS\n");
+   return 0;
+}
diff --git a/memcheck/tests/solaris/mmapobj_bssonly.stderr.exp b/memcheck/tests/solaris/mmapobj_bssonly.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/mmapobj_bssonly.stderr.exp
diff --git a/memcheck/tests/solaris/mmapobj_bssonly.stdout.exp b/memcheck/tests/solaris/mmapobj_bssonly.stdout.exp
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/memcheck/tests/solaris/mmapobj_bssonly.stdout.exp
@@ -0,0 +1 @@
+PASS
diff --git a/memcheck/tests/solaris/mmapobj_bssonly.vgtest b/memcheck/tests/solaris/mmapobj_bssonly.vgtest
new file mode 100644
index 0000000..07937c9
--- /dev/null
+++ b/memcheck/tests/solaris/mmapobj_bssonly.vgtest
@@ -0,0 +1,2 @@
+prog: mmapobj_bssonly
+vgopts: -q
diff --git a/memcheck/tests/solaris/mmapobj_bssonly_lib.c b/memcheck/tests/solaris/mmapobj_bssonly_lib.c
new file mode 100644
index 0000000..cc5e277
--- /dev/null
+++ b/memcheck/tests/solaris/mmapobj_bssonly_lib.c
@@ -0,0 +1,3 @@
+/* Contains only uninitialized data which end up in BSS section. */
+
+char dummy[10];
diff --git a/memcheck/tests/solaris/name_service_door.c b/memcheck/tests/solaris/name_service_door.c
new file mode 100644
index 0000000..4afbf70
--- /dev/null
+++ b/memcheck/tests/solaris/name_service_door.c
@@ -0,0 +1,272 @@
+/* Tests for name switch cache daemon (nscd) door wrapper. */
+
+#include "config.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <door.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <nss_dbdefs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#if defined(SOLARIS_NSCD_DOOR_SYSTEM_VOLATILE)
+#define DOOR_FILE "/system/volatile/name_service_door"
+#else
+#define DOOR_FILE "/var/run/name_service_door"
+#endif
+
+#define HEADER(file, test_name) \
+   fprintf(file, "---------------------------------------------------------\n"  \
+                 "%s\n"                                                         \
+                 "---------------------------------------------------------\n", \
+                 test_name);
+
+
+static long x0;
+
+/* It's possible that the system allocated a new memory for rbuf.
+   Unmap it if it is the case. */
+static int handle_rbuf(door_arg_t *params, void *buf)
+{
+   if (params->rbuf != buf) {
+      if (munmap(params->rbuf, params->rsize) != 0) {
+         perror("munmap");
+         return EINVAL;
+      }
+   }
+
+   return 0;
+}
+
+__attribute__((noinline))
+static int test_app_small_request(int did)
+{
+   /* Set call parameters. */
+   size_t buf_size = sizeof(uint32_t);
+   char *buf = malloc(buf_size);
+   assert(buf != NULL);
+
+   nss_pheader_t *header = (nss_pheader_t *) buf;
+   header->nsc_callnumber = x0 + NSCD_GETENT;
+
+   door_arg_t params;
+   params.data_ptr = buf;
+   params.data_size = buf_size;
+   params.desc_ptr = NULL;
+   params.desc_num = 0;
+   params.rbuf = buf;
+   params.rsize = buf_size;
+
+   /* Make the call. */
+   if (door_call(did, &params) != 0) {
+      return errno;
+   }
+
+   return handle_rbuf(&params, buf);
+}
+
+__attribute__((noinline))
+static int test_app_uninitialized_request(int did)
+{
+   /* Set call parameters. */
+   size_t buf_size = sizeof(nss_pheader_t) + sizeof(nss_dbd_t);
+   char *buf = malloc(buf_size);
+   assert(buf != NULL);
+
+   nss_pheader_t *header = (nss_pheader_t *) buf;
+   header->nsc_callnumber = x0 + NSCD_GETENT;
+   header->dbd_off = x0 + sizeof(nss_pheader_t);
+   header->dbd_len = x0 + sizeof(nss_dbd_t);
+   nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t));
+   dbd->flags = x0;
+   dbd->o_name = x0 + 100;
+   dbd->o_config_name = x0 + 100;
+   dbd->o_default_config = x0 + 100;
+   header->key_off = x0 + sizeof(nss_pheader_t) + sizeof(nss_dbd_t);
+   header->key_len = x0 + 1; // one byte past the end of 'buf'
+   header->pbufsiz = x0 + 10000000;
+
+   door_arg_t params;
+   params.data_ptr = buf;
+   params.data_size = buf_size;
+   params.desc_ptr = NULL;
+   params.desc_num = 0;
+   params.rbuf = buf;
+   params.rsize = buf_size;
+
+   /* Make the call. */
+   if (door_call(did, &params) != 0) {
+      return errno;
+   }
+
+   /* Check definedness of response attributes ... */
+   int x = 0;
+   if (header->p_status != NSS_SUCCESS) x = -1; else x = -2;
+   if (header->p_herrno != 0) x = -2; else x = -3;
+   if (header->key_off != 0) x = -4; else x = -5;
+   if (header->key_len != 0) x = -6; else x = -7;
+   if (header->data_off != 0) x = -8; else x = -9;
+   if (header->data_len != 0) x = -10; else x = -11;
+   /* ... and now one which is not defined. */
+   if (header->reserved1 != 0) x = -12; else x = -13;
+
+   handle_rbuf(&params, buf);
+   return x;
+}
+
+__attribute__((noinline))
+static int test_app_proto_icmp(int did)
+{
+   door_arg_t params;
+   char buf[16384];
+
+   /* Set call parameters. */
+   nss_pheader_t *header = (nss_pheader_t *) buf;
+   header->nsc_callnumber = NSCD_SEARCH;
+   header->p_ruid = getuid();
+   header->p_euid = geteuid();
+   header->p_version = NSCD_HEADER_REV;
+   header->p_status = 0;
+   header->p_errno = 0;
+   header->p_herrno = 0;
+   header->libpriv = 0;
+   header->nss_dbop = NSS_DBOP_PROTOCOLS_BYNAME;
+
+   size_t name_len = strlen(NSS_DBNAM_PROTOCOLS);
+   size_t default_config_len = strlen(NSS_FILES_ONLY);
+   header->dbd_off = sizeof(nss_pheader_t);
+   header->dbd_len = sizeof(nss_dbd_t) + name_len + 1 + default_config_len + 1;
+   nss_dbd_t *dbd = (nss_dbd_t *) (buf + sizeof(nss_pheader_t));
+   dbd->o_name = sizeof(nss_dbd_t);
+   dbd->o_config_name = 0;
+   dbd->o_default_config = dbd->o_name + name_len + 1;
+   dbd->flags = 0;
+   strcpy(buf + header->dbd_off + dbd->o_name, NSS_DBNAM_PROTOCOLS);
+   strcpy(buf + header->dbd_off + dbd->o_default_config,
+          NSS_DEFCONF_PROTOCOLS);
+
+   name_len = strlen("icmp");
+   header->key_off = header->dbd_off + ROUND_UP(header->dbd_len, sizeof(nssuint_t));
+   header->key_len = name_len + 1;
+   strcpy(buf + header->key_off, "icmp");
+
+   header->data_off = header->key_off + ROUND_UP(header->key_len, sizeof(nssuint_t));
+   header->data_len = 0;
+   header->pbufsiz = header->data_off + header->data_len;
+
+   params.data_ptr = buf;
+   params.data_size = header->pbufsiz;
+   params.desc_ptr = NULL;
+   params.desc_num = 0;
+   params.rbuf = buf;
+   params.rsize = sizeof(buf);
+
+   /* Sanity checks on the nss_pheader_t header. */
+   assert(header->p_version == NSCD_HEADER_REV);
+   assert(header->dbd_off == sizeof(nss_pheader_t));
+   assert((params.data_size & 3) == 0);
+   assert((header->dbd_off & 3) == 0);
+   assert((header->key_off & 3) == 0);
+   assert((header->data_off & 3) == 0);
+   assert(header->data_off == params.data_size);
+   nssuint_t l1 = header->key_off - header-> dbd_off;
+   assert(l1 >= header->dbd_len);
+   nssuint_t l2 = header->data_off - header->key_off;
+   assert(l2 >= header->key_len);
+   assert(sizeof(nss_pheader_t) + l1 + l2 == header->data_off);
+   assert(header->data_off + header->data_len == header->pbufsiz);
+
+   /* Make the call. */
+   if (door_call(did, &params) != 0) {
+      return errno;
+   }
+
+   /* Print response attributes. */
+   HEADER(stdout, "app_proto_icmp");
+   printf("status=%u\n", header->p_status);
+   printf("errno=%u\n", header->p_errno);
+   printf("herrno=%u\n", header->p_herrno);
+   printf("bufsiz=%" PRIu64 "\n", header->pbufsiz);
+   printf("dbd_off=%" PRIu64 " dbd_len=%" PRIu64 "\n",
+          header->dbd_off, header->dbd_len);
+   printf("key_off=%" PRIu64 " key_len=%" PRIu64 "\n",
+          header->key_off, header->key_len);
+   printf("data_off=%" PRIu64 " data_len=%" PRIu64 "\n",
+          header->data_off, header->data_len);
+   printf("ext_off=%" PRIu64 " ext_len=%" PRIu64 "\n",
+          header->ext_off, header->ext_len);
+   printf("key=%s\n", buf + header->key_off);
+
+   /* Parse response proto data. */
+   char *p = buf + header->data_off;
+   char *limit = p + header->data_len;
+
+   while ((p < limit) && isspace(*p))
+      p++;
+   char *name_start = p;
+   while ((p < limit) && !isspace(*p))
+      p++; // skip over the name
+   name_len = p - name_start;
+
+   while ((p < limit) && isspace(*p))
+      p++;
+   char *number_start = p;
+   do {
+      p++; // skip over the proto number
+   } while ((p < limit) && !isspace(*p));
+   size_t number_len = p - number_start;
+
+   while ((p < limit) && isspace(*p))
+      p++;
+   char *aliases_start = p;
+   while ((p < limit) && !isspace(*p))
+      p++; // skip over the aliases
+   size_t aliases_len = p - aliases_start;
+
+   printf("data: name=%.*s number=%.*s aliases=%.*s\n",
+      (int) name_len, name_start, (int) number_len, number_start,
+      (int) aliases_len, aliases_start);
+
+   return handle_rbuf(&params, buf);
+}
+
+int main(int argc, const char *argv[])
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   int did = open(DOOR_FILE, O_RDONLY);
+   if (did < 0) {
+      perror("open " DOOR_FILE);
+      fprintf(stderr, "Make sure the name service switch daemon (nscd) "
+              "is running.\n");
+      return 1;
+   }
+
+   struct door_info info;
+   if (door_info(did, &info) != 0) {
+      perror("door_info " DOOR_FILE);
+      close(did);
+      return 1;
+   }
+
+   HEADER(stderr, "app_small_request");
+   test_app_small_request(did);
+
+   HEADER(stderr, "app_uninitialized_request");
+   test_app_uninitialized_request(did);
+
+   HEADER(stderr, "app_proto_icmp");
+   test_app_proto_icmp(did);
+
+   close(did);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/name_service_door.stderr.exp-amd64 b/memcheck/tests/solaris/name_service_door.stderr.exp-amd64
new file mode 100644
index 0000000..9ee4bd9
--- /dev/null
+++ b/memcheck/tests/solaris/name_service_door.stderr.exp-amd64
@@ -0,0 +1,146 @@
+---------------------------------------------------------
+app_small_request
+---------------------------------------------------------
+Syscall param door_call(".../name_service_door", nss_pheader->nsc_callnumber) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 0 bytes inside a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->p_version) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 12 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 32 bytes before an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 24 bytes before an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 16 bytes before an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 8 bytes before an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes inside an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 8 bytes inside an unallocated block of size 4,194,048 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->pbufsiz) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 24 bytes after a block of size 16 in arena "client"
+
+Syscall param door_call(".../name_service_door", pbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_dbd) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 4,194,033 bytes inside an unallocated block of size 4,194,048 in arena "client"
+
+---------------------------------------------------------
+app_uninitialized_request
+---------------------------------------------------------
+Syscall param door_call(".../name_service_door", nss_pheader->nsc_callnumber) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 0 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->p_version) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 16 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 48 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 56 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 64 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 72 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 80 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 88 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->pbufsiz) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 40 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", pbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes after a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_dbd) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 128 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 20 bytes inside an unallocated block of size 4,193,840 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_config_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 20 bytes inside an unallocated block of size 4,193,840 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_default_config) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 20 bytes inside an unallocated block of size 4,193,840 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss->key) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes after a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+---------------------------------------------------------
+app_proto_icmp
+---------------------------------------------------------
diff --git a/memcheck/tests/solaris/name_service_door.stderr.exp-x86 b/memcheck/tests/solaris/name_service_door.stderr.exp-x86
new file mode 100644
index 0000000..455f9b7
--- /dev/null
+++ b/memcheck/tests/solaris/name_service_door.stderr.exp-x86
@@ -0,0 +1,136 @@
+---------------------------------------------------------
+app_small_request
+---------------------------------------------------------
+Syscall param door_call(".../name_service_door", nss_pheader->nsc_callnumber) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 0 bytes inside a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->p_version) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 12 bytes after a block of size 4 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 8 bytes before an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes inside an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 8 bytes inside an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 16 bytes inside an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 24 bytes inside an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 32 bytes inside an unallocated block of size 4,194,128 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_pheader->pbufsiz) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 16 bytes before an unallocated block of size 4,194,128 in arena "client"
+
+---------------------------------------------------------
+app_uninitialized_request
+---------------------------------------------------------
+Syscall param door_call(".../name_service_door", nss_pheader->nsc_callnumber) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 0 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->p_version) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 16 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 48 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->dbd_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 56 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 64 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->key_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 72 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 80 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->data_len) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 88 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_pheader->pbufsiz) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 40 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", pbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes after a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_dbd) points to uninitialised byte(s)
+   ...
+ Address 0x........ is 128 bytes inside a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 36 bytes inside an unallocated block of size 4,193,936 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_config_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 36 bytes inside an unallocated block of size 4,193,936 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss_dbd->o_default_config) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 36 bytes inside an unallocated block of size 4,193,936 in arena "client"
+
+Syscall param door_call(".../name_service_door", nss->key) points to unaddressable byte(s)
+   ...
+ Address 0x........ is 0 bytes after a block of size 144 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+---------------------------------------------------------
+app_proto_icmp
+---------------------------------------------------------
diff --git a/memcheck/tests/solaris/name_service_door.stdout.exp b/memcheck/tests/solaris/name_service_door.stdout.exp
new file mode 100644
index 0000000..8ad8b72
--- /dev/null
+++ b/memcheck/tests/solaris/name_service_door.stdout.exp
@@ -0,0 +1,13 @@
+---------------------------------------------------------
+app_proto_icmp
+---------------------------------------------------------
+status=0
+errno=0
+herrno=0
+bufsiz=16384
+dbd_off=128 dbd_len=32
+key_off=160 key_len=5
+data_off=168 data_len=12
+ext_off=0 ext_len=0
+key=icmp
+data: name=icmp number=1 aliases=ICMP
diff --git a/memcheck/tests/solaris/name_service_door.vgtest b/memcheck/tests/solaris/name_service_door.vgtest
new file mode 100644
index 0000000..17ab5cb
--- /dev/null
+++ b/memcheck/tests/solaris/name_service_door.vgtest
@@ -0,0 +1,7 @@
+# Tests door wrapper of name switch cache daemon (nscd).
+# The nscd must be running and its door attached.
+prereq: test -e /system/volatile/name_service_door -o -e /var/run/name_service_door
+prog: name_service_door
+vgopts: -q
+stderr_filter: filter_name_service_door
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/pkcs11.c b/memcheck/tests/solaris/pkcs11.c
new file mode 100644
index 0000000..9fed347
--- /dev/null
+++ b/memcheck/tests/solaris/pkcs11.c
@@ -0,0 +1,64 @@
+/* Test for PKCS#11 calls. */ 
+
+#include <stdio.h>
+#include <security/cryptoki.h>
+#include <security/pkcs11.h>
+
+int main(void)
+{
+   CK_RV ret = C_Initialize(NULL);
+   if (ret != CKR_OK) {
+      fprintf(stderr, "Initialize: %lu\n", ret);
+      return 1;
+   }
+
+   CK_ULONG slot_count;
+   ret = C_GetSlotList(0, NULL, &slot_count);
+   if (ret != CKR_OK) {
+      fprintf(stderr, "GetSlotList(NULL): %lu\n", ret);
+      return 1;
+   }
+
+   CK_SLOT_ID_PTR slots = malloc(slot_count * sizeof(CK_SLOT_ID));
+   if (slots == NULL) {
+      fprintf(stderr, "malloc(slots)\n");
+      return 1;
+   }
+
+   ret = C_GetSlotList(0, slots, &slot_count);
+   if (ret != CKR_OK) {
+      fprintf(stderr, "GetSlotList(slots): %lu\n", ret);
+      return 1;
+   }
+
+   CK_ULONG i;
+   for (i = 0; i < slot_count; i++) {
+      CK_SLOT_ID slot_id = slots[i];
+
+      CK_ULONG mech_count;
+      ret = C_GetMechanismList(slot_id, NULL, &mech_count);
+      if (ret != CKR_OK) {
+         fprintf(stderr, "GetMechanismList(NULL): %lu\n", ret);
+         return 1;
+      }
+
+      CK_MECHANISM_TYPE_PTR mechs = malloc(mech_count * sizeof(CK_MECHANISM_TYPE));
+      if (slots == NULL) {
+         fprintf(stderr, "malloc(mechs)\n");
+         return 1;
+      }
+
+      ret = C_GetMechanismList(slot_id, mechs, &mech_count);
+      if (ret != CKR_OK) {
+         fprintf(stderr, "GetMechanismList(mechs): %lu\n", ret);
+         return 1;
+      }
+
+      free(mechs);
+   }
+
+   free(slots);
+   C_Finalize(NULL_PTR);
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/pkcs11.stderr.exp-illumos b/memcheck/tests/solaris/pkcs11.stderr.exp-illumos
new file mode 100644
index 0000000..03976f6
--- /dev/null
+++ b/memcheck/tests/solaris/pkcs11.stderr.exp-illumos
@@ -0,0 +1,6 @@
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
diff --git a/memcheck/tests/solaris/pkcs11.stderr.exp-solaris b/memcheck/tests/solaris/pkcs11.stderr.exp-solaris
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/pkcs11.stderr.exp-solaris
diff --git a/memcheck/tests/solaris/pkcs11.stdout.exp b/memcheck/tests/solaris/pkcs11.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/pkcs11.stdout.exp
diff --git a/memcheck/tests/solaris/pkcs11.vgtest b/memcheck/tests/solaris/pkcs11.vgtest
new file mode 100644
index 0000000..a887d63
--- /dev/null
+++ b/memcheck/tests/solaris/pkcs11.vgtest
@@ -0,0 +1,3 @@
+prog: pkcs11
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar.c b/memcheck/tests/solaris/scalar.c
new file mode 100644
index 0000000..281a2ed
--- /dev/null
+++ b/memcheck/tests/solaris/scalar.c
@@ -0,0 +1,2422 @@
+/* Basic syscall test, see memcheck/tests/x86-linux/scalar.c for more info. */
+
+#include "scalar.h"
+
+#include <bsm/audit.h>
+#include <nfs/nfs.h>
+#include <nfs/nfssys.h>
+#include <sys/acl.h>
+#include <sys/door.h>
+#include <sys/fcntl.h>
+#include <sys/lwp.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/port_impl.h>
+#include <sys/priocntl.h>
+#include <sys/priv.h>
+#include <sys/sem_impl.h>
+#include <sys/sendfile.h>
+#include <sys/shm_impl.h>
+#include <sys/termios.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+#include <sys/tsol/tndb.h>
+#include <sys/tsol/tsyscall.h>
+
+/* Helper functions.  These are necessary if we've got two tests for a single
+   syscall.  In that case, Memcheck can sometimes merge error messages.  Doing
+   each test in its own function prevents that. */
+__attribute__((noinline))
+static void sys_mount(void)
+{
+   GO(SYS_mount, "(4-arg, table variant) 4s 2m");
+   SY(SYS_mount, x0 + 1, x0, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_mount2(void)
+{
+   GO(SYS_mount, "(4-arg) 4s 3m");
+   SY(SYS_mount, x0 + 1, x0, x0, x0 + 256); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_mount3(void)
+{
+   GO(SYS_mount, "(6-arg) 6s 4m");
+   SY(SYS_mount, x0 + 1, x0, x0 | MS_DATA, x0 + 256, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_mount4(void)
+{
+   GO(SYS_mount, "(8-arg) 8s 5m");
+   SY(SYS_mount, x0 + 1, x0, x0 | MS_OPTIONSTR, x0 + 256, x0 + 1, x0 + 1,
+                 x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_pgrpsys(void)
+{
+   GO(SYS_pgrpsys, "(GETPGRP) 1s 0m");
+   SY(SYS_pgrpsys, x0); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_pgrpsys2(void)
+{
+   GO(SYS_pgrpsys, "(GETSID) 2s 0m");
+   SY(SYS_pgrpsys, x0 + 2, x0); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_pgrpsys3(void)
+{
+   GO(SYS_pgrpsys, "(GETPGID) 2s 0m");
+   SY(SYS_pgrpsys, x0 + 4, x0); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_shmsys(void)
+{
+   GO(SYS_shmsys, "(SHMAT) 4s 0m");
+   SY(SYS_shmsys, x0 + SHMAT, x0, x0 - 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys2(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,SHM_LOCK) 3s 0m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + SHM_LOCK); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys3(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,SHM_UNLOCK) 3s 0m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + SHM_UNLOCK); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys4(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_RMID) 3s 0m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_RMID); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys5(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_SET) 4s 3m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_SET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys6(void)
+{
+   struct shmid_ds buf;
+   buf.shm_perm.uid = x0 + 1;
+   buf.shm_perm.gid = x0 + 1;
+   buf.shm_perm.mode = x0 + 1;
+
+   GO(SYS_shmsys, "(SHMCTL,IPC_SET) 6s 0m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_SET, &buf); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys7(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_STAT) 4s 1m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_STAT, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys8(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_SET64) 4s 3m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_SET64, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys9(void)
+{
+   struct shmid_ds64 buf;
+   buf.shmx_perm.ipcx_uid = x0 + 1;
+   buf.shmx_perm.ipcx_gid = x0 + 1;
+   buf.shmx_perm.ipcx_mode = x0 + 1;
+
+   GO(SYS_shmsys, "(SHMCTL,IPC_SET64) 6s 0m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_SET64, &buf); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys10(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_STAT64) 4s 1m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_STAT64, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys11(void)
+{
+   GO(SYS_shmsys, "(SHMDT) 2s 0m");
+   SY(SYS_shmsys, x0 + SHMDT, x0 - 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys12(void)
+{
+   GO(SYS_shmsys, "(SHMGET) 4s 0m");
+   SY(SYS_shmsys, x0 + SHMGET, x0, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys13(void)
+{
+   GO(SYS_shmsys, "(SHMIDS) 4s 2m");
+   SY(SYS_shmsys, x0 + SHMIDS, x0 + 1, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys(void)
+{
+   GO(SYS_semsys, "(SEMCTL,IPC_STAT) 5s 1m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + IPC_STAT, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys2(void)
+{
+   GO(SYS_semsys, "(SEMCTL,IPC_SET) 5s 1m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + IPC_SET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys3(void)
+{
+   GO(SYS_semsys, "(SEMCTL,IPC_STAT64) 5s 1m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + IPC_STAT64, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys4(void)
+{
+   GO(SYS_semsys, "(SEMCTL,IPC_SET64) 5s 1m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + IPC_SET64, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys5(void)
+{
+   GO(SYS_semsys, "(SEMCTL,IPC_RMID) 3s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + IPC_RMID); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys6(void)
+{
+   GO(SYS_semsys, "(SEMCTL,GETALL) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + GETALL, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys7(void)
+{
+   GO(SYS_semsys, "(SEMCTL,SETALL) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + SETALL, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys8(void)
+{
+   GO(SYS_semsys, "(SEMCTL,GETVAL) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + GETVAL); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys9(void)
+{
+   GO(SYS_semsys, "(SEMCTL,SETVAL) 5s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + SETVAL, x0 + 2); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys10(void)
+{
+   GO(SYS_semsys, "(SEMCTL,GETPID) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + GETPID); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys11(void)
+{
+   GO(SYS_semsys, "(SEMCTL,GETNCNT) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + GETNCNT); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys12(void)
+{
+   GO(SYS_semsys, "(SEMCTL,GETZCNT) 4s 0m");
+   SY(SYS_semsys, x0 + SEMCTL, x0, x0, x0 + GETZCNT); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys13(void)
+{
+   GO(SYS_semsys, "(SEMGET) 4s 0m");
+   SY(SYS_semsys, x0 + SEMGET, x0, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys14(void)
+{
+   GO(SYS_semsys, "(SEMOP) 4s 1m");
+   SY(SYS_semsys, x0 + SEMOP, x0, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys15(void)
+{
+   GO(SYS_semsys, "(SEMIDS) 4s 2m");
+   SY(SYS_semsys, x0 + SEMIDS, x0 + 1, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_semsys16(void)
+{
+   GO(SYS_semsys, "(SEMTIMEDOP) 5s 2m");
+   SY(SYS_semsys, x0 + SEMTIMEDOP, x0, x0 + 1, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_fcntl(void)
+{
+   GO(SYS_fcntl, "(GETFD) 2s 0m");
+   SY(SYS_fcntl, x0 - 1, x0 + F_GETFD); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_fcntl2(void)
+{
+   GO(SYS_fcntl, "(DUPFD) 3s 0m");
+   SY(SYS_fcntl, x0 - 1, x0 + F_DUPFD, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_fcntl3(void)
+{
+   GO(SYS_fcntl, "(GETLK) 3s 5m");
+   SY(SYS_fcntl, x0 - 1, x0 + F_GETLK, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_openat(void)
+{
+   GO(SYS_openat, "(3-args) 3s 1m");
+   SY(SYS_openat, x0 - 1, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_openat2(void)
+{
+   GO(SYS_openat, "(4-args) 4s 1m");
+   SY(SYS_openat, x0 - 1, x0, x0 | O_CREAT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_tasksys(void)
+{
+   GO(SYS_tasksys, "(settaskid) 3s 0m");
+   SY(SYS_tasksys, x0 + 0, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_tasksys2(void)
+{
+   GO(SYS_tasksys, "(gettaskid) 1s 0m");
+   SY(SYS_tasksys, x0 + 1); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_tasksys3(void)
+{
+   GO(SYS_tasksys, "(getprojid) 1s 0m");
+   SY(SYS_tasksys, x0 + 2); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_tasksys4(void)
+{
+   GO(SYS_tasksys, "(projlist) 3s 1m");
+   /* ARG2 and ARG3 are ignored */
+   SY(SYS_tasksys, x0 + 3, x0, x0, x0 + 1, x0 + 2); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_sendfilev(void)
+{
+   GO(SYS_sendfilev, "(SENDFILEV) 5s 2m");
+   SY(SYS_sendfilev, x0 + SENDFILEV, x0 - 1, x0 + 1, x0 + 2, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_sendfilev2(void)
+{
+   struct sendfilevec vec[2];
+   vec[0].sfv_fd = SFV_FD_SELF;
+   vec[0].sfv_off = (off_t)(x0 + 1);
+   vec[0].sfv_len = x0 + 1;
+   vec[0].sfv_flag = 0; // should be set to zero according to man page
+   vec[1].sfv_fd = x0 - 1;
+   vec[1].sfv_off = x0;
+   vec[1].sfv_len = x0 + 1;
+   vec[1].sfv_flag = 0; // should be set to zero according to man page
+
+   GO(SYS_sendfilev, "(SENDFILEV) 4s 2m");
+   SY(SYS_sendfilev, x0 + SENDFILEV, x0 - 1, vec, 2, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_sendfilev3(void)
+{
+   GO(SYS_sendfilev, "(SENDFILEV64) 5s 2m");
+   SY(SYS_sendfilev, x0 + SENDFILEV64, x0 - 1, x0 + 1, x0 + 2, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_sendfilev4(void)
+{
+   struct sendfilevec64 vec[2];
+   vec[0].sfv_fd = SFV_FD_SELF;
+   vec[0].sfv_off = (off_t)(x0 + 1);
+   vec[0].sfv_len = x0 + 1;
+   vec[0].sfv_flag = 0; // should be set to zero according to man page
+   vec[1].sfv_fd = x0 - 1;
+   vec[1].sfv_off = x0;
+   vec[1].sfv_len = x0 + 1;
+   vec[1].sfv_flag = 0; // should be set to zero according to man page
+
+   GO(SYS_sendfilev, "(SENDFILEV64) 4s 2m");
+   SY(SYS_sendfilev, x0 + SENDFILEV64, x0 - 1, vec, 2, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_SETPPRIV) 5s 1m");
+   SY(SYS_privsys, x0 + PRIVSYS_SETPPRIV, x0, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys2(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_GETPPRIV) 5s 1m");
+   SY(SYS_privsys, x0 + PRIVSYS_GETPPRIV, x0, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys3(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_GETIMPLINFO) 5s 1m");
+   SY(SYS_privsys, x0 + PRIVSYS_GETIMPLINFO, x0, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys4(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_SETPFLAGS) 3s 0m");
+   SY(SYS_privsys, x0 + PRIVSYS_SETPFLAGS, x0, x0 + 2); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys5(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_GETPFLAGS) 2s 0m");
+   SY(SYS_privsys, x0 + PRIVSYS_GETPFLAGS, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_privsys6(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_ISSETUGID) 1s 0m");
+   SY(SYS_privsys, x0 + PRIVSYS_ISSETUGID); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_privsys7(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_PFEXEC_REG) 2s 0m");
+   SY(SYS_privsys, x0 + PRIVSYS_PFEXEC_REG, x0 - 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_privsys8(void)
+{
+   GO(SYS_privsys, "(PRIVSYS_PFEXEC_UNREG) 2s 0m");
+   SY(SYS_privsys, x0 + PRIVSYS_PFEXEC_UNREG, x0 - 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_ucredsys(void)
+{
+   GO(SYS_ucredsys, "(UCREDSYS_UCREDGET) 3s 1m");
+   SY(SYS_ucredsys, x0 + 0, x0, x0 + 1 ); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ucredsys2(void)
+{
+   GO(SYS_ucredsys, "(UCREDSYS_GETPEERUCRED) 3s 1m");
+   SY(SYS_ucredsys, x0 + 1, x0 - 1, x0 + 1 ); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_context(void)
+{
+   GO(SYS_context, "(GETCONTEXT) 2s 1m");
+   SY(SYS_context, x0 + GETCONTEXT, x0); FAILx(EFAULT);
+}
+
+__attribute__((noinline))
+static void sys_context2(void)
+{
+   /* The setcontext() wrapper has to call ML_(safe_to_deref) before doing the
+      PRE_READ_*() stuff, therefore the 0m parameter. */
+   GO(SYS_context, "(SETCONTEXT) 2s 0m");
+   SY(SYS_context, x0 + SETCONTEXT, x0 + 1); FAILx(EFAULT);
+}
+
+__attribute__((noinline))
+static void sys_context3(void)
+{
+   GO(SYS_context, "(GETUSTACK) 2s 1m");
+   SY(SYS_context, x0 + GETUSTACK, x0); FAILx(EFAULT);
+}
+
+__attribute__((noinline))
+static void sys_context4(void)
+{
+   GO(SYS_context, "(SETUSTACK) 2s 1m");
+   SY(SYS_context, x0 + SETUSTACK, x0); FAILx(EFAULT);
+}
+
+__attribute__((noinline))
+static void sys_statvfs(void)
+{
+   GO(SYS_statvfs, "2s 2m");
+   SY(SYS_statvfs, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static int sys_statvfs2(void)
+{
+   const char path[] = "/";
+   struct statvfs stats;
+
+   GO(SYS_statvfs, "4s 0m");
+   SY(SYS_statvfs, x0 + path, x0 + &stats); SUCC;
+
+   size_t basetype_len = strlen(stats.f_basetype);
+   size_t fstr_len = strlen(stats.f_fstr);
+
+   /* Now check that memory after the strings is reported uninitialized. */
+   int x = 0;
+   if (stats.f_basetype[basetype_len + 2] != ' ') x = -1; else x = -2;
+   if (stats.f_fstr[fstr_len + 2] != ' ') x = -3; else x = -4;
+   return x;
+}
+
+__attribute__((noinline))
+static void sys_nfssys(void)
+{
+   GO(SYS_nfssys, "(NFS_REVAUTH) 2s 1m");
+   SY(SYS_nfssys, x0 + NFS_REVAUTH, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys(void)
+{
+   pcinfo_t pcinfo;
+   pcinfo.pc_clname[0] = x0 + 'T';
+   pcinfo.pc_clname[1] = x0 + 'S';
+   pcinfo.pc_clname[2] = x0;
+
+   GO(SYS_priocntlsys, "(GETCID) 6s 0m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETCID, x0 + &pcinfo, x0); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys2(void)
+{
+   pcinfo_t pcinfo;
+   pcinfo.pc_cid = x0 + 1;
+
+   GO(SYS_priocntlsys, "(GETCLINFO) 6s 0m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETCLINFO, x0 + &pcinfo, x0); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys3(void)
+{
+   GO(SYS_priocntlsys, "(SETPARMS) 5s 2m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_SETPARMS, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys4(void)
+{
+   GO(SYS_priocntlsys, "(GETPARMS) 5s 2m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETPARMS, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys5(void)
+{
+   GO(SYS_priocntlsys, "(GETPRIRANGE) 5s 2m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETPRIRANGE, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys6(void)
+{
+   GO(SYS_priocntlsys, "(DONICE) 5s 2m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_DONICE, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys7(void)
+{
+   GO(SYS_priocntlsys, "(SETXPARMS) 5s 3m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_SETXPARMS, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys8(void)
+{
+   GO(SYS_priocntlsys, "(GETXPARMS) 5s 3m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETXPARMS, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys9(void)
+{
+   GO(SYS_priocntlsys, "(SETDFLCL) 5s 1m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_SETDFLCL, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys10(void)
+{
+   GO(SYS_priocntlsys, "(GETDFLCL) 5s 1m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_GETDFLCL, x0 + 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_priocntlsys11(void)
+{
+   GO(SYS_priocntlsys, "(DOPRIO) 5s 2m");
+   SY(SYS_priocntlsys, x0 + 1, x0, x0 + PC_DOPRIO, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_uname(void)
+{
+   GO(SYS_uname, "1s 1m");
+   SY(SYS_uname, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static int sys_uname2(void)
+{
+   struct utsname name;
+
+   GO(SYS_uname, "6s 0m");
+   SY(SYS_uname, x0 + &name); SUCC;
+
+   size_t sysname_len = strlen(name.sysname);
+   size_t nodename_len = strlen(name.nodename);
+   size_t release_len = strlen(name.release);
+   size_t version_len = strlen(name.version);
+   size_t machine_len = strlen(name.machine);
+
+   /* Now check that memory after the strings is reported uninitialized. */
+   int x = 0;
+   if (name.sysname[sysname_len + 2] != ' ') x = -1; else x = -2;
+   if (name.nodename[nodename_len + 2] != ' ') x = -3; else x = -4;
+   if (name.release[release_len + 2] != ' ') x = -5; else x = -6;
+   if (name.version[version_len + 2] != ' ') x = -7; else x = -8;
+   if (name.machine[machine_len + 2] != ' ') x = -9; else x = -10;
+   return x;
+}
+
+__attribute__((noinline))
+static void sys_rusagesys(void)
+{
+   GO(SYS_rusagesys, "(_RUSAGESYS_GETRUSAGE) 2s 1m");
+   SY(SYS_rusagesys, x0 + _RUSAGESYS_GETRUSAGE, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_rusagesys2(void)
+{
+   GO(SYS_rusagesys, "(_RUSAGESYS_GETRUSAGE_CHLD) 2s 1m");
+   SY(SYS_rusagesys, x0 + _RUSAGESYS_GETRUSAGE_CHLD, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_rusagesys3(void)
+{
+   GO(SYS_rusagesys, "(_RUSAGESYS_GETRUSAGE_LWP) 2s 1m");
+   SY(SYS_rusagesys, x0 + _RUSAGESYS_GETRUSAGE_LWP, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_rusagesys4(void)
+{
+   GO(SYS_rusagesys, "(_RUSAGESYS_GETVMUSAGE) 5s 1m");
+   SY(SYS_rusagesys, x0 + _RUSAGESYS_GETVMUSAGE, x0, x0, x0 + 1, x0 + 1);
+   FAIL;
+}
+
+__attribute__((noinline))
+static void sys_rusagesys5(void)
+{
+   size_t nres = 10;
+
+   GO(SYS_rusagesys, "(_RUSAGESYS_GETVMUSAGE) 5s 1m");
+   SY(SYS_rusagesys, x0 + _RUSAGESYS_GETVMUSAGE, x0, x0, x0 + 1, x0 + &nres);
+   FAIL;
+}
+
+__attribute__((noinline))
+static void sys_port(void)
+{
+   GO(SYS_port, "(PORT_CREATE) 1s 0m");
+   SY(SYS_port, (x0 + PORT_CREATE) | PORT_SYS_NOPORT); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_port2(void)
+{
+   GO(SYS_port, "(PORT_ASSOCIATE,PORT_SOURCE_FD) 6s 0m");
+   SY(SYS_port, x0 + PORT_ASSOCIATE, x0 - 1, x0 + PORT_SOURCE_FD, x0, x0,
+                x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port3(void)
+{
+   GO(SYS_port, "(PORT_ASSOCIATE,PORT_SOURCE_FILE) 6s 1m");
+   SY(SYS_port, x0 + PORT_ASSOCIATE, x0 - 1, x0 + PORT_SOURCE_FILE, x0, x0,
+                x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port4(void)
+{
+   GO(SYS_port, "(PORT_DISSOCIATE,PORT_SOURCE_FD) 6s 0m");
+   SY(SYS_port, x0 + PORT_DISSOCIATE, x0 - 1, x0 + PORT_SOURCE_FD, x0, x0,
+                x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port5(void)
+{
+   GO(SYS_port, "(PORT_DISSOCIATE,PORT_SOURCE_FILE) 6s 1m");
+   SY(SYS_port, x0 + PORT_DISSOCIATE, x0 - 1, x0 + PORT_SOURCE_FILE, x0, x0,
+                x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port6(void)
+{
+   GO(SYS_port, "(PORT_SEND) 4s 0m");
+   SY(SYS_port, x0 + PORT_SEND, x0 - 1, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port7(void)
+{
+   GO(SYS_port, "(PORT_SENDN) 6s 2m");
+   SY(SYS_port, (x0 + PORT_SENDN) | PORT_SYS_NOPORT, x0, x0, x0 + 1, x0,
+                x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_port8(void)
+{
+   GO(SYS_port, "(PORT_GET) 6s 1m");
+   SY(SYS_port, x0 + PORT_GET, x0 - 1, x0, x0, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port9(void)
+{
+   GO(SYS_port, "(PORT_GETN) 5s 2m");
+   SY(SYS_port, x0 + PORT_GETN, x0 - 1, x0, x0 + 1, x0, x0 + 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port10(void)
+{
+   GO(SYS_port, "(PORT_ALERT) 5s 0m");
+   SY(SYS_port, x0 + PORT_ALERT, x0 - 1, x0, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_port11(void)
+{
+   GO(SYS_port, "(PORT_DISPATCH) 6s 0m");
+   SY(SYS_port, x0 + PORT_DISPATCH, x0 - 1, x0, x0, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_labelsys(void)
+{
+   GO(SYS_labelsys, "(TSOL_SYSLABELING) 1s 0m");
+   SY(SYS_labelsys, x0 + TSOL_SYSLABELING); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_labelsys2(void)
+{
+   GO(SYS_labelsys, "(TSOL_TNRH) 3s 1m");
+   SY(SYS_labelsys, x0 + TSOL_TNRH, x0 + TNDB_GET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys3(void)
+{
+   GO(SYS_labelsys, "(TSOL_TNRHTP) 3s 1m");
+   SY(SYS_labelsys, x0 + TSOL_TNRHTP, x0 + TNDB_GET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys4(void)
+{
+   GO(SYS_labelsys, "(TSOL_TNMLP) 3s 1m");
+   SY(SYS_labelsys, x0 + TSOL_TNMLP, x0 + TNDB_GET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys5(void)
+{
+   GO(SYS_labelsys, "(TSOL_GETLABEL) 3s 2m");
+   SY(SYS_labelsys, x0 + TSOL_GETLABEL, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys6(void)
+{
+   GO(SYS_labelsys, "(TSOL_FGETLABEL) 3s 1m");
+   SY(SYS_labelsys, x0 + TSOL_FGETLABEL, x0 - 1, x0 + 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_acl(void)
+{
+   GO(SYS_acl, "(SETACL) 4s 2m");
+   SY(SYS_acl, x0, x0 + SETACL, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_acl2(void)
+{
+   GO(SYS_acl, "(GETACL) 4s 2m");
+   SY(SYS_acl, x0, x0 + GETACL, x0 + 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_acl3(void)
+{
+   GO(SYS_acl, "(GETACLCNT) 4s 1m");
+   SY(SYS_acl, x0, x0 + GETACLCNT, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_acl4(void)
+{
+   GO(SYS_acl, "(ACE_SETACL) 4s 2m");
+   SY(SYS_acl, x0, x0 + ACE_SETACL, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_acl5(void)
+{
+   GO(SYS_acl, "(ACE_GETACL) 4s 2m");
+   SY(SYS_acl, x0, x0 + ACE_GETACL, x0 + 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_acl6(void)
+{
+   GO(SYS_acl, "(ACE_GETACLCNT) 4s 1m");
+   SY(SYS_acl, x0, x0 + ACE_GETACLCNT, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys(void)
+{
+   GO(SYS_auditsys, "(BSM_GETAUID) 2s 1m");
+   SY(SYS_auditsys, x0 + BSM_GETAUID, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys2(void)
+{
+   GO(SYS_auditsys, "(BSM_SETAUID) 2s 1m");
+   SY(SYS_auditsys, x0 + BSM_SETAUID, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys3(void)
+{
+   GO(SYS_auditsys, "(BSM_GETAUDIT) 2s 1m");
+   SY(SYS_auditsys, x0 + BSM_GETAUDIT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys4(void)
+{
+   GO(SYS_auditsys, "(BSM_SETAUDIT) 2s 1m");
+   SY(SYS_auditsys, x0 + BSM_SETAUDIT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys5(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDIT) 3s 1m");
+   /* The following syscall can succeed if auditing is not enabled. */
+   SY(SYS_auditsys, x0 + BSM_AUDIT, x0, x0 + 1); /*FAIL;*/
+}
+
+__attribute__((noinline))
+static void sys_auditsys6(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETPOLICY) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETPOLICY, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys7(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETPOLICY) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETPOLICY, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys8(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETKMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETKMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys9(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETKMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETKMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys10(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETQCTRL) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETQCTRL, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys11(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETQCTRL) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETQCTRL, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys12(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETCWD) 4s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETCWD, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys13(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETCAR) 4s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETCAR, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys14(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETSTAT) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETSTAT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys15(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETSTAT) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETSTAT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys16(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETUMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETUMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys17(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETSMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETSMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys18(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETCOND) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETCOND, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys19(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETCOND) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETCOND, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys20(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETCLASS) 3s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETCLASS, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys21(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETCLASS) 3s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETCLASS, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys22(void)
+{
+   au_evclass_map_t classmap;
+   classmap.ec_number = x0;
+   classmap.ec_class = x0;
+
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETCLASS) 4s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETCLASS, &classmap); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys23(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETPINFO) 3s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETPINFO, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys24(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETPMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETPMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys25(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETPINFO_ADDR) 4s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETPINFO_ADDR, x0,
+                    x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys26(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETKAUDIT) 4s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETKAUDIT, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys27(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETKAUDIT) 4s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETKAUDIT, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys28(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_GETAMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_GETAMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys29(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITCTL,A_SETAMASK) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_AUDITCTL, x0 + A_SETAMASK, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys30(void)
+{
+   GO(SYS_auditsys, "(BSM_GETAUDIT_ADDR) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_GETAUDIT_ADDR, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys31(void)
+{
+   GO(SYS_auditsys, "(BSM_SETAUDIT_ADDR) 3s 1m");
+   SY(SYS_auditsys, x0 + BSM_SETAUDIT_ADDR, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_auditsys32(void)
+{
+   GO(SYS_auditsys, "(BSM_AUDITDOOR) 2s 0m");
+   SY(SYS_auditsys, x0 + BSM_AUDITDOOR, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_timer_create(void)
+{
+   GO(SYS_timer_create, "3s 4m");
+   SY(SYS_timer_create, x0, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_timer_create2(void)
+{
+   struct sigevent evp;
+   evp.sigev_notify = x0 + SIGEV_THREAD;
+   evp.sigev_value.sival_ptr = (void *)(x0 + 1);
+
+   GO(SYS_timer_create, "5s 2m");
+   SY(SYS_timer_create, x0, &evp, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_facl(void)
+{
+   GO(SYS_facl, "(SETACL) 4s 1m");
+   SY(SYS_facl, x0 - 1, x0 + SETACL, x0 + 1, x0 + 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_facl2(void)
+{
+   GO(SYS_facl, "(GETACL) 4s 1m");
+   SY(SYS_facl, x0 - 1, x0 + GETACL, x0 + 1, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_facl3(void)
+{
+   GO(SYS_facl, "(GETACLCNT) 4s 0m");
+   SY(SYS_facl, x0 - 1, x0 + GETACLCNT, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_facl4(void)
+{
+   GO(SYS_facl, "(ACE_SETACL) 4s 1m");
+   SY(SYS_facl, x0 - 1, x0 + ACE_SETACL, x0 + 1, x0 + 1); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_facl5(void)
+{
+   GO(SYS_facl, "(ACE_GETACL) 4s 1m");
+   SY(SYS_facl, x0 - 1, x0 + ACE_GETACL, x0 + 1, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_facl6(void)
+{
+   GO(SYS_facl, "(ACE_GETACLCNT) 4s 0m");
+   SY(SYS_facl, x0 - 1, x0 + ACE_GETACLCNT, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_door(void)
+{
+   GO(SYS_door, "(DOOR_CREATE) 4s 0m");
+   SY(SYS_door, x0, x0, x0, x0, x0, x0 + DOOR_CREATE); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_door2(void)
+{
+   GO(SYS_door, "(DOOR_REVOKE) 2s 0m");
+   SY(SYS_door, x0, x0, x0, x0, x0, x0 + DOOR_REVOKE); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_door3(void)
+{
+   GO(SYS_door, "(DOOR_INFO) 3s 1m");
+   SY(SYS_door, x0, x0 - 1, x0, x0, x0, x0 + DOOR_INFO); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_door4(void)
+{
+   GO(SYS_door, "(DOOR_CALL) 3s 6m");
+   SY(SYS_door, x0 - 1, x0, x0, x0, x0, x0 + DOOR_CALL); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_door5(void)
+{
+   door_arg_t params;
+   params.data_ptr = (void *)(x0 + 1);
+   params.data_size = x0 + 1;
+   params.desc_ptr = (void *)(x0 + 1);
+   params.desc_num = x0 + 1;
+   params.rbuf = (void *)(x0 + 1);
+   params.rsize = x0 + 1;
+
+   GO(SYS_door, "(DOOR_CALL) 9s 2m");
+   SY(SYS_door, x0, x0 + &params, x0, x0, x0, x0 + DOOR_CALL); FAIL;
+}
+
+
+__attribute__((noinline))
+static void sys_lwp_rwlock(void)
+{
+   GO(SYS_lwp_rwlock_sys, "(RDLOCK) 3s 8m");
+   SY(SYS_lwp_rwlock_sys, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_lwp_rwlock2(void)
+{
+   GO(SYS_lwp_rwlock_sys, "(WRLOCK) 3s 8m");
+   SY(SYS_lwp_rwlock_sys, x0 + 1, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_lwp_rwlock3(void)
+{
+   GO(SYS_lwp_rwlock_sys, "(TRYRDLOCK) 2s 7m");
+   SY(SYS_lwp_rwlock_sys, x0 + 2, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_lwp_rwlock4(void)
+{
+   GO(SYS_lwp_rwlock_sys, "(TRYWRLOCK) 2s 7m");
+   SY(SYS_lwp_rwlock_sys, x0 + 3, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_lwp_rwlock5(void)
+{
+   GO(SYS_lwp_rwlock_sys, "(UNLOCK) 2s 2m");
+   SY(SYS_lwp_rwlock_sys, x0 + 4, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone(void)
+{
+   GO(SYS_zone, "(ZONE_CREATE) 2s 12m");
+   SY(SYS_zone, x0 + ZONE_CREATE, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone2(void)
+{
+   zone_def zd;
+   zd.zone_name = (void *)(x0 + 1);
+   zd.zone_root = (void *)(x0 + 1);
+   zd.zone_privs = (void *)x0;
+   zd.zone_privssz = x0 + 1;
+   zd.rctlbuf = (void *)x0;
+   zd.rctlbufsz = x0 + 1;
+   zd.extended_error = (void *)x0;
+   zd.zfsbuf = (void *)x0;
+   zd.zfsbufsz = x0 + 1;
+   zd.match = x0;
+   zd.doi = x0;
+   zd.label = (void *)(x0 + 1);
+   zd.flags = x0;
+
+   GO(SYS_zone, "(create) 2s 19m");
+   SY(SYS_zone, x0 + ZONE_CREATE, x0 + &zd); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone3(void)
+{
+   GO(SYS_zone, "(ZONE_DESTROY) 2s 0m");
+   SY(SYS_zone, x0 + ZONE_DESTROY, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone4(void)
+{
+   GO(SYS_zone, "(ZONE_GETATTR) 5s 1m");
+   SY(SYS_zone, x0 + ZONE_GETATTR, x0, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone5(void)
+{
+   GO(SYS_zone, "(ZONE_ENTER) 2s 0m");
+   SY(SYS_zone, x0 + ZONE_ENTER, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone6(void)
+{
+   GO(SYS_zone, "(ZONE_LIST) 3s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone7(void)
+{
+   uint_t numzones = x0 + 1;
+
+   GO(SYS_zone, "(ZONE_LIST) 3s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST, x0 + 1, x0 + &numzones); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone8(void)
+{
+   GO(SYS_zone, "(ZONE_SHUTDOWN) 2s 0m");
+   SY(SYS_zone, x0 + ZONE_SHUTDOWN, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone9(void)
+{
+   GO(SYS_zone, "(ZONE_LOOKUP) 2s 1m");
+   SY(SYS_zone, x0 + ZONE_LOOKUP, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone10(void)
+{
+   GO(SYS_zone, "(ZONE_BOOT) 2s 0m");
+   SY(SYS_zone, x0 + ZONE_BOOT, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone11(void)
+{
+   GO(SYS_zone, "(ZONE_SETATTR) 5s 1m");
+   SY(SYS_zone, x0 + ZONE_SETATTR, x0, x0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone12(void)
+{
+   GO(SYS_zone, "(ZONE_ADD_DATALINK) 3s 0m");
+   SY(SYS_zone, x0 + ZONE_ADD_DATALINK, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone13(void)
+{
+   GO(SYS_zone, "(ZONE_DEL_DATALINK) 3s 0m");
+   SY(SYS_zone, x0 + ZONE_DEL_DATALINK, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone14(void)
+{
+   GO(SYS_zone, "(ZONE_CHECK_DATALINK) 3s 1m");
+   SY(SYS_zone, x0 + ZONE_CHECK_DATALINK, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone15(void)
+{
+   GO(SYS_zone, "(ZONE_LIST_DATALINK) 4s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST_DATALINK, x0, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone16(void)
+{
+   int dlnum = x0 + 1;
+
+   GO(SYS_zone, "(ZONE_LIST_DATALINK) 4s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST_DATALINK, x0, x0 + &dlnum, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_getpeername(void)
+{
+   GO(SYS_getpeername, "4s 1m");
+   SY(SYS_getpeername, x0 - 1, x0 + 1, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_getpeername2(void)
+{
+   socklen_t size = x0 + 10;
+
+   GO(SYS_getpeername, "4s 1m");
+   SY(SYS_getpeername, x0 - 1, x0 + 1, &size, x0); FAILx(EBADF);
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_syscall                 0 */
+   /* SPARC only. */
+
+   /* SYS_exit                    1 */
+   /* Tested below. */
+
+   /* SYS_read                    3 */
+   GO(SYS_read, "3s 0m");
+   SY(SYS_read, x0 - 1, x0, x0 + 1); FAILx(EBADF);
+   /* Note that above should be preferably "3s 1m" test.. */
+
+   /* SYS_write                   4 */
+   GO(SYS_write, "3s 1m");
+   SY(SYS_write, x0 + 1, x0, x0 + 1); FAIL;
+
+   /* SYS_open                    5 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_close                   6 */
+   GO(SYS_close, "1s 0m");
+   SY(SYS_close, x0 - 1); FAILx(EBADF);
+
+   /* SYS_linkat                  7 */
+   GO(SYS_linkat, "5s 2m");
+   SY(SYS_linkat, x0 - 1, x0 + 1, x0 - 1, x0 + 1, x0); FAIL;
+
+   /* SYS_link                    9 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_unlink                 10 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_symlinkat              11 */
+   GO(SYS_symlinkat, "3s 2m");
+   SY(SYS_symlinkat, x0 + 1, x0 - 1, x0 + 1); FAIL;
+
+   /* SYS_chdir                  12 */
+   GO(SYS_chdir, "1s 1m");
+   SY(SYS_chdir, x0); FAIL;
+
+   /* SYS_time                   13 */
+   GO(SYS_time, "0s 0m");
+   SY(SYS_time); SUCC;
+
+   /* SYS_mknod                  14 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_chmod                  15 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_chown                  16 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_brk                    17 */
+   GO(SYS_brk, "1s 0m");
+   SY(SYS_brk, x0); SUCC;
+
+   /* SYS_stat                   18 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_lseek                  19 */
+   GO(SYS_lseek, "3s 0m");
+   SY(SYS_lseek, x0 - 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_getpid                 20 */
+   GO(SYS_getpid, "0s 0m");
+   SY(SYS_getpid); SUCC;
+
+   /* SYS_mount                  21 */
+   sys_mount();
+   sys_mount2();
+   sys_mount3();
+   sys_mount4();
+
+   /* SYS_readlinkat             22 */
+   GO(SYS_readlinkat, "4s 2m");
+   SY(SYS_readlinkat, x0 - 1, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_setuid                 23 */
+   GO(SYS_setuid, "1s 0m");
+   SY(SYS_setuid, x0 - 1); FAIL;
+
+   /* SYS_getuid                 24 */
+   GO(SYS_getuid, "0s 0m");
+   SY(SYS_getuid); SUCC;
+
+   /* SYS_stime                  25 */
+   GO(SYS_stime, "1s 0m");
+   SY(SYS_stime, x0); FAIL;
+
+   /* SYS_pcsample               26 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_alarm                  27 */
+   GO(SYS_alarm, "1s 0m");
+   SY(SYS_alarm, x0); SUCC;
+
+   /* SYS_fstat                  28 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_pause                  29 */
+   /* Don't bother to test this. */
+   GO(SYS_pause, "ignore");
+
+   /* SYS_stty                   31 */
+   GO(SYS_stty, "2s 1m");
+   SY(SYS_stty, x0 - 1, x0 + 1); FAIL;
+
+   /* SYS_gtty                   32 */
+   GO(SYS_gtty, "2s 1m");
+   SY(SYS_gtty, x0 - 1, x0 + 1); FAIL;
+
+   /* SYS_access                 33 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_nice                   34 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_statfs                 35 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_sync                   36 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_kill                   37 */
+   GO(SYS_kill, "2s 0m");
+   SY(SYS_kill, x0, x0); SUCC;
+
+   /* SYS_fstatfs                38 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_pgrpsys                39 */
+   sys_pgrpsys();
+   sys_pgrpsys2();
+   sys_pgrpsys3();
+
+   /* SYS_uucopystr              40 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_pipe                   42 */
+   /* Don't bother to test this. */
+   GO(SYS_pipe, "ignore");
+
+   /* SYS_times                  43 */
+   GO(SYS_times, "1s 1m");
+   SY(SYS_times, x0 + 1); FAIL;
+
+   /* SYS_profil                 44 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_faccessat              45 */
+   GO(SYS_faccessat, "4s 1m");
+   SY(SYS_faccessat, x0 - 1, x0 + 1, x0, x0); FAIL;
+
+   /* SYS_setgid                 46 */
+   GO(SYS_setgid, "1s 0m");
+   SY(SYS_setgid, x0 - 1); FAIL;
+
+   /* SYS_getgid                 47 */
+   GO(SYS_getgid, "0s 0m");
+   SY(SYS_getgid); SUCC;
+
+   /* SYS_mknodat                48 */
+   GO(SYS_mknodat, "4s 1m");
+   SY(SYS_mknodat, x0 - 1, x0 + 1, x0, x0); FAIL;
+
+   /* SYS_msgsys                 49 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_sysi86                 50 */
+   /* TODO Add test. */
+   GO(SYS_sysi86, "incoming");
+
+   /* SYS_acct                   51 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_shmsys                 52 */
+   sys_shmsys();
+   sys_shmsys2();
+   sys_shmsys3();
+   sys_shmsys4();
+   sys_shmsys5();
+   sys_shmsys6();
+   sys_shmsys7();
+   sys_shmsys8();
+   sys_shmsys9();
+   sys_shmsys10();
+   sys_shmsys11();
+   sys_shmsys12();
+   sys_shmsys13();
+
+   /* SYS_semsys                 53 */
+   sys_semsys();
+   sys_semsys2();
+   sys_semsys3();
+   sys_semsys4();
+   sys_semsys5();
+   sys_semsys6();
+   sys_semsys7();
+   sys_semsys8();
+   sys_semsys9();
+   sys_semsys10();
+   sys_semsys11();
+   sys_semsys12();
+   sys_semsys13();
+   sys_semsys14();
+   sys_semsys15();
+   sys_semsys16();
+
+   /* SYS_ioctl                  54 */
+   GO(SYS_ioctl, "3s 1m");
+   SY(SYS_ioctl, x0, x0 + TCGETS, x0); FAIL;
+
+   /* SYS_uadmin                 55 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_fchownat               56 */
+   GO(SYS_fchownat, "5s 1m");
+   SY(SYS_fchownat, x0 - 1, x0 + 1, x0, x0, x0); FAIL;
+
+   /* SYS_utssys                 57 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_fdsync                 58 */
+   GO(SYS_fdsync, "2s 0m");
+   SY(SYS_fdsync, x0 - 1, x0); FAILx(EBADF);
+
+   /* SYS_execve                 59 */
+   /* illumos ignores the fourth argument. */
+   GO(SYS_execve, "3s 1m");
+   SY(SYS_execve, x0, x0, x0, 0); FAIL;
+   /* More cases tested in execx.c */
+
+   /* SYS_umask                  60 */
+   GO(SYS_umask, "1s 0m");
+   SY(SYS_umask, x0 + 022); SUCC;
+
+   /* SYS_chroot                 61 */
+   GO(SYS_chroot, "1s 1m");
+   SY(SYS_chroot, x0 + 1); FAIL;
+
+   /* SYS_fcntl                  62 */
+   sys_fcntl();
+   sys_fcntl2();
+   sys_fcntl3();
+
+   /* SYS_ulimit                 63 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_renameat               64 */
+   GO(SYS_renameat, "4s 2m");
+   SY(SYS_renameat, x0 - 1, x0, x0, x0); FAIL;
+
+   /* SYS_unlinkat               65 */
+   GO(SYS_unlinkat, "3s 1m");
+   SY(SYS_unlinkat, x0 - 1, x0, x0); FAIL;
+
+   /* SYS_fstatat                66 */
+   GO(SYS_fstatat, "4s 2m");
+   SY(SYS_fstatat, x0 - 1, x0 + 1, x0, x0); FAIL;
+
+   /* SYS_fstatat64              67 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_openat                 68 */
+   sys_openat();
+   sys_openat2();
+
+   /* SYS_openat64               69 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_tasksys                70 */
+   sys_tasksys();
+   sys_tasksys2();
+   sys_tasksys3();
+   sys_tasksys4();
+
+   /* SYS_acctctl                71 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_exacctsys              72 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_getpagesizes           73 */
+   GO(SYS_getpagesizes, "3s 1m");
+   SY(SYS_getpagesizes, x0, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_rctlsys                74 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_sidsys                 75 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_park               77 */
+   /* Don't bother to test this. */
+   GO(SYS_lwp_park, "ignore");
+
+   /* SYS_sendfilev              78 */
+   sys_sendfilev();
+   sys_sendfilev2();
+   sys_sendfilev3();
+   sys_sendfilev4();
+
+   /* SYS_rmdir                  79 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_mkdir                  80 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_getdents               81 */
+   GO(SYS_getdents, "3s 1m");
+   SY(SYS_getdents, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_Privsys                82 */
+   sys_privsys();
+   sys_privsys2();
+   sys_privsys3();
+   sys_privsys4();
+   sys_privsys5();
+   sys_privsys6();
+   sys_privsys7();
+   sys_privsys8();
+
+   /* SYS_ucredsys               83 */
+   sys_ucredsys();
+   sys_ucredsys2();
+
+   /* SYS_sysfs                  84 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_getmsg                 85 */
+   GO(SYS_getmsg, "4s 1m");
+   SY(SYS_getmsg, x0, x0, x0, x0); FAIL;
+
+   /* SYS_putmsg                 86 */
+   GO(SYS_putmsg, "4s 0m");
+   SY(SYS_putmsg, x0, x0, x0, x0);
+
+   /* SYS_lstat                  88 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_symlink                89 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_readlink               90 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_setgroups              91 */
+   GO(SYS_setgroups, "2s 1m");
+   SY(SYS_setgroups, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_getgroups              92 */
+   GO(SYS_getgroups, "2s 1m");
+   SY(SYS_getgroups, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_fchmod                 93 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_fchown                 94 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_sigprocmask            95 */
+   GO(SYS_sigprocmask, "3s 2m");
+   SY(SYS_sigprocmask, x0, x0 + 1, x0 + 1); FAILx(EFAULT);
+
+   /* SYS_sigsuspend             96 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_sigaltstack            97 */
+   GO(SYS_sigaltstack, "2s 2m");
+   SY(SYS_sigaltstack, x0 + 1, x0 + 1); FAILx(EFAULT);
+
+   /* SYS_sigaction              98 */
+   GO(SYS_sigaction, "3s 4m");
+   SY(SYS_sigaction, x0, x0 + 1, x0 + 1); FAILx(EFAULT);
+
+   /* SYS_sigpending             99 */
+   GO(SYS_sigpending, "2s 1m");
+   SY(SYS_sigpending, x0, x0 + 1);
+
+   /* SYS_context               100 */
+   sys_context();
+   sys_context2();
+   sys_context3();
+   sys_context4();
+
+   /* SYS_fchmodat              101 */
+   GO(SYS_fchmodat, "4s 1m");
+   SY(SYS_fchmodat, x0 - 1, x0 + 1, x0, x0); FAIL;
+
+   /* SYS_mkdirat               102 */
+   GO(SYS_mkdirat, "3s 1m");
+   SY(SYS_mkdirat, x0 - 1, x0, x0); FAIL;
+
+   /* SYS_statvfs               103 */
+   sys_statvfs();
+   sys_statvfs2();
+
+   /* SYS_fstatvfs              104 */
+   GO(SYS_fstatvfs, "2s 1m");
+   SY(SYS_fstatvfs, x0 - 1, x0 + 1); FAILx(EBADF);
+
+   /* SYS_getloadavg            105 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_nfssys                106 */
+   sys_nfssys();
+   /* :TODO: Add test cases when other opcodes are implemented. */
+
+   /* SYS_waitid                107 */
+   GO(SYS_waitid, "4s 1m");
+   SY(SYS_waitid, x0 - 1, x0, x0, x0); FAIL;
+
+   /* SYS_sigsendsys            108 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_hrtsys                109 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_utimesys              110 */
+   /* SYS_utimensat             110 */
+   /* Tested in scalar_utimesys and scalar_utimensat. */
+
+   /* SYS_sigresend             111 */
+   GO(SYS_sigresend, "3s 2m");
+   SY(SYS_sigresend, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_priocntlsys           112 */
+   sys_priocntlsys();
+   sys_priocntlsys2();
+   sys_priocntlsys3();
+   sys_priocntlsys4();
+   sys_priocntlsys5();
+   sys_priocntlsys6();
+   sys_priocntlsys7();
+   sys_priocntlsys8();
+   sys_priocntlsys9();
+   sys_priocntlsys10();
+   sys_priocntlsys11();
+
+   /* SYS_pathconf              113 */
+   GO(SYS_pathconf, "2s 1m");
+   SY(SYS_pathconf, x0, x0); FAIL;
+
+   /* SYS_mincore               114 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_mmap                  115 */
+   GO(SYS_mmap, "6s 0m");
+   SY(SYS_mmap, x0, x0, x0, x0, x0, x0); FAILx(EINVAL);
+
+   /* SYS_mprotect              116 */
+   GO(SYS_mprotect, "3s 0m");
+   SY(SYS_mprotect, x0, x0, x0); FAILx(EINVAL);
+
+   /* SYS_munmap                117 */
+   GO(SYS_munmap, "2s 0m");
+   SY(SYS_munmap, x0, x0); FAILx(EINVAL);
+
+   /* SYS_fpathconf             118 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_vfork                 119 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_fchdir                120 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_readv                 121 */
+   GO(SYS_readv, "3s 1m");
+   SY(SYS_readv, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_writev                122 */
+   GO(SYS_writev, "3s 1m");
+   SY(SYS_writev, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_mmapobj               127 */
+   GO(SYS_mmapobj, "5s 2m");
+   SY(SYS_mmapobj, x0 - 1, x0 | MMOBJ_PADDING, x0, x0, x0); FAILx(EBADF);
+
+   /* SYS_setrlimit             128 */
+   GO(SYS_setrlimit, "2s 1m");
+   SY(SYS_setrlimit, x0, x0); FAIL;
+
+   /* SYS_getrlimit             129 */
+   GO(SYS_getrlimit, "2s 1m");
+   SY(SYS_getrlimit, x0, x0); FAIL;
+
+   /* SYS_lchown                130 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_memcntl               131 */
+   GO(SYS_memcntl, "6s 1m");
+   SY(SYS_memcntl, x0, x0, x0 | MC_HAT_ADVISE, x0, x0, x0); FAIL;
+
+   /* SYS_getpmsg               132 */
+   GO(SYS_getpmsg, "5s 2m");
+   SY(SYS_getpmsg, x0, x0, x0, x0, x0); FAIL;
+
+   /* SYS_putpmsg               133 */
+   GO(SYS_putpmsg, "5s 0m");
+   SY(SYS_putpmsg, x0, x0, x0, x0, x0); FAIL;
+
+   /* SYS_rename                134 */
+   /* Tested in scalar_obsolete.c. */
+
+   /* SYS_uname                 135 */
+   sys_uname();
+   sys_uname2();
+
+   /* SYS_setegid               136 */
+   GO(SYS_setegid, "1s 0m");
+   SY(SYS_setegid, x0 - 1); FAIL;
+
+   /* SYS_sysconfig             137 */
+   GO(SYS_sysconfig, "1s 0m");
+   SY(SYS_sysconfig, x0 - 1); FAIL;
+
+   /* SYS_adjtime               138 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_systeminfo            139 */
+   GO(SYS_systeminfo, "3s 1m");
+   SY(SYS_systeminfo, x0 + 1, x0, x0 + 1); FAIL;
+
+   /* SYS_sharefs               140 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_seteuid               141 */
+   GO(SYS_seteuid, "1s 0m");
+   SY(SYS_seteuid, x0 - 1); FAIL;
+
+   /* SYS_forksys               142 */
+   GO(SYS_forksys, "2s 0m");
+   SY(SYS_forksys, x0, x0 - 1); FAIL;
+
+   /* SYS_sigtimedwait          144 */
+   GO(SYS_sigtimedwait, "3s 3m");
+   SY(SYS_sigtimedwait, x0 - 1, x0 - 1, x0 - 1); FAIL;
+
+   /* SYS_lwp_info              145 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_yield                 146 */
+   GO(SYS_yield, "0s 0m");
+   SY(SYS_yield); SUCC;
+
+   /* SYS_lwp_sema_post         148 */
+   GO(SYS_lwp_sema_post, "1s 3m");
+   SY(SYS_lwp_sema_post, x0); FAIL;
+
+   /* SYS_lwp_sema_trywait      149 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_detach            150 */
+   GO(SYS_lwp_detach, "1s 0m");
+   SY(SYS_lwp_detach, x0); FAIL;
+
+   /* SYS_corectl               151 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_modctl                152 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_fchroot               153 */
+   GO(SYS_fchroot, "1s 0m");
+   SY(SYS_fchroot, x0 - 1); FAILx(EBADF);
+
+   /* SYS_vhangup               155 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_gettimeofday          156 */
+   GO(SYS_gettimeofday, "1s 1m");
+   SY(SYS_gettimeofday, x0 + 1); FAIL;
+
+   /* SYS_getitimer             157 */
+   GO(SYS_getitimer, "2s 2m");
+   SY(SYS_getitimer, x0, x0 + 1); FAIL;
+
+   /* SYS_setitimer             158 */
+   GO(SYS_setitimer, "3s 4m");
+   SY(SYS_setitimer, x0, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_lwp_create            159 */
+   /* In the lwp_create() wrapper, we unfortunately have to call
+      ML_(safe_to_deref) before doing the PRE_READ_*() stuff, therefore only 1m
+      parameter. */
+   GO(SYS_lwp_create, "3s 1m");
+   SY(SYS_lwp_create, x0, x0, x0 + 1); FAILx(EINVAL);
+
+   /* SYS_lwp_exit              160 */
+   /* Don't bother to test this. */
+   GO(SYS_lwp_exit, "ignore");
+
+   /* SYS_lwp_suspend           161 */
+   GO(SYS_lwp_suspend, "1s 0m");
+   SY(SYS_lwp_suspend, x0 - 1); FAIL;
+
+   /* SYS_lwp_continue          162 */
+   GO(SYS_lwp_continue, "1s 0m");
+   SY(SYS_lwp_continue, x0 - 1); FAIL;
+
+   /* SYS_lwp_kill              163 */
+   /* SYS_lwp_sigqueue          163 */
+   /* Tested in scalar_lwp_kill and scalar_lwp_sigqueue. */
+
+   /* SYS_lwp_self              164 */
+   GO(SYS_lwp_self, "0s 0m");
+   SY(SYS_lwp_self); SUCC;
+
+   /* SYS_lwp_sigmask           165 */
+   GO(SYS_lwp_sigmask, "5s 0m");
+   SY(SYS_lwp_sigmask, x0, x0, x0, x0, x0); FAIL;
+
+   /* SYS_lwp_private           166 */
+   GO(SYS_lwp_private, "3s 1m");
+#if defined(__i386)
+   SY(SYS_lwp_private, x0 + _LWP_GETPRIVATE, x0 + _LWP_GSBASE, x0); FAIL;
+#elif defined(__amd64)
+   SY(SYS_lwp_private, x0 + _LWP_GETPRIVATE, x0 + _LWP_FSBASE, x0); FAIL;
+#else
+#error Unsupported platform
+#endif
+
+   /* SYS_lwp_wait              167 */
+   GO(SYS_lwp_wait, "2s 1m");
+   SY(SYS_lwp_wait, x0 - 1, x0 + 1); FAIL;
+
+   /* SYS_lwp_mutex_wakeup      168 */
+   GO(SYS_lwp_mutex_wakeup, "2s 2m");
+   SY(SYS_lwp_mutex_wakeup, x0, x0); FAIL;
+
+   /* SYS_lwp_cond_wait         170 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_cond_signal       171 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_cond_broadcast    172 */
+   GO(SYS_lwp_cond_broadcast, "1s 2m");
+   SY(SYS_lwp_cond_broadcast, x0); FAIL;
+
+   /* SYS_pread                 173 */
+   GO(SYS_pread, "4s 1m");
+   SY(SYS_pread, x0 - 1, x0, x0 + 1, x0); FAILx(EBADF);
+
+   /* SYS_pwrite                174 */
+   GO(SYS_pwrite, "4s 1m");
+   SY(SYS_pwrite, x0 - 1, x0, x0 + 1, x0); FAILx(EBADF);
+
+   /* SYS_llseek                175 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_inst_sync             176 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_brand                 177 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_kaio                  178 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_cpc                   179 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lgrpsys               180 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_rusagesys             181 */
+   sys_rusagesys();
+   sys_rusagesys2();
+   sys_rusagesys3();
+   sys_rusagesys4();
+   sys_rusagesys5();
+
+   /* SYS_port                  182 */
+   sys_port();
+   sys_port2();
+   sys_port3();
+   sys_port4();
+   sys_port5();
+   sys_port6();
+   sys_port7();
+   sys_port8();
+   sys_port9();
+   sys_port10();
+   sys_port11();
+
+   /* SYS_pollsys               183 */
+   GO(SYS_pollsys, "4s 5m");
+   SY(SYS_pollsys, x0, x0 + 1, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_labelsys              184 */
+   sys_labelsys();
+   sys_labelsys2();
+   sys_labelsys3();
+   sys_labelsys4();
+   sys_labelsys5();
+   sys_labelsys6();
+
+   /* SYS_acl                   185 */
+   sys_acl();
+   sys_acl2();
+   sys_acl3();
+   sys_acl4();
+   sys_acl5();
+   sys_acl6();
+
+   /* SYS_auditsys              186 */
+   sys_auditsys();
+   sys_auditsys2();
+   sys_auditsys3();
+   sys_auditsys4();
+   sys_auditsys5();
+   sys_auditsys6();
+   sys_auditsys7();
+   sys_auditsys8();
+   sys_auditsys9();
+   sys_auditsys10();
+   sys_auditsys11();
+   sys_auditsys12();
+   sys_auditsys13();
+   sys_auditsys14();
+   sys_auditsys15();
+   sys_auditsys16();
+   sys_auditsys17();
+   sys_auditsys18();
+   sys_auditsys19();
+   sys_auditsys20();
+   sys_auditsys21();
+   sys_auditsys22();
+   sys_auditsys23();
+   sys_auditsys24();
+   sys_auditsys25();
+   sys_auditsys26();
+   sys_auditsys27();
+   sys_auditsys28();
+   sys_auditsys29();
+   sys_auditsys30();
+   sys_auditsys31();
+   sys_auditsys32();
+
+   /* SYS_processor_bind        187 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_processor_info        188 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_p_online              189 */
+   GO(SYS_p_online, "2s 0m");
+   SY(SYS_p_online, x0, x0); FAILx(EINVAL);
+
+   /* SYS_sigqueue              190 */
+   GO(SYS_sigqueue, "5s 1m");
+   SY(SYS_sigqueue, x0 - 1, x0, x0 + 1, x0, x0 - 1); FAIL;
+
+   /* SYS_clock_gettime         191 */
+   GO(SYS_clock_gettime, "2s 1m");
+   SY(SYS_clock_gettime, x0, x0); FAIL;
+
+   /* SYS_clock_settime         192 */
+   GO(SYS_clock_settime, "2s 1m");
+   SY(SYS_clock_settime, x0, x0);  FAIL;
+
+   /* SYS_clock_getres          193 */
+   GO(SYS_clock_getres, "2s 1m");
+   SY(SYS_clock_getres, x0 + 1, x0 + 1); FAIL;
+
+   /* SYS_timer_create          194 */
+   sys_timer_create();
+   sys_timer_create2();
+
+   /* SYS_timer_delete          195 */
+   GO(SYS_timer_delete, "1s 0m");
+   SY(SYS_timer_delete, x0 + 1); FAIL;
+
+   /* SYS_timer_settime         196 */
+   GO(SYS_timer_settime, "4s 2m");
+   SY(SYS_timer_settime, x0, x0, x0 + 1, x0 + 2); FAIL;
+
+   /* SYS_timer_gettime         197 */
+   GO(SYS_timer_gettime, "2s 1m");
+   SY(SYS_timer_gettime, x0, x0 + 1); FAIL;
+
+   /* SYS_timer_getoverrun      198 */
+   GO(SYS_timer_getoverrun, "1s 0m");
+   SY(SYS_timer_getoverrun, x0); FAIL;
+
+   /* SYS_nanosleep             199 */
+   GO(SYS_nanosleep, "2s 2m");
+   SY(SYS_nanosleep, x0, x0 + 1); FAIL;
+
+   /* SYS_facl                  200 */
+   sys_facl();
+   sys_facl2();
+   sys_facl3();
+   sys_facl4();
+   sys_facl5();
+   sys_facl6();
+
+   /* SYS_door                  201 */
+   sys_door();
+   sys_door2();
+   sys_door3();
+   sys_door4();
+   sys_door5();
+   /* XXX Additional sys_door variants still unimplemented. */
+
+   /* SYS_setreuid              202 */
+   GO(SYS_setreuid, "2s 0m");
+   SY(SYS_setreuid, x0 - 1, x0 - 1); SUCC;
+
+   /* SYS_setregid              203 */
+   GO(SYS_setregid, "2s 0m");
+   SY(SYS_setregid, x0 - 1, x0 - 1); SUCC;
+
+   /* SYS_install_utrap         204 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_signotify             205 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_schedctl              206 */
+   GO(SYS_schedctl, "0s 0m");
+   SY(SYS_schedctl); SUCC;
+
+   /* SYS_pset                  207 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_sparc_utrap_install   208 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_resolvepath           209 */
+   GO(SYS_resolvepath, "3s 2m");
+   SY(SYS_resolvepath, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_lwp_mutex_timedlock   210 */
+   GO(SYS_lwp_mutex_timedlock, "3s 7m");
+   SY(SYS_lwp_mutex_timedlock, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_lwp_sema_timedwait    211 */
+   GO(SYS_lwp_sema_timedwait, "3s 4m");
+   SY(SYS_lwp_sema_timedwait, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_lwp_rwlock_sys        212 */
+   sys_lwp_rwlock();
+   sys_lwp_rwlock2();
+   sys_lwp_rwlock3();
+   sys_lwp_rwlock4();
+   sys_lwp_rwlock5();
+
+   /* SYS_getdents64            213 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_mmap64                214 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_stat64                215 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_lstat64               216 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_fstat64               217 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_statvfs64             218 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_fstatvfs64            219 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_setrlimit64           220 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_getrlimit64           221 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_pread64               222 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_pwrite64              223 */
+   /* Tested in x86-solaris/scalar.c. */
+
+   /* SYS_open64                225 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_rpcsys                226 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_zone                  227 */
+   sys_zone();
+   sys_zone2();
+   sys_zone3();
+   sys_zone4();
+   sys_zone5();
+   sys_zone6();
+   sys_zone7();
+   sys_zone8();
+   sys_zone9();
+   sys_zone10();
+   sys_zone11();
+   /*
+   2013-09-22 Petr Pavlu -- The following test crashes my system because of
+   a kernel bug (illumos), commenting it out for now.
+   sys_zone12();
+   */
+   sys_zone13();
+   /*
+   2013-09-22 Petr Pavlu -- The following test provides an incorrect result
+   because of a kernel bug (illumos), commenting it out for now.
+   sys_zone14();
+   */
+   sys_zone15();
+   /*
+   2013-09-22 Petr Pavlu -- The following test provides an incorrect result
+   because of a kernel bug (illumos), commenting it out for now.
+   sys_zone16();
+   */
+
+   /* SYS_autofssys             228 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_getcwd                229 */
+   GO(SYS_getcwd, "2s 1m");
+   SY(SYS_getcwd, x0, x0 + 1); FAIL;
+
+   /* SYS_so_socket             230 */
+   GO(SYS_so_socket, "5s 1m");
+   SY(SYS_so_socket, x0, x0, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_so_socketpair         231 */
+   GO(SYS_so_socketpair, "1s 1m");
+   SY(SYS_so_socketpair, x0); FAIL;
+
+   /* SYS_bind                  232 */
+   GO(SYS_bind, "4s 0m");
+   SY(SYS_bind, x0, x0, x0, x0); FAIL;
+
+   /* SYS_listen                233 */
+   GO(SYS_listen, "3s 0m");
+   SY(SYS_listen, x0, x0, x0); FAIL;
+
+   /* SYS_accept                234 */
+   /* Illumos added a new version of the accept() syscall which takes an extra
+      flag parameter.  This is trivially handled in the syscall wrapper but it
+      is not tested here so it is not necessary to have two versions of the
+      stderr.exp file. */
+   GO(SYS_accept, "4s 0m");
+   SY(SYS_accept, x0, x0, x0, x0, 0); FAIL;
+
+   /* SYS_connect               235 */
+   GO(SYS_connect, "4s 0m");
+   SY(SYS_connect, x0, x0, x0, x0); FAIL;
+
+   /* SYS_shutdown              236 */
+   GO(SYS_shutdown, "3s 0m");
+   SY(SYS_shutdown, x0 - 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_recv                  237 */
+   GO(SYS_recv, "4s 1m");
+   SY(SYS_recv, x0, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_recvfrom              238 */
+   GO(SYS_recvfrom, "6s 1m");
+   SY(SYS_recvfrom, x0, x0, x0 + 1, x0, x0, x0); FAIL;
+
+   /* SYS_recvmsg               239 */
+   GO(SYS_recvmsg, "3s 0m");
+   SY(SYS_recvmsg, x0, x0, x0); FAIL;
+
+   /* SYS_send                  240 */
+   GO(SYS_send, "4s 1m");
+   SY(SYS_send, x0, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_sendmsg               241 */
+   GO(SYS_sendmsg, "3s 0m");
+   SY(SYS_sendmsg, x0, x0, x0); FAIL;
+
+   /* SYS_sendto                242 */
+   GO(SYS_sendto, "6s 1m");
+   SY(SYS_sendto, x0, x0, x0 + 1, x0, x0, x0); FAIL;
+
+   /* SYS_getpeername           243 */
+   sys_getpeername();
+   sys_getpeername2();
+
+   /* SYS_getsockname           244 */
+   GO(SYS_getsockname, "4s 1m");
+   SY(SYS_getsockname, x0, x0, x0, x0); FAIL;
+
+   /* SYS_getsockopt            245 */
+   GO(SYS_getsockopt, "6s 0m");
+   SY(SYS_getsockopt, x0, x0, x0, x0, x0, x0); FAIL;
+
+   /* SYS_setsockopt            246 */
+   GO(SYS_setsockopt, "6s 1m");
+   SY(SYS_setsockopt, x0, x0, x0, x0, x0 + 1, x0); FAIL;
+
+   /* SYS_sockconfig            247 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_ntp_gettime           248 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_ntp_adjtime           249 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_mutex_unlock      250 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_mutex_trylock     251 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_lwp_mutex_register    252 */
+   GO(SYS_lwp_mutex_register, "2s 1m");
+   SY(SYS_lwp_mutex_register, x0, x0); FAIL;
+
+   /* SYS_cladm                 253 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_uucopy                254 */
+   GO(SYS_uucopy, "3s 2m");
+   SY(SYS_uucopy, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_umount2               255 */
+   GO(SYS_umount2, "2s 1m");
+   SY(SYS_umount2, x0, x0); FAIL;
+
+   /* No such syscall... */
+#if 0
+   GO(9999, "1e");
+   SY(9999); FAIL;
+#endif
+
+   /* SYS_exit                    1 */
+   GO(SYS_exit, "1s 0m");
+   SY(SYS_exit, x0); FAIL;
+
+   assert(0);
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar.h b/memcheck/tests/solaris/scalar.h
new file mode 100644
index 0000000..601a46e
--- /dev/null
+++ b/memcheck/tests/solaris/scalar.h
@@ -0,0 +1,38 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+
+#define GO(syscall_num, param) \
+   fprintf(stderr, "---------------------------------------------------------\n"  \
+                   "%3d:%24s %s\n"                                                \
+                   "---------------------------------------------------------\n", \
+                   syscall_num, #syscall_num, param);
+
+#define SY res = syscall
+
+#define FAIL assert(res == -1);
+#define SUCC assert(res != -1);
+#define FAILx(E) \
+   do { \
+      int myerrno = errno; \
+      if (res == -1) { \
+         if (myerrno == E) { \
+            /* as expected */ \
+         } \
+         else { \
+            fprintf(stderr, "Expected error %s (%d), got %d\n", #E, E, myerrno); \
+            exit(1); \
+         } \
+      } \
+      else { \
+         fprintf(stderr, "Expected error %s (%d), got success\n", #E, E); \
+         exit(1); \
+      } \
+   } while (0);
+
+/* Module variables. */
+static long x0;
+static long res;
+
diff --git a/memcheck/tests/solaris/scalar.stderr.exp b/memcheck/tests/solaris/scalar.stderr.exp
new file mode 100644
index 0000000..969e111
--- /dev/null
+++ b/memcheck/tests/solaris/scalar.stderr.exp
@@ -0,0 +1,5094 @@
+---------------------------------------------------------
+  3:                SYS_read 3s 0m
+---------------------------------------------------------
+Syscall param read(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param read(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param read(count) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+  4:               SYS_write 3s 1m
+---------------------------------------------------------
+Syscall param write(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param write(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param write(count) contains uninitialised byte(s)
+   ...
+
+Syscall param write(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  6:               SYS_close 1s 0m
+---------------------------------------------------------
+Syscall param close(fd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+  7:              SYS_linkat 5s 2m
+---------------------------------------------------------
+Syscall param linkat(fd1) contains uninitialised byte(s)
+   ...
+
+Syscall param linkat(path1) contains uninitialised byte(s)
+   ...
+
+Syscall param linkat(fd2) contains uninitialised byte(s)
+   ...
+
+Syscall param linkat(path2) contains uninitialised byte(s)
+   ...
+
+Syscall param linkat(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param linkat(path1) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param linkat(path2) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 11:           SYS_symlinkat 3s 2m
+---------------------------------------------------------
+Syscall param symlinkat(path1) contains uninitialised byte(s)
+   ...
+
+Syscall param symlinkat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param symlinkat(path2) contains uninitialised byte(s)
+   ...
+
+Syscall param symlinkat(path1) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param symlinkat(path2) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 12:               SYS_chdir 1s 1m
+---------------------------------------------------------
+Syscall param chdir(path) contains uninitialised byte(s)
+   ...
+
+Syscall param chdir(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 13:                SYS_time 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+ 17:                 SYS_brk 1s 0m
+---------------------------------------------------------
+Syscall param brk(end_data_segment) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 19:               SYS_lseek 3s 0m
+---------------------------------------------------------
+Syscall param lseek(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param lseek(offset) contains uninitialised byte(s)
+   ...
+
+Syscall param lseek(whence) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 20:              SYS_getpid 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+ 21:               SYS_mount (4-arg, table variant) 4s 2m
+---------------------------------------------------------
+Syscall param mount(spec) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dir) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(mflag) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(fstype) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(spec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dir) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 21:               SYS_mount (4-arg) 4s 3m
+---------------------------------------------------------
+Syscall param mount(spec) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dir) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(mflag) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(fstype) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(spec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dir) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(fstype) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 21:               SYS_mount (6-arg) 6s 4m
+---------------------------------------------------------
+Syscall param mount(spec) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dir) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(mflag) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(fstype) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(datalen) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(spec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dir) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(fstype) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dataptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 21:               SYS_mount (8-arg) 8s 5m
+---------------------------------------------------------
+Syscall param mount(spec) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dir) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(mflag) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(fstype) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(datalen) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(optptr) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(optlen) contains uninitialised byte(s)
+   ...
+
+Syscall param mount(spec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dir) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(fstype) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(dataptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mount(optptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 22:          SYS_readlinkat 4s 2m
+---------------------------------------------------------
+Syscall param readlinkat(dfd) contains uninitialised byte(s)
+   ...
+
+Syscall param readlinkat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param readlinkat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param readlinkat(bufsiz) contains uninitialised byte(s)
+   ...
+
+Syscall param readlinkat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param readlinkat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 23:              SYS_setuid 1s 0m
+---------------------------------------------------------
+Syscall param setuid(uid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 24:              SYS_getuid 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+ 25:               SYS_stime 1s 0m
+---------------------------------------------------------
+Syscall param stime(time) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 27:               SYS_alarm 1s 0m
+---------------------------------------------------------
+Syscall param alarm(seconds) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 29:               SYS_pause ignore
+---------------------------------------------------------
+---------------------------------------------------------
+ 31:                SYS_stty 2s 1m
+---------------------------------------------------------
+Syscall param stty(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param stty(tty) contains uninitialised byte(s)
+   ...
+
+Syscall param stty(tty) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 32:                SYS_gtty 2s 1m
+---------------------------------------------------------
+Syscall param gtty(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param gtty(tty) contains uninitialised byte(s)
+   ...
+
+Syscall param gtty(tty) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 37:                SYS_kill 2s 0m
+---------------------------------------------------------
+Syscall param kill(pid) contains uninitialised byte(s)
+   ...
+
+Syscall param kill(signal) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 39:             SYS_pgrpsys (GETPGRP) 1s 0m
+---------------------------------------------------------
+Syscall param pgrpsys_getpgrp(flag) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 39:             SYS_pgrpsys (GETSID) 2s 0m
+---------------------------------------------------------
+Syscall param pgrpsys_getsid(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param pgrpsys_getsid(pid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 39:             SYS_pgrpsys (GETPGID) 2s 0m
+---------------------------------------------------------
+Syscall param pgrpsys_getpgid(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param pgrpsys_getpgid(pid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 42:                SYS_pipe ignore
+---------------------------------------------------------
+---------------------------------------------------------
+ 43:               SYS_times 1s 1m
+---------------------------------------------------------
+Syscall param times(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param times(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 45:           SYS_faccessat 4s 1m
+---------------------------------------------------------
+Syscall param faccessat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param faccessat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param faccessat(amode) contains uninitialised byte(s)
+   ...
+
+Syscall param faccessat(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param faccessat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 46:              SYS_setgid 1s 0m
+---------------------------------------------------------
+Syscall param setgid(gid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 47:              SYS_getgid 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+ 48:             SYS_mknodat 4s 1m
+---------------------------------------------------------
+Syscall param mknodat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param mknodat(fname) contains uninitialised byte(s)
+   ...
+
+Syscall param mknodat(fmode) contains uninitialised byte(s)
+   ...
+
+Syscall param mknodat(dev) contains uninitialised byte(s)
+   ...
+
+Syscall param mknodat(fname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 50:              SYS_sysi86 incoming
+---------------------------------------------------------
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMAT) 4s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmat(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmat(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmat(shmaddr) contains uninitialised byte(s)
+   ...
+
+
+More than 100 errors detected.  Subsequent errors
+will still be recorded, but in less detail than before.
+Syscall param shmsys_shmat(shmflg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,SHM_LOCK) 3s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_lock(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_lock(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_lock(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,SHM_UNLOCK) 3s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_unlock(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_unlock(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_unlock(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_RMID) 3s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_rmid(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_rmid(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_rmid(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_SET) 4s 3m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_set(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.uid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.gid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.mode) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_SET) 6s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_set(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.uid) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.gid) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param shmsys(shmctl, ipc_set, buf->shm_perm.mode) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_STAT) 4s 1m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_stat(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_stat, buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_SET64) 4s 3m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_set64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set64(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_uid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_gid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_mode) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_SET64) 6s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_set64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set64(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_set64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_uid) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_gid) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param shmsys(shmctl, ipc_set64, buf->shmx_perm.ipcx_mode) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_STAT64) 4s 1m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_stat64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat64(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_stat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_stat64, buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMDT) 2s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmdt(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmdt(shmaddr) contains uninitialised byte(s)
+   ...
+
+Warning: client syscall shmdt tried to modify addresses 0x........-0x........
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMGET) 4s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmget(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget(key) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget(size) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget(shmflg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMIDS) 4s 2m
+---------------------------------------------------------
+Syscall param shmsys_shmids(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmids(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmids(nids) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmids(pnids) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmids, buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param shmsys(shmids, pnids) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,IPC_STAT) 5s 1m
+---------------------------------------------------------
+Syscall param semsys_semctl_stat(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param semctl(IPC_STAT, arg.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,IPC_SET) 5s 1m
+---------------------------------------------------------
+Syscall param semsys_semctl_set(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param semctl(IPC_SET, arg.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,IPC_STAT64) 5s 1m
+---------------------------------------------------------
+Syscall param semsys_semctl_stat64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat64(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat64(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_stat64(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param semctl(IPC_STAT, arg.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,IPC_SET64) 5s 1m
+---------------------------------------------------------
+Syscall param semsys_semctl_set64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set64(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set64(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_set64(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param semctl(IPC_SET, arg.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,IPC_RMID) 3s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_rmid(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_rmid(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_rmid(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,GETALL) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_getall(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getall(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getall(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getall(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,SETALL) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_setall(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setall(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setall(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setall(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,GETVAL) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_getval(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getval(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getval(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getval(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,SETVAL) 5s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_setval(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setval(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setval(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setval(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_setval(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,GETPID) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_getpid(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getpid(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getpid(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getpid(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,GETNCNT) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_getncnt(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getncnt(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getncnt(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getncnt(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMCTL,GETZCNT) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semctl_getzcnt(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getzcnt(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getzcnt(semnum) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semctl_getzcnt(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMGET) 4s 0m
+---------------------------------------------------------
+Syscall param semsys_semget(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semget(key) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semget(nsems) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semget(semflg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMOP) 4s 1m
+---------------------------------------------------------
+Syscall param semsys_semop(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semop(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semop(sops) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semop(nsops) contains uninitialised byte(s)
+   ...
+
+Syscall param semop(sops) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMIDS) 4s 2m
+---------------------------------------------------------
+Syscall param semsys_semids(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semids(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semids(nids) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semids(pnids) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys(semids, buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param semsys(semids, pnids) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 53:              SYS_semsys (SEMTIMEDOP) 5s 2m
+---------------------------------------------------------
+Syscall param semsys_semtimedop(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semtimedop(semid) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semtimedop(sops) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semtimedop(nsops) contains uninitialised byte(s)
+   ...
+
+Syscall param semsys_semtimedop(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param semtimedop(sops) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param semtimedop(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCGETS) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 56:            SYS_fchownat 5s 1m
+---------------------------------------------------------
+Syscall param fchownat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fchownat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param fchownat(owner) contains uninitialised byte(s)
+   ...
+
+Syscall param fchownat(group) contains uninitialised byte(s)
+   ...
+
+Syscall param fchownat(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param fchownat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 58:              SYS_fdsync 2s 0m
+---------------------------------------------------------
+Syscall param fdsync(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fdsync(flag) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 59:              SYS_execve 3s 1m
+---------------------------------------------------------
+Syscall param execve(file) contains uninitialised byte(s)
+   ...
+
+Syscall param execve(argv) contains uninitialised byte(s)
+   ...
+
+Syscall param execve(envp) contains uninitialised byte(s)
+   ...
+
+Syscall param execve(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 60:               SYS_umask 1s 0m
+---------------------------------------------------------
+Syscall param umask(mask) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 61:              SYS_chroot 1s 1m
+---------------------------------------------------------
+Syscall param chroot(path) contains uninitialised byte(s)
+   ...
+
+Syscall param chroot(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 62:               SYS_fcntl (GETFD) 2s 0m
+---------------------------------------------------------
+Syscall param fcntl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(cmd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 62:               SYS_fcntl (DUPFD) 3s 0m
+---------------------------------------------------------
+Syscall param fcntl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 62:               SYS_fcntl (GETLK) 3s 5m
+---------------------------------------------------------
+Syscall param fcntl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(lock) contains uninitialised byte(s)
+   ...
+
+Syscall param fcntl(lock->l_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fcntl(lock->l_whence) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fcntl(lock->l_start) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fcntl(lock->l_len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fcntl(lock) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 64:            SYS_renameat 4s 2m
+---------------------------------------------------------
+Syscall param renameat(fromfd) contains uninitialised byte(s)
+   ...
+
+Syscall param renameat(old) contains uninitialised byte(s)
+   ...
+
+Syscall param renameat(tofd) contains uninitialised byte(s)
+   ...
+
+Syscall param renameat(new) contains uninitialised byte(s)
+   ...
+
+Syscall param renameat(old) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param renameat(new) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ xx:            SYS_unlinkat 3s 1m
+---------------------------------------------------------
+Syscall param unlinkat(dirfd) contains uninitialised byte(s)
+   ...
+
+Syscall param unlinkat(pathname) contains uninitialised byte(s)
+   ...
+
+Syscall param unlinkat(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param unlinkat(pathname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 66:             SYS_fstatat 4s 2m
+---------------------------------------------------------
+Syscall param fstatat(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fstatat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 68:              SYS_openat (3-args) 3s 1m
+---------------------------------------------------------
+Syscall param openat(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 68:              SYS_openat (4-args) 4s 1m
+---------------------------------------------------------
+Syscall param openat(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param openat(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 70:             SYS_tasksys (settaskid) 3s 0m
+---------------------------------------------------------
+Syscall param tasksys_settaskid(code) contains uninitialised byte(s)
+   ...
+
+Syscall param tasksys_settaskid(projid) contains uninitialised byte(s)
+   ...
+
+Syscall param tasksys_settaskid(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 70:             SYS_tasksys (gettaskid) 1s 0m
+---------------------------------------------------------
+Syscall param tasksys_gettaskid(code) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 70:             SYS_tasksys (getprojid) 1s 0m
+---------------------------------------------------------
+Syscall param tasksys_getprojid(code) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 70:             SYS_tasksys (projlist) 3s 1m
+---------------------------------------------------------
+Syscall param tasksys_projlist(code) contains uninitialised byte(s)
+   ...
+
+Syscall param tasksys_projlist(idbuf) contains uninitialised byte(s)
+   ...
+
+Syscall param tasksys_projlist(idbufsz) contains uninitialised byte(s)
+   ...
+
+Syscall param tasksys(idbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 73:        SYS_getpagesizes 3s 1m
+---------------------------------------------------------
+Syscall param getpagesizes(legacy) contains uninitialised byte(s)
+   ...
+
+Syscall param getpagesizes(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param getpagesizes(nelem) contains uninitialised byte(s)
+   ...
+
+Syscall param getpagesizes(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 77:            SYS_lwp_park ignore
+---------------------------------------------------------
+---------------------------------------------------------
+ 78:           SYS_sendfilev (SENDFILEV) 5s 2m
+---------------------------------------------------------
+Syscall param sendfilev(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(sfvcnt) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(xferred) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sendfilev(xferred) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 78:           SYS_sendfilev (SENDFILEV) 4s 2m
+---------------------------------------------------------
+Syscall param sendfilev(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(xferred) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param sendfilev(xferred) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sendfilev(vec[0].sfv_off points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 78:           SYS_sendfilev (SENDFILEV64) 5s 2m
+---------------------------------------------------------
+Syscall param sendfilev(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(sfvcnt) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(xferred) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sendfilev(xferred) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 78:           SYS_sendfilev (SENDFILEV64) 4s 2m
+---------------------------------------------------------
+Syscall param sendfilev(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(xferred) contains uninitialised byte(s)
+   ...
+
+Syscall param sendfilev(vec) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param sendfilev(xferred) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sendfilev(vec[0].sfv_off points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 81:            SYS_getdents 3s 1m
+---------------------------------------------------------
+Syscall param getdents(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents(dirp) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents(count) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents(dirp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_SETPPRIV) 5s 1m
+---------------------------------------------------------
+Syscall param privsys_setppriv(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setppriv(op) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setppriv(type) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setppriv(pset) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setppriv(bufsize) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys(pset) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_GETPPRIV) 5s 1m
+---------------------------------------------------------
+Syscall param privsys_getppriv(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getppriv(op) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getppriv(type) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getppriv(pset) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getppriv(bufsize) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys(pset) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_GETIMPLINFO) 5s 1m
+---------------------------------------------------------
+Syscall param privsys_getprivinfo(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getprivinfo(op) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getprivinfo(type) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getprivinfo(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_getprivinfo(bufsize) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_SETPFLAGS) 3s 0m
+---------------------------------------------------------
+Syscall param privsys_setpflags(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setpflags(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setpflags(val) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_GETPFLAGS) 2s 0m
+---------------------------------------------------------
+Syscall param privsys_setpflags(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_setpflags(flag) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_ISSETUGID) 1s 0m
+---------------------------------------------------------
+Syscall param privsys_issetugid(code) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_PFEXEC_REG) 2s 0m
+---------------------------------------------------------
+Syscall param privsys_register_pfexec(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_register_pfexec(did) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 82:             SYS_privsys (PRIVSYS_PFEXEC_UNREG) 2s 0m
+---------------------------------------------------------
+Syscall param privsys_unregister_pfexec(code) contains uninitialised byte(s)
+   ...
+
+Syscall param privsys_unregister_pfexec(did) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 83:            SYS_ucredsys (UCREDSYS_UCREDGET) 3s 1m
+---------------------------------------------------------
+Syscall param ucredsys_ucredget(code) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys_ucredget(pid) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys_ucredget(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 83:            SYS_ucredsys (UCREDSYS_GETPEERUCRED) 3s 1m
+---------------------------------------------------------
+Syscall param ucredsys_getpeerucred(code) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys_getpeerucred(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys_getpeerucred(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param ucredsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 85:              SYS_getmsg 4s 1m
+---------------------------------------------------------
+Syscall param getmsg(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param getmsg(ctlptr) contains uninitialised byte(s)
+   ...
+
+Syscall param getmsg(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param getmsg(flagsp) contains uninitialised byte(s)
+   ...
+
+Syscall param getmsg(flagsp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 86:              SYS_putmsg 4s 0m
+---------------------------------------------------------
+Syscall param putmsg(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param putmsg(ctrlptr) contains uninitialised byte(s)
+   ...
+
+Syscall param putmsg(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param putmsg(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 91:           SYS_setgroups 2s 1m
+---------------------------------------------------------
+Syscall param setgroups(size) contains uninitialised byte(s)
+   ...
+
+Syscall param setgroups(list) contains uninitialised byte(s)
+   ...
+
+Syscall param setgroups(list) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 92:           SYS_getgroups 2s 1m
+---------------------------------------------------------
+Syscall param getgroups(size) contains uninitialised byte(s)
+   ...
+
+Syscall param getgroups(list) contains uninitialised byte(s)
+   ...
+
+Syscall param getgroups(list) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 95:         SYS_sigprocmask 3s 2m
+---------------------------------------------------------
+Syscall param sigprocmask(how) contains uninitialised byte(s)
+   ...
+
+Syscall param sigprocmask(set) contains uninitialised byte(s)
+   ...
+
+Syscall param sigprocmask(oset) contains uninitialised byte(s)
+   ...
+
+Syscall param sigprocmask(set) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigprocmask(oset) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 97:         SYS_sigaltstack 2s 2m
+---------------------------------------------------------
+Syscall param sigaltstack(ss) contains uninitialised byte(s)
+   ...
+
+Syscall param sigaltstack(oss) contains uninitialised byte(s)
+   ...
+
+Syscall param sigaltstack(ss) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigaltstack(oss) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 98:           SYS_sigaction 3s 4m
+---------------------------------------------------------
+Syscall param sigaction(signal) contains uninitialised byte(s)
+   ...
+
+Syscall param sigaction(act) contains uninitialised byte(s)
+   ...
+
+Syscall param sigaction(oact) contains uninitialised byte(s)
+   ...
+
+Syscall param sigaction(act->sa_flags) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigaction(act->sa_handler) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigaction(act->sa_mask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigaction(oact) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 99:          SYS_sigpending 2s 1m
+---------------------------------------------------------
+Syscall param sigpending(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param sigpending(setp) contains uninitialised byte(s)
+   ...
+
+Syscall param sigpending(setp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+100:             SYS_context (GETCONTEXT) 2s 1m
+---------------------------------------------------------
+Syscall param getsetcontext_getcontext(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext_getcontext(ucp) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext(ucp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+100:             SYS_context (SETCONTEXT) 2s 0m
+---------------------------------------------------------
+Syscall param getsetcontext_setcontext(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext_setcontext(ucp) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+100:             SYS_context (GETUSTACK) 2s 1m
+---------------------------------------------------------
+Syscall param getsetcontext_getustack(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext_getustack(spp) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext(spp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+100:             SYS_context (SETUSTACK) 2s 1m
+---------------------------------------------------------
+Syscall param getsetcontext_setustack(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext_setustack(sp) contains uninitialised byte(s)
+   ...
+
+Syscall param getsetcontext_setustack(sp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+101:            SYS_fchmodat 4s 1m
+---------------------------------------------------------
+Syscall param fchmodat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fchmodat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param fchmodat(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param fchmodat(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param fchmodat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+102:             SYS_mkdirat 3s 1m
+---------------------------------------------------------
+Syscall param mkdirat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param mkdirat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param mkdirat(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param mkdirat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+103:             SYS_statvfs 2s 2m
+---------------------------------------------------------
+Syscall param statvfs(path) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param statvfs(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+103:             SYS_statvfs 4s 0m
+---------------------------------------------------------
+Syscall param statvfs(path) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs(buf) contains uninitialised byte(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+---------------------------------------------------------
+104:            SYS_fstatvfs 2s 1m
+---------------------------------------------------------
+Syscall param fstatvfs(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatvfs(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatvfs(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+106:              SYS_nfssys (NFS_REVAUTH) 2s 1m
+---------------------------------------------------------
+Syscall param nfssys_nfs_revauth(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param nfssys_nfs_revauth(args) contains uninitialised byte(s)
+   ...
+
+Syscall param nfssys(arg) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+107:              SYS_waitid 4s 1m
+---------------------------------------------------------
+Syscall param waitid(idtype) contains uninitialised byte(s)
+   ...
+
+Syscall param waitid(id) contains uninitialised byte(s)
+   ...
+
+Syscall param waitid(infop) contains uninitialised byte(s)
+   ...
+
+Syscall param waitid(options) contains uninitialised byte(s)
+   ...
+
+Syscall param waitid(infop) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+111:           SYS_sigresend 3s 2m
+---------------------------------------------------------
+Syscall param sigresend(signal) contains uninitialised byte(s)
+   ...
+
+Syscall param sigresend(siginfo) contains uninitialised byte(s)
+   ...
+
+Syscall param sigresend(mask) contains uninitialised byte(s)
+   ...
+
+Syscall param sigresend(siginfo) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigresend(mask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETCID) 6s 0m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(clname) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETCLINFO) 6s 0m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cid) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (SETPARMS) 5s 2m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(parms) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETPARMS) 5s 2m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(parms) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETPRIRANGE) 5s 2m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(pri) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (DONICE) 5s 2m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(op) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (SETXPARMS) 5s 3m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(clname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(vaparmscnt) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETXPARMS) 5s 3m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(clname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(vaparmscnt) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (SETDFLCL) 5s 1m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(clname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (GETDFLCL) 5s 1m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(clname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+112:         SYS_priocntlsys (DOPRIO) 5s 2m
+---------------------------------------------------------
+Syscall param priocntlsys(pc_version) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param priocntlsys(psp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param priocntlsys(op) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+113:            SYS_pathconf 2s 1m
+---------------------------------------------------------
+Syscall param pathconf(path) contains uninitialised byte(s)
+   ...
+
+Syscall param pathconf(name) contains uninitialised byte(s)
+   ...
+
+Syscall param pathconf(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+115:                SYS_mmap 6s 0m
+---------------------------------------------------------
+Syscall param mmap(start) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(length) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(prot) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(offset) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+116:            SYS_mprotect 3s 0m
+---------------------------------------------------------
+Syscall param mprotect(addr) contains uninitialised byte(s)
+   ...
+
+Syscall param mprotect(len) contains uninitialised byte(s)
+   ...
+
+Syscall param mprotect(prot) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+117:              SYS_munmap 2s 0m
+---------------------------------------------------------
+Syscall param munmap(start) contains uninitialised byte(s)
+   ...
+
+Syscall param munmap(length) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+121:               SYS_readv 3s 1m
+---------------------------------------------------------
+Syscall param readv(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param readv(vector) contains uninitialised byte(s)
+   ...
+
+Syscall param readv(count) contains uninitialised byte(s)
+   ...
+
+Syscall param readv(vector) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+122:              SYS_writev 3s 1m
+---------------------------------------------------------
+Syscall param writev(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param writev(vector) contains uninitialised byte(s)
+   ...
+
+Syscall param writev(count) contains uninitialised byte(s)
+   ...
+
+Syscall param writev(vector) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+127:             SYS_mmapobj 5s 2m
+---------------------------------------------------------
+Syscall param mmapobj(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param mmapobj(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param mmapobj(storage) contains uninitialised byte(s)
+   ...
+
+Syscall param mmapobj(elements) contains uninitialised byte(s)
+   ...
+
+Syscall param mmapobj(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param mmapobj(elements) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param mmapobj(arg) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+128:           SYS_setrlimit 2s 1m
+---------------------------------------------------------
+Syscall param setrlimit(resource) contains uninitialised byte(s)
+   ...
+
+Syscall param setrlimit(rlim) contains uninitialised byte(s)
+   ...
+
+Syscall param setrlimit(rlim) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+129:           SYS_getrlimit 2s 1m
+---------------------------------------------------------
+Syscall param getrlimit(resource) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimit(rlim) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimit(rlim) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+131:             SYS_memcntl 6s 1m
+---------------------------------------------------------
+Syscall param memcntl(addr) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(len) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(attr) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(mask) contains uninitialised byte(s)
+   ...
+
+Syscall param memcntl(arg) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+132:             SYS_getpmsg 5s 2m
+---------------------------------------------------------
+Syscall param getpmsg(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param getpmsg(ctlptr) contains uninitialised byte(s)
+   ...
+
+Syscall param getpmsg(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param getpmsg(bandp) contains uninitialised byte(s)
+   ...
+
+Syscall param getpmsg(flagsp) contains uninitialised byte(s)
+   ...
+
+Syscall param getpmsg(bandp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param getpmsg(flagsp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+133:             SYS_putpmsg 5s 0m
+---------------------------------------------------------
+Syscall param putpmsg(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param putpmsg(ctrlptr) contains uninitialised byte(s)
+   ...
+
+Syscall param putpmsg(dataptr) contains uninitialised byte(s)
+   ...
+
+Syscall param putpmsg(band) contains uninitialised byte(s)
+   ...
+
+Syscall param putpmsg(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+135:               SYS_uname 1s 1m
+---------------------------------------------------------
+Syscall param uname(name) contains uninitialised byte(s)
+   ...
+
+Syscall param uname(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+135:               SYS_uname 6s 0m
+---------------------------------------------------------
+Syscall param uname(name) contains uninitialised byte(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+---------------------------------------------------------
+136:             SYS_setegid 1s 0m
+---------------------------------------------------------
+Syscall param setegid(egid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+137:           SYS_sysconfig 1s 0m
+---------------------------------------------------------
+Syscall param sysconf(name) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+139:          SYS_systeminfo 3s 1m
+---------------------------------------------------------
+Syscall param sysinfo(command) contains uninitialised byte(s)
+   ...
+
+Syscall param sysinfo(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param sysinfo(count) contains uninitialised byte(s)
+   ...
+
+Syscall param sysinfo(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+141:             SYS_seteuid 1s 0m
+---------------------------------------------------------
+Syscall param seteuid(euid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+142:             SYS_forksys 2s 0m
+---------------------------------------------------------
+Syscall param forksys(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param forksys(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+144:        SYS_sigtimedwait 3s 3m
+---------------------------------------------------------
+Syscall param sigtimedwait(set) contains uninitialised byte(s)
+   ...
+
+Syscall param sigtimedwait(info) contains uninitialised byte(s)
+   ...
+
+Syscall param sigtimedwait(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param sigtimewait(set) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigtimedwait(info) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sigtimedwait(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+146:               SYS_yield 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+148:       SYS_lwp_sema_post 1s 3m
+---------------------------------------------------------
+Syscall param lwp_sema_post(sema) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sema_post(sema->type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_sema_post(sema->count) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_sema_post(sema->waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+150:          SYS_lwp_detach 1s 0m
+---------------------------------------------------------
+Syscall param lwp_detach(lwpid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+153:             SYS_fchroot 1s 0m
+---------------------------------------------------------
+Syscall param fchroot(fd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+156:        SYS_gettimeofday 1s 1m
+---------------------------------------------------------
+Syscall param gettimeofday(tp) contains uninitialised byte(s)
+   ...
+
+Syscall param gettimeofday(tp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+157:           SYS_getitimer 2s 2m
+---------------------------------------------------------
+Syscall param getitimer(which) contains uninitialised byte(s)
+   ...
+
+Syscall param getitimer(value) contains uninitialised byte(s)
+   ...
+
+Syscall param getitimer(&value->it_interval) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param getitimer(&value->it_value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+158:           SYS_setitimer 3s 4m
+---------------------------------------------------------
+Syscall param setitimer(which) contains uninitialised byte(s)
+   ...
+
+Syscall param setitimer(value) contains uninitialised byte(s)
+   ...
+
+Syscall param setitimer(ovalue) contains uninitialised byte(s)
+   ...
+
+Syscall param setitimer(&value->it_interval) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param setitimer(&value->it_value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param setitimer(&ovalue->it_interval) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param setitimer(&ovalue->it_value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+159:          SYS_lwp_create 3s 1m
+---------------------------------------------------------
+Syscall param lwp_create(ucp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_create(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_create(new_lwp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_create(new_lwp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+160:            SYS_lwp_exit ignore
+---------------------------------------------------------
+---------------------------------------------------------
+161:         SYS_lwp_suspend 1s 0m
+---------------------------------------------------------
+Syscall param lwp_suspend(lwpid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+162:        SYS_lwp_continue 1s 0m
+---------------------------------------------------------
+Syscall param lwp_continue(target_lwp) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+164:            SYS_lwp_self 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+165:         SYS_lwp_sigmask 5s 0m
+---------------------------------------------------------
+Syscall param lwp_sigmask(how) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigmask(bits0) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigmask(bits1) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigmask(bits2) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigmask(bits3) contains uninitialised byte(s)
+   ...
+
+sigprocmask: unknown 'how' field 0
+---------------------------------------------------------
+166:         SYS_lwp_private 3s 1m
+---------------------------------------------------------
+Syscall param lwp_private(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_private(which) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_private(base) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_private(base) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+167:            SYS_lwp_wait 2s 1m
+---------------------------------------------------------
+Syscall param lwp_wait(lwpid) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_wait(departed) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_wait(departed) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+168:    SYS_lwp_mutex_wakeup 2s 2m
+---------------------------------------------------------
+Syscall param lwp_mutex_wakeup(lp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_wakeup(release_all) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_wakeup(lp->mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_wakeup(lp->mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+172:  SYS_lwp_cond_broadcast 1s 2m
+---------------------------------------------------------
+Syscall param lwp_cond_broadcast(cvp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_cond_broadcast(cvp->type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_cond_broadcast(cvp->waiters_kernel) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+173:               SYS_pread 4s 1m
+---------------------------------------------------------
+Syscall param pread(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param pread(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param pread(nbyte) contains uninitialised byte(s)
+   ...
+
+Syscall param pread(offset) contains uninitialised byte(s)
+   ...
+
+Syscall param pread(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+174:              SYS_pwrite 4s 1m
+---------------------------------------------------------
+Syscall param pwrite(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite(nbyte) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite(offset) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+181:           SYS_rusagesys (_RUSAGESYS_GETRUSAGE) 2s 1m
+---------------------------------------------------------
+Syscall param rusagesys_getrusage(code) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getrusage(r_usage) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys(r_usage) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+181:           SYS_rusagesys (_RUSAGESYS_GETRUSAGE_CHLD) 2s 1m
+---------------------------------------------------------
+Syscall param rusagesys_getrusage(code) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getrusage(r_usage) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys(r_usage) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+181:           SYS_rusagesys (_RUSAGESYS_GETRUSAGE_LWP) 2s 1m
+---------------------------------------------------------
+Syscall param rusagesys_getrusage(code) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getrusage(r_usage) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys(r_usage) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+181:           SYS_rusagesys (_RUSAGESYS_GETVMUSAGE) 5s 1m
+---------------------------------------------------------
+Syscall param rusagesys_getvmusage(code) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(age) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(nres) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys(nres) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+181:           SYS_rusagesys (_RUSAGESYS_GETVMUSAGE) 5s 1m
+---------------------------------------------------------
+Syscall param rusagesys_getvmusage(code) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(age) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys_getvmusage(nres) contains uninitialised byte(s)
+   ...
+
+Syscall param rusagesys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_CREATE) 1s 0m
+---------------------------------------------------------
+Syscall param port_create(opcode) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+182:                SYS_port (PORT_ASSOCIATE,PORT_SOURCE_FD) 6s 0m
+---------------------------------------------------------
+Syscall param port_associate(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a4) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+182:                SYS_port (PORT_ASSOCIATE,PORT_SOURCE_FILE) 6s 1m
+---------------------------------------------------------
+Syscall param port_associate(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_associate(a4) contains uninitialised byte(s)
+   ...
+
+Syscall param port(file_obj) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_DISSOCIATE,PORT_SOURCE_FD) 6s 0m
+---------------------------------------------------------
+Syscall param port_dissociate(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a4) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+182:                SYS_port (PORT_DISSOCIATE,PORT_SOURCE_FILE) 6s 1m
+---------------------------------------------------------
+Syscall param port_dissociate(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dissociate(a4) contains uninitialised byte(s)
+   ...
+
+Syscall param port(file_obj) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_SEND) 4s 0m
+---------------------------------------------------------
+Syscall param port_send(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_send(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_send(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_send(a2) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+182:                SYS_port (PORT_SENDN) 6s 2m
+---------------------------------------------------------
+Syscall param port_sendn(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_sendn(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_sendn(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_sendn(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_sendn(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_sendn(a4) contains uninitialised byte(s)
+   ...
+
+Syscall param port(ports) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param port(errors) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_GET) 6s 1m
+---------------------------------------------------------
+Syscall param port_get(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_get(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_get(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_get(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_get(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_get(a4) contains uninitialised byte(s)
+   ...
+
+Syscall param port(uevp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_GETN) 5s 2m
+---------------------------------------------------------
+Syscall param port_getn(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_getn(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_getn(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_getn(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_getn(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_getn(a4) contains uninitialised byte(s)
+   ...
+
+Syscall param port(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param port(uevp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+182:                SYS_port (PORT_ALERT) 5s 0m
+---------------------------------------------------------
+Syscall param port_alert(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_alert(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_alert(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_alert(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_alert(a3) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+182:                SYS_port (PORT_DISPATCH) 6s 0m
+---------------------------------------------------------
+Syscall param port_dispatch(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dispatch(a0) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dispatch(a1) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dispatch(a2) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dispatch(a3) contains uninitialised byte(s)
+   ...
+
+Syscall param port_dispatch(a4) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+183:             SYS_pollsys 4s 5m
+---------------------------------------------------------
+Syscall param poll(fds) contains uninitialised byte(s)
+   ...
+
+Syscall param poll(nfds) contains uninitialised byte(s)
+   ...
+
+Syscall param poll(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param poll(set) contains uninitialised byte(s)
+   ...
+
+Syscall param poll(ufds.fd) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param poll(ufds.events) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param poll(ufds.revents) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param poll(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param poll(set) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_SYSLABELING) 1s 0m
+---------------------------------------------------------
+Syscall param labelsys_syslabeling(op) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_TNRH) 3s 1m
+---------------------------------------------------------
+Syscall param labelsys_tnrh(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnrh(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnrh(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_TNRHTP) 3s 1m
+---------------------------------------------------------
+Syscall param labelsys_tnrhtp(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnrhtp(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnrhtp(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_TNMLP) 3s 1m
+---------------------------------------------------------
+Syscall param labelsys_tnmlp(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnmlp(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_tnmlp(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_GETLABEL) 3s 2m
+---------------------------------------------------------
+Syscall param labelsys_getlabel(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_getlabel(path) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_getlabel(label) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param labelsys(label) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_FGETLABEL) 3s 1m
+---------------------------------------------------------
+Syscall param labelsys_fgetlabel(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_fgetlabel(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_fgetlabel(label) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(label) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (SETACL) 4s 2m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param acl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (GETACL) 4s 2m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param acl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (GETACLCNT) 4s 1m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (ACE_SETACL) 4s 2m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param acl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (ACE_GETACL) 4s 2m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param acl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+185:                 SYS_acl (ACE_GETACLCNT) 4s 1m
+---------------------------------------------------------
+Syscall param acl(pathp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param acl(pathp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_GETAUID) 2s 1m
+---------------------------------------------------------
+Syscall param auditsys_getauid(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_getauid(auid) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(auid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_SETAUID) 2s 1m
+---------------------------------------------------------
+Syscall param auditsys_setauid(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_setauid(auid) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(auid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_GETAUDIT) 2s 1m
+---------------------------------------------------------
+Syscall param auditsys_getaudit(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_getaudit(ai) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(ai) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_SETAUDIT) 2s 1m
+---------------------------------------------------------
+Syscall param auditsys_setaudit(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_setaudit(ai) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(ai) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDIT) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_audit(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_audit(record) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_audit(length) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(record) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETPOLICY) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getpolicy(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpolicy(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpolicy(policy) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(policy) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETPOLICY) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setpolicy(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setpolicy(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setpolicy(policy) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(policy) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETKMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getkmask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getkmask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getkmask(kmask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(kmask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETKMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setkmask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setkmask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setkmask(kmask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(kmask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETQCTRL) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getqctrl(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getqctrl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getqctrl(qctrl) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(qctrl) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETQCTRL) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setqctrl(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setqctrl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setqctrl(qctrl) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(qctrl) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETCWD) 4s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getcwd(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcwd(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcwd(data) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcwd(length) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(data) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETCAR) 4s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getcar(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcar(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcar(data) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcar(length) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(data) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETSTAT) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getstat(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getstat(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getstat(stats) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(stats) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETSTAT) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setstat(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setstat(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setstat(stats) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(stats) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETUMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setumask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setumask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setumask(umask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(umask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETSMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setsmask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setsmask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setsmask(smask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(smask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETCOND) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getcond(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcond(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getcond(cond) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(cond) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETCOND) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setcond(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setcond(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setcond(state) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(cond) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETCLASS) 3s 0m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getclass(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getclass(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getclass(classmap) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETCLASS) 3s 0m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setclass(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setclass(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setclass(classmap) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETCLASS) 4s 0m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setclass(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setclass(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(classmap.ec_number) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param auditsys(classmap.ec_class) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETPINFO) 3s 0m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getpinfo(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpinfo(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpinfo(apinfo) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETPMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setpmask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setpmask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setpmask(apinfo) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(apinfo) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETPINFO_ADDR) 4s 0m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getpinfo_addr(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpinfo_addr(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpinfo_addr(apinfo) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getpinfo_addr(length) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETKAUDIT) 4s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getkaudit(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getkaudit(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getkaudit(kaudit) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getkaudit(length) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(kaudit) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETKAUDIT) 4s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setkaudit(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setkaudit(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setkaudit(kaudit) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setkaudit(length) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(kaudit) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_GETAMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_getamask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getamask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_getamask(amask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(amask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITCTL,A_SETAMASK) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_auditctl_setamask(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setamask(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_auditctl_setamask(amask) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(amask) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_GETAUDIT_ADDR) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_getaudit_addr(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_getaudit_addr(ai) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_getaudit_addr(len) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(ai) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_SETAUDIT_ADDR) 3s 1m
+---------------------------------------------------------
+Syscall param auditsys_setaudit_addr(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_setaudit_addr(ai) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_setaudit_addr(len) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys(ai) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+186:            SYS_auditsys (BSM_AUDITDOOR) 2s 0m
+---------------------------------------------------------
+Syscall param auditsys_door(code) contains uninitialised byte(s)
+   ...
+
+Syscall param auditsys_door(fd) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+189:            SYS_p_online 2s 0m
+---------------------------------------------------------
+Syscall param p_online(processorid) contains uninitialised byte(s)
+   ...
+
+Syscall param p_online(flag) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+190:            SYS_sigqueue 5s 1m
+---------------------------------------------------------
+Syscall param sigqueue(pid) contains uninitialised byte(s)
+   ...
+
+Syscall param sigqueue(signo) contains uninitialised byte(s)
+   ...
+
+Syscall param sigqueue(value) contains uninitialised byte(s)
+   ...
+
+Syscall param sigqueue(si_code) contains uninitialised byte(s)
+   ...
+
+Syscall param sigqueue(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param sigqueue(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+191:       SYS_clock_gettime 2s 1m
+---------------------------------------------------------
+Syscall param clock_gettime(clock_id) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_gettime(tp) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_gettime(tp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+192:       SYS_clock_settime 2s 1m
+---------------------------------------------------------
+Syscall param clock_settime(clock_id) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_settime(tp) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_settime(tp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+193:        SYS_clock_getres 2s 1m
+---------------------------------------------------------
+Syscall param clock_getres(clock_id) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_getres(res) contains uninitialised byte(s)
+   ...
+
+Syscall param clock_getres(res) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+194:        SYS_timer_create 3s 4m
+---------------------------------------------------------
+Syscall param timer_create(clock_id) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_create(evp) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_create(timerid) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_create(evp.sigev_notify) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param timer_create(evp.sigev_signo) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param timer_create(evp.sigev_value.sival_int) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param timer_create(timerid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+194:        SYS_timer_create 5s 2m
+---------------------------------------------------------
+Syscall param timer_create(clock_id) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_create(timerid) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_create(evp.sigev_notify) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param timer_create(evp.sigev_signo) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param timer_create(evp.sigev_value.sival_int) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param timer_create(evp.sigev_value.sival_ptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param timer_create(timerid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+195:        SYS_timer_delete 1s 0m
+---------------------------------------------------------
+Syscall param timer_delete(timerid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+196:       SYS_timer_settime 4s 2m
+---------------------------------------------------------
+Syscall param timer_settime(timerid) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_settime(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_settime(value) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_settime(ovalue) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_settime(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param timer_settime(ovalue) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+197:       SYS_timer_gettime 2s 1m
+---------------------------------------------------------
+Syscall param timer_gettime(timerid) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_gettime(value) contains uninitialised byte(s)
+   ...
+
+Syscall param timer_gettime(value) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+198:    SYS_timer_getoverrun 1s 0m
+---------------------------------------------------------
+Syscall param timer_getoverrun(timerid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+199:           SYS_nanosleep 2s 2m
+---------------------------------------------------------
+Syscall param nanosleep(req) contains uninitialised byte(s)
+   ...
+
+Syscall param nanosleep(rem) contains uninitialised byte(s)
+   ...
+
+Syscall param nanosleep(req) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param nanosleep(rem) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+200:                SYS_facl (SETACL) 4s 1m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+200:                SYS_facl (GETACL) 4s 1m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+200:                SYS_facl (GETACLCNT) 4s 0m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+200:                SYS_facl (ACE_SETACL) 4s 1m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+200:                SYS_facl (ACE_GETACL) 4s 1m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+200:                SYS_facl (ACE_GETACLCNT) 4s 0m
+---------------------------------------------------------
+Syscall param facl(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(nentries) contains uninitialised byte(s)
+   ...
+
+Syscall param facl(aclbufp) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+201:                SYS_door (DOOR_CREATE) 4s 0m
+---------------------------------------------------------
+Syscall param door(arg1) contains uninitialised byte(s)
+   ...
+
+Syscall param door(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param door(arg3) contains uninitialised byte(s)
+   ...
+
+Syscall param door(subcode) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+201:                SYS_door (DOOR_REVOKE) 2s 0m
+---------------------------------------------------------
+Syscall param door(arg1) contains uninitialised byte(s)
+   ...
+
+Syscall param door(subcode) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+201:                SYS_door (DOOR_INFO) 3s 1m
+---------------------------------------------------------
+Syscall param door(arg1) contains uninitialised byte(s)
+   ...
+
+Syscall param door(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param door(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param door_info(info) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+201:                SYS_door (DOOR_CALL) 3s 6m
+---------------------------------------------------------
+Syscall param door(arg1) contains uninitialised byte(s)
+   ...
+
+Syscall param door(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param door(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param door_call(params->data_ptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->data_size) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->desc_ptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->desc_num) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->rbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->rsize) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+201:                SYS_door (DOOR_CALL) 9s 2m
+---------------------------------------------------------
+Syscall param door(arg1) contains uninitialised byte(s)
+   ...
+
+Syscall param door(arg2) contains uninitialised byte(s)
+   ...
+
+Syscall param door(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param door_call(params->data_ptr) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->data_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->desc_ptr) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->desc_num) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->rbuf) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->rsize) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param door_call(params->desc_ptr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param door_call(params->rbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+202:            SYS_setreuid 2s 0m
+---------------------------------------------------------
+Syscall param setreuid(ruid) contains uninitialised byte(s)
+   ...
+
+Syscall param setreuid(euid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+203:            SYS_setregid 2s 0m
+---------------------------------------------------------
+Syscall param setregid(rgid) contains uninitialised byte(s)
+   ...
+
+Syscall param setregid(egid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+206:            SYS_schedctl 0s 0m
+---------------------------------------------------------
+---------------------------------------------------------
+209:         SYS_resolvepath 3s 2m
+---------------------------------------------------------
+Syscall param resolvepath(path) contains uninitialised byte(s)
+   ...
+
+Syscall param resolvepath(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param resolvepath(bufsiz) contains uninitialised byte(s)
+   ...
+
+Syscall param resolvepath(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param resolvepath(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+210: SYS_lwp_mutex_timedlock 3s 7m
+---------------------------------------------------------
+Syscall param lwp_mutex_timedlock(lp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_timedlock(tsp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_timedlock(owner) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_timedlock(lp->mutex_flag) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(lp->mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(lp->mutex_owner) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(lp->mutex_ownerpid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(lp->mutex_lockw) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(lp->mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_mutex_timedlock(tsp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+211:  SYS_lwp_sema_timedwait 3s 4m
+---------------------------------------------------------
+Syscall param lwp_sema_timedwait(sema) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sema_timedwait(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sema_timedwait(check_park) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sema_timedwait(sema->type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_sema_timedwait(sema->count) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_sema_timedwait(sema->waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_sema_timedwait(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+212:      SYS_lwp_rwlock_sys (RDLOCK) 3s 8m
+---------------------------------------------------------
+Syscall param lwp_rwlock_rdlock(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_rdlock(rwlp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_rdlock(tsp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock(rwlp->rwlock_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->rwlock_readers) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_owner) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_ownerpid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_lockw) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(tsp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+212:      SYS_lwp_rwlock_sys (WRLOCK) 3s 8m
+---------------------------------------------------------
+Syscall param lwp_rwlock_wrlock(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_wrlock(rwlp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_wrlock(tsp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock(rwlp->rwlock_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->rwlock_readers) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_owner) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_ownerpid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_lockw) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(tsp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+212:      SYS_lwp_rwlock_sys (TRYRDLOCK) 2s 7m
+---------------------------------------------------------
+Syscall param lwp_rwlock_tryrdlock(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_tryrdlock(rwlp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock(rwlp->rwlock_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->rwlock_readers) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_owner) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_ownerpid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_lockw) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+212:      SYS_lwp_rwlock_sys (TRYWRLOCK) 2s 7m
+---------------------------------------------------------
+Syscall param lwp_rwlock_trywrlock(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_trywrlock(rwlp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock(rwlp->rwlock_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->rwlock_readers) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_owner) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_ownerpid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_lockw) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_waiters) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+212:      SYS_lwp_rwlock_sys (UNLOCK) 2s 2m
+---------------------------------------------------------
+Syscall param lwp_rwlock_unlock(subcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock_unlock(rwlp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_rwlock(rwlp->mutex.mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lwp_rwlock(rwlp->rwlock_readers) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_CREATE) 2s 12m
+---------------------------------------------------------
+Syscall param zone_create(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_create(zd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(zd.zone_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zone_root) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zone_privs) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zone_privssz) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.rctlbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.rctlbufsz) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zfsbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zfsbufsz) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.extended_error) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.match) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.doi) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.label) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.flags) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (create) 2s 19m
+---------------------------------------------------------
+Syscall param zone_create(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_create(zd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(zd.zone_name) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zone_root) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zone_privs) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zone_privssz) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.rctlbuf) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.rctlbufsz) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zfsbuf) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zfsbufsz) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.extended_error) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.match) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.doi) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.label) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.flags) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param zone(zd.zone_name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zone_root) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zone_privs) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.rctlbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.zfsbuf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(zd.label) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_DESTROY) 2s 0m
+---------------------------------------------------------
+Syscall param zone_destroy(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_destroy(zoneid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_GETATTR) 5s 1m
+---------------------------------------------------------
+Syscall param zone_getattr(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr(zoneid) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr(attr) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr(valp) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr(size) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(valp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_ENTER) 2s 0m
+---------------------------------------------------------
+Syscall param zone_enter(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_enter(zoneid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LIST) 3s 1m
+---------------------------------------------------------
+Syscall param zone_list(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list(zonelist) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list(numzones) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(numzones) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LIST) 3s 1m
+---------------------------------------------------------
+Syscall param zone_list(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list(zonelist) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list(numzones) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(zonelist) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_SHUTDOWN) 2s 0m
+---------------------------------------------------------
+Syscall param zone_shutdown(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_shutdown(zoneid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LOOKUP) 2s 1m
+---------------------------------------------------------
+Syscall param zone_lookup(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_lookup(name) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_BOOT) 2s 0m
+---------------------------------------------------------
+Syscall param zone_boot(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_boot(zoneid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_SETATTR) 5s 1m
+---------------------------------------------------------
+Syscall param zone_setattr(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_setattr(zoneid) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_setattr(attr) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_setattr(valp) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_setattr(size) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(valp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_DEL_DATALINK) 3s 0m
+---------------------------------------------------------
+Syscall param zone_del_datalink(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_del_datalink(zoneid) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_del_datalink(linkid) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LIST_DATALINK) 4s 1m
+---------------------------------------------------------
+Syscall param zone_list_datalink(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_datalink(zoneid) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_datalink(dlnump) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_datalink(linkids) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(dlnump) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+229:              SYS_getcwd 2s 1m
+---------------------------------------------------------
+Syscall param getcwd(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param getcwd(size) contains uninitialised byte(s)
+   ...
+
+Syscall param getcwd(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+230:           SYS_so_socket 5s 1m
+---------------------------------------------------------
+Syscall param socket(family) contains uninitialised byte(s)
+   ...
+
+Syscall param socket(type) contains uninitialised byte(s)
+   ...
+
+Syscall param socket(protocol) contains uninitialised byte(s)
+   ...
+
+Syscall param socket(devpath) contains uninitialised byte(s)
+   ...
+
+Syscall param socket(version) contains uninitialised byte(s)
+   ...
+
+Syscall param socket(devpath) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+231:       SYS_so_socketpair 1s 1m
+---------------------------------------------------------
+Syscall param socketpair(sv) contains uninitialised byte(s)
+   ...
+
+Syscall param socketpair(sv) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+232:                SYS_bind 4s 0m
+---------------------------------------------------------
+Syscall param bind(s) contains uninitialised byte(s)
+   ...
+
+Syscall param bind(name) contains uninitialised byte(s)
+   ...
+
+Syscall param bind(namelen) contains uninitialised byte(s)
+   ...
+
+Syscall param bind(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+233:              SYS_listen 3s 0m
+---------------------------------------------------------
+Syscall param listen(s) contains uninitialised byte(s)
+   ...
+
+Syscall param listen(backlog) contains uninitialised byte(s)
+   ...
+
+Syscall param listen(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+234:              SYS_accept 4s 0m
+---------------------------------------------------------
+Syscall param accept(s) contains uninitialised byte(s)
+   ...
+
+Syscall param accept(addr) contains uninitialised byte(s)
+   ...
+
+Syscall param accept(addrlen) contains uninitialised byte(s)
+   ...
+
+Syscall param accept(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+235:             SYS_connect 4s 0m
+---------------------------------------------------------
+Syscall param connect(s) contains uninitialised byte(s)
+   ...
+
+Syscall param connect(name) contains uninitialised byte(s)
+   ...
+
+Syscall param connect(namelen) contains uninitialised byte(s)
+   ...
+
+Syscall param connect(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+236:            SYS_shutdown 3s 0m
+---------------------------------------------------------
+Syscall param shutdown(sock) contains uninitialised byte(s)
+   ...
+
+Syscall param shutdown(how) contains uninitialised byte(s)
+   ...
+
+Syscall param shutdown(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+237:                SYS_recv 4s 1m
+---------------------------------------------------------
+Syscall param recv(s) contains uninitialised byte(s)
+   ...
+
+Syscall param recv(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param recv(len) contains uninitialised byte(s)
+   ...
+
+Syscall param recv(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.recv(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+238:            SYS_recvfrom 6s 1m
+---------------------------------------------------------
+Syscall param recvfrom(s) contains uninitialised byte(s)
+   ...
+
+Syscall param recvfrom(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param recvfrom(len) contains uninitialised byte(s)
+   ...
+
+Syscall param recvfrom(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param recvfrom(from) contains uninitialised byte(s)
+   ...
+
+Syscall param recvfrom(fromlen) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.recvfrom(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+239:             SYS_recvmsg 3s 0m
+---------------------------------------------------------
+Syscall param recvmsg(s) contains uninitialised byte(s)
+   ...
+
+Syscall param recvmsg(msg) contains uninitialised byte(s)
+   ...
+
+Syscall param recvmsg(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+240:                SYS_send 4s 1m
+---------------------------------------------------------
+Syscall param send(s) contains uninitialised byte(s)
+   ...
+
+Syscall param send(msg) contains uninitialised byte(s)
+   ...
+
+Syscall param send(len) contains uninitialised byte(s)
+   ...
+
+Syscall param send(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.send(msg) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+241:             SYS_sendmsg 3s 0m
+---------------------------------------------------------
+Syscall param sendmsg(s) contains uninitialised byte(s)
+   ...
+
+Syscall param sendmsg(msg) contains uninitialised byte(s)
+   ...
+
+Syscall param sendmsg(flags) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+242:              SYS_sendto 6s 1m
+---------------------------------------------------------
+Syscall param sendto(s) contains uninitialised byte(s)
+   ...
+
+Syscall param sendto(msg) contains uninitialised byte(s)
+   ...
+
+Syscall param sendto(len) contains uninitialised byte(s)
+   ...
+
+Syscall param sendto(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param sendto(to) contains uninitialised byte(s)
+   ...
+
+Syscall param sendto(tolen) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.sendto(msg) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+243:         SYS_getpeername 4s 1m
+---------------------------------------------------------
+Syscall param getpeername(s) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(name) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(namelen) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(version) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(namelen) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+243:         SYS_getpeername 4s 1m
+---------------------------------------------------------
+Syscall param getpeername(s) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(name) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(version) contains uninitialised byte(s)
+   ...
+
+Syscall param getpeername(namelen) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param getpeername(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+244:         SYS_getsockname 4s 1m
+---------------------------------------------------------
+Syscall param getsockname(s) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockname(name) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockname(namelen) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockname(version) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.getsockname(namelen_in) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+245:          SYS_getsockopt 6s 0m
+---------------------------------------------------------
+Syscall param getsockopt(s) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockopt(level) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockopt(optname) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockopt(optval) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockopt(option) contains uninitialised byte(s)
+   ...
+
+Syscall param getsockopt(version) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+246:          SYS_setsockopt 6s 1m
+---------------------------------------------------------
+Syscall param setsockopt(s) contains uninitialised byte(s)
+   ...
+
+Syscall param setsockopt(level) contains uninitialised byte(s)
+   ...
+
+Syscall param setsockopt(optname) contains uninitialised byte(s)
+   ...
+
+Syscall param setsockopt(optval) contains uninitialised byte(s)
+   ...
+
+Syscall param setsockopt(optlen) contains uninitialised byte(s)
+   ...
+
+Syscall param setsockopt(version) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.setsockopt(optval) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+252:  SYS_lwp_mutex_register 2s 1m
+---------------------------------------------------------
+Syscall param lwp_mutex_register(mp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_register(uaddr) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_mutex_register(mp->mutex_type) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+254:              SYS_uucopy 3s 2m
+---------------------------------------------------------
+Syscall param uucopy(s1) contains uninitialised byte(s)
+   ...
+
+Syscall param uucopy(s2) contains uninitialised byte(s)
+   ...
+
+Syscall param uucopy(n) contains uninitialised byte(s)
+   ...
+
+Syscall param uucopy(s1) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param uucopy(s2) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+255:             SYS_umount2 2s 1m
+---------------------------------------------------------
+Syscall param umount2(file) contains uninitialised byte(s)
+   ...
+
+Syscall param umount2(mflag) contains uninitialised byte(s)
+   ...
+
+Syscall param umount2(file) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  1:                SYS_exit 1s 0m
+---------------------------------------------------------
+Syscall param exit(status) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar.stdout.exp b/memcheck/tests/solaris/scalar.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar.stdout.exp
diff --git a/memcheck/tests/solaris/scalar.vgtest b/memcheck/tests/solaris/scalar.vgtest
new file mode 100644
index 0000000..20d2e6e
--- /dev/null
+++ b/memcheck/tests/solaris/scalar.vgtest
@@ -0,0 +1,10 @@
+prog: scalar
+vgopts: -q --error-limit=no --sim-hints=lax-doors
+stderr_filter: filter_scalar
+# Remove all frames from the stack trace except the first one.
+# This is important because syscall() function on x86 isn't ABI conformant
+# which confuses the Valgrind stack unwinder.
+# Therefore x86 and amd64 stack traces are unified so that they contain only
+# 'syscall (in libc)' stack frame and this is then filtered out completely.
+stderr_filter_args: libc
+
diff --git a/memcheck/tests/solaris/scalar_frealpathat.c b/memcheck/tests/solaris/scalar_frealpathat.c
new file mode 100644
index 0000000..7a4cd76
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_frealpathat.c
@@ -0,0 +1,17 @@
+/* Test for frealpathat syscall which is available on Solaris 11.1. */ 
+
+#include "scalar.h"
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_frealpathat           30 */
+   GO(SYS_frealpathat, "4s 2m");
+   SY(SYS_frealpathat, x0 - 1, x0 + 1, x0 + 2, x0 + 3); FAIL;
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_frealpathat.stderr.exp b/memcheck/tests/solaris/scalar_frealpathat.stderr.exp
new file mode 100644
index 0000000..aca2880
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_frealpathat.stderr.exp
@@ -0,0 +1,23 @@
+---------------------------------------------------------
+ 30:         SYS_frealpathat 4s 2m
+---------------------------------------------------------
+Syscall param frealpathat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param frealpathat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param frealpathat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param frealpathat(buflen) contains uninitialised byte(s)
+   ...
+
+Syscall param frealpathat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param frealpathat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_frealpathat.stdout.exp b/memcheck/tests/solaris/scalar_frealpathat.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_frealpathat.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_frealpathat.vgtest b/memcheck/tests/solaris/scalar_frealpathat.vgtest
new file mode 100644
index 0000000..8f535ae
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_frealpathat.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_frealpathat
+prog: scalar_frealpathat
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_ioctl.c b/memcheck/tests/solaris/scalar_ioctl.c
new file mode 100644
index 0000000..c11b326
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_ioctl.c
@@ -0,0 +1,337 @@
+/* Basic ioctl test. */
+
+#define __EXTENSIONS__ 1
+
+#include "scalar.h"
+
+#include <net/if.h>
+#include <sys/crypto/ioctl.h>
+#include <sys/dtrace.h>
+#include <sys/filio.h>
+#include <sys/stat.h>		/* for _ST_FSTYPSZ */
+#include <sys/mntio.h>
+#include <sys/mnttab.h>
+#include <sys/pool_impl.h>
+#include <sys/sockio.h>
+#include <sys/stropts.h>
+#include <sys/termios.h>
+
+/* pools */
+__attribute__((noinline))
+static void sys_ioctl_POOL_STATUSQ(void)
+{
+   GO(SYS_ioctl, "(POOL_STATUSQ) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + POOL_STATUSQ, x0); FAIL;
+}
+
+/* mntio */
+__attribute__((noinline))
+static void sys_ioctl_MNTIOC_GETMNTANY(void)
+{
+   GO(SYS_ioctl, "(MNTIOC_GETMNTANY) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + MNTIOC_GETMNTANY, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_MNTIOC_GETMNTANY_2(void)
+{
+   struct mntentbuf embuf;
+
+   embuf.mbuf_emp = (void *) (x0 + 1);
+   embuf.mbuf_buf = (void *) (x0 + 1);
+   embuf.mbuf_bufsize = x0 + 1;
+
+   GO(SYS_ioctl, "(MNTIOC_GETMNTANY) 4s 2m");
+   SY(SYS_ioctl, x0 - 1, x0 + MNTIOC_GETMNTANY, &embuf + x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_MNTIOC_GETMNTANY_3(void)
+{
+   struct mnttab mnt;
+   struct mntentbuf embuf;
+
+   mnt.mnt_special = (void *) (x0 + 1);
+   mnt.mnt_mountp = (void *) (x0 + 1);
+   mnt.mnt_fstype = (void *) (x0 + 1);
+   mnt.mnt_mntopts = (void *) (x0 + 1);
+   mnt.mnt_time = (void *) (x0 + 1);
+
+   embuf.mbuf_emp = x0 + (struct extmnttab *) &mnt;
+   embuf.mbuf_buf = (void *) (x0 + 1);
+   embuf.mbuf_bufsize = x0 + 1;
+
+   GO(SYS_ioctl, "(MNTIOC_GETMNTANY) 5s 6m");
+   SY(SYS_ioctl, x0 - 1, x0 + MNTIOC_GETMNTANY, &embuf + x0); FAIL;
+}
+
+/* termio/termios */
+__attribute__((noinline))
+static void sys_ioctl_TCGETA(void)
+{
+   GO(SYS_ioctl, "(TCGETA) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TCGETA, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TCGETS(void)
+{
+   GO(SYS_ioctl, "(TCGETS) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TCGETS, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TCSETS(void)
+{
+   GO(SYS_ioctl, "(TCSETS) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TCSETS, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TCSETSW(void)
+{
+   GO(SYS_ioctl, "(TCSETSW) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TCSETSW, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TCSETSF(void)
+{
+   GO(SYS_ioctl, "(TCSETSF) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TCSETSF, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCGWINSZ(void)
+{
+   GO(SYS_ioctl, "(TIOCGWINSZ) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCGWINSZ, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCSWINSZ(void)
+{
+   GO(SYS_ioctl, "(TIOCSWINSZ) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCSWINSZ, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCGPGRP(void)
+{
+   GO(SYS_ioctl, "(TIOCGPGRP) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCGPGRP, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCSPGRP(void)
+{
+   GO(SYS_ioctl, "(TIOCSPGRP) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCSPGRP, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCGSID(void)
+{
+   GO(SYS_ioctl, "(TIOCGSID) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCGSID, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCNOTTY(void)
+{
+   GO(SYS_ioctl, "(TIOCNOTTY) 2s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCNOTTY); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_TIOCSCTTY(void)
+{
+   GO(SYS_ioctl, "(TIOCSCTTY) 2s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + TIOCSCTTY); FAIL;
+}
+
+/* STREAMS */
+__attribute__((noinline))
+static void sys_ioctl_I_PUSH(void)
+{
+   GO(SYS_ioctl, "(I_PUSH) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_PUSH, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_I_STR(void)
+{
+   GO(SYS_ioctl, "(I_STR) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_STR, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_I_STR_2(void)
+{
+   struct strioctl str;
+
+   str.ic_cmd = x0;
+   str.ic_timout = x0;
+   str.ic_len = x0 + 1;
+   str.ic_dp = (void *) (x0 + 1);
+
+   GO(SYS_ioctl, "(I_STR) 4s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_STR, &str + x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_I_PEEK(void)
+{
+   GO(SYS_ioctl, "(I_PEEK) 3s 7m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_PEEK, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_I_PEEK_2(void)
+{
+   struct strpeek peek;
+
+   peek.ctlbuf.maxlen = x0 + 1;
+   peek.ctlbuf.len = x0;
+   peek.ctlbuf.buf = (void*)(x0 + 1);
+   peek.databuf.maxlen = x0 + 1;
+   peek.databuf.len = x0;
+   peek.databuf.buf = (void*)(x0 + 1);
+   peek.flags = x0;
+
+   GO(SYS_ioctl, "(I_PEEK) 3s 7m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_PEEK, &peek + x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_I_CANPUT(void)
+{
+   GO(SYS_ioctl, "(I_CANPUT) 3s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + I_CANPUT, x0); FAIL;
+}
+
+/* sockio */
+__attribute__((noinline))
+static void sys_ioctl_SIOCGLIFNUM(void)
+{
+   struct lifnum lifn;
+
+   lifn.lifn_family = x0;
+   lifn.lifn_flags = x0;
+
+   GO(SYS_ioctl, "(SIOCGLIFNUM) 4s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + SIOCGLIFNUM, &lifn + x0); FAIL;
+}
+
+/* filio */
+__attribute__((noinline))
+static void sys_ioctl_FIOSETOWN(void)
+{
+   pid_t pid;
+
+   GO(SYS_ioctl, "(FIOSETOWN) 4s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + FIOSETOWN, &pid + x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_FIOGETOWN(void)
+{
+   GO(SYS_ioctl, "(FIOGETOWN) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + FIOGETOWN, x0 + 1); FAIL;
+}
+
+/* crypto */
+__attribute__((noinline))
+static void sys_ioctl_CRYPTO_GET_PROVIDER_LIST(void)
+{
+   GO(SYS_ioctl, "(CRYPTO_GET_PROVIDER_LIST) 3s 1m");
+   SY(SYS_ioctl, x0 - 1, x0 + CRYPTO_GET_PROVIDER_LIST, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_CRYPTO_GET_PROVIDER_LIST_2(void)
+{
+   crypto_get_provider_list_t pl;
+
+   pl.pl_count = x0 + 1;
+
+   GO(SYS_ioctl, "(CRYPTO_GET_PROVIDER_LIST) 4s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + CRYPTO_GET_PROVIDER_LIST, &pl + x0); FAIL;
+}
+
+/* dtrace */
+__attribute__((noinline))
+static void sys_ioctl_DTRACEHIOC_REMOVE(void)
+{
+   GO(SYS_ioctl, "(DTRACEHIOC_REMOVE) 3s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + DTRACEHIOC_REMOVE, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_ioctl_DTRACEHIOC_ADDDOF(void)
+{
+   dof_helper_t dh;
+
+   dh.dofhp_mod[0] = x0 + 'D';
+   dh.dofhp_mod[1] = x0 + '\0';
+   dh.dofhp_addr = x0;
+   dh.dofhp_dof = x0;
+
+   GO(SYS_ioctl, "(DTRACEHIOC_ADDDOF) 6s 0m");
+   SY(SYS_ioctl, x0 - 1, x0 + DTRACEHIOC_ADDDOF, x0 + &dh); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* pools */
+   sys_ioctl_POOL_STATUSQ();
+
+   /* mntio */
+   sys_ioctl_MNTIOC_GETMNTANY();
+   sys_ioctl_MNTIOC_GETMNTANY_2();
+   sys_ioctl_MNTIOC_GETMNTANY_3();
+
+   /* termio/termios */
+   sys_ioctl_TCGETA();
+   sys_ioctl_TCGETS();
+   sys_ioctl_TCSETS();
+   sys_ioctl_TCSETSW();
+   sys_ioctl_TCSETSF();
+   sys_ioctl_TIOCGWINSZ();
+   sys_ioctl_TIOCSWINSZ();
+   sys_ioctl_TIOCGPGRP();
+   sys_ioctl_TIOCSPGRP();
+   sys_ioctl_TIOCGSID();
+   sys_ioctl_TIOCNOTTY();
+   sys_ioctl_TIOCSCTTY();
+
+   /* STREAMS */
+   sys_ioctl_I_PUSH();
+   sys_ioctl_I_STR();
+   sys_ioctl_I_STR_2();
+   sys_ioctl_I_PEEK();
+   sys_ioctl_I_PEEK_2();
+   sys_ioctl_I_CANPUT();
+
+   /* sockio */
+   sys_ioctl_SIOCGLIFNUM();
+
+   /* filio */
+   sys_ioctl_FIOSETOWN();
+   sys_ioctl_FIOGETOWN();
+
+   /* crypto */
+   sys_ioctl_CRYPTO_GET_PROVIDER_LIST();
+   sys_ioctl_CRYPTO_GET_PROVIDER_LIST_2();
+
+   /* dtrace */
+   sys_ioctl_DTRACEHIOC_REMOVE();
+   sys_ioctl_DTRACEHIOC_ADDDOF();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_ioctl.stderr.exp b/memcheck/tests/solaris/scalar_ioctl.stderr.exp
new file mode 100644
index 0000000..d9bdceb
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_ioctl.stderr.exp
@@ -0,0 +1,545 @@
+---------------------------------------------------------
+ 54:               SYS_ioctl (POOL_STATUSQ) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(POOL_STATUSQ) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (MNTIOC_GETMNTANY) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(MNTIOC_GETMNTANY) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (MNTIOC_GETMNTANY) 4s 2m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(MNTIOC_GETMNTANY) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(MNTIOC_GETMNTANY, embuf->mbuf_emp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, embuf->mbuf_buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (MNTIOC_GETMNTANY) 5s 6m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(MNTIOC_GETMNTANY) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(MNTIOC_GETMNTANY, embuf->mbuf_emp) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(MNTIOC_GETMNTANY, embuf->mbuf_buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, mnt->mnt_special) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, mnt->mnt_mountp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, mnt->mnt_fstype) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, mnt->mnt_mntopts) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(MNTIOC_GETMNTANY, mnt->mnt_time) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TCGETA) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCGETA) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TCGETS) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCGETS) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TCSETS) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCSETS) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TCSETSW) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCSETSW) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TCSETSF) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TCSETSF) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCGWINSZ) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TIOCGWINSZ) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCSWINSZ) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TIOCSWINSZ) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCGPGRP) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TIOCGPGRP) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCSPGRP) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TIOCSPGRP) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCGSID) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(TIOCGSID) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCNOTTY) 2s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (TIOCSCTTY) 2s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_PUSH) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(I_PUSH) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_STR) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(I_STR) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_STR) 4s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(I_STR) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(I_STR, strioctl->ic_dp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_PEEK) 3s 7m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.maxlen) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.maxlen) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.len) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->flags) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_PEEK) 3s 7m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.maxlen) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.buf) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.maxlen) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.buf) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(I_PEEK, strpeek->flags) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+
+More than 100 errors detected.  Subsequent errors
+will still be recorded, but in less detail than before.
+Syscall param ioctl(I_PEEK, strpeek->ctlbuf.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param ioctl(I_PEEK, strpeek->databuf.buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (I_CANPUT) 3s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (SIOCGLIFNUM) 4s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(SIOCGLIFNUM, lifn->lifn_family) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(SIOCGLIFNUM, lifn->lifn_flags) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (FIOSETOWN) 4s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(FIOSETOWN) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (FIOGETOWN) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(FIOGETOWN) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (CRYPTO_GET_PROVIDER_LIST) 3s 1m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(CRYPTO_GET_PROVIDER_LIST, pl->pl_count) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (CRYPTO_GET_PROVIDER_LIST) 4s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(CRYPTO_GET_PROVIDER_LIST, pl->pl_count) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (DTRACEHIOC_REMOVE) 3s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 54:               SYS_ioctl (DTRACEHIOC_ADDDOF) 6s 0m
+---------------------------------------------------------
+Syscall param ioctl(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(request) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(arg) contains uninitialised byte(s)
+   ...
+
+Syscall param ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_mod) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_addr points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param ioctl(DTRACEHIOC_ADDDOF, dh->dofhp_dof points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
diff --git a/memcheck/tests/solaris/scalar_ioctl.stdout.exp b/memcheck/tests/solaris/scalar_ioctl.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_ioctl.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_ioctl.vgtest b/memcheck/tests/solaris/scalar_ioctl.vgtest
new file mode 100644
index 0000000..3c85607
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_ioctl.vgtest
@@ -0,0 +1,4 @@
+prog: scalar_ioctl
+vgopts: -q --error-limit=no
+stderr_filter: filter_scalar
+stderr_filter_args: libc
diff --git a/memcheck/tests/solaris/scalar_lwp_kill.c b/memcheck/tests/solaris/scalar_lwp_kill.c
new file mode 100644
index 0000000..929f5cf
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_kill.c
@@ -0,0 +1,20 @@
+/* Test for lwp_kill syscall which is available on illumos
+   and Solaris 11 and 11.1. This syscall has been renamed
+   on Solaris 11.2 to lwp_sigqueue and extra parameters added.
+ */
+
+#include "scalar.h"
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_lwp_kill              163 */
+   GO(SYS_lwp_kill, "2s 0m");
+   SY(SYS_lwp_kill, x0 - 1, x0); FAIL;
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_lwp_kill.stderr.exp b/memcheck/tests/solaris/scalar_lwp_kill.stderr.exp
new file mode 100644
index 0000000..f802402
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_kill.stderr.exp
@@ -0,0 +1,9 @@
+---------------------------------------------------------
+163:            SYS_lwp_kill 2s 0m
+---------------------------------------------------------
+Syscall param lwp_kill(target_lwp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_kill(signal) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_lwp_kill.stdout.exp b/memcheck/tests/solaris/scalar_lwp_kill.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_kill.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_lwp_kill.vgtest b/memcheck/tests/solaris/scalar_lwp_kill.vgtest
new file mode 100644
index 0000000..9b26d9e
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_kill.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_lwp_kill
+prog: scalar_lwp_kill
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_lwp_name.c b/memcheck/tests/solaris/scalar_lwp_name.c
new file mode 100644
index 0000000..54ec2c2
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_name.c
@@ -0,0 +1,31 @@
+/* Test for lwp_name syscall which is available on newer Solaris. */ 
+
+#include "scalar.h"
+
+__attribute__((noinline))
+static void sys_lwp_name(void)
+{
+   GO(SYS_lwp_name, "(lwp_setname) 3s 1m");
+   SY(SYS_lwp_name, x0 + 0, x0, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_lwp_name2(void)
+{  
+   GO(SYS_lwp_name, "(lwp_getname) 4s 1m");
+   SY(SYS_lwp_name, x0 + 1, x0, x0 + 1, x0 + 2); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_lwp_name              79 */
+   sys_lwp_name();
+   sys_lwp_name2();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_lwp_name.stderr.exp b/memcheck/tests/solaris/scalar_lwp_name.stderr.exp
new file mode 100644
index 0000000..7a16583
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_name.stderr.exp
@@ -0,0 +1,35 @@
+---------------------------------------------------------
+ 79:            SYS_lwp_name (lwp_setname) 3s 1m
+---------------------------------------------------------
+Syscall param lwp_name(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(lwpid) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(name) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 79:            SYS_lwp_name (lwp_getname) 4s 1m
+---------------------------------------------------------
+Syscall param lwp_name(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(lwpid) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(name) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(len) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_name(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_lwp_name.stdout.exp b/memcheck/tests/solaris/scalar_lwp_name.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_name.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_lwp_name.vgtest b/memcheck/tests/solaris/scalar_lwp_name.vgtest
new file mode 100644
index 0000000..50ce4ff
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_name.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_lwp_name
+prog: scalar_lwp_name
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue.c b/memcheck/tests/solaris/scalar_lwp_sigqueue.c
new file mode 100644
index 0000000..26a29af
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue.c
@@ -0,0 +1,19 @@
+/* Test for lwp_sigqueue syscall which is available since
+   Solaris 11.2.
+ */
+
+#include "scalar.h"
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_lwp_sigqueue          163 */
+   GO(SYS_lwp_sigqueue, "5s 1m");
+   SY(SYS_lwp_sigqueue, x0 - 1, x0, x0 + 1, x0, x0 - 1); FAIL;
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue.stderr.exp b/memcheck/tests/solaris/scalar_lwp_sigqueue.stderr.exp
new file mode 100644
index 0000000..363100a
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue.stderr.exp
@@ -0,0 +1,22 @@
+---------------------------------------------------------
+163:        SYS_lwp_sigqueue 5s 1m
+---------------------------------------------------------
+Syscall param lwp_sigqueue(target_lwp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(signal) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(value) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(si_code) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue.stdout.exp b/memcheck/tests/solaris/scalar_lwp_sigqueue.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue.vgtest b/memcheck/tests/solaris/scalar_lwp_sigqueue.vgtest
new file mode 100644
index 0000000..01be952
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_lwp_sigqueue
+prog: scalar_lwp_sigqueue
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.c b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.c
new file mode 100644
index 0000000..2e0fef0
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.c
@@ -0,0 +1,19 @@
+/* Test for lwp_sigqueue syscall which accepts pid along the thread id.
+   Available since Solaris 12.
+ */
+
+#include "scalar.h"
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_lwp_sigqueue          163 */
+   GO(SYS_lwp_sigqueue, "6s 1m");
+   SY(SYS_lwp_sigqueue, x0 - 1, x0 - 1, x0, x0 + 1, x0, x0 - 1); FAIL;
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.stderr.exp b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.stderr.exp
new file mode 100644
index 0000000..56dfe0a
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.stderr.exp
@@ -0,0 +1,25 @@
+---------------------------------------------------------
+163:        SYS_lwp_sigqueue 6s 1m
+---------------------------------------------------------
+Syscall param lwp_sigqueue(target_pid) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(target_lwp) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(signal) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(value) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(si_code) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(timeout) contains uninitialised byte(s)
+   ...
+
+Syscall param lwp_sigqueue(timeout) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.vgtest b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.vgtest
new file mode 100644
index 0000000..c056c34
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_lwp_sigqueue_pid.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_lwp_sigqueue_pid
+prog: scalar_lwp_sigqueue_pid
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_obsolete.c b/memcheck/tests/solaris/scalar_obsolete.c
new file mode 100644
index 0000000..ea03027
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_obsolete.c
@@ -0,0 +1,113 @@
+/* Test for syscalls that are available on illumos but are removed on
+   Solaris 11.  This test is compiled only on illumos. */
+
+#include "scalar.h"
+
+#include <sys/fcntl.h>
+
+__attribute__((noinline))
+static void sys_open(void)
+{
+   GO(SYS_open, "(2-args) 2s 1m");
+   SY(SYS_open, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_open2(void)
+{
+   GO(SYS_open, "(3-args) 3s 1m");
+   SY(SYS_open, x0, x0 | O_CREAT, x0); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_open                    5 */
+   sys_open();
+   sys_open2();
+
+   /* SYS_link                    9 */
+   GO(SYS_link, "2s 2m");
+   SY(SYS_link, x0, x0); FAIL;
+
+   /* SYS_unlink                 10 */
+   GO(SYS_unlink, "1s 1m");
+   SY(SYS_unlink, x0); FAIL;
+
+   /* SYS_mknod                  14 */
+   /* XXX Missing wrapper. */
+
+   /* SYS_chmod                  15 */
+   GO(SYS_chmod, "2s 1m");
+   SY(SYS_chmod, x0, x0); FAIL;
+
+   /* SYS_chown                  16 */
+   GO(SYS_chown, "3s 1m");
+   SY(SYS_chown, x0, x0, x0); FAIL;
+
+   /* SYS_stat                   18 */
+   GO(SYS_stat, "2s 2m");
+   SY(SYS_stat, x0, x0); FAIL;
+
+   /* SYS_fstat                  28 */
+   GO(SYS_fstat, "2s 1m");
+   SY(SYS_fstat, x0, x0); FAIL;
+
+   /* SYS_access                 33 */
+   GO(SYS_access, "2s 1m");
+   SY(SYS_access, x0, x0); FAIL;
+
+   /* SYS_rmdir                  79 */
+   GO(SYS_rmdir, "1s 1m");
+   SY(SYS_rmdir, x0); FAIL;
+
+   /* SYS_mkdir                  80 */
+   GO(SYS_mkdir, "2s 1m");
+   SY(SYS_mkdir, x0, x0); FAIL;
+
+   /* SYS_lstat                  88 */
+   GO(SYS_lstat, "2s 2m");
+   SY(SYS_lstat, x0, x0); FAIL;
+
+   /* SYS_symlink                89 */
+   GO(SYS_symlink, "2s 2m");
+   SY(SYS_symlink, x0, x0); FAIL;
+
+   /* SYS_readlink               90 */
+   GO(SYS_readlink, "3s 2m");
+   SY(SYS_readlink, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_fchmod                 93 */
+   GO(SYS_fchmod, "2s 0m");
+   SY(SYS_fchmod, x0 - 1, x0); FAIL;
+
+   /* SYS_fchown                 94 */
+   GO(SYS_fchown, "3s 0m");
+   SY(SYS_fchown, x0, x0, x0); FAIL;
+
+   /* SYS_lchown                130 */
+   GO(SYS_lchown, "3s 1m");
+   SY(SYS_lchown, x0, x0, x0); FAIL;
+
+   /* SYS_rename                134 */
+   GO(SYS_rename, "2s 2m");
+   SY(SYS_rename, x0, x0); FAIL;
+
+   /* SYS_stat64                215 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_lstat64               216 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_fstat64               217 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_open64                225 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_obsolete.stderr.exp b/memcheck/tests/solaris/scalar_obsolete.stderr.exp
new file mode 100644
index 0000000..ae2e594
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_obsolete.stderr.exp
@@ -0,0 +1,259 @@
+---------------------------------------------------------
+  5:                SYS_open (2-args) 2s 1m
+---------------------------------------------------------
+Syscall param open(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param open(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param open(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  5:                SYS_open (3-args) 3s 1m
+---------------------------------------------------------
+Syscall param open(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param open(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param open(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param open(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  9:                SYS_link 2s 2m
+---------------------------------------------------------
+Syscall param link(oldpath) contains uninitialised byte(s)
+   ...
+
+Syscall param link(newpath) contains uninitialised byte(s)
+   ...
+
+Syscall param link(oldpath) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param link(newpath) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 10:              SYS_unlink 1s 1m
+---------------------------------------------------------
+Syscall param unlink(pathname) contains uninitialised byte(s)
+   ...
+
+Syscall param unlink(pathname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 15:               SYS_chmod 2s 1m
+---------------------------------------------------------
+Syscall param chmod(path) contains uninitialised byte(s)
+   ...
+
+Syscall param chmod(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param chmod(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 16:               SYS_chown 3s 1m
+---------------------------------------------------------
+Syscall param chown(path) contains uninitialised byte(s)
+   ...
+
+Syscall param chown(owner) contains uninitialised byte(s)
+   ...
+
+Syscall param chown(group) contains uninitialised byte(s)
+   ...
+
+Syscall param chown(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 18:                SYS_stat 2s 2m
+---------------------------------------------------------
+Syscall param stat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param stat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param stat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param stat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 28:               SYS_fstat 2s 1m
+---------------------------------------------------------
+Syscall param fstat(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fstat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 33:              SYS_access 2s 1m
+---------------------------------------------------------
+Syscall param access(pathname) contains uninitialised byte(s)
+   ...
+
+Syscall param access(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param access(pathname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 79:               SYS_rmdir 1s 1m
+---------------------------------------------------------
+Syscall param rmdir(pathname) contains uninitialised byte(s)
+   ...
+
+Syscall param rmdir(pathname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 80:               SYS_mkdir 2s 1m
+---------------------------------------------------------
+Syscall param mkdir(pathname) contains uninitialised byte(s)
+   ...
+
+Syscall param mkdir(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param mkdir(pathname) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 88:               SYS_lstat 2s 2m
+---------------------------------------------------------
+Syscall param lstat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param lstat(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param lstat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lstat(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 89:             SYS_symlink 2s 2m
+---------------------------------------------------------
+Syscall param symlink(oldpath) contains uninitialised byte(s)
+   ...
+
+Syscall param symlink(newpath) contains uninitialised byte(s)
+   ...
+
+Syscall param symlink(oldpath) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param symlink(newpath) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 90:            SYS_readlink 3s 2m
+---------------------------------------------------------
+Syscall param readlink(path) contains uninitialised byte(s)
+   ...
+
+Syscall param readlink(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param readlink(bufsiz) contains uninitialised byte(s)
+   ...
+
+Syscall param readlink(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param readlink(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 93:              SYS_fchmod 2s 0m
+---------------------------------------------------------
+Syscall param fchmod(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fchmod(mode) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+ 94:              SYS_fchown 3s 0m
+---------------------------------------------------------
+Syscall param fchown(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fchown(owner) contains uninitialised byte(s)
+   ...
+
+Syscall param fchown(group) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+130:              SYS_lchown 3s 1m
+---------------------------------------------------------
+Syscall param lchown(path) contains uninitialised byte(s)
+   ...
+
+Syscall param lchown(owner) contains uninitialised byte(s)
+   ...
+
+Syscall param lchown(group) contains uninitialised byte(s)
+   ...
+
+Syscall param lchown(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+134:              SYS_rename 2s 2m
+---------------------------------------------------------
+Syscall param rename(from) contains uninitialised byte(s)
+   ...
+
+Syscall param rename(to) contains uninitialised byte(s)
+   ...
+
+Syscall param rename(from) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param rename(to) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_obsolete.stdout.exp b/memcheck/tests/solaris/scalar_obsolete.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_obsolete.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_obsolete.vgtest b/memcheck/tests/solaris/scalar_obsolete.vgtest
new file mode 100644
index 0000000..4541cb9
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_obsolete.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_obsolete
+prog: scalar_obsolete
+vgopts: -q --error-limit=no
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_shm_new.c b/memcheck/tests/solaris/scalar_shm_new.c
new file mode 100644
index 0000000..b2552d7
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_shm_new.c
@@ -0,0 +1,50 @@
+/* Scalar test for new shmsys syscall subcodes available on Solaris 11. */
+
+#include "scalar.h"
+
+#include <sys/shm.h>
+#include <sys/shm_impl.h>
+
+__attribute__((noinline))
+static void sys_shmsys(void)
+{
+   GO(SYS_shmsys, "(SHMCTL,IPC_XSTAT64) 4s 1m");
+   SY(SYS_shmsys, x0 + SHMCTL, x0, x0 + IPC_XSTAT64, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys2(void)
+{
+   GO(SYS_shmsys, "(SHMADV,SHM_ADV_GET) 4s 1m");
+   SY(SYS_shmsys, x0 + SHMADV, x0, x0 + SHM_ADV_GET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys3(void)
+{
+   GO(SYS_shmsys, "(SHMADV,SHM_ADV_SET) 4s 1m");
+   SY(SYS_shmsys, x0 + SHMADV, x0, x0 + SHM_ADV_SET, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_shmsys4(void)
+{
+   GO(SYS_shmsys, "(SHMGET_OSM) 5s 0m");
+   SY(SYS_shmsys, x0 + SHMGET_OSM, x0, x0, x0, x0); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_shmsys                 52 */
+   sys_shmsys();
+   sys_shmsys2();
+   sys_shmsys3();
+   sys_shmsys4();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_shm_new.stderr.exp b/memcheck/tests/solaris/scalar_shm_new.stderr.exp
new file mode 100644
index 0000000..6669040
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_shm_new.stderr.exp
@@ -0,0 +1,75 @@
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMCTL,IPC_XSTAT64) 4s 1m
+---------------------------------------------------------
+Syscall param shmsys_shmctl_xstat64(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_xstat64(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_xstat64(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmctl_xstat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmctl, ipc_xstat64, buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMADV,SHM_ADV_GET) 4s 1m
+---------------------------------------------------------
+Syscall param shmsys_shmadv(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(advice) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmadv, advice) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMADV,SHM_ADV_SET) 4s 1m
+---------------------------------------------------------
+Syscall param shmsys_shmadv(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(shmid) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmadv(advice) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys(shmadv, advice) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 52:              SYS_shmsys (SHMGET_OSM) 5s 0m
+---------------------------------------------------------
+Syscall param shmsys_shmget_osm(opcode) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget_osm(key) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget_osm(size) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget_osm(shmflg) contains uninitialised byte(s)
+   ...
+
+Syscall param shmsys_shmget_osm(granule_sz) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_shm_new.stdout.exp b/memcheck/tests/solaris/scalar_shm_new.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_shm_new.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_shm_new.vgtest b/memcheck/tests/solaris/scalar_shm_new.vgtest
new file mode 100644
index 0000000..ada1807
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_shm_new.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_shm_new
+prog: scalar_shm_new
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_spawn.c b/memcheck/tests/solaris/scalar_spawn.c
new file mode 100644
index 0000000..401b56e
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_spawn.c
@@ -0,0 +1,72 @@
+/* Scalar test for new spawn syscall available on Solaris 11. */
+
+#include "scalar.h"
+
+#include <sys/spawn_impl.h>
+
+__attribute__((noinline))
+static void sys_spawn(void)
+{
+   GO(SYS_spawn, "5s 7m");
+   SY(SYS_spawn, x0 + 1, x0 + 1, x0 - 1, x0 + 1, x0 - 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_spawn2(void)
+{
+   kspawn_attr_t ksa;
+   ksa.ksa_version = x0 + SPAWN_VERSION;
+   ksa.ksa_size = x0 + sizeof(ksa);
+   ksa.ksa_attr_off = x0 + 0;
+   ksa.ksa_path_off = x0 + 0;
+   ksa.ksa_shell_off = x0 + 0;
+   char *argenv = "";
+
+   GO(SYS_spawn, "9s 1m");
+   SY(SYS_spawn, x0 + 1, x0 + &ksa, sizeof(ksa), x0 + argenv, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_spawn3(void)
+{
+   kspawn_attr_t ksa;
+   ksa.ksa_version = x0 + SPAWN_VERSION;
+   ksa.ksa_size = x0 + 0xbadcaffe;
+   ksa.ksa_attr_off = x0 + 0xbadcaffe;
+   ksa.ksa_attr_size = x0 + 1;
+   ksa.ksa_path_off = x0 + 0xdeadcaffe;
+   ksa.ksa_path_size = x0 + 2;
+   ksa.ksa_shell_off = x0 + 0xdeadcaffe;
+   ksa.ksa_shell_size = x0 + 3;
+   char *argenv = "\1arg1\0\1arg2\0\1arg3\0\0\1env1\0\1env2\0\0";
+
+   GO(SYS_spawn, "13s 4m");
+   SY(SYS_spawn, x0 + 1, x0 + &ksa, x0 + 0xbadcaffe,
+      x0 + argenv, x0 + sizeof(argenv)); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_spawn4(void)
+{
+   char path[] = "/bin/sh";
+   char *argenv = "\2arg1\0\0";
+
+   GO(SYS_spawn, "4s 0m");
+   SY(SYS_spawn, path, x0, x0, x0 + argenv, x0 + sizeof(argenv));
+   FAILx(EINVAL);
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_spawn                   2 */
+   sys_spawn();
+   sys_spawn2();
+   sys_spawn3();
+   sys_spawn4();
+
+   return 0;
+}
diff --git a/memcheck/tests/solaris/scalar_spawn.stderr.exp b/memcheck/tests/solaris/scalar_spawn.stderr.exp
new file mode 100644
index 0000000..126c429
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_spawn.stderr.exp
@@ -0,0 +1,166 @@
+---------------------------------------------------------
+  2:               SYS_spawn 5s 7m
+---------------------------------------------------------
+Syscall param spawn(path) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrs) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrsize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(argenv) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(aesize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_version) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_size) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_attr_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_path_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_shell_off) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(argenv) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  2:               SYS_spawn 9s 1m
+---------------------------------------------------------
+Syscall param spawn(path) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrs) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(argenv) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(aesize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_version) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_attr_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_path_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_shell_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+---------------------------------------------------------
+  2:               SYS_spawn 13s 4m
+---------------------------------------------------------
+Syscall param spawn(path) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrs) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrsize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(argenv) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(aesize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_version) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_attr_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_path_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_shell_off) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_attr_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_attr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_path_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param spawn(attrs->ksa_shell_size) points to uninitialised byte(s)
+   ...
+ Address 0x........ is on thread 1's stack
+
+Syscall param spawn(attrs->ksa_shell) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+  2:               SYS_spawn 4s 0m
+---------------------------------------------------------
+Syscall param spawn(attrs) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(attrsize) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(argenv) contains uninitialised byte(s)
+   ...
+
+Syscall param spawn(aesize) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_spawn.stdout.exp b/memcheck/tests/solaris/scalar_spawn.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_spawn.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_spawn.vgtest b/memcheck/tests/solaris/scalar_spawn.vgtest
new file mode 100644
index 0000000..c5918b8
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_spawn.vgtest
@@ -0,0 +1,6 @@
+prereq: test -e scalar_spawn
+prog: scalar_spawn
+vgopts: -q
+stderr_filter: filter_scalar
+# See comment in scalar.vgtest.
+stderr_filter_args: libc
diff --git a/memcheck/tests/solaris/scalar_tsol_clearance.c b/memcheck/tests/solaris/scalar_tsol_clearance.c
new file mode 100644
index 0000000..7b75559
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_tsol_clearance.c
@@ -0,0 +1,75 @@
+/* Scalar test for new labelsys syscall subcodes TSOL_GETCLEARANCE
+   and TSOL_SETCLEARANCE available on Solaris 11. */
+
+#include "scalar.h"
+
+#include <sys/syscall.h>
+#include <sys/tsol/tsyscall.h>
+#include <tsol/label.h>
+
+__attribute__((noinline))
+static void sys_labelsys(void)
+{
+   GO(SYS_labelsys, "(TSOL_GETCLEARANCE) 2s 1m");
+   SY(SYS_labelsys, x0 + TSOL_GETCLEARANCE, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys2(void)
+{
+   m_label_t *label = m_label_alloc(USER_CLEAR);
+   if (label == NULL) {
+      perror("m_label_alloc");
+      return;
+   }
+
+   GO(SYS_labelsys, "(TSOL_GETCLEARANCE) 1s 0m");
+   SY(SYS_labelsys, x0 + TSOL_GETCLEARANCE, label); SUCC;
+
+   m_label_free(label);
+}
+
+__attribute__((noinline))
+static void sys_labelsys3(void)
+{
+   GO(SYS_labelsys, "(TSOL_SETCLEARANCE) 2s 1m");
+   SY(SYS_labelsys, x0 + TSOL_SETCLEARANCE, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_labelsys4(void)
+{
+   m_label_t *label = m_label_alloc(USER_CLEAR);
+   if (label == NULL) {
+      perror("m_label_alloc");
+      return;
+   }
+
+   int ret = getclearance(label);
+   if (ret != 0) {
+      perror("getclearance");
+      m_label_free(label);
+      return;
+   }
+
+   GO(SYS_labelsys, "(TSOL_SETCLEARANCE) 1s 0m");
+   SY(SYS_labelsys, x0 + TSOL_SETCLEARANCE, label); SUCC;
+
+   m_label_free(label);
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_labelsys                52 */
+   sys_labelsys();
+   sys_labelsys2();
+   sys_labelsys3();
+   sys_labelsys4();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_tsol_clearance.stderr.exp b/memcheck/tests/solaris/scalar_tsol_clearance.stderr.exp
new file mode 100644
index 0000000..286f9c0
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_tsol_clearance.stderr.exp
@@ -0,0 +1,38 @@
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_GETCLEARANCE) 2s 1m
+---------------------------------------------------------
+Syscall param labelsys_getclearance(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_getclearance(clearance) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(clearance) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_GETCLEARANCE) 1s 0m
+---------------------------------------------------------
+Syscall param labelsys_getclearance(op) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_SETCLEARANCE) 2s 1m
+---------------------------------------------------------
+Syscall param labelsys_setclearance(op) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys_setclearance(clearance) contains uninitialised byte(s)
+   ...
+
+Syscall param labelsys(clearance) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+184:            SYS_labelsys (TSOL_SETCLEARANCE) 1s 0m
+---------------------------------------------------------
+Syscall param labelsys_setclearance(op) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_tsol_clearance.vgtest b/memcheck/tests/solaris/scalar_tsol_clearance.vgtest
new file mode 100644
index 0000000..977e28a
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_tsol_clearance.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_tsol_clearance
+prog: scalar_tsol_clearance
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_utimensat.c b/memcheck/tests/solaris/scalar_utimensat.c
new file mode 100644
index 0000000..594a5c9
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimensat.c
@@ -0,0 +1,31 @@
+/* Test for utimensat() syscall which is available on newer Solaris. */ 
+
+#include "scalar.h"
+
+__attribute__((noinline))
+static void sys_utimensat(void)
+{
+   GO(SYS_utimensat, "4s 2m");
+   SY(SYS_utimensat, x0 - 1, x0 + 1, x0 + 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_utimensat2(void)
+{
+   GO(SYS_utimensat, "4s 0m");
+   SY(SYS_utimensat, x0 - 1, x0 + NULL, x0 + NULL, x0); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_utimensat            110 */
+   sys_utimensat();
+   sys_utimensat2();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_utimensat.stderr.exp b/memcheck/tests/solaris/scalar_utimensat.stderr.exp
new file mode 100644
index 0000000..4b93d30
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimensat.stderr.exp
@@ -0,0 +1,38 @@
+---------------------------------------------------------
+110:           SYS_utimensat 4s 2m
+---------------------------------------------------------
+Syscall param utimensat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(times) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param utimensat(times) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+110:           SYS_utimensat 4s 0m
+---------------------------------------------------------
+Syscall param utimensat(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(path) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(times) contains uninitialised byte(s)
+   ...
+
+Syscall param utimensat(flag) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_utimensat.stdout.exp b/memcheck/tests/solaris/scalar_utimensat.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimensat.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_utimensat.vgtest b/memcheck/tests/solaris/scalar_utimensat.vgtest
new file mode 100644
index 0000000..788f7ea
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimensat.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_utimensat
+prog: scalar_utimensat
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_utimesys.c b/memcheck/tests/solaris/scalar_utimesys.c
new file mode 100644
index 0000000..3591d82
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimesys.c
@@ -0,0 +1,49 @@
+/* Test for utimesys() syscall which is available on illumos
+   and older Solaris.
+ */
+
+#include "scalar.h"
+
+__attribute__((noinline))
+static void sys_utimesys(void)
+{
+   GO(SYS_utimesys, "(FUTIMENS) 3s 1m");
+   SY(SYS_utimesys, x0 + 0, x0 - 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_utimesys2(void)
+{
+   GO(SYS_utimesys, "(FUTIMENS) 3s 0m");
+   SY(SYS_utimesys, x0 + 0, x0 - 1, x0 + NULL); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_utimesys3(void)
+{
+   GO(SYS_utimesys, "(UTIMENSAT) 5s 2m");
+   SY(SYS_utimesys, x0 + 1, x0 - 1, x0 + 1, x0 + 1, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_utimesys4(void)
+{
+   GO(SYS_utimesys, "(UTIMENSAT) 5s 0m");
+   SY(SYS_utimesys, x0 + 1, x0 - 1, x0 + NULL, x0 + NULL, x0); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_utimesys             110 */
+   sys_utimesys();
+   sys_utimesys2();
+   sys_utimesys3();
+   sys_utimesys4();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_utimesys.stderr.exp b/memcheck/tests/solaris/scalar_utimesys.stderr.exp
new file mode 100644
index 0000000..5bc76e4
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimesys.stderr.exp
@@ -0,0 +1,72 @@
+---------------------------------------------------------
+110:            SYS_utimesys (FUTIMENS) 3s 1m
+---------------------------------------------------------
+Syscall param utimesys(code) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(times) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(times) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+110:            SYS_utimesys (FUTIMENS) 3s 0m
+---------------------------------------------------------
+Syscall param utimesys(code) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(times) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+110:            SYS_utimesys (UTIMENSAT) 5s 2m
+---------------------------------------------------------
+Syscall param utimesys(code) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(path) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(times) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param utimesys(times) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+110:            SYS_utimesys (UTIMENSAT) 5s 0m
+---------------------------------------------------------
+Syscall param utimesys(code) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(path) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(times) contains uninitialised byte(s)
+   ...
+
+Syscall param utimesys(flag) contains uninitialised byte(s)
+   ...
+
diff --git a/memcheck/tests/solaris/scalar_utimesys.stdout.exp b/memcheck/tests/solaris/scalar_utimesys.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimesys.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_utimesys.vgtest b/memcheck/tests/solaris/scalar_utimesys.vgtest
new file mode 100644
index 0000000..e8e252d
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_utimesys.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_utimesys
+prog: scalar_utimesys
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_uuidsys.c b/memcheck/tests/solaris/scalar_uuidsys.c
new file mode 100644
index 0000000..fb6abc2
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_uuidsys.c
@@ -0,0 +1,17 @@
+/* Test for uuidsys syscall which is available on newer Solaris. */ 
+
+#include "scalar.h"
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_uuidsys              124 */
+   GO(SYS_uuidsys, "1s 1m");
+   SY(SYS_uuidsys, x0 + 1); FAIL;
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_uuidsys.stderr.exp b/memcheck/tests/solaris/scalar_uuidsys.stderr.exp
new file mode 100644
index 0000000..ab3ecde
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_uuidsys.stderr.exp
@@ -0,0 +1,10 @@
+---------------------------------------------------------
+124:             SYS_uuidsys 1s 1m
+---------------------------------------------------------
+Syscall param uuidsys(uuid) contains uninitialised byte(s)
+   ...
+
+Syscall param uuidsys(uuid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_uuidsys.stdout.exp b/memcheck/tests/solaris/scalar_uuidsys.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_uuidsys.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_uuidsys.vgtest b/memcheck/tests/solaris/scalar_uuidsys.vgtest
new file mode 100644
index 0000000..f08e020
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_uuidsys.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_uuidsys
+prog: scalar_uuidsys
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/scalar_zone_defunct.c b/memcheck/tests/solaris/scalar_zone_defunct.c
new file mode 100644
index 0000000..0ad8978
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_zone_defunct.c
@@ -0,0 +1,44 @@
+/* Scalar test for new zone syscall subcodes available on Solaris 11. */
+
+#include "scalar.h"
+
+#include <sys/zone.h>
+
+__attribute__((noinline))
+static void sys_zone(void)
+{
+   GO(SYS_zone, "(ZONE_LIST_DEFUNCT) 3s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST_DEFUNCT, x0 + 1, x0 + 2); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_zone2(void)
+{
+   uint_t numzones = x0 + 1;
+
+   GO(SYS_zone, "(ZONE_LIST_DEFUNCT) 2s 1m");
+   SY(SYS_zone, x0 + ZONE_LIST_DEFUNCT, x0 + 1, &numzones); SUCC;
+}
+
+__attribute__((noinline))
+static void sys_zone3(void)
+{
+   GO(SYS_zone, "(ZONE_GETATTR_DEFUNCT) 5s 2m");
+   SY(SYS_zone, x0 + ZONE_GETATTR_DEFUNCT, x0 + 1, x0, x0 + 2, x0 + 3);
+   FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_zone                  227 */
+   sys_zone();
+   sys_zone2();
+   sys_zone3();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/scalar_zone_defunct.stderr.exp b/memcheck/tests/solaris/scalar_zone_defunct.stderr.exp
new file mode 100644
index 0000000..db561c8
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_zone_defunct.stderr.exp
@@ -0,0 +1,55 @@
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LIST_DEFUNCT) 3s 1m
+---------------------------------------------------------
+Syscall param zone_list_defunct(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_defunct(uniqidlist) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_defunct(numzones) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(numzones) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_LIST_DEFUNCT) 2s 1m
+---------------------------------------------------------
+Syscall param zone_list_defunct(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_list_defunct(uniqidlist) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(uniqidlist) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+227:                SYS_zone (ZONE_GETATTR_DEFUNCT) 5s 2m
+---------------------------------------------------------
+Syscall param zone_getattr_defunct(cmd) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr_defunct(uniqid) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr_defunct(attr) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr_defunct(valp) contains uninitialised byte(s)
+   ...
+
+Syscall param zone_getattr_defunct(size) contains uninitialised byte(s)
+   ...
+
+Syscall param zone(uniqid) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param zone(valp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/solaris/scalar_zone_defunct.stdout.exp b/memcheck/tests/solaris/scalar_zone_defunct.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_zone_defunct.stdout.exp
diff --git a/memcheck/tests/solaris/scalar_zone_defunct.vgtest b/memcheck/tests/solaris/scalar_zone_defunct.vgtest
new file mode 100644
index 0000000..88279d8
--- /dev/null
+++ b/memcheck/tests/solaris/scalar_zone_defunct.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_zone_defunct
+prog: scalar_zone_defunct
+vgopts: -q
+stderr_filter_args:
diff --git a/memcheck/tests/solaris/sendfilev.c b/memcheck/tests/solaris/sendfilev.c
new file mode 100644
index 0000000..83d003c
--- /dev/null
+++ b/memcheck/tests/solaris/sendfilev.c
@@ -0,0 +1,88 @@
+/* Tests sendfilev with bogus inputs. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/sendfile.h>
+
+#define CHUNK (8 * 1024)
+#define TEST_FILE "sendfile.test"
+
+int main(int argc, const char *argv[])
+{
+   int test_fd = open(TEST_FILE, O_WRONLY | O_CREAT, 0666);
+   if (test_fd < 0) {
+      int error = errno;
+      fprintf(stderr, "open failed: %s (%d).\n", strerror(error), error);
+      return 1;
+   }
+
+   char chunk1[CHUNK];
+   bzero(&chunk1, sizeof(chunk1));
+   ssize_t nbytes = write(test_fd, &chunk1, sizeof(chunk1));
+   if (nbytes != CHUNK) {
+      int error = errno;
+      fprintf(stderr, "write failed (nbytes=%zd): %s (%d).\n",
+              nbytes, strerror(error), error);
+      return 1;
+   }
+
+   close(test_fd);
+   printf("Test file created.\n"); 
+
+   test_fd = open(TEST_FILE, O_RDWR, 0666);
+   if (test_fd < 0) {
+      int error = errno;
+      fprintf(stderr, "open failed: %s (%d).\n", strerror(error), error);
+      return 1;
+   }
+
+   sendfilevec_t vec[2];
+   vec[0].sfv_fd = SFV_FD_SELF;
+   vec[0].sfv_off = -1;
+   vec[0].sfv_len = 1;
+   vec[0].sfv_flag = 0;
+   vec[1].sfv_fd = test_fd;
+   vec[1].sfv_off = 0;
+   vec[1].sfv_len = CHUNK;
+   vec[1].sfv_flag = 0;
+   size_t xferred;
+
+   nbytes = sendfilev(test_fd, vec, 2, &xferred);
+   if (nbytes < 0) {
+      if (errno == EFAULT) {
+         printf("Received EFAULT as expected.\n");
+      } else {
+         fprintf(stderr, "Expected EFAULT, got %d.\n", errno);
+      }
+   } else {
+      fprintf(stderr, "Error: sendfilev returned a positive value.\n");
+   }
+
+   nbytes = sendfilev(test_fd, vec, -1, &xferred);
+   if (nbytes < 0) {
+      if (errno == EINVAL) {
+         printf("Received EINVAL as expected.\n");
+      } else {
+         fprintf(stderr, "Expected EINVAL, got %d.\n", errno);
+      }
+   } else {
+      fprintf(stderr, "Error: sendfilev returned a positive value.\n");
+   }
+
+   vec[0].sfv_off = (off_t) "HEADER";
+   vec[0].sfv_len = 6;
+   nbytes = sendfilev(test_fd, vec, 1, &xferred);
+   if (nbytes < 0) {
+      int error = errno;
+      fprintf(stderr, "sendfilev failed: %s (%d).\n", strerror(error), error);
+   } else {
+      printf("sendfilev for the first buffer succeeded.\n");
+   }
+
+   unlink(TEST_FILE);
+   return 0;
+}
diff --git a/memcheck/tests/solaris/sendfilev.stderr.exp b/memcheck/tests/solaris/sendfilev.stderr.exp
new file mode 100644
index 0000000..db07a0d
--- /dev/null
+++ b/memcheck/tests/solaris/sendfilev.stderr.exp
@@ -0,0 +1,11 @@
+Syscall param sendfilev(vec[0].sfv_off points to unaddressable byte(s)
+   ...
+   by 0x........: main (sendfilev.c:54)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param sendfilev(vec) points to uninitialised byte(s)
+   ...
+   by 0x........: main (sendfilev.c:65)
+ Address 0x........ is on thread 1's stack
+ in frame #., created by main (sendfilev.c:15)
+
diff --git a/memcheck/tests/solaris/sendfilev.stdout.exp b/memcheck/tests/solaris/sendfilev.stdout.exp
new file mode 100644
index 0000000..65dcf64
--- /dev/null
+++ b/memcheck/tests/solaris/sendfilev.stdout.exp
@@ -0,0 +1,4 @@
+Test file created.
+Received EFAULT as expected.
+Received EINVAL as expected.
+sendfilev for the first buffer succeeded.
diff --git a/memcheck/tests/solaris/sendfilev.vgtest b/memcheck/tests/solaris/sendfilev.vgtest
new file mode 100644
index 0000000..98f3433
--- /dev/null
+++ b/memcheck/tests/solaris/sendfilev.vgtest
@@ -0,0 +1,4 @@
+prog: sendfilev
+vgopts: -q
+stderr_filter: filter_sendfilev
+stderr_filter_args: sendfilev.c
diff --git a/memcheck/tests/solaris/shmat.c b/memcheck/tests/solaris/shmat.c
new file mode 100644
index 0000000..de65748
--- /dev/null
+++ b/memcheck/tests/solaris/shmat.c
@@ -0,0 +1,44 @@
+/* Tests simple manipulation with a shared memory segment. */
+
+#include <stdio.h>
+#include <sys/shm.h>
+
+#define SEGMENT_SIZE 167
+
+int main(int argc, const char *argv[])
+{
+   int shmid = shmget(IPC_PRIVATE, SEGMENT_SIZE, IPC_CREAT | SHM_R | SHM_W);
+   if (shmid < 0) {
+      perror("shmget()");
+      return 1;
+   }
+
+   void *addr = shmat(shmid, NULL, 0);
+   if (addr == (void *) -1) {
+      perror("shmat()");
+      return 2;
+   }
+
+   struct shmid_ds stats;
+   int ret = shmctl(shmid, IPC_STAT, &stats);
+   if (ret != 0) {
+      perror("shmctl(IPC_STAT)");
+      return 3;
+   }   
+
+   printf("segment size: %zu\n", stats.shm_segsz);
+
+   ret = shmdt(addr);
+   if (ret != 0) {
+      perror("shmdt()");
+      return 4;
+   }
+
+   ret = shmctl(shmid, IPC_RMID, NULL);
+   if (ret != 0) {
+      perror("shmctl(IPC_RMID)");
+      return 5;
+   }
+
+   return 0;
+}
diff --git a/memcheck/tests/solaris/shmat.stderr.exp b/memcheck/tests/solaris/shmat.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/shmat.stderr.exp
diff --git a/memcheck/tests/solaris/shmat.stdout.exp b/memcheck/tests/solaris/shmat.stdout.exp
new file mode 100644
index 0000000..b1c5236
--- /dev/null
+++ b/memcheck/tests/solaris/shmat.stdout.exp
@@ -0,0 +1 @@
+segment size: 167
diff --git a/memcheck/tests/solaris/shmat.vgtest b/memcheck/tests/solaris/shmat.vgtest
new file mode 100644
index 0000000..c65e9a9
--- /dev/null
+++ b/memcheck/tests/solaris/shmat.vgtest
@@ -0,0 +1,2 @@
+prog: shmat
+vgopts: -q
diff --git a/memcheck/tests/solaris/spawn.c b/memcheck/tests/solaris/spawn.c
new file mode 100644
index 0000000..f3c0632
--- /dev/null
+++ b/memcheck/tests/solaris/spawn.c
@@ -0,0 +1,112 @@
+/* Functional tests for spawn() syscall invoked indirectly via posix_spawn()
+   or system(). */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <sys/wait.h>
+
+
+#define EXE_NAME "../../../tests/true"
+
+static volatile int sigchld_handled = 0;
+static void sigchld_handler(int sig, siginfo_t *sip, void *ucontext) {
+   assert(sig == SIGCHLD);
+   sigchld_handled = 1;
+}
+
+int main(int argc, char *const argv[], char *const envp[]) {
+   int ret = system(EXE_NAME);
+   if (ret != 0)
+      perror("system");
+
+   /* system() */
+   ret = system(NULL);
+   if (ret == 0)
+      fprintf(stderr, "system() succeeded");
+
+   /* posix_spawn(), no file actions, no attrs */
+   char *const argv_exe[] = {"true", NULL};
+   pid_t child;
+   ret = posix_spawn(&child, EXE_NAME, NULL, NULL, argv_exe, envp);
+   if (ret != 0)
+      perror("posix_spawn");
+   waitpid(child, NULL, 0);
+
+   /* posix_spawn(), file actions, no attrs */
+   posix_spawn_file_actions_t fa;
+   ret = posix_spawn_file_actions_init(&fa);
+   if (ret != 0)
+      perror("posix_spawn_file_actions_init");
+   ret = posix_spawn_file_actions_addopen(&fa, 10, "/dev/null", O_RDONLY, 0);
+   if (ret != 0)
+      perror("posix_spawn_file_actions_addopen");
+   ret = posix_spawn(&child, EXE_NAME, &fa, NULL, argv_exe, envp);
+   if (ret != 0)
+      perror("posix_spawn");
+   waitpid(child, NULL, 0);
+   ret = posix_spawn_file_actions_destroy(&fa);
+   if (ret != 0)
+      perror("posix_spawn_file_actions_destroy");
+
+   /* posix_spawn(), no file actions, attrs */
+   posix_spawnattr_t spa;
+   ret = posix_spawnattr_init(&spa);
+   if (ret != 0)
+      perror("posix_spawnattr_init");
+   ret = posix_spawnattr_setflags(&spa, POSIX_SPAWN_RESETIDS);
+   if (ret != 0)
+      perror("posix_spawnattr_setflags");
+   ret = posix_spawn(&child, EXE_NAME, NULL, &spa, argv_exe, envp);
+   if (ret != 0)
+      perror("posix_spawn");
+   waitpid(child, NULL, 0);
+   ret = posix_spawnattr_destroy(&spa);
+   if (ret != 0)
+      perror("posix_spawnattr_destroy");
+
+   /* posix_spawn(), no file actions, no attrs, test SIGCHLD delivery */
+   struct sigaction act;
+   bzero(&act, sizeof(act));
+   act.sa_sigaction = sigchld_handler;
+   act.sa_flags = SA_SIGINFO;
+   ret = sigaction(SIGCHLD, &act, NULL);
+   if (ret != 0)
+      perror("sigaction");
+   sigchld_handled = 0;
+   ret = posix_spawn(&child, EXE_NAME, NULL, NULL, argv_exe, envp);
+   if (ret != 0)
+      perror("posix_spawn");
+   waitpid(child, NULL, 0);
+   if (sigchld_handled == 1) {
+      printf("PASS\n");
+   } else {
+      printf("FAIL\n");
+   }
+
+   /* posix_spawn(), no file actions, attrs, test *no* SIGCHLD delivery */
+   ret = posix_spawnattr_init(&spa);
+   if (ret != 0)
+      perror("posix_spawnattr_init");
+   ret = posix_spawnattr_setflags(&spa, POSIX_SPAWN_NOSIGCHLD_NP);
+   if (ret != 0)
+      perror("posix_spawnattr_setflags");
+   sigchld_handled = 0;
+   ret = posix_spawn(&child, EXE_NAME, NULL, &spa, argv_exe, envp);
+   if (ret != 0)
+      perror("posix_spawn");
+   waitpid(child, NULL, 0);
+   if (sigchld_handled == 0) {
+      printf("PASS\n");
+   } else {
+      printf("FAIL\n");
+   }
+   ret = posix_spawnattr_destroy(&spa);
+   if (ret != 0)
+      perror("posix_spawnattr_destroy");
+
+   return 0;
+}
diff --git a/memcheck/tests/solaris/spawn.stderr.exp b/memcheck/tests/solaris/spawn.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/spawn.stderr.exp
diff --git a/memcheck/tests/solaris/spawn.stdout.exp b/memcheck/tests/solaris/spawn.stdout.exp
new file mode 100644
index 0000000..38e0352
--- /dev/null
+++ b/memcheck/tests/solaris/spawn.stdout.exp
@@ -0,0 +1,2 @@
+PASS
+PASS
diff --git a/memcheck/tests/solaris/spawn.vgtest b/memcheck/tests/solaris/spawn.vgtest
new file mode 100644
index 0000000..e40eaa9
--- /dev/null
+++ b/memcheck/tests/solaris/spawn.vgtest
@@ -0,0 +1,3 @@
+prereq: test -e spawn
+prog: spawn
+vgopts: -q --trace-children=yes
diff --git a/memcheck/tests/solaris/strlcpy.c b/memcheck/tests/solaris/strlcpy.c
new file mode 100644
index 0000000..9dd7e13
--- /dev/null
+++ b/memcheck/tests/solaris/strlcpy.c
@@ -0,0 +1,47 @@
+/* Tests for some interesting cases in non-standard strlcpy(). */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+int main(void)
+{
+   size_t copied;
+
+   char *src = malloc(100);
+   if (src == NULL) {
+      fprintf(stderr, "Memory allocation failure.\n");
+      return 1;
+   }
+   strcpy(src, "Hey, dude!");
+
+   char *dst = malloc(10);
+   if (dst == NULL) {
+      fprintf(stderr, "Memory allocation failure.\n");
+      return 1;
+   }
+
+   /* This is ok. */
+   copied = strlcpy(dst, src, 10);
+   if (copied != 10)
+      fprintf(stderr, "Expected 10 but got %zu for test #1.\n", copied);
+
+   /* Here dst is not large enough. */
+   copied = strlcpy(dst, src, strlen(src) + 1);
+   if (copied != 10)
+      fprintf(stderr, "Expected 10 but got %zu for test #2.\n", copied);
+
+   /* This is just a fancy way how to write strlen(src).
+      Undocumented but heavily used. */
+   copied = strlcpy(NULL, src, 0);
+   if (copied != 10)
+      fprintf(stderr, "Expected 10 but got %zu for test #3.\n", copied);
+
+   /* Source and destination overlap. */
+   strlcpy(src + 9, src, strlen(src) + 1);
+   /* Return value is not checked because function behaviour
+      is undefined in such case (and valgrind's differs). */
+
+   return 0;
+}
+
diff --git a/memcheck/tests/solaris/strlcpy.stderr.exp b/memcheck/tests/solaris/strlcpy.stderr.exp
new file mode 100644
index 0000000..ad1c373
--- /dev/null
+++ b/memcheck/tests/solaris/strlcpy.stderr.exp
@@ -0,0 +1,11 @@
+Invalid write of size 1
+   at 0x........: strlcpy (vg_replace_strmem.c:...)
+   ...
+ Address 0x........ is 0 bytes after a block of size 10 alloc'd
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   ...
+
+Source and destination overlap in strlcpy(0x........, 0x........, 11)
+   at 0x........: strlcpy (vg_replace_strmem.c:...)
+   ...
+
diff --git a/memcheck/tests/solaris/strlcpy.stdout.exp b/memcheck/tests/solaris/strlcpy.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/strlcpy.stdout.exp
diff --git a/memcheck/tests/solaris/strlcpy.vgtest b/memcheck/tests/solaris/strlcpy.vgtest
new file mode 100644
index 0000000..fd32702
--- /dev/null
+++ b/memcheck/tests/solaris/strlcpy.vgtest
@@ -0,0 +1,5 @@
+prog: strlcpy
+vgopts: -q
+# The next line causes that all stack traces are completely removed.
+stderr_filter_args:
+stderr_filter: filter_scalar
diff --git a/memcheck/tests/solaris/supponlyobj.stderr.exp b/memcheck/tests/solaris/supponlyobj.stderr.exp
new file mode 100644
index 0000000..25c4159
--- /dev/null
+++ b/memcheck/tests/solaris/supponlyobj.stderr.exp
@@ -0,0 +1,8 @@
+Conditional jump or move depends on uninitialised value(s)
+   ...
+   by 0x........: main (inlinfo.c:9)
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+   by 0x........: main (inlinfo.c:9)
+
diff --git a/memcheck/tests/solaris/supponlyobj.supp b/memcheck/tests/solaris/supponlyobj.supp
new file mode 100644
index 0000000..374cbcd
--- /dev/null
+++ b/memcheck/tests/solaris/supponlyobj.supp
@@ -0,0 +1,16 @@
+{
+   obj2
+   Memcheck:Cond
+   obj:*inlinfo_nested.so
+   obj:*inlinfo_nested.so
+}
+
+{
+   obj5
+   Memcheck:Cond
+   obj:*inlinfo_nested.so
+   obj:*inlinfo_nested.so
+   obj:*inlinfo_nested.so
+   obj:*inlinfo_nested.so
+   obj:*inlinfo_nested.so
+}
diff --git a/memcheck/tests/solaris/supponlyobj.vgtest b/memcheck/tests/solaris/supponlyobj.vgtest
new file mode 100644
index 0000000..565e44e
--- /dev/null
+++ b/memcheck/tests/solaris/supponlyobj.vgtest
@@ -0,0 +1,4 @@
+# Test suppressions with only obj: markers.
+prog: inlinfo
+vgopts: -q --read-inline-info=no --suppressions=supponlyobj.supp
+stderr_filter_args: inlinfo.c
diff --git a/memcheck/tests/solaris/syscall_at.c b/memcheck/tests/solaris/syscall_at.c
new file mode 100644
index 0000000..7aaf34f
--- /dev/null
+++ b/memcheck/tests/solaris/syscall_at.c
@@ -0,0 +1,107 @@
+/* Tests various combinations of dfd and pathname for *at syscalls.
+   In particular, dfd should not be checked when pathname is absolute.
+   See https://bugs.kde.org/show_bug.cgi?id=307103 for more information.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#define DIRECTORY "/tmp/"
+#define FILENAME "abc123"
+
+int main(void)
+{
+   char buf[1];
+   struct stat stats;
+
+   int dfd = open(DIRECTORY, O_RDONLY);
+
+   /* linkat */
+   linkat(dfd, FILENAME, dfd, FILENAME, 0);
+   linkat(0x9879151, DIRECTORY FILENAME, 0x9879152, DIRECTORY FILENAME, 0);
+   linkat(AT_FDCWD, FILENAME, AT_FDCWD, FILENAME, 0);
+   linkat(0x9879153, FILENAME, 0x9879154, FILENAME, 0); /* warning for this one */
+
+   /* symlinkat */
+   symlinkat(FILENAME, dfd, FILENAME);
+   symlinkat(DIRECTORY FILENAME, 0x26868151, DIRECTORY FILENAME);
+   symlinkat(FILENAME, AT_FDCWD, FILENAME);
+   symlinkat(FILENAME, 0x26868152, FILENAME); /* warning for this one */
+
+   /* readlinkat */
+   readlinkat(dfd, FILENAME, buf, 1);
+   readlinkat(0x4368151, DIRECTORY FILENAME, buf, 1);
+   readlinkat(AT_FDCWD, FILENAME, buf, 1);
+   readlinkat(0x4368152, FILENAME, buf, 1); /* warning for this one */
+
+#if defined(SOLARIS_FREALPATHAT_SYSCALL)
+   /* frealpathat - not available directly */
+   syscall(SYS_frealpathat, dfd, FILENAME, buf, 1);
+   syscall(SYS_frealpathat, 0x443115, DIRECTORY FILENAME, buf, 1);
+   syscall(SYS_frealpathat, AT_FDCWD, FILENAME, buf, 1);
+#endif /* SOLARIS_FREALPATHAT_SYSCALL */
+
+   /* faccessat */
+   faccessat(dfd, FILENAME, F_OK, 0);
+   faccessat(0x4132151, DIRECTORY FILENAME, F_OK, 0);
+   faccessat(AT_FDCWD, FILENAME, F_OK, 0);
+   faccessat(0x4132152, FILENAME, F_OK, 0); /* warning for this one */
+
+   /* fchownat */
+   fchownat(dfd, FILENAME, -1, -1, 0);
+   fchownat(0x4369251, DIRECTORY FILENAME, -1, -1, 0);
+   fchownat(AT_FDCWD, FILENAME, -1, -1, 0);
+   fchownat(0x4369252, FILENAME, -1, -1, 0); /* warning for this one */
+
+   /* renameat */
+   renameat(dfd, FILENAME, dfd, FILENAME);
+   renameat(0x4371151, DIRECTORY FILENAME, 0x4371152, DIRECTORY FILENAME);
+   renameat(AT_FDCWD, FILENAME, AT_FDCWD, FILENAME);
+   renameat(0x4371153, FILENAME, 0x4371154, FILENAME); /* warning for this one */
+
+   /* unlinkat */
+   unlinkat(dfd, FILENAME, 0);
+   unlinkat(0x7608151, DIRECTORY FILENAME, 0);
+   unlinkat(AT_FDCWD, FILENAME, 0);
+   unlinkat(0x7608152, FILENAME, 0); /* warning for this one */
+
+   /* fstatat */
+   fstatat(dfd, FILENAME, &stats, 0);
+   fstatat(0x42515151, DIRECTORY FILENAME, &stats, 0);
+   fstatat(AT_FDCWD, FILENAME, &stats, 0);
+   fstatat(0x42515152, FILENAME, &stats, 0); /* warning for this one */
+
+   /* openat */
+   openat(dfd, FILENAME, O_RDONLY);
+   openat(0x9038151, DIRECTORY FILENAME, O_RDONLY);
+   openat(AT_FDCWD, FILENAME, O_RDONLY);
+   openat(0x9038152, FILENAME, O_RDONLY); /* warning for this one */
+
+   /* fchmodat */
+   fchmodat(dfd, FILENAME, S_IRUSR | S_IWUSR, 0);
+   fchmodat(0x4303151, DIRECTORY FILENAME, S_IRUSR | S_IWUSR, 0);
+   fchmodat(AT_FDCWD, FILENAME, S_IRUSR | S_IWUSR, 0);
+   fchmodat(0x4303152, FILENAME, S_IRUSR | S_IWUSR, 0); /* warning for this one */
+
+   /* mkdirat */
+   mkdirat(dfd, FILENAME, S_IRUSR | S_IWUSR);
+   mkdirat(0x9384151, DIRECTORY FILENAME, S_IRUSR | S_IWUSR);
+   mkdirat(AT_FDCWD, FILENAME, S_IRUSR | S_IWUSR);
+   mkdirat(0x9384152, FILENAME, S_IRUSR | S_IWUSR); /* warning for this one */
+
+   /* utimensat */
+   utimensat(dfd, FILENAME, NULL, 0);
+   utimensat(0x59837215, DIRECTORY FILENAME, NULL, 0);
+   utimensat(AT_FDCWD, FILENAME, NULL, 0);
+   utimensat(0x59837216, FILENAME, NULL, 0); /* warning for this one */
+
+   rmdir(DIRECTORY FILENAME);
+   rmdir(FILENAME);
+   close(dfd);
+   return 0;
+}
diff --git a/memcheck/tests/solaris/syscall_at.stderr.exp b/memcheck/tests/solaris/syscall_at.stderr.exp
new file mode 100644
index 0000000..97b2cd5
--- /dev/null
+++ b/memcheck/tests/solaris/syscall_at.stderr.exp
@@ -0,0 +1,24 @@
+
+Warning: invalid file descriptor 159879507 in syscall linkat()
+Warning: invalid file descriptor 159879508 in syscall linkat()
+Warning: invalid file descriptor 646349138 in syscall symlinkat()
+Warning: invalid file descriptor 70680914 in syscall readlinkat()
+Warning: invalid file descriptor 68362578 in syscall faccessat()
+Warning: invalid file descriptor 70685266 in syscall fchownat()
+Warning: invalid file descriptor 70717779 in syscall renameat()
+Warning: invalid file descriptor 70717780 in syscall renameat()
+Warning: invalid file descriptor 123765074 in syscall unlinkat()
+Warning: invalid file descriptor 1112625490 in syscall fstatat()
+Warning: invalid file descriptor 151224658 in syscall openat()
+Warning: invalid file descriptor 70267218 in syscall fchmodat()
+Warning: invalid file descriptor 154681682 in syscall mkdirat()
+Warning: invalid file descriptor 1501786646 in syscall utimeXXX()
+
+HEAP SUMMARY:
+    in use at exit: 0 bytes in 0 blocks
+  total heap usage: 0 allocs, 0 frees, 0 bytes allocated
+
+For a detailed leak analysis, rerun with: --leak-check=full
+
+For counts of detected and suppressed errors, rerun with: -v
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/memcheck/tests/solaris/syscall_at.stdout.exp b/memcheck/tests/solaris/syscall_at.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/syscall_at.stdout.exp
diff --git a/memcheck/tests/solaris/syscall_at.vgtest b/memcheck/tests/solaris/syscall_at.vgtest
new file mode 100644
index 0000000..f80366d
--- /dev/null
+++ b/memcheck/tests/solaris/syscall_at.vgtest
@@ -0,0 +1,2 @@
+prog: syscall_at
+stderr_filter: filter_syscall_at
diff --git a/memcheck/tests/solaris/thr_daemon_exit_libc.c b/memcheck/tests/solaris/thr_daemon_exit_libc.c
new file mode 100644
index 0000000..b8c1e9a
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_libc.c
@@ -0,0 +1,72 @@
+/* Creates several daemon threads and non-daemon threads.
+   Tests that the process can exit even if the daemon threads are still running,
+   as per thr_create(3C). */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <thread.h>
+#include <unistd.h>
+
+#define DAEMON_THREADS 5
+#define NON_DAEMON_THREADS 6
+#define SLEEP_100_MS usleep(100 * 1000)
+
+static pthread_barrier_t barrier;
+
+void *daemon_thread_func(void *arg) {
+   size_t index = (size_t) arg;
+   printf("DAEMON thread #%zu running\n", index); fflush(stdout);
+   pthread_barrier_wait(&barrier);
+
+   /* Give the non-daemon threads enough time to exit. */
+   sleep(10);
+   printf("DAEMON thread #%zu still running?!\n", index); fflush(stdout);
+   return NULL;
+}
+
+void *normal_thread_func(void *arg) {
+   size_t index = (size_t) arg;
+   printf("non-daemon thread #%zu running\n", index); fflush(stdout);
+   pthread_barrier_wait(&barrier);
+
+   sleep(2);
+   return NULL;
+}
+
+int main(void) {
+   size_t i;
+   int ret = pthread_barrier_init(&barrier, NULL,
+                                  DAEMON_THREADS + NON_DAEMON_THREADS + 1);
+   if (ret != 0) {
+      fprintf(stderr, "pthread_barrier_init failed: %s\n", strerror(ret));
+      return 1;
+   }
+
+   for (i = 0; i < DAEMON_THREADS; i++) {
+      ret = thr_create(NULL, 0, daemon_thread_func, (void *) i,
+                       THR_DAEMON, NULL);
+      if (ret != 0) {
+         fprintf(stderr, "thr_create failed: %s\n", strerror(ret));
+         return 1;
+      }
+      SLEEP_100_MS;
+   }
+
+   for (i = 0; i < NON_DAEMON_THREADS; i++) {
+      ret = thr_create(NULL, 0, normal_thread_func, (void *) i, 0, NULL);
+      if (ret != 0) {
+         fprintf(stderr, "thr_create failed: %s\n", strerror(ret));
+         return 1;
+      }
+      SLEEP_100_MS;
+   }
+
+   pthread_barrier_wait(&barrier);
+
+   printf("MAIN thread exiting\n");
+   /* Exit only the main thread, not whole process.
+      That is, do not exit(0) or return(0). */
+   thr_exit(NULL);
+}
diff --git a/memcheck/tests/solaris/thr_daemon_exit_libc.stderr.exp b/memcheck/tests/solaris/thr_daemon_exit_libc.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_libc.stderr.exp
diff --git a/memcheck/tests/solaris/thr_daemon_exit_libc.stdout.exp b/memcheck/tests/solaris/thr_daemon_exit_libc.stdout.exp
new file mode 100644
index 0000000..db0afc1
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_libc.stdout.exp
@@ -0,0 +1,12 @@
+DAEMON thread #0 running
+DAEMON thread #1 running
+DAEMON thread #2 running
+DAEMON thread #3 running
+DAEMON thread #4 running
+non-daemon thread #0 running
+non-daemon thread #1 running
+non-daemon thread #2 running
+non-daemon thread #3 running
+non-daemon thread #4 running
+non-daemon thread #5 running
+MAIN thread exiting
diff --git a/memcheck/tests/solaris/thr_daemon_exit_libc.vgtest b/memcheck/tests/solaris/thr_daemon_exit_libc.vgtest
new file mode 100644
index 0000000..8193709
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_libc.vgtest
@@ -0,0 +1,2 @@
+prog: thr_daemon_exit_libc
+vgopts: -q
diff --git a/memcheck/tests/solaris/thr_daemon_exit_standalone.c b/memcheck/tests/solaris/thr_daemon_exit_standalone.c
new file mode 100644
index 0000000..cf1987f
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_standalone.c
@@ -0,0 +1,234 @@
+/* Tests that the process can exit even if daemon thread is still running.
+   This test does *not* use any libc; it interfaces only with kernel. */
+
+#include <sys/lwp.h>
+#include <sys/mman.h>
+#include <sys/segments.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+extern void bzero(void *ptr, size_t n);
+
+#if defined(VGP_x86_solaris)
+asm("\n"
+".text\n"
+".globl bzero\n"
+"bzero:\n"
+"   push %edi\n"
+"   movl $0, %eax\n"
+"   movl 12(%esp), %ecx\n"
+"   movl 8(%esp), %edi\n"
+"   rep  stosb\n"
+"   pop  %edi\n"
+"   ret\n"
+);
+#elif defined(VGP_amd64_solaris)
+asm("\n"
+".text\n"
+".globl bzero\n"
+"bzero:\n"
+"   push %rdi\n"
+"   movq %rsi, %rcx\n"
+"   movq $0, %rax\n"
+"   rep  stosb\n"
+"   pop  %rdi\n"
+"   ret\n"
+);
+#else
+#  error "Unknown platform"
+#endif
+
+static void sleep(unsigned int sec) {
+   timespec_t ts;
+   ts.tv_sec = (time_t)sec;
+   ts.tv_nsec = 0;
+
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "pushl $0\n"
+      "pushl %[TS]\n"
+      "pushl $0xdeadbeef\n"
+      "movl  %[SYSNO], %%eax\n"
+      "int   $0x91\n"
+      "addl  $12, %%esp\n"
+      :
+      : [TS] "g" (&ts), [SYSNO] "n" (SYS_nanosleep)
+      : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__ (
+      "movq %[SYSNO], %%rax\n"
+      "movq %[TS], %%rdi\n"
+      "movq $0, %%rsi\n"
+      "syscall\n"
+      :
+      : [TS] "g" (&ts), [SYSNO] "n" (SYS_nanosleep)
+      : "rax", "rdx", "rdi", "rsi", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+}
+
+static void lwp_exit(void) {
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "movl %[SYSNO], %%eax\n"
+      "int  $0x91\n"
+      :
+      : [SYSNO] "n" (SYS_lwp_exit)
+      : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__ (
+      "movq %[SYSNO], %%rax\n"
+      "syscall\n"
+      :
+      : [SYSNO] "n" (SYS_lwp_exit)
+      : "rax", "rdx", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+}
+
+#define STACK_FLAGS (MAP_PRIVATE | MAP_NORESERVE | MAP_ANON)
+#define STACK_PROT  (PROT_READ | PROT_WRITE)
+static void *allocate_stack(size_t stacksize) {
+   void *address = NULL;
+
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "pushl $0\n"
+      "pushl $-1\n"
+      "pushl %[FLAGS]\n"
+      "pushl %[PROT]\n"
+      "pushl %[SIZE]\n"
+      "pushl $0\n"
+      "pushl $0xdeadbeef\n"
+      "movl  %[SYSNO], %%eax\n"
+      "int   $0x91\n"
+      "addl  $28, %%esp\n"
+      "movl %%eax, %[ADDRESS]\n"
+      : [ADDRESS] "=r" (address)
+      : [FLAGS] "n" (STACK_FLAGS), [PROT] "n" (STACK_PROT),
+        [SIZE] "g" (stacksize), [SYSNO] "n" (SYS_mmap)
+      : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__ (
+      "movq %[SYSNO], %%rax\n"
+      "movq $0, %%rdi\n"
+      "movq %[SIZE], %%rsi\n"
+      "movq %[PROT], %%rdx\n"
+      "movq %[FLAGS], %%r10\n"
+      "movq $-1, %%r8\n"
+      "movq $0, %%r9\n"
+      "syscall\n"
+      "movq %%rax, %[ADDRESS]\n"
+      : [ADDRESS] "=r" (address)
+      : [FLAGS] "n" (STACK_FLAGS), [PROT] "n" (STACK_PROT),
+        [SIZE] "g" (stacksize), [SYSNO] "n" (SYS_mmap)
+      : "rax", "rdx", "rdi", "rsi", "r10", "r8", "r9", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+
+   return address;
+}
+#undef STACK_FLAGS
+#undef STACK_PROT
+
+static void thread_func(void) {
+   sleep(10000);
+}
+
+#define LWP_FLAGS (LWP_SUSPENDED | LWP_DETACHED | LWP_DAEMON)
+static id_t lwp_create(void *stack) {
+   id_t tid;
+
+   ucontext_t ucontext;
+   bzero(&ucontext, sizeof(ucontext));
+   ucontext.uc_flags = UC_CPU;
+
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "mov %%ss, %[STACK_SEG]\n"
+      : [STACK_SEG] "=r" (ucontext.uc_mcontext.gregs[SS])
+      :
+      :);
+   ucontext.uc_mcontext.gregs[EIP] = (greg_t) thread_func;
+   ucontext.uc_mcontext.gregs[UESP] = (greg_t) stack;
+   ucontext.uc_mcontext.gregs[EBP] = (greg_t) stack;
+#elif defined(VGP_amd64_solaris)
+   ucontext.uc_mcontext.gregs[REG_SS] = UDS_SEL;
+   ucontext.uc_mcontext.gregs[REG_RIP] = (greg_t) thread_func;
+   ucontext.uc_mcontext.gregs[REG_RSP] = (greg_t) stack;
+   ucontext.uc_mcontext.gregs[REG_RBP] = (greg_t) stack;
+#else
+#  error "Unknown platform"
+#endif
+
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "pushl $0\n"
+      "pushl %[FLAGS]\n"
+      "pushl %[UCONTEXT]\n"
+      "pushl $0xdeadbeef\n"
+      "movl  %[SYSNO], %%eax\n"
+      "int   $0x91\n"
+      "addl  $16, %%esp\n"
+      "movl %%eax, %[TID]\n"
+      : [TID] "=r" (tid)
+      : [FLAGS] "n" (LWP_FLAGS), [UCONTEXT] "g" (&ucontext),
+        [SYSNO] "n" (SYS_lwp_create)
+      : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__ (
+      "movq %[SYSNO], %%rax\n"
+      "movq %[UCONTEXT], %%rdi\n"
+      "movq %[FLAGS], %%rsi\n"
+      "movq $0, %%rdx\n"
+      "syscall\n"
+      "movl %%eax, %[TID]\n"
+      : [TID] "=r" (tid)
+      : [FLAGS] "n" (LWP_FLAGS), [UCONTEXT] "g" (&ucontext),
+        [SYSNO] "n" (SYS_lwp_create)
+      : "rax", "rdx", "rdi", "rsi", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+
+   return tid;
+}
+
+static void lwp_continue(id_t tid) {
+#if defined(VGP_x86_solaris)
+   __asm__ __volatile__ (
+      "pushl %[TID]\n"
+      "pushl $0xdeadbeef\n"
+      "movl  %[SYSNO], %%eax\n"
+      "int   $0x91\n"
+      "addl  $8, %%esp\n"
+      :
+      : [TID] "m" (tid), [SYSNO] "n" (SYS_lwp_continue)
+      : "eax", "edx", "cc", "memory");
+#elif defined(VGP_amd64_solaris)
+   __asm__ __volatile__ (
+      "movq %[SYSNO], %%rax\n"
+      "xor %%rdi, %%rdi\n"
+      "movl %[TID], %%edi\n"
+      "syscall\n"
+      :
+      : [TID] "r" (tid), [SYSNO] "n" (SYS_lwp_continue)
+      : "rax", "rdx", "rdi", "cc", "memory");
+#else
+#  error "Unknown platform"
+#endif
+}
+
+#define STACK_SIZE 16384
+void _start(void) {
+   void *stack = allocate_stack(STACK_SIZE);
+   id_t tid = lwp_create((char *) stack + STACK_SIZE);
+   lwp_continue(tid);
+   sleep(5);
+   lwp_exit();
+   return; /* not reached */
+}
+
diff --git a/memcheck/tests/solaris/thr_daemon_exit_standalone.stderr.exp b/memcheck/tests/solaris/thr_daemon_exit_standalone.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_standalone.stderr.exp
diff --git a/memcheck/tests/solaris/thr_daemon_exit_standalone.stdout.exp b/memcheck/tests/solaris/thr_daemon_exit_standalone.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_standalone.stdout.exp
diff --git a/memcheck/tests/solaris/thr_daemon_exit_standalone.vgtest b/memcheck/tests/solaris/thr_daemon_exit_standalone.vgtest
new file mode 100644
index 0000000..9b9061e
--- /dev/null
+++ b/memcheck/tests/solaris/thr_daemon_exit_standalone.vgtest
@@ -0,0 +1,2 @@
+prog: thr_daemon_exit_standalone
+vgopts: -q
diff --git a/memcheck/tests/str_tester.c b/memcheck/tests/str_tester.c
index 85c496a..9f7790a 100644
--- a/memcheck/tests/str_tester.c
+++ b/memcheck/tests/str_tester.c
@@ -504,7 +504,7 @@
 #endif
 
 // DDD: better done by testing for the function.
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__sun)
 static void
 test_rawmemchr (void)
 {
@@ -580,7 +580,7 @@
 }
 
 // DDD: better done by testing for the function.
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__sun)
 static void
 test_memrchr (void)
 {
@@ -1063,7 +1063,7 @@
     }
 }
 
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__sun)
 static void
 test_mempcpy (void)
 {
@@ -1442,7 +1442,7 @@
   test_strchrnul ();
 # endif
 
-# if !defined(__APPLE__)
+# if !defined(__APPLE__) && !defined(__sun)
   /* rawmemchr.  */
   test_rawmemchr ();
 # endif
@@ -1453,7 +1453,7 @@
   /* strrchr.  */
   test_strrchr ();
 
-# if !defined(__APPLE__)
+# if !defined(__APPLE__) && !defined(__sun)
   /* memrchr.  */
   test_memrchr ();
 # endif
@@ -1494,7 +1494,7 @@
   /* memmove - must work on overlap.  */
   test_memmove ();
 
-# if !defined(__APPLE__)
+# if !defined(__APPLE__) && !defined(__sun)
   /* mempcpy */
   test_mempcpy ();
 # endif
diff --git a/memcheck/tests/supponlyobj.vgtest b/memcheck/tests/supponlyobj.vgtest
index bead116..6653d3c 100644
--- a/memcheck/tests/supponlyobj.vgtest
+++ b/memcheck/tests/supponlyobj.vgtest
@@ -1,3 +1,9 @@
+prereq: (! ../../tests/os_test solaris)
+# This test is disabled on Solaris because function below main (_start)
+# is part of the inlinfo object whereas on Linux it is part of libc
+# (__libc_start_main).
+# solaris/supponlyobj test exists to check the Solaris variant.
+#
 # test suppressions with only obj: markers
 prog: inlinfo
 vgopts: -q --read-inline-info=no --suppressions=supponlyobj.supp
diff --git a/memcheck/tests/thread_alloca.c b/memcheck/tests/thread_alloca.c
index fa0c185..c30d1dc 100644
--- a/memcheck/tests/thread_alloca.c
+++ b/memcheck/tests/thread_alloca.c
@@ -66,7 +66,7 @@
        assert(i == j+2);
        sprintf (n, "%d",  atoi(argv[1]) - 1);
        // system ("env | wc");
-       execle(argv[0], argv[0], n, NULL, new_env);
+       execle(argv[0], argv[0], n, (char *) NULL, new_env);
        assert(0);
     } else
        return 0;
diff --git a/memcheck/tests/threadname.c b/memcheck/tests/threadname.c
index 91e7f83..c0e0b47 100644
--- a/memcheck/tests/threadname.c
+++ b/memcheck/tests/threadname.c
@@ -1,8 +1,13 @@
+#include "config.h"
+
 #define _GNU_SOURCE
 #include <stdio.h>
 #include <pthread.h>
 #include <string.h>
 #include <stdlib.h>
+#if defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#endif /* HAVE_SYS_PRCTL_H */
 #include <sys/types.h>
 #include <unistd.h>
 #include <assert.h>
diff --git a/memcheck/tests/threadname.stderr.exp b/memcheck/tests/threadname.stderr.exp
index 1cf2313..3321af7 100644
--- a/memcheck/tests/threadname.stderr.exp
+++ b/memcheck/tests/threadname.stderr.exp
@@ -1,50 +1,50 @@
 Invalid write of size 1
-   at 0x........: bad_things (threadname.c:16)
-   by 0x........: main (threadname.c:76)
+   at 0x........: bad_things (threadname.c:21)
+   by 0x........: main (threadname.c:81)
  Address 0x........ is 0 bytes after a block of size 1 alloc'd
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: bad_things (threadname.c:15)
-   by 0x........: main (threadname.c:76)
+   by 0x........: bad_things (threadname.c:20)
+   by 0x........: main (threadname.c:81)
 
 Thread 2:
 Invalid write of size 1
-   at 0x........: bad_things (threadname.c:16)
-   by 0x........: child_fn_0 (threadname.c:61)
+   at 0x........: bad_things (threadname.c:21)
+   by 0x........: child_fn_0 (threadname.c:66)
    ...
  Address 0x........ is 0 bytes after a block of size 2 alloc'd
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: bad_things (threadname.c:15)
-   by 0x........: child_fn_0 (threadname.c:61)
+   by 0x........: bad_things (threadname.c:20)
+   by 0x........: child_fn_0 (threadname.c:66)
    ...
 
 Thread 3 try1:
 Invalid write of size 1
-   at 0x........: bad_things (threadname.c:16)
-   by 0x........: child_fn_1 (threadname.c:46)
+   at 0x........: bad_things (threadname.c:21)
+   by 0x........: child_fn_1 (threadname.c:51)
    ...
  Address 0x........ is 0 bytes after a block of size 3 alloc'd
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: bad_things (threadname.c:15)
-   by 0x........: child_fn_1 (threadname.c:46)
+   by 0x........: bad_things (threadname.c:20)
+   by 0x........: child_fn_1 (threadname.c:51)
    ...
 
 Thread 4 012345678901234:
 Invalid write of size 1
-   at 0x........: bad_things (threadname.c:16)
-   by 0x........: child_fn_2 (threadname.c:30)
+   at 0x........: bad_things (threadname.c:21)
+   by 0x........: child_fn_2 (threadname.c:35)
    ...
  Address 0x........ is 0 bytes after a block of size 4 alloc'd
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: bad_things (threadname.c:15)
-   by 0x........: child_fn_2 (threadname.c:30)
+   by 0x........: bad_things (threadname.c:20)
+   by 0x........: child_fn_2 (threadname.c:35)
    ...
 
 Thread 1:
 Invalid write of size 1
-   at 0x........: bad_things (threadname.c:16)
-   by 0x........: main (threadname.c:84)
+   at 0x........: bad_things (threadname.c:21)
+   by 0x........: main (threadname.c:89)
  Address 0x........ is 0 bytes after a block of size 5 alloc'd
    at 0x........: malloc (vg_replace_malloc.c:...)
-   by 0x........: bad_things (threadname.c:15)
-   by 0x........: main (threadname.c:84)
+   by 0x........: bad_things (threadname.c:20)
+   by 0x........: main (threadname.c:89)
 
diff --git a/memcheck/tests/vbit-test/util.c b/memcheck/tests/vbit-test/util.c
index 170fb8a..17ef972 100644
--- a/memcheck/tests/vbit-test/util.c
+++ b/memcheck/tests/vbit-test/util.c
@@ -7,6 +7,14 @@
 #include <machine/endian.h>
 #define __BYTE_ORDER    BYTE_ORDER
 #define __LITTLE_ENDIAN LITTLE_ENDIAN
+#elif defined(__sun)
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN    4321
+#  if defined(_LITTLE_ENDIAN)
+#  define __BYTE_ORDER    __LITTLE_ENDIAN
+#  else
+#  define __BYTE_ORDER    __BIG_ENDIAN
+#  endif
 #else
 #include <endian.h>
 #endif
diff --git a/memcheck/tests/vbit-test/vbits.c b/memcheck/tests/vbit-test/vbits.c
index 95c1adf..3c10acc 100644
--- a/memcheck/tests/vbit-test/vbits.c
+++ b/memcheck/tests/vbit-test/vbits.c
@@ -6,6 +6,14 @@
 #include <machine/endian.h>
 #define __BYTE_ORDER    BYTE_ORDER
 #define __LITTLE_ENDIAN LITTLE_ENDIAN
+#elif defined(__sun)
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN    4321
+#  if defined(_LITTLE_ENDIAN)
+#  define __BYTE_ORDER    __LITTLE_ENDIAN
+#  else
+#  define __BYTE_ORDER    __BIG_ENDIAN
+#  endif
 #else
 #include <endian.h>
 #endif
diff --git a/memcheck/tests/vcpu_fnfns.stdout.exp-solaris b/memcheck/tests/vcpu_fnfns.stdout.exp-solaris
new file mode 100644
index 0000000..f94bfc6
--- /dev/null
+++ b/memcheck/tests/vcpu_fnfns.stdout.exp-solaris
@@ -0,0 +1,786 @@
+floorD(-2.0000000000000e+00) = -2.0000000000000e+00
+floorD(-1.9000000001000e+00) = -2.0000000000000e+00
+floorD(-1.8000000002000e+00) = -2.0000000000000e+00
+floorD(-1.7000000003000e+00) = -2.0000000000000e+00
+floorD(-1.6000000004000e+00) = -2.0000000000000e+00
+floorD(-1.5000000005000e+00) = -2.0000000000000e+00
+floorD(-1.4000000006000e+00) = -2.0000000000000e+00
+floorD(-1.3000000007000e+00) = -2.0000000000000e+00
+floorD(-1.2000000008000e+00) = -2.0000000000000e+00
+floorD(-1.1000000009000e+00) = -2.0000000000000e+00
+floorD(-1.0000000010000e+00) = -2.0000000000000e+00
+floorD(-9.0000000110000e-01) = -1.0000000000000e+00
+floorD(-8.0000000120000e-01) = -1.0000000000000e+00
+floorD(-7.0000000130000e-01) = -1.0000000000000e+00
+floorD(-6.0000000140000e-01) = -1.0000000000000e+00
+floorD(-5.0000000150000e-01) = -1.0000000000000e+00
+floorD(-4.0000000160000e-01) = -1.0000000000000e+00
+floorD(-3.0000000170000e-01) = -1.0000000000000e+00
+floorD(-2.0000000180000e-01) = -1.0000000000000e+00
+floorD(-1.0000000190000e-01) = -1.0000000000000e+00
+floorD(-1.9999992495467e-09) = -1.0000000000000e+00
+floorD(+9.9999997900001e-02) = +0.0000000000000e+00
+floorD(+1.9999999780000e-01) = +0.0000000000000e+00
+floorD(+2.9999999770000e-01) = +0.0000000000000e+00
+floorD(+3.9999999760000e-01) = +0.0000000000000e+00
+floorD(+4.9999999750000e-01) = +0.0000000000000e+00
+floorD(+5.9999999740000e-01) = +0.0000000000000e+00
+floorD(+6.9999999730000e-01) = +0.0000000000000e+00
+floorD(+7.9999999720000e-01) = +0.0000000000000e+00
+floorD(+8.9999999710000e-01) = +0.0000000000000e+00
+floorD(+9.9999999700000e-01) = +0.0000000000000e+00
+floorD(+1.0999999969000e+00) = +1.0000000000000e+00
+floorD(+1.1999999968000e+00) = +1.0000000000000e+00
+floorD(+1.2999999967000e+00) = +1.0000000000000e+00
+floorD(+1.3999999966000e+00) = +1.0000000000000e+00
+floorD(+1.4999999965000e+00) = +1.0000000000000e+00
+floorD(+1.5999999964000e+00) = +1.0000000000000e+00
+floorD(+1.6999999963000e+00) = +1.0000000000000e+00
+floorD(+1.7999999962000e+00) = +1.0000000000000e+00
+floorD(+1.8999999961000e+00) = +1.0000000000000e+00
+floorD(+1.9999999960000e+00) = +1.0000000000000e+00
+floorF(         -2.0000e+00) =          -2.0000e+00
+floorF(         -1.9001e+00) =          -2.0000e+00
+floorF(         -1.8002e+00) =          -2.0000e+00
+floorF(         -1.7003e+00) =          -2.0000e+00
+floorF(         -1.6004e+00) =          -2.0000e+00
+floorF(         -1.5005e+00) =          -2.0000e+00
+floorF(         -1.4006e+00) =          -2.0000e+00
+floorF(         -1.3007e+00) =          -2.0000e+00
+floorF(         -1.2008e+00) =          -2.0000e+00
+floorF(         -1.1009e+00) =          -2.0000e+00
+floorF(         -1.0010e+00) =          -2.0000e+00
+floorF(         -9.0110e-01) =          -1.0000e+00
+floorF(         -8.0120e-01) =          -1.0000e+00
+floorF(         -7.0130e-01) =          -1.0000e+00
+floorF(         -6.0140e-01) =          -1.0000e+00
+floorF(         -5.0150e-01) =          -1.0000e+00
+floorF(         -4.0160e-01) =          -1.0000e+00
+floorF(         -3.0170e-01) =          -1.0000e+00
+floorF(         -2.0180e-01) =          -1.0000e+00
+floorF(         -1.0190e-01) =          -1.0000e+00
+floorF(         -1.9999e-03) =          -1.0000e+00
+floorF(         +9.7900e-02) =          +0.0000e+00
+floorF(         +1.9780e-01) =          +0.0000e+00
+floorF(         +2.9770e-01) =          +0.0000e+00
+floorF(         +3.9760e-01) =          +0.0000e+00
+floorF(         +4.9750e-01) =          +0.0000e+00
+floorF(         +5.9740e-01) =          +0.0000e+00
+floorF(         +6.9730e-01) =          +0.0000e+00
+floorF(         +7.9720e-01) =          +0.0000e+00
+floorF(         +8.9710e-01) =          +0.0000e+00
+floorF(         +9.9700e-01) =          +0.0000e+00
+floorF(         +1.0969e+00) =          +1.0000e+00
+floorF(         +1.1968e+00) =          +1.0000e+00
+floorF(         +1.2967e+00) =          +1.0000e+00
+floorF(         +1.3966e+00) =          +1.0000e+00
+floorF(         +1.4965e+00) =          +1.0000e+00
+floorF(         +1.5964e+00) =          +1.0000e+00
+floorF(         +1.6963e+00) =          +1.0000e+00
+floorF(         +1.7962e+00) =          +1.0000e+00
+floorF(         +1.8961e+00) =          +1.0000e+00
+floorF(         +1.9960e+00) =          +1.0000e+00
+ ceilD(-2.0000000000000e+00) = -2.0000000000000e+00
+ ceilD(-1.9000000001000e+00) = -1.0000000000000e+00
+ ceilD(-1.8000000002000e+00) = -1.0000000000000e+00
+ ceilD(-1.7000000003000e+00) = -1.0000000000000e+00
+ ceilD(-1.6000000004000e+00) = -1.0000000000000e+00
+ ceilD(-1.5000000005000e+00) = -1.0000000000000e+00
+ ceilD(-1.4000000006000e+00) = -1.0000000000000e+00
+ ceilD(-1.3000000007000e+00) = -1.0000000000000e+00
+ ceilD(-1.2000000008000e+00) = -1.0000000000000e+00
+ ceilD(-1.1000000009000e+00) = -1.0000000000000e+00
+ ceilD(-1.0000000010000e+00) = -1.0000000000000e+00
+ ceilD(-9.0000000110000e-01) = -0.0000000000000e+00
+ ceilD(-8.0000000120000e-01) = -0.0000000000000e+00
+ ceilD(-7.0000000130000e-01) = -0.0000000000000e+00
+ ceilD(-6.0000000140000e-01) = -0.0000000000000e+00
+ ceilD(-5.0000000150000e-01) = -0.0000000000000e+00
+ ceilD(-4.0000000160000e-01) = -0.0000000000000e+00
+ ceilD(-3.0000000170000e-01) = -0.0000000000000e+00
+ ceilD(-2.0000000180000e-01) = -0.0000000000000e+00
+ ceilD(-1.0000000190000e-01) = -0.0000000000000e+00
+ ceilD(-1.9999992495467e-09) = -0.0000000000000e+00
+ ceilD(+9.9999997900001e-02) = +1.0000000000000e+00
+ ceilD(+1.9999999780000e-01) = +1.0000000000000e+00
+ ceilD(+2.9999999770000e-01) = +1.0000000000000e+00
+ ceilD(+3.9999999760000e-01) = +1.0000000000000e+00
+ ceilD(+4.9999999750000e-01) = +1.0000000000000e+00
+ ceilD(+5.9999999740000e-01) = +1.0000000000000e+00
+ ceilD(+6.9999999730000e-01) = +1.0000000000000e+00
+ ceilD(+7.9999999720000e-01) = +1.0000000000000e+00
+ ceilD(+8.9999999710000e-01) = +1.0000000000000e+00
+ ceilD(+9.9999999700000e-01) = +1.0000000000000e+00
+ ceilD(+1.0999999969000e+00) = +2.0000000000000e+00
+ ceilD(+1.1999999968000e+00) = +2.0000000000000e+00
+ ceilD(+1.2999999967000e+00) = +2.0000000000000e+00
+ ceilD(+1.3999999966000e+00) = +2.0000000000000e+00
+ ceilD(+1.4999999965000e+00) = +2.0000000000000e+00
+ ceilD(+1.5999999964000e+00) = +2.0000000000000e+00
+ ceilD(+1.6999999963000e+00) = +2.0000000000000e+00
+ ceilD(+1.7999999962000e+00) = +2.0000000000000e+00
+ ceilD(+1.8999999961000e+00) = +2.0000000000000e+00
+ ceilD(+1.9999999960000e+00) = +2.0000000000000e+00
+ ceilF(         -2.0000e+00) =          -2.0000e+00
+ ceilF(         -1.9001e+00) =          -1.0000e+00
+ ceilF(         -1.8002e+00) =          -1.0000e+00
+ ceilF(         -1.7003e+00) =          -1.0000e+00
+ ceilF(         -1.6004e+00) =          -1.0000e+00
+ ceilF(         -1.5005e+00) =          -1.0000e+00
+ ceilF(         -1.4006e+00) =          -1.0000e+00
+ ceilF(         -1.3007e+00) =          -1.0000e+00
+ ceilF(         -1.2008e+00) =          -1.0000e+00
+ ceilF(         -1.1009e+00) =          -1.0000e+00
+ ceilF(         -1.0010e+00) =          -1.0000e+00
+ ceilF(         -9.0110e-01) =          -0.0000e+00
+ ceilF(         -8.0120e-01) =          -0.0000e+00
+ ceilF(         -7.0130e-01) =          -0.0000e+00
+ ceilF(         -6.0140e-01) =          -0.0000e+00
+ ceilF(         -5.0150e-01) =          -0.0000e+00
+ ceilF(         -4.0160e-01) =          -0.0000e+00
+ ceilF(         -3.0170e-01) =          -0.0000e+00
+ ceilF(         -2.0180e-01) =          -0.0000e+00
+ ceilF(         -1.0190e-01) =          -0.0000e+00
+ ceilF(         -1.9999e-03) =          -0.0000e+00
+ ceilF(         +9.7900e-02) =          +1.0000e+00
+ ceilF(         +1.9780e-01) =          +1.0000e+00
+ ceilF(         +2.9770e-01) =          +1.0000e+00
+ ceilF(         +3.9760e-01) =          +1.0000e+00
+ ceilF(         +4.9750e-01) =          +1.0000e+00
+ ceilF(         +5.9740e-01) =          +1.0000e+00
+ ceilF(         +6.9730e-01) =          +1.0000e+00
+ ceilF(         +7.9720e-01) =          +1.0000e+00
+ ceilF(         +8.9710e-01) =          +1.0000e+00
+ ceilF(         +9.9700e-01) =          +1.0000e+00
+ ceilF(         +1.0969e+00) =          +2.0000e+00
+ ceilF(         +1.1968e+00) =          +2.0000e+00
+ ceilF(         +1.2967e+00) =          +2.0000e+00
+ ceilF(         +1.3966e+00) =          +2.0000e+00
+ ceilF(         +1.4965e+00) =          +2.0000e+00
+ ceilF(         +1.5964e+00) =          +2.0000e+00
+ ceilF(         +1.6963e+00) =          +2.0000e+00
+ ceilF(         +1.7962e+00) =          +2.0000e+00
+ ceilF(         +1.8961e+00) =          +2.0000e+00
+ ceilF(         +1.9960e+00) =          +2.0000e+00
+  sinD(-2.0000000000000e+00) = -9.0929742682568e-01
+  sinD(-1.9000000001000e+00) = -9.4630008765509e-01
+  sinD(-1.8000000002000e+00) = -9.7384763083275e-01
+  sinD(-1.7000000003000e+00) = -9.9166481041382e-01
+  sinD(-1.6000000004000e+00) = -9.9957360302983e-01
+  sinD(-1.5000000005000e+00) = -9.9749498663942e-01
+  sinD(-1.4000000006000e+00) = -9.8544973009044e-01
+  sinD(-1.3000000007000e+00) = -9.6355818560444e-01
+  sinD(-1.2000000008000e+00) = -9.3203908625711e-01
+  sinD(-1.1000000009000e+00) = -8.9120736046967e-01
+  sinD(-1.0000000010000e+00) = -8.4147098534820e-01
+  sinD(-9.0000000110000e-01) = -7.8332691031125e-01
+  sinD(-8.0000000120000e-01) = -7.1735609173557e-01
+  sinD(-7.0000000130000e-01) = -6.4421768823199e-01
+  sinD(-6.0000000140000e-01) = -5.6464247455050e-01
+  sinD(-5.0000000150000e-01) = -4.7942553992058e-01
+  sinD(-4.0000000160000e-01) = -3.8941834378235e-01
+  sinD(-3.0000000170000e-01) = -2.9552020828541e-01
+  sinD(-2.0000000180000e-01) = -1.9866933255918e-01
+  sinD(-1.0000000190000e-01) = -9.9833418537335e-02
+  sinD(-1.9999992495467e-09) = -1.9999992495467e-09
+  sinD(+9.9999997900001e-02) = +9.9833414557320e-02
+  sinD(+1.9999999780000e-01) = +1.9866932863892e-01
+  sinD(+2.9999999770000e-01) = +2.9552020446407e-01
+  sinD(+3.9999999760000e-01) = +3.8941834009810e-01
+  sinD(+4.9999999750000e-01) = +4.7942553641025e-01
+  sinD(+5.9999999740000e-01) = +5.6464247124916e-01
+  sinD(+6.9999999730000e-01) = +6.4421768517262e-01
+  sinD(+7.9999999720000e-01) = +7.1735608894874e-01
+  sinD(+8.9999999710000e-01) = +7.8332690782482e-01
+  sinD(+9.9999999700000e-01) = +8.4147098318699e-01
+  sinD(+1.0999999969000e+00) = +8.9120735865529e-01
+  sinD(+1.1999999968000e+00) = +9.3203908480768e-01
+  sinD(+1.2999999967000e+00) = +9.6355818453445e-01
+  sinD(+1.3999999966000e+00) = +9.8544972941057e-01
+  sinD(+1.4999999965000e+00) = +9.9749498635647e-01
+  sinD(+1.5999999964000e+00) = +9.9957360314662e-01
+  sinD(+1.6999999963000e+00) = +9.9166481092919e-01
+  sinD(+1.7999999962000e+00) = +9.7384763174156e-01
+  sinD(+1.8999999961000e+00) = +9.4630008894824e-01
+  sinD(+1.9999999960000e+00) = +9.0929742849027e-01
+  sinF(         -2.0000e+00) =          -9.0930e-01
+  sinF(         -1.9001e+00) =          -9.4627e-01
+  sinF(         -1.8002e+00) =          -9.7380e-01
+  sinF(         -1.7003e+00) =          -9.9163e-01
+  sinF(         -1.6004e+00) =          -9.9956e-01
+  sinF(         -1.5005e+00) =          -9.9753e-01
+  sinF(         -1.4006e+00) =          -9.8555e-01
+  sinF(         -1.3007e+00) =          -9.6375e-01
+  sinF(         -1.2008e+00) =          -9.3233e-01
+  sinF(         -1.1009e+00) =          -8.9162e-01
+  sinF(         -1.0010e+00) =          -8.4201e-01
+  sinF(         -9.0110e-01) =          -7.8401e-01
+  sinF(         -8.0120e-01) =          -7.1819e-01
+  sinF(         -7.0130e-01) =          -6.4521e-01
+  sinF(         -6.0140e-01) =          -5.6580e-01
+  sinF(         -5.0150e-01) =          -4.8074e-01
+  sinF(         -4.0160e-01) =          -3.9089e-01
+  sinF(         -3.0170e-01) =          -2.9714e-01
+  sinF(         -2.0180e-01) =          -2.0043e-01
+  sinF(         -1.0190e-01) =          -1.0172e-01
+  sinF(         -1.9999e-03) =          -1.9999e-03
+  sinF(         +9.7900e-02) =          +9.7744e-02
+  sinF(         +1.9780e-01) =          +1.9651e-01
+  sinF(         +2.9770e-01) =          +2.9332e-01
+  sinF(         +3.9760e-01) =          +3.8721e-01
+  sinF(         +4.9750e-01) =          +4.7723e-01
+  sinF(         +5.9740e-01) =          +5.6249e-01
+  sinF(         +6.9730e-01) =          +6.4215e-01
+  sinF(         +7.9720e-01) =          +7.1540e-01
+  sinF(         +8.9710e-01) =          +7.8152e-01
+  sinF(         +9.9700e-01) =          +8.3985e-01
+  sinF(         +1.0969e+00) =          +8.8980e-01
+  sinF(         +1.1968e+00) =          +9.3087e-01
+  sinF(         +1.2967e+00) =          +9.6267e-01
+  sinF(         +1.3966e+00) =          +9.8487e-01
+  sinF(         +1.4965e+00) =          +9.9724e-01
+  sinF(         +1.5964e+00) =          +9.9967e-01
+  sinF(         +1.6963e+00) =          +9.9213e-01
+  sinF(         +1.7962e+00) =          +9.7470e-01
+  sinF(         +1.8961e+00) =          +9.4755e-01
+  sinF(         +1.9960e+00) =          +9.1095e-01
+  cosD(-2.0000000000000e+00) = -4.1614683654714e-01
+  cosD(-1.9000000001000e+00) = -3.2328956695813e-01
+  cosD(-1.8000000002000e+00) = -2.2720209488786e-01
+  cosD(-1.7000000003000e+00) = -1.2884449459302e-01
+  cosD(-1.6000000004000e+00) = -2.9199522701118e-02
+  cosD(-1.5000000005000e+00) = +7.0737201168956e-02
+  cosD(-1.4000000006000e+00) = +1.6996714230897e-01
+  cosD(-1.3000000007000e+00) = +2.6749882795010e-01
+  cosD(-1.2000000008000e+00) = +3.6235775373104e-01
+  cosD(-1.1000000009000e+00) = +4.5359612062349e-01
+  cosD(-1.0000000010000e+00) = +5.4030230502667e-01
+  cosD(-9.0000000110000e-01) = +6.2160996740901e-01
+  cosD(-8.0000000120000e-01) = +6.9670670848634e-01
+  cosD(-7.0000000130000e-01) = +7.6484218644701e-01
+  cosD(-6.0000000140000e-01) = +8.2533561411918e-01
+  cosD(-5.0000000150000e-01) = +8.7758256117123e-01
+  cosD(-4.0000000160000e-01) = +9.2106099337982e-01
+  cosD(-3.0000000170000e-01) = +9.5533648862322e-01
+  cosD(-2.0000000180000e-01) = +9.8006657748364e-01
+  cosD(-1.0000000190000e-01) = +9.9500416508834e-01
+  cosD(-1.9999992495467e-09) = +1.0000000000000e+00
+  cosD(+9.9999997900001e-02) = +9.9500416548768e-01
+  cosD(+1.9999999780000e-01) = +9.8006657827831e-01
+  cosD(+2.9999999770000e-01) = +9.5533648980530e-01
+  cosD(+3.9999999760000e-01) = +9.2106099493749e-01
+  cosD(+4.9999999750000e-01) = +8.7758256308894e-01
+  cosD(+5.9999999740000e-01) = +8.2533561637775e-01
+  cosD(+6.9999999730000e-01) = +7.6484218902388e-01
+  cosD(+7.9999999720000e-01) = +6.9670671135576e-01
+  cosD(+8.9999999710000e-01) = +6.2160997054231e-01
+  cosD(+9.9999999700000e-01) = +5.4030230839255e-01
+  cosD(+1.0999999969000e+00) = +4.5359612418832e-01
+  cosD(+1.1999999968000e+00) = +3.6235775745920e-01
+  cosD(+1.2999999967000e+00) = +2.6749883180433e-01
+  cosD(+1.3999999966000e+00) = +1.6996714625077e-01
+  cosD(+1.4999999965000e+00) = +7.0737205158934e-02
+  cosD(+1.5999999964000e+00) = -2.9199518702825e-02
+  cosD(+1.6999999963000e+00) = -1.2884449062637e-01
+  cosD(+1.7999999962000e+00) = -2.2720209099247e-01
+  cosD(+1.8999999961000e+00) = -3.2328956317293e-01
+  cosD(+1.9999999960000e+00) = -4.1614683290995e-01
+  cosF(         -2.0000e+00) =          -4.1615e-01
+  cosF(         -1.9001e+00) =          -3.2338e-01
+  cosF(         -1.8002e+00) =          -2.2740e-01
+  cosF(         -1.7003e+00) =          -1.2914e-01
+  cosF(         -1.6004e+00) =          -2.9599e-02
+  cosF(         -1.5005e+00) =          +7.0238e-02
+  cosF(         -1.4006e+00) =          +1.6938e-01
+  cosF(         -1.3007e+00) =          +2.6682e-01
+  cosF(         -1.2008e+00) =          +3.6161e-01
+  cosF(         -1.1009e+00) =          +4.5279e-01
+  cosF(         -1.0010e+00) =          +5.3946e-01
+  cosF(         -9.0110e-01) =          +6.2075e-01
+  cosF(         -8.0120e-01) =          +6.9585e-01
+  cosF(         -7.0130e-01) =          +7.6400e-01
+  cosF(         -6.0140e-01) =          +8.2454e-01
+  cosF(         -5.0150e-01) =          +8.7686e-01
+  cosF(         -4.0160e-01) =          +9.2044e-01
+  cosF(         -3.0170e-01) =          +9.5483e-01
+  cosF(         -2.0180e-01) =          +9.7971e-01
+  cosF(         -1.0190e-01) =          +9.9481e-01
+  cosF(         -1.9999e-03) =          +1.0000e+00
+  cosF(         +9.7900e-02) =          +9.9521e-01
+  cosF(         +1.9780e-01) =          +9.8050e-01
+  cosF(         +2.9770e-01) =          +9.5601e-01
+  cosF(         +3.9760e-01) =          +9.2199e-01
+  cosF(         +4.9750e-01) =          +8.7878e-01
+  cosF(         +5.9740e-01) =          +8.2680e-01
+  cosF(         +6.9730e-01) =          +7.6658e-01
+  cosF(         +7.9720e-01) =          +6.9871e-01
+  cosF(         +8.9710e-01) =          +6.2388e-01
+  cosF(         +9.9700e-01) =          +5.4282e-01
+  cosF(         +1.0969e+00) =          +4.5636e-01
+  cosF(         +1.1968e+00) =          +3.6534e-01
+  cosF(         +1.2967e+00) =          +2.7068e-01
+  cosF(         +1.3966e+00) =          +1.7332e-01
+  cosF(         +1.4965e+00) =          +7.4228e-02
+  cosF(         +1.5964e+00) =          -2.5601e-02
+  cosF(         +1.6963e+00) =          -1.2517e-01
+  cosF(         +1.7962e+00) =          -2.2350e-01
+  cosF(         +1.8961e+00) =          -3.1960e-01
+  cosF(         +1.9960e+00) =          -4.1251e-01
+  tanD(-2.0000000000000e+00) = +2.1850398632615e+00
+  tanD(-1.9000000001000e+00) = +2.9270975137210e+00
+  tanD(-1.8000000002000e+00) = +4.2862616707537e+00
+  tanD(-1.7000000003000e+00) = +7.6966021213879e+00
+  tanD(-1.6000000004000e+00) = +3.4232532266411e+01
+  tanD(-1.5000000005000e+00) = -1.4101420047097e+01
+  tanD(-1.4000000006000e+00) = -5.7978837362521e+00
+  tanD(-1.3000000007000e+00) = -3.6021024577506e+00
+  tanD(-1.2000000008000e+00) = -2.5721516282191e+00
+  tanD(-1.1000000009000e+00) = -1.9647596616229e+00
+  tanD(-1.0000000010000e+00) = -1.5574077280804e+00
+  tanD(-9.0000000110000e-01) = -1.2601582203971e+00
+  tanD(-8.0000000120000e-01) = -1.0296385595225e+00
+  tanD(-7.0000000130000e-01) = -8.4228838268536e-01
+  tanD(-6.0000000140000e-01) = -6.8413681039695e-01
+  tanD(-5.0000000150000e-01) = -5.4630249179146e-01
+  tanD(-4.0000000160000e-01) = -4.2279322062417e-01
+  tanD(-3.0000000170000e-01) = -3.0933625147229e-01
+  tanD(-2.0000000180000e-01) = -2.0271003738264e-01
+  tanD(-1.0000000190000e-01) = -1.0033467400458e-01
+  tanD(-1.9999992495467e-09) = -1.9999992495467e-09
+  tanD(+9.9999997900001e-02) = +1.0033466996431e-01
+  tanD(+1.9999999780000e-01) = +2.0271003321827e-01
+  tanD(+2.9999999770000e-01) = +3.0933624708954e-01
+  tanD(+3.9999999760000e-01) = +4.2279321590915e-01
+  tanD(+4.9999999750000e-01) = +5.4630248659768e-01
+  tanD(+5.9999999740000e-01) = +6.8413680452478e-01
+  tanD(+6.9999999730000e-01) = +8.4228837584757e-01
+  tanD(+7.9999999720000e-01) = +1.0296385512819e+00
+  tanD(+8.9999999710000e-01) = +1.2601582100451e+00
+  tanD(+9.9999999700000e-01) = +1.5574077143783e+00
+  tanD(+1.0999999969000e+00) = +1.9647596421818e+00
+  tanD(+1.1999999968000e+00) = +2.5721515977552e+00
+  tanD(+1.2999999967000e+00) = +3.6021024018500e+00
+  tanD(+1.3999999966000e+00) = +5.7978835977904e+00
+  tanD(+1.4999999965000e+00) = +1.4101419247697e+01
+  tanD(+1.5999999964000e+00) = -3.4232536957875e+01
+  tanD(+1.6999999963000e+00) = -7.6966023623385e+00
+  tanD(+1.7999999962000e+00) = -4.2862617482418e+00
+  tanD(+1.8999999961000e+00) = -2.9270975519926e+00
+  tanD(+1.9999999960000e+00) = -2.1850398863591e+00
+  tanF(         -2.0000e+00) =          +2.1850e+00
+  tanF(         -1.9001e+00) =          +2.9261e+00
+  tanF(         -1.8002e+00) =          +4.2824e+00
+  tanF(         -1.7003e+00) =          +7.6786e+00
+  tanF(         -1.6004e+00) =          +3.3770e+01
+  tanF(         -1.5005e+00) =          -1.4202e+01
+  tanF(         -1.4006e+00) =          -5.8187e+00
+  tanF(         -1.3007e+00) =          -3.6119e+00
+  tanF(         -1.2008e+00) =          -2.5783e+00
+  tanF(         -1.1009e+00) =          -1.9691e+00
+  tanF(         -1.0010e+00) =          -1.5608e+00
+  tanF(         -9.0110e-01) =          -1.2630e+00
+  tanF(         -8.0120e-01) =          -1.0321e+00
+  tanF(         -7.0130e-01) =          -8.4451e-01
+  tanF(         -6.0140e-01) =          -6.8619e-01
+  tanF(         -5.0150e-01) =          -5.4825e-01
+  tanF(         -4.0160e-01) =          -4.2468e-01
+  tanF(         -3.0170e-01) =          -3.1120e-01
+  tanF(         -2.0180e-01) =          -2.0458e-01
+  tanF(         -1.0190e-01) =          -1.0225e-01
+  tanF(         -1.9999e-03) =          -1.9999e-03
+  tanF(         +9.7900e-02) =          +9.8214e-02
+  tanF(         +1.9780e-01) =          +2.0042e-01
+  tanF(         +2.9770e-01) =          +3.0682e-01
+  tanF(         +3.9760e-01) =          +4.1997e-01
+  tanF(         +4.9750e-01) =          +5.4306e-01
+  tanF(         +5.9740e-01) =          +6.8033e-01
+  tanF(         +6.9730e-01) =          +8.3768e-01
+  tanF(         +7.9720e-01) =          +1.0239e+00
+  tanF(         +8.9710e-01) =          +1.2527e+00
+  tanF(         +9.9700e-01) =          +1.5472e+00
+  tanF(         +1.0969e+00) =          +1.9498e+00
+  tanF(         +1.1968e+00) =          +2.5480e+00
+  tanF(         +1.2967e+00) =          +3.5565e+00
+  tanF(         +1.3966e+00) =          +5.6825e+00
+  tanF(         +1.4965e+00) =          +1.3435e+01
+  tanF(         +1.5964e+00) =          -3.9048e+01
+  tanF(         +1.6963e+00) =          -7.9260e+00
+  tanF(         +1.7962e+00) =          -4.3611e+00
+  tanF(         +1.8961e+00) =          -2.9648e+00
+  tanF(         +1.9960e+00) =          -2.2083e+00
+  expD(-2.0000000000000e+00) = +1.3533528323661e-01
+  expD(-1.9000000001000e+00) = +1.4956861920768e-01
+  expD(-1.8000000002000e+00) = +1.6529888818853e-01
+  expD(-1.7000000003000e+00) = +1.8268352399793e-01
+  expD(-1.6000000004000e+00) = +2.0189651791390e-01
+  expD(-1.5000000005000e+00) = +2.2313016003686e-01
+  expD(-1.4000000006000e+00) = +2.4659696379365e-01
+  expD(-1.3000000007000e+00) = +2.7253179284324e-01
+  expD(-1.2000000008000e+00) = +3.0119421167125e-01
+  expD(-1.1000000009000e+00) = +3.3287108339850e-01
+  expD(-1.0000000010000e+00) = +3.6787944080356e-01
+  expD(-9.0000000110000e-01) = +4.0656965929337e-01
+  expD(-8.0000000120000e-01) = +4.4932896357803e-01
+  expD(-7.0000000130000e-01) = +4.9658530314585e-01
+  expD(-6.0000000140000e-01) = +5.4881163532569e-01
+  expD(-5.0000000150000e-01) = +6.0653065880284e-01
+  expD(-4.0000000160000e-01) = +6.7032004496313e-01
+  expD(-3.0000000170000e-01) = +7.4081821942233e-01
+  expD(-2.0000000180000e-01) = +8.1873075160427e-01
+  expD(-1.0000000190000e-01) = +9.0483741631677e-01
+  expD(-1.9999992495467e-09) = +9.9999999800000e-01
+  expD(+9.9999997900001e-02) = +1.1051709157548e+00
+  expD(+1.9999999780000e-01) = +1.2214027554731e+00
+  expD(+2.9999999770000e-01) = +1.3498588044713e+00
+  expD(+3.9999999760000e-01) = +1.4918246940609e+00
+  expD(+4.9999999750000e-01) = +1.6487212665783e+00
+  expD(+5.9999999740000e-01) = +1.8221187956530e+00
+  expD(+6.9999999730000e-01) = +2.0137527020333e+00
+  expD(+7.9999999720000e-01) = +2.2255409222610e+00
+  expD(+8.9999999710000e-01) = +2.4596031040241e+00
+  expD(+9.9999999700000e-01) = +2.7182818203042e+00
+  expD(+1.0999999969000e+00) = +3.0041660146335e+00
+  expD(+1.1999999968000e+00) = +3.3201169121122e+00
+  expD(+1.2999999967000e+00) = +3.6692966555106e+00
+  expD(+1.3999999966000e+00) = +4.0551999530570e+00
+  expD(+1.4999999965000e+00) = +4.4816890546522e+00
+  expD(+1.5999999964000e+00) = +4.9530324065642e+00
+  expD(+1.6999999963000e+00) = +5.4739473714736e+00
+  expD(+1.7999999962000e+00) = +6.0496474414243e+00
+  expD(+1.8999999961000e+00) = +6.6858944162043e+00
+  expD(+1.9999999960000e+00) = +7.3890560693744e+00
+  expF(         -2.0000e+00) =          +1.3534e-01
+  expF(         -1.9001e+00) =          +1.4955e-01
+  expF(         -1.8002e+00) =          +1.6527e-01
+  expF(         -1.7003e+00) =          +1.8263e-01
+  expF(         -1.6004e+00) =          +2.0182e-01
+  expF(         -1.5005e+00) =          +2.2302e-01
+  expF(         -1.4006e+00) =          +2.4645e-01
+  expF(         -1.3007e+00) =          +2.7234e-01
+  expF(         -1.2008e+00) =          +3.0095e-01
+  expF(         -1.1009e+00) =          +3.3257e-01
+  expF(         -1.0010e+00) =          +3.6751e-01
+  expF(         -9.0110e-01) =          +4.0612e-01
+  expF(         -8.0120e-01) =          +4.4879e-01
+  expF(         -7.0130e-01) =          +4.9594e-01
+  expF(         -6.0140e-01) =          +5.4804e-01
+  expF(         -5.0150e-01) =          +6.0562e-01
+  expF(         -4.0160e-01) =          +6.6925e-01
+  expF(         -3.0170e-01) =          +7.3956e-01
+  expF(         -2.0180e-01) =          +8.1726e-01
+  expF(         -1.0190e-01) =          +9.0312e-01
+  expF(         -1.9999e-03) =          +9.9800e-01
+  expF(         +9.7900e-02) =          +1.1029e+00
+  expF(         +1.9780e-01) =          +1.2187e+00
+  expF(         +2.9770e-01) =          +1.3468e+00
+  expF(         +3.9760e-01) =          +1.4882e+00
+  expF(         +4.9750e-01) =          +1.6446e+00
+  expF(         +5.9740e-01) =          +1.8174e+00
+  expF(         +6.9730e-01) =          +2.0083e+00
+  expF(         +7.9720e-01) =          +2.2193e+00
+  expF(         +8.9710e-01) =          +2.4525e+00
+  expF(         +9.9700e-01) =          +2.7101e+00
+  expF(         +1.0969e+00) =          +2.9949e+00
+  expF(         +1.1968e+00) =          +3.3095e+00
+  expF(         +1.2967e+00) =          +3.6572e+00
+  expF(         +1.3966e+00) =          +4.0414e+00
+  expF(         +1.4965e+00) =          +4.4660e+00
+  expF(         +1.5964e+00) =          +4.9352e+00
+  expF(         +1.6963e+00) =          +5.4537e+00
+  expF(         +1.7962e+00) =          +6.0267e+00
+  expF(         +1.8961e+00) =          +6.6599e+00
+  expF(         +1.9960e+00) =          +7.3596e+00
+ sqrtD(+0.0000000000000e+00) = +0.0000000000000e+00
+ sqrtD(+9.9999999900000e-02) = +3.1622776585872e-01
+ sqrtD(+1.9999999980000e-01) = +4.4721359527635e-01
+ sqrtD(+2.9999999970000e-01) = +5.4772255723130e-01
+ sqrtD(+3.9999999960000e-01) = +6.3245553171745e-01
+ sqrtD(+4.9999999950000e-01) = +7.0710678083299e-01
+ sqrtD(+5.9999999940000e-01) = +7.7459666885419e-01
+ sqrtD(+6.9999999930000e-01) = +8.3666002611575e-01
+ sqrtD(+7.9999999920000e-01) = +8.9442719055270e-01
+ sqrtD(+8.9999999910000e-01) = +9.4868329757617e-01
+ sqrtD(+9.9999999900000e-01) = +9.9999999950000e-01
+ sqrtD(+1.0999999989000e+00) = +1.0488088476457e+00
+ sqrtD(+1.1999999988000e+00) = +1.0954451144626e+00
+ sqrtD(+1.2999999987000e+00) = +1.1401754245291e+00
+ sqrtD(+1.3999999986000e+00) = +1.1832159560283e+00
+ sqrtD(+1.4999999985000e+00) = +1.2247448707792e+00
+ sqrtD(+1.5999999984000e+00) = +1.2649110634349e+00
+ sqrtD(+1.6999999983000e+00) = +1.3038404803886e+00
+ sqrtD(+1.7999999982000e+00) = +1.3416407858291e+00
+ sqrtD(+1.8999999981000e+00) = +1.3784048745198e+00
+ sqrtD(+1.9999999980000e+00) = +1.4142135616660e+00
+ sqrtF(         +0.0000e+00) =          +0.0000e+00
+ sqrtF(         +9.9900e-02) =          +3.1607e-01
+ sqrtF(         +1.9980e-01) =          +4.4699e-01
+ sqrtF(         +2.9970e-01) =          +5.4745e-01
+ sqrtF(         +3.9960e-01) =          +6.3214e-01
+ sqrtF(         +4.9950e-01) =          +7.0675e-01
+ sqrtF(         +5.9940e-01) =          +7.7421e-01
+ sqrtF(         +6.9930e-01) =          +8.3624e-01
+ sqrtF(         +7.9920e-01) =          +8.9398e-01
+ sqrtF(         +8.9910e-01) =          +9.4821e-01
+ sqrtF(         +9.9900e-01) =          +9.9950e-01
+ sqrtF(         +1.0989e+00) =          +1.0483e+00
+ sqrtF(         +1.1988e+00) =          +1.0949e+00
+ sqrtF(         +1.2987e+00) =          +1.1396e+00
+ sqrtF(         +1.3986e+00) =          +1.1826e+00
+ sqrtF(         +1.4985e+00) =          +1.2241e+00
+ sqrtF(         +1.5984e+00) =          +1.2643e+00
+ sqrtF(         +1.6983e+00) =          +1.3032e+00
+ sqrtF(         +1.7982e+00) =          +1.3410e+00
+ sqrtF(         +1.8981e+00) =          +1.3777e+00
+ sqrtF(         +1.9980e+00) =          +1.4135e+00
+  logD(+0.0000000000000e+00) =            -Infinity
+  logD(+9.9999999900000e-02) = -2.3025850939940e+00
+  logD(+1.9999999980000e-01) = -1.6094379134341e+00
+  logD(+2.9999999970000e-01) = -1.2039728053259e+00
+  logD(+3.9999999960000e-01) = -9.1629073287416e-01
+  logD(+4.9999999950000e-01) = -6.9314718155995e-01
+  logD(+5.9999999940000e-01) = -5.1082562476599e-01
+  logD(+6.9999999930000e-01) = -3.5667494493873e-01
+  logD(+7.9999999920000e-01) = -2.2314355231421e-01
+  logD(+8.9999999910000e-01) = -1.0536051665783e-01
+  logD(+9.9999999900000e-01) = -1.0000000832404e-09
+  logD(+1.0999999989000e+00) = +9.5310178804325e-02
+  logD(+1.1999999988000e+00) = +1.8232155579395e-01
+  logD(+1.2999999987000e+00) = +2.6236426346749e-01
+  logD(+1.3999999986000e+00) = +3.3647223562121e-01
+  logD(+1.4999999985000e+00) = +4.0546510710816e-01
+  logD(+1.5999999984000e+00) = +4.7000362824574e-01
+  logD(+1.6999999983000e+00) = +5.3062825006217e-01
+  logD(+1.7999999982000e+00) = +5.8778666390212e-01
+  logD(+1.8999999981000e+00) = +6.4185388517240e-01
+  logD(+1.9999999980000e+00) = +6.9314717955995e-01
+  logF(         +0.0000e+00) =                 -Inf
+  logF(         +9.9900e-02) =          -2.3036e+00
+  logF(         +1.9980e-01) =          -1.6104e+00
+  logF(         +2.9970e-01) =          -1.2050e+00
+  logF(         +3.9960e-01) =          -9.1729e-01
+  logF(         +4.9950e-01) =          -6.9415e-01
+  logF(         +5.9940e-01) =          -5.1183e-01
+  logF(         +6.9930e-01) =          -3.5768e-01
+  logF(         +7.9920e-01) =          -2.2414e-01
+  logF(         +8.9910e-01) =          -1.0636e-01
+  logF(         +9.9900e-01) =          -1.0005e-03
+  logF(         +1.0989e+00) =          +9.4310e-02
+  logF(         +1.1988e+00) =          +1.8132e-01
+  logF(         +1.2987e+00) =          +2.6136e-01
+  logF(         +1.3986e+00) =          +3.3547e-01
+  logF(         +1.4985e+00) =          +4.0446e-01
+  logF(         +1.5984e+00) =          +4.6900e-01
+  logF(         +1.6983e+00) =          +5.2963e-01
+  logF(         +1.7982e+00) =          +5.8679e-01
+  logF(         +1.8981e+00) =          +6.4085e-01
+  logF(         +1.9980e+00) =          +6.9215e-01
+log10D(+0.0000000000000e+00) =            -Infinity
+log10D(+9.9999999900000e-02) = -1.0000000004343e+00
+log10D(+1.9999999980000e-01) = -6.9897000477031e-01
+log10D(+2.9999999970000e-01) = -5.2287874571463e-01
+log10D(+3.9999999960000e-01) = -3.9794000910633e-01
+log10D(+4.9999999950000e-01) = -3.0102999609828e-01
+log10D(+5.9999999940000e-01) = -2.2184875005065e-01
+log10D(+6.9999999930000e-01) = -1.5490196042004e-01
+log10D(+7.9999999920000e-01) = -9.6910013442351e-02
+log10D(+8.9999999910000e-01) = -4.5757490994970e-02
+log10D(+9.9999999900000e-01) = -4.3429451805409e-10
+log10D(+1.0999999989000e+00) = +4.1392684723931e-02
+log10D(+1.1999999988000e+00) = +7.9181245613330e-02
+log10D(+1.2999999987000e+00) = +1.1394335187254e-01
+log10D(+1.3999999986000e+00) = +1.4612803524394e-01
+log10D(+1.4999999985000e+00) = +1.7609125862139e-01
+log10D(+1.5999999984000e+00) = +2.0411998222163e-01
+log10D(+1.6999999983000e+00) = +2.3044892094398e-01
+log10D(+1.7999999982000e+00) = +2.5527250466901e-01
+log10D(+1.8999999981000e+00) = +2.7875360051853e-01
+log10D(+1.9999999980000e+00) = +3.0102999522969e-01
+log10F(         +0.0000e+00) =                 -Inf
+log10F(         +9.9900e-02) =          -1.0004e+00
+log10F(         +1.9980e-01) =          -6.9940e-01
+log10F(         +2.9970e-01) =          -5.2331e-01
+log10F(         +3.9960e-01) =          -3.9837e-01
+log10F(         +4.9950e-01) =          -3.0146e-01
+log10F(         +5.9940e-01) =          -2.2228e-01
+log10F(         +6.9930e-01) =          -1.5534e-01
+log10F(         +7.9920e-01) =          -9.7345e-02
+log10F(         +8.9910e-01) =          -4.6192e-02
+log10F(         +9.9900e-01) =          -4.3451e-04
+log10F(         +1.0989e+00) =          +4.0958e-02
+log10F(         +1.1988e+00) =          +7.8747e-02
+log10F(         +1.2987e+00) =          +1.1351e-01
+log10F(         +1.3986e+00) =          +1.4569e-01
+log10F(         +1.4985e+00) =          +1.7566e-01
+log10F(         +1.5984e+00) =          +2.0369e-01
+log10F(         +1.6983e+00) =          +2.3001e-01
+log10F(         +1.7982e+00) =          +2.5484e-01
+log10F(         +1.8981e+00) =          +2.7832e-01
+log10F(         +1.9980e+00) =          +3.0060e-01
+ asinD(-1.0000000000000e+00) = -1.5707963267949e+00
+ asinD(-9.0000000010000e-01) = -1.1197695152280e+00
+ asinD(-8.0000000020000e-01) = -9.2729521833495e-01
+ asinD(-7.0000000030000e-01) = -7.7539749703084e-01
+ asinD(-6.0000000040000e-01) = -6.4350110929328e-01
+ asinD(-5.0000000050000e-01) = -5.2359877617565e-01
+ asinD(-4.0000000060000e-01) = -4.1151684672214e-01
+ asinD(-3.0000000070000e-01) = -3.0469265474920e-01
+ asinD(-2.0000000080000e-01) = -2.0135792160683e-01
+ asinD(-1.0000000090000e-01) = -1.0016742206609e-01
+ asinD(-1.0000000549848e-09) = -1.0000000549848e-09
+ asinD(+9.9999998900000e-02) = +1.0016742005602e-01
+ asinD(+1.9999999880000e-01) = +2.0135791956559e-01
+ asinD(+2.9999999870000e-01) = +3.0469265265263e-01
+ asinD(+3.9999999860000e-01) = +4.1151684453996e-01
+ asinD(+4.9999999850000e-01) = +5.2359877386625e-01
+ asinD(+5.9999999840000e-01) = +6.4350110679328e-01
+ asinD(+6.9999999830000e-01) = +7.7539749423028e-01
+ asinD(+7.9999999820000e-01) = +9.2729521500161e-01
+ asinD(+8.9999999810000e-01) = +1.1197695106397e+00
+ asinD(+9.9999999800000e-01) = +1.5707330812408e+00
+ asinF(         -1.0000e+00) =          -1.5708e+00
+ asinF(         -9.0010e-01) =          -1.1200e+00
+ asinF(         -8.0020e-01) =          -9.2763e-01
+ asinF(         -7.0030e-01) =          -7.7582e-01
+ asinF(         -6.0040e-01) =          -6.4400e-01
+ asinF(         -5.0050e-01) =          -5.2418e-01
+ asinF(         -4.0060e-01) =          -4.1217e-01
+ asinF(         -3.0070e-01) =          -3.0543e-01
+ asinF(         -2.0080e-01) =          -2.0217e-01
+ asinF(         -1.0090e-01) =          -1.0107e-01
+ asinF(         -9.9994e-04) =          -9.9994e-04
+ asinF(         +9.8900e-02) =          +9.9062e-02
+ asinF(         +1.9880e-01) =          +2.0013e-01
+ asinF(         +2.9870e-01) =          +3.0333e-01
+ asinF(         +3.9860e-01) =          +4.0999e-01
+ asinF(         +4.9850e-01) =          +5.2187e-01
+ asinF(         +5.9840e-01) =          +6.4150e-01
+ asinF(         +6.9830e-01) =          +7.7302e-01
+ asinF(         +7.9820e-01) =          +9.2430e-01
+ asinF(         +8.9810e-01) =          +1.1154e+00
+ asinF(         +9.9800e-01) =          +1.5075e+00
+ acosD(-1.0000000000000e+00) =    +3.1415926536e+00
+ acosD(-9.0000010000000e-01) =    +2.6905660712e+00
+ acosD(-8.0000020000000e-01) =    +2.4980918781e+00
+ acosD(-7.0000030000000e-01) =    +2.3461942435e+00
+ acosD(-6.0000040000000e-01) =    +2.2142979356e+00
+ acosD(-5.0000050000000e-01) =    +2.0943956797e+00
+ acosD(-4.0000060000000e-01) =    +1.9823138275e+00
+ acosD(-3.0000070000000e-01) =    +1.8754897146e+00
+ acosD(-2.0000080000000e-01) =    +1.7721550641e+00
+ acosD(-1.0000090000000e-01) =    +1.6709646525e+00
+ acosD(-9.9999999977896e-07) =    +1.5707973268e+00
+ acosD(+9.9998900000000e-02) =    +1.4706300112e+00
+ acosD(+1.9999880000000e-01) =    +1.3694396307e+00
+ acosD(+2.9999870000000e-01) =    +1.2661050355e+00
+ acosD(+3.9999860000000e-01) =    +1.1592810083e+00
+ acosD(+4.9999850000000e-01) =    +1.0471992832e+00
+ acosD(+5.9999840000000e-01) =    +9.2729721800e-01
+ acosD(+6.9999830000000e-01) =    +7.9540121066e-01
+ acosD(+7.9999820000000e-01) =    +6.4350410879e-01
+ acosD(+8.9999810000000e-01) =    +4.5103117068e-01
+ acosD(+9.9999800000000e-01) =    +2.0000003331e-03
+ acosF(         -1.0000e+00) =          +3.1416e+00
+ acosF(         -9.0010e-01) =          +2.6908e+00
+ acosF(         -8.0020e-01) =          +2.4984e+00
+ acosF(         -7.0030e-01) =          +2.3466e+00
+ acosF(         -6.0040e-01) =          +2.2148e+00
+ acosF(         -5.0050e-01) =          +2.0950e+00
+ acosF(         -4.0060e-01) =          +1.9830e+00
+ acosF(         -3.0070e-01) =          +1.8762e+00
+ acosF(         -2.0080e-01) =          +1.7730e+00
+ acosF(         -1.0090e-01) =          +1.6719e+00
+ acosF(         -9.9994e-04) =          +1.5718e+00
+ acosF(         +9.8900e-02) =          +1.4717e+00
+ acosF(         +1.9880e-01) =          +1.3707e+00
+ acosF(         +2.9870e-01) =          +1.2675e+00
+ acosF(         +3.9860e-01) =          +1.1608e+00
+ acosF(         +4.9850e-01) =          +1.0489e+00
+ acosF(         +5.9840e-01) =          +9.2929e-01
+ acosF(         +6.9830e-01) =          +7.9778e-01
+ acosF(         +7.9820e-01) =          +6.4650e-01
+ acosF(         +8.9810e-01) =          +4.5537e-01
+ acosF(         +9.9800e-01) =          +6.3255e-02
+ atanD(-1.0000000000000e+00) = -7.8539816339745e-01
+ atanD(-9.0000000010000e-01) = -7.3281510184176e-01
+ atanD(-8.0000000020000e-01) = -6.7474094234550e-01
+ atanD(-7.0000000030000e-01) = -6.1072596459055e-01
+ atanD(-6.0000000040000e-01) = -5.4041950056470e-01
+ atanD(-5.0000000050000e-01) = -4.6364760940081e-01
+ atanD(-4.0000000060000e-01) = -3.8050637762961e-01
+ atanD(-3.0000000070000e-01) = -2.9145679512007e-01
+ atanD(-2.0000000080000e-01) = -1.9739556061911e-01
+ atanD(-1.0000000090000e-01) = -9.9668653382251e-02
+ atanD(-1.0000000549848e-09) = -1.0000000549848e-09
+ atanD(+9.9999998900000e-02) = +9.9668651402053e-02
+ atanD(+1.9999999880000e-01) = +1.9739555869603e-01
+ atanD(+2.9999999870000e-01) = +2.9145679328521e-01
+ atanD(+3.9999999860000e-01) = +3.8050637590547e-01
+ atanD(+4.9999999850000e-01) = +4.6364760780081e-01
+ atanD(+5.9999999840000e-01) = +5.4041949909411e-01
+ atanD(+6.9999999830000e-01) = +6.1072596324827e-01
+ atanD(+7.9999999820000e-01) = +6.7474094112599e-01
+ atanD(+8.9999999810000e-01) = +7.3281510073678e-01
+ atanD(+9.9999999800000e-01) = +7.8539816239745e-01
+ atanF(         -1.0000e+00) =          -7.8540e-01
+ atanF(         -9.0010e-01) =          -7.3287e-01
+ atanF(         -8.0020e-01) =          -6.7486e-01
+ atanF(         -7.0030e-01) =          -6.1093e-01
+ atanF(         -6.0040e-01) =          -5.4071e-01
+ atanF(         -5.0050e-01) =          -4.6405e-01
+ atanF(         -4.0060e-01) =          -3.8102e-01
+ atanF(         -3.0070e-01) =          -2.9210e-01
+ atanF(         -2.0080e-01) =          -1.9816e-01
+ atanF(         -1.0090e-01) =          -1.0056e-01
+ atanF(         -9.9994e-04) =          -9.9994e-04
+ atanF(         +9.8900e-02) =          +9.8579e-02
+ atanF(         +1.9880e-01) =          +1.9624e-01
+ atanF(         +2.9870e-01) =          +2.9026e-01
+ atanF(         +3.9860e-01) =          +3.7930e-01
+ atanF(         +4.9850e-01) =          +4.6245e-01
+ atanF(         +5.9840e-01) =          +5.3924e-01
+ atanF(         +6.9830e-01) =          +6.0958e-01
+ atanF(         +7.9820e-01) =          +6.7364e-01
+ atanF(         +8.9810e-01) =          +7.3176e-01
+ atanF(         +9.9800e-01) =          +7.8440e-01
+atan2D(-1.0000000000000e+00) = -7.8539816339745e-01
+atan2D(-9.0000000010000e-01) = -7.3281510184176e-01
+atan2D(-8.0000000020000e-01) = -6.7474094234550e-01
+atan2D(-7.0000000030000e-01) = -6.1072596459055e-01
+atan2D(-6.0000000040000e-01) = -5.4041950056470e-01
+atan2D(-5.0000000050000e-01) = -4.6364760940081e-01
+atan2D(-4.0000000060000e-01) = -3.8050637762961e-01
+atan2D(-3.0000000070000e-01) = -2.9145679512007e-01
+atan2D(-2.0000000080000e-01) = -1.9739556061911e-01
+atan2D(-1.0000000090000e-01) = -9.9668653382251e-02
+atan2D(-1.0000000549848e-09) = -1.0000000549848e-09
+atan2D(+9.9999998900000e-02) = +9.9668651402053e-02
+atan2D(+1.9999999880000e-01) = +1.9739555869603e-01
+atan2D(+2.9999999870000e-01) = +2.9145679328521e-01
+atan2D(+3.9999999860000e-01) = +3.8050637590547e-01
+atan2D(+4.9999999850000e-01) = +4.6364760780081e-01
+atan2D(+5.9999999840000e-01) = +5.4041949909411e-01
+atan2D(+6.9999999830000e-01) = +6.1072596324827e-01
+atan2D(+7.9999999820000e-01) = +6.7474094112599e-01
+atan2D(+8.9999999810000e-01) = +7.3281510073678e-01
+atan2D(+9.9999999800000e-01) = +7.8539816239745e-01
+atan2F(         -1.0000e+00) =          -7.8540e-01
+atan2F(         -9.0010e-01) =          -7.3287e-01
+atan2F(         -8.0020e-01) =          -6.7486e-01
+atan2F(         -7.0030e-01) =          -6.1093e-01
+atan2F(         -6.0040e-01) =          -5.4071e-01
+atan2F(         -5.0050e-01) =          -4.6405e-01
+atan2F(         -4.0060e-01) =          -3.8102e-01
+atan2F(         -3.0070e-01) =          -2.9210e-01
+atan2F(         -2.0080e-01) =          -1.9816e-01
+atan2F(         -1.0090e-01) =          -1.0056e-01
+atan2F(         -9.9994e-04) =          -9.9994e-04
+atan2F(         +9.8900e-02) =          +9.8579e-02
+atan2F(         +1.9880e-01) =          +1.9624e-01
+atan2F(         +2.9870e-01) =          +2.9026e-01
+atan2F(         +3.9860e-01) =          +3.7930e-01
+atan2F(         +4.9850e-01) =          +4.6245e-01
+atan2F(         +5.9840e-01) =          +5.3924e-01
+atan2F(         +6.9830e-01) =          +6.0958e-01
+atan2F(         +7.9820e-01) =          +6.7364e-01
+atan2F(         +8.9810e-01) =          +7.3176e-01
+atan2F(         +9.9800e-01) =          +7.8440e-01
diff --git a/memcheck/tests/writev1.stderr.exp-solaris b/memcheck/tests/writev1.stderr.exp-solaris
new file mode 100644
index 0000000..b19d775
--- /dev/null
+++ b/memcheck/tests/writev1.stderr.exp-solaris
@@ -0,0 +1,19 @@
+Test file created.
+Syscall param writev(vector[...]) points to unaddressable byte(s)
+   ...
+   by 0x........: main (writev1.c:56)
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Received EFAULT as expected
+Syscall param writev(vector) points to unaddressable byte(s)
+   ...
+   by 0x........: main (writev1.c:68)
+ Address 0x........ is 0 bytes after the brk data segment limit 0x........
+
+Received EINVAL as expected
+Syscall param readv(vector) points to unaddressable byte(s)
+   ...
+   by 0x........: main (writev1.c:76)
+ Address 0x........ is 0 bytes after the brk data segment limit 0x........
+
+Received EINVAL as expected
diff --git a/memcheck/tests/x86-linux/scalar.stderr.exp b/memcheck/tests/x86-linux/scalar.stderr.exp
index 95b1e85..30cfd1c 100644
--- a/memcheck/tests/x86-linux/scalar.stderr.exp
+++ b/memcheck/tests/x86-linux/scalar.stderr.exp
@@ -415,7 +415,7 @@
    ...
    by 0x........: main (scalar.c:196)
 
-Syscall param kill(sig) contains uninitialised byte(s)
+Syscall param kill(signal) contains uninitialised byte(s)
    ...
    by 0x........: main (scalar.c:196)
 
diff --git a/memcheck/tests/x86-solaris/Makefile.am b/memcheck/tests/x86-solaris/Makefile.am
new file mode 100644
index 0000000..78ae0a7
--- /dev/null
+++ b/memcheck/tests/x86-solaris/Makefile.am
@@ -0,0 +1,30 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = filter_stderr
+
+EXTRA_DIST = \
+	scalar.stderr.exp scalar.stdout.exp scalar.vgtest \
+	scalar_obsolete.stderr.exp scalar_obsolete.stdout.exp scalar_obsolete.vgtest \
+	context_eflags.stderr.exp context_eflags.stdout.exp context_eflags.vgtest \
+	context_eflags2.stderr.exp context_eflags2.stdout.exp context_eflags2.vgtest \
+	context_fpu.stderr.exp context_fpu.stdout.exp context_fpu.vgtest \
+	context_gpr.stderr.exp context_gpr.stdout.exp context_gpr.vgtest \
+	context_sse.stderr.exp context_sse.stdout.exp context_sse.vgtest
+
+check_PROGRAMS = \
+	scalar \
+	context_eflags \
+	context_eflags2 \
+	context_fpu \
+	context_gpr \
+	context_sse
+
+if SOLARIS_OLD_SYSCALLS
+check_PROGRAMS += scalar_obsolete
+endif
+
+AM_CFLAGS    += @FLAG_M32@
+AM_CXXFLAGS  += @FLAG_M32@
+AM_CCASFLAGS += @FLAG_M32@
+
diff --git a/memcheck/tests/x86-solaris/context_eflags.c b/memcheck/tests/x86-solaris/context_eflags.c
new file mode 100644
index 0000000..63c6377
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags.c
@@ -0,0 +1,71 @@
+/* x86 variant of the amd64-solaris/context_rflags.c test. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+#define OBIT(eflags) (!!((eflags) & (1 << 11)))
+#define SBIT(eflags) (!!((eflags) & (1 << 7)))
+
+static siginfo_t si;
+static ucontext_t uc;
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   int eflags;
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set overflow and sign flags. */
+      "movl   $1, %%edx\n"
+      "addl   $0x7fffffff, %%edx\n"
+
+      /* Prepare syscall parameters. */
+      "pushl  %[sig]\n"
+      "pushl  %[pid]\n"
+      "pushl  $0xdeadbeef\n"
+      "movl   %[scall], %%eax\n"
+
+      /* Trigger the signal handler. */
+      "int    $0x91\n"
+      "pushfl\n"
+      "popl   %%edx\n"
+      "addl   $12, %%esp\n"
+      : "=d" (eflags)
+      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1)
+      : "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  overflow=%d, sign=%d\n",
+          OBIT(uc.uc_mcontext.gregs[EFL]), SBIT(uc.uc_mcontext.gregs[EFL]));
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  overflow=%d, sign=%d\n", OBIT(eflags), SBIT(eflags));
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/context_eflags.stderr.exp b/memcheck/tests/x86-solaris/context_eflags.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags.stderr.exp
diff --git a/memcheck/tests/x86-solaris/context_eflags.stdout.exp b/memcheck/tests/x86-solaris/context_eflags.stdout.exp
new file mode 100644
index 0000000..8ad7bac
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  overflow=1, sign=1
+Values after the return from the signal handler:
+  overflow=1, sign=1
diff --git a/memcheck/tests/x86-solaris/context_eflags.vgtest b/memcheck/tests/x86-solaris/context_eflags.vgtest
new file mode 100644
index 0000000..20378e9
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags.vgtest
@@ -0,0 +1,2 @@
+prog: context_eflags
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/x86-solaris/context_eflags2.c b/memcheck/tests/x86-solaris/context_eflags2.c
new file mode 100644
index 0000000..4f37693
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags2.c
@@ -0,0 +1,80 @@
+/* x86 variant of the amd64-solaris/context_rflags2.c test. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+#define OBIT(eflags) (!!((eflags) & (1 << 11)))
+#define SBIT(eflags) (!!((eflags) & (1 << 7)))
+
+static siginfo_t si;
+static ucontext_t uc;
+
+void break_out(void);
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   /* Break out of the endless loop. */
+   *(uintptr_t*)&ucp->uc_mcontext.gregs[EIP] = (uintptr_t)break_out;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   int eflags;
+   int x1;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   int *px = malloc(sizeof(*px));
+   x1 = px[0] + 1;
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGALRM, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   alarm(2);
+
+   __asm__ __volatile__(
+      /* Set overflow and sign flags. */
+      "movl   %[x1], %%edx\n"
+      "addl   $0x7fffffff, %%edx\n"
+
+      /* Loopity loop, this is where the SIGALRM is triggered. */
+      "1:\n"
+      "jmp    1b\n"
+
+      "break_out:\n"
+      "pushfl\n"
+      "popl   %%edx\n"
+      : "=d" (eflags)
+      : [x1] "m" (x1)
+      : "cc", "memory");
+
+   /* Check that the overflow and sign flags are uninitialised.
+
+      Note: This actually fails because the eflags are only approximate
+      (always initialised) in the signal handler. */
+   if (!OBIT(uc.uc_mcontext.gregs[EFL]) || !SBIT(uc.uc_mcontext.gregs[EFL]))
+      assert(0);
+
+   /* Check that the overflow and sign flags are uninitialised. */
+   if (!OBIT(eflags) || !SBIT(eflags))
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/context_eflags2.stderr.exp b/memcheck/tests/x86-solaris/context_eflags2.stderr.exp
new file mode 100644
index 0000000..ce2b2e7
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags2.stderr.exp
@@ -0,0 +1,12 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_eflags2.c:75)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_eflags2.c:35)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_eflags2.c:75)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_eflags2.c:35)
+
diff --git a/memcheck/tests/x86-solaris/context_eflags2.stdout.exp b/memcheck/tests/x86-solaris/context_eflags2.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags2.stdout.exp
diff --git a/memcheck/tests/x86-solaris/context_eflags2.vgtest b/memcheck/tests/x86-solaris/context_eflags2.vgtest
new file mode 100644
index 0000000..bd57570
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_eflags2.vgtest
@@ -0,0 +1,2 @@
+prog: context_eflags2
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/x86-solaris/context_fpu.c b/memcheck/tests/x86-solaris/context_fpu.c
new file mode 100644
index 0000000..6d618ff
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_fpu.c
@@ -0,0 +1,116 @@
+/* x86 variant of the amd64-solaris/context_fpu.c test. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+static float inhandler[8];
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   int i;
+
+   si = *sip;
+   uc = *ucp;
+
+   /* Reset the FP stack so it's possible to push other values onto it.  (It
+      is fully filled in main() before triggering the signal handler).  Note
+      that VEX also clears all FP values when the finit instruction is
+      executed.  This provides another level of validation that the restore
+      code is correct. */
+   __asm__ __volatile__(
+      "finit\n");
+
+   /* Convert 80b values in mcontext to 32b values in the inhandler array. */
+   for (i = 0; i < 8; i++) {
+      __asm__ __volatile__(
+         "fldt   %[in]\n"
+         "fstps  %[out]\n"
+         : [out] "=m" (inhandler[i])
+         : [in] "m" (*((char*)&ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state
+                       + 28 + i * 10)));
+   }
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   float out[8];
+   float x0;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   float *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set values in the FP stack. */
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+      "flds   %[x0]\n"
+      "fld1\n"
+
+      /* Prepare syscall parameters. */
+      "pushl  %[sig]\n"
+      "pushl  %[pid]\n"
+      "pushl  $0xdeadbeef\n"
+      "movl   %[scall], %%eax\n"
+
+      /* Trigger the signal handler. */
+      "int    $0x91\n"
+      "addl   $12, %%esp\n"
+      "fstps  0x00 + %[out]\n"
+      "fstps  0x04 + %[out]\n"
+      "fstps  0x08 + %[out]\n"
+      "fstps  0x0c + %[out]\n"
+      "fstps  0x10 + %[out]\n"
+      "fstps  0x14 + %[out]\n"
+      "fstps  0x18 + %[out]\n"
+      "fstps  0x1c + %[out]\n"
+      : [out] "=m" (out[0])
+      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1),
+        [x0] "m" (x0)
+      : "edx", "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
+          inhandler[0], inhandler[2], inhandler[4], inhandler[6]);
+   /* Check that inhandler[1], inhandler[3], inhandler[5] and inhandler[7]
+      contain uninitialised values (origin is px[0]). */
+   if (inhandler[1] || inhandler[3] || inhandler[5] || inhandler[7])
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  fp[0]=%f, fp[2]=%f, fp[4]=%f, fp[6]=%f\n",
+          out[0], out[2], out[4], out[6]);
+   /* Check that out[1], out[3], out[5] and out[7] contain uninitialised
+      values (origin is px[0]). */
+   if (out[1] || out[3] || out[5] || out[7])
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/context_fpu.stderr.exp b/memcheck/tests/x86-solaris/context_fpu.stderr.exp
new file mode 100644
index 0000000..d770097
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_fpu.stderr.exp
@@ -0,0 +1,96 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:103)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_fpu.c:111)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_fpu.c:49)
+
diff --git a/memcheck/tests/x86-solaris/context_fpu.stdout.exp b/memcheck/tests/x86-solaris/context_fpu.stdout.exp
new file mode 100644
index 0000000..2c3bf1d
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_fpu.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  fp[0]=1.000000, fp[2]=1.000000, fp[4]=1.000000, fp[6]=1.000000
+Values after the return from the signal handler:
+  fp[0]=1.000000, fp[2]=1.000000, fp[4]=1.000000, fp[6]=1.000000
diff --git a/memcheck/tests/x86-solaris/context_fpu.vgtest b/memcheck/tests/x86-solaris/context_fpu.vgtest
new file mode 100644
index 0000000..8a3955d
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_fpu.vgtest
@@ -0,0 +1,2 @@
+prog: context_fpu
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/x86-solaris/context_gpr.c b/memcheck/tests/x86-solaris/context_gpr.c
new file mode 100644
index 0000000..6535ea3
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_gpr.c
@@ -0,0 +1,92 @@
+/* x86 variant of the amd64-solaris/context_gpr.c test. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+/* x0 is always zero, but is visible to Valgrind as uninitialised. */
+static int x0;
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   ucp->uc_mcontext.gregs[ECX] = x0;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   int eax, ebx, ecx, edx, esi, edi;
+   int y0;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   int *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   /* Uninitialised, but we know py[0] is 0x0. */
+   int *py = malloc(sizeof(*py));
+   y0 = py[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set values in general purpose registers. */
+      "movl   %[y0], %%ebx\n"
+      "movl   $0xf1, %%ecx\n"
+      "movl   $0xf2, %%edx\n"
+      "movl   $0xf3, %%esi\n"
+      "movl   $0xf4, %%edi\n"
+
+      /* Prepare syscall parameters. */
+      "pushl  %[sig]\n"
+      "pushl  %[pid]\n"
+      "pushl  $0xdeadbeef\n"
+      "movl   %[scall], %%eax\n"
+
+      /* Trigger the signal handler. */
+      "int    $0x91\n"
+      "addl   $12, %%esp\n"
+      : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx), "=S" (esi),
+        "=D" (edi)
+      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1),
+        [y0] "m" (y0)
+      : "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  eax=%#x, edx=%#x, esi=%#x, edi=%#x\n",
+          uc.uc_mcontext.gregs[EAX], uc.uc_mcontext.gregs[EDX],
+          uc.uc_mcontext.gregs[ESI], uc.uc_mcontext.gregs[EDI]);
+   /* Check that ebx contains an uninitialised value (origin is py[0]). */
+   if (uc.uc_mcontext.gregs[EBX])
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  eax=%#x, edx=%#x, esi=%#x, edi=%#x\n", eax, edx, esi, edi);
+   /* Check that ebx and ecx contain uninitialised values (origin is py[0]
+      and px[0], respectively). */
+   if (ebx || ecx)
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/context_gpr.stderr.exp b/memcheck/tests/x86-solaris/context_gpr.stderr.exp
new file mode 100644
index 0000000..0f24498
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_gpr.stderr.exp
@@ -0,0 +1,18 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:80)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:36)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:36)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_gpr.c:87)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_gpr.c:32)
+
diff --git a/memcheck/tests/x86-solaris/context_gpr.stdout.exp b/memcheck/tests/x86-solaris/context_gpr.stdout.exp
new file mode 100644
index 0000000..e8ff239
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_gpr.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  eax=0, edx=0, esi=0xf3, edi=0xf4
+Values after the return from the signal handler:
+  eax=0, edx=0, esi=0xf3, edi=0xf4
diff --git a/memcheck/tests/x86-solaris/context_gpr.vgtest b/memcheck/tests/x86-solaris/context_gpr.vgtest
new file mode 100644
index 0000000..df56f58
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_gpr.vgtest
@@ -0,0 +1,2 @@
+prog: context_gpr
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/x86-solaris/context_sse.c b/memcheck/tests/x86-solaris/context_sse.c
new file mode 100644
index 0000000..adea470
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_sse.c
@@ -0,0 +1,106 @@
+/* x86 variant of the amd64-solaris/context_sse.c test. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/ucontext.h>
+
+static siginfo_t si;
+static ucontext_t uc;
+/* x0 is always zero, but is visible to Valgrind as uninitialised. */
+static upad128_t x0;
+static upad128_t d0 = {0};
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   si = *sip;
+   uc = *ucp;
+
+   ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[0] = d0;
+   ucp->uc_mcontext.fpregs.fp_reg_set.fpchip_state.xmm[1] = x0;
+}
+
+int main(void)
+{
+   struct sigaction sa;
+   pid_t pid;
+   upad128_t out[8];
+   upad128_t y0;
+   struct fpchip_state *fs = &uc.uc_mcontext.fpregs.fp_reg_set.fpchip_state;
+
+   /* Uninitialised, but we know px[0] is 0x0. */
+   upad128_t *px = malloc(sizeof(*px));
+   x0 = px[0];
+
+   /* Uninitialised, but we know py[0] is 0x0. */
+   upad128_t *py = malloc(sizeof(*py));
+   y0 = py[0];
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   pid = getpid();
+
+   __asm__ __volatile__(
+      /* Set values in the SSE registers. */
+      "movups %[y0], %%xmm0\n"
+      "movups %[d0], %%xmm1\n"
+      "movups %[d0], %%xmm2\n"
+      "movups %[y0], %%xmm3\n"
+      "movups %[y0], %%xmm4\n"
+      "movups %[d0], %%xmm5\n"
+      "movups %[d0], %%xmm6\n"
+      "movups %[y0], %%xmm7\n"
+
+      /* Prepare syscall parameters. */
+      "pushl  %[sig]\n"
+      "pushl  %[pid]\n"
+      "pushl  $0xdeadbeef\n"
+      "movl   %[scall], %%eax\n"
+
+      /* Trigger the signal handler. */
+      "int    $0x91\n"
+      "addl   $12, %%esp\n"
+      "movups %%xmm0, 0x00 + %[out]\n"
+      "movups %%xmm1, 0x10 + %[out]\n"
+      "movups %%xmm2, 0x20 + %[out]\n"
+      "movups %%xmm3, 0x30 + %[out]\n"
+      "movups %%xmm4, 0x40 + %[out]\n"
+      "movups %%xmm5, 0x50 + %[out]\n"
+      "movups %%xmm6, 0x60 + %[out]\n"
+      "movups %%xmm7, 0x70 + %[out]\n"
+      : [out] "=m" (out[0])
+      : [scall] "i" (SYS_kill), [pid] "a" (pid), [sig] "i" (SIGUSR1),
+        [y0] "m" (y0), [d0] "m" (d0)
+      : "edx", "cc", "memory");
+
+   printf("Values in the signal handler:\n");
+   printf("  xmm1=%Lf, xmm2=%Lf, xmm5=%Lf, xmm6=%Lf\n",
+          fs->xmm[1]._q, fs->xmm[2]._q, fs->xmm[5]._q, fs->xmm[6]._q);
+   /* Check that fs->xmm[0], fs->xmm[3], fs->xmm[4] and fs->xmm[7] contain
+      uninitialised values (origin is py[0]). */
+   if (fs->xmm[0]._q || fs->xmm[3]._q || fs->xmm[4]._q || fs->xmm[7]._q)
+      assert(0);
+
+   printf("Values after the return from the signal handler:\n");
+   printf("  xmm0=%Lf, xmm2=%Lf, xmm5=%Lf, xmm6=%Lf\n",
+          out[0]._q, out[2]._q, out[5]._q, out[6]._q);
+   /* Check that out[1], out[3], out[4] and out[7] contain uninitialised
+      values (origin is px[0]). */
+   if (out[1]._q || out[3]._q || out[4]._q || out[7]._q)
+      assert(0);
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/context_sse.stderr.exp b/memcheck/tests/x86-solaris/context_sse.stderr.exp
new file mode 100644
index 0000000..d7d5614
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_sse.stderr.exp
@@ -0,0 +1,96 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:93)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:35)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:35)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (context_sse.c:101)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (context_sse.c:39)
+
diff --git a/memcheck/tests/x86-solaris/context_sse.stdout.exp b/memcheck/tests/x86-solaris/context_sse.stdout.exp
new file mode 100644
index 0000000..2cefcc8
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_sse.stdout.exp
@@ -0,0 +1,4 @@
+Values in the signal handler:
+  xmm1=0.000000, xmm2=0.000000, xmm5=0.000000, xmm6=0.000000
+Values after the return from the signal handler:
+  xmm0=0.000000, xmm2=0.000000, xmm5=0.000000, xmm6=0.000000
diff --git a/memcheck/tests/x86-solaris/context_sse.vgtest b/memcheck/tests/x86-solaris/context_sse.vgtest
new file mode 100644
index 0000000..97d6be1
--- /dev/null
+++ b/memcheck/tests/x86-solaris/context_sse.vgtest
@@ -0,0 +1,2 @@
+prog: context_sse
+vgopts: -q --track-origins=yes
diff --git a/memcheck/tests/x86-solaris/filter_stderr b/memcheck/tests/x86-solaris/filter_stderr
new file mode 100755
index 0000000..a778e97
--- /dev/null
+++ b/memcheck/tests/x86-solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr "$@"
diff --git a/memcheck/tests/x86-solaris/scalar.c b/memcheck/tests/x86-solaris/scalar.c
new file mode 100644
index 0000000..3894d2f
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar.c
@@ -0,0 +1,116 @@
+/* Basic syscall test for Solaris/x86 specific syscalls. */
+
+#include "../solaris/scalar.h"
+
+#include <string.h>
+#include <sys/fcntl.h>
+#include <sys/statvfs.h>
+
+/* Helper functions.  These are necessary if we've got two tests for a single
+   syscall.  In that case, Memcheck can sometimes merge error messages.  Doing
+   each test in its own function prevents that. */
+__attribute__((noinline))
+static void sys_openat64(void)
+{
+   GO(SYS_openat64, "(3-args) 3s 1m");
+   SY(SYS_openat64, x0 - 1, x0, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_openat642(void)
+{
+   GO(SYS_openat64, "(4-args) 4s 1m");
+   SY(SYS_openat64, x0 - 1, x0, x0 | O_CREAT, x0); FAILx(EBADF);
+}
+
+__attribute__((noinline))
+static void sys_statvfs64(void)
+{
+   GO(SYS_statvfs64, "2s 2m");
+   SY(SYS_statvfs64, x0 + 1, x0 + 1); FAIL;
+}
+
+__attribute__((noinline))
+static int sys_statvfs642(void)
+{
+   const char path[] = "/";
+   struct statvfs64 stats;
+
+   GO(SYS_statvfs64, "4s 0m");
+   SY(SYS_statvfs64, x0 + path, x0 + &stats); SUCC;
+
+   size_t basetype_len = strlen(stats.f_basetype);
+   size_t fstr_len = strlen(stats.f_fstr);
+
+   /* Now check that memory after the strings is reported uninitialized. */
+   int x = 0;
+   if (stats.f_basetype[basetype_len + 2] != ' ') x = -1; else x = -2;
+   if (stats.f_fstr[fstr_len + 2] != ' ') x = -3; else x = -4;
+   return x;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_fstatat64              67 */
+   GO(SYS_fstatat64, "4s 2m");
+   SY(SYS_fstatat64, x0 - 1, x0 + 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_openat64               69 */
+   sys_openat64();
+   sys_openat642();
+
+   /* SYS_llseek                175 */
+   GO(SYS_llseek, "3s 0m");
+   SY(SYS_llseek, x0 - 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_getdents64            213 */
+   GO(SYS_getdents64, "3s 1m");
+   SY(SYS_getdents64, x0, x0, x0 + 1); FAIL;
+
+   /* SYS_mmap64                214 */
+   GO(SYS_mmap64, "7s 0m");
+   SY(SYS_mmap64, x0, x0, x0, x0, x0, x0, x0); FAILx(EINVAL);
+
+   /* SYS_stat64                215 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_lstat64               216 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_fstat64               217 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   /* SYS_statvfs64             218 */
+   sys_statvfs64();
+   sys_statvfs642();
+
+   /* SYS_fstatvfs64            219 */
+   GO(SYS_fstatvfs64, "2s 1m");
+   SY(SYS_fstatvfs64, x0 - 1, x0 + 1); FAILx(EBADF);
+
+   /* SYS_setrlimit64           220 */
+   GO(SYS_setrlimit64, "2s 1m");
+   SY(SYS_setrlimit64, x0, x0); FAIL;
+
+   /* SYS_getrlimit64           221 */
+   GO(SYS_getrlimit64, "2s 1m");
+   SY(SYS_getrlimit64, x0, x0); FAIL;
+
+   /* SYS_pread64               222 */
+   GO(SYS_pread64, "5s 1m");
+   SY(SYS_pread64, x0 - 1, x0, x0 + 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_pwrite64              223 */
+   GO(SYS_pwrite64, "5s 1m");
+   SY(SYS_pwrite64, x0 - 1, x0, x0 + 1, x0, x0); FAILx(EBADF);
+
+   /* SYS_open64                225 */
+   /* Tested in x86-solaris/scalar_obsolete.c. */
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/scalar.stderr.exp b/memcheck/tests/x86-solaris/scalar.stderr.exp
new file mode 100644
index 0000000..6599aaf
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar.stderr.exp
@@ -0,0 +1,225 @@
+---------------------------------------------------------
+ 67:           SYS_fstatat64 4s 2m
+---------------------------------------------------------
+Syscall param fstatat64(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat64(path) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat64(flag) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatat64(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param fstatat64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 69:            SYS_openat64 (3-args) 3s 1m
+---------------------------------------------------------
+Syscall param openat64(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+ 69:            SYS_openat64 (4-args) 4s 1m
+---------------------------------------------------------
+Syscall param openat64(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param openat64(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+175:              SYS_llseek 3s 0m
+---------------------------------------------------------
+Syscall param llseek(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param llseek(offset_low) contains uninitialised byte(s)
+   ...
+
+Syscall param llseek(offset_high) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+213:          SYS_getdents64 3s 1m
+---------------------------------------------------------
+Syscall param getdents64(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents64(dirp) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents64(count) contains uninitialised byte(s)
+   ...
+
+Syscall param getdents64(dirp) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+214:              SYS_mmap64 7s 0m
+---------------------------------------------------------
+Syscall param mmap(start) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(length) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(prot) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(offlo) contains uninitialised byte(s)
+   ...
+
+Syscall param mmap(offhi) contains uninitialised byte(s)
+   ...
+
+---------------------------------------------------------
+218:           SYS_statvfs64 2s 2m
+---------------------------------------------------------
+Syscall param statvfs64(path) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs64(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param statvfs64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+218:           SYS_statvfs64 4s 0m
+---------------------------------------------------------
+Syscall param statvfs64(path) contains uninitialised byte(s)
+   ...
+
+Syscall param statvfs64(buf) contains uninitialised byte(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+Conditional jump or move depends on uninitialised value(s)
+   ...
+
+---------------------------------------------------------
+219:          SYS_fstatvfs64 2s 1m
+---------------------------------------------------------
+Syscall param fstatvfs64(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatvfs64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstatvfs64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+220:         SYS_setrlimit64 2s 1m
+---------------------------------------------------------
+Syscall param setrlimit64(resource) contains uninitialised byte(s)
+   ...
+
+Syscall param setrlimit64(rlim) contains uninitialised byte(s)
+   ...
+
+Syscall param setrlimit64(rlim) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+221:         SYS_getrlimit64 2s 1m
+---------------------------------------------------------
+Syscall param getrlimit64(resource) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimit64(rlim) contains uninitialised byte(s)
+   ...
+
+Syscall param getrlimit64(rlim) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+222:             SYS_pread64 5s 1m
+---------------------------------------------------------
+Syscall param pread64(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param pread64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param pread64(count) contains uninitialised byte(s)
+   ...
+
+Syscall param pread64(offset_1) contains uninitialised byte(s)
+   ...
+
+Syscall param pread64(offset_2) contains uninitialised byte(s)
+   ...
+
+Syscall param pread64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+223:            SYS_pwrite64 5s 1m
+---------------------------------------------------------
+Syscall param pwrite64(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite64(count) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite64(offset_1) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite64(offset_2) contains uninitialised byte(s)
+   ...
+
+Syscall param pwrite64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/x86-solaris/scalar.stdout.exp b/memcheck/tests/x86-solaris/scalar.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar.stdout.exp
diff --git a/memcheck/tests/x86-solaris/scalar.vgtest b/memcheck/tests/x86-solaris/scalar.vgtest
new file mode 100644
index 0000000..b80f314
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar.vgtest
@@ -0,0 +1,3 @@
+prog: scalar
+vgopts: -q --error-limit=no
+stderr_filter_args:
diff --git a/memcheck/tests/x86-solaris/scalar_obsolete.c b/memcheck/tests/x86-solaris/scalar_obsolete.c
new file mode 100644
index 0000000..ecb68e0
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar_obsolete.c
@@ -0,0 +1,49 @@
+/* Test for syscalls that are available on illumos but are removed on
+   Solaris 11.  This test is compiled only on illumos. */
+
+#include "../solaris/scalar.h"
+
+#include <sys/fcntl.h>
+
+/* Helper functions.  These are necessary if we've got two tests for a single
+   syscall.  In that case, Memcheck can sometimes merge error messages.  Doing
+   each test in its own function prevents that. */
+__attribute__((noinline))
+static void sys_open64(void)
+{
+   GO(SYS_open64, "(2-args) 2s 1m");
+   SY(SYS_open64, x0, x0); FAIL;
+}
+
+__attribute__((noinline))
+static void sys_open642(void)
+{
+   GO(SYS_open64, "(3-args) 3s 1m");
+   SY(SYS_open64, x0, x0 | O_CREAT, x0); FAIL;
+}
+
+int main(void)
+{
+   /* Uninitialised, but we know px[0] is 0x0. */
+   long *px = malloc(sizeof(long));
+   x0 = px[0];
+
+   /* SYS_stat64                215 */
+   GO(SYS_stat64, "2s 2m");
+   SY(SYS_stat64, x0, x0); FAIL;
+
+   /* SYS_lstat64               216 */
+   GO(SYS_lstat64, "2s 2m");
+   SY(SYS_lstat64, x0, x0); FAIL;
+
+   /* SYS_fstat64               217 */
+   GO(SYS_fstat64, "2s 1m");
+   SY(SYS_fstat64, x0, x0); FAIL;
+
+   /* SYS_open64                225 */
+   sys_open64();
+   sys_open642();
+
+   return 0;
+}
+
diff --git a/memcheck/tests/x86-solaris/scalar_obsolete.stderr.exp b/memcheck/tests/x86-solaris/scalar_obsolete.stderr.exp
new file mode 100644
index 0000000..6050717
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar_obsolete.stderr.exp
@@ -0,0 +1,76 @@
+---------------------------------------------------------
+215:              SYS_stat64 2s 2m
+---------------------------------------------------------
+Syscall param stat64(path) contains uninitialised byte(s)
+   ...
+
+Syscall param stat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param stat64(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param stat64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+216:             SYS_lstat64 2s 2m
+---------------------------------------------------------
+Syscall param lstat64(path) contains uninitialised byte(s)
+   ...
+
+Syscall param lstat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param lstat64(path) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+Syscall param lstat64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+217:             SYS_fstat64 2s 1m
+---------------------------------------------------------
+Syscall param fstat64(fildes) contains uninitialised byte(s)
+   ...
+
+Syscall param fstat64(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param fstat64(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+225:              SYS_open64 (2-args) 2s 1m
+---------------------------------------------------------
+Syscall param open64(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param open64(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param open(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
+---------------------------------------------------------
+225:              SYS_open64 (3-args) 3s 1m
+---------------------------------------------------------
+Syscall param open64(filename) contains uninitialised byte(s)
+   ...
+
+Syscall param open64(flags) contains uninitialised byte(s)
+   ...
+
+Syscall param open64(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param open(filename) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+
diff --git a/memcheck/tests/x86-solaris/scalar_obsolete.stdout.exp b/memcheck/tests/x86-solaris/scalar_obsolete.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar_obsolete.stdout.exp
diff --git a/memcheck/tests/x86-solaris/scalar_obsolete.vgtest b/memcheck/tests/x86-solaris/scalar_obsolete.vgtest
new file mode 100644
index 0000000..4541cb9
--- /dev/null
+++ b/memcheck/tests/x86-solaris/scalar_obsolete.vgtest
@@ -0,0 +1,4 @@
+prereq: test -e scalar_obsolete
+prog: scalar_obsolete
+vgopts: -q --error-limit=no
+stderr_filter_args:
diff --git a/memcheck/tests/x86/pushfpopf_s.S b/memcheck/tests/x86/pushfpopf_s.S
index 067a6da..7b219f6 100644
--- a/memcheck/tests/x86/pushfpopf_s.S
+++ b/memcheck/tests/x86/pushfpopf_s.S
@@ -1,13 +1,13 @@
 #include "tests/asm.h"
 
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 	.version	"01.01"
 #endif
 gcc2_compiled.:
 .text
 	.align 4
 .globl VG_SYM_ASM(fooble)
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 	.type	VG_SYM_ASM(fooble),@function
 #endif
 VG_SYM_ASM(fooble):
@@ -42,7 +42,7 @@
 	popl	%ebp
 	ret
 .Lfe1:
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 	.size	VG_SYM_ASM(fooble),.Lfe1-VG_SYM_ASM(fooble)
 #endif
 	.ident	"GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-98)"
diff --git a/memcheck/tests/x86/tronical.S b/memcheck/tests/x86/tronical.S
index a2122c7..e5bb400 100644
--- a/memcheck/tests/x86/tronical.S
+++ b/memcheck/tests/x86/tronical.S
@@ -52,7 +52,7 @@
 #include "tests/asm.h"
 
 	.file	"tronical.c"
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 	.version	"01.01"
 #endif
 gcc2_compiled.:
diff --git a/memcheck/tests/xml1.c b/memcheck/tests/xml1.c
index 6cab287..0cbbb03 100644
--- a/memcheck/tests/xml1.c
+++ b/memcheck/tests/xml1.c
@@ -46,7 +46,15 @@
 
 int main ( void )
 {
-  return frame1() - 1;
+  int ret = frame1() - 1;
+
+#if defined(VGO_solaris)
+  /* Avoid reporting possible memory leak on finish when both FILE->base
+     and FILE->ptr point to the middle of a buffer allocated in _findbuf()
+     for stdout. */
+  fcloseall();
+#endif
+  return ret;
 }
 
 /*
diff --git a/mpi/Makefile.am b/mpi/Makefile.am
index c15680b..fca5d64 100644
--- a/mpi/Makefile.am
+++ b/mpi/Makefile.am
@@ -42,6 +42,10 @@
  MPI_FLAG_M3264_PRI = $(AM_FLAG_M3264_PRI)
  MPI_FLAG_M3264_SEC = $(AM_FLAG_M3264_SEC)
 endif
+if VGCONF_OS_IS_SOLARIS
+ MPI_FLAG_M3264_PRI = $(AM_FLAG_M3264_PRI)
+ MPI_FLAG_M3264_SEC = $(AM_FLAG_M3264_SEC)
+endif
 
 
 if BUILD_MPIWRAP_PRI
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index dd5959e..dd7f1d7 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -43,6 +43,9 @@
 if VGCONF_OS_IS_DARWIN
 SUBDIRS += darwin
 endif
+if VGCONF_OS_IS_SOLARIS
+SUBDIRS += solaris
+endif
 
 # Platform-specific tests
 if VGCONF_PLATFORMS_INCLUDE_AMD64_LINUX
@@ -51,17 +54,22 @@
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 SUBDIRS += x86-linux
 endif
-
 if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
 SUBDIRS += amd64-darwin
 endif
 if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
 SUBDIRS += x86-darwin
 endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_SOLARIS
+SUBDIRS += amd64-solaris
+endif
+if VGCONF_PLATFORMS_INCLUDE_X86_SOLARIS
+SUBDIRS += x86-solaris
+endif
 
 DIST_SUBDIRS = x86 amd64 ppc32 ppc64 arm arm64 s390x mips32 mips64 tilegx \
-	       linux darwin amd64-linux x86-linux amd64-darwin \
-	       x86-darwin scripts .
+               linux darwin solaris amd64-linux x86-linux amd64-darwin \
+               x86-darwin amd64-solaris x86-solaris scripts .
 
 dist_noinst_SCRIPTS = \
 	filter_cmdline0 \
@@ -102,7 +110,8 @@
 	discard.vgtest \
 	empty-exe.vgtest empty-exe.stderr.exp \
 	exec-sigmask.vgtest exec-sigmask.stdout.exp \
-	exec-sigmask.stdout.exp2 exec-sigmask.stdout.exp3 exec-sigmask.stderr.exp \
+	exec-sigmask.stdout.exp2 exec-sigmask.stdout.exp3 \
+	exec-sigmask.stdout.exp-solaris exec-sigmask.stderr.exp \
 	execve.vgtest execve.stdout.exp execve.stderr.exp \
 	faultstatus.vgtest faultstatus.stderr.exp faultstatus.stderr.exp-s390x \
 	fcntl_setown.vgtest fcntl_setown.stdout.exp fcntl_setown.stderr.exp \
@@ -160,6 +169,7 @@
 	require-text-symbol-1.vgtest \
 		require-text-symbol-1.stderr.exp \
 	require-text-symbol-2.vgtest \
+		require-text-symbol-2.stderr.exp-libcso1 \
 		require-text-symbol-2.stderr.exp-libcso6 \
 	res_search.stderr.exp res_search.stdout.exp res_search.vgtest \
 	resolv.stderr.exp resolv.stdout.exp resolv.vgtest \
@@ -250,6 +260,14 @@
 # Extra stuff for C tests
 ansi_CFLAGS		= $(AM_CFLAGS) -ansi
 execve_CFLAGS		= $(AM_CFLAGS) @FLAG_W_NO_NONNULL@
+if VGCONF_OS_IS_SOLARIS
+fcntl_setown_LDADD	= -lsocket -lnsl
+fdleak_cmsg_CFLAGS	= $(AM_CFLAGS) -D_XOPEN_SOURCE=500
+fdleak_cmsg_LDADD	= -lsocket -lnsl
+fdleak_ipv4_LDADD	= -lsocket -lnsl
+fdleak_creat_LDADD	= -lsocket -lnsl
+fdleak_socketpair_LDADD	= -lsocket -lnsl
+endif
 floored_LDADD 		= -lm
 manythreads_LDADD	= -lpthread
 if VGCONF_OS_IS_DARWIN
@@ -278,13 +296,29 @@
 pth_mutexspeed_LDADD	= -lpthread
 pth_once_LDADD		= -lpthread
 pth_rwlock_LDADD	= -lpthread
+pth_rwlock_CFLAGS	= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+pth_rwlock_CFLAGS	+= --std=c99
+endif
 pth_stackalign_LDADD	= -lpthread
 res_search_LDADD        = -lresolv -lpthread
+resolv_CFLAGS		= $(AM_CFLAGS)
 resolv_LDADD            = -lresolv -lpthread
+if VGCONF_OS_IS_SOLARIS
+resolv_CFLAGS		+= -U_REENTRANT
+endif
 semlimit_LDADD		= -lpthread
+sha1_test_CFLAGS	= $(AM_CFLAGS)
+if VGCONF_OS_IS_SOLARIS
+sha1_test_CFLAGS	+= -Du_int32_t=uint32_t
+endif
 thread_exits_LDADD	= -lpthread
 threaded_fork_LDADD	= -lpthread
+threadederrno_CFLAGS	= $(AM_CFLAGS)
 threadederrno_LDADD	= -lpthread
+if VGCONF_OS_IS_SOLARIS
+threadederrno_CFLAGS	+= --std=c99
+endif
 tls_SOURCES		= tls.c tls2.c
 tls_DEPENDENCIES	= tls.so tls2.so
 tls_LDFLAGS		= -Wl,-rpath,$(abs_top_builddir)/none/tests
diff --git a/none/tests/allexec.c b/none/tests/allexec.c
index 527c36e..69e1208 100644
--- a/none/tests/allexec.c
+++ b/none/tests/allexec.c
@@ -19,9 +19,15 @@
 
 void test_allexec (char *exec)
 {
-   FORKEXECWAIT (execlp(exec, exec, NULL));
-   FORKEXECWAIT (execlp(exec, exec, "constant_arg1", "constant_arg2", NULL));
-   FORKEXECWAIT (execve(exec, NULL, environ));
+   FORKEXECWAIT (execlp(exec, exec, (char *) NULL));
+   FORKEXECWAIT (execlp(exec, exec, "constant_arg1", "constant_arg2",
+                        (char *) NULL));
+   {
+      /* Solaris requires that the argv parameter to execve() isn't NULL, so
+         set it.  Note that this isn't necessary on Linux. */
+      char *const argv[] = {exec, NULL};
+      FORKEXECWAIT (execve(exec, argv, environ));
+   }
 }
 
 
diff --git a/none/tests/amd64-solaris/Makefile.am b/none/tests/amd64-solaris/Makefile.am
new file mode 100644
index 0000000..3830fbe
--- /dev/null
+++ b/none/tests/amd64-solaris/Makefile.am
@@ -0,0 +1,24 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+	coredump_single_thread_mdb \
+	coredump_single_thread_sse_mdb \
+	filter_stderr
+
+EXTRA_DIST = \
+	coredump_single_thread.post.exp coredump_single_thread.stderr.exp \
+	coredump_single_thread.stdout.exp coredump_single_thread.vgtest \
+	coredump_single_thread_sse.post.exp coredump_single_thread_sse.stderr.exp \
+	coredump_single_thread_sse.stdout.exp coredump_single_thread_sse.vgtest \
+	syscall_return_args.stderr.exp syscall_return_args.vgtest
+
+check_PROGRAMS = \
+	coredump_single_thread \
+	coredump_single_thread_sse \
+	syscall_return_args
+
+AM_CFLAGS    += @FLAG_M64@
+AM_CXXFLAGS  += @FLAG_M64@
+AM_CCASFLAGS += @FLAG_M64@
+
diff --git a/none/tests/amd64-solaris/coredump_single_thread.c b/none/tests/amd64-solaris/coredump_single_thread.c
new file mode 100644
index 0000000..230ab06
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread.c
@@ -0,0 +1,46 @@
+/* Tests that Valgrind coredump support works correctly by producing
+   a core dump analyzable by mdb. */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+__attribute__((noinline))
+static void inner(void)
+{
+   /* Set registers to apriori known values. */
+   __asm__ __volatile__(
+      "movq $0x101, %%rax\n"
+      "movq $0x102, %%rbx\n"
+      "movq $0x103, %%rcx\n"
+      "movq $0x104, %%rdx\n"
+      "movq $0x105, %%rsi\n"
+      "movq $0x106, %%rdi\n"
+      "movq $0x107, %%r8\n"
+      "movq $0x108, %%r9\n"
+      "movq $0x109, %%r10\n"
+      "movq $0x10a, %%r11\n"
+      "movq $0x10b, %%r12\n"
+      "movq $0x10c, %%r13\n"
+      "movq $0x10d, %%r14\n"
+      "movq $0x10e, %%r15\n"
+      // not %rbp as mdb is then not able to reconstruct stack trace
+      "movq $0x10f, %%rsp\n"
+      "movq $0x1234, (%%rax)\n"  // should cause SEGV here
+      "ud2"                      // should never get here
+      : // no output registers
+      : // no input registers
+      : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+        "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%rsp");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+   inner();
+}
+
+int main(int argc, const char *argv[])
+{
+   outer();
+   return 0;
+}
diff --git a/none/tests/amd64-solaris/coredump_single_thread.post.exp b/none/tests/amd64-solaris/coredump_single_thread.post.exp
new file mode 100644
index 0000000..a5aa542
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread.post.exp
@@ -0,0 +1,29 @@
+---Status---
+debugging core file of coredump_single (64-bit) from ...
+initial argv: ./coredump_single_thread
+threading model: native threads
+status: process terminated by SIGSEGV (Segmentation Fault), addr=........
+
+---Registers---
+%rax = 0x0000000000000101       %r8  = 0x0000000000000107
+%rbx = 0x0000000000000102       %r9  = 0x0000000000000108
+%rcx = 0x0000000000000103       %r10 = 0x0000000000000109
+%rdx = 0x0000000000000104       %r11 = 0x000000000000010a
+%rsi = 0x0000000000000105       %r12 = 0x000000000000010b
+%rdi = 0x0000000000000106       %r13 = 0x000000000000010c
+                                %r14 = 0x000000000000010d
+                                %r15 = 0x000000000000010e
+
+
+%rip = 0x........  coredump_single_thread`inner+0x........
+%rsp = 0x000000000000010f
+
+
+%trapno = 0x0
+   %err = 0x0
+
+---Stack trace---
+coredump_single_thread`inner
+coredump_single_thread`outer
+coredump_single_thread`main
+coredump_single_thread`_start
diff --git a/none/tests/amd64-solaris/coredump_single_thread.stderr.exp b/none/tests/amd64-solaris/coredump_single_thread.stderr.exp
new file mode 100644
index 0000000..e26e25b
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread.stderr.exp
@@ -0,0 +1,9 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: inner (coredump_single_thread.c:11)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
diff --git a/none/tests/amd64-solaris/coredump_single_thread.stdout.exp b/none/tests/amd64-solaris/coredump_single_thread.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread.stdout.exp
diff --git a/none/tests/amd64-solaris/coredump_single_thread.vgtest b/none/tests/amd64-solaris/coredump_single_thread.vgtest
new file mode 100644
index 0000000..77604a0
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread.vgtest
@@ -0,0 +1,5 @@
+prereq: rm -f vgcore.*
+prog: coredump_single_thread
+vgopts: -q
+post: ./coredump_single_thread_mdb
+cleanup: rm -f vgcore.*
diff --git a/none/tests/amd64-solaris/coredump_single_thread_mdb b/none/tests/amd64-solaris/coredump_single_thread_mdb
new file mode 100755
index 0000000..00b864f
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_mdb
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+# Filters are not run for post-test check commands.
+# Filter everything here.
+
+echo "---Status---"
+echo "::status" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/from \S*$/from .../' | \
+perl -0 -p -e 's/^file: .+?^(initial argv:)/$1/ms' | \
+perl -p -e 's/addr=[0-9A-Fa-f]+/addr=......../g'
+
+echo "\n---Registers---"
+echo "::regs" | /usr/bin/mdb vgcore.* | \
+sed '/^%cs =/ d' | \
+sed '/^%ds =/ d' | \
+perl -p -e 's/%rip\s+=\s+0x[0-9A-Fa-f]+(.*)\+0x[0-9A-Fa-f]+$/%rip = 0x........ $1+0x......../' | \
+sed '/^%rbp/ d' | \
+sed '/^%rflags/ d' | \
+sed '/id=/ d' | \
+sed '/status=/ d' | \
+sed '/^%gsbase = / d' | \
+sed '/^%fsbase = / d' \
+
+echo "\n---Stack trace---"
+echo "::stack ! perl -p -e 's/^(\S+)\+.*/\$1/g'" | /usr/bin/mdb vgcore.*
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse.c b/none/tests/amd64-solaris/coredump_single_thread_sse.c
new file mode 100644
index 0000000..3f25b78
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse.c
@@ -0,0 +1,65 @@
+/* Tests that Valgrind coredump support for XMM registers works correctly
+   by producing a core dump analyzable by mdb.
+   Basic register set is tested in coredump_single_thread. */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+__attribute__((noinline))
+static void inner(void) {
+   const char *input =
+   "\x12\x34\x56\x78\x9a\xbc\xde\xf0\xfe\xdb\xca\x98\x76\x54\x32\x10"
+   "\x23\x45\x67\x89\x09\x87\x65\x43\x21\xfe\xdc\xba\x94\x67\xfe\xca"
+   "\xab\xcd\xab\xcd\xce\xde\xce\xde\xfa\xba\xfa\xba\x50\x65\x67\x54"
+   "\x03\x05\x06\x08\x1d\x1b\x4b\x15\x25\x27\x21\x20\x37\x3a\x3d\x35"
+   "\x9a\xbc\xde\xf0\x76\x54\x32\x10\x12\x34\x56\x78\xfe\xdb\xca\x98"
+   "\x94\x67\xfe\xca\x23\x45\x67\x89\x21\xfe\xdc\xba\x09\x87\x65\x43"
+   "\x50\x65\x67\x54\xce\xde\xce\xde\xab\xcd\xab\xcd\xfa\xba\xfa\xba"
+   "\x37\x3a\x3d\x35\x1d\x1b\x4b\x15\x03\x05\x06\x08\x25\x27\x21\x20"
+   "\x24\x15\xb1\x5e\x00\x96\x83\xdd\xdc\x92\x66\x29\xbc\x35\xb1\x8a"
+   "\xc6\x72\x50\x4b\xbd\x8e\x9a\x95\xc6\xf7\xd3\x30\xd5\x34\x68\x22"
+   "\xc8\xd1\xca\xb6\xf4\x5c\xd1\xc7\x03\xdb\xc8\xb5\x8a\x1a\xf3\xbd"
+   "\x10\x60\x6d\x52\xa2\xd7\x75\x21\x35\x08\xfa\xe5\xa3\x4b\x5c\x9d"
+   "\xab\x87\x21\xbe\xb0\xbc\x32\x72\x2c\x22\x00\x6f\xf5\x63\x80\x6e"
+   "\x3d\x33\x4a\xab\xef\x9f\x3b\xf0\x25\xc3\x20\xa6\xe9\x55\x07\x0a"
+   "\x78\x29\xa1\xb8\xa5\xfd\xd2\xdf\x25\x6a\x53\xba\x6a\x9c\x06\x04"
+   "\x36\x39\x9e\x9b\x04\xdd\x2d\x24\xe1\xa7\x34\x95\x93\xef\x67\x2a";
+
+   /* Set 128-bit wide XMM registers to apriori known values. */
+   __asm__ __volatile__("\n"
+      "movupd   0(%[input]), %%xmm0\n"
+      "movupd  16(%[input]), %%xmm1\n"
+      "movupd  32(%[input]), %%xmm2\n"
+      "movupd  48(%[input]), %%xmm3\n"
+      "movupd  64(%[input]), %%xmm4\n"
+      "movupd  80(%[input]), %%xmm5\n"
+      "movupd  96(%[input]), %%xmm6\n"
+      "movupd 112(%[input]), %%xmm7\n"
+      "movupd 128(%[input]), %%xmm8\n"
+      "movupd 144(%[input]), %%xmm9\n"
+      "movupd 160(%[input]), %%xmm10\n"
+      "movupd 176(%[input]), %%xmm11\n"
+      "movupd 192(%[input]), %%xmm12\n"
+      "movupd 208(%[input]), %%xmm13\n"
+      "movupd 224(%[input]), %%xmm14\n"
+      "movupd 240(%[input]), %%xmm15\n"
+      "movq $0x1, %%rax\n"
+      "movq $0x1234, (%%rax)\n"  // should cause SEGV here
+      : // no output registers
+      : [input]  "r" (input)
+      : "memory", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6",
+        "%xmm7", "%xmm8", "%xmm9", "%xmm10", "%xmm11", "%xmm12", "%xmm13",
+        "%xmm14", "%xmm15");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+   inner();
+}
+
+int main(int argc, const char *argv[])
+{
+   outer();
+   return 0;
+}
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse.post.exp b/none/tests/amd64-solaris/coredump_single_thread_sse.post.exp
new file mode 100644
index 0000000..9840da5
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse.post.exp
@@ -0,0 +1,23 @@
+---Status---
+debugging core file of coredump_single (64-bit) from ...
+initial argv: ./coredump_single_thread_sse
+threading model: native threads
+status: process terminated by SIGSEGV (Segmentation Fault), addr=........
+
+---SSE Registers---
+%xmm0  0x1032547698cadbfef0debc9a78563412
+%xmm1  0xcafe6794badcfe214365870989674523
+%xmm2  0x54676550bafabafadecedececdabcdab
+%xmm3  0x353d3a3720212725154b1b1d08060503
+%xmm4  0x98cadbfe7856341210325476f0debc9a
+%xmm5  0x43658709badcfe2189674523cafe6794
+%xmm6  0xbafabafacdabcdabdecedece54676550
+%xmm7  0x2021272508060503154b1b1d353d3a37
+%xmm8  0x8ab135bc296692dcdd8396005eb11524
+%xmm9  0x226834d530d3f7c6959a8ebd4b5072c6
+%xmm10 0xbdf31a8ab5c8db03c7d15cf4b6cad1c8
+%xmm11 0x9d5c4ba3e5fa08352175d7a2526d6010
+%xmm12 0x6e8063f56f00222c7232bcb0be2187ab
+%xmm13 0x0a0755e9a620c325f03b9fefab4a333d
+%xmm14 0x04069c6aba536a25dfd2fda5b8a12978
+%xmm15 0x2a67ef939534a7e1242ddd049b9e3936
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse.stderr.exp b/none/tests/amd64-solaris/coredump_single_thread_sse.stderr.exp
new file mode 100644
index 0000000..ca1f503
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse.stderr.exp
@@ -0,0 +1,11 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: inner (coredump_single_thread_sse.c:29)
+   by 0x........: outer (coredump_single_thread_sse.c:58)
+   by 0x........: main (coredump_single_thread_sse.c:63)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse.stdout.exp b/none/tests/amd64-solaris/coredump_single_thread_sse.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse.stdout.exp
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse.vgtest b/none/tests/amd64-solaris/coredump_single_thread_sse.vgtest
new file mode 100644
index 0000000..5292597
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse.vgtest
@@ -0,0 +1,5 @@
+prereq: rm -f vgcore.* && ../../../tests/x86_amd64_features amd64-sse3
+prog: coredump_single_thread_sse
+vgopts: -q
+post: ./coredump_single_thread_sse_mdb
+cleanup: rm -f vgcore.*
diff --git a/none/tests/amd64-solaris/coredump_single_thread_sse_mdb b/none/tests/amd64-solaris/coredump_single_thread_sse_mdb
new file mode 100755
index 0000000..3cc5413
--- /dev/null
+++ b/none/tests/amd64-solaris/coredump_single_thread_sse_mdb
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Filters are not run for post-test check commands.
+# Filter everything here.
+
+echo "---Status---"
+echo "::status" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/from \S*$/from .../' | \
+perl -0 -p -e 's/^file: .+?^(initial argv:)/$1/ms' | \
+perl -p -e 's/addr=[0-9A-Fa-f]+/addr=......../g'
+
+echo "\n---SSE Registers---"
+echo "::fpregs" | /usr/bin/mdb vgcore.* | \
+perl -n -e '/^%xmm/ && print $_;'
+
diff --git a/none/tests/amd64-solaris/filter_stderr b/none/tests/amd64-solaris/filter_stderr
new file mode 100755
index 0000000..0ae9313
--- /dev/null
+++ b/none/tests/amd64-solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/none/tests/amd64-solaris/syscall_return_args.c b/none/tests/amd64-solaris/syscall_return_args.c
new file mode 100644
index 0000000..8fcb90e
--- /dev/null
+++ b/none/tests/amd64-solaris/syscall_return_args.c
@@ -0,0 +1,63 @@
+/* Tests that Valgrind correctly handles syscalls returning
+   either 1 (in %rax) or 2 values (in %rdx:%rax). */
+
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+
+#define GARBAGE 0x0caffedeadbeef
+
+static void syscall_rval(int sysno, uint64_t *rval_hi, uint64_t *rval_lo)
+{
+   __asm__ (
+      "movq %[INPUT1],%%rdx\n"
+      "movq %[SYSCALL_NUMBER],%%rax\n"
+      "syscall\n"
+      "movq %[RVAL_HI],%%rcx\n"
+      "movq %%rdx,(%%rcx)\n"
+      "movq %[RVAL_LO],%%rcx\n"
+      "movq %%rax,(%%rcx)\n"
+      : [RVAL_HI] "=m" (rval_hi), [RVAL_LO] "=m" (rval_lo)	/* output */
+      : [INPUT1] "i" (GARBAGE), [SYSCALL_NUMBER] "g" (sysno)	/* input */
+      : "rax", "rcx", "rdx", "cc", "memory");			/* clobbers */
+}
+
+static int syscall_rval1(void) {
+   uint64_t valHi, valLo;
+
+   /* Syscall lwp_self returns just tid in rax. */
+   valHi = valLo = GARBAGE;
+   syscall_rval(SYS_lwp_self, &valHi, &valLo);
+   if ((valHi != GARBAGE) || (valLo != 1)) {
+      fprintf(stderr, "rval1 FAILED [%#lx:%#lx]\n", valHi, valLo);
+      return 1;
+   }
+
+   return 0;
+}
+
+static int syscall_rval2(void) {
+   uint64_t valHi, valLo;
+
+   /* Syscall getpid returns pid in rax and ppid in rdx. */
+   valHi = valLo = GARBAGE;
+   syscall_rval(SYS_getpid, &valHi, &valLo);
+   if ((valHi == GARBAGE) || (valLo == GARBAGE)) {
+      fprintf(stderr, "rval2 FAILED [%#lx:%#lx]\n", valHi, valLo);
+      return 1;
+   }
+
+   return 0;
+}
+
+int main(void) {
+   int ret = 0;
+
+   ret |= syscall_rval1();
+   ret |= syscall_rval2();
+
+   if (ret != 0)
+     fprintf(stderr, "FAIL\n");
+
+   return ret;
+}
diff --git a/none/tests/amd64-solaris/syscall_return_args.stderr.exp b/none/tests/amd64-solaris/syscall_return_args.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/amd64-solaris/syscall_return_args.stderr.exp
diff --git a/none/tests/amd64-solaris/syscall_return_args.vgtest b/none/tests/amd64-solaris/syscall_return_args.vgtest
new file mode 100644
index 0000000..ce1591d
--- /dev/null
+++ b/none/tests/amd64-solaris/syscall_return_args.vgtest
@@ -0,0 +1,2 @@
+prog: syscall_return_args
+vgopts: -q
diff --git a/none/tests/amd64/Makefile.am b/none/tests/amd64/Makefile.am
index 21d419e..7e943ab 100644
--- a/none/tests/amd64/Makefile.am
+++ b/none/tests/amd64/Makefile.am
@@ -1,7 +1,7 @@
 
 include $(top_srcdir)/Makefile.tool-tests.am
 
-dist_noinst_SCRIPTS = filter_cpuid filter_stderr gen_insn_test.pl
+dist_noinst_SCRIPTS = filter_cpuid filter_inf_nan filter_stderr gen_insn_test.pl
 
 CLEANFILES = $(addsuffix .c,$(INSN_TESTS))
 
@@ -44,6 +44,7 @@
 	fcmovnu.vgtest fcmovnu.stderr.exp fcmovnu.stdout.exp \
 	fxtract.vgtest fxtract.stderr.exp fxtract.stdout.exp \
 	fxtract.stdout.exp-older-glibc \
+	getseg.stdout.exp getseg.stderr.exp getseg.vgtest \
 	$(addsuffix .stderr.exp,$(INSN_TESTS)) \
 	$(addsuffix .stdout.exp,$(INSN_TESTS)) \
 	$(addsuffix .vgtest,$(INSN_TESTS)) \
@@ -91,6 +92,7 @@
 	bug127521-64 bug132813-amd64 bug132918 bug137714-amd64 \
 	clc \
 	cmpxchg \
+	getseg \
 	$(INSN_TESTS) \
 	nan80and64 \
 	rcl-amd64 \
diff --git a/none/tests/amd64/amd64locked.c b/none/tests/amd64/amd64locked.c
index d464857..baf9bbe 100644
--- a/none/tests/amd64/amd64locked.c
+++ b/none/tests/amd64/amd64locked.c
@@ -14,6 +14,18 @@
 typedef  unsigned long           UWord;
 typedef  char                    HChar;
 
+unsigned myrandom(void)
+{
+   /* Simple multiply-with-carry random generator. */
+   static unsigned m_w = 11;
+   static unsigned m_z = 13;
+
+   m_z = 36969 * (m_z & 65535) + (m_z >> 16);
+   m_w = 18000 * (m_w & 65535) + (m_w >> 16);
+
+   return (m_z << 16) + m_w;
+}
+
 /////////////////////////////////////////////////////////////////
 // BEGIN crc32 stuff                                           //
 /////////////////////////////////////////////////////////////////
@@ -664,8 +676,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsq_mem(block, bitoff); break;
@@ -700,8 +712,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsl_mem(block, bitoff); break;
@@ -736,8 +748,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsw_mem(block, bitoff); break;
@@ -1046,7 +1058,7 @@
   // objdump -d ./amd64locked | grep lock | grep -v do_lock | grep -v elf64 | wc
 
 
-  { UInt crcExpd = 0x1F677629;
+  { UInt crcExpd = 0xDF0656F1;
     theCRC = crcFinalise( theCRC );
     if (theCRC == crcExpd) {
        printf("amd64locked: PASS: CRCs actual 0x%08X expected 0x%08X\n",
diff --git a/none/tests/amd64/amd64locked.stdout.exp b/none/tests/amd64/amd64locked.stdout.exp
index 97202d2..abe8b73 100644
--- a/none/tests/amd64/amd64locked.stdout.exp
+++ b/none/tests/amd64/amd64locked.stdout.exp
@@ -1 +1 @@
-amd64locked: PASS: CRCs actual 0x1F677629 expected 0x1F677629
+amd64locked: PASS: CRCs actual 0xDF0656F1 expected 0xDF0656F1
diff --git a/none/tests/amd64/bug132918.vgtest b/none/tests/amd64/bug132918.vgtest
index 7bfbf95..8c94907 100644
--- a/none/tests/amd64/bug132918.vgtest
+++ b/none/tests/amd64/bug132918.vgtest
@@ -1 +1,2 @@
 prog: bug132918
+stdout_filter: filter_inf_nan
diff --git a/none/tests/amd64/bug156404-amd64.c b/none/tests/amd64/bug156404-amd64.c
index d0c4ea0..3af8b60 100644
--- a/none/tests/amd64/bug156404-amd64.c
+++ b/none/tests/amd64/bug156404-amd64.c
@@ -14,6 +14,7 @@
 #define VG_STRINGIFZ(__str)  #__str
 #define VG_STRINGIFY(__str)  VG_STRINGIFZ(__str)
 
+#if defined(VGO_linux) || defined(VGO_darwin)
 #define __NR_READLINK        VG_STRINGIFY(__NR_readlink)
 
 extern long my_readlink ( const char* path );
@@ -32,6 +33,30 @@
 ".previous\n"
 );
 
+#elif defined(VGO_solaris)
+#define __NR_READLINKAT      VG_STRINGIFY(SYS_readlinkat)
+
+extern long my_readlink ( const char* path );
+asm(
+".text\n"
+".globl my_readlink\n"
+"my_readlink:\n"
+"\tsubq    $0x1008,%rsp\n"
+"\tmovq    %rdi,%rsi\n"
+"\txorq    %rdi,%rdi\n"
+"\tmovq    %rsp,%rdx\n"
+"\tmovq    $0x1000,%r10\n"
+"\tmovl    $"__NR_READLINKAT",%eax\n"
+"\tsyscall\n"
+"\taddq    $0x1008,%rsp\n"
+"\tret\n"
+".previous\n"
+);
+
+#else
+#error "Unknown OS"
+#endif
+
 long recurse ( const char* path, long count )
 {
    if (count <= 0) {
diff --git a/none/tests/amd64/filter_inf_nan b/none/tests/amd64/filter_inf_nan
new file mode 100755
index 0000000..ce40f21
--- /dev/null
+++ b/none/tests/amd64/filter_inf_nan
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+# Solaris libc prints 'Inf' or 'Infinity' instead of 'inf'
+# and 'NaN' instead of 'nan'. Filter these differences here.
+sed "s/-Infinity/     -inf/g" |
+sed "s/Infinity/     inf/g"   |
+sed "s/Inf/inf/g"             |
+sed "s/NaN/nan/g"
+
+exit 0
+
diff --git a/none/tests/amd64/fxtract.vgtest b/none/tests/amd64/fxtract.vgtest
index b265384..8e9e84d 100644
--- a/none/tests/amd64/fxtract.vgtest
+++ b/none/tests/amd64/fxtract.vgtest
@@ -1,2 +1,3 @@
 prereq: test -e fxtract
 prog: fxtract
+stdout_filter: filter_inf_nan
diff --git a/none/tests/amd64/getseg.c b/none/tests/amd64/getseg.c
new file mode 100644
index 0000000..ac09af6
--- /dev/null
+++ b/none/tests/amd64/getseg.c
@@ -0,0 +1,25 @@
+/* Test segment register getting. */
+
+#include <stdio.h>
+
+int main(void)
+{
+   unsigned short csw = -1;
+   unsigned int csl = -1;
+   unsigned long csq = -1;
+   unsigned short csw_mem = -1;
+
+   __asm__ __volatile__ (
+       "movw %%cs, %0\n" /* mov segReg, r16 */
+       "movl %%cs, %1\n" /* mov segReg, r32 */
+       "movq %%cs, %2\n" /* mov segReg, r64 */
+       "movw %%cs, %3\n" /* mov segReg, mem16 */
+       : "=r" (csw), "=r" (csl), "=r" (csq), "=m" (csw_mem));
+
+   printf("cs(w)=%u\n", csw);
+   printf("cs(l)=%u\n", csl);
+   printf("cs(q)=%lu\n", csq);
+   printf("cs(w_mem)=%u\n", csw_mem);
+
+   return 0;
+}
diff --git a/none/tests/amd64/getseg.stderr.exp b/none/tests/amd64/getseg.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/amd64/getseg.stderr.exp
diff --git a/none/tests/amd64/getseg.stdout.exp b/none/tests/amd64/getseg.stdout.exp
new file mode 100644
index 0000000..558358d
--- /dev/null
+++ b/none/tests/amd64/getseg.stdout.exp
@@ -0,0 +1,4 @@
+cs(w)=0
+cs(l)=0
+cs(q)=0
+cs(w_mem)=0
diff --git a/none/tests/amd64/getseg.vgtest b/none/tests/amd64/getseg.vgtest
new file mode 100644
index 0000000..9d91132
--- /dev/null
+++ b/none/tests/amd64/getseg.vgtest
@@ -0,0 +1,2 @@
+prog: getseg
+vgopts: -q
diff --git a/none/tests/amd64/sse4-64.vgtest b/none/tests/amd64/sse4-64.vgtest
index a5e7f19..872dcea 100644
--- a/none/tests/amd64/sse4-64.vgtest
+++ b/none/tests/amd64/sse4-64.vgtest
@@ -1,3 +1,4 @@
 prog: sse4-64
 prereq: ../../../tests/x86_amd64_features amd64-sse42
 vgopts: -q
+stdout_filter: filter_inf_nan
diff --git a/none/tests/async-sigs.c b/none/tests/async-sigs.c
index 25b730b..d027b6c 100644
--- a/none/tests/async-sigs.c
+++ b/none/tests/async-sigs.c
@@ -43,7 +43,7 @@
       char pidbuf[20];
       sprintf(sigbuf, "-%d", sig);
       sprintf(pidbuf, "%d", pid);
-      execl("/bin/kill", "kill", sigbuf, pidbuf, NULL);
+      execl("/bin/kill", "kill", sigbuf, pidbuf, (char *) NULL);
       perror("exec failed");
       exit(1);
    }
@@ -87,7 +87,11 @@
    // - otherwise, wait in client code (by spinning).
    // The alarm() calls is so that if something breaks, we don't get stuck.
    if (pid == 0) {
-      signal(caughtsig, handler);
+      struct sigaction sa;
+      sa.sa_handler = handler;
+      sigemptyset(&sa.sa_mask);
+      sa.sa_flags = 0;
+      sigaction(caughtsig, &sa, 0);
       alarm(10);
 
       for (;;)
diff --git a/none/tests/async-sigs.vgtest b/none/tests/async-sigs.vgtest
index ec51f03..3d4d862 100644
--- a/none/tests/async-sigs.vgtest
+++ b/none/tests/async-sigs.vgtest
@@ -1,2 +1,3 @@
 prog: async-sigs
 vgopts: -q
+cleanup: rm -f vgcore.*
diff --git a/none/tests/cmdline1.stdout.exp b/none/tests/cmdline1.stdout.exp
index 564a2e0..355b554 100644
--- a/none/tests/cmdline1.stdout.exp
+++ b/none/tests/cmdline1.stdout.exp
@@ -95,7 +95,7 @@
     --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
     --sim-hints=hint1,hint2,...  activate unusual sim behaviours [none] 
          where hint is one of:
-           lax-ioctls fuse-compatible enable-outer
+           lax-ioctls lax-doors fuse-compatible enable-outer
            no-inner-prefix no-nptl-pthread-stackcache none
     --fair-sched=no|yes|try   schedule threads fairly on multicore systems [no]
     --kernel-variant=variant1,variant2,...
diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp
index 4efc423..59619b0 100644
--- a/none/tests/cmdline2.stdout.exp
+++ b/none/tests/cmdline2.stdout.exp
@@ -95,7 +95,7 @@
     --run-libc-freeres=no|yes free up glibc memory at exit on Linux? [yes]
     --sim-hints=hint1,hint2,...  activate unusual sim behaviours [none] 
          where hint is one of:
-           lax-ioctls fuse-compatible enable-outer
+           lax-ioctls lax-doors fuse-compatible enable-outer
            no-inner-prefix no-nptl-pthread-stackcache none
     --fair-sched=no|yes|try   schedule threads fairly on multicore systems [no]
     --kernel-variant=variant1,variant2,...
diff --git a/none/tests/coolo_sigaction.vgtest b/none/tests/coolo_sigaction.vgtest
index 4ee1d82..c24fb77 100644
--- a/none/tests/coolo_sigaction.vgtest
+++ b/none/tests/coolo_sigaction.vgtest
@@ -1 +1,3 @@
+# Disabled on Solaris because parent process never gets SIGCHLD.
+prereq: (! ../../tests/os_test solaris)
 prog: coolo_sigaction
diff --git a/none/tests/exec-sigmask.c b/none/tests/exec-sigmask.c
index 11a24c5..2ab8fed 100644
--- a/none/tests/exec-sigmask.c
+++ b/none/tests/exec-sigmask.c
@@ -19,7 +19,7 @@
 	}
 	if (pid == 0) {
 		sigprocmask(SIG_SETMASK, mask, NULL);
-		execl(path, path, arg, NULL);
+		execl(path, path, arg, (char *) NULL);
 			
 		fprintf(stderr, "FAILED: execl failed with %s\n",
 			strerror(errno));
diff --git a/none/tests/exec-sigmask.stdout.exp-solaris b/none/tests/exec-sigmask.stdout.exp-solaris
new file mode 100644
index 0000000..1979811
--- /dev/null
+++ b/none/tests/exec-sigmask.stdout.exp-solaris
@@ -0,0 +1 @@
+full: signal 36 missing from mask
diff --git a/none/tests/execve.c b/none/tests/execve.c
index e6a3044..db2be29 100644
--- a/none/tests/execve.c
+++ b/none/tests/execve.c
@@ -8,11 +8,16 @@
    {
       // This tests the case where argv and envp are NULL, which is easy to
       // get wrong because it's an unusual case.
-#  if !defined(VGO_darwin)
-      if (execve("/bin/true", NULL, NULL) < 0)
-#  else
+
+#if defined(VGO_solaris)
+      // Solaris requires non-NULL argv parameter
+      char *const argv_exe[] = {"true", NULL};
+      if (execve("/bin/true", argv_exe, NULL) < 0)
+#elif defined(VGO_darwin)
       if (execve("/usr/bin/true", NULL, NULL) < 0)          
-#  endif
+#else
+      if (execve("/bin/true", NULL, NULL) < 0)
+#endif
       {
          perror("execve");
          exit(1);
diff --git a/none/tests/faultstatus.c b/none/tests/faultstatus.c
index cbee7e4..81e6908 100644
--- a/none/tests/faultstatus.c
+++ b/none/tests/faultstatus.c
@@ -29,6 +29,17 @@
 #  define DIVISION_BY_ZERO_SI_CODE      FPE_INTDIV
 #endif
 
+/* Accessing non-mapped virtual address results in SIGBUS
+ * with si_code equal to BUS_ADRERR on Linux, whereas in SIGBUS
+ * with si_code equal to BUS_OBJERR on Solaris. On Solaris,
+ * BUS_ADRERR is used for bus time out while BUS_OBJERR is translated
+ * from underlying codes FC_OBJERR (x86) or ASYNC_BERR (sparc).
+ */
+#if defined(VGO_solaris)
+#  define BUS_ERROR_SI_CODE  BUS_OBJERR
+#else
+#  define BUS_ERROR_SI_CODE  BUS_ADRERR
+#endif
 
 struct test {
 	void (*test)(void);
@@ -155,7 +166,7 @@
 #define T(n, sig, code, addr) { test##n, sig, code, addr }
 			T(1, SIGSEGV,	SEGV_MAPERR,	BADADDR),
 			T(2, SIGSEGV,	SEGV_ACCERR,	mapping),
-			T(3, SIGBUS,	BUS_ADRERR,	&mapping[FILESIZE+10]),
+			T(3, SIGBUS,	BUS_ERROR_SI_CODE, &mapping[FILESIZE+10]),
 			T(4, SIGFPE,    DIVISION_BY_ZERO_SI_CODE, 0),
 #undef T
 		};
diff --git a/none/tests/fdleak_creat.c b/none/tests/fdleak_creat.c
index 994692a..3c7c401 100644
--- a/none/tests/fdleak_creat.c
+++ b/none/tests/fdleak_creat.c
@@ -9,7 +9,7 @@
 
    CLOSE_INHERITED_FDS;
 
-   sprintf(filename, "/tmp/file.%d", getpid());
+   sprintf(filename, "/tmp/file.%ld", (long) getpid());
    (void) DO( creat(filename, 0) );
    (void) DO( unlink(filename) );
    return 0;
diff --git a/none/tests/filter_fdleak b/none/tests/filter_fdleak
index bb1ef42..9315207 100755
--- a/none/tests/filter_fdleak
+++ b/none/tests/filter_fdleak
@@ -6,6 +6,8 @@
 
 perl -p -e 's/^Open AF_UNIX socket [0-9]*: <unknown>/Open AF_UNIX socket ...: <unknown>/' |
 perl -p -e 's/^Open (AF_UNIX socket|file descriptor) [0-9]*: \/dev\/null/Open $1 ...: \/dev\/null/' |
+# Solaris-specific, translate /devices/pseudo/mm@0:null to /dev/null
+perl -p -e 's/^Open (AF_UNIX socket|file descriptor) [0-9]*: \/devices\/pseudo\/mm\@0:null/Open $1 ...: \/dev\/null/' |
 # Nb: on Darwin, /tmp is a symlink to /private/tmp, so sometimes it's
 # necessary to filter out the "/private" part.
 perl -p -e 's/^Open (AF_UNIX socket|file descriptor) [0-9]*: (\/private)?\/tmp\/(sock|data1|data2|file)\.[0-9]*/Open $1 ...: \/tmp\/$3/' |
diff --git a/none/tests/ioctl_moans.c b/none/tests/ioctl_moans.c
index ed05e7b..378ff44 100644
--- a/none/tests/ioctl_moans.c
+++ b/none/tests/ioctl_moans.c
@@ -8,7 +8,7 @@
    The choice of values here needs to match the logic in
    ML_(PRE_unknown_ioctl) and take into account that _IOC_NONE
    is not == 0 everywhere. */
-# if !defined(VGO_darwin)
+# if defined(VGO_linux)
 #define IOCTL_REQUEST_BASE (0x12345670 | _IOC(_IOC_NONE,0,0,0))
 # else
 #define IOCTL_REQUEST_BASE  0x12345670
diff --git a/none/tests/libvex_test.c b/none/tests/libvex_test.c
index e297921..5718e54 100644
--- a/none/tests/libvex_test.c
+++ b/none/tests/libvex_test.c
@@ -1,8 +1,8 @@
 #include <stdio.h>
 #include <stdlib.h>
-# if !defined(VGO_darwin)
+# if defined(VGO_linux)
 #include <endian.h>
-# else
+# elif defined(VGO_darwin)
 #include <machine/endian.h>
 # endif
 #include "../../VEX/pub/libvex.h"
diff --git a/none/tests/map_unmap.c b/none/tests/map_unmap.c
index bfc2503..212d7e3 100644
--- a/none/tests/map_unmap.c
+++ b/none/tests/map_unmap.c
@@ -77,7 +77,7 @@
 static void prmaps()
 {
 	char buf[100];
-	sprintf(buf, "/bin/cat /proc/%d/maps", getpid());
+	sprintf(buf, "/bin/cat /proc/%ld/maps", (long) getpid());
 	system(buf);
 	exit(1);
 }
diff --git a/none/tests/mq.c b/none/tests/mq.c
index b2ab7bc..8105a8d 100644
--- a/none/tests/mq.c
+++ b/none/tests/mq.c
@@ -64,11 +64,8 @@
       exit(1);
     }
 
-  if (len != 4 || memcmp(buffer, "PING", 4) != 0)
-    {
-      fprintf(stderr, "Message corrupt!");
-    }
-
+#if !defined(VGO_solaris)
+  /* On Solaris, there is no existing notification registration. */
   if (mq_notify(mqdr, NULL) < 0)
     {
       perror("mq_notify");
@@ -76,6 +73,12 @@
       mq_close(mqdw);
       exit(1);
     }
+#endif /* !VGO_solaris */
+
+  if (len != 4 || memcmp(buffer, "PING", 4) != 0)
+    {
+      fprintf(stderr, "Message corrupt!");
+    }
 
   if (mq_getattr(mqdr, &mqa) < 0)
     {
diff --git a/none/tests/procfs-cmdline-exe.c b/none/tests/procfs-cmdline-exe.c
index 9f550e5..cfb78d6 100644
--- a/none/tests/procfs-cmdline-exe.c
+++ b/none/tests/procfs-cmdline-exe.c
@@ -98,12 +98,12 @@
     perror("getcwd");
   strcat(cwd, "/");
 
-  snprintf(path, sizeof(path), "/proc/%d/cmdline", getpid());
+  snprintf(path, sizeof(path), "/proc/%ld/cmdline", (long) getpid());
 
   test_cmdline(cwd, "/proc/self/cmdline", "/proc/self/cmdline");
   test_cmdline(cwd, "/proc/<pid>/cmdline", path);
 
-  snprintf(path, sizeof(path), "/proc/%d/exe", getpid());
+  snprintf(path, sizeof(path), "/proc/%ld/exe", (long) getpid());
 
   test_readlink(cwd, "/proc/self/exe", "/proc/self/exe");
   test_readlink(cwd, "/proc/<pid>/exe", path);
diff --git a/none/tests/pth_atfork1.c b/none/tests/pth_atfork1.c
index 99a087f..34201ef 100644
--- a/none/tests/pth_atfork1.c
+++ b/none/tests/pth_atfork1.c
@@ -18,7 +18,7 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <errno.h>
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__sun)
 # include <error.h>
 #endif
 #include <stdlib.h>
@@ -27,7 +27,7 @@
 #include <sys/wait.h>
 #include <stdio.h>
 
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__sun)
 #include <string.h>  /* strerror */
 static void error (int status, int errnum, char* msg)
 {
diff --git a/none/tests/require-text-symbol-2.stderr.exp-libcso1 b/none/tests/require-text-symbol-2.stderr.exp-libcso1
new file mode 100644
index 0000000..8c0c3ea
--- /dev/null
+++ b/none/tests/require-text-symbol-2.stderr.exp-libcso1
@@ -0,0 +1,9 @@
+
+valgrind:  Fatal error at when loading library with soname
+valgrind:     libc.so.1
+valgrind:  Cannot find any text symbol with a name that matches the pattern
+valgrind:     doesntexist
+valgrind:  as required by a --require-text-symbol= specification.
+
+valgrind:  Cannot continue -- exiting now.
+
diff --git a/none/tests/resolv.vgtest b/none/tests/resolv.vgtest
index e8c1e29..e4c3de0 100644
--- a/none/tests/resolv.vgtest
+++ b/none/tests/resolv.vgtest
@@ -1 +1,4 @@
+# Disabled on Solaris because different approach needs to be taken.
+# There is none/tests/solaris/resolv for that purpose.
+prereq: (! ../../tests/os_test solaris)
 prog: resolv
diff --git a/none/tests/rlimit64_nofile.vgtest b/none/tests/rlimit64_nofile.vgtest
index 49934f8..e061f39 100644
--- a/none/tests/rlimit64_nofile.vgtest
+++ b/none/tests/rlimit64_nofile.vgtest
@@ -1,2 +1,2 @@
-prereq: ../../tests/os_test linux
+prereq: ../../tests/os_test linux || ../../tests/os_test solaris
 prog: rlimit64_nofile
diff --git a/none/tests/scripts/Makefile.am b/none/tests/scripts/Makefile.am
index 9fe986b..ab6d0de 100644
--- a/none/tests/scripts/Makefile.am
+++ b/none/tests/scripts/Makefile.am
@@ -9,7 +9,8 @@
 EXTRA_DIST = \
 	bug231357.vgtest bug231357.stderr.exp bug231357.stdout.exp \
 	shell shell.vgtest shell.stderr.exp shell.stderr.exp-dash \
-	shell.stdout.exp shell.stderr.exp-dash2 \
+	shell.stdout.exp shell.stderr.exp-dash2 shell.stderr.exp-illumos \
+	shell.stderr.exp-solaris shell.stderr.exp-solaris-spawn \
 	shell_badinterp shell_badinterp.vgtest shell_badinterp.stderr.exp \
 	shell_binaryfile shell_binaryfile.vgtest shell_binaryfile.stderr.exp \
 	shell_dir.vgtest shell_dir.stderr.exp \
diff --git a/none/tests/scripts/shell.stderr.exp-illumos b/none/tests/scripts/shell.stderr.exp-illumos
new file mode 100644
index 0000000..9866b2e
--- /dev/null
+++ b/none/tests/scripts/shell.stderr.exp-illumos
@@ -0,0 +1,8 @@
+./shell[10]: ./x86/: cannot execute [is a directory]
+./shell[13]: ./shell.vgtest: cannot execute [Permission denied]
+execve(0x........(./shell_badinterp), 0x........, 0x........) failed, errno 2
+EXEC FAILED: I can't recover from execve() failing, so I'm dying.
+Add more stringent tests in PRE(sys_execve), or work out how to recover.
+./shell_binaryfile: ./shell_binaryfile: cannot execute [Exec format error]
+./shell[22]: ./shell_nosuchfile: not found [No such file or directory]
+./shell[25]: shell_nosuchfile: not found [No such file or directory]
diff --git a/none/tests/scripts/shell.stderr.exp-solaris b/none/tests/scripts/shell.stderr.exp-solaris
new file mode 100644
index 0000000..5a8229f
--- /dev/null
+++ b/none/tests/scripts/shell.stderr.exp-solaris
@@ -0,0 +1,8 @@
+./shell[10]: ./x86/: cannot execute [is a directory]
+./shell[13]: ./shell.vgtest: cannot execute [Permission denied]
+execve(0x........(./shell_badinterp), 0x........, 0x........, 0) failed, errno 2
+EXEC FAILED: I can't recover from execve() failing, so I'm dying.
+Add more stringent tests in PRE(sys_execve), or work out how to recover.
+./shell_binaryfile: ./shell_binaryfile: cannot execute [Exec format error]
+./shell[22]: ./shell_nosuchfile: not found [No such file or directory]
+./shell[25]: shell_nosuchfile: not found [No such file or directory]
diff --git a/none/tests/scripts/shell.stderr.exp-solaris-spawn b/none/tests/scripts/shell.stderr.exp-solaris-spawn
new file mode 100644
index 0000000..e40fd97
--- /dev/null
+++ b/none/tests/scripts/shell.stderr.exp-solaris-spawn
@@ -0,0 +1,6 @@
+./shell[10]: ./x86/: cannot execute [is a directory]
+./shell[13]: ./shell.vgtest: cannot execute [Permission denied]
+./shell[16]: ./shell_badinterp: not found [No such file or directory]
+./shell_binaryfile: ./shell_binaryfile: cannot execute [Exec format error]
+./shell[22]: ./shell_nosuchfile: not found [No such file or directory]
+./shell[25]: shell_nosuchfile: not found [No such file or directory]
diff --git a/none/tests/solaris/Makefile.am b/none/tests/solaris/Makefile.am
new file mode 100644
index 0000000..2527ea0
--- /dev/null
+++ b/none/tests/solaris/Makefile.am
@@ -0,0 +1,58 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+	filter_coredump_many_threads_post \
+	filter_coredump_many_threads_stderr \
+	filter_stderr
+
+EXTRA_DIST = \
+	block_all_signals.stderr.exp block_all_signals.stdout.exp block_all_signals.vgtest \
+	blockfault.stderr.exp blockfault.vgtest \
+	context_link.stderr.exp context_link.stdout.exp context_link.vgtest \
+	context_link2.stderr.exp context_link2.stdout.exp context_link2.vgtest \
+	context_null.stderr.exp context_null.stdout.exp context_null.vgtest \
+	context_stack.stderr.exp context_stack.stdout.exp context_stack.vgtest \
+	coredump_many_threads.post.exp coredump_many_threads.stderr.exp coredump_many_threads.vgtest \
+	mmap_noreserve.stderr.exp mmap_noreserve.stdout.exp mmap_noreserve.vgtest \
+	proc_aout.stderr.exp proc_aout.stdout.exp proc_aout.vgtest \
+	proc_auxv.stderr.exp proc_auxv.stdout.exp proc_auxv.vgtest \
+	proc_auxv_multiple.stderr.exp proc_auxv_multiple.stdout.exp proc_auxv_multiple.vgtest \
+	proc_psinfo.stderr.exp proc_psinfo.stdout.exp proc_psinfo.vgtest \
+	posix_spawn.stderr.exp posix_spawn.stdout.exp posix_spawn.vgtest \
+	pthread-stack.stderr.exp pthread-stack.vgtest \
+	resolv.stdout.exp resolv.stderr.exp resolv.vgtest \
+	sigresend.stderr.exp sigresend.stdout.exp sigresend.vgtest \
+	stack-overflow.stderr.exp stack-overflow.vgtest \
+	stack_prot.stderr.exp stack_prot.stdout.exp stack_prot.vgtest \
+	threads_exitall.stderr.exp threads_exitall.stdout.exp threads_exitall.vgtest
+
+check_PROGRAMS = \
+	block_all_signals \
+	blockfault \
+	context_link \
+	context_link2 \
+	context_null \
+	context_stack \
+	coredump_many_segments \
+	coredump_many_threads \
+	mmap_noreserve \
+	proc_aout \
+	proc_auxv \
+	proc_auxv_multiple \
+	proc_psinfo \
+	posix_spawn \
+	pthread-stack \
+	resolv \
+	sigresend \
+	stack-overflow \
+	stack_prot \
+	threads_exitall
+
+AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
+pthread_stack_LDADD = -lpthread
+resolv_LDADD = -lresolv
+stack_prot_LDFLAGS = -Wl,-M,/usr/lib/ld/map.noexstk
+threads_exitall_LDADD = -lpthread
diff --git a/none/tests/solaris/block_all_signals.c b/none/tests/solaris/block_all_signals.c
new file mode 100644
index 0000000..b0d23c2
--- /dev/null
+++ b/none/tests/solaris/block_all_signals.c
@@ -0,0 +1,64 @@
+/* Tests that Valgrind retains control over blocked signals.
+   If synchronous signals (SIGSEGV) would be blocked, kernel would
+   simply kill the process. When operating properly, Valgrind involves
+   its synchronous signal handler and reports on the signal delivery.
+
+   Valgrind and libc all retain their sigmasks and lie to us politely
+   about what the actual sigmask is. One of reliable tests is to fork
+   another process (because libc thinks it blocks all signals before fork
+   and the forked process inherits the sigmask) and try to SIGSEGV it.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+int main(void)
+{
+   pid_t pid = fork();
+   if (pid < 0) {
+      perror("fork");
+      exit(1);
+   } else if (pid == 0) {
+      /* Causes SIGSEGV. */
+      char *s = NULL;
+      s[0] = 1;
+   } else {
+      pid_t ret;
+      int status;
+      
+      while ((ret = waitpid(pid, &status, 0)) != pid) {
+         if (errno != EINTR) {
+            perror("waitpid");
+            exit(1);
+         }
+      }
+
+      if (WIFSIGNALED(status)) {
+         assert(WTERMSIG(status) != 0);
+
+         if (WTERMSIG(status) == SIGSEGV) {
+            printf("PASS\n");
+         } else {
+            fprintf(stderr, "Child process died with unexpected signal %d.\n",
+                    WTERMSIG(status));
+         }
+      } else if (WIFEXITED(status)) {
+         if (WEXITSTATUS(status) == 0) {
+            fprintf(stderr, "Child process exited without expected SIGSEGV "
+                    "signal.\n");
+         } else {
+            fprintf(stderr, "Child process exited with unexpected status %d.\n",
+                    WEXITSTATUS(status));
+         }
+      } else {
+         fprintf(stderr, "Unrecognized status of child proces %x?\n", status);
+      }
+   }
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/block_all_signals.stderr.exp b/none/tests/solaris/block_all_signals.stderr.exp
new file mode 100644
index 0000000..8e49f7b
--- /dev/null
+++ b/none/tests/solaris/block_all_signals.stderr.exp
@@ -0,0 +1,12 @@
+
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: main (block_all_signals.c:28)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
+
+
diff --git a/none/tests/solaris/block_all_signals.stdout.exp b/none/tests/solaris/block_all_signals.stdout.exp
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/none/tests/solaris/block_all_signals.stdout.exp
@@ -0,0 +1 @@
+PASS
diff --git a/none/tests/solaris/block_all_signals.vgtest b/none/tests/solaris/block_all_signals.vgtest
new file mode 100644
index 0000000..73bbe5a
--- /dev/null
+++ b/none/tests/solaris/block_all_signals.vgtest
@@ -0,0 +1,4 @@
+prog: block_all_signals
+vgopts: --trace-children=yes
+stderr_filter: filter_stderr
+cleanup: rm -f vgcore.*
diff --git a/none/tests/solaris/blockfault.c b/none/tests/solaris/blockfault.c
new file mode 100644
index 0000000..c11c7c5
--- /dev/null
+++ b/none/tests/solaris/blockfault.c
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include "tests/sys_mman.h"
+
+static void handler(int sig, siginfo_t *info, void *v)
+{
+	printf("info: sig=%d code=%d addr=%p\n",
+	       info->si_signo, info->si_code, info->si_addr);
+	exit(0);
+}
+
+/* Blocking a fault (for example SIGSEGV) won't work,
+   and is the same as having the default handler. */
+int main()
+{
+	int* unmapped_page = get_unmapped_page();
+	struct sigaction sa;
+	sigset_t mask;
+
+	sa.sa_sigaction = handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_SIGINFO;
+	
+	sigaction(SIGSEGV, &sa, NULL);
+
+	sigfillset(&mask);
+	sigprocmask(SIG_BLOCK, &mask, NULL);
+
+	*(volatile int *)unmapped_page = 213;
+
+	return 0;
+}
diff --git a/none/tests/solaris/blockfault.stderr.exp b/none/tests/solaris/blockfault.stderr.exp
new file mode 100644
index 0000000..b57c037
--- /dev/null
+++ b/none/tests/solaris/blockfault.stderr.exp
@@ -0,0 +1,11 @@
+
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: main (blockfault.c:30)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
+
diff --git a/none/tests/solaris/blockfault.vgtest b/none/tests/solaris/blockfault.vgtest
new file mode 100644
index 0000000..084f579
--- /dev/null
+++ b/none/tests/solaris/blockfault.vgtest
@@ -0,0 +1,2 @@
+prog: blockfault
+post: rm -f vgcore.*
diff --git a/none/tests/solaris/context_link.c b/none/tests/solaris/context_link.c
new file mode 100644
index 0000000..6d2f457
--- /dev/null
+++ b/none/tests/solaris/context_link.c
@@ -0,0 +1,38 @@
+/* Test of correct simulation for uc->uc_link. */
+
+#include <assert.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+static void print_value(int value)
+{
+   printf("Value is %d.\n", value);
+}
+
+int main(void)
+{
+   ucontext_t uc;
+   char stack[8096];
+   volatile int done = 0;
+
+   /* Get current context. */
+   getcontext(&uc);
+   if (done) {
+      /* Execution resumes here when print_value() returns. */
+      return 0;
+   }
+   done = 1;
+
+   /* Setup the stack. */
+   uc.uc_stack.ss_sp = stack;
+   uc.uc_stack.ss_size = sizeof(stack);
+
+   /* Call print_value(). */
+   makecontext(&uc, print_value, 1, 42);
+   setcontext(&uc);
+
+   /* This code should not be reached. */
+   assert(0);
+   return 0;
+}
+
diff --git a/none/tests/solaris/context_link.stderr.exp b/none/tests/solaris/context_link.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_link.stderr.exp
diff --git a/none/tests/solaris/context_link.stdout.exp b/none/tests/solaris/context_link.stdout.exp
new file mode 100644
index 0000000..835e408
--- /dev/null
+++ b/none/tests/solaris/context_link.stdout.exp
@@ -0,0 +1 @@
+Value is 42.
diff --git a/none/tests/solaris/context_link.vgtest b/none/tests/solaris/context_link.vgtest
new file mode 100644
index 0000000..bdcecfd
--- /dev/null
+++ b/none/tests/solaris/context_link.vgtest
@@ -0,0 +1,2 @@
+prog: context_link
+vgopts: -q
diff --git a/none/tests/solaris/context_link2.c b/none/tests/solaris/context_link2.c
new file mode 100644
index 0000000..9d64b6b
--- /dev/null
+++ b/none/tests/solaris/context_link2.c
@@ -0,0 +1,48 @@
+/* Test of correct simulation for uc->uc_link in a signal handler. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+static void sighandler(int sig, siginfo_t *sip, ucontext_t *ucp)
+{
+   ucontext_t uc2;
+
+   /* Current uc_link value has to be equal to ucp. */
+   getcontext(&uc2);
+   assert(uc2.uc_link == ucp);
+}
+
+int main(void)
+{
+   ucontext_t uc;
+   struct sigaction sa;
+
+   /* Current uc_link value has to be NULL. */
+   if (getcontext(&uc)) {
+      perror("getcontext");
+      return 1;
+   }
+   assert(!uc.uc_link);
+
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   raise(SIGUSR1);
+
+   /* Current uc_link value has to be NULL. */
+   getcontext(&uc);
+   assert(!uc.uc_link);
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/context_link2.stderr.exp b/none/tests/solaris/context_link2.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_link2.stderr.exp
diff --git a/none/tests/solaris/context_link2.stdout.exp b/none/tests/solaris/context_link2.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_link2.stdout.exp
diff --git a/none/tests/solaris/context_link2.vgtest b/none/tests/solaris/context_link2.vgtest
new file mode 100644
index 0000000..a0a7416
--- /dev/null
+++ b/none/tests/solaris/context_link2.vgtest
@@ -0,0 +1,2 @@
+prog: context_link2
+vgopts: -q
diff --git a/none/tests/solaris/context_null.c b/none/tests/solaris/context_null.c
new file mode 100644
index 0000000..4d206c7
--- /dev/null
+++ b/none/tests/solaris/context_null.c
@@ -0,0 +1,15 @@
+/* Test that setting NULL context causes the thread to exit. */
+
+#include <assert.h>
+#include <sys/syscall.h>
+#include <ucontext.h>
+
+int main(void)
+{
+   syscall(SYS_context, SETCONTEXT, NULL);
+
+   /* This code should not be reached. */
+   assert(0);
+   return 0;
+}
+
diff --git a/none/tests/solaris/context_null.stderr.exp b/none/tests/solaris/context_null.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_null.stderr.exp
diff --git a/none/tests/solaris/context_null.stdout.exp b/none/tests/solaris/context_null.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_null.stdout.exp
diff --git a/none/tests/solaris/context_null.vgtest b/none/tests/solaris/context_null.vgtest
new file mode 100644
index 0000000..8811696
--- /dev/null
+++ b/none/tests/solaris/context_null.vgtest
@@ -0,0 +1,2 @@
+prog: context_null
+vgopts: -q
diff --git a/none/tests/solaris/context_stack.c b/none/tests/solaris/context_stack.c
new file mode 100644
index 0000000..ff3ade6
--- /dev/null
+++ b/none/tests/solaris/context_stack.c
@@ -0,0 +1,72 @@
+/* Test of correct simulation for active stack. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+static char altstack_map[8096];
+static volatile stack_t *sp;
+
+static void sighandler(int sig)
+{
+   /* Check that the alternate stack is active. */
+   assert(sp->ss_sp == altstack_map);
+   assert(sp->ss_size == sizeof(altstack_map));
+   assert(sp->ss_flags == SS_ONSTACK);
+}
+
+int main(void)
+{
+   stack_t mainstack;
+   stack_t altstack;
+   struct sigaction sa;
+   /* Obtain an address inside the stack using a dirty trick. */
+   void *local = &sa;
+
+   /* Get an address for stack definition. */
+   if (getustack((stack_t**)&sp)) {
+      perror("getustack");
+      return 1;
+   }
+
+   /* Check the current stack. */
+   assert(sp->ss_sp <= local);
+   assert(local < (void*)((char*)sp->ss_sp + sp->ss_size));
+   assert(sp->ss_flags == 0);
+
+   /* Backup the current stack. */
+   mainstack = *sp;
+
+   /* Setup a signal handler. */
+   sa.sa_handler = sighandler;
+   sa.sa_flags = SA_ONSTACK;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGUSR1, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   /* Setup an alternate stack. */
+   altstack.ss_sp = altstack_map;
+   altstack.ss_size = sizeof(altstack_map);
+   altstack.ss_flags = 0;
+   if (sigaltstack(&altstack, NULL)) {
+      perror("sigaltstack");
+      return 1;
+   }
+
+   /* Raise a signal. */
+   raise(SIGUSR1);
+
+   /* Check the current stack. */
+   assert(mainstack.ss_sp == sp->ss_sp);
+   assert(mainstack.ss_size == sp->ss_size);
+   assert(mainstack.ss_flags == sp->ss_flags);
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/context_stack.stderr.exp b/none/tests/solaris/context_stack.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_stack.stderr.exp
diff --git a/none/tests/solaris/context_stack.stdout.exp b/none/tests/solaris/context_stack.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/context_stack.stdout.exp
diff --git a/none/tests/solaris/context_stack.vgtest b/none/tests/solaris/context_stack.vgtest
new file mode 100644
index 0000000..4876b1b
--- /dev/null
+++ b/none/tests/solaris/context_stack.vgtest
@@ -0,0 +1,2 @@
+prog: context_stack
+vgopts: -q
diff --git a/none/tests/solaris/coredump_many_segments.c b/none/tests/solaris/coredump_many_segments.c
new file mode 100644
index 0000000..e5868e5
--- /dev/null
+++ b/none/tests/solaris/coredump_many_segments.c
@@ -0,0 +1,234 @@
+/* Tests that Valgrind coredump support works correctly even when
+   number of segments exceeds 0xffff.
+   For this to work, large number of pages is mmap()'ed into the
+   process (virtual) address space. These pages must not be adjacent
+   to each other otherwise the memory manager will coalesce them
+   into a single one. So they are one page apart.
+
+   NOTE: Valgrind's internal limit VG_N_SEGMENTS must be at least
+   140000 otherwise you get a fatal error similar to this one:
+       "FATAL: VG_N_SEGMENTS is too low."
+
+   Test case passes successfully if the number of segments is
+   correctly displayed in elfdump output:
+
+   $ elfdump -e vgcore.*
+ELF Header
+  ...
+  e_phoff: 0x34  e_phentsize: 32  e_phnum: PN_XNUM (see shdr[0].sh_info)
+                                  ^^^^^^^^^^^^^^^^
+Section Header[0]:  (ELF Ehdr extensions)
+  ...
+    sh_link: 0 (e_shstrndx)  sh_info: 65554 (e_phnum)
+                             ^^^^^^^^^^^^^^^^^^^^^^^^
+*/ 
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/procfs.h>
+#include <sys/stat.h>
+
+#define SEGMENTS (0xffff + 2)
+
+#if 0
+#define DEBUG(format, ...) printf(format, ## __VA_ARGS__)
+#else
+#define DEBUG(format, ...)
+#endif
+
+#define PRINT(format, ...) printf(format, ## __VA_ARGS__)
+
+/* Represents a free range of a virtual address space. */
+typedef struct range {
+   uintptr_t     start;
+   uintptr_t     end;
+   size_t        size;
+   struct range *next;
+} range_t;
+
+/* Processes a single prmap_t entry and builds the free ranges. */
+static int process_map(const prmap_t *map, range_t **ranges_head,
+                       range_t **ranges_tail, size_t page_size)
+{
+   assert(map != NULL);
+   assert(ranges_head != NULL);
+   assert(ranges_tail != NULL);
+
+   range_t *head = *ranges_head;
+   range_t *tail = *ranges_tail;
+
+   DEBUG("processing map with addr=%p and size=%zu\n",
+         map->pr_vaddr, map->pr_size);
+
+   if (head == NULL) {
+      head = calloc(1, sizeof(range_t));
+      if (head == NULL) {
+         fprintf(stderr, "calloc failed\n");
+         return -1;
+      }
+      head->start = (uintptr_t) page_size; // do not start at address '0'
+
+      tail = head;
+      *ranges_head = head;
+      *ranges_tail = tail;
+   }
+
+   if ((map->pr_vaddr < tail->start) ||
+       (map->pr_vaddr - tail->start < 3 * page_size)) {
+      DEBUG("last range at %p is too small, skipping it\n",
+            tail->start);
+      tail->start = map->pr_vaddr + map->pr_size + page_size;
+      return 0;
+   }
+
+   tail->end = map->pr_vaddr - page_size;
+   tail->size = tail->end - tail->start;
+
+   range_t *new_one = calloc(1, sizeof(range_t));
+   if (new_one == NULL) {
+      fprintf(stderr, "calloc failed\n");
+      return -1;
+   }
+
+   new_one->start = map->pr_vaddr + map->pr_size + page_size;
+   tail->next = new_one;
+   *ranges_tail = new_one;
+   return 0;
+}
+
+/* Reads /proc/self/map and builds free ranges. */
+static range_t *read_proc_map(size_t page_size)
+{
+   int fd = open("/proc/self/map", O_RDONLY);
+   if (fd == -1) {
+      int error = errno;
+      fprintf(stderr, "open failed: %s (%d)\n", strerror(error), error);
+      return NULL;
+   }
+
+   prmap_t map;
+   range_t *ranges_head = NULL;
+   range_t *ranges_tail = NULL;
+
+   ssize_t bytes = read(fd, &map, sizeof(map));
+   while (bytes == sizeof(map)) {
+      if (map.pr_size != 0) {
+         if (process_map(&map, &ranges_head, &ranges_tail,
+                         page_size) != 0) {
+            return NULL;
+         }
+      }
+      bytes = read(fd, &map, sizeof(map));
+   }
+
+   if (ranges_tail != NULL) {
+      ranges_tail->end = (uintptr_t) ~0;
+      ranges_tail->size = ranges_tail->end - ranges_tail->start;
+   }
+
+   close(fd);
+   return ranges_head;
+}
+
+static void print_ranges(const range_t *head)
+{
+   while (head != NULL) {
+      DEBUG("free range [%8p - %8p] of size %7zuK\n",
+            head->start, head->end, head->size / 1024);
+      head = head->next;
+   }
+}
+
+static size_t sum_ranges(const range_t *head)
+{
+   size_t sum = 0;
+
+   while (head != NULL) {
+      sum += head->size;
+      head = head->next;
+   }
+
+   return sum;
+}
+
+static void *map_segment(void *fixed_addr)
+{
+   int flags = MAP_NORESERVE | MAP_ANON | MAP_PRIVATE | MAP_FIXED;
+   void *addr = mmap(fixed_addr, 1, PROT_READ | PROT_WRITE,
+                     flags, -1, 0);
+   if (addr == MAP_FAILED) {
+      int error = errno;
+      fprintf(stderr, "mmap failed: %s (%d)\n", strerror(error), error);
+      return NULL;
+   }
+   assert(addr == fixed_addr);
+
+   *((char *) addr) = 1; // make the mmap'ed page dirty
+   // DEBUG("mmap(%8p) = %8p\n", fixed_addr, addr);
+   return addr;
+}
+
+int main(int argc, const char *argv[])
+{
+   long page_size = sysconf(_SC_PAGESIZE);
+   if (page_size == -1) {
+      perror("sysconf");
+      return 1;
+   }
+
+   PRINT("Page size determined as %ld bytes.\n", page_size);
+
+   range_t *ranges = read_proc_map(page_size);
+   print_ranges(ranges);
+
+   size_t sum = sum_ranges(ranges);
+   if (sum < SEGMENTS * page_size) {
+      fprintf(stderr, "Free (virtual) address space cannot accomodate "
+              "%u pages.\n", SEGMENTS);
+      return 1;
+   }
+
+   PRINT("mmap()'ing %u segments:", SEGMENTS);
+   fflush(stdout);
+
+   unsigned int segment = 0;
+   while ((ranges != NULL) && (segment < SEGMENTS)) {
+      unsigned int page;
+      for (page = 0; page < ranges->size / (2 * page_size); page++) {
+         uintptr_t start = ranges->start + 2 * page * page_size;
+         void *addr = map_segment((void *) start);
+         if (addr == NULL) {
+            fprintf(stderr, "Mapping failed for segment %u at address "
+                    "%" PRIxPTR ".\n", segment, start);
+            return 1;
+         }
+
+         segment += 1;
+         if (segment >= SEGMENTS) {
+            break;
+         }
+
+         if (segment % (SEGMENTS / 10) == 0) {
+            PRINT(" %u0%%", segment / (SEGMENTS / 10));
+            fflush(stdout);
+         }
+      }
+      ranges = ranges->next;
+   }
+   assert(segment == SEGMENTS);
+
+   PRINT(".\nDumping core...\n");
+   char *nihil = NULL;
+   *nihil = 0; // SEGV here
+   fprintf(stderr, "Should not reach here.\n");
+
+   return 0;
+}
diff --git a/none/tests/solaris/coredump_many_threads.c b/none/tests/solaris/coredump_many_threads.c
new file mode 100644
index 0000000..1b45a17
--- /dev/null
+++ b/none/tests/solaris/coredump_many_threads.c
@@ -0,0 +1,100 @@
+/*
+ * Creates 8 threads. The fifth one (counting the main thread as well)
+ * causes a core dump.
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NEVERENDING_SLEEP 10000
+
+static pthread_barrier_t barrier;
+
+static void *thread_func2(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func3(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func4(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func5(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(2);
+
+   char *x = (char *) 0x1;
+   *x = 2;
+   return NULL;
+}
+
+static void *thread_func6(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func7(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func8(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void *thread_func9(void *arg) {
+   pthread_barrier_wait(&barrier);
+   sleep(NEVERENDING_SLEEP);
+   return NULL;
+}
+
+static void create_thread(void *(*thread_func)(void *))
+{
+   pthread_t thread;
+
+   int ret = pthread_create(&thread, NULL, thread_func, NULL);
+   if (ret != 0) {
+      fprintf(stderr, "pthread_create: %s (%d)\n", strerror(ret), ret);
+      exit(1);
+   }
+}
+
+int main(int argc, const char *argv[])
+{
+   int ret = pthread_barrier_init(&barrier, NULL, 9);
+   if (ret != 0) {
+      fprintf(stderr, "pthread_barrier_init: %s (%d)\n",
+              strerror(ret), ret);
+      exit(1);
+   }
+
+   create_thread(thread_func2);
+   create_thread(thread_func3);
+   create_thread(thread_func4);
+   create_thread(thread_func5);
+   create_thread(thread_func6);
+   create_thread(thread_func7);
+   create_thread(thread_func8);
+   create_thread(thread_func9);
+   pthread_barrier_wait(&barrier);
+
+   sleep(NEVERENDING_SLEEP);
+   return 0;
+}
diff --git a/none/tests/solaris/coredump_many_threads.post.exp b/none/tests/solaris/coredump_many_threads.post.exp
new file mode 100644
index 0000000..5c94dc2
--- /dev/null
+++ b/none/tests/solaris/coredump_many_threads.post.exp
@@ -0,0 +1,59 @@
+---Status---
+debugging core file of coredump_many_t from ...
+initial argv: ./coredump_many_threads
+threading model: native threads
+status: process terminated by SIGSEGV (Segmentation Fault), addr=........
+
+---Stacks---
+THREAD STATE SOBJ COUNT
+5 UNPARKED <NONE> 1
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+1 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`main
+coredump_many_threads`_start
+
+2 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func2
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+3 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func3
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+4 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func4
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+6 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func6
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+7 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func7
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+8 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func8
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
+9 UNPARKED <NONE> 1
+libc.so.1`sleep
+coredump_many_threads`thread_func9
+libc.so.1`_thrp_setup
+libc.so.1`_lwp_start
+
diff --git a/none/tests/solaris/coredump_many_threads.stderr.exp b/none/tests/solaris/coredump_many_threads.stderr.exp
new file mode 100644
index 0000000..3ffdf6d
--- /dev/null
+++ b/none/tests/solaris/coredump_many_threads.stderr.exp
@@ -0,0 +1,11 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: thread_func5 (coredump_many_threads.c:40)
+   by 0x........: _thrp_setup (in /...libc...)
+   by 0x........: ??? (in /...libc...)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
diff --git a/none/tests/solaris/coredump_many_threads.vgtest b/none/tests/solaris/coredump_many_threads.vgtest
new file mode 100644
index 0000000..807751b
--- /dev/null
+++ b/none/tests/solaris/coredump_many_threads.vgtest
@@ -0,0 +1,6 @@
+prereq: rm -f vgcore.*
+prog: coredump_many_threads
+vgopts: -q
+stderr_filter: ./filter_coredump_many_threads_stderr
+post: ./filter_coredump_many_threads_post
+cleanup: rm -f vgcore.*
diff --git a/none/tests/solaris/filter_coredump_many_threads_post b/none/tests/solaris/filter_coredump_many_threads_post
new file mode 100755
index 0000000..5a893a2
--- /dev/null
+++ b/none/tests/solaris/filter_coredump_many_threads_post
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# Filters are not run for post-test check commands.
+# Filter everything here.
+
+echo "---Status---"
+echo "::status" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/\(.*\) from \S*$/from .../' | \
+perl -0 -p -e 's/^file: .+?^(initial argv:)/$1/ms' | \
+perl -p -e 's/addr=[0-9A-Fa-f]+/addr=......../g'
+
+echo "\n---Stacks---"
+echo "::stacks ! perl -p -e 's/^(\S+)\+.*/\$1/g'" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/^(THREAD)\s+(STATE)\s+(SOBJ)\s+(COUNT)\s*$/$1 $2 $3 $4\n/' | \
+perl -p -e 's/^(\d+)\s+(UNPARKED)\s+(\S+)\s+(\d+)/$1 $2 $3 $4/g' | \
+perl -p -e 's/^\s*libc.*.so.1/libc.so.1/g' | \
+perl -p -e 's/^\s*(coredump_many_threads)/$1/g' | \
+perl -p -e 's/\+0x[0-9A-Fa-f]+//g'
diff --git a/none/tests/solaris/filter_coredump_many_threads_stderr b/none/tests/solaris/filter_coredump_many_threads_stderr
new file mode 100755
index 0000000..449556d
--- /dev/null
+++ b/none/tests/solaris/filter_coredump_many_threads_stderr
@@ -0,0 +1,7 @@
+#! /bin/sh
+
+# Sometimes valgrind on amd64 prints smt_pause() instead of ???
+# for the top-most stack frame. Filter it here.
+
+./filter_stderr | \
+sed -e 's/smt_pause/???/'
diff --git a/none/tests/solaris/filter_stderr b/none/tests/solaris/filter_stderr
new file mode 100755
index 0000000..0ae9313
--- /dev/null
+++ b/none/tests/solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/none/tests/solaris/mmap_noreserve.c b/none/tests/solaris/mmap_noreserve.c
new file mode 100644
index 0000000..975e951
--- /dev/null
+++ b/none/tests/solaris/mmap_noreserve.c
@@ -0,0 +1,90 @@
+/* Maps several pages with or without MAP_NORESEVE.
+   Mappings with MAP_NORESEVE do not show in /proc/self/xmap
+   (only in /proc/self/rmap) until they actually materialize.
+   Very nice from Solaris kernel :-(
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <wait.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+
+static void *do_map(int flags)
+{
+   flags |= MAP_PRIVATE | MAP_ANON;
+   void *addr = mmap(0, PAGESIZE, PROT_READ | PROT_WRITE, flags, -1, 0);
+   if (addr == NULL) {
+      perror("mmap");
+      exit(1);
+   } else {
+      return addr;
+   }
+}
+
+static void *do_dlopen(const char *pathname)
+{
+   int mode = RTLD_LAZY | RTLD_LOCAL;
+   void *handle = dlopen(pathname, mode);
+   if (handle == NULL) {
+      fprintf(stderr, "dlopen failed for %s: %s",
+              pathname, dlerror());
+      exit(1);
+   } else {
+      return handle;
+   }
+}
+
+int main(int argc, const char *argv[])
+{
+   do_map(MAP_NORESERVE);
+   do_dlopen("libm.so");
+   do_map(0);
+   do_map(0);
+   do_map(MAP_NORESERVE);
+   do_dlopen("liby.so");
+   do_map(MAP_NORESERVE);
+   do_map(0);
+   do_map(0);
+   do_map(MAP_NORESERVE);
+   do_map(MAP_NORESERVE);
+   do_dlopen("libz.so");
+   do_map(MAP_NORESERVE);
+   do_map(MAP_NORESERVE);
+   do_map(0);
+
+   pid_t pid = fork();
+   if (pid == -1) {
+      perror("fork");
+      exit(1);
+   }
+
+   if (pid == 0) {
+      do_map(MAP_NORESERVE);
+      do_map(0);
+      do_map(0);
+      do_dlopen("libw.so");
+      do_map(0);
+      do_map(MAP_NORESERVE);
+      do_map(MAP_NORESERVE);
+      do_map(0);
+      printf("CHILD: PASSED\n");
+      fflush(stdout);
+      return 0;
+   }
+
+   int status;
+   if (waitpid(pid, &status, 0) != pid) {
+      perror("waitpid");
+   } else if ((WIFEXITED(status) != 0) && (WEXITSTATUS(status) == 0)) {
+      printf("PASSED\n");
+   } else {
+      fprintf(stderr, "FAILED: child exited with unexpected status %s %d\n",
+              WIFEXITED(status) ? "exit" : "signal", 
+              WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status));
+   }
+
+   return 0;
+}
diff --git a/none/tests/solaris/mmap_noreserve.stderr.exp b/none/tests/solaris/mmap_noreserve.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/mmap_noreserve.stderr.exp
diff --git a/none/tests/solaris/mmap_noreserve.stdout.exp b/none/tests/solaris/mmap_noreserve.stdout.exp
new file mode 100644
index 0000000..44ea7f1
--- /dev/null
+++ b/none/tests/solaris/mmap_noreserve.stdout.exp
@@ -0,0 +1,2 @@
+CHILD: PASSED
+PASSED
diff --git a/none/tests/solaris/mmap_noreserve.vgtest b/none/tests/solaris/mmap_noreserve.vgtest
new file mode 100644
index 0000000..915c260
--- /dev/null
+++ b/none/tests/solaris/mmap_noreserve.vgtest
@@ -0,0 +1,3 @@
+prog: mmap_noreserve
+vgopts: -q --sanity-level=3
+stderr_filter: filter_stderr
diff --git a/none/tests/solaris/posix_spawn.c b/none/tests/solaris/posix_spawn.c
new file mode 100644
index 0000000..d37ecd1
--- /dev/null
+++ b/none/tests/solaris/posix_spawn.c
@@ -0,0 +1,54 @@
+/* Test that an error from posix_spawn() is correctly propagated to the
+   parent. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <spawn.h>
+
+int main(void)
+{
+   int res = 1;
+   int err;
+   posix_spawn_file_actions_t file_actions;
+   char *argv_exe[] = {"true", NULL};
+   char *envv_exe[] = {NULL};
+
+   err = posix_spawn_file_actions_init(&file_actions);
+   if (err != 0) {
+      errno = err;
+      perror("posix_spawn_file_actions_init");
+      return 1;
+   }
+
+   err = posix_spawn_file_actions_adddup2(&file_actions, 3, 4);
+   if (err != 0) {
+      errno = err;
+      perror("posix_spawn_file_actions_adddup2");
+      goto out;
+   }
+
+   /* The following call to posix_spawn() should fail because the requested
+      dup2 action cannot be performed. */
+   err = posix_spawn(NULL, "/bin/true", &file_actions, NULL, argv_exe,
+                     envv_exe);
+   if (err != 0) {
+      errno = err;
+      perror("posix_spawn");
+      goto out;
+   }
+
+   res = 0;
+
+out:
+   err = posix_spawn_file_actions_destroy(&file_actions);
+   if (err != 0) {
+      errno = err;
+      perror("posix_spawn_file_actions_destroy");
+      res = 1;
+   }
+
+   return res;
+}
+
diff --git a/none/tests/solaris/posix_spawn.stderr.exp b/none/tests/solaris/posix_spawn.stderr.exp
new file mode 100644
index 0000000..017e9cf
--- /dev/null
+++ b/none/tests/solaris/posix_spawn.stderr.exp
@@ -0,0 +1 @@
+posix_spawn: Bad file number
diff --git a/none/tests/solaris/posix_spawn.stdout.exp b/none/tests/solaris/posix_spawn.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/posix_spawn.stdout.exp
diff --git a/none/tests/solaris/posix_spawn.vgtest b/none/tests/solaris/posix_spawn.vgtest
new file mode 100644
index 0000000..38f7fdd
--- /dev/null
+++ b/none/tests/solaris/posix_spawn.vgtest
@@ -0,0 +1,2 @@
+prog: posix_spawn
+vgopts: -q
diff --git a/none/tests/solaris/proc_aout.c b/none/tests/solaris/proc_aout.c
new file mode 100644
index 0000000..872426e
--- /dev/null
+++ b/none/tests/solaris/proc_aout.c
@@ -0,0 +1,71 @@
+/* Test whether /proc/{self,$PID}/path/a.out is correctly simulated. */
+
+#include <limits.h>
+#include <stdio.h>
+#include <strings.h>
+#include <unistd.h>
+#include <sys/fcntl.h>
+
+static void test_readlink(const char *cwd, const char *label,
+      const char *path)
+{
+   char buf[PATH_MAX];
+   int n;
+
+   if ((n = readlink(path, buf, sizeof(buf) - 1)) >= 0) {
+      const char *p;
+      size_t len = strlen(cwd);
+
+      buf[n] = '\0';
+
+      p = buf;
+      if (!strncmp(buf, cwd, len))
+         p += len;
+      printf("Result of readlink(\"%s\"): %s\n", label, p);
+   }
+   else
+      perror("readlink");
+}
+
+static void test_readlinkat(const char *cwd, const char *label,
+      const char *path)
+{
+   char buf[PATH_MAX];
+   int n;
+
+   if ((n = readlinkat(AT_FDCWD, path, buf, sizeof(buf) - 1)) >= 0) {
+      const char *p;
+      size_t len = strlen(cwd);
+
+      buf[n] = '\0';
+
+      p = buf;
+      if (!strncmp(buf, cwd, len))
+         p += len;
+      printf("Result of readlinkat(\"%s\"): %s\n", label, p);
+   }
+   else
+      perror("readlinkat");
+}
+
+int main(void)
+{
+   char cwd[PATH_MAX];
+   char path[PATH_MAX];
+
+   cwd[0] = '\0';
+   if (!getcwd(cwd, sizeof(cwd) - 1)) /* '-1' to make room for '/' */
+      perror("getcwd");
+   strcat(cwd, "/");
+
+   snprintf(path, sizeof(path), "/proc/%ld/path/a.out", (long)getpid());
+
+   test_readlink(cwd, "/proc/self/path/a.out", "/proc/self/path/a.out");
+   test_readlink(cwd, "/proc/<pid>/path/a.out", path);
+
+   test_readlinkat(cwd, "/proc/self/path/a.out", "/proc/self/path/a.out");
+   test_readlinkat(cwd, "/proc/<pid>/path/a.out", path);
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/proc_aout.stderr.exp b/none/tests/solaris/proc_aout.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/proc_aout.stderr.exp
diff --git a/none/tests/solaris/proc_aout.stdout.exp b/none/tests/solaris/proc_aout.stdout.exp
new file mode 100644
index 0000000..49f3e01
--- /dev/null
+++ b/none/tests/solaris/proc_aout.stdout.exp
@@ -0,0 +1,4 @@
+Result of readlink("/proc/self/path/a.out"): proc_aout
+Result of readlink("/proc/<pid>/path/a.out"): proc_aout
+Result of readlinkat("/proc/self/path/a.out"): proc_aout
+Result of readlinkat("/proc/<pid>/path/a.out"): proc_aout
diff --git a/none/tests/solaris/proc_aout.vgtest b/none/tests/solaris/proc_aout.vgtest
new file mode 100644
index 0000000..960e758
--- /dev/null
+++ b/none/tests/solaris/proc_aout.vgtest
@@ -0,0 +1,2 @@
+prog: proc_aout
+vgopts: -q
diff --git a/none/tests/solaris/proc_auxv.c b/none/tests/solaris/proc_auxv.c
new file mode 100644
index 0000000..4af8f57
--- /dev/null
+++ b/none/tests/solaris/proc_auxv.c
@@ -0,0 +1,91 @@
+/* Test if /proc/{self,$PID}/auxv is correctly simulated and that the aux
+   vector contains plausible values. */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/auxv.h>
+#include <sys/fcntl.h>
+
+static int check_file(const char *path, auxv_t *auxv)
+{
+   auxv_t rauxv;
+   int res = 1;
+   FILE *fi;
+
+   if (!(fi = fopen(path, "r"))) {
+      perror("fopen");
+      return 1;
+   }
+   while (1) {
+      if (fread(&rauxv, sizeof(rauxv), 1, fi) != 1) {
+         if (ferror(fi)) {
+            perror("fread");
+            goto out;
+         }
+         fprintf(stderr, "unexpected EOF\n");
+         goto out;
+      }
+      if (memcmp(auxv, &rauxv, sizeof(rauxv))) {
+         fprintf(stderr, "incorrect auxv in %s\n", path);
+         fprintf(stderr, "expected: type=%d, val=%ld\n", auxv->a_type,
+                 auxv->a_un.a_val);
+         fprintf(stderr, "got: type=%d, val=%ld\n", rauxv.a_type,
+                 rauxv.a_un.a_val);
+         goto out;
+      }
+
+      if (auxv->a_type == AT_NULL)
+         break;
+
+      auxv++;
+   }
+
+   res = 0;
+
+out:
+   fclose(fi);
+   return res;
+}
+
+int main(int argc, char *argv[], char *envp[])
+{
+   auxv_t *auxv;
+   char buf[128];
+
+   /* Find aux vector. */
+   while (*envp)
+      envp++;
+   auxv = (auxv_t*)(envp + 1);
+
+   /* /proc/self/auxv check */
+   if (check_file("/proc/self/auxv", auxv))
+      return 1;
+
+   /* /proc/$PID/auxv check */
+   snprintf(buf, sizeof(buf), "/proc/%ld/auxv", (long)getpid());
+   if (check_file(buf, auxv))
+      return 1;
+
+   /* AT_SUN_EXECNAME check */
+   while (auxv->a_type != AT_NULL) {
+      if (auxv->a_type == AT_SUN_EXECNAME) {
+         const char *execname = auxv->a_un.a_ptr;
+         if (!execname) {
+            fprintf(stderr, "AT_SUN_EXECNAME is null\n");
+            return 1;
+         }
+         if (access(execname, R_OK | X_OK)) {
+            fprintf(stderr, "AT_SUN_EXECNAME (%s) is invalid: %s\n",
+                    execname, strerror(errno));
+            return 1;
+         }
+         break;
+      }
+      auxv++;
+   }
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/proc_auxv.stderr.exp b/none/tests/solaris/proc_auxv.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/proc_auxv.stderr.exp
diff --git a/none/tests/solaris/proc_auxv.stdout.exp b/none/tests/solaris/proc_auxv.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/proc_auxv.stdout.exp
diff --git a/none/tests/solaris/proc_auxv.vgtest b/none/tests/solaris/proc_auxv.vgtest
new file mode 100644
index 0000000..df3a009
--- /dev/null
+++ b/none/tests/solaris/proc_auxv.vgtest
@@ -0,0 +1,2 @@
+prog: proc_auxv
+vgopts: -q
diff --git a/none/tests/solaris/proc_auxv_multiple.c b/none/tests/solaris/proc_auxv_multiple.c
new file mode 100644
index 0000000..a03dbb4
--- /dev/null
+++ b/none/tests/solaris/proc_auxv_multiple.c
@@ -0,0 +1,91 @@
+/* Test that /proc/{self,$PID}/auxv can be opened and read simultaneously
+   using two different file descriptors. */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/auxv.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+/* Reads one auxv_t entry from the input file. */
+int read_entry(int fi, auxv_t *out)
+{
+   size_t toread = sizeof(*out);
+   char *ptr = (char*)out;
+
+   while (toread) {
+      ssize_t r;
+
+      r = read(fi, ptr, toread);
+      if (r == 0) {
+         fprintf(stderr, "unexpected EOF\n");
+         return 1;
+      }
+      if (r == -1) {
+         perror("read");
+         return 1;
+      }
+
+      ptr += r;
+      toread -= r;
+
+      assert(toread >= 0);
+   }
+
+   return 0;
+}
+
+int main(void)
+{
+   auxv_t vector[2][4];
+   int fi[2] = {-1, -1};
+   size_t i;
+   int res = 1;
+
+   /* Open the first input file. */
+   if ((fi[0] = open("/proc/self/auxv", O_RDONLY)) == -1) {
+      perror("open");
+      goto out;
+   }
+
+   /* Read the first two entries from the first file. */
+   for (i = 0; i < 2; i++)
+      if (read_entry(fi[0], &vector[0][i]))
+         goto out;
+
+   /* Open the second input file. */
+   if ((fi[1] = open("/proc/self/auxv", O_RDONLY)) == -1) {
+      perror("open");
+      goto out;
+   }
+
+   /* Read the first two entries from the first file. */
+   for (i = 2; i < 4; i++)
+      if (read_entry(fi[0], &vector[0][i]))
+         goto out;
+
+   /* Read the first four entries from the second file. */
+   for (i = 0; i < 4; i++)
+      if (read_entry(fi[1], &vector[1][i]))
+         goto out;
+
+   /* Compare read vectors. */
+   if (memcmp(vector[0], vector[1], 4 * sizeof(vector[0][0]))) {
+      fprintf(stderr, "vectors differ\n");
+      goto out;
+   }
+
+   res = 0;
+
+out:
+   for (i = 0; i < 2; i++)
+      if (fi[i] >= 0)
+         close(fi[i]);
+
+   return res;
+}
+
diff --git a/none/tests/solaris/proc_auxv_multiple.stderr.exp b/none/tests/solaris/proc_auxv_multiple.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/proc_auxv_multiple.stderr.exp
diff --git a/none/tests/solaris/proc_auxv_multiple.stdout.exp b/none/tests/solaris/proc_auxv_multiple.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/proc_auxv_multiple.stdout.exp
diff --git a/none/tests/solaris/proc_auxv_multiple.vgtest b/none/tests/solaris/proc_auxv_multiple.vgtest
new file mode 100644
index 0000000..d8dbdb7
--- /dev/null
+++ b/none/tests/solaris/proc_auxv_multiple.vgtest
@@ -0,0 +1,2 @@
+prog: proc_auxv_multiple
+vgopts: -q
diff --git a/none/tests/solaris/proc_psinfo.c b/none/tests/solaris/proc_psinfo.c
new file mode 100644
index 0000000..da4109f
--- /dev/null
+++ b/none/tests/solaris/proc_psinfo.c
@@ -0,0 +1,69 @@
+/*
+ * Reads /proc/self/psinfo such that it can be tested whether Valgrind
+ * intercepts the system calls that access this pseudo-file.
+ */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <procfs.h>
+#include <stdio.h>
+#include <unistd.h>
+
+static void test_psinfo(int op, const char *label,
+                        const char *path)
+{
+   int fd;
+   if (op == 0) {
+      printf("open for %s:\n", label);
+
+      fd = open(path, O_RDONLY); 
+      if (fd < 0) {
+         perror("open");
+         return;
+      }
+   } else {
+      printf("openat for %s:\n", label);
+
+      fd = openat(AT_FDCWD, path, O_RDONLY);
+      if (fd < 0) {
+         perror("openat");
+         return;
+      }
+   }
+
+   psinfo_t psinfo;
+   ssize_t bytes = read(fd, &psinfo, sizeof(psinfo));
+   if (bytes != sizeof(psinfo)) {
+      perror("read");
+      return;
+   }
+
+   printf("fname: %s\n", psinfo.pr_fname);
+   printf("psargs: %s\n", psinfo.pr_psargs);
+
+   printf("argc: %d\n", psinfo.pr_argc);
+   unsigned int i;
+   char **argv = (char **) psinfo.pr_argv;
+   for (i = 0; i < psinfo.pr_argc; i++) {
+      printf("argv[%u]: %s\n", i, argv[i]);
+   }
+
+   close(fd);
+}
+
+int main(int argc, const char *argv[])
+{
+   char path[PATH_MAX];
+   snprintf(path, sizeof(path), "/proc/%ld/psinfo", (long int) getpid());
+
+   test_psinfo(0, "/proc/self/psinfo", "/proc/self/psinfo");
+   printf("\n");
+   test_psinfo(0, "/proc/<pid>/psinfo", path);
+   printf("\n");
+
+   test_psinfo(1, "/proc/self/psinfo", "/proc/self/psinfo");
+   printf("\n");
+   test_psinfo(1, "/proc/<pid>/psinfo", path);
+
+   return 0;
+}
diff --git a/none/tests/solaris/proc_psinfo.stderr.exp b/none/tests/solaris/proc_psinfo.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/solaris/proc_psinfo.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/solaris/proc_psinfo.stdout.exp b/none/tests/solaris/proc_psinfo.stdout.exp
new file mode 100644
index 0000000..734f6c6
--- /dev/null
+++ b/none/tests/solaris/proc_psinfo.stdout.exp
@@ -0,0 +1,35 @@
+open for /proc/self/psinfo:
+fname: proc_psinfo
+psargs: ./proc_psinfo arg1 arg 2 arg3
+argc: 4
+argv[0]: ./proc_psinfo
+argv[1]: arg1
+argv[2]: arg 2
+argv[3]: arg3
+
+open for /proc/<pid>/psinfo:
+fname: proc_psinfo
+psargs: ./proc_psinfo arg1 arg 2 arg3
+argc: 4
+argv[0]: ./proc_psinfo
+argv[1]: arg1
+argv[2]: arg 2
+argv[3]: arg3
+
+openat for /proc/self/psinfo:
+fname: proc_psinfo
+psargs: ./proc_psinfo arg1 arg 2 arg3
+argc: 4
+argv[0]: ./proc_psinfo
+argv[1]: arg1
+argv[2]: arg 2
+argv[3]: arg3
+
+openat for /proc/<pid>/psinfo:
+fname: proc_psinfo
+psargs: ./proc_psinfo arg1 arg 2 arg3
+argc: 4
+argv[0]: ./proc_psinfo
+argv[1]: arg1
+argv[2]: arg 2
+argv[3]: arg3
diff --git a/none/tests/solaris/proc_psinfo.vgtest b/none/tests/solaris/proc_psinfo.vgtest
new file mode 100644
index 0000000..88fdc8c
--- /dev/null
+++ b/none/tests/solaris/proc_psinfo.vgtest
@@ -0,0 +1,2 @@
+prog: proc_psinfo
+args: arg1 "arg 2" arg3
diff --git a/none/tests/solaris/pthread-stack.c b/none/tests/solaris/pthread-stack.c
new file mode 100644
index 0000000..af589c4
--- /dev/null
+++ b/none/tests/solaris/pthread-stack.c
@@ -0,0 +1,104 @@
+/* This test causes an error in 3.10.1 and earlier versions like so:
+
+==8336== Can't extend stack to 0x4033f98 during signal delivery for thread 2:
+==8336==   no stack segment
+
+  The reason was that only AnonC segments were considered as stack
+  segments. */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+static volatile char *lowest_j;
+static jmp_buf goback;
+
+static void sigsegv_handler(int signr)
+{
+   longjmp(goback, 1);
+}
+
+static void bad_things_till_guard_page(void)
+{
+   fprintf(stderr, "... doing bad things till guard page\n");
+   char j = 0;
+   char *p = &j;
+
+   for (;;) {
+      j = j + *p;
+      p = p - 400;
+      lowest_j = p;
+   }
+}
+
+static void say_something(void)
+{
+  fprintf(stderr, "plugh\n");
+}
+
+static void *child_func(void *arg)
+{
+   if (setjmp(goback))
+      say_something();
+   else
+      bad_things_till_guard_page();
+
+   return NULL;
+}
+
+int main(int argc, const char *argv[])
+{
+   /* We will discover the thread guard page using SEGV.
+      So, prepare a handler. */
+   struct sigaction sa;
+   sa.sa_handler = sigsegv_handler;
+   sigemptyset(&sa.sa_mask);
+   sa.sa_flags = 0;
+   if (sigaction(SIGSEGV, &sa, NULL) != 0)
+      perror("sigaction");
+
+   /* Create a file that will be used as stack for a pthread.  */
+   size_t file_size = 1024 * 1024;
+   const char file_name[] = "FILE";
+   int fd = open(file_name, O_CREAT|O_WRONLY,
+                 S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+   assert(fd >= 0);
+   void *p = calloc(file_size, 1);
+   assert(p != 0);
+   int written = write(fd, p, file_size);
+   assert(written == file_size);
+   close(fd);
+
+   /* Create a file-based stack for the child. */
+   fd = open(file_name, O_CREAT|O_RDWR,
+             S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+   assert(fd >= 0);
+   const size_t stack_size = 256 * 1024;
+   assert(stack_size < file_size);
+   void *stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE,
+                      MAP_PRIVATE, fd, 0);
+   assert(stack != (void *)-1);
+   pthread_attr_t attr;
+   pthread_attr_init(&attr);
+   int r = pthread_attr_setstack(&attr, stack, stack_size);
+   assert(r == 0);
+
+   /* Create child run. */
+   pthread_t child;
+   r = pthread_create(&child, &attr, child_func, NULL);
+   assert(r == 0);
+   r = pthread_join(child, NULL);
+   assert(r == 0);
+
+   /* Remove file */
+   unlink(file_name);
+   return 0;
+}
+
diff --git a/none/tests/solaris/pthread-stack.stderr.exp b/none/tests/solaris/pthread-stack.stderr.exp
new file mode 100644
index 0000000..391e60c
--- /dev/null
+++ b/none/tests/solaris/pthread-stack.stderr.exp
@@ -0,0 +1,2 @@
+... doing bad things till guard page
+plugh
diff --git a/none/tests/solaris/pthread-stack.vgtest b/none/tests/solaris/pthread-stack.vgtest
new file mode 100644
index 0000000..50cafcb
--- /dev/null
+++ b/none/tests/solaris/pthread-stack.vgtest
@@ -0,0 +1,2 @@
+prog: pthread-stack
+vgopts: -q
diff --git a/none/tests/solaris/resolv.c b/none/tests/solaris/resolv.c
new file mode 100644
index 0000000..078e142
--- /dev/null
+++ b/none/tests/solaris/resolv.c
@@ -0,0 +1,20 @@
+/* Tests initialization of the resolver library.
+ * Adapted from none/tests/resolv for Solaris.
+ */
+
+#include <resolv.h>
+#include <stdio.h>
+#include <strings.h>
+
+int main(int argc, char *argv[])
+{
+   struct __res_state stats;
+   bzero(&stats, sizeof(stats));
+
+   printf("PRE stats->nscount = %d\n", stats.nscount );
+   fflush(stdout);
+   res_ninit(&stats);
+   printf("POST stats->nscount = %d\n", ( int ) stats.nscount > 0 );
+   fflush(stdout);
+   return 0;
+}
diff --git a/none/tests/solaris/resolv.stderr.exp b/none/tests/solaris/resolv.stderr.exp
new file mode 100644
index 0000000..139597f
--- /dev/null
+++ b/none/tests/solaris/resolv.stderr.exp
@@ -0,0 +1,2 @@
+
+
diff --git a/none/tests/solaris/resolv.stdout.exp b/none/tests/solaris/resolv.stdout.exp
new file mode 100644
index 0000000..e843305
--- /dev/null
+++ b/none/tests/solaris/resolv.stdout.exp
@@ -0,0 +1,2 @@
+PRE stats->nscount = 0
+POST stats->nscount = 1
diff --git a/none/tests/solaris/resolv.vgtest b/none/tests/solaris/resolv.vgtest
new file mode 100644
index 0000000..e8c1e29
--- /dev/null
+++ b/none/tests/solaris/resolv.vgtest
@@ -0,0 +1 @@
+prog: resolv
diff --git a/none/tests/solaris/sigresend.c b/none/tests/solaris/sigresend.c
new file mode 100644
index 0000000..9ed4aeb
--- /dev/null
+++ b/none/tests/solaris/sigresend.c
@@ -0,0 +1,73 @@
+/* Test to check that the mask parameter of the sigresend syscall is handled
+   correctly. */
+
+#include <assert.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+static void signal_handler(int signo, siginfo_t *info, void *uc)
+{
+   ssize_t written;
+   const char str[] = "Signal caught.\n";
+   size_t len = sizeof(str) - 1;
+   sigset_t current;
+
+   written = write(STDOUT_FILENO, str, len);
+   assert(written == len);
+
+   /* Check that SIGUSR1 is already blocked in the signal handler. */
+   assert(!sigprocmask(SIG_BLOCK, NULL, &current));
+   assert(sigismember(&current, SIGUSR1));
+}
+
+int main(void)
+{
+   sigset_t block, current;
+   struct sigaction sa;
+
+   /* Check that SIGUSR1 is unblocked. */
+   if (sigprocmask(0, NULL, &current)) {
+      perror("sigprocmask");
+      return 1;
+   }
+   assert(!sigismember(&current, SIGUSR1));
+
+   /* Establish a SIGINT handler. */
+   sa.sa_sigaction = signal_handler;
+   sa.sa_flags = SA_RESTART | SA_SIGINFO;
+   if (sigfillset(&sa.sa_mask)) {
+      perror("sigfillset");
+      return 1;
+   }
+   if (sigaction(SIGINT, &sa, NULL)) {
+      perror("sigaction");
+      return 1;
+   }
+
+   /* Send us a signal to handle and install a new sigmask. */
+   if (sigemptyset(&block)) {
+      perror("sigemptyset");
+      return 1;
+   }
+   if (sigaddset(&block, SIGUSR1)) {
+      perror("sigaddset");
+      return 1;
+   }
+   if (syscall(SYS_sigresend, SIGINT, NULL, &block)) {
+      fprintf(stderr, "Sigresend failed.\n");
+      return 1;
+   }
+
+   /* Check that SIGUSR1 is now blocked. */
+   if (sigprocmask(SIG_BLOCK, NULL, &current)) {
+      perror("sigprocmask");
+      return 1;
+   }
+   assert(sigismember(&current, SIGUSR1));
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/sigresend.stderr.exp b/none/tests/solaris/sigresend.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/sigresend.stderr.exp
diff --git a/none/tests/solaris/sigresend.stdout.exp b/none/tests/solaris/sigresend.stdout.exp
new file mode 100644
index 0000000..a49633f
--- /dev/null
+++ b/none/tests/solaris/sigresend.stdout.exp
@@ -0,0 +1 @@
+Signal caught.
diff --git a/none/tests/solaris/sigresend.vgtest b/none/tests/solaris/sigresend.vgtest
new file mode 100644
index 0000000..6df0094
--- /dev/null
+++ b/none/tests/solaris/sigresend.vgtest
@@ -0,0 +1,2 @@
+prog: sigresend
+vgopts: -q
diff --git a/none/tests/solaris/stack-overflow.c b/none/tests/solaris/stack-overflow.c
new file mode 100644
index 0000000..0ebbfbb
--- /dev/null
+++ b/none/tests/solaris/stack-overflow.c
@@ -0,0 +1,5 @@
+/* There should be a user message about the overflow.
+   Written in a single line so there is no confusion on what line
+   the overflow occurs. */
+
+int main(int argc, char *argv[]) { volatile int arr[1000]; return main(arr[argc%2], 0); }
diff --git a/none/tests/solaris/stack-overflow.stderr.exp b/none/tests/solaris/stack-overflow.stderr.exp
new file mode 100644
index 0000000..dd5e595
--- /dev/null
+++ b/none/tests/solaris/stack-overflow.stderr.exp
@@ -0,0 +1,13 @@
+
+Stack overflow in thread #1: can't grow stack to 0x........
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+Stack overflow in thread #1: can't grow stack to 0x........
+   at 0x........: main (stack-overflow.c:5)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
+
diff --git a/none/tests/solaris/stack-overflow.vgtest b/none/tests/solaris/stack-overflow.vgtest
new file mode 100644
index 0000000..3b9ffd4
--- /dev/null
+++ b/none/tests/solaris/stack-overflow.vgtest
@@ -0,0 +1 @@
+prog: stack-overflow
diff --git a/none/tests/solaris/stack_prot.c b/none/tests/solaris/stack_prot.c
new file mode 100644
index 0000000..8376245
--- /dev/null
+++ b/none/tests/solaris/stack_prot.c
@@ -0,0 +1,65 @@
+#include <procfs.h>
+#include <stdio.h>
+
+#define ARRAY_LENGTH(array) (sizeof((array)) / sizeof(0[(array)]))
+
+int main(void)
+{
+   int res = 1;
+   FILE *fi = NULL;
+   prxmap_t map[32];
+   int found = 0;
+   int done = 0;
+   /* Obtain an address inside the stack using a dirty trick. */
+   uintptr_t local = (uintptr_t)&fi;
+
+   /* Open /proc/self/xmap for reading. */
+   fi = fopen("/proc/self/xmap", "r");
+   if (!fi) {
+      perror("fopen");
+      goto out;
+   }
+
+   /* Read the file until EOF or the stack is found. */
+   while (!done && !found) {
+      size_t i, items;
+
+      items = fread(map, sizeof(map[0]), ARRAY_LENGTH(map), fi);
+      if (items != ARRAY_LENGTH(map)) {
+         if (ferror(fi)) {
+            perror("fread");
+            goto out;
+         }
+         done = 1;
+      }
+
+      /* Scan the read mappings. */
+      for (i = 0; i < items; i++)
+         if (map[i].pr_vaddr <= local
+             && local < map[i].pr_vaddr + map[i].pr_size) {
+            /* Stack was found, validate it. */
+            found = 1;
+            if ((map[i].pr_mflags & (MA_READ | MA_WRITE | MA_EXEC))
+                != (MA_READ | MA_WRITE)) {
+               fprintf(stderr, "Incorrect stack mapping detected.\n");
+               goto out;
+            }
+         }
+   }
+
+   /* Check if the stack was indeed found. */
+   if (!found) {
+      fprintf(stderr, "Stack not found.\n");
+      goto out;
+   }
+
+   res = 0;
+
+out:
+   /* Cleanup. */
+   if (fi)
+      fclose(fi);
+
+   return res;
+}
+
diff --git a/none/tests/solaris/stack_prot.stderr.exp b/none/tests/solaris/stack_prot.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/stack_prot.stderr.exp
diff --git a/none/tests/solaris/stack_prot.stdout.exp b/none/tests/solaris/stack_prot.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/stack_prot.stdout.exp
diff --git a/none/tests/solaris/stack_prot.vgtest b/none/tests/solaris/stack_prot.vgtest
new file mode 100644
index 0000000..3a3a920
--- /dev/null
+++ b/none/tests/solaris/stack_prot.vgtest
@@ -0,0 +1,2 @@
+prog: stack_prot
+vgopts: -q
diff --git a/none/tests/solaris/threads_exitall.c b/none/tests/solaris/threads_exitall.c
new file mode 100644
index 0000000..4899a1c
--- /dev/null
+++ b/none/tests/solaris/threads_exitall.c
@@ -0,0 +1,39 @@
+/* Test that all threads are killed when exit() is called. */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void *thread_proc(void *arg)
+{
+   /* Wait for main thread to block. */
+   sleep(2);
+
+   /* Exit the program. */
+   exit(0);
+
+   return NULL;
+}
+
+int main(void)
+{
+   pthread_t thread;
+   void *status;
+
+   if (pthread_create(&thread, NULL, thread_proc, NULL)) {
+      perror("pthread_create");
+      return 1;
+   }
+
+   if (pthread_join(thread, &status)) {
+      perror("pthread_join");
+      return 1;
+   }
+
+   /* This code should not be reached. */
+   fprintf(stderr, "Thread joined\n");
+
+   return 0;
+}
+
diff --git a/none/tests/solaris/threads_exitall.stderr.exp b/none/tests/solaris/threads_exitall.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/threads_exitall.stderr.exp
diff --git a/none/tests/solaris/threads_exitall.stdout.exp b/none/tests/solaris/threads_exitall.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/solaris/threads_exitall.stdout.exp
diff --git a/none/tests/solaris/threads_exitall.vgtest b/none/tests/solaris/threads_exitall.vgtest
new file mode 100644
index 0000000..a733071
--- /dev/null
+++ b/none/tests/solaris/threads_exitall.vgtest
@@ -0,0 +1,2 @@
+prog: threads_exitall
+vgopts: -q
diff --git a/none/tests/threadederrno.c b/none/tests/threadederrno.c
index 9d9b0ff..ffc735e 100644
--- a/none/tests/threadederrno.c
+++ b/none/tests/threadederrno.c
@@ -1,3 +1,5 @@
+/* Make sure we use the POSIX version of strerror_r() on Linux. */
+#define _XOPEN_SOURCE 600
 
 #include <pthread.h>
 #include <stdio.h>
@@ -7,27 +9,33 @@
 
 void* thr2 ( void* v )
 {
+  char errstr[128];
   FILE* f = fopen("bogus2", "r");
-  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, strerror(errno));
+  strerror_r(errno, errstr, sizeof(errstr));
+  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, errstr);
   return NULL;
 }
 
 void* thr3 ( void* v )
 {
+  char errstr[128];
   FILE* f = fopen("bogus3", "r");
-  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, strerror(errno));
+  strerror_r(errno, errstr, sizeof(errstr));
+  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, errstr);
   return NULL;
 }
 
 
 int main ( void )
 {
+  char errstr[128];
   FILE* f;
   pthread_t tid2, tid3;
   pthread_create(&tid2, NULL, &thr2, NULL);
   pthread_create(&tid3, NULL, &thr3, NULL);
   f = fopen("bogus", "r");
-  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, strerror(errno));
+  strerror_r(errno, errstr, sizeof(errstr));
+  printf("f  = %ld, errno  = %d (%s)\n", (long)f, errno, errstr);
   pthread_join(tid2, NULL);
   pthread_join(tid3, NULL);
   return 0;
diff --git a/none/tests/x86-solaris/Makefile.am b/none/tests/x86-solaris/Makefile.am
new file mode 100644
index 0000000..ee69b23
--- /dev/null
+++ b/none/tests/x86-solaris/Makefile.am
@@ -0,0 +1,25 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+	coredump_single_thread_mdb \
+	coredump_single_thread_sse_mdb \
+	filter_stderr
+	
+
+EXTRA_DIST = \
+	coredump_single_thread.post.exp coredump_single_thread.stderr.exp \
+	coredump_single_thread.stdout.exp coredump_single_thread.vgtest \
+	coredump_single_thread_sse.post.exp coredump_single_thread_sse.stderr.exp \
+	coredump_single_thread_sse.stdout.exp coredump_single_thread_sse.vgtest \
+	syscalls.stderr.exp syscalls.stdout.exp syscalls.vgtest
+
+check_PROGRAMS = \
+	coredump_single_thread \
+	coredump_single_thread_sse \
+	syscalls
+
+AM_CFLAGS    += @FLAG_M32@
+AM_CXXFLAGS  += @FLAG_M32@
+AM_CCASFLAGS += @FLAG_M32@
+
diff --git a/none/tests/x86-solaris/coredump_single_thread.c b/none/tests/x86-solaris/coredump_single_thread.c
new file mode 100644
index 0000000..7f2d3a9
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread.c
@@ -0,0 +1,52 @@
+/* Tests that Valgrind coredump support works correctly by producing
+   a core dump analyzable by mdb. */ 
+
+#include <stdio.h>
+#include <sys/types.h>
+
+__attribute__((noinline))
+static void inner(void)
+{
+   uint16_t cs, ds, ss, es, fs, gs;
+
+   /* Print segment registers as they cannot be set to arbitrary
+      values. */
+   __asm__ __volatile__(
+      "movw %%cs, %0\n"
+      "movw %%ds, %1\n"
+      "movw %%ss, %2\n"
+      "movw %%es, %3\n"
+      "movw %%fs, %4\n"
+      "movw %%gs, %5\n"
+      : "=m" (cs), "=m" (ds), "=m" (ss), "=m" (es), "=m" (fs), "=m" (gs));
+   printf("cs=%#x ds=%#x ss=%#x es=%#x fs=%#x gs=%#x\n",
+          cs, ds, ss, es, fs, gs);
+
+   /* Set other registers to apriori known values. */
+   __asm__ __volatile__(
+      "movl $0x101, %%eax\n"
+      "movl $0x102, %%ebx\n"
+      "movl $0x103, %%ecx\n"
+      "movl $0x104, %%edx\n"
+      "movl $0x105, %%esi\n"
+      "movl $0x106, %%edi\n"
+      // not %ebp as mdb is then not able to reconstruct stack trace
+      "movl $0x108, %%esp\n"
+      "movl $0x1234, (%%eax)\n"  // should cause SEGV here
+      "ud2"                      // should never get here
+      : // no output registers
+      : // no input registers
+      : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%esp");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+   inner();
+}
+
+int main(int argc, const char *argv[])
+{
+   outer();
+   return 0;
+}
diff --git a/none/tests/x86-solaris/coredump_single_thread.post.exp b/none/tests/x86-solaris/coredump_single_thread.post.exp
new file mode 100644
index 0000000..407f7ac
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread.post.exp
@@ -0,0 +1,27 @@
+---Status---
+debugging core file of coredump_single (32-bit) from ...
+initial argv: ./coredump_single_thread
+threading model: native threads
+status: process terminated by SIGSEGV (Segmentation Fault), addr=........
+
+---Registers---
+%cs = 0x........            %eax = 0x00000101 
+%ds = 0x........            %ebx = 0x00000102 
+%ss = 0x........            %ecx = 0x00000103 
+%es = 0x........            %edx = 0x00000104 
+%fs = 0x........            %esi = 0x00000105 
+%gs = 0x........            %edi = 0x00000106 
+
+ %eip = 0x........  coredump_single_thread`inner+0x........
+%kesp = 0x00000000
+
+
+   %esp = 0x00000108
+%trapno = 0x0
+   %err = 0x0
+
+---Stack trace---
+coredump_single_thread`inner
+coredump_single_thread`outer
+coredump_single_thread`main
+coredump_single_thread`_start
diff --git a/none/tests/x86-solaris/coredump_single_thread.stderr.exp b/none/tests/x86-solaris/coredump_single_thread.stderr.exp
new file mode 100644
index 0000000..9ef2a8d
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread.stderr.exp
@@ -0,0 +1,9 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: inner (coredump_single_thread.c:26)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
diff --git a/none/tests/x86-solaris/coredump_single_thread.stdout.exp b/none/tests/x86-solaris/coredump_single_thread.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread.stdout.exp
diff --git a/none/tests/x86-solaris/coredump_single_thread.vgtest b/none/tests/x86-solaris/coredump_single_thread.vgtest
new file mode 100644
index 0000000..77604a0
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread.vgtest
@@ -0,0 +1,5 @@
+prereq: rm -f vgcore.*
+prog: coredump_single_thread
+vgopts: -q
+post: ./coredump_single_thread_mdb
+cleanup: rm -f vgcore.*
diff --git a/none/tests/x86-solaris/coredump_single_thread_mdb b/none/tests/x86-solaris/coredump_single_thread_mdb
new file mode 100755
index 0000000..c500478
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_mdb
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Filters are not run for post-test check commands.
+# Filter everything here.
+
+echo "---Status---"
+echo "::status" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/from \S*$/from .../' | \
+perl -0 -p -e 's/^file: .+?^(initial argv:)/$1/ms' | \
+perl -p -e 's/addr=[0-9A-Fa-f]+/addr=......../g'
+
+echo "\n---Registers---"
+echo "::regs" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/(%[cdsefg]s)\s+=\s+0x[0-9A-Fa-f]+/$1 = 0x......../' | \
+perl -p -e 's/%eip\s+=\s+0x[0-9A-Fa-f]+(.*)\+0x[0-9A-Fa-f]+$/%eip = 0x........ $1+0x......../' | \
+sed '/%ebp/ d' | \
+sed '/^%eflags/ d' | \
+sed '/id=/ d' | \
+sed '/status=/ d'
+
+echo "\n---Stack trace---"
+echo "::stack ! perl -p -e 's/^(\S+)\+.*/\$1/g'" | /usr/bin/mdb vgcore.*
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse.c b/none/tests/x86-solaris/coredump_single_thread_sse.c
new file mode 100644
index 0000000..2d8c883
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse.c
@@ -0,0 +1,73 @@
+/* Tests that Valgrind coredump support for SSE registers works correctly
+   by producing a core dump analyzable by mdb.
+   Basic register set is tested in coredump_single_thread. */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+__attribute__((noinline))
+static void inner(void)
+{
+   /* Set XMM registers to apriori known values.
+      Unfortunately there is no instruction to load
+      an immediate value directly into xmm register. */
+   __asm__ __volatile__("\n"
+      "pushl $0x12345678\n"
+      "pushl $0x9abcdef0\n"
+      "pushl $0xfedbca98\n"
+      "pushl $0x76543210\n"
+      "movups (%%esp), %%xmm0\n"
+      "pushl $0x23456789\n"
+      "pushl $0x09876543\n"
+      "pushl $0x21fedcba\n"
+      "pushl $0x9467feca\n"
+      "movups (%%esp), %%xmm1\n"
+      "pushl $0xabcdabcd\n"
+      "pushl $0xcedecede\n"
+      "pushl $0xfabafaba\n"
+      "pushl $0x50656754\n"
+      "movups (%%esp), %%xmm2\n"
+      "pushl $0x03050608\n"
+      "pushl $0x1d1b4b15\n"
+      "pushl $0x25272120\n"
+      "pushl $0x373a3d35\n"
+      "movups (%%esp), %%xmm3\n"
+      "pushl $0x9abcdef0\n"
+      "pushl $0x76543210\n"
+      "pushl $0x12345678\n"
+      "pushl $0xfedbca98\n"
+      "movups (%%esp), %%xmm4\n"
+      "pushl $0x9467feca\n"
+      "pushl $0x23456789\n"
+      "pushl $0x21fedcba\n"
+      "pushl $0x09876543\n"
+      "movups (%%esp), %%xmm5\n"
+      "pushl $0x50656754\n"
+      "pushl $0xcedecede\n"
+      "pushl $0xabcdabcd\n"
+      "pushl $0xfabafaba\n"
+      "movups (%%esp), %%xmm6\n"
+      "pushl $0x373a3d35\n"
+      "pushl $0x1d1b4b15\n"
+      "pushl $0x03050608\n"
+      "pushl $0x25272120\n"
+      "movups (%%esp), %%xmm7\n"
+      "movl $0x1, %%eax\n"
+      "movl $0x1234, (%%eax)\n"  // should cause SEGV here
+      : // no output registers
+      : // no input registers
+      : "memory", "%xmm0", "%xmm1", "%xmm2", "%xmm3",
+                  "%xmm4", "%xmm5", "%xmm6", "%xmm7");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+   inner();
+}
+
+int main(int argc, const char *argv[])
+{
+   outer();
+   return 0;
+}
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse.post.exp b/none/tests/x86-solaris/coredump_single_thread_sse.post.exp
new file mode 100644
index 0000000..d42da8a
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse.post.exp
@@ -0,0 +1,15 @@
+---Status---
+debugging core file of coredump_single (32-bit) from ...
+initial argv: ./coredump_single_thread_sse
+threading model: native threads
+status: process terminated by SIGSEGV (Segmentation Fault), addr=........
+
+---SSE Registers---
+%xmm0  0x123456789abcdef0fedbca9876543210
+%xmm1  0x234567890987654321fedcba9467feca
+%xmm2  0xabcdabcdcedecedefabafaba50656754
+%xmm3  0x030506081d1b4b1525272120373a3d35
+%xmm4  0x9abcdef07654321012345678fedbca98
+%xmm5  0x9467feca2345678921fedcba09876543
+%xmm6  0x50656754cedecedeabcdabcdfabafaba
+%xmm7  0x373a3d351d1b4b150305060825272120
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse.stderr.exp b/none/tests/x86-solaris/coredump_single_thread_sse.stderr.exp
new file mode 100644
index 0000000..7d8706a
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse.stderr.exp
@@ -0,0 +1,11 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+   at 0x........: inner (coredump_single_thread_sse.c:14)
+   by 0x........: outer (coredump_single_thread_sse.c:66)
+   by 0x........: main (coredump_single_thread_sse.c:71)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse.stdout.exp b/none/tests/x86-solaris/coredump_single_thread_sse.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse.stdout.exp
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse.vgtest b/none/tests/x86-solaris/coredump_single_thread_sse.vgtest
new file mode 100644
index 0000000..efc880a
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse.vgtest
@@ -0,0 +1,5 @@
+prereq: rm -f vgcore.* && ../../../tests/x86_amd64_features x86-sse
+prog: coredump_single_thread_sse
+vgopts: -q
+post: ./coredump_single_thread_sse_mdb
+cleanup: rm -f vgcore.*
diff --git a/none/tests/x86-solaris/coredump_single_thread_sse_mdb b/none/tests/x86-solaris/coredump_single_thread_sse_mdb
new file mode 100755
index 0000000..3cc5413
--- /dev/null
+++ b/none/tests/x86-solaris/coredump_single_thread_sse_mdb
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Filters are not run for post-test check commands.
+# Filter everything here.
+
+echo "---Status---"
+echo "::status" | /usr/bin/mdb vgcore.* | \
+perl -p -e 's/from \S*$/from .../' | \
+perl -0 -p -e 's/^file: .+?^(initial argv:)/$1/ms' | \
+perl -p -e 's/addr=[0-9A-Fa-f]+/addr=......../g'
+
+echo "\n---SSE Registers---"
+echo "::fpregs" | /usr/bin/mdb vgcore.* | \
+perl -n -e '/^%xmm/ && print $_;'
+
diff --git a/none/tests/x86-solaris/filter_stderr b/none/tests/x86-solaris/filter_stderr
new file mode 100755
index 0000000..0ae9313
--- /dev/null
+++ b/none/tests/x86-solaris/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/none/tests/x86-solaris/syscalls.c b/none/tests/x86-solaris/syscalls.c
new file mode 100644
index 0000000..75040a0
--- /dev/null
+++ b/none/tests/x86-solaris/syscalls.c
@@ -0,0 +1,59 @@
+/* Test that all instructions that make syscalls are handled correctly.
+   Note that it isn't possible to run this program natively. */
+
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <sys/trap.h>
+
+#define SYSCALL(instr, scnum, out) \
+do { \
+__asm__ __volatile__( \
+   "movl %1,%%eax\n" \
+   "leal 0f,%%edx\n" /* Set return address for SYSENTER. */ \
+   instr "\n" \
+   "0:\n" \
+   "movl %%eax,%0\n" \
+   : "=m" (out) \
+   : "i" (scnum) \
+   : "eax", "edx", "cc", "memory"); \
+} while (0)
+
+static void check_pid(int pid, int pid2, const char *instr)
+{
+   if (pid == pid2)
+      return;
+
+   fprintf(stderr, "Pid values differ, instruction: %s\n", instr);
+}
+
+int main(void)
+{
+   int pid, pid2, dummy;
+
+   /* Normal Solaris/x86 syscall instructions. */
+   SYSCALL("int $0x91", SYS_getpid, pid);
+
+   /* AMD's syscall instruction. */
+   SYSCALL("syscall", SYS_getpid, pid2);
+   check_pid(pid, pid2, "syscall");
+
+   /* Intel's sysenter instruction. */
+   SYSCALL("sysenter", SYS_getpid, pid2);
+   check_pid(pid, pid2, "sysenter");
+
+   /* Linux syscall instructions that are handled as "int $0x91". */
+   SYSCALL("int $0x80", SYS_getpid, pid2);
+   check_pid(pid, pid2, "int $0x80");
+
+   SYSCALL("int $0x81", SYS_getpid, pid2);
+   check_pid(pid, pid2, "int $0x81");
+
+   SYSCALL("int $0x82", SYS_getpid, pid2);
+   check_pid(pid, pid2, "int $0x82");
+
+   /* Fasttraps. */
+   SYSCALL("int $0xd2", T_GETHRTIME, dummy);
+
+   return 0;
+}
+
diff --git a/none/tests/x86-solaris/syscalls.stderr.exp b/none/tests/x86-solaris/syscalls.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/x86-solaris/syscalls.stderr.exp
diff --git a/none/tests/x86-solaris/syscalls.stdout.exp b/none/tests/x86-solaris/syscalls.stdout.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/x86-solaris/syscalls.stdout.exp
diff --git a/none/tests/x86-solaris/syscalls.vgtest b/none/tests/x86-solaris/syscalls.vgtest
new file mode 100644
index 0000000..16769d0
--- /dev/null
+++ b/none/tests/x86-solaris/syscalls.vgtest
@@ -0,0 +1,2 @@
+prog: syscalls
+vgopts: -q
diff --git a/none/tests/x86/Makefile.am b/none/tests/x86/Makefile.am
index e2465f7..f9632ef 100644
--- a/none/tests/x86/Makefile.am
+++ b/none/tests/x86/Makefile.am
@@ -1,17 +1,21 @@
 
 include $(top_srcdir)/Makefile.tool-tests.am
 
-dist_noinst_SCRIPTS = filter_cpuid filter_stderr gen_insn_test.pl
+dist_noinst_SCRIPTS = filter_cpuid filter_inf_nan filter_stderr gen_insn_test.pl
 
 CLEANFILES = $(addsuffix .c,$(INSN_TESTS))
 
-INSN_TESTS = insn_basic insn_fpu insn_cmov insn_mmx insn_mmxext \
+INSN_TESTS = insn_basic insn_cmov insn_mmx insn_mmxext \
 		insn_sse insn_sse2
+if BUILD_SSSE3_TESTS
+   INSN_TESTS += insn_ssse3
+endif
+if !SOLARIS_SUN_STUDIO_AS
+# Sun Studio assembler fails to build some tests (illegal mnemonic).
+INSN_TESTS += insn_fpu
 if BUILD_SSE3_TESTS
    INSN_TESTS += insn_sse3
 endif
-if BUILD_SSSE3_TESTS
-   INSN_TESTS += insn_ssse3
 endif
 
 # Explicitly include insn_sse3 even if ! BUILD_SSE3_TESTS, 
@@ -22,7 +26,8 @@
 
 EXTRA_DIST = \
 	aad_aam.stdout.exp aad_aam.stderr.exp aad_aam.vgtest \
-	badseg.stderr.exp badseg.stdout.exp badseg.vgtest \
+	badseg.stderr.exp badseg.stdout.exp badseg.stdout.exp-solaris \
+	badseg.vgtest \
 	bt_everything.stderr.exp bt_everything.stdout.exp bt_everything.vgtest \
 	bt_literal.stderr.exp bt_literal.stdout.exp bt_literal.vgtest \
 	bug125959-x86.stderr.exp bug125959-x86.stdout.exp bug125959-x86.vgtest \
@@ -46,6 +51,7 @@
 	$(addsuffix .stderr.exp,$(INSN_TESTS)) \
 	$(addsuffix .stdout.exp,$(INSN_TESTS)) \
 	$(addsuffix .vgtest,$(INSN_TESTS)) \
+	insn_fpu.stdout.exp insn_fpu.stderr.exp insn_fpu.vgtest \
 	insn_sse3.stdout.exp insn_sse3.stderr.exp insn_sse3.vgtest \
 	insn_ssse3.stdout.exp insn_ssse3.stderr.exp insn_ssse3.vgtest \
 	jcxz.stdout.exp jcxz.stderr.exp jcxz.vgtest \
@@ -91,7 +97,6 @@
 	lahf \
 	looper \
 	movx \
-	pushpopseg \
 	sbbmisc \
 	shift_ndep \
 	smc1 \
@@ -106,11 +111,18 @@
  check_PROGRAMS += lzcnt32
 endif
 if !VGCONF_OS_IS_DARWIN
+if !SOLARIS_SUN_STUDIO_AS
+# Sun Studio assembler fails to assemble the bound instruction
  check_PROGRAMS += faultstatus
 endif
+endif
 if BUILD_MOVBE_TESTS
  check_PROGRAMS += movbe
 endif
+if !SOLARIS_SUN_STUDIO_AS
+# Sun Studio assembler fails to assemble pushw %fs, popw %fs
+ check_PROGRAMS += pushpopseg
+endif
 
 
 AM_CFLAGS    += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
diff --git a/none/tests/x86/badseg.stdout.exp-solaris b/none/tests/x86/badseg.stdout.exp-solaris
new file mode 100644
index 0000000..fd45cc7
--- /dev/null
+++ b/none/tests/x86/badseg.stdout.exp-solaris
@@ -0,0 +1 @@
+info: sig=11 code=1 addr=0x0
diff --git a/none/tests/x86/bt_everything.c b/none/tests/x86/bt_everything.c
index b367c02..ebe57ac 100644
--- a/none/tests/x86/bt_everything.c
+++ b/none/tests/x86/bt_everything.c
@@ -3,6 +3,17 @@
 #include <stdlib.h>
 #include <assert.h>
 
+unsigned myrandom(void)
+{
+   /* Simple multiply-with-carry random generator. */
+   static unsigned m_w = 11;
+   static unsigned m_z = 13;
+
+   m_z = 36969 * (m_z & 65535) + (m_z >> 16);
+   m_w = 18000 * (m_w & 65535) + (m_w >> 16);
+
+   return (m_z << 16) + m_w;
+}
 
 unsigned int btsl_mem ( unsigned char* base, int bitno )
 {
@@ -155,8 +166,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsl_mem(block, bitoff); break;
@@ -185,8 +196,8 @@
    reg = 0;
 
    for (n = 0; n < 1000; n++) {
-      bitoff = (random() % 100) - 50;
-      op = random() % 4;
+      bitoff = (myrandom() % 100) - 50;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsl_reg(reg, bitoff, &reg); break;
diff --git a/none/tests/x86/bt_everything.stdout.exp b/none/tests/x86/bt_everything.stdout.exp
index fd67221..c02cc36 100644
--- a/none/tests/x86/bt_everything.stdout.exp
+++ b/none/tests/x86/bt_everything.stdout.exp
@@ -1,2 +1,2 @@
-MEM-L: final res 0xd2bfea53, carrydep 0x5b80deee
-REG-L: final res 0x605d78ff, carrydep 0x7c0dc86a
+MEM-L: final res 0x2e9fc392, carrydep 0x23a9479e
+REG-L: final res 0x46a4bd35, carrydep 0xddfae2da
diff --git a/none/tests/x86/cpuid_s.S b/none/tests/x86/cpuid_s.S
index 6d1dfbc..70040ce 100644
--- a/none/tests/x86/cpuid_s.S
+++ b/none/tests/x86/cpuid_s.S
@@ -1,7 +1,7 @@
 #include "tests/asm.h"
 	
 	.file	"oneparam.c"
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_solaris)
 	.version	"01.01"
 #endif
 gcc2_compiled.:
diff --git a/none/tests/x86/filter_inf_nan b/none/tests/x86/filter_inf_nan
new file mode 100755
index 0000000..b4ddfc9
--- /dev/null
+++ b/none/tests/x86/filter_inf_nan
@@ -0,0 +1,10 @@
+#! /bin/sh
+
+# Solaris libc prints 'Infinity' instead of 'inf' and 'NaN' instead of 'nan'.
+# Filter these differences here.
+sed "s/-Infinity/     -inf/g" |
+sed "s/Infinity/     inf/g"   |
+sed "s/NaN/nan/g"
+
+exit 0
+
diff --git a/none/tests/x86/fxtract.vgtest b/none/tests/x86/fxtract.vgtest
index 341b15a..4b5efc5 100644
--- a/none/tests/x86/fxtract.vgtest
+++ b/none/tests/x86/fxtract.vgtest
@@ -1 +1,2 @@
 prog: fxtract
+stdout_filter: filter_inf_nan
diff --git a/none/tests/x86/x86locked.c b/none/tests/x86/x86locked.c
index 38d1108..8b014cb 100644
--- a/none/tests/x86/x86locked.c
+++ b/none/tests/x86/x86locked.c
@@ -14,6 +14,18 @@
 typedef  unsigned long           UWord;
 typedef  char                    HChar;
 
+unsigned myrandom(void)
+{
+   /* Simple multiply-with-carry random generator. */
+   static unsigned m_w = 11;
+   static unsigned m_z = 13;
+
+   m_z = 36969 * (m_z & 65535) + (m_z >> 16);
+   m_w = 18000 * (m_w & 65535) + (m_w >> 16);
+
+   return (m_z << 16) + m_w;
+}
+
 /////////////////////////////////////////////////////////////////
 // BEGIN crc32 stuff                                           //
 /////////////////////////////////////////////////////////////////
@@ -571,8 +583,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsl_mem(block, bitoff); break;
@@ -607,8 +619,8 @@
    /* Valid bit offsets are -800 .. 799 inclusive. */
 
    for (n = 0; n < 10000; n++) {
-      bitoff = (random() % 1600) - 800;
-      op = random() % 4;
+      bitoff = (myrandom() % 1600) - 800;
+      op = myrandom() % 4;
       c = 2;
       switch (op) {
          case 0: c = btsw_mem(block, bitoff); break;
@@ -848,7 +860,7 @@
   // confirm with
   // objdump -d ./x86locked | grep lock | grep -v do_lock | grep -v elf32 | wc
 
-  { UInt crcExpd = 0x8235DC9C;
+  { UInt crcExpd = 0xB2D75045;
     theCRC = crcFinalise( theCRC );
     if (theCRC == crcExpd) {
        printf("x86locked: PASS: CRCs actual 0x%08X expected 0x%08X\n",
diff --git a/none/tests/x86/x86locked.stdout.exp b/none/tests/x86/x86locked.stdout.exp
index e5145cc..826a1b5 100644
--- a/none/tests/x86/x86locked.stdout.exp
+++ b/none/tests/x86/x86locked.stdout.exp
@@ -1 +1 @@
-x86locked: PASS: CRCs actual 0x8235DC9C expected 0x8235DC9C
+x86locked: PASS: CRCs actual 0xB2D75045 expected 0xB2D75045
diff --git a/shared/vg_replace_strmem.c b/shared/vg_replace_strmem.c
index 41e384d..e092618 100644
--- a/shared/vg_replace_strmem.c
+++ b/shared/vg_replace_strmem.c
@@ -103,6 +103,15 @@
    20420 STPNCPY
 */
 
+#if defined(VGO_solaris)
+/*
+   Detour functions in the libc and the runtime linker. If a function isn't
+   much optimized (and no overlap checking is necessary) then redir the
+   function only in the libc. This way we can keep stacktraces in the tests
+   consistent.
+*/
+#endif
+
 
 /* Figure out if [dst .. dst+dstlen-1] overlaps with
                  [src .. src+srclen-1].
@@ -208,6 +217,11 @@
   STRRCHR(libsystemZucZddylib, strrchr)
 # endif
 
+#elif defined(VGO_solaris)
+ STRRCHR(VG_Z_LIBC_SONAME,   strrchr)
+ STRRCHR(VG_Z_LIBC_SONAME,   rindex)
+ STRRCHR(VG_Z_LD_SO_1,       strrchr)
+
 #endif
 
 
@@ -250,6 +264,12 @@
   STRCHR(libsystemZuplatformZddylib, _platform_strchr$VARIANT$Generic)
   STRCHR(libsystemZuplatformZddylib, _platform_strchr$VARIANT$Haswell)
 # endif
+
+#elif defined(VGO_solaris)
+ STRCHR(VG_Z_LIBC_SONAME,          strchr)
+ STRCHR(VG_Z_LIBC_SONAME,          index)
+ STRCHR(VG_Z_LD_SO_1,              strchr)
+
 #endif
 
 
@@ -285,6 +305,10 @@
 #elif defined(VGO_darwin)
  //STRCAT(VG_Z_LIBC_SONAME, strcat)
 
+#elif defined(VGO_solaris)
+ STRCAT(VG_Z_LIBC_SONAME, strcat)
+ STRCAT(VG_Z_LD_SO_1,     strcat)
+
 #endif
 
 
@@ -322,6 +346,9 @@
  //STRNCAT(VG_Z_LIBC_SONAME, strncat)
  //STRNCAT(VG_Z_DYLD,        strncat)
 
+#elif defined(VGO_solaris)
+ STRNCAT(VG_Z_LIBC_SONAME, strncat)
+
 #endif
 
 
@@ -370,6 +397,9 @@
  //STRLCAT(VG_Z_DYLD,        strlcat)
  STRLCAT(VG_Z_LIBC_SONAME, strlcat)
 
+#elif defined(VGO_solaris)
+ STRLCAT(VG_Z_LIBC_SONAME, strlcat)
+
 #endif
 
 
@@ -395,6 +425,9 @@
   STRNLEN(libsystemZucZddylib, strnlen)
 # endif
 
+#elif defined(VGO_solaris)
+ STRNLEN(VG_Z_LIBC_SONAME, strnlen)
+
 #endif
 
 
@@ -435,6 +468,11 @@
 # if DARWIN_VERS >= DARWIN_10_9
   STRLEN(libsystemZucZddylib, strlen)
 # endif
+
+#elif defined(VGO_solaris)
+ STRLEN(VG_Z_LIBC_SONAME,          strlen)
+ STRLEN(VG_Z_LD_SO_1,              strlen)
+
 #endif
 
 
@@ -473,6 +511,10 @@
   STRCPY(libsystemZucZddylib, strcpy)
 # endif
 
+#elif defined(VGO_solaris)
+ STRCPY(VG_Z_LIBC_SONAME, strcpy)
+ STRCPY(VG_Z_LD_SO_1,     strcpy)
+
 #endif
 
 
@@ -510,6 +552,10 @@
   STRNCPY(libsystemZucZddylib, strncpy)
 # endif
 
+#elif defined(VGO_solaris)
+ STRNCPY(VG_Z_LIBC_SONAME, strncpy)
+ STRNCPY(VG_Z_LD_SO_1,     strncpy)
+
 #endif
 
 
@@ -527,6 +573,8 @@
       HChar* dst_orig = dst; \
       SizeT m = 0; \
       \
+      STRLCPY_CHECK_FOR_DSTSIZE_ZERO \
+      \
       while (m < n-1 && *src) { m++; *dst++ = *src++; } \
       /* m non-nul bytes have now been copied, and m <= n-1. */ \
       /* Check for overlap after copying; all n bytes of dst are relevant, */ \
@@ -544,14 +592,26 @@
 
 #if defined(VGPV_arm_linux_android) || defined(VGPV_x86_linux_android) \
     || defined(VGPV_mips32_linux_android)
+ #define STRLCPY_CHECK_FOR_DSTSIZE_ZERO
  STRLCPY(VG_Z_LIBC_SONAME, strlcpy);
 #endif
 
 #elif defined(VGO_darwin)
+ #define STRLCPY_CHECK_FOR_DSTSIZE_ZERO
  //STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
  //STRLCPY(VG_Z_DYLD,        strlcpy)
  STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
 
+#elif defined(VGO_solaris)
+ /* special case for n == 0 which is undocumented but heavily used */
+ #define STRLCPY_CHECK_FOR_DSTSIZE_ZERO \
+    if (n == 0) { \
+       while (*src) src++; \
+       return src - src_orig; \
+    }
+
+ STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
+
 #endif
 
 
@@ -589,6 +649,9 @@
   STRNCMP(libsystemZuplatformZddylib, _platform_strncmp)
 # endif
 
+#elif defined(VGO_solaris)
+ STRNCMP(VG_Z_LIBC_SONAME, strncmp)
+
 #endif
 
 
@@ -627,6 +690,9 @@
 #elif defined(VGO_darwin)
  //STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
 
+#elif defined(VGO_solaris)
+ STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp)
+
 #endif
 
 
@@ -668,6 +734,9 @@
  //STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
  //STRNCASECMP(VG_Z_DYLD,        strncasecmp)
 
+#elif defined(VGO_solaris)
+ STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp)
+
 #endif
 
 
@@ -702,6 +771,8 @@
 #elif defined(VGO_darwin)
  //STRCASECMP_L(VG_Z_LIBC_SONAME, strcasecmp_l)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -739,6 +810,8 @@
  //STRNCASECMP_L(VG_Z_LIBC_SONAME, strncasecmp_l)
  //STRNCASECMP_L(VG_Z_DYLD,        strncasecmp_l)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -782,6 +855,10 @@
   STRCMP(libsystemZuplatformZddylib, _platform_strcmp)
 # endif
 
+#elif defined(VGO_solaris)
+ STRCMP(VG_Z_LIBC_SONAME,          strcmp)
+ STRCMP(VG_Z_LD_SO_1,              strcmp)
+
 #endif
 
 
@@ -816,6 +893,9 @@
   MEMCHR(libsystemZuplatformZddylib, _platform_memchr$VARIANT$Generic)
 # endif
 
+#elif defined(VGO_solaris)
+ MEMCHR(VG_Z_LIBC_SONAME, memchr)
+
 #endif
 
 
@@ -842,6 +922,8 @@
  //MEMRCHR(VG_Z_LIBC_SONAME, memrchr)
  //MEMRCHR(VG_Z_DYLD,        memrchr)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -953,6 +1035,10 @@
  MEMCPY(VG_Z_LIBC_SONAME,  memcpyZDVARIANTZDsse3x) /* memcpy$VARIANT$sse3x */
  MEMCPY(VG_Z_LIBC_SONAME,  memcpyZDVARIANTZDsse42) /* memcpy$VARIANT$sse42 */
 
+#elif defined(VGO_solaris)
+ MEMCPY(VG_Z_LIBC_SONAME,  memcpy)
+ MEMCPY(VG_Z_LD_SO_1,      memcpy)
+
 #endif
 
 
@@ -1011,6 +1097,11 @@
   MEMCMP(libsystemZuplatformZddylib, _platform_memcmp)
 # endif
 
+#elif defined(VGO_solaris)
+ MEMCMP(VG_Z_LIBC_SONAME, memcmp)
+ MEMCMP(VG_Z_LIBC_SONAME, bcmp)
+ MEMCMP(VG_Z_LD_SO_1,     memcmp)
+
 #endif
 
 
@@ -1053,6 +1144,9 @@
  //STPCPY(VG_Z_LIBC_SONAME,          stpcpy)
  //STPCPY(VG_Z_DYLD,                 stpcpy)
 
+#elif defined(VGO_solaris)
+ STPCPY(VG_Z_LIBC_SONAME,          stpcpy)
+
 #endif
 
 
@@ -1131,6 +1225,9 @@
  //MEMSET(VG_Z_DYLD,        memset)
  MEMSET(VG_Z_LIBC_SONAME, memset)
 
+#elif defined(VGO_solaris)
+ MEMSET(VG_Z_LIBC_SONAME, memset)
+
 #endif
 
 
@@ -1156,6 +1253,11 @@
   /* _platform_memmove$VARIANT$Ivybridge */
   MEMMOVE(libsystemZuplatformZddylib, ZuplatformZumemmoveZDVARIANTZDIvybridge)
 # endif
+
+#elif defined(VGO_solaris)
+ MEMMOVE(VG_Z_LIBC_SONAME, memmove)
+ MEMMOVE(VG_Z_LD_SO_1,     memmove)
+
 #endif
 
 
@@ -1188,6 +1290,9 @@
  //BCOPY(VG_Z_LIBC_SONAME, bcopy)
  //BCOPY(VG_Z_DYLD,        bcopy)
 
+#elif defined(VGO_darwin)
+ BCOPY(VG_Z_LIBC_SONAME, bcopy)
+
 #endif
 
 
@@ -1230,6 +1335,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1256,6 +1363,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1282,6 +1391,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1316,6 +1427,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1349,6 +1462,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1395,6 +1510,8 @@
 #elif defined(VGO_darwin)
  //GLIBC25_MEMPCPY(VG_Z_LIBC_SONAME, mempcpy)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1445,6 +1562,8 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+
 #endif
 
 
@@ -1494,6 +1613,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+ STRSTR(VG_Z_LIBC_SONAME,          strstr)
+
 #endif
 
 
@@ -1536,6 +1658,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+ STRPBRK(VG_Z_LIBC_SONAME,          strpbrk)
+
 #endif
 
 
@@ -1579,6 +1704,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+ STRCSPN(VG_Z_LIBC_SONAME,          strcspn)
+
 #endif
 
 
@@ -1623,6 +1751,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+ STRSPN(VG_Z_LIBC_SONAME,          strspn)
+
 #endif
 
 
@@ -1676,6 +1807,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+  STRCASESTR(VG_Z_LIBC_SONAME,      strcasestr)
+
 #endif
 
 
@@ -1702,6 +1836,9 @@
 
 #elif defined(VGO_darwin)
 
+#elif defined(VGO_solaris)
+ WCSLEN(VG_Z_LIBC_SONAME,          wcslen)
+
 #endif
 
 /*---------------------- wcscmp ----------------------*/
diff --git a/solaris/Makefile.am b/solaris/Makefile.am
new file mode 100644
index 0000000..6e66379
--- /dev/null
+++ b/solaris/Makefile.am
@@ -0,0 +1,9 @@
+# We need to list all files here to make sure they are included in
+# the make dist target.
+
+dist_noinst_SCRIPTS = build_solaris_package
+		
+EXTRA_DIST = \
+	gdb-sol-thread.patch \
+	valgrind.p5m \
+	vgpreload-solaris.mapfile
diff --git a/solaris/build_solaris_package b/solaris/build_solaris_package
new file mode 100755
index 0000000..52508d7
--- /dev/null
+++ b/solaris/build_solaris_package
@@ -0,0 +1,192 @@
+#!/usr/bin/ksh
+#
+# Builds a Solaris IPS package called "valgrind" from the project sources.
+# Sources are cloned and updated to the tag found in solaris/valgrind.p5m
+# IPS manifest.
+#
+# Requires the following packages to be installed on Solaris 11:
+# - data/xml-common		(install first before any docbook ones!)
+# - data/docbook/docbook-style-xsl
+# - data/docbook/docbook-dtds
+# - developer/build/autoconf
+# - developer/build/automake-111
+# - developer/debug/gdb
+# - developer/gnu-binutils
+# - developer/versioning/mercurial
+# - system/header
+# - and the latest developer/gcc package.
+#
+# Requires a pre-established IPS repository.
+# For example to create a file-based repository, do:
+# - pkgrepo create $repo_uri
+# - pkgrepo set -s $repo_uri publisher/prefix=valgrind
+#
+
+TMPDIR=/var/tmp/valgrind-solaris-build
+SRCDIR=$TMPDIR/sources
+INSTALLDIR=$TMPDIR/install
+PROJECT_URL=https://bitbucket.org/iraisr/valgrind-solaris
+IPS_MANIFEST=solaris/valgrind.p5m
+
+usage() {
+    echo "Usage:"
+    echo "build_solaris_package -s repo_uri [-r lint_repo_uri]"
+    echo "\t-s repo_uri publishes to the repository located at the given URI"
+    echo "\t            or file system path"
+    echo "\t-r lint_repo_uri location of lint reference repository"
+}
+
+fail() {
+    msg=$1
+
+    echo "\n$msg"
+    echo "Additional information could be found in directory $TMPDIR"
+    exit 1
+}
+
+remove_dirs() {
+    rm -rf $TMPDIR
+}
+
+create_dirs() {
+    mkdir -p $TMPDIR
+    (( $? != 0 )) && fail "Failed to create directory $TMPDIR"
+
+    mkdir -p $INSTALLDIR
+    (( $? != 0 )) && fail "Failed to create directory $INSTALLDIR"
+}
+
+clone_sources() {
+    printf "Cloning valgrind-solaris sources... "
+    hg --quiet clone --insecure $PROJECT_URL $SRCDIR 2> $TMPDIR/hg-clone.log.stderr
+    (( $? != 0 )) && fail "Failed to clone repo from $PROJECT_URL"
+    printf "done.\n"
+}
+
+update_sources_to_revision() {
+    cd $SRCDIR
+    tag=$( grep "pkg.fmri" $IPS_MANIFEST | tr -s ' ' | \
+           sed -e 's/^.*developer\/debug\/valgrind@.*,//' )
+    [[ -z $tag ]] && fail "Failed to find revision tag in $IPS_MANIFEST"
+
+    printf "Updating cloned sources to revision tag $tag... "
+    hg --quiet update -r $tag
+    (( $? != 0 )) && fail "Failed to update cloned sources to tag $tag"
+    printf "done.\n"
+}
+
+run_autogen() {
+    printf "Creating autotools support files... "
+    ./autogen.sh > $TMPDIR/autogen.log.stdout 2> $TMPDIR/autogen.log.stderr
+    (( $? != 0 )) && fail "Failed to generate autotools support files"
+    printf "done.\n"
+}
+
+run_configure() {
+    printf "Running configure... "
+    ./configure CC='gcc -m64' CXX='g++ -m64' --prefix=/usr > $TMPDIR/configure.log
+    (( $? != 0 )) && fail "Failed to run configure"
+    printf "done.\n"
+}
+
+run_make_docs() {
+   printf "Making docs... "
+   make --directory=docs html-docs > $TMPDIR/make-docs.log.stdout 2> $TMPDIR/make-docs.log.stderr
+   (( $? != 0 )) && fail "Failed to make html-docs"
+   printf "done.\n"
+}
+
+run_make_man_pages() {
+   printf "Making man pages... "
+   make --directory=docs man-pages > $TMPDIR/make-man-pages.log.stdout 2> $TMPDIR/make-man-pages.log.stderr
+   (( $? != 0 )) && fail "Failed to make man-pages"
+   printf "done.\n"
+}
+
+run_make() {
+    printf "Running make... "
+    make --quiet > $TMPDIR/make.log
+    (( $? != 0 )) && fail "Failed to run make"
+    printf "done.\n"
+}
+
+run_make_install() {
+    printf "Running 'make install'... "
+    make --quiet install DESTDIR=$INSTALLDIR > $TMPDIR/make-install.log
+    (( $? != 0 )) && fail "Failed to run 'make install'"
+
+    cp AUTHORS COPYING* NEWS NEWS.old README* $INSTALLDIR/usr/share/doc/valgrind
+    (( $? != 0 )) && fail "Failed to copy additional files to $INSTALLDIR"
+
+    printf "done.\n"
+}
+
+run_pkglint() {
+    printf "Running pkglint... "
+    pkglint -c $TMPDIR/lint-cache -r $lint_repo_uri $SRCDIR/$IPS_MANIFEST > $TMPDIR/pkglint.log
+    (( $? != 0 )) && fail "pkglint failed"
+    printf "done.\n"
+}
+
+publish_package() {
+    printf "Publishing package... "
+    pkgsend publish -s $repo_uri -d $INSTALLDIR $SRCDIR/solaris/valgrind.p5m > $TMPDIR/pkgsend.log
+    (( $? != 0 )) && fail "Failed to publish the package"
+    printf "done.\n"
+}
+
+while getopts "r:s:" args; do
+    case $args in
+    s)
+        repo_uri=$OPTARG
+        ;;
+    r)
+        lint_repo_uri=$OPTARG
+        ;;
+    *)
+        usage
+        exit 1
+        ;;
+    esac
+done
+
+if [[ -z $repo_uri ]]; then
+    echo "No repo_uri specified.\n"
+    usage
+    exit 1
+fi
+
+# Determine the lint repo_uri to use from the current 'solaris' one
+# if not specified explicitly.
+if [[ -z $lint_repo_uri ]]; then
+    publisher=$( pkg publisher | grep solaris | tr -s ' ' )
+    if [[ $publisher == *sticky* ]]; then
+        lint_repo_uri=$( echo "$publisher" | cut -d ' ' -f 6 )
+    else
+        lint_repo_uri=$( echo "$publisher" | cut -d ' ' -f 5 )
+    fi
+    [[ -z $lint_repo_uri ]] && fail "Failed to determine solaris IPS publisher"
+    echo "lint_repo_uri determined as $lint_repo_uri"
+fi
+
+
+remove_dirs
+create_dirs
+cd $TMPDIR
+
+clone_sources
+update_sources_to_revision 
+cd $SRCDIR
+run_autogen
+run_configure
+run_make_docs
+run_make_man_pages
+run_make
+run_make_install
+
+cd $TMPDIR
+run_pkglint
+publish_package
+
+remove_dirs
+return 0
diff --git a/solaris/gdb-sol-thread.patch b/solaris/gdb-sol-thread.patch
new file mode 100644
index 0000000..d06415c
--- /dev/null
+++ b/solaris/gdb-sol-thread.patch
@@ -0,0 +1,13 @@
+--- gdb-7.6.2/gdb/sol-thread.c.orig	2013-12-26 22:02:08.930437615 +0000
++++ gdb-7.6.2/gdb/sol-thread.c	2013-12-26 22:05:06.506977611 +0000
+@@ -588,6 +588,10 @@
+   td_err_e err;
+   ptid_t ptid;
+ 
++  /* Don't attempt to use thread_db for remote targets.  */
++  if (!(target_can_run (&current_target) || core_bfd))
++    return;
++
+   /* Do nothing if we couldn't load libthread_db.so.1.  */
+   if (p_td_ta_new == NULL)
+     return;
diff --git a/solaris/valgrind.p5m b/solaris/valgrind.p5m
new file mode 100644
index 0000000..599806c
--- /dev/null
+++ b/solaris/valgrind.p5m
@@ -0,0 +1,151 @@
+set name=pkg.fmri value=developer/debug/valgrind@3.11.0,1508
+set name=pkg.description value="valgrind: instrumentation framework and tools to detect memory and threading problems"
+set name=pkg.summary value="Valgrind is an award-winning instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tools. Currently x86 (32-bit) and amd64 (64-bit) platforms are supported."
+set name=variant.arch value=i386
+set name=info.classification value="org.opensolaris.category.2008:Development/System"
+set name=info.upstream-url value=https://bitbucket.org/iraisr/valgrind-solaris
+set name=info.source-url value=https://bitbucket.org/iraisr/valgrind-solaris/get/r1508.tar.bz2
+
+# Contents:
+dir  path=usr/bin                       owner=root group=bin mode=0755
+file path=usr/bin/callgrind_annotate    owner=root group=bin mode=0755
+file path=usr/bin/callgrind_control     owner=root group=bin mode=0755
+file path=usr/bin/cg_annotate           owner=root group=bin mode=0755
+file path=usr/bin/cg_diff               owner=root group=bin mode=0755
+file path=usr/bin/cg_merge              owner=root group=bin mode=0755
+file path=usr/bin/ms_print              owner=root group=bin mode=0755
+file path=usr/bin/valgrind              owner=root group=bin mode=0755
+file path=usr/bin/valgrind-di-server    owner=root group=bin mode=0755
+file path=usr/bin/valgrind-listener     owner=root group=bin mode=0755
+file path=usr/bin/vgdb                  owner=root group=bin mode=0755
+
+dir  path=usr/include                                      owner=root group=bin mode=0755
+dir  path=usr/include/valgrind                             owner=root group=bin mode=0755
+file path=usr/include/valgrind/callgrind.h                 owner=root group=bin mode=0644
+file path=usr/include/valgrind/drd.h                       owner=root group=bin mode=0644
+file path=usr/include/valgrind/memcheck.h                  owner=root group=bin mode=0644
+file path=usr/include/valgrind/valgrind.h                  owner=root group=bin mode=0644
+
+dir  path=usr/lib/valgrind                                               owner=root group=bin mode=0755
+file path=usr/lib/valgrind/32bit-core-valgrind-s1.xml                    owner=root group=bin mode=0644
+file path=usr/lib/valgrind/32bit-core-valgrind-s2.xml                    owner=root group=bin mode=0644
+file path=usr/lib/valgrind/32bit-core.xml                                owner=root group=bin mode=0644
+file path=usr/lib/valgrind/32bit-sse-valgrind-s1.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/32bit-sse-valgrind-s2.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/32bit-sse.xml                                 owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-avx-valgrind-s1.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-avx-valgrind-s2.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-avx.xml                                 owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-core-valgrind-s1.xml                    owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-core-valgrind-s2.xml                    owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-core.xml                                owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-sse-valgrind-s1.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-sse-valgrind-s2.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/64bit-sse.xml                                 owner=root group=bin mode=0644
+file path=usr/lib/valgrind/amd64-avx-coresse-valgrind.xml                owner=root group=bin mode=0644
+file path=usr/lib/valgrind/amd64-avx-coresse.xml                         owner=root group=bin mode=0644
+file path=usr/lib/valgrind/amd64-coresse-valgrind.xml                    owner=root group=bin mode=0644
+file path=usr/lib/valgrind/cachegrind-amd64-solaris                      owner=root group=bin mode=0755
+file path=usr/lib/valgrind/cachegrind-x86-solaris                        owner=root group=bin mode=0755
+file path=usr/lib/valgrind/callgrind-amd64-solaris                       owner=root group=bin mode=0755
+file path=usr/lib/valgrind/callgrind-x86-solaris                         owner=root group=bin mode=0755
+file path=usr/lib/valgrind/default.supp                                  owner=root group=bin mode=0644
+file path=usr/lib/valgrind/drd-amd64-solaris                             owner=root group=bin mode=0755
+file path=usr/lib/valgrind/drd-x86-solaris                               owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-bbv-amd64-solaris                         owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-bbv-x86-solaris                           owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-dhat-amd64-solaris                        owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-dhat-x86-solaris                          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-sgcheck-amd64-solaris                     owner=root group=bin mode=0755
+file path=usr/lib/valgrind/exp-sgcheck-x86-solaris                       owner=root group=bin mode=0755
+file path=usr/lib/valgrind/getoff-amd64-solaris                          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/getoff-x86-solaris                            owner=root group=bin mode=0755
+file path=usr/lib/valgrind/i386-coresse-valgrind.xml                     owner=root group=bin mode=0644
+file path=usr/lib/valgrind/lackey-amd64-solaris                          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/lackey-x86-solaris                            owner=root group=bin mode=0755
+file path=usr/lib/valgrind/massif-amd64-solaris                          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/massif-x86-solaris                            owner=root group=bin mode=0755
+file path=usr/lib/valgrind/memcheck-amd64-solaris                        owner=root group=bin mode=0755
+file path=usr/lib/valgrind/memcheck-x86-solaris                          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/none-amd64-solaris                            owner=root group=bin mode=0755
+file path=usr/lib/valgrind/none-x86-solaris                              owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_core-amd64-solaris.so               owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_core-x86-solaris.so                 owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_drd-amd64-solaris.so                owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_drd-x86-solaris.so                  owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_exp-dhat-amd64-solaris.so           owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_exp-dhat-x86-solaris.so             owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_exp-sgcheck-amd64-solaris.so        owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_exp-sgcheck-x86-solaris.so          owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_massif-amd64-solaris.so             owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_massif-x86-solaris.so               owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_memcheck-amd64-solaris.so           owner=root group=bin mode=0755
+file path=usr/lib/valgrind/vgpreload_memcheck-x86-solaris.so             owner=root group=bin mode=0755
+
+# Documentation from html-docs
+dir  path=usr/share/doc/valgrind					owner=root group=bin mode=0755
+dir  path=usr/share/doc/valgrind/html					owner=root group=bin mode=0755
+dir  path=usr/share/doc/valgrind/html/images				owner=root group=bin mode=0755
+file path=usr/share/doc/valgrind/html/bbv-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/cg-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/cl-format.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/cl-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/design-impl.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dh-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.authors.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.html				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.news.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.news.old.html		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.readme-developers.html	owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.readme-missing.html		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.readme-solaris.html		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/dist.readme.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/drd-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/faq.html				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/FAQ.html  			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/hg-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/index.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/license.gfdl.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/license.gpl.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/licenses.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/lk-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/manual-core-adv.html		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/manual-core.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/manual-intro.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/manual-writing-tools.html		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/mc-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/ms-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/nl-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/quick-start.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/QuickStart.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/sg-manual.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/tech-docs.html			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/vg_basic.css			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/images/home.png			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/images/next.png			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/images/prev.png			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/html/images/up.png			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/AUTHORS				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/COPYING				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/COPYING.DOCS				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/NEWS					owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/NEWS.old				owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/README					owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/README_DEVELOPERS			owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/README_DEVELOPERS_processes		owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/README_MISSING_SYSCALL_OR_IOCTL	owner=root group=bin mode=0644
+file path=usr/share/doc/valgrind/README.solaris				owner=root group=bin mode=0644
+
+# Man pages
+dir  path=usr/share/man					owner=root group=bin mode=0755
+dir  path=usr/share/man/man1				owner=root group=bin mode=0755
+file path=usr/share/man/man1/callgrind_annotate.1	owner=root group=bin mode=0644
+file path=usr/share/man/man1/callgrind_control.1	owner=root group=bin mode=0644
+file path=usr/share/man/man1/cg_annotate.1		owner=root group=bin mode=0644
+file path=usr/share/man/man1/cg_diff.1			owner=root group=bin mode=0644
+file path=usr/share/man/man1/cg_merge.1			owner=root group=bin mode=0644
+file path=usr/share/man/man1/ms_print.1			owner=root group=bin mode=0644
+file path=usr/share/man/man1/valgrind-listener.1	owner=root group=bin mode=0644
+file path=usr/share/man/man1/valgrind.1			owner=root group=bin mode=0644
+file path=usr/share/man/man1/vgdb.1			owner=root group=bin mode=0644
diff --git a/solaris/vgpreload-solaris.mapfile b/solaris/vgpreload-solaris.mapfile
new file mode 100644
index 0000000..da2abc3
--- /dev/null
+++ b/solaris/vgpreload-solaris.mapfile
@@ -0,0 +1,19 @@
+# Mapfile used for linking Valgrind preload libraries
+# (vgpreload_core-*.so and vgpreload_<tool>-*.so).
+#
+# Linking Valgrind with '-std=gnu99' causes the link editor
+# to include also symbols which alter Solaris libc behaviour.
+# This is undesirable: it would mean that non XPG-aware program
+# (conforming implicitly to XPG3) would behave differently when
+# run under Valgrind, due to preload libraries containing symbols
+# relevant to XPG6 (X/Open Portability Guide, Issue 6).
+#
+
+$mapfile_version 2
+
+SYMBOL_SCOPE {
+	ELIMINATE:
+		_lib_version;
+		__xpg4;
+		__xpg6;
+};
diff --git a/solaris11.supp b/solaris11.supp
new file mode 100644
index 0000000..6010936
--- /dev/null
+++ b/solaris11.supp
@@ -0,0 +1,43 @@
+# This is a real problem in the Solaris libc. It is caused by a read past the
+# FILE structure. It's an intentional hack to differentiate between two file
+# structures, FILE and xFILE.
+{
+   Solaris:snprintf
+   Memcheck:Cond
+   fun:getxfdat
+   ...
+   fun:_ndoprnt
+   fun:snprintf
+}
+
+# The same problem as above.
+{
+   Solaris:vsnprintf
+   Memcheck:Cond
+   fun:getxfdat
+   ...
+   fun:_ndoprnt
+   fun:vsnprintf
+}
+
+# Solaris libc doesn't deallocate I/O buffers on program exit.
+{
+   Solaris:file_buffer_malloc
+   Memcheck:Leak
+   fun:malloc
+   fun:_findbuf
+   obj:/lib/libc.so.1
+   obj:/lib/libc.so.1
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc reinitializes mutex udp->ld_lock in the child's post-fork
+# handler.
+{  
+   Solaris:postfork_child_mutex_reinit
+   drd:MutexErr
+   fun:mutex_init
+   fun:postfork1_child
+   fun:forkx
+}
+
diff --git a/solaris12.supp b/solaris12.supp
new file mode 100644
index 0000000..2c68508
--- /dev/null
+++ b/solaris12.supp
@@ -0,0 +1,168 @@
+# This is a real problem in the Solaris libc. It is caused by a read past the
+# FILE structure. It's an intentional hack to differentiate between two file
+# structures, FILE and xFILE.
+{
+   Solaris:sprintf
+   Memcheck:Cond
+   fun:getxfdat
+   fun:_set_memstream
+   fun:sprintf
+}
+
+# The same problem as above.
+{
+   Solaris:snprintf
+   Memcheck:Cond
+   fun:getxfdat
+   fun:_set_memstream
+   fun:snprintf
+}
+
+# The same problem as above.
+{
+   Solaris:snprintf
+   Memcheck:Cond
+   fun:getxfdat
+   fun:_realbufend
+   fun:_ndoprnt
+   fun:snprintf
+}
+
+# The same problem as above.
+{
+   Solaris:vsnprintf
+   Memcheck:Cond
+   fun:getxfdat
+   fun:_set_memstream
+   fun:vsnprintf
+}
+
+# The same problem as above.
+{
+   Solaris:vsnprintf
+   Memcheck:Cond
+   fun:getxfdat
+   fun:_realbufend
+   fun:_ndoprnt
+   fun:vsnprintf
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc doesn't deallocate I/O buffers on program exit.
+{
+   Solaris:file_buffer_malloc
+   Memcheck:Leak
+   fun:malloc
+   fun:_findbuf
+   obj:/lib/libc.so.1
+   obj:/lib/libc.so.1
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc doesn't deallocate netconfig list pointed to by netpp. 
+# This includes other allocated structures and strings contained there.
+{
+   Solaris:setnetconfig-fgetnetconfig
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:calloc
+   fun:fgetnetconfig
+   fun:getnetlist
+   fun:setnetconfig
+}
+
+# The same problem as above.
+{
+   Solaris:setnetconfig-fgetnetconfig-getlookups-strdup
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:strdup
+   fun:getlookups
+   fun:fgetnetconfig
+   fun:getnetlist
+   fun:setnetconfig
+}
+
+# The same problem as above.
+{
+   Solaris:setnetconfig-fgetnetconfig-getlookups-malloc
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:getlookups
+   fun:fgetnetconfig
+   fun:getnetlist
+   fun:setnetconfig
+}
+
+# The same problem as above.
+{
+   Solaris:setnetconfig-fgetnetconfig-gettoken
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:strdup
+   fun:gettoken
+   fun:fgetnetconfig
+   fun:getnetlist
+   fun:setnetconfig
+}
+
+# The same problem as above.
+{
+   Solaris:setnetconfig-getnetlist
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:getnetlist
+   fun:setnetconfig
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc doesn't deallocate static strings netid_tcp_main
+# and netid_tcp_udp allocated in __rpc_getconfip.
+{
+   Solaris:__rpc_getconfip-netid_tcp+udp_main
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:malloc
+   fun:strdup
+   fun:__rpc_getconfip
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc doesn't deallocate global variable global_gt.
+{
+   Solaris:dgettext
+   Memcheck:Leak
+   match-leak-kinds: reachable
+   fun:calloc
+   fun:dgettext
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc reinitializes mutex udp->ld_lock in the child's post-fork
+# handler.
+{
+   Solaris:postfork_child_mutex_reinit
+   drd:MutexErr
+   fun:mutex_init
+   fun:postfork1_child
+   fun:forkx
+}
+
+#----------------------------------------------------------------------------#
+# Solaris libc implements pthread barrier with a mutex and a condition
+# variable. In pthread_barrier_wait(), the last thread returning with
+# SERIAL_THREAD first unlocks the mutex and then broadcasts the condition
+# variable. This is ok here because that mutex does not have any priorities
+# associated, therefore no unpredicatble scheduling behaviour can occurr.
+{
+   Solaris:pthread_barrier_wait
+   Helgrind:Misc
+   fun:pthread_cond_broadcast_WRK
+   fun:cond_broadcast
+   fun:pthread_barrier_wait
+}
+
diff --git a/tests/arch_test.c b/tests/arch_test.c
index 81a12ec..d83f0e5 100644
--- a/tests/arch_test.c
+++ b/tests/arch_test.c
@@ -39,10 +39,12 @@
 
 static Bool go(char* arch)
 { 
-#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \
+   || defined(VGP_x86_solaris)
    if ( 0 == strcmp( arch, "x86"   ) ) return True;
 
-#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \
+   || defined(VGP_amd64_solaris)
 #if defined(VGA_SEC_x86)
    if ( 0 == strcmp( arch, "x86"   ) ) return True;
 #endif
diff --git a/tests/check_headers_and_includes b/tests/check_headers_and_includes
index 3c53386..b154f41 100755
--- a/tests/check_headers_and_includes
+++ b/tests/check_headers_and_includes
@@ -66,7 +66,8 @@
     "perf" => 1,
     "tests" => 1,
     "gdbserver_tests" => 1,
-    "mpi" => 1
+    "mpi" => 1,
+    "solaris" => 1
     );
 
 my %tool_export_header = (
diff --git a/tests/filter_libc b/tests/filter_libc
index dd30ef1..5d8e0ac 100755
--- a/tests/filter_libc
+++ b/tests/filter_libc
@@ -9,11 +9,9 @@
     s/ __GI___/ __/;
     s/ __([a-z]*)_nocancel / $1 /;
 
-    # "lib[S|s]ystem*" occurs on Darwin.
-    s/\(in \/.*(libc|libSystem).*\)$/(in \/...libc...)/;
-    s/\(within \/.*(libc|libSystem).*\)$/(within \/...libc...)/;
-    s/\(in \/.*(libc|libsystem).*\)$/(in \/...libc...)/;
-    s/\(within \/.*(libc|libsystem).*\)$/(within \/...libc...)/;
+    # "lib[S|s]ystem*" occurs on Darwin, "libsocket" on older Solaris/illumos.
+    s/\(in \/.*(libc|libSystem|libsystem|libsocket).*\)$/(in \/...libc...)/;
+    s/\(within \/.*(libc|libSystem|libsystem|libsocket).*\)$/(within \/...libc...)/;
 
     # Filter out dynamic loader
     s/ \(in \/.*ld-.*so\)$//;
diff --git a/tests/filter_stderr_basic b/tests/filter_stderr_basic
index c24cd5e..3fb737b 100755
--- a/tests/filter_stderr_basic
+++ b/tests/filter_stderr_basic
@@ -47,8 +47,11 @@
 # complete list of messages in the bash source file siglist.c.
 perl -n -e 'print if !/^(Segmentation fault|Alarm clock|Aborted|Bus error)( \(core dumped\))?$/' |
 
+# Similar as above, but for ksh on Solaris/illumos.
+perl -n -e 'print if !/^(Memory fault|Killed) $/' |
+
 # Translate intercepted glibc functions back to their canonical name
-perl -p -e "s/: memcpy\@\@?GLIBC_[.1-9]+ \(vg_replace_strmem.c:...\)/: memcpy \(vg_replace_strmem.c:...\)/" |
+perl -p -e "s/: memcpy\@\@?GLIBC_[.1-9]+ \(vg_replace_strmem.c:.*?\)/: memcpy \(vg_replace_strmem.c:...\)/" |
 sed -e "s/: \(__GI_\|__\|\)\(memcmp\|memcpy\|strcpy\|strncpy\|strchr\|strrchr\)\(\|_sse4_1\|_sse42\|_sse2_unaligned\) (vg_replace_strmem.c:/: \2 (vg_replace_strmem.c:/" |
 
 # Remove any ": dumping core" message as the user might have a
diff --git a/tests/os_test.c b/tests/os_test.c
index b755e30..d3c5a69 100644
--- a/tests/os_test.c
+++ b/tests/os_test.c
@@ -23,6 +23,7 @@
 char* all_OSes[] = {
    "linux",
    "darwin",
+   "solaris",
    NULL
 };
 
@@ -62,6 +63,9 @@
 #elif defined(VGO_darwin)
    if ( 0 == strcmp( OS, "darwin" ) ) return True;
 
+#elif defined(VGO_solaris)
+   if ( 0 == strcmp( OS, "solaris" ) ) return True;
+
 #else
 #  error Unknown OS
 #endif   // VGO_*
diff --git a/tests/platform_test b/tests/platform_test
index 43275c8..9653921 100644
--- a/tests/platform_test
+++ b/tests/platform_test
@@ -15,6 +15,7 @@
 all_platforms="$all_platforms arm-linux"
 all_platforms="$all_platforms s390x-linux mips32-linux mips64-linux"
 all_platforms="$all_platforms x86-darwin amd64-darwin"
+all_platforms="$all_platforms x86-solaris amd64-solaris"
 
 if [ $# -ne 2 ] ; then
     echo "usage: platform_test <arch-type> <OS-type>"