]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge the DARWIN branch onto the trunk.
authorNicholas Nethercote <njn@valgrind.org>
Thu, 28 May 2009 01:53:07 +0000 (01:53 +0000)
committerNicholas Nethercote <njn@valgrind.org>
Thu, 28 May 2009 01:53:07 +0000 (01:53 +0000)
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

176 files changed:
Makefile.am
Makefile.core-tool.am
Makefile.flags.am
Makefile.tool-tests.am
Makefile.tool.am
NEWS
auxprogs/Makefile.am
cachegrind/Makefile.am
cachegrind/cg_main.c
cachegrind/tests/Makefile.am
callgrind/Makefile.am
configure.in
coregrind/Makefile.am
coregrind/launcher-darwin.c [new file with mode: 0644]
coregrind/m_aspacemgr/aspacemgr-common.c
coregrind/m_aspacemgr/aspacemgr-linux.c
coregrind/m_coredump/coredump-amd64-darwin.c [new file with mode: 0644]
coregrind/m_coredump/coredump-x86-darwin.c [new file with mode: 0644]
coregrind/m_debugger.c
coregrind/m_debuginfo/d3basics.c
coregrind/m_debuginfo/debuginfo.c
coregrind/m_debuginfo/priv_readmacho.h [new file with mode: 0644]
coregrind/m_debuginfo/priv_storage.h
coregrind/m_debuginfo/readdwarf.c
coregrind/m_debuginfo/readdwarf3.c
coregrind/m_debuginfo/readmacho.c [new file with mode: 0644]
coregrind/m_debuginfo/readstabs.c
coregrind/m_debuginfo/storage.c
coregrind/m_debuglog.c
coregrind/m_dispatch/dispatch-amd64-darwin.S [new file with mode: 0644]
coregrind/m_dispatch/dispatch-x86-darwin.S [new file with mode: 0644]
coregrind/m_initimg/initimg-darwin.c [new file with mode: 0644]
coregrind/m_libcassert.c
coregrind/m_libcbase.c
coregrind/m_libcfile.c
coregrind/m_libcproc.c
coregrind/m_libcsignal.c
coregrind/m_mach/mach_basics.c [new file with mode: 0644]
coregrind/m_mach/mach_msg.c [new file with mode: 0644]
coregrind/m_mach/mach_traps-amd64-darwin.S [new file with mode: 0644]
coregrind/m_mach/mach_traps-x86-darwin.S [new file with mode: 0644]
coregrind/m_machine.c
coregrind/m_main.c
coregrind/m_options.c
coregrind/m_redir.c
coregrind/m_replacemalloc/vg_replace_malloc.c
coregrind/m_scheduler/priv_sema.h
coregrind/m_scheduler/scheduler.c
coregrind/m_scheduler/sema.c
coregrind/m_sigframe/sigframe-amd64-darwin.c [new file with mode: 0644]
coregrind/m_sigframe/sigframe-x86-darwin.c [new file with mode: 0644]
coregrind/m_signals.c
coregrind/m_stacktrace.c
coregrind/m_start-amd64-darwin.S [new file with mode: 0644]
coregrind/m_start-x86-darwin.S [new file with mode: 0644]
coregrind/m_syscall.c
coregrind/m_syswrap/priv_syswrap-darwin.h [new file with mode: 0644]
coregrind/m_syswrap/priv_syswrap-main.h
coregrind/m_syswrap/priv_types_n_macros.h
coregrind/m_syswrap/syscall-amd64-darwin.S [new file with mode: 0644]
coregrind/m_syswrap/syscall-x86-darwin.S [new file with mode: 0644]
coregrind/m_syswrap/syswrap-amd64-darwin.c [new file with mode: 0644]
coregrind/m_syswrap/syswrap-darwin.c [new file with mode: 0644]
coregrind/m_syswrap/syswrap-generic.c
coregrind/m_syswrap/syswrap-main.c
coregrind/m_syswrap/syswrap-x86-darwin.c [new file with mode: 0644]
coregrind/m_trampoline.S
coregrind/m_translate.c
coregrind/m_ume/elf.c
coregrind/m_ume/macho.c [new file with mode: 0644]
coregrind/m_ume/main.c
coregrind/m_ume/priv_ume.h
coregrind/m_vki.c
coregrind/pub_core_aspacemgr.h
coregrind/pub_core_debuginfo.h
coregrind/pub_core_initimg.h
coregrind/pub_core_mach.h [new file with mode: 0644]
coregrind/pub_core_machine.h
coregrind/pub_core_mallocfree.h
coregrind/pub_core_options.h
coregrind/pub_core_scheduler.h
coregrind/pub_core_syscall.h
coregrind/pub_core_syswrap.h
coregrind/pub_core_threadstate.h
coregrind/pub_core_trampoline.h
coregrind/pub_core_ume.h
coregrind/pub_core_vkiscnums.h
coregrind/vg_preloaded.c
darwin9.supp [new file with mode: 0644]
docs/internals/Darwin-notes.txt [new file with mode: 0644]
docs/internals/Makefile.am
drd/Makefile.am
drd/drd_main.c
drd/drd_pthread_intercepts.c
drd/tests/recursive_mutex.c
exp-omega/Makefile.am
exp-ptrcheck/Makefile.am
exp-ptrcheck/h_main.c
exp-ptrcheck/pc_main.c
exp-ptrcheck/tests/Makefile.am
glibc-2.34567-NPTL-helgrind.supp
helgrind/Makefile.am
helgrind/hg_intercepts.c
helgrind/hg_main.c
helgrind/tests/Makefile.am
helgrind/tests/tc20_verifywrap.c
include/pub_tool_basics.h
include/pub_tool_basics_asm.h
include/pub_tool_libcbase.h
include/pub_tool_libcfile.h
include/pub_tool_machine.h
include/pub_tool_redir.h
include/pub_tool_tooliface.h
include/pub_tool_vki.h
include/pub_tool_vkiscnums.h
include/valgrind.h
include/vki/Makefile.am
include/vki/vki-darwin.h [new file with mode: 0644]
include/vki/vki-scnums-darwin.h [new file with mode: 0644]
lackey/Makefile.am
massif/Makefile.am
massif/ms_main.c
massif/tests/malloc_usable.c
memcheck/Makefile.am
memcheck/mc_errors.c
memcheck/mc_machine.c
memcheck/mc_main.c
memcheck/mc_replace_strmem.c
memcheck/tests/Makefile.am
memcheck/tests/amd64/Makefile.am
memcheck/tests/badjump2.c
memcheck/tests/darwin/Makefile.am [new file with mode: 0644]
memcheck/tests/darwin/filter_stderr [new file with mode: 0644]
memcheck/tests/darwin/scalar.c [new file with mode: 0644]
memcheck/tests/darwin/scalar.h [new file with mode: 0644]
memcheck/tests/darwin/scalar.stderr.exp [new file with mode: 0644]
memcheck/tests/darwin/scalar.vgtest [new file with mode: 0644]
memcheck/tests/darwin/scalar_fork.c [new file with mode: 0644]
memcheck/tests/darwin/scalar_fork.stderr.exp [new file with mode: 0644]
memcheck/tests/darwin/scalar_fork.vgtest [new file with mode: 0644]
memcheck/tests/darwin/scalar_vfork.c [new file with mode: 0644]
memcheck/tests/darwin/scalar_vfork.stderr.exp [new file with mode: 0644]
memcheck/tests/darwin/scalar_vfork.vgtest [new file with mode: 0644]
memcheck/tests/linux/Makefile.am
memcheck/tests/malloc_usable.c
memcheck/tests/memalign2.c
memcheck/tests/origin1-yes.c
memcheck/tests/origin1-yes.stderr.exp
memcheck/tests/origin1-yes.stderr.exp-darwin [new file with mode: 0644]
memcheck/tests/sigkill.stderr.exp-darwin [new file with mode: 0644]
memcheck/tests/stack_changes.c
memcheck/tests/str_tester.c
memcheck/tests/strchr.stderr.exp-darwin [new file with mode: 0644]
memcheck/tests/x86/Makefile.am
none/Makefile.am
none/tests/Makefile.am
none/tests/amd64/Makefile.am
none/tests/darwin/Makefile.am [new file with mode: 0644]
none/tests/darwin/apple-main-arg.c [new file with mode: 0644]
none/tests/darwin/apple-main-arg.stderr.exp [new file with mode: 0644]
none/tests/darwin/apple-main-arg.vgtest [new file with mode: 0644]
none/tests/darwin/filter_stderr [new file with mode: 0644]
none/tests/darwin/rlimit.c [new file with mode: 0644]
none/tests/darwin/rlimit.stderr.exp [new file with mode: 0644]
none/tests/darwin/rlimit.vgtest [new file with mode: 0644]
none/tests/pth_atfork1.c
none/tests/x86/Makefile.am
tests/Makefile.am
tests/arch_test.c
tests/asm.h
tests/filter_libc
tests/malloc.h
tests/os_test.c
tests/platform_test
tests/sys_mman.h
tests/x86_amd64_features.c

index 57ab3e20ff54c62090f469031c2d2a4ffc9ca0ee..010620922b17bb57223a43982f79583383c61ec8 100644 (file)
@@ -15,6 +15,22 @@ TOOLS =              memcheck \
 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 @@ SUPP_FILES = \
        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 @@ endif
 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 @@ default.supp: $(DEFAULT_SUPP_FILES)
 
 ## 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
