Merge the DARWIN branch onto the trunk.
I tried using 'svn merge' to do the merge but it did a terrible job and
there were bazillions of conflicts. So instead I just took the diff between
the branch and trunk at r10155, applied the diff to the trunk, 'svn add'ed
the added files (no files needed to be 'svn remove'd) and committed.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@10156 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/Makefile.am b/Makefile.am
index 57ab3e2..0106209 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -15,6 +15,22 @@
EXP_TOOLS = exp-omega \
exp-ptrcheck
+# DDD: once all tools work on Darwin, TEST_TOOLS and TEST_EXP_TOOLS can be
+# replaced with TOOLS and EXP_TOOLS.
+if !VGCONF_OS_IS_DARWIN
+ TEST_TOOLS = $(TOOLS)
+ TEST_EXP_TOOLS = $(EXP_TOOLS)
+else
+ TEST_TOOLS = memcheck \
+ cachegrind \
+ callgrind \
+ massif \
+ lackey \
+ none
+
+ TEST_EXP_TOOLS = exp-omega
+endif
+
# Put docs last because building the HTML is slow and we want to get
# everything else working before we try it.
SUBDIRS = include coregrind . tests perf auxprogs $(TOOLS) $(EXP_TOOLS) docs
@@ -27,7 +43,8 @@
glibc-2.34567-NPTL-helgrind.supp \
glibc-2.2-LinuxThreads-helgrind.supp \
glibc-2.X-drd.supp \
- exp-ptrcheck.supp
+ exp-ptrcheck.supp \
+ darwin9.supp
DEFAULT_SUPP_FILES = @DEFAULT_SUPP@
# We include all the base .supp files in the distribution, but not
@@ -78,6 +95,9 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
# Ditto
endif
+if VGCONF_OS_IS_DARWIN
+# GrP untested, possibly hopeless
+endif
default.supp: $(DEFAULT_SUPP_FILES)
echo "# This is a generated file, composed of the following suppression rules:" > default.supp
@@ -86,11 +106,11 @@
## Preprend @PERL@ because tests/vg_regtest isn't executable
regtest: check
- @PERL@ tests/vg_regtest $(TOOLS) $(EXP_TOOLS)
+ @PERL@ tests/vg_regtest $(TEST_TOOLS) $(TEST_EXP_TOOLS)
nonexp-regtest: check
- @PERL@ tests/vg_regtest $(TOOLS)
+ @PERL@ tests/vg_regtest $(TEST_TOOLS)
exp-regtest: check
- @PERL@ tests/vg_regtest $(EXP_TOOLS)
+ @PERL@ tests/vg_regtest $(TEST_EXP_TOOLS)
## Preprend @PERL@ because tests/vg_perf isn't executable
perf: check
diff --git a/Makefile.core-tool.am b/Makefile.core-tool.am
index e5ba118..493e8c3 100644
--- a/Makefile.core-tool.am
+++ b/Makefile.core-tool.am
@@ -1,6 +1,15 @@
# This file contains things shared by coregrind/Makefile.am and tool
# Makefile.am files.
+# See Makefile.tool-tests.am for an explanation of dSYMs.
+build-noinst_DSYMS:
+ for f in $(noinst_DSYMS); do \
+ if [ ! -e $$f.dSYM -o $$f -nt $$f.dSYM ] ; then \
+ echo "dsymutil $$f"; \
+ dsymutil $$f; \
+ fi; \
+ done
+
# This is used by coregrind/Makefile.am and Makefile.tool.am for doing
# "in-place" installs. It copies $(noinst_PROGRAMS) into $inplacedir.
# It needs to be depended on by an 'all-local' rule.
@@ -13,6 +22,16 @@
done ; \
fi
+# Similar to inplace-noinst_PROGRAMS
+inplace-noinst_DSYMS: build-noinst_DSYMS
+ if [ -n "$(noinst_DSYMS)" ] ; then \
+ mkdir -p $(inplacedir); \
+ for f in $(noinst_DSYMS); do \
+ rm -f $(inplacedir)/$$f.dSYM; \
+ ln -f -s ../$(subdir)/$$f.dSYM $(inplacedir); \
+ done ; \
+ fi
+
# This is used by coregrind/Makefile.am and by <tool>/Makefile.am for doing
# "make install". It copies $(noinst_PROGRAMS) into $prefix/lib/valgrind/.
# It needs to be depended on by an 'install-exec-local' rule.
@@ -24,3 +43,23 @@
done ; \
fi
+# Similar to install-noinst_PROGRAMS.
+# Nb: we don't use $(INSTALL_PROGRAM) here because it doesn't work with
+# directories. XXX: not sure whether the resulting permissions will be
+# correct when using 'cp -R'...
+install-noinst_DSYMS: build-noinst_DSYMS
+ if [ -n "$(noinst_DSYMS)" ] ; then \
+ $(mkinstalldirs) $(DESTDIR)$(valdir); \
+ for f in $(noinst_DSYMS); do \
+ cp -R $$f.dSYM $(DESTDIR)$(valdir); \
+ done ; \
+ fi
+
+# This needs to be depended on by a 'clean-local' rule.
+clean-noinst_DSYMS:
+ for f in $(noinst_DSYMS); do \
+ rm -rf $$f.dSYM; \
+ done
+
+
+
diff --git a/Makefile.flags.am b/Makefile.flags.am
index dc09cab..322c8fb 100644
--- a/Makefile.flags.am
+++ b/Makefile.flags.am
@@ -10,7 +10,12 @@
# The aim is to give reasonable performance but also to have good
# stack traces, since users often see stack traces extending
# into (and through) the preloads.
-AM_CFLAGS_PIC = -O -g -fpic -fno-omit-frame-pointer -fno-strict-aliasing
+if VGCONF_OS_IS_DARWIN
+AM_CFLAGS_PIC = -dynamic -O -g -fno-omit-frame-pointer -fno-strict-aliasing -mno-dynamic-no-pic
+else
+AM_CFLAGS_PIC = -fpic -O -g -fno-omit-frame-pointer -fno-strict-aliasing
+endif
+
# Flags for specific targets.
#
@@ -82,6 +87,25 @@
AM_CCASFLAGS_PPC64_AIX5 = $(AM_CPPFLAGS_PPC64_AIX5) \
@FLAG_MAIX64@ -mcpu=powerpc64 -g
+AM_FLAG_M3264_X86_DARWIN = -arch i386
+AM_CPPFLAGS_X86_DARWIN = $(AM_CPPFLAGS_COMMON) \
+ -DVGA_x86=1 \
+ -DVGO_darwin=1 \
+ -DVGP_x86_darwin=1
+AM_CFLAGS_X86_DARWIN = $(WERROR) -arch i386 $(AM_CFLAGS_BASE) \
+ -mmacosx-version-min=10.5 -fno-stack-protector \
+ -mdynamic-no-pic
+AM_CCASFLAGS_X86_DARWIN = $(AM_CPPFLAGS_X86_DARWIN) -arch i386 -g
+
+AM_FLAG_M3264_AMD64_DARWIN = -arch x86_64
+AM_CPPFLAGS_AMD64_DARWIN = $(AM_CPPFLAGS_COMMON) \
+ -DVGA_amd64=1 \
+ -DVGO_darwin=1 \
+ -DVGP_amd64_darwin=1
+AM_CFLAGS_AMD64_DARWIN = $(WERROR) -arch x86_64 $(AM_CFLAGS_BASE) \
+ -mmacosx-version-min=10.5 -fno-stack-protector
+AM_CCASFLAGS_AMD64_DARWIN = $(AM_CPPFLAGS_AMD64_DARWIN) -arch x86_64 -g
+
# Flags for the primary target. These must be used to build the
# regtests and performance tests. In fact, these must be used to
# build anything which is built only once on a dual-arch build.
@@ -102,9 +126,12 @@
#
PRELOAD_LDFLAGS_COMMON_LINUX = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst
PRELOAD_LDFLAGS_COMMON_AIX5 = -nodefaultlibs -shared -Wl,-G -Wl,-bnogc
+PRELOAD_LDFLAGS_COMMON_DARWIN = -dynamic -dynamiclib -all_load
PRELOAD_LDFLAGS_X86_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@
PRELOAD_LDFLAGS_AMD64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
PRELOAD_LDFLAGS_PPC32_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@
PRELOAD_LDFLAGS_PPC64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@
PRELOAD_LDFLAGS_PPC32_AIX5 = $(PRELOAD_LDFLAGS_COMMON_AIX5) @FLAG_MAIX32@
PRELOAD_LDFLAGS_PPC64_AIX5 = $(PRELOAD_LDFLAGS_COMMON_AIX5) @FLAG_MAIX64@
+PRELOAD_LDFLAGS_X86_DARWIN = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch i386
+PRELOAD_LDFLAGS_AMD64_DARWIN = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch x86_64
diff --git a/Makefile.tool-tests.am b/Makefile.tool-tests.am
index b81d3e5..9694f06 100644
--- a/Makefile.tool-tests.am
+++ b/Makefile.tool-tests.am
@@ -16,3 +16,25 @@
# automake; see comments in Makefile.flags.am for more detail.
AM_CCASFLAGS = $(AM_CPPFLAGS)
+
+# On Darwin, for a program 'p', the DWARF debug info is stored in the
+# directory 'p.dSYM'. This must be generated after the executable is
+# created, with 'dsymutil p'. We could redefine LINK with a script that
+# executes 'dsymutil' after linking, but that's a pain. Instead we use this
+# hook so that every time "make check" is run, we subsequently invoke
+# 'dsymutil' on all the executables that lack a .dSYM directory, or that are
+# newer than their corresponding .dSYM directory.
+if VGCONF_OS_IS_DARWIN
+check-local:
+ for f in $(check_PROGRAMS) ; do \
+ if [ ! -e $$f.dSYM -o $$f -nt $$f.dSYM ] ; then \
+ echo "dsymutil $$f"; \
+ dsymutil $$f; \
+ fi \
+ done
+
+clean-local:
+ for f in $(check_PROGRAMS) ; do \
+ rm -rf $$f.dSYM; \
+ done
+endif
diff --git a/Makefile.tool.am b/Makefile.tool.am
index 0812728..21925fc 100644
--- a/Makefile.tool.am
+++ b/Makefile.tool.am
@@ -24,6 +24,12 @@
LIBREPLACEMALLOC_PPC64_AIX5 = \
$(top_builddir)/coregrind/libreplacemalloc_toolpreload-ppc64-aix5.a
+LIBREPLACEMALLOC_X86_DARWIN = \
+ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-darwin.a
+
+LIBREPLACEMALLOC_AMD64_DARWIN = \
+ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-amd64-darwin.a
+
COREGRIND_LIBS_X86_LINUX = \
$(top_builddir)/coregrind/libcoregrind-x86-linux.a \
@@ -49,6 +55,14 @@
$(top_builddir)/coregrind/libcoregrind-ppc64-aix5.a \
@VEX_DIR@/libvex-ppc64-aix5.a
+COREGRIND_LIBS_X86_DARWIN = \
+ $(top_builddir)/coregrind/libcoregrind-x86-darwin.a \
+ @VEX_DIR@/libvex-x86-darwin.a
+
+COREGRIND_LIBS_AMD64_DARWIN = \
+ $(top_builddir)/coregrind/libcoregrind-amd64-darwin.a \
+ @VEX_DIR@/libvex-amd64-darwin.a
+
##.PHONY: @VEX_DIR@/libvex.a
@@ -88,6 +102,18 @@
EXTRA_CFLAGS="$(AM_CFLAGS_PPC64_AIX5) @FLAG_WDECL_AFTER_STMT@ \
@FLAG_FNO_STACK_PROTECTOR@"
+@VEX_DIR@/libvex-x86-darwin.a: @VEX_DIR@/priv/main/vex_svnversion.h
+ $(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" \
+ libvex-x86-darwin.a \
+ EXTRA_CFLAGS="$(AM_CFLAGS_X86_DARWIN) @FLAG_WDECL_AFTER_STMT@ \
+ @FLAG_FNO_STACK_PROTECTOR@"
+
+@VEX_DIR@/libvex-amd64-darwin.a: @VEX_DIR@/priv/main/vex_svnversion.h
+ $(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" \
+ libvex-amd64-darwin.a \
+ EXTRA_CFLAGS="$(AM_CFLAGS_AMD64_DARWIN) @FLAG_WDECL_AFTER_STMT@ \
+ @FLAG_FNO_STACK_PROTECTOR@"
+
@VEX_DIR@/priv/main/vex_svnversion.h:
$(MAKE) -C @VEX_DIR@ CC="$(CC)" version
@@ -97,7 +123,8 @@
-Wl,-defsym,valt_load_address=@VALT_LOAD_ADDRESS@ \
-nodefaultlibs -nostartfiles -u _start
TOOL_LDFLAGS_COMMON_AIX5 = -static -Wl,-e_start_valgrind
-
+TOOL_LDFLAGS_COMMON_DARWIN = -nodefaultlibs -nostartfiles \
+ -Wl,-u,__start -Wl,-e,__start -Wl,-bind_at_load /usr/lib/dyld
TOOL_LDADD_X86_LINUX = $(COREGRIND_LIBS_X86_LINUX) $(TOOL_LDADD_COMMON)
TOOL_LDFLAGS_X86_LINUX = \
@@ -127,6 +154,23 @@
TOOL_LDFLAGS_PPC64_AIX5 = \
$(TOOL_LDFLAGS_COMMON_AIX5) @FLAG_MAIX64@ -Wl,-bbigtoc
+TOOL_LDADD_X86_DARWIN = $(COREGRIND_LIBS_X86_DARWIN) $(TOOL_LDADD_COMMON)
+TOOL_LDFLAGS_X86_DARWIN = \
+ $(TOOL_LDFLAGS_COMMON_DARWIN) -arch i386 \
+ -Wl,-seg1addr,0xf0080000 \
+ -Wl,-stack_addr,0xf0080000 -Wl,-stack_size,0x80000 \
+ -Wl,-pagezero_size,0xf0000000
+
+# pagezero can't be unmapped and remapped. Use stack instead.
+# GrP fixme no stack guard
+TOOL_LDADD_AMD64_DARWIN = $(COREGRIND_LIBS_AMD64_DARWIN) $(TOOL_LDADD_COMMON)
+TOOL_LDFLAGS_AMD64_DARWIN = \
+ $(TOOL_LDFLAGS_COMMON_DARWIN) -arch x86_64 \
+ -Wl,-seg1addr,0x7fff55000000 \
+ -Wl,-stack_addr,0x7fff50080000 -Wl,-stack_size,0x7ffe50080000 \
+ -Wl,-pagezero_size,0x100000000
+
+
LIBREPLACEMALLOC_LDFLAGS_X86_LINUX = \
-Wl,--whole-archive \
$(LIBREPLACEMALLOC_X86_LINUX) \
@@ -153,8 +197,17 @@
LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5 = \
$(LIBREPLACEMALLOC_PPC64_AIX5)
+LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN = \
+ $(LIBREPLACEMALLOC_X86_DARWIN)
-all-local: inplace-noinst_PROGRAMS
+LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN = \
+ $(LIBREPLACEMALLOC_AMD64_DARWIN)
-install-exec-local: install-noinst_PROGRAMS
+
+
+all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
+
+clean-local: clean-noinst_DSYMS
+
+install-exec-local: install-noinst_PROGRAMS install-noinst_DSYMS
diff --git a/NEWS b/NEWS
index 757b220..332abab 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,22 @@
Release 3.5.0 (???)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+* XXX: Mac OS X support
+ - x86/Darwin.
+ - probably amd64/Darwin.
+ - Requires Mac OS X 10.5 Leopard or later.
+ - No support for Mac OS X on PowerPC machines.
+ - Many thanks to Greg Parker for developing this port over several years.
+
+ Things that don't work
+ - Objective-C garbage collection
+ - --db-attach=yes
+ - Messages like the following indicate a mismatch between Valgrind's
+ memory map and the kernel. Occasional failures are expected in
+ multithreaded programs. If the failure repeats for the same address
+ range, then there may be a problem causing false errors or crashes.
+ sync check at ...: FAILED
+
* A new Memcheck client request VALGRIND_COUNT_LEAK_BLOCKS has been added.
It is similar to VALGRIND_COUNT_LEAKS but counts blocks instead of bytes.
[XXX: consider adding VALGRIND_COUNT_LEAK_BYTES as a synonym and
diff --git a/auxprogs/Makefile.am b/auxprogs/Makefile.am
index 7145df7..df59b74 100644
--- a/auxprogs/Makefile.am
+++ b/auxprogs/Makefile.am
@@ -27,7 +27,6 @@
#
#----------------------------------------------------------
-
#------------------------- mpi wrappers -----------------------
# Build libmpiwrap.so for the primary target, and for the secondary
# target if relevant.
@@ -51,11 +50,18 @@
-qflag=w:w -qlanglvl=extended \
`echo $(AM_FLAG_M3264_SEC) | sed s/maix/q/g`
else
+if VGCONF_OS_IS_DARWIN
+ HACKY_FLAGS_PRI = -g -O -fno-omit-frame-pointer -Wall -dynamic \
+ -dynamiclib -all_load $(AM_FLAG_M3264_PRI)
+ HACKY_FLAGS_SEC = -g -O -fno-omit-frame-pointer -Wall -dynamic \
+ -dynamiclib -all_load $(AM_FLAG_M3264_SEC)
+else
HACKY_FLAGS_PRI = -g -O -fno-omit-frame-pointer -Wall -fpic -shared \
$(AM_FLAG_M3264_PRI)
HACKY_FLAGS_SEC = -g -O -fno-omit-frame-pointer -Wall -fpic -shared \
$(AM_FLAG_M3264_SEC)
endif
+endif
## First, we have to say how to build the .so's ..
@@ -120,6 +126,9 @@
rm -f libmpiwrap-.c \
libmpiwrap-@VGCONF_ARCH_PRI@-@VGCONF_OS@.c \
libmpiwrap-@VGCONF_ARCH_SEC@-@VGCONF_OS@.c
+if VGCONF_OS_IS_DARWIN
+ rm -rf libmpiwrap-*.dSYM
+endif
#
#----------------------------------------------------------
diff --git a/cachegrind/Makefile.am b/cachegrind/Makefile.am
index eac2825..f165e8d 100644
--- a/cachegrind/Makefile.am
+++ b/cachegrind/Makefile.am
@@ -23,6 +23,12 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += cachegrind-ppc64-aix5
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += cachegrind-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += cachegrind-amd64-darwin
+endif
# Build cg_merge for the primary target only.
bin_PROGRAMS = cg_merge
@@ -80,3 +86,17 @@
cachegrind_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
cachegrind_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
cachegrind_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+cachegrind_x86_darwin_SOURCES = $(CACHEGRIND_SOURCES_COMMON) $(CACHEGRIND_SOURCES_X86)
+cachegrind_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+cachegrind_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+cachegrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+cachegrind_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+cachegrind_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+cachegrind_amd64_darwin_SOURCES = $(CACHEGRIND_SOURCES_COMMON) $(CACHEGRIND_SOURCES_AMD64)
+cachegrind_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+cachegrind_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+cachegrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+cachegrind_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+cachegrind_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/cachegrind/cg_main.c b/cachegrind/cg_main.c
index 279356b..6c4e1e4 100644
--- a/cachegrind/cg_main.c
+++ b/cachegrind/cg_main.c
@@ -1464,13 +1464,14 @@
if (VG_(clo_verbosity) == 0)
return;
- #define MAX(a, b) ((a) >= (b) ? (a) : (b))
+ // Nb: this isn't called "MAX" because that overshadows a global on Darwin.
+ #define CG_MAX(a, b) ((a) >= (b) ? (a) : (b))
/* I cache results. Use the I_refs value to determine the first column
* width. */
l1 = ULong_width(Ir_total.a);
- l2 = ULong_width(MAX(Dr_total.a, Bc_total.b));
- l3 = ULong_width(MAX(Dw_total.a, Bi_total.b));
+ l2 = ULong_width(CG_MAX(Dr_total.a, Bc_total.b));
+ l3 = ULong_width(CG_MAX(Dw_total.a, Bi_total.b));
/* Make format string, getting width right for numbers */
VG_(sprintf)(fmt, "%%s %%,%dllu", l1);
diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am
index 497ee19..f7f12a7 100644
--- a/cachegrind/tests/Makefile.am
+++ b/cachegrind/tests/Makefile.am
@@ -25,5 +25,9 @@
# C ones
dlclose_LDADD = -ldl
-myprint_so_LDFLAGS = $(AM_FLAG_M3264_PRI) -shared -fPIC
+if VGCONF_OS_IS_DARWIN
+myprint_so_LDFLAGS = $(AM_CFLAGS) -dynamic -dynamiclib -all_load -fpic
+else
+myprint_so_LDFLAGS = $(AM_CFLAGS) -shared -fPIC
+endif
myprint_so_CFLAGS = $(AM_CFLAGS) -fPIC
diff --git a/callgrind/Makefile.am b/callgrind/Makefile.am
index ac1720c..bc983b6 100644
--- a/callgrind/Makefile.am
+++ b/callgrind/Makefile.am
@@ -23,6 +23,12 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += callgrind-ppc64-aix5
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += callgrind-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += callgrind-amd64-darwin
+endif
CALLGRIND_SOURCES_COMMON = main.c events.c bb.c clo.c \
costs.c bbcc.c command.c debug.c fn.c \
@@ -81,3 +87,17 @@
callgrind_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
callgrind_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
callgrind_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+callgrind_x86_darwin_SOURCES = $(CALLGRIND_SOURCES_COMMON) $(CALLGRIND_SOURCES_X86)
+callgrind_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+callgrind_x86_darwin_CFLAGS = $(CALLGRIND_CFLAGS_COMMON) $(AM_CFLAGS_X86_DARWIN)
+callgrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+callgrind_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+callgrind_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+callgrind_amd64_darwin_SOURCES = $(CALLGRIND_SOURCES_COMMON) $(CALLGRIND_SOURCES_AMD64)
+callgrind_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+callgrind_amd64_darwin_CFLAGS = $(CALLGRIND_CFLAGS_COMMON) $(AM_CFLAGS_AMD64_DARWIN)
+callgrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+callgrind_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+callgrind_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/configure.in b/configure.in
index 1e3892f..e6657df 100644
--- a/configure.in
+++ b/configure.in
@@ -62,6 +62,7 @@
AM_PROG_CC_C_O
AC_PROG_CPP
AC_PROG_CXX
+AC_PROG_OBJC
AC_PROG_RANLIB
# If no AR variable was specified, look up the name of the archiver. Otherwise
@@ -219,6 +220,8 @@
AC_MSG_CHECKING([for a supported OS])
AC_SUBST(VGCONF_OS)
+DEFAULT_SUPP=""
+
case "${host_os}" in
*linux*)
AC_MSG_RESULT([ok (${host_os})])
@@ -266,6 +269,34 @@
VGCONF_OS="freebsd"
;;
+ *darwin*)
+ AC_MSG_RESULT([ok (${host_os})])
+ VGCONF_OS="darwin"
+
+ AC_MSG_CHECKING([for the kernel version])
+ kernel=`uname -r`
+
+ # Nb: for Darwin we set DEFAULT_SUPP here. That's because Darwin
+ # has only one relevant version, the OS version. The `uname` check
+ # is a good way to get that version (i.e. "Darwin 9.6.0" is Mac OS
+ # X 10.5.6, and "Darwin 10.x" would presumably be Mac OS X 10.6.x
+ # Snow Leopard and darwin10.supp), and we don't know of an macros
+ # similar to __GLIBC__ to get that info.
+ #
+ # XXX: `uname -r` won't do the right thing for cross-compiles, but
+ # that's not a problem yet.
+ case "${kernel}" in
+ 9.*)
+ AC_MSG_RESULT([Darwin 9.x (${kernel}) / Mac OS X 10.5 Leopard])
+ DEFAULT_SUPP="darwin9.supp ${DEFAULT_SUPP}"
+ ;;
+ *)
+ AC_MSG_RESULT([unsupported (${kernel})])
+ AC_MSG_ERROR([Valgrind works on Darwin 9.x (Mac OS X 10.5)])
+ ;;
+ esac
+ ;;
+
*)
AC_MSG_RESULT([no (${host_os})])
AC_MSG_ERROR([Valgrind is operating system specific. Sorry. Please consider doing a port.])
@@ -405,6 +436,33 @@
valt_load_address_inner="0x28000000"
AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
;;
+ x86-darwin)
+ VGCONF_ARCH_PRI="x86"
+ VGCONF_PLATFORM_PRI_CAPS="X86_DARWIN"
+ VGCONF_PLATFORM_SEC_CAPS=""
+ valt_load_address_normal="0x0"
+ valt_load_address_inner="0x0"
+ AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+ ;;
+ amd64-darwin)
+ if test x$vg_cv_only64bit = xyes; then
+ VGCONF_ARCH_PRI="amd64"
+ VGCONF_PLATFORM_PRI_CAPS="AMD64_DARWIN"
+ VGCONF_PLATFORM_SEC_CAPS=""
+ elif test x$vg_cv_only32bit = xyes; then
+ VGCONF_ARCH_PRI="x86"
+ VGCONF_PLATFORM_PRI_CAPS="X86_DARWIN"
+ VGCONF_PLATFORM_SEC_CAPS=""
+ VGCONF_ARCH_PRI_CAPS="x86"
+ else
+ VGCONF_ARCH_PRI="amd64"
+ VGCONF_PLATFORM_PRI_CAPS="AMD64_DARWIN"
+ VGCONF_PLATFORM_SEC_CAPS="X86_DARWIN"
+ fi
+ valt_load_address_normal="0x0"
+ valt_load_address_inner="0x0"
+ AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})])
+ ;;
*)
VGCONF_ARCH_PRI="unknown"
VGCONF_PLATFORM_PRI_CAPS="UNKNOWN"
@@ -420,9 +478,12 @@
# defined.
AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_X86,
test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \
- -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX )
+ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX \
+ -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
+ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN )
AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64,
- test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX )
+ test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \
+ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN )
AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \
-o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX \
@@ -444,12 +505,20 @@
-o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX)
AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_LINUX,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX)
+
AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC32_AIX5,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_AIX5 \
-o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_AIX5)
AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_AIX5)
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_DARWIN,
+ test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
+ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN)
+AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN,
+ test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
+
+
# Similarly, set up VGCONF_OF_IS_<os>. Exactly one of these becomes defined.
# Relies on the assumption that the primary and secondary targets are
# for the same OS, so therefore only necessary to test the primary.
@@ -461,6 +530,9 @@
AM_CONDITIONAL(VGCONF_OS_IS_AIX5,
test x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_AIX5 \
-o x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_AIX5)
+AM_CONDITIONAL(VGCONF_OS_IS_DARWIN,
+ test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \
+ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN)
# Sometimes, in the Makefile.am files, it's useful to know whether or not
@@ -493,7 +565,6 @@
# Libc and suppressions
#----------------------------------------------------------------------------
# This variable will collect the suppression files to be used.
-DEFAULT_SUPP=""
AC_SUBST(DEFAULT_SUPP)
GLIBC_VERSION=""
@@ -596,6 +667,15 @@
],
GLIBC_VERSION="aix5")
+# not really a version check
+AC_EGREP_CPP([DARWIN_LIBC], [
+#include <sys/cdefs.h>
+#if defined(__DARWIN_VERS_1050)
+ DARWIN_LIBC
+#endif
+],
+GLIBC_VERSION="darwin")
+
AC_MSG_CHECKING([the GLIBC_VERSION version])
case "${GLIBC_VERSION}" in
@@ -670,11 +750,17 @@
AC_DEFINE([AIX5_LIBC], 1, [Define to 1 if you're using AIX 5.1 or 5.2 or 5.3])
DEFAULT_SUPP="aix5libc.supp ${DEFAULT_SUPP}"
;;
+ darwin)
+ AC_MSG_RESULT(Darwin)
+ AC_DEFINE([DARWIN_LIBC], 1, [Define to 1 if you're using Darwin])
+ # DEFAULT_SUPP set by kernel version check above.
+ ;;
*)
AC_MSG_RESULT(unsupported version)
AC_MSG_ERROR([Valgrind requires glibc version 2.2 - 2.10])
AC_MSG_ERROR([or AIX 5.1 or 5.2 or 5.3 GLIBC_VERSION])
+ AC_MSG_ERROR([or Darwin libc])
;;
esac
@@ -1341,6 +1427,14 @@
#----------------------------------------------------------------------------
+# Check for /proc filesystem
+#----------------------------------------------------------------------------
+AC_CHECK_FILES(/proc/self/fd /proc/self/exe /proc/self/maps,
+ [ AC_DEFINE([HAVE_PROC], 1, [can use /proc filesystem]) ],
+ [])
+
+
+#----------------------------------------------------------------------------
# Checks for C header files.
#----------------------------------------------------------------------------
@@ -1389,6 +1483,7 @@
memchr \
memset \
mkdir \
+ mremap \
ppoll \
pthread_barrier_init \
pthread_condattr_setclock \
@@ -1738,6 +1833,7 @@
memcheck/tests/amd64/Makefile
memcheck/tests/x86/Makefile
memcheck/tests/linux/Makefile
+ memcheck/tests/darwin/Makefile
memcheck/tests/x86-linux/Makefile
memcheck/perf/Makefile
memcheck/docs/Makefile
@@ -1769,6 +1865,7 @@
none/tests/ppc64/Makefile
none/tests/x86/Makefile
none/tests/linux/Makefile
+ none/tests/darwin/Makefile
none/tests/x86-linux/Makefile
none/docs/Makefile
exp-omega/Makefile
diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am
index 0839b85..1bcfec7 100644
--- a/coregrind/Makefile.am
+++ b/coregrind/Makefile.am
@@ -7,29 +7,40 @@
include $(top_srcdir)/Makefile.flags.am
include $(top_srcdir)/Makefile.core-tool.am
-
AM_CPPFLAGS_CORE_COMMON = \
-I$(top_srcdir)/coregrind \
-DVG_LIBDIR="\"$(valdir)"\"
AM_CPPFLAGS_X86_LINUX += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"x86-linux\""
+
AM_CPPFLAGS_AMD64_LINUX += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"amd64-linux\""
+
AM_CPPFLAGS_PPC32_LINUX += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc32-linux\""
+
AM_CPPFLAGS_PPC64_LINUX += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc64-linux\""
+
AM_CPPFLAGS_PPC32_AIX5 += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc32-aix5\""
+
AM_CPPFLAGS_PPC64_AIX5 += \
$(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"ppc64-aix5\""
+AM_CPPFLAGS_X86_DARWIN += \
+ $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"x86-darwin\""
+
+AM_CPPFLAGS_AMD64_DARWIN += \
+ $(AM_CPPFLAGS_CORE_COMMON) -DVG_PLATFORM="\"amd64-darwin\""
+
default.supp: $(SUPP_FILES)
noinst_PROGRAMS =
+noinst_DSYMS =
pkglib_LIBRARIES =
LIBVEX =
@@ -69,6 +80,20 @@
LIBVEX += libvex-ppc64-aix5.a
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += vgpreload_core-x86-darwin.so
+noinst_DSYMS += vgpreload_core-x86-darwin.so
+pkglib_LIBRARIES += libcoregrind-x86-darwin.a libreplacemalloc_toolpreload-x86-darwin.a
+LIBVEX += libvex-x86-darwin.a
+endif
+
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += vgpreload_core-amd64-darwin.so
+noinst_DSYMS += vgpreload_core-amd64-darwin.so
+pkglib_LIBRARIES += libcoregrind-amd64-darwin.a libreplacemalloc_toolpreload-amd64-darwin.a
+LIBVEX += libvex-amd64-darwin.a
+endif
+
#------------------------- launcher -----------------------
# Build the launcher (valgrind) for the primary target only.
@@ -87,6 +112,46 @@
m_debuglog.c \
m_vkiscnums.c
endif
+if VGCONF_OS_IS_DARWIN
+valgrind_SOURCES = \
+ launcher-darwin.c \
+ m_debuglog.c
+endif
+
+# Mach RPC interface definitions
+# Here are some more .defs files that are not used, but could be in the
+# future:
+# clock.defs \
+# clock_priv.defs \
+# clock_reply.defs \
+# exc.defs \
+# host_priv.defs \
+# host_security.defs \
+# ledger.defs \
+# lock_set.defs \
+# mach_host.defs \
+# mach_port.defs \
+# notify.defs \
+# processor.defs \
+# processor_set.defs \
+#
+if VGCONF_OS_IS_DARWIN
+mach_defs = \
+ mach_vm.defs \
+ task.defs \
+ thread_act.defs \
+ vm_map.defs
+else
+mach_defs =
+endif
+
+mach_srcs = $(addprefix m_mach/,$(mach_defs:.defs=User.c))
+mach_server_srcs = $(addprefix m_mach/,$(mach_defs:.defs=Server.c))
+mach_hdrs = $(addprefix m_mach/,$(mach_defs:.defs=.h))
+mach_files = $(addprefix /usr/include/mach/,$(mach_defs))
+
+$(mach_srcs) $(mach_hdrs): $(mach_files)
+ (cd m_mach && mig $(mach_files))
valgrind_CPPFLAGS = $(AM_CPPFLAGS_PRI)
valgrind_CFLAGS = $(AM_CFLAGS_PRI)
@@ -103,6 +168,7 @@
noinst_HEADERS = \
+ $(mach_hdrs) \
launcher-aix5-bootblock.h \
pub_core_aspacehl.h \
pub_core_aspacemgr.h \
@@ -129,6 +195,7 @@
pub_core_libcprint.h \
pub_core_libcproc.h \
pub_core_libcsignal.h \
+ pub_core_mach.h \
pub_core_machine.h \
pub_core_mallocfree.h \
pub_core_options.h \
@@ -166,6 +233,7 @@
m_debuginfo/priv_readdwarf.h \
m_debuginfo/priv_readdwarf3.h \
m_debuginfo/priv_readelf.h \
+ m_debuginfo/priv_readmacho.h \
m_debuginfo/priv_readxcoff.h \
m_demangle/ansidecl.h \
m_demangle/cp-demangle.h \
@@ -181,17 +249,22 @@
m_syswrap/priv_syswrap-linux.h \
m_syswrap/priv_syswrap-linux-variants.h \
m_syswrap/priv_syswrap-aix5.h \
+ m_syswrap/priv_syswrap-darwin.h \
m_syswrap/priv_syswrap-main.h \
m_ume/priv_ume.h
BUILT_SOURCES =
CLEANFILES =
+if VGCONF_OS_IS_DARWIN
+BUILT_SOURCES += $(COREGRIND_DARWIN_BUILT_SOURCES)
+CLEANFILES += $(COREGRIND_DARWIN_BUILT_SOURCES)
+endif
COREGRIND_SOURCES_COMMON = \
m_commandline.c \
- m_cpuid.S \
m_clientstate.c \
+ m_cpuid.S \
m_debugger.c \
m_debuglog.c \
m_errormgr.c \
@@ -241,6 +314,7 @@
m_scheduler/sema.c \
m_syswrap/syswrap-main.c \
m_ume/elf.c \
+ m_ume/macho.c \
m_ume/main.c \
m_ume/script.c
@@ -264,6 +338,28 @@
m_initimg/initimg-aix5.c \
m_syswrap/syswrap-aix5.c
+ # Note that the *User.c files are generated using 'mig' from $mach_defs
+ # above.
+COREGRIND_DARWIN_SOURCE = \
+ m_aspacemgr/aspacemgr-linux.c \
+ m_debuginfo/readdwarf.c \
+ m_debuginfo/readdwarf3.c \
+ m_debuginfo/readstabs.c \
+ m_debuginfo/readmacho.c \
+ m_debuginfo/readpdb.c \
+ m_mach/mach_basics.c \
+ m_mach/mach_msg.c \
+ m_initimg/initimg-darwin.c \
+ m_initimg/initimg-pathscan.c \
+ m_syswrap/syswrap-darwin.c \
+ m_syswrap/syswrap-generic.c
+
+COREGRIND_DARWIN_BUILT_SOURCES = \
+ m_mach/mach_vmUser.c \
+ m_mach/taskUser.c \
+ m_mach/thread_actUser.c \
+ m_mach/vm_mapUser.c
+
libcoregrind_x86_linux_a_SOURCES = \
$(COREGRIND_SOURCES_COMMON) \
$(COREGRIND_LINUX_SOURCE) \
@@ -338,6 +434,37 @@
libcoregrind_ppc64_aix5_a_CCASFLAGS = $(AM_CCASFLAGS_PPC64_AIX5)
libcoregrind_ppc64_aix5_a_AR = $(AR) -X64 cru
+libcoregrind_x86_darwin_a_SOURCES = \
+ $(COREGRIND_SOURCES_COMMON) \
+ $(COREGRIND_DARWIN_SOURCE) \
+ m_coredump/coredump-x86-darwin.c \
+ m_dispatch/dispatch-x86-darwin.S \
+ m_mach/mach_traps-x86-darwin.S \
+ m_sigframe/sigframe-x86-darwin.c \
+ m_start-x86-darwin.S \
+ m_syswrap/syscall-x86-darwin.S \
+ m_syswrap/syswrap-x86-darwin.c
+nodist_libcoregrind_x86_darwin_a_SOURCES = $(COREGRIND_DARWIN_BUILT_SOURCES)
+libcoregrind_x86_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+libcoregrind_x86_darwin_a_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+libcoregrind_x86_darwin_a_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+
+
+libcoregrind_amd64_darwin_a_SOURCES = \
+ $(COREGRIND_SOURCES_COMMON) \
+ $(COREGRIND_DARWIN_SOURCE) \
+ m_coredump/coredump-amd64-darwin.c \
+ m_dispatch/dispatch-amd64-darwin.S \
+ m_mach/mach_traps-amd64-darwin.S \
+ m_sigframe/sigframe-amd64-darwin.c \
+ m_start-amd64-darwin.S \
+ m_syswrap/syscall-amd64-darwin.S \
+ m_syswrap/syswrap-amd64-darwin.c
+nodist_libcoregrind_amd64_darwin_a_SOURCES = $(COREGRIND_DARWIN_BUILT_SOURCES)
+libcoregrind_amd64_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+libcoregrind_amd64_darwin_a_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+libcoregrind_amd64_darwin_a_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+
libreplacemalloc_toolpreload_x86_linux_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
libreplacemalloc_toolpreload_x86_linux_a_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
@@ -365,18 +492,30 @@
libreplacemalloc_toolpreload_ppc64_aix5_a_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC)
libreplacemalloc_toolpreload_ppc64_aix5_a_AR = $(AR) -X64 cru
+libreplacemalloc_toolpreload_x86_darwin_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_x86_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+libreplacemalloc_toolpreload_x86_darwin_a_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+
+libreplacemalloc_toolpreload_amd64_darwin_a_SOURCES = m_replacemalloc/vg_replace_malloc.c
+libreplacemalloc_toolpreload_amd64_darwin_a_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+libreplacemalloc_toolpreload_amd64_darwin_a_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+
m_dispatch/dispatch-x86-linux.S: libvex_guest_offsets.h
m_dispatch/dispatch-amd64-linux.S: libvex_guest_offsets.h
m_dispatch/dispatch-ppc32-linux.S: libvex_guest_offsets.h
m_dispatch/dispatch-ppc64-linux.S: libvex_guest_offsets.h
m_dispatch/dispatch-ppc32-aix5.S: libvex_guest_offsets.h
m_dispatch/dispatch-ppc64-aix5.S: libvex_guest_offsets.h
+m_dispatch/dispatch-x86-darwin.S: libvex_guest_offsets.h
+m_dispatch/dispatch-amd64-darwin.S: libvex_guest_offsets.h
m_syswrap/syscall-x86-linux.S: libvex_guest_offsets.h
m_syswrap/syscall-amd64-linux.S: libvex_guest_offsets.h
m_syswrap/syscall-ppc32-linux.S: libvex_guest_offsets.h
m_syswrap/syscall-ppc64-linux.S: libvex_guest_offsets.h
m_syswrap/syscall-ppc32-aix5.S: libvex_guest_offsets.h
m_syswrap/syscall-ppc64-aix5.S: libvex_guest_offsets.h
+m_syswrap/syscall-x86-darwin.S: libvex_guest_offsets.h
+m_syswrap/syscall-amd64-darwin.S: libvex_guest_offsets.h
m_syswrap/syswrap-main.c: libvex_guest_offsets.h
libvex_guest_offsets.h:
@@ -414,14 +553,25 @@
vgpreload_core_ppc64_aix5_so_CFLAGS = $(AM_CFLAGS_PPC64_AIX5) $(AM_CFLAGS_PIC)
vgpreload_core_ppc64_aix5_so_LDFLAGS = $(PRELOAD_LDFLAGS_PPC64_AIX5)
-all-local: inplace-noinst_PROGRAMS
+vgpreload_core_x86_darwin_so_SOURCES = $(VGPRELOAD_CORE_SOURCES_COMMON)
+vgpreload_core_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_core_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_core_x86_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_X86_DARWIN)
-clean-local:
+vgpreload_core_amd64_darwin_so_SOURCES = $(VGPRELOAD_CORE_SOURCES_COMMON)
+vgpreload_core_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_core_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_core_amd64_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_AMD64_DARWIN)
+
+all-local: inplace-noinst_PROGRAMS inplace-noinst_DSYMS
+
+clean-local: clean-noinst_DSYMS
$(MAKE) -C @VEX_DIR@ CC="$(CC)" AR="$(AR)" clean
+ rm -f $(mach_srcs) $(mach_server_srcs) $(mach_hdrs)
# Nb: The loop installs the libvex library for possible use by standalone
# tools.
-install-exec-local: install-noinst_PROGRAMS
+install-exec-local: install-noinst_PROGRAMS install-noinst_DSYMS
for v in $(LIBVEX) ; do \
$(INSTALL_DATA) @VEX_DIR@/$$v $(DESTDIR)$(valdir) ; \
done
diff --git a/coregrind/launcher-darwin.c b/coregrind/launcher-darwin.c
new file mode 100644
index 0000000..a470cf1
--- /dev/null
+++ b/coregrind/launcher-darwin.c
@@ -0,0 +1,421 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Launching valgrind launcher-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Note: this is a "normal" program and not part of Valgrind proper,
+ and so it doesn't have to conform to Valgrind's arcane rules on
+ no-glibc-usage etc. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/user.h>
+#include <unistd.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#include "pub_core_debuglog.h"
+#include "pub_core_vki.h" // Avoids warnings from
+ // pub_core_libcfile.h
+#include "pub_core_libcproc.h" // For VALGRIND_LIB, VALGRIND_LAUNCHER
+#include "pub_core_ume.h"
+
+static struct {
+ cpu_type_t cputype;
+ const char *apple_name; // e.g. x86_64
+ const char *valgrind_name; // e.g. amd64
+} valid_archs[] = {
+ { CPU_TYPE_X86, "i386", "x86" },
+ { CPU_TYPE_X86_64, "x86_64", "amd64" },
+ { CPU_TYPE_ARM, "arm", "arm" },
+ { CPU_TYPE_POWERPC, "ppc", "ppc32" },
+ { CPU_TYPE_POWERPC64, "ppc64", "ppc64" },
+};
+static int valid_archs_count = sizeof(valid_archs)/sizeof(valid_archs[0]);
+
+static const char *name_for_cputype(cpu_type_t cputype)
+{
+ int i;
+ for (i = 0; i < valid_archs_count; i++) {
+ if (valid_archs[i].cputype == cputype) {
+ return valid_archs[i].valgrind_name;
+ }
+ }
+ return NULL;
+}
+
+/* Report fatal errors */
+__attribute__((noreturn))
+static void barf ( const char *format, ... )
+{
+ va_list vargs;
+
+ va_start(vargs, format);
+ fprintf(stderr, "valgrind: ");
+ vfprintf(stderr, format, vargs);
+ fprintf(stderr, "\n");
+ va_end(vargs);
+
+ exit(1);
+ /*NOTREACHED*/
+ assert(0);
+}
+
+/* Search the path for the client program */
+static const char *find_client(const char *clientname)
+{
+ static char fullname[PATH_MAX];
+ const char *path = getenv("PATH");
+ const char *colon;
+
+ while (path)
+ {
+ if ((colon = strchr(path, ':')) == NULL)
+ {
+ strcpy(fullname, path);
+ path = NULL;
+ }
+ else
+ {
+ memcpy(fullname, path, colon - path);
+ fullname[colon - path] = '\0';
+ path = colon + 1;
+ }
+
+ strcat(fullname, "/");
+ strcat(fullname, clientname);
+
+ if (access(fullname, R_OK|X_OK) == 0)
+ return fullname;
+ }
+
+ return clientname;
+}
+
+static int fat_has_cputype(struct fat_header *fh, cpu_type_t cputype)
+{
+ struct fat_arch *fa = (struct fat_arch *)(fh+1);
+ uint32_t nfat_arch = ntohl(fh->nfat_arch);
+ uint32_t i;
+ for (i = 0; i < nfat_arch; i++) {
+ if (ntohl(fa[i].cputype) == cputype) return 1;
+ }
+ return 0;
+}
+
+/* Examine the client and work out which arch it is for */
+static const char *select_arch(const char *clientname, cpu_type_t default_cputype, const char *default_arch)
+{
+ uint8_t buf[4096];
+ ssize_t bytes;
+ int fd = open(find_client(clientname), O_RDONLY);
+ if (fd < 0) {
+ barf("%s: %s", clientname, strerror(errno));
+ }
+
+ bytes = pread(fd, buf, sizeof(buf), 0);
+ if (bytes != sizeof(buf)) {
+ close(fd);
+ return NULL;
+ }
+
+ // If it's thin, return that arch.
+ {
+ struct mach_header *mh = (struct mach_header *)buf;
+ if (mh->magic == MH_MAGIC || mh->magic == MH_MAGIC_64) {
+ return name_for_cputype(mh->cputype);
+ } else if (mh->magic == MH_CIGAM || mh->magic == MH_CIGAM_64) {
+ return name_for_cputype(OSSwapInt32(mh->cputype));
+ }
+ }
+
+ // If it's fat, look for a good arch.
+ {
+ struct fat_header *fh = (struct fat_header *)buf;
+ if (ntohl(fh->magic) == FAT_MAGIC) {
+ uint32_t nfat_arch = ntohl(fh->nfat_arch);
+ int i;
+ // If only one fat arch, use it.
+ if (nfat_arch == 1) {
+ struct fat_arch *fa = (struct fat_arch *)(fh+1);
+ return name_for_cputype(ntohl(fa->cputype));
+ }
+ // Scan fat headers for default arch.
+ if (fat_has_cputype(fh, default_cputype)) {
+ return default_arch;
+ }
+
+ // Scan fat headers for any supported arch.
+ for (i = 0; i < valid_archs_count; i++) {
+ if (fat_has_cputype(fh, valid_archs[i].cputype)) {
+ return valid_archs[i].valgrind_name;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+/* Where we expect to find all our aux files */
+static const char *valgrind_lib;
+
+int main(int argc, char** argv, char** envp)
+{
+ int i, j, loglevel;
+ const char *toolname = NULL;
+ const char *clientname = NULL;
+ int clientname_arg = 0;
+ const char *archname = NULL;
+ const char *arch;
+ const char *default_arch;
+ cpu_type_t default_cputype;
+ char *toolfile;
+ char launcher_name[PATH_MAX+1];
+ char* new_line;
+ char* set_cwd;
+ char* cwd;
+ char** new_env;
+ char **new_argv;
+ int new_argc;
+
+ /* Start the debugging-log system ASAP. First find out how many
+ "-d"s were specified. This is a pre-scan of the command line.
+ At the same time, look for the tool name. */
+ loglevel = 0;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ clientname = argv[i];
+ clientname_arg = i;
+ break;
+ }
+ if (0 == strcmp(argv[i], "--")) {
+ if (i+1 < argc) {
+ clientname = argv[i+1];
+ clientname_arg = i;
+ }
+ break;
+ }
+ if (0 == strcmp(argv[i], "-d"))
+ loglevel++;
+ if (0 == strncmp(argv[i], "--tool=", 7))
+ toolname = argv[i] + 7;
+ if (0 == strncmp(argv[i], "--arch=", 7))
+ archname = argv[i] + 7;
+ }
+
+ /* ... and start the debug logger. Now we can safely emit logging
+ messages all through startup. */
+ VG_(debugLog_startup)(loglevel, "Stage 1");
+
+ /* Make sure we know which tool we're using */
+ if (toolname) {
+ VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname);
+ } else {
+ VG_(debugLog)(1, "launcher",
+ "no tool requested, defaulting to 'memcheck'\n");
+ toolname = "memcheck";
+ }
+
+ /* Find the real executable if clientname is an app bundle. */
+ if (clientname) {
+ struct stat st;
+ if (0 == stat(clientname, &st) && (st.st_mode & S_IFDIR)) {
+ char *copy = strdup(clientname);
+ char *appname = basename(copy);
+ char *dot = strrchr(appname, '.');
+ if (dot) {
+ char *newclient;
+ *dot = '\0';
+ asprintf(&newclient, "%s/Contents/MacOS/%s", clientname, appname);
+ VG_(debugLog)(1, "launcher", "Using executable in app bundle: %s\n", newclient);
+ clientname = newclient;
+ argv[clientname_arg] = newclient;
+ }
+ free(copy);
+ }
+ }
+
+ /* Establish the correct VALGRIND_LIB. */
+ { const char *cp;
+ cp = getenv(VALGRIND_LIB);
+ valgrind_lib = ( cp == NULL ? VG_LIBDIR : cp );
+ }
+
+ /* Find installed architectures. Use vgpreload_core-<platform>.so as the
+ * indicator of whether the platform is installed. */
+ for (i = 0; i < valid_archs_count; i++) {
+ char *vgpreload_core;
+ asprintf(&vgpreload_core, "%s/vgpreload_core-%s-darwin.so", valgrind_lib, valid_archs[i].valgrind_name);
+ if (access(vgpreload_core, R_OK|X_OK) != 0) {
+ VG_(debugLog)(1, "launcher", "arch '%s' IS NOT installed\n", valid_archs[i].valgrind_name);
+ bzero(&valid_archs[i], sizeof(valid_archs[i]));
+ } else {
+ VG_(debugLog)(1, "launcher", "arch '%s' IS installed\n", valid_archs[i].valgrind_name);
+ }
+ free(vgpreload_core);
+ }
+
+ /* Find the "default" arch (VGCONF_ARCH_PRI from configure).
+ This is the preferred arch from fat files and the fallback. */
+ default_arch = NULL;
+ default_cputype = 0;
+ for (i = 0; i < valid_archs_count; i++) {
+ if (!valid_archs[i].cputype) continue;
+ if (0 == strncmp(VG_PLATFORM, valid_archs[i].valgrind_name,
+ strlen(valid_archs[i].valgrind_name)))
+ {
+ default_arch = valid_archs[i].valgrind_name;
+ default_cputype = valid_archs[i].cputype;
+ break;
+ }
+ }
+ if (i == valid_archs_count) barf("Unknown/uninstalled VG_PLATFORM '%s'", VG_PLATFORM);
+ assert(NULL != default_arch);
+ assert(0 != default_cputype);
+
+ /* Work out what arch to use, or use the default arch if not possible. */
+ if (archname != NULL) {
+ // --arch from command line
+ arch = NULL;
+ for (i = 0; i < valid_archs_count; i++) {
+ if (0 == strcmp(archname, valid_archs[i].apple_name) ||
+ 0 == strcmp(archname, valid_archs[i].valgrind_name))
+ {
+ arch = valid_archs[i].valgrind_name;
+ break;
+ }
+ }
+ if (i == valid_archs_count) barf("Unknown --arch '%s'", archname);
+ assert(NULL != arch);
+ VG_(debugLog)(1, "launcher", "using arch '%s' from --arch=%s\n",
+ arch, archname);
+ }
+ else if (clientname == NULL) {
+ // no client executable; use default as fallback
+ VG_(debugLog)(1, "launcher",
+ "no client specified, defaulting arch to '%s'\n",
+ default_arch);
+ arch = default_arch;
+ }
+ else if ((arch = select_arch(clientname, default_cputype,default_arch))) {
+ // arch from client executable
+ VG_(debugLog)(1, "launcher", "selected arch '%s'\n", arch);
+ }
+ else {
+ // nothing found in client executable; use default as fallback
+ VG_(debugLog)(1, "launcher",
+ "no arch detected, defaulting arch to '%s'\n",
+ default_arch);
+ arch = default_arch;
+ }
+
+ cwd = getcwd(NULL, 0);
+ if (!cwd) barf("Current directory no longer exists.");
+
+ /* Figure out the name of this executable (viz, the launcher), so
+ we can tell stage2. stage2 will use the name for recursive
+ invokations of valgrind on child processes. */
+ memset(launcher_name, 0, PATH_MAX+1);
+ for (i = 0; envp[i]; i++)
+ ; /* executable path is after last envp item */
+ /* envp[i] == NULL ; envp[i+1] == executable_path */
+ if (envp[i+1][0] != '/') {
+ strcpy(launcher_name, cwd);
+ strcat(launcher_name, "/");
+ }
+ if (strlen(launcher_name) + strlen(envp[i+1]) > PATH_MAX)
+ barf("launcher path is too long");
+ strcat(launcher_name, envp[i+1]);
+ VG_(debugLog)(1, "launcher", "launcher_name = %s\n", launcher_name);
+
+ /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */
+ asprintf(&new_line, VALGRIND_LAUNCHER "=%s", launcher_name);
+
+ /* tediously augment the env: VALGRIND_STARTUP_PWD_%PID_XYZZY=current_working_dir */
+ asprintf(&set_cwd, "VALGRIND_STARTUP_PWD_%u_XYZZY=%s", getppid(), cwd);
+
+ // Note that Apple binaries get a secret fourth arg, "char* apple", which
+ // contains the executable path. Don't forget about it.
+ for (j = 0; envp[j]; j++)
+ ;
+ new_env = malloc((j+4) * sizeof(char*));
+ if (new_env == NULL)
+ barf("malloc of new_env failed.");
+ for (i = 0; i < j; i++)
+ new_env[i] = envp[i];
+ new_env[i++] = new_line;
+ new_env[i++] = set_cwd;
+ new_env[i++] = NULL;
+ new_env[i ] = envp[i-2]; // the 'apple' arg == the executable_path
+ assert(i == j+3);
+
+ /* tediously edit env: hide dyld options from valgrind's captive dyld */
+ for (i = 0; envp[i]; i++) {
+ if (0 == strncmp(envp[i], "DYLD_", 5)) {
+ envp[i][0] = 'V'; /* VYLD_; changed back by initimg-darwin */
+ }
+ }
+
+ /* tediously edit argv: remove --arch= */
+ new_argv = malloc((1+argc) * sizeof(char *));
+ for (i = 0, new_argc = 0; i < argc; i++) {
+ if (0 == strncmp(argv[i], "--arch=", 7)) {
+ // skip
+ } else {
+ new_argv[new_argc++] = argv[i];
+ }
+ }
+ new_argv[new_argc++] = NULL;
+
+ /* Build the stage2 invokation, and execve it. Bye! */
+ asprintf(&toolfile, "%s/%s-%s-darwin", valgrind_lib, toolname, arch);
+ if (access(toolfile, R_OK|X_OK) != 0) {
+ barf("tool '%s' not installed (%s) (%s)", toolname, toolfile, strerror(errno));
+ }
+
+ VG_(debugLog)(1, "launcher", "launching %s\n", toolfile);
+
+ execve(toolfile, new_argv, new_env);
+
+ fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s-darwin': %s\n",
+ toolname, arch, strerror(errno));
+
+ exit(1);
+}
diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c
index 62c21da..b8a7dd8 100644
--- a/coregrind/m_aspacemgr/aspacemgr-common.c
+++ b/coregrind/m_aspacemgr/aspacemgr-common.c
@@ -160,6 +160,18 @@
|| defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
prot, flags, fd, offset);
+# elif defined(VGP_x86_darwin)
+ if (fd == 0 && (flags & VKI_MAP_ANONYMOUS)) {
+ fd = -1; // MAP_ANON with fd==0 is EINVAL
+ }
+ res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length,
+ prot, flags, fd, offset & 0xffffffff, offset >> 32);
+# elif defined(VGP_amd64_darwin)
+ if (fd == 0 && (flags & VKI_MAP_ANONYMOUS)) {
+ fd = -1; // MAP_ANON with fd==0 is EINVAL
+ }
+ res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length,
+ prot, flags, (UInt)fd, offset);
# else
# error Unknown platform
# endif
@@ -177,6 +189,9 @@
return VG_(do_syscall2)(__NR_munmap, (UWord)start, length );
}
+#if HAVE_MREMAP
+/* The following are used only to implement mremap(). */
+
SysRes ML_(am_do_extend_mapping_NO_NOTIFY)(
Addr old_addr,
SizeT old_len,
@@ -227,6 +242,8 @@
# endif
}
+#endif
+
/* --- Pertaining to files --- */
SysRes ML_(am_open) ( const Char* pathname, Int flags, Int mode )
@@ -257,6 +274,8 @@
{
# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
# else
# error "Unknown OS"
# endif
@@ -310,6 +329,17 @@
I_die_here; /* maybe just return False? */
return False;
+#elif defined(VGO_darwin)
+ HChar tmp[VKI_MAXPATHLEN+1];
+ if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
+ if (nbuf > 0) {
+ VG_(strncpy)( buf, tmp, nbuf < sizeof(tmp) ? nbuf : sizeof(tmp) );
+ buf[nbuf-1] = 0;
+ }
+ if (tmp[0] == '/') return True;
+ }
+ return False;
+
# else
# error Unknown OS
# endif
diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c
index 4f09b67..0af3bb5 100644
--- a/coregrind/m_aspacemgr/aspacemgr-linux.c
+++ b/coregrind/m_aspacemgr/aspacemgr-linux.c
@@ -3,7 +3,7 @@
/*--- The address space manager: segment initialisation and ---*/
/*--- tracking, stack operations ---*/
/*--- ---*/
-/*--- Implementation for Linux m_aspacemgr-linux.c ---*/
+/*--- Implementation for Linux (and Darwin!) m_aspacemgr-linux.c ---*/
/*--------------------------------------------------------------------*/
/*
@@ -848,9 +848,11 @@
/* If a problem has already been detected, don't continue comparing
segments, so as to avoid flooding the output with error
messages. */
+#if !defined(VGO_darwin)
+ /* GrP fixme not */
if (!sync_check_ok)
return;
-
+#endif
if (len == 0)
return;
@@ -911,7 +913,7 @@
= nsegments[i].dev != 0 || nsegments[i].ino != 0;
/* Consider other reasons to not compare dev/inode */
-
+#if defined(VGO_linux)
/* bproc does some godawful hack on /dev/zero at process
migration, which changes the name of it, and its dev & ino */
if (filename && 0==VG_(strcmp)(filename, "/dev/zero (deleted)"))
@@ -920,7 +922,16 @@
/* hack apparently needed on MontaVista Linux */
if (filename && VG_(strstr)(filename, "/.lib-ro/"))
cmp_devino = False;
+#endif
+#if defined(VGO_darwin)
+ // GrP fixme kernel info doesn't have dev/inode
+ cmp_devino = False;
+
+ // GrP fixme V and kernel don't agree on offsets
+ cmp_offsets = False;
+#endif
+
/* If we are doing sloppy execute permission checks then we
allow segment to have X permission when we weren't expecting
it (but not vice versa) so if the kernel reported execute
@@ -971,9 +982,11 @@
/* If a problem has already been detected, don't continue comparing
segments, so as to avoid flooding the output with error
messages. */
+#if !defined(VGO_darwin)
+ /* GrP fixme not */
if (!sync_check_ok)
return;
-
+#endif
if (len == 0)
return;
@@ -1517,6 +1530,11 @@
seg.kind = SkAnonV;
if (dev != 0 && ino != 0)
seg.kind = SkFileV;
+#if defined(VGO_darwin)
+ // GrP fixme no dev/ino on darwin
+ if (offset != 0)
+ seg.kind = SkFileV;
+#endif
if (filename)
seg.fnIdx = allocate_segname( filename );
@@ -1558,6 +1576,27 @@
nsegments[0] = seg;
nsegments_used = 1;
+#if defined(VGO_darwin)
+
+# if VG_WORDSIZE == 4
+ aspacem_minAddr = (Addr) 0x00001000;
+ aspacem_maxAddr = (Addr) 0xffffffff;
+
+ aspacem_cStart = aspacem_minAddr;
+ aspacem_vStart = 0xf0000000; // 0xc0000000..0xf0000000 available
+# else
+ aspacem_minAddr = (Addr) 0x100000000; // 4GB page zero
+ aspacem_maxAddr = (Addr) 0x7fffffffffff;
+
+ aspacem_cStart = aspacem_minAddr;
+ aspacem_vStart = 0x700000000000; // 0x7000:00000000..0x7fff:5c000000 avail
+ // 0x7fff:5c000000..0x7fff:ffe00000? is stack, dyld, shared cache
+# endif
+
+ suggested_clstack_top = -1; // ignored; Mach-O specifies its stack
+
+#else
+
/* Establish address limits and block out unusable parts
accordingly. */
@@ -1588,6 +1627,8 @@
suggested_clstack_top = aspacem_maxAddr - 16*1024*1024ULL
+ VKI_PAGE_SIZE;
+#endif
+
aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr));
aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_maxAddr + 1));
aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_cStart));
@@ -2090,6 +2131,12 @@
SysRes VG_(am_mmap_file_fixed_client)
( Addr start, SizeT length, UInt prot, Int fd, Off64T offset )
{
+ return VG_(am_mmap_named_file_fixed_client)(start, length, prot, fd, offset, NULL);
+}
+
+SysRes VG_(am_mmap_named_file_fixed_client)
+ ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name )
+{
SysRes sres;
NSegment seg;
Addr advised;
@@ -2116,6 +2163,7 @@
/* We have been advised that the mapping is allowable at the
specified address. So hand it off to the kernel, and propagate
any resulting failure immediately. */
+ // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sres = VG_(am_do_mmap_NO_NOTIFY)(
start, length, prot,
VKI_MAP_FIXED|VKI_MAP_PRIVATE,
@@ -2146,7 +2194,9 @@
seg.ino = ino;
seg.mode = mode;
}
- if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
+ if (name) {
+ seg.fnIdx = allocate_segname( name );
+ } else if (ML_(am_resolve_filename)(fd, buf, VKI_PATH_MAX)) {
seg.fnIdx = allocate_segname( buf );
}
add_segment( &seg );
@@ -2182,6 +2232,7 @@
/* We have been advised that the mapping is allowable at the
specified address. So hand it off to the kernel, and propagate
any resulting failure immediately. */
+ // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sres = VG_(am_do_mmap_NO_NOTIFY)(
start, length, prot,
VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
@@ -2239,6 +2290,7 @@
/* We have been advised that the mapping is allowable at the
advised address. So hand it off to the kernel, and propagate
any resulting failure immediately. */
+ // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sres = VG_(am_do_mmap_NO_NOTIFY)(
advised, length, prot,
VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
@@ -2309,18 +2361,41 @@
if (!ok)
return VG_(mk_SysRes_Error)( VKI_EINVAL );
+// On Darwin, for anonymous maps you can pass in a tag which is used by
+// programs like vmmap for statistical purposes.
+#ifndef VM_TAG_VALGRIND
+# define VM_TAG_VALGRIND 0
+#endif
+
/* We have been advised that the mapping is allowable at the
specified address. So hand it off to the kernel, and propagate
any resulting failure immediately. */
+ /* GrP fixme darwin: use advisory as a hint only, otherwise syscall in
+ another thread can pre-empt our spot. [At one point on the DARWIN
+ branch the VKI_MAP_FIXED was commented out; unclear if this is
+ necessary or not given the second Darwin-only call that immediately
+ follows if this one fails. --njn] */
sres = VG_(am_do_mmap_NO_NOTIFY)(
advised, length,
VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
- 0, 0
+ VM_TAG_VALGRIND, 0
);
+#if defined(VGO_darwin)
+ if (sr_isError(sres)) {
+ /* try again, ignoring the advisory */
+ sres = VG_(am_do_mmap_NO_NOTIFY)(
+ 0, length,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
+ /*VKI_MAP_FIXED|*/VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS,
+ VM_TAG_VALGRIND, 0
+ );
+ }
+#endif
if (sr_isError(sres))
return sres;
+#if defined(VGO_linux)
if (sr_Res(sres) != advised) {
/* I don't think this can happen. It means the kernel made a
fixed map succeed but not at the requested location. Try to
@@ -2328,6 +2403,7 @@
(void)ML_(am_do_munmap_NO_NOTIFY)( sr_Res(sres), length );
return VG_(mk_SysRes_Error)( VKI_EINVAL );
}
+#endif
/* Ok, the mapping succeeded. Now notify the interval map. */
init_nsegment( &seg );
@@ -2687,6 +2763,7 @@
return False;
/* Extend the kernel's mapping. */
+ // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sres = VG_(am_do_mmap_NO_NOTIFY)(
nsegments[segR].start, delta,
prot,
@@ -2722,6 +2799,7 @@
return False;
/* Extend the kernel's mapping. */
+ // DDD: #warning GrP fixme MAP_FIXED can clobber memory!
sres = VG_(am_do_mmap_NO_NOTIFY)(
nsegments[segA].start-delta, delta,
prot,
@@ -2750,6 +2828,8 @@
/* --- --- --- resizing/move a mapping --- --- --- */
+#if HAVE_MREMAP
+
/* Let SEG be a client mapping (anonymous or file). This fn extends
the mapping forwards only by DELTA bytes, and trashes whatever was
in the new area. Fails if SEG is not a single client mapping or if
@@ -2894,6 +2974,10 @@
return True;
}
+#endif // HAVE_MREMAP
+
+
+#if HAVE_PROC
/*-----------------------------------------------------------------*/
/*--- ---*/
@@ -3192,6 +3276,202 @@
(*record_gap) ( gapStart, Addr_MAX - gapStart + 1 );
}
+#elif defined(VGO_darwin)
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+
+static unsigned int mach2vki(unsigned int vm_prot)
+{
+ return
+ ((vm_prot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
+ ((vm_prot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
+ ((vm_prot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0) ;
+}
+
+static UInt stats_machcalls = 0;
+
+static void parse_procselfmaps (
+ void (*record_mapping)( Addr addr, SizeT len, UInt prot,
+ ULong dev, ULong ino, Off64T offset,
+ const UChar* filename ),
+ void (*record_gap)( Addr addr, SizeT len )
+ )
+{
+ vm_address_t iter;
+ unsigned int depth;
+ vm_address_t last;
+
+ iter = 0;
+ depth = 0;
+ last = 0;
+ while (1) {
+ mach_vm_address_t addr = iter;
+ mach_vm_size_t size;
+ vm_region_submap_short_info_data_64_t info;
+ kern_return_t kr;
+
+ while (1) {
+ mach_msg_type_number_t info_count
+ = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
+ stats_machcalls++;
+ kr = mach_vm_region_recurse(mach_task_self(), &addr, &size, &depth,
+ (vm_region_info_t)&info, &info_count);
+ if (kr)
+ return;
+ if (info.is_submap) {
+ depth++;
+ continue;
+ }
+ break;
+ }
+ iter = addr + size;
+
+ if (addr > last && record_gap) {
+ (*record_gap)(last, addr - last);
+ }
+ if (record_mapping) {
+ (*record_mapping)(addr, size, mach2vki(info.protection),
+ 0, 0, info.offset, NULL);
+ }
+ last = addr + size;
+ }
+
+ if ((Addr)-1 > last && record_gap)
+ (*record_gap)(last, (Addr)-1 - last);
+}
+
+ChangedSeg* css_local;
+Int css_size_local;
+Int css_used_local;
+
+static void add_mapping_callback(Addr addr, SizeT len, UInt prot,
+ ULong dev, ULong ino, Off64T offset,
+ const UChar *filename)
+{
+ // derived from sync_check_mapping_callback()
+
+ Int iLo, iHi, i;
+
+ if (len == 0) return;
+
+ /* The kernel should not give us wraparounds. */
+ aspacem_assert(addr <= addr + len - 1);
+
+ iLo = find_nsegment_idx( addr );
+ iHi = find_nsegment_idx( addr + len - 1 );
+
+
+ /* NSegments iLo .. iHi inclusive should agree with the presented
+ data. */
+ for (i = iLo; i <= iHi; i++) {
+
+ UInt seg_prot;
+
+ if (nsegments[i].kind == SkAnonV || nsegments[i].kind == SkFileV) {
+ /* Ignore V regions */
+ continue;
+ }
+ else if (nsegments[i].kind == SkFree || nsegments[i].kind == SkResvn) {
+ /* Add mapping for SkResvn regions */
+ ChangedSeg* cs = &css_local[css_used_local];
+ aspacem_assert(css_used_local < css_size_local);
+ cs->is_added = True;
+ cs->start = addr;
+ cs->end = addr + len - 1;
+ cs->prot = prot;
+ cs->offset = offset;
+ css_used_local++;
+ return;
+
+ } else if (nsegments[i].kind == SkAnonC ||
+ nsegments[i].kind == SkFileC ||
+ nsegments[i].kind == SkShmC)
+ {
+ /* Check permissions on client regions */
+ // GrP fixme
+ seg_prot = 0;
+ if (nsegments[i].hasR) seg_prot |= VKI_PROT_READ;
+ if (nsegments[i].hasW) seg_prot |= VKI_PROT_WRITE;
+# if defined(VGA_x86)
+ // GrP fixme sloppyXcheck
+ // darwin: kernel X ignored and spuriously changes? (vm_copy)
+ seg_prot |= (prot & VKI_PROT_EXEC);
+# else
+ if (nsegments[i].hasX) seg_prot |= VKI_PROT_EXEC;
+# endif
+ if (seg_prot != prot) {
+ if (VG_(clo_trace_syscalls))
+ VG_(debugLog)(0,"aspacem","\nregion %p..%p permission "
+ "mismatch (kernel %x, V %x)",
+ (void*)nsegments[i].start,
+ (void*)(nsegments[i].end+1), prot, seg_prot);
+ }
+
+ } else {
+ aspacem_assert(0);
+ }
+ }
+}
+
+static void remove_mapping_callback(Addr addr, SizeT len)
+{
+ // derived from sync_check_gap_callback()
+
+ Int iLo, iHi, i;
+
+ if (len == 0)
+ return;
+
+ /* The kernel should not give us wraparounds. */
+ aspacem_assert(addr <= addr + len - 1);
+
+ iLo = find_nsegment_idx( addr );
+ iHi = find_nsegment_idx( addr + len - 1 );
+
+ /* NSegments iLo .. iHi inclusive should agree with the presented data. */
+ for (i = iLo; i <= iHi; i++) {
+ if (nsegments[i].kind != SkFree && nsegments[i].kind != SkResvn) {
+ // V has a mapping, kernel doesn't
+ ChangedSeg* cs = &css_local[css_used_local];
+ aspacem_assert(css_used_local < css_size_local);
+ cs->is_added = True;
+ cs->is_added = False;
+ cs->start = nsegments[i].start;
+ cs->end = nsegments[i].end;
+ cs->prot = 0;
+ cs->offset = 0;
+ css_used_local++;
+ return;
+ }
+ }
+}
+
+
+void VG_(get_changed_segments)(
+ const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
+ Int css_size, /*OUT*/Int* css_used)
+{
+ static UInt stats_synccalls = 1;
+ aspacem_assert(when && where);
+
+ if (0)
+ VG_(debugLog)(0,"aspacem",
+ "[%u,%u] VG_(get_changed_segments)(%s, %s)\n",
+ stats_synccalls++, stats_machcalls, when, where
+ );
+
+ css_local = css;
+ css_size_local = css_size;
+ css_used_local = 0;
+
+ // Get the list of segs that need to be added/removed.
+ parse_procselfmaps(&add_mapping_callback, &remove_mapping_callback);
+
+ *css_used = css_used_local;
+}
+
+#endif
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_coredump/coredump-amd64-darwin.c b/coregrind/m_coredump/coredump-amd64-darwin.c
new file mode 100644
index 0000000..6b18f32
--- /dev/null
+++ b/coregrind/m_coredump/coredump-amd64-darwin.c
@@ -0,0 +1,39 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Dumping core. coredump-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_coredump.h"
+#include "pub_core_threadstate.h"
+
+void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
+{
+ // DDD: #warning GrP fixme coredump
+}
diff --git a/coregrind/m_coredump/coredump-x86-darwin.c b/coregrind/m_coredump/coredump-x86-darwin.c
new file mode 100644
index 0000000..3618113
--- /dev/null
+++ b/coregrind/m_coredump/coredump-x86-darwin.c
@@ -0,0 +1,39 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Dumping core. coredump-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_coredump.h"
+#include "pub_core_threadstate.h"
+
+void VG_(make_coredump)(ThreadId tid, const vki_siginfo_t *si, UInt max_size)
+{
+ // DDD: #warning GrP fixme coredump
+}
diff --git a/coregrind/m_debugger.c b/coregrind/m_debugger.c
index de28e36..1bc9fe5 100644
--- a/coregrind/m_debugger.c
+++ b/coregrind/m_debugger.c
@@ -211,6 +211,12 @@
#elif defined(VGP_ppc64_aix5)
I_die_here;
+#elif defined(VGP_x86_darwin)
+ I_die_here;
+
+#elif defined(VGP_amd64_darwin)
+ I_die_here;
+
#else
# error Unknown arch
#endif
diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c
index f561c4c..055f814 100644
--- a/coregrind/m_debuginfo/d3basics.c
+++ b/coregrind/m_debuginfo/d3basics.c
@@ -379,10 +379,10 @@
static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, RegSummary* regs )
{
vg_assert(regs);
-# if defined(VGP_x86_linux)
+# if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
if (regno == 5/*EBP*/) { *a = regs->fp; return True; }
if (regno == 4/*ESP*/) { *a = regs->sp; return True; }
-# elif defined(VGP_amd64_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
if (regno == 6/*RBP*/) { *a = regs->fp; return True; }
if (regno == 7/*RSP*/) { *a = regs->sp; return True; }
# elif defined(VGP_ppc32_linux)
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index d9d9217..4ec85c8 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -51,6 +51,7 @@
#include "pub_core_xarray.h"
#include "pub_core_oset.h"
#include "pub_core_stacktrace.h" // VG_(get_StackTrace) XXX: circular dependency
+#include "pub_core_ume.h"
#include "priv_misc.h" /* dinfo_zalloc/free */
#include "priv_d3basics.h" /* ML_(pp_GX) */
@@ -67,6 +68,9 @@
# include "pub_core_libcproc.h"
# include "pub_core_libcfile.h"
# include "priv_readxcoff.h"
+#elif defined(VGO_darwin)
+# include "priv_readmacho.h"
+# include "priv_readpdb.h"
#endif
@@ -576,7 +580,7 @@
/*--- ---*/
/*--------------------------------------------------------------*/
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_darwin)
/* The debug info system is driven by notifications that a text
segment has been mapped in, or unmapped. When that happens it
@@ -703,11 +707,10 @@
*/
is_rx_map = False;
is_rw_map = False;
-# if defined(VGP_x86_linux)
+# if defined(VGA_x86)
is_rx_map = seg->hasR && seg->hasX;
is_rw_map = seg->hasR && seg->hasW;
-# elif defined(VGP_amd64_linux) \
- || defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
+# elif defined(VGA_amd64) || defined(VGA_ppc32) || defined(VGA_ppc64)
is_rx_map = seg->hasR && seg->hasX && !seg->hasW;
is_rw_map = seg->hasR && seg->hasW && !seg->hasX;
# else
@@ -750,8 +753,15 @@
vg_assert(nread > 0 && nread <= sizeof(buf1k) );
/* We're only interested in mappings of ELF object files. */
+#if defined(HAVE_ELF)
if (!ML_(is_elf_object_file)( buf1k, (SizeT)nread ))
return 0;
+#elif defined(HAVE_MACHO)
+ if (!ML_(is_macho_object_file)( buf1k, (SizeT)nread ))
+ return 0;
+#else
+# error "unknown executable type"
+#endif
/* See if we have a DebugInfo for this filename. If not,
create one. */
@@ -803,7 +813,13 @@
discard_DebugInfos_which_overlap_with( di );
/* .. and acquire new info. */
+#if defined(HAVE_ELF)
ok = ML_(read_elf_debug_info)( di );
+#elif defined(HAVE_MACHO)
+ ok = ML_(read_macho_debug_info)( di );
+#else
+# error "unknown executable type"
+#endif
if (ok) {
@@ -863,7 +879,7 @@
void VG_(di_notify_mprotect)( Addr a, SizeT len, UInt prot )
{
Bool exe_ok = toBool(prot & VKI_PROT_EXEC);
-# if defined(VGP_x86_linux)
+# if defined(VGA_x86)
exe_ok = exe_ok || toBool(prot & VKI_PROT_READ);
# endif
if (0 && !exe_ok) {
@@ -1383,6 +1399,9 @@
VG_STREQ("generic_start_main", name) || // Yellow Dog doggedness
#elif defined(VGO_aix5)
VG_STREQ("__start", name) || // AIX aches
+#elif defined(VGO_darwin)
+ // See readmacho.c for an explanation of this.
+ VG_STREQ("start_according_to_valgrind", name) || // Darwin, darling
#else
# error Unknown OS
#endif
@@ -3384,7 +3403,6 @@
}
-
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/priv_readmacho.h b/coregrind/m_debuginfo/priv_readmacho.h
new file mode 100644
index 0000000..e9da383
--- /dev/null
+++ b/coregrind/m_debuginfo/priv_readmacho.h
@@ -0,0 +1,52 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from Mach-O files. ---*/
+/*--- priv_readmacho.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PRIV_READMACHO_H
+#define __PRIV_READMACHO_H
+
+/* Identify a Mach-O object file by peering at the first few bytes of
+ it. */
+extern Bool ML_(is_macho_object_file)( const void* buf, SizeT size );
+
+/* The central function for reading Mach-O debug info. For the
+ object/exe specified by the DebugInfo, find Mach-O sections, then read
+ the symbols, line number info, file name info, CFA (stack-unwind
+ info) and anything else we want, into the tables within the
+ supplied DebugInfo.
+*/
+extern Bool ML_(read_macho_debug_info) ( struct _DebugInfo* si );
+
+
+#endif /* ndef __PRIV_READMACHO_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/priv_storage.h b/coregrind/m_debuginfo/priv_storage.h
index 9749b24..f6e6e82 100644
--- a/coregrind/m_debuginfo/priv_storage.h
+++ b/coregrind/m_debuginfo/priv_storage.h
@@ -619,6 +619,12 @@
UChar* dirname, /* NULL is allowable */
Addr this, Addr next, Int lineno, Int entry);
+/* Shrink completed tables to save memory. */
+extern
+void ML_(shrinkSym) ( struct _DebugInfo *di );
+extern
+void ML_(shrinkLineInfo) ( struct _DebugInfo *di );
+
/* Add a CFI summary record. The supplied DiCfSI is copied. */
extern void ML_(addDiCfSI) ( struct _DebugInfo* di, DiCfSI* cfsi );
diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c
index 30df436..69000e6 100644
--- a/coregrind/m_debuginfo/readdwarf.c
+++ b/coregrind/m_debuginfo/readdwarf.c
@@ -1785,6 +1785,14 @@
# define FP_REG 1
# define SP_REG 1
# define RA_REG_DEFAULT 8 // CAB: What's a good default ?
+#elif defined(VGP_x86_darwin)
+# define FP_REG 5
+# define SP_REG 4
+# define RA_REG_DEFAULT 8
+#elif defined(VGP_amd64_darwin)
+# define FP_REG 6
+# define SP_REG 7
+# define RA_REG_DEFAULT 16
#else
# error "Unknown platform"
#endif
diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c
index d8eed6a..d94b17d 100644
--- a/coregrind/m_debuginfo/readdwarf3.c
+++ b/coregrind/m_debuginfo/readdwarf3.c
@@ -138,6 +138,7 @@
#include "pub_core_libcassert.h"
#include "pub_core_libcprint.h"
#include "pub_core_options.h"
+#include "pub_core_tooliface.h" /* VG_(needs) */
#include "pub_core_xarray.h"
#include "pub_core_wordfm.h"
#include "priv_misc.h" /* dinfo_zalloc/free */
@@ -3903,6 +3904,7 @@
TRACE_SYMTAB("\n");
#endif
+
/*--------------------------------------------------------------------*/
/*--- end readdwarf3.c ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/readmacho.c b/coregrind/m_debuginfo/readmacho.c
new file mode 100644
index 0000000..76293ad
--- /dev/null
+++ b/coregrind/m_debuginfo/readmacho.c
@@ -0,0 +1,1095 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Reading of syms & debug info from Mach-O files. ---*/
+/*--- readmacho.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_aspacemgr.h" /* for mmaping debuginfo files */
+#include "pub_core_machine.h" /* VG_ELF_CLASS */
+#include "pub_core_options.h"
+#include "pub_core_oset.h"
+#include "pub_core_tooliface.h" /* VG_(needs) */
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuginfo.h"
+
+#include "priv_d3basics.h"
+#include "priv_misc.h"
+#include "priv_tytypes.h"
+#include "priv_storage.h"
+#include "priv_readmacho.h"
+#include "priv_readdwarf.h"
+#include "priv_readdwarf3.h"
+#include "priv_readstabs.h"
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/fat.h>
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+#if VG_WORDSIZE == 4
+# define MAGIC MH_MAGIC
+# define MACH_HEADER mach_header
+# define LC_SEGMENT_CMD LC_SEGMENT
+# define SEGMENT_COMMAND segment_command
+# define SECTION section
+# define NLIST nlist
+#else
+# define MAGIC MH_MAGIC_64
+# define MACH_HEADER mach_header_64
+# define LC_SEGMENT_CMD LC_SEGMENT_64
+# define SEGMENT_COMMAND segment_command_64
+# define SECTION section_64
+# define NLIST nlist_64
+#endif
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Mach-O file mapping/unmapping helpers ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+typedef
+ struct {
+ /* These two describe the entire mapped-in ("primary") image,
+ fat headers, kitchen sink, whatnot: the entire file. The
+ image is mapped into img[0 .. img_szB-1]. */
+ UChar* img;
+ SizeT img_szB;
+ /* These two describe the Mach-O object of interest, which is
+ presumably somewhere inside the primary image.
+ map_image_aboard() below, which generates this info, will
+ carefully check that the macho_ fields denote a section of
+ memory that falls entirely inside img[0 .. img_szB-1]. */
+ UChar* macho_img;
+ SizeT macho_img_szB;
+ }
+ ImageInfo;
+
+
+Bool ML_(is_macho_object_file)( const void* buf, SizeT szB )
+{
+ /* (JRS: the Mach-O headers might not be in this mapped data,
+ because we only mapped a page for this initial check,
+ or at least not very much, and what's at the start of the file
+ is in general a so-called fat header. The Mach-O object we're
+ interested in could be arbitrarily far along the image, and so
+ we can't assume its header will fall within this page.) */
+
+ /* But we can say that either it's a fat object, in which case it
+ begins with a fat header, or it's unadorned Mach-O, in which
+ case it starts with a normal header. At least do what checks we
+ can to establish whether or not we're looking at something
+ sane. */
+
+ const struct fat_header* fh_be = buf;
+ const struct MACH_HEADER* mh = buf;
+
+ vg_assert(buf);
+ if (szB < sizeof(struct fat_header))
+ return False;
+ if (VG_(ntohl)(fh_be->magic) == FAT_MAGIC)
+ return True;
+
+ if (szB < sizeof(struct MACH_HEADER))
+ return False;
+ if (mh->magic == MAGIC)
+ return True;
+
+ return False;
+}
+
+
+/* Unmap an image mapped in by map_image_aboard. */
+static void unmap_image ( /*MOD*/ImageInfo* ii )
+{
+ SysRes sres;
+ vg_assert(ii->img);
+ vg_assert(ii->img_szB > 0);
+ sres = VG_(am_munmap_valgrind)( (Addr)ii->img, ii->img_szB );
+ /* Do we care if this fails? I suppose so; it would indicate
+ some fairly serious snafu with the mapping of the file. */
+ vg_assert( !sr_isError(sres) );
+ VG_(memset)(ii, 0, sizeof(*ii));
+}
+
+
+/* Map a given fat or thin object aboard, find the thin part if
+ necessary, do some checks, and write details of both the fat and
+ thin parts into *ii. Returns False (and leaves the file unmapped)
+ on failure. Guarantees to return pointers to a valid(ish) Mach-O
+ image if it succeeds. */
+static Bool map_image_aboard ( DebugInfo* di, /* only for err msgs */
+ /*OUT*/ImageInfo* ii, UChar* filename )
+{
+ VG_(memset)(ii, 0, sizeof(*ii));
+
+ /* First off, try to map the thing in. */
+ { SizeT size;
+ SysRes fd, sres;
+ struct vg_stat stat_buf;
+
+ fd = VG_(stat)(filename, &stat_buf);
+ if (sr_isError(fd)) {
+ ML_(symerr)(di, True, "Can't stat image (to determine its size)?!");
+ return False;
+ }
+ size = stat_buf.size;
+
+ fd = VG_(open)(filename, VKI_O_RDONLY, 0);
+ if (sr_isError(fd)) {
+ ML_(symerr)(di, True, "Can't open image to read symbols?!");
+ return False;
+ }
+
+ sres = VG_(am_mmap_file_float_valgrind)
+ ( size, VKI_PROT_READ, sr_Res(fd), 0 );
+ if (sr_isError(sres)) {
+ ML_(symerr)(di, True, "Can't mmap image to read symbols?!");
+ return False;
+ }
+
+ VG_(close)(sr_Res(fd));
+
+ ii->img = (UChar*)sr_Res(sres);
+ ii->img_szB = size;
+ }
+
+ /* Now it's mapped in and we have .img and .img_szB set. Look for
+ the embedded Mach-O object. If not findable, unmap and fail. */
+ { struct fat_header* fh_be;
+ struct fat_header fh;
+ struct MACH_HEADER* mh;
+
+ // Assume initially that we have a thin image, and update
+ // these if it turns out to be fat.
+ ii->macho_img = ii->img;
+ ii->macho_img_szB = ii->img_szB;
+
+ // Check for fat header.
+ if (ii->img_szB < sizeof(struct fat_header)) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (0 too small).");
+ goto unmap_and_fail;
+ }
+
+ // Fat header is always BIG-ENDIAN
+ fh_be = (struct fat_header *)ii->img;
+ fh.magic = VG_(ntohl)(fh_be->magic);
+ fh.nfat_arch = VG_(ntohl)(fh_be->nfat_arch);
+ if (fh.magic == FAT_MAGIC) {
+ // Look for a good architecture.
+ struct fat_arch *arch_be;
+ struct fat_arch arch;
+ Int f;
+ if (ii->img_szB < sizeof(struct fat_header)
+ + fh.nfat_arch * sizeof(struct fat_arch)) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (1 too small).");
+ goto unmap_and_fail;
+ }
+ for (f = 0, arch_be = (struct fat_arch *)(fh_be+1);
+ f < fh.nfat_arch;
+ f++, arch_be++) {
+ Int cputype;
+# if defined(VGA_ppc)
+ cputype = CPU_TYPE_POWERPC;
+# elif defined(VGA_ppc64)
+ cputype = CPU_TYPE_POWERPC64;
+# elif defined(VGA_x86)
+ cputype = CPU_TYPE_X86;
+# elif defined(VGA_amd64)
+ cputype = CPU_TYPE_X86_64;
+# else
+# error "unknown architecture"
+# endif
+ arch.cputype = VG_(ntohl)(arch_be->cputype);
+ arch.cpusubtype = VG_(ntohl)(arch_be->cpusubtype);
+ arch.offset = VG_(ntohl)(arch_be->offset);
+ arch.size = VG_(ntohl)(arch_be->size);
+ if (arch.cputype == cputype) {
+ if (ii->img_szB < arch.offset + arch.size) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (2 too small).");
+ goto unmap_and_fail;
+ }
+ ii->macho_img = ii->img + arch.offset;
+ ii->macho_img_szB = arch.size;
+ break;
+ }
+ }
+ if (f == fh.nfat_arch) {
+ ML_(symerr)(di, True,
+ "No acceptable architecture found in fat file.");
+ goto unmap_and_fail;
+ }
+ }
+
+ /* Sanity check what we found. */
+
+ /* assured by logic above */
+ vg_assert(ii->img_szB >= sizeof(struct fat_header));
+
+ if (ii->macho_img_szB < sizeof(struct MACH_HEADER)) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (3 too small).");
+ goto unmap_and_fail;
+ }
+
+ if (ii->macho_img_szB > ii->img_szB) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (thin bigger than fat).");
+ goto unmap_and_fail;
+ }
+
+ if (ii->macho_img >= ii->img
+ && ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB) {
+ /* thin entirely within fat, as expected */
+ } else {
+ ML_(symerr)(di, True, "Invalid Mach-O file (thin not inside fat).");
+ goto unmap_and_fail;
+ }
+
+ mh = (struct MACH_HEADER *)ii->macho_img;
+ if (mh->magic != MAGIC) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (bad magic).");
+ goto unmap_and_fail;
+ }
+
+ if (ii->macho_img_szB < sizeof(struct MACH_HEADER) + mh->sizeofcmds) {
+ ML_(symerr)(di, True, "Invalid Mach-O file (4 too small).");
+ goto unmap_and_fail;
+ }
+ }
+
+ vg_assert(ii->img);
+ vg_assert(ii->macho_img);
+ vg_assert(ii->img_szB > 0);
+ vg_assert(ii->macho_img_szB > 0);
+ vg_assert(ii->macho_img >= ii->img);
+ vg_assert(ii->macho_img + ii->macho_img_szB <= ii->img + ii->img_szB);
+ return True; /* success */
+ /*NOTREACHED*/
+
+ unmap_and_fail:
+ unmap_image(ii);
+ return False; /* bah! */
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Mach-O symbol table reading ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* Read a symbol table (nlist). Add the resulting candidate symbols
+ to 'syms'; the caller will post-process them and hand them off to
+ ML_(addSym) itself. */
+static
+void read_symtab( /*OUT*/XArray* /* DiSym */ syms,
+ struct _DebugInfo* di,
+ struct NLIST* o_symtab, UInt o_symtab_count,
+ UChar* o_strtab, UInt o_strtab_sz )
+{
+ Int i;
+ Addr sym_addr;
+ DiSym risym;
+ UChar* name;
+
+ static UChar* s_a_t_v = NULL; /* do not make non-static */
+
+ for (i = 0; i < o_symtab_count; i++) {
+ struct NLIST *nl = o_symtab+i;
+ if ((nl->n_type & N_TYPE) == N_SECT) {
+ sym_addr = di->text_bias + nl->n_value;
+ /*} else if ((nl->n_type & N_TYPE) == N_ABS) {
+ GrP fixme don't ignore absolute symbols?
+ sym_addr = nl->n_value; */
+ } else {
+ continue;
+ }
+
+ if (di->trace_symtab)
+ VG_(printf)("nlist raw: avma %010lx %s\n",
+ sym_addr, o_strtab + nl->n_un.n_strx );
+
+ /* If no part of the symbol falls within the mapped range,
+ ignore it. */
+ if (sym_addr <= di->text_avma
+ || sym_addr >= di->text_avma+di->text_size) {
+ continue;
+ }
+
+ /* skip names which point outside the string table;
+ following these risks segfaulting Valgrind */
+ name = o_strtab + nl->n_un.n_strx;
+ if (name < o_strtab || name >= o_strtab + o_strtab_sz)
+ continue;
+
+ /* skip nameless symbols; these appear to be common, but
+ useless */
+ if (*name == 0)
+ continue;
+
+ risym.tocptr = 0;
+ risym.addr = sym_addr;
+ risym.size = // let canonicalize fix it
+ di->text_avma+di->text_size - sym_addr;
+ risym.name = ML_(addStr)(di, name, -1);
+ risym.isText = True;
+ // Lots of user function names get prepended with an underscore. Eg. the
+ // function 'f' becomes the symbol '_f'. And the "below main"
+ // function is called "start". So we skip the leading underscore, and
+ // if we see 'start' and --show-below-main=no, we rename it as
+ // "start_according_to_valgrind", which makes it easy to spot later
+ // and display as "(below main)".
+ if (risym.name[0] == '_') {
+ risym.name++;
+ } else if (!VG_(clo_show_below_main) && VG_STREQ(risym.name, "start")) {
+ if (s_a_t_v == NULL)
+ s_a_t_v = ML_(addStr)(di, "start_according_to_valgrind", -1);
+ vg_assert(s_a_t_v);
+ risym.name = s_a_t_v;
+ }
+
+ vg_assert(risym.name);
+ VG_(addToXA)( syms, &risym );
+ }
+}
+
+
+/* Compare DiSyms by their start address, and for equal addresses, use
+ the name as a secondary sort key. */
+static Int cmp_DiSym_by_start_then_name ( void* v1, void* v2 )
+{
+ DiSym* s1 = (DiSym*)v1;
+ DiSym* s2 = (DiSym*)v2;
+ if (s1->addr < s2->addr) return -1;
+ if (s1->addr > s2->addr) return 1;
+ return VG_(strcmp)(s1->name, s2->name);
+}
+
+/* 'cand' is a bunch of candidate symbols obtained by reading
+ nlist-style symbol table entries. Their ends may overlap, so sort
+ them and truncate them accordingly. The code in this routine is
+ copied almost verbatim from read_symbol_table() in readxcoff.c. */
+static void tidy_up_cand_syms ( /*MOD*/XArray* /* of DiSym */ syms,
+ Bool trace_symtab )
+{
+ Word nsyms, i, j, k, m;
+
+ nsyms = VG_(sizeXA)(syms);
+
+ VG_(setCmpFnXA)(syms, cmp_DiSym_by_start_then_name);
+ VG_(sortXA)(syms);
+
+ /* We only know for sure the start addresses (actual VMAs) of
+ symbols, and an overestimation of their end addresses. So sort
+ by start address, then clip each symbol so that its end address
+ does not overlap with the next one along.
+
+ There is a small refinement: if a group of symbols have the same
+ address, treat them as a group: find the next symbol along that
+ has a higher start address, and clip all of the group
+ accordingly. This clips the group as a whole so as not to
+ overlap following symbols. This leaves prefersym() in
+ storage.c, which is not nlist-specific, to later decide which of
+ the symbols in the group to keep.
+
+ Another refinement is that we need to get rid of symbols which,
+ after clipping, have identical starts, ends, and names. So the
+ sorting uses the name as a secondary key.
+ */
+
+ for (i = 0; i < nsyms; i++) {
+ for (k = i+1;
+ k < nsyms
+ && ((DiSym*)VG_(indexXA)(syms,i))->addr
+ == ((DiSym*)VG_(indexXA)(syms,k))->addr;
+ k++)
+ ;
+ /* So now [i .. k-1] is a group all with the same start address.
+ Clip their ending addresses so they don't overlap [k]. In
+ the normal case (no overlaps), k == i+1. */
+ if (k < nsyms) {
+ DiSym* next = (DiSym*)VG_(indexXA)(syms,k);
+ for (m = i; m < k; m++) {
+ DiSym* here = (DiSym*)VG_(indexXA)(syms,m);
+ vg_assert(here->addr < next->addr);
+ if (here->addr + here->size > next->addr)
+ here->size = next->addr - here->addr;
+ }
+ }
+ i = k-1;
+ vg_assert(i <= nsyms);
+ }
+
+ j = 0;
+ if (nsyms > 0) {
+ j = 1;
+ for (i = 1; i < nsyms; i++) {
+ DiSym *s_j1, *s_j, *s_i;
+ vg_assert(j <= i);
+ s_j1 = (DiSym*)VG_(indexXA)(syms, j-1);
+ s_j = (DiSym*)VG_(indexXA)(syms, j);
+ s_i = (DiSym*)VG_(indexXA)(syms, i);
+ if (s_i->addr != s_j1->addr
+ || s_i->size != s_j1->size
+ || 0 != VG_(strcmp)(s_i->name, s_j1->name)) {
+ *s_j = *s_i;
+ j++;
+ } else {
+ if (trace_symtab)
+ VG_(printf)("nlist cleanup: dump duplicate avma %010lx %s\n",
+ s_i->addr, s_i->name );
+ }
+ }
+ }
+ vg_assert(j >= 0 && j <= nsyms);
+ VG_(dropTailXA)(syms, nsyms - j);
+}
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- Mach-O top-level processing ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+#if !defined(APPLE_DSYM_EXT_AND_SUBDIRECTORY)
+#define APPLE_DSYM_EXT_AND_SUBDIRECTORY ".dSYM/Contents/Resources/DWARF/"
+#endif
+
+
+static Bool file_exists_p(const Char *path)
+{
+ struct vg_stat sbuf;
+ SysRes res = VG_(stat)(path, &sbuf);
+ return sr_isError(res) ? False : True;
+}
+
+
+/* Search for an existing dSYM file as a possible separate debug file.
+ Adapted from gdb. */
+static Char *
+find_separate_debug_file (const Char *executable_name)
+{
+ Char *basename_str;
+ Char *dot_ptr;
+ Char *slash_ptr;
+ Char *dsymfile;
+
+ /* Make sure the object file name itself doesn't contain ".dSYM" in it or we
+ will end up with an infinite loop where after we add a dSYM symbol file,
+ it will then enter this function asking if there is a debug file for the
+ dSYM file itself. */
+ if (VG_(strcasestr) (executable_name, ".dSYM") == NULL)
+ {
+ /* Check for the existence of a .dSYM file for a given executable. */
+ basename_str = VG_(basename) (executable_name);
+ dsymfile = ML_(dinfo_zalloc)("di.readmacho.dsymfile",
+ VG_(strlen) (executable_name)
+ + VG_(strlen) (APPLE_DSYM_EXT_AND_SUBDIRECTORY)
+ + VG_(strlen) (basename_str)
+ + 1
+ );
+
+ /* First try for the dSYM in the same directory as the original file. */
+ VG_(strcpy) (dsymfile, executable_name);
+ VG_(strcat) (dsymfile, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+ VG_(strcat) (dsymfile, basename_str);
+
+ if (file_exists_p (dsymfile))
+ return dsymfile;
+
+ /* Now search for any parent directory that has a '.' in it so we can find
+ Mac OS X applications, bundles, plugins, and any other kinds of files.
+ Mac OS X application bundles wil have their program in
+ "/some/path/MyApp.app/Contents/MacOS/MyApp" (or replace ".app" with
+ ".bundle" or ".plugin" for other types of bundles). So we look for any
+ prior '.' character and try appending the apple dSYM extension and
+ subdirectory and see if we find an existing dSYM file (in the above
+ MyApp example the dSYM would be at either:
+ "/some/path/MyApp.app.dSYM/Contents/Resources/DWARF/MyApp" or
+ "/some/path/MyApp.dSYM/Contents/Resources/DWARF/MyApp". */
+ VG_(strcpy) (dsymfile, VG_(dirname) (executable_name));
+ while ((dot_ptr = VG_(strrchr) (dsymfile, '.')))
+ {
+ /* Find the directory delimiter that follows the '.' character since
+ we now look for a .dSYM that follows any bundle extension. */
+ slash_ptr = VG_(strchr) (dot_ptr, '/');
+ if (slash_ptr)
+ {
+ /* NULL terminate the string at the '/' character and append
+ the path down to the dSYM file. */
+ *slash_ptr = '\0';
+ VG_(strcat) (slash_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+ VG_(strcat) (slash_ptr, basename_str);
+ if (file_exists_p (dsymfile))
+ return dsymfile;
+ }
+
+ /* NULL terminate the string at the '.' character and append
+ the path down to the dSYM file. */
+ *dot_ptr = '\0';
+ VG_(strcat) (dot_ptr, APPLE_DSYM_EXT_AND_SUBDIRECTORY);
+ VG_(strcat) (dot_ptr, basename_str);
+ if (file_exists_p (dsymfile))
+ return dsymfile;
+
+ /* NULL terminate the string at the '.' locatated by the strrchr()
+ function again. */
+ *dot_ptr = '\0';
+
+ /* We found a previous extension '.' character and did not find a
+ dSYM file so now find previous directory delimiter so we don't
+ try multiple times on a file name that may have a version number
+ in it such as "/some/path/MyApp.6.0.4.app". */
+ slash_ptr = VG_(strrchr) (dsymfile, '/');
+ if (!slash_ptr)
+ break;
+ /* NULL terminate the string at the previous directory character
+ and search again. */
+ *slash_ptr = '\0';
+ }
+ }
+
+ return NULL;
+}
+
+
+static UChar *getsectdata(UChar* base, SizeT size,
+ Char *segname, Char *sectname,
+ /*OUT*/Word *sect_size)
+{
+ struct MACH_HEADER *mh = (struct MACH_HEADER *)base;
+ struct load_command *cmd;
+ Int c;
+
+ for (c = 0, cmd = (struct load_command *)(mh+1);
+ c < mh->ncmds;
+ c++, cmd = (struct load_command *)(cmd->cmdsize + (Addr)cmd))
+ {
+ if (cmd->cmd == LC_SEGMENT_CMD) {
+ struct SEGMENT_COMMAND *seg = (struct SEGMENT_COMMAND *)cmd;
+ if (0 == VG_(strncmp(seg->segname, segname, sizeof(seg->segname)))) {
+ struct SECTION *sects = (struct SECTION *)(seg+1);
+ Int s;
+ for (s = 0; s < seg->nsects; s++) {
+ if (0 == VG_(strncmp(sects[s].sectname, sectname,
+ sizeof(sects[s].sectname))))
+ {
+ if (sect_size) *sect_size = sects[s].size;
+ return (UChar *)(base + sects[s].offset);
+ }
+ }
+ }
+ }
+ }
+
+ if (sect_size) *sect_size = 0;
+ return 0;
+}
+
+
+/* Brute force just simply search for uuid[0..15] in img[0..n_img-1] */
+static Bool check_uuid_matches ( Addr imgA, Word n_img, UChar* uuid )
+{
+ Word i;
+ UChar* img = (UChar*)imgA;
+ UChar first = uuid[0];
+ if (n_img < 16)
+ return False;
+ for (i = 0; i < n_img-16; i++) {
+ if (img[i] != first)
+ continue;
+ if (0 == VG_(memcmp)( &img[i], &uuid[0], 16 ))
+ return True;
+ }
+ return False;
+}
+
+
+/* Heuristic kludge: return True if this looks like an installed
+ standard library; hence we shouldn't consider automagically running
+ dsymutil on it. */
+static Bool is_systemish_library_name ( UChar* name )
+{
+ vg_assert(name);
+ if (0 == VG_(strncasecmp)(name, "/usr/", 5)
+ || 0 == VG_(strncasecmp)(name, "/bin/", 5)
+ || 0 == VG_(strncasecmp)(name, "/sbin/", 6)
+ || 0 == VG_(strncasecmp)(name, "/System/", 8)
+ || 0 == VG_(strncasecmp)(name, "/Library/", 9)) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
+
+Bool ML_(read_macho_debug_info)( struct _DebugInfo* di )
+{
+ struct symtab_command *symcmd = NULL;
+ struct dysymtab_command *dysymcmd = NULL;
+ HChar* dsymfilename = NULL;
+ Bool have_uuid = False;
+ UChar uuid[16];
+ ImageInfo ii; /* main file */
+ ImageInfo iid; /* auxiliary .dSYM file */
+ Bool ok;
+
+ /* mmap the object file to look for di->soname and di->text_bias
+ and uuid and nlist and STABS */
+
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg,
+ "%s (%#lx)", di->filename, di->rx_map_avma );
+
+ /* This should be ensured by our caller. */
+ vg_assert(di->have_rx_map);
+ vg_assert(di->have_rw_map);
+
+ VG_(memset)(&ii, 0, sizeof(ii));
+ VG_(memset)(&iid, 0, sizeof(iid));
+ VG_(memset)(&uuid, 0, sizeof(uuid));
+
+ ok = map_image_aboard( di, &ii, di->filename );
+ if (!ok) goto fail;
+
+ vg_assert(ii.macho_img != NULL && ii.macho_img_szB > 0);
+
+ /* Poke around in the Mach-O header, to find some important
+ stuff. */
+ // Find LC_SYMTAB and LC_DYSYMTAB, if present.
+ // Read di->soname from LC_ID_DYLIB if present,
+ // or from LC_ID_DYLINKER if present,
+ // or use "NONE".
+ // Get di->text_bias (aka slide) based on the corresponding LC_SEGMENT
+ // Get uuid for later dsym search
+
+ di->text_bias = 0;
+
+ { struct MACH_HEADER *mh = (struct MACH_HEADER *)ii.macho_img;
+ struct load_command *cmd;
+ Int c;
+
+ for (c = 0, cmd = (struct load_command *)(mh+1);
+ c < mh->ncmds;
+ c++, cmd = (struct load_command *)(cmd->cmdsize
+ + (unsigned long)cmd)) {
+ if (cmd->cmd == LC_SYMTAB) {
+ symcmd = (struct symtab_command *)cmd;
+ }
+ else if (cmd->cmd == LC_DYSYMTAB) {
+ dysymcmd = (struct dysymtab_command *)cmd;
+ }
+ else if (cmd->cmd == LC_ID_DYLIB && mh->filetype == MH_DYLIB) {
+ // GrP fixme bundle?
+ struct dylib_command *dcmd = (struct dylib_command *)cmd;
+ UChar *dylibname = dcmd->dylib.name.offset + (UChar *)dcmd;
+ UChar *soname = VG_(strrchr)(dylibname, '/');
+ if (!soname) soname = dylibname;
+ else soname++;
+ di->soname = ML_(dinfo_strdup)("di.readmacho.dylibname",
+ soname);
+ }
+ else if (cmd->cmd==LC_ID_DYLINKER && mh->filetype==MH_DYLINKER) {
+ struct dylinker_command *dcmd = (struct dylinker_command *)cmd;
+ UChar *dylinkername = dcmd->name.offset + (UChar *)dcmd;
+ UChar *soname = VG_(strrchr)(dylinkername, '/');
+ if (!soname) soname = dylinkername;
+ else soname++;
+ di->soname = ML_(dinfo_strdup)("di.readmacho.dylinkername",
+ soname);
+ }
+
+ // A comment from Julian about why varinfo[35] fail:
+ //
+ // My impression is, from comparing the output of otool -l for these
+ // executables with the logic in ML_(read_macho_debug_info),
+ // specifically the part that begins "else if (cmd->cmd ==
+ // LC_SEGMENT_CMD) {", that it's a complete hack which just happens
+ // to work ok for text symbols. In particular, it appears to assume
+ // that in a "struct load_command" of type LC_SEGMENT_CMD, the first
+ // "struct SEGMENT_COMMAND" inside it is going to contain the info we
+ // need. However, otool -l shows, and also the Apple docs state,
+ // that a struct load_command may contain an arbitrary number of
+ // struct SEGMENT_COMMANDs, so I'm not sure why it's OK to merely
+ // snarf the first. But I'm not sure about this.
+ //
+ // The "Try for __DATA" block below simply adds acquisition of data
+ // svma/bias values using the same assumption. It also needs
+ // (probably) to deal with bss sections, but I don't understand how
+ // this all ties together really, so it requires further study.
+ //
+ // If you can get your head around the relationship between MachO
+ // segments, sections and load commands, this might be relatively
+ // easy to fix properly.
+ //
+ // Basically we need to come up with plausible numbers for di->
+ // {text,data,bss}_{avma,svma}, from which the _bias numbers are
+ // then trivially derived. Then I think the debuginfo reader should
+ // work pretty well.
+ else if (cmd->cmd == LC_SEGMENT_CMD) {
+ struct SEGMENT_COMMAND *seg = (struct SEGMENT_COMMAND *)cmd;
+ /* Try for __TEXT */
+ if (!di->text_present
+ && 0 == VG_(strcmp)(seg->segname, "__TEXT")
+ /* DDD: is the next line a kludge? -- JRS */
+ && seg->fileoff == 0 && seg->filesize != 0) {
+ di->text_present = True;
+ di->text_svma = (Addr)seg->vmaddr;
+ di->text_avma = di->rx_map_avma;
+ di->text_size = seg->vmsize;
+ di->text_bias = di->text_avma - di->text_svma;
+ /* Make the _debug_ values be the same as the
+ svma/bias for the primary object, since there is
+ no secondary (debuginfo) object, but nevertheless
+ downstream biasing of Dwarf3 relies on the
+ _debug_ values. */
+ di->text_debug_svma = di->text_svma;
+ di->text_debug_bias = di->text_bias;
+ }
+ /* Try for __DATA */
+ if (!di->data_present
+ && 0 == VG_(strcmp)(seg->segname, "__DATA")
+ /* && DDD:seg->fileoff == 0 */ && seg->filesize != 0) {
+ di->data_present = True;
+ di->data_svma = (Addr)seg->vmaddr;
+ di->data_avma = di->rw_map_avma;
+ di->data_size = seg->vmsize;
+ di->data_bias = di->data_avma - di->data_svma;
+ di->data_debug_svma = di->data_svma;
+ di->data_debug_bias = di->data_bias;
+ }
+ }
+ else if (cmd->cmd == LC_UUID) {
+ struct uuid_command *uuid_cmd = (struct uuid_command *)cmd;
+ VG_(memcpy)(uuid, uuid_cmd->uuid, sizeof(uuid));
+ have_uuid = True;
+ }
+ }
+ }
+
+ if (!di->soname) {
+ di->soname = ML_(dinfo_strdup)("di.readmacho.noname", "NONE");
+ }
+
+ /* Now we have the base object to hand. Read symbols from it. */
+
+ if (ii.macho_img && ii.macho_img_szB > 0 && symcmd && dysymcmd) {
+
+ /* Read nlist symbol table */
+ struct NLIST *syms;
+ UChar *strs;
+ XArray* /* DiSym */ candSyms = NULL;
+ Word i, nCandSyms;
+
+ if (ii.macho_img_szB < symcmd->stroff + symcmd->strsize
+ || ii.macho_img_szB < symcmd->symoff + symcmd->nsyms
+ * sizeof(struct NLIST)) {
+ ML_(symerr)(di, False, "Invalid Mach-O file (5 too small).");
+ goto fail;
+ }
+ if (dysymcmd->ilocalsym + dysymcmd->nlocalsym > symcmd->nsyms
+ || dysymcmd->iextdefsym + dysymcmd->nextdefsym > symcmd->nsyms) {
+ ML_(symerr)(di, False, "Invalid Mach-O file (bad symbol table).");
+ goto fail;
+ }
+
+ syms = (struct NLIST *)(ii.macho_img + symcmd->symoff);
+ strs = (UChar *)(ii.macho_img + symcmd->stroff);
+
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg,
+ " reading syms from primary file (%d %d)",
+ dysymcmd->nextdefsym, dysymcmd->nlocalsym );
+
+ /* Read candidate symbols into 'candSyms', so we can truncate
+ overlapping ends and generally tidy up, before presenting
+ them to ML_(addSym). */
+ candSyms = VG_(newXA)(
+ ML_(dinfo_zalloc), "di.readmacho.candsyms.1",
+ ML_(dinfo_free), sizeof(DiSym)
+ );
+ vg_assert(candSyms);
+
+ // extern symbols
+ read_symtab(candSyms,
+ di,
+ syms + dysymcmd->iextdefsym, dysymcmd->nextdefsym,
+ strs, symcmd->strsize);
+ // static and private_extern symbols
+ read_symtab(candSyms,
+ di,
+ syms + dysymcmd->ilocalsym, dysymcmd->nlocalsym,
+ strs, symcmd->strsize);
+
+ /* tidy up the cand syms -- trim overlapping ends. May resize
+ candSyms. */
+ tidy_up_cand_syms( candSyms, di->trace_symtab );
+
+ /* and finally present them to ML_(addSym) */
+ nCandSyms = VG_(sizeXA)( candSyms );
+ for (i = 0; i < nCandSyms; i++) {
+ DiSym* cand = (DiSym*) VG_(indexXA)( candSyms, i );
+ if (di->trace_symtab)
+ VG_(printf)("nlist final: acquire avma %010lx-%010lx %s\n",
+ cand->addr, cand->addr + cand->size - 1, cand->name );
+ ML_(addSym)( di, cand );
+ }
+ VG_(deleteXA)( candSyms );
+ }
+
+ /* If there's no UUID in the primary, don't even bother to try and
+ read any DWARF, since we won't be able to verify it matches.
+ Our policy is not to load debug info unless we can verify that
+ it matches the primary. Just declare success at this point.
+ And don't complain to the user, since that would cause us to
+ complain on objects compiled without -g. (Some versions of
+ XCode are observed to omit a UUID entry for object linked(?)
+ without -g. Others don't appear to omit it.) */
+ if (!have_uuid)
+ goto success;
+
+ /* mmap the dSYM file to look for DWARF debug info. If successful,
+ use the .macho_img and .macho_img_szB in iid. */
+
+ dsymfilename = find_separate_debug_file( di->filename );
+
+ /* Try to load it. */
+ if (dsymfilename) {
+ Bool valid;
+
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg, " dSYM= %s", dsymfilename);
+
+ ok = map_image_aboard( di, &iid, dsymfilename );
+ if (!ok) goto fail;
+
+ /* check it has the right uuid. */
+ vg_assert(have_uuid);
+ valid = iid.macho_img && iid.macho_img_szB > 0
+ && check_uuid_matches( (Addr)iid.macho_img,
+ iid.macho_img_szB, uuid );
+ if (valid)
+ goto read_the_dwarf;
+
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg, " dSYM does not have "
+ "correct UUID (out of date?)");
+ }
+
+ /* There was no dsym file, or it doesn't match. We'll have to try
+ regenerating it, unless auto-run-dsymutil is disabled, in which
+ case just complain instead. */
+
+ /* If this looks like a lib that we shouldn't run dsymutil on, just
+ give up. (possible reasons: is system lib, or in /usr etc, or
+ the dsym dir would not be writable by the user, or we're running
+ as root) */
+ vg_assert(di->filename);
+ if (is_systemish_library_name(di->filename))
+ goto success;
+
+ if (!VG_(clo_auto_run_dsymutil)) {
+ if (VG_(clo_verbosity) == 1) {
+ VG_(message)(Vg_DebugMsg, "%s:", di->filename);
+ }
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_DebugMsg, "%sdSYM directory %s; consider using "
+ "--auto-run-dsymutil=yes",
+ VG_(clo_verbosity) > 1 ? " " : "",
+ dsymfilename ? "has wrong UUID" : "is missing");
+ goto success;
+ }
+
+ /* Run dsymutil */
+
+ { Int r;
+ HChar* dsymutil = "/usr/bin/dsymutil ";
+ HChar* cmd = ML_(dinfo_zalloc)( "di.readmacho.tmp1",
+ VG_(strlen)(dsymutil)
+ + VG_(strlen)(di->filename)
+ + 30 /* misc */ );
+ VG_(strcpy)(cmd, dsymutil);
+ if (0) VG_(strcat)(cmd, "--verbose ");
+ VG_(strcat)(cmd, di->filename);
+ VG_(message)(Vg_DebugMsg, "run: %s", cmd);
+ r = VG_(system)( cmd );
+ if (r)
+ VG_(message)(Vg_DebugMsg, "run: %s FAILED", dsymutil);
+ ML_(dinfo_free)(cmd);
+ dsymfilename = find_separate_debug_file(di->filename);
+ }
+
+ /* Try again to load it. */
+ if (dsymfilename) {
+ Bool valid;
+
+ if (VG_(clo_verbosity) > 1)
+ VG_(message)(Vg_DebugMsg, " dsyms= %s", dsymfilename);
+
+ ok = map_image_aboard( di, &iid, dsymfilename );
+ if (!ok) goto fail;
+
+ /* check it has the right uuid. */
+ vg_assert(have_uuid);
+ valid = iid.macho_img && iid.macho_img_szB > 0
+ && check_uuid_matches( (Addr)iid.macho_img,
+ iid.macho_img_szB, uuid );
+ if (!valid) {
+ if (VG_(clo_verbosity) > 0) {
+ VG_(message)(Vg_DebugMsg,
+ "WARNING: did not find expected UUID %02X%02X%02X%02X"
+ "-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X"
+ " in dSYM dir",
+ (UInt)uuid[0], (UInt)uuid[1], (UInt)uuid[2], (UInt)uuid[3],
+ (UInt)uuid[4], (UInt)uuid[5], (UInt)uuid[6], (UInt)uuid[7],
+ (UInt)uuid[8], (UInt)uuid[9], (UInt)uuid[10],
+ (UInt)uuid[11], (UInt)uuid[12], (UInt)uuid[13],
+ (UInt)uuid[14], (UInt)uuid[15] );
+ VG_(message)(Vg_DebugMsg,
+ "WARNING: for %s", di->filename);
+ }
+ unmap_image( &iid );
+ /* unmap_image zeroes the fields, so the following test makes
+ sense. */
+ goto fail;
+ }
+ }
+
+ /* Right. Finally we have our best try at the dwarf image, so go
+ on to reading stuff out of it. */
+
+ read_the_dwarf:
+ if (iid.macho_img && iid.macho_img_szB > 0) {
+ UChar* debug_info_img = NULL;
+ Word debug_info_sz;
+ UChar* debug_abbv_img;
+ Word debug_abbv_sz;
+ UChar* debug_line_img;
+ Word debug_line_sz;
+ UChar* debug_str_img;
+ Word debug_str_sz;
+ UChar* debug_ranges_img;
+ Word debug_ranges_sz;
+ UChar* debug_loc_img;
+ Word debug_loc_sz;
+ UChar* debug_name_img;
+ Word debug_name_sz;
+
+ debug_info_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_info", &debug_info_sz);
+ debug_abbv_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_abbrev", &debug_abbv_sz);
+ debug_line_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_line", &debug_line_sz);
+ debug_str_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_str", &debug_str_sz);
+ debug_ranges_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_ranges", &debug_ranges_sz);
+ debug_loc_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_loc", &debug_loc_sz);
+ debug_name_img =
+ getsectdata(iid.macho_img, iid.macho_img_szB,
+ "__DWARF", "__debug_pubnames", &debug_name_sz);
+
+ if (debug_info_img) {
+ if (VG_(clo_verbosity) > 1) {
+ if (0)
+ VG_(message)(Vg_DebugMsg,
+ "Reading dwarf3 for %s (%#lx) from %s"
+ " (%ld %ld %ld %ld %ld %ld)",
+ di->filename, di->text_avma, dsymfilename,
+ debug_info_sz, debug_abbv_sz, debug_line_sz,
+ debug_str_sz, debug_ranges_sz, debug_loc_sz
+ );
+ VG_(message)(Vg_DebugMsg,
+ " reading dwarf3 from dsyms file");
+ }
+ /* The old reader: line numbers and unwind info only */
+ ML_(read_debuginfo_dwarf3) ( di,
+ debug_info_img, debug_info_sz,
+ debug_abbv_img, debug_abbv_sz,
+ debug_line_img, debug_line_sz,
+ debug_str_img, debug_str_sz );
+
+ /* The new reader: read the DIEs in .debug_info to acquire
+ information on variable types and locations. But only if
+ the tool asks for it, or the user requests it on the
+ command line. */
+ if (VG_(needs).var_info /* the tool requires it */
+ || VG_(clo_read_var_info) /* the user asked for it */) {
+ ML_(new_dwarf3_reader)(
+ di, debug_info_img, debug_info_sz,
+ debug_abbv_img, debug_abbv_sz,
+ debug_line_img, debug_line_sz,
+ debug_str_img, debug_str_sz,
+ debug_ranges_img, debug_ranges_sz,
+ debug_loc_img, debug_loc_sz
+ );
+ }
+ }
+ }
+
+ if (dsymfilename) ML_(dinfo_free)(dsymfilename);
+
+ success:
+ if (ii.img)
+ unmap_image(&ii);
+ if (iid.img)
+ unmap_image(&iid);
+ return True;
+
+ /* NOTREACHED */
+
+ fail:
+ ML_(symerr)(di, True, "Error reading Mach-O object.");
+ if (ii.img)
+ unmap_image(&ii);
+ if (iid.img)
+ unmap_image(&iid);
+ return False;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end readmacho.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/readstabs.c b/coregrind/m_debuginfo/readstabs.c
index 5bb9ac2..72de81d 100644
--- a/coregrind/m_debuginfo/readstabs.c
+++ b/coregrind/m_debuginfo/readstabs.c
@@ -46,7 +46,17 @@
#include "priv_readstabs.h" /* self */
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
-#include <a.out.h> /* stabs defns */
+#if defined(VGO_linux)
+# include <a.out.h> /* stabs defns */
+#elif defined(VGO_darwin)
+# include <mach-o/nlist.h>
+# define n_other n_sect
+# if VG_WORDSIZE == 8
+# define nlist nlist_64
+# endif
+#else
+# error "Unknown OS"
+#endif
/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
/*------------------------------------------------------------*/
diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c
index 343cf3b..f8d0834 100644
--- a/coregrind/m_debuginfo/storage.c
+++ b/coregrind/m_debuginfo/storage.c
@@ -229,6 +229,24 @@
}
+/* Resize the symbol table to save memory.
+*/
+void ML_(shrinkSym)( struct _DebugInfo* di )
+{
+ DiSym* new_tab;
+ UInt new_sz = di->symtab_used;
+ if (new_sz == di->symtab_size) return;
+
+ new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkSym",
+ new_sz * sizeof(DiSym) );
+ VG_(memcpy)(new_tab, di->symtab, new_sz * sizeof(DiSym));
+
+ ML_(dinfo_free)(di->symtab);
+ di->symtab = new_tab;
+ di->symtab_size = new_sz;
+}
+
+
/* Add a location to the location table.
*/
static void addLoc ( struct _DebugInfo* di, DiLoc* loc )
@@ -259,6 +277,24 @@
}
+/* Resize the lineinfo table to save memory.
+*/
+void ML_(shrinkLineInfo)( struct _DebugInfo* di )
+{
+ DiLoc* new_tab;
+ UInt new_sz = di->loctab_used;
+ if (new_sz == di->loctab_size) return;
+
+ new_tab = ML_(dinfo_zalloc)( "di.storage.shrinkLineInfo",
+ new_sz * sizeof(DiLoc) );
+ VG_(memcpy)(new_tab, di->loctab, new_sz * sizeof(DiLoc));
+
+ ML_(dinfo_free)(di->loctab);
+ di->loctab = new_tab;
+ di->loctab_size = new_sz;
+}
+
+
/* Top-level place to call to add a source-location mapping entry.
*/
void ML_(addLineInfo) ( struct _DebugInfo* di,
@@ -1060,6 +1096,8 @@
#if defined(VGO_linux) || defined(VGO_aix5)
# define VERSION_CHAR '@'
+#elif defined(VGO_darwin)
+# define VERSION_CHAR '$'
#else
# error Unknown OS
#endif
@@ -1145,6 +1183,7 @@
if (cmp > 0) {
preferB = True; goto out;
}
+
/* If we get here, they are the same name. */
/* In this case we could choose either (arbitrarily), but might as
@@ -1195,7 +1234,8 @@
for (i = 0; i < j; i++) {
if (i < j-1
&& di->symtab[i].addr == di->symtab[i+1].addr
- && di->symtab[i].size == di->symtab[i+1].size) {
+ && di->symtab[i].size == di->symtab[i+1].size
+ ) {
n_merged++;
/* merge the two into one */
di->symtab[di->symtab_used++]
diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c
index 431e04e..06f6988 100644
--- a/coregrind/m_debuglog.c
+++ b/coregrind/m_debuglog.c
@@ -46,6 +46,11 @@
/* This module is also notable because it is linked into both
stage1 and stage2. */
+/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
+ of syscalls rather than the vanilla version, if a _nocancel version
+ is available. See docs/internals/Darwin-notes.txt for the reason
+ why. */
+
#include "pub_core_basics.h" /* basic types */
#include "pub_core_vkiscnums.h" /* for syscall numbers */
#include "pub_core_debuglog.h" /* our own iface */
@@ -393,6 +398,88 @@
return (UInt)block[0];
}
+#elif defined(VGP_x86_darwin)
+
+/* Using _SYSNO_INDEX rather than _SYSNO_NUM assumes that these are
+ Unix-class syscalls (which they are). Unfortunately _SYSNO_NUM
+ involves a C-style "cond ? :" expression which doesn't impress the
+ Darwin assembler very much. */
+__attribute__((noinline))
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+ UInt __res;
+ __asm__ volatile (
+ "movl %2, %%eax\n" /* push n */
+ "pushl %%eax\n"
+ "movl %1, %%eax\n" /* push buf */
+ "pushl %%eax\n"
+ "movl $2, %%eax\n" /* push stderr */
+ "pushl %%eax\n"
+ "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_write_nocancel))
+ ", %%eax\n"
+ "pushl %%eax\n" /* push fake return address */
+ "int $0x80\n" /* write(stderr, buf, n) */
+ "jnc 1f\n" /* jump if no error */
+ "movl $-1, %%eax\n" /* return -1 if error */
+ "1: "
+ "movl %%eax, %0\n" /* __res = eax */
+ "addl $16, %%esp\n" /* pop x4 */
+ : "=mr" (__res)
+ : "g" (buf), "g" (n)
+ : "eax", "edx", "cc"
+ );
+ return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+ UInt __res;
+ __asm__ volatile (
+ "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_INDEX(__NR_getpid))", %%eax\n"
+ "int $0x80\n" /* getpid() */
+ "movl %%eax, %0\n" /* set __res = eax */
+ : "=mr" (__res)
+ :
+ : "eax", "cc" );
+ return __res;
+}
+
+#elif defined(VGP_amd64_darwin)
+
+__attribute__((noinline))
+static UInt local_sys_write_stderr ( HChar* buf, Int n )
+{
+ UInt __res;
+ __asm__ volatile (
+ "movq $2, %%rdi\n" /* push stderr */
+ "movq %1, %%rsi\n" /* push buf */
+ "movl %2, %%edx\n" /* push n */
+ "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_NUM(__NR_write_nocancel))
+ ", %%eax\n"
+ "syscall\n" /* write(stderr, buf, n) */
+ "jnc 1f\n" /* jump if no error */
+ "movq $-1, %%rax\n" /* return -1 if error */
+ "1: "
+ "movl %%eax, %0\n" /* __res = eax */
+ : "=mr" (__res)
+ : "g" (buf), "g" (n)
+ : "rdi", "rsi", "rdx", "rcx", "rax", "cc" );
+ return __res;
+}
+
+static UInt local_sys_getpid ( void )
+{
+ UInt __res;
+ __asm__ volatile (
+ "movl $"VG_STRINGIFY(VG_DARWIN_SYSNO_NUM(__NR_getpid))", %%eax\n"
+ "syscall\n" /* getpid() */
+ "movl %%eax, %0\n" /* set __res = eax */
+ : "=mr" (__res)
+ :
+ : "rax", "rcx", "cc" );
+ return __res;
+}
+
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_dispatch/dispatch-amd64-darwin.S b/coregrind/m_dispatch/dispatch-amd64-darwin.S
new file mode 100644
index 0000000..bc095e4
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-amd64-darwin.S
@@ -0,0 +1,331 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address. ---*/
+/*--- dispatch-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_dispatch_asm.h"
+#include "pub_core_transtab_asm.h"
+#include "libvex_guest_offsets.h" /* for OFFSET_amd64_RIP */
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
+/*--- run all translations except no-redir ones. ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Preamble (set everything up) ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
+*/
+
+.text
+.globl VG_(run_innerloop)
+VG_(run_innerloop):
+ /* %rdi holds guest_state */
+ /* %rsi holds do_profiling */
+
+ /* ----- entry point to VG_(run_innerloop) ----- */
+ pushq %rbx
+ pushq %rcx
+ pushq %rdx
+ pushq %rsi
+ pushq %rbp
+ pushq %r8
+ pushq %r9
+ pushq %r10
+ pushq %r11
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ pushq %rdi /* guest_state */
+
+ movq VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
+ movl (%r15), %r15d
+ pushq %r15
+
+ /* 8(%rsp) holds cached copy of guest_state ptr */
+ /* 0(%rsp) holds cached copy of VG_(dispatch_ctr) */
+
+ /* Set up the guest state pointer */
+ movq %rdi, %rbp
+
+ /* fetch %RIP into %rax */
+ movq OFFSET_amd64_RIP(%rbp), %rax
+
+ /* set host FPU control word to the default mode expected
+ by VEX-generated code. See comments in libvex.h for
+ more info. */
+ finit
+ pushq $0x027F
+ fldcw (%rsp)
+ addq $8, %rsp
+
+ /* set host SSE control word to the default mode expected
+ by VEX-generated code. */
+ pushq $0x1F80
+ ldmxcsr (%rsp)
+ addq $8, %rsp
+
+ /* set dir flag to known value */
+ cld
+
+ /* fall into main loop (the right one) */
+ cmpq $0, %rsi
+ je VG_(run_innerloop__dispatch_unprofiled)
+ jmp VG_(run_innerloop__dispatch_profiled)
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- NO-PROFILING (standard) dispatcher ---*/
+/*----------------------------------------------------*/
+
+.align 4
+.globl VG_(run_innerloop__dispatch_unprofiled)
+VG_(run_innerloop__dispatch_unprofiled):
+ /* AT ENTRY: %rax is next guest addr, %rbp is possibly
+ modified guest state ptr */
+
+ /* Has the guest state pointer been messed with? If yes, exit. */
+ cmpq 8(%rsp), %rbp
+ movq VG_(tt_fast)@GOTPCREL(%rip), %rcx
+ jnz gsp_changed
+
+ /* save the jump address in the guest state */
+ movq %rax, OFFSET_amd64_RIP(%rbp)
+
+ /* Are we out of timeslice? If yes, defer to scheduler. */
+ subl $1, 0(%rsp)
+ jz counter_is_zero
+
+ /* try a fast lookup in the translation cache */
+ movq %rax, %rbx
+ andq $VG_TT_FAST_MASK, %rbx /* entry# */
+ shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */
+ movq 0(%rcx,%rbx,1), %r10 /* .guest */
+ movq 8(%rcx,%rbx,1), %r11 /* .host */
+ cmpq %rax, %r10
+ jnz fast_lookup_failed
+
+ /* Found a match. Jump to .host. */
+ jmp *%r11
+ ud2 /* persuade insn decoders not to speculate past here */
+ /* generated code should run, then jump back to
+ VG_(run_innerloop__dispatch_unprofiled). */
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- PROFILING dispatcher (can be much slower) ---*/
+/*----------------------------------------------------*/
+
+.align 4
+.globl VG_(run_innerloop__dispatch_profiled)
+VG_(run_innerloop__dispatch_profiled):
+ /* AT ENTRY: %rax is next guest addr, %rbp is possibly
+ modified guest state ptr */
+
+ /* Has the guest state pointer been messed with? If yes, exit. */
+ cmpq 8(%rsp), %rbp
+ movq VG_(tt_fast)@GOTPCREL(%rip), %rcx
+ jnz gsp_changed
+
+ /* save the jump address in the guest state */
+ movq %rax, OFFSET_amd64_RIP(%rbp)
+
+ /* Are we out of timeslice? If yes, defer to scheduler. */
+ subl $1, 0(%rsp)
+ jz counter_is_zero
+
+ /* try a fast lookup in the translation cache */
+ movq %rax, %rbx
+ andq $VG_TT_FAST_MASK, %rbx /* entry# */
+ shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */
+ movq 0(%rcx,%rbx,1), %r10 /* .guest */
+ movq 8(%rcx,%rbx,1), %r11 /* .host */
+ cmpq %rax, %r10
+ jnz fast_lookup_failed
+
+ /* increment bb profile counter */
+ movq VG_(tt_fastN)@GOTPCREL(%rip), %rdx
+ shrq $1, %rbx /* entry# * sizeof(UInt*) */
+ movq (%rdx,%rbx,1), %rdx
+ addl $1, (%rdx)
+
+ /* Found a match. Jump to .host. */
+ jmp *%r11
+ ud2 /* persuade insn decoders not to speculate past here */
+ /* generated code should run, then jump back to
+ VG_(run_innerloop__dispatch_profiled). */
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- exit points ---*/
+/*----------------------------------------------------*/
+
+gsp_changed:
+ /* Someone messed with the gsp. Have to
+ defer to scheduler to resolve this. dispatch ctr
+ is not yet decremented, so no need to increment. */
+ /* %RIP is NOT up to date here. First, need to write
+ %rax back to %RIP, but without trashing %rbp since
+ that holds the value we want to return to the scheduler.
+ Hence use %r15 transiently for the guest state pointer. */
+ movq 8(%rsp), %r15
+ movq %rax, OFFSET_amd64_RIP(%r15)
+ movq %rbp, %rax
+ jmp run_innerloop_exit
+ /*NOTREACHED*/
+
+counter_is_zero:
+ /* %RIP is up to date here */
+ /* back out decrement of the dispatch counter */
+ addl $1, 0(%rsp)
+ movq $VG_TRC_INNER_COUNTERZERO, %rax
+ jmp run_innerloop_exit
+
+fast_lookup_failed:
+ /* %RIP is up to date here */
+ /* back out decrement of the dispatch counter */
+ addl $1, 0(%rsp)
+ movq $VG_TRC_INNER_FASTMISS, %rax
+ jmp run_innerloop_exit
+
+
+
+/* All exits from the dispatcher go through here. %rax holds
+ the return value.
+*/
+run_innerloop_exit:
+ /* We're leaving. Check that nobody messed with
+ %mxcsr or %fpucw. We can't mess with %rax here as it
+ holds the tentative return value, but any other is OK. */
+#if !defined(ENABLE_INNER)
+ /* This check fails for self-hosting, so skip in that case */
+ pushq $0
+ fstcw (%rsp)
+ cmpl $0x027F, (%rsp)
+ popq %r15 /* get rid of the word without trashing %eflags */
+ jnz invariant_violation
+#endif
+ pushq $0
+ stmxcsr (%rsp)
+ andl $0xFFFFFFC0, (%rsp) /* mask out status flags */
+ cmpl $0x1F80, (%rsp)
+ popq %r15
+ jnz invariant_violation
+ /* otherwise we're OK */
+ jmp run_innerloop_exit_REALLY
+
+invariant_violation:
+ movq $VG_TRC_INVARIANT_FAILED, %rax
+ jmp run_innerloop_exit_REALLY
+
+run_innerloop_exit_REALLY:
+
+ /* restore VG_(dispatch_ctr) */
+ popq %r14
+ movq VG_(dispatch_ctr)@GOTPCREL(%rip), %r15
+ movl %r14d, (%r15)
+
+ popq %rdi
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %r11
+ popq %r10
+ popq %r9
+ popq %r8
+ popq %rbp
+ popq %rsi
+ popq %rdx
+ popq %rcx
+ popq %rbx
+ ret
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- A special dispatcher, for running no-redir ---*/
+/*--- translations. Just runs the given translation once. ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* signature:
+void VG_(run_a_noredir_translation) ( UWord* argblock );
+*/
+
+/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
+ and 2 to carry results:
+ 0: input: ptr to translation
+ 1: input: ptr to guest state
+ 2: output: next guest PC
+ 3: output: guest state pointer afterwards (== thread return code)
+*/
+.align 4
+.globl VG_(run_a_noredir_translation)
+VG_(run_a_noredir_translation):
+ /* Save callee-saves regs */
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+
+ pushq %rdi /* we will need it after running the translation */
+ movq 8(%rdi), %rbp
+ jmp *0(%rdi)
+ /*NOTREACHED*/
+ ud2
+ /* If the translation has been correctly constructed, we
+ should resume at the the following label. */
+.globl VG_(run_a_noredir_translation__return_point)
+VG_(run_a_noredir_translation__return_point):
+ popq %rdi
+ movq %rax, 16(%rdi)
+ movq %rbp, 24(%rdi)
+
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+ ret
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_dispatch/dispatch-x86-darwin.S b/coregrind/m_dispatch/dispatch-x86-darwin.S
new file mode 100644
index 0000000..11956a8
--- /dev/null
+++ b/coregrind/m_dispatch/dispatch-x86-darwin.S
@@ -0,0 +1,318 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address. ---*/
+/*--- dispatch-x86.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2006 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_dispatch_asm.h"
+#include "pub_core_transtab_asm.h"
+#include "libvex_guest_offsets.h" /* for OFFSET_x86_EIP */
+
+
+/* Global variables */
+/* These are defined here instead of in their respective C files to
+ avoid extra PIC branch code here. */
+.data
+.align 2
+
+/* m_transtab.c */
+.globl VG_(tt_fast)
+.align 4
+VG_(tt_fast): .space VG_TT_FAST_SIZE*8, 0 /* (2*Addr) [VG_TT_FAST_SIZE] */
+.globl VG_(tt_fastN)
+VG_(tt_fastN): .space VG_TT_FAST_SIZE*4, 0 /* (UInt *) [VG_TT_FAST_SIZE] */
+
+/* scheduler.c */
+.globl VG_(dispatch_ctr)
+VG_(dispatch_ctr): .long 0
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- The dispatch loop. VG_(run_innerloop) is used to ---*/
+/*--- run all translations except no-redir ones. ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Preamble (set everything up) ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+UWord VG_(run_innerloop) ( void* guest_state, UWord do_profiling );
+*/
+.text
+.globl VG_(run_innerloop)
+VG_(run_innerloop):
+ /* 4(%esp) holds guest_state */
+ /* 8(%esp) holds do_profiling */
+
+ /* ----- entry point to VG_(run_innerloop) ----- */
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+
+ /* 28(%esp) holds guest_state */
+ /* 32(%esp) holds do_profiling */
+
+ /* Set up the guest state pointer */
+ movl 28(%esp), %ebp
+
+ /* fetch %EIP into %eax */
+ movl OFFSET_x86_EIP(%ebp), %eax
+
+ /* set host FPU control word to the default mode expected
+ by VEX-generated code. See comments in libvex.h for
+ more info. */
+ finit
+ pushl $0x027F
+ fldcw (%esp)
+ addl $4, %esp
+
+ /* set host SSE control word to the default mode expected
+ by VEX-generated code. */
+ cmpl $0, VG_(machine_x86_have_mxcsr)
+ jz L1
+ pushl $0x1F80
+ ldmxcsr (%esp)
+ addl $4, %esp
+L1:
+ /* set dir flag to known value */
+ cld
+
+ /* fall into main loop (the right one) */
+ cmpl $0, 32(%esp) /* do_profiling */
+ je VG_(run_innerloop__dispatch_unprofiled)
+ jmp VG_(run_innerloop__dispatch_profiled)
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- NO-PROFILING (standard) dispatcher ---*/
+/*----------------------------------------------------*/
+
+.globl VG_(run_innerloop__dispatch_unprofiled)
+VG_(run_innerloop__dispatch_unprofiled):
+ /* AT ENTRY: %eax is next guest addr, %ebp is possibly
+ modified guest state ptr */
+
+ /* Has the guest state pointer been messed with? If yes, exit. */
+ cmpl 28(%esp), %ebp
+ jnz gsp_changed
+
+ /* save the jump address in the guest state */
+ movl %eax, OFFSET_x86_EIP(%ebp)
+
+ /* Are we out of timeslice? If yes, defer to scheduler. */
+ subl $1, VG_(dispatch_ctr)
+ jz counter_is_zero
+
+ /* try a fast lookup in the translation cache */
+ movl %eax, %ebx
+ andl $VG_TT_FAST_MASK, %ebx
+ movl 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */
+ movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */
+ cmpl %eax, %esi
+ jnz fast_lookup_failed
+
+ /* Found a match. Jump to .host. */
+ jmp *%edi
+ ud2 /* persuade insn decoders not to speculate past here */
+ /* generated code should run, then jump back to
+ VG_(run_innerloop__dispatch_unprofiled). */
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- PROFILING dispatcher (can be much slower) ---*/
+/*----------------------------------------------------*/
+
+.globl VG_(run_innerloop__dispatch_profiled)
+VG_(run_innerloop__dispatch_profiled):
+ /* AT ENTRY: %eax is next guest addr, %ebp is possibly
+ modified guest state ptr */
+
+ /* Has the guest state pointer been messed with? If yes, exit. */
+ cmpl 28(%esp), %ebp
+ jnz gsp_changed
+
+ /* save the jump address in the guest state */
+ movl %eax, OFFSET_x86_EIP(%ebp)
+
+ /* Are we out of timeslice? If yes, defer to scheduler. */
+ subl $1, VG_(dispatch_ctr)
+ jz counter_is_zero
+
+ /* try a fast lookup in the translation cache */
+ movl %eax, %ebx
+ andl $VG_TT_FAST_MASK, %ebx
+ movl 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */
+ movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */
+ cmpl %eax, %esi
+ jnz fast_lookup_failed
+ /* increment bb profile counter */
+ /* note: innocuous as this sounds, it causes a huge amount more
+ stress on D1 and significantly slows everything down. */
+ movl VG_(tt_fastN)(,%ebx,4), %edx
+ /* Use "addl $1", not "incl", to avoid partial-flags stall on P4 */
+ addl $1, (%edx)
+
+ /* Found a match. Jump to .host. */
+ jmp *%edi
+ ud2 /* persuade insn decoders not to speculate past here */
+ /* generated code should run, then jump back to
+ VG_(run_innerloop__dispatch_profiled). */
+ /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- exit points ---*/
+/*----------------------------------------------------*/
+
+gsp_changed:
+ /* Someone messed with the gsp. Have to
+ defer to scheduler to resolve this. dispatch ctr
+ is not yet decremented, so no need to increment. */
+ /* %EIP is NOT up to date here. First, need to write
+ %eax back to %EIP, but without trashing %ebp since
+ that holds the value we want to return to the scheduler.
+ Hence use %esi transiently for the guest state pointer. */
+ movl 28(%esp), %esi
+ movl %eax, OFFSET_x86_EIP(%esi)
+ movl %ebp, %eax
+ jmp run_innerloop_exit
+ /*NOTREACHED*/
+
+counter_is_zero:
+ /* %EIP is up to date here */
+ /* back out decrement of the dispatch counter */
+ addl $1, VG_(dispatch_ctr)
+ movl $VG_TRC_INNER_COUNTERZERO, %eax
+ jmp run_innerloop_exit
+ /*NOTREACHED*/
+
+fast_lookup_failed:
+ /* %EIP is up to date here */
+ /* back out decrement of the dispatch counter */
+ addl $1, VG_(dispatch_ctr)
+ movl $VG_TRC_INNER_FASTMISS, %eax
+ jmp run_innerloop_exit
+ /*NOTREACHED*/
+
+
+
+/* All exits from the dispatcher go through here. %eax holds
+ the return value.
+*/
+run_innerloop_exit:
+ /* We're leaving. Check that nobody messed with
+ %mxcsr or %fpucw. We can't mess with %eax here as it
+ holds the tentative return value, but any other is OK. */
+#if !defined(ENABLE_INNER)
+ /* This check fails for self-hosting, so skip in that case */
+ pushl $0
+ fstcw (%esp)
+ cmpl $0x027F, (%esp)
+ popl %esi /* get rid of the word without trashing %eflags */
+ jnz invariant_violation
+#endif
+ cmpl $0, VG_(machine_x86_have_mxcsr)
+ jz L2
+ pushl $0
+ stmxcsr (%esp)
+ andl $0xFFFFFFC0, (%esp) /* mask out status flags */
+ cmpl $0x1F80, (%esp)
+ popl %esi
+ jnz invariant_violation
+L2: /* otherwise we're OK */
+ jmp run_innerloop_exit_REALLY
+
+invariant_violation:
+ movl $VG_TRC_INVARIANT_FAILED, %eax
+ jmp run_innerloop_exit_REALLY
+
+run_innerloop_exit_REALLY:
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %edx
+ popl %ecx
+ popl %ebx
+ ret
+
+
+/*------------------------------------------------------------*/
+/*--- ---*/
+/*--- A special dispatcher, for running no-redir ---*/
+/*--- translations. Just runs the given translation once. ---*/
+/*--- ---*/
+/*------------------------------------------------------------*/
+
+/* signature:
+void VG_(run_a_noredir_translation) ( UWord* argblock );
+*/
+
+/* Run a no-redir translation. argblock points to 4 UWords, 2 to carry args
+ and 2 to carry results:
+ 0: input: ptr to translation
+ 1: input: ptr to guest state
+ 2: output: next guest PC
+ 3: output: guest state pointer afterwards (== thread return code)
+*/
+.globl VG_(run_a_noredir_translation)
+VG_(run_a_noredir_translation):
+ /* Save callee-saves regs */
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ pushl %ebx
+
+ movl 20(%esp), %edi /* %edi = argblock */
+ movl 4(%edi), %ebp /* argblock[1] */
+ jmp *0(%edi) /* argblock[0] */
+ /*NOTREACHED*/
+ ud2
+ /* If the translation has been correctly constructed, we
+ should resume at the the following label. */
+.globl VG_(run_a_noredir_translation__return_point)
+VG_(run_a_noredir_translation__return_point):
+ movl 20(%esp), %edi
+ movl %eax, 8(%edi) /* argblock[2] */
+ movl %ebp, 12(%edi) /* argblock[3] */
+
+ popl %ebx
+ popl %ebp
+ popl %edi
+ popl %esi
+ ret
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/initimg-darwin.c b/coregrind/m_initimg/initimg-darwin.c
new file mode 100644
index 0000000..13da3bc
--- /dev/null
+++ b/coregrind/m_initimg/initimg-darwin.c
@@ -0,0 +1,621 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on Darwin ---*/
+/*--- initimg-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_machine.h"
+#include "pub_core_ume.h"
+#include "pub_core_options.h"
+#include "pub_core_tooliface.h" /* VG_TRACK */
+#include "pub_core_threadstate.h" /* ThreadArchState */
+#include "priv_initimg_pathscan.h"
+#include "pub_core_initimg.h" /* self */
+
+
+/*====================================================================*/
+/*=== Loading the client ===*/
+/*====================================================================*/
+
+/* Load the client whose name is VG_(argv_the_exename). */
+
+static void load_client ( /*OUT*/ExeInfo* info,
+ /*OUT*/Addr* client_ip)
+{
+ HChar* exe_name;
+ Int ret;
+ SysRes res;
+
+ vg_assert( VG_(args_the_exename) != NULL);
+ exe_name = ML_(find_executable)( VG_(args_the_exename) );
+
+ if (!exe_name) {
+ VG_(printf)("valgrind: %s: command not found\n", VG_(args_the_exename));
+ VG_(exit)(127); // 127 is Posix NOTFOUND
+ }
+
+ VG_(memset)(info, 0, sizeof(*info));
+ ret = VG_(do_exec)(exe_name, info);
+
+ // The client was successfully loaded! Continue.
+
+ /* Get hold of a file descriptor which refers to the client
+ executable. This is needed for attaching to GDB. */
+ res = VG_(open)(exe_name, VKI_O_RDONLY, VKI_S_IRUSR);
+ if (!sr_isError(res))
+ VG_(cl_exec_fd) = sr_Res(res);
+
+ /* Copy necessary bits of 'info' that were filled in */
+ *client_ip = info->init_ip;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's environment ===*/
+/*====================================================================*/
+
+/* Prepare the client's environment. This is basically a copy of our
+ environment, except:
+
+ DYLD_INSERT_LIBRARIES=$VALGRIND_LIB/vgpreload_core-PLATFORM.so:
+ ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)?
+ DYLD_INSERT_LIBRARIES
+
+ If this is missing, then it is added.
+
+ Also, remove any binding for VALGRIND_LAUNCHER=. The client should
+ not be able to see this.
+
+ Also, add DYLD_SHARED_REGION=avoid, because V doesn't know how
+ to process the dyld shared cache file.
+
+ Also, change VYLD_* (mangled by launcher) back to DYLD_*.
+
+ If this needs to handle any more variables it should be hacked
+ into something table driven. The copy is VG_(malloc)'d space.
+*/
+static HChar** setup_client_env ( HChar** origenv, const HChar* toolname)
+{
+ HChar* preload_core = "vgpreload_core";
+ HChar* ld_preload = "DYLD_INSERT_LIBRARIES=";
+ HChar* dyld_cache = "DYLD_SHARED_REGION=";
+ HChar* dyld_cache_value= "avoid";
+ HChar* v_launcher = VALGRIND_LAUNCHER "=";
+ Int ld_preload_len = VG_(strlen)( ld_preload );
+ Int dyld_cache_len = VG_(strlen)( dyld_cache );
+ Int v_launcher_len = VG_(strlen)( v_launcher );
+ Bool ld_preload_done = False;
+ Bool dyld_cache_done = False;
+ Int vglib_len = VG_(strlen)(VG_(libdir));
+
+ HChar** cpp;
+ HChar** ret;
+ HChar* preload_tool_path;
+ Int envc, i;
+
+ /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+ paths. We might not need the space for vgpreload_<tool>.so, but it
+ doesn't hurt to over-allocate briefly. The 16s are just cautious
+ slop. */
+ Int preload_core_path_len = vglib_len + sizeof(preload_core)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
+ + sizeof(VG_PLATFORM) + 16;
+ Int preload_string_len = preload_core_path_len + preload_tool_path_len;
+ HChar* preload_string = VG_(malloc)("initimg-darwin.sce.1", preload_string_len);
+ vg_assert(preload_string);
+
+ /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
+ preload_string. */
+ preload_tool_path = VG_(malloc)("initimg-darwin.sce.2", preload_tool_path_len);
+ vg_assert(preload_tool_path);
+ VG_(snprintf)(preload_tool_path, preload_tool_path_len,
+ "%s/vgpreload_%s-%s.so", VG_(libdir), toolname, VG_PLATFORM);
+ if (VG_(access)(preload_tool_path, True/*r*/, False/*w*/, False/*x*/) == 0) {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so:%s",
+ VG_(libdir), preload_core, VG_PLATFORM, preload_tool_path);
+ } else {
+ VG_(snprintf)(preload_string, preload_string_len, "%s/%s-%s.so",
+ VG_(libdir), preload_core, VG_PLATFORM);
+ }
+ VG_(free)(preload_tool_path);
+
+ VG_(debugLog)(2, "initimg", "preload_string:\n");
+ VG_(debugLog)(2, "initimg", " \"%s\"\n", preload_string);
+
+ /* Count the original size of the env */
+ envc = 0;
+ for (cpp = origenv; cpp && *cpp; cpp++)
+ envc++;
+
+ /* Allocate a new space */
+ ret = VG_(malloc) ("initimg-darwin.sce.3",
+ sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
+ vg_assert(ret);
+
+ /* copy it over */
+ for (cpp = ret; *origenv; )
+ *cpp++ = *origenv++;
+ *cpp = NULL;
+
+ vg_assert(envc == (cpp - ret));
+
+ /* Walk over the new environment, mashing as we go */
+ for (cpp = ret; cpp && *cpp; cpp++) {
+ if (VG_(memcmp)(*cpp, ld_preload, ld_preload_len) == 0) {
+ Int len = VG_(strlen)(*cpp) + preload_string_len;
+ HChar *cp = VG_(malloc)("initimg-darwin.sce.4", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s:%s",
+ ld_preload, preload_string, (*cpp)+ld_preload_len);
+
+ *cpp = cp;
+
+ ld_preload_done = True;
+ }
+ if (VG_(memcmp)(*cpp, dyld_cache, dyld_cache_len) == 0) {
+ Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
+ HChar *cp = VG_(malloc)("initimg-darwin.sce.4.2", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
+
+ *cpp = cp;
+
+ ld_preload_done = True;
+ }
+ }
+
+ /* Add the missing bits */
+ if (!ld_preload_done) {
+ Int len = ld_preload_len + preload_string_len;
+ HChar *cp = VG_(malloc) ("initimg-darwin.sce.5", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+ ret[envc++] = cp;
+ }
+ if (!dyld_cache_done) {
+ Int len = dyld_cache_len + VG_(strlen)(dyld_cache_value) + 1;
+ HChar *cp = VG_(malloc) ("initimg-darwin.sce.5.2", len);
+ vg_assert(cp);
+
+ VG_(snprintf)(cp, len, "%s%s", dyld_cache, dyld_cache_value);
+
+ ret[envc++] = cp;
+ }
+
+
+ /* ret[0 .. envc-1] is live now. */
+ /* Find and remove a binding for VALGRIND_LAUNCHER. */
+ for (i = 0; i < envc; i++)
+ if (0 == VG_(memcmp)(ret[i], v_launcher, v_launcher_len))
+ break;
+
+ if (i < envc) {
+ for (; i < envc-1; i++)
+ ret[i] = ret[i+1];
+ envc--;
+ }
+
+ /* Change VYLD_ to DYLD */
+ for (i = 0; i < envc; i++) {
+ if (0 == VG_(strncmp)(ret[i], "VYLD_", 5)) {
+ ret[i][0] = 'D';
+ }
+ }
+
+
+ VG_(free)(preload_string);
+ ret[envc] = NULL;
+ return ret;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's stack ===*/
+/*====================================================================*/
+
+/* Add a string onto the string table, and return its address */
+static char *copy_str(char **tab, const char *str)
+{
+ char *cp = *tab;
+ char *orig = cp;
+
+ while(*str)
+ *cp++ = *str++;
+ *cp++ = '\0';
+
+ if (0)
+ VG_(printf)("copied %p \"%s\" len %lld\n", orig, orig, (Long)(cp-orig));
+
+ *tab = cp;
+
+ return orig;
+}
+
+
+/* ----------------------------------------------------------------
+
+ This sets up the client's initial stack, containing the args,
+ environment and aux vector.
+
+ The format of the stack on Darwin is:
+
+ higher address +-----------------+ <- clstack_end
+ | |
+ : string table :
+ | |
+ +-----------------+
+ | NULL |
+ +-----------------+
+ | executable_path | (first arg to execve())
+ +-----------------+
+ | NULL |
+ - -
+ | envp |
+ +-----------------+
+ | NULL |
+ - -
+ | argv |
+ +-----------------+
+ | argc |
+ +-----------------+
+ | mach_header * | (dynamic only)
+ lower address +-----------------+ <- sp
+ | undefined |
+ : :
+
+ Allocate and create the initial client stack. It is allocated down
+ from clstack_end, which was previously determined by the address
+ space manager. The returned value is the SP value for the client.
+
+ ---------------------------------------------------------------- */
+
+static
+Addr setup_client_stack( void* init_sp,
+ char** orig_envp,
+ const ExeInfo* info,
+ Addr clstack_end,
+ SizeT clstack_max_size )
+{
+ char **cpp;
+ char *strtab; /* string table */
+ char *stringbase;
+ Addr *ptr;
+ unsigned stringsize; /* total size of strings in bytes */
+ unsigned auxsize; /* total size of auxv in bytes */
+ Int argc; /* total argc */
+ Int envc; /* total number of env vars */
+ unsigned stacksize; /* total client stack size */
+ Addr client_SP; /* client stack base (initial SP) */
+ Addr clstack_start;
+ Int i;
+ Bool have_exename;
+
+ vg_assert(VG_IS_PAGE_ALIGNED(clstack_end+1));
+ vg_assert( VG_(args_for_client) );
+
+ /* ==================== compute sizes ==================== */
+
+ /* first of all, work out how big the client stack will be */
+ stringsize = 0;
+ auxsize = 0;
+ have_exename = VG_(args_the_exename) != NULL;
+
+ /* paste on the extra args if the loader needs them (ie, the #!
+ interpreter and its argument) */
+ argc = 0;
+ if (info->interp_name != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_name) + 1;
+ }
+ if (info->interp_args != NULL) {
+ argc++;
+ stringsize += VG_(strlen)(info->interp_args) + 1;
+ }
+
+ /* now scan the args we're given... */
+ if (have_exename)
+ stringsize += VG_(strlen)( VG_(args_the_exename) ) + 1;
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ argc++;
+ stringsize += VG_(strlen)( * (HChar**)
+ VG_(indexXA)( VG_(args_for_client), i ))
+ + 1;
+ }
+
+ /* ...and the environment */
+ envc = 0;
+ for (cpp = orig_envp; cpp && *cpp; cpp++) {
+ envc++;
+ stringsize += VG_(strlen)(*cpp) + 1;
+ }
+
+ /* Darwin executable_path + NULL */
+ auxsize += 2 * sizeof(Word);
+ if (info->executable_path) {
+ stringsize += 1 + VG_(strlen)(info->executable_path);
+ }
+
+ /* Darwin mach_header */
+ if (info->dynamic) auxsize += sizeof(Word);
+
+ /* OK, now we know how big the client stack is */
+ stacksize =
+ sizeof(Word) + /* argc */
+ (have_exename ? sizeof(char **) : 0) + /* argc[0] == exename */
+ sizeof(char **)*argc + /* argv */
+ sizeof(char **) + /* terminal NULL */
+ sizeof(char **)*envc + /* envp */
+ sizeof(char **) + /* terminal NULL */
+ auxsize + /* auxv */
+ VG_ROUNDUP(stringsize, sizeof(Word)); /* strings (aligned) */
+
+ if (0) VG_(printf)("stacksize = %d\n", stacksize);
+
+ /* client_SP is the client's stack pointer */
+ client_SP = clstack_end - stacksize;
+ client_SP = VG_ROUNDDN(client_SP, 32); /* make stack 32 byte aligned */
+
+ /* base of the string table (aligned) */
+ stringbase = strtab = (char *)clstack_end
+ - VG_ROUNDUP(stringsize, sizeof(int));
+
+ /* The max stack size */
+ clstack_max_size = VG_PGROUNDUP(clstack_max_size);
+
+ /* Darwin stack is chosen by the ume loader */
+ clstack_start = clstack_end - clstack_max_size;
+
+ /* Record stack extent -- needed for stack-change code. */
+ /* GrP fixme really? */
+ VG_(clstk_base) = clstack_start;
+ VG_(clstk_end) = clstack_end;
+
+ if (0)
+ VG_(printf)("stringsize=%d auxsize=%d stacksize=%d maxsize=0x%x\n"
+ "clstack_start %p\n"
+ "clstack_end %p\n",
+ stringsize, auxsize, stacksize, (Int)clstack_max_size,
+ (void*)clstack_start, (void*)clstack_end);
+
+ /* ==================== allocate space ==================== */
+
+ /* Stack was allocated by the ume loader. */
+
+ /* ==================== create client stack ==================== */
+
+ ptr = (Addr*)client_SP;
+
+ /* --- mach_header --- */
+ if (info->dynamic) *ptr++ = info->text;
+
+ /* --- client argc --- */
+ *ptr++ = (Addr)(argc + (have_exename ? 1 : 0));
+
+ /* --- client argv --- */
+ if (info->interp_name) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_name);
+ VG_(free)(info->interp_name);
+ }
+ if (info->interp_args) {
+ *ptr++ = (Addr)copy_str(&strtab, info->interp_args);
+ VG_(free)(info->interp_args);
+ }
+
+ if (have_exename)
+ *ptr++ = (Addr)copy_str(&strtab, VG_(args_the_exename));
+
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_client) ); i++) {
+ *ptr++ = (Addr)copy_str(
+ &strtab,
+ * (HChar**) VG_(indexXA)( VG_(args_for_client), i )
+ );
+ }
+ *ptr++ = 0;
+
+ /* --- envp --- */
+ VG_(client_envp) = (Char **)ptr;
+ for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++)
+ *ptr = (Addr)copy_str(&strtab, *cpp);
+ *ptr++ = 0;
+
+ /* --- executable_path + NULL --- */
+ if (info->executable_path)
+ *ptr++ = (Addr)copy_str(&strtab, info->executable_path);
+ else
+ *ptr++ = 0;
+ *ptr++ = 0;
+
+ vg_assert((strtab-stringbase) == stringsize);
+
+ /* client_SP is pointing at client's argc/argv */
+
+ if (0) VG_(printf)("startup SP = %#lx\n", client_SP);
+ return client_SP;
+}
+
+
+/*====================================================================*/
+/*=== Record system memory regions ===*/
+/*====================================================================*/
+
+static void record_system_memory(void)
+{
+ /* Tell aspacem where the client's kernel commpage is */
+#if defined(VGA_amd64)
+ /* commpage 0x7fff:ffe00000+ - not in vm_region */
+ // GrP fixme check again
+ VG_(am_notify_client_mmap)(0x7fffffe00000, 0x7ffffffff000-0x7fffffe00000,
+ VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
+
+#elif defined(VGA_x86)
+ /* commpage 0xfffec000+ - not in vm_region */
+ // GrP fixme check again
+ VG_(am_notify_client_mmap)(0xfffec000, 0xfffff000-0xfffec000,
+ VKI_PROT_READ|VKI_PROT_EXEC, 0, -1, 0);
+
+#else
+# error unknown architecture
+#endif
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(ii_create_image) ===*/
+/*====================================================================*/
+
+/* Create the client's initial memory image. */
+IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii )
+{
+ ExeInfo info;
+ HChar** env = NULL;
+
+ IIFinaliseImageInfo iifii;
+ VG_(memset)( &iifii, 0, sizeof(iifii) );
+
+ //--------------------------------------------------------------
+ // Load client executable, finding in $PATH if necessary
+ // p: get_helprequest_and_toolname() [for 'exec', 'need_help']
+ // p: layout_remaining_space [so there's space]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Loading client\n");
+
+ if (VG_(args_the_exename) == NULL)
+ VG_(err_missing_prog)();
+
+ load_client(&info, &iifii.initial_client_IP);
+
+ //--------------------------------------------------------------
+ // Set up client's environment
+ // p: set-libdir [for VG_(libdir)]
+ // p: get_helprequest_and_toolname [for toolname]
+ //--------------------------------------------------------------
+ VG_(debugLog)(1, "initimg", "Setup client env\n");
+ env = setup_client_env(iicii.envp, iicii.toolname);
+
+ //--------------------------------------------------------------
+ // Setup client stack, eip, and VG_(client_arg[cv])
+ // p: load_client() [for 'info']
+ // p: fix_environment() [for 'env']
+ //--------------------------------------------------------------
+ iicii.clstack_top = info.stack_end - 1;
+ iifii.clstack_max_size = info.stack_end - info.stack_start;
+
+ iifii.initial_client_SP =
+ setup_client_stack( iicii.argv - 1, env, &info,
+ iicii.clstack_top, iifii.clstack_max_size );
+
+ VG_(free)(env);
+
+ VG_(debugLog)(2, "initimg",
+ "Client info: "
+ "initial_IP=%p initial_SP=%p stack=%p..%p\n",
+ (void*)(iifii.initial_client_IP),
+ (void*)(iifii.initial_client_SP),
+ (void*)(info.stack_start),
+ (void*)(info.stack_end));
+
+
+ // Tell aspacem about commpage, etc
+ record_system_memory();
+
+ return iifii;
+}
+
+
+/*====================================================================*/
+/*=== TOP-LEVEL: VG_(ii_finalise_image) ===*/
+/*====================================================================*/
+
+/* Just before starting the client, we may need to make final
+ adjustments to its initial image. Also we need to set up the VEX
+ guest state for thread 1 (the root thread) and copy in essential
+ starting values. This is handed the IIFinaliseImageInfo created by
+ VG_(ii_create_image).
+*/
+void VG_(ii_finalise_image)( IIFinaliseImageInfo iifii )
+{
+ ThreadArchState* arch = &VG_(threads)[1].arch;
+
+ /* GrP fixme doesn't handle all registers from LC_THREAD or LC_UNIXTHREAD */
+
+# if defined(VGP_x86_darwin)
+ vg_assert(0 == sizeof(VexGuestX86State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestX86_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestX86State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_ESP = iifii.initial_client_SP;
+ arch->vex.guest_EIP = iifii.initial_client_IP;
+
+# elif defined(VGP_amd64_darwin)
+ vg_assert(0 == sizeof(VexGuestAMD64State) % 16);
+
+ /* Zero out the initial state, and set up the simulated FPU in a
+ sane way. */
+ LibVEX_GuestAMD64_initialise(&arch->vex);
+
+ /* Zero out the shadow areas. */
+ VG_(memset)(&arch->vex_shadow1, 0, sizeof(VexGuestAMD64State));
+ VG_(memset)(&arch->vex_shadow2, 0, sizeof(VexGuestAMD64State));
+
+ /* Put essential stuff into the new state. */
+ arch->vex.guest_RSP = iifii.initial_client_SP;
+ arch->vex.guest_RIP = iifii.initial_client_IP;
+
+# else
+# error Unknown platform
+# endif
+
+ /* Tell the tool that we just wrote to the registers. */
+ VG_TRACK( post_reg_write, Vg_CoreStartup, /*tid*/1, /*offset*/0,
+ sizeof(VexGuestArchState));
+}
diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c
index 8dbded3..b6bdbbe 100644
--- a/coregrind/m_libcassert.c
+++ b/coregrind/m_libcassert.c
@@ -45,7 +45,7 @@
Assertery.
------------------------------------------------------------------ */
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
# define GET_REAL_PC_SP_AND_FP(pc, sp, fp) \
asm("call 0f;" \
"0: popl %0;" \
@@ -54,7 +54,7 @@
: "=r" (pc),\
"=r" (sp),\
"=r" (fp));
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
# define GET_REAL_PC_SP_AND_FP(pc, sp, fp) \
asm("leaq 0(%%rip), %0;" \
"movq %%rsp, %1;" \
@@ -101,7 +101,7 @@
{
#if defined(VGO_linux)
(void)VG_(do_syscall1)(__NR_exit_group, status );
-#elif defined(VGO_aix5)
+#elif defined(VGO_aix5) || defined(VGO_darwin)
(void)VG_(do_syscall1)(__NR_exit, status );
#else
# error Unknown OS
diff --git a/coregrind/m_libcbase.c b/coregrind/m_libcbase.c
index 42aba3e..3614b92 100644
--- a/coregrind/m_libcbase.c
+++ b/coregrind/m_libcbase.c
@@ -155,6 +155,15 @@
return n;
}
+Char VG_(tolower) ( Char c )
+{
+ if ( c >= 'A' && c <= 'Z' ) {
+ return c - 'A' + 'a';
+ } else {
+ return c;
+ }
+}
+
/* ---------------------------------------------------------------------
String functions
------------------------------------------------------------------ */
@@ -247,6 +256,22 @@
}
}
+Int VG_(strcasecmp) ( const Char* s1, const Char* s2 )
+{
+ while (True) {
+ UChar c1 = (UChar)VG_(tolower)(*s1);
+ UChar c2 = (UChar)VG_(tolower)(*s2);
+ if (c1 == 0 && c2 == 0) return 0;
+ if (c1 == 0) return -1;
+ if (c2 == 0) return 1;
+
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+
+ s1++; s2++;
+ }
+}
+
Int VG_(strncmp) ( const Char* s1, const Char* s2, SizeT nmax )
{
SizeT n = 0;
@@ -263,6 +288,26 @@
}
}
+Int VG_(strncasecmp) ( const Char* s1, const Char* s2, SizeT nmax )
+{
+ Int n = 0;
+ while (True) {
+ UChar c1;
+ UChar c2;
+ if (n >= nmax) return 0;
+ c1 = (UChar)VG_(tolower)(*s1);
+ c2 = (UChar)VG_(tolower)(*s2);
+ if (c1 == 0 && c2 == 0) return 0;
+ if (c1 == 0) return -1;
+ if (c2 == 0) return 1;
+
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+
+ s1++; s2++; n++;
+ }
+}
+
Char* VG_(strstr) ( const Char* haystack, Char* needle )
{
SizeT n;
@@ -278,6 +323,21 @@
}
}
+Char* VG_(strcasestr) ( const Char* haystack, Char* needle )
+{
+ Int n;
+ if (haystack == NULL)
+ return NULL;
+ n = VG_(strlen)(needle);
+ while (True) {
+ if (haystack[0] == 0)
+ return NULL;
+ if (VG_(strncasecmp)(haystack, needle, n) == 0)
+ return (Char*)haystack;
+ haystack++;
+ }
+}
+
Char* VG_(strchr) ( const Char* s, Char c )
{
while (True) {
diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c
index 9cddfc0..72a9ea6 100644
--- a/coregrind/m_libcfile.c
+++ b/coregrind/m_libcfile.c
@@ -41,6 +41,11 @@
#include "pub_core_clientstate.h" // VG_(fd_hard_limit)
#include "pub_core_syscall.h"
+/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
+ of syscalls rather than the vanilla version, if a _nocancel version
+ is available. See docs/internals/Darwin-notes.txt for the reason
+ why. */
+
/* ---------------------------------------------------------------------
File stuff
------------------------------------------------------------------ */
@@ -87,6 +92,17 @@
I_die_here; /* maybe just return False? */
return False;
+# elif defined(VGO_darwin)
+ HChar tmp[VKI_MAXPATHLEN+1];
+ if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) {
+ if (n_buf > 0) {
+ VG_(strncpy)( buf, tmp, n_buf < sizeof(tmp) ? n_buf : sizeof(tmp) );
+ buf[n_buf-1] = 0;
+ }
+ if (tmp[0] == '/') return True;
+ }
+ return False;
+
# else
# error Unknown OS
# endif
@@ -94,19 +110,40 @@
SysRes VG_(open) ( const Char* pathname, Int flags, Int mode )
{
- SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode);
+# if defined(VGO_linux) || defined(VGO_aix5)
+ SysRes res = VG_(do_syscall3)(__NR_open,
+ (UWord)pathname, flags, mode);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_open_nocancel,
+ (UWord)pathname, flags, mode);
+# else
+# error Unknown OS
+# endif
return res;
}
void VG_(close) ( Int fd )
{
+ /* Hmm. Return value is not checked. That's uncool. */
+# if defined(VGO_linux) || defined(VGO_aix5)
(void)VG_(do_syscall1)(__NR_close, fd);
+# elif defined(VGO_darwin)
+ (void)VG_(do_syscall1)(__NR_close_nocancel, fd);
+# else
+# error Unknown OS
+# endif
}
Int VG_(read) ( Int fd, void* buf, Int count)
{
Int ret;
+# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_read_nocancel, fd, (UWord)buf, count);
+# else
+# error Unknown OS
+# endif
if (sr_isError(res)) {
ret = - (Int)(Word)sr_Err(res);
vg_assert(ret < 0);
@@ -120,7 +157,13 @@
Int VG_(write) ( Int fd, const void* buf, Int count)
{
Int ret;
+# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall3)(__NR_write, fd, (UWord)buf, count);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_write_nocancel, fd, (UWord)buf, count);
+# else
+# error "Unknown OS"
+# endif
if (sr_isError(res)) {
ret = - (Int)(Word)sr_Err(res);
vg_assert(ret < 0);
@@ -137,6 +180,14 @@
# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd);
return sr_isError(res) ? -1 : 0;
+# elif defined(VGO_darwin)
+ /* __NR_pipe is UX64, so produces a double-word result */
+ SysRes res = VG_(do_syscall0)(__NR_pipe);
+ if (!sr_isError(res)) {
+ fd[0] = (Int)sr_Res(res);
+ fd[1] = (Int)sr_ResHI(res);
+ }
+ return sr_isError(res) ? -1 : 0;
# else
# error "Unknown OS"
# endif
@@ -144,9 +195,12 @@
OffT VG_(lseek) ( Int fd, OffT offset, Int whence )
{
-#if defined(VGO_linux) || defined(VGO_aix5)
+# if defined(VGO_linux) || defined(VGO_aix5) || defined(VGP_amd64_darwin)
SysRes res = VG_(do_syscall3)(__NR_lseek, fd, offset, whence);
vg_assert(sizeof(OffT) == sizeof(Word));
+# elif defined(VGP_x86_darwin)
+ SysRes res = VG_(do_syscall4)(__NR_lseek, fd,
+ offset & 0xffffffff, offset >> 32, whence);
# else
# error "Unknown plat"
# endif
@@ -185,7 +239,7 @@
SysRes res;
VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
/* First try with stat64. If that doesn't work out, fall back to
the vanilla version. */
# if defined(__NR_stat64)
@@ -235,7 +289,7 @@
SysRes res;
VG_(memset)(vgbuf, 0, sizeof(*vgbuf));
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
/* First try with fstat64. If that doesn't work out, fall back to
the vanilla version. */
# if defined(__NR_fstat64)
@@ -289,7 +343,7 @@
SysRes VG_(dup2) ( Int oldfd, Int newfd )
{
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
return VG_(do_syscall2)(__NR_dup2, oldfd, newfd);
# elif defined(VGO_aix5)
I_die_here;
@@ -301,7 +355,13 @@
/* Returns -1 on error. */
Int VG_(fcntl) ( Int fd, Int cmd, Addr arg )
{
+# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall3)(__NR_fcntl, fd, cmd, arg);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_fcntl_nocancel, fd, cmd, arg);
+# else
+# error "Unknown OS"
+# endif
return sr_isError(res) ? -1 : sr_Res(res);
}
@@ -349,8 +409,8 @@
return True;
}
}
-# elif defined(VGO_aix5)
- /* We can't ask the kernel, so instead rely on launcher-aix5.c to
+# elif defined(VGO_aix5) || defined(VGO_darwin)
+ /* We can't ask the kernel, so instead rely on launcher-*.c to
tell us the startup path. Note the env var is keyed to the
parent's PID, not ours, since our parent is the launcher
process. */
@@ -399,6 +459,8 @@
/* res = getdents( fd, dirp, count ); */
res = VG_(do_syscall3)(__NR_getdents, fd, (UWord)dirp, count);
return sr_isError(res) ? -1 : sr_Res(res);
+# elif defined(VGO_darwin)
+ I_die_here;
# else
# error "Unknown OS"
# endif
@@ -503,9 +565,10 @@
return 0;
}
-/* Note this moves (or at least, is believed to move) the file pointer
+/* DDD: Note this moves (or at least, is believed to move) the file pointer
on Linux and AIX5 but doesn't on Darwin. This inconsistency should
- be fixed. */
+ be fixed. (In other words, why isn't the Linux/AIX5 version implemented in
+ terms of pread()?) */
SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset )
{
SysRes res;
@@ -516,6 +579,14 @@
return VG_(mk_SysRes_Error)( VKI_EINVAL );
res = VG_(do_syscall3)(__NR_read, fd, (UWord)buf, count );
return res;
+# elif defined(VGP_amd64_darwin)
+ res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset);
+ return res;
+# elif defined(VGP_x86_darwin)
+ /* ppc32-darwin is the same, but with the args inverted */
+ res = VG_(do_syscall5)(__NR_pread_nocancel, fd, (UWord)buf, count,
+ offset & 0xffffffff, offset >> 32);
+ return res;
# else
# error "Unknown platform"
# endif
@@ -632,7 +703,7 @@
*/
Int VG_(connect_via_socket)( UChar* str )
{
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
Int sd, res;
struct vki_sockaddr_in servAddr;
UInt ip = 0;
@@ -741,6 +812,20 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall3)(__NR_socket, domain, type, protocol);
+ if (!sr_isError(res)) {
+ // Set SO_NOSIGPIPE so write() returns EPIPE instead of raising SIGPIPE
+ Int optval = 1;
+ SysRes res2;
+ res2 = VG_(do_syscall5)(__NR_setsockopt, sr_Res(res), VKI_SOL_SOCKET,
+ VKI_SO_NOSIGPIPE, (UWord)&optval,
+ sizeof(optval));
+ // ignore setsockopt() error
+ }
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown arch"
# endif
@@ -768,6 +853,12 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall3)(__NR_connect_nocancel,
+ sockfd, (UWord)serv_addr, addrlen);
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown arch"
# endif
@@ -776,9 +867,13 @@
Int VG_(write_socket)( Int sd, void *msg, Int count )
{
/* This is actually send(). */
- /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
+
+ /* For Linux, VKI_MSG_NOSIGNAL is a request not to send SIGPIPE on
errors on stream oriented sockets when the other end breaks the
- connection. The EPIPE error is still returned. */
+ connection. The EPIPE error is still returned.
+
+ For Darwin, VG_(socket)() sets SO_NOSIGPIPE to get EPIPE instead of
+ SIGPIPE */
# if defined(VGP_x86_linux) || defined(VGP_ppc32_linux) \
|| defined(VGP_ppc64_linux)
@@ -800,6 +895,11 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+ SysRes res;
+ res = VG_(do_syscall3)(__NR_write_nocancel, sd, (UWord)msg, count);
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown platform"
# endif
@@ -826,6 +926,12 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall3)( __NR_getsockname,
+ (UWord)sd, (UWord)name, (UWord)namelen );
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown platform"
# endif
@@ -852,6 +958,12 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall3)( __NR_getpeername,
+ (UWord)sd, (UWord)name, (UWord)namelen );
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown platform"
# endif
@@ -882,12 +994,96 @@
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
I_die_here;
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall5)( __NR_getsockopt,
+ (UWord)sd, (UWord)level, (UWord)optname,
+ (UWord)optval, (UWord)optlen );
+ return sr_isError(res) ? -1 : sr_Res(res);
+
# else
# error "Unknown platform"
# endif
}
+Char *VG_(basename)(const Char *path)
+{
+ static Char buf[VKI_PATH_MAX];
+
+ const Char *p, *end;
+
+ if (path == NULL ||
+ 0 == VG_(strcmp)(path, ""))
+ {
+ return ".";
+ }
+
+ p = path + VG_(strlen)(path);
+ while (p > path && *p == '/') {
+ // skip all trailing '/'
+ p--;
+ }
+
+ if (p == path && *p == '/') return "/"; // all slashes
+
+ end = p;
+
+ while (p > path && *p != '/') {
+ // now skip non '/'
+ p--;
+ }
+
+ if (*p == '/') p++;
+
+ VG_(strncpy)(buf, p, end-p+1);
+ buf[end-p+1] = '\0';
+
+ return buf;
+}
+
+
+Char *VG_(dirname)(const Char *path)
+{
+ static Char buf[VKI_PATH_MAX];
+
+ const Char *p;
+
+ if (path == NULL ||
+ 0 == VG_(strcmp)(path, "") ||
+ 0 == VG_(strcmp)(path, "/"))
+ {
+ return ".";
+ }
+
+ p = path + VG_(strlen)(path);
+ while (p > path && *p == '/') {
+ // skip all trailing '/'
+ p--;
+ }
+
+ while (p > path && *p != '/') {
+ // now skip non '/'
+ p--;
+ }
+
+ if (p == path) {
+ if (*p == '/') return "/"; // all slashes
+ else return "."; // no slashes
+ }
+
+ while (p > path && *p == '/') {
+ // skip '/' again
+ p--;
+ }
+
+ VG_(strncpy)(buf, path, p-path+1);
+ buf[p-path+1] = '\0';
+
+ return buf;
+}
+
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c
index 86ebd23..1c02ba4 100644
--- a/coregrind/m_libcproc.c
+++ b/coregrind/m_libcproc.c
@@ -42,6 +42,17 @@
#include "pub_core_xarray.h"
#include "pub_core_clientstate.h"
+#if defined(VGO_darwin)
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach/mach.h> /* mach_thread_self */
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+#endif
+
+/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
+ of syscalls rather than the vanilla version, if a _nocancel version
+ is available. See docs/internals/Darwin-notes.txt for the reason
+ why. */
+
/* ---------------------------------------------------------------------
Command line and environment stuff
------------------------------------------------------------------ */
@@ -194,17 +205,32 @@
// when starting child processes, so they don't see that added stuff.
void VG_(env_remove_valgrind_env_stuff)(Char** envp)
{
+
+#if defined(VGO_darwin)
+
+ // Environment cleanup is also handled during parent launch
+ // in vg_preloaded.c:vg_cleanup_env().
+
+#endif
+
Int i;
Char* ld_preload_str = NULL;
Char* ld_library_path_str = NULL;
+ Char* dyld_insert_libraries_str = NULL;
Char* buf;
// Find LD_* variables
+ // DDD: should probably conditionally compiled some of this:
+ // - LD_LIBRARY_PATH is universal?
+ // - LD_PRELOAD is on Linux, not on Darwin, not sure about AIX
+ // - DYLD_INSERT_LIBRARIES and DYLD_SHARED_REGION are Darwin-only
for (i = 0; envp[i] != NULL; i++) {
if (VG_(strncmp)(envp[i], "LD_PRELOAD=", 11) == 0)
ld_preload_str = &envp[i][11];
if (VG_(strncmp)(envp[i], "LD_LIBRARY_PATH=", 16) == 0)
ld_library_path_str = &envp[i][16];
+ if (VG_(strncmp)(envp[i], "DYLD_INSERT_LIBRARIES=", 22) == 0)
+ dyld_insert_libraries_str = &envp[i][22];
}
buf = VG_(arena_malloc)(VG_AR_CORE, "libcproc.erves.1",
@@ -213,12 +239,16 @@
// Remove Valgrind-specific entries from LD_*.
VG_(sprintf)(buf, "%s*/vgpreload_*.so", VG_(libdir));
mash_colon_env(ld_preload_str, buf);
+ mash_colon_env(dyld_insert_libraries_str, buf);
VG_(sprintf)(buf, "%s*", VG_(libdir));
mash_colon_env(ld_library_path_str, buf);
// Remove VALGRIND_LAUNCHER variable.
VG_(env_unsetenv)(envp, VALGRIND_LAUNCHER);
+ // Remove DYLD_SHARED_REGION variable.
+ VG_(env_unsetenv)(envp, "DYLD_SHARED_REGION");
+
// XXX if variable becomes empty, remove it completely?
VG_(arena_free)(VG_AR_CORE, buf);
@@ -231,7 +261,12 @@
Int VG_(waitpid)(Int pid, Int *status, Int options)
{
# if defined(VGO_linux)
- SysRes res = VG_(do_syscall4)(__NR_wait4, pid, (UWord)status, options, 0);
+ SysRes res = VG_(do_syscall4)(__NR_wait4,
+ pid, (UWord)status, options, 0);
+ return sr_isError(res) ? -1 : sr_Res(res);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall4)(__NR_wait4_nocancel,
+ pid, (UWord)status, options, 0);
return sr_isError(res) ? -1 : sr_Res(res);
# elif defined(VGO_aix5)
/* magic number 4 obtained by truss-ing a C program doing
@@ -415,6 +450,11 @@
r = sr_Res(res);
return r;
+# elif defined(VGO_darwin)
+ // Darwin's gettid syscall is something else.
+ // Use Mach thread ports for lwpid instead.
+ return mach_thread_self();
+
# else
# error "Unknown OS"
# endif
@@ -489,7 +529,8 @@
return sr_Res(sres);
# elif defined(VGP_amd64_linux) || defined(VGP_ppc64_linux) \
- || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+ || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) \
+ || defined(VGO_darwin)
SysRes sres;
sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list);
if (sr_isError(sres))
@@ -527,6 +568,17 @@
return -1;
return sr_Res(res);
+# elif defined(VGO_darwin)
+ SysRes res;
+ res = VG_(do_syscall0)(__NR_fork); /* __NR_fork is UX64 */
+ if (sr_isError(res))
+ return -1;
+ /* on success: wLO = child pid; wHI = 1 for child, 0 for parent */
+ if (sr_ResHI(res) != 0) {
+ return 0; /* this is child: return 0 instead of child pid */
+ }
+ return sr_Res(res);
+
# else
# error "Unknown OS"
# endif
@@ -576,6 +628,14 @@
now = ((ULong)sec1) * 1000000ULL;
now += (ULong)(nsec / 1000);
+# elif defined(VGO_darwin)
+ { SysRes res;
+ struct vki_timeval tv_now;
+ res = VG_(do_syscall2)(__NR_gettimeofday, (UWord)&tv_now, (UWord)NULL);
+ vg_assert(! sr_isError(res));
+ now = tv_now.tv_sec * 1000000ULL + tv_now.tv_usec;
+ }
+
# else
# error "Unknown OS"
# endif
@@ -652,6 +712,7 @@
(*atforks[i].child)(tid);
}
+
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c
index cd79b19..50aa2a8 100644
--- a/coregrind/m_libcsignal.c
+++ b/coregrind/m_libcsignal.c
@@ -37,6 +37,11 @@
#include "pub_core_syscall.h"
#include "pub_core_libcsignal.h" /* self */
+/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
+ of syscalls rather than the vanilla version, if a _nocancel version
+ is available. See docs/internals/Darwin-notes.txt for the reason
+ why. */
+
/* sigemptyset, sigfullset, sigaddset and sigdelset return 0 on
success and -1 on error. */
/* I believe the indexing scheme in ->sig[] is also correct for
@@ -181,6 +186,12 @@
how, (UWord)set, (UWord)oldset);
# endif
+# elif defined(VGO_darwin)
+ /* On Darwin, __NR_sigprocmask appears to affect the entire
+ process, not just this thread. Hence need to use
+ __NR___pthread_sigmask instead. */
+ SysRes res = VG_(do_syscall3)(__NR___pthread_sigmask,
+ how, (UWord)set, (UWord)oldset);
# else
# error "Unknown OS"
# endif
@@ -188,6 +199,24 @@
}
+#if defined(VGO_darwin)
+/* A helper function for sigaction on Darwin. */
+static
+void darwin_signal_demux(void* a1, UWord a2, UWord a3, void* a4, void* a5) {
+ VG_(debugLog)(2, "libcsignal",
+ "PRE demux sig, a2 = %lu, signo = %lu\n", a2, a3);
+ if (a2 == 1)
+ ((void(*)(int))a1) (a3);
+ else
+ ((void(*)(int,void*,void*))a1) (a3,a4,a5);
+ VG_(debugLog)(2, "libcsignal",
+ "POST demux sig, a2 = %lu, signo = %lu\n", a2, a3);
+ VG_(do_syscall2)(__NR_sigreturn, (UWord)a5, 0x1E);
+ /* NOTREACHED */
+ __asm__ __volatile__("ud2");
+}
+#endif
+
Int VG_(sigaction) ( Int signum,
const vki_sigaction_toK_t* act,
vki_sigaction_fromK_t* oldact)
@@ -200,6 +229,51 @@
_VKI_NSIG_WORDS * sizeof(UWord));
return sr_isError(res) ? -1 : 0;
+# elif defined(VGO_darwin)
+ /* If we're passing a new action to the kernel, make a copy of the
+ new action, install our own sa_tramp field in it, and ignore
+ whatever we were provided with. This is OK because all the
+ sigaction requests come from m_signals, and are not directly
+ what the client program requested, so there is no chance that we
+ will inadvertantly ignore the sa_tramp field requested by the
+ client. (In fact m_signals does ignore it when building signal
+ frames for the client, but that's a completely different
+ matter).
+
+ If we're receiving an old action from the kernel, be very
+ paranoid and make sure the kernel doesn't trash bits of memory
+ that we don't expect it to. */
+ SysRes res;
+
+ vki_sigaction_toK_t actCopy;
+ struct {
+ ULong before[2];
+ vki_sigaction_fromK_t oa;
+ ULong after[2];
+ }
+ oldactCopy;
+
+ vki_sigaction_toK_t* real_act;
+ vki_sigaction_fromK_t* real_oldact;
+
+ real_act = act ? &actCopy : NULL;
+ real_oldact = oldact ? &oldactCopy.oa : NULL;
+ VG_(memset)(&oldactCopy, 0x55, sizeof(oldactCopy));
+ if (real_act) {
+ *real_act = *act;
+ real_act->sa_tramp = (void*)&darwin_signal_demux;
+ }
+ res = VG_(do_syscall3)(__NR_sigaction,
+ signum, (UWord)real_act, (UWord)real_oldact);
+ if (real_oldact) {
+ vg_assert(oldactCopy.before[0] == 0x5555555555555555ULL);
+ vg_assert(oldactCopy.before[1] == 0x5555555555555555ULL);
+ vg_assert(oldactCopy.after[0] == 0x5555555555555555ULL);
+ vg_assert(oldactCopy.after[1] == 0x5555555555555555ULL);
+ *oldact = *real_oldact;
+ }
+ return sr_isError(res) ? -1 : 0;
+
# else
# error "Unsupported OS"
# endif
@@ -213,6 +287,11 @@
{
# if defined(VGO_linux) || defined(VGO_aix5)
*toK = *fromK;
+# elif defined(VGO_darwin)
+ toK->ksa_handler = fromK->ksa_handler;
+ toK->sa_tramp = NULL; /* the cause of all the difficulty */
+ toK->sa_mask = fromK->sa_mask;
+ toK->sa_flags = fromK->sa_flags;
# else
# error "Unsupported OS"
# endif
@@ -221,7 +300,14 @@
Int VG_(kill)( Int pid, Int signo )
{
+# if defined(VGO_linux) || defined(VGO_aix5)
SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo);
+# elif defined(VGO_darwin)
+ SysRes res = VG_(do_syscall3)(__NR_kill,
+ pid, signo, 1/*posix-compliant*/);
+# else
+# error "Unsupported OS"
+# endif
return sr_isError(res) ? -1 : 0;
}
@@ -234,6 +320,12 @@
res = VG_(do_syscall2)(__NR_kill, lwpid, signo);
return sr_isError(res) ? -1 : 0;
+# elif defined(VGO_darwin)
+ // Note that the __pthread_kill syscall takes a Mach thread, not a pthread.
+ SysRes res;
+ res = VG_(do_syscall2)(__NR___pthread_kill, lwpid, signo);
+ return sr_isError(res) ? -1 : 0;
+
# else
# error "Unsupported plat"
# endif
@@ -360,8 +452,113 @@
return i;
}
+/* ---------- sigtimedwait_zero: Darwin ----------- */
+
+#elif defined(VGO_darwin)
+
+//static void show_set ( HChar* str, const vki_sigset_t* set ) {
+// Int i;
+// VG_(printf)("%s { ", str);
+// for (i = 1; i <= _VKI_NSIG; i++) {
+// if (VG_(sigismember)(set, i))
+// VG_(printf)("%u ", i);
+// }
+// VG_(printf)("}\n");
+//}
+
+static void sigtimedwait_zero_handler ( Int sig )
+{
+ /* XXX this is wrong -- get rid of these. We could
+ get _any_ signal here */
+ vg_assert(sig != VKI_SIGILL);
+ vg_assert(sig != VKI_SIGSEGV);
+ vg_assert(sig != VKI_SIGBUS);
+ vg_assert(sig != VKI_SIGTRAP);
+ /* do nothing */
+}
+
+Int VG_(sigtimedwait_zero)( const vki_sigset_t *set,
+ vki_siginfo_t *info )
+{
+ const Bool debug = False;
+ Int i, ir;
+ SysRes sr;
+ vki_sigset_t pending, blocked, allbutone;
+ vki_sigaction_toK_t sa, saved_sa2;
+ vki_sigaction_fromK_t saved_sa;
+
+ //show_set("STWZ: looking for", set);
+
+ /* Find out what's pending: Darwin sigpending */
+ sr = VG_(do_syscall1)(__NR_sigpending, (UWord)&pending);
+ vg_assert(!sr_isError(sr));
+
+ /* don't try for signals not in 'set' */
+ /* pending = pending `intersect` set */
+ VG_(sigintersectset)(&pending, (vki_sigset_t*)set);
+
+ /* don't try for signals not blocked at the moment */
+ ir = VG_(sigprocmask)(VKI_SIG_SETMASK, NULL, &blocked);
+ vg_assert(ir == 0);
+
+ /* pending = pending `intersect` blocked */
+ VG_(sigintersectset)(&pending, &blocked);
+
+ /* decide which signal we're going to snarf */
+ for (i = 1; i < _VKI_NSIG; i++)
+ if (VG_(sigismember)(&pending,i))
+ break;
+
+ if (i == _VKI_NSIG)
+ return 0;
+
+ if (debug)
+ VG_(debugLog)(0, "libcsignal",
+ "sigtimedwait_zero: snarfing signal %d\n", i );
+
+ /* fetch signal i.
+ pre: i is blocked and pending
+ pre: we are the only thread running
+ */
+ /* Set up alternative signal handler */
+ VG_(sigfillset)(&sa.sa_mask);
+ sa.ksa_handler = &sigtimedwait_zero_handler;
+ sa.sa_flags = 0;
+ ir = VG_(sigaction)(i, &sa, &saved_sa);
+ vg_assert(ir == 0);
+
+ /* Switch signal masks and wait for the signal. This should happen
+ immediately, since we've already established it is pending and
+ blocked. */
+ VG_(sigfillset)(&allbutone);
+ VG_(sigdelset)(&allbutone, i);
+ /* Note: pass the sig mask by value here, not reference (!) */
+ vg_assert(_VKI_NSIG_WORDS == 1);
+ sr = VG_(do_syscall3)(__NR_sigsuspend_nocancel,
+ (UWord)allbutone.sig[0], 0,0);
+ if (debug)
+ VG_(debugLog)(0, "libcsignal",
+ "sigtimedwait_zero: sigsuspend got "
+ "res: %s %#lx\n",
+ sr_isError(sr) ? "FAIL" : "SUCCESS",
+ sr_isError(sr) ? sr_Err(sr) : sr_Res(sr));
+ vg_assert(sr_isError(sr));
+ vg_assert(sr_Err(sr) == VKI_EINTR);
+
+ /* Restore signal's handler to whatever it was before */
+ VG_(convert_sigaction_fromK_to_toK)( &saved_sa, &saved_sa2 );
+ ir = VG_(sigaction)(i, &saved_sa2, NULL);
+ vg_assert(ir == 0);
+
+ /* This is bogus - we could get more info from the sighandler. */
+ VG_(memset)( info, 0, sizeof(*info) );
+ info->si_signo = i;
+
+ return i;
+}
+
#else
-# error Unknown OS
+# error "Unknown OS"
#endif
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_basics.c b/coregrind/m_mach/mach_basics.c
new file mode 100644
index 0000000..cd6df6c
--- /dev/null
+++ b/coregrind/m_mach/mach_basics.c
@@ -0,0 +1,101 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach interface functions mach_basics.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_mach.h"
+
+#if defined(VGO_darwin)
+
+#include <mach/mach.h>
+#include <mach/machine/ndr_def.h>
+
+/* From mach_traps-<arch>-darwin.S */
+//extern mach_port_name_t host_self_trap(void);
+extern mach_port_name_t thread_self_trap(void);
+extern mach_port_t mach_reply_port(void);
+
+/* Global variables set in mach_init() */
+vm_size_t vm_page_size = 0;
+mach_port_name_t mach_task_self_ = 0;
+
+
+mach_port_name_t mach_thread_self(void)
+{
+ return thread_self_trap();
+}
+
+static mach_port_t reply = 0;
+
+mach_port_t mig_get_reply_port(void)
+{
+ if (!reply) reply = mach_reply_port();
+ return reply;
+ // GrP fixme is just one enough for valgrind's own use?
+ // might work if valgrind never blocks in mig calls on
+ // its own behalf, and doesn't call mig outside the semaphore
+}
+
+
+void mig_dealloc_reply_port(mach_port_t reply_port)
+{
+}
+
+
+void mig_put_reply_port(mach_port_t reply_port)
+{
+}
+
+
+/* Initialize Mach global data.
+ Should be called early in main(). */
+void VG_(mach_init)(void)
+{
+ reply = 0;
+ mach_task_self_ = task_self_trap();
+
+ // GrP fixme host_page_size(host_self_trap(), &vm_page_size);
+ vm_page_size = 4096;
+}
+
+
+#else
+
+// For platforms that don't actually have Mach kernel interfaces
+
+void VG_(mach_init)(void)
+{
+ // do nothing
+}
+
+#endif
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_msg.c b/coregrind/m_mach/mach_msg.c
new file mode 100644
index 0000000..0b9aa96
--- /dev/null
+++ b/coregrind/m_mach/mach_msg.c
@@ -0,0 +1,106 @@
+#include "pub_core_basics.h"
+#include "pub_core_mach.h"
+
+#if defined(VGO_darwin)
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * HISTORY
+ * $Log:mach_msg.c,v $
+ * Revision 2.3 92/01/23 15:22:17 rpd
+ * Fixed to not pass MACH_SEND_INTERRUPT and MACH_RCV_INTERRUPT
+ * to the kernel.
+ * [92/01/20 rpd]
+ *
+ * Revision 2.2 92/01/15 17:17:13 rpd
+ * Created from msg.c.
+ * [92/01/15 rpd]
+ *
+ */
+
+#include <mach/port.h>
+#include <mach/message.h>
+
+#define LIBMACH_OPTIONS (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
+
+extern mach_msg_return_t
+mach_msg_trap(mach_msg_header_t *msg,
+ mach_msg_option_t option,
+ mach_msg_size_t send_size,
+ mach_msg_size_t rcv_size,
+ mach_port_t rcv_name,
+ mach_msg_timeout_t timeout,
+ mach_port_t notify);
+
+mach_msg_return_t
+mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify)
+ mach_msg_header_t *msg;
+ mach_msg_option_t option;
+ mach_msg_size_t send_size;
+ mach_msg_size_t rcv_size;
+ mach_port_t rcv_name;
+ mach_msg_timeout_t timeout;
+ mach_port_t notify;
+{
+ mach_msg_return_t mr;
+
+ /*
+ * Consider the following cases:
+ *1) Errors in pseudo-receive (eg, MACH_SEND_INTERRUPTED
+ *plus special bits).
+ *2) Use of MACH_SEND_INTERRUPT/MACH_RCV_INTERRUPT options.
+ *3) RPC calls with interruptions in one/both halves.
+ *
+ * We refrain from passing the option bits that we implement
+ * to the kernel. This prevents their presence from inhibiting
+ * the kernel's fast paths (when it checks the option value).
+ */
+
+ mr = mach_msg_trap(msg, option &~ LIBMACH_OPTIONS,
+ send_size, rcv_size, rcv_name,
+ timeout, notify);
+ if (mr == MACH_MSG_SUCCESS)
+ return MACH_MSG_SUCCESS;
+
+ if ((option & MACH_SEND_INTERRUPT) == 0)
+ while (mr == MACH_SEND_INTERRUPTED)
+ mr = mach_msg_trap(msg,
+ option &~ LIBMACH_OPTIONS,
+ send_size, rcv_size, rcv_name,
+ timeout, notify);
+
+ if ((option & MACH_RCV_INTERRUPT) == 0)
+ while (mr == MACH_RCV_INTERRUPTED)
+ mr = mach_msg_trap(msg,
+ option &~ (LIBMACH_OPTIONS|MACH_SEND_MSG),
+ 0, rcv_size, rcv_name,
+ timeout, notify);
+
+ return mr;
+}
+
+#endif
diff --git a/coregrind/m_mach/mach_traps-amd64-darwin.S b/coregrind/m_mach/mach_traps-amd64-darwin.S
new file mode 100644
index 0000000..7a85e41
--- /dev/null
+++ b/coregrind/m_mach/mach_traps-amd64-darwin.S
@@ -0,0 +1,136 @@
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach traps mach_traps.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2007 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "vki/vki-scnums-darwin.h"
+
+ // mach_port_name_t task_self_trap(void)
+ .text
+ .align 4
+ .globl _task_self_trap
+_task_self_trap:
+ movq $__NR_task_self_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+// DDD: doesn't get used...
+// // mach_port_name_t host_self_trap(void)
+// .text
+// .align 4
+// .globl _host_self_trap
+//_host_self_trap:
+// movq $__NR_host_self_trap, %rax
+// movq %rcx, %r10
+// syscall
+// ret
+
+ // mach_port_name_t thread_self_trap(void)
+ .text
+ .align 4
+ .globl _thread_self_trap
+_thread_self_trap:
+ movq $__NR_thread_self_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // mach_msg_return_t mach_msg_trap(...)
+ .text
+ .align 4
+ .globl _mach_msg_trap
+_mach_msg_trap:
+ movq $__NR_mach_msg_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // mach_port_t mach_reply_port(...)
+ .text
+ .align 4
+ .globl _mach_reply_port
+_mach_reply_port:
+ movq $__NR_mach_reply_port, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // boolean_t swtch_pri(int)
+ .text
+ .align 4
+ .globl _swtch_pri
+_swtch_pri:
+ movq $__NR_swtch_pri, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // kern_return_t semaphore_wait(semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_wait
+_semaphore_wait:
+ movq $__NR_semaphore_wait_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // kern_return_t semaphore_signal(semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_signal
+_semaphore_signal:
+ movq $__NR_semaphore_signal_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // kern_return_t semaphore_signal_thread(semaphore_t, thread_t)
+ .text
+ .align 4
+ .globl _semaphore_signal_thread
+_semaphore_signal_thread:
+ movq $__NR_semaphore_signal_thread_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+ // kern_return_t semaphore_wait_signal(semaphore_t, semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_wait_signal
+_semaphore_wait_signal:
+ movq $__NR_semaphore_wait_signal_trap, %rax
+ movq %rcx, %r10
+ syscall
+ ret
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_mach/mach_traps-x86-darwin.S b/coregrind/m_mach/mach_traps-x86-darwin.S
new file mode 100644
index 0000000..b843834
--- /dev/null
+++ b/coregrind/m_mach/mach_traps-x86-darwin.S
@@ -0,0 +1,124 @@
+/*--------------------------------------------------------------------*/
+/*--- Basic Mach traps mach_traps.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+
+ // mach_port_name_t task_self_trap(void)
+ .text
+ .align 4
+ .globl _task_self_trap
+_task_self_trap:
+ mov $-28, %eax
+ int $0x81
+ ret
+
+ // mach_port_name_t host_self_trap(void)
+ .text
+ .align 4
+ .globl _host_self_trap
+_host_self_trap:
+ mov $-29, %eax
+ int $0x81
+ ret
+
+ // mach_port_name_t thread_self_trap(void)
+ .text
+ .align 4
+ .globl _thread_self_trap
+_thread_self_trap:
+ mov $-27, %eax
+ int $0x81
+ ret
+
+ // mach_msg_return_t mach_msg_trap(...)
+ .text
+ .align 4
+ .globl _mach_msg_trap
+_mach_msg_trap:
+ mov $-31, %eax
+ int $0x81
+ ret
+
+ // mach_port_t mach_reply_port(...)
+ .text
+ .align 4
+ .globl _mach_reply_port
+_mach_reply_port:
+ mov $-26, %eax
+ int $0x81
+ ret
+
+ // boolean_t swtch_pri(int)
+ .text
+ .align 4
+ .globl _swtch_pri
+_swtch_pri:
+ mov $-59, %eax
+ int $0x81
+ ret
+
+ // kern_return_t semaphore_wait(semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_wait
+_semaphore_wait:
+ mov $-36, %eax
+ int $0x81
+ ret
+
+ // kern_return_t semaphore_signal(semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_signal
+_semaphore_signal:
+ mov $-33, %eax
+ int $0x81
+ ret
+
+ // kern_return_t semaphore_signal_thread(semaphore_t, thread_t)
+ .text
+ .align 4
+ .globl _semaphore_signal_thread
+_semaphore_signal_thread:
+ mov $-35, %eax
+ int $0x81
+ ret
+
+ // kern_return_t semaphore_wait_signal(semaphore_t, semaphore_t)
+ .text
+ .align 4
+ .globl _semaphore_wait_signal
+_semaphore_wait_signal:
+ mov $-37, %eax
+ int $0x81
+ ret
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c
index 0429bfe..e85b917 100644
--- a/coregrind/m_machine.c
+++ b/coregrind/m_machine.c
@@ -98,6 +98,8 @@
VG_(threads)[tid].arch.vex_shadow2.guest_GPR3 = s2res;
VG_(threads)[tid].arch.vex_shadow1.guest_GPR4 = s1err;
VG_(threads)[tid].arch.vex_shadow2.guest_GPR4 = s2err;
+# elif defined(VGO_darwin)
+ // GrP fixme darwin syscalls may return more values (2 registers plus error)
# else
# error "Unknown plat"
# endif
@@ -672,8 +674,8 @@
// produce a pointer to the actual entry point for the function.
void* VG_(fnptr_to_fnentry)( void* f )
{
-#if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
- || defined(VGP_ppc32_linux)
+#if defined(VGP_x86_linux) || defined(VGP_amd64_linux) || \
+ defined(VGP_ppc32_linux) || defined(VGO_darwin)
return f;
#elif defined(VGP_ppc64_linux) || defined(VGP_ppc32_aix5) \
|| defined(VGP_ppc64_aix5)
diff --git a/coregrind/m_main.c b/coregrind/m_main.c
index e880e3c..f3dfbcd 100644
--- a/coregrind/m_main.c
+++ b/coregrind/m_main.c
@@ -48,6 +48,7 @@
#include "pub_core_libcproc.h"
#include "pub_core_libcsignal.h"
#include "pub_core_syscall.h" // VG_(strerror)
+#include "pub_core_mach.h"
#include "pub_core_machine.h"
#include "pub_core_mallocfree.h"
#include "pub_core_options.h"
@@ -435,6 +436,9 @@
else if VG_STR_CLO (arg, "--kernel-variant", VG_(clo_kernel_variant)) {}
+ else if VG_BOOL_CLO(arg, "--auto-run-dsymutil",
+ VG_(clo_auto_run_dsymutil)) {}
+
else if VG_BINT_CLO(arg, "--vex-iropt-verbosity",
VG_(clo_vex_control).iropt_verbosity, 0, 10) {}
else if VG_BINT_CLO(arg, "--vex-iropt-level",
@@ -956,6 +960,14 @@
rl.rlim_max = 1024;
}
+# if defined(VGO_darwin)
+ /* Darwin lies. It reports file max as RLIM_INFINITY but
+ silently disallows anything bigger than 10240. */
+ if (rl.rlim_cur >= 10240 && rl.rlim_max == 0x7fffffffffffffffULL) {
+ rl.rlim_max = 10240;
+ }
+# endif
+
if (show)
VG_(printf)("fd limits: host, before: cur %lu max %lu\n",
(UWord)rl.rlim_cur, (UWord)rl.rlim_max);
@@ -1153,6 +1165,14 @@
VG_(client_envp) = (Char**)envp;
//--------------------------------------------------------------
+ // Start up Mach kernel interface, if any
+ // p: none
+ //--------------------------------------------------------------
+# if defined(VGO_darwin)
+ VG_(mach_init)();
+# endif
+
+ //--------------------------------------------------------------
// Start up the logging mechanism
// p: none
//--------------------------------------------------------------
@@ -1229,9 +1249,28 @@
# endif
//--------------------------------------------------------------
+ // Darwin only: munmap address-space-filling segments
+ // (oversized pagezero or stack)
+ // p: none
+ //--------------------------------------------------------------
+#if defined(VGO_darwin)
+# if VG_WORDSIZE == 4
+ VG_(do_syscall2)(__NR_munmap, 0x00000000, 0xf0000000);
+# else
+ // open up client space
+ VG_(do_syscall2)(__NR_munmap, 0x100000000, 0x700000000000-0x100000000);
+ // open up client stack and dyld
+ VG_(do_syscall2)(__NR_munmap, 0x7fff5c000000, 0x4000000);
+# endif
+#endif
+
+ //--------------------------------------------------------------
// Ensure we're on a plausible stack.
// p: logging
//--------------------------------------------------------------
+#if defined(VGO_darwin)
+ // Darwin doesn't use the interim stack.
+#else
VG_(debugLog)(1, "main", "Checking current stack is plausible\n");
{ HChar* limLo = (HChar*)(&VG_(interim_stack).bytes[0]);
HChar* limHi = limLo + sizeof(VG_(interim_stack));
@@ -1259,11 +1298,12 @@
VG_(debugLog)(0, "main", " Cannot continue. Sorry.\n");
VG_(exit)(1);
}
+#endif
//--------------------------------------------------------------
// Start up the address space manager, and determine the
// approximate location of the client's stack
- // p: logging, plausible-stack
+ // p: logging, plausible-stack, darwin-munmap
//--------------------------------------------------------------
VG_(debugLog)(1, "main", "Starting the address space manager\n");
vg_assert(VKI_PAGE_SIZE == 4096 || VKI_PAGE_SIZE == 65536);
@@ -1453,7 +1493,7 @@
if (!need_help) {
VG_(debugLog)(1, "main", "Create initial image\n");
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
the_iicii.argv = argv;
the_iicii.envp = envp;
the_iicii.toolname = toolname;
@@ -1509,6 +1549,10 @@
// when it tries to open /proc/<pid>/cmdline for itself.
// p: setup file descriptors
//--------------------------------------------------------------
+#if !HAVE_PROC
+ // client shouldn't be using /proc!
+ VG_(cl_cmdline_fd) = -1;
+#else
if (!need_help) {
HChar buf[50], buf2[50+64];
HChar nul[1];
@@ -1546,6 +1590,7 @@
VG_(cl_cmdline_fd) = fd;
}
+#endif
//--------------------------------------------------------------
// Init tool part 1: pre_clo_init
@@ -1650,6 +1695,8 @@
iters = 5;
# elif defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
iters = 4;
+# elif defined(VGO_darwin)
+ iters = 3;
# else
# error "Unknown plat"
# endif
@@ -1752,6 +1799,20 @@
VG_(free)(changes);
}
+# elif defined(VGO_darwin)
+ { Addr* seg_starts;
+ Int n_seg_starts;
+ seg_starts = VG_(get_segment_starts)( &n_seg_starts );
+ vg_assert(seg_starts && n_seg_starts >= 0);
+
+ /* show them all to the debug info reader.
+ Don't read from V segments (unlike Linux) */
+ // GrP fixme really?
+ for (i = 0; i < n_seg_starts; i++)
+ VG_(di_notify_mmap)( seg_starts[i], False/*don't allow_SkFileV*/ );
+
+ VG_(free)( seg_starts );
+ }
# else
# error Unknown OS
# endif
@@ -2168,6 +2229,13 @@
/* We were killed by a fatal signal, so replicate the effect */
vg_assert(VG_(threads)[tid].os_state.fatalsig != 0);
VG_(kill_self)(VG_(threads)[tid].os_state.fatalsig);
+ /* we shouldn't be alive at this point. But VG_(kill_self)
+ sometimes fails with EPERM on Darwin, for unclear reasons. */
+# if defined(VGO_darwin)
+ VG_(debugLog)(0, "main", "VG_(kill_self) failed. Exiting normally.\n");
+ VG_(exit)(0); /* bogus, but we really need to exit now */
+ /* fall through .. */
+# endif
VG_(core_panic)("main(): signal was supposed to be fatal");
break;
@@ -2181,9 +2249,11 @@
/* Final clean-up before terminating the process.
Clean up the client by calling __libc_freeres() (if requested)
This is Linux-specific?
+ GrP fixme glibc-specific, anyway
*/
static void final_tidyup(ThreadId tid)
{
+#if !defined(VGO_darwin)
# if defined(VGP_ppc64_linux)
Addr r2;
# endif
@@ -2247,6 +2317,7 @@
VG_(scheduler)(tid);
vg_assert(VG_(is_exiting)(tid));
+#endif
}
@@ -2585,6 +2656,59 @@
void max_pw_passlen ( void ) { vg_assert(0); }
+/*====================================================================*/
+/*=== Getting to main() alive: darwin ===*/
+/*====================================================================*/
+
+#elif defined(VGO_darwin)
+
+void* __memcpy_chk(void *dest, const void *src, SizeT n, SizeT n2);
+void* __memcpy_chk(void *dest, const void *src, SizeT n, SizeT n2) {
+ // skip check
+ return VG_(memcpy)(dest,src,n);
+}
+void* __memset_chk(void *s, int c, SizeT n, SizeT n2);
+void* __memset_chk(void *s, int c, SizeT n, SizeT n2) {
+ // skip check
+ return VG_(memset)(s,c,n);
+}
+void bzero(void *s, SizeT n);
+void bzero(void *s, SizeT n) {
+ VG_(memset)(s,0,n);
+}
+
+void* memcpy(void *dest, const void *src, SizeT n);
+void* memcpy(void *dest, const void *src, SizeT n) {
+ return VG_(memcpy)(dest,src,n);
+}
+void* memset(void *s, int c, SizeT n);
+void* memset(void *s, int c, SizeT n) {
+ return VG_(memset)(s,c,n);
+}
+
+/* _start in m_start-<arch>-darwin.S calls _start_in_C_darwin(). */
+
+/* Avoid compiler warnings: this fn _is_ used, but labelling it
+ 'static' causes gcc to complain it isn't. */
+void _start_in_C_darwin ( UWord* pArgc );
+void _start_in_C_darwin ( UWord* pArgc )
+{
+ Int r;
+ Int argc = *(Int *)pArgc; // not pArgc[0] on LP64
+ HChar** argv = (HChar**)&pArgc[1];
+ HChar** envp = (HChar**)&pArgc[1+argc+1];
+
+ VG_(memset)( &the_iicii, 0, sizeof(the_iicii) );
+ VG_(memset)( &the_iifii, 0, sizeof(the_iifii) );
+
+ the_iicii.sp_at_startup = (Addr)pArgc;
+
+ r = valgrind_main( (Int)argc, argv, envp );
+ /* NOTREACHED */
+ VG_(exit)(r);
+}
+
+
#else
# error "Unknown OS"
diff --git a/coregrind/m_options.c b/coregrind/m_options.c
index 2a06fcd..089ed1d 100644
--- a/coregrind/m_options.c
+++ b/coregrind/m_options.c
@@ -90,6 +90,7 @@
Bool VG_(clo_wait_for_gdb) = False;
VgSmc VG_(clo_smc_check) = Vg_SmcStack;
HChar* VG_(clo_kernel_variant) = NULL;
+Bool VG_(clo_auto_run_dsymutil) = False;
/*====================================================================*/
diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c
index d31d90f..d824a79 100644
--- a/coregrind/m_redir.c
+++ b/coregrind/m_redir.c
@@ -940,6 +940,27 @@
# elif defined(VGP_ppc64_aix5)
/* nothing so far */
+# elif defined(VGO_darwin)
+ /* If we're using memcheck, use these intercepts right from
+ the start, otherwise dyld makes a lot of noise. */
+ if (0==VG_(strcmp)("Memcheck", VG_(details).name)) {
+ add_hardwired_spec("dyld", "strcmp",
+ (Addr)&VG_(darwin_REDIR_FOR_strcmp), NULL);
+ add_hardwired_spec("dyld", "strlen",
+ (Addr)&VG_(darwin_REDIR_FOR_strlen), NULL);
+ add_hardwired_spec("dyld", "strcat",
+ (Addr)&VG_(darwin_REDIR_FOR_strcat), NULL);
+ add_hardwired_spec("dyld", "strcpy",
+ (Addr)&VG_(darwin_REDIR_FOR_strcpy), NULL);
+ add_hardwired_spec("dyld", "strlcat",
+ (Addr)&VG_(darwin_REDIR_FOR_strlcat), NULL);
+#if defined(VGP_amd64_darwin)
+ // DDD: #warning fixme rdar://6166275
+ add_hardwired_spec("dyld", "arc4random",
+ (Addr)&VG_(darwin_REDIR_FOR_arc4random), NULL);
+#endif
+ }
+
# else
# error Unknown platform
# endif
diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c
index 5e2757b..b36e802 100644
--- a/coregrind/m_replacemalloc/vg_replace_malloc.c
+++ b/coregrind/m_replacemalloc/vg_replace_malloc.c
@@ -144,6 +144,21 @@
return v; \
}
+#define ZONEALLOC_or_NULL(soname, fnname, vg_replacement) \
+ \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, SizeT n); \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, SizeT n) \
+ { \
+ void* v; \
+ \
+ if (!init_done) init(); \
+ MALLOC_TRACE(#fnname "(%p, %llu)", zone, (ULong)n ); \
+ \
+ v = (void*)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, n ); \
+ MALLOC_TRACE(" = %p", v ); \
+ return v; \
+ }
+
/* Generate a replacement for 'fnname' in object 'soname', which calls
'vg_replacement' to allocate memory. If that fails, it bombs the
@@ -178,6 +193,8 @@
ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc);
#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc_common, malloc);
+#elif defined(VGO_darwin)
+ZONEALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc_zone_malloc, malloc);
#endif
@@ -197,7 +214,7 @@
#endif
// operator new(unsigned long), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGO_darwin)
ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwm, __builtin_new);
ALLOC_or_BOMB(VG_Z_LIBC_SONAME, _Znwm, __builtin_new);
#endif
@@ -217,7 +234,7 @@
#endif
// operator new(unsigned long, std::nothrow_t const&), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new);
ALLOC_or_NULL(VG_Z_LIBC_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new);
#endif
@@ -241,7 +258,7 @@
#endif
// operator new[](unsigned long), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znam, __builtin_vec_new );
ALLOC_or_BOMB(VG_Z_LIBC_SONAME, _Znam, __builtin_vec_new );
#endif
@@ -261,7 +278,7 @@
#endif
// operator new[](unsigned long, std::nothrow_t const&), GNU mangling
-#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
+#if VG_WORDSIZE == 8 || defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5) || defined(VGO_darwin)
ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new );
ALLOC_or_NULL(VG_Z_LIBC_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new );
#endif
@@ -277,6 +294,18 @@
/* Generate a replacement for 'fnname' in object 'soname', which calls
'vg_replacement' to free previously allocated memory.
*/
+#define ZONEFREE(soname, fnname, vg_replacement) \
+ \
+ void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, void *p); \
+ void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *zone, void *p) \
+ { \
+ if (!init_done) init(); \
+ MALLOC_TRACE(#vg_replacement "(%p, %p)", zone, p ); \
+ if (p == NULL) \
+ return; \
+ (void)VALGRIND_NON_SIMD_CALL1( info.tl_##vg_replacement, p ); \
+ }
+
#define FREE(soname, fnname, vg_replacement) \
\
void VG_REPLACE_FUNCTION_ZU(soname,fnname) (void *p); \
@@ -294,6 +323,8 @@
FREE(VG_Z_LIBC_SONAME, free, free );
#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
FREE(VG_Z_LIBC_SONAME, free_common, free );
+#elif defined(VGO_darwin)
+ZONEFREE(VG_Z_LIBC_SONAME, malloc_zone_free, free );
#endif
@@ -350,6 +381,21 @@
/*---------------------- calloc ----------------------*/
+#define ZONECALLOC(soname, fnname) \
+ \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT nmemb, SizeT size ); \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT nmemb, SizeT size ) \
+ { \
+ void* v; \
+ \
+ if (!init_done) init(); \
+ MALLOC_TRACE("calloc(%p, %llu,%llu)", zone, (ULong)nmemb, (ULong)size ); \
+ \
+ v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_calloc, nmemb, size ); \
+ MALLOC_TRACE(" = %p", v ); \
+ return v; \
+ }
+
#define CALLOC(soname, fnname) \
\
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT nmemb, SizeT size ); \
@@ -368,11 +414,37 @@
CALLOC(VG_Z_LIBC_SONAME, calloc);
#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
CALLOC(VG_Z_LIBC_SONAME, calloc_common);
+#elif defined(VGO_darwin)
+ZONECALLOC(VG_Z_LIBC_SONAME, malloc_zone_calloc);
#endif
/*---------------------- realloc ----------------------*/
+#define ZONEREALLOC(soname, fnname) \
+ \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, void* ptrV, SizeT new_size );\
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, void* ptrV, SizeT new_size ) \
+ { \
+ void* v; \
+ \
+ if (!init_done) init(); \
+ MALLOC_TRACE("realloc(%p,%p,%llu)", zone, ptrV, (ULong)new_size ); \
+ \
+ if (ptrV == NULL) \
+ /* We need to call a malloc-like function; so let's use \
+ one which we know exists. GrP fixme use zonemalloc instead? */ \
+ return VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,malloc) (new_size); \
+ if (new_size <= 0) { \
+ VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,free)(ptrV); \
+ MALLOC_TRACE(" = 0"); \
+ return NULL; \
+ } \
+ v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \
+ MALLOC_TRACE(" = %p", v ); \
+ return v; \
+ }
+
#define REALLOC(soname, fnname) \
\
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void* ptrV, SizeT new_size );\
@@ -400,11 +472,36 @@
REALLOC(VG_Z_LIBC_SONAME, realloc);
#if defined(VGP_ppc32_aix5) || defined(VGP_ppc64_aix5)
REALLOC(VG_Z_LIBC_SONAME, realloc_common);
+#elif defined(VGO_darwin)
+ZONEREALLOC(VG_Z_LIBC_SONAME, malloc_zone_realloc);
#endif
/*---------------------- memalign ----------------------*/
+#define ZONEMEMALIGN(soname, fnname) \
+ \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT alignment, SizeT n ); \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT alignment, SizeT n ) \
+ { \
+ void* v; \
+ \
+ if (!init_done) init(); \
+ MALLOC_TRACE("memalign(%p, al %llu, size %llu)", \
+ zone, (ULong)alignment, (ULong)n ); \
+ \
+ /* Round up to minimum alignment if necessary. */ \
+ if (alignment < VG_MIN_MALLOC_SZB) \
+ alignment = VG_MIN_MALLOC_SZB; \
+ \
+ /* Round up to nearest power-of-two if necessary (like glibc). */ \
+ while (0 != (alignment & (alignment - 1))) alignment++; \
+ \
+ v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_memalign, alignment, n ); \
+ MALLOC_TRACE(" = %p", v ); \
+ return v; \
+ }
+
#define MEMALIGN(soname, fnname) \
\
void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( SizeT alignment, SizeT n ); \
@@ -429,6 +526,9 @@
}
MEMALIGN(VG_Z_LIBC_SONAME, memalign);
+#if defined(VGO_darwin)
+ZONEMEMALIGN(VG_Z_LIBC_SONAME, malloc_zone_memalign);
+#endif
/*---------------------- valloc ----------------------*/
@@ -454,7 +554,23 @@
((SizeT)pszB, size); \
}
+#define ZONEVALLOC(soname, fnname) \
+ \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT size ); \
+ void* VG_REPLACE_FUNCTION_ZU(soname,fnname) ( void *zone, SizeT size ) \
+ { \
+ static int pszB = 0; \
+ extern int getpagesize (void); \
+ if (pszB == 0) \
+ pszB = getpagesize(); \
+ return VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME,memalign) \
+ ((SizeT)pszB, size); \
+ }
+
VALLOC(VG_Z_LIBC_SONAME, valloc);
+#if defined(VGO_darwin)
+ZONEVALLOC(VG_Z_LIBC_SONAME, malloc_zone_valloc);
+#endif
/*---------------------- mallopt ----------------------*/
@@ -567,6 +683,7 @@
}
MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size);
+MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_size);
/*---------------------- (unimplemented) ----------------------*/
@@ -623,6 +740,58 @@
MALLINFO(VG_Z_LIBC_SONAME, mallinfo);
+#if defined(VGO_darwin)
+
+static vki_malloc_zone_t vg_default_zone = {
+ NULL, // reserved
+ NULL, // reserved
+ NULL, // GrP fixme malloc_size
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_malloc),
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_calloc),
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_valloc),
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_free),
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_realloc),
+ NULL, // GrP fixme destroy
+ "ValgrindMallocZone",
+ NULL, // batch_malloc
+ NULL, // batch_free
+ NULL, // GrP fixme introspect
+ 2, // version (GrP fixme 3?)
+ // DDD: this field exists in Mac OS 10.6, but not 10.5.
+ #if 0
+ (void*)VG_REPLACE_FUNCTION_ZU(VG_Z_LIBC_SONAME, malloc_zone_memalign)
+ #endif
+};
+
+#define DEFAULT_ZONE(soname, fnname) \
+ \
+ void *VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void ); \
+ void *VG_REPLACE_FUNCTION_ZU(soname, fnname) ( void ) \
+ { \
+ return &vg_default_zone; \
+ }
+
+#if defined(VGO_darwin)
+DEFAULT_ZONE(VG_Z_LIBC_SONAME, malloc_zone_from_ptr);
+DEFAULT_ZONE(VG_Z_LIBC_SONAME, malloc_default_zone);
+#endif
+
+// GrP fixme bypass libc's use of zone->introspect->check
+#define ZONE_CHECK(soname, fnname) \
+ \
+ int VG_REPLACE_FUNCTION_ZU(soname, fnname)(void* zone); \
+ int VG_REPLACE_FUNCTION_ZU(soname, fnname)(void* zone) \
+ { \
+ return 1; \
+ }
+
+#if defined(VGO_darwin)
+ZONE_CHECK(VG_Z_LIBC_SONAME, malloc_zone_check);
+#endif
+
+#endif
+
+
/* All the code in here is unused until this function is called */
static void init(void)
diff --git a/coregrind/m_scheduler/priv_sema.h b/coregrind/m_scheduler/priv_sema.h
index dfcab13..6693e88 100644
--- a/coregrind/m_scheduler/priv_sema.h
+++ b/coregrind/m_scheduler/priv_sema.h
@@ -33,16 +33,17 @@
/* Not really a semaphore, but use a pipe for a token-passing scheme */
typedef struct {
- Int pipe[2];
- Int owner_lwpid; /* who currently has it */
+ Int pipe[2];
+ Int owner_lwpid; /* who currently has it */
+ Bool held_as_LL; /* if held, True == held by a _LL call */
} vg_sema_t;
// Nb: this may be OS-specific, but let's not factor it out until we
// implement an OS port for which this isn't ok.
void ML_(sema_init) ( vg_sema_t *sema );
void ML_(sema_deinit) ( vg_sema_t *sema );
-void ML_(sema_down) ( vg_sema_t *sema );
-void ML_(sema_up) ( vg_sema_t *sema );
+void ML_(sema_down) ( vg_sema_t *sema, Bool as_LL );
+void ML_(sema_up) ( vg_sema_t *sema, Bool as_LL );
#endif // __PRIV_SEMA_H
diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c
index f1177ba..d0d17e6 100644
--- a/coregrind/m_scheduler/scheduler.c
+++ b/coregrind/m_scheduler/scheduler.c
@@ -71,6 +71,9 @@
#include "pub_core_libcprint.h"
#include "pub_core_libcproc.h"
#include "pub_core_libcsignal.h"
+#if defined(VGO_darwin)
+#include "pub_core_mach.h"
+#endif
#include "pub_core_machine.h"
#include "pub_core_mallocfree.h"
#include "pub_core_options.h"
@@ -154,6 +157,8 @@
case VEX_TRC_JMP_SYS_SYSCALL: return "SYSCALL";
case VEX_TRC_JMP_SYS_INT32: return "INT32";
case VEX_TRC_JMP_SYS_INT128: return "INT128";
+ case VEX_TRC_JMP_SYS_INT129: return "INT129";
+ case VEX_TRC_JMP_SYS_INT130: return "INT130";
case VEX_TRC_JMP_SYS_SYSENTER: return "SYSENTER";
case VEX_TRC_JMP_CLIENTREQ: return "CLIENTREQ";
case VEX_TRC_JMP_YIELD: return "YIELD";
@@ -211,7 +216,7 @@
/* First, acquire the_BigLock. We can't do anything else safely
prior to this point. Even doing debug printing prior to this
point is, technically, wrong. */
- ML_(sema_down)(&the_BigLock);
+ ML_(sema_down)(&the_BigLock, False/*not LL*/);
tst = VG_(get_ThreadState)(tid);
@@ -267,9 +272,22 @@
/* Release the_BigLock; this will reschedule any runnable
thread. */
- ML_(sema_up)(&the_BigLock);
+ ML_(sema_up)(&the_BigLock, False/*not LL*/);
}
+/* See pub_core_scheduler.h for description */
+void VG_(acquire_BigLock_LL) ( HChar* who )
+{
+ ML_(sema_down)(&the_BigLock, True/*LL*/);
+}
+
+/* See pub_core_scheduler.h for description */
+void VG_(release_BigLock_LL) ( HChar* who )
+{
+ ML_(sema_up)(&the_BigLock, True/*LL*/);
+}
+
+
/* Clear out the ThreadState and release the semaphore. Leaves the
ThreadState in VgTs_Zombie state, so that it doesn't get
reallocated until the caller is really ready. */
@@ -288,7 +306,7 @@
if (VG_(clo_trace_sched))
print_sched_event(tid, "release lock in VG_(exit_thread)");
- ML_(sema_up)(&the_BigLock);
+ ML_(sema_up)(&the_BigLock, False/*not LL*/);
}
/* If 'tid' is blocked in a syscall, send it SIGVGKILL so as to get it
@@ -300,11 +318,39 @@
vg_assert(!VG_(is_running_thread)(tid));
if (VG_(threads)[tid].status == VgTs_WaitSys) {
- if (VG_(clo_trace_signals))
+ if (VG_(clo_trace_signals)) {
VG_(message)(Vg_DebugMsg,
"get_thread_out_of_syscall zaps tid %d lwp %d",
tid, VG_(threads)[tid].os_state.lwpid);
- VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VG_SIGVGKILL);
+ }
+# if defined(VGO_darwin)
+ {
+ // GrP fixme use mach primitives on darwin?
+ // GrP fixme thread_abort_safely?
+ // GrP fixme race for thread with WaitSys set but not in syscall yet?
+ extern kern_return_t thread_abort(mach_port_t);
+ thread_abort(VG_(threads)[tid].os_state.lwpid);
+ }
+# else
+ {
+ __attribute__((unused))
+ Int r = VG_(tkill)(VG_(threads)[tid].os_state.lwpid, VG_SIGVGKILL);
+ /* JRS 2009-Mar-20: should we assert for r==0 (tkill succeeded)?
+ I'm really not sure. Here's a race scenario which argues
+ that we shoudn't; but equally I'm not sure the scenario is
+ even possible, because of constraints caused by the question
+ of who holds the BigLock when.
+
+ Target thread tid does sys_read on a socket and blocks. This
+ function gets called, and we observe correctly that tid's
+ status is WaitSys but then for whatever reason this function
+ goes very slowly for a while. Then data arrives from
+ wherever, tid's sys_read returns, tid exits. Then we do
+ tkill on tid, but tid no longer exists; tkill returns an
+ error code and the assert fails. */
+ /* vg_assert(r == 0); */
+ }
+# endif
}
}
@@ -355,10 +401,24 @@
{
tst->os_state.lwpid = 0;
tst->os_state.threadgroup = 0;
-# if defined(VGO_aix5)
+# if defined(VGO_linux)
+ /* no other fields to clear */
+# elif defined(VGO_aix5)
tst->os_state.cancel_async = False;
tst->os_state.cancel_disabled = False;
tst->os_state.cancel_progress = Canc_NoRequest;
+# elif defined(VGO_darwin)
+ tst->os_state.post_mach_trap_fn = NULL;
+ tst->os_state.pthread = 0;
+ tst->os_state.func_arg = 0;
+ VG_(memset)(&tst->os_state.child_go, 0, sizeof(tst->os_state.child_go));
+ VG_(memset)(&tst->os_state.child_done, 0, sizeof(tst->os_state.child_done));
+ tst->os_state.wq_jmpbuf_valid = False;
+ tst->os_state.remote_port = 0;
+ tst->os_state.msgh_id = 0;
+ VG_(memset)(&tst->os_state.mach_args, 0, sizeof(tst->os_state.mach_args));
+# else
+# error "Unknown OS"
# endif
}
@@ -419,6 +479,11 @@
ThreadId tid;
vg_assert(VG_(running_tid) == me);
+# if defined(VGO_darwin)
+ // GrP fixme hack reset Mach ports
+ VG_(mach_init)();
+# endif
+
VG_(threads)[me].os_state.lwpid = VG_(gettid)();
VG_(threads)[me].os_state.threadgroup = VG_(getpid)();
@@ -434,7 +499,7 @@
/* re-init and take the sema */
ML_(sema_deinit)(&the_BigLock);
ML_(sema_init)(&the_BigLock);
- ML_(sema_down)(&the_BigLock);
+ ML_(sema_down)(&the_BigLock, False/*not LL*/);
}
@@ -807,7 +872,7 @@
}
}
-static void handle_syscall(ThreadId tid)
+static void handle_syscall(ThreadId tid, UInt trc)
{
ThreadState * volatile tst = VG_(get_ThreadState)(tid);
Bool jumped;
@@ -820,7 +885,7 @@
if (VG_(clo_sanity_level >= 3))
VG_(am_do_sync_check)("(BEFORE SYSCALL)",__FILE__,__LINE__);
- SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid));
+ SCHEDSETJMP(tid, jumped, VG_(client_syscall)(tid, trc));
if (VG_(clo_sanity_level >= 3))
VG_(am_do_sync_check)("(AFTER SYSCALL)",__FILE__,__LINE__);
@@ -1013,8 +1078,10 @@
break;
case VEX_TRC_JMP_SYS_INT128: /* x86-linux */
- case VEX_TRC_JMP_SYS_SYSCALL: /* amd64-linux, ppc32-linux */
- handle_syscall(tid);
+ case VEX_TRC_JMP_SYS_INT129: /* x86-darwin */
+ case VEX_TRC_JMP_SYS_INT130: /* x86-darwin */
+ case VEX_TRC_JMP_SYS_SYSCALL: /* amd64-linux, ppc32-linux, amd64-darwin */
+ handle_syscall(tid, trc);
if (VG_(clo_sanity_level) > 2)
VG_(sanity_check_general)(True); /* sanity-check every syscall */
break;
@@ -1154,10 +1221,16 @@
# if defined(VGP_x86_linux)
vg_assert2(0, "VG_(scheduler), phase 3: "
"sysenter_x86 on x86-linux is not supported");
+# elif defined(VGP_x86_darwin)
+ /* return address in client edx */
+ VG_(threads)[tid].arch.vex.guest_EIP
+ = VG_(threads)[tid].arch.vex.guest_EDX;
+ handle_syscall(tid, trc);
# else
vg_assert2(0, "VG_(scheduler), phase 3: "
"sysenter_x86 on non-x86 platform?!?!");
# endif
+ break;
default:
vg_assert2(0, "VG_(scheduler), phase 3: "
@@ -1466,12 +1539,15 @@
bad = True;
}
+#if !defined(VGO_darwin)
+ // GrP fixme
if (lwpid != the_BigLock.owner_lwpid) {
VG_(message)(Vg_DebugMsg,
"Thread (LWPID) %d doesn't own the_BigLock\n",
tid);
bad = True;
}
+#endif
/* Periodically show the state of all threads, for debugging
purposes. */
diff --git a/coregrind/m_scheduler/sema.c b/coregrind/m_scheduler/sema.c
index 22b4676..ed84505 100644
--- a/coregrind/m_scheduler/sema.c
+++ b/coregrind/m_scheduler/sema.c
@@ -87,7 +87,7 @@
}
/* get a token */
-void ML_(sema_down)(vg_sema_t *sema)
+void ML_(sema_down)( vg_sema_t *sema, Bool as_LL )
{
Char buf[2];
Int ret;
@@ -114,13 +114,15 @@
if (sema_char == 'Z') sema_char = 'A'; else sema_char++;
sema->owner_lwpid = lwpid;
+ sema->held_as_LL = as_LL;
}
/* put token back */
-void ML_(sema_up)(vg_sema_t *sema)
+void ML_(sema_up)( vg_sema_t *sema, Bool as_LL )
{
Int ret;
Char buf[2];
+ vg_assert(as_LL == sema->held_as_LL);
buf[0] = sema_char;
buf[1] = 0;
vg_assert(sema->owner_lwpid != -1); /* must be initialised */
diff --git a/coregrind/m_sigframe/sigframe-amd64-darwin.c b/coregrind/m_sigframe/sigframe-amd64-darwin.c
new file mode 100644
index 0000000..4c8bc92
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-amd64-darwin.c
@@ -0,0 +1,68 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames. ---*/
+/*--- sigframe-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006-2009 OpenWorks Ltd
+ info@open-works.co.uk
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_trampoline.h"
+#include "pub_core_sigframe.h" /* self */
+
+
+void VG_(sigframe_create) ( ThreadId tid,
+ Addr sp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ const struct vki_ucontext *siguc,
+ void *handler,
+ UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer )
+{
+ I_die_here;
+}
+
+
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+ I_die_here;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end sigframe-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_sigframe/sigframe-x86-darwin.c b/coregrind/m_sigframe/sigframe-x86-darwin.c
new file mode 100644
index 0000000..698d940
--- /dev/null
+++ b/coregrind/m_sigframe/sigframe-x86-darwin.c
@@ -0,0 +1,232 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Create/destroy signal delivery frames. ---*/
+/*--- sigframe-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2006-2009 OpenWorks Ltd
+ info@open-works.co.uk
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_machine.h"
+#include "pub_core_options.h"
+#include "pub_core_signals.h"
+#include "pub_core_tooliface.h"
+#include "pub_core_trampoline.h"
+#include "pub_core_sigframe.h" /* self */
+
+
+/* Cheap-ass hack copied from ppc32-aix5 code, just to get started.
+ Produce a frame with layout entirely of our own choosing. */
+
+/* This module creates and removes signal frames for signal deliveries
+ on x86-darwin. Kludgey; the machine state ought to be saved in a
+ ucontext and retrieved from it later, so the handler can modify it
+ and return. However .. for now .. just stick the vex guest state
+ in the frame and snarf it again later.
+
+ Also, don't bother with creating siginfo and ucontext in the
+ handler, although do point them somewhere non-faulting.
+
+ Frame should have a 16-aligned size, just in case that turns out to
+ be important for Darwin. (be conservative)
+*/
+struct hacky_sigframe {
+ /* first four words look like a call to a 3-arg x86 function */
+ UInt returnAddr;
+ UInt a1_signo;
+ UInt a2_siginfo;
+ UInt a3_ucontext;
+ UChar lower_guardzone[512]; // put nothing here
+ VexGuestX86State gst;
+ VexGuestX86State gshadow1;
+ VexGuestX86State gshadow2;
+ vki_siginfo_t fake_siginfo;
+ struct vki_ucontext fake_ucontext;
+ UInt magicPI;
+ UInt sigNo_private;
+ vki_sigset_t mask; // saved sigmask; restore when hdlr returns
+ UInt __pad[1];
+ UChar upper_guardzone[512]; // put nothing here
+};
+
+
+/* Extend the stack segment downwards if needed so as to ensure the
+ new signal frames are mapped to something. Return a Bool
+ indicating whether or not the operation was successful.
+*/
+static Bool extend ( ThreadState *tst, Addr addr, SizeT size )
+{
+ ThreadId tid = tst->tid;
+ /* For tracking memory events, indicate the entire frame has been
+ allocated. Except, don't mess with the area which
+ overlaps the previous frame's redzone. */
+ /* XXX is the following call really right? compared with the
+ amd64-linux version, this doesn't appear to handle the redzone
+ in the same way. */
+ VG_TRACK( new_mem_stack_signal,
+ addr, size - VG_STACK_REDZONE_SZB, tid );
+ return True;
+}
+
+
+/* Create a signal frame for thread 'tid'. Make a 3-arg frame
+ regardless of whether the client originally requested a 1-arg
+ version (no SA_SIGINFO) or a 3-arg one (SA_SIGINFO) since in the
+ former case, the x86 calling conventions will simply cause the
+ extra 2 args to be ignored (inside the handler). */
+void VG_(sigframe_create) ( ThreadId tid,
+ Addr sp_top_of_frame,
+ const vki_siginfo_t *siginfo,
+ const struct vki_ucontext *siguc,
+ void *handler,
+ UInt flags,
+ const vki_sigset_t *mask,
+ void *restorer )
+{
+ ThreadState* tst;
+ Addr esp;
+ struct hacky_sigframe* frame;
+ Int sigNo = siginfo->si_signo;
+
+ vg_assert(VG_IS_16_ALIGNED(sizeof(struct hacky_sigframe)));
+
+ sp_top_of_frame &= ~0xf;
+ esp = sp_top_of_frame - sizeof(struct hacky_sigframe);
+
+ tst = VG_(get_ThreadState)(tid);
+ if (!extend(tst, esp, sp_top_of_frame - esp))
+ return;
+
+ vg_assert(VG_IS_16_ALIGNED(esp));
+
+ frame = (struct hacky_sigframe *) esp;
+
+ /* clear it (very conservatively) (why so conservatively??) */
+ VG_(memset)(&frame->lower_guardzone, 0, 512);
+ VG_(memset)(&frame->gst, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&frame->gshadow1, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&frame->gshadow2, 0, sizeof(VexGuestX86State));
+ VG_(memset)(&frame->fake_siginfo, 0, sizeof(frame->fake_siginfo));
+ VG_(memset)(&frame->fake_ucontext, 0, sizeof(frame->fake_ucontext));
+
+ /* save stuff in frame */
+ frame->gst = tst->arch.vex;
+ frame->gshadow1 = tst->arch.vex_shadow1;
+ frame->gshadow2 = tst->arch.vex_shadow2;
+ frame->sigNo_private = sigNo;
+ frame->mask = tst->sig_mask;
+ frame->magicPI = 0x31415927;
+
+ /* Minimally fill in the siginfo and ucontext. Note, utter
+ lameness prevails. Be underwhelmed, be very underwhelmed. */
+ frame->fake_siginfo.si_signo = sigNo;
+ frame->fake_siginfo.si_code = siginfo->si_code;
+
+ /* Set up stack pointer */
+ vg_assert(esp == (Addr)&frame->returnAddr);
+ VG_(set_SP)(tid, esp);
+ VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(UInt));
+
+ /* Set up program counter */
+ VG_(set_IP)(tid, (UInt)handler);
+ VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_INSTR_PTR, sizeof(UInt));
+
+ /* Set up RA and args for the frame */
+ VG_TRACK( pre_mem_write, Vg_CoreSignal, tid, "signal handler frame",
+ (Addr)frame, 4*sizeof(UInt) );
+ frame->returnAddr = (UInt)&VG_(x86_darwin_SUBST_FOR_sigreturn);
+ frame->a1_signo = sigNo;
+ frame->a2_siginfo = (UInt)&frame->fake_siginfo; /* oh well */
+ frame->a3_ucontext = (UInt)&frame->fake_ucontext; /* oh well */
+ VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+ (Addr)frame, 4*sizeof(UInt) );
+ VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+ (Addr)&frame->fake_siginfo, sizeof(frame->fake_siginfo));
+ VG_TRACK( post_mem_write, Vg_CoreSignal, tid,
+ (Addr)&frame->fake_ucontext, sizeof(frame->fake_ucontext));
+
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg,
+ "sigframe_create (thread %d): next EIP=%#lx, next ESP=%#lx",
+ tid, (Addr)handler, (Addr)frame );
+}
+
+
+/* Remove a signal frame from thread 'tid's stack, and restore the CPU
+ state from it. Note, isRT is irrelevant here. */
+void VG_(sigframe_destroy)( ThreadId tid, Bool isRT )
+{
+ ThreadState *tst;
+ Addr esp;
+ Int sigNo;
+ struct hacky_sigframe* frame;
+
+ vg_assert(VG_(is_valid_tid)(tid));
+ tst = VG_(get_ThreadState)(tid);
+
+ /* Check that the stack frame looks valid */
+ esp = VG_(get_SP)(tid);
+
+ /* why -4 ? because the signal handler's return will have popped
+ the return address of the stack; and the return address is the
+ lowest-addressed element of hacky_sigframe. */
+ frame = (struct hacky_sigframe*)(esp - 4);
+ vg_assert(frame->magicPI == 0x31415927);
+ vg_assert(VG_IS_16_ALIGNED(frame));
+
+ /* restore the entire guest state, and shadows, from the
+ frame. Note, as per comments above, this is a kludge - should
+ restore it from saved ucontext. Oh well. */
+ tst->arch.vex = frame->gst;
+ tst->arch.vex_shadow1 = frame->gshadow1;
+ tst->arch.vex_shadow2 = frame->gshadow2;
+ tst->sig_mask = frame->mask;
+ tst->tmp_sig_mask = frame->mask;
+ sigNo = frame->sigNo_private;
+
+ if (VG_(clo_trace_signals))
+ VG_(message)(Vg_DebugMsg,
+ "sigframe_destroy (thread %d): valid magic; next EIP=%#x",
+ tid, tst->arch.vex.guest_EIP);
+
+ VG_TRACK( die_mem_stack_signal,
+ (Addr)frame,
+ sizeof(struct hacky_sigframe) - VG_STACK_REDZONE_SZB );
+
+ /* tell the tools */
+ VG_TRACK( post_deliver_signal, tid, sigNo );
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end sigframe-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index c5b4b10..43c9aec 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -423,6 +423,82 @@
return VG_UCONTEXT_STACK_PTR(ucV);
}
+#elif defined(VGP_x86_darwin)
+
+ static inline Addr VG_UCONTEXT_INSTR_PTR( void* ucV ) {
+ ucontext_t* uc = (ucontext_t*)ucV;
+ struct __darwin_mcontext32* mc = uc->uc_mcontext;
+ struct __darwin_i386_thread_state* ss = &mc->__ss;
+ return ss->__eip;
+ }
+ static inline Addr VG_UCONTEXT_STACK_PTR( void* ucV ) {
+ ucontext_t* uc = (ucontext_t*)ucV;
+ struct __darwin_mcontext32* mc = uc->uc_mcontext;
+ struct __darwin_i386_thread_state* ss = &mc->__ss;
+ return ss->__esp;
+ }
+ static inline SysRes VG_UCONTEXT_SYSCALL_SYSRES( void* ucV,
+ UWord scclass ) {
+ /* this is complicated by the problem that there are 3 different
+ kinds of syscalls, each with its own return convention.
+ NB: scclass is a host word, hence UWord is good for both
+ amd64-darwin and x86-darwin */
+ ucontext_t* uc = (ucontext_t*)ucV;
+ struct __darwin_mcontext32* mc = uc->uc_mcontext;
+ struct __darwin_i386_thread_state* ss = &mc->__ss;
+ /* duplicates logic in m_syswrap.getSyscallStatusFromGuestState */
+ UInt carry = 1 & ss->__eflags;
+ UInt err = 0;
+ UInt wLO = 0;
+ UInt wHI = 0;
+ switch (scclass) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ err = carry;
+ wLO = ss->__eax;
+ wHI = ss->__edx;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ wLO = ss->__eax;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ wLO = ss->__eax;
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+ return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False,
+ wHI, wLO );
+ }
+ static inline Addr VG_UCONTEXT_LINK_REG( void* ucV ) {
+ return 0; /* No, really. We have no LRs today. */
+ }
+ static inline Addr VG_UCONTEXT_FRAME_PTR( void* ucV ) {
+ ucontext_t* uc = (ucontext_t*)ucV;
+ struct __darwin_mcontext32* mc = uc->uc_mcontext;
+ struct __darwin_i386_thread_state* ss = &mc->__ss;
+ return ss->__ebp;
+ }
+
+#elif defined(VGP_amd64_darwin)
+
+ static inline Addr VG_UCONTEXT_INSTR_PTR( void* ucV ) {
+ I_die_here;
+ }
+ static inline Addr VG_UCONTEXT_STACK_PTR( void* ucV ) {
+ I_die_here;
+ }
+ static inline SysRes VG_UCONTEXT_SYSCALL_SYSRES( void* ucV,
+ UWord scclass ) {
+ I_die_here;
+ }
+ static inline Addr VG_UCONTEXT_LINK_REG( void* ucV ) {
+ return 0; /* No, really. We have no LRs today. */
+ }
+ static inline Addr VG_UCONTEXT_FRAME_PTR( void* ucV ) {
+ I_die_here;
+ }
+
#else
# error Unknown platform
#endif
@@ -438,6 +514,9 @@
#elif defined(VGO_aix5)
# define VKI_SIGINFO_si_addr si_addr
# define VKI_SIGINFO_si_pid si_pid
+#elif defined(VGO_darwin)
+# define VKI_SIGINFO_si_addr si_addr
+# define VKI_SIGINFO_si_pid si_pid
#else
# error Unknown OS
#endif
@@ -722,6 +801,18 @@
".globl my_sigreturn\n" \
"my_sigreturn:\n" \
".long 0\n"
+#elif defined(VGP_x86_darwin)
+# define _MY_SIGRETURN(name) \
+ ".text\n" \
+ "my_sigreturn:\n" \
+ "movl $" VG_STRINGIFY(__NR_DARWIN_FAKE_SIGRETURN) ",%eax\n" \
+ "int $0x80"
+#elif defined(VGP_amd64_darwin)
+ // DDD: todo
+# define _MY_SIGRETURN(name) \
+ ".text\n" \
+ "my_sigreturn:\n" \
+ "ud2\n"
#else
# error Unknown platform
#endif
@@ -763,8 +854,9 @@
ksa.ksa_handler = skss.skss_per_sig[sig].skss_handler;
ksa.sa_flags = skss.skss_per_sig[sig].skss_flags;
-# if !defined(VGP_ppc32_linux) && !defined(VGP_ppc32_aix5) \
- && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_linux) && \
+ !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
ksa.sa_restorer = my_sigreturn;
# endif
/* Re above ifdef (also the assertion below), PaulM says:
@@ -784,8 +876,7 @@
sig, ksa.ksa_handler,
(UWord)ksa.sa_flags,
_VKI_NSIG_WORDS > 1 ? (ULong)ksa.sa_mask.sig[1] : 0,
- (ULong)ksa.sa_mask.sig[0]
- );
+ (ULong)ksa.sa_mask.sig[0]);
res = VG_(sigaction)( sig, &ksa, &ksa_old );
vg_assert(res == 0);
@@ -797,8 +888,9 @@
== skss_old.skss_per_sig[sig].skss_handler);
vg_assert(ksa_old.sa_flags
== skss_old.skss_per_sig[sig].skss_flags);
-# if !defined(VGP_ppc32_linux) && !defined(VGP_ppc32_aix5) \
- && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_linux) && \
+ !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
vg_assert(ksa_old.sa_restorer
== my_sigreturn);
# endif
@@ -919,7 +1011,8 @@
old_act->ksa_handler = scss.scss_per_sig[signo].scss_handler;
old_act->sa_flags = scss.scss_per_sig[signo].scss_flags;
old_act->sa_mask = scss.scss_per_sig[signo].scss_mask;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
old_act->sa_restorer = scss.scss_per_sig[signo].scss_restorer;
# endif
}
@@ -931,11 +1024,15 @@
scss.scss_per_sig[signo].scss_mask = new_act->sa_mask;
scss.scss_per_sig[signo].scss_restorer = NULL;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
scss.scss_per_sig[signo].scss_restorer = new_act->sa_restorer;
# endif
scss.scss_per_sig[signo].scss_sa_tramp = NULL;
+# if defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+ scss.scss_per_sig[signo].scss_sa_tramp = new_act->sa_tramp;
+# endif
VG_(sigdelset)(&scss.scss_per_sig[signo].scss_mask, VKI_SIGKILL);
VG_(sigdelset)(&scss.scss_per_sig[signo].scss_mask, VKI_SIGSTOP);
@@ -1234,13 +1331,15 @@
/* Hit ourselves with a signal using the default handler */
void VG_(kill_self)(Int sigNo)
{
+ Int r;
vki_sigset_t mask, origmask;
vki_sigaction_toK_t sa, origsa2;
vki_sigaction_fromK_t origsa;
sa.ksa_handler = VKI_SIG_DFL;
sa.sa_flags = 0;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
sa.sa_restorer = 0;
# endif
VG_(sigemptyset)(&sa.sa_mask);
@@ -1251,7 +1350,9 @@
VG_(sigaddset)(&mask, sigNo);
VG_(sigprocmask)(VKI_SIG_UNBLOCK, &mask, &origmask);
- VG_(kill)(VG_(getpid)(), sigNo);
+ r = VG_(kill)(VG_(getpid)(), sigNo);
+ /* This sometimes fails with EPERM on Darwin. I don't know why. */
+ /* vg_assert(r == 0); */
VG_(convert_sigaction_fromK_to_toK)( &origsa, &origsa2 );
VG_(sigaction)(sigNo, &origsa2, NULL);
@@ -1262,8 +1363,9 @@
// kernel, eg.: seg faults, illegal opcodes. Some come from the user, eg.:
// from kill() (SI_USER), or timer_settime() (SI_TIMER), or an async I/O
// request (SI_ASYNCIO). There's lots of implementation-defined leeway in
-// POSIX, but the user vs. kernal distinction is what we want here.
-static Bool is_signal_from_kernel(int si_code)
+// POSIX, but the user vs. kernal distinction is what we want here. We also
+// pass in some other details that can help when si_code is unreliable.
+static Bool is_signal_from_kernel(ThreadId tid, int signum, int si_code)
{
#if defined(VGO_linux) || defined(VGO_aix5)
// On Linux, SI_USER is zero, negative values are from the user, positive
@@ -1271,6 +1373,35 @@
// macros but we don't use them here because other platforms don't have
// them.
return ( si_code > VKI_SI_USER ? True : False );
+#elif defined(VGO_darwin)
+ // On Darwin 9.6.0, the si_code is completely unreliable. It should be the
+ // case that 0 means "user", and >0 means "kernel". But:
+ // - For SIGSEGV, it seems quite reliable.
+ // - For SIGBUS, it's always 2.
+ // - For SIGFPE, it's often 0, even for kernel ones (eg.
+ // div-by-integer-zero always gives zero).
+ // - For SIGILL, it's unclear.
+ // - For SIGTRAP, it's always 1.
+ // You can see the "NOTIMP" (not implemented) status of a number of the
+ // sub-cases in sys/signal.h. Hopefully future versions of Darwin will
+ // get this right.
+
+ // If we're blocked waiting on a syscall, it must be a user signal, because
+ // the kernel won't generate sync signals within syscalls.
+ if (VG_(threads)[tid].status == VgTs_WaitSys) {
+ return False;
+
+ // If it's a SIGSEGV, use the proper condition, since it's fairly reliable.
+ } else if (SIGSEGV == signum) {
+ return ( si_code > 0 ? True : False );
+
+ // If it's anything else, assume it's kernel-generated. Reason being that
+ // kernel-generated sync signals are more common, and it's probable that
+ // misdiagnosing a user signal as a kernel signal is better than the
+ // opposite.
+ } else {
+ return True;
+ }
#else
# error Unknown OS
#endif
@@ -1358,7 +1489,7 @@
}
if ( (VG_(clo_verbosity) > 1 ||
- (could_core && is_signal_from_kernel(info->si_code))
+ (could_core && is_signal_from_kernel(tid, sigNo, info->si_code))
) &&
!VG_(clo_xml) ) {
VG_UMSG("");
@@ -1366,7 +1497,7 @@
sigNo, signame(sigNo), core ? ": dumping core" : "");
/* Be helpful - decode some more details about this fault */
- if (is_signal_from_kernel(info->si_code)) {
+ if (is_signal_from_kernel(tid, sigNo, info->si_code)) {
const Char *event = NULL;
Bool haveaddr = True;
@@ -1448,7 +1579,7 @@
VG_(pp_ExeContext)( ec );
}
if (sigNo == VKI_SIGSEGV
- && info && is_signal_from_kernel(info->si_code)
+ && info && is_signal_from_kernel(tid, sigNo, info->si_code)
&& info->si_code == VKI_SEGV_MAPERR) {
VG_UMSG(" If you believe this happened as a result of a stack" );
VG_UMSG(" overflow in your program's main thread (unlikely but");
@@ -1640,6 +1771,11 @@
{
vki_siginfo_t info;
struct vki_ucontext uc;
+# if defined(VGP_x86_darwin)
+ struct __darwin_mcontext32 mc;
+# elif defined(VGP_amd64_darwin)
+ struct __darwin_mcontext64 mc;
+# endif
vg_assert(VG_(threads)[tid].status == VgTs_Runnable);
@@ -1653,6 +1789,12 @@
for a breakpoint trap... */
uc.uc_mcontext.err = 0; /* tjh: no error code for x86
breakpoint trap... */
+# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+ /* the same thing, but using Darwin field/struct names */
+ VG_(memset)(&mc, 0, sizeof(mc));
+ uc.uc_mcontext = &mc;
+ uc.uc_mcontext->__es.__trapno = 3;
+ uc.uc_mcontext->__es.__err = 0;
# endif
resume_scheduler(tid);
@@ -1756,7 +1898,7 @@
mask them off) sign extends them when exporting to user space so
we do the same thing here. */
return (Short)si_code;
-#elif defined(VGO_aix5)
+#elif defined(VGO_aix5) || defined(VGO_darwin)
return si_code;
#else
# error Unknown OS
@@ -1812,7 +1954,16 @@
VG_(fixup_guest_state_after_syscall_interrupted) will detect
that the thread was not in said window and ignore the SysRes. */
+ /* To make matters more complex still, on Darwin we need to know
+ the "class" of the syscall under consideration in order to be
+ able to extract the a correct SysRes. The class will have been
+ saved just before the syscall, by VG_(client_syscall), into this
+ thread's tst->arch.vex.guest_SC_CLASS. Hence: */
+# if defined(VGO_darwin)
+ sres = VG_UCONTEXT_SYSCALL_SYSRES(uc, tst->arch.vex.guest_SC_CLASS);
+# else
sres = VG_UCONTEXT_SYSCALL_SYSRES(uc);
+# endif
/* (1) */
VG_(fixup_guest_state_after_syscall_interrupted)(
@@ -2050,7 +2201,6 @@
}
}
-
static
void sync_signalhandler_from_kernel ( ThreadId tid,
Int sigNo, vki_siginfo_t *info, struct vki_ucontext *uc )
@@ -2140,7 +2290,7 @@
info->si_code = sanitize_si_code(info->si_code);
- from_user = !is_signal_from_kernel(info->si_code);
+ from_user = !is_signal_from_kernel(tid, sigNo, info->si_code);
if (VG_(clo_trace_signals)) {
VG_DMSG("sync signal handler: "
@@ -2220,7 +2370,8 @@
VG_(printf)("pp_ksigaction: handler %p, flags 0x%x, restorer %p\n",
sa->ksa_handler,
(UInt)sa->sa_flags,
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
sa->sa_restorer
# else
(void*)0
@@ -2242,7 +2393,8 @@
sa.ksa_handler = VKI_SIG_DFL;
sa.sa_flags = 0;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
sa.sa_restorer = 0;
# endif
VG_(sigemptyset)(&sa.sa_mask);
@@ -2326,6 +2478,13 @@
/* Get the old host action */
ret = VG_(sigaction)(i, NULL, &sa);
+# if defined(VGP_x86_darwin)
+ /* apparently we may not even ask about the disposition of these
+ signals, let alone change them */
+ if (ret != 0 && (i == VKI_SIGKILL || i == VKI_SIGSTOP))
+ continue;
+# endif
+
if (ret != 0)
break;
@@ -2337,7 +2496,8 @@
tsa.ksa_handler = (void *)sync_signalhandler;
tsa.sa_flags = VKI_SA_SIGINFO;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
tsa.sa_restorer = 0;
# endif
VG_(sigfillset)(&tsa.sa_mask);
@@ -2364,11 +2524,18 @@
scss.scss_per_sig[i].scss_mask = sa.sa_mask;
scss.scss_per_sig[i].scss_restorer = NULL;
-# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5)
+# if !defined(VGP_ppc32_aix5) && !defined(VGP_ppc64_aix5) && \
+ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin)
scss.scss_per_sig[i].scss_restorer = sa.sa_restorer;
# endif
scss.scss_per_sig[i].scss_sa_tramp = NULL;
+# if defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+ scss.scss_per_sig[i].scss_sa_tramp = NULL;
+ /*sa.sa_tramp;*/
+ /* We can't know what it was, because Darwin's sys_sigaction
+ doesn't tell us. */
+# endif
}
if (VG_(clo_trace_signals))
diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c
index edfaf73..6e3c8d0 100644
--- a/coregrind/m_stacktrace.c
+++ b/coregrind/m_stacktrace.c
@@ -101,6 +101,9 @@
/* Assertion broken before main() is reached in pthreaded programs; the
* offending stack traces only have one item. --njn, 2002-aug-16 */
/* vg_assert(fp_min <= fp_max);*/
+ // On Darwin, this kicks in for pthread-related stack traces, so they're
+ // only 1 entry long which is wrong.
+#if !defined(VGO_darwin)
if (fp_min + 512 >= fp_max) {
/* If the stack limits look bogus, don't poke around ... but
don't bomb out either. */
@@ -109,13 +112,14 @@
ips[0] = ip;
return 1;
}
+#endif
/* Otherwise unwind the stack in a platform-specific way. Trying
to merge the x86, amd64, ppc32 and ppc64 logic into a single
piece of code is just too confusing and difficult to
performance-tune. */
-# if defined(VGP_x86_linux)
+# if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
/*--------------------- x86 ---------------------*/
@@ -209,7 +213,7 @@
break;
}
-# elif defined(VGP_amd64_linux)
+# elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
/*--------------------- amd64 ---------------------*/
@@ -551,7 +555,6 @@
VG_(pp_StackTrace)(ips, n_ips);
}
-
void VG_(apply_StackTrace)( void(*action)(UInt n, Addr ip),
StackTrace ips, UInt n_ips )
{
diff --git a/coregrind/m_start-amd64-darwin.S b/coregrind/m_start-amd64-darwin.S
new file mode 100644
index 0000000..e414a26
--- /dev/null
+++ b/coregrind/m_start-amd64-darwin.S
@@ -0,0 +1,81 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin amd64 bootstrap. m_start-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2007 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+ .text
+ .align 3,0x90
+Ldyld_stub_binding_helper:
+ pushq %r11
+ leaq ___dso_handle(%rip), %r11
+ pushq %r11
+ jmpq *Ldyld_lazy_symbol_binding_entry_point(%rip)
+
+ .dyld
+ .align 3
+Ldyld_lazy_symbol_binding_entry_point:
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad 0
+ .quad Ldyld_stub_binding_helper
+ .quad 0
+
+
+ // Memory layout established by kernel:
+ //
+ // 0
+ // executable_name
+ // 0
+ // envp[n]
+ // ...
+ // envp[0]
+ // 0
+ // argv[argc-1]
+ // ...
+ // sp+8-> argv[0]
+ // sp -> argc
+
+ .text
+ .align 3,0x90
+ .globl __start
+__start:
+ movq %rsp, %rdi // save &argc
+ andq $-16, %rsp // align stack
+ pushq $0 // push NULL "return address" for backtraces
+ pushq $0 // push fake saved ebp and align stack
+ movq %rsp, %rbp // save frame pointer
+ call __start_in_C_darwin // __start_in_C_darwin(&argc)
+
+ // should not reach here
+ int $3
+ int $3
+
diff --git a/coregrind/m_start-x86-darwin.S b/coregrind/m_start-x86-darwin.S
new file mode 100644
index 0000000..57b49d0
--- /dev/null
+++ b/coregrind/m_start-x86-darwin.S
@@ -0,0 +1,80 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin x86 bootstrap. m_start-x86-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2007 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+ .text
+ .align 2,0x90
+Ldyld_stub_binding_helper:
+ pushl $__mh_execute_header
+ jmpl *Ldyld_lazy_symbol_binding_entry_point
+
+ .dyld
+ .align 2
+Ldyld_lazy_symbol_binding_entry_point:
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long Ldyld_stub_binding_helper
+ .long 0
+
+
+ // Memory layout established by kernel:
+ //
+ // 0
+ // executable_name
+ // 0
+ // envp[n]
+ // ...
+ // envp[0]
+ // 0
+ // argv[argc-1]
+ // ...
+ // sp+4-> argv[0]
+ // sp -> argc
+
+ .text
+ .align 2,0x90
+ .globl __start
+__start:
+ movl %esp, %eax // save &argc
+ andl $-16, %esp // align stack
+ pushl $0 // push NULL "return address" for backtraces
+ pushl $0 // push fake saved ebp
+ movl %esp, %ebp // save frame pointer
+ pushl $0 // align stack
+ pushl %eax // start_in_C_darwin(&argc)
+ call __start_in_C_darwin
+
+ // should not reach here
+ int $3
+ int $3
diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c
index 0970e6b..3a74a89 100644
--- a/coregrind/m_syscall.c
+++ b/coregrind/m_syscall.c
@@ -29,6 +29,7 @@
*/
#include "pub_core_basics.h"
+#include "pub_core_libcassert.h"
#include "pub_core_vki.h"
#include "pub_core_vkiscnums.h"
#include "pub_core_syscall.h"
@@ -155,6 +156,95 @@
}
+#elif defined(VGO_darwin)
+
+/* Darwin: Some syscalls return a double-word result. */
+SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
+ UInt wHI, UInt wLO )
+{
+ SysRes res;
+ res._wHI = 0;
+ res._wLO = 0;
+ res._mode = 0; /* invalid */
+ vg_assert(isErr == False || isErr == True);
+ vg_assert(sizeof(UWord) == sizeof(UInt));
+ switch (scclass) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ res._wLO = wLO;
+ res._wHI = wHI;
+ res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ vg_assert(!isErr);
+ vg_assert(wHI == 0);
+ res._wLO = wLO;
+ res._mode = SysRes_MACH;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ vg_assert(!isErr);
+ vg_assert(wHI == 0);
+ res._wLO = wLO;
+ res._mode = SysRes_MDEP;
+ break;
+ default:
+ vg_assert(0);
+ }
+ return res;
+}
+
+SysRes VG_(mk_SysRes_amd64_darwin) ( UChar scclass, Bool isErr,
+ ULong wHI, ULong wLO )
+{
+ SysRes res;
+ res._wHI = 0;
+ res._wLO = 0;
+ res._mode = 0; /* invalid */
+ vg_assert(isErr == False || isErr == True);
+ vg_assert(sizeof(UWord) == sizeof(ULong));
+ switch (scclass) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ res._wLO = wLO;
+ res._wHI = wHI;
+ res._mode = isErr ? SysRes_UNIX_ERR : SysRes_UNIX_OK;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ vg_assert(!isErr);
+ vg_assert(wHI == 0);
+ res._wLO = wLO;
+ res._mode = SysRes_MACH;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ vg_assert(!isErr);
+ vg_assert(wHI == 0);
+ res._wLO = wLO;
+ res._mode = SysRes_MDEP;
+ break;
+ default:
+ vg_assert(0);
+ }
+ return res;
+}
+
+/* Generic constructors. We assume (without checking if this makes
+ any sense, from the caller's point of view) that these are for the
+ UNIX style of syscall. */
+SysRes VG_(mk_SysRes_Error) ( UWord err ) {
+ SysRes r;
+ r._wHI = 0;
+ r._wLO = err;
+ r._mode = SysRes_UNIX_ERR;
+ return r;
+}
+
+SysRes VG_(mk_SysRes_Success) ( UWord res ) {
+ SysRes r;
+ r._wHI = 0;
+ r._wLO = res;
+ r._mode = SysRes_UNIX_OK;
+ return r;
+}
+
+
#else
# error "Unknown OS"
#endif
@@ -460,6 +550,138 @@
*res_r4 = args[1];
}
+#elif defined(VGP_x86_darwin)
+
+/* Incoming args (syscall number + up to 8 args) come in on the stack
+
+ The kernel's syscall calling convention is:
+ * the syscall number goes in eax
+ * the args are passed to the syscall on the stack,
+ pushed onto the stack R->L (that is, the usual x86
+ calling conventions, with the leftmost arg at the lowest
+ address)
+ Call instruction:
+ * UNIX: sysenter
+ * UNIX: int $0x80
+ * MACH: int $0x81
+ * MDEP: int $0x82
+ Note that the call type can be determined from the syscall number;
+ there is no need to inspect the actual instruction. Although obviously
+ the instruction must match.
+ Return value:
+ * MACH,MDEP: the return value comes back in eax
+ * UNIX: the return value comes back in edx:eax (hi32:lo32)
+ Error:
+ * MACH,MDEP: no error is returned
+ * UNIX: the carry flag indicates success or failure
+
+ nb here, sizeof(UWord) == sizeof(UInt)
+*/
+
+__private_extern__ ULong
+do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
+ UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
+ UWord a7, UWord a8, /* 28(esp)..32(esp) */
+ UWord syscall_no, /* 36(esp) */
+ /*OUT*/UInt* errflag /* 40(esp) */ );
+// Unix syscall: 64-bit return in edx:eax, with LSB in eax
+// error indicated by carry flag: clear=good, set=bad
+asm(".private_extern _do_syscall_unix_WRK\n"
+ "_do_syscall_unix_WRK:\n"
+ " movl 40(%esp), %ecx \n" /* assume syscall success */
+ " movl $0, (%ecx) \n"
+ " movl 36(%esp), %eax \n"
+ " int $0x80 \n"
+ " jnc 1f \n" /* jump if success */
+ " movl 40(%esp), %ecx \n" /* syscall failed - set *errflag */
+ " movl $1, (%ecx) \n"
+ " 1: ret \n"
+ );
+
+__private_extern__ UInt
+do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
+ UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
+ UWord a7, UWord a8, /* 28(esp)..32(esp) */
+ UWord syscall_no /* 36(esp) */ );
+// Mach trap: 32-bit result in %eax, no error flag
+asm(".private_extern _do_syscall_mach_WRK\n"
+ "_do_syscall_mach_WRK:\n"
+ " movl 36(%esp), %eax \n"
+ " int $0x81 \n"
+ " ret \n"
+ );
+
+__private_extern__ UInt
+do_syscall_mdep_WRK ( UWord a1, UWord a2, UWord a3, /* 4(esp)..12(esp) */
+ UWord a4, UWord a5, UWord a6, /* 16(esp)..24(esp) */
+ UWord a7, UWord a8, /* 28(esp)..32(esp) */
+ UWord syscall_no /* 36(esp) */ );
+// mdep trap: 32-bit result in %eax, no error flag
+asm(
+ ".private_extern _do_syscall_mdep_WRK\n"
+ "_do_syscall_mdep_WRK:\n"
+ " movl 36(%esp), %eax \n"
+ " int $0x82 \n"
+ " ret \n"
+ );
+
+
+#elif defined(VGP_amd64_darwin)
+
+/* Incoming args (syscall number + up to 8 args) come in registers and stack
+
+ The kernel's syscall calling convention is:
+ * the syscall number goes in rax
+ * the args are passed to the syscall in registers and the stack
+ * the call instruction is 'syscall'
+ Return value:
+ * MACH,MDEP: the return value comes back in rax
+ * UNIX: the return value comes back in rdx:rax (hi64:lo64)
+ Error:
+ * MACH,MDEP: no error is returned
+ * UNIX: the carry flag indicates success or failure
+
+ nb here, sizeof(UWord) == sizeof(ULong)
+*/
+
+__private_extern__ UWord
+do_syscall_unix_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
+ UWord a4, UWord a5, UWord a6, /* rcx, r8, r9 */
+ UWord a7, UWord a8, /* 8(rsp), 16(rsp) */
+ UWord syscall_no, /* 24(rsp) */
+ /*OUT*/ULong* errflag, /* 32(rsp) */
+ /*OUT*/ULong* res2 ); /* 40(rsp) */
+// Unix syscall: 128-bit return in rax:rdx, with LSB in rax
+// error indicated by carry flag: clear=good, set=bad
+asm(".private_extern _do_syscall_unix_WRK\n"
+ "_do_syscall_unix_WRK:\n"
+ " movq %rcx, %r10 \n" /* pass rcx in r10 instead */
+ " movq 32(%rsp), %rax \n" /* assume syscall success */
+ " movq $0, (%rax) \n"
+ " movq 24(%rsp), %rax \n" /* load syscall_no */
+ " syscall \n"
+ " jnc 1f \n" /* jump if success */
+ " movq 32(%rsp), %rcx \n" /* syscall failed - set *errflag */
+ " movq $1, (%rcx) \n"
+ " 1: movq 40(%rsp), %rcx \n" /* save 2nd result word */
+ " movq %rdx, (%rcx) \n"
+ " retq \n" /* return 1st result word */
+ );
+
+__private_extern__ UWord
+do_syscall_mach_WRK ( UWord a1, UWord a2, UWord a3, /* rdi, rsi, rdx */
+ UWord a4, UWord a5, UWord a6, /* rcx, r8, r9 */
+ UWord a7, UWord a8, /* 8(rsp), 16(rsp) */
+ UWord syscall_no ); /* 24(rsp) */
+// Mach trap: 64-bit result, no error flag
+asm(".private_extern _do_syscall_mach_WRK\n"
+ "_do_syscall_mach_WRK:\n"
+ " movq %rcx, %r10 \n" /* pass rcx in r10 instead */
+ " movq 24(%rsp), %rax \n" /* load syscall_no */
+ " syscall \n"
+ " retq \n"
+ );
+
#else
# error Unknown platform
#endif
@@ -536,6 +758,53 @@
}
return VG_(mk_SysRes_ppc64_aix5)( res, err );
+# elif defined(VGP_x86_darwin)
+ UInt wLO = 0, wHI = 0, err = 0;
+ ULong u64;
+ UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
+ switch (scclass) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ u64 = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+ VG_DARWIN_SYSNO_NUM(sysno), &err);
+ wLO = (UInt)u64;
+ wHI = (UInt)(u64 >> 32);
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+ VG_DARWIN_SYSNO_NUM(sysno));
+ err = 0;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ wLO = do_syscall_mdep_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+ VG_DARWIN_SYSNO_NUM(sysno));
+ err = 0;
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+ return VG_(mk_SysRes_x86_darwin)( scclass, err ? True : False, wHI, wLO );
+
+# elif defined(VGP_amd64_darwin)
+ ULong wLO = 0, wHI = 0, err = 0;
+ UChar scclass = VG_DARWIN_SYSNO_CLASS(sysno);
+ switch (scclass) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ wLO = do_syscall_unix_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+ VG_DARWIN_SYSNO_NUM(sysno), &err, &wHI);
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ wLO = do_syscall_mach_WRK(a1,a2,a3,a4,a5,a6,a7,a8,
+ VG_DARWIN_SYSNO_NUM(sysno));
+ err = 0;
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+ return VG_(mk_SysRes_amd64_darwin)( scclass, err ? True : False, wHI, wLO );
+
#else
# error Unknown platform
#endif
diff --git a/coregrind/m_syswrap/priv_syswrap-darwin.h b/coregrind/m_syswrap/priv_syswrap-darwin.h
new file mode 100644
index 0000000..bc85706
--- /dev/null
+++ b/coregrind/m_syswrap/priv_syswrap-darwin.h
@@ -0,0 +1,289 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Private syscalls header for Darwin. priv_syswrap-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PRIV_SYSWRAP_DARWIN_H
+#define __PRIV_SYSWRAP_DARWIN_H
+
+/* requires #include "priv_types_n_macros.h" */
+
+// syswrap-darwin.c
+Addr allocstack ( ThreadId tid );
+void find_stack_segment ( ThreadId tid, Addr sp );
+void start_thread_NORETURN ( Word arg );
+void assign_port_name(mach_port_t port, const char *name);
+void record_named_port(ThreadId tid, mach_port_t port, mach_port_right_t right, const char *name);
+
+extern const SyscallTableEntry ML_(mach_trap_table)[];
+extern const SyscallTableEntry ML_(syscall_table)[];
+extern const SyscallTableEntry ML_(mdep_trap_table)[];
+
+extern const UInt ML_(syscall_table_size);
+extern const UInt ML_(mach_trap_table_size);
+extern const UInt ML_(mdep_trap_table_size);
+
+void VG_(show_open_ports)(void);
+
+// Unix syscalls
+DECL_TEMPLATE(darwin, sys_semget);
+DECL_TEMPLATE(darwin, sys_semop);
+DECL_TEMPLATE(darwin, sys_semctl);
+DECL_TEMPLATE(darwin, sys_sem_open);
+DECL_TEMPLATE(darwin, sys_sem_close);
+DECL_TEMPLATE(darwin, sys_sem_unlink);
+DECL_TEMPLATE(darwin, sys_sem_post);
+DECL_TEMPLATE(darwin, sys_sem_init);
+DECL_TEMPLATE(darwin, sys_sem_destroy);
+DECL_TEMPLATE(darwin, sys_sem_wait_nocancel);
+DECL_TEMPLATE(darwin, sys_sem_trywait);
+DECL_TEMPLATE(darwin, sys_bsdthread_create);
+DECL_TEMPLATE(darwin, sys_bsdthread_terminate);
+DECL_TEMPLATE(darwin, sys_kqueue);
+DECL_TEMPLATE(darwin, sys_kevent);
+DECL_TEMPLATE(darwin, sys_bsdthread_register);
+DECL_TEMPLATE(darwin, sys_workq_open);
+DECL_TEMPLATE(darwin, sys_workq_ops);
+DECL_TEMPLATE(darwin, sys___mac_syscall);
+DECL_TEMPLATE(darwin, sys_exit);
+DECL_TEMPLATE(darwin, sys_sigaction);
+DECL_TEMPLATE(darwin, sys___pthread_canceled);
+DECL_TEMPLATE(darwin, sys___pthread_markcancel);
+DECL_TEMPLATE(darwin, sys___pthread_sigmask);
+DECL_TEMPLATE(darwin, sys___disable_threadsignal);
+DECL_TEMPLATE(darwin, sys_kdebug_trace);
+DECL_TEMPLATE(darwin, sys_seteuid);
+DECL_TEMPLATE(darwin, sys_setegid);
+DECL_TEMPLATE(darwin, sys_listxattr);
+DECL_TEMPLATE(darwin, sys_flistxattr);
+DECL_TEMPLATE(darwin, sys_shmget);
+DECL_TEMPLATE(darwin, sys_shm_open);
+DECL_TEMPLATE(darwin, sys_statx);
+DECL_TEMPLATE(darwin, sys_fchmod_extended);
+DECL_TEMPLATE(darwin, sys_chmod_extended);
+DECL_TEMPLATE(darwin, sys_accessx);
+DECL_TEMPLATE(darwin, sys_chflags);
+DECL_TEMPLATE(darwin, sys_fchflags);
+DECL_TEMPLATE(darwin, sys_stat64);
+DECL_TEMPLATE(darwin, sys_lstat64);
+DECL_TEMPLATE(darwin, sys_fstat64);
+DECL_TEMPLATE(darwin, sys_getfsstat);
+DECL_TEMPLATE(darwin, sys_getattrlist);
+DECL_TEMPLATE(darwin, sys_setattrlist);
+DECL_TEMPLATE(darwin, sys_getdirentriesattr);
+DECL_TEMPLATE(darwin, sys_fsctl);
+DECL_TEMPLATE(darwin, sys_socket);
+DECL_TEMPLATE(darwin, sys_setsockopt);
+DECL_TEMPLATE(darwin, sys_getsockopt);
+DECL_TEMPLATE(darwin, sys_connect);
+DECL_TEMPLATE(darwin, sys_accept);
+DECL_TEMPLATE(darwin, sys_sendto);
+DECL_TEMPLATE(darwin, sys_recvfrom);
+DECL_TEMPLATE(darwin, sys_sendmsg);
+DECL_TEMPLATE(darwin, sys_recvmsg);
+DECL_TEMPLATE(darwin, sys_shutdown);
+DECL_TEMPLATE(darwin, sys_bind);
+DECL_TEMPLATE(darwin, sys_listen);
+DECL_TEMPLATE(darwin, sys_getsockname);
+DECL_TEMPLATE(darwin, sys_getpeername);
+DECL_TEMPLATE(darwin, sys_socketpair);
+DECL_TEMPLATE(darwin, sys_gethostuuid);
+DECL_TEMPLATE(darwin, sys_pipe);
+DECL_TEMPLATE(darwin, sys_getlogin);
+DECL_TEMPLATE(darwin, sys_ptrace);
+DECL_TEMPLATE(darwin, sys_issetugid);
+DECL_TEMPLATE(darwin, sys_getdtablesize);
+DECL_TEMPLATE(darwin, sys_lseek);
+DECL_TEMPLATE(darwin, sys_getdirentries);
+DECL_TEMPLATE(darwin, sys_getdirentries64);
+DECL_TEMPLATE(darwin, sys_statfs64);
+DECL_TEMPLATE(darwin, sys_fstatfs64);
+DECL_TEMPLATE(darwin, sys_csops);
+DECL_TEMPLATE(darwin, sys_auditon);
+DECL_TEMPLATE(darwin, sys_pathconf);
+DECL_TEMPLATE(darwin, sys_fpathconf);
+DECL_TEMPLATE(darwin, sys_shared_region_map_file_np);
+DECL_TEMPLATE(darwin, sys_mmap);
+DECL_TEMPLATE(darwin, sys_sysctl);
+DECL_TEMPLATE(darwin, sys_sigpending);
+DECL_TEMPLATE(darwin, sys_sigprocmask);
+DECL_TEMPLATE(darwin, sys_sigsuspend);
+DECL_TEMPLATE(darwin, sys_watchevent);
+DECL_TEMPLATE(darwin, sys_waitevent);
+DECL_TEMPLATE(darwin, sys_modwatch);
+DECL_TEMPLATE(darwin, sys_getxattr);
+DECL_TEMPLATE(darwin, sys_fgetxattr);
+DECL_TEMPLATE(darwin, sys_setxattr);
+DECL_TEMPLATE(darwin, sys_fsetxattr);
+DECL_TEMPLATE(darwin, sys_initgroups);
+DECL_TEMPLATE(darwin, sys_posix_spawn);
+DECL_TEMPLATE(darwin, sys_settid);
+DECL_TEMPLATE(darwin, sys_sendfile);
+DECL_TEMPLATE(darwin, sys_fcntl);
+DECL_TEMPLATE(darwin, sys_fcntl64);
+DECL_TEMPLATE(darwin, sys_ioctl);
+DECL_TEMPLATE(darwin, sys_futimes);
+DECL_TEMPLATE(darwin, sys_FAKE_SIGRETURN);
+DECL_TEMPLATE(darwin, sys_sigreturn);
+
+// Mach message helpers
+DECL_TEMPLATE(darwin, host_info);
+DECL_TEMPLATE(darwin, host_page_size);
+DECL_TEMPLATE(darwin, host_get_io_master);
+DECL_TEMPLATE(darwin, host_get_clock_service);
+DECL_TEMPLATE(darwin, host_request_notification);
+DECL_TEMPLATE(darwin, mach_port_type);
+DECL_TEMPLATE(darwin, mach_port_extract_member);
+DECL_TEMPLATE(darwin, mach_port_allocate);
+DECL_TEMPLATE(darwin, mach_port_deallocate);
+DECL_TEMPLATE(darwin, mach_port_get_refs);
+DECL_TEMPLATE(darwin, mach_port_mod_refs);
+DECL_TEMPLATE(darwin, mach_port_get_set_status);
+DECL_TEMPLATE(darwin, mach_port_destroy);
+DECL_TEMPLATE(darwin, mach_port_request_notification);
+DECL_TEMPLATE(darwin, mach_port_insert_right);
+DECL_TEMPLATE(darwin, mach_port_get_attributes);
+DECL_TEMPLATE(darwin, mach_port_set_attributes);
+DECL_TEMPLATE(darwin, mach_port_insert_member);
+DECL_TEMPLATE(darwin, task_get_special_port);
+DECL_TEMPLATE(darwin, semaphore_create);
+DECL_TEMPLATE(darwin, semaphore_destroy);
+DECL_TEMPLATE(darwin, mach_ports_lookup);
+DECL_TEMPLATE(darwin, task_threads);
+DECL_TEMPLATE(darwin, task_suspend);
+DECL_TEMPLATE(darwin, task_resume);
+DECL_TEMPLATE(darwin, vm_allocate);
+DECL_TEMPLATE(darwin, vm_deallocate);
+DECL_TEMPLATE(darwin, vm_protect);
+DECL_TEMPLATE(darwin, vm_inherit);
+DECL_TEMPLATE(darwin, vm_read);
+DECL_TEMPLATE(darwin, mach_vm_read);
+DECL_TEMPLATE(darwin, vm_copy);
+DECL_TEMPLATE(darwin, vm_read_overwrite);
+DECL_TEMPLATE(darwin, vm_map);
+DECL_TEMPLATE(darwin, vm_remap);
+DECL_TEMPLATE(darwin, mach_make_memory_entry_64);
+DECL_TEMPLATE(darwin, vm_purgable_control);
+DECL_TEMPLATE(darwin, mach_vm_purgable_control);
+DECL_TEMPLATE(darwin, mach_vm_allocate);
+DECL_TEMPLATE(darwin, mach_vm_deallocate);
+DECL_TEMPLATE(darwin, mach_vm_protect);
+DECL_TEMPLATE(darwin, mach_vm_copy);
+DECL_TEMPLATE(darwin, mach_vm_inherit);
+DECL_TEMPLATE(darwin, mach_vm_map);
+DECL_TEMPLATE(darwin, mach_vm_region_recurse);
+DECL_TEMPLATE(darwin, thread_terminate);
+DECL_TEMPLATE(darwin, thread_create);
+DECL_TEMPLATE(darwin, thread_create_running);
+DECL_TEMPLATE(darwin, thread_suspend);
+DECL_TEMPLATE(darwin, thread_get_state);
+DECL_TEMPLATE(darwin, thread_policy);
+DECL_TEMPLATE(darwin, thread_info);
+DECL_TEMPLATE(darwin, bootstrap_register);
+DECL_TEMPLATE(darwin, bootstrap_look_up);
+DECL_TEMPLATE(darwin, mach_msg_receive);
+DECL_TEMPLATE(darwin, mach_msg_bootstrap);
+DECL_TEMPLATE(darwin, mach_msg_host);
+DECL_TEMPLATE(darwin, mach_msg_task);
+DECL_TEMPLATE(darwin, mach_msg_thread);
+
+// Mach traps
+DECL_TEMPLATE(darwin, mach_msg_unhandled);
+DECL_TEMPLATE(darwin, mach_msg);
+DECL_TEMPLATE(darwin, mach_reply_port);
+DECL_TEMPLATE(darwin, mach_thread_self);
+DECL_TEMPLATE(darwin, mach_host_self);
+DECL_TEMPLATE(darwin, mach_task_self);
+DECL_TEMPLATE(darwin, syscall_thread_switch);
+DECL_TEMPLATE(darwin, semaphore_signal);
+DECL_TEMPLATE(darwin, semaphore_signal_all);
+DECL_TEMPLATE(darwin, semaphore_signal_thread);
+DECL_TEMPLATE(darwin, semaphore_wait);
+DECL_TEMPLATE(darwin, semaphore_wait_signal);
+DECL_TEMPLATE(darwin, semaphore_timedwait);
+DECL_TEMPLATE(darwin, semaphore_timedwait_signal);
+DECL_TEMPLATE(darwin, sys___semwait_signal);
+DECL_TEMPLATE(darwin, task_for_pid);
+DECL_TEMPLATE(darwin, pid_for_task);
+DECL_TEMPLATE(darwin, mach_timebase_info);
+DECL_TEMPLATE(darwin, mach_wait_until);
+DECL_TEMPLATE(darwin, mk_timer_create);
+DECL_TEMPLATE(darwin, mk_timer_destroy);
+DECL_TEMPLATE(darwin, mk_timer_arm);
+DECL_TEMPLATE(darwin, mk_timer_cancel);
+DECL_TEMPLATE(darwin, iokit_user_client_trap);
+DECL_TEMPLATE(darwin, swtch);
+DECL_TEMPLATE(darwin, swtch_pri);
+
+// Machine-dependent traps
+DECL_TEMPLATE(darwin, pthread_set_self);
+
+// syswrap-<arch>-darwin.c
+#include <mach/mach.h>
+extern
+void thread_state_from_vex(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic);
+extern
+void thread_state_to_vex(const thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic);
+extern
+ThreadState *build_thread(const thread_state_t state,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count);
+extern
+void hijack_thread_state(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ ThreadState *tst);
+extern
+__attribute__((noreturn))
+void call_on_new_stack_0_1 ( Addr stack,
+ Addr retaddr,
+ void (*f)(Word),
+ Word arg1 );
+
+extern void pthread_hijack_asm(void);
+extern void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
+ Addr stacksize, Addr flags, Addr sp);
+extern void wqthread_hijack_asm(void);
+extern void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem, Int reuse, Addr sp);
+
+extern Addr pthread_starter;
+extern Addr wqthread_starter;
+extern SizeT pthread_structsize;
+
+
+#endif
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/priv_syswrap-main.h b/coregrind/m_syswrap/priv_syswrap-main.h
index 7c4fc52..e4b87b3 100644
--- a/coregrind/m_syswrap/priv_syswrap-main.h
+++ b/coregrind/m_syswrap/priv_syswrap-main.h
@@ -35,6 +35,12 @@
extern
void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch );
+#if defined(VGO_darwin)
+/* Longjmp to scheduler after client calls workq_ops(WQOPS_THREAD_RETURN)*/
+extern
+void ML_(wqthread_continue_NORETURN)(ThreadId tid);
+#endif
+
#endif // __PRIV_SYSWRAP_MAIN_H
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h
index 45536b8..c481b8f 100644
--- a/coregrind/m_syswrap/priv_types_n_macros.h
+++ b/coregrind/m_syswrap/priv_types_n_macros.h
@@ -49,8 +49,8 @@
/* Arguments for a syscall. */
typedef
- struct {
- UWord sysno;
+ struct SyscallArgs {
+ Word sysno;
UWord arg1;
UWord arg2;
UWord arg3;
@@ -64,7 +64,7 @@
/* Current status of a syscall being done on behalf of the client. */
typedef
- struct {
+ struct SyscallStatus {
enum {
/* call is complete, result is in 'res' */
SsComplete=1,
@@ -80,6 +80,12 @@
/* Guest state layout info for syscall args. */
typedef
struct {
+ // Note that, depending on the platform, arguments may be found in
+ // registers or on the stack. (See the comment at the top of
+ // syswrap-main.c for per-platform details.) For register arguments
+ // (which have o_arg field names) the o_arg value is the offset from
+ // the vex register state. For stack arguments (which have s_arg
+ // field names), the s_arg value is the offset from the stack pointer.
Int o_sysno;
# if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \
|| defined(VGP_ppc32_linux) || defined(VGP_ppc64_linux)
@@ -100,6 +106,24 @@
Int o_arg6;
Int o_arg7;
Int o_arg8;
+# elif defined(VGP_x86_darwin)
+ Int s_arg1;
+ Int s_arg2;
+ Int s_arg3;
+ Int s_arg4;
+ Int s_arg5;
+ Int s_arg6;
+ Int s_arg7;
+ Int s_arg8;
+# elif defined(VGP_amd64_darwin)
+ Int o_arg1;
+ Int o_arg2;
+ Int o_arg3;
+ Int o_arg4;
+ Int o_arg5;
+ Int o_arg6;
+ Int s_arg7;
+ Int s_arg8;
# else
# error "Unknown platform"
# endif
@@ -146,7 +170,7 @@
*/
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_darwin)
/* On Linux, finding the wrapper is easy: just look up in fixed,
platform-specific tables. These are defined in the relevant
platform-specific files -- syswrap-arch-os.c */
@@ -245,8 +269,15 @@
vgSysWrap_##auxstr##_##name##_after
/* Add a generic wrapper to a syscall table. */
-#define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name)
-#define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name)
+#if defined(VGO_linux) || defined(VGO_aix5)
+# define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name)
+# define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name)
+#elif defined(VGO_darwin)
+# define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
+# define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#else
+# error Unknown OS
+#endif
/* Add a Linux-specific, arch-independent wrapper to a syscall
table. */
@@ -343,15 +374,57 @@
/* Macros used to tell tools about uses of scalar arguments. Note,
these assume little-endianness. These can only be used in
pre-wrappers, and they refer to the layout parameter passed in. */
-/* PRRAn == "pre-register-read-argument"
- PRRSN == "pre-register-read-syscall"
+/* PRRSN == "pre-register-read-sysno"
+ PRRAn == "pre-register-read-argument"
+ PSRAn == "pre-stack-read-argument"
+ PRAn == "pre-read-argument"
*/
+#if defined(VGO_linux)
+ /* Up to 6 parameters, all in registers. */
+# define PRA1(s,t,a) PRRAn(1,s,t,a)
+# define PRA2(s,t,a) PRRAn(2,s,t,a)
+# define PRA3(s,t,a) PRRAn(3,s,t,a)
+# define PRA4(s,t,a) PRRAn(4,s,t,a)
+# define PRA5(s,t,a) PRRAn(5,s,t,a)
+# define PRA6(s,t,a) PRRAn(6,s,t,a)
+
+#elif defined(VGO_aix5)
+# error Need to fill this in for AIX5
+
+#elif defined(VGP_x86_darwin)
+ /* Up to 8 parameters, all on the stack. */
+# define PRA1(s,t,a) PSRAn(1,s,t,a)
+# define PRA2(s,t,a) PSRAn(2,s,t,a)
+# define PRA3(s,t,a) PSRAn(3,s,t,a)
+# define PRA4(s,t,a) PSRAn(4,s,t,a)
+# define PRA5(s,t,a) PSRAn(5,s,t,a)
+# define PRA6(s,t,a) PSRAn(6,s,t,a)
+# define PRA7(s,t,a) PSRAn(7,s,t,a)
+# define PRA8(s,t,a) PSRAn(8,s,t,a)
+
+#elif defined(VGP_amd64_darwin)
+ /* Up to 8 parameters, 6 in registers, 2 on the stack. */
+# define PRA1(s,t,a) PRRAn(1,s,t,a)
+# define PRA2(s,t,a) PRRAn(2,s,t,a)
+# define PRA3(s,t,a) PRRAn(3,s,t,a)
+# define PRA4(s,t,a) PRRAn(4,s,t,a)
+# define PRA5(s,t,a) PRRAn(5,s,t,a)
+# define PRA6(s,t,a) PRRAn(6,s,t,a)
+# define PRA7(s,t,a) PSRAn(7,s,t,a)
+# define PRA8(s,t,a) PSRAn(8,s,t,a)
+
+#else
+# error Unknown platform
+#endif
+
+
/* Tell the tool that the syscall number is being read. */
#define PRRSN \
VG_(tdict).track_pre_reg_read(Vg_CoreSysCall, tid, "(syscallno)", \
layout->o_sysno, sizeof(UWord));
+/* REGISTER PARAMETERS */
/* PRRAn: Tell the tool that the register holding the n-th syscall
argument is being read, at type 't' which must be at most the size
@@ -402,6 +475,55 @@
#endif
+/* STACK PARAMETERS */
+
+/* PSRAn: Tell the tool that the memory holding the n-th syscall
+ argument is being read, at type 't' which must be at most the size
+ of a register but can be smaller. In the latter case we need to be
+ careful about endianness. */
+
+/* little-endian: the part of the guest state being read is
+ let here = offset_of_reg
+ in [here .. here + sizeof(t) - 1]
+ since the least significant parts of the guest register are stored
+ in memory at the lowest address.
+*/
+#define PSRAn_LE(n,s,t,a) \
+ do { \
+ Addr here = layout->s_arg##n + VG_(get_SP)(tid); \
+ vg_assert(sizeof(t) <= sizeof(UWord)); \
+ VG_(tdict).track_pre_mem_read( \
+ Vg_CoreSysCallArgInMem, tid, s"("#a")", \
+ here, sizeof(t) \
+ ); \
+ } while (0)
+
+/* big-endian: the part of the guest state being read is
+ let next = offset_of_reg + sizeof(reg)
+ in [next - sizeof(t) .. next - 1]
+ since the least significant parts of the guest register are stored
+ in memory at the highest address.
+*/
+#define PSRAn_BE(n,s,t,a) \
+ do { \
+ Addr next = layout->o_arg##n + sizeof(UWord) + \
+ VG_(threads)[tid].arch.vex.VG_STACK_PTR; \
+ vg_assert(sizeof(t) <= sizeof(UWord)); \
+ VG_(tdict).track_pre_mem_read( \
+ Vg_CoreSysCallArgInMem, tid, s"("#a")", \
+ next-sizeof(t), sizeof(t) \
+ ); \
+ } while (0)
+
+#if defined(VG_BIGENDIAN)
+# define PSRAn(n,s,t,a) PSRAn_BE(n,s,t,a)
+#elif defined(VG_LITTLEENDIAN)
+# define PSRAn(n,s,t,a) PSRAn_LE(n,s,t,a)
+#else
+# error "Unknown endianness"
+#endif
+
+
#define PRE_REG_READ0(tr, s) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
@@ -409,35 +531,50 @@
#define PRE_REG_READ1(tr, s, t1, a1) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); \
+ PRA1(s,t1,a1); \
}
#define PRE_REG_READ2(tr, s, t1, a1, t2, a2) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); \
}
#define PRE_REG_READ3(tr, s, t1, a1, t2, a2, t3, a3) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
}
#define PRE_REG_READ4(tr, s, t1, a1, t2, a2, t3, a3, t4, a4) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
- PRRAn(4,s,t4,a4); \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
+ PRA4(s,t4,a4); \
}
#define PRE_REG_READ5(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
- PRRAn(4,s,t4,a4); PRRAn(5,s,t5,a5); \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
+ PRA4(s,t4,a4); PRA5(s,t5,a5); \
}
#define PRE_REG_READ6(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6) \
if (VG_(tdict).track_pre_reg_read) { \
PRRSN; \
- PRRAn(1,s,t1,a1); PRRAn(2,s,t2,a2); PRRAn(3,s,t3,a3); \
- PRRAn(4,s,t4,a4); PRRAn(5,s,t5,a5); PRRAn(6,s,t6,a6); \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
+ PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
+ }
+#define PRE_REG_READ7(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7) \
+ if (VG_(tdict).track_pre_reg_read) { \
+ PRRSN; \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
+ PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
+ PRA7(s,t7,a7); \
+ }
+
+#define PRE_REG_READ8(tr, s, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, t6, a6, t7, a7, t8, a8) \
+ if (VG_(tdict).track_pre_reg_read) { \
+ PRRSN; \
+ PRA1(s,t1,a1); PRA2(s,t2,a2); PRA3(s,t3,a3); \
+ PRA4(s,t4,a4); PRA5(s,t5,a5); PRA6(s,t6,a6); \
+ PRA7(s,t7,a7); PRA8(s,t8,a8); \
}
#define PRE_MEM_READ(zzname, zzaddr, zzlen) \
diff --git a/coregrind/m_syswrap/syscall-amd64-darwin.S b/coregrind/m_syswrap/syscall-amd64-darwin.S
new file mode 100644
index 0000000..099a94e
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-amd64-darwin.S
@@ -0,0 +1,253 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls. syscall-amd64-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums.h"
+#include "libvex_guest_offsets.h"
+
+
+/*----------------------------------------------------------------*/
+/*
+ Perform a syscall for the client. This will run a syscall
+ with the client's specific per-thread signal mask.
+
+ The structure of this function is such that, if the syscall is
+ interrupted by a signal, we can determine exactly what
+ execution state we were in with respect to the execution of
+ the syscall by examining the value of %eip in the signal
+ handler. This means that we can always do the appropriate
+ thing to precisely emulate the kernel's signal/syscall
+ interactions.
+
+ The syscall number is taken from the argument, even though it
+ should also be in guest_state->guest_RAX. The syscall result
+ is written back to guest_state->guest_RAX on completion.
+
+ Returns 0 if the syscall was successfully called (even if the
+ syscall itself failed), or a -ve error code if one of the
+ sigprocmasks failed (there's no way to determine which one
+ failed).
+
+ VG_(fixup_guest_state_after_syscall_interrupted) does the
+ thread state fixup in the case where we were interrupted by a
+ signal.
+
+ Prototype:
+
+ Int ML_(do_syscall_for_client_WRK(
+ Int syscallno, // rdi
+ void* guest_state, // rsi
+ const vki_sigset_t *sysmask, // rdx
+ const vki_sigset_t *postmask, // rcx
+ Int sigsetSzB) // r8
+
+ Note that sigsetSzB is totally ignored (and irrelevant).
+*/
+
+/* from vki_arch.h */
+#define VKI_SIG_SETMASK 3
+
+/* DO_SYSCALL MACH|MDEP|UNIX */
+#define MACH 1
+#define MDEP 2
+#define UNIX 3
+
+.macro DO_SYSCALL
+ /* save callee-saved regs */
+ pushq %rbp
+ movq %rsp, %rbp
+ // stack is now aligned
+ pushq %rdi // -8(%rbp) syscallno
+ pushq %rsi // -16(%rbp) guest_state
+ pushq %rdx // -24(%rbp) sysmask
+ pushq %rcx // -32(%rbp) postmask
+ pushq %r8 // -40(%rbp) sigsetSzB
+ // stack is now aligned
+
+L_$0_1: /* Even though we can't take a signal until the sigprocmask completes,
+ start the range early.
+ If rip is in the range [1,2), the syscall hasn't been started yet */
+
+ /* Set the signal mask which should be current during the syscall. */
+ /* GrP fixme signals
+ DDD: JRS fixme: use __NR___pthread_sigmask, not __NR_rt_sigprocmask
+ movq $__NR_rt_sigprocmask, %rax // syscall #
+ movq $VKI_SIG_SETMASK, %rdi // how
+ movq -24(%rbp), %rsi // sysmask
+ movq -32(%rbp), %rdx // postmask
+ movq -40(%rbp), %r10 // sigsetSzB in r10 not rcx
+ DDD: fixme return address
+ syscall
+
+ jnc 7f // sigprocmask failed
+ */
+
+ /* OK, that worked. Now do the syscall proper. */
+
+ /* 6 register parameters */
+ movq -16(%rbp), %r11 /* r11 = VexGuestAMD64State * */
+ movq OFFSET_amd64_RDI(%r11), %rdi
+ movq OFFSET_amd64_RSI(%r11), %rsi
+ movq OFFSET_amd64_RDX(%r11), %rdx
+ movq OFFSET_amd64_RCX(%r11), %r10 /* rcx is passed in r10 instead */
+ movq OFFSET_amd64_R8(%r11), %r8
+ movq OFFSET_amd64_R9(%r11), %r9
+ /* 2 stack parameters plus return address (ignored by syscall) */
+ movq OFFSET_amd64_RSP(%r11), %r11 /* r11 = simulated RSP */
+ movq 16(%r11), %rax
+ pushq %rax
+ movq 8(%r11), %rax
+ pushq %rax
+ /* stack is currently aligned - return address misaligns */
+ movq 0(%r11), %rax
+ pushq %rax
+ /* syscallno */
+ movq -8(%rbp), %rax
+
+ /* If rip==2, then the syscall was either just about
+ to start, or was interrupted and the kernel was
+ restarting it. */
+L_$0_2: syscall
+L_$0_3: /* In the range [3, 4), the syscall result is in %rax,
+ but hasn't been committed to RAX. */
+
+ /* stack contents: 3 words for syscall above, plus our prologue */
+ setc 0(%rsp) /* stash returned carry flag */
+
+ movq -16(%rbp), %r11 /* r11 = VexGuestAMD64State * */
+ movq %rax, OFFSET_amd64_RAX(%r11) /* save back to RAX */
+ movq %rdx, OFFSET_amd64_RDX(%r11) /* save back to RDX */
+
+.if $0 == UNIX
+ /* save carry flag to VEX */
+ xor %rax, %rax
+ movb 0(%rsp), %al
+ movq %rax, %rdi /* arg1 = new flag */
+ movq %r11, %rsi /* arg2 = vex state */
+ addq $$24, %rsp /* remove syscall parameters */
+ call _LibVEX_GuestAMD64_put_rflag_c
+.else
+ addq $$24, %rsp /* remove syscall parameters*/
+.endif
+
+L_$0_4: /* Re-block signals. If eip is in [4,5), then the syscall
+ is complete and we needn't worry about it. */
+ /* GrP fixme signals
+ DDD: JRS fixme: use __NR___pthread_sigmask, not __NR_rt_sigprocmask
+ PUSH_di_si_dx_cx_8
+
+ movq $__NR_rt_sigprocmask, %rax // syscall #
+ movq $VKI_SIG_SETMASK, %rdi // how
+ movq %rcx, %rsi // postmask
+ xorq %rdx, %rdx // NULL
+ movq %r8, %r10 // sigsetSzB
+ DDD: fixme return address
+ syscall
+
+ POP_di_si_dx_cx_8
+
+ jnc 7f // sigprocmask failed
+ */
+L_$0_5: /* now safe from signals */
+ movq $$0, %rax /* SUCCESS */
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+
+/* GrP fixme signals
+L_$0_7: // failure: return 0x8000 | error code
+ DDD: fixme return value
+ movq %rbp, %rsp
+ popq %rbp
+ ret
+*/
+
+.endmacro
+
+
+.globl ML_(do_syscall_for_client_unix_WRK)
+ML_(do_syscall_for_client_unix_WRK):
+ DO_SYSCALL UNIX
+
+.globl ML_(do_syscall_for_client_mach_WRK)
+ML_(do_syscall_for_client_mach_WRK):
+ DO_SYSCALL MACH
+
+.globl ML_(do_syscall_for_client_mdep_WRK)
+ML_(do_syscall_for_client_mdep_WRK):
+ DO_SYSCALL MDEP
+
+.data
+/* export the ranges so that
+ VG_(fixup_guest_state_after_syscall_interrupted) can do the
+ right thing */
+
+/* eg MK_L_SCLASS_N(UNIX,99) produces L_3_99
+ since UNIX is #defined to 3 at the top of this file */
+#define FOO(scclass,labelno) L_##scclass##_##labelno
+#define MK_L_SCCLASS_N(scclass,labelno) FOO(scclass,labelno)
+
+.globl ML_(blksys_setup_MACH)
+.globl ML_(blksys_restart_MACH)
+.globl ML_(blksys_complete_MACH)
+.globl ML_(blksys_committed_MACH)
+.globl ML_(blksys_finished_MACH)
+ML_(blksys_setup_MACH): .quad MK_L_SCCLASS_N(MACH,1)
+ML_(blksys_restart_MACH): .quad MK_L_SCCLASS_N(MACH,2)
+ML_(blksys_complete_MACH): .quad MK_L_SCCLASS_N(MACH,3)
+ML_(blksys_committed_MACH): .quad MK_L_SCCLASS_N(MACH,4)
+ML_(blksys_finished_MACH): .quad MK_L_SCCLASS_N(MACH,5)
+
+.globl ML_(blksys_setup_MDEP)
+.globl ML_(blksys_restart_MDEP)
+.globl ML_(blksys_complete_MDEP)
+.globl ML_(blksys_committed_MDEP)
+.globl ML_(blksys_finished_MDEP)
+ML_(blksys_setup_MDEP): .quad MK_L_SCCLASS_N(MDEP,1)
+ML_(blksys_restart_MDEP): .quad MK_L_SCCLASS_N(MDEP,2)
+ML_(blksys_complete_MDEP): .quad MK_L_SCCLASS_N(MDEP,3)
+ML_(blksys_committed_MDEP): .quad MK_L_SCCLASS_N(MDEP,4)
+ML_(blksys_finished_MDEP): .quad MK_L_SCCLASS_N(MDEP,5)
+
+.globl ML_(blksys_setup_UNIX)
+.globl ML_(blksys_restart_UNIX)
+.globl ML_(blksys_complete_UNIX)
+.globl ML_(blksys_committed_UNIX)
+.globl ML_(blksys_finished_UNIX)
+ML_(blksys_setup_UNIX): .quad MK_L_SCCLASS_N(UNIX,1)
+ML_(blksys_restart_UNIX): .quad MK_L_SCCLASS_N(UNIX,2)
+ML_(blksys_complete_UNIX): .quad MK_L_SCCLASS_N(UNIX,3)
+ML_(blksys_committed_UNIX): .quad MK_L_SCCLASS_N(UNIX,4)
+ML_(blksys_finished_UNIX): .quad MK_L_SCCLASS_N(UNIX,5)
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-x86-darwin.S b/coregrind/m_syswrap/syscall-x86-darwin.S
new file mode 100644
index 0000000..41cc27e
--- /dev/null
+++ b/coregrind/m_syswrap/syscall-x86-darwin.S
@@ -0,0 +1,252 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Support for doing system calls. syscall-x86-darwin.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2007 Julian Seward
+ jseward@acm.org
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+#include "pub_core_vkiscnums.h"
+#include "libvex_guest_offsets.h"
+
+
+/*----------------------------------------------------------------*/
+/*
+ Perform a syscall for the client. This will run a syscall
+ with the client's specific per-thread signal mask.
+
+ The structure of this function is such that, if the syscall is
+ interrupted by a signal, we can determine exactly what
+ execution state we were in with respect to the execution of
+ the syscall by examining the value of %eip in the signal
+ handler. This means that we can always do the appropriate
+ thing to precisely emulate the kernel's signal/syscall
+ interactions.
+
+ The syscall number is taken from the argument, even though it
+ should also be in regs->m_eax. The syscall result is written
+ back to regs->m_eax on completion.
+
+ Returns 0 if the syscall was successfully called (even if the
+ syscall itself failed), or a -ve error code if one of the
+ sigprocmasks failed (there's no way to determine which one
+ failed).
+
+ VG_(fixup_guest_state_after_syscall_interrupted) does the
+ thread state fixup in the case where we were interrupted by a
+ signal.
+
+ Prototype:
+
+ Int ML_(do_syscall_for_client_WRK)(
+ Int syscallno, // ebp+8
+ void* guest_state, // ebp+12
+ const vki_sigset_t *sysmask, // ebp+16
+ const vki_sigset_t *postmask, // ebp+20
+ Int sigsetSzB) // ebp+24
+
+ Note that sigsetSzB is totally ignored (and irrelevant).
+*/
+
+/* from vki-darwin.h, checked at startup by m_vki.c */
+#define VKI_SIG_SETMASK 3
+
+/* DO_SYSCALL MACH|MDEP|UNIX */
+#define MACH 1
+#define MDEP 2
+#define UNIX 3
+
+.macro DO_SYSCALL
+ /* establish stack frame */
+ push %ebp
+ mov %esp, %ebp
+ subl $$8, %esp /* 16-byte align stack */
+
+L_$0_1: /* Even though we can't take a signal until the
+ __pthread_sigmask completes, start the range early.
+ If eip is in the range [1,2), the syscall hasn't been started yet */
+
+ /* Set the signal mask which should be current during the syscall. */
+ /* Set up for __pthread_sigmask(SIG_SETMASK, sysmask, postmask) */
+ pushl 20(%ebp)
+ pushl 16(%ebp)
+ pushl $$VKI_SIG_SETMASK
+ pushl $$0xcafebabe /* totally fake return address */
+ movl $$__NR___pthread_sigmask, %eax
+ int $$0x80 /* should be sysenter? */
+ jc L_$0_7 /* __pthread_sigmask failed */
+ addl $$16,%esp
+
+ /* Copy syscall parameters to the stack - assume no more than 8
+ * plus the return address */
+ /* do_syscall8 */
+ /* stack is currently aligned assuming 8 parameters */
+ movl 12(%ebp), %edx
+ movl OFFSET_x86_ESP(%edx), %edx /* edx = simulated ESP */
+ movl 28+4(%edx), %eax
+ pushl %eax
+ movl 24+4(%edx), %eax
+ pushl %eax
+ movl 20+4(%edx), %eax
+ pushl %eax
+ movl 16+4(%edx), %eax
+ pushl %eax
+ movl 12+4(%edx), %eax
+ pushl %eax
+ movl 8+4(%edx), %eax
+ pushl %eax
+ movl 4+4(%edx), %eax
+ pushl %eax
+ movl 0+4(%edx), %eax
+ pushl %eax
+ /* return address */
+ movl 0(%edx), %eax
+ pushl %eax
+
+ /* Put syscall number in eax */
+ movl 8(%ebp), %eax
+
+ /* If eip==2, then the syscall was either just about to start,
+ or was interrupted and the kernel was restarting it. */
+L_$0_2:
+.if $0 == UNIX
+ int $$0x80 /* UNIX (GrP fixme should be sysenter?) */
+.elseif $0 == MACH
+ int $$0x81
+.elseif $0 == MDEP
+ int $$0x82
+.else
+ error$0 x
+.endif
+
+L_$0_3: /* In the range [3, 4), the syscall result is in %eax and %edx and C,
+ but hasn't been committed to the thread state. */
+ setc 0(%esp) /* stash returned carry flag */
+ movl 12(%ebp), %ecx
+ movl %eax, OFFSET_x86_EAX(%ecx) /* save EAX to vex */
+ movl %edx, OFFSET_x86_EDX(%ecx) /* save EDX to vex */
+.if $0 == UNIX
+ /* UNIX: save carry flag to vex */
+ subl $$12, %esp
+ movl %ecx, 4(%esp)
+ movl $$0, 0(%esp)
+ movb 12(%esp), %al
+ movb %al, 0(%esp)
+ call _LibVEX_GuestX86_put_eflag_c
+ addl $$12, %esp
+.endif
+
+L_$0_4: /* Re-block signals. If eip is in [4,5), then the syscall is
+ complete and we needn't worry about it. */
+ /* Set up for __pthread_sigmask(SIG_SETMASK, postmask, NULL) */
+ pushl $$0
+ pushl 20(%ebp)
+ pushl $$VKI_SIG_SETMASK
+ pushl $$0xcafef00d /* totally fake return address */
+ movl $$__NR___pthread_sigmask, %eax
+ int $$0x80 /* should be sysenter? */
+ jc L_$0_7 /* __pthread_sigmask failed */
+ addl $$16,%esp
+
+L_$0_5: /* now safe from signals */
+ movl $$0, %eax /* SUCCESS */
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+L_$0_7: /* failure: return 0x8000 | error code */
+ /* Note that we enter here with %esp being 16 too low
+ (4 extra words on the stack). But because we're nuking
+ the stack frame now, that doesn't matter. */
+ andl $$0x7FFF, %eax
+ orl $$0x8000, %eax
+ movl %ebp, %esp
+ popl %ebp
+ ret
+
+.endmacro
+
+
+.globl ML_(do_syscall_for_client_unix_WRK)
+ML_(do_syscall_for_client_unix_WRK):
+ DO_SYSCALL UNIX
+
+.globl ML_(do_syscall_for_client_mach_WRK)
+ML_(do_syscall_for_client_mach_WRK):
+ DO_SYSCALL MACH
+
+.globl ML_(do_syscall_for_client_mdep_WRK)
+ML_(do_syscall_for_client_mdep_WRK):
+ DO_SYSCALL MDEP
+
+.data
+/* export the ranges so that
+ VG_(fixup_guest_state_after_syscall_interrupted) can do the
+ right thing */
+
+/* eg MK_L_SCLASS_N(UNIX,99) produces L_3_99
+ since UNIX is #defined to 3 at the top of this file */
+#define FOO(scclass,labelno) L_##scclass##_##labelno
+#define MK_L_SCCLASS_N(scclass,labelno) FOO(scclass,labelno)
+
+.globl ML_(blksys_setup_MACH)
+.globl ML_(blksys_restart_MACH)
+.globl ML_(blksys_complete_MACH)
+.globl ML_(blksys_committed_MACH)
+.globl ML_(blksys_finished_MACH)
+ML_(blksys_setup_MACH): .long MK_L_SCCLASS_N(MACH,1)
+ML_(blksys_restart_MACH): .long MK_L_SCCLASS_N(MACH,2)
+ML_(blksys_complete_MACH): .long MK_L_SCCLASS_N(MACH,3)
+ML_(blksys_committed_MACH): .long MK_L_SCCLASS_N(MACH,4)
+ML_(blksys_finished_MACH): .long MK_L_SCCLASS_N(MACH,5)
+
+.globl ML_(blksys_setup_MDEP)
+.globl ML_(blksys_restart_MDEP)
+.globl ML_(blksys_complete_MDEP)
+.globl ML_(blksys_committed_MDEP)
+.globl ML_(blksys_finished_MDEP)
+ML_(blksys_setup_MDEP): .long MK_L_SCCLASS_N(MDEP,1)
+ML_(blksys_restart_MDEP): .long MK_L_SCCLASS_N(MDEP,2)
+ML_(blksys_complete_MDEP): .long MK_L_SCCLASS_N(MDEP,3)
+ML_(blksys_committed_MDEP): .long MK_L_SCCLASS_N(MDEP,4)
+ML_(blksys_finished_MDEP): .long MK_L_SCCLASS_N(MDEP,5)
+
+.globl ML_(blksys_setup_UNIX)
+.globl ML_(blksys_restart_UNIX)
+.globl ML_(blksys_complete_UNIX)
+.globl ML_(blksys_committed_UNIX)
+.globl ML_(blksys_finished_UNIX)
+ML_(blksys_setup_UNIX): .long MK_L_SCCLASS_N(UNIX,1)
+ML_(blksys_restart_UNIX): .long MK_L_SCCLASS_N(UNIX,2)
+ML_(blksys_complete_UNIX): .long MK_L_SCCLASS_N(UNIX,3)
+ML_(blksys_committed_UNIX): .long MK_L_SCCLASS_N(UNIX,4)
+ML_(blksys_finished_UNIX): .long MK_L_SCCLASS_N(UNIX,5)
+
+
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-amd64-darwin.c b/coregrind/m_syswrap/syswrap-amd64-darwin.c
new file mode 100644
index 0000000..714a755
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-amd64-darwin.c
@@ -0,0 +1,457 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc. syswrap-amd64-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_debuginfo.h" // VG_(di_notify_*)
+#include "pub_core_transtab.h" // VG_(discard_translations)
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h" /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h" /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+
+#include <mach/mach.h>
+
+static void x86_thread_state64_from_vex(x86_thread_state64_t *mach,
+ VexGuestAMD64State *vex)
+{
+ mach->__rax = vex->guest_RAX;
+ mach->__rbx = vex->guest_RBX;
+ mach->__rcx = vex->guest_RCX;
+ mach->__rdx = vex->guest_RDX;
+ mach->__rdi = vex->guest_RDI;
+ mach->__rsi = vex->guest_RSI;
+ mach->__rbp = vex->guest_RBP;
+ mach->__rsp = vex->guest_RSP;
+ mach->__rflags = LibVEX_GuestAMD64_get_rflags(vex);
+ mach->__rip = vex->guest_RIP;
+ mach->__r8 = vex->guest_R8;
+ mach->__r9 = vex->guest_R9;
+ mach->__r10 = vex->guest_R10;
+ mach->__r11 = vex->guest_R11;
+ mach->__r12 = vex->guest_R12;
+ mach->__r13 = vex->guest_R13;
+ mach->__r14 = vex->guest_R14;
+ mach->__r15 = vex->guest_R15;
+ /* GrP fixme
+ mach->__cs = vex->guest_CS;
+ mach->__fs = vex->guest_FS;
+ mach->__gs = vex->guest_GS;
+ */
+}
+
+
+static void x86_float_state64_from_vex(x86_float_state64_t *mach,
+ VexGuestAMD64State *vex)
+{
+ // DDD: #warning GrP fixme fp state
+
+ VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 16 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_from_vex(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic)
+{
+ VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
+
+ switch (flavor) {
+ case x86_THREAD_STATE64:
+ vg_assert(count == x86_THREAD_STATE64_COUNT);
+ x86_thread_state64_from_vex((x86_thread_state64_t *)mach_generic, vex);
+ break;
+
+ case x86_FLOAT_STATE64:
+ vg_assert(count == x86_FLOAT_STATE64_COUNT);
+ x86_float_state64_from_vex((x86_float_state64_t *)mach_generic, vex);
+ break;
+
+ default:
+ vg_assert(0);
+ }
+}
+
+
+static void x86_thread_state64_to_vex(const x86_thread_state64_t *mach,
+ VexGuestAMD64State *vex)
+{
+ LibVEX_GuestAMD64_initialise(vex);
+ vex->guest_RAX = mach->__rax;
+ vex->guest_RBX = mach->__rbx;
+ vex->guest_RCX = mach->__rcx;
+ vex->guest_RDX = mach->__rdx;
+ vex->guest_RDI = mach->__rdi;
+ vex->guest_RSI = mach->__rsi;
+ vex->guest_RBP = mach->__rbp;
+ vex->guest_RSP = mach->__rsp;
+ // DDD: #warning GrP fixme eflags
+ vex->guest_RIP = mach->__rip;
+ vex->guest_R8 = mach->__r8;
+ vex->guest_R9 = mach->__r9;
+ vex->guest_R10 = mach->__r10;
+ vex->guest_R11 = mach->__r11;
+ vex->guest_R12 = mach->__r12;
+ vex->guest_R13 = mach->__r13;
+ vex->guest_R14 = mach->__r14;
+ vex->guest_R15 = mach->__r15;
+ /* GrP fixme
+ vex->guest_CS = mach->__cs;
+ vex->guest_FS = mach->__fs;
+ vex->guest_GS = mach->__gs;
+ */
+}
+
+static void x86_float_state64_to_vex(const x86_float_state64_t *mach,
+ VexGuestAMD64State *vex)
+{
+ // DDD: #warning GrP fixme fp state
+
+ VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 16 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_to_vex(const thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic)
+{
+ VexGuestAMD64State *vex = (VexGuestAMD64State *)vex_generic;
+
+ switch(flavor) {
+ case x86_THREAD_STATE64:
+ vg_assert(count == x86_THREAD_STATE64_COUNT);
+ x86_thread_state64_to_vex((const x86_thread_state64_t*)mach_generic,vex);
+ break;
+ case x86_FLOAT_STATE64:
+ vg_assert(count == x86_FLOAT_STATE64_COUNT);
+ x86_float_state64_to_vex((const x86_float_state64_t*)mach_generic,vex);
+ break;
+
+ default:
+ vg_assert(0);
+ break;
+ }
+}
+
+
+ThreadState *build_thread(const thread_state_t state,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count)
+{
+ ThreadId tid = VG_(alloc_ThreadState)();
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+
+ vg_assert(flavor == x86_THREAD_STATE64);
+ vg_assert(count == x86_THREAD_STATE64_COUNT);
+
+ // Initialize machine registers
+
+ thread_state_to_vex(state, flavor, count, &tst->arch.vex);
+
+ I_die_here;
+ // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
+
+ find_stack_segment(tid, tst->arch.vex.guest_RSP);
+
+ return tst;
+}
+
+
+// Edit the thread state to send to the real kernel.
+// The real thread will run start_thread_NORETURN(tst)
+// on a separate non-client stack.
+void hijack_thread_state(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ ThreadState *tst)
+{
+ x86_thread_state64_t *mach = (x86_thread_state64_t *)mach_generic;
+ char *stack;
+
+ vg_assert(flavor == x86_THREAD_STATE64);
+ vg_assert(count == x86_THREAD_STATE64_COUNT);
+
+ stack = (char *)allocstack(tst->tid);
+ stack -= 64+320; // make room for top frame
+ memset(stack, 0, 64+320); // ...and clear it
+ *(uintptr_t *)stack = 0; // push fake return address
+
+ mach->__rdi = (uintptr_t)tst; // arg1 = tst
+ mach->__rip = (uintptr_t)&start_thread_NORETURN;
+ mach->__rsp = (uintptr_t)stack;
+}
+
+
+/* Call f(arg1), but first switch stacks, using 'stack' as the new
+ stack, and use 'retaddr' as f's return-to address. Also, clear all
+ the integer registers before entering f.*/
+__attribute__((noreturn))
+void call_on_new_stack_0_1 ( Addr stack,
+ Addr retaddr,
+ void (*f)(Word),
+ Word arg1 );
+// %rdi == stack (must be 16-byte aligned)
+// %rsi == retaddr
+// %rdx == f
+// %rcx == arg1
+asm(
+".globl _call_on_new_stack_0_1\n"
+"_call_on_new_stack_0_1:\n"
+" movq %rsp, %rbp\n" // remember old stack pointer
+" movq %rdi, %rsp\n" // set new stack
+" movq %rcx, %rdi\n" // set arg1
+" pushq %rsi\n" // retaddr to new stack
+" pushq %rdx\n" // f to new stack
+" movq $0, %rax\n" // zero all other GP regs
+" movq $0, %rbx\n"
+" movq $0, %rcx\n"
+" movq $0, %rdx\n"
+" movq $0, %rsi\n"
+" movq $0, %rbp\n"
+" movq $0, %r8\n"
+" movq $0, %r9\n"
+" movq $0, %r10\n"
+" movq $0, %r11\n"
+" movq $0, %r12\n"
+" movq $0, %r13\n"
+" movq $0, %r14\n"
+" movq $0, %r15\n"
+" ret\n" // jump to f
+" ud2\n" // should never get here
+);
+
+asm(
+".globl _pthread_hijack_asm\n"
+"_pthread_hijack_asm:\n"
+" movq %rsp,%rbp\n"
+" push $0\n" // alignment pad
+" push %rbp\n" // original sp
+ // other values stay where they are in registers
+" push $0\n" // fake return address
+" jmp _pthread_hijack\n"
+ );
+
+
+
+void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
+ Addr stacksize, Addr flags, Addr sp)
+{
+ ThreadState *tst = (ThreadState *)func_arg;
+ VexGuestAMD64State *vex = &tst->arch.vex;
+
+ // VG_(printf)("pthread_hijack pthread %p, machthread %p, func %p, arg %p, stack %p, flags %p, stack %p\n", self, kport, func, func_arg, stacksize, flags, sp);
+
+ // Wait for parent thread's permission.
+ // The parent thread holds V's lock on our behalf.
+ semaphore_wait(tst->os_state.child_go);
+
+ // Set thread's registers
+ // Do this FIRST because some code below tries to collect a backtrace,
+ // which requires valid register data.
+ LibVEX_GuestAMD64_initialise(vex);
+ vex->guest_RIP = pthread_starter;
+ vex->guest_RDI = self;
+ vex->guest_RSI = kport;
+ vex->guest_RDX = func;
+ vex->guest_RCX = tst->os_state.func_arg;
+ vex->guest_R8 = stacksize;
+ vex->guest_R9 = flags;
+ vex->guest_RSP = sp;
+
+ // Record thread's stack and Mach port and pthread struct
+ tst->os_state.pthread = self;
+ tst->os_state.lwpid = kport;
+ record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
+
+ if ((flags & 0x01000000) == 0) {
+ // kernel allocated stack - needs mapping
+ Addr stack = VG_PGROUNDUP(sp) - stacksize;
+ tst->client_stack_highest_word = stack+stacksize;
+ tst->client_stack_szB = stacksize;
+
+ // pthread structure
+ ML_(notify_core_and_tool_of_mmap)(
+ stack+stacksize, pthread_structsize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // stack contents
+ ML_(notify_core_and_tool_of_mmap)(
+ stack, stacksize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // guard page
+ ML_(notify_core_and_tool_of_mmap)(
+ stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
+ } else {
+ // client allocated stack
+ find_stack_segment(tst->tid, sp);
+ }
+ VG_(am_do_sync_check)("after", "pthread_hijack", 0);
+
+ // Tell parent thread's POST(sys_bsdthread_create) that we're done
+ // initializing registers and mapping memory.
+ semaphore_signal(tst->os_state.child_done);
+ // LOCK IS GONE BELOW THIS POINT
+
+ // Go!
+ call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
+ start_thread_NORETURN, (Word)tst);
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+
+asm(
+".globl _wqthread_hijack_asm\n"
+"_wqthread_hijack_asm:\n"
+" movq %rsp,%r9\n" // original sp
+ // other values stay where they are in registers
+" push $0\n" // fake return address
+" jmp _wqthread_hijack\n"
+ );
+
+
+/*
+ wqthread note: The kernel may create or destroy pthreads in the
+ wqthread pool at any time with no userspace interaction,
+ and wqthread_start may be entered at any time with no userspace
+ interaction.
+ To handle this in valgrind, we create and destroy a valgrind
+ thread for every work item.
+*/
+void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
+ Int reuse, Addr sp)
+{
+ ThreadState *tst;
+ VexGuestAMD64State *vex;
+ Addr stack;
+ SizeT stacksize;
+
+ if (reuse) {
+ // This thread already exists; we're merely re-entering
+ // after leaving via workq_ops(WQOPS_THREAD_RETURN).
+ // Don't allocate any V thread resources.
+ // Do reset thread registers.
+ ThreadId tid = VG_(lwpid_to_vgtid)(kport);
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(mach_thread_self() == kport);
+
+ tst = VG_(get_ThreadState)(tid);
+ vex = &tst->arch.vex;
+ vg_assert(tst->os_state.pthread == self);
+ }
+ else {
+ // This is a new thread.
+ tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
+ vex = &tst->arch.vex;
+ allocstack(tst->tid);
+ LibVEX_GuestAMD64_initialise(vex);
+ }
+
+ // Set thread's registers
+ // Do this FIRST because some code below tries to collect a backtrace,
+ // which requires valid register data.
+ vex->guest_RIP = wqthread_starter;
+ vex->guest_RDI = self;
+ vex->guest_RSI = kport;
+ vex->guest_RDX = stackaddr;
+ vex->guest_RCX = workitem;
+ vex->guest_R8 = reuse;
+ vex->guest_R9 = 0;
+ vex->guest_RSP = sp;
+
+ stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE
+ stack = VG_PGROUNDUP(sp) - stacksize;
+
+ if (reuse) {
+ // Continue V's thread back in the scheduler.
+ // The client thread is of course in another location entirely.
+ ML_(wqthread_continue_NORETURN)(tst->tid);
+ }
+ else {
+
+ // Record thread's stack and Mach port and pthread struct
+ tst->os_state.pthread = self;
+ tst->os_state.lwpid = kport;
+ record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
+
+ // kernel allocated stack - needs mapping
+ tst->client_stack_highest_word = stack+stacksize;
+ tst->client_stack_szB = stacksize;
+
+ // GrP fixme scheduler lock?!
+
+ // pthread structure
+ ML_(notify_core_and_tool_of_mmap)(
+ stack+stacksize, pthread_structsize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // stack contents
+ // GrP fixme uninitialized!
+ ML_(notify_core_and_tool_of_mmap)(
+ stack, stacksize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // guard page
+ // GrP fixme ban_mem_stack!
+ ML_(notify_core_and_tool_of_mmap)(
+ stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE, 0, VKI_MAP_PRIVATE, -1, 0);
+
+ VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
+
+ // Go!
+ call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
+ start_thread_NORETURN, (Word)tst);
+ }
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
diff --git a/coregrind/m_syswrap/syswrap-darwin.c b/coregrind/m_syswrap/syswrap-darwin.c
new file mode 100644
index 0000000..49b8a9a
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-darwin.c
@@ -0,0 +1,7549 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc. syswrap-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_vkiscnums.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_debuginfo.h" // VG_(di_notify_*)
+#include "pub_core_transtab.h" // VG_(discard_translations)
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_machine.h" // VG_(get_SP)
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_sigframe.h" // For VG_(sigframe_destroy)()
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h" /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h" /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <semaphore.h>
+#include <sys/acl.h> /* struct kauth_filesec */
+/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */
+
+#define msgh_request_port msgh_remote_port
+#define msgh_reply_port msgh_local_port
+#define BOOTSTRAP_MAX_NAME_LEN 128
+typedef char name_t[BOOTSTRAP_MAX_NAME_LEN];
+
+typedef uint64_t mig_addr_t;
+
+
+// Saved ports
+static mach_port_t vg_host_port = 0;
+static mach_port_t vg_task_port = 0;
+static mach_port_t vg_bootstrap_port = 0;
+
+// Run a thread from beginning to end and return the thread's
+// scheduler-return-code.
+static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
+{
+ VgSchedReturnCode ret;
+ ThreadId tid = (ThreadId)tidW;
+ ThreadState* tst = VG_(get_ThreadState)(tid);
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "thread_wrapper(tid=%lld): entry\n",
+ (ULong)tidW);
+
+ vg_assert(tst->status == VgTs_Init);
+
+ /* make sure we get the CPU lock before doing anything significant */
+ VG_(acquire_BigLock)(tid, "thread_wrapper");
+
+ if (0)
+ VG_(printf)("thread tid %d started: stack = %p\n",
+ tid, &tid);
+
+ VG_TRACK(pre_thread_first_insn, tid);
+
+ tst->os_state.lwpid = VG_(gettid)();
+ tst->os_state.threadgroup = VG_(getpid)();
+
+ /* Thread created with all signals blocked; scheduler will set the
+ appropriate mask */
+
+ ret = VG_(scheduler)(tid);
+
+ vg_assert(VG_(is_exiting)(tid));
+
+ vg_assert(tst->status == VgTs_Runnable);
+ vg_assert(VG_(is_running_thread)(tid));
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "thread_wrapper(tid=%lld): done\n",
+ (ULong)tidW);
+
+ /* Return to caller, still holding the lock. */
+ return ret;
+}
+
+
+
+/* Allocate a stack for this thread, if it doesn't already have one.
+ Returns the initial stack pointer value to use, or 0 if allocation
+ failed. */
+
+Addr allocstack ( ThreadId tid )
+{
+ ThreadState* tst = VG_(get_ThreadState)(tid);
+ VgStack* stack;
+ Addr initial_SP;
+
+ /* Either the stack_base and stack_init_SP are both zero (in which
+ case a stack hasn't been allocated) or they are both non-zero,
+ in which case it has. */
+
+ if (tst->os_state.valgrind_stack_base == 0)
+ vg_assert(tst->os_state.valgrind_stack_init_SP == 0);
+
+ if (tst->os_state.valgrind_stack_base != 0)
+ vg_assert(tst->os_state.valgrind_stack_init_SP != 0);
+
+ /* If no stack is present, allocate one. */
+
+ if (tst->os_state.valgrind_stack_base == 0) {
+ stack = VG_(am_alloc_VgStack)( &initial_SP );
+ if (stack) {
+ tst->os_state.valgrind_stack_base = (Addr)stack;
+ tst->os_state.valgrind_stack_init_SP = initial_SP;
+ }
+ }
+
+ VG_(debugLog)( 2, "syswrap-darwin", "stack for tid %d at %p; init_SP=%p\n",
+ tid,
+ (void*)tst->os_state.valgrind_stack_base,
+ (void*)tst->os_state.valgrind_stack_init_SP );
+
+ vg_assert(VG_IS_32_ALIGNED(tst->os_state.valgrind_stack_init_SP));
+
+ return tst->os_state.valgrind_stack_init_SP;
+}
+
+
+void find_stack_segment(ThreadId tid, Addr sp)
+{
+ /* We don't really know where the client stack is, because it's
+ allocated by the client. The best we can do is look at the
+ memory mappings and try to derive some useful information. We
+ assume that esp starts near its highest possible value, and can
+ only go down to the start of the mmaped segment. */
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ const NSegment *seg = VG_(am_find_nsegment)(sp);
+ if (seg && seg->kind != SkResvn) {
+ tst->client_stack_highest_word = (Addr)VG_PGROUNDUP(sp);
+ tst->client_stack_szB = tst->client_stack_highest_word - seg->start;
+
+ if (1)
+ VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n",
+ tid, seg->start, VG_PGROUNDUP(sp));
+ } else {
+ VG_(printf)("couldn't find user stack\n");
+ VG_(message)(Vg_UserMsg, "!? New thread %d starts with SP(%#lx) unmapped\n",
+ tid, sp);
+ tst->client_stack_szB = 0;
+ }
+}
+
+
+/* Run a thread all the way to the end, then do appropriate exit actions
+ (this is the last-one-out-turn-off-the-lights bit).
+*/
+static void run_a_thread_NORETURN ( Word tidW )
+{
+ Int c;
+ VgSchedReturnCode src;
+ ThreadId tid = (ThreadId)tidW;
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n",
+ (ULong)tidW);
+
+ /* Run the thread all the way through. */
+ src = thread_wrapper(tid);
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
+ (ULong)tidW);
+
+ c = VG_(count_living_threads)();
+ vg_assert(c >= 1); /* stay sane */
+
+ // Tell the tool this thread is exiting
+ VG_TRACK( pre_thread_ll_exit, tid );
+
+ if (c == 1) {
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "last one standing\n",
+ (ULong)tidW);
+
+ /* We are the last one standing. Keep hold of the lock and
+ carry on to show final tool results, then exit the entire system.
+ Use the continuation pointer set at startup in m_main. */
+ ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src);
+
+ } else {
+
+ ThreadState *tst;
+ mach_msg_header_t msg;
+
+ VG_(debugLog)(1, "syswrap-darwin",
+ "run_a_thread_NORETURN(tid=%lld): "
+ "not last one standing\n",
+ (ULong)tidW);
+
+ /* OK, thread is dead, but others still exist. Just exit. */
+ tst = VG_(get_ThreadState)(tid);
+
+ /* This releases the run lock */
+ VG_(exit_thread)(tid);
+ vg_assert(tst->status == VgTs_Zombie);
+
+ /* tid is now invalid. */
+
+ // GrP fixme exit race
+ msg.msgh_bits = MACH_MSGH_BITS(17, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ msg.msgh_request_port = VG_(gettid)();
+ msg.msgh_reply_port = 0;
+ msg.msgh_id = 3600; // thread_terminate
+
+ tst->status = VgTs_Empty;
+ // GrP fixme race here! new thread may claim this V thread stack
+ // before we get out here!
+ // GrP fixme use bsdthread_terminate for safe cleanup?
+ mach_msg(&msg, MACH_SEND_MSG|MACH_MSG_OPTION_NONE,
+ sizeof(msg), 0, 0, MACH_MSG_TIMEOUT_NONE, 0);
+
+ // DDD: This is reached sometimes on none/tests/manythreads, maybe
+ // because of the race above.
+ VG_(core_panic)("Thread exit failed?\n");
+ }
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+/* Allocate a stack for the main thread, and run it all the way to the
+ end. Although we already have a working VgStack
+ (VG_(interim_stack)) it's better to allocate a new one, so that
+ overflow detection works uniformly for all threads.
+*/
+void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
+{
+ Addr sp;
+ VG_(debugLog)(1, "syswrap-darwin",
+ "entering VG_(main_thread_wrapper_NORETURN)\n");
+
+ sp = allocstack(tid);
+
+ /* If we can't even allocate the first thread's stack, we're hosed.
+ Give up. */
+ vg_assert2(sp != 0, "Cannot allocate main thread's stack.");
+
+ /* shouldn't be any other threads around yet */
+ vg_assert( VG_(count_living_threads)() == 1 );
+
+ call_on_new_stack_0_1(
+ (Addr)sp, /* stack */
+ 0, /*bogus return address*/
+ run_a_thread_NORETURN, /* fn to call */
+ (Word)tid /* arg to give it */
+ );
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+void start_thread_NORETURN ( Word arg )
+{
+ ThreadState* tst = (ThreadState*)arg;
+ ThreadId tid = tst->tid;
+
+ run_a_thread_NORETURN ( (Word)tid );
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+void VG_(cleanup_thread) ( ThreadArchState* arch )
+{
+}
+
+
+/* ---------------------------------------------------------------------
+ Mach port tracking (based on syswrap-generic's fd tracker)
+ ------------------------------------------------------------------ */
+
+/* One of these is allocated for each open port. */
+typedef struct OpenPort
+{
+ mach_port_t port;
+ mach_port_type_t type; /* right type(s) */
+ Int send_count; /* number of send rights */
+ Char *name; /* bootstrap name or NULL */
+ ExeContext *where; /* first allocation only */
+ struct OpenPort *next, *prev;
+} OpenPort;
+
+// strlen("0x12345678")
+#define PORT_STRLEN (2+2*sizeof(mach_port_t))
+
+/* List of allocated ports. */
+static OpenPort *allocated_ports;
+
+/* Count of open ports. */
+static Int allocated_port_count = 0;
+
+
+__attribute__((unused))
+static Bool port_exists(mach_port_t port)
+{
+ OpenPort *i;
+
+ /* Check to see if this port is already open. */
+ i = allocated_ports;
+ while (i) {
+ if (i->port == port) {
+ return True;
+ }
+ i = i->next;
+ }
+
+ return False;
+}
+
+static OpenPort *info_for_port(mach_port_t port)
+{
+ OpenPort *i;
+ if (!port) return NULL;
+
+ i = allocated_ports;
+ while (i) {
+ if (i->port == port) {
+ return i;
+ }
+ i = i->next;
+ }
+
+ return NULL;
+}
+
+
+// Give a port a name, without changing its refcount
+// GrP fixme don't override name if it already has a specific one
+__private_extern__ void assign_port_name(mach_port_t port, const char *name)
+{
+ OpenPort *i;
+ if (!port) return;
+ vg_assert(name);
+
+ i = info_for_port(port);
+ vg_assert(i);
+
+ if (i->name) VG_(arena_free)(VG_AR_CORE, i->name);
+ i->name =
+ VG_(arena_malloc)(VG_AR_CORE, "syswrap-darwin.mach-port-name",
+ VG_(strlen)(name) + PORT_STRLEN + 1);
+ VG_(sprintf)(i->name, name, port);
+}
+
+
+// Return the name of the given port or "UNKNOWN 0x1234" if not known.
+static const char *name_for_port(mach_port_t port)
+{
+ static char buf[8 + PORT_STRLEN + 1];
+ OpenPort *i;
+
+ // hack
+ if (port == VG_(gettid)()) return "mach_thread_self()";
+ if (port == 0) return "NULL";
+
+ i = allocated_ports;
+ while (i) {
+ if (i->port == port) {
+ return i->name;
+ }
+ i = i->next;
+ }
+
+ VG_(sprintf)(buf, "NONPORT-%#x", port);
+ return buf;
+}
+
+/* Note the fact that a port was just deallocated. */
+
+static
+void record_port_mod_refs(mach_port_t port, mach_port_type_t right, Int delta)
+{
+ OpenPort *i = allocated_ports;
+ if (!port) return;
+
+ while(i) {
+ if(i->port == port) {
+ vg_assert(right != MACH_PORT_TYPE_DEAD_NAME);
+ if (right & MACH_PORT_TYPE_SEND) {
+ // send rights are refcounted
+ if (delta == INT_MIN) delta = -i->send_count; // INT_MIN == destroy
+ i->send_count += delta;
+ if (i->send_count > 0) i->type |= MACH_PORT_TYPE_SEND;
+ else i->type &= ~MACH_PORT_TYPE_SEND;
+ }
+ right = right & ~MACH_PORT_TYPE_SEND;
+ if (right) {
+ // other rights are not refcounted
+ if (delta > 0) {
+ i->type |= right;
+ } else if (delta < 0) {
+ i->type &= ~right;
+ }
+ }
+
+ if (i->type != 0) return;
+
+ // Port has no rights left. Kill it.
+ // VG_(printf)("deleting port %p %s", i->port, i->name);
+ if(i->prev)
+ i->prev->next = i->next;
+ else
+ allocated_ports = i->next;
+ if(i->next)
+ i->next->prev = i->prev;
+ if(i->name)
+ VG_(arena_free) (VG_AR_CORE, i->name);
+ VG_(arena_free) (VG_AR_CORE, i);
+ allocated_port_count--;
+ return;
+ }
+ i = i->next;
+ }
+
+ VG_(printf)("UNKNOWN Mach port modified (port %#x delta %d)\n", port, delta);
+}
+
+static
+void record_port_insert_rights(mach_port_t port, mach_msg_type_name_t type)
+{
+ switch (type) {
+ case MACH_MSG_TYPE_PORT_NAME:
+ // this task has no rights for the name
+ break;
+ case MACH_MSG_TYPE_PORT_RECEIVE:
+ // this task gets receive rights
+ record_port_mod_refs(port, MACH_PORT_TYPE_RECEIVE, 1);
+ break;
+ case MACH_MSG_TYPE_PORT_SEND:
+ // this task gets a send right
+ record_port_mod_refs(port, MACH_PORT_TYPE_SEND, 1);
+ break;
+ case MACH_MSG_TYPE_PORT_SEND_ONCE:
+ // this task gets send-once rights
+ record_port_mod_refs(port, MACH_PORT_TYPE_SEND_ONCE, 1);
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+}
+
+static
+void record_port_dealloc(mach_port_t port)
+{
+ // deletes 1 send or send-once right (port can't have both)
+ record_port_mod_refs(port, MACH_PORT_TYPE_SEND_RIGHTS, -1);
+}
+
+static
+void record_port_destroy(mach_port_t port)
+{
+ // deletes all rights to port
+ record_port_mod_refs(port, MACH_PORT_TYPE_ALL_RIGHTS, INT_MIN);
+}
+
+
+/* Note the fact that a Mach port was just allocated or transferred.
+ If the port is already known, increment its reference count. */
+void record_named_port(ThreadId tid, mach_port_t port,
+ mach_port_right_t right, const char *name)
+{
+ OpenPort *i;
+ if (!port) return;
+
+ /* Check to see if this port is already open. */
+ i = allocated_ports;
+ while (i) {
+ if (i->port == port) {
+ if (right != -1) record_port_mod_refs(port, MACH_PORT_TYPE(right), 1);
+ return;
+ }
+ i = i->next;
+ }
+
+ /* Not already one: allocate an OpenPort */
+ if (i == NULL) {
+ i = VG_(arena_malloc)(VG_AR_CORE, "syswrap-darwin.mach-port",
+ sizeof(OpenPort));
+
+ i->prev = NULL;
+ i->next = allocated_ports;
+ if(allocated_ports) allocated_ports->prev = i;
+ allocated_ports = i;
+ allocated_port_count++;
+
+ i->port = port;
+ i->where = (tid == -1) ? NULL : VG_(record_ExeContext)(tid, 0);
+ i->name = NULL;
+ if (right != -1) {
+ i->type = MACH_PORT_TYPE(right);
+ i->send_count = (right == MACH_PORT_RIGHT_SEND) ? 1 : 0;
+ } else {
+ i->type = 0;
+ i->send_count = 0;
+ }
+
+ assign_port_name(port, name);
+ }
+}
+
+
+// Record opening of a nameless port.
+static void record_unnamed_port(ThreadId tid, mach_port_t port, mach_port_right_t right)
+{
+ record_named_port(tid, port, right, "unnamed-%p");
+}
+
+
+/* Dump summary of open Mach ports, like VG_(show_open_fds) */
+void VG_(show_open_ports)(void)
+{
+ OpenPort *i;
+
+ VG_(message)(Vg_UserMsg,
+ "MACH PORTS: %d open at exit.", allocated_port_count);
+
+ for (i = allocated_ports; i; i = i->next) {
+ if (i->name) {
+ VG_(message)(Vg_UserMsg, "Open Mach port 0x%x: %s", i->port, i->name);
+ } else {
+ VG_(message)(Vg_UserMsg, "Open Mach port 0x%x", i->port);
+ }
+
+ if (i->where) {
+ VG_(pp_ExeContext)(i->where);
+ VG_(message)(Vg_UserMsg, "");
+ }
+ }
+
+ VG_(message)(Vg_UserMsg, "");
+}
+
+
+/* ---------------------------------------------------------------------
+ sync_mappings
+ ------------------------------------------------------------------ */
+
+static void sync_mappings(const HChar *when, const HChar *where, Int num)
+{
+ // I haven't seen more than 1 segment be added or removed in a single calls
+ // to sync_mappings(). So 20 seems generous. The upper bound is the
+ // number of segments currently in use. --njn
+ #define CSS_SIZE 20
+ ChangedSeg css[CSS_SIZE];
+ Int css_used;
+ Int i;
+
+ VG_(get_changed_segments)(when, where, css, CSS_SIZE, &css_used);
+
+ // Now add/remove them.
+ for (i = 0; i < css_used; i++) {
+ ChangedSeg* cs = &css[i];
+ Char* action;
+ if (cs->is_added) {
+ ML_(notify_core_and_tool_of_mmap)(
+ cs->start, cs->end - cs->start + 1,
+ cs->prot, VKI_MAP_PRIVATE, 0, cs->offset);
+ // should this call VG_(di_notify_mmap) also?
+ action = "added";
+
+ } else {
+ ML_(notify_core_and_tool_of_munmap)(
+ cs->start, cs->end - cs->start + 1);
+ action = "removed";
+ }
+ if (VG_(clo_trace_syscalls)) {
+ VG_(debugLog)(0, "aspacem",
+ "\n%s region 0x%010lx..0x%010lx at %s (%s)\n",
+ action, cs->start, cs->end + 1, where, when);
+ }
+ }
+}
+
+/* ---------------------------------------------------------------------
+ wrappers
+ ------------------------------------------------------------------ */
+
+#define PRE(name) DEFN_PRE_TEMPLATE(darwin, name)
+#define POST(name) DEFN_POST_TEMPLATE(darwin, name)
+
+#define PRE_FN(name) vgSysWrap_darwin_##name##_before
+#define POST_FN(name) vgSysWrap_darwin_##name##_after
+
+#define CALL_PRE(name) PRE_FN(name)(tid, layout, arrghs, status, flags)
+#define CALL_POST(name) POST_FN(name)(tid, arrghs, status)
+
+#if VG_WORDSIZE == 4
+// Combine two 32-bit values into a 64-bit value
+// Always use with low-numbered arg first (e.g. LOHI64(ARG1,ARG2) )
+# if defined(VGA_x86)
+# define LOHI64(lo,hi) ( (lo) | ((ULong)(hi) << 32) )
+# else
+# error unknown architecture
+# endif
+#endif
+
+// Retrieve the current Mach thread
+#define MACH_THREAD ((Addr)VG_(get_ThreadState)(tid)->os_state.lwpid)
+
+// Set the POST handler for a mach_msg derivative
+#define AFTER VG_(get_ThreadState)(tid)->os_state.post_mach_trap_fn
+
+// Set or get values saved from Mach messages
+#define MACH_ARG(x) VG_(get_ThreadState)(tid)->os_state.mach_args.x
+#define MACH_REMOTE VG_(get_ThreadState)(tid)->os_state.remote_port
+#define MACH_MSGH_ID VG_(get_ThreadState)(tid)->os_state.msgh_id
+
+/* ---------------------------------------------------------------------
+ darwin ioctl wrapper
+ ------------------------------------------------------------------ */
+
+PRE(sys_ioctl)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_ioctl ( %ld, 0x%lx, %#lx )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "ioctl",
+ unsigned int, fd, unsigned int, request, unsigned long, arg);
+
+ switch (ARG2 /* request */) {
+ case VKI_TIOCGWINSZ:
+ PRE_MEM_WRITE( "ioctl(TIOCGWINSZ)", ARG3, sizeof(struct vki_winsize) );
+ break;
+ case VKI_TIOCSWINSZ:
+ PRE_MEM_READ( "ioctl(TIOCSWINSZ)", ARG3, sizeof(struct vki_winsize) );
+ break;
+ case VKI_TIOCMBIS:
+ PRE_MEM_READ( "ioctl(TIOCMBIS)", ARG3, sizeof(unsigned int) );
+ break;
+ case VKI_TIOCMBIC:
+ PRE_MEM_READ( "ioctl(TIOCMBIC)", ARG3, sizeof(unsigned int) );
+ break;
+ case VKI_TIOCMSET:
+ PRE_MEM_READ( "ioctl(TIOCMSET)", ARG3, sizeof(unsigned int) );
+ break;
+ case VKI_TIOCMGET:
+ PRE_MEM_WRITE( "ioctl(TIOCMGET)", ARG3, sizeof(unsigned int) );
+ break;
+ case VKI_TIOCGPGRP:
+ /* Get process group ID for foreground processing group. */
+ PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
+ break;
+ case VKI_TIOCSPGRP:
+ /* Set a process group ID? */
+ PRE_MEM_WRITE( "ioctl(TIOCGPGRP)", ARG3, sizeof(vki_pid_t) );
+ break;
+ case VKI_TIOCSCTTY:
+ /* Just takes an int value. */
+ break;
+ case VKI_FIONBIO:
+ PRE_MEM_READ( "ioctl(FIONBIO)", ARG3, sizeof(int) );
+ break;
+ case VKI_FIOASYNC:
+ PRE_MEM_READ( "ioctl(FIOASYNC)", ARG3, sizeof(int) );
+ break;
+ case VKI_FIONREAD: /* identical to SIOCINQ */
+ PRE_MEM_WRITE( "ioctl(FIONREAD)", ARG3, sizeof(int) );
+ break;
+
+
+ /* These all use struct ifreq AFAIK */
+ /* GrP fixme is sizeof(struct vki_if_req) correct if it's using a sockaddr? */
+ case VKI_SIOCGIFFLAGS: /* get flags */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFFLAGS)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFFLAGS)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFMTU: /* get MTU size */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMTU)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFMTU)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFADDR: /* get PA address */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFADDR)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFADDR)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFNETMASK: /* get network PA mask */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFNETMASK)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFNETMASK)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFMETRIC: /* get metric */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFMETRIC)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFMETRIC)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFDSTADDR: /* get remote PA address */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFDSTADDR)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFDSTADDR)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFBRDADDR: /* get broadcast PA address */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCGIFBRDADDR)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_WRITE( "ioctl(SIOCGIFBRDADDR)", ARG3, sizeof(struct vki_ifreq));
+ break;
+ case VKI_SIOCGIFCONF: /* get iface list */
+ /* WAS:
+ PRE_MEM_WRITE( "ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
+ KERNEL_DO_SYSCALL(tid,RES);
+ if (!VG_(is_kerror)(RES) && RES == 0)
+ POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
+ */
+ PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
+ (Addr)&((struct vki_ifconf *)ARG3)->ifc_len,
+ sizeof(((struct vki_ifconf *)ARG3)->ifc_len));
+ PRE_MEM_READ( "ioctl(SIOCGIFCONF)",
+ (Addr)&((struct vki_ifconf *)ARG3)->vki_ifc_buf,
+ sizeof(((struct vki_ifconf *)ARG3)->vki_ifc_buf));
+ if ( ARG3 ) {
+ // TODO len must be readable and writable
+ // buf pointer only needs to be readable
+ struct vki_ifconf *ifc = (struct vki_ifconf *) ARG3;
+ PRE_MEM_WRITE( "ioctl(SIOCGIFCONF).ifc_buf",
+ (Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
+ }
+ break;
+
+ case VKI_SIOCSIFFLAGS: /* set flags */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCSIFFLAGS)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_READ( "ioctl(SIOCSIFFLAGS)",
+ (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_flags,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_flags) );
+ break;
+ case VKI_SIOCSIFADDR: /* set PA address */
+ case VKI_SIOCSIFDSTADDR: /* set remote PA address */
+ case VKI_SIOCSIFBRDADDR: /* set broadcast PA address */
+ case VKI_SIOCSIFNETMASK: /* set network PA mask */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCSIF*ADDR)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_READ( "ioctl(SIOCSIF*ADDR)",
+ (Addr)&((struct vki_ifreq *)ARG3)->ifr_addr,
+ sizeof(((struct vki_ifreq *)ARG3)->ifr_addr) );
+ break;
+ case VKI_SIOCSIFMETRIC: /* set metric */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMETRIC)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_READ( "ioctl(SIOCSIFMETRIC)",
+ (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_metric,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_metric) );
+ break;
+ case VKI_SIOCSIFMTU: /* set MTU size */
+ PRE_MEM_RASCIIZ( "ioctl(SIOCSIFMTU)",
+ (Addr)((struct vki_ifreq *)ARG3)->vki_ifr_name );
+ PRE_MEM_READ( "ioctl(SIOCSIFMTU)",
+ (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_mtu,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_mtu) );
+ break;
+ /* Routing table calls. */
+#ifdef VKI_SIOCADDRT
+ case VKI_SIOCADDRT: /* add routing table entry */
+ case VKI_SIOCDELRT: /* delete routing table entry */
+ PRE_MEM_READ( "ioctl(SIOCADDRT/DELRT)", ARG3,
+ sizeof(struct vki_rtentry));
+ break;
+#endif
+
+ case VKI_SIOCGPGRP:
+ PRE_MEM_WRITE( "ioctl(SIOCGPGRP)", ARG3, sizeof(int) );
+ break;
+ case VKI_SIOCSPGRP:
+ PRE_MEM_READ( "ioctl(SIOCSPGRP)", ARG3, sizeof(int) );
+ //tst->sys_flags &= ~SfMayBlock;
+ break;
+
+ case VKI_FIODTYPE:
+ PRE_MEM_WRITE( "ioctl(FIONREAD)", ARG3, sizeof(int) );
+ break;
+
+ case VKI_DTRACEHIOC_REMOVE:
+ case VKI_DTRACEHIOC_ADDDOF:
+ break;
+
+ // ttycom.h
+ case VKI_TIOCGETA:
+ PRE_MEM_WRITE( "ioctl(TIOCGETA)", ARG3, sizeof(struct vki_termios) );
+ break;
+ case VKI_TIOCSETA:
+ PRE_MEM_READ( "ioctl(TIOCSETA)", ARG3, sizeof(struct vki_termios) );
+ break;
+ case VKI_TIOCGETD:
+ PRE_MEM_WRITE( "ioctl(TIOCGETD)", ARG3, sizeof(int) );
+ break;
+ case VKI_TIOCSETD:
+ PRE_MEM_READ( "ioctl(TIOCSETD)", ARG3, sizeof(int) );
+ break;
+ case VKI_TIOCPTYGNAME:
+ PRE_MEM_WRITE( "ioctl(TIOCPTYGNAME)", ARG3, 128 );
+ break;
+ case VKI_TIOCPTYGRANT:
+ case VKI_TIOCPTYUNLK:
+ break;
+
+ default:
+ ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
+ break;
+ }
+}
+
+
+POST(sys_ioctl)
+{
+ vg_assert(SUCCESS);
+ switch (ARG2 /* request */) {
+ case VKI_TIOCGWINSZ:
+ POST_MEM_WRITE( ARG3, sizeof(struct vki_winsize) );
+ break;
+ case VKI_TIOCSWINSZ:
+ case VKI_TIOCMBIS:
+ case VKI_TIOCMBIC:
+ case VKI_TIOCMSET:
+ break;
+ case VKI_TIOCMGET:
+ POST_MEM_WRITE( ARG3, sizeof(unsigned int) );
+ break;
+ case VKI_TIOCGPGRP:
+ /* Get process group ID for foreground processing group. */
+ POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
+ break;
+ case VKI_TIOCSPGRP:
+ /* Set a process group ID? */
+ POST_MEM_WRITE( ARG3, sizeof(vki_pid_t) );
+ break;
+ case VKI_TIOCSCTTY:
+ break;
+ case VKI_FIONBIO:
+ break;
+ case VKI_FIOASYNC:
+ break;
+ case VKI_FIONREAD: /* identical to SIOCINQ */
+ POST_MEM_WRITE( ARG3, sizeof(int) );
+ break;
+
+ /* These all use struct ifreq AFAIK */
+ case VKI_SIOCGIFFLAGS: /* get flags */
+ POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_flags,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_flags) );
+ break;
+ case VKI_SIOCGIFMTU: /* get MTU size */
+ POST_MEM_WRITE( (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_mtu,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_mtu) );
+ break;
+ case VKI_SIOCGIFADDR: /* get PA address */
+ case VKI_SIOCGIFDSTADDR: /* get remote PA address */
+ case VKI_SIOCGIFBRDADDR: /* get broadcast PA address */
+ case VKI_SIOCGIFNETMASK: /* get network PA mask */
+ POST_MEM_WRITE(
+ (Addr)&((struct vki_ifreq *)ARG3)->ifr_addr,
+ sizeof(((struct vki_ifreq *)ARG3)->ifr_addr) );
+ break;
+ case VKI_SIOCGIFMETRIC: /* get metric */
+ POST_MEM_WRITE(
+ (Addr)&((struct vki_ifreq *)ARG3)->vki_ifr_metric,
+ sizeof(((struct vki_ifreq *)ARG3)->vki_ifr_metric) );
+ break;
+ case VKI_SIOCGIFCONF: /* get iface list */
+ /* WAS:
+ PRE_MEM_WRITE("ioctl(SIOCGIFCONF)", ARG3, sizeof(struct ifconf));
+ KERNEL_DO_SYSCALL(tid,RES);
+ if (!VG_(is_kerror)(RES) && RES == 0)
+ POST_MEM_WRITE(ARG3, sizeof(struct ifconf));
+ */
+ if (RES == 0 && ARG3 ) {
+ struct vki_ifconf *ifc = (struct vki_ifconf *) ARG3;
+ if (ifc->vki_ifc_buf != NULL)
+ POST_MEM_WRITE( (Addr)(ifc->vki_ifc_buf), ifc->ifc_len );
+ }
+ break;
+
+ case VKI_SIOCSIFFLAGS: /* set flags */
+ case VKI_SIOCSIFDSTADDR: /* set remote PA address */
+ case VKI_SIOCSIFBRDADDR: /* set broadcast PA address */
+ case VKI_SIOCSIFNETMASK: /* set network PA mask */
+ case VKI_SIOCSIFMETRIC: /* set metric */
+ case VKI_SIOCSIFADDR: /* set PA address */
+ case VKI_SIOCSIFMTU: /* set MTU size */
+ break;
+
+#ifdef VKI_SIOCADDRT
+ /* Routing table calls. */
+ case VKI_SIOCADDRT: /* add routing table entry */
+ case VKI_SIOCDELRT: /* delete routing table entry */
+ break;
+#endif
+
+ case VKI_SIOCGPGRP:
+ POST_MEM_WRITE(ARG3, sizeof(int));
+ break;
+ case VKI_SIOCSPGRP:
+ break;
+
+ case VKI_FIODTYPE:
+ POST_MEM_WRITE( ARG3, sizeof(int) );
+ break;
+
+ case VKI_DTRACEHIOC_REMOVE:
+ case VKI_DTRACEHIOC_ADDDOF:
+ break;
+
+ // ttycom.h
+ case VKI_TIOCGETA:
+ POST_MEM_WRITE( ARG3, sizeof(struct vki_termios));
+ break;
+ case VKI_TIOCSETA:
+ break;
+ case VKI_TIOCGETD:
+ POST_MEM_WRITE( ARG3, sizeof(int) );
+ break;
+ case VKI_TIOCSETD:
+ break;
+ case VKI_TIOCPTYGNAME:
+ POST_MEM_WRITE( ARG3, 128);
+ break;
+ case VKI_TIOCPTYGRANT:
+ case VKI_TIOCPTYUNLK:
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/* ---------------------------------------------------------------------
+ darwin fcntl wrapper
+ ------------------------------------------------------------------ */
+static const char *name_for_fcntl(UWord cmd) {
+#define F(n) case VKI_##n: return #n
+ switch (cmd) {
+ F(F_CHKCLEAN);
+ F(F_RDAHEAD);
+ F(F_NOCACHE);
+ F(F_FULLFSYNC);
+ F(F_FREEZE_FS);
+ F(F_THAW_FS);
+ F(F_GLOBAL_NOCACHE);
+ F(F_PREALLOCATE);
+ F(F_SETSIZE);
+ F(F_RDADVISE);
+ F(F_READBOOTSTRAP);
+ F(F_WRITEBOOTSTRAP);
+ F(F_LOG2PHYS);
+ F(F_GETPATH);
+ F(F_PATHPKG_CHECK);
+ F(F_ADDSIGS);
+ default:
+ return "UNKNOWN";
+ }
+#undef F
+}
+
+PRE(sys_fcntl)
+{
+ switch (ARG2) {
+ // These ones ignore ARG3.
+ case VKI_F_GETFD:
+ case VKI_F_GETFL:
+ case VKI_F_GETOWN:
+ PRINT("sys_fcntl ( %ld, %ld )", ARG1,ARG2);
+ PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
+ break;
+
+ // These ones use ARG3 as "arg".
+ case VKI_F_DUPFD:
+ case VKI_F_SETFD:
+ case VKI_F_SETFL:
+ case VKI_F_SETOWN:
+ PRINT("sys_fcntl[ARG3=='arg'] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd, unsigned long, arg);
+ break;
+
+ // These ones use ARG3 as "lock".
+ case VKI_F_GETLK:
+ case VKI_F_SETLK:
+ case VKI_F_SETLKW:
+ PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ struct flock64 *, lock);
+ // GrP fixme mem read sizeof(flock64)
+ if (ARG2 == VKI_F_SETLKW)
+ *flags |= SfMayBlock;
+ break;
+
+ // none
+ case VKI_F_CHKCLEAN:
+ case VKI_F_RDAHEAD:
+ case VKI_F_NOCACHE:
+ case VKI_F_FULLFSYNC:
+ case VKI_F_FREEZE_FS:
+ case VKI_F_THAW_FS:
+ case VKI_F_GLOBAL_NOCACHE:
+ PRINT("sys_fcntl ( %ld, %s )", ARG1, name_for_fcntl(ARG1));
+ PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
+ break;
+
+ // struct fstore
+ case VKI_F_PREALLOCATE:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ struct fstore *, fstore);
+ {
+ struct vki_fstore *fstore = (struct vki_fstore *)ARG3;
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)",
+ fstore->fst_flags );
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)",
+ fstore->fst_posmode );
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)",
+ fstore->fst_offset );
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, fstore->fst_flags)",
+ fstore->fst_length );
+ PRE_FIELD_WRITE( "fcntl(F_PREALLOCATE, fstore->fst_bytesalloc)",
+ fstore->fst_bytesalloc);
+ }
+ break;
+
+ // off_t
+ case VKI_F_SETSIZE:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ vki_off_t *, offset);
+ break;
+
+ // struct radvisory
+ case VKI_F_RDADVISE:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ struct vki_radvisory *, radvisory);
+ {
+ struct vki_radvisory *radvisory = (struct vki_radvisory *)ARG3;
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, radvisory->ra_offset)",
+ radvisory->ra_offset );
+ PRE_FIELD_READ( "fcntl(F_PREALLOCATE, radvisory->ra_count)",
+ radvisory->ra_count );
+ }
+ break;
+
+ // struct fbootstraptransfer
+ case VKI_F_READBOOTSTRAP:
+ case VKI_F_WRITEBOOTSTRAP:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ struct fbootstraptransfer *, bootstrap);
+ PRE_MEM_READ( "fcntl(F_READ/WRITEBOOTSTRAP, bootstrap)",
+ ARG3, sizeof(struct vki_fbootstraptransfer) );
+ break;
+
+ // struct log2phys (out)
+ case VKI_F_LOG2PHYS:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ struct log2phys *, l2p);
+ PRE_MEM_WRITE( "fcntl(F_LOG2PHYS, l2p)",
+ ARG3, sizeof(struct vki_log2phys) );
+ break;
+
+ // char[maxpathlen] (out)
+ case VKI_F_GETPATH:
+ PRINT("sys_fcntl ( %ld, %s, %#lx )", ARG1, name_for_fcntl(ARG2), ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ char *, pathbuf);
+ PRE_MEM_WRITE( "fcntl(F_GETPATH, pathbuf)",
+ ARG3, VKI_MAXPATHLEN );
+ break;
+
+ // char[maxpathlen] (in)
+ case VKI_F_PATHPKG_CHECK:
+ PRINT("sys_fcntl ( %ld, %s, %#lx '%s')", ARG1, name_for_fcntl(ARG2), ARG3,
+ (char *)ARG3);
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ char *, pathbuf);
+ PRE_MEM_RASCIIZ( "fcntl(F_PATHPKG_CHECK, pathbuf)", ARG3);
+ break;
+
+ case VKI_F_ADDSIGS: /* Add detached signatures (for code signing) */
+ PRINT("sys_fcntl ( %ld, %s )", ARG1, name_for_fcntl(ARG2));
+ PRE_REG_READ3(long, "fcntl",
+ unsigned int, fd, unsigned int, cmd,
+ vki_fsignatures_t *, sigs);
+
+ {
+ vki_fsignatures_t *fsigs = (vki_fsignatures_t*)ARG3;
+ PRE_FIELD_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_start)",
+ fsigs->fs_blob_start);
+ PRE_FIELD_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_size)",
+ fsigs->fs_blob_size);
+
+ if (fsigs->fs_blob_start)
+ PRE_MEM_READ( "fcntl(F_ADDSIGS, fsigs->fs_blob_start)",
+ (Addr)fsigs->fs_blob_start, fsigs->fs_blob_size);
+ }
+ break;
+
+ default:
+ PRINT("sys_fcntl ( %ld, %ld [??] )", ARG1, ARG2);
+ VG_(printf)("UNKNOWN fcntl %ld!", ARG2);
+ break;
+ }
+}
+
+POST(sys_fcntl)
+{
+ vg_assert(SUCCESS);
+ switch (ARG2) {
+ case VKI_F_DUPFD:
+ if (!ML_(fd_allowed)(RES, "fcntl(DUPFD)", tid, True)) {
+ VG_(close)(RES);
+ SET_STATUS_Failure( VKI_EMFILE );
+ } else {
+ if (VG_(clo_track_fds))
+ ML_(record_fd_open_named)(tid, RES);
+ }
+ break;
+
+ case VKI_F_GETFD:
+ case VKI_F_GETFL:
+ case VKI_F_GETOWN:
+ case VKI_F_SETFD:
+ case VKI_F_SETFL:
+ case VKI_F_SETOWN:
+ case VKI_F_GETLK:
+ case VKI_F_SETLK:
+ case VKI_F_SETLKW:
+ break;
+
+ case VKI_F_PREALLOCATE:
+ {
+ struct vki_fstore *fstore = (struct vki_fstore *)ARG3;
+ POST_FIELD_WRITE( fstore->fst_bytesalloc );
+ }
+ break;
+
+ case VKI_F_LOG2PHYS:
+ POST_MEM_WRITE( ARG3, sizeof(struct vki_log2phys) );
+ break;
+
+ case VKI_F_GETPATH:
+ POST_MEM_WRITE( ARG3, 1+VG_(strlen)((char *)ARG3) );
+ PRINT("\"%s\"", (char*)ARG3);
+ break;
+
+ default:
+ // DDD: ugh, missing lots of cases here, not nice
+ break;
+ }
+}
+
+// XXX: wrapper only suitable for 32-bit systems
+PRE(sys_fcntl64)
+{
+ switch (ARG2) {
+ // These ones ignore ARG3.
+ case VKI_F_GETFD:
+ case VKI_F_GETFL:
+ case VKI_F_GETOWN:
+ PRINT("sys_fcntl64 ( %ld, %ld )", ARG1,ARG2);
+ PRE_REG_READ2(long, "fcntl64", unsigned int, fd, unsigned int, cmd);
+ break;
+
+ // These ones use ARG3 as "arg".
+ case VKI_F_DUPFD:
+ case VKI_F_SETFD:
+ case VKI_F_SETFL:
+ case VKI_F_SETOWN:
+ PRINT("sys_fcntl64[ARG3=='arg'] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "fcntl64",
+ unsigned int, fd, unsigned int, cmd, unsigned long, arg);
+ break;
+
+ // These ones use ARG3 as "lock".
+ case VKI_F_GETLK:
+ case VKI_F_SETLK:
+ case VKI_F_SETLKW:
+ PRINT("sys_fcntl64[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "fcntl64",
+ unsigned int, fd, unsigned int, cmd,
+ struct flock64 *, lock);
+ if (ARG2 == VKI_F_SETLKW)
+ *flags |= SfMayBlock;
+ break;
+
+ default:
+ I_die_here; // DDD: do something better here
+ break;
+ }
+}
+
+POST(sys_fcntl64)
+{
+ vg_assert(SUCCESS);
+ switch (ARG2) {
+ case VKI_F_DUPFD:
+ if (!ML_(fd_allowed)(RES, "fcntl64(DUPFD)", tid, True)) {
+ VG_(close)(RES);
+ SET_STATUS_Failure( VKI_EMFILE );
+ } else {
+ if (VG_(clo_track_fds))
+ ML_(record_fd_open_named)(tid, RES);
+ }
+ break;
+
+ case VKI_F_GETFD:
+ case VKI_F_GETFL:
+ case VKI_F_GETOWN:
+ case VKI_F_SETFD:
+ case VKI_F_SETFL:
+ case VKI_F_SETOWN:
+ case VKI_F_GETLK:
+ case VKI_F_SETLK:
+ case VKI_F_SETLKW:
+ break;
+
+ default:
+ I_die_here; // DDD: do something better here
+ break;
+ }
+}
+
+/* ---------------------------------------------------------------------
+ unix syscalls
+ ------------------------------------------------------------------ */
+
+PRE(sys_futimes)
+{
+ PRINT("sys_futimes ( %ld, %#lx )", ARG1,ARG2);
+ PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, tvp);
+ if (ARG2 != 0) {
+ PRE_timeval_READ( "futimes(tvp[0])", ARG2 );
+ PRE_timeval_READ( "futimes(tvp[1])", ARG2+sizeof(struct vki_timeval) );
+ }
+}
+
+PRE(sys_semget)
+{
+ PRINT("sys_semget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "semget", vki_key_t, key, int, nsems, int, semflg);
+}
+
+PRE(sys_semop)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_semop ( %ld, %#lx, %lu )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "semop",
+ int, semid, struct sembuf *, sops, vki_size_t, nsoops);
+ ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
+}
+
+PRE(sys_semctl)
+{
+ switch (ARG3) {
+ case VKI_IPC_STAT:
+ case VKI_IPC_SET:
+ PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+ PRE_REG_READ4(long, "semctl",
+ int, semid, int, semnum, int, cmd, struct semid_ds *, arg);
+ break;
+ case VKI_GETALL:
+ case VKI_SETALL:
+ PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+ PRE_REG_READ4(long, "semctl",
+ int, semid, int, semnum, int, cmd, unsigned short *, arg);
+ break;
+ case VKI_SETVAL:
+ PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+ PRE_REG_READ4(long, "semctl",
+ int, semid, int, semnum, int, cmd, int, arg);
+ break;
+ default:
+ PRINT("sys_semctl ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "semctl",
+ int, semid, int, semnum, int, cmd);
+ break;
+ }
+ ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+POST(sys_semctl)
+{
+ ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
+}
+
+PRE(sys_sem_open)
+{
+ if (ARG2 & VKI_O_CREAT) {
+ // 4-arg version
+ PRINT("sys_sem_open ( %#lx(%s), %ld, %ld, %ld )",
+ ARG1,(char*)ARG1,ARG2,ARG3,ARG4);
+ PRE_REG_READ4(vki_sem_t *, "sem_open",
+ const char *, name, int, oflag, vki_mode_t, mode,
+ unsigned int, value);
+ } else {
+ // 2-arg version
+ PRINT("sys_sem_open ( %#lx(%s), %ld )",ARG1,(char*)ARG1,ARG2);
+ PRE_REG_READ2(vki_sem_t *, "sem_open",
+ const char *, name, int, oflag);
+ }
+ PRE_MEM_RASCIIZ( "sem_open(name)", ARG1 );
+
+ /* Otherwise handle normally */
+ *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_close)
+{
+ PRINT("sem_close( %#lx )", ARG1);
+ PRE_REG_READ1(int, "sem_close", vki_sem_t *, sem);
+}
+
+PRE(sys_sem_unlink)
+{
+ PRINT("sem_unlink( %#lx(%s) )", ARG1,(char*)ARG1);
+ PRE_REG_READ1(int, "sem_unlink", const char *, name);
+ PRE_MEM_RASCIIZ( "sem_unlink(name)", ARG1 );
+}
+
+PRE(sys_sem_post)
+{
+ PRINT("sem_post( %#lx )", ARG1);
+ PRE_REG_READ1(int, "sem_post", vki_sem_t *, sem);
+ *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_destroy)
+{
+ PRINT("sem_destroy( %#lx )", ARG1);
+ PRE_REG_READ1(int, "sem_destroy", vki_sem_t *, sem);
+ PRE_MEM_READ("sem_destroy(sem)", ARG1, sizeof(vki_sem_t));
+}
+
+PRE(sys_sem_init)
+{
+ PRINT("sem_init( %#lx, %ld, %ld )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(int, "sem_init", vki_sem_t *, sem,
+ int, pshared, unsigned int, value);
+ PRE_MEM_WRITE("sem_init(sem)", ARG1, sizeof(vki_sem_t));
+}
+
+POST(sys_sem_init)
+{
+ POST_MEM_WRITE(ARG1, sizeof(vki_sem_t));
+}
+
+PRE(sys_sem_wait_nocancel)
+{
+ PRINT("sem_wait_nocancel( %#lx )", ARG1);
+ PRE_REG_READ1(int, "sem_wait_nocancel", vki_sem_t *, sem);
+ *flags |= SfMayBlock;
+}
+
+PRE(sys_sem_trywait)
+{
+ PRINT("sem_trywait( %#lx )", ARG1);
+ PRE_REG_READ1(int, "sem_trywait", vki_sem_t *, sem);
+ *flags |= SfMayBlock;
+}
+
+PRE(sys_kqueue)
+{
+ PRINT("kqueue()");
+}
+
+POST(sys_kqueue)
+{
+ if (!ML_(fd_allowed)(RES, "kqueue", tid, True)) {
+ VG_(close)(RES);
+ SET_STATUS_Failure( VKI_EMFILE );
+ } else {
+ if (VG_(clo_track_fds)) {
+ ML_(record_fd_open_with_given_name)(tid, RES, NULL);
+ }
+ }
+}
+
+PRE(sys_kevent)
+{
+ PRINT("kevent( %ld, %#lx, %ld, %#lx, %ld, %#lx )",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+ PRE_REG_READ6(int,"kevent", int,kq,
+ const struct vki_kevent *,changelist, int,nchanges,
+ struct vki_kevent *,eventlist, int,nevents,
+ const struct vki_timespec *,timeout);
+
+ if (ARG3) PRE_MEM_READ ("kevent(changelist)",
+ ARG2, ARG3 * sizeof(struct vki_kevent));
+ if (ARG5) PRE_MEM_WRITE("kevent(eventlist)",
+ ARG4, ARG5 * sizeof(struct vki_kevent));
+ if (ARG6) PRE_MEM_READ ("kevent(timeout)",
+ ARG6, sizeof(struct vki_timespec));
+
+ *flags |= SfMayBlock;
+}
+
+POST(sys_kevent)
+{
+ PRINT("kevent ret %ld dst %#lx (%zu)", RES, ARG4, sizeof(struct vki_kevent));
+ if (RES > 0) POST_MEM_WRITE(ARG4, RES * sizeof(struct vki_kevent));
+}
+
+
+Addr pthread_starter = 0;
+Addr wqthread_starter = 0;
+SizeT pthread_structsize = 0;
+
+PRE(sys_bsdthread_register)
+{
+ PRINT("bsdthread_register( %#lx, %#lx, %lu )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(int,"__bsdthread_register", void *,"threadstart",
+ void *,"wqthread", size_t,"pthsize");
+
+ pthread_starter = ARG1;
+ wqthread_starter = ARG2;
+ pthread_structsize = ARG3;
+ ARG1 = (Word)&pthread_hijack_asm;
+ ARG2 = (Word)&wqthread_hijack_asm;
+}
+
+PRE(sys_workq_open)
+{
+ PRINT("workq_open()");
+ PRE_REG_READ0(int, "workq_open");
+
+ // This creates lots of threads and thread stacks under the covers,
+ // but we ignore them all until some work item starts running on it.
+}
+
+static const char *workqop_name(int op)
+{
+ switch (op) {
+ case VKI_WQOPS_QUEUE_ADD: return "QUEUE_ADD";
+ case VKI_WQOPS_QUEUE_REMOVE: return "QUEUE_REMOVE";
+ case VKI_WQOPS_THREAD_RETURN: return "THREAD_RETURN";
+ default: return "?";
+ }
+}
+
+
+PRE(sys_workq_ops)
+{
+ PRINT("workq_ops( %ld(%s), %#lx, %ld )", ARG1, workqop_name(ARG1), ARG2,
+ ARG3);
+ PRE_REG_READ3(int,"workq_ops", int,"options", void *,"item",
+ int,"priority");
+
+ switch (ARG1) {
+ case VKI_WQOPS_QUEUE_ADD:
+ case VKI_WQOPS_QUEUE_REMOVE:
+ // GrP fixme need anything here?
+ // GrP fixme may block?
+ break;
+
+ case VKI_WQOPS_THREAD_RETURN: {
+ // The interesting case. The kernel will do one of two things:
+ // 1. Return normally. We continue; libc proceeds to stop the thread.
+ // V does nothing special here.
+ // 2. Jump to wqthread_hijack. This wipes the stack and runs a
+ // new work item, and never returns from workq_ops.
+ // V handles this by longjmp() from wqthread_hijack back to the
+ // scheduler, which continues at the new client SP/IP/state.
+ // This works something like V's signal handling.
+ // To the tool, this looks like workq_ops() sometimes returns
+ // to a strange address.
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ tst->os_state.wq_jmpbuf_valid = True;
+ *flags |= SfMayBlock; // GrP fixme true?
+ break;
+ }
+
+ default:
+ VG_(printf)("UNKNOWN workq_ops option %ld\n", ARG1);
+ break;
+ }
+}
+
+POST(sys_workq_ops)
+{
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ tst->os_state.wq_jmpbuf_valid = False;
+}
+
+
+
+PRE(sys___mac_syscall)
+{
+ PRINT("__mac_syscall( %#lx, %ld, %#lx )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(int,"__mac_syscall", char *,"policy",
+ int,"call", void *,"arg");
+
+ // GrP fixme check call's arg?
+ // GrP fixme check policy?
+}
+
+
+/* Not syswrap-generic's sys_exit, which exits only one thread.
+ More like syswrap-generic's sys_exit_group. */
+PRE(sys_exit)
+{
+ ThreadId t;
+ ThreadState* tst;
+
+ PRINT("darwin exit( %ld )", ARG1);
+ PRE_REG_READ1(void, "exit", int, status);
+
+ tst = VG_(get_ThreadState)(tid);
+
+ /* A little complex; find all the threads with the same threadgroup
+ as this one (including this one), and mark them to exit */
+ for (t = 1; t < VG_N_THREADS; t++) {
+ if ( /* not alive */
+ VG_(threads)[t].status == VgTs_Empty
+ /* GrP fixme zombie? */
+ )
+ continue;
+
+ VG_(threads)[t].exitreason = VgSrc_ExitProcess;
+ VG_(threads)[t].os_state.exitcode = ARG1;
+
+ if (t != tid)
+ VG_(get_thread_out_of_syscall)(t); /* unblock it, if blocked */
+ }
+
+ /* We have to claim the syscall already succeeded. */
+ SET_STATUS_Success(0);
+}
+
+
+PRE(sys_sigaction)
+{
+ PRINT("sys_sigaction ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "sigaction",
+ int, signum, vki_sigaction_toK_t *, act,
+ vki_sigaction_fromK_t *, oldact);
+
+ if (ARG2 != 0) {
+ vki_sigaction_toK_t *sa = (vki_sigaction_toK_t *)ARG2;
+ PRE_MEM_READ( "sigaction(act->sa_handler)",
+ (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
+ PRE_MEM_READ( "sigaction(act->sa_mask)",
+ (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
+ PRE_MEM_READ( "sigaction(act->sa_flags)",
+ (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
+ }
+ if (ARG3 != 0)
+ PRE_MEM_WRITE( "sigaction(oldact)",
+ ARG3, sizeof(vki_sigaction_fromK_t));
+
+ SET_STATUS_from_SysRes(
+ VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t *)ARG2,
+ (vki_sigaction_fromK_t *)ARG3)
+ );
+}
+POST(sys_sigaction)
+{
+ vg_assert(SUCCESS);
+ if (RES == 0 && ARG3 != 0)
+ POST_MEM_WRITE( ARG3, sizeof(vki_sigaction_fromK_t));
+}
+
+
+PRE(sys___pthread_sigmask)
+{
+ // GrP fixme
+ // JRS: arguments are identical to sigprocmask
+ // (how, sigset_t*, sigset_t*). Perhaps behave identically?
+ static Bool warned;
+ if (!warned) {
+ VG_(printf)("UNKNOWN __pthread_sigmask is unsupported. "
+ "This warning will not be repeated.\n");
+ warned = True;
+ }
+ SET_STATUS_Success( 0 );
+}
+
+
+PRE(sys___pthread_canceled)
+{
+ *flags |= SfMayBlock; /* might kill this thread??? */
+ /* I don't think so -- I think it just changes the cancellation
+ state. But taking no chances. */
+ PRINT("__pthread_canceled ( %ld )", ARG1);
+ PRE_REG_READ1(long, "__pthread_canceled", void*, arg1);
+}
+
+
+PRE(sys___pthread_markcancel)
+{
+ *flags |= SfMayBlock; /* might kill this thread??? */
+ PRINT("__pthread_markcancel ( %#lx )", ARG1);
+ PRE_REG_READ1(long, "__pthread_markcancel", void*, arg1);
+ /* Just let it go through. No idea if this is correct. */
+}
+
+
+PRE(sys___disable_threadsignal)
+{
+ vki_sigset_t set;
+ PRINT("__disable_threadsignal(%ld, %ld, %ld)", ARG1, ARG2, ARG3);
+ /* I don't think this really looks at its arguments. So don't
+ bother to check them. */
+
+ VG_(sigfillset)( &set );
+ SET_STATUS_from_SysRes(
+ VG_(do_sys_sigprocmask) ( tid, VKI_SIG_BLOCK, &set, NULL )
+ );
+
+ /* We don't expect that blocking all signals for this thread could
+ cause any more to be delivered (how could it?), but just in case
+ .. */
+ if (SUCCESS)
+ *flags |= SfPollAfter;
+}
+
+
+PRE(sys_kdebug_trace)
+{
+ PRINT("kdebug_trace(%ld, %ld, %ld, %ld, %ld, %ld)",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+ PRE_REG_READ6(long, "kdebug_trace",
+ int,"code", int,"arg1", int,"arg2",
+ int,"arg3", int,"arg4", int,"arg5");
+ // GrP fixme anything else?
+}
+
+
+PRE(sys_seteuid)
+{
+ PRINT("seteuid(%ld)", ARG1);
+ PRE_REG_READ1(long, "seteuid", vki_uid_t, "uid");
+}
+
+
+PRE(sys_setegid)
+{
+ PRINT("setegid(%ld)", ARG1);
+ PRE_REG_READ1(long, "setegid", vki_uid_t, "uid");
+}
+
+PRE(sys_settid)
+{
+ PRINT("settid(%ld, %ld)", ARG1, ARG2);
+ PRE_REG_READ2(long, "settid", vki_uid_t, "uid", vki_gid_t, "gid");
+}
+
+/* XXX need to check whether we need POST operations for
+ * waitevent, watchevent, modwatch -- jpeach
+ */
+PRE(sys_watchevent)
+{
+ PRINT("watchevent(%#lx, %#lx)", ARG1, ARG2);
+ PRE_REG_READ2(long, "watchevent",
+ vki_eventreq *, "event", unsigned int, "eventmask");
+
+ PRE_MEM_READ("watchevent(event)", ARG1, sizeof(vki_eventreq));
+ PRE_MEM_READ("watchevent(eventmask)", ARG2, sizeof(unsigned int));
+ *flags |= SfMayBlock;
+}
+
+#define WAITEVENT_FAST_POLL ((Addr)(struct timeval *)-1)
+PRE(sys_waitevent)
+{
+ PRINT("waitevent(%#lx, %#lx)", ARG1, ARG2);
+ PRE_REG_READ2(long, "waitevent",
+ vki_eventreq *, "event", struct timeval *, "timeout");
+ PRE_MEM_WRITE("waitevent(event)", ARG1, sizeof(vki_eventreq));
+
+ if (ARG2 && ARG2 != WAITEVENT_FAST_POLL) {
+ PRE_timeval_READ("waitevent(timeout)", ARG2);
+ }
+
+ /* XXX ((timeval*)-1) is valid for ARG2 -- jpeach */
+ *flags |= SfMayBlock;
+}
+
+POST(sys_waitevent)
+{
+ POST_MEM_WRITE(ARG1, sizeof(vki_eventreq));
+}
+
+PRE(sys_modwatch)
+{
+ PRINT("modwatch(%#lx, %#lx)", ARG1, ARG2);
+ PRE_REG_READ2(long, "modwatch",
+ vki_eventreq *, "event", unsigned int, "eventmask");
+
+ PRE_MEM_READ("modwatch(event)", ARG1, sizeof(vki_eventreq));
+ PRE_MEM_READ("modwatch(eventmask)", ARG2, sizeof(unsigned int));
+}
+
+PRE(sys_getxattr)
+{
+ PRINT("getxattr(%#lx(%s), %#lx(%s), %#lx, %lu, %lu, %ld)",
+ ARG1, (char *)ARG1, ARG2, (char *)ARG2, ARG3, ARG4, ARG5, ARG6);
+
+ PRE_REG_READ6(vki_ssize_t, "getxattr",
+ const char *, path, char *, name, void *, value,
+ vki_size_t, size, uint32_t, position, int, options);
+ PRE_MEM_RASCIIZ("getxattr(path)", ARG1);
+ PRE_MEM_RASCIIZ("getxattr(name)", ARG2);
+ PRE_MEM_WRITE( "getxattr(value)", ARG3, ARG4);
+}
+
+POST(sys_getxattr)
+{
+ vg_assert((vki_ssize_t)RES >= 0);
+ POST_MEM_WRITE(ARG3, (vki_ssize_t)RES);
+}
+
+PRE(sys_fgetxattr)
+{
+ PRINT("fgetxattr(%ld, %#lx(%s), %#lx, %lu, %lu, %ld)",
+ ARG1, ARG2, (char *)ARG2, ARG3, ARG4, ARG5, ARG6);
+
+ PRE_REG_READ6(vki_ssize_t, "fgetxattr",
+ int, fd, char *, name, void *, value,
+ vki_size_t, size, uint32_t, position, int, options);
+ PRE_MEM_RASCIIZ("getxattr(name)", ARG2);
+ PRE_MEM_WRITE( "getxattr(value)", ARG3, ARG4);
+}
+
+POST(sys_fgetxattr)
+{
+ vg_assert((vki_ssize_t)RES >= 0);
+ POST_MEM_WRITE(ARG3, (vki_ssize_t)RES);
+}
+
+PRE(sys_setxattr)
+{
+ PRINT("setxattr ( %#lx(%s), %#lx(%s), %#lx, %lu, %lu, %ld )",
+ ARG1, (char *)ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5, ARG6 );
+ PRE_REG_READ6(int, "setxattr",
+ const char *,"path", char *,"name", void *,"value",
+ vki_size_t,"size", uint32_t,"position", int,"options" );
+
+ PRE_MEM_RASCIIZ( "setxattr(path)", ARG1 );
+ PRE_MEM_RASCIIZ( "setxattr(name)", ARG2 );
+ PRE_MEM_READ( "setxattr(value)", ARG3, ARG4 );
+}
+
+
+PRE(sys_fsetxattr)
+{
+ PRINT( "fsetxattr ( %ld, %#lx(%s), %#lx, %lu, %lu, %ld )",
+ ARG1, ARG2, (char*)ARG2, ARG3, ARG4, ARG5, ARG6 );
+ PRE_REG_READ6(int, "fsetxattr",
+ int,"fd", char *,"name", void *,"value",
+ vki_size_t,"size", uint32_t,"position", int,"options" );
+
+ PRE_MEM_RASCIIZ( "fsetxattr(name)", ARG2 );
+ PRE_MEM_READ( "fsetxattr(value)", ARG3, ARG4 );
+}
+
+
+PRE(sys_listxattr)
+{
+ PRINT( "listxattr ( %#lx(%s), %#lx, %lu, %ld )",
+ ARG1, (char *)ARG1, ARG2, ARG3, ARG4 );
+ PRE_REG_READ4 (long, "listxattr",
+ const char *,"path", char *,"namebuf",
+ vki_size_t,"size", int,"options" );
+
+ PRE_MEM_RASCIIZ( "listxattr(path)", ARG1 );
+ PRE_MEM_WRITE( "listxattr(namebuf)", ARG2, ARG3 );
+ *flags |= SfMayBlock;
+}
+POST(sys_listxattr)
+{
+ vg_assert(SUCCESS);
+ vg_assert((vki_ssize_t)RES >= 0);
+ POST_MEM_WRITE( ARG2, (vki_ssize_t)RES );
+}
+
+
+PRE(sys_flistxattr)
+{
+ PRINT( "flistxattr ( %ld, %#lx, %lu, %ld )",
+ ARG1, ARG2, ARG3, ARG4 );
+ PRE_REG_READ4 (long, "flistxattr",
+ int, "fd", char *,"namebuf",
+ vki_size_t,"size", int,"options" );
+ PRE_MEM_WRITE( "flistxattr(namebuf)", ARG2, ARG3 );
+ *flags |= SfMayBlock;
+}
+POST(sys_flistxattr)
+{
+ vg_assert(SUCCESS);
+ vg_assert((vki_ssize_t)RES >= 0);
+ POST_MEM_WRITE( ARG2, (vki_ssize_t)RES );
+}
+
+PRE(sys_shmget)
+{
+ PRINT("sys_shmget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "shmget", vki_key_t, key, vki_size_t, size, int, shmflg);
+}
+
+PRE(sys_shm_open)
+{
+ PRINT("shm_open(%#lx(%s), %ld, %ld)", ARG1, (char *)ARG1, ARG2, ARG3);
+ PRE_REG_READ3(long, "shm_open",
+ const char *,"name", int,"flags", vki_mode_t,"mode");
+
+ PRE_MEM_RASCIIZ( "shm_open(filename)", ARG1 );
+
+ *flags |= SfMayBlock;
+}
+
+POST(sys_shm_open)
+{
+ vg_assert(SUCCESS);
+ if (!ML_(fd_allowed)(RES, "shm_open", tid, True)) {
+ VG_(close)(RES);
+ SET_STATUS_Failure( VKI_EMFILE );
+ } else {
+ if (VG_(clo_track_fds))
+ ML_(record_fd_open_with_given_name)(tid, RES, (Char*)ARG1);
+ }
+}
+
+
+PRE(sys_statx)
+{
+ PRINT("statx( %#lx(%s), %#lx, %#lx, %#lx )",
+ ARG1, (char *)ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4(int, "statx", char *, file_name, struct stat *, buf,
+ void *, fsacl, vki_size_t *, fsacl_size);
+ PRE_MEM_RASCIIZ( "statx(file_name)", ARG1 );
+ PRE_MEM_READ( "statx(fsacl_size)", ARG4, sizeof(vki_size_t) );
+ PRE_MEM_WRITE( "statx(buf)", ARG2, sizeof(struct vki_stat) );
+ PRE_MEM_WRITE( "statx(fsacl_size)", ARG4, sizeof(vki_size_t) );
+ PRE_MEM_WRITE( "statx(fsacl)", ARG3, *(vki_size_t *)ARG4 );
+}
+POST(sys_statx)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
+ POST_MEM_WRITE( ARG4, sizeof(vki_size_t) );
+ POST_MEM_WRITE( ARG3, *(vki_size_t *)ARG4 );
+}
+
+
+PRE(sys_fchmod_extended)
+{
+ /* Note: this is not really correct. Handling of
+ sys_chmod_extended is broken in the same way. */
+ PRINT("sys_fchmod_extended ( %ld, %ld, %ld, %ld, %#lx )",
+ ARG1, ARG2, ARG3, ARG4, ARG5);
+ PRE_REG_READ5(long, "fchmod",
+ unsigned int, fildes,
+ uid_t, uid,
+ gid_t, gid,
+ vki_mode_t, mode,
+ void* /*really,user_addr_t*/, xsecurity);
+ /* relative to the xnu sources (kauth_copyinfilesec), this
+ is just way wrong. */
+ PRE_MEM_READ( "fchmod_extended(xsecurity)", ARG5,
+ sizeof(struct kauth_filesec) );
+}
+
+PRE(sys_chmod_extended)
+{
+ /* Note: this is not really correct. Handling of
+ sys_fchmod_extended is broken in the same way. */
+ PRINT("sys_chmod_extended ( %#lx(%s), %ld, %ld, %ld, %#lx )",
+ ARG1, ARG1 ? (HChar*)ARG1 : "(null)", ARG2, ARG3, ARG4, ARG5);
+ PRE_REG_READ5(long, "chmod",
+ unsigned int, fildes,
+ uid_t, uid,
+ gid_t, gid,
+ vki_mode_t, mode,
+ void* /*really,user_addr_t*/, xsecurity);
+ PRE_MEM_RASCIIZ("chmod_extended(path)", ARG1);
+ /* relative to the xnu sources (kauth_copyinfilesec), this
+ is just way wrong. */
+ PRE_MEM_READ( "chmod_extended(xsecurity)", ARG5,
+ sizeof(struct kauth_filesec) );
+}
+
+
+PRE(sys_accessx)
+{
+ // GrP fixme difficult
+}
+
+POST(sys_accessx)
+{
+ // GrP fixme
+}
+
+PRE(sys_chflags)
+{
+ PRINT("sys_chflags ( %#lx(%s), %lu )", ARG1, (char *)ARG1, ARG2);
+ PRE_REG_READ2(int, "chflags", const char *,path, unsigned int,flags);
+ PRE_MEM_RASCIIZ("chflags(path)", ARG1);
+
+ // GrP fixme sanity-check flags value?
+}
+
+PRE(sys_fchflags)
+{
+ PRINT("sys_fchflags ( %ld, %lu )", ARG1, ARG2);
+ PRE_REG_READ2(int, "fchflags", int,fd, unsigned int,flags);
+
+ // GrP fixme sanity-check flags value?
+}
+
+POST(sys_stat64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_stat64)
+{
+ PRINT("sys_stat64 ( %#lx(%s), %#lx )", ARG1, (char *)ARG1, ARG2);
+ PRE_REG_READ2(long, "stat", const char *,path, struct stat64 *,buf);
+ PRE_MEM_RASCIIZ("stat64(path)", ARG1);
+ PRE_MEM_WRITE( "stat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+POST(sys_lstat64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_lstat64)
+{
+ PRINT("sys_lstat64 ( %#lx(%s), %#lx )", ARG1, (char *)ARG1, ARG2);
+ PRE_REG_READ2(long, "stat", const char *,path, struct stat64 *,buf);
+ PRE_MEM_RASCIIZ("lstat64(path)", ARG1);
+ PRE_MEM_WRITE( "lstat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+POST(sys_fstat64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_stat64) );
+}
+
+PRE(sys_fstat64)
+{
+ PRINT("sys_fstat64 ( %ld, %#lx )", ARG1,ARG2);
+ PRE_REG_READ2(long, "fstat", unsigned int, fd, struct stat64 *, buf);
+ PRE_MEM_WRITE( "fstat64(buf)", ARG2, sizeof(struct vki_stat64) );
+}
+
+
+PRE(sys_getfsstat)
+{
+ PRINT("getfsstat(%#lx, %ld, %ld)", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(int, "getfsstat", struct vki_statfs *, buf,
+ int, bufsize, int, flags);
+ if (ARG1) {
+ // ARG2 is a BYTE SIZE
+ PRE_MEM_WRITE("getfsstat", ARG1, ARG2);
+ }
+}
+
+POST(sys_getfsstat)
+{
+ if (ARG1) {
+ // RES is a STRUCT COUNT
+ POST_MEM_WRITE(ARG1, RES * sizeof(struct vki_statfs));
+ }
+}
+
+
+static void scan_attrlist(ThreadId tid, struct vki_attrlist *attrList,
+ void *attrBuf, SizeT attrBufSize,
+ void (*fn)(ThreadId, void *attrData, SizeT size)
+ )
+{
+ typedef struct {
+ uint32_t attrBit;
+ int32_t attrSize;
+ } attrspec;
+ static const attrspec commonattr[] = {
+ // This order is important.
+ { ATTR_CMN_NAME, -1 },
+ { ATTR_CMN_DEVID, sizeof(dev_t) },
+ { ATTR_CMN_FSID, sizeof(fsid_t) },
+ { ATTR_CMN_OBJTYPE, sizeof(fsobj_type_t) },
+ { ATTR_CMN_OBJTAG, sizeof(fsobj_tag_t) },
+ { ATTR_CMN_OBJID, sizeof(fsobj_id_t) },
+ { ATTR_CMN_OBJPERMANENTID, sizeof(fsobj_id_t) },
+ { ATTR_CMN_PAROBJID, sizeof(fsobj_id_t) },
+ { ATTR_CMN_SCRIPT, sizeof(text_encoding_t) },
+ { ATTR_CMN_CRTIME, sizeof(struct timespec) },
+ { ATTR_CMN_MODTIME, sizeof(struct timespec) },
+ { ATTR_CMN_CHGTIME, sizeof(struct timespec) },
+ { ATTR_CMN_ACCTIME, sizeof(struct timespec) },
+ { ATTR_CMN_BKUPTIME, sizeof(struct timespec) },
+ { ATTR_CMN_FNDRINFO, 32 /*FileInfo+ExtendedFileInfo, or FolderInfo+ExtendedFolderInfo*/ },
+ { ATTR_CMN_OWNERID, sizeof(uid_t) },
+ { ATTR_CMN_GRPID, sizeof(gid_t) },
+ { ATTR_CMN_ACCESSMASK, sizeof(uint32_t) },
+ { ATTR_CMN_NAMEDATTRCOUNT, sizeof(uint32_t) },
+ { ATTR_CMN_NAMEDATTRLIST, -1 },
+ { ATTR_CMN_FLAGS, sizeof(uint32_t) },
+ { ATTR_CMN_USERACCESS, sizeof(uint32_t) },
+ { ATTR_CMN_FILEID, sizeof(uint64_t) },
+ { ATTR_CMN_PARENTID, sizeof(uint64_t) },
+ { 0, 0 }
+ };
+ static const attrspec volattr[] = {
+ // This order is important.
+ { ATTR_VOL_INFO, 0 },
+ { ATTR_VOL_FSTYPE, sizeof(uint32_t) },
+ { ATTR_VOL_SIGNATURE, sizeof(uint32_t) },
+ { ATTR_VOL_SIZE, sizeof(off_t) },
+ { ATTR_VOL_SPACEFREE, sizeof(off_t) },
+ { ATTR_VOL_SPACEAVAIL, sizeof(off_t) },
+ { ATTR_VOL_MINALLOCATION, sizeof(off_t) },
+ { ATTR_VOL_ALLOCATIONCLUMP, sizeof(off_t) },
+ { ATTR_VOL_IOBLOCKSIZE, sizeof(uint32_t) },
+ { ATTR_VOL_OBJCOUNT, sizeof(uint32_t) },
+ { ATTR_VOL_FILECOUNT, sizeof(uint32_t) },
+ { ATTR_VOL_DIRCOUNT, sizeof(uint32_t) },
+ { ATTR_VOL_MAXOBJCOUNT, sizeof(uint32_t) },
+ { ATTR_VOL_MOUNTPOINT, -1 },
+ { ATTR_VOL_NAME, -1 },
+ { ATTR_VOL_MOUNTFLAGS, sizeof(uint32_t) },
+ { ATTR_VOL_MOUNTEDDEVICE, -1 },
+ { ATTR_VOL_ENCODINGSUSED, sizeof(uint64_t) },
+ { ATTR_VOL_CAPABILITIES, sizeof(vol_capabilities_attr_t) },
+ { ATTR_VOL_ATTRIBUTES, sizeof(vol_attributes_attr_t) },
+ { 0, 0 }
+ };
+ static const attrspec dirattr[] = {
+ // This order is important.
+ { ATTR_DIR_LINKCOUNT, sizeof(uint32_t) },
+ { ATTR_DIR_ENTRYCOUNT, sizeof(uint32_t) },
+ { ATTR_DIR_MOUNTSTATUS, sizeof(uint32_t) },
+ { 0, 0 }
+ };
+ static const attrspec fileattr[] = {
+ // This order is important.
+ { ATTR_FILE_LINKCOUNT, sizeof(uint32_t) },
+ { ATTR_FILE_TOTALSIZE, sizeof(off_t) },
+ { ATTR_FILE_ALLOCSIZE, sizeof(off_t) },
+ { ATTR_FILE_IOBLOCKSIZE, sizeof(uint32_t) },
+ { ATTR_FILE_CLUMPSIZE, sizeof(uint32_t) },
+ { ATTR_FILE_DEVTYPE, sizeof(uint32_t) },
+ { ATTR_FILE_FILETYPE, sizeof(uint32_t) },
+ { ATTR_FILE_FORKCOUNT, sizeof(uint32_t) },
+ { ATTR_FILE_FORKLIST, -1 },
+ { ATTR_FILE_DATALENGTH, sizeof(off_t) },
+ { ATTR_FILE_DATAALLOCSIZE, sizeof(off_t) },
+ { ATTR_FILE_DATAEXTENTS, sizeof(extentrecord) },
+ { ATTR_FILE_RSRCLENGTH, sizeof(off_t) },
+ { ATTR_FILE_RSRCALLOCSIZE, sizeof(off_t) },
+ { ATTR_FILE_RSRCEXTENTS, sizeof(extentrecord) },
+ { 0, 0 }
+ };
+ static const attrspec forkattr[] = {
+ // This order is important.
+ { ATTR_FORK_TOTALSIZE, sizeof(off_t) },
+ { ATTR_FORK_ALLOCSIZE, sizeof(off_t) },
+ { 0, 0 }
+ };
+
+ static const attrspec *attrdefs[5] = {
+ commonattr, volattr, dirattr, fileattr, forkattr
+ };
+ attrgroup_t a[5];
+ uint8_t *d, *dend;
+ int g, i;
+
+ vg_assert(attrList->bitmapcount == 5);
+ VG_(memcpy)(a, &attrList->commonattr, sizeof(a));
+ d = attrBuf;
+ dend = d + attrBufSize;
+
+ for (g = 0; g < 5; g++) {
+ for (i = 0; attrdefs[g][i].attrBit; i++) {
+ uint32_t bit = attrdefs[g][i].attrBit;
+ int32_t size = attrdefs[g][i].attrSize;
+
+ if (a[g] & bit) {
+ a[g] &= ~bit; // clear bit for error check later
+ if (size == -1) {
+ attrreference_t *ref = (attrreference_t *)d;
+ size = MIN(sizeof(attrreference_t), dend - d);
+ fn(tid, d, size);
+ if (size >= sizeof(attrreference_t) &&
+ d + ref->attr_dataoffset < dend)
+ {
+ fn(tid, d + ref->attr_dataoffset,
+ MIN(ref->attr_length, dend - (d + ref->attr_dataoffset)));
+ }
+ d += size;
+ }
+ else {
+ size = MIN(size, dend - d);
+ fn(tid, d, size);
+ d += size;
+ }
+
+ if ((uintptr_t)d % 4) d += 4 - ((uintptr_t)d % 4);
+ if (d > dend) d = dend;
+ }
+ }
+
+ // Known bits are cleared. Die if any bits are left.
+ if (a[g] != 0) {
+ VG_(message)(Vg_UserMsg, "UNKNOWN attrlist flags %d:0x%x\n", g, a[g]);
+ }
+ }
+}
+
+static void get1attr(ThreadId tid, void *attrData, SizeT attrDataSize)
+{
+ POST_MEM_WRITE((Addr)attrData, attrDataSize);
+}
+
+static void set1attr(ThreadId tid, void *attrData, SizeT attrDataSize)
+{
+ PRE_MEM_READ("setattrlist(attrBuf value)", (Addr)attrData, attrDataSize);
+}
+
+PRE(sys_getattrlist)
+{
+ PRINT("getattrlist(%#lx(%s), %#lx, %#lx, %lu, %lu)",
+ ARG1, (char *)ARG1, ARG2, ARG3, ARG4, ARG5);
+ PRE_REG_READ5(int, "getattrlist",
+ const char *,path, struct vki_attrlist *,attrList,
+ void *,attrBuf, vki_size_t,attrBufSize, unsigned int,options);
+ PRE_MEM_RASCIIZ("getattrlist(path)", ARG1);
+ PRE_MEM_READ("getattrlist(attrList)", ARG2, sizeof(struct vki_attrlist));
+ PRE_MEM_WRITE("getattrlist(attrBuf)", ARG3, ARG4);
+}
+
+POST(sys_getattrlist)
+{
+ if (ARG4 > sizeof(vki_uint32_t)) {
+ // attrBuf is uint32_t bytes written followed by attr data
+ vki_uint32_t *sizep = (vki_uint32_t *)ARG3;
+ POST_MEM_WRITE(ARG3, sizeof(vki_uint32_t));
+ scan_attrlist(tid, (struct vki_attrlist *)ARG2, sizep+1, *sizep, &get1attr);
+ }
+}
+
+
+PRE(sys_setattrlist)
+{
+ PRINT("setattrlist(%#lx(%s), %#lx, %#lx, %lu, %lu)",
+ ARG1, (char *)ARG1, ARG2, ARG3, ARG4, ARG5);
+ PRE_REG_READ5(int, "setattrlist",
+ const char *,path, struct vki_attrlist *,attrList,
+ void *,attrBuf, vki_size_t,attrBufSize, unsigned int,options);
+ PRE_MEM_RASCIIZ("setattrlist(path)", ARG1);
+ PRE_MEM_READ("setattrlist(attrList)", ARG2, sizeof(struct vki_attrlist));
+ scan_attrlist(tid, (struct vki_attrlist *)ARG2, (void*)ARG3, ARG4, &set1attr);
+}
+
+
+PRE(sys_getdirentriesattr)
+{
+ PRINT("getdirentriesattr(%ld, %#lx, %#lx, %ld, %#lx, %#lx, %#lx, %ld)",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8);
+ PRE_REG_READ8(int, "getdirentriesattr",
+ int,fd, struct vki_attrlist *,attrList,
+ void *,attrBuf, size_t,attrBufSize,
+ unsigned int *,count, unsigned int *,basep,
+ unsigned int *,newState, unsigned int,options);
+ PRE_MEM_READ("getdirentriesattr(attrList)",
+ ARG2, sizeof(struct vki_attrlist));
+ PRE_MEM_WRITE("getdirentriesattr(attrBuf)", ARG3, ARG4);
+ PRE_MEM_READ("getdirentriesattr(count)", ARG5, sizeof(unsigned int));
+ PRE_MEM_WRITE("getdirentriesattr(count)", ARG5, sizeof(unsigned int));
+ PRE_MEM_WRITE("getdirentriesattr(basep)", ARG6, sizeof(unsigned int));
+ PRE_MEM_WRITE("getdirentriesattr(newState)", ARG7, sizeof(unsigned int));
+}
+
+POST(sys_getdirentriesattr)
+{
+ char *p, *end;
+ unsigned int count;
+ unsigned int i;
+
+ POST_MEM_WRITE(ARG5, sizeof(unsigned int));
+ POST_MEM_WRITE(ARG6, sizeof(unsigned int));
+ POST_MEM_WRITE(ARG7, sizeof(unsigned int));
+
+ // return buffer is concatenation of variable-size structs
+ count = *(unsigned int *)ARG5;
+ p = (char *)ARG3;
+ end = (char *)ARG3 + ARG4;
+ for (i = 0; i < count; i++) {
+ vg_assert(p < end); // failure is kernel bug or Valgrind bug
+ p += *(unsigned int *)p;
+ }
+
+ POST_MEM_WRITE(ARG3, p - (char *)ARG3);
+
+ PRINT("got %d records, %d/%lu bytes\n", count, p-(char *)ARG3, ARG4);
+}
+
+
+PRE(sys_fsctl)
+{
+ PRINT("fsctl ( %#lx(%s), %ld, %#lx, %ld )",
+ ARG1, (char *)ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4( long, "fsctl",
+ char *,"path", unsigned int,"request",
+ void *,"data", unsigned int,"options");
+
+ PRE_MEM_RASCIIZ( "fsctl(path)", ARG1 );
+
+ switch (ARG2) {
+ case VKI_afpfsByteRangeLock2FSCTL: {
+ struct vki_ByteRangeLockPB2 *pb = (struct vki_ByteRangeLockPB2 *)ARG3;
+ PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->offset)",
+ pb->offset);
+ PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->length)",
+ pb->length);
+ PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->unLockFlag)",
+ pb->unLockFlag);
+ PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->startEndFlag)",
+ pb->startEndFlag);
+ PRE_FIELD_READ("fsctl(afpfsByteRangeLock2, pb->fd)",
+ pb->fd);
+
+ PRE_FIELD_WRITE("fsctl(afpfsByteRangeLock2, pb->retRangeStart)",
+ pb->retRangeStart);
+
+ // GrP fixme check fd
+ break;
+ }
+ case VKI_FSIOC_SYNC_VOLUME:
+ PRE_MEM_READ( "fsctl(FSIOC_SYNC_VOLUME)", ARG3, sizeof(int) );
+ break;
+
+ default:
+ // fsctl requests use ioctl encoding
+ ML_(PRE_unknown_ioctl)(tid, ARG2, ARG3);
+ break;
+ }
+}
+
+POST(sys_fsctl)
+{
+ switch (ARG2) {
+ case VKI_afpfsByteRangeLock2FSCTL: {
+ struct vki_ByteRangeLockPB2 *pb = (struct vki_ByteRangeLockPB2 *)ARG3;
+ POST_FIELD_WRITE(pb->retRangeStart);
+ break;
+ }
+ case VKI_FSIOC_SYNC_VOLUME:
+ break;
+
+ default:
+ // fsctl requests use ioctl encoding
+ ML_(POST_unknown_ioctl)(tid, RES, ARG2, ARG3);
+ break;
+ }
+}
+
+PRE(sys_initgroups)
+{
+ PRINT("sys_initgroups(%s, %#lx, %lu)", (char *)ARG1, ARG2, ARG3);
+ PRE_REG_READ3(long, "initgroups",
+ int, setlen, vki_gid_t *, gidset, vki_uid_t, gmuid);
+ PRE_MEM_READ("gidset", ARG2, ARG1 * sizeof(vki_gid_t));
+}
+
+
+//--------- posix_spawn ---------//
+/* Largely copied from PRE(sys_execve) in syswrap-generic.c, and from
+ the simpler AIX equivalent (syswrap-aix5.c). */
+// Pre_read a char** argument.
+static void pre_argv_envp(Addr a, ThreadId tid, Char* s1, Char* s2)
+{
+ while (True) {
+ Addr a_deref;
+ Addr* a_p = (Addr*)a;
+ PRE_MEM_READ( s1, (Addr)a_p, sizeof(Addr) );
+ a_deref = *a_p;
+ if (0 == a_deref)
+ break;
+ PRE_MEM_RASCIIZ( s2, a_deref );
+ a += sizeof(char*);
+ }
+}
+static SysRes simple_pre_exec_check(const HChar* exe_name)
+{
+ Int fd, ret;
+ SysRes res;
+ Bool setuid_allowed;
+
+ // Check it's readable
+ res = VG_(open)(exe_name, VKI_O_RDONLY, 0);
+ if (sr_isError(res)) {
+ return res;
+ }
+ fd = sr_Res(res);
+ VG_(close)(fd);
+
+ // Check we have execute permissions. We allow setuid executables
+ // to be run only in the case when we are not simulating them, that
+ // is, they to be run natively.
+ setuid_allowed = VG_(clo_trace_children) ? False : True;
+ ret = VG_(check_executable)(NULL/*&is_setuid*/,
+ (HChar*)exe_name, setuid_allowed);
+ if (0 != ret) {
+ return VG_(mk_SysRes_Error)(ret);
+ }
+ return VG_(mk_SysRes_Success)(0);
+}
+PRE(sys_posix_spawn)
+{
+ Char* path = NULL; /* path to executable */
+ Char** envp = NULL;
+ Char** argv = NULL;
+ Char** arg2copy;
+ Char* launcher_basename = NULL;
+ Int i, j, tot_args;
+ SysRes res;
+
+ /* args: pid_t* pid
+ char* path
+ posix_spawn_file_actions_t* file_actions
+ char** argv
+ char** envp
+ */
+ PRINT("sys_posix_spawn( %#lx, %#lx(%s), %#lx, %#lx, %#lx )",
+ ARG1, ARG2, ARG2 ? (HChar*)ARG2 : "(null)", ARG3, ARG4, ARG5 );
+
+ /* Standard pre-syscall checks */
+
+ PRE_REG_READ5(int, "posix_spawn", vki_pid_t*, pid, char*, path,
+ void*, file_actions, char**, argv, char**, envp );
+ PRE_MEM_WRITE("posix_spawn(pid)", ARG1, sizeof(vki_pid_t) );
+ PRE_MEM_RASCIIZ("posix_spawn(path)", ARG2);
+ // DDD: check file_actions
+ if (ARG4 != 0)
+ pre_argv_envp( ARG4, tid, "posix_spawn(argv)",
+ "posix_spawn(argv[i])" );
+ if (ARG5 != 0)
+ pre_argv_envp( ARG5, tid, "posix_spawn(envp)",
+ "posix_spawn(envp[i])" );
+
+ if (0)
+ VG_(printf)("sys_posix_spawn( %#lx, %#lx(%s), %#lx, %#lx, %#lx )\n",
+ ARG1, ARG2, ARG2 ? (HChar*)ARG2 : "(null)", ARG3, ARG4, ARG5 );
+
+ /* Now follows a bunch of logic copied from PRE(sys_execve) in
+ syswrap-generic.c. */
+
+ /* Check that the name at least begins in client-accessible storage. */
+ if (!VG_(am_is_valid_for_client)( ARG2, 1, VKI_PROT_READ )) {
+ SET_STATUS_Failure( VKI_EFAULT );
+ return;
+ }
+
+ // Do the important checks: it is a file, is executable, permissions are
+ // ok, etc. We allow setuid executables to run only in the case when
+ // we are not simulating them, that is, they to be run natively.
+ res = simple_pre_exec_check((const HChar*)ARG2);
+ if (sr_isError(res)) {
+ SET_STATUS_Failure( sr_Err(res) );
+ return;
+ }
+
+ /* If we're tracing the child, and the launcher name looks bogus
+ (possibly because launcher.c couldn't figure it out, see
+ comments therein) then we have no option but to fail. */
+ if (VG_(clo_trace_children)
+ && (VG_(name_of_launcher) == NULL
+ || VG_(name_of_launcher)[0] != '/')) {
+ SET_STATUS_Failure( VKI_ECHILD ); /* "No child processes" */
+ return;
+ }
+
+ /* Ok. So let's give it a try. */
+ VG_(debugLog)(1, "syswrap", "Posix_spawn of %s\n", (Char*)ARG2);
+
+ // Set up the child's exe path.
+ //
+ if (VG_(clo_trace_children)) {
+
+ // We want to exec the launcher. Get its pre-remembered path.
+ path = VG_(name_of_launcher);
+ // VG_(name_of_launcher) should have been acquired by m_main at
+ // startup. The following two assertions should be assured by
+ // the "If we're tracking the child .." test just above here.
+ vg_assert(path);
+ vg_assert(path[0] == '/');
+ launcher_basename = path;
+
+ } else {
+ path = (Char*)ARG2;
+ }
+
+ // Set up the child's environment.
+ //
+ // Remove the valgrind-specific stuff from the environment so the
+ // child doesn't get vgpreload_core.so, vgpreload_<tool>.so, etc.
+ // This is done unconditionally, since if we are tracing the child,
+ // the child valgrind will set up the appropriate client environment.
+ // Nb: we make a copy of the environment before trying to mangle it
+ // as it might be in read-only memory (this was bug #101881).
+ //
+ // Then, if tracing the child, set VALGRIND_LIB for it.
+ //
+ if (ARG5 == 0) {
+ envp = NULL;
+ } else {
+ envp = VG_(env_clone)( (Char**)ARG5 );
+ vg_assert(envp);
+ VG_(env_remove_valgrind_env_stuff)( envp );
+ }
+
+ if (VG_(clo_trace_children)) {
+ // Set VALGRIND_LIB in ARG5 (the environment)
+ VG_(env_setenv)( &envp, VALGRIND_LIB, VG_(libdir));
+ }
+
+ // Set up the child's args. If not tracing it, they are
+ // simply ARG4. Otherwise, they are
+ //
+ // [launcher_basename] ++ VG_(args_for_valgrind) ++ [ARG2] ++ ARG4[1..]
+ //
+ // except that the first VG_(args_for_valgrind_noexecpass) args
+ // are omitted.
+ //
+ if (!VG_(clo_trace_children)) {
+ argv = (Char**)ARG4;
+ } else {
+ vg_assert( VG_(args_for_valgrind) );
+ vg_assert( VG_(args_for_valgrind_noexecpass) >= 0 );
+ vg_assert( VG_(args_for_valgrind_noexecpass)
+ <= VG_(sizeXA)( VG_(args_for_valgrind) ) );
+ /* how many args in total will there be? */
+ // launcher basename
+ tot_args = 1;
+ // V's args
+ tot_args += VG_(sizeXA)( VG_(args_for_valgrind) );
+ tot_args -= VG_(args_for_valgrind_noexecpass);
+ // name of client exe
+ tot_args++;
+ // args for client exe, skipping [0]
+ arg2copy = (Char**)ARG4;
+ if (arg2copy && arg2copy[0]) {
+ for (i = 1; arg2copy[i]; i++)
+ tot_args++;
+ }
+ // allocate
+ argv = VG_(malloc)( "di.syswrap.pre_sys_execve.1",
+ (tot_args+1) * sizeof(HChar*) );
+ vg_assert(argv);
+ // copy
+ j = 0;
+ argv[j++] = launcher_basename;
+ for (i = 0; i < VG_(sizeXA)( VG_(args_for_valgrind) ); i++) {
+ if (i < VG_(args_for_valgrind_noexecpass))
+ continue;
+ argv[j++] = * (HChar**) VG_(indexXA)( VG_(args_for_valgrind), i );
+ }
+ argv[j++] = (Char*)ARG2;
+ if (arg2copy && arg2copy[0])
+ for (i = 1; arg2copy[i]; i++)
+ argv[j++] = arg2copy[i];
+ argv[j++] = NULL;
+ // check
+ vg_assert(j == tot_args+1);
+ }
+
+ /* DDD: sort out the signal state. What signal
+ state does the child inherit from the parent? */
+
+ if (0) {
+ Char **cpp;
+ VG_(printf)("posix_spawn: %s\n", path);
+ for (cpp = argv; cpp && *cpp; cpp++)
+ VG_(printf)("argv: %s\n", *cpp);
+ if (1)
+ for (cpp = envp; cpp && *cpp; cpp++)
+ VG_(printf)("env: %s\n", *cpp);
+ }
+
+ /* Let the call go through as usual. However, we have to poke
+ the altered arguments back into the argument slots. */
+ ARG2 = (UWord)path;
+ ARG4 = (UWord)argv;
+ ARG5 = (UWord)envp;
+
+ /* not to mention .. */
+ *flags |= SfMayBlock;
+}
+POST(sys_posix_spawn)
+{
+ vg_assert(SUCCESS);
+ //POST_MEM_WRITE( ARG1, sizeof(vki_pid_t) );
+}
+
+
+PRE(sys_socket)
+{
+ PRINT("sys_socket ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "socket", int, domain, int, type, int, protocol);
+}
+
+POST(sys_socket)
+{
+ SysRes r;
+ vg_assert(SUCCESS);
+ r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES));
+ SET_STATUS_from_SysRes(r);
+}
+
+
+PRE(sys_setsockopt)
+{
+ PRINT("sys_setsockopt ( %ld, %ld, %ld, %#lx, %ld )",
+ ARG1,ARG2,ARG3,ARG4,ARG5);
+ PRE_REG_READ5(long, "setsockopt",
+ int, s, int, level, int, optname,
+ const void *, optval, vki_socklen_t, optlen);
+ ML_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
+}
+
+
+PRE(sys_getsockopt)
+{
+ Addr optval_p = ARG4;
+ Addr optlen_p = ARG5;
+ PRINT("sys_getsockopt ( %ld, %ld, %ld, %#lx, %#lx )",
+ ARG1,ARG2,ARG3,ARG4,ARG5);
+ PRE_REG_READ5(long, "getsockopt",
+ int, s, int, level, int, optname,
+ void *, optval, vki_socklen_t *, optlen);
+ /* int getsockopt(int socket, int level, int option_name,
+ void *restrict option_value,
+ socklen_t *restrict option_len); */
+ /* vg_assert(sizeof(socklen_t) == sizeof(UInt)); */
+ if (optval_p != (Addr)NULL) {
+ ML_(buf_and_len_pre_check) ( tid, optval_p, optlen_p,
+ "socketcall.getsockopt(optval)",
+ "socketcall.getsockopt(optlen)" );
+ }
+ // DDD: #warning GrP fixme darwin-specific sockopts
+}
+
+POST(sys_getsockopt)
+{
+ Addr optval_p = ARG4;
+ Addr optlen_p = ARG5;
+ vg_assert(SUCCESS);
+ if (optval_p != (Addr)NULL) {
+ ML_(buf_and_len_post_check) ( tid, VG_(mk_SysRes_Success)(RES),
+ optval_p, optlen_p,
+ "socketcall.getsockopt(optlen_out)" );
+ // DDD: #warning GrP fixme darwin-specific sockopts
+ }
+}
+
+
+PRE(sys_connect)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_connect ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "connect",
+ int, sockfd, struct sockaddr *, serv_addr, int, addrlen);
+ ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_accept)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_accept ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "accept",
+ int, s, struct sockaddr *, addr, int, *addrlen);
+ ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_accept)
+{
+ SysRes r;
+ vg_assert(SUCCESS);
+ r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
+ ARG1,ARG2,ARG3);
+ SET_STATUS_from_SysRes(r);
+}
+
+
+PRE(sys_sendto)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_sendto ( %ld, %s, %ld, %lu, %#lx, %ld )",
+ ARG1,(char *)ARG2,ARG3,ARG4,ARG5,ARG6);
+ PRE_REG_READ6(long, "sendto",
+ int, s, const void *, msg, int, len,
+ unsigned int, flags,
+ const struct sockaddr *, to, int, tolen);
+ ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+PRE(sys_sendfile)
+{
+#if VG_WORDSIZE == 4
+ PRINT("sys_sendfile(%ld, %ld, %llu, %#lx, %#lx, %ld)",
+ ARG1, ARG2, LOHI64(ARG3, ARG4), ARG5, ARG6, ARG7);
+
+ PRE_REG_READ7(long, "sendfile",
+ int, fromfd, int, tofd,
+ vki_uint32_t, offset_low32, vki_uint32_t, offset_high32,
+ vki_uint64_t *, nwritten, struct sf_hdtr *, sf_header, int, flags);
+ PRE_MEM_WRITE("sendfile(nwritten)", ARG5, sizeof(vki_uint64_t));
+ if (ARG6) PRE_MEM_WRITE("sendfile(sf_header)", ARG6, sizeof(struct sf_hdtr));
+#else
+ PRINT("sys_sendfile(%ld, %ld, %ld, %#lx, %#lx, %ld)",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+
+ PRE_REG_READ6(long, "sendfile",
+ int, fromfd, int, tofd,
+ vki_uint64_t, offset,
+ vki_uint64_t *, nwritten, struct sf_hdtr *, sf_header, int, flags);
+ PRE_MEM_WRITE("sendfile(nwritten)", ARG4, sizeof(vki_uint64_t));
+ if (ARG5) PRE_MEM_WRITE("sendfile(sf_header)", ARG5, sizeof(struct sf_hdtr));
+#endif
+
+ *flags |= SfMayBlock;
+}
+
+POST(sys_sendfile)
+{
+#if VG_WORDSIZE == 4
+ POST_MEM_WRITE(ARG5, sizeof(vki_uint64_t));
+ if (ARG6) POST_MEM_WRITE(ARG6, sizeof(struct sf_hdtr));
+#else
+ POST_MEM_WRITE(ARG4, sizeof(vki_uint64_t));
+ if (ARG5) POST_MEM_WRITE(ARG5, sizeof(struct sf_hdtr));
+#endif
+}
+
+PRE(sys_recvfrom)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_recvfrom ( %ld, %#lx, %ld, %lu, %#lx, %#lx )",
+ ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+ PRE_REG_READ6(long, "recvfrom",
+ int, s, void *, buf, int, len, unsigned int, flags,
+ struct sockaddr *, from, int *, fromlen);
+ ML_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+POST(sys_recvfrom)
+{
+ vg_assert(SUCCESS);
+ ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES),
+ ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+
+PRE(sys_sendmsg)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_sendmsg ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "sendmsg",
+ int, s, const struct msghdr *, msg, int, flags);
+ ML_(generic_PRE_sys_sendmsg)(tid, ARG1,ARG2);
+}
+
+
+PRE(sys_recvmsg)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_recvmsg ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "recvmsg", int, s, struct msghdr *, msg, int, flags);
+ ML_(generic_PRE_sys_recvmsg)(tid, ARG1,ARG2);
+}
+
+POST(sys_recvmsg)
+{
+ ML_(generic_POST_sys_recvmsg)(tid, ARG1,ARG2);
+}
+
+
+PRE(sys_shutdown)
+{
+ *flags |= SfMayBlock;
+ PRINT("sys_shutdown ( %ld, %ld )",ARG1,ARG2);
+ PRE_REG_READ2(int, "shutdown", int, s, int, how);
+}
+
+
+PRE(sys_bind)
+{
+ PRINT("sys_bind ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "bind",
+ int, sockfd, struct sockaddr *, my_addr, int, addrlen);
+ ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_listen)
+{
+ PRINT("sys_listen ( %ld, %ld )",ARG1,ARG2);
+ PRE_REG_READ2(long, "listen", int, s, int, backlog);
+}
+
+
+PRE(sys_getsockname)
+{
+ PRINT("sys_getsockname ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "getsockname",
+ int, s, struct sockaddr *, name, int *, namelen);
+ ML_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_getsockname)
+{
+ vg_assert(SUCCESS);
+ ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES),
+ ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_getpeername)
+{
+ PRINT("sys_getpeername ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
+ PRE_REG_READ3(long, "getpeername",
+ int, s, struct sockaddr *, name, int *, namelen);
+ ML_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_getpeername)
+{
+ vg_assert(SUCCESS);
+ ML_(generic_POST_sys_getpeername)(tid, VG_(mk_SysRes_Success)(RES),
+ ARG1,ARG2,ARG3);
+}
+
+
+PRE(sys_socketpair)
+{
+ PRINT("sys_socketpair ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
+ PRE_REG_READ4(long, "socketpair",
+ int, d, int, type, int, protocol, int *, sv);
+ ML_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4);
+}
+
+POST(sys_socketpair)
+{
+ vg_assert(SUCCESS);
+ ML_(generic_POST_sys_socketpair)(tid, VG_(mk_SysRes_Success)(RES),
+ ARG1,ARG2,ARG3,ARG4);
+}
+
+
+PRE(sys_gethostuuid)
+{
+ PRINT("sys_gethostuuid ( %#lx, %#lx )", ARG1, ARG2);
+ PRE_REG_READ2(int,"gethostuuid",
+ char *,"uuid_buf",
+ const struct vki_timespec *,"timeout");
+
+ PRE_MEM_WRITE("uuid_buf", ARG1, 16);
+ PRE_MEM_READ("timeout", ARG2, sizeof(struct vki_timespec));
+
+ *flags |= SfMayBlock;
+}
+
+
+POST(sys_gethostuuid)
+{
+ POST_MEM_WRITE(ARG1, 16);
+}
+
+/* Darwin pipe() returns the two descriptors in two registers. */
+PRE(sys_pipe)
+{
+ PRINT("sys_pipe ( )");
+ PRE_REG_READ0(int, "pipe");
+}
+
+POST(sys_pipe)
+{
+ Int p0, p1;
+ vg_assert(SUCCESS);
+ p0 = RES;
+ p1 = RESHI;
+
+ if (!ML_(fd_allowed)(p0, "pipe", tid, True) ||
+ !ML_(fd_allowed)(p1, "pipe", tid, True)) {
+ VG_(close)(p0);
+ VG_(close)(p1);
+ SET_STATUS_Failure( VKI_EMFILE );
+ } else {
+ if (VG_(clo_track_fds)) {
+ ML_(record_fd_open_nameless)(tid, p0);
+ ML_(record_fd_open_nameless)(tid, p1);
+ }
+ }
+}
+
+
+PRE(sys_getlogin)
+{
+ PRINT("getlogin ( %#lx, %ld )", ARG1, ARG2);
+ PRE_REG_READ2(long, "getlogin",
+ char *,"namebuf", unsigned int,"namelen");
+
+ PRE_MEM_WRITE("getlogin(namebuf)", ARG1, ARG2);
+}
+
+POST(sys_getlogin)
+{
+ POST_MEM_WRITE(ARG1, ARG2);
+}
+
+
+PRE(sys_ptrace)
+{
+ PRINT("ptrace ( %ld, %ld, %#lx, %ld )", ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4(long, "ptrace",
+ int,"request", vki_pid_t,"pid",
+ vki_caddr_t,"addr", int,"data");
+
+ // Note: some code uses ptrace(random, 0, 0, 0) as a profiling mechanism.
+
+ // GrP fixme anything needed?
+}
+
+
+PRE(sys_issetugid)
+{
+ PRINT("issetugid ( )");
+ PRE_REG_READ0(long, "issetugid");
+}
+
+
+PRE(sys_getdtablesize)
+{
+ PRINT("getdtablesize ( )");
+ PRE_REG_READ0(long, "getdtablesize");
+}
+
+POST(sys_getdtablesize)
+{
+ // Subtract Valgrind's fd range from client's dtable
+ if (RES > VG_(fd_hard_limit)) SET_STATUS_Success(VG_(fd_hard_limit));
+}
+
+PRE(sys_lseek)
+{
+ PRINT("lseek ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
+ PRE_REG_READ4(vki_off_t, "lseek",
+ unsigned int,fd, int,offset_hi, int,offset_lo,
+ unsigned int,whence);
+}
+
+
+PRE(sys_pathconf)
+{
+ PRINT("pathconf(%#lx(%s), %ld)", ARG1,(char *)ARG1,ARG2);
+ PRE_REG_READ2(long,"pathconf", const char *,"path", int,"name");
+ PRE_MEM_RASCIIZ("pathconf(path)", ARG1);
+}
+
+
+PRE(sys_fpathconf)
+{
+ PRINT("fpathconf(%ld, %ld)", ARG1,ARG2);
+ PRE_REG_READ2(long,"fpathconf", int,"fd", int,"name");
+
+ if (!ML_(fd_allowed)(ARG1, "fpathconf", tid, False))
+ SET_STATUS_Failure( VKI_EBADF );
+}
+
+
+PRE(sys_getdirentries)
+{
+ PRINT("getdirentries(%ld, %#lx, %ld, %#lx)", ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4(int, "getdirentries",
+ int, fd, char *, buf, int, nbytes, long *, basep);
+ PRE_MEM_WRITE("getdirentries(basep)", ARG4, sizeof(long));
+ PRE_MEM_WRITE("getdirentries(buf)", ARG2, ARG3);
+}
+
+POST(sys_getdirentries)
+{
+ POST_MEM_WRITE(ARG4, sizeof(long));
+ // GrP fixme be specific about d_name?
+ POST_MEM_WRITE(ARG2, RES);
+}
+
+
+PRE(sys_getdirentries64)
+{
+ PRINT("getdirentries64(%ld, %#lx, %lu, %#lx)", ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4(vki_ssize_t, "getdirentries",
+ int,fd, char *,buf, vki_size_t,nbytes, vki_off_t *,basep);
+ PRE_MEM_WRITE("getdirentries(position)", ARG4, sizeof(vki_off_t));
+ PRE_MEM_WRITE("getdirentries(buf)", ARG2, ARG3);
+}
+
+POST(sys_getdirentries64)
+{
+ POST_MEM_WRITE(ARG4, sizeof(vki_off_t));
+ // GrP fixme be specific about d_name? (fixme copied from 32 bit version)
+ POST_MEM_WRITE(ARG2, RES);
+}
+
+
+PRE(sys_statfs64)
+{
+ PRINT("sys_statfs64 ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2);
+ PRE_REG_READ2(long, "statfs64", const char *, path, struct statfs64 *, buf);
+ PRE_MEM_RASCIIZ( "statfs64(path)", ARG1 );
+ PRE_MEM_WRITE( "statfs64(buf)", ARG2, sizeof(struct vki_statfs64) );
+}
+
+POST(sys_statfs64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs64) );
+}
+
+
+PRE(sys_fstatfs64)
+{
+ PRINT("sys_fstatfs64 ( %ld, %#lx )",ARG1,ARG2);
+ PRE_REG_READ2(long, "fstatfs64",
+ unsigned int, fd, struct statfs *, buf);
+ PRE_MEM_WRITE( "fstatfs64(buf)", ARG2, sizeof(struct vki_statfs64) );
+}
+
+POST(sys_fstatfs64)
+{
+ POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs64) );
+}
+
+PRE(sys_csops)
+{
+ PRINT("sys_csops ( %ld, %#lx, %#lx, %lu )", ARG1, ARG2, ARG3, ARG4);
+ PRE_REG_READ4(int, "csops",
+ vki_pid_t, pid, uint32_t, ops,
+ void *, useraddr, vki_size_t, usersize);
+
+ PRE_MEM_WRITE( "csops(addr)", ARG3, ARG4 );
+
+ // If the pid is ours, don't mark the program as KILL or HARD
+ // Maybe we should keep track of this for later calls to STATUS
+ if (!ARG1 || VG_(getpid)() == ARG1) {
+ switch (ARG2) {
+ case VKI_CS_OPS_MARKINVALID:
+ case VKI_CS_OPS_MARKHARD:
+ case VKI_CS_OPS_MARKKILL:
+ SET_STATUS_Success(0);
+ }
+ }
+}
+
+POST(sys_csops)
+{
+ POST_MEM_WRITE( ARG3, ARG4 );
+}
+
+PRE(sys_auditon)
+{
+ PRINT("sys_auditon ( %ld, %#lx, %ld )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(int,"auditon",
+ int,"cmd", void*,"data", unsigned int,"length");
+
+ switch (ARG1) {
+
+ case VKI_A_SETPOLICY:
+ case VKI_A_SETKMASK:
+ case VKI_A_SETQCTRL:
+ case VKI_A_SETCOND:
+ case VKI_A_SETCLASS:
+ case VKI_A_SETPMASK:
+ case VKI_A_SETFSIZE:
+ // kernel reads data..data+length
+ PRE_MEM_READ("auditon(data)", ARG2, ARG3);
+ break;
+
+ case VKI_A_GETKMASK:
+ case VKI_A_GETPOLICY:
+ case VKI_A_GETQCTRL:
+ case VKI_A_GETFSIZE:
+ case VKI_A_GETCOND:
+ // kernel writes data..data+length
+ // GrP fixme be precise about what gets written
+ PRE_MEM_WRITE("auditon(data)", ARG2, ARG3);
+ break;
+
+
+ case VKI_A_GETCLASS:
+ case VKI_A_GETPINFO:
+ case VKI_A_GETPINFO_ADDR:
+ // kernel reads and writes data..data+length
+ // GrP fixme be precise about what gets read and written
+ PRE_MEM_READ("auditon(data)", ARG2, ARG3);
+ PRE_MEM_WRITE("auditon(data)", ARG2, ARG3);
+ break;
+
+ case VKI_A_SETKAUDIT:
+ case VKI_A_SETSTAT:
+ case VKI_A_SETUMASK:
+ case VKI_A_SETSMASK:
+ case VKI_A_GETKAUDIT:
+ case VKI_A_GETCWD:
+ case VKI_A_GETCAR:
+ case VKI_A_GETSTAT:
+ // unimplemented on darwin
+ break;
+
+ default:
+ VG_(message)(Vg_UserMsg, "UNKNOWN auditon cmd %ld", ARG1);
+ break;
+ }
+}
+
+POST(sys_auditon)
+{
+ switch (ARG1) {
+
+ case VKI_A_SETPOLICY:
+ case VKI_A_SETKMASK:
+ case VKI_A_SETQCTRL:
+ case VKI_A_SETCOND:
+ case VKI_A_SETCLASS:
+ case VKI_A_SETPMASK:
+ case VKI_A_SETFSIZE:
+ // kernel reads data..data+length
+ break;
+
+ case VKI_A_GETKMASK:
+ case VKI_A_GETPOLICY:
+ case VKI_A_GETQCTRL:
+ case VKI_A_GETFSIZE:
+ case VKI_A_GETCOND:
+ // kernel writes data..data+length
+ // GrP fixme be precise about what gets written
+ POST_MEM_WRITE(ARG2, ARG3);
+ break;
+
+
+ case VKI_A_GETCLASS:
+ case VKI_A_GETPINFO:
+ case VKI_A_GETPINFO_ADDR:
+ // kernel reads and writes data..data+length
+ // GrP fixme be precise about what gets read and written
+ POST_MEM_WRITE(ARG2, ARG3);
+ break;
+
+ case VKI_A_SETKAUDIT:
+ case VKI_A_SETSTAT:
+ case VKI_A_SETUMASK:
+ case VKI_A_SETSMASK:
+ case VKI_A_GETKAUDIT:
+ case VKI_A_GETCWD:
+ case VKI_A_GETCAR:
+ case VKI_A_GETSTAT:
+ // unimplemented on darwin
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+PRE(sys_mmap)
+{
+ // SysRes r;
+
+#if VG_WORDSIZE == 4
+ PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, %lld )",
+ ARG1, ARG2, ARG3, ARG4, ARG5, LOHI64(ARG6, ARG7) );
+ PRE_REG_READ7(Addr, "mmap",
+ Addr,start, vki_size_t,length, int,prot, int,flags, int,fd,
+ unsigned long,offset_hi, unsigned long,offset_lo);
+ // GrP fixme V mmap and kernel mach_msg collided once - don't use
+ // V's mechanism for now
+ // r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5,
+ // (Off64T)LOHI64(ARG6, ARG7) );
+#else
+ PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, %ld )",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+ PRE_REG_READ6(long, "mmap",
+ Addr,start, vki_size_t,length, int,prot, int,flags, int,fd,
+ Off64T,offset);
+ // r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+
+#endif
+
+ // SET_STATUS_from_SysRes(r);
+}
+
+POST(sys_mmap)
+{
+ if (RES != -1) {
+ ML_(notify_core_and_tool_of_mmap)(RES, ARG2, ARG3, ARG4, ARG5, ARG6);
+ // Try to load symbols from the region
+ VG_(di_notify_mmap)( (Addr)RES, False/*allow_SkFileV*/ );
+ }
+}
+
+
+PRE(sys_sysctl)
+{
+ PRINT( "sysctl ( %#lx, %ld, %#lx, %#lx, %#lx, %ld )",
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+
+ PRE_REG_READ6(int, "sysctl", int*, name, unsigned int, namelen,
+ void*, oldp, vki_size_t *, oldlenp,
+ void*, newp, vki_size_t *, newlenp);
+
+ PRE_MEM_READ("sysctl(name)", ARG1, ARG2); // reads name[0..namelen-1]
+ if (ARG4) {
+ // writes *ARG4
+ PRE_MEM_WRITE("sysctl(oldlenp)", ARG4, sizeof(size_t));
+ if (ARG3) {
+ // also reads *ARG4, and writes as much as ARG3[0..ARG4-1]
+ PRE_MEM_READ("sysctl(oldlenp)", ARG4, sizeof(size_t));
+ PRE_MEM_WRITE("sysctl(oldp)", ARG3, *(size_t *)ARG4);
+ }
+ }
+ if (ARG5) {
+ PRE_MEM_READ("sysctl(newp)", ARG5, ARG6);
+ }
+
+ if (VG_(clo_trace_syscalls)) {
+ unsigned int i;
+ int *name = (int *)ARG1;
+ VG_(printf)(" mib: [ ");
+ for (i = 0; i < ARG2; i++) {
+ VG_(printf)("%d ", name[i]);
+ }
+ VG_(printf)("]");
+ }
+
+ // GrP fixme intercept KERN_PROCARGS and KERN_PROC_PID for our pid
+ // (executable path and arguments and environment
+
+ {
+ // Intercept sysctl(kern.usrstack). The kernel's reply would be
+ // Valgrind's stack, not the client's stack.
+ // GrP fixme kern_usrstack64
+ if (ARG1 && ARG2 == 2 &&
+ ((int *)ARG1)[0] == VKI_CTL_KERN &&
+#if VG_WORDSIZE == 4
+ ((int *)ARG1)[1] == VKI_KERN_USRSTACK32
+#else
+ ((int *)ARG1)[1] == VKI_KERN_USRSTACK64
+#endif
+ )
+ {
+ if (ARG5/*newp*/ || ARG6/*newlen*/) {
+ SET_STATUS_Failure(VKI_EPERM); // USRSTACK is read-only
+ } else {
+ Addr *oldp = (Addr *)ARG3;
+ size_t *oldlenp = (size_t *)ARG4;
+ if (oldlenp) {
+ Addr stack_end = VG_(clstk_end)+1;
+ size_t oldlen = *oldlenp;
+ // always return actual size
+ *oldlenp = sizeof(Addr);
+ if (oldp && oldlen >= sizeof(Addr)) {
+ // oldp is big enough
+ // copy value and return 0
+ *oldp = stack_end;
+ SET_STATUS_Success(0);
+ } else {
+ // oldp isn't big enough
+ // copy as much as possible and return ENOMEM
+ if (oldp) VG_(memcpy)(oldp, &stack_end, oldlen);
+ SET_STATUS_Failure(VKI_ENOMEM);
+ }
+ }
+ }
+ }
+ }
+
+ if (!SUCCESS && !FAILURE) {
+ // Don't set SfPostOnFail if we've already handled it locally.
+ *flags |= SfPostOnFail;
+ }
+}
+
+POST(sys_sysctl)
+{
+ if (SUCCESS || ERR == VKI_ENOMEM) {
+ // sysctl can write truncated data and return VKI_ENOMEM
+ if (ARG4) {
+ POST_MEM_WRITE(ARG4, sizeof(size_t));
+ }
+ if (ARG3 && ARG4) {
+ POST_MEM_WRITE(ARG3, *(size_t *)ARG4);
+ }
+ }
+}
+
+
+PRE(sys_sigpending)
+{
+ PRINT( "sys_sigpending ( %#lx )", ARG1 );
+ PRE_REG_READ1(long, "sigpending", vki_sigset_t *, set);
+ PRE_MEM_WRITE( "sigpending(set)", ARG1, sizeof(vki_sigset_t));
+}
+
+POST(sys_sigpending)
+{
+ POST_MEM_WRITE( ARG1, sizeof(vki_sigset_t) ) ;
+}
+
+
+PRE(sys_sigprocmask)
+{
+ UWord arg1;
+ PRINT("sigprocmask ( %ld, %#lx, %#lx )", ARG1, ARG2, ARG3);
+ PRE_REG_READ3(long, "sigprocmask",
+ int, how, vki_sigset_t *, set, vki_sigset_t *, oldset);
+ if (ARG2 != 0)
+ PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
+ if (ARG3 != 0)
+ PRE_MEM_WRITE( "sigprocmask(oldset)", ARG3, sizeof(vki_sigset_t));
+
+ /* Massage ARG1 ('how'). If ARG2 (the new mask) is NULL then the
+ value of 'how' is irrelevant, and it appears that Darwin's libc
+ passes zero, which is not equal to any of
+ SIG_{BLOCK,UNBLOCK,SETMASK}. This causes
+ VG_(do_sys_sigprocmask) to complain, since it checks the 'how'
+ value independently of the other args. Solution: in this case,
+ simply pass a valid (but irrelevant) value for 'how'. */
+ /* Also, in this case the new set is passed to the kernel by
+ reference, not value, as in some other sigmask related Darwin
+ syscalls. */
+ arg1 = ARG1;
+ if (ARG2 == 0 /* the new-set is NULL */
+ && ARG1 != VKI_SIG_BLOCK
+ && ARG1 != VKI_SIG_UNBLOCK && ARG1 != VKI_SIG_SETMASK) {
+ arg1 = VKI_SIG_SETMASK;
+ }
+ SET_STATUS_from_SysRes(
+ VG_(do_sys_sigprocmask) ( tid, arg1, (vki_sigset_t*)ARG2,
+ (vki_sigset_t*)ARG3 )
+ );
+
+ if (SUCCESS)
+ *flags |= SfPollAfter;
+}
+
+POST(sys_sigprocmask)
+{
+ vg_assert(SUCCESS);
+ if (RES == 0 && ARG3 != 0)
+ POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t));
+}
+
+
+PRE(sys_sigsuspend)
+{
+ /* Just hand this off to the kernel. Is that really correct? And
+ shouldn't we at least set SfPollAfter? These questions apply to
+ all the Linux versions too. */
+ /* I think the first arg is the 32-bit signal mask (by value), and
+ the other two args are ignored. */
+ *flags |= SfMayBlock;
+ PRINT("sys_sigsuspend ( mask=0x%08lx )", ARG1 );
+ PRE_REG_READ1(int, "sigsuspend", int, sigmask);
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: formatted messages
+ ------------------------------------------------------------------ */
+
+static size_t desc_size(mach_msg_descriptor_t *desc)
+{
+ switch (desc->type.type) {
+ case MACH_MSG_PORT_DESCRIPTOR: return sizeof(desc->port);
+ case MACH_MSG_OOL_DESCRIPTOR: return sizeof(desc->out_of_line);
+ case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: return sizeof(desc->out_of_line);
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR: return sizeof(desc->ool_ports);
+ default:
+ VG_(printf)("UNKNOWN mach message descriptor %d\n", desc->type.type);
+ return sizeof(desc->type); // guess
+ }
+}
+
+
+static void assign_port_names(mach_msg_ool_ports_descriptor_t *desc,
+ const char *name)
+{
+ mach_msg_size_t i;
+ mach_port_t *ports = (mach_port_t *)desc->address;
+ for (i = 0; i < desc->count; i++) {
+ assign_port_name(ports[i], name);
+ }
+}
+
+
+static void import_complex_message(ThreadId tid, mach_msg_header_t *mh)
+{
+ mach_msg_body_t *body;
+ mach_msg_size_t count, i;
+ uint8_t *p;
+ mach_msg_descriptor_t *desc;
+
+ vg_assert(mh->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+
+ body = (mach_msg_body_t *)(mh+1);
+ count = body->msgh_descriptor_count;
+ p = (uint8_t *)(body+1);
+
+ for (i = 0; i < count; i++) {
+ desc = (mach_msg_descriptor_t *)p;
+ p += desc_size(desc);
+
+ switch (desc->type.type) {
+ case MACH_MSG_PORT_DESCRIPTOR:
+ // single port
+ record_unnamed_port(tid, desc->port.name, -1);
+ record_port_insert_rights(desc->port.name, desc->port.disposition);
+ PRINT("got port %s; ", name_for_port(desc->port.name));
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
+ // out-of-line memory - map it
+ // GrP fixme how is VOLATILE different? do we care?
+ // GrP fixme do other flags tell us anything? assume shared for now
+ // GrP fixme more SF_ flags marking mach_msg memory might be nice
+ // GrP fixme protection
+ if (desc->out_of_line.size > 0) {
+ Addr start = VG_PGROUNDDN((Addr)desc->out_of_line.address);
+ Addr end = VG_PGROUNDUP((Addr)desc->out_of_line.address +
+ (Addr)desc->out_of_line.size);
+ PRINT("got ool mem %p..%#lx; ", desc->out_of_line.address,
+ (Addr)desc->out_of_line.address+desc->out_of_line.size);
+
+ ML_(notify_core_and_tool_of_mmap)(
+ start, end - start, VKI_PROT_READ|VKI_PROT_WRITE,
+ VKI_MAP_PRIVATE, -1, 0);
+ }
+ // GrP fixme mark only un-rounded part as initialized
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ // out-of-line array of ports - map it
+ // GrP fixme see fixmes above
+ PRINT("got %d ool ports %p..%#lx", desc->ool_ports.count, desc->ool_ports.address, (Addr)desc->ool_ports.address+desc->ool_ports.count*sizeof(mach_port_t));
+
+ if (desc->ool_ports.count > 0) {
+ Addr start = VG_PGROUNDDN((Addr)desc->ool_ports.address);
+ Addr end = VG_PGROUNDUP((Addr)desc->ool_ports.address + desc->ool_ports.count * sizeof(mach_port_t));
+ mach_port_t *ports = (mach_port_t *)desc->ool_ports.address;
+
+ ML_(notify_core_and_tool_of_mmap)(
+ start, end - start, VKI_PROT_READ|VKI_PROT_WRITE,
+ VKI_MAP_PRIVATE, -1, 0);
+
+ PRINT(":");
+ for (i = 0; i < desc->ool_ports.count; i++) {
+ record_unnamed_port(tid, ports[i], -1);
+ record_port_insert_rights(ports[i], desc->port.disposition);
+ PRINT(" %s", name_for_port(ports[i]));
+ }
+ }
+ PRINT(";");
+ break;
+
+ default:
+ VG_(printf)("UNKNOWN Mach descriptor type %u!\n", desc->type.type);
+ break;
+ }
+ }
+}
+
+
+static void pre_port_desc_read(ThreadId tid, mach_msg_port_descriptor_t *desc2)
+{
+#pragma pack(4)
+ struct {
+ mach_port_t name;
+ mach_msg_size_t pad1;
+ uint16_t pad2;
+ uint8_t disposition;
+ uint8_t type;
+ } *desc = (void*)desc2;
+#pragma pack()
+
+ PRE_FIELD_READ("msg->desc.port.name", desc->name);
+ PRE_FIELD_READ("msg->desc.port.disposition", desc->disposition);
+ PRE_FIELD_READ("msg->desc.port.type", desc->type);
+}
+
+
+static void pre_ool_desc_read(ThreadId tid, mach_msg_ool_descriptor_t *desc2)
+{
+#pragma pack(4)
+ struct {
+ Addr address;
+#if VG_WORDSIZE != 8
+ mach_msg_size_t size;
+#endif
+ uint8_t deallocate;
+ uint8_t copy;
+ uint8_t pad1;
+ uint8_t type;
+#if VG_WORDSIZE == 8
+ mach_msg_size_t size;
+#endif
+ } *desc = (void*)desc2;
+#pragma pack()
+
+ PRE_FIELD_READ("msg->desc.out_of_line.address", desc->address);
+ PRE_FIELD_READ("msg->desc.out_of_line.size", desc->size);
+ PRE_FIELD_READ("msg->desc.out_of_line.deallocate", desc->deallocate);
+ PRE_FIELD_READ("msg->desc.out_of_line.copy", desc->copy);
+ PRE_FIELD_READ("msg->desc.out_of_line.type", desc->type);
+}
+
+static void pre_oolports_desc_read(ThreadId tid,
+ mach_msg_ool_ports_descriptor_t *desc2)
+{
+#pragma pack(4)
+ struct {
+ Addr address;
+#if VG_WORDSIZE != 8
+ mach_msg_size_t size;
+#endif
+ uint8_t deallocate;
+ uint8_t copy;
+ uint8_t disposition;
+ uint8_t type;
+#if VG_WORDSIZE == 8
+ mach_msg_size_t size;
+#endif
+ } *desc = (void*)desc2;
+#pragma pack()
+
+ PRE_FIELD_READ("msg->desc.ool_ports.address", desc->address);
+ PRE_FIELD_READ("msg->desc.ool_ports.size", desc->size);
+ PRE_FIELD_READ("msg->desc.ool_ports.deallocate", desc->deallocate);
+ PRE_FIELD_READ("msg->desc.ool_ports.copy", desc->copy);
+ PRE_FIELD_READ("msg->desc.ool_ports.disposition", desc->disposition);
+ PRE_FIELD_READ("msg->desc.ool_ports.type", desc->type);
+}
+
+
+// Returns the size of the descriptor area
+// (mach_msg_body_t + any mach_msg_descriptor_t)
+static size_t export_complex_message(ThreadId tid, mach_msg_header_t *mh)
+{
+ mach_msg_body_t *body;
+ mach_msg_size_t count, i;
+ uint8_t *p;
+ mach_msg_descriptor_t *desc;
+
+ vg_assert(mh->msgh_bits & MACH_MSGH_BITS_COMPLEX);
+
+ body = (mach_msg_body_t *)(mh+1);
+ PRE_MEM_READ("msg->msgh_descriptor_count)", (Addr)body, sizeof(*body));
+
+ count = body->msgh_descriptor_count;
+ p = (uint8_t *)(body+1);
+
+ for (i = 0; i < count; i++) {
+ desc = (mach_msg_descriptor_t *)p;
+ p += desc_size(desc);
+
+ switch (desc->type.type) {
+ case MACH_MSG_PORT_DESCRIPTOR:
+ // single port; no memory map effects
+ pre_port_desc_read(tid, &desc->port);
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
+ // out-of-line memory - unmap it if it's marked dealloc
+ // GrP fixme need to remap if message fails?
+ // GrP fixme how is VOLATILE different? do we care?
+ // GrP fixme struct is different for lp64
+ pre_ool_desc_read(tid, &desc->out_of_line);
+
+ if (desc->out_of_line.deallocate && desc->out_of_line.size > 0) {
+ vm_size_t size = desc->out_of_line.size;
+ Addr start = VG_PGROUNDDN((Addr)desc->out_of_line.address);
+ Addr end = VG_PGROUNDUP((Addr)desc->out_of_line.address + size);
+ PRINT("kill ool mem %p..%#lx; ", desc->out_of_line.address,
+ (Addr)desc->out_of_line.address + size);
+ ML_(notify_core_and_tool_of_munmap)(start, end - start);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ // out-of-line array of ports - unmap it if it's marked dealloc
+ // GrP fixme need to remap if message fails?
+ // GrP fixme struct different for lp64
+ pre_oolports_desc_read(tid, &desc->ool_ports);
+
+ if (desc->ool_ports.deallocate && desc->ool_ports.count > 0) {
+ vm_size_t size = desc->ool_ports.count * sizeof(mach_port_t);
+ Addr start = VG_PGROUNDDN((Addr)desc->ool_ports.address);
+ Addr end = VG_PGROUNDUP((Addr)desc->ool_ports.address + size);
+ PRINT("kill ool port array %p..%#lx; ", desc->ool_ports.address,
+ (Addr)desc->ool_ports.address + size);
+ ML_(notify_core_and_tool_of_munmap)(start, end - start);
+ }
+ break;
+ default:
+ VG_(printf)("UNKNOWN Mach descriptor type %u!\n", desc->type.type);
+ break;
+ }
+ }
+
+ return (size_t)((Addr)p - (Addr)body);
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: host-related messages
+ ------------------------------------------------------------------ */
+
+
+POST(host_info)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_type_number_t host_info_outCnt;
+ integer_t host_info_out[14];
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+PRE(host_info)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ host_flavor_t flavor;
+ mach_msg_type_number_t host_info_outCnt;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("host_info(mach_host_self(), flavor %d)", req->flavor);
+
+ AFTER = POST_FN(host_info);
+}
+
+
+POST(host_page_size)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ vm_size_t out_page_size;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ PRINT("page size %u", reply->out_page_size);
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+PRE(host_page_size)
+{
+ PRINT("host_page_size(mach_host_self(), ...)");
+
+ AFTER = POST_FN(host_page_size);
+}
+
+
+POST(host_get_io_master)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t io_master;
+ /* end of the kernel processed data */
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ assign_port_name(reply->io_master.name, "io_master-%p");
+ PRINT("%s", name_for_port(reply->io_master.name));
+}
+
+PRE(host_get_io_master)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ } Request;
+#pragma pack()
+
+ // Request *req = (Request *)ARG1;
+
+ PRINT("host_get_io_master(mach_host_self())");
+
+ AFTER = POST_FN(host_get_io_master);
+}
+
+
+POST(host_get_clock_service)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t clock_serv;
+ /* end of the kernel processed data */
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ assign_port_name(reply->clock_serv.name, "clock-%p");
+ PRINT("%s", name_for_port(reply->clock_serv.name));
+}
+
+PRE(host_get_clock_service)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ clock_id_t clock_id;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("host_get_clock_service(mach_host_self(), %d)", req->clock_id);
+
+ AFTER = POST_FN(host_get_clock_service);
+}
+
+
+PRE(host_request_notification)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t notify_port;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ host_flavor_t notify_type;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ if (MACH_REMOTE == mach_task_self()) {
+ if (req->notify_type == 0) {
+ PRINT("host_request_notification(mach_host_self(), %s, %s)",
+ "HOST_NOTIFY_CALENDAR_CHANGE",
+ name_for_port(req->notify_port.name));
+ } else {
+ PRINT("host_request_notification(mach_host_self(), %d, %s)",
+ req->notify_type,
+ name_for_port(req->notify_port.name));
+ }
+ } else {
+ PRINT("host_request_notification(%s, %d, %s)",
+ name_for_port(MACH_REMOTE),
+ req->notify_type,
+ name_for_port(req->notify_port.name));
+ }
+
+ // GrP fixme only do this on success
+ assign_port_name(req->notify_port.name, "host_notify-%p");
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: messages to a task
+ ------------------------------------------------------------------ */
+
+
+PRE(mach_port_type)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_type(%s, %s, ...)",
+ name_for_port(MACH_REMOTE), name_for_port(req->name));
+
+ AFTER = POST_FN(mach_port_type);
+}
+
+POST(mach_port_type)
+{
+}
+
+
+PRE(mach_port_extract_member)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_name_t pset;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_extract_member(%s, 0x%x, 0x%x)",
+ name_for_port(MACH_REMOTE),
+ req->name, req->pset);
+
+ AFTER = POST_FN(mach_port_extract_member);
+
+ // GrP fixme port tracker?
+}
+
+POST(mach_port_extract_member)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+
+PRE(mach_port_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_right_t right;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_allocate(mach_task_self(), %d, ...)", req->right);
+
+ MACH_ARG(mach_port_allocate.right) = req->right;
+
+ AFTER = POST_FN(mach_port_allocate);
+}
+
+POST(mach_port_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_port_name_t name;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme port tracking is too imprecise
+ // vg_assert(!port_exists(reply->name));
+ record_unnamed_port(tid, reply->name, MACH_ARG(mach_port_allocate.right));
+ PRINT("got port 0x%x", reply->name);
+ } else {
+ VG_(printf)("UNKNOWN inserted port 0x%x into remote task\n", reply->name);
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_port_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_deallocate(%s, %s)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name));
+
+ MACH_ARG(mach_port.port) = req->name;
+
+ AFTER = POST_FN(mach_port_deallocate);
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // Must have cleared SfMayBlock in PRE to prevent race
+ record_port_dealloc(MACH_ARG(mach_port.port));
+ } else {
+ VG_(printf)("UNKNOWN remote port dealloc\n");
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_port_get_refs)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_right_t right;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_get_refs(%s, %s, 0x%x)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->right);
+
+ MACH_ARG(mach_port_mod_refs.port) = req->name;
+ MACH_ARG(mach_port_mod_refs.right) = req->right;
+
+ AFTER = POST_FN(mach_port_get_refs);
+}
+
+POST(mach_port_get_refs)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_port_urefs_t refs;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ PRINT("got refs=%d", reply->refs);
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_port_mod_refs)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_right_t right;
+ mach_port_delta_t delta;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_mod_refs(%s, %s, 0x%x, 0x%x)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->right, req->delta);
+
+ MACH_ARG(mach_port_mod_refs.port) = req->name;
+ MACH_ARG(mach_port_mod_refs.right) = req->right;
+ MACH_ARG(mach_port_mod_refs.delta) = req->delta;
+
+ AFTER = POST_FN(mach_port_mod_refs);
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_mod_refs)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // Must have cleared SfMayBlock in PRE to prevent race
+ record_port_mod_refs(MACH_ARG(mach_port_mod_refs.port),
+ MACH_PORT_TYPE(MACH_ARG(mach_port_mod_refs.right)),
+ MACH_ARG(mach_port_mod_refs.delta));
+ } else {
+ VG_(printf)("UNKNOWN remote port mod refs\n");
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_port_get_set_status)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_get_set_status(%s, %s)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name));
+
+ AFTER = POST_FN(mach_port_get_set_status);
+}
+
+POST(mach_port_get_set_status)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_descriptor_t members;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_msg_type_number_t membersCnt;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ // Reply *reply = (Reply *)ARG1;
+
+ // GrP fixme nothing to do?
+}
+
+
+PRE(mach_port_destroy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_destroy(%s, %s)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name));
+
+ MACH_ARG(mach_port.port) = req->name;
+
+ AFTER = POST_FN(mach_port_destroy);
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(mach_port_destroy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // Must have cleared SfMayBlock in PRE to prevent race
+ record_port_destroy(MACH_ARG(mach_port.port));
+ } else {
+ VG_(printf)("UNKNOWN remote port destroy\n");
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_port_request_notification)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t notify;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_msg_id_t msgid;
+ mach_port_mscount_t sync;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_request_notification(%s, %s, %d, %d, %d, %d, ...)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->msgid, req->sync,
+ req->notify.name, req->notify.disposition);
+
+ AFTER = POST_FN(mach_port_request_notification);
+}
+
+POST(mach_port_request_notification)
+{
+ // GrP fixme port tracker? not sure
+}
+
+
+PRE(mach_port_insert_right)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t poly;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_insert_right(%s, %s, %d, %d)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->poly.name, req->poly.disposition);
+
+ AFTER = POST_FN(mach_port_insert_right);
+
+ if (MACH_REMOTE == mach_task_self()) {
+ // GrP fixme import_complex_message handles everything?
+ // what about export_complex_message for MOVE variants?
+ } else {
+ VG_(printf)("UNKNOWN mach_port_insert_right into remote task!\n");
+ // GrP fixme also may remove rights from this task?
+ }
+
+ // GrP fixme port tracker?
+}
+
+POST(mach_port_insert_right)
+{
+}
+
+
+PRE(mach_port_get_attributes)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_flavor_t flavor;
+ mach_msg_type_number_t port_info_outCnt;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_get_attributes(%s, %s, %d, ..., %d)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->flavor, req->port_info_outCnt);
+
+ AFTER = POST_FN(mach_port_get_attributes);
+}
+
+POST(mach_port_get_attributes)
+{
+}
+
+
+PRE(mach_port_set_attributes)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_flavor_t flavor;
+ mach_msg_type_number_t port_infoCnt;
+ integer_t port_info[10];
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_set_attributes(%s, %s, %d, ..., %d)",
+ name_for_port(MACH_REMOTE),
+ name_for_port(req->name), req->flavor, req->port_infoCnt);
+
+ AFTER = POST_FN(mach_port_set_attributes);
+}
+
+POST(mach_port_set_attributes)
+{
+}
+
+
+PRE(mach_port_insert_member)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_port_name_t name;
+ mach_port_name_t pset;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_port_insert_member(%s, 0x%x, 0x%x)",
+ name_for_port(MACH_REMOTE), req->name, req->pset);
+
+ AFTER = POST_FN(mach_port_insert_member);
+
+ // GrP fixme port tracker?
+}
+
+POST(mach_port_insert_member)
+{
+}
+
+
+PRE(task_get_special_port)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ int which_port;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ switch (req->which_port) {
+ case TASK_KERNEL_PORT:
+ PRINT("task_get_special_port(%s, TASK_KERNEL_PORT)",
+ name_for_port(MACH_REMOTE));
+ break;
+ case TASK_HOST_PORT:
+ PRINT("task_get_special_port(%s, TASK_HOST_PORT)",
+ name_for_port(MACH_REMOTE));
+ break;
+ case TASK_BOOTSTRAP_PORT:
+ PRINT("task_get_special_port(%s, TASK_BOOTSTRAP_PORT)",
+ name_for_port(MACH_REMOTE));
+ break;
+ case TASK_WIRED_LEDGER_PORT:
+ PRINT("task_get_special_port(%s, TASK_WIRED_LEDGER_PORT)",
+ name_for_port(MACH_REMOTE));
+ break;
+ case TASK_PAGED_LEDGER_PORT:
+ PRINT("task_get_special_port(%s, TASK_PAGED_LEDGER_PORT)",
+ name_for_port(MACH_REMOTE));
+ break;
+ default:
+ PRINT("task_get_special_port(%s, %d)",
+ name_for_port(MACH_REMOTE), req->which_port);
+ break;
+ }
+
+ MACH_ARG(task_get_special_port.which_port) = req->which_port;
+
+ AFTER = POST_FN(task_get_special_port);
+}
+
+POST(task_get_special_port)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t special_port;
+ /* end of the kernel processed data */
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ PRINT("got port %#x ", reply->special_port.name);
+
+ switch (MACH_ARG(task_get_special_port.which_port)) {
+ case TASK_BOOTSTRAP_PORT:
+ vg_bootstrap_port = reply->special_port.name;
+ assign_port_name(reply->special_port.name, "bootstrap");
+ break;
+ case TASK_KERNEL_PORT:
+ assign_port_name(reply->special_port.name, "kernel");
+ break;
+ case TASK_HOST_PORT:
+ assign_port_name(reply->special_port.name, "host");
+ break;
+ case TASK_WIRED_LEDGER_PORT:
+ assign_port_name(reply->special_port.name, "wired-ledger");
+ break;
+ case TASK_PAGED_LEDGER_PORT:
+ assign_port_name(reply->special_port.name, "paged-ledger");
+ break;
+ default:
+ assign_port_name(reply->special_port.name, "special-%p");
+ break;
+ }
+
+ PRINT("%s", name_for_port(reply->special_port.name));
+}
+
+
+PRE(semaphore_create)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ int policy;
+ int value;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("semaphore_create(%s, ..., %d, %d)",
+ name_for_port(MACH_REMOTE), req->policy, req->value);
+
+ AFTER = POST_FN(semaphore_create);
+}
+
+POST(semaphore_create)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t semaphore;
+ /* end of the kernel processed data */
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ assign_port_name(reply->semaphore.name, "semaphore-%p");
+ PRINT("%s", name_for_port(reply->semaphore.name));
+}
+
+
+PRE(semaphore_destroy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t semaphore;
+ /* end of the kernel processed data */
+ mach_msg_trailer_t trailer;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("semaphore_destroy(%s, %s)",
+ name_for_port(MACH_REMOTE), name_for_port(req->semaphore.name));
+
+ record_port_destroy(req->semaphore.name);
+
+ AFTER = POST_FN(semaphore_destroy);
+}
+
+POST(semaphore_destroy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+ if (!reply->RetCode) {
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_ports_lookup)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ } Request;
+#pragma pack()
+
+ // Request *req = (Request *)ARG1;
+
+ PRINT("mach_ports_lookup(%s)", name_for_port(MACH_REMOTE));
+
+ AFTER = POST_FN(mach_ports_lookup);
+}
+
+POST(mach_ports_lookup)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_ports_descriptor_t init_port_set;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_msg_type_number_t init_port_setCnt;
+ } Reply;
+#pragma pack()
+
+ // Reply *reply = (Reply *)ARG1;
+}
+
+
+PRE(task_threads)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ } Request;
+#pragma pack()
+
+ // Request *req = (Request *)ARG1;
+
+ PRINT("task_threads(%s)", name_for_port(MACH_REMOTE));
+
+ AFTER = POST_FN(task_threads);
+}
+
+POST(task_threads)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_ports_descriptor_t act_list;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_msg_type_number_t act_listCnt;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (MACH_REMOTE == vg_task_port) {
+ assign_port_names(&reply->act_list, "thread-%p");
+ } else {
+ assign_port_names(&reply->act_list, "remote-thread-%p");
+ }
+}
+
+
+PRE(task_suspend)
+{
+ PRINT("task_suspend(%s)", name_for_port(MACH_REMOTE));
+
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme self-suspend
+ vg_assert(0);
+ } else {
+ // suspend other - no problem
+ }
+
+ AFTER = POST_FN(task_suspend);
+}
+
+POST(task_suspend)
+{
+}
+
+
+PRE(task_resume)
+{
+ PRINT("task_resume(%s)", name_for_port(MACH_REMOTE));
+
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme self-resume
+ vg_assert(0);
+ } else {
+ // resume other - no problem
+ }
+
+ AFTER = POST_FN(task_resume);
+}
+
+POST(task_resume)
+{
+}
+
+
+PRE(vm_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ int flags;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_allocate (%s, at %#x, size %d, flags %#x)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size, req->flags);
+
+ MACH_ARG(vm_allocate.size) = req->size;
+ MACH_ARG(vm_allocate.flags) = req->flags;
+
+ AFTER = POST_FN(vm_allocate);
+}
+
+POST(vm_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ vm_address_t address;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ PRINT("allocated at %#x", reply->address);
+ // requesting 0 bytes returns address 0 with no error
+ if (MACH_ARG(vm_allocate.size)) {
+ ML_(notify_core_and_tool_of_mmap)(
+ reply->address, MACH_ARG(vm_allocate.size),
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_ANON, -1, 0);
+ }
+ } else {
+ PRINT("allocated at %#x in remote task %s", reply->address,
+ name_for_port(MACH_REMOTE));
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_deallocate(%s, at %#x, size %d)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size);
+
+ MACH_ARG(vm_deallocate.address) = req->address;
+ MACH_ARG(vm_deallocate.size) = req->size;
+
+ AFTER = POST_FN(vm_deallocate);
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(vm_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ if (MACH_ARG(vm_deallocate.size)) {
+ Addr start = VG_PGROUNDDN(MACH_ARG(vm_deallocate.address));
+ Addr end = VG_PGROUNDUP(MACH_ARG(vm_deallocate.address) +
+ MACH_ARG(vm_deallocate.size));
+ // Must have cleared SfMayBlock in PRE to prevent race
+ ML_(notify_core_and_tool_of_munmap)(start, end - start);
+ }
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_protect)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ boolean_t set_maximum;
+ vm_prot_t new_protection;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_protect(%s, at %#x, size %d, set_max %d, prot %d)",
+ name_for_port(MACH_REMOTE), req->address, req->size,
+ req->set_maximum, req->new_protection);
+
+ MACH_ARG(vm_protect.address) = req->address;
+ MACH_ARG(vm_protect.size) = req->size;
+ MACH_ARG(vm_protect.set_maximum) = req->set_maximum;
+ MACH_ARG(vm_protect.new_protection) = req->new_protection;
+
+ AFTER = POST_FN(vm_protect);
+}
+
+POST(vm_protect)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ Addr start = VG_PGROUNDDN(MACH_ARG(vm_protect.address));
+ Addr end = VG_PGROUNDUP(MACH_ARG(vm_protect.address) +
+ MACH_ARG(vm_protect.size));
+ UInt prot = MACH_ARG(vm_protect.new_protection);
+ if (MACH_ARG(vm_protect.set_maximum)) {
+ // GrP fixme mprotect max
+ VG_(printf)("UNKNOWN vm_protect set maximum");
+ //VG_(mprotect_max_range)(start, end-start, prot);
+ } else {
+ ML_(notify_core_and_tool_of_mprotect)(start, end-start, prot);
+ }
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_inherit)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ vm_inherit_t new_inheritance;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_inherit(%s, at %#x, size %d, value %d)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size,
+ req->new_inheritance);
+
+ AFTER = POST_FN(vm_inherit);
+}
+
+POST(vm_inherit)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme do something?
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_read)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_read(from %s at %#x size %u)",
+ name_for_port(MACH_REMOTE), req->address, req->size);
+
+ MACH_ARG(vm_read.addr) = req->address;
+ MACH_ARG(vm_read.size) = req->size;
+
+ AFTER = POST_FN(vm_read);
+}
+
+POST(vm_read)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_descriptor_t data;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_msg_type_number_t dataCnt;
+ } Reply;
+#pragma pack()
+
+ // Reply *reply = (Reply *)ARG1;
+
+ if (MACH_REMOTE == vg_task_port) {
+ // vm_read from self
+ // GrP fixme copy initialized state
+ }
+}
+
+
+
+PRE(mach_vm_read)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_read(from %s at 0x%llx size %llu)",
+ name_for_port(MACH_REMOTE), req->address, req->size);
+
+ MACH_ARG(mach_vm_read.addr) = req->address;
+ MACH_ARG(mach_vm_read.size) = req->size;
+
+ AFTER = POST_FN(mach_vm_read);
+}
+
+POST(mach_vm_read)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_ool_descriptor_t data;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_msg_type_number_t dataCnt;
+ } Reply;
+#pragma pack()
+
+ // Reply *reply = (Reply *)ARG1;
+
+ if (MACH_REMOTE == vg_task_port) {
+ // vm_read from self
+ // GrP fixme copy initialized state
+ }
+}
+
+
+PRE(vm_read_overwrite)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ vm_address_t data;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_read_overwrite(from %s at %#x size %u to %#x)",
+ name_for_port(MACH_REMOTE), req->address, req->size, req->data);
+
+ MACH_ARG(vm_read_overwrite.addr) = req->address;
+ MACH_ARG(vm_read_overwrite.size) = req->size;
+ MACH_ARG(vm_read_overwrite.data) = req->data;
+
+ PRE_MEM_WRITE("vm_read_overwrite(data)", req->data, req->size);
+
+ AFTER = POST_FN(vm_read_overwrite);
+}
+
+POST(vm_read_overwrite)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ vm_size_t outsize;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (reply->RetCode) {
+ PRINT("mig return %d", reply->RetCode);
+ } else {
+ PRINT("read %llu bytes", (unsigned long long)reply->outsize);
+ if (MACH_REMOTE == vg_task_port) {
+ // vm_read_overwrite from self
+ // GrP fixme copy initialized state
+ POST_MEM_WRITE(MACH_ARG(vm_read_overwrite.data), reply->outsize);
+ } else {
+ // vm_read_overwrite from remote
+ POST_MEM_WRITE(MACH_ARG(vm_read_overwrite.data), reply->outsize);
+ }
+ }
+}
+
+
+PRE(vm_copy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t source_address;
+ vm_size_t size;
+ vm_address_t dest_address;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_copy(%s, %#x, %d, %#x)",
+ name_for_port(MACH_REMOTE),
+ req->source_address, req->size, req->dest_address);
+
+ MACH_ARG(vm_copy.src) = req->source_address;
+ MACH_ARG(vm_copy.dst) = req->dest_address;
+ MACH_ARG(vm_copy.size) = req->size;
+
+ AFTER = POST_FN(vm_copy);
+}
+
+POST(vm_copy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme set dst's initialization equal to src's
+ // and wipe any symbols or translations in dst
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_map)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t object;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_size_t size;
+ vm_address_t mask;
+ int flags;
+ vm_offset_t offset;
+ boolean_t copy;
+ vm_prot_t cur_protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ // GrP fixme check these
+ PRINT("vm_map(in %s, at %#x, size %d, from %s ...)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size,
+ name_for_port(req->object.name));
+
+ MACH_ARG(vm_map.size) = req->size;
+ MACH_ARG(vm_map.copy) = req->copy;
+ MACH_ARG(vm_map.protection) = (req->cur_protection & req->max_protection);
+
+ AFTER = POST_FN(vm_map);
+}
+
+POST(vm_map)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ vm_address_t address;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ // GrP fixme check src and dest tasks
+ PRINT("mapped at %#x", reply->address);
+ // GrP fixme max prot
+ ML_(notify_core_and_tool_of_mmap)(
+ reply->address, VG_PGROUNDUP(MACH_ARG(vm_map.size)),
+ MACH_ARG(vm_map.protection), VKI_MAP_SHARED, -1, 0);
+ // GrP fixme VKI_MAP_PRIVATE if !copy?
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(vm_remap)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t src_task;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ vm_address_t target_address;
+ vm_size_t size;
+ vm_address_t mask;
+ boolean_t anywhere;
+ vm_address_t src_address;
+ boolean_t copy;
+ vm_inherit_t inheritance;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ // GrP fixme check src and dest tasks
+
+ if (VG_(clo_trace_syscalls)) {
+ mach_port_name_t source_task = req->src_task.name;
+ if (source_task == mach_task_self()) {
+ PRINT("vm_remap(mach_task_self(), "
+ "to %#x size %d, from mach_task_self() at %#x, ...)",
+ req->target_address, req->size, req->src_address);
+ } else {
+ PRINT("vm_remap(mach_task_self(), "
+ "to %#x size %d, from task %u at %#x, ...)",
+ req->target_address, req->size,
+ source_task, req->src_address);
+ }
+ }
+
+ // arg1 is task
+ // vt->syscall_arg2 = req->target_address;
+ MACH_ARG(vm_remap.size) = req->size;
+ // vt->syscall_arg4 = req->copy;
+
+ AFTER = POST_FN(vm_remap);
+}
+
+POST(vm_remap)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ vm_address_t target_address;
+ vm_prot_t cur_protection;
+ vm_prot_t max_protection;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ // GrP fixme check src and dest tasks
+ UInt prot = reply->cur_protection & reply->max_protection;
+ // GrP fixme max prot
+ PRINT("mapped at %#x", reply->target_address);
+ ML_(notify_core_and_tool_of_mmap)(
+ reply->target_address, VG_PGROUNDUP(MACH_ARG(vm_remap.size)),
+ prot, VKI_MAP_SHARED, -1, 0);
+ // GrP fixme VKI_MAP_FIXED if !copy?
+ // GrP fixme copy initialized bits from source to dest if source_task is also mach_task_self
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_make_memory_entry_64)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t parent_entry;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ memory_object_size_t size;
+ memory_object_offset_t offset;
+ vm_prot_t permission;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_make_memory_entry_64(%s, %llu, %llu, %d, ..., %u)",
+ name_for_port(MACH_REMOTE),
+ req->size, req->offset, req->permission, req->parent_entry.type);
+
+ AFTER = POST_FN(mach_make_memory_entry_64);
+}
+
+POST(mach_make_memory_entry_64)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t object;
+ NDR_record_t NDR;
+ memory_object_size_t size;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ assign_port_name(reply->object.name, "memory-%p");
+ PRINT("%s", name_for_port(reply->object.name));
+ }
+}
+
+
+PRE(vm_purgable_control)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ vm_address_t address;
+ vm_purgable_t control;
+ int state;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("vm_purgable_control(%s, %#x, %d, %d)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->control, req->state);
+
+ // GrP fixme verify address?
+
+ AFTER = POST_FN(vm_purgable_control);
+}
+
+POST(vm_purgable_control)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ int state;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_purgable_control)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ vm_purgable_t control;
+ int state;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_purgable_control(%s, 0x%llx, %d, %d)",
+ name_for_port(MACH_REMOTE),
+ (unsigned long long)req->address, req->control, req->state);
+
+ // GrP fixme verify address?
+
+ AFTER = POST_FN(mach_vm_purgable_control);
+}
+
+POST(mach_vm_purgable_control)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ int state;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ int flags;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_allocate (%s, at 0x%llx, size %lld, flags 0x%x)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size, req->flags);
+
+ MACH_ARG(mach_vm_allocate.size) = req->size;
+ MACH_ARG(mach_vm_allocate.flags) = req->flags;
+
+ AFTER = POST_FN(mach_vm_allocate);
+}
+
+POST(mach_vm_allocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_vm_address_t address;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ PRINT("allocated at 0x%llx", reply->address);
+ // requesting 0 bytes returns address 0 with no error
+ if (MACH_ARG(mach_vm_allocate.size)) {
+ ML_(notify_core_and_tool_of_mmap)(
+ reply->address, MACH_ARG(mach_vm_allocate.size),
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_ANON, -1, 0);
+ }
+ } else {
+ PRINT("allocated at 0x%llx in remote task %s", reply->address,
+ name_for_port(MACH_REMOTE));
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_deallocate(%s, at 0x%llx, size %lld)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size);
+
+ MACH_ARG(mach_vm_deallocate.address) = req->address;
+ MACH_ARG(mach_vm_deallocate.size) = req->size;
+
+ AFTER = POST_FN(mach_vm_deallocate);
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(mach_vm_deallocate)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ if (MACH_ARG(mach_vm_deallocate.size)) {
+ Addr start = VG_PGROUNDDN(MACH_ARG(mach_vm_deallocate.address));
+ Addr end = VG_PGROUNDUP(MACH_ARG(mach_vm_deallocate.address) +
+ MACH_ARG(mach_vm_deallocate.size));
+ // Must have cleared SfMayBlock in PRE to prevent race
+ ML_(notify_core_and_tool_of_munmap)(start, end - start);
+ }
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_protect)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ boolean_t set_maximum;
+ vm_prot_t new_protection;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_protect(%s, at 0x%llx, size %lld, set_max %d, prot %d)",
+ name_for_port(MACH_REMOTE), req->address, req->size,
+ req->set_maximum, req->new_protection);
+
+ MACH_ARG(mach_vm_protect.address) = req->address;
+ MACH_ARG(mach_vm_protect.size) = req->size;
+ MACH_ARG(mach_vm_protect.set_maximum) = req->set_maximum;
+ MACH_ARG(mach_vm_protect.new_protection) = req->new_protection;
+
+ AFTER = POST_FN(mach_vm_protect);
+}
+
+POST(mach_vm_protect)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ Addr start = VG_PGROUNDDN(MACH_ARG(mach_vm_protect.address));
+ Addr end = VG_PGROUNDUP(MACH_ARG(mach_vm_protect.address) +
+ MACH_ARG(mach_vm_protect.size));
+ UInt prot = MACH_ARG(mach_vm_protect.new_protection);
+ if (MACH_ARG(mach_vm_protect.set_maximum)) {
+ // DDD: #warning GrP fixme mprotect max
+ //VG_(mprotect_max_range)(start, end-start, prot);
+ } else {
+ ML_(notify_core_and_tool_of_mprotect)(start, end-start, prot);
+ }
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_inherit)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ vm_inherit_t new_inheritance;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_inherit(to %s, at 0x%llx, size %llu, value %u)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size, req->new_inheritance);
+
+ AFTER = POST_FN(mach_vm_inherit);
+}
+
+POST(mach_vm_inherit)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ // no V-visible side effects
+ // GrP fixme except maybe fork/exec
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_copy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t source_address;
+ mach_vm_size_t size;
+ mach_vm_address_t dest_address;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_copy(%s, 0x%llx, %llu, 0x%llx)",
+ name_for_port(MACH_REMOTE),
+ req->source_address, req->size, req->dest_address);
+
+ // arg1 is task
+ // vt->syscall_arg2 = req->source_address;
+ // vt->syscall_arg3 = req->size;
+ // vt->syscall_arg4 = req->dest_address;
+
+ AFTER = POST_FN(mach_vm_copy);
+}
+
+POST(mach_vm_copy)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ if (MACH_REMOTE == vg_task_port) {
+ // GrP fixme set dest's initialization equal to src's
+ // BUT vm_copy allocates no memory
+ }
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_map)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t object;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ mach_vm_address_t mask;
+ int flags;
+ memory_object_offset_t offset;
+ boolean_t copy;
+ vm_prot_t cur_protection;
+ vm_prot_t max_protection;
+ vm_inherit_t inheritance;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ // GrP fixme check these
+ PRINT("mach_vm_map(in %s, at 0x%llx, size %llu, from %s ...)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->size,
+ name_for_port(req->object.name));
+
+ MACH_ARG(mach_vm_map.size) = req->size;
+ MACH_ARG(mach_vm_map.copy) = req->copy;
+ MACH_ARG(mach_vm_map.protection) =
+ (req->cur_protection & req->max_protection);
+
+ AFTER = POST_FN(mach_vm_map);
+}
+
+POST(mach_vm_map)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_vm_address_t address;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ // GrP fixme check src and dest tasks
+ PRINT("mapped at 0x%llx", reply->address);
+ // GrP fixme max prot
+ ML_(notify_core_and_tool_of_mmap)(
+ reply->address, VG_PGROUNDUP(MACH_ARG(mach_vm_map.size)),
+ MACH_ARG(mach_vm_map.protection), VKI_MAP_SHARED, -1, 0);
+ // GrP fixme VKI_MAP_PRIVATE if !copy?
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+PRE(mach_vm_region_recurse)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ mach_vm_address_t address;
+ natural_t nesting_depth;
+ mach_msg_type_number_t infoCnt;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("mach_vm_region_recurse(in %s, at 0x%llx, depth %u, count %u)",
+ name_for_port(MACH_REMOTE),
+ req->address, req->nesting_depth, req->infoCnt);
+
+ AFTER = POST_FN(mach_vm_region_recurse);
+}
+
+POST(mach_vm_region_recurse)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_vm_address_t address;
+ mach_vm_size_t size;
+ natural_t nesting_depth;
+ mach_msg_type_number_t infoCnt;
+ int info[19];
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (!reply->RetCode) {
+ PRINT("got region at 0x%llx, size %llu, depth %u, count %u",
+ reply->address, reply->size,
+ reply->nesting_depth, reply->infoCnt);
+ // GrP fixme mark info contents beyond infoCnt as bogus
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: messages to thread
+ ------------------------------------------------------------------ */
+
+
+
+POST(thread_terminate)
+{
+}
+
+
+PRE(thread_terminate)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+ Bool self_terminate = (mh->msgh_request_port == MACH_THREAD);
+
+ PRINT("thread_terminate(%s)", name_for_port(mh->msgh_request_port));
+
+ AFTER = POST_FN(thread_terminate);
+
+ if (self_terminate) {
+ // Terminating this thread.
+ // Copied from sys_exit.
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ tst->exitreason = VgSrc_ExitThread;
+ tst->os_state.exitcode = 0; // GrP fixme anything better?
+ // What we would like to do is:
+ // SET_STATUS_Success(0);
+ // but that doesn't work, because this is a MACH-class syscall,
+ // and SET_STATUS_Success creates a UNIX-class syscall result.
+ // Hence we have to laboriously construct the full SysRes "by hand"
+ // and use that to set the syscall return status.
+ SET_STATUS_from_SysRes(
+ VG_(mk_SysRes_x86_darwin)(
+ VG_DARWIN_SYSCALL_CLASS_MACH,
+ False/*success*/, 0, 0
+ )
+ );
+ *flags &= ~SfMayBlock; // clear flag set by PRE(mach_msg)
+ } else {
+ // Terminating some other thread.
+ // Do keep the scheduler lock while terminating any other thread.
+ // Otherwise we might halt the other thread while it holds the lock,
+ // which would deadlock the process.
+ // GrP fixme good enough?
+ // GrP fixme need to clean up other thread's valgrind data?
+ }
+}
+
+
+POST(thread_create)
+{
+}
+
+
+PRE(thread_create)
+{
+ PRINT("thread_create(mach_task_self(), ...)");
+
+ AFTER = POST_FN(thread_create);
+
+ // GrP fixme
+ VG_(core_panic)("thread_create() unimplemented");
+}
+
+
+PRE(thread_create_running)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t new_stateCnt;
+ natural_t new_state[144];
+ } Request;
+#pragma pack()
+
+ Request *req;
+ thread_state_t regs;
+ ThreadState *new_thread;
+
+ PRINT("thread_create_running(mach_task_self(), ...)");
+
+ // The new thread will immediately begin execution,
+ // so we need to hijack the register state here.
+
+ req = (Request *)ARG1;
+ regs = (thread_state_t)req->new_state;
+
+ // Build virtual thread.
+ new_thread = build_thread(regs, req->flavor, req->new_stateCnt);
+
+ // Edit the thread state to send to the real kernel.
+ hijack_thread_state(regs, req->flavor, req->new_stateCnt, new_thread);
+
+ AFTER = POST_FN(thread_create_running);
+}
+
+
+POST(thread_create_running)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t child_act;
+ /* end of the kernel processed data */
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ assign_port_name(reply->child_act.name, "thread-%p");
+ PRINT("%s", name_for_port(reply->child_act.name));
+}
+
+
+PRE(sys_bsdthread_create)
+{
+ ThreadState *tst;
+
+ PRINT("bsdthread_create( %#lx, %#lx, %#lx, %#lx, %#lx )",
+ ARG1, ARG2, ARG3, ARG4, ARG5);
+ PRE_REG_READ5(pthread_t,"bsdthread_create",
+ void *,"func", void *,"func_arg", void *,"stack",
+ pthread_t,"thread", unsigned int,"flags");
+
+ // The kernel will call V's pthread_hijack() to launch the thread.
+ // Here we allocate the thread state and pass it to pthread_hijack()
+ // via the func_arg parameter.
+
+ tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
+ allocstack(tst->tid);
+
+ tst->os_state.func_arg = (Addr)ARG2;
+ ARG2 = (Word)tst;
+
+ // Create a semaphore that pthread_hijack will signal once it starts
+ // POST(sys_bsdthread_create) needs to wait for the new memory map to appear
+ semaphore_create(mach_task_self(), &tst->os_state.child_go,
+ SYNC_POLICY_FIFO, 0);
+ semaphore_create(mach_task_self(), &tst->os_state.child_done,
+ SYNC_POLICY_FIFO, 0);
+}
+
+POST(sys_bsdthread_create)
+{
+ // Tell new thread's pthread_hijack to proceed, and wait for it to finish.
+ // We hold V's lock on the child's behalf.
+ // If we return before letting pthread_hijack do its thing, V thinks
+ // the new pthread struct is still unmapped when we return to libc,
+ // causing false errors.
+
+ ThreadState *tst = (ThreadState *)ARG2;
+ semaphore_signal(tst->os_state.child_go);
+ semaphore_wait(tst->os_state.child_done);
+ semaphore_destroy(mach_task_self(), tst->os_state.child_go);
+ semaphore_destroy(mach_task_self(), tst->os_state.child_done);
+
+ // GrP fixme semaphore destroy needed when thread creation fails
+ // GrP fixme probably other cleanup too
+
+ // DDD: I'm not at all sure this is the right spot for this. It probably
+ // should be in pthread_hijack instead, just before the call to
+ // start_thread_NORETURN(), call_on_new_stack_0_1(), but we don't have the
+ // parent tid value there...
+ VG_TRACK ( pre_thread_ll_create, tid, tst->tid );
+}
+
+
+PRE(sys_bsdthread_terminate)
+{
+ ThreadState *tst;
+
+ PRINT("bsdthread_terminate( %#lx, %lx, %s, %s )",
+ ARG1, ARG2, name_for_port(ARG3), name_for_port(ARG4));
+ PRE_REG_READ4(int,"bsdthread_terminate",
+ void *,"freeaddr", size_t,"freesize",
+ mach_port_t,"kport", mach_port_t,"joinsem");
+
+ // Free memory and signal semaphore.
+ // GrP fixme errors?
+ if (ARG4) semaphore_signal((semaphore_t)ARG4);
+ if (ARG1 && ARG2) {
+ ML_(notify_core_and_tool_of_munmap)(ARG1, ARG2);
+ vm_deallocate(mach_task_self(), (vm_address_t)ARG1, (vm_size_t)ARG2);
+ }
+
+ // Tell V to terminate the thread.
+ // Copied from sys_exit.
+ tst = VG_(get_ThreadState)(tid);
+ tst->exitreason = VgSrc_ExitThread;
+ tst->os_state.exitcode = 0; // GrP fixme anything better?
+ SET_STATUS_Success(0);
+}
+
+
+POST(thread_suspend)
+{
+}
+
+PRE(thread_suspend)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+ Bool self_suspend = (mh->msgh_request_port == MACH_THREAD);
+
+ PRINT("thread_suspend(%s)", name_for_port(mh->msgh_request_port));
+
+ AFTER = POST_FN(thread_suspend);
+
+ if (self_suspend) {
+ // Don't keep the scheduler lock while self-suspending.
+ // Otherwise we might halt while still holding the lock,
+ // which would deadlock the process.
+ *flags |= SfMayBlock;
+ } else {
+ // Do keep the scheduler lock while suspending any other thread.
+ // Otherwise we might halt the other thread while it holds the lock,
+ // which would deadlock the process.
+ }
+}
+
+
+POST(thread_get_state)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_type_number_t old_stateCnt;
+ natural_t old_state[144];
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+ // mach_port_t thread = MACH_ARG(thread_get_state.thread);
+ thread_state_flavor_t flavor = MACH_ARG(thread_get_state.flavor);
+
+ if (!reply->RetCode) {
+ thread_state_from_vex((thread_state_t)reply->old_state,
+ flavor, reply->old_stateCnt,
+ &VG_(get_ThreadState)(tid)->arch.vex);
+ } else {
+ PRINT("mig return %d", reply->RetCode);
+ }
+}
+
+PRE(thread_get_state)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t old_stateCnt;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+ // Bool self = (req->Head.msgh_request_port == MACH_THREAD);
+
+ // GrP fixme if (self) {
+ PRINT("thread_get_state(%s, %d)",
+ name_for_port(req->Head.msgh_request_port), req->flavor);
+ /*} else {
+ PRINT("thread_get_state(0x%x, %d)",
+ req->Head.msgh_request_port, req->flavor);
+ }*/
+
+ // Hack the thread state after making the real call.
+ MACH_ARG(thread_get_state.thread) = req->Head.msgh_request_port;
+ MACH_ARG(thread_get_state.flavor) = req->flavor;
+
+ AFTER = POST_FN(thread_get_state);
+}
+
+
+POST(thread_policy)
+{
+}
+
+PRE(thread_policy)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+ // Bool self = (mh->msgh_request_port == MACH_THREAD);
+
+ // GrP fixme if (self) {
+ PRINT("thread_policy(%s, ...)", name_for_port(mh->msgh_request_port));
+ /*} else {
+ PRINT("thread_policy(thread 0x%x, ...)", mh->msgh_request_port);
+ }*/
+
+ AFTER = POST_FN(thread_policy);
+}
+
+
+PRE(thread_info)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ PRINT("thread_info(%s, ...)", name_for_port(mh->msgh_request_port));
+ // GrP fixme does any thread info need to be hijacked?
+
+ AFTER = POST_FN(thread_info);
+}
+
+POST(thread_info)
+{
+ // GrP fixme mark unused parts of thread_info_out as uninitialized?
+}
+
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: messages to bootstrap port
+ ------------------------------------------------------------------ */
+
+
+POST(bootstrap_register)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ kern_return_t RetCode;
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if (reply->RetCode) PRINT("mig return %d", reply->RetCode);
+}
+
+PRE(bootstrap_register)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t service_port;
+ /* end of the kernel processed data */
+ NDR_record_t NDR;
+ name_t service_name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("bootstrap_register(port 0x%x, \"%s\")",
+ req->service_port.name, req->service_name);
+
+ assign_port_name(req->service_port.name, req->service_name);
+
+ AFTER = POST_FN(bootstrap_register);
+}
+
+
+POST(bootstrap_look_up)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ /* start of the kernel processed data */
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t service_port;
+ /* end of the kernel processed data */
+ mach_msg_trailer_t trailer;
+ } Reply;
+#pragma pack()
+
+ Reply *reply = (Reply *)ARG1;
+
+ if ((reply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&
+ reply->service_port.name)
+ {
+ assign_port_name(reply->service_port.name,
+ MACH_ARG(bootstrap_look_up.service_name));
+ PRINT("%s", name_for_port(reply->service_port.name));
+ } else {
+ PRINT("not found");
+ }
+ VG_(arena_free)(VG_AR_CORE, MACH_ARG(bootstrap_look_up.service_name));
+}
+
+PRE(bootstrap_look_up)
+{
+#pragma pack(4)
+ typedef struct {
+ mach_msg_header_t Head;
+ NDR_record_t NDR;
+ name_t service_name;
+ } Request;
+#pragma pack()
+
+ Request *req = (Request *)ARG1;
+
+ PRINT("bootstrap_look_up(\"%s\")", req->service_name);
+
+ MACH_ARG(bootstrap_look_up.service_name) =
+ VG_(arena_strdup)(VG_AR_CORE, "syswrap-darwin.bootstrap-name",
+ req->service_name);
+
+ AFTER = POST_FN(bootstrap_look_up);
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: receiver-specific handlers
+ ------------------------------------------------------------------ */
+
+
+POST(mach_msg_receive)
+{
+ // mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ // GrP fixme don't know of anything interesting here currently
+ // import_complex_message handles everything
+ // PRINT("UNHANDLED reply %d", mh->msgh_id);
+
+ // Assume the call may have mapped or unmapped memory
+ sync_mappings("after", "mach_msg_receive", 0);
+}
+
+PRE(mach_msg_receive)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ PRINT("mach_msg_receive(port %s)", name_for_port(mh->msgh_reply_port));
+
+ AFTER = POST_FN(mach_msg_receive);
+
+ // no message sent, only listening for a reply
+ // assume message may block
+ *flags |= SfMayBlock;
+}
+
+
+PRE(mach_msg_bootstrap)
+{
+ // message to bootstrap port
+
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ switch (mh->msgh_id) {
+ case 403:
+ CALL_PRE(bootstrap_register);
+ return;
+ case 404:
+ CALL_PRE(bootstrap_look_up);
+ return;
+
+ default:
+ PRINT("UNHANDLED bootstrap message [id %d, to %s, reply 0x%x]\n",
+ mh->msgh_id, name_for_port(mh->msgh_request_port),
+ mh->msgh_reply_port);
+ return;
+ }
+}
+
+
+PRE(mach_msg_host)
+{
+ // message to host self - check for host-level kernel calls
+
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ switch (mh->msgh_id) {
+ case 200:
+ CALL_PRE(host_info);
+ return;
+ case 202:
+ CALL_PRE(host_page_size);
+ return;
+ case 205:
+ CALL_PRE(host_get_io_master);
+ return;
+ case 206:
+ CALL_PRE(host_get_clock_service);
+ return;
+ case 217:
+ CALL_PRE(host_request_notification);
+ return;
+
+ default:
+ // unknown message to host self
+ VG_(printf)("UNKNOWN host message [id %d, to %s, reply 0x%x]\n",
+ mh->msgh_id, name_for_port(mh->msgh_request_port),
+ mh->msgh_reply_port);
+ return;
+ }
+}
+
+PRE(mach_msg_task)
+{
+ // message to a task port
+
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ switch (mh->msgh_id) {
+ case 3201:
+ CALL_PRE(mach_port_type);
+ return;
+ case 3204:
+ CALL_PRE(mach_port_allocate);
+ return;
+ case 3205:
+ CALL_PRE(mach_port_destroy);
+ return;
+ case 3206:
+ CALL_PRE(mach_port_deallocate);
+ return;
+ case 3207:
+ CALL_PRE(mach_port_get_refs);
+ return;
+ case 3208:
+ CALL_PRE(mach_port_mod_refs);
+ return;
+ case 3211:
+ CALL_PRE(mach_port_get_set_status);
+ return;
+ case 3213:
+ CALL_PRE(mach_port_request_notification);
+ return;
+ case 3214:
+ CALL_PRE(mach_port_insert_right);
+ return;
+ case 3217:
+ CALL_PRE(mach_port_get_attributes);
+ return;
+ case 3218:
+ CALL_PRE(mach_port_set_attributes);
+ return;
+ case 3226:
+ CALL_PRE(mach_port_insert_member);
+ return;
+ case 3227:
+ CALL_PRE(mach_port_extract_member);
+ return;
+
+ case 3402:
+ CALL_PRE(task_threads);
+ return;
+ case 3404:
+ CALL_PRE(mach_ports_lookup);
+ return;
+
+ case 3407:
+ CALL_PRE(task_suspend);
+ return;
+ case 3408:
+ CALL_PRE(task_resume);
+ return;
+
+ case 3409:
+ CALL_PRE(task_get_special_port);
+ return;
+ case 3411:
+ CALL_PRE(thread_create);
+ return;
+ case 3412:
+ CALL_PRE(thread_create_running);
+ return;
+
+ case 3418:
+ CALL_PRE(semaphore_create);
+ return;
+ case 3419:
+ CALL_PRE(semaphore_destroy);
+ return;
+
+ case 3801:
+ CALL_PRE(vm_allocate);
+ return;
+ case 3802:
+ CALL_PRE(vm_deallocate);
+ return;
+ case 3803:
+ CALL_PRE(vm_protect);
+ return;
+ case 3804:
+ CALL_PRE(vm_inherit);
+ return;
+ case 3805:
+ CALL_PRE(vm_read);
+ return;
+ case 3808:
+ CALL_PRE(vm_copy);
+ return;
+ case 3809:
+ CALL_PRE(vm_read_overwrite);
+ return;
+ case 3812:
+ CALL_PRE(vm_map);
+ return;
+ case 3814:
+ CALL_PRE(vm_remap);
+ return;
+ case 3825:
+ CALL_PRE(mach_make_memory_entry_64);
+ return;
+ case 3830:
+ CALL_PRE(vm_purgable_control);
+ return;
+
+ case 4800:
+ CALL_PRE(mach_vm_allocate);
+ return;
+ case 4801:
+ CALL_PRE(mach_vm_deallocate);
+ return;
+ case 4802:
+ CALL_PRE(mach_vm_protect);
+ return;
+ case 4803:
+ CALL_PRE(mach_vm_inherit);
+ return;
+ case 4804:
+ CALL_PRE(mach_vm_read);
+ return;
+ case 4807:
+ CALL_PRE(mach_vm_copy);
+ return;
+ case 4811:
+ CALL_PRE(mach_vm_map);
+ return;
+ case 4815:
+ CALL_PRE(mach_vm_region_recurse);
+ return;
+ case 4817:
+ CALL_PRE(mach_make_memory_entry_64);
+ return;
+ case 4818:
+ CALL_PRE(mach_vm_purgable_control);
+ return;
+
+ default:
+ // unknown message to task self
+ VG_(printf)("UNKNOWN task message [id %d, to %s, reply 0x%x]\n",
+ mh->msgh_id, name_for_port(mh->msgh_remote_port),
+ mh->msgh_reply_port);
+ return;
+ }
+}
+
+
+PRE(mach_msg_thread)
+{
+ // message to local thread - check for thread-level kernel calls
+
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+
+ switch (mh->msgh_id) {
+ case 3600:
+ CALL_PRE(thread_terminate);
+ return;
+ case 3603:
+ CALL_PRE(thread_get_state);
+ return;
+ case 3605:
+ CALL_PRE(thread_suspend);
+ return;
+ case 3612:
+ CALL_PRE(thread_info);
+ return;
+ case 3616:
+ CALL_PRE(thread_policy);
+ return;
+ default:
+ // unknown message to a thread
+ VG_(printf)("UNKNOWN thread message [id %d, to %s, reply 0x%x]\n",
+ mh->msgh_id, name_for_port(mh->msgh_request_port),
+ mh->msgh_reply_port);
+ return;
+ }
+}
+
+
+static int is_thread_port(mach_port_t port)
+{
+ if (port == 0) return False;
+
+ return VG_(lwpid_to_vgtid)(port) != VG_INVALID_THREADID;
+}
+
+
+static int is_task_port(mach_port_t port)
+{
+ if (port == 0) return False;
+
+ if (port == vg_task_port) return True;
+
+ return (0 == VG_(strncmp)("task-", name_for_port(port), 5));
+}
+
+
+/* ---------------------------------------------------------------------
+ mach_msg: base handlers
+ ------------------------------------------------------------------ */
+
+PRE(mach_msg)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+ mach_msg_option_t option = (mach_msg_option_t)ARG2;
+ // mach_msg_size_t send_size = (mach_msg_size_t)ARG3;
+ mach_msg_size_t rcv_size = (mach_msg_size_t)ARG4;
+ // mach_port_t rcv_name = (mach_port_t)ARG5;
+ size_t complex_header_size = 0;
+
+ PRE_REG_READ7(long, "mach_msg",
+ mach_msg_header_t*,"msg", mach_msg_option_t,"option",
+ mach_msg_size_t,"send_size", mach_msg_size_t,"rcv_size",
+ mach_port_t,"rcv_name", mach_msg_timeout_t,"timeout",
+ mach_port_t,"notify");
+
+ // Assume default POST handler until specified otherwise
+ AFTER = NULL;
+
+ // Assume call may block unless specified otherwise
+ *flags |= SfMayBlock;
+
+ if (option & MACH_SEND_MSG) {
+ // Validate outgoing message header
+ PRE_MEM_READ("mach_msg(msg.msgh_bits)",
+ (Addr)&mh->msgh_bits, sizeof(mh->msgh_bits));
+ // msgh_size not required, use parameter instead
+ PRE_MEM_READ("mach_msg(msg.msgh_remote_port)",
+ (Addr)&mh->msgh_remote_port, sizeof(mh->msgh_remote_port));
+ PRE_MEM_READ("mach_msg(msg.msgh_local_port)",
+ (Addr)&mh->msgh_local_port, sizeof(mh->msgh_local_port));
+ // msgh_reserved not required
+ PRE_MEM_READ("mach_msg(msg.msgh_id)",
+ (Addr)&mh->msgh_id, sizeof(mh->msgh_id));
+
+ if (mh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ // Validate typed message data and handle memory map changes.
+ complex_header_size = export_complex_message(tid, mh);
+ }
+
+ // GrP fixme handle sender-specified message trailer
+ // (but is this only for too-secure processes?)
+ vg_assert(! (mh->msgh_bits & MACH_SEND_TRAILER));
+
+ MACH_REMOTE = mh->msgh_remote_port;
+ MACH_MSGH_ID = mh->msgh_id;
+ }
+
+ if (option & MACH_RCV_MSG) {
+ // Pre-validate receive buffer
+ PRE_MEM_WRITE("mach_msg(receive buffer)", (Addr)mh, rcv_size);
+ }
+
+ // Call a PRE handler. The PRE handler may set an AFTER handler.
+
+ if (!(option & MACH_SEND_MSG)) {
+ // no message sent, receive only
+ CALL_PRE(mach_msg_receive);
+ return;
+ }
+ else if (mh->msgh_request_port == vg_host_port) {
+ // message sent to mach_host_self()
+ CALL_PRE(mach_msg_host);
+ return;
+ }
+ else if (is_task_port(mh->msgh_request_port)) {
+ // message sent to a task
+ CALL_PRE(mach_msg_task);
+ return;
+ }
+ else if (mh->msgh_request_port == vg_bootstrap_port) {
+ // message sent to bootstrap port
+ CALL_PRE(mach_msg_bootstrap);
+ return;
+ }
+ else if (is_thread_port(mh->msgh_request_port)) {
+ // message sent to one of this process's threads
+ CALL_PRE(mach_msg_thread);
+ return;
+ }
+ else {
+ // arbitrary message to arbitrary port
+ PRINT("UNHANDLED mach_msg [id %d, to %s, reply 0x%x]",
+ mh->msgh_id, name_for_port(mh->msgh_request_port),
+ mh->msgh_reply_port);
+
+ AFTER = POST_FN(mach_msg_unhandled);
+
+ // Assume the entire message body may be read.
+ // GrP fixme generates false positives for unknown protocols
+ /*
+ PRE_MEM_READ("mach_msg(payload)",
+ (Addr)((char*)mh + sizeof(mach_msg_header_t) + complex_header_size),
+ send_size - sizeof(mach_msg_header_t) - complex_header_size);
+ */
+ return;
+ }
+}
+
+POST(mach_msg)
+{
+ mach_msg_header_t *mh = (mach_msg_header_t *)ARG1;
+ mach_msg_option_t option = (mach_msg_option_t)ARG2;
+
+ if (option & MACH_RCV_MSG) {
+ if (RES != 0) {
+ // error during send or receive
+ // GrP fixme need to clean up port rights?
+ } else {
+ mach_msg_trailer_t *mt =
+ (mach_msg_trailer_t *)((Addr)mh + round_msg(mh->msgh_size));
+
+ // Assume the entire received message and trailer is initialized
+ // GrP fixme would being more specific catch any bugs?
+ POST_MEM_WRITE((Addr)mh,
+ round_msg(mh->msgh_size) + mt->msgh_trailer_size);
+
+ if (mh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ // Update memory map for out-of-line message data
+ import_complex_message(tid, mh);
+ }
+ }
+ }
+
+ // Call handler chosen by PRE(mach_msg)
+ if (AFTER) {
+ (*AFTER)(tid, arrghs, status);
+ }
+}
+
+
+POST(mach_msg_unhandled)
+{
+ sync_mappings("after", "mach_msg_unhandled", 0);
+}
+
+
+/* ---------------------------------------------------------------------
+ other Mach traps
+ ------------------------------------------------------------------ */
+
+PRE(mach_reply_port)
+{
+ PRINT("mach_reply_port()");
+}
+
+POST(mach_reply_port)
+{
+ record_named_port(tid, RES, MACH_PORT_RIGHT_RECEIVE, "reply-%p");
+ PRINT("reply port %s", name_for_port(RES));
+}
+
+
+PRE(mach_thread_self)
+{
+ PRINT("mach_thread_self()");
+}
+
+POST(mach_thread_self)
+{
+ record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "thread-%p");
+ PRINT("thread %#lx", RES);
+}
+
+
+PRE(mach_host_self)
+{
+ PRINT("mach_host_self()");
+}
+
+POST(mach_host_self)
+{
+ vg_host_port = RES;
+ record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mach_host_self()");
+ PRINT("host %#lx", RES);
+}
+
+
+PRE(mach_task_self)
+{
+ PRINT("mach_task_self()");
+}
+
+POST(mach_task_self)
+{
+ vg_task_port = RES;
+ record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mach_task_self()");
+ PRINT("task %#lx", RES);
+}
+
+
+PRE(syscall_thread_switch)
+{
+ PRINT("syscall_thread_switch(%s, %ld, %ld)",
+ name_for_port(ARG1), ARG2, ARG3);
+ PRE_REG_READ3(long, "syscall_thread_switch",
+ mach_port_t,"thread", int,"option", natural_t,"timeout");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_signal)
+{
+ PRINT("semaphore_signal(%s)", name_for_port(ARG1));
+ PRE_REG_READ1(long, "semaphore_signal", semaphore_t,"semaphore");
+}
+
+
+PRE(semaphore_signal_all)
+{
+ PRINT("semaphore_signal_all(%s)", name_for_port(ARG1));
+ PRE_REG_READ1(long, "semaphore_signal_all", semaphore_t,"semaphore");
+}
+
+
+PRE(semaphore_signal_thread)
+{
+ PRINT("semaphore_signal_thread(%s, %s)",
+ name_for_port(ARG1), name_for_port(ARG2));
+ PRE_REG_READ2(long, "semaphore_signal_thread",
+ semaphore_t,"semaphore", mach_port_t,"thread");
+}
+
+
+PRE(semaphore_wait)
+{
+ PRINT("semaphore_wait(%s)", name_for_port(ARG1));
+ PRE_REG_READ1(long, "semaphore_signal", semaphore_t,"semaphore");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_wait_signal)
+{
+ PRINT("semaphore_wait_signal(%s, %s)",
+ name_for_port(ARG1), name_for_port(ARG2));
+ PRE_REG_READ2(long, "semaphore_wait_signal",
+ semaphore_t,"wait_semaphore",
+ semaphore_t,"signal_semaphore");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_timedwait)
+{
+ PRINT("semaphore_timedwait(%s, %g seconds)",
+ name_for_port(ARG1), ARG2+ARG3/1000000000.0);
+ PRE_REG_READ3(long, "semaphore_wait_signal",
+ semaphore_t,"semaphore",
+ int,"wait_time_hi",
+ int,"wait_time_lo");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(semaphore_timedwait_signal)
+{
+ PRINT("semaphore_wait_signal(wait %s, signal %s, %g seconds)",
+ name_for_port(ARG1), name_for_port(ARG2), ARG3+ARG4/1000000000.0);
+ PRE_REG_READ4(long, "semaphore_wait_signal",
+ semaphore_t,"wait_semaphore",
+ semaphore_t,"signal_semaphore",
+ int,"wait_time_hi",
+ int,"wait_time_lo");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(sys___semwait_signal)
+{
+ /* args: int cond_sem, int mutex_sem,
+ int timeout, int relative,
+ time_t tv_sec, time_t tv_nsec */
+ PRINT("sys___semwait_signal(wait %s, signal %s, %ld, %ld, %lds:%ldns)",
+ name_for_port(ARG1), name_for_port(ARG2), ARG3, ARG4, ARG5, ARG6);
+ PRE_REG_READ6(long, "sys___semwait_signal",
+ int,"cond_sem", int,"mutex_sem",
+ int,"timeout", int,"relative",
+ vki_time_t,"tv_sec", int,"tv_nsec");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(task_for_pid)
+{
+ PRINT("task_for_pid(%s, %ld, %#lx)", name_for_port(ARG1), ARG2, ARG3);
+ PRE_REG_READ3(long, "task_for_pid",
+ mach_port_t,"target",
+ vki_pid_t, "pid", mach_port_t *,"task");
+ PRE_MEM_WRITE("task_for_pid(task)", ARG3, sizeof(mach_port_t));
+}
+
+POST(task_for_pid)
+{
+ mach_port_t task;
+
+ POST_MEM_WRITE(ARG3, sizeof(mach_port_t));
+
+ task = *(mach_port_t *)ARG3;
+ record_named_port(tid, task, MACH_PORT_RIGHT_SEND, "task-%p");
+ PRINT("task 0x%x", task);
+}
+
+
+PRE(pid_for_task)
+{
+ PRINT("pid_for_task(%s, %#lx)", name_for_port(ARG1), ARG2);
+ PRE_REG_READ2(long, "task_for_pid", mach_port_t,"task", vki_pid_t *,"pid");
+ PRE_MEM_WRITE("task_for_pid(pid)", ARG2, sizeof(vki_pid_t));
+}
+
+POST(pid_for_task)
+{
+ vki_pid_t pid;
+
+ POST_MEM_WRITE(ARG2, sizeof(vki_pid_t));
+
+ pid = *(vki_pid_t *)ARG2;
+ PRINT("pid %u", pid);
+}
+
+
+PRE(mach_timebase_info)
+{
+ PRINT("mach_timebase_info(%#lx)", ARG1);
+ PRE_REG_READ1(long, "mach_timebase_info", void *,"info");
+ PRE_MEM_WRITE("mach_timebase_info(info)", ARG1, sizeof(struct vki_mach_timebase_info));
+}
+
+POST(mach_timebase_info)
+{
+ POST_MEM_WRITE(ARG1, sizeof(struct vki_mach_timebase_info));
+}
+
+
+PRE(mach_wait_until)
+{
+#if VG_WORDSIZE == 8
+ PRINT("mach_wait_until(%llu)", ARG1);
+ PRE_REG_READ1(long, "mach_wait_until",
+ unsigned long long,"deadline");
+#else
+ PRINT("mach_wait_until(%llu)", LOHI64(ARG1, ARG2));
+ PRE_REG_READ2(long, "mach_wait_until",
+ int,"deadline_hi", int,"deadline_lo");
+#endif
+ *flags |= SfMayBlock;
+}
+
+
+PRE(mk_timer_create)
+{
+ PRINT("mk_timer_create()");
+ PRE_REG_READ0(long, "mk_timer_create");
+}
+
+POST(mk_timer_create)
+{
+ record_named_port(tid, RES, MACH_PORT_RIGHT_SEND, "mk_timer-%p");
+}
+
+
+PRE(mk_timer_destroy)
+{
+ PRINT("mk_timer_destroy(%s)", name_for_port(ARG1));
+ PRE_REG_READ1(long, "mk_timer_destroy", mach_port_t,"name");
+
+ // Must block to prevent race (other thread allocates and
+ // notifies after we deallocate but before we notify)
+ *flags &= ~SfMayBlock;
+}
+
+POST(mk_timer_destroy)
+{
+ // Must have cleared SfMayBlock in PRE to prevent race
+ record_port_destroy(ARG1);
+}
+
+
+PRE(mk_timer_arm)
+{
+#if VG_WORDSIZE == 8
+ PRINT("mk_timer_arm(%s, %llu)", name_for_port(ARG1), ARG2);
+ PRE_REG_READ2(long, "mk_timer_arm", mach_port_t,"name",
+ unsigned long,"expire_time");
+#else
+ PRINT("mk_timer_arm(%s, %llu)", name_for_port(ARG1), LOHI64(ARG2, ARG3));
+ PRE_REG_READ3(long, "mk_timer_arm", mach_port_t,"name",
+ int,"expire_time_hi", int,"expire_time_lo");
+#endif
+}
+
+
+PRE(mk_timer_cancel)
+{
+ PRINT("mk_timer_cancel(%s, %#lx)", name_for_port(ARG1), ARG2);
+ PRE_REG_READ2(long, "mk_timer_cancel",
+ mach_port_t,"name", Addr,"result_time");
+ if (ARG2) {
+ PRE_MEM_WRITE("mk_timer_cancel(result_time)", ARG2,sizeof(vki_uint64_t));
+ }
+}
+
+POST(mk_timer_cancel)
+{
+ if (ARG2) {
+ POST_MEM_WRITE(ARG2, sizeof(vki_uint64_t));
+ }
+}
+
+
+PRE(iokit_user_client_trap)
+{
+ PRINT("iokit_user_client_trap(%s, %ld, %lx, %lx, %lx, %lx, %lx, %lx)",
+ name_for_port(ARG1), ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8);
+ PRE_REG_READ8(kern_return_t, "iokit_user_client_trap",
+ mach_port_t,connect, unsigned int,index,
+ uintptr_t,p1, uintptr_t,p2, uintptr_t,p3,
+ uintptr_t,p4, uintptr_t,p5, uintptr_t,p6);
+
+ // can't do anything else with this in general
+ // might be able to use connect+index to choose something sometimes
+}
+
+POST(iokit_user_client_trap)
+{
+ sync_mappings("after", "iokit_user_client_trap", ARG2);
+}
+
+
+PRE(swtch)
+{
+ PRINT("swtch ( )");
+ PRE_REG_READ0(long, "swtch");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(swtch_pri)
+{
+ PRINT("swtch_pri ( %ld )", ARG1);
+ PRE_REG_READ1(long, "swtch_pri", int,"pri");
+
+ *flags |= SfMayBlock;
+}
+
+
+PRE(sys_FAKE_SIGRETURN)
+{
+ /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for
+ an explanation of what follows. */
+ /* This handles the fake signal-return system call created by
+ sigframe-x86-darwin.c. */
+ /* See also comments just below on PRE(sys_sigreturn). */
+
+ PRINT("FAKE_SIGRETURN ( )");
+
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(tid >= 1 && tid < VG_N_THREADS);
+ vg_assert(VG_(is_running_thread)(tid));
+
+ /* Remove the signal frame from this thread's (guest) stack,
+ in the process restoring the pre-signal guest state. */
+ VG_(sigframe_destroy)(tid, True);
+
+ /* Tell the driver not to update the guest state with the "result",
+ and set a bogus result to keep it happy. */
+ *flags |= SfNoWriteResult;
+ SET_STATUS_Success(0);
+
+ /* Check to see if any signals arose as a result of this. */
+ *flags |= SfPollAfter;
+}
+
+
+PRE(sys_sigreturn)
+{
+ /* This is the "real" sigreturn. But because we construct all the
+ signal frames ourselves (of course, in m_sigframe), this cannot
+ happen as a result of normal signal delivery. I think it
+ happens only when doing siglongjmp, in which case Darwin's Libc
+ appears to use it for two different purposes: to mess with the
+ per-thread sigaltstack flags (as per arg 2), or to restore the
+ thread's state from a ucontext* (as per arg 1). */
+
+ PRINT("sigreturn ( uctx=%#lx, infostyle=%#lx )", ARG1, ARG2);
+
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(tid >= 1 && tid < VG_N_THREADS);
+ vg_assert(VG_(is_running_thread)(tid));
+
+ if (ARG2 == VKI_UC_SET_ALT_STACK) {
+ /* This is confusing .. the darwin kernel sources imply there is
+ a per-thread on-altstack/not-on-altstack flag, which is set
+ by this flag. Just ignore it and claim success for the time
+ being. */
+ VG_(debugLog)(0, "syswrap-darwin",
+ "WARNING: Ignoring sys_sigreturn( ..., "
+ "UC_SET_ALT_STACK );\n");
+ SET_STATUS_Success(0);
+ return;
+ }
+ if (ARG2 == VKI_UC_RESET_ALT_STACK) {
+ /* Ditto */
+ VG_(debugLog)(0, "syswrap-darwin",
+ "WARNING: Ignoring sys_sigreturn( ..., "
+ "UC_RESET_ALT_STACK );\n");
+ SET_STATUS_Success(0);
+ return;
+ }
+
+ /* Otherwise claim this isn't supported. (Could be
+ catastrophic).
+
+ What do we have to do if we do need to support it?
+
+ 1. Change the second argument of VG_(sigframe_destroy) from
+ "Bool isRT" to "UInt sysno", so we can pass the syscall
+ number, so it can distinguish this case from the
+ __NR_DARWIN_FAKE_SIGRETURN case.
+
+ 2. In VG_(sigframe_destroy), look at sysno to distinguish the
+ cases. For __NR_DARWIN_FAKE_SIGRETURN, behave as at present.
+ For this case, restore the thread's CPU state (or at least
+ the integer regs) from the ucontext in ARG1 (and do all the
+ other "signal-returns" stuff too).
+
+ 3. For (2), how do we know where the ucontext is? One way is to
+ temporarily copy ARG1 into this thread's guest_EBX (or any
+ other int reg), and have VG_(sigframe_destroy) read
+ guest_EBX. Why is it ok to trash guest_EBX (or any other int
+ reg)? Because VG_(sigframe_destroy) is just about to
+ overwrite all the regs anyway -- since the primary purpose of
+ calling it is to restore the register state from the ucontext
+ pointed to by ARG1.
+
+ Hey, it's uggerly. But at least it's documented.
+ */
+ /* But in the meantime ... */
+ VG_(debugLog)(0, "syswrap-darwin",
+ "WARNING: Ignoring sys_sigreturn( uctx=..., 0 );\n");
+ VG_(debugLog)(0, "syswrap-darwin",
+ "WARNING: Thread/program/Valgrind "
+ "will likely segfault now.\n");
+ VG_(debugLog)(0, "syswrap-darwin",
+ "WARNING: Please file a bug report at "
+ "http://www.valgrind.org.\n");
+ SET_STATUS_Failure( VKI_ENOSYS );
+}
+
+
+/* ---------------------------------------------------------------------
+ machine-dependent traps
+ ------------------------------------------------------------------ */
+
+#if defined(VGA_x86)
+static VexGuestX86SegDescr* alloc_zeroed_x86_LDT ( void )
+{
+ Int nbytes = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr);
+ return VG_(arena_calloc)(VG_AR_CORE, "syswrap-darwin.ldt", nbytes, 1);
+}
+#endif
+
+PRE(pthread_set_self)
+{
+ PRINT("pthread_set_self ( %#lx )", ARG1);
+ PRE_REG_READ1(void, "pthread_set_self", struct pthread_t *, self);
+
+#if defined(VGA_x86)
+ // GrP fixme hack this isn't really pthread_set_self
+ // Point the USER_CTHREAD ldt entry (slot 6, reg 0x37) at this pthread
+ {
+ VexGuestX86SegDescr *ldt;
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ ldt = (VexGuestX86SegDescr *)tst->arch.vex.guest_LDT;
+ if (!ldt) {
+ ldt = alloc_zeroed_x86_LDT();
+ tst->arch.vex.guest_LDT = (HWord)ldt;
+ }
+ VG_(memset)(&ldt[6], 0, sizeof(ldt[6]));
+ ldt[6].LdtEnt.Bits.LimitLow = 1;
+ ldt[6].LdtEnt.Bits.LimitHi = 0;
+ ldt[6].LdtEnt.Bits.BaseLow = ARG1 & 0xffff;
+ ldt[6].LdtEnt.Bits.BaseMid = (ARG1 >> 16) & 0xff;
+ ldt[6].LdtEnt.Bits.BaseHi = (ARG1 >> 24) & 0xff;
+ ldt[6].LdtEnt.Bits.Pres = 1; // ACC_P
+ ldt[6].LdtEnt.Bits.Dpl = 3; // ACC_PL_U
+ ldt[6].LdtEnt.Bits.Type = 0x12; // ACC_DATA_W
+ ldt[6].LdtEnt.Bits.Granularity = 1; // SZ_G
+ ldt[6].LdtEnt.Bits.Default_Big = 1; // SZ_32
+
+ tst->os_state.pthread = ARG1;
+ tst->arch.vex.guest_GS = 0x37;
+
+ // What we would like to do is:
+ // SET_STATUS_Success(0x37);
+ // but that doesn't work, because this is a MDEP-class syscall,
+ // and SET_STATUS_Success creates a UNIX-class syscall result.
+ // Hence we have to laboriously construct the full SysRes "by hand"
+ // and use that to set the syscall return status.
+ SET_STATUS_from_SysRes(
+ VG_(mk_SysRes_x86_darwin)(
+ VG_DARWIN_SYSNO_CLASS(__NR_pthread_set_self),
+ False, 0, 0x37
+ )
+ );
+ }
+
+#elif defined(VGA_amd64)
+ // GrP fixme bigger hack than x86
+ {
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+ tst->os_state.pthread = ARG1;
+ tst->arch.vex.guest_GS_0x60 = ARG1;
+ // SET_STATUS_Success(0x60);
+ // see comments on x86 case just above
+ SET_STATUS_from_SysRes(
+ VG_(mk_SysRes_amd64_darwin)(
+ VG_DARWIN_SYSNO_CLASS(__NR_pthread_set_self),
+ False, 0, 0x60
+ )
+ );
+ }
+
+#else
+#error unknown architecture
+#endif
+}
+
+
+/* ---------------------------------------------------------------------
+ syscall tables
+ ------------------------------------------------------------------ */
+
+/* Add a Darwin-specific, arch-independent wrapper to a syscall table. */
+#define MACX_(sysno, name) WRAPPER_ENTRY_X_(darwin, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#define MACXY(sysno, name) WRAPPER_ENTRY_XY(darwin, VG_DARWIN_SYSNO_INDEX(sysno), name)
+#define _____(sysno) GENX_(sysno, sys_ni_syscall)
+
+/*
+ _____ : unsupported by the kernel (sys_ni_syscall)
+ // _____ : unimplemented in valgrind
+ GEN : handlers are in syswrap-generic.c
+ MAC : handlers are in this file
+ X_ : PRE handler only
+ XY : PRE and POST handlers
+*/
+// DDD: the "sys_" prefixes I think aren't necessary. The name on the right
+// is meant to be the name of the function implementing the syscall in the
+// kernel. On Darwin that seems to usually match the __NR_xyz name.
+const SyscallTableEntry ML_(syscall_table)[] = {
+// _____(__NR_syscall), // 0
+ MACX_(__NR_exit, sys_exit),
+ GENX_(__NR_fork, sys_fork),
+ GENXY(__NR_read, sys_read),
+ GENX_(__NR_write, sys_write),
+ GENXY(__NR_open, sys_open),
+ GENXY(__NR_close, sys_close),
+ GENXY(__NR_wait4, sys_wait4),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(8)), // old creat
+ GENX_(__NR_link, sys_link),
+ GENX_(__NR_unlink, sys_unlink),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(11)), // old execv
+ GENX_(__NR_chdir, sys_chdir),
+ GENX_(__NR_fchdir, sys_fchdir),
+ GENX_(__NR_mknod, sys_mknod),
+ GENX_(__NR_chmod, sys_chmod),
+ GENX_(__NR_chown, sys_chown),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(17)), // old break
+ MACXY(__NR_getfsstat, sys_getfsstat),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(19)), // old lseek
+ GENX_(__NR_getpid, sys_getpid), // 20
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(21)), // old mount
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(22)), // old umount
+ GENX_(__NR_setuid, sys_setuid),
+ GENX_(__NR_getuid, sys_getuid),
+ GENX_(__NR_geteuid, sys_geteuid),
+ MACX_(__NR_ptrace, sys_ptrace),
+ MACXY(__NR_recvmsg, sys_recvmsg),
+ MACX_(__NR_sendmsg, sys_sendmsg),
+ MACXY(__NR_recvfrom, sys_recvfrom),
+ MACXY(__NR_accept, sys_accept),
+ MACXY(__NR_getpeername, sys_getpeername),
+ MACXY(__NR_getsockname, sys_getsockname),
+ GENX_(__NR_access, sys_access),
+ MACX_(__NR_chflags, sys_chflags),
+ MACX_(__NR_fchflags, sys_fchflags),
+ GENX_(__NR_sync, sys_sync),
+ GENX_(__NR_kill, sys_kill),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(38)), // old stat
+ GENX_(__NR_getppid, sys_getppid),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(40)), // old lstat
+ GENXY(__NR_dup, sys_dup),
+ MACXY(__NR_pipe, sys_pipe),
+ GENX_(__NR_getegid, sys_getegid),
+// _____(__NR_profil),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(45)), // old ktrace
+ MACXY(__NR_sigaction, sys_sigaction),
+ GENX_(__NR_getgid, sys_getgid),
+ MACXY(__NR_sigprocmask, sys_sigprocmask),
+ MACXY(__NR_getlogin, sys_getlogin),
+// _____(__NR_setlogin),
+// _____(__NR_acct),
+// _____(__NR_sigpending),
+ GENXY(__NR_sigaltstack, sys_sigaltstack),
+ MACXY(__NR_ioctl, sys_ioctl),
+// _____(__NR_reboot),
+// _____(__NR_revoke),
+// _____(__NR_symlink),
+ GENX_(__NR_readlink, sys_readlink),
+ GENX_(__NR_execve, sys_execve),
+ GENX_(__NR_umask, sys_umask), // 60
+ GENX_(__NR_chroot, sys_chroot),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(62)), // old fstat
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(63)), // used internally, reserved
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(64)), // old getpagesize
+ GENX_(__NR_msync, sys_msync),
+ GENX_(__NR_vfork, sys_fork), // (We treat vfork as fork.)
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(67)), // old vread
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(68)), // old vwrite
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(69)), // old sbrk
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(70)), // old sstk
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(71)), // old mmap
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(72)), // old vadvise
+ GENXY(__NR_munmap, sys_munmap),
+ GENXY(__NR_mprotect, sys_mprotect),
+ GENX_(__NR_madvise, sys_madvise),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(76)), // old vhangup
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(77)), // old vlimit
+// _____(__NR_mincore),
+ GENXY(__NR_getgroups, sys_getgroups),
+// _____(__NR_setgroups), // 80
+ GENX_(__NR_getpgrp, sys_getpgrp),
+// _____(__NR_setpgid),
+ GENXY(__NR_setitimer, sys_setitimer),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(84)), // old wait
+// _____(__NR_swapon),
+ GENXY(__NR_getitimer, sys_getitimer),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(87)), // old gethostname
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(88)), // old sethostname
+ MACXY(__NR_getdtablesize, sys_getdtablesize),
+ GENXY(__NR_dup2, sys_dup2),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(91)), // old getdopt
+ MACXY(__NR_fcntl, sys_fcntl),
+ GENX_(__NR_select, sys_select),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(94)), // old setdopt
+ GENX_(__NR_fsync, sys_fsync),
+ GENX_(__NR_setpriority, sys_setpriority),
+ MACXY(__NR_socket, sys_socket),
+ MACX_(__NR_connect, sys_connect),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(99)), // old accept
+ GENX_(__NR_getpriority, sys_getpriority), // 100
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(101)), // old send
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(102)), // old recv
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(103)), // old sigreturn
+ MACX_(__NR_bind, sys_bind),
+ MACX_(__NR_setsockopt, sys_setsockopt),
+ MACX_(__NR_listen, sys_listen),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(107)), // old vtimes
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(108)), // old sigvec
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(109)), // old sigblock
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(110)), // old sigsetmask
+ MACX_(__NR_sigsuspend, sys_sigsuspend), // old sigsuspend
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(112)), // old sigstack
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(113)), // old recvmsg
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(114)), // old sendmsg
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(115)), // old vtrace
+ GENXY(__NR_gettimeofday, sys_gettimeofday),
+ GENXY(__NR_getrusage, sys_getrusage),
+ MACXY(__NR_getsockopt, sys_getsockopt),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(119)), // old resuba
+ GENXY(__NR_readv, sys_readv), // 120
+ GENX_(__NR_writev, sys_writev),
+// _____(__NR_settimeofday),
+ GENX_(__NR_fchown, sys_fchown),
+ GENX_(__NR_fchmod, sys_fchmod),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(125)), // old recvfrom
+// _____(__NR_setreuid),
+// _____(__NR_setregid),
+ GENX_(__NR_rename, sys_rename),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(129)), // old truncate
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(130)), // old ftruncate
+ GENX_(__NR_flock, sys_flock),
+// _____(__NR_mkfifo),
+ MACX_(__NR_sendto, sys_sendto),
+ MACX_(__NR_shutdown, sys_shutdown),
+ MACXY(__NR_socketpair, sys_socketpair),
+ GENX_(__NR_mkdir, sys_mkdir),
+ GENX_(__NR_rmdir, sys_rmdir),
+ GENX_(__NR_utimes, sys_utimes),
+ MACX_(__NR_futimes, sys_futimes),
+// _____(__NR_adjtime), // 140
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(141)), // old getpeername
+ MACXY(__NR_gethostuuid, sys_gethostuuid),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(143)), // old sethostid
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(144)), // old getrlimit
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(145)), // old setrlimit
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(146)), // old killpg
+ GENX_(__NR_setsid, sys_setsid),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(148)), // old setquota
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(149)), // old qquota
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(150)), // old getsockname
+// _____(__NR_getpgid),
+// _____(__NR_setprivexec),
+ GENXY(__NR_pread, sys_pread64),
+ GENX_(__NR_pwrite, sys_pwrite64),
+// _____(__NR_nfssvc),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(156)), // old getdirentries
+ GENXY(__NR_statfs, sys_statfs),
+ GENXY(__NR_fstatfs, sys_fstatfs),
+// _____(__NR_unmount),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(160)), // old async_daemon
+// _____(__NR_getfh),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(162)), // old getdomainname
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(163)), // old setdomainname
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(164)), // ???
+// _____(__NR_quotactl),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(166)), // old exportfs
+// _____(__NR_mount),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(168)), // old ustat
+ MACXY(__NR_csops, sys_csops), // code-signing ops
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(170)), // old table
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(171)), // old wait3
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(172)), // old rpause
+// _____(__NR_waitid),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(174)), // old getdents
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(175)), // old gc_control
+// _____(__NR_add_profil),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(177)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(178)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(179)), // ???
+ MACX_(__NR_kdebug_trace, sys_kdebug_trace), // 180
+ GENX_(__NR_setgid, sys_setgid),
+ MACX_(__NR_setegid, sys_setegid),
+ MACX_(__NR_seteuid, sys_seteuid),
+ MACX_(__NR_sigreturn, sys_sigreturn),
+// _____(__NR_chud),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(186)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(187)), // ???
+ GENXY(__NR_stat, sys_newstat),
+ GENXY(__NR_fstat, sys_newfstat),
+ GENXY(__NR_lstat, sys_newlstat),
+ MACX_(__NR_pathconf, sys_pathconf),
+ MACX_(__NR_fpathconf, sys_fpathconf),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(193)), // ???
+ GENXY(__NR_getrlimit, sys_getrlimit),
+ GENX_(__NR_setrlimit, sys_setrlimit),
+ MACXY(__NR_getdirentries, sys_getdirentries),
+ MACXY(__NR_mmap, sys_mmap),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(198)), // __syscall
+ MACX_(__NR_lseek, sys_lseek),
+ GENX_(__NR_truncate, sys_truncate64), // 200
+ GENX_(__NR_ftruncate, sys_ftruncate64),
+ MACXY(__NR___sysctl, sys_sysctl),
+ GENX_(__NR_mlock, sys_mlock),
+ GENX_(__NR_munlock, sys_munlock),
+// _____(__NR_undelete),
+// _____(__NR_ATsocket),
+// _____(__NR_ATgetmsg),
+// _____(__NR_ATputmsg),
+// _____(__NR_ATPsndreq),
+// _____(__NR_ATPsndrsp),
+// _____(__NR_ATPgetreq),
+// _____(__NR_ATPgetrsp),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(213)), // Reserved for AppleTalk
+// _____(__NR_kqueue_from_portset_np),
+// _____(__NR_kqueue_portset_np),
+// _____(__NR_mkcomplex),
+// _____(__NR_statv),
+// _____(__NR_lstatv),
+// _____(__NR_fstatv),
+ MACXY(__NR_getattrlist, sys_getattrlist), // 220
+ MACX_(__NR_setattrlist, sys_setattrlist),
+ MACXY(__NR_getdirentriesattr, sys_getdirentriesattr),
+// _____(__NR_exchangedata),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(224)), // checkuseraccess
+// _____(__NR_searchfs),
+ GENX_(__NR_delete, sys_unlink),
+// _____(__NR_copyfile),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(228)), // ??
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(229)), // ??
+ GENXY(__NR_poll, sys_poll),
+ MACX_(__NR_watchevent, sys_watchevent),
+ MACXY(__NR_waitevent, sys_waitevent),
+ MACX_(__NR_modwatch, sys_modwatch),
+ MACXY(__NR_getxattr, sys_getxattr),
+ MACXY(__NR_fgetxattr, sys_fgetxattr),
+ MACX_(__NR_setxattr, sys_setxattr),
+ MACX_(__NR_fsetxattr, sys_fsetxattr),
+// _____(__NR_removexattr),
+// _____(__NR_fremovexattr),
+ MACXY(__NR_listxattr, sys_listxattr), // 240
+ MACXY(__NR_flistxattr, sys_flistxattr),
+ MACXY(__NR_fsctl, sys_fsctl),
+ MACX_(__NR_initgroups, sys_initgroups),
+ MACXY(__NR_posix_spawn, sys_posix_spawn),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(245)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(246)), // ???
+// _____(__NR_nfsclnt),
+// _____(__NR_fhopen),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(249)), // ???
+// _____(__NR_minherit),
+// _____(__NR_semsys),
+// _____(__NR_msgsys),
+// _____(__NR_shmsys),
+ MACXY(__NR_semctl, sys_semctl),
+ MACX_(__NR_semget, sys_semget),
+ MACX_(__NR_semop, sys_semop),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(257)), // ???
+// _____(__NR_msgctl),
+// _____(__NR_msgget),
+// _____(__NR_msgsnd), // 260
+// _____(__NR_msgrcv),
+// _____(__NR_shmat),
+// _____(__NR_shmctl),
+// _____(__NR_shmdt),
+ MACX_(__NR_shmget, sys_shmget),
+ MACXY(__NR_shm_open, sys_shm_open),
+// _____(__NR_shm_unlink),
+ MACX_(__NR_sem_open, sys_sem_open),
+ MACX_(__NR_sem_close, sys_sem_close),
+ MACX_(__NR_sem_unlink, sys_sem_unlink),
+// _____(__NR_sem_wait),
+ MACX_(__NR_sem_trywait, sys_sem_trywait),
+// _____(__NR_sem_post),
+ MACX_(__NR_sem_post, sys_sem_post),
+// _____(__NR_sem_getvalue),
+ MACXY(__NR_sem_init, sys_sem_init),
+ MACX_(__NR_sem_destroy, sys_sem_destroy),
+// _____(__NR_open_extended),
+// _____(__NR_umask_extended),
+ MACXY(__NR_stat_extended, sys_statx),
+// _____(__NR_lstat_extended), // 280
+// _____(__NR_fstat_extended),
+ MACX_(__NR_chmod_extended, sys_chmod_extended),
+ MACX_(__NR_fchmod_extended, sys_fchmod_extended),
+// _____(__NR_access_extended),
+ MACX_(__NR_settid, sys_settid),
+// _____(__NR_gettid),
+// _____(__NR_setsgroups),
+// _____(__NR_getsgroups),
+// _____(__NR_setwgroups),
+// _____(__NR_getwgroups),
+// _____(__NR_mkfifo_extended),
+// _____(__NR_mkdir_extended),
+// _____(__NR_identitysvc),
+// _____(__NR_shared_region_check_np),
+// _____(__NR_shared_region_map_np),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(296)), // old load_shared_file
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(297)), // old reset_shared_file
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(298)), // old new_system_shared_regions
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(299)), // old shared_region_map_file_np
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(300)), // old shared_region_make_private_np
+// _____(__NR___pthread_mutex_destroy),
+// _____(__NR___pthread_mutex_init),
+// _____(__NR___pthread_mutex_lock),
+// _____(__NR___pthread_mutex_trylock),
+// _____(__NR___pthread_mutex_unlock),
+// _____(__NR___pthread_cond_init),
+// _____(__NR___pthread_cond_destroy),
+// _____(__NR___pthread_cond_broadcast),
+// _____(__NR___pthread_cond_signal),
+// _____(__NR_getsid),
+// _____(__NR_settid_with_pid),
+// _____(__NR___pthread_cond_timedwait),
+// _____(__NR_aio_fsync),
+// _____(__NR_aio_return),
+// _____(__NR_aio_suspend),
+// _____(__NR_aio_cancel),
+// _____(__NR_aio_error),
+// _____(__NR_aio_read),
+// _____(__NR_aio_write),
+// _____(__NR_lio_listio), // 320
+// _____(__NR___pthread_cond_wait),
+// _____(__NR_iopolicysys),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(323)), // ???
+// _____(__NR_mlockall),
+// _____(__NR_munlockall),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(326)), // ???
+ MACX_(__NR_issetugid, sys_issetugid),
+// _____(__NR___pthread_kill),
+ MACX_(__NR___pthread_sigmask, sys___pthread_sigmask),
+// _____(__NR___sigwait),
+ MACX_(__NR___disable_threadsignal, sys___disable_threadsignal),
+ MACX_(__NR___pthread_markcancel, sys___pthread_markcancel),
+ MACX_(__NR___pthread_canceled, sys___pthread_canceled),
+ MACX_(__NR___semwait_signal, sys___semwait_signal),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(335)), // old utrace
+// _____(__NR_proc_info),
+ MACXY(__NR_sendfile, sys_sendfile),
+ MACXY(__NR_stat64, sys_stat64),
+ MACXY(__NR_fstat64, sys_fstat64),
+ MACXY(__NR_lstat64, sys_lstat64), // 340
+// _____(__NR_stat64_extended),
+// _____(__NR_lstat64_extended),
+// _____(__NR_fstat64_extended),
+ MACXY(__NR_getdirentries64, sys_getdirentries64),
+ MACXY(__NR_statfs64, sys_statfs64),
+ MACXY(__NR_fstatfs64, sys_fstatfs64),
+// _____(__NR_getfsstat64),
+// _____(__NR___pthread_chdir),
+// _____(__NR___pthread_fchdir),
+// _____(__NR_audit),
+ MACXY(__NR_auditon, sys_auditon),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(352)), // ???
+// _____(__NR_getauid),
+// _____(__NR_setauid),
+// _____(__NR_getaudit),
+// _____(__NR_setaudit),
+// _____(__NR_getaudit_addr),
+// _____(__NR_setaudit_addr),
+// _____(__NR_auditctl),
+ MACXY(__NR_bsdthread_create, sys_bsdthread_create), // 360
+ MACX_(__NR_bsdthread_terminate, sys_bsdthread_terminate),
+ MACXY(__NR_kqueue, sys_kqueue),
+ MACXY(__NR_kevent, sys_kevent),
+// _____(__NR_lchown),
+// _____(__NR_stack_snapshot),
+ MACX_(__NR_bsdthread_register, sys_bsdthread_register),
+ MACX_(__NR_workq_open, sys_workq_open),
+ MACXY(__NR_workq_ops, sys_workq_ops),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(369)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(370)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(371)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(372)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(373)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(374)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(375)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(376)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(377)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(378)), // ???
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(379)), // ???
+// _____(__NR___mac_execve), // 380
+ MACX_(__NR___mac_syscall, sys___mac_syscall),
+// _____(__NR___mac_get_file),
+// _____(__NR___mac_set_file),
+// _____(__NR___mac_get_link),
+// _____(__NR___mac_set_link),
+// _____(__NR___mac_get_proc),
+// _____(__NR___mac_set_proc),
+// _____(__NR___mac_get_fd),
+// _____(__NR___mac_set_fd),
+// _____(__NR___mac_get_pid),
+// _____(__NR___mac_get_lcid),
+// _____(__NR___mac_get_lctx),
+// _____(__NR___mac_set_lctx),
+// _____(__NR_setlcid),
+// _____(__NR_getlcid),
+ // GrP fixme need any special nocancel handling?
+ GENXY(__NR_read_nocancel, sys_read),
+ GENX_(__NR_write_nocancel, sys_write),
+ GENXY(__NR_open_nocancel, sys_open),
+ GENXY(__NR_close_nocancel, sys_close),
+ GENXY(__NR_wait4_nocancel, sys_wait4), // 400
+ MACXY(__NR_recvmsg_nocancel, sys_recvmsg),
+ MACX_(__NR_sendmsg_nocancel, sys_sendmsg),
+ MACXY(__NR_recvfrom_nocancel, sys_recvfrom),
+ MACXY(__NR_accept_nocancel, sys_accept),
+ GENX_(__NR_msync_nocancel, sys_msync),
+ MACXY(__NR_fcntl_nocancel, sys_fcntl),
+ GENX_(__NR_select_nocancel, sys_select),
+ GENX_(__NR_fsync_nocancel, sys_fsync),
+ MACX_(__NR_connect_nocancel, sys_connect),
+// _____(__NR_sigsuspend_nocancel),
+ GENXY(__NR_readv_nocancel, sys_readv),
+ GENX_(__NR_writev_nocancel, sys_writev),
+ MACX_(__NR_sendto_nocancel, sys_sendto),
+ GENXY(__NR_pread_nocancel, sys_pread64),
+ GENX_(__NR_pwrite_nocancel, sys_pwrite64),
+// _____(__NR_waitid_nocancel),
+ GENXY(__NR_poll_nocancel, sys_poll),
+// _____(__NR_msgsnd_nocancel),
+// _____(__NR_msgrcv_nocancel),
+ MACX_(__NR_sem_wait_nocancel, sys_sem_wait_nocancel), // 420
+// _____(__NR_aio_suspend_nocancel),
+// _____(__NR___sigwait_nocancel),
+ MACX_(__NR___semwait_signal_nocancel, sys___semwait_signal),
+// _____(__NR___mac_mount),
+// _____(__NR___mac_get_mount),
+// _____(__NR___mac_getfsstat),
+// _____(__NR_MAXSYSCALL)
+ MACX_(__NR_DARWIN_FAKE_SIGRETURN, sys_FAKE_SIGRETURN)
+};
+
+
+// Mach traps use negative syscall numbers.
+// Use ML_(mach_trap_table)[-mach_trap_number] .
+
+const SyscallTableEntry ML_(mach_trap_table)[] = {
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(0)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(1)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(2)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(3)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(4)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(5)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(6)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(7)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(8)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(9)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(10)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(11)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(12)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(13)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(14)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(15)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(16)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(17)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(18)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(19)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(20)), // -20
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(21)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(22)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(23)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(24)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(25)),
+ MACXY(__NR_mach_reply_port, mach_reply_port),
+ MACXY(__NR_thread_self_trap, mach_thread_self),
+ MACXY(__NR_task_self_trap, mach_task_self),
+ MACXY(__NR_host_self_trap, mach_host_self),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(30)),
+ MACXY(__NR_mach_msg_trap, mach_msg),
+// _____(__NR_mach_msg_overwrite_trap),
+ MACX_(__NR_semaphore_signal_trap, semaphore_signal),
+ MACX_(__NR_semaphore_signal_all_trap, semaphore_signal_all),
+ MACX_(__NR_semaphore_signal_thread_trap, semaphore_signal_thread),
+ MACX_(__NR_semaphore_wait_trap, semaphore_wait),
+ MACX_(__NR_semaphore_wait_signal_trap, semaphore_wait_signal),
+ MACX_(__NR_semaphore_timedwait_trap, semaphore_timedwait),
+ MACX_(__NR_semaphore_timedwait_signal_trap, semaphore_timedwait_signal),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(40)), // -40
+#if defined(VGA_x86)
+// _____(__NR_init_process),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(42)),
+// _____(__NR_map_fd),
+#else
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(41)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(42)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(43)),
+#endif
+// _____(__NR_task_name_for_pid),
+ MACXY(__NR_task_for_pid, task_for_pid),
+ MACXY(__NR_pid_for_task, pid_for_task),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(47)),
+#if defined(VGA_x86)
+// _____(__NR_macx_swapon),
+// _____(__NR_macx_swapoff),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(50)),
+// _____(__NR_macx_triggers),
+// _____(__NR_macx_backing_store_suspend),
+// _____(__NR_macx_backing_store_recovery),
+#else
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(48)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(49)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(50)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(51)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(52)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(53)),
+#endif
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(54)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(55)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(56)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(57)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(58)),
+ MACX_(__NR_swtch_pri, swtch_pri),
+ MACX_(__NR_swtch, swtch), // -60
+ MACX_(__NR_syscall_thread_switch, syscall_thread_switch),
+// _____(__NR_clock_sleep_trap),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(63)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(64)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(65)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(66)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(67)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(68)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(69)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(70)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(71)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(72)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(73)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(74)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(75)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(76)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(77)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(78)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(79)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(80)), // -80
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(81)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(82)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(83)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(84)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(85)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(86)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(87)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(88)),
+ MACXY(__NR_mach_timebase_info, mach_timebase_info),
+ MACX_(__NR_mach_wait_until, mach_wait_until),
+ MACXY(__NR_mk_timer_create, mk_timer_create),
+ MACXY(__NR_mk_timer_destroy, mk_timer_destroy),
+ MACX_(__NR_mk_timer_arm, mk_timer_arm),
+ MACXY(__NR_mk_timer_cancel, mk_timer_cancel),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(95)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(96)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(97)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(98)),
+ _____(VG_DARWIN_SYSCALL_CONSTRUCT_MACH(99)),
+ MACXY(__NR_iokit_user_client_trap, iokit_user_client_trap), // -100
+};
+
+
+// Machine-dependent traps have wacky syscall numbers, and use the Mach trap
+// calling convention instead of the syscall convention.
+// Use ML_(mdep_trap_table)[syscallno - ML_(mdep_trap_base)] .
+
+#if defined(VGA_x86)
+const SyscallTableEntry ML_(mdep_trap_table)[] = {
+ MACX_(__NR_pthread_set_self, pthread_set_self),
+};
+#elif defined(VGA_amd64)
+const SyscallTableEntry ML_(mdep_trap_table)[] = {
+ MACX_(__NR_pthread_set_self, pthread_set_self),
+};
+#else
+#error unknown architecture
+#endif
+
+const UInt ML_(syscall_table_size) =
+ sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);
+
+const UInt ML_(mach_trap_table_size) =
+ sizeof(ML_(mach_trap_table)) / sizeof(ML_(mach_trap_table)[0]);
+
+const UInt ML_(mdep_trap_table_size) =
+ sizeof(ML_(mdep_trap_table)) / sizeof(ML_(mdep_trap_table)[0]);
+
+
+/*--------------------------------------------------------------------*/
+/*--- end syswrap-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c
index 67a6628..a34ccb9 100644
--- a/coregrind/m_syswrap/syswrap-generic.c
+++ b/coregrind/m_syswrap/syswrap-generic.c
@@ -45,6 +45,7 @@
#include "pub_core_libcprint.h"
#include "pub_core_libcproc.h"
#include "pub_core_libcsignal.h"
+#include "pub_core_machine.h" // VG_(get_SP)
#include "pub_core_mallocfree.h"
#include "pub_core_options.h"
#include "pub_core_scheduler.h"
@@ -228,6 +229,7 @@
+#if HAVE_MREMAP
/* Expand (or shrink) an existing mapping, potentially moving it at
the same time (controlled by the MREMAP_MAYMOVE flag). Nightmare.
*/
@@ -502,6 +504,7 @@
# undef MIN_SIZET
}
+#endif /* HAVE_MREMAP */
/* ---------------------------------------------------------------------
@@ -759,6 +762,7 @@
void VG_(init_preopened_fds)(void)
{
// Nb: AIX5 is handled in syswrap-aix5.c.
+// DDD: should probably use HAVE_PROC here or similar, instead.
#if defined(VGO_linux)
Int ret;
struct vki_dirent d;
@@ -793,6 +797,9 @@
out:
VG_(close)(sr_Res(f));
+#elif defined(VGO_darwin)
+ init_preopened_fds_without_proc_self_fd();
+
#else
# error Unknown OS
#endif
@@ -905,6 +912,7 @@
}
}
+/* GrP kernel ignores sa_len (at least on Darwin); this checks the rest */
static
void pre_mem_read_sockaddr ( ThreadId tid,
Char *description,
@@ -929,6 +937,7 @@
case VKI_AF_UNIX:
VG_(sprintf) ( outmsg, description, "sun_path" );
PRE_MEM_RASCIIZ( outmsg, (Addr) sun->sun_path );
+ // GrP fixme max of sun_len-2? what about nul char?
break;
case VKI_AF_INET:
@@ -1576,6 +1585,7 @@
union vki_semun arg = *(union vki_semun *)&arg3;
UInt nsems;
switch (arg2 /* cmd */) {
+#if defined(VKI_IPC_INFO)
case VKI_IPC_INFO:
case VKI_SEM_INFO:
case VKI_IPC_INFO|VKI_IPC_64:
@@ -1583,32 +1593,51 @@
PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)",
(Addr)arg.buf, sizeof(struct vki_seminfo) );
break;
+#endif
+
case VKI_IPC_STAT:
+#if defined(VKI_SEM_STAT)
case VKI_SEM_STAT:
+#endif
PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
(Addr)arg.buf, sizeof(struct vki_semid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_STAT|VKI_IPC_64:
+#if defined(VKI_SEM_STAT)
case VKI_SEM_STAT|VKI_IPC_64:
+#endif
PRE_MEM_WRITE( "semctl(IPC_STAT, arg.buf)",
(Addr)arg.buf, sizeof(struct vki_semid64_ds) );
break;
+#endif
+
case VKI_IPC_SET:
PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
(Addr)arg.buf, sizeof(struct vki_semid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_SET|VKI_IPC_64:
PRE_MEM_READ( "semctl(IPC_SET, arg.buf)",
(Addr)arg.buf, sizeof(struct vki_semid64_ds) );
break;
+#endif
+
case VKI_GETALL:
+#if defined(VKI_IPC_64)
case VKI_GETALL|VKI_IPC_64:
+#endif
nsems = get_sem_count( arg0 );
PRE_MEM_WRITE( "semctl(IPC_GETALL, arg.array)",
(Addr)arg.array, sizeof(unsigned short) * nsems );
break;
+
case VKI_SETALL:
+#if defined(VKI_IPC_64)
case VKI_SETALL|VKI_IPC_64:
+#endif
nsems = get_sem_count( arg0 );
PRE_MEM_READ( "semctl(IPC_SETALL, arg.array)",
(Addr)arg.array, sizeof(unsigned short) * nsems );
@@ -1625,22 +1654,33 @@
union vki_semun arg = *(union vki_semun *)&arg3;
UInt nsems;
switch (arg2 /* cmd */) {
+#if defined(VKI_IPC_INFO)
case VKI_IPC_INFO:
case VKI_SEM_INFO:
case VKI_IPC_INFO|VKI_IPC_64:
case VKI_SEM_INFO|VKI_IPC_64:
POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_seminfo) );
break;
+#endif
+
case VKI_IPC_STAT:
+#if defined(VKI_SEM_STAT)
case VKI_SEM_STAT:
+#endif
POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_STAT|VKI_IPC_64:
case VKI_SEM_STAT|VKI_IPC_64:
POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_semid64_ds) );
break;
+#endif
+
case VKI_GETALL:
+#if defined(VKI_IPC_64)
case VKI_GETALL|VKI_IPC_64:
+#endif
nsems = get_sem_count( arg0 );
POST_MEM_WRITE( (Addr)arg.array, sizeof(unsigned short) * nsems );
break;
@@ -1765,37 +1805,56 @@
{
/* int shmctl(int shmid, int cmd, struct shmid_ds *buf); */
switch (arg1 /* cmd */) {
+#if defined(VKI_IPC_INFO)
case VKI_IPC_INFO:
PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
arg2, sizeof(struct vki_shminfo) );
break;
+#if defined(VKI_IPC_64)
case VKI_IPC_INFO|VKI_IPC_64:
PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)",
arg2, sizeof(struct vki_shminfo64) );
break;
+#endif
+#endif
+
+#if defined(VKI_SHM_INFO)
case VKI_SHM_INFO:
+#if defined(VKI_IPC_64)
case VKI_SHM_INFO|VKI_IPC_64:
+#endif
PRE_MEM_WRITE( "shmctl(SHM_INFO, buf)",
arg2, sizeof(struct vki_shm_info) );
break;
+#endif
+
case VKI_IPC_STAT:
+#if defined(VKI_SHM_STAT)
case VKI_SHM_STAT:
+#endif
PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)",
arg2, sizeof(struct vki_shmid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_STAT|VKI_IPC_64:
case VKI_SHM_STAT|VKI_IPC_64:
PRE_MEM_WRITE( "shmctl(IPC_STAT, arg.buf)",
arg2, sizeof(struct vki_shmid64_ds) );
break;
+#endif
+
case VKI_IPC_SET:
PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
arg2, sizeof(struct vki_shmid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_SET|VKI_IPC_64:
PRE_MEM_READ( "shmctl(IPC_SET, arg.buf)",
arg2, sizeof(struct vki_shmid64_ds) );
break;
+#endif
}
}
@@ -1805,24 +1864,37 @@
UWord arg0, UWord arg1, UWord arg2 )
{
switch (arg1 /* cmd */) {
+#if defined(VKI_IPC_INFO)
case VKI_IPC_INFO:
POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo) );
break;
case VKI_IPC_INFO|VKI_IPC_64:
POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo64) );
break;
+#endif
+
+#if defined(VKI_SHM_INFO)
case VKI_SHM_INFO:
case VKI_SHM_INFO|VKI_IPC_64:
POST_MEM_WRITE( arg2, sizeof(struct vki_shm_info) );
break;
+#endif
+
case VKI_IPC_STAT:
+#if defined(VKI_SHM_STAT)
case VKI_SHM_STAT:
+#endif
POST_MEM_WRITE( arg2, sizeof(struct vki_shmid_ds) );
break;
+
+#if defined(VKI_IPC_64)
case VKI_IPC_STAT|VKI_IPC_64:
case VKI_SHM_STAT|VKI_IPC_64:
POST_MEM_WRITE( arg2, sizeof(struct vki_shmid64_ds) );
break;
+#endif
+
+
}
}
@@ -1866,6 +1938,16 @@
MapRequest mreq;
Bool mreq_ok;
+#if defined(VGO_darwin)
+ // Nb: we can't use this on Darwin, it has races:
+ // * needs to RETRY if advisory succeeds but map fails
+ // (could have been some other thread in a nonblocking call)
+ // * needs to not use fixed-position mmap() on Darwin
+ // (mmap will cheerfully smash whatever's already there, which might
+ // be a new mapping from some other thread in a nonblocking call)
+ VG_(core_panic)("can't use ML_(generic_PRE_sys_mmap) on Darwin");
+#endif
+
if (arg2 == 0) {
/* SuSV3 says: If len is zero, mmap() shall fail and no mapping
shall be established. */
@@ -2004,6 +2086,7 @@
#if VG_WORDSIZE == 4
// Combine two 32-bit values into a 64-bit value
// Always use with low-numbered arg first (e.g. LOHI64(ARG1,ARG2) )
+// GrP fixme correct for ppc-linux?
#define LOHI64(lo,hi) ( ((ULong)(lo)) | (((ULong)(hi)) << 32) )
#endif
@@ -2023,8 +2106,17 @@
PRE(sys_ni_syscall)
{
- // Nb: AIX5 is handled in syswrap-aix5.c.
- PRINT("non-existent syscall! (ni_syscall)");
+ PRINT("unimplemented (by the kernel) syscall %ld! (ni_syscall)\n",
+// Nb: AIX5 is handled in syswrap-aix5.c.
+// DDD: make this generic
+#if defined(VGO_linux)
+ SYSNO
+#elif defined(VGO_darwin)
+ VG_DARWIN_SYSNO_PRINT(SYSNO)
+#else
+# error Unknown OS
+#endif
+ );
PRE_REG_READ0(long, "ni_syscall");
SET_STATUS_Failure( VKI_ENOSYS );
}
@@ -2130,6 +2222,7 @@
PRE_timeval_WRITE( "getitimer(&value->it_interval)", &(value->it_interval));
PRE_timeval_WRITE( "getitimer(&value->it_value)", &(value->it_value));
}
+
POST(sys_getitimer)
{
if (ARG2 != (Addr)NULL) {
@@ -2185,6 +2278,7 @@
unsigned long, start, vki_size_t, length, int, advice);
}
+#if HAVE_MREMAP
PRE(sys_mremap)
{
// Nb: this is different to the glibc version described in the man pages,
@@ -2207,6 +2301,7 @@
do_mremap((Addr)ARG1, ARG2, (Addr)ARG5, ARG3, ARG4, tid)
);
}
+#endif /* HAVE_MREMAP */
PRE(sys_nice)
{
@@ -2811,9 +2906,17 @@
if (!SUCCESS) return;
+#if defined(VGO_linux) || defined(VGO_aix5)
// RES is 0 for child, non-0 (the child's PID) for parent.
is_child = ( RES == 0 ? True : False );
child_pid = ( is_child ? -1 : RES );
+#elif defined(VGO_darwin)
+ // RES is the child's pid. RESHI is 1 for child, 0 for parent.
+ is_child = RESHI;
+ child_pid = RES;
+#else
+# error Unknown OS
+#endif
VG_(do_atfork_pre)(tid);
@@ -2830,7 +2933,7 @@
if (!VG_(logging_to_socket) && VG_(clo_child_silent_after_fork))
VG_(clo_log_fd) = -1;
- } else {
+ } else {
VG_(do_atfork_parent)(tid);
PRINT(" fork: process %d created child %d\n", VG_(getpid)(), child_pid);
@@ -3002,6 +3105,12 @@
{
POST_MEM_WRITE( a2, sizeof(struct vki_rlimit) );
+#ifdef _RLIMIT_POSIX_FLAG
+ // Darwin will sometimes set _RLIMIT_POSIX_FLAG on getrlimit calls.
+ // Unset it here to make the switch case below work correctly.
+ a1 &= ~_RLIMIT_POSIX_FLAG;
+#endif
+
switch (a1) {
case VKI_RLIMIT_NOFILE:
((struct vki_rlimit *)a2)->rlim_cur = VG_(fd_soft_limit);
@@ -3063,6 +3172,7 @@
PRINT("sys_gettimeofday ( %#lx, %#lx )", ARG1,ARG2);
PRE_REG_READ2(long, "gettimeofday",
struct timeval *, tv, struct timezone *, tz);
+ // GrP fixme does darwin write to *tz anymore?
if (ARG1 != 0)
PRE_timeval_WRITE( "gettimeofday(tv)", ARG1 );
if (ARG2 != 0)
@@ -3286,6 +3396,7 @@
if (!ML_(valid_client_addr)(ARG1, ARG2, tid, "mprotect")) {
SET_STATUS_Failure( VKI_ENOMEM );
}
+#if defined(VKI_PROT_GROWSDOWN)
else
if (ARG3 & (VKI_PROT_GROWSDOWN|VKI_PROT_GROWSUP)) {
/* Deal with mprotects on growable stack areas.
@@ -3337,6 +3448,7 @@
SET_STATUS_Failure( VKI_EINVAL );
}
}
+#endif // defined(VKI_PROT_GROWSDOWN)
}
POST(sys_mprotect)
@@ -3412,6 +3524,7 @@
}
PRE_MEM_RASCIIZ( "open(filename)", ARG1 );
+#if HAVE_PROC
/* Handle the case where the open is of /proc/self/cmdline or
/proc/<pid>/cmdline, and just give it a copy of the fd for the
fake file we cooked up at startup (in m_main). Also, seek the
@@ -3436,6 +3549,7 @@
return;
}
}
+#endif // HAVE_PROC
/* Otherwise handle normally */
*flags |= SfMayBlock;
@@ -3558,6 +3672,7 @@
PRE_MEM_WRITE( "readlink(buf)", ARG2,ARG3 );
{
+#if HAVE_PROC
/*
* Handle the case where readlink is looking at /proc/self/exe or
* /proc/<pid>/exe.
@@ -3573,6 +3688,7 @@
SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, (UWord)name,
ARG2, ARG3));
} else
+#endif // HAVE_PROC
{
/* Normal case */
SET_STATUS_from_SysRes( VG_(do_syscall3)(saved, ARG1, ARG2, ARG3));
@@ -3703,12 +3819,19 @@
PRE(sys_setrlimit)
{
+ UWord arg1 = ARG1;
PRINT("sys_setrlimit ( %ld, %#lx )", ARG1,ARG2);
PRE_REG_READ2(long, "setrlimit",
unsigned int, resource, struct rlimit *, rlim);
PRE_MEM_READ( "setrlimit(rlim)", ARG2, sizeof(struct vki_rlimit) );
- if (ARG1 == VKI_RLIMIT_NOFILE) {
+#ifdef _RLIMIT_POSIX_FLAG
+ // Darwin will sometimes set _RLIMIT_POSIX_FLAG on setrlimit calls.
+ // Unset it here to make the if statements below work correctly.
+ arg1 &= ~_RLIMIT_POSIX_FLAG;
+#endif
+
+ if (arg1 == VKI_RLIMIT_NOFILE) {
if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(fd_hard_limit) ||
((struct vki_rlimit *)ARG2)->rlim_max != VG_(fd_hard_limit)) {
SET_STATUS_Failure( VKI_EPERM );
@@ -3718,7 +3841,7 @@
SET_STATUS_Success( 0 );
}
}
- else if (ARG1 == VKI_RLIMIT_DATA) {
+ else if (arg1 == VKI_RLIMIT_DATA) {
if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(client_rlimit_data).rlim_max ||
((struct vki_rlimit *)ARG2)->rlim_max > VG_(client_rlimit_data).rlim_max) {
SET_STATUS_Failure( VKI_EPERM );
@@ -3728,7 +3851,7 @@
SET_STATUS_Success( 0 );
}
}
- else if (ARG1 == VKI_RLIMIT_STACK && tid == 1) {
+ else if (arg1 == VKI_RLIMIT_STACK && tid == 1) {
if (((struct vki_rlimit *)ARG2)->rlim_cur > VG_(client_rlimit_stack).rlim_max ||
((struct vki_rlimit *)ARG2)->rlim_max > VG_(client_rlimit_stack).rlim_max) {
SET_STATUS_Failure( VKI_EPERM );
@@ -3927,7 +4050,6 @@
PRE_timeval_READ( "utimes(tvp[0])", ARG2 );
PRE_timeval_READ( "utimes(tvp[1])", ARG2+sizeof(struct vki_timeval) );
}
-
}
PRE(sys_acct)
diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c
index cc6166b..8238cb5 100644
--- a/coregrind/m_syswrap/syswrap-main.c
+++ b/coregrind/m_syswrap/syswrap-main.c
@@ -29,6 +29,7 @@
*/
#include "libvex_guest_offsets.h"
+#include "libvex_trc_values.h"
#include "pub_core_basics.h"
#include "pub_core_aspacemgr.h"
#include "pub_core_vki.h"
@@ -52,6 +53,9 @@
#include "priv_types_n_macros.h"
#include "priv_syswrap-main.h"
+#if defined(VGO_darwin)
+#include "priv_syswrap-darwin.h"
+#endif
/* Useful info which needs to be recorded somewhere:
Use of registers in syscalls is:
@@ -62,9 +66,19 @@
amd64 rax rdi rsi rdx r10 r8 r9 n/a n/a rax (== NUM)
ppc32 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
ppc64 r0 r3 r4 r5 r6 r7 r8 n/a n/a r3+CR0.SO (== ARG1)
+
AIX:
ppc32 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err)
ppc64 r2 r3 r4 r5 r6 r7 r8 r9 r10 r3(res),r4(err)
+
+ DARWIN:
+ x86 eax +4 +8 +12 +16 +20 +24 +28 +32 edx:eax, eflags.c
+ amd64 rax rdi rsi rdx rcx r8 r9 +8 +16 rdx:rax, rflags.c
+
+ For x86-darwin, "+N" denotes "in memory at N(%esp)"; ditto
+ amd64-darwin. Apparently 0(%esp) is some kind of return address
+ (perhaps for syscalls done with "sysenter"?) I don't think it is
+ relevant for syscalls done with "int $0x80/1/2".
*/
/* This is the top level of the system-call handler module. All
@@ -141,6 +155,10 @@
ppc32: Success(N) ==> r3 = N, CR0.SO = 0
Fail(N) ==> r3 = N, CR0.SO = 1
+ Darwin:
+ x86: Success(N) ==> edx:eax = N, cc = 0
+ Fail(N) ==> edx:eax = N, cc = 1
+
* The post wrapper is called if:
- it exists, and
@@ -255,6 +273,25 @@
const vki_sigset_t *restore_mask,
Word sigsetSzB, /* unused */
Word __nr_sigprocmask );
+#elif defined(VGO_darwin)
+extern
+UWord ML_(do_syscall_for_client_unix_WRK)( Word syscallno,
+ void* guest_state,
+ const vki_sigset_t *syscall_mask,
+ const vki_sigset_t *restore_mask,
+ Word sigsetSzB ); /* unused */
+extern
+UWord ML_(do_syscall_for_client_mach_WRK)( Word syscallno,
+ void* guest_state,
+ const vki_sigset_t *syscall_mask,
+ const vki_sigset_t *restore_mask,
+ Word sigsetSzB ); /* unused */
+extern
+UWord ML_(do_syscall_for_client_mdep_WRK)( Word syscallno,
+ void* guest_state,
+ const vki_sigset_t *syscall_mask,
+ const vki_sigset_t *restore_mask,
+ Word sigsetSzB ); /* unused */
#else
# error "Unknown OS"
#endif
@@ -278,6 +315,31 @@
syscall_mask, &saved, 0/*unused:sigsetSzB*/,
__NR_rt_sigprocmask
);
+# elif defined(VGO_darwin)
+ switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ err = ML_(do_syscall_for_client_unix_WRK)(
+ VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex,
+ syscall_mask, &saved, 0/*unused:sigsetSzB*/
+ );
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ err = ML_(do_syscall_for_client_mach_WRK)(
+ VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex,
+ syscall_mask, &saved, 0/*unused:sigsetSzB*/
+ );
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ err = ML_(do_syscall_for_client_mdep_WRK)(
+ VG_DARWIN_SYSNO_NUM(syscallno), &tst->arch.vex,
+ syscall_mask, &saved, 0/*unused:sigsetSzB*/
+ );
+ break;
+ default:
+ vg_assert(0);
+ /*NOTREACHED*/
+ break;
+ }
# else
# error "Unknown OS"
# endif
@@ -313,6 +375,14 @@
/* was: return s1->what == s2->what && sr_EQ( s1->sres, s2->sres ); */
if (s1->what == s2->what && sr_EQ( s1->sres, s2->sres ))
return True;
+# if defined(VGO_darwin)
+ /* Darwin-specific debugging guff */
+ vg_assert(s1->what == s2->what);
+ VG_(printf)("eq_SyscallStatus:\n");
+ VG_(printf)(" {%lu %lu %u}\n", s1->sres._wLO, s1->sres._wHI, s1->sres._mode);
+ VG_(printf)(" {%lu %lu %u}\n", s2->sres._wLO, s2->sres._wHI, s2->sres._mode);
+ vg_assert(0);
+# endif
return False;
}
@@ -334,7 +404,8 @@
static
void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs* canonical,
- /*IN*/ VexGuestArchState* gst_vanilla )
+ /*IN*/ VexGuestArchState* gst_vanilla,
+ /*IN*/ UInt trc )
{
#if defined(VGP_x86_linux)
VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
@@ -411,6 +482,120 @@
canonical->arg7 = gst->guest_GPR9;
canonical->arg8 = gst->guest_GPR10;
+#elif defined(VGP_x86_darwin)
+ VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+ UWord *stack = (UWord *)gst->guest_ESP;
+ // GrP fixme hope syscalls aren't called with really shallow stacks...
+ canonical->sysno = gst->guest_EAX;
+ if (canonical->sysno != 0) {
+ // stack[0] is return address
+ canonical->arg1 = stack[1];
+ canonical->arg2 = stack[2];
+ canonical->arg3 = stack[3];
+ canonical->arg4 = stack[4];
+ canonical->arg5 = stack[5];
+ canonical->arg6 = stack[6];
+ canonical->arg7 = stack[7];
+ canonical->arg8 = stack[8];
+ } else {
+ // GrP fixme hack handle syscall()
+ // GrP fixme what about __syscall() ?
+ // stack[0] is return address
+ // DDD: the tool can't see that the params have been shifted! Can
+ // lead to incorrect checking, I think, because the PRRAn/PSARn
+ // macros will mention the pre-shifted args.
+ canonical->sysno = stack[1];
+ vg_assert(canonical->sysno != 0);
+ canonical->arg1 = stack[2];
+ canonical->arg2 = stack[3];
+ canonical->arg3 = stack[4];
+ canonical->arg4 = stack[5];
+ canonical->arg5 = stack[6];
+ canonical->arg6 = stack[7];
+ canonical->arg7 = stack[8];
+ canonical->arg8 = stack[9];
+
+ PRINT("SYSCALL[%d,?](%3lld) syscall(#%ld, ...); please stand by...\n",
+ VG_(getpid)(), /*tid,*/ (Long)0, canonical->sysno);
+ }
+
+ // DDD: Would it be better to stash the JMP kind into the Darwin
+ // thread state rather than passing in the trc?
+ switch (trc) {
+ case VEX_TRC_JMP_SYS_INT128:
+ // int $0x80 = Unix, 64-bit result
+ vg_assert(canonical->sysno >= 0);
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno);
+ break;
+ case VEX_TRC_JMP_SYS_SYSENTER:
+ // syscall = Unix, 32-bit result
+ // OR Mach, 32-bit result
+ if (canonical->sysno >= 0) {
+ // GrP fixme hack I386_SYSCALL_NUMBER_MASK
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(canonical->sysno
+ & 0xffff);
+ } else {
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
+ }
+ break;
+ case VEX_TRC_JMP_SYS_INT129:
+ // int $0x81 = Mach, 32-bit result
+ vg_assert(canonical->sysno < 0);
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MACH(-canonical->sysno);
+ break;
+ case VEX_TRC_JMP_SYS_INT130:
+ // int $0x82 = mdep, 32-bit result
+ vg_assert(canonical->sysno >= 0);
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(canonical->sysno);
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+
+#elif defined(VGP_amd64_darwin)
+ VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+ UWord *stack = (UWord *)gst->guest_RSP;
+
+ vg_assert(trc == VEX_TRC_JMP_SYS_SYSCALL);
+
+ // GrP fixme hope syscalls aren't called with really shallow stacks...
+ canonical->sysno = gst->guest_RAX;
+ if (canonical->sysno != __NR_syscall) {
+ // stack[0] is return address
+ canonical->arg1 = gst->guest_RDI;
+ canonical->arg2 = gst->guest_RSI;
+ canonical->arg3 = gst->guest_RDX;
+ canonical->arg4 = gst->guest_R10; // not rcx with syscall insn
+ canonical->arg5 = gst->guest_R8;
+ canonical->arg6 = gst->guest_R9;
+ canonical->arg7 = stack[1];
+ canonical->arg8 = stack[2];
+ } else {
+ // GrP fixme hack handle syscall()
+ // GrP fixme what about __syscall() ?
+ // stack[0] is return address
+ // DDD: the tool can't see that the params have been shifted! Can
+ // lead to incorrect checking, I think, because the PRRAn/PSARn
+ // macros will mention the pre-shifted args.
+ canonical->sysno = VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(gst->guest_RDI);
+ vg_assert(canonical->sysno != __NR_syscall);
+ canonical->arg1 = gst->guest_RSI;
+ canonical->arg2 = gst->guest_RDX;
+ canonical->arg3 = gst->guest_R10; // not rcx with syscall insn
+ canonical->arg4 = gst->guest_R8;
+ canonical->arg5 = gst->guest_R9;
+ canonical->arg6 = stack[1];
+ canonical->arg7 = stack[2];
+ canonical->arg8 = stack[3];
+
+ PRINT("SYSCALL[%d,?](%3lld) syscall(#%lx, ...); please stand by...\n",
+ VG_(getpid)(), /*tid,*/ (Long)0,
+ VG_DARWIN_SYSNO_PRINT(canonical->sysno));
+ }
+
+ // no canonical->sysno adjustment needed
+
#else
# error "getSyscallArgsFromGuestState: unknown arch"
#endif
@@ -484,6 +669,40 @@
gst->guest_GPR9 = canonical->arg7;
gst->guest_GPR10 = canonical->arg8;
+#elif defined(VGP_x86_darwin)
+ VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+ UWord *stack = (UWord *)gst->guest_ESP;
+
+ gst->guest_EAX = VG_DARWIN_SYSNO_NUM(canonical->sysno);
+
+ // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
+ // stack[0] is return address
+ stack[1] = canonical->arg1;
+ stack[2] = canonical->arg2;
+ stack[3] = canonical->arg3;
+ stack[4] = canonical->arg4;
+ stack[5] = canonical->arg5;
+ stack[6] = canonical->arg6;
+ stack[7] = canonical->arg7;
+ stack[8] = canonical->arg8;
+
+#elif defined(VGP_amd64_darwin)
+ VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+ UWord *stack = (UWord *)gst->guest_RSP;
+
+ gst->guest_RAX = VG_DARWIN_SYSNO_NUM(canonical->sysno);
+ // GrP fixme? gst->guest_TEMP_EFLAG_C = 0;
+
+ // stack[0] is return address
+ gst->guest_RDI = canonical->arg1;
+ gst->guest_RSI = canonical->arg2;
+ gst->guest_RDX = canonical->arg3;
+ gst->guest_RCX = canonical->arg4;
+ gst->guest_R8 = canonical->arg5;
+ gst->guest_R9 = canonical->arg6;
+ stack[1] = canonical->arg7;
+ stack[2] = canonical->arg8;
+
#else
# error "putSyscallArgsIntoGuestState: unknown arch"
#endif
@@ -529,13 +748,77 @@
gst->guest_GPR4 );
canonical->what = SsComplete;
+# elif defined(VGP_x86_darwin)
+ /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
+ VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+ UInt carry = 1 & LibVEX_GuestX86_get_eflags(gst);
+ UInt err = 0;
+ UInt wLO = 0;
+ UInt wHI = 0;
+ switch (gst->guest_SC_CLASS) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ // int $0x80 = Unix, 64-bit result
+ err = carry;
+ wLO = gst->guest_EAX;
+ wHI = gst->guest_EDX;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ // int $0x81 = Mach, 32-bit result
+ wLO = gst->guest_EAX;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ // int $0x82 = mdep, 32-bit result
+ wLO = gst->guest_EAX;
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+ canonical->sres = VG_(mk_SysRes_x86_darwin)(
+ gst->guest_SC_CLASS, err ? True : False,
+ wHI, wLO
+ );
+ canonical->what = SsComplete;
+
+# elif defined(VGP_amd64_darwin)
+ /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */
+ VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+ ULong carry = 1 & LibVEX_GuestAMD64_get_rflags(gst);
+ ULong err = 0;
+ ULong wLO = 0;
+ ULong wHI = 0;
+ switch (gst->guest_SC_CLASS) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ // syscall = Unix, 128-bit result
+ err = carry;
+ wLO = gst->guest_RAX;
+ wHI = gst->guest_RDX;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ // syscall = Mach, 64-bit result
+ wLO = gst->guest_RAX;
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ // syscall = mdep, 64-bit result
+ wLO = gst->guest_RAX;
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+ canonical->sres = VG_(mk_SysRes_amd64_darwin)(
+ gst->guest_SC_CLASS, err ? True : False,
+ wHI, wLO
+ );
+ canonical->what = SsComplete;
+
# else
# error "getSyscallStatusFromGuestState: unknown arch"
# endif
}
static
-void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
+void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid,
/*IN*/ SyscallStatus* canonical,
/*OUT*/VexGuestArchState* gst_vanilla )
{
@@ -623,6 +906,72 @@
VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
OFFSET_ppc64_GPR4, sizeof(UWord) );
+#elif defined(VGP_x86_darwin)
+ VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla;
+ SysRes sres = canonical->sres;
+ vg_assert(canonical->what == SsComplete);
+ /* Unfortunately here we have to break abstraction and look
+ directly inside 'res', in order to decide what to do. */
+ switch (sres._mode) {
+ case SysRes_MACH: // int $0x81 = Mach, 32-bit result
+ case SysRes_MDEP: // int $0x82 = mdep, 32-bit result
+ gst->guest_EAX = sres._wLO;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_x86_EAX, sizeof(UInt) );
+ break;
+ case SysRes_UNIX_OK: // int $0x80 = Unix, 64-bit result
+ case SysRes_UNIX_ERR: // int $0x80 = Unix, 64-bit error
+ gst->guest_EAX = sres._wLO;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_x86_EAX, sizeof(UInt) );
+ gst->guest_EDX = sres._wHI;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_x86_EDX, sizeof(UInt) );
+ LibVEX_GuestX86_put_eflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
+ gst );
+ // GrP fixme sets defined for entire eflags, not just bit c
+ // DDD: this breaks exp-ptrcheck.
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ offsetof(VexGuestX86State, guest_CC_DEP1), sizeof(UInt) );
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+
+#elif defined(VGP_amd64_darwin)
+ VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla;
+ SysRes sres = canonical->sres;
+ vg_assert(canonical->what == SsComplete);
+ /* Unfortunately here we have to break abstraction and look
+ directly inside 'res', in order to decide what to do. */
+ switch (sres._mode) {
+ case SysRes_MACH: // syscall = Mach, 64-bit result
+ case SysRes_MDEP: // syscall = mdep, 64-bit result
+ gst->guest_RAX = sres._wLO;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_amd64_RAX, sizeof(ULong) );
+ break;
+ case SysRes_UNIX_OK: // syscall = Unix, 128-bit result
+ case SysRes_UNIX_ERR: // syscall = Unix, 128-bit error
+ gst->guest_RAX = sres._wLO;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_amd64_RAX, sizeof(ULong) );
+ gst->guest_RDX = sres._wHI;
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ OFFSET_amd64_RDX, sizeof(ULong) );
+ LibVEX_GuestAMD64_put_rflag_c( sres._mode==SysRes_UNIX_ERR ? 1 : 0,
+ gst );
+ // GrP fixme sets defined for entire rflags, not just bit c
+ // DDD: this breaks exp-ptrcheck.
+ VG_TRACK( post_reg_write, Vg_CoreSysCall, tid,
+ offsetof(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) );
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+
# else
# error "putSyscallStatusIntoGuestState: unknown arch"
# endif
@@ -702,6 +1051,29 @@
layout->o_arg7 = OFFSET_ppc64_GPR9;
layout->o_arg8 = OFFSET_ppc64_GPR10;
+#elif defined(VGP_x86_darwin)
+ layout->o_sysno = OFFSET_x86_EAX;
+ // syscall parameters are on stack in C convention
+ layout->s_arg1 = sizeof(UWord) * 1;
+ layout->s_arg2 = sizeof(UWord) * 2;
+ layout->s_arg3 = sizeof(UWord) * 3;
+ layout->s_arg4 = sizeof(UWord) * 4;
+ layout->s_arg5 = sizeof(UWord) * 5;
+ layout->s_arg6 = sizeof(UWord) * 6;
+ layout->s_arg7 = sizeof(UWord) * 7;
+ layout->s_arg8 = sizeof(UWord) * 8;
+
+#elif defined(VGP_amd64_darwin)
+ layout->o_sysno = OFFSET_amd64_RAX;
+ layout->o_arg1 = OFFSET_amd64_RDI;
+ layout->o_arg2 = OFFSET_amd64_RSI;
+ layout->o_arg3 = OFFSET_amd64_RDX;
+ layout->o_arg4 = OFFSET_amd64_RCX;
+ layout->o_arg5 = OFFSET_amd64_R8;
+ layout->o_arg6 = OFFSET_amd64_R9;
+ layout->s_arg7 = sizeof(UWord) * 1;
+ layout->s_arg8 = sizeof(UWord) * 2;
+
#else
# error "getSyscallLayout: unknown arch"
#endif
@@ -723,11 +1095,20 @@
/*OUT*/UWord* flags )
{
VG_(message)
- (Vg_DebugMsg,"WARNING: unhandled syscall: %llu", (ULong)args->sysno);
-# if defined(VGO_aix5)
+ (Vg_DebugMsg,"WARNING: unhandled syscall: %lld", (Long)args->sysno);
+ // DDD: make this generic with a common function.
+# if defined(VGO_linux)
+ // nothing
+# elif defined(VGO_aix5)
VG_(message)
(Vg_DebugMsg," name of syscall: \"%s\"",
VG_(aix5_sysno_to_sysname)(args->sysno));
+# elif defined(VGO_darwin)
+ VG_(message)
+ (Vg_DebugMsg," a.k.a.: %lld",
+ (Long)VG_DARWIN_SYSNO_PRINT(args->sysno));
+# else
+# error unknown OS
# endif
if (VG_(clo_verbosity) > 1) {
VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
@@ -747,7 +1128,7 @@
static SyscallTableEntry bad_sys =
{ bad_before, NULL };
-static const SyscallTableEntry* get_syscall_entry ( UInt syscallno )
+static const SyscallTableEntry* get_syscall_entry ( Int syscallno )
{
const SyscallTableEntry* sys = NULL;
@@ -762,6 +1143,30 @@
# elif defined(VGP_ppc64_aix5)
sys = ML_(get_ppc64_aix5_syscall_entry) ( syscallno );
+# elif defined(VGO_darwin)
+ Int idx = VG_DARWIN_SYSNO_INDEX(syscallno);
+
+ switch (VG_DARWIN_SYSNO_CLASS(syscallno)) {
+ case VG_DARWIN_SYSCALL_CLASS_UNIX:
+ if (idx >= 0 && idx < ML_(syscall_table_size) &&
+ ML_(syscall_table)[idx].before != NULL)
+ sys = &ML_(syscall_table)[idx];
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MACH:
+ if (idx >= 0 && idx < ML_(mach_trap_table_size) &&
+ ML_(mach_trap_table)[idx].before != NULL)
+ sys = &ML_(mach_trap_table)[idx];
+ break;
+ case VG_DARWIN_SYSCALL_CLASS_MDEP:
+ if (idx >= 0 && idx < ML_(mdep_trap_table_size) &&
+ ML_(mdep_trap_table)[idx].before != NULL)
+ sys = &ML_(mdep_trap_table)[idx];
+ break;
+ default:
+ vg_assert(0);
+ break;
+ }
+
# else
# error Unknown OS
# endif
@@ -815,7 +1220,7 @@
/* --- This is the main function of this file. --- */
-void VG_(client_syscall) ( ThreadId tid )
+void VG_(client_syscall) ( ThreadId tid, UInt trc )
{
Word sysno;
ThreadState* tst;
@@ -924,7 +1329,7 @@
sci = & syscallInfo[tid];
vg_assert(sci->status.what == SsIdle);
- getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex );
+ getSyscallArgsFromGuestState( &sci->orig_args, &tst->arch.vex, trc );
/* Copy .orig_args to .args. The pre-handler may modify .args, but
we want to keep the originals too, just in case. */
@@ -934,6 +1339,19 @@
is interrupted by a signal. */
sysno = sci->orig_args.sysno;
+# if defined(VGO_darwin)
+ /* Record syscall class. But why? Because the syscall might be
+ interrupted by a signal, and in the signal handler (which will
+ be m_signals.async_signalhandler) we will need to build a SysRes
+ reflecting the syscall return result. In order to do that we
+ need to know the syscall class. Hence stash it in the guest
+ state of this thread. This madness is not needed on Linux or
+ AIX5, because those OSs only have a single syscall return
+ convention and so there is no ambiguity involved in converting
+ the post-signal machine state into a SysRes. */
+ tst->arch.vex.guest_SC_CLASS = VG_DARWIN_SYSNO_CLASS(sysno);
+# endif
+
/* The default what-to-do-next thing is hand the syscall to the
kernel, so we pre-set that here. Set .sres to something
harmless looking (is irrelevant because .what is not
@@ -967,7 +1385,16 @@
sci->flags is zero.
*/
- PRINT("SYSCALL[%d,%d](%3lld) ", VG_(getpid)(), tid, (ULong)sysno);
+ PRINT("SYSCALL[%d,%d](%3lld) ", VG_(getpid)(), tid,
+ // DDD: make this generic
+ #if defined(VGO_linux) || defined(VGO_aix5)
+ (Long)sysno
+ #elif defined(VGO_darwin)
+ (Long)VG_DARWIN_SYSNO_PRINT(sysno)
+ #else
+ # error Unknown OS
+ #endif
+ );
/* Do any pre-syscall actions */
if (VG_(needs).syscall_wrapper) {
@@ -1055,7 +1482,12 @@
/* Gack. More impedance matching. Copy the possibly
modified syscall args back into the guest state. */
- vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
+ /* JRS 2009-Mar-16: if the syscall args are possibly modified,
+ then this assertion is senseless:
+ vg_assert(eq_SyscallArgs(&sci->args, &sci->orig_args));
+ The case that exposed it was sys_posix_spawn on Darwin,
+ which heavily modifies its arguments but then lets the call
+ go through anyway, with SfToBlock set, hence we end up here. */
putSyscallArgsIntoGuestState( &sci->args, &tst->arch.vex );
/* Drop the bigLock */
@@ -1077,6 +1509,13 @@
VG_(post_syscall). Once that's done, control drops back
to the scheduler. */
+ /* Darwin: do_syscall_for_client may not return if the
+ syscall was workq_ops(WQOPS_THREAD_RETURN) and the kernel
+ responded by starting the thread at wqthread_hijack(reuse=1)
+ (to run another workqueue item). In that case, wqthread_hijack
+ calls ML_(wqthread_continue), which is similar to
+ VG_(fixup_guest_state_after_syscall_interrupted). */
+
/* Reacquire the lock */
VG_(acquire_BigLock)(tid, "VG_(client_syscall)[async]");
@@ -1089,6 +1528,10 @@
if (VG_(clo_trace_syscalls)) {
Bool failed = sr_isError(sci->status.sres);
Word tmp_sysno = sysno;
+# if defined(VGO_darwin)
+ // DDD: genericise this
+ tmp_sysno = VG_DARWIN_SYSNO_PRINT(tmp_sysno);
+# endif
if (failed) {
PRINT("SYSCALL[%d,%d](%3ld) ... [async] --> Failure(0x%llx)",
VG_(getpid)(), tid, tmp_sysno,
@@ -1165,6 +1608,7 @@
There are two ways to get here: the normal way -- being called by
VG_(client_syscall), and the unusual way, from
VG_(fixup_guest_state_after_syscall_interrupted).
+ Darwin: there's a third way, ML_(wqthread_continue).
*/
void VG_(post_syscall) (ThreadId tid)
{
@@ -1198,6 +1642,15 @@
getSyscallStatusFromGuestState( &test_status, &tst->arch.vex );
if (!(sci->flags & SfNoWriteResult))
vg_assert(eq_SyscallStatus( &sci->status, &test_status ));
+ /* Failure of the above assertion on Darwin can indicate a problem
+ in the syscall wrappers that pre-fail or pre-succeed the
+ syscall, by calling SET_STATUS_Success or SET_STATUS_Failure,
+ when they really should call SET_STATUS_from_SysRes. The former
+ create a UNIX-class syscall result on Darwin, which may not be
+ correct for the syscall; if that's the case then this assertion
+ fires. See PRE(pthread_set_self) for an example. On non-Darwin
+ platforms this assertion is should never fail, and this comment
+ is completely irrelevant. */
/* Ok, looks sane */
/* Get the system call number. Because the pre-handler isn't
@@ -1283,6 +1736,23 @@
extern const Addr ML_(blksys_complete);
extern const Addr ML_(blksys_committed);
extern const Addr ML_(blksys_finished);
+#elif defined(VGO_darwin)
+ /* Darwin requires extra uglyness */
+ extern const Addr ML_(blksys_setup_MACH);
+ extern const Addr ML_(blksys_restart_MACH);
+ extern const Addr ML_(blksys_complete_MACH);
+ extern const Addr ML_(blksys_committed_MACH);
+ extern const Addr ML_(blksys_finished_MACH);
+ extern const Addr ML_(blksys_setup_MDEP);
+ extern const Addr ML_(blksys_restart_MDEP);
+ extern const Addr ML_(blksys_complete_MDEP);
+ extern const Addr ML_(blksys_committed_MDEP);
+ extern const Addr ML_(blksys_finished_MDEP);
+ extern const Addr ML_(blksys_setup_UNIX);
+ extern const Addr ML_(blksys_restart_UNIX);
+ extern const Addr ML_(blksys_complete_UNIX);
+ extern const Addr ML_(blksys_committed_UNIX);
+ extern const Addr ML_(blksys_finished_UNIX);
#else
# error "Unknown OS"
#endif
@@ -1375,6 +1845,34 @@
vg_assert(p[0] == 0x44 && p[1] == 0x0 && p[2] == 0x0 && p[3] == 0x2);
}
+#elif defined(VGP_x86_darwin)
+ arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL;
+
+ /* Make sure our caller is actually sane, and we're really backing
+ back over a syscall.
+
+ int $0x80 == CD 80
+ int $0x81 == CD 81
+ int $0x82 == CD 82
+ sysenter == 0F 34
+ */
+ {
+ UChar *p = (UChar *)arch->vex.guest_EIP;
+ Bool ok = (p[0] == 0xCD && p[1] == 0x80)
+ || (p[0] == 0xCD && p[1] == 0x81)
+ || (p[0] == 0xCD && p[1] == 0x82)
+ || (p[0] == 0x0F && p[1] == 0x34);
+ if (!ok)
+ VG_(message)(Vg_DebugMsg,
+ "?! restarting over syscall at %#x %02x %02x\n",
+ arch->vex.guest_EIP, p[0], p[1]);
+ vg_assert(ok);
+ }
+
+#elif defined(VGP_amd64_darwin)
+ // DDD: #warning GrP fixme amd64 restart unimplemented
+ vg_assert(0);
+
#else
# error "ML_(fixup_guest_state_to_restart_syscall): unknown plat"
#endif
@@ -1450,6 +1948,28 @@
= ip >= ML_(blksys_complete) && ip < ML_(blksys_committed);
in_committed_to_finished
= ip >= ML_(blksys_committed) && ip < ML_(blksys_finished);
+# elif defined(VGO_darwin)
+ outside_range
+ = (ip < ML_(blksys_setup_MACH) || ip >= ML_(blksys_finished_MACH))
+ && (ip < ML_(blksys_setup_MDEP) || ip >= ML_(blksys_finished_MDEP))
+ && (ip < ML_(blksys_setup_UNIX) || ip >= ML_(blksys_finished_UNIX));
+ in_setup_to_restart
+ = (ip >= ML_(blksys_setup_MACH) && ip < ML_(blksys_restart_MACH))
+ || (ip >= ML_(blksys_setup_MDEP) && ip < ML_(blksys_restart_MDEP))
+ || (ip >= ML_(blksys_setup_UNIX) && ip < ML_(blksys_restart_UNIX));
+ at_restart
+ = (ip == ML_(blksys_restart_MACH))
+ || (ip == ML_(blksys_restart_MDEP))
+ || (ip == ML_(blksys_restart_UNIX));
+ in_complete_to_committed
+ = (ip >= ML_(blksys_complete_MACH) && ip < ML_(blksys_committed_MACH))
+ || (ip >= ML_(blksys_complete_MDEP) && ip < ML_(blksys_committed_MDEP))
+ || (ip >= ML_(blksys_complete_UNIX) && ip < ML_(blksys_committed_UNIX));
+ in_committed_to_finished
+ = (ip >= ML_(blksys_committed_MACH) && ip < ML_(blksys_finished_MACH))
+ || (ip >= ML_(blksys_committed_MDEP) && ip < ML_(blksys_finished_MDEP))
+ || (ip >= ML_(blksys_committed_UNIX) && ip < ML_(blksys_finished_UNIX));
+ /* Wasn't that just So Much Fun? Does your head hurt yet? Mine does. */
# else
# error "Unknown OS"
# endif
@@ -1558,6 +2078,45 @@
}
+#if defined(VGO_darwin)
+// Clean up after workq_ops(WQOPS_THREAD_RETURN) jumped to wqthread_hijack.
+// This is similar to VG_(fixup_guest_state_after_syscall_interrupted).
+// This longjmps back to the scheduler.
+void ML_(wqthread_continue_NORETURN)(ThreadId tid)
+{
+ ThreadState* tst;
+ SyscallInfo* sci;
+
+ VG_(acquire_BigLock)(tid, "wqthread_continue_NORETURN");
+
+ PRINT("SYSCALL[%d,%d](%3lld) workq_ops() starting new workqueue item\n",
+ VG_(getpid)(), tid, (Long)VG_DARWIN_SYSNO_PRINT(__NR_workq_ops));
+
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(tid >= 1 && tid < VG_N_THREADS);
+ vg_assert(VG_(is_running_thread)(tid));
+
+ tst = VG_(get_ThreadState)(tid);
+ sci = & syscallInfo[tid];
+ vg_assert(sci->status.what != SsIdle);
+ vg_assert(tst->os_state.wq_jmpbuf_valid); // check this BEFORE post_syscall
+
+ // Pretend the syscall completed normally, but don't touch the thread state.
+ sci->status = convert_SysRes_to_SyscallStatus( VG_(mk_SysRes_Success)(0) );
+ sci->flags |= SfNoWriteResult;
+ VG_(post_syscall)(tid);
+
+ sci->status.what = SsIdle;
+
+ vg_assert(tst->sched_jmpbuf_valid);
+ __builtin_longjmp(tst->sched_jmpbuf, True);
+
+ /* NOTREACHED */
+ vg_assert(0);
+}
+#endif
+
+
/* ---------------------------------------------------------------------
A place to store the where-to-call-when-really-done pointer
------------------------------------------------------------------ */
diff --git a/coregrind/m_syswrap/syswrap-x86-darwin.c b/coregrind/m_syswrap/syswrap-x86-darwin.c
new file mode 100644
index 0000000..5532033
--- /dev/null
+++ b/coregrind/m_syswrap/syswrap-x86-darwin.c
@@ -0,0 +1,502 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific syscalls, etc. syswrap-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+#include "pub_core_threadstate.h"
+#include "pub_core_aspacemgr.h"
+#include "pub_core_xarray.h"
+#include "pub_core_clientstate.h"
+#include "pub_core_debuglog.h"
+#include "pub_core_debuginfo.h" // VG_(di_notify_*)
+#include "pub_core_transtab.h" // VG_(discard_translations)
+#include "pub_core_libcbase.h"
+#include "pub_core_libcassert.h"
+#include "pub_core_libcfile.h"
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_libcsignal.h"
+#include "pub_core_mallocfree.h"
+#include "pub_core_options.h"
+#include "pub_core_scheduler.h"
+#include "pub_core_signals.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_tooliface.h"
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h" /* for decls of generic wrappers */
+#include "priv_syswrap-darwin.h" /* for decls of darwin-ish wrappers */
+#include "priv_syswrap-main.h"
+
+
+#include <mach/mach.h>
+
+static void x86_thread_state32_from_vex(i386_thread_state_t *mach,
+ VexGuestX86State *vex)
+{
+ mach->__eax = vex->guest_EAX;
+ mach->__ebx = vex->guest_EBX;
+ mach->__ecx = vex->guest_ECX;
+ mach->__edx = vex->guest_EDX;
+ mach->__edi = vex->guest_EDI;
+ mach->__esi = vex->guest_ESI;
+ mach->__ebp = vex->guest_EBP;
+ mach->__esp = vex->guest_ESP;
+ mach->__ss = vex->guest_SS;
+ mach->__eflags = LibVEX_GuestX86_get_eflags(vex);
+ mach->__eip = vex->guest_EIP;
+ mach->__cs = vex->guest_CS;
+ mach->__ds = vex->guest_DS;
+ mach->__es = vex->guest_ES;
+ mach->__fs = vex->guest_FS;
+ mach->__gs = vex->guest_GS;
+}
+
+
+static void x86_float_state32_from_vex(i386_float_state_t *mach,
+ VexGuestX86State *vex)
+{
+ // DDD: #warning GrP fixme fp state
+
+ VG_(memcpy)(&mach->__fpu_xmm0, &vex->guest_XMM0, 8 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_from_vex(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic)
+{
+ VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
+
+ switch (flavor) {
+ case i386_THREAD_STATE:
+ vg_assert(count == i386_THREAD_STATE_COUNT);
+ x86_thread_state32_from_vex((i386_thread_state_t *)mach_generic, vex);
+ break;
+
+ case i386_FLOAT_STATE:
+ vg_assert(count == i386_FLOAT_STATE_COUNT);
+ x86_float_state32_from_vex((i386_float_state_t *)mach_generic, vex);
+ break;
+
+ default:
+ vg_assert(0);
+ }
+}
+
+
+static void x86_thread_state32_to_vex(const i386_thread_state_t *mach,
+ VexGuestX86State *vex)
+{
+ LibVEX_GuestX86_initialise(vex);
+ vex->guest_EAX = mach->__eax;
+ vex->guest_EBX = mach->__ebx;
+ vex->guest_ECX = mach->__ecx;
+ vex->guest_EDX = mach->__edx;
+ vex->guest_EDI = mach->__edi;
+ vex->guest_ESI = mach->__esi;
+ vex->guest_EBP = mach->__ebp;
+ vex->guest_ESP = mach->__esp;
+ vex->guest_SS = mach->__ss;
+ // DDD: #warning GrP fixme eflags
+ vex->guest_EIP = mach->__eip;
+ vex->guest_CS = mach->__cs;
+ vex->guest_DS = mach->__ds;
+ vex->guest_ES = mach->__es;
+ vex->guest_FS = mach->__fs;
+ vex->guest_GS = mach->__gs;
+}
+
+static void x86_float_state32_to_vex(const i386_float_state_t *mach,
+ VexGuestX86State *vex)
+{
+ // DDD: #warning GrP fixme fp state
+
+ VG_(memcpy)(&vex->guest_XMM0, &mach->__fpu_xmm0, 8 * sizeof(mach->__fpu_xmm0));
+}
+
+
+void thread_state_to_vex(const thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ VexGuestArchState *vex_generic)
+{
+ VexGuestX86State *vex = (VexGuestX86State *)vex_generic;
+
+ switch(flavor) {
+ case i386_THREAD_STATE:
+ vg_assert(count == i386_THREAD_STATE_COUNT);
+ x86_thread_state32_to_vex((const i386_thread_state_t*)mach_generic,vex);
+ break;
+ case i386_FLOAT_STATE:
+ vg_assert(count == i386_FLOAT_STATE_COUNT);
+ x86_float_state32_to_vex((const i386_float_state_t*)mach_generic,vex);
+ break;
+
+ default:
+ vg_assert(0);
+ break;
+ }
+}
+
+
+ThreadState *build_thread(const thread_state_t state,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count)
+{
+ ThreadId tid = VG_(alloc_ThreadState)();
+ ThreadState *tst = VG_(get_ThreadState)(tid);
+
+ vg_assert(flavor == i386_THREAD_STATE);
+ vg_assert(count == i386_THREAD_STATE_COUNT);
+
+ // Initialize machine registers
+
+ thread_state_to_vex(state, flavor, count, &tst->arch.vex);
+
+ I_die_here;
+ // GrP fixme signals, sig_mask, tmp_sig_mask, os_state.parent
+
+ find_stack_segment(tid, tst->arch.vex.guest_ESP);
+
+ return tst;
+}
+
+
+// Edit the thread state to send to the real kernel.
+// The real thread will run start_thread_NORETURN(tst)
+// on a separate non-client stack.
+void hijack_thread_state(thread_state_t mach_generic,
+ thread_state_flavor_t flavor,
+ mach_msg_type_number_t count,
+ ThreadState *tst)
+{
+ i386_thread_state_t *mach = (i386_thread_state_t *)mach_generic;
+ char *stack;
+
+ vg_assert(flavor == i386_THREAD_STATE);
+ vg_assert(count == i386_THREAD_STATE_COUNT);
+
+ stack = (char *)allocstack(tst->tid);
+ stack -= 64+320; // make room for top frame
+ memset(stack, 0, 64+320); // ...and clear it
+ *(uintptr_t *)stack = (uintptr_t)tst; // set parameter
+ stack -= sizeof(uintptr_t);
+ *(uintptr_t *)stack = 0; // push fake return address
+
+ mach->__eip = (uintptr_t)&start_thread_NORETURN;
+ mach->__esp = (uintptr_t)stack;
+}
+
+
+/* Call f(arg1), but first switch stacks, using 'stack' as the new
+ stack, and use 'retaddr' as f's return-to address. Also, clear all
+ the integer registers before entering f.*/
+__attribute__((noreturn))
+void call_on_new_stack_0_1 ( Addr stack,
+ Addr retaddr,
+ void (*f)(Word),
+ Word arg1 );
+// 4(%esp) == stack (must be 16-byte aligned)
+// 8(%esp) == retaddr
+// 12(%esp) == f
+// 16(%esp) == arg1
+asm(
+".globl _call_on_new_stack_0_1\n"
+"_call_on_new_stack_0_1:\n"
+" movl %esp, %esi\n" // remember old stack pointer
+" movl 4(%esi), %esp\n" // set new stack
+" pushl $0\n" // align stack
+" pushl $0\n" // align stack
+" pushl $0\n" // align stack
+" pushl 16(%esi)\n" // arg1 to stack
+" pushl 8(%esi)\n" // retaddr to stack
+" pushl 12(%esi)\n" // f to stack
+" movl $0, %eax\n" // zero all GP regs
+" movl $0, %ebx\n"
+" movl $0, %ecx\n"
+" movl $0, %edx\n"
+" movl $0, %esi\n"
+" movl $0, %edi\n"
+" movl $0, %ebp\n"
+" ret\n" // jump to f
+" ud2\n" // should never get here
+);
+
+
+asm(
+".globl _pthread_hijack_asm\n"
+"_pthread_hijack_asm:\n"
+" movl %esp,%ebp\n"
+" push $0\n" // alignment pad
+" push %ebp\n" // original sp
+" push %esi\n" // flags
+" push %edi\n" // stacksize
+" push %edx\n" // func_arg
+" push %ecx\n" // func
+" push %ebx\n" // kport
+" push %eax\n" // self
+" push $0\n" // fake return address
+" jmp _pthread_hijack\n"
+ );
+
+
+
+void pthread_hijack(Addr self, Addr kport, Addr func, Addr func_arg,
+ Addr stacksize, Addr flags, Addr sp)
+{
+ vki_sigset_t blockall;
+ ThreadState *tst = (ThreadState *)func_arg;
+ VexGuestX86State *vex = &tst->arch.vex;
+
+ // VG_(printf)("pthread_hijack pthread %p, machthread %p, func %p, arg %p, stack %p, flags %p, stack %p\n", self, kport, func, func_arg, stacksize, flags, sp);
+
+ // Wait for parent thread's permission.
+ // The parent thread holds V's lock on our behalf.
+ semaphore_wait(tst->os_state.child_go);
+
+ /* Start the thread with all signals blocked. VG_(scheduler) will
+ set the mask correctly when we finally get there. */
+ VG_(sigfillset)(&blockall);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
+
+ // Set thread's registers
+ // Do this FIRST because some code below tries to collect a backtrace,
+ // which requires valid register data.
+ // DDD: need to do post_reg_write events here?
+ LibVEX_GuestX86_initialise(vex);
+ vex->guest_EIP = pthread_starter;
+ vex->guest_EAX = self;
+ vex->guest_EBX = kport;
+ vex->guest_ECX = func;
+ vex->guest_EDX = tst->os_state.func_arg;
+ vex->guest_EDI = stacksize;
+ vex->guest_ESI = flags;
+ vex->guest_ESP = sp;
+
+ // Record thread's stack and Mach port and pthread struct
+ tst->os_state.pthread = self;
+ tst->os_state.lwpid = kport;
+ record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "thread-%p");
+
+ if ((flags & 0x01000000) == 0) {
+ // kernel allocated stack - needs mapping
+ Addr stack = VG_PGROUNDUP(sp) - stacksize;
+ tst->client_stack_highest_word = stack+stacksize;
+ tst->client_stack_szB = stacksize;
+
+ // pthread structure
+ ML_(notify_core_and_tool_of_mmap)(
+ stack+stacksize, pthread_structsize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // stack contents
+ ML_(notify_core_and_tool_of_mmap)(
+ stack, stacksize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // guard page
+ ML_(notify_core_and_tool_of_mmap)(
+ stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
+ 0, VKI_MAP_PRIVATE, -1, 0);
+ } else {
+ // client allocated stack
+ find_stack_segment(tst->tid, sp);
+ }
+ VG_(am_do_sync_check)("after", "pthread_hijack", 0);
+
+ // DDD: should this be here rather than in POST(sys_bsdthread_create)?
+ // But we don't have ptid here...
+ //VG_TRACK ( pre_thread_ll_create, ptid, tst->tid );
+
+ // Tell parent thread's POST(sys_bsdthread_create) that we're done
+ // initializing registers and mapping memory.
+ semaphore_signal(tst->os_state.child_done);
+ // LOCK IS GONE BELOW THIS POINT
+
+ // Go!
+ call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
+ start_thread_NORETURN, (Word)tst);
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+
+
+asm(
+".globl _wqthread_hijack_asm\n"
+"_wqthread_hijack_asm:\n"
+" movl %esp,%ebp\n"
+" push $0\n" // alignment
+" push $0\n" // alignment
+" push %ebp\n" // original sp
+" push %edi\n" // reuse
+" push %edx\n" // workitem
+" push %ecx\n" // stackaddr
+" push %ebx\n" // kport
+" push %eax\n" // self
+" push $0\n" // fake return address
+" jmp _wqthread_hijack\n"
+ );
+
+
+/* wqthread note: The kernel may create or destroy pthreads in the
+ wqthread pool at any time with no userspace interaction,
+ and wqthread_start may be entered at any time with no userspace
+ interaction.
+ To handle this in valgrind, we create and destroy a valgrind
+ thread for every work item.
+*/
+void wqthread_hijack(Addr self, Addr kport, Addr stackaddr, Addr workitem,
+ Int reuse, Addr sp)
+{
+ ThreadState *tst;
+ VexGuestX86State *vex;
+ Addr stack;
+ SizeT stacksize;
+ vki_sigset_t blockall;
+
+ /* When we enter here we hold no lock (!), so we better acquire it
+ pronto. Why do we hold no lock? Because (presumably) the only
+ way to get here is as a result of a SfMayBlock syscall
+ "workq_ops(WQOPS_THREAD_RETURN)", which will have dropped the
+ lock. At least that's clear for the 'reuse' case. The
+ non-reuse case? Dunno, perhaps it's a new thread the kernel
+ pulled out of a hat. In any case we still need to take a
+ lock. */
+ VG_(acquire_BigLock_LL)("wqthread_hijack");
+
+ /* Start the thread with all signals blocked. VG_(scheduler) will
+ set the mask correctly when we finally get there. */
+ VG_(sigfillset)(&blockall);
+ VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, NULL);
+
+ if (reuse) {
+ // This thread already exists; we're merely re-entering
+ // after leaving via workq_ops(WQOPS_THREAD_RETURN).
+ // Don't allocate any V thread resources.
+ // Do reset thread registers.
+ ThreadId tid = VG_(lwpid_to_vgtid)(kport);
+ vg_assert(VG_(is_valid_tid)(tid));
+ vg_assert(mach_thread_self() == kport);
+
+ tst = VG_(get_ThreadState)(tid);
+ vex = &tst->arch.vex;
+ vg_assert(tst->os_state.pthread == self);
+ }
+ else {
+ // This is a new thread.
+ tst = VG_(get_ThreadState)(VG_(alloc_ThreadState)());
+ vex = &tst->arch.vex;
+ allocstack(tst->tid);
+ LibVEX_GuestX86_initialise(vex);
+ }
+
+ // Set thread's registers
+ // Do this FIRST because some code below tries to collect a backtrace,
+ // which requires valid register data.
+ vex->guest_EIP = wqthread_starter;
+ vex->guest_EAX = self;
+ vex->guest_EBX = kport;
+ vex->guest_ECX = stackaddr;
+ vex->guest_EDX = workitem;
+ vex->guest_EDI = reuse;
+ vex->guest_ESI = 0;
+ vex->guest_ESP = sp;
+
+ stacksize = 512*1024; // wq stacks are always DEFAULT_STACK_SIZE
+ stack = VG_PGROUNDUP(sp) - stacksize;
+
+ if (reuse) {
+ // Continue V's thread back in the scheduler.
+ // The client thread is of course in another location entirely.
+
+ /* Drop the lock before going into
+ ML_(wqthread_continue_NORETURN). The latter will immediately
+ attempt to reacquire it in non-LL mode, which is a bit
+ wasteful but I don't think is harmful. A better solution
+ would be to not drop the lock but instead "upgrade" it from a
+ LL lock to a full lock, but that's too much like hard work
+ right now. */
+ VG_(release_BigLock_LL)("wqthread_hijack(1)");
+ ML_(wqthread_continue_NORETURN)(tst->tid);
+ }
+ else {
+ // Record thread's stack and Mach port and pthread struct
+ tst->os_state.pthread = self;
+ tst->os_state.lwpid = kport;
+ record_named_port(tst->tid, kport, MACH_PORT_RIGHT_SEND, "wqthread-%p");
+
+ // kernel allocated stack - needs mapping
+ tst->client_stack_highest_word = stack+stacksize;
+ tst->client_stack_szB = stacksize;
+
+ // GrP fixme scheduler lock?!
+
+ // pthread structure
+ ML_(notify_core_and_tool_of_mmap)(
+ stack+stacksize, pthread_structsize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // stack contents
+ // GrP fixme uninitialized!
+ ML_(notify_core_and_tool_of_mmap)(
+ stack, stacksize,
+ VKI_PROT_READ|VKI_PROT_WRITE, VKI_MAP_PRIVATE, -1, 0);
+ // guard page
+ // GrP fixme ban_mem_stack!
+ ML_(notify_core_and_tool_of_mmap)(
+ stack-VKI_PAGE_SIZE, VKI_PAGE_SIZE,
+ 0, VKI_MAP_PRIVATE, -1, 0);
+
+ VG_(am_do_sync_check)("after", "wqthread_hijack", 0);
+
+ // Go!
+ /* Same comments as the 'release' in the then-clause.
+ start_thread_NORETURN calls run_thread_NORETURN calls
+ thread_wrapper which acquires the lock before continuing.
+ Let's hope nothing non-thread-local happens until that point.
+
+ DDD: I think this is plain wrong .. if we get to
+ thread_wrapper not holding the lock, and someone has recycled
+ this thread slot in the meantime, we're hosed. Is that
+ possible, though? */
+ VG_(release_BigLock_LL)("wqthread_hijack(2)");
+ call_on_new_stack_0_1(tst->os_state.valgrind_stack_init_SP, 0,
+ start_thread_NORETURN, (Word)tst);
+ }
+
+ /*NOTREACHED*/
+ vg_assert(0);
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end syswrap-x86-darwin.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S
index d267172..e52076d 100644
--- a/coregrind/m_trampoline.S
+++ b/coregrind/m_trampoline.S
@@ -735,7 +735,307 @@
# undef UD2_256
# undef UD2_1024
# undef UD2_PAGE
+
+/*---------------- x86-darwin ----------------*/
+#else
+#if defined(VGP_x86_darwin)
+
+ /* a leading page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+.globl VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+.globl VG_(x86_darwin_SUBST_FOR_sigreturn)
+VG_(x86_darwin_SUBST_FOR_sigreturn):
+ /* XXX does this need to have any special form? (cf x86-linux
+ version) */
+ movl $ __NR_DARWIN_FAKE_SIGRETURN, %eax
+ int $0x80
+ ud2
+
+.globl VG_(darwin_REDIR_FOR_strlen)
+VG_(darwin_REDIR_FOR_strlen):
+ movl 4(%esp), %edx
+ movl %edx, %eax
+ jmp 1f
+0:
+ incl %eax
+1:
+ cmpb $0, (%eax)
+ jne 0b
+ subl %edx, %eax
+ ret
+
+.globl VG_(darwin_REDIR_FOR_strcat)
+VG_(darwin_REDIR_FOR_strcat):
+ pushl %esi
+ movl 8(%esp), %esi
+ movl 12(%esp), %ecx
+ movl %esi, %edx
+ jmp 1f
+0:
+ incl %edx
+1:
+ cmpb $0, (%edx)
+ jne 0b
+2:
+ movzbl (%ecx), %eax
+ incl %ecx
+ movb %al, (%edx)
+ incl %edx
+ testb %al, %al
+ jne 2b
+ movl %esi, %eax
+ popl %esi
+ ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcmp)
+VG_(darwin_REDIR_FOR_strcmp):
+ movl 4(%esp), %edx
+ movl 8(%esp), %ecx
+ jmp 1f
+0:
+ incl %edx
+ incl %ecx
+1:
+ movzbl (%edx), %eax
+ testb %al, %al
+ je 2f
+ cmpb (%ecx), %al
+ je 0b
+2:
+ movzbl (%ecx),%edx
+ movzbl %al,%eax
+ subl %edx, %eax
+ ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcpy)
+VG_(darwin_REDIR_FOR_strcpy):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %esi
+ movl 8(%ebp), %esi
+ movl 12(%ebp), %ecx
+ movl %esi, %edx
+ jmp 1f
+0:
+ incl %ecx
+ incl %edx
+1:
+ movzbl (%ecx), %eax
+ testb %al, %al
+ movb %al, (%edx)
+ jne 0b
+ movl %esi, %eax
+ popl %esi
+ leave
+ ret
+
+.globl VG_(darwin_REDIR_FOR_strlcat)
+VG_(darwin_REDIR_FOR_strlcat):
+ pushl %ebp
+ movl %esp, %ebp
+ pushl %edi
+ pushl %esi
+ subl $16, %esp
+ movl 8(%ebp), %esi
+ movl 16(%ebp), %ecx
+ movl %esi, %edx
+ leal (%ecx,%esi), %eax
+ jmp 1f
+0:
+ incl %edx
+1:
+ cmpl %edx, %eax
+ je 2f
+ cmpb $0, (%edx)
+ jne 0b
+2:
+ movl %edx, %edi
+ subl %esi, %edi
+ movl %ecx, %esi
+ subl %edi, %esi
+ je 3f
+ movl 12(%ebp), %eax
+ jmp 6f
+3:
+ movl 12(%ebp), %eax
+ movl %eax, (%esp)
+ call VG_(darwin_REDIR_FOR_strlen)
+ jmp 7f
+4:
+ cmpl $1, %esi
+ je 5f
+ movb %cl, (%edx)
+ decl %esi
+ incl %edx
+5:
+ incl %eax
+6:
+ movzbl (%eax), %ecx
+ testb %cl, %cl
+ jne 4b
+ movb $0, (%edx)
+ subl 12(%ebp), %eax
+7:
+ addl $16, %esp
+ leal (%edi,%eax), %eax
+ popl %esi
+ popl %edi
+ leave
+ ret
+
+.globl VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+ /* a trailing page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+
+/*---------------- amd64-darwin ----------------*/
+#else
+#if defined(VGP_amd64_darwin)
+
+ /* a leading page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+.globl VG_(trampoline_stuff_start)
+VG_(trampoline_stuff_start):
+
+.globl VG_(darwin_REDIR_FOR_strlen)
+VG_(darwin_REDIR_FOR_strlen):
+ movq %rdi, %rax
+ jmp 1f
+0:
+ incq %rax
+1:
+ cmpb $0, (%rax)
+ jne 0b
+ subq %rdi, %rax
+ ret
+
+.globl VG_(darwin_REDIR_FOR_strcat)
+VG_(darwin_REDIR_FOR_strcat):
+ movq %rdi, %rdx
+ jmp 1f
+0:
+ incq %rdx
+1:
+ cmpb $0, (%rdx)
+ jne 0b
+2:
+ movzbl (%rsi), %eax
+ incq %rsi
+ movb %al, (%rdx)
+ incq %rdx
+ testb %al, %al
+ jne 2b
+ movq %rdi, %rax
+ ret
+
+
+.globl VG_(darwin_REDIR_FOR_strcmp)
+VG_(darwin_REDIR_FOR_strcmp):
+ jmp 1f
+0:
+ incq %rdi
+ incq %rsi
+1:
+ movzbl (%rdi), %eax
+ testb %al, %al
+ je 2f
+ cmpb (%rsi), %al
+ je 0b
+2:
+ movzbl (%rsi), %edx
+ movzbl %al, %eax
+ subl %edx, %eax
+ ret
+
+.globl VG_(darwin_REDIR_FOR_strcpy)
+VG_(darwin_REDIR_FOR_strcpy):
+ pushq %rbp
+ movq %rdi, %rdx
+ movq %rsp, %rbp
+ jmp 1f
+0:
+ incq %rsi
+ incq %rdx
+1:
+ movzbl (%rsi), %eax
+ testb %al, %al
+ movb %al, (%rdx)
+ jne 0b
+ leave
+ movq %rdi, %rax
+ ret
+
+.globl VG_(darwin_REDIR_FOR_strlcat)
+VG_(darwin_REDIR_FOR_strlcat):
+ pushq %rbp
+ leaq (%rdx,%rdi), %rax
+ movq %rdi, %rcx
+ movq %rsp, %rbp
+ pushq %rbx
+ subq $8, %rsp
+ jmp 1f
+0:
+ incq %rcx
+1:
+ cmpq %rcx, %rax
+ je 2f
+ cmpb $0, (%rcx)
+ jne 0b
+2:
+ movq %rcx, %rbx
+ subq %rdi, %rbx
+ movq %rdx, %rdi
+ subq %rbx, %rdi
+ je 3f
+ movq %rsi, %rax
+ jmp 6f
+3:
+ movq %rsi, %rdi
+ call VG_(darwin_REDIR_FOR_strlen)
+ jmp 7f
+4:
+ cmpq $1, %rdi
+ je 5f
+ movb %dl, (%rcx)
+ decq %rdi
+ incq %rcx
+5:
+ incq %rax
+6:
+ movzbl (%rax), %edx
+ testb %dl, %dl
+ jne 4b
+ movb $0, (%rcx)
+ subq %rsi, %rax
+7:
+ leaq (%rbx,%rax), %rax
+ addq $8, %rsp
+ popq %rbx
+ leave
+ ret
+
+.globl VG_(darwin_REDIR_FOR_arc4random)
+VG_(darwin_REDIR_FOR_arc4random):
+ /* not very random, hope dyld won't mind */
+ movq $0x76616c6772696e64, %rax
+ ret
+
+.globl VG_(trampoline_stuff_end)
+VG_(trampoline_stuff_end):
+
+ /* a trailing page of unexecutable code */
+.fill 2048, 2, 0x0b0f /* `ud2` */
+
+
/*---------------- unknown ----------------*/
#else
# error Unknown platform
@@ -746,6 +1046,8 @@
#endif
#endif
#endif
+#endif
+#endif
#if defined(VGO_linux)
/* Let the linker know we don't need an executable stack */
diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c
index ea7ec46..1e1f049 100644
--- a/coregrind/m_translate.c
+++ b/coregrind/m_translate.c
@@ -708,6 +708,14 @@
static Bool self_check_required ( NSegment const* seg, ThreadId tid )
{
+#if defined(VGO_darwin)
+ // GrP fixme hack - dyld i386 IMPORT gets rewritten
+ // to really do this correctly, we'd need to flush the
+ // translation cache whenever a segment became +WX
+ if (seg->hasX && seg->hasW) {
+ return True;
+ }
+#endif
switch (VG_(clo_smc_check)) {
case Vg_SmcNone: return False;
case Vg_SmcAll: return True;
@@ -1417,6 +1425,9 @@
# if defined(VGP_amd64_linux)
vex_abiinfo.guest_amd64_assume_fs_is_zero = True;
# endif
+# if defined(VGP_amd64_darwin)
+ vex_abiinfo.guest_amd64_assume_gs_is_0x60 = True;
+# endif
# if defined(VGP_ppc32_linux)
vex_abiinfo.guest_ppc_zap_RZ_at_blr = False;
vex_abiinfo.guest_ppc_zap_RZ_at_bl = NULL;
diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c
index f771960..8dfbb1f 100644
--- a/coregrind/m_ume/elf.c
+++ b/coregrind/m_ume/elf.c
@@ -44,7 +44,6 @@
#include "priv_ume.h"
-
#if defined(HAVE_ELF)
/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
diff --git a/coregrind/m_ume/macho.c b/coregrind/m_ume/macho.c
new file mode 100644
index 0000000..db5db4f
--- /dev/null
+++ b/coregrind/m_ume/macho.c
@@ -0,0 +1,776 @@
+
+/*--------------------------------------------------------------------*/
+/*--- User-mode execve() for Mach-O executables m_ume_macho.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics.h"
+#include "pub_core_vki.h"
+
+#include "pub_core_aspacemgr.h" // various mapping fns
+#include "pub_core_debuglog.h"
+#include "pub_core_libcassert.h" // VG_(exit), vg_assert
+#include "pub_core_libcbase.h" // VG_(memcmp), etc
+#include "pub_core_libcfile.h" // VG_(open) et al
+#include "pub_core_libcprint.h"
+#include "pub_core_libcproc.h"
+#include "pub_core_machine.h" // VG_ELF_CLASS (XXX: which should be moved)
+#include "pub_core_mallocfree.h" // VG_(malloc), VG_(free)
+#include "pub_core_syscall.h" // VG_(strerror)
+#include "pub_core_ume.h" // self
+
+#include "priv_ume.h"
+
+
+#if defined(HAVE_MACHO)
+
+#include <mach/mach.h>
+
+#include <mach-o/dyld.h>
+#include <mach-o/fat.h>
+#include <mach-o/loader.h>
+
+#if VG_WORDSIZE == 4
+#define MAGIC MH_MAGIC
+#define MACH_HEADER mach_header
+#define LC_SEGMENT_CMD LC_SEGMENT
+#define SEGMENT_COMMAND segment_command
+#define SECTION section
+#else
+#define MAGIC MH_MAGIC_64
+#define MACH_HEADER mach_header_64
+#define LC_SEGMENT_CMD LC_SEGMENT_64
+#define SEGMENT_COMMAND segment_command_64
+#define SECTION section_64
+#endif
+
+
+static void print(const char *str)
+{
+ VG_(printf)("%s", str);
+}
+
+static void check_mmap(SysRes res, Addr base, SizeT len)
+{
+ if (sr_isError(res)) {
+ VG_(printf)("valgrind: mmap(0x%llx, %lld) failed in UME.\n",
+ (ULong)base, (Long)len);
+ VG_(exit)(1);
+ }
+}
+
+
+static int
+load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+static int
+load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+static int
+load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry);
+
+
+/* Open and map a dylinker file.
+ Returns 0 on success, -1 on any failure.
+ filename must be an absolute path.
+ The dylinker's entry point is returned in *out_linker_entry.
+ */
+static int
+open_dylinker(const char *filename, vki_uint8_t **out_linker_entry)
+{
+ struct vg_stat sb;
+ vki_size_t filesize;
+ SysRes res;
+ int fd;
+ int err;
+
+ if (filename[0] != '/') {
+ print("bad executable (dylinker name is not an absolute path)\n");
+ return -1;
+ }
+
+ res = VG_(open)(filename, VKI_O_RDONLY, 0);
+ fd = sr_Res(res);
+ if (sr_isError(res)) {
+ print("couldn't open dylinker: ");
+ print(filename);
+ print("\n");
+ return -1;
+ }
+ err = VG_(fstat)(fd, &sb);
+ if (err) {
+ print("couldn't stat dylinker: ");
+ print(filename);
+ print("\n");
+ VG_(close)(fd);
+ return -1;
+ }
+ filesize = sb.size;
+
+ err = load_mach_file(fd, 0, filesize, MH_DYLINKER, filename,
+ NULL, NULL, NULL, out_linker_entry, NULL);
+ if (err) {
+ print("...while loading dylinker: ");
+ print(filename);
+ print("\n");
+ }
+ VG_(close)(fd);
+ return err;
+}
+
+
+/*
+ Process an LC_SEGMENT command, mapping it into memory if appropriate.
+ fd[offset..size) is a Mach-O thin file.
+ Returns 0 on success, -1 on any failure.
+ If this segment contains the executable's Mach headers, their
+ loaded address is returned in *text.
+ If this segment is a __UNIXSTACK, its start address is returned in
+ *stack_start.
+*/
+static int
+load_segment(int fd, vki_off_t offset, vki_off_t size,
+ vki_uint8_t **text, vki_uint8_t **stack_start,
+ struct SEGMENT_COMMAND *segcmd, const HChar *filename)
+{
+ SysRes res;
+ Addr addr;
+ vki_size_t filesize; // page-aligned
+ vki_size_t vmsize; // page-aligned
+ unsigned int prot;
+
+ // GrP fixme mark __UNIXSTACK as SF_STACK
+
+#if VG_WORDSIZE == 8
+ if (segcmd->vmaddr == 0 && 0 == VG_(strcmp)(segcmd->segname, SEG_PAGEZERO)) {
+ if (segcmd->vmsize != 0x100000000) {
+ print("bad executable (__PAGEZERO is not 4 GB)\n");
+ return -1;
+ }
+ return 0;
+ }
+#endif
+
+ // Record the segment containing the Mach headers themselves
+ if (segcmd->fileoff == 0 && segcmd->filesize != 0) {
+ if (text) *text = (vki_uint8_t *)segcmd->vmaddr;
+ }
+
+ // Record the __UNIXSTACK start
+ if (0 == VG_(strcmp)(segcmd->segname, SEG_UNIXSTACK)) {
+ if (stack_start) *stack_start = (vki_uint8_t *)segcmd->vmaddr;
+ }
+
+ // Sanity-check the segment
+ if (segcmd->fileoff + segcmd->filesize > size) {
+ print("bad executable (invalid segment command)\n");
+ return -1;
+ }
+ if (segcmd->vmsize == 0) {
+ return 0; // nothing to map - ok
+ }
+
+ // Get desired memory protection
+ // GrP fixme need maxprot too
+ prot = (((segcmd->initprot & VM_PROT_READ) ? VKI_PROT_READ : 0) |
+ ((segcmd->initprot & VM_PROT_WRITE) ? VKI_PROT_WRITE : 0) |
+ ((segcmd->initprot & VM_PROT_EXECUTE) ? VKI_PROT_EXEC : 0));
+
+ // Map the segment
+ filesize = VG_PGROUNDUP(segcmd->filesize);
+ vmsize = VG_PGROUNDUP(segcmd->vmsize);
+ if (filesize > 0) {
+ addr = (Addr)segcmd->vmaddr;
+ res = VG_(am_mmap_named_file_fixed_client)(addr, filesize, prot, fd,
+ offset + segcmd->fileoff,
+ filename);
+ check_mmap(res, addr, filesize);
+ }
+
+ // Zero-fill the remainder of the segment, if any
+ if (segcmd->filesize != filesize) {
+ // non-page-aligned part
+ // GrP fixme kernel doesn't do this?
+ //bzero(segcmd->filesize+(vki_uint8_t *)addr, filesize-segcmd->filesize);
+ }
+ if (filesize != vmsize) {
+ // page-aligned part
+ SizeT length = vmsize - filesize;
+ addr = (Addr)(filesize + segcmd->vmaddr);
+ res = VG_(am_mmap_anon_fixed_client)(addr, length, prot);
+ check_mmap(res, addr, length);
+ }
+
+ return 0;
+}
+
+
+/*
+ Parse a LC_THREAD or LC_UNIXTHREAD command.
+ Return 0 on success, -1 on any failure.
+ The stack address is returned in *stack. If the executable requested
+ a non-default stack address, *customstack is set to TRUE. The thread's
+ entry point is returned in *entry.
+ The stack itself (if any) is not mapped.
+ Other custom register settings are silently ignored (GrP fixme).
+*/
+static int
+load_genericthread(vki_uint8_t **stack_end,
+ int *customstack, vki_uint8_t **entry,
+ struct thread_command *threadcmd)
+{
+ unsigned int flavor;
+ unsigned int count;
+ unsigned int *p;
+ unsigned int left;
+
+ p = (unsigned int *)(threadcmd + 1);
+ left = (threadcmd->cmdsize - sizeof(struct thread_command)) / sizeof(*p);
+
+ while (left > 0) {
+ if (left < 2) {
+ print("bad executable (invalid thread command)\n");
+ return -1;
+ }
+ flavor = *p++; left--;
+ count = *p++; left--;
+
+ if (left < count) {
+ print("bad executable (invalid thread command 2)\n");
+ return -1;
+ }
+
+#if defined(VGA_x86)
+ if (flavor == i386_THREAD_STATE && count == i386_THREAD_STATE_COUNT) {
+ i386_thread_state_t *state = (i386_thread_state_t *)p;
+ if (entry) *entry = (vki_uint8_t *)state->__eip;
+ if (stack_end) *stack_end = (vki_uint8_t *)(state->__esp ? state->__esp : VKI_USRSTACK);
+ if (customstack) *customstack = state->__esp;
+ return 0;
+ }
+
+#elif defined(VGA_amd64)
+ if (flavor == x86_THREAD_STATE64 && count == x86_THREAD_STATE64_COUNT){
+ x86_thread_state64_t *state = (x86_thread_state64_t *)p;
+ if (entry) *entry = (vki_uint8_t *)state->__rip;
+ if (stack_end) *stack_end = (vki_uint8_t *)(state->__rsp ? state->__rsp : VKI_USRSTACK64);
+ if (customstack) *customstack = state->__rsp;
+ return 0;
+ }
+
+#else
+# error unknown platform
+#endif
+ p += count;
+ left -= count;
+ }
+
+ print("bad executable (no arch-compatible thread state)\n");
+ return -1;
+}
+
+
+/* Returns the main stack size on this platform,
+ using getrlimit or a fixed size.
+ GrP fixme 64-bit? */
+static vki_size_t default_stack_size(void)
+{
+ struct vki_rlimit lim;
+ int err = VG_(getrlimit)(VKI_RLIMIT_STACK, &lim);
+ if (err) return 8*1024*1024; // 8 MB
+ else return lim.rlim_cur;
+}
+
+
+/*
+ Processes a LC_UNIXTHREAD command.
+ Returns 0 on success, -1 on any failure.
+ The stack is mapped in and returned in *out_stack.
+ The thread's entry point is returned in *out_entry.
+*/
+static int
+load_unixthread(vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_entry, struct thread_command *threadcmd)
+{
+ int err;
+ vki_uint8_t *stack_end;
+ int customstack;
+
+ err = load_genericthread(&stack_end, &customstack, out_entry, threadcmd);
+ if (err) return -1;
+
+ if (!stack_end) {
+ print("bad executable (no thread stack)\n");
+ return -1;
+ }
+
+ if (!customstack) {
+ // Map the stack
+ vki_size_t stacksize = VG_PGROUNDUP(default_stack_size());
+ vm_address_t stackbase = VG_PGROUNDDN(stack_end-stacksize);
+ SysRes res;
+
+ res = VG_(am_mmap_anon_fixed_client)(stackbase, stacksize, VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC);
+ check_mmap(res, stackbase, stacksize);
+ if (out_stack_start) *out_stack_start = (vki_uint8_t *)stackbase;
+ } else {
+ // custom stack - mapped via __UNIXTHREAD segment
+ }
+
+ if (out_stack_end) *out_stack_end = stack_end;
+
+ return 0;
+}
+
+
+/*
+ Processes an LC_LOAD_DYLINKER command.
+ Returns 0 on success, -1 on any error.
+ The linker itself is mapped into memory.
+ The linker's entry point is returned in *linker_entry.
+*/
+static int
+load_dylinker(vki_uint8_t **linker_entry, struct dylinker_command *dycmd)
+{
+ const char *name;
+
+ if (dycmd->name.offset >= dycmd->cmdsize) {
+ print("bad executable (invalid dylinker command)\n");
+ return -1;
+ }
+
+ name = dycmd->name.offset + (char *)dycmd;
+
+ // GrP fixme assumes name is terminated somewhere
+ return open_dylinker(name, linker_entry);
+}
+
+
+/*
+ Process an LC_THREAD command.
+ Returns 0 on success, -1 on any failure.
+ The thread's entry point is returned in *out_entry.
+*/
+static int
+load_thread(vki_uint8_t **out_entry, struct thread_command *threadcmd)
+{
+ int customstack;
+ int err;
+
+ err = load_genericthread(NULL, &customstack, out_entry, threadcmd);
+ if (err) return -1;
+ if (customstack) {
+ print("bad executable (stackless thread has stack)\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ Loads a Mach-O executable into memory, along with any threads,
+ stacks, and dylinker.
+ Returns 0 on success, -1 on any failure.
+ fd[offset..offset+size) is a Mach-O thin file.
+ filetype is MH_EXECUTE or MH_DYLINKER.
+ The mapped but empty stack is returned in *out_stack.
+ The executable's Mach headers are returned in *out_text.
+ The executable's entry point is returned in *out_entry.
+ The dylinker's entry point (if any) is returned in *out_linker_entry.
+ GrP fixme need to return whether dylinker was found - stack layout is different
+*/
+static int
+load_thin_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+ struct MACH_HEADER mh;
+ vki_uint8_t *headers;
+ vki_uint8_t *headers_end;
+ struct load_command *lc;
+ struct load_command *lcend;
+ struct SEGMENT_COMMAND *segcmd;
+ struct thread_command *threadcmd;
+ struct dylinker_command *dycmd;
+ int err;
+ SysRes res;
+ vki_size_t len;
+
+ vki_uint8_t *stack_start = NULL; // allocated thread stack (hot end)
+ vki_uint8_t *stack_end = NULL; // allocated thread stack (cold end)
+ vki_uint8_t *entry = NULL; // static entry point
+ vki_uint8_t *text = NULL; // start of text segment (i.e. the mach headers)
+ vki_uint8_t *linker_entry = NULL; // dylinker entry point
+
+ // Read Mach-O header
+ if (sizeof(mh) > size) {
+ print("bad executable (no Mach-O header)\n");
+ }
+ res = VG_(pread)(fd, &mh, sizeof(mh), offset);
+ if (sr_isError(res) || sr_Res(res) != sizeof(mh)) {
+ print("bad executable (no Mach-O header)\n");
+ return -1;
+ }
+
+
+ // Sanity-check the header itself
+ if (mh.magic != MAGIC) {
+ print("bad executable (no Mach-O magic)\n");
+ return -1;
+ }
+
+ if (mh.filetype != filetype) {
+ // expecting MH_EXECUTE or MH_DYLINKER
+ print("bad executable (wrong file type)\n");
+ return -1;
+ }
+
+
+ // Map all headers into memory
+ len = sizeof(mh) + mh.sizeofcmds;
+ if (len > size) {
+ print("bad executable (missing load commands)\n");
+ return -1;
+ }
+
+ headers = VG_(malloc)("ume.macho.headers", len);
+ res = VG_(pread)(fd, headers, len, offset);
+ if (sr_isError(res)) {
+ print("couldn't read load commands from executable\n");
+ return -1;
+ }
+ headers_end = headers + size;
+
+
+ // Map some segments into client memory:
+ // LC_SEGMENT (text, data, etc)
+ // UNIXSTACK (stack)
+ // LOAD_DYLINKER (dyld)
+ lcend = (struct load_command *)(headers + mh.sizeofcmds + sizeof(mh));
+ for (lc = (struct load_command *)(headers + sizeof(mh));
+ lc < lcend;
+ lc = (struct load_command *)(lc->cmdsize + (vki_uint8_t *)lc))
+ {
+ if ((vki_uint8_t *)lc < headers ||
+ lc->cmdsize+(vki_uint8_t *)lc > headers_end) {
+ print("bad executable (invalid load commands)\n");
+ return -1;
+ }
+
+ switch (lc->cmd) {
+ case LC_SEGMENT_CMD:
+ if (lc->cmdsize < sizeof(struct SEGMENT_COMMAND)) {
+ print("bad executable (invalid load commands)\n");
+ return -1;
+ }
+ segcmd = (struct SEGMENT_COMMAND *)lc;
+ err = load_segment(fd, offset, size, &text, &stack_start,
+ segcmd, filename);
+ if (err) return -1;
+
+ break;
+
+ case LC_UNIXTHREAD:
+ if (stack_end || entry) {
+ print("bad executable (multiple thread commands)\n");
+ return -1;
+ }
+ if (lc->cmdsize < sizeof(struct thread_command)) {
+ print("bad executable (invalid load commands)\n");
+ return -1;
+ }
+ threadcmd = (struct thread_command *)lc;
+ err = load_unixthread(&stack_start, &stack_end, &entry, threadcmd);
+ if (err) return -1;
+ break;
+
+ case LC_LOAD_DYLINKER:
+ if (filetype == MH_DYLINKER) {
+ print("bad executable (dylinker needs a dylinker)\n");
+ return -1;
+ }
+ if (linker_entry) {
+ print("bad executable (multiple dylinker commands)\n");
+ }
+ if (lc->cmdsize < sizeof(struct dylinker_command)) {
+ print("bad executable (invalid load commands)\n");
+ return -1;
+ }
+ dycmd = (struct dylinker_command *)lc;
+ err = load_dylinker(&linker_entry, dycmd);
+ if (err) return -1;
+ break;
+
+ case LC_THREAD:
+ if (filetype == MH_EXECUTE) {
+ print("bad executable (stackless thread)\n");
+ return -1;
+ }
+ if (stack_end || entry) {
+ print("bad executable (multiple thread commands)\n");
+ return -1;
+ }
+ if (lc->cmdsize < sizeof(struct thread_command)) {
+ print("bad executable (invalid load commands)\n");
+ return -1;
+ }
+ threadcmd = (struct thread_command *)lc;
+ err = load_thread(&entry, threadcmd);
+ if (err) return -1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+
+ // Done with the headers
+ VG_(free)(headers);
+
+ if (filetype == MH_EXECUTE) {
+ // Verify the necessary pieces for an executable:
+ // a stack
+ // a text segment
+ // an entry point (static or linker)
+ if (!stack_end || !stack_start) {
+ print("bad executable (no stack)\n");
+ return -1;
+ }
+ if (!text) {
+ print("bad executable (no text segment)\n");
+ return -1;
+ }
+ if (!entry && !linker_entry) {
+ print("bad executable (no entry point)\n");
+ return -1;
+ }
+ }
+ else if (filetype == MH_DYLINKER) {
+ // Verify the necessary pieces for a dylinker:
+ // an entry point
+ if (!entry) {
+ print("bad executable (no entry point)\n");
+ return -1;
+ }
+ }
+
+ if (out_stack_start) *out_stack_start = stack_start;
+ if (out_stack_end) *out_stack_end = stack_end;
+ if (out_text) *out_text = text;
+ if (out_entry) *out_entry = entry;
+ if (out_linker_entry) *out_linker_entry = linker_entry;
+
+ return 0;
+}
+
+
+/*
+ Load a fat Mach-O executable.
+*/
+static int
+load_fat_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+ struct fat_header fh;
+ vki_off_t arch_offset;
+ int i;
+ cpu_type_t good_arch;
+ SysRes res;
+
+#if defined(VGA_ppc32)
+ good_arch = CPU_TYPE_POWERPC;
+#elif defined(VGA_ppc64)
+ good_arch = CPU_TYPE_POWERPC64;
+#elif defined(VGA_x86)
+ good_arch = CPU_TYPE_I386;
+#elif defined(VGA_amd64)
+ good_arch = CPU_TYPE_X86_64;
+#else
+# error unknown architecture
+#endif
+
+ // Read fat header
+ // All fat contents are BIG-ENDIAN
+ if (size < sizeof(fh)) {
+ print("bad executable (bad fat header)\n");
+ return -1;
+ }
+ res = VG_(pread)(fd, &fh, sizeof(fh), offset);
+ if (sr_isError(res) || sr_Res(res) != sizeof(fh)) {
+ print("bad executable (bad fat header)\n");
+ return -1;
+ }
+
+ // Scan arch headers looking for a good one
+ arch_offset = offset + sizeof(fh);
+ fh.nfat_arch = VG_(ntohl)(fh.nfat_arch);
+ for (i = 0; i < fh.nfat_arch; i++) {
+ struct fat_arch arch;
+ if (arch_offset + sizeof(arch) > size) {
+ print("bad executable (corrupt fat archs)\n");
+ return -1;
+ }
+
+ res = VG_(pread)(fd, &arch, sizeof(arch), arch_offset);
+ arch_offset += sizeof(arch);
+ if (sr_isError(res) || sr_Res(res) != sizeof(arch)) {
+ VG_(printf)("bad executable (corrupt fat arch) %x %llu\n",
+ arch.cputype, (ULong)arch_offset);
+ return -1;
+ }
+
+ arch.cputype = VG_(ntohl)(arch.cputype);
+ arch.cpusubtype = VG_(ntohl)(arch.cpusubtype);
+ arch.offset = VG_(ntohl)(arch.offset);
+ arch.size = VG_(ntohl)(arch.size);
+ arch.align = VG_(ntohl)(arch.align);
+ if (arch.cputype == good_arch) {
+ // use this arch
+ if (arch.offset > size || arch.offset + arch.size > size) {
+ print("bad executable (corrupt fat arch 2)\n");
+ return -1;
+ }
+ return load_mach_file(fd, offset+arch.offset, arch.size, filetype,
+ filename, out_stack_start, out_stack_end,
+ out_text, out_entry, out_linker_entry);
+ }
+ }
+
+ print("bad executable (can't run on this machine)\n");
+ return -1;
+}
+
+/*
+ Load a Mach-O executable or dylinker.
+ The file may be fat or thin.
+*/
+static int
+load_mach_file(int fd, vki_off_t offset, vki_off_t size, unsigned long filetype,
+ const char *filename,
+ vki_uint8_t **out_stack_start, vki_uint8_t **out_stack_end,
+ vki_uint8_t **out_text, vki_uint8_t **out_entry, vki_uint8_t **out_linker_entry)
+{
+ vki_uint32_t magic;
+ SysRes res;
+
+ if (size < sizeof(magic)) {
+ print("bad executable (no Mach-O magic)\n");
+ return -1;
+ }
+ res = VG_(pread)(fd, &magic, sizeof(magic), offset);
+ if (sr_isError(res) || sr_Res(res) != sizeof(magic)) {
+ print("bad executable (no Mach-O magic)\n");
+ return -1;
+ }
+
+ if (magic == MAGIC) {
+ // thin
+ return load_thin_file(fd, offset, size, filetype, filename,
+ out_stack_start, out_stack_end,
+ out_text, out_entry, out_linker_entry);
+ } else if (magic == VG_(htonl)(FAT_MAGIC)) {
+ // fat
+ return load_fat_file(fd, offset, size, filetype, filename,
+ out_stack_start, out_stack_end,
+ out_text, out_entry, out_linker_entry);
+ } else {
+ // huh?
+ print("bad executable (bad Mach-O magic)\n");
+ return -1;
+ }
+}
+
+
+Bool VG_(match_macho)(Char *hdr, Int len)
+{
+ vki_uint32_t *magic = (vki_uint32_t *)hdr;
+
+ // GrP fixme check more carefully for matching fat arch?
+
+ return (len >= VKI_PAGE_SIZE &&
+ (*magic == MAGIC || *magic == VG_(ntohl)(FAT_MAGIC)))
+ ? True : False;
+}
+
+
+Int VG_(load_macho)(Int fd, const HChar *name, ExeInfo *info)
+{
+ int err;
+ struct vg_stat sb;
+ vki_uint8_t *stack_start;
+ vki_uint8_t *stack_end;
+ vki_uint8_t *text;
+ vki_uint8_t *entry;
+ vki_uint8_t *linker_entry;
+
+ err = VG_(fstat)(fd, &sb);
+ if (err) {
+ print("couldn't stat executable\n");
+ return VKI_ENOEXEC;
+ }
+
+ err = load_mach_file(fd, 0, sb.size, MH_EXECUTE, name,
+ &stack_start, &stack_end,
+ &text, &entry, &linker_entry);
+ if (err) return VKI_ENOEXEC;
+
+ // GrP fixme exe_base
+ // GrP fixme exe_end
+ info->entry = (Addr)entry;
+ info->init_ip = (Addr)(linker_entry ? linker_entry : entry);
+ info->brkbase = 0xffffffff; // GrP fixme hack
+ info->init_toc = 0; // GrP fixme unused
+
+ info->stack_start = (Addr)stack_start;
+ info->stack_end = (Addr)stack_end;
+ info->text = (Addr)text;
+ info->dynamic = linker_entry ? True : False;
+
+ info->executable_path = VG_(strdup)("ume.macho.executable_path", name);
+
+ return 0;
+}
+
+#endif // defined(HAVE_MACHO)
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
+
diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c
index a32bec7..1673fc9 100644
--- a/coregrind/m_ume/main.c
+++ b/coregrind/m_ume/main.c
@@ -58,6 +58,9 @@
# if defined(HAVE_SCRIPT)
{ "script", VG_(match_script), VG_(load_script) },
# endif
+# if defined(HAVE_MACHO)
+ { "Mach-O", VG_(match_macho), VG_(load_macho) },
+# endif
};
#define EXE_HANDLER_COUNT (sizeof(exe_handlers)/sizeof(exe_handlers[0]))
diff --git a/coregrind/m_ume/priv_ume.h b/coregrind/m_ume/priv_ume.h
index ce5f090..ca3f95b 100644
--- a/coregrind/m_ume/priv_ume.h
+++ b/coregrind/m_ume/priv_ume.h
@@ -42,6 +42,11 @@
extern Int VG_(load_script) ( Int fd, const HChar *name, ExeInfo *info );
#endif
+#if defined(HAVE_MACHO)
+extern Bool VG_(match_macho) ( Char *hdr, Int len );
+extern Int VG_(load_macho) ( Int fd, const HChar *name, ExeInfo *info );
+#endif
+
#endif /* __PRIV_UME_H */
/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_vki.c b/coregrind/m_vki.c
index 25beafb..9a4c3ef 100644
--- a/coregrind/m_vki.c
+++ b/coregrind/m_vki.c
@@ -77,6 +77,12 @@
# if defined(VGO_linux) || defined(VGO_aix5)
/* nothing to check */
+# elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+ vg_assert(_VKI_NSIG == NSIG);
+ vg_assert(_VKI_NSIG == 32);
+ vg_assert(_VKI_NSIG_WORDS == 1);
+ vg_assert(sizeof(sigset_t) /* defined by Darwin */
+ == sizeof(vki_sigset_t) /* what we actually use */);
# else
# error "Unknown plat"
# endif
@@ -87,6 +93,39 @@
/* the toK- and fromK- forms are identical */
vg_assert( sizeof(vki_sigaction_toK_t)
== sizeof(vki_sigaction_fromK_t) );
+# elif defined(VGO_darwin)
+ /* the toK- and fromK- forms differ by one function-pointer field
+ (sa_tramp) */
+ vg_assert( sizeof(vki_sigaction_toK_t)
+ == sizeof(vki_sigaction_fromK_t) + sizeof(void*) );
+
+ vg_assert(sizeof(struct sigaction) == sizeof(vki_sigaction_fromK_t));
+ vg_assert(sizeof(struct __sigaction) == sizeof(vki_sigaction_toK_t));
+ { struct __sigaction t1;
+ vki_sigaction_toK_t t2;
+ struct sigaction f1;
+ vki_sigaction_fromK_t f2;
+ vg_assert(sizeof(t1.sa_handler) == sizeof(t2.ksa_handler));
+ vg_assert(sizeof(t1.sa_tramp) == sizeof(t2.sa_tramp));
+ vg_assert(sizeof(t1.sa_mask) == sizeof(t2.sa_mask));
+ vg_assert(sizeof(t1.sa_flags) == sizeof(t2.sa_flags));
+ vg_assert(sizeof(f1.sa_handler) == sizeof(f2.ksa_handler));
+ vg_assert(sizeof(f1.sa_mask) == sizeof(f2.sa_mask));
+ vg_assert(sizeof(f1.sa_flags) == sizeof(f2.sa_flags));
+# if 0
+ vg_assert(offsetof(t1,sa_handler) == offsetof(t2.ksa_handler));
+ vg_assert(offsetof(t1.sa_tramp) == offsetof(t2.sa_tramp));
+ vg_assert(offsetof(t1.sa_mask) == offsetof(t2.sa_mask));
+ vg_assert(offsetof(t1.sa_flags) == offsetof(t2.sa_flags));
+ vg_assert(offsetof(f1.sa_handler) == offsetof(f2.ksa_handler));
+ vg_assert(offsetof(f1.sa_mask) == offsetof(f2.sa_mask));
+ vg_assert(offsetof(f1.sa_flags) == offsetof(f2.sa_flags));
+# endif
+ }
+ /* also .. */
+ /* VKI_SET_SIGMASK is hardwired into syscall-x86-darwin.S and
+ syscall-amd64-darwin.S */
+ vg_assert(VKI_SIG_SETMASK == 3);
# else
# error "Unknown OS"
diff --git a/coregrind/pub_core_aspacemgr.h b/coregrind/pub_core_aspacemgr.h
index c47120f..372b923 100644
--- a/coregrind/pub_core_aspacemgr.h
+++ b/coregrind/pub_core_aspacemgr.h
@@ -120,7 +120,6 @@
extern Bool VG_(am_do_sync_check) ( const HChar* fn,
const HChar* file, Int line );
-
//--------------------------------------------------------------
// Functions pertaining to the central query-notify mechanism
// used to handle mmap/munmap/mprotect resulting from client
@@ -250,6 +249,8 @@
segment array accordingly. */
extern SysRes VG_(am_mmap_file_fixed_client)
( Addr start, SizeT length, UInt prot, Int fd, Off64T offset );
+extern SysRes VG_(am_mmap_named_file_fixed_client)
+ ( Addr start, SizeT length, UInt prot, Int fd, Off64T offset, const HChar *name );
/* Map anonymously at a fixed address for the client, and update
the segment array accordingly. */
@@ -400,6 +401,22 @@
extern Int VG_(am_get_VgStack_unused_szB)( VgStack* stack );
+// DDD: this is ugly
+#if defined(VGO_darwin)
+typedef
+ struct {
+ Bool is_added; // Added or removed seg?
+ Addr start;
+ SizeT end;
+ UInt prot; // Not used for removed segs.
+ Off64T offset; // Not used for removed segs.
+ }
+ ChangedSeg;
+
+extern void VG_(get_changed_segments)(
+ const HChar* when, const HChar* where, /*OUT*/ChangedSeg* css,
+ Int css_size, /*OUT*/Int* css_used);
+#endif
#endif // __PUB_CORE_ASPACEMGR_H
diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h
index 6f1c944..b947af1 100644
--- a/coregrind/pub_core_debuginfo.h
+++ b/coregrind/pub_core_debuginfo.h
@@ -56,7 +56,7 @@
in later queries to m_debuginfo. In this case the handle value
will be one or above. If the returned value is zero, no debug info
was read. */
-#if defined(VGO_linux)
+#if defined(VGO_linux) || defined(VGO_darwin)
extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV );
extern void VG_(di_notify_munmap)( Addr a, SizeT len );
@@ -70,6 +70,7 @@
#endif
#if defined(VGO_aix5)
+// GrP fixme use this instead for darwin?
/* AIX5: Very similar, except packaged more neatly. The supplied
parameters describe a code segment and its associated data segment,
that have recently been mapped in -- so we need to read debug info
diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h
index 9e9416b..4c4e09d 100644
--- a/coregrind/pub_core_initimg.h
+++ b/coregrind/pub_core_initimg.h
@@ -60,7 +60,6 @@
extern
void VG_(ii_finalise_image)( IIFinaliseImageInfo );
-
/* Note that both IICreateImageInfo and IIFinaliseImageInfo are
OS-specific. We now go on to give instantiations of them
for supported OSes. */
@@ -169,6 +168,37 @@
UInt adler32_exp;
};
+
+/* ------------------------- Darwin ------------------------- */
+
+#elif defined(VGO_darwin)
+
+struct _IICreateImageInfo {
+ /* ------ Mandatory fields ------ */
+ HChar* toolname;
+ Addr sp_at_startup;
+ Addr clstack_top;
+ /* ------ Per-OS fields ------ */
+ HChar** argv;
+ HChar** envp;
+ Addr entry; /* &_start */
+ Addr init_ip; /* &__dyld_start, or copy of entry */
+ Addr stack_start; /* stack segment hot */
+ Addr stack_end; /* stack segment cold */
+ Addr text; /* executable's Mach header */
+ Bool dynamic; /* False iff executable is static */
+ HChar* executable_path; /* path passed to execve() */
+};
+
+struct _IIFinaliseImageInfo {
+ /* ------ Mandatory fields ------ */
+ SizeT clstack_max_size;
+ Addr initial_client_SP;
+ /* ------ Per-OS fields ------ */
+ Addr initial_client_IP;
+};
+
+
#else
# error "Unknown OS"
#endif
diff --git a/coregrind/pub_core_mach.h b/coregrind/pub_core_mach.h
new file mode 100644
index 0000000..719df44
--- /dev/null
+++ b/coregrind/pub_core_mach.h
@@ -0,0 +1,48 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Mach kernel interface module. pub_core_mach.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2005 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_MACH_H
+#define __PUB_CORE_MACH_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module contains the Mach kernel interface,
+// for operating systems like Darwin / Mac OS X that use it.
+//--------------------------------------------------------------------
+
+#if defined(VGO_darwin)
+// Call this early in Valgrind's main(). It depends on nothing.
+extern void VG_(mach_init)(void);
+#endif
+
+#endif // __PUB_CORE_MACH_H
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h
index 6b6734b..be47cdc 100644
--- a/coregrind/pub_core_machine.h
+++ b/coregrind/pub_core_machine.h
@@ -65,6 +65,11 @@
# undef VG_ELF_MACHINE
# undef VG_ELF_CLASS
# define VG_PLAT_USES_PPCTOC 1
+#elif defined(VGO_darwin)
+# undef VG_ELF_DATA2XXX
+# undef VG_ELF_MACHINE
+# undef VG_ELF_CLASS
+# undef VG_PLAT_USES_PPCTOC
#else
# error Unknown platform
#endif
diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h
index 5bf2088..8229ec8 100644
--- a/coregrind/pub_core_mallocfree.h
+++ b/coregrind/pub_core_mallocfree.h
@@ -73,15 +73,18 @@
defined(VGP_ppc32_linux) || \
defined(VGP_ppc32_aix5)
# define VG_MIN_MALLOC_SZB 8
+// Nb: We always use 16 bytes for Darwin, even on 32-bits, so it can be used
+// for any AltiVec- or SSE-related type. This matches the Darwin libc.
#elif defined(VGP_amd64_linux) || \
defined(VGP_ppc64_linux) || \
- defined(VGP_ppc64_aix5)
+ defined(VGP_ppc64_aix5) || \
+ defined(VGP_x86_darwin) || \
+ defined(VGP_amd64_darwin)
# define VG_MIN_MALLOC_SZB 16
#else
# error Unknown platform
#endif
-
/* This struct definition MUST match the system one. */
/* SVID2/XPG mallinfo structure */
struct vg_mallinfo {
diff --git a/coregrind/pub_core_options.h b/coregrind/pub_core_options.h
index 486cf94..73f4a63 100644
--- a/coregrind/pub_core_options.h
+++ b/coregrind/pub_core_options.h
@@ -182,6 +182,10 @@
so they can be properly handled by m_syswrap. */
extern HChar* VG_(clo_kernel_variant);
+/* Darwin-specific: automatically run /usr/bin/dsymutil to update
+ .dSYM directories as necessary? */
+extern Bool VG_(clo_auto_run_dsymutil);
+
/* --------- Functions --------- */
/* Call this if the executable is missing. This function prints an
diff --git a/coregrind/pub_core_scheduler.h b/coregrind/pub_core_scheduler.h
index 029472b..b295a13 100644
--- a/coregrind/pub_core_scheduler.h
+++ b/coregrind/pub_core_scheduler.h
@@ -59,6 +59,11 @@
thread. */
extern void VG_(acquire_BigLock) ( ThreadId tid, HChar* who );
+/* Simple version, which simply acquires the lock, but does not mess
+ with the guest state in the same way as the non _LL version
+ does. */
+extern void VG_(acquire_BigLock_LL) ( HChar* who );
+
/* Set a thread into a sleeping state. Before the call, the thread
must be runnable, and holding the CPU lock. When this call
returns, the thread will be set to the specified sleeping state,
@@ -67,9 +72,14 @@
caller must be careful not to touch any shared state. It is also
the caller's responsibility to actually block until the thread is
ready to run again. */
-extern void VG_(release_BigLock) ( ThreadId tid, ThreadStatus state, HChar* who );
+extern void VG_(release_BigLock) ( ThreadId tid,
+ ThreadStatus state, HChar* who );
-/* Yield the CPU for a while */
+/* Matching function to acquire_BigLock_LL. */
+extern void VG_(release_BigLock_LL) ( HChar* who );
+
+/* Yield the CPU for a while. Drops/acquires the lock using the
+ normal (non _LL) functions. */
extern void VG_(vg_yield)(void);
// The scheduler.
diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h
index b4fd04e..aa1d68d 100644
--- a/coregrind/pub_core_syscall.h
+++ b/coregrind/pub_core_syscall.h
@@ -75,6 +75,10 @@
extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so );
extern SysRes VG_(mk_SysRes_ppc32_aix5) ( UInt val, UInt err );
extern SysRes VG_(mk_SysRes_ppc64_aix5) ( ULong val, ULong err );
+extern SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr,
+ UInt wHI, UInt wLO );
+extern SysRes VG_(mk_SysRes_amd64_darwin)( UChar scclass, Bool isErr,
+ ULong wHI, ULong wLO );
extern SysRes VG_(mk_SysRes_Error) ( UWord val );
extern SysRes VG_(mk_SysRes_Success) ( UWord val );
diff --git a/coregrind/pub_core_syswrap.h b/coregrind/pub_core_syswrap.h
index 89f0d8c..43428f6 100644
--- a/coregrind/pub_core_syswrap.h
+++ b/coregrind/pub_core_syswrap.h
@@ -40,7 +40,7 @@
// as if the thread had been set up by clone()
extern void VG_(main_thread_wrapper_NORETURN)(ThreadId tid);
-extern void VG_(client_syscall) ( ThreadId tid );
+extern void VG_(client_syscall) ( ThreadId tid, UInt trc );
extern void VG_(post_syscall) ( ThreadId tid );
diff --git a/coregrind/pub_core_threadstate.h b/coregrind/pub_core_threadstate.h
index e7bde55..51b4adf 100644
--- a/coregrind/pub_core_threadstate.h
+++ b/coregrind/pub_core_threadstate.h
@@ -87,6 +87,9 @@
# error Unknown architecture
#endif
+/* Forward declarations */
+struct SyscallStatus;
+struct SyscallArgs;
/* Architecture-specific thread state */
typedef
@@ -120,7 +123,7 @@
typedef
struct {
/* who we are */
- Int lwpid; // PID of kernel task
+ Int lwpid; // PID of kernel task (Darwin: Mach thread)
Int threadgroup; // thread group id
ThreadId parent; // parent tid (if any)
@@ -146,6 +149,135 @@
cancel_progress;
/* Initial state is False, False, Canc_Normal. */
# endif
+
+# if defined(VGO_darwin)
+ // Mach trap POST handler as chosen by PRE
+ void (*post_mach_trap_fn)(ThreadId tid,
+ struct SyscallArgs *, struct SyscallStatus *);
+
+ // This thread's pthread
+ Addr pthread;
+
+ // Argument passed when thread started
+ Addr func_arg;
+
+ // Synchronization between child thread and parent thread's POST wrapper
+ semaphore_t child_go;
+ semaphore_t child_done;
+
+ // Workqueue re-entry
+ // (setjmp in PRE(workq_ops), longjmp in wqthread_hijack)
+ // DDD: JRS fixme: this comment is no longer correct; wq_jmpbuf is
+ // never used, and there is no such setjmp or longjmp pair.
+ // I guess we could leave wq_jmpbuf_valid in place though, since
+ // it does allow for an assertion in ML_(wqthread_continue_NORETURN).
+ Bool wq_jmpbuf_valid;
+ //jmp_buf wq_jmpbuf;
+
+ // Values saved from transient Mach RPC messages
+ Addr remote_port; // destination for original message
+ Int msgh_id; // outgoing message id
+ union {
+ struct {
+ Addr port;
+ } mach_port;
+ struct {
+ Int right;
+ } mach_port_allocate;
+ struct {
+ Addr port;
+ Int right;
+ Int delta;
+ } mach_port_mod_refs;
+ struct {
+ Addr task;
+ Addr name;
+ Int disposition;
+ } mach_port_insert_right;
+ struct {
+ Addr size;
+ int flags;
+ } vm_allocate;
+ struct {
+ Addr address;
+ Addr size;
+ } vm_deallocate;
+ struct {
+ Addr src;
+ Addr dst;
+ Addr size;
+ } vm_copy;
+ struct {
+ Addr address;
+ Addr size;
+ int set_maximum;
+ UWord new_protection;
+ } vm_protect;
+ struct {
+ Addr addr;
+ SizeT size;
+ } vm_read;
+ struct {
+ ULong addr;
+ ULong size;
+ } mach_vm_read;
+ struct {
+ Addr addr;
+ SizeT size;
+ Addr data;
+ } vm_read_overwrite;
+ struct {
+ Addr size;
+ int copy;
+ UWord protection;
+ } vm_map;
+ struct {
+ Addr size;
+ } vm_remap;
+ struct {
+ ULong size;
+ int flags;
+ } mach_vm_allocate;
+ struct {
+ ULong address;
+ ULong size;
+ } mach_vm_deallocate;
+ struct {
+ ULong address;
+ ULong size;
+ int set_maximum;
+ unsigned int new_protection;
+ } mach_vm_protect;
+ struct {
+ ULong size;
+ int copy;
+ UWord protection;
+ } mach_vm_map;
+ struct {
+ Addr thread;
+ UWord flavor;
+ } thread_get_state;
+ struct {
+ Addr address;
+ } io_connect_unmap_memory;
+ struct {
+ int which_port;
+ } task_get_special_port;
+ struct {
+ char *service_name;
+ } bootstrap_look_up;
+ struct {
+ vki_size_t size;
+ } WindowServer_29828;
+ struct {
+ Int access_rights;
+ } WindowServer_29831;
+ struct {
+ char *path;
+ } io_registry_entry_from_path;
+ } mach_args;
+# endif
+
}
ThreadOSstate;
@@ -238,6 +370,7 @@
// to write to this.
extern ThreadId VG_(running_tid);
+
/*------------------------------------------------------------*/
/*--- Basic operations on the thread table. ---*/
/*------------------------------------------------------------*/
diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h
index cbda7ab..c8c6520 100644
--- a/coregrind/pub_core_trampoline.h
+++ b/coregrind/pub_core_trampoline.h
@@ -112,6 +112,16 @@
extern void VG_(ppc64_aix5_do_preloads_then_start_client);
#endif
+#if defined(VGO_darwin)
+extern void VG_(x86_darwin_SUBST_FOR_sigreturn);
+extern SizeT VG_(darwin_REDIR_FOR_strlen)( void* );
+extern SizeT VG_(darwin_REDIR_FOR_strcmp)( void*, void* );
+extern void* VG_(darwin_REDIR_FOR_strcat)( void*, void * );
+extern char* VG_(darwin_REDIR_FOR_strcpy)( char *s1, char *s2 );
+extern SizeT VG_(darwin_REDIR_FOR_strlcat)( char *s1, const char *s2, SizeT size );
+extern UInt VG_(darwin_REDIR_FOR_arc4random)( void );
+#endif
+
#endif // __PUB_CORE_TRAMPOLINE_H
/*--------------------------------------------------------------------*/
diff --git a/coregrind/pub_core_ume.h b/coregrind/pub_core_ume.h
index cf7b1ad..b6e59e5 100644
--- a/coregrind/pub_core_ume.h
+++ b/coregrind/pub_core_ume.h
@@ -43,6 +43,10 @@
#elif defined(VGO_aix5)
// The AIX port doesn't use UME.
+#elif defined(VGO_darwin)
+# define HAVE_MACHO
+# define HAVE_SCRIPT
+
#else
#error unknown architecture
#endif
@@ -60,9 +64,18 @@
Addr exe_base; // INOUT: lowest (allowed) address of exe
Addr exe_end; // INOUT: highest (allowed) address
+#if !defined(VGO_darwin)
Addr phdr; // OUT: address phdr was mapped at
Int phnum; // OUT: number of phdrs
Addr interp_base; // OUT: where interpreter (ld.so) was mapped
+#else
+ Addr stack_start; // OUT: address of start of stack segment (hot)
+ Addr stack_end; // OUT: address of end of stack segment (cold)
+ Addr text; // OUT: address of executable's Mach header
+ Bool dynamic; // OUT: False iff executable is static
+ char* executable_path; // OUT: path passed to execve()
+#endif
+
Addr entry; // OUT: entrypoint in main executable
Addr init_ip; // OUT: address of first instruction to execute
Addr brkbase; // OUT: base address of brk segment
diff --git a/coregrind/pub_core_vkiscnums.h b/coregrind/pub_core_vkiscnums.h
index 4cedf37..4ce09d8 100644
--- a/coregrind/pub_core_vkiscnums.h
+++ b/coregrind/pub_core_vkiscnums.h
@@ -54,6 +54,17 @@
successful, False if the name is unknown. */
extern Bool VG_(aix5_register_syscall)( Int, UChar* );
+#elif defined(VGO_darwin)
+
+/* Convert a syscall number into a nicer form(?) */
+#if defined(VGA_x86)
+# define VG_DARWIN_SYSNO_NUM(sysno) VG_DARWIN_SYSNO_PRINT(sysno)
+#elif defined(VGA_amd64)
+# define VG_DARWIN_SYSNO_NUM(sysno) (sysno)
+#else
+# error unknown arch
+#endif
+
#else
# error Unknown OS
#endif // defined(VGO_*)
diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c
index 3539832..6f0f049 100644
--- a/coregrind/vg_preloaded.c
+++ b/coregrind/vg_preloaded.c
@@ -51,6 +51,8 @@
Hook for running __libc_freeres once the program exits.
------------------------------------------------------------------ */
+#if defined(VGO_linux) || defined(VGO_aix5)
+
void VG_NOTIFY_ON_LOAD(freeres)( void );
void VG_NOTIFY_ON_LOAD(freeres)( void )
{
@@ -66,6 +68,94 @@
*(int *)0 = 'x';
}
+#elif defined(VGO_darwin)
+
+/* ---------------------------------------------------------------------
+ Darwin crash log hints
+ ------------------------------------------------------------------ */
+
+/* This string will be inserted into crash logs, so crashes while
+ running under Valgrind can be distinguished from other crashes. */
+__private_extern__ char *__crashreporter_info__ = "Instrumented by Valgrind " VERSION;
+
+/* ---------------------------------------------------------------------
+ Darwin environment cleanup
+ ------------------------------------------------------------------ */
+
+/* Scrubbing DYLD_INSERT_LIBRARIES from envp during exec is insufficient,
+ as there are other ways to launch a process with environment that
+ valgrind can't catch easily (i.e. launchd).
+ Instead, scrub DYLD_INSERT_LIBRARIES from the parent process once
+ dyld is done loading vg_preload.so.
+*/
+#include <string.h>
+#include <crt_externs.h>
+
+// GrP fixme copied from m_libcproc
+static void env_unsetenv ( Char **env, const Char *varname )
+{
+ Char **from;
+ Char **to = NULL;
+ Int len = strlen(varname);
+
+ for (from = to = env; from && *from; from++) {
+ if (!(strncmp(varname, *from, len) == 0 && (*from)[len] == '=')) {
+ *to = *from;
+ to++;
+ }
+ }
+ *(to++) = *(from++);
+ /* fix the 4th "char* apple" pointer (aka. executable path pointer) */
+ *(to++) = *(from++);
+ *to = NULL;
+}
+
+static void vg_cleanup_env(void) __attribute__((constructor));
+static void vg_cleanup_env(void)
+{
+ Char **envp = (Char**)*_NSGetEnviron();
+ env_unsetenv(envp, "VALGRIND_LAUNCHER");
+ env_unsetenv(envp, "DYLD_SHARED_REGION");
+ // GrP fixme should be more like mash_colon_env()
+ env_unsetenv(envp, "DYLD_INSERT_LIBRARIES");
+}
+
+/* ---------------------------------------------------------------------
+ Darwin arc4random (rdar://6166275)
+ ------------------------------------------------------------------ */
+
+#include <stdio.h>
+
+int VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random)(void);
+int VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random)(void)
+{
+ static FILE *rnd = 0;
+ int result;
+
+ if (!rnd) rnd = fopen("/dev/random", "r");
+
+ fread(&result, sizeof(result), 1, rnd);
+ return result;
+}
+
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_stir)(void);
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_stir)(void)
+{
+ // do nothing
+}
+
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned char *dat, int datlen);
+void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned char *dat, int datlen)
+{
+ // do nothing
+ // GrP fixme ought to check [dat..dat+datlen) is defined
+ // but don't care if it's initialized
+}
+
+#else
+
+# error Unknown OS
+#endif
/*--------------------------------------------------------------------*/
/*--- end ---*/
diff --git a/darwin9.supp b/darwin9.supp
new file mode 100644
index 0000000..74c31e3
--- /dev/null
+++ b/darwin9.supp
@@ -0,0 +1,167 @@
+
+##----------------------------------------------------------------------##
+#
+# Suppressions for Darwin 9.x / Mac OS X 10.5 Leopard
+#
+
+{
+ mach_msg_trap-1
+ Memcheck:Param
+ mach_msg(msg.msgh_remote_port)
+ fun:mach_msg_trap
+ obj:/System/Library/Frameworks/CoreFoundation*
+ obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+ mach_msg_trap-2
+ Memcheck:Param
+ mach_msg(msg.msgh_remote_port)
+ fun:mach_msg_trap
+ obj:/System/Library/Frameworks/CoreFoundation*
+ obj:/System/Library/Frameworks/CoreServices*
+}
+
+{
+ mach_msg_trap-3
+ Memcheck:Param
+ mach_msg(msg.msgh_remote_port)
+ fun:mach_msg_trap
+ obj:/System/Library/Frameworks/CoreFoundation*
+ obj:/System/Library/Frameworks/Carbon*
+}
+
+{
+ mach_msg_trap-4
+ Memcheck:Param
+ mach_msg(msg.msgh_remote_port)
+ fun:mach_msg_trap
+ obj:/System/Library/Frameworks/CoreFoundation*
+ obj:/System/Library/Frameworks/CoreFoundation*
+}
+
+{
+ mach_msg_trap-5
+ Memcheck:Param
+ mach_msg(msg.msgh_remote_port)
+ fun:mach_msg_trap
+ obj:/System/Library/Frameworks/CoreFoundation*
+ obj:/System/Library/Frameworks/AppKit*
+}
+
+{
+ macos-Cond-1
+ Memcheck:Cond
+ fun:GetVariationInfoFromName
+ obj:/System/Library/Frameworks/ApplicationServices*
+ obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+ macos-Cond-2
+ Memcheck:Cond
+ fun:*PMMutex*Lock*
+ obj:/System/Library/Frameworks/ApplicationServices*
+ obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+ macos-Cond-3
+ Memcheck:Cond
+ fun:sseCGSBlendXXXX8888
+ obj:/System/Library/Frameworks/ApplicationServices*
+ obj:/System/Library/Frameworks/ApplicationServices*
+}
+
+{
+ macos-Cond-4
+ Memcheck:Cond
+ fun:*CASettingsStorage*RefreshSettings*
+ obj:/System/Library/Frameworks/CoreAudio*
+ obj:/System/Library/Frameworks/CoreAudio*
+}
+
+{
+ macos-Cond-5
+ Memcheck:Cond
+ fun:gle*
+ obj:/System/Library/Frameworks/OpenGL*
+ obj:/System/Library/Frameworks/OpenGL*
+}
+
+{
+ futimes-1
+ Memcheck:Param
+ futimes(tvp[1])
+ fun:futimes
+ obj:/usr/lib/libSystem*
+ obj:/usr/lib/libSystem*
+}
+
+##----------------------------------------------------------------------##
+#
+# Suppressions for Helgrind.
+
+# These ones were necessary to give no errors on a tiny non-threaded
+# program. I don't know if they're real problems or false positives (njn).
+
+# keymgr seems to deliberately do some bogus actions, and if they are bogus,
+# it passes the error codes back to the caller.
+{
+ __keymgr_initializer lock failed
+ Helgrind:PthAPIerror
+ fun:pthread_mutex_lock
+ fun:_dyld_register_func_for_*_image
+ fun:__keymgr_initializer
+ fun:libSystem_initializer
+}
+{
+ __keymgr_initializer unlock failed
+ Helgrind:PthAPIerror
+ fun:pthread_mutex_unlock
+ fun:_dyld_register_func_for_*_image
+ fun:__keymgr_initializer
+ fun:libSystem_initializer
+}
+{
+ __keymgr_initializer bogus unlock
+ Helgrind:UnlockBogus
+ fun:pthread_mutex_unlock
+ fun:_dyld_register_func_for_*_image
+ fun:__keymgr_initializer
+ fun:libSystem_initializer
+}
+
+# These ones were necessary to give no errors on a tiny threaded program.
+# I don't know if they're real problems or false positives (njn).
+
+{
+ crude1
+ Helgrind:Race
+ obj:/usr/lib/dyld
+}
+{
+ crude2
+ Helgrind:Race
+ obj:/usr/lib/libSystem.B.dylib
+}
+# This would be better as "fun:\?\?\?" but string matching doesn't seem to
+# allow escaping meta-chars.
+{
+ crude3
+ Helgrind:Race
+ fun:???
+}
+{
+ crude4
+ Helgrind:Race
+ fun:mythread_wrapper
+}
+{
+ crude5
+ Helgrind:Race
+ ...
+ fun:pthread_create_WRK
+ fun:pthread_create
+}
+
diff --git a/docs/internals/Darwin-notes.txt b/docs/internals/Darwin-notes.txt
new file mode 100644
index 0000000..f526c4f
--- /dev/null
+++ b/docs/internals/Darwin-notes.txt
@@ -0,0 +1,136 @@
+
+Valgrind-developer notes, re the MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+JRS 22 Mar 09: re these comments in m_libc* and m_debuglog:
+
+/* IMPORTANT: on Darwin it is essential to use the _nocancel versions
+ of syscalls rather than the vanilla version, if a _nocancel version
+ is available. See docs/internals/Darwin-notes.txt for the reason
+ why. */
+
+when Valgrind does (for its own purposes, not for the client)
+read/write/open/close etc syscalls, it really is critical to use the
+_nocancel versions of syscalls rather than the vanilla versions. This
+holds throughout the entire code base: whenever V does a syscall for
+its own purposes, we must use the _nocancel version if it exists.
+This is of course most prevalent in m_libc* since all of our
+own-purpose (non-client) syscalls should get routed through there.
+
+Why? Because on Darwin, pthread cancellation is done within the
+kernel (unlike on Linux, iiuc). And read/write/open/close and a whole
+bunch of other syscalls to do with stream I/O are cancellation points.
+So what can happen is, client informs the kernel that a given thread
+is to be cancelled. Then at the next (eg) VG_(printf) call by that
+thread, which leads to a sys_write, the write syscall gets hit by the
+cancellation request, and is duly nuked by the kernel. Of course from
+the outside it looks as if the thread had mysteriously disappeared off
+the radar for no reason.
+
+In short, we need to use _nocancel versions in order to ensure that
+cancellation requests only take effect at the places where the client
+does a syscall, and not the places where Valgrind does syscalls.
+
+How observed: using the standard pipe-based implementation in
+coregrind/m_scheduler/sema.c, none/tests/pth_cancel1 would hang
+(compared to succeeding using native Darwin semaphores). And if the
+"pause()" call in said test is turned into a spin ("while (1) ;") then
+the entire Valgrind run mysteriously disappears, rather than spinning
+using native Darwin semaphores.
+
+Because the pipe-based semaphore intensively uses sys_read/sys_write,
+it is not surprising that it inadvertantly was eating up cancellation
+requests directed to client threads. With abovementioned change in
+force the pipe-based semaphore appears to work correctly.
+
+
+
+Valgrind-developer notes, things removed from the original MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There was a broken debugstub implementation. It was removed over several
+commits: r9477, which removed most of it, and r9711, r9759, and r10012,
+which cleaned up remaining bits.
+
+There was machinery to read function names from Dwarf3 debug info. But we
+already read function names from the symbol tables, so this was duplicated
+functionality. Furthermore, a Darwin-specific hack was required in
+storage.c to choose between symbol table names vs. Dwarf3 names. So this
+machinery was removed in r10155.
+
+
+Valgrind-developer notes, todos re the MacOSX port
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+* m_syswrap/syscall-amd64-darwin.S
+ - correct signal mask is not applied during syscall
+ - restart-labels are completely bogus
+
+* m_syswrap/syswrap-darwin.c:
+ - PRE(sys_posix_spawn) completely ignores signal issues, and
+ also ignores the file_actions argument
+
+* env var handling w/ exec on Darwin: is there something odd? Compare
+ "valgrind env" on Darwin and Linux. On the former there are
+ settings VALGRIND_LIB and VALGRIND_LIB_INNER, but not for the
+ former.
+ There's a suspicious-looking "#if defined(VGO_darwin)" in
+ VG_(env_remove_valgrind_env_stuff). Maybe related?
+
+* Cleanups: sort wrappers in syswrap-darwin.c and priv_syswrap-darwin.h
+ alphabetically. Also, some aren't properly implemented -- check and
+ print warnings
+
+* Cleanups: m_scheduler/sema.c: use pipe implementation
+ (but this apparently causes none/tests/pth_cancel1 to hang.
+ I have no idea why, despite quite some investigation).
+
+* Cleanups: m_debugstub: move to attic
+
+* syswrap-darwin.c: sys_{f,}chmod_extended: handling of ARG5 is way
+ wrong
+
+* Cleanups (Linux,AIX5): bogus launcher-path mangling logic in
+ PRE(sys_execve)
+
+* Cleanups (ALL PLATFORMS): m_signals.c: are the _MY_SIGRETURN
+ assembly stubs actually necessary for anything? I don't know.
+
+* Cleanups: check that changes to VG_(stat) and VG_(stat64) have
+ not broken 64-bit statting on 32-bit Linux
+
+* Cleanups: #if !HAVE_PROC in m_main (to do with /proc/<pid>/cmdline
+
+--------
+
+m_main doesn't read symbols for the valgrind exe itself, which is
+annoying. On minimal investigation it seems that the executable isn't
+even listed by aspacem. This is very strange and not in accordance
+with the Linux or AIX ports.
+
+
+m_main: relatedly, Darwin version does not collect/give out
+initial debuginfo handles; hence ptrcheck won't work
+
+
+m_main: Darwin port relies on blocking out big sections of address
+space with mmap at startup. We know from history that this is a bad
+idea. (It's also really slow on 64-bit builds, taking 3--4 seconds.)
+Also, startup is not done on the interim startup stack -- why not?
+
+
+VG_(di_notify_mmap): Linux version is also used for Darwin, and
+contains some ifdeffery. Clean up.
+
+
+PRE(sys_fork), #ifdeffery
+
+
+syswrap-generic.c: VG_(init_preopened_fds) is #ifdefd for Darwin
+
+
+scheduler.c: #ifdeffery in VG_(get_thread_out_of_syscall)
+
+
+look at notes in coregrind/Makefile.am re Mach RPC interface
+definitions. See if we can get rid of any more stuff now that
+m_debugstub is gone.
diff --git a/docs/internals/Makefile.am b/docs/internals/Makefile.am
index 1f82a67..76fed03 100644
--- a/docs/internals/Makefile.am
+++ b/docs/internals/Makefile.am
@@ -3,6 +3,7 @@
3_2_BUGSTATUS.txt 3_3_BUGSTATUS.txt \
3_4_BUGSTATUS.txt \
BIG_APP_NOTES.txt \
+ Darwin-notes.txt \
directory-structure.txt \
howto_BUILD_KDE42.txt \
howto_oprofile.txt \
diff --git a/drd/Makefile.am b/drd/Makefile.am
index 18a8844..84655f2 100644
--- a/drd/Makefile.am
+++ b/drd/Makefile.am
@@ -1,6 +1,7 @@
include $(top_srcdir)/Makefile.tool.am
noinst_PROGRAMS =
+noinst_DSYMS =
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
noinst_PROGRAMS += drd-x86-linux vgpreload_drd-x86-linux.so
endif
@@ -19,6 +20,14 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += drd-ppc64-aix5 vgpreload_drd-ppc64-aix5.so
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+ noinst_PROGRAMS += drd-x86-darwin vgpreload_drd-x86-darwin.so
+ noinst_DSYMS += vgpreload_drd-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+ noinst_PROGRAMS += drd-amd64-darwin vgpreload_drd-amd64-darwin.so
+ noinst_DSYMS += vgpreload_drd-amd64-darwin.so
+endif
VGPRELOAD_DRD_SOURCES = \
@@ -91,6 +100,22 @@
vgpreload_drd_ppc64_aix5_so_LDFLAGS = $(PRELOAD_LDFLAGS_PPC64_AIX5)\
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+vgpreload_drd_x86_darwin_so_SOURCES = $(VGPRELOAD_DRD_SOURCES)
+vgpreload_drd_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_drd_x86_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_drd_x86_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_X86_DARWIN)\
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_drd_amd64_darwin_so_SOURCES = $(VGPRELOAD_DRD_SOURCES)
+vgpreload_drd_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_drd_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_drd_amd64_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_drd_amd64_darwin_so_DEPENDENCIES =
+vgpreload_drd_amd64_darwin_so_LDFLAGS = $(PRELOAD_LDFLAGS_AMD64_DARWIN)\
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
DRD_SOURCES = \
drd_barrier.c \
@@ -175,3 +200,19 @@
drd_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
drd_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
drd_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+drd_x86_darwin_SOURCES = $(DRD_SOURCES)
+drd_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+drd_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+drd_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+drd_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+drd_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+drd_amd64_darwin_SOURCES = $(DRD_SOURCES)
+drd_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+drd_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+drd_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+drd_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+drd_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
+
diff --git a/drd/drd_main.c b/drd/drd_main.c
index 0dfb00a..3cc6348 100644
--- a/drd/drd_main.c
+++ b/drd/drd_main.c
@@ -607,8 +607,13 @@
static
void drd_pre_clo_init(void)
{
- // Basic tool stuff.
+#if defined(VGO_darwin)
+ // This makes the (all-failing) regtests run much faster.
+ VG_(printf)("DRD doesn't work on Darwin yet, sorry.\n");
+ VG_(exit)(1);
+#endif
+ // Basic tool stuff.
VG_(details_name) ("drd");
VG_(details_version) (NULL);
VG_(details_description) ("a thread error detector");
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
index f77569d..db33fbd 100644
--- a/drd/drd_pthread_intercepts.c
+++ b/drd/drd_pthread_intercepts.c
@@ -643,6 +643,7 @@
}
+#if defined(HAVE_PTHREAD_SPIN_LOCK)
// pthread_spin_init
PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
pthread_spinlock_t *spinlock,
@@ -723,7 +724,10 @@
spinlock, 0, 0, 0, 0);
return ret;
}
+#endif // HAVE_PTHREAD_SPIN_LOCK
+
+#if defined(HAVE_PTHREAD_BARRIER_INIT)
// pthread_barrier_init
PTH_FUNC(int, pthreadZubarrierZuinit, // pthread_barrier_init
pthread_barrier_t* barrier,
@@ -775,6 +779,7 @@
ret == PTHREAD_BARRIER_SERIAL_THREAD, 0);
return ret;
}
+#endif // HAVE_PTHREAD_BARRIER_INIT
// sem_init
diff --git a/drd/tests/recursive_mutex.c b/drd/tests/recursive_mutex.c
index ad79b63..3ddfc25 100644
--- a/drd/tests/recursive_mutex.c
+++ b/drd/tests/recursive_mutex.c
@@ -10,6 +10,7 @@
#include "../../config.h"
+#if !defined(VGO_darwin)
static void lock_twice(pthread_mutex_t* const p)
{
pthread_mutex_lock(p);
@@ -17,6 +18,7 @@
pthread_mutex_unlock(p);
pthread_mutex_unlock(p);
}
+#endif
int main(int argc, char** argv)
{
@@ -60,6 +62,10 @@
pthread_mutex_destroy(&m);
}
#endif
+
+// DDD: Darwin doesn't support signals yet, so the alarm() call doesn't kick
+// in, which causes it to hang.
+#if !defined(VGO_darwin)
{
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
@@ -68,5 +74,6 @@
lock_twice(&m);
}
printf("Done.\n");
+#endif
return 0;
}
diff --git a/exp-omega/Makefile.am b/exp-omega/Makefile.am
index 6af2f3f..122d8a6 100644
--- a/exp-omega/Makefile.am
+++ b/exp-omega/Makefile.am
@@ -30,6 +30,12 @@
##zz if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
##zz noinst_PROGRAMS += exp-omega-ppc64-aix5 vgpreload_exp-omega-ppc64-aix5.so
##zz endif
+##zz if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+##zz noinst_PROGRAMS += exp-omega-x86-darwin vgpreload_exp-omega-x86-darwin.so
+##zz endif
+##zz if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+##zz noinst_PROGRAMS += exp-omega-amd64-darwin vgpreload_exp-omega-amd64-darwin.so
+##zz endif
##zz
##zz VGPRELOAD_OMEGA_SOURCES_COMMON = o_replace_memops.c
##zz
@@ -87,6 +93,24 @@
##zz $(PRELOAD_LDFLAGS_PPC64_AIX5) \
##zz $(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
##zz
+##zz vgpreload_exp_omega_x86_darwin_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
+##zz vgpreload_exp_omega_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+##zz vgpreload_exp_omega_x86_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+##zz vgpreload_exp_omega_x86_darwin_so_LDFLAGS = \
+##zz $(PRELOAD_LDFLAGS_X86_DARWIN) \
+##zz $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+##zz
+##zz vgpreload_exp_omega_amd64_darwin_so_SOURCES = $(VGPRELOAD_OMEGA_SOURCES_COMMON)
+##zz vgpreload_exp_omega_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+##zz vgpreload_exp_omega_amd64_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+##zz vgpreload_exp_omega_amd64_darwin_so_LDFLAGS = \
+##zz $(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+##zz $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+##zz
##zz OMEGA_SOURCES_COMMON = \
##zz o_main.c
##zz
@@ -138,6 +162,22 @@
##zz exp_omega_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
##zz exp_omega_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
##zz
+##zz exp_omega_x86_darwin_SOURCES = $(OMEGA_SOURCES_COMMON)
+##zz exp_omega_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+##zz exp_omega_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN) -O2
+##zz exp_omega_x86_darwin_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+##zz exp_omega_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+##zz exp_omega_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+##zz exp_omega_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+##zz
+##zz exp_omega_amd64_darwin_SOURCES = $(OMEGA_SOURCES_COMMON)
+##zz exp_omega_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) -g -O0 #-O2
+##zz exp_omega_amd64_darwin_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+##zz exp_omega_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
+##zz
##zz oincludedir = $(includedir)/valgrind
##zz
##zz oinclude_HEADERS = exp-omega.h
diff --git a/exp-ptrcheck/Makefile.am b/exp-ptrcheck/Makefile.am
index d4591e3..37b3ef5 100644
--- a/exp-ptrcheck/Makefile.am
+++ b/exp-ptrcheck/Makefile.am
@@ -1,6 +1,7 @@
include $(top_srcdir)/Makefile.tool.am
noinst_PROGRAMS =
+noinst_DSYMS =
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
noinst_PROGRAMS += exp-ptrcheck-x86-linux vgpreload_exp-ptrcheck-x86-linux.so
endif
@@ -19,6 +20,14 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += exp-ptrcheck-ppc64-aix5 vgpreload_exp-ptrcheck-ppc64-aix5.so
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += exp-ptrcheck-x86-darwin vgpreload_exp-ptrcheck-x86-darwin.so
+noinst_DSYMS += vgpreload_exp-ptrcheck-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += exp-ptrcheck-amd64-darwin vgpreload_exp-ptrcheck-amd64-darwin.so
+noinst_DSYMS += vgpreload_exp-ptrcheck-amd64-darwin.so
+endif
VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON = h_intercepts.c
@@ -77,6 +86,24 @@
$(PRELOAD_LDFLAGS_PPC64_AIX5) \
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+vgpreload_exp_ptrcheck_x86_darwin_so_SOURCES = $(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
+vgpreload_exp_ptrcheck_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_ptrcheck_x86_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_exp_ptrcheck_x86_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_X86_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_exp_ptrcheck_amd64_darwin_so_SOURCES = $(VGPRELOAD_EXP_PTRCHECK_SOURCES_COMMON)
+vgpreload_exp_ptrcheck_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_exp_ptrcheck_amd64_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_exp_ptrcheck_amd64_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
EXP_PTRCHECK_SOURCES_COMMON = \
@@ -124,6 +151,20 @@
exp_ptrcheck_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
exp_ptrcheck_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+exp_ptrcheck_x86_darwin_SOURCES = $(EXP_PTRCHECK_SOURCES_COMMON)
+exp_ptrcheck_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+exp_ptrcheck_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+exp_ptrcheck_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+exp_ptrcheck_amd64_darwin_SOURCES = $(EXP_PTRCHECK_SOURCES_COMMON)
+exp_ptrcheck_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+exp_ptrcheck_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
noinst_HEADERS = h_main.h sg_main.h pc_common.h
EXTRA_DIST =
diff --git a/exp-ptrcheck/h_main.c b/exp-ptrcheck/h_main.c
index 50f4154..c4342a3 100644
--- a/exp-ptrcheck/h_main.c
+++ b/exp-ptrcheck/h_main.c
@@ -1957,6 +1957,8 @@
if (is_integer_guest_reg( (Int)offset, (Int)size )) {
put_guest_intreg( tid, 1, offset, size, (UWord)NONPTR );
} else {
+ // DDD: on Darwin, this assertion fails because we currently do a
+ // 'post_reg_write' on the 'guest_CC_DEP1' pseudo-register.
tl_assert(0);
}
// VG_(set_thread_shadow_archreg)( tid, reg, (UInt)NONPTR );
@@ -2127,16 +2129,16 @@
syscall-specific handling is is required. No further details of it
are stored in the table.
- On Linux, 'number' is a __NR_xxx constant.
+ On Linux and Darwin, 'number' is a __NR_xxx constant.
On AIX5, 'number' is an Int*, which points to the Int variable
holding the currently assigned number for this syscall.
When querying the table, we compare the supplied syscall number
- with the 'number' field (directly on Linux, after dereferencing on
- AIX5), to find the relevant entry. This requires a linear search
- of the table. To stop the costs getting too high, the table is
- incrementally rearranged after each search, to move commonly
+ with the 'number' field (directly on Linux and Darwin, after
+ dereferencing on AIX5), to find the relevant entry. This requires a
+ linear search of the table. To stop the costs getting too high, the
+ table is incrementally rearranged after each search, to move commonly
requested items a bit closer to the front.
The table is built once, the first time it is used. After that we
@@ -2439,6 +2441,30 @@
ADD(1, __NR_AIX5_kload); /* not sure what to do here */
ADD(0, __NR_AIX5_kwrite);
+ /* --------------- DARWIN ------------- */
+
+# elif defined(VGO_darwin)
+
+# define ADD(_flag, _syscallname) \
+ do { UWordPair p; p.uw1 = (_syscallname); p.uw2 = (_flag); \
+ VG_(addToXA)( post_syscall_table, &p ); \
+ } while (0)
+
+ // DDD: a desultory attempt thus far...
+
+ // Unix/BSD syscalls.
+
+ // Mach traps.
+ ADD(0, __NR_host_self_trap);
+ ADD(0, __NR_mach_msg_trap);
+ ADD(0, __NR_mach_reply_port);
+ ADD(0, __NR_task_self_trap);
+
+ // Machine-dependent syscalls.
+ ADD(0, __NR_pthread_set_self);
+
+ /* ------------------------------------ */
+
# else
# error "Unsupported OS"
# endif
@@ -2459,7 +2485,7 @@
n = VG_(sizeXA)( post_syscall_table );
for (i = 0; i < n; i++) {
pair = VG_(indexXA)( post_syscall_table, i );
-# if defined(VGO_linux)
+# if defined(VGO_linux) || defined(VGO_darwin)
if (pair->uw1 == (UWord)sysno)
break;
# elif defined(VGO_aix5)
@@ -2473,10 +2499,17 @@
tl_assert(i >= 0 && i <= n);
if (i == n) {
+// DDD: genericise this
+# if defined(VGO_linux)
VG_(printf)("sysno == %u\n", sysno);
-# if defined(VGO_aix5)
+# elif defined(VGO_aix5)
+ VG_(printf)("sysno == %u\n", sysno);
VG_(printf)("syscallnm == %s\n",
VG_(aix5_sysno_to_sysname)(sysno));
+# elif defined(VGO_darwin)
+ VG_(printf)("sysno == %d\n", VG_DARWIN_SYSNO_PRINT(sysno));
+# else
+# error "Unsupported OS"
# endif
VG_(tool_panic)("unhandled syscall");
}
diff --git a/exp-ptrcheck/pc_main.c b/exp-ptrcheck/pc_main.c
index 1dfd9a5..6f44bbf 100644
--- a/exp-ptrcheck/pc_main.c
+++ b/exp-ptrcheck/pc_main.c
@@ -144,6 +144,12 @@
static void pc_pre_clo_init(void)
{
+#if defined(VGO_darwin)
+ // This makes the (all-failing) regtests run much faster.
+ VG_(printf)("Ptrcheck doesn't work on Darwin yet, sorry.\n");
+ VG_(exit)(1);
+#endif
+
VG_(details_name) ("exp-ptrcheck");
VG_(details_version) (NULL);
VG_(details_description) ("a heap, stack & global array "
diff --git a/exp-ptrcheck/tests/Makefile.am b/exp-ptrcheck/tests/Makefile.am
index 5c27f35..6a1d884 100644
--- a/exp-ptrcheck/tests/Makefile.am
+++ b/exp-ptrcheck/tests/Makefile.am
@@ -65,7 +65,7 @@
zero.vgtest zero.stderr.exp
check_PROGRAMS = \
- add and arith bad_percentify base ccc cmp fp \
+ add and arith bad_percentify base cmp fp \
globalerr hackedbz2 \
hp_bounds hp_dangle idiv imul \
justify mm not neg or partial \
@@ -74,6 +74,14 @@
stackerr \
strcpy strlen sub supp syscall tricky unaligned xor zero
+# DDD: not sure if these ones should work on Darwin or not... if not, should
+# be moved into x86-linux/.
+if ! VGCONF_OS_IS_DARWIN
+ check_PROGRAMS += \
+ ccc
+endif
+
+
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
@@ -98,11 +106,16 @@
preen_invars_LDADD = -ldl
preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ preen_invars_LDADD = -ldl
+ preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI)
+else
preen_invars_LDADD = -ldl
preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI) \
-Wl,-rpath,$(top_builddir)/memcheck/tests
endif
endif
+endif
preen_invars_so_so_CFLAGS = $(AM_CFLAGS) -fpic
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
@@ -112,8 +125,13 @@
preen_invars_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ preen_invars_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+ -dynamiclib -all_load
+else
preen_invars_so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-soname -Wl,preen_invars_so.so
endif
endif
+endif
diff --git a/glibc-2.34567-NPTL-helgrind.supp b/glibc-2.34567-NPTL-helgrind.supp
index 0a4aeaa..616309e 100644
--- a/glibc-2.34567-NPTL-helgrind.supp
+++ b/glibc-2.34567-NPTL-helgrind.supp
@@ -137,6 +137,7 @@
{
helgrind-glibc2X-112
Helgrind:Race
+ fun:pthread_create_WRK
fun:pthread_create@*
}
{
diff --git a/helgrind/Makefile.am b/helgrind/Makefile.am
index 02f96ba..55379c2 100644
--- a/helgrind/Makefile.am
+++ b/helgrind/Makefile.am
@@ -1,6 +1,7 @@
include $(top_srcdir)/Makefile.tool.am
noinst_PROGRAMS =
+noinst_DSYMS =
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
noinst_PROGRAMS += helgrind-x86-linux vgpreload_helgrind-x86-linux.so
endif
@@ -19,6 +20,14 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += helgrind-ppc64-aix5 vgpreload_helgrind-ppc64-aix5.so
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += helgrind-x86-darwin vgpreload_helgrind-x86-darwin.so
+noinst_DSYMS += vgpreload_helgrind-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += helgrind-amd64-darwin vgpreload_helgrind-amd64-darwin.so
+noinst_DSYMS += vgpreload_helgrind-amd64-darwin.so
+endif
VGPRELOAD_HELGRIND_SOURCES_COMMON = hg_intercepts.c
@@ -70,6 +79,22 @@
$(PRELOAD_LDFLAGS_PPC64_AIX5) \
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+vgpreload_helgrind_x86_darwin_so_SOURCES = $(VGPRELOAD_HELGRIND_SOURCES_COMMON)
+vgpreload_helgrind_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_helgrind_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_helgrind_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_helgrind_x86_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_X86_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_helgrind_amd64_darwin_so_SOURCES = $(VGPRELOAD_HELGRIND_SOURCES_COMMON)
+vgpreload_helgrind_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_helgrind_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_helgrind_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_helgrind_amd64_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
HELGRIND_SOURCES_COMMON = \
hg_basics.c hg_lock_n_thread.c hg_wordset.c libhb_core.c \
hg_errors.c hg_main.c
@@ -116,6 +141,20 @@
helgrind_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
helgrind_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+helgrind_x86_darwin_SOURCES = $(HELGRIND_SOURCES_COMMON)
+helgrind_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+helgrind_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN) -O2
+helgrind_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+helgrind_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+helgrind_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+helgrind_amd64_darwin_SOURCES = $(HELGRIND_SOURCES_COMMON)
+helgrind_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+helgrind_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) -O2
+helgrind_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+helgrind_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+helgrind_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
hgincludedir = $(includedir)/valgrind
hginclude_HEADERS = helgrind.h
diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c
index 698a082..47cb3af 100644
--- a/helgrind/hg_intercepts.c
+++ b/helgrind/hg_intercepts.c
@@ -195,9 +195,13 @@
}
// pthread_create
-PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
- pthread_t *thread, const pthread_attr_t *attr,
- void *(*start) (void *), void *arg)
+// glibc-2.8.90 has "pthread_create@@GLIBC_2.2.5".
+// Darwin has "pthread_create".
+//
+// DDD: for Darwin, need to have non-"@*"-suffixed versions for all pthread
+// functions that currently have them.
+static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start) (void *), void *arg)
{
int ret;
OrigFn fn;
@@ -234,6 +238,16 @@
}
return ret;
}
+PTH_FUNC(int, pthreadZucreate, // pthread_create
+ pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start) (void *), void *arg) {
+ return pthread_create_WRK(thread, attr, start, arg);
+}
+PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
+ pthread_t *thread, const pthread_attr_t *attr,
+ void *(*start) (void *), void *arg) {
+ return pthread_create_WRK(thread, attr, start, arg);
+}
// pthread_join
PTH_FUNC(int, pthreadZujoin, // pthread_join
@@ -756,6 +770,8 @@
/*--- pthread_barrier_t functions ---*/
/*----------------------------------------------------------------*/
+#if defined(HAVE_PTHREAD_BARRIER_INIT)
+
/* Handled: pthread_barrier_init
pthread_barrier_wait
pthread_barrier_destroy
@@ -861,6 +877,8 @@
return ret;
}
+#endif // defined(HAVE_PTHREAD_BARRIER_INIT)
+
/*----------------------------------------------------------------*/
/*--- pthread_rwlock_t functions ---*/
/*----------------------------------------------------------------*/
diff --git a/helgrind/hg_main.c b/helgrind/hg_main.c
index 796d966..bff2fd5 100644
--- a/helgrind/hg_main.c
+++ b/helgrind/hg_main.c
@@ -11,6 +11,8 @@
Copyright (C) 2007-2009 OpenWorks LLP
info@open-works.co.uk
+ Copyright (C) 2007-2009 Apple, Inc.
+
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
@@ -4201,6 +4203,7 @@
static void hg_pre_clo_init ( void )
{
Thr* hbthr_root;
+
VG_(details_name) ("Helgrind");
VG_(details_version) (NULL);
VG_(details_description) ("a thread error detector");
diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am
index c594f3b..5f68d40 100644
--- a/helgrind/tests/Makefile.am
+++ b/helgrind/tests/Makefile.am
@@ -92,10 +92,15 @@
tc18_semabuse \
tc19_shadowmem \
tc21_pthonce \
- tc22_exit_w_lock \
tc23_bogus_condwait \
tc24_nonzero_sem
+# DDD: it seg faults, and then the Valgrind exit path hangs
+if ! VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+ check_PROGRAMS += \
+ tc22_exit_w_lock
+endif
+
if HAVE_PTHREAD_BARRIER
check_PROGRAMS += bar_bad bar_trivial
endif
diff --git a/helgrind/tests/tc20_verifywrap.c b/helgrind/tests/tc20_verifywrap.c
index 667aafa..6a8b30c 100644
--- a/helgrind/tests/tc20_verifywrap.c
+++ b/helgrind/tests/tc20_verifywrap.c
@@ -18,7 +18,7 @@
#include <pthread.h>
#include <semaphore.h>
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
#if !defined(__GLIBC_PREREQ)
# error "This program needs __GLIBC_PREREQ (in /usr/include/features.h)"
diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h
index cda74ab..734391c 100644
--- a/include/pub_tool_basics.h
+++ b/include/pub_tool_basics.h
@@ -112,7 +112,15 @@
// - off_t is "used for file sizes".
// At one point we were using it for memory offsets, but PtrdiffT should be
// used in those cases.
+// Nb: on Linux and AIX, off_t is a signed word-sized int. On Darwin it's
+// always a signed 64-bit int. So we defined our own Off64T as well.
+#if defined(VGO_linux) || defined(VGO_aix5)
typedef Word OffT; // 32 64
+#elif defined(VGO_darwin)
+typedef Long OffT; // 64 64
+#else
+# error Unknown OS
+#endif
typedef Long Off64T; // 64 64
#if !defined(NULL)
@@ -183,6 +191,19 @@
Bool _isError;
}
SysRes;
+#elif defined(VGO_darwin)
+typedef
+ struct {
+ UWord _wLO;
+ UWord _wHI;
+ enum {
+ SysRes_MACH=40, // MACH, result is _wLO
+ SysRes_MDEP, // MDEP, result is _wLO
+ SysRes_UNIX_OK, // UNIX, success, result is _wHI:_wLO
+ SysRes_UNIX_ERR // UNIX, error, error is _wHI:_wLO
+ } _mode;
+ }
+ SysRes;
#else
# error "Unknown OS"
#endif
@@ -214,6 +235,44 @@
# error "need to define SysRes accessors on AIX5 (copy from 3.4.1 sources)"
+#elif defined(VGO_darwin)
+
+static inline Bool sr_isError ( SysRes sr ) {
+ switch (sr._mode) {
+ case SysRes_UNIX_ERR: return True;
+ default: return False;
+ /* should check tags properly and assert here, but we can't here */
+ }
+}
+
+static inline UWord sr_Res ( SysRes sr ) {
+ switch (sr._mode) {
+ case SysRes_MACH:
+ case SysRes_MDEP:
+ case SysRes_UNIX_OK: return sr._wLO;
+ default: return 0; /* should assert, but we can't here */
+ }
+}
+
+static inline UWord sr_ResHI ( SysRes sr ) {
+ switch (sr._mode) {
+ case SysRes_UNIX_OK: return sr._wHI;
+ default: return 0; /* should assert, but we can't here */
+ }
+}
+
+static inline UWord sr_Err ( SysRes sr ) {
+ switch (sr._mode) {
+ case SysRes_UNIX_ERR: return sr._wLO;
+ default: return 0; /* should assert, but we can't here */
+ }
+}
+
+static inline Bool sr_EQ ( SysRes sr1, SysRes sr2 ) {
+ return sr1._mode == sr2._mode
+ && sr1._wLO == sr2._wLO && sr1._wHI == sr2._wHI;
+}
+
#else
# error "Unknown OS"
#endif
diff --git a/include/pub_tool_basics_asm.h b/include/pub_tool_basics_asm.h
index 201c1b5..42a8a31 100644
--- a/include/pub_tool_basics_asm.h
+++ b/include/pub_tool_basics_asm.h
@@ -48,8 +48,15 @@
#define VGAPPEND(str1,str2) str1##str2
-#define VG_(str) VGAPPEND(vgPlain_, str)
-#define ML_(str) VGAPPEND(vgModuleLocal_, str)
+#if defined(VGO_linux) || defined(VGO_aix5)
+# define VG_(str) VGAPPEND( vgPlain_, str)
+# define ML_(str) VGAPPEND( vgModuleLocal_, str)
+#elif defined(VGO_darwin)
+# define VG_(str) VGAPPEND(_vgPlain_, str)
+# define ML_(str) VGAPPEND(_vgModuleLocal_, str)
+#else
+# error Unknown OS
+#endif
#endif /* __PUB_TOOL_BASICS_ASM_H */
diff --git a/include/pub_tool_libcbase.h b/include/pub_tool_libcbase.h
index c2cab19..0460112 100644
--- a/include/pub_tool_libcbase.h
+++ b/include/pub_tool_libcbase.h
@@ -37,6 +37,7 @@
extern Bool VG_(isspace) ( Char c );
extern Bool VG_(isdigit) ( Char c );
+extern Char VG_(tolower) ( Char c );
/* ---------------------------------------------------------------------
Converting strings to numbers
@@ -86,8 +87,11 @@
extern Char* VG_(strcpy) ( Char* dest, const Char* src );
extern Char* VG_(strncpy) ( Char* dest, const Char* src, SizeT ndest );
extern Int VG_(strcmp) ( const Char* s1, const Char* s2 );
+extern Int VG_(strcasecmp) ( const Char* s1, const Char* s2 );
extern Int VG_(strncmp) ( const Char* s1, const Char* s2, SizeT nmax );
+extern Int VG_(strncasecmp) ( const Char* s1, const Char* s2, SizeT nmax );
extern Char* VG_(strstr) ( const Char* haystack, Char* needle );
+extern Char* VG_(strcasestr) ( const Char* haystack, Char* needle );
extern Char* VG_(strchr) ( const Char* s, Char c );
extern Char* VG_(strrchr) ( const Char* s, Char c );
extern SizeT VG_(strspn) ( const Char* s, const Char* accpt );
@@ -115,6 +119,7 @@
#define VG_IS_4_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x3)))
#define VG_IS_8_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x7)))
#define VG_IS_16_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0xf)))
+#define VG_IS_32_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)0x1f)))
#define VG_IS_WORD_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(sizeof(Addr)-1))))
#define VG_IS_PAGE_ALIGNED(aaa_p) (0 == (((Addr)(aaa_p)) & ((Addr)(VKI_PAGE_SIZE-1))))
diff --git a/include/pub_tool_libcfile.h b/include/pub_tool_libcfile.h
index 916b431..5e04c96 100644
--- a/include/pub_tool_libcfile.h
+++ b/include/pub_tool_libcfile.h
@@ -85,6 +85,9 @@
extern Int VG_(readlink)( const Char* path, Char* buf, UInt bufsize );
extern Int VG_(getdents)( Int fd, struct vki_dirent *dirp, UInt count );
+extern Char* VG_(basename)( const Char* path );
+extern Char* VG_(dirname) ( const Char* path );
+
/* Copy the working directory at startup into buf[0 .. size-1], or return
False if buf is too small. */
extern Bool VG_(get_startup_wd) ( Char* buf, SizeT size );
diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h
index 7301d51..d7789a3 100644
--- a/include/pub_tool_machine.h
+++ b/include/pub_tool_machine.h
@@ -68,6 +68,17 @@
# define VG_MAX_INSTR_SZB 4
# define VG_CLREQ_SZB 20
# define VG_STACK_REDZONE_SZB 288 // is this right?
+#elif defined(VGP_x86_darwin)
+# define VG_MIN_INSTR_SZB 1 // min length of native instruction
+# define VG_MAX_INSTR_SZB 16 // max length of native instruction
+# define VG_CLREQ_SZB 14 // length of a client request, may
+ // be larger than VG_MAX_INSTR_SZB
+# define VG_STACK_REDZONE_SZB 0 // number of addressable bytes below %RSP
+#elif defined(VGP_amd64_darwin)
+# define VG_MIN_INSTR_SZB 1
+# define VG_MAX_INSTR_SZB 16
+# define VG_CLREQ_SZB 19
+# define VG_STACK_REDZONE_SZB 128
#else
# error Unknown platform
#endif
diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h
index ca40bc4..5a97bff 100644
--- a/include/pub_tool_redir.h
+++ b/include/pub_tool_redir.h
@@ -178,6 +178,8 @@
# define VG_Z_LIBC_SONAME libcZaZdaZLshrZdoZR // libc*.a(shr.o)
#elif defined(VGP_ppc64_aix5)
# define VG_Z_LIBC_SONAME libcZaZdaZLshrZu64ZdoZR // libc*.a(shr_64.o)
+#elif defined(VGO_darwin)
+# define VG_Z_LIBC_SONAME libSystemZdZaZddylib // libSystem.*.dylib
#else
# error "Unknown platform"
#endif
@@ -202,6 +204,8 @@
#if defined(VGO_linux) || defined(VGO_aix5)
# define VG_Z_LIBPTHREAD_SONAME libpthreadZdsoZd0 // libpthread.so.0
+#elif defined(VGO_darwin)
+# define VG_Z_LIBPTHREAD_SONAME libSystemZdZaZddylib // libSystem.*.dylib
#else
# error "Unknown platform"
#endif
@@ -215,6 +219,13 @@
#define VG_Z_LD_SO_1 ldZdsoZd1 // ld.so.1
#endif
+/* --- Executable name for Darwin Mach-O linker. --- */
+
+#if defined(VGO_darwin)
+#define VG_Z_DYLD dyld // dyld
+#endif
+
+
#endif // __PUB_TOOL_REDIR_H
/*--------------------------------------------------------------------*/
diff --git a/include/pub_tool_tooliface.h b/include/pub_tool_tooliface.h
index 3a7c391..5b1725c 100644
--- a/include/pub_tool_tooliface.h
+++ b/include/pub_tool_tooliface.h
@@ -439,8 +439,14 @@
what kind of error message should be emitted. */
typedef
enum { Vg_CoreStartup=1, Vg_CoreSignal, Vg_CoreSysCall,
- Vg_CoreTranslate, Vg_CoreClientReq }
- CorePart;
+ // This is for platforms where syscall args are passed on the
+ // stack; although pre_mem_read is the callback that will be
+ // called, such an arg should be treated (with respect to
+ // presenting information to the user) as if it was passed in a
+ // register, ie. like pre_reg_read.
+ Vg_CoreSysCallArgInMem,
+ Vg_CoreTranslate, Vg_CoreClientReq
+ } CorePart;
/* Events happening in core to track. To be notified, pass a callback
function to the appropriate function. To ignore an event, don't do
diff --git a/include/pub_tool_vki.h b/include/pub_tool_vki.h
index 75da646..f6c9792 100644
--- a/include/pub_tool_vki.h
+++ b/include/pub_tool_vki.h
@@ -51,6 +51,8 @@
# include "vki/vki-ppc32-aix5.h"
#elif defined(VGP_ppc64_aix5)
# include "vki/vki-ppc64-aix5.h"
+#elif defined(VGO_darwin)
+# include "vki/vki-darwin.h"
#else
# error Unknown Plat/OS
#endif
diff --git a/include/pub_tool_vkiscnums.h b/include/pub_tool_vkiscnums.h
index 061b36e..adb6cc0 100644
--- a/include/pub_tool_vkiscnums.h
+++ b/include/pub_tool_vkiscnums.h
@@ -42,6 +42,10 @@
different for each process (in principle; in practice they rarely
change). 32- and 64-bit AIX5 share a common "implementation".
+ On Darwin the __NR_name consts are #define'd constants which are
+ computed using various macros. 32- and 64-bit Darwin share a common
+ "implementation" also.
+
This file is merely a top-level "steering" file, which pulls in the
correct bits for the relevant platform. You should not directly
#include any file in include/vki; instead #include only this one or
@@ -72,10 +76,31 @@
/* Look up the name of a syscall, using the bindings previously
created by VG_(aix5_register_syscall), for the purposes of making
error messages. */
+// DDD: should combine this and VG_DARWIN_SYSNO_PRINT into a single generic
+// function which returns a string, something like VG_(pprint_sysno)().
extern UChar* VG_(aix5_sysno_to_sysname)( Int sysno );
#endif /* !defined(VG_IN_ASSEMBLY_SOURCE) */
+#elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin)
+# include "vki/vki-scnums-darwin.h"
+
+// Convert a syscall number into a nice form for printing. Unix syscalls
+// get positive numbers (0..400-odd), Mach traps get negative numbers
+// (-10..-127).
+// DDD: Machine-dependent ones get positive numbers which will overlap with
+// Unix ones! So eg. both 'pthread_set_self' and 'read' are reported as
+// "3".
+#define VG_DARWIN_SYSNO_PRINT(sysno) \
+ ((VG_DARWIN_SYSNO_CLASS(sysno) == VG_DARWIN_SYSCALL_CLASS_MACH) \
+ ? -VG_DARWIN_SYSNO_INDEX(sysno) \
+ : VG_DARWIN_SYSNO_INDEX(sysno) \
+ )
+
+/* Macros for working out which syscall a syscall number refers to. */
+#define VG_DARWIN_SYSNO_INDEX(sysno) ((sysno) & VG_DARWIN_SYSCALL_NUMBER_MASK)
+#define VG_DARWIN_SYSNO_CLASS(sysno) ((sysno) >> VG_DARWIN_SYSCALL_CLASS_SHIFT)
+
#else
# error Unknown platform
#endif
diff --git a/include/valgrind.h b/include/valgrind.h
index 679f159..da24274 100644
--- a/include/valgrind.h
+++ b/include/valgrind.h
@@ -92,26 +92,26 @@
#undef PLAT_ppc32_aix5
#undef PLAT_ppc64_aix5
-#if !defined(_AIX) && defined(__i386__)
-# define PLAT_x86_linux 1
-#elif !defined(_AIX) && defined(__x86_64__)
-# define PLAT_amd64_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && !defined(__powerpc64__)
-# define PLAT_ppc32_linux 1
-#elif !defined(_AIX) && defined(__powerpc__) && defined(__powerpc64__)
-# define PLAT_ppc64_linux 1
-#elif defined(_AIX) && defined(__64BIT__)
+
+#if defined(_AIX) && defined(__64BIT__)
# define PLAT_ppc64_aix5 1
#elif defined(_AIX) && !defined(__64BIT__)
# define PLAT_ppc32_aix5 1
-#endif
-
-
+#elif defined(__APPLE__) && defined(__i386__)
+# define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+# define PLAT_amd64_darwin 1
+#elif defined(__i386__)
+# define PLAT_x86_linux 1
+#elif defined(__x86_64__)
+# define PLAT_amd64_linux 1
+#elif defined(__powerpc__) && !defined(__powerpc64__)
+# define PLAT_ppc32_linux 1
+#elif defined(__powerpc__) && defined(__powerpc64__)
+# define PLAT_ppc64_linux 1
+#else
/* If we're not compiling for our target platform, don't generate
any inline asms. */
-#if !defined(PLAT_x86_linux) && !defined(PLAT_amd64_linux) \
- && !defined(PLAT_ppc32_linux) && !defined(PLAT_ppc64_linux) \
- && !defined(PLAT_ppc32_aix5) && !defined(PLAT_ppc64_aix5)
# if !defined(NVALGRIND)
# define NVALGRIND 1
# endif
@@ -172,9 +172,9 @@
inline asm stuff to be useful.
*/
-/* ------------------------- x86-linux ------------------------- */
+/* ------------------------- x86-{linux,darwin} ---------------- */
-#if defined(PLAT_x86_linux)
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin)
typedef
struct {
@@ -224,11 +224,11 @@
__SPECIAL_INSTRUCTION_PREAMBLE \
/* call-noredir *%EAX */ \
"xchgl %%edx,%%edx\n\t"
-#endif /* PLAT_x86_linux */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
-/* ------------------------ amd64-linux ------------------------ */
+/* ------------------------ amd64-{linux,darwin} --------------- */
-#if defined(PLAT_amd64_linux)
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
typedef
struct {
@@ -278,7 +278,7 @@
__SPECIAL_INSTRUCTION_PREAMBLE \
/* call-noredir *%RAX */ \
"xchgq %%rdx,%%rdx\n\t"
-#endif /* PLAT_amd64_linux */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
/* ------------------------ ppc32-linux ------------------------ */
@@ -632,9 +632,9 @@
do { volatile unsigned long _junk; \
CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
-/* ------------------------- x86-linux ------------------------- */
+/* ------------------------- x86-{linux,darwin} ---------------- */
-#if defined(PLAT_x86_linux)
+#if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin)
/* These regs are trashed by the hidden call. No need to mention eax
as gcc can already see that, plus causes gcc to bomb. */
@@ -1027,11 +1027,11 @@
lval = (__typeof__(lval)) _res; \
} while (0)
-#endif /* PLAT_x86_linux */
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
-/* ------------------------ amd64-linux ------------------------ */
+/* ------------------------ amd64-{linux,darwin} --------------- */
-#if defined(PLAT_amd64_linux)
+#if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin)
/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
@@ -1465,7 +1465,7 @@
lval = (__typeof__(lval)) _res; \
} while (0)
-#endif /* PLAT_amd64_linux */
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
/* ------------------------ ppc32-linux ------------------------ */
diff --git a/include/vki/Makefile.am b/include/vki/Makefile.am
index 137fe1d..81b40e5 100644
--- a/include/vki/Makefile.am
+++ b/include/vki/Makefile.am
@@ -3,6 +3,7 @@
incinc_HEADERS = \
vki-linux.h \
+ vki-darwin.h \
vki-posixtypes-amd64-linux.h \
vki-posixtypes-ppc32-linux.h \
vki-posixtypes-ppc64-linux.h \
@@ -14,7 +15,8 @@
vki-scnums-amd64-linux.h \
vki-scnums-ppc32-linux.h \
vki-scnums-ppc64-linux.h \
- vki-scnums-x86-linux.h
+ vki-scnums-x86-linux.h \
+ vki-scnums-darwin.h
noinst_HEADERS = \
vki-ppc32-aix5.h \
diff --git a/include/vki/vki-darwin.h b/include/vki/vki-darwin.h
new file mode 100644
index 0000000..cf5e542
--- /dev/null
+++ b/include/vki/vki-darwin.h
@@ -0,0 +1,1023 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Darwin-specific kernel interface. vki-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2007-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Unlike vki-linux, this Darwin kernel interface includes system headers
+ directly, to avoid copyright complexity. */
+
+#ifndef __VKI_DARWIN_H
+#define __VKI_DARWIN_H
+
+#include <stdint.h>
+
+#define vki_int8_t int8_t
+#define vki_uint8_t uint8_t
+#define vki_int16_t int16_t
+#define vki_uint16_t uint16_t
+#define vki_int32_t int32_t
+#define vki_uint32_t uint32_t
+#define vki_int64_t int64_t
+#define vki_uint64_t uint64_t
+#define vki_intptr_t intptr_t
+#define vki_uintptr_t uintptr_t
+
+#include <sys/types.h>
+
+#define vki_dev_t dev_t
+#define vki_mode_t mode_t
+#define vki_ino_t ino_t
+#define vki_ino64_t ino64_t
+#define vki_nlink_t nlink_t
+#define vki_uid_t uid_t
+#define vki_gid_t gid_t
+#define vki_time_t time_t
+#define vki_off_t off_t
+#define vki_blkcnt_t blkcnt_t
+#define vki_blksize_t blksize_t
+#define vki_size_t size_t
+#define vki_ssize_t ssize_t
+#define vki_pid_t pid_t
+#define vki_socklen_t socklen_t
+#define vki_suseconds_t suseconds_t
+#define vki_caddr_t caddr_t
+#define vki_u_long u_long
+#define vki_u_short u_short
+#define vki_clock_t clock_t
+#define vki_u_int32_t u_int32_t
+#define vki_u_int16_t u_int16_t
+
+
+// valgrind special
+
+// magic mmap() flags
+#define VKI_MAP_ANONYMOUS MAP_ANON // linux synonym
+
+// fds for mmap(MAP_ANON), displayed by vmmap
+#define VM_TAG_VALGRIND VM_MAKE_TAG(239) // SkAnonV
+
+// page sizes
+#define VKI_MAX_PAGE_SHIFT VKI_PAGE_SHIFT
+#define VKI_MAX_PAGE_SIZE VKI_PAGE_SIZE
+
+// types
+typedef uint32_t vki_u32;
+
+// linux-like ioctl flags
+#define _VKI_IOC_DIR(x) ((x) & IOC_DIRMASK)
+#define _VKI_IOC_SIZE(x) IOCPARM_LEN(x)
+#define _VKI_IOC_NONE IOC_VOID /* GrP fixme correct? */
+#define _VKI_IOC_READ IOC_OUT
+#define _VKI_IOC_WRITE IOC_IN
+
+
+#include <malloc/malloc.h>
+
+#define vki_malloc_zone_t malloc_zone_t
+
+
+#include <sys/time.h>
+
+#define vki_timeval timeval
+#define vki_timeval32 timeval32
+#define vki_timespec timespec
+#define vki_itimerval itimerval
+#define vki_timezone timezone
+
+
+#include <sys/stat.h>
+
+#define VKI_S_ISBLK(m) S_ISBLK(m)
+#define VKI_S_ISCHR(m) S_ISCHR(m)
+#define VKI_S_ISDIR(m) S_ISDIR(m)
+#define VKI_S_ISFIFO(m) S_ISFIFO(m)
+#define VKI_S_ISREG(m) S_ISREG(m)
+#define VKI_S_ISLNK(m) S_ISLNK(m)
+#define VKI_S_ISSOCK(m) S_ISSOCK(m)
+#define VKI_S_ISWHT(m) S_ISWHT(m)
+#define VKI_S_ISXATTR(m) S_ISXATTR(m)
+
+#define VKI_S_IRWXU S_IRWXU
+#define VKI_S_IRUSR S_IRUSR
+#define VKI_S_IWUSR S_IWUSR
+#define VKI_S_IXUSR S_IXUSR
+#define VKI_S_IRWXG S_IRWXG
+#define VKI_S_IRGRP S_IRGRP
+#define VKI_S_IWGRP S_IWGRP
+#define VKI_S_IXGRP S_IXGRP
+#define VKI_S_IRWXO S_IRWXO
+#define VKI_S_IROTH S_IROTH
+#define VKI_S_IWOTH S_IWOTH
+#define VKI_S_IXOTH S_IXOTH
+#define VKI_S_ISUID S_ISUID
+#define VKI_S_ISGID S_ISGID
+#define VKI_S_ISVTX S_ISVTX
+
+#define vki_stat stat
+#define vki_stat64 stat64
+
+#define st_atime st_atimespec.tv_sec
+#define st_atime_nsec st_atimespec.tv_nsec
+#define st_mtime st_mtimespec.tv_sec
+#define st_mtime_nsec st_mtimespec.tv_nsec
+#define st_ctime st_ctimespec.tv_sec
+#define st_ctime_nsec st_ctimespec.tv_nsec
+
+
+#include <sys/dirent.h>
+
+#define VKI_MAXNAMLEN MAXNAMLEN
+#define vki_dirent dirent
+
+
+#include <sys/socket.h>
+#define VKI_SOCK_STREAM SOCK_STREAM
+#define VKI_SOCK_DGRAM SOCK_DGRAM
+#define VKI_SOCK_RAW SOCK_RAW
+
+#define VKI_AF_UNIX AF_UNIX
+#define VKI_AF_INET AF_INET
+#define VKI_AF_INET6 AF_INET6
+
+#define VKI_SOL_SOCKET SOL_SOCKET
+
+#define VKI_SO_REUSEADDR SO_REUSEADDR
+
+#define VKI_SO_SNDBUF SO_SNDBUF
+#define VKI_SO_RCVBUF SO_RCVBUF
+#define VKI_SO_SNDLOWAT SO_SNDLOWAT
+#define VKI_SO_RCVLOWAT SO_RCVLOWAT
+#define VKI_SO_SNDTIMEO SO_SNDTIMEO
+#define VKI_SO_RCVTIMEO SO_RCVTIMEO
+#define VKI_SO_ERROR SO_ERROR
+#define VKI_SO_TYPE SO_TYPE
+#define VKI_SO_NREAD SO_NREAD
+#define VKI_SO_NKE SO_NKE
+#define VKI_SO_NOSIGPIPE SO_NOSIGPIPE
+#define VKI_SO_NOADDRERR SO_NOADDRERR
+#define VKI_SO_NWRITE SO_NWRITE
+#define VKI_SO_LINGER_SEC SO_LINGER_SEC
+
+#define vki_sa_family_t sa_family_t
+#define vki_sockaddr sockaddr
+#define vki_iovec iovec
+#define vki_msghdr msghdr
+#define vki_cmsghdr cmsghdr
+
+
+#define VKI_CMSG_ALIGN(a) ALIGN(a)
+#define VKI_CMSG_DATA(cmsg) CMSG_DATA(cmsg)
+#define VKI_CMSG_FIRSTHDR(mhdr) CMSG_FIRSTHDR(mhdr)
+#define VKI_CMSG_NXTHDR(mhdr, cmsg) CMSG_NXTHDR(mhdr, cmsg)
+
+#define VKI_SCM_RIGHTS SCM_RIGHTS
+#define VKI_SCM_TIMESTAMP SCM_TIMESTAMP
+#define VKI_SCM_CREDS SCM_CREDS
+
+
+#include <sys/un.h>
+
+#define vki_sockaddr_un sockaddr_un
+
+
+#include <netinet/in.h>
+
+#define vki_in_addr_t in_addr_t
+#define vki_in_port_t in_port_t
+#define vki_in_addr in_addr
+#define vki_sockaddr_in sockaddr_in
+
+#define VKI_INADDR_LOOPBACK INADDR_LOOPBACK
+
+
+// #include <netinet6/in6.h>
+
+#define vki_in6_addr in6_addr
+#define vki_sockaddr_in6 sockaddr_in6
+
+
+#include <net/if.h>
+
+#define VKI_IFNAMSIZ IFNAMSIZ
+
+#define vki_ifdevmtu ifdevmtu
+#define vki_ifreq ifreq
+#define vki_ifr_name ifr_name
+#define vki_ifr_addr ifr_addr
+#define vki_ifr_dstaddr ifr_dstaddr
+#define vki_ifr_broadaddr ifr_broadaddr
+#define vki_ifr_flags ifr_flags
+#define vki_ifr_metric ifr_metric
+#define vki_ifr_mtu ifr_mtu
+#define vki_ifr_phys ifr_phys
+#define vki_ifr_media ifr_media
+#define vki_ifr_data ifr_data
+#define vki_ifr_devmtu ifr_devmtu
+#define vki_ifr_intval ifr_intval
+
+#define vki_ifconf ifconf
+#define vki_ifc_buf ifc_buf
+#define vki_ifc_req ifc_req
+
+
+#include <sys/fcntl.h>
+
+#define VKI_SEEK_SET SEEK_SET
+#define VKI_SEEK_CUR SEEK_CUR
+#define VKI_SEEK_END SEEK_END
+
+#define VKI_O_RDONLY O_RDONLY
+#define VKI_O_WRONLY O_WRONLY
+#define VKI_O_RDWR O_RDWR
+#define VKI_O_ACCMODE O_ACCMODE
+#define VKI_O_NONBLOCK O_NONBLOCK
+#define VKI_O_APPEND O_APPEND
+#define VKI_O_SYNC O_SYN
+#define VKI_O_SHLOCK O_SHLOCK
+#define VKI_O_EXLOCK O_EXLOCK
+#define VKI_O_ASYNC O_ASYNC
+#define VKI_O_NOFOLLOW O_NOFOLLOW
+#define VKI_O_CREAT O_CREAT
+#define VKI_O_TRUNC O_TRUNC
+#define VKI_O_EXCL O_EXCL
+#define VKI_O_EVTONLY O_EVTONLY
+
+#define VKI_F_DUPFD F_DUPFD
+#define VKI_F_GETFD F_GETFD
+#define VKI_F_SETFD F_SETFD
+#define VKI_F_GETFL F_GETFL
+#define VKI_F_SETFL F_SETFL
+#define VKI_F_GETOWN F_GETOWN
+#define VKI_F_SETOWN F_SETOWN
+#define VKI_F_GETLK F_GETLK
+#define VKI_F_SETLK F_SETLK
+#define VKI_F_SETLKW F_SETLKW
+
+#define VKI_F_CHKCLEAN F_CHKCLEAN
+#define VKI_F_PREALLOCATE F_PREALLOCATE
+#define VKI_F_SETSIZE F_SETSIZE
+#define VKI_F_RDADVISE F_RDADVISE
+#define VKI_F_RDAHEAD F_RDAHEAD
+#define VKI_F_READBOOTSTRAP F_READBOOTSTRAP
+#define VKI_F_WRITEBOOTSTRAP F_WRITEBOOTSTRAP
+#define VKI_F_NOCACHE F_NOCACHE
+#define VKI_F_LOG2PHYS F_LOG2PHYS
+#define VKI_F_GETPATH F_GETPATH
+#define VKI_F_ADDSIGS F_ADDSIGS
+#define VKI_F_FULLFSYNC F_FULLFSYNC
+#define VKI_F_PATHPKG_CHECK F_PATHPKG_CHECK
+#define VKI_F_FREEZE_FS F_FREEZE_FS
+#define VKI_F_THAW_FS F_THAW_FS
+#define VKI_F_GLOBAL_NOCACHE F_GLOBAL_NOCACHE
+
+#define VKI_FD_CLOEXEC FD_CLOEXEC
+
+#define vki_radvisory radvisory
+#define vki_fstore fstore
+#define vki_fbootstraptransfer fbootstraptransfer
+#define vki_log2phys log2phys
+#define vki_fsignatures_t fsignatures_t
+
+// These constants aren't in a standard header, they are from the kernel code:
+// xnu-1228.3.13/bsd/sys/codesign.h
+// Mac OS X 10.5.6 - Darwin 9.6
+#define VKI_CS_OPS_STATUS 0 /* return status */
+#define VKI_CS_OPS_MARKINVALID 1 /* invalidate process */
+#define VKI_CS_OPS_MARKHARD 2 /* set HARD flag */
+#define VKI_CS_OPS_MARKKILL 3 /* set KILL flag (sticky) */
+#define VKI_CS_OPS_PIDPATH 4 /* get executable's pathname */
+#define VKI_CS_OPS_CDHASH 5 /* get code directory hash */
+
+#include <sys/mman.h>
+
+#define VKI_PROT_NONE PROT_NONE
+#define VKI_PROT_READ PROT_READ
+#define VKI_PROT_WRITE PROT_WRITE
+#define VKI_PROT_EXEC PROT_EXEC
+
+#define VKI_MAP_SHARED MAP_SHARED
+#define VKI_MAP_PRIVATE MAP_PRIVATE
+#define VKI_MAP_FIXED MAP_FIXED
+#define VKI_MAP_RENAME MAP_RENAME
+#define VKI_MAP_NORESERVE MAP_NORESERVE
+#define VKI_MAP_RESERVED0080 MAP_RESERVED0080
+#define VKI_MAP_NOEXTEND MAP_NOEXTEND
+#define VKI_MAP_HASSEMAPHORE MAP_HASSEMAPHORE
+#define VKI_MAP_FILE MAP_FILE
+#define VKI_MAP_ANON MAP_ANON
+#define VKI_MAP_FAILED MAP_FAILED
+
+
+#include <mach/vm_param.h>
+
+#define VKI_PAGE_SHIFT PAGE_SHIFT
+#define VKI_PAGE_SIZE PAGE_SIZE
+#define VKI_PAGE_MASK PAGE_MASK
+
+
+#include <sys/vmparam.h>
+
+#define VKI_USRSTACK USRSTACK
+#define VKI_USRSTACK64 USRSTACK64
+
+
+#include <mach/mach_time.h>
+
+#define vki_mach_timebase_info mach_timebase_info
+
+
+#include <sys/syslimits.h>
+
+#define VKI_PATH_MAX PATH_MAX
+
+
+#include <sys/param.h>
+
+#define VKI_MAXPATHLEN MAXPATHLEN
+
+
+#include <sys/signal.h>
+
+/* While we fully intend to make 'vki_sigset_t' match the native
+ Darwin 'sigset_t', we can't just clone the Darwin sigset_t type,
+ because it isn't an array, and the VG_(sigfillset) etc functions
+ assume it is. So instead define another isomorphic type, and check
+ in VG_(vki_do_initial_consistency_checks) that it really is
+ correct. */
+/* #define vki_sigset_t sigset_t */
+#define _VKI_NSIG_BPW 32
+#define _VKI_NSIG 32
+#define _VKI_NSIG_WORDS (_VKI_NSIG / _VKI_NSIG_BPW)
+typedef struct {
+ UInt sig[_VKI_NSIG_WORDS];
+} vki_sigset_t;
+/* and now let VG_(vki_do_initial_consistency_checks) make sure it
+ matches 'sigset_t'. */
+
+
+#define VKI_SS_ONSTACK SS_ONSTACK
+#define VKI_SS_DISABLE SS_DISABLE
+#define VKI_MINSIGSTKSZ MINSIGSTKSZ
+#define VKI_SIGSTKSZ SIGSTKSZ
+
+#define vki_stack_t stack_t
+#define vki_siginfo_t siginfo_t
+
+/* There are two versions of this. 'struct __sigaction' is used for
+ passing sigactions to the kernel interface, and has the added
+ complexity of requiring an extra pointer to a new demultiplexing
+ function to be run in user space. 'struct sigaction' is used for
+ receiving old sigactions from the kernel, and lacks this
+ demux-function pointer. So the type of the second and third
+ parameters in Darwin's sys_sigaction appear to be different,
+ respectively 'struct __sigaction*' and 'struct sigaction*'.
+*/
+//#define vki_sigaction __sigaction
+//#define vki_user_sigaction sigaction
+//#define vki_sigaltstack sigaltstack
+//#define vki_sigval sigval
+//#define vki_sigaction_u sigaction_u
+//#define vki_sigaction sigaction
+
+//typedef struct __sigaction vki_sigaction_toK_t;
+//typedef struct sigaction vki_sigaction_fromK_t;
+
+typedef
+ struct {
+ void* ksa_handler;
+ void (*sa_tramp)(void*,UWord,UWord,void*,void*);
+ vki_sigset_t sa_mask;
+ int sa_flags;
+ }
+ vki_sigaction_toK_t;
+
+typedef
+ struct {
+ void* ksa_handler;
+ vki_sigset_t sa_mask;
+ int sa_flags;
+ }
+ vki_sigaction_fromK_t;
+
+
+
+/* and /usr/include/sys/signal.c in turn defines 'sa_handler' to
+ be '__sigaction_u.__sa_handler' */
+//#define ksa_handler sa_handler
+
+//#define vki_sa_sigaction sa_sigaction
+
+#define VKI_SA_ONSTACK SA_ONSTACK
+#define VKI_SA_RESTART SA_RESTART
+#define VKI_SA_DISABLE SA_DISABLE
+#define VKI_SA_RESETHAND SA_RESETHAND
+#define VKI_SA_NOCLDSTOP SA_NOCLDSTOP
+#define VKI_SA_NODEFER SA_NODEFER
+#define VKI_SA_NOCLDWAIT SA_NOCLDWAIT
+#define VKI_SA_SIGINFO SA_SIGINFO
+#define VKI_SA_USERTRAMP SA_USERTRAMP
+#define VKI_SA_64REGSET SA_64REGSET
+#define VKI_SA_RESTORER 0 /* Darwin doesn't have this */
+
+#define VKI_SIG_BLOCK SIG_BLOCK
+#define VKI_SIG_UNBLOCK SIG_UNBLOCK
+#define VKI_SIG_SETMASK SIG_SETMASK
+
+#define VKI_SIGHUP SIGHUP
+#define VKI_SIGINT SIGINT
+#define VKI_SIGQUIT SIGQUIT
+#define VKI_SIGILL SIGILL
+#define VKI_SIGTRAP SIGTRAP
+#define VKI_SIGABRT SIGABRT
+#define VKI_SIGPOLL SIGPOLL
+#define VKI_SIGFPE SIGFPE
+#define VKI_SIGKILL SIGKILL
+#define VKI_SIGBUS SIGBUS
+#define VKI_SIGSEGV SIGSEGV
+#define VKI_SIGSYS SIGSYS
+#define VKI_SIGPIPE SIGPIPE
+#define VKI_SIGALRM SIGALRM
+#define VKI_SIGTERM SIGTERM
+#define VKI_SIGURG SIGURG
+#define VKI_SIGSTOP SIGSTOP
+#define VKI_SIGTSTP SIGTSTP
+#define VKI_SIGCONT SIGCONT
+#define VKI_SIGCHLD SIGCHLD
+#define VKI_SIGTTIN SIGTTIN
+#define VKI_SIGTTOU SIGTTOU
+#define VKI_SIGIO SIGIO
+#define VKI_SIGXCPU SIGXCPU
+#define VKI_SIGXFSZ SIGXFSZ
+#define VKI_SIGVTALRM SIGVTALRM
+#define VKI_SIGPROF SIGPROF
+#define VKI_SIGWINCH SIGWINCH
+#define VKI_SIGINFO SIGINFO
+#define VKI_SIGUSR1 SIGUSR1
+#define VKI_SIGUSR2 SIGUSR2
+
+#define VKI_SIG_DFL SIG_DFL
+#define VKI_SIG_IGN SIG_IGN
+
+
+#define VKI_SI_USER SI_USER
+#define VKI_SEGV_MAPERR SEGV_MAPERR
+#define VKI_SEGV_ACCERR SEGV_ACCERR
+#define VKI_ILL_ILLOPC ILL_ILLOPC
+#define VKI_ILL_ILLOPN ILL_ILLOPN
+#define VKI_ILL_ILLADR ILL_ILLADR
+#define VKI_ILL_ILLTRP ILL_ILLTRP
+#define VKI_ILL_PRVOPC ILL_PRVOPC
+#define VKI_ILL_PRVREG ILL_PRVREG
+#define VKI_ILL_COPROC ILL_COPROC
+#define VKI_ILL_BADSTK ILL_BADSTK
+#define VKI_FPE_INTDIV FPE_INTDIV
+#define VKI_FPE_INTOVF FPE_INTOVF
+#define VKI_FPE_FLTDIV FPE_FLTDIV
+#define VKI_FPE_FLTOVF FPE_FLTOVF
+#define VKI_FPE_FLTUND FPE_FLTUND
+#define VKI_FPE_FLTRES FPE_FLTRES
+#define VKI_FPE_FLTINV FPE_FLTINV
+#define VKI_FPE_FLTSUB FPE_FLTSUB
+#define VKI_BUS_ADRALN BUS_ADRALN
+#define VKI_BUS_ADRERR BUS_ADRERR
+#define VKI_BUS_OBJERR BUS_OBJERR
+#define VKI_TRAP_BRKPT TRAP_BRKPT
+
+/* JRS: not 100% sure, but I think these two are correct */
+#define VKI_SA_ONESHOT SA_RESETHAND
+#define VKI_SA_NOMASK SA_NODEFER
+
+#define VKI_UC_SET_ALT_STACK 0x40000000
+#define VKI_UC_RESET_ALT_STACK 0x80000000
+
+
+#include <sys/errno.h>
+
+#define VKI_EPERM EPERM
+#define VKI_ENOENT ENOENT
+#define VKI_ESRCH ESRCH
+#define VKI_EINTR EINTR
+#define VKI_EIO EIO
+#define VKI_ENXIO ENXIO
+#define VKI_E2BIG E2BIG
+#define VKI_ENOEXEC ENOEXEC
+#define VKI_EBADF EBADF
+#define VKI_ECHILD ECHILD
+#define VKI_EDEADLK EDEADLK
+#define VKI_ENOMEM ENOMEM
+#define VKI_EACCES EACCES
+#define VKI_EFAULT EFAULT
+#define VKI_ENOTBLK ENOTBLK
+#define VKI_EBUSY EBUSY
+#define VKI_EEXIST EEXIST
+#define VKI_EXDEV EXDEV
+#define VKI_ENODEV ENODEV
+#define VKI_ENOTDIR ENOTDIR
+#define VKI_EISDIR EISDIR
+#define VKI_EINVAL EINVAL
+#define VKI_ENFILE ENFILE
+#define VKI_EMFILE EMFILE
+#define VKI_ENOTTY ENOTTY
+#define VKI_ETXTBSY ETXTBSY
+#define VKI_EFBIG EFBIG
+#define VKI_ENOSPC ENOSPC
+#define VKI_ESPIPE ESPIPE
+#define VKI_EROFS EROFS
+#define VKI_EMLINK EMLINK
+#define VKI_EPIPE EPIPE
+#define VKI_EDOM EDOM
+#define VKI_ERANGE ERANGE
+#define VKI_EAGAIN EAGAIN
+#define VKI_EWOULDBLOCK EAGAIN
+#define VKI_EINPROGRESS EINPROGRESS
+#define VKI_EALREADY EALREADY
+#define VKI_ENOTSOCK ENOTSOCK
+#define VKI_EDESTADDRREQ EDESTADDRREQ
+#define VKI_EMSGSIZE EMSGSIZE
+#define VKI_EPROTOTYPE EPROTOTYPE
+#define VKI_ENOPROTOOPT ENOPROTOOPT
+#define VKI_EPROTONOSUPPORT EPROTONOSUPPORT
+#define VKI_ESOCKTNOSUPPORT ESOCKTNOSUPPORT
+#define VKI_ENOTSUP ENOTSUP
+#define VKI_EPFNOSUPPORT EPFNOSUPPORT
+#define VKI_EAFNOSUPPORT EAFNOSUPPORT
+#define VKI_EADDRINUSE EADDRINUSE
+#define VKI_EADDRNOTAVAIL EADDRNOTAVAIL
+#define VKI_ENETDOWN ENETDOWN
+#define VKI_ENETUNREACH ENETUNREACH
+#define VKI_ENETRESET ENETRESET
+#define VKI_ECONNABORTED ECONNABORTED
+#define VKI_ECONNRESET ECONNRESET
+#define VKI_ENOBUFS ENOBUFS
+#define VKI_EISCONN EISCONN
+#define VKI_ENOTCONN ENOTCONN
+#define VKI_ESHUTDOWN ESHUTDOWN
+#define VKI_ETOOMANYREFS ETOOMANYREFS
+#define VKI_ETIMEDOUT ETIMEDOUT
+#define VKI_ECONNREFUSED ECONNREFUSED
+#define VKI_ELOOP ELOOP
+#define VKI_ENAMETOOLONG ENAMETOOLONG
+#define VKI_EHOSTDOWN EHOSTDOWN
+#define VKI_EHOSTUNREACH EHOSTUNREACH
+#define VKI_ENOTEMPTY ENOTEMPTY
+#define VKI_EPROCLIM EPROCLIM
+#define VKI_EUSERS EUSERS
+#define VKI_EDQUOT EDQUOT
+#define VKI_ESTALE ESTALE
+#define VKI_EREMOTE EREMOTE
+#define VKI_EBADRPC EBADRPC
+#define VKI_ERPCMISMATCH ERPCMISMATCH
+#define VKI_EPROGUNAVAIL EPROGUNAVAIL
+#define VKI_EPROGMISMATCH EPROGMISMATCH
+#define VKI_EPROCUNAVAIL EPROCUNAVAIL
+#define VKI_ENOLCK ENOLCK
+#define VKI_ENOSYS ENOSYS
+#define VKI_EFTYPE EFTYPE
+#define VKI_EAUTH EAUTH
+#define VKI_ENEEDAUTH ENEEDAUTH
+#define VKI_EPWROFF EPWROFF
+#define VKI_EDEVERR EDEVERR
+#define VKI_EOVERFLOW EOVERFLOW
+#define VKI_EBADEXEC EBADEXEC
+#define VKI_EBADARCH EBADARCH
+#define VKI_ESHLIBVERS ESHLIBVERS
+#define VKI_EBADMACHO EBADMACHO
+#define VKI_ECANCELED ECANCELED
+#define VKI_EIDRM EIDRM
+#define VKI_ENOMSG ENOMSG
+#define VKI_EILSEQ EILSEQ
+#define VKI_ENOATTR ENOATTR
+#define VKI_EBADMSG EBADMSG
+#define VKI_EMULTIHOP EMULTIHOP
+#define VKI_ENODATA ENODATA
+#define VKI_ENOLINK ENOLINK
+#define VKI_ENOSR ENOSR
+#define VKI_ENOSTR ENOSTR
+#define VKI_EPROTO EPROTO
+#define VKI_ETIME ETIME
+#define VKI_EOPNOTSUPP EOPNOTSUPP
+#define VKI_ELAST ELAST
+
+
+#include <sys/resource.h>
+
+#define VKI_RLIMIT_CPU RLIMIT_CPU
+#define VKI_RLIMIT_FSIZE RLIMIT_FSIZE
+#define VKI_RLIMIT_DATA RLIMIT_DATA
+#define VKI_RLIMIT_STACK RLIMIT_STACK
+#define VKI_RLIMIT_CORE RLIMIT_CORE
+#define VKI_RLIMIT_AS RLIMIT_AD
+#define VKI_RLIMIT_RSS RLIMIT_AS
+#define VKI_RLIMIT_MEMLOCK RLIMIT_MEMLOCK
+#define VKI_RLIMIT_NPROC RLIMIT_NPROC
+#define VKI_RLIMIT_NOFILE RLIMIT_NOFILE
+#define VKI_RLIM_NLIMITS RLIM_NLIMITS
+
+#define vki_rlim_t rlim_t
+#define vki_rlimit rlimit
+#define vki_rusage rusage
+
+
+#include <sys/poll.h>
+
+#define vki_pollfd pollfd
+
+
+#include <sys/ipc.h>
+
+#define VKI_IPC_RMID IPC_RMID
+#define VKI_IPC_SET IPC_SET
+#define VKI_IPC_STAT IPC_STAT
+
+#define vki_key_t key_t
+#define vki_ipc_perm ipc_perm
+
+
+#include <sys/sem.h>
+
+#define VKI_GETNCNT GETNCNT
+#define VKI_GETPID GETPID
+#define VKI_GETVAL GETVAL
+#define VKI_GETALL GETALL
+#define VKI_GETZCNT GETZCNT
+#define VKI_SETVAL SETVAL
+#define VKI_SETALL SETALL
+
+#define vki_sembuf sembuf
+#define vki_semid_ds semid_ds
+#define vki_semun semun
+
+
+#include <sys/semaphore.h>
+
+#define vki_sem_t sem_t
+
+
+#include <sys/mount.h>
+
+#define VKI_MFSNAMELEN MFSNAMELEN
+#define VKI_MNAMELEN MNAMELEN
+
+#define vki_fsid fsid
+#define vki_fsid_t fsid_t
+#define vki_statfs statfs
+#define vki_statfs64 statfs64
+
+
+#include <sys/select.h>
+
+#define vki_fd_set fd_set
+
+
+#include <sys/msgbuf.h>
+
+#define VKI_MSG_BSIZE MSG_BSIZE
+#define VKI_MSG_MAGIC MSG_MAGIC
+#define vki_msgbuf msgbuf
+
+
+#include <sys/shm.h>
+
+#define VKI_SHM_RDONLY SHM_RDONLY
+#define VKI_SHM_RND SHM_RND
+
+#define vki_shmid_ds shmid_ds
+
+
+#include <sys/times.h>
+
+#define vki_tms tms
+
+
+#include <sys/utsname.h>
+
+#define _VKI_SYS_NAMELEN _SYS_NAMELEN
+#define vki_new_utsname utsname
+
+
+#include <sys/unistd.h>
+
+#define VKI_F_OK F_OK
+#define VKI_X_OK X_OK
+#define VKI_W_OK W_OK
+#define VKI_R_OK R_OK
+
+
+#include <sys/sysctl.h>
+
+#define VKI_CTL_MAXNAME CTL_MAXNAME
+
+#define VKI_CTL_UNSPEC CTL_UNSPEC
+#define VKI_CTL_KERN CTL_KERN
+#define VKI_CTL_VM CTL_VM
+#define VKI_CTL_VFS CTL_VFS
+#define VKI_CTL_NET CTL_NET
+#define VKI_CTL_DEBUG CTL_DEBUG
+#define VKI_CTL_HW CTL_HW
+#define VKI_CTL_MACHDEP CTL_MACHDEP
+#define VKI_CTL_USER CTL_USER
+#define VKI_CTL_MAXID CTL_MAXID
+
+#define VKI_HW_MACHINE HW_MACHINE
+#define VKI_HW_MODEL HW_MODEL
+#define VKI_HW_NCPU HW_NCPU
+#define VKI_HW_BYTEORDER HW_BYTEORDER
+#define VKI_HW_PHYSMEM HW_PHYSMEM
+#define VKI_HW_USERMEM HW_USERMEM
+#define VKI_HW_PAGESIZE HW_PAGESIZE
+#define VKI_HW_DISKNAMES HW_DISKNAMES
+#define VKI_HW_DISKSTATS HW_DISKSTATS
+#define VKI_HW_EPOCH HW_EPOCH
+#define VKI_HW_FLOATINGPT HW_FLOATINGPT
+#define VKI_HW_MACHINE_ARCH HW_MACHINE_ARCH
+#define VKI_HW_VECTORUNIT HW_VECTORUNIT
+#define VKI_HW_BUS_FREQ HW_BUS_FREQ
+#define VKI_HW_CPU_FREQ HW_CPU_FREQ
+#define VKI_HW_CACHELINE HW_CACHELINE
+#define VKI_HW_L1ICACHESIZE HW_L1ICACHESIZE
+#define VKI_HW_L1DCACHESIZE HW_L1DCACHESIZE
+#define VKI_HW_L2SETTINGS HW_L2SETTINGS
+#define VKI_HW_L2CACHESIZE HW_L2CACHESIZE
+#define VKI_HW_L3SETTINGS HW_L3SETTINGS
+#define VKI_HW_L3CACHESIZE HW_L3CACHESIZE
+#define VKI_HW_TB_FREQ HW_TB_FREQ
+#define VKI_HW_MEMSIZE HW_MEMSIZE
+#define VKI_HW_AVAILCPU MW_AVAILCPU
+#define VKI_HW_MAXID MW_MAXID
+
+#define VKI_KERN_USRSTACK32 KERN_USRSTACK32
+#define VKI_KERN_USRSTACK64 KERN_USRSTACK64
+
+
+#include <sys/attr.h>
+
+#define vki_attrlist attrlist
+
+
+#include <sys/event.h>
+
+#define vki_kevent kevent
+
+
+#include <sys/ev.h>
+
+typedef struct eventreq vki_eventreq;
+
+
+#include <sys/ptrace.h>
+
+#define VKI_PTRACE_TRACEME PT_TRACE_ME
+#define VKI_PTRACE_DETACH PT_DETACH
+
+
+// sqlite/src/os_unix.c
+
+struct ByteRangeLockPB2
+{
+ unsigned long long offset; /* offset to first byte to lock */
+ unsigned long long length; /* nbr of bytes to lock */
+ unsigned long long retRangeStart; /* nbr of 1st byte locked if successful */
+ unsigned char unLockFlag; /* 1 = unlock, 0 = lock */
+ unsigned char startEndFlag; /* 1=rel to end of fork, 0=rel to start */
+ int fd; /* file desc to assoc this lock with */
+};
+
+#define afpfsByteRangeLock2FSCTL _IOWR('z', 23, struct ByteRangeLockPB2)
+
+#define vki_ByteRangeLockPB2 ByteRangeLockPB2
+#define VKI_afpfsByteRangeLock2FSCTL afpfsByteRangeLock2FSCTL
+
+
+// xnu/bsd/sys/fsctl.h
+
+#define VKI_FSIOC_SYNC_VOLUME _IOW('A', 1, uint32_t)
+
+
+// Libc/pthreads/pthread.c
+
+#define VKI_WQOPS_QUEUE_ADD 1
+#define VKI_WQOPS_QUEUE_REMOVE 2
+#define VKI_WQOPS_THREAD_RETURN 4
+
+
+#include <sys/ttycom.h>
+
+#define vki_winsize winsize
+
+#define VKI_TIOCMODG TIOCMODG
+#define VKI_TIOCMODS TIOCMODS
+#define VKI_TIOCEXCL TIOCEXCL
+#define VKI_TIOCNXCL TIOCNXCL
+#define VKI_TIOCFLUSH TIOCFLUSH
+#define VKI_TIOCGETA TIOCGETA
+#define VKI_TIOCSETA TIOCSETA
+#define VKI_TIOCSETAW TIOCSETAW
+#define VKI_TIOCSETAF TIOCSETAF
+#define VKI_TIOCGETD TIOCGETD
+#define VKI_TIOCSETD TIOCSETD
+#define VKI_TIOCSBRK TIOCSBRK
+#define VKI_TIOCCBRK TIOCCBRK
+#define VKI_TIOCSDTR TIOCSDTR
+#define VKI_TIOCCDTR TIOCCDTR
+#define VKI_TIOCGPGRP TIOCGPGRP
+#define VKI_TIOCSPGRP TIOCSPGRP
+#define VKI_TIOCOUTQ TIOCOUTQ
+#define VKI_TIOCSTI TIOCSTI
+#define VKI_TIOCNOTTY TIOCNOTTY
+#define VKI_TIOCPKT TIOCPKT
+#define VKI_TIOCSTOP TIOCSTOP
+#define VKI_TIOCSTART TIOCSTART
+#define VKI_TIOCMSET TIOCMSET
+#define VKI_TIOCMBIS TIOCMBIS
+#define VKI_TIOCMBIC TIOCMBIC
+#define VKI_TIOCMGET TIOCMGET
+#define VKI_TIOCREMOTE TIOCREMOTE
+#define VKI_TIOCGWINSZ TIOCGWINSZ
+#define VKI_TIOCSWINSZ TIOCSWINSZ
+#define VKI_TIOCUCNTL TIOCUCNTL
+#define VKI_TIOCSTAT TIOCSTAT
+#define VKI_UIOCCMD(n) UIOCCMD(n)
+#define VKI_TIOCSCONS TIOCSCONS
+#define VKI_TIOCCONS TIOCCONS
+#define VKI_TIOCSCTTY TIOCSCTTY
+#define VKI_TIOCEXT TIOCEXT
+#define VKI_TIOCSIG TIOCSIG
+#define VKI_TIOCDRAIN TIOCDRAIN
+#define VKI_TIOCMSDTRWAIT TIOCMSDTRWAIT
+#define VKI_TIOCMGDTRWAIT TIOCMGDTRWAIT
+#define VKI_TIOCTIMESTAMP TIOCTIMESTAMP
+#define VKI_TIOCDCDTIMESTAMP TIOCDCDTIMESTAMP
+#define VKI_TIOCSDRAINWAIT TIOCSDRAINWAIT
+#define VKI_TIOCGDRAINWAIT TIOCGDRAINWAIT
+#define VKI_TIOCDSIMICROCODE TIOCDSIMICROCODE
+#define VKI_TIOCPTYGRANT TIOCPTYGRANT
+#define VKI_TIOCPTYGNAME TIOCPTYGNAME
+#define VKI_TIOCPTYUNLK TIOCPTYUNLK
+
+
+#include <sys/filio.h>
+
+#define VKI_FIOCLEX FIOCLEX
+#define VKI_FIONCLEX FIONCLEX
+#define VKI_FIONREAD FIONREAD
+#define VKI_FIONBIO FIONBIO
+#define VKI_FIOASYNC FIOASYNC
+#define VKI_FIOSETOWN FIOSETOWN
+#define VKI_FIOGETOWN FIOGETOWN
+#define VKI_FIODTYPE FIODTYPE
+
+
+#include <sys/sockio.h>
+
+#define VKI_SIOCSHIWAT SIOCSHIWAT
+#define VKI_SIOCGHIWAT SIOCGHIWAT
+#define VKI_SIOCSLOWAT SIOCSLOWAT
+#define VKI_SIOCGLOWAT SIOCGLOWAT
+#define VKI_SIOCATMARK SIOCATMARK
+#define VKI_SIOCSPGRP SIOCSPGRP
+#define VKI_SIOCGPGRP SIOCGPGRP
+
+#define VKI_SIOCSIFADDR SIOCSIFADDR
+#define VKI_OSIOCGIFADDR OSIOCGIFADDR
+#define VKI_SIOCSIFDSTADDR SIOCSIFDSTADDR
+#define VKI_OSIOCGIFDSTADDR OSIOCGIFDSTADDR
+#define VKI_SIOCSIFFLAGS SIOCSIFFLAGS
+#define VKI_SIOCGIFFLAGS SIOCGIFFLAGS
+#define VKI_OSIOCGIFBRDADDR OSIOCGIFBRDADDR
+#define VKI_SIOCSIFBRDADDR SIOCSIFBRDADDR
+#define VKI_OSIOCGIFCONF OSIOCGIFCONF
+#define VKI_OSIOCGIFNETMASK OSIOCGIFNETMASK
+#define VKI_SIOCSIFNETMASK SIOCSIFNETMASK
+#define VKI_SIOCGIFMETRIC SIOCGIFMETRIC
+#define VKI_SIOCSIFMETRIC SIOCSIFMETRIC
+#define VKI_SIOCDIFADDR SIOCDIFADDR
+#define VKI_SIOCAIFADDR SIOCAIFADDR
+#define VKI_SIOCGETVIFCNT SIOCGETVIFCNT
+#define VKI_SIOCGETSGCNT SIOCGETSGCNT
+#define VKI_SIOCALIFADDR SIOCALIFADDR
+#define VKI_SIOCGLIFADDR SIOCGLIFADDR
+#define VKI_SIOCDLIFADDR SIOCDLIFADDR
+
+#define VKI_SIOCGIFADDR SIOCGIFADDR
+#define VKI_SIOCGIFDSTADDR SIOCGIFDSTADDR
+#define VKI_SIOCGIFBRDADDR SIOCGIFBRDADDR
+#define VKI_SIOCGIFCONF SIOCGIFCONF
+#define VKI_SIOCGIFNETMASK SIOCGIFNETMASK
+#define VKI_SIOCAUTOADDR SIOCAUTOADDR
+#define VKI_SIOCAUTONETMASK SIOCAUTONETMASK
+#define VKI_SIOCARPIPLL SIOCARPIPLL
+
+#define VKI_SIOCADDMULTI SIOCADDMULTI
+#define VKI_SIOCDELMULTI SIOCDELMULTI
+#define VKI_SIOCGIFMTU SIOCGIFMTU
+#define VKI_SIOCSIFMTU SIOCSIFMTU
+#define VKI_SIOCGIFPHYS SIOCGIFPHYS
+#define VKI_SIOCSIFPHYS SIOCSIFPHYS
+#define VKI_SIOCSIFMEDIA SIOCSIFMEDIA
+#define VKI_SIOCGIFMEDIA SIOCGIFMEDIA
+#define VKI_SIOCSIFGENERIC SIOCSIFGENERIC
+#define VKI_SIOCGIFGENERIC SIOCGIFGENERIC
+#define VKI_SIOCRSLVMULTI SIOCRSLVMULTI
+
+#define VKI_SIOCSIFLLADDR SIOCSIFLLADDR
+#define VKI_SIOCGIFSTATUS SIOCGIFSTATUS
+#define VKI_SIOCSIFPHYADDR SIOCSIFPHYADDR
+#define VKI_SIOCGIFPSRCADDR SIOCGIFPSRCADDR
+#define VKI_SIOCGIFPDSTADDR SIOCGIFPDSTADDR
+#define VKI_SIOCDIFPHYADDR SIOCDIFPHYADDR
+#define VKI_SIOCSLIFPHYADDR SIOCSLIFPHYADDR
+#define VKI_SIOCGLIFPHYADDR SIOCGLIFPHYADDR
+
+#define VKI_SIOCGIFDEVMTU SIOCGIFDEVMTU
+#define VKI_SIOCSIFALTMTU SIOCSIFALTMTU
+#define VKI_SIOCGIFALTMTU SIOCGIFALTMTU
+#define VKI_SIOCSIFBOND SIOCSIFBOND
+#define VKI_SIOCGIFBOND SIOCGIFBOND
+#define VKI_SIOCIFCREATE SIOCIFCREATE
+#define VKI_SIOCIFDESTROY SIOCIFDESTROY
+#define VKI_SIOCSIFVLAN SIOCSIFVLAN
+#define VKI_SIOCGIFVLAN SIOCGIFVLAN
+
+#define VKI_SIOCSETVLAN SIOCSIFVLAN
+#define VKI_SIOCGETVLAN SIOCGIFVLAN
+
+#define VKI_SIOCGIFASYNCMAP SIOCGIFASYNCMAP
+#define VKI_SIOCSIFASYNCMAP SIOCSIGASYNCMAP
+
+
+#include <sys/dtrace.h>
+
+#define VKI_DTRACEHIOC_REMOVE DTRACEHIOC_REMOVE
+#define VKI_DTRACEHIOC_ADDDOF DTRACEHIOC_ADDDOF
+
+
+#include <sys/ucontext.h>
+
+/* quite why sys/ucontext.h provides a 'struct __darwin_ucontext'
+ but no 'struct ucontext' beats me. -- JRS */
+#define vki_ucontext __darwin_ucontext
+
+
+#include <sys/termios.h>
+
+#define vki_termios termios
+
+
+#include <uuid/uuid.h>
+
+#define vki_uuid_t uuid_t
+
+
+#include <bsm/audit.h>
+
+#define VKI_A_GETPOLICY A_GETPOLICY
+#define VKI_A_SETPOLICY A_SETPOLICY
+#define VKI_A_GETKMASK A_GETKMASK
+#define VKI_A_SETKMASK A_SETKMASK
+#define VKI_A_GETQCTRL A_GETQCTRL
+#define VKI_A_SETQCTRL A_SETQCTRL
+#define VKI_A_GETCWD A_GETCWD
+#define VKI_A_GETCAR A_GETCAR
+#define VKI_A_GETSTAT A_GETSTAT
+#define VKI_A_SETSTAT A_SETSTAT
+#define VKI_A_SETUMASK A_SETUMASK
+#define VKI_A_SETSMASK A_SETSMASK
+#define VKI_A_GETCOND A_GETCOND
+#define VKI_A_SETCOND A_SETCOND
+#define VKI_A_GETCLASS A_GETCLASS
+#define VKI_A_SETCLASS A_SETCLASS
+#define VKI_A_GETPINFO A_GETPINFO
+#define VKI_A_SETPMASK A_SETPMASK
+#define VKI_A_SETFSIZE A_SETFSIZE
+#define VKI_A_GETFSIZE A_GETFSIZE
+#define VKI_A_GETPINFO_ADDR A_GETPINFO_ADDR
+#define VKI_A_GETKAUDIT A_GETKAUDIT
+#define VKI_A_SETKAUDIT A_SETKAUDIT
+
+
+#endif
diff --git a/include/vki/vki-scnums-darwin.h b/include/vki/vki-scnums-darwin.h
new file mode 100644
index 0000000..281ccc3
--- /dev/null
+++ b/include/vki/vki-scnums-darwin.h
@@ -0,0 +1,580 @@
+
+/*--------------------------------------------------------------------*/
+/*--- System call numbers for Darwin. vki-scnums-darwin.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2007-2009 Apple Inc.
+ Greg Parker gparker@apple.com
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __VKI_SCNUMS_DARWIN_H
+#define __VKI_SCNUMS_DARWIN_H
+
+
+// osfmk/mach/i386/syscall_sw.h
+
+// x86_64's syscall numbering system is used for all architectures.
+// Don't pass __NR_something directly to any syscall instruction.
+// Hack: x86 `int $0x80` (unix, 64-bit result) are special.
+
+// Encoding: the top 8-bits are the syscall class. The low 24 are the
+// syscall number (index) within that class.
+
+#define VG_DARWIN_SYSCALL_CLASS_SHIFT 24
+#define VG_DARWIN_SYSCALL_CLASS_MASK (0xFF << VG_DARWIN_SYSCALL_CLASS_SHIFT)
+#define VG_DARWIN_SYSCALL_NUMBER_MASK (~VG_DARWIN_SYSCALL_CLASS_MASK)
+
+#define VG_DARWIN_SYSCALL_CLASS_NONE 0 /* Invalid */
+#define VG_DARWIN_SYSCALL_CLASS_MACH 1 /* Mach */
+#define VG_DARWIN_SYSCALL_CLASS_UNIX 2 /* Unix/BSD */
+#define VG_DARWIN_SYSCALL_CLASS_MDEP 3 /* Machine-dependent */
+#define VG_DARWIN_SYSCALL_CLASS_DIAG 4 /* Diagnostics */
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_MACH(syscall_number) \
+ ((VG_DARWIN_SYSCALL_CLASS_MACH << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+ (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(syscall_number) \
+ ((VG_DARWIN_SYSCALL_CLASS_UNIX << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+ (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(syscall_number) \
+ ((VG_DARWIN_SYSCALL_CLASS_MDEP << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+ (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+#define VG_DARWIN_SYSCALL_CONSTRUCT_DIAG(syscall_number) \
+ ((VG_DARWIN_SYSCALL_CLASS_DIAG << VG_DARWIN_SYSCALL_CLASS_SHIFT) | \
+ (VG_DARWIN_SYSCALL_NUMBER_MASK & (syscall_number)))
+
+
+
+// mdep syscalls
+
+#if defined(VGA_x86)
+
+// osfmk/i386/machdep_call.c
+// # define __NR_thread_get_cthread_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(0)
+// # define __NR_thread_set_cthread_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(1)
+// # define __NR_2 VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(2)
+# define __NR_pthread_set_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(3)
+// # define __NR_thread_set_user_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(4)
+// # define __NR_i386_set_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(5)
+// # define __NR_i386_get_ldt VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(6)
+
+#elif defined(VGA_amd64)
+
+// osfmk/i386/machdep_call.c
+# define __NR_pthread_set_self VG_DARWIN_SYSCALL_CONSTRUCT_MDEP(3)
+
+#else
+# error unknown architecture
+#endif
+
+
+// osfmk/mach/syscall_sw.h
+
+#define __NR_mach_reply_port VG_DARWIN_SYSCALL_CONSTRUCT_MACH(26)
+#define __NR_thread_self_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(27)
+#define __NR_task_self_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(28)
+#define __NR_host_self_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(29)
+
+#define __NR_mach_msg_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(31)
+#define __NR_mach_msg_overwrite_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(32)
+#define __NR_semaphore_signal_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(33)
+#define __NR_semaphore_signal_all_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(34)
+#define __NR_semaphore_signal_thread_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(35)
+#define __NR_semaphore_wait_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(36)
+#define __NR_semaphore_wait_signal_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(37)
+#define __NR_semaphore_timedwait_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(38)
+#define __NR_semaphore_timedwait_signal_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(39)
+
+#if defined(VGA_x86)
+#define __NR_init_process VG_DARWIN_SYSCALL_CONSTRUCT_MACH(41)
+#define __NR_map_fd VG_DARWIN_SYSCALL_CONSTRUCT_MACH(43)
+#endif
+
+#define __NR_task_name_for_pid VG_DARWIN_SYSCALL_CONSTRUCT_MACH(44)
+#define __NR_task_for_pid VG_DARWIN_SYSCALL_CONSTRUCT_MACH(45)
+#define __NR_pid_for_task VG_DARWIN_SYSCALL_CONSTRUCT_MACH(46)
+
+#if defined(VGA_x86)
+#define __NR_macx_swapon VG_DARWIN_SYSCALL_CONSTRUCT_MACH(48)
+#define __NR_macx_swapoff VG_DARWIN_SYSCALL_CONSTRUCT_MACH(49)
+#define __NR_macx_triggers VG_DARWIN_SYSCALL_CONSTRUCT_MACH(51)
+#define __NR_macx_backing_store_suspend VG_DARWIN_SYSCALL_CONSTRUCT_MACH(52)
+#define __NR_macx_backing_store_recovery VG_DARWIN_SYSCALL_CONSTRUCT_MACH(53)
+#endif
+
+#define __NR_swtch_pri VG_DARWIN_SYSCALL_CONSTRUCT_MACH(59)
+#define __NR_swtch VG_DARWIN_SYSCALL_CONSTRUCT_MACH(60)
+#define __NR_sched_yield __NR_swtch /* linux-alike name */
+#define __NR_syscall_thread_switch VG_DARWIN_SYSCALL_CONSTRUCT_MACH(61)
+#define __NR_clock_sleep_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(62)
+
+#define __NR_mach_timebase_info VG_DARWIN_SYSCALL_CONSTRUCT_MACH(89)
+#define __NR_mach_wait_until VG_DARWIN_SYSCALL_CONSTRUCT_MACH(90)
+#define __NR_mk_timer_create VG_DARWIN_SYSCALL_CONSTRUCT_MACH(91)
+#define __NR_mk_timer_destroy VG_DARWIN_SYSCALL_CONSTRUCT_MACH(92)
+#define __NR_mk_timer_arm VG_DARWIN_SYSCALL_CONSTRUCT_MACH(93)
+#define __NR_mk_timer_cancel VG_DARWIN_SYSCALL_CONSTRUCT_MACH(94)
+
+#define __NR_iokit_user_client_trap VG_DARWIN_SYSCALL_CONSTRUCT_MACH(100)
+
+
+// bsd/sys/syscall.h
+
+#define __NR_syscall VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(0)
+#define __NR_exit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(1)
+#define __NR_fork VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(2) // was UX64
+#define __NR_read VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(3)
+#define __NR_write VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(4)
+#define __NR_open VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(5)
+#define __NR_close VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(6)
+#define __NR_wait4 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(7)
+ /* 8 old creat */
+#define __NR_link VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(9)
+#define __NR_unlink VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(10)
+ /* 11 old execv */
+#define __NR_chdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(12)
+#define __NR_fchdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(13)
+#define __NR_mknod VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(14)
+#define __NR_chmod VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(15)
+#define __NR_chown VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(16)
+ /* 17 old break */
+#define __NR_getfsstat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(18)
+ /* 19 old lseek */
+#define __NR_getpid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(20)
+ /* 21 old mount */
+ /* 22 old umount */
+#define __NR_setuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(23)
+#define __NR_getuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(24)
+#define __NR_geteuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(25)
+#define __NR_ptrace VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(26)
+#define __NR_recvmsg VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(27)
+#define __NR_sendmsg VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(28)
+#define __NR_recvfrom VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(29)
+#define __NR_accept VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(30)
+#define __NR_getpeername VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(31)
+#define __NR_getsockname VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(32)
+#define __NR_access VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(33)
+#define __NR_chflags VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(34)
+#define __NR_fchflags VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(35)
+#define __NR_sync VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(36)
+#define __NR_kill VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(37)
+ /* 38 old stat */
+#define __NR_getppid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(39)
+ /* 40 old lstat */
+#define __NR_dup VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(41)
+#define __NR_pipe VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(42) // was UX64
+#define __NR_getegid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(43)
+#define __NR_profil VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(44)
+ /* 45 old ktrace */
+#define __NR_sigaction VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(46)
+#define __NR_getgid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(47)
+#define __NR_sigprocmask VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(48)
+#define __NR_getlogin VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(49)
+#define __NR_setlogin VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(50)
+#define __NR_acct VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(51)
+#define __NR_sigpending VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(52)
+#define __NR_sigaltstack VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(53)
+#define __NR_ioctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(54)
+#define __NR_reboot VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(55)
+#define __NR_revoke VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(56)
+#define __NR_symlink VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(57)
+#define __NR_readlink VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(58)
+#define __NR_execve VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(59)
+#define __NR_umask VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(60)
+#define __NR_chroot VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(61)
+ /* 62 old fstat */
+ /* 63 used internally , reserved */
+ /* 64 old getpagesize */
+#define __NR_msync VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(65)
+#define __NR_vfork VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(66)
+ /* 67 old vread */
+ /* 68 old vwrite */
+ /* 69 old sbrk */
+ /* 70 old sstk */
+ /* 71 old mmap */
+ /* 72 old vadvise */
+#define __NR_munmap VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(73)
+#define __NR_mprotect VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(74)
+#define __NR_madvise VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(75)
+ /* 76 old vhangup */
+ /* 77 old vlimit */
+#define __NR_mincore VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(78)
+#define __NR_getgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(79)
+#define __NR_setgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(80)
+#define __NR_getpgrp VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(81)
+#define __NR_setpgid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(82)
+#define __NR_setitimer VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(83)
+ /* 84 old wait */
+#define __NR_swapon VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(85)
+#define __NR_getitimer VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(86)
+ /* 87 old gethostname */
+ /* 88 old sethostname */
+#define __NR_getdtablesize VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(89)
+#define __NR_dup2 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(90)
+ /* 91 old getdopt */
+#define __NR_fcntl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(92)
+#define __NR_select VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(93)
+ /* 94 old setdopt */
+#define __NR_fsync VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(95)
+#define __NR_setpriority VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(96)
+#define __NR_socket VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(97)
+#define __NR_connect VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(98)
+ /* 99 old accept */
+#define __NR_getpriority VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(100)
+ /* 101 old send */
+ /* 102 old recv */
+ /* 103 old sigreturn */
+#define __NR_bind VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(104)
+#define __NR_setsockopt VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(105)
+#define __NR_listen VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(106)
+ /* 107 old vtimes */
+ /* 108 old sigvec */
+ /* 109 old sigblock */
+ /* 110 old sigsetmask */
+#define __NR_sigsuspend VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(111)
+ /* 112 old sigstack */
+ /* 113 old recvmsg */
+ /* 114 old sendmsg */
+ /* 115 old vtrace */
+#define __NR_gettimeofday VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(116)
+#define __NR_getrusage VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(117)
+#define __NR_getsockopt VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(118)
+ /* 119 old resuba */
+#define __NR_readv VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(120)
+#define __NR_writev VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(121)
+#define __NR_settimeofday VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(122)
+#define __NR_fchown VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(123)
+#define __NR_fchmod VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(124)
+ /* 125 old recvfrom */
+#define __NR_setreuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(126)
+#define __NR_setregid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(127)
+#define __NR_rename VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(128)
+ /* 129 old truncate */
+ /* 130 old ftruncate */
+#define __NR_flock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(131)
+#define __NR_mkfifo VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(132)
+#define __NR_sendto VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(133)
+#define __NR_shutdown VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(134)
+#define __NR_socketpair VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(135)
+#define __NR_mkdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(136)
+#define __NR_rmdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(137)
+#define __NR_utimes VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(138)
+#define __NR_futimes VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(139)
+#define __NR_adjtime VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(140)
+ /* 141 old getpeername */
+#define __NR_gethostuuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(142)
+ /* 143 old sethostid */
+ /* 144 old getrlimit */
+ /* 145 old setrlimit */
+ /* 146 old killpg */
+#define __NR_setsid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(147)
+ /* 148 old setquota */
+ /* 149 old qquota */
+ /* 150 old getsockname */
+#define __NR_getpgid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(151)
+#define __NR_setprivexec VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(152)
+#define __NR_pread VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(153)
+#define __NR_pwrite VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(154)
+#define __NR_nfssvc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(155)
+ /* 156 old getdirentries */
+#define __NR_statfs VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(157)
+#define __NR_fstatfs VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(158)
+#define __NR_unmount VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(159)
+ /* 160 old async_daemon */
+#define __NR_getfh VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(161)
+ /* 162 old getdomainname */
+ /* 163 old setdomainname */
+ /* 164 */
+#define __NR_quotactl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(165)
+ /* 166 old exportfs */
+#define __NR_mount VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(167)
+ /* 168 old ustat */
+#define __NR_csops VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(169)
+ /* 170 old table */
+ /* 171 old wait3 */
+ /* 172 old rpause */
+#define __NR_waitid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(173)
+ /* 174 old getdents */
+ /* 175 old gc_control */
+#define __NR_add_profil VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(176)
+ /* 177 */
+ /* 178 */
+ /* 179 */
+#define __NR_kdebug_trace VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(180)
+#define __NR_setgid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(181)
+#define __NR_setegid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(182)
+#define __NR_seteuid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(183)
+#define __NR_sigreturn VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(184)
+#define __NR_chud VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(185)
+ /* 186 */
+ /* 187 */
+#define __NR_stat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(188)
+#define __NR_fstat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(189)
+#define __NR_lstat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(190)
+#define __NR_pathconf VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(191)
+#define __NR_fpathconf VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(192)
+ /* 193 */
+#define __NR_getrlimit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(194)
+#define __NR_setrlimit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(195)
+#define __NR_getdirentries VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(196)
+#define __NR_mmap VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(197)
+ /* 198 __syscall */
+#define __NR_lseek VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(199) // was UX64
+#define __NR_truncate VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(200)
+#define __NR_ftruncate VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(201)
+#define __NR___sysctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(202)
+#define __NR_mlock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(203)
+#define __NR_munlock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(204)
+#define __NR_undelete VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(205)
+#define __NR_ATsocket VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(206)
+#define __NR_ATgetmsg VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(207)
+#define __NR_ATputmsg VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(208)
+#define __NR_ATPsndreq VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(209)
+#define __NR_ATPsndrsp VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(210)
+#define __NR_ATPgetreq VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(211)
+#define __NR_ATPgetrsp VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(212)
+ /* 213 Reserved for AppleTalk */
+#define __NR_kqueue_from_portset_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(214)
+#define __NR_kqueue_portset_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(215)
+#define __NR_mkcomplex VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(216)
+#define __NR_statv VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(217)
+#define __NR_lstatv VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(218)
+#define __NR_fstatv VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(219)
+#define __NR_getattrlist VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(220)
+#define __NR_setattrlist VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(221)
+#define __NR_getdirentriesattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(222)
+#define __NR_exchangedata VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(223)
+ /* 224 checkuseraccess */
+#define __NR_searchfs VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(225)
+#define __NR_delete VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(226)
+#define __NR_copyfile VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(227)
+ /* 228 */
+ /* 229 */
+#define __NR_poll VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(230)
+#define __NR_watchevent VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(231)
+#define __NR_waitevent VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(232)
+#define __NR_modwatch VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(233)
+#define __NR_getxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(234)
+#define __NR_fgetxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(235)
+#define __NR_setxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(236)
+#define __NR_fsetxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(237)
+#define __NR_removexattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(238)
+#define __NR_fremovexattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(239)
+#define __NR_listxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(240)
+#define __NR_flistxattr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(241)
+#define __NR_fsctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(242)
+#define __NR_initgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(243)
+#define __NR_posix_spawn VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(244)
+ /* 245 */
+ /* 246 */
+#define __NR_nfsclnt VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(247)
+#define __NR_fhopen VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(248)
+ /* 249 */
+#define __NR_minherit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(250)
+#define __NR_semsys VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(251)
+#define __NR_msgsys VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(252)
+#define __NR_shmsys VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(253)
+#define __NR_semctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(254)
+#define __NR_semget VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(255)
+#define __NR_semop VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(256)
+ /* 257 */
+#define __NR_msgctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(258)
+#define __NR_msgget VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(259)
+#define __NR_msgsnd VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(260)
+#define __NR_msgrcv VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(261)
+#define __NR_shmat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(262)
+#define __NR_shmctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(263)
+#define __NR_shmdt VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(264)
+#define __NR_shmget VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(265)
+#define __NR_shm_open VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(266)
+#define __NR_shm_unlink VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(267)
+#define __NR_sem_open VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(268)
+#define __NR_sem_close VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(269)
+#define __NR_sem_unlink VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(270)
+#define __NR_sem_wait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(271)
+#define __NR_sem_trywait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(272)
+#define __NR_sem_post VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(273)
+#define __NR_sem_getvalue VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(274)
+#define __NR_sem_init VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(275)
+#define __NR_sem_destroy VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(276)
+#define __NR_open_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(277)
+#define __NR_umask_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(278)
+#define __NR_stat_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(279)
+#define __NR_lstat_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(280)
+#define __NR_fstat_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(281)
+#define __NR_chmod_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(282)
+#define __NR_fchmod_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(283)
+#define __NR_access_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(284)
+#define __NR_settid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(285)
+#define __NR_gettid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(286)
+#define __NR_setsgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(287)
+#define __NR_getsgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(288)
+#define __NR_setwgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(289)
+#define __NR_getwgroups VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(290)
+#define __NR_mkfifo_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(291)
+#define __NR_mkdir_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(292)
+#define __NR_identitysvc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(293)
+#define __NR_shared_region_check_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(294)
+#define __NR_shared_region_map_np VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(295)
+ /* 296 old load_shared_file */
+ /* 297 old reset_shared_file */
+ /* 298 old new_system_shared_regions */
+ /* 299 old shared_region_map_file_np */
+ /* 300 old shared_region_make_private_np */
+#define __NR___pthread_mutex_destroy VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(301)
+#define __NR___pthread_mutex_init VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(302)
+#define __NR___pthread_mutex_lock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(303)
+#define __NR___pthread_mutex_trylock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(304)
+#define __NR___pthread_mutex_unlock VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(305)
+#define __NR___pthread_cond_init VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(306)
+#define __NR___pthread_cond_destroy VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(307)
+#define __NR___pthread_cond_broadcast VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(308)
+#define __NR___pthread_cond_signal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(309)
+#define __NR_getsid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(310)
+#define __NR_settid_with_pid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(311)
+#define __NR___pthread_cond_timedwait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(312)
+#define __NR_aio_fsync VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(313)
+#define __NR_aio_return VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(314)
+#define __NR_aio_suspend VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(315)
+#define __NR_aio_cancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(316)
+#define __NR_aio_error VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(317)
+#define __NR_aio_read VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(318)
+#define __NR_aio_write VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(319)
+#define __NR_lio_listio VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(320)
+#define __NR___pthread_cond_wait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(321)
+#define __NR_iopolicysys VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(322)
+ /* 323 */
+#define __NR_mlockall VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(324)
+#define __NR_munlockall VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(325)
+ /* 326 */
+#define __NR_issetugid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(327)
+#define __NR___pthread_kill VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(328)
+#define __NR___pthread_sigmask VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(329)
+#define __NR___sigwait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(330)
+#define __NR_sigwait VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(330) // GrP fixme hack
+#define __NR___disable_threadsignal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(331)
+#define __NR___pthread_markcancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(332)
+#define __NR___pthread_canceled VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(333)
+#define __NR___semwait_signal VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(334)
+ /* 335 old utrace */
+#define __NR_proc_info VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(336)
+#define __NR_sendfile VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(337)
+#define __NR_stat64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(338)
+#define __NR_fstat64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(339)
+#define __NR_lstat64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(340)
+#define __NR_stat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(341)
+#define __NR_lstat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(342)
+#define __NR_fstat64_extended VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(343)
+#define __NR_getdirentries64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(344)
+#define __NR_statfs64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(345)
+#define __NR_fstatfs64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(346)
+#define __NR_getfsstat64 VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(347)
+#define __NR___pthread_chdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(348)
+#define __NR___pthread_fchdir VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(349)
+
+#define __NR_audit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(350)
+#define __NR_auditon VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(351)
+ /* 352 */
+#define __NR_getauid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(353)
+#define __NR_setauid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(354)
+#define __NR_getaudit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(355)
+#define __NR_setaudit VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(356)
+#define __NR_getaudit_addr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(357)
+#define __NR_setaudit_addr VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(358)
+#define __NR_auditctl VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(359)
+#define __NR_bsdthread_create VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(360)
+#define __NR_bsdthread_terminate VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(361)
+#define __NR_kqueue VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(362)
+#define __NR_kevent VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(363)
+#define __NR_lchown VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(364)
+#define __NR_stack_snapshot VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(365)
+#define __NR_bsdthread_register VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(366)
+#define __NR_workq_open VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(367)
+#define __NR_workq_ops VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(368)
+ /* 369 */
+ /* 370 */
+ /* 371 */
+ /* 372 */
+ /* 373 */
+ /* 374 */
+ /* 375 */
+ /* 376 */
+ /* 377 */
+ /* 378 */
+ /* 379 */
+#define __NR___mac_execve VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(380)
+#define __NR___mac_syscall VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(381)
+#define __NR___mac_get_file VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(382)
+#define __NR___mac_set_file VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(383)
+#define __NR___mac_get_link VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(384)
+#define __NR___mac_set_link VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(385)
+#define __NR___mac_get_proc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(386)
+#define __NR___mac_set_proc VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(387)
+#define __NR___mac_get_fd VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(388)
+#define __NR___mac_set_fd VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(389)
+#define __NR___mac_get_pid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(390)
+#define __NR___mac_get_lcid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(391)
+#define __NR___mac_get_lctx VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(392)
+#define __NR___mac_set_lctx VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(393)
+#define __NR_setlcid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(394)
+#define __NR_getlcid VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(395)
+#define __NR_read_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(396)
+#define __NR_write_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(397)
+#define __NR_open_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(398)
+#define __NR_close_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(399)
+#define __NR_wait4_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(400)
+#define __NR_recvmsg_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(401)
+#define __NR_sendmsg_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(402)
+#define __NR_recvfrom_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(403)
+#define __NR_accept_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(404)
+#define __NR_msync_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(405)
+#define __NR_fcntl_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(406)
+#define __NR_select_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(407)
+#define __NR_fsync_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(408)
+#define __NR_connect_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(409)
+#define __NR_sigsuspend_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(410)
+#define __NR_readv_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(411)
+#define __NR_writev_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(412)
+#define __NR_sendto_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(413)
+#define __NR_pread_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(414)
+#define __NR_pwrite_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(415)
+#define __NR_waitid_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(416)
+#define __NR_poll_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(417)
+#define __NR_msgsnd_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(418)
+#define __NR_msgrcv_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(419)
+#define __NR_sem_wait_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(420)
+#define __NR_aio_suspend_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(421)
+#define __NR___sigwait_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(422)
+#define __NR___semwait_signal_nocancel VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(423)
+#define __NR___mac_mount VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(424)
+#define __NR___mac_get_mount VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(425)
+#define __NR___mac_getfsstat VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(426)
+#define __NR_MAXSYSCALL VG_DARWIN_SYSCALL_CONSTRUCT_UNIX(427)
+
+#define __NR_DARWIN_FAKE_SIGRETURN (1 + __NR_MAXSYSCALL)
+
+#endif
diff --git a/lackey/Makefile.am b/lackey/Makefile.am
index 69a1a82..6a2ff3d 100644
--- a/lackey/Makefile.am
+++ b/lackey/Makefile.am
@@ -19,6 +19,12 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += lackey-ppc64-aix5
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += lackey-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += lackey-amd64-darwin
+endif
LACKEY_SOURCES_COMMON = lk_main.c
@@ -63,3 +69,17 @@
lackey_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
lackey_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
lackey_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+lackey_x86_darwin_SOURCES = $(LACKEY_SOURCES_COMMON)
+lackey_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+lackey_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+lackey_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+lackey_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+lackey_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+lackey_amd64_darwin_SOURCES = $(LACKEY_SOURCES_COMMON)
+lackey_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+lackey_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+lackey_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+lackey_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+lackey_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/massif/Makefile.am b/massif/Makefile.am
index 6ff1f51..3033df1 100644
--- a/massif/Makefile.am
+++ b/massif/Makefile.am
@@ -5,6 +5,7 @@
bin_SCRIPTS = ms_print
noinst_PROGRAMS =
+noinst_DSYMS =
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
noinst_PROGRAMS += massif-x86-linux vgpreload_massif-x86-linux.so
endif
@@ -23,6 +24,14 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += massif-ppc64-aix5 vgpreload_massif-ppc64-aix5.so
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += massif-x86-darwin vgpreload_massif-x86-darwin.so
+noinst_DSYMS += vgpreload_massif-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += massif-amd64-darwin vgpreload_massif-amd64-darwin.so
+noinst_DSYMS += vgpreload_massif-amd64-darwin.so
+endif
vgpreload_massif_x86_linux_so_SOURCES =
vgpreload_massif_x86_linux_so_CPPFLAGS = $(AM_CPPFLAGS_X86_LINUX)
@@ -72,6 +81,22 @@
$(PRELOAD_LDFLAGS_PPC64_AIX5) \
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+vgpreload_massif_x86_darwin_so_SOURCES =
+vgpreload_massif_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_massif_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_massif_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_massif_x86_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_X86_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_massif_amd64_darwin_so_SOURCES =
+vgpreload_massif_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_massif_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC)
+vgpreload_massif_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_massif_amd64_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
MASSIF_SOURCES_COMMON = ms_main.c
massif_x86_linux_SOURCES = $(MASSIF_SOURCES_COMMON)
@@ -115,3 +140,17 @@
massif_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
massif_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
massif_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+massif_x86_darwin_SOURCES = $(MASSIF_SOURCES_COMMON)
+massif_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+massif_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+massif_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+massif_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+massif_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+massif_amd64_darwin_SOURCES = $(MASSIF_SOURCES_COMMON)
+massif_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+massif_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+massif_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+massif_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+massif_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 318fc11..f3d46fe 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -1288,8 +1288,10 @@
// Take a snapshot, and only that -- decisions on whether to take a
// snapshot, or what kind of snapshot, are made elsewhere.
+// Nb: we call the arg "my_time" because "time" shadows a global declaration
+// in /usr/include/time.h on Darwin.
static void
-take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time time,
+take_snapshot(Snapshot* snapshot, SnapshotKind kind, Time my_time,
Bool is_detailed)
{
tl_assert(!is_snapshot_in_use(snapshot));
@@ -1314,7 +1316,7 @@
// Rest of snapshot.
snapshot->kind = kind;
- snapshot->time = time;
+ snapshot->time = my_time;
sanity_check_snapshot(snapshot);
// Update stats.
@@ -1341,12 +1343,14 @@
Snapshot* snapshot;
Bool is_detailed;
- Time time = get_time();
+ // Nb: we call this variable "my_time" because "time" shadows a global
+ // declaration in /usr/include/time.h on Darwin.
+ Time my_time = get_time();
switch (kind) {
case Normal:
// Only do a snapshot if it's time.
- if (time < earliest_possible_time_of_next_snapshot) {
+ if (my_time < earliest_possible_time_of_next_snapshot) {
n_skipped_snapshots++;
n_skipped_snapshots_since_last_snapshot++;
return;
@@ -1376,7 +1380,7 @@
// Take the snapshot.
snapshot = & snapshots[next_snapshot_i];
- take_snapshot(snapshot, kind, time, is_detailed);
+ take_snapshot(snapshot, kind, my_time, is_detailed);
// Record if it was detailed.
if (is_detailed) {
@@ -1422,7 +1426,7 @@
}
// Work out the earliest time when the next snapshot can happen.
- earliest_possible_time_of_next_snapshot = time + min_time_interval;
+ earliest_possible_time_of_next_snapshot = my_time + min_time_interval;
}
diff --git a/massif/tests/malloc_usable.c b/massif/tests/malloc_usable.c
index 4a0e470..2578173 100644
--- a/massif/tests/malloc_usable.c
+++ b/massif/tests/malloc_usable.c
@@ -5,7 +5,7 @@
int main(void)
{
-# if !defined(VGO_aix5)
+# if !defined(VGO_aix5) && !defined(VGO_darwin)
// Because our allocations are in multiples of 8 or 16, 99 will round up
// to 104 or 112.
int* x = malloc(99);
diff --git a/memcheck/Makefile.am b/memcheck/Makefile.am
index e042a6b..e11e841 100644
--- a/memcheck/Makefile.am
+++ b/memcheck/Makefile.am
@@ -3,6 +3,7 @@
SUBDIRS += perf
noinst_PROGRAMS =
+noinst_DSYMS =
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
noinst_PROGRAMS += memcheck-x86-linux vgpreload_memcheck-x86-linux.so
endif
@@ -21,6 +22,14 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += memcheck-ppc64-aix5 vgpreload_memcheck-ppc64-aix5.so
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += memcheck-x86-darwin vgpreload_memcheck-x86-darwin.so
+noinst_DSYMS += vgpreload_memcheck-x86-darwin.so
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += memcheck-amd64-darwin vgpreload_memcheck-amd64-darwin.so
+noinst_DSYMS += vgpreload_memcheck-amd64-darwin.so
+endif
VGPRELOAD_MEMCHECK_SOURCES_COMMON = mc_replace_strmem.c
@@ -78,6 +87,24 @@
$(PRELOAD_LDFLAGS_PPC64_AIX5) \
$(LIBREPLACEMALLOC_LDFLAGS_PPC64_AIX5)
+vgpreload_memcheck_x86_darwin_so_SOURCES = $(VGPRELOAD_MEMCHECK_SOURCES_COMMON)
+vgpreload_memcheck_x86_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_CFLAGS = $(AM_CFLAGS_X86_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_memcheck_x86_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_X86_DARWIN)
+vgpreload_memcheck_x86_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_X86_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN)
+
+vgpreload_memcheck_amd64_darwin_so_SOURCES = $(VGPRELOAD_MEMCHECK_SOURCES_COMMON)
+vgpreload_memcheck_amd64_darwin_so_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) $(AM_CFLAGS_PIC) -O2
+vgpreload_memcheck_amd64_darwin_so_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_DEPENDENCIES = $(LIBREPLACEMALLOC_AMD64_DARWIN)
+vgpreload_memcheck_amd64_darwin_so_LDFLAGS = \
+ $(PRELOAD_LDFLAGS_AMD64_DARWIN) \
+ $(LIBREPLACEMALLOC_LDFLAGS_AMD64_DARWIN)
+
MEMCHECK_SOURCES_COMMON = \
mc_leakcheck.c \
mc_malloc_wrappers.c \
@@ -134,6 +161,22 @@
memcheck_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
memcheck_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+memcheck_x86_darwin_SOURCES = $(MEMCHECK_SOURCES_COMMON)
+memcheck_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+memcheck_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN) -O2
+memcheck_x86_darwin_CCASFLAGS = $(AM_CCASFLAGS_X86_DARWIN)
+memcheck_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+memcheck_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+memcheck_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+memcheck_amd64_darwin_SOURCES = $(MEMCHECK_SOURCES_COMMON)
+memcheck_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+memcheck_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN) -O2
+memcheck_amd64_darwin_CCASFLAGS = $(AM_CCASFLAGS_AMD64_DARWIN)
+memcheck_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+memcheck_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+memcheck_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
+
mcincludedir = $(includedir)/valgrind
mcinclude_HEADERS = \
diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c
index e56a163..edc123a 100644
--- a/memcheck/mc_errors.c
+++ b/memcheck/mc_errors.c
@@ -268,7 +268,7 @@
if (maybe_gcc) {
VG_(message)(Vg_UserMsg,
"%sAddress 0x%llx is just below the stack ptr. "
- "To suppress, use: --workaround-gcc296-bugs=yes%s",
+ "To suppress, use: --workaround-gcc296-bugs=yes%s",
xpre, (ULong)a, xpost
);
} else {
diff --git a/memcheck/mc_machine.c b/memcheck/mc_machine.c
index 4072b8a..05f6da4 100644
--- a/memcheck/mc_machine.c
+++ b/memcheck/mc_machine.c
@@ -491,6 +491,7 @@
if (o == GOF(IP_AT_SYSCALL) && sz == 8) return -1; /* slot unused */
if (o == GOF(IDFLAG) && sz == 8) return -1; /* slot used for %DH */
if (o == GOF(FS_ZERO) && sz == 8) return -1; /* slot unused */
+ if (o == GOF(GS_0x60) && sz == 8) return -1; /* slot unused */
if (o == GOF(TISTART) && sz == 8) return -1; /* slot unused */
if (o == GOF(TILEN) && sz == 8) return -1; /* slot unused */
diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c
index 8cf7a7b..a6660ad 100644
--- a/memcheck/mc_main.c
+++ b/memcheck/mc_main.c
@@ -92,8 +92,9 @@
/* Conceptually, every byte value has 8 V bits, which track whether Memcheck
thinks the corresponding value bit is defined. And every memory byte
has an A bit, which tracks whether Memcheck thinks the program can access
- it safely. So every N-bit register is shadowed with N V bits, and every
- memory byte is shadowed with 8 V bits and one A bit.
+ it safely (ie. it's mapped, and has at least one of the RWX permission bits
+ set). So every N-bit register is shadowed with N V bits, and every memory
+ byte is shadowed with 8 V bits and one A bit.
In the implementation, we use two forms of compression (compressed V bits
and distinguished secondary maps) to avoid the 9-bit-per-byte overhead
@@ -3667,6 +3668,10 @@
isAddrErr ? 0 : otag );
break;
+ case Vg_CoreSysCallArgInMem:
+ MC_(record_regparam_error) ( tid, s, otag );
+ break;
+
/* If we're being asked to jump to a silly address, record an error
message before potentially crashing the entire system. */
case Vg_CoreTranslate:
@@ -3697,10 +3702,19 @@
}
static
+void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
+ ULong di_handle )
+{
+ if (rr || ww || xx)
+ MC_(make_mem_defined)(a, len);
+ else
+ MC_(make_mem_noaccess)(a, len);
+}
+
+static
void mc_new_mem_startup( Addr a, SizeT len,
Bool rr, Bool ww, Bool xx, ULong di_handle )
{
- /* Ignore the permissions, just make it defined. Seems to work... */
// Because code is defined, initialised variables get put in the data
// segment and are defined, and uninitialised variables get put in the
// bss segment and are auto-zeroed (and so defined).
@@ -3711,16 +3725,14 @@
// false negative, but it's a grey area -- the behaviour is defined (the
// padding is zeroed) but it's probably not what the user intended. And
// we can't avoid it.
+ //
+ // Note: we generally ignore RWX permissions, because we can't track them
+ // without requiring more than one A bit which would slow things down a
+ // lot. But on Darwin the 0th page is mapped but !R and !W and !X.
+ // So we mark any such pages as "unaddressable".
DEBUG("mc_new_mem_startup(%#lx, %llu, rr=%u, ww=%u, xx=%u)\n",
a, (ULong)len, rr, ww, xx);
- MC_(make_mem_defined)(a, len);
-}
-
-static
-void mc_new_mem_mmap ( Addr a, SizeT len, Bool rr, Bool ww, Bool xx,
- ULong di_handle )
-{
- MC_(make_mem_defined)(a, len);
+ mc_new_mem_mmap(a, len, rr, ww, xx, di_handle);
}
static
@@ -5110,6 +5122,7 @@
return True;
}
+
/*------------------------------------------------------------*/
/*--- Crude profiling machinery. ---*/
/*------------------------------------------------------------*/
diff --git a/memcheck/mc_replace_strmem.c b/memcheck/mc_replace_strmem.c
index b7c30fc..6c5e31b 100644
--- a/memcheck/mc_replace_strmem.c
+++ b/memcheck/mc_replace_strmem.c
@@ -117,6 +117,9 @@
STRRCHR(VG_Z_LIBC_SONAME, rindex)
#if defined(VGO_linux)
STRRCHR(VG_Z_LD_LINUX_SO_2, rindex)
+#elif defined(VGO_darwin)
+STRRCHR(VG_Z_DYLD, strrchr)
+STRRCHR(VG_Z_DYLD, rindex)
#endif
@@ -141,6 +144,9 @@
STRCHR(VG_Z_LD_LINUX_SO_2, index)
STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, strchr)
STRCHR(VG_Z_LD_LINUX_X86_64_SO_2, index)
+#elif defined(VGO_darwin)
+STRCHR(VG_Z_DYLD, strchr)
+STRCHR(VG_Z_DYLD, index)
#endif
@@ -194,6 +200,51 @@
}
STRNCAT(VG_Z_LIBC_SONAME, strncat)
+#if defined(VGO_darwin)
+STRNCAT(VG_Z_DYLD, strncat)
+#endif
+
+
+/* Append src to dst. n is the size of dst's buffer. dst is guaranteed
+ to be nul-terminated after the copy, unless n <= strlen(dst_orig).
+ Returns min(n, strlen(dst_orig)) + strlen(src_orig).
+ Truncation occurred if retval >= n.
+*/
+#define STRLCAT(soname, fnname) \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( char* dst, const char* src, SizeT n ); \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ ( char* dst, const char* src, SizeT n ) \
+ { \
+ const Char* src_orig = src; \
+ Char* dst_orig = dst; \
+ SizeT m = 0; \
+\
+ while (m < n && *dst) { m++; dst++; } \
+ if (m < n) { \
+ /* Fill as far as dst_orig[n-2], then nul-terminate. */ \
+ while (m < n-1 && *src) { m++; *dst++ = *src++; } \
+ *dst = 0; \
+ } else { \
+ /* No space to copy anything to dst. m == n */ \
+ } \
+ /* Finish counting min(n, strlen(dst_orig)) + strlen(src_orig) */ \
+ while (*src) { m++; src++; } \
+ /* This checks for overlap after copying, unavoidable without */ \
+ /* pre-counting lengths... should be ok */ \
+ if (is_overlap(dst_orig, \
+ src_orig, \
+ (Addr)dst-(Addr)dst_orig+1, \
+ (Addr)src-(Addr)src_orig+1)) \
+ RECORD_OVERLAP_ERROR("strlcat", dst_orig, src_orig, n); \
+\
+ return m; \
+ }
+
+#if defined(VGO_darwin)
+STRLCAT(VG_Z_LIBC_SONAME, strlcat)
+STRLCAT(VG_Z_DYLD, strlcat)
+#endif
#define STRNLEN(soname, fnname) \
@@ -250,6 +301,9 @@
}
STRCPY(VG_Z_LIBC_SONAME, strcpy)
+#if defined(VGO_darwin)
+STRCPY(VG_Z_DYLD, strcpy)
+#endif
#define STRNCPY(soname, fnname) \
@@ -273,6 +327,40 @@
}
STRNCPY(VG_Z_LIBC_SONAME, strncpy)
+#if defined(VGO_darwin)
+STRNCPY(VG_Z_DYLD, strncpy)
+#endif
+
+
+/* Copy up to n-1 bytes from src to dst. Then nul-terminate dst if n > 0.
+ Returns strlen(src). Does not zero-fill the remainder of dst. */
+#define STRLCPY(soname, fnname) \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
+ ( char* dst, const char* src, SizeT n ); \
+ SizeT VG_REPLACE_FUNCTION_ZU(soname, fnname) \
+ ( char* dst, const char* src, SizeT n ) \
+ { \
+ const char* src_orig = src; \
+ char* dst_orig = dst; \
+ SizeT m = 0; \
+\
+ while (m < n-1 && *src) { m++; *dst++ = *src++; } \
+ /* m non-nul bytes have now been copied, and m <= n-1. */ \
+ /* Check for overlap after copying; all n bytes of dst are relevant, */ \
+ /* but only m+1 bytes of src if terminator was found */ \
+ if (is_overlap(dst_orig, src_orig, n, (m < n) ? m+1 : n)) \
+ RECORD_OVERLAP_ERROR("strlcpy", dst, src, n); \
+ /* Nul-terminate dst. */ \
+ if (n > 0) *dst = 0; \
+ /* Finish counting strlen(src). */ \
+ while (*src) src++; \
+ return src - src_orig; \
+ }
+
+#if defined(VGO_darwin)
+STRLCPY(VG_Z_LIBC_SONAME, strlcpy)
+STRLCPY(VG_Z_DYLD, strlcpy)
+#endif
#define STRNCMP(soname, fnname) \
@@ -296,6 +384,9 @@
}
STRNCMP(VG_Z_LIBC_SONAME, strncmp)
+#if defined(VGO_darwin)
+STRNCMP(VG_Z_DYLD, strncmp)
+#endif
#define STRCMP(soname, fnname) \
@@ -338,6 +429,9 @@
}
MEMCHR(VG_Z_LIBC_SONAME, memchr)
+#if defined(VGO_darwin)
+MEMCHR(VG_Z_DYLD, memchr)
+#endif
#define MEMCPY(soname, fnname) \
@@ -389,6 +483,8 @@
#if defined(VGO_linux)
MEMCPY(VG_Z_LD_SO_1, memcpy) /* ld.so.1 */
MEMCPY(VG_Z_LD64_SO_1, memcpy) /* ld64.so.1 */
+#elif defined(VGO_darwin)
+MEMCPY(VG_Z_DYLD, memcpy)
#endif
/* icc9 blats these around all over the place. Not only in the main
executable but various .so's. They are highly tuned and read
@@ -430,6 +526,9 @@
MEMCMP(VG_Z_LIBC_SONAME, bcmp)
#if defined(VGO_linux)
MEMCMP(VG_Z_LD_SO_1, bcmp)
+#elif defined(VGO_darwin)
+MEMCMP(VG_Z_DYLD, memcmp)
+MEMCMP(VG_Z_DYLD, bcmp)
#endif
@@ -460,6 +559,8 @@
#if defined(VGO_linux)
STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy)
STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy)
+#elif defined(VGO_darwin)
+STPCPY(VG_Z_DYLD, stpcpy)
#endif
@@ -483,6 +584,9 @@
}
MEMSET(VG_Z_LIBC_SONAME, memset)
+#if defined(VGO_darwin)
+MEMSET(VG_Z_DYLD, memset)
+#endif
#define MEMMOVE(soname, fnname) \
@@ -507,6 +611,35 @@
}
MEMMOVE(VG_Z_LIBC_SONAME, memmove)
+#if defined(VGO_darwin)
+MEMMOVE(VG_Z_DYLD, memmove)
+#endif
+
+
+#define BCOPY(soname, fnname) \
+ void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ (const void *srcV, void *dstV, SizeT n); \
+ void VG_REPLACE_FUNCTION_ZU(soname,fnname) \
+ (const void *srcV, void *dstV, SizeT n) \
+ { \
+ SizeT i; \
+ Char* dst = (Char*)dstV; \
+ Char* src = (Char*)srcV; \
+ if (dst < src) { \
+ for (i = 0; i < n; i++) \
+ dst[i] = src[i]; \
+ } \
+ else \
+ if (dst > src) { \
+ for (i = 0; i < n; i++) \
+ dst[n-i-1] = src[n-i-1]; \
+ } \
+ }
+
+#if defined(VGO_darwin)
+BCOPY(VG_Z_LIBC_SONAME, bcopy)
+BCOPY(VG_Z_DYLD, bcopy)
+#endif
/* glibc 2.5 variant of memmove which checks the dest is big enough.
diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am
index b5be28d..96101cb 100644
--- a/memcheck/tests/Makefile.am
+++ b/memcheck/tests/Makefile.am
@@ -15,13 +15,16 @@
if VGCONF_OS_IS_LINUX
SUBDIRS += linux
endif
+if VGCONF_OS_IS_DARWIN
+SUBDIRS += darwin
+endif
# Platform-specific tests
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
SUBDIRS += x86-linux
endif
-DIST_SUBDIRS = x86 amd64 linux x86-linux .
+DIST_SUBDIRS = x86 amd64 linux darwin x86-linux .
noinst_SCRIPTS = \
filter_addressable \
@@ -105,7 +108,7 @@
noisy_child.vgtest noisy_child.stderr.exp noisy_child.stdout.exp \
null_socket.stderr.exp null_socket.vgtest \
origin1-yes.vgtest origin1-yes.stdout.exp \
- origin1-yes.stderr.exp \
+ origin1-yes.stderr.exp origin1-yes.stderr.exp-darwin \
origin2-not-quite.vgtest origin2-not-quite.stdout.exp \
origin2-not-quite.stderr.exp \
origin3-no.vgtest origin3-no.stdout.exp \
@@ -138,12 +141,13 @@
sh-mem-random.stderr.exp sh-mem-random.stdout.exp64 \
sh-mem-random.stdout.exp sh-mem-random.vgtest \
sigaltstack.stderr.exp sigaltstack.vgtest \
- sigkill.stderr.exp sigkill.vgtest \
+ sigkill.stderr.exp sigkill.stderr.exp-darwin sigkill.vgtest \
signal2.stderr.exp signal2.stdout.exp signal2.vgtest \
sigprocmask.stderr.exp sigprocmask.stderr.exp2 sigprocmask.vgtest \
stack_changes.stderr.exp stack_changes.stdout.exp \
stack_changes.stdout.exp2 stack_changes.vgtest \
- strchr.stderr.exp strchr.stderr.exp2 strchr.vgtest \
+ strchr.stderr.exp strchr.stderr.exp2 strchr.stderr.exp-darwin \
+ strchr.vgtest \
str_tester.stderr.exp str_tester.vgtest \
supp_unknown.stderr.exp supp_unknown.vgtest supp_unknown.supp \
supp1.stderr.exp supp1.vgtest \
@@ -298,6 +302,10 @@
varinfo5_LDADD = `pwd`/varinfo5so.so
varinfo5_LDFLAGS = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ varinfo5_LDADD = `pwd`/varinfo5so.so
+ varinfo5_LDFLAGS = $(AM_FLAG_M3264_PRI)
+else
varinfo5_LDADD = varinfo5so.so
varinfo5_LDFLAGS = $(AM_FLAG_M3264_PRI) \
-Wl,-rpath,$(top_builddir)/memcheck/tests
@@ -313,10 +321,16 @@
varinfo5so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ varinfo5so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+ -dynamiclib -all_load
+else
varinfo5so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-soname -Wl,varinfo5so.so
endif
endif
+endif
+
# Build shared object for wrap7
wrap7_SOURCES = wrap7.c
wrap7_DEPENDENCIES = wrap7so.so
@@ -328,11 +342,16 @@
wrap7_LDADD = `pwd`/wrap7so.so
wrap7_LDFLAGS = $(AM_FLAG_M3264_PRI) -Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ wrap7_LDADD = `pwd`/wrap7so.so
+ wrap7_LDFLAGS = $(AM_FLAG_M3264_PRI)
+else
wrap7_LDADD = wrap7so.so
wrap7_LDFLAGS = $(AM_FLAG_M3264_PRI) \
-Wl,-rpath,$(top_builddir)/memcheck/tests
endif
endif
+endif
wrap7so_so_SOURCES = wrap7so.c
wrap7so_so_CFLAGS = $(AM_CFLAGS) -fpic
@@ -343,9 +362,15 @@
wrap7so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-G -Wl,-bnogc
else
+if VGCONF_OS_IS_DARWIN
+ wrap7so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -dynamic \
+ -dynamiclib -all_load
+else
wrap7so_so_LDFLAGS = -fpic $(AM_FLAG_M3264_PRI) -shared \
-Wl,-soname -Wl,wrap7so.so
endif
endif
+endif
+endif
diff --git a/memcheck/tests/amd64/Makefile.am b/memcheck/tests/amd64/Makefile.am
index bb1c803..5dedb0d 100644
--- a/memcheck/tests/amd64/Makefile.am
+++ b/memcheck/tests/amd64/Makefile.am
@@ -22,10 +22,18 @@
xor-undef-amd64.stderr.exp xor-undef-amd64.stdout.exp \
xor-undef-amd64.vgtest
-check_PROGRAMS = bt_everything bug132146 defcfaexpr fxsave-amd64 \
- int3-amd64 \
- more_x87_fp sse_memory xor-undef-amd64
+check_PROGRAMS = bt_everything bug132146 fxsave-amd64 \
+ xor-undef-amd64
+# DDD: not sure if these ones should work on Darwin or not... if not, should
+# be moved into amd64-linux/.
+if ! VGCONF_OS_IS_DARWIN
+ check_PROGRAMS += \
+ defcfaexpr \
+ int3-amd64 \
+ more_x87_fp \
+ sse_memory
+endif
AM_CFLAGS += @FLAG_M64@
AM_CXXFLAGS += @FLAG_M64@
diff --git a/memcheck/tests/badjump2.c b/memcheck/tests/badjump2.c
index d91283c..a4ba803 100644
--- a/memcheck/tests/badjump2.c
+++ b/memcheck/tests/badjump2.c
@@ -24,7 +24,7 @@
/* Install own SIGSEGV handler */
sigsegv_new.sa_handler = SIGSEGV_handler;
sigsegv_new.sa_flags = 0;
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
sigsegv_new.sa_restorer = NULL;
#endif
res = sigemptyset( &sigsegv_new.sa_mask );
diff --git a/memcheck/tests/darwin/Makefile.am b/memcheck/tests/darwin/Makefile.am
new file mode 100644
index 0000000..9d41756
--- /dev/null
+++ b/memcheck/tests/darwin/Makefile.am
@@ -0,0 +1,20 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+noinst_SCRIPTS = filter_stderr
+
+noinst_HEADERS = scalar.h
+
+EXTRA_DIST = $(noinst_SCRIPTS) \
+ scalar.stderr.exp scalar.vgtest \
+ scalar_fork.stderr.exp scalar_fork.vgtest \
+ scalar_vfork.stderr.exp scalar_vfork.vgtest
+
+check_PROGRAMS = \
+ scalar scalar_fork scalar_vfork
+
+
+AM_CFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CXXFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
+AM_CCASFLAGS += @FLAG_M32@
+
diff --git a/memcheck/tests/darwin/filter_stderr b/memcheck/tests/darwin/filter_stderr
new file mode 100644
index 0000000..0ae9313
--- /dev/null
+++ b/memcheck/tests/darwin/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/memcheck/tests/darwin/scalar.c b/memcheck/tests/darwin/scalar.c
new file mode 100644
index 0000000..2ee66ea
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.c
@@ -0,0 +1,1726 @@
+#include "../../memcheck.h"
+#include "scalar.h"
+#include <unistd.h>
+#include <sched.h>
+#include <signal.h>
+
+// See memcheck/tests/x86-linux/scalar.c for an explanation of what this test
+// is doing.
+
+int main(void)
+{
+ // uninitialised, but we know px[0] is 0x0
+ long* px = malloc(sizeof(long));
+ long x0 = px[0];
+ long res;
+
+ VALGRIND_MAKE_MEM_NOACCESS(0, 0x1000);
+
+ // __NR_syscall 0
+ // XXX
+
+ // __NR_exit 1
+ GO(__NR_exit, "below");
+ // (see below)
+
+ // __NR_fork 2
+ GO(__NR_fork, "other");
+ // (sse scalar_fork.c)
+
+ // __NR_read 3
+ // Nb: here we are also getting an error from the syscall arg itself.
+ GO(__NR_read, "1+3s 1m");
+ SY(__NR_read+(int)x0, x0, x0, x0+1); FAILx(EFAULT);
+
+ // __NR_write 4
+ GO(__NR_write, "3s 1m");
+ SY(__NR_write, x0, x0, x0+1); FAIL;
+ //res = write(x0, x0, x0+1); FAIL;
+
+ // __NR_open 5
+ // __NR_close 6
+ // __NR_wait4 7
+ // /* 8 old creat */
+ // __NR_link 9
+ // __NR_unlink 10
+ // /* 11 old execv */
+ // __NR_chdir 12
+ // __NR_fchdir 13
+ // __NR_mknod 14
+ // __NR_chmod 15
+ // __NR_chown 16
+ // /* 17 old break */
+ // __NR_getfsstat 18
+ // /* 19 old lseek */
+ // __NR_getpid 20
+ // /* 21 old mount */
+ // /* 22 old umount */
+ // __NR_setuid 23
+ // __NR_getuid 24
+ // __NR_geteuid 25
+ // __NR_ptrace 26
+ // __NR_recvmsg 27
+ // __NR_sendmsg 28
+ // __NR_recvfrom 29
+ // __NR_accept 30
+ // __NR_getpeername 31
+ // __NR_getsockname 32
+ // __NR_access 33
+ // __NR_chflags 34
+ // __NR_fchflags 35
+ // __NR_sync 36
+ // __NR_kill 37
+ // /* 38 old stat */
+ // __NR_getppid 39
+ // /* 40 old lstat */
+ // __NR_dup 41
+ // __NR_pipe VG_DARWIN_SYSCALL_CONSTRUCT_UX64(42
+ // __NR_getegid 43
+ // __NR_profil 44
+ // /* 45 old ktrace */
+ // __NR_sigaction 46
+ // __NR_getgid 47
+ // __NR_sigprocmask 48
+ // __NR_getlogin 49
+ // __NR_setlogin 50
+ // __NR_acct 51
+ // __NR_sigpending 52
+ // __NR_sigaltstack 53
+ // __NR_ioctl 54
+ // __NR_reboot 55
+ // __NR_revoke 56
+ // __NR_symlink 57
+ // __NR_readlink 58
+ // __NR_execve 59
+ // __NR_umask 60
+ // __NR_chroot 61
+ // /* 62 old fstat */
+ // /* 63 used internally , reserved */
+ // /* 64 old getpagesize */
+ // __NR_msync 65
+ // __NR_vfork 66
+ // /* 67 old vread */
+ // /* 68 old vwrite */
+ // /* 69 old sbrk */
+ // /* 70 old sstk */
+ // /* 71 old mmap */
+ // /* 72 old vadvise */
+ // __NR_munmap 73
+ // __NR_mprotect 74
+ // __NR_madvise 75
+ // /* 76 old vhangup */
+ // /* 77 old vlimit */
+ // __NR_mincore 78
+ // __NR_getgroups 79
+ // __NR_setgroups 80
+ // __NR_getpgrp 81
+ // __NR_setpgid 82
+ // __NR_setitimer 83
+ // /* 84 old wait */
+ // __NR_swapon 85
+ // __NR_getitimer 86
+ // /* 87 old gethostname */
+ // /* 88 old sethostname */
+ // __NR_getdtablesize 89
+ // __NR_dup2 90
+ // /* 91 old getdopt */
+ // __NR_fcntl 92
+ // __NR_select 93
+ // /* 94 old setdopt */
+ // __NR_fsync 95
+ // __NR_setpriority 96
+ // __NR_socket 97
+ // __NR_connect 98
+ // /* 99 old accept */
+ // __NR_getpriority 100
+ // /* 101 old send */
+ // /* 102 old recv */
+ // /* 103 old sigreturn */
+ // __NR_bind 104
+
+ // __NR_setsockopt 105
+ GO(__NR_setsockopt, "5s 1m");
+ SY(__NR_setsockopt, x0, x0, x0, x0+1, x0+1); FAIL;
+
+ // __NR_listen 106
+ // /* 107 old vtimes */
+ // /* 108 old sigvec */
+ // /* 109 old sigblock */
+ // /* 110 old sigsetmask */
+ // __NR_sigsuspend 111
+ // /* 112 old sigstack */
+ // /* 113 old recvmsg */
+ // /* 114 old sendmsg */
+ // /* 115 old vtrace */
+ // __NR_gettimeofday 116
+ // __NR_getrusage 117
+
+ // __NR_getsockopt 118
+ // Nb: there's no "getsockopt(optlen) points to unaddressable byte(s)";
+ // difficult to get with arg4 being checked with buf_and_len_pre_check.
+ GO(__NR_getsockopt, "5s 1m");
+ SY(__NR_getsockopt, x0, x0, x0, x0+1, x0+&px[1]); FAIL;
+
+ // /* 119 old resuba */
+ // __NR_readv 120
+ // __NR_writev 121
+ // __NR_settimeofday 122
+ // __NR_fchown 123
+ // __NR_fchmod 124
+ // /* 125 old recvfrom */
+ // __NR_setreuid 126
+ // __NR_setregid 127
+ // __NR_rename 128
+ // /* 129 old truncate */
+ // /* 130 old ftruncate */
+ // __NR_flock 131
+ // __NR_mkfifo 132
+ // __NR_sendto 133
+ // __NR_shutdown 134
+ // __NR_socketpair 135
+ // __NR_mkdir 136
+ // __NR_rmdir 137
+ // __NR_utimes 138
+ // __NR_futimes 139
+ // __NR_adjtime 140
+ // /* 141 old getpeername */
+ // __NR_gethostuuid 142
+ // /* 143 old sethostid */
+ // /* 144 old getrlimit */
+ // /* 145 old setrlimit */
+ // /* 146 old killpg */
+ // __NR_setsid 147
+ // /* 148 old setquota */
+ // /* 149 old qquota */
+ // /* 150 old getsockname */
+ // __NR_getpgid 151
+ // __NR_setprivexec 152
+ // __NR_pread 153
+ // __NR_pwrite 154
+ // __NR_nfssvc 155
+ // /* 156 old getdirentries */
+ // __NR_statfs 157
+ // __NR_fstatfs 158
+ // __NR_unmount 159
+ // /* 160 old async_daemon */
+ // __NR_getfh 161
+ // /* 162 old getdomainname */
+ // /* 163 old setdomainname */
+ // /* 164 */
+ // __NR_quotactl 165
+ // /* 166 old exportfs */
+ // __NR_mount 167
+ // /* 168 old ustat */
+
+ // __NR_csops 169
+ GO(__NR_csops, "4s 1m");
+ SY(__NR_csops, x0, x0, x0+1, x0+1); FAILx(EFAULT);
+
+ // /* 170 old table */
+ // /* 171 old wait3 */
+ // /* 172 old rpause */
+ // __NR_waitid 173
+ // /* 174 old getdents */
+ // /* 175 old gc_control */
+ // __NR_add_profil 176
+ // /* 177 */
+ // /* 178 */
+ // /* 179 */
+ // __NR_kdebug_trace 180
+ // __NR_setgid 181
+ // __NR_setegid 182
+ // __NR_seteuid 183
+ // __NR_sigreturn 184
+ // __NR_chud 185
+ // /* 186 */
+ // /* 187 */
+ // __NR_stat 188
+ // __NR_fstat 189
+ // __NR_lstat 190
+ // __NR_pathconf 191
+ // __NR_fpathconf 192
+ // /* 193 */
+ // __NR_getrlimit 194
+ // __NR_setrlimit 195
+ // __NR_getdirentries 196
+ // __NR_mmap 197
+ // /* 198 __syscall */
+ // __NR_lseek VG_DARWIN_SYSCALL_CONSTRUCT_UX64(199
+ // __NR_truncate 200
+ // __NR_ftruncate 201
+ // __NR___sysctl 202
+ // __NR_mlock 203
+ // __NR_munlock 204
+ // __NR_undelete 205
+ // __NR_ATsocket 206
+ // __NR_ATgetmsg 207
+ // __NR_ATputmsg 208
+ // __NR_ATPsndreq 209
+ // __NR_ATPsndrsp 210
+ // __NR_ATPgetreq 211
+ // __NR_ATPgetrsp 212
+ // /* 213 Reserved for AppleTalk */
+ // __NR_kqueue_from_portset_np 214
+ // __NR_kqueue_portset_np 215
+ // __NR_mkcomplex 216
+ // __NR_statv 217
+ // __NR_lstatv 218
+ // __NR_fstatv 219
+ // __NR_getattrlist 220
+ // __NR_setattrlist 221
+ // __NR_getdirentriesattr 222
+ // __NR_exchangedata 223
+ // /* 224 checkuseraccess */
+ // __NR_searchfs 225
+ // __NR_delete 226
+ // __NR_copyfile 227
+ // /* 228 */
+ // /* 229 */
+ // __NR_poll 230
+ // __NR_watchevent 231
+ // __NR_waitevent 232
+ // __NR_modwatch 233
+ // __NR_getxattr 234
+ // __NR_fgetxattr 235
+ // __NR_setxattr 236
+ // __NR_fsetxattr 237
+ // __NR_removexattr 238
+ // __NR_fremovexattr 239
+ // __NR_listxattr 240
+ // __NR_flistxattr 241
+ // __NR_fsctl 242
+ // __NR_initgroups 243
+ // __NR_posix_spawn 244
+ // /* 245 */
+ // /* 246 */
+ // __NR_nfsclnt 247
+ // __NR_fhopen 248
+ // /* 249 */
+ // __NR_minherit 250
+ // __NR_semsys 251
+ // __NR_msgsys 252
+ // __NR_shmsys 253
+ // __NR_semctl 254
+ // __NR_semget 255
+ // __NR_semop 256
+ // /* 257 */
+ // __NR_msgctl 258
+ // __NR_msgget 259
+ // __NR_msgsnd 260
+ // __NR_msgrcv 261
+ // __NR_shmat 262
+ // __NR_shmctl 263
+ // __NR_shmdt 264
+
+ // __NR_shmget 265
+ GO(__NR_shmget, "3s 0m");
+ SY(__NR_shmget, x0, x0, x0); FAIL;
+
+ // __NR_shm_open 266
+ // __NR_shm_unlink 267
+
+ // __NR_sem_open 268
+ GO(__NR_sem_open, "2s 1m");
+ SY(__NR_sem_open, x0, x0); FAIL;
+
+ GO(__NR_sem_open, "(4-args) 2s 0m");
+ SY(__NR_sem_open, "my_sem", O_CREAT|O_EXCL, x0, x0); SUCC_OR_FAIL;
+
+ // __NR_sem_close 269
+ // Nb: we add 0x12345 to make sure it's not a valid semaphore descriptor.
+ GO(__NR_sem_close, "1s 0m");
+ SY(__NR_sem_close, x0+0x12345); FAIL;
+
+ // __NR_sem_unlink 270
+ GO(__NR_sem_unlink, "1s 1m");
+ SY(__NR_sem_unlink, x0); FAIL;
+
+ // __NR_sem_wait 271
+ // __NR_sem_trywait 272
+
+ // __NR_sem_post 273
+ GO(__NR_sem_post, "1s 0m");
+ SY(__NR_sem_post, x0); FAIL;
+
+ // __NR_sem_getvalue 274
+
+ // __NR_sem_init 275
+ GO(__NR_sem_init, "3s 1m");
+ SY(__NR_sem_init, x0+1, x0, x0); FAILx(ENOSYS);
+
+ // __NR_sem_destroy 276
+ GO(__NR_sem_destroy, "1s 1m");
+ SY(__NR_sem_destroy, x0+1); FAILx(ENOSYS);
+
+ // __NR_open_extended 277
+ // __NR_umask_extended 278
+ // __NR_stat_extended 279
+ // __NR_lstat_extended 280
+ // __NR_fstat_extended 281
+ // __NR_chmod_extended 282
+ // __NR_fchmod_extended 283
+ // __NR_access_extended 284
+ // __NR_settid 285
+ // __NR_gettid 286
+ // __NR_setsgroups 287
+ // __NR_getsgroups 288
+ // __NR_setwgroups 289
+ // __NR_getwgroups 290
+ // __NR_mkfifo_extended 291
+ // __NR_mkdir_extended 292
+ // __NR_identitysvc 293
+ // __NR_shared_region_check_np 294
+ // __NR_shared_region_map_np 295
+ // /* 296 old load_shared_file */
+ // /* 297 old reset_shared_file */
+ // /* 298 old new_system_shared_regions */
+ // /* 299 old shared_region_map_file_np */
+ // /* 300 old shared_region_make_private_np */
+ // __NR___pthread_mutex_destroy 301
+ // __NR___pthread_mutex_init 302
+ // __NR___pthread_mutex_lock 303
+ // __NR___pthread_mutex_trylock 304
+ // __NR___pthread_mutex_unlock 305
+ // __NR___pthread_cond_init 306
+ // __NR___pthread_cond_destroy 307
+ // __NR___pthread_cond_broadcast 308
+ // __NR___pthread_cond_signal 309
+ // __NR_getsid 310
+ // __NR_settid_with_pid 311
+ // __NR___pthread_cond_timedwait 312
+ // __NR_aio_fsync 313
+ // __NR_aio_return 314
+ // __NR_aio_suspend 315
+ // __NR_aio_cancel 316
+ // __NR_aio_error 317
+ // __NR_aio_read 318
+ // __NR_aio_write 319
+ // __NR_lio_listio 320
+ // __NR___pthread_cond_wait 321
+ // __NR_iopolicysys 322
+ // /* 323 */
+ // __NR_mlockall 324
+ // __NR_munlockall 325
+ // /* 326 */
+ // __NR_issetugid 327
+ // __NR___pthread_kill 328
+ // __NR___pthread_sigmask 329
+ // __NR___sigwait 330
+ // __NR_sigwait 330) // GrP fixme hack
+ // __NR___disable_threadsignal 331
+ // __NR___pthread_markcancel 332
+ // __NR___pthread_canceled 333
+ // __NR___semwait_signal 334
+ // /* 335 old utrace */
+ // __NR_proc_info 336
+ // __NR_sendfile 337
+ // __NR_stat64 338
+ // __NR_fstat64 339
+ // __NR_lstat64 340
+ // __NR_stat64_extended 341
+ // __NR_lstat64_extended 342
+ // __NR_fstat64_extended 343
+ // __NR_getdirentries64 344
+ // __NR_statfs64 345
+ // __NR_fstatfs64 346
+ // __NR_getfsstat64 347
+ // __NR___pthread_chdir 348
+ // __NR___pthread_fchdir 349
+ // __NR_audit 350
+ // __NR_auditon 351
+ // /* 352 */
+ // __NR_getauid 353
+ // __NR_setauid 354
+ // __NR_getaudit 355
+ // __NR_setaudit 356
+ // __NR_getaudit_addr 357
+ // __NR_setaudit_addr 358
+ // __NR_auditctl 359
+ // __NR_bsdthread_create 360
+ // __NR_bsdthread_terminate 361
+ // __NR_kqueue 362
+ // __NR_kevent 363
+ // __NR_lchown 364
+ // __NR_stack_snapshot 365
+ // __NR_bsdthread_register 366
+ // __NR_workq_open 367
+ // __NR_workq_ops 368
+ // /* 369 */
+ // /* 370 */
+ // /* 371 */
+ // /* 372 */
+ // /* 373 */
+ // /* 374 */
+ // /* 375 */
+ // /* 376 */
+ // /* 377 */
+ // /* 378 */
+ // /* 379 */
+ // __NR___mac_execve 380
+ // __NR___mac_syscall 381
+ // __NR___mac_get_file 382
+ // __NR___mac_set_file 383
+ // __NR___mac_get_link 384
+ // __NR___mac_set_link 385
+ // __NR___mac_get_proc 386
+ // __NR___mac_set_proc 387
+ // __NR___mac_get_fd 388
+ // __NR___mac_set_fd 389
+ // __NR___mac_get_pid 390
+ // __NR___mac_get_lcid 391
+ // __NR___mac_get_lctx 392
+ // __NR___mac_set_lctx 393
+ // __NR_setlcid 394
+ // __NR_getlcid 395
+ // __NR_read_nocancel 396
+ // __NR_write_nocancel 397
+ // __NR_open_nocancel 398
+ // __NR_close_nocancel 399
+ // __NR_wait4_nocancel 400
+ // __NR_recvmsg_nocancel 401
+ // __NR_sendmsg_nocancel 402
+ // __NR_recvfrom_nocancel 403
+ // __NR_accept_nocancel 404
+ // __NR_msync_nocancel 405
+ // __NR_fcntl_nocancel 406
+ // __NR_select_nocancel 407
+ // __NR_fsync_nocancel 408
+ // __NR_connect_nocancel 409
+ // __NR_sigsuspend_nocancel 410
+ // __NR_readv_nocancel 411
+ // __NR_writev_nocancel 412
+ // __NR_sendto_nocancel 413
+ // __NR_pread_nocancel 414
+ // __NR_pwrite_nocancel 415
+ // __NR_waitid_nocancel 416
+ // __NR_poll_nocancel 417
+ // __NR_msgsnd_nocancel 418
+ // __NR_msgrcv_nocancel 419
+
+ // __NR_sem_wait_nocancel 420
+ GO(__NR_sem_wait_nocancel, "1s 0m");
+ SY(__NR_sem_wait_nocancel, x0); FAIL;
+
+ // __NR_aio_suspend_nocancel 421
+ // __NR___sigwait_nocancel 422
+ // __NR___semwait_signal_nocancel 423
+ // __NR___mac_mount 424
+ // __NR___mac_get_mount 425
+ // __NR___mac_getfsstat 426
+ // __NR_MAXSYSCALL 427
+
+#if 0
+ // XXX: all these are copied from x86-darwin/scalar.c.
+
+ // __NR_open 5
+ GO(__NR_open, "(2-args) 2s 1m");
+ SY(__NR_open, x0, x0); FAIL;
+
+ // Only 1s 0m errors -- the other 2s 1m have been checked in the previous
+ // open test, and if we test them they may be commoned up but they also
+ // may not.
+ GO(__NR_open, "(3-args) 1s 0m");
+ SY(__NR_open, "scalar.c", O_CREAT|O_EXCL, x0); FAIL;
+
+ // __NR_close 6
+ GO(__NR_close, "1s 0m");
+ SY(__NR_close, x0-1); FAIL;
+
+ // __NR_waitpid 7
+ GO(__NR_waitpid, "3s 1m");
+ SY(__NR_waitpid, x0, x0+1, x0); FAIL;
+
+ // __NR_creat 8
+ GO(__NR_creat, "2s 1m");
+ SY(__NR_creat, x0, x0); FAIL;
+
+ // __NR_link 9
+ GO(__NR_link, "2s 2m");
+ SY(__NR_link, x0, x0); FAIL;
+
+ // __NR_unlink 10
+ GO(__NR_unlink, "1s 1m");
+ SY(__NR_unlink, x0); FAIL;
+
+ // __NR_execve 11
+ // Nb: could have 3 memory errors if we pass x0+1 as the 2nd and 3rd
+ // args, except for bug #93174.
+ GO(__NR_execve, "3s 1m");
+ SY(__NR_execve, x0, x0, x0); FAIL;
+
+ // __NR_chdir 12
+ GO(__NR_chdir, "1s 1m");
+ SY(__NR_chdir, x0); FAIL;
+
+ // __NR_time 13
+ GO(__NR_time, "1s 1m");
+ SY(__NR_time, x0+1); FAIL;
+
+ // __NR_mknod 14
+ GO(__NR_mknod, "3s 1m");
+ SY(__NR_mknod, x0, x0, x0); FAIL;
+
+ // __NR_chmod 15
+ GO(__NR_chmod, "2s 1m");
+ SY(__NR_chmod, x0, x0); FAIL;
+
+ // __NR_lchown 16
+ GO(__NR_lchown, "n/a");
+ //SY(__NR_lchown); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_break 17
+ GO(__NR_break, "ni");
+ SY(__NR_break); FAIL;
+
+ // __NR_oldstat 18
+ GO(__NR_oldstat, "n/a");
+ // (obsolete, not handled by Valgrind)
+
+ // __NR_lseek 19
+ GO(__NR_lseek, "3s 0m");
+ SY(__NR_lseek, x0-1, x0, x0); FAILx(EBADF);
+
+ // __NR_getpid 20
+ GO(__NR_getpid, "0s 0m");
+ SY(__NR_getpid); SUCC;
+
+ // __NR_mount 21
+ GO(__NR_mount, "5s 3m");
+ SY(__NR_mount, x0, x0, x0, x0, x0); FAIL;
+
+ // __NR_umount 22
+ GO(__NR_umount, "1s 1m");
+ SY(__NR_umount, x0); FAIL;
+
+ // __NR_setuid 23
+ GO(__NR_setuid, "1s 0m");
+ SY(__NR_setuid, x0); FAIL;
+
+ // __NR_getuid 24
+ GO(__NR_getuid, "0s 0m");
+ SY(__NR_getuid); SUCC;
+
+ // __NR_stime 25
+ GO(__NR_stime, "n/a");
+ //SY(__NR_stime); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_ptrace 26
+ // XXX: memory pointed to be arg3 goes unchecked... otherwise would be 2m
+ GO(__NR_ptrace, "4s 1m");
+ SY(__NR_ptrace, x0+PTRACE_GETREGS, x0, x0, x0); FAIL;
+
+ // __NR_alarm 27
+ GO(__NR_alarm, "1s 0m");
+ SY(__NR_alarm, x0); SUCC;
+
+ // __NR_oldfstat 28
+ GO(__NR_oldfstat, "n/a");
+ // (obsolete, not handled by Valgrind)
+
+ // __NR_pause 29
+ GO(__NR_pause, "ignore");
+ // (hard to test, and no args so not much to be gained -- don't bother)
+
+ // __NR_utime 30
+ GO(__NR_utime, "2s 2m");
+ SY(__NR_utime, x0, x0+1); FAIL;
+
+ // __NR_stty 31
+ GO(__NR_stty, "ni");
+ SY(__NR_stty); FAIL;
+
+ // __NR_gtty 32
+ GO(__NR_gtty, "ni");
+ SY(__NR_gtty); FAIL;
+
+ // __NR_access 33
+ GO(__NR_access, "2s 1m");
+ SY(__NR_access, x0, x0); FAIL;
+
+ // __NR_nice 34
+ GO(__NR_nice, "1s 0m");
+ SY(__NR_nice, x0); SUCC;
+
+ // __NR_ftime 35
+ GO(__NR_ftime, "ni");
+ SY(__NR_ftime); FAIL;
+
+ // __NR_sync 36
+ GO(__NR_sync, "0s 0m");
+ SY(__NR_sync); SUCC;
+
+ // __NR_kill 37
+ GO(__NR_kill, "2s 0m");
+ SY(__NR_kill, x0, x0); SUCC;
+
+ // __NR_rename 38
+ GO(__NR_rename, "2s 2m");
+ SY(__NR_rename, x0, x0); FAIL;
+
+ // __NR_mkdir 39
+ GO(__NR_mkdir, "2s 1m");
+ SY(__NR_mkdir, x0, x0); FAIL;
+
+ // __NR_rmdir 40
+ GO(__NR_rmdir, "1s 1m");
+ SY(__NR_rmdir, x0); FAIL;
+
+ // __NR_dup 41
+ GO(__NR_dup, "1s 0m");
+ SY(__NR_dup, x0-1); FAIL;
+
+ // __NR_pipe 42
+ GO(__NR_pipe, "1s 1m");
+ SY(__NR_pipe, x0); FAIL;
+
+ // __NR_times 43
+ GO(__NR_times, "1s 1m");
+ SY(__NR_times, x0+1); FAIL;
+
+ // __NR_prof 44
+ GO(__NR_prof, "ni");
+ SY(__NR_prof); FAIL;
+
+ // __NR_brk 45
+ GO(__NR_brk, "1s 0m");
+ SY(__NR_brk, x0); SUCC;
+
+ // __NR_setgid 46
+ GO(__NR_setgid, "1s 0m");
+ SY(__NR_setgid, x0); FAIL;
+
+ // __NR_getgid 47
+ GO(__NR_getgid, "0s 0m");
+ SY(__NR_getgid); SUCC;
+
+ // __NR_signal 48
+ GO(__NR_signal, "n/a");
+ //SY(__NR_signal); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_geteuid 49
+ GO(__NR_geteuid, "0s 0m");
+ SY(__NR_geteuid); SUCC;
+
+ // __NR_getegid 50
+ GO(__NR_getegid, "0s 0m");
+ SY(__NR_getegid); SUCC;
+
+ // __NR_acct 51
+ GO(__NR_acct, "1s 1m");
+ SY(__NR_acct, x0); FAIL;
+
+ // __NR_umount2 52
+ GO(__NR_umount2, "2s 1m");
+ SY(__NR_umount2, x0, x0); FAIL;
+
+ // __NR_lock 53
+ GO(__NR_lock, "ni");
+ SY(__NR_lock); FAIL;
+
+ // __NR_ioctl 54
+ #include <asm/ioctls.h>
+ GO(__NR_ioctl, "3s 1m");
+ SY(__NR_ioctl, x0, x0+TCSETS, x0); FAIL;
+
+ // __NR_fcntl 55
+ // As with sys_open(), the 'fd' error is suppressed for the later ones.
+ // For F_GETFD the 3rd arg is ignored
+ GO(__NR_fcntl, "(GETFD) 2s 0m");
+ SY(__NR_fcntl, x0-1, x0+F_GETFD, x0); FAILx(EBADF);
+
+ // For F_DUPFD the 3rd arg is 'arg'. We don't check the 1st two args
+ // because any errors may or may not be commoned up with the ones from
+ // the previous fcntl call.
+ GO(__NR_fcntl, "(DUPFD) 1s 0m");
+ SY(__NR_fcntl, -1, F_DUPFD, x0); FAILx(EBADF);
+
+ // For F_GETLK the 3rd arg is 'lock'. On x86, this fails w/EBADF. But
+ // on amd64 in 32-bit mode it fails w/EFAULT. We don't check the 1st two
+ // args for the reason given above.
+ GO(__NR_fcntl, "(GETLK) 1s 0m");
+ SY(__NR_fcntl, -1, F_GETLK, x0); FAIL; //FAILx(EBADF);
+
+ // __NR_mpx 56
+ GO(__NR_mpx, "ni");
+ SY(__NR_mpx); FAIL;
+
+ // __NR_setpgid 57
+ GO(__NR_setpgid, "2s 0m");
+ SY(__NR_setpgid, x0, x0-1); FAIL;
+
+ // __NR_ulimit 58
+ GO(__NR_ulimit, "ni");
+ SY(__NR_ulimit); FAIL;
+
+ // __NR_oldolduname 59
+ GO(__NR_oldolduname, "n/a");
+ // (obsolete, not handled by Valgrind)
+
+ // __NR_umask 60
+ GO(__NR_umask, "1s 0m");
+ SY(__NR_umask, x0+022); SUCC;
+
+ // __NR_chroot 61
+ GO(__NR_chroot, "1s 1m");
+ SY(__NR_chroot, x0); FAIL;
+
+ // __NR_ustat 62
+ GO(__NR_ustat, "n/a");
+ // (deprecated, not handled by Valgrind)
+
+ // __NR_dup2 63
+ GO(__NR_dup2, "2s 0m");
+ SY(__NR_dup2, x0-1, x0); FAIL;
+
+ // __NR_getppid 64
+ GO(__NR_getppid, "0s 0m");
+ SY(__NR_getppid); SUCC;
+
+ // __NR_getpgrp 65
+ GO(__NR_getpgrp, "0s 0m");
+ SY(__NR_getpgrp); SUCC;
+
+ // __NR_setsid 66
+ GO(__NR_setsid, "0s 0m");
+ SY(__NR_setsid); SUCC_OR_FAIL;
+
+ // __NR_sigaction 67
+ GO(__NR_sigaction, "3s 4m");
+ SY(__NR_sigaction, x0, x0+&px[1], x0+&px[1]); FAIL;
+
+ // __NR_sgetmask 68 sys_sgetmask()
+ GO(__NR_sgetmask, "n/a");
+ //SY(__NR_sgetmask); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_ssetmask 69
+ GO(__NR_ssetmask, "n/a");
+ //SY(__NR_ssetmask); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_setreuid 70
+ GO(__NR_setreuid, "2s 0m");
+ SY(__NR_setreuid, x0, x0); FAIL;
+
+ // __NR_setregid 71
+ GO(__NR_setregid, "2s 0m");
+ SY(__NR_setregid, x0, x0); FAIL;
+
+ // __NR_sigsuspend 72
+ // XXX: how do you use this function?
+ GO(__NR_sigsuspend, "ignore");
+ // (I don't know how to test this...)
+
+ // __NR_sigpending 73
+ GO(__NR_sigpending, "1s 1m");
+ SY(__NR_sigpending, x0); FAIL;
+
+ // __NR_sethostname 74
+ GO(__NR_sethostname, "n/a");
+ //SY(__NR_sethostname); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_setrlimit 75
+ GO(__NR_setrlimit, "2s 1m");
+ SY(__NR_setrlimit, x0, x0); FAIL;
+
+ // __NR_getrlimit 76
+ GO(__NR_getrlimit, "2s 1m");
+ SY(__NR_getrlimit, x0, x0); FAIL;
+
+ // __NR_getrusage 77
+ GO(__NR_getrusage, "2s 1m");
+ SY(__NR_getrusage, x0, x0); FAIL;
+
+ // __NR_gettimeofday 78
+ GO(__NR_gettimeofday, "2s 2m");
+ SY(__NR_gettimeofday, x0, x0+1); FAIL;
+
+ // __NR_settimeofday 79
+ GO(__NR_settimeofday, "2s 2m");
+ SY(__NR_settimeofday, x0, x0+1); FAIL;
+
+ // __NR_getgroups 80
+ GO(__NR_getgroups, "2s 1m");
+ SY(__NR_getgroups, x0+1, x0+1); FAIL;
+
+ // __NR_setgroups 81
+ GO(__NR_setgroups, "2s 1m");
+ SY(__NR_setgroups, x0+1, x0+1); FAIL;
+
+ // __NR_select 82
+ {
+ long args[5] = { x0+8, x0+0xffffffee, x0+1, x0+1, x0+1 };
+ GO(__NR_select, "1s 5m");
+ SY(__NR_select, args+x0); FAIL;
+ }
+
+ // __NR_symlink 83
+ GO(__NR_symlink, "2s 2m");
+ SY(__NR_symlink, x0, x0); FAIL;
+
+ // __NR_oldlstat 84
+ GO(__NR_oldlstat, "n/a");
+ // (obsolete, not handled by Valgrind)
+
+ // __NR_readlink 85
+ GO(__NR_readlink, "3s 2m");
+ SY(__NR_readlink, x0+1, x0+1, x0+1); FAIL;
+
+ // __NR_uselib 86
+ GO(__NR_uselib, "n/a");
+ //SY(__NR_uselib); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_swapon 87
+ GO(__NR_swapon, "n/a");
+ //SY(__NR_swapon); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_reboot 88
+ GO(__NR_reboot, "n/a");
+ //SY(__NR_reboot); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_readdir 89
+ GO(__NR_readdir, "n/a");
+ // (superseded, not handled by Valgrind)
+
+ // __NR_mmap 90
+ {
+ long args[6] = { x0, x0, x0, x0, x0-1, x0 };
+ GO(__NR_mmap, "1s 1m");
+ SY(__NR_mmap, args+x0); FAIL;
+ }
+
+ // __NR_munmap 91
+ GO(__NR_munmap, "2s 0m");
+ SY(__NR_munmap, x0, x0); FAIL;
+
+ // __NR_truncate 92
+ GO(__NR_truncate, "2s 1m");
+ SY(__NR_truncate, x0, x0); FAIL;
+
+ // __NR_ftruncate 93
+ GO(__NR_ftruncate, "2s 0m");
+ SY(__NR_ftruncate, x0, x0); FAIL;
+
+ // __NR_fchmod 94
+ GO(__NR_fchmod, "2s 0m");
+ SY(__NR_fchmod, x0-1, x0); FAIL;
+
+ // __NR_fchown 95
+ GO(__NR_fchown, "3s 0m");
+ SY(__NR_fchown, x0, x0, x0); FAIL;
+
+ // __NR_getpriority 96
+ GO(__NR_getpriority, "2s 0m");
+ SY(__NR_getpriority, x0-1, x0); FAIL;
+
+ // __NR_setpriority 97
+ GO(__NR_setpriority, "3s 0m");
+ SY(__NR_setpriority, x0-1, x0, x0); FAIL;
+
+ // __NR_profil 98
+ GO(__NR_profil, "ni");
+ SY(__NR_profil); FAIL;
+
+ // __NR_statfs 99
+ GO(__NR_statfs, "2s 2m");
+ SY(__NR_statfs, x0, x0); FAIL;
+
+ // __NR_fstatfs 100
+ GO(__NR_fstatfs, "2s 1m");
+ SY(__NR_fstatfs, x0, x0); FAIL;
+
+ // __NR_ioperm 101
+ GO(__NR_ioperm, "3s 0m");
+ SY(__NR_ioperm, x0, x0, x0); FAIL;
+
+ // __NR_socketcall 102
+ GO(__NR_socketcall, "XXX");
+ // (XXX: need to do all sub-cases properly)
+
+ // __NR_syslog 103
+ GO(__NR_syslog, "3s 1m");
+ SY(__NR_syslog, x0+2, x0, x0+1); FAIL;
+
+ // __NR_setitimer 104
+ GO(__NR_setitimer, "3s 2m");
+ SY(__NR_setitimer, x0, x0+1, x0+1); FAIL;
+
+ // __NR_getitimer 105
+ GO(__NR_getitimer, "2s 1m");
+ SY(__NR_getitimer, x0, x0, x0); FAIL;
+
+ // __NR_stat 106
+ GO(__NR_stat, "2s 2m");
+ SY(__NR_stat, x0, x0); FAIL;
+
+ // __NR_lstat 107
+ GO(__NR_lstat, "2s 2m");
+ SY(__NR_lstat, x0, x0); FAIL;
+
+ // __NR_fstat 108
+ GO(__NR_fstat, "2s 1m");
+ SY(__NR_fstat, x0, x0); FAIL;
+
+ // __NR_olduname 109
+ GO(__NR_olduname, "n/a");
+ // (obsolete, not handled by Valgrind)
+
+ // __NR_iopl 110
+ GO(__NR_iopl, "1s 0m");
+ SY(__NR_iopl, x0+100); FAIL;
+
+ // __NR_vhangup 111
+ GO(__NR_vhangup, "0s 0m");
+ SY(__NR_vhangup); SUCC_OR_FAIL; // Will succeed for superuser
+
+ // __NR_idle 112
+ GO(__NR_idle, "ni");
+ SY(__NR_idle); FAIL;
+
+ // __NR_vm86old 113
+ GO(__NR_vm86old, "n/a");
+ // (will probably never be handled by Valgrind)
+
+ // __NR_wait4 114
+ GO(__NR_wait4, "4s 2m");
+ SY(__NR_wait4, x0, x0+1, x0, x0+1); FAIL;
+
+ // __NR_swapoff 115
+ GO(__NR_swapoff, "n/a");
+ //SY(__NR_swapoff); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_sysinfo 116
+ GO(__NR_sysinfo, "1s 1m");
+ SY(__NR_sysinfo, x0); FAIL;
+
+ // __NR_ipc 117
+ // XXX: This is simplistic -- need to do all the sub-cases properly.
+ // XXX: Also, should be 6 scalar errors, except glibc's syscall() doesn't
+ // use the 6th one!
+ GO(__NR_ipc, "5s 0m");
+ SY(__NR_ipc, x0+4, x0, x0, x0, x0, x0); FAIL;
+
+ // __NR_fsync 118
+ GO(__NR_fsync, "1s 0m");
+ SY(__NR_fsync, x0-1); FAIL;
+
+ // __NR_sigreturn 119
+ GO(__NR_sigreturn, "n/a");
+ //SY(__NR_sigreturn); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_clone 120
+#ifndef CLONE_PARENT_SETTID
+#define CLONE_PARENT_SETTID 0x00100000
+#endif
+ // XXX: should really be "4s 2m"? Not sure... (see PRE(sys_clone))
+ GO(__NR_clone, "4s 0m");
+ SY(__NR_clone, x0|CLONE_PARENT_SETTID|SIGCHLD, x0, x0, x0); FAIL;
+ if (0 == res) {
+ SY(__NR_exit, 0); FAIL;
+ }
+
+ // __NR_setdomainname 121
+ GO(__NR_setdomainname, "n/a");
+ //SY(__NR_setdomainname); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_uname 122
+ GO(__NR_uname, "1s 1m");
+ SY(__NR_uname, x0); FAIL;
+
+ // __NR_modify_ldt 123
+ GO(__NR_modify_ldt, "3s 1m");
+ SY(__NR_modify_ldt, x0+1, x0, x0+1); FAILx(EINVAL);
+
+ // __NR_adjtimex 124
+ // XXX: need to do properly, but deref'ing NULL causing Valgrind to crash...
+ GO(__NR_adjtimex, "XXX");
+// SY(__NR_adjtimex, x0); FAIL;
+
+ // __NR_mprotect 125
+ GO(__NR_mprotect, "3s 0m");
+ SY(__NR_mprotect, x0+1, x0, x0); FAILx(EINVAL);
+
+ // __NR_sigprocmask 126
+ GO(__NR_sigprocmask, "3s 2m");
+ SY(__NR_sigprocmask, x0, x0+&px[1], x0+&px[1]); SUCC;
+
+ // __NR_create_module 127
+ GO(__NR_create_module, "ni");
+ SY(__NR_create_module); FAIL;
+
+ // __NR_init_module 128
+ GO(__NR_init_module, "3s 2m");
+ SY(__NR_init_module, x0, x0+1, x0); FAIL;
+
+ // __NR_delete_module 129
+ GO(__NR_delete_module, "n/a");
+ //SY(__NR_delete_module); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_get_kernel_syms 130
+ GO(__NR_get_kernel_syms, "ni");
+ SY(__NR_get_kernel_syms); FAIL;
+
+ // __NR_quotactl 131
+ GO(__NR_quotactl, "4s 1m");
+ SY(__NR_quotactl, x0, x0, x0, x0); FAIL;
+
+ // __NR_getpgid 132
+ GO(__NR_getpgid, "1s 0m");
+ SY(__NR_getpgid, x0-1); FAIL;
+
+ // __NR_fchdir 133
+ GO(__NR_fchdir, "1s 0m");
+ SY(__NR_fchdir, x0-1); FAIL;
+
+ // __NR_bdflush 134
+ GO(__NR_bdflush, "n/a");
+ //SY(__NR_bdflush); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_sysfs 135
+ GO(__NR_sysfs, "n/a");
+ //SY(__NR_sysfs); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_personality 136
+ GO(__NR_personality, "1s 0m");
+ SY(__NR_personality, x0+0xffffffff); SUCC;
+
+ // __NR_afs_syscall 137
+ GO(__NR_afs_syscall, "ni");
+ SY(__NR_afs_syscall); FAIL;
+
+ // __NR_setfsuid 138
+ GO(__NR_setfsuid, "1s 0m");
+ SY(__NR_setfsuid, x0); SUCC; // This syscall has a stupid return value
+
+ // __NR_setfsgid 139
+ GO(__NR_setfsgid, "1s 0m");
+ SY(__NR_setfsgid, x0); SUCC; // This syscall has a stupid return value
+
+ // __NR__llseek 140
+ GO(__NR__llseek, "5s 1m");
+ SY(__NR__llseek, x0, x0, x0, x0, x0); FAIL;
+
+ // __NR_getdents 141
+ GO(__NR_getdents, "3s 1m");
+ SY(__NR_getdents, x0, x0, x0+1); FAIL;
+
+ // __NR__newselect 142
+ GO(__NR__newselect, "5s 4m");
+ SY(__NR__newselect, x0+8, x0+0xffffffff, x0+1, x0+1, x0+1); FAIL;
+
+ // __NR_flock 143
+ GO(__NR_flock, "2s 0m");
+ SY(__NR_flock, x0, x0); FAIL;
+
+ // __NR_msync 144
+ GO(__NR_msync, "3s 1m");
+ SY(__NR_msync, x0, x0+1, x0); FAIL;
+
+ // __NR_readv 145
+ GO(__NR_readv, "3s 1m");
+ SY(__NR_readv, x0, x0, x0+1); FAIL;
+
+ // __NR_writev 146
+ GO(__NR_writev, "3s 1m");
+ SY(__NR_writev, x0, x0, x0+1); FAIL;
+
+ // __NR_getsid 147
+ GO(__NR_getsid, "1s 0m");
+ SY(__NR_getsid, x0-1); FAIL;
+
+ // __NR_fdatasync 148
+ GO(__NR_fdatasync, "1s 0m");
+ SY(__NR_fdatasync, x0-1); FAIL;
+
+ // __NR__sysctl 149
+ GO(__NR__sysctl, "1s 1m");
+ SY(__NR__sysctl, x0); FAIL;
+
+ // __NR_mlock 150
+ GO(__NR_mlock, "2s 0m");
+ SY(__NR_mlock, x0, x0+1); FAIL;
+
+ // __NR_munlock 151
+ GO(__NR_munlock, "2s 0m");
+ SY(__NR_munlock, x0, x0+1); FAIL;
+
+ // __NR_mlockall 152
+ GO(__NR_mlockall, "1s 0m");
+ SY(__NR_mlockall, x0-1); FAIL;
+
+ // __NR_munlockall 153
+ GO(__NR_munlockall, "0s 0m");
+ SY(__NR_munlockall); SUCC_OR_FAILx(EPERM);
+
+ // __NR_sched_setparam 154
+ GO(__NR_sched_setparam, "2s 1m");
+ SY(__NR_sched_setparam, x0, x0); FAIL;
+
+ // __NR_sched_getparam 155
+ GO(__NR_sched_getparam, "2s 1m");
+ SY(__NR_sched_getparam, x0, x0); FAIL;
+
+ // __NR_sched_setscheduler 156
+ GO(__NR_sched_setscheduler, "3s 1m");
+ SY(__NR_sched_setscheduler, x0-1, x0, x0+1); FAIL;
+
+ // __NR_sched_getscheduler 157
+ GO(__NR_sched_getscheduler, "1s 0m");
+ SY(__NR_sched_getscheduler, x0-1); FAIL;
+
+ // __NR_sched_yield 158
+ GO(__NR_sched_yield, "0s 0m");
+ SY(__NR_sched_yield); SUCC;
+
+ // __NR_sched_get_priority_max 159
+ GO(__NR_sched_get_priority_max, "1s 0m");
+ SY(__NR_sched_get_priority_max, x0-1); FAIL;
+
+ // __NR_sched_get_priority_min 160
+ GO(__NR_sched_get_priority_min, "1s 0m");
+ SY(__NR_sched_get_priority_min, x0-1); FAIL;
+
+ // __NR_sched_rr_get_interval 161
+ GO(__NR_sched_rr_get_interval, "n/a");
+ //SY(__NR_sched_rr_get_interval); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_nanosleep 162
+ GO(__NR_nanosleep, "2s 2m");
+ SY(__NR_nanosleep, x0, x0+1); FAIL;
+
+ // __NR_mremap 163
+ GO(__NR_mremap, "5s 0m");
+ SY(__NR_mremap, x0+1, x0, x0, x0+MREMAP_FIXED, x0); FAILx(EINVAL);
+
+ // __NR_setresuid 164
+ GO(__NR_setresuid, "3s 0m");
+ SY(__NR_setresuid, x0, x0, x0); FAIL;
+
+ // __NR_getresuid 165
+ GO(__NR_getresuid, "3s 3m");
+ SY(__NR_getresuid, x0, x0, x0); FAIL;
+
+ // __NR_vm86 166
+ GO(__NR_vm86, "n/a");
+ // (will probably never be handled by Valgrind)
+
+ // __NR_query_module 167
+ GO(__NR_query_module, "ni");
+ SY(__NR_query_module); FAIL;
+
+ // __NR_poll 168
+ GO(__NR_poll, "3s 1m");
+ SY(__NR_poll, x0, x0+1, x0); FAIL;
+
+ // __NR_nfsservctl 169
+ GO(__NR_nfsservctl, "n/a");
+ //SY(__NR_nfsservctl); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_setresgid 170
+ GO(__NR_setresgid, "3s 0m");
+ SY(__NR_setresgid, x0, x0, x0); FAIL;
+
+ // __NR_getresgid 171
+ GO(__NR_getresgid, "3s 3m");
+ SY(__NR_getresgid, x0, x0, x0); FAIL;
+
+ // __NR_prctl 172
+ GO(__NR_prctl, "5s 0m");
+ SY(__NR_prctl, x0, x0, x0, x0, x0); FAIL;
+
+ // __NR_rt_sigreturn 173
+ GO(__NR_rt_sigreturn, "n/a");
+ //SY(__NR_rt_sigreturn); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_rt_sigaction 174
+ GO(__NR_rt_sigaction, "4s 4m");
+ SY(__NR_rt_sigaction, x0, x0+&px[2], x0+&px[2], x0); FAIL;
+
+ // __NR_rt_sigprocmask 175
+ GO(__NR_rt_sigprocmask, "4s 2m");
+ SY(__NR_rt_sigprocmask, x0, x0+1, x0+1, x0); FAIL;
+
+ // __NR_rt_sigpending 176
+ GO(__NR_rt_sigpending, "2s 1m");
+ SY(__NR_rt_sigpending, x0, x0+1); FAIL;
+
+ // __NR_rt_sigtimedwait 177
+ GO(__NR_rt_sigtimedwait, "4s 3m");
+ SY(__NR_rt_sigtimedwait, x0+1, x0+1, x0+1, x0); FAIL;
+
+ // __NR_rt_sigqueueinfo 178
+ GO(__NR_rt_sigqueueinfo, "3s 1m");
+ SY(__NR_rt_sigqueueinfo, x0, x0+1, x0); FAIL;
+
+ // __NR_rt_sigsuspend 179
+ GO(__NR_rt_sigsuspend, "ignore");
+ // (I don't know how to test this...)
+
+ // __NR_pread64 180
+ GO(__NR_pread64, "5s 1m");
+ SY(__NR_pread64, x0, x0, x0+1, x0, x0); FAIL;
+
+ // __NR_pwrite64 181
+ GO(__NR_pwrite64, "5s 1m");
+ SY(__NR_pwrite64, x0, x0, x0+1, x0, x0); FAIL;
+
+ // __NR_chown 182
+ GO(__NR_chown, "3s 1m");
+ SY(__NR_chown, x0, x0, x0); FAIL;
+
+ // __NR_getcwd 183
+ GO(__NR_getcwd, "2s 1m");
+ SY(__NR_getcwd, x0, x0+1); FAIL;
+
+ // __NR_capget 184
+ GO(__NR_capget, "2s 2m");
+ SY(__NR_capget, x0, x0); FAIL;
+
+ // __NR_capset 185
+ GO(__NR_capset, "2s 2m");
+ SY(__NR_capset, x0, x0); FAIL;
+
+ // __NR_sigaltstack 186
+ {
+ struct our_sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+ } ss;
+ ss.ss_sp = NULL;
+ ss.ss_flags = 0;
+ ss.ss_size = 0;
+ VALGRIND_MAKE_MEM_NOACCESS(& ss, sizeof(struct our_sigaltstack));
+ GO(__NR_sigaltstack, "2s 2m");
+ SY(__NR_sigaltstack, x0+&ss, x0+&ss); SUCC;
+ }
+
+ // __NR_sendfile 187
+ GO(__NR_sendfile, "4s 1m");
+ SY(__NR_sendfile, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_getpmsg 188
+ // Could do 5s 4m with more effort, but I can't be bothered for this
+ // crappy non-standard syscall.
+ GO(__NR_getpmsg, "5s 0m");
+ SY(__NR_getpmsg, x0, x0, x0, x0); FAIL;
+
+ // __NR_putpmsg 189
+ // Could do 5s 2m with more effort, but I can't be bothered for this
+ // crappy non-standard syscall.
+ GO(__NR_putpmsg, "5s 0m");
+ SY(__NR_putpmsg, x0, x0, x0, x0, x0); FAIL;
+
+ // __NR_vfork 190
+ GO(__NR_vfork, "other");
+ // (sse scalar_vfork.c)
+
+ // __NR_ugetrlimit 191
+ GO(__NR_ugetrlimit, "2s 1m");
+ SY(__NR_ugetrlimit, x0, x0); FAIL;
+
+ // __NR_mmap2 192
+ GO(__NR_mmap2, "6s 0m");
+ SY(__NR_mmap2, x0, x0, x0, x0, x0-1, x0); FAIL;
+
+ // __NR_truncate64 193
+ GO(__NR_truncate64, "3s 1m");
+ SY(__NR_truncate64, x0, x0, x0); FAIL;
+
+ // __NR_ftruncate64 194
+ GO(__NR_ftruncate64, "3s 0m");
+ SY(__NR_ftruncate64, x0, x0, x0); FAIL;
+
+ // __NR_stat64 195
+ GO(__NR_stat64, "2s 2m");
+ SY(__NR_stat64, x0, x0); FAIL;
+
+ // __NR_lstat64 196
+ GO(__NR_lstat64, "2s 2m");
+ SY(__NR_lstat64, x0, x0); FAIL;
+
+ // __NR_fstat64 197
+ GO(__NR_fstat64, "2s 1m");
+ SY(__NR_fstat64, x0, x0); FAIL;
+
+ // __NR_lchown32 198
+ GO(__NR_lchown32, "3s 1m");
+ SY(__NR_lchown32, x0, x0, x0); FAIL;
+
+ // __NR_getuid32 199
+ GO(__NR_getuid32, "0s 0m");
+ SY(__NR_getuid32); SUCC;
+
+ // __NR_getgid32 200
+ GO(__NR_getgid32, "0s 0m");
+ SY(__NR_getgid32); SUCC;
+
+ // __NR_geteuid32 201
+ GO(__NR_geteuid32, "0s 0m");
+ SY(__NR_geteuid32); SUCC;
+
+ // __NR_getegid32 202
+ GO(__NR_getegid32, "0s 0m");
+ SY(__NR_getegid32); SUCC;
+
+ // __NR_setreuid32 203
+ GO(__NR_setreuid32, "2s 0m");
+ SY(__NR_setreuid32, x0, x0); FAIL;
+
+ // __NR_setregid32 204
+ GO(__NR_setregid32, "2s 0m");
+ SY(__NR_setregid32, x0, x0); FAIL;
+
+ // __NR_getgroups32 205
+ GO(__NR_getgroups32, "2s 1m");
+ SY(__NR_getgroups32, x0+1, x0+1); FAIL;
+
+ // __NR_setgroups32 206
+ GO(__NR_setgroups32, "2s 1m");
+ SY(__NR_setgroups32, x0+1, x0+1); FAIL;
+
+ // __NR_fchown32 207
+ GO(__NR_fchown32, "3s 0m");
+ SY(__NR_fchown32, x0, x0, x0); FAIL;
+
+ // __NR_setresuid32 208
+ GO(__NR_setresuid32, "3s 0m");
+ SY(__NR_setresuid32, x0, x0, x0); FAIL;
+
+ // __NR_getresuid32 209
+ GO(__NR_getresuid32, "3s 3m");
+ SY(__NR_getresuid32, x0, x0, x0); FAIL;
+
+ // __NR_setresgid32 210
+ GO(__NR_setresgid32, "3s 0m");
+ SY(__NR_setresgid32, x0, x0, x0); FAIL;
+
+ // __NR_getresgid32 211
+ GO(__NR_getresgid32, "3s 3m");
+ SY(__NR_getresgid32, x0, x0, x0); FAIL;
+
+ // __NR_chown32 212
+ GO(__NR_chown32, "3s 1m");
+ SY(__NR_chown32, x0, x0, x0); FAIL;
+
+ // __NR_setuid32 213
+ GO(__NR_setuid32, "1s 0m");
+ SY(__NR_setuid32, x0); FAIL;
+
+ // __NR_setgid32 214
+ GO(__NR_setgid32, "1s 0m");
+ SY(__NR_setgid32, x0); FAIL;
+
+ // __NR_setfsuid32 215
+ GO(__NR_setfsuid32, "1s 0m");
+ SY(__NR_setfsuid32, x0); SUCC; // This syscall has a stupid return value
+
+ // __NR_setfsgid32 216
+ GO(__NR_setfsgid32, "1s 0m");
+ SY(__NR_setfsgid32, x0); SUCC; // This syscall has a stupid return value
+
+ // __NR_pivot_root 217
+ GO(__NR_pivot_root, "n/a");
+ //SY(__NR_pivot_root); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_mincore 218
+ GO(__NR_mincore, "3s 1m");
+ SY(__NR_mincore, x0, x0+40960, x0); FAIL;
+
+ // __NR_madvise 219
+ GO(__NR_madvise, "3s 0m");
+ SY(__NR_madvise, x0, x0+1, x0); FAILx(ENOMEM);
+
+ // __NR_getdents64 220
+ GO(__NR_getdents64, "3s 1m");
+ SY(__NR_getdents64, x0, x0, x0+1); FAIL;
+
+ // __NR_fcntl64 221
+ // As with sys_open(), we don't trigger errors for the 1st two args for
+ // the later ones.
+ // For F_GETFD the 3rd arg is ignored.
+ GO(__NR_fcntl64, "(GETFD) 2s 0m");
+ SY(__NR_fcntl64, x0-1, x0+F_GETFD, x0); FAILx(EBADF);
+
+ // For F_DUPFD the 3rd arg is 'arg'
+ GO(__NR_fcntl64, "(DUPFD) 1s 0m");
+ SY(__NR_fcntl64, -1, F_DUPFD, x0); FAILx(EBADF);
+
+ // For F_GETLK the 3rd arg is 'lock'.
+ // On x86, this fails w/EBADF. But on amd64 in 32-bit mode it fails
+ // w/EFAULT.
+ GO(__NR_fcntl64, "(GETLK) 1s 0m");
+ SY(__NR_fcntl64, -1, +F_GETLK, x0); FAIL; //FAILx(EBADF);
+
+ // 222
+ GO(222, "ni");
+ SY(222); FAIL;
+
+ // 223
+ GO(223, "ni");
+ SY(223); FAIL;
+
+ // __NR_gettid 224
+ GO(__NR_gettid, "n/a");
+ //SY(__NR_gettid); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_readahead 225
+ GO(__NR_readahead, "n/a");
+ //SY(__NR_readahead); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_setxattr 226
+ GO(__NR_setxattr, "5s 3m");
+ SY(__NR_setxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_lsetxattr 227
+ GO(__NR_lsetxattr, "5s 3m");
+ SY(__NR_lsetxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_fsetxattr 228
+ GO(__NR_fsetxattr, "5s 2m");
+ SY(__NR_fsetxattr, x0, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_getxattr 229
+ GO(__NR_getxattr, "4s 3m");
+ SY(__NR_getxattr, x0, x0, x0, x0+1); FAIL;
+
+ // __NR_lgetxattr 230
+ GO(__NR_lgetxattr, "4s 3m");
+ SY(__NR_lgetxattr, x0, x0, x0, x0+1); FAIL;
+
+ // __NR_fgetxattr 231
+ GO(__NR_fgetxattr, "4s 2m");
+ SY(__NR_fgetxattr, x0, x0, x0, x0+1); FAIL;
+
+ // __NR_listxattr 232
+ GO(__NR_listxattr, "3s 2m");
+ SY(__NR_listxattr, x0, x0, x0+1); FAIL;
+
+ // __NR_llistxattr 233
+ GO(__NR_llistxattr, "3s 2m");
+ SY(__NR_llistxattr, x0, x0, x0+1); FAIL;
+
+ // __NR_flistxattr 234
+ GO(__NR_flistxattr, "3s 1m");
+ SY(__NR_flistxattr, x0-1, x0, x0+1); FAIL; /* kernel returns EBADF, but both seem correct */
+
+ // __NR_removexattr 235
+ GO(__NR_removexattr, "2s 2m");
+ SY(__NR_removexattr, x0, x0); FAIL;
+
+ // __NR_lremovexattr 236
+ GO(__NR_lremovexattr, "2s 2m");
+ SY(__NR_lremovexattr, x0, x0); FAIL;
+
+ // __NR_fremovexattr 237
+ GO(__NR_fremovexattr, "2s 1m");
+ SY(__NR_fremovexattr, x0, x0); FAIL;
+
+ // __NR_tkill 238
+ GO(__NR_tkill, "n/a");
+ //SY(__NR_tkill); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_sendfile64 239
+ GO(__NR_sendfile64, "4s 1m");
+ SY(__NR_sendfile64, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_futex 240
+ #ifndef FUTEX_WAIT
+ #define FUTEX_WAIT 0
+ #endif
+ // XXX: again, glibc not doing 6th arg means we have only 5s errors
+ GO(__NR_futex, "5s 2m");
+ SY(__NR_futex, x0+FUTEX_WAIT, x0, x0, x0+1, x0, x0); FAIL;
+
+ // __NR_sched_setaffinity 241
+ GO(__NR_sched_setaffinity, "3s 1m");
+ SY(__NR_sched_setaffinity, x0, x0+1, x0); FAIL;
+
+ // __NR_sched_getaffinity 242
+ GO(__NR_sched_getaffinity, "3s 1m");
+ SY(__NR_sched_getaffinity, x0, x0+1, x0); FAIL;
+
+ // __NR_set_thread_area 243
+ GO(__NR_set_thread_area, "1s 1m");
+ SY(__NR_set_thread_area, x0); FAILx(EFAULT);
+
+ // __NR_get_thread_area 244
+ GO(__NR_get_thread_area, "1s 1m");
+ SY(__NR_get_thread_area, x0); FAILx(EFAULT);
+
+ // __NR_io_setup 245
+ GO(__NR_io_setup, "2s 1m");
+ SY(__NR_io_setup, x0, x0); FAIL;
+
+ // __NR_io_destroy 246
+ {
+ // jump through hoops to prevent the PRE(io_destroy) wrapper crashing.
+ struct fake_aio_ring {
+ unsigned id; /* kernel internal index number */
+ unsigned nr; /* number of io_events */
+ // There are more fields in the real aio_ring, but the 'nr' field is
+ // the only one used by the PRE() wrapper.
+ } ring = { 0, 0 };
+ struct fake_aio_ring* ringptr = ˚
+ GO(__NR_io_destroy, "1s 0m");
+ SY(__NR_io_destroy, x0+&ringptr); FAIL;
+ }
+
+ // __NR_io_getevents 247
+ GO(__NR_io_getevents, "5s 2m");
+ SY(__NR_io_getevents, x0, x0, x0+1, x0, x0+1); FAIL;
+
+ // __NR_io_submit 248
+ GO(__NR_io_submit, "3s 1m");
+ SY(__NR_io_submit, x0, x0+1, x0); FAIL;
+
+ // __NR_io_cancel 249
+ GO(__NR_io_cancel, "3s 2m");
+ SY(__NR_io_cancel, x0, x0, x0); FAIL;
+
+ // __NR_fadvise64 250
+ GO(__NR_fadvise64, "n/a");
+ //SY(__NR_fadvise64); // (Not yet handled by Valgrind) FAIL;
+
+ // 251
+ GO(251, "ni");
+ SY(251); FAIL;
+
+ // __NR_exit_group 252
+ GO(__NR_exit_group, "other");
+ // (see scalar_exit_group.c)
+
+ // __NR_lookup_dcookie 253
+ GO(__NR_lookup_dcookie, "4s 1m");
+ SY(__NR_lookup_dcookie, x0, x0, x0, x0+1); FAIL;
+
+ // __NR_epoll_create 254
+ GO(__NR_epoll_create, "1s 0m");
+ SY(__NR_epoll_create, x0); SUCC_OR_FAIL;
+
+ // __NR_epoll_ctl 255
+ GO(__NR_epoll_ctl, "4s 1m");
+ SY(__NR_epoll_ctl, x0, x0, x0, x0); FAIL;
+
+ // __NR_epoll_wait 256
+ GO(__NR_epoll_wait, "4s 1m");
+ SY(__NR_epoll_wait, x0, x0, x0+1, x0); FAIL;
+
+ // __NR_remap_file_pages 257
+ GO(__NR_remap_file_pages, "n/a");
+ //SY(__NR_remap_file_pages); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_set_tid_address 258
+ GO(__NR_set_tid_address, "1s 0m");
+ SY(__NR_set_tid_address, x0); SUCC_OR_FAILx(ENOSYS);
+
+ // __NR_timer_create 259
+ GO(__NR_timer_create, "3s 2m");
+ SY(__NR_timer_create, x0, x0+1, x0); FAIL;
+
+ // __NR_timer_settime (__NR_timer_create+1)
+ GO(__NR_timer_settime, "4s 2m");
+ SY(__NR_timer_settime, x0, x0, x0, x0+1); FAIL;
+
+ // __NR_timer_gettime (__NR_timer_create+2)
+ GO(__NR_timer_gettime, "2s 1m");
+ SY(__NR_timer_gettime, x0, x0); FAIL;
+
+ // __NR_timer_getoverrun (__NR_timer_create+3)
+ GO(__NR_timer_getoverrun, "1s 0m");
+ SY(__NR_timer_getoverrun, x0); FAIL;
+
+ // __NR_timer_delete (__NR_timer_create+4)
+ GO(__NR_timer_delete, "1s 0m");
+ SY(__NR_timer_delete, x0); FAIL;
+
+ // __NR_clock_settime (__NR_timer_create+5)
+ GO(__NR_clock_settime, "2s 1m");
+ SY(__NR_clock_settime, x0, x0); FAIL; FAIL;
+
+ // __NR_clock_gettime (__NR_timer_create+6)
+ GO(__NR_clock_gettime, "2s 1m");
+ SY(__NR_clock_gettime, x0, x0); FAIL;
+
+ // __NR_clock_getres (__NR_timer_create+7)
+ GO(__NR_clock_getres, "2s 1m");
+ SY(__NR_clock_getres, x0+1, x0+1); FAIL; FAIL;
+
+ // __NR_clock_nanosleep (__NR_timer_create+8)
+ GO(__NR_clock_nanosleep, "n/a");
+ //SY(__NR_clock_nanosleep); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_statfs64 268
+ GO(__NR_statfs64, "3s 2m");
+ SY(__NR_statfs64, x0, x0+1, x0); FAIL;
+
+ // __NR_fstatfs64 269
+ GO(__NR_fstatfs64, "3s 1m");
+ SY(__NR_fstatfs64, x0, x0+1, x0); FAIL;
+
+ // __NR_tgkill 270
+ GO(__NR_tgkill, "n/a");
+ //SY(__NR_tgkill); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_utimes 271
+ GO(__NR_utimes, "2s 2m");
+ SY(__NR_utimes, x0, x0+1); FAIL;
+
+ // __NR_fadvise64_64 272
+ GO(__NR_fadvise64_64, "n/a");
+ //SY(__NR_fadvise64_64); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_vserver 273
+ GO(__NR_vserver, "ni");
+ SY(__NR_vserver); FAIL;
+
+ // __NR_mbind 274
+ GO(__NR_mbind, "n/a");
+ //SY(__NR_mbind); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_get_mempolicy 275
+ GO(__NR_get_mempolicy, "n/a");
+ //SY(__NR_get_mempolicy); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_set_mempolicy 276
+ GO(__NR_set_mempolicy, "n/a");
+ //SY(__NR_set_mempolicy); // (Not yet handled by Valgrind) FAIL;
+
+ // __NR_mq_open 277
+ GO(__NR_mq_open, "4s 3m");
+ SY(__NR_mq_open, x0, x0+O_CREAT, x0, x0+1); FAIL;
+
+ // __NR_mq_unlink (__NR_mq_open+1)
+ GO(__NR_mq_unlink, "1s 1m");
+ SY(__NR_mq_unlink, x0); FAIL;
+
+ // __NR_mq_timedsend (__NR_mq_open+2)
+ GO(__NR_mq_timedsend, "5s 2m");
+ SY(__NR_mq_timedsend, x0, x0, x0+1, x0, x0+1); FAIL;
+
+ // __NR_mq_timedreceive (__NR_mq_open+3)
+ GO(__NR_mq_timedreceive, "5s 3m");
+ SY(__NR_mq_timedreceive, x0, x0, x0+1, x0+1, x0+1); FAIL;
+
+ // __NR_mq_notify (__NR_mq_open+4)
+ GO(__NR_mq_notify, "2s 1m");
+ SY(__NR_mq_notify, x0, x0+1); FAIL;
+
+ // __NR_mq_getsetattr (__NR_mq_open+5)
+ GO(__NR_mq_getsetattr, "3s 2m");
+ SY(__NR_mq_getsetattr, x0, x0+1, x0+1); FAIL;
+
+ // __NR_sys_kexec_load 283
+ GO(__NR_sys_kexec_load, "ni");
+ SY(__NR_sys_kexec_load); FAIL;
+#endif
+
+ // no such syscall...
+ GO(9999, "1e");
+ SY(9999); FAIL;
+
+ // __NR_exit 1
+ GO(__NR_exit, "1s 0m");
+ SY(__NR_exit, x0); FAIL;
+
+ assert(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar.h b/memcheck/tests/darwin/scalar.h
new file mode 100644
index 0000000..8bfd2e1
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.h
@@ -0,0 +1,57 @@
+#include "vki/vki-scnums-darwin.h"
+#include "pub_tool_vkiscnums.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+// Since we use vki_unistd.h, we can't include <unistd.h>. So we have to
+// declare this ourselves.
+extern int syscall (int __sysno, ...);
+
+// Thorough syscall scalar arg checking. Also serves as thorough checking
+// for (very) basic syscall use. Generally not trying to do anything
+// meaningful with the syscalls.
+
+#define GO(__NR_xxx, s) \
+ fprintf(stderr, "-----------------------------------------------------\n" \
+ "%3d:%20s %s\n" \
+ "-----------------------------------------------------\n", \
+ VG_DARWIN_SYSNO_PRINT(__NR_xxx), #__NR_xxx, s);
+
+#define SY(__NR_xxx, args...) res = syscall(__NR_xxx, ##args);
+
+#define FAIL assert(-1 == res);
+#define SUCC assert(-1 != res);
+#define SUCC_OR_FAIL /* no test */
+
+#define FAILx(E) \
+ do { \
+ int myerrno = errno; \
+ if (-1 == res) { \
+ if (E == myerrno) { \
+ /* as expected */ \
+ } else { \
+ fprintf(stderr, "Expected error %s (%d), got %d\n", #E, E, myerrno); \
+ exit(1); \
+ } \
+ } else { \
+ fprintf(stderr, "Expected error %s (%d), got success\n", #E, E); \
+ exit(1); \
+ } \
+ } while (0);
+
+#define SUCC_OR_FAILx(E) \
+ do { \
+ int myerrno = errno; \
+ if (-1 == res) { \
+ if (E == myerrno) { \
+ /* as expected */ \
+ } else { \
+ fprintf(stderr, "Expected error %s (%d), got %d\n", #E, E, myerrno); \
+ exit(1); \
+ } \
+ } \
+ } while (0);
diff --git a/memcheck/tests/darwin/scalar.stderr.exp b/memcheck/tests/darwin/scalar.stderr.exp
new file mode 100644
index 0000000..7b383cc
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.stderr.exp
@@ -0,0 +1,208 @@
+-----------------------------------------------------
+ 1: __NR_exit below
+-----------------------------------------------------
+-----------------------------------------------------
+ 2: __NR_fork other
+-----------------------------------------------------
+-----------------------------------------------------
+ 3: __NR_read 1+3s 1m
+-----------------------------------------------------
+Syscall param (syscallno) contains uninitialised byte(s)
+ ...
+
+Syscall param read(fd) contains uninitialised byte(s)
+ ...
+
+Syscall param read(buf) contains uninitialised byte(s)
+ ...
+
+Syscall param read(count) contains uninitialised byte(s)
+ ...
+
+Syscall param read(buf) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+ 4: __NR_write 3s 1m
+-----------------------------------------------------
+
+Syscall param write(fd) contains uninitialised byte(s)
+ ...
+
+Syscall param write(buf) contains uninitialised byte(s)
+ ...
+
+Syscall param write(count) contains uninitialised byte(s)
+ ...
+
+Syscall param write(buf) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+105: __NR_setsockopt 5s 1m
+-----------------------------------------------------
+
+Syscall param setsockopt(s) contains uninitialised byte(s)
+ ...
+
+Syscall param setsockopt(level) contains uninitialised byte(s)
+ ...
+
+Syscall param setsockopt(optname) contains uninitialised byte(s)
+ ...
+
+Syscall param setsockopt(optval) contains uninitialised byte(s)
+ ...
+
+Syscall param setsockopt(optlen) contains uninitialised byte(s)
+ ...
+
+Syscall param socketcall.setsockopt(optval) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+118: __NR_getsockopt 5s 1m
+-----------------------------------------------------
+
+Syscall param getsockopt(s) contains uninitialised byte(s)
+ ...
+
+Syscall param getsockopt(level) contains uninitialised byte(s)
+ ...
+
+Syscall param getsockopt(optname) contains uninitialised byte(s)
+ ...
+
+Syscall param getsockopt(optval) contains uninitialised byte(s)
+ ...
+
+Syscall param getsockopt(optlen) contains uninitialised byte(s)
+ ...
+
+Syscall param socketcall.getsockopt(optlen) points to unaddressable byte(s)
+ ...
+ Address 0x........ is 0 bytes after a block of size 4 alloc'd
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (scalar.c:13)
+-----------------------------------------------------
+169: __NR_csops 4s 1m
+-----------------------------------------------------
+
+Syscall param csops(pid) contains uninitialised byte(s)
+ ...
+
+Syscall param csops(ops) contains uninitialised byte(s)
+ ...
+
+Syscall param csops(useraddr) contains uninitialised byte(s)
+ ...
+
+Syscall param csops(usersize) contains uninitialised byte(s)
+ ...
+
+Syscall param csops(addr) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+265: __NR_shmget 3s 0m
+-----------------------------------------------------
+
+Syscall param shmget(key) contains uninitialised byte(s)
+ ...
+
+Syscall param shmget(size) contains uninitialised byte(s)
+ ...
+
+Syscall param shmget(shmflg) contains uninitialised byte(s)
+ ...
+-----------------------------------------------------
+268: __NR_sem_open 2s 1m
+-----------------------------------------------------
+
+Syscall param sem_open(name) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_open(oflag) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_open(name) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+268: __NR_sem_open (4-args) 2s 0m
+-----------------------------------------------------
+
+Syscall param sem_open(mode) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_open(value) contains uninitialised byte(s)
+ ...
+-----------------------------------------------------
+269: __NR_sem_close 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_close(sem) contains uninitialised byte(s)
+ ...
+-----------------------------------------------------
+270: __NR_sem_unlink 1s 1m
+-----------------------------------------------------
+
+Syscall param sem_unlink(name) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_unlink(name) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+273: __NR_sem_post 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_post(sem) contains uninitialised byte(s)
+ ...
+-----------------------------------------------------
+275: __NR_sem_init 3s 1m
+-----------------------------------------------------
+
+Syscall param sem_init(sem) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_init(pshared) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_init(value) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_init(sem) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+276: __NR_sem_destroy 1s 1m
+-----------------------------------------------------
+
+Syscall param sem_destroy(sem) contains uninitialised byte(s)
+ ...
+
+Syscall param sem_destroy(sem) points to unaddressable byte(s)
+ ...
+ Address 0x........ is not stack'd, malloc'd or (recently) free'd
+-----------------------------------------------------
+420:__NR_sem_wait_nocancel 1s 0m
+-----------------------------------------------------
+
+Syscall param sem_wait_nocancel(sem) contains uninitialised byte(s)
+ ...
+-----------------------------------------------------
+9999: 9999 1e
+-----------------------------------------------------
+WARNING: unhandled syscall: 33564431
+ a.k.a.: 9999
+You may be able to write your own handler.
+Read the file README_MISSING_SYSCALL_OR_IOCTL.
+Nevertheless we consider this a bug. Please report
+it at http://valgrind.org/support/bug_reports.html.
+-----------------------------------------------------
+ 1: __NR_exit 1s 0m
+-----------------------------------------------------
+
+Syscall param exit(status) contains uninitialised byte(s)
+ ...
diff --git a/memcheck/tests/darwin/scalar.vgtest b/memcheck/tests/darwin/scalar.vgtest
new file mode 100644
index 0000000..897d9e7
--- /dev/null
+++ b/memcheck/tests/darwin/scalar.vgtest
@@ -0,0 +1,3 @@
+prog: scalar
+vgopts: -q --error-limit=no
+args: < scalar.c
diff --git a/memcheck/tests/darwin/scalar_fork.c b/memcheck/tests/darwin/scalar_fork.c
new file mode 100644
index 0000000..805ade8
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.c
@@ -0,0 +1,15 @@
+#include "scalar.h"
+
+int main(void)
+{
+ int res;
+
+ // All __NR_xxx numbers are taken from x86
+
+ // __NR_fork 2 --> arch/sys_fork()
+ GO(__NR_fork, "0e");
+ SY(__NR_fork);
+
+ return(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar_fork.stderr.exp b/memcheck/tests/darwin/scalar_fork.stderr.exp
new file mode 100644
index 0000000..e898498
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.stderr.exp
@@ -0,0 +1,3 @@
+-----------------------------------------------------
+ 2: __NR_fork 0e
+-----------------------------------------------------
diff --git a/memcheck/tests/darwin/scalar_fork.vgtest b/memcheck/tests/darwin/scalar_fork.vgtest
new file mode 100644
index 0000000..e38fdf6
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_fork.vgtest
@@ -0,0 +1,2 @@
+prog: scalar_fork
+vgopts: -q
diff --git a/memcheck/tests/darwin/scalar_vfork.c b/memcheck/tests/darwin/scalar_vfork.c
new file mode 100644
index 0000000..5f9cea8
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.c
@@ -0,0 +1,13 @@
+#include "scalar.h"
+
+int main(void)
+{
+ int res;
+
+ // __NR_vfork 66 --> __NR_fork [we can't use sys_vfork()]
+ GO(__NR_vfork, "0e");
+ SY(__NR_vfork);
+
+ return(0);
+}
+
diff --git a/memcheck/tests/darwin/scalar_vfork.stderr.exp b/memcheck/tests/darwin/scalar_vfork.stderr.exp
new file mode 100644
index 0000000..32644bd
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.stderr.exp
@@ -0,0 +1,3 @@
+-----------------------------------------------------
+ 66: __NR_vfork 0e
+-----------------------------------------------------
diff --git a/memcheck/tests/darwin/scalar_vfork.vgtest b/memcheck/tests/darwin/scalar_vfork.vgtest
new file mode 100644
index 0000000..3ddad70
--- /dev/null
+++ b/memcheck/tests/darwin/scalar_vfork.vgtest
@@ -0,0 +1,2 @@
+prog: scalar_vfork
+vgopts: -q
diff --git a/memcheck/tests/linux/Makefile.am b/memcheck/tests/linux/Makefile.am
index 81a2c9b..664ee63 100644
--- a/memcheck/tests/linux/Makefile.am
+++ b/memcheck/tests/linux/Makefile.am
@@ -22,3 +22,4 @@
stack_switch_LDADD = -lpthread
timerfd_syscall_LDADD = -lrt
+
diff --git a/memcheck/tests/malloc_usable.c b/memcheck/tests/malloc_usable.c
index 4e2d2a0..ab57663 100644
--- a/memcheck/tests/malloc_usable.c
+++ b/memcheck/tests/malloc_usable.c
@@ -5,7 +5,7 @@
int main(void)
{
-# if !defined(VGO_aix5)
+# if !defined(VGO_aix5) && !defined(VGO_darwin)
// Because Memcheck marks any slop as inaccessible, it doesn't round up
// sizes for malloc_usable_size().
int* x = malloc(99);
diff --git a/memcheck/tests/memalign2.c b/memcheck/tests/memalign2.c
index e163bf4..a3aacfe 100644
--- a/memcheck/tests/memalign2.c
+++ b/memcheck/tests/memalign2.c
@@ -22,6 +22,9 @@
# if defined(VGO_aix5)
// AIX 5.2 has neither memalign() nor posix_memalign(); do nothing.
+# elif defined(VGO_darwin)
+ // Likewise for Mac OS X.
+
# else
// Nb: assuming VG_MIN_MALLOC_SZB is 8 or more...
int* p;
diff --git a/memcheck/tests/origin1-yes.c b/memcheck/tests/origin1-yes.c
index acfd8ab..3ebe6f0 100644
--- a/memcheck/tests/origin1-yes.c
+++ b/memcheck/tests/origin1-yes.c
@@ -86,12 +86,21 @@
}
// Heap segment (brk), uninitialised
+ // Nb: on Darwin, sbrk() is implemented via vm_allocate() which always
+ // zeroes its allocated memory. So we use a separate .exp file for Darwin,
+ // but we add an extra printf on Darwin only so that it cannot be
+ // successfully matched on non-Darwin platforms.
+#if defined(VGO_darwin)
+ fprintf(stderr, "\nUndef 7 of 8 (brk)\n");
+ fprintf(stderr, "\n(no complaint; sbrk initialises memory on Darwin)\n");
+#else
{
int* ptr_to_new_brk_limit = sbrk(4096);
int undef_brk_int = *ptr_to_new_brk_limit;
fprintf(stderr, "\nUndef 7 of 8 (brk)\n");
x += (undef_brk_int == 0x12345678 ? 15 : 26);
}
+#endif
// User block, marked as undefined
{
diff --git a/memcheck/tests/origin1-yes.stderr.exp b/memcheck/tests/origin1-yes.stderr.exp
index 418dcd0..e2af1ab 100644
--- a/memcheck/tests/origin1-yes.stderr.exp
+++ b/memcheck/tests/origin1-yes.stderr.exp
@@ -45,18 +45,18 @@
Undef 7 of 8 (brk)
Conditional jump or move depends on uninitialised value(s)
- at 0x........: main (origin1-yes.c:93)
+ at 0x........: main (origin1-yes.c:101)
Uninitialised value was created
at 0x........: brk (in /...libc...)
by 0x........: sbrk (in /...libc...)
- by 0x........: main (origin1-yes.c:90)
+ by 0x........: main (origin1-yes.c:98)
Undef 8 of 8 (MAKE_MEM_UNDEFINED)
Conditional jump or move depends on uninitialised value(s)
- at 0x........: main (origin1-yes.c:101)
+ at 0x........: main (origin1-yes.c:110)
Uninitialised value was created by a client request
- at 0x........: main (origin1-yes.c:99)
+ at 0x........: main (origin1-yes.c:108)
Def 1 of 3
diff --git a/memcheck/tests/origin1-yes.stderr.exp-darwin b/memcheck/tests/origin1-yes.stderr.exp-darwin
new file mode 100644
index 0000000..add1a37
--- /dev/null
+++ b/memcheck/tests/origin1-yes.stderr.exp-darwin
@@ -0,0 +1,60 @@
+
+Undef 1 of 8 (stack, 32 bit)
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:37)
+ Uninitialised value was created by a stack allocation
+ at 0x........: main (origin1-yes.c:23)
+
+Undef 2 of 8 (stack, 32 bit)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:49)
+ Uninitialised value was created by a stack allocation
+ at 0x........: main (origin1-yes.c:23)
+
+Undef 3 of 8 (stack, 64 bit)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:56)
+ Uninitialised value was created by a stack allocation
+ at 0x........: main (origin1-yes.c:23)
+
+Undef 4 of 8 (mallocd, 32-bit)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:64)
+ Uninitialised value was created by a heap allocation
+ at 0x........: malloc (vg_replace_malloc.c:...)
+ by 0x........: main (origin1-yes.c:61)
+
+Undef 5 of 8 (realloc)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:76)
+ Uninitialised value was created by a heap allocation
+ at 0x........: realloc (vg_replace_malloc.c:...)
+ by 0x........: main (origin1-yes.c:71)
+
+Undef 6 of 8 (MALLOCLIKE_BLOCK)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:85)
+ Uninitialised value was created by a heap allocation
+ at 0x........: main (origin1-yes.c:82)
+
+Undef 7 of 8 (brk)
+
+(no complaint; sbrk initialises memory on Darwin)
+
+Undef 8 of 8 (MAKE_MEM_UNDEFINED)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: main (origin1-yes.c:110)
+ Uninitialised value was created by a client request
+ at 0x........: main (origin1-yes.c:108)
+
+Def 1 of 3
+
+Def 2 of 3
+
+Def 3 of 3
diff --git a/memcheck/tests/sigkill.stderr.exp-darwin b/memcheck/tests/sigkill.stderr.exp-darwin
new file mode 100644
index 0000000..0e04bd8
--- /dev/null
+++ b/memcheck/tests/sigkill.stderr.exp-darwin
@@ -0,0 +1,192 @@
+
+setting signal 1: Success
+getting signal 1: Success
+
+setting signal 2: Success
+getting signal 2: Success
+
+setting signal 3: Success
+getting signal 3: Success
+
+setting signal 4: Success
+getting signal 4: Success
+
+setting signal 5: Success
+getting signal 5: Success
+
+setting signal 6: Success
+getting signal 6: Success
+
+setting signal 7: Success
+getting signal 7: Success
+
+setting signal 8: Success
+getting signal 8: Success
+
+setting signal 9: Invalid argument
+getting signal 9: Invalid argument
+
+setting signal 10: Success
+getting signal 10: Success
+
+setting signal 11: Success
+getting signal 11: Success
+
+setting signal 12: Success
+getting signal 12: Success
+
+setting signal 13: Success
+getting signal 13: Success
+
+setting signal 14: Success
+getting signal 14: Success
+
+setting signal 15: Success
+getting signal 15: Success
+
+setting signal 16: Success
+getting signal 16: Success
+
+setting signal 17: Invalid argument
+getting signal 17: Invalid argument
+
+setting signal 18: Success
+getting signal 18: Success
+
+setting signal 19: Success
+getting signal 19: Success
+
+setting signal 20: Success
+getting signal 20: Success
+
+setting signal 21: Success
+getting signal 21: Success
+
+setting signal 22: Success
+getting signal 22: Success
+
+setting signal 23: Success
+getting signal 23: Success
+
+setting signal 24: Success
+getting signal 24: Success
+
+setting signal 25: Success
+getting signal 25: Success
+
+setting signal 26: Success
+getting signal 26: Success
+
+setting signal 27: Success
+getting signal 27: Success
+
+setting signal 28: Success
+getting signal 28: Success
+
+setting signal 29: Success
+getting signal 29: Success
+
+setting signal 30: Success
+getting signal 30: Success
+
+setting signal 31: Warning: ignored attempt to set SIGUSR2 handler in sigaction();
+ the SIGUSR2 signal is used internally by Valgrind
+Invalid argument
+getting signal 31: Success
+
+setting signal 34: Invalid argument
+getting signal 34: Invalid argument
+
+setting signal 35: Invalid argument
+getting signal 35: Invalid argument
+
+setting signal 36: Invalid argument
+getting signal 36: Invalid argument
+
+setting signal 37: Invalid argument
+getting signal 37: Invalid argument
+
+setting signal 38: Invalid argument
+getting signal 38: Invalid argument
+
+setting signal 39: Invalid argument
+getting signal 39: Invalid argument
+
+setting signal 40: Invalid argument
+getting signal 40: Invalid argument
+
+setting signal 41: Invalid argument
+getting signal 41: Invalid argument
+
+setting signal 42: Invalid argument
+getting signal 42: Invalid argument
+
+setting signal 43: Invalid argument
+getting signal 43: Invalid argument
+
+setting signal 44: Invalid argument
+getting signal 44: Invalid argument
+
+setting signal 45: Invalid argument
+getting signal 45: Invalid argument
+
+setting signal 46: Invalid argument
+getting signal 46: Invalid argument
+
+setting signal 47: Invalid argument
+getting signal 47: Invalid argument
+
+setting signal 48: Invalid argument
+getting signal 48: Invalid argument
+
+setting signal 49: Invalid argument
+getting signal 49: Invalid argument
+
+setting signal 50: Invalid argument
+getting signal 50: Invalid argument
+
+setting signal 51: Invalid argument
+getting signal 51: Invalid argument
+
+setting signal 52: Invalid argument
+getting signal 52: Invalid argument
+
+setting signal 53: Invalid argument
+getting signal 53: Invalid argument
+
+setting signal 54: Invalid argument
+getting signal 54: Invalid argument
+
+setting signal 55: Invalid argument
+getting signal 55: Invalid argument
+
+setting signal 56: Invalid argument
+getting signal 56: Invalid argument
+
+setting signal 57: Invalid argument
+getting signal 57: Invalid argument
+
+setting signal 58: Invalid argument
+getting signal 58: Invalid argument
+
+setting signal 59: Invalid argument
+getting signal 59: Invalid argument
+
+setting signal 60: Invalid argument
+getting signal 60: Invalid argument
+
+setting signal 61: Invalid argument
+getting signal 61: Invalid argument
+
+setting signal 62: Invalid argument
+getting signal 62: Invalid argument
+
+setting signal 65: Invalid argument
+getting signal 65: Invalid argument
+
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
+malloc/free: in use at exit: ... bytes in ... blocks.
+malloc/free: ... allocs, ... frees, ... bytes allocated.
+For a detailed leak analysis, rerun with: --leak-check=yes
+For counts of detected errors, rerun with: -v
diff --git a/memcheck/tests/stack_changes.c b/memcheck/tests/stack_changes.c
index e9d57d0..0d7438c 100644
--- a/memcheck/tests/stack_changes.c
+++ b/memcheck/tests/stack_changes.c
@@ -10,7 +10,7 @@
// This test is checking the libc context calls (setcontext, etc.) and
// checks that Valgrind notices their stack changes properly.
-#if defined(_AIX)
+#if defined(_AIX) || defined(__APPLE__)
typedef ucontext_t mycontext;
#else /* linux */
typedef struct ucontext mycontext;
diff --git a/memcheck/tests/str_tester.c b/memcheck/tests/str_tester.c
index 3c15ea7..7516696 100644
--- a/memcheck/tests/str_tester.c
+++ b/memcheck/tests/str_tester.c
@@ -264,6 +264,8 @@
SIMPLE_COPY(stpcpy, 16, "6666666666666666", 59);
}
+// DDD: better done by testing for the function.
+#if !defined(__APPLE__)
static void
test_stpncpy (void)
{
@@ -278,6 +280,7 @@
check (stpncpy (one, "abcd", 6) == one + 4, 7);
check (one[4] == '\0' && one[5] == '\0' && one[6] == 'x', 8);
}
+#endif
static void
test_strcat (void)
@@ -464,7 +467,7 @@
}
// DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
static void
test_strchrnul (void)
{
@@ -501,7 +504,7 @@
#endif /* !defined(_AIX) */
// DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
static void
test_rawmemchr (void)
{
@@ -577,7 +580,7 @@
}
// DDD: better done by testing for the function.
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
static void
test_memrchr (void)
{
@@ -899,7 +902,7 @@
equal(one+4, "c", 50);
{
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
char text[] = "This,is,a,test";
char *list = strdupa (text);
equal (strsep (&list, ","), "This", 51);
@@ -1060,7 +1063,7 @@
}
}
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
static void
test_mempcpy (void)
{
@@ -1276,6 +1279,7 @@
equal(one, "abcdef", 4); /* Zero-length copy. */
}
+#if !defined(__APPLE__)
static void
test_strndup (void)
{
@@ -1299,6 +1303,7 @@
equal(p, "abc", 6);
free (p);
}
+#endif
static void
test_bcmp (void)
@@ -1382,8 +1387,10 @@
/* A closely related function is stpcpy. */
test_stpcpy ();
+#if !defined(__APPLE__)
/* stpncpy. */
test_stpncpy ();
+#endif
/* strcat. */
test_strcat ();
@@ -1403,12 +1410,12 @@
/* strchr. */
test_strchr ();
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
/* strchrnul. */
test_strchrnul ();
# endif
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
/* rawmemchr. */
test_rawmemchr ();
# endif
@@ -1419,7 +1426,7 @@
/* strrchr. */
test_strrchr ();
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
/* memrchr. */
test_memrchr ();
# endif
@@ -1460,7 +1467,7 @@
/* memmove - must work on overlap. */
test_memmove ();
-# if !defined(_AIX)
+# if !defined(_AIX) && !defined(__APPLE__)
/* mempcpy */
test_mempcpy ();
# endif
@@ -1480,8 +1487,10 @@
/* bcmp - somewhat like memcmp. */
test_bcmp ();
+#if !defined(__APPLE__)
/* strndup. */
test_strndup ();
+#endif
/* strerror - VERY system-dependent. */
test_strerror ();
diff --git a/memcheck/tests/strchr.stderr.exp-darwin b/memcheck/tests/strchr.stderr.exp-darwin
new file mode 100644
index 0000000..8b870df
--- /dev/null
+++ b/memcheck/tests/strchr.stderr.exp-darwin
@@ -0,0 +1,11 @@
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: strchr (mc_replace_strmem.c:...)
+ by 0x........: main (strchr.c:15)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: strchr (mc_replace_strmem.c:...)
+ by 0x........: main (strchr.c:15)
+
+Conditional jump or move depends on uninitialised value(s)
+ at 0x........: strrchr (mc_replace_strmem.c:...)
+ by 0x........: main (strchr.c:16)
diff --git a/memcheck/tests/x86/Makefile.am b/memcheck/tests/x86/Makefile.am
index 28dd116..2cd7b03 100644
--- a/memcheck/tests/x86/Makefile.am
+++ b/memcheck/tests/x86/Makefile.am
@@ -42,9 +42,15 @@
AM_CXXFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
AM_CCASFLAGS += @FLAG_M32@
-# must be built with these flags -- bug only occurred with them
+
+# fpeflags must use these flags -- bug only occurred with them.
fpeflags_CFLAGS = $(AM_CFLAGS) -march=i686
pushfpopf_SOURCES = pushfpopf_c.c pushfpopf_s.S
+if VGCONF_OS_IS_DARWIN
+pushpopmem_CFLAGS = $(AM_CFLAGS) -mdynamic-no-pic
+else
+pushpopmem_CFLAGS = $(AM_CFLAGS)
+endif
tronical_SOURCES = tronical.S
more_x86_fp_LDADD = -lm
diff --git a/none/Makefile.am b/none/Makefile.am
index ac47371..34061af 100644
--- a/none/Makefile.am
+++ b/none/Makefile.am
@@ -19,6 +19,12 @@
if VGCONF_PLATFORMS_INCLUDE_PPC64_AIX5
noinst_PROGRAMS += none-ppc64-aix5
endif
+if VGCONF_PLATFORMS_INCLUDE_X86_DARWIN
+noinst_PROGRAMS += none-x86-darwin
+endif
+if VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+noinst_PROGRAMS += none-amd64-darwin
+endif
NONE_SOURCES_COMMON = nl_main.c
@@ -63,3 +69,17 @@
none_ppc64_aix5_DEPENDENCIES = $(COREGRIND_LIBS_PPC64_AIX5)
none_ppc64_aix5_LDADD = $(TOOL_LDADD_PPC64_AIX5)
none_ppc64_aix5_LDFLAGS = $(TOOL_LDFLAGS_PPC64_AIX5)
+
+none_x86_darwin_SOURCES = $(NONE_SOURCES_COMMON)
+none_x86_darwin_CPPFLAGS = $(AM_CPPFLAGS_X86_DARWIN)
+none_x86_darwin_CFLAGS = $(AM_CFLAGS_X86_DARWIN)
+none_x86_darwin_DEPENDENCIES = $(COREGRIND_LIBS_X86_DARWIN)
+none_x86_darwin_LDADD = $(TOOL_LDADD_X86_DARWIN)
+none_x86_darwin_LDFLAGS = $(TOOL_LDFLAGS_X86_DARWIN)
+
+none_amd64_darwin_SOURCES = $(NONE_SOURCES_COMMON)
+none_amd64_darwin_CPPFLAGS = $(AM_CPPFLAGS_AMD64_DARWIN)
+none_amd64_darwin_CFLAGS = $(AM_CFLAGS_AMD64_DARWIN)
+none_amd64_darwin_DEPENDENCIES = $(COREGRIND_LIBS_AMD64_DARWIN)
+none_amd64_darwin_LDADD = $(TOOL_LDADD_AMD64_DARWIN)
+none_amd64_darwin_LDFLAGS = $(TOOL_LDFLAGS_AMD64_DARWIN)
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index dfec067..1cc18af 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -21,13 +21,16 @@
if VGCONF_OS_IS_LINUX
SUBDIRS += linux
endif
+if VGCONF_OS_IS_DARWIN
+SUBDIRS += darwin
+endif
# Platform-specific tests
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
SUBDIRS += x86-linux
endif
-DIST_SUBDIRS = x86 amd64 ppc32 ppc64 linux x86-linux .
+DIST_SUBDIRS = x86 amd64 ppc32 ppc64 linux darwin x86-linux .
noinst_SCRIPTS = \
filter_cmdline0 filter_linenos \
@@ -140,7 +143,7 @@
fdleak_cmsg fdleak_creat fdleak_dup fdleak_dup2 \
fdleak_fcntl fdleak_ipv4 fdleak_open fdleak_pipe \
fdleak_socketpair \
- floored fork fucomip manythreads \
+ floored fork fucomip \
munmap_exe map_unaligned map_unmap mq \
nestedfns \
pending \
@@ -151,10 +154,27 @@
rlimit_nofile selfrun sem semlimit sha1_test \
shortpush shorts stackgrowth sigstackgrowth \
syscall-restart1 syscall-restart2 system \
- thread-exits threaded-fork threadederrno \
+ threaded-fork threadederrno \
tls tls.so tls2.so vgprintf \
coolo_sigaction gxx304
+# DDD:
+# - manythreads and thread-exits have lots of this:
+# --61831:0:aspacem sync_check_mapping_callback: segment mismatch:
+# kernel's seg:
+# --61831:0:aspacem start=0x102538000 end=0x1025b7fff prot=3 dev=0 ino=0
+# offset=0 name="(none)"
+# --61831:0:aspacem sync_check_mapping_callback: segment mismatch: V's seg:
+# --61831:0:aspacem NSegment{ , start=0x10067a000, end=0x109a1efff,
+# smode=SmFixed, dev=0, ino=0, offset=0, fnIdx=-1, hasR=0,
+# hasW=0, hasX=0, hasT=0, mark=0, name="(none)"}
+if ! VGCONF_PLATFORMS_INCLUDE_AMD64_DARWIN
+ check_PROGRAMS += \
+ manythreads \
+ thread-exits
+endif
+
+
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
@@ -162,7 +182,11 @@
ansi_CFLAGS = $(AM_CFLAGS) -ansi
floored_LDADD = -lm
manythreads_LDADD = -lpthread
-mq_LDADD = -lrt
+if VGCONF_OS_IS_DARWIN
+ nestedfns_CFLAGS = $(AM_CFLAGS) -fnested-functions
+else
+ mq_LDADD = -lrt
+endif
pth_atfork1_LDADD = -lpthread
pth_blockedsig_LDADD = -lpthread
pth_cancel1_CFLAGS = $(AM_CFLAGS) -Wno-shadow
@@ -180,6 +204,7 @@
res_search_LDADD = -lpthread
else
res_search_LDADD = -lresolv -lpthread
+ resolv_LDADD = -lresolv -lpthread
endif
semlimit_LDADD = -lpthread
thread_exits_LDADD = -lpthread
@@ -199,12 +224,21 @@
tls_so_LDFLAGS = -shared -fPIC
tls_so_LDADD = `pwd`/tls2.so
else
+if VGCONF_OS_IS_DARWIN
+ tls_so_LDFLAGS = -dynamic -dynamiclib -all_load -fpic
+ tls_so_LDADD = `pwd`/tls2.so
+else
tls_so_LDFLAGS = -Wl,-rpath,$(top_builddir)/none/tests -shared -fPIC
tls_so_LDADD = tls2.so
endif
+endif
tls_so_CFLAGS = $(AM_CFLAGS) -fPIC
tls2_so_SOURCES = tls2_so.c
+if VGCONF_OS_IS_DARWIN
+tls2_so_LDFLAGS = -dynamic -dynamiclib -all_load
+else
tls2_so_LDFLAGS = -shared
+endif
# C++ tests
coolo_sigaction_SOURCES = coolo_sigaction.cpp
diff --git a/none/tests/amd64/Makefile.am b/none/tests/amd64/Makefile.am
index 13621d0..798bf86 100644
--- a/none/tests/amd64/Makefile.am
+++ b/none/tests/amd64/Makefile.am
@@ -50,19 +50,31 @@
slahf-amd64.vgtest
check_PROGRAMS = \
- bug127521-64 bug132813-amd64 bug137714-amd64 bug132918 \
- bug156404-amd64 \
+ bug127521-64 bug132813-amd64 bug132918 \
clc \
- faultstatus fcmovnu fxtract $(INSN_TESTS) looper jrcxz \
+ $(INSN_TESTS) \
rcl-amd64 \
redundantRexW \
- smc1 shrld \
- nibz_bennee_mmap \
- slahf-amd64
+ smc1 \
+ nibz_bennee_mmap
if BUILD_SSSE3_TESTS
check_PROGRAMS += ssse3_misaligned
endif
+# DDD: these need to be made to work on Darwin like the x86/ ones were.
+if ! VGCONF_OS_IS_DARWIN
+ check_PROGRAMS += \
+ bug137714-amd64 \
+ bug156404-amd64 \
+ faultstatus \
+ fcmovnu \
+ fxtract \
+ looper \
+ jrcxz \
+ shrld \
+ slahf-amd64
+endif
+
AM_CFLAGS += @FLAG_M64@
AM_CXXFLAGS += @FLAG_M64@
AM_CCASFLAGS += @FLAG_M64@
diff --git a/none/tests/darwin/Makefile.am b/none/tests/darwin/Makefile.am
new file mode 100644
index 0000000..b4c90bf
--- /dev/null
+++ b/none/tests/darwin/Makefile.am
@@ -0,0 +1,17 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+noinst_SCRIPTS = filter_stderr
+
+EXTRA_DIST = $(noinst_SCRIPTS) \
+ apple-main-arg.stderr.exp apple-main-arg.vgtest \
+ rlimit.stderr.exp rlimit.vgtest
+
+check_PROGRAMS = \
+ apple-main-arg \
+ rlimit
+
+
+AM_CFLAGS += $(AM_FLAG_M3264_PRI)
+AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
diff --git a/none/tests/darwin/apple-main-arg.c b/none/tests/darwin/apple-main-arg.c
new file mode 100644
index 0000000..945acc1
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/syslimits.h>
+
+// On Darwin there's this secret fourth argument, 'apple', which is a pointer
+// to a string that contains the executable path, like argv[0], but unlike
+// argv[0] it can't be changed using exec().
+
+int main(int argc, char *argv[], char *envp[], char *apple[])
+{
+ char *pargv = calloc((PATH_MAX+1), sizeof(char)),
+ *pappl = calloc((PATH_MAX+1), sizeof(char));
+ int i;
+
+ for (i = 0; envp[i]; i++)
+ ;
+
+ // envp[i]==NULL; envp[i+1]==apple[0]==executable_path
+ assert(envp[i+1] == apple[0]);
+
+ // Make sure realpath(argv[0]) == realpath(apple[0]). (realpath resolves
+ // symlinks.)
+ realpath(argv[0], pargv);
+ realpath(apple[0], pappl);
+ assert(0 == strcmp(pargv, pappl));
+
+ return 0;
+}
+
diff --git a/none/tests/darwin/apple-main-arg.stderr.exp b/none/tests/darwin/apple-main-arg.stderr.exp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.stderr.exp
diff --git a/none/tests/darwin/apple-main-arg.vgtest b/none/tests/darwin/apple-main-arg.vgtest
new file mode 100644
index 0000000..df4e15a
--- /dev/null
+++ b/none/tests/darwin/apple-main-arg.vgtest
@@ -0,0 +1,2 @@
+prog: apple-main-arg
+vgopts: -q
diff --git a/none/tests/darwin/filter_stderr b/none/tests/darwin/filter_stderr
new file mode 100644
index 0000000..0ae9313
--- /dev/null
+++ b/none/tests/darwin/filter_stderr
@@ -0,0 +1,3 @@
+#! /bin/sh
+
+../filter_stderr
diff --git a/none/tests/darwin/rlimit.c b/none/tests/darwin/rlimit.c
new file mode 100644
index 0000000..ac5ac82
--- /dev/null
+++ b/none/tests/darwin/rlimit.c
@@ -0,0 +1,17 @@
+// Small test program to demonstrate Valgrind bug.
+// https://bugs.kde.org/show_bug.cgi?id=191761
+// Author: rohitrao@google.com
+//
+// Before the fix, it was printing 266. Now it prints 256.
+
+#include <stdio.h>
+#include <sys/resource.h>
+
+int main(void)
+{
+ struct rlimit rlp;
+ getrlimit(RLIMIT_NOFILE, &rlp);
+ fprintf(stderr, "RLIMIT_NOFILE is %lld\n", (long long)rlp.rlim_cur);
+ return 0;
+}
+
diff --git a/none/tests/darwin/rlimit.stderr.exp b/none/tests/darwin/rlimit.stderr.exp
new file mode 100644
index 0000000..56d4e4c
--- /dev/null
+++ b/none/tests/darwin/rlimit.stderr.exp
@@ -0,0 +1 @@
+RLIMIT_NOFILE is 256
diff --git a/none/tests/darwin/rlimit.vgtest b/none/tests/darwin/rlimit.vgtest
new file mode 100644
index 0000000..2706845
--- /dev/null
+++ b/none/tests/darwin/rlimit.vgtest
@@ -0,0 +1,2 @@
+prog: rlimit
+vgopts: -q
diff --git a/none/tests/pth_atfork1.c b/none/tests/pth_atfork1.c
index 79ce177..df5ef98 100644
--- a/none/tests/pth_atfork1.c
+++ b/none/tests/pth_atfork1.c
@@ -18,7 +18,7 @@
Boston, MA 02111-1307, USA. */
#include <errno.h>
-#if !defined(_AIX)
+#if !defined(_AIX) && !defined(__APPLE__)
# include <error.h>
#endif
#include <stdlib.h>
@@ -27,7 +27,7 @@
#include <sys/wait.h>
#include <stdio.h>
-#if defined(_AIX)
+#if defined(_AIX) || defined(__APPLE__)
#include <string.h> /* strerror */
static void error (int status, int errnum, char* msg)
{
diff --git a/none/tests/x86/Makefile.am b/none/tests/x86/Makefile.am
index cc0372b..f405c51 100644
--- a/none/tests/x86/Makefile.am
+++ b/none/tests/x86/Makefile.am
@@ -92,6 +92,14 @@
AM_CXXFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
AM_CCASFLAGS += @FLAG_M32@
+if VGCONF_OS_IS_DARWIN
+# Some of the tests (bug125959_x86, bug152818_x86, insn_*) need
+# -mdynamic-no-pic. I tried setting *_CFLAGS separately for all of them,
+# but it caused problems with the generation of insn_*.c. So just use this
+# crude approach of setting -mdynamic-no-pic for all tests in this
+# directory.
+AM_CFLAGS += -mdynamic-no-pic
+endif
cpuid_SOURCES = cpuid_c.c cpuid_s.S
# fpu_lazy_eflags must use these flags -- the bug only occurred with them.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0350f0d..2cf5a82 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -27,3 +27,7 @@
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+if VGCONF_OS_IS_DARWIN
+x86_amd64_features_CFLAGS = $(AM_CFLAGS) -mdynamic-no-pic
+endif
+
diff --git a/tests/arch_test.c b/tests/arch_test.c
index f6206e3..6771f4a 100644
--- a/tests/arch_test.c
+++ b/tests/arch_test.c
@@ -32,10 +32,10 @@
static Bool go(char* arch)
{
-#if defined(VGP_x86_linux)
+#if defined(VGP_x86_linux) || defined(VGP_x86_darwin)
if ( 0 == strcmp( arch, "x86" ) ) return True;
-#elif defined(VGP_amd64_linux)
+#elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin)
if ( 0 == strcmp( arch, "x86" ) ) return True;
if ( 0 == strcmp( arch, "amd64" ) ) return True;
diff --git a/tests/asm.h b/tests/asm.h
index 99f9cc5..e2c2524 100644
--- a/tests/asm.h
+++ b/tests/asm.h
@@ -5,7 +5,15 @@
// general, any symbol named in asm code should be wrapped by VG_SYM.
// This one is for use in inline asm in C files.
+#if defined(VGO_darwin)
+#define VG_SYM(x) "_"#x
+#else
#define VG_SYM(x) #x
+#endif
// This one is for use in asm files.
+#if defined(VGO_darwin)
+#define VG_SYM_ASM(x) _##x
+#else
#define VG_SYM_ASM(x) x
+#endif
diff --git a/tests/filter_libc b/tests/filter_libc
index a89fb89..48c443f 100755
--- a/tests/filter_libc
+++ b/tests/filter_libc
@@ -15,8 +15,9 @@
s/ __GI___/ __/;
s/ __([a-z]*)_nocancel / $1 /;
- s/\(in \/.*libc.*\)$/(in \/...libc...)/;
- s/\(within \/.*libc.*\)$/(within \/...libc...)/;
+ # "libSystem*" occurs on Darwin.
+ s/\(in \/.*(libc|libSystem).*\)$/(in \/...libc...)/;
+ s/\(within \/.*(libc|libSystem).*\)$/(within \/...libc...)/;
# Remove the filename -- on some platforms (eg. Linux) it will be in
# libc, on some (eg. Darwin) it will be in the main executable.
diff --git a/tests/malloc.h b/tests/malloc.h
index 454d2cf..0179b38 100644
--- a/tests/malloc.h
+++ b/tests/malloc.h
@@ -1,7 +1,11 @@
// Replacement for malloc.h which factors out platform differences.
#include <stdlib.h>
-#include <malloc.h>
+#if defined(VGO_darwin)
+# include <malloc/malloc.h>
+#else
+# include <malloc.h>
+#endif
#include <assert.h>
@@ -10,7 +14,12 @@
static void* memalign16(size_t szB)
{
void* x;
+#if defined(VGO_darwin)
+ // Darwin lacks memalign, but its malloc is always 16-aligned anyway.
+ x = malloc(szB);
+#else
x = memalign(16, szB);
+#endif
assert(x);
assert(0 == ((16-1) & (unsigned long)x));
return x;
diff --git a/tests/os_test.c b/tests/os_test.c
index 065dbe5..a65115c 100644
--- a/tests/os_test.c
+++ b/tests/os_test.c
@@ -22,6 +22,7 @@
char* all_OSes[] = {
"linux",
"aix5",
+ "darwin",
NULL
};
@@ -31,7 +32,10 @@
if ( 0 == strcmp( OS, "linux" ) ) return True;
#elif defined(VGO_aix5)
- if ( 0 == strcmp( OS, "aix5" ) ) return True;
+ if ( 0 == strcmp( OS, "aix5" ) ) return True;
+
+#elif defined(VGO_darwin)
+ if ( 0 == strcmp( OS, "darwin" ) ) return True;
#else
# error Unknown OS
diff --git a/tests/platform_test b/tests/platform_test
index e91b9f7..4d57901 100644
--- a/tests/platform_test
+++ b/tests/platform_test
@@ -13,6 +13,7 @@
all_platforms=
all_platforms="$all_platforms x86-linux amd64-linux ppc32-linux ppc64-linux"
all_platforms="$all_platforms ppc32-aix5 ppc64-aix5"
+all_platforms="$all_platforms x86-darwin amd64-darwin"
if [ $# -ne 2 ] ; then
echo "usage: platform_test <arch-type> <OS-type>"
diff --git a/tests/sys_mman.h b/tests/sys_mman.h
index 862bccc..7ac64d5 100644
--- a/tests/sys_mman.h
+++ b/tests/sys_mman.h
@@ -2,6 +2,10 @@
#include <sys/mman.h>
+#if defined(VGO_darwin)
+# define MAP_ANONYMOUS MAP_ANON
+#endif
+
#include <assert.h>
#include <unistd.h>
diff --git a/tests/x86_amd64_features.c b/tests/x86_amd64_features.c
index 9d17805..06ebe5d 100644
--- a/tests/x86_amd64_features.c
+++ b/tests/x86_amd64_features.c
@@ -83,7 +83,7 @@
return 1; // Feature not present.
}
-#else // defined(VGA_x86) || defined(VGA_amd64)
+#else
static Bool go(char* cpu)
{