Merge the DARWIN branch onto the trunk.

I tried using 'svn merge' to do the merge but it did a terrible job and
there were bazillions of conflicts.  So instead I just took the diff between
the branch and trunk  at r10155, applied the diff to the trunk, 'svn add'ed
the added files (no files needed to be 'svn remove'd) and committed.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10156 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/Makefile.am b/Makefile.am
index 57ab3e2..0106209 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,6 +15,22 @@
 EXP_TOOLS = 	exp-omega \
 		exp-ptrcheck
 
+# DDD: once all tools work on Darwin, TEST_TOOLS and TEST_EXP_TOOLS can be
+# replaced with TOOLS and EXP_TOOLS.
+if !VGCONF_OS_IS_DARWIN
+  TEST_TOOLS = $(TOOLS)
+  TEST_EXP_TOOLS = $(EXP_TOOLS)
+else
+  TEST_TOOLS =	memcheck \
+		cachegrind \
+		callgrind \
+		massif \
+		lackey \
+		none
+
+  TEST_EXP_TOOLS = exp-omega
+endif
+
 # Put docs last because building the HTML is slow and we want to get
 # everything else working before we try it.
 SUBDIRS = include coregrind . tests perf auxprogs $(TOOLS) $(EXP_TOOLS) docs
@@ -27,7 +43,8 @@
 	glibc-2.34567-NPTL-helgrind.supp \
 	glibc-2.2-LinuxThreads-helgrind.supp \
 	glibc-2.X-drd.supp \
-	exp-ptrcheck.supp
+	exp-ptrcheck.supp \
+	darwin9.supp
 DEFAULT_SUPP_FILES = @DEFAULT_SUPP@
 
 # We include all the base .supp files in the distribution, but not
@@ -78,6 +95,9 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 # Ditto
 endif
+if VGCONF_OS_IS_DARWIN
+# GrP untested, possibly hopeless
+endif
 
 default.supp: $(DEFAULT_SUPP_FILES)
 	echo "# This is a generated file, composed of the following suppression rules:" > default.supp
@@ -86,11 +106,11 @@
 
 ## Preprend @PERL@ because tests/vg_regtest isn't executable
 regtest: check
-	@PERL@ tests/vg_regtest $(TOOLS) $(EXP_TOOLS)
+	@PERL@ tests/vg_regtest $(TEST_TOOLS) $(TEST_EXP_TOOLS)
 nonexp-regtest: check
-	@PERL@ tests/vg_regtest $(TOOLS)
+	@PERL@ tests/vg_regtest $(TEST_TOOLS)
 exp-regtest: check
-	@PERL@ tests/vg_regtest $(EXP_TOOLS)
+	@PERL@ tests/vg_regtest $(TEST_EXP_TOOLS)
 
 ## Preprend @PERL@ because tests/vg_perf isn't executable
 perf: check
diff --git a/Makefile.core-tool.am b/Makefile.core-tool.am
index e5ba118..493e8c3 100644
--- a/Makefile.core-tool.am
+++ b/Makefile.core-tool.am
@@ -1,6 +1,15 @@
 # This file contains things shared by coregrind/Makefile.am and tool
 # Makefile.am files.
 
+# See Makefile.tool-tests.am for an explanation of dSYMs.
+build-noinst_DSYMS:
+	for f in $(noinst_DSYMS); do \
+	  if [ ! -e $$f.dSYM  -o  $$f -nt $$f.dSYM ] ; then \
+	      echo "dsymutil $$f"; \
+	      dsymutil $$f; \
+	  fi; \
+	done
+
 # This is used by coregrind/Makefile.am and Makefile.tool.am for doing
 # "in-place" installs.  It copies $(noinst_PROGRAMS) into $inplacedir.
 # It needs to be depended on by an 'all-local' rule.
@@ -13,6 +22,16 @@
 	  done ; \
 	fi
 
+# Similar to inplace-noinst_PROGRAMS
+inplace-noinst_DSYMS: build-noinst_DSYMS
+	if [ -n "$(noinst_DSYMS)" ] ; then \
+	  mkdir -p $(inplacedir); \
+	  for f in $(noinst_DSYMS); do \
+	    rm -f $(inplacedir)/$$f.dSYM; \
+	    ln -f -s ../$(subdir)/$$f.dSYM $(inplacedir); \
+	  done ; \
+	fi
+
 # This is used by coregrind/Makefile.am and by <tool>/Makefile.am for doing
 # "make install".  It copies $(noinst_PROGRAMS) into $prefix/lib/valgrind/.
 # It needs to be depended on by an 'install-exec-local' rule.
@@ -24,3 +43,23 @@
 	  done ; \
 	fi
 
+# Similar to install-noinst_PROGRAMS.
+# Nb: we don't use $(INSTALL_PROGRAM) here because it doesn't work with
+# directories.  XXX: not sure whether the resulting permissions will be
+# correct when using 'cp -R'...
+install-noinst_DSYMS: build-noinst_DSYMS
+	if [ -n "$(noinst_DSYMS)" ] ; then \
+	  $(mkinstalldirs) $(DESTDIR)$(valdir); \
+	  for f in $(noinst_DSYMS); do \
+	    cp -R $$f.dSYM $(DESTDIR)$(valdir); \
+	  done ; \
+	fi
+
+# This needs to be depended on by a 'clean-local' rule.
+clean-noinst_DSYMS:
+	for f in $(noinst_DSYMS); do \
+	  rm -rf $$f.dSYM; \
+	done
+
+
+
diff --git a/Makefile.flags.am b/Makefile.flags.am
index dc09cab..322c8fb 100644
--- a/Makefile.flags.am
+++ b/Makefile.flags.am
@@ -10,7 +10,12 @@
 # The aim is to give reasonable performance but also to have good
 # stack traces, since users often see stack traces extending 
 # into (and through) the preloads.
-AM_CFLAGS_PIC = -O -g -fpic -fno-omit-frame-pointer -fno-strict-aliasing
+if VGCONF_OS_IS_DARWIN
+AM_CFLAGS_PIC = -dynamic -O -g -fno-omit-frame-pointer -fno-strict-aliasing -mno-dynamic-no-pic
+else
+AM_CFLAGS_PIC = -fpic -O -g -fno-omit-frame-pointer -fno-strict-aliasing
+endif
+
 
 # Flags for specific targets.
 #
@@ -82,6 +87,25 @@
 AM_CCASFLAGS_PPC64_AIX5   = $(AM_CPPFLAGS_PPC64_AIX5) \
 			    @FLAG_MAIX64@ -mcpu=powerpc64 -g
 
+AM_FLAG_M3264_X86_DARWIN = -arch i386
+AM_CPPFLAGS_X86_DARWIN	  = $(AM_CPPFLAGS_COMMON) \
+			    -DVGA_x86=1 \
+			    -DVGO_darwin=1 \
+			    -DVGP_x86_darwin=1
+AM_CFLAGS_X86_DARWIN     = $(WERROR) -arch i386 $(AM_CFLAGS_BASE) \
+			    -mmacosx-version-min=10.5 -fno-stack-protector \
+			    -mdynamic-no-pic
+AM_CCASFLAGS_X86_DARWIN  = $(AM_CPPFLAGS_X86_DARWIN) -arch i386 -g
+
+AM_FLAG_M3264_AMD64_DARWIN = -arch x86_64
+AM_CPPFLAGS_AMD64_DARWIN  = $(AM_CPPFLAGS_COMMON) \
+			    -DVGA_amd64=1 \
+			    -DVGO_darwin=1 \
+			    -DVGP_amd64_darwin=1
+AM_CFLAGS_AMD64_DARWIN     = $(WERROR) -arch x86_64 $(AM_CFLAGS_BASE) \
+			    -mmacosx-version-min=10.5 -fno-stack-protector
+AM_CCASFLAGS_AMD64_DARWIN  = $(AM_CPPFLAGS_AMD64_DARWIN) -arch x86_64 -g
+
 # 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.
@@ -102,9 +126,12 @@
 #
 PRELOAD_LDFLAGS_COMMON_LINUX = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst
 PRELOAD_LDFLAGS_COMMON_AIX5  = -nodefaultlibs -shared -Wl,-G -Wl,-bnogc
+PRELOAD_LDFLAGS_COMMON_DARWIN = -dynamic -dynamiclib -all_load
 PRELOAD_LDFLAGS_X86_LINUX   = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@
 PRELOAD_LDFLAGS_AMD64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
 PRELOAD_LDFLAGS_PPC32_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@
 PRELOAD_LDFLAGS_PPC64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
 PRELOAD_LDFLAGS_PPC32_AIX5  = $(PRELOAD_LDFLAGS_COMMON_AIX5)  @FLAG_MAIX32@
 PRELOAD_LDFLAGS_PPC64_AIX5  = $(PRELOAD_LDFLAGS_COMMON_AIX5)  @FLAG_MAIX64@
+PRELOAD_LDFLAGS_X86_DARWIN   = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch i386
+PRELOAD_LDFLAGS_AMD64_DARWIN = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch x86_64
diff --git a/Makefile.tool-tests.am b/Makefile.tool-tests.am
index b81d3e5..9694f06 100644
--- a/Makefile.tool-tests.am
+++ b/Makefile.tool-tests.am
@@ -16,3 +16,25 @@
 # automake;  see comments in Makefile.flags.am for more detail.
 AM_CCASFLAGS = $(AM_CPPFLAGS)
 
+
+# On Darwin, for a program 'p', the DWARF debug info is stored in the
+# directory 'p.dSYM'.  This must be generated after the executable is
+# created, with 'dsymutil p'.  We could redefine LINK with a script that
+# executes 'dsymutil' after linking, but that's a pain.  Instead we use this
+# hook so that every time "make check" is run, we subsequently invoke
+# 'dsymutil' on all the executables that lack a .dSYM directory, or that are
+# newer than their corresponding .dSYM directory.
+if VGCONF_OS_IS_DARWIN
+check-local:
+	for f in $(check_PROGRAMS) ; do \
+	    if [ ! -e $$f.dSYM  -o  $$f -nt $$f.dSYM ] ; then \
+	        echo "dsymutil $$f"; \
+	        dsymutil $$f; \
+	    fi \
+	done
+
+clean-local:
+	for f in $(check_PROGRAMS) ; do \
+	    rm -rf $$f.dSYM; \
+	done
+endif  
diff --git a/Makefile.tool.am b/Makefile.tool.am
index 0812728..21925fc 100644
--- a/Makefile.tool.am
+++ b/Makefile.tool.am
@@ -24,6 +24,12 @@
 LIBREPLACEMALLOC_PPC64_AIX5 = \
 	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-ppc64-aix5.a
 
+LIBREPLACEMALLOC_X86_DARWIN = \
+	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-darwin.a
+
+LIBREPLACEMALLOC_AMD64_DARWIN = \
+	$(top_builddir)/coregrind/libreplacemalloc_toolpreload-amd64-darwin.a
+
 
 COREGRIND_LIBS_X86_LINUX = \
 	$(top_builddir)/coregrind/libcoregrind-x86-linux.a \
@@ -49,6 +55,14 @@
 	$(top_builddir)/coregrind/libcoregrind-ppc64-aix5.a \
 	@VEX_DIR@/libvex-ppc64-aix5.a
 
+COREGRIND_LIBS_X86_DARWIN = \
+	$(top_builddir)/coregrind/libcoregrind-x86-darwin.a \
+	@VEX_DIR@/libvex-x86-darwin.a
+
+COREGRIND_LIBS_AMD64_DARWIN = \
+	$(top_builddir)/coregrind/libcoregrind-amd64-darwin.a \
+	@VEX_DIR@/libvex-amd64-darwin.a
+
 
 ##.PHONY:  @VEX_DIR@/libvex.a
 
@@ -88,6 +102,18 @@
 	EXTRA_CFLAGS="$(AM_CFLAGS_PPC64_AIX5) @FLAG_WDECL_AFTER_STMT@ \
 			@FLAG_FNO_STACK_PROTECTOR@"
 
+@VEX_DIR@/libvex-x86-darwin.a: @VEX_DIR@/priv/main/vex_svnversion.h
+	$(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" \
+	libvex-x86-darwin.a \
+	EXTRA_CFLAGS="$(AM_CFLAGS_X86_DARWIN) @FLAG_WDECL_AFTER_STMT@ \
+		@FLAG_FNO_STACK_PROTECTOR@"
+
+@VEX_DIR@/libvex-amd64-darwin.a: @VEX_DIR@/priv/main/vex_svnversion.h
+	$(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" \
+	libvex-amd64-darwin.a \
+	EXTRA_CFLAGS="$(AM_CFLAGS_AMD64_DARWIN) @FLAG_WDECL_AFTER_STMT@ \
+		@FLAG_FNO_STACK_PROTECTOR@"
+
 @VEX_DIR@/priv/main/vex_svnversion.h:
 	$(MAKE) -C @VEX_DIR@ CC="$(CC)" version
 
@@ -97,7 +123,8 @@
 	-Wl,-defsym,valt_load_address=@VALT_LOAD_ADDRESS@ \
 	-nodefaultlibs -nostartfiles -u _start
 TOOL_LDFLAGS_COMMON_AIX5 = -static -Wl,-e_start_valgrind
-
+TOOL_LDFLAGS_COMMON_DARWIN = -nodefaultlibs -nostartfiles \
+	-Wl,-u,__start -Wl,-e,__start -Wl,-bind_at_load /usr/lib/dyld
 
 TOOL_LDADD_X86_LINUX = $(COREGRIND_LIBS_X86_LINUX) $(TOOL_LDADD_COMMON)
 TOOL_LDFLAGS_X86_LINUX = \
@@ -127,6 +154,23 @@
 TOOL_LDFLAGS_PPC64_AIX5 = \
 	$(TOOL_LDFLAGS_COMMON_AIX5) @FLAG_MAIX64@ -Wl,-bbigtoc
 
+TOOL_LDADD_X86_DARWIN = $(COREGRIND_LIBS_X86_DARWIN) $(TOOL_LDADD_COMMON)
+TOOL_LDFLAGS_X86_DARWIN = \
+	$(TOOL_LDFLAGS_COMMON_DARWIN) -arch i386 \
+	-Wl,-seg1addr,0xf0080000 \
+	-Wl,-stack_addr,0xf0080000 -Wl,-stack_size,0x80000 \
+	-Wl,-pagezero_size,0xf0000000
+
+# pagezero can't be unmapped and remapped. Use stack instead.
+# GrP fixme no stack guard
+TOOL_LDADD_AMD64_DARWIN = $(COREGRIND_LIBS_AMD64_DARWIN) $(TOOL_LDADD_COMMON)
+TOOL_LDFLAGS_AMD64_DARWIN = \
+	$(TOOL_LDFLAGS_COMMON_DARWIN) -arch x86_64 \
+	-Wl,-seg1addr,0x7fff55000000 \
+	-Wl,-stack_addr,0x7fff50080000 -Wl,-stack_size,0x7ffe50080000 \
+	-Wl,-pagezero_size,0x100000000
+
+
 LIBREPLACEMALLOC_LDFLAGS_X86_LINUX = \
 	-Wl,--whole-archive \
 	$(LIBREPLACEMALLOC_X86_LINUX) \
@@ -153,8 +197,17 @@
 LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5 = \
 	$(LIBREPLACEMALLOC_PPC64_AIX5)
 
+LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN = \
+	$(LIBREPLACEMALLOC_X86_DARWIN)
 
-all-local: inplace-noinst_PROGRAMS
+LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN = \
+	$(LIBREPLACEMALLOC_AMD64_DARWIN)
 
-install-exec-local: install-noinst_PROGRAMS
+
+
+all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
+
+clean-local: clean-noinst_DSYMS
+
+install-exec-local: install-noinst_PROGRAMS install-noinst_DSYMS
 
diff --git a/NEWS b/NEWS
index 757b220..332abab 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,22 @@
 
 Release 3.5.0 (???)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* XXX: Mac OS X support
+  - x86/Darwin.
+  - probably amd64/Darwin.
+  - Requires Mac OS X 10.5 Leopard or later.
+  - No support for Mac OS X on PowerPC machines.
+  - Many thanks to Greg Parker for developing this port over several years.
+
+  Things that don't work
+  - Objective-C garbage collection
+  - --db-attach=yes
+  - Messages like the following indicate a mismatch between Valgrind's
+    memory map and the kernel. Occasional failures are expected in
+    multithreaded programs. If the failure repeats for the same address
+    range, then there may be a problem causing false errors or crashes.
+        sync check at ...: FAILED
+
 * A new Memcheck client request VALGRIND_COUNT_LEAK_BLOCKS has been added.
   It is similar to VALGRIND_COUNT_LEAKS but counts blocks instead of bytes.
   [XXX: consider adding VALGRIND_COUNT_LEAK_BYTES as a synonym and
diff --git a/auxprogs/Makefile.am b/auxprogs/Makefile.am
index 7145df7..df59b74 100644
--- a/auxprogs/Makefile.am
+++ b/auxprogs/Makefile.am
@@ -27,7 +27,6 @@
 #
 #----------------------------------------------------------
 
-
 #------------------------- mpi wrappers -----------------------
 # Build libmpiwrap.so for the primary target, and for the secondary
 # target if relevant.
@@ -51,11 +50,18 @@
 			-qflag=w:w -qlanglvl=extended \
 			`echo $(AM_FLAG_M3264_SEC) | sed s/maix/q/g`
 else
+if VGCONF_OS_IS_DARWIN
+ HACKY_FLAGS_PRI = -g -O -fno-omit-frame-pointer -Wall -dynamic \
+			-dynamiclib -all_load $(AM_FLAG_M3264_PRI)
+ HACKY_FLAGS_SEC = -g -O -fno-omit-frame-pointer -Wall -dynamic \
+			-dynamiclib -all_load $(AM_FLAG_M3264_SEC)
+else
  HACKY_FLAGS_PRI = -g -O -fno-omit-frame-pointer -Wall -fpic -shared \
 			$(AM_FLAG_M3264_PRI)
  HACKY_FLAGS_SEC = -g -O -fno-omit-frame-pointer -Wall -fpic -shared \
 			$(AM_FLAG_M3264_SEC)
 endif
+endif
 
 
 ## First, we have to say how to build the .so's ..
@@ -120,6 +126,9 @@
 	rm -f libmpiwrap-.c \
 	    libmpiwrap-@VGCONF_ARCH_PRI@-@VGCONF_OS@.c \
 	    libmpiwrap-@VGCONF_ARCH_SEC@-@VGCONF_OS@.c
+if VGCONF_OS_IS_DARWIN
+	rm -rf libmpiwrap-*.dSYM
+endif
 
 #
 #----------------------------------------------------------
diff --git a/cachegrind/Makefile.am b/cachegrind/Makefile.am
index eac2825..f165e8d 100644
--- a/cachegrind/Makefile.am
+++ b/cachegrind/Makefile.am
@@ -23,6 +23,12 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += cachegrind-ppc64-aix5
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += cachegrind-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += cachegrind-amd64-darwin
+endif
 
 # Build cg_merge for the primary target only.
 bin_PROGRAMS = cg_merge
@@ -80,3 +86,17 @@
 cachegrind_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 cachegrind_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 cachegrind_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+cachegrind_x86_darwin_SOURCES      = $(CACHEGRIND_SOURCES_COMMON) $(CACHEGRIND_SOURCES_X86)
+cachegrind_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+cachegrind_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN)
+cachegrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+cachegrind_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+cachegrind_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+cachegrind_amd64_darwin_SOURCES      = $(CACHEGRIND_SOURCES_COMMON) $(CACHEGRIND_SOURCES_AMD64)
+cachegrind_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+cachegrind_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+cachegrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+cachegrind_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+cachegrind_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index 279356b..6c4e1e4 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1464,13 +1464,14 @@
    if (VG_(clo_verbosity) == 0) 
       return;
 
-   #define MAX(a, b)  ((a) >= (b) ? (a) : (b))
+   // Nb: this isn't called "MAX" because that overshadows a global on Darwin.
+   #define CG_MAX(a, b)  ((a) >= (b) ? (a) : (b))
 
    /* I cache results.  Use the I_refs value to determine the first column
     * width. */
    l1 = ULong_width(Ir_total.a);
-   l2 = ULong_width(MAX(Dr_total.a, Bc_total.b));
-   l3 = ULong_width(MAX(Dw_total.a, Bi_total.b));
+   l2 = ULong_width(CG_MAX(Dr_total.a, Bc_total.b));
+   l3 = ULong_width(CG_MAX(Dw_total.a, Bi_total.b));
 
    /* Make format string, getting width right for numbers */
    VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am
index 497ee19..f7f12a7 100644
--- a/cachegrind/tests/Makefile.am
+++ b/cachegrind/tests/Makefile.am
@@ -25,5 +25,9 @@
 
 # C ones
 dlclose_LDADD		= -ldl
-myprint_so_LDFLAGS	= $(AM_FLAG_M3264_PRI) -shared -fPIC
+if VGCONF_OS_IS_DARWIN
+myprint_so_LDFLAGS	= $(AM_CFLAGS) -dynamic -dynamiclib -all_load -fpic
+else
+myprint_so_LDFLAGS	= $(AM_CFLAGS) -shared -fPIC
+endif
 myprint_so_CFLAGS	= $(AM_CFLAGS) -fPIC
diff --git a/callgrind/Makefile.am b/callgrind/Makefile.am
index ac1720c..bc983b6 100644
--- a/callgrind/Makefile.am
+++ b/callgrind/Makefile.am
@@ -23,6 +23,12 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += callgrind-ppc64-aix5
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += callgrind-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += callgrind-amd64-darwin
+endif
 
 CALLGRIND_SOURCES_COMMON = main.c events.c bb.c clo.c \
                            costs.c bbcc.c command.c debug.c fn.c \
@@ -81,3 +87,17 @@
 callgrind_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 callgrind_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 callgrind_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+callgrind_x86_darwin_SOURCES      = $(CALLGRIND_SOURCES_COMMON) $(CALLGRIND_SOURCES_X86)
+callgrind_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+callgrind_x86_darwin_CFLAGS       = $(CALLGRIND_CFLAGS_COMMON) $(AM_CFLAGS_X86_DARWIN)
+callgrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+callgrind_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+callgrind_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+callgrind_amd64_darwin_SOURCES      = $(CALLGRIND_SOURCES_COMMON) $(CALLGRIND_SOURCES_AMD64)
+callgrind_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+callgrind_amd64_darwin_CFLAGS       = $(CALLGRIND_CFLAGS_COMMON) $(AM_CFLAGS_AMD64_DARWIN)
+callgrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+callgrind_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+callgrind_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/configure.in b/configure.in
index 1e3892f..e6657df 100644
--- a/configure.in
+++ b/configure.in
@@ -62,6 +62,7 @@
 AM_PROG_CC_C_O
 AC_PROG_CPP
 AC_PROG_CXX
+AC_PROG_OBJC
 AC_PROG_RANLIB
 
 # If no AR variable was specified, look up the name of the archiver. Otherwise
@@ -219,6 +220,8 @@
 AC_MSG_CHECKING([for a supported OS])
 AC_SUBST(VGCONF_OS)
 
+DEFAULT_SUPP=""
+
 case "${host_os}" in
      *linux*)
 	AC_MSG_RESULT([ok (${host_os})])
@@ -266,6 +269,34 @@
         VGCONF_OS="freebsd"
         ;;
 
+     *darwin*)
+        AC_MSG_RESULT([ok (${host_os})])
+        VGCONF_OS="darwin"
+
+	AC_MSG_CHECKING([for the kernel version])
+	kernel=`uname -r`
+
+        # Nb: for Darwin we set DEFAULT_SUPP here.  That's because Darwin
+        # has only one relevant version, the OS version. The `uname` check
+        # is a good way to get that version (i.e. "Darwin 9.6.0" is Mac OS
+        # X 10.5.6, and "Darwin 10.x" would presumably be Mac OS X 10.6.x
+        # Snow Leopard and darwin10.supp), and we don't know of an macros
+        # similar to __GLIBC__ to get that info.
+        #
+        # XXX: `uname -r` won't do the right thing for cross-compiles, but
+        # that's not a problem yet.
+	case "${kernel}" in
+	     9.*)
+		  AC_MSG_RESULT([Darwin 9.x (${kernel}) / Mac OS X 10.5 Leopard])
+		  DEFAULT_SUPP="darwin9.supp ${DEFAULT_SUPP}"
+		  ;;
+     *) 
+		  AC_MSG_RESULT([unsupported (${kernel})])
+		  AC_MSG_ERROR([Valgrind works on Darwin 9.x (Mac OS X 10.5)])
+		  ;;
+	esac
+        ;;
+
      *) 
 	AC_MSG_RESULT([no (${host_os})])
 	AC_MSG_ERROR([Valgrind is operating system specific. Sorry. Please consider doing a port.])
@@ -405,6 +436,33 @@
         valt_load_address_inner="0x28000000"
         AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
 	;;
+     x86-darwin)
+        VGCONF_ARCH_PRI="x86"
+	VGCONF_PLATFORM_PRI_CAPS="X86_DARWIN"
+	VGCONF_PLATFORM_SEC_CAPS=""
+        valt_load_address_normal="0x0"
+        valt_load_address_inner="0x0"
+        AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+	;;
+     amd64-darwin)
+	if test x$vg_cv_only64bit = xyes; then
+           VGCONF_ARCH_PRI="amd64"
+	   VGCONF_PLATFORM_PRI_CAPS="AMD64_DARWIN"
+	   VGCONF_PLATFORM_SEC_CAPS=""
+	elif test x$vg_cv_only32bit = xyes; then
+           VGCONF_ARCH_PRI="x86"
+	   VGCONF_PLATFORM_PRI_CAPS="X86_DARWIN"
+	   VGCONF_PLATFORM_SEC_CAPS=""
+	   VGCONF_ARCH_PRI_CAPS="x86"
+	else
+           VGCONF_ARCH_PRI="amd64"
+	   VGCONF_PLATFORM_PRI_CAPS="AMD64_DARWIN"
+	   VGCONF_PLATFORM_SEC_CAPS="X86_DARWIN"
+	fi
+        valt_load_address_normal="0x0"
+        valt_load_address_inner="0x0"
+        AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+	;;
     *)
         VGCONF_ARCH_PRI="unknown"
 	VGCONF_PLATFORM_PRI_CAPS="UNKNOWN"
@@ -420,9 +478,12 @@
 # defined.
 AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_X86,   
                test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
-                 -o x$VGCONF_PLATFORM_SEC_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 )
 AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64, 
-               test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX )
+               test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN )
 AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \ 
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX \
@@ -444,12 +505,20 @@
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX)
 AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_LINUX, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX)
+
 AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_AIX5 \ 
                  -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_AIX5)
 AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5, 
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_AIX5)
 
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_DARWIN,   
+               test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
+                 -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN)
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN, 
+               test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
+
+
 # Similarly, set up VGCONF_OF_IS_<os>.  Exactly one of these becomes defined.
 # Relies on the assumption that the primary and secondary targets are 
 # for the same OS, so therefore only necessary to test the primary.
@@ -461,6 +530,9 @@
 AM_CONDITIONAL(VGCONF_OS_IS_AIX5,
                test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_AIX5 \
                  -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_AIX5)
+AM_CONDITIONAL(VGCONF_OS_IS_DARWIN,
+               test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
+                 -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
 
 
 # Sometimes, in the Makefile.am files, it's useful to know whether or not
@@ -493,7 +565,6 @@
 # Libc and suppressions
 #----------------------------------------------------------------------------
 # This variable will collect the suppression files to be used.
-DEFAULT_SUPP=""
 AC_SUBST(DEFAULT_SUPP)
 
 GLIBC_VERSION=""
@@ -596,6 +667,15 @@
 ],
 GLIBC_VERSION="aix5")
 
+# not really a version check
+AC_EGREP_CPP([DARWIN_LIBC], [
+#include <sys/cdefs.h>
+#if defined(__DARWIN_VERS_1050)
+  DARWIN_LIBC
+#endif
+],
+GLIBC_VERSION="darwin")
+
 AC_MSG_CHECKING([the GLIBC_VERSION version])
 
 case "${GLIBC_VERSION}" in
@@ -670,11 +750,17 @@
 	AC_DEFINE([AIX5_LIBC], 1, [Define to 1 if you're using AIX 5.1 or 5.2 or 5.3])
 	DEFAULT_SUPP="aix5libc.supp ${DEFAULT_SUPP}"
 	;;
+     darwin)
+	AC_MSG_RESULT(Darwin)
+	AC_DEFINE([DARWIN_LIBC], 1, [Define to 1 if you're using Darwin])
+	# DEFAULT_SUPP set by kernel version check above.
+	;;
 
      *)
 	AC_MSG_RESULT(unsupported version)
 	AC_MSG_ERROR([Valgrind requires glibc version 2.2 - 2.10])
 	AC_MSG_ERROR([or AIX 5.1 or 5.2 or 5.3 GLIBC_VERSION])
+	AC_MSG_ERROR([or Darwin libc])
 	;;
 esac
 
@@ -1341,6 +1427,14 @@
 
 
 #----------------------------------------------------------------------------
+# Check for /proc filesystem
+#----------------------------------------------------------------------------
+AC_CHECK_FILES(/proc/self/fd /proc/self/exe /proc/self/maps, 
+    [ AC_DEFINE([HAVE_PROC], 1, [can use /proc filesystem]) ], 
+    [])
+
+
+#----------------------------------------------------------------------------
 # Checks for C header files.
 #----------------------------------------------------------------------------
 
@@ -1389,6 +1483,7 @@
         memchr       \
         memset       \
         mkdir        \
+        mremap       \
         ppoll        \
         pthread_barrier_init       \
         pthread_condattr_setclock  \
@@ -1738,6 +1833,7 @@
    memcheck/tests/amd64/Makefile
    memcheck/tests/x86/Makefile
    memcheck/tests/linux/Makefile
+   memcheck/tests/darwin/Makefile
    memcheck/tests/x86-linux/Makefile
    memcheck/perf/Makefile
    memcheck/docs/Makefile
@@ -1769,6 +1865,7 @@
    none/tests/ppc64/Makefile
    none/tests/x86/Makefile
    none/tests/linux/Makefile
+   none/tests/darwin/Makefile
    none/tests/x86-linux/Makefile
    none/docs/Makefile
    exp-omega/Makefile
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 0839b85..1bcfec7 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -7,29 +7,40 @@
 include $(top_srcdir)/Makefile.flags.am
 include $(top_srcdir)/Makefile.core-tool.am
 
-
 AM_CPPFLAGS_CORE_COMMON = \
 	-I$(top_srcdir)/coregrind \
 	-DVG_LIBDIR="\"$(valdir)"\"
 
 AM_CPPFLAGS_X86_LINUX   += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"x86-linux\""
+
 AM_CPPFLAGS_AMD64_LINUX += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"amd64-linux\""
+
 AM_CPPFLAGS_PPC32_LINUX += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc32-linux\""
+
 AM_CPPFLAGS_PPC64_LINUX += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc64-linux\""
+
 AM_CPPFLAGS_PPC32_AIX5  += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc32-aix5\""
+
 AM_CPPFLAGS_PPC64_AIX5  += \
     $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc64-aix5\""
 
+AM_CPPFLAGS_X86_DARWIN   += \
+    $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"x86-darwin\""
+
+AM_CPPFLAGS_AMD64_DARWIN += \
+    $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"amd64-darwin\""
+
 
 default.supp: $(SUPP_FILES)
 
 
 noinst_PROGRAMS =
+noinst_DSYMS =
 pkglib_LIBRARIES =
 LIBVEX =
 
@@ -69,6 +80,20 @@
 LIBVEX           += libvex-ppc64-aix5.a
 endif
 
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS  += vgpreload_core-x86-darwin.so
+noinst_DSYMS     += vgpreload_core-x86-darwin.so
+pkglib_LIBRARIES += libcoregrind-x86-darwin.a libreplacemalloc_toolpreload-x86-darwin.a
+LIBVEX           += libvex-x86-darwin.a
+endif
+
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS  += vgpreload_core-amd64-darwin.so
+noinst_DSYMS     += vgpreload_core-amd64-darwin.so
+pkglib_LIBRARIES += libcoregrind-amd64-darwin.a libreplacemalloc_toolpreload-amd64-darwin.a
+LIBVEX           += libvex-amd64-darwin.a
+endif
+
 
 #------------------------- launcher -----------------------
 # Build the launcher (valgrind) for the primary target only.
@@ -87,6 +112,46 @@
 	m_debuglog.c \
 	m_vkiscnums.c
 endif
+if VGCONF_OS_IS_DARWIN
+valgrind_SOURCES = \
+	launcher-darwin.c \
+	m_debuglog.c
+endif
+
+# Mach RPC interface definitions
+# Here are some more .defs files that are not used, but could be in the
+# future:
+#	clock.defs \
+#	clock_priv.defs \
+#	clock_reply.defs \
+#	exc.defs \
+#	host_priv.defs \
+#	host_security.defs \
+#	ledger.defs \
+#	lock_set.defs \
+#	mach_host.defs \
+#	mach_port.defs \
+#	notify.defs \
+#	processor.defs \
+#	processor_set.defs \
+#
+if VGCONF_OS_IS_DARWIN
+mach_defs = \
+	mach_vm.defs \
+	task.defs \
+	thread_act.defs \
+	vm_map.defs
+else
+mach_defs =
+endif
+
+mach_srcs = $(addprefix m_mach/,$(mach_defs:.defs=User.c))
+mach_server_srcs = $(addprefix m_mach/,$(mach_defs:.defs=Server.c))
+mach_hdrs = $(addprefix m_mach/,$(mach_defs:.defs=.h))
+mach_files = $(addprefix /usr/include/mach/,$(mach_defs))
+
+$(mach_srcs) $(mach_hdrs): $(mach_files)
+	(cd m_mach && mig $(mach_files))
 
 valgrind_CPPFLAGS  = $(AM_CPPFLAGS_PRI)
 valgrind_CFLAGS    = $(AM_CFLAGS_PRI)
@@ -103,6 +168,7 @@
 
 
 noinst_HEADERS = \
+	$(mach_hdrs) \
 	launcher-aix5-bootblock.h \
 	pub_core_aspacehl.h	\
 	pub_core_aspacemgr.h	\
@@ -129,6 +195,7 @@
 	pub_core_libcprint.h	\
 	pub_core_libcproc.h	\
 	pub_core_libcsignal.h	\
+	pub_core_mach.h	\
 	pub_core_machine.h	\
 	pub_core_mallocfree.h	\
 	pub_core_options.h	\
@@ -166,6 +233,7 @@
 	m_debuginfo/priv_readdwarf.h	\
 	m_debuginfo/priv_readdwarf3.h	\
 	m_debuginfo/priv_readelf.h	\
+	m_debuginfo/priv_readmacho.h	\
 	m_debuginfo/priv_readxcoff.h	\
 	m_demangle/ansidecl.h	\
 	m_demangle/cp-demangle.h \
@@ -181,17 +249,22 @@
 	m_syswrap/priv_syswrap-linux.h \
 	m_syswrap/priv_syswrap-linux-variants.h \
 	m_syswrap/priv_syswrap-aix5.h \
+	m_syswrap/priv_syswrap-darwin.h \
 	m_syswrap/priv_syswrap-main.h \
 	m_ume/priv_ume.h
 
 BUILT_SOURCES = 
 CLEANFILES = 
+if VGCONF_OS_IS_DARWIN
+BUILT_SOURCES += $(COREGRIND_DARWIN_BUILT_SOURCES)
+CLEANFILES    += $(COREGRIND_DARWIN_BUILT_SOURCES)
+endif
 
 
 COREGRIND_SOURCES_COMMON = \
 	m_commandline.c \
-	m_cpuid.S \
 	m_clientstate.c \
+	m_cpuid.S \
 	m_debugger.c \
 	m_debuglog.c \
 	m_errormgr.c \
@@ -241,6 +314,7 @@
 	m_scheduler/sema.c \
 	m_syswrap/syswrap-main.c \
 	m_ume/elf.c \
+	m_ume/macho.c \
 	m_ume/main.c \
 	m_ume/script.c
 
@@ -264,6 +338,28 @@
 	m_initimg/initimg-aix5.c \
 	m_syswrap/syswrap-aix5.c
 
+    # Note that the *User.c files are generated using 'mig' from $mach_defs
+    # above.
+COREGRIND_DARWIN_SOURCE = \
+	m_aspacemgr/aspacemgr-linux.c \
+	m_debuginfo/readdwarf.c \
+	m_debuginfo/readdwarf3.c \
+	m_debuginfo/readstabs.c \
+	m_debuginfo/readmacho.c \
+	m_debuginfo/readpdb.c \
+	m_mach/mach_basics.c \
+	m_mach/mach_msg.c \
+	m_initimg/initimg-darwin.c \
+	m_initimg/initimg-pathscan.c \
+	m_syswrap/syswrap-darwin.c \
+	m_syswrap/syswrap-generic.c
+
+COREGRIND_DARWIN_BUILT_SOURCES = \
+	m_mach/mach_vmUser.c \
+	m_mach/taskUser.c \
+	m_mach/thread_actUser.c \
+	m_mach/vm_mapUser.c
+
 libcoregrind_x86_linux_a_SOURCES = \
 	$(COREGRIND_SOURCES_COMMON) \
 	$(COREGRIND_LINUX_SOURCE) \
@@ -338,6 +434,37 @@
 libcoregrind_ppc64_aix5_a_CCASFLAGS = $(AM_CCASFLAGS_PPC64_AIX5)
 libcoregrind_ppc64_aix5_a_AR = $(AR) -X64 cru
 
+libcoregrind_x86_darwin_a_SOURCES = \
+	$(COREGRIND_SOURCES_COMMON) \
+	$(COREGRIND_DARWIN_SOURCE) \
+	m_coredump/coredump-x86-darwin.c \
+	m_dispatch/dispatch-x86-darwin.S \
+	m_mach/mach_traps-x86-darwin.S \
+	m_sigframe/sigframe-x86-darwin.c \
+	m_start-x86-darwin.S \
+	m_syswrap/syscall-x86-darwin.S \
+	m_syswrap/syswrap-x86-darwin.c
+nodist_libcoregrind_x86_darwin_a_SOURCES = $(COREGRIND_DARWIN_BUILT_SOURCES)
+libcoregrind_x86_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+libcoregrind_x86_darwin_a_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+libcoregrind_x86_darwin_a_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+
+
+libcoregrind_amd64_darwin_a_SOURCES = \
+	$(COREGRIND_SOURCES_COMMON) \
+	$(COREGRIND_DARWIN_SOURCE) \
+	m_coredump/coredump-amd64-darwin.c \
+	m_dispatch/dispatch-amd64-darwin.S \
+	m_mach/mach_traps-amd64-darwin.S \
+	m_sigframe/sigframe-amd64-darwin.c \
+	m_start-amd64-darwin.S \
+	m_syswrap/syscall-amd64-darwin.S \
+	m_syswrap/syswrap-amd64-darwin.c
+nodist_libcoregrind_amd64_darwin_a_SOURCES = $(COREGRIND_DARWIN_BUILT_SOURCES)
+libcoregrind_amd64_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+libcoregrind_amd64_darwin_a_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+libcoregrind_amd64_darwin_a_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+
 
 libreplacemalloc_toolpreload_x86_linux_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
 libreplacemalloc_toolpreload_x86_linux_a_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
@@ -365,18 +492,30 @@
 libreplacemalloc_toolpreload_ppc64_aix5_a_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC)
 libreplacemalloc_toolpreload_ppc64_aix5_a_AR = $(AR) -X64 cru
 
+libreplacemalloc_toolpreload_x86_darwin_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_x86_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+libreplacemalloc_toolpreload_x86_darwin_a_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+
+libreplacemalloc_toolpreload_amd64_darwin_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_amd64_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+libreplacemalloc_toolpreload_amd64_darwin_a_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+
 m_dispatch/dispatch-x86-linux.S:	 libvex_guest_offsets.h
 m_dispatch/dispatch-amd64-linux.S:	 libvex_guest_offsets.h
 m_dispatch/dispatch-ppc32-linux.S:	 libvex_guest_offsets.h
 m_dispatch/dispatch-ppc64-linux.S:	 libvex_guest_offsets.h
 m_dispatch/dispatch-ppc32-aix5.S:	 libvex_guest_offsets.h
 m_dispatch/dispatch-ppc64-aix5.S:	 libvex_guest_offsets.h
+m_dispatch/dispatch-x86-darwin.S:	 libvex_guest_offsets.h
+m_dispatch/dispatch-amd64-darwin.S:	 libvex_guest_offsets.h
 m_syswrap/syscall-x86-linux.S:		 libvex_guest_offsets.h
 m_syswrap/syscall-amd64-linux.S:	 libvex_guest_offsets.h
 m_syswrap/syscall-ppc32-linux.S:	 libvex_guest_offsets.h
 m_syswrap/syscall-ppc64-linux.S:	 libvex_guest_offsets.h
 m_syswrap/syscall-ppc32-aix5.S:		 libvex_guest_offsets.h
 m_syswrap/syscall-ppc64-aix5.S:		 libvex_guest_offsets.h
+m_syswrap/syscall-x86-darwin.S:		 libvex_guest_offsets.h
+m_syswrap/syscall-amd64-darwin.S:	 libvex_guest_offsets.h
 m_syswrap/syswrap-main.c: 		 libvex_guest_offsets.h
 
 libvex_guest_offsets.h:
@@ -414,14 +553,25 @@
 vgpreload_core_ppc64_aix5_so_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC)
 vgpreload_core_ppc64_aix5_so_LDFLAGS = $(PRELOAD_LDFLAGS_PPC64_AIX5)
 
-all-local: inplace-noinst_PROGRAMS
+vgpreload_core_x86_darwin_so_SOURCES = $(VGPRELOAD_CORE_SOURCES_COMMON)
+vgpreload_core_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_core_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_core_x86_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_X86_DARWIN)
 
-clean-local:
+vgpreload_core_amd64_darwin_so_SOURCES = $(VGPRELOAD_CORE_SOURCES_COMMON)
+vgpreload_core_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_core_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_core_amd64_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_AMD64_DARWIN)
+
+all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
+
+clean-local: clean-noinst_DSYMS
 	$(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" clean
+	rm -f $(mach_srcs) $(mach_server_srcs) $(mach_hdrs)
 
 # Nb: The loop installs the libvex library for possible use by standalone
 # tools.
-install-exec-local: install-noinst_PROGRAMS
+install-exec-local: install-noinst_PROGRAMS install-noinst_DSYMS
 	for v in $(LIBVEX) ; do \
 	  $(INSTALL_DATA) @VEX_DIR@/$$v $(DESTDIR)$(valdir) ; \
 	done
diff --git a/coregrind/launcher-darwin.c b/coregrind/launcher-darwin.c
new file mode 100644
index 0000000..a470cf1
--- /dev/null
+++ b/coregrind/launcher-darwin.c
@@ -0,0 +1,421 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Launching valgrind                         launcher-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2007 Julian Seward 
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Note: this is a "normal" program and not part of Valgrind proper,
+   and so it doesn't have to conform to Valgrind's arcane rules on
+   no-glibc-usage etc. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <unistd.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "pub_core_debuglog.h"
+#include "pub_core_vki.h"       // Avoids warnings from
+                                // pub_core_libcfile.h
+#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
+#include "pub_core_ume.h"
+
+static struct {
+   cpu_type_t cputype;
+   const char *apple_name;     // e.g. x86_64
+   const char *valgrind_name;  // e.g. amd64
+} valid_archs[] = {
+   { CPU_TYPE_X86, "i386", "x86" }, 
+   { CPU_TYPE_X86_64, "x86_64", "amd64" }, 
+   { CPU_TYPE_ARM, "arm", "arm" }, 
+   { CPU_TYPE_POWERPC, "ppc", "ppc32" }, 
+   { CPU_TYPE_POWERPC64, "ppc64", "ppc64" }, 
+};
+static int valid_archs_count = sizeof(valid_archs)/sizeof(valid_archs[0]);
+
+static const char *name_for_cputype(cpu_type_t cputype)
+{
+   int i;
+   for (i = 0; i < valid_archs_count; i++) {
+      if (valid_archs[i].cputype == cputype) {
+         return valid_archs[i].valgrind_name;
+      }
+   }
+   return NULL;
+}
+
+/* Report fatal errors */
+__attribute__((noreturn))
+static void barf ( const char *format, ... )
+{
+   va_list vargs;
+
+   va_start(vargs, format);
+   fprintf(stderr, "valgrind: ");
+   vfprintf(stderr, format, vargs);
+   fprintf(stderr, "\n");
+   va_end(vargs);
+
+   exit(1);
+   /*NOTREACHED*/
+   assert(0);
+}
+
+/* Search the path for the client program */
+static const char *find_client(const char *clientname)
+{
+   static char fullname[PATH_MAX];
+   const char *path = getenv("PATH");
+   const char *colon;
+
+   while (path)
+   {
+      if ((colon = strchr(path, ':')) == NULL)
+      {
+         strcpy(fullname, path);
+         path = NULL;
+      }
+      else
+      {
+         memcpy(fullname, path, colon - path);
+         fullname[colon - path] = '\0';
+         path = colon + 1;
+      }
+
+      strcat(fullname, "/");
+      strcat(fullname, clientname);
+
+      if (access(fullname, R_OK|X_OK) == 0)
+         return fullname;
+   }
+
+   return clientname;
+}
+
+static int fat_has_cputype(struct fat_header *fh, cpu_type_t cputype)
+{
+   struct fat_arch *fa = (struct fat_arch *)(fh+1);
+   uint32_t nfat_arch = ntohl(fh->nfat_arch);
+   uint32_t i;
+   for (i = 0; i < nfat_arch; i++) {
+      if (ntohl(fa[i].cputype) == cputype) return 1;
+   }
+   return 0;
+}
+
+/* Examine the client and work out which arch it is for */
+static const char *select_arch(const char *clientname, cpu_type_t default_cputype, const char *default_arch)
+{
+   uint8_t buf[4096];
+   ssize_t bytes;
+   int fd = open(find_client(clientname), O_RDONLY);
+   if (fd < 0) {
+      barf("%s: %s", clientname, strerror(errno));
+   }
+
+   bytes = pread(fd, buf, sizeof(buf), 0);
+   if (bytes != sizeof(buf)) {
+      close(fd);
+      return NULL;
+   }
+   
+   // If it's thin, return that arch.
+   {
+      struct mach_header *mh = (struct mach_header *)buf;
+      if (mh->magic == MH_MAGIC  ||  mh->magic == MH_MAGIC_64) {
+         return name_for_cputype(mh->cputype);
+      } else if (mh->magic == MH_CIGAM  ||  mh->magic == MH_CIGAM_64) {
+         return name_for_cputype(OSSwapInt32(mh->cputype));
+      }
+   }
+
+   // If it's fat, look for a good arch.
+   {
+      struct fat_header *fh = (struct fat_header *)buf;
+      if (ntohl(fh->magic) == FAT_MAGIC) {
+         uint32_t nfat_arch = ntohl(fh->nfat_arch);
+         int i;
+         // If only one fat arch, use it.
+         if (nfat_arch == 1) {
+            struct fat_arch *fa = (struct fat_arch *)(fh+1);
+            return name_for_cputype(ntohl(fa->cputype));
+         }
+         // Scan fat headers for default arch.
+         if (fat_has_cputype(fh, default_cputype)) {
+            return default_arch;
+         }
+         
+         // Scan fat headers for any supported arch.
+         for (i = 0; i < valid_archs_count; i++) {
+            if (fat_has_cputype(fh, valid_archs[i].cputype)) {
+               return valid_archs[i].valgrind_name;
+            }
+         }
+      }
+   }
+   
+   return NULL;
+}
+
+
+/* Where we expect to find all our aux files */
+static const char *valgrind_lib;
+
+int main(int argc, char** argv, char** envp)
+{
+   int i, j, loglevel;
+   const char *toolname = NULL;
+   const char *clientname = NULL;
+   int clientname_arg = 0;
+   const char *archname = NULL;
+   const char *arch;
+   const char *default_arch;
+   cpu_type_t default_cputype;
+   char *toolfile;
+   char launcher_name[PATH_MAX+1];
+   char* new_line;
+   char* set_cwd;
+   char* cwd;
+   char** new_env;
+   char **new_argv;
+   int new_argc;
+
+   /* Start the debugging-log system ASAP.  First find out how many 
+      "-d"s were specified.  This is a pre-scan of the command line.
+      At the same time, look for the tool name. */
+   loglevel = 0;
+   for (i = 1; i < argc; i++) {
+      if (argv[i][0] != '-') {
+         clientname = argv[i];
+         clientname_arg = i;
+         break;
+      }
+      if (0 == strcmp(argv[i], "--")) {
+         if (i+1 < argc) {
+            clientname = argv[i+1];
+            clientname_arg = i;
+         }
+         break;
+      }
+      if (0 == strcmp(argv[i], "-d")) 
+         loglevel++;
+      if (0 == strncmp(argv[i], "--tool=", 7)) 
+         toolname = argv[i] + 7;
+      if (0 == strncmp(argv[i], "--arch=", 7))
+         archname = argv[i] + 7;
+   }
+
+   /* ... and start the debug logger.  Now we can safely emit logging
+      messages all through startup. */
+   VG_(debugLog_startup)(loglevel, "Stage 1");
+
+   /* Make sure we know which tool we're using */
+   if (toolname) {
+      VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
+   } else {
+      VG_(debugLog)(1, "launcher", 
+                       "no tool requested, defaulting to 'memcheck'\n");
+      toolname = "memcheck";
+   }
+
+   /* Find the real executable if clientname is an app bundle. */
+   if (clientname) {
+      struct stat st;
+      if (0 == stat(clientname, &st)  &&  (st.st_mode & S_IFDIR)) {
+         char *copy = strdup(clientname);
+         char *appname = basename(copy);
+         char *dot = strrchr(appname, '.');
+         if (dot) {
+            char *newclient;
+            *dot = '\0';
+            asprintf(&newclient, "%s/Contents/MacOS/%s", clientname, appname);
+            VG_(debugLog)(1, "launcher", "Using executable in app bundle: %s\n", newclient);
+            clientname = newclient;
+            argv[clientname_arg] = newclient;
+         }
+         free(copy);
+      }
+   }
+
+   /* Establish the correct VALGRIND_LIB. */
+   {  const char *cp;
+      cp = getenv(VALGRIND_LIB);
+      valgrind_lib = ( cp == NULL ? VG_LIBDIR : cp );
+   }
+
+   /* Find installed architectures. Use vgpreload_core-<platform>.so as the
+    * indicator of whether the platform is installed. */
+   for (i = 0; i < valid_archs_count; i++) {
+      char *vgpreload_core;
+      asprintf(&vgpreload_core, "%s/vgpreload_core-%s-darwin.so", valgrind_lib, valid_archs[i].valgrind_name);
+      if (access(vgpreload_core, R_OK|X_OK) != 0) {
+         VG_(debugLog)(1, "launcher", "arch '%s' IS NOT installed\n", valid_archs[i].valgrind_name);
+         bzero(&valid_archs[i], sizeof(valid_archs[i]));
+      } else {
+         VG_(debugLog)(1, "launcher", "arch '%s' IS installed\n", valid_archs[i].valgrind_name);
+      }
+      free(vgpreload_core);
+   }
+
+   /* Find the "default" arch (VGCONF_ARCH_PRI from configure). 
+      This is the preferred arch from fat files and the fallback. */
+   default_arch = NULL;
+   default_cputype = 0;
+   for (i = 0; i < valid_archs_count; i++) {
+      if (!valid_archs[i].cputype) continue;
+      if (0 == strncmp(VG_PLATFORM, valid_archs[i].valgrind_name, 
+                       strlen(valid_archs[i].valgrind_name))) 
+      {
+         default_arch = valid_archs[i].valgrind_name;
+         default_cputype = valid_archs[i].cputype;
+         break;
+      }
+   }
+   if (i == valid_archs_count) barf("Unknown/uninstalled VG_PLATFORM '%s'", VG_PLATFORM);
+   assert(NULL != default_arch);
+   assert(0 != default_cputype);
+
+   /* Work out what arch to use, or use the default arch if not possible. */
+   if (archname != NULL) {
+      // --arch from command line
+      arch = NULL;
+      for (i = 0; i < valid_archs_count; i++) {
+         if (0 == strcmp(archname, valid_archs[i].apple_name)  ||  
+             0 == strcmp(archname, valid_archs[i].valgrind_name))
+         {
+            arch = valid_archs[i].valgrind_name;
+            break;
+         }
+      }
+      if (i == valid_archs_count) barf("Unknown --arch '%s'", archname);
+      assert(NULL != arch);
+      VG_(debugLog)(1, "launcher", "using arch '%s' from --arch=%s\n", 
+                    arch, archname);
+   } 
+   else if (clientname == NULL) {
+      // no client executable; use default as fallback
+      VG_(debugLog)(1, "launcher", 
+                       "no client specified, defaulting arch to '%s'\n",
+                        default_arch);
+      arch = default_arch;
+   } 
+   else if ((arch = select_arch(clientname, default_cputype,default_arch))) {
+      // arch from client executable
+      VG_(debugLog)(1, "launcher", "selected arch '%s'\n", arch);
+   } 
+   else {
+      // nothing found in client executable; use default as fallback
+      VG_(debugLog)(1, "launcher", 
+                       "no arch detected, defaulting arch to '%s'\n",
+                       default_arch);
+      arch = default_arch;
+   }
+   
+   cwd = getcwd(NULL, 0);
+   if (!cwd) barf("Current directory no longer exists.");
+
+   /* Figure out the name of this executable (viz, the launcher), so
+      we can tell stage2.  stage2 will use the name for recursive
+      invokations of valgrind on child processes. */
+   memset(launcher_name, 0, PATH_MAX+1);
+   for (i = 0; envp[i]; i++) 
+       ; /* executable path is after last envp item */
+   /* envp[i] == NULL ; envp[i+1] == executable_path */
+   if (envp[i+1][0] != '/') {
+      strcpy(launcher_name, cwd);
+      strcat(launcher_name, "/");
+   }
+   if (strlen(launcher_name) + strlen(envp[i+1]) > PATH_MAX)
+      barf("launcher path is too long");
+   strcat(launcher_name, envp[i+1]);
+   VG_(debugLog)(1, "launcher", "launcher_name = %s\n", launcher_name);
+
+   /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
+   asprintf(&new_line, VALGRIND_LAUNCHER "=%s", launcher_name);
+
+   /* tediously augment the env: VALGRIND_STARTUP_PWD_%PID_XYZZY=current_working_dir */
+   asprintf(&set_cwd, "VALGRIND_STARTUP_PWD_%u_XYZZY=%s", getppid(), cwd);
+
+   // Note that Apple binaries get a secret fourth arg, "char* apple", which
+   // contains the executable path.  Don't forget about it.
+   for (j = 0; envp[j]; j++)
+      ;
+   new_env = malloc((j+4) * sizeof(char*));
+   if (new_env == NULL)
+      barf("malloc of new_env failed.");
+   for (i = 0; i < j; i++)
+      new_env[i] = envp[i];
+   new_env[i++] = new_line;
+   new_env[i++] = set_cwd;
+   new_env[i++] = NULL;
+   new_env[i  ] = envp[i-2]; // the 'apple' arg == the executable_path
+   assert(i == j+3);
+
+   /* tediously edit env: hide dyld options from valgrind's captive dyld */
+   for (i = 0; envp[i]; i++) {
+      if (0 == strncmp(envp[i], "DYLD_", 5)) {
+         envp[i][0] = 'V';  /* VYLD_; changed back by initimg-darwin */
+      }
+   }
+
+   /* tediously edit argv: remove --arch= */
+   new_argv = malloc((1+argc) * sizeof(char *));
+   for (i = 0, new_argc = 0; i < argc; i++) {
+      if (0 == strncmp(argv[i], "--arch=", 7)) {
+         // skip
+      } else {
+         new_argv[new_argc++] = argv[i];
+      }
+   }
+   new_argv[new_argc++] = NULL;
+
+   /* Build the stage2 invokation, and execve it.  Bye! */
+   asprintf(&toolfile, "%s/%s-%s-darwin", valgrind_lib, toolname, arch);
+   if (access(toolfile, R_OK|X_OK) != 0) {
+      barf("tool '%s' not installed (%s) (%s)", toolname, toolfile, strerror(errno));
+   }
+
+   VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
+
+   execve(toolfile, new_argv, new_env);
+
+   fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s-darwin': %s\n",
+                   toolname, arch, strerror(errno));
+
+   exit(1);
+}
diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c
index 62c21da..b8a7dd8 100644
--- a/coregrind/m_aspacemgr/aspacemgr-common.c
+++ b/coregrind/m_aspacemgr/aspacemgr-common.c
@@ -160,6 +160,18 @@
         || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, 
                          prot, flags, fd, offset);
+#  elif defined(VGP_x86_darwin)
+   if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
+       fd = -1;  // MAP_ANON with fd==0 is EINVAL
+   }
+   res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length,
+                          prot, flags, fd, offset & 0xffffffff, offset >> 32);
+#  elif defined(VGP_amd64_darwin)
+   if (fd == 0  &&  (flags & VKI_MAP_ANONYMOUS)) {
+       fd = -1;  // MAP_ANON with fd==0 is EINVAL
+   }
+   res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
+                          prot, flags, (UInt)fd, offset);
 #  else
 #    error Unknown platform
 #  endif
@@ -177,6 +189,9 @@
    return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
 }
 
+#if HAVE_MREMAP
+/* The following are used only to implement mremap(). */
+
 SysRes ML_(am_do_extend_mapping_NO_NOTIFY)( 
           Addr  old_addr, 
           SizeT old_len,
@@ -227,6 +242,8 @@
 #  endif
 }
 
+#endif
+
 /* --- Pertaining to files --- */
 
 SysRes ML_(am_open) ( const Char* pathname, Int flags, Int mode )
@@ -257,6 +274,8 @@
 {
 #  if defined(VGO_linux) || defined(VGO_aix5)
    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);
 #  else
 #  error "Unknown OS"
 #  endif
@@ -310,6 +329,17 @@
    I_die_here; /* maybe just return False? */
    return False;
 
+#elif defined(VGO_darwin)
+   HChar tmp[VKI_MAXPATHLEN+1];
+   if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
+      if (nbuf > 0) {
+         VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
+         buf[nbuf-1] = 0;
+      }
+      if (tmp[0] == '/') return True;
+   }
+   return False;
+
 #  else
 #     error Unknown OS
 #  endif
diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c
index 4f09b67..0af3bb5 100644
--- a/coregrind/m_aspacemgr/aspacemgr-linux.c
+++ b/coregrind/m_aspacemgr/aspacemgr-linux.c
@@ -3,7 +3,7 @@
 /*--- The address space manager: segment initialisation and        ---*/
 /*--- tracking, stack operations                                   ---*/
 /*---                                                              ---*/
-/*--- Implementation for Linux                 m_aspacemgr-linux.c ---*/
+/*--- Implementation for Linux (and Darwin!)   m_aspacemgr-linux.c ---*/
 /*--------------------------------------------------------------------*/
 
 /*
@@ -848,9 +848,11 @@
    /* If a problem has already been detected, don't continue comparing
       segments, so as to avoid flooding the output with error
       messages. */
+#if !defined(VGO_darwin)
+   /* GrP fixme not */
    if (!sync_check_ok)
       return;
-
+#endif
    if (len == 0)
       return;
 
@@ -911,7 +913,7 @@
          = nsegments[i].dev != 0 || nsegments[i].ino != 0;
 
       /* Consider other reasons to not compare dev/inode */
-
+#if defined(VGO_linux)
       /* bproc does some godawful hack on /dev/zero at process
          migration, which changes the name of it, and its dev & ino */
       if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
@@ -920,7 +922,16 @@
       /* hack apparently needed on MontaVista Linux */
       if (filename && VG_(strstr)(filename, "/.lib-ro/"))
          cmp_devino = False;
+#endif
 
+#if defined(VGO_darwin)
+      // GrP fixme kernel info doesn't have dev/inode
+      cmp_devino = False;
+      
+      // GrP fixme V and kernel don't agree on offsets
+      cmp_offsets = False;
+#endif
+      
       /* If we are doing sloppy execute permission checks then we
          allow segment to have X permission when we weren't expecting
          it (but not vice versa) so if the kernel reported execute
@@ -971,9 +982,11 @@
    /* If a problem has already been detected, don't continue comparing
       segments, so as to avoid flooding the output with error
       messages. */
+#if !defined(VGO_darwin)
+   /* GrP fixme not */
    if (!sync_check_ok)
       return;
-
+#endif 
    if (len == 0)
       return;
 
@@ -1517,6 +1530,11 @@
    seg.kind = SkAnonV;
    if (dev != 0 && ino != 0) 
       seg.kind = SkFileV;
+#if defined(VGO_darwin)
+   // GrP fixme no dev/ino on darwin
+   if (offset != 0) 
+       seg.kind = SkFileV;
+#endif
    if (filename)
       seg.fnIdx = allocate_segname( filename );
 
@@ -1558,6 +1576,27 @@
    nsegments[0]    = seg;
    nsegments_used  = 1;
 
+#if defined(VGO_darwin)
+
+# if VG_WORDSIZE == 4
+   aspacem_minAddr = (Addr) 0x00001000;
+   aspacem_maxAddr = (Addr) 0xffffffff;
+
+   aspacem_cStart = aspacem_minAddr;
+   aspacem_vStart = 0xf0000000;  // 0xc0000000..0xf0000000 available
+# else
+   aspacem_minAddr = (Addr) 0x100000000;  // 4GB page zero
+   aspacem_maxAddr = (Addr) 0x7fffffffffff;
+
+   aspacem_cStart = aspacem_minAddr;
+   aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
+   // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
+# endif
+
+   suggested_clstack_top = -1; // ignored; Mach-O specifies its stack
+
+#else
+
    /* Establish address limits and block out unusable parts
       accordingly. */
 
@@ -1588,6 +1627,8 @@
    suggested_clstack_top = aspacem_maxAddr - 16*1024*1024ULL
                                            + VKI_PAGE_SIZE;
 
+#endif
+
    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
    aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
@@ -2090,6 +2131,12 @@
 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);
+}
+
+SysRes VG_(am_mmap_named_file_fixed_client)
+     ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
+{
    SysRes     sres;
    NSegment   seg;
    Addr       advised;
@@ -2116,6 +2163,7 @@
    /* We have been advised that the mapping is allowable at the
       specified address.  So hand it off to the kernel, and propagate
       any resulting failure immediately. */
+   // 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, 
@@ -2146,7 +2194,9 @@
       seg.ino = ino;
       seg.mode = mode;
    }
-   if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
+   if (name) {
+      seg.fnIdx = allocate_segname( name );
+   } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
       seg.fnIdx = allocate_segname( buf );
    }
    add_segment( &seg );
@@ -2182,6 +2232,7 @@
    /* We have been advised that the mapping is allowable at the
       specified address.  So hand it off to the kernel, and propagate
       any resulting failure immediately. */
+   // 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|VKI_MAP_ANONYMOUS, 
@@ -2239,6 +2290,7 @@
    /* We have been advised that the mapping is allowable at the
       advised address.  So hand it off to the kernel, and propagate
       any resulting failure immediately. */
+   // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
    sres = VG_(am_do_mmap_NO_NOTIFY)( 
              advised, length, prot, 
              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
@@ -2309,18 +2361,41 @@
    if (!ok)
       return VG_(mk_SysRes_Error)( VKI_EINVAL );
 
+// On Darwin, for anonymous maps you can pass in a tag which is used by
+// programs like vmmap for statistical purposes.
+#ifndef VM_TAG_VALGRIND
+#  define VM_TAG_VALGRIND 0
+#endif
+
    /* We have been advised that the mapping is allowable at the
       specified address.  So hand it off to the kernel, and propagate
       any resulting failure immediately. */
+   /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in 
+      another thread can pre-empt our spot.  [At one point on the DARWIN
+      branch the VKI_MAP_FIXED was commented out;  unclear if this is
+      necessary or not given the second Darwin-only call that immediately
+      follows if this one fails.  --njn] */
    sres = VG_(am_do_mmap_NO_NOTIFY)( 
              advised, length, 
              VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 
              VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
-             0, 0 
+             VM_TAG_VALGRIND, 0
           );
+#if defined(VGO_darwin)
+   if (sr_isError(sres)) {
+       /* try again, ignoring the advisory */
+       sres = VG_(am_do_mmap_NO_NOTIFY)( 
+             0, length, 
+             VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC, 
+             /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, 
+             VM_TAG_VALGRIND, 0
+          );
+   }
+#endif
    if (sr_isError(sres))
       return sres;
 
+#if defined(VGO_linux)
    if (sr_Res(sres) != advised) {
       /* I don't think this can happen.  It means the kernel made a
          fixed map succeed but not at the requested location.  Try to
@@ -2328,6 +2403,7 @@
       (void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
       return VG_(mk_SysRes_Error)( VKI_EINVAL );
    }
+#endif
 
    /* Ok, the mapping succeeded.  Now notify the interval map. */
    init_nsegment( &seg );
@@ -2687,6 +2763,7 @@
         return False;
         
       /* Extend the kernel's mapping. */
+      // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
       sres = VG_(am_do_mmap_NO_NOTIFY)( 
                 nsegments[segR].start, delta,
                 prot,
@@ -2722,6 +2799,7 @@
         return False;
         
       /* Extend the kernel's mapping. */
+      // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
       sres = VG_(am_do_mmap_NO_NOTIFY)( 
                 nsegments[segA].start-delta, delta,
                 prot,
@@ -2750,6 +2828,8 @@
 
 /* --- --- --- resizing/move a mapping --- --- --- */
 
+#if HAVE_MREMAP
+
 /* Let SEG be a client mapping (anonymous or file).  This fn extends
    the mapping forwards only by DELTA bytes, and trashes whatever was
    in the new area.  Fails if SEG is not a single client mapping or if
@@ -2894,6 +2974,10 @@
    return True;
 }
 
+#endif // HAVE_MREMAP
+
+
+#if HAVE_PROC
 
 /*-----------------------------------------------------------------*/
 /*---                                                           ---*/
@@ -3192,6 +3276,202 @@
       (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
 }
 
+#elif defined(VGO_darwin)
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+
+static unsigned int mach2vki(unsigned int vm_prot)
+{
+   return
+      ((vm_prot & VM_PROT_READ)    ? VKI_PROT_READ    : 0) |
+      ((vm_prot & VM_PROT_WRITE)   ? VKI_PROT_WRITE   : 0) |
+      ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC    : 0) ;
+}
+
+static UInt stats_machcalls = 0;
+
+static void parse_procselfmaps (
+      void (*record_mapping)( Addr addr, SizeT len, UInt prot,
+                              ULong dev, ULong ino, Off64T offset, 
+                              const UChar* filename ),
+      void (*record_gap)( Addr addr, SizeT len )
+   )
+{
+   vm_address_t iter;
+   unsigned int depth;
+   vm_address_t last;
+
+   iter = 0;
+   depth = 0;
+   last = 0;
+   while (1) {
+      mach_vm_address_t addr = iter;
+      mach_vm_size_t size;
+      vm_region_submap_short_info_data_64_t info;
+      kern_return_t kr;
+
+      while (1) {
+         mach_msg_type_number_t info_count
+            = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
+         stats_machcalls++;
+         kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
+                                     (vm_region_info_t)&info, &info_count);
+         if (kr) 
+            return;
+         if (info.is_submap) {
+            depth++;
+            continue;
+         }
+         break;
+      }
+      iter = addr + size;
+
+      if (addr > last  &&  record_gap) {
+         (*record_gap)(last, addr - last);
+      }
+      if (record_mapping) {
+         (*record_mapping)(addr, size, mach2vki(info.protection),
+                           0, 0, info.offset, NULL);
+      }
+      last = addr + size;
+   }
+
+   if ((Addr)-1 > last  &&  record_gap)
+      (*record_gap)(last, (Addr)-1 - last);
+}
+
+ChangedSeg* css_local;
+Int         css_size_local;
+Int         css_used_local;
+
+static void add_mapping_callback(Addr addr, SizeT len, UInt prot, 
+                                 ULong dev, ULong ino, Off64T offset, 
+                                 const UChar *filename)
+{
+   // derived from sync_check_mapping_callback()
+
+   Int iLo, iHi, i;
+
+   if (len == 0) return;
+
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
+
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
+
+
+   /* NSegments iLo .. iHi inclusive should agree with the presented
+      data. */
+   for (i = iLo; i <= iHi; i++) {
+
+      UInt seg_prot;
+
+      if (nsegments[i].kind == SkAnonV  ||  nsegments[i].kind == SkFileV) {
+         /* Ignore V regions */
+         continue;
+      } 
+      else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
+          /* Add mapping for SkResvn regions */
+         ChangedSeg* cs = &css_local[css_used_local];
+         aspacem_assert(css_used_local < css_size_local);
+         cs->is_added = True;
+         cs->start    = addr;
+         cs->end      = addr + len - 1;
+         cs->prot     = prot;
+         cs->offset   = offset;
+         css_used_local++;
+         return;
+
+      } else if (nsegments[i].kind == SkAnonC ||
+                 nsegments[i].kind == SkFileC ||
+                 nsegments[i].kind == SkShmC)
+      {
+         /* Check permissions on client regions */
+         // GrP fixme
+         seg_prot = 0;
+         if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
+         if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
+#        if defined(VGA_x86)
+         // GrP fixme sloppyXcheck 
+         // darwin: kernel X ignored and spuriously changes? (vm_copy)
+         seg_prot |= (prot & VKI_PROT_EXEC);
+#        else
+         if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
+#        endif
+         if (seg_prot != prot) {
+             if (VG_(clo_trace_syscalls)) 
+                 VG_(debugLog)(0,"aspacem","\nregion %p..%p permission "
+                                 "mismatch (kernel %x, V %x)", 
+                                 (void*)nsegments[i].start,
+                                 (void*)(nsegments[i].end+1), prot, seg_prot);
+         }
+
+      } else {
+         aspacem_assert(0);
+      }
+   }
+}
+
+static void remove_mapping_callback(Addr addr, SizeT len)
+{
+   // derived from sync_check_gap_callback()
+
+   Int iLo, iHi, i;
+
+   if (len == 0)
+      return;
+
+   /* The kernel should not give us wraparounds. */
+   aspacem_assert(addr <= addr + len - 1); 
+
+   iLo = find_nsegment_idx( addr );
+   iHi = find_nsegment_idx( addr + len - 1 );
+
+   /* NSegments iLo .. iHi inclusive should agree with the presented data. */
+   for (i = iLo; i <= iHi; i++) {
+      if (nsegments[i].kind != SkFree  &&  nsegments[i].kind != SkResvn) {
+         // V has a mapping, kernel doesn't
+         ChangedSeg* cs = &css_local[css_used_local];
+         aspacem_assert(css_used_local < css_size_local);
+         cs->is_added = True;
+         cs->is_added = False;
+         cs->start    = nsegments[i].start;
+         cs->end      = nsegments[i].end;
+         cs->prot     = 0;
+         cs->offset   = 0;
+         css_used_local++;
+         return;
+      }
+   }
+}
+
+
+void VG_(get_changed_segments)(
+      const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
+      Int css_size, /*OUT*/Int* css_used)
+{
+   static UInt stats_synccalls = 1;
+   aspacem_assert(when && where);
+
+   if (0)
+      VG_(debugLog)(0,"aspacem",
+         "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
+         stats_synccalls++, stats_machcalls, when, where
+      );
+
+   css_local = css;
+   css_size_local = css_size;
+   css_used_local = 0;
+
+   // Get the list of segs that need to be added/removed.
+   parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
+
+   *css_used = css_used_local;
+}
+
+#endif
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_coredump/coredump-amd64-darwin.c b/coregrind/m_coredump/coredump-amd64-darwin.c
new file mode 100644
index 0000000..6b18f32
--- /dev/null
+++ b/coregrind/m_coredump/coredump-amd64-darwin.c
@@ -0,0 +1,39 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Dumping core.                        coredump-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+ 
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_coredump.h"
+#include "pub_core_threadstate.h"
+
+void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
+{
+   // DDD: #warning GrP fixme coredump
+}
diff --git a/coregrind/m_coredump/coredump-x86-darwin.c b/coregrind/m_coredump/coredump-x86-darwin.c
new file mode 100644
index 0000000..3618113
--- /dev/null
+++ b/coregrind/m_coredump/coredump-x86-darwin.c
@@ -0,0 +1,39 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Dumping core.                          coredump-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+ 
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_coredump.h"
+#include "pub_core_threadstate.h"
+
+void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
+{
+   // DDD: #warning GrP fixme coredump
+}
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index de28e36..1bc9fe5 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -211,6 +211,12 @@
 #elif defined(VGP_ppc64_aix5)
    I_die_here;
 
+#elif defined(VGP_x86_darwin)
+   I_die_here;
+
+#elif defined(VGP_amd64_darwin)
+   I_die_here;
+
 #else
 #  error Unknown arch
 #endif
diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c
index f561c4c..055f814 100644
--- a/coregrind/m_debuginfo/d3basics.c
+++ b/coregrind/m_debuginfo/d3basics.c
@@ -379,10 +379,10 @@
 static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, RegSummary* regs )
 {
    vg_assert(regs);
-#  if defined(VGP_x86_linux)
+#  if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
    if (regno == 5/*EBP*/) { *a = regs->fp; return True; }
    if (regno == 4/*ESP*/) { *a = regs->sp; return True; }
-#  elif defined(VGP_amd64_linux)
+#  elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
    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 d9d9217..4ec85c8 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -51,6 +51,7 @@
 #include "pub_core_xarray.h"
 #include "pub_core_oset.h"
 #include "pub_core_stacktrace.h" // VG_(get_StackTrace) XXX: circular dependency
+#include "pub_core_ume.h"
 
 #include "priv_misc.h"           /* dinfo_zalloc/free */
 #include "priv_d3basics.h"       /* ML_(pp_GX) */
@@ -67,6 +68,9 @@
 # include "pub_core_libcproc.h"
 # include "pub_core_libcfile.h"
 # include "priv_readxcoff.h"
+#elif defined(VGO_darwin)
+# include "priv_readmacho.h"
+# include "priv_readpdb.h"
 #endif
 
 
@@ -576,7 +580,7 @@
 /*---                                                        ---*/
 /*--------------------------------------------------------------*/
 
-#if defined(VGO_linux)
+#if defined(VGO_linux)  ||  defined(VGO_darwin)
 
 /* The debug info system is driven by notifications that a text
    segment has been mapped in, or unmapped.  When that happens it
@@ -703,11 +707,10 @@
    */
    is_rx_map = False;
    is_rw_map = False;
-#  if defined(VGP_x86_linux)
+#  if defined(VGA_x86)
    is_rx_map = seg->hasR && seg->hasX;
    is_rw_map = seg->hasR && seg->hasW;
-#  elif defined(VGP_amd64_linux) \
-        || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+#  elif defined(VGA_amd64) || defined(VGA_ppc32) || defined(VGA_ppc64)
    is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
    is_rw_map = seg->hasR && seg->hasW && !seg->hasX;
 #  else
@@ -750,8 +753,15 @@
    vg_assert(nread > 0 && nread <= sizeof(buf1k) );
 
    /* We're only interested in mappings of ELF object files. */
+#if defined(HAVE_ELF)
    if (!ML_(is_elf_object_file)( buf1k, (SizeT)nread ))
       return 0;
+#elif defined(HAVE_MACHO)
+   if (!ML_(is_macho_object_file)( buf1k, (SizeT)nread ))
+      return 0;
+#else
+#  error "unknown executable type"
+#endif
 
    /* See if we have a DebugInfo for this filename.  If not,
       create one. */
@@ -803,7 +813,13 @@
    discard_DebugInfos_which_overlap_with( di );
 
    /* .. and acquire new info. */
+#if defined(HAVE_ELF)
    ok = ML_(read_elf_debug_info)( di );
+#elif defined(HAVE_MACHO)
+   ok = ML_(read_macho_debug_info)( di );
+#else
+#  error "unknown executable type"
+#endif
 
    if (ok) {
 
@@ -863,7 +879,7 @@
 void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
 {
    Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
-#  if defined(VGP_x86_linux)
+#  if defined(VGA_x86)
    exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
 #  endif
    if (0 && !exe_ok) {
@@ -1383,6 +1399,9 @@
        VG_STREQ("generic_start_main", name) ||  // Yellow Dog doggedness
 #elif defined(VGO_aix5)
        VG_STREQ("__start", name)            ||  // AIX aches
+#elif defined(VGO_darwin)
+       // See readmacho.c for an explanation of this.
+       VG_STREQ("start_according_to_valgrind", name) ||  // Darwin, darling
 #else
 #      error Unknown OS
 #endif
@@ -3384,7 +3403,6 @@
 
 }
 
-
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/priv_readmacho.h b/coregrind/m_debuginfo/priv_readmacho.h
new file mode 100644
index 0000000..e9da383
--- /dev/null
+++ b/coregrind/m_debuginfo/priv_readmacho.h
@@ -0,0 +1,52 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from Mach-O files.              ---*/
+/*---                                             priv_readmacho.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   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_READMACHO_H
+#define __PRIV_READMACHO_H
+
+/* Identify a Mach-O object file by peering at the first few bytes of
+   it. */
+extern Bool ML_(is_macho_object_file)( const void* buf, SizeT size );
+
+/* The central function for reading Mach-O debug info.  For the
+   object/exe specified by the DebugInfo, find Mach-O sections, then read
+   the symbols, line number info, file name info, CFA (stack-unwind
+   info) and anything else we want, into the tables within the
+   supplied DebugInfo.
+*/
+extern Bool ML_(read_macho_debug_info) ( struct _DebugInfo* si );
+
+
+#endif /* ndef __PRIV_READMACHO_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index 9749b24..f6e6e82 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -619,6 +619,12 @@
                         UChar*   dirname,  /* NULL is allowable */
                         Addr this, Addr next, Int lineno, Int entry);
 
+/* Shrink completed tables to save memory. */
+extern 
+void ML_(shrinkSym) ( struct _DebugInfo *di );
+extern 
+void ML_(shrinkLineInfo) ( struct _DebugInfo *di );
+
 /* Add a CFI summary record.  The supplied DiCfSI is copied. */
 extern void ML_(addDiCfSI) ( struct _DebugInfo* di, DiCfSI* cfsi );
 
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 30df436..69000e6 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -1785,6 +1785,14 @@
 #  define FP_REG         1
 #  define SP_REG         1
 #  define RA_REG_DEFAULT 8     // CAB: What's a good default ?
+#elif defined(VGP_x86_darwin)
+#  define FP_REG         5
+#  define SP_REG         4
+#  define RA_REG_DEFAULT 8
+#elif defined(VGP_amd64_darwin)
+#  define FP_REG         6
+#  define SP_REG         7
+#  define RA_REG_DEFAULT 16
 #else
 #  error "Unknown platform"
 #endif
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index d8eed6a..d94b17d 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -138,6 +138,7 @@
 #include "pub_core_libcassert.h"
 #include "pub_core_libcprint.h"
 #include "pub_core_options.h"
+#include "pub_core_tooliface.h"    /* VG_(needs) */
 #include "pub_core_xarray.h"
 #include "pub_core_wordfm.h"
 #include "priv_misc.h"             /* dinfo_zalloc/free */
@@ -3903,6 +3904,7 @@
    TRACE_SYMTAB("\n");
 #endif
 
+
 /*--------------------------------------------------------------------*/
 /*--- end                                             readdwarf3.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/readmacho.c b/coregrind/m_debuginfo/readmacho.c
new file mode 100644
index 0000000..76293ad
--- /dev/null
+++ b/coregrind/m_debuginfo/readmacho.c
@@ -0,0 +1,1095 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from Mach-O files.              ---*/
+/*---                                                  readmacho.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_aspacemgr.h"    /* for mmaping debuginfo files */
+#include "pub_core_machine.h"      /* VG_ELF_CLASS */
+#include "pub_core_options.h"
+#include "pub_core_oset.h"
+#include "pub_core_tooliface.h"    /* VG_(needs) */
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuginfo.h"
+
+#include "priv_d3basics.h"
+#include "priv_misc.h"
+#include "priv_tytypes.h"
+#include "priv_storage.h"
+#include "priv_readmacho.h"
+#include "priv_readdwarf.h"
+#include "priv_readdwarf3.h"
+#include "priv_readstabs.h"
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/fat.h>
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+#if VG_WORDSIZE == 4
+# define MAGIC MH_MAGIC
+# define MACH_HEADER mach_header
+# define LC_SEGMENT_CMD LC_SEGMENT
+# define SEGMENT_COMMAND segment_command
+# define SECTION section
+# define NLIST nlist
+#else
+# define MAGIC MH_MAGIC_64
+# define MACH_HEADER mach_header_64
+# define LC_SEGMENT_CMD LC_SEGMENT_64
+# define SEGMENT_COMMAND segment_command_64
+# define SECTION section_64
+# define NLIST nlist_64
+#endif
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- Mach-O file mapping/unmapping helpers                ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+typedef
+   struct {
+      /* These two describe the entire mapped-in ("primary") image,
+         fat headers, kitchen sink, whatnot: the entire file.  The
+         image is mapped into img[0 .. img_szB-1]. */
+      UChar* img;
+      SizeT  img_szB;
+      /* These two describe the Mach-O object of interest, which is
+         presumably somewhere inside the primary image.
+         map_image_aboard() below, which generates this info, will
+         carefully check that the macho_ fields denote a section of
+         memory that falls entirely inside img[0 .. img_szB-1]. */
+      UChar* macho_img;
+      SizeT  macho_img_szB;
+   }
+   ImageInfo;
+
+
+Bool ML_(is_macho_object_file)( const void* buf, SizeT szB )
+{
+   /* (JRS: the Mach-O headers might not be in this mapped data,
+      because we only mapped a page for this initial check,
+      or at least not very much, and what's at the start of the file
+      is in general a so-called fat header.  The Mach-O object we're
+      interested in could be arbitrarily far along the image, and so
+      we can't assume its header will fall within this page.) */
+
+   /* But we can say that either it's a fat object, in which case it
+      begins with a fat header, or it's unadorned Mach-O, in which
+      case it starts with a normal header.  At least do what checks we
+      can to establish whether or not we're looking at something
+      sane. */
+
+   const struct fat_header*  fh_be = buf;
+   const struct MACH_HEADER* mh    = buf;
+
+   vg_assert(buf);
+   if (szB < sizeof(struct fat_header))
+      return False;
+   if (VG_(ntohl)(fh_be->magic) == FAT_MAGIC)
+      return True;
+
+   if (szB < sizeof(struct MACH_HEADER))
+      return False;
+   if (mh->magic == MAGIC)
+      return True;
+
+   return False;
+}
+
+
+/* Unmap an image mapped in by map_image_aboard. */
+static void unmap_image ( /*MOD*/ImageInfo* ii )
+{
+   SysRes sres;
+   vg_assert(ii->img);
+   vg_assert(ii->img_szB > 0);
+   sres = VG_(am_munmap_valgrind)( (Addr)ii->img, ii->img_szB );
+   /* Do we care if this fails?  I suppose so; it would indicate
+      some fairly serious snafu with the mapping of the file. */
+   vg_assert( !sr_isError(sres) );
+   VG_(memset)(ii, 0, sizeof(*ii));
+}
+
+
+/* Map a given fat or thin object aboard, find the thin part if
+   necessary, do some checks, and write details of both the fat and
+   thin parts into *ii.  Returns False (and leaves the file unmapped)
+   on failure.  Guarantees to return pointers to a valid(ish) Mach-O
+   image if it succeeds. */
+static Bool map_image_aboard ( DebugInfo* di, /* only for err msgs */
+                               /*OUT*/ImageInfo* ii, UChar* filename )
+{
+   VG_(memset)(ii, 0, sizeof(*ii));
+
+   /* First off, try to map the thing in. */
+   { SizeT  size;
+     SysRes fd, sres;
+     struct vg_stat stat_buf;
+
+     fd = VG_(stat)(filename, &stat_buf);
+     if (sr_isError(fd)) {
+        ML_(symerr)(di, True, "Can't stat image (to determine its size)?!");
+        return False;
+     }
+     size = stat_buf.size;
+
+     fd = VG_(open)(filename, VKI_O_RDONLY, 0);
+     if (sr_isError(fd)) {
+       ML_(symerr)(di, True, "Can't open image to read symbols?!");
+        return False;
+     }
+
+     sres = VG_(am_mmap_file_float_valgrind)
+               ( size, VKI_PROT_READ, sr_Res(fd), 0 );
+     if (sr_isError(sres)) {
+        ML_(symerr)(di, True, "Can't mmap image to read symbols?!");
+        return False;
+     }
+
+     VG_(close)(sr_Res(fd));
+
+     ii->img     = (UChar*)sr_Res(sres);
+     ii->img_szB = size;
+   }
+
+   /* Now it's mapped in and we have .img and .img_szB set.  Look for
+      the embedded Mach-O object.  If not findable, unmap and fail. */
+   { struct fat_header*  fh_be;
+     struct fat_header   fh;
+     struct MACH_HEADER* mh;
+     
+     // Assume initially that we have a thin image, and update
+     // these if it turns out to be fat.
+     ii->macho_img     = ii->img;
+     ii->macho_img_szB = ii->img_szB;
+
+     // Check for fat header.
+     if (ii->img_szB < sizeof(struct fat_header)) {
+        ML_(symerr)(di, True, "Invalid Mach-O file (0 too small).");
+        goto unmap_and_fail;
+     }
+
+     // Fat header is always BIG-ENDIAN
+     fh_be = (struct fat_header *)ii->img;
+     fh.magic = VG_(ntohl)(fh_be->magic);
+     fh.nfat_arch = VG_(ntohl)(fh_be->nfat_arch);
+     if (fh.magic == FAT_MAGIC) {
+        // Look for a good architecture.
+        struct fat_arch *arch_be;
+        struct fat_arch arch;
+        Int f;
+        if (ii->img_szB < sizeof(struct fat_header)
+                          + fh.nfat_arch * sizeof(struct fat_arch)) {
+           ML_(symerr)(di, True, "Invalid Mach-O file (1 too small).");
+           goto unmap_and_fail;
+        }
+        for (f = 0, arch_be = (struct fat_arch *)(fh_be+1); 
+             f < fh.nfat_arch;
+             f++, arch_be++) {
+           Int cputype;
+#          if defined(VGA_ppc)
+           cputype = CPU_TYPE_POWERPC;
+#          elif defined(VGA_ppc64)
+           cputype = CPU_TYPE_POWERPC64;
+#          elif defined(VGA_x86)
+           cputype = CPU_TYPE_X86;
+#          elif defined(VGA_amd64)
+           cputype = CPU_TYPE_X86_64;
+#          else
+#            error "unknown architecture"
+#          endif
+           arch.cputype    = VG_(ntohl)(arch_be->cputype);
+           arch.cpusubtype = VG_(ntohl)(arch_be->cpusubtype);
+           arch.offset     = VG_(ntohl)(arch_be->offset);
+           arch.size       = VG_(ntohl)(arch_be->size);
+           if (arch.cputype == cputype) {
+              if (ii->img_szB < arch.offset + arch.size) {
+                 ML_(symerr)(di, True, "Invalid Mach-O file (2 too small).");
+                 goto unmap_and_fail;
+              }
+              ii->macho_img     = ii->img + arch.offset;
+              ii->macho_img_szB = arch.size;
+              break;
+           }
+        }
+        if (f == fh.nfat_arch) {
+           ML_(symerr)(di, True,
+                       "No acceptable architecture found in fat file.");
+           goto unmap_and_fail;
+        }
+     }
+
+     /* Sanity check what we found. */
+
+     /* assured by logic above */
+     vg_assert(ii->img_szB >= sizeof(struct fat_header));
+
+     if (ii->macho_img_szB < sizeof(struct MACH_HEADER)) {
+        ML_(symerr)(di, True, "Invalid Mach-O file (3 too small).");
+        goto unmap_and_fail;
+     }
+
+     if (ii->macho_img_szB > ii->img_szB) {
+        ML_(symerr)(di, True, "Invalid Mach-O file (thin bigger than fat).");
+        goto unmap_and_fail;
+     }
+
+     if (ii->macho_img >= ii->img
+         && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) {
+        /* thin entirely within fat, as expected */
+     } else {
+        ML_(symerr)(di, True, "Invalid Mach-O file (thin not inside fat).");
+        goto unmap_and_fail;
+     }
+
+     mh = (struct MACH_HEADER *)ii->macho_img;
+     if (mh->magic != MAGIC) {
+        ML_(symerr)(di, True, "Invalid Mach-O file (bad magic).");
+        goto unmap_and_fail;
+     }
+
+     if (ii->macho_img_szB < sizeof(struct MACH_HEADER) + mh->sizeofcmds) {
+        ML_(symerr)(di, True, "Invalid Mach-O file (4 too small).");
+        goto unmap_and_fail;
+     }
+   }
+
+   vg_assert(ii->img);
+   vg_assert(ii->macho_img);
+   vg_assert(ii->img_szB > 0);
+   vg_assert(ii->macho_img_szB > 0);
+   vg_assert(ii->macho_img >= ii->img);
+   vg_assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB);
+   return True;  /* success */
+   /*NOTREACHED*/
+
+  unmap_and_fail:
+   unmap_image(ii);
+   return False; /* bah! */
+}
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- Mach-O symbol table reading                          ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/* Read a symbol table (nlist).  Add the resulting candidate symbols
+   to 'syms'; the caller will post-process them and hand them off to
+   ML_(addSym) itself. */
+static
+void read_symtab( /*OUT*/XArray* /* DiSym */ syms,
+                  struct _DebugInfo* di, 
+                  struct NLIST* o_symtab, UInt o_symtab_count,
+                  UChar*     o_strtab, UInt o_strtab_sz )
+{
+   Int    i;
+   Addr   sym_addr;
+   DiSym  risym;
+   UChar* name;
+
+   static UChar* s_a_t_v = NULL; /* do not make non-static */
+
+   for (i = 0; i < o_symtab_count; i++) {
+      struct NLIST *nl = o_symtab+i;
+      if ((nl->n_type & N_TYPE) == N_SECT) {
+         sym_addr = di->text_bias + nl->n_value;
+    /*} else if ((nl->n_type & N_TYPE) == N_ABS) {
+         GrP fixme don't ignore absolute symbols?
+         sym_addr = nl->n_value; */
+      } else {
+         continue;
+      }
+      
+      if (di->trace_symtab)
+         VG_(printf)("nlist raw: avma %010lx  %s\n",
+                     sym_addr, o_strtab + nl->n_un.n_strx );
+
+      /* If no part of the symbol falls within the mapped range,
+         ignore it. */
+      if (sym_addr <= di->text_avma
+          || sym_addr >= di->text_avma+di->text_size) {
+         continue;
+      }
+
+      /* skip names which point outside the string table;
+         following these risks segfaulting Valgrind */
+      name = o_strtab + nl->n_un.n_strx;
+      if (name < o_strtab || name >= o_strtab + o_strtab_sz)
+         continue;
+
+      /* skip nameless symbols; these appear to be common, but
+         useless */
+      if (*name == 0)
+         continue;
+
+      risym.tocptr = 0;
+      risym.addr = sym_addr;
+      risym.size = // let canonicalize fix it
+                   di->text_avma+di->text_size - sym_addr;
+      risym.name = ML_(addStr)(di, name, -1);
+      risym.isText = True;
+      // Lots of user function names get prepended with an underscore.  Eg. the
+      // function 'f' becomes the symbol '_f'.  And the "below main"
+      // function is called "start".  So we skip the leading underscore, and
+      // if we see 'start' and --show-below-main=no, we rename it as
+      // "start_according_to_valgrind", which makes it easy to spot later
+      // and display as "(below main)".
+      if (risym.name[0] == '_') {
+         risym.name++;
+      } else if (!VG_(clo_show_below_main) && VG_STREQ(risym.name, "start")) {
+         if (s_a_t_v == NULL)
+            s_a_t_v = ML_(addStr)(di, "start_according_to_valgrind", -1);
+         vg_assert(s_a_t_v);
+         risym.name = s_a_t_v;
+      }
+
+      vg_assert(risym.name);
+      VG_(addToXA)( syms, &risym );
+   }
+}
+
+
+/* Compare DiSyms by their start address, and for equal addresses, use
+   the name as a secondary sort key. */
+static Int cmp_DiSym_by_start_then_name ( void* v1, void* v2 )
+{
+   DiSym* s1 = (DiSym*)v1;
+   DiSym* s2 = (DiSym*)v2;
+   if (s1->addr < s2->addr) return -1;
+   if (s1->addr > s2->addr) return 1;
+   return VG_(strcmp)(s1->name, s2->name);
+}
+
+/* 'cand' is a bunch of candidate symbols obtained by reading
+   nlist-style symbol table entries.  Their ends may overlap, so sort
+   them and truncate them accordingly.  The code in this routine is
+   copied almost verbatim from read_symbol_table() in readxcoff.c. */
+static void tidy_up_cand_syms ( /*MOD*/XArray* /* of DiSym */ syms,
+                                Bool trace_symtab )
+{
+   Word nsyms, i, j, k, m;
+
+   nsyms = VG_(sizeXA)(syms);
+
+   VG_(setCmpFnXA)(syms, cmp_DiSym_by_start_then_name);
+   VG_(sortXA)(syms);
+
+   /* We only know for sure the start addresses (actual VMAs) of
+      symbols, and an overestimation of their end addresses.  So sort
+      by start address, then clip each symbol so that its end address
+      does not overlap with the next one along.
+
+      There is a small refinement: if a group of symbols have the same
+      address, treat them as a group: find the next symbol along that
+      has a higher start address, and clip all of the group
+      accordingly.  This clips the group as a whole so as not to
+      overlap following symbols.  This leaves prefersym() in
+      storage.c, which is not nlist-specific, to later decide which of
+      the symbols in the group to keep.
+
+      Another refinement is that we need to get rid of symbols which,
+      after clipping, have identical starts, ends, and names.  So the
+      sorting uses the name as a secondary key.
+   */
+
+   for (i = 0; i < nsyms; i++) {
+      for (k = i+1;
+           k < nsyms
+             && ((DiSym*)VG_(indexXA)(syms,i))->addr
+                 == ((DiSym*)VG_(indexXA)(syms,k))->addr;
+           k++)
+         ;
+      /* So now [i .. k-1] is a group all with the same start address.
+         Clip their ending addresses so they don't overlap [k].  In
+         the normal case (no overlaps), k == i+1. */
+      if (k < nsyms) {
+         DiSym* next = (DiSym*)VG_(indexXA)(syms,k);
+         for (m = i; m < k; m++) {
+            DiSym* here = (DiSym*)VG_(indexXA)(syms,m);
+            vg_assert(here->addr < next->addr);
+            if (here->addr + here->size > next->addr)
+               here->size = next->addr - here->addr;
+         }
+      }
+      i = k-1;
+      vg_assert(i <= nsyms);
+   }
+
+   j = 0;
+   if (nsyms > 0) {
+      j = 1;
+      for (i = 1; i < nsyms; i++) {
+         DiSym *s_j1, *s_j, *s_i;
+         vg_assert(j <= i);
+         s_j1 = (DiSym*)VG_(indexXA)(syms, j-1);
+         s_j  = (DiSym*)VG_(indexXA)(syms, j);
+         s_i  = (DiSym*)VG_(indexXA)(syms, i);
+         if (s_i->addr != s_j1->addr
+             || s_i->size != s_j1->size
+             || 0 != VG_(strcmp)(s_i->name, s_j1->name)) {
+            *s_j = *s_i;
+            j++;
+         } else {
+            if (trace_symtab)
+               VG_(printf)("nlist cleanup: dump duplicate avma %010lx  %s\n",
+                           s_i->addr, s_i->name );
+         }
+      }
+   }
+   vg_assert(j >= 0 && j <= nsyms);
+   VG_(dropTailXA)(syms, nsyms - j);
+}
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- Mach-O top-level processing                          ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+#if !defined(APPLE_DSYM_EXT_AND_SUBDIRECTORY)
+#define APPLE_DSYM_EXT_AND_SUBDIRECTORY ".dSYM/Contents/Resources/DWARF/"
+#endif
+
+
+static Bool file_exists_p(const Char *path)
+{
+   struct vg_stat sbuf;
+   SysRes res = VG_(stat)(path, &sbuf);
+   return sr_isError(res) ? False : True;
+}
+
+
+/* Search for an existing dSYM file as a possible separate debug file.  
+   Adapted from gdb. */
+static Char *
+find_separate_debug_file (const Char *executable_name)
+{
+   Char *basename_str;
+   Char *dot_ptr;
+   Char *slash_ptr;
+   Char *dsymfile;
+    
+   /* Make sure the object file name itself doesn't contain ".dSYM" in it or we
+      will end up with an infinite loop where after we add a dSYM symbol file,
+      it will then enter this function asking if there is a debug file for the
+      dSYM file itself.  */
+   if (VG_(strcasestr) (executable_name, ".dSYM") == NULL)
+   {
+      /* Check for the existence of a .dSYM file for a given executable.  */
+      basename_str = VG_(basename) (executable_name);
+      dsymfile = ML_(dinfo_zalloc)("di.readmacho.dsymfile", 
+                    VG_(strlen) (executable_name)
+                    + VG_(strlen) (APPLE_DSYM_EXT_AND_SUBDIRECTORY)
+                    + VG_(strlen) (basename_str)
+                    + 1
+                 );
+        
+      /* First try for the dSYM in the same directory as the original file.  */
+      VG_(strcpy) (dsymfile, executable_name);
+      VG_(strcat) (dsymfile, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+      VG_(strcat) (dsymfile, basename_str);
+        
+      if (file_exists_p (dsymfile))
+         return dsymfile;
+        
+      /* Now search for any parent directory that has a '.' in it so we can find
+         Mac OS X applications, bundles, plugins, and any other kinds of files. 
+         Mac OS X application bundles wil have their program in
+         "/some/path/MyApp.app/Contents/MacOS/MyApp" (or replace ".app" with
+         ".bundle" or ".plugin" for other types of bundles).  So we look for any
+         prior '.' character and try appending the apple dSYM extension and
+         subdirectory and see if we find an existing dSYM file (in the above
+         MyApp example the dSYM would be at either:
+         "/some/path/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp" or
+         "/some/path/MyApp.dSYM/Contents/Resources/DWARF/MyApp".  */
+      VG_(strcpy) (dsymfile, VG_(dirname) (executable_name));
+      while ((dot_ptr = VG_(strrchr) (dsymfile, '.')))
+      {
+         /* Find the directory delimiter that follows the '.' character since
+            we now look for a .dSYM that follows any bundle extension.  */
+         slash_ptr = VG_(strchr) (dot_ptr, '/');
+         if (slash_ptr)
+         {
+             /* NULL terminate the string at the '/' character and append
+                the path down to the dSYM file.  */
+            *slash_ptr = '\0';
+            VG_(strcat) (slash_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+            VG_(strcat) (slash_ptr, basename_str);
+            if (file_exists_p (dsymfile))
+               return dsymfile;
+         }
+         
+         /* NULL terminate the string at the '.' character and append
+            the path down to the dSYM file.  */
+         *dot_ptr = '\0';
+         VG_(strcat) (dot_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+         VG_(strcat) (dot_ptr, basename_str);
+         if (file_exists_p (dsymfile))
+            return dsymfile;
+         
+         /* NULL terminate the string at the '.' locatated by the strrchr()
+            function again.  */
+         *dot_ptr = '\0';
+         
+         /* We found a previous extension '.' character and did not find a
+            dSYM file so now find previous directory delimiter so we don't
+            try multiple times on a file name that may have a version number
+            in it such as "/some/path/MyApp.6.0.4.app".  */
+         slash_ptr = VG_(strrchr) (dsymfile, '/');
+         if (!slash_ptr)
+            break;
+         /* NULL terminate the string at the previous directory character
+            and search again.  */
+         *slash_ptr = '\0';
+      }
+   }
+
+   return NULL;
+}
+
+
+static UChar *getsectdata(UChar* base, SizeT size, 
+                          Char *segname, Char *sectname,
+                          /*OUT*/Word *sect_size)
+{
+   struct MACH_HEADER *mh = (struct MACH_HEADER *)base;
+   struct load_command *cmd;          
+   Int c;
+
+   for (c = 0, cmd = (struct load_command *)(mh+1);
+        c < mh->ncmds;
+        c++, cmd = (struct load_command *)(cmd->cmdsize + (Addr)cmd))
+   {
+      if (cmd->cmd == LC_SEGMENT_CMD) {
+         struct SEGMENT_COMMAND *seg = (struct SEGMENT_COMMAND *)cmd;
+         if (0 == VG_(strncmp(seg->segname, segname, sizeof(seg->segname)))) {
+            struct SECTION *sects = (struct SECTION *)(seg+1);
+            Int s;
+            for (s = 0; s < seg->nsects; s++) {
+               if (0 == VG_(strncmp(sects[s].sectname, sectname, 
+                                    sizeof(sects[s].sectname)))) 
+               {
+                  if (sect_size) *sect_size = sects[s].size;
+                  return (UChar *)(base + sects[s].offset);
+               }
+            }
+         }
+      }
+   }
+
+   if (sect_size) *sect_size = 0;
+   return 0;
+}
+
+
+/* Brute force just simply search for uuid[0..15] in img[0..n_img-1] */
+static Bool check_uuid_matches ( Addr imgA, Word n_img, UChar* uuid )
+{
+   Word   i;
+   UChar* img = (UChar*)imgA;
+   UChar  first = uuid[0];
+   if (n_img < 16)
+      return False;
+   for (i = 0; i < n_img-16; i++) {
+      if (img[i] != first)
+         continue;
+      if (0 == VG_(memcmp)( &img[i], &uuid[0], 16 ))
+         return True;
+   }
+   return False;
+}
+
+
+/* Heuristic kludge: return True if this looks like an installed
+   standard library; hence we shouldn't consider automagically running
+   dsymutil on it. */
+static Bool is_systemish_library_name ( UChar* name )
+{
+   vg_assert(name);
+   if (0 == VG_(strncasecmp)(name, "/usr/", 5)
+       || 0 == VG_(strncasecmp)(name, "/bin/", 5)
+       || 0 == VG_(strncasecmp)(name, "/sbin/", 6)
+       || 0 == VG_(strncasecmp)(name, "/System/", 8)
+       || 0 == VG_(strncasecmp)(name, "/Library/", 9)) {
+      return True;
+   } else {
+      return False;
+   }
+}
+
+
+Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
+{
+   struct symtab_command *symcmd = NULL;
+   struct dysymtab_command *dysymcmd = NULL;
+   HChar* dsymfilename = NULL;
+   Bool have_uuid = False;
+   UChar uuid[16];
+   ImageInfo ii;  /* main file */
+   ImageInfo iid; /* auxiliary .dSYM file */
+   Bool ok;
+
+   /* mmap the object file to look for di->soname and di->text_bias 
+      and uuid and nlist and STABS */
+
+   if (VG_(clo_verbosity) > 1)
+      VG_(message)(Vg_DebugMsg,
+                   "%s (%#lx)", di->filename, di->rx_map_avma );
+
+   /* This should be ensured by our caller. */
+   vg_assert(di->have_rx_map);
+   vg_assert(di->have_rw_map);
+
+   VG_(memset)(&ii,   0, sizeof(ii));
+   VG_(memset)(&iid,  0, sizeof(iid));
+   VG_(memset)(&uuid, 0, sizeof(uuid));
+
+   ok = map_image_aboard( di, &ii, di->filename );
+   if (!ok) goto fail;
+
+   vg_assert(ii.macho_img != NULL && ii.macho_img_szB > 0);
+
+   /* Poke around in the Mach-O header, to find some important
+      stuff. */
+   // Find LC_SYMTAB and LC_DYSYMTAB, if present.
+   // Read di->soname from LC_ID_DYLIB if present, 
+   //    or from LC_ID_DYLINKER if present, 
+   //    or use "NONE".
+   // Get di->text_bias (aka slide) based on the corresponding LC_SEGMENT
+   // Get uuid for later dsym search
+
+   di->text_bias = 0;
+
+   { struct MACH_HEADER *mh = (struct MACH_HEADER *)ii.macho_img;
+      struct load_command *cmd;
+      Int c;
+
+      for (c = 0, cmd = (struct load_command *)(mh+1);
+           c < mh->ncmds;
+           c++, cmd = (struct load_command *)(cmd->cmdsize
+                                              + (unsigned long)cmd)) {
+         if (cmd->cmd == LC_SYMTAB) {
+            symcmd = (struct symtab_command *)cmd;
+         } 
+         else if (cmd->cmd == LC_DYSYMTAB) {
+            dysymcmd = (struct dysymtab_command *)cmd;
+         } 
+         else if (cmd->cmd == LC_ID_DYLIB && mh->filetype == MH_DYLIB) {
+            // GrP fixme bundle?
+            struct dylib_command *dcmd = (struct dylib_command *)cmd;
+            UChar *dylibname = dcmd->dylib.name.offset + (UChar *)dcmd;
+            UChar *soname = VG_(strrchr)(dylibname, '/');
+            if (!soname) soname = dylibname;
+            else soname++;
+            di->soname = ML_(dinfo_strdup)("di.readmacho.dylibname",
+                                           soname);
+         }
+         else if (cmd->cmd==LC_ID_DYLINKER  &&  mh->filetype==MH_DYLINKER) {
+            struct dylinker_command *dcmd = (struct dylinker_command *)cmd;
+            UChar *dylinkername = dcmd->name.offset + (UChar *)dcmd;
+            UChar *soname = VG_(strrchr)(dylinkername, '/');
+            if (!soname) soname = dylinkername;
+            else soname++;
+            di->soname = ML_(dinfo_strdup)("di.readmacho.dylinkername",
+                                           soname);
+         }
+
+         // A comment from Julian about why varinfo[35] fail:
+         //
+         // My impression is, from comparing the output of otool -l for these
+         // executables with the logic in ML_(read_macho_debug_info),
+         // specifically the part that begins "else if (cmd->cmd ==
+         // LC_SEGMENT_CMD) {", that it's a complete hack which just happens
+         // to work ok for text symbols.  In particular, it appears to assume
+         // that in a "struct load_command" of type LC_SEGMENT_CMD, the first
+         // "struct SEGMENT_COMMAND" inside it is going to contain the info we
+         // need.  However, otool -l shows, and also the Apple docs state,
+         // that a struct load_command may contain an arbitrary number of
+         // struct SEGMENT_COMMANDs, so I'm not sure why it's OK to merely
+         // snarf the first.  But I'm not sure about this.
+         //
+         // The "Try for __DATA" block below simply adds acquisition of data
+         // svma/bias values using the same assumption.  It also needs
+         // (probably) to deal with bss sections, but I don't understand how
+         // this all ties together really, so it requires further study.
+         //
+         // If you can get your head around the relationship between MachO
+         // segments, sections and load commands, this might be relatively
+         // easy to fix properly.
+         //
+         // Basically we need to come up with plausible numbers for di->
+         // {text,data,bss}_{avma,svma}, from which the _bias numbers are
+         // then trivially derived.  Then I think the debuginfo reader should
+         // work pretty well.
+         else if (cmd->cmd == LC_SEGMENT_CMD) {
+            struct SEGMENT_COMMAND *seg = (struct SEGMENT_COMMAND *)cmd;
+            /* Try for __TEXT */
+            if (!di->text_present
+                && 0 == VG_(strcmp)(seg->segname, "__TEXT")
+                /* DDD: is the  next line a kludge? -- JRS */
+                && seg->fileoff == 0 && seg->filesize != 0) {
+               di->text_present = True;
+               di->text_svma = (Addr)seg->vmaddr;
+               di->text_avma = di->rx_map_avma;
+               di->text_size = seg->vmsize;
+               di->text_bias = di->text_avma - di->text_svma;
+               /* Make the _debug_ values be the same as the
+                  svma/bias for the primary object, since there is
+                  no secondary (debuginfo) object, but nevertheless
+                  downstream biasing of Dwarf3 relies on the
+                  _debug_ values. */
+               di->text_debug_svma = di->text_svma;
+               di->text_debug_bias = di->text_bias;
+            }
+            /* Try for __DATA */
+            if (!di->data_present
+                && 0 == VG_(strcmp)(seg->segname, "__DATA")
+                /* && DDD:seg->fileoff == 0 */ && seg->filesize != 0) {
+               di->data_present = True;
+               di->data_svma = (Addr)seg->vmaddr;
+               di->data_avma = di->rw_map_avma;
+               di->data_size = seg->vmsize;
+               di->data_bias = di->data_avma - di->data_svma;
+               di->data_debug_svma = di->data_svma;
+               di->data_debug_bias = di->data_bias;
+            }
+         }
+         else if (cmd->cmd == LC_UUID) {
+             struct uuid_command *uuid_cmd = (struct uuid_command *)cmd;
+             VG_(memcpy)(uuid, uuid_cmd->uuid, sizeof(uuid));
+             have_uuid = True;
+         }
+      }
+   }
+
+   if (!di->soname) {
+      di->soname = ML_(dinfo_strdup)("di.readmacho.noname", "NONE");
+   }
+
+   /* Now we have the base object to hand.  Read symbols from it. */
+
+   if (ii.macho_img && ii.macho_img_szB > 0 && symcmd && dysymcmd) {
+
+      /* Read nlist symbol table */
+      struct NLIST *syms;
+      UChar *strs;
+      XArray* /* DiSym */ candSyms = NULL;
+      Word i, nCandSyms;
+
+      if (ii.macho_img_szB < symcmd->stroff + symcmd->strsize
+          || ii.macho_img_szB < symcmd->symoff + symcmd->nsyms
+                                                 * sizeof(struct NLIST)) {
+         ML_(symerr)(di, False, "Invalid Mach-O file (5 too small).");
+         goto fail;
+      }   
+      if (dysymcmd->ilocalsym + dysymcmd->nlocalsym > symcmd->nsyms
+          || dysymcmd->iextdefsym + dysymcmd->nextdefsym > symcmd->nsyms) {
+         ML_(symerr)(di, False, "Invalid Mach-O file (bad symbol table).");
+         goto fail;
+      }
+      
+      syms = (struct NLIST *)(ii.macho_img + symcmd->symoff);
+      strs = (UChar *)(ii.macho_img + symcmd->stroff);
+      
+      if (VG_(clo_verbosity) > 1)
+         VG_(message)(Vg_DebugMsg,
+            "   reading syms   from primary file (%d %d)",
+            dysymcmd->nextdefsym, dysymcmd->nlocalsym );
+
+      /* Read candidate symbols into 'candSyms', so we can truncate
+         overlapping ends and generally tidy up, before presenting
+         them to ML_(addSym). */
+      candSyms = VG_(newXA)(
+                    ML_(dinfo_zalloc), "di.readmacho.candsyms.1",
+                    ML_(dinfo_free), sizeof(DiSym)
+                 );
+      vg_assert(candSyms);
+
+      // extern symbols
+      read_symtab(candSyms,
+                  di, 
+                  syms + dysymcmd->iextdefsym, dysymcmd->nextdefsym, 
+                  strs, symcmd->strsize);
+      // static and private_extern symbols
+      read_symtab(candSyms,
+                  di, 
+                  syms + dysymcmd->ilocalsym, dysymcmd->nlocalsym, 
+                  strs, symcmd->strsize);
+
+      /* tidy up the cand syms -- trim overlapping ends.  May resize
+         candSyms. */
+      tidy_up_cand_syms( candSyms, di->trace_symtab );
+
+      /* and finally present them to ML_(addSym) */
+      nCandSyms = VG_(sizeXA)( candSyms );
+      for (i = 0; i < nCandSyms; i++) {
+         DiSym* cand = (DiSym*) VG_(indexXA)( candSyms, i );
+         if (di->trace_symtab)
+            VG_(printf)("nlist final: acquire  avma %010lx-%010lx  %s\n",
+                        cand->addr, cand->addr + cand->size - 1, cand->name );
+         ML_(addSym)( di, cand );
+      }
+      VG_(deleteXA)( candSyms );
+   }
+
+   /* If there's no UUID in the primary, don't even bother to try and
+      read any DWARF, since we won't be able to verify it matches.
+      Our policy is not to load debug info unless we can verify that
+      it matches the primary.  Just declare success at this point.
+      And don't complain to the user, since that would cause us to
+      complain on objects compiled without -g.  (Some versions of
+      XCode are observed to omit a UUID entry for object linked(?)
+      without -g.  Others don't appear to omit it.) */
+   if (!have_uuid)
+      goto success;
+
+   /* mmap the dSYM file to look for DWARF debug info.  If successful,
+      use the .macho_img and .macho_img_szB in iid. */
+
+   dsymfilename = find_separate_debug_file( di->filename );
+
+   /* Try to load it. */
+   if (dsymfilename) {
+      Bool valid;
+
+      if (VG_(clo_verbosity) > 1)
+         VG_(message)(Vg_DebugMsg, "   dSYM= %s", dsymfilename);
+
+      ok = map_image_aboard( di, &iid, dsymfilename );
+      if (!ok) goto fail;
+
+      /* check it has the right uuid. */
+      vg_assert(have_uuid);
+      valid = iid.macho_img && iid.macho_img_szB > 0 
+              && check_uuid_matches( (Addr)iid.macho_img,
+                                     iid.macho_img_szB, uuid );
+      if (valid)
+         goto read_the_dwarf;
+
+      if (VG_(clo_verbosity) > 1)
+         VG_(message)(Vg_DebugMsg, "   dSYM does not have "
+                                   "correct UUID (out of date?)");
+   }
+
+   /* There was no dsym file, or it doesn't match.  We'll have to try
+      regenerating it, unless auto-run-dsymutil is disabled, in which
+      case just complain instead. */
+
+   /* If this looks like a lib that we shouldn't run dsymutil on, just
+      give up.  (possible reasons: is system lib, or in /usr etc, or
+      the dsym dir would not be writable by the user, or we're running
+      as root) */
+   vg_assert(di->filename);
+   if (is_systemish_library_name(di->filename))
+      goto success;
+
+   if (!VG_(clo_auto_run_dsymutil)) {
+      if (VG_(clo_verbosity) == 1) {
+         VG_(message)(Vg_DebugMsg, "%s:", di->filename);
+      }
+      if (VG_(clo_verbosity) > 0)
+         VG_(message)(Vg_DebugMsg, "%sdSYM directory %s; consider using "
+                      "--auto-run-dsymutil=yes",
+                      VG_(clo_verbosity) > 1 ? "   " : "",
+                      dsymfilename ? "has wrong UUID" : "is missing"); 
+      goto success;
+   }
+
+   /* Run dsymutil */
+
+   { Int r;
+     HChar* dsymutil = "/usr/bin/dsymutil ";
+     HChar* cmd = ML_(dinfo_zalloc)( "di.readmacho.tmp1", 
+                                     VG_(strlen)(dsymutil)
+                                     + VG_(strlen)(di->filename)
+                                     + 30 /* misc */ );
+     VG_(strcpy)(cmd, dsymutil);
+     if (0) VG_(strcat)(cmd, "--verbose ");
+     VG_(strcat)(cmd, di->filename);
+     VG_(message)(Vg_DebugMsg, "run: %s", cmd);
+     r = VG_(system)( cmd );
+     if (r)
+        VG_(message)(Vg_DebugMsg, "run: %s FAILED", dsymutil);
+     ML_(dinfo_free)(cmd);
+     dsymfilename = find_separate_debug_file(di->filename);
+   }
+
+   /* Try again to load it. */
+   if (dsymfilename) {
+      Bool valid;
+
+      if (VG_(clo_verbosity) > 1)
+         VG_(message)(Vg_DebugMsg, "   dsyms= %s", dsymfilename);
+
+      ok = map_image_aboard( di, &iid, dsymfilename );
+      if (!ok) goto fail;
+
+      /* check it has the right uuid. */
+      vg_assert(have_uuid);
+      valid = iid.macho_img && iid.macho_img_szB > 0 
+              && check_uuid_matches( (Addr)iid.macho_img,
+                                     iid.macho_img_szB, uuid );
+      if (!valid) {
+         if (VG_(clo_verbosity) > 0) {
+            VG_(message)(Vg_DebugMsg,
+               "WARNING: did not find expected UUID %02X%02X%02X%02X"
+               "-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X"
+               " in dSYM dir",
+               (UInt)uuid[0], (UInt)uuid[1], (UInt)uuid[2], (UInt)uuid[3],
+               (UInt)uuid[4], (UInt)uuid[5], (UInt)uuid[6], (UInt)uuid[7],
+               (UInt)uuid[8], (UInt)uuid[9], (UInt)uuid[10],
+               (UInt)uuid[11], (UInt)uuid[12], (UInt)uuid[13],
+               (UInt)uuid[14], (UInt)uuid[15] );
+            VG_(message)(Vg_DebugMsg,
+                         "WARNING: for %s", di->filename);
+         }
+         unmap_image( &iid );
+         /* unmap_image zeroes the fields, so the following test makes
+            sense. */
+         goto fail;
+      }
+   }
+
+   /* Right.  Finally we have our best try at the dwarf image, so go
+      on to reading stuff out of it. */
+
+  read_the_dwarf:
+   if (iid.macho_img && iid.macho_img_szB > 0) {
+      UChar* debug_info_img = NULL;
+      Word   debug_info_sz;
+      UChar* debug_abbv_img;
+      Word   debug_abbv_sz;
+      UChar* debug_line_img;
+      Word   debug_line_sz;
+      UChar* debug_str_img;
+      Word   debug_str_sz;
+      UChar* debug_ranges_img;
+      Word   debug_ranges_sz;
+      UChar* debug_loc_img;
+      Word   debug_loc_sz;
+      UChar* debug_name_img;
+      Word   debug_name_sz;
+
+      debug_info_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_info", &debug_info_sz);
+      debug_abbv_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_abbrev", &debug_abbv_sz);
+      debug_line_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_line", &debug_line_sz);
+      debug_str_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_str", &debug_str_sz);
+      debug_ranges_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_ranges", &debug_ranges_sz);
+      debug_loc_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_loc", &debug_loc_sz);
+      debug_name_img = 
+          getsectdata(iid.macho_img, iid.macho_img_szB, 
+                      "__DWARF", "__debug_pubnames", &debug_name_sz);
+   
+      if (debug_info_img) {
+         if (VG_(clo_verbosity) > 1) {
+            if (0)
+            VG_(message)(Vg_DebugMsg,
+                         "Reading dwarf3 for %s (%#lx) from %s"
+                         " (%ld %ld %ld %ld %ld %ld)",
+                         di->filename, di->text_avma, dsymfilename,
+                         debug_info_sz, debug_abbv_sz, debug_line_sz, 
+                         debug_str_sz, debug_ranges_sz, debug_loc_sz
+                         );
+            VG_(message)(Vg_DebugMsg,
+               "   reading dwarf3 from dsyms file");
+         }
+         /* The old reader: line numbers and unwind info only */
+         ML_(read_debuginfo_dwarf3) ( di,
+                                      debug_info_img, debug_info_sz,
+                                      debug_abbv_img, debug_abbv_sz,
+                                      debug_line_img, debug_line_sz,
+                                      debug_str_img,  debug_str_sz );
+
+         /* The new reader: read the DIEs in .debug_info to acquire
+            information on variable types and locations.  But only if
+            the tool asks for it, or the user requests it on the
+            command line. */
+         if (VG_(needs).var_info /* the tool requires it */
+             || VG_(clo_read_var_info) /* the user asked for it */) {
+            ML_(new_dwarf3_reader)(
+               di, debug_info_img,   debug_info_sz,
+                   debug_abbv_img,   debug_abbv_sz,
+                   debug_line_img,   debug_line_sz,
+                   debug_str_img,    debug_str_sz,
+                   debug_ranges_img, debug_ranges_sz,
+                   debug_loc_img,    debug_loc_sz
+            );
+         }
+      }
+   }
+
+   if (dsymfilename) ML_(dinfo_free)(dsymfilename);
+
+  success:
+   if (ii.img)
+      unmap_image(&ii);
+   if (iid.img)
+      unmap_image(&iid);
+   return True;
+
+   /* NOTREACHED */
+
+  fail:
+   ML_(symerr)(di, True, "Error reading Mach-O object.");
+   if (ii.img)
+      unmap_image(&ii);
+   if (iid.img)
+      unmap_image(&iid);
+   return False;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                              readmacho.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/readstabs.c b/coregrind/m_debuginfo/readstabs.c
index 5bb9ac2..72de81d 100644
--- a/coregrind/m_debuginfo/readstabs.c
+++ b/coregrind/m_debuginfo/readstabs.c
@@ -46,7 +46,17 @@
 #include "priv_readstabs.h"        /* self */
 
 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
-#include <a.out.h> /* stabs defns */
+#if defined(VGO_linux)
+#  include <a.out.h> /* stabs defns */
+#elif defined(VGO_darwin)
+#  include <mach-o/nlist.h>
+#  define n_other n_sect
+#  if VG_WORDSIZE == 8
+#     define nlist nlist_64
+#  endif
+#else
+#  error "Unknown OS"
+#endif
 /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
 
 /*------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index 343cf3b..f8d0834 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -229,6 +229,24 @@
 }
 
 
+/* Resize the symbol table to save memory.
+*/
+void ML_(shrinkSym)( struct _DebugInfo* di )
+{
+   DiSym* new_tab;
+   UInt new_sz = di->symtab_used;
+   if (new_sz == di->symtab_size) return;
+
+   new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkSym", 
+                                new_sz * sizeof(DiSym) );
+   VG_(memcpy)(new_tab, di->symtab, new_sz * sizeof(DiSym));
+
+   ML_(dinfo_free)(di->symtab);
+   di->symtab = new_tab;
+   di->symtab_size = new_sz;
+}
+
+
 /* Add a location to the location table. 
 */
 static void addLoc ( struct _DebugInfo* di, DiLoc* loc )
@@ -259,6 +277,24 @@
 }
 
 
+/* Resize the lineinfo table to save memory.
+*/
+void ML_(shrinkLineInfo)( struct _DebugInfo* di )
+{
+   DiLoc* new_tab;
+   UInt new_sz = di->loctab_used;
+   if (new_sz == di->loctab_size) return;
+
+   new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkLineInfo", 
+                                new_sz * sizeof(DiLoc) );
+   VG_(memcpy)(new_tab, di->loctab, new_sz * sizeof(DiLoc));
+
+   ML_(dinfo_free)(di->loctab);
+   di->loctab = new_tab;
+   di->loctab_size = new_sz;
+}
+
+
 /* Top-level place to call to add a source-location mapping entry.
 */
 void ML_(addLineInfo) ( struct _DebugInfo* di,
@@ -1060,6 +1096,8 @@
 
 #if defined(VGO_linux) || defined(VGO_aix5)
 #  define VERSION_CHAR '@'
+#elif defined(VGO_darwin)
+#  define VERSION_CHAR '$'
 #else
 #  error Unknown OS
 #endif
@@ -1145,6 +1183,7 @@
    if (cmp > 0) {
       preferB = True; goto out;
    }
+
    /* If we get here, they are the same name. */
 
    /* In this case we could choose either (arbitrarily), but might as
@@ -1195,7 +1234,8 @@
       for (i = 0; i < j; i++) {
          if (i < j-1
              && di->symtab[i].addr   == di->symtab[i+1].addr
-             && di->symtab[i].size   == di->symtab[i+1].size) {
+             && di->symtab[i].size   == di->symtab[i+1].size
+             ) {
             n_merged++;
             /* merge the two into one */
 	    di->symtab[di->symtab_used++] 
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 431e04e..06f6988 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -46,6 +46,11 @@
 /* This module is also notable because it is linked into both 
    stage1 and stage2. */
 
+/* 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
+   why. */
+
 #include "pub_core_basics.h"     /* basic types */
 #include "pub_core_vkiscnums.h"  /* for syscall numbers */
 #include "pub_core_debuglog.h"   /* our own iface */
@@ -393,6 +398,88 @@
    return (UInt)block[0];
 }
 
+#elif defined(VGP_x86_darwin)
+
+/* Using _SYSNO_INDEX rather than _SYSNO_NUM assumes that these are
+   Unix-class syscalls (which they are).  Unfortunately _SYSNO_NUM
+   involves a C-style "cond ? :" expression which doesn't impress the
+   Darwin assembler very much. */
+__attribute__((noinline))
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+   UInt __res;
+   __asm__ volatile (
+      "movl  %2, %%eax\n"    /* push n */
+      "pushl %%eax\n"
+      "movl  %1, %%eax\n"    /* push buf */
+      "pushl %%eax\n"
+      "movl  $2, %%eax\n"    /* push stderr */
+      "pushl %%eax\n"
+      "movl  $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
+             ", %%eax\n"
+      "pushl %%eax\n"        /* push fake return address */
+      "int   $0x80\n"        /* write(stderr, buf, n) */
+      "jnc   1f\n"           /* jump if no error */
+      "movl  $-1, %%eax\n"   /* return -1 if error */
+      "1: "
+      "movl  %%eax, %0\n"    /* __res = eax */
+      "addl  $16, %%esp\n"   /* pop x4 */
+      : "=mr" (__res)
+      : "g" (buf), "g" (n)
+      : "eax", "edx", "cc"
+   );
+   return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+   UInt __res;
+   __asm__ volatile (
+      "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
+      "int  $0x80\n"       /* getpid() */
+      "movl %%eax, %0\n"   /* set __res = eax */
+      : "=mr" (__res)
+      :
+      : "eax", "cc" );
+   return __res;
+}
+
+#elif defined(VGP_amd64_darwin)
+
+__attribute__((noinline))
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+   UInt __res;
+   __asm__ volatile (
+      "movq  $2, %%rdi\n"    /* push stderr */
+      "movq  %1, %%rsi\n"    /* push buf */
+      "movl  %2, %%edx\n"    /* push n */
+      "movl  $"VG_STRINGIFY(VG_DARWIN_SYSNO_NUM(__NR_write_nocancel))
+             ", %%eax\n"
+      "syscall\n"            /* write(stderr, buf, n) */
+      "jnc   1f\n"           /* jump if no error */
+      "movq  $-1, %%rax\n"   /* return -1 if error */
+      "1: "
+      "movl  %%eax, %0\n"    /* __res = eax */
+      : "=mr" (__res)
+      : "g" (buf), "g" (n)
+      : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
+   return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+   UInt __res;
+   __asm__ volatile (
+      "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_NUM(__NR_getpid))", %%eax\n"
+      "syscall\n"          /* getpid() */
+      "movl %%eax, %0\n"   /* set __res = eax */
+      : "=mr" (__res)
+      :
+      : "rax", "rcx", "cc" );
+   return __res;
+}
+
 #else
 # error Unknown platform
 #endif
diff --git a/coregrind/m_dispatch/dispatch-amd64-darwin.S b/coregrind/m_dispatch/dispatch-amd64-darwin.S
new file mode 100644
index 0000000..bc095e4
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-amd64-darwin.S
@@ -0,0 +1,331 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                      dispatch-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2007 Julian Seward 
+     jseward@acm.org
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_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_(run_innerloop) is used to    ---*/
+/*--- run all translations except no-redir ones.           ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Preamble (set everything up)                 ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
+*/
+
+.text
+.globl VG_(run_innerloop)
+VG_(run_innerloop):
+	/* %rdi holds guest_state */
+	/* %rsi holds do_profiling */
+	
+	/* ----- entry point to VG_(run_innerloop) ----- */
+	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
+	pushq	%rdi  /* guest_state */
+
+	movq	VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
+	movl	(%r15), %r15d
+	pushq	%r15
+
+	/* 8(%rsp) holds cached copy of guest_state ptr */
+	/* 0(%rsp) holds cached copy of VG_(dispatch_ctr) */
+
+	/* Set up the guest state pointer */
+	movq	%rdi, %rbp
+	
+	/* fetch %RIP into %rax */
+	movq	OFFSET_amd64_RIP(%rbp), %rax
+
+	/* 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
+
+	/* fall into main loop  (the right one) */
+	cmpq	$0, %rsi
+	je	VG_(run_innerloop__dispatch_unprofiled)
+	jmp	VG_(run_innerloop__dispatch_profiled)
+	/*NOTREACHED*/	
+
+/*----------------------------------------------------*/
+/*--- NO-PROFILING (standard) dispatcher           ---*/
+/*----------------------------------------------------*/
+
+.align	4
+.globl	VG_(run_innerloop__dispatch_unprofiled)
+VG_(run_innerloop__dispatch_unprofiled):
+	/* AT ENTRY: %rax is next guest addr, %rbp is possibly
+           modified guest state ptr */
+
+	/* Has the guest state pointer been messed with?  If yes, exit. */
+	cmpq	8(%rsp), %rbp
+	movq	VG_(tt_fast)@GOTPCREL(%rip), %rcx
+	jnz	gsp_changed
+
+	/* save the jump address in the guest state */
+	movq	%rax, OFFSET_amd64_RIP(%rbp)
+
+	/* Are we out of timeslice?  If yes, defer to scheduler. */
+	subl	$1, 0(%rsp)
+	jz	counter_is_zero
+
+	/* try a fast lookup in the translation cache */
+	movq	%rax, %rbx
+	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 */
+	/* generated code should run, then jump back to
+	   VG_(run_innerloop__dispatch_unprofiled). */
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- PROFILING dispatcher (can be much slower)    ---*/
+/*----------------------------------------------------*/
+
+.align	4
+.globl	VG_(run_innerloop__dispatch_profiled)
+VG_(run_innerloop__dispatch_profiled):
+	/* AT ENTRY: %rax is next guest addr, %rbp is possibly
+           modified guest state ptr */
+
+	/* Has the guest state pointer been messed with?  If yes, exit. */
+	cmpq	8(%rsp), %rbp
+	movq	VG_(tt_fast)@GOTPCREL(%rip), %rcx
+	jnz	gsp_changed
+
+	/* save the jump address in the guest state */
+	movq	%rax, OFFSET_amd64_RIP(%rbp)
+
+	/* Are we out of timeslice?  If yes, defer to scheduler. */
+	subl	$1, 0(%rsp)
+	jz	counter_is_zero
+
+	/* try a fast lookup in the translation cache */
+	movq	%rax, %rbx
+	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
+
+	/* increment bb profile counter */
+	movq	VG_(tt_fastN)@GOTPCREL(%rip), %rdx
+	shrq	$1, %rbx		/* entry# * sizeof(UInt*) */
+	movq	(%rdx,%rbx,1), %rdx
+	addl	$1, (%rdx)
+
+        /* Found a match.  Jump to .host. */
+	jmp 	*%r11
+	ud2	/* persuade insn decoders not to speculate past here */
+	/* generated code should run, then jump back to
+	   VG_(run_innerloop__dispatch_profiled). */
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- exit points                                  ---*/
+/*----------------------------------------------------*/
+
+gsp_changed:
+	/* Someone messed with the gsp.  Have to
+           defer to scheduler to resolve this.  dispatch ctr
+	   is not yet decremented, so no need to increment. */
+	/* %RIP is NOT up to date here.  First, need to write
+	   %rax back to %RIP, but without trashing %rbp since
+	   that holds the value we want to return to the scheduler.
+	   Hence use %r15 transiently for the guest state pointer. */
+	movq	8(%rsp), %r15
+	movq	%rax, OFFSET_amd64_RIP(%r15)
+	movq	%rbp, %rax
+	jmp	run_innerloop_exit
+	/*NOTREACHED*/
+
+counter_is_zero:
+	/* %RIP is up to date here */
+	/* back out decrement of the dispatch counter */
+	addl	$1, 0(%rsp)
+	movq	$VG_TRC_INNER_COUNTERZERO, %rax
+	jmp	run_innerloop_exit
+
+fast_lookup_failed:
+	/* %RIP is up to date here */
+	/* back out decrement of the dispatch counter */
+	addl	$1, 0(%rsp)
+	movq	$VG_TRC_INNER_FASTMISS, %rax
+	jmp	run_innerloop_exit
+
+
+
+/* All exits from the dispatcher go through here.  %rax holds
+   the return value. 
+*/
+run_innerloop_exit: 
+	/* We're leaving.  Check that nobody messed with
+           %mxcsr or %fpucw.  We can't mess with %rax here as it
+	   holds the tentative return value, but any other is 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 %eflags */
+	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	run_innerloop_exit_REALLY
+
+invariant_violation:
+	movq	$VG_TRC_INVARIANT_FAILED, %rax
+	jmp	run_innerloop_exit_REALLY
+
+run_innerloop_exit_REALLY:
+
+	/* restore VG_(dispatch_ctr) */	
+	popq	%r14
+	movq	VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
+	movl	%r14d, (%r15)
+
+	popq	%rdi
+	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
+	ret	
+
+	
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- A special dispatcher, for running no-redir           ---*/
+/*--- translations.  Just runs the given translation once. ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/* signature:
+void VG_(run_a_noredir_translation) ( UWord* argblock );
+*/
+
+/* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
+   and 2 to carry results:
+      0: input:  ptr to translation
+      1: input:  ptr to guest state
+      2: output: next guest PC
+      3: output: guest state pointer afterwards (== thread return code)
+*/
+.align 4
+.globl VG_(run_a_noredir_translation)
+VG_(run_a_noredir_translation):
+	/* Save callee-saves regs */
+	pushq %rbx
+	pushq %rbp
+	pushq %r12
+	pushq %r13
+	pushq %r14
+	pushq %r15
+
+	pushq %rdi  /* we will need it after running the translation */
+	movq 8(%rdi), %rbp
+	jmp *0(%rdi)
+	/*NOTREACHED*/
+	ud2
+	/* If the translation has been correctly constructed, we
+	should resume at the the following label. */
+.globl VG_(run_a_noredir_translation__return_point)
+VG_(run_a_noredir_translation__return_point):
+	popq %rdi
+	movq %rax, 16(%rdi)
+	movq %rbp, 24(%rdi)
+
+	popq  %r15
+	popq  %r14
+	popq  %r13
+	popq  %r12
+	popq  %rbp
+	popq  %rbx
+	ret
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_dispatch/dispatch-x86-darwin.S b/coregrind/m_dispatch/dispatch-x86-darwin.S
new file mode 100644
index 0000000..11956a8
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-x86-darwin.S
@@ -0,0 +1,318 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                               dispatch-x86.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2006 Julian Seward 
+     jseward@acm.org
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_dispatch_asm.h"
+#include "pub_core_transtab_asm.h"
+#include "libvex_guest_offsets.h"	/* for OFFSET_x86_EIP */
+
+
+/* Global variables */
+/* These are defined here instead of in their respective C files to
+   avoid extra PIC branch code here. */
+.data
+.align 2
+
+/* m_transtab.c */
+.globl VG_(tt_fast)
+.align 4
+VG_(tt_fast):	.space VG_TT_FAST_SIZE*8, 0  /* (2*Addr) [VG_TT_FAST_SIZE] */
+.globl VG_(tt_fastN)
+VG_(tt_fastN):	.space VG_TT_FAST_SIZE*4, 0  /* (UInt *) [VG_TT_FAST_SIZE] */
+
+/* scheduler.c */
+.globl VG_(dispatch_ctr)
+VG_(dispatch_ctr):	.long 0
+
+	
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- The dispatch loop.  VG_(run_innerloop) is used to    ---*/
+/*--- run all translations except no-redir ones.           ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Preamble (set everything up)                 ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
+*/
+.text
+.globl VG_(run_innerloop)
+VG_(run_innerloop):
+	/* 4(%esp) holds guest_state */
+	/* 8(%esp) holds do_profiling */
+	
+	/* ----- entry point to VG_(run_innerloop) ----- */
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edx
+	pushl	%esi
+	pushl	%edi
+	pushl	%ebp
+	
+	/* 28(%esp) holds guest_state */
+	/* 32(%esp) holds do_profiling */
+
+	/* Set up the guest state pointer */
+	movl	28(%esp), %ebp
+	
+	/* fetch %EIP into %eax */
+	movl	OFFSET_x86_EIP(%ebp), %eax
+
+	/* 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
+	
+	/* fall into main loop (the right one) */
+	cmpl	$0, 32(%esp) /* do_profiling */
+	je	VG_(run_innerloop__dispatch_unprofiled)
+	jmp	VG_(run_innerloop__dispatch_profiled)
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- NO-PROFILING (standard) dispatcher           ---*/
+/*----------------------------------------------------*/
+
+.globl	VG_(run_innerloop__dispatch_unprofiled)
+VG_(run_innerloop__dispatch_unprofiled):
+	/* AT ENTRY: %eax is next guest addr, %ebp is possibly
+           modified guest state ptr */
+
+	/* Has the guest state pointer been messed with?  If yes, exit. */
+	cmpl	28(%esp), %ebp
+	jnz	gsp_changed
+
+	/* save the jump address in the guest state */
+	movl	%eax, OFFSET_x86_EIP(%ebp)
+
+	/* Are we out of timeslice?  If yes, defer to scheduler. */
+	subl	$1, VG_(dispatch_ctr)
+	jz	counter_is_zero
+
+	/* try a fast lookup in the translation cache */
+	movl	%eax, %ebx
+	andl	$VG_TT_FAST_MASK, %ebx
+	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 */
+	/* generated code should run, then jump back to
+	   VG_(run_innerloop__dispatch_unprofiled). */
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- PROFILING dispatcher (can be much slower)    ---*/
+/*----------------------------------------------------*/
+
+.globl	VG_(run_innerloop__dispatch_profiled)
+VG_(run_innerloop__dispatch_profiled):
+	/* AT ENTRY: %eax is next guest addr, %ebp is possibly
+           modified guest state ptr */
+
+	/* Has the guest state pointer been messed with?  If yes, exit. */
+	cmpl	28(%esp), %ebp
+	jnz	gsp_changed
+
+	/* save the jump address in the guest state */
+	movl	%eax, OFFSET_x86_EIP(%ebp)
+
+	/* Are we out of timeslice?  If yes, defer to scheduler. */
+	subl	$1, VG_(dispatch_ctr)
+	jz	counter_is_zero
+
+	/* try a fast lookup in the translation cache */
+	movl	%eax, %ebx
+	andl	$VG_TT_FAST_MASK, %ebx
+	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
+	/* increment bb profile counter */
+	/* note: innocuous as this sounds, it causes a huge amount more
+           stress on D1 and significantly slows everything down. */
+	movl	VG_(tt_fastN)(,%ebx,4), %edx
+	/* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
+	addl	$1, (%edx)
+
+	/* Found a match.  Jump to .host. */
+	jmp 	*%edi
+	ud2	/* persuade insn decoders not to speculate past here */
+	/* generated code should run, then jump back to
+	   VG_(run_innerloop__dispatch_profiled). */
+	/*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- exit points                                  ---*/
+/*----------------------------------------------------*/
+
+gsp_changed:
+	/* Someone messed with the gsp.  Have to
+           defer to scheduler to resolve this.  dispatch ctr
+	   is not yet decremented, so no need to increment. */
+	/* %EIP is NOT up to date here.  First, need to write
+	   %eax back to %EIP, but without trashing %ebp since
+	   that holds the value we want to return to the scheduler.
+	   Hence use %esi transiently for the guest state pointer. */
+	movl	28(%esp), %esi
+	movl	%eax, OFFSET_x86_EIP(%esi)
+	movl	%ebp, %eax
+	jmp	run_innerloop_exit
+	/*NOTREACHED*/
+
+counter_is_zero:
+	/* %EIP is up to date here */
+	/* back out decrement of the dispatch counter */
+	addl	$1, VG_(dispatch_ctr)
+	movl	$VG_TRC_INNER_COUNTERZERO, %eax
+	jmp	run_innerloop_exit
+	/*NOTREACHED*/
+
+fast_lookup_failed:
+	/* %EIP is up to date here */
+	/* back out decrement of the dispatch counter */
+	addl	$1, VG_(dispatch_ctr)
+	movl	$VG_TRC_INNER_FASTMISS, %eax
+	jmp	run_innerloop_exit
+	/*NOTREACHED*/
+
+
+
+/* All exits from the dispatcher go through here.  %eax holds
+   the return value. 
+*/
+run_innerloop_exit: 
+	/* We're leaving.  Check that nobody messed with
+           %mxcsr or %fpucw.  We can't mess with %eax here as it
+	   holds the tentative return value, but any other is OK. */
+#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	run_innerloop_exit_REALLY
+
+invariant_violation:
+	movl	$VG_TRC_INVARIANT_FAILED, %eax
+	jmp	run_innerloop_exit_REALLY
+
+run_innerloop_exit_REALLY:
+	popl	%ebp
+	popl	%edi
+	popl	%esi
+	popl	%edx
+	popl	%ecx
+	popl	%ebx
+	ret	
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- A special dispatcher, for running no-redir           ---*/
+/*--- translations.  Just runs the given translation once. ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/* signature:
+void VG_(run_a_noredir_translation) ( UWord* argblock );
+*/
+
+/* Run a no-redir translation.  argblock points to 4 UWords, 2 to carry args
+   and 2 to carry results:
+      0: input:  ptr to translation
+      1: input:  ptr to guest state
+      2: output: next guest PC
+      3: output: guest state pointer afterwards (== thread return code)
+*/
+.globl VG_(run_a_noredir_translation)
+VG_(run_a_noredir_translation):
+	/* Save callee-saves regs */
+	pushl %esi
+	pushl %edi
+	pushl %ebp
+	pushl %ebx
+
+	movl 20(%esp), %edi	/* %edi = argblock */
+	movl 4(%edi), %ebp	/* argblock[1] */
+	jmp *0(%edi)		/* argblock[0] */
+	/*NOTREACHED*/
+	ud2
+	/* If the translation has been correctly constructed, we
+	should resume at the the following label. */
+.globl VG_(run_a_noredir_translation__return_point)
+VG_(run_a_noredir_translation__return_point):
+	movl 20(%esp), %edi
+	movl %eax, 8(%edi)	/* argblock[2] */
+	movl %ebp, 12(%edi)	/* argblock[3] */
+
+	popl %ebx
+	popl %ebp
+	popl %edi
+	popl %esi
+	ret
+
+			
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/initimg-darwin.c b/coregrind/m_initimg/initimg-darwin.c
new file mode 100644
index 0000000..13da3bc
--- /dev/null
+++ b/coregrind/m_initimg/initimg-darwin.c
@@ -0,0 +1,621 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Darwin              ---*/
+/*---                                             initimg-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2007 Julian Seward
+      jseward@acm.org
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_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*/Addr*    client_ip)
+{
+   HChar* exe_name;
+   Int    ret;
+   SysRes res;
+
+   vg_assert( VG_(args_the_exename) != NULL);
+   exe_name = ML_(find_executable)( VG_(args_the_exename) );
+
+   if (!exe_name) {
+      VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
+      VG_(exit)(127);      // 127 is Posix NOTFOUND
+   }
+
+   VG_(memset)(info, 0, sizeof(*info));
+   ret = VG_(do_exec)(exe_name, info);
+
+   // The client was successfully loaded!  Continue.
+
+   /* 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);
+
+   /* Copy necessary bits of 'info' that were filled in */
+   *client_ip  = info->init_ip;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's environment                          ===*/
+/*====================================================================*/
+
+/* Prepare the client's environment.  This is basically a copy of our
+   environment, except:
+
+     DYLD_INSERT_LIBRARIES=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
+                ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
+                DYLD_INSERT_LIBRARIES
+
+   If this is missing, then it is added.
+
+   Also, remove any binding for VALGRIND_LAUNCHER=.  The client should
+   not be able to see this.
+
+   Also, add DYLD_SHARED_REGION=avoid, because V doesn't know how 
+   to process the dyld shared cache file.
+
+   Also, change VYLD_* (mangled by launcher) back to DYLD_*.
+
+   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)
+{
+   HChar* preload_core    = "vgpreload_core";
+   HChar* ld_preload      = "DYLD_INSERT_LIBRARIES=";
+   HChar* dyld_cache      = "DYLD_SHARED_REGION=";
+   HChar* dyld_cache_value= "avoid";
+   HChar* v_launcher      = VALGRIND_LAUNCHER "=";
+   Int    ld_preload_len  = VG_(strlen)( ld_preload );
+   Int    dyld_cache_len  = VG_(strlen)( dyld_cache );
+   Int    v_launcher_len  = VG_(strlen)( v_launcher );
+   Bool   ld_preload_done = False;
+   Bool   dyld_cache_done = False;
+   Int    vglib_len       = VG_(strlen)(VG_(libdir));
+
+   HChar** cpp;
+   HChar** ret;
+   HChar*  preload_tool_path;
+   Int     envc, i;
+
+   /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+      paths.  We might not need the space for vgpreload_<tool>.so, but it
+      doesn't hurt to over-allocate briefly.  The 16s are just cautious
+      slop. */
+   Int preload_core_path_len = vglib_len + sizeof(preload_core) 
+                                         + sizeof(VG_PLATFORM) + 16;
+   Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname) 
+                                         + sizeof(VG_PLATFORM) + 16;
+   Int preload_string_len    = preload_core_path_len + preload_tool_path_len;
+   HChar* preload_string     = VG_(malloc)("initimg-darwin.sce.1", preload_string_len);
+   vg_assert(preload_string);
+
+   /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
+      preload_string. */
+   preload_tool_path = VG_(malloc)("initimg-darwin.sce.2", preload_tool_path_len);
+   vg_assert(preload_tool_path);
+   VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+                 "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
+   if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
+      VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s", 
+                    VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
+   } else {
+      VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so", 
+                    VG_(libdir), preload_core, 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; cpp++)
+      envc++;
+
+   /* Allocate a new space */
+   ret = VG_(malloc) ("initimg-darwin.sce.3", 
+                      sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
+   vg_assert(ret);
+
+   /* 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; cpp++) {
+      if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
+         Int len = VG_(strlen)(*cpp) + preload_string_len;
+         HChar *cp = VG_(malloc)("initimg-darwin.sce.4", len);
+         vg_assert(cp);
+
+         VG_(snprintf)(cp, len, "%s%s:%s",
+                       ld_preload, preload_string, (*cpp)+ld_preload_len);
+
+         *cpp = cp;
+
+         ld_preload_done = True;
+      }
+      if (VG_(memcmp)(*cpp, dyld_cache, dyld_cache_len) == 0) {
+         Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
+         HChar *cp = VG_(malloc)("initimg-darwin.sce.4.2", len);
+         vg_assert(cp);
+
+         VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
+
+         *cpp = cp;
+
+         ld_preload_done = True;
+      }
+   }
+
+   /* Add the missing bits */
+   if (!ld_preload_done) {
+      Int len = ld_preload_len + preload_string_len;
+      HChar *cp = VG_(malloc) ("initimg-darwin.sce.5", len);
+      vg_assert(cp);
+
+      VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+      ret[envc++] = cp;
+   }
+   if (!dyld_cache_done) {
+      Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
+      HChar *cp = VG_(malloc) ("initimg-darwin.sce.5.2", len);
+      vg_assert(cp);
+
+      VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
+
+      ret[envc++] = cp;
+   }
+   
+
+   /* ret[0 .. envc-1] is live now. */
+   /* Find and remove a binding for VALGRIND_LAUNCHER. */
+   for (i = 0; i < envc; i++)
+      if (0 == VG_(memcmp)(ret[i], v_launcher, v_launcher_len))
+         break;
+
+   if (i < envc) {
+      for (; i < envc-1; i++)
+         ret[i] = ret[i+1];
+      envc--;
+   }
+
+   /* Change VYLD_ to DYLD */
+   for (i = 0; i < envc; i++) {
+      if (0 == VG_(strncmp)(ret[i], "VYLD_", 5)) {
+         ret[i][0] = 'D';
+      }
+   }
+
+
+   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 char *copy_str(char **tab, const char *str)
+{
+   char *cp = *tab;
+   char *orig = cp;
+
+   while(*str)
+      *cp++ = *str++;
+   *cp++ = '\0';
+
+   if (0)
+      VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
+
+   *tab = cp;
+
+   return orig;
+}
+
+
+/* ----------------------------------------------------------------
+ 
+   This sets up the client's initial stack, containing the args,
+   environment and aux vector.
+
+   The format of the stack on Darwin is:
+
+   higher address +-----------------+ <- clstack_end
+                  |                 |
+                  : string table    :
+                  |                 |
+                  +-----------------+
+                  | NULL            |
+                  +-----------------+
+                  | executable_path | (first arg to execve())
+                  +-----------------+
+                  | NULL            |
+                  -                 -
+                  | envp            |
+                  +-----------------+
+                  | NULL            |
+                  -                 -
+                  | argv            |
+                  +-----------------+
+                  | argc            |
+                  +-----------------+
+                  | mach_header *   | (dynamic only)
+   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.
+
+   ---------------------------------------------------------------- */
+
+static 
+Addr setup_client_stack( void*  init_sp,
+                         char** orig_envp, 
+                         const ExeInfo* info,
+                         Addr   clstack_end,
+                         SizeT  clstack_max_size )
+{
+   char **cpp;
+   char *strtab;		/* string table */
+   char *stringbase;
+   Addr *ptr;
+   unsigned stringsize;		/* total size of strings in bytes */
+   unsigned auxsize;		/* total size of auxv in bytes */
+   Int argc;			/* total argc */
+   Int envc;			/* total number of env vars */
+   unsigned stacksize;		/* total client stack size */
+   Addr client_SP;	        /* client stack base (initial SP) */
+   Addr clstack_start;
+   Int i;
+   Bool have_exename;
+
+   vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
+   vg_assert( VG_(args_for_client) );
+
+   /* ==================== compute sizes ==================== */
+
+   /* first of all, work out how big the client stack will be */
+   stringsize   = 0;
+   auxsize = 0;
+   have_exename = VG_(args_the_exename) != NULL;
+
+   /* paste on the extra args if the loader needs them (ie, the #! 
+      interpreter and its argument) */
+   argc = 0;
+   if (info->interp_name != NULL) {
+      argc++;
+      stringsize += VG_(strlen)(info->interp_name) + 1;
+   }
+   if (info->interp_args != NULL) {
+      argc++;
+      stringsize += VG_(strlen)(info->interp_args) + 1;
+   }
+
+   /* now scan the args we're given... */
+   if (have_exename)
+      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; cpp++) {
+      envc++;
+      stringsize += VG_(strlen)(*cpp) + 1;
+   }
+
+   /* Darwin executable_path + NULL */
+   auxsize += 2 * sizeof(Word);
+   if (info->executable_path) {
+       stringsize += 1 + VG_(strlen)(info->executable_path);
+   }
+
+   /* Darwin mach_header */
+   if (info->dynamic) auxsize += sizeof(Word);
+
+   /* OK, now we know how big the client stack is */
+   stacksize =
+      sizeof(Word) +                          /* argc */
+      (have_exename ? sizeof(char **) : 0) +  /* argc[0] == exename */
+      sizeof(char **)*argc +                  /* argv */
+      sizeof(char **) +	                      /* terminal NULL */
+      sizeof(char **)*envc +                  /* envp */
+      sizeof(char **) +	                      /* terminal NULL */
+      auxsize +                               /* auxv */
+      VG_ROUNDUP(stringsize, sizeof(Word));   /* strings (aligned) */
+
+   if (0) VG_(printf)("stacksize = %d\n", stacksize);
+
+   /* client_SP is the client's stack pointer */
+   client_SP = clstack_end - stacksize;
+   client_SP = VG_ROUNDDN(client_SP, 32); /* make stack 32 byte aligned */
+
+   /* base of the string table (aligned) */
+   stringbase = strtab = (char *)clstack_end 
+                         - VG_ROUNDUP(stringsize, sizeof(int));
+
+   /* The max stack size */
+   clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+   /* Darwin stack is chosen by the ume loader */
+   clstack_start = clstack_end - clstack_max_size;
+
+   /* Record stack extent -- needed for stack-change code. */
+   /* GrP fixme really? */
+   VG_(clstk_base) = clstack_start;
+   VG_(clstk_end)  = clstack_end;
+
+   if (0)
+      VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
+                  "clstack_start %p\n"
+                  "clstack_end   %p\n",
+	          stringsize, auxsize, stacksize, (Int)clstack_max_size,
+                  (void*)clstack_start, (void*)clstack_end);
+
+   /* ==================== allocate space ==================== */
+
+   /* Stack was allocated by the ume loader. */
+
+   /* ==================== create client stack ==================== */
+
+   ptr = (Addr*)client_SP;
+
+   /* --- mach_header --- */
+   if (info->dynamic) *ptr++ = info->text;
+
+   /* --- client argc --- */
+   *ptr++ = (Addr)(argc + (have_exename ? 1 : 0));
+
+   /* --- 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);
+   }
+
+   if (have_exename)
+      *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;
+
+   /* --- envp --- */
+   VG_(client_envp) = (Char **)ptr;
+   for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
+      *ptr = (Addr)copy_str(&strtab, *cpp);
+   *ptr++ = 0;
+
+   /* --- executable_path + NULL --- */
+   if (info->executable_path) 
+       *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
+   else 
+       *ptr++ = 0;
+   *ptr++ = 0;
+
+   vg_assert((strtab-stringbase) == stringsize);
+
+   /* client_SP is pointing at client's argc/argv */
+
+   if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
+   return client_SP;
+}
+
+
+/*====================================================================*/
+/*=== Record system memory regions                                 ===*/
+/*====================================================================*/
+
+static void record_system_memory(void)
+{
+   /* Tell aspacem where the client's kernel commpage is */
+#if defined(VGA_amd64)
+   /* commpage 0x7fff:ffe00000+ - not in vm_region */
+   // GrP fixme check again
+   VG_(am_notify_client_mmap)(0x7fffffe00000, 0x7ffffffff000-0x7fffffe00000,
+                              VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
+
+#elif defined(VGA_x86)
+   /* commpage 0xfffec000+ - not in vm_region */
+   // GrP fixme check again
+   VG_(am_notify_client_mmap)(0xfffec000, 0xfffff000-0xfffec000,
+                              VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
+
+#else
+#  error unknown architecture
+#endif  
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(ii_create_image)                              ===*/
+/*====================================================================*/
+
+/* Create the client's initial memory image. */
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+   ExeInfo info;
+   HChar** env = NULL;
+
+   IIFinaliseImageInfo iifii;
+   VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+   //--------------------------------------------------------------
+   // Load client executable, finding in $PATH if necessary
+   //   p: get_helprequest_and_toolname()  [for 'exec', 'need_help']
+   //   p: layout_remaining_space          [so there's space]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "initimg", "Loading client\n");
+
+   if (VG_(args_the_exename) == NULL)
+      VG_(err_missing_prog)();
+
+   load_client(&info, &iifii.initial_client_IP);
+
+   //--------------------------------------------------------------
+   // Set up client's environment
+   //   p: set-libdir                   [for VG_(libdir)]
+   //   p: get_helprequest_and_toolname [for toolname]
+   //--------------------------------------------------------------
+   VG_(debugLog)(1, "initimg", "Setup client env\n");
+   env = setup_client_env(iicii.envp, iicii.toolname);
+
+   //--------------------------------------------------------------
+   // Setup client stack, eip, and VG_(client_arg[cv])
+   //   p: load_client()     [for 'info']
+   //   p: fix_environment() [for 'env']
+   //--------------------------------------------------------------
+   iicii.clstack_top = info.stack_end - 1;
+   iifii.clstack_max_size = info.stack_end - info.stack_start;
+   
+   iifii.initial_client_SP = 
+       setup_client_stack( iicii.argv - 1, env, &info, 
+                           iicii.clstack_top, iifii.clstack_max_size );
+
+   VG_(free)(env);
+
+   VG_(debugLog)(2, "initimg",
+                 "Client info: "
+                 "initial_IP=%p initial_SP=%p stack=%p..%p\n", 
+                 (void*)(iifii.initial_client_IP),
+                 (void*)(iifii.initial_client_SP),
+                 (void*)(info.stack_start), 
+                 (void*)(info.stack_end));
+
+
+   // Tell aspacem about commpage, etc
+   record_system_memory();
+
+   return iifii;
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(ii_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;
+
+   /* GrP fixme doesn't handle all registers from LC_THREAD or LC_UNIXTHREAD */
+
+#  if defined(VGP_x86_darwin)
+   vg_assert(0 == sizeof(VexGuestX86State) % 16);
+
+   /* 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;
+
+#  elif defined(VGP_amd64_darwin)
+   vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
+
+   /* 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;
+
+#  else
+#    error Unknown platform
+#  endif
+
+   /* Tell the tool that we just wrote to the registers. */
+   VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
+             sizeof(VexGuestArchState));
+}
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index 8dbded3..b6bdbbe 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -45,7 +45,7 @@
    Assertery.
    ------------------------------------------------------------------ */
 
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux)  ||  defined(VGP_x86_darwin)
 #  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)      \
       asm("call 0f;" \
           "0: popl %0;" \
@@ -54,7 +54,7 @@
           : "=r" (pc),\
             "=r" (sp),\
             "=r" (fp));
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux)  ||  defined(VGP_amd64_darwin)
 #  define GET_REAL_PC_SP_AND_FP(pc, sp, fp)      \
       asm("leaq 0(%%rip), %0;" \
           "movq %%rsp, %1;" \
@@ -101,7 +101,7 @@
 {
 #if defined(VGO_linux)
    (void)VG_(do_syscall1)(__NR_exit_group, status );
-#elif defined(VGO_aix5)
+#elif defined(VGO_aix5) || defined(VGO_darwin)
    (void)VG_(do_syscall1)(__NR_exit, status );
 #else
 #  error Unknown OS
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index 42aba3e..3614b92 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -155,6 +155,15 @@
    return n;
 }
 
+Char VG_(tolower) ( Char c )
+{
+   if ( c >= 'A'  &&  c <= 'Z' ) {
+      return c - 'A' + 'a';
+   } else {
+      return c;
+   }
+}
+
 /* ---------------------------------------------------------------------
    String functions
    ------------------------------------------------------------------ */
@@ -247,6 +256,22 @@
    }
 }
 
+Int VG_(strcasecmp) ( const Char* s1, const Char* s2 )
+{
+   while (True) {
+      UChar c1 = (UChar)VG_(tolower)(*s1);
+      UChar c2 = (UChar)VG_(tolower)(*s2);
+      if (c1 == 0 && c2 == 0) return 0;
+      if (c1 == 0) return -1;
+      if (c2 == 0) return 1;
+
+      if (c1 < c2) return -1;
+      if (c1 > c2) return 1;
+
+      s1++; s2++;
+   }
+}
+
 Int VG_(strncmp) ( const Char* s1, const Char* s2, SizeT nmax )
 {
    SizeT n = 0;
@@ -263,6 +288,26 @@
    }
 }
 
+Int VG_(strncasecmp) ( const Char* s1, const Char* s2, SizeT nmax )
+{
+   Int n = 0;
+   while (True) {
+      UChar c1;
+      UChar c2;
+      if (n >= nmax) return 0;
+      c1 = (UChar)VG_(tolower)(*s1);
+      c2 = (UChar)VG_(tolower)(*s2);
+      if (c1 == 0 && c2 == 0) return 0;
+      if (c1 == 0) return -1;
+      if (c2 == 0) return 1;
+
+      if (c1 < c2) return -1;
+      if (c1 > c2) return 1;
+
+      s1++; s2++; n++;
+   }
+}
+
 Char* VG_(strstr) ( const Char* haystack, Char* needle )
 {
    SizeT n; 
@@ -278,6 +323,21 @@
    }
 }
 
+Char* VG_(strcasestr) ( const Char* haystack, Char* needle )
+{
+   Int n; 
+   if (haystack == NULL)
+      return NULL;
+   n = VG_(strlen)(needle);
+   while (True) {
+      if (haystack[0] == 0) 
+         return NULL;
+      if (VG_(strncasecmp)(haystack, needle, n) == 0) 
+         return (Char*)haystack;
+      haystack++;
+   }
+}
+
 Char* VG_(strchr) ( const Char* s, Char c )
 {
    while (True) {
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index 9cddfc0..72a9ea6 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -41,6 +41,11 @@
 #include "pub_core_clientstate.h"   // VG_(fd_hard_limit)
 #include "pub_core_syscall.h"
 
+/* 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
+   why. */
+
 /* ---------------------------------------------------------------------
    File stuff
    ------------------------------------------------------------------ */
@@ -87,6 +92,17 @@
    I_die_here; /* maybe just return False? */
    return False;
 
+#  elif defined(VGO_darwin)
+   HChar tmp[VKI_MAXPATHLEN+1];
+   if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
+      if (n_buf > 0) {
+         VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
+         buf[n_buf-1] = 0;
+      }
+      if (tmp[0] == '/') return True;
+   }
+   return False;
+
 #  else
 #     error Unknown OS
 #  endif
@@ -94,19 +110,40 @@
 
 SysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
 {  
-   SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
+#  if defined(VGO_linux) || defined(VGO_aix5)
+   SysRes res = VG_(do_syscall3)(__NR_open,
+                                 (UWord)pathname, flags, mode);
+#  elif defined(VGO_darwin)
+   SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
+                                 (UWord)pathname, flags, mode);
+#  else
+#    error Unknown OS
+#  endif
    return res;
 }
 
 void VG_(close) ( Int fd )
 {
+   /* Hmm.  Return value is not checked.  That's uncool. */
+#  if defined(VGO_linux) || defined(VGO_aix5)
    (void)VG_(do_syscall1)(__NR_close, fd);
+#  elif defined(VGO_darwin)
+   (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
+#  else
+#    error Unknown OS
+#  endif
 }
 
 Int VG_(read) ( Int fd, void* buf, Int count)
 {
    Int    ret;
+#  if defined(VGO_linux) || defined(VGO_aix5)
    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);
+#  else
+#    error Unknown OS
+#  endif
    if (sr_isError(res)) {
       ret = - (Int)(Word)sr_Err(res);
       vg_assert(ret < 0);
@@ -120,7 +157,13 @@
 Int VG_(write) ( Int fd, const void* buf, Int count)
 {
    Int    ret;
+#  if defined(VGO_linux) || defined(VGO_aix5)
    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);
+#  else
+#    error "Unknown OS"
+#  endif
    if (sr_isError(res)) {
       ret = - (Int)(Word)sr_Err(res);
       vg_assert(ret < 0);
@@ -137,6 +180,14 @@
 #  if defined(VGO_linux) || defined(VGO_aix5)
    SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
    return sr_isError(res) ? -1 : 0;
+#  elif defined(VGO_darwin)
+   /* __NR_pipe is UX64, so produces a double-word result */
+   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;
 #  else
 #    error "Unknown OS"
 #  endif
@@ -144,9 +195,12 @@
 
 OffT VG_(lseek) ( Int fd, OffT offset, Int whence )
 {
-#if defined(VGO_linux) || defined(VGO_aix5)
+#  if defined(VGO_linux) || defined(VGO_aix5) || defined(VGP_amd64_darwin)
    SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
    vg_assert(sizeof(OffT) == sizeof(Word));
+#  elif defined(VGP_x86_darwin)
+   SysRes res = VG_(do_syscall4)(__NR_lseek, fd, 
+                                 offset & 0xffffffff, offset >> 32, whence);
 #  else
 #    error "Unknown plat"
 #  endif
@@ -185,7 +239,7 @@
    SysRes res;
    VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
 
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_darwin)
    /* First try with stat64.  If that doesn't work out, fall back to
       the vanilla version. */
 #  if defined(__NR_stat64)
@@ -235,7 +289,7 @@
    SysRes res;
    VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
 
-#  if defined(VGO_linux)
+#  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)
@@ -289,7 +343,7 @@
 
 SysRes VG_(dup2) ( Int oldfd, Int newfd )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux)  ||  defined(VGO_darwin)
    return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
 #  elif defined(VGO_aix5)
    I_die_here;
@@ -301,7 +355,13 @@
 /* Returns -1 on error. */
 Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
 {
+#  if defined(VGO_linux) || defined(VGO_aix5)
    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);
+#  else
+#    error "Unknown OS"
+#  endif
    return sr_isError(res) ? -1 : sr_Res(res);
 }
 
@@ -349,8 +409,8 @@
         return True;
      }
    }
-#  elif defined(VGO_aix5)
-   /* We can't ask the kernel, so instead rely on launcher-aix5.c to
+#  elif defined(VGO_aix5) || defined(VGO_darwin)
+   /* We can't ask the kernel, so instead rely on launcher-*.c to
       tell us the startup path.  Note the env var is keyed to the
       parent's PID, not ours, since our parent is the launcher
       process. */
@@ -399,6 +459,8 @@
    /* res = getdents( fd, dirp, count ); */
    res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
    return sr_isError(res) ? -1 : sr_Res(res);
+#  elif defined(VGO_darwin)
+   I_die_here;
 #  else
 #    error "Unknown OS"
 #  endif
@@ -503,9 +565,10 @@
    return 0;
 }
 
-/* Note this moves (or at least, is believed to move) the file pointer
+/* DDD: Note this moves (or at least, is believed to move) the file pointer
    on Linux and AIX5 but doesn't on Darwin.  This inconsistency should
-   be fixed. */
+   be fixed.  (In other words, why isn't the Linux/AIX5 version implemented in
+   terms of pread()?) */
 SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
 {
    SysRes res;
@@ -516,6 +579,14 @@
       return VG_(mk_SysRes_Error)( VKI_EINVAL );
    res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count );
    return res;
+#  elif defined(VGP_amd64_darwin)
+   res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
+   return res;
+#  elif defined(VGP_x86_darwin)
+   /* ppc32-darwin is the same, but with the args inverted */
+   res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count, 
+                          offset & 0xffffffff, offset >> 32);
+   return res;
 #  else
 #    error "Unknown platform"
 #  endif
@@ -632,7 +703,7 @@
 */
 Int VG_(connect_via_socket)( UChar* str )
 {
-#  if defined(VGO_linux)
+#  if defined(VGO_linux) || defined(VGO_darwin)
    Int sd, res;
    struct vki_sockaddr_in servAddr;
    UInt   ip   = 0;
@@ -741,6 +812,20 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
+   if (!sr_isError(res)) {
+       // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
+       Int optval = 1;
+       SysRes res2;
+       res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET, 
+                               VKI_SO_NOSIGPIPE, (UWord)&optval, 
+                               sizeof(optval));
+       // ignore setsockopt() error
+   }
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown arch"
 #  endif
@@ -768,6 +853,12 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall3)(__NR_connect_nocancel,
+                          sockfd, (UWord)serv_addr, addrlen);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown arch"
 #  endif
@@ -776,9 +867,13 @@
 Int VG_(write_socket)( Int sd, void *msg, Int count )
 {
    /* This is actually send(). */
-   /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
+
+   /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on 
       errors on stream oriented sockets when the other end breaks the
-      connection. The EPIPE error is still returned. */
+      connection. The EPIPE error is still returned.
+
+      For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of 
+      SIGPIPE */
 
 #  if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
       || defined(VGP_ppc64_linux)
@@ -800,6 +895,11 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+   SysRes res;
+   res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -826,6 +926,12 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall3)( __NR_getsockname,
+                           (UWord)sd, (UWord)name, (UWord)namelen );
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -852,6 +958,12 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall3)( __NR_getpeername,
+                           (UWord)sd, (UWord)name, (UWord)namelen );
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
@@ -882,12 +994,96 @@
 #  elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
    I_die_here;
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall5)( __NR_getsockopt,
+                           (UWord)sd, (UWord)level, (UWord)optname, 
+                           (UWord)optval, (UWord)optlen );
+   return sr_isError(res) ? -1 : sr_Res(res);
+
 #  else
 #    error "Unknown platform"
 #  endif
 }
 
 
+Char *VG_(basename)(const Char *path)
+{
+   static Char buf[VKI_PATH_MAX];
+   
+   const Char *p, *end;
+
+   if (path == NULL  ||  
+       0 == VG_(strcmp)(path, ""))
+   {
+      return ".";
+   }
+
+   p = path + VG_(strlen)(path);
+   while (p > path  &&  *p == '/') {
+      // skip all trailing '/'
+      p--;
+   }
+
+   if (p == path  &&  *p == '/') return "/"; // all slashes
+
+   end = p;
+
+   while (p > path  &&  *p != '/') {
+      // now skip non '/'
+      p--;
+   }
+
+   if (*p == '/') p++;
+
+   VG_(strncpy)(buf, p, end-p+1);
+   buf[end-p+1] = '\0';
+
+   return buf;
+}
+
+
+Char *VG_(dirname)(const Char *path)
+{
+   static Char buf[VKI_PATH_MAX];
+    
+   const Char *p;
+
+   if (path == NULL  ||  
+       0 == VG_(strcmp)(path, "")  ||  
+       0 == VG_(strcmp)(path, "/"))
+   {
+      return ".";
+   }
+
+   p = path + VG_(strlen)(path);
+   while (p > path  &&  *p == '/') {
+      // skip all trailing '/'
+      p--;
+   }
+
+   while (p > path  &&  *p != '/') {
+      // now skip non '/'
+      p--;
+   }
+
+   if (p == path) {
+      if (*p == '/') return "/"; // all slashes
+      else return "."; // no slashes
+   } 
+
+   while (p > path  &&  *p == '/') {
+      // skip '/' again
+      p--;
+   }
+
+   VG_(strncpy)(buf, path, p-path+1);
+   buf[p-path+1] = '\0';
+
+   return buf;
+}
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 86ebd23..1c02ba4 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -42,6 +42,17 @@
 #include "pub_core_xarray.h"
 #include "pub_core_clientstate.h"
 
+#if defined(VGO_darwin)
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach/mach.h>   /* mach_thread_self */
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+#endif
+
+/* 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
+   why. */
+
 /* ---------------------------------------------------------------------
    Command line and environment stuff
    ------------------------------------------------------------------ */
@@ -194,17 +205,32 @@
 // when starting child processes, so they don't see that added stuff.
 void VG_(env_remove_valgrind_env_stuff)(Char** envp)
 {
+
+#if defined(VGO_darwin)
+
+   // Environment cleanup is also handled during parent launch 
+   // in vg_preloaded.c:vg_cleanup_env().
+
+#endif
+
    Int i;
    Char* ld_preload_str = NULL;
    Char* ld_library_path_str = NULL;
+   Char* dyld_insert_libraries_str = NULL;
    Char* buf;
 
    // Find LD_* variables
+   // DDD: should probably conditionally compiled some of this:
+   // - LD_LIBRARY_PATH is universal?
+   // - LD_PRELOAD is on Linux, not on Darwin, not sure about AIX
+   // - 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)
          ld_preload_str = &envp[i][11];
       if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0)
          ld_library_path_str = &envp[i][16];
+      if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0)
+         dyld_insert_libraries_str = &envp[i][22];
    }
 
    buf = VG_(arena_malloc)(VG_AR_CORE, "libcproc.erves.1",
@@ -213,12 +239,16 @@
    // Remove Valgrind-specific entries from LD_*.
    VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
    mash_colon_env(ld_preload_str, buf);
+   mash_colon_env(dyld_insert_libraries_str, buf);
    VG_(sprintf)(buf, "%s*", VG_(libdir));
    mash_colon_env(ld_library_path_str, buf);
 
    // Remove VALGRIND_LAUNCHER variable.
    VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER);
 
+   // Remove DYLD_SHARED_REGION variable.
+   VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION");
+
    // XXX if variable becomes empty, remove it completely?
 
    VG_(arena_free)(VG_AR_CORE, buf);
@@ -231,7 +261,12 @@
 Int VG_(waitpid)(Int pid, Int *status, Int options)
 {
 #  if defined(VGO_linux)
-   SysRes res = VG_(do_syscall4)(__NR_wait4, pid, (UWord)status, options, 0);
+   SysRes res = VG_(do_syscall4)(__NR_wait4,
+                                 pid, (UWord)status, options, 0);
+   return sr_isError(res) ? -1 : sr_Res(res);
+#  elif defined(VGO_darwin)
+   SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel,
+                                 pid, (UWord)status, options, 0);
    return sr_isError(res) ? -1 : sr_Res(res);
 #  elif defined(VGO_aix5)
    /* magic number 4 obtained by truss-ing a C program doing
@@ -415,6 +450,11 @@
    r = sr_Res(res);
    return r;
 
+#  elif defined(VGO_darwin)
+   // Darwin's gettid syscall is something else.
+   // Use Mach thread ports for lwpid instead.
+   return mach_thread_self();
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -489,7 +529,8 @@
    return sr_Res(sres);
 
 #  elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
-        || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+        || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) \
+        || defined(VGO_darwin)
    SysRes sres;
    sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
    if (sr_isError(sres))
@@ -527,6 +568,17 @@
       return -1;
    return sr_Res(res);
 
+#  elif defined(VGO_darwin)
+   SysRes res;
+   res = VG_(do_syscall0)(__NR_fork); /* __NR_fork is UX64 */
+   if (sr_isError(res))
+      return -1;
+   /* on success: wLO = child pid; wHI = 1 for child, 0 for parent */
+   if (sr_ResHI(res) != 0) {
+      return 0;  /* this is child: return 0 instead of child pid */
+   }
+   return sr_Res(res);
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -576,6 +628,14 @@
    now  = ((ULong)sec1) * 1000000ULL;
    now += (ULong)(nsec / 1000);
 
+#  elif defined(VGO_darwin)
+   { SysRes res;
+     struct vki_timeval tv_now;
+     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;
+   }
+
 #  else
 #    error "Unknown OS"
 #  endif
@@ -652,6 +712,7 @@
          (*atforks[i].child)(tid);
 }
 
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c
index cd79b19..50aa2a8 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 */
 
+/* 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
+   why. */
+
 /* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on
    success and -1 on error.  */
 /* I believe the indexing scheme in ->sig[] is also correct for
@@ -181,6 +186,12 @@
                                  how, (UWord)set, (UWord)oldset);
 #  endif
 
+#  elif defined(VGO_darwin)
+   /* On Darwin, __NR_sigprocmask appears to affect the entire
+      process, not just this thread.  Hence need to use
+      __NR___pthread_sigmask instead. */
+   SysRes res =  VG_(do_syscall3)(__NR___pthread_sigmask, 
+                                  how, (UWord)set, (UWord)oldset);
 #  else
 #    error "Unknown OS"
 #  endif
@@ -188,6 +199,24 @@
 }
 
 
+#if defined(VGO_darwin)
+/* A helper function for sigaction on Darwin. */
+static 
+void darwin_signal_demux(void* a1, UWord a2, UWord a3, void* a4, void* a5) {
+   VG_(debugLog)(2, "libcsignal",
+                    "PRE  demux sig, a2 = %lu, signo = %lu\n", a2, a3);
+   if (a2 == 1)
+      ((void(*)(int))a1) (a3);
+   else
+      ((void(*)(int,void*,void*))a1) (a3,a4,a5);
+   VG_(debugLog)(2, "libcsignal",
+                    "POST demux sig, a2 = %lu, signo = %lu\n", a2, a3);
+   VG_(do_syscall2)(__NR_sigreturn, (UWord)a5, 0x1E);
+   /* NOTREACHED */
+   __asm__ __volatile__("ud2");
+}
+#endif
+
 Int VG_(sigaction) ( Int signum, 
                      const vki_sigaction_toK_t* act,  
                      vki_sigaction_fromK_t* oldact)
@@ -200,6 +229,51 @@
                                  _VKI_NSIG_WORDS * sizeof(UWord));
    return sr_isError(res) ? -1 : 0;
 
+#  elif defined(VGO_darwin)
+   /* If we're passing a new action to the kernel, make a copy of the
+      new action, install our own sa_tramp field in it, and ignore
+      whatever we were provided with.  This is OK because all the
+      sigaction requests come from m_signals, and are not directly
+      what the client program requested, so there is no chance that we
+      will inadvertantly ignore the sa_tramp field requested by the
+      client.  (In fact m_signals does ignore it when building signal
+      frames for the client, but that's a completely different
+      matter).
+
+      If we're receiving an old action from the kernel, be very
+      paranoid and make sure the kernel doesn't trash bits of memory
+      that we don't expect it to. */
+   SysRes res;
+
+   vki_sigaction_toK_t actCopy;
+   struct {
+     ULong before[2];
+     vki_sigaction_fromK_t oa;
+     ULong after[2];
+   }
+   oldactCopy;
+
+   vki_sigaction_toK_t*   real_act;
+   vki_sigaction_fromK_t* real_oldact;
+
+   real_act    = act    ? &actCopy       : NULL;
+   real_oldact = oldact ? &oldactCopy.oa : NULL;
+   VG_(memset)(&oldactCopy, 0x55, sizeof(oldactCopy));
+   if (real_act) {
+      *real_act = *act;
+      real_act->sa_tramp = (void*)&darwin_signal_demux;
+   }
+   res = VG_(do_syscall3)(__NR_sigaction, 
+                          signum, (UWord)real_act, (UWord)real_oldact);
+   if (real_oldact) {
+      vg_assert(oldactCopy.before[0] == 0x5555555555555555ULL);
+      vg_assert(oldactCopy.before[1] == 0x5555555555555555ULL);
+      vg_assert(oldactCopy.after[0]  == 0x5555555555555555ULL);
+      vg_assert(oldactCopy.after[1]  == 0x5555555555555555ULL);
+      *oldact = *real_oldact;
+   }
+   return sr_isError(res) ? -1 : 0;
+
 #  else
 #    error "Unsupported OS"
 #  endif
@@ -213,6 +287,11 @@
 {
 #  if defined(VGO_linux) || defined(VGO_aix5)
    *toK = *fromK;
+#  elif defined(VGO_darwin)
+   toK->ksa_handler = fromK->ksa_handler;
+   toK->sa_tramp    = NULL; /* the cause of all the difficulty */
+   toK->sa_mask     = fromK->sa_mask;
+   toK->sa_flags    = fromK->sa_flags;
 #  else
 #    error "Unsupported OS"
 #  endif
@@ -221,7 +300,14 @@
 
 Int VG_(kill)( Int pid, Int signo )
 {
+#  if defined(VGO_linux) || defined(VGO_aix5)
    SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo);
+#  elif defined(VGO_darwin)
+   SysRes res = VG_(do_syscall3)(__NR_kill,
+                                 pid, signo, 1/*posix-compliant*/);
+#  else
+#    error "Unsupported OS"
+#  endif
    return sr_isError(res) ? -1 : 0;
 }
 
@@ -234,6 +320,12 @@
       res = VG_(do_syscall2)(__NR_kill, lwpid, signo);
    return sr_isError(res) ? -1 : 0;
 
+#  elif defined(VGO_darwin)
+   // Note that the __pthread_kill syscall takes a Mach thread, not a pthread.
+   SysRes res;
+   res = VG_(do_syscall2)(__NR___pthread_kill, lwpid, signo);
+   return sr_isError(res) ? -1 : 0;
+
 #  else
 #    error "Unsupported plat"
 #  endif
@@ -360,8 +452,113 @@
   return i;
 }
 
+/* ---------- sigtimedwait_zero: Darwin ----------- */
+
+#elif defined(VGO_darwin)
+
+//static void show_set ( HChar* str, const vki_sigset_t* set ) {
+//   Int i;
+//   VG_(printf)("%s { ", str);
+//   for (i = 1; i <= _VKI_NSIG; i++) {
+//     if (VG_(sigismember)(set, i))
+//         VG_(printf)("%u ", i);
+//   }
+//   VG_(printf)("}\n");
+//}
+
+static void sigtimedwait_zero_handler ( Int sig ) 
+{
+   /* XXX this is wrong -- get rid of these.  We could
+      get _any_ signal here */
+   vg_assert(sig != VKI_SIGILL);
+   vg_assert(sig != VKI_SIGSEGV);
+   vg_assert(sig != VKI_SIGBUS);
+   vg_assert(sig != VKI_SIGTRAP);
+   /* do nothing */ 
+}
+
+Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, 
+                            vki_siginfo_t *info )
+{
+  const Bool debug = False;
+  Int    i, ir;
+  SysRes sr;
+  vki_sigset_t pending, blocked, allbutone;
+  vki_sigaction_toK_t   sa, saved_sa2;
+  vki_sigaction_fromK_t saved_sa;
+
+  //show_set("STWZ: looking for", set);
+
+  /* Find out what's pending: Darwin sigpending */
+  sr = VG_(do_syscall1)(__NR_sigpending, (UWord)&pending);
+  vg_assert(!sr_isError(sr));
+
+  /* don't try for signals not in 'set' */
+  /* pending = pending `intersect` set */
+  VG_(sigintersectset)(&pending, (vki_sigset_t*)set);
+
+  /* don't try for signals not blocked at the moment */
+  ir = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked);
+  vg_assert(ir == 0);
+
+  /* pending = pending `intersect` blocked */
+  VG_(sigintersectset)(&pending, &blocked);
+
+  /* decide which signal we're going to snarf */
+  for (i = 1; i < _VKI_NSIG; i++)
+     if (VG_(sigismember)(&pending,i))
+        break;
+
+  if (i == _VKI_NSIG)
+     return 0;
+
+  if (debug)
+     VG_(debugLog)(0, "libcsignal",
+                      "sigtimedwait_zero: snarfing signal %d\n", i );
+
+  /* fetch signal i.
+     pre: i is blocked and pending
+     pre: we are the only thread running 
+  */
+  /* Set up alternative signal handler */
+  VG_(sigfillset)(&sa.sa_mask);
+  sa.ksa_handler = &sigtimedwait_zero_handler;
+  sa.sa_flags    = 0;
+  ir = VG_(sigaction)(i, &sa, &saved_sa);
+  vg_assert(ir == 0);
+
+  /* Switch signal masks and wait for the signal.  This should happen
+     immediately, since we've already established it is pending and
+     blocked. */
+  VG_(sigfillset)(&allbutone);
+  VG_(sigdelset)(&allbutone, i);
+  /* Note: pass the sig mask by value here, not reference (!) */
+  vg_assert(_VKI_NSIG_WORDS == 1);
+  sr = VG_(do_syscall3)(__NR_sigsuspend_nocancel,
+                        (UWord)allbutone.sig[0], 0,0);
+  if (debug)
+     VG_(debugLog)(0, "libcsignal",
+                      "sigtimedwait_zero: sigsuspend got "
+                      "res: %s %#lx\n", 
+                      sr_isError(sr) ? "FAIL" : "SUCCESS",
+                      sr_isError(sr) ? sr_Err(sr) : sr_Res(sr));
+  vg_assert(sr_isError(sr));
+  vg_assert(sr_Err(sr) == VKI_EINTR);
+
+  /* Restore signal's handler to whatever it was before */
+  VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &saved_sa2 );
+  ir = VG_(sigaction)(i, &saved_sa2, NULL);
+  vg_assert(ir == 0);
+
+  /* This is bogus - we could get more info from the sighandler. */
+  VG_(memset)( info, 0, sizeof(*info) );
+  info->si_signo = i;
+
+  return i;
+}
+
 #else
-#  error Unknown OS
+#  error "Unknown OS"
 #endif
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_basics.c b/coregrind/m_mach/mach_basics.c
new file mode 100644
index 0000000..cd6df6c
--- /dev/null
+++ b/coregrind/m_mach/mach_basics.c
@@ -0,0 +1,101 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach interface functions                 mach_basics.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_mach.h"
+
+#if defined(VGO_darwin) 
+
+#include <mach/mach.h>
+#include <mach/machine/ndr_def.h>
+
+/* From mach_traps-<arch>-darwin.S */
+//extern mach_port_name_t host_self_trap(void);
+extern mach_port_name_t thread_self_trap(void);
+extern mach_port_t mach_reply_port(void);
+
+/* Global variables set in mach_init() */
+vm_size_t vm_page_size = 0;
+mach_port_name_t mach_task_self_ = 0;
+
+
+mach_port_name_t mach_thread_self(void)
+{
+    return thread_self_trap();
+}
+
+static mach_port_t reply = 0;
+
+mach_port_t mig_get_reply_port(void)
+{
+    if (!reply) reply = mach_reply_port();
+    return reply;
+    // GrP fixme is just one enough for valgrind's own use?
+    // might work if valgrind never blocks in mig calls on 
+    // its own behalf, and doesn't call mig outside the semaphore
+}
+
+
+void mig_dealloc_reply_port(mach_port_t reply_port)
+{
+}
+
+
+void mig_put_reply_port(mach_port_t reply_port)
+{
+}
+
+
+/* Initialize Mach global data. 
+   Should be called early in main(). */
+void VG_(mach_init)(void)
+{
+    reply = 0;
+    mach_task_self_ = task_self_trap();
+
+    // GrP fixme host_page_size(host_self_trap(), &vm_page_size);
+    vm_page_size = 4096;
+}
+
+
+#else
+
+// For platforms that don't actually have Mach kernel interfaces
+
+void VG_(mach_init)(void)
+{
+    // do nothing
+}
+
+#endif
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_msg.c b/coregrind/m_mach/mach_msg.c
new file mode 100644
index 0000000..0b9aa96
--- /dev/null
+++ b/coregrind/m_mach/mach_msg.c
@@ -0,0 +1,106 @@
+#include "pub_core_basics.h"
+#include "pub_core_mach.h"
+
+#if defined(VGO_darwin) 
+
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log:mach_msg.c,v $
+ * Revision 2.3  92/01/23  15:22:17  rpd
+ * Fixed to not pass MACH_SEND_INTERRUPT and MACH_RCV_INTERRUPT
+ * to the kernel.
+ * [92/01/20            rpd]
+ * 
+ * Revision 2.2  92/01/15  17:17:13  rpd
+ * Created from msg.c.
+ * [92/01/15            rpd]
+ * 
+ */
+
+#include <mach/port.h>
+#include <mach/message.h>
+
+#define LIBMACH_OPTIONS (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
+
+extern mach_msg_return_t 
+mach_msg_trap(mach_msg_header_t *msg, 
+              mach_msg_option_t option,
+              mach_msg_size_t send_size,
+              mach_msg_size_t rcv_size,
+              mach_port_t rcv_name,
+              mach_msg_timeout_t timeout,
+              mach_port_t notify);
+
+mach_msg_return_t
+mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify)
+    mach_msg_header_t *msg;
+    mach_msg_option_t option;
+    mach_msg_size_t send_size;
+    mach_msg_size_t rcv_size;
+    mach_port_t rcv_name;
+    mach_msg_timeout_t timeout;
+    mach_port_t notify;
+{
+    mach_msg_return_t mr;
+
+    /*
+     * Consider the following cases:
+     *1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
+     *plus special bits).
+     *2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
+     *3) RPC calls with interruptions in one/both halves.
+     *
+     * We refrain from passing the option bits that we implement
+     * to the kernel.  This prevents their presence from inhibiting
+     * the kernel's fast paths (when it checks the option value).
+     */
+
+    mr = mach_msg_trap(msg, option &~ LIBMACH_OPTIONS,
+                       send_size, rcv_size, rcv_name,
+                       timeout, notify);
+    if (mr == MACH_MSG_SUCCESS)
+        return MACH_MSG_SUCCESS;
+
+    if ((option & MACH_SEND_INTERRUPT) == 0)
+        while (mr == MACH_SEND_INTERRUPTED)
+            mr = mach_msg_trap(msg,
+                               option &~ LIBMACH_OPTIONS,
+                               send_size, rcv_size, rcv_name,
+                               timeout, notify);
+
+    if ((option & MACH_RCV_INTERRUPT) == 0)
+        while (mr == MACH_RCV_INTERRUPTED)
+            mr = mach_msg_trap(msg,
+                               option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
+                               0, rcv_size, rcv_name,
+                               timeout, notify);
+
+    return mr;
+}
+
+#endif
diff --git a/coregrind/m_mach/mach_traps-amd64-darwin.S b/coregrind/m_mach/mach_traps-amd64-darwin.S
new file mode 100644
index 0000000..7a85e41
--- /dev/null
+++ b/coregrind/m_mach/mach_traps-amd64-darwin.S
@@ -0,0 +1,136 @@
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach traps                                mach_traps.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2007 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "vki/vki-scnums-darwin.h"
+
+	// mach_port_name_t task_self_trap(void)
+	.text
+	.align 4
+	.globl _task_self_trap
+_task_self_trap:
+	movq	$__NR_task_self_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+// DDD: doesn't get used...
+//	// mach_port_name_t host_self_trap(void)
+//	.text
+//	.align 4
+//	.globl _host_self_trap
+//_host_self_trap:
+//	movq	$__NR_host_self_trap, %rax
+//	movq	%rcx, %r10
+//	syscall
+//	ret
+
+	// mach_port_name_t thread_self_trap(void)
+	.text
+	.align 4
+	.globl _thread_self_trap
+_thread_self_trap:
+	movq	$__NR_thread_self_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// mach_msg_return_t mach_msg_trap(...)
+	.text
+	.align 4
+	.globl _mach_msg_trap
+_mach_msg_trap:
+	movq	$__NR_mach_msg_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// mach_port_t mach_reply_port(...)
+	.text
+	.align 4
+	.globl _mach_reply_port
+_mach_reply_port:
+	movq	$__NR_mach_reply_port, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// boolean_t swtch_pri(int)
+	.text
+	.align 4
+	.globl _swtch_pri
+_swtch_pri:
+	movq	$__NR_swtch_pri, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// kern_return_t semaphore_wait(semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_wait
+_semaphore_wait:
+	movq	$__NR_semaphore_wait_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// kern_return_t semaphore_signal(semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_signal
+_semaphore_signal:
+	movq	$__NR_semaphore_signal_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// kern_return_t semaphore_signal_thread(semaphore_t, thread_t)
+	.text
+	.align 4
+	.globl _semaphore_signal_thread
+_semaphore_signal_thread:
+	movq	$__NR_semaphore_signal_thread_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+	// kern_return_t semaphore_wait_signal(semaphore_t, semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_wait_signal
+_semaphore_wait_signal:
+	movq	$__NR_semaphore_wait_signal_trap, %rax
+	movq	%rcx, %r10
+	syscall
+	ret
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_traps-x86-darwin.S b/coregrind/m_mach/mach_traps-x86-darwin.S
new file mode 100644
index 0000000..b843834
--- /dev/null
+++ b/coregrind/m_mach/mach_traps-x86-darwin.S
@@ -0,0 +1,124 @@
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach traps                                mach_traps.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   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.
+*/
+
+
+	// mach_port_name_t task_self_trap(void)
+	.text
+	.align 4
+	.globl _task_self_trap
+_task_self_trap:
+	mov	$-28, %eax
+	int	$0x81
+	ret
+
+	// mach_port_name_t host_self_trap(void)
+	.text
+	.align 4
+	.globl _host_self_trap
+_host_self_trap:
+	mov	$-29, %eax
+	int	$0x81
+	ret
+
+	// mach_port_name_t thread_self_trap(void)
+	.text
+	.align 4
+	.globl _thread_self_trap
+_thread_self_trap:
+	mov	$-27, %eax
+	int	$0x81
+	ret
+
+	// mach_msg_return_t mach_msg_trap(...)
+	.text
+	.align 4
+	.globl _mach_msg_trap
+_mach_msg_trap:
+	mov	$-31, %eax
+	int	$0x81
+	ret
+
+	// mach_port_t mach_reply_port(...)
+	.text
+	.align 4
+	.globl _mach_reply_port
+_mach_reply_port:
+	mov	$-26, %eax
+	int	$0x81
+	ret
+
+	// boolean_t swtch_pri(int)
+	.text
+	.align 4
+	.globl _swtch_pri
+_swtch_pri:
+	mov	$-59, %eax
+	int	$0x81
+	ret
+
+	// kern_return_t semaphore_wait(semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_wait
+_semaphore_wait:
+	mov	$-36, %eax
+	int	$0x81
+	ret
+
+	// kern_return_t semaphore_signal(semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_signal
+_semaphore_signal:
+	mov	$-33, %eax
+	int	$0x81
+	ret
+
+	// kern_return_t semaphore_signal_thread(semaphore_t, thread_t)
+	.text
+	.align 4
+	.globl _semaphore_signal_thread
+_semaphore_signal_thread:
+	mov	$-35, %eax
+	int	$0x81
+	ret
+
+	// kern_return_t semaphore_wait_signal(semaphore_t, semaphore_t)
+	.text
+	.align 4
+	.globl _semaphore_wait_signal
+_semaphore_wait_signal:
+	mov	$-37, %eax
+	int	$0x81
+	ret
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 0429bfe..e85b917 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -98,6 +98,8 @@
    VG_(threads)[tid].arch.vex_shadow2.guest_GPR3 = s2res;
    VG_(threads)[tid].arch.vex_shadow1.guest_GPR4 = s1err;
    VG_(threads)[tid].arch.vex_shadow2.guest_GPR4 = s2err;
+#  elif defined(VGO_darwin)
+   // GrP fixme darwin syscalls may return more values (2 registers plus error)
 #  else
 #    error "Unknown plat"
 #  endif
@@ -672,8 +674,8 @@
 // produce a pointer to the actual entry point for the function.
 void* VG_(fnptr_to_fnentry)( void* f )
 {
-#if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
-                           || defined(VGP_ppc32_linux)
+#if defined(VGP_x86_linux)   || defined(VGP_amd64_linux) || \
+    defined(VGP_ppc32_linux) || defined(VGO_darwin)
    return f;
 #elif defined(VGP_ppc64_linux) || defined(VGP_ppc32_aix5) \
                                || defined(VGP_ppc64_aix5)
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index e880e3c..f3dfbcd 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -48,6 +48,7 @@
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
 #include "pub_core_syscall.h"       // VG_(strerror)
+#include "pub_core_mach.h"
 #include "pub_core_machine.h"
 #include "pub_core_mallocfree.h"
 #include "pub_core_options.h"
@@ -435,6 +436,9 @@
 
       else if VG_STR_CLO (arg, "--kernel-variant",   VG_(clo_kernel_variant)) {}
 
+      else if VG_BOOL_CLO(arg, "--auto-run-dsymutil",
+                               VG_(clo_auto_run_dsymutil)) {}
+
       else if VG_BINT_CLO(arg, "--vex-iropt-verbosity",
                        VG_(clo_vex_control).iropt_verbosity, 0, 10) {}
       else if VG_BINT_CLO(arg, "--vex-iropt-level",
@@ -956,6 +960,14 @@
       rl.rlim_max = 1024;
    }
 
+#  if defined(VGO_darwin)
+   /* Darwin lies. It reports file max as RLIM_INFINITY but
+      silently disallows anything bigger than 10240. */
+   if (rl.rlim_cur >= 10240  &&  rl.rlim_max == 0x7fffffffffffffffULL) {
+      rl.rlim_max = 10240;
+   }
+#  endif
+
    if (show)
       VG_(printf)("fd limits: host, before: cur %lu max %lu\n", 
                   (UWord)rl.rlim_cur, (UWord)rl.rlim_max);
@@ -1153,6 +1165,14 @@
    VG_(client_envp) = (Char**)envp;
 
    //--------------------------------------------------------------
+   // Start up Mach kernel interface, if any
+   //   p: none
+   //--------------------------------------------------------------
+#  if defined(VGO_darwin)
+   VG_(mach_init)();
+#  endif
+
+   //--------------------------------------------------------------
    // Start up the logging mechanism
    //   p: none
    //--------------------------------------------------------------
@@ -1229,9 +1249,28 @@
 #  endif
 
    //--------------------------------------------------------------
+   // Darwin only: munmap address-space-filling segments
+   // (oversized pagezero or stack)
+   //   p: none
+   //--------------------------------------------------------------
+#if defined(VGO_darwin)
+# if VG_WORDSIZE == 4
+   VG_(do_syscall2)(__NR_munmap, 0x00000000, 0xf0000000);
+# else
+   // open up client space
+   VG_(do_syscall2)(__NR_munmap, 0x100000000, 0x700000000000-0x100000000);
+   // open up client stack and dyld
+   VG_(do_syscall2)(__NR_munmap, 0x7fff5c000000, 0x4000000);
+# endif
+#endif
+
+   //--------------------------------------------------------------
    // Ensure we're on a plausible stack.
    //   p: logging
    //--------------------------------------------------------------
+#if defined(VGO_darwin)
+   // Darwin doesn't use the interim stack.
+#else
    VG_(debugLog)(1, "main", "Checking current stack is plausible\n");
    { HChar* limLo  = (HChar*)(&VG_(interim_stack).bytes[0]);
      HChar* limHi  = limLo + sizeof(VG_(interim_stack));
@@ -1259,11 +1298,12 @@
       VG_(debugLog)(0, "main", "   Cannot continue.  Sorry.\n");
       VG_(exit)(1);
    }
+#endif
 
    //--------------------------------------------------------------
    // Start up the address space manager, and determine the
    // approximate location of the client's stack
-   //   p: logging, plausible-stack
+   //   p: logging, plausible-stack, darwin-munmap
    //--------------------------------------------------------------
    VG_(debugLog)(1, "main", "Starting the address space manager\n");
    vg_assert(VKI_PAGE_SIZE     == 4096 || VKI_PAGE_SIZE     == 65536);
@@ -1453,7 +1493,7 @@
    if (!need_help) {
       VG_(debugLog)(1, "main", "Create initial image\n");
 
-#     if defined(VGO_linux)
+#     if defined(VGO_linux) || defined(VGO_darwin)
       the_iicii.argv              = argv;
       the_iicii.envp              = envp;
       the_iicii.toolname          = toolname;
@@ -1509,6 +1549,10 @@
    // when it tries to open /proc/<pid>/cmdline for itself.
    //   p: setup file descriptors
    //--------------------------------------------------------------
+#if !HAVE_PROC
+   // client shouldn't be using /proc!
+   VG_(cl_cmdline_fd) = -1;
+#else
    if (!need_help) {
       HChar  buf[50], buf2[50+64];
       HChar  nul[1];
@@ -1546,6 +1590,7 @@
 
       VG_(cl_cmdline_fd) = fd;
    }
+#endif
 
    //--------------------------------------------------------------
    // Init tool part 1: pre_clo_init
@@ -1650,6 +1695,8 @@
       iters = 5;
 #     elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
       iters = 4;
+#     elif defined(VGO_darwin)
+      iters = 3;
 #     else
 #       error "Unknown plat"
 #     endif
@@ -1752,6 +1799,20 @@
 
      VG_(free)(changes);
    }
+#  elif defined(VGO_darwin)
+   { Addr* seg_starts;
+     Int   n_seg_starts;
+     seg_starts = VG_(get_segment_starts)( &n_seg_starts );
+     vg_assert(seg_starts && n_seg_starts >= 0);
+
+     /* show them all to the debug info reader.  
+        Don't read from V segments (unlike Linux) */
+     // GrP fixme really?
+     for (i = 0; i < n_seg_starts; i++)
+        VG_(di_notify_mmap)( seg_starts[i], False/*don't allow_SkFileV*/ );
+
+     VG_(free)( seg_starts );
+   }
 #  else
 #    error Unknown OS
 #  endif
@@ -2168,6 +2229,13 @@
       /* We were killed by a fatal signal, so replicate the effect */
       vg_assert(VG_(threads)[tid].os_state.fatalsig != 0);
       VG_(kill_self)(VG_(threads)[tid].os_state.fatalsig);
+      /* we shouldn't be alive at this point.  But VG_(kill_self)
+         sometimes fails with EPERM on Darwin, for unclear reasons. */
+#     if defined(VGO_darwin)
+      VG_(debugLog)(0, "main", "VG_(kill_self) failed.  Exiting normally.\n");
+      VG_(exit)(0); /* bogus, but we really need to exit now */
+      /* fall through .. */
+#     endif
       VG_(core_panic)("main(): signal was supposed to be fatal");
       break;
 
@@ -2181,9 +2249,11 @@
 /* Final clean-up before terminating the process.  
    Clean up the client by calling __libc_freeres() (if requested) 
    This is Linux-specific?
+   GrP fixme glibc-specific, anyway
 */
 static void final_tidyup(ThreadId tid)
 {
+#if !defined(VGO_darwin)
 #  if defined(VGP_ppc64_linux)
    Addr r2;
 #  endif
@@ -2247,6 +2317,7 @@
    VG_(scheduler)(tid);
 
    vg_assert(VG_(is_exiting)(tid));
+#endif
 }
 
 
@@ -2585,6 +2656,59 @@
 void max_pw_passlen       ( void ) { vg_assert(0); }
 
 
+/*====================================================================*/
+/*=== Getting to main() alive: darwin                              ===*/
+/*====================================================================*/
+
+#elif defined(VGO_darwin)
+
+void* __memcpy_chk(void *dest, const void *src, SizeT n, SizeT n2);
+void* __memcpy_chk(void *dest, const void *src, SizeT n, SizeT n2) {
+    // skip check
+   return VG_(memcpy)(dest,src,n);
+}
+void* __memset_chk(void *s, int c, SizeT n, SizeT n2);
+void* __memset_chk(void *s, int c, SizeT n, SizeT n2) {
+    // skip check
+  return VG_(memset)(s,c,n);
+}
+void bzero(void *s, SizeT n);
+void bzero(void *s, SizeT n) {
+    VG_(memset)(s,0,n);
+}
+
+void* memcpy(void *dest, const void *src, SizeT n);
+void* memcpy(void *dest, const void *src, SizeT n) {
+   return VG_(memcpy)(dest,src,n);
+}
+void* memset(void *s, int c, SizeT n);
+void* memset(void *s, int c, SizeT n) {
+  return VG_(memset)(s,c,n);
+}
+
+/* _start in m_start-<arch>-darwin.S calls _start_in_C_darwin(). */
+
+/* Avoid compiler warnings: this fn _is_ used, but labelling it
+   'static' causes gcc to complain it isn't. */
+void _start_in_C_darwin ( UWord* pArgc );
+void _start_in_C_darwin ( UWord* pArgc )
+{
+   Int     r;
+   Int    argc = *(Int *)pArgc;  // not pArgc[0] on LP64
+   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"
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 2a06fcd..089ed1d 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -90,6 +90,7 @@
 Bool   VG_(clo_wait_for_gdb)   = False;
 VgSmc  VG_(clo_smc_check)      = Vg_SmcStack;
 HChar* VG_(clo_kernel_variant) = NULL;
+Bool   VG_(clo_auto_run_dsymutil) = False;
 
 
 /*====================================================================*/
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index d31d90f..d824a79 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -940,6 +940,27 @@
 #  elif defined(VGP_ppc64_aix5)
    /* nothing so far */
 
+#  elif defined(VGO_darwin)
+   /* If we're using memcheck, use these intercepts right from
+      the start, otherwise dyld makes a lot of noise. */
+   if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+      add_hardwired_spec("dyld", "strcmp",
+                         (Addr)&VG_(darwin_REDIR_FOR_strcmp), NULL);
+      add_hardwired_spec("dyld", "strlen",
+                         (Addr)&VG_(darwin_REDIR_FOR_strlen), NULL);
+      add_hardwired_spec("dyld", "strcat",
+                         (Addr)&VG_(darwin_REDIR_FOR_strcat), NULL);
+      add_hardwired_spec("dyld", "strcpy",
+                         (Addr)&VG_(darwin_REDIR_FOR_strcpy), NULL);
+      add_hardwired_spec("dyld", "strlcat",
+                         (Addr)&VG_(darwin_REDIR_FOR_strlcat), NULL);
+#if defined(VGP_amd64_darwin)
+      // DDD: #warning fixme rdar://6166275
+      add_hardwired_spec("dyld", "arc4random",
+                         (Addr)&VG_(darwin_REDIR_FOR_arc4random), NULL);
+#endif
+   }
+
 #  else
 #    error Unknown platform
 #  endif
diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c
index 5e2757b..b36e802 100644
--- a/coregrind/m_replacemalloc/vg_replace_malloc.c
+++ b/coregrind/m_replacemalloc/vg_replace_malloc.c
@@ -144,6 +144,21 @@
       return v; \
    }
 
+#define ZONEALLOC_or_NULL(soname, fnname, vg_replacement) \
+   \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, SizeT n); \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, SizeT n)  \
+   { \
+      void* v; \
+      \
+      if (!init_done) init(); \
+      MALLOC_TRACE(#fnname "(%p, %llu)", zone, (ULong)n ); \
+      \
+      v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, n ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
 
 /* Generate a replacement for 'fnname' in object 'soname', which calls
    'vg_replacement' to allocate memory.  If that fails, it bombs the
@@ -178,6 +193,8 @@
 ALLOC_or_NULL(VG_Z_LIBC_SONAME,      malloc,      malloc);
 #if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
 ALLOC_or_NULL(VG_Z_LIBC_SONAME,      malloc_common, malloc);
+#elif defined(VGO_darwin)
+ZONEALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc_zone_malloc, malloc);
 #endif
 
 
@@ -197,7 +214,7 @@
 #endif
 
 // operator new(unsigned long), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGO_darwin)
  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwm,          __builtin_new);
  ALLOC_or_BOMB(VG_Z_LIBC_SONAME,      _Znwm,          __builtin_new);
 #endif
@@ -217,7 +234,7 @@
 #endif
 
 // operator new(unsigned long, std::nothrow_t const&), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwmRKSt9nothrow_t,  __builtin_new);
  ALLOC_or_NULL(VG_Z_LIBC_SONAME,      _ZnwmRKSt9nothrow_t,  __builtin_new);
 #endif
@@ -241,7 +258,7 @@
 #endif
 
 // operator new[](unsigned long), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
  ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znam,             __builtin_vec_new );
  ALLOC_or_BOMB(VG_Z_LIBC_SONAME,      _Znam,             __builtin_vec_new );
 #endif
@@ -261,7 +278,7 @@
 #endif
 
 // operator new[](unsigned long, std::nothrow_t const&), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
  ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new );
  ALLOC_or_NULL(VG_Z_LIBC_SONAME,      _ZnamRKSt9nothrow_t, __builtin_vec_new );
 #endif
@@ -277,6 +294,18 @@
 /* Generate a replacement for 'fnname' in object 'soname', which calls
    'vg_replacement' to free previously allocated memory.
 */
+#define ZONEFREE(soname, fnname, vg_replacement) \
+   \
+   void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, void *p); \
+   void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, void *p)  \
+   { \
+      if (!init_done) init(); \
+      MALLOC_TRACE(#vg_replacement "(%p, %p)", zone, p ); \
+      if (p == NULL)  \
+         return; \
+      (void)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, p ); \
+   }
+
 #define FREE(soname, fnname, vg_replacement) \
    \
    void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *p); \
@@ -294,6 +323,8 @@
 FREE(VG_Z_LIBC_SONAME,       free,                 free );
 #if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
 FREE(VG_Z_LIBC_SONAME,       free_common,          free );
+#elif defined(VGO_darwin)
+ZONEFREE(VG_Z_LIBC_SONAME,   malloc_zone_free,     free );
 #endif
 
 
@@ -350,6 +381,21 @@
 
 /*---------------------- calloc ----------------------*/
 
+#define ZONECALLOC(soname, fnname) \
+   \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT nmemb, SizeT size ); \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT nmemb, SizeT size )  \
+   { \
+      void* v; \
+      \
+      if (!init_done) init(); \
+      MALLOC_TRACE("calloc(%p, %llu,%llu)", zone, (ULong)nmemb, (ULong)size ); \
+      \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_calloc, nmemb, size ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
 #define CALLOC(soname, fnname) \
    \
    void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT nmemb, SizeT size ); \
@@ -368,11 +414,37 @@
 CALLOC(VG_Z_LIBC_SONAME, calloc);
 #if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
 CALLOC(VG_Z_LIBC_SONAME, calloc_common);
+#elif defined(VGO_darwin)
+ZONECALLOC(VG_Z_LIBC_SONAME, malloc_zone_calloc);
 #endif
 
 
 /*---------------------- realloc ----------------------*/
 
+#define ZONEREALLOC(soname, fnname) \
+   \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, void* ptrV, SizeT new_size );\
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, void* ptrV, SizeT new_size ) \
+   { \
+      void* v; \
+      \
+      if (!init_done) init(); \
+      MALLOC_TRACE("realloc(%p,%p,%llu)", zone, ptrV, (ULong)new_size ); \
+      \
+      if (ptrV == NULL) \
+         /* We need to call a malloc-like function; so let's use \
+            one which we know exists. GrP fixme use zonemalloc instead? */ \
+         return VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,malloc) (new_size); \
+      if (new_size <= 0) { \
+         VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,free)(ptrV); \
+         MALLOC_TRACE(" = 0"); \
+         return NULL; \
+      } \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
 #define REALLOC(soname, fnname) \
    \
    void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void* ptrV, SizeT new_size );\
@@ -400,11 +472,36 @@
 REALLOC(VG_Z_LIBC_SONAME, realloc);
 #if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
 REALLOC(VG_Z_LIBC_SONAME, realloc_common);
+#elif defined(VGO_darwin)
+ZONEREALLOC(VG_Z_LIBC_SONAME, malloc_zone_realloc);
 #endif
 
 
 /*---------------------- memalign ----------------------*/
 
+#define ZONEMEMALIGN(soname, fnname) \
+   \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT alignment, SizeT n ); \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT alignment, SizeT n ) \
+   { \
+      void* v; \
+      \
+      if (!init_done) init(); \
+      MALLOC_TRACE("memalign(%p, al %llu, size %llu)", \
+                   zone, (ULong)alignment, (ULong)n );  \
+      \
+      /* Round up to minimum alignment if necessary. */ \
+      if (alignment < VG_MIN_MALLOC_SZB) \
+         alignment = VG_MIN_MALLOC_SZB; \
+      \
+      /* Round up to nearest power-of-two if necessary (like glibc). */ \
+      while (0 != (alignment & (alignment - 1))) alignment++; \
+      \
+      v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_memalign, alignment, n ); \
+      MALLOC_TRACE(" = %p", v ); \
+      return v; \
+   }
+
 #define MEMALIGN(soname, fnname) \
    \
    void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT alignment, SizeT n ); \
@@ -429,6 +526,9 @@
    }
 
 MEMALIGN(VG_Z_LIBC_SONAME, memalign);
+#if defined(VGO_darwin)
+ZONEMEMALIGN(VG_Z_LIBC_SONAME, malloc_zone_memalign);
+#endif
 
 
 /*---------------------- valloc ----------------------*/
@@ -454,7 +554,23 @@
                 ((SizeT)pszB, size); \
    }
 
+#define ZONEVALLOC(soname, fnname) \
+   \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT size ); \
+   void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT size )  \
+   { \
+      static int pszB = 0; \
+      extern int getpagesize (void); \
+      if (pszB == 0) \
+         pszB = getpagesize(); \
+      return VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,memalign) \
+                ((SizeT)pszB, size); \
+   }
+
 VALLOC(VG_Z_LIBC_SONAME, valloc);
+#if defined(VGO_darwin)
+ZONEVALLOC(VG_Z_LIBC_SONAME, malloc_zone_valloc);
+#endif
 
 
 /*---------------------- mallopt ----------------------*/
@@ -567,6 +683,7 @@
    }
 
 MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size);
+MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_size);
 
 
 /*---------------------- (unimplemented) ----------------------*/
@@ -623,6 +740,58 @@
 MALLINFO(VG_Z_LIBC_SONAME, mallinfo);
 
 
+#if defined(VGO_darwin)
+
+static vki_malloc_zone_t vg_default_zone = {
+    NULL, // reserved
+    NULL, // reserved
+    NULL, // GrP fixme malloc_size
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_malloc), 
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_calloc), 
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_valloc), 
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_free), 
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_realloc), 
+    NULL, // GrP fixme destroy
+    "ValgrindMallocZone", 
+    NULL, // batch_malloc
+    NULL, // batch_free
+    NULL, // GrP fixme introspect
+    2,  // version (GrP fixme 3?)
+    // DDD: this field exists in Mac OS 10.6, but not 10.5.
+    #if 0
+    (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_memalign)
+    #endif
+};
+
+#define DEFAULT_ZONE(soname, fnname) \
+   \
+   void *VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void ); \
+   void *VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void )  \
+   { \
+      return &vg_default_zone; \
+   }
+
+#if defined(VGO_darwin)
+DEFAULT_ZONE(VG_Z_LIBC_SONAME, malloc_zone_from_ptr);
+DEFAULT_ZONE(VG_Z_LIBC_SONAME, malloc_default_zone);
+#endif
+
+// GrP fixme bypass libc's use of zone->introspect->check
+#define ZONE_CHECK(soname, fnname) \
+                                   \
+   int VG_REPLACE_FUNCTION_ZU(soname, fnname)(void* zone); \
+   int VG_REPLACE_FUNCTION_ZU(soname, fnname)(void* zone)  \
+   { \
+      return 1; \
+   }
+
+#if defined(VGO_darwin)
+ZONE_CHECK(VG_Z_LIBC_SONAME, malloc_zone_check);    
+#endif
+
+#endif
+
+
 /* All the code in here is unused until this function is called */
 
 static void init(void)
diff --git a/coregrind/m_scheduler/priv_sema.h b/coregrind/m_scheduler/priv_sema.h
index dfcab13..6693e88 100644
--- a/coregrind/m_scheduler/priv_sema.h
+++ b/coregrind/m_scheduler/priv_sema.h
@@ -33,16 +33,17 @@
 
 /* Not really a semaphore, but use a pipe for a token-passing scheme */
 typedef struct {
-   Int pipe[2];
-   Int owner_lwpid;		/* who currently has it */
+   Int  pipe[2];
+   Int  owner_lwpid;  /* who currently has it */
+   Bool held_as_LL;   /* if held, True == held by a _LL call */
 } vg_sema_t;
 
 // Nb: this may be OS-specific, but let's not factor it out until we
 // implement an OS port for which this isn't ok.
 void ML_(sema_init)   ( vg_sema_t *sema );
 void ML_(sema_deinit) ( vg_sema_t *sema );
-void ML_(sema_down)   ( vg_sema_t *sema );
-void ML_(sema_up)     ( vg_sema_t *sema );
+void ML_(sema_down)   ( vg_sema_t *sema, Bool as_LL );
+void ML_(sema_up)     ( vg_sema_t *sema, Bool as_LL );
 
 #endif   // __PRIV_SEMA_H
 
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index f1177ba..d0d17e6 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -71,6 +71,9 @@
 #include "pub_core_libcprint.h"
 #include "pub_core_libcproc.h"
 #include "pub_core_libcsignal.h"
+#if defined(VGO_darwin)
+#include "pub_core_mach.h"
+#endif
 #include "pub_core_machine.h"
 #include "pub_core_mallocfree.h"
 #include "pub_core_options.h"
@@ -154,6 +157,8 @@
       case VEX_TRC_JMP_SYS_SYSCALL:   return "SYSCALL";
       case VEX_TRC_JMP_SYS_INT32:     return "INT32";
       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_SYSENTER:  return "SYSENTER";
       case VEX_TRC_JMP_CLIENTREQ:     return "CLIENTREQ";
       case VEX_TRC_JMP_YIELD:         return "YIELD";
@@ -211,7 +216,7 @@
    /* First, acquire the_BigLock.  We can't do anything else safely
       prior to this point.  Even doing debug printing prior to this
       point is, technically, wrong. */
-   ML_(sema_down)(&the_BigLock);
+   ML_(sema_down)(&the_BigLock, False/*not LL*/);
 
    tst = VG_(get_ThreadState)(tid);
 
@@ -267,9 +272,22 @@
 
    /* Release the_BigLock; this will reschedule any runnable
       thread. */
-   ML_(sema_up)(&the_BigLock);
+   ML_(sema_up)(&the_BigLock, False/*not LL*/);
 }
 
+/* See pub_core_scheduler.h for description */
+void VG_(acquire_BigLock_LL) ( HChar* who )
+{
+  ML_(sema_down)(&the_BigLock, True/*LL*/);
+}
+
+/* See pub_core_scheduler.h for description */
+void VG_(release_BigLock_LL) ( HChar* who )
+{
+   ML_(sema_up)(&the_BigLock, True/*LL*/);
+}
+
+
 /* Clear out the ThreadState and release the semaphore. Leaves the
    ThreadState in VgTs_Zombie state, so that it doesn't get
    reallocated until the caller is really ready. */
@@ -288,7 +306,7 @@
    if (VG_(clo_trace_sched))
       print_sched_event(tid, "release lock in VG_(exit_thread)");
 
-   ML_(sema_up)(&the_BigLock);
+   ML_(sema_up)(&the_BigLock, False/*not LL*/);
 }
 
 /* If 'tid' is blocked in a syscall, send it SIGVGKILL so as to get it
@@ -300,11 +318,39 @@
    vg_assert(!VG_(is_running_thread)(tid));
 
    if (VG_(threads)[tid].status == VgTs_WaitSys) {
-      if (VG_(clo_trace_signals))
+      if (VG_(clo_trace_signals)) {
 	 VG_(message)(Vg_DebugMsg, 
                       "get_thread_out_of_syscall zaps tid %d lwp %d",
 		      tid, VG_(threads)[tid].os_state.lwpid);
-      VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VG_SIGVGKILL);
+      }
+#     if defined(VGO_darwin)
+      {
+         // GrP fixme use mach primitives on darwin?
+         // GrP fixme thread_abort_safely?
+         // GrP fixme race for thread with WaitSys set but not in syscall yet?
+         extern kern_return_t thread_abort(mach_port_t);
+         thread_abort(VG_(threads)[tid].os_state.lwpid);
+      }
+#     else
+      {
+         __attribute__((unused))
+         Int r = VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VG_SIGVGKILL);
+         /* JRS 2009-Mar-20: should we assert for r==0 (tkill succeeded)?
+            I'm really not sure.  Here's a race scenario which argues
+            that we shoudn't; but equally I'm not sure the scenario is
+            even possible, because of constraints caused by the question
+            of who holds the BigLock when.
+
+            Target thread tid does sys_read on a socket and blocks.  This
+            function gets called, and we observe correctly that tid's
+            status is WaitSys but then for whatever reason this function
+            goes very slowly for a while.  Then data arrives from
+            wherever, tid's sys_read returns, tid exits.  Then we do
+            tkill on tid, but tid no longer exists; tkill returns an
+            error code and the assert fails. */
+         /* vg_assert(r == 0); */
+      }
+#     endif
    }
 }
 
@@ -355,10 +401,24 @@
 {
    tst->os_state.lwpid       = 0;
    tst->os_state.threadgroup = 0;
-#  if defined(VGO_aix5)
+#  if defined(VGO_linux)
+   /* no other fields to clear */
+#  elif defined(VGO_aix5)
    tst->os_state.cancel_async    = False;
    tst->os_state.cancel_disabled = False;
    tst->os_state.cancel_progress = Canc_NoRequest;
+#  elif defined(VGO_darwin)
+   tst->os_state.post_mach_trap_fn = NULL;
+   tst->os_state.pthread           = 0;
+   tst->os_state.func_arg          = 0;
+   VG_(memset)(&tst->os_state.child_go, 0, sizeof(tst->os_state.child_go));
+   VG_(memset)(&tst->os_state.child_done, 0, sizeof(tst->os_state.child_done));
+   tst->os_state.wq_jmpbuf_valid   = False;
+   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));
+#  else
+#    error "Unknown OS"
 #  endif
 }
 
@@ -419,6 +479,11 @@
    ThreadId tid;
    vg_assert(VG_(running_tid) == me);
 
+#  if defined(VGO_darwin)
+   // GrP fixme hack reset Mach ports
+   VG_(mach_init)();
+#  endif
+
    VG_(threads)[me].os_state.lwpid = VG_(gettid)();
    VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
 
@@ -434,7 +499,7 @@
    /* re-init and take the sema */
    ML_(sema_deinit)(&the_BigLock);
    ML_(sema_init)(&the_BigLock);
-   ML_(sema_down)(&the_BigLock);
+   ML_(sema_down)(&the_BigLock, False/*not LL*/);
 }
 
 
@@ -807,7 +872,7 @@
    }
 }
 
-static void handle_syscall(ThreadId tid)
+static void handle_syscall(ThreadId tid, UInt trc)
 {
    ThreadState * volatile tst = VG_(get_ThreadState)(tid);
    Bool jumped; 
@@ -820,7 +885,7 @@
    if (VG_(clo_sanity_level >= 3))
       VG_(am_do_sync_check)("(BEFORE SYSCALL)",__FILE__,__LINE__);
 
-   SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
+   SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid, trc));
 
    if (VG_(clo_sanity_level >= 3))
       VG_(am_do_sync_check)("(AFTER SYSCALL)",__FILE__,__LINE__);
@@ -1013,8 +1078,10 @@
 	 break;
 
       case VEX_TRC_JMP_SYS_INT128:  /* x86-linux */
-      case VEX_TRC_JMP_SYS_SYSCALL: /* amd64-linux, ppc32-linux */
-	 handle_syscall(tid);
+      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 */
+	 handle_syscall(tid, trc);
 	 if (VG_(clo_sanity_level) > 2)
 	    VG_(sanity_check_general)(True); /* sanity-check every syscall */
 	 break;
@@ -1154,10 +1221,16 @@
 #        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)
+         /* return address in client edx */
+         VG_(threads)[tid].arch.vex.guest_EIP
+            = VG_(threads)[tid].arch.vex.guest_EDX;
+         handle_syscall(tid, trc);
 #        else
          vg_assert2(0, "VG_(scheduler), phase 3: "
                        "sysenter_x86 on non-x86 platform?!?!");
 #        endif
+         break;
 
       default: 
 	 vg_assert2(0, "VG_(scheduler), phase 3: "
@@ -1466,12 +1539,15 @@
       bad = True;
    }
 
+#if !defined(VGO_darwin)
+   // GrP fixme
    if (lwpid != the_BigLock.owner_lwpid) {
       VG_(message)(Vg_DebugMsg,
                    "Thread (LWPID) %d doesn't own the_BigLock\n",
                    tid);
       bad = True;
    }
+#endif
 
    /* Periodically show the state of all threads, for debugging
       purposes. */
diff --git a/coregrind/m_scheduler/sema.c b/coregrind/m_scheduler/sema.c
index 22b4676..ed84505 100644
--- a/coregrind/m_scheduler/sema.c
+++ b/coregrind/m_scheduler/sema.c
@@ -87,7 +87,7 @@
 }
 
 /* get a token */
-void ML_(sema_down)(vg_sema_t *sema)
+void ML_(sema_down)( vg_sema_t *sema, Bool as_LL )
 {
    Char buf[2];
    Int ret;
@@ -114,13 +114,15 @@
    if (sema_char == 'Z') sema_char = 'A'; else sema_char++;
 
    sema->owner_lwpid = lwpid;
+   sema->held_as_LL = as_LL;
 }
 
 /* put token back */
-void ML_(sema_up)(vg_sema_t *sema)
+void ML_(sema_up)( vg_sema_t *sema, Bool as_LL )
 {
    Int ret;
    Char buf[2];
+   vg_assert(as_LL == sema->held_as_LL);
    buf[0] = sema_char; 
    buf[1] = 0;
    vg_assert(sema->owner_lwpid != -1); /* must be initialised */
diff --git a/coregrind/m_sigframe/sigframe-amd64-darwin.c b/coregrind/m_sigframe/sigframe-amd64-darwin.c
new file mode 100644
index 0000000..4c8bc92
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-amd64-darwin.c
@@ -0,0 +1,68 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames.                       ---*/
+/*---                                      sigframe-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006-2009 OpenWorks Ltd
+      info@open-works.co.uk
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.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_trampoline.h"
+#include "pub_core_sigframe.h"      /* self */
+
+
+void VG_(sigframe_create) ( ThreadId tid,
+                            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 )
+{
+   I_die_here;
+}
+
+
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+   I_die_here;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                  sigframe-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_sigframe/sigframe-x86-darwin.c b/coregrind/m_sigframe/sigframe-x86-darwin.c
new file mode 100644
index 0000000..698d940
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-x86-darwin.c
@@ -0,0 +1,232 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames.                       ---*/
+/*---                                        sigframe-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2006-2009 OpenWorks Ltd
+      info@open-works.co.uk
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.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_trampoline.h"
+#include "pub_core_sigframe.h"      /* self */
+
+
+/* Cheap-ass hack copied from ppc32-aix5 code, just to get started.
+   Produce a frame with layout entirely of our own choosing. */
+
+/* This module creates and removes signal frames for signal deliveries
+   on x86-darwin.  Kludgey; the machine state ought to be saved in a
+   ucontext and retrieved from it later, so the handler can modify it
+   and return.  However .. for now .. just stick the vex guest state
+   in the frame and snarf it again later.
+
+   Also, don't bother with creating siginfo and ucontext in the
+   handler, although do point them somewhere non-faulting.
+
+   Frame should have a 16-aligned size, just in case that turns out to
+   be important for Darwin.  (be conservative)
+*/
+struct hacky_sigframe {
+   /* first four words look like a call to a 3-arg x86 function */
+   UInt             returnAddr;
+   UInt             a1_signo;
+   UInt             a2_siginfo;
+   UInt             a3_ucontext;
+   UChar            lower_guardzone[512];  // put nothing here
+   VexGuestX86State gst;
+   VexGuestX86State gshadow1;
+   VexGuestX86State gshadow2;
+   vki_siginfo_t    fake_siginfo;
+   struct vki_ucontext fake_ucontext;
+   UInt             magicPI;
+   UInt             sigNo_private;
+   vki_sigset_t     mask; // saved sigmask; restore when hdlr returns
+   UInt             __pad[1];
+   UChar            upper_guardzone[512]; // put nothing here
+};
+
+
+/* Extend the stack segment downwards if needed so as to ensure the
+   new signal frames are mapped to something.  Return a Bool
+   indicating whether or not the operation was successful.
+*/
+static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
+{
+   ThreadId tid = tst->tid;
+   /* For tracking memory events, indicate the entire frame has been
+      allocated.  Except, don't mess with the area which
+      overlaps the previous frame's redzone. */
+   /* XXX is the following call really right?  compared with the
+      amd64-linux version, this doesn't appear to handle the redzone
+      in the same way. */
+   VG_TRACK( new_mem_stack_signal,
+             addr, size - VG_STACK_REDZONE_SZB, tid );
+   return True;
+}
+
+
+/* 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 calling conventions will simply cause the
+   extra 2 args to be ignored (inside the handler). */
+void VG_(sigframe_create) ( ThreadId tid,
+                            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;
+   Addr esp;
+   struct hacky_sigframe* frame;
+   Int sigNo = siginfo->si_signo;
+
+   vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
+
+   sp_top_of_frame &= ~0xf;
+   esp = sp_top_of_frame - sizeof(struct hacky_sigframe);
+
+   tst = VG_(get_ThreadState)(tid);
+   if (!extend(tst, esp, sp_top_of_frame - esp))
+      return;
+
+   vg_assert(VG_IS_16_ALIGNED(esp));
+
+   frame = (struct hacky_sigframe *) esp;
+
+   /* clear it (very conservatively) (why so conservatively??) */
+   VG_(memset)(&frame->lower_guardzone, 0, 512);
+   VG_(memset)(&frame->gst,      0, sizeof(VexGuestX86State));
+   VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestX86State));
+   VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestX86State));
+   VG_(memset)(&frame->fake_siginfo,  0, sizeof(frame->fake_siginfo));
+   VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
+
+   /* save stuff in frame */
+   frame->gst           = tst->arch.vex;
+   frame->gshadow1      = tst->arch.vex_shadow1;
+   frame->gshadow2      = tst->arch.vex_shadow2;
+   frame->sigNo_private = sigNo;
+   frame->mask          = tst->sig_mask;
+   frame->magicPI       = 0x31415927;
+
+   /* Minimally fill in the siginfo and ucontext.  Note, utter
+      lameness prevails.  Be underwhelmed, be very underwhelmed. */
+   frame->fake_siginfo.si_signo = sigNo;
+   frame->fake_siginfo.si_code  = siginfo->si_code;
+
+   /* Set up stack pointer */
+   vg_assert(esp == (Addr)&frame->returnAddr);
+   VG_(set_SP)(tid, esp);
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt));
+
+   /* Set up program counter */
+   VG_(set_IP)(tid, (UInt)handler);
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt));
+
+   /* Set up RA and args for the frame */
+   VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
+             (Addr)frame, 4*sizeof(UInt) );
+   frame->returnAddr  = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
+   frame->a1_signo    = sigNo;
+   frame->a2_siginfo  = (UInt)&frame->fake_siginfo;  /* oh well */
+   frame->a3_ucontext = (UInt)&frame->fake_ucontext; /* oh well */
+   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+             (Addr)frame, 4*sizeof(UInt) );
+   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+             (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
+   VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+             (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "sigframe_create (thread %d): next EIP=%#lx, next ESP=%#lx",
+                   tid, (Addr)handler, (Addr)frame );
+}
+
+
+/* Remove a signal frame from thread 'tid's stack, and restore the CPU
+   state from it.  Note, isRT is irrelevant here. */
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+   ThreadState *tst;
+   Addr esp;
+   Int sigNo;
+   struct hacky_sigframe* frame;
+ 
+   vg_assert(VG_(is_valid_tid)(tid));
+   tst = VG_(get_ThreadState)(tid);
+
+   /* Check that the stack frame looks valid */
+   esp = VG_(get_SP)(tid);
+
+   /* why -4 ? because the signal handler's return will have popped
+      the return address of the stack; and the return address is the
+      lowest-addressed element of hacky_sigframe. */
+   frame = (struct hacky_sigframe*)(esp - 4);
+   vg_assert(frame->magicPI == 0x31415927);
+   vg_assert(VG_IS_16_ALIGNED(frame));
+
+   /* restore the entire guest state, and shadows, from the
+      frame.  Note, as per comments above, this is a kludge - should
+      restore it from saved ucontext.  Oh well. */
+   tst->arch.vex = frame->gst;
+   tst->arch.vex_shadow1 = frame->gshadow1;
+   tst->arch.vex_shadow2 = frame->gshadow2;
+   tst->sig_mask = frame->mask;
+   tst->tmp_sig_mask = frame->mask;
+   sigNo = frame->sigNo_private;
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg,
+                   "sigframe_destroy (thread %d): valid magic; next EIP=%#x",
+                   tid, tst->arch.vex.guest_EIP);
+
+   VG_TRACK( die_mem_stack_signal, 
+             (Addr)frame, 
+             sizeof(struct hacky_sigframe) - VG_STACK_REDZONE_SZB );
+
+   /* tell the tools */
+   VG_TRACK( post_deliver_signal, tid, sigNo );
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                    sigframe-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index c5b4b10..43c9aec 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -423,6 +423,82 @@
       return VG_UCONTEXT_STACK_PTR(ucV);
    }
 
+#elif defined(VGP_x86_darwin)
+
+   static inline Addr VG_UCONTEXT_INSTR_PTR( void* ucV ) {
+      ucontext_t* uc = (ucontext_t*)ucV;
+      struct __darwin_mcontext32* mc = uc->uc_mcontext;
+      struct __darwin_i386_thread_state* ss = &mc->__ss;
+      return ss->__eip;
+   }
+   static inline Addr VG_UCONTEXT_STACK_PTR( void* ucV ) {
+      ucontext_t* uc = (ucontext_t*)ucV;
+      struct __darwin_mcontext32* mc = uc->uc_mcontext;
+      struct __darwin_i386_thread_state* ss = &mc->__ss;
+      return ss->__esp;
+   }
+   static inline SysRes VG_UCONTEXT_SYSCALL_SYSRES( void* ucV,
+                                                    UWord scclass ) {
+      /* this is complicated by the problem that there are 3 different
+         kinds of syscalls, each with its own return convention.
+         NB: scclass is a host word, hence UWord is good for both
+         amd64-darwin and x86-darwin */
+      ucontext_t* uc = (ucontext_t*)ucV;
+      struct __darwin_mcontext32* mc = uc->uc_mcontext;
+      struct __darwin_i386_thread_state* ss = &mc->__ss;
+      /* duplicates logic in m_syswrap.getSyscallStatusFromGuestState */
+      UInt carry = 1 & ss->__eflags;
+      UInt err = 0;
+      UInt wLO = 0;
+      UInt wHI = 0;
+      switch (scclass) {
+         case VG_DARWIN_SYSCALL_CLASS_UNIX:
+            err = carry;
+            wLO = ss->__eax;
+            wHI = ss->__edx;
+            break;
+         case VG_DARWIN_SYSCALL_CLASS_MACH:
+            wLO = ss->__eax;
+            break;
+         case VG_DARWIN_SYSCALL_CLASS_MDEP:
+            wLO = ss->__eax;
+            break;
+         default: 
+            vg_assert(0);
+            break;
+      }
+      return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, 
+                                        wHI, wLO );
+   }
+   static inline Addr VG_UCONTEXT_LINK_REG( void* ucV ) {
+      return 0; /* No, really.  We have no LRs today. */
+   }
+   static inline Addr VG_UCONTEXT_FRAME_PTR( void* ucV ) {
+      ucontext_t* uc = (ucontext_t*)ucV;
+      struct __darwin_mcontext32* mc = uc->uc_mcontext;
+      struct __darwin_i386_thread_state* ss = &mc->__ss;
+      return ss->__ebp;
+   }
+
+#elif defined(VGP_amd64_darwin)
+
+   static inline Addr VG_UCONTEXT_INSTR_PTR( void* ucV ) {
+      I_die_here;
+   }
+   static inline Addr VG_UCONTEXT_STACK_PTR( void* ucV ) {
+      I_die_here;
+   }
+   static inline SysRes VG_UCONTEXT_SYSCALL_SYSRES( void* ucV,
+                                                    UWord scclass ) {
+      I_die_here;
+   }
+   static inline Addr VG_UCONTEXT_LINK_REG( void* ucV ) {
+      return 0; /* No, really.  We have no LRs today. */
+   }
+   static inline Addr VG_UCONTEXT_FRAME_PTR( void* ucV ) {
+      I_die_here;
+   }
+
 #else 
 #  error Unknown platform
 #endif
@@ -438,6 +514,9 @@
 #elif defined(VGO_aix5)
 #  define VKI_SIGINFO_si_addr  si_addr
 #  define VKI_SIGINFO_si_pid   si_pid
+#elif defined(VGO_darwin)
+#  define VKI_SIGINFO_si_addr  si_addr
+#  define VKI_SIGINFO_si_pid   si_pid
 #else
 #  error Unknown OS
 #endif
@@ -722,6 +801,18 @@
    ".globl my_sigreturn\n" \
    "my_sigreturn:\n" \
    ".long 0\n"
+#elif defined(VGP_x86_darwin)
+#  define _MY_SIGRETURN(name) \
+   ".text\n" \
+   "my_sigreturn:\n" \
+   "movl $" VG_STRINGIFY(__NR_DARWIN_FAKE_SIGRETURN) ",%eax\n" \
+   "int $0x80"
+#elif defined(VGP_amd64_darwin)
+   // DDD: todo
+#  define _MY_SIGRETURN(name) \
+   ".text\n" \
+   "my_sigreturn:\n" \
+   "ud2\n"
 #else
 #  error Unknown platform
 #endif
@@ -763,8 +854,9 @@
 
       ksa.ksa_handler = skss.skss_per_sig[sig].skss_handler;
       ksa.sa_flags    = skss.skss_per_sig[sig].skss_flags;
-#     if !defined(VGP_ppc32_linux) && !defined(VGP_ppc32_aix5) \
-         && !defined(VGP_ppc64_aix5)
+#     if !defined(VGP_ppc32_linux) && \
+         !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+         !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
       ksa.sa_restorer = my_sigreturn;
 #     endif
       /* Re above ifdef (also the assertion below), PaulM says:
@@ -784,8 +876,7 @@
                  sig, ksa.ksa_handler,
                  (UWord)ksa.sa_flags,
                  _VKI_NSIG_WORDS > 1 ? (ULong)ksa.sa_mask.sig[1] : 0,
-                 (ULong)ksa.sa_mask.sig[0]
-         );
+                 (ULong)ksa.sa_mask.sig[0]);
 
       res = VG_(sigaction)( sig, &ksa, &ksa_old );
       vg_assert(res == 0);
@@ -797,8 +888,9 @@
                    == skss_old.skss_per_sig[sig].skss_handler);
          vg_assert(ksa_old.sa_flags 
                    == skss_old.skss_per_sig[sig].skss_flags);
-#        if !defined(VGP_ppc32_linux) && !defined(VGP_ppc32_aix5) \
-            && !defined(VGP_ppc64_aix5)
+#        if !defined(VGP_ppc32_linux) && \
+            !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+            !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
          vg_assert(ksa_old.sa_restorer 
                    == my_sigreturn);
 #        endif
@@ -919,7 +1011,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_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#     if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+         !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
       old_act->sa_restorer = scss.scss_per_sig[signo].scss_restorer;
 #     endif
    }
@@ -931,11 +1024,15 @@
       scss.scss_per_sig[signo].scss_mask     = new_act->sa_mask;
 
       scss.scss_per_sig[signo].scss_restorer = NULL;
-#     if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#     if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+         !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
       scss.scss_per_sig[signo].scss_restorer = new_act->sa_restorer;
 #     endif
 
       scss.scss_per_sig[signo].scss_sa_tramp = NULL;
+#     if defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+      scss.scss_per_sig[signo].scss_sa_tramp = new_act->sa_tramp;
+#     endif
 
       VG_(sigdelset)(&scss.scss_per_sig[signo].scss_mask, VKI_SIGKILL);
       VG_(sigdelset)(&scss.scss_per_sig[signo].scss_mask, VKI_SIGSTOP);
@@ -1234,13 +1331,15 @@
 /* Hit ourselves with a signal using the default handler */
 void VG_(kill_self)(Int sigNo)
 {
+   Int r;
    vki_sigset_t	         mask, origmask;
    vki_sigaction_toK_t   sa, origsa2;
    vki_sigaction_fromK_t origsa;   
 
    sa.ksa_handler = VKI_SIG_DFL;
    sa.sa_flags = 0;
-#  if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#  if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+      !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
    sa.sa_restorer = 0;
 #  endif
    VG_(sigemptyset)(&sa.sa_mask);
@@ -1251,7 +1350,9 @@
    VG_(sigaddset)(&mask, sigNo);
    VG_(sigprocmask)(VKI_SIG_UNBLOCK, &mask, &origmask);
 
-   VG_(kill)(VG_(getpid)(), sigNo);
+   r = VG_(kill)(VG_(getpid)(), sigNo);
+   /* This sometimes fails with EPERM on Darwin.  I don't know why. */
+   /* vg_assert(r == 0); */
 
    VG_(convert_sigaction_fromK_to_toK)( &origsa, &origsa2 );
    VG_(sigaction)(sigNo, &origsa2, NULL);
@@ -1262,8 +1363,9 @@
 // kernel, eg.: seg faults, illegal opcodes.  Some come from the user, eg.:
 // from kill() (SI_USER), or timer_settime() (SI_TIMER), or an async I/O
 // request (SI_ASYNCIO).  There's lots of implementation-defined leeway in
-// POSIX, but the user vs. kernal distinction is what we want here.
-static Bool is_signal_from_kernel(int si_code)
+// POSIX, but the user vs. kernal distinction is what we want here.  We also
+// 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) || defined(VGO_aix5)
    // On Linux, SI_USER is zero, negative values are from the user, positive
@@ -1271,6 +1373,35 @@
    // macros but we don't use them here because other platforms don't have
    // them.
    return ( si_code > VKI_SI_USER ? True : False );
+#elif defined(VGO_darwin)
+   // On Darwin 9.6.0, the si_code is completely unreliable.  It should be the
+   // case that 0 means "user", and >0 means "kernel".  But:
+   // - For SIGSEGV, it seems quite reliable.
+   // - For SIGBUS, it's always 2.
+   // - For SIGFPE, it's often 0, even for kernel ones (eg.
+   //   div-by-integer-zero always gives zero).
+   // - For SIGILL, it's unclear.
+   // - For SIGTRAP, it's always 1.
+   // You can see the "NOTIMP" (not implemented) status of a number of the
+   // sub-cases in sys/signal.h.  Hopefully future versions of Darwin will
+   // get this right.
+
+   // If we're blocked waiting on a syscall, it must be a user signal, because
+   // the kernel won't generate sync signals within syscalls.
+   if (VG_(threads)[tid].status == VgTs_WaitSys) {
+      return False;
+
+   // If it's a SIGSEGV, use the proper condition, since it's fairly reliable.
+   } else if (SIGSEGV == signum) {
+      return ( si_code > 0 ? True : False );
+
+   // If it's anything else, assume it's kernel-generated.  Reason being that
+   // kernel-generated sync signals are more common, and it's probable that
+   // misdiagnosing a user signal as a kernel signal is better than the
+   // opposite.
+   } else {
+      return True;
+   }
 #else
 #  error Unknown OS
 #endif
@@ -1358,7 +1489,7 @@
    }
 
    if ( (VG_(clo_verbosity) > 1 ||
-         (could_core && is_signal_from_kernel(info->si_code))
+         (could_core && is_signal_from_kernel(tid, sigNo, info->si_code))
         ) &&
         !VG_(clo_xml) ) {
       VG_UMSG("");
@@ -1366,7 +1497,7 @@
               sigNo, signame(sigNo), core ? ": dumping core" : "");
 
       /* Be helpful - decode some more details about this fault */
-      if (is_signal_from_kernel(info->si_code)) {
+      if (is_signal_from_kernel(tid, sigNo, info->si_code)) {
 	 const Char *event = NULL;
 	 Bool haveaddr = True;
 
@@ -1448,7 +1579,7 @@
          VG_(pp_ExeContext)( ec );
       }
       if (sigNo == VKI_SIGSEGV 
-          && info && is_signal_from_kernel(info->si_code)
+          && info && is_signal_from_kernel(tid, sigNo, info->si_code)
           && info->si_code == VKI_SEGV_MAPERR) {
          VG_UMSG(" If you believe this happened as a result of a stack" );
          VG_UMSG(" overflow in your program's main thread (unlikely but");
@@ -1640,6 +1771,11 @@
 {
    vki_siginfo_t info;
    struct vki_ucontext uc;
+#  if defined(VGP_x86_darwin)
+   struct __darwin_mcontext32 mc;
+#  elif defined(VGP_amd64_darwin)
+   struct __darwin_mcontext64 mc;
+#  endif
 
    vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
 
@@ -1653,6 +1789,12 @@
                                           for a breakpoint trap... */
    uc.uc_mcontext.err = 0;        /* tjh: no error code for x86
                                           breakpoint trap... */
+#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+   /* the same thing, but using Darwin field/struct names */
+   VG_(memset)(&mc, 0, sizeof(mc));
+   uc.uc_mcontext = &mc;
+   uc.uc_mcontext->__es.__trapno = 3;
+   uc.uc_mcontext->__es.__err = 0;
 #  endif
 
    resume_scheduler(tid);
@@ -1756,7 +1898,7 @@
       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_aix5)
+#elif defined(VGO_aix5) || defined(VGO_darwin)
    return si_code;
 #else
 #  error Unknown OS
@@ -1812,7 +1954,16 @@
       VG_(fixup_guest_state_after_syscall_interrupted) will detect
       that the thread was not in said window and ignore the SysRes. */
 
+   /* To make matters more complex still, on Darwin we need to know
+      the "class" of the syscall under consideration in order to be
+      able to extract the a correct SysRes.  The class will have been
+      saved just before the syscall, by VG_(client_syscall), into this
+      thread's tst->arch.vex.guest_SC_CLASS.  Hence: */
+#  if defined(VGO_darwin)
+   sres = VG_UCONTEXT_SYSCALL_SYSRES(uc, tst->arch.vex.guest_SC_CLASS);
+#  else
    sres = VG_UCONTEXT_SYSCALL_SYSRES(uc);
+#  endif
 
    /* (1) */
    VG_(fixup_guest_state_after_syscall_interrupted)(
@@ -2050,7 +2201,6 @@
    }
 }
 
-
 static
 void sync_signalhandler_from_kernel ( ThreadId tid,
          Int sigNo, vki_siginfo_t *info, struct vki_ucontext *uc )
@@ -2140,7 +2290,7 @@
 
    info->si_code = sanitize_si_code(info->si_code);
 
-   from_user = !is_signal_from_kernel(info->si_code);
+   from_user = !is_signal_from_kernel(tid, sigNo, info->si_code);
 
    if (VG_(clo_trace_signals)) {
       VG_DMSG("sync signal handler: "
@@ -2220,7 +2370,8 @@
    VG_(printf)("pp_ksigaction: handler %p, flags 0x%x, restorer %p\n", 
                sa->ksa_handler, 
                (UInt)sa->sa_flags, 
-#              if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#              if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+                  !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
                   sa->sa_restorer
 #              else
                   (void*)0
@@ -2242,7 +2393,8 @@
 
    sa.ksa_handler = VKI_SIG_DFL;
    sa.sa_flags = 0;
-#  if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#  if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+      !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
    sa.sa_restorer = 0;
 #  endif
    VG_(sigemptyset)(&sa.sa_mask);
@@ -2326,6 +2478,13 @@
       /* Get the old host action */
       ret = VG_(sigaction)(i, NULL, &sa);
 
+#     if defined(VGP_x86_darwin)
+      /* apparently we may not even ask about the disposition of these
+         signals, let alone change them */
+      if (ret != 0 && (i == VKI_SIGKILL || i == VKI_SIGSTOP))
+         continue;
+#     endif
+
       if (ret != 0)
 	 break;
 
@@ -2337,7 +2496,8 @@
 
 	 tsa.ksa_handler = (void *)sync_signalhandler;
 	 tsa.sa_flags = VKI_SA_SIGINFO;
-#        if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#        if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+            !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
 	 tsa.sa_restorer = 0;
 #        endif
 	 VG_(sigfillset)(&tsa.sa_mask);
@@ -2364,11 +2524,18 @@
       scss.scss_per_sig[i].scss_mask     = sa.sa_mask;
 
       scss.scss_per_sig[i].scss_restorer = NULL;
-#     if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+#     if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+         !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
       scss.scss_per_sig[i].scss_restorer = sa.sa_restorer;
 #     endif
 
       scss.scss_per_sig[i].scss_sa_tramp = NULL;
+#     if defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+      scss.scss_per_sig[i].scss_sa_tramp = NULL;
+      /*sa.sa_tramp;*/
+      /* We can't know what it was, because Darwin's sys_sigaction
+         doesn't tell us. */
+#     endif
    }
 
    if (VG_(clo_trace_signals))
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index edfaf73..6e3c8d0 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -101,6 +101,9 @@
    /* Assertion broken before main() is reached in pthreaded programs;  the
     * offending stack traces only have one item.  --njn, 2002-aug-16 */
    /* 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 (fp_min + 512 >= fp_max) {
       /* If the stack limits look bogus, don't poke around ... but
          don't bomb out either. */
@@ -109,13 +112,14 @@
       ips[0] = ip;
       return 1;
    } 
+#endif
 
    /* Otherwise unwind the stack in a platform-specific way.  Trying
       to merge the x86, amd64, ppc32 and ppc64 logic into a single
       piece of code is just too confusing and difficult to
       performance-tune.  */
 
-#  if defined(VGP_x86_linux)
+#  if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
 
    /*--------------------- x86 ---------------------*/
 
@@ -209,7 +213,7 @@
       break;
    }
 
-#  elif defined(VGP_amd64_linux)
+#  elif defined(VGP_amd64_linux)  ||  defined(VGP_amd64_darwin)
 
    /*--------------------- amd64 ---------------------*/
 
@@ -551,7 +555,6 @@
    VG_(pp_StackTrace)(ips, n_ips);
 }
 
-
 void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
                             StackTrace ips, UInt n_ips )
 {
diff --git a/coregrind/m_start-amd64-darwin.S b/coregrind/m_start-amd64-darwin.S
new file mode 100644
index 0000000..e414a26
--- /dev/null
+++ b/coregrind/m_start-amd64-darwin.S
@@ -0,0 +1,81 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin amd64 bootstrap.               m_start-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2007 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+	.text
+	.align	3,0x90
+Ldyld_stub_binding_helper:
+        pushq   %r11
+        leaq    ___dso_handle(%rip), %r11
+        pushq   %r11
+	jmpq    *Ldyld_lazy_symbol_binding_entry_point(%rip)
+
+	.dyld
+	.align	3
+Ldyld_lazy_symbol_binding_entry_point:
+	.quad	0
+	.quad	0
+	.quad	0
+	.quad	0
+	.quad	0
+	.quad	Ldyld_stub_binding_helper
+	.quad	0
+
+		
+	// Memory layout established by kernel:
+	//
+	//        0
+	//        executable_name
+	//        0
+	//        envp[n]
+	//        ...
+	//        envp[0]
+	//        0
+	//        argv[argc-1]
+	//        ...
+	// sp+8-> argv[0]
+	// sp  -> argc
+	
+	.text
+	.align 3,0x90
+	.globl __start
+__start:
+	movq	%rsp, %rdi	// save &argc
+	andq	$-16, %rsp	// align stack
+	pushq	$0		// push NULL "return address" for backtraces
+	pushq	$0		// push fake saved ebp and align stack
+	movq	%rsp, %rbp	// save frame pointer
+	call	__start_in_C_darwin  // __start_in_C_darwin(&argc)
+	
+	// should not reach here
+	int $3
+	int $3
+
diff --git a/coregrind/m_start-x86-darwin.S b/coregrind/m_start-x86-darwin.S
new file mode 100644
index 0000000..57b49d0
--- /dev/null
+++ b/coregrind/m_start-x86-darwin.S
@@ -0,0 +1,80 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin x86 bootstrap.                   m_start-x86-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2007 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+	.text
+	.align	2,0x90
+Ldyld_stub_binding_helper:
+	pushl   $__mh_execute_header
+	jmpl    *Ldyld_lazy_symbol_binding_entry_point
+
+	.dyld
+	.align	2
+Ldyld_lazy_symbol_binding_entry_point:
+	.long	0
+	.long	0
+	.long	0
+	.long	0
+	.long	0
+	.long	Ldyld_stub_binding_helper
+	.long	0
+
+		
+	// Memory layout established by kernel:
+	//
+	//        0
+	//        executable_name
+	//        0
+	//        envp[n]
+	//        ...
+	//        envp[0]
+	//        0
+	//        argv[argc-1]
+	//        ...
+	// sp+4-> argv[0]
+	// sp  -> argc
+	
+	.text
+	.align 2,0x90
+	.globl __start
+__start:
+	movl	%esp, %eax	// save &argc
+	andl	$-16, %esp	// align stack
+	pushl	$0		// push NULL "return address" for backtraces
+	pushl	$0		// push fake saved ebp
+	movl	%esp, %ebp	// save frame pointer
+	pushl	$0		// align stack
+	pushl	%eax		// start_in_C_darwin(&argc)
+	call	__start_in_C_darwin
+	
+	// should not reach here
+	int $3
+	int $3
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index 0970e6b..3a74a89 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -29,6 +29,7 @@
 */
 
 #include "pub_core_basics.h"
+#include "pub_core_libcassert.h"
 #include "pub_core_vki.h"
 #include "pub_core_vkiscnums.h"
 #include "pub_core_syscall.h"
@@ -155,6 +156,95 @@
 }
 
 
+#elif defined(VGO_darwin)
+
+/* Darwin: Some syscalls return a double-word result. */
+SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
+                                   UInt wHI, UInt wLO )
+{
+   SysRes res;
+   res._wHI  = 0;
+   res._wLO  = 0;
+   res._mode = 0; /* invalid */
+   vg_assert(isErr == False || isErr == True);
+   vg_assert(sizeof(UWord) == sizeof(UInt));
+   switch (scclass) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         res._wLO  = wLO;
+         res._wHI  = wHI;
+         res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         vg_assert(!isErr);
+         vg_assert(wHI == 0);
+         res._wLO  = wLO;
+         res._mode = SysRes_MACH;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         vg_assert(!isErr);
+         vg_assert(wHI == 0);
+         res._wLO  = wLO;
+         res._mode = SysRes_MDEP;
+         break;
+      default:
+         vg_assert(0);
+   }
+   return res;
+}
+
+SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
+                                     ULong wHI, ULong wLO )
+{
+   SysRes res;
+   res._wHI  = 0;
+   res._wLO  = 0;
+   res._mode = 0; /* invalid */
+   vg_assert(isErr == False || isErr == True);
+   vg_assert(sizeof(UWord) == sizeof(ULong));
+   switch (scclass) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         res._wLO  = wLO;
+         res._wHI  = wHI;
+         res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         vg_assert(!isErr);
+         vg_assert(wHI == 0);
+         res._wLO  = wLO;
+         res._mode = SysRes_MACH;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         vg_assert(!isErr);
+         vg_assert(wHI == 0);
+         res._wLO  = wLO;
+         res._mode = SysRes_MDEP;
+         break;
+      default:
+         vg_assert(0);
+   }
+   return res;
+}
+
+/* Generic constructors.  We assume (without checking if this makes
+   any sense, from the caller's point of view) that these are for the
+   UNIX style of syscall. */
+SysRes VG_(mk_SysRes_Error) ( UWord err ) {
+   SysRes r;
+   r._wHI  = 0;
+   r._wLO  = err;
+   r._mode = SysRes_UNIX_ERR;
+   return r;
+}
+
+SysRes VG_(mk_SysRes_Success) ( UWord res ) {
+   SysRes r;
+   r._wHI  = 0;
+   r._wLO  = res;
+   r._mode = SysRes_UNIX_OK;
+   return r;
+}
+
+
 #else
 #  error "Unknown OS"
 #endif
@@ -460,6 +550,138 @@
    *res_r4 = args[1];
 }
 
+#elif defined(VGP_x86_darwin)
+
+/* Incoming args (syscall number + up to 8 args) come in on the stack
+
+   The kernel's syscall calling convention is:
+   * the syscall number goes in eax
+   * the args are passed to the syscall on the stack,
+     pushed onto the stack R->L (that is, the usual x86
+     calling conventions, with the leftmost arg at the lowest
+     address)
+   Call instruction:
+   * UNIX: sysenter
+   * UNIX: int $0x80
+   * MACH: int $0x81
+   * MDEP: int $0x82
+   Note that the call type can be determined from the syscall number;
+   there is no need to inspect the actual instruction.  Although obviously
+   the instruction must match.
+   Return value:
+   * MACH,MDEP: the return value comes back in eax
+   * UNIX: the return value comes back in edx:eax (hi32:lo32)
+   Error:
+   * MACH,MDEP: no error is returned
+   * UNIX: the carry flag indicates success or failure
+
+   nb here, sizeof(UWord) == sizeof(UInt)
+*/
+
+__private_extern__ ULong 
+do_syscall_unix_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) */ );
+// Unix syscall: 64-bit return in edx:eax, with LSB in eax
+// error indicated by carry flag: clear=good, set=bad
+asm(".private_extern _do_syscall_unix_WRK\n"
+    "_do_syscall_unix_WRK:\n"
+    "        movl    40(%esp), %ecx   \n"  /* assume syscall success */
+    "        movl    $0, (%ecx)       \n"
+    "        movl    36(%esp), %eax   \n"
+    "        int     $0x80            \n"
+    "        jnc     1f               \n"  /* jump if success */
+    "        movl    40(%esp), %ecx   \n"  /* syscall failed - set *errflag */
+    "        movl    $1, (%ecx)       \n"
+    "    1:  ret                      \n"
+    );
+
+__private_extern__ UInt 
+do_syscall_mach_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) */ );
+// Mach trap: 32-bit result in %eax, no error flag
+asm(".private_extern _do_syscall_mach_WRK\n"
+    "_do_syscall_mach_WRK:\n"
+    "        movl    36(%esp), %eax   \n"
+    "        int     $0x81            \n"
+    "        ret                      \n"
+    );
+
+__private_extern__ UInt 
+do_syscall_mdep_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) */ );
+// mdep trap: 32-bit result in %eax, no error flag
+asm(
+    ".private_extern _do_syscall_mdep_WRK\n"
+    "_do_syscall_mdep_WRK:\n"
+    "        movl    36(%esp), %eax   \n"
+    "        int     $0x82            \n"
+    "        ret                      \n"
+    );
+
+
+#elif defined(VGP_amd64_darwin)
+
+/* Incoming args (syscall number + up to 8 args) come in registers and stack
+
+   The kernel's syscall calling convention is:
+   * the syscall number goes in rax
+   * the args are passed to the syscall in registers and the stack
+   * the call instruction is 'syscall'
+   Return value:
+   * MACH,MDEP: the return value comes back in rax
+   * UNIX: the return value comes back in rdx:rax (hi64:lo64)
+   Error:
+   * MACH,MDEP: no error is returned
+   * UNIX: the carry flag indicates success or failure
+
+   nb here, sizeof(UWord) == sizeof(ULong)
+*/
+
+__private_extern__ UWord 
+do_syscall_unix_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) */
+// Unix syscall: 128-bit return in rax:rdx, with LSB in rax
+// error indicated by carry flag: clear=good, set=bad
+asm(".private_extern _do_syscall_unix_WRK\n"
+    "_do_syscall_unix_WRK:\n"
+    "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
+    "        movq    32(%rsp), %rax   \n"  /* assume syscall success */
+    "        movq    $0, (%rax)       \n"
+    "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
+    "        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"
+    "        retq                     \n"  /* return 1st result word */
+    );
+
+__private_extern__ UWord 
+do_syscall_mach_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) */
+// Mach trap: 64-bit result, no error flag
+asm(".private_extern _do_syscall_mach_WRK\n"
+    "_do_syscall_mach_WRK:\n"
+    "        movq    %rcx, %r10       \n"  /* pass rcx in r10 instead */
+    "        movq    24(%rsp), %rax   \n"  /* load syscall_no */
+    "        syscall                  \n"
+    "        retq                     \n"
+    );
+
 #else
 #  error Unknown platform
 #endif
@@ -536,6 +758,53 @@
    }
    return VG_(mk_SysRes_ppc64_aix5)( res, err );
 
+#  elif defined(VGP_x86_darwin)
+   UInt  wLO = 0, wHI = 0, err = 0;
+   ULong u64;
+   UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
+   switch (scclass) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+                                   VG_DARWIN_SYSNO_NUM(sysno), &err);
+         wLO = (UInt)u64;
+         wHI = (UInt)(u64 >> 32);
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
+                                   VG_DARWIN_SYSNO_NUM(sysno));
+         err = 0;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
+                                   VG_DARWIN_SYSNO_NUM(sysno));
+         err = 0;
+         break;
+      default:
+         vg_assert(0);
+         break;
+   }
+   return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
+
+#  elif defined(VGP_amd64_darwin)
+   ULong wLO = 0, wHI = 0, err = 0;
+   UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
+   switch (scclass) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+                                   VG_DARWIN_SYSNO_NUM(sysno), &err, &wHI);
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8, 
+                                   VG_DARWIN_SYSNO_NUM(sysno));
+         err = 0;
+         break;
+      default:
+         vg_assert(0);
+         break;
+   }
+   return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
+  
 #else
 #  error Unknown platform
 #endif
diff --git a/coregrind/m_syswrap/priv_syswrap-darwin.h b/coregrind/m_syswrap/priv_syswrap-darwin.h
new file mode 100644
index 0000000..bc85706
--- /dev/null
+++ b/coregrind/m_syswrap/priv_syswrap-darwin.h
@@ -0,0 +1,289 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Private syscalls header for Darwin.    priv_syswrap-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   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_DARWIN_H
+#define __PRIV_SYSWRAP_DARWIN_H
+
+/* requires #include "priv_types_n_macros.h" */
+
+// syswrap-darwin.c
+Addr allocstack ( ThreadId tid );
+void find_stack_segment ( ThreadId tid, Addr sp );
+void start_thread_NORETURN ( Word arg );
+void assign_port_name(mach_port_t port, const char *name);
+void record_named_port(ThreadId tid, mach_port_t port, mach_port_right_t right, const char *name);
+
+extern const SyscallTableEntry ML_(mach_trap_table)[];
+extern const SyscallTableEntry ML_(syscall_table)[];
+extern const SyscallTableEntry ML_(mdep_trap_table)[];
+
+extern const UInt ML_(syscall_table_size);
+extern const UInt ML_(mach_trap_table_size);
+extern const UInt ML_(mdep_trap_table_size);
+
+void VG_(show_open_ports)(void);
+
+// Unix syscalls
+DECL_TEMPLATE(darwin, sys_semget);
+DECL_TEMPLATE(darwin, sys_semop);
+DECL_TEMPLATE(darwin, sys_semctl);
+DECL_TEMPLATE(darwin, sys_sem_open);
+DECL_TEMPLATE(darwin, sys_sem_close);
+DECL_TEMPLATE(darwin, sys_sem_unlink);
+DECL_TEMPLATE(darwin, sys_sem_post);
+DECL_TEMPLATE(darwin, sys_sem_init);
+DECL_TEMPLATE(darwin, sys_sem_destroy);
+DECL_TEMPLATE(darwin, sys_sem_wait_nocancel);
+DECL_TEMPLATE(darwin, sys_sem_trywait);
+DECL_TEMPLATE(darwin, sys_bsdthread_create);
+DECL_TEMPLATE(darwin, sys_bsdthread_terminate);
+DECL_TEMPLATE(darwin, sys_kqueue);
+DECL_TEMPLATE(darwin, sys_kevent);
+DECL_TEMPLATE(darwin, sys_bsdthread_register);
+DECL_TEMPLATE(darwin, sys_workq_open);
+DECL_TEMPLATE(darwin, sys_workq_ops);
+DECL_TEMPLATE(darwin, sys___mac_syscall);
+DECL_TEMPLATE(darwin, sys_exit);
+DECL_TEMPLATE(darwin, sys_sigaction);
+DECL_TEMPLATE(darwin, sys___pthread_canceled);
+DECL_TEMPLATE(darwin, sys___pthread_markcancel);
+DECL_TEMPLATE(darwin, sys___pthread_sigmask);
+DECL_TEMPLATE(darwin, sys___disable_threadsignal);
+DECL_TEMPLATE(darwin, sys_kdebug_trace);
+DECL_TEMPLATE(darwin, sys_seteuid);
+DECL_TEMPLATE(darwin, sys_setegid);
+DECL_TEMPLATE(darwin, sys_listxattr);
+DECL_TEMPLATE(darwin, sys_flistxattr);
+DECL_TEMPLATE(darwin, sys_shmget);
+DECL_TEMPLATE(darwin, sys_shm_open);
+DECL_TEMPLATE(darwin, sys_statx);
+DECL_TEMPLATE(darwin, sys_fchmod_extended);
+DECL_TEMPLATE(darwin, sys_chmod_extended);
+DECL_TEMPLATE(darwin, sys_accessx);
+DECL_TEMPLATE(darwin, sys_chflags);
+DECL_TEMPLATE(darwin, sys_fchflags);
+DECL_TEMPLATE(darwin, sys_stat64);
+DECL_TEMPLATE(darwin, sys_lstat64);
+DECL_TEMPLATE(darwin, sys_fstat64);
+DECL_TEMPLATE(darwin, sys_getfsstat);
+DECL_TEMPLATE(darwin, sys_getattrlist);
+DECL_TEMPLATE(darwin, sys_setattrlist);
+DECL_TEMPLATE(darwin, sys_getdirentriesattr);
+DECL_TEMPLATE(darwin, sys_fsctl);
+DECL_TEMPLATE(darwin, sys_socket);
+DECL_TEMPLATE(darwin, sys_setsockopt);
+DECL_TEMPLATE(darwin, sys_getsockopt);
+DECL_TEMPLATE(darwin, sys_connect);
+DECL_TEMPLATE(darwin, sys_accept);
+DECL_TEMPLATE(darwin, sys_sendto);
+DECL_TEMPLATE(darwin, sys_recvfrom);
+DECL_TEMPLATE(darwin, sys_sendmsg);
+DECL_TEMPLATE(darwin, sys_recvmsg);
+DECL_TEMPLATE(darwin, sys_shutdown);
+DECL_TEMPLATE(darwin, sys_bind);
+DECL_TEMPLATE(darwin, sys_listen);
+DECL_TEMPLATE(darwin, sys_getsockname);
+DECL_TEMPLATE(darwin, sys_getpeername);
+DECL_TEMPLATE(darwin, sys_socketpair);
+DECL_TEMPLATE(darwin, sys_gethostuuid);
+DECL_TEMPLATE(darwin, sys_pipe);
+DECL_TEMPLATE(darwin, sys_getlogin);
+DECL_TEMPLATE(darwin, sys_ptrace);
+DECL_TEMPLATE(darwin, sys_issetugid);
+DECL_TEMPLATE(darwin, sys_getdtablesize);
+DECL_TEMPLATE(darwin, sys_lseek);
+DECL_TEMPLATE(darwin, sys_getdirentries);
+DECL_TEMPLATE(darwin, sys_getdirentries64);
+DECL_TEMPLATE(darwin, sys_statfs64);
+DECL_TEMPLATE(darwin, sys_fstatfs64);
+DECL_TEMPLATE(darwin, sys_csops);
+DECL_TEMPLATE(darwin, sys_auditon);
+DECL_TEMPLATE(darwin, sys_pathconf);
+DECL_TEMPLATE(darwin, sys_fpathconf);
+DECL_TEMPLATE(darwin, sys_shared_region_map_file_np);
+DECL_TEMPLATE(darwin, sys_mmap);
+DECL_TEMPLATE(darwin, sys_sysctl);
+DECL_TEMPLATE(darwin, sys_sigpending);
+DECL_TEMPLATE(darwin, sys_sigprocmask);
+DECL_TEMPLATE(darwin, sys_sigsuspend);
+DECL_TEMPLATE(darwin, sys_watchevent);
+DECL_TEMPLATE(darwin, sys_waitevent);
+DECL_TEMPLATE(darwin, sys_modwatch);
+DECL_TEMPLATE(darwin, sys_getxattr);
+DECL_TEMPLATE(darwin, sys_fgetxattr);
+DECL_TEMPLATE(darwin, sys_setxattr);
+DECL_TEMPLATE(darwin, sys_fsetxattr);
+DECL_TEMPLATE(darwin, sys_initgroups);
+DECL_TEMPLATE(darwin, sys_posix_spawn);
+DECL_TEMPLATE(darwin, sys_settid);
+DECL_TEMPLATE(darwin, sys_sendfile);
+DECL_TEMPLATE(darwin, sys_fcntl);
+DECL_TEMPLATE(darwin, sys_fcntl64);
+DECL_TEMPLATE(darwin, sys_ioctl);
+DECL_TEMPLATE(darwin, sys_futimes);
+DECL_TEMPLATE(darwin, sys_FAKE_SIGRETURN);
+DECL_TEMPLATE(darwin, sys_sigreturn);
+
+// Mach message helpers
+DECL_TEMPLATE(darwin, host_info);
+DECL_TEMPLATE(darwin, host_page_size);
+DECL_TEMPLATE(darwin, host_get_io_master);
+DECL_TEMPLATE(darwin, host_get_clock_service);
+DECL_TEMPLATE(darwin, host_request_notification);
+DECL_TEMPLATE(darwin, mach_port_type);
+DECL_TEMPLATE(darwin, mach_port_extract_member);
+DECL_TEMPLATE(darwin, mach_port_allocate);
+DECL_TEMPLATE(darwin, mach_port_deallocate);
+DECL_TEMPLATE(darwin, mach_port_get_refs);
+DECL_TEMPLATE(darwin, mach_port_mod_refs);
+DECL_TEMPLATE(darwin, mach_port_get_set_status);
+DECL_TEMPLATE(darwin, mach_port_destroy);
+DECL_TEMPLATE(darwin, mach_port_request_notification);
+DECL_TEMPLATE(darwin, mach_port_insert_right);
+DECL_TEMPLATE(darwin, mach_port_get_attributes);
+DECL_TEMPLATE(darwin, mach_port_set_attributes);
+DECL_TEMPLATE(darwin, mach_port_insert_member);
+DECL_TEMPLATE(darwin, task_get_special_port);
+DECL_TEMPLATE(darwin, semaphore_create);
+DECL_TEMPLATE(darwin, semaphore_destroy);
+DECL_TEMPLATE(darwin, mach_ports_lookup);
+DECL_TEMPLATE(darwin, task_threads);
+DECL_TEMPLATE(darwin, task_suspend);
+DECL_TEMPLATE(darwin, task_resume);
+DECL_TEMPLATE(darwin, vm_allocate);
+DECL_TEMPLATE(darwin, vm_deallocate);
+DECL_TEMPLATE(darwin, vm_protect);
+DECL_TEMPLATE(darwin, vm_inherit);
+DECL_TEMPLATE(darwin, vm_read);
+DECL_TEMPLATE(darwin, mach_vm_read);
+DECL_TEMPLATE(darwin, vm_copy);
+DECL_TEMPLATE(darwin, vm_read_overwrite);
+DECL_TEMPLATE(darwin, vm_map);
+DECL_TEMPLATE(darwin, vm_remap);
+DECL_TEMPLATE(darwin, mach_make_memory_entry_64);
+DECL_TEMPLATE(darwin, vm_purgable_control);
+DECL_TEMPLATE(darwin, mach_vm_purgable_control);
+DECL_TEMPLATE(darwin, mach_vm_allocate);
+DECL_TEMPLATE(darwin, mach_vm_deallocate);
+DECL_TEMPLATE(darwin, mach_vm_protect);
+DECL_TEMPLATE(darwin, mach_vm_copy);
+DECL_TEMPLATE(darwin, mach_vm_inherit);
+DECL_TEMPLATE(darwin, mach_vm_map);
+DECL_TEMPLATE(darwin, mach_vm_region_recurse);
+DECL_TEMPLATE(darwin, thread_terminate);
+DECL_TEMPLATE(darwin, thread_create);
+DECL_TEMPLATE(darwin, thread_create_running);
+DECL_TEMPLATE(darwin, thread_suspend);
+DECL_TEMPLATE(darwin, thread_get_state);
+DECL_TEMPLATE(darwin, thread_policy);
+DECL_TEMPLATE(darwin, thread_info);
+DECL_TEMPLATE(darwin, bootstrap_register);
+DECL_TEMPLATE(darwin, bootstrap_look_up);
+DECL_TEMPLATE(darwin, mach_msg_receive);
+DECL_TEMPLATE(darwin, mach_msg_bootstrap);
+DECL_TEMPLATE(darwin, mach_msg_host);
+DECL_TEMPLATE(darwin, mach_msg_task);
+DECL_TEMPLATE(darwin, mach_msg_thread);
+
+// Mach traps
+DECL_TEMPLATE(darwin, mach_msg_unhandled);
+DECL_TEMPLATE(darwin, mach_msg);
+DECL_TEMPLATE(darwin, mach_reply_port);
+DECL_TEMPLATE(darwin, mach_thread_self);
+DECL_TEMPLATE(darwin, mach_host_self);
+DECL_TEMPLATE(darwin, mach_task_self);
+DECL_TEMPLATE(darwin, syscall_thread_switch);
+DECL_TEMPLATE(darwin, semaphore_signal);
+DECL_TEMPLATE(darwin, semaphore_signal_all);
+DECL_TEMPLATE(darwin, semaphore_signal_thread);
+DECL_TEMPLATE(darwin, semaphore_wait);
+DECL_TEMPLATE(darwin, semaphore_wait_signal);
+DECL_TEMPLATE(darwin, semaphore_timedwait);
+DECL_TEMPLATE(darwin, semaphore_timedwait_signal);
+DECL_TEMPLATE(darwin, sys___semwait_signal);
+DECL_TEMPLATE(darwin, task_for_pid);
+DECL_TEMPLATE(darwin, pid_for_task);
+DECL_TEMPLATE(darwin, mach_timebase_info);
+DECL_TEMPLATE(darwin, mach_wait_until);
+DECL_TEMPLATE(darwin, mk_timer_create);
+DECL_TEMPLATE(darwin, mk_timer_destroy);
+DECL_TEMPLATE(darwin, mk_timer_arm);
+DECL_TEMPLATE(darwin, mk_timer_cancel);
+DECL_TEMPLATE(darwin, iokit_user_client_trap);
+DECL_TEMPLATE(darwin, swtch);
+DECL_TEMPLATE(darwin, swtch_pri);
+
+// Machine-dependent traps
+DECL_TEMPLATE(darwin, pthread_set_self);
+
+// syswrap-<arch>-darwin.c
+#include <mach/mach.h>
+extern 
+void thread_state_from_vex(thread_state_t mach_generic, 
+                           thread_state_flavor_t flavor, 
+                           mach_msg_type_number_t count, 
+                           VexGuestArchState *vex_generic);
+extern
+void thread_state_to_vex(const thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         VexGuestArchState *vex_generic);
+extern 
+ThreadState *build_thread(const thread_state_t state, 
+                          thread_state_flavor_t flavor, 
+                          mach_msg_type_number_t count);
+extern
+void hijack_thread_state(thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         ThreadState *tst);
+extern
+__attribute__((noreturn))
+void call_on_new_stack_0_1 ( Addr stack,
+			     Addr retaddr,
+			     void (*f)(Word),
+                             Word arg1 );
+
+extern void pthread_hijack_asm(void);
+extern void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
+                           Addr stacksize, Addr flags, Addr sp);
+extern void wqthread_hijack_asm(void);
+extern void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, Int reuse, Addr sp);
+
+extern Addr pthread_starter;
+extern Addr wqthread_starter;
+extern SizeT pthread_structsize;
+
+
+#endif
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/priv_syswrap-main.h b/coregrind/m_syswrap/priv_syswrap-main.h
index 7c4fc52..e4b87b3 100644
--- a/coregrind/m_syswrap/priv_syswrap-main.h
+++ b/coregrind/m_syswrap/priv_syswrap-main.h
@@ -35,6 +35,12 @@
 extern
 void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch );
 
+#if defined(VGO_darwin)
+/* Longjmp to scheduler after client calls workq_ops(WQOPS_THREAD_RETURN)*/
+extern
+void ML_(wqthread_continue_NORETURN)(ThreadId tid);
+#endif
+
 #endif   // __PRIV_SYSWRAP_MAIN_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h
index 45536b8..c481b8f 100644
--- a/coregrind/m_syswrap/priv_types_n_macros.h
+++ b/coregrind/m_syswrap/priv_types_n_macros.h
@@ -49,8 +49,8 @@
 
 /* Arguments for a syscall. */
 typedef
-   struct {
-      UWord sysno;
+   struct SyscallArgs {
+      Word sysno;
       UWord arg1;
       UWord arg2;
       UWord arg3;
@@ -64,7 +64,7 @@
 
 /* Current status of a syscall being done on behalf of the client. */
 typedef
-   struct {
+   struct SyscallStatus {
       enum { 
          /* call is complete, result is in 'res' */
          SsComplete=1,
@@ -80,6 +80,12 @@
 /* Guest state layout info for syscall args. */
 typedef
    struct {
+      // Note that, depending on the platform, arguments may be found in
+      // registers or on the stack.  (See the comment at the top of
+      // syswrap-main.c for per-platform details.)  For register arguments
+      // (which have o_arg field names) the o_arg value is the offset from
+      // the vex register state.  For stack arguments (which have s_arg
+      // field names), the s_arg value is the offset from the stack pointer.
       Int o_sysno;
 #     if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
          || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
@@ -100,6 +106,24 @@
       Int o_arg6;
       Int o_arg7;
       Int o_arg8;
+#     elif defined(VGP_x86_darwin)
+      Int s_arg1;
+      Int s_arg2;
+      Int s_arg3;
+      Int s_arg4;
+      Int s_arg5;
+      Int s_arg6;
+      Int s_arg7;
+      Int s_arg8;
+#     elif defined(VGP_amd64_darwin)
+      Int o_arg1;
+      Int o_arg2;
+      Int o_arg3;
+      Int o_arg4;
+      Int o_arg5;
+      Int o_arg6;
+      Int s_arg7;
+      Int s_arg8;
 #     else
 #       error "Unknown platform"
 #     endif
@@ -146,7 +170,7 @@
 */
 
 
-#if defined(VGO_linux)
+#if defined(VGO_linux)  ||  defined(VGO_darwin)
 /* On Linux, finding the wrapper is easy: just look up in fixed,
    platform-specific tables.  These are defined in the relevant
    platform-specific files -- syswrap-arch-os.c */
@@ -245,8 +269,15 @@
     vgSysWrap_##auxstr##_##name##_after
 
 /* Add a generic wrapper to a syscall table. */
-#define GENX_(sysno, name)    WRAPPER_ENTRY_X_(generic, sysno, name)
-#define GENXY(sysno, name)    WRAPPER_ENTRY_XY(generic, sysno, name)
+#if defined(VGO_linux) || defined(VGO_aix5)
+#  define GENX_(sysno, name)  WRAPPER_ENTRY_X_(generic, sysno, name)
+#  define GENXY(sysno, name)  WRAPPER_ENTRY_XY(generic, sysno, name)
+#elif defined(VGO_darwin)
+#  define GENX_(sysno, name)  WRAPPER_ENTRY_X_(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#  define GENXY(sysno, name)  WRAPPER_ENTRY_XY(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#else
+#  error Unknown OS
+#endif
 
 /* Add a Linux-specific, arch-independent wrapper to a syscall
    table. */
@@ -343,15 +374,57 @@
 /* Macros used to tell tools about uses of scalar arguments.  Note,
    these assume little-endianness.  These can only be used in
    pre-wrappers, and they refer to the layout parameter passed in. */
-/* PRRAn == "pre-register-read-argument"
-   PRRSN == "pre-register-read-syscall"
+/* PRRSN == "pre-register-read-sysno"
+   PRRAn == "pre-register-read-argument"
+   PSRAn == "pre-stack-read-argument"
+   PRAn  == "pre-read-argument"
 */
 
+#if defined(VGO_linux)
+   /* Up to 6 parameters, all in registers. */
+#  define PRA1(s,t,a) PRRAn(1,s,t,a)
+#  define PRA2(s,t,a) PRRAn(2,s,t,a)
+#  define PRA3(s,t,a) PRRAn(3,s,t,a)
+#  define PRA4(s,t,a) PRRAn(4,s,t,a)
+#  define PRA5(s,t,a) PRRAn(5,s,t,a)
+#  define PRA6(s,t,a) PRRAn(6,s,t,a)
+
+#elif defined(VGO_aix5)
+#  error Need to fill this in for AIX5
+
+#elif defined(VGP_x86_darwin)
+   /* 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)
+#  define PRA3(s,t,a) PSRAn(3,s,t,a)
+#  define PRA4(s,t,a) PSRAn(4,s,t,a)
+#  define PRA5(s,t,a) PSRAn(5,s,t,a)
+#  define PRA6(s,t,a) PSRAn(6,s,t,a)
+#  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)
+   /* 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)
+#  define PRA3(s,t,a) PRRAn(3,s,t,a)
+#  define PRA4(s,t,a) PRRAn(4,s,t,a)
+#  define PRA5(s,t,a) PRRAn(5,s,t,a)
+#  define PRA6(s,t,a) PRRAn(6,s,t,a)
+#  define PRA7(s,t,a) PSRAn(7,s,t,a)
+#  define PRA8(s,t,a) PSRAn(8,s,t,a)
+
+#else
+#  error Unknown platform
+#endif
+
+
 /* Tell the tool that the syscall number is being read. */
 #define PRRSN \
       VG_(tdict).track_pre_reg_read(Vg_CoreSysCall, tid, "(syscallno)", \
                                     layout->o_sysno, sizeof(UWord));
 
+/* REGISTER PARAMETERS */
 
 /* PRRAn: Tell the tool that the register holding the n-th syscall
    argument is being read, at type 't' which must be at most the size
@@ -402,6 +475,55 @@
 #endif
 
 
+/* STACK PARAMETERS */
+
+/* PSRAn: Tell the tool that the memory holding the n-th syscall
+   argument is being read, at type 't' which must be at most the size
+   of a register but can be smaller.  In the latter case we need to be
+   careful about endianness. */
+
+/* little-endian: the part of the guest state being read is
+      let here = offset_of_reg
+      in  [here .. here + sizeof(t) - 1]
+   since the least significant parts of the guest register are stored
+   in memory at the lowest address.
+*/
+#define PSRAn_LE(n,s,t,a)                          \
+   do {                                            \
+      Addr here = layout->s_arg##n + VG_(get_SP)(tid); \
+      vg_assert(sizeof(t) <= sizeof(UWord));       \
+      VG_(tdict).track_pre_mem_read(               \
+         Vg_CoreSysCallArgInMem, tid, s"("#a")",   \
+         here, sizeof(t)                           \
+      );                                           \
+   } while (0)
+
+/* big-endian: the part of the guest state being read is
+      let next = offset_of_reg + sizeof(reg) 
+      in  [next - sizeof(t) .. next - 1]
+   since the least significant parts of the guest register are stored
+   in memory at the highest address.
+*/
+#define PSRAn_BE(n,s,t,a)                                         \
+   do {                                                           \
+      Addr next = layout->o_arg##n + sizeof(UWord) +              \
+                  VG_(threads)[tid].arch.vex.VG_STACK_PTR;        \
+      vg_assert(sizeof(t) <= sizeof(UWord));                      \
+      VG_(tdict).track_pre_mem_read(                              \
+         Vg_CoreSysCallArgInMem, tid, s"("#a")",                  \
+         next-sizeof(t), sizeof(t)                                \
+      );                                                          \
+   } while (0)
+
+#if defined(VG_BIGENDIAN)
+#  define PSRAn(n,s,t,a) PSRAn_BE(n,s,t,a)
+#elif defined(VG_LITTLEENDIAN)
+#  define PSRAn(n,s,t,a) PSRAn_LE(n,s,t,a)
+#else
+#  error "Unknown endianness"
+#endif
+
+
 #define PRE_REG_READ0(tr, s) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
@@ -409,35 +531,50 @@
 #define PRE_REG_READ1(tr, s, t1, a1) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); \
+      PRA1(s,t1,a1);                            \
    }
 #define PRE_REG_READ2(tr, s, t1, a1, t2, a2) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); \
+      PRA1(s,t1,a1); PRA2(s,t2,a2);           \
    }
 #define PRE_REG_READ3(tr, s, t1, a1, t2, a2, t3, a3) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
    }
 #define PRE_REG_READ4(tr, s, t1, a1, t2, a2, t3, a3, t4, a4) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
-      PRRAn(4,s,t4,a4); \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
+      PRA4(s,t4,a4);                                    \
    }
 #define PRE_REG_READ5(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
-      PRRAn(4,s,t4,a4); PRRAn(5,s,t5,a5); \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);  \
+      PRA4(s,t4,a4); PRA5(s,t5,a5);                   \
    }
 #define PRE_REG_READ6(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6) \
    if (VG_(tdict).track_pre_reg_read) { \
       PRRSN; \
-      PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
-      PRRAn(4,s,t4,a4); PRRAn(5,s,t5,a5); PRRAn(6,s,t6,a6); \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
+      PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
+   }
+#define PRE_REG_READ7(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7) \
+   if (VG_(tdict).track_pre_reg_read) { \
+      PRRSN; \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
+      PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
+      PRA7(s,t7,a7);                                     \
+   }
+
+#define PRE_REG_READ8(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7, t8, a8) \
+   if (VG_(tdict).track_pre_reg_read) { \
+      PRRSN; \
+      PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3);   \
+      PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6);   \
+      PRA7(s,t7,a7); PRA8(s,t8,a8);                    \
    }
 
 #define PRE_MEM_READ(zzname, zzaddr, zzlen) \
diff --git a/coregrind/m_syswrap/syscall-amd64-darwin.S b/coregrind/m_syswrap/syscall-amd64-darwin.S
new file mode 100644
index 0000000..099a94e
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-amd64-darwin.S
@@ -0,0 +1,253 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls.       syscall-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2007 Julian Seward 
+     jseward@acm.org
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums.h"
+#include "libvex_guest_offsets.h"
+
+
+/*----------------------------------------------------------------*/
+/*
+	Perform a syscall for the client.  This will run a syscall
+	with the client's specific per-thread signal mask.
+	
+	The structure of this function is such that, if the syscall is
+	interrupted by a signal, we can determine exactly what
+	execution state we were in with respect to the execution of
+	the syscall by examining the value of %eip in the signal
+	handler.  This means that we can always do the appropriate
+	thing to precisely emulate the kernel's signal/syscall
+	interactions.
+
+	The syscall number is taken from the argument, even though it
+	should also be in guest_state->guest_RAX.  The syscall result
+	is written back to guest_state->guest_RAX on completion.
+	
+	Returns 0 if the syscall was successfully called (even if the
+	syscall itself failed), or a -ve error code if one of the
+	sigprocmasks failed (there's no way to determine which one
+	failed).
+
+	VG_(fixup_guest_state_after_syscall_interrupted) does the
+	thread state fixup in the case where we were interrupted by a
+	signal.
+	
+	Prototype:
+
+	Int ML_(do_syscall_for_client_WRK(
+	                          Int syscallno,		// rdi
+				  void* guest_state,		// rsi
+				  const vki_sigset_t *sysmask,	// rdx
+				  const vki_sigset_t *postmask,	// rcx
+				  Int sigsetSzB)		// r8
+
+        Note that sigsetSzB is totally ignored (and irrelevant).
+*/
+
+/* from vki_arch.h */	
+#define VKI_SIG_SETMASK	3
+
+/* DO_SYSCALL MACH|MDEP|UNIX */
+#define MACH 1
+#define MDEP 2
+#define UNIX 3
+
+.macro DO_SYSCALL
+	/* save callee-saved regs */
+	pushq	%rbp
+	movq	%rsp, %rbp
+	// stack is now aligned
+	pushq	%rdi  // -8(%rbp)   syscallno
+	pushq	%rsi  // -16(%rbp)  guest_state
+	pushq	%rdx  // -24(%rbp)  sysmask
+	pushq	%rcx  // -32(%rbp)  postmask
+	pushq	%r8   // -40(%rbp)  sigsetSzB
+	// stack is now aligned
+	
+L_$0_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 */
+
+	/* Set the signal mask which should be current during the syscall. */
+	/* GrP fixme signals
+           DDD: JRS fixme: use __NR___pthread_sigmask, not __NR_rt_sigprocmask
+	movq	$__NR_rt_sigprocmask, %rax	// syscall #
+	movq	$VKI_SIG_SETMASK, %rdi		// how
+	movq	-24(%rbp), %rsi			// sysmask
+	movq	-32(%rbp), %rdx			// postmask
+	movq	-40(%rbp), %r10			// sigsetSzB in r10 not rcx
+	DDD: fixme return address
+	syscall
+
+	jnc	7f	// sigprocmask failed
+	*/
+	
+	/* OK, that worked.  Now do the syscall proper. */
+
+	/* 6 register parameters */
+	movq	-16(%rbp), %r11	/* r11 = VexGuestAMD64State * */
+	movq	OFFSET_amd64_RDI(%r11), %rdi
+	movq	OFFSET_amd64_RSI(%r11), %rsi
+	movq	OFFSET_amd64_RDX(%r11), %rdx
+	movq	OFFSET_amd64_RCX(%r11), %r10 /* rcx is passed in r10 instead */
+	movq	OFFSET_amd64_R8(%r11), %r8
+	movq	OFFSET_amd64_R9(%r11), %r9
+	/* 2 stack parameters plus return address (ignored by syscall) */
+	movq	OFFSET_amd64_RSP(%r11), %r11 /* r11 = simulated RSP */
+	movq	16(%r11), %rax
+	pushq	%rax
+	movq	8(%r11), %rax
+	pushq	%rax
+	/* stack is currently aligned - return address misaligns */
+	movq	0(%r11), %rax
+	pushq	%rax
+	/* syscallno */
+	movq	-8(%rbp), %rax
+	
+	/* If rip==2, then the syscall was either just about
+	   to start, or was interrupted and the kernel was 
+	   restarting it. */
+L_$0_2:	syscall
+L_$0_3:	/* In the range [3, 4), the syscall result is in %rax, 
+	   but hasn't been committed to RAX. */
+
+	/* stack contents: 3 words for syscall above, plus our prologue */
+	setc	0(%rsp) 	/* stash returned carry flag */
+
+	movq	-16(%rbp), %r11	/* r11 = VexGuestAMD64State * */
+	movq	%rax, OFFSET_amd64_RAX(%r11)	/* save back to RAX */
+	movq	%rdx, OFFSET_amd64_RDX(%r11)	/* save back to RDX */
+
+.if $0 == UNIX
+	/* save carry flag to VEX */
+	xor	%rax, %rax
+	movb	0(%rsp), %al
+	movq	%rax, %rdi	/* arg1 = new flag */
+	movq	%r11, %rsi	/* arg2 = vex state */
+	addq	$$24, %rsp	/* remove syscall parameters */
+	call	_LibVEX_GuestAMD64_put_rflag_c
+.else
+	addq	$$24, %rsp	/* remove syscall parameters*/
+.endif
+
+L_$0_4:	/* Re-block signals.  If eip is in [4,5), then the syscall 
+	   is complete and we needn't worry about it. */
+	/* GrP fixme signals
+           DDD: JRS fixme: use __NR___pthread_sigmask, not __NR_rt_sigprocmask
+	PUSH_di_si_dx_cx_8
+
+	movq	$__NR_rt_sigprocmask, %rax	// syscall #
+	movq	$VKI_SIG_SETMASK, %rdi		// how
+	movq	%rcx, %rsi			// postmask
+	xorq	%rdx, %rdx			// NULL
+	movq	%r8, %r10			// sigsetSzB
+	DDD: fixme return address
+	syscall
+
+	POP_di_si_dx_cx_8
+
+	jnc	7f	// sigprocmask failed
+	*/
+L_$0_5:	/* now safe from signals */
+	movq	$$0, %rax	/* SUCCESS */
+	movq	%rbp, %rsp
+	popq	%rbp
+	ret
+
+/* GrP fixme signals
+L_$0_7:	// failure:	 return 0x8000 | error code
+	DDD: fixme return value
+	movq	%rbp, %rsp
+	popq	%rbp
+	ret
+*/
+
+.endmacro
+
+	
+.globl ML_(do_syscall_for_client_unix_WRK)
+ML_(do_syscall_for_client_unix_WRK):
+	DO_SYSCALL UNIX
+
+.globl ML_(do_syscall_for_client_mach_WRK)
+ML_(do_syscall_for_client_mach_WRK):
+	DO_SYSCALL MACH
+	
+.globl ML_(do_syscall_for_client_mdep_WRK)
+ML_(do_syscall_for_client_mdep_WRK):
+	DO_SYSCALL MDEP
+
+.data
+/* export the ranges so that
+   VG_(fixup_guest_state_after_syscall_interrupted) can do the
+   right thing */
+
+/* eg MK_L_SCLASS_N(UNIX,99) produces L_3_99
+   since UNIX is #defined to 3 at the top of this file */
+#define FOO(scclass,labelno) L_##scclass##_##labelno
+#define MK_L_SCCLASS_N(scclass,labelno) FOO(scclass,labelno)
+
+.globl ML_(blksys_setup_MACH)
+.globl ML_(blksys_restart_MACH)
+.globl ML_(blksys_complete_MACH)
+.globl ML_(blksys_committed_MACH)
+.globl ML_(blksys_finished_MACH)
+ML_(blksys_setup_MACH):	.quad MK_L_SCCLASS_N(MACH,1)
+ML_(blksys_restart_MACH):	.quad MK_L_SCCLASS_N(MACH,2)
+ML_(blksys_complete_MACH):	.quad MK_L_SCCLASS_N(MACH,3)
+ML_(blksys_committed_MACH):	.quad MK_L_SCCLASS_N(MACH,4)
+ML_(blksys_finished_MACH):	.quad MK_L_SCCLASS_N(MACH,5)
+
+.globl ML_(blksys_setup_MDEP)
+.globl ML_(blksys_restart_MDEP)
+.globl ML_(blksys_complete_MDEP)
+.globl ML_(blksys_committed_MDEP)
+.globl ML_(blksys_finished_MDEP)
+ML_(blksys_setup_MDEP):	.quad MK_L_SCCLASS_N(MDEP,1)
+ML_(blksys_restart_MDEP):	.quad MK_L_SCCLASS_N(MDEP,2)
+ML_(blksys_complete_MDEP):	.quad MK_L_SCCLASS_N(MDEP,3)
+ML_(blksys_committed_MDEP):	.quad MK_L_SCCLASS_N(MDEP,4)
+ML_(blksys_finished_MDEP):	.quad MK_L_SCCLASS_N(MDEP,5)
+
+.globl ML_(blksys_setup_UNIX)
+.globl ML_(blksys_restart_UNIX)
+.globl ML_(blksys_complete_UNIX)
+.globl ML_(blksys_committed_UNIX)
+.globl ML_(blksys_finished_UNIX)
+ML_(blksys_setup_UNIX):	.quad MK_L_SCCLASS_N(UNIX,1)
+ML_(blksys_restart_UNIX):	.quad MK_L_SCCLASS_N(UNIX,2)
+ML_(blksys_complete_UNIX):	.quad MK_L_SCCLASS_N(UNIX,3)
+ML_(blksys_committed_UNIX):	.quad MK_L_SCCLASS_N(UNIX,4)
+ML_(blksys_finished_UNIX):	.quad MK_L_SCCLASS_N(UNIX,5)
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-x86-darwin.S b/coregrind/m_syswrap/syscall-x86-darwin.S
new file mode 100644
index 0000000..41cc27e
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-x86-darwin.S
@@ -0,0 +1,252 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls.         syscall-x86-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2007 Julian Seward 
+     jseward@acm.org
+
+  This program is free software; you can redistribute it and/or
+  modify it under the terms of the GNU General Public License as
+  published by the Free Software Foundation; either version 2 of the
+  License, or (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+  02111-1307, USA.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums.h"
+#include "libvex_guest_offsets.h"
+		
+	
+/*----------------------------------------------------------------*/
+/*
+	Perform a syscall for the client.  This will run a syscall
+	with the client's specific per-thread signal mask.
+	
+	The structure of this function is such that, if the syscall is
+	interrupted by a signal, we can determine exactly what
+	execution state we were in with respect to the execution of
+	the syscall by examining the value of %eip in the signal
+	handler.  This means that we can always do the appropriate
+	thing to precisely emulate the kernel's signal/syscall
+	interactions.
+
+	The syscall number is taken from the argument, even though it
+	should also be in regs->m_eax.  The syscall result is written
+	back to regs->m_eax on completion.
+	
+	Returns 0 if the syscall was successfully called (even if the
+	syscall itself failed), or a -ve error code if one of the
+	sigprocmasks failed (there's no way to determine which one
+	failed).
+
+	VG_(fixup_guest_state_after_syscall_interrupted) does the
+	thread state fixup in the case where we were interrupted by a
+	signal.
+	
+	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
+				  Int sigsetSzB)		// ebp+24
+
+        Note that sigsetSzB is totally ignored (and irrelevant).
+*/
+
+/* from vki-darwin.h, checked at startup by m_vki.c */	
+#define VKI_SIG_SETMASK	3
+
+/* DO_SYSCALL MACH|MDEP|UNIX */
+#define MACH 1
+#define MDEP 2
+#define UNIX 3
+	
+.macro DO_SYSCALL
+	/* establish stack frame */
+	push	%ebp
+	mov	%esp, %ebp
+	subl	$$8, %esp	/* 16-byte align stack */
+	
+L_$0_1:	/* Even though we can't take a signal until the
+           __pthread_sigmask completes, start the range early.
+	   If eip is in the range [1,2), the syscall hasn't been started yet */
+
+	/* Set the signal mask which should be current during the syscall. */
+        /* Set up for __pthread_sigmask(SIG_SETMASK, sysmask, postmask) */
+        pushl   20(%ebp)
+        pushl   16(%ebp)
+        pushl   $$VKI_SIG_SETMASK
+        pushl   $$0xcafebabe    /* totally fake return address */
+        movl    $$__NR___pthread_sigmask, %eax
+        int     $$0x80  /* should be sysenter? */
+        jc      L_$0_7  /* __pthread_sigmask failed */
+        addl    $$16,%esp
+
+	/* Copy syscall parameters to the stack - assume no more than 8 
+	 * plus the return address */
+	/* do_syscall8 */
+	/* stack is currently aligned assuming 8 parameters */
+	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
+
+	/* If eip==2, then the syscall was either just about to start, 
+	   or was interrupted and the kernel was restarting it. */
+L_$0_2:
+.if $0 == UNIX
+	int	$$0x80		/* UNIX (GrP fixme should be sysenter?) */
+.elseif $0 == MACH
+	int	$$0x81
+.elseif $0 == MDEP
+	int	$$0x82
+.else
+	error$0 x
+.endif
+
+L_$0_3:	/* In the range [3, 4), the syscall result is in %eax and %edx and C,
+           but hasn't been committed to the thread state. */
+	setc	0(%esp)				/* stash returned carry flag */
+	movl	12(%ebp), %ecx
+	movl	%eax, OFFSET_x86_EAX(%ecx)	/* save EAX to vex */
+	movl	%edx, OFFSET_x86_EDX(%ecx)	/* save EDX to vex */
+.if $0 == UNIX
+	/* UNIX: save carry flag to vex */
+	subl	$$12, %esp
+	movl	%ecx, 4(%esp)
+	movl	$$0, 0(%esp)
+	movb	12(%esp), %al
+	movb	%al, 0(%esp)
+	call	_LibVEX_GuestX86_put_eflag_c
+	addl	$$12, %esp
+.endif
+
+L_$0_4:	/* Re-block signals.  If eip is in [4,5), then the syscall is
+           complete and we needn't worry about it. */
+        /* Set up for __pthread_sigmask(SIG_SETMASK, postmask, NULL) */
+        pushl   $$0
+        pushl   20(%ebp)
+        pushl   $$VKI_SIG_SETMASK
+        pushl   $$0xcafef00d    /* totally fake return address */
+        movl    $$__NR___pthread_sigmask, %eax
+        int     $$0x80  /* should be sysenter? */
+        jc      L_$0_7  /* __pthread_sigmask failed */
+        addl    $$16,%esp
+
+L_$0_5:	/* now safe from signals */
+	movl	$$0, %eax       /* SUCCESS */
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+
+L_$0_7: /* 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	%ebp, %esp
+	popl	%ebp
+	ret
+
+.endmacro
+	
+
+.globl ML_(do_syscall_for_client_unix_WRK)
+ML_(do_syscall_for_client_unix_WRK):
+	DO_SYSCALL UNIX
+
+.globl ML_(do_syscall_for_client_mach_WRK)
+ML_(do_syscall_for_client_mach_WRK):
+	DO_SYSCALL MACH
+	
+.globl ML_(do_syscall_for_client_mdep_WRK)
+ML_(do_syscall_for_client_mdep_WRK):
+	DO_SYSCALL MDEP
+
+.data
+/* export the ranges so that
+   VG_(fixup_guest_state_after_syscall_interrupted) can do the
+   right thing */
+
+/* eg MK_L_SCLASS_N(UNIX,99) produces L_3_99
+   since UNIX is #defined to 3 at the top of this file */
+#define FOO(scclass,labelno) L_##scclass##_##labelno
+#define MK_L_SCCLASS_N(scclass,labelno) FOO(scclass,labelno)
+
+.globl ML_(blksys_setup_MACH)
+.globl ML_(blksys_restart_MACH)
+.globl ML_(blksys_complete_MACH)
+.globl ML_(blksys_committed_MACH)
+.globl ML_(blksys_finished_MACH)
+ML_(blksys_setup_MACH):	.long MK_L_SCCLASS_N(MACH,1)
+ML_(blksys_restart_MACH):	.long MK_L_SCCLASS_N(MACH,2)
+ML_(blksys_complete_MACH):	.long MK_L_SCCLASS_N(MACH,3)
+ML_(blksys_committed_MACH):	.long MK_L_SCCLASS_N(MACH,4)
+ML_(blksys_finished_MACH):	.long MK_L_SCCLASS_N(MACH,5)
+
+.globl ML_(blksys_setup_MDEP)
+.globl ML_(blksys_restart_MDEP)
+.globl ML_(blksys_complete_MDEP)
+.globl ML_(blksys_committed_MDEP)
+.globl ML_(blksys_finished_MDEP)
+ML_(blksys_setup_MDEP):	.long MK_L_SCCLASS_N(MDEP,1)
+ML_(blksys_restart_MDEP):	.long MK_L_SCCLASS_N(MDEP,2)
+ML_(blksys_complete_MDEP):	.long MK_L_SCCLASS_N(MDEP,3)
+ML_(blksys_committed_MDEP):	.long MK_L_SCCLASS_N(MDEP,4)
+ML_(blksys_finished_MDEP):	.long MK_L_SCCLASS_N(MDEP,5)
+
+.globl ML_(blksys_setup_UNIX)
+.globl ML_(blksys_restart_UNIX)
+.globl ML_(blksys_complete_UNIX)
+.globl ML_(blksys_committed_UNIX)
+.globl ML_(blksys_finished_UNIX)
+ML_(blksys_setup_UNIX):	.long MK_L_SCCLASS_N(UNIX,1)
+ML_(blksys_restart_UNIX):	.long MK_L_SCCLASS_N(UNIX,2)
+ML_(blksys_complete_UNIX):	.long MK_L_SCCLASS_N(UNIX,3)
+ML_(blksys_committed_UNIX):	.long MK_L_SCCLASS_N(UNIX,4)
+ML_(blksys_finished_UNIX):	.long MK_L_SCCLASS_N(UNIX,5)
+
+
+ 
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-amd64-darwin.c b/coregrind/m_syswrap/syswrap-amd64-darwin.c
new file mode 100644
index 0000000..714a755
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-amd64-darwin.c
@@ -0,0 +1,457 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc.        syswrap-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_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_debuginfo.h"    // VG_(di_notify_*)
+#include "pub_core_transtab.h"     // VG_(discard_translations)
+#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"
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h"      // For VG_(sigframe_destroy)()
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"   /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h"    /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+
+#include <mach/mach.h>
+
+static void x86_thread_state64_from_vex(x86_thread_state64_t *mach, 
+                                        VexGuestAMD64State *vex)
+{
+    mach->__rax = vex->guest_RAX;
+    mach->__rbx = vex->guest_RBX;
+    mach->__rcx = vex->guest_RCX;
+    mach->__rdx = vex->guest_RDX;
+    mach->__rdi = vex->guest_RDI;
+    mach->__rsi = vex->guest_RSI;
+    mach->__rbp = vex->guest_RBP;
+    mach->__rsp = vex->guest_RSP;
+    mach->__rflags = LibVEX_GuestAMD64_get_rflags(vex);
+    mach->__rip = vex->guest_RIP;
+    mach->__r8  = vex->guest_R8;
+    mach->__r9  = vex->guest_R9;
+    mach->__r10 = vex->guest_R10;
+    mach->__r11 = vex->guest_R11;
+    mach->__r12 = vex->guest_R12;
+    mach->__r13 = vex->guest_R13;
+    mach->__r14 = vex->guest_R14;
+    mach->__r15 = vex->guest_R15;
+    /* GrP fixme
+    mach->__cs = vex->guest_CS;
+    mach->__fs = vex->guest_FS;
+    mach->__gs = vex->guest_GS;
+    */
+}
+
+
+static void x86_float_state64_from_vex(x86_float_state64_t *mach, 
+                                       VexGuestAMD64State *vex)
+{
+   // DDD: #warning GrP fixme fp state
+
+   VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_from_vex(thread_state_t mach_generic, 
+                           thread_state_flavor_t flavor, 
+                           mach_msg_type_number_t count, 
+                           VexGuestArchState *vex_generic)
+{
+   VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
+
+   switch (flavor) {
+   case x86_THREAD_STATE64:
+      vg_assert(count == x86_THREAD_STATE64_COUNT);
+      x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
+      break;
+
+   case x86_FLOAT_STATE64:
+      vg_assert(count == x86_FLOAT_STATE64_COUNT);
+      x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
+      break;
+       
+   default:
+      vg_assert(0);
+   }
+}
+
+
+static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach, 
+                                      VexGuestAMD64State *vex)
+{
+   LibVEX_GuestAMD64_initialise(vex);
+   vex->guest_RAX = mach->__rax;
+   vex->guest_RBX = mach->__rbx;
+   vex->guest_RCX = mach->__rcx;
+   vex->guest_RDX = mach->__rdx;
+   vex->guest_RDI = mach->__rdi;
+   vex->guest_RSI = mach->__rsi;
+   vex->guest_RBP = mach->__rbp;
+   vex->guest_RSP = mach->__rsp;
+   // DDD: #warning GrP fixme eflags
+   vex->guest_RIP = mach->__rip;
+   vex->guest_R8  = mach->__r8;
+   vex->guest_R9  = mach->__r9;
+   vex->guest_R10 = mach->__r10;
+   vex->guest_R11 = mach->__r11;
+   vex->guest_R12 = mach->__r12;
+   vex->guest_R13 = mach->__r13;
+   vex->guest_R14 = mach->__r14;
+   vex->guest_R15 = mach->__r15;
+   /* GrP fixme 
+   vex->guest_CS = mach->__cs;
+   vex->guest_FS = mach->__fs;
+   vex->guest_GS = mach->__gs;
+   */
+}
+
+static void x86_float_state64_to_vex(const x86_float_state64_t *mach, 
+                                     VexGuestAMD64State *vex)
+{
+   // DDD: #warning GrP fixme fp state
+
+   VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_to_vex(const thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         VexGuestArchState *vex_generic)
+{
+   VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
+   
+   switch(flavor) {
+   case x86_THREAD_STATE64:
+      vg_assert(count == x86_THREAD_STATE64_COUNT);
+      x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
+      break;
+   case x86_FLOAT_STATE64:
+      vg_assert(count == x86_FLOAT_STATE64_COUNT);
+      x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
+      break;
+
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+
+ThreadState *build_thread(const thread_state_t state, 
+                          thread_state_flavor_t flavor, 
+                          mach_msg_type_number_t count)
+{
+   ThreadId tid = VG_(alloc_ThreadState)();
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+    
+   vg_assert(flavor == x86_THREAD_STATE64);
+   vg_assert(count == x86_THREAD_STATE64_COUNT);
+
+   // Initialize machine registers
+
+   thread_state_to_vex(state, flavor, count, &tst->arch.vex);
+
+   I_die_here;
+   // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
+
+   find_stack_segment(tid, tst->arch.vex.guest_RSP);
+
+   return tst;
+}
+
+
+// Edit the thread state to send to the real kernel.
+// The real thread will run start_thread_NORETURN(tst)
+// on a separate non-client stack.
+void hijack_thread_state(thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         ThreadState *tst)
+{
+   x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
+   char *stack;
+
+   vg_assert(flavor == x86_THREAD_STATE64);
+   vg_assert(count == x86_THREAD_STATE64_COUNT);
+
+   stack = (char *)allocstack(tst->tid);
+   stack -= 64+320;                       // make room for top frame
+   memset(stack, 0, 64+320);              // ...and clear it
+   *(uintptr_t *)stack = 0;               // push fake return address
+
+   mach->__rdi = (uintptr_t)tst;          // arg1 = tst
+   mach->__rip = (uintptr_t)&start_thread_NORETURN;
+   mach->__rsp = (uintptr_t)stack;
+}
+
+
+/* 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 call_on_new_stack_0_1 ( Addr stack,
+			     Addr retaddr,
+			     void (*f)(Word),
+                             Word arg1 );
+// %rdi == stack (must be 16-byte aligned)
+// %rsi == retaddr
+// %rdx == f
+// %rcx == arg1
+asm(
+".globl _call_on_new_stack_0_1\n"
+"_call_on_new_stack_0_1:\n"
+"   movq  %rsp, %rbp\n"     // remember old stack pointer
+"   movq  %rdi, %rsp\n"     // set new stack
+"   movq  %rcx, %rdi\n"     // set arg1
+"   pushq %rsi\n"           // retaddr to new stack
+"   pushq %rdx\n"           // f to new stack
+"   movq $0, %rax\n"        // zero all other GP regs
+"   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
+);
+
+asm(
+".globl _pthread_hijack_asm\n"
+"_pthread_hijack_asm:\n"
+"   movq %rsp,%rbp\n"
+"   push $0\n"    // alignment pad
+"   push %rbp\n"  // original sp
+                  // other values stay where they are in registers
+"   push $0\n"    // fake return address
+"   jmp _pthread_hijack\n"
+    );
+
+
+
+void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
+                    Addr stacksize, Addr flags, Addr sp)
+{
+   ThreadState *tst = (ThreadState *)func_arg;
+   VexGuestAMD64State *vex = &tst->arch.vex;
+
+   // VG_(printf)("pthread_hijack pthread %p, machthread %p, func %p, arg %p, stack %p, flags %p, stack %p\n", self, kport, func, func_arg, stacksize, flags, sp);
+
+   // Wait for parent thread's permission.
+   // The parent thread holds V's lock on our behalf.
+   semaphore_wait(tst->os_state.child_go);
+
+   // Set thread's registers
+   // Do this FIRST because some code below tries to collect a backtrace, 
+   // which requires valid register data.
+   LibVEX_GuestAMD64_initialise(vex);
+   vex->guest_RIP = pthread_starter;
+   vex->guest_RDI = self;
+   vex->guest_RSI = kport;
+   vex->guest_RDX = func;
+   vex->guest_RCX = tst->os_state.func_arg;
+   vex->guest_R8  = stacksize;
+   vex->guest_R9  = flags;
+   vex->guest_RSP = sp;
+
+   // Record thread's stack and Mach port and pthread struct
+   tst->os_state.pthread = self;
+   tst->os_state.lwpid = kport;
+   record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
+
+   if ((flags & 0x01000000) == 0) {
+      // kernel allocated stack - needs mapping
+      Addr stack = VG_PGROUNDUP(sp) - stacksize;
+      tst->client_stack_highest_word = stack+stacksize;
+      tst->client_stack_szB = stacksize;
+
+      // pthread structure
+      ML_(notify_core_and_tool_of_mmap)(
+            stack+stacksize, pthread_structsize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // stack contents
+      ML_(notify_core_and_tool_of_mmap)(
+            stack, stacksize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // guard page
+      ML_(notify_core_and_tool_of_mmap)(
+            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
+   } else {
+      // client allocated stack
+      find_stack_segment(tst->tid, sp);
+   }
+   VG_(am_do_sync_check)("after", "pthread_hijack", 0);
+
+   // Tell parent thread's POST(sys_bsdthread_create) that we're done 
+   // initializing registers and mapping memory.
+   semaphore_signal(tst->os_state.child_done);
+   // LOCK IS GONE BELOW THIS POINT
+
+   // Go!
+   call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
+                         start_thread_NORETURN, (Word)tst);
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+
+
+asm(
+".globl _wqthread_hijack_asm\n"
+"_wqthread_hijack_asm:\n"
+"   movq %rsp,%r9\n"  // original sp
+                      // other values stay where they are in registers
+"   push $0\n"        // fake return address
+"   jmp _wqthread_hijack\n"
+    );
+
+
+/*
+  wqthread note: The kernel may create or destroy pthreads in the 
+    wqthread pool at any time with no userspace interaction, 
+    and wqthread_start may be entered at any time with no userspace 
+    interaction.
+    To handle this in valgrind, we create and destroy a valgrind 
+    thread for every work item.
+*/
+void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
+                     Int reuse, Addr sp)
+{
+   ThreadState *tst;
+   VexGuestAMD64State *vex;
+   Addr stack;
+   SizeT stacksize;
+
+   if (reuse) {
+       // This thread already exists; we're merely re-entering 
+       // after leaving via workq_ops(WQOPS_THREAD_RETURN). 
+       // Don't allocate any V thread resources.
+       // Do reset thread registers.
+       ThreadId tid = VG_(lwpid_to_vgtid)(kport);
+       vg_assert(VG_(is_valid_tid)(tid));
+       vg_assert(mach_thread_self() == kport);
+
+       tst = VG_(get_ThreadState)(tid);
+       vex = &tst->arch.vex;
+       vg_assert(tst->os_state.pthread == self);
+   }
+   else {
+       // This is a new thread.
+       tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());        
+       vex = &tst->arch.vex;
+       allocstack(tst->tid);
+       LibVEX_GuestAMD64_initialise(vex);
+   }
+       
+   // Set thread's registers
+   // Do this FIRST because some code below tries to collect a backtrace, 
+   // which requires valid register data.
+   vex->guest_RIP = wqthread_starter;
+   vex->guest_RDI = self;
+   vex->guest_RSI = kport;
+   vex->guest_RDX = stackaddr;
+   vex->guest_RCX = workitem;
+   vex->guest_R8  = reuse;
+   vex->guest_R9  = 0;
+   vex->guest_RSP = sp;
+
+   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
+   stack = VG_PGROUNDUP(sp) - stacksize;
+
+   if (reuse) {
+      // Continue V's thread back in the scheduler. 
+      // The client thread is of course in another location entirely.
+      ML_(wqthread_continue_NORETURN)(tst->tid);
+   } 
+   else {
+
+      // Record thread's stack and Mach port and pthread struct
+      tst->os_state.pthread = self;
+      tst->os_state.lwpid = kport;
+      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
+      
+      // kernel allocated stack - needs mapping
+      tst->client_stack_highest_word = stack+stacksize;
+      tst->client_stack_szB = stacksize;
+
+      // GrP fixme scheduler lock?!
+      
+      // pthread structure
+      ML_(notify_core_and_tool_of_mmap)(
+            stack+stacksize, pthread_structsize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // stack contents
+      // GrP fixme uninitialized!
+      ML_(notify_core_and_tool_of_mmap)(
+            stack, stacksize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // guard page
+      // GrP fixme ban_mem_stack!
+      ML_(notify_core_and_tool_of_mmap)(
+            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
+
+      VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
+
+      // Go!
+      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
+                            start_thread_NORETURN, (Word)tst);
+   }
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
diff --git a/coregrind/m_syswrap/syswrap-darwin.c b/coregrind/m_syswrap/syswrap-darwin.c
new file mode 100644
index 0000000..49b8a9a
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-darwin.c
@@ -0,0 +1,7549 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc.              syswrap-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.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_debuginfo.h"    // VG_(di_notify_*)
+#include "pub_core_transtab.h"     // VG_(discard_translations)
+#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"
+#include "pub_core_machine.h"      // VG_(get_SP)
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h"      // For VG_(sigframe_destroy)()
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"   /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h"    /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <semaphore.h>
+#include <sys/acl.h>   /* struct kauth_filesec */
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+#define msgh_request_port      msgh_remote_port
+#define msgh_reply_port        msgh_local_port
+#define BOOTSTRAP_MAX_NAME_LEN                  128
+typedef char name_t[BOOTSTRAP_MAX_NAME_LEN];
+
+typedef uint64_t mig_addr_t;
+
+
+// Saved ports
+static mach_port_t vg_host_port = 0;
+static mach_port_t vg_task_port = 0;
+static mach_port_t vg_bootstrap_port = 0;
+
+// 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-darwin", 
+                    "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");
+
+   if (0)
+      VG_(printf)("thread tid %d started: stack = %p\n",
+                  tid, &tid);
+
+   VG_TRACK(pre_thread_first_insn, tid);
+
+   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-darwin", 
+                    "thread_wrapper(tid=%lld): done\n", 
+                    (ULong)tidW);
+
+   /* Return to caller, still holding the lock. */
+   return ret;
+}
+
+
+
+/* Allocate a stack for this thread, if it doesn't already have one.
+   Returns the initial stack pointer value to use, or 0 if allocation
+   failed. */
+
+Addr 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;
+      }
+   }
+
+   VG_(debugLog)( 2, "syswrap-darwin", "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 );
+
+   vg_assert(VG_IS_32_ALIGNED(tst->os_state.valgrind_stack_init_SP));
+   
+   return tst->os_state.valgrind_stack_init_SP;
+}
+
+
+void find_stack_segment(ThreadId tid, Addr sp)
+{
+   /* We don't really know where the client stack is, because it's
+      allocated by the client.  The best we can do is look at the
+      memory mappings and try to derive some useful information.  We
+      assume that esp starts near its highest possible value, and can
+      only go down to the start of the mmaped segment. */
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   const NSegment *seg = VG_(am_find_nsegment)(sp);
+   if (seg && seg->kind != SkResvn) {
+      tst->client_stack_highest_word = (Addr)VG_PGROUNDUP(sp);
+      tst->client_stack_szB = tst->client_stack_highest_word - seg->start;
+
+      if (1)
+         VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
+                     tid, seg->start, VG_PGROUNDUP(sp));
+   } else {
+       VG_(printf)("couldn't find user stack\n");
+      VG_(message)(Vg_UserMsg, "!? New thread %d starts with SP(%#lx) unmapped\n",
+                   tid, sp);
+      tst->client_stack_szB  = 0;
+   }
+}
+
+
+/* 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 )
+{
+   Int               c;
+   VgSchedReturnCode src;
+   ThreadId tid = (ThreadId)tidW;
+
+   VG_(debugLog)(1, "syswrap-darwin", 
+                    "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n",
+                    (ULong)tidW);
+
+   /* Run the thread all the way through. */
+   src = thread_wrapper(tid);  
+
+   VG_(debugLog)(1, "syswrap-darwin", 
+                    "run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
+                    (ULong)tidW);
+
+   c = VG_(count_living_threads)();
+   vg_assert(c >= 1); /* stay sane */
+
+   // Tell the tool this thread is exiting
+   VG_TRACK( pre_thread_ll_exit, tid );
+
+   if (c == 1) {
+
+      VG_(debugLog)(1, "syswrap-darwin", 
+                       "run_a_thread_NORETURN(tid=%lld): "
+                          "last one standing\n",
+                          (ULong)tidW);
+
+      /* We are the last one 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. */
+      ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src);
+
+   } else {
+
+      ThreadState *tst;
+      mach_msg_header_t msg;
+
+      VG_(debugLog)(1, "syswrap-darwin", 
+                       "run_a_thread_NORETURN(tid=%lld): "
+                          "not last one standing\n",
+                          (ULong)tidW);
+
+      /* OK, thread is dead, but others still exist.  Just exit. */
+      tst = VG_(get_ThreadState)(tid);
+
+      /* This releases the run lock */
+      VG_(exit_thread)(tid);
+      vg_assert(tst->status == VgTs_Zombie);
+
+      /* tid is now invalid. */
+
+      // GrP fixme exit race
+      msg.msgh_bits = MACH_MSGH_BITS(17, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+      msg.msgh_request_port = VG_(gettid)();
+      msg.msgh_reply_port = 0;
+      msg.msgh_id = 3600;  // thread_terminate
+      
+      tst->status = VgTs_Empty;
+      // GrP fixme race here! new thread may claim this V thread stack 
+      // before we get out here!
+      // GrP fixme use bsdthread_terminate for safe cleanup?
+      mach_msg(&msg, MACH_SEND_MSG|MACH_MSG_OPTION_NONE, 
+               sizeof(msg), 0, 0, MACH_MSG_TIMEOUT_NONE, 0);
+      
+      // DDD: This is reached sometimes on none/tests/manythreads, maybe
+      // because of the race above.
+      VG_(core_panic)("Thread exit failed?\n");
+   }
+   
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+
+/* 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.
+*/
+void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
+{
+   Addr sp;
+   VG_(debugLog)(1, "syswrap-darwin", 
+                    "entering VG_(main_thread_wrapper_NORETURN)\n");
+
+   sp = allocstack(tid);
+
+   /* 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 );
+   
+   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);
+}
+
+
+void start_thread_NORETURN ( Word arg )
+{
+   ThreadState* tst = (ThreadState*)arg;
+   ThreadId     tid = tst->tid;
+
+   run_a_thread_NORETURN ( (Word)tid );
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+
+void VG_(cleanup_thread) ( ThreadArchState* arch )
+{
+}  
+
+
+/* ---------------------------------------------------------------------
+   Mach port tracking (based on syswrap-generic's fd tracker)
+   ------------------------------------------------------------------ */
+
+/* One of these is allocated for each open port.  */
+typedef struct OpenPort
+{
+   mach_port_t port;
+   mach_port_type_t type;         /* right type(s) */
+   Int send_count;                /* number of send rights */
+   Char *name;                    /* bootstrap name or NULL */
+   ExeContext *where;             /* first allocation only */
+   struct OpenPort *next, *prev;
+} OpenPort;
+
+// strlen("0x12345678")
+#define PORT_STRLEN (2+2*sizeof(mach_port_t))
+
+/* List of allocated ports. */
+static OpenPort *allocated_ports;
+
+/* Count of open ports. */
+static Int allocated_port_count = 0;
+
+
+__attribute__((unused))
+static Bool port_exists(mach_port_t port)
+{
+   OpenPort *i;
+
+   /* Check to see if this port is already open. */
+   i = allocated_ports;
+   while (i) {
+      if (i->port == port) {
+         return True;
+      }
+      i = i->next;
+   }
+   
+   return False;
+}
+
+static OpenPort *info_for_port(mach_port_t port)
+{
+   OpenPort *i;
+   if (!port) return NULL;
+
+   i = allocated_ports;
+   while (i) {
+      if (i->port == port) {
+         return i;
+      }
+      i = i->next;
+   }
+
+   return NULL;
+}
+
+
+// Give a port a name, without changing its refcount
+// GrP fixme don't override name if it already has a specific one
+__private_extern__ void assign_port_name(mach_port_t port, const char *name)
+{
+   OpenPort *i;
+   if (!port) return;
+   vg_assert(name);
+
+   i = info_for_port(port);
+   vg_assert(i);
+
+   if (i->name) VG_(arena_free)(VG_AR_CORE, i->name);
+   i->name = 
+       VG_(arena_malloc)(VG_AR_CORE, "syswrap-darwin.mach-port-name", 
+                         VG_(strlen)(name) + PORT_STRLEN + 1);
+   VG_(sprintf)(i->name, name, port);
+}
+
+
+// Return the name of the given port or "UNKNOWN 0x1234" if not known.
+static const char *name_for_port(mach_port_t port)
+{
+   static char buf[8 + PORT_STRLEN + 1];
+   OpenPort *i;
+
+   // hack
+   if (port == VG_(gettid)()) return "mach_thread_self()";
+   if (port == 0) return "NULL";
+
+   i = allocated_ports;
+   while (i) {
+      if (i->port == port) {
+         return i->name;
+      }
+      i = i->next;
+   }
+
+   VG_(sprintf)(buf, "NONPORT-%#x", port);
+   return buf;
+}
+
+/* Note the fact that a port was just deallocated. */
+
+static
+void record_port_mod_refs(mach_port_t port, mach_port_type_t right, Int delta)
+{
+   OpenPort *i = allocated_ports;
+   if (!port) return;
+
+   while(i) {
+      if(i->port == port) {
+         vg_assert(right != MACH_PORT_TYPE_DEAD_NAME);
+         if (right & MACH_PORT_TYPE_SEND) {
+            // send rights are refcounted
+            if (delta == INT_MIN) delta = -i->send_count; // INT_MIN == destroy
+            i->send_count += delta;
+            if (i->send_count > 0) i->type |= MACH_PORT_TYPE_SEND;
+            else i->type &= ~MACH_PORT_TYPE_SEND;
+         } 
+         right = right & ~MACH_PORT_TYPE_SEND;
+         if (right) {
+            // other rights are not refcounted
+            if (delta > 0) {
+               i->type |= right;
+            } else if (delta < 0) {
+               i->type &= ~right;
+            }
+         }
+
+         if (i->type != 0) return;
+
+         // Port has no rights left. Kill it.
+         // VG_(printf)("deleting port %p %s", i->port, i->name);
+         if(i->prev)
+            i->prev->next = i->next;
+         else
+            allocated_ports = i->next;
+         if(i->next)
+            i->next->prev = i->prev;
+         if(i->name) 
+            VG_(arena_free) (VG_AR_CORE, i->name);
+         VG_(arena_free) (VG_AR_CORE, i);
+         allocated_port_count--;
+         return;
+      }
+      i = i->next;
+   }
+
+   VG_(printf)("UNKNOWN Mach port modified (port %#x delta %d)\n", port, delta);
+}
+
+static 
+void record_port_insert_rights(mach_port_t port, mach_msg_type_name_t type)
+{
+   switch (type) {
+   case MACH_MSG_TYPE_PORT_NAME:
+      // this task has no rights for the name
+      break;
+   case MACH_MSG_TYPE_PORT_RECEIVE:
+      // this task gets receive rights
+      record_port_mod_refs(port, MACH_PORT_TYPE_RECEIVE, 1);
+      break;
+   case MACH_MSG_TYPE_PORT_SEND:
+      // this task gets a send right
+      record_port_mod_refs(port, MACH_PORT_TYPE_SEND, 1);
+      break;
+   case MACH_MSG_TYPE_PORT_SEND_ONCE:
+      // this task gets send-once rights
+      record_port_mod_refs(port, MACH_PORT_TYPE_SEND_ONCE, 1);
+      break;
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+static 
+void record_port_dealloc(mach_port_t port)
+{
+   // deletes 1 send or send-once right (port can't have both)
+   record_port_mod_refs(port, MACH_PORT_TYPE_SEND_RIGHTS, -1);
+}
+
+static 
+void record_port_destroy(mach_port_t port)
+{
+   // deletes all rights to port
+   record_port_mod_refs(port, MACH_PORT_TYPE_ALL_RIGHTS, INT_MIN);
+}
+
+
+/* Note the fact that a Mach port was just allocated or transferred.
+   If the port is already known, increment its reference count. */
+void record_named_port(ThreadId tid, mach_port_t port, 
+                       mach_port_right_t right, const char *name)
+{
+   OpenPort *i;
+   if (!port) return;
+
+   /* Check to see if this port is already open. */
+   i = allocated_ports;
+   while (i) {
+      if (i->port == port) {
+         if (right != -1) record_port_mod_refs(port, MACH_PORT_TYPE(right), 1);
+         return;
+      }
+      i = i->next;
+   }
+
+   /* Not already one: allocate an OpenPort */
+   if (i == NULL) {
+      i = VG_(arena_malloc)(VG_AR_CORE, "syswrap-darwin.mach-port", 
+                            sizeof(OpenPort));
+
+      i->prev = NULL;
+      i->next = allocated_ports;
+      if(allocated_ports) allocated_ports->prev = i;
+      allocated_ports = i;
+      allocated_port_count++;
+
+      i->port = port;
+      i->where = (tid == -1) ? NULL : VG_(record_ExeContext)(tid, 0);
+      i->name = NULL;
+      if (right != -1) {
+         i->type = MACH_PORT_TYPE(right);
+         i->send_count = (right == MACH_PORT_RIGHT_SEND) ? 1 : 0;
+      } else {
+         i->type = 0;
+         i->send_count = 0;
+      }
+      
+      assign_port_name(port, name);
+   }
+}
+
+
+// Record opening of a nameless port.
+static void record_unnamed_port(ThreadId tid, mach_port_t port, mach_port_right_t right)
+{
+   record_named_port(tid, port, right, "unnamed-%p");
+}
+
+
+/* Dump summary of open Mach ports, like VG_(show_open_fds) */
+void VG_(show_open_ports)(void)
+{
+   OpenPort *i;
+   
+   VG_(message)(Vg_UserMsg, 
+                "MACH PORTS: %d open at exit.", allocated_port_count);
+
+   for (i = allocated_ports; i; i = i->next) {
+      if (i->name) {
+         VG_(message)(Vg_UserMsg, "Open Mach port 0x%x: %s", i->port, i->name);
+      } else {
+         VG_(message)(Vg_UserMsg, "Open Mach port 0x%x", i->port);
+      }
+
+      if (i->where) {
+         VG_(pp_ExeContext)(i->where);
+         VG_(message)(Vg_UserMsg, "");
+      }
+   }
+
+   VG_(message)(Vg_UserMsg, "");
+}
+
+
+/* ---------------------------------------------------------------------
+   sync_mappings
+   ------------------------------------------------------------------ */
+
+static void sync_mappings(const HChar *when, const HChar *where, Int num)
+{
+   // I haven't seen more than 1 segment be added or removed in a single calls
+   // to sync_mappings().  So 20 seems generous.  The upper bound is the
+   // number of segments currently in use.  --njn
+   #define CSS_SIZE     20
+   ChangedSeg css[CSS_SIZE];
+   Int        css_used;
+   Int        i;
+
+   VG_(get_changed_segments)(when, where, css, CSS_SIZE, &css_used);
+
+   // Now add/remove them.
+   for (i = 0; i < css_used; i++) {
+      ChangedSeg* cs = &css[i];
+      Char* action;
+      if (cs->is_added) {
+         ML_(notify_core_and_tool_of_mmap)(
+               cs->start, cs->end - cs->start + 1,
+               cs->prot, VKI_MAP_PRIVATE, 0, cs->offset);
+         // should this call VG_(di_notify_mmap) also?
+         action = "added";
+
+      } else {
+         ML_(notify_core_and_tool_of_munmap)(
+               cs->start, cs->end - cs->start + 1);
+         action = "removed";
+      }
+      if (VG_(clo_trace_syscalls)) {
+          VG_(debugLog)(0, "aspacem",
+                        "\n%s region 0x%010lx..0x%010lx at %s (%s)\n", 
+                        action, cs->start, cs->end + 1, where, when);
+      }
+   }
+}
+
+/* ---------------------------------------------------------------------
+   wrappers
+   ------------------------------------------------------------------ */
+
+#define PRE(name)       DEFN_PRE_TEMPLATE(darwin, name)
+#define POST(name)      DEFN_POST_TEMPLATE(darwin, name)
+
+#define PRE_FN(name)    vgSysWrap_darwin_##name##_before
+#define POST_FN(name)   vgSysWrap_darwin_##name##_after
+
+#define CALL_PRE(name) PRE_FN(name)(tid, layout, arrghs, status, flags)
+#define CALL_POST(name) POST_FN(name)(tid, arrghs, status)
+
+#if VG_WORDSIZE == 4
+// Combine two 32-bit values into a 64-bit value
+// Always use with low-numbered arg first (e.g. LOHI64(ARG1,ARG2) )
+# if defined(VGA_x86)
+#  define LOHI64(lo,hi)   ( (lo) | ((ULong)(hi) << 32) )
+# else
+#  error unknown architecture
+# endif
+#endif
+
+// Retrieve the current Mach thread
+#define MACH_THREAD ((Addr)VG_(get_ThreadState)(tid)->os_state.lwpid)
+
+// Set the POST handler for a mach_msg derivative
+#define AFTER VG_(get_ThreadState)(tid)->os_state.post_mach_trap_fn
+
+// Set or get values saved from Mach messages
+#define MACH_ARG(x) VG_(get_ThreadState)(tid)->os_state.mach_args.x
+#define MACH_REMOTE VG_(get_ThreadState)(tid)->os_state.remote_port
+#define MACH_MSGH_ID VG_(get_ThreadState)(tid)->os_state.msgh_id
+
+/* ---------------------------------------------------------------------
+   darwin ioctl wrapper
+   ------------------------------------------------------------------ */
+
+PRE(sys_ioctl)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_ioctl ( %ld, 0x%lx, %#lx )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "ioctl",
+                 unsigned int, fd, unsigned int, request, unsigned long, arg);
+
+   switch (ARG2 /* request */) {
+   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_TIOCMBIS:
+      PRE_MEM_READ( "ioctl(TIOCMBIS)",    ARG3, sizeof(unsigned int) );
+      break;
+   case VKI_TIOCMBIC:
+      PRE_MEM_READ( "ioctl(TIOCMBIC)",    ARG3, sizeof(unsigned int) );
+      break;
+   case VKI_TIOCMSET:
+      PRE_MEM_READ( "ioctl(TIOCMSET)",    ARG3, sizeof(unsigned int) );
+      break;
+   case VKI_TIOCMGET:
+      PRE_MEM_WRITE( "ioctl(TIOCMGET)",   ARG3, sizeof(unsigned int) );
+      break;
+   case VKI_TIOCGPGRP:
+      /* Get process group ID for foreground processing group. */
+      PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
+      break;
+   case VKI_TIOCSPGRP:
+      /* Set a process group ID? */
+      PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
+      break;
+   case VKI_TIOCSCTTY:
+      /* Just takes an int value.  */
+      break;
+   case VKI_FIONBIO:
+      PRE_MEM_READ( "ioctl(FIONBIO)",    ARG3, sizeof(int) );
+      break;
+   case VKI_FIOASYNC:
+      PRE_MEM_READ( "ioctl(FIOASYNC)",   ARG3, sizeof(int) );
+      break;
+   case VKI_FIONREAD:                /* identical to SIOCINQ */
+      PRE_MEM_WRITE( "ioctl(FIONREAD)",  ARG3, sizeof(int) );
+      break;
+
+
+      /* These all use struct ifreq AFAIK */
+      /* GrP fixme is sizeof(struct vki_if_req) correct if it's using a sockaddr? */
+   case VKI_SIOCGIFFLAGS:        /* get flags                    */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFFLAGS)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFFLAGS)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFMTU:          /* get MTU size                 */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMTU)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFMTU)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFADDR:         /* get PA address               */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFADDR)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFADDR)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFNETMASK:      /* get network PA mask          */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFNETMASK)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFNETMASK)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFMETRIC:       /* get metric                   */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMETRIC)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFMETRIC)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFDSTADDR:      /* get remote PA address        */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFDSTADDR)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFDSTADDR)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFBRDADDR:      /* get broadcast PA address     */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCGIFBRDADDR)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_WRITE( "ioctl(SIOCGIFBRDADDR)", ARG3, sizeof(struct vki_ifreq));
+      break;
+   case VKI_SIOCGIFCONF:         /* get iface list               */
+      /* WAS:
+         PRE_MEM_WRITE( "ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
+         KERNEL_DO_SYSCALL(tid,RES);
+         if (!VG_(is_kerror)(RES) && RES == 0)
+         POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
+      */
+      PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
+                    (Addr)&((struct vki_ifconf *)ARG3)->ifc_len,
+                    sizeof(((struct vki_ifconf *)ARG3)->ifc_len));
+      PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
+                    (Addr)&((struct vki_ifconf *)ARG3)->vki_ifc_buf,
+                    sizeof(((struct vki_ifconf *)ARG3)->vki_ifc_buf));
+      if ( ARG3 ) {
+         // TODO len must be readable and writable
+         // buf pointer only needs to be readable
+         struct vki_ifconf *ifc = (struct vki_ifconf *) ARG3;
+         PRE_MEM_WRITE( "ioctl(SIOCGIFCONF).ifc_buf",
+                        (Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
+      }
+      break;
+                    
+   case VKI_SIOCSIFFLAGS:        /* set flags                    */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCSIFFLAGS)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_READ( "ioctl(SIOCSIFFLAGS)",
+                     (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_flags,
+                     sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_flags) );
+      break;
+   case VKI_SIOCSIFADDR:         /* set PA address               */
+   case VKI_SIOCSIFDSTADDR:      /* set remote PA address        */
+   case VKI_SIOCSIFBRDADDR:      /* set broadcast PA address     */
+   case VKI_SIOCSIFNETMASK:      /* set network PA mask          */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCSIF*ADDR)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_READ( "ioctl(SIOCSIF*ADDR)",
+                     (Addr)&((struct vki_ifreq *)ARG3)->ifr_addr,
+                     sizeof(((struct vki_ifreq *)ARG3)->ifr_addr) );
+      break;
+   case VKI_SIOCSIFMETRIC:       /* set metric                   */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMETRIC)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_READ( "ioctl(SIOCSIFMETRIC)",
+                     (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_metric,
+                     sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_metric) );
+      break;
+   case VKI_SIOCSIFMTU:          /* set MTU size                 */
+      PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMTU)",
+                     (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+      PRE_MEM_READ( "ioctl(SIOCSIFMTU)",
+                     (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_mtu,
+                     sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_mtu) );
+      break;
+      /* Routing table calls.  */
+#ifdef VKI_SIOCADDRT
+   case VKI_SIOCADDRT:           /* add routing table entry      */
+   case VKI_SIOCDELRT:           /* delete routing table entry   */
+      PRE_MEM_READ( "ioctl(SIOCADDRT/DELRT)", ARG3, 
+                    sizeof(struct vki_rtentry));
+      break;
+#endif
+
+   case VKI_SIOCGPGRP:
+      PRE_MEM_WRITE( "ioctl(SIOCGPGRP)", ARG3, sizeof(int) );
+      break;
+   case VKI_SIOCSPGRP:
+      PRE_MEM_READ( "ioctl(SIOCSPGRP)", ARG3, sizeof(int) );
+      //tst->sys_flags &= ~SfMayBlock;
+      break;
+
+   case VKI_FIODTYPE: 
+      PRE_MEM_WRITE( "ioctl(FIONREAD)", ARG3, sizeof(int) );
+      break;
+
+   case VKI_DTRACEHIOC_REMOVE: 
+   case VKI_DTRACEHIOC_ADDDOF: 
+       break;
+
+       // ttycom.h
+   case VKI_TIOCGETA:
+       PRE_MEM_WRITE( "ioctl(TIOCGETA)", ARG3, sizeof(struct vki_termios) );
+       break;
+   case VKI_TIOCSETA:
+       PRE_MEM_READ( "ioctl(TIOCSETA)", ARG3, sizeof(struct vki_termios) );
+       break;
+   case VKI_TIOCGETD:
+       PRE_MEM_WRITE( "ioctl(TIOCGETD)", ARG3, sizeof(int) );
+       break;
+   case VKI_TIOCSETD:
+       PRE_MEM_READ( "ioctl(TIOCSETD)", ARG3, sizeof(int) );
+       break;
+   case VKI_TIOCPTYGNAME:
+       PRE_MEM_WRITE( "ioctl(TIOCPTYGNAME)", ARG3, 128 );
+       break;
+   case VKI_TIOCPTYGRANT:
+   case VKI_TIOCPTYUNLK:
+       break;
+
+   default: 
+      ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
+      break;
+   }
+}
+
+
+POST(sys_ioctl)
+{
+   vg_assert(SUCCESS);
+   switch (ARG2 /* request */) {
+   case VKI_TIOCGWINSZ:
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_winsize) );
+      break;
+   case VKI_TIOCSWINSZ:
+   case VKI_TIOCMBIS:
+   case VKI_TIOCMBIC:
+   case VKI_TIOCMSET:
+      break;
+   case VKI_TIOCMGET:
+      POST_MEM_WRITE( ARG3, sizeof(unsigned int) );
+      break;
+   case VKI_TIOCGPGRP:
+      /* Get process group ID for foreground processing group. */
+      POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
+      break;
+   case VKI_TIOCSPGRP:
+      /* Set a process group ID? */
+      POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
+      break;
+   case VKI_TIOCSCTTY:
+      break;
+   case VKI_FIONBIO:
+      break;
+   case VKI_FIOASYNC:
+      break;
+   case VKI_FIONREAD:                /* identical to SIOCINQ */
+      POST_MEM_WRITE( ARG3, sizeof(int) );
+      break;
+
+      /* These all use struct ifreq AFAIK */
+   case VKI_SIOCGIFFLAGS:        /* get flags                    */
+      POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_flags,
+                      sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_flags) );
+      break;
+   case VKI_SIOCGIFMTU:          /* get MTU size                 */
+      POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_mtu,
+                      sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_mtu) );
+      break;
+   case VKI_SIOCGIFADDR:         /* get PA address               */
+   case VKI_SIOCGIFDSTADDR:      /* get remote PA address        */
+   case VKI_SIOCGIFBRDADDR:      /* get broadcast PA address     */
+   case VKI_SIOCGIFNETMASK:      /* get network PA mask          */
+      POST_MEM_WRITE(
+                (Addr)&((struct vki_ifreq *)ARG3)->ifr_addr,
+                sizeof(((struct vki_ifreq *)ARG3)->ifr_addr) );
+      break;
+   case VKI_SIOCGIFMETRIC:       /* get metric                   */
+      POST_MEM_WRITE(
+                (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_metric,
+                sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_metric) );
+      break;
+   case VKI_SIOCGIFCONF:         /* get iface list               */
+      /* WAS:
+         PRE_MEM_WRITE("ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
+         KERNEL_DO_SYSCALL(tid,RES);
+         if (!VG_(is_kerror)(RES) && RES == 0)
+         POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
+      */
+      if (RES == 0 && ARG3 ) {
+         struct vki_ifconf *ifc = (struct vki_ifconf *) ARG3;
+         if (ifc->vki_ifc_buf != NULL)
+            POST_MEM_WRITE( (Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
+      }
+      break;
+                    
+   case VKI_SIOCSIFFLAGS:        /* set flags                    */
+   case VKI_SIOCSIFDSTADDR:      /* set remote PA address        */
+   case VKI_SIOCSIFBRDADDR:      /* set broadcast PA address     */
+   case VKI_SIOCSIFNETMASK:      /* set network PA mask          */
+   case VKI_SIOCSIFMETRIC:       /* set metric                   */
+   case VKI_SIOCSIFADDR:         /* set PA address               */
+   case VKI_SIOCSIFMTU:          /* set MTU size                 */
+      break;
+
+#ifdef VKI_SIOCADDRT
+      /* Routing table calls.  */
+   case VKI_SIOCADDRT:           /* add routing table entry      */
+   case VKI_SIOCDELRT:           /* delete routing table entry   */
+      break;
+#endif
+
+   case VKI_SIOCGPGRP:
+      POST_MEM_WRITE(ARG3, sizeof(int));
+      break;
+   case VKI_SIOCSPGRP:
+      break;
+
+   case VKI_FIODTYPE: 
+      POST_MEM_WRITE( ARG3, sizeof(int) );
+      break;
+
+   case VKI_DTRACEHIOC_REMOVE: 
+   case VKI_DTRACEHIOC_ADDDOF: 
+       break;
+
+       // ttycom.h
+   case VKI_TIOCGETA:
+       POST_MEM_WRITE( ARG3, sizeof(struct vki_termios));
+       break;
+   case VKI_TIOCSETA:
+       break;
+   case VKI_TIOCGETD:
+       POST_MEM_WRITE( ARG3, sizeof(int) );
+       break;
+   case VKI_TIOCSETD:
+       break;
+   case VKI_TIOCPTYGNAME:
+       POST_MEM_WRITE( ARG3, 128);
+       break;
+   case VKI_TIOCPTYGRANT:
+   case VKI_TIOCPTYUNLK:
+       break;
+
+   default:
+      break;
+   }
+}
+
+
+/* ---------------------------------------------------------------------
+   darwin fcntl wrapper
+   ------------------------------------------------------------------ */
+static const char *name_for_fcntl(UWord cmd) {
+#define F(n) case VKI_##n: return #n
+   switch (cmd) {
+      F(F_CHKCLEAN);
+      F(F_RDAHEAD);
+      F(F_NOCACHE);
+      F(F_FULLFSYNC);
+      F(F_FREEZE_FS);
+      F(F_THAW_FS);
+      F(F_GLOBAL_NOCACHE);
+      F(F_PREALLOCATE);
+      F(F_SETSIZE);
+      F(F_RDADVISE);
+      F(F_READBOOTSTRAP);
+      F(F_WRITEBOOTSTRAP);
+      F(F_LOG2PHYS);
+      F(F_GETPATH);
+      F(F_PATHPKG_CHECK);
+      F(F_ADDSIGS);   
+   default:
+      return "UNKNOWN";
+   }
+#undef F
+}
+
+PRE(sys_fcntl)
+{
+   switch (ARG2) {
+   // These ones ignore ARG3.
+   case VKI_F_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETOWN:
+      PRINT("sys_fcntl ( %ld, %ld )", ARG1,ARG2);
+      PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
+      break;
+
+   // These ones use ARG3 as "arg".
+   case VKI_F_DUPFD:
+   case VKI_F_SETFD:
+   case VKI_F_SETFL:
+   case VKI_F_SETOWN:
+      PRINT("sys_fcntl[ARG3=='arg'] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd, unsigned long, arg);
+      break;
+
+   // These ones use ARG3 as "lock".
+   case VKI_F_GETLK:
+   case VKI_F_SETLK:
+   case VKI_F_SETLKW:
+      PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct flock64 *, lock);
+      // GrP fixme mem read sizeof(flock64)
+      if (ARG2 == VKI_F_SETLKW) 
+         *flags |= SfMayBlock;
+      break;
+
+       // none
+   case VKI_F_CHKCLEAN:
+   case VKI_F_RDAHEAD:
+   case VKI_F_NOCACHE:
+   case VKI_F_FULLFSYNC:
+   case VKI_F_FREEZE_FS:
+   case VKI_F_THAW_FS:
+   case VKI_F_GLOBAL_NOCACHE:
+      PRINT("sys_fcntl ( %ld, %s )", ARG1, name_for_fcntl(ARG1));
+      PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
+      break;
+
+       // struct fstore
+   case VKI_F_PREALLOCATE:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct fstore *, fstore);
+      {
+         struct vki_fstore *fstore = (struct vki_fstore *)ARG3;
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)", 
+                         fstore->fst_flags );
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)", 
+                         fstore->fst_posmode );
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)", 
+                         fstore->fst_offset );
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)", 
+                         fstore->fst_length );
+         PRE_FIELD_WRITE( "fcntl(F_PREALLOCATE, fstore->fst_bytesalloc)", 
+                          fstore->fst_bytesalloc);
+      }
+      break;
+
+       // off_t
+   case VKI_F_SETSIZE:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    vki_off_t *, offset);
+      break;
+
+       // struct radvisory
+   case VKI_F_RDADVISE:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct vki_radvisory *, radvisory);
+      {
+         struct vki_radvisory *radvisory = (struct vki_radvisory *)ARG3;
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, radvisory->ra_offset)", 
+                         radvisory->ra_offset );
+         PRE_FIELD_READ( "fcntl(F_PREALLOCATE, radvisory->ra_count)", 
+                         radvisory->ra_count );
+      }
+      break;
+
+       // struct fbootstraptransfer
+   case VKI_F_READBOOTSTRAP:
+   case VKI_F_WRITEBOOTSTRAP:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct fbootstraptransfer *, bootstrap);
+      PRE_MEM_READ( "fcntl(F_READ/WRITEBOOTSTRAP, bootstrap)", 
+                    ARG3, sizeof(struct vki_fbootstraptransfer) );
+      break;
+
+       // struct log2phys (out)
+   case VKI_F_LOG2PHYS:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct log2phys *, l2p);
+      PRE_MEM_WRITE( "fcntl(F_LOG2PHYS, l2p)", 
+                     ARG3, sizeof(struct vki_log2phys) );
+      break;
+
+       // char[maxpathlen] (out)
+   case VKI_F_GETPATH:
+      PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    char *, pathbuf);
+      PRE_MEM_WRITE( "fcntl(F_GETPATH, pathbuf)", 
+                     ARG3, VKI_MAXPATHLEN );
+      break;
+
+       // char[maxpathlen] (in)
+   case VKI_F_PATHPKG_CHECK:
+      PRINT("sys_fcntl ( %ld, %s, %#lx '%s')", ARG1, name_for_fcntl(ARG2), ARG3,
+          (char *)ARG3);
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    char *, pathbuf);
+      PRE_MEM_RASCIIZ( "fcntl(F_PATHPKG_CHECK, pathbuf)", ARG3);
+      break;
+
+   case VKI_F_ADDSIGS: /* Add detached signatures (for code signing) */
+      PRINT("sys_fcntl ( %ld, %s )", ARG1, name_for_fcntl(ARG2));
+      PRE_REG_READ3(long, "fcntl",
+                    unsigned int, fd, unsigned int, cmd,
+                    vki_fsignatures_t *, sigs);
+
+      {
+         vki_fsignatures_t *fsigs = (vki_fsignatures_t*)ARG3;
+         PRE_FIELD_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_start)",
+                         fsigs->fs_blob_start);
+         PRE_FIELD_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_size)",
+                         fsigs->fs_blob_size);
+
+         if (fsigs->fs_blob_start)
+            PRE_MEM_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_start)",
+                          (Addr)fsigs->fs_blob_start, fsigs->fs_blob_size);
+      }
+      break;
+
+   default:
+      PRINT("sys_fcntl ( %ld, %ld [??] )", ARG1, ARG2);
+      VG_(printf)("UNKNOWN fcntl %ld!", ARG2);
+      break;
+   }
+}
+
+POST(sys_fcntl)
+{
+   vg_assert(SUCCESS);
+   switch (ARG2) {
+   case VKI_F_DUPFD:
+      if (!ML_(fd_allowed)(RES, "fcntl(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_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETOWN:
+   case VKI_F_SETFD:
+   case VKI_F_SETFL:
+   case VKI_F_SETOWN:
+   case VKI_F_GETLK:
+   case VKI_F_SETLK:
+   case VKI_F_SETLKW:
+       break;
+
+   case VKI_F_PREALLOCATE:
+      {
+         struct vki_fstore *fstore = (struct vki_fstore *)ARG3;
+         POST_FIELD_WRITE( fstore->fst_bytesalloc );
+      }
+      break;
+
+   case VKI_F_LOG2PHYS:
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_log2phys) );
+      break;
+
+   case VKI_F_GETPATH:
+      POST_MEM_WRITE( ARG3, 1+VG_(strlen)((char *)ARG3) );
+      PRINT("\"%s\"", (char*)ARG3);
+      break;
+
+   default:
+      // DDD: ugh, missing lots of cases here, not nice
+      break;
+   }
+}
+
+// XXX: wrapper only suitable for 32-bit systems
+PRE(sys_fcntl64)
+{
+   switch (ARG2) {
+   // These ones ignore ARG3.
+   case VKI_F_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETOWN:
+      PRINT("sys_fcntl64 ( %ld, %ld )", ARG1,ARG2);
+      PRE_REG_READ2(long, "fcntl64", unsigned int, fd, unsigned int, cmd);
+      break;
+
+   // These ones use ARG3 as "arg".
+   case VKI_F_DUPFD:
+   case VKI_F_SETFD:
+   case VKI_F_SETFL:
+   case VKI_F_SETOWN:
+      PRINT("sys_fcntl64[ARG3=='arg'] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(long, "fcntl64",
+                    unsigned int, fd, unsigned int, cmd, unsigned long, arg);
+      break;
+
+   // These ones use ARG3 as "lock".
+   case VKI_F_GETLK:
+   case VKI_F_SETLK:
+   case VKI_F_SETLKW:
+      PRINT("sys_fcntl64[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(long, "fcntl64",
+                    unsigned int, fd, unsigned int, cmd,
+                    struct flock64 *, lock);
+   if (ARG2 == VKI_F_SETLKW)
+      *flags |= SfMayBlock;
+      break;
+
+   default:
+      I_die_here;    // DDD: do something better here
+      break;
+   }
+}
+
+POST(sys_fcntl64)
+{
+   vg_assert(SUCCESS);
+   switch (ARG2) {
+   case VKI_F_DUPFD:
+      if (!ML_(fd_allowed)(RES, "fcntl64(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_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETOWN:
+   case VKI_F_SETFD:
+   case VKI_F_SETFL:
+   case VKI_F_SETOWN:
+   case VKI_F_GETLK:
+   case VKI_F_SETLK:
+   case VKI_F_SETLKW:
+       break;
+
+   default:
+      I_die_here;    // DDD: do something better here
+      break;
+   }
+}
+
+/* ---------------------------------------------------------------------
+   unix syscalls
+   ------------------------------------------------------------------ */
+
+PRE(sys_futimes)
+{
+   PRINT("sys_futimes ( %ld, %#lx )", ARG1,ARG2);
+   PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, tvp);
+   if (ARG2 != 0) {
+      PRE_timeval_READ( "futimes(tvp[0])", ARG2 );
+      PRE_timeval_READ( "futimes(tvp[1])", ARG2+sizeof(struct vki_timeval) );
+   }
+}
+
+PRE(sys_semget)
+{
+   PRINT("sys_semget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "semget", vki_key_t, key, int, nsems, int, semflg);
+}
+
+PRE(sys_semop)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_semop ( %ld, %#lx, %lu )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "semop",
+                 int, semid, struct sembuf *, sops, vki_size_t, nsoops);
+   ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
+}
+
+PRE(sys_semctl)
+{
+   switch (ARG3) {
+   case VKI_IPC_STAT:
+   case VKI_IPC_SET:
+      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(long, "semctl",
+                    int, semid, int, semnum, int, cmd, struct semid_ds *, arg);
+      break;
+   case VKI_GETALL:
+   case VKI_SETALL:
+      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(long, "semctl",
+                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
+      break;
+   case VKI_SETVAL:
+      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(long, "semctl",
+                    int, semid, int, semnum, int, cmd, int, arg);
+      break;
+   default:
+      PRINT("sys_semctl ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+      PRE_REG_READ3(long, "semctl",
+                    int, semid, int, semnum, int, cmd);
+      break;
+   }
+   ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+POST(sys_semctl)
+{
+   ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
+}
+
+PRE(sys_sem_open)
+{
+   if (ARG2 & VKI_O_CREAT) {
+      // 4-arg version
+      PRINT("sys_sem_open ( %#lx(%s), %ld, %ld, %ld )",
+            ARG1,(char*)ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(vki_sem_t *, "sem_open",
+                    const char *, name, int, oflag, vki_mode_t, mode,
+                    unsigned int, value);
+   } else {
+      // 2-arg version
+      PRINT("sys_sem_open ( %#lx(%s), %ld )",ARG1,(char*)ARG1,ARG2);
+      PRE_REG_READ2(vki_sem_t *, "sem_open",
+                    const char *, name, int, oflag);
+   }
+   PRE_MEM_RASCIIZ( "sem_open(name)", ARG1 );
+
+   /* Otherwise handle normally */
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_close)
+{
+   PRINT("sem_close( %#lx )", ARG1);
+   PRE_REG_READ1(int, "sem_close", vki_sem_t *, sem);
+}
+
+PRE(sys_sem_unlink)
+{
+   PRINT("sem_unlink(  %#lx(%s) )", ARG1,(char*)ARG1);
+   PRE_REG_READ1(int, "sem_unlink", const char *, name);
+   PRE_MEM_RASCIIZ( "sem_unlink(name)", ARG1 );
+}
+
+PRE(sys_sem_post)
+{
+   PRINT("sem_post( %#lx )", ARG1);
+   PRE_REG_READ1(int, "sem_post", vki_sem_t *, sem);
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_destroy)
+{
+  PRINT("sem_destroy( %#lx )", ARG1);
+  PRE_REG_READ1(int, "sem_destroy", vki_sem_t *, sem);
+  PRE_MEM_READ("sem_destroy(sem)", ARG1, sizeof(vki_sem_t));
+}
+
+PRE(sys_sem_init)
+{
+  PRINT("sem_init( %#lx, %ld, %ld )", ARG1, ARG2, ARG3);
+  PRE_REG_READ3(int, "sem_init", vki_sem_t *, sem,
+                int, pshared, unsigned int, value);
+  PRE_MEM_WRITE("sem_init(sem)", ARG1, sizeof(vki_sem_t));
+}
+
+POST(sys_sem_init)
+{
+  POST_MEM_WRITE(ARG1, sizeof(vki_sem_t));
+}
+
+PRE(sys_sem_wait_nocancel)
+{
+   PRINT("sem_wait_nocancel( %#lx )", ARG1);
+   PRE_REG_READ1(int, "sem_wait_nocancel", vki_sem_t *, sem);
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_trywait)
+{
+   PRINT("sem_trywait( %#lx )", ARG1);
+   PRE_REG_READ1(int, "sem_trywait", vki_sem_t *, sem);
+   *flags |= SfMayBlock;
+}
+
+PRE(sys_kqueue)
+{
+    PRINT("kqueue()");
+}
+
+POST(sys_kqueue)
+{
+   if (!ML_(fd_allowed)(RES, "kqueue", 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, NULL);
+      }
+   }
+}
+
+PRE(sys_kevent)
+{
+   PRINT("kevent( %ld, %#lx, %ld, %#lx, %ld, %#lx )", 
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(int,"kevent", int,kq, 
+                 const struct vki_kevent *,changelist, int,nchanges, 
+                 struct vki_kevent *,eventlist, int,nevents, 
+                 const struct vki_timespec *,timeout);
+
+   if (ARG3) PRE_MEM_READ ("kevent(changelist)", 
+                           ARG2, ARG3 * sizeof(struct vki_kevent));
+   if (ARG5) PRE_MEM_WRITE("kevent(eventlist)", 
+                           ARG4, ARG5 * sizeof(struct vki_kevent));
+   if (ARG6) PRE_MEM_READ ("kevent(timeout)", 
+                           ARG6, sizeof(struct vki_timespec));
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_kevent)
+{
+   PRINT("kevent ret %ld dst %#lx (%zu)", RES, ARG4, sizeof(struct vki_kevent));
+   if (RES > 0) POST_MEM_WRITE(ARG4, RES * sizeof(struct vki_kevent));
+}
+
+
+Addr pthread_starter = 0;
+Addr wqthread_starter = 0;
+SizeT pthread_structsize = 0;
+
+PRE(sys_bsdthread_register)
+{
+   PRINT("bsdthread_register( %#lx, %#lx, %lu )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int,"__bsdthread_register", void *,"threadstart", 
+                 void *,"wqthread", size_t,"pthsize");
+
+   pthread_starter = ARG1;
+   wqthread_starter = ARG2;
+   pthread_structsize = ARG3;
+   ARG1 = (Word)&pthread_hijack_asm;
+   ARG2 = (Word)&wqthread_hijack_asm;
+}
+
+PRE(sys_workq_open)
+{
+   PRINT("workq_open()");
+   PRE_REG_READ0(int, "workq_open");
+
+   // This creates lots of threads and thread stacks under the covers, 
+   // but we ignore them all until some work item starts running on it.
+}
+
+static const char *workqop_name(int op)
+{
+   switch (op) {
+   case VKI_WQOPS_QUEUE_ADD: return "QUEUE_ADD";
+   case VKI_WQOPS_QUEUE_REMOVE: return "QUEUE_REMOVE";
+   case VKI_WQOPS_THREAD_RETURN: return "THREAD_RETURN";
+   default: return "?";
+   }
+}
+
+
+PRE(sys_workq_ops)
+{
+   PRINT("workq_ops( %ld(%s), %#lx, %ld )", ARG1, workqop_name(ARG1), ARG2,
+      ARG3);
+   PRE_REG_READ3(int,"workq_ops", int,"options", void *,"item", 
+                 int,"priority");
+
+   switch (ARG1) {
+   case VKI_WQOPS_QUEUE_ADD:
+   case VKI_WQOPS_QUEUE_REMOVE:
+      // GrP fixme need anything here?
+      // GrP fixme may block?
+      break;
+
+   case VKI_WQOPS_THREAD_RETURN: {
+      // The interesting case. The kernel will do one of two things:
+      // 1. Return normally. We continue; libc proceeds to stop the thread.
+      //    V does nothing special here.
+      // 2. Jump to wqthread_hijack. This wipes the stack and runs a 
+      //    new work item, and never returns from workq_ops. 
+      //    V handles this by longjmp() from wqthread_hijack back to the 
+      //    scheduler, which continues at the new client SP/IP/state.
+      //    This works something like V's signal handling.
+      //    To the tool, this looks like workq_ops() sometimes returns 
+      //    to a strange address.
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      tst->os_state.wq_jmpbuf_valid = True;
+      *flags |= SfMayBlock;  // GrP fixme true?
+      break;
+   }
+
+   default:
+      VG_(printf)("UNKNOWN workq_ops option %ld\n", ARG1);
+      break;
+   }
+}
+
+POST(sys_workq_ops)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   tst->os_state.wq_jmpbuf_valid = False;
+}
+
+
+
+PRE(sys___mac_syscall)
+{
+   PRINT("__mac_syscall( %#lx, %ld, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int,"__mac_syscall", char *,"policy", 
+                 int,"call", void *,"arg");
+
+   // GrP fixme check call's arg?
+   // GrP fixme check policy?
+}
+
+
+/* Not syswrap-generic's sys_exit, which exits only one thread.
+   More like syswrap-generic's sys_exit_group. */
+PRE(sys_exit)
+{
+   ThreadId     t;
+   ThreadState* tst;
+
+   PRINT("darwin exit( %ld )", ARG1);
+   PRE_REG_READ1(void, "exit", int, status);
+
+   tst = VG_(get_ThreadState)(tid);
+
+   /* A little complex; find all the threads with the same threadgroup
+      as this one (including this one), and mark them to exit */
+   for (t = 1; t < VG_N_THREADS; t++) {
+      if ( /* not alive */
+           VG_(threads)[t].status == VgTs_Empty 
+           /* GrP fixme zombie? */
+         )
+         continue;
+
+      VG_(threads)[t].exitreason = VgSrc_ExitProcess;
+      VG_(threads)[t].os_state.exitcode = ARG1;
+
+      if (t != tid)
+         VG_(get_thread_out_of_syscall)(t);     /* unblock it, if blocked */
+   }
+
+   /* We have to claim the syscall already succeeded. */
+   SET_STATUS_Success(0);
+}
+
+
+PRE(sys_sigaction)
+{
+   PRINT("sys_sigaction ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "sigaction",
+                 int, signum, vki_sigaction_toK_t *, act,
+                 vki_sigaction_fromK_t *, oldact);
+
+   if (ARG2 != 0) {
+      vki_sigaction_toK_t *sa = (vki_sigaction_toK_t *)ARG2;
+      PRE_MEM_READ( "sigaction(act->sa_handler)",
+                    (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
+      PRE_MEM_READ( "sigaction(act->sa_mask)",
+                    (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
+      PRE_MEM_READ( "sigaction(act->sa_flags)",
+                    (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
+   }
+   if (ARG3 != 0)
+      PRE_MEM_WRITE( "sigaction(oldact)",
+                     ARG3, sizeof(vki_sigaction_fromK_t));
+
+   SET_STATUS_from_SysRes(
+      VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t *)ARG2,
+                                  (vki_sigaction_fromK_t *)ARG3)
+   );
+}
+POST(sys_sigaction)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0 && ARG3 != 0)
+      POST_MEM_WRITE( ARG3, sizeof(vki_sigaction_fromK_t));
+}
+
+
+PRE(sys___pthread_sigmask)
+{
+   // GrP fixme
+   // JRS: arguments are identical to sigprocmask 
+   // (how, sigset_t*, sigset_t*).  Perhaps behave identically?
+   static Bool warned;
+   if (!warned) {
+      VG_(printf)("UNKNOWN __pthread_sigmask is unsupported. "
+                  "This warning will not be repeated.\n");
+      warned = True;
+   }
+   SET_STATUS_Success( 0 );
+}
+
+
+PRE(sys___pthread_canceled)
+{
+   *flags |= SfMayBlock; /* might kill this thread??? */
+   /* I don't think so -- I think it just changes the cancellation
+      state.  But taking no chances. */
+   PRINT("__pthread_canceled ( %ld )", ARG1);
+   PRE_REG_READ1(long, "__pthread_canceled", void*, arg1);
+}
+
+
+PRE(sys___pthread_markcancel)
+{
+   *flags |= SfMayBlock; /* might kill this thread??? */
+   PRINT("__pthread_markcancel ( %#lx )", ARG1);
+   PRE_REG_READ1(long, "__pthread_markcancel", void*, arg1);
+   /* Just let it go through.  No idea if this is correct. */
+}
+
+
+PRE(sys___disable_threadsignal)
+{
+   vki_sigset_t set;
+   PRINT("__disable_threadsignal(%ld, %ld, %ld)", ARG1, ARG2, ARG3);
+   /* I don't think this really looks at its arguments.  So don't
+      bother to check them. */
+
+   VG_(sigfillset)( &set );
+   SET_STATUS_from_SysRes(
+      VG_(do_sys_sigprocmask) ( tid, VKI_SIG_BLOCK, &set, NULL )
+   );
+
+   /* We don't expect that blocking all signals for this thread could
+      cause any more to be delivered (how could it?), but just in case
+      .. */
+   if (SUCCESS)
+      *flags |= SfPollAfter;
+}
+
+
+PRE(sys_kdebug_trace)
+{
+   PRINT("kdebug_trace(%ld, %ld, %ld, %ld, %ld, %ld)", 
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "kdebug_trace", 
+                 int,"code", int,"arg1", int,"arg2", 
+                 int,"arg3", int,"arg4", int,"arg5");
+   // GrP fixme anything else?
+}
+
+
+PRE(sys_seteuid)
+{
+    PRINT("seteuid(%ld)", ARG1);
+    PRE_REG_READ1(long, "seteuid", vki_uid_t, "uid");
+}
+
+
+PRE(sys_setegid)
+{
+    PRINT("setegid(%ld)", ARG1);
+    PRE_REG_READ1(long, "setegid", vki_uid_t, "uid");
+}
+
+PRE(sys_settid)
+{
+    PRINT("settid(%ld, %ld)", ARG1, ARG2);
+    PRE_REG_READ2(long, "settid", vki_uid_t, "uid", vki_gid_t, "gid");
+}
+
+/* XXX need to check whether we need POST operations for
+ * waitevent, watchevent, modwatch -- jpeach 
+ */
+PRE(sys_watchevent)
+{
+    PRINT("watchevent(%#lx, %#lx)", ARG1, ARG2);
+    PRE_REG_READ2(long, "watchevent",
+        vki_eventreq *, "event", unsigned int, "eventmask");
+
+    PRE_MEM_READ("watchevent(event)", ARG1, sizeof(vki_eventreq));
+    PRE_MEM_READ("watchevent(eventmask)", ARG2, sizeof(unsigned int));
+    *flags |= SfMayBlock;
+}
+
+#define WAITEVENT_FAST_POLL ((Addr)(struct timeval *)-1)
+PRE(sys_waitevent)
+{
+   PRINT("waitevent(%#lx, %#lx)", ARG1, ARG2);
+   PRE_REG_READ2(long, "waitevent",
+      vki_eventreq *, "event", struct timeval *, "timeout");
+   PRE_MEM_WRITE("waitevent(event)", ARG1, sizeof(vki_eventreq));
+
+   if (ARG2  &&  ARG2 != WAITEVENT_FAST_POLL) {
+      PRE_timeval_READ("waitevent(timeout)", ARG2);
+   }
+
+   /* XXX ((timeval*)-1) is valid for ARG2 -- jpeach */
+   *flags |= SfMayBlock;
+}
+
+POST(sys_waitevent)
+{
+   POST_MEM_WRITE(ARG1, sizeof(vki_eventreq));
+}
+
+PRE(sys_modwatch)
+{
+   PRINT("modwatch(%#lx, %#lx)", ARG1, ARG2);
+   PRE_REG_READ2(long, "modwatch",
+      vki_eventreq *, "event", unsigned int, "eventmask");
+
+   PRE_MEM_READ("modwatch(event)", ARG1, sizeof(vki_eventreq));
+   PRE_MEM_READ("modwatch(eventmask)", ARG2, sizeof(unsigned int));
+}
+
+PRE(sys_getxattr)
+{
+   PRINT("getxattr(%#lx(%s), %#lx(%s), %#lx, %lu, %lu, %ld)",
+         ARG1, (char *)ARG1, ARG2, (char *)ARG2, ARG3, ARG4, ARG5, ARG6);
+
+   PRE_REG_READ6(vki_ssize_t, "getxattr",
+                const char *, path, char *, name, void *, value,
+                vki_size_t, size, uint32_t, position, int, options);
+   PRE_MEM_RASCIIZ("getxattr(path)", ARG1);
+   PRE_MEM_RASCIIZ("getxattr(name)", ARG2);
+   PRE_MEM_WRITE( "getxattr(value)", ARG3, ARG4);
+}
+
+POST(sys_getxattr)
+{
+   vg_assert((vki_ssize_t)RES >= 0);
+   POST_MEM_WRITE(ARG3, (vki_ssize_t)RES);
+}
+
+PRE(sys_fgetxattr)
+{
+   PRINT("fgetxattr(%ld, %#lx(%s), %#lx, %lu, %lu, %ld)",
+      ARG1, ARG2, (char *)ARG2, ARG3, ARG4, ARG5, ARG6);
+
+   PRE_REG_READ6(vki_ssize_t, "fgetxattr",
+                 int, fd, char *, name, void *, value,
+                 vki_size_t, size, uint32_t, position, int, options);
+   PRE_MEM_RASCIIZ("getxattr(name)", ARG2);
+   PRE_MEM_WRITE( "getxattr(value)", ARG3, ARG4);
+}
+
+POST(sys_fgetxattr)
+{
+   vg_assert((vki_ssize_t)RES >= 0);
+   POST_MEM_WRITE(ARG3, (vki_ssize_t)RES);
+}
+
+PRE(sys_setxattr)
+{
+   PRINT("setxattr ( %#lx(%s), %#lx(%s), %#lx, %lu, %lu, %ld )", 
+         ARG1, (char *)ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5, ARG6 );
+   PRE_REG_READ6(int, "setxattr", 
+                 const char *,"path", char *,"name", void *,"value", 
+                 vki_size_t,"size", uint32_t,"position", int,"options" );
+   
+   PRE_MEM_RASCIIZ( "setxattr(path)", ARG1 );
+   PRE_MEM_RASCIIZ( "setxattr(name)", ARG2 );
+   PRE_MEM_READ( "setxattr(value)", ARG3, ARG4 );
+}
+
+
+PRE(sys_fsetxattr)
+{
+   PRINT( "fsetxattr ( %ld, %#lx(%s), %#lx, %lu, %lu, %ld )", 
+          ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5, ARG6 );
+   PRE_REG_READ6(int, "fsetxattr", 
+                 int,"fd", char *,"name", void *,"value", 
+                 vki_size_t,"size", uint32_t,"position", int,"options" );
+   
+   PRE_MEM_RASCIIZ( "fsetxattr(name)", ARG2 );
+   PRE_MEM_READ( "fsetxattr(value)", ARG3, ARG4 );
+}
+
+
+PRE(sys_listxattr)
+{
+   PRINT( "listxattr ( %#lx(%s), %#lx, %lu, %ld )", 
+          ARG1, (char *)ARG1, ARG2, ARG3, ARG4 );
+   PRE_REG_READ4 (long, "listxattr", 
+                 const char *,"path", char *,"namebuf", 
+                 vki_size_t,"size", int,"options" );
+   
+   PRE_MEM_RASCIIZ( "listxattr(path)", ARG1 );
+   PRE_MEM_WRITE( "listxattr(namebuf)", ARG2, ARG3 );
+   *flags |= SfMayBlock;
+}
+POST(sys_listxattr)
+{
+   vg_assert(SUCCESS);
+   vg_assert((vki_ssize_t)RES >= 0);
+   POST_MEM_WRITE( ARG2, (vki_ssize_t)RES );
+}
+
+
+PRE(sys_flistxattr)
+{
+   PRINT( "flistxattr ( %ld, %#lx, %lu, %ld )", 
+          ARG1, ARG2, ARG3, ARG4 );
+   PRE_REG_READ4 (long, "flistxattr", 
+                  int, "fd", char *,"namebuf", 
+                 vki_size_t,"size", int,"options" );
+   PRE_MEM_WRITE( "flistxattr(namebuf)", ARG2, ARG3 );
+   *flags |= SfMayBlock;
+}
+POST(sys_flistxattr)
+{
+   vg_assert(SUCCESS);
+   vg_assert((vki_ssize_t)RES >= 0);
+   POST_MEM_WRITE( ARG2, (vki_ssize_t)RES );
+}
+
+PRE(sys_shmget)
+{
+   PRINT("sys_shmget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "shmget", vki_key_t, key, vki_size_t, size, int, shmflg);
+}
+
+PRE(sys_shm_open)
+{
+   PRINT("shm_open(%#lx(%s), %ld, %ld)", ARG1, (char *)ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "shm_open",
+                 const char *,"name", int,"flags", vki_mode_t,"mode");
+
+   PRE_MEM_RASCIIZ( "shm_open(filename)", ARG1 );
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_shm_open)
+{
+   vg_assert(SUCCESS);
+   if (!ML_(fd_allowed)(RES, "shm_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, (Char*)ARG1);
+   }
+}
+
+
+PRE(sys_statx)
+{
+   PRINT("statx( %#lx(%s), %#lx, %#lx, %#lx )",
+      ARG1, (char *)ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "statx", char *, file_name, struct stat *, buf, 
+                 void *, fsacl, vki_size_t *, fsacl_size);
+   PRE_MEM_RASCIIZ( "statx(file_name)",  ARG1 );
+   PRE_MEM_READ(    "statx(fsacl_size)", ARG4, sizeof(vki_size_t) );
+   PRE_MEM_WRITE(   "statx(buf)",        ARG2, sizeof(struct vki_stat) );
+   PRE_MEM_WRITE(   "statx(fsacl_size)", ARG4, sizeof(vki_size_t) );
+   PRE_MEM_WRITE(   "statx(fsacl)",      ARG3, *(vki_size_t *)ARG4 );
+}
+POST(sys_statx)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
+   POST_MEM_WRITE( ARG4, sizeof(vki_size_t) );
+   POST_MEM_WRITE( ARG3, *(vki_size_t *)ARG4 );
+}
+
+
+PRE(sys_fchmod_extended)
+{
+   /* Note: this is not really correct.  Handling of
+      sys_chmod_extended is broken in the same way. */
+   PRINT("sys_fchmod_extended ( %ld, %ld, %ld, %ld, %#lx )",
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "fchmod", 
+                 unsigned int, fildes, 
+                 uid_t, uid,
+                 gid_t, gid,
+                 vki_mode_t, mode,
+                 void* /*really,user_addr_t*/, xsecurity);
+   /* relative to the xnu sources (kauth_copyinfilesec), this
+      is just way wrong. */
+   PRE_MEM_READ( "fchmod_extended(xsecurity)", ARG5, 
+                 sizeof(struct kauth_filesec) );
+}
+
+PRE(sys_chmod_extended)
+{
+   /* Note: this is not really correct.  Handling of
+      sys_fchmod_extended is broken in the same way. */
+   PRINT("sys_chmod_extended ( %#lx(%s), %ld, %ld, %ld, %#lx )",
+         ARG1, ARG1 ? (HChar*)ARG1 : "(null)", ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(long, "chmod", 
+                 unsigned int, fildes, 
+                 uid_t, uid,
+                 gid_t, gid,
+                 vki_mode_t, mode,
+                 void* /*really,user_addr_t*/, xsecurity);
+   PRE_MEM_RASCIIZ("chmod_extended(path)", ARG1);
+   /* relative to the xnu sources (kauth_copyinfilesec), this
+      is just way wrong. */
+   PRE_MEM_READ( "chmod_extended(xsecurity)", ARG5, 
+                 sizeof(struct kauth_filesec) );
+}
+
+
+PRE(sys_accessx)
+{
+    // GrP fixme difficult
+}
+
+POST(sys_accessx)
+{
+    // GrP fixme
+}
+
+PRE(sys_chflags)
+{
+   PRINT("sys_chflags ( %#lx(%s), %lu )", ARG1, (char *)ARG1, ARG2);
+   PRE_REG_READ2(int, "chflags", const char *,path, unsigned int,flags);
+   PRE_MEM_RASCIIZ("chflags(path)", ARG1);
+
+   // GrP fixme sanity-check flags value?
+}
+
+PRE(sys_fchflags)
+{
+   PRINT("sys_fchflags ( %ld, %lu )", ARG1, ARG2);
+   PRE_REG_READ2(int, "fchflags", int,fd, unsigned int,flags);
+
+   // GrP fixme sanity-check flags value?
+}
+
+POST(sys_stat64)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_stat64)
+{
+   PRINT("sys_stat64 ( %#lx(%s), %#lx )", ARG1, (char *)ARG1, ARG2);
+   PRE_REG_READ2(long, "stat", const char *,path, struct stat64 *,buf);
+   PRE_MEM_RASCIIZ("stat64(path)", ARG1);
+   PRE_MEM_WRITE( "stat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+POST(sys_lstat64)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_lstat64)
+{
+   PRINT("sys_lstat64 ( %#lx(%s), %#lx )", ARG1, (char *)ARG1, ARG2);
+   PRE_REG_READ2(long, "stat", const char *,path, struct stat64 *,buf);
+   PRE_MEM_RASCIIZ("lstat64(path)", ARG1);
+   PRE_MEM_WRITE( "lstat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+POST(sys_fstat64)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_fstat64)
+{
+   PRINT("sys_fstat64 ( %ld, %#lx )", ARG1,ARG2);
+   PRE_REG_READ2(long, "fstat", unsigned int, fd, struct stat64 *, buf);
+   PRE_MEM_WRITE( "fstat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+PRE(sys_getfsstat)
+{
+   PRINT("getfsstat(%#lx, %ld, %ld)", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "getfsstat", struct vki_statfs *, buf, 
+                 int, bufsize, int, flags);
+   if (ARG1) {
+      // ARG2 is a BYTE SIZE
+      PRE_MEM_WRITE("getfsstat", ARG1, ARG2);
+   }
+}
+
+POST(sys_getfsstat)
+{
+   if (ARG1) {
+      // RES is a STRUCT COUNT
+      POST_MEM_WRITE(ARG1, RES * sizeof(struct vki_statfs));
+   }
+}
+
+
+static void scan_attrlist(ThreadId tid, struct vki_attrlist *attrList, 
+                          void *attrBuf, SizeT attrBufSize, 
+                          void (*fn)(ThreadId, void *attrData, SizeT size)
+                          )
+{
+   typedef struct {
+      uint32_t attrBit;
+      int32_t attrSize;
+   } attrspec;
+   static const attrspec commonattr[] = {
+      // This order is important.
+      { ATTR_CMN_NAME,            -1 }, 
+      { ATTR_CMN_DEVID,           sizeof(dev_t) }, 
+      { ATTR_CMN_FSID,            sizeof(fsid_t) }, 
+      { ATTR_CMN_OBJTYPE,         sizeof(fsobj_type_t) }, 
+      { ATTR_CMN_OBJTAG,          sizeof(fsobj_tag_t) }, 
+      { ATTR_CMN_OBJID,           sizeof(fsobj_id_t) }, 
+      { ATTR_CMN_OBJPERMANENTID,  sizeof(fsobj_id_t) }, 
+      { ATTR_CMN_PAROBJID,        sizeof(fsobj_id_t) }, 
+      { ATTR_CMN_SCRIPT,          sizeof(text_encoding_t) }, 
+      { ATTR_CMN_CRTIME,          sizeof(struct timespec) }, 
+      { ATTR_CMN_MODTIME,         sizeof(struct timespec) }, 
+      { ATTR_CMN_CHGTIME,         sizeof(struct timespec) }, 
+      { ATTR_CMN_ACCTIME,         sizeof(struct timespec) }, 
+      { ATTR_CMN_BKUPTIME,        sizeof(struct timespec) }, 
+      { ATTR_CMN_FNDRINFO,        32 /*FileInfo+ExtendedFileInfo, or FolderInfo+ExtendedFolderInfo*/ }, 
+      { ATTR_CMN_OWNERID,         sizeof(uid_t) }, 
+      { ATTR_CMN_GRPID,           sizeof(gid_t) }, 
+      { ATTR_CMN_ACCESSMASK,      sizeof(uint32_t) }, 
+      { ATTR_CMN_NAMEDATTRCOUNT,  sizeof(uint32_t) }, 
+      { ATTR_CMN_NAMEDATTRLIST,   -1 }, 
+      { ATTR_CMN_FLAGS,           sizeof(uint32_t) }, 
+      { ATTR_CMN_USERACCESS,      sizeof(uint32_t) }, 
+      { ATTR_CMN_FILEID,          sizeof(uint64_t) }, 
+      { ATTR_CMN_PARENTID,        sizeof(uint64_t) }, 
+      { 0,                        0 }
+   };
+   static const attrspec volattr[] = {
+      // This order is important.
+      { ATTR_VOL_INFO,            0 }, 
+      { ATTR_VOL_FSTYPE,          sizeof(uint32_t) }, 
+      { ATTR_VOL_SIGNATURE,       sizeof(uint32_t) }, 
+      { ATTR_VOL_SIZE,            sizeof(off_t) }, 
+      { ATTR_VOL_SPACEFREE,       sizeof(off_t) }, 
+      { ATTR_VOL_SPACEAVAIL,      sizeof(off_t) }, 
+      { ATTR_VOL_MINALLOCATION,   sizeof(off_t) }, 
+      { ATTR_VOL_ALLOCATIONCLUMP, sizeof(off_t) }, 
+      { ATTR_VOL_IOBLOCKSIZE,     sizeof(uint32_t) }, 
+      { ATTR_VOL_OBJCOUNT,        sizeof(uint32_t) }, 
+      { ATTR_VOL_FILECOUNT,       sizeof(uint32_t) }, 
+      { ATTR_VOL_DIRCOUNT,        sizeof(uint32_t) }, 
+      { ATTR_VOL_MAXOBJCOUNT,     sizeof(uint32_t) }, 
+      { ATTR_VOL_MOUNTPOINT,      -1 }, 
+      { ATTR_VOL_NAME,            -1 }, 
+      { ATTR_VOL_MOUNTFLAGS,      sizeof(uint32_t) }, 
+      { ATTR_VOL_MOUNTEDDEVICE,   -1 }, 
+      { ATTR_VOL_ENCODINGSUSED,   sizeof(uint64_t) }, 
+      { ATTR_VOL_CAPABILITIES,    sizeof(vol_capabilities_attr_t) }, 
+      { ATTR_VOL_ATTRIBUTES,      sizeof(vol_attributes_attr_t) }, 
+      { 0,                        0 }
+   };
+   static const attrspec dirattr[] = {
+      // This order is important.
+      { ATTR_DIR_LINKCOUNT,       sizeof(uint32_t) }, 
+      { ATTR_DIR_ENTRYCOUNT,      sizeof(uint32_t) }, 
+      { ATTR_DIR_MOUNTSTATUS,     sizeof(uint32_t) }, 
+      { 0,                        0 }
+   };
+   static const attrspec fileattr[] = {
+      // This order is important.
+      { ATTR_FILE_LINKCOUNT,      sizeof(uint32_t) }, 
+      { ATTR_FILE_TOTALSIZE,      sizeof(off_t) }, 
+      { ATTR_FILE_ALLOCSIZE,      sizeof(off_t) }, 
+      { ATTR_FILE_IOBLOCKSIZE,    sizeof(uint32_t) }, 
+      { ATTR_FILE_CLUMPSIZE,      sizeof(uint32_t) }, 
+      { ATTR_FILE_DEVTYPE,        sizeof(uint32_t) }, 
+      { ATTR_FILE_FILETYPE,       sizeof(uint32_t) }, 
+      { ATTR_FILE_FORKCOUNT,      sizeof(uint32_t) }, 
+      { ATTR_FILE_FORKLIST,       -1 }, 
+      { ATTR_FILE_DATALENGTH,     sizeof(off_t) }, 
+      { ATTR_FILE_DATAALLOCSIZE,  sizeof(off_t) }, 
+      { ATTR_FILE_DATAEXTENTS,    sizeof(extentrecord) }, 
+      { ATTR_FILE_RSRCLENGTH,     sizeof(off_t) }, 
+      { ATTR_FILE_RSRCALLOCSIZE,  sizeof(off_t) }, 
+      { ATTR_FILE_RSRCEXTENTS,    sizeof(extentrecord) }, 
+      { 0,                        0 }
+   };
+   static const attrspec forkattr[] = {
+      // This order is important.
+      { ATTR_FORK_TOTALSIZE,      sizeof(off_t) }, 
+      { ATTR_FORK_ALLOCSIZE,      sizeof(off_t) }, 
+      { 0,                        0 }
+   };
+
+   static const attrspec *attrdefs[5] = { 
+      commonattr, volattr, dirattr, fileattr, forkattr 
+   };
+   attrgroup_t a[5];
+   uint8_t *d, *dend;
+   int g, i;
+
+   vg_assert(attrList->bitmapcount == 5);
+   VG_(memcpy)(a, &attrList->commonattr, sizeof(a));
+   d = attrBuf;
+   dend = d + attrBufSize;
+
+   for (g = 0; g < 5; g++) {
+      for (i = 0; attrdefs[g][i].attrBit; i++) {
+         uint32_t bit = attrdefs[g][i].attrBit;
+         int32_t size = attrdefs[g][i].attrSize;
+
+         if (a[g] & bit) {
+             a[g] &= ~bit;  // clear bit for error check later
+            if (size == -1) {
+               attrreference_t *ref = (attrreference_t *)d;
+               size = MIN(sizeof(attrreference_t), dend - d);
+               fn(tid, d, size);
+               if (size >= sizeof(attrreference_t)  &&  
+                   d + ref->attr_dataoffset < dend) 
+               {
+                  fn(tid, d + ref->attr_dataoffset, 
+                     MIN(ref->attr_length, dend - (d + ref->attr_dataoffset)));
+               }
+               d += size;
+            } 
+            else {
+               size = MIN(size, dend - d);
+               fn(tid, d, size);
+               d += size;
+            }
+            
+            if ((uintptr_t)d % 4) d += 4 - ((uintptr_t)d % 4);
+            if (d > dend) d = dend;
+         }
+      }
+
+      // Known bits are cleared. Die if any bits are left.
+      if (a[g] != 0) {
+         VG_(message)(Vg_UserMsg, "UNKNOWN attrlist flags %d:0x%x\n", g, a[g]);
+      }
+   }
+}
+
+static void get1attr(ThreadId tid, void *attrData, SizeT attrDataSize)
+{
+   POST_MEM_WRITE((Addr)attrData, attrDataSize);
+}
+
+static void set1attr(ThreadId tid, void *attrData, SizeT attrDataSize)
+{
+   PRE_MEM_READ("setattrlist(attrBuf value)", (Addr)attrData, attrDataSize);
+}
+
+PRE(sys_getattrlist)
+{
+   PRINT("getattrlist(%#lx(%s), %#lx, %#lx, %lu, %lu)", 
+         ARG1, (char *)ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(int, "getattrlist", 
+                 const char *,path, struct vki_attrlist *,attrList, 
+                 void *,attrBuf, vki_size_t,attrBufSize, unsigned int,options);
+   PRE_MEM_RASCIIZ("getattrlist(path)", ARG1);
+   PRE_MEM_READ("getattrlist(attrList)", ARG2, sizeof(struct vki_attrlist));
+   PRE_MEM_WRITE("getattrlist(attrBuf)", ARG3, ARG4);
+}
+
+POST(sys_getattrlist) 
+{
+   if (ARG4 > sizeof(vki_uint32_t)) {
+      // attrBuf is uint32_t bytes written followed by attr data
+      vki_uint32_t *sizep = (vki_uint32_t *)ARG3;
+      POST_MEM_WRITE(ARG3, sizeof(vki_uint32_t));
+      scan_attrlist(tid, (struct vki_attrlist *)ARG2, sizep+1, *sizep, &get1attr);
+   }
+}
+
+
+PRE(sys_setattrlist)
+{
+   PRINT("setattrlist(%#lx(%s), %#lx, %#lx, %lu, %lu)", 
+         ARG1, (char *)ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(int, "setattrlist", 
+                 const char *,path, struct vki_attrlist *,attrList, 
+                 void *,attrBuf, vki_size_t,attrBufSize, unsigned int,options);
+   PRE_MEM_RASCIIZ("setattrlist(path)", ARG1);
+   PRE_MEM_READ("setattrlist(attrList)", ARG2, sizeof(struct vki_attrlist));
+   scan_attrlist(tid, (struct vki_attrlist *)ARG2, (void*)ARG3, ARG4, &set1attr);
+}
+
+
+PRE(sys_getdirentriesattr)
+{
+   PRINT("getdirentriesattr(%ld, %#lx, %#lx, %ld, %#lx, %#lx, %#lx, %ld)", 
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8);
+   PRE_REG_READ8(int, "getdirentriesattr", 
+                 int,fd, struct vki_attrlist *,attrList, 
+                 void *,attrBuf, size_t,attrBufSize, 
+                 unsigned int *,count, unsigned int *,basep, 
+                 unsigned int *,newState, unsigned int,options);
+   PRE_MEM_READ("getdirentriesattr(attrList)", 
+                ARG2, sizeof(struct vki_attrlist));
+   PRE_MEM_WRITE("getdirentriesattr(attrBuf)", ARG3, ARG4);
+   PRE_MEM_READ("getdirentriesattr(count)", ARG5, sizeof(unsigned int));
+   PRE_MEM_WRITE("getdirentriesattr(count)", ARG5, sizeof(unsigned int));
+   PRE_MEM_WRITE("getdirentriesattr(basep)", ARG6, sizeof(unsigned int));
+   PRE_MEM_WRITE("getdirentriesattr(newState)", ARG7, sizeof(unsigned int));
+}
+
+POST(sys_getdirentriesattr) 
+{
+   char *p, *end;
+   unsigned int count;
+   unsigned int i;
+
+   POST_MEM_WRITE(ARG5, sizeof(unsigned int));
+   POST_MEM_WRITE(ARG6, sizeof(unsigned int));
+   POST_MEM_WRITE(ARG7, sizeof(unsigned int));
+
+   // return buffer is concatenation of variable-size structs
+   count = *(unsigned int *)ARG5;
+   p = (char *)ARG3;
+   end = (char *)ARG3 + ARG4;
+   for (i = 0; i < count; i++) {
+      vg_assert(p < end);  // failure is kernel bug or Valgrind bug
+      p += *(unsigned int *)p;
+   }
+
+   POST_MEM_WRITE(ARG3, p - (char *)ARG3);
+
+   PRINT("got %d records, %d/%lu bytes\n", count, p-(char *)ARG3, ARG4);
+}
+
+
+PRE(sys_fsctl)
+{
+   PRINT("fsctl ( %#lx(%s), %ld, %#lx, %ld )",
+      ARG1, (char *)ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4( long, "fsctl", 
+                  char *,"path", unsigned int,"request", 
+                  void *,"data", unsigned int,"options");
+   
+   PRE_MEM_RASCIIZ( "fsctl(path)", ARG1 );
+
+   switch (ARG2) {
+   case VKI_afpfsByteRangeLock2FSCTL: {
+      struct vki_ByteRangeLockPB2 *pb = (struct vki_ByteRangeLockPB2 *)ARG3;
+      PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->offset)", 
+                     pb->offset);
+      PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->length)", 
+                     pb->length);
+      PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->unLockFlag)", 
+                     pb->unLockFlag);
+      PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->startEndFlag)", 
+                     pb->startEndFlag);
+      PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->fd)", 
+                     pb->fd);
+
+      PRE_FIELD_WRITE("fsctl(afpfsByteRangeLock2, pb->retRangeStart)", 
+                      pb->retRangeStart);
+
+      // GrP fixme check fd
+      break;
+   }
+   case VKI_FSIOC_SYNC_VOLUME:
+       PRE_MEM_READ( "fsctl(FSIOC_SYNC_VOLUME)", ARG3, sizeof(int) );
+       break;
+
+   default:
+      // fsctl requests use ioctl encoding
+      ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
+      break;
+   }
+}
+
+POST(sys_fsctl)
+{
+   switch (ARG2) {
+   case VKI_afpfsByteRangeLock2FSCTL: {
+      struct vki_ByteRangeLockPB2 *pb = (struct vki_ByteRangeLockPB2 *)ARG3;
+      POST_FIELD_WRITE(pb->retRangeStart);
+      break;
+   }
+   case VKI_FSIOC_SYNC_VOLUME:
+       break;
+
+   default:
+      // fsctl requests use ioctl encoding
+      ML_(POST_unknown_ioctl)(tid, RES, ARG2, ARG3);
+      break;
+   }
+}
+
+PRE(sys_initgroups)
+{
+    PRINT("sys_initgroups(%s, %#lx, %lu)", (char *)ARG1, ARG2, ARG3);
+    PRE_REG_READ3(long, "initgroups",
+        int, setlen, vki_gid_t *, gidset, vki_uid_t, gmuid);
+    PRE_MEM_READ("gidset", ARG2, ARG1 * sizeof(vki_gid_t));
+}
+
+
+//--------- posix_spawn ---------//
+/* Largely copied from PRE(sys_execve) in syswrap-generic.c, and from
+   the simpler AIX equivalent (syswrap-aix5.c). */
+// Pre_read a char** argument.
+static void pre_argv_envp(Addr a, ThreadId tid, Char* s1, Char* s2)
+{
+   while (True) {
+      Addr a_deref;
+      Addr* a_p = (Addr*)a;
+      PRE_MEM_READ( s1, (Addr)a_p, sizeof(Addr) );
+      a_deref = *a_p;
+      if (0 == a_deref)
+         break;
+      PRE_MEM_RASCIIZ( s2, a_deref );
+      a += sizeof(char*);
+   }
+}
+static SysRes simple_pre_exec_check(const HChar* exe_name)
+{
+   Int fd, ret;
+   SysRes res;
+   Bool setuid_allowed;
+
+   // Check it's readable
+   res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
+   if (sr_isError(res)) {
+      return res;
+   }
+   fd = sr_Res(res);
+   VG_(close)(fd);
+
+   // Check we have execute permissions.  We allow setuid executables
+   // to be run only in the case when we are not simulating them, that
+   // is, they to be run natively.
+   setuid_allowed = VG_(clo_trace_children)  ? False  : True;
+   ret = VG_(check_executable)(NULL/*&is_setuid*/,
+                               (HChar*)exe_name, setuid_allowed);
+   if (0 != ret) {
+      return VG_(mk_SysRes_Error)(ret);
+   }
+   return VG_(mk_SysRes_Success)(0);
+}
+PRE(sys_posix_spawn)
+{
+   Char*        path = NULL;       /* path to executable */
+   Char**       envp = NULL;
+   Char**       argv = NULL;
+   Char**       arg2copy;
+   Char*        launcher_basename = NULL;
+   Int          i, j, tot_args;
+   SysRes       res;
+
+   /* args: pid_t* pid
+            char*  path
+            posix_spawn_file_actions_t* file_actions
+            char** argv
+            char** envp
+   */
+   PRINT("sys_posix_spawn( %#lx, %#lx(%s), %#lx, %#lx, %#lx )",
+         ARG1, ARG2, ARG2 ? (HChar*)ARG2 : "(null)", ARG3, ARG4, ARG5 );
+
+   /* Standard pre-syscall checks */
+
+   PRE_REG_READ5(int, "posix_spawn", vki_pid_t*, pid, char*, path,
+                 void*, file_actions, char**, argv, char**, envp );
+   PRE_MEM_WRITE("posix_spawn(pid)", ARG1, sizeof(vki_pid_t) );
+   PRE_MEM_RASCIIZ("posix_spawn(path)", ARG2);
+   // DDD: check file_actions
+   if (ARG4 != 0)
+      pre_argv_envp( ARG4, tid, "posix_spawn(argv)",
+                                "posix_spawn(argv[i])" );
+   if (ARG5 != 0)
+      pre_argv_envp( ARG5, tid, "posix_spawn(envp)",
+                                "posix_spawn(envp[i])" );
+
+   if (0)
+   VG_(printf)("sys_posix_spawn( %#lx, %#lx(%s), %#lx, %#lx, %#lx )\n",
+         ARG1, ARG2, ARG2 ? (HChar*)ARG2 : "(null)", ARG3, ARG4, ARG5 );
+
+   /* Now follows a bunch of logic copied from PRE(sys_execve) in
+      syswrap-generic.c. */
+
+   /* Check that the name at least begins in client-accessible storage. */
+   if (!VG_(am_is_valid_for_client)( ARG2, 1, VKI_PROT_READ )) {
+      SET_STATUS_Failure( VKI_EFAULT );
+      return;
+   }
+
+   // 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.
+   res = simple_pre_exec_check((const HChar*)ARG2);
+   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 (VG_(clo_trace_children)
+       && (VG_(name_of_launcher) == NULL
+           || VG_(name_of_launcher)[0] != '/')) {
+      SET_STATUS_Failure( VKI_ECHILD ); /* "No child processes" */
+      return;
+   }
+
+   /* Ok.  So let's give it a try. */
+   VG_(debugLog)(1, "syswrap", "Posix_spawn of %s\n", (Char*)ARG2);
+
+   // Set up the child's exe path.
+   //
+   if (VG_(clo_trace_children)) {
+
+      // We want to exec the launcher.  Get its pre-remembered path.
+      path = VG_(name_of_launcher);
+      // VG_(name_of_launcher) should have been acquired by m_main at
+      // startup.  The following two assertions should be assured by
+      // the "If we're tracking the child .." test just above here.
+      vg_assert(path);
+      vg_assert(path[0] == '/');
+      launcher_basename = path;
+
+   } else {
+      path = (Char*)ARG2;
+   }
+
+   // 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 (this was bug #101881).
+   //
+   // Then, if tracing the child, set VALGRIND_LIB for it.
+   //
+   if (ARG5 == 0) {
+      envp = NULL;
+   } else {
+      envp = VG_(env_clone)( (Char**)ARG5 );
+      vg_assert(envp);
+      VG_(env_remove_valgrind_env_stuff)( envp );
+   }
+
+   if (VG_(clo_trace_children)) {
+      // Set VALGRIND_LIB in ARG5 (the environment)
+      VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
+   }
+
+   // Set up the child's args.  If not tracing it, they are
+   // simply ARG4.  Otherwise, they are
+   //
+   // [launcher_basename] ++ VG_(args_for_valgrind) ++ [ARG2] ++ ARG4[1..]
+   //
+   // except that the first VG_(args_for_valgrind_noexecpass) args
+   // are omitted.
+   //
+   if (!VG_(clo_trace_children)) {
+      argv = (Char**)ARG4;
+   } else {
+      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]
+      arg2copy = (Char**)ARG4;
+      if (arg2copy && arg2copy[0]) {
+         for (i = 1; arg2copy[i]; i++)
+            tot_args++;
+      }
+      // allocate
+      argv = VG_(malloc)( "di.syswrap.pre_sys_execve.1",
+                          (tot_args+1) * sizeof(HChar*) );
+      vg_assert(argv);
+      // copy
+      j = 0;
+      argv[j++] = 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++] = (Char*)ARG2;
+      if (arg2copy && arg2copy[0])
+         for (i = 1; arg2copy[i]; i++)
+            argv[j++] = arg2copy[i];
+      argv[j++] = NULL;
+      // check
+      vg_assert(j == tot_args+1);
+   }
+
+   /* DDD: sort out the signal state.  What signal
+      state does the child inherit from the parent?  */
+
+   if (0) {
+      Char **cpp;
+      VG_(printf)("posix_spawn: %s\n", path);
+      for (cpp = argv; cpp && *cpp; cpp++)
+         VG_(printf)("argv: %s\n", *cpp);
+      if (1)
+         for (cpp = envp; cpp && *cpp; cpp++)
+            VG_(printf)("env: %s\n", *cpp);
+   }
+
+   /* Let the call go through as usual.  However, we have to poke
+      the altered arguments back into the argument slots. */
+   ARG2 = (UWord)path;
+   ARG4 = (UWord)argv;
+   ARG5 = (UWord)envp;
+
+   /* not to mention .. */
+   *flags |= SfMayBlock;
+}
+POST(sys_posix_spawn)
+{
+   vg_assert(SUCCESS);
+   //POST_MEM_WRITE( ARG1, sizeof(vki_pid_t) );
+}
+
+
+PRE(sys_socket)
+{
+   PRINT("sys_socket ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "socket", int, domain, int, type, int, protocol);
+}
+
+POST(sys_socket)
+{
+   SysRes r;
+   vg_assert(SUCCESS);
+   r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES));
+   SET_STATUS_from_SysRes(r);
+}
+
+
+PRE(sys_setsockopt)
+{
+   PRINT("sys_setsockopt ( %ld, %ld, %ld, %#lx, %ld )",
+      ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(long, "setsockopt",
+                 int, s, int, level, int, optname,
+                 const void *, optval, vki_socklen_t, optlen);
+   ML_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
+}
+
+
+PRE(sys_getsockopt)
+{
+   Addr optval_p = ARG4;
+   Addr optlen_p = ARG5;
+   PRINT("sys_getsockopt ( %ld, %ld, %ld, %#lx, %#lx )",
+      ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(long, "getsockopt",
+                 int, s, int, level, int, optname,
+                 void *, optval, vki_socklen_t *, optlen);
+   /* int getsockopt(int socket, int level, int option_name, 
+                     void *restrict option_value,
+                     socklen_t *restrict option_len); */
+   /* vg_assert(sizeof(socklen_t) == sizeof(UInt)); */
+   if (optval_p != (Addr)NULL) {
+      ML_(buf_and_len_pre_check) ( tid, optval_p, optlen_p,
+                                   "socketcall.getsockopt(optval)",
+                                   "socketcall.getsockopt(optlen)" );
+   }
+   // DDD: #warning GrP fixme darwin-specific sockopts
+}
+
+POST(sys_getsockopt)
+{
+   Addr optval_p = ARG4;
+   Addr optlen_p = ARG5;
+   vg_assert(SUCCESS);
+   if (optval_p != (Addr)NULL) {
+      ML_(buf_and_len_post_check) ( tid, VG_(mk_SysRes_Success)(RES),
+                                    optval_p, optlen_p,
+                                    "socketcall.getsockopt(optlen_out)" );
+   // DDD: #warning GrP fixme darwin-specific sockopts
+   }
+}
+
+
+PRE(sys_connect)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_connect ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "connect",
+                 int, sockfd, struct sockaddr *, serv_addr, int, addrlen);
+   ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_accept)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_accept ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "accept",
+                 int, s, struct sockaddr *, addr, int, *addrlen);
+   ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_accept)
+{
+   SysRes r;
+   vg_assert(SUCCESS);
+   r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
+                                         ARG1,ARG2,ARG3);
+   SET_STATUS_from_SysRes(r);
+}
+
+
+PRE(sys_sendto)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sendto ( %ld, %s, %ld, %lu, %#lx, %ld )",
+      ARG1,(char *)ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(long, "sendto",
+                 int, s, const void *, msg, int, len, 
+                 unsigned int, flags, 
+                 const struct sockaddr *, to, int, tolen);
+   ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+PRE(sys_sendfile)
+{
+#if VG_WORDSIZE == 4
+   PRINT("sys_sendfile(%ld, %ld, %llu, %#lx, %#lx, %ld)",
+         ARG1, ARG2, LOHI64(ARG3, ARG4), ARG5, ARG6, ARG7);
+
+   PRE_REG_READ7(long, "sendfile",
+      int, fromfd, int, tofd,
+      vki_uint32_t, offset_low32, vki_uint32_t, offset_high32,
+      vki_uint64_t *, nwritten, struct sf_hdtr *, sf_header, int, flags);
+   PRE_MEM_WRITE("sendfile(nwritten)", ARG5, sizeof(vki_uint64_t));
+   if (ARG6) PRE_MEM_WRITE("sendfile(sf_header)", ARG6, sizeof(struct sf_hdtr));
+#else
+   PRINT("sys_sendfile(%ld, %ld, %ld, %#lx, %#lx, %ld)",
+      ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+
+   PRE_REG_READ6(long, "sendfile",
+      int, fromfd, int, tofd,
+      vki_uint64_t, offset, 
+      vki_uint64_t *, nwritten, struct sf_hdtr *, sf_header, int, flags);
+   PRE_MEM_WRITE("sendfile(nwritten)", ARG4, sizeof(vki_uint64_t));
+   if (ARG5) PRE_MEM_WRITE("sendfile(sf_header)", ARG5, sizeof(struct sf_hdtr));
+#endif
+
+   *flags |= SfMayBlock;
+}
+
+POST(sys_sendfile)
+{
+#if VG_WORDSIZE == 4
+   POST_MEM_WRITE(ARG5, sizeof(vki_uint64_t));
+   if (ARG6) POST_MEM_WRITE(ARG6, sizeof(struct sf_hdtr));
+#else
+   POST_MEM_WRITE(ARG4, sizeof(vki_uint64_t));
+   if (ARG5) POST_MEM_WRITE(ARG5, sizeof(struct sf_hdtr));
+#endif
+}
+
+PRE(sys_recvfrom)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_recvfrom ( %ld, %#lx, %ld, %lu, %#lx, %#lx )",
+      ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(long, "recvfrom",
+                 int, s, void *, buf, int, len, unsigned int, flags,
+                 struct sockaddr *, from, int *, fromlen);
+   ML_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+POST(sys_recvfrom)
+{
+   vg_assert(SUCCESS);
+   ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES),
+                                       ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+
+PRE(sys_sendmsg)
+{
+   *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, ARG1,ARG2);
+}
+
+
+PRE(sys_recvmsg)
+{
+   *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, ARG1,ARG2);
+}
+
+POST(sys_recvmsg)
+{
+   ML_(generic_POST_sys_recvmsg)(tid, ARG1,ARG2);
+}
+
+
+PRE(sys_shutdown)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_shutdown ( %ld, %ld )",ARG1,ARG2);
+   PRE_REG_READ2(int, "shutdown", int, s, int, how);
+}
+
+
+PRE(sys_bind)
+{
+   PRINT("sys_bind ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "bind",
+                 int, sockfd, struct sockaddr *, my_addr, int, addrlen);
+   ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_listen)
+{
+   PRINT("sys_listen ( %ld, %ld )",ARG1,ARG2);
+   PRE_REG_READ2(long, "listen", int, s, int, backlog);
+}
+
+
+PRE(sys_getsockname)
+{
+   PRINT("sys_getsockname ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "getsockname",
+                 int, s, struct sockaddr *, name, int *, namelen);
+   ML_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_getsockname)
+{
+   vg_assert(SUCCESS);
+   ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES),
+                                          ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_getpeername)
+{
+   PRINT("sys_getpeername ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "getpeername",
+                 int, s, struct sockaddr *, name, int *, namelen);
+   ML_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_getpeername)
+{
+   vg_assert(SUCCESS);
+   ML_(generic_POST_sys_getpeername)(tid, VG_(mk_SysRes_Success)(RES),
+                                          ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_socketpair)
+{
+   PRINT("sys_socketpair ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(long, "socketpair",
+                 int, d, int, type, int, protocol, int *, sv);
+   ML_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+
+POST(sys_socketpair)
+{
+   vg_assert(SUCCESS);
+   ML_(generic_POST_sys_socketpair)(tid, VG_(mk_SysRes_Success)(RES),
+                                         ARG1,ARG2,ARG3,ARG4);
+}
+
+
+PRE(sys_gethostuuid)
+{
+   PRINT("sys_gethostuuid ( %#lx, %#lx )", ARG1, ARG2);
+   PRE_REG_READ2(int,"gethostuuid", 
+                 char *,"uuid_buf", 
+                 const struct vki_timespec *,"timeout");
+
+   PRE_MEM_WRITE("uuid_buf", ARG1, 16);
+   PRE_MEM_READ("timeout", ARG2, sizeof(struct vki_timespec));
+
+   *flags |= SfMayBlock;
+}
+
+
+POST(sys_gethostuuid)
+{
+   POST_MEM_WRITE(ARG1, 16);
+}
+
+/* Darwin pipe() returns the two descriptors in two registers. */
+PRE(sys_pipe)
+{
+   PRINT("sys_pipe ( )");
+   PRE_REG_READ0(int, "pipe");
+}
+
+POST(sys_pipe)
+{
+   Int p0, p1;
+   vg_assert(SUCCESS);
+   p0 = RES;
+   p1 = RESHI;
+
+   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_getlogin)
+{
+   PRINT("getlogin ( %#lx, %ld )", ARG1, ARG2);
+   PRE_REG_READ2(long, "getlogin", 
+                 char *,"namebuf", unsigned int,"namelen");
+
+   PRE_MEM_WRITE("getlogin(namebuf)", ARG1, ARG2);
+}
+
+POST(sys_getlogin)
+{
+   POST_MEM_WRITE(ARG1, ARG2);
+}
+
+
+PRE(sys_ptrace)
+{
+   PRINT("ptrace ( %ld, %ld, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(long, "ptrace", 
+                 int,"request", vki_pid_t,"pid", 
+                 vki_caddr_t,"addr", int,"data");
+    
+   // Note: some code uses ptrace(random, 0, 0, 0) as a profiling mechanism. 
+
+   // GrP fixme anything needed?
+}
+
+
+PRE(sys_issetugid)
+{
+   PRINT("issetugid ( )");
+   PRE_REG_READ0(long, "issetugid");
+}
+
+
+PRE(sys_getdtablesize)
+{
+   PRINT("getdtablesize ( )");
+   PRE_REG_READ0(long, "getdtablesize");
+}
+
+POST(sys_getdtablesize)
+{
+   // Subtract Valgrind's fd range from client's dtable
+   if (RES > VG_(fd_hard_limit)) SET_STATUS_Success(VG_(fd_hard_limit));
+}
+
+PRE(sys_lseek)
+{
+   PRINT("lseek ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+   PRE_REG_READ4(vki_off_t, "lseek",
+                 unsigned int,fd, int,offset_hi, int,offset_lo, 
+                 unsigned int,whence);
+}
+
+
+PRE(sys_pathconf)
+{
+   PRINT("pathconf(%#lx(%s), %ld)", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(long,"pathconf", const char *,"path", int,"name");
+   PRE_MEM_RASCIIZ("pathconf(path)", ARG1);
+}
+
+
+PRE(sys_fpathconf)
+{
+   PRINT("fpathconf(%ld, %ld)", ARG1,ARG2);
+   PRE_REG_READ2(long,"fpathconf", int,"fd", int,"name");
+
+   if (!ML_(fd_allowed)(ARG1, "fpathconf", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+}
+
+
+PRE(sys_getdirentries)
+{
+   PRINT("getdirentries(%ld, %#lx, %ld, %#lx)", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "getdirentries", 
+                 int, fd, char *, buf, int, nbytes, long *, basep);
+   PRE_MEM_WRITE("getdirentries(basep)", ARG4, sizeof(long));
+   PRE_MEM_WRITE("getdirentries(buf)", ARG2, ARG3);
+}
+
+POST(sys_getdirentries) 
+{
+   POST_MEM_WRITE(ARG4, sizeof(long));
+   // GrP fixme be specific about d_name?
+   POST_MEM_WRITE(ARG2, RES);
+}
+
+
+PRE(sys_getdirentries64)
+{
+   PRINT("getdirentries64(%ld, %#lx, %lu, %#lx)", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(vki_ssize_t, "getdirentries", 
+                 int,fd, char *,buf, vki_size_t,nbytes, vki_off_t *,basep);
+   PRE_MEM_WRITE("getdirentries(position)", ARG4, sizeof(vki_off_t));
+   PRE_MEM_WRITE("getdirentries(buf)", ARG2, ARG3);
+}
+
+POST(sys_getdirentries64) 
+{
+   POST_MEM_WRITE(ARG4, sizeof(vki_off_t));
+   // GrP fixme be specific about d_name? (fixme copied from 32 bit version)
+   POST_MEM_WRITE(ARG2, RES);
+}
+
+
+PRE(sys_statfs64)
+{
+   PRINT("sys_statfs64 ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(long, "statfs64", const char *, path, struct statfs64 *, buf);
+   PRE_MEM_RASCIIZ( "statfs64(path)", ARG1 );
+   PRE_MEM_WRITE( "statfs64(buf)", ARG2, sizeof(struct vki_statfs64) );
+}
+
+POST(sys_statfs64)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs64) );
+}
+
+
+PRE(sys_fstatfs64)
+{
+   PRINT("sys_fstatfs64 ( %ld, %#lx )",ARG1,ARG2);
+   PRE_REG_READ2(long, "fstatfs64",
+                 unsigned int, fd, struct statfs *, buf);
+   PRE_MEM_WRITE( "fstatfs64(buf)", ARG2, sizeof(struct vki_statfs64) );
+}
+
+POST(sys_fstatfs64)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs64) );
+}
+
+PRE(sys_csops)
+{
+   PRINT("sys_csops ( %ld, %#lx, %#lx, %lu )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "csops",
+                 vki_pid_t, pid, uint32_t, ops,
+                 void *, useraddr, vki_size_t, usersize);
+
+   PRE_MEM_WRITE( "csops(addr)", ARG3, ARG4 );
+
+   // If the pid is ours, don't mark the program as KILL or HARD
+   // Maybe we should keep track of this for later calls to STATUS
+   if (!ARG1 || VG_(getpid)() == ARG1) {
+      switch (ARG2) {
+      case VKI_CS_OPS_MARKINVALID:
+      case VKI_CS_OPS_MARKHARD:
+      case VKI_CS_OPS_MARKKILL:
+         SET_STATUS_Success(0);
+      }
+   }
+}
+
+POST(sys_csops)
+{
+   POST_MEM_WRITE( ARG3, ARG4 );
+}
+
+PRE(sys_auditon)
+{
+   PRINT("sys_auditon ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int,"auditon", 
+                 int,"cmd", void*,"data", unsigned int,"length");
+
+   switch (ARG1) {
+
+   case VKI_A_SETPOLICY: 
+   case VKI_A_SETKMASK:
+   case VKI_A_SETQCTRL:
+   case VKI_A_SETCOND:
+   case VKI_A_SETCLASS:
+   case VKI_A_SETPMASK:
+   case VKI_A_SETFSIZE:
+      // kernel reads data..data+length
+      PRE_MEM_READ("auditon(data)", ARG2, ARG3);
+      break;
+
+   case VKI_A_GETKMASK:
+   case VKI_A_GETPOLICY:
+   case VKI_A_GETQCTRL:
+   case VKI_A_GETFSIZE:
+   case VKI_A_GETCOND:
+      // kernel writes data..data+length
+      // GrP fixme be precise about what gets written
+      PRE_MEM_WRITE("auditon(data)", ARG2, ARG3);
+      break;
+
+
+   case VKI_A_GETCLASS:
+   case VKI_A_GETPINFO:
+   case VKI_A_GETPINFO_ADDR:
+      // kernel reads and writes data..data+length
+      // GrP fixme be precise about what gets read and written
+      PRE_MEM_READ("auditon(data)", ARG2, ARG3);
+      PRE_MEM_WRITE("auditon(data)", ARG2, ARG3);
+      break;
+
+   case VKI_A_SETKAUDIT:
+   case VKI_A_SETSTAT:
+   case VKI_A_SETUMASK:
+   case VKI_A_SETSMASK:
+   case VKI_A_GETKAUDIT:
+   case VKI_A_GETCWD:
+   case VKI_A_GETCAR:
+   case VKI_A_GETSTAT:
+      // unimplemented on darwin
+      break;
+
+   default:
+      VG_(message)(Vg_UserMsg, "UNKNOWN auditon cmd %ld", ARG1);
+      break;
+   }
+}
+
+POST(sys_auditon)
+{
+   switch (ARG1) {
+
+   case VKI_A_SETPOLICY: 
+   case VKI_A_SETKMASK:
+   case VKI_A_SETQCTRL:
+   case VKI_A_SETCOND:
+   case VKI_A_SETCLASS:
+   case VKI_A_SETPMASK:
+   case VKI_A_SETFSIZE:
+      // kernel reads data..data+length
+      break;
+
+   case VKI_A_GETKMASK:
+   case VKI_A_GETPOLICY:
+   case VKI_A_GETQCTRL:
+   case VKI_A_GETFSIZE:
+   case VKI_A_GETCOND:
+      // kernel writes data..data+length
+      // GrP fixme be precise about what gets written
+      POST_MEM_WRITE(ARG2, ARG3);
+      break;
+
+
+   case VKI_A_GETCLASS:
+   case VKI_A_GETPINFO:
+   case VKI_A_GETPINFO_ADDR:
+      // kernel reads and writes data..data+length
+      // GrP fixme be precise about what gets read and written
+      POST_MEM_WRITE(ARG2, ARG3);
+      break;
+
+   case VKI_A_SETKAUDIT:
+   case VKI_A_SETSTAT:
+   case VKI_A_SETUMASK:
+   case VKI_A_SETSMASK:
+   case VKI_A_GETKAUDIT:
+   case VKI_A_GETCWD:
+   case VKI_A_GETCAR:
+   case VKI_A_GETSTAT:
+      // unimplemented on darwin
+      break;
+
+   default:
+      break;
+   }    
+}
+
+
+PRE(sys_mmap)
+{
+   // SysRes r;
+
+#if VG_WORDSIZE == 4
+   PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, %lld )",
+         ARG1, ARG2, ARG3, ARG4, ARG5, LOHI64(ARG6, ARG7) );
+   PRE_REG_READ7(Addr, "mmap",
+                 Addr,start, vki_size_t,length, int,prot, int,flags, int,fd, 
+                 unsigned long,offset_hi, unsigned long,offset_lo);
+   // GrP fixme V mmap and kernel mach_msg collided once - don't use 
+   // V's mechanism for now
+   // r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, 
+   // (Off64T)LOHI64(ARG6, ARG7) );
+#else
+   PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, %ld )",
+         ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+   PRE_REG_READ6(long, "mmap",
+                 Addr,start, vki_size_t,length, int,prot, int,flags, int,fd, 
+                 Off64T,offset);
+   // r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+
+#endif
+
+   // SET_STATUS_from_SysRes(r);
+}
+
+POST(sys_mmap)
+{
+   if (RES != -1) {
+      ML_(notify_core_and_tool_of_mmap)(RES, ARG2, ARG3, ARG4, ARG5, ARG6);
+      // Try to load symbols from the region
+      VG_(di_notify_mmap)( (Addr)RES, False/*allow_SkFileV*/ );
+   }
+}
+
+
+PRE(sys_sysctl)
+{
+   PRINT( "sysctl ( %#lx, %ld, %#lx, %#lx, %#lx, %ld )", 
+          ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+
+   PRE_REG_READ6(int, "sysctl", int*, name, unsigned int, namelen, 
+                 void*, oldp, vki_size_t *, oldlenp, 
+                 void*, newp, vki_size_t *, newlenp);
+
+   PRE_MEM_READ("sysctl(name)", ARG1, ARG2);  // reads name[0..namelen-1]
+   if (ARG4) {
+      // writes *ARG4
+      PRE_MEM_WRITE("sysctl(oldlenp)", ARG4, sizeof(size_t));
+      if (ARG3) {
+         // also reads *ARG4, and writes as much as ARG3[0..ARG4-1]
+         PRE_MEM_READ("sysctl(oldlenp)", ARG4, sizeof(size_t));
+         PRE_MEM_WRITE("sysctl(oldp)", ARG3, *(size_t *)ARG4);
+      }
+   }
+   if (ARG5) {
+      PRE_MEM_READ("sysctl(newp)", ARG5, ARG6);
+   }
+
+   if (VG_(clo_trace_syscalls)) {
+      unsigned int i;
+      int *name = (int *)ARG1;
+      VG_(printf)(" mib: [ ");
+      for (i = 0; i < ARG2; i++) {
+         VG_(printf)("%d ", name[i]);
+      }
+      VG_(printf)("]");
+   }
+
+   // GrP fixme intercept KERN_PROCARGS and KERN_PROC_PID for our pid
+   // (executable path and arguments and environment
+
+   {
+      // Intercept sysctl(kern.usrstack). The kernel's reply would be
+      // Valgrind's stack, not the client's stack.
+      // GrP fixme kern_usrstack64
+      if (ARG1  &&  ARG2 == 2  &&  
+          ((int *)ARG1)[0] == VKI_CTL_KERN  &&  
+#if VG_WORDSIZE == 4
+          ((int *)ARG1)[1] == VKI_KERN_USRSTACK32
+#else
+          ((int *)ARG1)[1] == VKI_KERN_USRSTACK64
+#endif
+          )
+      {
+         if (ARG5/*newp*/  ||  ARG6/*newlen*/) {
+            SET_STATUS_Failure(VKI_EPERM); // USRSTACK is read-only
+         } else {
+            Addr *oldp = (Addr *)ARG3;
+            size_t *oldlenp = (size_t *)ARG4;
+            if (oldlenp) {
+               Addr stack_end = VG_(clstk_end)+1;
+               size_t oldlen = *oldlenp;
+               // always return actual size
+               *oldlenp = sizeof(Addr);
+               if (oldp  &&  oldlen >= sizeof(Addr)) {
+                  // oldp is big enough
+                  // copy value and return 0
+                  *oldp = stack_end;
+                  SET_STATUS_Success(0);
+               } else {
+                  // oldp isn't big enough
+                  // copy as much as possible and return ENOMEM
+                  if (oldp) VG_(memcpy)(oldp, &stack_end, oldlen);
+                  SET_STATUS_Failure(VKI_ENOMEM);
+               }
+            }
+         }
+      }
+   }
+
+   if (!SUCCESS  &&  !FAILURE) {
+      // Don't set SfPostOnFail if we've already handled it locally.
+      *flags |= SfPostOnFail;
+   }
+}
+
+POST(sys_sysctl)
+{
+   if (SUCCESS  ||  ERR == VKI_ENOMEM) {
+      // sysctl can write truncated data and return VKI_ENOMEM
+      if (ARG4) {
+         POST_MEM_WRITE(ARG4, sizeof(size_t));
+      }
+      if (ARG3  &&  ARG4) {
+         POST_MEM_WRITE(ARG3, *(size_t *)ARG4);
+      }
+   }
+}
+
+
+PRE(sys_sigpending)
+{
+   PRINT( "sys_sigpending ( %#lx )", ARG1 );
+   PRE_REG_READ1(long, "sigpending", vki_sigset_t *, set);
+   PRE_MEM_WRITE( "sigpending(set)", ARG1, sizeof(vki_sigset_t));
+}
+
+POST(sys_sigpending)
+{
+   POST_MEM_WRITE( ARG1, sizeof(vki_sigset_t) ) ;
+}
+
+
+PRE(sys_sigprocmask)
+{
+   UWord arg1;
+   PRINT("sigprocmask ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "sigprocmask",
+                 int, how, vki_sigset_t *, set, vki_sigset_t *, oldset);
+   if (ARG2 != 0)
+      PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
+   if (ARG3 != 0)
+      PRE_MEM_WRITE( "sigprocmask(oldset)", ARG3, sizeof(vki_sigset_t));
+
+   /* Massage ARG1 ('how').  If ARG2 (the new mask) is NULL then the
+      value of 'how' is irrelevant, and it appears that Darwin's libc
+      passes zero, which is not equal to any of
+      SIG_{BLOCK,UNBLOCK,SETMASK}.  This causes
+      VG_(do_sys_sigprocmask) to complain, since it checks the 'how'
+      value independently of the other args.  Solution: in this case,
+      simply pass a valid (but irrelevant) value for 'how'. */
+   /* Also, in this case the new set is passed to the kernel by
+      reference, not value, as in some other sigmask related Darwin
+      syscalls. */
+   arg1 = ARG1;
+   if (ARG2 == 0  /* the new-set is NULL */
+       && ARG1 != VKI_SIG_BLOCK
+       && ARG1 != VKI_SIG_UNBLOCK && ARG1 != VKI_SIG_SETMASK) {
+      arg1 = VKI_SIG_SETMASK;
+   }
+   SET_STATUS_from_SysRes(
+      VG_(do_sys_sigprocmask) ( tid, arg1, (vki_sigset_t*)ARG2,
+                                           (vki_sigset_t*)ARG3 )
+   );
+
+   if (SUCCESS)
+      *flags |= SfPollAfter;
+}
+
+POST(sys_sigprocmask)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0 && ARG3 != 0)
+      POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t));
+}
+
+
+PRE(sys_sigsuspend)
+{
+   /* Just hand this off to the kernel.  Is that really correct?  And
+      shouldn't we at least set SfPollAfter?  These questions apply to
+      all the Linux versions too. */
+   /* I think the first arg is the 32-bit signal mask (by value), and
+      the other two args are ignored. */
+   *flags |= SfMayBlock;
+   PRINT("sys_sigsuspend ( mask=0x%08lx )", ARG1 );
+   PRE_REG_READ1(int, "sigsuspend", int, sigmask);
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: formatted messages
+   ------------------------------------------------------------------ */
+
+static size_t desc_size(mach_msg_descriptor_t *desc)
+{
+   switch (desc->type.type) {
+   case MACH_MSG_PORT_DESCRIPTOR:          return sizeof(desc->port);
+   case MACH_MSG_OOL_DESCRIPTOR:           return sizeof(desc->out_of_line);
+   case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:  return sizeof(desc->out_of_line);
+   case MACH_MSG_OOL_PORTS_DESCRIPTOR:     return sizeof(desc->ool_ports);
+   default: 
+      VG_(printf)("UNKNOWN mach message descriptor %d\n", desc->type.type);
+      return sizeof(desc->type); // guess
+   }
+}
+
+
+static void assign_port_names(mach_msg_ool_ports_descriptor_t *desc, 
+                              const char *name)
+{
+   mach_msg_size_t i;
+   mach_port_t *ports = (mach_port_t *)desc->address;
+   for (i = 0; i < desc->count; i++) {
+      assign_port_name(ports[i], name);
+   }
+}
+
+
+static void import_complex_message(ThreadId tid, mach_msg_header_t *mh)
+{
+   mach_msg_body_t *body;
+   mach_msg_size_t count, i;
+   uint8_t *p;
+   mach_msg_descriptor_t *desc;
+   
+   vg_assert(mh->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+   
+   body = (mach_msg_body_t *)(mh+1);
+   count = body->msgh_descriptor_count;
+   p = (uint8_t *)(body+1);
+   
+   for (i = 0; i < count; i++) {
+      desc = (mach_msg_descriptor_t *)p;
+      p += desc_size(desc);
+      
+      switch (desc->type.type) {
+      case MACH_MSG_PORT_DESCRIPTOR:
+         // single port
+         record_unnamed_port(tid, desc->port.name, -1);
+         record_port_insert_rights(desc->port.name, desc->port.disposition);
+         PRINT("got port %s; ", name_for_port(desc->port.name));
+         break;
+
+      case MACH_MSG_OOL_DESCRIPTOR:
+      case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
+         // out-of-line memory - map it
+         // GrP fixme how is VOLATILE different? do we care?
+         // GrP fixme do other flags tell us anything? assume shared for now
+         // GrP fixme more SF_ flags marking mach_msg memory might be nice
+         // GrP fixme protection
+         if (desc->out_of_line.size > 0) {
+            Addr start = VG_PGROUNDDN((Addr)desc->out_of_line.address);
+            Addr end = VG_PGROUNDUP((Addr)desc->out_of_line.address + 
+                                    (Addr)desc->out_of_line.size);
+            PRINT("got ool mem %p..%#lx; ", desc->out_of_line.address, 
+                  (Addr)desc->out_of_line.address+desc->out_of_line.size);
+
+            ML_(notify_core_and_tool_of_mmap)(
+               start, end - start, VKI_PROT_READ|VKI_PROT_WRITE, 
+               VKI_MAP_PRIVATE, -1, 0);
+         }
+         // GrP fixme mark only un-rounded part as initialized 
+         break;
+
+      case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+         // out-of-line array of ports - map it
+         // GrP fixme see fixmes above
+         PRINT("got %d ool ports %p..%#lx", desc->ool_ports.count, desc->ool_ports.address, (Addr)desc->ool_ports.address+desc->ool_ports.count*sizeof(mach_port_t));
+
+         if (desc->ool_ports.count > 0) {
+            Addr start = VG_PGROUNDDN((Addr)desc->ool_ports.address);
+            Addr end = VG_PGROUNDUP((Addr)desc->ool_ports.address + desc->ool_ports.count * sizeof(mach_port_t));
+            mach_port_t *ports = (mach_port_t *)desc->ool_ports.address;
+
+            ML_(notify_core_and_tool_of_mmap)(
+               start, end - start, VKI_PROT_READ|VKI_PROT_WRITE, 
+               VKI_MAP_PRIVATE, -1, 0);
+
+            PRINT(":");
+            for (i = 0; i < desc->ool_ports.count; i++) {
+               record_unnamed_port(tid, ports[i], -1);
+               record_port_insert_rights(ports[i], desc->port.disposition);
+               PRINT(" %s", name_for_port(ports[i]));
+            }
+         }
+         PRINT(";");
+         break;
+
+      default:
+         VG_(printf)("UNKNOWN Mach descriptor type %u!\n", desc->type.type);
+         break;
+      }
+   }
+}
+
+
+static void pre_port_desc_read(ThreadId tid, mach_msg_port_descriptor_t *desc2)
+{
+#pragma pack(4)
+   struct {
+      mach_port_t name;
+      mach_msg_size_t pad1;
+      uint16_t pad2;
+      uint8_t disposition;
+      uint8_t type;
+   } *desc = (void*)desc2;
+#pragma pack()
+
+   PRE_FIELD_READ("msg->desc.port.name",        desc->name);
+   PRE_FIELD_READ("msg->desc.port.disposition", desc->disposition);
+   PRE_FIELD_READ("msg->desc.port.type",        desc->type);
+}
+
+
+static void pre_ool_desc_read(ThreadId tid, mach_msg_ool_descriptor_t *desc2)
+{
+#pragma pack(4)
+   struct {
+      Addr address;
+#if VG_WORDSIZE != 8
+      mach_msg_size_t size;
+#endif
+      uint8_t deallocate;
+      uint8_t copy;
+      uint8_t pad1;
+      uint8_t type;
+#if VG_WORDSIZE == 8
+      mach_msg_size_t size;
+#endif
+   } *desc = (void*)desc2;
+#pragma pack()
+
+   PRE_FIELD_READ("msg->desc.out_of_line.address",    desc->address);
+   PRE_FIELD_READ("msg->desc.out_of_line.size",       desc->size);
+   PRE_FIELD_READ("msg->desc.out_of_line.deallocate", desc->deallocate);
+   PRE_FIELD_READ("msg->desc.out_of_line.copy",       desc->copy);
+   PRE_FIELD_READ("msg->desc.out_of_line.type",       desc->type);
+}
+
+static void pre_oolports_desc_read(ThreadId tid, 
+                                   mach_msg_ool_ports_descriptor_t *desc2)
+{
+#pragma pack(4)
+   struct {
+      Addr address;
+#if VG_WORDSIZE != 8
+      mach_msg_size_t size;
+#endif
+      uint8_t deallocate;
+      uint8_t copy;
+      uint8_t disposition;
+      uint8_t type;
+#if VG_WORDSIZE == 8
+      mach_msg_size_t size;
+#endif
+   } *desc = (void*)desc2;
+#pragma pack()
+
+   PRE_FIELD_READ("msg->desc.ool_ports.address",     desc->address);
+   PRE_FIELD_READ("msg->desc.ool_ports.size",        desc->size);
+   PRE_FIELD_READ("msg->desc.ool_ports.deallocate",  desc->deallocate);
+   PRE_FIELD_READ("msg->desc.ool_ports.copy",        desc->copy);
+   PRE_FIELD_READ("msg->desc.ool_ports.disposition", desc->disposition);
+   PRE_FIELD_READ("msg->desc.ool_ports.type",        desc->type);
+}
+
+
+// Returns the size of the descriptor area
+// (mach_msg_body_t + any mach_msg_descriptor_t)
+static size_t export_complex_message(ThreadId tid, mach_msg_header_t *mh)
+{
+   mach_msg_body_t *body;
+   mach_msg_size_t count, i;
+   uint8_t *p;
+   mach_msg_descriptor_t *desc;
+   
+   vg_assert(mh->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+   
+   body = (mach_msg_body_t *)(mh+1);
+   PRE_MEM_READ("msg->msgh_descriptor_count)", (Addr)body, sizeof(*body));
+
+   count = body->msgh_descriptor_count;
+   p = (uint8_t *)(body+1);
+   
+   for (i = 0; i < count; i++) {
+      desc = (mach_msg_descriptor_t *)p;
+      p += desc_size(desc);
+      
+      switch (desc->type.type) {
+      case MACH_MSG_PORT_DESCRIPTOR:
+         // single port; no memory map effects
+         pre_port_desc_read(tid, &desc->port);
+         break;
+
+      case MACH_MSG_OOL_DESCRIPTOR:
+      case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
+         // out-of-line memory - unmap it if it's marked dealloc
+         // GrP fixme need to remap if message fails?
+         // GrP fixme how is VOLATILE different? do we care?
+         // GrP fixme struct is different for lp64
+         pre_ool_desc_read(tid, &desc->out_of_line);
+
+         if (desc->out_of_line.deallocate  &&  desc->out_of_line.size > 0) {
+            vm_size_t size = desc->out_of_line.size;
+            Addr start = VG_PGROUNDDN((Addr)desc->out_of_line.address);
+            Addr end = VG_PGROUNDUP((Addr)desc->out_of_line.address + size);
+            PRINT("kill ool mem %p..%#lx; ", desc->out_of_line.address, 
+                  (Addr)desc->out_of_line.address + size);
+            ML_(notify_core_and_tool_of_munmap)(start, end - start);
+         }
+         break;
+
+      case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+         // out-of-line array of ports - unmap it if it's marked dealloc
+         // GrP fixme need to remap if message fails?
+         // GrP fixme struct different for lp64
+         pre_oolports_desc_read(tid, &desc->ool_ports);
+
+         if (desc->ool_ports.deallocate  &&  desc->ool_ports.count > 0) {
+            vm_size_t size = desc->ool_ports.count * sizeof(mach_port_t);
+            Addr start = VG_PGROUNDDN((Addr)desc->ool_ports.address);
+            Addr end = VG_PGROUNDUP((Addr)desc->ool_ports.address + size);
+            PRINT("kill ool port array %p..%#lx; ", desc->ool_ports.address, 
+                  (Addr)desc->ool_ports.address + size);
+            ML_(notify_core_and_tool_of_munmap)(start, end - start);
+         }
+         break;
+      default:
+         VG_(printf)("UNKNOWN Mach descriptor type %u!\n", desc->type.type);
+         break;
+      }
+   }
+
+   return (size_t)((Addr)p - (Addr)body);
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: host-related messages
+   ------------------------------------------------------------------ */
+
+
+POST(host_info)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_type_number_t host_info_outCnt;
+      integer_t host_info_out[14];
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+PRE(host_info)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      host_flavor_t flavor;
+      mach_msg_type_number_t host_info_outCnt;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("host_info(mach_host_self(), flavor %d)", req->flavor);
+
+   AFTER = POST_FN(host_info);
+}
+
+
+POST(host_page_size)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      vm_size_t out_page_size;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      PRINT("page size %u", reply->out_page_size);
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+PRE(host_page_size)
+{
+   PRINT("host_page_size(mach_host_self(), ...)");
+    
+   AFTER = POST_FN(host_page_size);
+}
+
+
+POST(host_get_io_master)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t io_master;
+      /* end of the kernel processed data */
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   assign_port_name(reply->io_master.name, "io_master-%p");
+   PRINT("%s", name_for_port(reply->io_master.name));
+}
+
+PRE(host_get_io_master)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+   } Request;
+#pragma pack()
+
+   // Request *req = (Request *)ARG1;
+
+   PRINT("host_get_io_master(mach_host_self())");
+
+   AFTER = POST_FN(host_get_io_master);
+}
+
+
+POST(host_get_clock_service)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t clock_serv;
+      /* end of the kernel processed data */
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   assign_port_name(reply->clock_serv.name, "clock-%p");
+   PRINT("%s", name_for_port(reply->clock_serv.name));
+}
+
+PRE(host_get_clock_service)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      clock_id_t clock_id;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("host_get_clock_service(mach_host_self(), %d)", req->clock_id);
+
+   AFTER = POST_FN(host_get_clock_service);
+}
+
+
+PRE(host_request_notification)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t notify_port;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      host_flavor_t notify_type;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   if (MACH_REMOTE == mach_task_self()) { 
+      if (req->notify_type == 0) {
+         PRINT("host_request_notification(mach_host_self(), %s, %s)", 
+               "HOST_NOTIFY_CALENDAR_CHANGE", 
+               name_for_port(req->notify_port.name));
+      } else {
+         PRINT("host_request_notification(mach_host_self(), %d, %s)",
+               req->notify_type, 
+               name_for_port(req->notify_port.name));
+      } 
+   } else {
+      PRINT("host_request_notification(%s, %d, %s)",
+            name_for_port(MACH_REMOTE), 
+            req->notify_type, 
+            name_for_port(req->notify_port.name));
+   }
+
+    // GrP fixme only do this on success
+   assign_port_name(req->notify_port.name, "host_notify-%p");
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: messages to a task
+   ------------------------------------------------------------------ */
+
+
+PRE(mach_port_type)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_type(%s, %s, ...)", 
+         name_for_port(MACH_REMOTE), name_for_port(req->name));
+
+   AFTER = POST_FN(mach_port_type);
+}
+
+POST(mach_port_type)
+{
+}
+
+
+PRE(mach_port_extract_member)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_name_t pset;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_extract_member(%s, 0x%x, 0x%x)", 
+         name_for_port(MACH_REMOTE), 
+         req->name, req->pset);
+
+   AFTER = POST_FN(mach_port_extract_member);
+
+   // GrP fixme port tracker?
+}
+
+POST(mach_port_extract_member)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+
+PRE(mach_port_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_right_t right;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_allocate(mach_task_self(), %d, ...)", req->right);
+
+   MACH_ARG(mach_port_allocate.right) = req->right;
+
+   AFTER = POST_FN(mach_port_allocate);
+}
+
+POST(mach_port_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_port_name_t name;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // GrP fixme port tracking is too imprecise
+         // vg_assert(!port_exists(reply->name));
+         record_unnamed_port(tid, reply->name, MACH_ARG(mach_port_allocate.right));
+         PRINT("got port 0x%x", reply->name);
+      } else {
+         VG_(printf)("UNKNOWN inserted port 0x%x into remote task\n", reply->name);
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_port_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_deallocate(%s, %s)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name));
+
+   MACH_ARG(mach_port.port) = req->name;
+
+   AFTER = POST_FN(mach_port_deallocate);
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // Must have cleared SfMayBlock in PRE to prevent race
+         record_port_dealloc(MACH_ARG(mach_port.port));
+      } else {
+         VG_(printf)("UNKNOWN remote port dealloc\n");
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_port_get_refs)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_right_t right;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_get_refs(%s, %s, 0x%x)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name), req->right);
+
+   MACH_ARG(mach_port_mod_refs.port) = req->name;
+   MACH_ARG(mach_port_mod_refs.right) = req->right;
+    
+   AFTER = POST_FN(mach_port_get_refs);
+}
+
+POST(mach_port_get_refs)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_port_urefs_t refs;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      PRINT("got refs=%d", reply->refs);
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_port_mod_refs)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_right_t right;
+      mach_port_delta_t delta;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_mod_refs(%s, %s, 0x%x, 0x%x)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name), req->right, req->delta);
+
+   MACH_ARG(mach_port_mod_refs.port) = req->name;
+   MACH_ARG(mach_port_mod_refs.right) = req->right;
+   MACH_ARG(mach_port_mod_refs.delta) = req->delta;
+    
+   AFTER = POST_FN(mach_port_mod_refs);
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_mod_refs)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // Must have cleared SfMayBlock in PRE to prevent race
+         record_port_mod_refs(MACH_ARG(mach_port_mod_refs.port), 
+                              MACH_PORT_TYPE(MACH_ARG(mach_port_mod_refs.right)), 
+                              MACH_ARG(mach_port_mod_refs.delta));
+      } else {
+         VG_(printf)("UNKNOWN remote port mod refs\n");
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_port_get_set_status)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_get_set_status(%s, %s)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name));
+
+   AFTER = POST_FN(mach_port_get_set_status);
+}
+
+POST(mach_port_get_set_status)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_ool_descriptor_t members;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_msg_type_number_t membersCnt;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   // Reply *reply = (Reply *)ARG1;
+
+   // GrP fixme nothing to do?
+}
+
+
+PRE(mach_port_destroy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_destroy(%s, %s)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name));
+
+   MACH_ARG(mach_port.port) = req->name;
+
+   AFTER = POST_FN(mach_port_destroy);
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_destroy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // Must have cleared SfMayBlock in PRE to prevent race
+         record_port_destroy(MACH_ARG(mach_port.port));
+      } else {
+         VG_(printf)("UNKNOWN remote port destroy\n");
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_port_request_notification)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t notify;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_msg_id_t msgid;
+      mach_port_mscount_t sync;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_request_notification(%s, %s, %d, %d, %d, %d, ...)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name), req->msgid, req->sync, 
+         req->notify.name, req->notify.disposition);
+
+   AFTER = POST_FN(mach_port_request_notification);
+}
+
+POST(mach_port_request_notification)
+{
+   // GrP fixme port tracker? not sure
+}
+
+
+PRE(mach_port_insert_right)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t poly;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_port_name_t name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_insert_right(%s, %s, %d, %d)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name), req->poly.name, req->poly.disposition);
+
+   AFTER = POST_FN(mach_port_insert_right);
+
+   if (MACH_REMOTE == mach_task_self()) {
+      // GrP fixme import_complex_message handles everything?
+      // what about export_complex_message for MOVE variants?
+   } else {
+      VG_(printf)("UNKNOWN mach_port_insert_right into remote task!\n");
+      // GrP fixme also may remove rights from this task?
+   }
+
+   // GrP fixme port tracker?
+}
+
+POST(mach_port_insert_right)
+{
+}
+
+
+PRE(mach_port_get_attributes)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_flavor_t flavor;
+      mach_msg_type_number_t port_info_outCnt;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_get_attributes(%s, %s, %d, ..., %d)", 
+         name_for_port(MACH_REMOTE), 
+         name_for_port(req->name), req->flavor, req->port_info_outCnt);
+
+   AFTER = POST_FN(mach_port_get_attributes);
+}
+
+POST(mach_port_get_attributes)
+{
+}
+
+
+PRE(mach_port_set_attributes)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_flavor_t flavor;
+      mach_msg_type_number_t port_infoCnt;
+      integer_t port_info[10];
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_set_attributes(%s, %s, %d, ..., %d)", 
+        name_for_port(MACH_REMOTE), 
+        name_for_port(req->name), req->flavor, req->port_infoCnt);
+
+   AFTER = POST_FN(mach_port_set_attributes);
+}
+
+POST(mach_port_set_attributes)
+{
+}
+
+
+PRE(mach_port_insert_member)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_port_name_t name;
+      mach_port_name_t pset;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_port_insert_member(%s, 0x%x, 0x%x)", 
+         name_for_port(MACH_REMOTE), req->name, req->pset);
+
+   AFTER = POST_FN(mach_port_insert_member);
+
+   // GrP fixme port tracker?
+}
+
+POST(mach_port_insert_member)
+{
+}
+
+
+PRE(task_get_special_port)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      int which_port;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   switch (req->which_port) {
+   case TASK_KERNEL_PORT:
+      PRINT("task_get_special_port(%s, TASK_KERNEL_PORT)", 
+            name_for_port(MACH_REMOTE));
+      break;
+   case TASK_HOST_PORT:
+      PRINT("task_get_special_port(%s, TASK_HOST_PORT)", 
+            name_for_port(MACH_REMOTE));
+      break;
+   case TASK_BOOTSTRAP_PORT:
+      PRINT("task_get_special_port(%s, TASK_BOOTSTRAP_PORT)", 
+            name_for_port(MACH_REMOTE));
+      break;
+   case TASK_WIRED_LEDGER_PORT:
+      PRINT("task_get_special_port(%s, TASK_WIRED_LEDGER_PORT)", 
+            name_for_port(MACH_REMOTE));
+      break;
+   case TASK_PAGED_LEDGER_PORT:
+      PRINT("task_get_special_port(%s, TASK_PAGED_LEDGER_PORT)", 
+            name_for_port(MACH_REMOTE));
+      break;
+   default:
+      PRINT("task_get_special_port(%s, %d)", 
+            name_for_port(MACH_REMOTE), req->which_port);
+      break;
+   }
+   
+   MACH_ARG(task_get_special_port.which_port) = req->which_port;
+   
+   AFTER = POST_FN(task_get_special_port);
+}
+
+POST(task_get_special_port)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t special_port;
+      /* end of the kernel processed data */
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   PRINT("got port %#x ", reply->special_port.name);
+
+   switch (MACH_ARG(task_get_special_port.which_port)) {
+   case TASK_BOOTSTRAP_PORT:
+      vg_bootstrap_port = reply->special_port.name;
+      assign_port_name(reply->special_port.name, "bootstrap");
+      break;
+   case TASK_KERNEL_PORT:
+      assign_port_name(reply->special_port.name, "kernel");
+      break;
+   case TASK_HOST_PORT:
+      assign_port_name(reply->special_port.name, "host");
+      break;
+   case TASK_WIRED_LEDGER_PORT:
+      assign_port_name(reply->special_port.name, "wired-ledger");
+      break;
+   case TASK_PAGED_LEDGER_PORT:
+      assign_port_name(reply->special_port.name, "paged-ledger");
+      break;
+   default:
+      assign_port_name(reply->special_port.name, "special-%p");
+      break;
+   }
+
+   PRINT("%s", name_for_port(reply->special_port.name));
+}
+
+
+PRE(semaphore_create)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      int policy;
+      int value;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("semaphore_create(%s, ..., %d, %d)",
+         name_for_port(MACH_REMOTE), req->policy, req->value);
+
+   AFTER = POST_FN(semaphore_create);
+}
+
+POST(semaphore_create)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t semaphore;
+      /* end of the kernel processed data */
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   assign_port_name(reply->semaphore.name, "semaphore-%p");
+   PRINT("%s", name_for_port(reply->semaphore.name));
+}
+
+
+PRE(semaphore_destroy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t semaphore;
+      /* end of the kernel processed data */
+      mach_msg_trailer_t trailer;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("semaphore_destroy(%s, %s)", 
+         name_for_port(MACH_REMOTE), name_for_port(req->semaphore.name));
+
+   record_port_destroy(req->semaphore.name);
+
+   AFTER = POST_FN(semaphore_destroy);
+}
+
+POST(semaphore_destroy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;        
+   if (!reply->RetCode) {
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_ports_lookup)
+{
+#pragma pack(4)
+   typedef struct {
+       mach_msg_header_t Head;
+   } Request;
+#pragma pack()
+
+   // Request *req = (Request *)ARG1;
+
+   PRINT("mach_ports_lookup(%s)", name_for_port(MACH_REMOTE));
+
+   AFTER = POST_FN(mach_ports_lookup);
+}
+
+POST(mach_ports_lookup)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_ool_ports_descriptor_t init_port_set;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_msg_type_number_t init_port_setCnt;
+   } Reply;
+#pragma pack()
+
+    // Reply *reply = (Reply *)ARG1;
+}
+
+
+PRE(task_threads)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+   } Request;
+#pragma pack()
+
+   // Request *req = (Request *)ARG1;
+
+   PRINT("task_threads(%s)", name_for_port(MACH_REMOTE));
+
+   AFTER = POST_FN(task_threads);
+}
+
+POST(task_threads)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_ool_ports_descriptor_t act_list;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_msg_type_number_t act_listCnt;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (MACH_REMOTE == vg_task_port) {
+      assign_port_names(&reply->act_list, "thread-%p");
+   } else {
+      assign_port_names(&reply->act_list, "remote-thread-%p");
+   }
+}
+
+
+PRE(task_suspend)
+{
+   PRINT("task_suspend(%s)", name_for_port(MACH_REMOTE));
+
+   if (MACH_REMOTE == vg_task_port) {
+      // GrP fixme self-suspend
+      vg_assert(0);
+   } else {
+      // suspend other - no problem
+   }
+
+   AFTER = POST_FN(task_suspend);
+}
+
+POST(task_suspend)
+{
+}
+
+
+PRE(task_resume)
+{
+   PRINT("task_resume(%s)", name_for_port(MACH_REMOTE));
+
+   if (MACH_REMOTE == vg_task_port) {
+      // GrP fixme self-resume
+      vg_assert(0);
+   } else {
+      // resume other - no problem
+   }
+
+   AFTER = POST_FN(task_resume);
+}
+
+POST(task_resume)
+{
+}
+
+
+PRE(vm_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+      int flags;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("vm_allocate (%s, at %#x, size %d, flags %#x)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, req->flags);
+
+   MACH_ARG(vm_allocate.size) = req->size;
+   MACH_ARG(vm_allocate.flags) = req->flags;
+
+   AFTER = POST_FN(vm_allocate);
+}
+
+POST(vm_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      vm_address_t address;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         PRINT("allocated at %#x", reply->address);
+         // requesting 0 bytes returns address 0 with no error
+         if (MACH_ARG(vm_allocate.size)) {
+            ML_(notify_core_and_tool_of_mmap)(
+                  reply->address, MACH_ARG(vm_allocate.size), 
+                  VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_ANON, -1, 0);
+         }
+      } else {
+         PRINT("allocated at %#x in remote task %s", reply->address, 
+               name_for_port(MACH_REMOTE));
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(vm_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("vm_deallocate(%s, at %#x, size %d)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size);
+   
+   MACH_ARG(vm_deallocate.address) = req->address;
+   MACH_ARG(vm_deallocate.size) = req->size;
+   
+   AFTER = POST_FN(vm_deallocate);
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(vm_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         if (MACH_ARG(vm_deallocate.size)) {
+            Addr start = VG_PGROUNDDN(MACH_ARG(vm_deallocate.address));
+            Addr end = VG_PGROUNDUP(MACH_ARG(vm_deallocate.address) + 
+                                    MACH_ARG(vm_deallocate.size));
+            // Must have cleared SfMayBlock in PRE to prevent race
+            ML_(notify_core_and_tool_of_munmap)(start, end - start);
+         }
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+   
+
+PRE(vm_protect)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+      boolean_t set_maximum;
+      vm_prot_t new_protection;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("vm_protect(%s, at %#x, size %d, set_max %d, prot %d)", 
+         name_for_port(MACH_REMOTE), req->address, req->size, 
+         req->set_maximum, req->new_protection);
+   
+   MACH_ARG(vm_protect.address) = req->address;
+   MACH_ARG(vm_protect.size) = req->size;
+   MACH_ARG(vm_protect.set_maximum) = req->set_maximum;
+   MACH_ARG(vm_protect.new_protection) = req->new_protection;
+   
+   AFTER = POST_FN(vm_protect);
+}
+
+POST(vm_protect)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         Addr start = VG_PGROUNDDN(MACH_ARG(vm_protect.address));
+         Addr end = VG_PGROUNDUP(MACH_ARG(vm_protect.address) + 
+                                 MACH_ARG(vm_protect.size));
+         UInt prot = MACH_ARG(vm_protect.new_protection);
+         if (MACH_ARG(vm_protect.set_maximum)) {
+             // GrP fixme mprotect max
+             VG_(printf)("UNKNOWN vm_protect set maximum");
+            //VG_(mprotect_max_range)(start, end-start, prot);
+         } else {
+            ML_(notify_core_and_tool_of_mprotect)(start, end-start, prot);
+         }
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(vm_inherit)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+      vm_inherit_t new_inheritance;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("vm_inherit(%s, at %#x, size %d, value %d)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, 
+         req->new_inheritance);
+   
+   AFTER = POST_FN(vm_inherit);
+}
+
+POST(vm_inherit)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // GrP fixme do something?
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(vm_read)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("vm_read(from %s at %#x size %u)", 
+         name_for_port(MACH_REMOTE), req->address, req->size);
+   
+   MACH_ARG(vm_read.addr) = req->address;
+   MACH_ARG(vm_read.size) = req->size;
+
+   AFTER = POST_FN(vm_read);
+}
+
+POST(vm_read)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_ool_descriptor_t data;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_msg_type_number_t dataCnt;
+   } Reply;
+#pragma pack()
+
+   // Reply *reply = (Reply *)ARG1;
+
+   if (MACH_REMOTE == vg_task_port) {
+      // vm_read from self
+      // GrP fixme copy initialized state
+   }
+}
+
+
+
+PRE(mach_vm_read)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_vm_read(from %s at 0x%llx size %llu)", 
+         name_for_port(MACH_REMOTE), req->address, req->size);
+   
+   MACH_ARG(mach_vm_read.addr) = req->address;
+   MACH_ARG(mach_vm_read.size) = req->size;
+
+   AFTER = POST_FN(mach_vm_read);
+}
+
+POST(mach_vm_read)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_ool_descriptor_t data;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_msg_type_number_t dataCnt;
+   } Reply;
+#pragma pack()
+
+   // Reply *reply = (Reply *)ARG1;
+
+   if (MACH_REMOTE == vg_task_port) {
+      // vm_read from self
+      // GrP fixme copy initialized state
+   }
+}
+
+
+PRE(vm_read_overwrite)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+      vm_address_t data;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("vm_read_overwrite(from %s at %#x size %u to %#x)", 
+         name_for_port(MACH_REMOTE), req->address, req->size, req->data);
+   
+   MACH_ARG(vm_read_overwrite.addr) = req->address;
+   MACH_ARG(vm_read_overwrite.size) = req->size;
+   MACH_ARG(vm_read_overwrite.data) = req->data;
+
+   PRE_MEM_WRITE("vm_read_overwrite(data)", req->data, req->size);
+
+   AFTER = POST_FN(vm_read_overwrite);
+}
+
+POST(vm_read_overwrite)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      vm_size_t outsize;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (reply->RetCode) {
+       PRINT("mig return %d", reply->RetCode);
+   } else {
+      PRINT("read %llu bytes", (unsigned long long)reply->outsize);
+      if (MACH_REMOTE == vg_task_port) {
+         // vm_read_overwrite from self
+         // GrP fixme copy initialized state
+         POST_MEM_WRITE(MACH_ARG(vm_read_overwrite.data), reply->outsize);
+      } else {
+         // vm_read_overwrite from remote
+         POST_MEM_WRITE(MACH_ARG(vm_read_overwrite.data), reply->outsize);
+      }
+   }
+}
+
+
+PRE(vm_copy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t source_address;
+      vm_size_t size;
+      vm_address_t dest_address;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("vm_copy(%s, %#x, %d, %#x)", 
+         name_for_port(MACH_REMOTE), 
+         req->source_address, req->size, req->dest_address);
+
+   MACH_ARG(vm_copy.src) = req->source_address;
+   MACH_ARG(vm_copy.dst) = req->dest_address;
+   MACH_ARG(vm_copy.size) = req->size;
+   
+   AFTER = POST_FN(vm_copy);
+}
+
+POST(vm_copy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // GrP fixme set dst's initialization equal to src's
+         // and wipe any symbols or translations in dst
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(vm_map)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t object;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_size_t size;
+      vm_address_t mask;
+      int flags;
+      vm_offset_t offset;
+      boolean_t copy;
+      vm_prot_t cur_protection;
+      vm_prot_t max_protection;
+      vm_inherit_t inheritance;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   // GrP fixme check these
+   PRINT("vm_map(in %s, at %#x, size %d, from %s ...)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, 
+         name_for_port(req->object.name));
+
+   MACH_ARG(vm_map.size) = req->size;
+   MACH_ARG(vm_map.copy) = req->copy;
+   MACH_ARG(vm_map.protection) = (req->cur_protection & req->max_protection);
+
+   AFTER = POST_FN(vm_map);
+}
+
+POST(vm_map)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      vm_address_t address;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      // GrP fixme check src and dest tasks
+      PRINT("mapped at %#x", reply->address);
+      // GrP fixme max prot
+      ML_(notify_core_and_tool_of_mmap)(
+            reply->address, VG_PGROUNDUP(MACH_ARG(vm_map.size)), 
+            MACH_ARG(vm_map.protection), VKI_MAP_SHARED, -1, 0);
+      // GrP fixme VKI_MAP_PRIVATE if !copy?
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(vm_remap)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t src_task;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      vm_address_t target_address;
+      vm_size_t size;
+      vm_address_t mask;
+      boolean_t anywhere;
+      vm_address_t src_address;
+      boolean_t copy;
+      vm_inherit_t inheritance;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   // GrP fixme check src and dest tasks
+
+   if (VG_(clo_trace_syscalls)) {
+      mach_port_name_t source_task = req->src_task.name;
+      if (source_task == mach_task_self()) {
+         PRINT("vm_remap(mach_task_self(), "
+               "to %#x size %d, from mach_task_self() at %#x, ...)",
+               req->target_address, req->size, req->src_address);
+      } else {
+          PRINT("vm_remap(mach_task_self(), "
+                "to %#x size %d, from task %u at %#x, ...)",
+                req->target_address, req->size, 
+                source_task,  req->src_address);
+      }
+   }
+
+   // arg1 is task
+   // vt->syscall_arg2 = req->target_address;
+   MACH_ARG(vm_remap.size) = req->size;
+   // vt->syscall_arg4 = req->copy;
+
+   AFTER = POST_FN(vm_remap);
+}
+
+POST(vm_remap)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      vm_address_t target_address;
+      vm_prot_t cur_protection;
+      vm_prot_t max_protection;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      // GrP fixme check src and dest tasks
+      UInt prot = reply->cur_protection & reply->max_protection;
+      // GrP fixme max prot
+      PRINT("mapped at %#x", reply->target_address);
+      ML_(notify_core_and_tool_of_mmap)(
+            reply->target_address, VG_PGROUNDUP(MACH_ARG(vm_remap.size)), 
+            prot, VKI_MAP_SHARED, -1, 0);
+      // GrP fixme VKI_MAP_FIXED if !copy?
+      // GrP fixme copy initialized bits from source to dest if source_task is also mach_task_self
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_make_memory_entry_64)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t parent_entry;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      memory_object_size_t size;
+      memory_object_offset_t offset;
+      vm_prot_t permission;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_make_memory_entry_64(%s, %llu, %llu, %d, ..., %u)", 
+         name_for_port(MACH_REMOTE), 
+         req->size, req->offset, req->permission, req->parent_entry.type);
+
+   AFTER = POST_FN(mach_make_memory_entry_64);
+}
+
+POST(mach_make_memory_entry_64)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t object;
+      NDR_record_t NDR;
+      memory_object_size_t size;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+      assign_port_name(reply->object.name, "memory-%p");
+      PRINT("%s", name_for_port(reply->object.name));
+   }
+}
+
+
+PRE(vm_purgable_control)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      vm_address_t address;
+      vm_purgable_t control;
+      int state;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("vm_purgable_control(%s, %#x, %d, %d)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->control, req->state);
+
+   // GrP fixme verify address?
+
+   AFTER = POST_FN(vm_purgable_control);
+}
+
+POST(vm_purgable_control)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      int state;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_purgable_control)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      vm_purgable_t control;
+      int state;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_vm_purgable_control(%s, 0x%llx, %d, %d)", 
+         name_for_port(MACH_REMOTE), 
+         (unsigned long long)req->address, req->control, req->state);
+
+   // GrP fixme verify address?
+
+   AFTER = POST_FN(mach_vm_purgable_control);
+}
+
+POST(mach_vm_purgable_control)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      int state;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+      int flags;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_vm_allocate (%s, at 0x%llx, size %lld, flags 0x%x)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, req->flags);
+
+   MACH_ARG(mach_vm_allocate.size) = req->size;
+   MACH_ARG(mach_vm_allocate.flags) = req->flags;
+
+   AFTER = POST_FN(mach_vm_allocate);
+}
+
+POST(mach_vm_allocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_vm_address_t address;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         PRINT("allocated at 0x%llx", reply->address);
+         // requesting 0 bytes returns address 0 with no error
+         if (MACH_ARG(mach_vm_allocate.size)) {
+            ML_(notify_core_and_tool_of_mmap)(
+                  reply->address, MACH_ARG(mach_vm_allocate.size), 
+                  VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_ANON, -1, 0);
+         }
+      } else {
+         PRINT("allocated at 0x%llx in remote task %s", reply->address, 
+               name_for_port(MACH_REMOTE));
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("mach_vm_deallocate(%s, at 0x%llx, size %lld)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size);
+   
+   MACH_ARG(mach_vm_deallocate.address) = req->address;
+   MACH_ARG(mach_vm_deallocate.size) = req->size;
+   
+   AFTER = POST_FN(mach_vm_deallocate);
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(mach_vm_deallocate)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         if (MACH_ARG(mach_vm_deallocate.size)) {
+            Addr start = VG_PGROUNDDN(MACH_ARG(mach_vm_deallocate.address));
+            Addr end = VG_PGROUNDUP(MACH_ARG(mach_vm_deallocate.address) + 
+                                    MACH_ARG(mach_vm_deallocate.size));
+            // Must have cleared SfMayBlock in PRE to prevent race
+            ML_(notify_core_and_tool_of_munmap)(start, end - start);
+         }
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+   
+
+PRE(mach_vm_protect)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+      boolean_t set_maximum;
+      vm_prot_t new_protection;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("mach_vm_protect(%s, at 0x%llx, size %lld, set_max %d, prot %d)", 
+         name_for_port(MACH_REMOTE), req->address, req->size, 
+         req->set_maximum, req->new_protection);
+   
+   MACH_ARG(mach_vm_protect.address) = req->address;
+   MACH_ARG(mach_vm_protect.size) = req->size;
+   MACH_ARG(mach_vm_protect.set_maximum) = req->set_maximum;
+   MACH_ARG(mach_vm_protect.new_protection) = req->new_protection;
+   
+   AFTER = POST_FN(mach_vm_protect);
+}
+
+POST(mach_vm_protect)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         Addr start = VG_PGROUNDDN(MACH_ARG(mach_vm_protect.address));
+         Addr end = VG_PGROUNDUP(MACH_ARG(mach_vm_protect.address) + 
+                                 MACH_ARG(mach_vm_protect.size));
+         UInt prot = MACH_ARG(mach_vm_protect.new_protection);
+         if (MACH_ARG(mach_vm_protect.set_maximum)) {
+            // DDD: #warning GrP fixme mprotect max
+            //VG_(mprotect_max_range)(start, end-start, prot);
+         } else {
+            ML_(notify_core_and_tool_of_mprotect)(start, end-start, prot);
+         }
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_inherit)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+      vm_inherit_t new_inheritance;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+   
+   PRINT("mach_vm_inherit(to %s, at 0x%llx, size %llu, value %u)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, req->new_inheritance);
+
+   AFTER = POST_FN(mach_vm_inherit);
+}
+
+POST(mach_vm_inherit)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      // no V-visible side effects
+      // GrP fixme except maybe fork/exec
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_copy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t source_address;
+      mach_vm_size_t size;
+      mach_vm_address_t dest_address;
+   } Request;
+#pragma pack()
+   
+   Request *req = (Request *)ARG1;
+   
+   PRINT("mach_vm_copy(%s, 0x%llx, %llu, 0x%llx)", 
+         name_for_port(MACH_REMOTE), 
+         req->source_address, req->size, req->dest_address);
+   
+   // arg1 is task
+   // vt->syscall_arg2 = req->source_address;
+   // vt->syscall_arg3 = req->size;
+   // vt->syscall_arg4 = req->dest_address;
+   
+   AFTER = POST_FN(mach_vm_copy);
+}
+
+POST(mach_vm_copy)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+   
+   if (!reply->RetCode) {
+      if (MACH_REMOTE == vg_task_port) {
+         // GrP fixme set dest's initialization equal to src's
+         // BUT vm_copy allocates no memory
+      }
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_map)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t object;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+      mach_vm_address_t mask;
+      int flags;
+      memory_object_offset_t offset;
+      boolean_t copy;
+      vm_prot_t cur_protection;
+      vm_prot_t max_protection;
+      vm_inherit_t inheritance;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   // GrP fixme check these
+   PRINT("mach_vm_map(in %s, at 0x%llx, size %llu, from %s ...)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->size, 
+         name_for_port(req->object.name));
+
+   MACH_ARG(mach_vm_map.size) = req->size;
+   MACH_ARG(mach_vm_map.copy) = req->copy;
+   MACH_ARG(mach_vm_map.protection) = 
+      (req->cur_protection & req->max_protection);
+
+   AFTER = POST_FN(mach_vm_map);
+}
+
+POST(mach_vm_map)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_vm_address_t address;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+      // GrP fixme check src and dest tasks
+      PRINT("mapped at 0x%llx", reply->address);
+      // GrP fixme max prot
+      ML_(notify_core_and_tool_of_mmap)(
+            reply->address, VG_PGROUNDUP(MACH_ARG(mach_vm_map.size)), 
+            MACH_ARG(mach_vm_map.protection), VKI_MAP_SHARED, -1, 0);
+      // GrP fixme VKI_MAP_PRIVATE if !copy?
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+PRE(mach_vm_region_recurse)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      mach_vm_address_t address;
+      natural_t nesting_depth;
+      mach_msg_type_number_t infoCnt;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("mach_vm_region_recurse(in %s, at 0x%llx, depth %u, count %u)", 
+         name_for_port(MACH_REMOTE), 
+         req->address, req->nesting_depth, req->infoCnt);
+
+   AFTER = POST_FN(mach_vm_region_recurse);
+}
+
+POST(mach_vm_region_recurse)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_vm_address_t address;
+      mach_vm_size_t size;
+      natural_t nesting_depth;
+      mach_msg_type_number_t infoCnt;
+      int info[19];
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (!reply->RetCode) {
+       PRINT("got region at 0x%llx, size %llu, depth %u, count %u", 
+             reply->address, reply->size, 
+             reply->nesting_depth, reply->infoCnt);
+       // GrP fixme mark info contents beyond infoCnt as bogus
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: messages to thread
+   ------------------------------------------------------------------ */
+
+
+
+POST(thread_terminate)
+{
+}
+
+
+PRE(thread_terminate)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   Bool self_terminate = (mh->msgh_request_port == MACH_THREAD);
+
+   PRINT("thread_terminate(%s)", name_for_port(mh->msgh_request_port));
+
+   AFTER = POST_FN(thread_terminate);
+
+   if (self_terminate) {
+      // Terminating this thread.
+      // Copied from sys_exit.
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      tst->exitreason = VgSrc_ExitThread;
+      tst->os_state.exitcode = 0;  // GrP fixme anything better?
+      // What we would like to do is:
+      //   SET_STATUS_Success(0);
+      // but that doesn't work, because this is a MACH-class syscall,
+      // and SET_STATUS_Success creates a UNIX-class syscall result.
+      // Hence we have to laboriously construct the full SysRes "by hand"
+      // and use that to set the syscall return status.
+      SET_STATUS_from_SysRes(
+         VG_(mk_SysRes_x86_darwin)(
+            VG_DARWIN_SYSCALL_CLASS_MACH,
+            False/*success*/, 0, 0
+         )
+      );
+      *flags &= ~SfMayBlock;  // clear flag set by PRE(mach_msg)
+   } else {
+      // Terminating some other thread.
+      // Do keep the scheduler lock while terminating any other thread. 
+      // Otherwise we might halt the other thread while it holds the lock, 
+      // which would deadlock the process.
+      // GrP fixme good enough?
+      // GrP fixme need to clean up other thread's valgrind data?
+   }
+}
+
+
+POST(thread_create)
+{
+}
+
+
+PRE(thread_create)
+{
+   PRINT("thread_create(mach_task_self(), ...)");
+
+   AFTER = POST_FN(thread_create);
+
+   // GrP fixme
+   VG_(core_panic)("thread_create() unimplemented");
+}
+
+
+PRE(thread_create_running)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      thread_state_flavor_t flavor;
+      mach_msg_type_number_t new_stateCnt;
+      natural_t new_state[144];
+   } Request;
+#pragma pack()
+   
+   Request *req;
+   thread_state_t regs;
+   ThreadState *new_thread;
+   
+   PRINT("thread_create_running(mach_task_self(), ...)");
+   
+   // The new thread will immediately begin execution, 
+   // so we need to hijack the register state here.
+   
+   req = (Request *)ARG1;
+   regs = (thread_state_t)req->new_state;
+   
+   // Build virtual thread.
+   new_thread = build_thread(regs, req->flavor, req->new_stateCnt);
+   
+   // Edit the thread state to send to the real kernel.
+   hijack_thread_state(regs, req->flavor, req->new_stateCnt, new_thread);
+
+   AFTER = POST_FN(thread_create_running);
+}
+
+
+POST(thread_create_running)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t child_act;
+      /* end of the kernel processed data */
+   } Reply;
+#pragma pack()
+   
+   Reply *reply = (Reply *)ARG1;
+
+   assign_port_name(reply->child_act.name, "thread-%p");
+   PRINT("%s", name_for_port(reply->child_act.name));
+}
+
+
+PRE(sys_bsdthread_create)
+{
+   ThreadState *tst;
+
+   PRINT("bsdthread_create( %#lx, %#lx, %#lx, %#lx, %#lx )", 
+         ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(pthread_t,"bsdthread_create", 
+                 void *,"func", void *,"func_arg", void *,"stack", 
+                 pthread_t,"thread", unsigned int,"flags");
+
+   // The kernel will call V's pthread_hijack() to launch the thread.
+   // Here we allocate the thread state and pass it to pthread_hijack()
+   // via the func_arg parameter.
+   
+   tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
+   allocstack(tst->tid);
+
+   tst->os_state.func_arg = (Addr)ARG2;
+   ARG2 = (Word)tst;
+
+   // Create a semaphore that pthread_hijack will signal once it starts
+   // POST(sys_bsdthread_create) needs to wait for the new memory map to appear
+   semaphore_create(mach_task_self(), &tst->os_state.child_go, 
+                    SYNC_POLICY_FIFO, 0);
+   semaphore_create(mach_task_self(), &tst->os_state.child_done, 
+                    SYNC_POLICY_FIFO, 0);
+}
+
+POST(sys_bsdthread_create)
+{ 
+   // Tell new thread's pthread_hijack to proceed, and wait for it to finish.
+   // We hold V's lock on the child's behalf.
+   // If we return before letting pthread_hijack do its thing, V thinks 
+   // the new pthread struct is still unmapped when we return to libc, 
+   // causing false errors.
+
+   ThreadState *tst = (ThreadState *)ARG2;
+   semaphore_signal(tst->os_state.child_go);
+   semaphore_wait(tst->os_state.child_done);
+   semaphore_destroy(mach_task_self(), tst->os_state.child_go);
+   semaphore_destroy(mach_task_self(), tst->os_state.child_done);
+
+   // GrP fixme semaphore destroy needed when thread creation fails
+   // GrP fixme probably other cleanup too
+
+   // DDD: I'm not at all sure this is the right spot for this.  It probably
+   // should be in pthread_hijack instead, just before the call to
+   // start_thread_NORETURN(), call_on_new_stack_0_1(), but we don't have the
+   // parent tid value there...
+   VG_TRACK ( pre_thread_ll_create, tid, tst->tid );
+}
+
+
+PRE(sys_bsdthread_terminate)
+{
+   ThreadState *tst;
+
+   PRINT("bsdthread_terminate( %#lx, %lx, %s, %s )", 
+         ARG1, ARG2, name_for_port(ARG3), name_for_port(ARG4));
+   PRE_REG_READ4(int,"bsdthread_terminate", 
+                 void *,"freeaddr", size_t,"freesize", 
+                 mach_port_t,"kport", mach_port_t,"joinsem");
+
+   // Free memory and signal semaphore.
+   // GrP fixme errors?
+   if (ARG4) semaphore_signal((semaphore_t)ARG4);
+   if (ARG1  &&  ARG2) {
+       ML_(notify_core_and_tool_of_munmap)(ARG1, ARG2);
+       vm_deallocate(mach_task_self(), (vm_address_t)ARG1, (vm_size_t)ARG2);
+   }
+
+   // Tell V to terminate the thread.
+   // Copied from sys_exit.
+   tst = VG_(get_ThreadState)(tid);
+   tst->exitreason = VgSrc_ExitThread;
+   tst->os_state.exitcode = 0;  // GrP fixme anything better?
+   SET_STATUS_Success(0);
+}
+
+
+POST(thread_suspend)
+{
+}
+
+PRE(thread_suspend)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   Bool self_suspend = (mh->msgh_request_port == MACH_THREAD);
+
+   PRINT("thread_suspend(%s)", name_for_port(mh->msgh_request_port));
+
+   AFTER = POST_FN(thread_suspend);
+
+   if (self_suspend) {
+       // Don't keep the scheduler lock while self-suspending.
+       // Otherwise we might halt while still holding the lock, 
+       // which would deadlock the process.
+       *flags |= SfMayBlock;
+   } else {
+       // Do keep the scheduler lock while suspending any other thread. 
+       // Otherwise we might halt the other thread while it holds the lock, 
+       // which would deadlock the process.
+   }
+}
+
+
+POST(thread_get_state)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_type_number_t old_stateCnt;
+      natural_t old_state[144];
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+   // mach_port_t thread = MACH_ARG(thread_get_state.thread);
+   thread_state_flavor_t flavor = MACH_ARG(thread_get_state.flavor);
+
+   if (!reply->RetCode) {
+      thread_state_from_vex((thread_state_t)reply->old_state, 
+                             flavor, reply->old_stateCnt, 
+                             &VG_(get_ThreadState)(tid)->arch.vex);
+   } else {
+      PRINT("mig return %d", reply->RetCode);
+   }
+}
+
+PRE(thread_get_state)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      thread_state_flavor_t flavor;
+      mach_msg_type_number_t old_stateCnt;
+   } Request;
+#pragma pack()
+    
+   Request *req = (Request *)ARG1;
+   // Bool self = (req->Head.msgh_request_port == MACH_THREAD);
+
+   // GrP fixme   if (self) {
+   PRINT("thread_get_state(%s, %d)", 
+         name_for_port(req->Head.msgh_request_port), req->flavor);
+       /*} else {
+       PRINT("thread_get_state(0x%x, %d)", 
+             req->Head.msgh_request_port, req->flavor);
+             }*/
+
+   // Hack the thread state after making the real call.
+   MACH_ARG(thread_get_state.thread) = req->Head.msgh_request_port;
+   MACH_ARG(thread_get_state.flavor) = req->flavor;
+
+   AFTER = POST_FN(thread_get_state);
+}
+
+
+POST(thread_policy)
+{
+}
+
+PRE(thread_policy)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   // Bool self = (mh->msgh_request_port == MACH_THREAD);
+
+   // GrP fixme   if (self) {
+      PRINT("thread_policy(%s, ...)", name_for_port(mh->msgh_request_port));
+      /*} else {
+      PRINT("thread_policy(thread 0x%x, ...)", mh->msgh_request_port);
+      }*/
+
+   AFTER = POST_FN(thread_policy);
+}
+
+
+PRE(thread_info)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+   PRINT("thread_info(%s, ...)", name_for_port(mh->msgh_request_port));
+   // GrP fixme does any thread info need to be hijacked?
+
+   AFTER = POST_FN(thread_info);
+}
+
+POST(thread_info)
+{
+   // GrP fixme mark unused parts of thread_info_out as uninitialized?
+}
+
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: messages to bootstrap port
+   ------------------------------------------------------------------ */
+
+
+POST(bootstrap_register)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      kern_return_t RetCode;
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+PRE(bootstrap_register)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t service_port;
+      /* end of the kernel processed data */
+      NDR_record_t NDR;
+      name_t service_name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("bootstrap_register(port 0x%x, \"%s\")",
+         req->service_port.name, req->service_name);
+
+   assign_port_name(req->service_port.name, req->service_name);
+
+   AFTER = POST_FN(bootstrap_register);
+}
+
+
+POST(bootstrap_look_up)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      /* start of the kernel processed data */
+      mach_msg_body_t msgh_body;
+      mach_msg_port_descriptor_t service_port;
+      /* end of the kernel processed data */
+      mach_msg_trailer_t trailer;
+   } Reply;
+#pragma pack()
+
+   Reply *reply = (Reply *)ARG1;
+
+   if ((reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)  &&  
+       reply->service_port.name) 
+   {
+       assign_port_name(reply->service_port.name, 
+                        MACH_ARG(bootstrap_look_up.service_name));
+       PRINT("%s", name_for_port(reply->service_port.name));
+   } else {
+       PRINT("not found");
+   }
+   VG_(arena_free)(VG_AR_CORE, MACH_ARG(bootstrap_look_up.service_name));
+}
+
+PRE(bootstrap_look_up)
+{
+#pragma pack(4)
+   typedef struct {
+      mach_msg_header_t Head;
+      NDR_record_t NDR;
+      name_t service_name;
+   } Request;
+#pragma pack()
+
+   Request *req = (Request *)ARG1;
+
+   PRINT("bootstrap_look_up(\"%s\")", req->service_name);
+
+   MACH_ARG(bootstrap_look_up.service_name) =
+      VG_(arena_strdup)(VG_AR_CORE, "syswrap-darwin.bootstrap-name", 
+                        req->service_name);
+
+   AFTER = POST_FN(bootstrap_look_up);
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: receiver-specific handlers
+   ------------------------------------------------------------------ */
+
+
+POST(mach_msg_receive)
+{
+   // mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+   // GrP fixme don't know of anything interesting here currently
+   // import_complex_message handles everything
+   // PRINT("UNHANDLED reply %d", mh->msgh_id);
+
+   // Assume the call may have mapped or unmapped memory
+   sync_mappings("after", "mach_msg_receive", 0);
+}
+
+PRE(mach_msg_receive)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   
+   PRINT("mach_msg_receive(port %s)", name_for_port(mh->msgh_reply_port));
+   
+   AFTER = POST_FN(mach_msg_receive);
+
+   // no message sent, only listening for a reply
+   // assume message may block
+   *flags |= SfMayBlock;
+}
+
+
+PRE(mach_msg_bootstrap)
+{
+   // message to bootstrap port
+
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   
+   switch (mh->msgh_id) {
+   case 403:
+      CALL_PRE(bootstrap_register);
+      return;
+   case 404:
+      CALL_PRE(bootstrap_look_up);
+      return;
+      
+   default:
+      PRINT("UNHANDLED bootstrap message [id %d, to %s, reply 0x%x]\n", 
+            mh->msgh_id, name_for_port(mh->msgh_request_port),
+            mh->msgh_reply_port);
+      return;
+   }
+}
+
+
+PRE(mach_msg_host)
+{
+   // message to host self - check for host-level kernel calls
+
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+   switch (mh->msgh_id) {
+   case 200:
+      CALL_PRE(host_info);
+      return;
+   case 202:
+      CALL_PRE(host_page_size);
+      return;
+   case 205:
+      CALL_PRE(host_get_io_master);
+      return;
+   case 206:
+      CALL_PRE(host_get_clock_service);
+      return;
+   case 217:
+      CALL_PRE(host_request_notification);
+      return;
+
+   default:
+      // unknown message to host self
+      VG_(printf)("UNKNOWN host message [id %d, to %s, reply 0x%x]\n", 
+                  mh->msgh_id, name_for_port(mh->msgh_request_port), 
+                  mh->msgh_reply_port);
+      return;
+   }
+} 
+
+PRE(mach_msg_task)
+{
+   // message to a task port
+
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+   switch (mh->msgh_id) {
+   case 3201:
+      CALL_PRE(mach_port_type);
+      return;
+   case 3204:
+      CALL_PRE(mach_port_allocate);
+      return;
+   case 3205:
+      CALL_PRE(mach_port_destroy);
+      return;
+   case 3206:
+      CALL_PRE(mach_port_deallocate);
+      return;
+   case 3207:
+      CALL_PRE(mach_port_get_refs);
+      return;
+   case 3208:
+      CALL_PRE(mach_port_mod_refs);
+      return;
+   case 3211:
+      CALL_PRE(mach_port_get_set_status);
+      return;
+   case 3213:
+      CALL_PRE(mach_port_request_notification);
+      return;
+   case 3214:
+      CALL_PRE(mach_port_insert_right);
+      return;
+   case 3217:
+      CALL_PRE(mach_port_get_attributes);
+      return;
+   case 3218:
+      CALL_PRE(mach_port_set_attributes);
+      return;
+   case 3226:
+      CALL_PRE(mach_port_insert_member);
+      return;
+   case 3227:
+      CALL_PRE(mach_port_extract_member);
+      return;
+        
+   case 3402:
+      CALL_PRE(task_threads);
+      return;
+   case 3404:
+      CALL_PRE(mach_ports_lookup);
+      return;
+
+   case 3407:
+      CALL_PRE(task_suspend);
+      return;
+   case 3408:
+      CALL_PRE(task_resume);
+      return;
+      
+   case 3409:
+      CALL_PRE(task_get_special_port);
+      return;
+   case 3411:
+      CALL_PRE(thread_create);
+      return;
+   case 3412:
+      CALL_PRE(thread_create_running);
+      return;
+      
+   case 3418:
+      CALL_PRE(semaphore_create);
+      return;
+   case 3419:
+      CALL_PRE(semaphore_destroy);
+      return;
+      
+   case 3801:
+      CALL_PRE(vm_allocate);
+      return;
+   case 3802:
+      CALL_PRE(vm_deallocate);
+      return;
+   case 3803:
+      CALL_PRE(vm_protect);
+      return;
+   case 3804:
+      CALL_PRE(vm_inherit);
+      return;
+   case 3805:
+      CALL_PRE(vm_read);
+      return;
+   case 3808:
+      CALL_PRE(vm_copy);
+      return;
+   case 3809:
+      CALL_PRE(vm_read_overwrite);
+      return;
+   case 3812:
+      CALL_PRE(vm_map);
+      return;
+   case 3814:
+      CALL_PRE(vm_remap);
+      return;
+   case 3825:
+      CALL_PRE(mach_make_memory_entry_64);
+      return;
+   case 3830:
+      CALL_PRE(vm_purgable_control);
+      return;
+
+   case 4800:
+      CALL_PRE(mach_vm_allocate);
+      return;
+   case 4801:
+      CALL_PRE(mach_vm_deallocate);
+      return;
+   case 4802:
+      CALL_PRE(mach_vm_protect);
+      return;
+   case 4803:
+      CALL_PRE(mach_vm_inherit);
+      return;
+   case 4804:
+      CALL_PRE(mach_vm_read);
+      return;
+   case 4807:
+      CALL_PRE(mach_vm_copy);
+      return;
+   case 4811:
+      CALL_PRE(mach_vm_map);
+      return;
+   case 4815:
+      CALL_PRE(mach_vm_region_recurse);
+      return;
+   case 4817:
+      CALL_PRE(mach_make_memory_entry_64);
+      return;
+   case 4818:
+      CALL_PRE(mach_vm_purgable_control);
+      return;
+
+   default:
+      // unknown message to task self
+      VG_(printf)("UNKNOWN task message [id %d, to %s, reply 0x%x]\n",
+                  mh->msgh_id, name_for_port(mh->msgh_remote_port),
+                  mh->msgh_reply_port);
+      return;
+   }
+} 
+
+
+PRE(mach_msg_thread)
+{
+   // message to local thread - check for thread-level kernel calls
+
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+   switch (mh->msgh_id) {
+   case 3600: 
+      CALL_PRE(thread_terminate);
+      return;
+   case 3603:
+      CALL_PRE(thread_get_state);
+      return;
+   case 3605: 
+      CALL_PRE(thread_suspend);
+      return;
+   case 3612: 
+      CALL_PRE(thread_info);
+      return;
+   case 3616: 
+      CALL_PRE(thread_policy);
+      return;
+   default:
+      // unknown message to a thread
+      VG_(printf)("UNKNOWN thread message [id %d, to %s, reply 0x%x]\n", 
+                  mh->msgh_id, name_for_port(mh->msgh_request_port), 
+                  mh->msgh_reply_port);
+      return;
+   }
+}
+
+
+static int is_thread_port(mach_port_t port)
+{
+   if (port == 0) return False;
+
+   return VG_(lwpid_to_vgtid)(port) != VG_INVALID_THREADID;
+}
+
+
+static int is_task_port(mach_port_t port)
+{
+   if (port == 0) return False;
+
+   if (port == vg_task_port) return True;
+
+   return (0 == VG_(strncmp)("task-", name_for_port(port), 5));
+}
+
+
+/* ---------------------------------------------------------------------
+   mach_msg: base handlers
+   ------------------------------------------------------------------ */
+
+PRE(mach_msg)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   mach_msg_option_t option = (mach_msg_option_t)ARG2;
+   // mach_msg_size_t send_size = (mach_msg_size_t)ARG3;
+   mach_msg_size_t rcv_size = (mach_msg_size_t)ARG4;
+   // mach_port_t rcv_name = (mach_port_t)ARG5;
+   size_t complex_header_size = 0;
+
+   PRE_REG_READ7(long, "mach_msg", 
+                 mach_msg_header_t*,"msg", mach_msg_option_t,"option", 
+                 mach_msg_size_t,"send_size", mach_msg_size_t,"rcv_size", 
+                 mach_port_t,"rcv_name", mach_msg_timeout_t,"timeout", 
+                 mach_port_t,"notify");
+
+   // Assume default POST handler until specified otherwise
+   AFTER = NULL;
+
+   // Assume call may block unless specified otherwise
+   *flags |= SfMayBlock;
+
+   if (option & MACH_SEND_MSG) {
+      // Validate outgoing message header
+      PRE_MEM_READ("mach_msg(msg.msgh_bits)", 
+                   (Addr)&mh->msgh_bits, sizeof(mh->msgh_bits));
+      // msgh_size not required, use parameter instead
+      PRE_MEM_READ("mach_msg(msg.msgh_remote_port)", 
+                   (Addr)&mh->msgh_remote_port, sizeof(mh->msgh_remote_port));
+      PRE_MEM_READ("mach_msg(msg.msgh_local_port)", 
+                   (Addr)&mh->msgh_local_port, sizeof(mh->msgh_local_port));
+      // msgh_reserved not required
+      PRE_MEM_READ("mach_msg(msg.msgh_id)", 
+                   (Addr)&mh->msgh_id, sizeof(mh->msgh_id));
+      
+      if (mh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+         // Validate typed message data and handle memory map changes.
+         complex_header_size = export_complex_message(tid, mh);
+      }
+
+      // GrP fixme handle sender-specified message trailer
+      // (but is this only for too-secure processes?)
+      vg_assert(! (mh->msgh_bits & MACH_SEND_TRAILER));
+
+      MACH_REMOTE = mh->msgh_remote_port;
+      MACH_MSGH_ID = mh->msgh_id;
+   }
+
+   if (option & MACH_RCV_MSG) {
+      // Pre-validate receive buffer
+      PRE_MEM_WRITE("mach_msg(receive buffer)", (Addr)mh, rcv_size);
+   }
+
+   // Call a PRE handler. The PRE handler may set an AFTER handler.
+
+   if (!(option & MACH_SEND_MSG)) {
+      // no message sent, receive only
+      CALL_PRE(mach_msg_receive);
+      return;
+   }
+   else if (mh->msgh_request_port == vg_host_port) {
+      // message sent to mach_host_self()
+      CALL_PRE(mach_msg_host);
+      return;
+   }
+   else if (is_task_port(mh->msgh_request_port)) {
+      // message sent to a task
+      CALL_PRE(mach_msg_task);
+      return;
+   }
+   else if (mh->msgh_request_port == vg_bootstrap_port) {
+      // message sent to bootstrap port
+      CALL_PRE(mach_msg_bootstrap);
+      return;
+   }
+   else if (is_thread_port(mh->msgh_request_port)) {
+      // message sent to one of this process's threads
+      CALL_PRE(mach_msg_thread);
+      return;
+   }
+   else {
+      // arbitrary message to arbitrary port
+      PRINT("UNHANDLED mach_msg [id %d, to %s, reply 0x%x]", 
+            mh->msgh_id, name_for_port(mh->msgh_request_port), 
+            mh->msgh_reply_port);
+
+      AFTER = POST_FN(mach_msg_unhandled);
+
+      // Assume the entire message body may be read.
+      // GrP fixme generates false positives for unknown protocols
+      /*
+      PRE_MEM_READ("mach_msg(payload)", 
+                   (Addr)((char*)mh + sizeof(mach_msg_header_t) + complex_header_size), 
+                   send_size - sizeof(mach_msg_header_t) - complex_header_size);
+      */
+      return;
+   }
+}
+
+POST(mach_msg)
+{
+   mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+   mach_msg_option_t option = (mach_msg_option_t)ARG2;
+
+   if (option & MACH_RCV_MSG) {
+      if (RES != 0) {
+         // error during send or receive
+         // GrP fixme need to clean up port rights?
+      } else {
+         mach_msg_trailer_t *mt = 
+             (mach_msg_trailer_t *)((Addr)mh + round_msg(mh->msgh_size));
+           
+         // Assume the entire received message and trailer is initialized
+         // GrP fixme would being more specific catch any bugs?
+         POST_MEM_WRITE((Addr)mh, 
+                        round_msg(mh->msgh_size) + mt->msgh_trailer_size);
+         
+         if (mh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+             // Update memory map for out-of-line message data
+             import_complex_message(tid, mh);
+         }
+      }
+   }
+   
+   // Call handler chosen by PRE(mach_msg)
+   if (AFTER) {
+      (*AFTER)(tid, arrghs, status);
+   }
+}
+
+
+POST(mach_msg_unhandled)
+{
+   sync_mappings("after", "mach_msg_unhandled", 0);
+}
+
+
+/* ---------------------------------------------------------------------
+   other Mach traps
+   ------------------------------------------------------------------ */
+
+PRE(mach_reply_port)
+{
+   PRINT("mach_reply_port()");
+}
+
+POST(mach_reply_port)
+{
+   record_named_port(tid, RES, MACH_PORT_RIGHT_RECEIVE, "reply-%p");
+   PRINT("reply port %s", name_for_port(RES));
+}
+
+
+PRE(mach_thread_self)
+{
+   PRINT("mach_thread_self()");
+}
+
+POST(mach_thread_self)
+{
+   record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "thread-%p");
+   PRINT("thread %#lx", RES);
+}
+
+
+PRE(mach_host_self)
+{
+   PRINT("mach_host_self()");
+}
+
+POST(mach_host_self)
+{
+   vg_host_port = RES;
+   record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mach_host_self()");
+   PRINT("host %#lx", RES);
+}
+
+
+PRE(mach_task_self)
+{
+   PRINT("mach_task_self()");
+}
+
+POST(mach_task_self)
+{
+   vg_task_port = RES;
+   record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mach_task_self()");
+   PRINT("task %#lx", RES);
+}
+
+
+PRE(syscall_thread_switch)
+{
+   PRINT("syscall_thread_switch(%s, %ld, %ld)",
+      name_for_port(ARG1), ARG2, ARG3);
+   PRE_REG_READ3(long, "syscall_thread_switch", 
+                 mach_port_t,"thread", int,"option", natural_t,"timeout");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_signal)
+{
+   PRINT("semaphore_signal(%s)", name_for_port(ARG1));
+   PRE_REG_READ1(long, "semaphore_signal", semaphore_t,"semaphore");
+}
+
+
+PRE(semaphore_signal_all)
+{
+   PRINT("semaphore_signal_all(%s)", name_for_port(ARG1));
+   PRE_REG_READ1(long, "semaphore_signal_all", semaphore_t,"semaphore");
+}
+
+
+PRE(semaphore_signal_thread)
+{
+   PRINT("semaphore_signal_thread(%s, %s)", 
+         name_for_port(ARG1), name_for_port(ARG2));
+   PRE_REG_READ2(long, "semaphore_signal_thread", 
+                 semaphore_t,"semaphore", mach_port_t,"thread");
+}
+
+
+PRE(semaphore_wait)
+{
+   PRINT("semaphore_wait(%s)", name_for_port(ARG1));
+   PRE_REG_READ1(long, "semaphore_signal", semaphore_t,"semaphore");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_wait_signal)
+{
+   PRINT("semaphore_wait_signal(%s, %s)", 
+         name_for_port(ARG1), name_for_port(ARG2));
+   PRE_REG_READ2(long, "semaphore_wait_signal", 
+                 semaphore_t,"wait_semaphore", 
+                 semaphore_t,"signal_semaphore");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_timedwait)
+{
+   PRINT("semaphore_timedwait(%s, %g seconds)",
+         name_for_port(ARG1), ARG2+ARG3/1000000000.0);
+   PRE_REG_READ3(long, "semaphore_wait_signal", 
+                 semaphore_t,"semaphore", 
+                 int,"wait_time_hi", 
+                 int,"wait_time_lo");
+   
+   *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_timedwait_signal)
+{
+   PRINT("semaphore_wait_signal(wait %s, signal %s, %g seconds)",
+         name_for_port(ARG1), name_for_port(ARG2), ARG3+ARG4/1000000000.0);
+   PRE_REG_READ4(long, "semaphore_wait_signal", 
+                 semaphore_t,"wait_semaphore", 
+                 semaphore_t,"signal_semaphore", 
+                 int,"wait_time_hi", 
+                 int,"wait_time_lo");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(sys___semwait_signal)
+{
+   /* args: int cond_sem, int mutex_sem,
+            int timeout, int relative,
+            time_t tv_sec, time_t tv_nsec */
+   PRINT("sys___semwait_signal(wait %s, signal %s, %ld, %ld, %lds:%ldns)", 
+         name_for_port(ARG1), name_for_port(ARG2), ARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(long, "sys___semwait_signal", 
+                 int,"cond_sem", int,"mutex_sem",
+                 int,"timeout", int,"relative", 
+                 vki_time_t,"tv_sec", int,"tv_nsec");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(task_for_pid)
+{
+   PRINT("task_for_pid(%s, %ld, %#lx)", name_for_port(ARG1), ARG2, ARG3);
+   PRE_REG_READ3(long, "task_for_pid", 
+                 mach_port_t,"target", 
+                 vki_pid_t, "pid", mach_port_t *,"task");
+   PRE_MEM_WRITE("task_for_pid(task)", ARG3, sizeof(mach_port_t));
+}
+
+POST(task_for_pid)
+{
+   mach_port_t task;
+
+   POST_MEM_WRITE(ARG3, sizeof(mach_port_t));
+
+   task = *(mach_port_t *)ARG3;
+   record_named_port(tid, task, MACH_PORT_RIGHT_SEND, "task-%p");
+   PRINT("task 0x%x", task);
+}
+
+
+PRE(pid_for_task)
+{
+   PRINT("pid_for_task(%s, %#lx)", name_for_port(ARG1), ARG2);
+   PRE_REG_READ2(long, "task_for_pid", mach_port_t,"task", vki_pid_t *,"pid");
+   PRE_MEM_WRITE("task_for_pid(pid)", ARG2, sizeof(vki_pid_t));
+}
+
+POST(pid_for_task)
+{
+   vki_pid_t pid;
+
+   POST_MEM_WRITE(ARG2, sizeof(vki_pid_t));
+
+   pid = *(vki_pid_t *)ARG2;
+   PRINT("pid %u", pid);
+}
+
+
+PRE(mach_timebase_info)
+{
+   PRINT("mach_timebase_info(%#lx)", ARG1);
+   PRE_REG_READ1(long, "mach_timebase_info", void *,"info");
+   PRE_MEM_WRITE("mach_timebase_info(info)", ARG1, sizeof(struct vki_mach_timebase_info));
+}
+
+POST(mach_timebase_info)
+{
+   POST_MEM_WRITE(ARG1, sizeof(struct vki_mach_timebase_info));
+}
+
+
+PRE(mach_wait_until)
+{
+#if VG_WORDSIZE == 8
+   PRINT("mach_wait_until(%llu)", ARG1);
+   PRE_REG_READ1(long, "mach_wait_until", 
+                 unsigned long long,"deadline");
+#else   
+   PRINT("mach_wait_until(%llu)", LOHI64(ARG1, ARG2));
+   PRE_REG_READ2(long, "mach_wait_until", 
+                 int,"deadline_hi", int,"deadline_lo");
+#endif   
+   *flags |= SfMayBlock;
+}
+
+
+PRE(mk_timer_create)
+{
+   PRINT("mk_timer_create()");
+   PRE_REG_READ0(long, "mk_timer_create");
+}
+
+POST(mk_timer_create)
+{
+   record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mk_timer-%p");
+}
+
+
+PRE(mk_timer_destroy)
+{
+   PRINT("mk_timer_destroy(%s)", name_for_port(ARG1));
+   PRE_REG_READ1(long, "mk_timer_destroy", mach_port_t,"name");
+
+   // Must block to prevent race (other thread allocates and 
+   // notifies after we deallocate but before we notify)
+   *flags &= ~SfMayBlock;
+}
+
+POST(mk_timer_destroy)
+{
+   // Must have cleared SfMayBlock in PRE to prevent race
+   record_port_destroy(ARG1);
+}
+
+
+PRE(mk_timer_arm)
+{
+#if VG_WORDSIZE == 8
+   PRINT("mk_timer_arm(%s, %llu)", name_for_port(ARG1), ARG2);
+   PRE_REG_READ2(long, "mk_timer_arm", mach_port_t,"name", 
+                 unsigned long,"expire_time");
+#else
+   PRINT("mk_timer_arm(%s, %llu)", name_for_port(ARG1), LOHI64(ARG2, ARG3));
+   PRE_REG_READ3(long, "mk_timer_arm", mach_port_t,"name", 
+                 int,"expire_time_hi", int,"expire_time_lo");
+#endif
+}
+
+
+PRE(mk_timer_cancel)
+{
+   PRINT("mk_timer_cancel(%s, %#lx)", name_for_port(ARG1), ARG2);
+   PRE_REG_READ2(long, "mk_timer_cancel", 
+                 mach_port_t,"name", Addr,"result_time");
+   if (ARG2) {
+      PRE_MEM_WRITE("mk_timer_cancel(result_time)", ARG2,sizeof(vki_uint64_t));
+   }
+}
+
+POST(mk_timer_cancel)
+{
+   if (ARG2) {
+      POST_MEM_WRITE(ARG2, sizeof(vki_uint64_t));
+   }
+}
+
+
+PRE(iokit_user_client_trap)
+{
+   PRINT("iokit_user_client_trap(%s, %ld, %lx, %lx, %lx, %lx, %lx, %lx)",
+         name_for_port(ARG1), ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8);
+   PRE_REG_READ8(kern_return_t, "iokit_user_client_trap", 
+                 mach_port_t,connect, unsigned int,index, 
+                 uintptr_t,p1, uintptr_t,p2, uintptr_t,p3, 
+                 uintptr_t,p4, uintptr_t,p5, uintptr_t,p6);
+
+   // can't do anything else with this in general
+   // might be able to use connect+index to choose something sometimes
+}
+
+POST(iokit_user_client_trap)
+{
+   sync_mappings("after", "iokit_user_client_trap", ARG2);
+}
+
+
+PRE(swtch)
+{
+   PRINT("swtch ( )");
+   PRE_REG_READ0(long, "swtch");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(swtch_pri)
+{
+   PRINT("swtch_pri ( %ld )", ARG1);
+   PRE_REG_READ1(long, "swtch_pri", int,"pri");
+
+   *flags |= SfMayBlock;
+}
+
+
+PRE(sys_FAKE_SIGRETURN)
+{
+   /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
+      an explanation of what follows. */
+   /* This handles the fake signal-return system call created by
+      sigframe-x86-darwin.c. */
+   /* See also comments just below on PRE(sys_sigreturn). */
+
+   PRINT("FAKE_SIGRETURN ( )");
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   vg_assert(tid >= 1 && tid < VG_N_THREADS);
+   vg_assert(VG_(is_running_thread)(tid));
+
+   /* Remove the signal frame from this thread's (guest) stack,
+      in the process restoring the pre-signal guest state. */
+   VG_(sigframe_destroy)(tid, True);
+
+   /* Tell the driver not to update the guest state with the "result",
+      and set a bogus result to keep it happy. */
+   *flags |= SfNoWriteResult;
+   SET_STATUS_Success(0);
+
+   /* Check to see if any signals arose as a result of this. */
+   *flags |= SfPollAfter;
+}
+
+
+PRE(sys_sigreturn)
+{
+   /* This is the "real" sigreturn.  But because we construct all the
+      signal frames ourselves (of course, in m_sigframe), this cannot
+      happen as a result of normal signal delivery.  I think it
+      happens only when doing siglongjmp, in which case Darwin's Libc
+      appears to use it for two different purposes: to mess with the
+      per-thread sigaltstack flags (as per arg 2), or to restore the
+      thread's state from a ucontext* (as per arg 1). */
+
+   PRINT("sigreturn ( uctx=%#lx, infostyle=%#lx )", ARG1, ARG2);
+
+   vg_assert(VG_(is_valid_tid)(tid));
+   vg_assert(tid >= 1 && tid < VG_N_THREADS);
+   vg_assert(VG_(is_running_thread)(tid));
+
+   if (ARG2 == VKI_UC_SET_ALT_STACK) {
+      /* This is confusing .. the darwin kernel sources imply there is
+         a per-thread on-altstack/not-on-altstack flag, which is set
+         by this flag.  Just ignore it and claim success for the time
+         being. */
+      VG_(debugLog)(0, "syswrap-darwin",
+                       "WARNING: Ignoring sys_sigreturn( ..., "
+                       "UC_SET_ALT_STACK );\n");
+      SET_STATUS_Success(0);
+      return;
+   }
+   if (ARG2 == VKI_UC_RESET_ALT_STACK) {
+      /* Ditto */
+      VG_(debugLog)(0, "syswrap-darwin",
+                       "WARNING: Ignoring sys_sigreturn( ..., "
+                       "UC_RESET_ALT_STACK );\n");
+      SET_STATUS_Success(0);
+      return;
+   }
+
+   /* Otherwise claim this isn't supported.  (Could be
+      catastrophic).
+
+      What do we have to do if we do need to support it?
+
+      1. Change the second argument of VG_(sigframe_destroy) from
+         "Bool isRT" to "UInt sysno", so we can pass the syscall
+         number, so it can distinguish this case from the
+         __NR_DARWIN_FAKE_SIGRETURN case.
+
+      2. In VG_(sigframe_destroy), look at sysno to distinguish the
+         cases.  For __NR_DARWIN_FAKE_SIGRETURN, behave as at present.
+         For this case, restore the thread's CPU state (or at least
+         the integer regs) from the ucontext in ARG1 (and do all the
+         other "signal-returns" stuff too).
+
+      3. For (2), how do we know where the ucontext is?  One way is to
+         temporarily copy ARG1 into this thread's guest_EBX (or any
+         other int reg), and have VG_(sigframe_destroy) read
+         guest_EBX.  Why is it ok to trash guest_EBX (or any other int
+         reg)?  Because VG_(sigframe_destroy) is just about to
+         overwrite all the regs anyway -- since the primary purpose of
+         calling it is to restore the register state from the ucontext
+         pointed to by ARG1.
+
+      Hey, it's uggerly.  But at least it's documented.
+   */
+   /* But in the meantime ... */
+   VG_(debugLog)(0, "syswrap-darwin",
+                    "WARNING: Ignoring sys_sigreturn( uctx=..., 0 );\n");
+   VG_(debugLog)(0, "syswrap-darwin",
+                    "WARNING: Thread/program/Valgrind "
+                    "will likely segfault now.\n");
+   VG_(debugLog)(0, "syswrap-darwin",
+                    "WARNING: Please file a bug report at "
+                    "http://www.valgrind.org.\n");
+   SET_STATUS_Failure( VKI_ENOSYS );
+}
+
+
+/* ---------------------------------------------------------------------
+   machine-dependent traps
+   ------------------------------------------------------------------ */
+
+#if defined(VGA_x86)
+static VexGuestX86SegDescr* alloc_zeroed_x86_LDT ( void )
+{
+   Int nbytes = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
+   return VG_(arena_calloc)(VG_AR_CORE, "syswrap-darwin.ldt", nbytes, 1);
+}
+#endif
+
+PRE(pthread_set_self)
+{
+   PRINT("pthread_set_self ( %#lx )", ARG1);
+   PRE_REG_READ1(void, "pthread_set_self", struct pthread_t *, self);
+
+#if defined(VGA_x86)
+   // GrP fixme hack this isn't really pthread_set_self
+   // Point the USER_CTHREAD ldt entry (slot 6, reg 0x37) at this pthread
+   {
+      VexGuestX86SegDescr *ldt;
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      ldt = (VexGuestX86SegDescr *)tst->arch.vex.guest_LDT;
+      if (!ldt) {
+         ldt = alloc_zeroed_x86_LDT();
+         tst->arch.vex.guest_LDT = (HWord)ldt;
+      }
+      VG_(memset)(&ldt[6], 0, sizeof(ldt[6]));
+      ldt[6].LdtEnt.Bits.LimitLow = 1;
+      ldt[6].LdtEnt.Bits.LimitHi = 0;
+      ldt[6].LdtEnt.Bits.BaseLow = ARG1 & 0xffff;
+      ldt[6].LdtEnt.Bits.BaseMid = (ARG1 >> 16) & 0xff;
+      ldt[6].LdtEnt.Bits.BaseHi = (ARG1 >> 24) & 0xff;
+      ldt[6].LdtEnt.Bits.Pres = 1; // ACC_P
+      ldt[6].LdtEnt.Bits.Dpl = 3; // ACC_PL_U
+      ldt[6].LdtEnt.Bits.Type = 0x12; // ACC_DATA_W
+      ldt[6].LdtEnt.Bits.Granularity = 1;  // SZ_G
+      ldt[6].LdtEnt.Bits.Default_Big = 1;  // SZ_32
+      
+      tst->os_state.pthread = ARG1;
+      tst->arch.vex.guest_GS = 0x37;
+
+      // What we would like to do is:
+      //   SET_STATUS_Success(0x37);
+      // but that doesn't work, because this is a MDEP-class syscall,
+      // and SET_STATUS_Success creates a UNIX-class syscall result.
+      // Hence we have to laboriously construct the full SysRes "by hand"
+      // and use that to set the syscall return status.
+      SET_STATUS_from_SysRes(
+         VG_(mk_SysRes_x86_darwin)(
+            VG_DARWIN_SYSNO_CLASS(__NR_pthread_set_self),
+            False, 0, 0x37
+         )
+      );
+   }
+
+#elif defined(VGA_amd64)
+   // GrP fixme bigger hack than x86
+   {
+      ThreadState *tst = VG_(get_ThreadState)(tid);
+      tst->os_state.pthread = ARG1;
+      tst->arch.vex.guest_GS_0x60 = ARG1;
+      // SET_STATUS_Success(0x60);
+      // see comments on x86 case just above
+      SET_STATUS_from_SysRes(
+         VG_(mk_SysRes_amd64_darwin)(
+            VG_DARWIN_SYSNO_CLASS(__NR_pthread_set_self),
+            False, 0, 0x60
+         )
+      );
+   }
+
+#else
+#error unknown architecture
+#endif
+}
+
+
+/* ---------------------------------------------------------------------
+   syscall tables
+   ------------------------------------------------------------------ */
+
+/* Add a Darwin-specific, arch-independent wrapper to a syscall table. */
+#define MACX_(sysno, name)    WRAPPER_ENTRY_X_(darwin, VG_DARWIN_SYSNO_INDEX(sysno), name) 
+#define MACXY(sysno, name)    WRAPPER_ENTRY_XY(darwin, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#define _____(sysno) GENX_(sysno, sys_ni_syscall)
+
+/*
+     _____ : unsupported by the kernel (sys_ni_syscall)
+  // _____ : unimplemented in valgrind
+     GEN   : handlers are in syswrap-generic.c
+     MAC   : handlers are in this file
+        X_ : PRE handler only
+        XY : PRE and POST handlers
+*/
+// DDD: the "sys_" prefixes I think aren't necessary.  The name on the right
+// is meant to be the name of the function implementing the syscall in the
+// kernel.  On Darwin that seems to usually match the __NR_xyz name.
+const SyscallTableEntry ML_(syscall_table)[] = {
+// _____(__NR_syscall),   // 0
+   MACX_(__NR_exit, sys_exit), 
+   GENX_(__NR_fork, sys_fork), 
+   GENXY(__NR_read, sys_read), 
+   GENX_(__NR_write, sys_write), 
+   GENXY(__NR_open, sys_open), 
+   GENXY(__NR_close, sys_close), 
+   GENXY(__NR_wait4, sys_wait4), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(8)),     // old creat
+   GENX_(__NR_link, sys_link), 
+   GENX_(__NR_unlink, sys_unlink), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(11)),    // old execv
+   GENX_(__NR_chdir, sys_chdir), 
+   GENX_(__NR_fchdir, sys_fchdir), 
+   GENX_(__NR_mknod, sys_mknod), 
+   GENX_(__NR_chmod, sys_chmod), 
+   GENX_(__NR_chown, sys_chown), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(17)),    // old break
+   MACXY(__NR_getfsstat, sys_getfsstat), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(19)),    // old lseek
+   GENX_(__NR_getpid, sys_getpid),     // 20
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(21)),    // old mount 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(22)),    // old umount
+   GENX_(__NR_setuid, sys_setuid), 
+   GENX_(__NR_getuid, sys_getuid), 
+   GENX_(__NR_geteuid, sys_geteuid), 
+   MACX_(__NR_ptrace, sys_ptrace), 
+   MACXY(__NR_recvmsg, sys_recvmsg), 
+   MACX_(__NR_sendmsg, sys_sendmsg), 
+   MACXY(__NR_recvfrom, sys_recvfrom), 
+   MACXY(__NR_accept, sys_accept), 
+   MACXY(__NR_getpeername, sys_getpeername), 
+   MACXY(__NR_getsockname, sys_getsockname), 
+   GENX_(__NR_access, sys_access), 
+   MACX_(__NR_chflags, sys_chflags), 
+   MACX_(__NR_fchflags, sys_fchflags), 
+   GENX_(__NR_sync, sys_sync), 
+   GENX_(__NR_kill, sys_kill), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(38)),    // old stat
+   GENX_(__NR_getppid, sys_getppid), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(40)),    // old lstat
+   GENXY(__NR_dup, sys_dup), 
+   MACXY(__NR_pipe, sys_pipe), 
+   GENX_(__NR_getegid, sys_getegid), 
+// _____(__NR_profil), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(45)),    // old ktrace
+   MACXY(__NR_sigaction, sys_sigaction), 
+   GENX_(__NR_getgid, sys_getgid), 
+   MACXY(__NR_sigprocmask, sys_sigprocmask), 
+   MACXY(__NR_getlogin, sys_getlogin), 
+// _____(__NR_setlogin), 
+// _____(__NR_acct), 
+// _____(__NR_sigpending), 
+   GENXY(__NR_sigaltstack, sys_sigaltstack), 
+   MACXY(__NR_ioctl, sys_ioctl), 
+// _____(__NR_reboot), 
+// _____(__NR_revoke), 
+// _____(__NR_symlink), 
+   GENX_(__NR_readlink, sys_readlink), 
+   GENX_(__NR_execve, sys_execve), 
+   GENX_(__NR_umask, sys_umask),     // 60
+   GENX_(__NR_chroot, sys_chroot), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(62)),    // old fstat
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(63)),    // used internally, reserved
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(64)),    // old getpagesize
+   GENX_(__NR_msync, sys_msync), 
+   GENX_(__NR_vfork, sys_fork),              // (We treat vfork as fork.)
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(67)),    // old vread
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(68)),    // old vwrite
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(69)),    // old sbrk
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(70)),    // old sstk
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(71)),    // old mmap
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(72)),    // old vadvise
+   GENXY(__NR_munmap, sys_munmap), 
+   GENXY(__NR_mprotect, sys_mprotect), 
+   GENX_(__NR_madvise, sys_madvise), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(76)),    // old vhangup
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(77)),    // old vlimit
+// _____(__NR_mincore), 
+   GENXY(__NR_getgroups, sys_getgroups), 
+// _____(__NR_setgroups),   // 80
+   GENX_(__NR_getpgrp, sys_getpgrp), 
+// _____(__NR_setpgid), 
+   GENXY(__NR_setitimer, sys_setitimer), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(84)),    // old wait
+// _____(__NR_swapon), 
+   GENXY(__NR_getitimer, sys_getitimer), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(87)),    // old gethostname
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(88)),    // old sethostname
+   MACXY(__NR_getdtablesize, sys_getdtablesize), 
+   GENXY(__NR_dup2, sys_dup2), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(91)),    // old getdopt
+   MACXY(__NR_fcntl, sys_fcntl), 
+   GENX_(__NR_select, sys_select), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(94)),    // old setdopt
+   GENX_(__NR_fsync, sys_fsync), 
+   GENX_(__NR_setpriority, sys_setpriority), 
+   MACXY(__NR_socket, sys_socket), 
+   MACX_(__NR_connect, sys_connect), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(99)),    // old accept
+   GENX_(__NR_getpriority, sys_getpriority),   // 100
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(101)),   // old send
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(102)),   // old recv
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(103)),   // old sigreturn
+   MACX_(__NR_bind, sys_bind), 
+   MACX_(__NR_setsockopt, sys_setsockopt), 
+   MACX_(__NR_listen, sys_listen), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(107)),   // old vtimes
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(108)),   // old sigvec
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(109)),   // old sigblock
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(110)),   // old sigsetmask
+   MACX_(__NR_sigsuspend, sys_sigsuspend),         // old sigsuspend
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(112)),   // old sigstack
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(113)),   // old recvmsg
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(114)),   // old sendmsg
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(115)),   // old vtrace
+   GENXY(__NR_gettimeofday, sys_gettimeofday), 
+   GENXY(__NR_getrusage, sys_getrusage), 
+   MACXY(__NR_getsockopt, sys_getsockopt), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(119)),   // old resuba
+   GENXY(__NR_readv, sys_readv),        // 120
+   GENX_(__NR_writev, sys_writev), 
+// _____(__NR_settimeofday), 
+   GENX_(__NR_fchown, sys_fchown), 
+   GENX_(__NR_fchmod, sys_fchmod), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(125)),   // old recvfrom
+// _____(__NR_setreuid), 
+// _____(__NR_setregid), 
+   GENX_(__NR_rename, sys_rename), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(129)),   // old truncate
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(130)),   // old ftruncate
+   GENX_(__NR_flock, sys_flock), 
+// _____(__NR_mkfifo), 
+   MACX_(__NR_sendto, sys_sendto), 
+   MACX_(__NR_shutdown, sys_shutdown), 
+   MACXY(__NR_socketpair, sys_socketpair), 
+   GENX_(__NR_mkdir, sys_mkdir), 
+   GENX_(__NR_rmdir, sys_rmdir), 
+   GENX_(__NR_utimes, sys_utimes), 
+   MACX_(__NR_futimes, sys_futimes), 
+// _____(__NR_adjtime),     // 140
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(141)),   // old getpeername
+   MACXY(__NR_gethostuuid, sys_gethostuuid), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(143)),   // old sethostid
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(144)),   // old getrlimit
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(145)),   // old setrlimit
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(146)),   // old killpg
+   GENX_(__NR_setsid, sys_setsid), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(148)),   // old setquota
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(149)),   // old qquota
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(150)),   // old getsockname 
+// _____(__NR_getpgid), 
+// _____(__NR_setprivexec), 
+   GENXY(__NR_pread, sys_pread64), 
+   GENX_(__NR_pwrite, sys_pwrite64), 
+// _____(__NR_nfssvc), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(156)),   // old getdirentries
+   GENXY(__NR_statfs, sys_statfs), 
+   GENXY(__NR_fstatfs, sys_fstatfs), 
+// _____(__NR_unmount), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(160)),   // old async_daemon
+// _____(__NR_getfh), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(162)),   // old getdomainname
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(163)),   // old setdomainname
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(164)),   // ???
+// _____(__NR_quotactl), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(166)),   // old exportfs
+// _____(__NR_mount), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(168)),   // old ustat
+   MACXY(__NR_csops, sys_csops),                   // code-signing ops
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(170)),   // old table
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(171)),   // old wait3
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(172)),   // old rpause
+// _____(__NR_waitid), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(174)),   // old getdents
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(175)),   // old gc_control
+// _____(__NR_add_profil), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(177)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(178)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(179)),   // ???
+   MACX_(__NR_kdebug_trace, sys_kdebug_trace),   // 180
+   GENX_(__NR_setgid, sys_setgid), 
+   MACX_(__NR_setegid, sys_setegid), 
+   MACX_(__NR_seteuid, sys_seteuid), 
+   MACX_(__NR_sigreturn, sys_sigreturn), 
+// _____(__NR_chud), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(186)),   // ??? 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(187)),   // ??? 
+   GENXY(__NR_stat, sys_newstat), 
+   GENXY(__NR_fstat, sys_newfstat), 
+   GENXY(__NR_lstat, sys_newlstat), 
+   MACX_(__NR_pathconf, sys_pathconf), 
+   MACX_(__NR_fpathconf, sys_fpathconf), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(193)),   // ???
+   GENXY(__NR_getrlimit, sys_getrlimit), 
+   GENX_(__NR_setrlimit, sys_setrlimit), 
+   MACXY(__NR_getdirentries, sys_getdirentries), 
+   MACXY(__NR_mmap, sys_mmap), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(198)),   // __syscall
+   MACX_(__NR_lseek, sys_lseek), 
+   GENX_(__NR_truncate, sys_truncate64),   // 200
+   GENX_(__NR_ftruncate, sys_ftruncate64), 
+   MACXY(__NR___sysctl, sys_sysctl), 
+   GENX_(__NR_mlock, sys_mlock), 
+   GENX_(__NR_munlock, sys_munlock), 
+// _____(__NR_undelete), 
+// _____(__NR_ATsocket), 
+// _____(__NR_ATgetmsg), 
+// _____(__NR_ATputmsg), 
+// _____(__NR_ATPsndreq), 
+// _____(__NR_ATPsndrsp), 
+// _____(__NR_ATPgetreq), 
+// _____(__NR_ATPgetrsp), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(213)),   // Reserved for AppleTalk
+// _____(__NR_kqueue_from_portset_np), 
+// _____(__NR_kqueue_portset_np), 
+// _____(__NR_mkcomplex), 
+// _____(__NR_statv), 
+// _____(__NR_lstatv), 
+// _____(__NR_fstatv), 
+   MACXY(__NR_getattrlist, sys_getattrlist),   // 220
+   MACX_(__NR_setattrlist, sys_setattrlist), 
+   MACXY(__NR_getdirentriesattr, sys_getdirentriesattr), 
+// _____(__NR_exchangedata), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(224)),   // checkuseraccess
+// _____(__NR_searchfs), 
+   GENX_(__NR_delete, sys_unlink), 
+// _____(__NR_copyfile), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(228)),   // ?? 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(229)),   // ?? 
+   GENXY(__NR_poll, sys_poll), 
+   MACX_(__NR_watchevent, sys_watchevent), 
+   MACXY(__NR_waitevent, sys_waitevent), 
+   MACX_(__NR_modwatch, sys_modwatch), 
+   MACXY(__NR_getxattr, sys_getxattr), 
+   MACXY(__NR_fgetxattr, sys_fgetxattr), 
+   MACX_(__NR_setxattr, sys_setxattr), 
+   MACX_(__NR_fsetxattr, sys_fsetxattr), 
+// _____(__NR_removexattr), 
+// _____(__NR_fremovexattr), 
+   MACXY(__NR_listxattr, sys_listxattr),    // 240
+   MACXY(__NR_flistxattr, sys_flistxattr), 
+   MACXY(__NR_fsctl, sys_fsctl), 
+   MACX_(__NR_initgroups, sys_initgroups), 
+   MACXY(__NR_posix_spawn, sys_posix_spawn), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(245)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(246)),   // ???
+// _____(__NR_nfsclnt), 
+// _____(__NR_fhopen), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(249)),   // ???
+// _____(__NR_minherit), 
+// _____(__NR_semsys), 
+// _____(__NR_msgsys), 
+// _____(__NR_shmsys), 
+   MACXY(__NR_semctl, sys_semctl), 
+   MACX_(__NR_semget, sys_semget), 
+   MACX_(__NR_semop, sys_semop), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(257)),   // ???
+// _____(__NR_msgctl), 
+// _____(__NR_msgget), 
+// _____(__NR_msgsnd),   // 260
+// _____(__NR_msgrcv), 
+// _____(__NR_shmat), 
+// _____(__NR_shmctl), 
+// _____(__NR_shmdt), 
+   MACX_(__NR_shmget, sys_shmget), 
+   MACXY(__NR_shm_open, sys_shm_open), 
+// _____(__NR_shm_unlink), 
+   MACX_(__NR_sem_open, sys_sem_open), 
+   MACX_(__NR_sem_close, sys_sem_close), 
+   MACX_(__NR_sem_unlink, sys_sem_unlink), 
+// _____(__NR_sem_wait), 
+   MACX_(__NR_sem_trywait, sys_sem_trywait), 
+// _____(__NR_sem_post), 
+   MACX_(__NR_sem_post, sys_sem_post), 
+// _____(__NR_sem_getvalue), 
+   MACXY(__NR_sem_init, sys_sem_init), 
+   MACX_(__NR_sem_destroy, sys_sem_destroy), 
+// _____(__NR_open_extended), 
+// _____(__NR_umask_extended), 
+   MACXY(__NR_stat_extended, sys_statx), 
+// _____(__NR_lstat_extended),   // 280
+// _____(__NR_fstat_extended), 
+   MACX_(__NR_chmod_extended, sys_chmod_extended), 
+   MACX_(__NR_fchmod_extended, sys_fchmod_extended), 
+// _____(__NR_access_extended), 
+   MACX_(__NR_settid, sys_settid), 
+// _____(__NR_gettid), 
+// _____(__NR_setsgroups), 
+// _____(__NR_getsgroups), 
+// _____(__NR_setwgroups), 
+// _____(__NR_getwgroups), 
+// _____(__NR_mkfifo_extended), 
+// _____(__NR_mkdir_extended), 
+// _____(__NR_identitysvc), 
+// _____(__NR_shared_region_check_np), 
+// _____(__NR_shared_region_map_np), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(296)),   // old load_shared_file 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(297)),   // old reset_shared_file 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(298)),   // old new_system_shared_regions 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(299)),   // old shared_region_map_file_np 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(300)),   // old shared_region_make_private_np
+// _____(__NR___pthread_mutex_destroy), 
+// _____(__NR___pthread_mutex_init), 
+// _____(__NR___pthread_mutex_lock), 
+// _____(__NR___pthread_mutex_trylock), 
+// _____(__NR___pthread_mutex_unlock), 
+// _____(__NR___pthread_cond_init), 
+// _____(__NR___pthread_cond_destroy), 
+// _____(__NR___pthread_cond_broadcast), 
+// _____(__NR___pthread_cond_signal), 
+// _____(__NR_getsid), 
+// _____(__NR_settid_with_pid), 
+// _____(__NR___pthread_cond_timedwait), 
+// _____(__NR_aio_fsync), 
+// _____(__NR_aio_return), 
+// _____(__NR_aio_suspend), 
+// _____(__NR_aio_cancel), 
+// _____(__NR_aio_error), 
+// _____(__NR_aio_read), 
+// _____(__NR_aio_write), 
+// _____(__NR_lio_listio),   // 320
+// _____(__NR___pthread_cond_wait), 
+// _____(__NR_iopolicysys), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(323)),   // ???
+// _____(__NR_mlockall), 
+// _____(__NR_munlockall), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(326)),   // ???
+   MACX_(__NR_issetugid, sys_issetugid), 
+// _____(__NR___pthread_kill), 
+   MACX_(__NR___pthread_sigmask, sys___pthread_sigmask), 
+// _____(__NR___sigwait), 
+   MACX_(__NR___disable_threadsignal, sys___disable_threadsignal), 
+   MACX_(__NR___pthread_markcancel, sys___pthread_markcancel), 
+   MACX_(__NR___pthread_canceled, sys___pthread_canceled),
+   MACX_(__NR___semwait_signal, sys___semwait_signal), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(335)),   // old utrace
+// _____(__NR_proc_info), 
+   MACXY(__NR_sendfile, sys_sendfile), 
+   MACXY(__NR_stat64, sys_stat64), 
+   MACXY(__NR_fstat64, sys_fstat64), 
+   MACXY(__NR_lstat64, sys_lstat64),    // 340
+// _____(__NR_stat64_extended), 
+// _____(__NR_lstat64_extended), 
+// _____(__NR_fstat64_extended), 
+   MACXY(__NR_getdirentries64, sys_getdirentries64), 
+   MACXY(__NR_statfs64, sys_statfs64), 
+   MACXY(__NR_fstatfs64, sys_fstatfs64), 
+// _____(__NR_getfsstat64), 
+// _____(__NR___pthread_chdir), 
+// _____(__NR___pthread_fchdir), 
+// _____(__NR_audit), 
+   MACXY(__NR_auditon, sys_auditon), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(352)),   // ???
+// _____(__NR_getauid), 
+// _____(__NR_setauid), 
+// _____(__NR_getaudit), 
+// _____(__NR_setaudit), 
+// _____(__NR_getaudit_addr), 
+// _____(__NR_setaudit_addr), 
+// _____(__NR_auditctl), 
+   MACXY(__NR_bsdthread_create, sys_bsdthread_create),   // 360
+   MACX_(__NR_bsdthread_terminate, sys_bsdthread_terminate), 
+   MACXY(__NR_kqueue, sys_kqueue), 
+   MACXY(__NR_kevent, sys_kevent), 
+// _____(__NR_lchown), 
+// _____(__NR_stack_snapshot), 
+   MACX_(__NR_bsdthread_register, sys_bsdthread_register), 
+   MACX_(__NR_workq_open, sys_workq_open), 
+   MACXY(__NR_workq_ops, sys_workq_ops), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(369)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(370)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(371)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(372)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(373)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(374)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(375)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(376)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(377)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(378)),   // ???
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(379)),   // ???
+// _____(__NR___mac_execve),   // 380
+   MACX_(__NR___mac_syscall, sys___mac_syscall),
+// _____(__NR___mac_get_file),
+// _____(__NR___mac_set_file),
+// _____(__NR___mac_get_link),
+// _____(__NR___mac_set_link),
+// _____(__NR___mac_get_proc),
+// _____(__NR___mac_set_proc),
+// _____(__NR___mac_get_fd),
+// _____(__NR___mac_set_fd),
+// _____(__NR___mac_get_pid),
+// _____(__NR___mac_get_lcid),
+// _____(__NR___mac_get_lctx),
+// _____(__NR___mac_set_lctx),
+// _____(__NR_setlcid),
+// _____(__NR_getlcid),
+   // GrP fixme need any special nocancel handling?
+   GENXY(__NR_read_nocancel, sys_read),
+   GENX_(__NR_write_nocancel, sys_write),
+   GENXY(__NR_open_nocancel, sys_open),
+   GENXY(__NR_close_nocancel, sys_close),
+   GENXY(__NR_wait4_nocancel, sys_wait4),   // 400
+   MACXY(__NR_recvmsg_nocancel, sys_recvmsg),
+   MACX_(__NR_sendmsg_nocancel, sys_sendmsg),
+   MACXY(__NR_recvfrom_nocancel, sys_recvfrom),
+   MACXY(__NR_accept_nocancel, sys_accept),
+   GENX_(__NR_msync_nocancel, sys_msync),
+   MACXY(__NR_fcntl_nocancel, sys_fcntl),
+   GENX_(__NR_select_nocancel, sys_select),
+   GENX_(__NR_fsync_nocancel, sys_fsync),
+   MACX_(__NR_connect_nocancel, sys_connect),
+// _____(__NR_sigsuspend_nocancel),
+   GENXY(__NR_readv_nocancel, sys_readv),
+   GENX_(__NR_writev_nocancel, sys_writev),
+   MACX_(__NR_sendto_nocancel, sys_sendto),
+   GENXY(__NR_pread_nocancel, sys_pread64),
+   GENX_(__NR_pwrite_nocancel, sys_pwrite64),
+// _____(__NR_waitid_nocancel),
+   GENXY(__NR_poll_nocancel, sys_poll),
+// _____(__NR_msgsnd_nocancel),
+// _____(__NR_msgrcv_nocancel),
+   MACX_(__NR_sem_wait_nocancel, sys_sem_wait_nocancel), // 420
+// _____(__NR_aio_suspend_nocancel),
+// _____(__NR___sigwait_nocancel),
+   MACX_(__NR___semwait_signal_nocancel, sys___semwait_signal), 
+// _____(__NR___mac_mount),
+// _____(__NR___mac_get_mount),
+// _____(__NR___mac_getfsstat),
+// _____(__NR_MAXSYSCALL)
+   MACX_(__NR_DARWIN_FAKE_SIGRETURN, sys_FAKE_SIGRETURN)
+};
+
+
+// Mach traps use negative syscall numbers. 
+// Use ML_(mach_trap_table)[-mach_trap_number] .
+
+const SyscallTableEntry ML_(mach_trap_table)[] = {
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(0)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(1)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(2)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(3)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(4)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(5)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(6)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(7)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(8)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(9)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(10)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(11)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(12)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(13)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(14)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(15)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(16)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(17)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(18)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(19)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(20)),   // -20
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(21)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(22)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(23)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(24)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(25)), 
+   MACXY(__NR_mach_reply_port, mach_reply_port), 
+   MACXY(__NR_thread_self_trap, mach_thread_self), 
+   MACXY(__NR_task_self_trap, mach_task_self), 
+   MACXY(__NR_host_self_trap, mach_host_self), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(30)), 
+   MACXY(__NR_mach_msg_trap, mach_msg), 
+// _____(__NR_mach_msg_overwrite_trap), 
+   MACX_(__NR_semaphore_signal_trap, semaphore_signal), 
+   MACX_(__NR_semaphore_signal_all_trap, semaphore_signal_all), 
+   MACX_(__NR_semaphore_signal_thread_trap, semaphore_signal_thread), 
+   MACX_(__NR_semaphore_wait_trap, semaphore_wait), 
+   MACX_(__NR_semaphore_wait_signal_trap, semaphore_wait_signal), 
+   MACX_(__NR_semaphore_timedwait_trap, semaphore_timedwait), 
+   MACX_(__NR_semaphore_timedwait_signal_trap, semaphore_timedwait_signal), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(40)),    // -40
+#if defined(VGA_x86)
+// _____(__NR_init_process), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(42)), 
+// _____(__NR_map_fd), 
+#else
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(41)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(42)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(43)), 
+#endif
+// _____(__NR_task_name_for_pid), 
+   MACXY(__NR_task_for_pid, task_for_pid), 
+   MACXY(__NR_pid_for_task, pid_for_task), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(47)), 
+#if defined(VGA_x86)
+// _____(__NR_macx_swapon), 
+// _____(__NR_macx_swapoff), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(50)), 
+// _____(__NR_macx_triggers), 
+// _____(__NR_macx_backing_store_suspend), 
+// _____(__NR_macx_backing_store_recovery), 
+#else
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(48)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(49)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(50)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(51)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(52)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(53)), 
+#endif
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(54)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(55)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(56)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(57)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(58)), 
+   MACX_(__NR_swtch_pri, swtch_pri), 
+   MACX_(__NR_swtch, swtch),   // -60
+   MACX_(__NR_syscall_thread_switch, syscall_thread_switch), 
+// _____(__NR_clock_sleep_trap), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(63)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(64)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(65)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(66)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(67)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(68)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(69)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(70)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(71)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(72)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(73)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(74)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(75)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(76)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(77)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(78)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(79)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(80)),   // -80
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(81)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(82)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(83)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(84)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(85)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(86)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(87)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(88)), 
+   MACXY(__NR_mach_timebase_info, mach_timebase_info), 
+   MACX_(__NR_mach_wait_until, mach_wait_until), 
+   MACXY(__NR_mk_timer_create, mk_timer_create), 
+   MACXY(__NR_mk_timer_destroy, mk_timer_destroy), 
+   MACX_(__NR_mk_timer_arm, mk_timer_arm), 
+   MACXY(__NR_mk_timer_cancel, mk_timer_cancel), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(95)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(96)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(97)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(98)), 
+   _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(99)), 
+   MACXY(__NR_iokit_user_client_trap, iokit_user_client_trap), // -100
+};
+
+
+// Machine-dependent traps have wacky syscall numbers, and use the Mach trap 
+// calling convention instead of the syscall convention.
+// Use ML_(mdep_trap_table)[syscallno - ML_(mdep_trap_base)] .
+
+#if defined(VGA_x86)
+const SyscallTableEntry ML_(mdep_trap_table)[] = {
+   MACX_(__NR_pthread_set_self, pthread_set_self), 
+};
+#elif defined(VGA_amd64)
+const SyscallTableEntry ML_(mdep_trap_table)[] = {
+   MACX_(__NR_pthread_set_self, pthread_set_self), 
+};
+#else
+#error unknown architecture
+#endif
+
+const UInt ML_(syscall_table_size) = 
+            sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);
+
+const UInt ML_(mach_trap_table_size) = 
+            sizeof(ML_(mach_trap_table)) / sizeof(ML_(mach_trap_table)[0]);
+
+const UInt ML_(mdep_trap_table_size) = 
+            sizeof(ML_(mdep_trap_table)) / sizeof(ML_(mdep_trap_table)[0]);
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                         syswrap-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 67a6628..a34ccb9 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -45,6 +45,7 @@
 #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_scheduler.h"
@@ -228,6 +229,7 @@
 
 
 
+#if HAVE_MREMAP
 /* Expand (or shrink) an existing mapping, potentially moving it at
    the same time (controlled by the MREMAP_MAYMOVE flag).  Nightmare.
 */
@@ -502,6 +504,7 @@
 
 #  undef MIN_SIZET
 }
+#endif /* HAVE_MREMAP */
 
 
 /* ---------------------------------------------------------------------
@@ -759,6 +762,7 @@
 void VG_(init_preopened_fds)(void)
 {
 // Nb: AIX5 is handled in syswrap-aix5.c.
+// DDD: should probably use HAVE_PROC here or similar, instead.
 #if defined(VGO_linux)
    Int ret;
    struct vki_dirent d;
@@ -793,6 +797,9 @@
   out:
    VG_(close)(sr_Res(f));
 
+#elif defined(VGO_darwin)
+   init_preopened_fds_without_proc_self_fd();
+
 #else
 #  error Unknown OS
 #endif
@@ -905,6 +912,7 @@
    }
 }
 
+/* GrP kernel ignores sa_len (at least on Darwin); this checks the rest */
 static
 void pre_mem_read_sockaddr ( ThreadId tid,
                              Char *description,
@@ -929,6 +937,7 @@
       case VKI_AF_UNIX:
          VG_(sprintf) ( outmsg, description, "sun_path" );
          PRE_MEM_RASCIIZ( outmsg, (Addr) sun->sun_path );
+         // GrP fixme max of sun_len-2? what about nul char?
          break;
                      
       case VKI_AF_INET:
@@ -1576,6 +1585,7 @@
    union vki_semun arg = *(union vki_semun *)&arg3;
    UInt nsems;
    switch (arg2 /* cmd */) {
+#if defined(VKI_IPC_INFO)
    case VKI_IPC_INFO:
    case VKI_SEM_INFO:
    case VKI_IPC_INFO|VKI_IPC_64:
@@ -1583,32 +1593,51 @@
       PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)",
                      (Addr)arg.buf, sizeof(struct vki_seminfo) );
       break;
+#endif
+
    case VKI_IPC_STAT:
+#if defined(VKI_SEM_STAT)
    case VKI_SEM_STAT:
+#endif
       PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
                      (Addr)arg.buf, sizeof(struct vki_semid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_STAT|VKI_IPC_64:
+#if defined(VKI_SEM_STAT)
    case VKI_SEM_STAT|VKI_IPC_64:
+#endif
       PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
                      (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
+#endif
+
    case VKI_IPC_SET:
       PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
                     (Addr)arg.buf, sizeof(struct vki_semid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_SET|VKI_IPC_64:
       PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
                     (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
+#endif
+
    case VKI_GETALL:
+#if defined(VKI_IPC_64)
    case VKI_GETALL|VKI_IPC_64:
+#endif
       nsems = get_sem_count( arg0 );
       PRE_MEM_WRITE( "semctl(IPC_GETALL, arg.array)",
                      (Addr)arg.array, sizeof(unsigned short) * nsems );
       break;
+
    case VKI_SETALL:
+#if defined(VKI_IPC_64)
    case VKI_SETALL|VKI_IPC_64:
+#endif
       nsems = get_sem_count( arg0 );
       PRE_MEM_READ( "semctl(IPC_SETALL, arg.array)",
                     (Addr)arg.array, sizeof(unsigned short) * nsems );
@@ -1625,22 +1654,33 @@
    union vki_semun arg = *(union vki_semun *)&arg3;
    UInt nsems;
    switch (arg2 /* cmd */) {
+#if defined(VKI_IPC_INFO)
    case VKI_IPC_INFO:
    case VKI_SEM_INFO:
    case VKI_IPC_INFO|VKI_IPC_64:
    case VKI_SEM_INFO|VKI_IPC_64:
       POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_seminfo) );
       break;
+#endif
+
    case VKI_IPC_STAT:
+#if defined(VKI_SEM_STAT)
    case VKI_SEM_STAT:
+#endif
       POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_STAT|VKI_IPC_64:
    case VKI_SEM_STAT|VKI_IPC_64:
       POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
       break;
+#endif
+
    case VKI_GETALL:
+#if defined(VKI_IPC_64)
    case VKI_GETALL|VKI_IPC_64:
+#endif
       nsems = get_sem_count( arg0 );
       POST_MEM_WRITE( (Addr)arg.array, sizeof(unsigned short) * nsems );
       break;
@@ -1765,37 +1805,56 @@
 {
    /* int shmctl(int shmid, int cmd, struct shmid_ds *buf); */
    switch (arg1 /* cmd */) {
+#if defined(VKI_IPC_INFO)
    case VKI_IPC_INFO:
       PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
                      arg2, sizeof(struct vki_shminfo) );
       break;
+#if defined(VKI_IPC_64)
    case VKI_IPC_INFO|VKI_IPC_64:
       PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
                      arg2, sizeof(struct vki_shminfo64) );
       break;
+#endif
+#endif
+
+#if defined(VKI_SHM_INFO)
    case VKI_SHM_INFO:
+#if defined(VKI_IPC_64)
    case VKI_SHM_INFO|VKI_IPC_64:
+#endif
       PRE_MEM_WRITE( "shmctl(SHM_INFO, buf)",
                      arg2, sizeof(struct vki_shm_info) );
       break;
+#endif
+
    case VKI_IPC_STAT:
+#if defined(VKI_SHM_STAT)
    case VKI_SHM_STAT:
+#endif
       PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)",
                      arg2, sizeof(struct vki_shmid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_STAT|VKI_IPC_64:
    case VKI_SHM_STAT|VKI_IPC_64:
       PRE_MEM_WRITE( "shmctl(IPC_STAT, arg.buf)",
                      arg2, sizeof(struct vki_shmid64_ds) );
       break;
+#endif
+
    case VKI_IPC_SET:
       PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
                     arg2, sizeof(struct vki_shmid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_SET|VKI_IPC_64:
       PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
                     arg2, sizeof(struct vki_shmid64_ds) );
       break;
+#endif
    }
 }
 
@@ -1805,24 +1864,37 @@
                                UWord arg0, UWord arg1, UWord arg2 )
 {
    switch (arg1 /* cmd */) {
+#if defined(VKI_IPC_INFO)
    case VKI_IPC_INFO:
       POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo) );
       break;
    case VKI_IPC_INFO|VKI_IPC_64:
       POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo64) );
       break;
+#endif
+
+#if defined(VKI_SHM_INFO)
    case VKI_SHM_INFO:
    case VKI_SHM_INFO|VKI_IPC_64:
       POST_MEM_WRITE( arg2, sizeof(struct vki_shm_info) );
       break;
+#endif
+
    case VKI_IPC_STAT:
+#if defined(VKI_SHM_STAT)
    case VKI_SHM_STAT:
+#endif
       POST_MEM_WRITE( arg2, sizeof(struct vki_shmid_ds) );
       break;
+
+#if defined(VKI_IPC_64)
    case VKI_IPC_STAT|VKI_IPC_64:
    case VKI_SHM_STAT|VKI_IPC_64:
       POST_MEM_WRITE( arg2, sizeof(struct vki_shmid64_ds) );
       break;
+#endif
+
+
    }
 }
 
@@ -1866,6 +1938,16 @@
    MapRequest mreq;
    Bool       mreq_ok;
 
+#if defined(VGO_darwin)
+   // Nb: we can't use this on Darwin, it has races:
+   // * needs to RETRY if advisory succeeds but map fails  
+   //   (could have been some other thread in a nonblocking call)
+   // * needs to not use fixed-position mmap() on Darwin
+   //   (mmap will cheerfully smash whatever's already there, which might 
+   //   be a new mapping from some other thread in a nonblocking call)
+   VG_(core_panic)("can't use ML_(generic_PRE_sys_mmap) on Darwin");
+#endif
+
    if (arg2 == 0) {
       /* SuSV3 says: If len is zero, mmap() shall fail and no mapping
          shall be established. */
@@ -2004,6 +2086,7 @@
 #if VG_WORDSIZE == 4
 // Combine two 32-bit values into a 64-bit value
 // Always use with low-numbered arg first (e.g. LOHI64(ARG1,ARG2) )
+// GrP fixme correct for ppc-linux?
 #define LOHI64(lo,hi)   ( ((ULong)(lo)) | (((ULong)(hi)) << 32) )
 #endif
 
@@ -2023,8 +2106,17 @@
 
 PRE(sys_ni_syscall)
 {
-   // Nb: AIX5 is handled in syswrap-aix5.c.
-   PRINT("non-existent syscall! (ni_syscall)");
+   PRINT("unimplemented (by the kernel) syscall %ld! (ni_syscall)\n",
+// Nb: AIX5 is handled in syswrap-aix5.c.
+// DDD: make this generic
+#if defined(VGO_linux)
+      SYSNO
+#elif defined(VGO_darwin)
+      VG_DARWIN_SYSNO_PRINT(SYSNO)
+#else
+#  error Unknown OS
+#endif
+   );
    PRE_REG_READ0(long, "ni_syscall");
    SET_STATUS_Failure( VKI_ENOSYS );
 }
@@ -2130,6 +2222,7 @@
    PRE_timeval_WRITE( "getitimer(&value->it_interval)", &(value->it_interval));
    PRE_timeval_WRITE( "getitimer(&value->it_value)",    &(value->it_value));
 }
+
 POST(sys_getitimer)
 {
    if (ARG2 != (Addr)NULL) {
@@ -2185,6 +2278,7 @@
                  unsigned long, start, vki_size_t, length, int, advice);
 }
 
+#if HAVE_MREMAP
 PRE(sys_mremap)
 {
    // Nb: this is different to the glibc version described in the man pages,
@@ -2207,6 +2301,7 @@
       do_mremap((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid) 
    );
 }
+#endif /* HAVE_MREMAP */
 
 PRE(sys_nice)
 {
@@ -2811,9 +2906,17 @@
 
    if (!SUCCESS) return;
 
+#if defined(VGO_linux) || defined(VGO_aix5)
    // RES is 0 for child, non-0 (the child's PID) for parent.
    is_child = ( RES == 0 ? True : False );
    child_pid = ( is_child ? -1 : RES );
+#elif defined(VGO_darwin)
+   // RES is the child's pid.  RESHI is 1 for child, 0 for parent.
+   is_child = RESHI;
+   child_pid = RES;
+#else
+#  error Unknown OS
+#endif
 
    VG_(do_atfork_pre)(tid);
 
@@ -2830,7 +2933,7 @@
       if (!VG_(logging_to_socket) && VG_(clo_child_silent_after_fork))
          VG_(clo_log_fd) = -1;
 
-   } else { 
+   } else {
       VG_(do_atfork_parent)(tid);
 
       PRINT("   fork: process %d created child %d\n", VG_(getpid)(), child_pid);
@@ -3002,6 +3105,12 @@
 {
    POST_MEM_WRITE( a2, sizeof(struct vki_rlimit) );
 
+#ifdef _RLIMIT_POSIX_FLAG
+   // Darwin will sometimes set _RLIMIT_POSIX_FLAG on getrlimit calls.
+   // Unset it here to make the switch case below work correctly.
+   a1 &= ~_RLIMIT_POSIX_FLAG;
+#endif
+
    switch (a1) {
    case VKI_RLIMIT_NOFILE:
       ((struct vki_rlimit *)a2)->rlim_cur = VG_(fd_soft_limit);
@@ -3063,6 +3172,7 @@
    PRINT("sys_gettimeofday ( %#lx, %#lx )", ARG1,ARG2);
    PRE_REG_READ2(long, "gettimeofday",
                  struct timeval *, tv, struct timezone *, tz);
+   // GrP fixme does darwin write to *tz anymore?
    if (ARG1 != 0)
       PRE_timeval_WRITE( "gettimeofday(tv)", ARG1 );
    if (ARG2 != 0)
@@ -3286,6 +3396,7 @@
    if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mprotect")) {
       SET_STATUS_Failure( VKI_ENOMEM );
    } 
+#if defined(VKI_PROT_GROWSDOWN)
    else 
    if (ARG3 & (VKI_PROT_GROWSDOWN|VKI_PROT_GROWSUP)) {
       /* Deal with mprotects on growable stack areas.
@@ -3337,6 +3448,7 @@
          SET_STATUS_Failure( VKI_EINVAL );
       }
    }
+#endif   // defined(VKI_PROT_GROWSDOWN)
 }
 
 POST(sys_mprotect)
@@ -3412,6 +3524,7 @@
    }
    PRE_MEM_RASCIIZ( "open(filename)", ARG1 );
 
+#if HAVE_PROC
    /* Handle the case where the open is of /proc/self/cmdline or
       /proc/<pid>/cmdline, and just give it a copy of the fd for the
       fake file we cooked up at startup (in m_main).  Also, seek the
@@ -3436,6 +3549,7 @@
          return;
       }
    }
+#endif // HAVE_PROC
 
    /* Otherwise handle normally */
    *flags |= SfMayBlock;
@@ -3558,6 +3672,7 @@
    PRE_MEM_WRITE( "readlink(buf)", ARG2,ARG3 );
 
    {
+#if HAVE_PROC
       /*
        * Handle the case where readlink is looking at /proc/self/exe or
        * /proc/<pid>/exe.
@@ -3573,6 +3688,7 @@
          SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name, 
                                                          ARG2, ARG3));
       } else
+#endif // HAVE_PROC
       {
          /* Normal case */
          SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, ARG1, ARG2, ARG3));
@@ -3703,12 +3819,19 @@
 
 PRE(sys_setrlimit)
 {
+   UWord arg1 = ARG1;
    PRINT("sys_setrlimit ( %ld, %#lx )", ARG1,ARG2);
    PRE_REG_READ2(long, "setrlimit",
                  unsigned int, resource, struct rlimit *, rlim);
    PRE_MEM_READ( "setrlimit(rlim)", ARG2, sizeof(struct vki_rlimit) );
 
-   if (ARG1 == VKI_RLIMIT_NOFILE) {
+#ifdef _RLIMIT_POSIX_FLAG
+   // Darwin will sometimes set _RLIMIT_POSIX_FLAG on setrlimit calls.
+   // Unset it here to make the if statements below work correctly.
+   arg1 &= ~_RLIMIT_POSIX_FLAG;
+#endif
+
+   if (arg1 == VKI_RLIMIT_NOFILE) {
       if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(fd_hard_limit) ||
           ((struct vki_rlimit *)ARG2)->rlim_max != VG_(fd_hard_limit)) {
          SET_STATUS_Failure( VKI_EPERM );
@@ -3718,7 +3841,7 @@
          SET_STATUS_Success( 0 );
       }
    }
-   else if (ARG1 == VKI_RLIMIT_DATA) {
+   else if (arg1 == VKI_RLIMIT_DATA) {
       if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(client_rlimit_data).rlim_max ||
           ((struct vki_rlimit *)ARG2)->rlim_max > VG_(client_rlimit_data).rlim_max) {
          SET_STATUS_Failure( VKI_EPERM );
@@ -3728,7 +3851,7 @@
          SET_STATUS_Success( 0 );
       }
    }
-   else if (ARG1 == VKI_RLIMIT_STACK && tid == 1) {
+   else if (arg1 == VKI_RLIMIT_STACK && tid == 1) {
       if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(client_rlimit_stack).rlim_max ||
           ((struct vki_rlimit *)ARG2)->rlim_max > VG_(client_rlimit_stack).rlim_max) {
          SET_STATUS_Failure( VKI_EPERM );
@@ -3927,7 +4050,6 @@
       PRE_timeval_READ( "utimes(tvp[0])", ARG2 );
       PRE_timeval_READ( "utimes(tvp[1])", ARG2+sizeof(struct vki_timeval) );
    }
-
 }
 
 PRE(sys_acct)
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index cc6166b..8238cb5 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -29,6 +29,7 @@
 */
 
 #include "libvex_guest_offsets.h"
+#include "libvex_trc_values.h"
 #include "pub_core_basics.h"
 #include "pub_core_aspacemgr.h"
 #include "pub_core_vki.h"
@@ -52,6 +53,9 @@
 #include "priv_types_n_macros.h"
 #include "priv_syswrap-main.h"
 
+#if defined(VGO_darwin)
+#include "priv_syswrap-darwin.h"
+#endif
 
 /* Useful info which needs to be recorded somewhere:
    Use of registers in syscalls is:
@@ -62,9 +66,19 @@
    amd64  rax rdi  rsi  rdx  r10  r8   r9   n/a  n/a  rax       (== NUM)
    ppc32  r0  r3   r4   r5   r6   r7   r8   n/a  n/a  r3+CR0.SO (== ARG1)
    ppc64  r0  r3   r4   r5   r6   r7   r8   n/a  n/a  r3+CR0.SO (== ARG1)
+
    AIX:
    ppc32  r2  r3   r4   r5   r6   r7   r8   r9   r10  r3(res),r4(err)
    ppc64  r2  r3   r4   r5   r6   r7   r8   r9   r10  r3(res),r4(err)
+
+   DARWIN:
+   x86    eax +4   +8   +12  +16  +20  +24  +28  +32  edx:eax, eflags.c
+   amd64  rax rdi  rsi  rdx  rcx  r8   r9   +8   +16  rdx:rax, rflags.c
+
+   For x86-darwin, "+N" denotes "in memory at N(%esp)"; ditto
+   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".
 */
 
 /* This is the top level of the system-call handler module.  All
@@ -141,6 +155,10 @@
      ppc32:  Success(N) ==>  r3 = N, CR0.SO = 0
              Fail(N) ==>     r3 = N, CR0.SO = 1
 
+     Darwin:
+     x86:    Success(N) ==>  edx:eax = N, cc = 0
+             Fail(N)    ==>  edx:eax = N, cc = 1
+
    * The post wrapper is called if:
 
      - it exists, and
@@ -255,6 +273,25 @@
                                       const vki_sigset_t *restore_mask,
                                       Word sigsetSzB, /* unused */
                                       Word __nr_sigprocmask );
+#elif defined(VGO_darwin)
+extern
+UWord ML_(do_syscall_for_client_unix_WRK)( Word syscallno, 
+                                           void* guest_state,
+                                           const vki_sigset_t *syscall_mask,
+                                           const vki_sigset_t *restore_mask,
+                                           Word sigsetSzB ); /* unused */
+extern
+UWord ML_(do_syscall_for_client_mach_WRK)( Word syscallno, 
+                                           void* guest_state,
+                                           const vki_sigset_t *syscall_mask,
+                                           const vki_sigset_t *restore_mask,
+                                           Word sigsetSzB ); /* unused */
+extern
+UWord ML_(do_syscall_for_client_mdep_WRK)( Word syscallno, 
+                                           void* guest_state,
+                                           const vki_sigset_t *syscall_mask,
+                                           const vki_sigset_t *restore_mask,
+                                           Word sigsetSzB ); /* unused */
 #else
 #  error "Unknown OS"
 #endif
@@ -278,6 +315,31 @@
             syscall_mask, &saved, 0/*unused:sigsetSzB*/,
             __NR_rt_sigprocmask
          );
+#  elif defined(VGO_darwin)
+   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         err = ML_(do_syscall_for_client_unix_WRK)(
+                  VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex, 
+                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
+               );
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         err = ML_(do_syscall_for_client_mach_WRK)(
+                  VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex, 
+                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
+               );
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         err = ML_(do_syscall_for_client_mdep_WRK)(
+                  VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex, 
+                  syscall_mask, &saved, 0/*unused:sigsetSzB*/
+               );
+         break;
+      default:
+         vg_assert(0);
+         /*NOTREACHED*/
+         break;
+   }
 #  else
 #    error "Unknown OS"
 #  endif
@@ -313,6 +375,14 @@
    /* was: return s1->what == s2->what && sr_EQ( s1->sres, s2->sres ); */
    if (s1->what == s2->what && sr_EQ( s1->sres, s2->sres ))
       return True;
+#  if defined(VGO_darwin)
+   /* Darwin-specific debugging guff */
+   vg_assert(s1->what == s2->what);
+   VG_(printf)("eq_SyscallStatus:\n");
+   VG_(printf)("  {%lu %lu %u}\n", s1->sres._wLO, s1->sres._wHI, s1->sres._mode);
+   VG_(printf)("  {%lu %lu %u}\n", s2->sres._wLO, s2->sres._wHI, s2->sres._mode);
+   vg_assert(0);
+#  endif
    return False;
 }
 
@@ -334,7 +404,8 @@
 
 static 
 void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs*       canonical,
-                                    /*IN*/ VexGuestArchState* gst_vanilla )
+                                    /*IN*/ VexGuestArchState* gst_vanilla, 
+                                    /*IN*/ UInt trc )
 {
 #if defined(VGP_x86_linux)
    VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
@@ -411,6 +482,120 @@
    canonical->arg7  = gst->guest_GPR9;
    canonical->arg8  = gst->guest_GPR10;
 
+#elif defined(VGP_x86_darwin)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_ESP;
+   // GrP fixme hope syscalls aren't called with really shallow stacks...
+   canonical->sysno = gst->guest_EAX;
+   if (canonical->sysno != 0) {
+      // stack[0] is 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];
+   } else {
+      // GrP fixme hack handle syscall()
+      // GrP fixme what about __syscall() ?
+      // stack[0] is return address
+      // DDD: the tool can't see that the params have been shifted!  Can
+      //      lead to incorrect checking, I think, because the PRRAn/PSARn
+      //      macros will mention the pre-shifted args.
+      canonical->sysno = stack[1];
+      vg_assert(canonical->sysno != 0);
+      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  = stack[9];
+      
+      PRINT("SYSCALL[%d,?](%3lld) syscall(#%ld, ...); please stand by...\n",
+            VG_(getpid)(), /*tid,*/ (Long)0, canonical->sysno);
+   }
+
+   // DDD: Would it be better to stash the JMP kind into the Darwin
+   // thread state rather than passing in the trc?
+   switch (trc) {
+   case VEX_TRC_JMP_SYS_INT128:
+      // int $0x80 = Unix, 64-bit result
+      vg_assert(canonical->sysno >= 0);
+      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno);
+      break;
+   case VEX_TRC_JMP_SYS_SYSENTER:
+      // syscall = Unix, 32-bit result
+      // OR        Mach, 32-bit result
+      if (canonical->sysno >= 0) {
+         // GrP fixme hack  I386_SYSCALL_NUMBER_MASK
+         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno
+                                                             & 0xffff);
+      } else {
+         canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
+      }
+      break;
+   case VEX_TRC_JMP_SYS_INT129:
+      // int $0x81 = Mach, 32-bit result
+      vg_assert(canonical->sysno < 0);
+      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
+      break;
+   case VEX_TRC_JMP_SYS_INT130:
+      // int $0x82 = mdep, 32-bit result
+      vg_assert(canonical->sysno >= 0);
+      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(canonical->sysno);
+      break;
+   default: 
+      vg_assert(0);
+      break;
+   }
+   
+#elif defined(VGP_amd64_darwin)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_RSP;
+
+   vg_assert(trc == VEX_TRC_JMP_SYS_SYSCALL);
+
+   // GrP fixme hope syscalls aren't called with really shallow stacks...
+   canonical->sysno = gst->guest_RAX;
+   if (canonical->sysno != __NR_syscall) {
+      // stack[0] is 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 insn
+      canonical->arg5  = gst->guest_R8;
+      canonical->arg6  = gst->guest_R9;
+      canonical->arg7  = stack[1];
+      canonical->arg8  = stack[2];
+   } else {
+      // GrP fixme hack handle syscall()
+      // GrP fixme what about __syscall() ?
+      // stack[0] is return address
+      // DDD: the tool can't see that the params have been shifted!  Can
+      //      lead to incorrect checking, I think, because the PRRAn/PSARn
+      //      macros will mention the pre-shifted args.
+      canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(gst->guest_RDI);
+      vg_assert(canonical->sysno != __NR_syscall);
+      canonical->arg1  = gst->guest_RSI;
+      canonical->arg2  = gst->guest_RDX;
+      canonical->arg3  = gst->guest_R10;  // not rcx with syscall insn
+      canonical->arg4  = gst->guest_R8;
+      canonical->arg5  = gst->guest_R9;
+      canonical->arg6  = stack[1];
+      canonical->arg7  = stack[2];
+      canonical->arg8  = stack[3];
+      
+      PRINT("SYSCALL[%d,?](%3lld) syscall(#%lx, ...); please stand by...\n",
+            VG_(getpid)(), /*tid,*/ (Long)0,
+            VG_DARWIN_SYSNO_PRINT(canonical->sysno));
+   }
+
+   // no canonical->sysno adjustment needed
+
 #else
 #  error "getSyscallArgsFromGuestState: unknown arch"
 #endif
@@ -484,6 +669,40 @@
    gst->guest_GPR9  = canonical->arg7;
    gst->guest_GPR10 = canonical->arg8;
 
+#elif defined(VGP_x86_darwin)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_ESP;
+
+   gst->guest_EAX = VG_DARWIN_SYSNO_NUM(canonical->sysno);
+
+   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
+   // stack[0] is 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_darwin)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   UWord *stack = (UWord *)gst->guest_RSP;
+
+   gst->guest_RAX = VG_DARWIN_SYSNO_NUM(canonical->sysno);
+   // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
+
+   // stack[0] is return address
+   gst->guest_RDI = canonical->arg1;
+   gst->guest_RSI = canonical->arg2;
+   gst->guest_RDX = canonical->arg3;
+   gst->guest_RCX = 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
@@ -529,13 +748,77 @@
                                                 gst->guest_GPR4 );
    canonical->what = SsComplete;
 
+#  elif defined(VGP_x86_darwin)
+   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   UInt carry = 1 & LibVEX_GuestX86_get_eflags(gst);
+   UInt err = 0;
+   UInt wLO = 0;
+   UInt wHI = 0;
+   switch (gst->guest_SC_CLASS) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         // int $0x80 = Unix, 64-bit result
+         err = carry;
+         wLO = gst->guest_EAX;
+         wHI = gst->guest_EDX;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         // int $0x81 = Mach, 32-bit result
+         wLO = gst->guest_EAX;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         // int $0x82 = mdep, 32-bit result
+         wLO = gst->guest_EAX;
+         break;
+      default: 
+         vg_assert(0);
+         break;
+   }
+   canonical->sres = VG_(mk_SysRes_x86_darwin)(
+                        gst->guest_SC_CLASS, err ? True : False, 
+                        wHI, wLO
+                     );
+   canonical->what = SsComplete;
+
+#  elif defined(VGP_amd64_darwin)
+   /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   ULong carry = 1 & LibVEX_GuestAMD64_get_rflags(gst);
+   ULong err = 0;
+   ULong wLO = 0;
+   ULong wHI = 0;
+   switch (gst->guest_SC_CLASS) {
+      case VG_DARWIN_SYSCALL_CLASS_UNIX:
+         // syscall = Unix, 128-bit result
+         err = carry;
+         wLO = gst->guest_RAX;
+         wHI = gst->guest_RDX;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MACH:
+         // syscall = Mach, 64-bit result
+         wLO = gst->guest_RAX;
+         break;
+      case VG_DARWIN_SYSCALL_CLASS_MDEP:
+         // syscall = mdep, 64-bit result
+         wLO = gst->guest_RAX;
+         break;
+      default: 
+         vg_assert(0);
+         break;
+   }
+   canonical->sres = VG_(mk_SysRes_amd64_darwin)(
+                        gst->guest_SC_CLASS, err ? True : False, 
+                        wHI, wLO
+                     );
+   canonical->what = SsComplete;
+
 #  else
 #    error "getSyscallStatusFromGuestState: unknown arch"
 #  endif
 }
 
 static 
-void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
+void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid, 
                                       /*IN*/ SyscallStatus*     canonical,
                                       /*OUT*/VexGuestArchState* gst_vanilla )
 {
@@ -623,6 +906,72 @@
    VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
              OFFSET_ppc64_GPR4, sizeof(UWord) );
 
+#elif defined(VGP_x86_darwin)
+   VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+   SysRes sres = canonical->sres;
+   vg_assert(canonical->what == SsComplete);
+   /* Unfortunately here we have to break abstraction and look
+      directly inside 'res', in order to decide what to do. */
+   switch (sres._mode) {
+      case SysRes_MACH: // int $0x81 = Mach, 32-bit result
+      case SysRes_MDEP: // int $0x82 = mdep, 32-bit result
+         gst->guest_EAX = sres._wLO;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_x86_EAX, sizeof(UInt) );
+         break;
+      case SysRes_UNIX_OK:  // int $0x80 = Unix, 64-bit result
+      case SysRes_UNIX_ERR: // int $0x80 = Unix, 64-bit error
+         gst->guest_EAX = sres._wLO;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_x86_EAX, sizeof(UInt) );
+         gst->guest_EDX = sres._wHI;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_x86_EDX, sizeof(UInt) );
+         LibVEX_GuestX86_put_eflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
+                                      gst );
+         // GrP fixme sets defined for entire eflags, not just bit c
+         // DDD: this breaks exp-ptrcheck.
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UInt) );
+         break;
+      default: 
+         vg_assert(0);
+         break;
+   }
+   
+#elif defined(VGP_amd64_darwin)
+   VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+   SysRes sres = canonical->sres;
+   vg_assert(canonical->what == SsComplete);
+   /* Unfortunately here we have to break abstraction and look
+      directly inside 'res', in order to decide what to do. */
+   switch (sres._mode) {
+      case SysRes_MACH: // syscall = Mach, 64-bit result
+      case SysRes_MDEP: // syscall = mdep, 64-bit result
+         gst->guest_RAX = sres._wLO;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_amd64_RAX, sizeof(ULong) );
+         break;
+      case SysRes_UNIX_OK:  // syscall = Unix, 128-bit result
+      case SysRes_UNIX_ERR: // syscall = Unix, 128-bit error
+         gst->guest_RAX = sres._wLO;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_amd64_RAX, sizeof(ULong) );
+         gst->guest_RDX = sres._wHI;
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   OFFSET_amd64_RDX, sizeof(ULong) );
+         LibVEX_GuestAMD64_put_rflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
+                                        gst );
+         // GrP fixme sets defined for entire rflags, not just bit c
+         // DDD: this breaks exp-ptrcheck.
+         VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, 
+                   offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) );
+         break;
+      default: 
+         vg_assert(0);
+         break;
+   }
+   
 #  else
 #    error "putSyscallStatusIntoGuestState: unknown arch"
 #  endif
@@ -702,6 +1051,29 @@
    layout->o_arg7   = OFFSET_ppc64_GPR9;
    layout->o_arg8   = OFFSET_ppc64_GPR10;
 
+#elif defined(VGP_x86_darwin)
+   layout->o_sysno  = OFFSET_x86_EAX;
+   // syscall parameters are on stack in C convention
+   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_darwin)
+   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_RCX;
+   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
@@ -723,11 +1095,20 @@
                   /*OUT*/UWord*         flags )
 {
    VG_(message)
-      (Vg_DebugMsg,"WARNING: unhandled syscall: %llu", (ULong)args->sysno);
-#  if defined(VGO_aix5)
+      (Vg_DebugMsg,"WARNING: unhandled syscall: %lld", (Long)args->sysno);
+   // DDD: make this generic with a common function.
+#  if defined(VGO_linux)
+   // nothing
+#  elif defined(VGO_aix5)
    VG_(message)
       (Vg_DebugMsg,"           name of syscall: \"%s\"",
                     VG_(aix5_sysno_to_sysname)(args->sysno));
+#  elif defined(VGO_darwin)
+   VG_(message)
+      (Vg_DebugMsg,"           a.k.a.: %lld",
+                    (Long)VG_DARWIN_SYSNO_PRINT(args->sysno));
+#  else
+#     error unknown OS
 #  endif
    if (VG_(clo_verbosity) > 1) {
       VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
@@ -747,7 +1128,7 @@
 static SyscallTableEntry bad_sys =
    { bad_before, NULL };
 
-static const SyscallTableEntry* get_syscall_entry ( UInt syscallno )
+static const SyscallTableEntry* get_syscall_entry ( Int syscallno )
 {
    const SyscallTableEntry* sys = NULL;
 
@@ -762,6 +1143,30 @@
 #  elif defined(VGP_ppc64_aix5)
    sys = ML_(get_ppc64_aix5_syscall_entry) ( syscallno );
 
+#  elif defined(VGO_darwin)
+   Int idx = VG_DARWIN_SYSNO_INDEX(syscallno);
+
+   switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
+   case VG_DARWIN_SYSCALL_CLASS_UNIX:
+      if (idx >= 0 && idx < ML_(syscall_table_size) &&
+          ML_(syscall_table)[idx].before != NULL)
+         sys = &ML_(syscall_table)[idx];
+         break;
+   case VG_DARWIN_SYSCALL_CLASS_MACH:
+      if (idx >= 0 && idx < ML_(mach_trap_table_size) &&
+          ML_(mach_trap_table)[idx].before != NULL)
+         sys = &ML_(mach_trap_table)[idx];
+         break;
+   case VG_DARWIN_SYSCALL_CLASS_MDEP:
+      if (idx >= 0 && idx < ML_(mdep_trap_table_size) &&
+          ML_(mdep_trap_table)[idx].before != NULL)
+         sys = &ML_(mdep_trap_table)[idx];
+         break;
+   default: 
+      vg_assert(0);
+      break;
+   }
+
 #  else
 #    error Unknown OS
 #  endif
@@ -815,7 +1220,7 @@
 
 /* --- This is the main function of this file. --- */
 
-void VG_(client_syscall) ( ThreadId tid )
+void VG_(client_syscall) ( ThreadId tid, UInt trc )
 {
    Word                     sysno;
    ThreadState*             tst;
@@ -924,7 +1329,7 @@
    sci = & syscallInfo[tid];
    vg_assert(sci->status.what == SsIdle);
 
-   getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex );
+   getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex, trc );
 
    /* Copy .orig_args to .args.  The pre-handler may modify .args, but
       we want to keep the originals too, just in case. */
@@ -934,6 +1339,19 @@
       is interrupted by a signal. */
    sysno = sci->orig_args.sysno;
 
+#  if defined(VGO_darwin)
+   /* Record syscall class.  But why?  Because the syscall might be
+      interrupted by a signal, and in the signal handler (which will
+      be m_signals.async_signalhandler) we will need to build a SysRes
+      reflecting the syscall return result.  In order to do that we
+      need to know the syscall class.  Hence stash it in the guest
+      state of this thread.  This madness is not needed on Linux or
+      AIX5, because those OSs only have a single syscall return
+      convention and so there is no ambiguity involved in converting
+      the post-signal machine state into a SysRes. */
+   tst->arch.vex.guest_SC_CLASS = VG_DARWIN_SYSNO_CLASS(sysno);
+#  endif
+
    /* The default what-to-do-next thing is hand the syscall to the
       kernel, so we pre-set that here.  Set .sres to something
       harmless looking (is irrelevant because .what is not
@@ -967,7 +1385,16 @@
         sci->flags        is zero.
    */
 
-   PRINT("SYSCALL[%d,%d](%3lld) ", VG_(getpid)(), tid, (ULong)sysno);
+   PRINT("SYSCALL[%d,%d](%3lld) ", VG_(getpid)(), tid,
+   // DDD: make this generic
+   #if defined(VGO_linux) || defined(VGO_aix5)
+      (Long)sysno
+   #elif defined(VGO_darwin)
+      (Long)VG_DARWIN_SYSNO_PRINT(sysno)
+   #else
+   #  error Unknown OS
+   #endif
+   );
 
    /* Do any pre-syscall actions */
    if (VG_(needs).syscall_wrapper) {
@@ -1055,7 +1482,12 @@
 
          /* Gack.  More impedance matching.  Copy the possibly
             modified syscall args back into the guest state. */
-         vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
+         /* JRS 2009-Mar-16: if the syscall args are possibly modified,
+            then this assertion is senseless:
+              vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
+            The case that exposed it was sys_posix_spawn on Darwin,
+            which heavily modifies its arguments but then lets the call
+            go through anyway, with SfToBlock set, hence we end up here. */
          putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
 
          /* Drop the bigLock */
@@ -1077,6 +1509,13 @@
             VG_(post_syscall).  Once that's done, control drops back
             to the scheduler.  */
 
+         /* Darwin: do_syscall_for_client may not return if the 
+            syscall was workq_ops(WQOPS_THREAD_RETURN) and the kernel 
+            responded by starting the thread at wqthread_hijack(reuse=1)
+            (to run another workqueue item). In that case, wqthread_hijack 
+            calls ML_(wqthread_continue), which is similar to 
+            VG_(fixup_guest_state_after_syscall_interrupted). */
+
          /* Reacquire the lock */
          VG_(acquire_BigLock)(tid, "VG_(client_syscall)[async]");
 
@@ -1089,6 +1528,10 @@
          if (VG_(clo_trace_syscalls)) {
             Bool failed = sr_isError(sci->status.sres);
             Word tmp_sysno = sysno;
+#           if defined(VGO_darwin)
+            // DDD: genericise this
+            tmp_sysno = VG_DARWIN_SYSNO_PRINT(tmp_sysno);
+#           endif
             if (failed) {
                PRINT("SYSCALL[%d,%d](%3ld) ... [async] --> Failure(0x%llx)",
                      VG_(getpid)(), tid, tmp_sysno, 
@@ -1165,6 +1608,7 @@
    There are two ways to get here: the normal way -- being called by
    VG_(client_syscall), and the unusual way, from
    VG_(fixup_guest_state_after_syscall_interrupted).
+   Darwin: there's a third way, ML_(wqthread_continue). 
 */
 void VG_(post_syscall) (ThreadId tid)
 {
@@ -1198,6 +1642,15 @@
    getSyscallStatusFromGuestState( &test_status, &tst->arch.vex );
    if (!(sci->flags & SfNoWriteResult))
       vg_assert(eq_SyscallStatus( &sci->status, &test_status ));
+   /* Failure of the above assertion on Darwin can indicate a problem
+      in the syscall wrappers that pre-fail or pre-succeed the
+      syscall, by calling SET_STATUS_Success or SET_STATUS_Failure,
+      when they really should call SET_STATUS_from_SysRes.  The former
+      create a UNIX-class syscall result on Darwin, which may not be
+      correct for the syscall; if that's the case then this assertion
+      fires.  See PRE(pthread_set_self) for an example.  On non-Darwin
+      platforms this assertion is should never fail, and this comment
+      is completely irrelevant. */
    /* Ok, looks sane */
 
    /* Get the system call number.  Because the pre-handler isn't
@@ -1283,6 +1736,23 @@
   extern const Addr ML_(blksys_complete);
   extern const Addr ML_(blksys_committed);
   extern const Addr ML_(blksys_finished);
+#elif defined(VGO_darwin)
+  /* Darwin requires extra uglyness */
+  extern const Addr ML_(blksys_setup_MACH);
+  extern const Addr ML_(blksys_restart_MACH);
+  extern const Addr ML_(blksys_complete_MACH);
+  extern const Addr ML_(blksys_committed_MACH);
+  extern const Addr ML_(blksys_finished_MACH);
+  extern const Addr ML_(blksys_setup_MDEP);
+  extern const Addr ML_(blksys_restart_MDEP);
+  extern const Addr ML_(blksys_complete_MDEP);
+  extern const Addr ML_(blksys_committed_MDEP);
+  extern const Addr ML_(blksys_finished_MDEP);
+  extern const Addr ML_(blksys_setup_UNIX);
+  extern const Addr ML_(blksys_restart_UNIX);
+  extern const Addr ML_(blksys_complete_UNIX);
+  extern const Addr ML_(blksys_committed_UNIX);
+  extern const Addr ML_(blksys_finished_UNIX);
 #else
 # error "Unknown OS"
 #endif
@@ -1375,6 +1845,34 @@
       vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
    }
 
+#elif defined(VGP_x86_darwin)
+   arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL; 
+
+   /* Make sure our caller is actually sane, and we're really backing
+      back over a syscall.
+
+      int $0x80 == CD 80
+      int $0x81 == CD 81
+      int $0x82 == CD 82
+      sysenter  == 0F 34
+   */
+   {
+       UChar *p = (UChar *)arch->vex.guest_EIP;
+       Bool  ok = (p[0] == 0xCD && p[1] == 0x80) 
+                  || (p[0] == 0xCD && p[1] == 0x81)
+                  || (p[0] == 0xCD && p[1] == 0x82)  
+                  || (p[0] == 0x0F && p[1] == 0x34);
+       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_darwin)
+   // DDD: #warning GrP fixme amd64 restart unimplemented
+   vg_assert(0);
+   
 #else
 #  error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
 #endif
@@ -1450,6 +1948,28 @@
       = ip >= ML_(blksys_complete) && ip < ML_(blksys_committed); 
    in_committed_to_finished
       = ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
+#  elif defined(VGO_darwin)
+   outside_range
+      =  (ip < ML_(blksys_setup_MACH) || ip >= ML_(blksys_finished_MACH))
+      && (ip < ML_(blksys_setup_MDEP) || ip >= ML_(blksys_finished_MDEP))
+      && (ip < ML_(blksys_setup_UNIX) || ip >= ML_(blksys_finished_UNIX));
+   in_setup_to_restart
+      =  (ip >= ML_(blksys_setup_MACH) && ip < ML_(blksys_restart_MACH))
+      || (ip >= ML_(blksys_setup_MDEP) && ip < ML_(blksys_restart_MDEP))
+      || (ip >= ML_(blksys_setup_UNIX) && ip < ML_(blksys_restart_UNIX));
+   at_restart
+      =  (ip == ML_(blksys_restart_MACH))
+      || (ip == ML_(blksys_restart_MDEP))
+      || (ip == ML_(blksys_restart_UNIX));
+   in_complete_to_committed
+      =  (ip >= ML_(blksys_complete_MACH) && ip < ML_(blksys_committed_MACH))
+      || (ip >= ML_(blksys_complete_MDEP) && ip < ML_(blksys_committed_MDEP))
+      || (ip >= ML_(blksys_complete_UNIX) && ip < ML_(blksys_committed_UNIX));
+   in_committed_to_finished
+      =  (ip >= ML_(blksys_committed_MACH) && ip < ML_(blksys_finished_MACH))
+      || (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. */
 #  else
 #    error "Unknown OS"
 #  endif
@@ -1558,6 +2078,45 @@
 }
 
 
+#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).
+// This longjmps back to the scheduler.
+void ML_(wqthread_continue_NORETURN)(ThreadId tid)
+{
+   ThreadState*     tst;
+   SyscallInfo*     sci;
+
+   VG_(acquire_BigLock)(tid, "wqthread_continue_NORETURN");
+
+   PRINT("SYSCALL[%d,%d](%3lld) workq_ops() starting new workqueue item\n", 
+         VG_(getpid)(), tid, (Long)VG_DARWIN_SYSNO_PRINT(__NR_workq_ops));
+
+   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);
+   sci     = & syscallInfo[tid];
+   vg_assert(sci->status.what != SsIdle);
+   vg_assert(tst->os_state.wq_jmpbuf_valid);  // check this BEFORE post_syscall
+
+   // Pretend the syscall completed normally, but don't touch the thread state.
+   sci->status = convert_SysRes_to_SyscallStatus( VG_(mk_SysRes_Success)(0) );
+   sci->flags |= SfNoWriteResult;
+   VG_(post_syscall)(tid);
+
+   sci->status.what = SsIdle;
+
+   vg_assert(tst->sched_jmpbuf_valid);
+   __builtin_longjmp(tst->sched_jmpbuf, True);
+
+   /* NOTREACHED */
+   vg_assert(0);
+}
+#endif
+
+
 /* ---------------------------------------------------------------------
    A place to store the where-to-call-when-really-done pointer
    ------------------------------------------------------------------ */
diff --git a/coregrind/m_syswrap/syswrap-x86-darwin.c b/coregrind/m_syswrap/syswrap-x86-darwin.c
new file mode 100644
index 0000000..5532033
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-x86-darwin.c
@@ -0,0 +1,502 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc.          syswrap-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_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_debuginfo.h"    // VG_(di_notify_*)
+#include "pub_core_transtab.h"     // VG_(discard_translations)
+#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"
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"   /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h"    /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+
+#include <mach/mach.h>
+
+static void x86_thread_state32_from_vex(i386_thread_state_t *mach, 
+                                        VexGuestX86State *vex)
+{
+    mach->__eax = vex->guest_EAX;
+    mach->__ebx = vex->guest_EBX;
+    mach->__ecx = vex->guest_ECX;
+    mach->__edx = vex->guest_EDX;
+    mach->__edi = vex->guest_EDI;
+    mach->__esi = vex->guest_ESI;
+    mach->__ebp = vex->guest_EBP;
+    mach->__esp = vex->guest_ESP;
+    mach->__ss = vex->guest_SS;
+    mach->__eflags = LibVEX_GuestX86_get_eflags(vex);
+    mach->__eip = vex->guest_EIP;
+    mach->__cs = vex->guest_CS;
+    mach->__ds = vex->guest_DS;
+    mach->__es = vex->guest_ES;
+    mach->__fs = vex->guest_FS;
+    mach->__gs = vex->guest_GS;
+}
+
+
+static void x86_float_state32_from_vex(i386_float_state_t *mach, 
+                                       VexGuestX86State *vex)
+{
+   // DDD: #warning GrP fixme fp state
+
+   VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 8 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_from_vex(thread_state_t mach_generic, 
+                           thread_state_flavor_t flavor, 
+                           mach_msg_type_number_t count, 
+                           VexGuestArchState *vex_generic)
+{
+   VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
+
+   switch (flavor) {
+   case i386_THREAD_STATE:
+      vg_assert(count == i386_THREAD_STATE_COUNT);
+      x86_thread_state32_from_vex((i386_thread_state_t *)mach_generic, vex);
+      break;
+
+   case i386_FLOAT_STATE:
+      vg_assert(count == i386_FLOAT_STATE_COUNT);
+      x86_float_state32_from_vex((i386_float_state_t *)mach_generic, vex);
+      break;
+       
+   default:
+      vg_assert(0);
+   }
+}
+
+
+static void x86_thread_state32_to_vex(const i386_thread_state_t *mach, 
+                                      VexGuestX86State *vex)
+{
+   LibVEX_GuestX86_initialise(vex);
+   vex->guest_EAX = mach->__eax;
+   vex->guest_EBX = mach->__ebx;
+   vex->guest_ECX = mach->__ecx;
+   vex->guest_EDX = mach->__edx;
+   vex->guest_EDI = mach->__edi;
+   vex->guest_ESI = mach->__esi;
+   vex->guest_EBP = mach->__ebp;
+   vex->guest_ESP = mach->__esp;
+   vex->guest_SS = mach->__ss;
+   // DDD: #warning GrP fixme eflags
+   vex->guest_EIP = mach->__eip;
+   vex->guest_CS = mach->__cs;
+   vex->guest_DS = mach->__ds;
+   vex->guest_ES = mach->__es;
+   vex->guest_FS = mach->__fs;
+   vex->guest_GS = mach->__gs;
+}
+
+static void x86_float_state32_to_vex(const i386_float_state_t *mach, 
+                                     VexGuestX86State *vex)
+{
+   // DDD: #warning GrP fixme fp state
+
+   VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 8 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_to_vex(const thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         VexGuestArchState *vex_generic)
+{
+   VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
+   
+   switch(flavor) {
+   case i386_THREAD_STATE:
+      vg_assert(count == i386_THREAD_STATE_COUNT);
+      x86_thread_state32_to_vex((const i386_thread_state_t*)mach_generic,vex);
+      break;
+   case i386_FLOAT_STATE:
+      vg_assert(count == i386_FLOAT_STATE_COUNT);
+      x86_float_state32_to_vex((const i386_float_state_t*)mach_generic,vex);
+      break;
+
+   default:
+      vg_assert(0);
+      break;
+   }
+}
+
+
+ThreadState *build_thread(const thread_state_t state, 
+                          thread_state_flavor_t flavor, 
+                          mach_msg_type_number_t count)
+{
+   ThreadId tid = VG_(alloc_ThreadState)();
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+    
+   vg_assert(flavor == i386_THREAD_STATE);
+   vg_assert(count == i386_THREAD_STATE_COUNT);
+
+   // Initialize machine registers
+
+   thread_state_to_vex(state, flavor, count, &tst->arch.vex);
+
+   I_die_here;
+   // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
+
+   find_stack_segment(tid, tst->arch.vex.guest_ESP);
+
+   return tst;
+}
+
+
+// Edit the thread state to send to the real kernel.
+// The real thread will run start_thread_NORETURN(tst)
+// on a separate non-client stack.
+void hijack_thread_state(thread_state_t mach_generic, 
+                         thread_state_flavor_t flavor, 
+                         mach_msg_type_number_t count, 
+                         ThreadState *tst)
+{
+   i386_thread_state_t *mach = (i386_thread_state_t *)mach_generic;
+   char *stack;
+
+   vg_assert(flavor == i386_THREAD_STATE);
+   vg_assert(count == i386_THREAD_STATE_COUNT);
+
+   stack = (char *)allocstack(tst->tid);
+   stack -= 64+320;                       // make room for top frame
+   memset(stack, 0, 64+320);              // ...and clear it
+   *(uintptr_t *)stack = (uintptr_t)tst;  // set parameter
+   stack -= sizeof(uintptr_t);
+   *(uintptr_t *)stack = 0;               // push fake return address
+
+   mach->__eip = (uintptr_t)&start_thread_NORETURN;
+   mach->__esp = (uintptr_t)stack;
+}
+
+
+/* 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 call_on_new_stack_0_1 ( Addr stack,
+			     Addr retaddr,
+			     void (*f)(Word),
+                             Word arg1 );
+//  4(%esp) == stack (must be 16-byte aligned)
+//  8(%esp) == retaddr
+// 12(%esp) == f
+// 16(%esp) == arg1
+asm(
+".globl _call_on_new_stack_0_1\n"
+"_call_on_new_stack_0_1:\n"
+"   movl %esp, %esi\n"     // remember old stack pointer
+"   movl 4(%esi), %esp\n"  // set new 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
+);
+
+
+asm(
+".globl _pthread_hijack_asm\n"
+"_pthread_hijack_asm:\n"
+"   movl %esp,%ebp\n"
+"   push $0\n"    // alignment pad
+"   push %ebp\n"  // original sp
+"   push %esi\n"  // flags
+"   push %edi\n"  // stacksize
+"   push %edx\n"  // func_arg
+"   push %ecx\n"  // func
+"   push %ebx\n"  // kport
+"   push %eax\n"  // self
+"   push $0\n"    // fake return address
+"   jmp _pthread_hijack\n"
+    );
+
+
+
+void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg, 
+                    Addr stacksize, Addr flags, Addr sp)
+{
+   vki_sigset_t blockall;
+   ThreadState *tst = (ThreadState *)func_arg;
+   VexGuestX86State *vex = &tst->arch.vex;
+
+   // VG_(printf)("pthread_hijack pthread %p, machthread %p, func %p, arg %p, stack %p, flags %p, stack %p\n", self, kport, func, func_arg, stacksize, flags, sp);
+
+   // Wait for parent thread's permission.
+   // The parent thread holds V's lock on our behalf.
+   semaphore_wait(tst->os_state.child_go);
+
+   /* Start the thread with all signals blocked.  VG_(scheduler) will
+      set the mask correctly when we finally get there. */
+   VG_(sigfillset)(&blockall);
+   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
+
+   // Set thread's registers
+   // Do this FIRST because some code below tries to collect a backtrace, 
+   // which requires valid register data.
+   // DDD: need to do post_reg_write events here?
+   LibVEX_GuestX86_initialise(vex);
+   vex->guest_EIP = pthread_starter;
+   vex->guest_EAX = self;
+   vex->guest_EBX = kport;
+   vex->guest_ECX = func;
+   vex->guest_EDX = tst->os_state.func_arg;
+   vex->guest_EDI = stacksize;
+   vex->guest_ESI = flags;
+   vex->guest_ESP = sp;
+
+   // Record thread's stack and Mach port and pthread struct
+   tst->os_state.pthread = self;
+   tst->os_state.lwpid = kport;
+   record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
+
+   if ((flags & 0x01000000) == 0) {
+      // kernel allocated stack - needs mapping
+      Addr stack = VG_PGROUNDUP(sp) - stacksize;
+      tst->client_stack_highest_word = stack+stacksize;
+      tst->client_stack_szB = stacksize;
+
+      // pthread structure
+      ML_(notify_core_and_tool_of_mmap)(
+            stack+stacksize, pthread_structsize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // stack contents
+      ML_(notify_core_and_tool_of_mmap)(
+            stack, stacksize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // guard page
+      ML_(notify_core_and_tool_of_mmap)(
+            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 
+            0, VKI_MAP_PRIVATE, -1, 0);
+   } else {
+      // client allocated stack
+      find_stack_segment(tst->tid, sp);
+   }
+   VG_(am_do_sync_check)("after", "pthread_hijack", 0);
+
+   // DDD: should this be here rather than in POST(sys_bsdthread_create)?
+   // But we don't have ptid here...
+   //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
+
+   // Tell parent thread's POST(sys_bsdthread_create) that we're done 
+   // initializing registers and mapping memory.
+   semaphore_signal(tst->os_state.child_done);
+   // LOCK IS GONE BELOW THIS POINT
+
+   // Go!
+   call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
+                         start_thread_NORETURN, (Word)tst);
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+
+
+asm(
+".globl _wqthread_hijack_asm\n"
+"_wqthread_hijack_asm:\n"
+"   movl %esp,%ebp\n"
+"   push $0\n"    // alignment
+"   push $0\n"    // alignment
+"   push %ebp\n"  // original sp
+"   push %edi\n"  // reuse
+"   push %edx\n"  // workitem
+"   push %ecx\n"  // stackaddr
+"   push %ebx\n"  // kport
+"   push %eax\n"  // self
+"   push $0\n"    // fake return address
+"   jmp _wqthread_hijack\n"
+    );
+
+
+/*  wqthread note: The kernel may create or destroy pthreads in the 
+    wqthread pool at any time with no userspace interaction, 
+    and wqthread_start may be entered at any time with no userspace 
+    interaction.
+    To handle this in valgrind, we create and destroy a valgrind 
+    thread for every work item.
+*/
+void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, 
+                     Int reuse, Addr sp)
+{
+   ThreadState *tst;
+   VexGuestX86State *vex;
+   Addr stack;
+   SizeT stacksize;
+   vki_sigset_t blockall;
+
+   /* When we enter here we hold no lock (!), so we better acquire it
+      pronto.  Why do we hold no lock?  Because (presumably) the only
+      way to get here is as a result of a SfMayBlock syscall
+      "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
+      lock.  At least that's clear for the 'reuse' case.  The
+      non-reuse case?  Dunno, perhaps it's a new thread the kernel
+      pulled out of a hat.  In any case we still need to take a
+      lock. */
+   VG_(acquire_BigLock_LL)("wqthread_hijack");
+
+   /* Start the thread with all signals blocked.  VG_(scheduler) will
+      set the mask correctly when we finally get there. */
+   VG_(sigfillset)(&blockall);
+   VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
+
+   if (reuse) {
+      // This thread already exists; we're merely re-entering 
+      // after leaving via workq_ops(WQOPS_THREAD_RETURN). 
+      // Don't allocate any V thread resources.
+      // Do reset thread registers.
+      ThreadId tid = VG_(lwpid_to_vgtid)(kport);
+      vg_assert(VG_(is_valid_tid)(tid));
+      vg_assert(mach_thread_self() == kport);
+
+      tst = VG_(get_ThreadState)(tid);
+      vex = &tst->arch.vex;
+      vg_assert(tst->os_state.pthread == self);
+   }
+   else {
+      // This is a new thread.
+      tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());        
+      vex = &tst->arch.vex;
+      allocstack(tst->tid);
+      LibVEX_GuestX86_initialise(vex);
+   }
+        
+   // Set thread's registers
+   // Do this FIRST because some code below tries to collect a backtrace, 
+   // which requires valid register data.
+   vex->guest_EIP = wqthread_starter;
+   vex->guest_EAX = self;
+   vex->guest_EBX = kport;
+   vex->guest_ECX = stackaddr;
+   vex->guest_EDX = workitem;
+   vex->guest_EDI = reuse;
+   vex->guest_ESI = 0;
+   vex->guest_ESP = sp;
+
+   stacksize = 512*1024;  // wq stacks are always DEFAULT_STACK_SIZE
+   stack = VG_PGROUNDUP(sp) - stacksize;
+
+   if (reuse) {
+       // Continue V's thread back in the scheduler. 
+       // The client thread is of course in another location entirely.
+
+      /* Drop the lock before going into
+         ML_(wqthread_continue_NORETURN).  The latter will immediately
+         attempt to reacquire it in non-LL mode, which is a bit
+         wasteful but I don't think is harmful.  A better solution
+         would be to not drop the lock but instead "upgrade" it from a
+         LL lock to a full lock, but that's too much like hard work
+         right now. */
+       VG_(release_BigLock_LL)("wqthread_hijack(1)");
+       ML_(wqthread_continue_NORETURN)(tst->tid);
+   } 
+   else {
+      // Record thread's stack and Mach port and pthread struct
+      tst->os_state.pthread = self;
+      tst->os_state.lwpid = kport;
+      record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
+      
+      // kernel allocated stack - needs mapping
+      tst->client_stack_highest_word = stack+stacksize;
+      tst->client_stack_szB = stacksize;
+
+      // GrP fixme scheduler lock?!
+      
+      // pthread structure
+      ML_(notify_core_and_tool_of_mmap)(
+            stack+stacksize, pthread_structsize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // stack contents
+      // GrP fixme uninitialized!
+      ML_(notify_core_and_tool_of_mmap)(
+            stack, stacksize, 
+            VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+      // guard page
+      // GrP fixme ban_mem_stack!
+      ML_(notify_core_and_tool_of_mmap)(
+            stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 
+            0, VKI_MAP_PRIVATE, -1, 0);
+
+      VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
+
+      // Go!
+      /* Same comments as the 'release' in the then-clause.
+         start_thread_NORETURN calls run_thread_NORETURN calls
+         thread_wrapper which acquires the lock before continuing.
+         Let's hope nothing non-thread-local happens until that point.
+
+         DDD: I think this is plain wrong .. if we get to
+         thread_wrapper not holding the lock, and someone has recycled
+         this thread slot in the meantime, we're hosed.  Is that
+         possible, though? */
+      VG_(release_BigLock_LL)("wqthread_hijack(2)");
+      call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0, 
+                            start_thread_NORETURN, (Word)tst);
+   }
+
+   /*NOTREACHED*/
+   vg_assert(0);
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                     syswrap-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index d267172..e52076d 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -735,7 +735,307 @@
 #	undef UD2_256
 #	undef UD2_1024
 #	undef UD2_PAGE
+
+/*---------------- x86-darwin ----------------*/
+#else
+#if defined(VGP_x86_darwin)
+
+        /* a leading page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+.globl VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+.globl VG_(x86_darwin_SUBST_FOR_sigreturn)
+VG_(x86_darwin_SUBST_FOR_sigreturn):
+        /* XXX does this need to have any special form? (cf x86-linux
+	version) */
+        movl    $ __NR_DARWIN_FAKE_SIGRETURN, %eax
+        int     $0x80
+        ud2
+
+.globl VG_(darwin_REDIR_FOR_strlen)
+VG_(darwin_REDIR_FOR_strlen):
+        movl    4(%esp), %edx
+        movl    %edx, %eax
+        jmp     1f
+0:
+        incl    %eax
+1:
+        cmpb    $0, (%eax)
+        jne     0b
+        subl    %edx, %eax
+        ret
+
+.globl VG_(darwin_REDIR_FOR_strcat)
+VG_(darwin_REDIR_FOR_strcat):
+        pushl   %esi
+        movl    8(%esp), %esi
+        movl    12(%esp), %ecx
+        movl    %esi, %edx
+        jmp     1f
+0:
+        incl    %edx
+1:
+        cmpb    $0, (%edx)
+        jne     0b
+2:
+        movzbl  (%ecx), %eax
+        incl    %ecx
+        movb    %al, (%edx)
+        incl    %edx
+        testb   %al, %al
+        jne     2b
+        movl    %esi, %eax
+        popl    %esi
+        ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcmp)
+VG_(darwin_REDIR_FOR_strcmp):
+        movl    4(%esp), %edx
+        movl    8(%esp), %ecx
+        jmp     1f
+0:
+        incl    %edx
+        incl    %ecx
+1:
+        movzbl  (%edx), %eax
+        testb   %al, %al
+        je      2f
+        cmpb    (%ecx), %al
+        je      0b
+2:
+        movzbl  (%ecx),%edx
+        movzbl  %al,%eax
+        subl    %edx, %eax
+        ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcpy)
+VG_(darwin_REDIR_FOR_strcpy):
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%esi
+	movl	8(%ebp), %esi
+	movl	12(%ebp), %ecx
+	movl	%esi, %edx
+	jmp	1f
+0:
+	incl	%ecx
+	incl	%edx
+1:
+	movzbl	(%ecx), %eax
+	testb	%al, %al
+	movb	%al, (%edx)
+	jne	0b
+	movl	%esi, %eax
+	popl	%esi
+	leave
+	ret
+
+.globl VG_(darwin_REDIR_FOR_strlcat)
+VG_(darwin_REDIR_FOR_strlcat):
+	pushl	%ebp
+	movl	%esp, %ebp
+	pushl	%edi
+	pushl	%esi
+	subl	$16, %esp
+	movl	8(%ebp), %esi
+	movl	16(%ebp), %ecx
+	movl	%esi, %edx
+	leal	(%ecx,%esi), %eax
+	jmp	1f
+0:
+	incl	%edx
+1:
+	cmpl	%edx, %eax
+	je	2f
+	cmpb	$0, (%edx)
+	jne	0b
+2:
+	movl	%edx, %edi
+	subl	%esi, %edi
+	movl	%ecx, %esi
+	subl	%edi, %esi
+	je	3f
+	movl	12(%ebp), %eax
+	jmp	6f
+3:
+	movl	12(%ebp), %eax
+	movl	%eax, (%esp)
+	call	VG_(darwin_REDIR_FOR_strlen)
+	jmp	7f
+4:
+	cmpl	$1, %esi
+	je	5f
+	movb	%cl, (%edx)
+	decl	%esi
+	incl	%edx
+5:
+	incl	%eax
+6:
+	movzbl	(%eax), %ecx
+	testb	%cl, %cl
+	jne	4b
+	movb	$0, (%edx)
+	subl	12(%ebp), %eax
+7:
+	addl	$16, %esp
+	leal	(%edi,%eax), %eax
+	popl	%esi
+	popl	%edi
+	leave
+	ret
 	
+	
+.globl VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+        /* a trailing page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+
+/*---------------- amd64-darwin ----------------*/
+#else
+#if defined(VGP_amd64_darwin)
+
+        /* a leading page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+.globl VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+.globl VG_(darwin_REDIR_FOR_strlen)
+VG_(darwin_REDIR_FOR_strlen):
+        movq    %rdi, %rax
+        jmp     1f
+0:
+        incq    %rax
+1:
+        cmpb    $0, (%rax)
+        jne     0b
+        subq    %rdi, %rax
+        ret
+
+.globl VG_(darwin_REDIR_FOR_strcat)
+VG_(darwin_REDIR_FOR_strcat):
+	movq	%rdi, %rdx
+	jmp	1f
+0:
+	incq	%rdx
+1:
+	cmpb	$0, (%rdx)
+	jne	0b
+2:
+	movzbl	(%rsi), %eax
+	incq	%rsi
+	movb	%al, (%rdx)
+	incq	%rdx
+	testb	%al, %al
+	jne	2b
+	movq	%rdi, %rax
+	ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcmp)
+VG_(darwin_REDIR_FOR_strcmp):
+	jmp	1f
+0:
+	incq	%rdi
+	incq	%rsi
+1:
+	movzbl	(%rdi), %eax
+	testb	%al, %al
+	je	2f
+	cmpb	(%rsi), %al
+	je	0b
+2:
+	movzbl	(%rsi), %edx
+	movzbl	%al, %eax
+	subl	%edx, %eax
+	ret
+
+.globl VG_(darwin_REDIR_FOR_strcpy)
+VG_(darwin_REDIR_FOR_strcpy):
+	pushq	%rbp
+	movq	%rdi, %rdx
+	movq	%rsp, %rbp
+	jmp	1f
+0:
+	incq	%rsi
+	incq	%rdx
+1:
+	movzbl	(%rsi), %eax
+	testb	%al, %al
+	movb	%al, (%rdx)
+	jne	0b
+	leave
+	movq	%rdi, %rax
+	ret
+	
+.globl VG_(darwin_REDIR_FOR_strlcat)
+VG_(darwin_REDIR_FOR_strlcat):
+	pushq	%rbp
+	leaq	(%rdx,%rdi), %rax
+	movq	%rdi, %rcx
+	movq	%rsp, %rbp
+	pushq	%rbx
+	subq	$8, %rsp
+	jmp	1f
+0:
+	incq	%rcx
+1:
+	cmpq	%rcx, %rax
+	je	2f
+	cmpb	$0, (%rcx)
+	jne	0b
+2:
+	movq	%rcx, %rbx
+	subq	%rdi, %rbx
+	movq	%rdx, %rdi
+	subq	%rbx, %rdi
+	je	3f
+	movq	%rsi, %rax
+	jmp	6f
+3:
+	movq	%rsi, %rdi
+	call	VG_(darwin_REDIR_FOR_strlen)
+	jmp	7f
+4:
+	cmpq	$1, %rdi
+	je	5f
+	movb	%dl, (%rcx)
+	decq	%rdi
+	incq	%rcx
+5:
+	incq	%rax
+6:
+	movzbl	(%rax), %edx
+	testb	%dl, %dl
+	jne	4b
+	movb	$0, (%rcx)
+	subq	%rsi, %rax
+7:
+	leaq	(%rbx,%rax), %rax
+	addq	$8, %rsp
+	popq	%rbx
+	leave
+	ret
+
+.globl VG_(darwin_REDIR_FOR_arc4random)
+VG_(darwin_REDIR_FOR_arc4random):
+	/* not very random, hope dyld won't mind */
+	movq	$0x76616c6772696e64, %rax
+	ret
+
+.globl VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+        /* a trailing page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+
 /*---------------- unknown ----------------*/
 #else
 #  error Unknown platform
@@ -746,6 +1046,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 ea7ec46..1e1f049 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -708,6 +708,14 @@
 
 static Bool self_check_required ( NSegment const* seg, ThreadId tid )
 {
+#if defined(VGO_darwin)
+   // GrP fixme hack - dyld i386 IMPORT gets rewritten
+   // to really do this correctly, we'd need to flush the 
+   // translation cache whenever a segment became +WX
+   if (seg->hasX  && seg->hasW) {
+      return True;
+   }
+#endif
    switch (VG_(clo_smc_check)) {
       case Vg_SmcNone:  return False;
       case Vg_SmcAll:   return True;
@@ -1417,6 +1425,9 @@
 #  if defined(VGP_amd64_linux)
    vex_abiinfo.guest_amd64_assume_fs_is_zero  = True;
 #  endif
+#  if defined(VGP_amd64_darwin)
+   vex_abiinfo.guest_amd64_assume_gs_is_0x60  = True;
+#  endif
 #  if defined(VGP_ppc32_linux)
    vex_abiinfo.guest_ppc_zap_RZ_at_blr        = False;
    vex_abiinfo.guest_ppc_zap_RZ_at_bl         = NULL;
diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c
index f771960..8dfbb1f 100644
--- a/coregrind/m_ume/elf.c
+++ b/coregrind/m_ume/elf.c
@@ -44,7 +44,6 @@
 
 #include "priv_ume.h"
 
-
 #if defined(HAVE_ELF)
 
 /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
diff --git a/coregrind/m_ume/macho.c b/coregrind/m_ume/macho.c
new file mode 100644
index 0000000..db5db4f
--- /dev/null
+++ b/coregrind/m_ume/macho.c
@@ -0,0 +1,776 @@
+
+/*--------------------------------------------------------------------*/
+/*--- User-mode execve() for Mach-O executables      m_ume_macho.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+
+#include "pub_core_aspacemgr.h"     // various mapping fns
+#include "pub_core_debuglog.h"
+#include "pub_core_libcassert.h"    // VG_(exit), vg_assert
+#include "pub_core_libcbase.h"      // VG_(memcmp), etc
+#include "pub_core_libcfile.h"      // VG_(open) et al
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_machine.h"       // VG_ELF_CLASS (XXX: which should be moved)
+#include "pub_core_mallocfree.h"    // VG_(malloc), VG_(free)
+#include "pub_core_syscall.h"       // VG_(strerror)
+#include "pub_core_ume.h"           // self
+
+#include "priv_ume.h"
+
+
+#if defined(HAVE_MACHO)
+
+#include <mach/mach.h>
+
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#if VG_WORDSIZE == 4
+#define MAGIC MH_MAGIC
+#define MACH_HEADER mach_header
+#define LC_SEGMENT_CMD LC_SEGMENT
+#define SEGMENT_COMMAND segment_command
+#define SECTION section
+#else
+#define MAGIC MH_MAGIC_64
+#define MACH_HEADER mach_header_64
+#define LC_SEGMENT_CMD LC_SEGMENT_64
+#define SEGMENT_COMMAND segment_command_64
+#define SECTION section_64
+#endif
+
+
+static void print(const char *str)
+{
+   VG_(printf)("%s", str);
+}
+
+static void check_mmap(SysRes res, Addr base, SizeT len)
+{
+   if (sr_isError(res)) {
+      VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME.\n", 
+                  (ULong)base, (Long)len);
+      VG_(exit)(1);
+   }
+}
+
+
+static int 
+load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+               const char *filename, 
+               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+static int 
+load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+              const char *filename, 
+              vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+              vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+static int 
+load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+               const char *filename, 
+               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+
+/* Open and map a dylinker file.
+   Returns 0 on success, -1 on any failure.
+   filename must be an absolute path.
+   The dylinker's entry point is returned in *out_linker_entry.
+ */
+static int 
+open_dylinker(const char *filename, vki_uint8_t **out_linker_entry)
+{
+   struct vg_stat sb;
+   vki_size_t filesize;
+   SysRes res;
+   int fd;
+   int err;
+
+   if (filename[0] != '/') {
+      print("bad executable (dylinker name is not an absolute path)\n");
+      return -1;
+   }
+
+   res = VG_(open)(filename, VKI_O_RDONLY, 0);
+   fd = sr_Res(res);
+   if (sr_isError(res)) {
+      print("couldn't open dylinker: ");
+      print(filename);
+      print("\n");
+      return -1;
+   }
+   err = VG_(fstat)(fd, &sb);
+   if (err) {
+      print("couldn't stat dylinker: ");
+      print(filename);
+      print("\n");
+      VG_(close)(fd);
+      return -1;
+   }
+   filesize = sb.size;
+
+   err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename, 
+                        NULL, NULL, NULL, out_linker_entry, NULL);
+   if (err) {
+      print("...while loading dylinker: ");
+      print(filename);
+      print("\n");
+   }
+   VG_(close)(fd);
+   return err;
+}
+
+
+/* 
+   Process an LC_SEGMENT command, mapping it into memory if appropriate.
+   fd[offset..size) is a Mach-O thin file. 
+   Returns 0 on success, -1 on any failure.
+   If this segment contains the executable's Mach headers, their 
+     loaded address is returned in *text.
+   If this segment is a __UNIXSTACK, its start address is returned in 
+     *stack_start.
+*/
+static int
+load_segment(int fd, vki_off_t offset, vki_off_t size, 
+             vki_uint8_t **text, vki_uint8_t **stack_start, 
+             struct SEGMENT_COMMAND *segcmd, const HChar *filename)
+{
+   SysRes res;
+   Addr addr;
+   vki_size_t filesize; // page-aligned 
+   vki_size_t vmsize;   // page-aligned
+   unsigned int prot;
+
+   // GrP fixme mark __UNIXSTACK as SF_STACK
+    
+#if VG_WORDSIZE == 8
+   if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
+      if (segcmd->vmsize != 0x100000000) {
+         print("bad executable (__PAGEZERO is not 4 GB)\n");
+         return -1;
+      }
+      return 0;
+   }
+#endif
+
+   // Record the segment containing the Mach headers themselves
+   if (segcmd->fileoff == 0  &&  segcmd->filesize != 0) {
+      if (text) *text = (vki_uint8_t *)segcmd->vmaddr;
+   }
+
+   // Record the __UNIXSTACK start
+   if (0 == VG_(strcmp)(segcmd->segname, SEG_UNIXSTACK)) {
+      if (stack_start) *stack_start = (vki_uint8_t *)segcmd->vmaddr;
+   }
+
+   // Sanity-check the segment
+   if (segcmd->fileoff + segcmd->filesize > size) {
+      print("bad executable (invalid segment command)\n");
+      return -1;
+   }
+   if (segcmd->vmsize == 0) {
+      return 0;  // nothing to map - ok
+   }
+
+   // Get desired memory protection
+   // GrP fixme need maxprot too
+   prot = (((segcmd->initprot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
+           ((segcmd->initprot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
+           ((segcmd->initprot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0));
+
+   // Map the segment    
+   filesize = VG_PGROUNDUP(segcmd->filesize);
+   vmsize = VG_PGROUNDUP(segcmd->vmsize);
+   if (filesize > 0) {
+      addr = (Addr)segcmd->vmaddr;
+      res = VG_(am_mmap_named_file_fixed_client)(addr, filesize, prot, fd, 
+                                                 offset + segcmd->fileoff, 
+                                                 filename);
+      check_mmap(res, addr, filesize);
+   }
+
+   // Zero-fill the remainder of the segment, if any
+   if (segcmd->filesize != filesize) {
+      // non-page-aligned part
+      // GrP fixme kernel doesn't do this?
+      //bzero(segcmd->filesize+(vki_uint8_t *)addr, filesize-segcmd->filesize);
+   }
+   if (filesize != vmsize) {
+      // page-aligned part
+      SizeT length = vmsize - filesize;
+      addr = (Addr)(filesize + segcmd->vmaddr);
+      res = VG_(am_mmap_anon_fixed_client)(addr, length, prot);
+      check_mmap(res, addr, length);
+   }
+
+   return 0;
+}
+
+
+/* 
+   Parse a LC_THREAD or LC_UNIXTHREAD command. 
+   Return 0 on success, -1 on any failure.
+   The stack address is returned in *stack. If the executable requested 
+   a non-default stack address, *customstack is set to TRUE. The thread's 
+   entry point is returned in *entry.
+   The stack itself (if any) is not mapped.
+   Other custom register settings are silently ignored (GrP fixme).
+*/
+static int 
+load_genericthread(vki_uint8_t **stack_end, 
+                   int *customstack, vki_uint8_t **entry, 
+                   struct thread_command *threadcmd)
+{
+   unsigned int flavor;
+   unsigned int count;
+   unsigned int *p;
+   unsigned int left; 
+
+   p = (unsigned int *)(threadcmd + 1);
+   left = (threadcmd->cmdsize - sizeof(struct thread_command)) / sizeof(*p);
+
+   while (left > 0) {
+      if (left < 2) {
+         print("bad executable (invalid thread command)\n");
+         return -1;
+      }
+      flavor = *p++; left--;
+      count = *p++; left--;
+      
+      if (left < count) {
+         print("bad executable (invalid thread command 2)\n");
+         return -1;
+      }
+
+#if defined(VGA_x86)
+      if (flavor == i386_THREAD_STATE && count == i386_THREAD_STATE_COUNT) {
+         i386_thread_state_t *state = (i386_thread_state_t *)p;
+         if (entry) *entry = (vki_uint8_t *)state->__eip;
+         if (stack_end) *stack_end = (vki_uint8_t *)(state->__esp ? state->__esp : VKI_USRSTACK);
+         if (customstack) *customstack = state->__esp;
+         return 0;
+      }
+
+#elif defined(VGA_amd64)
+      if (flavor == x86_THREAD_STATE64 && count == x86_THREAD_STATE64_COUNT){
+         x86_thread_state64_t *state = (x86_thread_state64_t *)p;
+         if (entry) *entry = (vki_uint8_t *)state->__rip;
+         if (stack_end) *stack_end = (vki_uint8_t *)(state->__rsp ? state->__rsp : VKI_USRSTACK64);
+         if (customstack) *customstack = state->__rsp;
+         return 0;
+      }
+
+#else
+# error unknown platform
+#endif
+      p += count;
+      left -= count;
+   }
+
+   print("bad executable (no arch-compatible thread state)\n");
+   return -1;
+}
+
+
+/* Returns the main stack size on this platform, 
+   using getrlimit or a fixed size.
+   GrP fixme 64-bit? */
+static vki_size_t default_stack_size(void)
+{
+   struct vki_rlimit lim;
+   int err = VG_(getrlimit)(VKI_RLIMIT_STACK, &lim);
+   if (err) return 8*1024*1024; // 8 MB
+   else return lim.rlim_cur;
+}
+
+
+/* 
+   Processes a LC_UNIXTHREAD command.
+   Returns 0 on success, -1 on any failure.
+   The stack is mapped in and returned in *out_stack. 
+   The thread's entry point is returned in *out_entry.
+*/
+static int 
+load_unixthread(vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+                vki_uint8_t **out_entry, struct thread_command *threadcmd)
+{
+   int err;
+   vki_uint8_t *stack_end;
+   int customstack;
+
+   err = load_genericthread(&stack_end, &customstack, out_entry, threadcmd);
+   if (err) return -1;
+
+   if (!stack_end) {
+      print("bad executable (no thread stack)\n");
+      return -1;
+   }
+
+   if (!customstack) {
+      // Map the stack
+      vki_size_t stacksize = VG_PGROUNDUP(default_stack_size());
+      vm_address_t stackbase = VG_PGROUNDDN(stack_end-stacksize);
+      SysRes res;
+        
+      res = VG_(am_mmap_anon_fixed_client)(stackbase, stacksize, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
+      check_mmap(res, stackbase, stacksize);
+      if (out_stack_start) *out_stack_start = (vki_uint8_t *)stackbase;
+   } else {
+      // custom stack - mapped via __UNIXTHREAD segment
+   }
+
+   if (out_stack_end) *out_stack_end = stack_end;
+
+   return 0;
+}
+
+
+/* 
+   Processes an LC_LOAD_DYLINKER command. 
+   Returns 0 on success, -1 on any error.
+   The linker itself is mapped into memory.
+   The linker's entry point is returned in *linker_entry.
+*/
+static int 
+load_dylinker(vki_uint8_t **linker_entry, struct dylinker_command *dycmd)
+{
+   const char *name;
+
+   if (dycmd->name.offset >= dycmd->cmdsize) {
+      print("bad executable (invalid dylinker command)\n");
+      return -1;
+   }
+
+   name = dycmd->name.offset + (char *)dycmd;
+    
+   // GrP fixme assumes name is terminated somewhere
+   return open_dylinker(name, linker_entry);
+}
+
+
+/* 
+    Process an LC_THREAD command. 
+    Returns 0 on success, -1 on any failure.
+    The thread's entry point is returned in *out_entry.
+*/
+static int 
+load_thread(vki_uint8_t **out_entry, struct thread_command *threadcmd)
+{
+   int customstack;
+   int err;
+
+   err = load_genericthread(NULL, &customstack, out_entry, threadcmd);
+   if (err) return -1;
+   if (customstack) {
+      print("bad executable (stackless thread has stack)\n");
+      return -1;
+   }
+   return 0;
+}
+
+
+/*
+  Loads a Mach-O executable into memory, along with any threads, 
+  stacks, and dylinker.
+  Returns 0 on success, -1 on any failure.
+  fd[offset..offset+size) is a Mach-O thin file.
+  filetype is MH_EXECUTE or MH_DYLINKER.
+  The mapped but empty stack is returned in *out_stack.
+  The executable's Mach headers are returned in *out_text.
+  The executable's entry point is returned in *out_entry.
+  The dylinker's entry point (if any) is returned in *out_linker_entry.
+  GrP fixme need to return whether dylinker was found - stack layout is different
+*/
+static int 
+load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+               const char *filename, 
+               vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+               vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+   struct MACH_HEADER mh;
+   vki_uint8_t *headers;
+   vki_uint8_t *headers_end;
+   struct load_command *lc;
+   struct load_command *lcend;
+   struct SEGMENT_COMMAND *segcmd;
+   struct thread_command *threadcmd;
+   struct dylinker_command *dycmd;
+   int err;
+   SysRes res;
+   vki_size_t len;
+
+   vki_uint8_t *stack_start = NULL;   // allocated thread stack (hot end)
+   vki_uint8_t *stack_end = NULL;   // allocated thread stack (cold end)
+   vki_uint8_t *entry = NULL;   // static entry point
+   vki_uint8_t *text = NULL;    // start of text segment (i.e. the mach headers)
+   vki_uint8_t *linker_entry = NULL; // dylinker entry point
+
+   // Read Mach-O header
+   if (sizeof(mh) > size) {
+      print("bad executable (no Mach-O header)\n");
+   }
+   res = VG_(pread)(fd, &mh, sizeof(mh), offset);
+   if (sr_isError(res)  ||  sr_Res(res) != sizeof(mh)) {
+      print("bad executable (no Mach-O header)\n");
+      return -1;
+   }
+   
+
+   // Sanity-check the header itself
+   if (mh.magic != MAGIC) {
+      print("bad executable (no Mach-O magic)\n");
+      return -1;
+   }
+
+   if (mh.filetype != filetype) {
+      // expecting MH_EXECUTE or MH_DYLINKER
+      print("bad executable (wrong file type)\n");
+      return -1;
+   }
+
+
+   // Map all headers into memory
+   len = sizeof(mh) + mh.sizeofcmds;
+   if (len > size) {
+      print("bad executable (missing load commands)\n");
+      return -1;
+   }
+
+   headers = VG_(malloc)("ume.macho.headers", len);
+   res = VG_(pread)(fd, headers, len, offset);
+   if (sr_isError(res)) {
+      print("couldn't read load commands from executable\n");
+      return -1;
+   }
+   headers_end = headers + size;
+
+   
+   // Map some segments into client memory:
+   // LC_SEGMENT    (text, data, etc)
+   // UNIXSTACK     (stack)
+   // LOAD_DYLINKER (dyld)
+   lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh));
+   for (lc = (struct load_command *)(headers + sizeof(mh)); 
+        lc < lcend; 
+        lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc))
+   {
+      if ((vki_uint8_t *)lc < headers  ||  
+          lc->cmdsize+(vki_uint8_t *)lc > headers_end) {
+          print("bad executable (invalid load commands)\n");
+          return -1;
+      }
+
+      switch (lc->cmd) {
+      case LC_SEGMENT_CMD:
+         if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) {
+            print("bad executable (invalid load commands)\n");
+            return -1;
+         }
+         segcmd = (struct SEGMENT_COMMAND *)lc;
+         err = load_segment(fd, offset, size, &text, &stack_start, 
+                            segcmd, filename);
+         if (err) return -1;
+          
+         break;
+
+      case LC_UNIXTHREAD:
+         if (stack_end  ||  entry) {
+            print("bad executable (multiple thread commands)\n");
+            return -1;
+         }
+         if (lc->cmdsize < sizeof(struct thread_command)) {
+            print("bad executable (invalid load commands)\n");
+            return -1;
+         }
+         threadcmd = (struct thread_command *)lc;
+         err = load_unixthread(&stack_start, &stack_end, &entry, threadcmd);
+         if (err) return -1;
+         break;
+
+      case LC_LOAD_DYLINKER:
+         if (filetype == MH_DYLINKER) {
+            print("bad executable (dylinker needs a dylinker)\n");
+            return -1;
+         }
+         if (linker_entry) {
+            print("bad executable (multiple dylinker commands)\n");
+         }
+         if (lc->cmdsize < sizeof(struct dylinker_command)) {
+            print("bad executable (invalid load commands)\n");
+            return -1;
+         }
+         dycmd = (struct dylinker_command *)lc;
+         err = load_dylinker(&linker_entry, dycmd);
+         if (err) return -1;
+         break;
+
+      case LC_THREAD:
+         if (filetype == MH_EXECUTE) {
+            print("bad executable (stackless thread)\n");
+            return -1;
+         }
+         if (stack_end  ||  entry) {
+            print("bad executable (multiple thread commands)\n");
+            return -1;
+         }
+         if (lc->cmdsize < sizeof(struct thread_command)) {
+            print("bad executable (invalid load commands)\n");
+            return -1;
+         }
+         threadcmd = (struct thread_command *)lc;
+         err = load_thread(&entry, threadcmd);
+         if (err) return -1;
+         break;
+
+      default:
+         break;
+      }
+   }
+
+
+   // Done with the headers
+   VG_(free)(headers);
+
+   if (filetype == MH_EXECUTE) {
+      // Verify the necessary pieces for an executable:
+      // a stack
+      // a text segment
+      // an entry point (static or linker)
+      if (!stack_end || !stack_start) {
+         print("bad executable (no stack)\n");
+         return -1;
+      }
+      if (!text) {
+         print("bad executable (no text segment)\n");
+         return -1;
+      }
+      if (!entry  &&  !linker_entry) {
+         print("bad executable (no entry point)\n");
+         return -1;
+      }
+   }
+   else if (filetype == MH_DYLINKER) {
+      // Verify the necessary pieces for a dylinker:
+      // an entry point
+      if (!entry) {
+         print("bad executable (no entry point)\n");
+         return -1;
+      }
+   }
+
+   if (out_stack_start) *out_stack_start = stack_start;
+   if (out_stack_end) *out_stack_end = stack_end;
+   if (out_text)  *out_text = text;
+   if (out_entry) *out_entry = entry;
+   if (out_linker_entry) *out_linker_entry = linker_entry;
+   
+   return 0;
+}
+
+
+/*
+ Load a fat Mach-O executable.
+*/
+static int 
+load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+             const char *filename, 
+             vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+             vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+   struct fat_header fh;
+   vki_off_t arch_offset;
+   int i;
+   cpu_type_t good_arch;
+   SysRes res;
+
+#if defined(VGA_ppc32)
+   good_arch = CPU_TYPE_POWERPC;
+#elif defined(VGA_ppc64)
+   good_arch = CPU_TYPE_POWERPC64;
+#elif defined(VGA_x86)
+   good_arch = CPU_TYPE_I386;
+#elif defined(VGA_amd64)
+   good_arch = CPU_TYPE_X86_64;
+#else
+# error unknown architecture
+#endif
+
+   // Read fat header
+   // All fat contents are BIG-ENDIAN
+   if (size < sizeof(fh)) {
+      print("bad executable (bad fat header)\n");
+      return -1;
+   }
+   res = VG_(pread)(fd, &fh, sizeof(fh), offset);
+   if (sr_isError(res)  ||  sr_Res(res) != sizeof(fh)) {
+      print("bad executable (bad fat header)\n");
+      return -1;
+   }
+   
+   // Scan arch headers looking for a good one
+   arch_offset = offset + sizeof(fh);
+   fh.nfat_arch = VG_(ntohl)(fh.nfat_arch);
+   for (i = 0; i < fh.nfat_arch; i++) {
+      struct fat_arch arch;
+      if (arch_offset + sizeof(arch) > size) {
+          print("bad executable (corrupt fat archs)\n");
+          return -1;
+      }
+
+      res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset);
+      arch_offset += sizeof(arch);
+      if (sr_isError(res)  ||  sr_Res(res) != sizeof(arch)) {
+         VG_(printf)("bad executable (corrupt fat arch) %x %llu\n", 
+                     arch.cputype, (ULong)arch_offset);
+         return -1;
+      }
+
+      arch.cputype = VG_(ntohl)(arch.cputype);
+      arch.cpusubtype = VG_(ntohl)(arch.cpusubtype);
+      arch.offset = VG_(ntohl)(arch.offset);
+      arch.size = VG_(ntohl)(arch.size);
+      arch.align = VG_(ntohl)(arch.align);
+      if (arch.cputype == good_arch) {
+         // use this arch
+         if (arch.offset > size  ||  arch.offset + arch.size > size) {
+            print("bad executable (corrupt fat arch 2)\n");
+            return -1;
+         }
+         return load_mach_file(fd, offset+arch.offset, arch.size, filetype, 
+                               filename, out_stack_start, out_stack_end, 
+                               out_text, out_entry, out_linker_entry);
+      }
+   }
+
+   print("bad executable (can't run on this machine)\n");
+   return -1;
+}
+
+/*
+ Load a Mach-O executable or dylinker.
+ The file may be fat or thin.
+*/
+static int 
+load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype, 
+              const char *filename, 
+              vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end, 
+              vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+   vki_uint32_t magic;
+   SysRes res;
+
+   if (size < sizeof(magic)) {
+      print("bad executable (no Mach-O magic)\n");
+      return -1;
+   }
+   res = VG_(pread)(fd, &magic, sizeof(magic), offset);
+   if (sr_isError(res)  ||  sr_Res(res) != sizeof(magic)) {
+      print("bad executable (no Mach-O magic)\n");
+      return -1;
+   }
+   
+   if (magic == MAGIC) {
+      // thin
+      return load_thin_file(fd, offset, size, filetype, filename, 
+                            out_stack_start, out_stack_end, 
+                            out_text, out_entry, out_linker_entry);
+   } else if (magic == VG_(htonl)(FAT_MAGIC)) {
+      // fat
+      return load_fat_file(fd, offset, size, filetype, filename, 
+                           out_stack_start, out_stack_end, 
+                           out_text, out_entry, out_linker_entry);
+   } else {
+      // huh?
+      print("bad executable (bad Mach-O magic)\n");
+      return -1;
+   }
+}
+
+
+Bool VG_(match_macho)(Char *hdr, Int len)
+{
+   vki_uint32_t *magic = (vki_uint32_t *)hdr;
+
+   // GrP fixme check more carefully for matching fat arch?
+
+   return (len >= VKI_PAGE_SIZE  &&  
+           (*magic == MAGIC  ||  *magic == VG_(ntohl)(FAT_MAGIC))) 
+      ? True : False;
+}
+
+
+Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info)
+{
+   int err;
+   struct vg_stat sb;
+   vki_uint8_t *stack_start;
+   vki_uint8_t *stack_end;
+   vki_uint8_t *text;
+   vki_uint8_t *entry;
+   vki_uint8_t *linker_entry;
+
+   err = VG_(fstat)(fd, &sb);
+   if (err) {
+      print("couldn't stat executable\n");
+      return VKI_ENOEXEC;
+   }
+   
+   err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name, 
+                        &stack_start, &stack_end, 
+                        &text, &entry, &linker_entry);
+   if (err) return VKI_ENOEXEC;
+
+   // GrP fixme exe_base
+   // GrP fixme exe_end
+   info->entry = (Addr)entry;
+   info->init_ip = (Addr)(linker_entry ? linker_entry : entry);
+   info->brkbase = 0xffffffff; // GrP fixme hack
+   info->init_toc = 0; // GrP fixme unused
+
+   info->stack_start = (Addr)stack_start;
+   info->stack_end = (Addr)stack_end;
+   info->text = (Addr)text;
+   info->dynamic = linker_entry ? True : False;
+
+   info->executable_path = VG_(strdup)("ume.macho.executable_path", name);
+
+   return 0;
+}
+
+#endif   // defined(HAVE_MACHO)
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
+
diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c
index a32bec7..1673fc9 100644
--- a/coregrind/m_ume/main.c
+++ b/coregrind/m_ume/main.c
@@ -58,6 +58,9 @@
 #  if defined(HAVE_SCRIPT)
    { "script", VG_(match_script), VG_(load_script) },
 #  endif
+#  if defined(HAVE_MACHO)
+   { "Mach-O", VG_(match_macho),  VG_(load_macho) },
+#  endif
 };
 #define EXE_HANDLER_COUNT (sizeof(exe_handlers)/sizeof(exe_handlers[0]))
 
diff --git a/coregrind/m_ume/priv_ume.h b/coregrind/m_ume/priv_ume.h
index ce5f090..ca3f95b 100644
--- a/coregrind/m_ume/priv_ume.h
+++ b/coregrind/m_ume/priv_ume.h
@@ -42,6 +42,11 @@
 extern Int  VG_(load_script)  ( Int fd, const HChar *name, ExeInfo *info );
 #endif
 
+#if defined(HAVE_MACHO)
+extern Bool VG_(match_macho) ( Char *hdr, Int len );
+extern Int  VG_(load_macho)  ( Int fd, const HChar *name, ExeInfo *info );
+#endif
+
 #endif /* __PRIV_UME_H */
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_vki.c b/coregrind/m_vki.c
index 25beafb..9a4c3ef 100644
--- a/coregrind/m_vki.c
+++ b/coregrind/m_vki.c
@@ -77,6 +77,12 @@
 
 #  if defined(VGO_linux) || defined(VGO_aix5)
    /* nothing to check */
+#  elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+   vg_assert(_VKI_NSIG == NSIG);
+   vg_assert(_VKI_NSIG == 32);
+   vg_assert(_VKI_NSIG_WORDS == 1);
+   vg_assert(sizeof(sigset_t) /* defined by Darwin */ 
+             == sizeof(vki_sigset_t) /* what we actually use */);
 #  else
 #    error "Unknown plat"
 #  endif
@@ -87,6 +93,39 @@
    /* the toK- and fromK- forms are identical */
    vg_assert( sizeof(vki_sigaction_toK_t) 
               == sizeof(vki_sigaction_fromK_t) );
+#  elif defined(VGO_darwin)
+   /* the toK- and fromK- forms differ by one function-pointer field
+      (sa_tramp) */
+   vg_assert( sizeof(vki_sigaction_toK_t) 
+              == sizeof(vki_sigaction_fromK_t) + sizeof(void*) );
+
+   vg_assert(sizeof(struct sigaction) == sizeof(vki_sigaction_fromK_t));
+   vg_assert(sizeof(struct __sigaction) == sizeof(vki_sigaction_toK_t));
+   { struct __sigaction    t1;
+     vki_sigaction_toK_t   t2;
+     struct sigaction      f1;
+     vki_sigaction_fromK_t f2;
+     vg_assert(sizeof(t1.sa_handler) == sizeof(t2.ksa_handler));
+     vg_assert(sizeof(t1.sa_tramp)   == sizeof(t2.sa_tramp));
+     vg_assert(sizeof(t1.sa_mask)    == sizeof(t2.sa_mask));
+     vg_assert(sizeof(t1.sa_flags)   == sizeof(t2.sa_flags));
+     vg_assert(sizeof(f1.sa_handler) == sizeof(f2.ksa_handler));
+     vg_assert(sizeof(f1.sa_mask)    == sizeof(f2.sa_mask));
+     vg_assert(sizeof(f1.sa_flags)   == sizeof(f2.sa_flags));
+#    if 0
+     vg_assert(offsetof(t1,sa_handler) == offsetof(t2.ksa_handler));
+     vg_assert(offsetof(t1.sa_tramp)   == offsetof(t2.sa_tramp));
+     vg_assert(offsetof(t1.sa_mask)    == offsetof(t2.sa_mask));
+     vg_assert(offsetof(t1.sa_flags)   == offsetof(t2.sa_flags));
+     vg_assert(offsetof(f1.sa_handler) == offsetof(f2.ksa_handler));
+     vg_assert(offsetof(f1.sa_mask)    == offsetof(f2.sa_mask));
+     vg_assert(offsetof(f1.sa_flags)   == offsetof(f2.sa_flags));
+#    endif
+   }
+   /* also .. */
+   /* VKI_SET_SIGMASK is hardwired into syscall-x86-darwin.S and
+      syscall-amd64-darwin.S */
+   vg_assert(VKI_SIG_SETMASK == 3);
 
 #  else
 #     error "Unknown OS" 
diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h
index c47120f..372b923 100644
--- a/coregrind/pub_core_aspacemgr.h
+++ b/coregrind/pub_core_aspacemgr.h
@@ -120,7 +120,6 @@
 extern Bool VG_(am_do_sync_check) ( const HChar* fn, 
                                     const HChar* file, Int line );
 
-
 //--------------------------------------------------------------
 // Functions pertaining to the central query-notify mechanism
 // used to handle mmap/munmap/mprotect resulting from client
@@ -250,6 +249,8 @@
    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_named_file_fixed_client)
+   ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name );
 
 /* Map anonymously at a fixed address for the client, and update
    the segment array accordingly. */
@@ -400,6 +401,22 @@
 
 extern Int VG_(am_get_VgStack_unused_szB)( VgStack* stack ); 
 
+// DDD: this is ugly
+#if defined(VGO_darwin)
+typedef 
+   struct {
+      Bool   is_added;  // Added or removed seg?
+      Addr   start;
+      SizeT  end;
+      UInt   prot;      // Not used for removed segs.
+      Off64T offset;    // Not used for removed segs.
+   }
+   ChangedSeg;
+
+extern void VG_(get_changed_segments)(
+      const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
+      Int css_size, /*OUT*/Int* css_used);
+#endif
 
 #endif   // __PUB_CORE_ASPACEMGR_H
 
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index 6f1c944..b947af1 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -56,7 +56,7 @@
    in later queries to m_debuginfo.  In this case the handle value
    will be one or above.  If the returned value is zero, no debug info
    was read. */
-#if defined(VGO_linux)
+#if defined(VGO_linux)  ||  defined(VGO_darwin)
 extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV );
 
 extern void VG_(di_notify_munmap)( Addr a, SizeT len );
@@ -70,6 +70,7 @@
 #endif
 
 #if defined(VGO_aix5)
+// GrP fixme use this instead for darwin?
 /* AIX5: Very similar, except packaged more neatly.  The supplied
    parameters describe a code segment and its associated data segment,
    that have recently been mapped in -- so we need to read debug info
diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h
index 9e9416b..4c4e09d 100644
--- a/coregrind/pub_core_initimg.h
+++ b/coregrind/pub_core_initimg.h
@@ -60,7 +60,6 @@
 extern 
 void VG_(ii_finalise_image)( IIFinaliseImageInfo );
 
-
 /* Note that both IICreateImageInfo and IIFinaliseImageInfo are
    OS-specific.  We now go on to give instantiations of them
    for supported OSes. */
@@ -169,6 +168,37 @@
    UInt adler32_exp;
 };
 
+
+/* ------------------------- Darwin ------------------------- */
+
+#elif defined(VGO_darwin)
+
+struct _IICreateImageInfo {
+   /* ------ Mandatory fields ------ */
+   HChar*  toolname;
+   Addr    sp_at_startup;
+   Addr    clstack_top;
+   /* ------ Per-OS fields ------ */
+   HChar** argv;
+   HChar** envp;
+   Addr    entry;            /* &_start */
+   Addr    init_ip;          /* &__dyld_start, or copy of entry */
+   Addr    stack_start;      /* stack segment hot */
+   Addr    stack_end;        /* stack segment cold */
+   Addr    text;             /* executable's Mach header */
+   Bool    dynamic;          /* False iff executable is static */
+   HChar*  executable_path;  /* path passed to execve() */
+};
+
+struct _IIFinaliseImageInfo {
+   /* ------ Mandatory fields ------ */
+   SizeT clstack_max_size;
+   Addr  initial_client_SP;
+   /* ------ Per-OS fields ------ */
+   Addr  initial_client_IP;
+};
+
+
 #else
 #  error "Unknown OS"
 #endif
diff --git a/coregrind/pub_core_mach.h b/coregrind/pub_core_mach.h
new file mode 100644
index 0000000..719df44
--- /dev/null
+++ b/coregrind/pub_core_mach.h
@@ -0,0 +1,48 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Mach kernel interface module.                pub_core_mach.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2005 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307, USA.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_MACH_H
+#define __PUB_CORE_MACH_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module contains the Mach kernel interface, 
+// for operating systems like Darwin / Mac OS X that use it.
+//--------------------------------------------------------------------
+
+#if defined(VGO_darwin)
+// Call this early in Valgrind's main(). It depends on nothing.
+extern void VG_(mach_init)(void);
+#endif
+
+#endif   // __PUB_CORE_MACH_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index 6b6734b..be47cdc 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -65,6 +65,11 @@
 #  undef  VG_ELF_MACHINE
 #  undef  VG_ELF_CLASS
 #  define VG_PLAT_USES_PPCTOC 1
+#elif defined(VGO_darwin)
+#  undef  VG_ELF_DATA2XXX
+#  undef  VG_ELF_MACHINE
+#  undef  VG_ELF_CLASS
+#  undef  VG_PLAT_USES_PPCTOC
 #else
 #  error Unknown platform
 #endif
diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h
index 5bf2088..8229ec8 100644
--- a/coregrind/pub_core_mallocfree.h
+++ b/coregrind/pub_core_mallocfree.h
@@ -73,15 +73,18 @@
       defined(VGP_ppc32_linux) || \
       defined(VGP_ppc32_aix5)
 #  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.
 #elif defined(VGP_amd64_linux) || \
       defined(VGP_ppc64_linux) || \
-      defined(VGP_ppc64_aix5)
+      defined(VGP_ppc64_aix5)  || \
+      defined(VGP_x86_darwin)  || \
+      defined(VGP_amd64_darwin)
 #  define VG_MIN_MALLOC_SZB       16
 #else
 #  error Unknown platform
 #endif
 
-
 /* This struct definition MUST match the system one. */
 /* SVID2/XPG mallinfo structure */
 struct vg_mallinfo {
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 486cf94..73f4a63 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -182,6 +182,10 @@
    so they can be properly handled by m_syswrap. */
 extern HChar* VG_(clo_kernel_variant);
 
+/* Darwin-specific: automatically run /usr/bin/dsymutil to update
+   .dSYM directories as necessary? */
+extern Bool VG_(clo_auto_run_dsymutil);
+
 /* --------- Functions --------- */
 
 /* Call this if the executable is missing.  This function prints an
diff --git a/coregrind/pub_core_scheduler.h b/coregrind/pub_core_scheduler.h
index 029472b..b295a13 100644
--- a/coregrind/pub_core_scheduler.h
+++ b/coregrind/pub_core_scheduler.h
@@ -59,6 +59,11 @@
    thread. */
 extern void VG_(acquire_BigLock) ( ThreadId tid, HChar* who );
 
+/* Simple version, which simply acquires the lock, but does not mess
+   with the guest state in the same way as the non _LL version
+   does. */
+extern void VG_(acquire_BigLock_LL) ( HChar* who );
+
 /* Set a thread into a sleeping state.  Before the call, the thread
    must be runnable, and holding the CPU lock.  When this call
    returns, the thread will be set to the specified sleeping state,
@@ -67,9 +72,14 @@
    caller must be careful not to touch any shared state.  It is also
    the caller's responsibility to actually block until the thread is
    ready to run again. */
-extern void VG_(release_BigLock) ( ThreadId tid, ThreadStatus state, HChar* who );
+extern void VG_(release_BigLock) ( ThreadId tid,
+                                   ThreadStatus state, HChar* who );
 
-/* Yield the CPU for a while */
+/* Matching function to acquire_BigLock_LL. */
+extern void VG_(release_BigLock_LL) ( HChar* who );
+
+/* Yield the CPU for a while.  Drops/acquires the lock using the
+   normal (non _LL) functions. */
 extern void VG_(vg_yield)(void);
 
 // The scheduler.
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index b4fd04e..aa1d68d 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -75,6 +75,10 @@
 extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so );
 extern SysRes VG_(mk_SysRes_ppc32_aix5)  ( UInt val, UInt err );
 extern SysRes VG_(mk_SysRes_ppc64_aix5)  ( ULong val, ULong err );
+extern SysRes VG_(mk_SysRes_x86_darwin)  ( UChar scclass, Bool isErr,
+                                           UInt wHI, UInt wLO );
+extern SysRes VG_(mk_SysRes_amd64_darwin)( UChar scclass, Bool isErr,
+                                           ULong wHI, ULong wLO );
 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 89f0d8c..43428f6 100644
--- a/coregrind/pub_core_syswrap.h
+++ b/coregrind/pub_core_syswrap.h
@@ -40,7 +40,7 @@
 // as if the thread had been set up by clone()
 extern void VG_(main_thread_wrapper_NORETURN)(ThreadId tid);
 
-extern void VG_(client_syscall) ( ThreadId tid );
+extern void VG_(client_syscall) ( ThreadId tid, UInt trc );
 
 extern void VG_(post_syscall)   ( ThreadId tid );
 
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index e7bde55..51b4adf 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -87,6 +87,9 @@
 #  error Unknown architecture
 #endif
 
+/* Forward declarations */
+struct SyscallStatus;
+struct SyscallArgs;
 
 /* Architecture-specific thread state */
 typedef 
@@ -120,7 +123,7 @@
 typedef
    struct {
       /* who we are */
-      Int lwpid;        // PID of kernel task
+      Int lwpid;        // PID of kernel task  (Darwin: Mach thread)
       Int threadgroup;  // thread group id
 
       ThreadId parent;  // parent tid (if any)
@@ -146,6 +149,135 @@
            cancel_progress;
       /* Initial state is False, False, Canc_Normal. */
 #     endif
+
+#     if defined(VGO_darwin)
+      // Mach trap POST handler as chosen by PRE
+      void (*post_mach_trap_fn)(ThreadId tid,
+                                struct SyscallArgs *, struct SyscallStatus *);
+    
+      // This thread's pthread
+      Addr pthread;
+    
+      // Argument passed when thread started
+      Addr func_arg;
+
+      // Synchronization between child thread and parent thread's POST wrapper
+      semaphore_t child_go;
+      semaphore_t child_done;
+
+      // Workqueue re-entry 
+      // (setjmp in PRE(workq_ops), longjmp in wqthread_hijack)
+      // DDD: JRS fixme: this comment is no longer correct; wq_jmpbuf is
+      // never used, and there is no such setjmp or longjmp pair.
+      // I guess we could leave wq_jmpbuf_valid in place though, since
+      // it does allow for an assertion in ML_(wqthread_continue_NORETURN).
+      Bool wq_jmpbuf_valid;
+      //jmp_buf wq_jmpbuf;
+
+      // Values saved from transient Mach RPC messages
+      Addr remote_port;  // destination for original message
+      Int msgh_id;       // outgoing message id
+      union {
+         struct {
+            Addr port;
+         } mach_port;
+         struct {
+            Int right;
+         } mach_port_allocate;
+         struct {
+            Addr port;
+            Int right;
+            Int delta;
+         } mach_port_mod_refs;
+         struct {
+            Addr task;
+            Addr name;
+            Int disposition;
+         } mach_port_insert_right;
+         struct {
+            Addr size;
+            int flags;
+         } vm_allocate;
+         struct {
+            Addr address;
+            Addr size;
+         } vm_deallocate;
+         struct {
+            Addr src;
+            Addr dst;
+            Addr size;
+         } vm_copy;
+         struct {
+            Addr address;
+            Addr size;
+            int set_maximum;
+            UWord new_protection;
+         } vm_protect;
+         struct {
+            Addr addr;
+            SizeT size;
+         } vm_read;
+         struct {
+            ULong addr;
+            ULong size;
+         } mach_vm_read;
+         struct {
+            Addr addr;
+            SizeT size;
+            Addr data;
+         } vm_read_overwrite;
+         struct {
+            Addr size;
+            int copy;
+            UWord protection;
+         } vm_map;
+         struct {
+            Addr size;
+         } vm_remap;
+         struct {
+            ULong size;
+            int flags;
+         } mach_vm_allocate;
+         struct {
+            ULong address;
+            ULong size;
+         } mach_vm_deallocate;
+         struct {
+            ULong address;
+            ULong size;
+            int set_maximum;
+            unsigned int new_protection;
+         } mach_vm_protect;
+         struct {
+            ULong size;
+            int copy;
+            UWord protection;
+         } mach_vm_map;
+         struct {
+            Addr thread;
+            UWord flavor;
+         } thread_get_state;
+         struct {
+            Addr address;
+         } io_connect_unmap_memory;
+         struct {
+            int which_port;
+         } task_get_special_port;
+         struct {
+            char *service_name;
+         } bootstrap_look_up;
+         struct {
+            vki_size_t size;
+         } WindowServer_29828;
+         struct {
+            Int access_rights;
+         } WindowServer_29831;
+         struct {
+            char *path;
+         } io_registry_entry_from_path;
+      } mach_args;
+#     endif
+
    }
    ThreadOSstate;
 
@@ -238,6 +370,7 @@
 // to write to this.
 extern ThreadId VG_(running_tid);
 
+
 /*------------------------------------------------------------*/
 /*--- Basic operations on the thread table.                ---*/
 /*------------------------------------------------------------*/
diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h
index cbda7ab..c8c6520 100644
--- a/coregrind/pub_core_trampoline.h
+++ b/coregrind/pub_core_trampoline.h
@@ -112,6 +112,16 @@
 extern void VG_(ppc64_aix5_do_preloads_then_start_client);
 #endif
 
+#if defined(VGO_darwin)
+extern void  VG_(x86_darwin_SUBST_FOR_sigreturn);
+extern SizeT VG_(darwin_REDIR_FOR_strlen)( void* );
+extern SizeT VG_(darwin_REDIR_FOR_strcmp)( void*, void* );
+extern void* VG_(darwin_REDIR_FOR_strcat)( void*, void * );
+extern char* VG_(darwin_REDIR_FOR_strcpy)( char *s1, char *s2 );
+extern SizeT VG_(darwin_REDIR_FOR_strlcat)( char *s1, const char *s2, SizeT size );
+extern UInt VG_(darwin_REDIR_FOR_arc4random)( void );
+#endif
+
 #endif   // __PUB_CORE_TRAMPOLINE_H
 
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_ume.h b/coregrind/pub_core_ume.h
index cf7b1ad..b6e59e5 100644
--- a/coregrind/pub_core_ume.h
+++ b/coregrind/pub_core_ume.h
@@ -43,6 +43,10 @@
 #elif defined(VGO_aix5)
 // The AIX port doesn't use UME.
 
+#elif defined(VGO_darwin)
+#  define HAVE_MACHO
+#  define HAVE_SCRIPT
+
 #else
 #error unknown architecture
 #endif
@@ -60,9 +64,18 @@
       Addr exe_base;     // INOUT: lowest (allowed) address of exe
       Addr exe_end;      // INOUT: highest (allowed) address
 
+#if !defined(VGO_darwin)
       Addr phdr;         // OUT: address phdr was mapped at
       Int  phnum;        // OUT: number of phdrs
       Addr interp_base;  // OUT: where interpreter (ld.so) was mapped
+#else
+      Addr  stack_start;      // OUT: address of start of stack segment (hot)
+      Addr  stack_end;        // OUT: address of end of stack segment (cold)
+      Addr  text;             // OUT: address of executable's Mach header
+      Bool  dynamic;          // OUT: False iff executable is static
+      char* executable_path;  // OUT: path passed to execve()
+#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/pub_core_vkiscnums.h b/coregrind/pub_core_vkiscnums.h
index 4cedf37..4ce09d8 100644
--- a/coregrind/pub_core_vkiscnums.h
+++ b/coregrind/pub_core_vkiscnums.h
@@ -54,6 +54,17 @@
    successful, False if the name is unknown. */
 extern Bool VG_(aix5_register_syscall)( Int, UChar* );
 
+#elif defined(VGO_darwin)
+
+/* Convert a syscall number into a nicer form(?) */
+#if defined(VGA_x86)
+#  define VG_DARWIN_SYSNO_NUM(sysno) VG_DARWIN_SYSNO_PRINT(sysno)
+#elif defined(VGA_amd64)
+#  define VG_DARWIN_SYSNO_NUM(sysno) (sysno)
+#else
+#  error unknown arch
+#endif
+
 #else
 #  error Unknown OS
 #endif // defined(VGO_*)
diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c
index 3539832..6f0f049 100644
--- a/coregrind/vg_preloaded.c
+++ b/coregrind/vg_preloaded.c
@@ -51,6 +51,8 @@
    Hook for running __libc_freeres once the program exits.
    ------------------------------------------------------------------ */
 
+#if defined(VGO_linux) || defined(VGO_aix5)
+
 void VG_NOTIFY_ON_LOAD(freeres)( void );
 void VG_NOTIFY_ON_LOAD(freeres)( void )
 {
@@ -66,6 +68,94 @@
    *(int *)0 = 'x';
 }
 
+#elif defined(VGO_darwin)
+
+/* ---------------------------------------------------------------------
+   Darwin crash log hints
+   ------------------------------------------------------------------ */
+
+/* This string will be inserted into crash logs, so crashes while 
+   running under Valgrind can be distinguished from other crashes. */
+__private_extern__ char *__crashreporter_info__ = "Instrumented by Valgrind " VERSION;
+
+/* ---------------------------------------------------------------------
+   Darwin environment cleanup
+   ------------------------------------------------------------------ */
+
+/* Scrubbing DYLD_INSERT_LIBRARIES from envp during exec is insufficient, 
+   as there are other ways to launch a process with environment that 
+   valgrind can't catch easily (i.e. launchd). 
+   Instead, scrub DYLD_INSERT_LIBRARIES from the parent process once 
+   dyld is done loading vg_preload.so.
+*/
+#include <string.h>
+#include <crt_externs.h>
+
+// GrP fixme copied from m_libcproc
+static void env_unsetenv ( Char **env, const Char *varname )
+{
+   Char **from;
+   Char **to = NULL;
+   Int len = strlen(varname);
+
+   for (from = to = env; from && *from; from++) {
+      if (!(strncmp(varname, *from, len) == 0 && (*from)[len] == '=')) {
+	 *to = *from;
+	 to++;
+      }
+   }
+   *(to++) = *(from++);
+   /* fix the 4th "char* apple" pointer (aka. executable path pointer) */
+   *(to++) = *(from++);
+   *to = NULL;
+}
+
+static void vg_cleanup_env(void)  __attribute__((constructor));
+static void vg_cleanup_env(void)
+{
+    Char **envp = (Char**)*_NSGetEnviron();
+    env_unsetenv(envp, "VALGRIND_LAUNCHER");
+    env_unsetenv(envp, "DYLD_SHARED_REGION");
+    // GrP fixme should be more like mash_colon_env()
+    env_unsetenv(envp, "DYLD_INSERT_LIBRARIES");
+}   
+
+/* ---------------------------------------------------------------------
+   Darwin arc4random (rdar://6166275)
+   ------------------------------------------------------------------ */
+
+#include <stdio.h>
+
+int VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random)(void);
+int VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random)(void)
+{
+    static FILE *rnd = 0;
+    int result;
+
+    if (!rnd) rnd = fopen("/dev/random", "r");
+    
+    fread(&result, sizeof(result), 1, rnd);
+    return result;
+}
+
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_stir)(void);
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_stir)(void)
+{
+    // do nothing
+}
+
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned char *dat, int datlen);
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned char *dat, int datlen)
+{
+    // do nothing
+    // GrP fixme ought to check [dat..dat+datlen) is defined
+    // but don't care if it's initialized
+}
+
+#else
+
+#  error Unknown OS
+#endif
 
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
diff --git a/darwin9.supp b/darwin9.supp
new file mode 100644
index 0000000..74c31e3
--- /dev/null
+++ b/darwin9.supp
@@ -0,0 +1,167 @@
+
+##----------------------------------------------------------------------##
+#
+# Suppressions for Darwin 9.x / Mac OS X 10.5 Leopard
+#
+
+{
+   mach_msg_trap-1
+   Memcheck:Param
+   mach_msg(msg.msgh_remote_port)
+   fun:mach_msg_trap
+   obj:/System/Library/Frameworks/CoreFoundation*
+   obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+   mach_msg_trap-2
+   Memcheck:Param
+   mach_msg(msg.msgh_remote_port)
+   fun:mach_msg_trap
+   obj:/System/Library/Frameworks/CoreFoundation*
+   obj:/System/Library/Frameworks/CoreServices*
+}
+
+{
+   mach_msg_trap-3
+   Memcheck:Param
+   mach_msg(msg.msgh_remote_port)
+   fun:mach_msg_trap
+   obj:/System/Library/Frameworks/CoreFoundation*
+   obj:/System/Library/Frameworks/Carbon*
+}
+
+{
+   mach_msg_trap-4
+   Memcheck:Param
+   mach_msg(msg.msgh_remote_port)
+   fun:mach_msg_trap
+   obj:/System/Library/Frameworks/CoreFoundation*
+   obj:/System/Library/Frameworks/CoreFoundation*
+}
+
+{
+   mach_msg_trap-5
+   Memcheck:Param
+   mach_msg(msg.msgh_remote_port)
+   fun:mach_msg_trap
+   obj:/System/Library/Frameworks/CoreFoundation*
+   obj:/System/Library/Frameworks/AppKit*
+}
+
+{
+   macos-Cond-1
+   Memcheck:Cond
+   fun:GetVariationInfoFromName
+   obj:/System/Library/Frameworks/ApplicationServices*
+   obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+   macos-Cond-2
+   Memcheck:Cond
+   fun:*PMMutex*Lock*
+   obj:/System/Library/Frameworks/ApplicationServices*
+   obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+   macos-Cond-3
+   Memcheck:Cond
+   fun:sseCGSBlendXXXX8888
+   obj:/System/Library/Frameworks/ApplicationServices*
+   obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+   macos-Cond-4
+   Memcheck:Cond
+   fun:*CASettingsStorage*RefreshSettings*
+   obj:/System/Library/Frameworks/CoreAudio*
+   obj:/System/Library/Frameworks/CoreAudio*
+}
+
+{
+   macos-Cond-5
+   Memcheck:Cond
+   fun:gle*
+   obj:/System/Library/Frameworks/OpenGL*
+   obj:/System/Library/Frameworks/OpenGL*
+}
+
+{
+   futimes-1
+   Memcheck:Param
+   futimes(tvp[1])
+   fun:futimes
+   obj:/usr/lib/libSystem*
+   obj:/usr/lib/libSystem*
+}
+
+##----------------------------------------------------------------------##
+#
+# Suppressions for Helgrind.
+
+# These ones were necessary to give no errors on a tiny non-threaded
+# program.  I don't know if they're real problems or false positives (njn).
+
+# keymgr seems to deliberately do some bogus actions, and if they are bogus,
+# it passes the error codes back to the caller.
+{
+   __keymgr_initializer lock failed
+   Helgrind:PthAPIerror
+   fun:pthread_mutex_lock
+   fun:_dyld_register_func_for_*_image
+   fun:__keymgr_initializer
+   fun:libSystem_initializer
+}
+{
+   __keymgr_initializer unlock failed
+   Helgrind:PthAPIerror
+   fun:pthread_mutex_unlock
+   fun:_dyld_register_func_for_*_image
+   fun:__keymgr_initializer
+   fun:libSystem_initializer
+}
+{
+   __keymgr_initializer bogus unlock
+   Helgrind:UnlockBogus
+   fun:pthread_mutex_unlock
+   fun:_dyld_register_func_for_*_image
+   fun:__keymgr_initializer
+   fun:libSystem_initializer
+}
+
+# These ones were necessary to give no errors on a tiny threaded program.
+# I don't know if they're real problems or false positives (njn).
+
+{
+   crude1
+   Helgrind:Race
+   obj:/usr/lib/dyld
+}
+{
+   crude2
+   Helgrind:Race
+   obj:/usr/lib/libSystem.B.dylib
+}
+# This would be better as "fun:\?\?\?" but string matching doesn't seem to
+# allow escaping meta-chars.
+{
+   crude3
+   Helgrind:Race
+   fun:???
+}
+{
+   crude4
+   Helgrind:Race
+   fun:mythread_wrapper
+}
+{
+   crude5
+   Helgrind:Race
+   ...
+   fun:pthread_create_WRK
+   fun:pthread_create
+}
+
diff --git a/docs/internals/Darwin-notes.txt b/docs/internals/Darwin-notes.txt
new file mode 100644
index 0000000..f526c4f
--- /dev/null
+++ b/docs/internals/Darwin-notes.txt
@@ -0,0 +1,136 @@
+
+Valgrind-developer notes, re the MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+JRS 22 Mar 09: re these comments in m_libc* and m_debuglog:
+
+/* 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
+   why. */
+
+when Valgrind does (for its own purposes, not for the client)
+read/write/open/close etc syscalls, it really is critical to use the
+_nocancel versions of syscalls rather than the vanilla versions.  This
+holds throughout the entire code base: whenever V does a syscall for
+its own purposes, we must use the _nocancel version if it exists.
+This is of course most prevalent in m_libc* since all of our
+own-purpose (non-client) syscalls should get routed through there.
+
+Why?  Because on Darwin, pthread cancellation is done within the
+kernel (unlike on Linux, iiuc).  And read/write/open/close and a whole
+bunch of other syscalls to do with stream I/O are cancellation points.
+So what can happen is, client informs the kernel that a given thread
+is to be cancelled.  Then at the next (eg) VG_(printf) call by that
+thread, which leads to a sys_write, the write syscall gets hit by the
+cancellation request, and is duly nuked by the kernel.  Of course from
+the outside it looks as if the thread had mysteriously disappeared off
+the radar for no reason.
+
+In short, we need to use _nocancel versions in order to ensure that
+cancellation requests only take effect at the places where the client
+does a syscall, and not the places where Valgrind does syscalls.
+
+How observed: using the standard pipe-based implementation in
+coregrind/m_scheduler/sema.c, none/tests/pth_cancel1 would hang
+(compared to succeeding using native Darwin semaphores).  And if the
+"pause()" call in said test is turned into a spin ("while (1) ;") then
+the entire Valgrind run mysteriously disappears, rather than spinning
+using native Darwin semaphores.
+
+Because the pipe-based semaphore intensively uses sys_read/sys_write,
+it is not surprising that it inadvertantly was eating up cancellation
+requests directed to client threads.  With abovementioned change in
+force the pipe-based semaphore appears to work correctly.
+
+
+
+Valgrind-developer notes, things removed from the original MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There was a broken debugstub implementation.  It was removed over several
+commits: r9477, which removed most of it, and r9711, r9759, and r10012,
+which cleaned up remaining bits.
+
+There was machinery to read function names from Dwarf3 debug info.  But we
+already read function names from the symbol tables, so this was duplicated
+functionality.  Furthermore, a Darwin-specific hack was required in
+storage.c to choose between symbol table names vs. Dwarf3 names.  So this
+machinery was removed in r10155.
+
+
+Valgrind-developer notes, todos re the MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* m_syswrap/syscall-amd64-darwin.S
+  - correct signal mask is not applied during syscall
+  - restart-labels are completely bogus
+
+* m_syswrap/syswrap-darwin.c:
+  - PRE(sys_posix_spawn) completely ignores signal issues, and
+    also ignores the file_actions argument
+
+* env var handling w/ exec on Darwin: is there something odd?  Compare
+  "valgrind env" on Darwin and Linux.  On the former there are
+  settings VALGRIND_LIB and VALGRIND_LIB_INNER, but not for the
+  former.
+  There's a suspicious-looking "#if defined(VGO_darwin)" in 
+  VG_(env_remove_valgrind_env_stuff).  Maybe related?
+
+* Cleanups: sort wrappers in syswrap-darwin.c and priv_syswrap-darwin.h
+  alphabetically.  Also, some aren't properly implemented -- check and
+  print warnings
+
+* Cleanups: m_scheduler/sema.c: use pipe implementation
+  (but this apparently causes none/tests/pth_cancel1 to hang.
+  I have no idea why, despite quite some investigation).
+
+* Cleanups: m_debugstub: move to attic
+
+* syswrap-darwin.c: sys_{f,}chmod_extended: handling of ARG5 is way
+  wrong
+
+* Cleanups (Linux,AIX5): bogus launcher-path mangling logic in
+  PRE(sys_execve)
+
+* Cleanups (ALL PLATFORMS): m_signals.c: are the _MY_SIGRETURN
+  assembly stubs actually necessary for anything?  I don't know.
+
+* Cleanups: check that changes to VG_(stat) and VG_(stat64) have
+  not broken 64-bit statting on 32-bit Linux
+
+* Cleanups: #if !HAVE_PROC in m_main (to do with /proc/<pid>/cmdline
+
+--------
+
+m_main doesn't read symbols for the valgrind exe itself, which is
+annoying.  On minimal investigation it seems that the executable isn't
+even listed by aspacem.  This is very strange and not in accordance
+with the Linux or AIX ports.
+
+
+m_main: relatedly, Darwin version does not collect/give out
+initial debuginfo handles; hence ptrcheck won't work
+
+
+m_main: Darwin port relies on blocking out big sections of address
+space with mmap at startup.  We know from history that this is a bad
+idea.  (It's also really slow on 64-bit builds, taking 3--4 seconds.)
+Also, startup is not done on the interim startup stack -- why not?
+
+
+VG_(di_notify_mmap): Linux version is also used for Darwin, and
+contains some ifdeffery.  Clean up.
+
+
+PRE(sys_fork), #ifdeffery
+
+
+syswrap-generic.c: VG_(init_preopened_fds) is #ifdefd for Darwin
+
+
+scheduler.c: #ifdeffery in VG_(get_thread_out_of_syscall)
+
+
+look at notes in coregrind/Makefile.am re Mach RPC interface
+definitions.  See if we can get rid of any more stuff now that
+m_debugstub is gone.
diff --git a/docs/internals/Makefile.am b/docs/internals/Makefile.am
index 1f82a67..76fed03 100644
--- a/docs/internals/Makefile.am
+++ b/docs/internals/Makefile.am
@@ -3,6 +3,7 @@
 	3_2_BUGSTATUS.txt 3_3_BUGSTATUS.txt \
 	3_4_BUGSTATUS.txt \
 	BIG_APP_NOTES.txt \
+	Darwin-notes.txt \
 	directory-structure.txt \
 	howto_BUILD_KDE42.txt \
 	howto_oprofile.txt \
diff --git a/drd/Makefile.am b/drd/Makefile.am
index 18a8844..84655f2 100644
--- a/drd/Makefile.am
+++ b/drd/Makefile.am
@@ -1,6 +1,7 @@
 include $(top_srcdir)/Makefile.tool.am
 
 noinst_PROGRAMS =
+noinst_DSYMS =
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
   noinst_PROGRAMS += drd-x86-linux   vgpreload_drd-x86-linux.so
 endif
@@ -19,6 +20,14 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
   noinst_PROGRAMS += drd-ppc64-aix5  vgpreload_drd-ppc64-aix5.so
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+  noinst_PROGRAMS += drd-x86-darwin  vgpreload_drd-x86-darwin.so
+  noinst_DSYMS    +=                 vgpreload_drd-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+  noinst_PROGRAMS += drd-amd64-darwin vgpreload_drd-amd64-darwin.so
+  noinst_DSYMS    +=                  vgpreload_drd-amd64-darwin.so
+endif
 
 
 VGPRELOAD_DRD_SOURCES =    \
@@ -91,6 +100,22 @@
 vgpreload_drd_ppc64_aix5_so_LDFLAGS      = $(PRELOAD_LDFLAGS_PPC64_AIX5)\
                                         $(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
+vgpreload_drd_x86_darwin_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES)
+vgpreload_drd_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_drd_x86_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_LDFLAGS      = $(PRELOAD_LDFLAGS_X86_DARWIN)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_drd_amd64_darwin_so_SOURCES      = $(VGPRELOAD_DRD_SOURCES)
+vgpreload_drd_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_drd_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_drd_amd64_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_drd_amd64_darwin_so_DEPENDENCIES =
+vgpreload_drd_amd64_darwin_so_LDFLAGS      = $(PRELOAD_LDFLAGS_AMD64_DARWIN)\
+                                        $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
 
 DRD_SOURCES =           \
   drd_barrier.c         \
@@ -175,3 +200,19 @@
 drd_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 drd_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 drd_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+drd_x86_darwin_SOURCES        = $(DRD_SOURCES)
+drd_x86_darwin_CPPFLAGS       = $(AM_CPPFLAGS_X86_DARWIN)
+drd_x86_darwin_CFLAGS         = $(AM_CFLAGS_X86_DARWIN)
+drd_x86_darwin_DEPENDENCIES   = $(COREGRIND_LIBS_X86_DARWIN)
+drd_x86_darwin_LDADD          = $(TOOL_LDADD_X86_DARWIN)
+drd_x86_darwin_LDFLAGS        = $(TOOL_LDFLAGS_X86_DARWIN)
+
+drd_amd64_darwin_SOURCES      = $(DRD_SOURCES)
+drd_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+drd_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+drd_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+drd_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+drd_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
+
diff --git a/drd/drd_main.c b/drd/drd_main.c
index 0dfb00a..3cc6348 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -607,8 +607,13 @@
 static
 void drd_pre_clo_init(void)
 {
-   // Basic tool stuff.
+#if defined(VGO_darwin)
+   // This makes the (all-failing) regtests run much faster.
+   VG_(printf)("DRD doesn't work on Darwin yet, sorry.\n");
+   VG_(exit)(1);
+#endif
 
+   // Basic tool stuff.
    VG_(details_name)            ("drd");
    VG_(details_version)         (NULL);
    VG_(details_description)     ("a thread error detector");
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
index f77569d..db33fbd 100644
--- a/drd/drd_pthread_intercepts.c
+++ b/drd/drd_pthread_intercepts.c
@@ -643,6 +643,7 @@
 }
 
 
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
 // pthread_spin_init
 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
          pthread_spinlock_t *spinlock,
@@ -723,7 +724,10 @@
                               spinlock, 0, 0, 0, 0);
    return ret;
 }
+#endif   // HAVE_PTHREAD_SPIN_LOCK
 
+
+#if defined(HAVE_PTHREAD_BARRIER_INIT)
 // pthread_barrier_init
 PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
          pthread_barrier_t* barrier,
@@ -775,6 +779,7 @@
                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
    return ret;
 }
+#endif   // HAVE_PTHREAD_BARRIER_INIT
 
 
 // sem_init
diff --git a/drd/tests/recursive_mutex.c b/drd/tests/recursive_mutex.c
index ad79b63..3ddfc25 100644
--- a/drd/tests/recursive_mutex.c
+++ b/drd/tests/recursive_mutex.c
@@ -10,6 +10,7 @@
 #include "../../config.h"
 
 
+#if !defined(VGO_darwin)
 static void lock_twice(pthread_mutex_t* const p)
 {
   pthread_mutex_lock(p);
@@ -17,6 +18,7 @@
   pthread_mutex_unlock(p);
   pthread_mutex_unlock(p);
 }
+#endif
 
 int main(int argc, char** argv)
 {
@@ -60,6 +62,10 @@
     pthread_mutex_destroy(&m);
   }
 #endif
+
+// DDD: Darwin doesn't support signals yet, so the alarm() call doesn't kick
+// in, which causes it to hang.
+#if !defined(VGO_darwin)
   {
     pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
 
@@ -68,5 +74,6 @@
     lock_twice(&m);
   }
   printf("Done.\n");
+#endif
   return 0;
 }
diff --git a/exp-omega/Makefile.am b/exp-omega/Makefile.am
index 6af2f3f..122d8a6 100644
--- a/exp-omega/Makefile.am
+++ b/exp-omega/Makefile.am
@@ -30,6 +30,12 @@
 ##zz if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 ##zz noinst_PROGRAMS += exp-omega-ppc64-aix5 vgpreload_exp-omega-ppc64-aix5.so
 ##zz endif
+##zz if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+##zz noinst_PROGRAMS += exp-omega-x86-darwin vgpreload_exp-omega-x86-darwin.so
+##zz endif
+##zz if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+##zz noinst_PROGRAMS += exp-omega-amd64-darwin vgpreload_exp-omega-amd64-darwin.so
+##zz endif
 ##zz 
 ##zz VGPRELOAD_OMEGA_SOURCES_COMMON = o_replace_memops.c
 ##zz 
@@ -87,6 +93,24 @@
 ##zz 	$(PRELOAD_LDFLAGS_PPC64_AIX5) \
 ##zz 	$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 ##zz 
+##zz vgpreload_exp_omega_x86_darwin_so_SOURCES      = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
+##zz vgpreload_exp_omega_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+##zz vgpreload_exp_omega_x86_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_LDFLAGS      = \
+##zz 	$(PRELOAD_LDFLAGS_X86_DARWIN) \
+##zz 	$(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+##zz 
+##zz vgpreload_exp_omega_amd64_darwin_so_SOURCES      = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
+##zz vgpreload_exp_omega_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+##zz vgpreload_exp_omega_amd64_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_LDFLAGS      = \
+##zz 	$(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+##zz 	$(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+##zz 
 ##zz OMEGA_SOURCES_COMMON = \
 ##zz 	o_main.c
 ##zz 
@@ -138,6 +162,22 @@
 ##zz exp_omega_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 ##zz exp_omega_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
 ##zz 
+##zz exp_omega_x86_darwin_SOURCES      = $(OMEGA_SOURCES_COMMON)
+##zz exp_omega_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+##zz exp_omega_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) -O2
+##zz exp_omega_x86_darwin_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+##zz exp_omega_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+##zz exp_omega_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+##zz exp_omega_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+##zz 
+##zz exp_omega_amd64_darwin_SOURCES      = $(OMEGA_SOURCES_COMMON)
+##zz exp_omega_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) -g -O0 #-O2
+##zz exp_omega_amd64_darwin_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
+##zz 
 ##zz oincludedir = $(includedir)/valgrind
 ##zz 
 ##zz oinclude_HEADERS = exp-omega.h
diff --git a/exp-ptrcheck/Makefile.am b/exp-ptrcheck/Makefile.am
index d4591e3..37b3ef5 100644
--- a/exp-ptrcheck/Makefile.am
+++ b/exp-ptrcheck/Makefile.am
@@ -1,6 +1,7 @@
 include $(top_srcdir)/Makefile.tool.am
 
 noinst_PROGRAMS = 
+noinst_DSYMS =
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 noinst_PROGRAMS += exp-ptrcheck-x86-linux vgpreload_exp-ptrcheck-x86-linux.so
 endif
@@ -19,6 +20,14 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += exp-ptrcheck-ppc64-aix5 vgpreload_exp-ptrcheck-ppc64-aix5.so
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += exp-ptrcheck-x86-darwin vgpreload_exp-ptrcheck-x86-darwin.so
+noinst_DSYMS    +=                         vgpreload_exp-ptrcheck-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += exp-ptrcheck-amd64-darwin vgpreload_exp-ptrcheck-amd64-darwin.so
+noinst_DSYMS    +=                           vgpreload_exp-ptrcheck-amd64-darwin.so
+endif
 
 
 VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON = h_intercepts.c
@@ -77,6 +86,24 @@
 	$(PRELOAD_LDFLAGS_PPC64_AIX5) \
 	$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
+vgpreload_exp_ptrcheck_x86_darwin_so_SOURCES      = $(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
+vgpreload_exp_ptrcheck_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_ptrcheck_x86_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_X86_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_exp_ptrcheck_amd64_darwin_so_SOURCES      = $(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
+vgpreload_exp_ptrcheck_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_ptrcheck_amd64_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
 
 
 EXP_PTRCHECK_SOURCES_COMMON = \
@@ -124,6 +151,20 @@
 exp_ptrcheck_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 exp_ptrcheck_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
 
+exp_ptrcheck_x86_darwin_SOURCES      = $(EXP_PTRCHECK_SOURCES_COMMON)
+exp_ptrcheck_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+exp_ptrcheck_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+exp_ptrcheck_amd64_darwin_SOURCES      = $(EXP_PTRCHECK_SOURCES_COMMON)
+exp_ptrcheck_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
 noinst_HEADERS = h_main.h sg_main.h pc_common.h
 
 EXTRA_DIST = 
diff --git a/exp-ptrcheck/h_main.c b/exp-ptrcheck/h_main.c
index 50f4154..c4342a3 100644
--- a/exp-ptrcheck/h_main.c
+++ b/exp-ptrcheck/h_main.c
@@ -1957,6 +1957,8 @@
    if (is_integer_guest_reg( (Int)offset, (Int)size )) {
       put_guest_intreg( tid, 1, offset, size, (UWord)NONPTR );
    } else {
+      // DDD: on Darwin, this assertion fails because we currently do a
+      // 'post_reg_write' on the 'guest_CC_DEP1' pseudo-register.
       tl_assert(0);
    }
    //   VG_(set_thread_shadow_archreg)( tid, reg, (UInt)NONPTR );
@@ -2127,16 +2129,16 @@
    syscall-specific handling is is required.  No further details of it
    are stored in the table.
 
-   On Linux, 'number' is a __NR_xxx constant.
+   On Linux and Darwin, 'number' is a __NR_xxx constant.
 
    On AIX5, 'number' is an Int*, which points to the Int variable
    holding the currently assigned number for this syscall.
 
    When querying the table, we compare the supplied syscall number
-   with the 'number' field (directly on Linux, after dereferencing on
-   AIX5), to find the relevant entry.  This requires a linear search
-   of the table.  To stop the costs getting too high, the table is
-   incrementally rearranged after each search, to move commonly
+   with the 'number' field (directly on Linux and Darwin, after
+   dereferencing on AIX5), to find the relevant entry.  This requires a
+   linear search of the table.  To stop the costs getting too high, the
+   table is incrementally rearranged after each search, to move commonly
    requested items a bit closer to the front.
 
    The table is built once, the first time it is used.  After that we
@@ -2439,6 +2441,30 @@
       ADD(1, __NR_AIX5_kload); /* not sure what to do here */
       ADD(0, __NR_AIX5_kwrite);
 
+   /* --------------- DARWIN ------------- */
+
+#  elif defined(VGO_darwin)
+
+#     define ADD(_flag, _syscallname) \
+         do { UWordPair p; p.uw1 = (_syscallname); p.uw2 = (_flag); \
+              VG_(addToXA)( post_syscall_table, &p ); \
+         } while (0)
+
+      // DDD: a desultory attempt thus far...
+
+      // Unix/BSD syscalls.
+
+      // Mach traps.
+      ADD(0, __NR_host_self_trap);
+      ADD(0, __NR_mach_msg_trap);
+      ADD(0, __NR_mach_reply_port);
+      ADD(0, __NR_task_self_trap);
+
+      // Machine-dependent syscalls.
+      ADD(0, __NR_pthread_set_self);
+
+   /* ------------------------------------ */
+
 #  else
 #     error "Unsupported OS"
 #  endif
@@ -2459,7 +2485,7 @@
    n = VG_(sizeXA)( post_syscall_table );
    for (i = 0; i < n; i++) {
       pair = VG_(indexXA)( post_syscall_table, i );
-#     if defined(VGO_linux)
+#     if defined(VGO_linux) || defined(VGO_darwin)
       if (pair->uw1 == (UWord)sysno)
          break;
 #     elif defined(VGO_aix5)
@@ -2473,10 +2499,17 @@
    tl_assert(i >= 0 && i <= n);
 
    if (i == n) {
+// DDD: genericise this
+#     if defined(VGO_linux)
       VG_(printf)("sysno == %u\n", sysno);
-#     if defined(VGO_aix5)
+#     elif defined(VGO_aix5)
+      VG_(printf)("sysno == %u\n", sysno);
       VG_(printf)("syscallnm == %s\n",
                   VG_(aix5_sysno_to_sysname)(sysno));
+#     elif defined(VGO_darwin)
+      VG_(printf)("sysno == %d\n", VG_DARWIN_SYSNO_PRINT(sysno));
+#     else
+#        error "Unsupported OS"
 #     endif
       VG_(tool_panic)("unhandled syscall");
    }
diff --git a/exp-ptrcheck/pc_main.c b/exp-ptrcheck/pc_main.c
index 1dfd9a5..6f44bbf 100644
--- a/exp-ptrcheck/pc_main.c
+++ b/exp-ptrcheck/pc_main.c
@@ -144,6 +144,12 @@
 
 static void pc_pre_clo_init(void)
 {
+#if defined(VGO_darwin)
+   // This makes the (all-failing) regtests run much faster.
+   VG_(printf)("Ptrcheck doesn't work on Darwin yet, sorry.\n");
+   VG_(exit)(1);
+#endif
+
    VG_(details_name)            ("exp-ptrcheck");
    VG_(details_version)         (NULL);
    VG_(details_description)     ("a heap, stack & global array "
diff --git a/exp-ptrcheck/tests/Makefile.am b/exp-ptrcheck/tests/Makefile.am
index 5c27f35..6a1d884 100644
--- a/exp-ptrcheck/tests/Makefile.am
+++ b/exp-ptrcheck/tests/Makefile.am
@@ -65,7 +65,7 @@
 	zero.vgtest zero.stderr.exp
 
 check_PROGRAMS = \
-	add and arith bad_percentify base ccc cmp fp \
+	add and arith bad_percentify base cmp fp \
 	globalerr hackedbz2 \
 	hp_bounds hp_dangle idiv imul \
 	justify mm not neg or partial \
@@ -74,6 +74,14 @@
 	stackerr \
 	strcpy strlen sub supp syscall tricky unaligned xor zero
 
+# DDD: not sure if these ones should work on Darwin or not... if not, should
+# be moved into x86-linux/.
+if ! VGCONF_OS_IS_DARWIN
+   check_PROGRAMS += \
+	ccc
+endif
+
+
 AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
@@ -98,11 +106,16 @@
  preen_invars_LDADD            = -ldl
  preen_invars_LDFLAGS          = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ preen_invars_LDADD            = -ldl
+ preen_invars_LDFLAGS          = $(AM_FLAG_M3264_PRI)
+else
  preen_invars_LDADD            = -ldl
  preen_invars_LDFLAGS          = $(AM_FLAG_M3264_PRI) \
 				-Wl,-rpath,$(top_builddir)/memcheck/tests
 endif
 endif
+endif
 
 preen_invars_so_so_CFLAGS       = $(AM_CFLAGS) -fpic
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
@@ -112,8 +125,13 @@
  preen_invars_so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -shared \
 					-Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ preen_invars_so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+					-dynamiclib -all_load
+else
  preen_invars_so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -shared \
 					-Wl,-soname -Wl,preen_invars_so.so
 endif
 endif
+endif
 
diff --git a/glibc-2.34567-NPTL-helgrind.supp b/glibc-2.34567-NPTL-helgrind.supp
index 0a4aeaa..616309e 100644
--- a/glibc-2.34567-NPTL-helgrind.supp
+++ b/glibc-2.34567-NPTL-helgrind.supp
@@ -137,6 +137,7 @@
 {
    helgrind-glibc2X-112
    Helgrind:Race
+   fun:pthread_create_WRK
    fun:pthread_create@*
 }
 {
diff --git a/helgrind/Makefile.am b/helgrind/Makefile.am
index 02f96ba..55379c2 100644
--- a/helgrind/Makefile.am
+++ b/helgrind/Makefile.am
@@ -1,6 +1,7 @@
 include $(top_srcdir)/Makefile.tool.am
 
 noinst_PROGRAMS = 
+noinst_DSYMS =
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 noinst_PROGRAMS += helgrind-x86-linux vgpreload_helgrind-x86-linux.so
 endif
@@ -19,6 +20,14 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += helgrind-ppc64-aix5 vgpreload_helgrind-ppc64-aix5.so
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += helgrind-x86-darwin vgpreload_helgrind-x86-darwin.so
+noinst_DSYMS    +=                     vgpreload_helgrind-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += helgrind-amd64-darwin vgpreload_helgrind-amd64-darwin.so
+noinst_DSYMS    +=                       vgpreload_helgrind-amd64-darwin.so
+endif
 
 VGPRELOAD_HELGRIND_SOURCES_COMMON = hg_intercepts.c
 
@@ -70,6 +79,22 @@
 	$(PRELOAD_LDFLAGS_PPC64_AIX5) \
 	$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
+vgpreload_helgrind_x86_darwin_so_SOURCES      = $(VGPRELOAD_HELGRIND_SOURCES_COMMON)
+vgpreload_helgrind_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_helgrind_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_helgrind_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_helgrind_x86_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_X86_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_helgrind_amd64_darwin_so_SOURCES      = $(VGPRELOAD_HELGRIND_SOURCES_COMMON)
+vgpreload_helgrind_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_helgrind_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_helgrind_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_helgrind_amd64_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
 HELGRIND_SOURCES_COMMON = \
 	hg_basics.c hg_lock_n_thread.c hg_wordset.c libhb_core.c \
 	hg_errors.c hg_main.c
@@ -116,6 +141,20 @@
 helgrind_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 helgrind_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
 
+helgrind_x86_darwin_SOURCES      = $(HELGRIND_SOURCES_COMMON)
+helgrind_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+helgrind_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) -O2
+helgrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+helgrind_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+helgrind_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+helgrind_amd64_darwin_SOURCES      = $(HELGRIND_SOURCES_COMMON)
+helgrind_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+helgrind_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) -O2
+helgrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+helgrind_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+helgrind_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
 hgincludedir = $(includedir)/valgrind
 
 hginclude_HEADERS = helgrind.h
diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c
index 698a082..47cb3af 100644
--- a/helgrind/hg_intercepts.c
+++ b/helgrind/hg_intercepts.c
@@ -195,9 +195,13 @@
 }
 
 // pthread_create
-PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
-              pthread_t *thread, const pthread_attr_t *attr,
-              void *(*start) (void *), void *arg)
+// glibc-2.8.90 has "pthread_create@@GLIBC_2.2.5".
+// Darwin has "pthread_create".
+//
+// DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
+// functions that currently have them.
+static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
+                              void *(*start) (void *), void *arg)
 {
    int    ret;
    OrigFn fn;
@@ -234,6 +238,16 @@
    }
    return ret;
 }
+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);
+}
+PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
+              pthread_t *thread, const pthread_attr_t *attr,
+              void *(*start) (void *), void *arg) {
+   return pthread_create_WRK(thread, attr, start, arg);
+}
 
 // pthread_join
 PTH_FUNC(int, pthreadZujoin, // pthread_join
@@ -756,6 +770,8 @@
 /*--- pthread_barrier_t functions                              ---*/
 /*----------------------------------------------------------------*/
 
+#if defined(HAVE_PTHREAD_BARRIER_INIT)
+
 /* Handled:   pthread_barrier_init
               pthread_barrier_wait
               pthread_barrier_destroy
@@ -861,6 +877,8 @@
    return ret;
 }
 
+#endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
+
 /*----------------------------------------------------------------*/
 /*--- pthread_rwlock_t functions                               ---*/
 /*----------------------------------------------------------------*/
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index 796d966..bff2fd5 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -11,6 +11,8 @@
    Copyright (C) 2007-2009 OpenWorks LLP
       info@open-works.co.uk
 
+   Copyright (C) 2007-2009 Apple, Inc.
+
    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
@@ -4201,6 +4203,7 @@
 static void hg_pre_clo_init ( void )
 {
    Thr* hbthr_root;
+
    VG_(details_name)            ("Helgrind");
    VG_(details_version)         (NULL);
    VG_(details_description)     ("a thread error detector");
diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am
index c594f3b..5f68d40 100644
--- a/helgrind/tests/Makefile.am
+++ b/helgrind/tests/Makefile.am
@@ -92,10 +92,15 @@
 	tc18_semabuse \
 	tc19_shadowmem \
 	tc21_pthonce \
-	tc22_exit_w_lock \
 	tc23_bogus_condwait \
 	tc24_nonzero_sem
 
+# DDD: it seg faults, and then the Valgrind exit path hangs
+if ! VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+   check_PROGRAMS += \
+	tc22_exit_w_lock
+endif
+
 if HAVE_PTHREAD_BARRIER
 check_PROGRAMS += bar_bad bar_trivial
 endif
diff --git a/helgrind/tests/tc20_verifywrap.c b/helgrind/tests/tc20_verifywrap.c
index 667aafa..6a8b30c 100644
--- a/helgrind/tests/tc20_verifywrap.c
+++ b/helgrind/tests/tc20_verifywrap.c
@@ -18,7 +18,7 @@
 #include <pthread.h>
 #include <semaphore.h>
 
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 
 #if !defined(__GLIBC_PREREQ)
 # error "This program needs __GLIBC_PREREQ (in /usr/include/features.h)"
diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h
index cda74ab..734391c 100644
--- a/include/pub_tool_basics.h
+++ b/include/pub_tool_basics.h
@@ -112,7 +112,15 @@
 // - off_t is "used for file sizes".
 // At one point we were using it for memory offsets, but PtrdiffT should be
 // used in those cases.
+// Nb: on Linux and AIX, 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) || defined(VGO_aix5)
 typedef Word                   OffT;      // 32             64
+#elif defined(VGO_darwin)
+typedef Long                   OffT;      // 64             64
+#else
+#  error Unknown OS
+#endif
 typedef Long                 Off64T;      // 64             64
 
 #if !defined(NULL)
@@ -183,6 +191,19 @@
       Bool  _isError;
    }
    SysRes;
+#elif defined(VGO_darwin)
+typedef
+   struct {
+      UWord _wLO;
+      UWord _wHI;
+      enum { 
+         SysRes_MACH=40,  // MACH, result is _wLO
+         SysRes_MDEP,     // MDEP, result is _wLO
+         SysRes_UNIX_OK,  // UNIX, success, result is _wHI:_wLO
+         SysRes_UNIX_ERR  // UNIX, error,   error  is _wHI:_wLO
+      } _mode;
+   }
+   SysRes;
 #else
 #  error "Unknown OS"
 #endif
@@ -214,6 +235,44 @@
 #  error "need to define SysRes accessors on AIX5 (copy from 3.4.1 sources)"
 
 
+#elif defined(VGO_darwin)
+
+static inline Bool sr_isError ( SysRes sr ) {
+   switch (sr._mode) {
+      case SysRes_UNIX_ERR: return True;
+      default:              return False;
+      /* should check tags properly and assert here, but we can't here */
+   }
+}
+
+static inline UWord sr_Res ( SysRes sr ) {
+   switch (sr._mode) {
+      case SysRes_MACH:
+      case SysRes_MDEP:
+      case SysRes_UNIX_OK: return sr._wLO;
+      default: return 0; /* should assert, but we can't here */
+   }
+}
+
+static inline UWord sr_ResHI ( SysRes sr ) {
+   switch (sr._mode) {
+      case SysRes_UNIX_OK: return sr._wHI;
+      default: return 0; /* should assert, but we can't here */
+   }
+}
+
+static inline UWord sr_Err ( SysRes sr ) {
+   switch (sr._mode) {
+      case SysRes_UNIX_ERR: return sr._wLO;
+      default: return 0; /* should assert, but we can't here */
+   }
+}
+
+static inline Bool sr_EQ ( SysRes sr1, SysRes sr2 ) {
+   return sr1._mode == sr2._mode
+          && sr1._wLO == sr2._wLO && sr1._wHI == sr2._wHI;
+}
+
 #else
 #  error "Unknown OS"
 #endif
diff --git a/include/pub_tool_basics_asm.h b/include/pub_tool_basics_asm.h
index 201c1b5..42a8a31 100644
--- a/include/pub_tool_basics_asm.h
+++ b/include/pub_tool_basics_asm.h
@@ -48,8 +48,15 @@
 
 #define VGAPPEND(str1,str2) str1##str2
  
-#define VG_(str)    VGAPPEND(vgPlain_,          str)
-#define ML_(str)    VGAPPEND(vgModuleLocal_,    str)
+#if defined(VGO_linux) || defined(VGO_aix5)
+#  define VG_(str)    VGAPPEND( vgPlain_,          str)
+#  define ML_(str)    VGAPPEND( vgModuleLocal_,    str)
+#elif defined(VGO_darwin)
+#  define VG_(str)    VGAPPEND(_vgPlain_,          str)
+#  define ML_(str)    VGAPPEND(_vgModuleLocal_,    str)
+#else
+#  error Unknown OS
+#endif
 
 #endif /* __PUB_TOOL_BASICS_ASM_H */
 
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index c2cab19..0460112 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -37,6 +37,7 @@
 
 extern Bool VG_(isspace) ( Char c );
 extern Bool VG_(isdigit) ( Char c );
+extern Char VG_(tolower) ( Char c );
 
 /* ---------------------------------------------------------------------
    Converting strings to numbers
@@ -86,8 +87,11 @@
 extern Char* VG_(strcpy)         ( Char* dest, const Char* src );
 extern Char* VG_(strncpy)        ( Char* dest, const Char* src, SizeT ndest );
 extern Int   VG_(strcmp)         ( const Char* s1, const Char* s2 );
+extern Int   VG_(strcasecmp)     ( const Char* s1, const Char* s2 );
 extern Int   VG_(strncmp)        ( const Char* s1, const Char* s2, SizeT nmax );
+extern Int   VG_(strncasecmp)    ( const Char* s1, const Char* s2, SizeT nmax );
 extern Char* VG_(strstr)         ( const Char* haystack, Char* needle );
+extern Char* VG_(strcasestr)     ( const Char* haystack, Char* needle );
 extern Char* VG_(strchr)         ( const Char* s, Char c );
 extern Char* VG_(strrchr)        ( const Char* s, Char c );
 extern SizeT VG_(strspn)         ( const Char* s, const Char* accpt );
@@ -115,6 +119,7 @@
 #define VG_IS_4_ALIGNED(aaa_p)    (0 == (((Addr)(aaa_p)) & ((Addr)0x3)))
 #define VG_IS_8_ALIGNED(aaa_p)    (0 == (((Addr)(aaa_p)) & ((Addr)0x7)))
 #define VG_IS_16_ALIGNED(aaa_p)   (0 == (((Addr)(aaa_p)) & ((Addr)0xf)))
+#define VG_IS_32_ALIGNED(aaa_p)   (0 == (((Addr)(aaa_p)) & ((Addr)0x1f)))
 #define VG_IS_WORD_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(sizeof(Addr)-1))))
 #define VG_IS_PAGE_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(VKI_PAGE_SIZE-1))))
 
diff --git a/include/pub_tool_libcfile.h b/include/pub_tool_libcfile.h
index 916b431..5e04c96 100644
--- a/include/pub_tool_libcfile.h
+++ b/include/pub_tool_libcfile.h
@@ -85,6 +85,9 @@
 extern Int    VG_(readlink)( const Char* path, Char* buf, UInt bufsize );
 extern Int    VG_(getdents)( Int fd, struct vki_dirent *dirp, UInt count );
 
+extern Char*  VG_(basename)( const Char* path );
+extern Char*  VG_(dirname) ( const Char* path );
+
 /* Copy the working directory at startup into buf[0 .. size-1], or return
    False if buf is too small. */
 extern Bool VG_(get_startup_wd) ( Char* buf, SizeT size );
diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h
index 7301d51..d7789a3 100644
--- a/include/pub_tool_machine.h
+++ b/include/pub_tool_machine.h
@@ -68,6 +68,17 @@
 #  define VG_MAX_INSTR_SZB          4 
 #  define VG_CLREQ_SZB             20
 #  define VG_STACK_REDZONE_SZB    288 // is this right?
+#elif defined(VGP_x86_darwin)
+#  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_darwin)
+#  define VG_MIN_INSTR_SZB          1
+#  define VG_MAX_INSTR_SZB         16
+#  define VG_CLREQ_SZB             19
+#  define VG_STACK_REDZONE_SZB    128
 #else
 #  error Unknown platform
 #endif
diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h
index ca40bc4..5a97bff 100644
--- a/include/pub_tool_redir.h
+++ b/include/pub_tool_redir.h
@@ -178,6 +178,8 @@
 #  define  VG_Z_LIBC_SONAME  libcZaZdaZLshrZdoZR     // libc*.a(shr.o)
 #elif defined(VGP_ppc64_aix5)
 #  define  VG_Z_LIBC_SONAME  libcZaZdaZLshrZu64ZdoZR // libc*.a(shr_64.o)
+#elif defined(VGO_darwin)
+#  define  VG_Z_LIBC_SONAME  libSystemZdZaZddylib    // libSystem.*.dylib
 #else
 #  error "Unknown platform"
 #endif
@@ -202,6 +204,8 @@
 
 #if defined(VGO_linux) || defined(VGO_aix5)
 #  define  VG_Z_LIBPTHREAD_SONAME  libpthreadZdsoZd0     // libpthread.so.0
+#elif defined(VGO_darwin)
+#  define  VG_Z_LIBPTHREAD_SONAME  libSystemZdZaZddylib  // libSystem.*.dylib
 #else
 #  error "Unknown platform"
 #endif
@@ -215,6 +219,13 @@
 #define  VG_Z_LD_SO_1               ldZdsoZd1                  // ld.so.1
 #endif
 
+/* --- Executable name for Darwin Mach-O linker. --- */
+
+#if defined(VGO_darwin)
+#define  VG_Z_DYLD               dyld                       // dyld
+#endif
+
+
 #endif   // __PUB_TOOL_REDIR_H
 
 /*--------------------------------------------------------------------*/
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index 3a7c391..5b1725c 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -439,8 +439,14 @@
    what kind of error message should be emitted. */
 typedef
    enum { Vg_CoreStartup=1, Vg_CoreSignal, Vg_CoreSysCall,
-          Vg_CoreTranslate, Vg_CoreClientReq }
-   CorePart;
+          // This is for platforms where syscall args are passed on the
+          // stack; although pre_mem_read is the callback that will be
+          // called, such an arg should be treated (with respect to
+          // presenting information to the user) as if it was passed in a
+          // register, ie. like pre_reg_read.
+          Vg_CoreSysCallArgInMem,  
+          Vg_CoreTranslate, Vg_CoreClientReq
+   } CorePart;
 
 /* Events happening in core to track.  To be notified, pass a callback
    function to the appropriate function.  To ignore an event, don't do
diff --git a/include/pub_tool_vki.h b/include/pub_tool_vki.h
index 75da646..f6c9792 100644
--- a/include/pub_tool_vki.h
+++ b/include/pub_tool_vki.h
@@ -51,6 +51,8 @@
 #  include "vki/vki-ppc32-aix5.h"
 #elif defined(VGP_ppc64_aix5)
 #  include "vki/vki-ppc64-aix5.h"
+#elif defined(VGO_darwin)
+#  include "vki/vki-darwin.h"
 #else
 #  error Unknown Plat/OS
 #endif
diff --git a/include/pub_tool_vkiscnums.h b/include/pub_tool_vkiscnums.h
index 061b36e..adb6cc0 100644
--- a/include/pub_tool_vkiscnums.h
+++ b/include/pub_tool_vkiscnums.h
@@ -42,6 +42,10 @@
    different for each process (in principle; in practice they rarely
    change).  32- and 64-bit AIX5 share a common "implementation".
 
+   On Darwin the __NR_name consts are #define'd constants which are
+   computed using various macros.  32- and 64-bit Darwin share a common
+   "implementation" also.
+
    This file is merely a top-level "steering" file, which pulls in the
    correct bits for the relevant platform.  You should not directly
    #include any file in include/vki; instead #include only this one or
@@ -72,10 +76,31 @@
 /* Look up the name of a syscall, using the bindings previously
    created by VG_(aix5_register_syscall), for the purposes of making
    error messages. */
+// DDD: should combine this and VG_DARWIN_SYSNO_PRINT into a single generic
+// function which returns a string, something like VG_(pprint_sysno)().
 extern UChar* VG_(aix5_sysno_to_sysname)( Int sysno );
 
 #endif /* !defined(VG_IN_ASSEMBLY_SOURCE) */
 
+#elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+#  include "vki/vki-scnums-darwin.h"
+
+// Convert a syscall number into a nice form for printing.  Unix syscalls
+// get positive numbers (0..400-odd), Mach traps get negative numbers
+// (-10..-127).  
+// DDD: Machine-dependent ones get positive numbers which will overlap with
+// Unix ones!  So eg. both 'pthread_set_self' and 'read' are reported as
+// "3".
+#define VG_DARWIN_SYSNO_PRINT(sysno) \
+    ((VG_DARWIN_SYSNO_CLASS(sysno) == VG_DARWIN_SYSCALL_CLASS_MACH) \
+    ? -VG_DARWIN_SYSNO_INDEX(sysno) \
+    :  VG_DARWIN_SYSNO_INDEX(sysno) \
+    )
+
+/* Macros for working out which syscall a syscall number refers to. */
+#define VG_DARWIN_SYSNO_INDEX(sysno) ((sysno) & VG_DARWIN_SYSCALL_NUMBER_MASK)
+#define VG_DARWIN_SYSNO_CLASS(sysno) ((sysno) >> VG_DARWIN_SYSCALL_CLASS_SHIFT)
+
 #else
 #  error Unknown platform
 #endif
diff --git a/include/valgrind.h b/include/valgrind.h
index 679f159..da24274 100644
--- a/include/valgrind.h
+++ b/include/valgrind.h
@@ -92,26 +92,26 @@
 #undef PLAT_ppc32_aix5
 #undef PLAT_ppc64_aix5
 
-#if !defined(_AIX) && defined(__i386__)
-#  define PLAT_x86_linux 1
-#elif !defined(_AIX) && defined(__x86_64__)
-#  define PLAT_amd64_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__)
-#  define PLAT_ppc32_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__)
-#  define PLAT_ppc64_linux 1
-#elif defined(_AIX) && defined(__64BIT__)
+
+#if defined(_AIX) && defined(__64BIT__)
 #  define PLAT_ppc64_aix5 1
 #elif defined(_AIX) && !defined(__64BIT__)
 #  define PLAT_ppc32_aix5 1
-#endif
-
-
+#elif defined(__APPLE__) && defined(__i386__)
+#  define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+#  define PLAT_amd64_darwin 1
+#elif defined(__i386__)
+#  define PLAT_x86_linux 1
+#elif defined(__x86_64__)
+#  define PLAT_amd64_linux 1
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+#  define PLAT_ppc32_linux 1
+#elif defined(__powerpc__) && defined(__powerpc64__)
+#  define PLAT_ppc64_linux 1
+#else
 /* If we're not compiling for our target platform, don't generate
    any inline asms.  */
-#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \
-    && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \
-    && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5)
 #  if !defined(NVALGRIND)
 #    define NVALGRIND 1
 #  endif
@@ -172,9 +172,9 @@
    inline asm stuff to be useful.
 */
 
-/* ------------------------- x86-linux ------------------------- */
+/* ------------------------- x86-{linux,darwin} ---------------- */
 
-#if defined(PLAT_x86_linux)
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
 
 typedef
    struct { 
@@ -224,11 +224,11 @@
                      __SPECIAL_INSTRUCTION_PREAMBLE               \
                      /* call-noredir *%EAX */                     \
                      "xchgl %%edx,%%edx\n\t"
-#endif /* PLAT_x86_linux */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
 
-/* ------------------------ amd64-linux ------------------------ */
+/* ------------------------ amd64-{linux,darwin} --------------- */
 
-#if defined(PLAT_amd64_linux)
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
 
 typedef
    struct { 
@@ -278,7 +278,7 @@
                      __SPECIAL_INSTRUCTION_PREAMBLE               \
                      /* call-noredir *%RAX */                     \
                      "xchgq %%rdx,%%rdx\n\t"
-#endif /* PLAT_amd64_linux */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
 
 /* ------------------------ ppc32-linux ------------------------ */
 
@@ -632,9 +632,9 @@
    do { volatile unsigned long _junk;                             \
         CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
 
-/* ------------------------- x86-linux ------------------------- */
+/* ------------------------- x86-{linux,darwin} ---------------- */
 
-#if defined(PLAT_x86_linux)
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
 
 /* These regs are trashed by the hidden call.  No need to mention eax
    as gcc can already see that, plus causes gcc to bomb. */
@@ -1027,11 +1027,11 @@
       lval = (__typeof__(lval)) _res;                             \
    } while (0)
 
-#endif /* PLAT_x86_linux */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
 
-/* ------------------------ amd64-linux ------------------------ */
+/* ------------------------ amd64-{linux,darwin} --------------- */
 
-#if defined(PLAT_amd64_linux)
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
 
 /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
 
@@ -1465,7 +1465,7 @@
       lval = (__typeof__(lval)) _res;                             \
    } while (0)
 
-#endif /* PLAT_amd64_linux */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
 
 /* ------------------------ ppc32-linux ------------------------ */
 
diff --git a/include/vki/Makefile.am b/include/vki/Makefile.am
index 137fe1d..81b40e5 100644
--- a/include/vki/Makefile.am
+++ b/include/vki/Makefile.am
@@ -3,6 +3,7 @@
 
 incinc_HEADERS = \
 	vki-linux.h			\
+	vki-darwin.h			\
 	vki-posixtypes-amd64-linux.h	\
 	vki-posixtypes-ppc32-linux.h	\
 	vki-posixtypes-ppc64-linux.h	\
@@ -14,7 +15,8 @@
 	vki-scnums-amd64-linux.h	\
 	vki-scnums-ppc32-linux.h	\
 	vki-scnums-ppc64-linux.h	\
-	vki-scnums-x86-linux.h
+	vki-scnums-x86-linux.h		\
+	vki-scnums-darwin.h
 
 noinst_HEADERS = \
 	vki-ppc32-aix5.h		\
diff --git a/include/vki/vki-darwin.h b/include/vki/vki-darwin.h
new file mode 100644
index 0000000..cf5e542
--- /dev/null
+++ b/include/vki/vki-darwin.h
@@ -0,0 +1,1023 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific kernel interface.               vki-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2007-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   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.
+*/
+
+/* Unlike vki-linux, this Darwin kernel interface includes system headers
+   directly, to avoid copyright complexity. */
+
+#ifndef __VKI_DARWIN_H
+#define __VKI_DARWIN_H
+
+#include <stdint.h>
+
+#define vki_int8_t int8_t
+#define vki_uint8_t uint8_t
+#define vki_int16_t int16_t
+#define vki_uint16_t uint16_t
+#define vki_int32_t int32_t
+#define vki_uint32_t uint32_t
+#define vki_int64_t int64_t
+#define vki_uint64_t uint64_t
+#define vki_intptr_t intptr_t
+#define vki_uintptr_t uintptr_t
+
+#include <sys/types.h>
+
+#define vki_dev_t dev_t
+#define vki_mode_t mode_t
+#define vki_ino_t ino_t
+#define vki_ino64_t ino64_t
+#define vki_nlink_t nlink_t
+#define vki_uid_t uid_t
+#define vki_gid_t gid_t
+#define vki_time_t time_t
+#define vki_off_t off_t
+#define vki_blkcnt_t blkcnt_t
+#define vki_blksize_t blksize_t
+#define vki_size_t size_t
+#define vki_ssize_t ssize_t
+#define vki_pid_t pid_t
+#define vki_socklen_t socklen_t
+#define vki_suseconds_t suseconds_t
+#define vki_caddr_t caddr_t
+#define vki_u_long u_long
+#define vki_u_short u_short
+#define vki_clock_t clock_t
+#define vki_u_int32_t u_int32_t
+#define vki_u_int16_t u_int16_t
+
+
+// valgrind special
+
+// magic mmap() flags
+#define	VKI_MAP_ANONYMOUS MAP_ANON	// linux synonym
+
+// fds for mmap(MAP_ANON), displayed by vmmap
+#define VM_TAG_VALGRIND VM_MAKE_TAG(239)  // SkAnonV
+
+// page sizes
+#define VKI_MAX_PAGE_SHIFT VKI_PAGE_SHIFT
+#define VKI_MAX_PAGE_SIZE VKI_PAGE_SIZE
+
+// types
+typedef uint32_t vki_u32;
+
+// linux-like ioctl flags
+#define _VKI_IOC_DIR(x)		((x) & IOC_DIRMASK)
+#define _VKI_IOC_SIZE(x)	IOCPARM_LEN(x)
+#define _VKI_IOC_NONE		IOC_VOID  /* GrP fixme correct? */
+#define _VKI_IOC_READ		IOC_OUT
+#define _VKI_IOC_WRITE		IOC_IN
+
+
+#include <malloc/malloc.h>
+
+#define vki_malloc_zone_t malloc_zone_t
+
+
+#include <sys/time.h>
+
+#define vki_timeval timeval
+#define vki_timeval32 timeval32
+#define vki_timespec timespec
+#define vki_itimerval itimerval
+#define vki_timezone timezone
+
+
+#include <sys/stat.h>
+
+#define	VKI_S_ISBLK(m)	S_ISBLK(m)
+#define	VKI_S_ISCHR(m)	S_ISCHR(m)
+#define	VKI_S_ISDIR(m)	S_ISDIR(m)
+#define	VKI_S_ISFIFO(m)	S_ISFIFO(m)
+#define	VKI_S_ISREG(m)	S_ISREG(m)
+#define	VKI_S_ISLNK(m)	S_ISLNK(m)
+#define	VKI_S_ISSOCK(m)	S_ISSOCK(m)
+#define	VKI_S_ISWHT(m)	S_ISWHT(m)
+#define VKI_S_ISXATTR(m) S_ISXATTR(m)
+
+#define	VKI_S_IRWXU	S_IRWXU
+#define	VKI_S_IRUSR	S_IRUSR
+#define	VKI_S_IWUSR	S_IWUSR
+#define	VKI_S_IXUSR	S_IXUSR
+#define	VKI_S_IRWXG	S_IRWXG
+#define	VKI_S_IRGRP	S_IRGRP
+#define	VKI_S_IWGRP	S_IWGRP
+#define	VKI_S_IXGRP	S_IXGRP
+#define	VKI_S_IRWXO	S_IRWXO
+#define	VKI_S_IROTH	S_IROTH
+#define	VKI_S_IWOTH	S_IWOTH
+#define	VKI_S_IXOTH	S_IXOTH
+#define	VKI_S_ISUID	S_ISUID
+#define	VKI_S_ISGID	S_ISGID
+#define	VKI_S_ISVTX	S_ISVTX
+
+#define vki_stat stat
+#define vki_stat64 stat64
+
+#define st_atime      st_atimespec.tv_sec
+#define st_atime_nsec st_atimespec.tv_nsec
+#define st_mtime      st_mtimespec.tv_sec
+#define st_mtime_nsec st_mtimespec.tv_nsec
+#define st_ctime      st_ctimespec.tv_sec
+#define st_ctime_nsec st_ctimespec.tv_nsec
+
+
+#include <sys/dirent.h>
+
+#define VKI_MAXNAMLEN MAXNAMLEN
+#define vki_dirent dirent
+
+
+#include <sys/socket.h>
+#define	VKI_SOCK_STREAM	SOCK_STREAM
+#define	VKI_SOCK_DGRAM	SOCK_DGRAM
+#define	VKI_SOCK_RAW	SOCK_RAW
+
+#define	VKI_AF_UNIX	AF_UNIX
+#define	VKI_AF_INET	AF_INET
+#define	VKI_AF_INET6	AF_INET6
+
+#define	VKI_SOL_SOCKET	SOL_SOCKET
+
+#define	VKI_SO_REUSEADDR SO_REUSEADDR
+
+#define VKI_SO_SNDBUF	SO_SNDBUF
+#define VKI_SO_RCVBUF	SO_RCVBUF
+#define VKI_SO_SNDLOWAT	SO_SNDLOWAT
+#define VKI_SO_RCVLOWAT	SO_RCVLOWAT
+#define VKI_SO_SNDTIMEO	SO_SNDTIMEO
+#define VKI_SO_RCVTIMEO	SO_RCVTIMEO
+#define	VKI_SO_ERROR	SO_ERROR
+#define	VKI_SO_TYPE	SO_TYPE
+#define VKI_SO_NREAD	SO_NREAD
+#define VKI_SO_NKE	SO_NKE
+#define VKI_SO_NOSIGPIPE	SO_NOSIGPIPE
+#define VKI_SO_NOADDRERR	SO_NOADDRERR
+#define VKI_SO_NWRITE	SO_NWRITE
+#define VKI_SO_LINGER_SEC	SO_LINGER_SEC
+
+#define vki_sa_family_t sa_family_t
+#define vki_sockaddr sockaddr
+#define vki_iovec iovec
+#define vki_msghdr msghdr
+#define vki_cmsghdr cmsghdr
+
+
+#define VKI_CMSG_ALIGN(a) 	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)
+
+#define	VKI_SCM_RIGHTS		SCM_RIGHTS
+#define	VKI_SCM_TIMESTAMP	SCM_TIMESTAMP
+#define	VKI_SCM_CREDS		SCM_CREDS
+
+
+#include <sys/un.h>
+
+#define vki_sockaddr_un sockaddr_un
+
+
+#include <netinet/in.h>
+
+#define vki_in_addr_t in_addr_t
+#define vki_in_port_t in_port_t
+#define vki_in_addr in_addr
+#define vki_sockaddr_in sockaddr_in
+
+#define	VKI_INADDR_LOOPBACK	INADDR_LOOPBACK
+
+
+// #include <netinet6/in6.h>
+
+#define vki_in6_addr in6_addr
+#define vki_sockaddr_in6 sockaddr_in6
+
+
+#include <net/if.h>
+
+#define	VKI_IFNAMSIZ	IFNAMSIZ
+
+#define vki_ifdevmtu ifdevmtu
+#define vki_ifreq ifreq
+#define vki_ifr_name 	ifr_name
+#define	vki_ifr_addr	ifr_addr
+#define	vki_ifr_dstaddr	ifr_dstaddr
+#define	vki_ifr_broadaddr	ifr_broadaddr
+#define	vki_ifr_flags	ifr_flags
+#define	vki_ifr_metric	ifr_metric
+#define	vki_ifr_mtu	ifr_mtu
+#define vki_ifr_phys	ifr_phys
+#define vki_ifr_media	ifr_media
+#define	vki_ifr_data	ifr_data
+#define vki_ifr_devmtu	ifr_devmtu
+#define vki_ifr_intval	ifr_intval
+
+#define vki_ifconf ifconf
+#define vki_ifc_buf 	ifc_buf
+#define vki_ifc_req 	ifc_req
+
+
+#include <sys/fcntl.h>
+
+#define	VKI_SEEK_SET	SEEK_SET
+#define	VKI_SEEK_CUR	SEEK_CUR
+#define	VKI_SEEK_END	SEEK_END
+
+#define	VKI_O_RDONLY	O_RDONLY
+#define	VKI_O_WRONLY	O_WRONLY
+#define	VKI_O_RDWR	O_RDWR
+#define	VKI_O_ACCMODE	O_ACCMODE
+#define	VKI_O_NONBLOCK	O_NONBLOCK
+#define	VKI_O_APPEND	O_APPEND
+#define	VKI_O_SYNC	O_SYN
+#define	VKI_O_SHLOCK	O_SHLOCK
+#define	VKI_O_EXLOCK	O_EXLOCK
+#define	VKI_O_ASYNC	O_ASYNC
+#define VKI_O_NOFOLLOW  O_NOFOLLOW
+#define	VKI_O_CREAT	O_CREAT
+#define	VKI_O_TRUNC	O_TRUNC
+#define	VKI_O_EXCL	O_EXCL
+#define	VKI_O_EVTONLY	O_EVTONLY
+
+#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_SETFL	F_SETFL
+#define	VKI_F_GETOWN	F_GETOWN
+#define VKI_F_SETOWN	F_SETOWN
+#define	VKI_F_GETLK	F_GETLK
+#define	VKI_F_SETLK	F_SETLK
+#define	VKI_F_SETLKW	F_SETLKW
+
+#define VKI_F_CHKCLEAN	F_CHKCLEAN
+#define VKI_F_PREALLOCATE	F_PREALLOCATE
+#define VKI_F_SETSIZE	F_SETSIZE
+#define VKI_F_RDADVISE	F_RDADVISE
+#define VKI_F_RDAHEAD	F_RDAHEAD
+#define VKI_F_READBOOTSTRAP	F_READBOOTSTRAP
+#define VKI_F_WRITEBOOTSTRAP	F_WRITEBOOTSTRAP
+#define VKI_F_NOCACHE	F_NOCACHE
+#define VKI_F_LOG2PHYS	F_LOG2PHYS
+#define VKI_F_GETPATH	F_GETPATH
+#define VKI_F_ADDSIGS	F_ADDSIGS
+#define VKI_F_FULLFSYNC	F_FULLFSYNC
+#define VKI_F_PATHPKG_CHECK	F_PATHPKG_CHECK
+#define VKI_F_FREEZE_FS	F_FREEZE_FS
+#define VKI_F_THAW_FS	F_THAW_FS
+#define	VKI_F_GLOBAL_NOCACHE	F_GLOBAL_NOCACHE
+
+#define VKI_FD_CLOEXEC	FD_CLOEXEC
+
+#define vki_radvisory radvisory
+#define vki_fstore fstore
+#define vki_fbootstraptransfer fbootstraptransfer
+#define vki_log2phys log2phys
+#define vki_fsignatures_t fsignatures_t
+
+// These constants aren't in a standard header, they are from the kernel code:
+// xnu-1228.3.13/bsd/sys/codesign.h
+// Mac OS X 10.5.6 - Darwin 9.6
+#define VKI_CS_OPS_STATUS           0       /* return status */
+#define VKI_CS_OPS_MARKINVALID      1       /* invalidate process */
+#define VKI_CS_OPS_MARKHARD         2       /* set HARD flag */
+#define VKI_CS_OPS_MARKKILL         3       /* set KILL flag (sticky) */
+#define VKI_CS_OPS_PIDPATH          4       /* get executable's pathname */
+#define VKI_CS_OPS_CDHASH           5       /* get code directory hash */
+
+#include <sys/mman.h>
+
+#define	VKI_PROT_NONE	PROT_NONE
+#define	VKI_PROT_READ	PROT_READ
+#define	VKI_PROT_WRITE	PROT_WRITE
+#define	VKI_PROT_EXEC	PROT_EXEC
+
+#define	VKI_MAP_SHARED	MAP_SHARED
+#define	VKI_MAP_PRIVATE	MAP_PRIVATE
+#define	VKI_MAP_FIXED	MAP_FIXED
+#define	VKI_MAP_RENAME	MAP_RENAME
+#define	VKI_MAP_NORESERVE	MAP_NORESERVE
+#define	VKI_MAP_RESERVED0080	MAP_RESERVED0080
+#define	VKI_MAP_NOEXTEND	MAP_NOEXTEND
+#define	VKI_MAP_HASSEMAPHORE	MAP_HASSEMAPHORE
+#define	VKI_MAP_FILE	MAP_FILE
+#define	VKI_MAP_ANON	MAP_ANON
+#define VKI_MAP_FAILED	MAP_FAILED
+
+
+#include <mach/vm_param.h>
+
+#define VKI_PAGE_SHIFT PAGE_SHIFT
+#define VKI_PAGE_SIZE PAGE_SIZE
+#define VKI_PAGE_MASK PAGE_MASK
+
+
+#include <sys/vmparam.h>
+
+#define VKI_USRSTACK USRSTACK
+#define VKI_USRSTACK64 USRSTACK64
+
+
+#include <mach/mach_time.h>
+
+#define vki_mach_timebase_info mach_timebase_info
+
+
+#include <sys/syslimits.h>
+
+#define VKI_PATH_MAX PATH_MAX
+
+
+#include <sys/param.h>
+
+#define VKI_MAXPATHLEN MAXPATHLEN
+
+
+#include <sys/signal.h>
+
+/* While we fully intend to make 'vki_sigset_t' match the native
+   Darwin 'sigset_t', we can't just clone the Darwin sigset_t type,
+   because it isn't an array, and the VG_(sigfillset) etc functions
+   assume it is.  So instead define another isomorphic type, and check
+   in VG_(vki_do_initial_consistency_checks) that it really is
+   correct. */
+/* #define vki_sigset_t sigset_t */
+#define _VKI_NSIG_BPW   32
+#define _VKI_NSIG       32
+#define _VKI_NSIG_WORDS (_VKI_NSIG / _VKI_NSIG_BPW)
+typedef struct {
+   UInt sig[_VKI_NSIG_WORDS];
+} vki_sigset_t;
+/* and now let VG_(vki_do_initial_consistency_checks) make sure it
+   matches 'sigset_t'. */
+
+
+#define VKI_SS_ONSTACK	SS_ONSTACK
+#define	VKI_SS_DISABLE	SS_DISABLE
+#define	VKI_MINSIGSTKSZ	MINSIGSTKSZ
+#define	VKI_SIGSTKSZ	SIGSTKSZ
+
+#define vki_stack_t        stack_t
+#define vki_siginfo_t      siginfo_t
+
+/* There are two versions of this.  'struct __sigaction' is used for
+   passing sigactions to the kernel interface, and has the added
+   complexity of requiring an extra pointer to a new demultiplexing
+   function to be run in user space.  'struct sigaction' is used for
+   receiving old sigactions from the kernel, and lacks this
+   demux-function pointer.  So the type of the second and third
+   parameters in Darwin's sys_sigaction appear to be different,
+   respectively 'struct __sigaction*' and 'struct sigaction*'.
+*/
+//#define vki_sigaction      __sigaction
+//#define vki_user_sigaction sigaction
+//#define vki_sigaltstack    sigaltstack
+//#define vki_sigval         sigval
+//#define vki_sigaction_u    sigaction_u
+//#define vki_sigaction     sigaction
+
+//typedef  struct __sigaction  vki_sigaction_toK_t;
+//typedef  struct sigaction    vki_sigaction_fromK_t;
+
+typedef
+   struct {
+      void* ksa_handler;
+      void (*sa_tramp)(void*,UWord,UWord,void*,void*);
+      vki_sigset_t sa_mask;
+      int sa_flags;
+   }
+   vki_sigaction_toK_t;
+
+typedef
+   struct {
+      void* ksa_handler;
+      vki_sigset_t sa_mask;
+      int sa_flags;
+   }
+   vki_sigaction_fromK_t;
+
+
+
+/* and /usr/include/sys/signal.c in turn defines 'sa_handler' to
+   be '__sigaction_u.__sa_handler' */
+//#define	ksa_handler      sa_handler
+
+//#define	vki_sa_sigaction sa_sigaction
+
+#define VKI_SA_ONSTACK	SA_ONSTACK
+#define VKI_SA_RESTART	SA_RESTART
+#define	VKI_SA_DISABLE	SA_DISABLE
+#define	VKI_SA_RESETHAND	SA_RESETHAND
+#define VKI_SA_NOCLDSTOP	SA_NOCLDSTOP
+#define	VKI_SA_NODEFER	SA_NODEFER
+#define	VKI_SA_NOCLDWAIT	SA_NOCLDWAIT
+#define	VKI_SA_SIGINFO	SA_SIGINFO
+#define	VKI_SA_USERTRAMP	SA_USERTRAMP
+#define	VKI_SA_64REGSET	SA_64REGSET
+#define VKI_SA_RESTORER  0 /* Darwin doesn't have this */
+
+#define	VKI_SIG_BLOCK	SIG_BLOCK
+#define	VKI_SIG_UNBLOCK	SIG_UNBLOCK
+#define	VKI_SIG_SETMASK	SIG_SETMASK
+
+#define	VKI_SIGHUP	SIGHUP
+#define	VKI_SIGINT	SIGINT
+#define	VKI_SIGQUIT	SIGQUIT
+#define	VKI_SIGILL	SIGILL
+#define	VKI_SIGTRAP	SIGTRAP
+#define	VKI_SIGABRT	SIGABRT
+#define	VKI_SIGPOLL	SIGPOLL
+#define	VKI_SIGFPE	SIGFPE
+#define	VKI_SIGKILL	SIGKILL
+#define	VKI_SIGBUS	SIGBUS
+#define	VKI_SIGSEGV	SIGSEGV
+#define	VKI_SIGSYS	SIGSYS
+#define	VKI_SIGPIPE	SIGPIPE
+#define	VKI_SIGALRM	SIGALRM
+#define	VKI_SIGTERM	SIGTERM
+#define	VKI_SIGURG	SIGURG
+#define	VKI_SIGSTOP	SIGSTOP
+#define	VKI_SIGTSTP	SIGTSTP
+#define	VKI_SIGCONT	SIGCONT
+#define	VKI_SIGCHLD	SIGCHLD
+#define	VKI_SIGTTIN	SIGTTIN
+#define	VKI_SIGTTOU	SIGTTOU
+#define	VKI_SIGIO	SIGIO
+#define	VKI_SIGXCPU	SIGXCPU
+#define	VKI_SIGXFSZ	SIGXFSZ
+#define	VKI_SIGVTALRM	SIGVTALRM
+#define	VKI_SIGPROF	SIGPROF
+#define VKI_SIGWINCH	SIGWINCH
+#define VKI_SIGINFO	SIGINFO
+#define VKI_SIGUSR1	SIGUSR1
+#define VKI_SIGUSR2	SIGUSR2
+
+#define VKI_SIG_DFL     SIG_DFL
+#define VKI_SIG_IGN     SIG_IGN
+
+
+#define VKI_SI_USER      SI_USER
+#define VKI_SEGV_MAPERR  SEGV_MAPERR
+#define VKI_SEGV_ACCERR  SEGV_ACCERR
+#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
+#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_BUS_ADRALN   BUS_ADRALN
+#define VKI_BUS_ADRERR   BUS_ADRERR
+#define VKI_BUS_OBJERR   BUS_OBJERR
+#define VKI_TRAP_BRKPT   TRAP_BRKPT
+
+/* JRS: not 100% sure, but I think these two are correct */
+#define VKI_SA_ONESHOT   SA_RESETHAND
+#define VKI_SA_NOMASK    SA_NODEFER
+
+#define VKI_UC_SET_ALT_STACK   0x40000000
+#define VKI_UC_RESET_ALT_STACK 0x80000000
+
+
+#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_ENOEXEC		ENOEXEC
+#define VKI_EBADF		EBADF
+#define VKI_ECHILD		ECHILD
+#define VKI_EDEADLK		EDEADLK
+#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_EAGAIN		EAGAIN
+#define VKI_EWOULDBLOCK		EAGAIN
+#define VKI_EINPROGRESS		EINPROGRESS
+#define VKI_EALREADY		EALREADY
+#define VKI_ENOTSOCK		ENOTSOCK
+#define VKI_EDESTADDRREQ	EDESTADDRREQ
+#define VKI_EMSGSIZE		EMSGSIZE
+#define VKI_EPROTOTYPE		EPROTOTYPE
+#define VKI_ENOPROTOOPT		ENOPROTOOPT
+#define VKI_EPROTONOSUPPORT	EPROTONOSUPPORT
+#define VKI_ESOCKTNOSUPPORT	ESOCKTNOSUPPORT
+#define VKI_ENOTSUP		ENOTSUP
+#define VKI_EPFNOSUPPORT	EPFNOSUPPORT
+#define VKI_EAFNOSUPPORT	EAFNOSUPPORT
+#define VKI_EADDRINUSE		EADDRINUSE
+#define VKI_EADDRNOTAVAIL	EADDRNOTAVAIL
+#define VKI_ENETDOWN		ENETDOWN
+#define VKI_ENETUNREACH		ENETUNREACH
+#define VKI_ENETRESET		ENETRESET
+#define VKI_ECONNABORTED	ECONNABORTED
+#define VKI_ECONNRESET		ECONNRESET
+#define VKI_ENOBUFS		ENOBUFS
+#define VKI_EISCONN		EISCONN
+#define VKI_ENOTCONN		ENOTCONN
+#define VKI_ESHUTDOWN		ESHUTDOWN
+#define VKI_ETOOMANYREFS	ETOOMANYREFS
+#define VKI_ETIMEDOUT		ETIMEDOUT
+#define VKI_ECONNREFUSED	ECONNREFUSED
+#define VKI_ELOOP		ELOOP
+#define VKI_ENAMETOOLONG	ENAMETOOLONG
+#define VKI_EHOSTDOWN		EHOSTDOWN
+#define VKI_EHOSTUNREACH	EHOSTUNREACH
+#define VKI_ENOTEMPTY		ENOTEMPTY
+#define VKI_EPROCLIM		EPROCLIM
+#define VKI_EUSERS		EUSERS
+#define VKI_EDQUOT		EDQUOT
+#define VKI_ESTALE		ESTALE
+#define VKI_EREMOTE		EREMOTE
+#define VKI_EBADRPC		EBADRPC
+#define VKI_ERPCMISMATCH	ERPCMISMATCH
+#define VKI_EPROGUNAVAIL	EPROGUNAVAIL
+#define VKI_EPROGMISMATCH	EPROGMISMATCH
+#define VKI_EPROCUNAVAIL	EPROCUNAVAIL
+#define VKI_ENOLCK		ENOLCK
+#define VKI_ENOSYS		ENOSYS
+#define VKI_EFTYPE		EFTYPE
+#define VKI_EAUTH		EAUTH
+#define VKI_ENEEDAUTH		ENEEDAUTH
+#define VKI_EPWROFF		EPWROFF
+#define VKI_EDEVERR		EDEVERR
+#define VKI_EOVERFLOW		EOVERFLOW
+#define VKI_EBADEXEC		EBADEXEC
+#define VKI_EBADARCH		EBADARCH
+#define VKI_ESHLIBVERS		ESHLIBVERS
+#define VKI_EBADMACHO		EBADMACHO
+#define VKI_ECANCELED		ECANCELED
+#define VKI_EIDRM		EIDRM
+#define VKI_ENOMSG		ENOMSG
+#define VKI_EILSEQ		EILSEQ
+#define VKI_ENOATTR		ENOATTR
+#define VKI_EBADMSG		EBADMSG
+#define VKI_EMULTIHOP		EMULTIHOP
+#define VKI_ENODATA		ENODATA
+#define VKI_ENOLINK		ENOLINK
+#define VKI_ENOSR		ENOSR
+#define VKI_ENOSTR		ENOSTR
+#define VKI_EPROTO		EPROTO
+#define VKI_ETIME		ETIME
+#define VKI_EOPNOTSUPP		EOPNOTSUPP
+#define VKI_ELAST		ELAST
+
+
+#include <sys/resource.h>
+
+#define	VKI_RLIMIT_CPU		RLIMIT_CPU
+#define	VKI_RLIMIT_FSIZE	RLIMIT_FSIZE
+#define	VKI_RLIMIT_DATA		RLIMIT_DATA
+#define	VKI_RLIMIT_STACK	RLIMIT_STACK
+#define	VKI_RLIMIT_CORE		RLIMIT_CORE
+#define	VKI_RLIMIT_AS		RLIMIT_AD
+#define	VKI_RLIMIT_RSS		RLIMIT_AS
+#define	VKI_RLIMIT_MEMLOCK	RLIMIT_MEMLOCK
+#define	VKI_RLIMIT_NPROC	RLIMIT_NPROC
+#define	VKI_RLIMIT_NOFILE	RLIMIT_NOFILE
+#define	VKI_RLIM_NLIMITS	RLIM_NLIMITS
+
+#define vki_rlim_t rlim_t
+#define vki_rlimit rlimit
+#define vki_rusage rusage
+
+
+#include <sys/poll.h>
+
+#define vki_pollfd pollfd
+
+
+#include <sys/ipc.h>
+
+#define	VKI_IPC_RMID	IPC_RMID
+#define	VKI_IPC_SET	IPC_SET
+#define	VKI_IPC_STAT	IPC_STAT
+
+#define vki_key_t key_t
+#define vki_ipc_perm ipc_perm
+
+
+#include <sys/sem.h>
+
+#define VKI_GETNCNT	GETNCNT
+#define VKI_GETPID	GETPID
+#define VKI_GETVAL	GETVAL
+#define VKI_GETALL	GETALL
+#define VKI_GETZCNT	GETZCNT
+#define VKI_SETVAL	SETVAL
+#define VKI_SETALL	SETALL
+
+#define vki_sembuf sembuf
+#define vki_semid_ds semid_ds
+#define vki_semun semun
+
+
+#include <sys/semaphore.h>
+
+#define vki_sem_t sem_t
+
+
+#include <sys/mount.h>
+
+#define	VKI_MFSNAMELEN	MFSNAMELEN
+#define	VKI_MNAMELEN	MNAMELEN
+
+#define vki_fsid fsid
+#define vki_fsid_t fsid_t
+#define vki_statfs statfs
+#define vki_statfs64 statfs64
+
+
+#include <sys/select.h>
+
+#define vki_fd_set fd_set
+
+
+#include <sys/msgbuf.h>
+
+#define	VKI_MSG_BSIZE	MSG_BSIZE
+#define VKI_MSG_MAGIC	MSG_MAGIC
+#define vki_msgbuf msgbuf
+
+
+#include <sys/shm.h>
+
+#define VKI_SHM_RDONLY	SHM_RDONLY
+#define VKI_SHM_RND	SHM_RND
+
+#define vki_shmid_ds shmid_ds
+
+
+#include <sys/times.h>
+
+#define vki_tms tms
+
+
+#include <sys/utsname.h>
+
+#define	_VKI_SYS_NAMELEN	_SYS_NAMELEN
+#define vki_new_utsname utsname
+
+
+#include <sys/unistd.h>
+
+#define	VKI_F_OK	F_OK
+#define	VKI_X_OK	X_OK
+#define	VKI_W_OK	W_OK
+#define	VKI_R_OK	R_OK
+
+
+#include <sys/sysctl.h>
+
+#define VKI_CTL_MAXNAME		CTL_MAXNAME
+
+#define	VKI_CTL_UNSPEC		CTL_UNSPEC
+#define	VKI_CTL_KERN		CTL_KERN
+#define	VKI_CTL_VM		CTL_VM
+#define	VKI_CTL_VFS		CTL_VFS
+#define	VKI_CTL_NET		CTL_NET
+#define	VKI_CTL_DEBUG		CTL_DEBUG
+#define	VKI_CTL_HW		CTL_HW
+#define	VKI_CTL_MACHDEP		CTL_MACHDEP
+#define	VKI_CTL_USER		CTL_USER
+#define	VKI_CTL_MAXID		CTL_MAXID
+
+#define	VKI_HW_MACHINE		HW_MACHINE
+#define	VKI_HW_MODEL		HW_MODEL
+#define	VKI_HW_NCPU		HW_NCPU
+#define	VKI_HW_BYTEORDER	HW_BYTEORDER
+#define	VKI_HW_PHYSMEM		HW_PHYSMEM
+#define	VKI_HW_USERMEM		HW_USERMEM
+#define	VKI_HW_PAGESIZE		HW_PAGESIZE
+#define	VKI_HW_DISKNAMES	HW_DISKNAMES
+#define	VKI_HW_DISKSTATS	HW_DISKSTATS
+#define	VKI_HW_EPOCH  		HW_EPOCH
+#define VKI_HW_FLOATINGPT	HW_FLOATINGPT
+#define VKI_HW_MACHINE_ARCH	HW_MACHINE_ARCH
+#define VKI_HW_VECTORUNIT	HW_VECTORUNIT
+#define VKI_HW_BUS_FREQ		HW_BUS_FREQ
+#define VKI_HW_CPU_FREQ		HW_CPU_FREQ
+#define VKI_HW_CACHELINE	HW_CACHELINE
+#define VKI_HW_L1ICACHESIZE	HW_L1ICACHESIZE
+#define VKI_HW_L1DCACHESIZE	HW_L1DCACHESIZE
+#define VKI_HW_L2SETTINGS	HW_L2SETTINGS
+#define VKI_HW_L2CACHESIZE	HW_L2CACHESIZE
+#define VKI_HW_L3SETTINGS	HW_L3SETTINGS
+#define VKI_HW_L3CACHESIZE	HW_L3CACHESIZE
+#define VKI_HW_TB_FREQ		HW_TB_FREQ
+#define VKI_HW_MEMSIZE		HW_MEMSIZE
+#define VKI_HW_AVAILCPU		MW_AVAILCPU
+#define	VKI_HW_MAXID		MW_MAXID
+
+#define	VKI_KERN_USRSTACK32	KERN_USRSTACK32
+#define	VKI_KERN_USRSTACK64	KERN_USRSTACK64
+
+
+#include <sys/attr.h>
+
+#define vki_attrlist attrlist
+
+
+#include <sys/event.h>
+
+#define vki_kevent kevent
+
+
+#include <sys/ev.h>
+
+typedef struct eventreq vki_eventreq;
+
+
+#include <sys/ptrace.h>
+
+#define VKI_PTRACE_TRACEME   PT_TRACE_ME
+#define VKI_PTRACE_DETACH    PT_DETACH
+
+
+// sqlite/src/os_unix.c
+
+struct ByteRangeLockPB2
+{
+    unsigned long long offset;        /* offset to first byte to lock */
+    unsigned long long length;        /* nbr of bytes to lock */
+    unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
+    unsigned char unLockFlag;         /* 1 = unlock, 0 = lock */
+    unsigned char startEndFlag;       /* 1=rel to end of fork, 0=rel to start */
+    int fd;                           /* file desc to assoc this lock with */
+};
+
+#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
+#define vki_ByteRangeLockPB2 ByteRangeLockPB2
+#define VKI_afpfsByteRangeLock2FSCTL afpfsByteRangeLock2FSCTL
+
+
+// xnu/bsd/sys/fsctl.h
+
+#define VKI_FSIOC_SYNC_VOLUME        _IOW('A', 1, uint32_t)
+
+
+// Libc/pthreads/pthread.c
+
+#define VKI_WQOPS_QUEUE_ADD      1
+#define VKI_WQOPS_QUEUE_REMOVE   2
+#define VKI_WQOPS_THREAD_RETURN  4
+
+
+#include <sys/ttycom.h>
+
+#define vki_winsize winsize
+
+#define	VKI_TIOCMODG	TIOCMODG
+#define	VKI_TIOCMODS	TIOCMODS
+#define	VKI_TIOCEXCL	TIOCEXCL
+#define	VKI_TIOCNXCL	TIOCNXCL
+#define	VKI_TIOCFLUSH	TIOCFLUSH
+#define	VKI_TIOCGETA	TIOCGETA
+#define	VKI_TIOCSETA	TIOCSETA
+#define	VKI_TIOCSETAW	TIOCSETAW
+#define	VKI_TIOCSETAF	TIOCSETAF
+#define	VKI_TIOCGETD	TIOCGETD
+#define	VKI_TIOCSETD	TIOCSETD
+#define	VKI_TIOCSBRK	TIOCSBRK
+#define	VKI_TIOCCBRK	TIOCCBRK
+#define	VKI_TIOCSDTR	TIOCSDTR
+#define	VKI_TIOCCDTR	TIOCCDTR
+#define	VKI_TIOCGPGRP	TIOCGPGRP
+#define	VKI_TIOCSPGRP	TIOCSPGRP
+#define	VKI_TIOCOUTQ	TIOCOUTQ
+#define	VKI_TIOCSTI	TIOCSTI
+#define	VKI_TIOCNOTTY	TIOCNOTTY
+#define	VKI_TIOCPKT	TIOCPKT
+#define	VKI_TIOCSTOP	TIOCSTOP
+#define	VKI_TIOCSTART	TIOCSTART
+#define	VKI_TIOCMSET	TIOCMSET
+#define	VKI_TIOCMBIS	TIOCMBIS
+#define	VKI_TIOCMBIC	TIOCMBIC
+#define	VKI_TIOCMGET	TIOCMGET
+#define	VKI_TIOCREMOTE	TIOCREMOTE
+#define	VKI_TIOCGWINSZ	TIOCGWINSZ
+#define	VKI_TIOCSWINSZ	TIOCSWINSZ
+#define	VKI_TIOCUCNTL	TIOCUCNTL
+#define	VKI_TIOCSTAT	TIOCSTAT
+#define	VKI_UIOCCMD(n)	UIOCCMD(n)
+#define	VKI_TIOCSCONS	TIOCSCONS
+#define	VKI_TIOCCONS	TIOCCONS
+#define	VKI_TIOCSCTTY	TIOCSCTTY
+#define	VKI_TIOCEXT	TIOCEXT
+#define	VKI_TIOCSIG	TIOCSIG
+#define	VKI_TIOCDRAIN	TIOCDRAIN
+#define	VKI_TIOCMSDTRWAIT	TIOCMSDTRWAIT
+#define	VKI_TIOCMGDTRWAIT	TIOCMGDTRWAIT
+#define	VKI_TIOCTIMESTAMP	TIOCTIMESTAMP
+#define	VKI_TIOCDCDTIMESTAMP	TIOCDCDTIMESTAMP
+#define	VKI_TIOCSDRAINWAIT	TIOCSDRAINWAIT
+#define	VKI_TIOCGDRAINWAIT	TIOCGDRAINWAIT
+#define	VKI_TIOCDSIMICROCODE	TIOCDSIMICROCODE
+#define VKI_TIOCPTYGRANT	TIOCPTYGRANT
+#define VKI_TIOCPTYGNAME	TIOCPTYGNAME
+#define VKI_TIOCPTYUNLK	TIOCPTYUNLK
+
+
+#include <sys/filio.h>
+
+#define	VKI_FIOCLEX	FIOCLEX
+#define	VKI_FIONCLEX	FIONCLEX
+#define	VKI_FIONREAD	FIONREAD
+#define	VKI_FIONBIO	FIONBIO
+#define	VKI_FIOASYNC	FIOASYNC
+#define	VKI_FIOSETOWN	FIOSETOWN
+#define	VKI_FIOGETOWN	FIOGETOWN
+#define	VKI_FIODTYPE	FIODTYPE
+
+
+#include <sys/sockio.h>
+
+#define	VKI_SIOCSHIWAT	SIOCSHIWAT
+#define	VKI_SIOCGHIWAT	SIOCGHIWAT
+#define	VKI_SIOCSLOWAT	SIOCSLOWAT
+#define	VKI_SIOCGLOWAT	SIOCGLOWAT
+#define	VKI_SIOCATMARK	SIOCATMARK
+#define	VKI_SIOCSPGRP	SIOCSPGRP
+#define	VKI_SIOCGPGRP	SIOCGPGRP
+
+#define	VKI_SIOCSIFADDR		SIOCSIFADDR
+#define	VKI_OSIOCGIFADDR	OSIOCGIFADDR
+#define	VKI_SIOCSIFDSTADDR	SIOCSIFDSTADDR
+#define	VKI_OSIOCGIFDSTADDR	OSIOCGIFDSTADDR
+#define	VKI_SIOCSIFFLAGS	SIOCSIFFLAGS
+#define	VKI_SIOCGIFFLAGS	SIOCGIFFLAGS
+#define	VKI_OSIOCGIFBRDADDR	OSIOCGIFBRDADDR
+#define	VKI_SIOCSIFBRDADDR	SIOCSIFBRDADDR
+#define	VKI_OSIOCGIFCONF	OSIOCGIFCONF
+#define	VKI_OSIOCGIFNETMASK	OSIOCGIFNETMASK
+#define	VKI_SIOCSIFNETMASK	SIOCSIFNETMASK
+#define	VKI_SIOCGIFMETRIC	SIOCGIFMETRIC
+#define	VKI_SIOCSIFMETRIC	SIOCSIFMETRIC
+#define	VKI_SIOCDIFADDR		SIOCDIFADDR
+#define	VKI_SIOCAIFADDR		SIOCAIFADDR
+#define	VKI_SIOCGETVIFCNT	SIOCGETVIFCNT
+#define	VKI_SIOCGETSGCNT	SIOCGETSGCNT
+#define VKI_SIOCALIFADDR	SIOCALIFADDR
+#define VKI_SIOCGLIFADDR	SIOCGLIFADDR
+#define VKI_SIOCDLIFADDR	SIOCDLIFADDR
+
+#define	VKI_SIOCGIFADDR		SIOCGIFADDR
+#define	VKI_SIOCGIFDSTADDR	SIOCGIFDSTADDR
+#define	VKI_SIOCGIFBRDADDR	SIOCGIFBRDADDR
+#define	VKI_SIOCGIFCONF		SIOCGIFCONF
+#define	VKI_SIOCGIFNETMASK	SIOCGIFNETMASK
+#define VKI_SIOCAUTOADDR	SIOCAUTOADDR
+#define VKI_SIOCAUTONETMASK	SIOCAUTONETMASK
+#define VKI_SIOCARPIPLL		SIOCARPIPLL
+
+#define	VKI_SIOCADDMULTI	SIOCADDMULTI
+#define	VKI_SIOCDELMULTI	SIOCDELMULTI
+#define	VKI_SIOCGIFMTU		SIOCGIFMTU
+#define	VKI_SIOCSIFMTU	 	SIOCSIFMTU
+#define	VKI_SIOCGIFPHYS		SIOCGIFPHYS
+#define	VKI_SIOCSIFPHYS	 	SIOCSIFPHYS
+#define	VKI_SIOCSIFMEDIA	SIOCSIFMEDIA
+#define	VKI_SIOCGIFMEDIA	SIOCGIFMEDIA
+#define	VKI_SIOCSIFGENERIC	SIOCSIFGENERIC
+#define	VKI_SIOCGIFGENERIC	SIOCGIFGENERIC
+#define VKI_SIOCRSLVMULTI   	SIOCRSLVMULTI
+
+#define	VKI_SIOCSIFLLADDR	SIOCSIFLLADDR
+#define	VKI_SIOCGIFSTATUS	SIOCGIFSTATUS
+#define	VKI_SIOCSIFPHYADDR   	SIOCSIFPHYADDR
+#define	VKI_SIOCGIFPSRCADDR	SIOCGIFPSRCADDR
+#define	VKI_SIOCGIFPDSTADDR	SIOCGIFPDSTADDR
+#define	VKI_SIOCDIFPHYADDR	SIOCDIFPHYADDR
+#define	VKI_SIOCSLIFPHYADDR	SIOCSLIFPHYADDR
+#define	VKI_SIOCGLIFPHYADDR	SIOCGLIFPHYADDR
+
+#define	VKI_SIOCGIFDEVMTU	SIOCGIFDEVMTU
+#define	VKI_SIOCSIFALTMTU	SIOCSIFALTMTU
+#define VKI_SIOCGIFALTMTU	SIOCGIFALTMTU
+#define VKI_SIOCSIFBOND	 	SIOCSIFBOND
+#define VKI_SIOCGIFBOND		SIOCGIFBOND
+#define	VKI_SIOCIFCREATE	SIOCIFCREATE
+#define	VKI_SIOCIFDESTROY	SIOCIFDESTROY
+#define	VKI_SIOCSIFVLAN	 	SIOCSIFVLAN
+#define	VKI_SIOCGIFVLAN		SIOCGIFVLAN
+
+#define	VKI_SIOCSETVLAN		SIOCSIFVLAN
+#define	VKI_SIOCGETVLAN		SIOCGIFVLAN
+
+#define	VKI_SIOCGIFASYNCMAP 	SIOCGIFASYNCMAP
+#define	VKI_SIOCSIFASYNCMAP 	SIOCSIGASYNCMAP
+
+
+#include <sys/dtrace.h>
+
+#define VKI_DTRACEHIOC_REMOVE   DTRACEHIOC_REMOVE
+#define VKI_DTRACEHIOC_ADDDOF   DTRACEHIOC_ADDDOF
+
+
+#include <sys/ucontext.h>
+
+/* quite why sys/ucontext.h provides a 'struct __darwin_ucontext'
+   but no 'struct ucontext' beats me. -- JRS */
+#define vki_ucontext __darwin_ucontext
+
+
+#include <sys/termios.h>
+
+#define vki_termios termios
+
+
+#include <uuid/uuid.h>
+
+#define vki_uuid_t uuid_t
+
+
+#include <bsm/audit.h>
+
+#define	VKI_A_GETPOLICY	A_GETPOLICY	
+#define	VKI_A_SETPOLICY	A_SETPOLICY	
+#define	VKI_A_GETKMASK	A_GETKMASK	
+#define	VKI_A_SETKMASK	A_SETKMASK	
+#define	VKI_A_GETQCTRL	A_GETQCTRL	
+#define	VKI_A_SETQCTRL	A_SETQCTRL	
+#define	VKI_A_GETCWD	A_GETCWD	
+#define	VKI_A_GETCAR	A_GETCAR	
+#define	VKI_A_GETSTAT	A_GETSTAT	
+#define	VKI_A_SETSTAT	A_SETSTAT	
+#define	VKI_A_SETUMASK	A_SETUMASK	
+#define	VKI_A_SETSMASK	A_SETSMASK	
+#define	VKI_A_GETCOND	A_GETCOND	
+#define	VKI_A_SETCOND	A_SETCOND	
+#define	VKI_A_GETCLASS	A_GETCLASS	
+#define	VKI_A_SETCLASS	A_SETCLASS	
+#define	VKI_A_GETPINFO	A_GETPINFO	
+#define	VKI_A_SETPMASK	A_SETPMASK	
+#define	VKI_A_SETFSIZE	A_SETFSIZE	
+#define	VKI_A_GETFSIZE	A_GETFSIZE	
+#define	VKI_A_GETPINFO_ADDR	A_GETPINFO_ADDR	
+#define	VKI_A_GETKAUDIT	A_GETKAUDIT	
+#define	VKI_A_SETKAUDIT	A_SETKAUDIT	
+
+
+#endif
diff --git a/include/vki/vki-scnums-darwin.h b/include/vki/vki-scnums-darwin.h
new file mode 100644
index 0000000..281ccc3
--- /dev/null
+++ b/include/vki/vki-scnums-darwin.h
@@ -0,0 +1,580 @@
+
+/*--------------------------------------------------------------------*/
+/*--- System call numbers for Darwin.          vki-scnums-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2007-2009 Apple Inc.
+      Greg Parker  gparker@apple.com
+
+   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_SCNUMS_DARWIN_H
+#define __VKI_SCNUMS_DARWIN_H
+
+
+// osfmk/mach/i386/syscall_sw.h
+
+// x86_64's syscall numbering system is used for all architectures. 
+// Don't pass __NR_something directly to any syscall instruction.
+// Hack: x86 `int $0x80` (unix, 64-bit result) are special.
+
+// Encoding: the top 8-bits are the syscall class.  The low 24 are the
+// syscall number (index) within that class.
+
+#define VG_DARWIN_SYSCALL_CLASS_SHIFT     24
+#define VG_DARWIN_SYSCALL_CLASS_MASK      (0xFF << VG_DARWIN_SYSCALL_CLASS_SHIFT)
+#define VG_DARWIN_SYSCALL_NUMBER_MASK     (~VG_DARWIN_SYSCALL_CLASS_MASK)
+
+#define VG_DARWIN_SYSCALL_CLASS_NONE      0       /* Invalid */
+#define VG_DARWIN_SYSCALL_CLASS_MACH      1       /* Mach */      
+#define VG_DARWIN_SYSCALL_CLASS_UNIX      2       /* Unix/BSD */
+#define VG_DARWIN_SYSCALL_CLASS_MDEP      3       /* Machine-dependent */
+#define VG_DARWIN_SYSCALL_CLASS_DIAG      4       /* Diagnostics */
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_MACH(syscall_number) \
+    ((VG_DARWIN_SYSCALL_CLASS_MACH << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+     (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(syscall_number) \
+    ((VG_DARWIN_SYSCALL_CLASS_UNIX << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+     (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(syscall_number) \
+    ((VG_DARWIN_SYSCALL_CLASS_MDEP << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+     (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_DIAG(syscall_number) \
+    ((VG_DARWIN_SYSCALL_CLASS_DIAG << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+     (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+
+
+// mdep syscalls
+
+#if defined(VGA_x86)
+
+// osfmk/i386/machdep_call.c
+// #  define __NR_thread_get_cthread_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(0)
+// #  define __NR_thread_set_cthread_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(1)
+// #  define __NR_2 VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(2)
+#  define __NR_pthread_set_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(3)
+// #  define __NR_thread_set_user_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(4)
+// #  define __NR_i386_set_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(5)
+// #  define __NR_i386_get_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(6)
+
+#elif defined(VGA_amd64)
+
+// osfmk/i386/machdep_call.c
+#  define __NR_pthread_set_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(3)
+
+#else
+#  error unknown architecture
+#endif
+
+
+// osfmk/mach/syscall_sw.h
+
+#define __NR_mach_reply_port                  VG_DARWIN_SYSCALL_CONSTRUCT_MACH(26)
+#define __NR_thread_self_trap                 VG_DARWIN_SYSCALL_CONSTRUCT_MACH(27)
+#define __NR_task_self_trap                   VG_DARWIN_SYSCALL_CONSTRUCT_MACH(28)
+#define __NR_host_self_trap                   VG_DARWIN_SYSCALL_CONSTRUCT_MACH(29)
+
+#define __NR_mach_msg_trap                    VG_DARWIN_SYSCALL_CONSTRUCT_MACH(31)
+#define __NR_mach_msg_overwrite_trap          VG_DARWIN_SYSCALL_CONSTRUCT_MACH(32)
+#define __NR_semaphore_signal_trap            VG_DARWIN_SYSCALL_CONSTRUCT_MACH(33)
+#define __NR_semaphore_signal_all_trap        VG_DARWIN_SYSCALL_CONSTRUCT_MACH(34)
+#define __NR_semaphore_signal_thread_trap     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(35)
+#define __NR_semaphore_wait_trap              VG_DARWIN_SYSCALL_CONSTRUCT_MACH(36)
+#define __NR_semaphore_wait_signal_trap       VG_DARWIN_SYSCALL_CONSTRUCT_MACH(37)
+#define __NR_semaphore_timedwait_trap         VG_DARWIN_SYSCALL_CONSTRUCT_MACH(38)
+#define __NR_semaphore_timedwait_signal_trap  VG_DARWIN_SYSCALL_CONSTRUCT_MACH(39)
+
+#if defined(VGA_x86)
+#define __NR_init_process                     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(41)
+#define __NR_map_fd                           VG_DARWIN_SYSCALL_CONSTRUCT_MACH(43)
+#endif
+
+#define __NR_task_name_for_pid                VG_DARWIN_SYSCALL_CONSTRUCT_MACH(44)
+#define __NR_task_for_pid                     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(45)
+#define __NR_pid_for_task                     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(46)
+
+#if defined(VGA_x86)
+#define __NR_macx_swapon                      VG_DARWIN_SYSCALL_CONSTRUCT_MACH(48)
+#define __NR_macx_swapoff                     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(49)
+#define __NR_macx_triggers                    VG_DARWIN_SYSCALL_CONSTRUCT_MACH(51)
+#define __NR_macx_backing_store_suspend       VG_DARWIN_SYSCALL_CONSTRUCT_MACH(52)
+#define __NR_macx_backing_store_recovery      VG_DARWIN_SYSCALL_CONSTRUCT_MACH(53)
+#endif
+
+#define __NR_swtch_pri                        VG_DARWIN_SYSCALL_CONSTRUCT_MACH(59)
+#define __NR_swtch                            VG_DARWIN_SYSCALL_CONSTRUCT_MACH(60)
+#define __NR_sched_yield  __NR_swtch  /* linux-alike name */
+#define __NR_syscall_thread_switch            VG_DARWIN_SYSCALL_CONSTRUCT_MACH(61)
+#define __NR_clock_sleep_trap                 VG_DARWIN_SYSCALL_CONSTRUCT_MACH(62)
+
+#define __NR_mach_timebase_info               VG_DARWIN_SYSCALL_CONSTRUCT_MACH(89)
+#define __NR_mach_wait_until                  VG_DARWIN_SYSCALL_CONSTRUCT_MACH(90)
+#define __NR_mk_timer_create                  VG_DARWIN_SYSCALL_CONSTRUCT_MACH(91)
+#define __NR_mk_timer_destroy                 VG_DARWIN_SYSCALL_CONSTRUCT_MACH(92)
+#define __NR_mk_timer_arm                     VG_DARWIN_SYSCALL_CONSTRUCT_MACH(93)
+#define __NR_mk_timer_cancel                  VG_DARWIN_SYSCALL_CONSTRUCT_MACH(94)
+
+#define __NR_iokit_user_client_trap           VG_DARWIN_SYSCALL_CONSTRUCT_MACH(100)
+
+
+// bsd/sys/syscall.h
+ 
+#define	__NR_syscall        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(0)
+#define	__NR_exit           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(1)
+#define	__NR_fork           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(2) // was UX64
+#define	__NR_read           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(3)
+#define	__NR_write          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(4)
+#define	__NR_open           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(5)
+#define	__NR_close          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(6)
+#define	__NR_wait4          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(7)
+			/* 8  old creat */
+#define	__NR_link           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(9)
+#define	__NR_unlink         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(10)
+			/* 11  old execv */
+#define	__NR_chdir          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(12)
+#define	__NR_fchdir         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(13)
+#define	__NR_mknod          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(14)
+#define	__NR_chmod          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(15)
+#define	__NR_chown          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(16)
+			/* 17  old break */
+#define	__NR_getfsstat      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(18)
+			/* 19  old lseek */
+#define	__NR_getpid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(20)
+			/* 21  old mount */
+			/* 22  old umount */
+#define	__NR_setuid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(23)
+#define	__NR_getuid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(24)
+#define	__NR_geteuid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(25)
+#define	__NR_ptrace         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(26)
+#define	__NR_recvmsg        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(27)
+#define	__NR_sendmsg        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(28)
+#define	__NR_recvfrom       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(29)
+#define	__NR_accept         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(30)
+#define	__NR_getpeername    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(31)
+#define	__NR_getsockname    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(32)
+#define	__NR_access         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(33)
+#define	__NR_chflags        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(34)
+#define	__NR_fchflags       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(35)
+#define	__NR_sync           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(36)
+#define	__NR_kill           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(37)
+			/* 38  old stat */
+#define	__NR_getppid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(39)
+			/* 40  old lstat */
+#define	__NR_dup            VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(41)
+#define	__NR_pipe           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(42) // was UX64
+#define	__NR_getegid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(43)
+#define	__NR_profil         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(44)
+			/* 45  old ktrace */
+#define	__NR_sigaction      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(46)
+#define	__NR_getgid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(47)
+#define	__NR_sigprocmask    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(48)
+#define	__NR_getlogin       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(49)
+#define	__NR_setlogin       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(50)
+#define	__NR_acct           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(51)
+#define	__NR_sigpending     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(52)
+#define	__NR_sigaltstack    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(53)
+#define	__NR_ioctl          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(54)
+#define	__NR_reboot         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(55)
+#define	__NR_revoke         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(56)
+#define	__NR_symlink        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(57)
+#define	__NR_readlink       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(58)
+#define	__NR_execve         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(59)
+#define	__NR_umask          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(60)
+#define	__NR_chroot         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(61)
+			/* 62  old fstat */
+			/* 63  used internally , reserved */
+			/* 64  old getpagesize */
+#define	__NR_msync          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(65)
+#define	__NR_vfork          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(66)
+			/* 67  old vread */
+			/* 68  old vwrite */
+			/* 69  old sbrk */
+			/* 70  old sstk */
+			/* 71  old mmap */
+			/* 72  old vadvise */
+#define	__NR_munmap         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(73)
+#define	__NR_mprotect       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(74)
+#define	__NR_madvise        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(75)
+			/* 76  old vhangup */
+			/* 77  old vlimit */
+#define	__NR_mincore        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(78)
+#define	__NR_getgroups      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(79)
+#define	__NR_setgroups      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(80)
+#define	__NR_getpgrp        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(81)
+#define	__NR_setpgid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(82)
+#define	__NR_setitimer      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(83)
+			/* 84  old wait */
+#define	__NR_swapon         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(85)
+#define	__NR_getitimer      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(86)
+			/* 87  old gethostname */
+			/* 88  old sethostname */
+#define	__NR_getdtablesize  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(89)
+#define	__NR_dup2           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(90)
+			/* 91  old getdopt */
+#define	__NR_fcntl          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(92)
+#define	__NR_select         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(93)
+			/* 94  old setdopt */
+#define	__NR_fsync          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(95)
+#define	__NR_setpriority    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(96)
+#define	__NR_socket         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(97)
+#define	__NR_connect        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(98)
+			/* 99  old accept */
+#define	__NR_getpriority    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(100)
+			/* 101  old send */
+			/* 102  old recv */
+			/* 103  old sigreturn */
+#define	__NR_bind           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(104)
+#define	__NR_setsockopt     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(105)
+#define	__NR_listen         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(106)
+			/* 107  old vtimes */
+			/* 108  old sigvec */
+			/* 109  old sigblock */
+			/* 110  old sigsetmask */
+#define	__NR_sigsuspend     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(111)
+			/* 112  old sigstack */
+			/* 113  old recvmsg */
+			/* 114  old sendmsg */
+			/* 115  old vtrace */
+#define	__NR_gettimeofday   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(116)
+#define	__NR_getrusage      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(117)
+#define	__NR_getsockopt     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(118)
+			/* 119  old resuba */
+#define	__NR_readv          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(120)
+#define	__NR_writev         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(121)
+#define	__NR_settimeofday   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(122)
+#define	__NR_fchown         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(123)
+#define	__NR_fchmod         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(124)
+			/* 125  old recvfrom */
+#define	__NR_setreuid       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(126)
+#define	__NR_setregid       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(127)
+#define	__NR_rename         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(128)
+			/* 129  old truncate */
+			/* 130  old ftruncate */
+#define	__NR_flock          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(131)
+#define	__NR_mkfifo         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(132)
+#define	__NR_sendto         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(133)
+#define	__NR_shutdown       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(134)
+#define	__NR_socketpair     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(135)
+#define	__NR_mkdir          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(136)
+#define	__NR_rmdir          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(137)
+#define	__NR_utimes         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(138)
+#define	__NR_futimes        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(139)
+#define	__NR_adjtime        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(140)
+			/* 141  old getpeername */
+#define __NR_gethostuuid    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(142)
+			/* 143  old sethostid */
+			/* 144  old getrlimit */
+			/* 145  old setrlimit */
+			/* 146  old killpg */
+#define	__NR_setsid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(147)
+			/* 148  old setquota */
+			/* 149  old qquota */
+			/* 150  old getsockname */
+#define	__NR_getpgid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(151)
+#define	__NR_setprivexec    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(152)
+#define	__NR_pread          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(153)
+#define	__NR_pwrite         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(154)
+#define __NR_nfssvc         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(155)
+			/* 156  old getdirentries */
+#define	__NR_statfs         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(157)
+#define	__NR_fstatfs        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(158)
+#define	__NR_unmount        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(159)
+			/* 160  old async_daemon */
+#define __NR_getfh          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(161)
+			/* 162  old getdomainname */
+			/* 163  old setdomainname */
+			/* 164  */
+#define	__NR_quotactl       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(165)
+			/* 166  old exportfs */
+#define	__NR_mount          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(167)
+			/* 168  old ustat */
+#define __NR_csops          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(169)
+			/* 170  old table */
+			/* 171  old wait3 */
+			/* 172  old rpause */
+#define	__NR_waitid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(173)
+			/* 174  old getdents */
+			/* 175  old gc_control */
+#define	__NR_add_profil     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(176)
+			/* 177  */
+			/* 178  */
+			/* 179  */
+#define	__NR_kdebug_trace   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(180)
+#define	__NR_setgid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(181)
+#define	__NR_setegid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(182)
+#define	__NR_seteuid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(183)
+#define __NR_sigreturn      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(184)
+#define __NR_chud           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(185)
+			/* 186  */
+			/* 187  */
+#define	__NR_stat           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(188)
+#define	__NR_fstat          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(189)
+#define	__NR_lstat          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(190)
+#define	__NR_pathconf       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(191)
+#define	__NR_fpathconf      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(192)
+			/* 193 */
+#define	__NR_getrlimit      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(194)
+#define	__NR_setrlimit      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(195)
+#define	__NR_getdirentries  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(196)
+#define	__NR_mmap           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(197)
+			/* 198  __syscall */
+#define	__NR_lseek          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(199) // was UX64
+#define	__NR_truncate       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(200)
+#define	__NR_ftruncate      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(201)
+#define	__NR___sysctl       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(202)
+#define	__NR_mlock          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(203)
+#define	__NR_munlock        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(204)
+#define	__NR_undelete       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(205)
+#define	__NR_ATsocket       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(206)
+#define	__NR_ATgetmsg       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(207)
+#define	__NR_ATputmsg       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(208)
+#define	__NR_ATPsndreq      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(209)
+#define	__NR_ATPsndrsp      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(210)
+#define	__NR_ATPgetreq      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(211)
+#define	__NR_ATPgetrsp      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(212)
+			/* 213  Reserved for AppleTalk */
+#define	__NR_kqueue_from_portset_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(214)
+#define	__NR_kqueue_portset_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(215)
+#define	__NR_mkcomplex      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(216)
+#define	__NR_statv          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(217)
+#define	__NR_lstatv         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(218)
+#define	__NR_fstatv         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(219)
+#define	__NR_getattrlist    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(220)
+#define	__NR_setattrlist    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(221)
+#define	__NR_getdirentriesattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(222)
+#define	__NR_exchangedata   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(223)
+			/* 224  checkuseraccess */
+#define	__NR_searchfs       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(225)
+#define	__NR_delete         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(226)
+#define	__NR_copyfile       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(227)
+			/* 228  */
+			/* 229  */
+#define	__NR_poll           VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(230)
+#define	__NR_watchevent     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(231)
+#define	__NR_waitevent      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(232)
+#define	__NR_modwatch       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(233)
+#define	__NR_getxattr       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(234)
+#define	__NR_fgetxattr      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(235)
+#define	__NR_setxattr       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(236)
+#define	__NR_fsetxattr      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(237)
+#define	__NR_removexattr    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(238)
+#define	__NR_fremovexattr   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(239)
+#define	__NR_listxattr      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(240)
+#define	__NR_flistxattr     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(241)
+#define	__NR_fsctl          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(242)
+#define	__NR_initgroups     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(243)
+#define __NR_posix_spawn    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(244)
+			/* 245  */
+			/* 246  */
+#define __NR_nfsclnt        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(247)
+#define __NR_fhopen         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(248)
+			/* 249  */
+#define	__NR_minherit       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(250)
+#define	__NR_semsys         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(251)
+#define	__NR_msgsys         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(252)
+#define	__NR_shmsys         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(253)
+#define	__NR_semctl         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(254)
+#define	__NR_semget         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(255)
+#define	__NR_semop          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(256)
+			/* 257  */
+#define	__NR_msgctl         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(258)
+#define	__NR_msgget         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(259)
+#define	__NR_msgsnd         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(260)
+#define	__NR_msgrcv         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(261)
+#define	__NR_shmat          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(262)
+#define	__NR_shmctl         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(263)
+#define	__NR_shmdt          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(264)
+#define	__NR_shmget         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(265)
+#define	__NR_shm_open       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(266)
+#define	__NR_shm_unlink     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(267)
+#define	__NR_sem_open       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(268)
+#define	__NR_sem_close      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(269)
+#define	__NR_sem_unlink     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(270)
+#define	__NR_sem_wait       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(271)
+#define	__NR_sem_trywait    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(272)
+#define	__NR_sem_post       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(273)
+#define	__NR_sem_getvalue   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(274)
+#define	__NR_sem_init       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(275)
+#define	__NR_sem_destroy    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(276)
+#define	__NR_open_extended  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(277)
+#define	__NR_umask_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(278)
+#define	__NR_stat_extended  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(279)
+#define	__NR_lstat_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(280)
+#define	__NR_fstat_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(281)
+#define	__NR_chmod_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(282)
+#define	__NR_fchmod_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(283)
+#define	__NR_access_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(284)
+#define	__NR_settid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(285)
+#define	__NR_gettid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(286)
+#define	__NR_setsgroups     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(287)
+#define	__NR_getsgroups     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(288)
+#define	__NR_setwgroups     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(289)
+#define	__NR_getwgroups     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(290)
+#define	__NR_mkfifo_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(291)
+#define	__NR_mkdir_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(292)
+#define	__NR_identitysvc    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(293)
+#define	__NR_shared_region_check_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(294)
+#define	__NR_shared_region_map_np   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(295)
+			/* 296  old load_shared_file */
+			/* 297  old reset_shared_file */
+			/* 298  old new_system_shared_regions */
+			/* 299  old shared_region_map_file_np */
+			/* 300  old shared_region_make_private_np */
+#define __NR___pthread_mutex_destroy VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(301)
+#define __NR___pthread_mutex_init VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(302)
+#define __NR___pthread_mutex_lock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(303)
+#define __NR___pthread_mutex_trylock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(304)
+#define __NR___pthread_mutex_unlock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(305)
+#define __NR___pthread_cond_init VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(306)
+#define __NR___pthread_cond_destroy VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(307)
+#define __NR___pthread_cond_broadcast VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(308)
+#define __NR___pthread_cond_signal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(309)
+#define	__NR_getsid         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(310)
+#define	__NR_settid_with_pid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(311)
+#define __NR___pthread_cond_timedwait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(312)
+#define	__NR_aio_fsync      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(313)
+#define	__NR_aio_return     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(314)
+#define	__NR_aio_suspend    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(315)
+#define	__NR_aio_cancel     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(316)
+#define	__NR_aio_error      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(317)
+#define	__NR_aio_read       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(318)
+#define	__NR_aio_write      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(319)
+#define	__NR_lio_listio     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(320)
+#define __NR___pthread_cond_wait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(321)
+#define __NR_iopolicysys    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(322)
+			/* 323  */
+#define	__NR_mlockall       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(324)
+#define	__NR_munlockall     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(325)
+			/* 326  */
+#define	__NR_issetugid      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(327)
+#define	__NR___pthread_kill VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(328)
+#define	__NR___pthread_sigmask VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(329)
+#define	__NR___sigwait        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(330)
+#define	__NR_sigwait        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(330) // GrP fixme hack
+#define	__NR___disable_threadsignal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(331)
+#define	__NR___pthread_markcancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(332)
+#define	__NR___pthread_canceled VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(333)
+#define	__NR___semwait_signal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(334)
+			/* 335  old utrace */
+#define __NR_proc_info      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(336)
+#define __NR_sendfile       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(337)
+#define __NR_stat64         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(338)
+#define __NR_fstat64        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(339)
+#define __NR_lstat64        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(340)
+#define __NR_stat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(341)
+#define __NR_lstat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(342)
+#define __NR_fstat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(343)
+#define __NR_getdirentries64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(344)
+#define __NR_statfs64       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(345)
+#define __NR_fstatfs64      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(346)
+#define __NR_getfsstat64    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(347)
+#define __NR___pthread_chdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(348)
+#define __NR___pthread_fchdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(349)
+
+#define	__NR_audit          VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(350)
+#define	__NR_auditon        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(351)
+			/* 352  */
+#define	__NR_getauid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(353)
+#define	__NR_setauid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(354)
+#define	__NR_getaudit       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(355)
+#define	__NR_setaudit       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(356)
+#define	__NR_getaudit_addr  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(357)
+#define	__NR_setaudit_addr  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(358)
+#define	__NR_auditctl       VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(359)
+#define	__NR_bsdthread_create VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(360)
+#define	__NR_bsdthread_terminate VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(361)
+#define	__NR_kqueue         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(362)
+#define	__NR_kevent         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(363)
+#define	__NR_lchown         VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(364)
+#define __NR_stack_snapshot VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(365)
+#define __NR_bsdthread_register VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(366)
+#define __NR_workq_open     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(367)
+#define __NR_workq_ops      VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(368)
+			/* 369  */
+			/* 370  */
+			/* 371  */
+			/* 372  */
+			/* 373  */
+			/* 374  */
+			/* 375  */
+			/* 376  */
+			/* 377  */
+			/* 378  */
+			/* 379  */
+#define __NR___mac_execve   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(380)
+#define __NR___mac_syscall  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(381)
+#define __NR___mac_get_file VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(382)
+#define __NR___mac_set_file VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(383)
+#define __NR___mac_get_link VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(384)
+#define __NR___mac_set_link VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(385)
+#define __NR___mac_get_proc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(386)
+#define __NR___mac_set_proc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(387)
+#define __NR___mac_get_fd   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(388)
+#define __NR___mac_set_fd   VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(389)
+#define __NR___mac_get_pid  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(390)
+#define __NR___mac_get_lcid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(391)
+#define __NR___mac_get_lctx VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(392)
+#define __NR___mac_set_lctx VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(393)
+#define __NR_setlcid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(394)
+#define __NR_getlcid        VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(395)
+#define __NR_read_nocancel  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(396)
+#define __NR_write_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(397)
+#define __NR_open_nocancel  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(398)
+#define __NR_close_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(399)
+#define __NR_wait4_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(400)
+#define __NR_recvmsg_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(401)
+#define __NR_sendmsg_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(402)
+#define __NR_recvfrom_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(403)
+#define __NR_accept_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(404)
+#define __NR_msync_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(405)
+#define __NR_fcntl_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(406)
+#define __NR_select_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(407)
+#define __NR_fsync_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(408)
+#define __NR_connect_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(409)
+#define __NR_sigsuspend_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(410)
+#define __NR_readv_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(411)
+#define __NR_writev_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(412)
+#define __NR_sendto_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(413)
+#define __NR_pread_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(414)
+#define __NR_pwrite_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(415)
+#define __NR_waitid_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(416)
+#define __NR_poll_nocancel  VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(417)
+#define __NR_msgsnd_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(418)
+#define __NR_msgrcv_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(419)
+#define __NR_sem_wait_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(420)
+#define __NR_aio_suspend_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(421)
+#define __NR___sigwait_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(422)
+#define __NR___semwait_signal_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(423)
+#define __NR___mac_mount    VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(424)
+#define __NR___mac_get_mount VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(425)
+#define __NR___mac_getfsstat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(426)
+#define	__NR_MAXSYSCALL     VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(427)
+
+#define __NR_DARWIN_FAKE_SIGRETURN (1 + __NR_MAXSYSCALL)
+
+#endif
diff --git a/lackey/Makefile.am b/lackey/Makefile.am
index 69a1a82..6a2ff3d 100644
--- a/lackey/Makefile.am
+++ b/lackey/Makefile.am
@@ -19,6 +19,12 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += lackey-ppc64-aix5
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += lackey-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += lackey-amd64-darwin
+endif
 
 LACKEY_SOURCES_COMMON = lk_main.c
 
@@ -63,3 +69,17 @@
 lackey_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 lackey_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 lackey_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+lackey_x86_darwin_SOURCES      = $(LACKEY_SOURCES_COMMON)
+lackey_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+lackey_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN)
+lackey_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+lackey_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+lackey_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+lackey_amd64_darwin_SOURCES      = $(LACKEY_SOURCES_COMMON)
+lackey_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+lackey_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+lackey_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+lackey_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+lackey_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/massif/Makefile.am b/massif/Makefile.am
index 6ff1f51..3033df1 100644
--- a/massif/Makefile.am
+++ b/massif/Makefile.am
@@ -5,6 +5,7 @@
 bin_SCRIPTS = ms_print
 
 noinst_PROGRAMS = 
+noinst_DSYMS =
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 noinst_PROGRAMS += massif-x86-linux vgpreload_massif-x86-linux.so
 endif
@@ -23,6 +24,14 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += massif-ppc64-aix5 vgpreload_massif-ppc64-aix5.so
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += massif-x86-darwin vgpreload_massif-x86-darwin.so
+noinst_DSYMS    +=                   vgpreload_massif-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += massif-amd64-darwin vgpreload_massif-amd64-darwin.so
+noinst_DSYMS    +=                     vgpreload_massif-amd64-darwin.so
+endif
 
 vgpreload_massif_x86_linux_so_SOURCES      = 
 vgpreload_massif_x86_linux_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_LINUX)
@@ -72,6 +81,22 @@
 	$(PRELOAD_LDFLAGS_PPC64_AIX5) \
 	$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
+vgpreload_massif_x86_darwin_so_SOURCES      = 
+vgpreload_massif_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_massif_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_massif_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_massif_x86_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_X86_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_massif_amd64_darwin_so_SOURCES      = 
+vgpreload_massif_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_massif_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_massif_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_massif_amd64_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
 MASSIF_SOURCES_COMMON = ms_main.c
 
 massif_x86_linux_SOURCES      = $(MASSIF_SOURCES_COMMON)
@@ -115,3 +140,17 @@
 massif_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 massif_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 massif_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+massif_x86_darwin_SOURCES      = $(MASSIF_SOURCES_COMMON)
+massif_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+massif_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN)
+massif_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+massif_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+massif_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+massif_amd64_darwin_SOURCES      = $(MASSIF_SOURCES_COMMON)
+massif_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+massif_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+massif_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+massif_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+massif_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 318fc11..f3d46fe 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -1288,8 +1288,10 @@
 
 // Take a snapshot, and only that -- decisions on whether to take a
 // snapshot, or what kind of snapshot, are made elsewhere.
+// Nb: we call the arg "my_time" because "time" shadows a global declaration
+// in /usr/include/time.h on Darwin.
 static void
-take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time time,
+take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time my_time,
               Bool is_detailed)
 {
    tl_assert(!is_snapshot_in_use(snapshot));
@@ -1314,7 +1316,7 @@
 
    // Rest of snapshot.
    snapshot->kind = kind;
-   snapshot->time = time;
+   snapshot->time = my_time;
    sanity_check_snapshot(snapshot);
 
    // Update stats.
@@ -1341,12 +1343,14 @@
 
    Snapshot* snapshot;
    Bool      is_detailed;
-   Time      time = get_time();
+   // Nb: we call this variable "my_time" because "time" shadows a global
+   // declaration in /usr/include/time.h on Darwin.
+   Time      my_time = get_time();
 
    switch (kind) {
     case Normal: 
       // Only do a snapshot if it's time.
-      if (time < earliest_possible_time_of_next_snapshot) {
+      if (my_time < earliest_possible_time_of_next_snapshot) {
          n_skipped_snapshots++;
          n_skipped_snapshots_since_last_snapshot++;
          return;
@@ -1376,7 +1380,7 @@
 
    // Take the snapshot.
    snapshot = & snapshots[next_snapshot_i];
-   take_snapshot(snapshot, kind, time, is_detailed);
+   take_snapshot(snapshot, kind, my_time, is_detailed);
 
    // Record if it was detailed.
    if (is_detailed) {
@@ -1422,7 +1426,7 @@
    }
 
    // Work out the earliest time when the next snapshot can happen.
-   earliest_possible_time_of_next_snapshot = time + min_time_interval;
+   earliest_possible_time_of_next_snapshot = my_time + min_time_interval;
 }
 
 
diff --git a/massif/tests/malloc_usable.c b/massif/tests/malloc_usable.c
index 4a0e470..2578173 100644
--- a/massif/tests/malloc_usable.c
+++ b/massif/tests/malloc_usable.c
@@ -5,7 +5,7 @@
 
 int main(void)
 {
-#  if !defined(VGO_aix5)
+#  if !defined(VGO_aix5) && !defined(VGO_darwin)
    // 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/Makefile.am b/memcheck/Makefile.am
index e042a6b..e11e841 100644
--- a/memcheck/Makefile.am
+++ b/memcheck/Makefile.am
@@ -3,6 +3,7 @@
 SUBDIRS += perf
 
 noinst_PROGRAMS = 
+noinst_DSYMS = 
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 noinst_PROGRAMS += memcheck-x86-linux vgpreload_memcheck-x86-linux.so
 endif
@@ -21,6 +22,14 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += memcheck-ppc64-aix5 vgpreload_memcheck-ppc64-aix5.so
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += memcheck-x86-darwin vgpreload_memcheck-x86-darwin.so
+noinst_DSYMS    +=                     vgpreload_memcheck-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += memcheck-amd64-darwin vgpreload_memcheck-amd64-darwin.so
+noinst_DSYMS    +=                       vgpreload_memcheck-amd64-darwin.so
+endif
 
 VGPRELOAD_MEMCHECK_SOURCES_COMMON = mc_replace_strmem.c
 
@@ -78,6 +87,24 @@
 	$(PRELOAD_LDFLAGS_PPC64_AIX5) \
 	$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
 
+vgpreload_memcheck_x86_darwin_so_SOURCES      = $(VGPRELOAD_MEMCHECK_SOURCES_COMMON)
+vgpreload_memcheck_x86_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_memcheck_x86_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_X86_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_memcheck_amd64_darwin_so_SOURCES      = $(VGPRELOAD_MEMCHECK_SOURCES_COMMON)
+vgpreload_memcheck_amd64_darwin_so_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_memcheck_amd64_darwin_so_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_LDFLAGS      = \
+	$(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+	$(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
 MEMCHECK_SOURCES_COMMON = \
 	mc_leakcheck.c \
 	mc_malloc_wrappers.c \
@@ -134,6 +161,22 @@
 memcheck_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 memcheck_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
 
+memcheck_x86_darwin_SOURCES      = $(MEMCHECK_SOURCES_COMMON)
+memcheck_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+memcheck_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN) -O2
+memcheck_x86_darwin_CCASFLAGS    = $(AM_CCASFLAGS_X86_DARWIN)
+memcheck_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+memcheck_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+memcheck_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+memcheck_amd64_darwin_SOURCES      = $(MEMCHECK_SOURCES_COMMON)
+memcheck_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+memcheck_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN) -O2
+memcheck_amd64_darwin_CCASFLAGS    = $(AM_CCASFLAGS_AMD64_DARWIN)
+memcheck_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+memcheck_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+memcheck_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
 mcincludedir = $(includedir)/valgrind
 
 mcinclude_HEADERS = \
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index e56a163..edc123a 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -268,7 +268,7 @@
          if (maybe_gcc) {
             VG_(message)(Vg_UserMsg, 
                "%sAddress 0x%llx is just below the stack ptr.  "
-               "To suppress, use: --workaround-gcc296-bugs=yes%s",
+               "To suppress, use: --workaround-gcc296-bugs=yes%s", 
                xpre, (ULong)a, xpost
             );
 	 } else {
diff --git a/memcheck/mc_machine.c b/memcheck/mc_machine.c
index 4072b8a..05f6da4 100644
--- a/memcheck/mc_machine.c
+++ b/memcheck/mc_machine.c
@@ -491,6 +491,7 @@
    if (o == GOF(IP_AT_SYSCALL) && sz == 8) return -1; /* slot unused */
    if (o == GOF(IDFLAG)  && sz == 8) return -1; /* slot used for %DH */
    if (o == GOF(FS_ZERO) && sz == 8) return -1; /* slot unused */
+   if (o == GOF(GS_0x60) && sz == 8) return -1; /* slot unused */
    if (o == GOF(TISTART) && sz == 8) return -1; /* slot unused */
    if (o == GOF(TILEN)   && sz == 8) return -1; /* slot unused */
 
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 8cf7a7b..a6660ad 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -92,8 +92,9 @@
 /* Conceptually, every byte value has 8 V bits, which track whether Memcheck
    thinks the corresponding value bit is defined.  And every memory byte
    has an A bit, which tracks whether Memcheck thinks the program can access
-   it safely.   So every N-bit register is shadowed with N V bits, and every
-   memory byte is shadowed with 8 V bits and one A bit.
+   it safely (ie. it's mapped, and has at least one of the RWX permission bits
+   set).  So every N-bit register is shadowed with N V bits, and every memory
+   byte is shadowed with 8 V bits and one A bit.
 
    In the implementation, we use two forms of compression (compressed V bits
    and distinguished secondary maps) to avoid the 9-bit-per-byte overhead
@@ -3667,6 +3668,10 @@
                                       isAddrErr ? 0 : otag );
          break;
       
+      case Vg_CoreSysCallArgInMem:
+         MC_(record_regparam_error) ( tid, s, otag );
+         break;
+
       /* If we're being asked to jump to a silly address, record an error 
          message before potentially crashing the entire system. */
       case Vg_CoreTranslate:
@@ -3697,10 +3702,19 @@
 }
 
 static
+void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
+                       ULong di_handle )
+{
+   if (rr || ww || xx)
+      MC_(make_mem_defined)(a, len);
+   else
+      MC_(make_mem_noaccess)(a, len);
+}
+
+static
 void mc_new_mem_startup( Addr a, SizeT len,
                          Bool rr, Bool ww, Bool xx, ULong di_handle )
 {
-   /* Ignore the permissions, just make it defined.  Seems to work... */
    // Because code is defined, initialised variables get put in the data
    // segment and are defined, and uninitialised variables get put in the
    // bss segment and are auto-zeroed (and so defined).  
@@ -3711,16 +3725,14 @@
    // false negative, but it's a grey area -- the behaviour is defined (the
    // padding is zeroed) but it's probably not what the user intended.  And
    // we can't avoid it.
+   //
+   // Note: we generally ignore RWX permissions, because we can't track them
+   // without requiring more than one A bit which would slow things down a
+   // lot.  But on Darwin the 0th page is mapped but !R and !W and !X.
+   // So we mark any such pages as "unaddressable".
    DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
          a, (ULong)len, rr, ww, xx);
-   MC_(make_mem_defined)(a, len);
-}
-
-static
-void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
-                       ULong di_handle )
-{
-   MC_(make_mem_defined)(a, len);
+   mc_new_mem_mmap(a, len, rr, ww, xx, di_handle);
 }
 
 static
@@ -5110,6 +5122,7 @@
    return True;
 }
 
+
 /*------------------------------------------------------------*/
 /*--- Crude profiling machinery.                           ---*/
 /*------------------------------------------------------------*/
diff --git a/memcheck/mc_replace_strmem.c b/memcheck/mc_replace_strmem.c
index b7c30fc..6c5e31b 100644
--- a/memcheck/mc_replace_strmem.c
+++ b/memcheck/mc_replace_strmem.c
@@ -117,6 +117,9 @@
 STRRCHR(VG_Z_LIBC_SONAME,   rindex)
 #if defined(VGO_linux)
 STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
+#elif defined(VGO_darwin)
+STRRCHR(VG_Z_DYLD,          strrchr)
+STRRCHR(VG_Z_DYLD,          rindex)
 #endif
    
 
@@ -141,6 +144,9 @@
 STRCHR(VG_Z_LD_LINUX_SO_2,        index)
 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
 STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
+#elif defined(VGO_darwin)
+STRCHR(VG_Z_DYLD,                 strchr)
+STRCHR(VG_Z_DYLD,                 index)
 #endif
 
 
@@ -194,6 +200,51 @@
    }
 
 STRNCAT(VG_Z_LIBC_SONAME, strncat)
+#if defined(VGO_darwin)
+STRNCAT(VG_Z_DYLD,        strncat)
+#endif
+
+
+/* Append src to dst. n is the size of dst's buffer. dst is guaranteed 
+   to be nul-terminated after the copy, unless n <= strlen(dst_orig). 
+   Returns min(n, strlen(dst_orig)) + strlen(src_orig). 
+   Truncation occurred if retval >= n. 
+*/
+#define STRLCAT(soname, fnname) \
+    SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+        ( char* dst, const char* src, SizeT n ); \
+    SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+        ( char* dst, const char* src, SizeT n ) \
+   { \
+      const Char* src_orig = src; \
+      Char* dst_orig = dst; \
+      SizeT m = 0; \
+\
+      while (m < n && *dst) { m++; dst++; } \
+      if (m < n) { \
+         /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
+         while (m < n-1 && *src) { m++; *dst++ = *src++; } \
+         *dst = 0; \
+      } else { \
+         /* No space to copy anything to dst. m == n */ \
+      } \
+      /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
+      while (*src) { m++; src++; } \
+      /* This checks for overlap after copying, unavoidable without */ \
+      /* pre-counting lengths... should be ok */ \
+      if (is_overlap(dst_orig,  \
+                     src_orig,  \
+                     (Addr)dst-(Addr)dst_orig+1,  \
+                     (Addr)src-(Addr)src_orig+1)) \
+         RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
+\
+      return m; \
+   }
+
+#if defined(VGO_darwin)
+STRLCAT(VG_Z_LIBC_SONAME, strlcat)
+STRLCAT(VG_Z_DYLD,        strlcat)
+#endif
 
 
 #define STRNLEN(soname, fnname) \
@@ -250,6 +301,9 @@
    }
 
 STRCPY(VG_Z_LIBC_SONAME, strcpy)
+#if defined(VGO_darwin)
+STRCPY(VG_Z_DYLD,        strcpy)
+#endif
 
 
 #define STRNCPY(soname, fnname) \
@@ -273,6 +327,40 @@
    }
 
 STRNCPY(VG_Z_LIBC_SONAME, strncpy)
+#if defined(VGO_darwin)
+STRNCPY(VG_Z_DYLD,        strncpy)
+#endif
+
+
+/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0. 
+   Returns strlen(src). Does not zero-fill the remainder of dst. */
+#define STRLCPY(soname, fnname) \
+   SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
+       ( char* dst, const char* src, SizeT n ); \
+   SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
+       ( char* dst, const char* src, SizeT n ) \
+   { \
+      const char* src_orig = src; \
+      char* dst_orig = dst; \
+      SizeT m = 0; \
+\
+      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, */ \
+      /* but only m+1 bytes of src if terminator was found */ \
+      if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
+          RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
+      /* Nul-terminate dst. */ \
+      if (n > 0) *dst = 0; \
+      /* Finish counting strlen(src). */ \
+      while (*src) src++; \
+      return src - src_orig; \
+   }
+
+#if defined(VGO_darwin)
+STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
+STRLCPY(VG_Z_DYLD,        strlcpy)
+#endif
 
 
 #define STRNCMP(soname, fnname) \
@@ -296,6 +384,9 @@
    }
 
 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
+#if defined(VGO_darwin)
+STRNCMP(VG_Z_DYLD,        strncmp)
+#endif
 
 
 #define STRCMP(soname, fnname) \
@@ -338,6 +429,9 @@
    }
 
 MEMCHR(VG_Z_LIBC_SONAME, memchr)
+#if defined(VGO_darwin)
+MEMCHR(VG_Z_DYLD,        memchr)
+#endif
 
 
 #define MEMCPY(soname, fnname) \
@@ -389,6 +483,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_darwin)
+MEMCPY(VG_Z_DYLD,        memcpy)
 #endif
 /* icc9 blats these around all over the place.  Not only in the main
    executable but various .so's.  They are highly tuned and read
@@ -430,6 +526,9 @@
 MEMCMP(VG_Z_LIBC_SONAME, bcmp)
 #if defined(VGO_linux)
 MEMCMP(VG_Z_LD_SO_1,     bcmp)
+#elif defined(VGO_darwin)
+MEMCMP(VG_Z_DYLD,        memcmp)
+MEMCMP(VG_Z_DYLD,        bcmp)
 #endif
 
 
@@ -460,6 +559,8 @@
 #if defined(VGO_linux)
 STPCPY(VG_Z_LD_LINUX_SO_2,        stpcpy)
 STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
+#elif defined(VGO_darwin)
+STPCPY(VG_Z_DYLD,                 stpcpy)
 #endif
 
 
@@ -483,6 +584,9 @@
    }
 
 MEMSET(VG_Z_LIBC_SONAME, memset)
+#if defined(VGO_darwin)
+MEMSET(VG_Z_DYLD,        memset)
+#endif
 
 
 #define MEMMOVE(soname, fnname) \
@@ -507,6 +611,35 @@
    }
 
 MEMMOVE(VG_Z_LIBC_SONAME, memmove)
+#if defined(VGO_darwin)
+MEMMOVE(VG_Z_DYLD,        memmove)
+#endif
+
+
+#define BCOPY(soname, fnname) \
+   void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+            (const void *srcV, void *dstV, SizeT n); \
+   void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+            (const void *srcV, void *dstV, SizeT n) \
+   { \
+      SizeT i; \
+      Char* dst = (Char*)dstV; \
+      Char* src = (Char*)srcV; \
+      if (dst < src) { \
+         for (i = 0; i < n; i++) \
+            dst[i] = src[i]; \
+      } \
+      else  \
+      if (dst > src) { \
+         for (i = 0; i < n; i++) \
+            dst[n-i-1] = src[n-i-1]; \
+      } \
+   }
+
+#if defined(VGO_darwin)
+BCOPY(VG_Z_LIBC_SONAME, bcopy)
+BCOPY(VG_Z_DYLD,        bcopy)
+#endif
 
 
 /* glibc 2.5 variant of memmove which checks the dest is big enough.
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index b5be28d..96101cb 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -15,13 +15,16 @@
 if VGCONF_OS_IS_LINUX
 SUBDIRS += linux
 endif
+if VGCONF_OS_IS_DARWIN
+SUBDIRS += darwin
+endif
 
 # Platform-specific tests
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 SUBDIRS += x86-linux
 endif
 
-DIST_SUBDIRS = x86 amd64 linux x86-linux .
+DIST_SUBDIRS = x86 amd64 linux darwin x86-linux .
 
 noinst_SCRIPTS = \
 	filter_addressable \
@@ -105,7 +108,7 @@
 	noisy_child.vgtest noisy_child.stderr.exp noisy_child.stdout.exp \
 	null_socket.stderr.exp null_socket.vgtest \
 	origin1-yes.vgtest origin1-yes.stdout.exp \
-	origin1-yes.stderr.exp \
+	    origin1-yes.stderr.exp origin1-yes.stderr.exp-darwin \
 	origin2-not-quite.vgtest origin2-not-quite.stdout.exp \
 	origin2-not-quite.stderr.exp \
 	origin3-no.vgtest origin3-no.stdout.exp \
@@ -138,12 +141,13 @@
 	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.vgtest \
+	sigkill.stderr.exp sigkill.stderr.exp-darwin sigkill.vgtest \
 	signal2.stderr.exp signal2.stdout.exp signal2.vgtest \
 	sigprocmask.stderr.exp sigprocmask.stderr.exp2 sigprocmask.vgtest \
 	stack_changes.stderr.exp stack_changes.stdout.exp \
 	stack_changes.stdout.exp2 stack_changes.vgtest \
-	strchr.stderr.exp strchr.stderr.exp2 strchr.vgtest \
+	strchr.stderr.exp strchr.stderr.exp2 strchr.stderr.exp-darwin \
+	    strchr.vgtest \
 	str_tester.stderr.exp str_tester.vgtest \
 	supp_unknown.stderr.exp supp_unknown.vgtest supp_unknown.supp \
 	supp1.stderr.exp supp1.vgtest \
@@ -298,6 +302,10 @@
  varinfo5_LDADD         = `pwd`/varinfo5so.so
  varinfo5_LDFLAGS       = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ varinfo5_LDADD         = `pwd`/varinfo5so.so
+ varinfo5_LDFLAGS       = $(AM_FLAG_M3264_PRI)
+else
  varinfo5_LDADD         = varinfo5so.so
  varinfo5_LDFLAGS       = $(AM_FLAG_M3264_PRI) \
 				-Wl,-rpath,$(top_builddir)/memcheck/tests
@@ -313,10 +321,16 @@
  varinfo5so_so_LDFLAGS  = -fpic $(AM_FLAG_M3264_PRI) -shared \
 				-Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ varinfo5so_so_LDFLAGS  = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+				-dynamiclib -all_load
+else
  varinfo5so_so_LDFLAGS  = -fpic $(AM_FLAG_M3264_PRI) -shared \
 				-Wl,-soname -Wl,varinfo5so.so
 endif
 endif
+endif
+
 # Build shared object for wrap7
 wrap7_SOURCES           = wrap7.c
 wrap7_DEPENDENCIES      = wrap7so.so
@@ -328,11 +342,16 @@
  wrap7_LDADD            = `pwd`/wrap7so.so
  wrap7_LDFLAGS          = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ wrap7_LDADD            = `pwd`/wrap7so.so
+ wrap7_LDFLAGS          = $(AM_FLAG_M3264_PRI)
+else
  wrap7_LDADD            = wrap7so.so
  wrap7_LDFLAGS          = $(AM_FLAG_M3264_PRI) \
 				-Wl,-rpath,$(top_builddir)/memcheck/tests
 endif
 endif
+endif
 
 wrap7so_so_SOURCES      = wrap7so.c
 wrap7so_so_CFLAGS       = $(AM_CFLAGS) -fpic
@@ -343,9 +362,15 @@
  wrap7so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -shared \
 				-Wl,-G -Wl,-bnogc
 else
+if VGCONF_OS_IS_DARWIN
+ wrap7so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+				-dynamiclib -all_load
+else
  wrap7so_so_LDFLAGS     = -fpic $(AM_FLAG_M3264_PRI) -shared \
 				-Wl,-soname -Wl,wrap7so.so
 endif
 endif
+endif
 
+endif
 
diff --git a/memcheck/tests/amd64/Makefile.am b/memcheck/tests/amd64/Makefile.am
index bb1c803..5dedb0d 100644
--- a/memcheck/tests/amd64/Makefile.am
+++ b/memcheck/tests/amd64/Makefile.am
@@ -22,10 +22,18 @@
 	xor-undef-amd64.stderr.exp xor-undef-amd64.stdout.exp \
 	xor-undef-amd64.vgtest
 
-check_PROGRAMS = bt_everything bug132146 defcfaexpr fxsave-amd64 \
-		int3-amd64 \
-		more_x87_fp sse_memory xor-undef-amd64
+check_PROGRAMS = bt_everything bug132146 fxsave-amd64 \
+		xor-undef-amd64
 
+# DDD: not sure if these ones should work on Darwin or not... if not, should
+# be moved into amd64-linux/.
+if ! VGCONF_OS_IS_DARWIN
+   check_PROGRAMS += \
+	defcfaexpr \
+	int3-amd64 \
+	more_x87_fp \
+	sse_memory
+endif
 
 AM_CFLAGS    += @FLAG_M64@
 AM_CXXFLAGS  += @FLAG_M64@
diff --git a/memcheck/tests/badjump2.c b/memcheck/tests/badjump2.c
index d91283c..a4ba803 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(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
    sigsegv_new.sa_restorer = NULL;
 #endif
    res = sigemptyset( &sigsegv_new.sa_mask );
diff --git a/memcheck/tests/darwin/Makefile.am b/memcheck/tests/darwin/Makefile.am
new file mode 100644
index 0000000..9d41756
--- /dev/null
+++ b/memcheck/tests/darwin/Makefile.am
@@ -0,0 +1,20 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+noinst_SCRIPTS = filter_stderr
+
+noinst_HEADERS = scalar.h
+
+EXTRA_DIST = $(noinst_SCRIPTS) \
+	scalar.stderr.exp scalar.vgtest \
+	scalar_fork.stderr.exp scalar_fork.vgtest \
+	scalar_vfork.stderr.exp scalar_vfork.vgtest
+
+check_PROGRAMS = \
+	scalar scalar_fork scalar_vfork
+
+
+AM_CFLAGS    += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CXXFLAGS  += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CCASFLAGS += @FLAG_M32@
+
diff --git a/memcheck/tests/darwin/filter_stderr b/memcheck/tests/darwin/filter_stderr
new file mode 100644
index 0000000..0ae9313
--- /dev/null
+++ b/memcheck/tests/darwin/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/memcheck/tests/darwin/scalar.c b/memcheck/tests/darwin/scalar.c
new file mode 100644
index 0000000..2ee66ea
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.c
@@ -0,0 +1,1726 @@
+#include "../../memcheck.h"
+#include "scalar.h"
+#include <unistd.h>
+#include <sched.h>
+#include <signal.h>
+
+// See memcheck/tests/x86-linux/scalar.c for an explanation of what this test
+// is doing.
+
+int main(void)
+{
+   // uninitialised, but we know px[0] is 0x0
+   long* px  = malloc(sizeof(long));
+   long  x0  = px[0];
+   long  res;
+
+   VALGRIND_MAKE_MEM_NOACCESS(0, 0x1000);
+
+   // __NR_syscall 0
+   // XXX
+
+   // __NR_exit 1 
+   GO(__NR_exit, "below");
+   // (see below)
+
+   // __NR_fork 2
+   GO(__NR_fork, "other");
+   // (sse scalar_fork.c)
+
+   // __NR_read 3
+   // Nb: here we are also getting an error from the syscall arg itself.
+   GO(__NR_read, "1+3s 1m");
+   SY(__NR_read+(int)x0, x0, x0, x0+1); FAILx(EFAULT);
+
+   // __NR_write 4
+   GO(__NR_write, "3s 1m");
+   SY(__NR_write, x0, x0, x0+1); FAIL;
+   //res = write(x0, x0, x0+1); FAIL;
+
+   // __NR_open 5
+   // __NR_close 6
+   // __NR_wait4 7
+   // /* 8  old creat */
+   // __NR_link 9
+   // __NR_unlink 10
+   // /* 11  old execv */
+   // __NR_chdir 12
+   // __NR_fchdir 13
+   // __NR_mknod 14
+   // __NR_chmod 15
+   // __NR_chown 16
+   // /* 17  old break */
+   // __NR_getfsstat 18
+   // /* 19  old lseek */
+   // __NR_getpid 20
+   // /* 21  old mount */
+   // /* 22  old umount */
+   // __NR_setuid 23
+   // __NR_getuid 24
+   // __NR_geteuid 25
+   // __NR_ptrace 26
+   // __NR_recvmsg 27
+   // __NR_sendmsg 28
+   // __NR_recvfrom 29
+   // __NR_accept 30
+   // __NR_getpeername 31
+   // __NR_getsockname 32
+   // __NR_access 33
+   // __NR_chflags 34
+   // __NR_fchflags 35
+   // __NR_sync 36
+   // __NR_kill 37
+   // /* 38  old stat */
+   // __NR_getppid 39
+   // /* 40  old lstat */
+   // __NR_dup 41
+   // __NR_pipe           VG_DARWIN_SYSCALL_CONSTRUCT_UX64(42
+   // __NR_getegid 43
+   // __NR_profil 44
+   // /* 45  old ktrace */
+   // __NR_sigaction 46
+   // __NR_getgid 47
+   // __NR_sigprocmask 48
+   // __NR_getlogin 49
+   // __NR_setlogin 50
+   // __NR_acct 51
+   // __NR_sigpending 52
+   // __NR_sigaltstack 53
+   // __NR_ioctl 54
+   // __NR_reboot 55
+   // __NR_revoke 56
+   // __NR_symlink 57
+   // __NR_readlink 58
+   // __NR_execve 59
+   // __NR_umask 60
+   // __NR_chroot 61
+   // /* 62  old fstat */
+   // /* 63  used internally , reserved */
+   // /* 64  old getpagesize */
+   // __NR_msync 65
+   // __NR_vfork 66
+   // /* 67  old vread */
+   // /* 68  old vwrite */
+   // /* 69  old sbrk */
+   // /* 70  old sstk */
+   // /* 71  old mmap */
+   // /* 72  old vadvise */
+   // __NR_munmap 73
+   // __NR_mprotect 74
+   // __NR_madvise 75
+   // /* 76  old vhangup */
+   // /* 77  old vlimit */
+   // __NR_mincore 78
+   // __NR_getgroups 79
+   // __NR_setgroups 80
+   // __NR_getpgrp 81
+   // __NR_setpgid 82
+   // __NR_setitimer 83
+   // /* 84  old wait */
+   // __NR_swapon 85
+   // __NR_getitimer 86
+   // /* 87  old gethostname */
+   // /* 88  old sethostname */
+   // __NR_getdtablesize 89
+   // __NR_dup2 90
+   // /* 91  old getdopt */
+   // __NR_fcntl 92
+   // __NR_select 93
+   // /* 94  old setdopt */
+   // __NR_fsync 95
+   // __NR_setpriority 96
+   // __NR_socket 97
+   // __NR_connect 98
+   // /* 99  old accept */
+   // __NR_getpriority 100
+   // /* 101  old send */
+   // /* 102  old recv */
+   // /* 103  old sigreturn */
+   // __NR_bind 104
+
+   // __NR_setsockopt 105
+   GO(__NR_setsockopt, "5s 1m");
+   SY(__NR_setsockopt, x0, x0, x0, x0+1, x0+1); FAIL;
+
+   // __NR_listen 106
+   // /* 107  old vtimes */
+   // /* 108  old sigvec */
+   // /* 109  old sigblock */
+   // /* 110  old sigsetmask */
+   // __NR_sigsuspend 111
+   // /* 112  old sigstack */
+   // /* 113  old recvmsg */
+   // /* 114  old sendmsg */
+   // /* 115  old vtrace */
+   // __NR_gettimeofday 116
+   // __NR_getrusage 117
+
+   // __NR_getsockopt 118
+   // Nb: there's no "getsockopt(optlen) points to unaddressable byte(s)";
+   // difficult to get with arg4 being checked with buf_and_len_pre_check.
+   GO(__NR_getsockopt, "5s 1m");
+   SY(__NR_getsockopt, x0, x0, x0, x0+1, x0+&px[1]); FAIL;
+
+   // /* 119  old resuba */
+   // __NR_readv 120
+   // __NR_writev 121
+   // __NR_settimeofday 122
+   // __NR_fchown 123
+   // __NR_fchmod 124
+   // /* 125  old recvfrom */
+   // __NR_setreuid 126
+   // __NR_setregid 127
+   // __NR_rename 128
+   // /* 129  old truncate */
+   // /* 130  old ftruncate */
+   // __NR_flock 131
+   // __NR_mkfifo 132
+   // __NR_sendto 133
+   // __NR_shutdown 134
+   // __NR_socketpair 135
+   // __NR_mkdir 136
+   // __NR_rmdir 137
+   // __NR_utimes 138
+   // __NR_futimes 139
+   // __NR_adjtime 140
+   // /* 141  old getpeername */
+   // __NR_gethostuuid 142
+   // /* 143  old sethostid */
+   // /* 144  old getrlimit */
+   // /* 145  old setrlimit */
+   // /* 146  old killpg */
+   // __NR_setsid 147
+   // /* 148  old setquota */
+   // /* 149  old qquota */
+   // /* 150  old getsockname */
+   // __NR_getpgid 151
+   // __NR_setprivexec 152
+   // __NR_pread 153
+   // __NR_pwrite 154
+   // __NR_nfssvc 155
+   // /* 156  old getdirentries */
+   // __NR_statfs 157
+   // __NR_fstatfs 158
+   // __NR_unmount 159
+   // /* 160  old async_daemon */
+   // __NR_getfh 161
+   // /* 162  old getdomainname */
+   // /* 163  old setdomainname */
+   // /* 164 */
+   // __NR_quotactl 165
+   // /* 166  old exportfs */
+   // __NR_mount 167
+   // /* 168  old ustat */
+
+   // __NR_csops 169
+   GO(__NR_csops, "4s 1m");
+   SY(__NR_csops, x0, x0, x0+1, x0+1); FAILx(EFAULT);
+
+   // /* 170  old table */
+   // /* 171  old wait3 */
+   // /* 172  old rpause */
+   // __NR_waitid 173
+   // /* 174  old getdents */
+   // /* 175  old gc_control */
+   // __NR_add_profil 176
+   // /* 177 */
+   // /* 178 */
+   // /* 179 */
+   // __NR_kdebug_trace 180
+   // __NR_setgid 181
+   // __NR_setegid 182
+   // __NR_seteuid 183
+   // __NR_sigreturn 184
+   // __NR_chud 185
+   // /* 186 */
+   // /* 187 */
+   // __NR_stat 188
+   // __NR_fstat 189
+   // __NR_lstat 190
+   // __NR_pathconf 191
+   // __NR_fpathconf 192
+   // /* 193 */
+   // __NR_getrlimit 194
+   // __NR_setrlimit 195
+   // __NR_getdirentries 196
+   // __NR_mmap 197
+   // /* 198  __syscall */
+   // __NR_lseek          VG_DARWIN_SYSCALL_CONSTRUCT_UX64(199
+   // __NR_truncate 200
+   // __NR_ftruncate 201
+   // __NR___sysctl 202
+   // __NR_mlock 203
+   // __NR_munlock 204
+   // __NR_undelete 205
+   // __NR_ATsocket 206
+   // __NR_ATgetmsg 207
+   // __NR_ATputmsg 208
+   // __NR_ATPsndreq 209
+   // __NR_ATPsndrsp 210
+   // __NR_ATPgetreq 211
+   // __NR_ATPgetrsp 212
+   // /* 213  Reserved for AppleTalk */
+   // __NR_kqueue_from_portset_np 214
+   // __NR_kqueue_portset_np 215
+   // __NR_mkcomplex 216
+   // __NR_statv 217
+   // __NR_lstatv 218
+   // __NR_fstatv 219
+   // __NR_getattrlist 220
+   // __NR_setattrlist 221
+   // __NR_getdirentriesattr 222
+   // __NR_exchangedata 223
+   // /* 224  checkuseraccess */
+   // __NR_searchfs 225
+   // __NR_delete 226
+   // __NR_copyfile 227
+   // /* 228 */
+   // /* 229 */
+   // __NR_poll 230
+   // __NR_watchevent 231
+   // __NR_waitevent 232
+   // __NR_modwatch 233
+   // __NR_getxattr 234
+   // __NR_fgetxattr 235
+   // __NR_setxattr 236
+   // __NR_fsetxattr 237
+   // __NR_removexattr 238
+   // __NR_fremovexattr 239
+   // __NR_listxattr 240
+   // __NR_flistxattr 241
+   // __NR_fsctl 242
+   // __NR_initgroups 243
+   // __NR_posix_spawn 244
+   // /* 245 */
+   // /* 246 */
+   // __NR_nfsclnt 247
+   // __NR_fhopen 248
+   // /* 249 */
+   // __NR_minherit 250
+   // __NR_semsys 251
+   // __NR_msgsys 252
+   // __NR_shmsys 253
+   // __NR_semctl 254
+   // __NR_semget 255
+   // __NR_semop 256
+   // /* 257 */
+   // __NR_msgctl 258
+   // __NR_msgget 259
+   // __NR_msgsnd 260
+   // __NR_msgrcv 261
+   // __NR_shmat 262
+   // __NR_shmctl 263
+   // __NR_shmdt 264
+
+   // __NR_shmget 265
+   GO(__NR_shmget, "3s 0m");
+   SY(__NR_shmget, x0, x0, x0); FAIL;
+
+   // __NR_shm_open 266
+   // __NR_shm_unlink 267
+
+   // __NR_sem_open 268
+   GO(__NR_sem_open, "2s 1m");
+   SY(__NR_sem_open, x0, x0); FAIL;
+
+   GO(__NR_sem_open, "(4-args) 2s 0m");
+   SY(__NR_sem_open, "my_sem", O_CREAT|O_EXCL, x0, x0); SUCC_OR_FAIL;
+
+   // __NR_sem_close 269
+   // Nb: we add 0x12345 to make sure it's not a valid semaphore descriptor.
+   GO(__NR_sem_close, "1s 0m");
+   SY(__NR_sem_close, x0+0x12345); FAIL;
+
+   // __NR_sem_unlink 270
+   GO(__NR_sem_unlink, "1s 1m");
+   SY(__NR_sem_unlink, x0); FAIL;
+
+   // __NR_sem_wait 271
+   // __NR_sem_trywait 272
+
+   // __NR_sem_post 273
+   GO(__NR_sem_post, "1s 0m");
+   SY(__NR_sem_post, x0); FAIL;
+
+   // __NR_sem_getvalue 274
+
+   // __NR_sem_init 275
+   GO(__NR_sem_init, "3s 1m");
+   SY(__NR_sem_init, x0+1, x0, x0); FAILx(ENOSYS);
+
+   // __NR_sem_destroy 276
+   GO(__NR_sem_destroy, "1s 1m");
+   SY(__NR_sem_destroy, x0+1); FAILx(ENOSYS);
+
+   // __NR_open_extended 277
+   // __NR_umask_extended 278
+   // __NR_stat_extended 279
+   // __NR_lstat_extended 280
+   // __NR_fstat_extended 281
+   // __NR_chmod_extended 282
+   // __NR_fchmod_extended 283
+   // __NR_access_extended 284
+   // __NR_settid 285
+   // __NR_gettid 286
+   // __NR_setsgroups 287
+   // __NR_getsgroups 288
+   // __NR_setwgroups 289
+   // __NR_getwgroups 290
+   // __NR_mkfifo_extended 291
+   // __NR_mkdir_extended 292
+   // __NR_identitysvc 293
+   // __NR_shared_region_check_np 294
+   // __NR_shared_region_map_np 295
+   // /* 296  old load_shared_file */
+   // /* 297  old reset_shared_file */
+   // /* 298  old new_system_shared_regions */
+   // /* 299  old shared_region_map_file_np */
+   // /* 300  old shared_region_make_private_np */
+   // __NR___pthread_mutex_destroy 301
+   // __NR___pthread_mutex_init 302
+   // __NR___pthread_mutex_lock 303
+   // __NR___pthread_mutex_trylock 304
+   // __NR___pthread_mutex_unlock 305
+   // __NR___pthread_cond_init 306
+   // __NR___pthread_cond_destroy 307
+   // __NR___pthread_cond_broadcast 308
+   // __NR___pthread_cond_signal 309
+   // __NR_getsid 310
+   // __NR_settid_with_pid 311
+   // __NR___pthread_cond_timedwait 312
+   // __NR_aio_fsync 313
+   // __NR_aio_return 314
+   // __NR_aio_suspend 315
+   // __NR_aio_cancel 316
+   // __NR_aio_error 317
+   // __NR_aio_read 318
+   // __NR_aio_write 319
+   // __NR_lio_listio 320
+   // __NR___pthread_cond_wait 321
+   // __NR_iopolicysys 322
+   // /* 323 */
+   // __NR_mlockall 324
+   // __NR_munlockall 325
+   // /* 326 */
+   // __NR_issetugid 327
+   // __NR___pthread_kill 328
+   // __NR___pthread_sigmask 329
+   // __NR___sigwait 330
+   // __NR_sigwait 330) // GrP fixme hack
+   // __NR___disable_threadsignal 331
+   // __NR___pthread_markcancel 332
+   // __NR___pthread_canceled 333
+   // __NR___semwait_signal 334
+   // /* 335  old utrace */
+   // __NR_proc_info 336
+   // __NR_sendfile 337
+   // __NR_stat64 338
+   // __NR_fstat64 339
+   // __NR_lstat64 340
+   // __NR_stat64_extended 341
+   // __NR_lstat64_extended 342
+   // __NR_fstat64_extended 343
+   // __NR_getdirentries64 344
+   // __NR_statfs64 345
+   // __NR_fstatfs64 346
+   // __NR_getfsstat64 347
+   // __NR___pthread_chdir 348
+   // __NR___pthread_fchdir 349
+   // __NR_audit 350
+   // __NR_auditon 351
+   // /* 352 */
+   // __NR_getauid 353
+   // __NR_setauid 354
+   // __NR_getaudit 355
+   // __NR_setaudit 356
+   // __NR_getaudit_addr 357
+   // __NR_setaudit_addr 358
+   // __NR_auditctl 359
+   // __NR_bsdthread_create 360
+   // __NR_bsdthread_terminate 361
+   // __NR_kqueue 362
+   // __NR_kevent 363
+   // __NR_lchown 364
+   // __NR_stack_snapshot 365
+   // __NR_bsdthread_register 366
+   // __NR_workq_open 367
+   // __NR_workq_ops 368
+   // /* 369 */
+   // /* 370 */
+   // /* 371 */
+   // /* 372 */
+   // /* 373 */
+   // /* 374 */
+   // /* 375 */
+   // /* 376 */
+   // /* 377 */
+   // /* 378 */
+   // /* 379 */
+   // __NR___mac_execve 380
+   // __NR___mac_syscall 381
+   // __NR___mac_get_file 382
+   // __NR___mac_set_file 383
+   // __NR___mac_get_link 384
+   // __NR___mac_set_link 385
+   // __NR___mac_get_proc 386
+   // __NR___mac_set_proc 387
+   // __NR___mac_get_fd 388
+   // __NR___mac_set_fd 389
+   // __NR___mac_get_pid 390
+   // __NR___mac_get_lcid 391
+   // __NR___mac_get_lctx 392
+   // __NR___mac_set_lctx 393
+   // __NR_setlcid 394
+   // __NR_getlcid 395
+   // __NR_read_nocancel 396
+   // __NR_write_nocancel 397
+   // __NR_open_nocancel 398
+   // __NR_close_nocancel 399
+   // __NR_wait4_nocancel 400
+   // __NR_recvmsg_nocancel 401
+   // __NR_sendmsg_nocancel 402
+   // __NR_recvfrom_nocancel 403
+   // __NR_accept_nocancel 404
+   // __NR_msync_nocancel 405
+   // __NR_fcntl_nocancel 406
+   // __NR_select_nocancel 407
+   // __NR_fsync_nocancel 408
+   // __NR_connect_nocancel 409
+   // __NR_sigsuspend_nocancel 410
+   // __NR_readv_nocancel 411
+   // __NR_writev_nocancel 412
+   // __NR_sendto_nocancel 413
+   // __NR_pread_nocancel 414
+   // __NR_pwrite_nocancel 415
+   // __NR_waitid_nocancel 416
+   // __NR_poll_nocancel 417
+   // __NR_msgsnd_nocancel 418
+   // __NR_msgrcv_nocancel 419
+
+   // __NR_sem_wait_nocancel 420
+   GO(__NR_sem_wait_nocancel, "1s 0m");
+   SY(__NR_sem_wait_nocancel, x0); FAIL;
+
+   // __NR_aio_suspend_nocancel 421
+   // __NR___sigwait_nocancel 422
+   // __NR___semwait_signal_nocancel 423
+   // __NR___mac_mount 424
+   // __NR___mac_get_mount 425
+   // __NR___mac_getfsstat 426
+   // __NR_MAXSYSCALL 427
+
+#if 0
+   // XXX: all these are copied from x86-darwin/scalar.c.
+
+   // __NR_open 5
+   GO(__NR_open, "(2-args) 2s 1m");
+   SY(__NR_open, x0, x0); FAIL;
+
+   // Only 1s 0m errors -- the other 2s 1m have been checked in the previous
+   // open test, and if we test them they may be commoned up but they also
+   // may not.
+   GO(__NR_open, "(3-args) 1s 0m");    
+   SY(__NR_open, "scalar.c", O_CREAT|O_EXCL, x0); FAIL;
+
+   // __NR_close 6
+   GO(__NR_close, "1s 0m");
+   SY(__NR_close, x0-1); FAIL;
+
+   // __NR_waitpid 7
+   GO(__NR_waitpid, "3s 1m");
+   SY(__NR_waitpid, x0, x0+1, x0); FAIL;
+
+   // __NR_creat 8
+   GO(__NR_creat, "2s 1m");
+   SY(__NR_creat, x0, x0); FAIL;
+
+   // __NR_link 9
+   GO(__NR_link, "2s 2m");
+   SY(__NR_link, x0, x0); FAIL;
+
+   // __NR_unlink 10
+   GO(__NR_unlink, "1s 1m");
+   SY(__NR_unlink, x0); FAIL;
+
+   // __NR_execve 11
+   // Nb: could have 3 memory errors if we pass x0+1 as the 2nd and 3rd
+   // args, except for bug #93174.
+   GO(__NR_execve, "3s 1m");
+   SY(__NR_execve, x0, x0, x0); FAIL;
+
+   // __NR_chdir 12
+   GO(__NR_chdir, "1s 1m");
+   SY(__NR_chdir, x0); FAIL;
+
+   // __NR_time 13
+   GO(__NR_time, "1s 1m");
+   SY(__NR_time, x0+1); FAIL;
+
+   // __NR_mknod 14
+   GO(__NR_mknod, "3s 1m");
+   SY(__NR_mknod, x0, x0, x0); FAIL;
+
+   // __NR_chmod 15
+   GO(__NR_chmod, "2s 1m");
+   SY(__NR_chmod, x0, x0); FAIL;
+
+   // __NR_lchown 16
+   GO(__NR_lchown, "n/a");
+ //SY(__NR_lchown); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_break 17
+   GO(__NR_break, "ni");
+   SY(__NR_break); FAIL;
+
+   // __NR_oldstat 18
+   GO(__NR_oldstat, "n/a");
+   // (obsolete, not handled by Valgrind)
+
+   // __NR_lseek 19
+   GO(__NR_lseek, "3s 0m");
+   SY(__NR_lseek, x0-1, x0, x0); FAILx(EBADF);
+
+   // __NR_getpid 20
+   GO(__NR_getpid, "0s 0m");
+   SY(__NR_getpid); SUCC;
+
+   // __NR_mount 21
+   GO(__NR_mount, "5s 3m");
+   SY(__NR_mount, x0, x0, x0, x0, x0); FAIL;
+   
+   // __NR_umount 22
+   GO(__NR_umount, "1s 1m");
+   SY(__NR_umount, x0); FAIL;
+
+   // __NR_setuid 23
+   GO(__NR_setuid, "1s 0m");
+   SY(__NR_setuid, x0); FAIL;
+
+   // __NR_getuid 24
+   GO(__NR_getuid, "0s 0m");
+   SY(__NR_getuid); SUCC;
+
+   // __NR_stime 25
+   GO(__NR_stime, "n/a");
+ //SY(__NR_stime); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_ptrace 26
+   // XXX: memory pointed to be arg3 goes unchecked... otherwise would be 2m
+   GO(__NR_ptrace, "4s 1m");
+   SY(__NR_ptrace, x0+PTRACE_GETREGS, x0, x0, x0); FAIL;
+
+   // __NR_alarm 27
+   GO(__NR_alarm, "1s 0m");
+   SY(__NR_alarm, x0); SUCC;
+
+   // __NR_oldfstat 28
+   GO(__NR_oldfstat, "n/a");
+   // (obsolete, not handled by Valgrind)
+
+   // __NR_pause 29
+   GO(__NR_pause, "ignore");
+   // (hard to test, and no args so not much to be gained -- don't bother)
+
+   // __NR_utime 30
+   GO(__NR_utime, "2s 2m");
+   SY(__NR_utime, x0, x0+1); FAIL;
+
+   // __NR_stty 31
+   GO(__NR_stty, "ni");
+   SY(__NR_stty); FAIL;
+
+   // __NR_gtty 32
+   GO(__NR_gtty, "ni");
+   SY(__NR_gtty); FAIL;
+
+   // __NR_access 33
+   GO(__NR_access, "2s 1m");
+   SY(__NR_access, x0, x0); FAIL;
+
+   // __NR_nice 34
+   GO(__NR_nice, "1s 0m");
+   SY(__NR_nice, x0); SUCC;
+
+   // __NR_ftime 35
+   GO(__NR_ftime, "ni");
+   SY(__NR_ftime); FAIL;
+
+   // __NR_sync 36
+   GO(__NR_sync, "0s 0m");
+   SY(__NR_sync); SUCC;
+
+   // __NR_kill 37
+   GO(__NR_kill, "2s 0m");
+   SY(__NR_kill, x0, x0); SUCC;
+
+   // __NR_rename 38
+   GO(__NR_rename, "2s 2m");
+   SY(__NR_rename, x0, x0); FAIL;
+
+   // __NR_mkdir 39
+   GO(__NR_mkdir, "2s 1m");
+   SY(__NR_mkdir, x0, x0); FAIL;
+
+   // __NR_rmdir 40
+   GO(__NR_rmdir, "1s 1m");
+   SY(__NR_rmdir, x0); FAIL;
+
+   // __NR_dup 41
+   GO(__NR_dup, "1s 0m");
+   SY(__NR_dup, x0-1); FAIL;
+
+   // __NR_pipe 42
+   GO(__NR_pipe, "1s 1m");
+   SY(__NR_pipe, x0); FAIL;
+
+   // __NR_times 43
+   GO(__NR_times, "1s 1m");
+   SY(__NR_times, x0+1); FAIL;
+
+   // __NR_prof 44
+   GO(__NR_prof, "ni");
+   SY(__NR_prof); FAIL;
+
+   // __NR_brk 45
+   GO(__NR_brk, "1s 0m");
+   SY(__NR_brk, x0); SUCC;
+
+   // __NR_setgid 46
+   GO(__NR_setgid, "1s 0m");
+   SY(__NR_setgid, x0); FAIL;
+
+   // __NR_getgid 47
+   GO(__NR_getgid, "0s 0m");
+   SY(__NR_getgid); SUCC;
+
+   // __NR_signal 48
+   GO(__NR_signal, "n/a");
+ //SY(__NR_signal); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_geteuid 49
+   GO(__NR_geteuid, "0s 0m");
+   SY(__NR_geteuid); SUCC;
+
+   // __NR_getegid 50
+   GO(__NR_getegid, "0s 0m");
+   SY(__NR_getegid); SUCC;
+
+   // __NR_acct 51
+   GO(__NR_acct, "1s 1m");
+   SY(__NR_acct, x0); FAIL;
+
+   // __NR_umount2 52
+   GO(__NR_umount2, "2s 1m");
+   SY(__NR_umount2, x0, x0); FAIL;
+
+   // __NR_lock 53
+   GO(__NR_lock, "ni");
+   SY(__NR_lock); FAIL;
+
+   // __NR_ioctl 54
+   #include <asm/ioctls.h>
+   GO(__NR_ioctl, "3s 1m");
+   SY(__NR_ioctl, x0, x0+TCSETS, x0); FAIL;
+
+   // __NR_fcntl 55
+   // As with sys_open(), the 'fd' error is suppressed for the later ones.
+   // For F_GETFD the 3rd arg is ignored
+   GO(__NR_fcntl, "(GETFD) 2s 0m");
+   SY(__NR_fcntl, x0-1, x0+F_GETFD, x0); FAILx(EBADF);
+
+   // For F_DUPFD the 3rd arg is 'arg'.  We don't check the 1st two args
+   // because any errors may or may not be commoned up with the ones from
+   // the previous fcntl call.
+   GO(__NR_fcntl, "(DUPFD) 1s 0m");
+   SY(__NR_fcntl, -1, F_DUPFD, x0); FAILx(EBADF);
+
+   // For F_GETLK the 3rd arg is 'lock'.  On x86, this fails w/EBADF.  But
+   // on amd64 in 32-bit mode it fails w/EFAULT.  We don't check the 1st two
+   // args for the reason given above.
+   GO(__NR_fcntl, "(GETLK) 1s 0m");
+   SY(__NR_fcntl, -1, F_GETLK, x0); FAIL; //FAILx(EBADF);
+
+   // __NR_mpx 56
+   GO(__NR_mpx, "ni");
+   SY(__NR_mpx); FAIL;
+
+   // __NR_setpgid 57
+   GO(__NR_setpgid, "2s 0m");
+   SY(__NR_setpgid, x0, x0-1); FAIL;
+
+   // __NR_ulimit 58
+   GO(__NR_ulimit, "ni");
+   SY(__NR_ulimit); FAIL;
+
+   // __NR_oldolduname 59
+   GO(__NR_oldolduname, "n/a");
+   // (obsolete, not handled by Valgrind)
+
+   // __NR_umask 60
+   GO(__NR_umask, "1s 0m");
+   SY(__NR_umask, x0+022); SUCC;
+
+   // __NR_chroot 61
+   GO(__NR_chroot, "1s 1m");
+   SY(__NR_chroot, x0); FAIL;
+
+   // __NR_ustat 62
+   GO(__NR_ustat, "n/a");
+   // (deprecated, not handled by Valgrind)
+
+   // __NR_dup2 63
+   GO(__NR_dup2, "2s 0m");
+   SY(__NR_dup2, x0-1, x0); FAIL;
+
+   // __NR_getppid 64
+   GO(__NR_getppid, "0s 0m");
+   SY(__NR_getppid); SUCC;
+
+   // __NR_getpgrp 65
+   GO(__NR_getpgrp, "0s 0m");
+   SY(__NR_getpgrp); SUCC;
+
+   // __NR_setsid 66
+   GO(__NR_setsid, "0s 0m");
+   SY(__NR_setsid); SUCC_OR_FAIL;
+
+   // __NR_sigaction 67
+   GO(__NR_sigaction, "3s 4m");
+   SY(__NR_sigaction, x0, x0+&px[1], x0+&px[1]); FAIL;
+
+   // __NR_sgetmask 68 sys_sgetmask()
+   GO(__NR_sgetmask, "n/a");
+ //SY(__NR_sgetmask); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_ssetmask 69
+   GO(__NR_ssetmask, "n/a");
+ //SY(__NR_ssetmask); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_setreuid 70
+   GO(__NR_setreuid, "2s 0m");
+   SY(__NR_setreuid, x0, x0); FAIL;
+
+   // __NR_setregid 71
+   GO(__NR_setregid, "2s 0m");
+   SY(__NR_setregid, x0, x0); FAIL;
+
+   // __NR_sigsuspend 72
+   // XXX: how do you use this function?
+   GO(__NR_sigsuspend, "ignore");
+   // (I don't know how to test this...)
+
+   // __NR_sigpending 73
+   GO(__NR_sigpending, "1s 1m");
+   SY(__NR_sigpending, x0); FAIL;
+
+   // __NR_sethostname 74
+   GO(__NR_sethostname, "n/a");
+ //SY(__NR_sethostname); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_setrlimit 75
+   GO(__NR_setrlimit, "2s 1m");
+   SY(__NR_setrlimit, x0, x0); FAIL;
+
+   // __NR_getrlimit 76
+   GO(__NR_getrlimit, "2s 1m");
+   SY(__NR_getrlimit, x0, x0); FAIL;
+
+   // __NR_getrusage 77
+   GO(__NR_getrusage, "2s 1m");
+   SY(__NR_getrusage, x0, x0); FAIL;
+
+   // __NR_gettimeofday 78
+   GO(__NR_gettimeofday, "2s 2m");
+   SY(__NR_gettimeofday, x0, x0+1); FAIL;
+
+   // __NR_settimeofday 79
+   GO(__NR_settimeofday, "2s 2m");
+   SY(__NR_settimeofday, x0, x0+1); FAIL;
+
+   // __NR_getgroups 80
+   GO(__NR_getgroups, "2s 1m");
+   SY(__NR_getgroups, x0+1, x0+1); FAIL;
+
+   // __NR_setgroups 81
+   GO(__NR_setgroups, "2s 1m");
+   SY(__NR_setgroups, x0+1, x0+1); FAIL;
+
+   // __NR_select 82
+   {
+      long args[5] = { x0+8, x0+0xffffffee, x0+1, x0+1, x0+1 };
+      GO(__NR_select, "1s 5m");
+      SY(__NR_select, args+x0); FAIL;
+   }
+
+   // __NR_symlink 83
+   GO(__NR_symlink, "2s 2m");
+   SY(__NR_symlink, x0, x0); FAIL;
+
+   // __NR_oldlstat 84
+   GO(__NR_oldlstat, "n/a");
+   // (obsolete, not handled by Valgrind)
+
+   // __NR_readlink 85
+   GO(__NR_readlink, "3s 2m");
+   SY(__NR_readlink, x0+1, x0+1, x0+1); FAIL;
+
+   // __NR_uselib 86
+   GO(__NR_uselib, "n/a");
+ //SY(__NR_uselib); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_swapon 87
+   GO(__NR_swapon, "n/a");
+ //SY(__NR_swapon); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_reboot 88
+   GO(__NR_reboot, "n/a");
+ //SY(__NR_reboot); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_readdir 89
+   GO(__NR_readdir, "n/a");
+   // (superseded, not handled by Valgrind)
+
+   // __NR_mmap 90
+   {
+      long args[6] = { x0, x0, x0, x0, x0-1, x0 };
+      GO(__NR_mmap, "1s 1m");
+      SY(__NR_mmap, args+x0); FAIL;
+   }
+
+   // __NR_munmap 91
+   GO(__NR_munmap, "2s 0m");
+   SY(__NR_munmap, x0, x0); FAIL;
+
+   // __NR_truncate 92
+   GO(__NR_truncate, "2s 1m");
+   SY(__NR_truncate, x0, x0); FAIL;
+
+   // __NR_ftruncate 93
+   GO(__NR_ftruncate, "2s 0m");
+   SY(__NR_ftruncate, x0, x0); FAIL;
+
+   // __NR_fchmod 94
+   GO(__NR_fchmod, "2s 0m");
+   SY(__NR_fchmod, x0-1, x0); FAIL;
+
+   // __NR_fchown 95
+   GO(__NR_fchown, "3s 0m");
+   SY(__NR_fchown, x0, x0, x0); FAIL;
+
+   // __NR_getpriority 96
+   GO(__NR_getpriority, "2s 0m");
+   SY(__NR_getpriority, x0-1, x0); FAIL;
+
+   // __NR_setpriority 97
+   GO(__NR_setpriority, "3s 0m");
+   SY(__NR_setpriority, x0-1, x0, x0); FAIL;
+
+   // __NR_profil 98
+   GO(__NR_profil, "ni");
+   SY(__NR_profil); FAIL;
+
+   // __NR_statfs 99
+   GO(__NR_statfs, "2s 2m");
+   SY(__NR_statfs, x0, x0); FAIL;
+
+   // __NR_fstatfs 100
+   GO(__NR_fstatfs, "2s 1m");
+   SY(__NR_fstatfs, x0, x0); FAIL;
+
+   // __NR_ioperm 101
+   GO(__NR_ioperm, "3s 0m");
+   SY(__NR_ioperm, x0, x0, x0); FAIL;
+
+   // __NR_socketcall 102
+   GO(__NR_socketcall, "XXX");
+   // (XXX: need to do all sub-cases properly)
+
+   // __NR_syslog 103
+   GO(__NR_syslog, "3s 1m");
+   SY(__NR_syslog, x0+2, x0, x0+1); FAIL;
+
+   // __NR_setitimer 104
+   GO(__NR_setitimer, "3s 2m");
+   SY(__NR_setitimer, x0, x0+1, x0+1); FAIL;
+
+   // __NR_getitimer 105
+   GO(__NR_getitimer, "2s 1m");
+   SY(__NR_getitimer, x0, x0, x0); FAIL;
+
+   // __NR_stat 106
+   GO(__NR_stat, "2s 2m");
+   SY(__NR_stat, x0, x0); FAIL;
+
+   // __NR_lstat 107
+   GO(__NR_lstat, "2s 2m");
+   SY(__NR_lstat, x0, x0); FAIL;
+
+   // __NR_fstat 108
+   GO(__NR_fstat, "2s 1m");
+   SY(__NR_fstat, x0, x0); FAIL;
+
+   // __NR_olduname 109
+   GO(__NR_olduname, "n/a");
+   // (obsolete, not handled by Valgrind)
+
+   // __NR_iopl 110
+   GO(__NR_iopl, "1s 0m");
+   SY(__NR_iopl, x0+100); FAIL;
+
+   // __NR_vhangup 111
+   GO(__NR_vhangup, "0s 0m");
+   SY(__NR_vhangup); SUCC_OR_FAIL;  // Will succeed for superuser
+   
+   // __NR_idle 112
+   GO(__NR_idle, "ni");
+   SY(__NR_idle); FAIL;
+
+   // __NR_vm86old 113
+   GO(__NR_vm86old, "n/a");
+   // (will probably never be handled by Valgrind)
+
+   // __NR_wait4 114
+   GO(__NR_wait4, "4s 2m");
+   SY(__NR_wait4, x0, x0+1, x0, x0+1); FAIL;
+
+   // __NR_swapoff 115
+   GO(__NR_swapoff, "n/a");
+ //SY(__NR_swapoff); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_sysinfo 116
+   GO(__NR_sysinfo, "1s 1m");
+   SY(__NR_sysinfo, x0); FAIL;
+
+   // __NR_ipc 117
+   // XXX: This is simplistic -- need to do all the sub-cases properly.
+   // XXX: Also, should be 6 scalar errors, except glibc's syscall() doesn't
+   //      use the 6th one!
+   GO(__NR_ipc, "5s 0m");
+   SY(__NR_ipc, x0+4, x0, x0, x0, x0, x0); FAIL;
+
+   // __NR_fsync 118
+   GO(__NR_fsync, "1s 0m");
+   SY(__NR_fsync, x0-1); FAIL;
+
+   // __NR_sigreturn 119
+   GO(__NR_sigreturn, "n/a");
+ //SY(__NR_sigreturn); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_clone 120
+#ifndef CLONE_PARENT_SETTID
+#define CLONE_PARENT_SETTID   0x00100000
+#endif
+   // XXX: should really be "4s 2m"?  Not sure... (see PRE(sys_clone))
+   GO(__NR_clone, "4s 0m");
+   SY(__NR_clone, x0|CLONE_PARENT_SETTID|SIGCHLD, x0, x0, x0); FAIL;
+   if (0 == res) {
+      SY(__NR_exit, 0); FAIL;
+   }
+
+   // __NR_setdomainname 121
+   GO(__NR_setdomainname, "n/a");
+ //SY(__NR_setdomainname); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_uname 122
+   GO(__NR_uname, "1s 1m");
+   SY(__NR_uname, x0); FAIL;
+
+   // __NR_modify_ldt 123
+   GO(__NR_modify_ldt, "3s 1m");
+   SY(__NR_modify_ldt, x0+1, x0, x0+1); FAILx(EINVAL);
+
+   // __NR_adjtimex 124
+   // XXX: need to do properly, but deref'ing NULL causing Valgrind to crash...
+     GO(__NR_adjtimex, "XXX");
+//   SY(__NR_adjtimex, x0); FAIL;
+
+   // __NR_mprotect 125
+   GO(__NR_mprotect, "3s 0m");
+   SY(__NR_mprotect, x0+1, x0, x0); FAILx(EINVAL);
+
+   // __NR_sigprocmask 126
+   GO(__NR_sigprocmask, "3s 2m");
+   SY(__NR_sigprocmask, x0, x0+&px[1], x0+&px[1]); SUCC;
+
+   // __NR_create_module 127
+   GO(__NR_create_module, "ni");
+   SY(__NR_create_module); FAIL;
+
+   // __NR_init_module 128
+   GO(__NR_init_module, "3s 2m");
+   SY(__NR_init_module, x0, x0+1, x0); FAIL;
+
+   // __NR_delete_module 129
+   GO(__NR_delete_module, "n/a");
+ //SY(__NR_delete_module); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_get_kernel_syms 130
+   GO(__NR_get_kernel_syms, "ni");
+   SY(__NR_get_kernel_syms); FAIL;
+
+   // __NR_quotactl 131
+   GO(__NR_quotactl, "4s 1m");
+   SY(__NR_quotactl, x0, x0, x0, x0); FAIL;
+
+   // __NR_getpgid 132
+   GO(__NR_getpgid, "1s 0m");
+   SY(__NR_getpgid, x0-1); FAIL;
+
+   // __NR_fchdir 133
+   GO(__NR_fchdir, "1s 0m");
+   SY(__NR_fchdir, x0-1); FAIL;
+
+   // __NR_bdflush 134
+   GO(__NR_bdflush, "n/a");
+ //SY(__NR_bdflush); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_sysfs 135
+   GO(__NR_sysfs, "n/a");
+ //SY(__NR_sysfs); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_personality 136
+   GO(__NR_personality, "1s 0m");
+   SY(__NR_personality, x0+0xffffffff); SUCC;
+
+   // __NR_afs_syscall 137
+   GO(__NR_afs_syscall, "ni");
+   SY(__NR_afs_syscall); FAIL;
+
+   // __NR_setfsuid 138
+   GO(__NR_setfsuid, "1s 0m");
+   SY(__NR_setfsuid, x0); SUCC;  // This syscall has a stupid return value
+
+   // __NR_setfsgid 139
+   GO(__NR_setfsgid, "1s 0m");
+   SY(__NR_setfsgid, x0); SUCC;  // This syscall has a stupid return value
+
+   // __NR__llseek 140
+   GO(__NR__llseek, "5s 1m");
+   SY(__NR__llseek, x0, x0, x0, x0, x0); FAIL;
+
+   // __NR_getdents 141
+   GO(__NR_getdents, "3s 1m");
+   SY(__NR_getdents, x0, x0, x0+1); FAIL;
+
+   // __NR__newselect 142
+   GO(__NR__newselect, "5s 4m");
+   SY(__NR__newselect, x0+8, x0+0xffffffff, x0+1, x0+1, x0+1); FAIL;
+
+   // __NR_flock 143
+   GO(__NR_flock, "2s 0m");
+   SY(__NR_flock, x0, x0); FAIL;
+
+   // __NR_msync 144
+   GO(__NR_msync, "3s 1m");
+   SY(__NR_msync, x0, x0+1, x0); FAIL;
+
+   // __NR_readv 145
+   GO(__NR_readv, "3s 1m");
+   SY(__NR_readv, x0, x0, x0+1); FAIL;
+
+   // __NR_writev 146
+   GO(__NR_writev, "3s 1m");
+   SY(__NR_writev, x0, x0, x0+1); FAIL;
+
+   // __NR_getsid 147
+   GO(__NR_getsid, "1s 0m");
+   SY(__NR_getsid, x0-1); FAIL;
+
+   // __NR_fdatasync 148
+   GO(__NR_fdatasync, "1s 0m");
+   SY(__NR_fdatasync, x0-1); FAIL;
+
+   // __NR__sysctl 149
+   GO(__NR__sysctl, "1s 1m");
+   SY(__NR__sysctl, x0); FAIL;
+
+   // __NR_mlock 150
+   GO(__NR_mlock, "2s 0m");
+   SY(__NR_mlock, x0, x0+1); FAIL;
+
+   // __NR_munlock 151
+   GO(__NR_munlock, "2s 0m");
+   SY(__NR_munlock, x0, x0+1); FAIL;
+
+   // __NR_mlockall 152
+   GO(__NR_mlockall, "1s 0m");
+   SY(__NR_mlockall, x0-1); FAIL;
+
+   // __NR_munlockall 153
+   GO(__NR_munlockall, "0s 0m");
+   SY(__NR_munlockall); SUCC_OR_FAILx(EPERM);
+
+   // __NR_sched_setparam 154
+   GO(__NR_sched_setparam, "2s 1m");
+   SY(__NR_sched_setparam, x0, x0); FAIL;
+
+   // __NR_sched_getparam 155
+   GO(__NR_sched_getparam, "2s 1m");
+   SY(__NR_sched_getparam, x0, x0); FAIL;
+
+   // __NR_sched_setscheduler 156
+   GO(__NR_sched_setscheduler, "3s 1m");
+   SY(__NR_sched_setscheduler, x0-1, x0, x0+1); FAIL;
+
+   // __NR_sched_getscheduler 157
+   GO(__NR_sched_getscheduler, "1s 0m");
+   SY(__NR_sched_getscheduler, x0-1); FAIL;
+
+   // __NR_sched_yield 158
+   GO(__NR_sched_yield, "0s 0m");
+   SY(__NR_sched_yield); SUCC;
+
+   // __NR_sched_get_priority_max 159
+   GO(__NR_sched_get_priority_max, "1s 0m");
+   SY(__NR_sched_get_priority_max, x0-1); FAIL;
+
+   // __NR_sched_get_priority_min 160
+   GO(__NR_sched_get_priority_min, "1s 0m");
+   SY(__NR_sched_get_priority_min, x0-1); FAIL;
+
+   // __NR_sched_rr_get_interval 161
+   GO(__NR_sched_rr_get_interval, "n/a");
+ //SY(__NR_sched_rr_get_interval); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_nanosleep 162
+   GO(__NR_nanosleep, "2s 2m");
+   SY(__NR_nanosleep, x0, x0+1); FAIL;
+
+   // __NR_mremap 163
+   GO(__NR_mremap, "5s 0m");
+   SY(__NR_mremap, x0+1, x0, x0, x0+MREMAP_FIXED, x0); FAILx(EINVAL);
+
+   // __NR_setresuid 164
+   GO(__NR_setresuid, "3s 0m");
+   SY(__NR_setresuid, x0, x0, x0); FAIL;
+
+   // __NR_getresuid 165
+   GO(__NR_getresuid, "3s 3m");
+   SY(__NR_getresuid, x0, x0, x0); FAIL;
+
+   // __NR_vm86 166
+   GO(__NR_vm86, "n/a");
+   // (will probably never be handled by Valgrind)
+
+   // __NR_query_module 167
+   GO(__NR_query_module, "ni");
+   SY(__NR_query_module); FAIL;
+
+   // __NR_poll 168
+   GO(__NR_poll, "3s 1m");
+   SY(__NR_poll, x0, x0+1, x0); FAIL;
+
+   // __NR_nfsservctl 169
+   GO(__NR_nfsservctl, "n/a");
+ //SY(__NR_nfsservctl); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_setresgid 170
+   GO(__NR_setresgid, "3s 0m");
+   SY(__NR_setresgid, x0, x0, x0); FAIL;
+
+   // __NR_getresgid 171
+   GO(__NR_getresgid, "3s 3m");
+   SY(__NR_getresgid, x0, x0, x0); FAIL;
+
+   // __NR_prctl 172
+   GO(__NR_prctl, "5s 0m");
+   SY(__NR_prctl, x0, x0, x0, x0, x0); FAIL;
+
+   // __NR_rt_sigreturn 173
+   GO(__NR_rt_sigreturn, "n/a");
+ //SY(__NR_rt_sigreturn); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_rt_sigaction 174
+   GO(__NR_rt_sigaction, "4s 4m");
+   SY(__NR_rt_sigaction, x0, x0+&px[2], x0+&px[2], x0); FAIL;
+
+   // __NR_rt_sigprocmask 175
+   GO(__NR_rt_sigprocmask, "4s 2m");
+   SY(__NR_rt_sigprocmask, x0, x0+1, x0+1, x0); FAIL;
+
+   // __NR_rt_sigpending 176
+   GO(__NR_rt_sigpending, "2s 1m");
+   SY(__NR_rt_sigpending, x0, x0+1); FAIL;
+
+   // __NR_rt_sigtimedwait 177
+   GO(__NR_rt_sigtimedwait, "4s 3m");
+   SY(__NR_rt_sigtimedwait, x0+1, x0+1, x0+1, x0); FAIL;
+
+   // __NR_rt_sigqueueinfo 178
+   GO(__NR_rt_sigqueueinfo, "3s 1m");
+   SY(__NR_rt_sigqueueinfo, x0, x0+1, x0); FAIL;
+
+   // __NR_rt_sigsuspend 179
+   GO(__NR_rt_sigsuspend, "ignore");
+   // (I don't know how to test this...)
+
+   // __NR_pread64 180
+   GO(__NR_pread64, "5s 1m");
+   SY(__NR_pread64, x0, x0, x0+1, x0, x0); FAIL;
+
+   // __NR_pwrite64 181
+   GO(__NR_pwrite64, "5s 1m");
+   SY(__NR_pwrite64, x0, x0, x0+1, x0, x0); FAIL;
+
+   // __NR_chown 182
+   GO(__NR_chown, "3s 1m");
+   SY(__NR_chown, x0, x0, x0); FAIL;
+
+   // __NR_getcwd 183
+   GO(__NR_getcwd, "2s 1m");
+   SY(__NR_getcwd, x0, x0+1); FAIL;
+
+   // __NR_capget 184
+   GO(__NR_capget, "2s 2m");
+   SY(__NR_capget, x0, x0); FAIL;
+
+   // __NR_capset 185
+   GO(__NR_capset, "2s 2m");
+   SY(__NR_capset, x0, x0); FAIL;
+
+   // __NR_sigaltstack 186
+   {
+      struct our_sigaltstack {
+              void *ss_sp;
+              int ss_flags;
+              size_t ss_size;
+      } ss;
+      ss.ss_sp     = NULL;
+      ss.ss_flags  = 0;
+      ss.ss_size   = 0;
+      VALGRIND_MAKE_MEM_NOACCESS(& ss, sizeof(struct our_sigaltstack));
+      GO(__NR_sigaltstack, "2s 2m");
+      SY(__NR_sigaltstack, x0+&ss, x0+&ss); SUCC;
+   }
+
+   // __NR_sendfile 187
+   GO(__NR_sendfile, "4s 1m");
+   SY(__NR_sendfile, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_getpmsg 188
+   // Could do 5s 4m with more effort, but I can't be bothered for this
+   // crappy non-standard syscall.
+   GO(__NR_getpmsg, "5s 0m");
+   SY(__NR_getpmsg, x0, x0, x0, x0); FAIL;
+
+   // __NR_putpmsg 189
+   // Could do 5s 2m with more effort, but I can't be bothered for this
+   // crappy non-standard syscall.
+   GO(__NR_putpmsg, "5s 0m");
+   SY(__NR_putpmsg, x0, x0, x0, x0, x0); FAIL;
+
+   // __NR_vfork 190
+   GO(__NR_vfork, "other");
+   // (sse scalar_vfork.c)
+
+   // __NR_ugetrlimit 191
+   GO(__NR_ugetrlimit, "2s 1m");
+   SY(__NR_ugetrlimit, x0, x0); FAIL;
+
+   // __NR_mmap2 192
+   GO(__NR_mmap2, "6s 0m");
+   SY(__NR_mmap2, x0, x0, x0, x0, x0-1, x0); FAIL;
+
+   // __NR_truncate64 193
+   GO(__NR_truncate64, "3s 1m");
+   SY(__NR_truncate64, x0, x0, x0); FAIL;
+
+   // __NR_ftruncate64 194
+   GO(__NR_ftruncate64, "3s 0m");
+   SY(__NR_ftruncate64, x0, x0, x0); FAIL;
+
+   // __NR_stat64 195
+   GO(__NR_stat64, "2s 2m");
+   SY(__NR_stat64, x0, x0); FAIL;
+
+   // __NR_lstat64 196
+   GO(__NR_lstat64, "2s 2m");
+   SY(__NR_lstat64, x0, x0); FAIL;
+
+   // __NR_fstat64 197
+   GO(__NR_fstat64, "2s 1m");
+   SY(__NR_fstat64, x0, x0); FAIL;
+
+   // __NR_lchown32 198
+   GO(__NR_lchown32, "3s 1m");
+   SY(__NR_lchown32, x0, x0, x0); FAIL;
+
+   // __NR_getuid32 199
+   GO(__NR_getuid32, "0s 0m");
+   SY(__NR_getuid32); SUCC;
+
+   // __NR_getgid32 200
+   GO(__NR_getgid32, "0s 0m");
+   SY(__NR_getgid32); SUCC;
+
+   // __NR_geteuid32 201
+   GO(__NR_geteuid32, "0s 0m");
+   SY(__NR_geteuid32); SUCC;
+
+   // __NR_getegid32 202
+   GO(__NR_getegid32, "0s 0m");
+   SY(__NR_getegid32); SUCC;
+
+   // __NR_setreuid32 203
+   GO(__NR_setreuid32, "2s 0m");
+   SY(__NR_setreuid32, x0, x0); FAIL;
+
+   // __NR_setregid32 204
+   GO(__NR_setregid32, "2s 0m");
+   SY(__NR_setregid32, x0, x0); FAIL;
+
+   // __NR_getgroups32 205
+   GO(__NR_getgroups32, "2s 1m");
+   SY(__NR_getgroups32, x0+1, x0+1); FAIL;
+
+   // __NR_setgroups32 206
+   GO(__NR_setgroups32, "2s 1m");
+   SY(__NR_setgroups32, x0+1, x0+1); FAIL;
+
+   // __NR_fchown32 207
+   GO(__NR_fchown32, "3s 0m");
+   SY(__NR_fchown32, x0, x0, x0); FAIL;
+
+   // __NR_setresuid32 208
+   GO(__NR_setresuid32, "3s 0m");
+   SY(__NR_setresuid32, x0, x0, x0); FAIL;
+
+   // __NR_getresuid32 209
+   GO(__NR_getresuid32, "3s 3m");
+   SY(__NR_getresuid32, x0, x0, x0); FAIL;
+
+   // __NR_setresgid32 210
+   GO(__NR_setresgid32, "3s 0m");
+   SY(__NR_setresgid32, x0, x0, x0); FAIL;
+
+   // __NR_getresgid32 211
+   GO(__NR_getresgid32, "3s 3m");
+   SY(__NR_getresgid32, x0, x0, x0); FAIL;
+
+   // __NR_chown32 212
+   GO(__NR_chown32, "3s 1m");
+   SY(__NR_chown32, x0, x0, x0); FAIL;
+
+   // __NR_setuid32 213
+   GO(__NR_setuid32, "1s 0m");
+   SY(__NR_setuid32, x0); FAIL;
+
+   // __NR_setgid32 214
+   GO(__NR_setgid32, "1s 0m");
+   SY(__NR_setgid32, x0); FAIL;
+
+   // __NR_setfsuid32 215
+   GO(__NR_setfsuid32, "1s 0m");
+   SY(__NR_setfsuid32, x0); SUCC;  // This syscall has a stupid return value
+
+   // __NR_setfsgid32 216
+   GO(__NR_setfsgid32, "1s 0m");
+   SY(__NR_setfsgid32, x0); SUCC;  // This syscall has a stupid return value
+
+   // __NR_pivot_root 217
+   GO(__NR_pivot_root, "n/a");
+ //SY(__NR_pivot_root); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_mincore 218
+   GO(__NR_mincore, "3s 1m");
+   SY(__NR_mincore, x0, x0+40960, x0); FAIL;
+
+   // __NR_madvise 219
+   GO(__NR_madvise, "3s 0m");
+   SY(__NR_madvise, x0, x0+1, x0); FAILx(ENOMEM);
+
+   // __NR_getdents64 220
+   GO(__NR_getdents64, "3s 1m");
+   SY(__NR_getdents64, x0, x0, x0+1); FAIL;
+
+   // __NR_fcntl64 221
+   // As with sys_open(), we don't trigger errors for the 1st two args for
+   // the later ones.
+   // For F_GETFD the 3rd arg is ignored.
+   GO(__NR_fcntl64, "(GETFD) 2s 0m");
+   SY(__NR_fcntl64, x0-1, x0+F_GETFD, x0); FAILx(EBADF);
+
+   // For F_DUPFD the 3rd arg is 'arg'
+   GO(__NR_fcntl64, "(DUPFD) 1s 0m");
+   SY(__NR_fcntl64, -1, F_DUPFD, x0); FAILx(EBADF);
+
+   // For F_GETLK the 3rd arg is 'lock'.
+   // On x86, this fails w/EBADF.  But on amd64 in 32-bit mode it fails
+   // w/EFAULT.
+   GO(__NR_fcntl64, "(GETLK) 1s 0m"); 
+   SY(__NR_fcntl64, -1, +F_GETLK, x0); FAIL; //FAILx(EBADF);
+
+   // 222
+   GO(222, "ni");
+   SY(222); FAIL;
+
+   // 223
+   GO(223, "ni");
+   SY(223); FAIL;
+
+   // __NR_gettid 224
+   GO(__NR_gettid, "n/a");
+ //SY(__NR_gettid); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_readahead 225
+   GO(__NR_readahead, "n/a");
+ //SY(__NR_readahead); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_setxattr 226
+   GO(__NR_setxattr, "5s 3m");
+   SY(__NR_setxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_lsetxattr 227
+   GO(__NR_lsetxattr, "5s 3m");
+   SY(__NR_lsetxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_fsetxattr 228
+   GO(__NR_fsetxattr, "5s 2m");
+   SY(__NR_fsetxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_getxattr 229
+   GO(__NR_getxattr, "4s 3m");
+   SY(__NR_getxattr, x0, x0, x0, x0+1); FAIL;
+
+   // __NR_lgetxattr 230
+   GO(__NR_lgetxattr, "4s 3m");
+   SY(__NR_lgetxattr, x0, x0, x0, x0+1); FAIL;
+
+   // __NR_fgetxattr 231
+   GO(__NR_fgetxattr, "4s 2m");
+   SY(__NR_fgetxattr, x0, x0, x0, x0+1); FAIL;
+
+   // __NR_listxattr 232
+   GO(__NR_listxattr, "3s 2m");
+   SY(__NR_listxattr, x0, x0, x0+1); FAIL;
+
+   // __NR_llistxattr 233
+   GO(__NR_llistxattr, "3s 2m");
+   SY(__NR_llistxattr, x0, x0, x0+1); FAIL;
+
+   // __NR_flistxattr 234
+   GO(__NR_flistxattr, "3s 1m");
+   SY(__NR_flistxattr, x0-1, x0, x0+1); FAIL; /* kernel returns EBADF, but both seem correct */
+
+   // __NR_removexattr 235
+   GO(__NR_removexattr, "2s 2m");
+   SY(__NR_removexattr, x0, x0); FAIL;
+
+   // __NR_lremovexattr 236
+   GO(__NR_lremovexattr, "2s 2m");
+   SY(__NR_lremovexattr, x0, x0); FAIL;
+
+   // __NR_fremovexattr 237
+   GO(__NR_fremovexattr, "2s 1m");
+   SY(__NR_fremovexattr, x0, x0); FAIL;
+
+   // __NR_tkill 238
+   GO(__NR_tkill, "n/a");
+ //SY(__NR_tkill); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_sendfile64 239
+   GO(__NR_sendfile64, "4s 1m");
+   SY(__NR_sendfile64, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_futex 240
+   #ifndef FUTEX_WAIT
+   #define FUTEX_WAIT   0
+   #endif
+   // XXX: again, glibc not doing 6th arg means we have only 5s errors
+   GO(__NR_futex, "5s 2m");
+   SY(__NR_futex, x0+FUTEX_WAIT, x0, x0, x0+1, x0, x0); FAIL;
+
+   // __NR_sched_setaffinity 241
+   GO(__NR_sched_setaffinity, "3s 1m");
+   SY(__NR_sched_setaffinity, x0, x0+1, x0); FAIL;
+
+   // __NR_sched_getaffinity 242
+   GO(__NR_sched_getaffinity, "3s 1m");
+   SY(__NR_sched_getaffinity, x0, x0+1, x0); FAIL;
+
+   // __NR_set_thread_area 243
+   GO(__NR_set_thread_area, "1s 1m");
+   SY(__NR_set_thread_area, x0); FAILx(EFAULT);
+
+   // __NR_get_thread_area 244
+   GO(__NR_get_thread_area, "1s 1m");
+   SY(__NR_get_thread_area, x0); FAILx(EFAULT);
+
+   // __NR_io_setup 245
+   GO(__NR_io_setup, "2s 1m");
+   SY(__NR_io_setup, x0, x0); FAIL;
+
+   // __NR_io_destroy 246
+   {
+      // jump through hoops to prevent the PRE(io_destroy) wrapper crashing.
+      struct fake_aio_ring {   
+        unsigned        id;     /* kernel internal index number */
+        unsigned        nr;     /* number of io_events */
+        // There are more fields in the real aio_ring, but the 'nr' field is
+        // the only one used by the PRE() wrapper.
+      } ring = { 0, 0 };
+      struct fake_aio_ring* ringptr = &ring;
+      GO(__NR_io_destroy, "1s 0m");
+      SY(__NR_io_destroy, x0+&ringptr); FAIL;
+   }
+
+   // __NR_io_getevents 247
+   GO(__NR_io_getevents, "5s 2m");
+   SY(__NR_io_getevents, x0, x0, x0+1, x0, x0+1); FAIL;
+
+   // __NR_io_submit 248
+   GO(__NR_io_submit, "3s 1m");
+   SY(__NR_io_submit, x0, x0+1, x0); FAIL;
+
+   // __NR_io_cancel 249
+   GO(__NR_io_cancel, "3s 2m");
+   SY(__NR_io_cancel, x0, x0, x0); FAIL;
+
+   // __NR_fadvise64 250
+   GO(__NR_fadvise64, "n/a");
+ //SY(__NR_fadvise64); // (Not yet handled by Valgrind) FAIL;
+
+   // 251
+   GO(251, "ni");
+   SY(251); FAIL;
+
+   // __NR_exit_group 252
+   GO(__NR_exit_group, "other");
+   // (see scalar_exit_group.c)
+
+   // __NR_lookup_dcookie 253
+   GO(__NR_lookup_dcookie, "4s 1m");
+   SY(__NR_lookup_dcookie, x0, x0, x0, x0+1); FAIL;
+
+   // __NR_epoll_create 254
+   GO(__NR_epoll_create, "1s 0m");
+   SY(__NR_epoll_create, x0); SUCC_OR_FAIL;
+
+   // __NR_epoll_ctl 255
+   GO(__NR_epoll_ctl, "4s 1m");
+   SY(__NR_epoll_ctl, x0, x0, x0, x0); FAIL;
+
+   // __NR_epoll_wait 256
+   GO(__NR_epoll_wait, "4s 1m");
+   SY(__NR_epoll_wait, x0, x0, x0+1, x0); FAIL;
+
+   // __NR_remap_file_pages 257
+   GO(__NR_remap_file_pages, "n/a");
+ //SY(__NR_remap_file_pages); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_set_tid_address 258
+   GO(__NR_set_tid_address, "1s 0m");
+   SY(__NR_set_tid_address, x0); SUCC_OR_FAILx(ENOSYS);
+
+   // __NR_timer_create 259
+   GO(__NR_timer_create, "3s 2m");
+   SY(__NR_timer_create, x0, x0+1, x0); FAIL;
+
+   // __NR_timer_settime (__NR_timer_create+1)
+   GO(__NR_timer_settime, "4s 2m");
+   SY(__NR_timer_settime, x0, x0, x0, x0+1); FAIL;
+
+   // __NR_timer_gettime (__NR_timer_create+2)
+   GO(__NR_timer_gettime, "2s 1m");
+   SY(__NR_timer_gettime, x0, x0); FAIL;
+
+   // __NR_timer_getoverrun (__NR_timer_create+3)
+   GO(__NR_timer_getoverrun, "1s 0m");
+   SY(__NR_timer_getoverrun, x0); FAIL;
+
+   // __NR_timer_delete (__NR_timer_create+4)
+   GO(__NR_timer_delete, "1s 0m");
+   SY(__NR_timer_delete, x0); FAIL;
+
+   // __NR_clock_settime (__NR_timer_create+5)
+   GO(__NR_clock_settime, "2s 1m");
+   SY(__NR_clock_settime, x0, x0);  FAIL; FAIL;
+
+   // __NR_clock_gettime (__NR_timer_create+6)
+   GO(__NR_clock_gettime, "2s 1m");
+   SY(__NR_clock_gettime, x0, x0); FAIL;
+
+   // __NR_clock_getres (__NR_timer_create+7)
+   GO(__NR_clock_getres, "2s 1m");
+   SY(__NR_clock_getres, x0+1, x0+1); FAIL; FAIL;
+
+   // __NR_clock_nanosleep (__NR_timer_create+8)
+   GO(__NR_clock_nanosleep, "n/a");
+ //SY(__NR_clock_nanosleep); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_statfs64 268
+   GO(__NR_statfs64, "3s 2m");
+   SY(__NR_statfs64, x0, x0+1, x0); FAIL;
+
+   // __NR_fstatfs64 269
+   GO(__NR_fstatfs64, "3s 1m");
+   SY(__NR_fstatfs64, x0, x0+1, x0); FAIL;
+
+   // __NR_tgkill 270
+   GO(__NR_tgkill, "n/a");
+ //SY(__NR_tgkill); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_utimes 271
+   GO(__NR_utimes, "2s 2m");
+   SY(__NR_utimes, x0, x0+1); FAIL;
+
+   // __NR_fadvise64_64 272
+   GO(__NR_fadvise64_64, "n/a");
+ //SY(__NR_fadvise64_64); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_vserver 273
+   GO(__NR_vserver, "ni");
+   SY(__NR_vserver); FAIL;
+
+   // __NR_mbind 274
+   GO(__NR_mbind, "n/a");
+ //SY(__NR_mbind); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_get_mempolicy 275
+   GO(__NR_get_mempolicy, "n/a");
+ //SY(__NR_get_mempolicy); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_set_mempolicy 276
+   GO(__NR_set_mempolicy, "n/a");
+ //SY(__NR_set_mempolicy); // (Not yet handled by Valgrind) FAIL;
+
+   // __NR_mq_open 277
+   GO(__NR_mq_open, "4s 3m");
+   SY(__NR_mq_open, x0, x0+O_CREAT, x0, x0+1); FAIL;
+
+   // __NR_mq_unlink (__NR_mq_open+1)
+   GO(__NR_mq_unlink, "1s 1m");
+   SY(__NR_mq_unlink, x0); FAIL;
+
+   // __NR_mq_timedsend (__NR_mq_open+2)
+   GO(__NR_mq_timedsend, "5s 2m");
+   SY(__NR_mq_timedsend, x0, x0, x0+1, x0, x0+1); FAIL;
+
+   // __NR_mq_timedreceive (__NR_mq_open+3)
+   GO(__NR_mq_timedreceive, "5s 3m");
+   SY(__NR_mq_timedreceive, x0, x0, x0+1, x0+1, x0+1); FAIL;
+  
+   // __NR_mq_notify (__NR_mq_open+4)
+   GO(__NR_mq_notify, "2s 1m");
+   SY(__NR_mq_notify, x0, x0+1); FAIL;
+
+   // __NR_mq_getsetattr (__NR_mq_open+5)
+   GO(__NR_mq_getsetattr, "3s 2m");
+   SY(__NR_mq_getsetattr, x0, x0+1, x0+1); FAIL;
+   
+   // __NR_sys_kexec_load 283
+   GO(__NR_sys_kexec_load, "ni");
+   SY(__NR_sys_kexec_load); FAIL;
+#endif
+
+   // no such syscall...
+   GO(9999, "1e");
+   SY(9999); FAIL;
+
+   // __NR_exit 1
+   GO(__NR_exit, "1s 0m");
+   SY(__NR_exit, x0); FAIL;
+
+   assert(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar.h b/memcheck/tests/darwin/scalar.h
new file mode 100644
index 0000000..8bfd2e1
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.h
@@ -0,0 +1,57 @@
+#include "vki/vki-scnums-darwin.h"
+#include "pub_tool_vkiscnums.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// Since we use vki_unistd.h, we can't include <unistd.h>.  So we have to
+// declare this ourselves.
+extern int syscall (int __sysno, ...);
+
+// Thorough syscall scalar arg checking.  Also serves as thorough checking
+// for (very) basic syscall use.  Generally not trying to do anything
+// meaningful with the syscalls.
+
+#define GO(__NR_xxx, s) \
+   fprintf(stderr, "-----------------------------------------------------\n"  \
+                   "%3d:%20s %s\n"                                            \
+                   "-----------------------------------------------------\n", \
+                   VG_DARWIN_SYSNO_PRINT(__NR_xxx), #__NR_xxx, s);
+
+#define SY(__NR_xxx, args...)    res = syscall(__NR_xxx, ##args);
+
+#define FAIL  assert(-1 == res);
+#define SUCC  assert(-1 != res);
+#define SUCC_OR_FAIL    /* no test */
+
+#define FAILx(E) \
+   do { \
+      int myerrno = errno; \
+      if (-1 == res) { \
+         if (E == myerrno) { \
+            /* 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);
+
+#define SUCC_OR_FAILx(E) \
+   do { \
+      int myerrno = errno; \
+      if (-1 == res) { \
+         if (E == myerrno) { \
+            /* as expected */ \
+         } else { \
+         fprintf(stderr, "Expected error %s (%d), got %d\n", #E, E, myerrno); \
+         exit(1); \
+         } \
+      } \
+   } while (0);
diff --git a/memcheck/tests/darwin/scalar.stderr.exp b/memcheck/tests/darwin/scalar.stderr.exp
new file mode 100644
index 0000000..7b383cc
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.stderr.exp
@@ -0,0 +1,208 @@
+-----------------------------------------------------
+  1:           __NR_exit below
+-----------------------------------------------------
+-----------------------------------------------------
+  2:           __NR_fork other
+-----------------------------------------------------
+-----------------------------------------------------
+  3:           __NR_read 1+3s 1m
+-----------------------------------------------------
+Syscall param (syscallno) contains uninitialised byte(s)
+   ...
+
+Syscall param read(fd) contains uninitialised byte(s)
+   ...
+
+Syscall param read(buf) contains uninitialised byte(s)
+   ...
+
+Syscall param read(count) contains uninitialised byte(s)
+   ...
+
+Syscall param read(buf) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+  4:          __NR_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
+-----------------------------------------------------
+105:     __NR_setsockopt 5s 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 socketcall.setsockopt(optval) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+118:     __NR_getsockopt 5s 1m
+-----------------------------------------------------
+
+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(optlen) contains uninitialised byte(s)
+   ...
+
+Syscall param socketcall.getsockopt(optlen) 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:...)
+   by 0x........: main (scalar.c:13)
+-----------------------------------------------------
+169:          __NR_csops 4s 1m
+-----------------------------------------------------
+
+Syscall param csops(pid) contains uninitialised byte(s)
+   ...
+
+Syscall param csops(ops) contains uninitialised byte(s)
+   ...
+
+Syscall param csops(useraddr) contains uninitialised byte(s)
+   ...
+
+Syscall param csops(usersize) contains uninitialised byte(s)
+   ...
+
+Syscall param csops(addr) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+265:         __NR_shmget 3s 0m
+-----------------------------------------------------
+
+Syscall param shmget(key) contains uninitialised byte(s)
+   ...
+
+Syscall param shmget(size) contains uninitialised byte(s)
+   ...
+
+Syscall param shmget(shmflg) contains uninitialised byte(s)
+   ...
+-----------------------------------------------------
+268:       __NR_sem_open 2s 1m
+-----------------------------------------------------
+
+Syscall param sem_open(name) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_open(oflag) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_open(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+268:       __NR_sem_open (4-args) 2s 0m
+-----------------------------------------------------
+
+Syscall param sem_open(mode) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_open(value) contains uninitialised byte(s)
+   ...
+-----------------------------------------------------
+269:      __NR_sem_close 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_close(sem) contains uninitialised byte(s)
+   ...
+-----------------------------------------------------
+270:     __NR_sem_unlink 1s 1m
+-----------------------------------------------------
+
+Syscall param sem_unlink(name) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_unlink(name) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+273:       __NR_sem_post 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_post(sem) contains uninitialised byte(s)
+   ...
+-----------------------------------------------------
+275:       __NR_sem_init 3s 1m
+-----------------------------------------------------
+
+Syscall param sem_init(sem) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_init(pshared) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_init(value) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_init(sem) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+276:    __NR_sem_destroy 1s 1m
+-----------------------------------------------------
+
+Syscall param sem_destroy(sem) contains uninitialised byte(s)
+   ...
+
+Syscall param sem_destroy(sem) points to unaddressable byte(s)
+   ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+420:__NR_sem_wait_nocancel 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_wait_nocancel(sem) contains uninitialised byte(s)
+   ...
+-----------------------------------------------------
+9999:                9999 1e
+-----------------------------------------------------
+WARNING: unhandled syscall: 33564431
+           a.k.a.: 9999
+You may be able to write your own handler.
+Read the file README_MISSING_SYSCALL_OR_IOCTL.
+Nevertheless we consider this a bug.  Please report
+it at http://valgrind.org/support/bug_reports.html.
+-----------------------------------------------------
+  1:           __NR_exit 1s 0m
+-----------------------------------------------------
+
+Syscall param exit(status) contains uninitialised byte(s)
+   ...
diff --git a/memcheck/tests/darwin/scalar.vgtest b/memcheck/tests/darwin/scalar.vgtest
new file mode 100644
index 0000000..897d9e7
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.vgtest
@@ -0,0 +1,3 @@
+prog: scalar
+vgopts: -q --error-limit=no
+args: < scalar.c
diff --git a/memcheck/tests/darwin/scalar_fork.c b/memcheck/tests/darwin/scalar_fork.c
new file mode 100644
index 0000000..805ade8
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.c
@@ -0,0 +1,15 @@
+#include "scalar.h"
+
+int main(void)
+{
+   int res;
+   
+   // All __NR_xxx numbers are taken from x86
+   
+   // __NR_fork 2 --> arch/sys_fork()
+   GO(__NR_fork, "0e");
+   SY(__NR_fork);
+
+   return(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar_fork.stderr.exp b/memcheck/tests/darwin/scalar_fork.stderr.exp
new file mode 100644
index 0000000..e898498
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.stderr.exp
@@ -0,0 +1,3 @@
+-----------------------------------------------------
+  2:           __NR_fork 0e
+-----------------------------------------------------
diff --git a/memcheck/tests/darwin/scalar_fork.vgtest b/memcheck/tests/darwin/scalar_fork.vgtest
new file mode 100644
index 0000000..e38fdf6
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.vgtest
@@ -0,0 +1,2 @@
+prog: scalar_fork
+vgopts: -q
diff --git a/memcheck/tests/darwin/scalar_vfork.c b/memcheck/tests/darwin/scalar_vfork.c
new file mode 100644
index 0000000..5f9cea8
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.c
@@ -0,0 +1,13 @@
+#include "scalar.h"
+
+int main(void)
+{
+   int res;
+   
+   // __NR_vfork 66 --> __NR_fork  [we can't use sys_vfork()]
+   GO(__NR_vfork, "0e");
+   SY(__NR_vfork);
+
+   return(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar_vfork.stderr.exp b/memcheck/tests/darwin/scalar_vfork.stderr.exp
new file mode 100644
index 0000000..32644bd
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.stderr.exp
@@ -0,0 +1,3 @@
+-----------------------------------------------------
+ 66:          __NR_vfork 0e
+-----------------------------------------------------
diff --git a/memcheck/tests/darwin/scalar_vfork.vgtest b/memcheck/tests/darwin/scalar_vfork.vgtest
new file mode 100644
index 0000000..3ddad70
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.vgtest
@@ -0,0 +1,2 @@
+prog: scalar_vfork
+vgopts: -q
diff --git a/memcheck/tests/linux/Makefile.am b/memcheck/tests/linux/Makefile.am
index 81a2c9b..664ee63 100644
--- a/memcheck/tests/linux/Makefile.am
+++ b/memcheck/tests/linux/Makefile.am
@@ -22,3 +22,4 @@
 
 stack_switch_LDADD    = -lpthread
 timerfd_syscall_LDADD = -lrt
+
diff --git a/memcheck/tests/malloc_usable.c b/memcheck/tests/malloc_usable.c
index 4e2d2a0..ab57663 100644
--- a/memcheck/tests/malloc_usable.c
+++ b/memcheck/tests/malloc_usable.c
@@ -5,7 +5,7 @@
 
 int main(void)
 {
-#  if !defined(VGO_aix5)
+#  if !defined(VGO_aix5) && !defined(VGO_darwin)
    // 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/memalign2.c b/memcheck/tests/memalign2.c
index e163bf4..a3aacfe 100644
--- a/memcheck/tests/memalign2.c
+++ b/memcheck/tests/memalign2.c
@@ -22,6 +22,9 @@
 #  if defined(VGO_aix5)
    // AIX 5.2 has neither memalign() nor posix_memalign();  do nothing.
 
+#  elif defined(VGO_darwin)
+   // Likewise for Mac OS X.
+
 #  else
    // Nb: assuming VG_MIN_MALLOC_SZB is 8 or more...
    int* p;
diff --git a/memcheck/tests/origin1-yes.c b/memcheck/tests/origin1-yes.c
index acfd8ab..3ebe6f0 100644
--- a/memcheck/tests/origin1-yes.c
+++ b/memcheck/tests/origin1-yes.c
@@ -86,12 +86,21 @@
    }
 
    // Heap segment (brk), uninitialised
+   // Nb: on Darwin, sbrk() is implemented via vm_allocate() which always
+   // zeroes its allocated memory.  So we use a separate .exp file for Darwin,
+   // but we add an extra printf on Darwin only so that it cannot be
+   // successfully matched on non-Darwin platforms.
+#if defined(VGO_darwin)
+      fprintf(stderr, "\nUndef 7 of 8 (brk)\n");
+      fprintf(stderr, "\n(no complaint; sbrk initialises memory on Darwin)\n");
+#else
    {
       int* ptr_to_new_brk_limit = sbrk(4096);
       int  undef_brk_int = *ptr_to_new_brk_limit;
       fprintf(stderr, "\nUndef 7 of 8 (brk)\n");
       x += (undef_brk_int == 0x12345678 ? 15 : 26);
    }
+#endif
 
    // User block, marked as undefined
    {
diff --git a/memcheck/tests/origin1-yes.stderr.exp b/memcheck/tests/origin1-yes.stderr.exp
index 418dcd0..e2af1ab 100644
--- a/memcheck/tests/origin1-yes.stderr.exp
+++ b/memcheck/tests/origin1-yes.stderr.exp
@@ -45,18 +45,18 @@
 Undef 7 of 8 (brk)
 
 Conditional jump or move depends on uninitialised value(s)
-   at 0x........: main (origin1-yes.c:93)
+   at 0x........: main (origin1-yes.c:101)
  Uninitialised value was created
    at 0x........: brk (in /...libc...)
    by 0x........: sbrk (in /...libc...)
-   by 0x........: main (origin1-yes.c:90)
+   by 0x........: main (origin1-yes.c:98)
 
 Undef 8 of 8 (MAKE_MEM_UNDEFINED)
 
 Conditional jump or move depends on uninitialised value(s)
-   at 0x........: main (origin1-yes.c:101)
+   at 0x........: main (origin1-yes.c:110)
  Uninitialised value was created by a client request
-   at 0x........: main (origin1-yes.c:99)
+   at 0x........: main (origin1-yes.c:108)
 
 Def 1 of 3
 
diff --git a/memcheck/tests/origin1-yes.stderr.exp-darwin b/memcheck/tests/origin1-yes.stderr.exp-darwin
new file mode 100644
index 0000000..add1a37
--- /dev/null
+++ b/memcheck/tests/origin1-yes.stderr.exp-darwin
@@ -0,0 +1,60 @@
+
+Undef 1 of 8 (stack, 32 bit)
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:37)
+ Uninitialised value was created by a stack allocation
+   at 0x........: main (origin1-yes.c:23)
+
+Undef 2 of 8 (stack, 32 bit)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:49)
+ Uninitialised value was created by a stack allocation
+   at 0x........: main (origin1-yes.c:23)
+
+Undef 3 of 8 (stack, 64 bit)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:56)
+ Uninitialised value was created by a stack allocation
+   at 0x........: main (origin1-yes.c:23)
+
+Undef 4 of 8 (mallocd, 32-bit)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:64)
+ Uninitialised value was created by a heap allocation
+   at 0x........: malloc (vg_replace_malloc.c:...)
+   by 0x........: main (origin1-yes.c:61)
+
+Undef 5 of 8 (realloc)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:76)
+ Uninitialised value was created by a heap allocation
+   at 0x........: realloc (vg_replace_malloc.c:...)
+   by 0x........: main (origin1-yes.c:71)
+
+Undef 6 of 8 (MALLOCLIKE_BLOCK)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:85)
+ Uninitialised value was created by a heap allocation
+   at 0x........: main (origin1-yes.c:82)
+
+Undef 7 of 8 (brk)
+
+(no complaint; sbrk initialises memory on Darwin)
+
+Undef 8 of 8 (MAKE_MEM_UNDEFINED)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: main (origin1-yes.c:110)
+ Uninitialised value was created by a client request
+   at 0x........: main (origin1-yes.c:108)
+
+Def 1 of 3
+
+Def 2 of 3
+
+Def 3 of 3
diff --git a/memcheck/tests/sigkill.stderr.exp-darwin b/memcheck/tests/sigkill.stderr.exp-darwin
new file mode 100644
index 0000000..0e04bd8
--- /dev/null
+++ b/memcheck/tests/sigkill.stderr.exp-darwin
@@ -0,0 +1,192 @@
+
+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: Invalid argument
+getting signal 9: Invalid argument
+
+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: Invalid argument
+getting signal 17: Invalid argument
+
+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: Success
+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: Warning: ignored attempt to set SIGUSR2 handler in sigaction();
+         the SIGUSR2 signal is used internally by Valgrind
+Invalid argument
+getting signal 31: Success
+
+setting signal 34: Invalid argument
+getting signal 34: Invalid argument
+
+setting signal 35: Invalid argument
+getting signal 35: Invalid argument
+
+setting signal 36: Invalid argument
+getting signal 36: Invalid argument
+
+setting signal 37: Invalid argument
+getting signal 37: Invalid argument
+
+setting signal 38: Invalid argument
+getting signal 38: Invalid argument
+
+setting signal 39: Invalid argument
+getting signal 39: Invalid argument
+
+setting signal 40: Invalid argument
+getting signal 40: Invalid argument
+
+setting signal 41: Invalid argument
+getting signal 41: Invalid argument
+
+setting signal 42: Invalid argument
+getting signal 42: Invalid argument
+
+setting signal 43: Invalid argument
+getting signal 43: Invalid argument
+
+setting signal 44: Invalid argument
+getting signal 44: Invalid argument
+
+setting signal 45: Invalid argument
+getting signal 45: Invalid argument
+
+setting signal 46: Invalid argument
+getting signal 46: Invalid argument
+
+setting signal 47: Invalid argument
+getting signal 47: Invalid argument
+
+setting signal 48: Invalid argument
+getting signal 48: Invalid argument
+
+setting signal 49: Invalid argument
+getting signal 49: Invalid argument
+
+setting signal 50: Invalid argument
+getting signal 50: Invalid argument
+
+setting signal 51: Invalid argument
+getting signal 51: Invalid argument
+
+setting signal 52: Invalid argument
+getting signal 52: Invalid argument
+
+setting signal 53: Invalid argument
+getting signal 53: Invalid argument
+
+setting signal 54: Invalid argument
+getting signal 54: Invalid argument
+
+setting signal 55: Invalid argument
+getting signal 55: Invalid argument
+
+setting signal 56: Invalid argument
+getting signal 56: Invalid argument
+
+setting signal 57: Invalid argument
+getting signal 57: Invalid argument
+
+setting signal 58: Invalid argument
+getting signal 58: Invalid argument
+
+setting signal 59: Invalid argument
+getting signal 59: Invalid argument
+
+setting signal 60: Invalid argument
+getting signal 60: Invalid argument
+
+setting signal 61: Invalid argument
+getting signal 61: Invalid argument
+
+setting signal 62: Invalid argument
+getting signal 62: Invalid argument
+
+setting signal 65: Invalid argument
+getting signal 65: Invalid argument
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+malloc/free: in use at exit: ... bytes in ... blocks.
+malloc/free: ... allocs, ... frees, ... bytes allocated.
+For a detailed leak analysis,  rerun with: --leak-check=yes
+For counts of detected errors, rerun with: -v
diff --git a/memcheck/tests/stack_changes.c b/memcheck/tests/stack_changes.c
index e9d57d0..0d7438c 100644
--- a/memcheck/tests/stack_changes.c
+++ b/memcheck/tests/stack_changes.c
@@ -10,7 +10,7 @@
 // This test is checking the libc context calls (setcontext, etc.) and
 // checks that Valgrind notices their stack changes properly.
 
-#if defined(_AIX)
+#if defined(_AIX) || defined(__APPLE__)
 typedef  ucontext_t  mycontext;
 #else /* linux */
 typedef  struct ucontext  mycontext;
diff --git a/memcheck/tests/str_tester.c b/memcheck/tests/str_tester.c
index 3c15ea7..7516696 100644
--- a/memcheck/tests/str_tester.c
+++ b/memcheck/tests/str_tester.c
@@ -264,6 +264,8 @@
   SIMPLE_COPY(stpcpy, 16, "6666666666666666", 59);
 }
 
+// DDD: better done by testing for the function.
+#if !defined(__APPLE__)
 static void
 test_stpncpy (void)
 {
@@ -278,6 +280,7 @@
   check (stpncpy (one, "abcd", 6) == one + 4, 7);
   check (one[4] == '\0' && one[5] == '\0' && one[6] == 'x', 8);
 }
+#endif
 
 static void
 test_strcat (void)
@@ -464,7 +467,7 @@
 }
 
 // DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 static void
 test_strchrnul (void)
 {
@@ -501,7 +504,7 @@
 #endif /* !defined(_AIX) */
 
 // DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 static void
 test_rawmemchr (void)
 {
@@ -577,7 +580,7 @@
 }
 
 // DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 static void
 test_memrchr (void)
 {
@@ -899,7 +902,7 @@
   equal(one+4, "c", 50);
 
   {
-#   if !defined(_AIX)
+#   if !defined(_AIX) && !defined(__APPLE__)
     char text[] = "This,is,a,test";
     char *list = strdupa (text);
     equal (strsep (&list, ","), "This", 51);
@@ -1060,7 +1063,7 @@
     }
 }
 
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 static void
 test_mempcpy (void)
 {
@@ -1276,6 +1279,7 @@
   equal(one, "abcdef", 4);		/* Zero-length copy. */
 }
 
+#if !defined(__APPLE__)
 static void
 test_strndup (void)
 {
@@ -1299,6 +1303,7 @@
     equal(p, "abc", 6);
   free (p);
 }
+#endif
 
 static void
 test_bcmp (void)
@@ -1382,8 +1387,10 @@
   /* A closely related function is stpcpy.  */
   test_stpcpy ();
 
+#if !defined(__APPLE__)
   /* stpncpy.  */
   test_stpncpy ();
+#endif
 
   /* strcat.  */
   test_strcat ();
@@ -1403,12 +1410,12 @@
   /* strchr.  */
   test_strchr ();
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* strchrnul.  */
   test_strchrnul ();
 # endif
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* rawmemchr.  */
   test_rawmemchr ();
 # endif
@@ -1419,7 +1426,7 @@
   /* strrchr.  */
   test_strrchr ();
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* memrchr.  */
   test_memrchr ();
 # endif
@@ -1460,7 +1467,7 @@
   /* memmove - must work on overlap.  */
   test_memmove ();
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* mempcpy */
   test_mempcpy ();
 # endif
@@ -1480,8 +1487,10 @@
   /* bcmp - somewhat like memcmp.  */
   test_bcmp ();
 
+#if !defined(__APPLE__)
   /* strndup.  */
   test_strndup ();
+#endif
 
   /* strerror - VERY system-dependent.  */
   test_strerror ();
diff --git a/memcheck/tests/strchr.stderr.exp-darwin b/memcheck/tests/strchr.stderr.exp-darwin
new file mode 100644
index 0000000..8b870df
--- /dev/null
+++ b/memcheck/tests/strchr.stderr.exp-darwin
@@ -0,0 +1,11 @@
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: strchr (mc_replace_strmem.c:...)
+   by 0x........: main (strchr.c:15)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: strchr (mc_replace_strmem.c:...)
+   by 0x........: main (strchr.c:15)
+
+Conditional jump or move depends on uninitialised value(s)
+   at 0x........: strrchr (mc_replace_strmem.c:...)
+   by 0x........: main (strchr.c:16)
diff --git a/memcheck/tests/x86/Makefile.am b/memcheck/tests/x86/Makefile.am
index 28dd116..2cd7b03 100644
--- a/memcheck/tests/x86/Makefile.am
+++ b/memcheck/tests/x86/Makefile.am
@@ -42,9 +42,15 @@
 AM_CXXFLAGS  += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
 AM_CCASFLAGS += @FLAG_M32@
 
-# must be built with these flags -- bug only occurred with them
+
+# fpeflags must use these flags -- bug only occurred with them.
 fpeflags_CFLAGS		= $(AM_CFLAGS) -march=i686
 pushfpopf_SOURCES 	= pushfpopf_c.c pushfpopf_s.S
+if VGCONF_OS_IS_DARWIN
+pushpopmem_CFLAGS 	= $(AM_CFLAGS) -mdynamic-no-pic
+else
+pushpopmem_CFLAGS 	= $(AM_CFLAGS)
+endif
 tronical_SOURCES 	= tronical.S
 
 more_x86_fp_LDADD	= -lm
diff --git a/none/Makefile.am b/none/Makefile.am
index ac47371..34061af 100644
--- a/none/Makefile.am
+++ b/none/Makefile.am
@@ -19,6 +19,12 @@
 if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
 noinst_PROGRAMS += none-ppc64-aix5
 endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += none-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += none-amd64-darwin
+endif
 
 NONE_SOURCES_COMMON = nl_main.c
 
@@ -63,3 +69,17 @@
 none_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 none_ppc64_aix5_LDADD        = $(TOOL_LDADD_PPC64_AIX5)
 none_ppc64_aix5_LDFLAGS      = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+none_x86_darwin_SOURCES      = $(NONE_SOURCES_COMMON)
+none_x86_darwin_CPPFLAGS     = $(AM_CPPFLAGS_X86_DARWIN)
+none_x86_darwin_CFLAGS       = $(AM_CFLAGS_X86_DARWIN)
+none_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+none_x86_darwin_LDADD        = $(TOOL_LDADD_X86_DARWIN)
+none_x86_darwin_LDFLAGS      = $(TOOL_LDFLAGS_X86_DARWIN)
+
+none_amd64_darwin_SOURCES      = $(NONE_SOURCES_COMMON)
+none_amd64_darwin_CPPFLAGS     = $(AM_CPPFLAGS_AMD64_DARWIN)
+none_amd64_darwin_CFLAGS       = $(AM_CFLAGS_AMD64_DARWIN)
+none_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+none_amd64_darwin_LDADD        = $(TOOL_LDADD_AMD64_DARWIN)
+none_amd64_darwin_LDFLAGS      = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index dfec067..1cc18af 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -21,13 +21,16 @@
 if VGCONF_OS_IS_LINUX
 SUBDIRS += linux
 endif
+if VGCONF_OS_IS_DARWIN
+SUBDIRS += darwin
+endif
 
 # Platform-specific tests
 if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
 SUBDIRS += x86-linux
 endif
 
-DIST_SUBDIRS = x86 amd64 ppc32 ppc64 linux x86-linux .
+DIST_SUBDIRS = x86 amd64 ppc32 ppc64 linux darwin x86-linux .
 
 noinst_SCRIPTS = \
 	filter_cmdline0 filter_linenos \
@@ -140,7 +143,7 @@
 	fdleak_cmsg fdleak_creat fdleak_dup fdleak_dup2 \
 	fdleak_fcntl fdleak_ipv4 fdleak_open fdleak_pipe \
 	fdleak_socketpair \
-	floored fork fucomip manythreads \
+	floored fork fucomip \
 	munmap_exe map_unaligned map_unmap mq \
 	nestedfns \
 	pending \
@@ -151,10 +154,27 @@
 	rlimit_nofile selfrun sem semlimit sha1_test \
 	shortpush shorts stackgrowth sigstackgrowth \
 	syscall-restart1 syscall-restart2 system \
-	thread-exits threaded-fork threadederrno \
+	threaded-fork threadederrno \
 	tls tls.so tls2.so vgprintf \
 	coolo_sigaction gxx304
 
+# DDD:
+# - manythreads and thread-exits have lots of this:
+# --61831:0:aspacem  sync_check_mapping_callback: segment mismatch:
+#                    kernel's seg:
+# --61831:0:aspacem  start=0x102538000 end=0x1025b7fff prot=3 dev=0 ino=0 
+#                    offset=0 name="(none)"
+# --61831:0:aspacem  sync_check_mapping_callback: segment mismatch: V's seg:
+# --61831:0:aspacem  NSegment{    , start=0x10067a000, end=0x109a1efff,
+#                    smode=SmFixed, dev=0, ino=0, offset=0, fnIdx=-1, hasR=0,
+#                    hasW=0, hasX=0, hasT=0, mark=0, name="(none)"}
+if ! VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+   check_PROGRAMS += \
+	manythreads \
+	thread-exits
+endif
+
+
 AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
@@ -162,7 +182,11 @@
 ansi_CFLAGS		= $(AM_CFLAGS) -ansi
 floored_LDADD 		= -lm
 manythreads_LDADD	= -lpthread
-mq_LDADD		= -lrt
+if VGCONF_OS_IS_DARWIN
+ nestedfns_CFLAGS	= $(AM_CFLAGS) -fnested-functions
+else
+ mq_LDADD		= -lrt
+endif
 pth_atfork1_LDADD	= -lpthread
 pth_blockedsig_LDADD	= -lpthread
 pth_cancel1_CFLAGS	= $(AM_CFLAGS) -Wno-shadow
@@ -180,6 +204,7 @@
  res_search_LDADD       = -lpthread
 else
  res_search_LDADD       = -lresolv -lpthread
+ resolv_LDADD           = -lresolv -lpthread
 endif
 semlimit_LDADD		= -lpthread
 thread_exits_LDADD	= -lpthread
@@ -199,12 +224,21 @@
  tls_so_LDFLAGS		= -shared -fPIC
  tls_so_LDADD		= `pwd`/tls2.so
 else
+if VGCONF_OS_IS_DARWIN
+ tls_so_LDFLAGS		= -dynamic -dynamiclib -all_load -fpic
+ tls_so_LDADD		= `pwd`/tls2.so
+else
  tls_so_LDFLAGS		= -Wl,-rpath,$(top_builddir)/none/tests -shared -fPIC
  tls_so_LDADD		= tls2.so
 endif
+endif
 tls_so_CFLAGS		= $(AM_CFLAGS) -fPIC
 tls2_so_SOURCES		= tls2_so.c
+if VGCONF_OS_IS_DARWIN
+tls2_so_LDFLAGS		= -dynamic -dynamiclib -all_load
+else
 tls2_so_LDFLAGS		= -shared
+endif
 
 # C++ tests
 coolo_sigaction_SOURCES	= coolo_sigaction.cpp
diff --git a/none/tests/amd64/Makefile.am b/none/tests/amd64/Makefile.am
index 13621d0..798bf86 100644
--- a/none/tests/amd64/Makefile.am
+++ b/none/tests/amd64/Makefile.am
@@ -50,19 +50,31 @@
 	slahf-amd64.vgtest
 
 check_PROGRAMS = \
-	bug127521-64 bug132813-amd64 bug137714-amd64 bug132918 \
-	bug156404-amd64 \
+	bug127521-64 bug132813-amd64 bug132918 \
 	clc \
-	faultstatus fcmovnu fxtract $(INSN_TESTS) looper jrcxz \
+	$(INSN_TESTS) \
 	rcl-amd64 \
 	redundantRexW \
-	smc1 shrld \
-	nibz_bennee_mmap \
-	slahf-amd64
+	smc1 \
+	nibz_bennee_mmap
 if BUILD_SSSE3_TESTS
  check_PROGRAMS += ssse3_misaligned
 endif
 
+# DDD: these need to be made to work on Darwin like the x86/ ones were.
+if ! VGCONF_OS_IS_DARWIN
+   check_PROGRAMS += \
+	bug137714-amd64 \
+	bug156404-amd64 \
+	faultstatus \
+	fcmovnu \
+	fxtract \
+	looper \
+	jrcxz \
+	shrld \
+	slahf-amd64
+endif
+
 AM_CFLAGS    += @FLAG_M64@
 AM_CXXFLAGS  += @FLAG_M64@
 AM_CCASFLAGS += @FLAG_M64@
diff --git a/none/tests/darwin/Makefile.am b/none/tests/darwin/Makefile.am
new file mode 100644
index 0000000..b4c90bf
--- /dev/null
+++ b/none/tests/darwin/Makefile.am
@@ -0,0 +1,17 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+noinst_SCRIPTS = filter_stderr
+
+EXTRA_DIST = $(noinst_SCRIPTS) \
+	apple-main-arg.stderr.exp apple-main-arg.vgtest \
+	rlimit.stderr.exp rlimit.vgtest
+
+check_PROGRAMS = \
+	apple-main-arg \
+	rlimit
+
+
+AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
diff --git a/none/tests/darwin/apple-main-arg.c b/none/tests/darwin/apple-main-arg.c
new file mode 100644
index 0000000..945acc1
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/syslimits.h>
+
+// On Darwin there's this secret fourth argument, 'apple', which is a pointer
+// to a string that contains the executable path, like argv[0], but unlike
+// argv[0] it can't be changed using exec().
+
+int main(int argc, char *argv[], char *envp[], char *apple[])
+{
+   char *pargv = calloc((PATH_MAX+1), sizeof(char)),
+        *pappl = calloc((PATH_MAX+1), sizeof(char));
+   int i;
+
+   for (i = 0; envp[i]; i++)
+      ;
+
+   // envp[i]==NULL; envp[i+1]==apple[0]==executable_path
+   assert(envp[i+1] == apple[0]);
+
+   // Make sure realpath(argv[0]) == realpath(apple[0]).  (realpath resolves
+   // symlinks.)
+   realpath(argv[0], pargv);
+   realpath(apple[0], pappl);
+   assert(0 == strcmp(pargv, pappl));
+
+   return 0;
+}
+
diff --git a/none/tests/darwin/apple-main-arg.stderr.exp b/none/tests/darwin/apple-main-arg.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.stderr.exp
diff --git a/none/tests/darwin/apple-main-arg.vgtest b/none/tests/darwin/apple-main-arg.vgtest
new file mode 100644
index 0000000..df4e15a
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.vgtest
@@ -0,0 +1,2 @@
+prog: apple-main-arg
+vgopts: -q
diff --git a/none/tests/darwin/filter_stderr b/none/tests/darwin/filter_stderr
new file mode 100644
index 0000000..0ae9313
--- /dev/null
+++ b/none/tests/darwin/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/none/tests/darwin/rlimit.c b/none/tests/darwin/rlimit.c
new file mode 100644
index 0000000..ac5ac82
--- /dev/null
+++ b/none/tests/darwin/rlimit.c
@@ -0,0 +1,17 @@
+// Small test program to demonstrate Valgrind bug.
+// https://bugs.kde.org/show_bug.cgi?id=191761
+// Author: rohitrao@google.com
+//
+// Before the fix, it was printing 266.  Now it prints 256.
+
+#include <stdio.h>
+#include <sys/resource.h>
+
+int main(void)
+{
+   struct rlimit rlp;
+   getrlimit(RLIMIT_NOFILE, &rlp);
+   fprintf(stderr, "RLIMIT_NOFILE is %lld\n", (long long)rlp.rlim_cur);
+   return 0;
+}
+
diff --git a/none/tests/darwin/rlimit.stderr.exp b/none/tests/darwin/rlimit.stderr.exp
new file mode 100644
index 0000000..56d4e4c
--- /dev/null
+++ b/none/tests/darwin/rlimit.stderr.exp
@@ -0,0 +1 @@
+RLIMIT_NOFILE is 256
diff --git a/none/tests/darwin/rlimit.vgtest b/none/tests/darwin/rlimit.vgtest
new file mode 100644
index 0000000..2706845
--- /dev/null
+++ b/none/tests/darwin/rlimit.vgtest
@@ -0,0 +1,2 @@
+prog: rlimit
+vgopts: -q
diff --git a/none/tests/pth_atfork1.c b/none/tests/pth_atfork1.c
index 79ce177..df5ef98 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(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 # include <error.h>
 #endif
 #include <stdlib.h>
@@ -27,7 +27,7 @@
 #include <sys/wait.h>
 #include <stdio.h>
 
-#if defined(_AIX)
+#if defined(_AIX) || defined(__APPLE__)
 #include <string.h>  /* strerror */
 static void error (int status, int errnum, char* msg)
 {
diff --git a/none/tests/x86/Makefile.am b/none/tests/x86/Makefile.am
index cc0372b..f405c51 100644
--- a/none/tests/x86/Makefile.am
+++ b/none/tests/x86/Makefile.am
@@ -92,6 +92,14 @@
 AM_CXXFLAGS  += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
 AM_CCASFLAGS += @FLAG_M32@
 
+if VGCONF_OS_IS_DARWIN
+# Some of the tests (bug125959_x86, bug152818_x86, insn_*) need
+# -mdynamic-no-pic.  I tried setting *_CFLAGS separately for all of them,
+# but it caused problems with the generation of insn_*.c.  So just use this
+# crude approach of setting -mdynamic-no-pic for all tests in this
+# directory.
+AM_CFLAGS += -mdynamic-no-pic
+endif
 
 cpuid_SOURCES 		= cpuid_c.c cpuid_s.S
 # fpu_lazy_eflags must use these flags -- the bug only occurred with them.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0350f0d..2cf5a82 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,3 +27,7 @@
 AM_CFLAGS   += $(AM_FLAG_M3264_PRI)
 AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
+if VGCONF_OS_IS_DARWIN
+x86_amd64_features_CFLAGS = $(AM_CFLAGS) -mdynamic-no-pic
+endif
+
diff --git a/tests/arch_test.c b/tests/arch_test.c
index f6206e3..6771f4a 100644
--- a/tests/arch_test.c
+++ b/tests/arch_test.c
@@ -32,10 +32,10 @@
 
 static Bool go(char* arch)
 { 
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
    if ( 0 == strcmp( arch, "x86"   ) ) return True;
 
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
    if ( 0 == strcmp( arch, "x86"   ) ) return True;
    if ( 0 == strcmp( arch, "amd64" ) ) return True;
 
diff --git a/tests/asm.h b/tests/asm.h
index 99f9cc5..e2c2524 100644
--- a/tests/asm.h
+++ b/tests/asm.h
@@ -5,7 +5,15 @@
 // general, any symbol named in asm code should be wrapped by VG_SYM.
 
 // This one is for use in inline asm in C files.
+#if defined(VGO_darwin)
+#define VG_SYM(x) "_"#x
+#else
 #define VG_SYM(x) #x
+#endif
 
 // This one is for use in asm files.
+#if defined(VGO_darwin)
+#define VG_SYM_ASM(x) _##x
+#else
 #define VG_SYM_ASM(x) x
+#endif
diff --git a/tests/filter_libc b/tests/filter_libc
index a89fb89..48c443f 100755
--- a/tests/filter_libc
+++ b/tests/filter_libc
@@ -15,8 +15,9 @@
     s/ __GI___/ __/;
     s/ __([a-z]*)_nocancel / $1 /;
 
-    s/\(in \/.*libc.*\)$/(in \/...libc...)/;
-    s/\(within \/.*libc.*\)$/(within \/...libc...)/;
+    # "libSystem*" occurs on Darwin.
+    s/\(in \/.*(libc|libSystem).*\)$/(in \/...libc...)/;
+    s/\(within \/.*(libc|libSystem).*\)$/(within \/...libc...)/;
 
     # Remove the filename -- on some platforms (eg. Linux) it will be in
     # libc, on some (eg. Darwin) it will be in the main executable.
diff --git a/tests/malloc.h b/tests/malloc.h
index 454d2cf..0179b38 100644
--- a/tests/malloc.h
+++ b/tests/malloc.h
@@ -1,7 +1,11 @@
 // Replacement for malloc.h which factors out platform differences.
 
 #include <stdlib.h>
-#include <malloc.h>
+#if defined(VGO_darwin)
+#  include <malloc/malloc.h>
+#else
+#  include <malloc.h>
+#endif
 
 #include <assert.h>
 
@@ -10,7 +14,12 @@
 static void* memalign16(size_t szB)
 {
    void* x;
+#if defined(VGO_darwin)
+   // Darwin lacks memalign, but its malloc is always 16-aligned anyway.
+   x = malloc(szB);
+#else
    x = memalign(16, szB);
+#endif
    assert(x);
    assert(0 == ((16-1) & (unsigned long)x));
    return x;
diff --git a/tests/os_test.c b/tests/os_test.c
index 065dbe5..a65115c 100644
--- a/tests/os_test.c
+++ b/tests/os_test.c
@@ -22,6 +22,7 @@
 char* all_OSes[] = {
    "linux",
    "aix5",
+   "darwin",
    NULL
 };
 
@@ -31,7 +32,10 @@
    if ( 0 == strcmp( OS, "linux" ) ) return True;
 
 #elif defined(VGO_aix5)
-   if ( 0 == strcmp( OS, "aix5"  ) ) return True;
+   if ( 0 == strcmp( OS, "aix5" ) ) return True;
+
+#elif defined(VGO_darwin)
+   if ( 0 == strcmp( OS, "darwin" ) ) return True;
 
 #else
 #  error Unknown OS
diff --git a/tests/platform_test b/tests/platform_test
index e91b9f7..4d57901 100644
--- a/tests/platform_test
+++ b/tests/platform_test
@@ -13,6 +13,7 @@
 all_platforms=
 all_platforms="$all_platforms x86-linux amd64-linux ppc32-linux ppc64-linux"
 all_platforms="$all_platforms ppc32-aix5 ppc64-aix5"
+all_platforms="$all_platforms x86-darwin amd64-darwin"
 
 if [ $# -ne 2 ] ; then
     echo "usage: platform_test <arch-type> <OS-type>"
diff --git a/tests/sys_mman.h b/tests/sys_mman.h
index 862bccc..7ac64d5 100644
--- a/tests/sys_mman.h
+++ b/tests/sys_mman.h
@@ -2,6 +2,10 @@
 
 #include <sys/mman.h>
 
+#if defined(VGO_darwin)
+#  define MAP_ANONYMOUS MAP_ANON
+#endif
+
 
 #include <assert.h>
 #include <unistd.h>
diff --git a/tests/x86_amd64_features.c b/tests/x86_amd64_features.c
index 9d17805..06ebe5d 100644
--- a/tests/x86_amd64_features.c
+++ b/tests/x86_amd64_features.c
@@ -83,7 +83,7 @@
    return 1;                                          // Feature not present.
 }
 
-#else    // defined(VGA_x86)  || defined(VGA_amd64)
+#else
 
 static Bool go(char* cpu)
 {