index e5ba1180972d80a2377b5279b8d5293213219d8e..493e8c36909d410f5df5dcb9e5272d91891b8dbc 100644 (file)
@@ -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 @@ inplace-noinst_PROGRAMS:
          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 @@ install-noinst_PROGRAMS:
          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
+
+
+
index dc09cab4269571b69b644032397462d770b7ba24..322c8fb24449d3b3fa776b708407c8a333ad4776 100644 (file)
@@ -10,7 +10,12 @@ AM_CFLAGS_BASE = -O2 -g -Wmissing-prototypes -Wall -Wshadow \
 # 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_CFLAGS_PPC64_AIX5      = @FLAG_MAIX64@ -mcpu=powerpc64 $(AM_CFLAGS_BASE)
 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 @@ endif
 #
 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
index b81d3e5837ff58073568dd491850b3766a1b1213..9694f064a4c8666b688da5631c60806530cb850a 100644 (file)
@@ -16,3 +16,25 @@ AM_CXXFLAGS = -Winline -Wall -Wshadow -g
 # 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  
index 08127286a62b963ac734bbfda7bdafbc30d561f7..21925fca4211a7fe65be456746ccfb24656c3ed9 100644 (file)
@@ -24,6 +24,12 @@ LIBREPLACEMALLOC_PPC32_AIX5 = \
 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 @@ COREGRIND_LIBS_PPC64_AIX5 = \
        $(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 @@ COREGRIND_LIBS_PPC64_AIX5 = \
        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 @@ TOOL_LDFLAGS_COMMON_LINUX = -static \
        -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_LDADD_PPC64_AIX5 = $(COREGRIND_LIBS_PPC64_AIX5) $(TOOL_LDADD_COMMON)
 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_PPC32_AIX5 = \
 LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5 = \
        $(LIBREPLACEMALLOC_PPC64_AIX5)
 
+LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN = \
+       $(LIBREPLACEMALLOC_X86_DARWIN)
+
+LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN = \
+       $(LIBREPLACEMALLOC_AMD64_DARWIN)
+
+
+
+all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
 
-all-local: inplace-noinst_PROGRAMS
+clean-local: clean-noinst_DSYMS
 
-install-exec-local: install-noinst_PROGRAMS
+install-exec-local: install-noinst_PROGRAMS install-noinst_DSYMS
 
diff --git a/NEWS b/NEWS
index 757b22043e438f33c5fdff962c00db48e2695907..332abab8436456f0759a6a4f0b07a5c72805b2af 100644 (file)
--- 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
index 7145df75290189c8531425512d2109b84dc69102..df59b7429a7a76dff64d98e0d33eec19c1162db9 100644 (file)
@@ -27,7 +27,6 @@ valgrind_listener_LDFLAGS   = $(AM_CFLAGS_PRI)
 #
 #----------------------------------------------------------
 
-
 #------------------------- mpi wrappers -----------------------
 # Build libmpiwrap.so for the primary target, and for the secondary
 # target if relevant.
@@ -50,12 +49,19 @@ if VGCONF_OS_IS_AIX5
  HACKY_FLAGS_SEC = -g -O -bE:libmpiwrap_aix5.exp -bM:SRE -bnoentry \
                        -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 @@ clean-local:
        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
 
 #
 #----------------------------------------------------------
index eac282558b920946f780411e81276fc62a222060..f165e8dc854aa739e99a6f58b531df37c281a9d2 100644 (file)
@@ -23,6 +23,12 @@ endif
 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_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5)
 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)
index 279356bd5e102958dea1019ee2dab7aa7cb4182c..6c4e1e4712dbcd8138bcf69bc60119aad8442a92 100644 (file)
@@ -1464,13 +1464,14 @@ static void cg_fini(Int exitcode)
    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);
index 497ee1977b701b043d6811972c0e0d882fc81bfe..f7f12a71c0288f3278271b3f65a165f4a6268c76 100644 (file)
@@ -25,5 +25,9 @@ AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
 # 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
index ac1720c492e7ad353756fc60c6cd851040306419..bc983b6eddf3e2d4d74fd955cc1dc32d9dc4bbcd 100644 (file)
@@ -23,6 +23,12 @@ endif
 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_CFLAGS       = $(CALLGRIND_CFLAGS_COMMON) $(AM_CFLAGS_PPC64
 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)
index 1e3892fc568687b3e3a77c5ad6f771460b416fb9..e6657df6c29c2ab350542d5e6c9a94436931d5c3 100644 (file)
@@ -62,6 +62,7 @@ AC_PROG_CC
 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 @@ fi
 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 @@ case "${host_os}" in
         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 @@ case "$ARCH_MAX-$VGCONF_OS" in
         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 @@ esac
 # 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 @@ AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC32_LINUX,
                  -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_LINUX,
 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 @@ fi
 # 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 @@ AC_EGREP_CPP([AIX5_LIBC], [
 ],
 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 @@ case "${GLIBC_VERSION}" in
        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
 
@@ -1340,6 +1426,14 @@ AC_DEFINE([HAVE_TLS], 1, [can use __thread to define thread-local variables])
 fi
 
 
+#----------------------------------------------------------------------------
+# 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 @@ AC_CHECK_FUNCS([     \
         memchr       \
         memset       \
         mkdir        \
+        mremap       \
         ppoll        \
         pthread_barrier_init       \
         pthread_condattr_setclock  \
@@ -1738,6 +1833,7 @@ AC_OUTPUT(
    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 @@ AC_OUTPUT(
    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
index 0839b856de028543ccdd3e2f8f52775aa9b994af..1bcfec7ff829906656731f3d8162cea2e9251b91 100644 (file)
@@ -7,29 +7,40 @@ include $(top_srcdir)/Makefile.all.am
 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 @@ pkglib_LIBRARIES += libcoregrind-ppc64-aix5.a libreplacemalloc_toolpreload-ppc64
 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 @@ valgrind_SOURCES = \
        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 @@ no_op_client_for_valgrind_LDFLAGS   = $(AM_CFLAGS_PRI)
 
 
 noinst_HEADERS = \
+       $(mach_hdrs) \
        launcher-aix5-bootblock.h \
        pub_core_aspacehl.h     \
        pub_core_aspacemgr.h    \
@@ -129,6 +195,7 @@ noinst_HEADERS = \
        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 @@ noinst_HEADERS = \
        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 @@ noinst_HEADERS = \
        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 @@ COREGRIND_SOURCES_COMMON = \
        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 @@ COREGRIND_AIX5_SOURCE = \
        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_CFLAGS = $(AM_CFLAGS_PPC64_AIX5)
 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_CPPFLAGS = $(AM_CPPFLAGS_PPC64_AIX5)
 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_CPPFLAGS = $(AM_CPPFLAGS_PPC64_AIX5)
 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)
+
+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-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 (file)
index 0000000..a470cf1
--- /dev/null
@@ -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);
+}
index 62c21dab61904953f57605e2d1953fed1f1cffb4..b8a7dd8b97bbc7eed5e6868881360a6bcb2b8c5e 100644 (file)
@@ -160,6 +160,18 @@ SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot,
         || 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 @@ SysRes ML_(am_do_munmap_NO_NOTIFY)(Addr start, SizeT length)
    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 @@ SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)(
 #  endif
 }
 
+#endif
+
 /* --- Pertaining to files --- */
 
 SysRes ML_(am_open) ( const Char* pathname, Int flags, Int mode )
@@ -257,6 +274,8 @@ Int ML_(am_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
@@ -310,6 +329,17 @@ Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf )
    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
index 4f09b67922b591d8677305d87ff0f9c3c2d5cfba..0af3bb5f23269303ba122b3bda4a894cf02df2ac 100644 (file)
@@ -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 @@ static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
    /* 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 @@ static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
          = 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 @@ static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot,
       /* 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 @@ static void sync_check_gap_callback ( Addr addr, SizeT len )
    /* 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 @@ static void read_maps_callback ( Addr addr, SizeT len, UInt prot,
    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 @@ Addr VG_(am_startup) ( Addr sp_at_startup )
    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 @@ Addr VG_(am_startup) ( Addr sp_at_startup )
    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));
@@ -2089,6 +2130,12 @@ Bool VG_(am_notify_munmap)( Addr start, SizeT len )
 
 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;
@@ -2116,6 +2163,7 @@ SysRes VG_(am_mmap_file_fixed_client)
    /* 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 @@ SysRes VG_(am_mmap_file_fixed_client)
       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 @@ SysRes VG_(am_mmap_anon_fixed_client) ( Addr start, SizeT length, UInt prot )
    /* 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 @@ SysRes VG_(am_mmap_anon_float_client) ( SizeT length, Int prot )
    /* 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 @@ SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
    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 @@ SysRes VG_(am_mmap_anon_float_valgrind)( SizeT length )
       (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 @@ Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg,
         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 @@ Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg,
         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 @@ Bool VG_(am_extend_into_adjacent_reservation_client) ( NSegment* seg,
 
 /* --- --- --- 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 @@ Bool VG_(am_relocate_nooverlap_client)( /*OUT*/Bool* need_discard,
    return True;
 }
 
+#endif // HAVE_MREMAP
+
+
+#if HAVE_PROC
 
 /*-----------------------------------------------------------------*/
 /*---                                                           ---*/
@@ -3192,6 +3276,202 @@ static void parse_procselfmaps (
       (*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 (file)
index 0000000..6b18f32
--- /dev/null
@@ -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 (file)
index 0000000..3618113
--- /dev/null
@@ -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
+}
index de28e363307203f80eef439e4df5574f22de81fb..1bc9fe5f1b9df304e3cc26e027c4ce5780f89e94 100644 (file)
@@ -211,6 +211,12 @@ static Int ptrace_setregs(Int pid, VexGuestArchState* vex)
 #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
index f561c4cd50694b1733b956f3d3c2bbdfd23a5a72..055f81468413b1725b195daec90d7ed7babb1757 100644 (file)
@@ -379,10 +379,10 @@ static Long read_leb128S( UChar **data )
 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)
