diff --git a/Makefile.all.am b/Makefile.all.am index 4a29695cc..c797e6f71 100644 --- a/Makefile.all.am +++ b/Makefile.all.am @@ -137,9 +137,14 @@ AM_CFLAGS_PSO_BASE = -dynamic \ -O -g -fno-omit-frame-pointer -fno-strict-aliasing \ -fpic -fPIC -fno-builtin @FLAG_FNO_IPA_ICF@ else +if VGCONF_OS_IS_FREEBSD +AM_CFLAGS_PSO_BASE = -O -g -fno-omit-frame-pointer -fno-strict-aliasing \ + -fpic -fPIC -fno-builtin +else AM_CFLAGS_PSO_BASE = -O -g -fno-omit-frame-pointer -fno-strict-aliasing \ -fpic -fno-builtin @FLAG_FNO_IPA_ICF@ endif +endif # Flags for specific targets. @@ -204,6 +209,12 @@ AM_CFLAGS_PPC64LE_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) AM_CFLAGS_PSO_PPC64LE_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE) AM_CCASFLAGS_PPC64LE_LINUX = @FLAG_M64@ -g +AM_FLAG_M3264_X86_FREEBSD = @FLAG_M32@ +AM_CFLAGS_X86_FREEBSD = @FLAG_M32@ @PREFERRED_STACK_BOUNDARY_2@ \ + $(AM_CFLAGS_BASE) -fomit-frame-pointer +AM_CFLAGS_PSO_X86_FREEBSD = @FLAG_M32@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE) +AM_CCASFLAGS_X86_FREEBSD = @FLAG_M32@ -g + AM_FLAG_M3264_ARM_LINUX = @FLAG_M32@ AM_CFLAGS_ARM_LINUX = @FLAG_M32@ \ $(AM_CFLAGS_BASE) -marm -mcpu=cortex-a8 @@ -217,6 +228,14 @@ AM_CFLAGS_ARM64_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) AM_CFLAGS_PSO_ARM64_LINUX = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE) AM_CCASFLAGS_ARM64_LINUX = @FLAG_M64@ -g + +AM_FLAG_M3264_AMD64_FREEBSD = @FLAG_M64@ +AM_CFLAGS_AMD64_FREEBSD = @FLAG_M64@ \ + $(AM_CFLAGS_BASE) -fomit-frame-pointer +AM_CFLAGS_PSO_AMD64_FREEBSD = @FLAG_M64@ $(AM_CFLAGS_BASE) $(AM_CFLAGS_PSO_BASE) +AM_CCASFLAGS_AMD64_FREEBSD = @FLAG_M64@ -g + + AM_FLAG_M3264_X86_DARWIN = -arch i386 AM_CFLAGS_X86_DARWIN = $(WERROR) -arch i386 $(AM_CFLAGS_BASE) \ -mmacosx-version-min=10.6 \ @@ -280,6 +299,7 @@ endif # Baseline link flags for making vgpreload shared objects. # PRELOAD_LDFLAGS_COMMON_LINUX = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst +PRELOAD_LDFLAGS_COMMON_FREEBSD = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst PRELOAD_LDFLAGS_COMMON_DARWIN = -dynamic -dynamiclib -all_load PRELOAD_LDFLAGS_COMMON_SOLARIS = -nodefaultlibs -shared -Wl,-z,interpose,-z,initfirst if SOLARIS_XPG_SYMBOLS_PRESENT @@ -300,6 +320,8 @@ PRELOAD_LDFLAGS_PPC64BE_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ PRELOAD_LDFLAGS_PPC64LE_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ PRELOAD_LDFLAGS_ARM_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M32@ PRELOAD_LDFLAGS_ARM64_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ +PRELOAD_LDFLAGS_X86_FREEBSD = $(PRELOAD_LDFLAGS_COMMON_FREEBSD) @FLAG_M32@ +PRELOAD_LDFLAGS_AMD64_FREEBSD= $(PRELOAD_LDFLAGS_COMMON_FREEBSD) @FLAG_M64@ PRELOAD_LDFLAGS_X86_DARWIN = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch i386 PRELOAD_LDFLAGS_AMD64_DARWIN = $(PRELOAD_LDFLAGS_COMMON_DARWIN) -arch x86_64 PRELOAD_LDFLAGS_S390X_LINUX = $(PRELOAD_LDFLAGS_COMMON_LINUX) @FLAG_M64@ diff --git a/Makefile.am b/Makefile.am index 154f68f5f..335a672ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ SUPP_FILES = \ glibc-2.X-drd.supp \ exp-sgcheck.supp \ darwin9.supp darwin9-drd.supp \ + freebsd.supp \ darwin10.supp darwin10-drd.supp \ darwin11.supp darwin12.supp darwin13.supp darwin14.supp darwin15.supp \ darwin16.supp darwin17.supp \ @@ -102,6 +103,7 @@ perf: check EXTRA_DIST = \ COPYING.DOCS \ README_DEVELOPERS \ + README_FREEBSD \ README_PACKAGERS \ README_MISSING_SYSCALL_OR_IOCTL \ README.s390 \ diff --git a/Makefile.tool.am b/Makefile.tool.am index 677571fad..0feb18c35 100644 --- a/Makefile.tool.am +++ b/Makefile.tool.am @@ -39,13 +39,21 @@ TOOL_LDFLAGS_COMMON_DARWIN = \ TOOL_LDFLAGS_COMMON_SOLARIS = \ -static -nodefaultlibs -nostartfiles -u _start \ -Wl,-M,/usr/lib/ld/map.noexstk +TOOL_LDFLAGS_COMMON_FREEBSD = -static \ + -nodefaultlibs -nostartfiles -u _start @FLAG_NO_BUILD_ID@ TOOL_LDFLAGS_X86_LINUX = \ $(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M32@ +TOOL_LDFLAGS_X86_FREEBSD = \ + $(TOOL_LDFLAGS_COMMON_FREEBSD) @FLAG_M32@ + TOOL_LDFLAGS_AMD64_LINUX = \ $(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M64@ +TOOL_LDFLAGS_AMD64_FREEBSD = \ + $(TOOL_LDFLAGS_COMMON_FREEBSD) @FLAG_M64@ + TOOL_LDFLAGS_PPC32_LINUX = \ $(TOOL_LDFLAGS_COMMON_LINUX) @FLAG_M32@ @@ -120,12 +128,18 @@ LIBREPLACEMALLOC_PPC64BE_LINUX = \ LIBREPLACEMALLOC_PPC64LE_LINUX = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-ppc64le-linux.a +LIBREPLACEMALLOC_X86_FREEBSD = \ + $(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-freebsd.a + LIBREPLACEMALLOC_ARM_LINUX = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-arm-linux.a LIBREPLACEMALLOC_ARM64_LINUX = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-arm64-linux.a +LIBREPLACEMALLOC_AMD64_FREEBSD = \ + $(top_builddir)/coregrind/libreplacemalloc_toolpreload-amd64-freebsd.a + LIBREPLACEMALLOC_X86_DARWIN = \ $(top_builddir)/coregrind/libreplacemalloc_toolpreload-x86-darwin.a @@ -182,6 +196,16 @@ LIBREPLACEMALLOC_LDFLAGS_ARM64_LINUX = \ $(LIBREPLACEMALLOC_ARM64_LINUX) \ -Wl,--no-whole-archive +LIBREPLACEMALLOC_LDFLAGS_X86_FREEBSD = \ + -Wl,--whole-archive \ + $(LIBREPLACEMALLOC_X86_FREEBSD) \ + -Wl,--no-whole-archive + +LIBREPLACEMALLOC_LDFLAGS_AMD64_FREEBSD = \ + -Wl,--whole-archive \ + $(LIBREPLACEMALLOC_AMD64_FREEBSD) \ + -Wl,--no-whole-archive + LIBREPLACEMALLOC_LDFLAGS_X86_DARWIN = \ $(LIBREPLACEMALLOC_X86_DARWIN) diff --git a/README_FREEBSD b/README_FREEBSD new file mode 100755 index 000000000..3ec8c8648 --- /dev/null +++ b/README_FREEBSD @@ -0,0 +1,14 @@ +So, install ports for autoconf, automake and gmake. +$ sh autogen.sh +$ ./configure --prefix=/where/ever +$ gmake +$ gmake install + +Sun Aug 19 20:26:48 UTC 2007 PS_STRINGS + Valgrind barfs all over the place on setproctitle. + + This also manifests itself in a corrupted environment in + children of child processes when --trace-children=yes is used. + + To cope correctly Valgrind must install the modified argv/envp + pointers in the ps-strings area, and mark it as accessible. diff --git a/cachegrind/tests/Makefile.am b/cachegrind/tests/Makefile.am index f2f890294..12da14457 100644 --- a/cachegrind/tests/Makefile.am +++ b/cachegrind/tests/Makefile.am @@ -30,7 +30,9 @@ AM_CFLAGS += $(AM_FLAG_M3264_PRI) AM_CXXFLAGS += $(AM_FLAG_M3264_PRI) # C ones +if !VGCONF_OS_IS_FREEBSD dlclose_LDADD = -ldl +endif if VGCONF_OS_IS_DARWIN myprint_so_LDFLAGS = $(AM_CFLAGS) -dynamic -dynamiclib -all_load -fpic else diff --git a/configure.ac b/configure.ac index 289514ff1..6b113a2f9 100644 --- a/configure.ac +++ b/configure.ac @@ -45,6 +45,8 @@ AC_PROG_CXX # AC_SUBST([OBJCFLAGS]) # ]) AC_PROG_RANLIB +AC_PROG_EGREP + # Set LTO_RANLIB variable to an lto enabled ranlib if test "x$LTO_RANLIB" = "x"; then AC_PATH_PROGS([LTO_RANLIB], [gcc-ranlib]) @@ -224,7 +226,7 @@ case "${host_cpu}" in ARCH_MAX="x86" ;; - x86_64) + x86_64|amd64) AC_MSG_RESULT([ok (${host_cpu})]) ARCH_MAX="amd64" ;; @@ -356,6 +358,12 @@ case "${host_os}" in ;; + *freebsd*) + AC_MSG_RESULT([ok (${host_os})]) + VGCONF_OS="freebsd" + DEFAULT_SUPP="freebsd.supp ${DEFAULT_SUPP}" + ;; + *darwin*) AC_MSG_RESULT([ok (${host_os})]) VGCONF_OS="darwin" @@ -656,6 +664,41 @@ case "$ARCH_MAX-$VGCONF_OS" in valt_load_address_pri_inner="0x38000000" AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})]) ;; + x86-freebsd) + VGCONF_ARCH_PRI="x86" + VGCONF_ARCH_SEC="" + VGCONF_PLATFORM_PRI_CAPS="X86_FREEBSD" + VGCONF_PLATFORM_SEC_CAPS="" + valt_load_address_pri_norml="0x38000000" + valt_load_address_pri_inner="0x28000000" + valt_load_address_sec_norml="0xUNSET" + valt_load_address_sec_inner="0xUNSET" + AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})]) + ;; + amd64-freebsd) + if test x$vg_cv_only64bit = xyes; then + VGCONF_ARCH_PRI="amd64" + VGCONF_ARCH_SEC="" + VGCONF_PLATFORM_PRI_CAPS="AMD64_FREEBSD" + VGCONF_PLATFORM_SEC_CAPS="" + elif test x$vg_cv_only32bit = xyes; then + VGCONF_ARCH_PRI="x86" + VGCONF_ARCH_SEC="" + VGCONF_PLATFORM_PRI_CAPS="X86_FREEBSD" + VGCONF_PLATFORM_SEC_CAPS="" + else + VGCONF_ARCH_PRI="amd64" + VGCONF_ARCH_SEC="x86" + VGCONF_PLATFORM_PRI_CAPS="AMD64_FREEBSD" + VGCONF_PLATFORM_SEC_CAPS="X86_FREEBSD" + fi + FLAG_32ON64="-B/usr/lib32" + valt_load_address_pri_norml="0x38000000" + valt_load_address_pri_inner="0x28000000" + valt_load_address_sec_norml="0x38000000" + valt_load_address_sec_inner="0x28000000" + AC_MSG_RESULT([ok (${ARCH_MAX}-${VGCONF_OS})]) + ;; # Darwin gets identified as 32-bit even when it supports 64-bit. # (Not sure why, possibly because 'uname' returns "i386"?) Just about # all Macs support both 32-bit and 64-bit, so we just build both. If @@ -845,12 +888,15 @@ esac 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_PRI_CAPS = xX86_FREEBSD \ + -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN \ -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS \ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_SOLARIS ) AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_AMD64, test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN \ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_SOLARIS ) AM_CONDITIONAL(VGCONF_ARCHS_INCLUDE_PPC32, @@ -899,6 +945,11 @@ AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_MIPS32_LINUX, -o x$VGCONF_PLATFORM_SEC_CAPS = xMIPS32_LINUX) AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_MIPS64_LINUX, test x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX) +AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_FREEBSD, + test x$VGCONF_PLATFORM_PRI_CAPS = xX86_FREEBSD \ + -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_FREEBSD) +AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_AMD64_FREEBSD, + test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_FREEBSD) AM_CONDITIONAL(VGCONF_PLATFORMS_INCLUDE_X86_DARWIN, test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN) @@ -925,6 +976,11 @@ AM_CONDITIONAL(VGCONF_OS_IS_LINUX, -o x$VGCONF_PLATFORM_PRI_CAPS = xS390X_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX) + AM_CONDITIONAL(VGCONF_OS_IS_FREEBSD, + test x$VGCONF_PLATFORM_PRI_CAPS = xX86_FREEBSD \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_FREEBSD \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_FREEBSD \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_FREEBSD) AM_CONDITIONAL(VGCONF_OS_IS_DARWIN, test x$VGCONF_PLATFORM_PRI_CAPS = xX86_DARWIN \ -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_DARWIN) @@ -1024,6 +1080,14 @@ AC_EGREP_CPP([DARWIN_LIBC], [ ], GLIBC_VERSION="darwin") +AC_EGREP_CPP([FREEBSD_LIBC], [ +#include +#if defined(__FreeBSD__) + FREEBSD_LIBC +#endif +], +GLIBC_VERSION="freebsd") + # not really a version check AC_EGREP_CPP([BIONIC_LIBC], [ #if defined(__ANDROID__) @@ -1090,6 +1154,11 @@ case "${GLIBC_VERSION}" in AC_DEFINE([DARWIN_LIBC], 1, [Define to 1 if you're using Darwin]) # DEFAULT_SUPP set by kernel version check above. ;; + freebsd) + AC_MSG_RESULT(FreeBSD) + AC_DEFINE([FREEBSD_LIBC], 1, [Define to 1 if you're using FreeBSD]) + # DEFAULT_SUPP set by kernel version check above. + ;; bionic) AC_MSG_RESULT(Bionic) AC_DEFINE([BIONIC_LIBC], 1, [Define to 1 if you're using Bionic]) @@ -1792,12 +1861,12 @@ case "${host_cpu}" in AC_MSG_CHECKING([if gcc accepts -m32]) safe_CFLAGS=$CFLAGS - CFLAGS="-m32 -Werror" + CFLAGS="${FLAG_32ON64} -m32 -Werror" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[ return 0; ]])], [ - FLAG_M32="-m32" + FLAG_M32="${FLAG_32ON64} -m32" AC_MSG_RESULT([yes]) ], [ FLAG_M32="" @@ -4075,6 +4144,8 @@ AC_FUNC_MMAP AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([rt], [clock_gettime]) +safe_CFLAGS=$CFLAGS +CFLAGS="${CFLAGS} -pthread" AC_CHECK_FUNCS([ \ clock_gettime\ epoll_create \ @@ -4108,6 +4179,7 @@ AC_CHECK_FUNCS([ \ process_vm_readv \ process_vm_writev \ ]) +CFLAGS=$safe_CFLAGS # AC_CHECK_LIB adds any library found to the variable LIBS, and links these # libraries with any shared object and/or executable. This is NOT what we @@ -4142,12 +4214,14 @@ AC_PATH_PROG([MPI_CC], [mpicc], [mpicc], mflag_primary= if test x$VGCONF_PLATFORM_PRI_CAPS = xX86_LINUX \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xARM_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS32_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xX86_SOLARIS ; then mflag_primary=$FLAG_M32 elif test x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_LINUX \ + -o x$VGCONF_PLATFORM_PRI_CAPS = xAMD64_FREEBSD \ -o x$VGCONF_PLATFORM_PRI_CAPS = xPPC64_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xARM64_LINUX \ -o x$VGCONF_PLATFORM_PRI_CAPS = xMIPS64_LINUX \ @@ -4163,7 +4237,8 @@ mflag_secondary= if test x$VGCONF_PLATFORM_SEC_CAPS = xX86_LINUX \ -o x$VGCONF_PLATFORM_SEC_CAPS = xPPC32_LINUX \ -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_SOLARIS \ - -o x$VGCONF_PLATFORM_SEC_CAPS = xMIPS32_LINUX ; then + -o x$VGCONF_PLATFORM_SEC_CAPS = xMIPS32_LINUX \ + -o x$VGCONF_PLATFORM_SEC_CAPS = xX86_FREEBSD ; then mflag_secondary=$FLAG_M32 elif test x$VGCONF_PLATFORM_SEC_CAPS = xX86_DARWIN ; then mflag_secondary="$FLAG_M32 -arch i386" @@ -4184,6 +4259,9 @@ AC_SUBST(MPI_CC) AM_COND_IF([VGCONF_OS_IS_LINUX], [CFLAGS_MPI="-g -O -fno-omit-frame-pointer -Wall -fpic" LDFLAGS_MPI="-fpic -shared"]) +AM_COND_IF([VGCONF_OS_IS_FREEBSD], + [CFLAGS_MPI="-g -O -fno-omit-frame-pointer -Wall -fpic" + LDFLAGS_MPI="-fpic -shared"]) AM_COND_IF([VGCONF_OS_IS_DARWIN], [CFLAGS_MPI="-g -O -fno-omit-frame-pointer -Wall -dynamic" LDFLAGS_MPI="-dynamic -dynamiclib -all_load"]) @@ -4680,6 +4758,8 @@ AC_CONFIG_FILES([ ]) AC_CONFIG_FILES([coregrind/link_tool_exe_linux], [chmod +x coregrind/link_tool_exe_linux]) +AC_CONFIG_FILES([coregrind/link_tool_exe_freebsd], + [chmod +x coregrind/link_tool_exe_freebsd]) AC_CONFIG_FILES([coregrind/link_tool_exe_darwin], [chmod +x coregrind/link_tool_exe_darwin]) AC_CONFIG_FILES([coregrind/link_tool_exe_solaris], diff --git a/coregrind/Makefile.am b/coregrind/Makefile.am index 94030fdb0..1e912f338 100644 --- a/coregrind/Makefile.am +++ b/coregrind/Makefile.am @@ -49,6 +49,11 @@ valgrind_SOURCES = \ launcher-linux.c \ m_debuglog.c endif +if VGCONF_OS_IS_FREEBSD +valgrind_SOURCES = \ + launcher-freebsd.c \ + m_debuglog.c +endif # for valgrind coregrind building, use the LTO versions, in case they differ from non lto versions AR = ${LTO_AR} @@ -92,6 +97,9 @@ endif if VGCONF_OS_IS_SOLARIS vgdb_SOURCES += vgdb-invoker-solaris.c endif +if VGCONF_OS_IS_FREEBSD +vgdb_SOURCES += vgdb-invoker-none.c +endif vgdb_CPPFLAGS = $(AM_CPPFLAGS_PRI) vgdb_CFLAGS = $(AM_CFLAGS_PRI) $(LTO_CFLAGS) @@ -276,6 +284,7 @@ noinst_HEADERS = \ m_syswrap/priv_syswrap-generic.h \ m_syswrap/priv_syswrap-linux.h \ m_syswrap/priv_syswrap-linux-variants.h \ + m_syswrap/priv_syswrap-freebsd.h \ m_syswrap/priv_syswrap-darwin.h \ m_syswrap/priv_syswrap-solaris.h \ m_syswrap/priv_syswrap-main.h \ @@ -376,6 +385,8 @@ COREGRIND_SOURCES_COMMON = \ m_dispatch/dispatch-s390x-linux.S \ m_dispatch/dispatch-mips32-linux.S \ m_dispatch/dispatch-mips64-linux.S \ + m_dispatch/dispatch-x86-freebsd.S \ + m_dispatch/dispatch-amd64-freebsd.S \ m_dispatch/dispatch-x86-darwin.S \ m_dispatch/dispatch-amd64-darwin.S \ m_dispatch/dispatch-x86-solaris.S \ @@ -399,6 +410,7 @@ COREGRIND_SOURCES_COMMON = \ m_gdbserver/valgrind-low-mips64.c \ m_gdbserver/version.c \ m_initimg/initimg-linux.c \ + m_initimg/initimg-freebsd.c \ m_initimg/initimg-darwin.c \ m_initimg/initimg-solaris.c \ m_initimg/initimg-pathscan.c \ @@ -414,6 +426,8 @@ COREGRIND_SOURCES_COMMON = \ m_sigframe/sigframe-common.c \ m_sigframe/sigframe-x86-linux.c \ m_sigframe/sigframe-amd64-linux.c \ + m_sigframe/sigframe-x86-freebsd.c \ + m_sigframe/sigframe-amd64-freebsd.c \ m_sigframe/sigframe-ppc32-linux.c \ m_sigframe/sigframe-ppc64-linux.c \ m_sigframe/sigframe-arm-linux.c \ @@ -434,6 +448,8 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syscall-s390x-linux.S \ m_syswrap/syscall-mips32-linux.S \ m_syswrap/syscall-mips64-linux.S \ + m_syswrap/syscall-x86-freebsd.S \ + m_syswrap/syscall-amd64-freebsd.S \ m_syswrap/syscall-x86-darwin.S \ m_syswrap/syscall-amd64-darwin.S \ m_syswrap/syscall-x86-solaris.S \ @@ -442,12 +458,16 @@ COREGRIND_SOURCES_COMMON = \ m_syswrap/syswrap-generic.c \ m_syswrap/syswrap-linux.c \ m_syswrap/syswrap-linux-variants.c \ + m_syswrap/syswrap-freebsd.c \ + m_syswrap/syswrap-freebsd-variants.c \ m_syswrap/syswrap-darwin.c \ m_syswrap/syswrap-solaris.c \ m_syswrap/syswrap-x86-linux.c \ m_syswrap/syswrap-amd64-linux.c \ m_syswrap/syswrap-ppc32-linux.c \ m_syswrap/syswrap-ppc64-linux.c \ + m_syswrap/syswrap-x86-freebsd.c \ + m_syswrap/syswrap-amd64-freebsd.c \ m_syswrap/syswrap-arm-linux.c \ m_syswrap/syswrap-arm64-linux.c \ m_syswrap/syswrap-s390x-linux.c \ diff --git a/coregrind/launcher-freebsd.c b/coregrind/launcher-freebsd.c new file mode 100755 index 000000000..4d92f546e --- /dev/null +++ b/coregrind/launcher-freebsd.c @@ -0,0 +1,339 @@ + +/*--------------------------------------------------------------------*/ +/*--- Launching valgrind m_launcher.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* #include */ +#include + +#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" + + + +#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno + where it is defined */ + +#ifndef EM_X86_64 +#define EM_X86_64 62 // elf.h doesn't define this on some older systems +#endif + +/* Report fatal errors */ +__attribute__((noreturn)) +static void barf ( const char *format, ... ) +{ + va_list vargs; + + va_start(vargs, format); + fprintf(stderr, "valgrind: Cannot continue: "); + 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; +} + +/* Examine the client and work out which platform it is for */ +static const char *select_platform(const char *clientname) +{ + int fd; + uint8_t header[4096]; + ssize_t n_bytes; + const char *platform = NULL; + + if (strchr(clientname, '/') == NULL) + clientname = find_client(clientname); + + if ((fd = open(clientname, O_RDONLY)) < 0) + return NULL; + // barf("open(%s): %s", clientname, strerror(errno)); + + n_bytes = read(fd, header, sizeof(header)); + close(fd); + if (n_bytes < 2) { + return NULL; + } + + if (header[0] == '#' && header[1] == '!') { + int i = 2; + char *interp = (char *)header + 2; + + // Skip whitespace. + while (1) { + if (i == n_bytes) return NULL; + if (' ' != header[i] && '\t' == header[i]) break; + i++; + } + + // Get the interpreter name. + interp = &header[i]; + while (1) { + if (i == n_bytes) break; + if (isspace(header[i])) break; + i++; + } + if (i == n_bytes) return NULL; + header[i] = '\0'; + + platform = select_platform(interp); + + } else if (n_bytes >= SELFMAG && memcmp(header, ELFMAG, SELFMAG) == 0) { + + if (n_bytes >= sizeof(Elf32_Ehdr) && header[EI_CLASS] == ELFCLASS32) { + const Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header; + + if (header[EI_DATA] == ELFDATA2LSB) { + if (ehdr->e_machine == EM_386 && + ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { + platform = "x86-freebsd"; + } + } + } else if (n_bytes >= sizeof(Elf64_Ehdr) && header[EI_CLASS] == ELFCLASS64) { + const Elf64_Ehdr *ehdr = (Elf64_Ehdr *)header; + + if (header[EI_DATA] == ELFDATA2LSB) { + if (ehdr->e_machine == EM_X86_64 && + ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD) { + platform = "amd64-freebsd"; + } + } + } + } + + return platform; +} + +/* Where we expect to find all our aux files */ +static const char *valgrind_lib = VG_LIBDIR; + +int main(int argc, char** argv, char** envp) +{ + int i, j, loglevel, r; + const char *toolname = NULL; + const char *clientname = NULL; + const char *platform; + const char *default_platform; + const char *cp; + char *toolfile; + char launcher_name[PATH_MAX+1]; + char* new_line; + char** new_env; +#if __FreeBSD__ >= 7 + int oid[4]; + vki_size_t len; +#endif + + /* 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]; + break; + } + if (0 == strcmp(argv[i], "--")) { + if (i+1 < argc) + clientname = argv[i+1]; + break; + } + if (0 == strcmp(argv[i], "-d")) + loglevel++; + if (0 == strncmp(argv[i], "--tool=", 7)) + toolname = argv[i] + 7; + } + + /* ... and start the debug logger. Now we can safely emit logging + messages all through startup. */ + VG_(debugLog_startup)(loglevel, "Stage 1"); + + /* Make sure we know which tool we're using */ + if (toolname) { + VG_(debugLog)(1, "launcher", "tool '%s' requested\n", toolname); + } else { + VG_(debugLog)(1, "launcher", + "no tool requested, defaulting to 'memcheck'\n"); + toolname = "memcheck"; + } + + /* Select a platform to use if we can't decide that by looking at + the executable (eg because it's a shell script). Note that the + default_platform is not necessarily either the primary or + secondary build target. Instead it's chosen to maximise the + chances that /bin/sh will work on it. Hence for a primary + target of ppc64-linux we still choose ppc32-linux as the default + target, because on most ppc64-linux setups, the basic /bin, + /usr/bin, etc, stuff is built in 32-bit mode, not 64-bit + mode. */ + if (0==strcmp(VG_PLATFORM,"x86-freebsd")) + default_platform = "x86-freebsd"; + else if (0==strcmp(VG_PLATFORM,"amd64-freebsd")) + default_platform = "amd64-freebsd"; + else + barf("Unknown VG_PLATFORM '%s'", VG_PLATFORM); + + /* Work out what platform to use, or use the default platform if + not possible. */ + if (clientname == NULL) { + VG_(debugLog)(1, "launcher", + "no client specified, defaulting platform to '%s'\n", + default_platform); + platform = default_platform; + } else if ((platform = select_platform(clientname)) != NULL) { + VG_(debugLog)(1, "launcher", "selected platform '%s'\n", platform); + } else { + VG_(debugLog)(1, "launcher", + "no platform detected, defaulting platform to '%s'\n", + default_platform); + platform = default_platform; + } + + /* Figure out the name of this executable (viz, the launcher), so + we can tell stage2. stage2 will use the name for recursive + invocations of valgrind on child processes. */ + memset(launcher_name, 0, PATH_MAX+1); + +#if __FreeBSD__ >= 7 + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_PATHNAME; + oid[3] = getpid(); + len = PATH_MAX; + r = sysctl(oid, 4, launcher_name, &len, 0, 0); + if (r != 0) { + fprintf(stderr, "valgrind: warning (non-fatal): " + "sysctl(\"kern.proc.pathname\") failed.\n"); + fprintf(stderr, "valgrind: continuing, however --trace-children=yes " + "will not work.\n"); + } +#else + r = readlink("/proc/curproc/file", launcher_name, PATH_MAX); + if (r == -1) { + /* If /proc/self/exe can't be followed, don't give up. Instead + continue with an empty string for VALGRIND_LAUNCHER. In the + sys_execve wrapper, this is tested, and if found to be empty, + fail the execve. */ + fprintf(stderr, "valgrind: warning (non-fatal): " + "readlink(\"/proc/curproc/file\") failed.\n"); + fprintf(stderr, "valgrind: continuing, however --trace-children=yes " + "will not work.\n"); + } +#endif + + /* tediously augment the env: VALGRIND_LAUNCHER=launcher_name */ + new_line = malloc(strlen(VALGRIND_LAUNCHER) + 1 + + strlen(launcher_name) + 1); + if (new_line == NULL) + barf("malloc of new_line failed."); + strcpy(new_line, VALGRIND_LAUNCHER); + strcat(new_line, "="); + strcat(new_line, launcher_name); + + for (j = 0; envp[j]; j++) + ; + new_env = malloc((j+2) * sizeof(char*)); + if (new_env == NULL) + barf("malloc of new_env failed."); + for (i = 0; i < j; i++) + new_env[i] = envp[i]; + new_env[i++] = new_line; + new_env[i++] = NULL; + assert(i == j+2); + + /* Establish the correct VALGRIND_LIB. */ + cp = getenv(VALGRIND_LIB); + + if (cp != NULL) + valgrind_lib = cp; + + /* Build the stage2 invocation, and execve it. Bye! */ + toolfile = malloc(strlen(valgrind_lib) + strlen(toolname) + strlen(platform) + 3); + if (toolfile == NULL) + barf("malloc of toolfile failed."); + sprintf(toolfile, "%s/%s-%s", valgrind_lib, toolname, platform); + + VG_(debugLog)(1, "launcher", "launching %s\n", toolfile); + + execve(toolfile, argv, new_env); + + fprintf(stderr, "valgrind: failed to start tool '%s' for platform '%s': %s\n", + toolname, platform, strerror(errno)); + + exit(1); +} diff --git a/coregrind/link_tool_exe_freebsd.in b/coregrind/link_tool_exe_freebsd.in new file mode 100755 index 000000000..bd77d90b5 --- /dev/null +++ b/coregrind/link_tool_exe_freebsd.in @@ -0,0 +1,88 @@ +#! @PERL@ + +# This script handles linking the tool executables on FreeBSD, +# statically and at an alternative load address. +# +# Linking statically sidesteps all sorts of complications to do with +# having two copies of the dynamic linker (valgrind's and the +# client's) coexisting in the same process. The alternative load +# address is needed because Valgrind itself will load the client at +# whatever address it specifies, which is almost invariably the +# default load address. Hence we can't allow Valgrind itself (viz, +# the tool executable) to be loaded at that address. +# +# Unfortunately there's no standard way to do 'static link at +# alternative address', so these link_tool_exe_*.in scripts handle +# the per-platform hoop-jumping. +# +# What we get passed here is: +# first arg +# the alternative load address +# all the rest of the args +# the gcc invokation to do the final link, that +# the build system would have done, left to itself +# +# We just let the script 'die' if something is wrong, rather than do +# proper error reporting. We don't expect the users to run this +# directly. It is only run as part of the build process, with +# carefully constrained inputs. +# +# Linux specific complications: +# +# - need to support both old GNU ld and gold: use -Ttext= to +# set the text segment address. +# +# - need to pass --build-id=none (that is, -Wl,--build-id=none to +# gcc) if it accepts it, to ensure the linker doesn't add a +# notes section which ends up at the default load address and +# so defeats our attempts to keep that address clear for the +# client. However, older linkers don't support this flag, so it +# is tested for by configure.in and is shipped to us as part of +# argv[2 ..]. +# +# +# So: what we actually do: +# +# pass the specified command to the linker as-is, except, add +# "-static" and "-Ttext=" to it. +# + +use warnings; +use strict; + +# expect at least: alt-load-address gcc -o foo bar.o +die "Not enough arguments" + if (($#ARGV + 1) < 5); + +my $ala = $ARGV[0]; + +# check for plausible-ish alt load address +die "Bogus alt-load address" + if (length($ala) < 3 || index($ala, "0x") != 0); + +# The cc invokation to do the final link +my $cc = $ARGV[1]; + +# and the 'restargs' are argv[2 ..] + +# so, build up the complete command here: +# 'cc' -static -Ttext='ala' 'restargs' + +my $cmd="$cc -static -Wl,-Ttext=$ala"; + +# Add the rest of the parameters +foreach my $n (2 .. $#ARGV) { + $cmd = "$cmd $ARGV[$n]"; +} + +#print "link_tool_exe_linux: $cmd\n"; + + +# Execute the command: +my $r = system("$cmd"); + +if ($r == 0) { + exit 0; +} else { + exit 1; +} diff --git a/coregrind/m_aspacemgr/aspacemgr-common.c b/coregrind/m_aspacemgr/aspacemgr-common.c index 95c8dd3db..2fdfddd4e 100644 --- a/coregrind/m_aspacemgr/aspacemgr-common.c +++ b/coregrind/m_aspacemgr/aspacemgr-common.c @@ -173,6 +173,16 @@ SysRes VG_(am_do_mmap_NO_NOTIFY)( Addr start, SizeT length, UInt prot, } res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, prot, flags, (UInt)fd, offset); +# elif defined(VGP_x86_freebsd) + if (flags & VKI_MAP_ANONYMOUS && fd == 0) + fd = -1; + res = VG_(do_syscall7)(__NR_mmap, (UWord)start, length, + prot, flags, fd, offset, offset >> 32ul); +# elif defined(VGP_amd64_freebsd) + if (flags & VKI_MAP_ANONYMOUS && fd == 0) + fd = -1; + res = VG_(do_syscall6)(__NR_mmap, (UWord)start, length, + prot, flags, fd, offset); # elif defined(VGP_x86_solaris) /* MAP_ANON with fd==0 is EINVAL. */ if (fd == 0 && (flags & VKI_MAP_ANONYMOUS)) @@ -221,6 +231,11 @@ SysRes ML_(am_do_extend_mapping_NO_NOTIFY)( 0/*flags, meaning: must be at old_addr, else FAIL */, 0/*new_addr, is ignored*/ ); +# elif defined(VGO_freebsd) +#warning Not implemented + ML_(am_barf)("ML_(am_do_extend_mapping_NO_NOTIFY) on FreeBSD"); + /* NOTREACHED, but gcc doesn't understand that */ + return VG_(mk_SysRes_Error)(0); # else # error Unknown OS # endif @@ -242,6 +257,10 @@ SysRes ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY)( VKI_MREMAP_MAYMOVE|VKI_MREMAP_FIXED/*move-or-fail*/, new_addr ); +# elif defined(VGO_freebsd) + ML_(am_barf)("ML_(am_do_relocate_nooverlap_mapping_NO_NOTIFY) on FreeBSD"); + /* NOTREACHED, but gcc doesn't understand that */ + return VG_(mk_SysRes_Error)(0); # else # error Unknown OS # endif @@ -257,7 +276,7 @@ SysRes ML_(am_open) ( const HChar* pathname, Int flags, Int mode ) /* ARM64 wants to use __NR_openat rather than __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, @@ -285,7 +304,7 @@ Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz) # if defined(VGP_arm64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -298,7 +317,7 @@ Int ML_(am_readlink)(const HChar* path, HChar* buf, UInt bufsiz) Int ML_(am_fcntl) ( Int fd, Int cmd, Addr arg ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) 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); @@ -314,7 +333,7 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, /*OUT*/ULong* dev, /*OUT*/ULong* ino, /*OUT*/UInt* mode ) { -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res; struct vki_stat buf; # if defined(VGO_linux) && defined(__NR_fstat64) @@ -360,6 +379,11 @@ Bool ML_(am_get_fd_d_i_m)( Int fd, # endif } +#if defined(VGO_freebsd) +#define M_FILEDESC_BUF 1000000 +static Char filedesc_buf[M_FILEDESC_BUF]; +#endif + Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf ) { #if defined(VGO_linux) @@ -372,6 +396,38 @@ Bool ML_(am_resolve_filename) ( Int fd, /*OUT*/HChar* buf, Int nbuf ) else return False; +#elif defined(VGO_freebsd) + Int mib[4]; + SysRes sres; + vki_size_t len; + Char *bp, *eb; + struct vki_kinfo_file *kf; + + mib[0] = VKI_CTL_KERN; + mib[1] = VKI_KERN_PROC; + mib[2] = VKI_KERN_PROC_FILEDESC; + mib[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(filedesc_buf); + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)mib, 4, (UWord)filedesc_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "sysctl(kern.proc.filedesc)", "%s\n", VG_(strerror)(sr_Err(sres))); + ML_(am_exit)(1); + } + /* Walk though the list. */ + bp = filedesc_buf; + eb = filedesc_buf + len; + while (bp < eb) { + kf = (struct vki_kinfo_file *)bp; + if (kf->kf_fd == fd) + break; + bp += kf->kf_structsize; + } + if (bp >= eb || *kf->kf_path == '\0') + VG_(strncpy)( buf, "[unknown]", nbuf ); + else + VG_(strncpy)( buf, kf->kf_path, nbuf ); + return True; #elif defined(VGO_darwin) HChar tmp[VKI_MAXPATHLEN+1]; if (0 == ML_(am_fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) { diff --git a/coregrind/m_aspacemgr/aspacemgr-linux.c b/coregrind/m_aspacemgr/aspacemgr-linux.c index afc041dbe..b97e023ee 100644 --- a/coregrind/m_aspacemgr/aspacemgr-linux.c +++ b/coregrind/m_aspacemgr/aspacemgr-linux.c @@ -4,7 +4,7 @@ /*--- The address space manager: segment initialisation and ---*/ /*--- tracking, stack operations ---*/ /*--- ---*/ -/*--- Implementation for Linux (and Darwin!) aspacemgr-linux.c ---*/ +/*--- Implementation for Linux, FreeBSD and Darwin ---*/ /*--------------------------------------------------------------------*/ /* @@ -32,7 +32,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* ************************************************************* DO NOT INCLUDE ANY OTHER FILES HERE. @@ -317,6 +317,7 @@ Addr VG_(clo_aspacem_minAddr) #elif defined(VGO_solaris) = (Addr) 0x00100000; // 1MB #else + = (Addr) 0x04000000; // 64M #endif @@ -872,7 +873,7 @@ static void sync_check_mapping_callback ( Addr addr, SizeT len, UInt prot, cmp_devino = False; #endif -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) // GrP fixme kernel info doesn't have dev/inode cmp_devino = False; @@ -1638,7 +1639,34 @@ Addr VG_(am_startup) ( Addr sp_at_startup ) suggested_clstack_end = -1; // ignored; Mach-O specifies its stack + // --- Freebsd ------------------------------------------ + +#elif defined(VGO_freebsd) + +# if VG_WORDSIZE == 4 + aspacem_maxAddr = VG_PGROUNDDN( sp_at_startup ) - 1; +# else + aspacem_maxAddr = (Addr) (Addr)0x800000000 - 1; // 32G +# ifdef ENABLE_INNER + { Addr cse = VG_PGROUNDDN( sp_at_startup ) - 1; + if (aspacem_maxAddr > cse) + aspacem_maxAddr = cse; + } +# endif +# endif + + aspacem_cStart = aspacem_minAddr; + aspacem_vStart = VG_PGROUNDUP((aspacem_minAddr + aspacem_maxAddr + 1) / 2); + +# ifdef ENABLE_INNER + aspacem_vStart -= 0x10000000; // 256M +# endif + + suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL + + VKI_PAGE_SIZE; + // --- Solaris ------------------------------------------ + #elif defined(VGO_solaris) # if VG_WORDSIZE == 4 /* @@ -1760,7 +1788,7 @@ Addr VG_(am_startup) ( Addr sp_at_startup ) suggested_clstack_end = aspacem_maxAddr - 16*1024*1024ULL + VKI_PAGE_SIZE; -#endif +#endif /* #else of 'defined(VGO_solaris)' */ // --- (end) -------------------------------------------- aspacem_assert(VG_IS_PAGE_ALIGNED(aspacem_minAddr)); @@ -3797,13 +3825,91 @@ Bool VG_(get_changed_segments)( return !css_overflowed; } -#endif // defined(VGO_darwin) - /*------END-procmaps-parser-for-Darwin---------------------------*/ +/*------BEGIN-procmaps-parser-for-Freebsd------------------------*/ + +#elif defined(VGO_freebsd) + + /* Size of a smallish table used to read /proc/self/map entries. */ + #define M_PROCMAP_BUF 10485760 /* 10M */ + + /* static ... to keep it out of the stack frame. */ + static char procmap_buf[M_PROCMAP_BUF]; + +static void parse_procselfmaps ( + void (*record_mapping)( Addr addr, SizeT len, UInt prot, + ULong dev, ULong ino, Off64T offset, + const HChar* filename ), + void (*record_gap)( Addr addr, SizeT len ) + ) +{ + Int i; + Addr start, endPlusOne, gapStart; + char* filename; + char *p; + UInt prot; + ULong foffset, dev, ino; + struct vki_kinfo_vmentry *kve; + vki_size_t len; + Int oid[4]; + SysRes sres; + + foffset = ino = 0; /* keep gcc-4.1.0 happy */ + + oid[0] = VKI_CTL_KERN; + oid[1] = VKI_KERN_PROC; + oid[2] = VKI_KERN_PROC_VMMAP; + oid[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(procmap_buf); + + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)oid, 4, (UWord)procmap_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "procselfmaps", "sysctll %ld\n", sr_Err(sres)); + ML_(am_exit)(1); + } + gapStart = Addr_MIN; + i = 0; + p = procmap_buf; + while (p < (char *)procmap_buf + len) { + kve = (struct vki_kinfo_vmentry *)p; + start = (UWord)kve->kve_start; + endPlusOne = (UWord)kve->kve_end; + foffset = kve->kve_offset; + filename = kve->kve_path; + dev = kve->kve_fsid; + ino = kve->kve_fileid; + if (filename[0] != '/') { + filename = NULL; + foffset = 0; + } + + prot = 0; + if (kve->kve_protection & VKI_KVME_PROT_READ) prot |= VKI_PROT_READ; + if (kve->kve_protection & VKI_KVME_PROT_WRITE) prot |= VKI_PROT_WRITE; + if (kve->kve_protection & VKI_KVME_PROT_EXEC) prot |= VKI_PROT_EXEC; + + if (record_gap && gapStart < start) + (*record_gap) ( gapStart, start-gapStart ); + + if (record_mapping && start < endPlusOne) + (*record_mapping) ( start, endPlusOne-start, + prot, dev, ino, + foffset, filename ); + gapStart = endPlusOne; + p += kve->kve_structsize; + } + + if (record_gap && gapStart < Addr_MAX) + (*record_gap) ( gapStart, Addr_MAX - gapStart + 1 ); +} + +/*------END-procmaps-parser-for-Freebsd--------------------------*/ + /*------BEGIN-procmaps-parser-for-Solaris------------------------*/ -#if defined(VGO_solaris) +#elif defined(VGO_solaris) /* Note: /proc/self/xmap contains extended information about already materialized mappings whereas /proc/self/rmap contains information about @@ -4113,7 +4219,7 @@ Bool VG_(am_search_for_new_segment)(Addr *addr, SizeT *size, UInt *prot) /*------END-procmaps-parser-for-Solaris--------------------------*/ -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_coredump/coredump-elf.c b/coregrind/m_coredump/coredump-elf.c index 2d36b26b4..62e558021 100644 --- a/coregrind/m_coredump/coredump-elf.c +++ b/coregrind/m_coredump/coredump-elf.c @@ -28,7 +28,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -191,6 +191,19 @@ static void write_note(Int fd, const struct note *n) VG_(write)(fd, &n->note, note_size(n)); } +#if defined(VGO_freebsd) +static void fill_prpsinfo(const ThreadState *tst, + struct vki_elf_prpsinfo *prpsinfo) +{ + VG_(memset)(prpsinfo, 0, sizeof(*prpsinfo)); + + prpsinfo->pr_version = VKI_PRPSINFO_VERSION; + prpsinfo->pr_psinfosz = sizeof(struct vki_elf_prpsinfo); + + VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), False); + VG_(strncpy)(prpsinfo->pr_psargs, prpsinfo->pr_fname, sizeof(prpsinfo->pr_psargs) - 1); +} +#else static void fill_prpsinfo(const ThreadState *tst, struct vki_elf_prpsinfo *prpsinfo) { @@ -221,6 +234,7 @@ static void fill_prpsinfo(const ThreadState *tst, VG_(client_fname)(prpsinfo->pr_fname, sizeof(prpsinfo->pr_fname), False); } +#endif static void fill_prstatus(const ThreadState *tst, /*OUT*/struct vki_elf_prstatus *prs, @@ -235,6 +249,16 @@ static void fill_prstatus(const ThreadState *tst, VG_(memset)(prs, 0, sizeof(*prs)); +#if defined(VGO_freebsd) + prs->pr_version = VKI_PRSTATUS_VERSION; + prs->pr_statussz = sizeof(struct vki_elf_prstatus); + prs->pr_gregsetsz = sizeof(vki_elf_gregset_t); + prs->pr_fpregsetsz = sizeof(vki_elf_fpregset_t); + prs->pr_osreldate = VG_(getosreldate)(); + + prs->pr_cursig = si->si_signo; + prs->pr_pid = tst->os_state.lwpid; +#else prs->pr_info.si_signo = si->si_signo; prs->pr_info.si_code = si->si_code; prs->pr_info.si_errno = 0; @@ -245,6 +269,7 @@ static void fill_prstatus(const ThreadState *tst, prs->pr_ppid = 0; prs->pr_pgrp = VG_(getpgrp)(); prs->pr_sid = VG_(getpgrp)(); +#endif #if defined(VGP_s390x_linux) /* prs->pr_reg has struct type. Need to take address. */ @@ -416,6 +441,47 @@ static void fill_prstatus(const ThreadState *tst, regs[VKI_MIPS64_EF_HI] = arch->vex.guest_HI; regs[VKI_MIPS64_EF_CP0_STATUS] = arch->vex.guest_CP0_status; regs[VKI_MIPS64_EF_CP0_EPC] = arch->vex.guest_PC; + +#elif defined(VGP_amd64_freebsd) + regs->rflags = LibVEX_GuestAMD64_get_rflags( &((ThreadArchState*)arch)->vex ); + regs->rsp = arch->vex.guest_RSP; + regs->rip = arch->vex.guest_RIP; + regs->rbx = arch->vex.guest_RBX; + regs->rcx = arch->vex.guest_RCX; + regs->rdx = arch->vex.guest_RDX; + regs->rsi = arch->vex.guest_RSI; + regs->rdi = arch->vex.guest_RDI; + regs->rbp = arch->vex.guest_RBP; + regs->rax = arch->vex.guest_RAX; + regs->r8 = arch->vex.guest_R8; + regs->r9 = arch->vex.guest_R9; + regs->r10 = arch->vex.guest_R10; + regs->r11 = arch->vex.guest_R11; + regs->r12 = arch->vex.guest_R12; + regs->r13 = arch->vex.guest_R13; + regs->r14 = arch->vex.guest_R14; + regs->r15 = arch->vex.guest_R15; + +#elif defined(VGP_x86_freebsd) + regs->eflags = LibVEX_GuestX86_get_eflags( &arch->vex ); + regs->esp = arch->vex.guest_ESP; + regs->eip = arch->vex.guest_EIP; + + regs->ebx = arch->vex.guest_EBX; + regs->ecx = arch->vex.guest_ECX; + regs->edx = arch->vex.guest_EDX; + regs->esi = arch->vex.guest_ESI; + regs->edi = arch->vex.guest_EDI; + regs->ebp = arch->vex.guest_EBP; + regs->eax = arch->vex.guest_EAX; + + regs->cs = arch->vex.guest_CS; + regs->ds = arch->vex.guest_DS; + regs->ss = arch->vex.guest_SS; + regs->es = arch->vex.guest_ES; + regs->fs = arch->vex.guest_FS; + regs->gs = arch->vex.guest_GS; + #else # error Unknown ELF platform #endif @@ -507,6 +573,17 @@ static void fill_fpu(const ThreadState *tst, vki_elf_fpregset_t *fpu) DO(16); DO(17); DO(18); DO(19); DO(20); DO(21); DO(22); DO(23); DO(24); DO(25); DO(26); DO(27); DO(28); DO(29); DO(30); DO(31); # undef DO + +#elif defined(VGP_x86_freebsd) + +#elif defined(VGP_amd64_freebsd) + +# define DO(n) VG_(memcpy)(fpu->xmm_space + n * 4, \ + &arch->vex.guest_YMM##n[0], 16) + DO(0); DO(1); DO(2); DO(3); DO(4); DO(5); DO(6); DO(7); + DO(8); DO(9); DO(10); DO(11); DO(12); DO(13); DO(14); DO(15); +# undef DO + #else # error Unknown ELF platform #endif diff --git a/coregrind/m_debuginfo/d3basics.c b/coregrind/m_debuginfo/d3basics.c index 088fa075c..be48c4b13 100644 --- a/coregrind/m_debuginfo/d3basics.c +++ b/coregrind/m_debuginfo/d3basics.c @@ -401,11 +401,11 @@ static Bool get_Dwarf_Reg( /*OUT*/Addr* a, Word regno, const RegSummary* regs ) { vg_assert(regs); # if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) if (regno == 5/*EBP*/) { *a = regs->fp; return True; } if (regno == 4/*ESP*/) { *a = regs->sp; return True; } # elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) 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 1aa43146f..05501a21d 100644 --- a/coregrind/m_debuginfo/debuginfo.c +++ b/coregrind/m_debuginfo/debuginfo.c @@ -59,7 +59,7 @@ #include "priv_tytypes.h" #include "priv_storage.h" #include "priv_readdwarf.h" -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # include "priv_readelf.h" # include "priv_readdwarf3.h" # include "priv_readpdb.h" @@ -816,7 +816,7 @@ void VG_(di_initialise) ( void ) /*--- ---*/ /*--------------------------------------------------------------*/ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* Helper (indirect) for di_notify_ACHIEVE_ACCEPT_STATE */ static Bool overlaps_DebugInfoMappings ( const DebugInfoMapping* map1, @@ -967,7 +967,7 @@ static ULong di_notify_ACHIEVE_ACCEPT_STATE ( struct _DebugInfo* di ) truncate_DebugInfoMapping_overlaps( di, di->fsm.maps ); /* And acquire new info. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) ok = ML_(read_elf_debug_info)( di ); # elif defined(VGO_darwin) ok = ML_(read_macho_debug_info)( di ); @@ -1249,7 +1249,7 @@ ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ) vg_assert(sr_Res(preadres) > 0 && sr_Res(preadres) <= sizeof(buf1k) ); /* We're only interested in mappings of object files. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) if (!ML_(is_elf_object_file)( buf1k, (SizeT)sr_Res(preadres), False )) return 0; # elif defined(VGO_darwin) @@ -1698,7 +1698,7 @@ void VG_(di_notify_pdb_debuginfo)( Int fd_obj, Addr avma_obj, if (pdbname) ML_(dinfo_free)(pdbname); } -#endif /* defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) */ +#endif /* defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) */ /*------------------------------------------------------------*/ @@ -2292,6 +2292,8 @@ Vg_FnNameKind VG_(get_fnname_kind) ( const HChar* name ) # if defined(VGA_ppc32) || defined(VGA_ppc64be) || defined(VGA_ppc64le) VG_STREQ("generic_start_main.isra.0", name) || // ppc glibness # endif +# elif defined(VGO_freebsd) + VG_STREQ("_start", name) || // FreeBSD libc # elif defined(VGO_darwin) // See readmacho.c for an explanation of this. VG_STREQ("start_according_to_valgrind", name) || // Darwin, darling diff --git a/coregrind/m_debuginfo/priv_readpdb.h b/coregrind/m_debuginfo/priv_readpdb.h index 97407d99a..3cee87d1e 100644 --- a/coregrind/m_debuginfo/priv_readpdb.h +++ b/coregrind/m_debuginfo/priv_readpdb.h @@ -32,7 +32,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #ifndef __PRIV_READPDB_H #define __PRIV_READPDB_H @@ -59,7 +59,7 @@ HChar* ML_(find_name_of_pdb_file)( const HChar* pename ); #endif /* ndef __PRIV_READPDB_H */ -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 3b7449a5b..94f1487ee 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -29,7 +29,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_debuginfo.h" @@ -1688,11 +1688,11 @@ void ML_(read_debuginfo_dwarf1) ( /* --------------- Decls --------------- */ -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define FP_REG 5 # define SP_REG 4 # define RA_REG_DEFAULT 8 -#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define FP_REG 6 # define SP_REG 7 # define RA_REG_DEFAULT 16 @@ -4151,7 +4151,7 @@ void ML_(read_callframe_info_dwarf3) return; } -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readdwarf3.c b/coregrind/m_debuginfo/readdwarf3.c index e9a3816a5..067b8aa1a 100644 --- a/coregrind/m_debuginfo/readdwarf3.c +++ b/coregrind/m_debuginfo/readdwarf3.c @@ -35,7 +35,7 @@ without prior written permission. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* REFERENCE (without which this code will not make much sense): @@ -5303,7 +5303,7 @@ ML_(new_dwarf3_reader) ( TRACE_SYMTAB("\n"); #endif -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c index 95b97d6bf..6d858950f 100644 --- a/coregrind/m_debuginfo/readelf.c +++ b/coregrind/m_debuginfo/readelf.c @@ -29,7 +29,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -1554,7 +1554,7 @@ static HChar* readlink_path (const HChar *path) #if defined(VGP_arm64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -#elif defined(VGO_linux) || defined(VGO_darwin) +#elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); #elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -2393,7 +2393,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) || defined(VGP_arm_linux) || defined (VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ || defined(VGP_arm64_linux) \ - || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) + || defined(VGP_x86_solaris) || defined(VGP_amd64_solaris) \ + || defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) /* Accept .plt where mapped as rx (code) */ if (0 == VG_(strcmp)(name, ".plt")) { if (inrx && !di->plt_present) { @@ -3333,7 +3334,7 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di ) /* NOTREACHED */ } -#endif // defined(VGO_linux) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c index 5506dde2b..ccb206bcb 100644 --- a/coregrind/m_debuginfo/readpdb.c +++ b/coregrind/m_debuginfo/readpdb.c @@ -35,7 +35,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_debuginfo.h" @@ -2606,7 +2606,7 @@ HChar* ML_(find_name_of_pdb_file)( const HChar* pename ) return res; } -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_debuginfo/storage.c b/coregrind/m_debuginfo/storage.c index 9d6a3fd11..400144118 100644 --- a/coregrind/m_debuginfo/storage.c +++ b/coregrind/m_debuginfo/storage.c @@ -321,6 +321,11 @@ void ML_(addSym) ( struct _DebugInfo* di, DiSym* sym ) vg_assert(sym->pri_name != NULL); vg_assert(sym->sec_names == NULL); +#if defined(VGO_freebsd) + if (sym->size == 0) + sym->size = 1; +#endif + /* Ignore zero-sized syms. */ if (sym->size == 0) return; @@ -1469,7 +1474,7 @@ Bool preferName ( const DebugInfo* di, vlena = VG_(strlen)(a_name); vlenb = VG_(strlen)(b_name); -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # define VERSION_CHAR '@' # elif defined(VGO_darwin) # define VERSION_CHAR '$' diff --git a/coregrind/m_debuglog.c b/coregrind/m_debuglog.c index 456a71129..3d86cbd93 100644 --- a/coregrind/m_debuglog.c +++ b/coregrind/m_debuglog.c @@ -437,6 +437,81 @@ static UInt local_sys_getpid ( void ) return (UInt)(__res); } +#elif defined(VGP_x86_freebsd) +static UInt local_sys_write_stderr ( HChar* buf, Int n ) +{ + Int result; + + __asm__ volatile ( + "pushl %%ebx\n" + "movl $"VG_STRINGIFY(__NR_write)", %%eax\n" /* %eax = __NR_write */ + "movl $2, %%ebx\n" /* %ebx = stderr */ + "int $0x80\n" /* write(stderr, buf, n) */ + "popl %%ebx\n" + : /*wr*/ "=a" (result) + : /*rd*/ "c" (buf), "d" (n) + : /*trash*/ "edi", "memory", "cc" + ); + + return result >= 0 ? result : -1; +} + +static UInt local_sys_getpid ( void ) +{ + UInt __res; + __asm__ volatile ( + "movl $20, %%eax\n" /* set %eax = __NR_getpid */ + "int $0x80\n" /* getpid() */ + "movl %%eax, %0\n" /* set __res = eax */ + : "=mr" (__res) + : + : "eax" ); + return __res; +} + +#elif defined(VGP_amd64_freebsd) +__attribute__((noinline)) +static UInt local_sys_write_stderr ( HChar* buf, Int n ) +{ + volatile Long block[2]; + block[0] = (Long)buf; + block[1] = n; + __asm__ volatile ( + "subq $256, %%rsp\n" /* don't trash the stack redzone */ + "pushq %%r15\n" /* r15 is callee-save */ + "movq %0, %%r15\n" /* r15 = &block */ + "pushq %%r15\n" /* save &block */ + "movq $"VG_STRINGIFY(__NR_write)", %%rax\n" /* rax = __NR_write */ + "movq $2, %%rdi\n" /* rdi = stderr */ + "movq 0(%%r15), %%rsi\n" /* rsi = buf */ + "movq 8(%%r15), %%rdx\n" /* rdx = n */ + "syscall\n" /* write(stderr, buf, n) */ + "popq %%r15\n" /* reestablish &block */ + "movq %%rax, 0(%%r15)\n" /* block[0] = result */ + "popq %%r15\n" /* restore r15 */ + "addq $256, %%rsp\n" /* restore stack ptr */ + : /*wr*/ + : /*rd*/ "g" (block) + : /*trash*/ "rax", "rdi", "rsi", "rdx", "memory", "cc" + ); + if (block[0] < 0) + block[0] = -1; + return (UInt)block[0]; +} + +static UInt local_sys_getpid ( void ) +{ + UInt __res; + __asm__ volatile ( + "movq $20, %%rax\n" /* set %rax = __NR_getpid */ + "syscall\n" /* getpid() */ + "movl %%eax, %0\n" /* set __res = %eax */ + : "=mr" (__res) + : + : "rax" ); + return __res; +} + #elif defined(VGP_mips32_linux) || defined(VGP_mips64_linux) static UInt local_sys_write_stderr ( const HChar* buf, Int n ) diff --git a/coregrind/m_dispatch/dispatch-amd64-freebsd.S b/coregrind/m_dispatch/dispatch-amd64-freebsd.S new file mode 100755 index 000000000..99477154d --- /dev/null +++ b/coregrind/m_dispatch/dispatch-amd64-freebsd.S @@ -0,0 +1,259 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core dispatch loop, for jumping to a code address. ---*/ +/*--- dispatch-amd64-linux.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2012 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics_asm.h" +#include "pub_core_dispatch_asm.h" +#include "pub_core_transtab_asm.h" +#include "libvex_guest_offsets.h" /* for OFFSET_amd64_RIP */ + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- The dispatch loop. VG_(disp_run_translations) is ---*/ +/*--- used to run all translations, ---*/ +/*--- including no-redir ones. ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/*----------------------------------------------------*/ +/*--- Entry and preamble (set everything up) ---*/ +/*----------------------------------------------------*/ + +/* signature: +void VG_(disp_run_translations)( UWord* two_words, + void* guest_state, + Addr host_addr ); +*/ +.text +.globl VG_(disp_run_translations) +.type VG_(disp_run_translations), @function +VG_(disp_run_translations): + /* %rdi holds two_words */ + /* %rsi holds guest_state */ + /* %rdx holds host_addr */ + + /* The preamble */ + + /* Save integer registers, since this is a pseudo-function. */ + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + /* %rdi must be saved last */ + pushq %rdi + + /* Get the host CPU in the state expected by generated code. */ + + /* set host FPU control word to the default mode expected + by VEX-generated code. See comments in libvex.h for + more info. */ + finit + pushq $0x027F + fldcw (%rsp) + addq $8, %rsp + + /* set host SSE control word to the default mode expected + by VEX-generated code. */ + pushq $0x1F80 + ldmxcsr (%rsp) + addq $8, %rsp + + /* set dir flag to known value */ + cld + + /* Set up the guest state pointer */ + movq %rsi, %rbp + + /* and jump into the code cache. Chained translations in + the code cache run, until for whatever reason, they can't + continue. When that happens, the translation in question + will jump (or call) to one of the continuation points + VG_(cp_...) below. */ + jmpq *%rdx + /*NOTREACHED*/ + +/*----------------------------------------------------*/ +/*--- Postamble and exit. ---*/ +/*----------------------------------------------------*/ + +postamble: + /* At this point, %rax and %rdx contain two + words to be returned to the caller. %rax + holds a TRC value, and %rdx optionally may + hold another word (for CHAIN_ME exits, the + address of the place to patch.) */ + + /* We're leaving. Check that nobody messed with %mxcsr + or %fpucw. We can't mess with %rax or %rdx here as they + hold the tentative return values, but any others are OK. */ +#if !defined(ENABLE_INNER) + /* This check fails for self-hosting, so skip in that case */ + pushq $0 + fstcw (%rsp) + cmpl $0x027F, (%rsp) + popq %r15 /* get rid of the word without trashing %rflags */ + jnz invariant_violation +#endif + pushq $0 + stmxcsr (%rsp) + andl $0xFFFFFFC0, (%rsp) /* mask out status flags */ + cmpl $0x1F80, (%rsp) + popq %r15 + jnz invariant_violation + /* otherwise we're OK */ + jmp remove_frame +invariant_violation: + movq $VG_TRC_INVARIANT_FAILED, %rax + movq $0, %rdx + +remove_frame: + /* Pop %rdi, stash return values */ + popq %rdi + movq %rax, 0(%rdi) + movq %rdx, 8(%rdi) + /* Now pop everything else */ + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax + ret + +/*----------------------------------------------------*/ +/*--- Continuation points ---*/ +/*----------------------------------------------------*/ + +/* ------ Chain me to slow entry point ------ */ +.global VG_(disp_cp_chain_me_to_slowEP) +VG_(disp_cp_chain_me_to_slowEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_S, RA) */ + movq $VG_TRC_CHAIN_ME_TO_SLOW_EP, %rax + popq %rdx + /* 10 = movabsq $VG_(disp_chain_me_to_slowEP), %r11; + 3 = call *%r11 */ + subq $10+3, %rdx + jmp postamble + +/* ------ Chain me to fast entry point ------ */ +.global VG_(disp_cp_chain_me_to_fastEP) +VG_(disp_cp_chain_me_to_fastEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA) */ + movq $VG_TRC_CHAIN_ME_TO_FAST_EP, %rax + popq %rdx + /* 10 = movabsq $VG_(disp_chain_me_to_fastEP), %r11; + 3 = call *%r11 */ + subq $10+3, %rdx + jmp postamble + +/* ------ Indirect but boring jump ------ */ +.global VG_(disp_cp_xindir) +VG_(disp_cp_xindir): + /* Where are we going? */ + movq OFFSET_amd64_RIP(%rbp), %rax + + /* stats only */ + addl $1, VG_(stats__n_xindirs_32) + + /* try a fast lookup in the translation cache */ + movabsq $VG_(tt_fast), %rcx + movq %rax, %rbx /* next guest addr */ + andq $VG_TT_FAST_MASK, %rbx /* entry# */ + shlq $4, %rbx /* entry# * sizeof(FastCacheEntry) */ + movq 0(%rcx,%rbx,1), %r10 /* .guest */ + movq 8(%rcx,%rbx,1), %r11 /* .host */ + cmpq %rax, %r10 + jnz fast_lookup_failed + + /* Found a match. Jump to .host. */ + jmp *%r11 + ud2 /* persuade insn decoders not to speculate past here */ + +fast_lookup_failed: + /* stats only */ + addl $1, VG_(stats__n_xindir_misses_32) + + movq $VG_TRC_INNER_FASTMISS, %rax + movq $0, %rdx + jmp postamble + +/* ------ Assisted jump ------ */ +.global VG_(disp_cp_xassisted) +VG_(disp_cp_xassisted): + /* %rbp contains the TRC */ + movq %rbp, %rax + movq $0, %rdx + jmp postamble + +/* ------ Event check failed ------ */ +.global VG_(disp_cp_evcheck_fail) +VG_(disp_cp_evcheck_fail): + movq $VG_TRC_INNER_COUNTERZERO, %rax + movq $0, %rdx + jmp postamble + + +.size VG_(disp_run_translations), .-VG_(disp_run_translations) + +/* Let the linker know we don't need an executable stack */ +.section .note.GNU-stack,"",@progbits + +#endif // defined(VGP_amd64_linux) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_dispatch/dispatch-x86-freebsd.S b/coregrind/m_dispatch/dispatch-x86-freebsd.S new file mode 100755 index 000000000..5dbcb3365 --- /dev/null +++ b/coregrind/m_dispatch/dispatch-x86-freebsd.S @@ -0,0 +1,250 @@ + +/*--------------------------------------------------------------------*/ +/*--- The core dispatch loop, for jumping to a code address. ---*/ +/*--- dispatch-x86-linux.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2012 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_x86_freebsd) + +#include "pub_core_basics_asm.h" +#include "pub_core_dispatch_asm.h" +#include "pub_core_transtab_asm.h" +#include "libvex_guest_offsets.h" /* for OFFSET_x86_EIP */ + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- The dispatch loop. VG_(disp_run_translations) is ---*/ +/*--- used to run all translations, ---*/ +/*--- including no-redir ones. ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/*----------------------------------------------------*/ +/*--- Entry and preamble (set everything up) ---*/ +/*----------------------------------------------------*/ + +/* signature: +void VG_(disp_run_translations)( UWord* two_words, + void* guest_state, + Addr host_addr ); +*/ +.text +.globl VG_(disp_run_translations) +.type VG_(disp_run_translations), @function +VG_(disp_run_translations): + /* 0(%esp) holds our return address. */ + /* 4(%esp) holds two_words */ + /* 8(%esp) holds guest_state */ + /* 12(%esp) holds host_addr */ + + /* The preamble */ + + /* Save integer registers, since this is a pseudo-function. */ + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushl %esi + pushl %edi + pushl %ebp + + /* 28+4(%esp) holds two_words */ + /* 28+8(%esp) holds guest_state */ + /* 28+12(%esp) holds host_addr */ + + /* Get the host CPU in the state expected by generated code. */ + + /* set host FPU control word to the default mode expected + by VEX-generated code. See comments in libvex.h for + more info. */ + finit + pushl $0x027F + fldcw (%esp) + addl $4, %esp + + /* set host SSE control word to the default mode expected + by VEX-generated code. */ + cmpl $0, VG_(machine_x86_have_mxcsr) + jz L1 + pushl $0x1F80 + ldmxcsr (%esp) + addl $4, %esp +L1: + /* set dir flag to known value */ + cld + + /* Set up the guest state pointer */ + movl 28+8(%esp), %ebp + + /* and jump into the code cache. Chained translations in + the code cache run, until for whatever reason, they can't + continue. When that happens, the translation in question + will jump (or call) to one of the continuation points + VG_(cp_...) below. */ + jmpl *28+12(%esp) + /*NOTREACHED*/ + +/*----------------------------------------------------*/ +/*--- Postamble and exit. ---*/ +/*----------------------------------------------------*/ + +postamble: + /* At this point, %eax and %edx contain two + words to be returned to the caller. %eax + holds a TRC value, and %edx optionally may + hold another word (for CHAIN_ME exits, the + address of the place to patch.) */ + + /* We're leaving. Check that nobody messed with %mxcsr + or %fpucw. We can't mess with %eax or %edx here as they + holds the tentative return value, but any others are OK. */ +#if !defined(ENABLE_INNER) + /* This check fails for self-hosting, so skip in that case */ + pushl $0 + fstcw (%esp) + cmpl $0x027F, (%esp) + popl %esi /* get rid of the word without trashing %eflags */ + jnz invariant_violation +#endif +# cmpl $0, VG_(machine_x86_have_mxcsr) + jz L2 + pushl $0 + stmxcsr (%esp) + andl $0xFFFFFFC0, (%esp) /* mask out status flags */ + cmpl $0x1F80, (%esp) + popl %esi + jnz invariant_violation +L2: /* otherwise we're OK */ + jmp remove_frame +invariant_violation: + movl $VG_TRC_INVARIANT_FAILED, %eax + movl $0, %edx + +remove_frame: + /* Stash return values */ + movl 28+4(%esp), %edi /* two_words */ + movl %eax, 0(%edi) + movl %edx, 4(%edi) + /* Restore int regs and return. */ + popl %ebp + popl %edi + popl %esi + popl %edx + popl %ecx + popl %ebx + popl %eax + ret + +/*----------------------------------------------------*/ +/*--- Continuation points ---*/ +/*----------------------------------------------------*/ + +/* ------ Chain me to slow entry point ------ */ +.global VG_(disp_cp_chain_me_to_slowEP) +VG_(disp_cp_chain_me_to_slowEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_S, RA) */ + movl $VG_TRC_CHAIN_ME_TO_SLOW_EP, %eax + popl %edx + /* 5 = movl $VG_(disp_chain_me_to_slowEP), %edx; + 2 = call *%edx */ + subl $5+2, %edx + jmp postamble + +/* ------ Chain me to fast entry point ------ */ +.global VG_(disp_cp_chain_me_to_fastEP) +VG_(disp_cp_chain_me_to_fastEP): + /* We got called. The return address indicates + where the patching needs to happen. Collect + the return address and, exit back to C land, + handing the caller the pair (Chain_me_F, RA) */ + movl $VG_TRC_CHAIN_ME_TO_FAST_EP, %eax + popl %edx + /* 5 = movl $VG_(disp_chain_me_to_fastEP), %edx; + 2 = call *%edx */ + subl $5+2, %edx + jmp postamble + +/* ------ Indirect but boring jump ------ */ +.global VG_(disp_cp_xindir) +VG_(disp_cp_xindir): + /* Where are we going? */ + movl OFFSET_x86_EIP(%ebp), %eax + + /* stats only */ + addl $1, VG_(stats__n_xindirs_32) + + /* try a fast lookup in the translation cache */ + movl %eax, %ebx /* next guest addr */ + andl $VG_TT_FAST_MASK, %ebx /* entry# */ + movl 0+VG_(tt_fast)(,%ebx,8), %esi /* .guest */ + movl 4+VG_(tt_fast)(,%ebx,8), %edi /* .host */ + cmpl %eax, %esi + jnz fast_lookup_failed + + /* Found a match. Jump to .host. */ + jmp *%edi + ud2 /* persuade insn decoders not to speculate past here */ + +fast_lookup_failed: + /* stats only */ + addl $1, VG_(stats__n_xindir_misses_32) + + movl $VG_TRC_INNER_FASTMISS, %eax + movl $0, %edx + jmp postamble + +/* ------ Assisted jump ------ */ +.global VG_(disp_cp_xassisted) +VG_(disp_cp_xassisted): + /* %ebp contains the TRC */ + movl %ebp, %eax + movl $0, %edx + jmp postamble + +/* ------ Event check failed ------ */ +.global VG_(disp_cp_evcheck_fail) +VG_(disp_cp_evcheck_fail): + movl $VG_TRC_INNER_COUNTERZERO, %eax + movl $0, %edx + jmp postamble + + +.size VG_(disp_run_translations), .-VG_(disp_run_translations) + +/* Let the linker know we don't need an executable stack */ +.section .note.GNU-stack,"",@progbits + +#endif // defined(VGP_x86_linux) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_initimg/initimg-freebsd.c b/coregrind/m_initimg/initimg-freebsd.c new file mode 100755 index 000000000..3ac4dfdfc --- /dev/null +++ b/coregrind/m_initimg/initimg-freebsd.c @@ -0,0 +1,896 @@ + +/*--------------------------------------------------------------------*/ +/*--- Startup: create initial process image on Linux ---*/ +/*--- initimg-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGO_freebsd) + +#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_syscall.h" +#include "pub_core_tooliface.h" /* VG_TRACK */ +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" /* ThreadArchState */ +#include "priv_initimg_pathscan.h" +#include "pub_core_initimg.h" /* self */ + +/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ +#define _GNU_SOURCE +#define _FILE_OFFSET_BITS 64 +/* This is for ELF types etc, and also the AT_ constants. */ +#include +/* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ + + +/*====================================================================*/ +/*=== Loading the client ===*/ +/*====================================================================*/ + +/* Load the client whose name is VG_(argv_the_exename). */ + +static void load_client ( /*OUT*/ExeInfo* info, + /*OUT*/Addr* client_ip, + /*OUT*/Addr* client_toc) +{ + const 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); + if (ret < 0) { + VG_(printf)("valgrind: could not execute '%s'\n", exe_name); + VG_(exit)(1); + } + + // 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; + *client_toc = info->init_toc; + VG_(brk_base) = VG_(brk_limit) = VG_PGROUNDUP(info->brkbase); +} + + +/*====================================================================*/ +/*=== Setting up the client's environment ===*/ +/*====================================================================*/ + +/* Prepare the client's environment. This is basically a copy of our + environment, except: + + LD_PRELOAD=$VALGRIND_LIB/vgpreload_core-PLATFORM.so: + ($VALGRIND_LIB/vgpreload_TOOL-PLATFORM.so:)? + $LD_PRELOAD + + If this is missing, then it is added. + + Also, remove any binding for VALGRIND_LAUNCHER=. The client should + not be able to see this. + + If this needs to handle any more variables it should be hacked + into something table driven. The copy is VG_(malloc)'d space. +*/ +static HChar** setup_client_env ( HChar** origenv, const HChar* toolname) +{ + const HChar* preload_core = "vgpreload_core"; + const HChar* ld_preload = "LD_PRELOAD="; + const HChar* v_launcher = VALGRIND_LAUNCHER "="; + Int ld_preload_len = VG_(strlen)( ld_preload ); + Int v_launcher_len = VG_(strlen)( v_launcher ); + Bool ld_preload_done = False; +#if defined(VGP_x86_freebsd) + HChar* ld_32_preload = "LD_32_PRELOAD="; + Int ld_32_preload_len = VG_(strlen)( ld_32_preload ); + Bool ld_32_preload_done = False; +#endif + 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_.so + paths. We might not need the space for vgpreload_.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-freebsd.sce.1", + preload_string_len); + vg_assert(origenv); + vg_assert(toolname); + vg_assert(preload_string); + + /* Determine if there's a vgpreload__.so file, and setup + preload_string. */ + preload_tool_path = VG_(malloc)("initimg-freebsd.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-freebsd.sce.3", + sizeof(HChar *) * (envc+2+1)); /* 2 new entry + NULL */ + vg_assert(ret); + + /* copy it over */ + for (cpp = ret; *origenv; ) + *cpp++ = *origenv++; + *cpp = NULL; + *(cpp + 1) = 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-freebsd.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; + } + } + + /* Add the missing bits */ + if (!ld_preload_done) { + Int len = ld_preload_len + preload_string_len; + HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5", len); + vg_assert(cp); + + VG_(snprintf)(cp, len, "%s%s", ld_preload, preload_string); + + ret[envc++] = cp; + } + +#if defined(VGP_x86_freebsd) + /* If we're running a 32 bit binary, ld-elf32.so.1 may be looking for + * a different variable name. Or it might be a 32 bit ld-elf.so.1 in a + * chroot. Cover both cases. */ + if (VG_(is32on64)()) { + for (cpp = ret; cpp && *cpp; cpp++) { + if (VG_(memcmp)(*cpp, ld_32_preload, ld_32_preload_len) == 0) { + Int len = VG_(strlen)(*cpp) + preload_string_len; + HChar *cp = VG_(malloc)("initimg-freebsd.sce.4a", len); + vg_assert(cp); + + VG_(snprintf)(cp, len, "%s%s:%s", + ld_32_preload, preload_string, (*cpp)+ld_32_preload_len); + + *cpp = cp; + + ld_32_preload_done = True; + } + } + if (!ld_32_preload_done) { + Int len = ld_32_preload_len + preload_string_len; + HChar *cp = VG_(malloc) ("initimg-freebsd.sce.5a", len); + vg_assert(cp); + + VG_(snprintf)(cp, len, "%s%s", ld_32_preload, preload_string); + + ret[envc++] = cp; + } + } +#endif + + /* ret[0 .. envc-1] is live now. */ + /* Find and remove a binding for VALGRIND_LAUNCHER. */ + for (i = 0; i < envc; i++) + if (0 == VG_(memcmp(ret[i], v_launcher, v_launcher_len))) + break; + + if (i < envc) { + for (; i < envc-1; i++) + ret[i] = ret[i+1]; + envc--; + } + + VG_(free)(preload_string); + ret[envc] = NULL; + + return ret; +} + + +/*====================================================================*/ +/*=== 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 is: + + higher address +-----------------+ <- clstack_end + | | + : string table : + | | + +-----------------+ + | AT_NULL | + - - + | auxv | + +-----------------+ + | NULL | + - - + | envp | + +-----------------+ + | NULL | + - - + | argv | + +-----------------+ + | argc | + lower address +-----------------+ <- sp + | undefined | + : : + + Allocate and create the initial client stack. It is allocated down + from clstack_end, which was previously determined by the address + space manager. The returned value is the SP value for the client. + + The client's auxv is created by copying and modifying our own one. + As a side effect of scanning our own auxv, some important bits of + info are collected: + + VG_(cache_line_size_ppc32) // ppc32 only -- cache line size + VG_(have_altivec_ppc32) // ppc32 only -- is Altivec supported? + + ---------------------------------------------------------------- */ + +struct auxv +{ + Word a_type; + union { + void *a_ptr; + Word a_val; + } u; +}; + +static +struct auxv *find_auxv(UWord* sp) +{ + sp++; // skip argc (Nb: is word-sized, not int-sized!) + + while (*sp != 0) // skip argv + sp++; + sp++; + + while (*sp != 0) // skip env + sp++; + sp++; + +#if defined(VGA_ppc32) || defined(VGA_ppc64) +# if defined AT_IGNOREPPC + while (*sp == AT_IGNOREPPC) // skip AT_IGNOREPPC entries + sp += 2; +# endif +#endif + + return (struct auxv *)sp; +} + +static +Addr setup_client_stack( void* init_sp, + char** orig_envp, + const ExeInfo* info, + UInt** client_auxv, + Addr clstack_end, + SizeT clstack_max_size ) +{ + SysRes res; + char **cpp; + char *strtab; /* string table */ + char *stringbase; + Addr *ptr; + struct auxv *auxv; + const struct auxv *orig_auxv; + const struct auxv *cauxv; + unsigned stringsize; /* total size of strings in bytes */ + unsigned auxsize; /* total size of auxv in bytes */ + Int argc; /* total argc */ + Int envc; /* total number of env vars */ + 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) ); + + /* use our own auxv as a prototype */ + orig_auxv = find_auxv(init_sp); + + /* ==================== compute sizes ==================== */ + + /* first of all, work out how big the client stack will be */ + stringsize = 0; + have_exename = VG_(args_the_exename) != NULL; + + /* paste on the extra args if the loader needs them (ie, the #! + interpreter and its argument) */ + argc = 0; + if (info->interp_name != NULL) { + argc++; + stringsize += 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; + } + + /* now, how big is the auxv? */ + auxsize = sizeof(*auxv); /* there's always at least one entry: AT_NULL */ + for (cauxv = orig_auxv; cauxv->a_type != AT_NULL; cauxv++) { + auxsize += sizeof(*cauxv); + } + + /* 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, 16); /* make stack 16 byte aligned */ + + /* base of the string table (aligned) */ + stringbase = strtab = (char *)clstack_end + - VG_ROUNDUP(stringsize, sizeof(int)); + + clstack_start = VG_PGROUNDDN(client_SP); + + /* The max stack size */ + clstack_max_size = VG_PGROUNDUP(clstack_max_size); + + /* Record stack extent -- needed for stack-change code. */ + VG_(clstk_start_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 ==================== */ + + { SizeT anon_size = clstack_end - clstack_start + 1; + SizeT resvn_size = clstack_max_size - anon_size; + Addr anon_start = clstack_start; + Addr resvn_start = anon_start - resvn_size; + SizeT inner_HACK = 0; + Bool ok; + + /* So far we've only accounted for space requirements down to the + stack pointer. If this target's ABI requires a redzone below + the stack pointer, we need to allocate an extra page, to + handle the worst case in which the stack pointer is almost at + the bottom of a page, and so there is insufficient room left + over to put the redzone in. In this case the simple thing to + do is allocate an extra page, by shrinking the reservation by + one page and growing the anonymous area by a corresponding + page. */ + vg_assert(VG_STACK_REDZONE_SZB >= 0); + vg_assert(VG_STACK_REDZONE_SZB < VKI_PAGE_SIZE); + if (VG_STACK_REDZONE_SZB > 0) { + vg_assert(resvn_size > VKI_PAGE_SIZE); + resvn_size -= VKI_PAGE_SIZE; + anon_start -= VKI_PAGE_SIZE; + anon_size += VKI_PAGE_SIZE; + } + + vg_assert(VG_IS_PAGE_ALIGNED(anon_size)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_size)); + vg_assert(VG_IS_PAGE_ALIGNED(anon_start)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_start)); + vg_assert(resvn_start == clstack_end + 1 - clstack_max_size); + +# ifdef ENABLE_INNER + inner_HACK = 1024*1024; // create 1M non-fault-extending stack +# endif + + if (0) + VG_(printf)("%#lx 0x%lx %#lx 0x%lx\n", + resvn_start, resvn_size, anon_start, anon_size); + + /* Create a shrinkable reservation followed by an anonymous + segment. Together these constitute a growdown stack. */ + res = VG_(mk_SysRes_Error)(0); + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size -inner_HACK, + SmUpper, + anon_size +inner_HACK + ); + if (ok) { + /* allocate a stack - mmap enough space for the stack */ + res = VG_(am_mmap_anon_fixed_client)( + anon_start -inner_HACK, + anon_size +inner_HACK, + VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC + ); + } + if ((!ok) || sr_isError(res)) { + /* Allocation of the stack failed. We have to stop. */ + VG_(printf)("valgrind: " + "I failed to allocate space for the application's stack.\n"); + VG_(printf)("valgrind: " + "This may be the result of a very large --main-stacksize=\n"); + VG_(printf)("valgrind: setting. Cannot continue. Sorry.\n\n"); + VG_(exit)(0); + } + + vg_assert(ok); + vg_assert(!sr_isError(res)); + } + + /* ==================== create client stack ==================== */ + + ptr = (Addr*)client_SP; + + /* --- client argc --- */ + *ptr++ = argc + (have_exename ? 1 : 0); + + /* --- client argv --- */ + if (info->interp_name) { + *ptr++ = (Addr)copy_str(&strtab, info->interp_name); + 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) = (HChar **)ptr; + for (cpp = orig_envp; cpp && *cpp; ptr++, cpp++) + *ptr = (Addr)copy_str(&strtab, *cpp); + *ptr++ = 0; + + /* --- auxv --- */ + auxv = (struct auxv *)ptr; + *client_auxv = (UInt *)auxv; + + for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) { + + /* copy the entry... */ + *auxv = *orig_auxv; + + /* ...and fix up / examine the copy */ + switch(auxv->a_type) { + + case AT_IGNORE: + case AT_PHENT: + case AT_PAGESZ: + case AT_FLAGS: + case AT_NOTELF: + case AT_UID: + case AT_EUID: + case AT_GID: + case AT_EGID: + /* All these are pointerless, so we don't need to do + anything about them. */ + break; + + case AT_PHDR: + if (info->phdr == 0) + auxv->a_type = AT_IGNORE; + else + auxv->u.a_val = info->phdr; + break; + + case AT_PHNUM: + if (info->phdr == 0) + auxv->a_type = AT_IGNORE; + else + auxv->u.a_val = info->phnum; + break; + + case AT_BASE: + auxv->u.a_val = info->interp_offset; + break; + + case AT_ENTRY: + auxv->u.a_val = info->entry; + break; + + default: + /* stomp out anything we don't know about */ + VG_(debugLog)(2, "initimg", + "stomping auxv entry %lld\n", + (ULong)auxv->a_type); + auxv->a_type = AT_IGNORE; + break; + } + } + *auxv = *orig_auxv; + vg_assert(auxv->a_type == AT_NULL); + + 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; +} + + +/* Allocate the client data segment. It is an expandable anonymous + mapping abutting a shrinkable reservation of size max_dseg_size. + The data segment starts at VG_(brk_base), which is page-aligned, + and runs up to VG_(brk_limit), which isn't. */ + +static void setup_client_dataseg ( SizeT max_size ) +{ + Bool ok; + SysRes sres; + Addr anon_start = VG_(brk_base); + SizeT anon_size = VKI_PAGE_SIZE; + Addr resvn_start = anon_start + anon_size; + SizeT resvn_size = max_size - anon_size; + + vg_assert(VG_IS_PAGE_ALIGNED(anon_size)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_size)); + vg_assert(VG_IS_PAGE_ALIGNED(anon_start)); + vg_assert(VG_IS_PAGE_ALIGNED(resvn_start)); + + /* Because there's been no brk activity yet: */ + vg_assert(VG_(brk_base) == VG_(brk_limit)); + + /* Try to create the data seg and associated reservation where + VG_(brk_base) says. */ + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size, + SmLower, + anon_size + ); + + if (!ok) { + /* Hmm, that didn't work. Well, let aspacem suggest an address + it likes better, and try again with that. */ + anon_start = VG_(am_get_advisory_client_simple) + ( 0/*floating*/, anon_size+resvn_size, &ok ); + if (ok) { + resvn_start = anon_start + anon_size; + ok = VG_(am_create_reservation)( + resvn_start, + resvn_size, + SmLower, + anon_size + ); + if (ok) + VG_(brk_base) = VG_(brk_limit) = anon_start; + } + /* that too might have failed, but if it has, we're hosed: there + is no Plan C. */ + } + vg_assert(ok); + + /* We make the data segment (heap) executable because LinuxThreads on + ppc32 creates trampolines in this area. Also, on x86/Linux the data + segment is RWX natively, at least according to /proc/self/maps. + Also, having a non-executable data seg would kill any program which + tried to create code in the data seg and then run it. */ + sres = VG_(am_mmap_anon_fixed_client)( + anon_start, + anon_size, + VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC + ); + vg_assert(!sr_isError(sres)); + vg_assert(sr_Res(sres) == anon_start); +} + + +/*====================================================================*/ +/*=== TOP-LEVEL: VG_(setup_client_initial_image) ===*/ +/*====================================================================*/ + +/* Create the client's initial memory image. */ +IIFinaliseImageInfo VG_(ii_create_image)( IICreateImageInfo iicii, + const VexArchInfo* vex_archinfo ) +{ + ExeInfo info; + HChar** env = NULL; + + 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, &iifii.initial_client_TOC); + + //-------------------------------------------------------------- + // 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'] + //-------------------------------------------------------------- + { + /* When allocating space for the client stack on Linux, take + notice of the --main-stacksize value. This makes it possible + to run programs with very large (primary) stack requirements + simply by specifying --main-stacksize. */ + /* Logic is as follows: + - by default, use the client's current stack rlimit + - if that exceeds 16M, clamp to 16M + - if a larger --main-stacksize value is specified, use that instead + - in all situations, the minimum allowed stack size is 1M + */ + void* init_sp = iicii.argv - 1; + SizeT m1 = 1024 * 1024; + SizeT m16 = 16 * m1; + SizeT szB = (SizeT)VG_(client_rlimit_stack).rlim_cur; + if (szB < m1) szB = m1; + if (szB > m16) szB = m16; + if (VG_(clo_main_stacksize) > 0) szB = VG_(clo_main_stacksize); + if (szB < m1) szB = m1; + szB = VG_PGROUNDUP(szB); + VG_(debugLog)(1, "initimg", + "Setup client stack: size will be %ld\n", szB); + + iifii.clstack_max_size = szB; + + iifii.initial_client_SP + = setup_client_stack( init_sp, env, + &info, &iifii.client_auxv, + iicii.clstack_end, iifii.clstack_max_size ); + + VG_(free)(env); + + VG_(debugLog)(2, "initimg", + "Client info: " + "initial_IP=%p initial_TOC=%p brk_base=%p\n", + (void*)(iifii.initial_client_IP), + (void*)(iifii.initial_client_TOC), + (void*)VG_(brk_base) ); + VG_(debugLog)(2, "initimg", + "Client info: " + "initial_SP=%p max_stack_size=%ld\n", + (void*)(iifii.initial_client_SP), + (SizeT)iifii.clstack_max_size ); + } + + //-------------------------------------------------------------- + // Setup client data (brk) segment. Initially a 1-page segment + // which abuts a shrinkable reservation. + // p: load_client() [for 'info' and hence VG_(brk_base)] + //-------------------------------------------------------------- + { + SizeT m1 = 1024 * 1024; + SizeT m8 = 8 * m1; + SizeT dseg_max_size = (SizeT)VG_(client_rlimit_data).rlim_cur; + VG_(debugLog)(1, "initimg", "Setup client data (brk) segment\n"); + if (dseg_max_size < m1) dseg_max_size = m1; + if (dseg_max_size > m8) dseg_max_size = m8; + dseg_max_size = VG_PGROUNDUP(dseg_max_size); + + setup_client_dataseg( dseg_max_size ); + } + + return iifii; +} + + +/*====================================================================*/ +/*=== TOP-LEVEL: VG_(finalise_thread1state) ===*/ +/*====================================================================*/ + +/* 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; + + /* On Linux we get client_{ip/sp/toc}, and start the client with + all other registers zeroed. */ + +# if defined(VGP_x86_freebsd) + 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; + + /* initialise %cs, %ds and %ss to point at the operating systems + default code, data and stack segments */ + asm volatile("movw %%cs, %0" : : "m" (arch->vex.guest_CS)); + asm volatile("movw %%ds, %0" : : "m" (arch->vex.guest_DS)); + asm volatile("movw %%ss, %0" : : "m" (arch->vex.guest_SS)); + +# elif defined(VGP_amd64_freebsd) + 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 - 8) & ~0xFul) + 8; + arch->vex.guest_RDI = 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)); +} + +#endif // defined(VGO_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_libcassert.c b/coregrind/m_libcassert.c index 3dba6771c..e77cc2bf5 100644 --- a/coregrind/m_libcassert.c +++ b/coregrind/m_libcassert.c @@ -51,7 +51,7 @@ ------------------------------------------------------------------ */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define GET_STARTREGS(srP) \ { UInt eip, esp, ebp; \ __asm__ __volatile__( \ @@ -68,7 +68,7 @@ (srP)->misc.X86.r_ebp = ebp; \ } #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define GET_STARTREGS(srP) \ { ULong rip, rsp, rbp; \ __asm__ __volatile__( \ @@ -272,7 +272,7 @@ void VG_(exit_now)( Int status ) { #if defined(VGO_linux) (void)VG_(do_syscall1)(__NR_exit_group, status ); -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) (void)VG_(do_syscall1)(__NR_exit, status ); #else # error Unknown OS diff --git a/coregrind/m_libcfile.c b/coregrind/m_libcfile.c index 1815874e9..d8b09836e 100644 --- a/coregrind/m_libcfile.c +++ b/coregrind/m_libcfile.c @@ -69,6 +69,11 @@ Int VG_(safe_fd)(Int oldfd) return newfd; } +#if defined(VGO_freebsd) +#define M_FILEDESC_BUF 1000000 +static Char filedesc_buf[M_FILEDESC_BUF]; +#endif + /* Given a file descriptor, attempt to deduce its filename. To do this, we use /proc/self/fd/. If this doesn't point to a file, or if it doesn't exist, we return False. @@ -115,6 +120,46 @@ Bool VG_(resolve_filename) ( Int fd, const HChar** result ) *result = NULL; return False; +#elif defined(VGO_freebsd) + Int mib[4]; + SysRes sres; + vki_size_t len; + Char *bp, *eb; + struct vki_kinfo_file *kf; + static HChar *buf = NULL; + static SizeT bufsiz = 0; + + if (buf == NULL) { // first time + bufsiz = 500; + buf = VG_(malloc)("resolve_filename", bufsiz); + } + + mib[0] = VKI_CTL_KERN; + mib[1] = VKI_KERN_PROC; + mib[2] = VKI_KERN_PROC_FILEDESC; + mib[3] = sr_Res(VG_(do_syscall0)(__NR_getpid)); + len = sizeof(filedesc_buf); + sres = VG_(do_syscall6)(__NR___sysctl, (UWord)mib, 4, (UWord)filedesc_buf, + (UWord)&len, 0, 0); + if (sr_isError(sres)) { + VG_(debugLog)(0, "sysctl(kern.proc.filedesc)", "%s\n", VG_(strerror)(sr_Err(sres))); + return False; + } + /* Walk though the list. */ + bp = filedesc_buf; + eb = filedesc_buf + len; + while (bp < eb) { + kf = (struct vki_kinfo_file *)bp; + if (kf->kf_fd == fd) + break; + bp += kf->kf_structsize; + } + if (bp >= eb || *kf->kf_path == '\0') + VG_(strncpy)( buf, "[unknown]", bufsiz ); + else + VG_(strncpy)( buf, kf->kf_path, bufsiz ); + *result = buf; + return True; # elif defined(VGO_darwin) HChar tmp[VKI_MAXPATHLEN+1]; if (0 == VG_(fcntl)(fd, VKI_F_GETPATH, (UWord)tmp)) { @@ -142,7 +187,7 @@ SysRes VG_(mknod) ( const HChar* pathname, Int mode, UWord dev ) /* ARM64 wants to use __NR_mknodat rather than __NR_mknod. */ SysRes res = VG_(do_syscall4)(__NR_mknodat, VKI_AT_FDCWD, (UWord)pathname, mode, dev); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_mknod, (UWord)pathname, mode, dev); # elif defined(VGO_solaris) @@ -160,7 +205,7 @@ SysRes VG_(open) ( const HChar* pathname, Int flags, Int mode ) /* ARM64 wants to use __NR_openat rather than __NR_open. */ SysRes res = VG_(do_syscall4)(__NR_openat, VKI_AT_FDCWD, (UWord)pathname, flags, mode); -# elif defined(VGO_linux) +# elif defined(VGO_linux) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_open, (UWord)pathname, flags, mode); # elif defined(VGO_darwin) @@ -188,7 +233,7 @@ Int VG_(fd_open) (const HChar* pathname, Int flags, Int mode) void VG_(close) ( Int fd ) { /* Hmm. Return value is not checked. That's uncool. */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) (void)VG_(do_syscall1)(__NR_close, fd); # elif defined(VGO_darwin) (void)VG_(do_syscall1)(__NR_close_nocancel, fd); @@ -200,7 +245,7 @@ void VG_(close) ( Int fd ) Int VG_(read) ( Int fd, void* buf, Int count) { Int ret; -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) 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); @@ -220,7 +265,7 @@ Int VG_(read) ( Int fd, void* buf, Int count) Int VG_(write) ( Int fd, const void* buf, Int count) { Int ret; -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) 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); @@ -256,6 +301,13 @@ Int VG_(pipe) ( Int fd[2] ) # elif defined(VGO_linux) SysRes res = VG_(do_syscall1)(__NR_pipe, (UWord)fd); return sr_isError(res) ? -1 : 0; +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall0)(__NR_pipe); + if (!sr_isError(res)) { + fd[0] = sr_Res(res); + fd[1] = sr_ResHI(res); + } + 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); @@ -283,7 +335,7 @@ Int VG_(pipe) ( Int fd[2] ) Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence ) { -# if defined(VGO_linux) || defined(VGP_amd64_darwin) +# if defined(VGO_linux) || defined(VGP_amd64_darwin) || defined(VGP_amd64_freebsd) # if defined(__NR__llseek) Off64T result; SysRes res = VG_(do_syscall5)(__NR__llseek, fd, @@ -295,7 +347,7 @@ Off64T VG_(lseek) ( Int fd, Off64T offset, Int whence ) vg_assert(sizeof(Off64T) == sizeof(sr_Res(res))); return sr_isError(res) ? (-1) : sr_Res(res); # endif -# elif defined(VGP_x86_darwin) +# elif defined(VGP_x86_darwin) || defined(VGP_x86_freebsd) SysRes res = VG_(do_syscall4)(__NR_lseek, fd, offset & 0xffffffff, offset >> 32, whence); return sr_isError(res) ? (-1) : sr_Res(res); @@ -344,7 +396,7 @@ SysRes VG_(stat) ( const HChar* file_name, struct vg_stat* vgbuf ) SysRes res; VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) /* First try with stat64. If that doesn't work out, fall back to the vanilla version. */ # if defined(__NR_stat64) @@ -397,7 +449,7 @@ Int VG_(fstat) ( Int fd, struct vg_stat* vgbuf ) SysRes res; VG_(memset)(vgbuf, 0, sizeof(*vgbuf)); -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) /* First try with fstat64. If that doesn't work out, fall back to the vanilla version. */ # if defined(__NR_fstat64) @@ -469,7 +521,7 @@ Bool VG_(is_dir) ( const HChar* f ) SysRes VG_(dup) ( Int oldfd ) { -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return VG_(do_syscall1)(__NR_dup, oldfd); # elif defined(VGO_solaris) return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUPFD, 0); @@ -491,7 +543,7 @@ SysRes VG_(dup2) ( Int oldfd, Int newfd ) return VG_(mk_SysRes_Success)(newfd); } return VG_(do_syscall3)(__NR_dup3, oldfd, newfd, 0); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return VG_(do_syscall2)(__NR_dup2, oldfd, newfd); # elif defined(VGO_solaris) return VG_(do_syscall3)(__NR_fcntl, oldfd, F_DUP2FD, newfd); @@ -503,7 +555,7 @@ SysRes VG_(dup2) ( Int oldfd, Int newfd ) /* Returns -1 on error. */ Int VG_(fcntl) ( Int fd, Int cmd, Addr arg ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) 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); @@ -518,7 +570,7 @@ Int VG_(rename) ( const HChar* old_name, const HChar* new_name ) # if defined(VGO_solaris) || defined(VGP_arm64_linux) SysRes res = VG_(do_syscall4)(__NR_renameat, VKI_AT_FDCWD, (UWord)old_name, VKI_AT_FDCWD, (UWord)new_name); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall2)(__NR_rename, (UWord)old_name, (UWord)new_name); # else # error "Unknown OS" @@ -531,7 +583,7 @@ Int VG_(unlink) ( const HChar* file_name ) # if defined(VGP_arm64_linux) SysRes res = VG_(do_syscall2)(__NR_unlinkat, VKI_AT_FDCWD, (UWord)file_name); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall1)(__NR_unlink, (UWord)file_name); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall3)(__NR_unlinkat, VKI_AT_FDCWD, @@ -553,7 +605,7 @@ static HChar *startup_wd; changes. */ void VG_(record_startup_wd) ( void ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* Simple: just ask the kernel */ SysRes res; SizeT szB = 0; @@ -561,7 +613,11 @@ void VG_(record_startup_wd) ( void ) szB += 500; startup_wd = VG_(realloc)("startup_wd", startup_wd, szB); VG_(memset)(startup_wd, 0, szB); +# if defined(VGO_linux) || defined(VGO_solaris) res = VG_(do_syscall2)(__NR_getcwd, (UWord)startup_wd, szB-1); +# elif defined(VGO_freebsd) + res = VG_(do_syscall2)(__NR___getcwd, (UWord)startup_wd, szB-1); +# endif } while (sr_isError(res) && sr_Err(res) == VKI_ERANGE); if (sr_isError(res)) { @@ -616,6 +672,8 @@ SysRes VG_(poll) (struct vki_pollfd *fds, Int nfds, Int timeout) (UWord)NULL); # elif defined(VGO_linux) res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout); +# elif defined(VGO_freebsd) + res = VG_(do_syscall3)(__NR_poll, (UWord)fds, nfds, timeout); # elif defined(VGO_darwin) res = VG_(do_syscall3)(__NR_poll_nocancel, (UWord)fds, nfds, timeout); # elif defined(VGO_solaris) @@ -649,7 +707,7 @@ SSizeT VG_(readlink) (const HChar* path, HChar* buf, SizeT bufsiz) # if defined(VGP_arm64_linux) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, (UWord)buf, bufsiz); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall3)(__NR_readlink, (UWord)path, (UWord)buf, bufsiz); # elif defined(VGO_solaris) res = VG_(do_syscall4)(__NR_readlinkat, VKI_AT_FDCWD, (UWord)path, @@ -727,7 +785,7 @@ Int VG_(access) ( const HChar* path, Bool irusr, Bool iwusr, Bool ixusr ) | (ixusr ? VKI_X_OK : 0); # if defined(VGP_arm64_linux) SysRes res = VG_(do_syscall3)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, w); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall2)(__NR_access, (UWord)path, w); # elif defined(VGO_solaris) SysRes res = VG_(do_syscall4)(__NR_faccessat, VKI_AT_FDCWD, (UWord)path, @@ -872,6 +930,15 @@ SysRes VG_(pread) ( Int fd, void* buf, Int count, OffT offset ) || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) res = VG_(do_syscall4)(__NR_pread64, fd, (UWord)buf, count, offset); return res; +# elif defined(VGP_amd64_freebsd) + vg_assert(sizeof(OffT) == 8); + res = VG_(do_syscall4)(__NR_pread, fd, (UWord)buf, count, offset); + return res; +# elif defined(VGP_x86_freebsd) + vg_assert(sizeof(OffT) == 8); + res = VG_(do_syscall5)(__NR_pread, fd, (UWord)buf, count, + offset & 0xffffffff, offset >> 32); + return res; # elif defined(VGP_amd64_darwin) vg_assert(sizeof(OffT) == 8); res = VG_(do_syscall4)(__NR_pread_nocancel, fd, (UWord)buf, count, offset); @@ -1023,7 +1090,7 @@ UShort VG_(ntohs) ( UShort x ) */ Int VG_(connect_via_socket)( const HChar* str ) { -# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) Int sd, res; struct vki_sockaddr_in servAddr; UInt ip = 0; @@ -1124,7 +1191,7 @@ Int VG_(socket) ( Int domain, Int type, Int protocol ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) + || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_socket, domain, type, protocol ); return sr_isError(res) ? -1 : sr_Res(res); @@ -1179,7 +1246,7 @@ Int my_connect ( Int sockfd, struct vki_sockaddr_in* serv_addr, Int addrlen ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) + || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)(__NR_connect, sockfd, (UWord)serv_addr, addrlen); return sr_isError(res) ? -1 : sr_Res(res); @@ -1226,7 +1293,7 @@ Int VG_(write_socket)( Int sd, const void *msg, Int count ) # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) + || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall6)(__NR_sendto, sd, (UWord)msg, count, VKI_MSG_NOSIGNAL, 0,0); @@ -1262,7 +1329,7 @@ Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen) return sr_isError(res) ? -1 : sr_Res(res); # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ - || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) + || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)( __NR_getsockname, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1300,7 +1367,7 @@ Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen) return sr_isError(res) ? -1 : sr_Res(res); # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ - || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) + || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall3)( __NR_getpeername, (UWord)sd, (UWord)name, (UWord)namelen ); @@ -1341,7 +1408,7 @@ Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval, # elif defined(VGP_amd64_linux) || defined(VGP_arm_linux) \ || defined(VGP_mips32_linux) || defined(VGP_mips64_linux) \ - || defined(VGP_arm64_linux) + || defined(VGP_arm64_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall5)( __NR_getsockopt, (UWord)sd, (UWord)level, (UWord)optname, @@ -1392,7 +1459,7 @@ Int VG_(setsockopt) ( Int sd, Int level, Int optname, void *optval, (UWord)optval, (UWord)optlen ); return sr_isError(res) ? -1 : sr_Res(res); -# elif defined(VGO_darwin) +# elif defined(VGO_darwin) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall5)( __NR_setsockopt, (UWord)sd, (UWord)level, (UWord)optname, diff --git a/coregrind/m_libcprint.c b/coregrind/m_libcprint.c index 92be7078c..7da2225f1 100644 --- a/coregrind/m_libcprint.c +++ b/coregrind/m_libcprint.c @@ -1175,7 +1175,7 @@ void VG_(err_config_error) ( const HChar* format, ... ) VG_(sr_as_string)() ------------------------------------------------------------------ */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) // FIXME: Does this function need to be adjusted for MIPS's _valEx ? const HChar *VG_(sr_as_string) ( SysRes sr ) { diff --git a/coregrind/m_libcproc.c b/coregrind/m_libcproc.c index 97a4fc534..08a50f448 100644 --- a/coregrind/m_libcproc.c +++ b/coregrind/m_libcproc.c @@ -67,7 +67,7 @@ HChar** VG_(client_envp) = NULL; const HChar *VG_(libdir) = VG_LIBDIR; const HChar *VG_(LD_PRELOAD_var_name) = -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) "LD_PRELOAD"; #elif defined(VGO_darwin) "DYLD_INSERT_LIBRARIES"; @@ -348,7 +348,7 @@ void VG_(client_cmd_and_args)(HChar *buffer, SizeT buf_size) Int VG_(waitpid)(Int pid, Int *status, Int options) { -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) SysRes res = VG_(do_syscall4)(__NR_wait4, pid, (UWord)status, options, 0); return sr_isError(res) ? -1 : sr_Res(res); @@ -586,7 +586,7 @@ Int VG_(system) ( const HChar* cmd ) Int VG_(sysctl)(Int *name, UInt namelen, void *oldp, SizeT *oldlenp, void *newp, SizeT newlen) { SysRes res; -# if defined(VGO_darwin) +# if defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall6)(__NR___sysctl, (UWord)name, namelen, (UWord)oldp, (UWord)oldlenp, (UWord)newp, newlen); # else @@ -684,6 +684,15 @@ Int VG_(gettid)(void) return sr_Res(res); +# elif defined(VGO_freebsd) + SysRes res; + long tid; + + res = VG_(do_syscall1)(__NR_thr_self, (UWord)&tid); + if (sr_isError(res)) + tid = sr_Res(VG_(do_syscall0)(__NR_getpid)); + return tid; + # elif defined(VGO_darwin) // Darwin's gettid syscall is something else. // Use Mach thread ports for lwpid instead. @@ -710,7 +719,7 @@ Int VG_(getpgrp) ( void ) /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ # if defined(VGP_arm64_linux) return sr_Res( VG_(do_syscall1)(__NR_getpgid, 0) ); -# elif defined(VGO_linux) || defined(VGO_darwin) +# elif defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return sr_Res( VG_(do_syscall0)(__NR_getpgrp) ); # elif defined(VGO_solaris) /* Uses the shared pgrpsys syscall, 0 for the getpgrp variant. */ @@ -723,7 +732,7 @@ Int VG_(getpgrp) ( void ) Int VG_(getppid) ( void ) { /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) return sr_Res( VG_(do_syscall0)(__NR_getppid) ); # elif defined(VGO_solaris) /* Uses the shared getpid/getppid syscall, val2 contains a parent pid. */ @@ -736,7 +745,7 @@ Int VG_(getppid) ( void ) Int VG_(geteuid) ( void ) { /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) { # if defined(__NR_geteuid32) // We use the 32-bit version if it's supported. Otherwise, IDs greater @@ -757,7 +766,7 @@ Int VG_(geteuid) ( void ) Int VG_(getegid) ( void ) { -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) /* ASSUMES SYSCALL ALWAYS SUCCEEDS */ # if defined(__NR_getegid32) // We use the 32-bit version if it's supported. Otherwise, IDs greater @@ -804,7 +813,7 @@ Int VG_(getgroups)( Int size, UInt* list ) || defined(VGP_ppc64be_linux) || defined(VGP_ppc64le_linux) \ || defined(VGO_darwin) || defined(VGP_s390x_linux) \ || defined(VGP_mips32_linux) || defined(VGP_arm64_linux) \ - || defined(VGO_solaris) + || defined(VGO_solaris) || defined(VGO_freebsd) SysRes sres; sres = VG_(do_syscall2)(__NR_getgroups, size, (Addr)list); if (sr_isError(sres)) @@ -823,7 +832,7 @@ Int VG_(getgroups)( Int size, UInt* list ) Int VG_(ptrace) ( Int request, Int pid, void *addr, void *data ) { SysRes res; -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) res = VG_(do_syscall4)(__NR_ptrace, request, pid, (UWord)addr, (UWord)data); # elif defined(VGO_solaris) /* There is no ptrace syscall on Solaris. Such requests has to be @@ -853,7 +862,7 @@ Int VG_(fork) ( void ) return -1; return sr_Res(res); -# elif defined(VGO_linux) +# elif defined(VGO_linux) || defined(VGO_freebsd) SysRes res; res = VG_(do_syscall0)(__NR_fork); if (sr_isError(res)) @@ -921,6 +930,13 @@ UInt VG_(read_millisecond_timer) ( void ) } } +# elif defined(VGO_freebsd) + { 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; + } # elif defined(VGO_darwin) // Weird: it seems that gettimeofday() doesn't fill in the timeval, but // rather returns the tv_sec as the low 32 bits of the result and the @@ -985,6 +1001,9 @@ UInt VG_(get_user_milliseconds)(void) # elif defined(VGO_darwin) res = 0; +# elif defined(VGO_freebsd) + res = 0; + # else # error "Unknown OS" # endif @@ -1057,6 +1076,76 @@ void VG_(do_atfork_child)(ThreadId tid) (*atforks[i].child)(tid); } +/* --------------------------------------------------------------------- + FreeBSD sysctlbyname(), modfind(), etc + ------------------------------------------------------------------ */ + +#if defined(VGO_freebsd) +Int VG_(sysctlbyname)(const Char *name, void *oldp, vki_size_t *oldlenp, void *newp, vki_size_t newlen) +{ + Int oid[2]; + Int real_oid[10]; + vki_size_t oidlen; + int error; + + oid[0] = 0; /* magic */ + oid[1] = 3; /* undocumented */ + oidlen = sizeof(real_oid); + error = VG_(sysctl)(oid, 2, real_oid, &oidlen, (void *)name, VG_(strlen)(name)); + if (error < 0) + return error; + oidlen /= sizeof(int); + error = VG_(sysctl)(real_oid, oidlen, oldp, oldlenp, newp, newlen); + return error; +} + +Int VG_(getosreldate)(void) +{ + static Int osreldate = 0; + vki_size_t osreldatel; + + if (osreldate == 0) { + osreldatel = sizeof(osreldate); + VG_(sysctlbyname)("kern.osreldate", &osreldate, &osreldatel, 0, 0); + } + return (osreldate); +} + +Bool VG_(is32on64)(void) +{ +#if defined(VGP_amd64_freebsd) + return False; +#elif defined(VGP_x86_freebsd) + Int oid[2], error; + vki_size_t len; + char machbuf[32]; + static Int is32on64 = -1; + + if (is32on64 == -1) { + oid[0] = VKI_CTL_HW; + oid[1] = VKI_HW_MACHINE; + len = sizeof(machbuf); + error = VG_(sysctl)(oid, 2, machbuf, &len, NULL, 0); + if (error == 0) { + machbuf[31] = '\0'; + if (VG_(strcmp)(machbuf, "amd64") == 0) + is32on64 = 1; + else + is32on64 = 0; + } else { + is32on64 = -2; + } + } + if (is32on64 == 1) { + return True; + } else { + return False; + } +#else +# error Unknown platform +#endif +} +#endif /* --------------------------------------------------------------------- icache invalidation diff --git a/coregrind/m_libcsetjmp.c b/coregrind/m_libcsetjmp.c index c73180640..d8685a87d 100644 --- a/coregrind/m_libcsetjmp.c +++ b/coregrind/m_libcsetjmp.c @@ -382,13 +382,13 @@ __asm__( /* -------- amd64-{linux,darwin,solaris} -------- */ #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) || \ - defined(VGP_amd64_solaris) + defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) __asm__( ".text" "\n" "" "\n" -#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) ".global VG_MINIMAL_SETJMP" "\n" // rdi = jmp_buf "VG_MINIMAL_SETJMP:" "\n" @@ -425,7 +425,7 @@ __asm__( "" "\n" -#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#if defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) ".global VG_MINIMAL_LONGJMP" "\n" "VG_MINIMAL_LONGJMP:" "\n" // rdi = jmp_buf @@ -473,19 +473,19 @@ __asm__( #endif ); -#endif /* VGP_amd64_linux || VGP_amd64_darwin || VGP_amd64_solaris */ +#endif /* VGP_amd64_linux || VGP_amd64_darwin || VGP_amd64_solaris || VGP_amd64_freebsd */ /* -------- x86-{linux,darwin,solaris} -------- */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) || \ - defined(VGP_x86_solaris) + defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) __asm__( ".text" "\n" "" "\n" -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) ".global VG_MINIMAL_SETJMP" "\n" // eax = jmp_buf "VG_MINIMAL_SETJMP:" "\n" @@ -516,7 +516,7 @@ __asm__( "" "\n" -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) ".global VG_MINIMAL_LONGJMP" "\n" "VG_MINIMAL_LONGJMP:" "\n" // eax = jmp_buf @@ -550,7 +550,7 @@ __asm__( #endif ); -#endif /* VGP_x86_linux || VGP_x86_darwin || VGP_x86_solaris */ +#endif /* VGP_x86_linux || VGP_x86_darwin || VGP_x86_solaris || VGP_x86_freebsd */ #if defined(VGP_mips32_linux) diff --git a/coregrind/m_libcsignal.c b/coregrind/m_libcsignal.c index 4703ad6a2..81be85c95 100644 --- a/coregrind/m_libcsignal.c +++ b/coregrind/m_libcsignal.c @@ -216,7 +216,7 @@ void VG_(sigcomplementset)( vki_sigset_t* dst, const vki_sigset_t* src ) */ Int VG_(sigprocmask)( Int how, const vki_sigset_t* set, vki_sigset_t* oldset) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # if defined(__NR_rt_sigprocmask) SysRes res = VG_(do_syscall4)(__NR_rt_sigprocmask, how, (UWord)set, (UWord)oldset, @@ -320,6 +320,12 @@ Int VG_(sigaction) ( Int signum, signum, (UWord)act, (UWord)oldact); return sr_isError(res) ? -1 : 0; +# elif defined(VGO_freebsd) + SysRes res = VG_(do_syscall3)(__NR_sigaction, + signum, (UWord)act, (UWord)oldact); + return sr_isError(res) ? -1 : 0; + + # else # error "Unsupported OS" # endif @@ -331,7 +337,7 @@ void VG_(convert_sigaction_fromK_to_toK)( const vki_sigaction_fromK_t* fromK, /*OUT*/vki_sigaction_toK_t* toK ) { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) *toK = *fromK; # elif defined(VGO_darwin) toK->ksa_handler = fromK->ksa_handler; @@ -348,7 +354,7 @@ Int VG_(kill)( Int pid, Int signo ) { # if defined(VGO_linux) || defined(VGO_solaris) SysRes res = VG_(do_syscall2)(__NR_kill, pid, signo); -# elif defined(VGO_darwin) +# elif defined(VGO_darwin) || defined(VGO_freebsd) SysRes res = VG_(do_syscall3)(__NR_kill, pid, signo, 1/*posix-compliant*/); # else @@ -387,6 +393,12 @@ Int VG_(tkill)( Int lwpid, Int signo ) # endif return sr_isError(res) ? -1 : 0; + +# elif defined(VGO_freebsd) + SysRes res; + res = VG_(do_syscall2)(__NR_thr_kill, lwpid, signo); + return sr_isError(res) ? -1 : 0; + # else # error "Unsupported plat" # endif @@ -550,6 +562,120 @@ Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, vki_siginfo_t *info ) return sr_isError(res) ? -1 : sr_Res(res); } +#elif defined(VGO_freebsd) + +/* + * This is a mess. sigtimedwait() was added in FreeBSD-6. However, + * there was no 32 bit syscall version until FreeBSD-7. So on older + * platforms we have to check. + */ +# if __FreeBSD__ < 7 +static void sigtimedwait_zero_handler ( Int sig ) +{ + vg_assert(sig != VKI_SIGILL); + vg_assert(sig != VKI_SIGSEGV); + vg_assert(sig != VKI_SIGBUS); + vg_assert(sig != VKI_SIGTRAP); + vg_assert(sig != VKI_SIGSYS); + /* do nothing */ +} +# endif + +Int VG_(sigtimedwait_zero)( const vki_sigset_t *set, + vki_siginfo_t *info ) +{ +# if __FreeBSD__ < 7 + Int i, ir; + SysRes sr; + vki_sigset_t pending, blocked, allbutone; + struct vki_sigaction sa, saved_sa; + Int osreldate; +# if defined(VGP_x86_freebsd) + Int is32on64; +# endif + Bool have_sigtimedwait_zero = True; +# endif + static const struct vki_timespec zero = { 0, 0 }; + +# if __FreeBSD__ < 7 + osreldate = VG_(getosreldate)(); + if (osreldate < 600000) + have_sigtimedwait_zero = False; +# if defined(VGP_x86_freebsd) + /* 32 bit emulation is busted, no sigtimedwait even though the kernel has it */ + is32on64 = VG_(is32on64)(); + if (is32on64 && osreldate < 700000) + have_sigtimedwait_zero = False; +# endif + if (have_sigtimedwait_zero) { +# endif + SysRes res = VG_(do_syscall3)(__NR_sigtimedwait, (UWord)set, (UWord)info, + (UWord)&zero); + return sr_isError(res) ? -1 : sr_Res(res); +# if __FreeBSD__ < 7 + } + + /* Find out what's pending: FreeBSD sigpending */ + sr = VG_(do_syscall1)(__NR_sigpending, (UWord)&pending); + vg_assert(!sr.isError); + + /* don't try for signals not in 'set' */ + /* pending = pending `intersect` set */ + for (i = 0; i < _VKI_NSIG_WORDS; i++) + pending.sig[i] &= set->sig[i]; + + /* 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 */ + for (i = 0; i < _VKI_NSIG_WORDS; i++) + pending.sig[i] &= blocked.sig[i]; + + /* 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; + + /* fetch signal i. + pre: i is blocked and pending + pre: we are the only thread running + */ + /* Set up alternative signal handler */ + VG_(sigfillset)(&allbutone); + VG_(sigdelset)(&allbutone, i); + sa.sa_mask = allbutone; + 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. */ + sr = VG_(do_syscall1)(__NR_sigsuspend, (UWord)&allbutone); + vg_assert(sr.isError); + if (0) + VG_(debugLog)(0, "libcsignal", + "sigtimedwait_zero: sigsuspend got res %ld err %ld\n", + sr.res, sr.err); + vg_assert(sr.res == (UWord)-1); + + /* Restore signal's handler to whatever it was before */ + ir = VG_(sigaction)(i, &saved_sa, 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; +# endif +} + #else # error "Unknown OS" #endif diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 7aa051bd1..af57f1d70 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -884,6 +884,20 @@ Bool VG_(machine_get_hwcaps)( void ) if (!have_cx8) return False; +#if defined(VGP_x86_freebsd) + if (have_sse1 || have_sse2) { + Int sc, error; + vki_size_t scl; + /* Regardless of whether cpuid says, the OS has to enable SSE first! */ + scl = sizeof(sc); + error = VG_(sysctlbyname)("hw.instruction_sse", &sc, &scl, 0, 0); + if (error == -1 || sc != 1) { + have_sse1 = 0; + have_sse2 = 0; + VG_(message)(Vg_UserMsg, "Warning: cpu has SSE, but the OS has not enabled it. Disabling in valgrind!"); + } + } +#endif /* Figure out if this is an AMD that can do MMXEXT. */ have_mmxext = False; if (0 == VG_(strcmp)(vstr, "AuthenticAMD") @@ -2038,7 +2052,7 @@ Int VG_(machine_get_size_of_largest_guest_register) ( void ) void* VG_(fnptr_to_fnentry)( void* f ) { # if defined(VGP_x86_linux) || defined(VGP_amd64_linux) \ - || defined(VGP_arm_linux) || defined(VGO_darwin) \ + || defined(VGP_arm_linux) || defined(VGO_darwin) || defined(VGO_freebsd) \ || defined(VGP_ppc32_linux) || defined(VGP_ppc64le_linux) \ || defined(VGP_s390x_linux) || defined(VGP_mips32_linux) \ || defined(VGP_mips64_linux) || defined(VGP_arm64_linux) \ diff --git a/coregrind/m_main.c b/coregrind/m_main.c index 7d987ea26..c82df9993 100644 --- a/coregrind/m_main.c +++ b/coregrind/m_main.c @@ -1062,7 +1062,11 @@ void main_process_cmd_line_options( void ) /* Number of file descriptors that Valgrind tries to reserve for its own use - just a small constant. */ +#if defined(VGO_freebsd) +#define N_RESERVED_FDS (20) +#else #define N_RESERVED_FDS (12) +#endif static void setup_file_descriptors(void) { @@ -1492,7 +1496,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) if (!need_help) { VG_(debugLog)(1, "main", "Create initial image\n"); -# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) the_iicii.argv = argv; the_iicii.envp = envp; the_iicii.toolname = VG_(clo_toolname); @@ -1757,7 +1761,7 @@ Int valgrind_main ( Int argc, HChar **argv, HChar **envp ) addr2dihandle = VG_(newXA)( VG_(malloc), "main.vm.2", VG_(free), sizeof(Addr_n_ULong) ); -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) { Addr* seg_starts; Int n_seg_starts; Addr_n_ULong anu; @@ -2448,7 +2452,7 @@ static void final_tidyup(ThreadId tid) /*=== Getting to main() alive: LINUX ===*/ /*====================================================================*/ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) /* If linking of the final executables is done with glibc present, then Valgrind starts at main() above as usual, and all of the @@ -2880,6 +2884,44 @@ asm("\n" "\tbreak 0x7\n" ".previous\n" ); +#elif defined(VGP_x86_freebsd) +asm("\n" + ".text\n" + "\t.globl _start\n" + "\t.type _start,@function\n" + "_start:\n" + /* set up the new stack in %eax */ + "\tmovl $vgPlain_interim_stack, %eax\n" + "\taddl $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %eax\n" + "\taddl $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %eax\n" + "\tsubl $16, %eax\n" + "\tandl $~15, %eax\n" + /* install it, and collect the original one */ + "\txchgl %eax, %esp\n" + /* call _start_in_C_linux, passing it the startup %esp */ + "\tpushl %eax\n" + "\tcall _start_in_C_linux\n" + "\thlt\n" + ".previous\n" +); +#elif defined(VGP_amd64_freebsd) +asm("\n" + ".text\n" + "\t.globl _start\n" + "\t.type _start,@function\n" + "_start:\n" + /* set up the new stack in %rsi */ + "\tmovq $vgPlain_interim_stack, %rsi\n" + "\taddq $"VG_STRINGIFY(VG_STACK_GUARD_SZB)", %rsi\n" + "\taddq $"VG_STRINGIFY(VG_DEFAULT_STACK_ACTIVE_SZB)", %rsi\n" + "\tandq $~15, %rsi\n" + /* install it, and collect the original one */ + "\txchgq %rsi, %rsp\n" + /* call _start_in_C_amd64_freebsd, passing it the startup %rsp */ + "\tcall _start_in_C_amd64_freebsd\n" + "\thlt\n" + ".previous\n" +); #elif defined(VGP_mips64_linux) asm( ".text\n" @@ -2920,7 +2962,7 @@ asm( ".previous\n" ); #else -# error "Unknown linux platform" +# error "Unknown platform" #endif /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ @@ -2930,6 +2972,26 @@ asm( #include /* --- !!! --- EXTERNAL HEADERS end --- !!! --- */ +#if defined(VGP_amd64_freebsd) +void _start_in_C_amd64_freebsd ( UWord* pArgc, UWord *initial_sp ); +void _start_in_C_amd64_freebsd ( UWord* pArgc, UWord *initial_sp ) +{ + Int r; + Word argc = pArgc[0]; + HChar** argv = (HChar**)&pArgc[1]; + HChar** envp = (HChar**)&pArgc[1+argc+1]; + + VG_(memset)( &the_iicii, 0, sizeof(the_iicii) ); + VG_(memset)( &the_iifii, 0, sizeof(the_iifii) ); + + the_iicii.sp_at_startup = (Addr)initial_sp; + + r = valgrind_main( (Int)argc, argv, envp ); + /* NOTREACHED */ + VG_(exit)(r); +} + +#else /* Avoid compiler warnings: this fn _is_ used, but labelling it 'static' causes gcc to complain it isn't. attribute 'used' also ensures the code is not eliminated at link @@ -2986,6 +3048,7 @@ void _start_in_C_linux ( UWord* pArgc ) /* NOTREACHED */ VG_(exit)(r); } +#endif /*====================================================================*/ diff --git a/coregrind/m_redir.c b/coregrind/m_redir.c index 6bc01b434..b65de3b2c 100644 --- a/coregrind/m_redir.c +++ b/coregrind/m_redir.c @@ -1213,6 +1213,9 @@ Bool VG_(is_soname_ld_so) (const HChar *soname) if (VG_STREQ(soname, VG_U_LD_SO_1)) return True; if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True; if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3)) return True; +# elif defined(VGO_freebsd) + if (VG_STREQ(soname, VG_U_LD_ELF_SO_1)) return True; + if (VG_STREQ(soname, VG_U_LD_ELF32_SO_1)) return True; # elif defined(VGO_darwin) if (VG_STREQ(soname, VG_U_DYLD)) return True; # elif defined(VGO_solaris) @@ -1528,6 +1531,8 @@ void VG_(redir_initialise) ( void ) # endif } +# elif defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) +/* XXX do something real if needed */ # elif defined(VGP_x86_darwin) /* If we're using memcheck, use these intercepts right from the start, otherwise dyld makes a lot of noise. */ diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c index 564829aa7..752ba8db3 100644 --- a/coregrind/m_replacemalloc/vg_replace_malloc.c +++ b/coregrind/m_replacemalloc/vg_replace_malloc.c @@ -308,6 +308,10 @@ static void init(void); ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); +#elif defined(VGO_freebsd) + ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); + ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); + #elif defined(VGO_darwin) ALLOC_or_NULL(VG_Z_LIBC_SONAME, malloc, malloc); ALLOC_or_NULL(SO_SYN_MALLOC, malloc, malloc); @@ -344,6 +348,20 @@ static void init(void); ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwm, __builtin_new); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned int), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwj, __builtin_new); + ALLOC_or_BOMB(VG_Z_LIBSUPCXX_SONAME, _Znwj, __builtin_new); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwm, __builtin_new); + #endif + // operator new(unsigned long), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znwm, __builtin_new); + ALLOC_or_BOMB(VG_Z_LIBSUPCXX_SONAME, _Znwm, __builtin_new); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znwm, __builtin_new); + #endif + #elif defined(VGO_darwin) // operator new(unsigned int), GNU mangling #if VG_WORDSIZE == 4 @@ -387,6 +405,20 @@ static void init(void); ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwmRKSt9nothrow_t, __builtin_new); #endif +#elif defined(VGO_freebsd) + // operator new(unsigned, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwjRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(VG_Z_LIBSUPCXX_SONAME, _ZnwjRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwjRKSt9nothrow_t, __builtin_new); + #endif + // operator new(unsigned long, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(VG_Z_LIBSUPCXX_SONAME, _ZnwmRKSt9nothrow_t, __builtin_new); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnwjRKSt9nothrow_t, __builtin_new); + #endif + #elif defined(VGO_darwin) // operator new(unsigned, std::nothrow_t const&), GNU mangling #if VG_WORDSIZE == 4 @@ -433,6 +465,20 @@ static void init(void); ALLOC_or_BOMB(SO_SYN_MALLOC, _Znam, __builtin_vec_new ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned int), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znaj, __builtin_vec_new ); + ALLOC_or_BOMB(VG_Z_LIBSUPCXX_SONAME, _Znaj, __builtin_vec_new ); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znaj, __builtin_vec_new ); + #endif + // operator new[](unsigned long), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_BOMB(VG_Z_LIBSTDCXX_SONAME, _Znam, __builtin_vec_new ); + ALLOC_or_BOMB(VG_Z_LIBSUPCXX_SONAME, _Znam, __builtin_vec_new ); + ALLOC_or_BOMB(SO_SYN_MALLOC, _Znaj, __builtin_vec_new ); + #endif + #elif defined(VGO_darwin) // operator new[](unsigned int), GNU mangling #if VG_WORDSIZE == 4 @@ -476,6 +522,20 @@ static void init(void); ALLOC_or_NULL(SO_SYN_MALLOC, _ZnamRKSt9nothrow_t, __builtin_vec_new ); #endif +#elif defined(VGO_freebsd) + // operator new[](unsigned, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 4 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(VG_Z_LIBSUPCXX_SONAME, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + #endif + // operator new[](unsigned long, std::nothrow_t const&), GNU mangling + #if VG_WORDSIZE == 8 + ALLOC_or_NULL(VG_Z_LIBSTDCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(VG_Z_LIBSUPCXX_SONAME, _ZnamRKSt9nothrow_t, __builtin_vec_new ); + ALLOC_or_NULL(SO_SYN_MALLOC, _ZnajRKSt9nothrow_t, __builtin_vec_new ); + #endif + #elif defined(VGO_darwin) // operator new[](unsigned, std::nothrow_t const&), GNU mangling #if VG_WORDSIZE == 4 @@ -539,6 +599,10 @@ static void init(void); FREE(VG_Z_LIBC_SONAME, free, free ); FREE(SO_SYN_MALLOC, free, free ); +#elif defined(VGO_freebsd) + FREE(VG_Z_LIBC_SONAME, free, free ); + FREE(SO_SYN_MALLOC, free, free ); + #elif defined(VGO_darwin) FREE(VG_Z_LIBC_SONAME, free, free ); FREE(SO_SYN_MALLOC, free, free ); @@ -596,6 +660,11 @@ static void init(void); #endif +#elif defined(VGO_freebsd) + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPv, __builtin_delete ); + FREE(VG_Z_LIBSUPCXX_SONAME, _ZdlPv, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPv, __builtin_delete ); + #elif defined(VGO_darwin) // operator delete(void*), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPv, __builtin_delete ); @@ -626,6 +695,12 @@ static void init(void); FREE(VG_Z_LIBC_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); FREE(SO_SYN_MALLOC, _ZdlPvRKSt9nothrow_t, __builtin_delete ); +#elif defined(VGO_freebsd) + // operator delete(void*, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + FREE(VG_Z_LIBSUPCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + FREE(SO_SYN_MALLOC, _ZdlPvRKSt9nothrow_t, __builtin_delete ); + #elif defined(VGO_darwin) // operator delete(void*, std::nothrow_t const&), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdlPvRKSt9nothrow_t, __builtin_delete ); @@ -662,6 +737,12 @@ static void init(void); FREE(SO_SYN_MALLOC, _ZdaPvm, __builtin_vec_delete ); #endif +#elif defined(VGO_freebsd) + // operator delete[](void*), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPv, __builtin_vec_delete ); + FREE(VG_Z_LIBSUPCXX_SONAME, _ZdaPv, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPv, __builtin_vec_delete ); + #elif defined(VGO_darwin) // operator delete[](void*), not mangled (for gcc 2.96) //FREE(VG_Z_LIBSTDCXX_SONAME, __builtin_vec_delete, __builtin_vec_delete ); @@ -695,6 +776,12 @@ static void init(void); FREE(VG_Z_LIBC_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); FREE(SO_SYN_MALLOC, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); +#elif defined(VGO_freebsd) + // operator delete[](void*, std::nothrow_t const&), GNU mangling + FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + FREE(VG_Z_LIBSUPCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + FREE(SO_SYN_MALLOC, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); + #elif defined(VGO_darwin) // operator delete[](void*, std::nothrow_t const&), GNU mangling //FREE(VG_Z_LIBSTDCXX_SONAME, _ZdaPvRKSt9nothrow_t, __builtin_vec_delete ); @@ -761,6 +848,10 @@ static void init(void); CALLOC(VG_Z_LIBC_SONAME, calloc); CALLOC(SO_SYN_MALLOC, calloc); +#elif defined(VGO_freebsd) + CALLOC(VG_Z_LIBC_SONAME, calloc); + CALLOC(SO_SYN_MALLOC, calloc); + #elif defined(VGO_darwin) CALLOC(VG_Z_LIBC_SONAME, calloc); CALLOC(SO_SYN_MALLOC, calloc); @@ -831,10 +922,45 @@ static void init(void); return v; \ } +#define REALLOCF(soname, fnname) \ + \ + void* VG_REPLACE_FUNCTION_EZU(10091,soname,fnname) \ + ( void* ptrV, SizeT new_size );\ + void* VG_REPLACE_FUNCTION_EZU(10091,soname,fnname) \ + ( void* ptrV, SizeT new_size ) \ + { \ + void* v; \ + \ + if (!init_done) init(); \ + MALLOC_TRACE("reallocf(%p,%llu)", ptrV, (ULong)new_size ); \ + \ + if (ptrV == NULL) \ + /* We need to call a malloc-like function; so let's use \ + one which we know exists. */ \ + return VG_REPLACE_FUNCTION_EZU(10010,VG_Z_LIBC_SONAME,malloc) \ + (new_size); \ + if (new_size <= 0) { \ + VG_REPLACE_FUNCTION_EZU(10050,VG_Z_LIBC_SONAME,free)(ptrV); \ + MALLOC_TRACE(" = 0\n"); \ + return NULL; \ + } \ + v = (void*)VALGRIND_NON_SIMD_CALL2( info.tl_realloc, ptrV, new_size ); \ + MALLOC_TRACE(" = %p\n", v ); \ + if (v == NULL) \ + VG_REPLACE_FUNCTION_EZU(10050,VG_Z_LIBC_SONAME,free)(ptrV); \ + MALLOC_TRACE(" = %p\n", v ); \ + return v; \ + } + #if defined(VGO_linux) REALLOC(VG_Z_LIBC_SONAME, realloc); REALLOC(SO_SYN_MALLOC, realloc); +#elif defined(VGO_freebsd) + REALLOC(VG_Z_LIBC_SONAME, realloc); + REALLOC(SO_SYN_MALLOC, realloc); + REALLOCF(VG_Z_LIBC_SONAME, reallocf); + #elif defined(VGO_darwin) REALLOC(VG_Z_LIBC_SONAME, realloc); REALLOC(SO_SYN_MALLOC, realloc); @@ -908,6 +1034,10 @@ static void init(void); MEMALIGN(VG_Z_LIBC_SONAME, memalign); MEMALIGN(SO_SYN_MALLOC, memalign); +#elif defined(VGO_freebsd) + MEMALIGN(VG_Z_LIBC_SONAME, memalign); + MEMALIGN(SO_SYN_MALLOC, memalign); + #elif defined(VGO_darwin) MEMALIGN(VG_Z_LIBC_SONAME, memalign); MEMALIGN(SO_SYN_MALLOC, memalign); @@ -955,6 +1085,10 @@ static void init(void); VALLOC(VG_Z_LIBC_SONAME, valloc); VALLOC(SO_SYN_MALLOC, valloc); +#elif defined(VGO_freebsd) + VALLOC(VG_Z_LIBC_SONAME, valloc); + VALLOC(SO_SYN_MALLOC, valloc); + #elif defined(VGO_darwin) VALLOC(VG_Z_LIBC_SONAME, valloc); VALLOC(SO_SYN_MALLOC, valloc); @@ -1072,6 +1206,10 @@ static void init(void); POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); POSIX_MEMALIGN(SO_SYN_MALLOC, posix_memalign); +#elif defined(VGO_freebsd) + POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); + POSIX_MEMALIGN(SO_SYN_MALLOC, posix_memalign); + #elif defined(VGO_darwin) //POSIX_MEMALIGN(VG_Z_LIBC_SONAME, posix_memalign); @@ -1113,6 +1251,10 @@ static void init(void); MALLOC_USABLE_SIZE(SO_SYN_MALLOC, dlmalloc_usable_size); # endif +#elif defined(VGO_freebsd) + MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size); + MALLOC_USABLE_SIZE(SO_SYN_MALLOC, malloc_usable_size); + #elif defined(VGO_darwin) //MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_usable_size); MALLOC_USABLE_SIZE(VG_Z_LIBC_SONAME, malloc_size); diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c index 68e9590a0..bd4da19e8 100644 --- a/coregrind/m_scheduler/scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -500,7 +500,7 @@ void VG_(vg_yield)(void) /* Tell the kernel we're yielding. */ -# if defined(VGO_linux) || defined(VGO_darwin) +# if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) VG_(do_syscall0)(__NR_sched_yield); # elif defined(VGO_solaris) VG_(do_syscall0)(__NR_yield); @@ -541,6 +541,8 @@ static void os_state_clear(ThreadState *tst) tst->os_state.stk_id = NULL_STK_ID; # if defined(VGO_linux) /* no other fields to clear */ +# elif defined(VGO_freebsd) + /* no other fields to clear */ # elif defined(VGO_darwin) tst->os_state.post_mach_trap_fn = NULL; tst->os_state.pthread = 0; diff --git a/coregrind/m_sigframe/sigframe-amd64-freebsd.c b/coregrind/m_sigframe/sigframe-amd64-freebsd.c new file mode 100755 index 000000000..d3f0b42ce --- /dev/null +++ b/coregrind/m_sigframe/sigframe-amd64-freebsd.c @@ -0,0 +1,433 @@ + +/*--------------------------------------------------------------------*/ +/*--- Create/destroy signal delivery frames. ---*/ +/*--- sigframe-amd64-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#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 */ + +/* This module creates and removes signal frames for signal deliveries + on amd64-freebsd. +*/ + + +/*------------------------------------------------------------*/ +/*--- Signal frame layouts ---*/ +/*------------------------------------------------------------*/ + +// A structure in which to save the application's registers +// during the execution of signal handlers. + +// In theory, so long as we get the arguments to the handler function +// right, it doesn't matter what the exact layout of the rest of the +// frame is. Unfortunately, things like gcc's exception unwinding +// make assumptions about the locations of various parts of the frame, +// so we need to duplicate it exactly. + +/* Valgrind-specific parts of the signal frame */ +struct vg_sigframe +{ + /* Sanity check word. */ + UInt magicPI; + + UInt handlerflags; /* flags for signal handler */ + + + /* Safely-saved version of sigNo, as described above. */ + Int sigNo_private; + + /* XXX This is wrong. Surely we should store the shadow values + into the shadow memory behind the actual values? */ + VexGuestAMD64State vex_shadow1; + VexGuestAMD64State vex_shadow2; + + /* HACK ALERT */ + VexGuestAMD64State vex; + /* end HACK ALERT */ + + /* saved signal mask to be restored when handler returns */ + vki_sigset_t mask; + + /* Sanity check word. Is the highest-addressed word; do not + move!*/ + UInt magicE; +}; + +struct sigframe +{ + /* Sig handler's return address */ + Addr retaddr; + + Int sigNo; + Addr psigInfo; /* code or pointer to sigContext */ + Addr puContext; /* points to uContext */ + Addr addr; /* "secret" 4th argument */ + Addr phandler; /* "action" or "handler" */ + + /* pointed to by puContext */ + struct vki_ucontext uContext; + + vki_siginfo_t sigInfo; + + struct _vki_fpstate fpstate; + + struct vg_sigframe vg; +}; + +/*------------------------------------------------------------*/ +/*--- Creating signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Create a plausible-looking sigcontext from the thread's + Vex guest state. +*/ +static +void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, + UWord trapno, UWord err, const vki_sigset_t *set, + struct vki_ucontext *uc, struct _vki_fpstate *fpstate) +{ + ThreadState *tst = VG_(get_ThreadState)(tid); + struct vki_mcontext *sc = &uc->uc_mcontext; + + VG_(memset)(uc, 0, sizeof(*uc)); + + uc->uc_flags = 0; + uc->uc_link = 0; + uc->uc_sigmask = *set; + uc->uc_stack = tst->altstack; + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + +# define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG + SC2(r8,R8); + SC2(r9,R9); + SC2(r10,R10); + SC2(r11,R11); + SC2(r12,R12); + SC2(r13,R13); + SC2(r14,R14); + SC2(r15,R15); + SC2(rdi,RDI); + SC2(rsi,RSI); + SC2(rbp,RBP); + SC2(rbx,RBX); + SC2(rdx,RDX); + SC2(rax,RAX); + SC2(rcx,RCX); + SC2(rsp,RSP); +/* + SC2(cs,CS); + SC2(gs,SS); + XXX +*/ + SC2(rip,RIP); + sc->addr = (UWord)si->si_addr; + sc->err = err; + sc->fpformat = VKI_FPFMT_NODEV; + sc->len = sizeof(*sc); + sc->ownedfp = VKI_FPOWNED_NONE; + sc->rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); + sc->trapno = trapno; +# undef SC2 +} + + +/* 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; + NSegment const* stackseg = NULL; + + if (VG_(extend_stack)(tid, addr)) { + stackseg = VG_(am_find_nsegment)(addr); + if (0 && stackseg) + VG_(printf)("frame=%#lx seg=%#lx-%#lx\n", + addr, stackseg->start, stackseg->end); + } + + if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) { + VG_(message)( + Vg_UserMsg, + "Can't extend stack to %#lx during signal delivery for thread %d:\n", + addr, tid); + if (stackseg == NULL) + VG_(message)(Vg_UserMsg, " no stack segment\n"); + else + VG_(message)(Vg_UserMsg, " too small or bad protection modes\n"); + + /* set SIGSEGV to default handler */ + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault_mapping)(tid, addr); + + /* The whole process should be about to die, since the default + action of SIGSEGV to kill the whole process. */ + return False; + } + + /* For tracking memory events, indicate the entire frame has been + allocated. */ + VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB, tid ); + + return True; +} + + +/* Build the Valgrind-specific part of a signal frame. */ + +static void build_vg_sigframe(struct vg_sigframe *frame, + ThreadState *tst, + const vki_sigset_t *mask, + UInt flags, + Int sigNo) +{ + frame->sigNo_private = sigNo; + frame->magicPI = 0x31415927; + frame->vex_shadow1 = tst->arch.vex_shadow1; + frame->vex_shadow2 = tst->arch.vex_shadow2; + /* HACK ALERT */ + frame->vex = tst->arch.vex; + /* end HACK ALERT */ + frame->mask = tst->sig_mask; + frame->handlerflags = flags; + frame->magicE = 0x27182818; +} + +static Addr build_sigframe(ThreadState *tst, + Addr rsp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, UInt flags, + const vki_sigset_t *mask, + void *restorer) +{ + struct sigframe *frame; + Addr rsp = rsp_top_of_frame; + Int sigNo = siginfo->si_signo; + UWord trapno; + UWord err; + + rsp -= sizeof(*frame); + rsp = VG_ROUNDDN(rsp, 16); + frame = (struct sigframe *)rsp; + + if (!extend(tst, rsp, sizeof(*frame))) + return rsp_top_of_frame; + + /* retaddr, siginfo, uContext fields are to be written */ + VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", + rsp, offsetof(struct sigframe, vg) ); + + frame->sigNo = sigNo; + frame->retaddr = (Addr)&VG_(amd64_freebsd_SUBST_FOR_sigreturn); + if ((flags & VKI_SA_SIGINFO) == 0) + frame->psigInfo = (Addr)siginfo->si_code; + else + frame->psigInfo = (Addr)&frame->sigInfo; + VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t)); + + if (siguc != NULL) { + trapno = siguc->uc_mcontext.trapno; + err = siguc->uc_mcontext.err; + } else { + trapno = 0; + err = 0; + } + + synth_ucontext(tst->tid, siginfo, trapno, err, mask, + &frame->uContext, &frame->fpstate); + + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + frame->sigInfo.si_addr = (void*)tst->arch.vex.guest_RIP; + + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + rsp, offsetof(struct sigframe, vg) ); + + build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo); + + return rsp; +} + + +void VG_(sigframe_create)( ThreadId tid, + Bool on_altstack, + Addr rsp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, + UInt flags, + const vki_sigset_t *mask, + void *restorer ) +{ + Addr rsp; + struct sigframe *frame; + ThreadState* tst = VG_(get_ThreadState)(tid); + + rsp = build_sigframe(tst, rsp_top_of_frame, siginfo, siguc, handler, + flags, mask, restorer); + frame = (struct sigframe *)rsp; + + /* Set the thread so it will next run the handler. */ + /* tst->m_rsp = rsp; also notify the tool we've updated RSP */ + VG_(set_SP)(tid, rsp); + VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr)); + + //VG_(printf)("handler = %p\n", handler); + tst->arch.vex.guest_RIP = (Addr) handler; + tst->arch.vex.guest_RDI = (ULong) siginfo->si_signo; + tst->arch.vex.guest_RSI = (Addr) &frame->sigInfo; + tst->arch.vex.guest_RDX = (Addr) &frame->uContext; + /* This thread needs to be marked runnable, but we leave that the + caller to do. */ +} + + +/*------------------------------------------------------------*/ +/*--- Destroying signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Return False and don't do anything, just set the client to take a + segfault, if it looks like the frame is corrupted. */ +static +Bool restore_vg_sigframe ( ThreadState *tst, + struct vg_sigframe *frame, Int *sigNo ) +{ + if (frame->magicPI != 0x31415927 || + frame->magicE != 0x27182818) { + VG_(message)(Vg_UserMsg, "Thread %d return signal frame " + "corrupted. Killing process.\n", + tst->tid); + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault)(tst->tid); + *sigNo = VKI_SIGSEGV; + return False; + } + tst->sig_mask = frame->mask; + tst->tmp_sig_mask = frame->mask; + tst->arch.vex_shadow1 = frame->vex_shadow1; + tst->arch.vex_shadow2 = frame->vex_shadow2; + /* HACK ALERT */ + tst->arch.vex = frame->vex; + /* end HACK ALERT */ + *sigNo = frame->sigNo_private; + return True; +} + +static +void restore_sigcontext( ThreadState *tst, + struct vki_mcontext *sc, + struct _vki_fpstate *fpstate ) +{ + tst->arch.vex.guest_RAX = sc->rax; + tst->arch.vex.guest_RCX = sc->rcx; + tst->arch.vex.guest_RDX = sc->rdx; + tst->arch.vex.guest_RBX = sc->rbx; + tst->arch.vex.guest_RBP = sc->rbp; + tst->arch.vex.guest_RSP = sc->rsp; + tst->arch.vex.guest_RSI = sc->rsi; + tst->arch.vex.guest_RDI = sc->rdi; + tst->arch.vex.guest_R8 = sc->r8; + tst->arch.vex.guest_R9 = sc->r9; + tst->arch.vex.guest_R10 = sc->r10; + tst->arch.vex.guest_R11 = sc->r11; + tst->arch.vex.guest_R12 = sc->r12; + tst->arch.vex.guest_R13 = sc->r13; + tst->arch.vex.guest_R14 = sc->r14; + tst->arch.vex.guest_R15 = sc->r15; +/* + XXX: + tst->arch.vex.guest_rflags = sc->rflags; +*/ + tst->arch.vex.guest_RIP = sc->rip; +/* + XXX + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; +*/ + VG_(memcpy)(fpstate, &sc->fpstate, sizeof(*fpstate)); +} + +static +SizeT restore_sigframe ( ThreadState *tst, + struct sigframe *frame, Int *sigNo ) +{ + if (restore_vg_sigframe(tst, &frame->vg, sigNo)) + restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate); + + return sizeof(*frame); +} + +void VG_(sigframe_destroy)( ThreadId tid ) +{ + Addr rsp; + ThreadState* tst; + SizeT size; + Int sigNo; + + tst = VG_(get_ThreadState)(tid); + + /* Correctly reestablish the frame base address. */ + rsp = tst->arch.vex.guest_RSP; + + size = restore_sigframe(tst, (struct sigframe *)rsp, &sigNo); + + VG_TRACK( die_mem_stack_signal, rsp - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB ); + + if (VG_(clo_trace_signals)) + VG_(message)( + Vg_DebugMsg, + "VG_(signal_return) (thread %d): valid magic; RIP=%#llx\n", + tid, tst->arch.vex.guest_RIP); + + /* tell the tools */ + VG_TRACK( post_deliver_signal, tid, sigNo ); +} + +#endif // defined(VGP_amd64_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_sigframe/sigframe-common.c b/coregrind/m_sigframe/sigframe-common.c index 9d243e674..13a552bab 100644 --- a/coregrind/m_sigframe/sigframe-common.c +++ b/coregrind/m_sigframe/sigframe-common.c @@ -49,7 +49,7 @@ static void track_frame_memory ( Addr addr, SizeT size, ThreadId tid ) VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, size, tid ); } -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* Extend the stack segment downwards if needed so as to ensure the new signal frames are mapped to something. Return a Bool diff --git a/coregrind/m_sigframe/sigframe-x86-freebsd.c b/coregrind/m_sigframe/sigframe-x86-freebsd.c new file mode 100755 index 000000000..2b78ca984 --- /dev/null +++ b/coregrind/m_sigframe/sigframe-x86-freebsd.c @@ -0,0 +1,424 @@ + +/*--------------------------------------------------------------------*/ +/*--- Create/destroy signal delivery frames. ---*/ +/*--- sigframe-x86-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2009 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_x86_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" /* find_segment */ +#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 */ + + +/* This module creates and removes signal frames for signal deliveries + on x86-freebsd. +*/ + + +/*------------------------------------------------------------*/ +/*--- Signal frame layouts ---*/ +/*------------------------------------------------------------*/ + +// A structure in which to save the application's registers +// during the execution of signal handlers. + +// In theory, so long as we get the arguments to the handler function +// right, it doesn't matter what the exact layout of the rest of the +// frame is. Unfortunately, things like gcc's exception unwinding +// make assumptions about the locations of various parts of the frame, +// so we need to duplicate it exactly. + +/* Valgrind-specific parts of the signal frame */ +struct vg_sigframe +{ + /* Sanity check word. */ + UInt magicPI; + + UInt handlerflags; /* flags for signal handler */ + + + /* Safely-saved version of sigNo, as described above. */ + Int sigNo_private; + + /* XXX This is wrong. Surely we should store the shadow values + into the shadow memory behind the actual values? */ + VexGuestX86State vex_shadow1; + VexGuestX86State vex_shadow2; + + /* HACK ALERT */ + VexGuestX86State vex; + /* end HACK ALERT */ + + /* saved signal mask to be restored when handler returns */ + vki_sigset_t mask; + + /* Sanity check word. Is the highest-addressed word; do not + move!*/ + UInt magicE; +}; + +struct sigframe +{ + /* Sig handler's return address */ + Addr retaddr; + + Int sigNo; + Addr psigInfo; /* code or pointer to sigContext */ + Addr puContext; /* points to uContext */ + Addr addr; /* "secret" 4th argument */ + Addr phandler; /* "action" or "handler" */ + + /* pointed to by puContext */ + struct vki_ucontext uContext; + + vki_siginfo_t sigInfo; + + struct _vki_fpstate fpstate; + + struct vg_sigframe vg; +}; + + +/*------------------------------------------------------------*/ +/*--- Creating signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Create a plausible-looking sigcontext from the thread's + Vex guest state. +*/ +static +void synth_ucontext(ThreadId tid, const vki_siginfo_t *si, + UWord trapno, UWord err, const vki_sigset_t *set, + struct vki_ucontext *uc, struct _vki_fpstate *fpstate) +{ + ThreadState *tst = VG_(get_ThreadState)(tid); + struct vki_mcontext *sc = &uc->uc_mcontext; + + VG_(memset)(uc, 0, sizeof(*uc)); + + uc->uc_flags = 0; + uc->uc_link = 0; + uc->uc_sigmask = *set; + uc->uc_stack = tst->altstack; + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); + +# define SC2(reg,REG) sc->reg = tst->arch.vex.guest_##REG + SC2(gs,GS); + SC2(fs,FS); + SC2(es,ES); + SC2(ds,DS); + + SC2(edi,EDI); + SC2(esi,ESI); + SC2(ebp,EBP); + SC2(esp,ESP); + SC2(ebx,EBX); + SC2(edx,EDX); + SC2(ecx,ECX); + SC2(eax,EAX); + + SC2(eip,EIP); + SC2(cs,CS); + sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); + SC2(ss,SS); + sc->trapno = trapno; + sc->err = err; +// sc->addr = (UWord)si->si_addr; + sc->fpformat = VKI_FPFMT_NODEV; + sc->len = sizeof(*sc); + sc->ownedfp = VKI_FPOWNED_NONE; +# undef SC2 + +// sc->cr2 = (UInt)si->_sifields._sigfault._addr; +} + + +/* 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; + NSegment const* stackseg = NULL; + + if (VG_(extend_stack)(tid, addr)) { + stackseg = VG_(am_find_nsegment)(addr); + if (0 && stackseg) + VG_(printf)("frame=%#lx seg=%#lx-%#lx\n", + addr, stackseg->start, stackseg->end); + } + + if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) { + VG_(message)( + Vg_UserMsg, + "Can't extend stack to %#lx during signal delivery for thread %d:\n", + addr, tid); + if (stackseg == NULL) + VG_(message)(Vg_UserMsg, " no stack segment\n"); + else + VG_(message)(Vg_UserMsg, " too small or bad protection modes\n"); + + /* set SIGSEGV to default handler */ + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault_mapping)(tid, addr); + + /* The whole process should be about to die, since the default + action of SIGSEGV to kill the whole process. */ + return False; + } + + /* For tracking memory events, indicate the entire frame has been + allocated. */ + VG_TRACK( new_mem_stack_signal, addr - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB, tid ); + + return True; +} + + +/* Build the Valgrind-specific part of a signal frame. */ + +static void build_vg_sigframe(struct vg_sigframe *frame, + ThreadState *tst, + const vki_sigset_t *mask, + UInt flags, + Int sigNo) +{ + frame->sigNo_private = sigNo; + frame->magicPI = 0x31415927; + frame->vex_shadow1 = tst->arch.vex_shadow1; + frame->vex_shadow2 = tst->arch.vex_shadow2; + /* HACK ALERT */ + frame->vex = tst->arch.vex; + /* end HACK ALERT */ + frame->mask = tst->sig_mask; + frame->handlerflags = flags; + frame->magicE = 0x27182818; +} + +static Addr build_sigframe(ThreadState *tst, + Addr esp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, UInt flags, + const vki_sigset_t *mask, + void *restorer) +{ + struct sigframe *frame; + Addr esp = esp_top_of_frame; + Int sigNo = siginfo->si_signo; + UWord trapno; + UWord err; + + esp -= sizeof(*frame); + esp = VG_ROUNDDN(esp, 16); + frame = (struct sigframe *)esp; + + if (!extend(tst, esp, sizeof(*frame))) + return esp_top_of_frame; + + /* retaddr, siginfo, uContext fields are to be written */ + VG_TRACK( pre_mem_write, Vg_CoreSignal, tst->tid, "signal handler frame", + esp, offsetof(struct sigframe, vg) ); + + frame->sigNo = sigNo; + frame->retaddr = (Addr)&VG_(x86_freebsd_SUBST_FOR_sigreturn); + if ((flags & VKI_SA_SIGINFO) == 0) + frame->psigInfo = (Addr)siginfo->si_code; + else + frame->psigInfo = (Addr)&frame->sigInfo; + VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t)); + + if (siguc != NULL) { + trapno = siguc->uc_mcontext.trapno; + err = siguc->uc_mcontext.err; + } else { + trapno = 0; + err = 0; + } + + synth_ucontext(tst->tid, siginfo, trapno, err, mask, + &frame->uContext, &frame->fpstate); + + if (sigNo == VKI_SIGILL && siginfo->si_code > 0) + frame->sigInfo.si_addr = (void*)tst->arch.vex.guest_EIP; + + VG_TRACK( post_mem_write, Vg_CoreSignal, tst->tid, + esp, offsetof(struct sigframe, vg) ); + + build_vg_sigframe(&frame->vg, tst, mask, flags, sigNo); + + return esp; +} + +/* EXPORTED */ +void VG_(sigframe_create)( ThreadId tid, + Bool on_altstack, + Addr esp_top_of_frame, + const vki_siginfo_t *siginfo, + const struct vki_ucontext *siguc, + void *handler, + UInt flags, + const vki_sigset_t *mask, + void *restorer ) +{ + Addr esp; + ThreadState* tst = VG_(get_ThreadState)(tid); + + esp = build_sigframe(tst, esp_top_of_frame, siginfo, siguc, handler, + flags, mask, restorer); + + /* Set the thread so it will next run the handler. */ + /* tst->m_esp = esp; also notify the tool we've updated ESP */ + VG_(set_SP)(tid, esp); + VG_TRACK( post_reg_write, Vg_CoreSignal, tid, VG_O_STACK_PTR, sizeof(Addr)); + + tst->arch.vex.guest_EIP = (Addr) handler; +// tst->arch.vex.guest_EDI = (ULong) siginfo->si_signo; + /* This thread needs to be marked runnable, but we leave that the + caller to do. */ + + if (0) + VG_(printf)("pushed signal frame; %%ESP now = %#lx, " + "next %%EIP = %#x, status=%d\n", + esp, tst->arch.vex.guest_EIP, tst->status); +} + + +/*------------------------------------------------------------*/ +/*--- Destroying signal frames ---*/ +/*------------------------------------------------------------*/ + +/* Return False and don't do anything, just set the client to take a + segfault, if it looks like the frame is corrupted. */ +static +Bool restore_vg_sigframe ( ThreadState *tst, + struct vg_sigframe *frame, Int *sigNo ) +{ + if (frame->magicPI != 0x31415927 || + frame->magicE != 0x27182818) { + VG_(message)(Vg_UserMsg, "Thread %d return signal frame " + "corrupted. Killing process.", tst->tid); + VG_(set_default_handler)(VKI_SIGSEGV); + VG_(synth_fault)(tst->tid); + *sigNo = VKI_SIGSEGV; + return False; + } + tst->sig_mask = frame->mask; + tst->tmp_sig_mask = frame->mask; + tst->arch.vex_shadow1 = frame->vex_shadow1; + tst->arch.vex_shadow2 = frame->vex_shadow2; + /* HACK ALERT */ + tst->arch.vex = frame->vex; + /* end HACK ALERT */ + *sigNo = frame->sigNo_private; + return True; +} + +static +void restore_sigcontext( ThreadState *tst, + struct vki_mcontext *sc, + struct _vki_fpstate *fpstate ) +{ + tst->arch.vex.guest_EAX = sc->eax; + tst->arch.vex.guest_ECX = sc->ecx; + tst->arch.vex.guest_EDX = sc->edx; + tst->arch.vex.guest_EBX = sc->ebx; + tst->arch.vex.guest_EBP = sc->ebp; + tst->arch.vex.guest_ESP = sc->esp; + tst->arch.vex.guest_ESI = sc->esi; + tst->arch.vex.guest_EDI = sc->edi; +//:: tst->arch.vex.guest_eflags = sc->eflags; + tst->arch.vex.guest_EIP = sc->eip; + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; + tst->arch.vex.guest_DS = sc->ds; + tst->arch.vex.guest_ES = sc->es; + tst->arch.vex.guest_FS = sc->fs; + tst->arch.vex.guest_GS = sc->gs; + VG_(memcpy)(fpstate, &sc->fpstate, sizeof(*fpstate)); +} + + +static +SizeT restore_sigframe ( ThreadState *tst, + struct sigframe *frame, Int *sigNo ) +{ + if (restore_vg_sigframe(tst, &frame->vg, sigNo)) + restore_sigcontext(tst, &frame->uContext.uc_mcontext, &frame->fpstate); + + return sizeof(*frame); +} + +/* EXPORTED */ +void VG_(sigframe_destroy)( ThreadId tid ) +{ + Addr esp; + ThreadState* tst; + SizeT size; + Int sigNo; + + tst = VG_(get_ThreadState)(tid); + + /* Correctly reestablish the frame base address. */ + esp = tst->arch.vex.guest_ESP; + esp += 8; /* Clean up stack from argument/ret passed to sigreturn(2) */ + + size = restore_sigframe(tst, (struct sigframe *)esp, &sigNo); + + VG_TRACK( die_mem_stack_signal, esp - VG_STACK_REDZONE_SZB, + size + VG_STACK_REDZONE_SZB ); + + if (VG_(clo_trace_signals)) + VG_(message)( + Vg_DebugMsg, + "VG_(signal_return) (thread %d): EIP=%#x\n", + tid, tst->arch.vex.guest_EIP); + + /* tell the tools */ + VG_TRACK( post_deliver_signal, tid, sigNo ); +} + +#endif // defined(VGP_x86_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c index e572f17cc..2a2980505 100644 --- a/coregrind/m_signals.c +++ b/coregrind/m_signals.c @@ -512,6 +512,22 @@ typedef struct SigQueue { srP->misc.AMD64.r_rbp = (ULong)(ss->__rbp); } +#elif defined(VGP_x86_freebsd) +# define VG_UCONTEXT_INSTR_PTR(uc) ((UWord)(uc)->uc_mcontext.eip) +# define VG_UCONTEXT_STACK_PTR(uc) ((UWord)(uc)->uc_mcontext.esp) +# define VG_UCONTEXT_FRAME_PTR(uc) ((UWord)(uc)->uc_mcontext.ebp) +# define VG_UCONTEXT_SYSCALL_NUM(uc) ((UWord)(uc)->uc_mcontext.eax) +# define VG_UCONTEXT_SYSCALL_SYSRES(uc) \ + /* Convert the value in uc_mcontext.eax into a SysRes. */ \ + VG_(mk_SysRes_x86_freebsd)( (uc)->uc_mcontext.eax, \ + (uc)->uc_mcontext.edx, ((uc)->uc_mcontext.eflags & 1) != 0 ? True : False) +# define VG_UCONTEXT_LINK_REG(uc) 0 /* What is an LR for anyway? */ +# define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc) \ + { (srP)->r_pc = (ULong)((uc)->uc_mcontext.eip); \ + (srP)->r_sp = (ULong)((uc)->uc_mcontext.esp); \ + (srP)->misc.X86.r_ebp = (uc)->uc_mcontext.ebp; \ + } + #elif defined(VGP_s390x_linux) # define VG_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.regs.psw.addr) @@ -528,6 +544,21 @@ typedef struct SigQueue { (srP)->misc.S390X.r_lr = (uc)->uc_mcontext.regs.gprs[14]; \ } +#elif defined(VGP_amd64_freebsd) +# define VG_UCONTEXT_INSTR_PTR(uc) ((uc)->uc_mcontext.rip) +# define VG_UCONTEXT_STACK_PTR(uc) ((uc)->uc_mcontext.rsp) +# define VG_UCONTEXT_FRAME_PTR(uc) ((uc)->uc_mcontext.rbp) +# define VG_UCONTEXT_SYSCALL_NUM(uc) ((uc)->uc_mcontext.rax) +# define VG_UCONTEXT_SYSCALL_SYSRES(uc) \ + /* Convert the value in uc_mcontext.rax into a SysRes. */ \ + VG_(mk_SysRes_amd64_freebsd)( (uc)->uc_mcontext.rax, \ + (uc)->uc_mcontext.rdx, ((uc)->uc_mcontext.rflags & 1) != 0 ? True : False ) +# define VG_UCONTEXT_LINK_REG(uc) 0 /* No LR on amd64 either */ +# define VG_UCONTEXT_TO_UnwindStartRegs(srP, uc) \ + { (srP)->r_pc = (uc)->uc_mcontext.rip; \ + (srP)->r_sp = (uc)->uc_mcontext.rsp; \ + (srP)->misc.AMD64.r_rbp = (uc)->uc_mcontext.rbp; \ + } #elif defined(VGP_mips32_linux) # define VG_UCONTEXT_INSTR_PTR(uc) ((UWord)(((uc)->uc_mcontext.sc_pc))) # define VG_UCONTEXT_STACK_PTR(uc) ((UWord)((uc)->uc_mcontext.sc_regs[29])) @@ -605,7 +636,7 @@ typedef struct SigQueue { #if defined(VGO_linux) # define VKI_SIGINFO_si_addr _sifields._sigfault._addr # define VKI_SIGINFO_si_pid _sifields._kill._pid -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) # define VKI_SIGINFO_si_addr si_addr # define VKI_SIGINFO_si_pid si_pid #else @@ -833,8 +864,10 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) /* always ask for SA_SIGINFO */ skss_flags |= VKI_SA_SIGINFO; +#ifdef VGO_linux /* use our own restorer */ skss_flags |= VKI_SA_RESTORER; +#endif /* Create SKSS entry for this signal. */ if (sig != VKI_SIGKILL && sig != VKI_SIGSTOP) @@ -858,6 +891,7 @@ void calculate_SKSS_from_SCSS ( SKSS* dst ) After a possible SCSS change, update SKSS and the kernel itself. ------------------------------------------------------------------ */ +#if defined(VGO_linux) || defined(VGO_darwin) // We need two levels of macro-expansion here to convert __NR_rt_sigreturn // to a number before converting it to a string... sigh. extern void my_sigreturn(void); @@ -996,6 +1030,7 @@ extern void my_sigreturn(void); asm( MY_SIGRETURN(__NR_rt_sigreturn) ); +#endif static void handle_SCSS_change ( Bool force_update ) @@ -1031,7 +1066,7 @@ static void handle_SCSS_change ( Bool force_update ) ksa.sa_flags = skss.skss_per_sig[sig].skss_flags; # if !defined(VGP_ppc32_linux) && \ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ - !defined(VGP_mips32_linux) && !defined(VGO_solaris) + !defined(VGP_mips32_linux) && !defined(VGO_solaris) && !defined(VGO_freebsd) ksa.sa_restorer = my_sigreturn; # endif /* Re above ifdef (also the assertion below), PaulM says: @@ -1078,6 +1113,7 @@ static void handle_SCSS_change ( Bool force_update ) # if !defined(VGP_ppc32_linux) && \ !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ !defined(VGP_mips32_linux) && !defined(VGP_mips64_linux) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) vg_assert(ksa_old.sa_restorer == my_sigreturn); # endif @@ -1199,6 +1235,7 @@ SysRes VG_(do_sys_sigaction) ( Int signo, old_act->sa_flags = scss.scss_per_sig[signo].scss_flags; old_act->sa_mask = scss.scss_per_sig[signo].scss_mask; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) old_act->sa_restorer = scss.scss_per_sig[signo].scss_restorer; # endif @@ -1212,6 +1249,7 @@ SysRes VG_(do_sys_sigaction) ( Int signo, scss.scss_per_sig[signo].scss_restorer = NULL; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) scss.scss_per_sig[signo].scss_restorer = new_act->sa_restorer; # endif @@ -1558,6 +1596,7 @@ void VG_(kill_self)(Int sigNo) sa.ksa_handler = VKI_SIG_DFL; sa.sa_flags = 0; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) sa.sa_restorer = 0; # endif @@ -1594,7 +1633,12 @@ static Bool is_signal_from_kernel(ThreadId tid, int signum, int si_code) // macros but we don't use them here because other platforms don't have // them. return ( si_code > VKI_SI_USER ? True : False ); - +#elif defined(VGO_freebsd) + // It looks like there's no reliable way to say where the signal came from + if (VG_(threads)[tid].status == VgTs_WaitSys) { + return False; + } else + return True; # 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: @@ -2278,7 +2322,7 @@ static int sanitize_si_code(int si_code) mask them off) sign extends them when exporting to user space so we do the same thing here. */ return (Short)si_code; -#elif defined(VGO_darwin) || defined(VGO_solaris) +#elif defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) return si_code; #else # error Unknown OS @@ -2904,6 +2948,7 @@ void pp_ksigaction ( vki_sigaction_toK_t* sa ) sa->ksa_handler, (UInt)sa->sa_flags, # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) sa->sa_restorer # else @@ -2927,6 +2972,7 @@ void VG_(set_default_handler)(Int signo) sa.ksa_handler = VKI_SIG_DFL; sa.sa_flags = 0; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) sa.sa_restorer = 0; # endif @@ -3047,6 +3093,7 @@ void VG_(sigstartup_actions) ( void ) tsa.ksa_handler = (void *)sync_signalhandler; tsa.sa_flags = VKI_SA_SIGINFO; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) tsa.sa_restorer = 0; # endif @@ -3075,6 +3122,7 @@ void VG_(sigstartup_actions) ( void ) scss.scss_per_sig[i].scss_restorer = NULL; # if !defined(VGP_x86_darwin) && !defined(VGP_amd64_darwin) && \ + !defined(VGP_x86_freebsd) && !defined(VGP_amd64_freebsd) && \ !defined(VGO_solaris) scss.scss_per_sig[i].scss_restorer = sa.sa_restorer; # endif diff --git a/coregrind/m_stacktrace.c b/coregrind/m_stacktrace.c index 24f1409dd..51c12fcec 100644 --- a/coregrind/m_stacktrace.c +++ b/coregrind/m_stacktrace.c @@ -94,7 +94,7 @@ do { \ /* ------------------------ x86 ------------------------- */ #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) #define N_FP_CF_VERIF 1021 // prime number so that size of fp_CF_verif is just below 4K or 8K @@ -500,7 +500,7 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, /* ----------------------- amd64 ------------------------ */ #if defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, /*OUT*/Addr* ips, UInt max_n_ips, @@ -638,6 +638,34 @@ UInt VG_(get_StackTrace_wrk) ( ThreadId tid_if_known, continue; } +#if defined(VGO_freebsd) + const NSegment *seg; + const HChar *filename = NULL; + int match = 0; + + seg = VG_(am_find_nsegment)(uregs.xip); + if (seg != NULL) { + filename = VG_(am_get_filename)(seg); + } + if (filename != NULL && VG_(strstr)(filename, "/libc.so")) { + match = 1; + } + if (match == 1 && fp_min <= uregs.xsp && + uregs.xsp <= fp_max - 1 * sizeof(UWord)) { + /* fp looks sane, so use it. */ + uregs.xip = (((UWord*)uregs.xsp)[0]); + if (0 == uregs.xip || 1 == uregs.xip) break; + if (fps) fps[i] = uregs.xsp; + uregs.xsp = uregs.xsp + sizeof(Addr) /*ra*/; + if (sps) sps[i] = uregs.xsp; + ips[i++] = uregs.xip - 1; /* -1: refer to calling insn, not the RA */ + if (debug) + VG_(printf)(" ipsFF[%d]=%#08lx\n", i-1, ips[i-1]); + uregs.xip = uregs.xip - 1; /* as per comment at the head of this loop */ + continue; + } +#endif + /* If VG_(use_CF_info) fails, it won't modify ip/sp/fp, so we can safely try the old-fashioned method. */ /* This bit is supposed to deal with frames resulting from diff --git a/coregrind/m_syscall.c b/coregrind/m_syscall.c index 5948cecf5..359a1ed15 100644 --- a/coregrind/m_syscall.c +++ b/coregrind/m_syscall.c @@ -331,6 +331,42 @@ SysRes VG_(mk_SysRes_amd64_solaris) ( Bool isErr, ULong val, ULong val2 ) return res; } + +#elif defined(VGO_freebsd) + +SysRes VG_(mk_SysRes_x86_freebsd) ( UInt val, UInt val2, Bool err ) { + SysRes r; + r._isError = err; + r._val = val; + r._val2 = val2; + return r; +} + +SysRes VG_(mk_SysRes_amd64_freebsd) ( ULong val, ULong val2, Bool err ) { + SysRes r; + r._isError = err; + r._val = val; + r._val2 = val2; + return r; +} + +/* Generic constructors. */ +SysRes VG_(mk_SysRes_Error) ( UWord err ) { + SysRes r; + r._val = err; + r._val2 = 0; + r._isError = True; + return r; +} + +SysRes VG_(mk_SysRes_Success) ( UWord res ) { + SysRes r; + r._val = res; + r._val2 = 0; + r._isError = False; + return r; +} + #else # error "Unknown OS" #endif @@ -600,6 +636,82 @@ asm( ".previous\n" ); +#elif defined(VGP_x86_freebsd) +/* Incoming args (syscall number + up to 8 args) are on the stack. + FreeBSD has a syscall called 'syscall' that takes all args (including + the syscall number) off the stack. Since we're called, the return + address is on the stack as expected, so we can just call syscall(2) + and it Just Works. Error is when carry is set. +*/ +extern ULong do_syscall_WRK ( + UWord syscall_no, + UWord a1, UWord a2, UWord a3, + UWord a4, UWord a5, UWord a6, + UWord a7, UWord a8, UInt *flags + ); +asm( +".text\n" +"do_syscall_WRK:\n" +" movl $0,%eax\n" /* syscall number = "syscall" (0) to avoid stack frobbing +*/ +" int $0x80\n" +" jb 1f\n" +" ret\n" +"1: movl 40(%esp),%ecx\n" /* store carry in *flags */ +" movl $1,(%ecx)\n" +" ret\n" +".previous\n" +); + +#elif defined(VGP_amd64_freebsd) +extern UWord do_syscall_WRK ( + UWord syscall_no, /* %rdi */ + UWord a1, /* %rsi */ + UWord a2, /* %rdx */ + UWord a3, /* %rcx */ + UWord a4, /* %r8 */ + UWord a5, /* %r9 */ + UWord a6, /* 8(%rsp) */ + UWord a7, /* 16(%rsp) */ + UWord a8, /* 24(%rsp) */ + UInt *flags, /* 32(%rsp) */ + UWord *rv2 /* 40(%rsp) */ + ); +asm( +".text\n" +"do_syscall_WRK:\n" + /* Convert function calling convention --> syscall calling + convention */ +" pushq %rbp\n" +" movq %rsp, %rbp\n" +" movq %rdi, %rax\n" /* syscall_no */ +" movq %rsi, %rdi\n" /* a1 */ +" movq %rdx, %rsi\n" /* a2 */ +" movq %rcx, %rdx\n" /* a3 */ +" movq %r8, %r10\n" /* a4 */ +" movq %r9, %r8\n" /* a5 */ +" movq 16(%rbp), %r9\n" /* a6 last arg from stack, account for %rbp */ +" movq 24(%rbp), %r11\n" /* a7 from stack */ +" pushq %r11\n" +" movq 32(%rbp), %r11\n" /* a8 from stack */ +" pushq %r11\n" +" subq $8,%rsp\n" /* fake return addr */ +" syscall\n" +" jb 1f\n" +" movq 48(%rbp),%rsi\n" +" movq %rdx, (%rsi)\n" +" movq %rbp, %rsp\n" +" popq %rbp\n" +" ret\n" +"1:\n" +" movq 40(%rbp), %rsi\n" +" movl $1,(%rsi)\n" +" movq %rbp, %rsp\n" +" popq %rbp\n" +" ret\n" +".previous\n" +); + #elif defined(VGP_x86_darwin) /* Incoming args (syscall number + up to 8 args) come in on the stack @@ -932,6 +1044,21 @@ SysRes VG_(do_syscall) ( UWord sysno, RegWord a1, RegWord a2, RegWord a3, UWord val = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6); return VG_(mk_SysRes_amd64_linux)( val ); +# elif defined(VGP_x86_freebsd) + ULong val; + UInt err = 0; + val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5, + a6, a7, a8, &err); + return VG_(mk_SysRes_x86_freebsd)( (UInt)val, (UInt)(val>>32), (err & 1) != 0 ? True : False); + +# elif defined(VGP_amd64_freebsd) + UWord val; + UWord val2 = 0; + UInt err = 0; + val = do_syscall_WRK(sysno, a1, a2, a3, a4, a5, + a6, a7, a8, &err, &val2); + return VG_(mk_SysRes_amd64_freebsd)( val, val2, (err & 1) != 0 ? True : False); + # elif defined(VGP_ppc32_linux) ULong ret = do_syscall_WRK(sysno,a1,a2,a3,a4,a5,a6); UInt val = (UInt)(ret>>32); diff --git a/coregrind/m_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h new file mode 100755 index 000000000..6ee6aa765 --- /dev/null +++ b/coregrind/m_syswrap/priv_syswrap-freebsd.h @@ -0,0 +1,279 @@ + +/*--------------------------------------------------------------------*/ +/*--- FreeBSD-specific syscalls stuff. priv_syswrap-freebsd.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __PRIV_SYSWRAP_FREEBSD_H +#define __PRIV_SYSWRAP_FREEBSD_H + +/* requires #include "priv_types_n_macros.h" */ + +// Clone-related functions +extern Word ML_(start_thread_NORETURN) ( void* arg ); +extern Addr ML_(allocstack) ( ThreadId tid ); +extern void ML_(call_on_new_stack_0_1) ( Addr stack, Addr retaddr, + void (*f)(Word), Word arg1 ); +extern SysRes ML_(do_fork) ( ThreadId tid ); +extern SysRes ML_(do_vfork) ( ThreadId tid ); +extern SysRes ML_(do_rfork) ( ThreadId tid, Int flags ); + + +DECL_TEMPLATE(freebsd, sys_syscall); +DECL_TEMPLATE(freebsd, sys_exit); +DECL_TEMPLATE(freebsd, sys_getfsstat4); +DECL_TEMPLATE(freebsd, sys_getfsstat); +DECL_TEMPLATE(freebsd, sys_mount); +DECL_TEMPLATE(freebsd, sys_unmount); +DECL_TEMPLATE(freebsd, sys_ptrace); +DECL_TEMPLATE(freebsd, sys_recvmsg); +DECL_TEMPLATE(freebsd, sys_sendmsg); +DECL_TEMPLATE(freebsd, sys_recvfrom); +DECL_TEMPLATE(freebsd, sys_accept); +DECL_TEMPLATE(freebsd, sys_getpeername); +DECL_TEMPLATE(freebsd, sys_getsockname); +DECL_TEMPLATE(freebsd, sys_chflags); +DECL_TEMPLATE(freebsd, sys_fchflags); +DECL_TEMPLATE(freebsd, sys_pipe); +DECL_TEMPLATE(freebsd, sys_pipe2); +DECL_TEMPLATE(freebsd, sys_ktrace); +DECL_TEMPLATE(freebsd, sys_getlogin); +DECL_TEMPLATE(freebsd, sys_setlogin); +DECL_TEMPLATE(freebsd, sys_reboot); +DECL_TEMPLATE(freebsd, sys_revoke); +DECL_TEMPLATE(freebsd, sys_sbrk); +DECL_TEMPLATE(freebsd, sys_sstk); +DECL_TEMPLATE(freebsd, sys_swapon); +DECL_TEMPLATE(freebsd, sys_getdtablesize); +DECL_TEMPLATE(freebsd, sys_socket); +DECL_TEMPLATE(freebsd, sys_connect); +DECL_TEMPLATE(freebsd, sys_bind); +DECL_TEMPLATE(freebsd, sys_setsockopt); +DECL_TEMPLATE(freebsd, sys_listen); +DECL_TEMPLATE(freebsd, sys_getsockopt); +DECL_TEMPLATE(freebsd, sys_mkfifo); +DECL_TEMPLATE(freebsd, sys_sendto); +DECL_TEMPLATE(freebsd, sys_shutdown); +DECL_TEMPLATE(freebsd, sys_socketpair); +DECL_TEMPLATE(freebsd, sys_adjtime); +DECL_TEMPLATE(freebsd, sys_quotactl); +DECL_TEMPLATE(freebsd, sys_nfssvc); +DECL_TEMPLATE(freebsd, sys_getfh); +DECL_TEMPLATE(freebsd, sys_getdomainname); +DECL_TEMPLATE(freebsd, sys_setdomainname); +DECL_TEMPLATE(freebsd, sys_uname); +DECL_TEMPLATE(freebsd, sys_sysarch); +DECL_TEMPLATE(freebsd, sys_rtprio); +DECL_TEMPLATE(freebsd, sys_semsys); +DECL_TEMPLATE(freebsd, sys_msgsys); +DECL_TEMPLATE(freebsd, sys_shmsys); +DECL_TEMPLATE(freebsd, sys_pread); +DECL_TEMPLATE(freebsd, sys_pwrite); +DECL_TEMPLATE(freebsd, sys_ntp_adjtime); +DECL_TEMPLATE(freebsd, sys_setegid); +DECL_TEMPLATE(freebsd, sys_seteuid); +DECL_TEMPLATE(freebsd, sys_stat); +DECL_TEMPLATE(freebsd, sys_fstat); +DECL_TEMPLATE(freebsd, sys_lstat); +DECL_TEMPLATE(freebsd, sys_pathconf); +DECL_TEMPLATE(freebsd, sys_fpathconf); +DECL_TEMPLATE(freebsd, sys_getdirentries); +DECL_TEMPLATE(freebsd, sys_mmap); +DECL_TEMPLATE(freebsd, sys___syscall); +DECL_TEMPLATE(freebsd, sys_lseek); +DECL_TEMPLATE(freebsd, sys_truncate); +DECL_TEMPLATE(freebsd, sys_ftruncate); +DECL_TEMPLATE(freebsd, sys___sysctl); +DECL_TEMPLATE(freebsd, sys_undelete); +DECL_TEMPLATE(freebsd, sys_futimes); +DECL_TEMPLATE(freebsd, sys_nfs_fhopen); +DECL_TEMPLATE(freebsd, sys___semctl7); +DECL_TEMPLATE(freebsd, sys___semctl); +DECL_TEMPLATE(freebsd, sys_semget); +DECL_TEMPLATE(freebsd, sys_semop); +DECL_TEMPLATE(freebsd, sys_msgctl); +DECL_TEMPLATE(freebsd, sys_msgget); +DECL_TEMPLATE(freebsd, sys_msgsnd); +DECL_TEMPLATE(freebsd, sys_msgrcv); +DECL_TEMPLATE(freebsd, sys_shmat); +DECL_TEMPLATE(freebsd, sys_shmctl); +DECL_TEMPLATE(freebsd, sys_shmctl7); +DECL_TEMPLATE(freebsd, sys_shmdt); +DECL_TEMPLATE(freebsd, sys_shmget); +DECL_TEMPLATE(freebsd, sys_clock_gettime); +DECL_TEMPLATE(freebsd, sys_clock_settime); +DECL_TEMPLATE(freebsd, sys_clock_getres); +DECL_TEMPLATE(freebsd, sys_minherit); +DECL_TEMPLATE(freebsd, sys_rfork); +DECL_TEMPLATE(freebsd, sys_issetugid); +DECL_TEMPLATE(freebsd, sys_lchmod); +DECL_TEMPLATE(freebsd, sys_lutimes); +DECL_TEMPLATE(freebsd, sys_netbsd_msync); +DECL_TEMPLATE(freebsd, sys_nstat); +DECL_TEMPLATE(freebsd, sys_nfstat); +DECL_TEMPLATE(freebsd, sys_nlstat); +DECL_TEMPLATE(freebsd, sys_fhstatfs); +DECL_TEMPLATE(freebsd, sys_fhopen); +DECL_TEMPLATE(freebsd, sys_fhstat); +DECL_TEMPLATE(freebsd, sys_modnext); +DECL_TEMPLATE(freebsd, sys_modstat); +DECL_TEMPLATE(freebsd, sys_modfnext); +DECL_TEMPLATE(freebsd, sys_modfind); +DECL_TEMPLATE(freebsd, sys_kldload); +DECL_TEMPLATE(freebsd, sys_kldunload); +DECL_TEMPLATE(freebsd, sys_kldfind); +DECL_TEMPLATE(freebsd, sys_kldnext); +DECL_TEMPLATE(freebsd, sys_kldstat); +DECL_TEMPLATE(freebsd, sys_kldfirstmod); +DECL_TEMPLATE(freebsd, sys_setresuid); +DECL_TEMPLATE(freebsd, sys_setresgid); +DECL_TEMPLATE(freebsd, sys_aio_return); +DECL_TEMPLATE(freebsd, sys_aio_suspend); +DECL_TEMPLATE(freebsd, sys_aio_cancel); +DECL_TEMPLATE(freebsd, sys_aio_error); +DECL_TEMPLATE(freebsd, sys_aio_read); +DECL_TEMPLATE(freebsd, sys_aio_write); +DECL_TEMPLATE(freebsd, sys_lio_listio); +DECL_TEMPLATE(freebsd, sys_yield); +DECL_TEMPLATE(freebsd, sys_thr_sleep); +DECL_TEMPLATE(freebsd, sys_thr_wakeup); +DECL_TEMPLATE(freebsd, sys_munlockall); +DECL_TEMPLATE(freebsd, sys___getcwd); +DECL_TEMPLATE(freebsd, sys_sched_setparam); +DECL_TEMPLATE(freebsd, sys_sched_getparam); +DECL_TEMPLATE(freebsd, sys_sched_setscheduler); +DECL_TEMPLATE(freebsd, sys_sched_getscheduler); +DECL_TEMPLATE(freebsd, sys_sched_yield); +DECL_TEMPLATE(freebsd, sys_sched_get_priority_max); +DECL_TEMPLATE(freebsd, sys_sched_get_priority_min); +DECL_TEMPLATE(freebsd, sys_sched_rr_get_interval); +DECL_TEMPLATE(freebsd, sys_utrace); +DECL_TEMPLATE(freebsd, sys_kldsym); +DECL_TEMPLATE(freebsd, sys_jail); +DECL_TEMPLATE(freebsd, sys_sigprocmask); +DECL_TEMPLATE(freebsd, sys_sigsuspend); +DECL_TEMPLATE(freebsd, sys_sigaction); +DECL_TEMPLATE(freebsd, sys_sigpending); +DECL_TEMPLATE(freebsd, sys_sigreturn); +DECL_TEMPLATE(freebsd, sys_fake_sigreturn); +DECL_TEMPLATE(freebsd, sys_sigtimedwait); +DECL_TEMPLATE(freebsd, sys_sigwaitinfo); +DECL_TEMPLATE(freebsd, sys_getcontext); +DECL_TEMPLATE(freebsd, sys_setcontext); +DECL_TEMPLATE(freebsd, sys_swapcontext); +DECL_TEMPLATE(freebsd, sys___acl_get_file); +DECL_TEMPLATE(freebsd, sys___acl_set_file); +DECL_TEMPLATE(freebsd, sys___acl_get_fd); +DECL_TEMPLATE(freebsd, sys___acl_set_fd); +DECL_TEMPLATE(freebsd, sys___acl_delete_file); +DECL_TEMPLATE(freebsd, sys___acl_delete_fd); +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_file); +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_fd); +DECL_TEMPLATE(freebsd, sys___acl_get_link); +DECL_TEMPLATE(freebsd, sys___acl_set_link); +DECL_TEMPLATE(freebsd, sys___acl_delete_link); +DECL_TEMPLATE(freebsd, sys___acl_aclcheck_link); +DECL_TEMPLATE(freebsd, sys_extattrctl); +DECL_TEMPLATE(freebsd, sys_extattr_set_file); +DECL_TEMPLATE(freebsd, sys_extattr_get_file); +DECL_TEMPLATE(freebsd, sys_extattr_delete_file); +DECL_TEMPLATE(freebsd, sys_aio_waitcomplete); +DECL_TEMPLATE(freebsd, sys_getresuid); +DECL_TEMPLATE(freebsd, sys_getresgid); +DECL_TEMPLATE(freebsd, sys_kqueue); +DECL_TEMPLATE(freebsd, sys_kevent); +DECL_TEMPLATE(freebsd, sys_sendfile); +DECL_TEMPLATE(freebsd, sys_statfs6); +DECL_TEMPLATE(freebsd, sys_fstatfs6); +DECL_TEMPLATE(freebsd, sys_fhstatfs6); +DECL_TEMPLATE(freebsd, sys_thr_exit); +DECL_TEMPLATE(freebsd, sys_thr_self); +DECL_TEMPLATE(freebsd, sys_thr_set_name); +DECL_TEMPLATE(freebsd, sys_rtprio_thread); +DECL_TEMPLATE(freebsd, sys_fork); +DECL_TEMPLATE(freebsd, sys_vfork); +DECL_TEMPLATE(freebsd, sys_modfind); +DECL_TEMPLATE(freebsd, sys_modstat); +DECL_TEMPLATE(freebsd, sys_lkmnosys0); +DECL_TEMPLATE(freebsd, sys_lkmnosys1); +DECL_TEMPLATE(freebsd, sys_lkmnosys2); +DECL_TEMPLATE(freebsd, sys_lkmnosys3); +DECL_TEMPLATE(freebsd, sys_lkmnosys4); +DECL_TEMPLATE(freebsd, sys_lkmnosys5); +DECL_TEMPLATE(freebsd, sys_lkmnosys6); +DECL_TEMPLATE(freebsd, sys_lkmnosys7); +DECL_TEMPLATE(freebsd, sys_lkmnosys8); +DECL_TEMPLATE(freebsd, sys_sigaction4); +DECL_TEMPLATE(freebsd, sys_mmap7); +DECL_TEMPLATE(freebsd, sys_lseek7); +DECL_TEMPLATE(freebsd, sys_truncate7); +DECL_TEMPLATE(freebsd, sys_ftruncate7); +DECL_TEMPLATE(freebsd, sys_pread7); +DECL_TEMPLATE(freebsd, sys_pwrite7); +DECL_TEMPLATE(freebsd, sys__umtx_op); +DECL_TEMPLATE(freebsd, sys__umtx_lock); +DECL_TEMPLATE(freebsd, sys__umtx_unlock); +DECL_TEMPLATE(freebsd, sys_thr_kill2); +DECL_TEMPLATE(freebsd, sys_thr_wake); +DECL_TEMPLATE(freebsd, sys_shm_open); +DECL_TEMPLATE(freebsd, sys_shm_unlink); +DECL_TEMPLATE(freebsd, sys_eaccess); +DECL_TEMPLATE(freebsd, sys_cpuset); +DECL_TEMPLATE(freebsd, sys_cpuset_setid); +DECL_TEMPLATE(freebsd, sys_cpuset_getid); +DECL_TEMPLATE(freebsd, sys_cpuset_getaffinity); +DECL_TEMPLATE(freebsd, sys_cpuset_setaffinity); +DECL_TEMPLATE(freebsd, sys_faccessat); +DECL_TEMPLATE(freebsd, sys_fchmodat); +DECL_TEMPLATE(freebsd, sys_fchownat); +DECL_TEMPLATE(freebsd, sys_fexecve); +DECL_TEMPLATE(freebsd, sys_fstatat); +DECL_TEMPLATE(freebsd, sys_futimesat); +DECL_TEMPLATE(freebsd, sys_linkat); +DECL_TEMPLATE(freebsd, sys_mkdirat); +DECL_TEMPLATE(freebsd, sys_mkfifoat); +DECL_TEMPLATE(freebsd, sys_mknodat); +DECL_TEMPLATE(freebsd, sys_openat); +DECL_TEMPLATE(freebsd, sys_readlinkat); +DECL_TEMPLATE(freebsd, sys_renameat); +DECL_TEMPLATE(freebsd, sys_symlinkat); +DECL_TEMPLATE(freebsd, sys_unlinkat); +DECL_TEMPLATE(freebsd, sys_posix_openpt); +DECL_TEMPLATE(freebsd, sys_kenv); +DECL_TEMPLATE(freebsd, sys_uuidgen); +DECL_TEMPLATE(freebsd, sys_thr_new); +DECL_TEMPLATE(freebsd, sys_thr_kill); +DECL_TEMPLATE(freebsd, sys_thr_kill2); +DECL_TEMPLATE(freebsd, sys_fcntl); +DECL_TEMPLATE(freebsd, sys_ioctl); +DECL_TEMPLATE(freebsd, sys_mq_open); +DECL_TEMPLATE(freebsd, sys_mq_unlink); +#endif // __PRIV_SYSWRAP_FREEBSD_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/priv_types_n_macros.h b/coregrind/m_syswrap/priv_types_n_macros.h index 2dd95f68e..3e9f86f4d 100644 --- a/coregrind/m_syswrap/priv_types_n_macros.h +++ b/coregrind/m_syswrap/priv_types_n_macros.h @@ -52,6 +52,9 @@ /* Arguments for a syscall. */ typedef struct SyscallArgs { +#if defined(VGO_freebsd) + Word klass; +#endif Word sysno; RegWord arg1; RegWord arg2; @@ -102,6 +105,24 @@ typedef Int o_arg6; Int uu_arg7; Int uu_arg8; +# elif defined(VGP_x86_freebsd) + 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_freebsd) + Int o_arg1; + Int o_arg2; + Int o_arg3; + Int o_arg4; + Int o_arg5; + Int o_arg6; + Int s_arg7; + Int s_arg8; # elif defined(VGP_mips32_linux) Int o_arg1; Int o_arg2; @@ -185,7 +206,7 @@ typedef extern SyscallTableEntry* ML_(get_linux_syscall_entry)( UInt sysno ); -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) /* XXX: Darwin still uses the old scheme of exposing the table array(s) and size(s) directly to syswrap-main.c. This should be fixed. */ @@ -278,6 +299,9 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); #if defined(VGO_linux) || defined(VGO_solaris) # define GENX_(sysno, name) WRAPPER_ENTRY_X_(generic, sysno, name) # define GENXY(sysno, name) WRAPPER_ENTRY_XY(generic, sysno, name) +#elif defined(VGO_freebsd) +# 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) @@ -290,6 +314,11 @@ SyscallTableEntry* ML_(get_solaris_syscall_entry)( UInt sysno ); #define LINX_(sysno, name) WRAPPER_ENTRY_X_(linux, sysno, name) #define LINXY(sysno, name) WRAPPER_ENTRY_XY(linux, sysno, name) +/* Add a FreeBSD-specific, arch-independent wrapper to a syscall + table. */ +#define BSDX_(sysno, name) WRAPPER_ENTRY_X_(freebsd, sysno, name) +#define BSDXY(sysno, name) WRAPPER_ENTRY_XY(freebsd, sysno, name) + /* --------------------------------------------------------------------- Macros useful for writing wrappers concisely. These refer to the @@ -335,7 +364,7 @@ static inline UWord getRES ( SyscallStatus* st ) { return sr_Res(st->sres); } -#if defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) static inline UWord getRESHI ( SyscallStatus* st ) { vg_assert(st->what == SsComplete); vg_assert(!sr_isError(st->sres)); @@ -356,6 +385,13 @@ static inline UWord getERR ( SyscallStatus* st ) { status->sres = VG_(mk_SysRes_Success)(zzz); \ } while (0) +#ifdef VGO_freebsd +#define SET_STATUS_Success2(zzz, zzz2) \ + do { status->what = SsComplete; \ + status->sres = VG_(mk_SysRes_amd64_freebsd)(zzz, zzz2, False); \ + } while (0) +#endif + #define SET_STATUS_Failure(zzz) \ do { Word wzz = (Word)(zzz); \ /* Catch out wildly bogus error values. */ \ @@ -408,6 +444,28 @@ static inline UWord getERR ( SyscallStatus* st ) { # define PRA5(s,t,a) PRRAn(5,s,t,a) # define PRA6(s,t,a) PRRAn(6,s,t,a) +#elif defined(VGP_x86_freebsd) + /* 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_freebsd) + /* 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) + #elif defined(VGP_x86_darwin) || defined(VGP_x86_solaris) /* Up to 8 parameters, all on the stack. */ # define PRA1(s,t,a) PSRAn(1,s,t,a) diff --git a/coregrind/m_syswrap/syscall-amd64-freebsd.S b/coregrind/m_syswrap/syscall-amd64-freebsd.S new file mode 100755 index 000000000..ae03120c5 --- /dev/null +++ b/coregrind/m_syswrap/syscall-amd64-freebsd.S @@ -0,0 +1,203 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-amd64-freebsd.S ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics_asm.h" +#include "pub_core_vkiscnums_asm.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 +*/ + +/* from vki_arch.h */ +#define VKI_SIG_SETMASK 3 + +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): + /* save callee-saved regs */ + pushq %rbp + movq %rsp, %rbp + 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 + +1: /* Even though we can't take a signal until the sigprocmask completes, + start the range early. + If eip is in the range [1,2), the syscall hasn't been started yet */ + + /* Set the signal mask which should be current during the syscall. */ + /* Save and restore all 5 arg regs round the call. This is easier + than figuring out the minimal set to save/restore. */ + + movq $__NR_sigprocmask, %rax // syscall # + movq $VKI_SIG_SETMASK, %rdi // how + movq %rdx, %rsi // sysmask + movq %rcx, %rdx // postmask + syscall + + jb 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_R10(%r11), %r10 + 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 + /* (fake) return address. */ + 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. */ +2: syscall +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 */ + + /* save carry flag to VEX */ + xorq %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 + +4: /* Re-block signals. If eip is in [4,5), then the syscall + is complete and we needn't worry about it. */ + + movq $__NR_sigprocmask, %rax // syscall # + movq $VKI_SIG_SETMASK, %rdi // how + movq -32(%rbp), %rsi // postmask + xorq %rdx, %rdx // NULL + syscall + + jb 7f /* sigprocmask failed */ + +5: /* now safe from signals */ + + xorq %rax,%rax + movq -8(%rbp), %rdi + movq -16(%rbp), %rsi + movq -24(%rbp), %rdx + movq -32(%rbp), %rcx + movq -40(%rbp), %r8 + movq %rbp, %rsp + popq %rbp + ret + +7: /* failure: return 0x8000 | error code */ + orq $0x8000, %rax + movq -8(%rbp), %rdi + movq -16(%rbp), %rsi + movq -24(%rbp), %rdx + movq -32(%rbp), %rcx + movq -40(%rbp), %r8 + movq %rbp, %rsp + popq %rbp + ret + +.section .rodata +/* export the ranges so that + VG_(fixup_guest_state_after_syscall_interrupted) can do the + right thing */ + +.globl ML_(blksys_setup) +.globl ML_(blksys_restart) +.globl ML_(blksys_complete) +.globl ML_(blksys_committed) +.globl ML_(blksys_finished) +ML_(blksys_setup): .quad 1b +ML_(blksys_restart): .quad 2b +ML_(blksys_complete): .quad 3b +ML_(blksys_committed): .quad 4b +ML_(blksys_finished): .quad 5b +.previous + +#endif /* defined(VGP_amd64_freebsd) */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syscall-x86-freebsd.S b/coregrind/m_syswrap/syscall-x86-freebsd.S new file mode 100755 index 000000000..9fb5b6440 --- /dev/null +++ b/coregrind/m_syswrap/syscall-x86-freebsd.S @@ -0,0 +1,197 @@ + +/*--------------------------------------------------------------------*/ +/*--- Support for doing system calls. syscall-x86-freebsd.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. +*/ + +#if defined(VGP_x86_freebsd) + +#include "pub_core_basics_asm.h" +#include "pub_core_vkiscnums_asm.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 + +.globl ML_(do_syscall_for_client_WRK) +ML_(do_syscall_for_client_WRK): + /* establish stack frame */ + push %ebp + mov %esp, %ebp + subl $8, %esp /* 16-byte align stack */ + +1: /* Even though we can't take a signal until the + sigprocmask completes, start the range early. + If eip is in the range [1,2), the syscall hasn't been started yet */ + + /* Set the signal mask which should be current during the syscall. */ + pushl 20(%ebp) + pushl 16(%ebp) + pushl $VKI_SIG_SETMASK + pushl $0xcafebabe /* totally fake return address */ + movl $__NR_sigprocmask, %eax + int $0x80 + jc 7f /* sigprocmask 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. */ +2: int $0x80 /* UNIX (GrP fixme should be sysenter?) */ + +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 */ + /* 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 + +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_sigprocmask, %eax + int $0x80 /* should be sysenter? */ + jc 7f /* sigprocmask failed */ + addl $16,%esp + +5: /* now safe from signals */ + movl $0, %eax /* SUCCESS */ + movl %ebp, %esp + popl %ebp + ret + +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 + +.section .rodata +/* export the ranges so that + VG_(fixup_guest_state_after_syscall_interrupted) can do the + right thing */ + +.globl ML_(blksys_setup) +.globl ML_(blksys_restart) +.globl ML_(blksys_complete) +.globl ML_(blksys_committed) +.globl ML_(blksys_finished) +ML_(blksys_setup): .long 1b +ML_(blksys_restart): .long 2b +ML_(blksys_complete): .long 3b +ML_(blksys_committed): .long 4b +ML_(blksys_finished): .long 5b +.previous + +#endif // defined(VGP_x86_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-amd64-freebsd.c b/coregrind/m_syswrap/syswrap-amd64-freebsd.c new file mode 100755 index 000000000..8497d7bfd --- /dev/null +++ b/coregrind/m_syswrap/syswrap-amd64-freebsd.c @@ -0,0 +1,718 @@ + +/*--------------------------------------------------------------------*/ +/*--- Platform-specific syscalls stuff. syswrap-amd64-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_amd64_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_sigframe.h" +#include "pub_core_signals.h" +#include "pub_core_syscall.h" +#include "pub_core_syswrap.h" +#include "pub_core_tooliface.h" +#include "pub_core_stacks.h" // VG_(register_stack) + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ +#include "priv_syswrap-freebsd.h" /* for decls of freebsd-ish wrappers */ +#include "priv_syswrap-main.h" + +/* --------------------------------------------------------------------- + clone() handling + ------------------------------------------------------------------ */ + +/* Call f(arg1), but first switch stacks, using 'stack' as the new + stack, and use 'retaddr' as f's return-to address. Also, clear all + the integer registers before entering f. */ +__attribute__((noreturn)) +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); +// %rdi == stack +// %rsi == retaddr +// %rdx == f +// %rcx == arg1 +asm( +".text\n" +".globl vgModuleLocal_call_on_new_stack_0_1\n" +"vgModuleLocal_call_on_new_stack_0_1:\n" +" movq %rdi, %rsp\n" // set stack +" pushq %rsi\n" // retaddr to stack +" pushq %rdx\n" // f to stack +" pushq %rcx\n" // arg1 to stack +" movq $0, %rax\n" // zero all GP regs +" movq $0, %rbx\n" +" movq $0, %rcx\n" +" movq $0, %rdx\n" +" movq $0, %rsi\n" +" movq $0, %rdi\n" +" movq $0, %rbp\n" +" movq $0, %r8\n" +" movq $0, %r9\n" +" movq $0, %r10\n" +" movq $0, %r11\n" +" movq $0, %r12\n" +" movq $0, %r13\n" +" movq $0, %r14\n" +" movq $0, %r15\n" +" popq %rdi\n" // arg1 to correct arg reg +" ret\n" // jump to f +" ud2\n" // should never get here +".previous\n" +); + + +/* --------------------------------------------------------------------- + More thread stuff + ------------------------------------------------------------------ */ + +void VG_(cleanup_thread) ( ThreadArchState *arch ) +{ +} + +/* --------------------------------------------------------------------- + PRE/POST wrappers for amd64/FreeBSD-specific syscalls + ------------------------------------------------------------------ */ + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +PRE(sys_thr_new) +{ + static const Bool debug = False; + + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(tid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + SysRes res; + vki_sigset_t blockall, savedmask; + struct vki_thr_param tp; + Addr stk; + + PRINT("thr_new ( %#lx, %ld )",ARG1,ARG2); + PRE_REG_READ2(int, "thr_new", + struct thr_param *, param, + int, param_size); + + PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare)); + if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + VG_(memset)(&tp, 0, sizeof(tp)); + VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare)); + PRE_MEM_WRITE("thr_new(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long)); + PRE_MEM_WRITE("thr_new(child_tidptr)", (Addr)tp.child_tid, sizeof(long)); + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(tid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + /* Copy register state + + On linux, both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + On FreeBSD, thr_new arranges a direct call. We don't actually need any + of this gunk. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL rsp for the new thread, then + it actually gets a copy of the parent's rsp. + */ + /* We inherit our parent's guest state. */ + ctst->arch.vex = ptst->arch.vex; + ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1; + ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2; + + /* Make thr_new appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_RAX = 0; + ctst->arch.vex.guest_RDX = 0; + LibVEX_GuestAMD64_put_rflag_c(0, &ctst->arch.vex); + + ctst->os_state.parent = tid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* Linux has to guess, we don't */ + ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size; + ctst->client_stack_szB = tp.stack_size; + VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size); + + /* Assume the thr_new will succeed, and tell any tool that wants to + know that this thread has come into existence. If the thr_new + fails, we'll send out a ll_exit notification for it at the out: + label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, tid, ctid ); + + if (debug) + VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base); + ctst->arch.vex.guest_FS_CONST = (UWord)tp.tls_base; + tp.tls_base = 0; /* Don't have the kernel do it too */ + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Set the client state for scheduler to run libthr's trampoline */ + ctst->arch.vex.guest_RDI = (Addr)tp.arg; + /* XXX: align on 16-byte boundary? */ + ctst->arch.vex.guest_RSP = (Addr)tp.stack_base + tp.stack_size - 8; + ctst->arch.vex.guest_RIP = (Addr)tp.start_func; + + /* But this is for thr_new() to run valgrind's trampoline */ + tp.start_func = (void *)ML_(start_thread_NORETURN); + tp.arg = &VG_(threads)[ctid]; + + /* And valgrind's trampoline on its own stack */ + stk = ML_(allocstack)(ctid); + if (stk == (Addr)NULL) { + res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); + goto fail; + } + tp.stack_base = (void *)ctst->os_state.valgrind_stack_base; + tp.stack_size = (Addr)stk - (Addr)tp.stack_base; + + /* Create the new thread */ + res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp)); + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + +fail: + if (sr_isError(res)) { + /* thr_new failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } else { + + POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long)); + POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long)); + + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } + + /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */ + SET_STATUS_from_SysRes(res); +} + +PRE(sys_rfork) +{ + PRINT("sys_rfork ( %#lx )", ARG1 ); + PRE_REG_READ1(long, "rfork", int, flags); + + VG_(message)(Vg_UserMsg, "rfork() not implemented"); + VG_(unimplemented)("Valgrind does not support rfork()."); + + SET_STATUS_Failure(VKI_ENOSYS); +} + +PRE(sys_sigreturn) +{ + PRINT("sys_sigreturn ( %#lx )", ARG1); + PRE_REG_READ1(long, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); +} + +PRE(sys_fake_sigreturn) +{ + ThreadState* tst; + struct vki_ucontext *uc; + int rflags; + + PRINT("sys_sigreturn ( %#lx )", ARG1); + PRE_REG_READ1(long, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + /* Adjust esp to point to start of frame; skip back up over handler + ret addr */ + tst = VG_(get_ThreadState)(tid); + tst->arch.vex.guest_RSP -= sizeof(Addr); + + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + VG_(sigframe_destroy)(tid); + + /* For unclear reasons, it appears we need the syscall to return + without changing %EAX. Since %EAX is the return value, and can + denote either success or failure, we must set up so that the + driver logic copies it back unchanged. Also, note %EAX is of + the guest registers written by VG_(sigframe_destroy). */ + rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); + SET_STATUS_from_SysRes( VG_(mk_SysRes_amd64_freebsd)( tst->arch.vex.guest_RAX, + tst->arch.vex.guest_RDX, (rflags & 1) != 0 ? True : False) ); + + /* + * Signal handler might have changed the signal mask. Respect that. + */ + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* 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 some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + tst->arch.vex.guest_RAX = sc->rax; + tst->arch.vex.guest_RCX = sc->rcx; + tst->arch.vex.guest_RDX = sc->rdx; + tst->arch.vex.guest_RBX = sc->rbx; + tst->arch.vex.guest_RBP = sc->rbp; + tst->arch.vex.guest_RSP = sc->rsp; + tst->arch.vex.guest_RSI = sc->rsi; + tst->arch.vex.guest_RDI = sc->rdi; + tst->arch.vex.guest_R8 = sc->r8; + tst->arch.vex.guest_R9 = sc->r9; + tst->arch.vex.guest_R10 = sc->r10; + tst->arch.vex.guest_R11 = sc->r11; + tst->arch.vex.guest_R12 = sc->r12; + tst->arch.vex.guest_R13 = sc->r13; + tst->arch.vex.guest_R14 = sc->r14; + tst->arch.vex.guest_R15 = sc->r15; + tst->arch.vex.guest_RIP = sc->rip; + /* + * XXX: missing support for other flags. + */ + if (sc->rflags & 0x0001) + LibVEX_GuestAMD64_put_rflag_c(1, &tst->arch.vex); + else + LibVEX_GuestAMD64_put_rflag_c(0, &tst->arch.vex); +} + +static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + sc->rax = tst->arch.vex.guest_RAX; + sc->rcx = tst->arch.vex.guest_RCX; + sc->rdx = tst->arch.vex.guest_RDX; + sc->rbx = tst->arch.vex.guest_RBX; + sc->rbp = tst->arch.vex.guest_RBP; + sc->rsp = tst->arch.vex.guest_RSP; + sc->rsi = tst->arch.vex.guest_RSI; + sc->rdi = tst->arch.vex.guest_RDI; + sc->r8 = tst->arch.vex.guest_R8; + sc->r9 = tst->arch.vex.guest_R9; + sc->r10 = tst->arch.vex.guest_R10; + sc->r11 = tst->arch.vex.guest_R11; + sc->r12 = tst->arch.vex.guest_R12; + sc->r13 = tst->arch.vex.guest_R13; + sc->r14 = tst->arch.vex.guest_R14; + sc->r15 = tst->arch.vex.guest_R15; + sc->rip = tst->arch.vex.guest_RIP; +/* + Not supported by VEX. + sc->cs = tst->arch.vex.guest_CS; + sc->ss = tst->arch.vex.guest_SS; + sc->ds = tst->arch.vex.guest_DS; + sc->es = tst->arch.vex.guest_ES; + sc->fs = tst->arch.vex.guest_FS; + sc->gs = tst->arch.vex.guest_GS; +*/ + sc->rflags = LibVEX_GuestAMD64_get_rflags(&tst->arch.vex); +/* + not yet. + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); +*/ + sc->fpformat = VKI_FPFMT_NODEV; + sc->ownedfp = VKI_FPOWNED_NONE; + sc->len = sizeof(*sc); + VG_(memset)(sc->spare2, 0, sizeof(sc->spare2)); +} + +PRE(sys_getcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_getcontext ( %#lx )", ARG1); + PRE_REG_READ1(long, "getcontext", + struct vki_ucontext *, ucp); + PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + fill_mcontext(tst, &uc->uc_mcontext); + uc->uc_mcontext.rax = 0; + uc->uc_mcontext.rdx = 0; + uc->uc_mcontext.rflags &= ~0x0001; /* PSL_C */ + uc->uc_sigmask = tst->sig_mask; + VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__)); + SET_STATUS_Success(0); +} + +PRE(sys_setcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_setcontext ( %#lx )", ARG1); + PRE_REG_READ1(long, "setcontext", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + 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); + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + restore_mcontext(tst, &uc->uc_mcontext); + tst->sig_mask = uc->uc_sigmask; + + /* 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 some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +PRE(sys_swapcontext) +{ + struct vki_ucontext *ucp, *oucp; + ThreadState* tst; + + PRINT("sys_swapcontext ( %#lx, %#lx )", ARG1, ARG2); + PRE_REG_READ2(long, "swapcontext", + struct vki_ucontext *, oucp, struct vki_ucontext *, ucp); + + PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) ); + + oucp = (struct vki_ucontext *)ARG1; + ucp = (struct vki_ucontext *)ARG2; + if (oucp == NULL || ucp == NULL || ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + + /* + * Save the context. + */ + fill_mcontext(tst, &oucp->uc_mcontext); + oucp->uc_mcontext.rax = 0; + oucp->uc_mcontext.rdx = 0; + oucp->uc_mcontext.rflags &= ~0x0001; /* PSL_C */ + oucp->uc_sigmask = tst->sig_mask; + VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__)); + + /* + * Switch to new one. + */ + restore_mcontext(tst, &ucp->uc_mcontext); + tst->sig_mask = ucp->uc_sigmask; + + /* 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 some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + + +/* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */ + +/* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7 */ + +PRE(sys_mmap) +{ + SysRes r; + + PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, pad%ld, 0x%lx)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7 ); + PRE_REG_READ7(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, int, pad, unsigned long, pos); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG7 ); + SET_STATUS_from_SysRes(r); +} + +/* FreeBSD-7 introduces a "regular" version of mmap etc. */ +PRE(sys_mmap7) +{ + SysRes r; + + PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, 0x%lx)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6 ); + PRE_REG_READ6(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, unsigned long, pos); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 ); + SET_STATUS_from_SysRes(r); +} + +PRE(sys_lseek) +{ + PRINT("sys_lseek ( %ld, 0x%lx, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "lseek", + unsigned int, fd, int, pad, unsigned long, offset, + unsigned int, whence); +} + +PRE(sys_lseek7) +{ + PRINT("sys_lseek ( %ld, 0x%lx, %ld )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "lseek", + unsigned int, fd, unsigned long, offset, + unsigned int, whence); +} + +PRE(sys_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_read ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "read", + unsigned int, fd, char *, buf, vki_size_t, count, + int, pad, unsigned long, off); + + if (!ML_(fd_allowed)(ARG1, "read", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "read(buf)", ARG2, ARG3 ); +} + +POST(sys_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +PRE(sys_pread7) +{ + *flags |= SfMayBlock; + PRINT("sys_read ( %ld, %#lx, %lu, %lu )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "read", + unsigned int, fd, char *, buf, vki_size_t, count, + unsigned long, off); + + if (!ML_(fd_allowed)(ARG1, "read", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "read(buf)", ARG2, ARG3 ); +} + +POST(sys_pread7) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +PRE(sys_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_write ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "write", + unsigned int, fd, const char *, buf, vki_size_t, count, + int, pad, unsigned long, off); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "write", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "write(buf)", ARG2, ARG3 ); +} + +PRE(sys_pwrite7) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_write ( %ld, %#lx, %lu, %lu )", ARG1, ARG2, ARG3, ARG4); + PRE_REG_READ4(ssize_t, "write", + unsigned int, fd, const char *, buf, vki_size_t, count, + unsigned long, off); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "write", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && SimHintiS(SimHint_enable_outer, VG_(clo_sim_hints))) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "write(buf)", ARG2, ARG3 ); +} + +PRE(sys_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %ld, %lu )", ARG1,ARG3); + PRE_REG_READ3(long, "ftruncate", unsigned int, fd, int, pad, + unsigned int, length); +} + +PRE(sys_ftruncate7) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %ld, %lu )", ARG1,ARG2); + PRE_REG_READ2(long, "ftruncate", unsigned int, fd, + unsigned long, length); +} + +PRE(sys_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#lx(%s), %lu )", ARG1,(char *)ARG1,ARG3); + PRE_REG_READ3(long, "truncate", + const char *, path, int, pad, unsigned int, length); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +PRE(sys_truncate7) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#lx(%s), %lu )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "truncate", + const char *, path, unsigned long, length); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +PRE(sys_sysarch) +{ + ThreadState *tst; + void **p; + + PRINT("sys_sysarch ( %ld, %#lx )", ARG1, ARG2); + PRE_REG_READ2(int, "sysarch", + int, number, void *, args); + switch (ARG1) { + case VKI_AMD64_SET_FSBASE: + PRINT("sys_amd64_set_fsbase ( %#lx )", ARG2); + PRE_REG_READ1(long, "amd64_set_fsbase", void *, base) + + /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */ + tst = VG_(get_ThreadState)(tid); + p = (void**)ARG2; + tst->arch.vex.guest_FS_CONST = (UWord)*p; + /* "do" the syscall ourselves; the kernel never sees it */ + SET_STATUS_Success2((ULong)*p, tst->arch.vex.guest_RDX ); + + break; + case VKI_AMD64_GET_FSBASE: + PRINT("sys_amd64_get_fsbase ( %#lx )", ARG2); + PRE_REG_READ1(int, "amd64_get_fsbase", void *, basep) + PRE_MEM_WRITE( "amd64_get_fsbase(basep)", ARG2, sizeof(void *) ); + + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FS_CONST, tst->arch.vex.guest_RDX ); + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + case VKI_AMD64_GET_XFPUSTATE: + PRINT("sys_amd64_get_xfpustate ( %#lx )", ARG2); + PRE_REG_READ1(int, "amd64_get_xfpustate", void *, basep) + PRE_MEM_WRITE( "amd64_get_xfpustate(basep)", ARG2, sizeof(void *) ); + + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FPTAG[0], tst->arch.vex.guest_FPTAG[0] ); + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + default: + VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %ld", ARG1); + VG_(unimplemented) ("unhandled sysarch cmd"); + break; + } +} + +#undef PRE +#undef POST + +#endif /* defined(VGP_amd64_freebsd) */ + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-freebsd-variants.c b/coregrind/m_syswrap/syswrap-freebsd-variants.c new file mode 100755 index 000000000..a35eebfcb --- /dev/null +++ b/coregrind/m_syswrap/syswrap-freebsd-variants.c @@ -0,0 +1,97 @@ + +/*--------------------------------------------------------------------*/ +/*--- Handlers for syscalls on minor variants of Linux kernels. ---*/ +/*--- syswrap-linux-variants.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 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. +*/ + +/* The files syswrap-generic.c, syswrap-linux.c, syswrap-x86-linux.c, + syswrap-amd64-linux.c and syswrap-ppc32-linux.c, and associated + vki*.h header files, constitute Valgrind's model of how a vanilla + Linux kernel behaves with respect to syscalls. + + On a few occasions, it is useful to run with a kernel that has some + (minor) extensions to the vanilla model, either due to running on a + hacked kernel, or using a vanilla kernel which has incorporated a + custom kernel module. Rather than clutter the standard model, all + such variant handlers are placed in here. + + Unlike the C files for the standard model, this file should also + contain all constants/types needed for said wrappers. The vki*.h + headers should not be polluted with non-vanilla info. */ + +#if defined(VGO_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuginfo.h" // VG_(di_notify_*) +#include "pub_core_transtab.h" // VG_(discard_translations) +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcfile.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_mallocfree.h" +#include "pub_core_tooliface.h" +#include "pub_core_options.h" +#include "pub_core_scheduler.h" +#include "pub_core_signals.h" +#include "pub_core_syscall.h" + +#include "priv_types_n_macros.h" +#include "priv_syswrap-freebsd.h" + + +#if 0 /* think about ylock syscall etc */ +/* --------------------------------------------------------------- + BProc wrappers + ------------------------------------------------------------ */ + +/* Return 0 means hand to kernel, non-0 means fail w/ that value. */ +Int ML_(linux_variant_PRE_sys_bproc)( UWord arg1, UWord arg2, + UWord arg3, UWord arg4, + UWord arg5, UWord arg6 ) +{ + return 0; +} + +void ML_(linux_variant_POST_sys_bproc)( UWord arg1, UWord arg2, + UWord arg3, UWord arg4, + UWord arg5, UWord arg6 ) +{ +} +#endif + +#endif // defined(VGO_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end syswrap-linux-variants.c ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c new file mode 100755 index 000000000..7d02e5402 --- /dev/null +++ b/coregrind/m_syswrap/syswrap-freebsd.c @@ -0,0 +1,4440 @@ + +/*--------------------------------------------------------------------*/ +/*--- FreeBSD-specific syscalls, etc. syswrap-freebsd.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGO_freebsd) + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuginfo.h" // VG_(di_notify_*) +#include "pub_core_transtab.h" // VG_(discard_translations) +#include "pub_core_xarray.h" +#include "pub_core_clientstate.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcfile.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.h" +#include "pub_core_mallocfree.h" +#include "pub_core_tooliface.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 "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" +#include "priv_syswrap-freebsd.h" + + +// 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-freebsd", + "thread_wrapper(tid=%lld): entry\n", + (ULong)tidW); + + vg_assert(tst->status == VgTs_Init); + + /* make sure we get the CPU lock before doing anything significant */ + VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)"); + + if (0) + VG_(printf)("thread tid %d started: stack = %p\n", + tid, &tid); + + /* Make sure error reporting is enabled in the new thread. */ + tst->err_disablement_level = 0; + + 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-freebsd", + "thread_wrapper(tid=%lld): exit\n", + (ULong)tidW); + + /* Return to caller, still holding the lock. */ + return ret; +} + + +/* --------------------------------------------------------------------- + clone-related stuff + ------------------------------------------------------------------ */ + +/* Run a thread all the way to the end, then do appropriate exit actions + (this is the last-one-out-turn-off-the-lights bit). */ +static void run_a_thread_NORETURN ( Word tidW ) +{ + ThreadId tid = (ThreadId)tidW; + VgSchedReturnCode src; + Int c; + ThreadState* tst; + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n", + (ULong)tidW); + + tst = VG_(get_ThreadState)(tid); + vg_assert(tst); + + /* Run the thread all the way through. */ + src = thread_wrapper(tid); + + VG_(debugLog)(1, "syswrap-freebsd", + "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 the thread is exiting with errors disabled, complain loudly; + doing so is bad (does the user know this has happened?) Also, + in all cases, be paranoid and clear the flag anyway so that the + thread slot is safe in this respect if later reallocated. This + should be unnecessary since the flag should be cleared when the + slot is reallocated, in thread_wrapper(). */ + if (tst->err_disablement_level > 0) { + VG_(umsg)( + "WARNING: exiting thread has error reporting disabled.\n" + "WARNING: possibly as a result of some mistake in the use\n" + "WARNING: of the VALGRIND_DISABLE_ERROR_REPORTING macros.\n" + ); + VG_(debugLog)( + 1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%lld): " + "WARNING: exiting thread has err_disablement_level = %u\n", + (ULong)tidW, tst->err_disablement_level + ); + } + tst->err_disablement_level = 0; + + if (c == 1) { + + VG_(debugLog)(1, "syswrap-freebsd", + "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 { + + VG_(debugLog)(1, "syswrap-freebsd", + "run_a_thread_NORETURN(tid=%lld): " + "not last one standing\n", + (ULong)tidW); + + /* OK, thread is dead, but others still exist. Just exit. */ + + /* This releases the run lock */ + VG_(exit_thread)(tid); + vg_assert(tst->status == VgTs_Zombie); + + /* We have to use this sequence to terminate the thread to + prevent a subtle race. If VG_(exit_thread)() had left the + ThreadState as Empty, then it could have been reallocated, + reusing the stack while we're doing these last cleanups. + Instead, VG_(exit_thread) leaves it as Zombie to prevent + reallocation. We need to make sure we don't touch the stack + between marking it Empty and exiting. Hence the + assembler. */ +#if defined(VGP_x86_freebsd) /* FreeBSD has args on the stack */ + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movl %2, %%eax\n" /* set %eax = __NR_thr_exit */ + "movl %3, %%ebx\n" /* set %ebx = tst->os_state.exitcode */ + "pushl %%ebx\n" /* arg on stack */ + "pushl %%ebx\n" /* fake return address */ + "int $0x80\n" /* thr_exit(tst->os_state.exitcode) */ + "popl %%ebx\n" /* fake return address */ + "popl %%ebx\n" /* arg off stack */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_thr_exit), "m" (tst->os_state.exitcode) + : "eax", "ebx" + ); +#elif defined(VGP_amd64_freebsd) + asm volatile ( + "movl %1, %0\n" /* set tst->status = VgTs_Empty */ + "movq %2, %%rax\n" /* set %rax = __NR_thr_exit */ + "movq %3, %%rdi\n" /* set %rdi = tst->os_state.exitcode */ + "pushq %%rdi\n" /* fake return address */ + "syscall\n" /* thr_exit(tst->os_state.exitcode) */ + "popq %%rdi\n" /* fake return address */ + : "=m" (tst->status) + : "n" (VgTs_Empty), "n" (__NR_thr_exit), "m" (tst->os_state.exitcode) + : "rax", "rdi" + ); +#else +# error Unknown platform +#endif + + VG_(core_panic)("Thread exit failed?\n"); + } + + /*NOTREACHED*/ + vg_assert(0); +} + +Word ML_(start_thread_NORETURN) ( void* arg ) +{ + ThreadState* tst = (ThreadState*)arg; + ThreadId tid = tst->tid; + + run_a_thread_NORETURN ( (Word)tid ); + /*NOTREACHED*/ + vg_assert(0); +} + +/* Allocate a stack for this thread, if it doesn't already have one. + They're allocated lazily, and never freed. Returns the initial stack + pointer value to use, or 0 if allocation failed. */ +Addr ML_(allocstack)(ThreadId tid) +{ + ThreadState* tst = VG_(get_ThreadState)(tid); + VgStack* stack; + Addr initial_SP; + + /* Either the stack_base and stack_init_SP are both zero (in which + case a stack hasn't been allocated) or they are both non-zero, + in which case it has. */ + + if (tst->os_state.valgrind_stack_base == 0) + vg_assert(tst->os_state.valgrind_stack_init_SP == 0); + + if (tst->os_state.valgrind_stack_base != 0) + vg_assert(tst->os_state.valgrind_stack_init_SP != 0); + + /* If no stack is present, allocate one. */ + + if (tst->os_state.valgrind_stack_base == 0) { + stack = VG_(am_alloc_VgStack)( &initial_SP ); + if (stack) { + tst->os_state.valgrind_stack_base = (Addr)stack; + tst->os_state.valgrind_stack_init_SP = initial_SP; + } + } + + if (0) + VG_(printf)( "stack for tid %d at %p; init_SP=%p\n", + tid, + (void*)tst->os_state.valgrind_stack_base, + (void*)tst->os_state.valgrind_stack_init_SP ); + + return tst->os_state.valgrind_stack_init_SP; +} + +/* Allocate a stack for the main thread, and run it all the way to the + end. Although we already have a working VgStack + (VG_(interim_stack)) it's better to allocate a new one, so that + overflow detection works uniformly for all threads. +*/ +void VG_(main_thread_wrapper_NORETURN)(ThreadId tid) +{ + Addr sp; + VG_(debugLog)(1, "syswrap-freebsd", + "entering VG_(main_thread_wrapper_NORETURN)\n"); + + sp = ML_(allocstack)(tid); + +/* QQQ keep for amd64 redzone stuff */ +#if defined(VGP_ppc32_linux) + /* make a stack frame */ + sp -= 16; + sp &= ~0xF; + *(UWord *)sp = 0; +#elif defined(VGP_ppc64_linux) + /* make a stack frame */ + sp -= 112; + sp &= ~((Addr)0xF); + *(UWord *)sp = 0; +#endif + + /* If we can't even allocate the first thread's stack, we're hosed. + Give up. */ + vg_assert2(sp != 0, "Cannot allocate main thread's stack."); + + /* shouldn't be any other threads around yet */ + vg_assert( VG_(count_living_threads)() == 1 ); + + ML_(call_on_new_stack_0_1)( + (Addr)sp, /* stack */ + 0, /* bogus return address */ + run_a_thread_NORETURN, /* fn to call */ + (Word)tid /* arg to give it */ + ); + + /*NOTREACHED*/ + vg_assert(0); +} + + +/* Do a fork() */ +SysRes ML_(do_fork) ( ThreadId tid ) +{ + vki_sigset_t fork_saved_mask; + vki_sigset_t mask; + SysRes res; + + /* Block all signals during fork, so that we can fix things up in + the child without being interrupted. */ + VG_(sigfillset)(&mask); + VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask); + + VG_(do_atfork_pre)(tid); + + res = VG_(do_syscall0)( __NR_fork ); + + if (!sr_isError(res)) { + if (sr_Res(res) == 0) { + /* child */ + VG_(do_atfork_child)(tid); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); + + } + else { + /* parent */ + VG_(do_atfork_parent)(tid); + + if (VG_(clo_trace_syscalls)) + VG_(printf)(" clone(fork): process %d created child %ld\n", + VG_(getpid)(), sr_Res(res)); + + /* restore signal mask */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL); + } + } + + return res; +} + + +/* --------------------------------------------------------------------- + PRE/POST wrappers for arch-generic, Linux-specific syscalls + ------------------------------------------------------------------ */ + +// Nb: See the comment above the generic PRE/POST wrappers in +// m_syswrap/syswrap-generic.c for notes about how they work. + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +// Combine two 32-bit values into a 64-bit value +#define LOHI64(lo,hi) ( (lo) | ((ULong)(hi) << 32) ) + +PRE(sys_fork) +{ + PRINT("sys_fork ()"); + PRE_REG_READ0(int, "fork"); + + SET_STATUS_from_SysRes( ML_(do_fork)(tid) ); + if (SUCCESS) { + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } +} + +PRE(sys_vfork) +{ + PRINT("sys_vfork ()"); + PRE_REG_READ0(int, "vfork"); + + /* Pretend vfork == fork. Not true, but will have to do. */ + SET_STATUS_from_SysRes( ML_(do_fork)(tid) ); + if (SUCCESS) { + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } +} + +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, int, 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, int, *optlen); + if (optval_p != (Addr)NULL) { + ML_(buf_and_len_pre_check) ( tid, optval_p, optlen_p, + "getsockopt(optval)", + "getsockopt(optlen)" ); + } +} +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, + "getsockopt(optlen_out)" ); + } +} + +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, %#lx, %ld, %lu, %#lx, %ld )",ARG1,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_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, "sendmsg", (struct vki_msghdr *)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, "recvmsg", (struct vki_msghdr *)ARG2); +} +POST(sys_recvmsg) +{ + + ML_(generic_POST_sys_recvmsg)(tid, "recvmsg", (struct vki_msghdr *)ARG2, RES); +} + +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); +} + +/* --------------------------------------------------------------------- + *mount wrappers + ------------------------------------------------------------------ */ + +PRE(sys_mount) +{ + // Nb: depending on 'flags', the 'type' and 'data' args may be ignored. + // We are conservative and check everything, except the memory pointed to + // by 'data'. + *flags |= SfMayBlock; + PRINT( "sys_mount( %#lx, %#lx, %ld, %#lx )" ,ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "mount", + char *, type, char *, path, int, flags, + void *, data); + PRE_MEM_RASCIIZ( "mount(type)", ARG1); + PRE_MEM_RASCIIZ( "mount(path)", ARG2); +} + +PRE(sys_unmount) +{ + PRINT("sys_umount( %#lx, %ld )", ARG1, ARG2); + PRE_REG_READ2(long, "unmount", char *, path, int, flags); + PRE_MEM_RASCIIZ( "unmount(path)", ARG1); +} + +/* --------------------------------------------------------------------- + 16- and 32-bit uid/gid wrappers + ------------------------------------------------------------------ */ + +#if 0 +PRE(sys_setfsuid) +{ + PRINT("sys_setfsuid ( %ld )", ARG1); + PRE_REG_READ1(long, "setfsuid", vki_uid_t, uid); +} + +PRE(sys_setfsgid) +{ + PRINT("sys_setfsgid ( %ld )", ARG1); + PRE_REG_READ1(long, "setfsgid", vki_gid_t, gid); +} +#endif + +PRE(sys_setresuid) +{ + PRINT("sys_setresuid ( %ld, %ld, %ld )", ARG1, ARG2, ARG3); + PRE_REG_READ3(long, "setresuid", + vki_uid_t, ruid, vki_uid_t, euid, vki_uid_t, suid); +} + +PRE(sys_getresuid) +{ + PRINT("sys_getresuid ( %#lx, %#lx, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getresuid", + vki_uid_t *, ruid, vki_uid_t *, euid, vki_uid_t *, suid); + PRE_MEM_WRITE( "getresuid(ruid)", ARG1, sizeof(vki_uid_t) ); + PRE_MEM_WRITE( "getresuid(euid)", ARG2, sizeof(vki_uid_t) ); + PRE_MEM_WRITE( "getresuid(suid)", ARG3, sizeof(vki_uid_t) ); +} + +POST(sys_getresuid) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG1, sizeof(vki_uid_t) ); + POST_MEM_WRITE( ARG2, sizeof(vki_uid_t) ); + POST_MEM_WRITE( ARG3, sizeof(vki_uid_t) ); + } +} + +PRE(sys_setresgid) +{ + PRINT("sys_setresgid ( %ld, %ld, %ld )", ARG1, ARG2, ARG3); + PRE_REG_READ3(long, "setresgid", + vki_gid_t, rgid, vki_gid_t, egid, vki_gid_t, sgid); +} + +PRE(sys_getresgid) +{ + PRINT("sys_getresgid ( %#lx, %#lx, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getresgid", + vki_gid_t *, rgid, vki_gid_t *, egid, vki_gid_t *, sgid); + PRE_MEM_WRITE( "getresgid(rgid)", ARG1, sizeof(vki_gid_t) ); + PRE_MEM_WRITE( "getresgid(egid)", ARG2, sizeof(vki_gid_t) ); + PRE_MEM_WRITE( "getresgid(sgid)", ARG3, sizeof(vki_gid_t) ); +} + +POST(sys_getresgid) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG1, sizeof(vki_gid_t) ); + POST_MEM_WRITE( ARG2, sizeof(vki_gid_t) ); + POST_MEM_WRITE( ARG3, sizeof(vki_gid_t) ); + } +} + +/* --------------------------------------------------------------------- + miscellaneous wrappers + ------------------------------------------------------------------ */ + +#if 0 +PRE(sys_exit_group) +{ + ThreadId t; + ThreadState* tst; + + PRINT("exit_group( %ld )", ARG1); + PRE_REG_READ1(void, "exit_group", int, exit_code); + + 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 + || + /* not our group */ + VG_(threads)[t].os_state.threadgroup != tst->os_state.threadgroup + ) + continue; + + VG_(threads)[t].exitreason = VgSrc_ExitSyscall; + 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); +} +#endif + +/* On FreeBSD, if any thread calls exit(2), then they are all shut down, pretty + * much like linux's exit_group(). + */ +PRE(sys_exit) +{ + ThreadId t; + + PRINT("exit( %ld )", ARG1); + PRE_REG_READ1(void, "exit", int, status); + + /* Mark all threads (including this one) to exit. */ + for (t = 1; t < VG_N_THREADS; t++) { + if ( /* not alive */ VG_(threads)[t].status == VgTs_Empty ) + continue; + + VG_(threads)[t].exitreason = VgSrc_ExitThread; + 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_getlogin) +{ + PRINT("sys_getlogin ( %#lx, %ld )",ARG1,ARG2); + PRE_REG_READ2(long, "getlogin", + char *, buf, int, len); + PRE_MEM_WRITE( "getlogin(buf, len)", ARG1, ARG2 ); +} +POST(sys_getlogin) +{ + if (ARG1 != 0) { + POST_MEM_WRITE( ARG1, ARG2 ); + } +} +PRE(sys_setlogin) +{ + PRINT("sys_setlogin ( %#lx )",ARG1); + PRE_REG_READ1(long, "setlogin", char *, buf); + PRE_MEM_RASCIIZ( "setlogin(buf)", ARG1 ); +} +PRE(sys_mkfifo) +{ + PRINT("sys_mkfifo ( %#lx(%s), 0x%lx, 0x%lx )", ARG1, (char *)ARG1, ARG2, ARG3 ); + PRE_REG_READ2(long, "mkfifo", const char *, pathname, int, mode); + PRE_MEM_RASCIIZ( "mkfifo(pathname)", ARG1 ); +} + +/* int quotactl(const char *path, int cmd, int id, void *addr); */ + +PRE(sys_quotactl) +{ + PRINT("sys_quotactl (%#lx, %ld, %ld, %#lx )", ARG1,ARG2,ARG3, ARG4); + PRE_REG_READ4(long, "quotactl", + const char *, path, int, cmd, int, id, + void *, addr); + PRE_MEM_RASCIIZ( "quotactl(path)", ARG1 ); +} + +/* int getdomainname(char *domainname, int len); */ +PRE(sys_getdomainname) +{ + PRINT("sys_getdomainname ( %#lx, %ld )",ARG1,ARG2); + PRE_REG_READ2(long, "getdomainname", + char *, buf, int, len); + PRE_MEM_WRITE( "getdomainname(buf, len)", ARG1, ARG2 ); +} +POST(sys_getdomainname) +{ + if (ARG1 != 0) { + POST_MEM_WRITE( ARG1, ARG2 ); + } +} +/* int setdomainname(char *domainname, int len); */ +PRE(sys_setdomainname) +{ + PRINT("sys_setdomainname ( %#lx )",ARG1); + PRE_REG_READ1(long, "setdomainname", char *, buf); + PRE_MEM_RASCIIZ( "setdomainname(buf)", ARG1 ); +} + +PRE(sys_uname) +{ + PRINT("sys_uname ( %#lx )", ARG1); + PRE_REG_READ1(long, "uname", struct utsname *, buf); + PRE_MEM_WRITE( "uname(buf)", ARG1, sizeof(struct vki_utsname) ); +} + +POST(sys_uname) +{ + if (ARG1 != 0) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_utsname) ); + } +} + +PRE(sys_lstat) +{ + PRINT("sys_lstat ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "lstat", char *, file_name, struct stat *, buf); + PRE_MEM_RASCIIZ( "lstat(file_name)", ARG1 ); + PRE_MEM_WRITE( "lstat(buf)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_lstat) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); + } +} + +PRE(sys_stat) +{ + PRINT("sys_stat ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "stat", char *, file_name, struct stat *, buf); + PRE_MEM_RASCIIZ( "stat(file_name)", ARG1 ); + PRE_MEM_WRITE( "stat(buf)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_stat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); +} + +PRE(sys_fstat) +{ + PRINT("sys_fstat ( %ld, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "fstat", unsigned long, fd, struct stat *, buf); + PRE_MEM_WRITE( "fstat(buf)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_fstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); +} + +PRE(sys_pathconf) +{ + PRINT("sys_pathconf ( %#lx(%s), %ld )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "pathconf", char *, file_name, int, name); + PRE_MEM_RASCIIZ( "pathconf(file_name)", ARG1 ); +} + +PRE(sys_fpathconf) +{ + PRINT("sys_fpathconf ( %ld, %ld )",ARG1,ARG2); + PRE_REG_READ2(long, "fpathconf", int, fd, int, name); +} + +PRE(sys_lchmod) +{ + PRINT("sys_lchmod ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "lchmod", const char *, path, vki_mode_t, mode); + PRE_MEM_RASCIIZ( "lchmod(path)", ARG1 ); +} + +PRE(sys_issetugid) +{ + PRINT("sys_issetugid ()"); + PRE_REG_READ0(long, "issetugid"); +} + +PRE(sys_revoke) +{ + PRINT("sys_vhangup ( )"); + PRE_REG_READ0(long, "vhangup"); +} +PRE(sys_undelete) +{ + *flags |= SfMayBlock; + PRINT("sys_undelete ( %#lx(%s) )", ARG1,(char *)ARG1); + PRE_REG_READ1(long, "undelete", const char *, pathname); + PRE_MEM_RASCIIZ( "undelete(pathname)", ARG1 ); +} +PRE(sys_yield) +{ + *flags |= SfMayBlock; + PRINT("yield()"); + PRE_REG_READ0(long, "yield"); +} + +PRE(sys_sched_yield) +{ + *flags |= SfMayBlock; + PRINT("sched_yield()"); +} + +#if 0 +PRE(sys_sysinfo) +{ + PRINT("sys_sysinfo ( %#lx )",ARG1); + PRE_REG_READ1(long, "sysinfo", struct sysinfo *, info); + PRE_MEM_WRITE( "sysinfo(info)", ARG1, sizeof(struct vki_sysinfo) ); +} + +POST(sys_sysinfo) +{ + POST_MEM_WRITE( ARG1, sizeof(struct vki_sysinfo) ); +} +#endif + +/* int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 */ + +PRE(sys___sysctl) +{ + PRINT("sys_sysctl ( %#lx, %ld, %#lx, %#lx, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6 ); + PRE_REG_READ6(long, "__sysctl", int *, name, unsigned int, namelen, void *, old, + vki_size_t *, oldlenp, void *, new, vki_size_t, newlen); + PRE_MEM_READ("sysctl(name)", ARG1, ARG2 * sizeof(int)); + if (ARG5 != (UWord)NULL) + PRE_MEM_READ("sysctl(new)", (Addr)ARG5, ARG6); + if (ARG4 != (UWord)NULL) { + if (ARG3 != (UWord)NULL) { + PRE_MEM_READ("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + PRE_MEM_WRITE("sysctl(oldval)", (Addr)ARG3, *(vki_size_t *)ARG4); + } + PRE_MEM_WRITE("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t)); + } +} +POST(sys___sysctl) +{ + if (ARG4 != (UWord)NULL) { + POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t)); + if (ARG3 != (UWord)NULL) + POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4); + } +} + +PRE(sys_sendfile) +{ + *flags |= SfMayBlock; +#if defined(VGP_x86_freebsd) + PRINT("sys_sendfile ( %ld, %ld, %llu, %ld, %#lx, %#lx, %lu )", ARG1,ARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,ARG8); + PRE_REG_READ8(int, "sendfile", + int, fd, int, s, unsigned int, offset_low, + unsigned int, offset_high, size_t, nbytes, + void *, hdtr, vki_off_t *, sbytes, int, flags); +# define SF_ARG_SBYTES ARG7 +#elif defined(VGP_amd64_freebsd) + PRINT("sys_sendfile ( %ld, %ld, %lu, %ld, %#lx, %#lx, %lu )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7); + PRE_REG_READ7(int, "sendfile", + int, fd, int, s, vki_off_t, offset, size_t, nbytes, + void *, hdtr, vki_off_t *, sbytes, int, flags); +# define SF_ARG_SBYTES ARG6 +#else +# error Unknown platform +#endif + if (SF_ARG_SBYTES != 0) + PRE_MEM_WRITE( "sendfile(offset)", SF_ARG_SBYTES, sizeof(vki_off_t) ); +} +POST(sys_sendfile) +{ + if (SF_ARG_SBYTES != 0 ) { + POST_MEM_WRITE( SF_ARG_SBYTES, sizeof( vki_off_t ) ); + } +} +#undef SF_ARG_SBYTES + +/* int getdirentries(int fd, char *buf, u_int count, long *basep); */ +PRE(sys_getdirentries) +{ + *flags |= SfMayBlock; + PRINT("sys_getdents ( %ld, %#lx, %ld )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getdirentries", + unsigned int, fd, struct dirent *, dirp, + unsigned int, count); + PRE_MEM_WRITE( "getdirentries(dirp)", ARG2, ARG3 ); +} + +POST(sys_getdirentries) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG2, RES ); + if ( ARG4 != 0 ) + POST_MEM_WRITE( ARG4, sizeof (long)); + } +} + +PRE(sys_seteuid) +{ + PRINT("sys_seteuid ( %ld )", ARG1); + PRE_REG_READ1(long, "seteuid", vki_uid_t, uid); +} + +PRE(sys_setegid) +{ + PRINT("sys_setegid ( %ld )", ARG1); + PRE_REG_READ1(long, "setegid", vki_gid_t, gid); +} + +PRE(sys_lutimes) +{ + PRINT("sys_lutimes ( %#lx(%s), %#lx )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "lutimes", char *, filename, struct timeval *, tvp); + PRE_MEM_RASCIIZ( "lutimes(filename)", ARG1 ); + if (ARG2 != 0) + PRE_MEM_READ( "lutimes(tvp)", ARG2, sizeof(struct vki_timeval) ); +} + +PRE(sys_futimes) +{ + PRINT("sys_lutimes ( %ld, %#lx )", ARG1,ARG2); + PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, tvp); + if (ARG2 != 0) + PRE_MEM_READ( "futimes(tvp)", ARG2, sizeof(struct vki_timeval) ); +} + +PRE(sys_utrace) +{ + PRINT("sys_utrace ( %#lx, %lu )", ARG1, ARG2); + PRE_REG_READ2(long, "utrace", const void *, buf, vki_size_t, len); + PRE_MEM_READ( "utrace(buf,len)", ARG2, ARG3 ); +} + +PRE(sys_getdtablesize) +{ + PRINT("sys_getdtablesize ( )"); + PRE_REG_READ0(long, "getdtablesize"); +} + +PRE(sys_kqueue) +{ + PRINT("sys_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_nameless)(tid, RES); + } + } +} + +PRE(sys_kevent) +{ + /* struct kevent { + uintptr_t ident; -- identifier for this event + short filter; -- filter for event + u_short flags; -- action flags for kqueue + u_int fflags; -- filter flag value + intptr_t data; -- filter data value + void *udata; -- opaque user data identifier + }; + int kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, + const struct timespec *timeout); + */ + *flags |= SfMayBlock; + PRINT("sys_kevent ( %ld, %#lx, %ld, %#lx, %ld, %#lx )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6); + PRE_REG_READ6(long, "kevent", + int, fd, struct vki_kevent *, newev, int, num_newev, + struct vki_kevent *, ret_ev, int, num_retev, + struct timespec *, timeout); + if (ARG2 != 0 && ARG3 != 0) + PRE_MEM_READ( "kevent(changeevent)", ARG2, sizeof(struct vki_kevent)*ARG3 ); + if (ARG4 != 0 && ARG5 != 0) + PRE_MEM_WRITE( "kevent(events)", ARG4, sizeof(struct vki_kevent)*ARG5); + if (ARG6 != 0) + PRE_MEM_READ( "kevent(timeout)", + ARG6, sizeof(struct vki_timespec)); +} + +POST(sys_kevent) +{ + vg_assert(SUCCESS); + if (RES > 0) { + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent)*RES) ; + } +} + +PRE(sys___getcwd) +{ + PRINT("sys___getcwd ( %#lx, %lu )", ARG1,ARG2); + PRE_REG_READ2(long, "__getcwd", char *, buf, unsigned int, size); + PRE_MEM_WRITE( "__getcwd(buf)", ARG1, ARG2 ); +} + +POST(sys___getcwd) +{ + vg_assert(SUCCESS); + if (RES == 0) { + // QQQ it is unclear if this is legal or not, but the + // QQQ kernel just wrote it there... + // QQQ Why oh why didn't phk return the length from __getcwd()? + UInt len = VG_(strlen) ( (char *)ARG1 ) + 1; + POST_MEM_WRITE( ARG1, len ); + } +} + +// getfsstat() takes a length in bytes, but returns the number of structures +// returned, not a length. +PRE(sys_getfsstat4) +{ + PRINT("sys_getfsstat ( %#lx, %ld, %ld )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getfsstat", struct vki_statfs4 *, buf, long, len, int, flags); + PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 ); +} +POST(sys_getfsstat4) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_statfs4) ); + } +} + +PRE(sys_getfsstat) +{ + PRINT("sys_getfsstat ( %#lx, %ld, %ld )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "getfsstat", struct vki_statfs *, buf, long, len, int, flags); + PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 ); +} +POST(sys_getfsstat) +{ + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_statfs) ); + } +} + +PRE(sys_fhopen) +{ + PRINT("sys_open ( %#lx, %ld )",ARG1,ARG2); + PRE_REG_READ2(long, "open", + struct fhandle *, fhp, int, flags); + PRE_MEM_READ( "fhopen(fhp)", ARG1, sizeof(struct vki_fhandle) ); + + /* Otherwise handle normally */ + *flags |= SfMayBlock; +} + +POST(sys_fhopen) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "fhopen", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless)(tid, RES); + } +} + +PRE(sys_fhstat) +{ + PRINT("sys_fhstat ( %#lx, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "fhstat", struct fhandle *, fhp, struct stat *, buf); + PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstat(buf)", ARG2, sizeof(struct vki_stat) ); +} + +POST(sys_fhstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) ); +} + +PRE(sys_fhstatfs) +{ + PRINT("sys_fstatfs ( %#lx, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "fhstatfs", + struct fhandle *, fhp, struct statfs *, buf); + PRE_MEM_READ( "fhstatfs(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstatfs(buf)", ARG2, sizeof(struct vki_statfs) ); +} + +POST(sys_fhstatfs) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) ); +} + +PRE(sys_fhstatfs6) +{ + PRINT("sys_fstatfs6 ( %#lx, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "fhstatfs6", + struct fhandle *, fhp, struct statfs *, buf); + PRE_MEM_READ( "fhstatfs6(fhp)", ARG1, sizeof(struct vki_fhandle) ); + PRE_MEM_WRITE( "fhstatfs6(buf)", ARG2, sizeof(struct vki_statfs6) ); +} + +POST(sys_fhstatfs6) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) ); +} + +PRE(sys_fstatfs6) +{ + PRINT("sys_fstatfs6 ( %ld, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "fstatfs6", + unsigned int, fd, struct statfs *, buf); + PRE_MEM_WRITE( "fstatfs6(buf)", ARG2, sizeof(struct vki_statfs6) ); +} + +POST(sys_fstatfs6) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) ); +} + +PRE(sys_statfs6) +{ + PRINT("sys_statfs6 ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "statfs6", const char *, path, struct statfs *, buf); + PRE_MEM_RASCIIZ( "statfs6(path)", ARG1 ); + PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_statfs6) ); +} +POST(sys_statfs6) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) ); +} + +/* --------------------------------------------------------------------- + kld* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_kldload) +{ + PRINT("sys_kldload ( %#lx(%s) )", ARG1, (char *)ARG1); + PRE_REG_READ1(int, "kldload", const char *, "file"); + + PRE_MEM_RASCIIZ( "kldload(file)", ARG1 ); +} + +PRE(sys_kldunload) +{ + PRINT("sys_kldunload ( %ld )", ARG1); + PRE_REG_READ1(int, "kldunload", int, "fileid"); +} + +PRE(sys_kldfind) +{ + PRINT("sys_kldfind ( %#lx(%s) )", ARG1, (char *)ARG1); + PRE_REG_READ1(int, "kldfind", const char *, "file"); + + PRE_MEM_RASCIIZ( "kldfind(file)", ARG1 ); +} + +PRE(sys_kldnext) +{ + PRINT("sys_kldnext ( %ld )", ARG1); + PRE_REG_READ1(int, "kldnext", int, "fileid"); +} + +PRE(sys_kldsym) +{ + PRINT("sys_kldsym ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3 ); + PRE_REG_READ3(int, "kldsym", int, "fileid", int, "command", void*, "data"); + PRE_MEM_READ( "kldsym(data)", ARG3, sizeof(struct vki_kld_sym_lookup) ); + struct vki_kld_sym_lookup *kslp = (struct vki_kld_sym_lookup *)ARG3; + PRE_MEM_RASCIIZ( "kldsym(data.symname)", (Addr)kslp->symname ); +} +POST(sys_kldsym) +{ + struct vki_kld_sym_lookup *kslp = (struct vki_kld_sym_lookup *)ARG3; + POST_MEM_WRITE( (Addr)&kslp->symvalue, sizeof(kslp->symvalue) ); + POST_MEM_WRITE( (Addr)&kslp->symsize, sizeof(kslp->symsize) ); +} + +#if 0 +/* --------------------------------------------------------------------- + aio_* wrappers + ------------------------------------------------------------------ */ + +// Nb: this wrapper has to pad/unpad memory around the syscall itself, +// and this allows us to control exactly the code that gets run while +// the padding is in place. + +PRE(sys_io_setup) +{ + PRINT("sys_io_setup ( %lu, %#lx )", ARG1,ARG2); + PRE_REG_READ2(long, "io_setup", + unsigned, nr_events, vki_aio_context_t *, ctxp); + PRE_MEM_WRITE( "io_setup(ctxp)", ARG2, sizeof(vki_aio_context_t) ); +} + +POST(sys_io_setup) +{ + SizeT size; + struct vki_aio_ring *r; + + size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) + + ARG1*sizeof(struct vki_io_event)); + r = *(struct vki_aio_ring **)ARG2; + vg_assert(ML_(valid_client_addr)((Addr)r, size, tid, "io_setup")); + + ML_(notify_aspacem_and_tool_of_mmap)( (Addr)r, size, + VKI_PROT_READ | VKI_PROT_WRITE, + VKI_MAP_ANONYMOUS, -1, 0 ); + + POST_MEM_WRITE( ARG2, sizeof(vki_aio_context_t) ); +} + +// Nb: This wrapper is "Special" because we need 'size' to do the unmap +// after the syscall. We must get 'size' from the aio_ring structure, +// before the syscall, while the aio_ring structure still exists. (And we +// know that we must look at the aio_ring structure because Tom inspected the +// kernel and glibc sources to see what they do, yuk.) +// +// XXX This segment can be implicitly unmapped when aio +// file-descriptors are closed... +PRE(sys_io_destroy) +{ + struct vki_aio_ring *r; + SizeT size; + + PRINT("sys_io_destroy ( %llu )", (ULong)ARG1); + PRE_REG_READ1(long, "io_destroy", vki_aio_context_t, ctx); + + // If we are going to seg fault (due to a bogus ARG1) do it as late as + // possible... + r = (struct vki_aio_ring *)ARG1; + size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) + + r->nr*sizeof(struct vki_io_event)); + + SET_STATUS_from_SysRes( VG_(do_syscall1)(SYSNO, ARG1) ); + + if (SUCCESS && RES == 0) { + Bool d = VG_(am_notify_munmap)( ARG1, size ); + VG_TRACK( die_mem_munmap, ARG1, size ); + if (d) + VG_(discard_translations)( (Addr64)ARG1, (ULong)size, + "PRE(sys_io_destroy)" ); + } +} + +PRE(sys_io_getevents) +{ + *flags |= SfMayBlock; + PRINT("sys_io_getevents ( %llu, %lld, %lld, %#lx, %#lx )", + (ULong)ARG1,(Long)ARG2,(Long)ARG3,ARG4,ARG5); + PRE_REG_READ5(long, "io_getevents", + vki_aio_context_t, ctx_id, long, min_nr, long, nr, + struct io_event *, events, + struct timespec *, timeout); + if (ARG3 > 0) + PRE_MEM_WRITE( "io_getevents(events)", + ARG4, sizeof(struct vki_io_event)*ARG3 ); + if (ARG5 != 0) + PRE_MEM_READ( "io_getevents(timeout)", + ARG5, sizeof(struct vki_timespec)); +} +POST(sys_io_getevents) +{ + Int i; + vg_assert(SUCCESS); + if (RES > 0) { + POST_MEM_WRITE( ARG4, sizeof(struct vki_io_event)*RES ); + for (i = 0; i < RES; i++) { + const struct vki_io_event *vev = ((struct vki_io_event *)ARG4) + i; + const struct vki_iocb *cb = (struct vki_iocb *)(Addr)vev->obj; + + switch (cb->aio_lio_opcode) { + case VKI_IOCB_CMD_PREAD: + if (vev->result > 0) + POST_MEM_WRITE( cb->aio_buf, vev->result ); + break; + + case VKI_IOCB_CMD_PWRITE: + break; + + default: + VG_(message)(Vg_DebugMsg, + "Warning: unhandled io_getevents opcode: %u\n", + cb->aio_lio_opcode); + break; + } + } + } +} + +PRE(sys_io_submit) +{ + Int i; + + PRINT("sys_io_submit ( %llu, %ld, %#lx )", (ULong)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "io_submit", + vki_aio_context_t, ctx_id, long, nr, + struct iocb **, iocbpp); + PRE_MEM_READ( "io_submit(iocbpp)", ARG3, ARG2*sizeof(struct vki_iocb *) ); + if (ARG3 != 0) { + for (i = 0; i < ARG2; i++) { + struct vki_iocb *cb = ((struct vki_iocb **)ARG3)[i]; + PRE_MEM_READ( "io_submit(iocb)", (Addr)cb, sizeof(struct vki_iocb) ); + switch (cb->aio_lio_opcode) { + case VKI_IOCB_CMD_PREAD: + PRE_MEM_WRITE( "io_submit(PREAD)", cb->aio_buf, cb->aio_nbytes ); + break; + + case VKI_IOCB_CMD_PWRITE: + PRE_MEM_READ( "io_submit(PWRITE)", cb->aio_buf, cb->aio_nbytes ); + break; + + default: + VG_(message)(Vg_DebugMsg,"Warning: unhandled io_submit opcode: %u\n", + cb->aio_lio_opcode); + break; + } + } + } +} + +PRE(sys_io_cancel) +{ + PRINT("sys_io_cancel ( %llu, %#lx, %#lx )", (ULong)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "io_cancel", + vki_aio_context_t, ctx_id, struct iocb *, iocb, + struct io_event *, result); + PRE_MEM_READ( "io_cancel(iocb)", ARG2, sizeof(struct vki_iocb) ); + PRE_MEM_WRITE( "io_cancel(result)", ARG3, sizeof(struct vki_io_event) ); +} +POST(sys_io_cancel) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_io_event) ); +} + +/* --------------------------------------------------------------------- + inotify_* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_inotify_init) +{ + PRINT("sys_inotify_init ( )"); + PRE_REG_READ0(long, "inotify_init"); +} +POST(sys_inotify_init) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "inotify_init", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_nameless) (tid, RES); + } +} + +PRE(sys_inotify_add_watch) +{ + PRINT( "sys_inotify_add_watch ( %ld, %#lx, %lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "inotify_add_watch", int, fd, char *, path, int, mask); + PRE_MEM_RASCIIZ( "inotify_add_watch(path)", ARG2 ); +} + +PRE(sys_inotify_rm_watch) +{ + PRINT( "sys_inotify_rm_watch ( %ld, %lx )", ARG1,ARG2); + PRE_REG_READ2(long, "inotify_rm_watch", int, fd, int, wd); +} +#endif + +/* --------------------------------------------------------------------- + mq_* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_mq_open) +{ + PRINT("sys_mq_open( %#lx(%s), %ld, %lld, %#lx )", + ARG1,(char *)ARG1,ARG2,(ULong)ARG3,ARG4); + PRE_REG_READ4(long, "mq_open", + const char *, name, int, oflag, vki_mode_t, mode, + struct mq_attr *, attr); + PRE_MEM_RASCIIZ( "mq_open(name)", ARG1 ); + if ((ARG2 & VKI_O_CREAT) != 0 && ARG4 != 0) { + const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG4; + PRE_MEM_READ( "mq_open(attr->mq_maxmsg)", + (Addr)&attr->mq_maxmsg, sizeof(attr->mq_maxmsg) ); + PRE_MEM_READ( "mq_open(attr->mq_msgsize)", + (Addr)&attr->mq_msgsize, sizeof(attr->mq_msgsize) ); + } +} +POST(sys_mq_open) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "mq_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_mq_unlink) +{ + PRINT("sys_mq_unlink ( %#lx(%s) )", ARG1,(char *)ARG1); + PRE_REG_READ1(long, "mq_unlink", const char *, name); + PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 ); +} + +#if 0 +PRE(sys_mq_timedsend) +{ + *flags |= SfMayBlock; + PRINT("sys_mq_timedsend ( %ld, %#lx, %llu, %ld, %#lx )", + ARG1,ARG2,(ULong)ARG3,ARG4,ARG5); + PRE_REG_READ5(long, "mq_timedsend", + vki_mqd_t, mqdes, const char *, msg_ptr, vki_size_t, msg_len, + unsigned int, msg_prio, const struct timespec *, abs_timeout); + if (!ML_(fd_allowed)(ARG1, "mq_timedsend", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + PRE_MEM_READ( "mq_timedsend(msg_ptr)", ARG2, ARG3 ); + if (ARG5 != 0) + PRE_MEM_READ( "mq_timedsend(abs_timeout)", ARG5, + sizeof(struct vki_timespec) ); + } +} + +PRE(sys_mq_timedreceive) +{ + *flags |= SfMayBlock; + PRINT("sys_mq_timedreceive( %ld, %#lx, %llu, %#lx, %#lx )", + ARG1,ARG2,(ULong)ARG3,ARG4,ARG5); + PRE_REG_READ5(ssize_t, "mq_timedreceive", + vki_mqd_t, mqdes, char *, msg_ptr, vki_size_t, msg_len, + unsigned int *, msg_prio, + const struct timespec *, abs_timeout); + if (!ML_(fd_allowed)(ARG1, "mq_timedreceive", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + PRE_MEM_WRITE( "mq_timedreceive(msg_ptr)", ARG2, ARG3 ); + if (ARG4 != 0) + PRE_MEM_WRITE( "mq_timedreceive(msg_prio)", + ARG4, sizeof(unsigned int) ); + if (ARG5 != 0) + PRE_MEM_READ( "mq_timedreceive(abs_timeout)", + ARG5, sizeof(struct vki_timespec) ); + } +} +POST(sys_mq_timedreceive) +{ + POST_MEM_WRITE( ARG2, ARG3 ); + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(unsigned int) ); +} + +PRE(sys_mq_notify) +{ + PRINT("sys_mq_notify( %ld, %#lx )", ARG1,ARG2 ); + PRE_REG_READ2(long, "mq_notify", + vki_mqd_t, mqdes, const struct sigevent *, notification); + if (!ML_(fd_allowed)(ARG1, "mq_notify", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else if (ARG2 != 0) + PRE_MEM_READ( "mq_notify(notification)", + ARG2, sizeof(struct vki_sigevent) ); +} + +PRE(sys_mq_getsetattr) +{ + PRINT("sys_mq_getsetattr( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3 ); + PRE_REG_READ3(long, "mq_getsetattr", + vki_mqd_t, mqdes, const struct mq_attr *, mqstat, + struct mq_attr *, omqstat); + if (!ML_(fd_allowed)(ARG1, "mq_getsetattr", tid, False)) { + SET_STATUS_Failure( VKI_EBADF ); + } else { + if (ARG2 != 0) { + const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG2; + PRE_MEM_READ( "mq_getsetattr(mqstat->mq_flags)", + (Addr)&attr->mq_flags, sizeof(attr->mq_flags) ); + } + if (ARG3 != 0) + PRE_MEM_WRITE( "mq_getsetattr(omqstat)", ARG3, + sizeof(struct vki_mq_attr) ); + } +} +POST(sys_mq_getsetattr) +{ + if (ARG3 != 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_mq_attr) ); +} + +#endif + +/* --------------------------------------------------------------------- + clock_* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_clock_settime) +{ + PRINT("sys_clock_settime( %ld, %#lx )", ARG1,ARG2); + PRE_REG_READ2(long, "clock_settime", + vki_clockid_t, clk_id, const struct timespec *, tp); + PRE_MEM_READ( "clock_settime(tp)", ARG2, sizeof(struct vki_timespec) ); +} + +PRE(sys_clock_gettime) +{ + PRINT("sys_clock_gettime( %ld, %#lx )" , ARG1,ARG2); + PRE_REG_READ2(long, "clock_gettime", + vki_clockid_t, clk_id, struct timespec *, tp); + PRE_MEM_WRITE( "clock_gettime(tp)", ARG2, sizeof(struct vki_timespec) ); +} +POST(sys_clock_gettime) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) ); +} + +PRE(sys_clock_getres) +{ + PRINT("sys_clock_getres( %ld, %#lx )" , ARG1,ARG2); + // Nb: we can't use "RES" as the param name because that's a macro + // defined above! + PRE_REG_READ2(long, "clock_getres", + vki_clockid_t, clk_id, struct timespec *, res); + if (ARG2 != 0) + PRE_MEM_WRITE( "clock_getres(res)", ARG2, sizeof(struct vki_timespec) ); +} +POST(sys_clock_getres) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) ); +} + +#if 0 +PRE(sys_clock_nanosleep) +{ + *flags |= SfMayBlock|SfPostOnFail; + PRINT("sys_clock_nanosleep( %ld, %ld, %#lx, %#lx )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(int32_t, "clock_nanosleep", + vki_clockid_t, clkid, int, flags, + const struct timespec *, rqtp, struct timespec *, rmtp); + PRE_MEM_READ( "clock_nanosleep(rqtp)", ARG3, sizeof(struct vki_timespec) ); + if (ARG4 != 0) + PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG4, sizeof(struct vki_timespec) ); +} +POST(sys_clock_nanosleep) +{ + if (ARG4 != 0 && FAILURE && RES_unchecked == VKI_EINTR) + POST_MEM_WRITE( ARG4, sizeof(struct vki_timespec) ); +} + +/* --------------------------------------------------------------------- + timer_* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_timer_create) +{ + PRINT("sys_timer_create( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "timer_create", + vki_clockid_t, clockid, struct sigevent *, evp, + vki_timer_t *, timerid); + if (ARG2 != 0) + PRE_MEM_READ( "timer_create(evp)", ARG2, sizeof(struct vki_sigevent) ); + PRE_MEM_WRITE( "timer_create(timerid)", ARG3, sizeof(vki_timer_t) ); +} +POST(sys_timer_create) +{ + POST_MEM_WRITE( ARG3, sizeof(vki_timer_t) ); +} + +PRE(sys_timer_settime) +{ + PRINT("sys_timer_settime( %lld, %ld, %#lx, %#lx )", (ULong)ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "timer_settime", + vki_timer_t, timerid, int, flags, + const struct itimerspec *, value, + struct itimerspec *, ovalue); + PRE_MEM_READ( "timer_settime(value)", ARG3, + sizeof(struct vki_itimerspec) ); + if (ARG4 != 0) + PRE_MEM_WRITE( "timer_settime(ovalue)", ARG4, + sizeof(struct vki_itimerspec) ); +} +POST(sys_timer_settime) +{ + if (ARG4 != 0) + POST_MEM_WRITE( ARG4, sizeof(struct vki_itimerspec) ); +} + +PRE(sys_timer_gettime) +{ + PRINT("sys_timer_gettime( %lld, %#lx )", (ULong)ARG1,ARG2); + PRE_REG_READ2(long, "timer_gettime", + vki_timer_t, timerid, struct itimerspec *, value); + PRE_MEM_WRITE( "timer_gettime(value)", ARG2, + sizeof(struct vki_itimerspec)); +} +POST(sys_timer_gettime) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_itimerspec) ); +} + +PRE(sys_timer_getoverrun) +{ + PRINT("sys_timer_getoverrun( %#lx )", ARG1); + PRE_REG_READ1(long, "timer_getoverrun", vki_timer_t, timerid); +} + +PRE(sys_timer_delete) +{ + PRINT("sys_timer_delete( %#lx )", ARG1); + PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid); +} + +/* --------------------------------------------------------------------- + sched_* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_sched_setparam) +{ + PRINT("sched_setparam ( %ld, %#lx )", ARG1, ARG2 ); + PRE_REG_READ2(long, "sched_setparam", + vki_pid_t, pid, struct sched_param *, p); + PRE_MEM_READ( "sched_setparam(p)", ARG2, sizeof(struct vki_sched_param) ); +} +POST(sys_sched_setparam) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) ); +} + +PRE(sys_sched_getparam) +{ + PRINT("sched_getparam ( %ld, %#lx )", ARG1, ARG2 ); + PRE_REG_READ2(long, "sched_getparam", + vki_pid_t, pid, struct sched_param *, p); + PRE_MEM_WRITE( "sched_getparam(p)", ARG2, sizeof(struct vki_sched_param) ); +} +POST(sys_sched_getparam) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) ); +} + +PRE(sys_sched_getscheduler) +{ + PRINT("sys_sched_getscheduler ( %ld )", ARG1); + PRE_REG_READ1(long, "sched_getscheduler", vki_pid_t, pid); +} + +PRE(sys_sched_setscheduler) +{ + PRINT("sys_sched_setscheduler ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "sched_setscheduler", + vki_pid_t, pid, int, policy, struct sched_param *, p); + if (ARG3 != 0) + PRE_MEM_READ( "sched_setscheduler(p)", + ARG3, sizeof(struct vki_sched_param)); +} + +PRE(sys_sched_yield) +{ + *flags |= SfMayBlock; + PRINT("sched_yield()"); + PRE_REG_READ0(long, "sched_yield"); +} +#endif + +PRE(sys_sched_get_priority_max) +{ + PRINT("sched_get_priority_max ( %ld )", ARG1); + PRE_REG_READ1(long, "sched_get_priority_max", int, policy); +} + +PRE(sys_sched_get_priority_min) +{ + PRINT("sched_get_priority_min ( %ld )", ARG1); + PRE_REG_READ1(long, "sched_get_priority_min", int, policy); +} + +#if 0 +PRE(sys_sched_setaffinity) +{ + PRINT("sched_setaffinity ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3); + PRE_REG_READ3(long, "sched_setaffinity", + vki_pid_t, pid, unsigned int, len, unsigned long *, mask); + PRE_MEM_READ( "sched_setaffinity(mask)", ARG3, ARG2); +} + +PRE(sys_sched_getaffinity) +{ + PRINT("sched_getaffinity ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3); + PRE_REG_READ3(long, "sched_getaffinity", + vki_pid_t, pid, unsigned int, len, unsigned long *, mask); + PRE_MEM_WRITE( "sched_getaffinity(mask)", ARG3, ARG2); +} +POST(sys_sched_getaffinity) +{ + POST_MEM_WRITE(ARG3, ARG2); +} + +#endif + +/* --------------------------------------------------------------------- + miscellaneous wrappers + ------------------------------------------------------------------ */ + +PRE(sys_munlockall) +{ + *flags |= SfMayBlock; + PRINT("sys_munlockall ( )"); + PRE_REG_READ0(long, "munlockall"); +} + +// Pipe on freebsd doesn't have args, and uses dual returns! +PRE(sys_pipe) +{ + PRINT("sys_pipe ()"); +} +POST(sys_pipe) +{ + if (!ML_(fd_allowed)(RES, "pipe", tid, True) || + !ML_(fd_allowed)(RESHI, "pipe", tid, True)) { + VG_(close)(RES); + VG_(close)(RESHI); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) { + ML_(record_fd_open_nameless)(tid, RES); + ML_(record_fd_open_nameless)(tid, RESHI); + } + } +} + +PRE(sys_pipe2) +{ + PRINT("sys_pipe2 ( %#lx, %ld )", ARG1, ARG2); + PRE_REG_READ2(long, "pipe2", + int *, fildes, int, flags); + PRE_MEM_WRITE("pipe2(fildes)", ARG1, 2 * sizeof(int)); + +} +POST(sys_pipe2) +{ + int *fildes; + + if (RES != 0) + return; + + POST_MEM_WRITE(ARG1, 2 * sizeof(int)); + fildes = (int *)ARG1; + + if (!ML_(fd_allowed)(fildes[0], "pipe2", tid, True) || + !ML_(fd_allowed)(fildes[1], "pipe2", tid, True)) { + VG_(close)(fildes[0]); + VG_(close)(fildes[1]); + SET_STATUS_Failure( VKI_EMFILE ); + } else if (VG_(clo_track_fds)) { + ML_(record_fd_open_nameless)(tid, fildes[0]); + ML_(record_fd_open_nameless)(tid, fildes[1]); + } +} + +#if 0 +PRE(sys_quotactl) +{ + PRINT("sys_quotactl (0x%lx, %#lx, 0x%lx, 0x%lx )", ARG1,ARG2,ARG3, ARG4); + PRE_REG_READ4(long, "quotactl", + unsigned int, cmd, const char *, special, vki_qid_t, id, + void *, addr); + PRE_MEM_RASCIIZ( "quotactl(special)", ARG2 ); +} + +PRE(sys_waitid) +{ + *flags |= SfMayBlock; + PRINT("sys_waitid( %ld, %ld, %#lx, %ld, %#lx )", ARG1,ARG2,ARG3,ARG4,ARG5); + PRE_REG_READ5(int32_t, "sys_waitid", + int, which, vki_pid_t, pid, struct vki_siginfo *, infop, + int, options, struct vki_rusage *, ru); + PRE_MEM_WRITE( "waitid(infop)", ARG3, sizeof(struct vki_siginfo) ); + if (ARG5 != 0) + PRE_MEM_WRITE( "waitid(ru)", ARG5, sizeof(struct vki_rusage) ); +} +POST(sys_waitid) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_siginfo) ); + if (ARG5 != 0) + POST_MEM_WRITE( ARG5, sizeof(struct vki_rusage) ); +} + +/* --------------------------------------------------------------------- + utime wrapper + ------------------------------------------------------------------ */ + +PRE(sys_utime) +{ + *flags |= SfMayBlock; + PRINT("sys_utime ( %#lx, %#lx )", ARG1,ARG2); + PRE_REG_READ2(long, "utime", char *, filename, struct utimbuf *, buf); + PRE_MEM_RASCIIZ( "utime(filename)", ARG1 ); + if (ARG2 != 0) + PRE_MEM_READ( "utime(buf)", ARG2, sizeof(struct vki_utimbuf) ); +} + +#endif + +/* --------------------------------------------------------------------- + thr* wrappers + ------------------------------------------------------------------ */ + +PRE(sys_thr_self) +{ + PRINT( "sys_thr_self ( %#lx )", ARG1 ); + PRE_REG_READ1(long, "thr_self", long *, "id"); + PRE_MEM_WRITE( "thr_self()", ARG1, sizeof(long)); +} +POST(sys_thr_self) +{ + POST_MEM_WRITE( ARG1, sizeof(long)); +} + +PRE(sys_thr_exit) +{ + ThreadState *tst; + + PRINT( "sys_thr_exit ( %#lx )", ARG1 ); + PRE_REG_READ1(long, "thr_exit", long *, "status"); + + if (ARG1) + PRE_MEM_WRITE( "thr_exit(status)", ARG1, sizeof(long) ); + tst = VG_(get_ThreadState)(tid); + tst->exitreason = VgSrc_ExitThread; + tst->os_state.exitcode = ARG1; + SET_STATUS_Success(0); +} + +PRE(sys_thr_set_name) +{ + PRINT( "sys_thr_set_name ( %ld, %#lx )", ARG1, ARG2 ); + PRE_REG_READ2(long, "thr_set_name", long, "id", const char *, "name"); + PRE_MEM_RASCIIZ( "sys_thr_set_name(threadname)", ARG2); +} + +PRE(sys_thr_kill) +{ + PRINT("sys_thr_kill ( %ld, %ld )", ARG1,ARG2); + PRE_REG_READ2(long, "thr_kill", long, id, int, sig); + if (!ML_(client_signal_OK)(ARG2)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + /* Check to see if this kill gave us a pending signal */ + *flags |= SfPollAfter; + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill: sending signal %ld to tid %ld\n", + ARG2, ARG1); + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) { + SET_STATUS_Success(0); + return; + } + + /* Ask to handle this syscall via the slow route, since that's the + only one that sets tst->status to VgTs_WaitSys. If the result + of doing the syscall is an immediate run of + async_signalhandler() in m_signals, then we need the thread to + be properly tidied away. I have the impression the previous + version of this wrapper worked on x86/amd64 only because the + kernel did not immediately deliver the async signal to this + thread (on ppc it did, which broke the assertion re tst->status + at the top of async_signalhandler()). */ + *flags |= SfMayBlock; +} +POST(sys_thr_kill) +{ + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill: sent signal %ld to tid %ld\n", + ARG2, ARG1); +} +PRE(sys_thr_kill2) +{ + PRINT("sys_thr_kill2 ( %ld, %ld, %ld )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "tgkill", int, pid, long, tid, int, sig); + if (!ML_(client_signal_OK)(ARG3)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + /* Check to see if this kill gave us a pending signal */ + *flags |= SfPollAfter; + + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill2: sending signal %ld to pid %ld/%ld\n", + ARG3, ARG1, ARG2); + + /* If we're sending SIGKILL, check to see if the target is one of + our threads and handle it specially. */ + if (ARG3 == VKI_SIGKILL && ML_(do_sigkill)(ARG2, ARG1)) { + SET_STATUS_Success(0); + return; + } + + /* Ask to handle this syscall via the slow route, since that's the + only one that sets tst->status to VgTs_WaitSys. If the result + of doing the syscall is an immediate run of + async_signalhandler() in m_signals, then we need the thread to + be properly tidied away. I have the impression the previous + version of this wrapper worked on x86/amd64 only because the + kernel did not immediately deliver the async signal to this + thread (on ppc it did, which broke the assertion re tst->status + at the top of async_signalhandler()). */ + *flags |= SfMayBlock; +} +POST(sys_thr_kill2) +{ + if (VG_(clo_trace_signals)) + VG_(message)(Vg_DebugMsg, "thr_kill2: sent signal %ld to pid %ld/%ld\n", + ARG3, ARG1, ARG2); +} + +PRE(sys_thr_wake) +{ + PRINT("sys_thr_wake ( %ld )", ARG1); + PRE_REG_READ1(long, "thr_wake", long, id); +} + +/* --------------------------------------------------------------------- + umtx* wrappers + ------------------------------------------------------------------ */ + +PRE(sys__umtx_op) +{ +// ThreadState *tst; + + /* 5 args are always passed through. The last two can vary, but + they're always pointers. They may not be used though. */ + switch(ARG2) { + case VKI_UMTX_OP_LOCK: + PRINT( "sys__umtx_op ( %#lx, LOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_lock", + struct umtx *, obj, int, op, unsigned long, id, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_lock(timespec)", ARG5, sizeof(struct vki_timespec) ); + PRE_MEM_WRITE( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_UNLOCK: + PRINT( "sys__umtx_op ( %#lx, UNLOCK, %ld)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_unlock", + struct umtx *, obj, int, op, unsigned long, id); + PRE_MEM_READ( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_WAIT: + PRINT( "sys__umtx_op ( %#lx, WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait", + struct umtx *, obj, int, op, unsigned long, id, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_wait(mtx)", ARG1, sizeof(struct vki_umtx) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, sizeof(struct vki_timespec) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_WAKE: + PRINT( "sys__umtx_op ( %#lx, WAKE, %ld)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_wake", + struct umtx *, obj, int, op, unsigned long, id); + PRE_MEM_READ( "_umtx_op_wake(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_MUTEX_TRYLOCK: + PRINT( "sys__umtx_op ( %#lx, MUTEX_TRYLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_mutex_trylock", + struct umutex *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_mutex_trylock(timespec)", ARG5, sizeof(struct vki_timespec) ); + PRE_MEM_WRITE( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_MUTEX_LOCK: + PRINT( "sys__umtx_op ( %#lx, MUTEX_LOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_mutex_lock", + struct umutex *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_mutex_lock(timespec)", ARG5, sizeof(struct vki_timespec) ); + PRE_MEM_WRITE( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_MUTEX_UNLOCK: + PRINT( "sys__umtx_op ( %#lx, MUTEX_UNLOCK)", ARG1); + PRE_REG_READ2(long, "_umtx_op_mutex_unlock", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SET_CEILING: + PRINT( "sys__umtx_op ( %#lx, SET_CEILING, %ld, %#lx)", ARG1, ARG3, ARG4); + PRE_REG_READ4(long, "_umtx_op_set_ceiling", + struct umutex *, obj, int, op, unsigned int, ceiling, + unsigned int *, old_ceiling); + PRE_MEM_READ( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) ); + if (ARG4) + PRE_MEM_WRITE( "_umtx_op_set_ceiling(old_ceiling)", ARG4, sizeof(vki_uint32_t) ); + break; + case VKI_UMTX_OP_CV_WAIT: + PRINT( "sys__umtx_op ( %#lx, CV_WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_cv_wait", + struct ucond *, obj, int, op, unsigned long, wflags, + struct umutex *, umtx, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_READ( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_cv_wait(timespec)", ARG5, sizeof(struct vki_timespec) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_CV_SIGNAL: + PRINT( "sys__umtx_op ( %#lx, CV_SIGNAL)", ARG1); + PRE_REG_READ2(long, "_umtx_op_cv_signal", + struct ucond *, obj, int, op); + PRE_MEM_READ( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) ); + break; + case VKI_UMTX_OP_CV_BROADCAST: + PRINT( "sys__umtx_op ( %#lx, CV_BROADCAST, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_cv_broadcast", + struct ucond *, obj, int, op); + PRE_MEM_READ( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) ); + PRE_MEM_WRITE( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) ); + break; + case VKI_UMTX_OP_WAIT_UINT: + PRINT( "sys__umtx_op ( %#lx, CV_WAIT_UINT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait_uint", + int *, obj, int, op, unsigned long, id, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_wait(uint)", ARG1, sizeof(int) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, sizeof(struct vki_timespec) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_RDLOCK: + PRINT( "sys__umtx_op ( %#lx, RW_RDLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_rw_rdlock", + struct urwlock *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_WRLOCK: + PRINT( "sys__umtx_op ( %#lx, RW_WRLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_rw_wrlock", + struct urwlock *, obj, int, op, unsigned long, noid, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_RW_UNLOCK: + PRINT( "sys__umtx_op ( %#lx, RW_UNLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_rw_unlock", + struct urwlock *, obj, int, op); + PRE_MEM_READ( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + PRE_MEM_WRITE( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) ); + break; + case VKI_UMTX_OP_WAIT_UINT_PRIVATE: + PRINT( "sys__umtx_op ( %#lx, CV_WAIT_UINT_PRIVATE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_wait_uint_private", + int *, obj, int, op, unsigned long, id, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_wait_private(uint)", ARG1, sizeof(int) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_wait_private(umtx_time)", ARG5, sizeof(struct vki_umtx_time) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_WAKE_PRIVATE: + PRINT( "sys__umtx_op ( %#lx, CV_WAKE_PRIVATE, %ld)", ARG1, ARG3); + PRE_REG_READ3(long, "_umtx_op_wake_private", + struct umtx *, obj, int, op, unsigned long, id); + PRE_MEM_READ( "_umtx_op_wake_private(mtx)", ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_MUTEX_WAIT: + PRINT( "sys__umtx_op ( %#lx, MUTEX_WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_mutex_wait", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_MUTEX_WAKE: + PRINT( "sys__umtx_op ( %#lx, MUTEX_WAKE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_mutex_wake", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SEM_WAIT: + PRINT( "sys__umtx_op ( %#lx, SEM_WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ5(long, "_umtx_op_sem_wait", + struct usem *, obj, int, op, unsigned long, id, + void *, zero, struct vki_timespec *, timeout); + PRE_MEM_READ( "_umtx_op_sem_wait(usem)", ARG1, sizeof(struct vki_usem) ); + PRE_MEM_WRITE( "_umtx_op_sem_wait(usem)", ARG1, sizeof(struct vki_usem) ); + if (ARG5) + PRE_MEM_READ( "_umtx_op_sem_wait(umtx_time)", ARG5, sizeof(struct vki_umtx_time) ); + *flags |= SfMayBlock; + break; + case VKI_UMTX_OP_SEM_WAKE: + PRINT( "sys__umtx_op ( %#lx, SEM_WAKE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ2(long, "_umtx_op_sem_wake", + struct umutex *, obj, int, op); + PRE_MEM_READ( "_umtx_op_sem_wake(mutex)", ARG1, sizeof(struct vki_usem) ); + PRE_MEM_WRITE( "_umtx_op_sem_wake(mutex)", ARG1, sizeof(struct vki_usem) ); + break; + case VKI_UMTX_OP_NWAKE_PRIVATE: + PRINT( "sys__umtx_op ( %#lx, NWAKE_PRIVATE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_nwake_private", + struct umutex *, obj, int, op, int, count); + PRE_MEM_READ( "_umtx_op_nwake_private(mtxs)", ARG1, ARG3 * sizeof(void *) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mtxs)", ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_MUTEX_WAKE2: + PRINT( "sys__umtx_op ( %#lx, MUTEX_WAKE2, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5); + PRE_REG_READ3(long, "_umtx_op_mutex_wake2", + struct umutex *, obj, int, op, unsigned long, flags); + PRE_MEM_READ( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + PRE_MEM_WRITE( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) ); + break; + default: + PRINT( "sys__umtx_op ( %#lx, %ld(UNKNOWN), %ld, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4, ARG5); + break; + } +// tst = VG_(get_ThreadState)(tid); +//PRINT(" [[ UMTX_OP %d: me=%d arg1 %#lx = %#lx (%ld) ]]", ARG2, tst->os_state.lwpid, ARG1, *(UWord *)ARG1, *(UWord *)ARG1 & 0x7fffffff); +} + +POST(sys__umtx_op) +{ +//PRINT("[[ POST_UMTX_OP %d: arg1 %#lx = %#lx (%ld) ]]\n", ARG2, ARG1, *(UWord *)ARG1, *(UWord *)ARG1 & 0x7fffffff); + switch(ARG2) { + case VKI_UMTX_OP_LOCK: + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_UNLOCK: + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) ); + break; + case VKI_UMTX_OP_WAIT: + case VKI_UMTX_OP_WAKE: + case VKI_UMTX_OP_WAIT_UINT: + case VKI_UMTX_OP_WAIT_UINT_PRIVATE: + case VKI_UMTX_OP_WAKE_PRIVATE: + break; + case VKI_UMTX_OP_MUTEX_TRYLOCK: + case VKI_UMTX_OP_MUTEX_LOCK: + case VKI_UMTX_OP_MUTEX_UNLOCK: + case VKI_UMTX_OP_MUTEX_WAIT: /* Sets/clears contested bits */ + case VKI_UMTX_OP_MUTEX_WAKE: /* Sets/clears contested bits */ + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) ); + break; + case VKI_UMTX_OP_SET_CEILING: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) ); + if (ARG4) + POST_MEM_WRITE( ARG4, sizeof(vki_uint32_t) ); + } + break; + case VKI_UMTX_OP_CV_WAIT: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + POST_MEM_WRITE( ARG4, sizeof(struct vki_umutex) ); + } + break; + case VKI_UMTX_OP_CV_SIGNAL: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + } + break; + case VKI_UMTX_OP_CV_BROADCAST: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) ); + } + break; + case VKI_UMTX_OP_RW_RDLOCK: + case VKI_UMTX_OP_RW_WRLOCK: + case VKI_UMTX_OP_RW_UNLOCK: + if (SUCCESS) { + POST_MEM_WRITE( ARG1, sizeof(struct vki_urwlock) ); + } + break; + default: + break; + } +} + +PRE(sys__umtx_lock) +{ + PRINT( "sys__umtx_lock ( %#lx )", ARG1); + PRE_REG_READ1(long, "_umtx_lock", struct vki_umtx *, umtx); + PRE_MEM_READ( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) ); +} + +POST(sys__umtx_lock) +{ + if (SUCCESS) + POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx)); +} + +PRE(sys__umtx_unlock) +{ + PRINT( "sys__umtx_unlock ( %#lx )", ARG1); + PRE_REG_READ1(long, "_umtx_unlock", struct vki_umtx *, umtx); + PRE_MEM_READ( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); + PRE_MEM_WRITE( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) ); +} + +POST(sys__umtx_unlock) +{ + if (SUCCESS) + POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx)); +} + +PRE(sys_rtprio_thread) +{ + PRINT( "sys_rtprio_thread ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3 ); + PRE_REG_READ3(long, "rtprio_thread", + int, "function", __vki_lwpid_t, "lwpid", struct vki_rtprio *, "rtp"); + if (ARG1 == VKI_RTP_SET) { + PRE_MEM_READ( "rtprio_thread(set)", ARG3, sizeof(struct vki_rtprio)); + } else if (ARG1 == VKI_RTP_LOOKUP) { + PRE_MEM_WRITE( "rtprio_thread(lookup)", ARG3, sizeof(struct vki_rtprio)); + } else { + /* PHK ?? */ + } +} +POST(sys_rtprio_thread) +{ + if (ARG1 == VKI_RTP_LOOKUP && RES == 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_rtprio)); +} + +/* --------------------------------------------------------------------- + sig* wrappers + ------------------------------------------------------------------ */ + +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) ) ; +} + +/* --------------------------------------------------------------------- + rt_sig* wrappers + ------------------------------------------------------------------ */ + +static int sigformat[_VKI_NSIG]; + +PRE(sys_sigaction4) +{ + PRINT("sys_sigaction ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "sigaction", + int, signum, const struct sigaction *, act, + struct sigaction *, oldact); + + if (ARG2 != 0) { + struct vki_sigaction *sa = (struct vki_sigaction *)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 (ARG1 < _VKI_NSIG) + sigformat[ARG1] = 4; + } + if (ARG3 != 0) + PRE_MEM_WRITE( "sigaction(oldact)", ARG3, sizeof(struct vki_sigaction)); + + /* process the signal immediately. */ + SET_STATUS_from_SysRes( + VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t *)ARG2, + (vki_sigaction_fromK_t *)ARG3) + ); +} +POST(sys_sigaction4) +{ + vg_assert(SUCCESS); + if (RES == 0 && ARG3 != 0) + POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction)); +} + +/* Identical, but warns the signal handler to expect the different sigframe */ +PRE(sys_sigaction) +{ + PRINT("sys_sigaction6 ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "sigaction6", + int, signum, const struct sigaction *, act, + struct sigaction *, oldact); + + if (ARG2 != 0) { + struct vki_sigaction *sa = (struct vki_sigaction *)ARG2; + PRE_MEM_READ( "sigaction6(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler)); + PRE_MEM_READ( "sigaction6(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask)); + PRE_MEM_READ( "sigaction6(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags)); + if (ARG1 < _VKI_NSIG) + sigformat[ARG1] = 6; + } + if (ARG3 != 0) + PRE_MEM_WRITE( "sigaction6(oldact)", ARG3, sizeof(struct vki_sigaction)); + + 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(struct vki_sigaction)); +} + + +PRE(sys_sigprocmask) +{ + PRINT("sys_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)); + + SET_STATUS_from_SysRes( + VG_(do_sys_sigprocmask) ( tid, ARG1 /*how*/, + (vki_sigset_t*) ARG2, + (vki_sigset_t*) ARG3 ) + ); + + if (SUCCESS) + *flags |= SfPollAfter; +} +POST(sys_sigprocmask) +{ + vg_assert(SUCCESS); + if (RES == 0 && ARG3 != 0) + POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t)); +} + +/* Not in 4.x */ +PRE(sys_sigtimedwait) +{ + *flags |= SfMayBlock; + PRINT("sys_sigtimedwait ( %#lx, %#lx, %#lx )", + ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "sigtimedwait", + const vki_sigset_t *, set, vki_siginfo_t *, info, + const struct timespec *, timeout); + if (ARG1 != 0) + PRE_MEM_READ( "sigtimedwait(set)", ARG1, sizeof(vki_sigset_t)); + if (ARG2 != 0) + PRE_MEM_WRITE( "sigtimedwait(info)", ARG2, sizeof(vki_siginfo_t) ); + if (ARG3 != 0) + PRE_MEM_READ( "sigtimedwait(timeout)", + ARG3, sizeof(struct vki_timespec) ); +} +POST(sys_sigtimedwait) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) ); +} + +/* Not in 4.x */ +PRE(sys_sigwaitinfo) +{ + *flags |= SfMayBlock; + PRINT("sys_sigwaitinfo ( %#lx, %#lx )", + ARG1,ARG2); + PRE_REG_READ2(long, "sigwaitinfo", + const vki_sigset_t *, set, vki_siginfo_t *, info); + if (ARG1 != 0) + PRE_MEM_READ( "sigwaitinfo(set)", ARG1, sizeof(vki_sigset_t)); + if (ARG2 != 0) + PRE_MEM_WRITE( "sigwaitinfo(info)", ARG2, sizeof(vki_siginfo_t) ); +} +POST(sys_sigwaitinfo) +{ + if (ARG2 != 0) + POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) ); +} + +#if 0 /* not on freebsd 4.x */ +PRE(sys_rt_sigqueueinfo) +{ + PRINT("sys_rt_sigqueueinfo(%ld, %ld, %#lx)", ARG1, ARG2, ARG3); + PRE_REG_READ3(long, "rt_sigqueueinfo", + int, pid, int, sig, vki_siginfo_t *, uinfo); + if (ARG2 != 0) + PRE_MEM_READ( "rt_sigqueueinfo(uinfo)", ARG3, sizeof(vki_siginfo_t) ); +} +POST(sys_rt_sigqueueinfo) +{ + if (!ML_(client_signal_OK)(ARG2)) + SET_STATUS_Failure( VKI_EINVAL ); +} +#endif + +PRE(sys_sigsuspend) +{ + *flags |= SfMayBlock; + PRINT("sys_sigsuspend ( %#lx )", ARG1 ); + PRE_REG_READ1(int, "rt_sigsuspend", vki_sigset_t *, mask) + if (ARG1 != (Addr)NULL) { + PRE_MEM_READ( "rt_sigsuspend(mask)", ARG1, sizeof(vki_sigset_t) ); + } +} + +#if 0 +/* --------------------------------------------------------------------- + linux msg* wrapper helpers + ------------------------------------------------------------------ */ + +void +ML_(linux_PRE_sys_msgsnd) ( ThreadId tid, + UWord arg0, UWord arg1, UWord arg2, UWord arg3 ) +{ + /* int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); */ + struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1; + PRE_MEM_READ( "msgsnd(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + PRE_MEM_READ( "msgsnd(msgp->mtext)", (Addr)&msgp->mtext, arg2 ); +} + +void +ML_(linux_PRE_sys_msgrcv) ( ThreadId tid, + UWord arg0, UWord arg1, UWord arg2, + UWord arg3, UWord arg4 ) +{ + /* ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, + long msgtyp, int msgflg); */ + struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1; + PRE_MEM_WRITE( "msgrcv(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + PRE_MEM_WRITE( "msgrcv(msgp->mtext)", (Addr)&msgp->mtext, arg2 ); +} +void +ML_(linux_POST_sys_msgrcv) ( ThreadId tid, + UWord res, + UWord arg0, UWord arg1, UWord arg2, + UWord arg3, UWord arg4 ) +{ + struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1; + POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) ); + POST_MEM_WRITE( (Addr)&msgp->mtext, res ); +} + +void +ML_(linux_PRE_sys_msgctl) ( ThreadId tid, + UWord arg0, UWord arg1, UWord arg2 ) +{ + /* int msgctl(int msqid, int cmd, struct msqid_ds *buf); */ + switch (arg1 /* cmd */) { + case VKI_IPC_INFO: + case VKI_MSG_INFO: + case VKI_IPC_INFO|VKI_IPC_64: + case VKI_MSG_INFO|VKI_IPC_64: + PRE_MEM_WRITE( "msgctl(IPC_INFO, buf)", + arg2, sizeof(struct vki_msginfo) ); + break; + case VKI_IPC_STAT: + case VKI_MSG_STAT: + PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)", + arg2, sizeof(struct vki_msqid_ds) ); + break; + case VKI_IPC_STAT|VKI_IPC_64: + case VKI_MSG_STAT|VKI_IPC_64: + PRE_MEM_WRITE( "msgctl(IPC_STAT, arg.buf)", + arg2, sizeof(struct vki_msqid64_ds) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)", + arg2, sizeof(struct vki_msqid_ds) ); + break; + case VKI_IPC_SET|VKI_IPC_64: + PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)", + arg2, sizeof(struct vki_msqid64_ds) ); + break; + } +} +void +ML_(linux_POST_sys_msgctl) ( ThreadId tid, + UWord res, + UWord arg0, UWord arg1, UWord arg2 ) +{ + switch (arg1 /* cmd */) { + case VKI_IPC_INFO: + case VKI_MSG_INFO: + case VKI_IPC_INFO|VKI_IPC_64: + case VKI_MSG_INFO|VKI_IPC_64: + POST_MEM_WRITE( arg2, sizeof(struct vki_msginfo) ); + break; + case VKI_IPC_STAT: + case VKI_MSG_STAT: + POST_MEM_WRITE( arg2, sizeof(struct vki_msqid_ds) ); + break; + case VKI_IPC_STAT|VKI_IPC_64: + case VKI_MSG_STAT|VKI_IPC_64: + POST_MEM_WRITE( arg2, sizeof(struct vki_msqid64_ds) ); + break; + } +} + +#endif + +PRE(sys_chflags) +{ + PRINT("sys_chflags ( %#lx(%s), 0x%lx )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "chown", + const char *, path, vki_int32_t, flags); + PRE_MEM_RASCIIZ( "chflags(path)", ARG1 ); +} + +PRE(sys_fchflags) +{ + PRINT("sys_fchflags ( %ld, %ld )", ARG1,ARG2); + PRE_REG_READ2(long, "fchflags", unsigned int, fildes, vki_int32_t, flags); +} + + +PRE(sys_modfind) +{ + PRINT("sys_modfind ( %#lx )",ARG1); + PRE_REG_READ1(long, "modfind", char *, modname); + PRE_MEM_RASCIIZ( "modfind(modname)", ARG1 ); +} + +PRE(sys_modstat) +{ + PRINT("sys_modstat ( %ld, %#lx )",ARG1,ARG2); + PRE_REG_READ2(long, "modstat", int, modid, struct module_stat *, buf); + PRE_MEM_WRITE( "modstat(buf)", ARG2, sizeof(struct vki_module_stat) ); +} + +POST(sys_modstat) +{ + POST_MEM_WRITE( ARG2, sizeof(struct vki_module_stat) ); +} + +PRE(sys_lkmnosys0) +{ + PRINT("sys_lkmnosys0 ()"); + PRE_REG_READ0(long, "lkmnosys0"); +} + +PRE(sys_lkmnosys1) +{ + PRINT("sys_lkmnosys1 ()"); + PRE_REG_READ0(long, "lkmnosys1"); +} + +PRE(sys_lkmnosys2) +{ + PRINT("sys_lkmnosys2 ()"); + PRE_REG_READ0(long, "lkmnosys2"); +} + +PRE(sys_lkmnosys3) +{ + PRINT("sys_lkmnosys3 ()"); + PRE_REG_READ0(long, "lkmnosys3"); +} + +PRE(sys_lkmnosys4) +{ + PRINT("sys_lkmnosys4 ()"); + PRE_REG_READ0(long, "lkmnosys4"); +} + +PRE(sys_lkmnosys5) +{ + PRINT("sys_lkmnosys5 ()"); + PRE_REG_READ0(long, "lkmnosys5"); +} + +PRE(sys_lkmnosys6) +{ + PRINT("sys_lkmnosys6 ()"); + PRE_REG_READ0(long, "lkmnosys6"); +} + +PRE(sys_lkmnosys7) +{ + PRINT("sys_lkmnosys7 ()"); + PRE_REG_READ0(long, "lkmnosys7"); +} + +PRE(sys_lkmnosys8) +{ + PRINT("sys_lkmnosys8 ()"); + PRE_REG_READ0(long, "lkmnosys8"); +} + +PRE(sys_kenv) +{ + PRINT("sys_kenv ( %ld, %#lx, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "kenv", + int, action, const char *, name, char *, value, int, len); + switch (ARG1) { + case VKI_KENV_GET: + case VKI_KENV_SET: + case VKI_KENV_UNSET: + PRE_MEM_RASCIIZ("kenv(name)", ARG2); + /* FALLTHROUGH */ + case VKI_KENV_DUMP: + break; + default: + I_die_here; + } +} + +POST(sys_kenv) +{ + if (SUCCESS) { + switch (ARG1) { + case VKI_KENV_GET: + POST_MEM_WRITE(ARG3, ARG4); + break; + case VKI_KENV_DUMP: + if (ARG3 != (Addr)NULL) + POST_MEM_WRITE(ARG3, ARG4); + break; + } + } +} + +PRE(sys_uuidgen) +{ + PRINT("sys_uuidgen ( %#lx, %ld )", ARG1,ARG2); + PRE_REG_READ2(long, "uuidgen", + struct vki_uuid *, store, int, count); + PRE_MEM_WRITE( "uuidgen(store)", ARG1, ARG2 * sizeof(struct vki_uuid)); +} + +POST(sys_uuidgen) +{ + if (SUCCESS) + POST_MEM_WRITE( ARG1, ARG2 * sizeof(struct vki_uuid) ); +} + + +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_shmat) +{ + UWord arg2tmp; + PRINT("sys_shmat ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "shmat", + int, shmid, const void *, shmaddr, int, shmflg); + arg2tmp = ML_(generic_PRE_sys_shmat)(tid, ARG1,ARG2,ARG3); + if (arg2tmp == 0) + SET_STATUS_Failure( VKI_EINVAL ); + else + ARG2 = arg2tmp; +} + +POST(sys_shmat) +{ + ML_(generic_POST_sys_shmat)(tid, RES,ARG1,ARG2,ARG3); +} + +PRE(sys_shmdt) +{ + PRINT("sys_shmdt ( %#lx )",ARG1); + PRE_REG_READ1(long, "shmdt", const void *, shmaddr); + if (!ML_(generic_PRE_sys_shmdt)(tid, ARG1)) + SET_STATUS_Failure( VKI_EINVAL ); +} + +POST(sys_shmdt) +{ + ML_(generic_POST_sys_shmdt)(tid, RES,ARG1); +} + +PRE(sys_shmctl) +{ + PRINT("sys_shmctl ( %ld, %ld, %#lx )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "shmctl", + int, shmid, int, cmd, struct vki_shmid_ds *, buf); + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "shmctl(IPC_STAT, buf)", + ARG3, sizeof(struct vki_shmid_ds) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "shmctl(IPC_SET, buf)", + ARG3, sizeof(struct vki_shmid_ds) ); + break; + } +} + +PRE(sys_shmctl7) +{ + PRINT("sys_shmctl7 ( %ld, %ld, %#lx )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "shmctl", + int, shmid, int, cmd, struct vki_shmid_ds7 *, buf); + switch (ARG2 /* cmd */) { + case VKI_IPC_STAT: + PRE_MEM_WRITE( "shmctl7(IPC_STAT, buf)", + ARG3, sizeof(struct vki_shmid_ds7) ); + break; + case VKI_IPC_SET: + PRE_MEM_READ( "shmctl7(IPC_SET, buf)", + ARG3, sizeof(struct vki_shmid_ds7) ); + break; + } +} + +POST(sys_shmctl) +{ + if (ARG2 == VKI_IPC_STAT) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds) ); + } +} + +POST(sys_shmctl7) +{ + if (ARG2 == VKI_IPC_STAT) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds7) ); + } +} + +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_shm_open) +{ + PRE_REG_READ3(long, "shm_open", + const char *, "name", int, "flags", vki_mode_t, "mode"); + if (ARG1 == VKI_SHM_ANON) { + PRINT("sys_shm_open(%#lx(SHM_ANON), %ld, %ld)", ARG1, ARG2, ARG3); + } else { + PRINT("sys_shm_open(%#lx(%s), %ld, %ld)", ARG1, (char *)ARG1, ARG2, ARG3); + 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, (HChar*)ARG1); + } +} + +PRE(sys_shm_unlink) +{ + PRINT("sys_shm_unlink(%#lx(%s))", ARG1, (char *)ARG1); + PRE_REG_READ1(long, "shm_unlink", + const char *, "name"); + + PRE_MEM_RASCIIZ( "shm_unlink(filename)", ARG1 ); + + *flags |= SfMayBlock; +} + +PRE(sys_semop) +{ + *flags |= SfMayBlock; + PRINT("sys_semop ( %ld, %#lx, %lu )",ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "semop", + int, semid, struct sembuf *, sops, unsigned, nsoops); + ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3); +} + +struct ipc_perm7 { + unsigned short cuid; /* creator user id */ + unsigned short cgid; /* creator group id */ + unsigned short uid; /* user id */ + unsigned short gid; /* group id */ + unsigned short mode; /* r/w permission */ + unsigned short seq; /* sequence # (to generate unique ipcid) */ + vki_key_t key; /* user specified msg/sem/shm key */ +}; + +struct semid_ds7 { + struct ipc_perm7 sem_perm; /* operation permission struct */ + struct sem *sem_base; /* pointer to first semaphore in set */ + unsigned short sem_nsems; /* number of sems in set */ + vki_time_t sem_otime; /* last operation time */ + long sem_pad1; /* SVABI/386 says I need this here */ + vki_time_t sem_ctime; /* last change time */ + /* Times measured in secs since */ + /* 00:00:00 GMT, Jan. 1, 1970 */ + long sem_pad2; /* SVABI/386 says I need this here */ + long sem_pad3[4]; /* SVABI/386 says I need this here */ +}; + +PRE(sys___semctl7) +{ + switch (ARG3) { + case VKI_IPC_INFO: + case VKI_SEM_INFO: + PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "semctl", + int, semid, int, semnum, int, cmd, struct seminfo *, arg); + break; + case VKI_IPC_STAT: + case VKI_SEM_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_ds7 *, 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; + 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___semctl7) +{ + ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4); +} + +PRE(sys___semctl) +{ + switch (ARG3) { + case VKI_IPC_INFO: + case VKI_SEM_INFO: + PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "semctl", + int, semid, int, semnum, int, cmd, struct seminfo *, arg); + break; + case VKI_IPC_STAT: + case VKI_SEM_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; + 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_eaccess) +{ + PRINT("sys_eaccess ( %#lx(%s), %ld )", ARG1,(char*)ARG1,ARG2); + PRE_REG_READ2(long, "eaccess", const char *, pathname, int, mode); + PRE_MEM_RASCIIZ( "eaccess(pathname)", ARG1 ); +} + + +/* --------------------------------------------------------------------- + *at wrappers + ------------------------------------------------------------------ */ + +PRE(sys_openat) +{ + + if (ARG3 & VKI_O_CREAT) { + // 4-arg version + PRINT("sys_openat ( %ld, %#lx(%s), %ld, %ld )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4); + PRE_REG_READ4(int, "openat", + int, dfd, const char *, filename, int, flags, vki_mode_t, mode); + } else { + // 3-arg version + PRINT("sys_openat ( %ld, %#lx(%s), %ld )",ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(int, "openat", + int, dfd, const char *, filename, int, flags); + } + + if (ARG1 != (unsigned)VKI_AT_FDCWD && !ML_(fd_allowed)(ARG1, "openat", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_RASCIIZ( "openat(filename)", ARG2 ); + + /* Otherwise handle normally */ + *flags |= SfMayBlock; +} + +POST(sys_openat) +{ + vg_assert(SUCCESS); + if (!ML_(fd_allowed)(RES, "openat", tid, True)) { + VG_(close)(RES); + SET_STATUS_Failure( VKI_EMFILE ); + } else { + if (VG_(clo_track_fds)) + ML_(record_fd_open_with_given_name)(tid, RES, (HChar*)ARG2); + } +} + +PRE(sys_mkdirat) +{ + *flags |= SfMayBlock; + PRINT("sys_mkdirat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(long, "mkdirat", + int, dfd, const char *, pathname, int, mode); + PRE_MEM_RASCIIZ( "mkdirat(pathname)", ARG2 ); +} + +PRE(sys_mkfifoat) +{ + PRINT("sys_mkfifoat ( %ld, %#lx(%s), 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3 ); + PRE_REG_READ3(long, "mkfifoat", + int, dfd, const char *, pathname, int, mode); + PRE_MEM_RASCIIZ( "mkfifoat(pathname)", ARG2 ); +} + +PRE(sys_mknodat) +{ + PRINT("sys_mknodat ( %ld, %#lx(%s), 0x%lx, 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 ); + PRE_REG_READ4(long, "mknodat", + int, dfd, const char *, pathname, int, mode, unsigned, dev); + PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 ); +} + +PRE(sys_fchownat) +{ + PRINT("sys_fchownat ( %ld, %#lx(%s), 0x%lx, 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "fchownat", + int, dfd, const char *, path, + vki_uid_t, owner, vki_gid_t, group); + PRE_MEM_RASCIIZ( "fchownat(path)", ARG2 ); +} + +PRE(sys_futimesat) +{ + PRINT("sys_futimesat ( %ld, %#lx(%s), %#lx )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(long, "futimesat", + int, dfd, char *, filename, struct timeval *, tvp); + if (ARG2 != 0) + PRE_MEM_RASCIIZ( "futimesat(filename)", ARG2 ); + if (ARG3 != 0) + PRE_MEM_READ( "futimesat(tvp)", ARG3, 2 * sizeof(struct vki_timeval) ); +} + +PRE(sys_fstatat) +{ + PRINT("sys_fstatat ( %ld, %#lx(%s), %#lx )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(long, "fstatat", + int, dfd, char *, file_name, struct stat *, buf); + PRE_MEM_RASCIIZ( "fstatat(file_name)", ARG2 ); + PRE_MEM_WRITE( "fstatat(buf)", ARG3, sizeof(struct vki_stat) ); +} + +POST(sys_fstatat) +{ + POST_MEM_WRITE( ARG3, sizeof(struct vki_stat) ); +} + +PRE(sys_unlinkat) +{ + *flags |= SfMayBlock; + PRINT("sys_unlinkat ( %ld, %#lx(%s) )", ARG1,ARG2,(char*)ARG2); + PRE_REG_READ2(long, "unlinkat", int, dfd, const char *, pathname); + PRE_MEM_RASCIIZ( "unlinkat(pathname)", ARG2 ); +} + +PRE(sys_renameat) +{ + PRINT("sys_renameat ( %ld, %#lx(%s), %ld, %#lx(%s) )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4); + PRE_REG_READ4(long, "renameat", + int, olddfd, const char *, oldpath, + int, newdfd, const char *, newpath); + PRE_MEM_RASCIIZ( "renameat(oldpath)", ARG2 ); + PRE_MEM_RASCIIZ( "renameat(newpath)", ARG4 ); +} + +PRE(sys_linkat) +{ + *flags |= SfMayBlock; + PRINT("sys_linkat ( %ld, %#lx(%s), %ld, %#lx(%s), %ld )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4,ARG5); + PRE_REG_READ5(long, "linkat", + int, olddfd, const char *, oldpath, + int, newdfd, const char *, newpath, + int, flags); + PRE_MEM_RASCIIZ( "linkat(oldpath)", ARG2); + PRE_MEM_RASCIIZ( "linkat(newpath)", ARG4); +} + +PRE(sys_symlinkat) +{ + *flags |= SfMayBlock; + PRINT("sys_symlinkat ( %#lx(%s), %ld, %#lx(%s) )",ARG1,(char*)ARG1,ARG2,ARG3,(char*)ARG3); + PRE_REG_READ3(long, "symlinkat", + const char *, oldpath, int, newdfd, const char *, newpath); + PRE_MEM_RASCIIZ( "symlinkat(oldpath)", ARG1 ); + PRE_MEM_RASCIIZ( "symlinkat(newpath)", ARG3 ); +} + +PRE(sys_readlinkat) +{ + HChar name[25]; + Word saved = SYSNO; + + PRINT("sys_readlinkat ( %ld, %#lx(%s), %#lx, %llu )", ARG1,ARG2,(char*)ARG2,ARG3,(ULong)ARG4); + PRE_REG_READ4(long, "readlinkat", + int, dfd, const char *, path, char *, buf, int, bufsiz); + PRE_MEM_RASCIIZ( "readlinkat(path)", ARG2 ); + PRE_MEM_WRITE( "readlinkat(buf)", ARG3,ARG4 ); + + /* + * Handle the case where readlinkat is looking at /proc/curproc/file or + * /proc//file. + */ + VG_(sprintf)(name, "/proc/%d/file", VG_(getpid)()); + if (ML_(safe_to_deref)((void*)ARG2, 1) + && (VG_(strcmp)((HChar *)ARG2, name) == 0 + || VG_(strcmp)((HChar *)ARG2, "/proc/curproc/file") == 0)) { + VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd)); + SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, (UWord)name, + ARG3, ARG4)); + } else { + /* Normal case */ + SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, ARG2, ARG3, ARG4)); + } + + if (SUCCESS && RES > 0) + POST_MEM_WRITE( ARG3, RES ); +} + +PRE(sys_fchmodat) +{ + PRINT("sys_fchmodat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(long, "fchmodat", + int, dfd, const char *, path, vki_mode_t, mode); + PRE_MEM_RASCIIZ( "fchmodat(path)", ARG2 ); +} + +PRE(sys_faccessat) +{ + PRINT("sys_faccessat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3); + PRE_REG_READ3(long, "faccessat", + int, dfd, const char *, pathname, int, mode); + PRE_MEM_RASCIIZ( "faccessat(pathname)", ARG2 ); +} + +/* --------------------------------------------------------------------- + __acl* wrappers + ------------------------------------------------------------------ */ + +PRE(sys___acl_get_file) +{ + PRINT("sys___acl_get_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_get_file", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_WRITE( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_file) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +PRE(sys___acl_set_file) +{ + PRINT("sys___acl_set_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_set_file", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_set_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +PRE(sys___acl_get_fd) +{ + PRINT("sys___acl_get_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_get_fd", + int, fd, int, acltype, struct vki_acl *, aclp); + PRE_MEM_WRITE( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_fd) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +PRE(sys___acl_set_fd) +{ + PRINT("sys___acl_set_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_set_fd", + int, fd, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +PRE(sys___acl_delete_file) +{ + PRINT("sys___acl_delete_file ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "__acl_delete_file", + const char *, path, int, acltype); +} + +PRE(sys___acl_delete_fd) +{ + PRINT("sys___acl_delete_fd ( %ld, %ld )", ARG1,ARG2); + PRE_REG_READ2(long, "__acl_delete_fd", + int, fd, int, acltype); +} + +PRE(sys___acl_aclcheck_file) +{ + PRINT("sys___acl_aclcheck_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_aclcheck_file", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_aclcheck_file(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +PRE(sys___acl_aclcheck_fd) +{ + PRINT("sys___acl_aclcheck_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_aclcheck_fd", + int, fd, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_aclcheck_fd(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +PRE(sys___acl_get_link) +{ + PRINT("sys___acl_get_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_get_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_WRITE( "__acl_get_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys___acl_get_link) +{ + vg_assert(SUCCESS); + if (RES == 0) { + POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) ); + } +} + +PRE(sys___acl_set_link) +{ + PRINT("sys___acl_set_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_set_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_set_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +PRE(sys___acl_delete_link) +{ + PRINT("sys___acl_delete_link ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2); + PRE_REG_READ2(long, "__acl_delete_link", + const char *, path, int, acltype); +} + +PRE(sys___acl_aclcheck_link) +{ + PRINT("sys___acl_aclcheck_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "__acl_aclcheck_link", + const char *, path, int, acltype, struct vki_acl *, aclp); + PRE_MEM_READ( "__acl_aclcheck_link(aclp)", ARG3, sizeof(struct vki_acl) ); +} + +POST(sys_getcontext) +{ + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) ); +} + +POST(sys_swapcontext) +{ + if (SUCCESS) + POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) ); +} + +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_DUPFD_CLOEXEC: + 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" - obsolete. + case VKI_F_OSETLKW: + *flags |= SfMayBlock; + /* FALLTHROUGH */ + case VKI_F_OGETLK: + case VKI_F_OSETLK: + PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "fcntl", + unsigned int, fd, unsigned int, cmd, + struct oflock *, lock); + break; + + // This one uses ARG3 as "oldd" and ARG4 as "newd". + case VKI_F_DUP2FD: + PRINT("sys_fcntl[ARG3=='oldd', ARG4=='newd'] ( %ld, %ld, %ld, %ld )", + ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "fcntl", + unsigned int, fd, unsigned int, cmd, + unsigned long, oldd, unsigned long, newd); + break; + + // These ones use ARG3 as "lock". + case VKI_F_SETLKW: + *flags |= SfMayBlock; + /* FALLTHROUGH */ + case VKI_F_GETLK: + case VKI_F_SETLK: + case VKI_F_SETLK_REMOTE: + PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "fcntl", + unsigned int, fd, unsigned int, cmd, + struct flock *, lock); + break; + + default: + PRINT("sys_fcntl[UNKNOWN] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3); + I_die_here; + break; + } +} + +POST(sys_fcntl) +{ + vg_assert(SUCCESS); + if (ARG2 == 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); + } + } +} + +PRE(sys_ioctl) +{ + UInt dir = _VKI_IOC_DIR(ARG2); + UInt size = _VKI_IOC_SIZE(ARG2); + *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); + +/* On FreeBSD, ALL ioctl's are IOR/IOW encoded. Just use the default decoder */ + if (VG_(strstr)(VG_(clo_sim_hints), "lax-ioctls") != NULL) { + /* + * Be very lax about ioctl handling; the only + * assumption is that the size is correct. Doesn't + * require the full buffer to be initialized when + * writing. Without this, using some device + * drivers with a large number of strange ioctl + * commands becomes very tiresome. + */ + } else if (/* size == 0 || */ dir == _VKI_IOC_NONE) { + static Int moans = 3; + if (moans > 0 && !VG_(clo_xml)) { + moans--; + VG_(message)(Vg_UserMsg, + "Warning: noted but unhandled ioctl 0x%lx" + " with no size/direction hints\n", + ARG2); + VG_(message)(Vg_UserMsg, + " This could cause spurious value errors" + " to appear.\n"); + VG_(message)(Vg_UserMsg, + " See README_MISSING_SYSCALL_OR_IOCTL for " + "guidance on writing a proper wrapper.\n" ); + } + } else { + if ((dir & _VKI_IOC_WRITE) && size > 0) + PRE_MEM_READ( "ioctl(generic)", ARG3, size); + if ((dir & _VKI_IOC_READ) && size > 0) + PRE_MEM_WRITE( "ioctl(generic)", ARG3, size); + } +} + +POST(sys_ioctl) +{ + UInt dir = _VKI_IOC_DIR(ARG2); + UInt size = _VKI_IOC_SIZE(ARG2); + vg_assert(SUCCESS); + if (size > 0 && (dir & _VKI_IOC_READ) + && RES == 0 && ARG3 != (Addr)NULL) + POST_MEM_WRITE(ARG3, size); +} + +PRE(sys_ptrace) +{ + struct vki_ptrace_io_desc *io_desc; + PRINT("sys_ptrace ( %ld, %ld, 0x%lx, %ld)", ARG1, ARG2, ARG3, ARG4); + + PRE_REG_READ4(int, "ptrace", int, request, int, pid, char *, addr, int, data); + + switch (ARG1) { + case VKI_PTRACE_TRACEME: + break; + case VKI_PTRACE_READ_I: + case VKI_PTRACE_READ_D: + break; + + case VKI_PTRACE_WRITE_I: + case VKI_PTRACE_WRITE_D: + break; + + case VKI_PTRACE_IO: + PRE_MEM_READ("ptrace", ARG3, sizeof(struct vki_ptrace_io_desc)); + io_desc = (struct vki_ptrace_io_desc *)ARG3; + switch (io_desc->piod_op) { + case VKI_PIOD_READ_D: + case VKI_PIOD_READ_I: + PRE_MEM_WRITE( "ptrace", (UWord)io_desc->piod_addr, io_desc->piod_len); + break; + case VKI_PIOD_WRITE_D: + case VKI_PIOD_WRITE_I: + PRE_MEM_READ( "ptrace", (UWord)io_desc->piod_addr, io_desc->piod_len); + break; + } + break; + + case VKI_PTRACE_CONTINUE: + break; + + case VKI_PTRACE_STEP: + break; + + case VKI_PTRACE_KILL: + break; + + case VKI_PTRACE_ATTACH: + break; + + case VKI_PTRACE_DETACH: + break; + + case VKI_PTRACE_GETREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_reg_struct)); + break; + + case VKI_PTRACE_SETREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_reg_struct)); + break; + + case VKI_PTRACE_GETFPREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_SETFPREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_GETDBREGS: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_SETDBREGS: + PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_LWPINFO: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_ptrace_lwpinfo)); + break; + + case VKI_PTRACE_GETNUMLWPS: + break; + + case VKI_PTRACE_GETLWPLIST: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(vki_lwpid_t) * ARG4); + break; + + case VKI_PTRACE_SETSTEP: + break; + + case VKI_PTRACE_CLEARSTEP: + break; + + case VKI_PTRACE_SUSPEND: + break; + + case VKI_PTRACE_RESUME: + break; + + case VKI_PTRACE_TO_SCE: + break; + + case VKI_PTRACE_TO_SCX: + break; + + case VKI_PTRACE_SYSCALL: + break; + + case VKI_PTRACE_VM_TIMESTAMP: + break; + + case VKI_PTRACE_VM_ENTRY: + PRE_MEM_WRITE( "ptrace", ARG3, sizeof(struct vki_ptrace_vm_entry)); + break; + } +} + +POST(sys_ptrace) +{ + struct vki_ptrace_io_desc *io_desc; + + switch (ARG1) { + case VKI_PTRACE_TRACEME: + break; + case VKI_PTRACE_READ_I: + case VKI_PTRACE_READ_D: + break; + + case VKI_PTRACE_WRITE_I: + case VKI_PTRACE_WRITE_D: + break; + + case VKI_PTRACE_IO: + io_desc = (struct vki_ptrace_io_desc *)ARG3; + switch (io_desc->piod_op) { + case VKI_PIOD_READ_D: + case VKI_PIOD_READ_I: + if (RES != -1) + POST_MEM_WRITE((UWord)io_desc->piod_addr, io_desc->piod_len); + break; + case VKI_PIOD_WRITE_D: + case VKI_PIOD_WRITE_I: + break; + } + break; + + case VKI_PTRACE_CONTINUE: + break; + + case VKI_PTRACE_STEP: + break; + + case VKI_PTRACE_KILL: + break; + + case VKI_PTRACE_ATTACH: + break; + + case VKI_PTRACE_DETACH: + break; + + case VKI_PTRACE_GETREGS: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_reg_struct)); + break; + + case VKI_PTRACE_SETREGS: + break; + + case VKI_PTRACE_GETFPREGS: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_fpreg)); + break; + + case VKI_PTRACE_SETFPREGS: + break; + + case VKI_PTRACE_GETDBREGS: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_dbreg)); + break; + + case VKI_PTRACE_SETDBREGS: + break; + + case VKI_PTRACE_LWPINFO: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_lwpinfo)); + break; + + case VKI_PTRACE_GETNUMLWPS: + break; + + case VKI_PTRACE_GETLWPLIST: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(vki_lwpid_t) * RES); + break; + + case VKI_PTRACE_SETSTEP: + break; + + case VKI_PTRACE_CLEARSTEP: + break; + + case VKI_PTRACE_SUSPEND: + break; + + case VKI_PTRACE_RESUME: + break; + + case VKI_PTRACE_TO_SCE: + break; + + case VKI_PTRACE_TO_SCX: + break; + + case VKI_PTRACE_SYSCALL: + break; + + case VKI_PTRACE_VM_TIMESTAMP: + break; + + case VKI_PTRACE_VM_ENTRY: + if (RES != -1) + POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_vm_entry)); + break; + } +} + +PRE(sys_cpuset_setaffinity) +{ + + PRINT("sys_cpuset_setaffinity ( %ld, %ld, %lld, %llu, %#lx )", ARG1, ARG2, + ARG3, ARG4, ARG5); + PRE_REG_READ5(int, "cpuset_setaffinity", + int, level, int, which, long, id, + size_t, setsize, void *, mask); + PRE_MEM_READ("cpuset_setaffinity", ARG5, ARG4); +} + +PRE(sys_cpuset_getaffinity) +{ + + PRINT("sys_cpuset_getaffinity ( %ld, %ld, %lld, %llu, %#lx )", ARG1, ARG2, + ARG3, ARG4, ARG5); + PRE_REG_READ5(int, "cpuset_getaffinity", + int, level, int, which, long, id, + size_t, setsize, void *, mask); + PRE_MEM_WRITE("cpuset_getaffinity", ARG5, ARG4); +} + +POST(sys_cpuset_getaffinity) +{ + vg_assert(SUCCESS); + if (RES == 0) + POST_MEM_WRITE( ARG5, ARG4 ); +} + +struct pselect_sized_sigset { + const vki_sigset_t *ss; + vki_size_t ss_len; +}; +struct pselect_adjusted_sigset { + struct pselect_sized_sigset ss; /* The actual syscall arg */ + vki_sigset_t adjusted_ss; +}; + +PRE(sys_pselect) +{ + *flags |= SfMayBlock | SfPostOnFail; + PRINT("sys_pselect ( %ld, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" + FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", + SARG1, ARG2, ARG3, ARG4, ARG5, ARG6); + PRE_REG_READ6(long, "pselect", + int, n, vki_fd_set *, readfds, vki_fd_set *, writefds, + vki_fd_set *, exceptfds, struct vki_timeval *, timeout, + void *, sig); + // XXX: this possibly understates how much memory is read. + if (ARG2 != 0) + PRE_MEM_READ( "pselect(readfds)", + ARG2, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG3 != 0) + PRE_MEM_READ( "pselect(writefds)", + ARG3, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG4 != 0) + PRE_MEM_READ( "pselect(exceptfds)", + ARG4, ARG1/8 /* __FD_SETSIZE/8 */ ); + if (ARG5 != 0) + PRE_MEM_READ( "pselect(timeout)", ARG5, sizeof(struct vki_timeval) ); + if (ARG6 != 0) { + const struct pselect_sized_sigset *pss = + (struct pselect_sized_sigset *)(Addr)ARG6; + PRE_MEM_READ( "pselect(sig)", ARG6, sizeof(*pss) ); + if (!ML_(safe_to_deref)(pss, sizeof(*pss))) { + ARG6 = 1; /* Something recognisable to POST() hook. */ + } else { + struct pselect_adjusted_sigset *pas; + pas = VG_(malloc)("syswrap.pselect.1", sizeof(*pas)); + ARG6 = (Addr)pas; + pas->ss.ss = (void *)1; + pas->ss.ss_len = pss->ss_len; + if (pss->ss_len == sizeof(*pss->ss)) { + if (pss->ss == NULL) { + pas->ss.ss = NULL; + } else { + PRE_MEM_READ("pselect(sig->ss)", (Addr)pss->ss, pss->ss_len); + if (ML_(safe_to_deref)(pss->ss, sizeof(*pss->ss))) { + pas->adjusted_ss = *pss->ss; + pas->ss.ss = &pas->adjusted_ss; + VG_(sanitize_client_sigmask)(&pas->adjusted_ss); + } + } + } + } + } +} +POST(sys_pselect) +{ + if (ARG6 != 0 && ARG6 != 1) { + VG_(free)((struct pselect_adjusted_sigset *)(Addr)ARG6); + } +} + +#undef PRE +#undef POST + +const SyscallTableEntry ML_(syscall_table)[] = { + // syscall (handled specially) // 0 + BSDX_(__NR_exit, sys_exit), // 1 + BSDX_(__NR_fork, sys_fork), // 2 + GENXY(__NR_read, sys_read), // 3 + + GENX_(__NR_write, sys_write), // 4 + GENXY(__NR_open, sys_open), // 5 + GENXY(__NR_close, sys_close), // 6 + GENXY(__NR_wait4, sys_wait4), // 7 + + // 4.3 creat 8 + GENX_(__NR_link, sys_link), // 9 + GENX_(__NR_unlink, sys_unlink), // 10 + // obsol execv 11 + + GENX_(__NR_chdir, sys_chdir), // 12 + GENX_(__NR_fchdir, sys_fchdir), // 13 + GENX_(__NR_mknod, sys_mknod), // 14 + GENX_(__NR_chmod, sys_chmod), // 15 + + GENX_(__NR_chown, sys_chown), // 16 + GENX_(__NR_break, sys_brk), // 17 + BSDXY(__NR_getfsstat4, sys_getfsstat4), // 18 + // 4.3 lseek 19 + + GENX_(__NR_getpid, sys_getpid), // 20 + BSDX_(__NR_mount, sys_mount), // 21 + BSDX_(__NR_unmount, sys_unmount), // 22 + GENX_(__NR_setuid, sys_setuid), // 23 + + GENX_(__NR_getuid, sys_getuid), // 24 + GENX_(__NR_geteuid, sys_geteuid), // 25 + BSDXY(__NR_ptrace, sys_ptrace), // 26 + BSDXY(__NR_recvmsg, sys_recvmsg), // 27 + + BSDX_(__NR_sendmsg, sys_sendmsg), // 28 + BSDXY(__NR_recvfrom, sys_recvfrom), // 29 + BSDXY(__NR_accept, sys_accept), // 30 + BSDXY(__NR_getpeername, sys_getpeername), // 31 + + BSDXY(__NR_getsockname, sys_getsockname), // 32 + GENX_(__NR_access, sys_access), // 33 + BSDX_(__NR_chflags, sys_chflags), // 34 + BSDX_(__NR_fchflags, sys_fchflags), // 35 + + GENX_(__NR_sync, sys_sync), // 36 + GENX_(__NR_kill, sys_kill), // 37 + // 4.3 stat 38 + GENX_(__NR_getppid, sys_getppid), // 39 + + // 4.3 lstat 40 + GENXY(__NR_dup, sys_dup), // 41 + BSDXY(__NR_pipe, sys_pipe), // 42 + GENX_(__NR_getegid, sys_getegid), // 43 + + // GENX_(__NR_profil, sys_profil), // 44 +// BSDX_(__NR_ktrace, sys_ktrace), // 45 + // 4.3 sigaction 46 + GENX_(__NR_getgid, sys_getgid), // 47 + + // 4.3 sigaction (int sigset) 48 + BSDXY(__NR_getlogin, sys_getlogin), // 49 + BSDX_(__NR_setlogin, sys_setlogin), // 50 + GENX_(__NR_acct, sys_acct), // 51 + + // 4.3 sigpending 52 + GENXY(__NR_sigaltstack, sys_sigaltstack), // 53 + BSDXY(__NR_ioctl, sys_ioctl), // 54 +// BSDX_(__NR_reboot, sys_reboot), // 55 + + BSDX_(__NR_revoke, sys_revoke), // 56 + GENX_(__NR_symlink, sys_symlink), // 57 + GENX_(__NR_readlink, sys_readlink), // 58 + GENX_(__NR_execve, sys_execve), // 59 + + GENX_(__NR_umask, sys_umask), // 60 + GENX_(__NR_chroot, sys_chroot), // 61 + // 4.3 fstat 62 + // 4.3 getgerninfo 63 + + // 4.3 getpagesize 64 + GENX_(__NR_msync, sys_msync), // 65 + BSDX_(__NR_vfork, sys_fork), // 66 + // obsol vread 67 + + // obsol vwrite 68 + // BSDX_(__NR_sbrk, sys_sbrk), // 69 + // BSDX_(__NR_sstk, sys_sstk), // 70 + // 4.3 mmap 71 + + // 4.2 vadvise 72 + GENXY(__NR_munmap, sys_munmap), // 73 + GENXY(__NR_mprotect, sys_mprotect), // 74 + GENX_(__NR_madvise, sys_madvise), // 75 + + // obsol vhangup 76 + // obsol vlimit 77 + GENXY(__NR_mincore, sys_mincore), // 78 + GENXY(__NR_getgroups, sys_getgroups), // 79 + + GENX_(__NR_setgroups, sys_setgroups), // 80 + GENX_(__NR_getpgrp, sys_getpgrp), // 81 + GENX_(__NR_setpgid, sys_setpgid), // 82 + GENXY(__NR_setitimer, sys_setitimer), // 83 + + // 4.3 wait 84 +// BSDX_(__NR_swapon, sys_swapon), // 85 + GENXY(__NR_getitimer, sys_getitimer), // 86 + // 4.3 gethostname 87 + + // 4.3 sethostname 88 + BSDX_(__NR_getdtablesize, sys_getdtablesize), // 89 + GENXY(__NR_dup2, sys_dup2), // 90 + // unimpl getdopt 91 + + BSDXY(__NR_fcntl, sys_fcntl), // 92 + GENX_(__NR_select, sys_select), // 93 + // unimpl setdopt 94 + GENX_(__NR_fsync, sys_fsync), // 95 + + GENX_(__NR_setpriority, sys_setpriority), // 96 + BSDXY(__NR_socket, sys_socket), // 97 + BSDX_(__NR_connect, sys_connect), // 98 + // 4.3 accept 99 + + GENX_(__NR_getpriority, sys_getpriority), // 100 + // 4.3 send 101 + // 4.3 recv 102 + // 4.3 sigreturn 103 + + BSDX_(__NR_bind, sys_bind), // 104 + BSDX_(__NR_setsockopt, sys_setsockopt), // 105 + BSDX_(__NR_listen, sys_listen), // 106 + // obsol vtimes 107 + + // 4.3 sigvec 108 + // 4.3 sigblock 109 + // 4.3 sigsetmask 110 + // 4.3 sigsuspend 111 + + // 4.3 sigstack 112 + // 4.3 recvmsg 113 + // 4.3 sendmsg 114 + // 4.3 vtrace 115 + + GENXY(__NR_gettimeofday, sys_gettimeofday), // 116 + GENXY(__NR_getrusage, sys_getrusage), // 117 + BSDXY(__NR_getsockopt, sys_getsockopt), // 118 + // unimpl resuba 119 + + GENXY(__NR_readv, sys_readv), // 120 + GENX_(__NR_writev, sys_writev), // 121 + GENX_(__NR_settimeofday, sys_settimeofday), // 122 + GENX_(__NR_fchown, sys_fchown), // 123 + + GENX_(__NR_fchmod, sys_fchmod), // 124 + // 4.3 recvfrom 125 + GENX_(__NR_setreuid, sys_setreuid), // 126 + GENX_(__NR_setregid, sys_setregid), // 127 + + GENX_(__NR_rename, sys_rename), // 128 + // 4.3 truncate 129 + // 4.3 ftruncate 130 + GENX_(__NR_flock, sys_flock), // 131 + + BSDX_(__NR_mkfifo, sys_mkfifo), // 132 + BSDX_(__NR_sendto, sys_sendto), // 133 + BSDX_(__NR_shutdown, sys_shutdown), // 134 + BSDXY(__NR_socketpair, sys_socketpair), // 135 + + GENX_(__NR_mkdir, sys_mkdir), // 136 + GENX_(__NR_rmdir, sys_rmdir), // 137 + GENX_(__NR_utimes, sys_utimes), // 138 + // 4.2 sigreturn 139 + +// BSDXY(__NR_adjtime, sys_adjtime), // 140 + // 4.3 getpeername 141 + // 4.3 gethostid 142 + // 4.3 sethostid 143 + + // 4.3 getrlimit 144 + // 4.3 setrlimit 145 + // 4.3 killpg 146 + GENX_(__NR_setsid, sys_setsid), // 147 + + BSDX_(__NR_quotactl, sys_quotactl), // 148 + // 4.3 quota 149 + // 4.3 getsockname 150 + // bsd/os sem_lock 151 + + // bsd/os sem_wakeup 152 + // bsd/os asyncdaemon 153 + // nosys 154 + // BSDXY(__NR_nfssvc, sys_nfssvc), // 155 + + // 4.3 getdirentries 156 + GENXY(__NR_statfs, sys_statfs), // 157 + GENXY(__NR_fstatfs, sys_fstatfs), // 158 + // nosys 159 + +// BSDXY(__NR_lgetfh, sys_lgetfh), // 160 +// BSDXY(__NR_getfh, sys_getfh), // 161 + BSDXY(__NR_getdomainname, sys_getdomainname), // 162 + BSDX_(__NR_setdomainname, sys_setdomainname), // 163 + + BSDXY(__NR_uname, sys_uname), // 164 + BSDX_(__NR_sysarch, sys_sysarch), // 165 +// BSDXY(__NR_rtprio, sys_rtprio), // 166 + // nosys 167 + + // nosys 168 +// BSDXY(__NR_semsys, sys_semsys), // 169 +// BSDXY(__NR_msgsys, sys_msgsys), // 170 +// BSDXY(__NR_shmsys, sys_shmsys), // 171 + + // nosys 172 + BSDXY(__NR_pread6, sys_pread), // 173 + BSDX_(__NR_pwrite6, sys_pwrite), // 174 + // nosys 175 + +// BSDXY(__NR_ntp_adjtime, sys_ntp_adjtime), // 176 + // bsd/os sfork 177 + // bsd/os getdescriptor 178 + // bsd/os setdescriptor 179 + + // nosys 180 + GENX_(__NR_setgid, sys_setgid), // 181 + BSDX_(__NR_setegid, sys_setegid), // 182 + BSDX_(__NR_seteuid, sys_seteuid), // 183 + + // unimpl lfs_bmapv 184 + // unimpl lfs_markv 185 + // unimpl lfs_segclean 186 + // unimpl lfs_segwait 187 + + BSDXY(__NR_stat, sys_stat), // 188 + BSDXY(__NR_fstat, sys_fstat), // 189 + BSDXY(__NR_lstat, sys_lstat), // 190 + BSDX_(__NR_pathconf, sys_pathconf), // 191 + + BSDX_(__NR_fpathconf, sys_fpathconf), // 192 + // nosys 193 + GENXY(__NR_getrlimit, sys_getrlimit), // 194 + GENX_(__NR_setrlimit, sys_setrlimit), // 195 + + BSDXY(__NR_getdirentries, sys_getdirentries), // 196 + BSDX_(__NR_mmap6, sys_mmap7), // 197 + // __syscall (handled specially) // 198 + BSDX_(__NR_lseek6, sys_lseek), // 199 + + BSDX_(__NR_truncate, sys_truncate), // 200 + BSDX_(__NR_ftruncate, sys_ftruncate), // 201 + BSDXY(__NR___sysctl, sys___sysctl), // 202 + GENX_(__NR_mlock, sys_mlock), // 203 + + GENX_(__NR_munlock, sys_munlock), // 204 + BSDX_(__NR_undelete, sys_undelete), // 205 + BSDX_(__NR_futimes, sys_futimes), // 206 + GENX_(__NR_getpgid, sys_getpgid), // 207 + + // netbsd newreboot 208 + GENXY(__NR_poll, sys_poll), // 209 + BSDX_(__NR_lkmnosys0, sys_lkmnosys0), // 210 + BSDX_(__NR_lkmnosys1, sys_lkmnosys1), // 211 + + BSDX_(__NR_lkmnosys2, sys_lkmnosys2), // 212 + BSDX_(__NR_lkmnosys3, sys_lkmnosys3), // 213 + BSDX_(__NR_lkmnosys4, sys_lkmnosys4), // 214 + BSDX_(__NR_lkmnosys5, sys_lkmnosys5), // 215 + + BSDX_(__NR_lkmnosys6, sys_lkmnosys6), // 216 + BSDX_(__NR_lkmnosys7, sys_lkmnosys7), // 217 + BSDX_(__NR_lkmnosys8, sys_lkmnosys8), // 218 +// BSDXY(__NR_nfs_fhopen, sys_nfs_fhopen), // 219 + + BSDXY(__NR___semctl7, sys___semctl7), // 220 + BSDX_(__NR_semget, sys_semget), // 221 + BSDX_(__NR_semop, sys_semop), // 222 + // unimpl semconfig 223 + +// BSDXY(__NR_msgctl, sys_msgctl), // 224 +// BSDX_(__NR_msgget, sys_msgget), // 225 +// BSDX_(__NR_msgsnd, sys_msgsnd), // 226 +// BSDXY(__NR_msgrcv, sys_msgrcv), // 227 + + BSDXY(__NR_shmat, sys_shmat), // 228 + BSDXY(__NR_shmctl7, sys_shmctl7), // 229 + BSDXY(__NR_shmdt, sys_shmdt), // 230 + BSDX_(__NR_shmget, sys_shmget), // 231 + + BSDXY(__NR_clock_gettime, sys_clock_gettime), // 232 + BSDX_(__NR_clock_settime, sys_clock_settime), // 233 + BSDXY(__NR_clock_getres, sys_clock_getres), // 234 + // unimpl timer_create 235 + + // unimpl timer_delete 236 + // unimpl timer_settime 237 + // unimpl timer_gettime 238 + // unimpl timer_getoverrun 239 + + GENXY(__NR_nanosleep, sys_nanosleep), // 240 + // nosys 241 + // nosys 242 + // nosys 243 + + // nosys 244 + // nosys 245 + // nosys 246 + // nosys 247 + +// BSDXY(__NR_ntp_gettime, sys_ntp_gettime), // 248 + // nosys 249 +// BSDXY(__NR_minherit, sys_minherit), // 250 + BSDX_(__NR_rfork, sys_rfork), // 251 + + GENXY(__NR_openbsd_poll, sys_poll), // 252 + BSDX_(__NR_issetugid, sys_issetugid), // 253 + GENX_(__NR_lchown, sys_lchown), // 254 + // nosys 255 + + // nosys 256 + // nosys 257 + // nosys 258 + // nosys 259 + + // nosys 260 + // nosys 261 + // nosys 262 + // nosys 263 + + // nosys 264 + // nosys 265 + // nosys 266 + // nosys 267 + + // nosys 268 + // nosys 269 + // nosys 270 + // nosys 271 + + GENXY(__NR_getdents, sys_getdents), // 272 + // nosys 273 + BSDX_(__NR_lchmod, sys_lchmod), // 274 + GENX_(__NR_netbsd_lchown, sys_lchown), // 275 + + BSDX_(__NR_lutimes, sys_lutimes), // 276 + // netbsd msync 277 + // netbsd stat 278 + // netbsd fstat 279 + + // netbsd lstat 280 + // nosys 281 + // nosys 282 + // nosys 283 + + // nosys 284 + // nosys 285 + // nosys 286 + // nosys 287 + + // nosys 288 + // nosys 289 + // nosys 290 + // nosys 291 + + // nosys 292 + // nosys 293 + // nosys 294 + // nosys 295 + + // nosys 296 + BSDXY(__NR_fhstatfs, sys_fhstatfs), // 297 + BSDXY(__NR_fhopen, sys_fhopen), // 298 + BSDXY(__NR_fhstat, sys_fhstat), // 299 + +// BSDX_(__NR_modnext, sys_modnext), // 300 + BSDXY(__NR_modstat, sys_modstat), // 301 +// BSDX_(__NR_modfnext, sys_modfnext), // 302 + BSDX_(__NR_modfind, sys_modfind), // 303 + + BSDX_(__NR_kldload, sys_kldload), // 304 + BSDX_(__NR_kldunload, sys_kldunload), // 305 + BSDX_(__NR_kldfind, sys_kldfind), // 306 + BSDX_(__NR_kldnext, sys_kldnext), // 307 + +// BSDXY(__NR_kldstat, sys_kldstat), // 308 +// BSDX_(__NR_kldfirstmod, sys_kldfirstmod), // 309 + GENX_(__NR_getsid, sys_getsid), // 310 + BSDX_(__NR_setresuid, sys_setresuid), // 311 + + BSDX_(__NR_setresgid, sys_setresgid), // 312 + // obsol signanosleep 313 + // BSDXY(__NR_aio_return, sys_aio_return), // 314 + // BSDXY(__NR_aio_suspend, sys_aio_suspend), // 315 + + // BSDXY(__NR_aio_cancel, sys_aio_cancel), // 316 + // BSDXY(__NR_aio_error, sys_aio_error), // 317 + // BSDXY(__NR_aio_read, sys_aio_read), // 318 + // BSDXY(__NR_aio_write, sys_aio_write), // 319 + + // BSDXY(__NR_lio_listio, sys_lio_listio), // 320 + BSDX_(__NR_yield, sys_yield), // 321 + // nosys 322 + // nosys 323 + + GENX_(__NR_mlockall, sys_mlockall), // 324 + BSDX_(__NR_munlockall, sys_munlockall), // 325 + BSDXY(__NR___getcwd, sys___getcwd), // 326 +// BSDXY(__NR_sched_setparam, sys_sched_setparam), // 327 + +// BSDXY(__NR_sched_getparam, sys_sched_getparam), // 328 +// BSDX_(__NR_sched_setscheduler, sys_sched_setscheduler), // 329 +// BSDX_(__NR_sched_getscheduler, sys_sched_getscheduler), // 330 + BSDX_(__NR_sched_yield, sys_sched_yield), // 331 + + BSDX_(__NR_sched_get_priority_max, sys_sched_get_priority_max), // 332 + BSDX_(__NR_sched_get_priority_min, sys_sched_get_priority_min), // 333 +// BSDXY(__NR_sched_rr_get_interval, sys_sched_rr_get_interval), // 334 + BSDX_(__NR_utrace, sys_utrace), // 335 + + // compat3 sendfile 336 + BSDXY(__NR_kldsym, sys_kldsym), // 337 +// BSDX_(__NR_jail, sys_jail), // 338 + // unimpl pioctl 339 + + BSDXY(__NR_sigprocmask, sys_sigprocmask), // 340 + BSDX_(__NR_sigsuspend, sys_sigsuspend), // 341 + BSDXY(__NR_sigaction4, sys_sigaction4), // 342 + BSDXY(__NR_sigpending, sys_sigpending), // 343 + +// BSDX_(__NR_sigreturn4, sys_sigreturn4), // 344 + BSDXY(__NR_sigtimedwait, sys_sigtimedwait), // 345 + BSDXY(__NR_sigwaitinfo, sys_sigwaitinfo), // 346 + BSDXY(__NR___acl_get_file, sys___acl_get_file), // 347 + + BSDX_(__NR___acl_set_file, sys___acl_set_file), // 348 + BSDXY(__NR___acl_get_fd, sys___acl_get_fd), // 349 + BSDX_(__NR___acl_set_fd, sys___acl_set_fd), // 350 + BSDX_(__NR___acl_delete_file, sys___acl_delete_file), // 351 + + BSDX_(__NR___acl_delete_fd, sys___acl_delete_fd), // 352 + BSDX_(__NR___acl_aclcheck_file, sys___acl_aclcheck_file), // 353 + BSDX_(__NR___acl_aclcheck_fd, sys___acl_aclcheck_fd), // 354 + // BSDXY(__NR_extattrctl, sys_extattrctl), // 355 + + // BSDXY(__NR_extattr_set_file, sys_extattr_set_file), // 356 + // BSDXY(__NR_extattr_get_file, sys_extattr_get_file), // 357 + // BSDXY(__NR_extattr_delete_file, sys_extattr_delete_file), // 358 + // BSDXY(__NR_aio_waitcomplete, sys_aio_waitcomplete), // 359 + + BSDXY(__NR_getresuid, sys_getresuid), // 360 + BSDXY(__NR_getresgid, sys_getresgid), // 361 + BSDX_(__NR_kqueue, sys_kqueue), // 362 + BSDXY(__NR_kevent, sys_kevent), // 363 + + // nosys 364 + // nosys 365 + // nosys 366 + // nosys 367 + + // nosys 368 + // nosys 369 + // lkmressys 370 + // extattr_set_fd 371 + + // extattr_get_fd 372 + // extattr_delete_fd 373 + // __setugid 374 + // nfsclnt 375 + + BSDX_(__NR_eaccess, sys_eaccess), // 376 + // afs_syscall 377 + // nmount 378 + // kse_exit 379 + + // kse_wakeup 380 + // kse_create 381 + // kse_thr_interrupt 382 + // kse_release 383 + + // __mac_get_proc 384 + // __mac_set_proc 385 + // __mac_get_fd 386 + // __mac_get_file 387 + + // __mac_set_fd 388 + // __mac_set_file 389 + BSDXY(__NR_kenv, sys_kenv), // 390 + // lchflags 391 + + BSDXY(__NR_uuidgen, sys_uuidgen), // 392 + BSDXY(__NR_sendfile, sys_sendfile), // 393 + // mac_syscall 394 + BSDXY(__NR_getfsstat, sys_getfsstat), // 395 + + BSDXY(__NR_statfs6, sys_statfs6), // 396 + BSDXY(__NR_fstatfs6, sys_fstatfs6), // 397 + BSDXY(__NR_fhstatfs6, sys_fhstatfs6), // 398 + // nosys 399 + + // ksem_close 400 + // ksem_post 401 + // ksem_wait 402 + // ksem_trywait 403 + + // ksem_init 404 + // ksem_open 405 + // ksem_unlink 406 + // ksem_getvalue 407 + + // ksem_destroy 408 + // __mac_get_pid 409 + // __mac_get_link 410 + // __mac_set_link 411 + + // extattr_set_link 412 + // extattr_get_link 413 + // extattr_delete_link 414 + // __mac_execve 415 + + BSDXY(__NR_sigaction, sys_sigaction), // 416 + BSDX_(__NR_sigreturn, sys_sigreturn), // 417 + // __xstat 418 + // __xfstat 419 + + // __xlstat 420 + BSDXY(__NR_getcontext, sys_getcontext), // 421 + BSDX_(__NR_setcontext, sys_setcontext), // 422 + BSDXY(__NR_swapcontext, sys_swapcontext), // 423 + + // swapoff 424 + BSDXY(__NR___acl_get_link, sys___acl_get_link), // 425 + BSDX_(__NR___acl_set_link, sys___acl_set_link), // 426 + BSDX_(__NR___acl_delete_link, sys___acl_delete_link), // 427 + + BSDX_(__NR___acl_aclcheck_link, sys___acl_aclcheck_link), // 428 + //!sigwait 429 + // thr_create 430 + BSDX_(__NR_thr_exit, sys_thr_exit), // 431 + + BSDXY(__NR_thr_self, sys_thr_self), // 432 + BSDXY(__NR_thr_kill, sys_thr_kill), // 433 + BSDXY(__NR__umtx_lock, sys__umtx_lock), // 434 + BSDXY(__NR__umtx_unlock, sys__umtx_unlock), // 435 + + // jail_attach 436 + // extattr_list_fd 437 + // extattr_list_file 438 + // extattr_list_link 439 + + // kse_switchin 440 + // ksem_timedwait 441 + // thr_suspend 442 + BSDX_(__NR_thr_wake, sys_thr_wake), // 443 + // kldunloadf 444 + // audit 445 + // auditon 446 + // getauid 447 + + // setauid 448 + // getaudit 449 + // setaudit 450 + // getaudit_addr 451 + + // setaudit_addr 452 + // auditctl 453 + BSDXY(__NR__umtx_op, sys__umtx_op), // 454 + BSDX_(__NR_thr_new, sys_thr_new), // 455 + + // sigqueue 456 + BSDXY(__NR_kmq_open, sys_mq_open), // 457 + // kmq_setattr 458 + // kmq_timedreceive 459 + + // kmq_timedsend 460 + // kmq_notify 461 + BSDX_(__NR_kmq_unlink, sys_mq_unlink), // 462 + // abort2 463 + + BSDX_(__NR_thr_set_name, sys_thr_set_name), // 464 + // aio_fsync 465 + BSDXY(__NR_rtprio_thread, sys_rtprio_thread), // 466 + // nosys 467 + + // nosys 468 + // __getpath_fromfd 469 + // __getpath_fromaddr 470 + // sctp_peeloff 471 + + // sctp_generic_sendmsg 472 + // sctp_generic_sendmsg_iov 473 + // sctp_generic_recvmsg 474 + BSDXY(__NR_pread, sys_pread7), // 475 + + BSDX_(__NR_pwrite, sys_pwrite7), // 476 + BSDX_(__NR_mmap, sys_mmap7), // 477 + BSDX_(__NR_lseek, sys_lseek7), // 478 + BSDX_(__NR_truncate7, sys_truncate7), // 479 + + BSDX_(__NR_ftruncate7, sys_ftruncate7), // 480 + BSDXY(__NR_thr_kill2, sys_thr_kill2), // 481 + BSDXY(__NR_shm_open, sys_shm_open), // 482 + BSDX_(__NR_shm_unlink, sys_shm_unlink), // 483 + + // cpuset 484 + // cpuset_setid 485 + // cpuset_getid 486 + + BSDXY(__NR_cpuset_getaffinity, sys_cpuset_getaffinity), // 487 + BSDX_(__NR_cpuset_setaffinity, sys_cpuset_setaffinity), // 488 + BSDX_(__NR_faccessat, sys_faccessat), // 489 + BSDX_(__NR_fchmodat, sys_fchmodat), // 490 + BSDX_(__NR_fchownat, sys_fchownat), // 491 + + // fexecve 492 + BSDXY(__NR_fstatat, sys_fstatat), // 493 + BSDX_(__NR_futimesat, sys_futimesat), // 494 + BSDX_(__NR_linkat, sys_linkat), // 495 + + BSDX_(__NR_mkdirat, sys_mkdirat), // 496 + BSDX_(__NR_mkfifoat, sys_mkfifoat), // 497 + BSDX_(__NR_mknodat, sys_mknodat), // 498 + BSDXY(__NR_openat, sys_openat), // 499 + + BSDX_(__NR_readlinkat, sys_readlinkat), // 500 + BSDX_(__NR_renameat, sys_renameat), // 501 + BSDX_(__NR_symlinkat, sys_symlinkat), // 502 + BSDX_(__NR_unlinkat, sys_unlinkat), // 503 + + // posix_openpt 504 + + BSDXY(__NR___semctl, sys___semctl), // 510 + BSDXY(__NR_shmctl, sys_shmctl), // 512 + BSDXY(__NR_pselect, sys_pselect), // 522 + BSDXY(__NR_pipe2, sys_pipe2), // 542 + + BSDX_(__NR_fake_sigreturn, sys_fake_sigreturn), // 1000, fake sigreturn + +}; + +const UInt ML_(syscall_table_size) = + sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]); + +#endif // defined(VGO_freebsd) + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_syswrap/syswrap-generic.c b/coregrind/m_syswrap/syswrap-generic.c index 8b3d6fc72..118e1c7a8 100644 --- a/coregrind/m_syswrap/syswrap-generic.c +++ b/coregrind/m_syswrap/syswrap-generic.c @@ -30,7 +30,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -926,7 +926,7 @@ void VG_(init_preopened_fds)(void) out: VG_(close)(sr_Res(f)); -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) init_preopened_fds_without_proc_self_fd(); #elif defined(VGO_solaris) @@ -1130,6 +1130,10 @@ void pre_mem_read_sockaddr ( ThreadId tid, VG_(sprintf) ( outmsg, description, "sa_family" ); PRE_MEM_READ( outmsg, (Addr) &sa->sa_family, sizeof(vki_sa_family_t)); +#if defined(VGO_freebsd) + VG_(sprintf) ( outmsg, description, ".sa_len" ); + PRE_MEM_READ( outmsg, (Addr) &sa->sa_len, sizeof(char)); +#endif /* Don't do any extra checking if we cannot determine the sa_family. */ if (! ML_(safe_to_deref) (&sa->sa_family, sizeof(vki_sa_family_t))) @@ -1808,6 +1812,15 @@ UInt get_sem_count( Int semid ) return buf.sem_nsems; +# elif defined(__NR___semctl) + struct vki_semid_ds buf; + arg.buf = &buf; + res = VG_(do_syscall4)(__NR___semctl, semid, 0, VKI_IPC_STAT, *(UWord *)&arg); + if (sr_isError(res)) + return 0; + + return buf.sem_nsems; + # elif defined(__NR_semsys) /* Solaris */ struct vki_semid_ds buf; arg.buf = &buf; @@ -1842,12 +1855,15 @@ ML_(generic_PRE_sys_semctl) ( ThreadId tid, #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: case VKI_SEM_INFO: +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: case VKI_SEM_INFO|VKI_IPC_64: +#endif +#if !defined(VGO_freebsd) PRE_MEM_WRITE( "semctl(IPC_INFO, arg.buf)", (Addr)arg.buf, sizeof(struct vki_seminfo) ); - break; #endif + break; case VKI_IPC_STAT: #if defined(VKI_SEM_STAT) @@ -1921,9 +1937,13 @@ ML_(generic_POST_sys_semctl) ( ThreadId tid, #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: case VKI_SEM_INFO: +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: case VKI_SEM_INFO|VKI_IPC_64: +#endif +#if !defined(VGO_freebsd) POST_MEM_WRITE( (Addr)arg.buf, sizeof(struct vki_seminfo) ); +#endif break; #endif @@ -1955,6 +1975,7 @@ ML_(generic_POST_sys_semctl) ( ThreadId tid, break; } } +#endif /* ------ */ @@ -2104,8 +2125,13 @@ ML_(generic_PRE_sys_shmctl) ( ThreadId tid, switch (arg1 /* cmd */) { #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: +# if defined(VGO_freebsd) + PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", + arg2, sizeof(struct vki_shmid_ds) ); +# else PRE_MEM_WRITE( "shmctl(IPC_INFO, buf)", arg2, sizeof(struct vki_shminfo) ); +# endif break; #if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: @@ -2163,12 +2189,18 @@ ML_(generic_POST_sys_shmctl) ( ThreadId tid, switch (arg1 /* cmd */) { #if defined(VKI_IPC_INFO) case VKI_IPC_INFO: +# if defined(VGO_freebsd) + POST_MEM_WRITE( arg2, sizeof(struct vki_shmid_ds) ); +# else POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo) ); +# endif break; +#if defined(VKI_IPC_64) case VKI_IPC_INFO|VKI_IPC_64: POST_MEM_WRITE( arg2, sizeof(struct vki_shminfo64) ); break; #endif +#endif #if defined(VKI_SHM_INFO) case VKI_SHM_INFO: @@ -2456,6 +2488,7 @@ ML_(generic_PRE_sys_mmap) ( ThreadId tid, #define PRE(name) DEFN_PRE_TEMPLATE(generic, name) #define POST(name) DEFN_POST_TEMPLATE(generic, name) +#if !defined(VGO_freebsd) /* On freebsd, exit(2) is all-threads shutdown */ PRE(sys_exit) { ThreadState* tst; @@ -2469,6 +2502,7 @@ PRE(sys_exit) tst->os_state.exitcode = ARG1; SET_STATUS_Success(0); } +#endif PRE(sys_ni_syscall) { @@ -2707,6 +2741,7 @@ PRE(sys_getpriority) PRE_REG_READ2(long, "getpriority", int, which, int, who); } +#if defined(VGO_linux) PRE(sys_pwrite64) { *flags |= SfMayBlock; @@ -2727,6 +2762,7 @@ PRE(sys_pwrite64) #endif PRE_MEM_READ( "pwrite64(buf)", ARG2, ARG3 ); } +#endif PRE(sys_sync) { @@ -2769,6 +2805,7 @@ PRE(sys_getsid) PRE_REG_READ1(long, "getsid", vki_pid_t, pid); } +#if defined(VGO_linux) PRE(sys_pread64) { *flags |= SfMayBlock; @@ -2796,6 +2833,7 @@ POST(sys_pread64) POST_MEM_WRITE( ARG2, RES ); } } +#endif PRE(sys_mknod) { @@ -3339,7 +3377,7 @@ PRE(sys_fork) if (!SUCCESS) return; -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) // 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 ); @@ -3367,12 +3405,15 @@ PRE(sys_fork) } #endif // !defined(VGO_solaris) && !defined(VGP_arm64_linux) +// ftruncate/truncate have padded arguments on FreeBSD. +#if !defined(VGO_freebsd) PRE(sys_ftruncate) { *flags |= SfMayBlock; PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2); PRE_REG_READ2(long, "ftruncate", unsigned int, fd, unsigned long, length); } +#endif PRE(sys_truncate) { @@ -4514,6 +4555,7 @@ PRE(sys_unlink) PRE_MEM_RASCIIZ( "unlink(pathname)", ARG1 ); } +#if !defined(VGO_freebsd) PRE(sys_newuname) { PRINT("sys_newuname ( %#" FMT_REGWORD "x )", ARG1); @@ -4527,6 +4569,7 @@ POST(sys_newuname) POST_MEM_WRITE( ARG1, sizeof(struct vki_new_utsname) ); } } +#endif PRE(sys_waitpid) { @@ -4669,7 +4712,7 @@ PRE(sys_sethostname) #undef PRE #undef POST -#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_syswrap/syswrap-main.c b/coregrind/m_syswrap/syswrap-main.c index a2876c5fb..b16d38c2b 100644 --- a/coregrind/m_syswrap/syswrap-main.c +++ b/coregrind/m_syswrap/syswrap-main.c @@ -73,6 +73,10 @@ mips64 v0 a0 a1 a2 a3 a4 a5 a6 a7 v0 (== NUM) arm64 x8 x0 x1 x2 x3 x4 x5 n/a n/a x0 ?? (== ARG1??) + FreeBSD: + 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 + On s390x the svc instruction is used for system calls. The system call number is encoded in the instruction (8 bit immediate field). Since Linux 2.6 it is also allowed to use svc 0 with the system call number in r1. @@ -86,8 +90,8 @@ 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 + For x86-darwin and x86-freebsd, "+N" denotes "in memory at N(%esp)"; + ditto amd64-darwin/amd64-freebsd. 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". @@ -174,6 +178,12 @@ ppc32: Success(N) ==> r3 = N, CR0.SO = 0 Fail(N) ==> r3 = N, CR0.SO = 1 + FreeBSD: + x86: Success(N) ==> edx:eax = N, cc = 0 + Fail(N) ==> edx:eax = N, cc = 1 + + ditto amd64 + Darwin: x86: Success(N) ==> edx:eax = N, cc = 0 Fail(N) ==> edx:eax = N, cc = 1 @@ -287,6 +297,13 @@ */ #if defined(VGO_linux) extern +UWord ML_(do_syscall_for_client_WRK)( Word syscallno, + void* guest_state, + const vki_sigset_t *syscall_mask, + const vki_sigset_t *restore_mask, + Word sigsetSzB ); +#elif defined(VGO_freebsd) +extern UWord ML_(do_syscall_for_client_WRK)( Word syscallno, void* guest_state, const vki_sigset_t *syscall_mask, @@ -335,11 +352,25 @@ void do_syscall_for_client ( Int syscallno, { vki_sigset_t saved; UWord err; +# if defined(VGO_freebsd) + Int real_syscallno; +# endif # if defined(VGO_linux) err = ML_(do_syscall_for_client_WRK)( syscallno, &tst->arch.vex, syscall_mask, &saved, sizeof(vki_sigset_t) ); +# elif defined(VGO_freebsd) + if (tst->arch.vex.guest_SC_CLASS == VG_FREEBSD_SYSCALL0) + real_syscallno = __NR_syscall; + else if (tst->arch.vex.guest_SC_CLASS == VG_FREEBSD_SYSCALL198) + real_syscallno = __NR___syscall; + else + real_syscallno = syscallno; + err = ML_(do_syscall_for_client_WRK)( + real_syscallno, &tst->arch.vex, + syscall_mask, &saved, sizeof(vki_sigset_t) + ); # elif defined(VGO_darwin) switch (VG_DARWIN_SYSNO_CLASS(syscallno)) { case VG_DARWIN_SYSCALL_CLASS_UNIX: @@ -509,6 +540,79 @@ void getSyscallArgsFromGuestState ( /*OUT*/SyscallArgs* canonical, canonical->arg7 = 0; canonical->arg8 = 0; +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_ESP; + + // FreeBSD supports different calling conventions + switch (gst->guest_EAX) { + case __NR_syscall: + canonical->klass = VG_FREEBSD_SYSCALL0; + canonical->sysno = stack[1]; + stack += 1; + break; + case __NR___syscall: + canonical->klass = VG_FREEBSD_SYSCALL198; + canonical->sysno = stack[1]; + stack += 2; + break; + default: + canonical->klass = 0; + canonical->sysno = gst->guest_EAX; + break; + } + // stack[0] is a (fake) 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]; + +#elif defined(VGP_amd64_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_RSP; + + // FreeBSD supports different calling conventions + switch (gst->guest_RAX) { + case __NR_syscall: + canonical->klass = VG_FREEBSD_SYSCALL0; + canonical->sysno = gst->guest_RDI; + break; + case __NR___syscall: + canonical->klass = VG_FREEBSD_SYSCALL198; + canonical->sysno = gst->guest_RDI; + break; + default: + canonical->klass = 0; + canonical->sysno = gst->guest_RAX; + break; + } + // stack[0] is a (fake) return address + if (canonical->klass != VG_FREEBSD_SYSCALL0 && canonical->klass != VG_FREEBSD_SYSCALL198) { + // 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; + canonical->arg5 = gst->guest_R8; + canonical->arg6 = gst->guest_R9; + canonical->arg7 = stack[1]; + canonical->arg8 = stack[2]; + } else { + // stack[0] is return address + canonical->arg1 = gst->guest_RSI; + canonical->arg2 = gst->guest_RDX; + canonical->arg3 = gst->guest_R10; + canonical->arg4 = gst->guest_R8; + canonical->arg5 = gst->guest_R9; + canonical->arg6 = stack[1]; + canonical->arg7 = stack[2]; + canonical->arg8 = stack[3]; + } + #elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; canonical->sysno = gst->guest_R7; @@ -818,6 +922,78 @@ void putSyscallArgsIntoGuestState ( /*IN*/ SyscallArgs* canonical, gst->guest_GPR7 = canonical->arg5; gst->guest_GPR8 = canonical->arg6; +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_ESP; + + // stack[0] is a (fake) return address + switch (canonical->klass) { + case VG_FREEBSD_SYSCALL0: + gst->guest_EAX = __NR_syscall; + stack[1] = canonical->sysno; + stack++; + break; + case VG_FREEBSD_SYSCALL198: + gst->guest_EAX = __NR___syscall; + stack[1] = canonical->sysno; + stack += 2; + break; + default: + gst->guest_EAX = canonical->sysno; + break; + } + 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_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + UWord *stack = (UWord *)gst->guest_RSP; + + // stack[0] is a (fake) return address + switch (canonical->klass) { + case VG_FREEBSD_SYSCALL0: + gst->guest_RAX = __NR_syscall; + gst->guest_RDI = canonical->sysno; + gst->guest_RSI = canonical->arg1; + gst->guest_RDX = canonical->arg2; + gst->guest_R10 = canonical->arg3; + gst->guest_R8 = canonical->arg4; + gst->guest_R9 = canonical->arg5; + stack[1] = canonical->arg6; + stack[2] = canonical->arg7; + stack[3] = canonical->arg8; + break; + case VG_FREEBSD_SYSCALL198: + gst->guest_RAX = __NR___syscall; + gst->guest_RDI = canonical->sysno; + gst->guest_RSI = canonical->arg1; + gst->guest_RDX = canonical->arg2; + gst->guest_R10 = canonical->arg3; + gst->guest_R8 = canonical->arg4; + gst->guest_R9 = canonical->arg5; + stack[1] = canonical->arg6; + stack[2] = canonical->arg7; + stack[3] = canonical->arg8; + break; + default: + gst->guest_RAX = canonical->sysno; + gst->guest_RDI = canonical->arg1; + gst->guest_RSI = canonical->arg2; + gst->guest_RDX = canonical->arg3; + gst->guest_R10 = canonical->arg4; + gst->guest_R8 = canonical->arg5; + gst->guest_R9 = canonical->arg6; + stack[1] = canonical->arg7; + stack[2] = canonical->arg8; + break; + } + #elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; gst->guest_R7 = canonical->sysno; @@ -983,6 +1159,15 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical, canonical->sres = VG_(mk_SysRes_ppc64_linux)( gst->guest_GPR3, cr0so ); canonical->what = SsComplete; +# elif defined(VGP_x86_freebsd) + /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + UInt flags = LibVEX_GuestX86_get_eflags(gst); + + canonical->sres = VG_(mk_SysRes_x86_freebsd)(gst->guest_EAX, gst->guest_EDX, + (flags & 1) != 0 ? True : False); + canonical->what = SsComplete; + # elif defined(VGP_arm_linux) VexGuestARMState* gst = (VexGuestARMState*)gst_vanilla; canonical->sres = VG_(mk_SysRes_arm_linux)( gst->guest_R0 ); @@ -1009,6 +1194,14 @@ void getSyscallStatusFromGuestState ( /*OUT*/SyscallStatus* canonical, canonical->sres = VG_(mk_SysRes_mips64_linux)(v0, v1, a3); canonical->what = SsComplete; +# elif defined(VGP_amd64_freebsd) + /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + ULong flags = LibVEX_GuestAMD64_get_rflags(gst); + canonical->sres = VG_(mk_SysRes_amd64_freebsd)(gst->guest_RAX, gst->guest_RDX, + (flags & 1) != 0 ? True : False); + canonical->what = SsComplete; + # elif defined(VGP_x86_darwin) /* duplicates logic in m_signals.VG_UCONTEXT_SYSCALL_SYSRES */ VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; @@ -1198,6 +1391,45 @@ void putSyscallStatusIntoGuestState ( /*IN*/ ThreadId tid, VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, OFFSET_arm64_X0, sizeof(UWord) ); +#elif defined(VGP_x86_freebsd) + VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; + vg_assert(canonical->what == SsComplete); + if (sr_isError(canonical->sres)) { + gst->guest_EAX = sr_Err(canonical->sres); + LibVEX_GuestX86_put_eflag_c(1, gst); + } else { + gst->guest_EAX = sr_Res(canonical->sres); + gst->guest_EDX = sr_ResHI(canonical->sres); + LibVEX_GuestX86_put_eflag_c(0, gst); + } + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_x86_EAX, sizeof(UInt) ); + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_x86_EDX, sizeof(UInt) ); + // 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) ); + +#elif defined(VGP_amd64_freebsd) + VexGuestAMD64State* gst = (VexGuestAMD64State*)gst_vanilla; + vg_assert(canonical->what == SsComplete); + if (sr_isError(canonical->sres)) { + gst->guest_RAX = sr_Err(canonical->sres); + LibVEX_GuestAMD64_put_rflag_c(1, gst); + } else { + gst->guest_RAX = sr_Res(canonical->sres); + gst->guest_RDX = sr_ResHI(canonical->sres); + LibVEX_GuestAMD64_put_rflag_c(0, gst); + } + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_amd64_RAX, sizeof(ULong) ); + VG_TRACK( post_reg_write, Vg_CoreSysCall, tid, + OFFSET_amd64_RDX, sizeof(ULong) ); + // 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(VexGuestAMD64State, guest_CC_DEP1), sizeof(ULong) ); #elif defined(VGP_x86_darwin) VexGuestX86State* gst = (VexGuestX86State*)gst_vanilla; SysRes sres = canonical->sres; @@ -1422,6 +1654,29 @@ void getSyscallArgLayout ( /*OUT*/SyscallArgLayout* layout ) layout->uu_arg7 = -1; /* impossible value */ layout->uu_arg8 = -1; /* impossible value */ +#elif defined(VGP_x86_freebsd) + 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_freebsd) + layout->o_sysno = OFFSET_amd64_RAX; + layout->o_arg1 = OFFSET_amd64_RDI; + layout->o_arg2 = OFFSET_amd64_RSI; + layout->o_arg3 = OFFSET_amd64_RDX; + layout->o_arg4 = OFFSET_amd64_R10; + layout->o_arg5 = OFFSET_amd64_R8; + layout->o_arg6 = OFFSET_amd64_R9; + layout->s_arg7 = sizeof(UWord) * 1; + layout->s_arg8 = sizeof(UWord) * 2; + #elif defined(VGP_arm_linux) layout->o_sysno = OFFSET_arm_R7; layout->o_arg1 = OFFSET_arm_R0; @@ -1570,6 +1825,11 @@ static const SyscallTableEntry* get_syscall_entry ( Int syscallno ) # if defined(VGO_linux) sys = ML_(get_linux_syscall_entry)( syscallno ); +# elif defined(VGO_freebsd) + if (syscallno >= 0 && syscallno < ML_(syscall_table_size) && + ML_(syscall_table)[syscallno].before != NULL) + sys = &ML_(syscall_table)[syscallno]; + # elif defined(VGO_darwin) Int idx = VG_DARWIN_SYSNO_INDEX(syscallno); @@ -1786,6 +2046,9 @@ void VG_(client_syscall) ( ThreadId tid, UInt trc ) is interrupted by a signal. */ sysno = sci->orig_args.sysno; +# if defined(VGO_freebsd) + tst->arch.vex.guest_SC_CLASS = sci->orig_args.klass; +# endif /* It's sometimes useful, as a crude debugging hack, to get a stack trace at each (or selected) syscalls. */ if (0 && sysno == __NR_ioctl) { @@ -2186,7 +2449,7 @@ void VG_(post_syscall) (ThreadId tid) /* These are addresses within ML_(do_syscall_for_client_WRK). See syscall-$PLAT.S for details. */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) extern const Addr ML_(blksys_setup); extern const Addr ML_(blksys_restart); extern const Addr ML_(blksys_complete); @@ -2363,6 +2626,46 @@ void ML_(fixup_guest_state_to_restart_syscall) ( ThreadArchState* arch ) vg_assert(p[0] == 0x01 && p[1] == 0x00 && p[2] == 0x00 && p[3] == 0xD4); } +#elif defined(VGP_x86_freebsd) + /* XXX: we support different syscall methods. */ + arch->vex.guest_EIP -= 2; // sizeof(int $0x80) + + /* Make sure our caller is actually sane, and we're really backing + back over a syscall. + + int $0x80 == CD 80 + */ + { + UChar *p = (UChar *)arch->vex.guest_EIP; + + if (p[0] != 0xcd || p[1] != 0x80) + VG_(message)(Vg_DebugMsg, + "?! restarting over syscall at %#x %02x %02x\n", + arch->vex.guest_EIP, p[0], p[1]); + + vg_assert(p[0] == 0xcd && p[1] == 0x80); + } + +#elif defined(VGP_amd64_freebsd) + /* XXX: we support different syscall methods. */ + arch->vex.guest_RIP -= 2; // sizeof(syscall) + + /* Make sure our caller is actually sane, and we're really backing + back over a syscall. + + syscall == 0F 05 + */ + { + UChar *p = (UChar *)arch->vex.guest_RIP; + + if (p[0] != 0x0F || p[1] != 0x05) + VG_(message)(Vg_DebugMsg, + "?! restarting over syscall at %#llx %02x %02x\n", + arch->vex.guest_RIP, p[0], p[1]); + + vg_assert(p[0] == 0x0F && p[1] == 0x05); + } + #elif defined(VGP_x86_darwin) arch->vex.guest_EIP = arch->vex.guest_IP_AT_SYSCALL; @@ -2592,7 +2895,7 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, th_regs = &tst->arch; sci = & syscallInfo[tid]; -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) outside_range = ip < ML_(blksys_setup) || ip >= ML_(blksys_finished); in_setup_to_restart @@ -2741,6 +3044,24 @@ VG_(fixup_guest_state_after_syscall_interrupted)( ThreadId tid, /* Result committed, but the signal mask has not been restored; we expect our caller (the signal handler) will have fixed this up. */ +/* XXX: needed? */ +#if defined(VGP_x86_freebsd) + /* On FreeBSD, the success/fail status is returned to the caller + and still has to be fixed up here. */ + if (!(sci->flags & SfNoWriteResult)) { + if (sr_isError(sres)) + LibVEX_GuestX86_put_eflag_c(1, &th_regs->vex); + else + LibVEX_GuestX86_put_eflag_c(0, &th_regs->vex); + } +#elif defined(VGP_amd64_freebsd) + if (!(sci->flags & SfNoWriteResult)) { + if (sr_isError(sres)) + LibVEX_GuestAMD64_put_rflag_c(1, &th_regs->vex); + else + LibVEX_GuestAMD64_put_rflag_c(0, &th_regs->vex); + } +#endif if (VG_(clo_trace_signals)) VG_(message)( Vg_DebugMsg, " completed and committed: nothing to do\n"); diff --git a/coregrind/m_syswrap/syswrap-x86-freebsd.c b/coregrind/m_syswrap/syswrap-x86-freebsd.c new file mode 100755 index 000000000..fffa039e6 --- /dev/null +++ b/coregrind/m_syswrap/syswrap-x86-freebsd.c @@ -0,0 +1,1170 @@ + +/*--------------------------------------------------------------------*/ +/*--- Platform-specific syscalls stuff. syswrap-x86-linux.c ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2008 Nicholas Nethercote + njn@valgrind.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#if defined(VGP_x86_freebsd) + +/* TODO/FIXME jrs 20050207: assignments to the syscall return result + in interrupted_syscall() need to be reviewed. They don't seem + to assign the shadow state. +*/ + +#include "pub_core_basics.h" +#include "pub_core_vki.h" +#include "pub_core_vkiscnums.h" +#include "pub_core_libcsetjmp.h" // to keep _threadstate.h happy +#include "pub_core_threadstate.h" +#include "pub_core_aspacemgr.h" +#include "pub_core_debuglog.h" +#include "pub_core_libcbase.h" +#include "pub_core_libcassert.h" +#include "pub_core_libcprint.h" +#include "pub_core_libcproc.h" +#include "pub_core_libcsignal.h" +#include "pub_core_machine.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 "pub_core_stacks.h" // VG_(register_stack) + +#include "priv_types_n_macros.h" +#include "priv_syswrap-generic.h" /* for decls of generic wrappers */ +#include "priv_syswrap-freebsd.h" /* for decls of linux-ish wrappers */ +#include "priv_syswrap-main.h" + +/* --------------------------------------------------------------------- + clone() handling + ------------------------------------------------------------------ */ + +/* Call f(arg1), but first switch stacks, using 'stack' as the new + stack, and use 'retaddr' as f's return-to address. Also, clear all + the integer registers before entering f.*/ +__attribute__((noreturn)) +void ML_(call_on_new_stack_0_1) ( Addr stack, + Addr retaddr, + void (*f)(Word), + Word arg1 ); +// 4(%esp) == stack +// 8(%esp) == retaddr +// 12(%esp) == f +// 16(%esp) == arg1 +asm( +".text\n" +".globl vgModuleLocal_call_on_new_stack_0_1\n" +"vgModuleLocal_call_on_new_stack_0_1:\n" +" movl %esp, %esi\n" // remember old stack pointer +" movl 4(%esi), %esp\n" // set stack +" pushl 16(%esi)\n" // arg1 to stack +" pushl 8(%esi)\n" // retaddr to stack +" pushl 12(%esi)\n" // f to stack +" movl $0, %eax\n" // zero all GP regs +" movl $0, %ebx\n" +" movl $0, %ecx\n" +" movl $0, %edx\n" +" movl $0, %esi\n" +" movl $0, %edi\n" +" movl $0, %ebp\n" +" ret\n" // jump to f +" ud2\n" // should never get here +".previous\n" +); + + +#if 0 +/* + Perform a rfork system call. rfork is strange because it has + fork()-like return-twice semantics, so it needs special + handling here. + + Upon entry, we have: + + int (fn)(void*) in 0+FSZ(%esp) + void* child_stack in 4+FSZ(%esp) + int flags in 8+FSZ(%esp) + void* arg in 12+FSZ(%esp) + pid_t* child_tid in 16+FSZ(%esp) + pid_t* parent_tid in 20+FSZ(%esp) + void* tls_ptr in 24+FSZ(%esp) + + System call requires: + + int $__NR_clone in %eax + int flags in %ebx + void* child_stack in %ecx + pid_t* parent_tid in %edx + pid_t* child_tid in %edi + void* tls_ptr in %esi + + Returns an Int encoded in the linux-x86 way, not a SysRes. + */ +#define FSZ "4+4+4+4" /* frame size = retaddr+ebx+edi+esi */ +#define __NR_CLONE VG_STRINGIFY(__NR_clone) +#define __NR_EXIT VG_STRINGIFY(__NR_exit) + +extern +Int do_syscall_clone_x86_freebsd ( Word (*fn)(void *), + void* stack, + Int flags, + void* arg, + Int* child_tid, + Int* parent_tid, + vki_modify_ldt_t * ); +asm( +".text\n" +"do_syscall_clone_x86_freebsd:\n" +" push %ebx\n" +" push %edi\n" +" push %esi\n" + + /* set up child stack with function and arg */ +" movl 4+"FSZ"(%esp), %ecx\n" /* syscall arg2: child stack */ +" movl 12+"FSZ"(%esp), %ebx\n" /* fn arg */ +" movl 0+"FSZ"(%esp), %eax\n" /* fn */ +" lea -8(%ecx), %ecx\n" /* make space on stack */ +" movl %ebx, 4(%ecx)\n" /* fn arg */ +" movl %eax, 0(%ecx)\n" /* fn */ + + /* get other args to clone */ +" movl 8+"FSZ"(%esp), %ebx\n" /* syscall arg1: flags */ +" movl 20+"FSZ"(%esp), %edx\n" /* syscall arg3: parent tid * */ +" movl 16+"FSZ"(%esp), %edi\n" /* syscall arg5: child tid * */ +" movl 24+"FSZ"(%esp), %esi\n" /* syscall arg4: tls_ptr * */ +" movl $"__NR_CLONE", %eax\n" +" int $0x80\n" /* clone() */ +" testl %eax, %eax\n" /* child if retval == 0 */ +" jnz 1f\n" + + /* CHILD - call thread function */ +" popl %eax\n" +" call *%eax\n" /* call fn */ + + /* exit with result */ +" movl %eax, %ebx\n" /* arg1: return value from fn */ +" movl $"__NR_EXIT", %eax\n" +" int $0x80\n" + + /* Hm, exit returned */ +" ud2\n" + +"1:\n" /* PARENT or ERROR */ +" pop %esi\n" +" pop %edi\n" +" pop %ebx\n" +" ret\n" +".previous\n" +); + +#undef FSZ +#undef __NR_CLONE +#undef __NR_EXIT + + +// forward declarations +static void setup_child ( ThreadArchState*, ThreadArchState*, Bool ); + +/* + When a client clones, we need to keep track of the new thread. This means: + 1. allocate a ThreadId+ThreadState+stack for the the thread + + 2. initialize the thread's new VCPU state + + 3. create the thread using the same args as the client requested, + but using the scheduler entrypoint for EIP, and a separate stack + for ESP. + */ +static SysRes do_rfork ( ThreadId ptid, + UInt flags) +{ + static const Bool debug = False; + + Addr esp; + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(ptid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + UWord* stack; + NSegment const* seg; + SysRes res; + Int eax; + vki_sigset_t blockall, savedmask; + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(ptid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + stack = (UWord*)ML_(allocstack)(ctid); + if (stack == NULL) { + res = VG_(mk_SysRes_Error)( VKI_ENOMEM ); + goto out; + } + + /* Copy register state + + Both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL esp for the new thread, then + it actually gets a copy of the parent's esp. + */ + /* Note: the clone call done by the Quadrics Elan3 driver specifies + clone flags of 0xF00, and it seems to rely on the assumption + that the child inherits a copy of the parent's GDT. + setup_child takes care of setting that up. */ + setup_child( &ctst->arch, &ptst->arch, True ); + + /* Make sys_clone appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_EAX = 0; + + /* Assume linuxthreads port storing its intended stack in %esi */ + esp = ctst->arch.vex.guest_ESI; + + ctst->os_state.parent = ptid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* We don't really know where the client stack is, because its + 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. */ + seg = VG_(am_find_nsegment)((Addr)esp); + if (seg && seg->kind != SkResvn) { + ctst->client_stack_highest_byte = (Addr)VG_PGROUNDUP(esp); + ctst->client_stack_szB = ctst->client_stack_highest_byte - seg->start; + + VG_(register_stack)(seg->start, ctst->client_stack_highest_byte); + + if (debug) + VG_(printf)("tid %d: guessed client stack range %#lx-%#lx\n", + ctid, seg->start, VG_PGROUNDUP(esp)); + } else { + VG_(message)(Vg_UserMsg, "!? New thread %d starts with ESP(%#lx) unmapped\n", + ctid, esp); + ctst->client_stack_szB = 0; + } + + /* Assume the clone will succeed, and tell any tool that wants to + know that this thread has come into existence. We cannot defer + it beyond this point because sys_set_thread_area, just below, + causes tCheck to assert by making references to the new ThreadId + if we don't state the new thread exists prior to that point. + If the clone fails, we'll send out a ll_exit notification for it + at the out: label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, ptid, ctid ); + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Create the new thread */ + /* XXX need to see what happens with tids etc with rfork */ + eax = do_syscall_clone_x86_freebsd( + ML_(start_thread_NORETURN), stack, flags /*, &VG_(threads)[ctid], NULL*/ ); + res = VG_(mk_SysRes_x86_freebsd)( eax ); /* XXX edx returns too! */ + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + + out: + if (res.isError) { + /* clone failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } + + return res; +} +#endif + +/* Translate a struct modify_ldt_ldt_s to a VexGuestX86SegDescr */ + +static +void translate_to_hw_format ( /* IN */ void* base, + /* OUT */ VexGuestX86SegDescr* out) +{ + UInt entry_1, entry_2; + UInt base_addr = (UInt) base; + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + + if (0) + VG_(printf)("translate_to_hw_format: base %p\n", base ); + + /* Allow LDTs to be cleared by the user. */ + if (base == 0) { + entry_1 = 0; + entry_2 = 0; + goto install; + } + /* base as specified, no limit, read/write/accessed etc */ + entry_1 = ((base_addr & 0x0000ffff) << 16) | 0x0ffff; + entry_2 = (base_addr & 0xff000000) | + ((base_addr & 0x00ff0000) >> 16) | 0x00cff300; + + /* Install the new entry ... */ + install: + out->LdtEnt.Words.word1 = entry_1; + out->LdtEnt.Words.word2 = entry_2; +} + +/* Create a zeroed-out GDT. */ +static VexGuestX86SegDescr* alloc_zeroed_x86_GDT ( void ) +{ + Int nbytes = VEX_GUEST_X86_GDT_NENT * sizeof(VexGuestX86SegDescr); + return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxG.1", nbytes, 1); +} + +#if 0 +/* Create a zeroed-out LDT. */ +static VexGuestX86SegDescr* alloc_zeroed_x86_LDT ( void ) +{ + Int nbytes = VEX_GUEST_X86_LDT_NENT * sizeof(VexGuestX86SegDescr); + return VG_(arena_calloc)(VG_AR_CORE, "di.syswrap-x86.azxL.1", nbytes, 1); +} + +/* Free up an LDT or GDT allocated by the above fns. */ +static void free_LDT_or_GDT ( VexGuestX86SegDescr* dt ) +{ + vg_assert(dt); + VG_(arena_free)(VG_AR_CORE, (void*)dt); +} + +/* Copy contents between two existing LDTs. */ +static void copy_LDT_from_to ( VexGuestX86SegDescr* src, + VexGuestX86SegDescr* dst ) +{ + Int i; + vg_assert(src); + vg_assert(dst); + for (i = 0; i < VEX_GUEST_X86_LDT_NENT; i++) + dst[i] = src[i]; +} + +/* Copy contents between two existing GDTs. */ +static void copy_GDT_from_to ( VexGuestX86SegDescr* src, + VexGuestX86SegDescr* dst ) +{ + Int i; + vg_assert(src); + vg_assert(dst); + for (i = 0; i < VEX_GUEST_X86_GDT_NENT; i++) + dst[i] = src[i]; +} + +/* Free this thread's DTs, if it has any. */ +static void deallocate_LGDTs_for_thread ( VexGuestX86State* vex ) +{ + vg_assert(sizeof(HWord) == sizeof(void*)); + + if (0) + VG_(printf)("deallocate_LGDTs_for_thread: " + "ldt = 0x%x, gdt = 0x%x\n", + vex->guest_LDT, vex->guest_GDT ); + + if (vex->guest_LDT != (HWord)NULL) { + free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_LDT ); + vex->guest_LDT = (HWord)NULL; + } + + if (vex->guest_GDT != (HWord)NULL) { + free_LDT_or_GDT( (VexGuestX86SegDescr*)vex->guest_GDT ); + vex->guest_GDT = (HWord)NULL; + } +} +#endif + +static SysRes sys_set_thread_area ( ThreadId tid, Int *idxptr, void *base) +{ + VexGuestX86SegDescr* gdt; + Int idx; + + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*)); + + gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT; + + /* If the thread doesn't have a GDT, allocate it now. */ + if (!gdt) { + gdt = alloc_zeroed_x86_GDT(); + VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt; + } + + idx = *idxptr; + if (idx == -1) { + /* Find and use the first free entry. Don't allocate entry + zero, because the hardware will never do that, and apparently + doing so confuses some code (perhaps stuff running on + Wine). */ + for (idx = 1; idx < VEX_GUEST_X86_GDT_NENT; idx++) { + if (gdt[idx].LdtEnt.Words.word1 == 0 + && gdt[idx].LdtEnt.Words.word2 == 0) + break; + } + + if (idx == VEX_GUEST_X86_GDT_NENT) + return VG_(mk_SysRes_Error)( VKI_ESRCH ); + } else if (idx < 0 || idx == 0 || idx >= VEX_GUEST_X86_GDT_NENT) { + /* Similarly, reject attempts to use GDT[0]. */ + return VG_(mk_SysRes_Error)( VKI_EINVAL ); + } + + translate_to_hw_format(base, &gdt[idx]); + + *idxptr = idx; + return VG_(mk_SysRes_Success)( 0 ); +} + +static SysRes sys_get_thread_area ( ThreadId tid, Int idx, void ** basep ) +{ + VexGuestX86SegDescr* gdt; + UInt base; + + vg_assert(sizeof(HWord) == sizeof(VexGuestX86SegDescr*)); + vg_assert(8 == sizeof(VexGuestX86SegDescr)); + + gdt = (VexGuestX86SegDescr*)VG_(threads)[tid].arch.vex.guest_GDT; + + /* If the thread doesn't have a GDT, allocate it now. */ + if (!gdt) { + gdt = alloc_zeroed_x86_GDT(); + VG_(threads)[tid].arch.vex.guest_GDT = (HWord)gdt; + } + + base = ( gdt[idx].LdtEnt.Bits.BaseHi << 24 ) | + ( gdt[idx].LdtEnt.Bits.BaseMid << 16 ) | + gdt[idx].LdtEnt.Bits.BaseLow; + *basep = (void *)base; + + return VG_(mk_SysRes_Success)( 0 ); +} + +/* --------------------------------------------------------------------- + More thread stuff + ------------------------------------------------------------------ */ + +void VG_(cleanup_thread) ( ThreadArchState* arch ) +{ +} + + +#if 0 +static void setup_child ( /*OUT*/ ThreadArchState *child, + /*IN*/ ThreadArchState *parent, + Bool inherit_parents_GDT ) +{ + /* We inherit our parent's guest state. */ + child->vex = parent->vex; + child->vex_shadow1 = parent->vex_shadow1; + child->vex_shadow2 = parent->vex_shadow2; + + /* We inherit our parent's LDT. */ + if (parent->vex.guest_LDT == (HWord)NULL) { + /* We hope this is the common case. */ + child->vex.guest_LDT = (HWord)NULL; + } else { + /* No luck .. we have to take a copy of the parent's. */ + child->vex.guest_LDT = (HWord)alloc_zeroed_x86_LDT(); + copy_LDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_LDT, + (VexGuestX86SegDescr*)child->vex.guest_LDT ); + } + + /* Either we start with an empty GDT (the usual case) or inherit a + copy of our parents' one (Quadrics Elan3 driver -style clone + only). */ + child->vex.guest_GDT = (HWord)NULL; + + if (inherit_parents_GDT && parent->vex.guest_GDT != (HWord)NULL) { + child->vex.guest_GDT = (HWord)alloc_zeroed_x86_GDT(); + copy_GDT_from_to( (VexGuestX86SegDescr*)parent->vex.guest_GDT, + (VexGuestX86SegDescr*)child->vex.guest_GDT ); + } +} +#endif + +/* --------------------------------------------------------------------- + PRE/POST wrappers for x86/Linux-specific syscalls + ------------------------------------------------------------------ */ + +#define PRE(name) DEFN_PRE_TEMPLATE(freebsd, name) +#define POST(name) DEFN_POST_TEMPLATE(freebsd, name) + +#if 0 +struct thr_param { + void (*start_func)(void *); /* thread entry function. */ + void *arg; /* argument for entry function. */ + char *stack_base; /* stack base address. */ + size_t stack_size; /* stack size. */ + char *tls_base; /* tls base address. */ + size_t tls_size; /* tls size. */ + long *child_tid; /* address to store new TID. */ + long *parent_tid; /* parent accesses the new TID here. */ + int flags; /* thread flags. */ + struct rtprio *rtp; /* Real-time scheduling priority */ + void *spare[3]; /* TODO: cpu affinity mask etc. */ +}; +int thr_new(struct thr_param *param, int param_size); +#endif + +PRE(sys_thr_new) +{ + static const Bool debug = False; + + ThreadId ctid = VG_(alloc_ThreadState)(); + ThreadState* ptst = VG_(get_ThreadState)(tid); + ThreadState* ctst = VG_(get_ThreadState)(ctid); + SysRes res; + vki_sigset_t blockall, savedmask; + struct vki_thr_param tp; + Int idx = -1; + Addr stk; + + PRINT("thr_new ( %#lx, %ld )",ARG1,ARG2); + PRE_REG_READ2(int, "thr_new", + struct thr_param *, param, + int, param_size); + + PRE_MEM_READ( "thr_new(param)", ARG1, offsetof(struct vki_thr_param, spare)); + if (!ML_(safe_to_deref)( (void*)ARG1, offsetof(struct vki_thr_param, spare))) { + SET_STATUS_Failure( VKI_EFAULT ); + return; + } + VG_(memset)(&tp, 0, sizeof(tp)); + VG_(memcpy)(&tp, (void *)ARG1, offsetof(struct vki_thr_param, spare)); + PRE_MEM_WRITE("clone(parent_tidptr)", (Addr)tp.parent_tid, sizeof(long)); + PRE_MEM_WRITE("clone(child_tidptr)", (Addr)tp.child_tid, sizeof(long)); + + VG_(sigfillset)(&blockall); + + vg_assert(VG_(is_running_thread)(tid)); + vg_assert(VG_(is_valid_tid)(ctid)); + + /* Copy register state + + On linux, both parent and child return to the same place, and the code + following the clone syscall works out which is which, so we + don't need to worry about it. + On FreeBSD, thr_new arranges a direct call. We don't actually need any + of this gunk. + + The parent gets the child's new tid returned from clone, but the + child gets 0. + + If the clone call specifies a NULL rsp for the new thread, then + it actually gets a copy of the parent's rsp. + */ + /* We inherit our parent's guest state. */ + ctst->arch.vex = ptst->arch.vex; + ctst->arch.vex_shadow1 = ptst->arch.vex_shadow1; + ctst->arch.vex_shadow2 = ptst->arch.vex_shadow2; + + /* Make sys_clone appear to have returned Success(0) in the + child. */ + ctst->arch.vex.guest_EAX = 0; + ctst->arch.vex.guest_EDX = 0; + LibVEX_GuestX86_put_eflag_c(0, &ctst->arch.vex); + + ctst->os_state.parent = tid; + + /* inherit signal mask */ + ctst->sig_mask = ptst->sig_mask; + ctst->tmp_sig_mask = ptst->sig_mask; + + /* Linux has to guess, we don't */ + VG_(register_stack)((Addr)tp.stack_base, (Addr)tp.stack_base + tp.stack_size); + + /* Assume the clone will succeed, and tell any tool that wants to + know that this thread has come into existence. If the clone + fails, we'll send out a ll_exit notification for it at the out: + label below, to clean up. */ + VG_TRACK ( pre_thread_ll_create, tid, ctid ); + + if (debug) + VG_(printf)("clone child has SETTLS: tls at %#lx\n", (Addr)tp.tls_base); + sys_set_thread_area( ctid, &idx, tp.tls_base ); + ctst->arch.vex.guest_GS = (idx << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + tp.tls_base = 0; /* Don't have the kernel do it too */ + + /* start the thread with everything blocked */ + VG_(sigprocmask)(VKI_SIG_SETMASK, &blockall, &savedmask); + + /* Set the client state for scheduler to run libthr's trampoline */ + ctst->arch.vex.guest_ESP = (Addr)tp.stack_base + tp.stack_size - 8; + ctst->arch.vex.guest_EIP = (Addr)tp.start_func; + *(UWord *)(ctst->arch.vex.guest_ESP + 4) = (UWord)tp.arg; /* Client arg */ + *(UWord *)(ctst->arch.vex.guest_ESP + 0) = 0; /* fake return addr */ + + /* Set up valgrind's trampoline on its own stack */ + stk = ML_(allocstack)(ctid); + tp.stack_base = (void *)ctst->os_state.valgrind_stack_base; + tp.stack_size = (Addr)stk - (Addr)tp.stack_base; + /* This is for thr_new() to run valgrind's trampoline */ + tp.start_func = (void *)ML_(start_thread_NORETURN); + tp.arg = &VG_(threads)[ctid]; + + /* Create the new thread */ + res = VG_(do_syscall2)(__NR_thr_new, (UWord)&tp, sizeof(tp)); + + VG_(sigprocmask)(VKI_SIG_SETMASK, &savedmask, NULL); + + if (sr_isError(res)) { + /* clone failed */ + VG_(cleanup_thread)(&ctst->arch); + ctst->status = VgTs_Empty; + /* oops. Better tell the tool the thread exited in a hurry :-) */ + VG_TRACK( pre_thread_ll_exit, ctid ); + } else { + + POST_MEM_WRITE((Addr)tp.parent_tid, sizeof(long)); + POST_MEM_WRITE((Addr)tp.child_tid, sizeof(long)); + POST_MEM_WRITE((Addr)ctst->arch.vex.guest_ESP, 8); + + /* Thread creation was successful; let the child have the chance + to run */ + *flags |= SfYieldAfter; + } + + /* "Complete" the syscall so that the wrapper doesn't call the kernel again. */ + SET_STATUS_from_SysRes(res); +} + + +PRE(sys_rfork) +{ + PRINT("sys_rfork ( %lx )",ARG1); + PRE_REG_READ1(int, "rfork", + unsigned int, flags); + +#if 0 + cloneflags = ARG1; + + if (!ML_(client_signal_OK)(ARG1 & VKI_CSIGNAL)) { + SET_STATUS_Failure( VKI_EINVAL ); + return; + } + + SET_STATUS_from_SysRes( do_clone(tid, ARG1)); + + if (SUCCESS) { + *flags |= SfYieldAfter; + } +#else + VG_(message)(Vg_UserMsg, "No rfork for you!"); + VG_(unimplemented) + ("Valgrind does not support rfork() yet."); + SET_STATUS_Failure( VKI_ENOSYS ); +#endif +} + +PRE(sys_sigreturn) +{ + PRINT("sys_sigreturn ( %#lx )", ARG1); + PRE_REG_READ1(long, "sigreturn", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "sigreturn(ucp)", ARG1, sizeof(struct vki_ucontext) ); +} + +PRE(sys_fake_sigreturn) +{ + /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for + an explanation of what follows. */ + + ThreadState* tst; + struct vki_ucontext *uc; + PRINT("sys_sigreturn ( )"); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + /* Adjust esp to point to start of frame; skip back up over handler + ret addr */ + tst = VG_(get_ThreadState)(tid); + tst->arch.vex.guest_ESP -= sizeof(Addr); /* QQQ should be redundant */ + + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + /* Restore register state from frame and remove it */ + VG_(sigframe_destroy)(tid); + + /* + * Signal handler might have changed the signal mask. Respect that. + */ + tst->sig_mask = uc->uc_sigmask; + tst->tmp_sig_mask = uc->uc_sigmask; + + /* 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; +} + +#if 0 /* QQQ keep for 6.x signals */ +PRE(sys_rt_sigreturn) +{ + /* See comments on PRE(sys_rt_sigreturn) in syswrap-amd64-linux.c for + an explanation of what follows. */ + + ThreadState* tst; + PRINT("sys_rt_sigreturn ( )"); + + vg_assert(VG_(is_valid_tid)(tid)); + vg_assert(tid >= 1 && tid < VG_N_THREADS); + vg_assert(VG_(is_running_thread)(tid)); + + /* Adjust esp to point to start of frame; skip back up over handler + ret addr */ + tst = VG_(get_ThreadState)(tid); + tst->arch.vex.guest_ESP -= sizeof(Addr); + + /* This is only so that the EIP is (might be) useful to report if + something goes wrong in the sigreturn */ + ML_(fixup_guest_state_to_restart_syscall)(&tst->arch); + + /* Restore register state from frame and remove it */ + 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; +} +#endif + +static void restore_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + tst->arch.vex.guest_EAX = sc->eax; + tst->arch.vex.guest_ECX = sc->ecx; + tst->arch.vex.guest_EDX = sc->edx; + tst->arch.vex.guest_EBX = sc->ebx; + tst->arch.vex.guest_EBP = sc->ebp; + tst->arch.vex.guest_ESP = sc->esp; + tst->arch.vex.guest_ESI = sc->esi; + tst->arch.vex.guest_EDI = sc->edi; + tst->arch.vex.guest_EIP = sc->eip; + tst->arch.vex.guest_CS = sc->cs; + tst->arch.vex.guest_SS = sc->ss; + tst->arch.vex.guest_DS = sc->ds; + tst->arch.vex.guest_ES = sc->es; + tst->arch.vex.guest_FS = sc->fs; + tst->arch.vex.guest_GS = sc->gs; + /* + * XXX: missing support for other flags. + */ + if (sc->eflags & 0x0001) + LibVEX_GuestX86_put_eflag_c(1, &tst->arch.vex); + else + LibVEX_GuestX86_put_eflag_c(0, &tst->arch.vex); +} + +static void fill_mcontext(ThreadState *tst, struct vki_mcontext *sc) +{ + sc->eax = tst->arch.vex.guest_EAX; + sc->ecx = tst->arch.vex.guest_ECX; + sc->edx = tst->arch.vex.guest_EDX; + sc->ebx = tst->arch.vex.guest_EBX; + sc->ebp = tst->arch.vex.guest_EBP; + sc->esp = tst->arch.vex.guest_ESP; + sc->esi = tst->arch.vex.guest_ESI; + sc->edi = tst->arch.vex.guest_EDI; + sc->eip = tst->arch.vex.guest_EIP; + sc->cs = tst->arch.vex.guest_CS; + sc->ss = tst->arch.vex.guest_SS; + sc->ds = tst->arch.vex.guest_DS; + sc->es = tst->arch.vex.guest_ES; + sc->fs = tst->arch.vex.guest_FS; + sc->gs = tst->arch.vex.guest_GS; + sc->eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex); +/* + not yet. + VG_(memcpy)(&sc->fpstate, fpstate, sizeof(*fpstate)); +*/ + sc->fpformat = VKI_FPFMT_NODEV; + sc->ownedfp = VKI_FPOWNED_NONE; + sc->len = sizeof(*sc); + VG_(memset)(sc->spare2, 0, sizeof(sc->spare2)); +} + + +PRE(sys_getcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_getcontext ( %#lx )", ARG1); + PRE_REG_READ1(long, "getcontext", + struct vki_ucontext *, ucp); + PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + fill_mcontext(tst, &uc->uc_mcontext); + uc->uc_mcontext.eax = 0; + uc->uc_mcontext.edx = 0; + uc->uc_mcontext.eflags &= ~0x0001; /* PSL_C */ + uc->uc_sigmask = tst->sig_mask; + VG_(memset)(uc->__spare__, 0, sizeof(uc->__spare__)); + SET_STATUS_Success(0); +} + +PRE(sys_setcontext) +{ + ThreadState* tst; + struct vki_ucontext *uc; + + PRINT("sys_setcontext ( %#lx )", ARG1); + PRE_REG_READ1(long, "setcontext", + struct vki_ucontext *, ucp); + + PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) ); + + 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); + uc = (struct vki_ucontext *)ARG1; + if (uc == NULL || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + + restore_mcontext(tst, &uc->uc_mcontext); + tst->sig_mask = uc->uc_sigmask; + + /* 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 some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +PRE(sys_swapcontext) +{ + struct vki_ucontext *ucp, *oucp; + ThreadState* tst; + + PRINT("sys_swapcontext ( %#lx, %#lx )", ARG1, ARG2); + PRE_REG_READ2(long, "swapcontext", + struct vki_ucontext *, oucp, struct vki_ucontext *, ucp); + + PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) ); + PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) ); + + oucp = (struct vki_ucontext *)ARG1; + ucp = (struct vki_ucontext *)ARG2; + if (oucp == NULL || ucp == NULL || ucp->uc_mcontext.len != sizeof(ucp->uc_mcontext)) { + SET_STATUS_Failure(VKI_EINVAL); + return; + } + tst = VG_(get_ThreadState)(tid); + + /* + * Save the context. + */ + fill_mcontext(tst, &oucp->uc_mcontext); + oucp->uc_mcontext.eax = 0; + oucp->uc_mcontext.edx = 0; + oucp->uc_mcontext.eflags &= ~0x0001; /* PSL_C */ + oucp->uc_sigmask = tst->sig_mask; + VG_(memset)(oucp->__spare__, 0, sizeof(oucp->__spare__)); + + /* + * Switch to new one. + */ + restore_mcontext(tst, &ucp->uc_mcontext); + tst->sig_mask = ucp->uc_sigmask; + + /* 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 some any signals arose as a result of this. */ + *flags |= SfPollAfter; +} + +/* This is here because on x86 the off_t is passed in 2 regs. Don't ask about pad. */ + +/* caddr_t mmap(caddr_t addr, size_t len, int prot, int flags, int fd, int pad, off_t pos); */ +/* ARG1 ARG2 ARG3 ARG4 ARG5 ARG6 ARG7+ARG8 */ + +PRE(sys_mmap) +{ + SysRes r; + + PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, pad%ld, lo0x%lx hi0x%lx)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8 ); + PRE_REG_READ8(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, int, pad, unsigned long, lo, unsigned long, hi); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG7 + ((Off64T)ARG8 << 32) ); + SET_STATUS_from_SysRes(r); +} + +PRE(sys_mmap7) +{ + SysRes r; + + PRINT("sys_mmap ( %#lx, %lu, %ld, %ld, %ld, lo0x%lx hi0x%lx)", + ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6, ARG7 ); + PRE_REG_READ7(long, "mmap", + char *, addr, unsigned long, len, int, prot, int, flags, + int, fd, unsigned long, lo, unsigned long, hi); + + r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 + ((Off64T)ARG7 << 32) ); + SET_STATUS_from_SysRes(r); +} + +PRE(sys_lseek) +{ + PRINT("sys_lseek ( %ld, 0x%lx, 0x%lx, %ld )", ARG1,ARG3,ARG4,ARG5); + PRE_REG_READ5(long, "lseek", + unsigned int, fd, int, pad, unsigned int, offset_low, + unsigned int, offset_high, unsigned int, whence); +} + +PRE(sys_lseek7) +{ + PRINT("sys_lseek ( %ld, 0x%lx, 0x%lx, %ld )", ARG1,ARG2,ARG3,ARG4); + PRE_REG_READ4(long, "lseek", + unsigned int, fd, unsigned int, offset_low, + unsigned int, offset_high, unsigned int, whence); +} + +PRE(sys_pread) +{ + *flags |= SfMayBlock; + PRINT("sys_read ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "read", + unsigned int, fd, char *, buf, vki_size_t, count, + int, pad, unsigned int, off_low, unsigned int, off_high); + + if (!ML_(fd_allowed)(ARG1, "read", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "read(buf)", ARG2, ARG3 ); +} + +POST(sys_pread) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +PRE(sys_pread7) +{ + *flags |= SfMayBlock; + PRINT("sys_read ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "read", + unsigned int, fd, char *, buf, vki_size_t, count, + unsigned int, off_low, unsigned int, off_high); + + if (!ML_(fd_allowed)(ARG1, "read", tid, False)) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_WRITE( "read(buf)", ARG2, ARG3 ); +} + +POST(sys_pread7) +{ + vg_assert(SUCCESS); + POST_MEM_WRITE( ARG2, RES ); +} + +PRE(sys_pwrite) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_write ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG5, ARG6); + PRE_REG_READ6(ssize_t, "write", + unsigned int, fd, const char *, buf, vki_size_t, count, + int, pad, unsigned int, off_low, unsigned int, off_high); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "write", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && VG_(strstr)(VG_(clo_sim_hints),"enable-outer")) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "write(buf)", ARG2, ARG3 ); +} + +PRE(sys_pwrite7) +{ + Bool ok; + *flags |= SfMayBlock; + PRINT("sys_write ( %ld, %#lx, %lu, %lu, %lu )", ARG1, ARG2, ARG3, ARG4, ARG5); + PRE_REG_READ5(ssize_t, "write", + unsigned int, fd, const char *, buf, vki_size_t, count, + unsigned int, off_low, unsigned int, off_high); + /* check to see if it is allowed. If not, try for an exemption from + --sim-hints=enable-outer (used for self hosting). */ + ok = ML_(fd_allowed)(ARG1, "write", tid, False); + if (!ok && ARG1 == 2/*stderr*/ + && VG_(strstr)(VG_(clo_sim_hints),"enable-outer")) + ok = True; + if (!ok) + SET_STATUS_Failure( VKI_EBADF ); + else + PRE_MEM_READ( "write(buf)", ARG2, ARG3 ); +} + +PRE(sys_ftruncate) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %ld, %lu, %lu )", ARG1,ARG3,ARG4); + PRE_REG_READ4(long, "ftruncate", unsigned int, fd, int, pad, + unsigned int, length_low, unsigned int, length_high); +} + +PRE(sys_ftruncate7) +{ + *flags |= SfMayBlock; + PRINT("sys_ftruncate ( %ld, %lu, %lu )", ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "ftruncate", unsigned int, fd, + unsigned int, length_low, unsigned int, length_high); +} + +PRE(sys_truncate) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#lx(%s), %lu, %lu )", ARG1,(char *)ARG1,ARG3,ARG4); + PRE_REG_READ4(long, "truncate", + const char *, path, int, pad, + unsigned int, length_low, unsigned int, length_high); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +PRE(sys_truncate7) +{ + *flags |= SfMayBlock; + PRINT("sys_truncate ( %#lx(%s), %lu, %lu )", ARG1,(char *)ARG1,ARG2,ARG3); + PRE_REG_READ3(long, "truncate", + const char *, path, + unsigned int, length_low, unsigned int, length_high); + PRE_MEM_RASCIIZ( "truncate(path)", ARG1 ); +} + +PRE(sys_sysarch) +{ + ThreadState *tst; + Int idx; + void **p; + + PRINT("sys_sysarch ( %ld, %#lx )", ARG1, ARG2); + PRE_REG_READ2(int, "sysarch", + int, number, void *, args); + switch (ARG1) { + case VKI_I386_SET_GSBASE: + PRINT("sys_i386_set_gsbase ( %#lx )", ARG2); + PRE_REG_READ1(int, "i386_set_gsbase", void *, base) + + /* On FreeBSD, the syscall loads the %gs selector for us, so do it now. */ + tst = VG_(get_ThreadState)(tid); + p = (void**)ARG2; + tst->arch.vex.guest_GS = (1 << 3) | 3; /* GSEL(GUGS_SEL, SEL_UPL) */ + /* "do" the syscall ourselves; the kernel never sees it */ + idx = 1; + SET_STATUS_from_SysRes( sys_set_thread_area( tid, &idx, *p ) ); + + break; + case VKI_I386_GET_GSBASE: + PRINT("sys_i386_get_gsbase ( %#lx )", ARG2); + PRE_REG_READ1(int, "i386_get_gsbase", void *, basep) + PRE_MEM_WRITE( "i386_get_gsbase(basep)", ARG2, sizeof(void *) ); + + /* "do" the syscall ourselves; the kernel never sees it */ + SET_STATUS_from_SysRes( sys_get_thread_area( tid, 2, (void **)ARG2 ) ); + + if (SUCCESS) { + POST_MEM_WRITE( ARG2, sizeof(void *) ); + } + break; + case VKI_I386_GET_XFPUSTATE: + PRINT("sys_i386_get_xfpustate ( %#lx )", ARG2); + PRE_REG_READ1(int, "i386_get_xfpustate", void *, basep) + PRE_MEM_WRITE( "i386_get_xfpustate(basep)", ARG2, sizeof(void *) ); + + /* "do" the syscall ourselves; the kernel never sees it */ + tst = VG_(get_ThreadState)(tid); + SET_STATUS_Success2( tst->arch.vex.guest_FPTAG[0], tst->arch.vex.guest_FPTAG[0] ); + POST_MEM_WRITE( ARG2, sizeof(void *) ); + break; + default: + VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %ld", ARG1); + VG_(unimplemented) ("unhandled sysarch cmd"); + break; + } +} + +#undef PRE +#undef POST + +#endif /* defined(VGP_x86_linux) */ + + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/coregrind/m_trampoline.S b/coregrind/m_trampoline.S index 0488b54bd..b4b39b2a3 100644 --- a/coregrind/m_trampoline.S +++ b/coregrind/m_trampoline.S @@ -853,6 +853,63 @@ VG_(trampoline_stuff_end): # undef UD2_1024 # undef UD2_PAGE +/*---------------- x86-freebsd ----------------*/ +#else +#if defined(VGP_x86_freebsd) + +.global VG_(trampoline_stuff_start) +VG_(trampoline_stuff_start): + +.global VG_(x86_freebsd_SUBST_FOR_sigreturn) +VG_(x86_freebsd_SUBST_FOR_sigreturn): + lea 0x14(%esp), %eax /* args to sigreturn(ucontext_t *) */ + pushl %eax + pushl %eax /* fake return addr */ +/* movl 0x44(%eax), %gs ; restore %gs, not done by sigreturn */ + movl $__NR_fake_sigreturn, %eax + int $0x80 + ud2 + +.global VG_(trampoline_stuff_end) +VG_(trampoline_stuff_end): + +#else +#if defined(VGP_amd64_freebsd) + +# define UD2_16 ud2 ; ud2 ; ud2 ; ud2 ;ud2 ; ud2 ; ud2 ; ud2 +# define UD2_64 UD2_16 ; UD2_16 ; UD2_16 ; UD2_16 +# define UD2_256 UD2_64 ; UD2_64 ; UD2_64 ; UD2_64 +# define UD2_1024 UD2_256 ; UD2_256 ; UD2_256 ; UD2_256 +# define UD2_PAGE UD2_1024 ; UD2_1024 ; UD2_1024 ; UD2_1024 + + /* a leading page of unexecutable code */ + UD2_PAGE + +.global VG_(trampoline_stuff_start) +VG_(trampoline_stuff_start): + +.global VG_(amd64_freebsd_SUBST_FOR_sigreturn) +VG_(amd64_freebsd_SUBST_FOR_sigreturn): + /* This is a very specific sequence which GDB uses to + recognize signal handler frames. */ + movq $__NR_fake_sigreturn, %rax + movq %rsp, %rdi + addq $40,%rdi + syscall + ud2 + +.global VG_(trampoline_stuff_end) +VG_(trampoline_stuff_end): + + /* and a trailing page of unexecutable code */ + UD2_PAGE + +# undef UD2_16 +# undef UD2_64 +# undef UD2_256 +# undef UD2_1024 +# undef UD2_PAGE + /*---------------- x86-darwin ----------------*/ #else #if defined(VGP_x86_darwin) @@ -1581,6 +1638,8 @@ VG_(trampoline_stuff_end): #endif #endif #endif +#endif +#endif /* Let the linker know we don't need an executable stack */ MARK_STACK_NO_EXEC diff --git a/coregrind/m_translate.c b/coregrind/m_translate.c index 3602a4663..c206e0789 100644 --- a/coregrind/m_translate.c +++ b/coregrind/m_translate.c @@ -1678,7 +1678,9 @@ Bool VG_(translate) ( ThreadId tid, vex_abiinfo.guest_amd64_assume_fs_is_const = True; vex_abiinfo.guest_amd64_assume_gs_is_const = True; # endif - +# if defined(VGP_amd64_freebsd) + vex_abiinfo.guest_amd64_assume_fs_is_const = True; +# endif # if defined(VGP_amd64_darwin) vex_abiinfo.guest_amd64_assume_gs_is_const = True; # endif diff --git a/coregrind/m_ume/elf.c b/coregrind/m_ume/elf.c index 21eb52bcb..72f63d407 100644 --- a/coregrind/m_ume/elf.c +++ b/coregrind/m_ume/elf.c @@ -28,7 +28,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) #include "pub_core_basics.h" #include "pub_core_vki.h" @@ -644,6 +644,15 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info) VG_(pread)(fd, buf, ph->p_filesz, ph->p_offset); buf[ph->p_filesz] = '\0'; +#if defined(VGP_x86_freebsd) + sres._isError = True; + /* Hack. FreeBSD's kernel overloads the interpreter name. */ + if (VG_(strcmp)(buf, "/libexec/ld-elf.so.1") == 0 || + VG_(strcmp)(buf, "/usr/libexec/ld-elf.so.1") == 0) { + sres = VG_(open)("/libexec/ld-elf32.so.1", VKI_O_RDONLY, 0); + } + if (sr_isError(sres)) +#endif sres = VG_(open)(buf, VKI_O_RDONLY, 0); if (sr_isError(sres)) { VG_(printf)("valgrind: m_ume.c: can't open interpreter\n"); @@ -870,7 +879,7 @@ Int VG_(load_ELF)(Int fd, const HChar* name, /*MOD*/ExeInfo* info) return 0; } -#endif // defined(VGO_linux) || defined(VGO_solaris) +#endif // defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /*--------------------------------------------------------------------*/ /*--- end ---*/ diff --git a/coregrind/m_ume/main.c b/coregrind/m_ume/main.c index 9990b4df9..8390bba6e 100644 --- a/coregrind/m_ume/main.c +++ b/coregrind/m_ume/main.c @@ -51,7 +51,7 @@ typedef struct { } ExeHandler; static ExeHandler exe_handlers[] = { -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) { VG_(match_ELF), VG_(load_ELF) }, # elif defined(VGO_darwin) { VG_(match_macho), VG_(load_macho) }, diff --git a/coregrind/m_ume/priv_ume.h b/coregrind/m_ume/priv_ume.h index c06445803..805204195 100644 --- a/coregrind/m_ume/priv_ume.h +++ b/coregrind/m_ume/priv_ume.h @@ -27,7 +27,7 @@ The GNU General Public License is contained in the file COPYING. */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) #ifndef __PRIV_UME_H #define __PRIV_UME_H @@ -36,7 +36,7 @@ extern Int VG_(do_exec_inner)(const HChar *exe, ExeInfo *info); -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) extern Bool VG_(match_ELF) ( const void *hdr, SizeT len ); extern Int VG_(load_ELF) ( Int fd, const HChar *name, ExeInfo *info ); #elif defined(VGO_darwin) diff --git a/coregrind/m_vki.c b/coregrind/m_vki.c index a5847ec2a..21298d46a 100644 --- a/coregrind/m_vki.c +++ b/coregrind/m_vki.c @@ -77,7 +77,7 @@ void VG_(vki_do_initial_consistency_checks) ( void ) /* --- Platform-specific checks on signal sets --- */ -# if defined(VGO_linux) || defined(VGO_solaris) +# if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) /* nothing to check */ # elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin) vg_assert(_VKI_NSIG == NSIG); @@ -91,7 +91,7 @@ void VG_(vki_do_initial_consistency_checks) ( void ) /* --- Platform-specific checks on sigactions --- */ -# if defined(VGO_linux) +# if defined(VGO_linux) || defined(VGO_freebsd) /* the toK- and fromK- forms are identical */ vg_assert( sizeof(vki_sigaction_toK_t) == sizeof(vki_sigaction_fromK_t) ); diff --git a/coregrind/m_vkiscnums.c b/coregrind/m_vkiscnums.c index 996345e91..ad7550e97 100644 --- a/coregrind/m_vkiscnums.c +++ b/coregrind/m_vkiscnums.c @@ -69,6 +69,17 @@ STATIC_ASSERT(__NR_pipe2 == 5287); #endif //--------------------------------------------------------------------------- +#elif defined(VGO_freebsd) +//--------------------------------------------------------------------------- + +const HChar* VG_(sysnum_string)(Word sysnum) +{ + static HChar buf[20+1]; // large enough + + VG_(snprintf)(buf, sizeof(buf), "%3ld", sysnum); + return buf; +} + #elif defined(VGO_darwin) //--------------------------------------------------------------------------- diff --git a/coregrind/pub_core_debuginfo.h b/coregrind/pub_core_debuginfo.h index e3d8453de..0f8458b7b 100644 --- a/coregrind/pub_core_debuginfo.h +++ b/coregrind/pub_core_debuginfo.h @@ -62,7 +62,7 @@ extern void VG_(di_initialise) ( void ); released by simply re-opening and closing the same file (even via different fd!). */ -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) extern ULong VG_(di_notify_mmap)( Addr a, Bool allow_SkFileV, Int use_fd ); extern void VG_(di_notify_munmap)( Addr a, SizeT len ); diff --git a/coregrind/pub_core_initimg.h b/coregrind/pub_core_initimg.h index 5ac4411c4..72f7c227e 100644 --- a/coregrind/pub_core_initimg.h +++ b/coregrind/pub_core_initimg.h @@ -68,7 +68,7 @@ void VG_(ii_finalise_image)( IIFinaliseImageInfo ); /* ------------------------- Linux ------------------------- */ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) struct _IICreateImageInfo { /* ------ Mandatory fields ------ */ diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h index 6ef5686ab..9625fcda5 100644 --- a/coregrind/pub_core_libcproc.h +++ b/coregrind/pub_core_libcproc.h @@ -87,6 +87,14 @@ extern void VG_(do_atfork_pre) ( ThreadId tid ); extern void VG_(do_atfork_parent) ( ThreadId tid ); extern void VG_(do_atfork_child) ( ThreadId tid ); +#if defined(VGO_freebsd) +// sysctl, modfind +//extern Int VG_(sysctl)(Int *oid, UInt oidlen, void *oldp, vki_size_t *oldlenp, void *newp, vki_size_t newlen); +extern Int VG_(sysctlbyname)(const Char *name, void *oldp, vki_size_t *oldlenp, void *newp, vki_size_t newlen); +extern Int VG_(getosreldate)(void); +extern Bool VG_(is32on64)(void); +#endif + // icache invalidation extern void VG_(invalidate_icache) ( void *ptr, SizeT nbytes ); diff --git a/coregrind/pub_core_machine.h b/coregrind/pub_core_machine.h index d6af843df..f1e770eb8 100644 --- a/coregrind/pub_core_machine.h +++ b/coregrind/pub_core_machine.h @@ -41,12 +41,12 @@ #include "pub_core_basics.h" // UnwindStartRegs // XXX: this is *really* the wrong spot for these things -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define VG_ELF_DATA2XXX ELFDATA2LSB # define VG_ELF_MACHINE EM_386 # define VG_ELF_CLASS ELFCLASS32 # undef VG_PLAT_USES_PPCTOC -#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define VG_ELF_DATA2XXX ELFDATA2LSB # define VG_ELF_MACHINE EM_X86_64 # define VG_ELF_CLASS ELFCLASS64 diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h index 5ed01d340..92431143d 100644 --- a/coregrind/pub_core_mallocfree.h +++ b/coregrind/pub_core_mallocfree.h @@ -79,6 +79,8 @@ typedef Int ArenaId; defined(VGP_ppc64le_linux) || \ defined(VGP_s390x_linux) || \ (defined(VGP_mips64_linux) && !defined(VGABI_N32)) || \ + defined(VGP_x86_freebsd) || \ + defined(VGP_amd64_freebsd) || \ defined(VGP_x86_darwin) || \ defined(VGP_amd64_darwin) || \ defined(VGP_arm64_linux) || \ diff --git a/coregrind/pub_core_sigframe.h b/coregrind/pub_core_sigframe.h index a8867ff1d..ab57b5884 100644 --- a/coregrind/pub_core_sigframe.h +++ b/coregrind/pub_core_sigframe.h @@ -60,9 +60,13 @@ void VG_(sigframe_create) ( ThreadId tid, /* Remove a signal frame from thread 'tid's stack, and restore the CPU state from it. */ +#ifdef VGO_freebsd +extern +void VG_(sigframe_destroy)( ThreadId tid ); +#else extern void VG_(sigframe_destroy)( ThreadId tid, Bool isRT ); - +#endif #if defined(VGO_solaris) extern void VG_(sigframe_return)(ThreadId tid, const vki_ucontext_t *uc); diff --git a/coregrind/pub_core_syscall.h b/coregrind/pub_core_syscall.h index b6238b6e6..d600bed34 100644 --- a/coregrind/pub_core_syscall.h +++ b/coregrind/pub_core_syscall.h @@ -75,6 +75,8 @@ extern SysRes VG_(mk_SysRes_x86_linux) ( Int val ); extern SysRes VG_(mk_SysRes_amd64_linux) ( Long val ); extern SysRes VG_(mk_SysRes_ppc32_linux) ( UInt val, UInt cr0so ); extern SysRes VG_(mk_SysRes_ppc64_linux) ( ULong val, ULong cr0so ); +extern SysRes VG_(mk_SysRes_x86_freebsd) ( UInt val, UInt val2, Bool err); +extern SysRes VG_(mk_SysRes_amd64_freebsd)( ULong val, ULong val2, Bool err ); extern SysRes VG_(mk_SysRes_arm_linux) ( Int val ); extern SysRes VG_(mk_SysRes_arm64_linux) ( Long val ); extern SysRes VG_(mk_SysRes_x86_darwin) ( UChar scclass, Bool isErr, diff --git a/coregrind/pub_core_trampoline.h b/coregrind/pub_core_trampoline.h index e29427d72..562b2d5e0 100644 --- a/coregrind/pub_core_trampoline.h +++ b/coregrind/pub_core_trampoline.h @@ -58,6 +58,14 @@ extern Addr VG_(trampoline_stuff_start); extern Addr VG_(trampoline_stuff_end); +#if defined(VGP_x86_freebsd) +extern void VG_(x86_freebsd_SUBST_FOR_sigreturn); +#endif + +#if defined(VGP_amd64_freebsd) +extern void VG_(amd64_freebsd_SUBST_FOR_sigreturn); +#endif + #if defined(VGP_x86_linux) extern Addr VG_(x86_linux_SUBST_FOR_sigreturn); extern Addr VG_(x86_linux_SUBST_FOR_rt_sigreturn); diff --git a/coregrind/vg_preloaded.c b/coregrind/vg_preloaded.c index ad033432a..c8c95fe9f 100644 --- a/coregrind/vg_preloaded.c +++ b/coregrind/vg_preloaded.c @@ -210,6 +210,8 @@ void VG_REPLACE_FUNCTION_ZU(libSystemZdZaZddylib, arc4random_addrandom)(unsigned // but don't care if it's initialized } +#elif defined(VGO_freebsd) +# warning "Do something!" #elif defined(VGO_solaris) /* Declare the errno and environ symbols weakly in case the client is not diff --git a/drd/drd_main.c b/drd/drd_main.c index 3df967ef2..fc8867687 100644 --- a/drd/drd_main.c +++ b/drd/drd_main.c @@ -740,7 +740,7 @@ void drd__atfork_child(ThreadId tid) static void DRD_(post_clo_init)(void) { -#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris) || defined(VGO_freebsd) /* fine */ #else VG_(printf)("\nWARNING: DRD has not yet been tested on this operating system.\n\n"); diff --git a/drd/tests/Makefile.am b/drd/tests/Makefile.am index fec3f466a..e27b292d2 100644 --- a/drd/tests/Makefile.am +++ b/drd/tests/Makefile.am @@ -423,8 +423,11 @@ endif if HAVE_BUILTIN_ATOMIC_CXX check_PROGRAMS += \ - annotate_smart_pointer \ - tsan_unittest + annotate_smart_pointer +endif + +if !VGCONF_OS_IS_FREEBSD +check_PROGRAMS += tsan_unittest endif # clang 3.3 will generate errors about libstdc++ headers from @@ -477,7 +480,11 @@ LDADD = -lpthread bug322621_SOURCES = bug322621.cpp concurrent_close_SOURCES = concurrent_close.cpp + +if !VGCONF_OS_IS_FREEBSD dlopen_main_LDADD = -ldl +endif + dlopen_lib_so_SOURCES = dlopen_lib.c dlopen_lib_so_CFLAGS = -fPIC dlopen_lib_so_LDFLAGS = -shared -fPIC diff --git a/drd/tests/pth_detached3.c b/drd/tests/pth_detached3.c index c02eef11a..597ccd924 100644 --- a/drd/tests/pth_detached3.c +++ b/drd/tests/pth_detached3.c @@ -5,6 +5,10 @@ #include #include +#if defined(VGO_freebsd) +#include +#endif + static void* thread_func(void* arg) { return 0; @@ -21,7 +25,11 @@ int main(int argc, char** argv) pthread_detach(thread); /* Invoke pthread_detach() with an invalid thread ID. */ +#ifdef VGO_freebsd + pthread_detach((pthread_t)12345); +#else pthread_detach(thread + 8); +#endif fprintf(stderr, "Finished.\n"); diff --git a/drd/tests/std_string.cpp b/drd/tests/std_string.cpp index 266c93fa5..63f94729a 100644 --- a/drd/tests/std_string.cpp +++ b/drd/tests/std_string.cpp @@ -8,6 +8,9 @@ #include #include #include +#if defined(__FreeBSD__) +#include +#endif #include #include diff --git a/exp-bbv/tests/x86/million.S b/exp-bbv/tests/x86/million.S index e034cc8ff..4d1975115 100644 --- a/exp-bbv/tests/x86/million.S +++ b/exp-bbv/tests/x86/million.S @@ -31,6 +31,9 @@ exit: #elif defined(VGO_solaris) pushl $0 # we return 0 int $0x91 # and exit +#elif defined(VGO_freebsd) + mov $0x1,%eax # we return 0 + int $0x80 # and exit #else # error "Unknown OS" #endif diff --git a/exp-sgcheck/tests/Makefile.am b/exp-sgcheck/tests/Makefile.am index fadf0e1df..c674b5085 100644 --- a/exp-sgcheck/tests/Makefile.am +++ b/exp-sgcheck/tests/Makefile.am @@ -53,7 +53,9 @@ if VGCONF_OS_IS_DARWIN preen_invars_LDADD = -ldl preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI) else +if !VGCONF_OS_IS_FREEBSD preen_invars_LDADD = -ldl +endif preen_invars_LDFLAGS = $(AM_FLAG_M3264_PRI) \ -Wl,-rpath,$(top_builddir)/memcheck/tests endif diff --git a/freebsd.supp b/freebsd.supp new file mode 100755 index 000000000..ae44f29be --- /dev/null +++ b/freebsd.supp @@ -0,0 +1,93 @@ +# Suppressions for FreeBSD + +##----------------------------------------------------------------------## +# Memcheck +##----------------------------------------------------------------------## + +{ + rtld-1 + Memcheck:Cond + obj:/libexec/ld-elf*.so.1 +} +{ + libc puts leak + Memcheck:Leak + fun:malloc + obj:/lib/libc.so.7 + obj:/lib/libc.so.7 + obj:/lib/libc.so.7 + fun:puts + fun:main +} +{ + DRD-1 + drd:ConflictingAccess + obj:/lib/libthr.so.3 + fun:pthread_create + fun:pthread_create + fun:main +} +{ + DRD-2 + drd:ConflictingAccess + fun:pthread_exit +} +{ + HELGRIND-PTHREAD-EXIT1 + Helgrind:Race + fun:_pthread_exit_mask + fun:pthread_exit + obj:/lib/libthr.so.3 +} +{ + HELGRIND-PTHREAD-EXIT2 + Helgrind:Race + fun:__sys_thr_exit + fun:_pthread_exit_mask + fun:pthread_exit + obj:/lib/libthr.so.3 +} +{ + HELGRIND-PTHREAD-EXIT3 + Helgrind:Race + obj:/lib/libthr.so.3 + fun:pthread_join_WRK + fun:pthread_join +} +{ + HELGRIND-PTHREAD-EXIT4 + Helgrind:Race + fun:_thr_try_gc + obj:/lib/libthr.so.3 + fun:pthread_join_WRK + fun:pthread_join +} +{ + HELGRIND-PTHREAD-EXIT5 + Helgrind:Race + fun:__sys_thr_exit + obj:/lib/libthr.so.3 + fun:_pthread_exit_mask + fun:pthread_exit + obj:/lib/libthr.so.3 +} +{ + HELGRIND-PTHREAD-BARRIER1 + Helgrind:Race + fun:pthread_barrier_init + fun:pthread_barrier_init + fun:main +} +{ + HELGRIND-PTHREAD-BARRIER2 + Helgrind:Race + fun:pthread_barrier_destroy + fun:pthread_barrier_destroy + fun:main +} +{ + HELGRIND-PTHREAD-CANCEL + Helgrind:Race + fun:pthread_cancel + fun:main +} diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c index e18671662..fe0dd3d52 100644 --- a/helgrind/hg_intercepts.c +++ b/helgrind/hg_intercepts.c @@ -241,7 +241,9 @@ static const HChar* lame_strerror ( long err ) case EDEADLK: return "EDEADLK: Resource deadlock would occur"; case EOPNOTSUPP: return "EOPNOTSUPP: Operation not supported on " "transport endpoint"; /* honest, guv */ +#if !defined(VGO_freebsd) case ETIME: return "ETIME: Timer expired"; +#endif default: return "hg_intercepts.c: lame_strerror(): " "unhandled case -- please fix me!"; } @@ -459,6 +461,12 @@ static int pthread_create_WRK(pthread_t *thread, const pthread_attr_t *attr, void *(*start) (void *), void *arg) { return pthread_create_WRK(thread, attr, start, arg); } +#elif defined(VGO_freebsd) + 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); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucreate, // pthread_create pthread_t *thread, const pthread_attr_t *attr, @@ -571,6 +579,11 @@ static int pthread_join_WRK(pthread_t thread, void** value_pointer) pthread_t thread, void** value_pointer) { return pthread_join_WRK(thread, value_pointer); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZujoin, // pthread_join + pthread_t thread, void** value_pointer) { + return pthread_join_WRK(thread, value_pointer); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZujoinZa, // pthread_join* pthread_t thread, void** value_pointer) { @@ -867,7 +880,7 @@ static int mutex_destroy_WRK(pthread_mutex_t *mutex) return ret; } -#if defined(VGO_linux) || defined(VGO_darwin) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZumutexZudestroy, // pthread_mutex_destroy pthread_mutex_t *mutex) { return mutex_destroy_WRK(mutex); @@ -919,7 +932,7 @@ static int mutex_lock_WRK(pthread_mutex_t *mutex) return ret; } -#if defined(VGO_linux) || defined(VGO_darwin) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock pthread_mutex_t *mutex) { return mutex_lock_WRK(mutex); @@ -1005,7 +1018,7 @@ static int mutex_trylock_WRK(pthread_mutex_t *mutex) return ret; } -#if defined(VGO_linux) || defined(VGO_darwin) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock pthread_mutex_t *mutex) { return mutex_trylock_WRK(mutex); @@ -1109,7 +1122,7 @@ static int mutex_unlock_WRK(pthread_mutex_t *mutex) return ret; } -#if defined(VGO_linux) || defined(VGO_darwin) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock pthread_mutex_t *mutex) { return mutex_unlock_WRK(mutex); @@ -1229,6 +1242,11 @@ static int pthread_cond_wait_WRK(pthread_cond_t* cond, pthread_cond_t* cond, pthread_mutex_t* mutex) { return pthread_cond_wait_WRK(cond, mutex); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZuwait, // pthread_cond_wait + pthread_cond_t* cond, pthread_mutex_t* mutex) { + return pthread_cond_wait_WRK(cond, mutex); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZuwaitZa, // pthread_cond_wait* pthread_cond_t* cond, pthread_mutex_t* mutex) { @@ -1329,6 +1347,12 @@ static int pthread_cond_timedwait_WRK(pthread_cond_t* cond, struct timespec* abstime) { return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait + pthread_cond_t* cond, pthread_mutex_t* mutex, + struct timespec* abstime) { + return pthread_cond_timedwait_WRK(cond, mutex, abstime, ETIMEDOUT); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZutimedwait, // pthread_cond_timedwait pthread_cond_t* cond, pthread_mutex_t* mutex, @@ -1404,6 +1428,11 @@ static int pthread_cond_signal_WRK(pthread_cond_t* cond) pthread_cond_t* cond) { return pthread_cond_signal_WRK(cond); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal + pthread_cond_t* cond) { + return pthread_cond_signal_WRK(cond); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZusignal, // pthread_cond_signal pthread_cond_t* cond) { @@ -1465,6 +1494,11 @@ static int pthread_cond_broadcast_WRK(pthread_cond_t* cond) pthread_cond_t* cond) { return pthread_cond_broadcast_WRK(cond); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast + pthread_cond_t* cond) { + return pthread_cond_broadcast_WRK(cond); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZubroadcast, // pthread_cond_broadcast pthread_cond_t* cond) { @@ -1521,6 +1555,11 @@ static int pthread_cond_init_WRK(pthread_cond_t* cond, pthread_condattr_t *cond_ pthread_cond_t* cond, pthread_condattr_t* cond_attr) { return pthread_cond_init_WRK(cond, cond_attr); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@* + pthread_cond_t* cond, pthread_condattr_t* cond_attr) { + return pthread_cond_init_WRK(cond, cond_attr); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZuinit, // pthread_cond_init pthread_cond_t* cond, pthread_condattr_t * cond_attr) { @@ -1611,6 +1650,11 @@ static int pthread_cond_destroy_WRK(pthread_cond_t* cond) pthread_cond_t* cond) { return pthread_cond_destroy_WRK(cond); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy + pthread_cond_t* cond) { + return pthread_cond_destroy_WRK(cond); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZucondZudestroy, // pthread_cond_destroy pthread_cond_t* cond) { @@ -1817,6 +1861,16 @@ static int pthread_spin_init_or_unlock_WRK(pthread_spinlock_t* lock, /* this is never actually called */ return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init + pthread_spinlock_t* lock, int pshared) { + return pthread_spin_init_or_unlock_WRK(lock, pshared); + } + PTH_FUNC(int, pthreadZuspinZuunlockZAZa, // pthread_spin_unlock@* + pthread_spinlock_t* lock) { + /* this is never actually called */ + return pthread_spin_init_or_unlock_WRK(lock, 0/*pshared*/); + } #elif defined(VGO_darwin) #elif defined(VGO_solaris) PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init @@ -1861,7 +1915,7 @@ static int pthread_spin_destroy_WRK(pthread_spinlock_t *lock) } return ret; } -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy pthread_spinlock_t *lock) { return pthread_spin_destroy_WRK(lock); @@ -1914,7 +1968,7 @@ static int pthread_spin_lock_WRK(pthread_spinlock_t *lock) } return ret; } -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock pthread_spinlock_t *lock) { return pthread_spin_lock_WRK(lock); @@ -1968,7 +2022,7 @@ static int pthread_spin_trylock_WRK(pthread_spinlock_t *lock) } return ret; } -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock pthread_spinlock_t *lock) { return pthread_spin_trylock_WRK(lock); @@ -2041,6 +2095,12 @@ static int pthread_rwlock_init_WRK(pthread_rwlock_t *rwl, pthread_rwlockattr_t* attr) { return pthread_rwlock_init_WRK(rwl, attr); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZuinit, // pthread_rwlock_init + pthread_rwlock_t *rwl, + pthread_rwlockattr_t* attr) { + return pthread_rwlock_init_WRK(rwl, attr); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZuinitZa, // pthread_rwlock_init* pthread_rwlock_t *rwl, @@ -2120,6 +2180,11 @@ static int pthread_rwlock_destroy_WRK(pthread_rwlock_t* rwl) pthread_rwlock_t *rwl) { return pthread_rwlock_destroy_WRK(rwl); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZudestroy, // pthread_rwlock_destroy + pthread_rwlock_t *rwl) { + return pthread_rwlock_destroy_WRK(rwl); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZudestroyZa, // pthread_rwlock_destroy* pthread_rwlock_t *rwl) { @@ -2174,6 +2239,11 @@ static int pthread_rwlock_wrlock_WRK(pthread_rwlock_t* rwlock) pthread_rwlock_t* rwlock) { return pthread_rwlock_wrlock_WRK(rwlock); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZuwrlock, // pthread_rwlock_wrlock + pthread_rwlock_t* rwlock) { + return pthread_rwlock_wrlock_WRK(rwlock); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZuwrlockZa, // pthread_rwlock_wrlock* pthread_rwlock_t* rwlock) { @@ -2254,6 +2324,11 @@ static int pthread_rwlock_rdlock_WRK(pthread_rwlock_t* rwlock) pthread_rwlock_t* rwlock) { return pthread_rwlock_rdlock_WRK(rwlock); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZurdlock, // pthread_rwlock_rdlock + pthread_rwlock_t* rwlock) { + return pthread_rwlock_rdlock_WRK(rwlock); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZurdlockZa, // pthread_rwlock_rdlock* pthread_rwlock_t* rwlock) { @@ -2340,6 +2415,11 @@ static int pthread_rwlock_trywrlock_WRK(pthread_rwlock_t* rwlock) pthread_rwlock_t* rwlock) { return pthread_rwlock_trywrlock_WRK(rwlock); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZutrywrlock, // pthread_rwlock_trywrlock + pthread_rwlock_t* rwlock) { + return pthread_rwlock_trywrlock_WRK(rwlock); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZutrywrlockZa, // pthread_rwlock_trywrlock* pthread_rwlock_t* rwlock) { @@ -2401,6 +2481,11 @@ static int pthread_rwlock_tryrdlock_WRK(pthread_rwlock_t* rwlock) pthread_rwlock_t* rwlock) { return pthread_rwlock_tryrdlock_WRK(rwlock); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZutryrdlock, // pthread_rwlock_tryrdlock + pthread_rwlock_t* rwlock) { + return pthread_rwlock_tryrdlock_WRK(rwlock); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZutryrdlockZa, // pthread_rwlock_tryrdlock* pthread_rwlock_t* rwlock) { @@ -2453,6 +2538,7 @@ static int pthread_rwlock_timedrdlock_WRK(pthread_rwlock_t *rwlock, } #if defined(VGO_linux) #elif defined(VGO_darwin) +#elif defined(VGO_freebsd) #elif defined(VGO_solaris) PTH_FUNC(int, pthreadZurwlockZutimedrdlock, // pthread_rwlock_timedrdlock pthread_rwlock_t *rwlock, @@ -2506,6 +2592,7 @@ static int pthread_rwlock_timedwrlock_WRK(pthread_rwlock_t *rwlock, } #if defined(VGO_linux) #elif defined(VGO_darwin) +#elif defined(VGO_freebsd) #elif defined(VGO_solaris) PTH_FUNC(int, pthreadZurwlockZutimedwrlock, // pthread_rwlock_timedwrlock pthread_rwlock_t *rwlock, @@ -2558,6 +2645,11 @@ static int pthread_rwlock_unlock_WRK(pthread_rwlock_t* rwlock) pthread_rwlock_t* rwlock) { return pthread_rwlock_unlock_WRK(rwlock); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, pthreadZurwlockZuunlock, // pthread_rwlock_unlock + pthread_rwlock_t* rwlock) { + return pthread_rwlock_unlock_WRK(rwlock); + } #elif defined(VGO_darwin) PTH_FUNC(int, pthreadZurwlockZuunlockZa, // pthread_rwlock_unlock* pthread_rwlock_t* rwlock) { @@ -2641,6 +2733,11 @@ static int sem_init_WRK(sem_t* sem, int pshared, unsigned long value) sem_t* sem, int pshared, unsigned long value) { return sem_init_WRK(sem, pshared, value); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, semZuinit, // sem_init + sem_t* sem, int pshared, unsigned long value) { + return sem_init_WRK(sem, pshared, value); + } #elif defined(VGO_darwin) PTH_FUNC(int, semZuinit, // sem_init sem_t* sem, int pshared, unsigned long value) { @@ -2723,6 +2820,11 @@ static int sem_destroy_WRK(sem_t* sem) sem_t* sem) { return sem_destroy_WRK(sem); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, semZudestroy, // sem_destroy + sem_t* sem) { + return sem_destroy_WRK(sem); + } #elif defined(VGO_darwin) PTH_FUNC(int, semZudestroy, // sem_destroy sem_t* sem) { @@ -2785,6 +2887,10 @@ static int sem_wait_WRK(sem_t* sem) PTH_FUNC(int, semZuwaitZAZa, sem_t* sem) { /* sem_wait@* */ return sem_wait_WRK(sem); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ + return sem_wait_WRK(sem); + } #elif defined(VGO_darwin) PTH_FUNC(int, semZuwait, sem_t* sem) { /* sem_wait */ return sem_wait_WRK(sem); @@ -2846,6 +2952,10 @@ static int sem_post_WRK(sem_t* sem) PTH_FUNC(int, semZupostZAZa, sem_t* sem) { /* sem_post@* */ return sem_post_WRK(sem); } +#elif defined(VGO_freebsd) + PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ + return sem_post_WRK(sem); + } #elif defined(VGO_darwin) PTH_FUNC(int, semZupost, sem_t* sem) { /* sem_post */ return sem_post_WRK(sem); diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am index ad1af191a..1ed8bf817 100644 --- a/helgrind/tests/Makefile.am +++ b/helgrind/tests/Makefile.am @@ -10,7 +10,7 @@ EXTRA_DIST = \ annotate_hbefore.vgtest annotate_hbefore.stdout.exp \ annotate_hbefore.stderr.exp \ annotate_rwlock.vgtest annotate_rwlock.stdout.exp \ - annotate_rwlock.stderr.exp \ + annotate_rwlock.stderr.exp annotate_rwlock.stderr.exp-freebsd \ annotate_smart_pointer.vgtest annotate_smart_pointer.stdout.exp \ annotate_smart_pointer.stderr.exp \ bug322621.vgtest bug322621.stderr.exp \ @@ -23,7 +23,7 @@ EXTRA_DIST = \ bar_bad.stderr.exp-destroy-hang \ bar_trivial.vgtest bar_trivial.stdout.exp bar_trivial.stderr.exp \ free_is_write.vgtest free_is_write.stdout.exp \ - free_is_write.stderr.exp \ + free_is_write.stderr.exp free_is_write.stderr.exp-freebsd \ hg01_all_ok.vgtest hg01_all_ok.stdout.exp hg01_all_ok.stderr.exp \ hg02_deadlock.vgtest hg02_deadlock.stdout.exp hg02_deadlock.stderr.exp \ hg03_inherit.vgtest hg03_inherit.stdout.exp hg03_inherit.stderr.exp \ diff --git a/helgrind/tests/annotate_rwlock.stderr.exp-freebsd b/helgrind/tests/annotate_rwlock.stderr.exp-freebsd new file mode 100755 index 000000000..aadff63fc --- /dev/null +++ b/helgrind/tests/annotate_rwlock.stderr.exp-freebsd @@ -0,0 +1,117 @@ +---Thread-Announcement------------------------------------------ + +Thread #x was created + ... + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + by 0x........: pthread_create (hg_intercepts.c:...) + by 0x........: main (annotate_rwlock.c:164) + +---Thread-Announcement------------------------------------------ + +Thread #x was created + ... + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + by 0x........: pthread_create (hg_intercepts.c:...) + by 0x........: main (annotate_rwlock.c:164) + +---------------------------------------------------------------- + +Possible data race during read of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: rwlock_rdlock (annotate_rwlock.c:71) + by 0x........: thread_func (annotate_rwlock.c:144) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: none + at 0x........: rwlock_wrlock (annotate_rwlock.c:106) + by 0x........: thread_func (annotate_rwlock.c:147) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +---------------------------------------------------------------- + +Possible data race during read of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: rwlock_rdlock (annotate_rwlock.c:81) + by 0x........: thread_func (annotate_rwlock.c:144) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous write of size 4 by thread #x +Locks held: none + at 0x........: rwlock_rdlock (annotate_rwlock.c:81) + by 0x........: thread_func (annotate_rwlock.c:144) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +---------------------------------------------------------------- + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: rwlock_rdlock (annotate_rwlock.c:81) + by 0x........: thread_func (annotate_rwlock.c:144) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous read of size 4 by thread #x +Locks held: none + at 0x........: rwlock_unlock (annotate_rwlock.c:131) + by 0x........: thread_func (annotate_rwlock.c:149) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +---------------------------------------------------------------- + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: rwlock_unlock (annotate_rwlock.c:121) + by 0x........: thread_func (annotate_rwlock.c:146) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous read of size 4 by thread #x +Locks held: none + at 0x........: rwlock_unlock (annotate_rwlock.c:131) + by 0x........: thread_func (annotate_rwlock.c:149) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +---------------------------------------------------------------- + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: none + at 0x........: rwlock_wrlock (annotate_rwlock.c:106) + by 0x........: thread_func (annotate_rwlock.c:147) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous read of size 4 by thread #x +Locks held: none + at 0x........: rwlock_unlock (annotate_rwlock.c:132) + by 0x........: thread_func (annotate_rwlock.c:149) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +---------------------------------------------------------------- + +Lock at 0x........ was first observed + at 0x........: rwlock_init (annotate_rwlock.c:54) + by 0x........: main (annotate_rwlock.c:161) + +Possible data race during write of size 4 at 0x........ by thread #x +Locks held: 1, at address 0x........ + at 0x........: rwlock_unlock (annotate_rwlock.c:127) + by 0x........: thread_func (annotate_rwlock.c:149) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous read of size 4 by thread #x +Locks held: none + at 0x........: rwlock_unlock (annotate_rwlock.c:132) + by 0x........: thread_func (annotate_rwlock.c:149) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +Finished. diff --git a/helgrind/tests/free_is_write.stderr.exp-freebsd b/helgrind/tests/free_is_write.stderr.exp-freebsd new file mode 100755 index 000000000..a21ee7d88 --- /dev/null +++ b/helgrind/tests/free_is_write.stderr.exp-freebsd @@ -0,0 +1,30 @@ + +Start. +---Thread-Announcement------------------------------------------ + +Thread #x was created + ... + by 0x........: pthread_create_WRK (hg_intercepts.c:...) + by 0x........: pthread_create (hg_intercepts.c:...) + by 0x........: main (free_is_write.c:32) + +---Thread-Announcement------------------------------------------ + +Thread #x is the program's root thread + +---------------------------------------------------------------- + +Possible data race during write of size 1 at 0x........ by thread #x +Locks held: none + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: thread_func (free_is_write.c:15) + by 0x........: mythread_wrapper (hg_intercepts.c:...) + ... + +This conflicts with a previous read of size 1 by thread #x +Locks held: none + at 0x........: main (free_is_write.c:36) + +Done. + +ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0) diff --git a/helgrind/tests/stackteardown.c b/helgrind/tests/stackteardown.c index 47e300a75..be4cbb753 100644 --- a/helgrind/tests/stackteardown.c +++ b/helgrind/tests/stackteardown.c @@ -93,7 +93,7 @@ int main ( void ) pthread_t child; r = pthread_attr_init(&attr); assert(!r); -# if !defined(VGO_darwin) +# if !defined(VGO_darwin) && !defined(VGO_freebsd) stack = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); # else diff --git a/helgrind/tests/tc07_hbl1.c b/helgrind/tests/tc07_hbl1.c index 1744dc130..2a67903a3 100644 --- a/helgrind/tests/tc07_hbl1.c +++ b/helgrind/tests/tc07_hbl1.c @@ -8,6 +8,8 @@ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux @@ -23,6 +25,10 @@ # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) @@ -47,7 +53,8 @@ #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \ || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \ - || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) + || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) \ + || defined(PLAT_amd64_freebsd) || defined(PLAT_x86_freebsd) # define INC(_lval,_lqual) \ __asm__ __volatile__ ( \ "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" ) diff --git a/helgrind/tests/tc08_hbl2.c b/helgrind/tests/tc08_hbl2.c index f660d82dd..d81345182 100644 --- a/helgrind/tests/tc08_hbl2.c +++ b/helgrind/tests/tc08_hbl2.c @@ -24,6 +24,8 @@ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux @@ -40,6 +42,10 @@ # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) @@ -69,7 +75,8 @@ #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \ || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \ - || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) + || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) \ + || defined(PLAT_amd64_freebsd) || defined(PLAT_x86_freebsd) # define INC(_lval,_lqual) \ __asm__ __volatile__ ( \ "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" ) diff --git a/helgrind/tests/tc11_XCHG.c b/helgrind/tests/tc11_XCHG.c index 48fc1b1a9..b03575613 100644 --- a/helgrind/tests/tc11_XCHG.c +++ b/helgrind/tests/tc11_XCHG.c @@ -11,6 +11,8 @@ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd #undef PLAT_x86_linux #undef PLAT_amd64_linux #undef PLAT_ppc32_linux @@ -25,6 +27,10 @@ # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 #elif defined(__linux__) && defined(__i386__) # define PLAT_x86_linux 1 #elif defined(__linux__) && defined(__x86_64__) @@ -50,7 +56,8 @@ #if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \ || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \ - || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) + || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris) \ + || defined(PLAT_amd64_freebsd) || defined(PLAT_x86_freebsd) # define XCHG_M_R(_addr,_lval) \ __asm__ __volatile__( \ "xchgl %0, %1" \ diff --git a/helgrind/tests/tc17_sembar.c b/helgrind/tests/tc17_sembar.c index 88a1fe5bb..3d05588ae 100644 --- a/helgrind/tests/tc17_sembar.c +++ b/helgrind/tests/tc17_sembar.c @@ -4,6 +4,9 @@ #include #include #include +#if defined(VGO_freebsd) +# include +#endif /* This is really a test of semaphore handling (sem_{init,destroy,post,wait}). Using semaphores a barrier function is created. Helgrind-3.3 (p.k.a Thrcheck) does understand @@ -231,7 +234,7 @@ static sem_t* my_sem_init (char* identity, int pshared, unsigned count) s = NULL; } } -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) char name[100]; sprintf(name, "anonsem_%s_pid%d", identity, (int)getpid()); name[ sizeof(name)-1 ] = 0; diff --git a/helgrind/tests/tc20_verifywrap.c b/helgrind/tests/tc20_verifywrap.c index c11000079..ae97bde8d 100644 --- a/helgrind/tests/tc20_verifywrap.c +++ b/helgrind/tests/tc20_verifywrap.c @@ -18,7 +18,7 @@ #include "safe-pthread.h" #include "safe-semaphore.h" -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) #if defined(__sun__) /* Fake __GLIBC_PREREQ on Solaris. Pretend glibc >= 2.4. */ diff --git a/helgrind/tests/tc23_bogus_condwait.c b/helgrind/tests/tc23_bogus_condwait.c index 6ea5ad90b..c2c8187fd 100644 --- a/helgrind/tests/tc23_bogus_condwait.c +++ b/helgrind/tests/tc23_bogus_condwait.c @@ -7,6 +7,9 @@ #include #include #include +#if defined(VGO_freebsd) +#include +#endif pthread_mutex_t mx[4]; pthread_cond_t cv; pthread_rwlock_t rwl; sem_t* quit_now; @@ -107,7 +110,7 @@ static sem_t* my_sem_init (char* identity, int pshared, unsigned count) s = NULL; } } -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) char name[100]; sprintf(name, "anonsem_%s_pid%d", identity, (int)getpid()); name[ sizeof(name)-1 ] = 0; diff --git a/helgrind/tests/tc24_nonzero_sem.c b/helgrind/tests/tc24_nonzero_sem.c index bcd467ccb..448d5c082 100644 --- a/helgrind/tests/tc24_nonzero_sem.c +++ b/helgrind/tests/tc24_nonzero_sem.c @@ -9,6 +9,9 @@ #include #include #include +#if defined(VGO_freebsd) +# include +#endif #define N_THREADS 3 @@ -59,7 +62,7 @@ static sem_t* my_sem_init (char* identity, int pshared, unsigned count) s = NULL; } } -#elif defined(VGO_darwin) +#elif defined(VGO_darwin) || defined(VGO_freebsd) char name[100]; sprintf(name, "anonsem_%s_pid%d", identity, (int)getpid()); name[ sizeof(name)-1 ] = 0; diff --git a/include/Makefile.am b/include/Makefile.am index 11c7ca86d..026ab120d 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -47,9 +47,12 @@ nobase_pkginclude_HEADERS = \ pub_tool_xtmemory.h \ valgrind.h \ vki/vki-linux.h \ + vki/vki-freebsd.h \ vki/vki-darwin.h \ vki/vki-solaris.h \ vki/vki-solaris-repcache.h \ + vki/vki-machine-types-amd64-freebsd.h \ + vki/vki-machine-types-x86-freebsd.h \ vki/vki-posixtypes-amd64-linux.h \ vki/vki-posixtypes-arm64-linux.h \ vki/vki-posixtypes-ppc32-linux.h \ @@ -64,6 +67,8 @@ nobase_pkginclude_HEADERS = \ vki/vki-ppc32-linux.h \ vki/vki-ppc64-linux.h \ vki/vki-x86-linux.h \ + vki/vki-amd64-freebsd.h \ + vki/vki-x86-freebsd.h \ vki/vki-arm-linux.h \ vki/vki-s390x-linux.h \ vki/vki-mips32-linux.h \ @@ -73,6 +78,7 @@ nobase_pkginclude_HEADERS = \ vki/vki-scnums-ppc32-linux.h \ vki/vki-scnums-ppc64-linux.h \ vki/vki-scnums-x86-linux.h \ + vki/vki-scnums-freebsd.h \ vki/vki-scnums-arm-linux.h \ vki/vki-scnums-s390x-linux.h \ vki/vki-scnums-mips32-linux.h \ diff --git a/include/pub_tool_basics.h b/include/pub_tool_basics.h index 9ad0f70d7..2e2bfa784 100644 --- a/include/pub_tool_basics.h +++ b/include/pub_tool_basics.h @@ -104,6 +104,8 @@ typedef Word PtrdiffT; // 32 64 // always a signed 64-bit int. So we defined our own Off64T as well. #if defined(VGO_linux) || defined(VGO_solaris) typedef Word OffT; // 32 64 +#elif defined(VGO_freebsd) +typedef Long OffT; // 64 64 #elif defined(VGO_darwin) typedef Long OffT; // 64 64 #else @@ -227,6 +229,14 @@ typedef SysResMode _mode; } SysRes; +#elif defined(VGO_freebsd) +typedef + struct { + UWord _val; + UWord _val2; + Bool _isError; + } + SysRes; #elif defined(VGO_solaris) typedef @@ -304,6 +314,27 @@ static inline Bool sr_EQ ( UInt sysno, SysRes sr1, SysRes sr2 ) { && sr1._isError == sr2._isError; } +#elif defined(VGO_freebsd) + +static inline Bool sr_isError ( SysRes sr ) { + return sr._isError; +} +static inline UWord sr_Res ( SysRes sr ) { + return sr._isError ? 0 : sr._val; +} +static inline UWord sr_ResHI ( SysRes sr ) { + return sr._isError ? 0 : sr._val2; +} +static inline UWord sr_Err ( SysRes sr ) { + return sr._isError ? sr._val : 0; +} +static inline Bool sr_EQ ( UInt sysno, SysRes sr1, SysRes sr2 ) { + return sr_Res(sr1) == sr_Res(sr2) + && sr_ResHI(sr1) == sr_ResHI(sr2) + && ((sr_isError(sr1) && sr_isError(sr2)) + || (!sr_isError(sr1) && !sr_isError(sr2))); +} + #elif defined(VGO_darwin) static inline Bool sr_isError ( SysRes sr ) { diff --git a/include/pub_tool_basics_asm.h b/include/pub_tool_basics_asm.h index a2f105641..64f3dbce6 100644 --- a/include/pub_tool_basics_asm.h +++ b/include/pub_tool_basics_asm.h @@ -48,7 +48,7 @@ #define VGAPPEND(str1,str2) str1##str2 -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # define VG_(str) VGAPPEND( vgPlain_, str) # define ML_(str) VGAPPEND( vgModuleLocal_, str) #elif defined(VGO_darwin) diff --git a/include/pub_tool_libcsetjmp.h b/include/pub_tool_libcsetjmp.h index ca96f54b5..6952f76fb 100644 --- a/include/pub_tool_libcsetjmp.h +++ b/include/pub_tool_libcsetjmp.h @@ -92,7 +92,7 @@ void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env)); #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) || \ - defined(VGP_amd64_solaris) + defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) #define VG_MINIMAL_JMP_BUF(_name) ULong _name [16+1] __attribute__((returns_twice)) @@ -102,7 +102,7 @@ void VG_MINIMAL_LONGJMP(VG_MINIMAL_JMP_BUF(_env)); #elif defined(VGP_x86_linux) || defined(VGP_x86_darwin) || \ - defined(VGP_x86_solaris) + defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) #define VG_MINIMAL_JMP_BUF(_name) UInt _name [8+1] __attribute__((returns_twice)) diff --git a/include/pub_tool_machine.h b/include/pub_tool_machine.h index fab8ee4fd..c6f60548f 100644 --- a/include/pub_tool_machine.h +++ b/include/pub_tool_machine.h @@ -34,14 +34,14 @@ #include "pub_tool_basics.h" // ThreadID #include "libvex.h" // VexArchInfo -#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) +#if defined(VGP_x86_linux) || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) # define VG_MIN_INSTR_SZB 1 // min length of native instruction # define VG_MAX_INSTR_SZB 16 // max length of native instruction # define VG_CLREQ_SZB 14 // length of a client request, may // be larger than VG_MAX_INSTR_SZB # define VG_STACK_REDZONE_SZB 0 // number of addressable bytes below %RSP -#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) +#elif defined(VGP_amd64_linux) || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) # define VG_MIN_INSTR_SZB 1 # define VG_MAX_INSTR_SZB 16 # define VG_CLREQ_SZB 19 diff --git a/include/pub_tool_redir.h b/include/pub_tool_redir.h index c97941ff4..4b4ffca6c 100644 --- a/include/pub_tool_redir.h +++ b/include/pub_tool_redir.h @@ -243,7 +243,7 @@ /* --- Soname of the standard C library. --- */ -#if defined(VGO_linux) || defined(VGO_solaris) +#if defined(VGO_linux) || defined(VGO_solaris) || defined(VGO_freebsd) # if defined(MUSL_LIBC) # define VG_Z_LIBC_SONAME libcZdZa // libc.* #else @@ -271,10 +271,11 @@ #endif -/* --- Soname of the GNU C++ library. --- */ +/* --- Sonames of the GNU C++ library. --- */ // Valid on all platforms(?) #define VG_Z_LIBSTDCXX_SONAME libstdcZpZpZa // libstdc++* +#define VG_Z_LIBSUPCXX_SONAME libsupcZpZpZa // libsupc++* /* --- Soname of the pthreads library. --- */ @@ -284,6 +285,8 @@ #else # define VG_Z_LIBPTHREAD_SONAME libpthreadZdsoZd0 // libpthread.so.0 #endif +#elif defined(VGO_freebsd) +# define VG_Z_LIBPTHREAD_SONAME libthrZdsoZa // libthr.so* #elif defined(VGO_darwin) # define VG_Z_LIBPTHREAD_SONAME libSystemZdZaZddylib // libSystem.*.dylib #elif defined(VGO_solaris) @@ -318,6 +321,18 @@ #endif +/* --- Sonames for FreeBSD ELF linkers, plus unencoded versions. --- */ + +#if defined(VGO_freebsd) + +#define VG_Z_LD_ELF_SO_1 ldZhelfZdsoZd1 // ld-elf.so.1 +#define VG_U_LD_ELF_SO_1 "ld-elf.so.1" + +#define VG_Z_LD_ELF32_SO_1 ldZhelf32ZdsoZd1 // ld-elf32.so.1 +#define VG_U_LD_ELF32_SO_1 "ld-elf32.so.1" + +#endif + /* --- Executable name for Darwin Mach-O linker. --- */ #if defined(VGO_darwin) diff --git a/include/pub_tool_vki.h b/include/pub_tool_vki.h index 9c1615e4b..49cf9446b 100644 --- a/include/pub_tool_vki.h +++ b/include/pub_tool_vki.h @@ -52,6 +52,8 @@ # include "vki/vki-darwin.h" #elif defined(VGO_solaris) # include "vki/vki-solaris.h" +#elif defined(VGO_freebsd) +# include "vki/vki-freebsd.h" #else # error Unknown Plat/OS #endif diff --git a/include/pub_tool_vkiscnums.h b/include/pub_tool_vkiscnums.h index 721948b20..5f7f3a51f 100644 --- a/include/pub_tool_vkiscnums.h +++ b/include/pub_tool_vkiscnums.h @@ -47,6 +47,12 @@ extern const HChar *VG_(sysnum_string) (Word sysnum); #define VG_SYSNUM_STRING(sysnum) VG_(sysnum_string)(sysnum) +#if defined(VGO_freebsd) + // See the FreeBSD-specific case in pub_tool_vkiscnums_asm.h for an + // explanation of why we include this here rather than there. +# include "vki/vki-scnums-freebsd.h" +#endif + #endif // __PUB_TOOL_VKISCNUMS_H /*--------------------------------------------------------------------*/ diff --git a/include/pub_tool_vkiscnums_asm.h b/include/pub_tool_vkiscnums_asm.h index 218175752..99f6354d8 100644 --- a/include/pub_tool_vkiscnums_asm.h +++ b/include/pub_tool_vkiscnums_asm.h @@ -60,6 +60,9 @@ #elif defined(VGP_mips64_linux) # include "vki/vki-scnums-mips64-linux.h" +#elif defined(VGP_x86_freebsd) || defined(VGP_amd64_freebsd) +# include "vki/vki-scnums-freebsd.h" + #elif defined(VGP_x86_darwin) || defined(VGP_amd64_darwin) # include "vki/vki-scnums-darwin.h" diff --git a/include/valgrind.h b/include/valgrind.h index 577c8f05e..26d988712 100644 --- a/include/valgrind.h +++ b/include/valgrind.h @@ -110,6 +110,8 @@ */ #undef PLAT_x86_darwin #undef PLAT_amd64_darwin +#undef PLAT_x86_freebsd +#undef PLAT_amd64_freebsd #undef PLAT_x86_win32 #undef PLAT_amd64_win64 #undef PLAT_x86_linux @@ -130,6 +132,10 @@ # define PLAT_x86_darwin 1 #elif defined(__APPLE__) && defined(__x86_64__) # define PLAT_amd64_darwin 1 +#elif defined(__FreeBSD__) && defined(__i386__) +# define PLAT_x86_freebsd 1 +#elif defined(__FreeBSD__) && defined(__amd64__) +# define PLAT_amd64_freebsd 1 #elif (defined(__MINGW32__) && !defined(__MINGW64__)) \ || defined(__CYGWIN32__) \ || (defined(_WIN32) && defined(_M_IX86)) @@ -254,7 +260,7 @@ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ || (defined(PLAT_x86_win32) && defined(__GNUC__)) \ - || defined(PLAT_x86_solaris) + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) typedef struct { @@ -394,6 +400,7 @@ valgrind_do_client_request_expr(uintptr_t _zzq_default, uintptr_t _zzq_request, #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ || defined(PLAT_amd64_solaris) \ + || defined(PLAT_amd64_freebsd) \ || (defined(PLAT_amd64_win64) && defined(__GNUC__)) typedef @@ -1145,7 +1152,7 @@ typedef /* ----------------- x86-{linux,darwin,solaris} ---------------- */ #if defined(PLAT_x86_linux) || defined(PLAT_x86_darwin) \ - || defined(PLAT_x86_solaris) + || defined(PLAT_x86_solaris) || defined(PLAT_x86_freebsd) /* These regs are trashed by the hidden call. No need to mention eax as gcc can already see that, plus causes gcc to bomb. */ @@ -1577,7 +1584,7 @@ typedef /* ---------------- amd64-{linux,darwin,solaris} --------------- */ #if defined(PLAT_amd64_linux) || defined(PLAT_amd64_darwin) \ - || defined(PLAT_amd64_solaris) + || defined(PLAT_amd64_solaris) || defined(PLAT_amd64_freebsd) /* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */ diff --git a/include/vki/vki-amd64-freebsd.h b/include/vki/vki-amd64-freebsd.h new file mode 100755 index 000000000..e5ea2c282 --- /dev/null +++ b/include/vki/vki-amd64-freebsd.h @@ -0,0 +1,224 @@ +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __VKI_AMD64_FREEBSD_H +#define __VKI_AMD64_FREEBSD_H + +/* PAGE_SHIFT determines the page size. */ +#define VKI_PAGE_SHIFT 12 +#define VKI_PAGE_SIZE (1UL << VKI_PAGE_SHIFT) +#define VKI_MAX_PAGE_SHIFT VKI_PAGE_SHIFT +#define VKI_MAX_PAGE_SIZE VKI_PAGE_SIZE + +#define VKI_MINSIGSTKSZ 2048 + +//---------------------------------------------------------------------- +// sys/_sigset.h +//---------------------------------------------------------------------- +#define _VKI_NSIG 128 +#define _VKI_NSIG_WORDS 4 +#define _VKI_NSIG_BPW ((_VKI_NSIG) / (_VKI_NSIG_WORDS)) + +typedef struct { + vki_uint32_t sig[_VKI_NSIG_WORDS]; +} vki_sigset_t; + +struct _vki_fpstate { + unsigned short cwd; + unsigned short swd; + unsigned short twd; + unsigned short fop; + unsigned long rip; + unsigned long rdp; + unsigned int mxcsr; + unsigned int mxcsr_mask; + unsigned int st_space[32]; /* 8*16 bytes for each FP-reg */ + unsigned int xmm_space[64]; /* 16*16 bytes for each XMM-reg */ + unsigned int reserved2[24]; +}; + +struct vki_sigcontext { + vki_sigset_t mask; + long onstack; + long rdi; + long rsi; + long rdx; + long rcx; + long r8; + long r9; + long rax; + long rbx; + long rbp; + long r10; + long r11; + long r12; + long r13; + long r14; + long r15; + long trapno; + long addr; + long flags; + long err; + long rip; + long cs; + long rflags; + long rsp; + long ss; + long len; /* sizeof(mcontext_t) */ + long fpformat; + long ownedfp; + struct _vki_fpstate fpstate; + long spare2[8]; +}; + +/* + * Retrieved from src/sys/amd64/include/reg.h + * Note that on 8.x trapno and err are no-more meaningful, but we + * don't set them anyway. + */ +struct vki_user_regs_struct { + vki_register_t r15; + vki_register_t r14; + vki_register_t r13; + vki_register_t r12; + vki_register_t r11; + vki_register_t r10; + vki_register_t r9; + vki_register_t r8; + vki_register_t rdi; + vki_register_t rsi; + vki_register_t rbp; + vki_register_t rbx; + vki_register_t rdx; + vki_register_t rcx; + vki_register_t rax; + vki_register_t trapno; + vki_register_t err; + vki_register_t rip; + vki_register_t cs; + vki_register_t rflags; + vki_register_t rsp; + vki_register_t ss; +}; + +struct vki_reg_struct { + vki_register_t r_r15; + vki_register_t r_r14; + vki_register_t r_r13; + vki_register_t r_r12; + vki_register_t r_r11; + vki_register_t r_r10; + vki_register_t r_r9; + vki_register_t r_r8; + vki_register_t r_rdi; + vki_register_t r_rsi; + vki_register_t r_rbp; + vki_register_t r_rbx; + vki_register_t r_rdx; + vki_register_t r_rcx; + vki_register_t r_rax; + vki_uint32_t r_trapno; + vki_uint16_t r_fs; + vki_uint16_t r_gs; + vki_uint32_t r_err; + vki_uint16_t r_es; + vki_uint16_t r_ds; + vki_register_t r_rip; + vki_register_t r_cs; + vki_register_t r_rflags; + vki_register_t r_rsp; + vki_register_t r_ss; +}; + +struct vki_fpreg { + unsigned long fpr_env[4]; + unsigned char fpr_acc[8][16]; + unsigned char fpr_xacc[16][16]; + unsigned long fpr_spare[12]; +}; + +struct vki_dbreg { + unsigned long dr[16]; +}; + +typedef vki_register_t vki_elf_greg_t; +typedef struct _vki_fpstate vki_elf_fpregset_t; + +#define VKI_AT_SYSINFO 32 +#define VKI_ELF_NGREG \ + (sizeof (struct vki_user_regs_struct) / sizeof(vki_elf_greg_t)) + +typedef vki_elf_greg_t vki_elf_gregset_t[VKI_ELF_NGREG]; + +struct vki_mcontext { + vki_register_t onstack; /* XXX - sigcontext compat. */ + vki_register_t rdi; /* machine state (struct trapframe) */ + vki_register_t rsi; + vki_register_t rdx; + vki_register_t rcx; + vki_register_t r8; + vki_register_t r9; + vki_register_t rax; + vki_register_t rbx; + vki_register_t rbp; + vki_register_t r10; + vki_register_t r11; + vki_register_t r12; + vki_register_t r13; + vki_register_t r14; + vki_register_t r15; + vki_register_t trapno; + vki_register_t addr; + vki_register_t flags; + vki_register_t err; + vki_register_t rip; + vki_register_t cs; + vki_register_t rflags; + vki_register_t rsp; + vki_register_t ss; + + long len; + long fpformat; + long ownedfp; + struct _vki_fpstate fpstate; + long spare2[8]; +}; + +#define VKI_FPFMT_NODEV 0x10000 +#define VKI_FPFMT_XMM 0x10002 + +#define VKI_FPOWNED_NONE 0x20000 +#define VKI_FPOWNED_FPU 0x20001 +#define VKI_FPOWNED_PCB 0x20002 + +struct vki_sigaction_base { + void (*ksa_handler)(int); + int sa_flags; + vki_sigset_t sa_mask; /* mask last for extensibility */ +}; +typedef struct vki_sigaction_base vki_sigaction_toK_t; +typedef struct vki_sigaction_base vki_sigaction_fromK_t; + +#endif /* __VKI_AMD64_FREEBSD_H */ diff --git a/include/vki/vki-freebsd.h b/include/vki/vki-freebsd.h new file mode 100755 index 000000000..32b4a749f --- /dev/null +++ b/include/vki/vki-freebsd.h @@ -0,0 +1,2160 @@ + +/*--------------------------------------------------------------------*/ +/*--- FreeBSD-specific kernel interface. vki-freebsd.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +/* This file defines types and constants for the kernel interface, and to + make that clear everything is prefixed VKI_/vki_. + + All code is copied verbatim from kernel source files, except that: + - VKI_/vki_ prefixes are added + - some extra explanatory comments are included; they are all within + "[[ ]]" + - for some types, we only care about the size; for a few of them (big + ones that are painful to fully drag in here), a VKI_SIZEOF_* constant + is used. + + The files the code is taken from is indicated. + + Note especially that the types are not the glibc versions, many of which + are different to those in here. + + Also note that this file contains all the generic header info, ie. that + from linux/include/linux/ *.h. The arch-specific header info, eg. that + from linux/include/asm-i386/ *.h, is in vki-$PLATFORM.h and + vki_posixtypes-$PLATFORM.h. (Two files are required to avoid + circular dependencies between the generic VKI header and the + arch-specific VKI header. It's possible in the future, as more stuff + gets pulled in, that we might have to split files up some more to avoid + further circular dependencies.) + + Finally, note that it is assumed that __KERNEL__ is set for all these + definitions, which affects some of them. +*/ + +#ifndef __VKI_FREEBSD_H +#define __VKI_FREEBSD_H + +//---------------------------------------------------------------------- +// Arch-specific POSIX types +//---------------------------------------------------------------------- + +#if defined(VGA_x86) +# include "vki-machine-types-x86-freebsd.h" +#elif defined(VGA_amd64) +# include "vki-machine-types-amd64-freebsd.h" +#else +# error Unknown platform +#endif + +#include +#include + + +//---------------------------------------------------------------------- +// From sys/select.h +//---------------------------------------------------------------------- + +typedef unsigned long __vki_fd_mask; + +#undef __VKI_NFDBITS +#define __VKI_NFDBITS (8 * sizeof(__vki_fd_mask)) + +#undef __VKI_FD_SETSIZE +#define __VKI_FD_SETSIZE 1024U + +#undef __VKI_FDSET_LONGS +#define __VKI_FDSET_LONGS (__VKI_FD_SETSIZE/__VKI_NFDBITS) + +#undef __VKI_FDELT +#define __VKI_FDELT(d) ((d) / __VKI_NFDBITS) + +#undef __VKI_FDMASK +#define __VKI_FDMASK(d) (1UL << ((d) % __VKI_NFDBITS)) + +typedef struct { + unsigned long fds_bits [__VKI_FDSET_LONGS]; +} __vki_fd_set; + +//---------------------------------------------------------------------- +// sys/_types.h +//---------------------------------------------------------------------- +/* MD QQQ 32 on 64 */ +typedef long __vki_key_t; +typedef long __vki_suseconds_t; +typedef struct __timer *__vki_timer_t; +typedef struct __mq *__vki_mqd_t; + +/* MI */ +typedef vki_uint32_t __vki_blksize_t; +typedef vki_int64_t __vki_blkcnt_t; +typedef vki_int32_t __vki_clockid_t; +typedef vki_int32_t __vki_ct_rune_t; +typedef vki_uint32_t __vki_fflags_t; +typedef vki_uint64_t __vki_fsblkcnt_t; +typedef vki_uint64_t __vki_fsfilcnt_t; +typedef vki_uint32_t __vki_gid_t; +typedef vki_int64_t __vki_id_t; +typedef vki_uint32_t __vki_ino_t; +typedef vki_int32_t __vki_lwpid_t; +typedef vki_uint16_t __vki_mode_t; +typedef vki_uint16_t __vki_nlink_t; +typedef vki_int64_t __vki_off_t; +typedef vki_int32_t __vki_pid_t; +typedef vki_int64_t __vki_rlim_t; +typedef vki_uint8_t __vki_sa_family_t; +typedef vki_uint32_t __vki_socklen_t; +typedef vki_uint32_t __vki_uid_t; +typedef vki_int32_t __vki_useconds_t; +typedef __vki_ct_rune_t __vki_rune_t; +typedef __vki_ct_rune_t __vki_wchar_t; +typedef __vki_ct_rune_t __vki_wint_t; +typedef vki_uint32_t __vki_dev_t; +typedef vki_uint32_t __vki_fixpt_t; + + +//---------------------------------------------------------------------- +// sys/types.h +//---------------------------------------------------------------------- + +typedef vki_uint8_t vki_u_int8_t; +typedef vki_uint16_t vki_u_int16_t; +typedef vki_uint32_t vki_u_int32_t; +typedef vki_uint64_t vki_u_int64_t; + +typedef vki_uint64_t vki_u_quad_t; +typedef vki_int64_t vki_quad_t; +typedef __vki_caddr_t vki_caddr_t; +typedef __const __vki_caddr_t vki_c_caddr_t; +typedef __volatile __vki_caddr_t vki_v_caddr_t; + +typedef __vki_blksize_t vki_blksize_t; +typedef __vki_blkcnt_t vki_blkcnt_t; +typedef __vki_clock_t vki_clock_t; +typedef __vki_clockid_t vki_clockid_t; +typedef __vki_dev_t vki_dev_t; +typedef __vki_fflags_t vki_fflags_t; +typedef __vki_fixpt_t vki_fixpt_t; +typedef __vki_fsblkcnt_t vki_fsblkcnt_t; +typedef __vki_fsfilcnt_t vki_fsfilcnt_t; +typedef __vki_gid_t vki_gid_t; +typedef vki_uint32_t vki_in_addr_t; +typedef vki_uint16_t vki_in_port_t; +typedef __vki_id_t vki_id_t; +typedef __vki_ino_t vki_ino_t; +typedef __vki_key_t vki_key_t; +typedef __vki_lwpid_t vki_lwpid_t; +typedef __vki_mode_t vki_mode_t; +typedef __vki_nlink_t vki_nlink_t; +typedef __vki_off_t vki_off_t; +typedef __vki_pid_t vki_pid_t; +typedef __vki_register_t vki_register_t; +typedef __vki_rlim_t vki_rlim_t; +typedef __vki_segsz_t vki_segsz_t; +typedef __vki_size_t vki_size_t; +typedef __vki_ssize_t vki_ssize_t; +typedef __vki_suseconds_t vki_suseconds_t; +typedef __vki_time_t vki_time_t; +typedef __vki_timer_t vki_timer_t; +typedef __vki_mqd_t vki_mqd_t; +typedef __vki_u_register_t vki_u_register_t; +typedef __vki_uid_t vki_uid_t; +typedef __vki_useconds_t vki_useconds_t; + +typedef __vki_vm_offset_t vki_vm_offset_t; +typedef __vki_vm_ooffset_t vki_vm_ooffset_t; +typedef __vki_vm_paddr_t vki_vm_paddr_t; +typedef __vki_vm_pindex_t vki_vm_pindex_t; +typedef __vki_vm_size_t vki_vm_size_t; + +//---------------------------------------------------------------------- +// sys/select.h +//---------------------------------------------------------------------- + +typedef __vki_fd_set vki_fd_set; + +//---------------------------------------------------------------------- +// Now the rest of the arch-specific stuff +//---------------------------------------------------------------------- + +#if defined(VGA_x86) +# include "vki-x86-freebsd.h" +#elif defined(VGA_amd64) +# include "vki-amd64-freebsd.h" +#elif defined(VGA_ppc32) +# include "vki-ppc32-freebsd.h" +#elif defined(VGA_ppc64) +# include "vki-ppc64-freebsd.h" +#else +# error Unknown platform +#endif + +//---------------------------------------------------------------------- +// linux and freebsd version hacks +//---------------------------------------------------------------------- +#ifndef ELFMAG +#define ELFMAG "\177ELF" /* magic string */ +#endif +#ifndef SELFMAG +#define SELFMAG 4 /* magic string size */ +#endif + +//---------------------------------------------------------------------- +// From sys/syslimits.h +//---------------------------------------------------------------------- + +#define VKI_PATH_MAX 1024 + + +//---------------------------------------------------------------------- +// From sys/timespec.h +//---------------------------------------------------------------------- + +struct vki_timespec { + vki_time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + +struct vki_itimerspec { + struct vki_timespec it_interval; /* timer period */ + struct vki_timespec it_value; /* timer expiration */ +}; + +//---------------------------------------------------------------------- +// From sys/_time.h +//---------------------------------------------------------------------- + +struct vki_timeval { + vki_time_t tv_sec; /* seconds */ + vki_suseconds_t tv_usec; /* microseconds */ +}; + +//---------------------------------------------------------------------- +// From sys/time.h +//---------------------------------------------------------------------- + +#define VKI_CLOCK_REALTIME 0 +#define VKI_CLOCK_MONOTONIC 1 +#define VKI_CLOCK_PROCESS_CPUTIME_ID 2 +#define VKI_CLOCK_THREAD_CPUTIME_ID 3 + +struct vki_timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +struct vki_itimerval { + struct vki_timeval it_interval; /* timer interval */ + struct vki_timeval it_value; /* current value */ +}; + +//---------------------------------------------------------------------- +// From sys/timex.h +//---------------------------------------------------------------------- + +struct vki_ntptimeval { + struct vki_timespec time; + long maxerror; + long esterror; + long tai; + int time_state; +}; + +struct vki_timex { + unsigned int modes; /* mode selector */ + long offset; /* time offset (usec) */ + long freq; /* frequency offset (scaled ppm) */ + long maxerror; /* maximum error (usec) */ + long esterror; /* estimated error (usec) */ + int status; /* clock command/status */ + long constant; /* pll time constant */ + long precision; /* clock precision (usec) (read only) */ + long tolerance; /* clock frequency tolerance (ppm) + * (read only) + */ + long ppsfreq; /* pps frequency (scaled ppm) (ro) */ + long jitter; /* pps jitter (us) (ro) */ + int shift; /* interval duration (s) (shift) (ro) */ + long stabil; /* pps stability (scaled ppm) (ro) */ + long jitcnt; /* jitter limit exceeded (ro) */ + long calcnt; /* calibration intervals (ro) */ + long errcnt; /* calibration errors (ro) */ + long stbcnt; /* stability limit exceeded (ro) */ +}; + +#define MOD_OFFSET 0x0001 /* time offset */ +#define MOD_FREQUENCY 0x0002 /* frequency offset */ +#define MOD_MAXERROR 0x0004 /* maximum time error */ +#define MOD_ESTERROR 0x0008 /* estimated time error */ +#define MOD_STATUS 0x0010 /* clock status */ +#define MOD_TIMECONST 0x0020 /* pll time constant */ +#define MOD_PPSMAX 0x0040 +#define MOD_TAI 0x0080 +#define MOD_MICRO 0x1000 +#define MOD_NANO 0x2000 +#define MOD_CLKB 0x4000 +#define MOD_CLKA 0x8000 + +//---------------------------------------------------------------------- +// From sys/times.h +//---------------------------------------------------------------------- + +struct vki_tms { + vki_clock_t tms_utime; + vki_clock_t tms_stime; + vki_clock_t tms_cutime; + vki_clock_t tms_cstime; +}; + +//---------------------------------------------------------------------- +// From sys/stat.h +//---------------------------------------------------------------------- + +/* QQQ 4.x stat layout */ +struct vki_stat { + vki_dev_t st_dev; + vki_ino_t st_ino; + vki_mode_t st_mode; + vki_nlink_t st_nlink; + vki_uid_t st_uid; + vki_gid_t st_gid; + vki_dev_t st_rdev; +#if 0 + struct vki_timespec st_atimespec; + struct vki_timespec st_mtimespec; + struct vki_timespec st_ctimespec; +#else + vki_time_t st_atime; + long st_atime_nsec; + vki_time_t st_mtime; + long st_mtime_nsec; + vki_time_t st_ctime; + long st_ctime_nsec; +#endif + vki_off_t st_size; + vki_blkcnt_t st_blocks; + vki_blksize_t st_blksize; + vki_fflags_t st_flags; + vki_uint32_t st_gen; + vki_int32_t st_lspare; + struct vki_timespec st_birthtimespec; + unsigned int :(8 / 2) * (16 - (int)sizeof(struct vki_timespec)); + unsigned int :(8 / 2) * (16 - (int)sizeof(struct vki_timespec)); +}; + + +//---------------------------------------------------------------------- +// From linux-2.6.8.1/include/linux/sched.h +//---------------------------------------------------------------------- + +struct vki_sched_param { + int sched_priority; +}; + +//---------------------------------------------------------------------- +// From sys/signal.h +//---------------------------------------------------------------------- + +#define VKI_SIG_BLOCK 1 /* block specified signal set */ +#define VKI_SIG_UNBLOCK 2 /* unblock specified signal set */ +#define VKI_SIG_SETMASK 3 /* set specified signal set */ + +#define VKI_SIG_DFL ((__vki_sighandler_t)0) +#define VKI_SIG_IGN ((__vki_sighandler_t)1) +#define VKI_SIG_ERR ((__vki_sighandler_t)-1) + +typedef void __vki_signalfn_t(int); +typedef __vki_signalfn_t *__vki_sighandler_t; + +#define VKI_SIGHUP 1 +#define VKI_SIGINT 2 +#define VKI_SIGQUIT 3 +#define VKI_SIGILL 4 +#define VKI_SIGTRAP 5 +#define VKI_SIGABRT 6 +#define VKI_SIGEMT 7 +#define VKI_SIGFPE 8 +#define VKI_SIGKILL 9 +#define VKI_SIGBUS 10 +#define VKI_SIGSEGV 11 +#define VKI_SIGSYS 12 +#define VKI_SIGPIPE 13 +#define VKI_SIGALRM 14 +#define VKI_SIGTERM 15 +#define VKI_SIGURG 16 +#define VKI_SIGSTOP 17 +#define VKI_SIGTSTP 18 +#define VKI_SIGCONT 19 +#define VKI_SIGCHLD 20 +#define VKI_SIGTTIN 21 +#define VKI_SIGTTOU 22 +#define VKI_SIGIO 23 +#define VKI_SIGXCPU 24 +#define VKI_SIGXFSZ 25 +#define VKI_SIGVTALRM 26 +#define VKI_SIGPROF 27 +#define VKI_SIGWINCH 28 +#define VKI_SIGINFO 29 +#define VKI_SIGUSR1 30 +#define VKI_SIGUSR2 31 +#define VKI_SIGTHR 32 + +#define VKI_SIGRTMIN 65 +#define VKI_SIGRTMAX 126 + +#define VKI_SA_ONSTACK 0x0001 +#define VKI_SA_RESTART 0x0002 +#define VKI_SA_RESETHAND 0x0004 +#define VKI_SA_NOCLDSTOP 0x0008 +#define VKI_SA_NODEFER 0x0010 +#define VKI_SA_NOCLDWAIT 0x0020 +#define VKI_SA_SIGINFO 0x0040 + +#define VKI_SS_ONSTACK 0x0001 +#define VKI_SS_DISABLE 0x0004 + +#define VKI_SA_ONESHOT VKI_SA_RESETHAND +#define VKI_SA_NOMASK VKI_SA_NODEFER + +struct vki_sigaction { + __vki_sighandler_t ksa_handler; + int sa_flags; + vki_sigset_t sa_mask; +}; + +typedef struct vki_sigaltstack { + void *ss_sp; + vki_size_t ss_size; + int ss_flags; +} vki_stack_t; + +typedef union vki_sigval { + int sival_int; + void *sival_ptr; +} vki_sigval_t; + +#if 0 /* freebsd6 */ +typedef struct vki_siginfo { + int si_signo; + int si_errno; + int si_code; + vki_pid_t si_pid; + vki_uid_t si_uid; + int si_status; + void *si_addr; + vki_sigval_t si_value; + + union { + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct { + int _trapno; /* TRAP # which caused the signal */ + } _sigfault; + + /* POSIX.1b timers */ + struct { + int _timerid; /* timer id */ + int _overrun; /* overrun count */ + } _timer; + + struct { + int _mqd; + } _mesgq; + + /* SIGPOLL */ + struct { + long _band; /* POLL_IN, POLL_OUT, POLL_MSG */ + } _sigpoll; + + struct { + long __spare1__; + int __spare2[7]; + } __spare__; + } _sifields; +} vki_siginfo_t; +#endif +typedef struct vki_siginfo { + int si_signo; + int si_errno; + int si_code; + vki_pid_t si_pid; + vki_uid_t si_uid; + int si_status; + void *si_addr; + vki_sigval_t si_value; +// 666: not valid. switch to above def +#ifdef si_band +#undef si_band +#endif + long si_band; + int __spare__[7]; +} vki_siginfo_t; + +/* + * si_code values + */ +#define VKI_SI_USER 0x10001 /* sent by kill, sigsend, raise */ +#define VKI_SI_QUEUE 0x10002 +#define VKI_SI_TIMER 0x10003 +#define VKI_SI_ASYNCIO 0x10004 +#define VKI_SI_MESGQ 0x10005 + +/* + * SIGILL si_codes + */ +#define VKI_ILL_ILLOPC 1 /* illegal opcode */ +#define VKI_ILL_ILLOPN 2 /* illegal operand */ +#define VKI_ILL_ILLADR 3 /* illegal addressing mode */ +#define VKI_ILL_ILLTRP 4 /* illegal trap */ +#define VKI_ILL_PRVOPC 5 /* privileged opcode */ +#define VKI_ILL_PRVREG 6 /* privileged register */ +#define VKI_ILL_COPROC 7 /* coprocessor error */ +#define VKI_ILL_BADSTK 8 /* internal stack error */ + +/* + * SIGFPE si_codes + */ +#define VKI_FPE_INTOVF 1 /* integer overflow */ +#define VKI_FPE_INTDIV 2 /* integer divide by zero */ +#define VKI_FPE_FLTDIV 3 /* floating point divide by zero */ +#define VKI_FPE_FLTOVF 4 /* floating point overflow */ +#define VKI_FPE_FLTUND 5 /* floating point underflow */ +#define VKI_FPE_FLTRES 6 /* floating point inexact result */ +#define VKI_FPE_FLTINV 7 /* floating point invalid operation */ +#define VKI_FPE_FLTSUB 8 /* subscript out of range */ + +/* + * SIGSEGV si_codes + */ +#define VKI_SEGV_MAPERR 1 /* address not mapped to object */ +#define VKI_SEGV_ACCERR 2 /* invalid permissions for mapped object */ +/* XXX i386 and amd64 specific */ +#define VKI_SEGV_PAGE_FAULT 12 + +/* + * SIGBUS si_codes + */ +#define VKI_BUS_ADRALN 1 /* invalid address alignment */ +#define VKI_BUS_ADRERR 2 /* non-existant physical address */ +#define VKI_BUS_OBJERR 3 /* object specific hardware error */ + +/* + * SIGTRAP si_codes + */ +#define VKI_TRAP_BRKPT 1 /* process breakpoint */ +#define VKI_TRAP_TRACE 2 /* process trace trap */ + + +#if 0 /* freebsd-6 */ +typedef struct vki_sigevent { + int sigev_notify; + int sigev_signo; + vki_sigval_t sigev_value; + union { + int _threadid; + + struct { + void (*_function)(vki_sigval_t); + void *_attribute; /* really pthread_attr_t */ + } _sigev_thread; + long __spare__[8]; + } _sigev_un; +} vki_sigevent_t; +#endif + +struct vki_sigevent { + int sigev_notify; /* Notification type */ + union { + int __sigev_signo; /* Signal number */ + int __sigev_notify_kqueue; + } __sigev_u; + vki_sigval_t sigev_value; /* Signal value */ +}; +#if 0 +#define sigev_signo __sigev_u.__sigev_signo +#define sigev_notify_kqueue __sigev_u.__sigev_notify_kqueue +#endif + +//---------------------------------------------------------------------- +// From sys/_iovec.h +//---------------------------------------------------------------------- + +struct vki_iovec +{ + void *iov_base; + __vki_size_t iov_len; +}; + +//---------------------------------------------------------------------- +// From sys/socket.h +//---------------------------------------------------------------------- + +typedef __vki_sa_family_t vki_sa_family_t; +typedef __vki_socklen_t vki_socklen_t; + +struct vki_sockaddr { + vki_uint8_t sa_len; + vki_sa_family_t sa_family; /* address family, AF_xxx */ + char sa_data[14]; /* 14 bytes of protocol address */ +}; + +struct vki_msghdr { + void * msg_name; /* Socket name */ + vki_socklen_t msg_namelen; /* Length of name */ + struct vki_iovec * msg_iov; /* Data blocks */ + int msg_iovlen; /* Number of blocks */ + void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */ + vki_socklen_t msg_controllen; /* Length of cmsg list */ + int msg_flags; +}; + +struct vki_cmsghdr { + vki_socklen_t cmsg_len; /* data byte count, including hdr */ + int cmsg_level; /* originating protocol */ + int cmsg_type; /* protocol-specific type */ +}; + +#define __VKI_CMSG_NXTHDR(ctl, len, cmsg) __vki_cmsg_nxthdr((ctl),(len),(cmsg)) +#define VKI_CMSG_NXTHDR(mhdr, cmsg) vki_cmsg_nxthdr((mhdr), (cmsg)) + +#define VKI_CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) ) + +#define VKI_CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + VKI_CMSG_ALIGN(sizeof(struct vki_cmsghdr)))) + +#define __VKI_CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct vki_cmsghdr) ? \ + (struct vki_cmsghdr *)(ctl) : \ + (struct vki_cmsghdr *)NULL) +#define VKI_CMSG_FIRSTHDR(msg) __VKI_CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) + +// [[Urgh, this is revolting...] +// QQQ check +static __inline struct vki_cmsghdr * __vki_cmsg_nxthdr(void *__ctl, vki_socklen_t __size, + struct vki_cmsghdr *__cmsg) +{ + struct vki_cmsghdr * __ptr; + + __ptr = (struct vki_cmsghdr*)(((unsigned char *) __cmsg) + VKI_CMSG_ALIGN(__cmsg->cmsg_len)); + if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) + return (struct vki_cmsghdr *)0; + + return __ptr; +} + +static __inline struct vki_cmsghdr * vki_cmsg_nxthdr (struct vki_msghdr *__msg, struct vki_cmsghdr *__cmsg) +{ + return __vki_cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg); +} + +#define VKI_SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ + +#define VKI_AF_UNIX 1 /* Unix domain sockets */ +#define VKI_AF_INET 2 /* Internet IP Protocol */ +#define VKI_AF_INET6 28 /* IP version 6 */ + +#define VKI_MSG_NOSIGNAL 0x20000 /* Do not generate SIGPIPE */ + +#define VKI_SOL_SOCKET 0xffff + +#define VKI_SO_TYPE 0x1008 + +#define VKI_SOCK_STREAM 1 + +#include + +#define VKI_TCP_NODELAY TCP_NODELAY + +#include + +#define VKI_IPPROTO_TCP IPPROTO_TCP + +//---------------------------------------------------------------------- +// From netinet/in.h +//---------------------------------------------------------------------- + +struct vki_in_addr { + vki_in_addr_t s_addr; +}; + +/* Structure describing an Internet (IP) socket address. */ +#define __VKI_SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct vki_sockaddr_in { + vki_uint8_t sin_len; + vki_sa_family_t sin_family; /* Address family */ + vki_in_port_t sin_port; /* Port number */ + struct vki_in_addr sin_addr; /* Internet address */ + char sin_zero[8]; +}; + +//---------------------------------------------------------------------- +// From netinet6/in6.h +//---------------------------------------------------------------------- + +struct vki_in6_addr +{ + union + { + vki_uint8_t u6_addr8[16]; + vki_uint16_t u6_addr16[8]; + vki_uint32_t u6_addr32[4]; + } vki_in6_u; +#define vki_s6_addr vki_in6_u.u6_addr8 +#define vki_s6_addr16 vki_in6_u.u6_addr16 +#define vki_s6_addr32 vki_in6_u.u6_addr32 +}; + +struct vki_sockaddr_in6 { + vki_uint8_t sin6_len; + vki_sa_family_t sin6_family; /* AF_INET6 */ + vki_uint16_t sin6_port; /* Transport layer port # */ + vki_uint32_t sin6_flowinfo; /* IPv6 flow information */ + struct vki_in6_addr sin6_addr; /* IPv6 address */ + vki_uint32_t sin6_scope_id; /* scope id (new in RFC2553) */ +}; + +//---------------------------------------------------------------------- +// From sys/un.h +//---------------------------------------------------------------------- + +#define VKI_UNIX_PATH_MAX 104 /* QQQ overridden by sun_len */ + +struct vki_sockaddr_un { + unsigned char sun_len; + vki_sa_family_t sun_family; /* AF_UNIX */ + char sun_path[VKI_UNIX_PATH_MAX]; /* pathname */ +}; + +#if 0 +//---------------------------------------------------------------------- +// From linux-2.6.8.1/include/linux/if.h +//---------------------------------------------------------------------- + +#define VKI_IFNAMSIZ 16 + +struct vki_ifmap +{ + unsigned long mem_start; + unsigned long mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; + /* 3 bytes spare */ +}; + +struct vki_if_settings +{ + unsigned int type; /* Type of physical device or protocol */ + unsigned int size; /* Size of the data allocated by the caller */ + union { + // [[Nb: converted these all to void* to avoid pulling in + // unnecessary headers]]] + /* {atm/eth/dsl}_settings anyone ? */ + void /*raw_hdlc_proto */__user *raw_hdlc; + void /*cisco_proto */__user *cisco; + void /*fr_proto */__user *fr; + void /*fr_proto_pvc */__user *fr_pvc; + void /*fr_proto_pvc_info */__user *fr_pvc_info; + + /* interface settings */ + void /*sync_serial_settings */__user *sync; + void /*te1_settings */__user *te1; + } ifs_ifsu; +}; + +struct vki_ifreq +{ +#define VKI_IFHWADDRLEN 6 + union + { + char ifrn_name[VKI_IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + + union { + struct vki_sockaddr ifru_addr; + struct vki_sockaddr ifru_dstaddr; + struct vki_sockaddr ifru_broadaddr; + struct vki_sockaddr ifru_netmask; + struct vki_sockaddr ifru_hwaddr; + short ifru_flags; + int ifru_ivalue; + int ifru_mtu; + struct vki_ifmap ifru_map; + char ifru_slave[VKI_IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[VKI_IFNAMSIZ]; + void __user * ifru_data; + struct vki_if_settings ifru_settings; + } ifr_ifru; +}; + +#define vki_ifr_name ifr_ifrn.ifrn_name /* interface name */ +#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ +#define ifr_addr ifr_ifru.ifru_addr /* address */ +#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ +#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define vki_ifr_flags ifr_ifru.ifru_flags /* flags */ +#define vki_ifr_metric ifr_ifru.ifru_ivalue /* metric */ +#define vki_ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_map ifr_ifru.ifru_map /* device map */ +#define ifr_slave ifr_ifru.ifru_slave /* slave device */ +#define vki_ifr_data ifr_ifru.ifru_data /* for use by interface */ +#define vki_ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ +#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ +#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */ +#define ifr_newname ifr_ifru.ifru_newname /* New name */ +#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ + +struct vki_ifconf +{ + int ifc_len; /* size of buffer */ + union + { + char __user *ifcu_buf; + struct vki_ifreq __user *ifcu_req; + } ifc_ifcu; +}; +#define vki_ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ + +//---------------------------------------------------------------------- +// From linux-2.6.8.1/include/linux/if_arp.h +//---------------------------------------------------------------------- + +struct vki_arpreq { + struct vki_sockaddr arp_pa; /* protocol address */ + struct vki_sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ + struct vki_sockaddr arp_netmask; /* netmask (only for proxy arps) */ + char arp_dev[16]; +}; + +//---------------------------------------------------------------------- +// From linux-2.6.8.1/include/linux/route.h +//---------------------------------------------------------------------- + +struct vki_rtentry +{ + unsigned long rt_pad1; + struct vki_sockaddr rt_dst; /* target address */ + struct vki_sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct vki_sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + unsigned long rt_pad3; + void *rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + char __user *rt_dev; /* forcing the device at add */ + unsigned long rt_mtu; /* per route MTU/Window */ +// [[Not important for Valgrind]] +//#ifndef __KERNEL__ +//#define rt_mss rt_mtu /* Compatibility :-( */ +//#endif + unsigned long rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ +}; +#endif + +// QQQ sort + +//---------------------------------------------------------------------- +// From sys/mount.h +//---------------------------------------------------------------------- + +typedef struct vki_fsid { vki_int32_t val[2]; } vki_fsid_t; +#define VKI_OMFSNAMELEN 16 +#define VKI_OMNAMELEN (88 - 2 * sizeof(long)) +#define VKI_MFSNAMELEN 16 +#define VKI_MNAMELEN 88 + +struct vki_statfs4 { + long f_spare2; + long f_bsize; + long f_iosize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + vki_fsid_t f_fsid; + vki_uid_t f_owner; + vki_int32_t f_type; + vki_int32_t f_flags; + long f_syncwrites; + long f_asyncwrites; + char f_fstypename[VKI_OMFSNAMELEN]; + char f_mntonname[VKI_OMNAMELEN]; + long f_syncreads; + long f_asyncreads; + vki_int16_t f_spares1; + char f_mntfromnname[VKI_OMNAMELEN]; + vki_int16_t f_spares2; + long f_spare[2]; +}; + +struct vki_statfs { + vki_uint32_t f_version; + vki_uint32_t f_type; + vki_uint64_t f_flags; + vki_uint64_t f_bsize; + vki_uint64_t f_iosize; + vki_uint64_t f_blocks; + vki_uint64_t f_bfree; + vki_int64_t f_bavail; + vki_uint64_t f_files; + vki_int64_t f_ffree; + vki_uint64_t f_syncwrites; + vki_uint64_t f_asyncwrites; + vki_uint64_t f_syncreads; + vki_uint64_t f_asyncreads; + vki_uint64_t f_spare[10]; + vki_uint32_t f_namemax; + vki_uid_t f_owner; + vki_fsid_t f_fsid; + char f_charspare[80]; + char f_fstypename[VKI_MFSNAMELEN]; + char f_mntfromnname[VKI_MNAMELEN]; + char f_mntonname[VKI_MNAMELEN]; +}; + +#define MAXFIDSZ 16 + +struct vki_fid { + vki_uint16_t fid_len; + vki_uint16_t fid_reserved; + char fid_data[MAXFIDSZ]; +}; + +struct vki_fhandle { + vki_fsid_t fh_fsid; + struct vki_fid fh_fid; +}; + +#define VKI_MNAMELEN6 88 +struct vki_statfs6 { + vki_uint32_t f_version; + vki_uint32_t f_type; + vki_uint64_t f_flags; + vki_uint64_t f_bsize; + vki_uint64_t f_iosize; + vki_uint64_t f_blocks; + vki_uint64_t f_bfree; + vki_int64_t f_bavail; + vki_uint64_t f_files; + vki_int64_t f_ffree; + vki_int64_t f_syncwrites; + vki_int64_t f_asyncwrites; + vki_int64_t f_syncreads; + vki_int64_t f_asyncreads; + vki_uint64_t f_spare[10]; + vki_uint32_t f_namemax; + vki_uid_t f_owner; + vki_fsid_t f_fsid; + char f_charspare[80]; + char f_fstypename[VKI_MFSNAMELEN]; + char f_mntfromnname[VKI_MNAMELEN6]; + char f_mntonname[VKI_MNAMELEN6]; +}; + +//---------------------------------------------------------------------- +// From sys/ttycom.h +//---------------------------------------------------------------------- + +struct vki_winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + + +//---------------------------------------------------------------------- +// From sys/termios.h +//---------------------------------------------------------------------- + +typedef unsigned int vki_tcflag_t; +typedef unsigned char vki_cc_t; +typedef unsigned int vki_speed_t; + +#define VKI_NCCS 20 +struct vki_termios { + vki_tcflag_t c_iflag; /* input mode flags */ + vki_tcflag_t c_oflag; /* output mode flags */ + vki_tcflag_t c_cflag; /* control mode flags */ + vki_tcflag_t c_lflag; /* local mode flags */ + vki_cc_t c_cc[VKI_NCCS]; /* control characters */ + vki_speed_t c_ispeed; + vki_speed_t c_ospeed; +}; + +//---------------------------------------------------------------------- +// From sys/ioccom.h +//---------------------------------------------------------------------- + +/* QQQ keep linux's naming, but use our layout */ + +/* + * We actually have a 16 bit "base" ioctl, which may or may not be decoded + * into number/group + */ +#define _VKI_IOC_BASEBITS 16 +#define _VKI_IOC_NRBITS 8 /* "num" on freebsd */ +#define _VKI_IOC_TYPEBITS 8 /* "group" on freebsd */ + +#define _VKI_IOC_SIZEBITS 13 +#define _VKI_IOC_DIRBITS 3 + +#define _VKI_IOC_BASEMASK ((1ul << _VKI_IOC_BASEBITS)-1) +#define _VKI_IOC_NRMASK ((1ul << _VKI_IOC_NRBITS)-1) +#define _VKI_IOC_TYPEMASK ((1ul << _VKI_IOC_TYPEBITS)-1) +#define _VKI_IOC_SIZEMASK ((1ul << _VKI_IOC_SIZEBITS)-1) +#define _VKI_IOC_DIRMASK ((1ul << _VKI_IOC_DIRBITS)-1) + +#define _VKI_IOC_BASESHIFT 0 +#define _VKI_IOC_NRSHIFT 0 +#define _VKI_IOC_TYPESHIFT (_VKI_IOC_NRSHIFT+_VKI_IOC_NRBITS) +#define _VKI_IOC_SIZESHIFT (_VKI_IOC_TYPESHIFT+_VKI_IOC_TYPEBITS) +#define _VKI_IOC_DIRSHIFT (_VKI_IOC_SIZESHIFT+_VKI_IOC_SIZEBITS) + +#define _VKI_IOC_NONE 1U /* "void" on freebsd, as a specific mode */ +#define _VKI_IOC_READ 2U /* "out", copyout in reversed linux terminology */ +#define _VKI_IOC_WRITE 4U /* "in", copyin in reversed linux terminology */ +#define _VKI_IOC_RDWR 6U /* "inout", copyin and copyout */ + +#define _VKI_IOC(dir,type,nr,size) \ + (((dir) << _VKI_IOC_DIRSHIFT) | \ + ((type) << _VKI_IOC_TYPESHIFT) | \ + ((nr) << _VKI_IOC_NRSHIFT) | \ + ((size) << _VKI_IOC_SIZESHIFT)) + +/* provoke compile error for invalid uses of size argument */ +extern unsigned int __vki_invalid_size_argument_for_IOC; +#define _VKI_IOC_TYPECHECK(t) \ + ((sizeof(t) == sizeof(t[1]) && \ + sizeof(t) < (1 << _VKI_IOC_SIZEBITS)) ? \ + sizeof(t) : __vki_invalid_size_argument_for_IOC) + +/* used to create numbers */ +#define _VKI_IO(type,nr) _VKI_IOC(_VKI_IOC_NONE,(type),(nr),0) +#define _VKI_IOR(type,nr,size) _VKI_IOC(_VKI_IOC_READ,(type),(nr),(_VKI_IOC_TYPECHECK(size))) +#define _VKI_IOW(type,nr,size) _VKI_IOC(_VKI_IOC_WRITE,(type),(nr),(_VKI_IOC_TYPECHECK(size))) +#define _VKI_IOWR(type,nr,size) _VKI_IOC(_VKI_IOC_READ|_VKI_IOC_WRITE,(type),(nr),(_VKI_IOC_TYPECHECK(size))) + +/* used to decode ioctl numbers.. */ +#define _VKI_IOC_DIR(nr) (((nr) >> _VKI_IOC_DIRSHIFT) & _VKI_IOC_DIRMASK) +#define _VKI_IOC_TYPE(nr) (((nr) >> _VKI_IOC_TYPESHIFT) & _VKI_IOC_TYPEMASK) +#define _VKI_IOC_NR(nr) (((nr) >> _VKI_IOC_NRSHIFT) & _VKI_IOC_NRMASK) +#define _VKI_IOC_SIZE(nr) (((nr) >> _VKI_IOC_SIZESHIFT) & _VKI_IOC_SIZEMASK) +#define _VKI_IOC_BASE(nr) (((nr) >> _VKI_IOC_BASESHIFT) & _VKI_IOC_BASEMASK) + + +//---------------------------------------------------------------------- +// From sys/termios.h +//---------------------------------------------------------------------- + +#if 0 +#define VKI_TCGETS 0x5401 +#define VKI_TCSETS 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */ +#define VKI_TCSETSW 0x5403 +#define VKI_TCSETSF 0x5404 +#define VKI_TCGETA 0x5405 y +#define VKI_TCSETA 0x5406 y +#define VKI_TCSETAW 0x5407 y +#define VKI_TCSETAF 0x5408 y +#define VKI_TCSBRK 0x5409 +#define VKI_TCXONC 0x540A +#define VKI_TCFLSH 0x540B y +#define VKI_TIOCSCTTY 0x540E +#define VKI_TIOCGPGRP 0x540F y +#define VKI_TIOCSPGRP 0x5410 y +#define VKI_TIOCOUTQ 0x5411 +#define VKI_TIOCGWINSZ 0x5413 y +#define VKI_TIOCSWINSZ 0x5414 y +#define VKI_TIOCMGET 0x5415 y +#define VKI_TIOCMBIS 0x5416 y +#define VKI_TIOCMBIC 0x5417 y +#define VKI_TIOCMSET 0x5418 y +#define VKI_FIONREAD 0x541B +#define VKI_TIOCLINUX 0x541C +#define VKI_FIONBIO 0x5421 +#define VKI_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define VKI_TIOCGPTN _VKI_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define VKI_TIOCSPTLCK _VKI_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define VKI_FIOASYNC 0x5452 +#define VKI_TIOCSERGETLSR 0x5459 /* Get line status register */ + +#define VKI_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#endif + +#define VKI_TIOCFLUSH _VKI_IOW('t', 16, int); +#define VKI_TIOCGETA _VKI_IOR('t', 19, struct vki_termios) /* get termios */ +#define VKI_TIOCSETA _VKI_IOR('t', 20, struct vki_termios) /* set termios */ +#define VKI_TIOCSETAW _VKI_IOR('t', 21, struct vki_termios) /* drain,set */ +#define VKI_TIOCSETAF _VKI_IOR('t', 22, struct vki_termios) /* flush,set */ + +#define VKI_TIOCSBRK _VKI_IO('t', 123) +#define VKI_TIOCCBRK _VKI_IO('t', 122) +#define VKI_TIOCGPGRP _VKI_IOR('t', 119, int) /* get pgrp */ +#define VKI_TIOCSPGRP _VKI_IOW('t', 118, int) /* set pgrp */ + +#define VKI_TIOCGWINSZ _VKI_IOR('t', 104, struct vki_winsize) /* get window size */ +#define VKI_TIOCSWINSZ _VKI_IOW('t', 103, struct vki_winsize) /* set window size */ + +#define VKI_TIOCMGET _VKI_IOR('t', 106, int) /* get all modem bits */ +#define VKI_TIOCMBIS _VKI_IOW('t', 108, int) /* bis modem bits */ +#define VKI_TIOCMBIC _VKI_IOW('t', 107, int) /* bic modem bits */ +#define VKI_TIOCMSET _VKI_IOW('t', 109, int) /* set all modem bits */ + + +//---------------------------------------------------------------------- +// From sys/filio.h +//---------------------------------------------------------------------- + +#define VKI_FIOCLEX _VKI_IO('f', 1) /* close on exec */ +#define VKI_FIONCLEX _VKI_IO('f', 2) /* no close on exec */ +#define VKI_FIONREAD _VKI_IOR('f', 127, int) +#define VKI_FIONBIO _VKI_IOW('f', 126, int) +#define VKI_FIOASYNC _VKI_IOW('f', 125, int) +#define VKI_FIOSETOWN _VKI_IOW('f', 124, int) +#define VKI_FIOGETOWN _VKI_IOW('f', 123, int) + +//---------------------------------------------------------------------- +// From sys/poll.h +//---------------------------------------------------------------------- + +#define VKI_POLLIN 0x0001 + +struct vki_pollfd { + int fd; + short events; + short revents; +}; + +//---------------------------------------------------------------------- +// From sys/kevent.h +//---------------------------------------------------------------------- +struct vki_kevent { + vki_uintptr_t ident; + vki_int16_t filter; + vki_uint16_t flags; + vki_uint32_t fflags; + vki_intptr_t data; + void *udata; +}; + + +// QQQ sort + +//---------------------------------------------------------------------- +// From sys/resource.h +//---------------------------------------------------------------------- + +struct vki_rusage { + struct vki_timeval ru_utime; /* user time used */ + struct vki_timeval ru_stime; /* system time used */ + long ru_maxrss; /* maximum resident set size */ + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +}; + +struct vki_rlimit { + vki_rlim_t rlim_cur; + vki_rlim_t rlim_max; +}; + +#define VKI_RLIMIT_DATA 2 /* max data size */ +#define VKI_RLIMIT_STACK 3 /* max stack size */ +#define VKI_RLIMIT_CORE 4 /* max core file size */ +#define VKI_RLIMIT_NOFILE 8 /* max number of open files */ + +//---------------------------------------------------------------------- +// From sys/procfs.h +//---------------------------------------------------------------------- + +#define VKI_PRSTATUS_VERSION 1 +struct vki_elf_prstatus +{ + int pr_version; /* version of struct - PRSTATUS_VERSION */ + vki_size_t pr_statussz; + vki_size_t pr_gregsetsz; + vki_size_t pr_fpregsetsz; + int pr_osreldate; + short pr_cursig; /* Current signal */ + vki_pid_t pr_pid; + vki_elf_gregset_t pr_reg; /* GP registers */ +}; + +#define VKI_ELF_PRARGSZ (80) /* Number of chars for args */ +#define VKI_MAXCOMLEN (16) + +#define VKI_PRPSINFO_VERSION 1 +struct vki_elf_prpsinfo +{ + int pr_version; /* version of struct - PRPSINFO_VERSION */ + vki_size_t pr_psinfosz; + char pr_fname[VKI_MAXCOMLEN+1]; /* filename of executable */ + char pr_psargs[VKI_ELF_PRARGSZ]; /* initial part of arg list */ +}; + +//---------------------------------------------------------------------- +// From posix4/mqueue.h +//---------------------------------------------------------------------- + +struct vki_mq_attr { + long mq_flags; /* message queue flags */ + long mq_maxmsg; /* maximum number of messages */ + long mq_msgsize; /* maximum message size */ + long mq_curmsgs; /* number of messages currently queued */ +}; + +//---------------------------------------------------------------------- +// From sys/ucontext.h +//---------------------------------------------------------------------- + +#define VKI_UCF_SWAPPED 1 + +struct vki_ucontext { + vki_sigset_t uc_sigmask; + struct vki_mcontext uc_mcontext; + struct vki_ucontext *uc_link; + vki_stack_t uc_stack; + int uc_flags; + unsigned int __spare__[4]; +}; + +//---------------------------------------------------------------------- +// From sys/utsname.h +//---------------------------------------------------------------------- + +#define VKI_SYS_NMLN 32 + +struct vki_utsname { + char sysname[VKI_SYS_NMLN]; /* Name of this OS. */ + char nodename[VKI_SYS_NMLN]; /* Name of this network node. */ + char release[VKI_SYS_NMLN]; /* Release level. */ + char version[VKI_SYS_NMLN]; /* Version level. */ + char machine[VKI_SYS_NMLN]; /* Hardware type. */ +}; + +#define VKI_IPC_CREAT 00001000 /* create if key is nonexistent */ +#define VKI_IPC_EXCL 00002000 /* fail if key exists */ +#define VKI_IPC_NOWAIT 00004000 /* return error on wait */ + +#define VKI_IPC_RMID 0 /* remove resource */ +#define VKI_IPC_SET 1 /* set ipc_perm options */ +#define VKI_IPC_STAT 2 /* get ipc_perm options */ +#define VKI_IPC_INFO 3 /* see ipcs */ + +struct vki_ipc_perm +{ + vki_uid_t cuid; + vki_gid_t cgid; + vki_uid_t uid; + vki_gid_t gid; + vki_mode_t mode; + unsigned short seq; + vki_key_t key; +}; + +struct vki_ipc_perm7 +{ + unsigned short cuid; + unsigned short cgid; + unsigned short uid; + unsigned short gid; + unsigned short mode; + unsigned short seq; + vki_key_t key; +}; + +//---------------------------------------------------------------------- +// From sys/sem.h +//---------------------------------------------------------------------- + +#if 0 +#define VKI_SEMOP 1 +#define VKI_SEMGET 2 +#define VKI_SEMCTL 3 +#define VKI_SEMTIMEDOP 4 +#endif + +#define VKI_GETALL 6 /* get all semval's */ +#define VKI_SETVAL 8 /* set semval */ +#define VKI_SETALL 9 /* set all semval's */ +#define VKI_SEM_STAT 10 +#define VKI_SEM_INFO 11 + +/* Obsolete, used only for backwards compatibility and libc5 compiles */ +struct vki_semid_ds { + struct vki_ipc_perm sem_perm; /* permissions .. see ipc.h */ + // [[Use void* to avoid excess header copying]] + void/*struct sem */*sem_base; /* ptr to first semaphore in array */ + unsigned short sem_nsems; /* no. of semaphores in array */ + vki_time_t sem_otime; /* last semop time */ + vki_time_t sem_ctime; /* last change time */ + long sem_pad2; + long sem_pad3[4]; +}; + +struct vki_sembuf { + vki_uint16_t sem_num; /* semaphore index in array */ + vki_int16_t sem_op; /* semaphore operation */ + vki_int16_t sem_flg; /* operation flags */ +}; + +union vki_semun { + int val; /* value for SETVAL */ + struct vki_semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + vki_uint16_t *array; /* array for GETALL & SETALL */ +}; + + +//---------------------------------------------------------------------- +// From sys/errno.h +//---------------------------------------------------------------------- + +#define VKI_ERESTART -1 +#define VKI_EPERM 1 /* Operation not permitted */ +#define VKI_ENOENT 2 /* No such file or directory */ +#define VKI_ESRCH 3 /* No such process */ +#define VKI_EINTR 4 /* Interrupted system call */ +#define VKI_EIO 5 /* Input/output error */ +#define VKI_ENXIO 6 /* Device not configured */ +#define VKI_E2BIG 7 /* Argument list too long */ +#define VKI_ENOEXEC 8 /* Exec format error */ +#define VKI_EBADF 9 /* Bad file descriptor */ +#define VKI_ECHILD 10 /* No child processes */ +#define VKI_EDEADLK 11 /* Resource deadlock avoided */ +#define VKI_ENOMEM 12 /* Cannot allocate memory */ +#define VKI_EACCES 13 /* Permission denied */ +#define VKI_EFAULT 14 /* Bad address */ +#define VKI_ENOTBLK 15 /* Block device required */ +#define VKI_EBUSY 16 /* Device busy */ +#define VKI_EEXIST 17 /* File exists */ +#define VKI_EXDEV 18 /* Cross-device link */ +#define VKI_ENODEV 19 /* Operation not supported by device */ +#define VKI_ENOTDIR 20 /* Not a directory */ +#define VKI_EISDIR 21 /* Is a directory */ +#define VKI_EINVAL 22 /* Invalid argument */ +#define VKI_ENFILE 23 /* Too many open files in system */ +#define VKI_EMFILE 24 /* Too many open files */ +#define VKI_ENOTTY 25 /* Inappropriate ioctl for device */ +#define VKI_ETXTBSY 26 /* Text file busy */ +#define VKI_EFBIG 27 /* File too large */ +#define VKI_ENOSPC 28 /* No space left on device */ +#define VKI_ESPIPE 29 /* Illegal seek */ +#define VKI_EROFS 30 /* Read-only filesystem */ +#define VKI_EMLINK 31 /* Too many links */ +#define VKI_EPIPE 32 /* Broken pipe */ +#define VKI_EDOM 33 /* Numerical argument out of domain */ +#define VKI_ERANGE 34 /* Result too large */ +#define VKI_EAGAIN 35 /* Resource temporarily unavailable */ +#define VKI_EWOULDBLOCK VKI_EAGAIN /* Operation would block */ +#define VKI_EINPROGRESS 36 /* Operation now in progress */ +#define VKI_EALREADY 37 /* Operation already in progress */ +#define VKI_ENOTSOCK 38 /* Socket operation on non-socket */ +#define VKI_EDESTADDRREQ 39 /* Destination address required */ +#define VKI_EMSGSIZE 40 /* Message too long */ +#define VKI_EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define VKI_ENOPROTOOPT 42 /* Protocol not available */ +#define VKI_EPROTONOSUPPORT 43 /* Protocol not supported */ +#define VKI_ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define VKI_EOPNOTSUPP 45 /* Operation not supported */ +#define VKI_ENOTSUP VKI_EOPNOTSUPP /* Operation not supported */ +#define VKI_EPFNOSUPPORT 46 /* Protocol family not supported */ +#define VKI_EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define VKI_EADDRINUSE 48 /* Address already in use */ +#define VKI_EADDRNOTAVAIL 49 +#define VKI_ENETDOWN 50 /* Network is down */ +#define VKI_ENETUNREACH 51 /* Network is unreachable */ +#define VKI_ENETRESET 52 /* Network dropped connection on reset */ +#define VKI_ECONNABORTED 53 /* Software caused connection abort */ +#define VKI_ECONNRESET 54 /* Connection reset by peer */ +#define VKI_ENOBUFS 55 /* No buffer space available */ +#define VKI_EISCONN 56 /* Socket is already connected */ +#define VKI_ENOTCONN 57 /* Socket is not connected */ +#define VKI_ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define VKI_ETOOMANYREFS 59 /* Too many references: can't splice */ +#define VKI_ETIMEDOUT 60 /* Operation timed out */ +#define VKI_ECONNREFUSED 61 /* Connection refused */ +#define VKI_ELOOP 62 /* Too many levels of symbolic links */ +#define VKI_ENAMETOOLONG 63 /* File name too long */ +#define VKI_EHOSTDOWN 64 /* Host is down */ +#define VKI_EHOSTUNREACH 65 /* No route to host */ +#define VKI_ENOTEMPTY 66 /* Directory not empty */ +#define VKI_EPROCLIM 67 /* Too many processes */ +#define VKI_EUSERS 68 /* Too many users */ +#define VKI_EDQUOT 69 /* Disc quota exceeded */ +#define VKI_ESTALE 70 /* Stale NFS file handle */ +#define VKI_EREMOTE 71 /* Too many levels of remote in path */ +#define VKI_EBADRPC 72 /* RPC struct is bad */ +#define VKI_ERPCMISMATCH 73 /* RPC version wrong */ +#define VKI_EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define VKI_EPROGMISMATCH 75 /* Program version wrong */ +#define VKI_EPROCUNAVAIL 76 /* Bad procedure for program */ +#define VKI_ENOLCK 77 /* No locks available */ +#define VKI_ENOSYS 78 /* Function not implemented */ +#define VKI_EFTYPE 79 /* Inappropriate file type or format */ +#define VKI_EAUTH 80 /* Authentication error */ +#define VKI_ENEEDAUTH 81 /* Need authenticator */ +#define VKI_EIDRM 82 /* Identifier removed */ +#define VKI_ENOMSG 83 /* No message of desired type */ +#define VKI_EOVERFLOW 84 /* Value too large to be stored in data type */ +#define VKI_ECANCELED 85 /* Operation canceled */ +#define VKI_EILSEQ 86 /* Illegal byte sequence */ +#define VKI_ENOATTR 87 /* Attribute not found */ +#define VKI_EDOOFUS 88 /* Programming error */ +#define VKI_EBADMSG 89 /* Bad message */ +#define VKI_EMULTIHOP 90 /* Multihop attempted */ +#define VKI_ENOLINK 91 /* Link has been severed */ +#define VKI_EPROTO 92 /* Protocol error */ +#define VKI_ENOTCAPABLE 93 /* Capabilities insufficient */ +#define VKI_ECAPMODE 94 /* Not permitted in capability mode */ + +//---------------------------------------------------------------------- +// From sys/wait.h +//---------------------------------------------------------------------- + +#define VKI_WNOHANG 0x00000001 + +//---------------------------------------------------------------------- +// From sys/mman.h +//---------------------------------------------------------------------- + +#define VKI_PROT_NONE 0x00 /* No page permissions */ +#define VKI_PROT_READ 0x01 /* page can be read */ +#define VKI_PROT_WRITE 0x02 /* page can be written */ +#define VKI_PROT_EXEC 0x04 /* page can be executed */ + +#define VKI_MAP_SHARED 0x01 /* Share changes */ +#define VKI_MAP_PRIVATE 0x02 /* Changes are private */ +#define VKI_MAP_FIXED 0x10 /* Interpret addr exactly */ +#define VKI_MAP_NORESERVE 0x0040 /* don't check for reservations */ +#define VKI_MAP_STACK 0x400 +#define VKI_MAP_ANON 0x1000 /* don't use a file */ +#define VKI_MAP_ANONYMOUS VKI_MAP_ANON + +//---------------------------------------------------------------------- +// From sys/stat.h +//---------------------------------------------------------------------- + +#define VKI_S_IFMT 00170000 + +#define VKI_S_IFWHT 0160000 +#define VKI_S_IFSOCK 0140000 +#define VKI_S_IFLNK 0120000 +#define VKI_S_IFREG 0100000 +#define VKI_S_IFBLK 0060000 +#define VKI_S_IFDIR 0040000 +#define VKI_S_IFCHR 0020000 +#define VKI_S_IFIFO 0010000 +#define VKI_S_ISUID 0004000 +#define VKI_S_ISGID 0002000 +#define VKI_S_ISTXT 0001000 + +#define VKI_S_ISLNK(m) (((m) & VKI_S_IFMT) == VKI_S_IFLNK) +#define VKI_S_ISREG(m) (((m) & VKI_S_IFMT) == VKI_S_IFREG) +#define VKI_S_ISDIR(m) (((m) & VKI_S_IFMT) == VKI_S_IFDIR) +#define VKI_S_ISCHR(m) (((m) & VKI_S_IFMT) == VKI_S_IFCHR) +#define VKI_S_ISBLK(m) (((m) & VKI_S_IFMT) == VKI_S_IFBLK) +#define VKI_S_ISFIFO(m) (((m) & VKI_S_IFMT) == VKI_S_IFIFO) +#define VKI_S_ISSOCK(m) (((m) & VKI_S_IFMT) == VKI_S_IFSOCK) +#define VKI_S_ISWHT(m) (((m) & VKI_S_IFMT) == VKI_S_IFWHT) + +#define VKI_S_IRWXU 00700 +#define VKI_S_IRUSR 00400 +#define VKI_S_IWUSR 00200 +#define VKI_S_IXUSR 00100 + +#define VKI_S_IRWXG 00070 +#define VKI_S_IRGRP 00040 +#define VKI_S_IWGRP 00020 +#define VKI_S_IXGRP 00010 + +#define VKI_S_IRWXO 00007 +#define VKI_S_IROTH 00004 +#define VKI_S_IWOTH 00002 +#define VKI_S_IXOTH 00001 + + +//---------------------------------------------------------------------- +// From sys/dirent.h +//---------------------------------------------------------------------- + +struct vki_dirent { + vki_uint32_t d_fileno; + vki_uint16_t d_reclen; + vki_uint8_t d_type; + vki_uint8_t d_namelen; + char d_name[256]; /* We must not include limits.h! */ +}; + +//---------------------------------------------------------------------- +// From sys/fcntl.h +//---------------------------------------------------------------------- + +#define VKI_O_RDONLY O_RDONLY +#define VKI_O_WRONLY O_WRONLY +#define VKI_O_RDWR O_RDWR + +#define VKI_O_NONBLOCK O_NONBLOCK +#define VKI_O_APPEND O_APPEND +#define VKI_O_CREAT O_CREAT +#define VKI_O_TRUNC O_TRUNC +#define VKI_O_EXCL O_EXCL + +#define VKI_AT_FDCWD AT_FDCWD + +#define VKI_F_DUPFD 0 /* dup */ +#define VKI_F_GETFD 1 /* get close_on_exec */ +#define VKI_F_SETFD 2 /* set/clear close_on_exec */ +#define VKI_F_GETFL 3 /* get file->f_flags */ +#define VKI_F_SETFL 4 /* set file->f_flags */ +#define VKI_F_SETOWN 5 /* for sockets. */ +#define VKI_F_GETOWN 6 /* for sockets. */ +#define VKI_F_OGETLK 7 /* get record locking information */ +#define VKI_F_OSETLK 8 /* set record locking information */ +#define VKI_F_OSETLKW 9 /* F_SETLK; wait if blocked */ +#define VKI_F_DUP2FD 10 /* duplicate file descriptor to arg */ +#define VKI_F_GETLK 11 /* get record locking information */ +#define VKI_F_SETLK 12 /* set record locking information */ +#define VKI_F_SETLKW 13 /* F_SETLK; wait if blocked */ +#define VKI_F_SETLK_REMOTE 14 /* debugging support for remote locks */ +#define VKI_F_DUPFD_CLOEXEC 17 /* dup close_on_exec */ + +/* for F_[GET|SET]FL */ +#define VKI_FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +//---------------------------------------------------------------------- +// From sys/unistd.h +//---------------------------------------------------------------------- + +#define VKI_SEEK_SET 0 +#define VKI_SEEK_CUR 1 +#define VKI_SEEK_END 2 + +#define VKI_F_OK 0 /* test for existence of file */ +#define VKI_X_OK 0x01 /* test for execute or search permission */ +#define VKI_W_OK 0x02 /* test for write permission */ +#define VKI_R_OK 0x04 /* test for read permission */ + +//---------------------------------------------------------------------- +// From sys/msg.h +//---------------------------------------------------------------------- + +#if 0 /* not in freebsd */ +#define VKI_MSGSND 11 +#define VKI_MSGRCV 12 +#define VKI_MSGGET 13 +#define VKI_MSGCTL 14 +#endif + +struct vki_msqid_ds { + struct vki_ipc_perm msg_perm; + struct vki_msg *msg_first; /* first message on queue,unused */ + struct vki_msg *msg_last; /* last message in queue,unused */ + vki_uint32_t msg_cbytes; /* current number of bytes on queue */ + vki_uint32_t msg_qnum; /* number of messages in queue */ + vki_uint32_t msg_qbytes; /* max number of bytes on queue */ + vki_pid_t msg_lspid; /* pid of last msgsnd */ + vki_pid_t msg_lrpid; /* last receive pid */ + vki_time_t msg_stime; /* last msgsnd time */ + vki_uint32_t msg_pad1; + vki_time_t msg_rtime; /* last msgrcv time */ + vki_uint32_t msg_pad2; + vki_time_t msg_ctime; /* last change time */ + vki_uint32_t msg_pad3; + vki_uint32_t msg_pad4[4]; +}; + +struct vki_msgbuf { + long mtype; /* type of message */ + char mtext[1]; /* message text */ +}; + + +//---------------------------------------------------------------------- +// From sys/shm.h +//---------------------------------------------------------------------- + +struct vki_shmid_ds { + struct vki_ipc_perm shm_perm; /* operation perms */ + vki_size_t shm_segsz; /* size of segment (bytes) */ + vki_pid_t shm_lpid; /* pid of last operator */ + vki_pid_t shm_cpid; /* pid of creator */ + int shm_nattch; /* no. of current attaches */ + vki_time_t shm_atime; /* last attach time */ + vki_time_t shm_dtime; /* last detach time */ + vki_time_t shm_ctime; /* last change time */ +}; + +struct vki_shmid_ds7 { + struct vki_ipc_perm7 shm_perm; /* operation perms */ + int shm_segsz; /* size of segment (bytes) */ + vki_pid_t shm_lpid; /* pid of last operator */ + vki_pid_t shm_cpid; /* pid of creator */ + short shm_nattch; /* no. of current attaches */ + vki_time_t shm_atime; /* last attach time */ + vki_time_t shm_dtime; /* last detach time */ + vki_time_t shm_ctime; /* last change time */ + void *shm_internal; /* sysv stupidity */ +}; + +#define VKI_SHMLBA VKI_PAGE_SIZE +#define VKI_SHM_RDONLY 010000 /* read-only access */ +#define VKI_SHM_ANON (1UL) + +#if 0 /* not in freebsd abi */ +#define VKI_SHMAT 21 +#define VKI_SHMDT 22 +#define VKI_SHMGET 23 +#define VKI_SHMCTL 24 +#endif + +#if 0 +//---------------------------------------------------------------------- +// From linux-2.6.8.1/include/linux/sockios.h +//---------------------------------------------------------------------- + +#define VKI_SIOCOUTQ VKI_TIOCOUTQ + +#define VKI_SIOCADDRT 0x890B /* add routing table entry */ +#define VKI_SIOCDELRT 0x890C /* delete routing table entry */ + +#define VKI_SIOCGIFNAME 0x8910 /* get iface name */ +#define VKI_SIOCGIFCONF 0x8912 /* get iface list */ +#define VKI_SIOCGIFFLAGS 0x8913 /* get flags */ +#define VKI_SIOCSIFFLAGS 0x8914 /* set flags */ +#define VKI_SIOCGIFADDR 0x8915 /* get PA address */ +#define VKI_SIOCSIFADDR 0x8916 /* set PA address */ +#define VKI_SIOCGIFDSTADDR 0x8917 /* get remote PA address */ +#define VKI_SIOCSIFDSTADDR 0x8918 /* set remote PA address */ +#define VKI_SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ +#define VKI_SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ +#define VKI_SIOCGIFNETMASK 0x891b /* get network PA mask */ +#define VKI_SIOCSIFNETMASK 0x891c /* set network PA mask */ +#define VKI_SIOCGIFMETRIC 0x891d /* get metric */ +#define VKI_SIOCSIFMETRIC 0x891e /* set metric */ +#define VKI_SIOCGIFMTU 0x8921 /* get MTU size */ +#define VKI_SIOCSIFMTU 0x8922 /* set MTU size */ +#define VKI_SIOCSIFHWADDR 0x8924 /* set hardware address */ +#define VKI_SIOCGIFHWADDR 0x8927 /* Get hardware address */ +#define VKI_SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ + +#define VKI_SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ +#define VKI_SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ + +#define VKI_SIOCGMIIPHY 0x8947 /* Get address of MII PHY in use. */ +#define VKI_SIOCGMIIREG 0x8948 /* Read MII PHY register. */ +#define VKI_SIOCSMIIREG 0x8949 /* Write MII PHY register. */ + +#define VKI_SIOCDARP 0x8953 /* delete ARP table entry */ +#define VKI_SIOCGARP 0x8954 /* get ARP table entry */ +#define VKI_SIOCSARP 0x8955 /* set ARP table entry */ + +#define VKI_SIOCDRARP 0x8960 /* delete RARP table entry */ +#define VKI_SIOCGRARP 0x8961 /* get RARP table entry */ +#define VKI_SIOCSRARP 0x8962 /* set RARP table entry */ + +#define VKI_SIOCGIFMAP 0x8970 /* Get device parameters */ +#define VKI_SIOCSIFMAP 0x8971 /* Set device parameters */ + +//---------------------------------------------------------------------- +// From linux-2.6.9/include/linux/kb.h +//---------------------------------------------------------------------- + +#define VKI_GIO_FONT 0x4B60 /* gets font in expanded form */ +#define VKI_PIO_FONT 0x4B61 /* use font in expanded form */ + +#define VKI_GIO_FONTX 0x4B6B /* get font using struct consolefontdesc */ +#define VKI_PIO_FONTX 0x4B6C /* set font using struct consolefontdesc */ +struct vki_consolefontdesc { + unsigned short charcount; /* characters in font (256 or 512) */ + unsigned short charheight; /* scan lines per character (1-32) */ + char __user *chardata; /* font data in expanded form */ +}; + +#define VKI_PIO_FONTRESET 0x4B6D /* reset to default font */ + +#define VKI_GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */ +#define VKI_PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */ + +#define VKI_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ +#define VKI_KDMKTONE 0x4B30 /* generate tone */ + +#define VKI_KDGETLED 0x4B31 /* return current led state */ +#define VKI_KDSETLED 0x4B32 /* set led state [lights, not flags] */ + +#define VKI_KDGKBTYPE 0x4B33 /* get keyboard type */ + +#define VKI_KDADDIO 0x4B34 /* add i/o port as valid */ +#define VKI_KDDELIO 0x4B35 /* del i/o port as valid */ +#define VKI_KDENABIO 0x4B36 /* enable i/o to video board */ +#define VKI_KDDISABIO 0x4B37 /* disable i/o to video board */ + +#define VKI_KDSETMODE 0x4B3A /* set text/graphics mode */ +#define VKI_KDGETMODE 0x4B3B /* get current mode */ + +#define VKI_KDMAPDISP 0x4B3C /* map display into address space */ +#define VKI_KDUNMAPDISP 0x4B3D /* unmap display from address space */ + +#define VKI_E_TABSZ 256 +#define VKI_GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */ +#define VKI_PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */ +#define VKI_GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */ +#define VKI_PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */ + +#define VKI_GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */ +#define VKI_PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */ +#define VKI_PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */ + +#define VKI_KDGKBMODE 0x4B44 /* gets current keyboard mode */ +#define VKI_KDSKBMODE 0x4B45 /* sets current keyboard mode */ + +#define VKI_KDGKBMETA 0x4B62 /* gets meta key handling mode */ +#define VKI_KDSKBMETA 0x4B63 /* sets meta key handling mode */ + +#define VKI_KDGKBLED 0x4B64 /* get led flags (not lights) */ +#define VKI_KDSKBLED 0x4B65 /* set led flags (not lights) */ + +struct vki_kbentry { + unsigned char kb_table; + unsigned char kb_index; + unsigned short kb_value; +}; +#define VKI_KDGKBENT 0x4B46 /* gets one entry in translation table */ +#define VKI_KDSKBENT 0x4B47 /* sets one entry in translation table */ + +struct vki_kbsentry { + unsigned char kb_func; + unsigned char kb_string[512]; +}; +#define VKI_KDGKBSENT 0x4B48 /* gets one function key string entry */ +#define VKI_KDSKBSENT 0x4B49 /* sets one function key string entry */ + +struct vki_kbdiacr { + unsigned char diacr, base, result; +}; +struct vki_kbdiacrs { + unsigned int kb_cnt; /* number of entries in following array */ + struct vki_kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */ +}; +#define VKI_KDGKBDIACR 0x4B4A /* read kernel accent table */ +#define VKI_KDSKBDIACR 0x4B4B /* write kernel accent table */ + +struct vki_kbkeycode { + unsigned int scancode, keycode; +}; +#define VKI_KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */ +#define VKI_KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */ + +#define VKI_KDSIGACCEPT 0x4B4E /* accept kbd generated signals */ + +struct vki_kbd_repeat { + int delay; /* in msec; <= 0: don't change */ + int period; /* in msec; <= 0: don't change */ + /* earlier this field was misnamed "rate" */ +}; +#define VKI_KDKBDREP 0x4B52 /* set keyboard delay/repeat rate; + * actually used values are returned */ + +#define VKI_KDFONTOP 0x4B72 /* font operations */ + +//---------------------------------------------------------------------- +// From linux-2.6.9/include/linux/kb.h +//---------------------------------------------------------------------- + +typedef __vki_kernel_uid32_t vki_qid_t; /* Type in which we store ids in memory */ + +#endif + +//---------------------------------------------------------------------- +// From sys/ptrace.h +//---------------------------------------------------------------------- + +#define VKI_PTRACE_TRACEME 0 +#define VKI_PTRACE_READ_I 1 +#define VKI_PTRACE_READ_D 2 +/* 3 - read user struct */ +#define VKI_PTRACE_WRITE_I 4 +#define VKI_PTRACE_WRITE_D 5 +/* 6 - write user struct */ +#define VKI_PTRACE_CONTINUE 7 +#define VKI_PTRACE_KILL 8 +#define VKI_PTRACE_STEP 9 +#define VKI_PTRACE_ATTACH 10 +#define VKI_PTRACE_DETACH 11 +#define VKI_PTRACE_IO 12 +#define VKI_PTRACE_LWPINFO 13 +#define VKI_PTRACE_GETNUMLWPS 14 +#define VKI_PTRACE_GETLWPLIST 15 +#define VKI_PTRACE_CLEARSTEP 16 +#define VKI_PTRACE_SETSTEP 17 +#define VKI_PTRACE_SUSPEND 18 +#define VKI_PTRACE_RESUME 19 +#define VKI_PTRACE_TO_SCE 20 +#define VKI_PTRACE_TO_SCX 21 +#define VKI_PTRACE_SYSCALL 22 +/* md */ +#define VKI_PTRACE_GETREGS 33 +#define VKI_PTRACE_SETREGS 34 +#define VKI_PTRACE_GETFPREGS 35 +#define VKI_PTRACE_SETFPREGS 36 +#define VKI_PTRACE_GETDBREGS 37 +#define VKI_PTRACE_SETDBREGS 38 + +#define VKI_PTRACE_VM_TIMESTAMP 40 +#define VKI_PTRACE_VM_ENTRY 41 + +#define VKI_PTRACE_FIRSTMACH 64 + +struct vki_ptrace_io_desc { + int piod_op; + void * piod_offs; + void * piod_addr; + vki_size_t piod_len; +}; +#define VKI_PIOD_READ_D 1 +#define VKI_PIOD_WRITE_D 2 +#define VKI_PIOD_READ_I 3 +#define VKI_PIOD_WRITE_I 4 + +struct vki_ptrace_lwpinfo { + vki_lwpid_t pl_lwpid; + int pl_event; +#define VKI_PL_EVENT_NONE 0 +#define VKI_PL_EVENT_SIGNAL 1 + int pl_flags; +#define VKI_FLAG_SA 0x01 +#define VKI_FLAG_BOUND 0x02 + vki_sigset_t pl_sigmask; + vki_sigset_t pl_siglist; +}; + +struct vki_ptrace_vm_entry { + int pve_entry; /* Entry number used for iteration. */ + int pve_timestamp; /* Generation number of VM map. */ + unsigned long pve_start; /* Start VA of range. */ + unsigned long pve_end; /* End VA of range (incl). */ + unsigned long pve_offset; /* Offset in backing object. */ + unsigned int pve_prot; /* Protection of memory range. */ + unsigned int pve_pathlen; /* Size of path. */ + long pve_fileid; /* File ID. */ + vki_uint32_t pve_fsid; /* File system ID. */ + char *pve_path; /* Path name of object. */ +}; + +#endif // __VKI_FREEBSD_H + +//---------------------------------------------------------------------- +// From i386/include/sysarch.h and amd64/include/sysarch.h (interchangeable) +//---------------------------------------------------------------------- + +#define VKI_I386_GET_FSBASE 7 +#define VKI_I386_SET_FSBASE 8 +#define VKI_I386_GET_GSBASE 9 +#define VKI_I386_SET_GSBASE 10 +#define VKI_I386_GET_XFPUSTATE 11 + +#define VKI_AMD64_GET_FSBASE 128 +#define VKI_AMD64_SET_FSBASE 129 +#define VKI_AMD64_GET_GSBASE 130 +#define VKI_AMD64_SET_GSBASE 131 +#define VKI_AMD64_GET_XFPUSTATE 132 + +//---------------------------------------------------------------------- +// From sys/module.h +//---------------------------------------------------------------------- + +#define VKI_MAXMODNAME 32 + +typedef union vki_modspecific { + vki_int32_t intval; + vki_uint32_t u_intval; +#if defined(VGP_x86_freebsd) + vki_int32_t longval; + vki_uint32_t u_longval; +#elif defined(VGP_amd64_freebsd) + vki_int64_t longval; + vki_uint64_t u_longval; +#else +#error Unknown platform +#endif +} vki_modspecific_t; + +struct vki_module_stat { + int version; + char name[VKI_MAXMODNAME]; + int refs; + int id; + vki_modspecific_t data; +}; + +//---------------------------------------------------------------------- +// From sys/rtprio.h +//---------------------------------------------------------------------- + +struct vki_rtprio { + vki_uint16_t type; + vki_uint16_t prio; +}; + +#define VKI_RTP_LOOKUP 0 +#define VKI_RTP_SET 1 + +//---------------------------------------------------------------------- +// From sys/umtx.h +//---------------------------------------------------------------------- + +struct vki_umtx { + unsigned long u_owner; +}; + +struct vki_umutex { + vki_lwpid_t m_owner; + vki_uint32_t m_flags; + vki_uint32_t m_ceilings[2]; + vki_uint32_t m_spare[4]; +}; + +struct vki_ucond { + vki_uint32_t c_has_waiters; + vki_uint32_t c_flags; + vki_uint32_t c_spare[2]; +}; + +struct vki_urwlock { + vki_uint32_t rw_state; + vki_uint32_t rw_flags; + vki_uint32_t rw_blocked_readers; + vki_uint32_t rw_blocked_writers; + vki_uint32_t rw_spare[4]; +}; + +struct vki_usem { + vki_uint32_t has_waiters; + vki_uint32_t count; + vki_uint32_t flags; +}; + +struct vki_umtx_time { + struct vki_timespec timeout; + vki_uint32_t flags; + vki_uint32_t clockid; +}; + +#define VKI_UMTX_OP_LOCK 0 +#define VKI_UMTX_OP_UNLOCK 1 +#define VKI_UMTX_OP_WAIT 2 +#define VKI_UMTX_OP_WAKE 3 +#define VKI_UMTX_OP_MUTEX_TRYLOCK 4 +#define VKI_UMTX_OP_MUTEX_LOCK 5 +#define VKI_UMTX_OP_MUTEX_UNLOCK 6 +#define VKI_UMTX_OP_SET_CEILING 7 +#define VKI_UMTX_OP_CV_WAIT 8 +#define VKI_UMTX_OP_CV_SIGNAL 9 +#define VKI_UMTX_OP_CV_BROADCAST 10 +#define VKI_UMTX_OP_WAIT_UINT 11 +#define VKI_UMTX_OP_RW_RDLOCK 12 +#define VKI_UMTX_OP_RW_WRLOCK 13 +#define VKI_UMTX_OP_RW_UNLOCK 14 +#define VKI_UMTX_OP_WAIT_UINT_PRIVATE 15 +#define VKI_UMTX_OP_WAKE_PRIVATE 16 +#define VKI_UMTX_OP_MUTEX_WAIT 17 +#define VKI_UMTX_OP_MUTEX_WAKE 18 /* deprecated */ +#define VKI_UMTX_OP_SEM_WAIT 19 +#define VKI_UMTX_OP_SEM_WAKE 20 +#define VKI_UMTX_OP_NWAKE_PRIVATE 21 +#define VKI_UMTX_OP_MUTEX_WAKE2 22 +#define VKI_UMTX_OP_MAX 23 + + +//---------------------------------------------------------------------- +// From sys/acl.h +//---------------------------------------------------------------------- + +struct vki_acl_entry { + int ae_tag; + vki_uid_t ae_uid; + vki_mode_t ae_perm; +}; + +#define VKI_ACL_MAX_ENTRIES 32 +struct vki_acl { + int acl_cnt; + struct vki_acl_entry acl_entry[VKI_ACL_MAX_ENTRIES]; +}; + + +//---------------------------------------------------------------------- +// From sys/uuid.h +//---------------------------------------------------------------------- + +struct vki_uuid { + vki_uint32_t time_low; + vki_uint16_t time_mid; + vki_uint16_t time_hi_and_version; + vki_uint8_t clock_seq_hi_and_reserved; + vki_uint8_t clock_seq_low; + vki_uint8_t node[6]; +}; + +//---------------------------------------------------------------------- +// From sys/user.h +//---------------------------------------------------------------------- + +#define VKI_KVME_TYPE_NONE 0 +#define VKI_KVME_TYPE_DEFAULT 1 +#define VKI_KVME_TYPE_VNODE 2 +#define VKI_KVME_TYPE_SWAP 3 +#define VKI_KVME_TYPE_DEVICE 4 +#define VKI_KVME_TYPE_PHYS 5 +#define VKI_KVME_TYPE_DEAD 6 +#define VKI_KVME_TYPE_UNKNOWN 255 + +#define VKI_KVME_PROT_READ 0x00000001 +#define VKI_KVME_PROT_WRITE 0x00000002 +#define VKI_KVME_PROT_EXEC 0x00000004 + +#define VKI_KVME_FLAG_COW 0x00000001 +#define VKI_KVME_FLAG_NEEDS_COPY 0x00000002 + +struct vki_kinfo_vmentry { + int kve_structsize; + int kve_type; + ULong kve_start; + ULong kve_end; + Off64T kve_offset; + ULong kve_fileid; + UInt kve_fsid; + int kve_flags; + int kve_resident; + int kve_private_resident; + int kve_protection; + int kve_ref_count; + int kve_shadow_count; + int _kve_pad0; + int kve_ispare[16]; + char kve_path[VKI_PATH_MAX]; +}; + +struct vki_kinfo_file { + int kf_structsize; /* Variable size of record. */ + int kf_type; /* Descriptor type. */ + int kf_fd; /* Array index. */ + int kf_ref_count; /* Reference count. */ + int kf_flags; /* Flags. */ + int _kf_pad0; /* Round to 64 bit alignment */ + Off64T kf_offset; /* Seek location. */ + int kf_vnode_type; /* Vnode type. */ + int kf_sock_domain; /* Socket domain. */ + int kf_sock_type; /* Socket type. */ + int kf_sock_protocol; /* Socket protocol. */ + char kf_sa_local[128]; /* Socket address. */ + char kf_sa_peer[128]; /* Peer address. */ + int _kf_ispare[16]; /* Space for more stuff. */ + /* Truncated before copyout in sysctl */ + char kf_path[VKI_PATH_MAX]; /* Path to file, if any. */ +}; + +//---------------------------------------------------------------------- +// From sys/kenv.h +//---------------------------------------------------------------------- +#define VKI_KENV_GET 0 +#define VKI_KENV_SET 1 +#define VKI_KENV_UNSET 2 +#define VKI_KENV_DUMP 3 + +//---------------------------------------------------------------------- +// From sys/sysctl.h (and related) +//---------------------------------------------------------------------- + +#include +#include + +#define VKI_CTL_KERN CTL_KERN +#define VKI_CTL_HW CTL_HW +#define VKI_KERN_PROC KERN_PROC +#define VKI_KERN_PROC_VMMAP KERN_PROC_VMMAP +#define VKI_KERN_PROC_FILEDESC KERN_PROC_FILEDESC +#define VKI_HW_MACHINE HW_MACHINE + +//---------------------------------------------------------------------- +// From sys/thr.h +//---------------------------------------------------------------------- + +struct vki_thr_param { + void (*start_func)(void *); + void *arg; + char *stack_base; + vki_size_t stack_size; + char *tls_base; + vki_size_t tls_size; + long *child_tid; + long *parent_tid; + int flags; + struct vki_rtprio *rtp; + void *spare[3]; +}; + +//---------------------------------------------------------------------- +// From sys/linker.h +//---------------------------------------------------------------------- + +struct vki_kld_sym_lookup { + int version; /* set to sizeof(struct kld_sym_lookup) */ + char *symname; /* Symbol name we are looking up */ + unsigned long symvalue; + vki_size_t symsize; +}; + +#if !defined(VKI_INIT_ARCH_ELF_STATE) + /* This structure is used to preserve architecture specific data during + the loading of an ELF file, throughout the checking of architecture + specific ELF headers & through to the point where the ELF load is + known to be proceeding. This implementation is a dummy for + architectures which require no specific state. */ + struct vki_arch_elf_state { + }; + +# define VKI_INIT_ARCH_ELF_STATE { } + +#endif +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/vki/vki-machine-types-amd64-freebsd.h b/include/vki/vki-machine-types-amd64-freebsd.h new file mode 100755 index 000000000..5c6107d2c --- /dev/null +++ b/include/vki/vki-machine-types-amd64-freebsd.h @@ -0,0 +1,77 @@ + +/*--------------------------------------------------------------------*/ +/*--- x86/Linux-specific kernel interface: posix types. ---*/ +/*--- vki_posixtypes-x86-linux.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __VKI_MACHINE_TYPES_AMD64_FREEBSD_H +#define __VKI_MACHINE_TYPES_AMD64_FREEBSD_H + +//---------------------------------------------------------------------- +// From sys/i386/include/_types.h +//---------------------------------------------------------------------- + +typedef __signed char vki_int8_t; +typedef unsigned char vki_uint8_t; +typedef short vki_int16_t; +typedef unsigned short vki_uint16_t; +typedef int vki_int32_t; +typedef unsigned int vki_uint32_t; +typedef long vki_int64_t; +typedef unsigned long vki_uint64_t; +typedef unsigned long vki_uintptr_t; +typedef long vki_intptr_t; + + +typedef unsigned int __vki_clock_t; +typedef unsigned int __vki_cpumask_t; +typedef char * __vki_caddr_t; /* QQQ 32 on 64 */ +typedef double __vki_double_t; +typedef double __vki_float_t; +typedef vki_int64_t __vki_intfptr_t; +typedef vki_int64_t __vki_intmax_t; +typedef vki_int64_t __vki_ptrdiff_t; +typedef vki_int64_t __vki_register_t; +typedef vki_int64_t __vki_segsz_t; +typedef vki_uint64_t __vki_size_t; +typedef vki_int64_t __vki_ssize_t; +typedef vki_int64_t __vki_time_t; +typedef vki_uint64_t __vki_uintfptr_t; +typedef vki_uint64_t __vki_uintmax_t; +typedef vki_uint64_t __vki_u_register_t; +typedef vki_uint64_t __vki_vm_offset_t; +typedef vki_int64_t __vki_vm_ooffset_t; +typedef vki_uint64_t __vki_vm_paddr_t; /* QQQ int64 for PAE */ +typedef vki_uint64_t __vki_vm_pindex_t; +typedef vki_uint64_t __vki_vm_size_t; + +#endif // __VKI_MACHINE_TYPES_AMD64_FREEBSD_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/vki/vki-machine-types-x86-freebsd.h b/include/vki/vki-machine-types-x86-freebsd.h new file mode 100755 index 000000000..0f0320e81 --- /dev/null +++ b/include/vki/vki-machine-types-x86-freebsd.h @@ -0,0 +1,77 @@ + +/*--------------------------------------------------------------------*/ +/*--- x86/Linux-specific kernel interface: posix types. ---*/ +/*--- vki_posixtypes-x86-linux.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __VKI_MACHINE_TYPES_X86_FREEBSD_H +#define __VKI_MACHINE_TYPES_X86_FREEBSD_H + +//---------------------------------------------------------------------- +// From sys/i386/include/_types.h +//---------------------------------------------------------------------- + +typedef __signed char vki_int8_t; +typedef unsigned char vki_uint8_t; +typedef short vki_int16_t; +typedef unsigned short vki_uint16_t; +typedef int vki_int32_t; +typedef unsigned int vki_uint32_t; +typedef long long vki_int64_t; +typedef unsigned long long vki_uint64_t; +typedef unsigned int vki_uintptr_t; +typedef int vki_intptr_t; + + +typedef unsigned long __vki_clock_t; +typedef unsigned int __vki_cpumask_t; +typedef char * __vki_caddr_t; /* QQQ 32 on 64 */ +typedef double __vki_double_t; +typedef double __vki_float_t; +typedef vki_int32_t __vki_intfptr_t; +typedef vki_int64_t __vki_intmax_t; +typedef vki_int32_t __vki_ptrdiff_t; +typedef vki_int32_t __vki_register_t; +typedef vki_int32_t __vki_segsz_t; +typedef vki_uint32_t __vki_size_t; +typedef vki_int32_t __vki_ssize_t; +typedef vki_int32_t __vki_time_t; +typedef vki_uint32_t __vki_uintfptr_t; +typedef vki_uint64_t __vki_uintmax_t; +typedef vki_uint32_t __vki_u_register_t; +typedef vki_uint32_t __vki_vm_offset_t; +typedef vki_int64_t __vki_vm_ooffset_t; +typedef vki_uint32_t __vki_vm_paddr_t; /* QQQ int64 for PAE */ +typedef vki_uint64_t __vki_vm_pindex_t; +typedef vki_uint32_t __vki_vm_size_t; + +#endif // __VKI_MACHINE_TYPES_X86_FREEBSD_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/include/vki/vki-scnums-freebsd.h b/include/vki/vki-scnums-freebsd.h new file mode 100755 index 000000000..9f105e461 --- /dev/null +++ b/include/vki/vki-scnums-freebsd.h @@ -0,0 +1,415 @@ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __VKI_UNISTD_FREEBSD_H +#define __VKI_UNISTD_FREEBSD_H + +#define VG_FREEBSD_SYSCALL_STD 0 +#define VG_FREEBSD_SYSCALL0 1 +#define VG_FREEBSD_SYSCALL198 2 + +// From sys/syscall.h + +#define __NR_syscall 0 +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_wait4 7 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_chdir 12 +#define __NR_fchdir 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_getfsstat4 18 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_unmount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_geteuid 25 +#define __NR_ptrace 26 +#define __NR_recvmsg 27 +#define __NR_sendmsg 28 +#define __NR_recvfrom 29 +#define __NR_accept 30 +#define __NR_getpeername 31 +#define __NR_getsockname 32 +#define __NR_access 33 +#define __NR_chflags 34 +#define __NR_fchflags 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_getppid 39 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_getegid 43 +#define __NR_profil 44 +#define __NR_ktrace 45 +#define __NR_getgid 47 +#define __NR_getlogin 49 +#define __NR_setlogin 50 +#define __NR_acct 51 +#define __NR_sigaltstack 53 +#define __NR_ioctl 54 +#define __NR_reboot 55 +#define __NR_revoke 56 +#define __NR_symlink 57 +#define __NR_readlink 58 +#define __NR_execve 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_msync 65 +#define __NR_vfork 66 +#define __NR_sbrk 69 +#define __NR_sstk 70 +#define __NR_vadvise 72 +#define __NR_munmap 73 +#define __NR_mprotect 74 +#define __NR_madvise 75 +#define __NR_mincore 78 +#define __NR_getgroups 79 +#define __NR_setgroups 80 +#define __NR_getpgrp 81 +#define __NR_setpgid 82 +#define __NR_setitimer 83 +#define __NR_swapon 85 +#define __NR_getitimer 86 +#define __NR_getdtablesize 89 +#define __NR_dup2 90 +#define __NR_fcntl 92 +#define __NR_select 93 +#define __NR_fsync 95 +#define __NR_setpriority 96 +#define __NR_socket 97 +#define __NR_connect 98 +#define __NR_getpriority 100 +#define __NR_bind 104 +#define __NR_setsockopt 105 +#define __NR_listen 106 +#define __NR_gettimeofday 116 +#define __NR_getrusage 117 +#define __NR_getsockopt 118 +#define __NR_readv 120 +#define __NR_writev 121 +#define __NR_settimeofday 122 +#define __NR_fchown 123 +#define __NR_fchmod 124 +#define __NR_setreuid 126 +#define __NR_setregid 127 +#define __NR_rename 128 +#define __NR_flock 131 +#define __NR_mkfifo 132 +#define __NR_sendto 133 +#define __NR_shutdown 134 +#define __NR_socketpair 135 +#define __NR_mkdir 136 +#define __NR_rmdir 137 +#define __NR_utimes 138 +#define __NR_adjtime 140 +#define __NR_setsid 147 +#define __NR_quotactl 148 +#define __NR_nfssvc 155 +#define __NR_statfs 157 +#define __NR_fstatfs 158 +#define __NR_lgetfh 160 +#define __NR_getfh 161 +#define __NR_getdomainname 162 +#define __NR_setdomainname 163 +#define __NR_uname 164 +#define __NR_sysarch 165 +#define __NR_rtprio 166 +#define __NR_semsys 169 +#define __NR_msgsys 170 +#define __NR_shmsys 171 +#define __NR_pread6 173 +#define __NR_pwrite6 174 +#define __NR_ntp_adjtime 176 +#define __NR_setgid 181 +#define __NR_setegid 182 +#define __NR_seteuid 183 +#define __NR_stat 188 +#define __NR_fstat 189 +#define __NR_lstat 190 +#define __NR_pathconf 191 +#define __NR_fpathconf 192 +#define __NR_getrlimit 194 +#define __NR_setrlimit 195 +#define __NR_getdirentries 196 +#define __NR_mmap6 197 +#define __NR___syscall 198 +#define __NR_lseek6 199 +#define __NR_truncate 200 +#define __NR_ftruncate 201 +#define __NR___sysctl 202 +#define __NR_mlock 203 +#define __NR_munlock 204 +#define __NR_undelete 205 +#define __NR_futimes 206 +#define __NR_getpgid 207 +#define __NR_poll 209 +#define __NR_lkmnosys0 210 +#define __NR_lkmnosys1 211 +#define __NR_lkmnosys2 212 +#define __NR_lkmnosys3 213 +#define __NR_lkmnosys4 214 +#define __NR_lkmnosys5 215 +#define __NR_lkmnosys6 216 +#define __NR_lkmnosys7 217 +#define __NR_lkmnosys8 218 +#define __NR_nfs_fhopen 219 +#define __NR___semctl7 220 +#define __NR_semget 221 +#define __NR_semop 222 +#define __NR_msgctl 224 +#define __NR_msgget 225 +#define __NR_msgsnd 226 +#define __NR_msgrcv 227 +#define __NR_shmat 228 +#define __NR_shmctl7 229 +#define __NR_shmdt 230 +#define __NR_shmget 231 +#define __NR_clock_gettime 232 +#define __NR_clock_settime 233 +#define __NR_clock_getres 234 +#define __NR_nanosleep 240 +#define __NR_minherit 250 +#define __NR_rfork 251 +#define __NR_openbsd_poll 252 +#define __NR_issetugid 253 +#define __NR_lchown 254 +#define __NR_getdents 272 +#define __NR_lchmod 274 +#define __NR_netbsd_lchown 275 +#define __NR_lutimes 276 +#define __NR_netbsd_msync 277 +#define __NR_nstat 278 +#define __NR_nfstat 279 +#define __NR_nlstat 280 +#define __NR_fhstatfs 297 +#define __NR_fhopen 298 +#define __NR_fhstat 299 +#define __NR_modnext 300 +#define __NR_modstat 301 +#define __NR_modfnext 302 +#define __NR_modfind 303 +#define __NR_kldload 304 +#define __NR_kldunload 305 +#define __NR_kldfind 306 +#define __NR_kldnext 307 +#define __NR_kldstat 308 +#define __NR_kldfirstmod 309 +#define __NR_getsid 310 +#define __NR_setresuid 311 +#define __NR_setresgid 312 +#define __NR_aio_return 314 +#define __NR_aio_suspend 315 +#define __NR_aio_cancel 316 +#define __NR_aio_error 317 +#define __NR_aio_read 318 +#define __NR_aio_write 319 +#define __NR_lio_listio 320 +#define __NR_yield 321 +#define __NR_mlockall 324 +#define __NR_munlockall 325 +#define __NR___getcwd 326 +#define __NR_sched_setparam 327 +#define __NR_sched_getparam 328 +#define __NR_sched_setscheduler 329 +#define __NR_sched_getscheduler 330 +#define __NR_sched_yield 331 +#define __NR_sched_get_priority_max 332 +#define __NR_sched_get_priority_min 333 +#define __NR_sched_rr_get_interval 334 +#define __NR_utrace 335 +#define __NR_kldsym 337 +#define __NR_jail 338 +#define __NR_sigprocmask 340 +#define __NR_sigsuspend 341 +#define __NR_sigaction4 342 +#define __NR_sigpending 343 +#define __NR_sigreturn4 344 +#define __NR_sigtimedwait 345 +#define __NR_sigwaitinfo 346 +#define __NR___acl_get_file 347 +#define __NR___acl_set_file 348 +#define __NR___acl_get_fd 349 +#define __NR___acl_set_fd 350 +#define __NR___acl_delete_file 351 +#define __NR___acl_delete_fd 352 +#define __NR___acl_aclcheck_file 353 +#define __NR___acl_aclcheck_fd 354 +#define __NR_extattrctl 355 +#define __NR_extattr_set_file 356 +#define __NR_extattr_get_file 357 +#define __NR_extattr_delete_file 358 +#define __NR_aio_waitcomplete 359 +#define __NR_getresuid 360 +#define __NR_getresgid 361 +#define __NR_kqueue 362 +#define __NR_kevent 363 +#define __NR_extattr_set_fd 371 +#define __NR_extattr_get_fd 372 +#define __NR_extattr_delete_fd 373 +#define __NR___setugid 374 +#define __NR_nfsclnt 375 +#define __NR_eaccess 376 +#define __NR_nmount 378 +#define __NR_kse_exit 379 +#define __NR_kse_wakeup 380 +#define __NR_kse_create 381 +#define __NR_kse_thr_interrupt 382 +#define __NR_kse_release 383 +#define __NR___mac_get_proc 384 +#define __NR___mac_set_proc 385 +#define __NR___mac_get_fd 386 +#define __NR___mac_get_file 387 +#define __NR___mac_set_fd 388 +#define __NR___mac_set_file 389 +#define __NR_kenv 390 +#define __NR_lchflags 391 +#define __NR_uuidgen 392 +#define __NR_sendfile 393 +#define __NR_mac_syscall 394 +#define __NR_getfsstat 395 +#define __NR_statfs6 396 +#define __NR_fstatfs6 397 +#define __NR_fhstatfs6 398 +#define __NR_ksem_close 400 +#define __NR_ksem_post 401 +#define __NR_ksem_wait 402 +#define __NR_ksem_trywait 403 +#define __NR_ksem_init 404 +#define __NR_ksem_open 405 +#define __NR_ksem_unlink 406 +#define __NR_ksem_getvalue 407 +#define __NR_ksem_destroy 408 +#define __NR___mac_get_pid 409 +#define __NR___mac_get_link 410 +#define __NR___mac_set_link 411 +#define __NR_extattr_set_link 412 +#define __NR_extattr_get_link 413 +#define __NR_extattr_delete_link 414 +#define __NR___mac_execve 415 +#define __NR_sigaction 416 +#define __NR_sigreturn 417 +#define __NR_getcontext 421 +#define __NR_setcontext 422 +#define __NR_swapcontext 423 +#define __NR_swapoff 424 +#define __NR___acl_get_link 425 +#define __NR___acl_set_link 426 +#define __NR___acl_delete_link 427 +#define __NR___acl_aclcheck_link 428 +#define __NR_sigwait 429 +#define __NR_thr_create 430 +#define __NR_thr_exit 431 +#define __NR_thr_self 432 +#define __NR_thr_kill 433 +#define __NR__umtx_lock 434 +#define __NR__umtx_unlock 435 +#define __NR_jail_attach 436 +#define __NR_extattr_list_fd 437 +#define __NR_extattr_list_file 438 +#define __NR_extattr_list_link 439 +#define __NR_kse_switchin 440 +#define __NR_ksem_timedwait 441 +#define __NR_thr_suspend 442 +#define __NR_thr_wake 443 +#define __NR_kldunloadf 444 +#define __NR_audit 445 +#define __NR_auditon 446 +#define __NR_getauid 447 +#define __NR_setauid 448 +#define __NR_getaudit 449 +#define __NR_setaudit 450 +#define __NR_getaudit_addr 451 +#define __NR_setaudit_addr 452 +#define __NR_auditctl 453 +#define __NR__umtx_op 454 +#define __NR_thr_new 455 +#define __NR_sigqueue 456 +#define __NR_kmq_open 457 +#define __NR_kmq_setattr 458 +#define __NR_kmq_timedreceive 459 +#define __NR_kmq_timedsend 460 +#define __NR_kmq_notify 461 +#define __NR_kmq_unlink 462 +#define __NR_abort2 463 +#define __NR_thr_set_name 464 +#define __NR_aio_fsync 465 +#define __NR_rtprio_thread 466 +#define __NR_nosys467 467 +#define __NR_nosys468 468 +#define __NR___getpath_fromfd 469 +#define __NR___getpath_fromaddr 470 +#define __NR_sctp_peeloff 471 +#define __NR_sctp_generic_sendmsg 472 +#define __NR_sctp_generic_sendmsg_iov 473 +#define __NR_sctp_generic_recvmsg 474 +#define __NR_pread 475 +#define __NR_pwrite 476 +#define __NR_mmap 477 +#define __NR_lseek 478 +#define __NR_truncate7 479 +#define __NR_ftruncate7 480 +#define __NR_thr_kill2 481 +#define __NR_shm_open 482 +#define __NR_shm_unlink 483 +#define __NR_cpuset 484 +#define __NR_cpuset_setid 485 +#define __NR_cpuset_getid 486 +#define __NR_cpuset_getaffinity 487 +#define __NR_cpuset_setaffinity 488 +#define __NR_faccessat 489 +#define __NR_fchmodat 490 +#define __NR_fchownat 491 +#define __NR_fexecve 492 +#define __NR_fstatat 493 +#define __NR_futimesat 494 +#define __NR_linkat 495 +#define __NR_mkdirat 496 +#define __NR_mkfifoat 497 +#define __NR_mknodat 498 +#define __NR_openat 499 +#define __NR_readlinkat 500 +#define __NR_renameat 501 +#define __NR_symlinkat 502 +#define __NR_unlinkat 503 +#define __NR_posix_openpt 504 +#define __NR___semctl 510 +#define __NR_shmctl 512 +#define __NR_pselect 522 +#define __NR_pipe2 542 + +#define __NR_fake_sigreturn 1000 + +#endif /* __VKI_UNISTD_FREEBSD_H */ diff --git a/include/vki/vki-x86-freebsd.h b/include/vki/vki-x86-freebsd.h new file mode 100755 index 000000000..012f8f0be --- /dev/null +++ b/include/vki/vki-x86-freebsd.h @@ -0,0 +1,269 @@ + +/*--------------------------------------------------------------------*/ +/*--- x86/FreeBSD-specific kernel interface. vki-x86-freebsd.h ---*/ +/*--------------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2009 Stanislav Sedov + Copyright (C) 2000-2005 Julian Seward + jseward@acm.org + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307, USA. + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __VKI_X86_FREEBSD_H +#define __VKI_X86_FREEBSD_H + +//---------------------------------------------------------------------- +// From somewhere +//---------------------------------------------------------------------- + +/* PAGE_SHIFT determines the page size */ +#define VKI_PAGE_SHIFT 12 +#define VKI_PAGE_SIZE (1UL << VKI_PAGE_SHIFT) +#define VKI_MAX_PAGE_SHIFT VKI_PAGE_SHIFT +#define VKI_MAX_PAGE_SIZE VKI_PAGE_SIZE + +//---------------------------------------------------------------------- +// From sys/i386/include/_limits.h and sys/sys/_sigset.h +//---------------------------------------------------------------------- + +#define VKI_MINSIGSTKSZ (512 * 4) + +#define _VKI_NSIG 128 +#define _VKI_NSIG_WORDS 4 +#define _VKI_NSIG_BPW ((_VKI_NSIG) / (_VKI_NSIG_WORDS)) + +typedef struct { + vki_uint32_t sig[_VKI_NSIG_WORDS]; +} vki_sigset_t; + + +//---------------------------------------------------------------------- +// From sys/i386/include/npx.h +//---------------------------------------------------------------------- + +struct _vki_env87 { + long en_cw; + long en_sw; + long en_tw; + long en_fip; + unsigned short en_fcs; + unsigned short en_opcode; + long en_foo; + long en_fos; +}; + +struct _vki_fpacc87 { + unsigned char fp_bytes[10]; +}; + +struct _vki_save87 { + struct _vki_env87 sv_env; + struct _vki_fpacc87 sv_ac[8]; + unsigned char sv_pad0[4]; + unsigned char sv_pad[64]; +}; + +struct _vki_xmmacc { + unsigned char xmm_bytes[16]; +}; + +struct _vki_envxmm { + unsigned short en_cw; + unsigned short en_sw; + unsigned short en_tw; + unsigned short en_opcode; + unsigned int en_fip; + unsigned short en_fcs; + unsigned short en_pad0; + unsigned int en_foo; + unsigned short en_fos; + unsigned short en_pad1; + unsigned int en_mxcsr; + unsigned int en_mxcsr_mask; +}; + +struct _vki_savexmm { + struct _vki_envxmm sv_env; + struct { + struct _vki_fpacc87 fp_acc; + unsigned char fp_pad[6]; + } sv_fp[8]; + struct _vki_xmmacc sv_xmm[8]; + unsigned char sv_pad[224]; +}; + +struct _vki_fpstate { + union { + struct _vki_save87 sv_87; + struct _vki_savexmm sv_xmm; + }; +}; + +struct vki_sigcontext { + vki_sigset_t sc_mask; + int onstack; + int gs; + int fs; + int es; + int ds; + int edi; + int esi; + int ebp; + int isp; + int ebx; + int edx; + int ecx; + int eax; + int trapno; + int err; + int eip; + int cs; + int eflags; + int esp; + int ss; + int len; + int fpformat; + int ownedfp; + int spare1[1]; + struct _vki_fpstate fpstate __attribute__((aligned(16))); + int fsbase; + int gsbase; + int spare2[6]; +}; + +struct vki_user_regs_struct { + unsigned int fs; + unsigned int es; + unsigned int ds; + unsigned int edi; + unsigned int esi; + unsigned int ebp; + unsigned int isp; + unsigned int ebx; + unsigned int edx; + unsigned int ecx; + unsigned int eax; + unsigned int trapno; + unsigned int err; + unsigned int eip; + unsigned int cs; + unsigned int eflags; + unsigned int esp; + unsigned int ss; + unsigned int gs; +}; + +struct vki_reg_struct { + unsigned int r_fs; + unsigned int r_es; + unsigned int r_ds; + unsigned int r_edi; + unsigned int r_esi; + unsigned int r_ebp; + unsigned int r_isp; + unsigned int r_ebx; + unsigned int r_edx; + unsigned int r_ecx; + unsigned int r_eax; + unsigned int r_trapno; + unsigned int r_err; + unsigned int r_eip; + unsigned int r_cs; + unsigned int r_eflags; + unsigned int r_esp; + unsigned int r_ss; + unsigned int r_gs; +}; + +struct vki_fpreg { + unsigned long fpr_env[7]; + unsigned char fpr_acc[8][10]; + unsigned long fpr_ex_sw; + unsigned char fpr_pad[64]; +}; + +struct vki_dbreg { + unsigned int dr[8]; +}; + +typedef unsigned int vki_elf_greg_t; +typedef struct _vki_fpstate vki_elf_fpregset_t; +typedef struct _vki_fpstate vki_elf_fpxregset_t; + +#define VKI_AT_SYSINFO 32 +#define VKI_ELF_NGREG (sizeof (struct vki_user_regs_struct) / sizeof(vki_elf_greg_t)) +typedef vki_elf_greg_t vki_elf_gregset_t[VKI_ELF_NGREG]; + +#define VKI_FPFMT_NODEV 0x10000 +#define VKI_FPFMT_387 0x10001 +#define VKI_FPFMT_XMM 0x10002 + +#define VKI_FPOWNED_NONE 0x20000 +#define VKI_FPOWNED_FPU 0x20001 +#define VKI_FPOWNED_PCB 0x20002 + +struct vki_mcontext { + int onstack; + int gs; + int fs; + int es; + int ds; + int edi; + int esi; + int ebp; + int isp; + int ebx; + int edx; + int ecx; + int eax; + int trapno; + int err; + int eip; + int cs; + int eflags; + int esp; + int ss; + + int len; + int fpformat; + int ownedfp; + int spare1[1]; + struct _vki_fpstate fpstate __attribute__((aligned(16))); + int fsbase; + int gsbase; + int spare2[6]; +}; + +struct vki_sigaction_base { + void (*ksa_handler)(int); + int sa_flags; + vki_sigset_t sa_mask; /* mask last for extensibility */ +}; +typedef struct vki_sigaction_base vki_sigaction_toK_t; +typedef struct vki_sigaction_base vki_sigaction_fromK_t; + +#endif // __VKI_X86_FREEBSD_H + +/*--------------------------------------------------------------------*/ +/*--- end ---*/ +/*--------------------------------------------------------------------*/ diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index 70b8adaf6..e069193b5 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -141,8 +141,8 @@ EXTRA_DIST = \ execve1.stderr.exp execve1.vgtest execve1.stderr.exp-kfail \ execve2.stderr.exp execve2.vgtest execve2.stderr.exp-kfail \ file_locking.stderr.exp file_locking.vgtest \ - fprw.stderr.exp fprw.stderr.exp-mips32-be fprw.stderr.exp-mips32-le \ - fprw.vgtest \ + fprw.stderr.exp fprw.stderr.exp-freebsd fprw.stderr.exp-mips32-be \ + fprw.stderr.exp-mips32-le fprw.vgtest \ fwrite.stderr.exp fwrite.vgtest fwrite.stderr.exp-kfail \ gone_abrt_xml.vgtest gone_abrt_xml.stderr.exp gone_abrt_xml.stderr.exp-solaris \ holey_buffer_too_small.vgtest holey_buffer_too_small.stdout.exp \ @@ -223,6 +223,7 @@ EXTRA_DIST = \ origin5-bz2.stderr.exp-glibc27-ppc64 \ origin5-bz2.stderr.exp-glibc212-s390x \ origin5-bz2.stderr.exp-glibc234-s390x \ + origin5-bz2.stderr.exp-freebsd \ origin5-bz2.stderr.exp-glibc218-mips32 \ origin6-fp.vgtest origin6-fp.stdout.exp \ origin6-fp.stderr.exp-glibc25-amd64 \ @@ -257,11 +258,12 @@ EXTRA_DIST = \ sbfragment.stdout.exp sbfragment.stderr.exp sbfragment.vgtest \ sem.stderr.exp sem.vgtest \ sendmsg.stderr.exp sendmsg.stderr.exp-solaris sendmsg.vgtest \ + sendmsg.stderr.exp-freebsd \ sh-mem.stderr.exp sh-mem.vgtest \ sh-mem-random.stderr.exp sh-mem-random.stdout.exp64 \ sh-mem-random.stdout.exp sh-mem-random.vgtest \ sigaltstack.stderr.exp sigaltstack.vgtest \ - sigkill.stderr.exp sigkill.stderr.exp-darwin sigkill.stderr.exp-mips32 \ + sigkill.stderr.exp sigkill.stderr.exp-darwin sigkill.stderr.exp-freebsd sigkill.stderr.exp-mips32 \ sigkill.stderr.exp-solaris \ sigkill.stderr.exp-glibc-2.28 sigkill.vgtest \ signal2.stderr.exp signal2.stdout.exp signal2.vgtest \ @@ -286,9 +288,10 @@ EXTRA_DIST = \ suppvarinfo5.stderr.exp suppvarinfo5.supp suppvarinfo5.vgtest \ test-plo-no.vgtest test-plo-no.stdout.exp \ test-plo-no.stderr.exp-le64 test-plo-no.stderr.exp-le32 \ + test-plo-no.stderr.exp-le32-freebsd test-plo-no.stderr.exp-le64-freebsd \ + test-plo-no.stderr.exp-s390x-mvc \ test-plo-yes.vgtest test-plo-yes.stdout.exp \ test-plo-yes.stderr.exp-le64 test-plo-yes.stderr.exp-le32 \ - test-plo-no.stderr.exp-s390x-mvc \ thread_alloca.stderr.exp thread_alloca.vgtest \ threadname.vgtest threadname.stderr.exp \ threadname_xml.vgtest threadname_xml.stderr.exp \ diff --git a/memcheck/tests/addressable.c b/memcheck/tests/addressable.c index 5f3c2e182..568fbb45e 100644 --- a/memcheck/tests/addressable.c +++ b/memcheck/tests/addressable.c @@ -9,6 +9,9 @@ #include #include #include +#if defined(VGO_freebsd) +#include +#endif static int pgsz; diff --git a/memcheck/tests/addressable.stderr.exp b/memcheck/tests/addressable.stderr.exp index 4c121987d..533d6e9bb 100644 --- a/memcheck/tests/addressable.stderr.exp +++ b/memcheck/tests/addressable.stderr.exp @@ -9,20 +9,20 @@ For a detailed leak analysis, rerun with: --leak-check=full For lists of detected and suppressed errors, rerun with: -s ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) Unaddressable byte(s) found during client check request - at 0x........: test2 (addressable.c:48) - by 0x........: main (addressable.c:125) + at 0x........: test2 (addressable.c:51) + by 0x........: main (addressable.c:128) Address 0x........ is not stack'd, malloc'd or (recently) free'd Invalid write of size 1 - at 0x........: test2 (addressable.c:51) - by 0x........: main (addressable.c:125) + at 0x........: test2 (addressable.c:54) + by 0x........: main (addressable.c:128) Address 0x........ is not stack'd, malloc'd or (recently) free'd Process terminating with default action of signal N (SIGSEGV or SIGBUS) Bad memory (SIGSEGV or SIGBUS) at address 0x........ - at 0x........: test2 (addressable.c:51) - by 0x........: main (addressable.c:125) + at 0x........: test2 (addressable.c:54) + by 0x........: main (addressable.c:128) If you believe this happened as a result of a stack overflow in your program's main thread (unlikely but possible), you can try to increase the size of the @@ -49,8 +49,8 @@ ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) Process terminating with default action of signal N (SIGSEGV or SIGBUS) Bad memory (SIGSEGV or SIGBUS) at address 0x........ - at 0x........: test4 (addressable.c:74) - by 0x........: main (addressable.c:125) + at 0x........: test4 (addressable.c:77) + by 0x........: main (addressable.c:128) HEAP SUMMARY: in use at exit: ... bytes in ... blocks @@ -61,13 +61,13 @@ For a detailed leak analysis, rerun with: --leak-check=full For lists of detected and suppressed errors, rerun with: -s ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) Uninitialised byte(s) found during client check request - at 0x........: test5 (addressable.c:85) - by 0x........: main (addressable.c:125) + at 0x........: test5 (addressable.c:88) + by 0x........: main (addressable.c:128) Address 0x........ is in a rw- anonymous segment Uninitialised byte(s) found during client check request - at 0x........: test5 (addressable.c:91) - by 0x........: main (addressable.c:125) + at 0x........: test5 (addressable.c:94) + by 0x........: main (addressable.c:128) Address 0x........ is in a r-- anonymous segment diff --git a/memcheck/tests/amd64/Makefile.am b/memcheck/tests/amd64/Makefile.am index da15cf797..bc3110fe9 100644 --- a/memcheck/tests/amd64/Makefile.am +++ b/memcheck/tests/amd64/Makefile.am @@ -33,7 +33,7 @@ EXTRA_DIST = \ shr_edx.stderr.exp shr_edx.stdout.exp shr_edx.vgtest \ sse_memory.stderr.exp sse_memory.stdout.exp sse_memory.vgtest \ xor-undef-amd64.stderr.exp xor-undef-amd64.stdout.exp \ - xor-undef-amd64.vgtest \ + xor-undef-amd64.stderr.exp-freebsd xor-undef-amd64.vgtest \ xsave-avx.vgtest xsave-avx.stdout.exp xsave-avx.stderr.exp check_PROGRAMS = \ diff --git a/memcheck/tests/amd64/xor-undef-amd64.stderr.exp-freebsd b/memcheck/tests/amd64/xor-undef-amd64.stderr.exp-freebsd new file mode 100755 index 000000000..0bfff2709 --- /dev/null +++ b/memcheck/tests/amd64/xor-undef-amd64.stderr.exp-freebsd @@ -0,0 +1,26 @@ + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (xor-undef-amd64.c:17) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (xor-undef-amd64.c:38) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (xor-undef-amd64.c:65) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (xor-undef-amd64.c:92) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (xor-undef-amd64.c:117) + + +HEAP SUMMARY: + in use at exit: 4,096 bytes in 1 blocks + total heap usage: 2 allocs, 1 frees, 4,144 bytes allocated + +For a detailed leak analysis, rerun with: --leak-check=full + +For counts of detected and suppressed errors, rerun with: -v +Use --track-origins=yes to see where uninitialised values come from +ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0) diff --git a/memcheck/tests/badjump2.c b/memcheck/tests/badjump2.c index 2085a30d9..039c1398d 100644 --- a/memcheck/tests/badjump2.c +++ b/memcheck/tests/badjump2.c @@ -24,7 +24,7 @@ int main(void) /* Install own SIGSEGV handler */ sigsegv_new.sa_handler = SIGSEGV_handler; sigsegv_new.sa_flags = 0; -#if !defined(__APPLE__) && !defined(__sun) +#if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) sigsegv_new.sa_restorer = NULL; #endif res = sigemptyset( &sigsegv_new.sa_mask ); diff --git a/memcheck/tests/fprw.stderr.exp-freebsd b/memcheck/tests/fprw.stderr.exp-freebsd new file mode 100755 index 000000000..af40ded39 --- /dev/null +++ b/memcheck/tests/fprw.stderr.exp-freebsd @@ -0,0 +1,41 @@ +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (fprw.c:16) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (fprw.c:17) + +Invalid read of size 8 + at 0x........: main (fprw.c:20) + Address 0x........ is 0 bytes inside a block of size 8 free'd + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:18) + +Invalid write of size 8 + at 0x........: main (fprw.c:20) + Address 0x........ is 0 bytes inside a block of size 8 free'd + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:18) + +Invalid read of size 4 + at 0x........: main (fprw.c:21) + Address 0x........ is 0 bytes inside a block of size 4 free'd + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:19) + +Invalid write of size 4 + at 0x........: main (fprw.c:21) + Address 0x........ is 0 bytes inside a block of size 4 free'd + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:19) + +Invalid free() / delete / delete[] / realloc() + at 0x........: free (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:22) + Address 0x........ is in the PLT segment of /lib/libc.so.7 + +Invalid write of size 8 + at 0x........: main (fprw.c:24) + Address 0x........ is 0 bytes inside a block of size 4 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: main (fprw.c:23) + diff --git a/memcheck/tests/memalign2.c b/memcheck/tests/memalign2.c index 95d13354e..116dcd826 100644 --- a/memcheck/tests/memalign2.c +++ b/memcheck/tests/memalign2.c @@ -30,6 +30,7 @@ int main ( void ) int res; assert(sizeof(long int) == sizeof(void*)); +#if !defined(__FreeBSD__) // Check behaviour of memalign/free for big alignment. // In particular, the below aims at checking that a // superblock with a big size is not marked as reclaimable @@ -78,9 +79,11 @@ int main ( void ) p = memalign(4 * 1024 * 1024, 100); assert(0 == (long)p % (4 * 1024 * 1024)); p = memalign(16 * 1024 * 1024, 100); assert(0 == (long)p % (16 * 1024 * 1024)); +#endif # define PM(a,b,c) posix_memalign((void**)a, b, c) +#if !defined(__FreeBSD__) || __FreeBSD__ >= 6 res = PM(&p, -1,100); assert(EINVAL == res); res = PM(&p, 0, 100); assert(EINVAL == res); res = PM(&p, 1, 100); assert(EINVAL == res); @@ -101,6 +104,7 @@ int main ( void ) && 0 == (long)p % (4 * 1024 * 1024)); res = PM(&p, 16 * 1024 * 1024, 100); assert(0 == res && 0 == (long)p % (16 * 1024 * 1024)); +#endif # endif return 0; diff --git a/memcheck/tests/origin5-bz2.stderr.exp-freebsd b/memcheck/tests/origin5-bz2.stderr.exp-freebsd new file mode 100755 index 000000000..cfa187fbb --- /dev/null +++ b/memcheck/tests/origin5-bz2.stderr.exp-freebsd @@ -0,0 +1,131 @@ +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (origin5-bz2.c:6481) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: copy_input_until_stop (origin5-bz2.c:4686) + by 0x........: handle_compress (origin5-bz2.c:4750) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: copy_input_until_stop (origin5-bz2.c:4686) + by 0x........: handle_compress (origin5-bz2.c:4750) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: copy_input_until_stop (origin5-bz2.c:4686) + by 0x........: handle_compress (origin5-bz2.c:4750) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2820) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2823) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2854) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2858) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2963) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: mainSort (origin5-bz2.c:2964) + by 0x........: BZ2_blockSort (origin5-bz2.c:3105) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: fallbackSort (origin5-bz2.c:2269) + by 0x........: BZ2_blockSort (origin5-bz2.c:3116) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Use of uninitialised value of size 8 + at 0x........: fallbackSort (origin5-bz2.c:2275) + by 0x........: BZ2_blockSort (origin5-bz2.c:3116) + by 0x........: BZ2_compressBlock (origin5-bz2.c:4034) + by 0x........: handle_compress (origin5-bz2.c:4753) + by 0x........: BZ2_bzCompress (origin5-bz2.c:4822) + by 0x........: BZ2_bzBuffToBuffCompress (origin5-bz2.c:5630) + by 0x........: main (origin5-bz2.c:6484) + Uninitialised value was created by a client request + at 0x........: main (origin5-bz2.c:6479) + +Conditional jump or move depends on uninitialised value(s) + at 0x........: main (origin5-bz2.c:6512) + Uninitialised value was created by a heap allocation + at 0x........: malloc (vg_replace_malloc.c:...) + by 0x........: g_serviceFn (origin5-bz2.c:6429) + by 0x........: default_bzalloc (origin5-bz2.c:4470) + by 0x........: BZ2_decompress (origin5-bz2.c:1578) + by 0x........: BZ2_bzDecompress (origin5-bz2.c:5192) + by 0x........: BZ2_bzBuffToBuffDecompress (origin5-bz2.c:5678) + by 0x........: main (origin5-bz2.c:6498) + diff --git a/memcheck/tests/sendmsg.stderr.exp-freebsd b/memcheck/tests/sendmsg.stderr.exp-freebsd new file mode 100755 index 000000000..7f2e8ecdb --- /dev/null +++ b/memcheck/tests/sendmsg.stderr.exp-freebsd @@ -0,0 +1,19 @@ +Syscall param socketcall.connect(serv_addr..sa_len) points to uninitialised byte(s) + ... + by 0x........: main (sendmsg.c:29) + Address 0x........ is on thread 1's stack + in frame #1, created by main (sendmsg.c:13) + +Syscall param sendmsg(sendmsg) points to uninitialised byte(s) + at 0x........: __sys_sendmsg (in /...libc...) + by 0x........: main (sendmsg.c:46) + Address 0x........ is on thread 1's stack + in frame #1, created by main (sendmsg.c:13) + +Syscall param socketcall.connect(serv_addr..sa_len) points to uninitialised byte(s) + ... + by 0x........: main (sendmsg.c:59) + Address 0x........ is on thread 1's stack + in frame #1, created by main (sendmsg.c:13) + +sendmsg: 6 diff --git a/memcheck/tests/sigkill.stderr.exp-freebsd b/memcheck/tests/sigkill.stderr.exp-freebsd new file mode 100755 index 000000000..4a2203812 --- /dev/null +++ b/memcheck/tests/sigkill.stderr.exp-freebsd @@ -0,0 +1,197 @@ + +setting signal 1: Success +getting signal 1: Success + +setting signal 2: Success +getting signal 2: Success + +setting signal 3: Success +getting signal 3: Success + +setting signal 4: Success +getting signal 4: Success + +setting signal 5: Success +getting signal 5: Success + +setting signal 6: Success +getting signal 6: Success + +setting signal 7: Success +getting signal 7: Success + +setting signal 8: Success +getting signal 8: Success + +setting signal 9: Warning: ignored attempt to set SIGKILL handler in sigaction(); + the SIGKILL signal is uncatchable +Invalid argument +getting signal 9: Success + +setting signal 10: Success +getting signal 10: Success + +setting signal 11: Success +getting signal 11: Success + +setting signal 12: Success +getting signal 12: Success + +setting signal 13: Success +getting signal 13: Success + +setting signal 14: Success +getting signal 14: Success + +setting signal 15: Success +getting signal 15: Success + +setting signal 16: Success +getting signal 16: Success + +setting signal 17: Warning: ignored attempt to set SIGSTOP handler in sigaction(); + the SIGSTOP signal is uncatchable +Invalid argument +getting signal 17: Success + +setting signal 18: Success +getting signal 18: Success + +setting signal 19: Success +getting signal 19: Success + +setting signal 20: Success +getting signal 20: Success + +setting signal 21: Success +getting signal 21: Success + +setting signal 22: Success +getting signal 22: Success + +setting signal 23: 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: Success +getting signal 31: Success + +setting signal 34: Success +getting signal 34: Success + +setting signal 35: Success +getting signal 35: Success + +setting signal 36: Success +getting signal 36: Success + +setting signal 37: Success +getting signal 37: Success + +setting signal 38: Success +getting signal 38: Success + +setting signal 39: Success +getting signal 39: Success + +setting signal 40: Success +getting signal 40: Success + +setting signal 41: Success +getting signal 41: Success + +setting signal 42: Success +getting signal 42: Success + +setting signal 43: Success +getting signal 43: Success + +setting signal 44: Success +getting signal 44: Success + +setting signal 45: Success +getting signal 45: Success + +setting signal 46: Success +getting signal 46: Success + +setting signal 47: Success +getting signal 47: Success + +setting signal 48: Success +getting signal 48: Success + +setting signal 49: Success +getting signal 49: Success + +setting signal 50: Success +getting signal 50: Success + +setting signal 51: Success +getting signal 51: Success + +setting signal 52: Success +getting signal 52: Success + +setting signal 53: Success +getting signal 53: Success + +setting signal 54: Success +getting signal 54: Success + +setting signal 55: Success +getting signal 55: Success + +setting signal 56: Success +getting signal 56: Success + +setting signal 57: Success +getting signal 57: Success + +setting signal 58: Success +getting signal 58: Success + +setting signal 59: Success +getting signal 59: Success + +setting signal 60: Success +getting signal 60: Success + +setting signal 61: Success +getting signal 61: Success + +setting signal 62: Success +getting signal 62: Success + +setting signal 65: Success +getting signal 65: Success + + +HEAP SUMMARY: + in use at exit: ... bytes in ... blocks + total heap usage: ... allocs, ... frees, ... bytes allocated + +For a detailed leak analysis, rerun with: --leak-check=full + +For counts of detected and suppressed errors, rerun with: -v +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/memcheck/tests/str_tester.c b/memcheck/tests/str_tester.c index 8a49428c8..7c2ff1e62 100644 --- a/memcheck/tests/str_tester.c +++ b/memcheck/tests/str_tester.c @@ -265,7 +265,7 @@ test_stpcpy (void) } // DDD: better done by testing for the function. -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) static void test_stpncpy (void) { @@ -467,7 +467,7 @@ test_strchr (void) } // DDD: better done by testing for the function. -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) static void test_strchrnul (void) { @@ -504,7 +504,7 @@ test_strchrnul (void) #endif // DDD: better done by testing for the function. -#if !defined(__APPLE__) && !defined(__sun) +#if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) static void test_rawmemchr (void) { @@ -580,7 +580,7 @@ test_strrchr (void) } // DDD: better done by testing for the function. -#if !defined(__APPLE__) && !defined(__sun) +#if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) static void test_memrchr (void) { @@ -911,7 +911,7 @@ test_strsep (void) equal(one+4, "c", 50); { -# if !defined(__APPLE__) +# if !defined(__APPLE__) && !defined(__FreeBSD__) char text[] = "This,is,a,test"; char *list = strdupa (text); equal (strsep (&list, ","), "This", 51); @@ -1072,7 +1072,7 @@ test_memcpy (void) } } -#if !defined(__APPLE__) && !defined(__sun) +#if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) static void test_mempcpy (void) { @@ -1288,7 +1288,7 @@ test_bzero (void) equal(one, "abcdef", 4); /* Zero-length copy. */ } -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) static void test_strndup (void) { @@ -1423,7 +1423,7 @@ main (void) /* A closely related function is stpcpy. */ test_stpcpy (); -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) /* stpncpy. */ test_stpncpy (); #endif @@ -1446,12 +1446,12 @@ main (void) /* strchr. */ test_strchr (); -# if !defined(__APPLE__) +# if !defined(__APPLE__) && !defined(__FreeBSD__) /* strchrnul. */ test_strchrnul (); # endif -# if !defined(__APPLE__) && !defined(__sun) +# if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) /* rawmemchr. */ test_rawmemchr (); # endif @@ -1462,7 +1462,7 @@ main (void) /* strrchr. */ test_strrchr (); -# if !defined(__APPLE__) && !defined(__sun) +# if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) /* memrchr. */ test_memrchr (); # endif @@ -1503,7 +1503,7 @@ main (void) /* memmove - must work on overlap. */ test_memmove (); -# if !defined(__APPLE__) && !defined(__sun) +# if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) /* mempcpy */ test_mempcpy (); # endif @@ -1523,7 +1523,7 @@ main (void) /* bcmp - somewhat like memcmp. */ test_bcmp (); -#if !defined(__APPLE__) +#if !defined(__APPLE__) && !defined(__FreeBSD__) /* strndup. */ test_strndup (); #endif diff --git a/memcheck/tests/test-plo-no.stderr.exp-le32-freebsd b/memcheck/tests/test-plo-no.stderr.exp-le32-freebsd new file mode 100755 index 000000000..f80232491 --- /dev/null +++ b/memcheck/tests/test-plo-no.stderr.exp-le32-freebsd @@ -0,0 +1,18 @@ +Invalid read of size 4 + ... + Address 0x........ is 4 bytes inside a block of size 5 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + ... + +Invalid read of size 4 + ... + Address 0x........ is 4 bytes inside a block of size 5 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + ... + +Invalid read of size 4 + ... + Address 0x........ is 4 bytes inside a block of size 12 free'd + at 0x........: free (vg_replace_malloc.c:...) + ... + diff --git a/memcheck/tests/test-plo-no.stderr.exp-le64-freebsd b/memcheck/tests/test-plo-no.stderr.exp-le64-freebsd new file mode 100755 index 000000000..ce4af703e --- /dev/null +++ b/memcheck/tests/test-plo-no.stderr.exp-le64-freebsd @@ -0,0 +1,18 @@ +Invalid read of size 8 + ... + Address 0x........ is 0 bytes inside a block of size 5 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + ... + +Invalid read of size 8 + ... + Address 0x........ is 0 bytes inside a block of size 5 alloc'd + at 0x........: malloc (vg_replace_malloc.c:...) + ... + +Invalid read of size 8 + ... + Address 0x........ is 8 bytes inside a block of size 24 free'd + at 0x........: free (vg_replace_malloc.c:...) + ... + diff --git a/memcheck/tests/thread_alloca.c b/memcheck/tests/thread_alloca.c index c30d1dc85..7924928c2 100644 --- a/memcheck/tests/thread_alloca.c +++ b/memcheck/tests/thread_alloca.c @@ -7,7 +7,9 @@ Also, a high nr of threads in thr[] is needed to get the problem. */ #include +#if !defined(__FreeBSD__) #include +#endif #include #include #include diff --git a/memcheck/tests/vbit-test/util.c b/memcheck/tests/vbit-test/util.c index d64268df5..460183a9a 100644 --- a/memcheck/tests/vbit-test/util.c +++ b/memcheck/tests/vbit-test/util.c @@ -39,8 +39,12 @@ # else # define __BYTE_ORDER __BIG_ENDIAN # endif -#else +#elif defined(__linux__) #include +#else +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN +#include #endif #include #include "vtest.h" diff --git a/memcheck/tests/vbit-test/vbits.c b/memcheck/tests/vbit-test/vbits.c index 5a5cd663d..3bfd6b5d1 100644 --- a/memcheck/tests/vbit-test/vbits.c +++ b/memcheck/tests/vbit-test/vbits.c @@ -38,8 +38,12 @@ # else # define __BYTE_ORDER __BIG_ENDIAN # endif -#else +#elif defined(__linux__) #include +#else +#include +#define __BYTE_ORDER BYTE_ORDER +#define __LITTLE_ENDIAN LITTLE_ENDIAN #endif #include #include "vbits.h" diff --git a/mpi/Makefile.am b/mpi/Makefile.am index 7ad9a2553..36df8ec95 100644 --- a/mpi/Makefile.am +++ b/mpi/Makefile.am @@ -38,6 +38,10 @@ if VGCONF_OS_IS_LINUX MPI_FLAG_M3264_PRI = $(AM_FLAG_M3264_PRI) MPI_FLAG_M3264_SEC = $(AM_FLAG_M3264_SEC) endif +if VGCONF_OS_IS_FREEBSD + MPI_FLAG_M3264_PRI = $(AM_FLAG_M3264_PRI) + MPI_FLAG_M3264_SEC = $(AM_FLAG_M3264_SEC) +endif if VGCONF_OS_IS_DARWIN MPI_FLAG_M3264_PRI = $(AM_FLAG_M3264_PRI) MPI_FLAG_M3264_SEC = $(AM_FLAG_M3264_SEC) diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am index 37ac4f087..2c7ca0f35 100644 --- a/none/tests/Makefile.am +++ b/none/tests/Makefile.am @@ -175,6 +175,7 @@ EXTRA_DIST = \ require-text-symbol-2.vgtest \ require-text-symbol-2.stderr.exp-libcso1 \ require-text-symbol-2.stderr.exp-libcso6 \ + require-text-symbol-2.stderr.exp-freebsd \ res_search.stderr.exp res_search.stdout.exp res_search.vgtest \ resolv.stderr.exp resolv.stdout.exp resolv.vgtest \ rlimit_nofile.stderr.exp rlimit_nofile.stdout.exp rlimit_nofile.vgtest \ @@ -256,7 +257,7 @@ if HAVE_NESTED_FUNCTIONS endif # This doesn't appear to be compilable on Darwin. -if ! VGCONF_OS_IS_DARWIN +if VGCONF_OS_IS_LINUX check_PROGRAMS += rlimit64_nofile \ ppoll_alarm endif @@ -318,9 +319,13 @@ pth_rwlock_CFLAGS = $(AM_CFLAGS) pth_stackalign_LDADD = -lpthread pth_2sig_LDADD = -lpthread pth_term_signal_LDADD = -lpthread +if VGCONF_OS_IS_FREEBSD + res_search_LDADD = -lpthread +else res_search_LDADD = -lresolv -lpthread -resolv_CFLAGS = $(AM_CFLAGS) resolv_LDADD = -lresolv -lpthread +endif +resolv_CFLAGS = $(AM_CFLAGS) if VGCONF_OS_IS_SOLARIS resolv_CFLAGS += -U_REENTRANT endif diff --git a/none/tests/amd64/bug156404-amd64.c b/none/tests/amd64/bug156404-amd64.c index 3af8b60a6..eb67ad5b0 100644 --- a/none/tests/amd64/bug156404-amd64.c +++ b/none/tests/amd64/bug156404-amd64.c @@ -14,7 +14,11 @@ #define VG_STRINGIFZ(__str) #__str #define VG_STRINGIFY(__str) VG_STRINGIFZ(__str) -#if defined(VGO_linux) || defined(VGO_darwin) +#if defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_freebsd) +#if !defined(__NR_readlink) +# define __NR_readlink 58 +#endif + #define __NR_READLINK VG_STRINGIFY(__NR_readlink) extern long my_readlink ( const char* path ); diff --git a/none/tests/pth_atfork1.c b/none/tests/pth_atfork1.c index 34201ef96..60ca281bf 100644 --- a/none/tests/pth_atfork1.c +++ b/none/tests/pth_atfork1.c @@ -18,7 +18,7 @@ Boston, MA 02111-1307, USA. */ #include -#if !defined(__APPLE__) && !defined(__sun) +#if !defined(__APPLE__) && !defined(__sun) && !defined(__FreeBSD__) # include #endif #include @@ -27,7 +27,7 @@ #include #include -#if defined(__APPLE__) || defined(__sun) +#if defined(__APPLE__) || defined(__sun) || defined(__FreeBSD__) #include /* strerror */ static void error (int status, int errnum, char* msg) { diff --git a/none/tests/require-text-symbol-2.stderr.exp-freebsd b/none/tests/require-text-symbol-2.stderr.exp-freebsd new file mode 100755 index 000000000..e71b0b497 --- /dev/null +++ b/none/tests/require-text-symbol-2.stderr.exp-freebsd @@ -0,0 +1,9 @@ + +valgrind: Fatal error at when loading library with soname +valgrind: libc.so.7 +valgrind: Cannot find any text symbol with a name that matches the pattern +valgrind: doesntexist +valgrind: as required by a --require-text-symbol= specification. + +valgrind: Cannot continue -- exiting now. + diff --git a/none/tests/x86/faultstatus.c b/none/tests/x86/faultstatus.c index 6335c19c8..e26911639 100644 --- a/none/tests/x86/faultstatus.c +++ b/none/tests/x86/faultstatus.c @@ -132,7 +132,9 @@ int main() { const struct test tests[] = { #define T(n, sig, code, addr) { test##n, sig, code, addr } +#if !defined(__FreeBSD__) || __FreeBSD__ >= 5 T(1, SIGILL, ILL_ILLOPN, &test1_ill), +#endif T(2, SIGTRAP, 128, 0), /* TRAP_BRKPT? */ T(3, SIGSEGV, 128, 0), diff --git a/shared/vg_replace_strmem.c b/shared/vg_replace_strmem.c index 89a7dccb7..dde3020d9 100644 --- a/shared/vg_replace_strmem.c +++ b/shared/vg_replace_strmem.c @@ -210,6 +210,12 @@ static inline void my_exit ( int x ) STRRCHR(NONE, __dl_strrchr); /* in /system/bin/linker */ #endif +#elif defined(VGO_freebsd) + STRRCHR(VG_Z_LIBC_SONAME, strrchr) + STRRCHR(VG_Z_LIBC_SONAME, rindex) + STRRCHR(VG_Z_LD_ELF_SO_1, strrchr) + STRRCHR(VG_Z_LD_ELF32_SO_1, strrchr) + #elif defined(VGO_darwin) //STRRCHR(VG_Z_LIBC_SONAME, strrchr) //STRRCHR(VG_Z_LIBC_SONAME, rindex) @@ -261,6 +267,12 @@ static inline void my_exit ( int x ) STRCHR(NONE, __dl_strchr) #endif +#elif defined(VGO_freebsd) + STRCHR(VG_Z_LIBC_SONAME, strchr) + STRCHR(VG_Z_LIBC_SONAME, index) + STRCHR(VG_Z_LD_ELF_SO_1, strchr) + STRCHR(VG_Z_LD_ELF32_SO_1, strchr) + #elif defined(VGO_darwin) STRCHR(VG_Z_LIBC_SONAME, strchr) # if DARWIN_VERS == DARWIN_10_9 @@ -310,6 +322,11 @@ static inline void my_exit ( int x ) STRCAT(VG_Z_LIBC_SONAME, strcat) STRCAT(VG_Z_LIBC_SONAME, __GI_strcat) +#elif defined(VGO_freebsd) + STRCAT(VG_Z_LIBC_SONAME, strcat) + STRCAT(VG_Z_LD_ELF_SO_1, strcat) + STRCAT(VG_Z_LD_ELF32_SO_1, strcat) + #elif defined(VGO_darwin) //STRCAT(VG_Z_LIBC_SONAME, strcat) @@ -350,6 +367,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) STRNCAT(VG_Z_LIBC_SONAME, strncat) +#elif defined(VGO_freebsd) + STRNCAT(VG_Z_LIBC_SONAME, strncat) + #elif defined(VGO_darwin) //STRNCAT(VG_Z_LIBC_SONAME, strncat) //STRNCAT(VG_Z_DYLD, strncat) @@ -400,6 +420,11 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) +#elif defined(VGO_freebsd) + STRLCAT(VG_Z_LD_ELF_SO_1, strlcat) + STRLCAT(VG_Z_LIBC_SONAME, strlcat) + STRLCAT(VG_Z_LD_ELF32_SO_1, strlcat) + #elif defined(VGO_darwin) //STRLCAT(VG_Z_LIBC_SONAME, strlcat) //STRLCAT(VG_Z_DYLD, strlcat) @@ -471,6 +496,11 @@ static inline void my_exit ( int x ) STRLEN(NONE, __dl_strlen); /* in /system/bin/linker */ # endif +#elif defined(VGO_freebsd) + STRLEN(VG_Z_LIBC_SONAME, strlen) + STRLEN(VG_Z_LD_ELF_SO_1, strlen) + STRLEN(VG_Z_LD_ELF32_SO_1, strlen) + #elif defined(VGO_darwin) STRLEN(VG_Z_LIBC_SONAME, strlen) # if DARWIN_VERS >= DARWIN_10_9 @@ -513,6 +543,11 @@ static inline void my_exit ( int x ) STRCPY(VG_Z_LIBC_SONAME, strcpy) STRCPY(VG_Z_LIBC_SONAME, __GI_strcpy) +#elif defined(VGO_freebsd) + STRCPY(VG_Z_LIBC_SONAME, strcpy) + STRCPY(VG_Z_LD_ELF_SO_1, strcpy) + STRCPY(VG_Z_LD_ELF32_SO_1, strcpy) + #elif defined(VGO_darwin) STRCPY(VG_Z_LIBC_SONAME, strcpy) # if DARWIN_VERS == DARWIN_10_9 @@ -554,6 +589,11 @@ static inline void my_exit ( int x ) STRNCPY(VG_Z_LIBC_SONAME, __strncpy_sse2) STRNCPY(VG_Z_LIBC_SONAME, __strncpy_sse2_unaligned) +#elif defined(VGO_freebsd) + STRNCPY(VG_Z_LIBC_SONAME, strncpy) + STRNCPY(VG_Z_LD_ELF_SO_1, strncpy) + STRNCPY(VG_Z_LD_ELF32_SO_1, strncpy) + #elif defined(VGO_darwin) STRNCPY(VG_Z_LIBC_SONAME, strncpy) # if DARWIN_VERS >= DARWIN_10_9 @@ -604,6 +644,12 @@ static inline void my_exit ( int x ) STRLCPY(VG_Z_LIBC_SONAME, strlcpy); #endif +#elif defined(VGO_freebsd) + #define STRLCPY_CHECK_FOR_DSTSIZE_ZERO + STRLCPY(VG_Z_LD_ELF_SO_1, strlcpy) + STRLCPY(VG_Z_LD_ELF32_SO_1, strlcpy) + STRLCPY(VG_Z_LIBC_SONAME, strlcpy) + #elif defined(VGO_darwin) #define STRLCPY_CHECK_FOR_DSTSIZE_ZERO //STRLCPY(VG_Z_LIBC_SONAME, strlcpy) @@ -651,6 +697,11 @@ static inline void my_exit ( int x ) STRNCMP(VG_Z_LIBC_SONAME, __strncmp_sse2) STRNCMP(VG_Z_LIBC_SONAME, __strncmp_sse42) +#elif defined(VGO_freebsd) + STRNCMP(VG_Z_LIBC_SONAME, strncmp) + STRNCMP(VG_Z_LD_ELF_SO_1, strncmp) + STRNCMP(VG_Z_LD_ELF32_SO_1, strncmp) + #elif defined(VGO_darwin) STRNCMP(VG_Z_LIBC_SONAME, strncmp) # if DARWIN_VERS >= DARWIN_10_9 @@ -695,6 +746,11 @@ static inline void my_exit ( int x ) STRCASECMP(VG_Z_LIBC_SONAME, __GI_strcasecmp) # endif +#elif defined(VGO_freebsd) + STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp) + STRNCMP(VG_Z_LD_ELF_SO_1, strcasecmp) + STRNCMP(VG_Z_LD_ELF32_SO_1, strcasecmp) + #elif defined(VGO_darwin) //STRCASECMP(VG_Z_LIBC_SONAME, strcasecmp) @@ -738,6 +794,11 @@ static inline void my_exit ( int x ) STRNCASECMP(VG_Z_LIBC_SONAME, __GI_strncasecmp) # endif +#elif defined(VGO_freebsd) + STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp) + STRNCASECMP(VG_Z_LD_ELF_SO_1, strncasecmp) + STRNCASECMP(VG_Z_LD_ELF32_SO_1, strncasecmp) + #elif defined(VGO_darwin) //STRNCASECMP(VG_Z_LIBC_SONAME, strncasecmp) //STRNCASECMP(VG_Z_DYLD, strncasecmp) @@ -857,6 +918,11 @@ static inline void my_exit ( int x ) STRCMP(NONE, __dl_strcmp); /* in /system/bin/linker */ # endif +#elif defined(VGO_freebsd) + STRCMP(VG_Z_LIBC_SONAME, strcmp) + STRCMP(VG_Z_LD_ELF_SO_1, strcmp) + STRCMP(VG_Z_LD_ELF32_SO_1, strcmp) + #elif defined(VGO_darwin) STRCMP(VG_Z_LIBC_SONAME, strcmp) # if DARWIN_VERS >= DARWIN_10_9 @@ -928,6 +994,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) MEMRCHR(VG_Z_LIBC_SONAME, memrchr) +#elif defined(VGO_freebsd) + MEMRCHR(VG_Z_LIBC_SONAME, memrchr) + #elif defined(VGO_darwin) //MEMRCHR(VG_Z_LIBC_SONAME, memrchr) //MEMRCHR(VG_Z_DYLD, memrchr) @@ -1048,6 +1117,11 @@ static inline void my_exit ( int x ) */ MEMCPY(NONE, ZuintelZufastZumemcpy) +#elif defined(VGO_freebsd) + MEMCPY(VG_Z_LIBC_SONAME, memcpy) + MEMCPY(VG_Z_LD_ELF_SO_1, memcpy) + MEMCPY(VG_Z_LD_ELF32_SO_1, memcpy) + #elif defined(VGO_darwin) # if DARWIN_VERS <= DARWIN_10_6 MEMCPY(VG_Z_LIBC_SONAME, memcpy) @@ -1113,6 +1187,10 @@ static inline void my_exit ( int x ) MEMCMP(VG_Z_LIBC_SONAME, bcmp) MEMCMP(VG_Z_LD_SO_1, bcmp) +#elif defined(VGO_freebsd) + MEMCMP(VG_Z_LIBC_SONAME, memcmp) + MEMCMP(VG_Z_LIBC_SONAME, bcmp) + #elif defined(VGO_darwin) # if DARWIN_VERS >= DARWIN_10_9 MEMCMP(libsystemZuplatformZddylib, _platform_memcmp) @@ -1161,6 +1239,11 @@ static inline void my_exit ( int x ) STPCPY(VG_Z_LD_LINUX_SO_2, stpcpy) STPCPY(VG_Z_LD_LINUX_X86_64_SO_2, stpcpy) +#elif defined(VGO_freebsd) + STPCPY(VG_Z_LD_ELF_SO_1, stpcpy) + STPCPY(VG_Z_LD_ELF32_SO_1, stpcpy) + STPCPY(VG_Z_LIBC_SONAME, stpcpy) + #elif defined(VGO_darwin) //STPCPY(VG_Z_LIBC_SONAME, stpcpy) //STPCPY(VG_Z_DYLD, stpcpy) @@ -1251,6 +1334,11 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) MEMSET(VG_Z_LIBC_SONAME, memset) +#elif defined(VGO_freebsd) + MEMSET(VG_Z_LIBC_SONAME, memset) + MEMSET(VG_Z_LD_ELF_SO_1, memset) + MEMSET(VG_Z_LD_ELF32_SO_1, memset) + #elif defined(VGO_darwin) //MEMSET(VG_Z_LIBC_SONAME, memset) //MEMSET(VG_Z_DYLD, memset) @@ -1275,6 +1363,11 @@ static inline void my_exit ( int x ) to call memcpy. */ MEMMOVE(VG_Z_LD64_SO_1, memmove) +#elif defined(VGO_freebsd) + MEMMOVE(VG_Z_LD_ELF_SO_1, memmove) + MEMMOVE(VG_Z_LD_ELF32_SO_1, memmove) + MEMMOVE(VG_Z_LIBC_SONAME, memmove) + #elif defined(VGO_darwin) # if DARWIN_VERS <= DARWIN_10_6 MEMMOVE(VG_Z_LIBC_SONAME, memmove) @@ -1319,6 +1412,11 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) BCOPY(VG_Z_LIBC_SONAME, bcopy) +#elif defined(VGO_freebsd) + BCOPY(VG_Z_LIBC_SONAME, bcopy) + BCOPY(VG_Z_LD_ELF_SO_1, bcopy) + BCOPY(VG_Z_LD_ELF32_SO_1, bcopy) + #elif defined(VGO_darwin) //BCOPY(VG_Z_LIBC_SONAME, bcopy) //BCOPY(VG_Z_DYLD, bcopy) @@ -1394,6 +1492,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul) +#elif defined(VGO_freebsd) + GLIBC232_STRCHRNUL(VG_Z_LIBC_SONAME, strchrnul) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1644,6 +1745,9 @@ static inline void my_exit ( int x ) STRSTR(VG_Z_LIBC_SONAME, __strstr_sse2) STRSTR(VG_Z_LIBC_SONAME, __strstr_sse42) +#elif defined(VGO_freebsd) + STRSTR(VG_Z_LIBC_SONAME, strstr) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1689,6 +1793,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) STRPBRK(VG_Z_LIBC_SONAME, strpbrk) +#elif defined(VGO_freebsd) + STRPBRK(VG_Z_LIBC_SONAME, strpbrk) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1736,6 +1843,9 @@ static inline void my_exit ( int x ) STRCSPN(VG_Z_LIBC_SONAME, strcspn) STRCSPN(VG_Z_LIBC_SONAME, __GI_strcspn) +#elif defined(VGO_freebsd) + STRCSPN(VG_Z_LIBC_SONAME, strcspn) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1783,6 +1893,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) STRSPN(VG_Z_LIBC_SONAME, strspn) +#elif defined(VGO_freebsd) + STRSPN(VG_Z_LIBC_SONAME, strspn) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1839,6 +1952,9 @@ static inline void my_exit ( int x ) STRCASESTR(VG_Z_LIBC_SONAME, strcasestr) # endif +#elif defined(VGO_freebsd) + STRCASESTR(VG_Z_LIBC_SONAME, strcasestr) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -1868,6 +1984,9 @@ static inline void my_exit ( int x ) #if defined(VGO_linux) WCSLEN(VG_Z_LIBC_SONAME, wcslen) +#elif defined(VGO_freebsd) + WCSLEN(VG_Z_LIBC_SONAME, wcslen) + #elif defined(VGO_darwin) #elif defined(VGO_solaris) @@ -2066,7 +2185,7 @@ static inline void my_exit ( int x ) /*--- Improve definedness checking of process environment ---*/ /*------------------------------------------------------------*/ -#if defined(VGO_linux) +#if defined(VGO_linux) || defined(VGO_freebsd) /* If these wind up getting generated via a macro, so that multiple versions of each function exist (as above), use the _EZU variants diff --git a/tests/arch_test.c b/tests/arch_test.c index 1c90dac67..0f8d4e601 100644 --- a/tests/arch_test.c +++ b/tests/arch_test.c @@ -39,11 +39,11 @@ char* all_archs[] = { static Bool go(char* arch) { #if defined(VGP_x86_linux) || defined(VGP_x86_darwin) \ - || defined(VGP_x86_solaris) + || defined(VGP_x86_solaris) || defined(VGP_x86_freebsd) if ( 0 == strcmp( arch, "x86" ) ) return True; #elif defined(VGP_amd64_linux) || defined(VGP_amd64_darwin) \ - || defined(VGP_amd64_solaris) + || defined(VGP_amd64_solaris) || defined(VGP_amd64_freebsd) #if defined(VGA_SEC_x86) if ( 0 == strcmp( arch, "x86" ) ) return True; #endif diff --git a/tests/malloc.h b/tests/malloc.h index 146790e3c..ddece2a8b 100644 --- a/tests/malloc.h +++ b/tests/malloc.h @@ -3,6 +3,8 @@ #include #if defined(VGO_darwin) # include +#elif defined(VGO_freebsd) +# include #else # include #endif @@ -14,7 +16,7 @@ __attribute__((unused)) static void* memalign16(size_t szB) { void* x; -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) // Darwin lacks memalign, but its malloc is always 16-aligned anyway. posix_memalign((void **)&x, 16, szB); #else @@ -30,7 +32,7 @@ __attribute__((unused)) static void* memalign32(size_t szB) { void* x; -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) // Darwin lacks memalign posix_memalign((void **)&x, 32, szB); #else @@ -46,7 +48,7 @@ __attribute__((unused)) static void* memalign64(size_t szB) { void* x; -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) // Darwin lacks memalign posix_memalign((void **)&x, 64, szB); #else diff --git a/tests/os_test.c b/tests/os_test.c index d3c5a69d0..7e47bf0ce 100644 --- a/tests/os_test.c +++ b/tests/os_test.c @@ -24,6 +24,7 @@ char* all_OSes[] = { "linux", "darwin", "solaris", + "freebsd", NULL }; @@ -66,6 +67,9 @@ static Bool go(char* OS, char *min_version) #elif defined(VGO_solaris) if ( 0 == strcmp( OS, "solaris" ) ) return True; +#elif defined(VGO_freebsd) + if ( 0 == strcmp( OS, "freebsd" ) ) return True; + #else # error Unknown OS #endif // VGO_* diff --git a/tests/sys_mman.h b/tests/sys_mman.h index 0cdc434f7..4c4b5d75a 100644 --- a/tests/sys_mman.h +++ b/tests/sys_mman.h @@ -2,7 +2,7 @@ #include -#if defined(VGO_darwin) +#if defined(VGO_darwin) || defined(VGO_freebsd) # define MAP_ANONYMOUS MAP_ANON #endif