index d9d921777133dd5d5f949f262c65db416b5b9a7d..4ec85c802a60527c6c7f8bbeb4a89bdaf89f14b9 100644 (file)
@@ -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 @@ void VG_(di_initialise) ( void )
 /*---                                                        ---*/
 /*--------------------------------------------------------------*/
 
-#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 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
    */
    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 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
    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 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV )
    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_munmap)( Addr a, SizeT len )
 void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
 {
    Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
-#  if defined(VGP_x86_linux)
+#  if defined(VGA_x86)
    exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
 #  endif
    if (0 && !exe_ok) {
@@ -1383,6 +1399,9 @@ Vg_FnNameKind VG_(get_fnname_kind) ( Char* name )
        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 @@ VgSectKind VG_(seginfo_sect_kind)( /*OUT*/UChar* name, SizeT n_name,
 
 }
 
-
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/priv_readmacho.h b/coregrind/m_debuginfo/priv_readmacho.h
new file mode 100644 (file)
index 0000000..e9da383
--- /dev/null
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
index 9749b247299c35f52e748e970bd24423a788be04..f6e6e82b02ccebfdee585510ccd67f34c2b4c5fc 100644 (file)
@@ -619,6 +619,12 @@ void ML_(addLineInfo) ( struct _DebugInfo* di,
                         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 );
 
index 30df436dc948cc6676d1b8758e680aef240d24e5..69000e63e8a32aa9e0a9c89734b960257820c84a 100644 (file)
@@ -1785,6 +1785,14 @@ void ML_(read_debuginfo_dwarf1) (
 #  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
index d8eed6a19bc770f6d233bac402a4cf23ff7baddb..d94b17dea13bc1d1e675ea035ee0552ef3d6b8f4 100644 (file)
 #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 @@ ML_(new_dwarf3_reader) (
    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 (file)
index 0000000..76293ad
--- /dev/null
@@ -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 ---*/
+/*--------------------------------------------------------------------*/
index 5bb9ac2d248446cedef4960b4cae8976b60aa89f..72de81dd842ea34c7b6460993b6b8df086b02153 100644 (file)
 #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 --- !!! --- */
 
 /*------------------------------------------------------------*/
index 343cf3b12aa5af6312fa65cb6564295142ecc859..f8d0834c85060aa4c1923bde7a06c07aa6850b12 100644 (file)
@@ -229,6 +229,24 @@ void ML_(addSym) ( struct _DebugInfo* di, DiSym* sym )
 }
 
 
+/* 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 @@ static void addLoc ( struct _DebugInfo* di, DiLoc* loc )
 }
 
 
+/* 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 @@ static DiSym* prefersym ( struct _DebugInfo* di, DiSym* a, DiSym* b )
 
 #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 @@ static DiSym* prefersym ( struct _DebugInfo* di, DiSym* a, DiSym* b )
    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 @@ static void canonicaliseSymtab ( struct _DebugInfo* di )
       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++] 
index 431e04e0990ebf6546212b6090295b1a1a392ff4..06f6988bb43dae48c524e323e1454eabb412d464 100644 (file)
 /* 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 @@ static UInt local_sys_getpid ( void )
    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 (file)
index 0000000..bc095e4
--- /dev/null
@@ -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 (file)
index 0000000..11956a8
--- /dev/null
@@ -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 (file)
index 0000000..13da3bc
--- /dev/null
@@ -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));
+}
index 8dbded319e70487800b5da9fb69d36e0fe623389..b6bdbbee3d7e9f19e18bce48a8e8c3a051fd36d1 100644 (file)
@@ -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 @@ void VG_(exit)( Int status )
 {
 #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
index 42aba3e687229fef479fc6447ea5e2f03e8de557..3614b9202bdc11fd89d4aa4a8a8a335ca12cf3a4 100644 (file)
@@ -155,6 +155,15 @@ double VG_(strtod) ( Char* str, Char** endptr )
    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_(strcmp) ( const Char* s1, const Char* s2 )
    }
 }
 
+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_(strncmp) ( const Char* s1, const Char* s2, SizeT nmax )
    }
 }
 
+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_(strstr) ( const Char* haystack, Char* needle )
    }
 }
 
+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) {
index 9cddfc0058a437069d6536ef1de959093396a8c7..72a9ea624d25122cf5ef51a934bf2f800927d66c 100644 (file)
 #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 @@ Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
    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 @@ Bool VG_(resolve_filename) ( Int fd, HChar* buf, Int n_buf )
 
 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_(read) ( Int fd, void* buf, Int count)
 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 @@ Int VG_(pipe) ( Int fd[2] )
 #  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 @@ Int VG_(pipe) ( Int fd[2] )
 
 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 VG_(stat) ( const Char* file_name, struct vg_stat* vgbuf )
    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 @@ Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf )
    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_(dup) ( Int oldfd )
 
 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 @@ SysRes VG_(dup2) ( Int oldfd, Int newfd )
 /* 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 @@ Bool VG_(record_startup_wd) ( void )
         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 @@ Int VG_(getdents) (Int fd, struct vki_dirent *dirp, UInt count)
    /* 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 @@ Int VG_(check_executable)(/*OUT*/Bool* is_setuid,
    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 @@ SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
       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 @@ UShort VG_(ntohs) ( UShort x )
 */
 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 @@ Int VG_(socket) ( Int domain, Int type, Int protocol )
 #  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 @@ Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
 #  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 my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen )
 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 @@ Int VG_(write_socket)( Int sd, void *msg, Int count )
 #  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 @@ Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
 #  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 @@ Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
 #  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 @@ Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
 #  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                                                          ---*/
 /*--------------------------------------------------------------------*/
index 86ebd23a714198af2325723db7da451943dc85a8..1c02ba4ef1b79feb08984a2de5a24aa9ff239115 100644 (file)
 #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 @@ static void mash_colon_env(Char *varp, const Char *remove_pattern)
 // 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 @@ void VG_(env_remove_valgrind_env_stuff)(Char** envp)
    // 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 @@ void VG_(env_remove_valgrind_env_stuff)(Char** envp)
 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 @@ Int VG_(gettid)(void)
    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 @@ Int VG_(getgroups)( Int size, UInt* list )
    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 @@ Int VG_(fork) ( void )
       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 @@ UInt VG_(read_millisecond_timer) ( void )
    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 @@ void VG_(do_atfork_child)(ThreadId tid)
          (*atforks[i].child)(tid);
 }
 
+
 /*--------------------------------------------------------------------*/
 /*--- end                                                          ---*/
 /*--------------------------------------------------------------------*/
index cd79b19a6aa51d7a1f4def91c454d59af89cd6b1..50aa2a8ef9e54655b4faf9be4125bbbf810e153a 100644 (file)
 #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 @@ Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
                                  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 @@ Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset)
 }
 
 
+#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 @@ Int VG_(sigaction) ( Int signum,
                                  _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 @@ VG_(convert_sigaction_fromK_to_toK)( vki_sigaction_fromK_t* fromK,
 {
 #  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 @@ VG_(convert_sigaction_fromK_to_toK)( vki_sigaction_fromK_t* fromK,
 
 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 @@ Int VG_(tkill)( Int lwpid, Int signo )
       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 @@ Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
   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 (file)
index 0000000..cd6df6c
--- /dev/null
@@ -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 (file)
index 0000000..0b9aa96
--- /dev/null
@@ -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 (file)
index 0000000..7a85e41
--- /dev/null
@@ -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 (file)
index 0000000..b843834
--- /dev/null
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
index 0429bfe6f9d6ed2c42023f64ad9f79ae119ec355..e85b917c265dc4aaf8c5051f9dd5f56ad52fc13b 100644 (file)
@@ -98,6 +98,8 @@ void VG_(set_syscall_return_shadows) ( ThreadId tid,
    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 @@ void VG_(machine_get_VexArchInfo)( /*OUT*/VexArch* pVa,
 // 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)
index e880e3c143ed054485d9e77e09e13e3ea8170ebb..f3dfbcd570dc25cdb9fa25a799329f9bfd22edf2 100644 (file)
@@ -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 @@ static Bool main_process_cmd_line_options( const HChar* toolname )
 
       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 @@ static void setup_file_descriptors(void)
       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);
@@ -1152,6 +1164,14 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
    /* This is needed to make VG_(getenv) usable early. */
    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
@@ -1228,10 +1248,29 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
    }
 #  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 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
       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 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
    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 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
    // 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 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
 
       VG_(cl_cmdline_fd) = fd;
    }
+#endif
 
    //--------------------------------------------------------------
    // Init tool part 1: pre_clo_init
@@ -1650,6 +1695,8 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
       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 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp )
 
      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 @@ void shutdown_actions_NORETURN( ThreadId tid,
       /* 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 @@ void shutdown_actions_NORETURN( ThreadId tid,
 /* 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 @@ static void final_tidyup(ThreadId tid)
    VG_(scheduler)(tid);
 
    vg_assert(VG_(is_exiting)(tid));
+#endif
 }
 
 
@@ -2585,6 +2656,59 @@ void getpass_auto         ( void ) { vg_assert(0); }
 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"
index 2a06fcd12de4df2c278fc30973dd0a64b6a5860e..089ed1d5b0fef67e435d8a1a728ec672a8b5812e 100644 (file)
@@ -90,6 +90,7 @@ Word   VG_(clo_main_stacksize) = 0; /* use client's rlimit.stack */
 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;
 
 
 /*====================================================================*/
index d31d90f7952e87d2eb41e70bd9041fbae53f95f2..d824a79a4258ec6a558df0770364ebbbc330c5f8 100644 (file)
@@ -940,6 +940,27 @@ void VG_(redir_initialise) ( void )
 #  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
index 5e2757bae7400a3b562fe58e11765770b37f00f5..b36e8028281f101afeed69b1f2eb33b6d55a0328 100644 (file)
@@ -144,6 +144,21 @@ static void init(void) __attribute__((constructor));
       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_LIBSTDCXX_SONAME, malloc,      malloc);
 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 @@ ALLOC_or_BOMB(VG_Z_LIBC_SONAME,       __builtin_new,  __builtin_new);
 #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 @@ ALLOC_or_BOMB(VG_Z_LIBC_SONAME,       __builtin_new,  __builtin_new);
 #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 @@ ALLOC_or_BOMB(VG_Z_LIBC_SONAME,       __builtin_vec_new, __builtin_vec_new );
 #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 @@ ALLOC_or_BOMB(VG_Z_LIBC_SONAME,       __builtin_vec_new, __builtin_vec_new );
 #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 @@ ALLOC_or_BOMB(VG_Z_LIBC_SONAME,       __builtin_vec_new, __builtin_vec_new );
 /* 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_LIBSTDCXX_SONAME,  free,                 free );
 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 @@ FREE(VG_Z_LIBC_SONAME,       _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
 
 /*---------------------- 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 @@ FREE(VG_Z_LIBC_SONAME,       _ZdaPvRKSt9nothrow_t, __builtin_vec_delete );
 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 @@ CALLOC(VG_Z_LIBC_SONAME, calloc_common);
 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 @@ REALLOC(VG_Z_LIBC_SONAME, realloc_common);
    }
 
 MEMALIGN(VG_Z_LIBC_SONAME, memalign);
+#if defined(VGO_darwin)
+ZONEMEMALIGN(VG_Z_LIBC_SONAME, malloc_zone_memalign);
+#endif
 
 
 /*---------------------- valloc ----------------------*/
@@ -454,7 +554,23 @@ static int local__getpagesize ( void ) {
                 ((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 @@ POSIX_MEMALIGN(VG_Z_LIBC_SONAME, memalign_common);
    }
 
 MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size);
+MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_size);
 
 
 /*---------------------- (unimplemented) ----------------------*/
@@ -623,6 +740,58 @@ MALLOC_STATS(VG_Z_LIBC_SONAME, malloc_stats);
 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)
index dfcab13effe2563cba932b346283d951c04c133f..6693e88a32a84ffc57c7b7fdf5f99d41228ba1ab 100644 (file)
 
 /* 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
 
index f1177ba12371926e064dcbad9345bcad600edaa6..d0d17e6c9d8f0058f5c311fe583c5215e2ef7f39 100644 (file)
@@ -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 @@ HChar* name_of_sched_event ( UInt event )
       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 @@ void VG_(acquire_BigLock)(ThreadId tid, HChar* who)
    /* 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 @@ void VG_(release_BigLock)(ThreadId tid, ThreadStatus sleepstate, HChar* who)
 
    /* 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 @@ void VG_(exit_thread)(ThreadId tid)
    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 @@ void VG_(get_thread_out_of_syscall)(ThreadId tid)
    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 @@ static void os_state_clear(ThreadState *tst)
 {
    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 @@ static void sched_fork_cleanup(ThreadId me)
    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 @@ static void sched_fork_cleanup(ThreadId me)
    /* 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_tt_miss ( ThreadId tid )
    }
 }
 
-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 @@ static void handle_syscall(ThreadId tid)
    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 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
         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 @@ VgSchedReturnCode VG_(scheduler) ( ThreadId tid )
 #        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 @@ void scheduler_sanity ( ThreadId tid )
       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. */
index 22b46765a1dad9ac8e531eba32bdd041a866632d..ed84505a073234c92195b533c673bdb3932b58df 100644 (file)
@@ -87,7 +87,7 @@ void ML_(sema_deinit)(vg_sema_t *sema)
 }
 
 /* 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 @@ void ML_(sema_down)(vg_sema_t *sema)
    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 (file)
index 0000000..4c8bc92
--- /dev/null
@@ -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 (file)
index 0000000..698d940
--- /dev/null
@@ -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 ---*/
+/*--------------------------------------------------------------------*/
index c5b4b10dbf6c72a1ca3f040248b43c02651d3406..43c9aecf98db2ee80ef20d1dcc6fc0f00879441c 100644 (file)
@@ -423,6 +423,82 @@ typedef struct SigQueue {
       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 @@ typedef struct SigQueue {
 #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 @@ extern void my_sigreturn(void);
    ".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 @@ static void handle_SCSS_change ( Bool force_update )
 
       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 @@ static void handle_SCSS_change ( Bool force_update )
                  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 @@ static void handle_SCSS_change ( Bool force_update )
                    == 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 @@ SysRes VG_(do_sys_sigaction) ( Int signo,
       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 @@ SysRes VG_(do_sys_sigaction) ( Int signo,
       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 @@ static const Char *signame(Int sigNo)
 /* 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 @@ void VG_(kill_self)(Int sigNo)
    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 @@ void VG_(kill_self)(Int sigNo)
 // 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 @@ static Bool is_signal_from_kernel(int si_code)
    // 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 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid)
    }
 
    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 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid)
               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 @@ static void default_action(const vki_siginfo_t *info, ThreadId tid)
          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 @@ void VG_(synth_sigtrap)(ThreadId tid)
 {
    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 @@ void VG_(synth_sigtrap)(ThreadId tid)
                                           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 @@ static int sanitize_si_code(int si_code)
       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 @@ void async_signalhandler ( Int sigNo,
       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 Bool extend_stack_if_appropriate(ThreadId tid, vki_siginfo_t* info)
    }
 }
 
-
 static
 void sync_signalhandler_from_kernel ( ThreadId tid,
          Int sigNo, vki_siginfo_t *info, struct vki_ucontext *uc )
@@ -2140,7 +2290,7 @@ void sync_signalhandler ( Int sigNo,
 
    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 @@ void pp_ksigaction ( vki_sigaction_toK_t* sa )
    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 @@ void VG_(set_default_handler)(Int signo)
 
    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 @@ void VG_(sigstartup_actions) ( void )
       /* 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 @@ void VG_(sigstartup_actions) ( void )
 
         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 @@ void VG_(sigstartup_actions) ( void )
       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))
index edfaf731aa9d87476addac982266d6fdf4a41413..6e3c8d07e4f07644ed6fa8081aec5c9a527c519a 100644 (file)
@@ -101,6 +101,9 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
    /* 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 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
       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 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known,
       break;
    }
 
-#  elif defined(VGP_amd64_linux)
+#  elif defined(VGP_amd64_linux)  ||  defined(VGP_amd64_darwin)
 
    /*--------------------- amd64 ---------------------*/
 
@@ -551,7 +555,6 @@ void VG_(get_and_pp_StackTrace) ( ThreadId tid, UInt max_n_ips )
    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 (file)
index 0000000..e414a26
--- /dev/null
@@ -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 (file)
index 0000000..57b49d0
--- /dev/null
@@ -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
index 0970e6b837356dfb089d1fe35823987386e07cde..3a74a89b425c583956c60e24eabf6d7e3e652988 100644 (file)
@@ -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 @@ SysRes VG_(mk_SysRes_Success) ( UWord res ) {
 }
 
 
+#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 @@ static void do_syscall_WRK ( UWord* res_r3, UWord* res_r4,
    *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 @@ SysRes VG_(do_syscall) ( UWord sysno, UWord a1, UWord a2, UWord a3,
    }
    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 (file)
index 0000000..bc85706
--- /dev/null
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
index 7c4fc5242ced9c821aa69268db90f6e3615208e5..e4b87b3ec3c5055134541711c6603e7b144d0c03 100644 (file)
 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
 
 /*--------------------------------------------------------------------*/
index 45536b8968a8b62b32a6ce1dca917f72daab8ff4..c481b8fc319d2806f023b000302c3a4a917b0be8 100644 (file)
@@ -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 @@ typedef
 
 /* 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 @@ typedef
 /* 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 @@ typedef
       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 @@ typedef
 */
 
 
-#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 @@ SyscallTableEntry* ML_(get_ppc64_aix5_syscall_entry) ( UInt sysno );
     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 @@ static inline UWord getERR ( SyscallStatus* st ) {
 /* 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 @@ static inline UWord getERR ( SyscallStatus* st ) {
 #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 @@ static inline UWord getERR ( SyscallStatus* st ) {
 #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 (file)
index 0000000..099a94e
--- /dev/null
@@ -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 (file)
index 0000000..41cc27e
--- /dev/null
@@ -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 (file)
index 0000000..714a755
--- /dev/null
@@ -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 (file)
index 0000000..49b8a9a
--- /dev/null
@@ -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 ---*/
+/*--------------------------------------------------------------------*/
index 67a662812a0675276e3a9b1097beeee097c640a8..a34ccb931a94fa5ee54c01a74c2e210d383e0410 100644 (file)
@@ -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 @@ ML_(notify_core_and_tool_of_mprotect) ( Addr a, SizeT len, Int prot )
 
 
 
+#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 @@ SysRes do_mremap( Addr old_addr, SizeT old_len,
 
 #  undef MIN_SIZET
 }
+#endif /* HAVE_MREMAP */
 
 
 /* ---------------------------------------------------------------------
@@ -759,6 +762,7 @@ void init_preopened_fds_without_proc_self_fd(void)
 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 @@ void VG_(init_preopened_fds)(void)
   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 @@ static void check_cmsg_for_fds(ThreadId tid, struct vki_msghdr *msg)
    }
 }
 
+/* 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 @@ void pre_mem_read_sockaddr ( ThreadId tid,
       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 @@ ML_(generic_PRE_sys_semctl) ( ThreadId tid,
    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 @@ ML_(generic_PRE_sys_semctl) ( ThreadId tid,
       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 @@ ML_(generic_POST_sys_semctl) ( ThreadId tid,
    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 @@ ML_(generic_PRE_sys_shmctl) ( ThreadId tid,
 {
    /* 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 @@ ML_(generic_POST_sys_shmctl) ( ThreadId tid,
                                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 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid,
    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 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid,
 #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_exit)
 
 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(sys_getitimer)
    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 @@ PRE(sys_madvise)
                  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 @@ PRE(sys_mremap)
       do_mremap((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid) 
    );
 }
+#endif /* HAVE_MREMAP */
 
 PRE(sys_nice)
 {
@@ -2811,9 +2906,17 @@ PRE(sys_fork)
 
    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 @@ PRE(sys_fork)
       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 @@ static void common_post_getrlimit(ThreadId tid, UWord a1, UWord a2)
 {
    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 @@ PRE(sys_gettimeofday)
    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 @@ PRE(sys_mprotect)
    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 @@ PRE(sys_mprotect)
          SET_STATUS_Failure( VKI_EINVAL );
       }
    }
+#endif   // defined(VKI_PROT_GROWSDOWN)
 }
 
 POST(sys_mprotect)
@@ -3412,6 +3524,7 @@ PRE(sys_open)
    }
    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 @@ PRE(sys_open)
          return;
       }
    }
+#endif // HAVE_PROC
 
    /* Otherwise handle normally */
    *flags |= SfMayBlock;
@@ -3558,6 +3672,7 @@ PRE(sys_readlink)
    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 @@ PRE(sys_readlink)
          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_setreuid)
 
 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 @@ PRE(sys_setrlimit)
          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 @@ PRE(sys_setrlimit)
          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(sys_utimes)
       PRE_timeval_READ( "utimes(tvp[0])", ARG2 );
       PRE_timeval_READ( "utimes(tvp[1])", ARG2+sizeof(struct vki_timeval) );
    }
-
 }
 
 PRE(sys_acct)
index cc6166b95ce9dec7c465345147bab0591d080001..8238cb5e92d5227f250c53a76c9be625bf2294af 100644 (file)
@@ -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:
    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
      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 @@ UWord ML_(do_syscall_for_client_WRK)( Word syscallno,
                                       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 @@ void do_syscall_for_client ( Int syscallno,
             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 @@ Bool eq_SyscallStatus ( SyscallStatus* s1, SyscallStatus* s2 )
    /* 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 @@ SyscallStatus convert_SysRes_to_SyscallStatus ( SysRes res )
 
 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 @@ void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs*       canonical,
    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 @@ void putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs*       canonical,
    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 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus*     canonical,
                                                 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 @@ void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
    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 @@ void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout )
    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 @@ void bad_before ( ThreadId              tid,
                   /*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 @@ void bad_before ( ThreadId              tid,
 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 @@ static const SyscallTableEntry* get_syscall_entry ( UInt syscallno )
 #  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 @@ static void ensure_initialised ( void )
 
 /* --- 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 @@ void VG_(client_syscall) ( ThreadId tid )
    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 @@ void VG_(client_syscall) ( ThreadId tid )
       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 @@ void VG_(client_syscall) ( ThreadId tid )
         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 @@ void VG_(client_syscall) ( ThreadId tid )
 
          /* 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 @@ void VG_(client_syscall) ( ThreadId tid )
             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 @@ void VG_(client_syscall) ( ThreadId tid )
          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 @@ void VG_(client_syscall) ( ThreadId tid )
    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 @@ void VG_(post_syscall) (ThreadId tid)
    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 @@ void VG_(post_syscall) (ThreadId tid)
   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 @@ void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch )
       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 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
       = 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 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid,
 }
 
 
+#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 (file)
index 0000000..5532033
--- /dev/null
@@ -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 ---*/
+/*--------------------------------------------------------------------*/
index d267172b73c9806155f50c45c78660a4ecf618d6..e52076dd0bea03d57c711d15936992f45208ab3e 100644 (file)
@@ -735,7 +735,307 @@ VG_(trampoline_stuff_end):
 #      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 @@ VG_(trampoline_stuff_end):
 #endif
 #endif
 #endif
+#endif
+#endif
 
 #if defined(VGO_linux)
 /* Let the linker know we don't need an executable stack */
index ea7ec468ba2ba07633f895b8f94c6739179d296a..1e1f049d5f45cf3f376656cc58bd38ec33b77967 100644 (file)
@@ -708,6 +708,14 @@ static Bool translations_allowable_from_seg ( NSegment const* seg )
 
 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 @@ Bool VG_(translate) ( ThreadId tid,
 #  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;
index f7719605cfd13d9cd6e18549c803023c761d695f..8dfbb1f05e0ce35f8f68c9107c52f1aabf2b1494 100644 (file)
@@ -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 (file)
index 0000000..db5db4f
--- /dev/null
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
+
index a32bec7ee5647fce4a11ce78b85f30649e1693ef..1673fc9809ca62e87c56f5ff4be08012f03fded3 100644 (file)
@@ -58,6 +58,9 @@ static ExeHandler exe_handlers[] = {
 #  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]))
 
index ce5f09046ce2b2c4b701acdce2f5bdb534fe0a28..ca3f95bc1a8ef95a5f941f047b862a99017bed43 100644 (file)
@@ -42,6 +42,11 @@ extern Bool VG_(match_script) ( Char *hdr, Int len );
 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 */
 
 /*--------------------------------------------------------------------*/
index 25beafbf62520e200c43de9abcd3fc68b2e1a8ad..9a4c3ef1da98ff5586f60bfa4228833014a2d51e 100644 (file)
@@ -77,6 +77,12 @@ void VG_(vki_do_initial_consistency_checks) ( void )
 
 #  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 @@ void VG_(vki_do_initial_consistency_checks) ( void )
    /* 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" 
index c47120fc71b572ec6844e4e13da50c337a70e883..372b9237a50a6e21ed56d94d1490b1183eb1d75a 100644 (file)
@@ -120,7 +120,6 @@ extern void VG_(am_show_nsegments) ( Int logLevel, HChar* who );
 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 @@ extern Bool VG_(am_aix5_sbrk_allowed);
    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 VgStack* VG_(am_alloc_VgStack)( /*OUT*/Addr* initial_sp );
 
 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
 
index 6f1c944309c514c07e6de77053ec116880679ea9..b947af1e3d09439f271ce7d15f7f5f7f0486f289 100644 (file)
@@ -56,7 +56,7 @@ extern void VG_(di_initialise) ( void );
    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 @@ extern void VG_(di_notify_pdb_debuginfo)( Int fd, Addr avma,
 #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
index 9e9416b710096b47d8d3e9d6e785a0a737a23c75..4c4e09d012bda6151a5368cd24cbe23b03baa441 100644 (file)
@@ -60,7 +60,6 @@ IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo );
 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 @@ struct _IIFinaliseImageInfo {
    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 (file)
index 0000000..719df44
--- /dev/null
@@ -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                                                          ---*/
+/*--------------------------------------------------------------------*/
index 6b6734b0e7bf0d2c47f11868668a2f45ba953aca..be47cdc6f64fdd7b7e32e4a623ad89ef5eb747c7 100644 (file)
 #  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
index 5bf2088a70d10b3e3b1aacfd9a9d5f4525ed0db5..8229ec86b5e50572b04fab041c67e5c67a429aa3 100644 (file)
@@ -73,15 +73,18 @@ typedef Int ArenaId;
       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 {
index 486cf94fb501ae27a4c9e460deff2cd5c5c7e4e9..73f4a630b29337e62129f32674c18f6643a6de9b 100644 (file)
@@ -182,6 +182,10 @@ extern VgSmc VG_(clo_smc_check);
    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
index 029472b70df7d303edb8ea494c20aa850e0bdae1..b295a13ed75afe82c0d6a9ff3b4e1d9549ada921 100644 (file)
@@ -59,6 +59,11 @@ extern void VG_(nuke_all_threads_except) ( ThreadId me,
    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 @@ extern void VG_(acquire_BigLock) ( ThreadId tid, HChar* who );
    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 );
+
+/* Matching function to acquire_BigLock_LL. */
+extern void VG_(release_BigLock_LL) ( HChar* who );
 
-/* Yield the CPU for a while */
+/* Yield the CPU for a while.  Drops/acquires the lock using the
+   normal (non _LL) functions. */
 extern void VG_(vg_yield)(void);
 
 // The scheduler.
index b4fd04e815a9bb44e190f34f6203518db91e1666..aa1d68dc7780b488fb8a4fedd6fdd23aa480cf35 100644 (file)
@@ -75,6 +75,10 @@ extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt  val, UInt  cr0so );
 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 );
 
index 89f0d8cbb2d067a0765d4f914b6eed3c22d5d78c..43428f6b572366db64590759302f659012f29dca 100644 (file)
@@ -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 );
 
index e7bde55c562fd5bf4ec1f918586aa711c73888ea..51b4adf94b856f72662f1e3792c08767cf61ef41 100644 (file)
@@ -87,6 +87,9 @@ typedef
 #  error Unknown architecture
 #endif
 
+/* Forward declarations */
+struct SyscallStatus;
+struct SyscallArgs;
 
 /* Architecture-specific thread state */
 typedef 
@@ -120,7 +123,7 @@ typedef
 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 @@ typedef
            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 @@ extern ThreadState VG_(threads)[VG_N_THREADS];
 // to write to this.
 extern ThreadId VG_(running_tid);
 
+
 /*------------------------------------------------------------*/
 /*--- Basic operations on the thread table.                ---*/
 /*------------------------------------------------------------*/
index cbda7ab5715ae52c2073e7b3daf2d53e81bb692f..c8c652074448e4877b5546a261da8d56d2825ef4 100644 (file)
@@ -112,6 +112,16 @@ extern void VG_(ppctoc_magic_redirect_return_stub);
 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
 
 /*--------------------------------------------------------------------*/
index cf7b1ad33352d2a0dc7b45ebccbb6dbd932ebc14..b6e59e56b850d6bf0343cf2fd4663ff98ba19891 100644 (file)
 #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 @@ typedef
       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
index 4cedf375246da07fc29f6a325c8a00c9543e5b89..4ce09d8bda1823ded04a194b7e7a86316065cfcd 100644 (file)
    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_*)
index 353983274fb57a01a2ae2d43bbd4a51fcfd7a4d2..6f0f04916d1d87625efdec9b80941a10a04d1893 100644 (file)
@@ -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 @@ void VG_NOTIFY_ON_LOAD(freeres)( void )
    *(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 (file)
index 0000000..74c31e3
--- /dev/null
@@ -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 (file)
index 0000000..f526c4f
--- /dev/null
@@ -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.
index 1f82a67415194584b03d76822d12ed557eef6481..76fed0369fe36ceb075a75ea14860b07fcc8297d 100644 (file)
@@ -3,6 +3,7 @@ EXTRA_DIST = \
        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 \
index 18a8844dbb06c6d061ff8ea1bbdec9b36771ffb3..84655f236937ac4dea0e38cf12aa43f5726991b7 100644 (file)
@@ -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 @@ endif
 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_DEPENDENCIES =
 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_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5)
 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)
+
+
index 0dfb00afed5a1cc8dcadab1fa44cf9fb920cbf19..3cc6348ffd27442c856bd779eeff896aa141dab1 100644 (file)
@@ -607,8 +607,13 @@ static void DRD_(fini)(Int exitcode)
 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");
index f77569d5994af9b45d0dbd70e3f0a31f136d30b6..db33fbdcfede8e16f2f5b1458d61aeb69f1611a1 100644 (file)
@@ -643,6 +643,7 @@ PTH_FUNC(int, pthreadZucondZubroadcastZa, // pthread_cond_broadcast*
 }
 
 
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
 // pthread_spin_init
 PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
          pthread_spinlock_t *spinlock,
@@ -723,7 +724,10 @@ PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
                               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 @@ PTH_FUNC(int, pthreadZubarrierZuwait, // pthread_barrier_wait
                               ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
    return ret;
 }
+#endif   // HAVE_PTHREAD_BARRIER_INIT
 
 
 // sem_init
index ad79b63fd3c992a2ceab0f76bcf4752202dfe172..3ddfc253801f906598b30eeeecf59c9088b10031 100644 (file)
@@ -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 @@ static void lock_twice(pthread_mutex_t* const p)
   pthread_mutex_unlock(p);
   pthread_mutex_unlock(p);
 }
+#endif
 
 int main(int argc, char** argv)
 {
@@ -60,6 +62,10 @@ int main(int argc, char** argv)
     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 @@ int main(int argc, char** argv)
     lock_twice(&m);
   }
   printf("Done.\n");
+#endif
   return 0;
 }
index 6af2f3ff5ecb7477d8874aeb73c7723a3102d27a..122d8a69bee3e325e386b5daff411331d18fa6f4 100644 (file)
@@ -30,6 +30,12 @@ EXTRA_DIST = exp-omega.h o_main.c o_replace_memops.c
 ##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 @@ EXTRA_DIST = exp-omega.h o_main.c o_replace_memops.c
 ##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 @@ EXTRA_DIST = exp-omega.h o_main.c o_replace_memops.c
 ##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
index d4591e3dfe84d01773c251e11b9c79e6ec41259c..37b3ef55b806ae04e23ed3d5701e79d5d3097746 100644 (file)
@@ -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 @@ endif
 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 @@ vgpreload_exp_ptrcheck_ppc64_aix5_so_LDFLAGS      = \
        $(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_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 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 = 
index 50f4154cd5147a613a39b8b673783f2b3b9ffa7e..c4342a323b8ee7e1c2c0c7a00d7280b7bd014092 100644 (file)
@@ -1957,6 +1957,8 @@ static void post_reg_write_nonptr ( ThreadId tid, PtrdiffT offset, SizeT size )
    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 @@ void h_pre_syscall ( ThreadId tid, UInt sysno )
    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 @@ static void setup_post_syscall_table ( void )
       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 @@ void h_post_syscall ( ThreadId tid, UInt sysno, SysRes res )
    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 @@ void h_post_syscall ( ThreadId tid, UInt sysno, SysRes res )
    tl_assert(i >= 0 && i <= n);
 
    if (i == n) {
+// DDD: genericise this
+#     if defined(VGO_linux)
+      VG_(printf)("sysno == %u\n", sysno);
+#     elif defined(VGO_aix5)
       VG_(printf)("sysno == %u\n", sysno);
-#     if defined(VGO_aix5)
       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");
    }
index 1dfd9a5d7503a4d2c8d2e5939b4101b723517543..6f44bbfd3c7d313e7eb463966ee9684ee8828df8 100644 (file)
@@ -144,6 +144,12 @@ static void pc_post_clo_init ( void )
 
 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 "
index 5c27f35b950e5c78607e5a42dfc1f44489bd8c0f..6a1d884d3ab69cef5b33dea885bf4a0df244c21f 100644 (file)
@@ -65,7 +65,7 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        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 @@ check_PROGRAMS = \
        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)
 
@@ -97,12 +105,17 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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
@@ -111,9 +124,14 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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
 
index 0a4aeaa1ebf178fb659270256112af8f8b6f923d..616309edee7e1ef8b939eac72d81799de0b39f1f 100644 (file)
 {
    helgrind-glibc2X-112
    Helgrind:Race
+   fun:pthread_create_WRK
    fun:pthread_create@*
 }
 {
index 02f96bab19e9182830984cd65250722c164abea8..55379c2f91ddbab44ddb7561e7602e736331716d 100644 (file)
@@ -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 @@ endif
 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 @@ vgpreload_helgrind_ppc64_aix5_so_LDFLAGS      = \
        $(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_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 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
index 698a0829c221b739546ce3b3b4b060168c130d7b..47cb3af767f888cfb3d51496ad03d750ac03eceb 100644 (file)
@@ -195,9 +195,13 @@ static void* mythread_wrapper ( void* xargsV )
 }
 
 // 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 @@ PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
    }
    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 @@ PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
 /*--- pthread_barrier_t functions                              ---*/
 /*----------------------------------------------------------------*/
 
+#if defined(HAVE_PTHREAD_BARRIER_INIT)
+
 /* Handled:   pthread_barrier_init
               pthread_barrier_wait
               pthread_barrier_destroy
@@ -861,6 +877,8 @@ PTH_FUNC(int, pthreadZubarrierZudestroy, // pthread_barrier_destroy
    return ret;
 }
 
+#endif   // defined(HAVE_PTHREAD_BARRIER_INIT)
+
 /*----------------------------------------------------------------*/
 /*--- pthread_rwlock_t functions                               ---*/
 /*----------------------------------------------------------------*/
index 796d96693b14678a03c3f47bf18cfb192c1d3f5e..bff2fd59ebd85ece529f8aca4ab34c981b963638 100644 (file)
@@ -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 @@ ExeContext*  for_libhb__get_EC ( Thr* hbt )
 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");
index c594f3ba673ddd901e95ef102c980c1bbacc809e..5f68d4094fcf0191e202ccfdce2e3bfcf6365fd2 100644 (file)
@@ -92,10 +92,15 @@ check_PROGRAMS = \
        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
index 667aafa4476b966b17eb56a1a5028a5545cce7fa..6a8b30c379eae8a32017038af9b45fa4c4df340d 100644 (file)
@@ -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)"
index cda74ab6192e0f8d74e18166ef009cb329527348..734391c1d9b52e94e96dcbf1c59c65c18b72324d 100644 (file)
@@ -112,7 +112,15 @@ typedef  Word                 PtrdiffT;   // 32             64
 // - 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 @@ typedef
       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 @@ static inline Bool sr_EQ ( SysRes sr1, SysRes sr2 ) {
 #  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
index 201c1b5afa2d7301945b75cc27700dadf39dc490..42a8a3159913fa560953b45d263e159046977ba2 100644 (file)
 
 #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 */
 
index c2cab19269a20dc0c7c753a4fe71bb770f22d194..0460112517431200a922725c1680a9ec5096cc6f 100644 (file)
@@ -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_(strpbrk)        ( const Char* s, const Char* accpt );
 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 @@ extern Int   VG_(memcmp) ( const void* s1, const void* s2, SizeT n );
 #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))))
 
index 916b431b5f4cc88ad6c561b9052ccf92fa7a1bb5..5e04c96fb9e2d0eca4e168acd02a6eae0c5b05fd 100644 (file)
@@ -85,6 +85,9 @@ extern Int    VG_(unlink) ( const Char* file_name );
 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 );
index 7301d51358ca5b0dbc573fcc85b97aebbe8c7733..d7789a3fc07f0fe773db5b52a9f0730d4e32cada 100644 (file)
 #  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
index ca40bc4f5450ef415be12a7ad6002e4c314c3501..5a97bff622ec95e34f4b7f2b4cf572004c7dd490 100644 (file)
 #  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
 
 #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
 #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
 
 /*--------------------------------------------------------------------*/
index 3a7c391b394c7776761e7baedb8e18d45a9931bb..5b1725c2cef759309dc8a6647b564a217699b620 100644 (file)
@@ -439,8 +439,14 @@ extern void VG_(needs_final_IR_tidy_pass) ( IRSB*(*final_tidy)(IRSB*) );
    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
index 75da646be35f18575e977c7730bd555e73531173..f6c9792b912a7de1d98bc42504a751439dca7f9e 100644 (file)
@@ -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
index 061b36e586d23f2cf082bab14069beb89f8213d4..adb6cc0131f79757847be5b3968bd29c12fbe564 100644 (file)
    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
 /* 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
index 679f1591d4b3982bb2d1ed9d61139acabe8ab920..da2427486fd55a25ddbe80a9c34e2852492aa7fa 100644 (file)
 #undef PLAT_ppc32_aix5
 #undef PLAT_ppc64_aix5
 
-#if !defined(_AIX) && defined(__i386__)
+
+#if defined(_AIX) && defined(__64BIT__)
+#  define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+#  define PLAT_ppc32_aix5 1
+#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(_AIX) && defined(__x86_64__)
+#elif defined(__x86_64__)
 #  define PLAT_amd64_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__)
+#elif defined(__powerpc__) && !defined(__powerpc64__)
 #  define PLAT_ppc32_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__)
+#elif defined(__powerpc__) && defined(__powerpc64__)
 #  define PLAT_ppc64_linux 1
-#elif defined(_AIX) && defined(__64BIT__)
-#  define PLAT_ppc64_aix5 1
-#elif defined(_AIX) && !defined(__64BIT__)
-#  define PLAT_ppc32_aix5 1
-#endif
-
-
+#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
    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 @@ typedef
                      __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 @@ typedef
                      __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 @@ typedef
    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 @@ typedef
       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 @@ typedef
       lval = (__typeof__(lval)) _res;                             \
    } while (0)
 
-#endif /* PLAT_amd64_linux */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
 
 /* ------------------------ ppc32-linux ------------------------ */
 
index 137fe1d4ac87fe3d46c8fc911ad448faf3eecf54..81b40e58c1319d3b91cea64154aa40d0df02b236 100644 (file)
@@ -3,6 +3,7 @@ incincdir = $(includedir)/valgrind/vki
 
 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 @@ incinc_HEADERS = \
        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 (file)
index 0000000..cf5e542
--- /dev/null
@@ -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 (file)
index 0000000..281ccc3
--- /dev/null
@@ -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
index 69a1a82364ff2b4f453a9dc54d97de267e45aa9c..6a2ff3d95fe03d86405e8722cc527d85ae145a0a 100644 (file)
@@ -19,6 +19,12 @@ endif
 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_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5)
 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)
index 6ff1f51ab37dee2b8006bcd4d76f91f24f5b88e4..3033df1ebc30b917e713df143468412d2d695e5a 100644 (file)
@@ -5,6 +5,7 @@ SUBDIRS += perf
 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 @@ endif
 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 @@ vgpreload_massif_ppc64_aix5_so_LDFLAGS      = \
        $(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_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5)
 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)
index 318fc11ac89cf17a75b255b3cb71664200e1a5cf..f3d46feb9a8e45cc38fe73e3fbe63a0c90afb0fd 100644 (file)
@@ -1288,8 +1288,10 @@ static Time get_time(void)
 
 // 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 @@ take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time time,
 
    // Rest of snapshot.
    snapshot->kind = kind;
-   snapshot->time = time;
+   snapshot->time = my_time;
    sanity_check_snapshot(snapshot);
 
    // Update stats.
@@ -1341,12 +1343,14 @@ maybe_take_snapshot(SnapshotKind kind, Char* what)
 
    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 @@ maybe_take_snapshot(SnapshotKind kind, Char* what)
 
    // 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 @@ maybe_take_snapshot(SnapshotKind kind, Char* what)
    }
 
    // 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;
 }
 
 
index 4a0e470d8102f214d2f30ae2d63f852b63406e76..25781732a6a3d58dbf62ff998c844a2aae05ff18 100644 (file)
@@ -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);
index e042a6b6c0873bb1c0ba3a1686629b7cc7762cc9..e11e841444d87291e996c8754986a48648b86bae 100644 (file)
@@ -3,6 +3,7 @@ include $(top_srcdir)/Makefile.tool.am
 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 @@ endif
 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 @@ vgpreload_memcheck_ppc64_aix5_so_LDFLAGS      = \
        $(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_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
 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 = \
index e56a16311718a5dd372892eece3decafb4a160b8..edc123ae044499390797668aed8e00abab1d105d 100644 (file)
@@ -268,7 +268,7 @@ static void mc_pp_AddrInfo ( Addr a, AddrInfo* ai, Bool maybe_gcc )
          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 {
index 4072b8ada00dd85bbb23451aee5ba949854c0ee1..05f6da4f4e889e87ab80882129824187e6ba8458 100644 (file)
@@ -491,6 +491,7 @@ static Int get_otrack_shadow_offset_wrk ( Int offset, Int szB )
    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 */
 
index 8cf7a7bc6124df8d07b808f3c363814f6ddda86a..a6660ad4b44667602ee1d1531fc1133abd436f2a 100644 (file)
@@ -92,8 +92,9 @@ static void ocache_sarp_Clear_Origins ( Addr, UWord ); /* fwds */
 /* 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 @@ void check_mem_is_defined ( CorePart part, ThreadId tid, Char* s,
                                       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:
@@ -3696,11 +3701,20 @@ void check_mem_is_defined_asciiz ( CorePart part, ThreadId tid,
    }
 }
 
+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 @@ void mc_new_mem_startup( Addr a, SizeT len,
    // 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 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
    return True;
 }
 
+
 /*------------------------------------------------------------*/
 /*--- Crude profiling machinery.                           ---*/
 /*------------------------------------------------------------*/
index b7c30fc60f278a42bfe0fcef4b60b048f564d185..6c5e31bc87f6ae4bbe2aaae4f9a09f9380a091e4 100644 (file)
@@ -117,6 +117,9 @@ STRRCHR(VG_Z_LIBC_SONAME,   strrchr)
 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,        strchr)
 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 @@ STRCAT(VG_Z_LIBC_SONAME, strcat)
    }
 
 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 @@ STRLEN(VG_Z_LD_LINUX_X86_64_SO_2, strlen)
    }
 
 STRCPY(VG_Z_LIBC_SONAME, strcpy)
+#if defined(VGO_darwin)
+STRCPY(VG_Z_DYLD,        strcpy)
+#endif
 
 
 #define STRNCPY(soname, fnname) \
@@ -273,6 +327,40 @@ STRCPY(VG_Z_LIBC_SONAME, strcpy)
    }
 
 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 @@ STRNCPY(VG_Z_LIBC_SONAME, strncpy)
    }
 
 STRNCMP(VG_Z_LIBC_SONAME, strncmp)
+#if defined(VGO_darwin)
+STRNCMP(VG_Z_DYLD,        strncmp)
+#endif
 
 
 #define STRCMP(soname, fnname) \
@@ -338,6 +429,9 @@ STRCMP(VG_Z_LD64_SO_1,            strcmp)
    }
 
 MEMCHR(VG_Z_LIBC_SONAME, memchr)
+#if defined(VGO_darwin)
+MEMCHR(VG_Z_DYLD,        memchr)
+#endif
 
 
 #define MEMCPY(soname, fnname) \
@@ -389,6 +483,8 @@ MEMCPY(VG_Z_LIBC_SONAME, memcpy)
 #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, memcmp)
 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 @@ STPCPY(VG_Z_LIBC_SONAME,          stpcpy)
 #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 @@ STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
    }
 
 MEMSET(VG_Z_LIBC_SONAME, memset)
+#if defined(VGO_darwin)
+MEMSET(VG_Z_DYLD,        memset)
+#endif
 
 
 #define MEMMOVE(soname, fnname) \
@@ -507,6 +611,35 @@ MEMSET(VG_Z_LIBC_SONAME, memset)
    }
 
 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.
index b5be28db5d9ea28dfb38eeea5bbf69c7f4ef235c..96101cb66904681f8bf6d56880fc1c5dc452f8b2 100644 (file)
@@ -15,13 +15,16 @@ endif
 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 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        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 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        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 \
@@ -297,6 +301,10 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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) \
@@ -312,11 +320,17 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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
@@ -327,12 +341,17 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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
@@ -342,10 +361,16 @@ else
 if VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5
  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
 
index bb1c8032a40872d5d6c264707d28da9d2d46ea0f..5dedb0d23b1c1dc44bae87ff610502c893c77c74 100644 (file)
@@ -22,10 +22,18 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        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@
index d91283cda35d7558b95f263e47621d4edf70104a..a4ba8036ab41f59b4d9586621b24fa954975357a 100644 (file)
@@ -24,7 +24,7 @@ int main(void)
    /* 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 (file)
index 0000000..9d41756
--- /dev/null
@@ -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 (file)
index 0000000..0ae9313
--- /dev/null
@@ -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 (file)
index 0000000..2ee66ea
--- /dev/null
@@ -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 (file)
index 0000000..8bfd2e1
--- /dev/null
@@ -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 (file)
index 0000000..7b383cc
--- /dev/null
@@ -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 (file)
index 0000000..897d9e7
--- /dev/null
@@ -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 (file)
index 0000000..805ade8
--- /dev/null
@@ -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 (file)
index 0000000..e898498
--- /dev/null
@@ -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 (file)
index 0000000..e38fdf6
--- /dev/null
@@ -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 (file)
index 0000000..5f9cea8
--- /dev/null
@@ -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 (file)
index 0000000..32644bd
--- /dev/null
@@ -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 (file)
index 0000000..3ddad70
--- /dev/null
@@ -0,0 +1,2 @@
+prog: scalar_vfork
+vgopts: -q
index 81a2c9bd494b5be480dde56f2833a556ad702006..664ee632b798b7c0757ed0bbe8aca27fd48969bd 100644 (file)
@@ -22,3 +22,4 @@ AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 
 stack_switch_LDADD    = -lpthread
 timerfd_syscall_LDADD = -lrt
+
index 4e2d2a048dccf7fb6239c475c2437998ca22dc6b..ab57663a1b1fdc4108742ac5c47fa023d0ef00c6 100644 (file)
@@ -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);
index e163bf4ed77f7ec3466e923320700a70051923d2..a3aacfe85ef26cb2d9e09597d0950f88f02c9970 100644 (file)
@@ -22,6 +22,9 @@ int main ( void )
 #  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;
index acfd8aba78e536f6c1c9e02b0b7cb19cd2e0a6b6..3ebe6f0f4112425a422096b1deb8081ebbbe3cf4 100644 (file)
@@ -86,12 +86,21 @@ int main(void)
    }
 
    // 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
    {
index 418dcd0e6760072da5e2d12b1d93eacbf2697a91..e2af1abdca7ba3fd4a0da95ea56ff686bf7c743e 100644 (file)
@@ -45,18 +45,18 @@ Conditional jump or move depends on uninitialised value(s)
 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 (file)
index 0000000..add1a37
--- /dev/null
@@ -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 (file)
index 0000000..0e04bd8
--- /dev/null
@@ -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
index e9d57d0192b22099a28b40916d216db8d0aa7110..0d7438c147284fad9c99c758ff14fa4cd5f9b0cc 100644 (file)
@@ -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;
index 3c15ea7cab1b5961918ba985a727ce7c9c9d4c1e..7516696ee5ce20afe912c9df2fc942feb679483b 100644 (file)
@@ -264,6 +264,8 @@ test_stpcpy (void)
   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 @@ test_stpncpy (void)
   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 @@ test_strchr (void)
 }
 
 // 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 @@ test_strchrnul (void)
 #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 @@ test_strrchr (void)
 }
 
 // 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 @@ test_strsep (void)
   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 @@ test_memcpy (void)
     }
 }
 
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
 static void
 test_mempcpy (void)
 {
@@ -1276,6 +1279,7 @@ test_bzero (void)
   equal(one, "abcdef", 4);             /* Zero-length copy. */
 }
 
+#if !defined(__APPLE__)
 static void
 test_strndup (void)
 {
@@ -1299,6 +1303,7 @@ test_strndup (void)
     equal(p, "abc", 6);
   free (p);
 }
+#endif
 
 static void
 test_bcmp (void)
@@ -1382,8 +1387,10 @@ main (void)
   /* A closely related function is stpcpy.  */
   test_stpcpy ();
 
+#if !defined(__APPLE__)
   /* stpncpy.  */
   test_stpncpy ();
+#endif
 
   /* strcat.  */
   test_strcat ();
@@ -1403,12 +1410,12 @@ main (void)
   /* 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 @@ main (void)
   /* strrchr.  */
   test_strrchr ();
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* memrchr.  */
   test_memrchr ();
 # endif
@@ -1460,7 +1467,7 @@ main (void)
   /* memmove - must work on overlap.  */
   test_memmove ();
 
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
   /* mempcpy */
   test_mempcpy ();
 # endif
@@ -1480,8 +1487,10 @@ main (void)
   /* 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 (file)
index 0000000..8b870df
--- /dev/null
@@ -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)
index 28dd116fbd830d140b9723619c38213a603b92cb..2cd7b03bcb7102c1e4d9145e61d6c83bb5c73f23 100644 (file)
@@ -42,9 +42,15 @@ AM_CFLAGS    += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
 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
index ac47371f668b3f3be9ca7935bbb69ed659d8ce8d..34061af3f8bd3124a8c4a8348bf96968ba35b26a 100644 (file)
@@ -19,6 +19,12 @@ endif
 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_CFLAGS       = $(AM_CFLAGS_PPC64_AIX5)
 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)
index dfec0678c029a63e29467b559642988884f33580..1cc18afc0870c3dbb4b9b851fdccaa0766247bc9 100644 (file)
@@ -21,13 +21,16 @@ endif
 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 @@ check_PROGRAMS = \
        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 @@ check_PROGRAMS = \
        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 @@ AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
 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 @@ if VGCONF_OS_IS_AIX5
  res_search_LDADD       = -lpthread
 else
  res_search_LDADD       = -lresolv -lpthread
+ resolv_LDADD           = -lresolv -lpthread
 endif
 semlimit_LDADD         = -lpthread
 thread_exits_LDADD     = -lpthread
@@ -198,13 +223,22 @@ tls_so_DEPENDENCIES       = tls2.so
 if VGCONF_OS_IS_AIX5
  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
index 13621d08bf4fb325e8c5dab16de327208736b222..798bf86e08de809b7e675d3a4c273df995c5055d 100644 (file)
@@ -50,19 +50,31 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
        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 (file)
index 0000000..b4c90bf
--- /dev/null
@@ -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 (file)
index 0000000..945acc1
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/none/tests/darwin/apple-main-arg.vgtest b/none/tests/darwin/apple-main-arg.vgtest
new file mode 100644 (file)
index 0000000..df4e15a
--- /dev/null
@@ -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 (file)
index 0000000..0ae9313
--- /dev/null
@@ -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 (file)
index 0000000..ac5ac82
--- /dev/null
@@ -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 (file)
index 0000000..56d4e4c
--- /dev/null
@@ -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 (file)
index 0000000..2706845
--- /dev/null
@@ -0,0 +1,2 @@
+prog: rlimit
+vgopts: -q
index 79ce177133e9bdb51b28169eddddf436152f5559..df5ef9811f2bc9cfec7acbfb5d154233cbe4fa03 100644 (file)
@@ -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)
 {
index cc0372b02a414be6429a191fd1ccde7d962beda9..f405c51eefcdbd2fe640490cc920757ec70ecfd9 100644 (file)
@@ -92,6 +92,14 @@ AM_CFLAGS    += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
 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.
index 0350f0db19f4ecbb75e831a648cb077c8107dd89..2cf5a82f92c3d9102c0d2faae63428f355b1d3ac 100644 (file)
@@ -27,3 +27,7 @@ check_PROGRAMS = \
 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
+
index f6206e3ef382dd1a34101d30a98a60f7e0aba27f..6771f4a6a6eb326124e0316623f023b72d85dc00 100644 (file)
@@ -32,10 +32,10 @@ char* all_archs[] = {
 
 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;
 
index 99f9cc5a54e53ab4c7058bbc076583e804a43d2c..e2c2524ed3e66f953d45f7c859f16bb6bd938153 100644 (file)
@@ -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
index a89fb89123a148b91c421eaba9024aba4b1e3583..48c443ffcdbc7763d76bac1e59637f9189b6099c 100755 (executable)
@@ -15,8 +15,9 @@ while (<>)
     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.
index 454d2cff6a52376067a2a2b599f85f444fef1d0d..0179b387cc393937cf8ab2bb73a625a82ff8325a 100644 (file)
@@ -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 @@ __attribute__((unused))
 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;
index 065dbe536e72ef8a36aa54d7747904e16ed04095..a65115c643971a49518f7ccf46105de4e446c39b 100644 (file)
@@ -22,6 +22,7 @@ typedef int    Bool;
 char* all_OSes[] = {
    "linux",
    "aix5",
+   "darwin",
    NULL
 };
 
@@ -31,7 +32,10 @@ static Bool go(char* OS)
    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
index e91b9f7ab699eab330e1f9e956afbde2e6c44312..4d57901136af72e411326ada2e680117a41e1ed9 100644 (file)
@@ -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>"
index 862bccc13dfce47a828181b9786beb5f3944b3e1..7ac64d54c4d045636ac1b46ea1e53853ea04e147 100644 (file)
@@ -2,6 +2,10 @@
 
 #include <sys/mman.h>
 
+#if defined(VGO_darwin)
+#  define MAP_ANONYMOUS MAP_ANON
+#endif
+
 
 #include <assert.h>
 #include <unistd.h>
index 9d17805a82dc79a545affe035704830a6fb81ee6..06ebe5d1ef8f1d4e598392e95ebbbeeeffcfa7ba 100644 (file)
@@ -83,7 +83,7 @@ static Bool go(char* cpu)
    return 1;                                          // Feature not present.
 }
 
-#else    // defined(VGA_x86)  || defined(VGA_amd64)
+#else
 
 static Bool go(char* cpu)
 {