]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
FreeBSD support, patch 11
authorPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 9 Oct 2021 12:11:48 +0000 (14:11 +0200)
committerPaul Floyd <pjfloyd@wanadoo.fr>
Sat, 9 Oct 2021 12:11:48 +0000 (14:11 +0200)
coregrind added files
the key mechanics and the syscall wrappers

15 files changed:
configure.ac
coregrind/Makefile.am
coregrind/launcher-freebsd.c [new file with mode: 0644]
coregrind/link_tool_exe_freebsd.in [new file with mode: 0755]
coregrind/m_dispatch/dispatch-amd64-freebsd.S [new file with mode: 0644]
coregrind/m_dispatch/dispatch-x86-freebsd.S [new file with mode: 0644]
coregrind/m_initimg/initimg-freebsd.c [new file with mode: 0644]
coregrind/m_sigframe/sigframe-amd64-freebsd.c [new file with mode: 0644]
coregrind/m_sigframe/sigframe-x86-freebsd.c [new file with mode: 0644]
coregrind/m_syswrap/priv_syswrap-freebsd.h [new file with mode: 0644]
coregrind/m_syswrap/syscall-amd64-freebsd.S [new file with mode: 0644]
coregrind/m_syswrap/syscall-x86-freebsd.S [new file with mode: 0644]
coregrind/m_syswrap/syswrap-amd64-freebsd.c [new file with mode: 0644]
coregrind/m_syswrap/syswrap-freebsd.c [new file with mode: 0644]
coregrind/m_syswrap/syswrap-x86-freebsd.c [new file with mode: 0644]

index 39e619575eb328b7d8f8d1e65efb9d928dfe4ca1..275c0ca02cc5add434f877b1322deadd92bd6280 100755 (executable)
@@ -5211,6 +5211,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],
index 01b8783ee49c3eb9abea0f0a30cc211aef84b77a..1de685bb45482cb8a52a008c0a89dfac65098ade 100644 (file)
@@ -286,6 +286,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 \
@@ -388,6 +389,8 @@ COREGRIND_SOURCES_COMMON = \
        m_dispatch/dispatch-mips32-linux.S \
        m_dispatch/dispatch-mips64-linux.S \
        m_dispatch/dispatch-nanomips-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 \
@@ -412,6 +415,7 @@ COREGRIND_SOURCES_COMMON = \
        m_gdbserver/valgrind-low-nanomips.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_mach/mach_basics.c \
@@ -426,6 +430,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 \
@@ -448,6 +454,8 @@ COREGRIND_SOURCES_COMMON = \
        m_syswrap/syscall-mips32-linux.S \
        m_syswrap/syscall-mips64-linux.S \
        m_syswrap/syscall-nanomips-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 \
@@ -456,12 +464,15 @@ 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-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 100644 (file)
index 0000000..7d40ad6
--- /dev/null
@@ -0,0 +1,325 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   The GNU General Public License is contained in the file COPYING.
+*/
+
+/* Note: this is a "normal" program and not part of Valgrind proper,
+   and so it doesn't have to conform to Valgrind's arcane rules on
+   no-glibc-usage etc. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/sysctl.h>
+/* #include <sys/user.h> */
+#include <unistd.h>
+
+#include "pub_core_debuglog.h"
+#include "pub_core_vki.h"       // Avoids warnings from
+// pub_core_libcfile.h
+#include "pub_core_libcproc.h"  // For VALGRIND_LIB, VALGRIND_LAUNCHER
+#include "pub_core_ume.h"
+
+
+#if !defined(PATH_MAX)
+#define PATH_MAX 4096 /* POSIX refers to this a lot but I dunno
+                         where it is defined */
+#endif
+
+#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;
+   char header[4096];
+   ssize_t n_bytes;
+   const char *platform = NULL;
+
+   VG_(debugLog)(2, "launcher", "selecting platform for '%s'\n", clientname);
+
+   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 ((size_t)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 ((size_t)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";
+            }
+         }
+      }
+   }
+
+   VG_(debugLog)(2, "launcher", "selected platform '%s'\n",
+                 platform ? platform : "unknown");
+
+   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;
+   int oid[4];
+   vki_size_t len;
+
+   /* 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);
+
+   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");
+   }
+
+   /* 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 (executable)
index 0000000..b4df462
--- /dev/null
@@ -0,0 +1,82 @@
+#! @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 compiler invocation 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.
+#
+# FreeBSD specific complications:
+#
+# - in the initial version of this file, the linker(s) it was targeted
+#   at supported only -Ttext to load the code at an alternative address,
+#   and did not require removing the build notes in order to function
+#   correctly, so the work done by configure to determine what should go
+#   into the FLAG_T_TEXT was ignored.
+#
+# - LLVM's ld.lld, for at least versions 8.0 (shipping with FreeBSD 12.1)
+#   and 9.0 support the -Ttext option and behave as desired.  As of
+#   LLVM ld.lld version 10.0 a breaking change made -Ttext unusable,
+#   however the --image-base option has the desired semantics.
+#   It turns out that ld.lld has supported --image-base since at least
+#   as far back as version 8.0.
+#
+# So: what we actually do:
+#
+#   pass the specified command to the linker as-is, except, add
+#   "-static" and the value of FLAG_T_TEXT as determined by configure.
+#   Previously we did this by adding these options after the first
+#   word of the rest of the arguments, which works in the common case
+#   when it's something like "gcc". But the linker invocation itself
+#   might be multiple words, say if it's "ccache gcc". So we now put
+#   the new options at the end instead.
+#
+
+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];
+shift; # Remove $ala from @ARGV
+
+# check for plausible-ish alt load address
+die "Bogus alt-load address"
+    if (length($ala) < 3 || index($ala, "0x") != 0);
+
+my $cmd = join(" ", @ARGV, "-static -Wl,@FLAG_T_TEXT@=$ala");
+
+#print "link_tool_exe_freebsd: $cmd\n";
+
+
+# Execute the command:
+my $r = system("$cmd");
+
+if ($r == 0) {
+    exit 0;
+} else {
+    exit 1;
+}
diff --git a/coregrind/m_dispatch/dispatch-amd64-freebsd.S b/coregrind/m_dispatch/dispatch-amd64-freebsd.S
new file mode 100644 (file)
index 0000000..db4dcca
--- /dev/null
@@ -0,0 +1,321 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                       dispatch-amd64-freebsd.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2017 Julian Seward
+     jseward@acm.org
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+  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, see <http://www.gnu.org/licenses/>.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+#if defined(VGP_amd64_freebsd)
+
+#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    // "guest"
+
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndirs_32)
+
+        // LIVE: %rbp (guest state ptr), %rax (guest address to go to).
+        // We use 4 temporaries:
+        //   %r9 (to point at the relevant FastCacheSet),
+        //   %r10, %r11 and %r12 (scratch).
+
+        /* Try a fast lookup in the translation cache.  This is pretty much
+           a handcoded version of VG_(lookupInFastCache). */
+
+        // Compute %r9 = VG_TT_FAST_HASH(guest)
+        movq    %rax, %r9               // guest
+        shrq    $VG_TT_FAST_BITS, %r9   // (guest >> VG_TT_FAST_BITS)
+        xorq    %rax, %r9               // (guest >> VG_TT_FAST_BITS) ^ guest
+        andq    $VG_TT_FAST_MASK, %r9   // setNo
+
+        // Compute %r9 = &VG_(tt_fast)[%r9]
+        shlq    $VG_FAST_CACHE_SET_BITS, %r9  // setNo * sizeof(FastCacheSet)
+        movabsq $VG_(tt_fast), %r10           // &VG_(tt_fast)[0]
+        leaq    (%r10, %r9), %r9              // &VG_(tt_fast)[setNo]
+
+        // LIVE: %rbp (guest state ptr), %rax (guest addr), %r9 (cache set)
+        // try way 0
+        cmpq    %rax, FCS_g0(%r9)   // cmp against .guest0
+        jnz     1f
+        // hit at way 0
+        jmp    *FCS_h0(%r9)         // goto .host0
+        ud2
+
+1:      // try way 1
+        cmpq    %rax, FCS_g1(%r9)   // cmp against .guest1
+        jnz     2f
+        // hit at way 1; swap upwards
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndir_hits1_32)
+        movq    FCS_g0(%r9), %r10   // r10 = old .guest0
+        movq    FCS_h0(%r9), %r11   // r11 = old .host0
+        movq    FCS_h1(%r9), %r12   // r12 = old .host1
+        movq    %rax, FCS_g0(%r9)   // new .guest0 = guest
+        movq    %r12, FCS_h0(%r9)   // new .host0 = old .host1
+        movq    %r10, FCS_g1(%r9)   // new .guest1 = old .guest0
+        movq    %r11, FCS_h1(%r9)   // new .host1 = old .host0
+        jmp     *%r12               // goto old .host1 a.k.a. new .host0
+        ud2
+
+2:      // try way 2
+        cmpq    %rax, FCS_g2(%r9)   // cmp against .guest2
+        jnz     3f
+        // hit at way 2; swap upwards
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndir_hits2_32)
+        movq    FCS_g1(%r9), %r10
+        movq    FCS_h1(%r9), %r11
+        movq    FCS_h2(%r9), %r12
+        movq    %rax, FCS_g1(%r9)
+        movq    %r12, FCS_h1(%r9)
+        movq    %r10, FCS_g2(%r9)
+        movq    %r11, FCS_h2(%r9)
+        jmp     *%r12
+        ud2
+
+3:      // try way 3
+        cmpq    %rax, FCS_g3(%r9)   // cmp against .guest3
+        jnz     4f
+        // hit at way 3; swap upwards
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndir_hits3_32)
+        movq    FCS_g2(%r9), %r10
+        movq    FCS_h2(%r9), %r11
+        movq    FCS_h3(%r9), %r12
+        movq    %rax, FCS_g2(%r9)
+        movq    %r12, FCS_h2(%r9)
+        movq    %r10, FCS_g3(%r9)
+        movq    %r11, FCS_h3(%r9)
+        jmp     *%r12
+        ud2
+
+4:      // fast lookup failed
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndir_misses_32)
+
+       movq    $VG_TRC_INNER_FASTMISS, %rax
+        movq    $0, %rdx
+       jmp     postamble
+
+/* ------ Assisted jump ------ */
+.global VG_(disp_cp_xassisted)
+VG_(disp_cp_xassisted):
+        /* %rbp contains the TRC */
+        movq    %rbp, %rax
+        movq    $0, %rdx
+        jmp     postamble
+
+/* ------ Event check failed ------ */
+.global VG_(disp_cp_evcheck_fail)
+VG_(disp_cp_evcheck_fail):
+        movq   $VG_TRC_INNER_COUNTERZERO, %rax
+        movq    $0, %rdx
+        jmp    postamble
+
+
+.size VG_(disp_run_translations), .-VG_(disp_run_translations)
+
+#endif // defined(VGP_amd64_freebsd)
+
+/* Let the linker know we don't need an executable stack */
+MARK_STACK_NO_EXEC
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_dispatch/dispatch-x86-freebsd.S b/coregrind/m_dispatch/dispatch-x86-freebsd.S
new file mode 100644 (file)
index 0000000..667bfcd
--- /dev/null
@@ -0,0 +1,251 @@
+
+/*--------------------------------------------------------------------*/
+/*--- The core dispatch loop, for jumping to a code address.       ---*/
+/*---                                       dispatch-x86-freebsd.S ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+  This file is part of Valgrind, a dynamic binary instrumentation
+  framework.
+
+  Copyright (C) 2000-2012 Julian Seward
+     jseward@acm.org
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+  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, see <http://www.gnu.org/licenses/>.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+#if defined(VGP_x86_freebsd)
+
+#include "pub_core_dispatch_asm.h"
+#include "pub_core_transtab_asm.h"
+#include "libvex_guest_offsets.h"      /* for OFFSET_x86_EIP */
+
+
+/*------------------------------------------------------------*/
+/*---                                                      ---*/
+/*--- The dispatch loop.  VG_(disp_run_translations) is    ---*/
+/*--- used to run all translations,                        ---*/
+/*--- including no-redir ones.                             ---*/
+/*---                                                      ---*/
+/*------------------------------------------------------------*/
+
+/*----------------------------------------------------*/
+/*--- Entry and preamble (set everything up)       ---*/
+/*----------------------------------------------------*/
+
+/* signature:
+void VG_(disp_run_translations)( UWord* two_words,
+                                 void*  guest_state,
+                                 Addr   host_addr );
+*/
+.text
+.globl VG_(disp_run_translations)
+.type  VG_(disp_run_translations), @function
+VG_(disp_run_translations):
+        /* 0(%esp) holds our return address. */
+       /* 4(%esp) holds two_words */
+       /* 8(%esp) holds guest_state */
+       /* 12(%esp) holds host_addr */
+
+        /* The preamble */
+
+        /* Save integer registers, since this is a pseudo-function. */
+        pushl   %eax
+       pushl   %ebx
+       pushl   %ecx
+       pushl   %edx
+       pushl   %esi
+       pushl   %edi
+       pushl   %ebp
+
+       /* 28+4(%esp) holds two_words */
+       /* 28+8(%esp) holds guest_state */
+       /* 28+12(%esp) holds host_addr */
+
+        /* Get the host CPU in the state expected by generated code. */
+
+       /* set host FPU control word to the default mode expected
+           by VEX-generated code.  See comments in libvex.h for
+           more info. */
+       finit
+       pushl   $0x027F
+       fldcw   (%esp)
+       addl    $4, %esp
+
+       /* set host SSE control word to the default mode expected
+          by VEX-generated code. */
+       cmpl    $0, VG_(machine_x86_have_mxcsr)
+       jz      L1
+       pushl   $0x1F80
+       ldmxcsr (%esp)
+       addl    $4, %esp
+L1:
+       /* set dir flag to known value */
+       cld
+
+       /* Set up the guest state pointer */
+       movl    28+8(%esp), %ebp
+
+        /* and jump into the code cache.  Chained translations in
+           the code cache run, until for whatever reason, they can't
+           continue.  When that happens, the translation in question
+           will jump (or call) to one of the continuation points
+           VG_(cp_...) below. */
+        jmpl    *28+12(%esp)
+       /*NOTREACHED*/
+
+/*----------------------------------------------------*/
+/*--- Postamble and exit.                          ---*/
+/*----------------------------------------------------*/
+
+postamble:
+        /* At this point, %eax and %edx contain two
+           words to be returned to the caller.  %eax
+           holds a TRC value, and %edx optionally may
+           hold another word (for CHAIN_ME exits, the
+           address of the place to patch.) */
+
+       /* We're leaving.  Check that nobody messed with %mxcsr
+           or %fpucw.  We can't mess with %eax or %edx here as they
+          holds the tentative return value, but any others are OK. */
+#if !defined(ENABLE_INNER)
+        /* This check fails for self-hosting, so skip in that case */
+       pushl   $0
+       fstcw   (%esp)
+       cmpl    $0x027F, (%esp)
+       popl    %esi /* get rid of the word without trashing %eflags */
+       jnz     invariant_violation
+#endif
+#      cmpl    $0, VG_(machine_x86_have_mxcsr)
+       jz      L2
+       pushl   $0
+       stmxcsr (%esp)
+       andl    $0xFFFFFFC0, (%esp)  /* mask out status flags */
+       cmpl    $0x1F80, (%esp)
+       popl    %esi
+       jnz     invariant_violation
+L2:    /* otherwise we're OK */
+       jmp     remove_frame
+invariant_violation:
+       movl    $VG_TRC_INVARIANT_FAILED, %eax
+        movl    $0, %edx
+
+remove_frame:
+        /* Stash return values */
+        movl    28+4(%esp), %edi        /* two_words */
+        movl    %eax, 0(%edi)
+        movl    %edx, 4(%edi)
+        /* Restore int regs and return. */
+       popl    %ebp
+       popl    %edi
+       popl    %esi
+       popl    %edx
+       popl    %ecx
+       popl    %ebx
+       popl    %eax
+       ret
+/*----------------------------------------------------*/
+/*--- Continuation points                          ---*/
+/*----------------------------------------------------*/
+
+/* ------ Chain me to slow entry point ------ */
+.global VG_(disp_cp_chain_me_to_slowEP)
+VG_(disp_cp_chain_me_to_slowEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_S, RA) */
+        movl    $VG_TRC_CHAIN_ME_TO_SLOW_EP, %eax
+        popl    %edx
+        /* 5 = movl $VG_(disp_chain_me_to_slowEP), %edx;
+           2 = call *%edx */
+        subl    $5+2, %edx
+        jmp     postamble
+
+/* ------ Chain me to fast entry point ------ */
+.global VG_(disp_cp_chain_me_to_fastEP)
+VG_(disp_cp_chain_me_to_fastEP):
+        /* We got called.  The return address indicates
+           where the patching needs to happen.  Collect
+           the return address and, exit back to C land,
+           handing the caller the pair (Chain_me_F, RA) */
+        movl    $VG_TRC_CHAIN_ME_TO_FAST_EP, %eax
+        popl    %edx
+        /* 5 = movl $VG_(disp_chain_me_to_fastEP), %edx;
+           2 = call *%edx */
+        subl    $5+2, %edx
+        jmp     postamble
+
+/* ------ Indirect but boring jump ------ */
+.global VG_(disp_cp_xindir)
+VG_(disp_cp_xindir):
+       /* Where are we going? */
+       movl    OFFSET_x86_EIP(%ebp), %eax
+
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndirs_32)
+
+        /* try a fast lookup in the translation cache */
+        movl    %eax, %ebx                      /* next guest addr */
+        andl    $VG_TT_FAST_MASK, %ebx          /* entry# */
+        movl    0+VG_(tt_fast)(,%ebx,8), %esi   /* .guest */
+        movl    4+VG_(tt_fast)(,%ebx,8), %edi   /* .host */
+        cmpl    %eax, %esi
+        jnz     fast_lookup_failed
+
+        /* Found a match.  Jump to .host. */
+       jmp     *%edi
+       ud2     /* persuade insn decoders not to speculate past here */
+
+fast_lookup_failed:
+        /* stats only */
+        addl    $1, VG_(stats__n_xIndir_misses_32)
+
+       movl    $VG_TRC_INNER_FASTMISS, %eax
+        movl    $0, %edx
+       jmp     postamble
+
+/* ------ Assisted jump ------ */
+.global VG_(disp_cp_xassisted)
+VG_(disp_cp_xassisted):
+        /* %ebp contains the TRC */
+        movl    %ebp, %eax
+        movl    $0, %edx
+        jmp     postamble
+
+/* ------ Event check failed ------ */
+.global VG_(disp_cp_evcheck_fail)
+VG_(disp_cp_evcheck_fail):
+        movl   $VG_TRC_INNER_COUNTERZERO, %eax
+        movl    $0, %edx
+        jmp    postamble
+
+
+.size VG_(disp_run_translations), .-VG_(disp_run_translations)
+
+#endif // defined(VGP_x86_freebsd)
+
+/* Let the linker know we don't need an executable stack */
+MARK_STACK_NO_EXEC
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_initimg/initimg-freebsd.c b/coregrind/m_initimg/initimg-freebsd.c
new file mode 100644 (file)
index 0000000..d19186a
--- /dev/null
@@ -0,0 +1,979 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Startup: create initial process image on FreeBSD             ---*/
+/*---                                            initimg-freebsd.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2009 Julian Seward
+      jseward@acm.org
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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_threadstate.h"     /* ThreadArchState */
+#include "pub_core_pathscan.h"
+#include "pub_core_initimg.h"         /* self */
+
+/* --- !!! --- EXTERNAL HEADERS start --- !!! --- */
+/* This is for ELF types etc, and also the AT_ constants. */
+#include <elf.h>
+/* --- !!! --- 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 = VG_(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)
+{
+   vg_assert(origenv);
+   vg_assert(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)
+   const 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));
+   Bool   debug           = False;
+
+   HChar** cpp;
+   HChar** ret;
+   HChar*  preload_tool_path;
+   Int     envc, i;
+
+   /* Alloc space for the vgpreload_core.so path and vgpreload_<tool>.so
+      paths.  We might not need the space for vgpreload_<tool>.so, but it
+      doesn't hurt to over-allocate briefly.  The 16s are just cautious
+      slop. */
+   Int preload_core_path_len = vglib_len + sizeof(preload_core)
+                               + sizeof(VG_PLATFORM) + 16;
+   Int preload_tool_path_len = vglib_len + VG_(strlen)(toolname)
+                               + sizeof(VG_PLATFORM) + 16;
+   Int preload_string_len    = preload_core_path_len + preload_tool_path_len;
+   HChar* preload_string     = VG_(malloc)("initimg-freebsd.sce.1",
+                                           preload_string_len);
+   /* Determine if there's a vgpreload_<tool>_<platform>.so file, and setup
+      preload_string. */
+   preload_tool_path = VG_(malloc)("initimg-freebsd.sce.2", preload_tool_path_len);
+   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 */
+   if (debug) VG_(printf)("\n\n");
+   envc = 0;
+   for (cpp = origenv; cpp && *cpp; cpp++) {
+      envc++;
+      if (debug) VG_(printf)("XXXXXXXXX: BEFORE %s\n", *cpp);
+   }
+
+   /* Allocate a new space */
+   ret = VG_(malloc) ("initimg-freebsd.sce.3",
+                      sizeof(HChar *) * (envc+2+1)); /* 2 new entries + NULL */
+
+   /* copy it over */
+   for (cpp = ret; *origenv; ) {
+      if (debug) VG_(printf)("XXXXXXXXX: COPY   %s\n", *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_(snprintf)(cp, len, "%s%s:%s",
+                       ld_preload, preload_string, (*cpp)+ld_preload_len);
+
+         *cpp = cp;
+
+         ld_preload_done = True;
+      }
+      if (debug) VG_(printf)("XXXXXXXXX: MASH   %s\n", *cpp);
+   }
+
+   /* 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_(snprintf)(cp, len, "%s%s", ld_preload, preload_string);
+
+      ret[envc++] = cp;
+      if (debug) VG_(printf)("XXXXXXXXX: ADD    %s\n", 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;
+
+   for (i = 0; i < envc; i++) {
+      if (debug) VG_(printf)("XXXXXXXXX: FINAL  %s\n", ret[i]);
+   }
+
+   return ret;
+}
+
+
+/*====================================================================*/
+/*=== Setting up the client's stack                                ===*/
+/*====================================================================*/
+
+/* Add a string onto the string table, and return its address */
+static HChar *copy_str(HChar **tab, const HChar *str)
+{
+   HChar *cp = *tab;
+   HChar *orig = cp;
+
+   while(*str)
+      *cp++ = *str++;
+   *cp++ = '\0';
+
+   if (0)
+      VG_(printf)("copied %p \"%s\" len %lld\n", (void*)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.
+
+   ---------------------------------------------------------------- */
+
+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++;
+
+   return (struct auxv *)sp;
+}
+
+static
+Addr setup_client_stack( void*  init_sp,
+                         HChar** orig_envp,
+                         const ExeInfo* info,
+                         UInt** client_auxv,
+                         Addr   clstack_end,
+                         SizeT  clstack_max_size )
+{
+   SysRes res;
+   HChar **cpp;
+   HChar *strtab;    /* string table */
+   HChar *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(HChar **) : 0) +  /* argc[0] == exename */
+      sizeof(HChar **)*argc +                 /* argv */
+      sizeof(HChar **) +                      /* terminal NULL */
+      sizeof(HChar **)*envc +                 /* envp */
+      sizeof(HChar **) +                      /* terminal NULL */
+      auxsize +                               /* auxv */
+      VG_ROUNDUP(stringsize, sizeof(Word));   /* strings (aligned) */
+
+   if (0) VG_(printf)("stacksize = %u\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 = (HChar *)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);
+
+   if (0)
+      VG_(printf)("stringsize=%u auxsize=%u stacksize=%u maxsize=0x%lx\n"
+                  "clstack_start %p\n"
+                  "clstack_end   %p\n",
+                  stringsize, auxsize, stacksize, 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)(1);
+      }
+
+      vg_assert(ok);
+      vg_assert(!sr_isError(res));
+
+      /* Record stack extent -- needed for stack-change code. */
+      VG_(clstk_start_base) = anon_start -inner_HACK;
+      VG_(clstk_end)  = VG_(clstk_start_base) + anon_size +inner_HACK -1;
+
+   }
+
+   /* ==================== 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);
+   if (info->interp_args)
+      *ptr++ = (Addr)copy_str(&strtab, 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;
+#if defined(VGP_x86_freebsd)
+   int* pagesizes = NULL;
+#endif
+
+   /*
+    * The PAGESIZES hack - PJF
+    *
+    * Normally a standalone application has a full auxv which, among
+    * many other things contains a vector of integers (PAGESIZES)
+    * of a platform dependent length (PAGESIZESLEN). On x86 the
+    * length is 2, on amd64 the length is 3 (there are other lengths
+    * for architectures not supported on Valgrind).
+    *
+    * When the dynamic loader executes it will run a routine
+    * static void init_pagesizes(Elf_Auxinfo **aux_info)
+    * (see /usr/src/libexec/rtld-elf/rltd.c). If the PAGESIZES info is in
+    * auxv, init_pagesizes will use that. However, normally this loop
+    * does not copy 'pointered' elements (because that would generate
+    * 'Invalid reads' in the guest). This means that the auxv that
+    * Valgrind provides to ldrt *doesn't* normally contain
+    * PAGESIZES.
+    *
+    * So init_pagesizes falls back to using sysctlnametomib/sysctl
+    * to read "hw.pagesizes". Unfortunately there seems to be a bug
+    * in this for an x86 executable compiled and running on an amd64
+    * kernel.
+    *
+    * The application sees MAXPAGESLEN as 3 (from the amd64 headers)
+    * but the x86 kernel sees MAXPAGESLEN as 2. The routine that
+    * copies out the data for a sysctl sees this discrepancy and
+    * sets an ENOMEM error. So guest execution doesn't even get past
+    * executing the dynamic linker.
+    */
+
+   for (; orig_auxv->a_type != AT_NULL; auxv++, orig_auxv++) {
+
+      /* copy the entry... */
+      *auxv = *orig_auxv;
+
+      /*
+       *  ...and fix up / examine the copy
+       * in general there are thee possibilities for these items
+       * 1. copy it, a common case for scalars
+       * 2. synthesize, if the value that the host gets isn't what we want
+       * 3. ignore, usually the case for pointers to memory for the host
+       *    the ignored items are just left commented out
+       */
+      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:
+      case AT_STACKPROT:
+      case AT_NCPUS:
+      case AT_OSRELDATE:
+#if (FREEBSD_VERS >= FREEBSD_11)
+      // FreeBSD 11+ also have HWCAP and HWCAP2
+      case AT_EHDRFLAGS:
+#endif
+         /* All these are pointerless, so we don't need to do
+            anything about them. */
+         break;
+         // case AT_CANARYLEN:
+         // case AT_EXECPATH:
+         // case AT_CANARY:
+#if defined(VGP_x86_freebsd)
+      case AT_PAGESIZESLEN:
+         if (!VG_(is32on64)()) {
+            VG_(debugLog)(2, "initimg",
+                          "stomping auxv entry %llu\n",
+                          (ULong)auxv->a_type);
+            auxv->a_type = AT_IGNORE;
+         }
+         break;
+      case AT_PAGESIZES:
+         if (VG_(is32on64)()) {
+            pagesizes = VG_(malloc)("initimg-freebsd.cpauxv.1", 2*sizeof(int));
+            pagesizes[0] = ((int*)auxv->u.a_ptr)[0];
+            pagesizes[1] = ((int*)auxv->u.a_ptr)[1];
+         } else {
+            VG_(debugLog)(2, "initimg",
+                          "stomping auxv entry %llu\n",
+                          (ULong)auxv->a_type);
+            auxv->a_type = AT_IGNORE;
+         }
+         break;
+#endif
+         // case AT_TIMEKEEP:
+         break;
+
+#if (FREEBSD_VERS >= FREEBSD_13)
+      case AT_BSDFLAGS:
+      case AT_ARGC:
+      // case AT_ARGV:
+      case AT_ENVC:
+         // case AT_ENVV:
+         // case AT_PS_STRINGS:
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_14)
+         // case AT_FXRNG:
+#endif
+
+      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 %llu\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);
+
+   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 = {
+      .clstack_max_size = 0,
+      .initial_client_SP = 0,
+      .initial_client_IP = 0,
+      .initial_client_TOC = 0,
+      .client_auxv = NULL,
+      .arch_elf_state = VKI_INIT_ARCH_ELF_STATE,
+   };
+
+   //--------------------------------------------------------------
+   // 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)();
+
+   VG_(memset)(&info, 0, sizeof(info));
+
+   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, 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 %lu\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=%lu\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 );
+   }
+
+   VG_(free)(info.interp_name);
+   info.interp_name = NULL;
+   VG_(free)(info.interp_args);
+   info.interp_args = NULL;
+   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;
+
+   /* 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_sigframe/sigframe-amd64-freebsd.c b/coregrind/m_sigframe/sigframe-amd64-freebsd.c
new file mode 100644 (file)
index 0000000..997cf77
--- /dev/null
@@ -0,0 +1,432 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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_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;
+
+   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 *ucp, struct _vki_fpstate *fpstate)
+{
+   ThreadState *tst = VG_(get_ThreadState)(tid);
+   struct vki_mcontext *sc = &ucp->uc_mcontext;
+
+   VG_(memset)(ucp, 0, sizeof(*ucp));
+
+   ucp->uc_flags = 0;
+   ucp->uc_link = 0;
+   ucp->uc_sigmask = *set;
+   ucp->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->ownedfp = VKI_FPOWNED_NONE;
+   sc->len = sizeof(*sc);
+   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 %u:\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) - 8;
+   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->retaddr = (Addr)&VG_(amd64_freebsd_SUBST_FOR_sigreturn);
+
+   if (siguc) {
+      trapno = siguc->uc_mcontext.trapno;
+      err = siguc->uc_mcontext.err;
+   } else {
+      trapno = 0;
+      err = 0;
+   }
+
+   VG_(memcpy)(&frame->sigInfo, siginfo, sizeof(vki_siginfo_t));
+
+   if (sigNo == VKI_SIGILL && siginfo->si_code > 0)
+      frame->sigInfo.si_addr = (void*)tst->arch.vex.guest_RIP;
+
+   synth_ucontext(tst->tid, siginfo, trapno, err, mask,
+                  &frame->uContext, &frame->fpstate);
+
+   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;
+   /* And tell the tool that these registers have been written. */
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
+             offsetof(VexGuestAMD64State,guest_RIP), sizeof(UWord) );
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
+             offsetof(VexGuestAMD64State,guest_RDI), sizeof(UWord) );
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
+             offsetof(VexGuestAMD64State,guest_RSI), sizeof(UWord) );
+   VG_TRACK( post_reg_write, Vg_CoreSignal, tst->tid,
+             offsetof(VexGuestAMD64State,guest_RDX), sizeof(UWord) );
+
+   /* 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 %u 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 %u): 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-x86-freebsd.c b/coregrind/m_sigframe/sigframe-x86-freebsd.c
new file mode 100644 (file)
index 0000000..a1d8638
--- /dev/null
@@ -0,0 +1,457 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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;
+
+   /*
+    * The following 7 members are roughly the same as
+    * 'stuct sigframe' in x86/sigrame.h
+    */
+   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 %u:\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;
+}
+
+/*
+ * According to the comments in lib/libc/i386/gen/signalcontext.c
+ * the stack sould look like this [where n = 4 = sizeof(int)]
+ *
+ * 2n+sizeof(struct sigframe) ucp
+ * 2n          struct sigframe
+ * 1n          &func
+ * 0n          &_ctx_start
+ *
+ * Note that the 'struct sigframe' above is the one defined in FreeBSD.
+ * 5 word members + ucontext + siginfo
+ *
+ * 'struct sigframe' below is the one defined in this file:
+ *
+ * Addr
+ * FreeBSD struct sigfame
+ * fpstate
+ * vg_sigframe
+ *
+ */
+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;
+
+#if defined(__clang__)
+   esp -= 4;
+   esp = VG_ROUNDDN(esp, 16);
+   esp -= sizeof(*frame) + 4;
+#else
+   esp -= sizeof(*frame);
+   esp = VG_ROUNDDN(esp, 16);
+#endif
+
+   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;
+   struct sigframe *frame;
+   ThreadState* tst = VG_(get_ThreadState)(tid);
+
+   esp = build_sigframe(tst, esp_top_of_frame, siginfo, siguc, handler,
+                        flags, mask, restorer);
+   frame = (struct sigframe *)esp;
+
+   /* 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;
+   tst->arch.vex.guest_ESI = (Addr) &frame->sigInfo;
+   tst->arch.vex.guest_EDX = (Addr) &frame->uContext;
+   /* 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=%u\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 %u 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 %u): 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_syswrap/priv_syswrap-freebsd.h b/coregrind/m_syswrap/priv_syswrap-freebsd.h
new file mode 100644 (file)
index 0000000..348a7fc
--- /dev/null
@@ -0,0 +1,554 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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" */
+#include "priv_types_n_macros.h"
+#include "config.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) // 1
+DECL_TEMPLATE(freebsd, sys_fork) // 2
+// generic read 3
+// generic write 4
+// generic open 5
+// generic close 6
+// generic wait4 7
+// generic link 9
+// generic unlink 10
+// generic chdir 12
+// generic fchdir 13
+// generic mknod 14
+// generic chmod 15
+// generic chown 16
+// generic brk 17
+DECL_TEMPLATE(freebsd, sys_mount) // 21
+DECL_TEMPLATE(freebsd, sys_unmount) // 22
+DECL_TEMPLATE(freebsd, sys_ptrace) // 26
+DECL_TEMPLATE(freebsd, sys_recvmsg) // 27
+DECL_TEMPLATE(freebsd, sys_sendmsg) // 28
+DECL_TEMPLATE(freebsd, sys_recvfrom) // 29
+DECL_TEMPLATE(freebsd, sys_accept) // 30
+DECL_TEMPLATE(freebsd, sys_getpeername) // 31
+DECL_TEMPLATE(freebsd, sys_getsockname) // 32
+// generic access 33
+DECL_TEMPLATE(freebsd, sys_chflags) // 34
+DECL_TEMPLATE(freebsd, sys_fchflags) // 35
+// generic sync 36
+// generic kill 37
+// generic getppid 39
+// generic dup 41
+DECL_TEMPLATE(freebsd, sys_pipe) // 42
+// generic getegid 43
+// generic profil redirect to ni_syscall 44
+// sys_ktrace refirect to ni_syscall 45
+// generic getgid 47
+DECL_TEMPLATE(freebsd, sys_getlogin) // 49
+DECL_TEMPLATE(freebsd, sys_setlogin) // 50
+// generic acct 51
+// generic sigaltstack 53
+DECL_TEMPLATE(freebsd, sys_ioctl) // 54
+DECL_TEMPLATE(freebsd, sys_reboot) // 55
+DECL_TEMPLATE(freebsd, sys_revoke) // 56
+// generic symlink 57
+// generic readlink 58
+// generic execve 59
+// generic umask 60
+// generic chroot 61
+// generic msync 65
+DECL_TEMPLATE(freebsd, sys_vfork) // 66
+DECL_TEMPLATE(freebsd, sys_sbrk) // 69
+
+// freebsd11 vadvise 72
+// generic munmap 73
+// generic mprotect 74
+// generic madvise 75
+// generic mincore 78
+// generic getgroups 79
+// generic setgroups 80
+// generic getpgrp 81
+// generic setpgid 82
+// generic setitimer 83
+
+DECL_TEMPLATE(freebsd, sys_swapon) // 85
+// generic getitimer 86
+DECL_TEMPLATE(freebsd, sys_getdtablesize) // 90
+DECL_TEMPLATE(freebsd, sys_fcntl) // 92
+// generic select 93
+// generic fsync 95
+// generic setpriority 96
+DECL_TEMPLATE(freebsd, sys_socket) // 97
+DECL_TEMPLATE(freebsd, sys_connect) // 98
+// generic getpriority 100
+DECL_TEMPLATE(freebsd, sys_bind) // 104
+DECL_TEMPLATE(freebsd, sys_setsockopt) // 105
+DECL_TEMPLATE(freebsd, sys_listen) // 106
+// generic gettimeofday 116
+// generic rusage 117
+DECL_TEMPLATE(freebsd, sys_getsockopt) // 118
+
+// generic readv 120
+// generic writev 121
+// generic settimeofday 122
+// generic fchown 123
+// generic fchmod 124
+// generic setreuid 126
+// generic setregid 127
+// generic rename 128
+// generic flock 131
+DECL_TEMPLATE(freebsd, sys_mkfifo) // 132
+DECL_TEMPLATE(freebsd, sys_sendto) // 133
+DECL_TEMPLATE(freebsd, sys_shutdown) // 134
+DECL_TEMPLATE(freebsd, sys_socketpair) // 135
+// generic mkdir 136
+// generic rmdir 137
+// generic utims 138
+DECL_TEMPLATE(freebsd, sys_adjtime) // 140
+// generic setsid 147
+DECL_TEMPLATE(freebsd, sys_quotactl) // 148
+// unimp nlm_syscall 154
+//DECL_TEMPLATE(freebsd, sys_nfssvc) 155
+DECL_TEMPLATE(freebsd, sys_lgetfh) // 160
+DECL_TEMPLATE(freebsd, sys_getfh) // 161
+#if (FREEBSD_VERS <= FREEBSD_10)
+DECL_TEMPLATE(freebsd, sys_freebsd4_getdomainname) // 162
+DECL_TEMPLATE(freebsd, sys_freebsd4_setdomainname) // 163
+DECL_TEMPLATE(freebsd, sys_freebsd4_uname) // 164
+#endif
+DECL_TEMPLATE(freebsd, sys_sysarch) // 165
+DECL_TEMPLATE(freebsd, sys_rtprio) // 166
+//DECL_TEMPLATE(freebsd, sys_semsys) 169
+//DECL_TEMPLATE(freebsd, sys_msgsys) 170
+//DECL_TEMPLATE(freebsd, sys_shmsys) 171
+#if (FREEBSD_VERS <= FREEBSD_10)
+DECL_TEMPLATE(freebsd, sys_freebsd6_pread) // 173
+DECL_TEMPLATE(freebsd, sys_freebsd6_pwrite) // 174
+#endif
+DECL_TEMPLATE(freebsd, sys_setfib) // 175
+//DECL_TEMPLATE(freebsd, sys_ntp_adjtime) 176
+// generic setgid 181
+DECL_TEMPLATE(freebsd, sys_setegid) // 182
+DECL_TEMPLATE(freebsd, sys_seteuid) // 183
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_stat) // 188
+DECL_TEMPLATE(freebsd, sys_freebsd11_fstat) // 189
+DECL_TEMPLATE(freebsd, sys_freebsd11_lstat)// 190
+#else
+DECL_TEMPLATE(freebsd, sys_stat) // 188
+DECL_TEMPLATE(freebsd, sys_fstat) // 189
+DECL_TEMPLATE(freebsd, sys_lstat) // 190
+#endif
+DECL_TEMPLATE(freebsd, sys_pathconf) // 191
+DECL_TEMPLATE(freebsd, sys_fpathconf) // 192
+// generic getrlimit 194
+// generic setrlimit 195
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_getdirentries) // 196
+#else
+DECL_TEMPLATE(freebsd, sys_getdirentries) // 196
+#endif
+
+#if (FREEBSD_VERS <= FREEBSD_10)
+DECL_TEMPLATE(freebsd, sys_freebsd6_mmap) // 197
+#endif
+
+#if (FREEBSD_VERS <= FREEBSD_10)
+DECL_TEMPLATE(freebsd, sys_freebsd6_lseek) // 199
+DECL_TEMPLATE(freebsd, sys_freebsd6_truncate) // 200
+DECL_TEMPLATE(freebsd, sys_freebsd6_ftruncate) // 201
+#endif
+DECL_TEMPLATE(freebsd, sys___sysctl) // 202
+// generic mlock 202
+// generic munlock 203
+DECL_TEMPLATE(freebsd, sys_undelete) // 205
+DECL_TEMPLATE(freebsd, sys_futimes) // 206
+// generic getpgod 207
+// generic poll 209
+DECL_TEMPLATE(freebsd, sys_freebsd7___semctl) // 220
+DECL_TEMPLATE(freebsd, sys_semget) // 221
+DECL_TEMPLATE(freebsd, sys_semop) // 222
+DECL_TEMPLATE(freebsd, sys_freebsd7_msgctl) // 224
+DECL_TEMPLATE(freebsd, sys_msgget) // 225
+DECL_TEMPLATE(freebsd, sys_msgsnd) // 226
+DECL_TEMPLATE(freebsd, sys_msgrcv) // 227
+DECL_TEMPLATE(freebsd, sys_shmat) // 228
+DECL_TEMPLATE(freebsd, sys_freebsd7_shmctl) // 229
+DECL_TEMPLATE(freebsd, sys_shmdt) // 230
+DECL_TEMPLATE(freebsd, sys_shmget) // 231
+DECL_TEMPLATE(freebsd, sys_clock_gettime) // 232
+DECL_TEMPLATE(freebsd, sys_clock_settime) // 233
+DECL_TEMPLATE(freebsd, sys_clock_getres) // 234
+DECL_TEMPLATE(freebsd, sys_timer_create) // 235
+DECL_TEMPLATE(freebsd, sys_timer_delete) // 236
+DECL_TEMPLATE(freebsd, sys_timer_settime) // 237
+DECL_TEMPLATE(freebsd, sys_timer_gettime) // 238
+DECL_TEMPLATE(freebsd, sys_timer_getoverrun) // 239
+// generic sys_nanosleep 240
+// unimpl ffclock_getcounter 241
+// unimpl ffclock_setestimate 242
+// unimpl ffclock_getestimate 243
+DECL_TEMPLATE(freebsd, sys_clock_nanosleep) // 244
+// unimpl clock_getcpuclockid2 247
+// unimpl ntp_gettime 248
+DECL_TEMPLATE(freebsd, sys_minherit) // 250
+DECL_TEMPLATE(freebsd, sys_rfork) // 251
+DECL_TEMPLATE(freebsd, sys_issetugid) // 253
+// generic lchown 254
+DECL_TEMPLATE(freebsd, sys_aio_read) // 255
+DECL_TEMPLATE(freebsd, sys_aio_write) // 256
+DECL_TEMPLATE(freebsd, sys_lio_listio) // 257
+// generic sys_getdents 272
+DECL_TEMPLATE(freebsd, sys_lchmod) // 274
+DECL_TEMPLATE(freebsd, sys_lutimes) // 276
+
+// unimpl freebsd11_nstat 278
+// unimpl freebsd11_nfstat 279
+// unimpl freebsd11_nlstat 280
+DECL_TEMPLATE(freebsd, sys_preadv) // 289
+DECL_TEMPLATE(freebsd, sys_pwritev) // 290
+
+DECL_TEMPLATE(freebsd, sys_fhopen) // 298
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_fhstat) // 299
+#else
+DECL_TEMPLATE(freebsd, sys_fhstat) // 299
+#endif
+
+DECL_TEMPLATE(freebsd, sys_modnext) // 300
+DECL_TEMPLATE(freebsd, sys_modstat) // 301
+DECL_TEMPLATE(freebsd, sys_modfnext) // 302
+DECL_TEMPLATE(freebsd, sys_modfind) // 303
+
+DECL_TEMPLATE(freebsd, sys_kldload) // 304
+DECL_TEMPLATE(freebsd, sys_kldunload) // 305
+DECL_TEMPLATE(freebsd, sys_kldfind) // 306
+DECL_TEMPLATE(freebsd, sys_kldnext) // 307
+DECL_TEMPLATE(freebsd, sys_kldstat) // 308
+DECL_TEMPLATE(freebsd, sys_kldfirstmod) // 309
+DECL_TEMPLATE(freebsd, sys_setresuid) // 311
+DECL_TEMPLATE(freebsd, sys_setresgid) // 312
+DECL_TEMPLATE(freebsd, sys_aio_return) //314
+DECL_TEMPLATE(freebsd, sys_aio_suspend) // 315
+DECL_TEMPLATE(freebsd, sys_aio_cancel) // 316
+DECL_TEMPLATE(freebsd, sys_aio_error) // 317
+DECL_TEMPLATE(freebsd, sys_yield) // 321
+DECL_TEMPLATE(freebsd, sys_munlockall) // 325
+DECL_TEMPLATE(freebsd, sys___getcwd) // 326
+DECL_TEMPLATE(freebsd, sys_sched_setparam) // 327
+DECL_TEMPLATE(freebsd, sys_sched_getparam) // 328
+DECL_TEMPLATE(freebsd, sys_sched_setscheduler) // 329
+DECL_TEMPLATE(freebsd, sys_sched_getscheduler) // 330
+DECL_TEMPLATE(freebsd, sys_sched_yield) // 331
+DECL_TEMPLATE(freebsd, sys_sched_get_priority_max) // 332
+DECL_TEMPLATE(freebsd, sys_sched_get_priority_min) // 333
+DECL_TEMPLATE(freebsd, sys_sched_rr_get_interval) // 334
+DECL_TEMPLATE(freebsd, sys_utrace) // 335
+DECL_TEMPLATE(freebsd, sys_kldsym) // 337
+DECL_TEMPLATE(freebsd, sys_jail) // 338
+// unimpl SYS_nnpfs_syscall 339
+DECL_TEMPLATE(freebsd, sys_sigprocmask) // 340
+DECL_TEMPLATE(freebsd, sys_sigsuspend) // 341
+
+DECL_TEMPLATE(freebsd, sys_sigpending) // 343
+
+DECL_TEMPLATE(freebsd, sys_sigtimedwait) // 345
+DECL_TEMPLATE(freebsd, sys_sigwaitinfo) // 346
+DECL_TEMPLATE(freebsd, sys___acl_get_file) // 347
+DECL_TEMPLATE(freebsd, sys___acl_set_file) // 348
+DECL_TEMPLATE(freebsd, sys___acl_get_fd) // // 349
+DECL_TEMPLATE(freebsd, sys___acl_set_fd) // 350
+DECL_TEMPLATE(freebsd, sys___acl_delete_file) // 351
+DECL_TEMPLATE(freebsd, sys___acl_delete_fd) // 352
+DECL_TEMPLATE(freebsd, sys___acl_aclcheck_file) // 353
+DECL_TEMPLATE(freebsd, sys___acl_aclcheck_fd) // 354
+
+DECL_TEMPLATE(freebsd, sys_extattrctl) // 355
+DECL_TEMPLATE(freebsd, sys_extattr_set_file) // 356
+DECL_TEMPLATE(freebsd, sys_extattr_get_file) // 357
+DECL_TEMPLATE(freebsd, sys_extattr_delete_file) // 358
+DECL_TEMPLATE(freebsd, sys_aio_waitcomplete) // 350
+DECL_TEMPLATE(freebsd, sys_getresuid) // 360
+DECL_TEMPLATE(freebsd, sys_getresgid) // 361
+DECL_TEMPLATE(freebsd, sys_kqueue) // 362
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_kevent) // 363
+#else
+DECL_TEMPLATE(freebsd, sys_kevent) // 363
+#endif
+DECL_TEMPLATE(freebsd, sys_extattr_set_fd) // 371
+DECL_TEMPLATE(freebsd, sys_extattr_get_fd) // 372
+DECL_TEMPLATE(freebsd, sys_extattr_delete_fd) // 373
+DECL_TEMPLATE(freebsd, sys___setugid) // 374
+DECL_TEMPLATE(freebsd, sys_eaccess) // 376
+// unimpl afs3_syscall 377
+DECL_TEMPLATE(freebsd, sys_nmount) // 378
+// unimpl __mac_get_proc 384
+// unimpl __mac_set_proc 385
+// unimpl __mac_get_fd 386
+// unimpl __mac_get_file 387
+// unimpl __mac_set_fd 388
+// unimpl __mac_set_file 389
+DECL_TEMPLATE(freebsd, sys_kenv) // 390
+DECL_TEMPLATE(freebsd, sys_lchflags) // 391
+DECL_TEMPLATE(freebsd, sys_uuidgen) // 392
+DECL_TEMPLATE(freebsd, sys_sendfile)  // 292
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_getfsstat) // 395
+DECL_TEMPLATE(freebsd, sys_freebsd11_statfs) // 396
+DECL_TEMPLATE(freebsd, sys_freebsd11_fstatfs) // 397
+DECL_TEMPLATE(freebsd, sys_freebsd11_fhstatfs) // 398
+#else
+DECL_TEMPLATE(freebsd, sys_getfsstat) // 395
+DECL_TEMPLATE(freebsd, sys_statfs) // 396
+DECL_TEMPLATE(freebsd, sys_fstatfs) // 397
+DECL_TEMPLATE(freebsd, sys_fhstatfs) // 398
+#endif
+
+// unimpl ksem_close 400
+// unimpl ksem_post 401
+// unimpl ksem_wait 402
+// unimpl ksem_trywait 403
+
+// unimpl ksem_init 404
+// unimpl ksem_open 405
+// unimpl ksem_unlink 406
+// unimpl ksem_getvalue 407
+
+// unimpl ksem_destroy 408
+// unimpl __mac_get_pid 409
+// unimpl __mac_get_link 410
+// unimpl __mac_set_link 411
+
+DECL_TEMPLATE(freebsd, sys_extattr_set_link) // 412
+DECL_TEMPLATE(freebsd, sys_extattr_get_link) // 413
+DECL_TEMPLATE(freebsd, sys_extattr_delete_link) // 414
+// unimpl __mac_execve 415
+
+DECL_TEMPLATE(freebsd, sys_sigaction) // 416
+DECL_TEMPLATE(freebsd, sys_sigreturn) // 417
+DECL_TEMPLATE(freebsd, sys_getcontext) // 421
+DECL_TEMPLATE(freebsd, sys_setcontext) // 422
+DECL_TEMPLATE(freebsd, sys_swapcontext) // 423
+DECL_TEMPLATE(freebsd, sys_swapoff) // 424
+DECL_TEMPLATE(freebsd, sys___acl_get_link) // 425
+DECL_TEMPLATE(freebsd, sys___acl_set_link) // 426
+DECL_TEMPLATE(freebsd, sys___acl_delete_link) // 427
+DECL_TEMPLATE(freebsd, sys___acl_aclcheck_link) // 428
+DECL_TEMPLATE(freebsd, sys_sigwait) // 429
+DECL_TEMPLATE(freebsd, sys_thr_create) // 430
+DECL_TEMPLATE(freebsd, sys_thr_exit) // 431
+DECL_TEMPLATE(freebsd, sys_thr_self) // 432
+DECL_TEMPLATE(freebsd, sys_thr_kill) // 433
+DECL_TEMPLATE(freebsd, sys__umtx_lock) // 434
+DECL_TEMPLATE(freebsd, sys__umtx_unlock) // 435
+DECL_TEMPLATE(freebsd, sys_jail_attach) // 436
+DECL_TEMPLATE(freebsd, sys_extattr_list_fd) // 437
+DECL_TEMPLATE(freebsd, sys_extattr_list_file) // 438
+DECL_TEMPLATE(freebsd, sys_extattr_list_link) // 439
+// unimpl ksem_timedwait 441
+DECL_TEMPLATE(freebsd, sys_thr_suspend) // 442
+DECL_TEMPLATE(freebsd, sys_thr_wake) // 443
+DECL_TEMPLATE(freebsd, sys_kldunloadf) // 444
+// unimpl audit 445
+// unimpl auditon 446
+// unimpl getauid 447
+// unimpl setauid 448
+// unimpl getaudit 449
+// unimpl setaudit 450
+// unimpl getaudit_addr 451
+// unimpl setaudit_addr 452
+// unimpl auditctl 453
+DECL_TEMPLATE(freebsd, sys__umtx_op) // 454
+DECL_TEMPLATE(freebsd, sys_thr_new) // 455
+DECL_TEMPLATE(freebsd, sys_sigqueue) // 455
+DECL_TEMPLATE(freebsd, sys_kmq_open) // 457
+DECL_TEMPLATE(freebsd, sys_kmq_setattr) // 458
+DECL_TEMPLATE(freebsd, sys_kmq_timedreceive) // 459
+DECL_TEMPLATE(freebsd, sys_kmq_timedsend) // 460
+DECL_TEMPLATE(freebsd, sys_kmq_notify) // 461
+DECL_TEMPLATE(freebsd, sys_kmq_unlink) // 462
+DECL_TEMPLATE(freebsd, sys_abort2) // 463
+DECL_TEMPLATE(freebsd, sys_thr_set_name) // 464
+DECL_TEMPLATE(freebsd, sys_aio_fsync) // 465
+DECL_TEMPLATE(freebsd, sys_rtprio_thread) // 466
+DECL_TEMPLATE(freebsd, sys_pread) // 475
+DECL_TEMPLATE(freebsd, sys_pwrite) // 476
+DECL_TEMPLATE(freebsd, sys_mmap) // 477
+DECL_TEMPLATE(freebsd, sys_lseek) // 478
+DECL_TEMPLATE(freebsd, sys_truncate) // 479
+DECL_TEMPLATE(freebsd, sys_ftruncate) // 480
+DECL_TEMPLATE(freebsd, sys_thr_kill2) // 481
+DECL_TEMPLATE(freebsd, sys_shm_open) // 482
+DECL_TEMPLATE(freebsd, sys_shm_unlink) // 483
+DECL_TEMPLATE(freebsd, sys_cpuset) // 484
+DECL_TEMPLATE(freebsd, sys_cpuset_setid) // 485
+DECL_TEMPLATE(freebsd, sys_cpuset_getid) // 486
+DECL_TEMPLATE(freebsd, sys_cpuset_getaffinity) // 487
+DECL_TEMPLATE(freebsd, sys_cpuset_setaffinity) // 488
+DECL_TEMPLATE(freebsd, sys_faccessat) // 489
+DECL_TEMPLATE(freebsd, sys_fchmodat) //490
+DECL_TEMPLATE(freebsd, sys_fchownat) // 491
+DECL_TEMPLATE(freebsd, sys_fexecve) // 492
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_fstatat) // 493
+#else
+DECL_TEMPLATE(freebsd, sys_fstatat) // 493
+#endif
+DECL_TEMPLATE(freebsd, sys_futimesat) // 494
+DECL_TEMPLATE(freebsd, sys_linkat) // 495
+DECL_TEMPLATE(freebsd, sys_mkdirat) // 496
+DECL_TEMPLATE(freebsd, sys_mkfifoat) // 497
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+DECL_TEMPLATE(freebsd, sys_freebsd11_mknodat) // 498
+#else
+DECL_TEMPLATE(freebsd, sys_mknodat) // 498
+#endif
+
+DECL_TEMPLATE(freebsd, sys_openat) // 499
+DECL_TEMPLATE(freebsd, sys_readlinkat) // 500
+DECL_TEMPLATE(freebsd, sys_renameat) // 501
+DECL_TEMPLATE(freebsd, sys_symlinkat) // 502
+DECL_TEMPLATE(freebsd, sys_unlinkat) // 503
+DECL_TEMPLATE(freebsd, sys_posix_openpt) // 504
+// unimp gssd_syscall 505
+DECL_TEMPLATE(freebsd, sys_jail_get) // 506
+DECL_TEMPLATE(freebsd, sys_jail_set) // 507
+DECL_TEMPLATE(freebsd, sys_jail_remove) // 508
+DECL_TEMPLATE(freebsd, sys_closefrom) // 508
+DECL_TEMPLATE(freebsd, sys___semctl) // 510
+DECL_TEMPLATE(freebsd, sys_msgctl) // 511
+DECL_TEMPLATE(freebsd, sys_shmctl) // 512
+DECL_TEMPLATE(freebsd, sys_lpathconf) // 513
+DECL_TEMPLATE(freebsd, sys_cap_rights_get) // 515
+DECL_TEMPLATE(freebsd, sys_cap_enter) // 516
+DECL_TEMPLATE(freebsd, sys_cap_getmode) // 517
+DECL_TEMPLATE(freebsd, sys_pdfork) // 518
+DECL_TEMPLATE(freebsd, sys_pdkill) // 519
+DECL_TEMPLATE(freebsd, sys_pdgetpid) // 520
+DECL_TEMPLATE(freebsd, sys_pselect) // 522
+DECL_TEMPLATE(freebsd, sys_getloginclass) // 523
+DECL_TEMPLATE(freebsd, sys_setloginclass) // 524
+DECL_TEMPLATE(freebsd, sys_rctl_get_racct) // 525
+DECL_TEMPLATE(freebsd, sys_rctl_get_rules) // 526
+DECL_TEMPLATE(freebsd, sys_rctl_get_limits) // 527
+DECL_TEMPLATE(freebsd, sys_rctl_add_rule) // 528
+DECL_TEMPLATE(freebsd, sys_rctl_remove_rule) // 529
+DECL_TEMPLATE(freebsd, sys_posix_fallocate) // 530
+DECL_TEMPLATE(freebsd, sys_posix_fadvise) // 531
+DECL_TEMPLATE(freebsd, sys_wait6) // 532
+DECL_TEMPLATE(freebsd, sys_cap_rights_limit) // 533
+DECL_TEMPLATE(freebsd, sys_cap_ioctls_limit) // 534
+DECL_TEMPLATE(freebsd, sys_cap_ioctls_get) // 535
+DECL_TEMPLATE(freebsd, sys_cap_fcntls_limit) // 536
+DECL_TEMPLATE(freebsd, sys_cap_fcntls_get) // 537
+DECL_TEMPLATE(freebsd, sys_bindat) // 538
+DECL_TEMPLATE(freebsd, sys_connectat) // 539
+DECL_TEMPLATE(freebsd, sys_chflagsat) // 540
+DECL_TEMPLATE(freebsd, sys_accept4) // 541
+DECL_TEMPLATE(freebsd, sys_pipe2) // 542
+DECL_TEMPLATE(freebsd, sys_aio_mlock) // 543
+DECL_TEMPLATE(freebsd, sys_procctl) // 544
+DECL_TEMPLATE(freebsd, sys_ppoll) // 545
+DECL_TEMPLATE(freebsd, sys_futimens) // 546
+DECL_TEMPLATE(freebsd, sys_utimensat) // 547
+DECL_TEMPLATE(freebsd, sys_fdatasync) // 550
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+
+DECL_TEMPLATE(freebsd, sys_fstat) // 551
+DECL_TEMPLATE(freebsd, sys_fstatat) // 552
+DECL_TEMPLATE(freebsd, sys_fhstat) // 553
+DECL_TEMPLATE(freebsd, sys_getdirentries) // 554
+DECL_TEMPLATE(freebsd, sys_statfs) // 555
+DECL_TEMPLATE(freebsd, sys_fstatfs) // 556
+DECL_TEMPLATE(freebsd, sys_getfsstat) // 557
+DECL_TEMPLATE(freebsd, sys_fhstatfs) // 558
+DECL_TEMPLATE(freebsd, sys_mknodat) // 559
+DECL_TEMPLATE(freebsd, sys_kevent) // 560
+DECL_TEMPLATE(freebsd, sys_cpuset_getdomain) // 561
+DECL_TEMPLATE(freebsd, sys_cpuset_setdomain) // 562
+DECL_TEMPLATE(freebsd, sys_getrandom) // 563
+DECL_TEMPLATE(freebsd, sys_getfhat) // 654
+DECL_TEMPLATE(freebsd, sys_fhlink) // 565
+DECL_TEMPLATE(freebsd, sys_fhlinkat) // 566
+DECL_TEMPLATE(freebsd, sys_fhreadlink) // 567
+
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_12_2)
+
+// unimpl __NR_funlinkat           568
+// unimpl __NR_copy_file_range     569
+DECL_TEMPLATE(freebsd, sys___sysctlbyname) // 570
+// unimpl __NR_shm_open2           571
+// unimpl __NR_shm_rename          572
+// unimpl __NR_sigfastblock        573
+// unimpl __NR___realpathat        574
+// unimpl __NR_close_range         575
+
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_13)
+
+// unimpl __NR_rpctls_syscall      576
+
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_14)
+
+// unimpl __NR___specialfd         577
+// unimpl __NR_aio_writev          578
+// unimpl __NR_aio_readv           579
+
+#endif
+
+DECL_TEMPLATE(freebsd, sys_fake_sigreturn)
+
+#endif   // PRIV_SYSWRAP_FREEBSD_H
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-amd64-freebsd.S b/coregrind/m_syswrap/syscall-amd64-freebsd.S
new file mode 100644 (file)
index 0000000..4143719
--- /dev/null
@@ -0,0 +1,207 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+  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, see <http://www.gnu.org/licenses/>.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+#if defined(VGP_amd64_freebsd)
+
+#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) */
+
+/* Let the linker know we don't need an executable stack */
+MARK_STACK_NO_EXEC
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syscall-x86-freebsd.S b/coregrind/m_syswrap/syscall-x86-freebsd.S
new file mode 100644 (file)
index 0000000..9437a34
--- /dev/null
@@ -0,0 +1,201 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+  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, see <http://www.gnu.org/licenses/>.
+
+  The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "pub_core_basics_asm.h"
+
+#if defined(VGP_x86_freebsd)
+
+#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)
+
+/* Let the linker know we don't need an executable stack */
+MARK_STACK_NO_EXEC
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-amd64-freebsd.c b/coregrind/m_syswrap/syswrap-amd64-freebsd.c
new file mode 100644 (file)
index 0000000..24226fa
--- /dev/null
@@ -0,0 +1,1113 @@
+
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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_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)
+
+// SYS_sysarch 165
+// int sysarch(int number, void *args);
+PRE(sys_sysarch)
+{
+   ThreadState *tst;
+   void **p;
+
+   PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", 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);
+
+      if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) {
+         /* 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 );
+      } else {
+         // ????
+         SET_STATUS_Failure( VKI_EINVAL );
+      }
+
+      break;
+   case VKI_AMD64_GET_FSBASE:
+      PRINT("sys_amd64_get_fsbase ( %#lx )", ARG2);
+      PRE_MEM_WRITE( "amd64_get_fsbase(basep)", ARG2, sizeof(void *) );
+      if (ML_(safe_to_deref)((void**)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 );
+      } else {
+         SET_STATUS_Failure( VKI_EINVAL );
+      }
+      break;
+   case VKI_AMD64_GET_XFPUSTATE:
+      PRINT("sys_amd64_get_xfpustate ( %#lx )", ARG2);
+      PRE_MEM_WRITE( "amd64_get_xfpustate(basep)", ARG2, sizeof(void *) );
+
+      // @todo PJF need a test for this
+      // I think that it will fail in the POST if ARG2 is not a valid pointer
+
+      /* "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] );
+      break;
+   default:
+      VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1);
+      VG_(unimplemented) ("unhandled sysarch cmd");
+      break;
+   }
+}
+
+POST(sys_sysarch)
+{
+   switch (ARG1) {
+   case VKI_AMD64_SET_FSBASE:
+      break;
+   case VKI_AMD64_GET_FSBASE:
+      POST_MEM_WRITE( ARG2, sizeof(void *) );
+      break;
+   case VKI_AMD64_GET_XFPUSTATE:
+      POST_MEM_WRITE( ARG2, sizeof(void *) );
+      break;
+   default:
+      break;
+   }
+}
+
+// freebsd6_pread 173
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_pread)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_freebsd6_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %lu, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", 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, "freebsd6_pread", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+   else
+      PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 );
+}
+
+POST(sys_freebsd6_pread)
+{
+   vg_assert(SUCCESS);
+   POST_MEM_WRITE( ARG2, RES );
+}
+#endif
+
+// freebsd6_pwrite 174
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_pwrite)
+{
+   Bool ok;
+   *flags |= SfMayBlock;
+   PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1, 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, "freebsd6_pwrite", 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( "freebsd6_pwrite(buf)", ARG2, ARG3 );
+}
+#endif
+
+// SYS_freebsd6_mmap 197
+#if (FREEBSD_VERS <= FREEBSD_10)
+/* 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_freebsd6_mmap)
+{
+   SysRes r;
+
+   PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, pad%" FMT_REGWORD "u, 0x%" FMT_REGWORD "x)",
+         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);
+}
+#endif
+
+// freebsd6_lseek 199
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_lseek)
+{
+   PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(long, "lseek",
+                 unsigned int, fd, int, pad, unsigned long, offset,
+                 unsigned int, whence);
+}
+#endif
+
+// freebsd6_truncate 200
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_truncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG3);
+   PRE_REG_READ3(long, "truncate",
+                 const char *, path, int, pad, unsigned int, length);
+   PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
+}
+#endif
+
+// freebsd6_ftruncate 201
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_ftruncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG3);
+   PRE_REG_READ3(long, "ftruncate", unsigned int, fd, int, pad,
+                 unsigned int, length);
+}
+#endif
+
+// SYS_rfork 251
+// pid_t rfork(int flags);
+PRE(sys_rfork)
+{
+   PRINT("sys_rfork ( %#" FMT_REGWORD "x )", 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);
+}
+
+// SYS_preadv  289
+// ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+PRE(sys_preadv)
+{
+   Int i;
+   struct vki_iovec * vec;
+   *flags |= SfMayBlock;
+   PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
+         FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, ARG2, SARG3, SARG4);
+   PRE_REG_READ4(ssize_t, "preadv",
+                 int, fd, const struct iovec *, iovr,
+                 int, iovcnt, vki_off_t, offset);
+   if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
+      SET_STATUS_Failure( VKI_EBADF );
+   } else {
+      if ((Int)ARG3 >= 0)
+         PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) );
+
+      if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
+         vec = (struct vki_iovec *)(Addr)ARG2;
+         for (i = 0; i < (Int)ARG3; i++)
+            PRE_MEM_WRITE( "preadv(iov[...])",
+                           (Addr)vec[i].iov_base, vec[i].iov_len );
+      }
+   }
+}
+
+POST(sys_preadv)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0) {
+      Int i;
+      struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
+      Int remains = RES;
+
+      /* RES holds the number of bytes read. */
+      for (i = 0; i < (Int)ARG3; i++) {
+         Int nReadThisBuf = vec[i].iov_len;
+         if (nReadThisBuf > remains) nReadThisBuf = remains;
+         POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
+         remains -= nReadThisBuf;
+         if (remains < 0) VG_(core_panic)("preadv: remains < 0");
+      }
+   }
+}
+
+// SYS_pwritev 290
+// ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+PRE(sys_pwritev)
+{
+   Int i;
+   struct vki_iovec * vec;
+   *flags |= SfMayBlock;
+   PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
+         FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, ARG2, SARG3, SARG4);
+
+   PRE_REG_READ4(ssize_t, "pwritev",
+                 int, fd, const struct iovec *, iov,
+                 int, iovcnt,
+                 vki_off_t, offset);
+   if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
+      SET_STATUS_Failure( VKI_EBADF );
+   } else {
+      if ((Int)ARG3 >= 0)
+         PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) );
+      if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
+         vec = (struct vki_iovec *)(Addr)ARG2;
+         for (i = 0; i < (Int)ARG3; i++)
+            PRE_MEM_READ( "pwritev(iov[...])",
+                          (Addr)vec[i].iov_base, vec[i].iov_len );
+      }
+   }
+}
+
+// SYS_sendfile   393
+// int sendfile(int fd, int s, off_t offset, size_t nbytes,
+//         struct sf_hdtr *hdtr, off_t *sbytes, int flags);
+PRE(sys_sendfile)
+{
+   *flags |= SfMayBlock;
+
+   PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %lu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         SARG1,SARG2,ARG3,ARG4,ARG5,ARG6,SARG7);
+   PRE_REG_READ7(int, "sendfile",
+                 int, fd, int, s, vki_off_t, offset, size_t, nbytes,
+                 void *, hdtr, vki_off_t *, sbytes, int, flags);
+
+   if (ARG5 != 0)
+      PRE_MEM_READ("sendfile(hdtr)", ARG5, sizeof(struct vki_sf_hdtr));
+
+   if (ARG6 != 0)
+      PRE_MEM_WRITE( "sendfile(sbytes)", ARG6, sizeof(vki_off_t) );
+}
+
+POST(sys_sendfile)
+{
+   if (ARG6 != 0 ) {
+      POST_MEM_WRITE( ARG6, sizeof( vki_off_t ) );
+   }
+}
+
+// SYS_sigreturn  417
+// int sigreturn(const ucontext_t *scp);
+PRE(sys_sigreturn)
+{
+   PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "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) );
+}
+
+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));
+}
+
+// SYS_getcontext 421
+// int getcontext(ucontext_t *ucp);
+PRE(sys_getcontext)
+{
+   ThreadState* tst;
+   struct vki_ucontext *uc;
+
+   PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "getcontext",
+                 struct vki_ucontext *, ucp);
+   PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
+   uc = (struct vki_ucontext *)ARG1;
+   if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      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);
+}
+
+// SYS_setcontext 422
+// int setcontext(const ucontext_t *ucp);
+PRE(sys_setcontext)
+{
+   ThreadState* tst;
+   struct vki_ucontext *uc;
+
+   PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", 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 (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || uc->uc_mcontext.len != sizeof(uc->uc_mcontext)) {
+      SET_STATUS_Failure(VKI_EFAULT);
+      return;
+   }
+
+   restore_mcontext(tst, &uc->uc_mcontext);
+   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;
+}
+
+// SYS_swapcontext   423
+// int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
+PRE(sys_swapcontext)
+{
+   struct vki_ucontext *ucp, *oucp;
+   ThreadState* tst;
+
+   PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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 (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) ||
+         !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) ||
+         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;
+   tst->tmp_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;
+}
+
+// SYS_thr_new 455
+// int thr_new(struct thr_param *param, int param_size);
+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 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",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;
+   ctst->os_state.stk_id = 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);
+}
+
+// SYS_pread   475
+// ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
+PRE(sys_pread)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(ssize_t, "pread",
+                 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( "pread(buf)", ARG2, ARG3 );
+}
+
+POST(sys_pread)
+{
+   vg_assert(SUCCESS);
+   POST_MEM_WRITE( ARG2, RES );
+}
+
+// SYS_pwrite  476
+// ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
+PRE(sys_pwrite)
+{
+   Bool ok;
+   *flags |= SfMayBlock;
+   PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(ssize_t, "pwrite",
+                 int, fd, const char *, buf, vki_size_t, nbytes,
+                 vki_off_t, offset);
+   /* 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, "pwrite", 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( "pwrite(buf)", ARG2, ARG3 );
+}
+
+// SYS_mmap 477
+/* FreeBSD-7 introduces a "regular" version of mmap etc. */
+// void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
+PRE(sys_mmap)
+{
+   SysRes r;
+
+   PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x)",
+         ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, ARG6 );
+   PRE_REG_READ6(void *, "mmap",
+                 void *, addr, size_t, len, int, prot,  int, flags,
+                 int, fd,  off_t, offset);
+
+   r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6 );
+   SET_STATUS_from_SysRes(r);
+}
+
+// SYS_lseek 478
+// off_t lseek(int fildes, off_t offset, int whence);
+PRE(sys_lseek)
+{
+   PRINT("sys_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "lseek",
+                 unsigned int, fd, unsigned long, offset,
+                 unsigned int, whence);
+}
+
+// SYS_truncate   479
+// int truncate(const char *path, off_t length);
+PRE(sys_truncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(long, "truncate",
+                 const char *, path, unsigned long, length);
+   PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
+}
+
+// SYS_ftruncate  480
+// int ftruncate(int fd, off_t length);
+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);
+}
+
+// SYS_cpuset_setid  485
+// int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
+PRE(sys_cpuset_setid)
+{
+   PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, ARG3);
+   PRE_REG_READ3(int, "cpuset_setid", vki_cpuwhich_t, which, vki_id_t, id,
+                 vki_cpusetid_t *,setid);
+}
+
+// SYS_cpuset_getid  486
+// int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
+//                  cpusetid_t *setid);
+PRE(sys_cpuset_getid)
+{
+   PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, SARG3, ARG4);
+   PRE_REG_READ4(int, "cpuset_getid", vki_cpulevel_t, level,
+                 vki_cpuwhich_t, which, vki_id_t, id,
+                 vki_cpusetid_t, setid);
+   PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t));
+}
+
+POST(sys_cpuset_getid)
+{
+   POST_MEM_WRITE(ARG4, sizeof(vki_cpusetid_t));
+}
+
+// SYS_cpuset_getaffinity  487
+// int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
+//                        size_t setsize, cpuset_t *mask);
+PRE(sys_cpuset_getaffinity)
+{
+   PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
+         ARG1, ARG2, SARG3, ARG4, ARG5);
+   PRE_REG_READ5(int, "cpuset_getaffinity",
+                 vki_cpulevel_t, level, vki_cpuwhich_t, which, vki_id_t, 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 );
+}
+
+// SYS_cpuset_setaffinity  488
+// int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
+//                        size_t setsize, const cpuset_t *mask);
+PRE(sys_cpuset_setaffinity)
+{
+
+   PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
+         ARG1, ARG2, SARG3, ARG4, ARG5);
+   PRE_REG_READ5(int, "cpuset_setaffinity",
+                 vki_cpulevel_t, level, vki_cpuwhich_t, which, vki_id_t, id,
+                 size_t, setsize, void *, mask);
+   PRE_MEM_READ("cpuset_setaffinity", ARG5, ARG4);
+}
+
+// SYS_posix_fallocate 530
+// int posix_fallocate(int fd, off_t offset, off_t len);
+PRE(sys_posix_fallocate)
+{
+   PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
+         SARG1, ARG2, ARG3);
+   PRE_REG_READ3(long, "posix_fallocate",
+                 int, fd, vki_off_t, offset,
+                 vki_off_t, len);
+}
+
+// SYS_posix_fadvise 531
+// int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+PRE(sys_posix_fadvise)
+{
+   PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "d )",
+         SARG1, ARG2, ARG3, SARG4);
+   PRE_REG_READ4(long, "posix_fadvise",
+                 int, fd, off_t, offset,
+                 off_t, len,
+                 int, advice);
+   // @todo PJF advice can be 0 to 5 inclusive
+}
+
+// SYS_wait6   532
+// pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
+//             struct __wrusage *wrusage, siginfo_t *infop);
+PRE(sys_wait6)
+{
+   PRINT("sys_wait6 ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, ARG3, SARG4, ARG5, ARG6);
+   PRE_REG_READ6(pid_t, "wait6", vki_idtype_t, idtype, vki_id_t, id, int *, status, int, options,
+                 struct vki___wrusage *, wrusage, vki_siginfo_t *,infop);
+   PRE_MEM_WRITE("wait6(status)", ARG3, sizeof(int));
+   if (ARG5) {
+      PRE_MEM_WRITE("wait6(wrusage)", ARG5, sizeof(struct vki___wrusage));
+   }
+   if (ARG6) {
+      PRE_MEM_WRITE("wait6(infop)", ARG6, sizeof(vki_siginfo_t));
+   }
+}
+
+POST(sys_wait6)
+{
+   POST_MEM_WRITE(ARG3, sizeof(int));
+   if (ARG5) {
+      POST_MEM_WRITE(ARG5, sizeof(struct vki___wrusage));
+   }
+
+   if (ARG6) {
+      POST_MEM_WRITE(ARG5, sizeof(vki_siginfo_t));
+   }
+}
+
+// the man page is inconsistent for the last argument
+// See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386
+// will stick to 'arg' for simplicity
+
+// SYS_procctl 544
+// int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
+PRE(sys_procctl)
+{
+   PRINT("sys_procctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, SARG3, ARG4);
+   PRE_REG_READ4(int, "procctl", vki_idtype_t, idtype, vki_id_t, id, int, cmd, void *, arg);
+   switch (ARG3) {
+   case PROC_ASLR_CTL:
+   case PROC_SPROTECT:
+   case PROC_TRACE_CTL:
+   case PROC_TRAPCAP_CTL:
+   case PROC_PDEATHSIG_CTL:
+   case PROC_STACKGAP_CTL:
+      PRE_MEM_READ("procctl(arg)", ARG4, sizeof(int));
+      break;
+   case PROC_REAP_STATUS:
+      PRE_MEM_READ("procctl(arg)", ARG4, sizeof(struct vki_procctl_reaper_status));
+      break;
+   case PROC_REAP_GETPIDS:
+      PRE_MEM_READ("procctl(arg)", ARG4, sizeof(struct vki_procctl_reaper_pids));
+      break;
+   case PROC_REAP_KILL:
+      /* The first three fields are reads
+       * int rk_sig;
+       * u_int rk_flags;
+       * pid_t rk_subtree;
+       *
+       * The last two fields are writes
+       * u_int rk_killed;
+       * pid_t rk_fpid;
+       *
+       * There is also a pad field
+       */
+      PRE_MEM_READ("procctl(arg)", ARG4, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t));
+      PRE_MEM_WRITE("procctl(arg)", ARG4+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
+      break;
+   case PROC_ASLR_STATUS:
+   case PROC_PDEATHSIG_STATUS:
+   case PROC_STACKGAP_STATUS:
+   case PROC_TRAPCAP_STATUS:
+   case PROC_TRACE_STATUS:
+      PRE_MEM_WRITE("procctl(arg)", ARG4, sizeof(int));
+   case PROC_REAP_ACQUIRE:
+   case PROC_REAP_RELEASE:
+   default:
+      break;
+   }
+}
+
+POST(sys_procctl)
+{
+   switch (ARG3) {
+   case PROC_REAP_KILL:
+      POST_MEM_WRITE(ARG4+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
+      break;
+   case PROC_ASLR_STATUS:
+   case PROC_PDEATHSIG_STATUS:
+   case PROC_STACKGAP_STATUS:
+   case PROC_TRAPCAP_STATUS:
+   case PROC_TRACE_STATUS:
+      POST_MEM_WRITE(ARG4, sizeof(int));
+   default:
+      break;
+   }
+}
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+
+// SYS_cpuset_getdomain 561
+// int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
+//                      size_t setsize, domainset_t *mask, int *policy);
+PRE(sys_cpuset_getdomain)
+{
+   PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, SARG3, ARG4, ARG5, ARG6);
+   PRE_REG_READ6(int, "cpuset_getdomain",
+                 cpulevel_t, level, cpuwhich_t, which, id_t, id,
+                 size_t, setsize, vki_domainset_t *, mask, int *, policy);
+   // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
+   PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG5, ARG4 );
+   PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG6, sizeof(int) );
+}
+
+POST(sys_cpuset_getdomain)
+{
+   POST_MEM_WRITE(ARG5, ARG4 );
+   POST_MEM_WRITE(ARG6, sizeof(int) );
+}
+
+// SYS_cpuset_setdomain 562
+// int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
+//                     size_t setsize, const domainset_t *mask, int policy);
+PRE(sys_cpuset_setdomain)
+{
+   PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         SARG1, SARG2, SARG3, ARG4, ARG5, SARG6);
+   PRE_REG_READ6(int, "cpuset_getdomain",
+                 cpulevel_t, level, cpuwhich_t, which, id_t, id,
+                 size_t, setsize, vki_domainset_t *, mask, int, policy);
+   // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
+   PRE_MEM_READ( "cpuset_getdomain(mask)", ARG5, ARG4 );
+}
+
+#endif
+
+PRE(sys_fake_sigreturn)
+{
+   ThreadState* tst;
+   struct vki_ucontext *uc;
+   int rflags;
+
+   PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", 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 %RAX.  Since %RAX 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 %RAX 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;
+}
+
+
+#undef PRE
+#undef POST
+
+#endif /* defined(VGP_amd64_freebsd) */
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
diff --git a/coregrind/m_syswrap/syswrap-freebsd.c b/coregrind/m_syswrap/syswrap-freebsd.c
new file mode 100644 (file)
index 0000000..77f5b30
--- /dev/null
@@ -0,0 +1,6876 @@
+/*--------------------------------------------------------------------*/
+/*--- 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
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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_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_stacks.h"
+#include "pub_core_syscall.h"
+#include "pub_core_syswrap.h"
+#include "pub_core_inner.h"
+#if defined(ENABLE_INNER_CLIENT_REQUEST)
+#include "pub_core_clreq.h"
+#endif
+
+#include "priv_types_n_macros.h"
+#include "priv_syswrap-generic.h"
+#include "priv_syswrap-main.h"
+#include "priv_syswrap-freebsd.h"
+
+static Bool capabiltyMode = False;
+
+Bool VG_(get_capability_mode)(void)
+{
+   return capabiltyMode;
+}
+
+
+// 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=%u): entry\n",
+                 tid);
+
+   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 %u started: stack = %p\n",
+                  tid, (void*)&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)();
+   /* Set the threadgroup for real.  This overwrites the provisional value set
+      in do_clone().  See comments in do_clone for background, also #226116. */
+   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=%u): exit, schedreturncode %s\n",
+                 tid, VG_(name_of_VgSchedReturnCode)(ret));
+
+   /* 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).  */
+__attribute__((noreturn))
+static void run_a_thread_NORETURN ( Word tidW )
+{
+   ThreadId          tid = (ThreadId)tidW;
+   VgSchedReturnCode src;
+   Int               c;
+   ThreadState*      tst;
+#ifdef ENABLE_INNER_CLIENT_REQUEST
+   Int               registered_vgstack_id;
+#endif
+
+   VG_(debugLog)(1, "syswrap-freebsd",
+                 "run_a_thread_NORETURN(tid=%u): pre-thread_wrapper\n",
+                 tid);
+
+   tst = VG_(get_ThreadState)(tid);
+   vg_assert(tst);
+
+   /* An thread has two stacks:
+      * the simulated stack (used by the synthetic cpu. Guest process
+        is using this stack).
+      * the valgrind stack (used by the real cpu. Valgrind code is running
+        on this stack).
+      When Valgrind runs as an inner, it must signals that its (real) stack
+      is the stack to use by the outer to e.g. do stacktraces.
+   */
+   INNER_REQUEST
+   (registered_vgstack_id
+    = VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base,
+                               tst->os_state.valgrind_stack_init_SP));
+
+   /* Run the thread all the way through. */
+   src = thread_wrapper(tid);
+
+   VG_(debugLog)(1, "syswrap-freebsd",
+                 "run_a_thread_NORETURN(tid=%u): post-thread_wrapper\n",
+                 tid);
+
+   c = VG_(count_living_threads)();
+   vg_assert(c >= 1); /* stay sane */
+
+   /* Deregister thread's stack. */
+   if (tst->os_state.stk_id != NULL_STK_ID)
+      VG_(deregister_stack)(tst->os_state.stk_id);
+
+   // Tell the tool this thread is exiting
+   VG_TRACK( pre_thread_ll_exit, tid );
+
+   /* If the thread is exiting with errors disabled, complain loudly;
+      doing so is bad (does the user know this has happened?)  Also,
+      in all cases, be paranoid and clear the flag anyway so that the
+      thread slot is safe in this respect if later reallocated.  This
+      should be unnecessary since the flag should be cleared when the
+      slot is reallocated, in thread_wrapper(). */
+   if (tst->err_disablement_level > 0) {
+      VG_(umsg)(
+         "WARNING: exiting thread has error reporting disabled.\n"
+         "WARNING: possibly as a result of some mistake in the use\n"
+         "WARNING: of the VALGRIND_DISABLE_ERROR_REPORTING macros.\n"
+      );
+      VG_(debugLog)(
+         1, "syswrap-freebsd",
+         "run_a_thread_NORETURN(tid=%u): "
+         "WARNING: exiting thread has err_disablement_level = %u\n",
+         tid, tst->err_disablement_level
+      );
+   }
+   tst->err_disablement_level = 0;
+
+   if (c == 1) {
+
+      VG_(debugLog)(1, "syswrap-freebsd",
+                    "run_a_thread_NORETURN(tid=%u): "
+                    "last one standing\n",
+                    tid);
+
+      /* 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=%u): "
+                    "not last one standing\n",
+                    tid);
+
+      /* OK, thread is dead, but others still exist.  Just exit. */
+
+      /* This releases the run lock */
+      VG_(exit_thread)(tid);
+      vg_assert(tst->status == VgTs_Zombie);
+      vg_assert(sizeof(tst->status) == 4);
+      vg_assert(sizeof(tst->os_state.exitcode) == sizeof(Word));
+
+      INNER_REQUEST (VALGRIND_STACK_DEREGISTER (registered_vgstack_id));
+
+      /* We have to use this sequence to terminate the thread to
+         prevent a subtle race.  If VG_(exit_thread)() had left the
+         ThreadState as Empty, then it could have been reallocated,
+         reusing the stack while we're doing these last cleanups.
+         Instead, VG_(exit_thread) leaves it as Zombie to prevent
+         reallocation.  We need to make sure we don't touch the stack
+         between marking it Empty and exiting.  Hence the
+         assembler. */
+#if defined(VGP_x86_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 %u 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.
+*/
+__attribute__((noreturn))
+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);
+#if defined(ENABLE_INNER_CLIENT_REQUEST)
+   {
+      // we must register the main thread stack before the call
+      // to ML_(call_on_new_stack_0_1), otherwise the outer valgrind
+      // reports 'write error' on the non registered stack.
+      ThreadState* tst = VG_(get_ThreadState)(tid);
+      INNER_REQUEST
+      ((void)
+       VALGRIND_STACK_REGISTER (tst->os_state.valgrind_stack_base,
+                                tst->os_state.valgrind_stack_init_SP));
+   }
+#endif
+
+   /* If we can't even allocate the first thread's stack, we're hosed.
+      Give up. */
+   vg_assert2(sp != 0, "%s", "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 %lu\n",
+                        VG_(getpid)(), sr_Res(res));
+
+         /* restore signal mask */
+         VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
+      }
+   }
+
+   return res;
+}
+
+static Addr ML_(make_safe_mask) ( const HChar* malloc_message, Addr mask_pointer )
+{
+   vki_sigset_t* new_mask;
+   const vki_sigset_t* old_mask = (vki_sigset_t *)mask_pointer;
+
+   if (!ML_(safe_to_deref)(old_mask, sizeof(vki_sigset_t))) {
+      new_mask = (vki_sigset_t*)1; /* Something recognisable to POST() hook. */
+   } else {
+      new_mask = VG_(malloc)(malloc_message, sizeof(vki_sigset_t));
+      *new_mask = *old_mask;
+      VG_(sanitize_client_sigmask)(new_mask);
+   }
+
+   return (Addr)new_mask;
+}
+
+static void ML_(free_safe_mask) ( Addr mask_pointer )
+{
+   if (mask_pointer != 0 && mask_pointer != 1) {
+      VG_(free)((vki_sigset_t *) mask_pointer);
+   }
+}
+
+
+/* ---------------------------------------------------------------------
+   PRE/POST wrappers for arch-generic, FreeBSD-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)
+
+/* On FreeBSD, if any thread calls exit(2), then they are all shut down, pretty
+ * much like linux's exit_group().
+ */
+// SYS_exit 1
+// void exit(int status);
+PRE(sys_exit)
+{
+   ThreadId     t;
+
+   PRINT("exit( %" FMT_REGWORD "u )", 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 */
+   }
+
+   VG_(nuke_all_threads_except)( tid, VgSrc_ExitProcess );
+   VG_(reap_threads)(tid);
+   VG_(threads)[tid].exitreason = VgSrc_ExitThread;
+
+   /* We have to claim the syscall already succeeded. */
+   SET_STATUS_Success(0);
+}
+
+// SYS_fork 2
+// pid_t fork(void);
+PRE(sys_fork)
+{
+   PRINT("%s", "sys_fork ()");
+   PRE_REG_READ0(pid_t, "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;
+   }
+}
+
+// SYS_read 3
+// generic
+
+// SYS_write   4
+// generic
+
+// SYS_open 5
+// generic
+
+// SYS_close   6
+// generic
+
+// SYS_wait4   7
+// generic
+
+// SYS_link 9
+// generic
+
+// SYS_unlink  10
+// generic
+
+// SYS_chdir   12
+
+// SYS_fchdir  13
+// generic
+
+// SYS_freebsd11_mknod  14
+// generic
+
+// SYS_chmod   15
+// generic
+
+// SYS_chown   16
+// generic
+
+// SYS_break   17
+// generic
+
+// SYS_getpid  20
+// generic
+
+// SYS_mount   21
+// int mount(const char *type, const char *dir, int flags, void *data);
+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( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "mount",
+                 const char *, type, char *, dir, int, flags,
+                 void *, data);
+   PRE_MEM_RASCIIZ( "mount(type)", ARG1);
+   PRE_MEM_RASCIIZ( "mount(path)", ARG2);
+}
+
+//  SYS_unmount   22
+// int unmount(const char *dir, int flags);
+PRE(sys_unmount)
+{
+   PRINT("sys_umount( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2);
+   PRE_REG_READ2(int, "unmount", const char *, dir, int, flags);
+   PRE_MEM_RASCIIZ( "unmount(path)", ARG1);
+}
+
+// SYS_setuid  23
+// generic
+
+// SYS_getuid  24
+// generic
+
+// SYS_geteuid 25
+// generic
+
+// SYS_ptrace  26
+// int ptrace(int request, pid_t pid, caddr_t addr, int data);
+PRE(sys_ptrace)
+{
+   struct vki_ptrace_io_desc *io_desc;
+   PRINT("sys_ptrace ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u)", ARG1, ARG2, ARG3, ARG4);
+
+   PRE_REG_READ4(int, "ptrace", int, request, pid_t, pid, caddr_t, 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_user_regs_struct));
+      break;
+
+   case VKI_PTRACE_SETREGS:
+      PRE_MEM_READ( "ptrace", ARG3, sizeof(struct vki_user_regs_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 ((Word)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 ((Word)RES != -1)
+         POST_MEM_WRITE(ARG3, sizeof(struct vki_user_regs_struct));
+      break;
+
+   case VKI_PTRACE_SETREGS:
+      break;
+
+   case VKI_PTRACE_GETFPREGS:
+      if ((Word)RES != -1)
+         POST_MEM_WRITE(ARG3, sizeof(struct vki_fpreg));
+      break;
+
+   case VKI_PTRACE_SETFPREGS:
+      break;
+
+   case VKI_PTRACE_GETDBREGS:
+      if ((Word)RES != -1)
+         POST_MEM_WRITE(ARG3, sizeof(struct vki_dbreg));
+      break;
+
+   case VKI_PTRACE_SETDBREGS:
+      break;
+
+   case VKI_PTRACE_LWPINFO:
+      if ((Word)RES != -1)
+         POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_lwpinfo));
+      break;
+
+   case VKI_PTRACE_GETNUMLWPS:
+      break;
+
+   case VKI_PTRACE_GETLWPLIST:
+      if ((Word)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 ((Word)RES != -1)
+         POST_MEM_WRITE(ARG3, sizeof(struct vki_ptrace_vm_entry));
+      break;
+   }
+}
+
+// SYS_recvmsg 27
+// ssize_t recvmsg(int s, struct msghdr *msg, int flags);
+PRE(sys_recvmsg)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_recvmsg ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",SARG1,ARG2,SARG3);
+   PRE_REG_READ3(vki_ssize_t, "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);
+}
+
+// SYS_sendmsg 28
+// ssize_t sendmsg(int s, const struct msghdr *msg, int flags);
+PRE(sys_sendmsg)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sendmsg ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(ssize_t, "sendmsg",
+                 int, s, const struct msghdr *, msg, int, flags);
+   ML_(generic_PRE_sys_sendmsg)(tid, "sendmsg", (struct vki_msghdr *)ARG2);
+}
+
+// SYS_recvfrom   29
+// ssize_t recvfrom(int s, void *buf, size_t len, int flags,
+//                  struct sockaddr * restrict from, socklen_t * restrict fromlen);
+PRE(sys_recvfrom)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_recvfrom ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",SARG1,ARG2,ARG3,SARG4,ARG5,ARG6);
+   PRE_REG_READ6(ssize_t, "recvfrom",
+                 int, s, void *, buf, size_t, len, 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);
+}
+
+// SYS_accept  30
+// int accept(int s, struct sockaddr * restrict addr,
+//            socklen_t * restrict addrlen);
+PRE(sys_accept)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_accept ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "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);
+}
+
+// SYS_getpeername   31
+// int getpeername(int s, struct sockaddr * restrict name,
+//                 socklen_t * restrict namelen);
+PRE(sys_getpeername)
+{
+   PRINT("sys_getpeername ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "getpeername",
+                 int, s, struct sockaddr *, name, socklen_t *, 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);
+}
+
+// SYS_getsockname   32
+// int getsockname(int s, struct sockaddr * restrict name,
+//                 socklen_t * restrict namelen);
+PRE(sys_getsockname)
+{
+   PRINT("sys_getsockname ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",SARG1,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);
+}
+
+// SYS_access  33
+// generic
+
+// SYS_chflags 34
+// int fchflags(int fd, unsigned long flags)
+PRE(sys_chflags)
+{
+   PRINT("sys_chflags ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(long, "chflags",
+                 const char *, path, unsigned long, flags);
+   PRE_MEM_RASCIIZ( "chflags(path)", ARG1 );
+}
+
+// SYS_fchflags   35
+// int  fchflags(int fd, unsigned long flags);
+PRE(sys_fchflags)
+{
+   PRINT("sys_fchflags ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2);
+   PRE_REG_READ2(int, "fchflags", int, fd, unsigned long, flags);
+}
+
+// SYS_sync 36
+// generic
+
+// SYS_kill 37
+// generic
+
+// SYS_getppid 39
+// generic
+
+// SYS_dup  41
+// generic
+
+// Pipe on freebsd doesn't have args, and uses dual returns!
+// SYS_freebsd10_pipe   42
+// int pipe(void);
+PRE(sys_pipe)
+{
+   PRINT("%s", "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);
+      }
+   }
+}
+
+// SYS_getegid 43
+// generic
+
+// SYS_profil  44
+// generic
+
+// SYS_ktrace  45
+// generic
+
+// SYS_getgid  47
+// generic
+
+// SYS_getlogin   49
+// syscall.master refers to namelen and namebuf for the argument names
+// man getlogin has just getlogin(void) but also
+// int getlogin_r(char *name, int len);
+// so let's go with those names
+PRE(sys_getlogin)
+{
+   PRINT("sys_getlogin ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
+   PRE_REG_READ2(int, "getlogin", char *, buf, u_int, len);
+   PRE_MEM_WRITE( "getlogin(name)", ARG1, ARG2 );
+}
+
+POST(sys_getlogin)
+{
+   POST_MEM_WRITE(ARG1, ARG2 );
+}
+
+// SYS_setlogin   50
+// int setlogin(const char *name);
+PRE(sys_setlogin)
+{
+   PRINT("sys_setlogin ( %#" FMT_REGWORD "x )",ARG1);
+   PRE_REG_READ1(long, "setlogin", char *, buf);
+   PRE_MEM_RASCIIZ( "setlogin(buf)", ARG1 );
+}
+
+// SYS_acct 51
+// generic
+
+// SYS_sigaltstack   53
+// generic
+
+// SYS_ioctl   54
+// int ioctl(int fd, unsigned long request, ...);
+PRE(sys_ioctl)
+{
+   UInt dir  = _VKI_IOC_DIR(ARG2);
+   UInt size = _VKI_IOC_SIZE(ARG2);
+   *flags |= SfMayBlock;
+   // @todo PJF presumably the presence of ARG3 depends on ARG2
+   PRINT("sys_ioctl ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "ioctl",
+                 int, fd, unsigned long, request, unsigned long, arg);
+
+   /* On FreeBSD, ALL ioctl's are IOR/IOW encoded.  Just use the default decoder */
+   if (SimHintiS(SimHint_lax_ioctls, VG_(clo_sim_hints))) {
+      /*
+      * 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 ((dir == _VKI_IOC_NONE) && size > 0) {
+      static UWord unknown_ioctl[10];
+      static Int moans = sizeof(unknown_ioctl) / sizeof(unknown_ioctl[0]);
+      if (moans > 0 && !VG_(clo_xml)) {
+         /* Check if have not already moaned for this request. */
+         UInt i;
+         for (i = 0; i < sizeof(unknown_ioctl)/sizeof(unknown_ioctl[0]); i++) {
+            if (unknown_ioctl[i] == ARG2)
+               break;
+            if (unknown_ioctl[i] == 0) {
+               unknown_ioctl[i] = ARG2;
+               moans--;
+               VG_(umsg)("Warning: noted but unhandled ioctl 0x%lx"
+                         " with no size/direction hints.\n", ARG2);
+               VG_(umsg)("   This could cause spurious value errors to appear.\n");
+               VG_(umsg)("   See README_MISSING_SYSCALL_OR_IOCTL for "
+                         "guidance on writing a proper wrapper.\n" );
+               //VG_(get_and_pp_StackTrace)(tid, VG_(clo_backtrace_size));
+               return;
+            }
+         }
+      }
+   } 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);
+   }
+
+   // The block below is from Ryan Stone
+   // https://bitbucket.org/rysto32/valgrind-freebsd/commits/5323c22be9f6c71a00e842c3ddfa1fa8a7feb279
+   // however it drags in hundreds of lines of headers into vki-freebsd.h.
+   // How stable are these structures? -> maintainability is a concern
+   // Also there are no testcases for this.
+   // Hence #if 0
+#if 0
+   /* Handle specific ioctls which pass structures which may have pointers to other
+      buffers */
+   switch (ARG2 /* request */) {
+   case VKI_SIOCGIFMEDIA:
+      if (ARG3) {
+         struct vki_ifmediareq* imr = (struct vki_ifmediareq*)ARG3;
+         if (imr->ifm_ulist) {
+            PRE_MEM_WRITE("ioctl(SIOCGIFMEDIA).ifm_ulist",
+                          (Addr)(imr->ifm_ulist), imr->ifm_count * sizeof(int));
+         }
+      }
+      break;
+
+   case VKI_PCIOCGETCONF:
+      if (ARG3) {
+         struct vki_pci_conf_io* pci = (struct vki_pci_conf_io*)ARG3;
+         PRE_MEM_READ("ioctl(PCIOCGETCONF).patterns",
+                      (Addr)(pci->patterns), pci->pat_buf_len);
+         PRE_MEM_WRITE("ioctl(PCIOCGETCONF).matches",
+                       (Addr)(pci->matches), pci->match_buf_len);
+      }
+      break;
+
+   case VKI_CAMIOCOMMAND:
+      if (ARG3) {
+         union vki_ccb* ccb = (union vki_ccb*)ARG3;
+         if (ccb->ccb_h.func_code == VKI_XPT_DEV_MATCH) {
+            PRE_MEM_WRITE("ioctl(CAMIOCOMMAND:XPT_DEV_MATCH).matches",
+                          (Addr)(ccb->cdm.matches), ccb->cdm.match_buf_len);
+         } else if (ccb->ccb_h.func_code == VKI_XPT_SCSI_IO) {
+            struct vki_ccb_scsiio* scsiio = (struct vki_ccb_scsiio*)ccb;
+            if (scsiio->dxfer_len) {
+               if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_IN) {
+                  PRE_MEM_WRITE("ioctl(CAMIOCOMMAND:XPT_SCSI_IO).data_ptr",
+                                (Addr)(scsiio->data_ptr), scsiio->dxfer_len);
+               } else if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_OUT) {
+                  PRE_MEM_READ("ioctl(CAMIOCOMMAND:XPT_SCSI_IO).data_ptr",
+                               (Addr)(scsiio->data_ptr), scsiio->dxfer_len);
+               }
+            }
+         } else if (ccb->ccb_h.func_code == VKI_XPT_GDEV_TYPE ||
+                    ccb->ccb_h.func_code == VKI_XPT_PATH_INQ ||
+                    ccb->ccb_h.func_code == VKI_XPT_GET_TRAN_SETTINGS) {
+            // do nothing
+         } else {
+            VG_(message)(Vg_UserMsg,
+                         "Warning: unhandled ioctl CAMIOCOMMAND function 0x%lx\n",
+                         ccb->ccb_h.func_code);
+         }
+      }
+      break;
+   }
+#endif
+}
+
+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);
+
+#if 0
+   /* Handle specific ioctls which pass structures which may have pointers to other
+      buffers */
+   switch (ARG2 /* request */) {
+   case VKI_SIOCGIFMEDIA:
+      if (ARG3) {
+         struct vki_ifmediareq* imr = (struct vki_ifmediareq*)ARG3;
+         if (imr->ifm_ulist) {
+            POST_MEM_WRITE((Addr)(imr->ifm_ulist), imr->ifm_count * sizeof(int));
+         }
+      }
+      break;
+
+   case VKI_PCIOCGETCONF:
+      if (ARG3) {
+         struct vki_pci_conf_io* pci = (struct vki_pci_conf_io*)ARG3;
+         POST_MEM_WRITE((Addr)(pci->matches), pci->num_matches * sizeof(struct vki_pci_conf));
+      }
+      break;
+
+   case VKI_CAMIOCOMMAND:
+      if (ARG3) {
+         union vki_ccb* ccb = (union vki_ccb*)ARG3;
+         if (ccb->ccb_h.func_code == VKI_XPT_DEV_MATCH) {
+            POST_MEM_WRITE((Addr)(ccb->cdm.matches), ccb->cdm.num_matches*sizeof(struct vki_dev_match_result));
+         } else if (ccb->ccb_h.func_code == VKI_XPT_SCSI_IO) {
+            struct vki_ccb_scsiio* scsiio = (struct vki_ccb_scsiio*)ccb;
+            if (scsiio->dxfer_len) {
+               if ((scsiio->ccb_h.flags & VKI_CAM_DIR_MASK) == VKI_CAM_DIR_IN) {
+                  POST_MEM_WRITE((Addr)(scsiio->data_ptr), scsiio->dxfer_len);
+               }
+            }
+         }
+      }
+      break;
+   }
+#endif
+}
+
+// SYS_reboot  55
+// int reboot(int howto);
+PRE(sys_reboot)
+{
+   PRINT("sys_reboot ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "reboot", int, howto);
+}
+
+// SYS_revoke  56
+// int revoke(const char *path);
+PRE(sys_revoke)
+{
+   PRINT("sys_revoke ( %#" FMT_REGWORD "x(%s) )", ARG1, (char*)ARG1);
+   PRE_REG_READ1(long, "revoke", const char *, path);
+   PRE_MEM_RASCIIZ( "revoke(path)", ARG1);
+}
+
+// SYS_symlink 57
+// generic
+
+// SYS_readlink   58
+// generic
+
+// SYS_execve  59
+// generic
+
+// SYS_umask   60
+// generic
+
+// SYS_chroot  61
+// generic
+
+// SYS_msync   65
+// generic
+
+// SYS_vfork 66
+// pid_t vfork(void);
+PRE(sys_vfork)
+{
+   PRINT("%s", "sys_vfork ()");
+   PRE_REG_READ0(pid_t, "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;
+   }
+}
+
+// SYS_sbrk 69
+// void * sbrk(intptr_t incr);
+PRE(sys_sbrk)
+{
+   PRINT("sys_sbrk ( %#" FMT_REGWORD "x )",ARG1);
+   PRE_REG_READ1(void*, "sbrk", vki_intptr_t, incr);
+}
+
+// SYS_freebsd11_vadvise   72
+// @todo maybe
+
+// SYS_munmap  73
+// generic
+
+// SYS_mprotect   74
+// generic
+
+// SYS_madvise 75
+// generic
+
+// SYS_mincore 78
+// generic
+
+// SYS_getgroups  79
+// generic
+
+// SYS_setgroups  80
+// generic
+
+// SYS_getpgrp 81
+// generic
+
+// SYS_setpgid 82
+// generic
+
+// SYS_setitimer  83
+// generic
+
+// SYS_swapon  85
+// int swapon(const char *special);
+PRE(sys_swapon)
+{
+   PRINT("sys_swapon ( %#" FMT_REGWORD "x(%s) )", ARG1,(char*)ARG1);
+   PRE_REG_READ1(int, "swapon", const char*, special );
+   PRE_MEM_RASCIIZ( "swapon(special)", ARG1 );
+}
+
+// SYS_getitimer  86
+// generic
+
+// SYS_getdtablesize 89
+// int getdtablesize(void);
+PRE(sys_getdtablesize)
+{
+   PRINT("%s", "sys_getdtablesize ( )");
+   PRE_REG_READ0(long, "getdtablesize");
+}
+
+// SYS_dup2 90
+// generic
+
+// SYS_fcntl   92
+// int fcntl(int fd, int cmd, ...);
+PRE(sys_fcntl)
+{
+   switch (ARG2) {
+   // These ones ignore ARG3.
+   case VKI_F_GETFD:
+   case VKI_F_GETFL:
+   case VKI_F_GETOWN:
+   case VKI_F_GET_SEALS:
+   case VKI_F_ISUNIONSTACK:
+      PRINT("sys_fcntl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,SARG2);
+      PRE_REG_READ2(int, "fcntl", int, fd, 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:
+   case VKI_F_READAHEAD:
+   case VKI_F_RDAHEAD:
+   case VKI_F_ADD_SEALS:
+      PRINT("sys_fcntl[ARG3=='arg'] ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,SARG2,SARG3);
+      PRE_REG_READ3(int, "fcntl",
+                    int, fd, int, cmd, int, 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'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(int, "fcntl",
+                    int, fd, int, cmd,
+                    struct oflock *, lock);
+      break;
+
+   // This one uses ARG3 as "oldd" and ARG4 as "newd".
+   case VKI_F_DUP2FD:
+   case VKI_F_DUP2FD_CLOEXEC:
+      PRINT("sys_fcntl[ARG3=='oldd', ARG4=='newd'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",
+            ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "fcntl",
+                    int, fd, 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'] ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3);
+      PRE_REG_READ3(int, "fcntl",
+                    int, fd, int, cmd,
+                    struct flock *, lock);
+      break;
+
+   default:
+      PRINT("sys_fcntl[UNKNOWN] ( %lu, %lu, %lu )", ARG1,ARG2,ARG3);
+      I_die_here;
+   }
+}
+
+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);
+      }
+   } else if (ARG2 == VKI_F_DUPFD_CLOEXEC) {
+      if (!ML_(fd_allowed)(RES, "fcntl(DUPFD_CLOEXEC)", tid, True)) {
+         VG_(close)(RES);
+         SET_STATUS_Failure( VKI_EMFILE );
+      } else {
+         if (VG_(clo_track_fds))
+            ML_(record_fd_open_named)(tid, RES);
+      }
+   }
+}
+
+// SYS_select  93
+// generic
+
+// SYS_fsync   95
+// generic
+
+// SYS_setpriority   9
+// generic
+
+// SYS_socket  97
+// int socket(int domain, int type, int protocol);
+PRE(sys_socket)
+{
+   PRINT("sys_socket ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d )",SARG1,SARG2,SARG3);
+   PRE_REG_READ3(int, "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);
+}
+
+// SYS_connect 98
+// int connect(int s, const struct sockaddr *name, socklen_t namelen);
+PRE(sys_connect)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_connect ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "connect",
+                 int, s, const struct sockaddr *, name, int, namelen);
+   ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
+}
+
+// SYS_getpriority   100
+// generic
+
+// SYS_bind 104
+// int bind(int s, const struct sockaddr *addr, socklen_t addrlen);
+PRE(sys_bind)
+{
+   PRINT("sys_bind ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "bind",
+                 int, s, struct sockaddr *, addr, int, addrlen);
+   ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3);
+}
+
+// SYS_setsockopt 105
+// int setsockopt(int s, int level, int optname, const void *optval,
+//                socklen_t optlen);
+PRE(sys_setsockopt)
+{
+   PRINT("sys_setsockopt ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",SARG1,SARG2,SARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "setsockopt",
+                 int, s, int, level, int, optname,
+                 const void *, optval, vki_socklen_t, optlen);
+   ML_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
+}
+
+// SYS_listen  106
+// int listen(int s, int backlog);
+PRE(sys_listen)
+{
+   PRINT("sys_listen ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )",SARG1,SARG2);
+   PRE_REG_READ2(int, "listen", int, s, int, backlog);
+}
+
+//SYS_gettimeofday   116
+// generic
+
+// SYS_getrusage  117
+// generic
+
+// SYS_getsockopt 118
+// int getsockopt(int s, int level, int optname, void * restrict optval,
+//                socklen_t * restrict optlen);
+PRE(sys_getsockopt)
+{
+   Addr optval_p = ARG4;
+   Addr optlen_p = ARG5;
+   PRINT("sys_getsockopt ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "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)" );
+   }
+}
+
+// SYS_readv   120
+// generic
+
+// SYS_writev  121
+// generic
+
+// SYS_settimeofday  122
+// generic
+
+// SYS_fchown  123
+// generic
+
+// SYS_fchmod  124
+// generic
+
+// SYS_setreuid   126
+// generic
+
+// SYS_setregid   127
+// generic
+
+// SYS_rename  128
+// generic
+
+// SYS_flock   131
+// generic
+
+// SYS_mkfifo  132
+// int mkfifo(const char *path, mode_t mode);
+PRE(sys_mkfifo)
+{
+   PRINT("sys_mkfifo ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1, (char *)ARG1, ARG2, ARG3 );
+   PRE_REG_READ2(int, "mkfifo", const char *, path, int, mode);
+   PRE_MEM_RASCIIZ( "mkfifo(path)", ARG1 );
+}
+
+// SYS_sendto  133
+// ssize_t sendto(int s, const void *msg, size_t len, int flags,
+//                const struct sockaddr *to, socklen_t tolen);
+PRE(sys_sendto)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sendto ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(ssize_t, "sendto",
+                 int, s, const void *, msg, int, len,
+                 int, flags,
+                 const struct sockaddr *, to, socklen_t, tolen);
+   ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+}
+
+// SYS_shutdown   134
+// int shutdown(int s, int how);
+PRE(sys_shutdown)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_shutdown ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2);
+   PRE_REG_READ2(int, "shutdown", int, s, int, how);
+}
+
+// SYS_socketpair 135
+// int socketpair(int domain, int type, int protocol, int *sv);
+PRE(sys_socketpair)
+{
+   PRINT("sys_socketpair ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "socketpair",
+                 int, domain, 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);
+}
+
+// SYS_mkdir   136
+// generic
+
+// SYS_rmdir   137
+// generic
+
+// SYS_utimes  138
+// generic
+
+// SYS_adjtime 140
+// int adjtime(const struct timeval *delta, struct timeval *olddelta);
+PRE(sys_adjtime)
+{
+   PRINT("sys_adjtime ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "adjtime",
+                 const struct vki_timeval *, delta, struct vki_timeval *, olddelta);
+   PRE_MEM_READ("adjtime(delta)", ARG1, sizeof(struct vki_timeval));
+   if (ARG2) {
+      PRE_MEM_WRITE("adjtime(olddelta)", ARG1, sizeof(struct vki_timeval));
+   }
+}
+
+POST(sys_adjtime)
+{
+   if (ARG2) {
+      POST_MEM_WRITE(ARG1, sizeof(struct vki_timeval));
+   }
+}
+
+// SYS_setsid  147
+// generic
+
+// SYS_quotactl   148
+/* int quotactl(const char *path, int cmd, int id, void *addr); */
+PRE(sys_quotactl)
+{
+   PRINT("sys_quotactl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3, ARG4);
+   switch (ARG2) {
+   case VKI_Q_QUOTAON:
+   case VKI_Q_SETQUOTA:
+   case VKI_Q_SETUSE:
+
+   case VKI_Q_GETQUOTASIZE:
+      PRE_REG_READ4(int, "quotactl",
+                    const char *, path, int, cmd, int, id,
+                    void *, addr);
+      PRE_MEM_RASCIIZ( "quotactl(path)", ARG1 );
+      break;
+   case VKI_Q_GETQUOTA:
+      if (VG_(tdict).track_pre_reg_read) {
+         \
+         PRRSN;
+         PRA1("quotactl",const char*,path);
+         PRA2("quotactl",int,cmd);
+         PRA4("quotactl",void*,addr);
+      }
+      break;
+   case VKI_Q_QUOTAOFF:
+   case VKI_Q_SYNC:
+      PRE_REG_READ2(int, "quotactl",
+                    const char *, path, int, cmd);
+      break;
+   default:
+      break;
+   }
+}
+
+// SYS_nlm_syscall   154
+// syscall.master says ; 154 is initialised by the NLM code, if present.
+// @todo
+
+// SYS_nfssvc  155
+// int nfssvc(int flags, void *argstructp);
+// lengthy manpage, at least 3 types of struct that argstructp can point to
+// @todo
+
+// SYS_lgetfh  160
+// int lgetfh(const char *path, fhandle_t *fhp);
+PRE(sys_lgetfh)
+{
+   PRINT("sys_lgetfh ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x ", ARG1, ARG2);
+   PRE_REG_READ2(int, "lgetfh", const char*, path, vki_fhandle_t*, fhp);
+   PRE_MEM_RASCIIZ( "lgetfh(path)", ARG1 );
+   PRE_MEM_WRITE("lgetfh(fhp)", ARG2, sizeof(vki_fhandle_t));
+}
+
+POST(sys_lgetfh)
+{
+   POST_MEM_WRITE(ARG2, sizeof(vki_fhandle_t));
+}
+
+// SYS_getfh   161
+// int getfh(const char *path, fhandle_t *fhp);
+PRE(sys_getfh)
+{
+   PRINT("sys_getfh ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x ", ARG1, ARG2);
+   PRE_REG_READ2(int, "getfh", const char*, path, vki_fhandle_t*, fhp);
+   PRE_MEM_RASCIIZ( "getfh(path)", ARG1 );
+   PRE_MEM_WRITE("getfh(fhp)", ARG2, sizeof(vki_fhandle_t));
+}
+
+POST(sys_getfh)
+{
+   POST_MEM_WRITE(ARG2, sizeof(vki_fhandle_t));
+}
+
+#if (FREEBSD_VERS <= FREEBSD_10)
+// 162
+// int getdomainname(char *domainname, int len);
+PRE(sys_freebsd4_getdomainname)
+{
+   PRINT("sys_freebsd4_getdomainname ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
+   PRE_REG_READ2(int, "getdomainname",
+                 char *, domainname, int, len);
+   PRE_MEM_WRITE( "getdomainname(domainname)", ARG1, ARG2 );
+}
+
+POST(sys_freebsd4_getdomainname)
+{
+   if (ARG1 != 0) {
+      POST_MEM_WRITE( ARG1, ARG2 );
+   }
+}
+
+// 163
+// int setdomainname(char *domainname, int len);
+PRE(sys_freebsd4_setdomainname)
+{
+   PRINT("sys_freebsd4_setdomainname ( %#" FMT_REGWORD "x )",ARG1);
+   PRE_REG_READ2(int, "setdomainname", char *, domainname, int, len);
+   PRE_MEM_RASCIIZ( "setdomainname(domainname)", ARG1 );
+}
+
+// 164
+// int uname(struct utsname *name);
+PRE(sys_freebsd4_uname)
+{
+   PRINT("sys_freebsd4_uname ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "uname", struct utsname *, name);
+   PRE_MEM_WRITE( "uname(name)", ARG1, sizeof(struct vki_utsname) );
+}
+
+POST(sys_freebsd4_uname)
+{
+   if (ARG1 != 0) {
+      POST_MEM_WRITE( ARG1, sizeof(struct vki_utsname) );
+   }
+}
+#endif
+
+// SYS_sysarch 165
+// x86/amd64
+
+// SYS_rtprio  166
+PRE(sys_rtprio)
+{
+   PRINT( "sys_rtprio ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3 );
+   PRE_REG_READ3(int, "rtprio",
+                 int, function, pid_t, pid, struct rtprio *, rtp);
+   if (ARG1 == VKI_RTP_SET) {
+      PRE_MEM_READ( "rtprio(rtp#set)", ARG3, sizeof(struct vki_rtprio));
+   } else if (ARG1 == VKI_RTP_LOOKUP) {
+      PRE_MEM_WRITE( "rtprio(rtp#lookup)", ARG3, sizeof(struct vki_rtprio));
+   } else {
+      /* PHK ?? */
+   }
+}
+
+POST(sys_rtprio)
+{
+   if (ARG1 == VKI_RTP_LOOKUP && RES == 0)
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_rtprio));
+}
+
+// freebsd6_pread 173 FREEBSD_VERS <= 10
+// x86/amd64
+
+// freebsd6_pwrite 174 FREEBSD_VERS <= 10
+// x86/amd64
+
+// SYS_setfib  175
+// int setfib(int fib);
+PRE(sys_setfib)
+{
+   PRINT("sys_setfib ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "setfib", int, fib);
+}
+
+// SYS_ntp_adjtime   176
+// int ntp_adjtime(struct timex *);
+// @todo
+
+// SYS_setgid  181
+// generic
+
+// SYS_setegid 182
+// int setegid(gid_t egid);
+PRE(sys_setegid)
+{
+   PRINT("sys_setegid ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(int, "setegid", vki_gid_t, gid);
+}
+
+// SYS_seteuid 183
+// int seteuid(uid_t euid);
+PRE(sys_seteuid)
+{
+   PRINT("sys_seteuid ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(long, "seteuid", vki_uid_t, uid);
+}
+
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+
+// SYS_freebsd11_stat   188
+// int stat(char *path, struct freebsd11_stat *sb);
+PRE(sys_freebsd11_stat)
+{
+   PRINT("sys_stat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "stat", char *, path, struct freebsd11_stat *, sb);
+   PRE_MEM_RASCIIZ( "stat(path)", ARG1 );
+   PRE_MEM_WRITE( "stat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_freebsd11_stat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+// SYS_freebsd11_fstat  189
+// int fstat(int fd, struct stat *sb);
+PRE(sys_freebsd11_fstat)
+{
+   PRINT("sys_freebsd11_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2);
+   PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb);
+   PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_freebsd11_fstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+// SYS_freebsd11_lstat  190
+// int lstat(const char * restrict path, struct stat * restrict sb);
+PRE(sys_freebsd11_lstat)
+{
+   PRINT("sys_lstat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(sb, "lstat", const char *, path, struct freebsd11_stat *, sb);
+   PRE_MEM_RASCIIZ( "lstat(path)", ARG1 );
+   PRE_MEM_WRITE( "lstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_freebsd11_lstat)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0) {
+      POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+   }
+}
+
+#else
+
+PRE(sys_stat)
+{
+   PRINT("sys_stat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "stat", char *, path, struct stat *, sb);
+   PRE_MEM_RASCIIZ( "stat(path)", ARG1 );
+   PRE_MEM_WRITE( "stat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_stat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+
+PRE(sys_fstat)
+{
+   PRINT("sys_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2);
+   PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb);
+   PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_fstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+PRE(sys_lstat)
+{
+   PRINT("sys_lstat ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "lstat", const char *, path, struct stat *, sb);
+   PRE_MEM_RASCIIZ( "lstat(path)", ARG1 );
+   PRE_MEM_WRITE( "lstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_lstat)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0) {
+      POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+   }
+}
+
+#endif
+
+// SYS_pathconf   191
+// long pathconf(const char *path, int name);
+PRE(sys_pathconf)
+{
+   PRINT("sys_pathconf ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(long, "pathconf", char *, path, int, name);
+   PRE_MEM_RASCIIZ( "pathconf(path)", ARG1 );
+}
+
+// SYS_fpathconf  192
+// long fpathconf(int fd, int name);
+PRE(sys_fpathconf)
+{
+   PRINT("sys_fpathconf ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2);
+   PRE_REG_READ2(long, "fpathconf", int, fd, int, name);
+}
+
+// SYS_getrlimit  194
+// generic
+
+// SYS_setrlimit  195
+// generic
+
+
+// SYS_freebsd11_getdirentries   196
+// int getdirentries(int fd, char *buf, int nbytes, long *basep);
+#if (FREEBSD_VERS >= FREEBSD_12)
+PRE(sys_freebsd11_getdirentries)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_freebsd11_getdirentries ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3);
+   PRE_REG_READ4(int, "getdirentries",
+                 int, fd, char *, buf,
+                 int, nbytes,
+                 long *, basep);
+   PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 );
+   if (ARG4)
+      PRE_MEM_WRITE( "getdirentries(basep)", ARG4, sizeof(long) );
+}
+
+POST(sys_freebsd11_getdirentries)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0) {
+      POST_MEM_WRITE( ARG2, RES );
+      if ( ARG4 != 0 )
+         POST_MEM_WRITE( ARG4, sizeof (long));
+   }
+}
+#else
+PRE(sys_getdirentries)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_getdirentries ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3);
+   PRE_REG_READ4(int, "getdirentries",
+                 int, fd, char *, buf,
+                 int, nbytes,
+                 long *, basep);
+   PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 );
+   if (ARG4)
+      PRE_MEM_WRITE( "getdirentries(basep)", ARG4, sizeof(long) );
+}
+
+POST(sys_getdirentries)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0) {
+      POST_MEM_WRITE( ARG2, RES );
+      if ( ARG4 != 0 )
+         POST_MEM_WRITE( ARG4, sizeof (long));
+   }
+}
+#endif
+
+// SYS_freebsd6_mmap 197
+// amd64 / x86
+
+
+// SYS___syscall  198
+// special handling
+
+// freebsd6_lseek 199 FREEBSD_VERS <= 10
+// x86/amd64
+
+// freebsd6_truncate 200 FREEBSD_VERS <= 10
+// x86/amd64
+
+// freebsd6_ftruncate 201 FREEBSD_VERS <= 10
+// x86/amd64
+
+// SYS___sysctl   202
+/* int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); */
+/*               ARG1        ARG2          ARG3         ARG4           ARG5        ARG6 */
+PRE(sys___sysctl)
+{
+   PRINT("sys_sysctl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5,ARG6 );
+
+   int* name = (int*)ARG1;
+   if (ML_(safe_to_deref)(name, sizeof(int))) {
+      PRINT("\nmib[0]: ");
+      if (SARG2 >= 1) {
+         switch (name[0]) {
+         case 0: // CTL_UNSPEC
+            PRINT("unspec");
+            break;
+         case 1: // CTL_KERN
+            PRINT("kern");
+            break;
+         case 2: // CTL_VM
+            PRINT("vm");
+            break;
+         case 3: // CTL_VFS
+            PRINT("vfs");
+            break;
+         case 4: // CTL_NET
+            PRINT("net");
+            break;
+         case 5: // CTL_DEBUG
+            PRINT("debug");
+            break;
+         case 6: // CTL_HW
+            PRINT("hw");
+            break;
+         case 7: // CTL_MACHDEP
+            PRINT("machdep");
+            break;
+         case 8: // CTL _USER
+            PRINT("user");
+            break;
+         case 9: //CTL_P1003_1B
+            PRINT("p1003_b1b");
+            break;
+         default:
+            PRINT("unrecognized (%d)", ((int*)ARG1)[0]);
+            break;
+         }
+      }
+      if (SARG2 >= 2 && ML_(safe_to_deref)(name, 2*sizeof(int))) {
+         PRINT(" mib[1]: %d\n", name[1]);
+      }
+   }
+
+   /*
+    * Special handling cases
+    *
+    * 1. kern.userstack
+    *    This sysctl returns the address of the bottom of the user stack
+    *    (that is the highest user stack address, since the stack grows
+    *    downwards). Without any special handling this would return the
+    *    address of the host userstack. We have created a stack for the
+    *    guest (in aspacemgr) and that is the one that we want the guest
+    *    to see. Aspacemgr is setup in m_main.c with the adresses and sizes
+    *    saved to file static variables in that file, so we call
+    *    VG_(get_usrstack)() to retrieve them from there.
+    */
+   if (SARG2 >= 2 && ML_(safe_to_deref)(name, 2*sizeof(int))) {
+      if (name[0] == 1 && name[1] == 33) {
+         // kern.userstack
+         Word tmp = VG_(get_usrstack)();
+         size_t* out = (size_t*)ARG3;
+         size_t* outlen = (size_t*)ARG4;
+         *out = tmp;
+         *outlen = sizeof(size_t);
+         SET_STATUS_Success(0);
+      }
+   }
+
+
+   PRE_REG_READ6(int, "__sysctl", int *, name, vki_u_int32_t, namelen, void *, oldp,
+                 vki_size_t *, oldlenp, void *, newp, vki_size_t, newlen);
+
+   // read number of ints specified in ARG2 from mem pointed to by ARG1
+   PRE_MEM_READ("sysctl(name)", (Addr)ARG1, ARG2 * sizeof(int));
+
+   // if 'newp' is not NULL can read namelen bytes from that address
+   if (ARG5 != (UWord)NULL)
+      PRE_MEM_READ("sysctl(newp)", (Addr)ARG5, ARG6);
+
+   // there are two scenarios for oldlenp/oldp
+   // 1. oldval is NULL and oldlenp is non-NULL
+   //    this is a query of oldlenp so oldlenp will be written
+   // 2. Both are non-NULL
+   //    this is a query of oldp, oldlenp will be read and oldp will
+   //    be written
+
+   // is oldlenp is not NULL, can write
+   if (ARG4 != (UWord)NULL) {
+      if (ARG3 != (UWord)NULL) {
+         // case 2 above
+         PRE_MEM_READ("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
+         if (ML_(safe_to_deref)((void*)(Addr)ARG4, sizeof(vki_size_t))) {
+            PRE_MEM_WRITE("sysctl(oldp)", (Addr)ARG3, *(vki_size_t *)ARG4);
+         } else {
+            VG_(dmsg)("Warning: Bad oldlenp address %p in sysctl\n",
+                      (void *)(Addr)ARG4);
+            SET_STATUS_Failure ( VKI_EFAULT );
+         }
+      } else {
+         // case 1 above
+         PRE_MEM_WRITE("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
+      }
+   }
+}
+
+POST(sys___sysctl)
+{
+   if (ARG4 != (UWord)NULL) {
+      if (ARG3 != (UWord)NULL) {
+         //POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t));
+         POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4);
+      } else
+         POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t));
+   }
+}
+
+// SYS_mlock   203
+// generic
+
+// SYS_munlock 204
+// generic
+
+// SYS_undelete   205
+// int undelete(const char *path);
+PRE(sys_undelete)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_undelete ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1);
+   PRE_REG_READ1(int, "undelete", const char *, path);
+   PRE_MEM_RASCIIZ( "undelete(path)", ARG1 );
+}
+
+// SYS_futimes 206
+// int futimes(int fd, const struct timeval *times);
+PRE(sys_futimes)
+{
+   PRINT("sys_lutimes ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2);
+   PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, times);
+   if (ARG2 != 0)
+      PRE_MEM_READ( "futimes(times)", ARG2, sizeof(struct vki_timeval) );
+}
+
+// SYS_getpgid 207
+// generic
+
+// SYS_poll 209
+// generic
+
+// SYS_freebsd7___semctl   220
+// int semctl(int semid, int semnum, int cmd, ...);
+PRE(sys_freebsd7___semctl)
+{
+   switch (ARG3) {
+   case VKI_IPC_INFO:
+   case VKI_SEM_INFO:
+      PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "semctl",
+                    int, semid, int, semnum, int, cmd, struct vki_semid_ds_old *, arg);
+      break;
+   case VKI_GETALL:
+   case VKI_SETALL:
+      PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "semctl",
+                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
+      break;
+   default:
+      PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",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_freebsd7___semctl)
+{
+   ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
+}
+
+// SYS_semget  221
+// int semget(key_t key, int nsems, int flag);
+PRE(sys_semget)
+{
+   PRINT("sys_semget ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "semget", vki_key_t, key, int, nsems, int, flag);
+}
+
+// SYS_semop   222
+// int semop(int semid, struct sembuf *array, size_t nops);
+PRE(sys_semop)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_semop ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "semop",
+                 int, semid, struct sembuf *, array, unsigned, nops);
+   ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
+}
+
+// SYS_freebsd7_msgctl  224
+// int msgctl(int msqid, int cmd, struct msqid_ds_old *buf);
+PRE(sys_freebsd7_msgctl)
+{
+   PRINT("sys_freebsd7_msgctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3 );
+
+   PRE_REG_READ3(int, "msgctl", int, msqid, int, cmd, struct msqid_ds_old *, buf);
+
+   switch (ARG2 /* cmd */) {
+   case VKI_IPC_STAT:
+      PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)",
+                     ARG3, sizeof(struct vki_msqid_ds_old) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "msgctl(IPC_SET, buf)",
+                    ARG3, sizeof(struct vki_msqid_ds_old) );
+      break;
+   }
+}
+
+POST(sys_freebsd7_msgctl)
+{
+   switch (ARG2 /* cmd */) {
+   case VKI_IPC_STAT:
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_msqid_ds_old) );
+      break;
+   }
+}
+
+// SYS_msgget  225
+// int msgget(key_t key, int msgflg);
+PRE(sys_msgget)
+{
+   PRINT("sys_msgget ( %" FMT_REGWORD"d, %" FMT_REGWORD"d )",SARG1,SARG2);
+   PRE_REG_READ2(int, "msgget", key_t, key, int, msgflg);
+}
+
+// SYS_msgsnd  226
+// int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
+PRE(sys_msgsnd)
+{
+   PRINT("sys_msgsnd ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,ARG2,SARG3,SARG4 );
+   PRE_REG_READ4(int, "msgsnd", int, msqid, struct msgbuf *, msgp, size_t, msgsz, int, msgflg);
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2;
+   PRE_MEM_READ( "msgsnd(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   PRE_MEM_READ( "msgsnd(msgp->mtext)", (Addr)&msgp->mtext, ARG3 );
+}
+// SYS_msgrcv  227
+// ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
+PRE(sys_msgrcv)
+{
+   *flags |= SfMayBlock;
+
+   PRINT("sys_msgrcv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1,ARG2,ARG3,SARG4,SARG5 );
+   PRE_REG_READ5(ssize_t, "msgrcv", int, msqid, struct msgbuf *, msgp, size_t, msgsz,
+                 long, msgtyp, int, msgflg);
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2;
+   PRE_MEM_WRITE( "msgrcv(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   PRE_MEM_WRITE( "msgrcv(msgp->mtext)", (Addr)&msgp->mtext, ARG3 );
+}
+
+POST(sys_msgrcv)
+{
+   struct vki_msgbuf *msgp = (struct vki_msgbuf *)ARG2;
+   POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) );
+   POST_MEM_WRITE( (Addr)&msgp->mtext, RES );
+}
+
+// SYS_shmat   228
+// void * shmat(int shmid, const void *addr, int flag);
+PRE(sys_shmat)
+{
+   UWord arg2tmp;
+   PRINT("sys_shmat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(void *, "shmat",
+                 int, shmid, const void *, addr, int, flag);
+   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);
+}
+
+// SYS_freebsd7_shmctl  229
+// int shmctl(int shmid, int cmd, struct shmid_ds *buf);
+PRE(sys_freebsd7_shmctl)
+{
+   PRINT("sys_freebsd7_shmctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,SARG2,ARG3);
+   PRE_REG_READ3(int, "shmctl",
+                 int, shmid, int, cmd, struct vki_shmid_ds_old *, buf);
+   switch (ARG2 /* cmd */) {
+   case VKI_IPC_STAT:
+      PRE_MEM_WRITE( "shmctl7(IPC_STAT, buf)",
+                     ARG3, sizeof(struct vki_shmid_ds_old) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "shmctl7(IPC_SET, buf)",
+                    ARG3, sizeof(struct vki_shmid_ds_old) );
+      break;
+   }
+}
+
+POST(sys_freebsd7_shmctl)
+{
+   if (ARG2 == VKI_IPC_STAT) {
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds_old) );
+   }
+}
+
+// SYS_shmdt   230
+// int shmdt(const void *addr);
+PRE(sys_shmdt)
+{
+   PRINT("sys_shmdt ( %#" FMT_REGWORD "x )",ARG1);
+   PRE_REG_READ1(int, "shmdt", const void *, addr);
+   if (!ML_(generic_PRE_sys_shmdt)(tid, ARG1))
+      SET_STATUS_Failure( VKI_EINVAL );
+}
+
+POST(sys_shmdt)
+{
+   ML_(generic_POST_sys_shmdt)(tid, RES,ARG1);
+}
+
+// SYS_shmget  231
+// int shmget(key_t key, size_t size, int flag);
+PRE(sys_shmget)
+{
+   PRINT("sys_shmget ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "shmget", vki_key_t, key, vki_size_t, size, int, flag);
+}
+
+
+// SYS_clock_gettime 232
+// int clock_gettime(clockid_t clock_id, struct timespec *tp);
+PRE(sys_clock_gettime)
+{
+   PRINT("sys_clock_gettime( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2);
+   PRE_REG_READ2(int, "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) );
+}
+
+// SYS_clock_settime 233
+// int clock_settime(clockid_t clock_id, const struct timespec *tp);
+PRE(sys_clock_settime)
+{
+   PRINT("sys_clock_settime( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2);
+   PRE_REG_READ2(int, "clock_settime",
+                 vki_clockid_t, clk_id, const struct timespec *, tp);
+   PRE_MEM_READ( "clock_settime(tp)", ARG2, sizeof(struct vki_timespec) );
+}
+
+// SYS_clock_getres  234
+// int clock_getres(clockid_t clock_id, struct timespec *tp);
+PRE(sys_clock_getres)
+{
+   PRINT("sys_clock_getres( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2);
+   // Nb: we can't use "RES" as the param name because that's a macro
+   // defined above!
+   PRE_REG_READ2(int, "clock_getres",
+                 vki_clockid_t, clock_id, struct timespec *, tp);
+   if (ARG2 != 0)
+      PRE_MEM_WRITE( "clock_getres(tp)", ARG2, sizeof(struct vki_timespec) );
+}
+
+POST(sys_clock_getres)
+{
+   if (ARG2 != 0)
+      POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) );
+}
+
+// SYS_ktimer_create 235
+// int      timer_create(clockid_t clockid, struct sigevent *restrict evp,
+//                       timer_t *restrict timerid);
+PRE(sys_timer_create)
+{
+   PRINT("sys_timer_create( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", SARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "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) );
+}
+
+// SYS_ktimer_delete 236
+// int timer_delete(timer_t timerid);
+PRE(sys_timer_delete)
+{
+   PRINT("sys_timer_delete( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
+}
+
+// SYS_ktimer_settime   237
+// int timer_settime(timer_t timerid, int flags,
+//                   const struct itimerspec *restrict value,
+//                   struct itimerspec *restrict ovalue);
+PRE(sys_timer_settime)
+{
+   PRINT("sys_timer_settime( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "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) );
+}
+
+// SYS_ktimer_gettime   238
+// int timer_gettime(timer_t timerid, struct itimerspec *value);
+PRE(sys_timer_gettime)
+{
+   PRINT("sys_timer_gettime( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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) );
+}
+
+// SYS_ktimer_getoverrun   239
+// int timer_getoverrun(timer_t timerid);
+PRE(sys_timer_getoverrun)
+{
+   PRINT("sys_timer_getoverrun( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "timer_getoverrun", vki_timer_t, timerid);
+}
+
+// SYS_nanosleep  240
+// generic
+
+// SYS_ffclock_getcounter  241
+// int ffclock_getcounter(ffcounter *ffcount);
+// @todo
+
+// SYS_ffclock_setestimate 242
+// int ffclock_setestimate(struct ffclock_estimate *cest);
+// @todo
+
+// SYS_ffclock_getestimate 243
+// int ffclock_getestimate(struct ffclock_estimate *cest);
+// @todo
+
+// SYS_clock_nanosleep 244
+// int clock_nanosleep(clockid_t clock_id, int flags,
+//                     const struct timespec *rqtp, struct timespec *rmtp);
+PRE(sys_clock_nanosleep)
+{
+   *flags |= SfMayBlock|SfPostOnFail;
+   PRINT("sys_clock_nanosleep ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "clock_nanosleep", clockid_t, clock_id, int, flags,
+                 const struct timespec *, rqtp, struct timespec *, rmtp);
+   PRE_MEM_READ("clock_nanosleep(rqtp)", ARG1, sizeof(struct vki_timespec));
+   if (ARG2 != 0)
+      PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG2, sizeof(struct vki_timespec) );
+
+}
+
+POST(sys_clock_nanosleep)
+{
+   if (ARG2 != 0)
+      PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG2, sizeof(struct vki_timespec) );
+}
+
+// SYS_clock_getcpuclockid2   247
+// no manpage for this
+// @todo
+
+// SYS_ntp_gettime   248
+// int ntp_gettime(struct ntptimeval *);
+// @todo
+
+// SYS_minherit   250
+// int minherit(void *addr, size_t len, int inherit);
+PRE(sys_minherit)
+{
+   PRINT("sys_minherit( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "minherit",
+                 void *, addr, vki_size_t, len, int, inherit);
+   if (ARG2 != 0)
+      PRE_MEM_WRITE( "minherit(addr)", ARG1,ARG2 );
+}
+
+POST(sys_minherit)
+{
+   if (ARG2 != 0)
+      POST_MEM_WRITE( ARG1, ARG2 );
+}
+
+// SYS_rfork   251
+// x86/amd64 not functional
+
+// SYS_issetugid  253
+// int issetugid(void);
+PRE(sys_issetugid)
+{
+   PRINT("%s", "sys_issetugid ()");
+   PRE_REG_READ0(long, "issetugid");
+}
+
+// SYS_lchown  254
+// generic
+
+// SYS_aio_read   255
+// int aio_read(struct aiocb *iocb);
+PRE(sys_aio_read)
+{
+   PRINT("sys_aio_read ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "aio_read", struct vki_aiocb *, iocb);
+   PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb));
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      PRE_MEM_WRITE( "aio_read(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
+   }
+}
+
+POST(sys_aio_read)
+{
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      POST_MEM_WRITE((Addr)iocb, sizeof(struct vki_aiocb));
+   }
+}
+
+// SYS_aio_write  256
+// int aio_write(struct aiocb *iocb);
+PRE(sys_aio_write)
+{
+   PRINT("sys_aio_write ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "aio_write", struct vki_aiocb *, iocb);
+   PRE_MEM_READ("aio_read(iocb)", ARG1, sizeof(struct vki_aiocb));
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
+   }
+}
+
+POST(sys_aio_write)
+{
+   if (ML_(safe_to_deref)((struct vki_aiocb *)ARG1, sizeof(struct vki_aiocb))) {
+      struct vki_aiocb *iocb = (struct vki_aiocb *)ARG1;
+      PRE_MEM_WRITE( "aio_write(iocb->aio_offset)", (Addr)iocb, sizeof(struct vki_aiocb));
+   }
+}
+
+// SYS_lio_listio 257
+// int lio_listio(int mode, struct aiocb * const list[], int nent,
+//                struct sigevent *sig);
+PRE(sys_lio_listio)
+{
+   PRINT("sys_lio_listio ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
+         SARG1, ARG2, SARG3, ARG4);
+   PRE_REG_READ4(int, "lio_listio", int, mode, struct aiocb * const *, list, int, nent,
+                 struct sigevent *,sig);
+   PRE_MEM_READ("lio_listio(list)", ARG2, ARG3*sizeof(struct vki_aiocb *));
+   // loop check elements
+   if (ML_(safe_to_deref)((struct vki_aiocb **)ARG2, ARG3*sizeof(struct vki_aiocb *))) {
+      struct vki_aiocb** list = (struct vki_aiocb **)ARG2;
+      for (int i = 0; i < (int)ARG3; ++i) {
+         if (list[i]) {
+            PRE_MEM_READ("lio_listio(list[?])", (Addr)list[i], ARG3*sizeof(struct vki_aiocb));
+         }
+         // @todo
+         // figure out what gets read/written
+         // when list[i]->aio_lio_opcode == VKI_LIO_READ and
+         // when list[i]->aio_lio_opcode == VKI_LIO_WRITE
+         //if (ML_(safe_to_deref)(list[i], ARG3*sizeof(struct vki_aiocb))) {
+         //}
+      }
+   }
+
+   if (ARG1 & VKI_LIO_WAIT) {
+      *flags |= SfMayBlock;
+   }
+
+   if (ARG4 && (ARG1 == VKI_LIO_NOWAIT)) {
+      PRE_MEM_READ("lio_listio(sig)", ARG4, sizeof(struct vki_sigevent));
+   }
+}
+
+// SYS_freebsd11_getdents  272
+// generic
+
+// SYS_lchmod  274
+// int lchmod(const char *path, mode_t mode);
+PRE(sys_lchmod)
+{
+   PRINT("sys_lchmod ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "lchmod", const char *, path, vki_mode_t, mode);
+   PRE_MEM_RASCIIZ( "lchmod(path)", ARG1 );
+}
+
+// SYS_lutimes 276
+// int lutimes(const char *path, const struct timeval *times);
+PRE(sys_lutimes)
+{
+   PRINT("sys_lutimes ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "lutimes", char *, path, struct timeval *, times);
+   PRE_MEM_RASCIIZ( "lutimes(path)", ARG1 );
+   if (ARG2 != 0)
+      PRE_MEM_READ( "lutimes(times)", ARG2, sizeof(struct vki_timeval) );
+}
+
+// SYS_freebsd11_nstat  278
+// @todo, maybe
+
+// SYS_freebsd11_nfstat 279
+// @todo, maybe
+
+// SYS_freebsd11_nlstat 280
+// @todo, maybe
+
+// SYS_preadv  289
+// amd64 / x86
+
+// SYS_pwritev 290
+// amd64 / x86
+
+// SYS_fhopen  298
+// int fhopen(const fhandle_t *fhp, int flags);
+PRE(sys_fhopen)
+{
+   PRINT("sys_open ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",ARG1,ARG2);
+   PRE_REG_READ2(int, "fhopen",
+                 struct fhandle_t *, 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);
+   }
+}
+
+// SYS_freebsd11_fhstat 299
+// int fhstat(const fhandle_t *fhp, struct stat *sb);
+#if (FREEBSD_VERS >= FREEBSD_12)
+PRE(sys_freebsd11_fhstat)
+{
+   PRINT("sys_freebsd11_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "fhstat", struct fhandle *, fhp, struct freebd11_stat *, sb);
+   PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) );
+   PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_freebsd11_fhstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+#else
+PRE(sys_fhstat)
+{
+   PRINT("sys_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "fhstat", struct fhandle *, fhp, struct stat *, sb);
+   PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) );
+   PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_fhstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_stat) );
+}
+
+#endif
+
+// SYS_modnext 300
+// int modnext(int modid);
+PRE(sys_modnext)
+{
+   PRINT("sys_modnext ( %" FMT_REGWORD "d )",SARG1);
+   PRE_REG_READ1(int, "modnext", int, modid);
+}
+
+// SYS_modstat 301
+// int modstat(int modid, struct module_stat *stat);
+PRE(sys_modstat)
+{
+   PRINT("sys_modstat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "modstat", int, modid, struct module_stat *, buf);
+   PRE_MEM_WRITE( "modstat(stat)", ARG2, sizeof(struct vki_module_stat) );
+}
+
+POST(sys_modstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_module_stat) );
+}
+
+// SYS_modfnext   302
+// int modfnext(int modid);
+PRE(sys_modfnext)
+{
+   PRINT("sys_modfnext ( %" FMT_REGWORD "d )",SARG1);
+   PRE_REG_READ1(int, "modfnext", int, modid);
+}
+
+// SYS_modfind 303
+// int modfind(const char *modname);
+PRE(sys_modfind)
+{
+   PRINT("sys_modfind ( %#" FMT_REGWORD "x )",ARG1);
+   PRE_REG_READ1(long, "modfind", char *, modname);
+   PRE_MEM_RASCIIZ( "modfind(modname)", ARG1 );
+}
+
+// SYS_kldload 304
+// int kldload(const char *file);
+PRE(sys_kldload)
+{
+   PRINT("sys_kldload ( %#" FMT_REGWORD "x(%s) )", ARG1, (char *)ARG1);
+   PRE_REG_READ1(int, "kldload", const char *, "file");
+   PRE_MEM_RASCIIZ( "kldload(file)", ARG1 );
+}
+
+// SYS_kldunload  305
+// int kldunload(int fileid);
+PRE(sys_kldunload)
+{
+   PRINT("sys_kldunload ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(int, "kldunload", int, "fileid");
+}
+
+// SYS_kldfind 306
+// int kldfind(const char *file);
+PRE(sys_kldfind)
+{
+   PRINT("sys_kldfind ( %#" FMT_REGWORD "x(%s) )", ARG1, (char *)ARG1);
+   PRE_REG_READ1(int, "kldfind", const char *, file);
+   PRE_MEM_RASCIIZ( "kldfind(file)", ARG1 );
+}
+
+// SYS_kldnext 307
+// int kldnext(int fileid);
+PRE(sys_kldnext)
+{
+   PRINT("sys_kldnext ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(int, "kldnext", int, fileid);
+}
+
+// SYS_kldstat 308
+// int kldstat(int fileid, struct kld_file_stat *stat);
+PRE(sys_kldstat)
+{
+   PRINT("sys_kldstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "kldstat", int, fileid, struct kld_file_stat*, stat);
+   PRE_MEM_WRITE("kldstat(stat)", ARG2, sizeof(struct vki_kld_file_stat));
+}
+
+POST(sys_kldstat)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_kld_file_stat));
+}
+
+// SYS_kldfirstmod   309
+// int kldfirstmod(int fileid);
+PRE(sys_kldfirstmod)
+{
+   PRINT("sys_kldfirstmod ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(int, "kldfirstmod", int, fileid);
+}
+
+// SYS_setresuid  311
+// int setresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+PRE(sys_setresuid)
+{
+   PRINT("sys_setresuid ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "setresuid",
+                 vki_uid_t, ruid, vki_uid_t, euid, vki_uid_t, suid);
+}
+
+// SYS_setresgid  312
+// int setresgid(gid_t rgid, gid_t egid, gid_t sgid);
+PRE(sys_setresgid)
+{
+   PRINT("sys_setresgid ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "setresgid",
+                 vki_gid_t, rgid, vki_gid_t, egid, vki_gid_t, sgid);
+}
+
+// SYS_aio_return 314
+// ssize_t aio_return(struct aiocb *iocb);
+PRE(sys_aio_return)
+{
+   PRINT("sys_aio_return ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(ssize_t, "aio_return", struct aiocb *, iocb);
+   // not too clear if this is read-only, sounds like it from the man page
+   // but it isn't const
+   PRE_MEM_READ("aio_return(iocb)", ARG1, sizeof(struct vki_aiocb));
+}
+
+// SYS_aio_suspend   315
+// int aio_suspend(const struct aiocb *const iocbs[], int niocb,
+//                 const struct timespec *timeout);
+PRE(sys_aio_suspend)
+{
+   PRINT("sys_aio_suspend ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ3(int, "aio_suspend", struct aiocb **, iocbs, int, nbiocb, const struct timespec*, timeout);
+   PRE_MEM_READ("aio_suspend(iocbs)", ARG1, ARG2*sizeof(struct vki_aiocb));
+   PRE_MEM_READ("aio_suspend(timeout)", ARG3, sizeof(struct vki_timespec));
+}
+
+// SYS_aio_cancel 316
+// int aio_cancel(int fildes, struct aiocb *iocb);
+PRE(sys_aio_cancel)
+{
+   PRINT("sys_aio_cancel ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "aio_cancel", int, fildex, struct aiocb *, iocb);
+   if (ARG2) {
+      PRE_MEM_READ("aio_cancel(iocb)", ARG2, sizeof(struct vki_aiocb));
+   }
+}
+
+// SYS_aio_error  317
+// int aio_error(const struct aiocb *iocb);
+PRE(sys_aio_error)
+{
+   PRINT("sys_aio_error ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(ssize_t, "aio_error", struct aiocb *, iocb);
+   PRE_MEM_READ("aio_error(iocb)", ARG1, sizeof(struct vki_aiocb));
+}
+
+// SYS_yield   321
+int yield(void);
+PRE(sys_yield)
+{
+   *flags |= SfMayBlock;
+   PRINT("%s", "yield()");
+   PRE_REG_READ0(long, "yield");
+}
+
+// SYS_mlockall   324
+// generic
+
+// SYS_munlockall 325
+// int munlockall(void);
+PRE(sys_munlockall)
+{
+   *flags |= SfMayBlock;
+   PRINT("%s", "sys_munlockall ( )");
+   PRE_REG_READ0(int, "munlockall");
+}
+
+// SYS___getcwd   326
+// int __getcwd(char *buf, size_t buflen);
+PRE(sys___getcwd)
+{
+   PRINT("sys___getcwd ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2);
+   PRE_REG_READ2(long, "__getcwd", char *, buf, unsigned int, buflen);
+   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 );
+   }
+}
+
+//SYS_sched_setparam 327
+// int sched_setparam(pid_t pid, const struct sched_param *param);
+PRE(sys_sched_setparam)
+{
+   PRINT("sched_setparam ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2 );
+   PRE_REG_READ2(int, "sched_setparam",
+                 vki_pid_t, pid, struct sched_param *, param);
+   PRE_MEM_READ( "sched_setparam(param)", ARG2, sizeof(struct vki_sched_param) );
+}
+
+POST(sys_sched_setparam)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) );
+}
+
+// SYS_sched_getparam   328
+// int sched_getparam(pid_t pid, struct sched_param *param);
+PRE(sys_sched_getparam)
+{
+   PRINT("sched_getparam ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2 );
+   PRE_REG_READ2(int, "sched_getparam",
+                 vki_pid_t, pid, struct sched_param *, param);
+   PRE_MEM_WRITE( "sched_getparam(param)", ARG2, sizeof(struct vki_sched_param) );
+}
+
+POST(sys_sched_getparam)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) );
+}
+
+// SYS_sched_setscheduler  329
+// int sched_setscheduler(pid_t pid, int policy,
+//                        const struct sched_param *param);
+PRE(sys_sched_setscheduler)
+{
+   PRINT("sys_sched_setscheduler ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3);
+   PRE_REG_READ3(int, "sched_setscheduler",
+                 vki_pid_t, pid, int, policy, struct sched_param *, param);
+   if (ARG3 != 0)
+      PRE_MEM_READ("sched_setscheduler(param)",
+                   ARG3, sizeof(struct vki_sched_param));
+}
+
+// SYS_sched_getscheduler  330
+// int sched_getscheduler(pid_t pid);
+PRE(sys_sched_getscheduler)
+{
+   PRINT("sys_sched_getscheduler ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "sched_getscheduler", vki_pid_t, pid);
+}
+
+// SYS_sched_yield   331
+// int sched_yield(void);
+PRE(sys_sched_yield)
+{
+   *flags |= SfMayBlock;
+   PRINT("sched_yield()");
+   PRE_REG_READ0(int, "sched_yield");
+}
+
+// SYS_sched_get_priority_max 332
+// int sched_get_priority_max(int policy);
+PRE(sys_sched_get_priority_max)
+{
+   PRINT("sched_get_priority_max ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(long, "sched_get_priority_max", int, policy);
+}
+
+// SYS_sched_get_priority_min 333
+// int sched_get_priority_min(int policy);
+PRE(sys_sched_get_priority_min)
+{
+   PRINT("sched_get_priority_min ( %" FMT_REGWORD "u )", ARG1);
+   PRE_REG_READ1(long, "sched_get_priority_min", int, policy);
+}
+
+// SYS_sched_rr_get_interval  334
+// int sched_rr_get_interval(pid_t pid, struct timespec *interval);
+PRE(sys_sched_rr_get_interval)
+{
+   PRINT("sys_sched_rr_get_interval ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "sched_rr_get_interval", vki_pid_t, pid, struct vki_timespec *,interval);
+   PRE_MEM_WRITE("sys_sched_rr_get_interval(interval)", ARG2, sizeof(struct vki_timespec));
+}
+
+POST(sys_sched_rr_get_interval)
+{
+   POST_MEM_WRITE(ARG2, sizeof(struct vki_timespec));
+}
+
+// SYS_utrace  335
+// int utrace(const void *addr, size_t len);
+PRE(sys_utrace)
+{
+   PRINT("sys_utrace ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2);
+   PRE_REG_READ2(int, "utrace", const void *, addr, vki_size_t, len);
+   PRE_MEM_READ( "utrace(addr)", ARG2, ARG3 );
+}
+
+// SYS_kldsym  337
+// int kldsym(int fileid, int cmd, void *data);
+PRE(sys_kldsym)
+{
+   PRINT("sys_kldsym ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3 );
+   PRE_REG_READ3(int, "kldsym", int, fileid, int, cmd, 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;
+   if (ML_(safe_to_deref)(kslp, sizeof(struct vki_kld_sym_lookup))) {
+      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) );
+}
+
+// SYS_jail 338
+// int jail(struct jail *jail);
+PRE(sys_jail)
+{
+   PRINT("sys_jail ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "jail", struct jail *, jail);
+   PRE_MEM_READ( "jail(jail)", ARG1, sizeof(struct vki_jail) );
+}
+
+// SYS_nnpfs_syscall 338
+// @todo
+
+// SYS_sigprocmask   340
+// int sigprocmask(int how, const sigset_t * restrict set,
+//                 sigset_t * restrict oset);
+PRE(sys_sigprocmask)
+{
+   PRINT("sys_sigprocmask ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "sigprocmask",
+                 int, how, vki_sigset_t *, set, vki_sigset_t *, oset);
+   if (ARG2 != 0)
+      PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
+   if (ARG3 != 0)
+      PRE_MEM_WRITE( "sigprocmask(oset)", ARG3, sizeof(vki_sigset_t));
+
+   if (ARG2 != 0  &&
+         !ML_(safe_to_deref)((void *)(Addr)ARG2, sizeof(vki_sigset_t))) {
+      VG_(dmsg)("Warning: Bad set handler address %p in sigprocmask\n",
+                (void *)(Addr)ARG2);
+      SET_STATUS_Failure ( VKI_EFAULT );
+   } else if (ARG3 != 0 &&
+              !ML_(safe_to_deref)((void *)(Addr)ARG3, sizeof(vki_sigset_t))) {
+      VG_(dmsg)("Warning: Bad oldset address %p in sigprocmask\n",
+                (void *)(Addr)ARG3);
+      SET_STATUS_Failure ( VKI_EFAULT );
+   } else {
+      SET_STATUS_from_SysRes(VG_(do_sys_sigprocmask)(tid, ARG1 /*how*/,
+                             (vki_sigset_t*)(Addr)ARG2,
+                             (vki_sigset_t*)(Addr)ARG3));
+   }
+
+   if (SUCCESS)
+      *flags |= SfPollAfter;
+}
+
+POST(sys_sigprocmask)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0 && ARG3 != 0)
+      POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t));
+}
+
+// SYS_sigsuspend 341
+// int sigsuspend(const sigset_t *sigmask);
+PRE(sys_sigsuspend)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sigsuspend ( %#" FMT_REGWORD "x )", ARG1 );
+   PRE_REG_READ1(int, "sigsuspend", const vki_sigset_t *, sigmask);
+   PRE_MEM_READ( "sigsuspend(sigmask)", ARG1, sizeof(vki_sigset_t) );
+   if (ARG1) {
+      ARG1 = ML_(make_safe_mask)("syswrap.sigsuspend.1", (Addr)ARG1);
+   }
+}
+
+POST(sys_sigsuspend)
+{
+   ML_(free_safe_mask) ( (Addr)ARG1 );
+}
+
+// SYS_sigpending 343
+// int sigpending(sigset_t *set);
+PRE(sys_sigpending)
+{
+   PRINT( "sys_sigpending ( %#" FMT_REGWORD "x )", ARG1 );
+   PRE_REG_READ1(int, "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) ) ;
+}
+
+
+// SYS_sigtimedwait  345
+// int sigtimedwait(const sigset_t *restrict set, siginfo_t *restrict info,
+//                  const struct timespec *restrict timeout);
+PRE(sys_sigtimedwait)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sigtimedwait ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "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) );
+}
+
+// SYS_sigwaitinfo   346
+// int sigwaitinfo(const sigset_t * restrict set, siginfo_t * restrict info);
+PRE(sys_sigwaitinfo)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sigwaitinfo ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         ARG1,ARG2);
+   PRE_REG_READ2(int, "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) );
+}
+
+// SYS___acl_get_file   347
+// int __acl_get_file(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_get_file)
+{
+   PRINT("sys___acl_get_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_get_file",
+                 const char *, path, int, type, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ("acl_get_file(path", ARG1);
+   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) );
+   }
+}
+
+// SYS___acl_set_file   348
+// int __acl_set_file(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_set_file)
+{
+   PRINT("sys___acl_set_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_set_file",
+                 const char *, path, int, type, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ("acl_set_file(path", ARG1);
+   PRE_MEM_READ("acl_set_file(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+
+// SYS___acl_get_fd  349
+// int __acl_get_fd(int filedes, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_get_fd)
+{
+   PRINT("sys___acl_get_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_get_fd",
+                 int, fd, int, type, 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) );
+   }
+}
+
+// SYS___acl_set_fd  350
+// int __acl_set_fd(int filedes, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_set_fd)
+{
+   PRINT("sys___acl_set_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_set_fd",
+                 int, filedes, int, type, struct vki_acl *, aclp);
+   PRE_MEM_READ( "acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+
+// SYS___acl_delete_file   351
+// int __acl_delete_file(const char *path, acl_type_t type);
+PRE(sys___acl_delete_file)
+{
+   PRINT("sys___acl_delete_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2);
+   PRE_MEM_RASCIIZ("acl_set_file(path", ARG1);
+   PRE_REG_READ2(int, "acl_delete_file",
+                 const char *, path, int, type);
+}
+// SYS___acl_delete_fd  352
+// int __acl_delete_fd(int filedes, acl_type_t type);
+PRE(sys___acl_delete_fd)
+{
+   PRINT("sys___acl_delete_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2);
+   PRE_REG_READ2(int, "acl_delete_fd",
+                 int, filedes, int, acltype);
+}
+
+// SYS___acl_aclcheck_file 353
+// int __acl_aclcheck_file(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_aclcheck_file)
+{
+   PRINT("sys___acl_aclcheck_file ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_aclcheck_file",
+                 const char *, path, int, type, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ("acl_set_file(path", ARG1);
+   PRE_MEM_READ( "acl_aclcheck_file(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+
+// SYS___acl_aclcheck_fd   354
+// int __acl_aclcheck_fd(int filedes, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_aclcheck_fd)
+{
+   PRINT("sys___acl_aclcheck_fd ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "acl_aclcheck_fd",
+                 int, fd, int, type, struct vki_acl *, aclp);
+   PRE_MEM_READ( "acl_aclcheck_fd(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+
+// SYS_extattrctl 355
+// no manpage?
+// syscalls.master: int extattrctl(_In_z_ const char *path, int cmd, _In_z_opt_ const char *filename, int attrnamespace, _In_z_ const char *attrname);
+PRE(sys_extattrctl)
+{
+   PRINT("sys_extattrctl ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3,SARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "extattrctl",
+                 const char *, path, int, cmd, const char *, filename, int, attrnamespace, const char *, attrname);
+   PRE_MEM_RASCIIZ("extattrctl(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattrctl(filename)", ARG3);
+   PRE_MEM_RASCIIZ("extattrctl(attrname)", ARG5);
+}
+
+// SYS_extattr_set_file 356
+// ssize_t extattr_set_file(const char *path, int attrnamespace,
+//                          const char *attrname, const void *data, size_t nbytes);
+PRE(sys_extattr_set_file)
+{
+   PRINT("sys_extattr_set_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "extattr_set_file",
+                 const char *, path, int, attrnamespace, const char *, attrname, const void *, data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_set_file(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_set_file(attrname)", ARG3);
+   PRE_MEM_READ("extattr_set_file(data)", ARG4, ARG5);
+}
+
+// SYS_extattr_get_file 357
+// ssize_t extattr_get_file(const char *path, int attrnamespace,
+//                          const char *attrname, void *data, size_t nbytes);
+PRE(sys_extattr_get_file)
+{
+   PRINT("sys_extattr_get_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "extattr_get_file",
+                 const char *, path, int, attrnamespace, const char *, attrname, void *, data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_get_file(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_get_file(attrname)", ARG3);
+   if (ARG4) {
+      PRE_MEM_WRITE("extattr_get_file(data)", ARG4, ARG5);
+   }
+}
+
+POST(sys_extattr_get_file)
+{
+   if (ARG4) {
+      POST_MEM_WRITE(ARG4, ARG5);
+   }
+}
+
+// SYS_extattr_delete_file 358
+// int extattr_delete_file(const char *path, int attrnamespace,
+//                         const char *attrname);
+PRE(sys_extattr_delete_file)
+{
+   PRINT("sys_extattr_delete_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3);
+   PRE_REG_READ3(ssize_t, "extattr_delete_file",
+                 const char *, path, int, attrnamespace, const char *, attrname);
+   PRE_MEM_RASCIIZ("extattr_delete_file(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_delete_file(attrname)", ARG3);
+}
+
+// SYS_aio_waitcomplete 359
+// ssize_t aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout);
+PRE(sys_aio_waitcomplete)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_aio_waitcomplete ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2);
+   PRE_REG_READ2(ssize_t, "aio_waitcomplete", struct aiocb **, iocbp, struct timespec *, timeout);
+   if (ARG2) {
+      PRE_MEM_READ("aio_waitcomplete(timeout", ARG2, sizeof(struct vki_timespec));
+   }
+   PRE_MEM_WRITE( "aio_waitcomplete(iocbp)", ARG1, sizeof(struct aiocb *));
+}
+
+POST(sys_aio_waitcomplete)
+{
+   POST_MEM_WRITE(ARG1, sizeof(struct aiocb *));
+}
+
+// SYS_getresuid  360
+// int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+PRE(sys_getresuid)
+{
+   PRINT("sys_getresuid ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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) );
+   }
+}
+
+// SYS_getresgid  361
+// int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
+PRE(sys_getresgid)
+{
+   PRINT("sys_getresgid ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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) );
+   }
+}
+
+// SYS_kqueue  362
+// int kqueue(void);
+PRE(sys_kqueue)
+{
+   PRINT("%s", "sys_kqueue ()");
+   PRE_REG_READ0(omt, "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);
+      }
+   }
+}
+
+// SYS_freebsd11_kevent 363
+// int kevent(int kq, const struct kevent *changelist, int nchanges,
+//            struct kevent *eventlist, int nevents,
+//            const struct timespec *timeout);
+#if (FREEBSD_VERS >= FREEBSD_12)
+PRE(sys_freebsd11_kevent)
+{
+   PRINT("sys_freebsd11_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(int, "kevent",
+                 int, fd, const struct vki_kevent_freebsd11 *, changelist, int, nchanges,
+                 struct vki_kevent_freebsd11 *, eventlist, int, nevents,
+                 struct timespec *, timeout);
+   if (ARG2 != 0 && ARG3 != 0)
+      PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent_freebsd11)*ARG3 );
+   if (ARG4 != 0 && ARG5 != 0)
+      PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent_freebsd11)*ARG5);
+   if (ARG5 != 0)
+      *flags |= SfMayBlock;
+   if (ARG6 != 0)
+      PRE_MEM_READ( "kevent(timeout)",
+                    ARG6, sizeof(struct vki_timespec));
+}
+
+POST(sys_freebsd11_kevent)
+{
+   vg_assert(SUCCESS);
+   if ((Word)RES != -1) {
+      if (ARG4 != 0)
+         POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent_freebsd11)*RES) ;
+   }
+}
+#else
+PRE(sys_kevent)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(int, "kevent",
+                 int, fd, struct vki_kevent_freebsd11 *, changelist, int, nchanges,
+                 struct vki_kevent_freebsd11 *, eventlist, int, nevents,
+                 struct timespec *, timeout);
+   if (ARG2 != 0 && ARG3 != 0)
+      PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent_freebsd11)*ARG3 );
+   if (ARG4 != 0 && ARG5 != 0)
+      PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent_freebsd11)*ARG5);
+   if (ARG6 != 0)
+      PRE_MEM_READ( "kevent(timeout)",
+                    ARG6, sizeof(struct vki_timespec));
+}
+
+POST(sys_kevent)
+{
+   vg_assert(SUCCESS);
+   if ((Word)RES != -1) {
+      if (ARG4 != 0)
+         POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent_freebsd11)*RES) ;
+   }
+}
+#endif
+
+// SYS_extattr_set_fd   371
+// ssize_t extattr_set_fd(int fd, int attrnamespace, const char *attrname,
+//                        const void *data, size_t nbytes);
+PRE(sys_extattr_set_fd)
+{
+   PRINT("sys_extattr_set_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "extattr_set_fd", int, fd, int, attrnamespace, const char *,attrname, const void *,data, size_t, nbytes);
+   PRE_MEM_RASCIIZ( "extattr_set_fd(attrname)", ARG3 );
+   PRE_MEM_READ("extattr_set_fd(data)", ARG4, ARG5);
+}
+
+// SYS_extattr_get_fd   372
+// ssize_t extattr_get_fd(int fd, int attrnamespace, const char *attrname,
+//                        void *data, size_t nbytes);
+PRE(sys_extattr_get_fd)
+{
+   PRINT("sys_extattr_get_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "extattr_get_fd", int, fd, int, attrnamespace, const char *,attrname, const void *,data, size_t, nbytes);
+   PRE_MEM_RASCIIZ( "extattr_get_fd(attrname)", ARG3 );
+   PRE_MEM_WRITE("extattr_get_fd(data)", ARG4, ARG5);
+}
+
+POST(sys_extattr_get_fd)
+{
+   POST_MEM_WRITE(ARG4, ARG5);
+}
+
+// SYS_extattr_delete_fd   373
+// int extattr_delete_fd(int fd, int attrnamespace, const char *attrname);
+PRE(sys_extattr_delete_fd)
+{
+   PRINT("sys_extattr_delete_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3);
+   PRE_REG_READ3(int, "extattr_delete_fd", int, fd, int, attrnamespace, const char *,attrname);
+   PRE_MEM_RASCIIZ( "extattr_delete_fd(attrname)", ARG3 );
+}
+
+// SYS___setugid  374
+// no manpage?
+// syscalls.master: int __setugid(int flag);
+PRE(sys___setugid)
+{
+   PRINT("sys___setugid ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "__setugid", int, flag);
+}
+
+// SYS_eaccess 376
+// int eaccess(const char *path, int mode);
+PRE(sys_eaccess)
+{
+   PRINT("sys_eaccess ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char*)ARG1,ARG2);
+   PRE_REG_READ2(int, "eaccess", const char *, path, int, mode);
+   PRE_MEM_RASCIIZ( "eaccess(path)", ARG1 );
+}
+
+// SYS_afs3_syscall  377
+// @todo
+
+// SYS_nmount  378
+// int nmount(struct iovec *iov, u_int niov, int flags);
+PRE(sys_nmount)
+{
+   PRINT("sys_nmount ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d )", ARG1, ARG2, SARG3);
+   PRE_REG_READ3(int, "nmount", struct iovec *, iov, u_int, niov, int, flags);
+   PRE_MEM_READ( "nmount(pathname)", ARG1, ARG2*sizeof(struct vki_iovec) );
+}
+
+// SYS___mac_get_proc   384
+// @todo
+
+// SYS___mac_set_proc   385
+// @todo
+
+// SYS___mac_get_fd  386
+// @todo
+
+// SYS___mac_get_file   387
+// @todo
+
+// SYS___mac_set_fd  388
+// @todo
+
+// SYS___mac_set_file   389
+// @todo
+
+// SYS_kenv 390
+// int kenv(int action, const char *name, char *value, int len);
+PRE(sys_kenv)
+{
+   PRINT("sys_kenv ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "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:
+      VG_(dmsg)("Warning: Bad action %" FMT_REGWORD "u in kenv\n", ARG1);
+   }
+}
+
+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;
+      }
+   }
+}
+
+// SYS_lchflags   391
+// int lchflags(const char *path, unsigned long flags);
+PRE(sys_lchflags)
+{
+   PRINT("sys_lchflags ( %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "lchflags",
+                 const char *, path, unsigned long, flags);
+   PRE_MEM_RASCIIZ( "lchflags(path)", ARG1 );
+}
+
+// SYS_uuidgen 392
+// int uuidgen(struct uuid *store, int count);
+PRE(sys_uuidgen)
+{
+   PRINT("sys_uuidgen ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,ARG2);
+   PRE_REG_READ2(int, "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) );
+}
+
+// SYS_sendfile   393
+// x86/amd64
+
+// SYS_mac_syscall   394
+// @todo
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+
+// SYS_freebsd11_getfsstat 395
+// int getfsstat(struct freebsd11_statfs *buf, long bufsize, int mode);
+
+PRE(sys_freebsd11_getfsstat)
+{
+   PRINT("sys_freebsd11_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "getfsstat", struct vki_freebsd11_statfs *, buf, long, bufsize, int, mode);
+   PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 );
+}
+
+POST(sys_freebsd11_getfsstat)
+{
+   vg_assert(SUCCESS);
+   if ((Word)RES != -1) {
+      POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_freebsd11_statfs) );
+   }
+}
+
+// SYS_freebsd11_statfs 396
+// int statfs(const char *path, struct statfs *buf);
+PRE(sys_freebsd11_statfs)
+{
+   PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf);
+   PRE_MEM_RASCIIZ( "statfs(path)", ARG1 );
+   PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+POST(sys_freebsd11_statfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+// SYS_freebsd11_fstatfs   397
+// int fstatfs(int fd, struct statfs *buf);
+PRE(sys_freebsd11_fstatfs)
+{
+   PRINT("sys_fstatfs ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "fstatfs",
+                 unsigned int, fd, struct statfs *, buf);
+   PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+POST(sys_freebsd11_fstatfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+// SYS_freebsd11_fhstatfs  398
+// int fhstatfs(const fhandle_t *fhp, struct statfs *buf);
+PRE(sys_freebsd11_fhstatfs)
+{
+   PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "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_freebsd11_statfs) );
+}
+
+POST(sys_freebsd11_fhstatfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+
+#else
+
+PRE(sys_getfsstat)
+{
+   PRINT("sys_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "getfsstat", struct vki_freebsd11_statfs *, buf, long, bufsize, int, mode);
+   PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 );
+}
+
+POST(sys_getfsstat)
+{
+   vg_assert(SUCCESS);
+   if ((Word)RES != -1) {
+      POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_freebsd11_statfs) );
+   }
+}
+
+PRE(sys_statfs)
+{
+   PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf);
+   PRE_MEM_RASCIIZ( "statfs(path)", ARG1 );
+   PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+POST(sys_statfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+PRE(sys_fstatfs)
+{
+   PRINT("sys_fstatfs ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "fstatfs",
+                 unsigned int, fd, struct statfs *, buf);
+   PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+POST(sys_fstatfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+PRE(sys_fhstatfs)
+{
+   PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(int, "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_freebsd11_statfs) );
+}
+
+POST(sys_fhstatfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_freebsd11_statfs) );
+}
+
+
+#endif
+
+// SYS_ksem_close 400
+// @todo
+
+// SYS_ksem_post  401
+// @todo
+
+// SYS_ksem_wait  402
+// @todo
+
+// SYS_ksem_trywait  403
+// @todo
+
+// SYS_ksem_init  404
+// @todo
+
+// SYS_ksem_open  405
+// @todo
+
+// SYS_ksem_unlink   406
+// @todo
+
+// SYS_ksem_getvalue 407
+// @todo
+
+// SYS_ksem_destroy  408
+// @todo
+
+// SYS___mac_get_pid 409
+// @todo
+
+// SYS___mac_get_link   410
+// @todo
+
+// SYS___mac_set_link   411
+// @todo
+
+// SYS_extattr_set_link 412
+// ssize_t extattr_set_link(const char *path, int attrnamespace,
+//                          const char *attrname, const void *data, size_t nbytes);
+PRE(sys_extattr_set_link)
+{
+   PRINT("sys_extattr_set_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "extattr_set_link",
+                 const char *, path, int, attrnamespace, const char *, attrname, const void *, data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_set_link(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_set_link(attrname)", ARG3);
+   PRE_MEM_READ("extattr_set_link(data)", ARG4, ARG5);
+}
+
+// SYS_extattr_get_link 413
+// ssize_t extattr_get_link(const char *path, int attrnamespace,
+//                          const char *attrname, void *data, size_t nbytes);
+PRE(sys_extattr_get_link)
+{
+   PRINT("sys_extattr_get_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,SARG2,ARG3,ARG4,ARG5);
+   PRE_REG_READ5(ssize_t, "extattr_get_link",
+                 const char *, path, int, attrnamespace, const char *, attrname, void *, data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_get_link(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_get_link(attrname)", ARG3);
+   if (ARG4) {
+      PRE_MEM_WRITE("extattr_get_link(data)", ARG4, ARG5);
+   }
+}
+
+POST(sys_extattr_get_link)
+{
+   if (ARG4) {
+      POST_MEM_WRITE(ARG4, ARG5);
+   }
+}
+
+// SYS_extattr_delete_link 414
+// int extattr_delete_link(const char *path, int attrnamespace,
+//                         const char *attrname);
+PRE(sys_extattr_delete_link)
+{
+   PRINT("sys_extattr_delete_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1,SARG2,ARG3);
+   PRE_REG_READ3(ssize_t, "extattr_delete_link",
+                 const char *, path, int, attrnamespace, const char *, attrname);
+   PRE_MEM_RASCIIZ("extattr_delete_link(path)", ARG1);
+   PRE_MEM_RASCIIZ("extattr_delete_link(attrname)", ARG3);
+}
+
+// SYS___mac_execve  415
+// @todo
+
+// SYS_sigaction  416
+//int sigaction(int sig, const struct sigaction * restrict act,
+//              struct sigaction * restrict oact);
+PRE(sys_sigaction)
+{
+   vki_sigaction_toK_t   new, *newp;
+   vki_sigaction_fromK_t old, *oldp;
+
+   PRINT("sys_sigaction ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "sigaction",
+                 int, sign, const struct sigaction *, act,
+                 struct sigaction *, oact);
+
+   newp = oldp = NULL;
+
+   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 (ARG3 != 0) {
+      PRE_MEM_WRITE( "sigaction(oact)", ARG3, sizeof(struct vki_sigaction));
+      oldp = &old;
+   }
+
+   if (ARG2 != 0
+         && ! ML_(safe_to_deref)((void *)(Addr)ARG2,
+                                 sizeof(struct vki_sigaction))) {
+      VG_(umsg)("Warning: bad act handler address %p in sigaction()\n",
+                (void *)(Addr)ARG2);
+      SET_STATUS_Failure ( VKI_EFAULT );
+   } else if ((ARG3 != 0
+               && ! ML_(safe_to_deref)((void *)(Addr)ARG3,
+                                       sizeof(struct vki_sigaction)))) {
+      VG_(umsg)("Warning: bad oact handler address %p in sigaction()\n",
+                (void *)(Addr)ARG3);
+      SET_STATUS_Failure ( VKI_EFAULT );
+   } else {
+      if (ARG2 != 0) {
+         struct vki_sigaction *oldnew =
+            (struct vki_sigaction *)(Addr)ARG2;
+
+         new.ksa_handler = oldnew->ksa_handler;
+         new.sa_flags = oldnew->sa_flags;
+         new.sa_mask = oldnew->sa_mask;
+         newp = &new;
+      }
+
+      SET_STATUS_from_SysRes( VG_(do_sys_sigaction)(ARG1, newp, oldp) );
+
+      if (ARG3 != 0 && SUCCESS && RES == 0) {
+         struct vki_sigaction *oldold =
+            (struct vki_sigaction *)(Addr)ARG3;
+
+         oldold->ksa_handler = oldp->ksa_handler;
+         oldold->sa_flags = oldp->sa_flags;
+         oldold->sa_mask = oldp->sa_mask;
+      }
+   }
+}
+
+POST(sys_sigaction)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0 && ARG3 != 0)
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction));
+}
+
+// SYS_sigreturn  417
+// x86/amd64
+
+// SYS_getcontext 421
+// SYS_setcontext 422
+// SYS_swapcontext   423
+// PRE in x86/amd64
+
+POST(sys_getcontext)
+{
+   POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) );
+}
+
+POST(sys_swapcontext)
+{
+   if (SUCCESS)
+      POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) );
+}
+
+// SYS_swapoff 424
+// int swapoff(const char *special);
+PRE(sys_swapoff)
+{
+   PRINT("sys_swapoff ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1);
+   PRE_REG_READ1(int, "swapoff", const char *, special);
+   PRE_MEM_RASCIIZ( "swapoff(special)", ARG1 );
+}
+
+// SYS___acl_get_link   425
+// int __acl_get_link(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_get_link)
+{
+   PRINT("sys___acl_get_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "__acl_get_link",
+                 const char *, path, int, acltype, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ( "__acl_get_link(path)", ARG1 );
+   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) );
+   }
+}
+
+// SYS___acl_set_link   426
+// int __acl_set_link(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_set_link)
+{
+   PRINT("sys___acl_set_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "__acl_set_link",
+                 const char *, path, int, acltype, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ( "__acl_set_link(path)", ARG1 );
+   PRE_MEM_READ( "__acl_set_link(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+// SYS___acl_delete_link   427
+// int __acl_delete_link(const char *path, acl_type_t type);
+PRE(sys___acl_delete_link)
+{
+   PRINT("sys___acl_delete_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,(char *)ARG1,ARG2);
+   PRE_MEM_RASCIIZ( "__acl_delete_link(path)", ARG1 );
+   PRE_REG_READ2(int, "__acl_delete_link",
+                 const char *, path, int, acltype);
+}
+
+// SYS___acl_aclcheck_link 428
+// int __acl_aclcheck_link(const char *path, acl_type_t type, struct acl *aclp);
+PRE(sys___acl_aclcheck_link)
+{
+   PRINT("sys___acl_aclcheck_link ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,(char *)ARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "__acl_aclcheck_link",
+                 const char *, path, int, acltype, struct vki_acl *, aclp);
+   PRE_MEM_RASCIIZ( "__acl_check_link(path)", ARG1 );
+   PRE_MEM_READ( "__acl_aclcheck_link(aclp)", ARG3, sizeof(struct vki_acl) );
+}
+
+// SYS_sigwait 429
+// int sigwait(const sigset_t * restrict set, int * restrict sig);
+PRE(sys_sigwait)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sigwait ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         ARG1,ARG2);
+   PRE_REG_READ2(int, "sigwait",
+                 const vki_sigset_t *, set, int *, sig);
+   if (ARG1 != 0)
+      PRE_MEM_READ(  "sigwait(set)",  ARG1, sizeof(vki_sigset_t));
+   if (ARG2 != 0)
+      PRE_MEM_WRITE( "sigwait(sig)", ARG2, sizeof(int));
+}
+
+POST(sys_sigwait)
+{
+   if (ARG2 != 0)
+      POST_MEM_WRITE( ARG2, sizeof(int));
+}
+
+// SYS_thr_create 430
+// no manpage?
+// syscalls.master: int thr_create(_In_ ucontext_t *ctx, _Out_ long *id, int flags );
+PRE(sys_thr_create)
+{
+   PRINT( "sys_thr_create ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", ARG1, ARG2, SARG3 );
+   PRE_REG_READ3(int, "thr_create", /*ucontext_t*/void *, ctx, long *, id, int, flags );
+
+   VG_(message)(Vg_UserMsg, "thr_create() not implemented");
+   VG_(unimplemented)("Valgrind does not support thr_create().");
+
+   SET_STATUS_Failure(VKI_ENOSYS);
+}
+
+// SYS_thr_exit   431
+// void thr_exit(long *state);
+PRE(sys_thr_exit)
+{
+   ThreadState *tst;
+
+   PRINT( "sys_thr_exit ( %#" FMT_REGWORD "x )", ARG1 );
+   PRE_REG_READ1(void, "thr_exit", long *, state);
+
+   if (ARG1) {
+      PRE_MEM_WRITE( "thr_exit(state)", ARG1, sizeof(long) );
+   }
+
+   tst = VG_(get_ThreadState)(tid);
+   tst->exitreason = VgSrc_ExitThread;
+   tst->os_state.exitcode = ARG1;
+   SET_STATUS_Success(0);
+}
+
+// SYS_thr_self   432
+// int thr_self(long *id);
+PRE(sys_thr_self)
+{
+   PRINT( "sys_thr_self ( %#" FMT_REGWORD "x )", ARG1 );
+   PRE_REG_READ1(int, "thr_self", long *, id);
+   PRE_MEM_WRITE( "thr_self()", ARG1, sizeof(long));
+}
+
+POST(sys_thr_self)
+{
+   POST_MEM_WRITE( ARG1, sizeof(long));
+}
+
+// SYS_thr_kill   433
+// int thr_kill(long id, int sig);
+PRE(sys_thr_kill)
+{
+   PRINT("sys_thr_kill ( %" FMT_REGWORD "u, %" FMT_REGWORD "u )", 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 %lu to tid %lu\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 %lu to tid %lu\n",
+                   ARG2, ARG1);
+}
+
+#if (FREEBSD_VERS <= FREEBSD_10)
+// SYS__umtx_lock 434
+PRE(sys__umtx_lock)
+{
+   PRINT( "sys__umtx_lock ( %#" FMT_REGWORD "x )", 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));
+}
+
+// SYS__umtx_unlock 434
+PRE(sys__umtx_unlock)
+{
+   PRINT( "sys__umtx_unlock ( %#" FMT_REGWORD "x )", 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));
+}
+#endif
+
+// SYS_jail_attach   436
+// int jail_attach(int jid);
+PRE(sys_jail_attach)
+{
+   PRINT("sys_jail_attach ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "jail_attach", int, jid);
+}
+
+// SYS_extattr_list_fd  437
+// ssize_t extattr_list_fd(int fd, int attrnamespace, void *data, size_t nbytes);
+PRE(sys_extattr_list_fd)
+{
+   PRINT("extattr_list_fd ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(ssize_t, "extattr_list_fd", int, id, int, attrnamespace, void *,data, size_t, nbytes);
+   PRE_MEM_WRITE("extattr_list_fd(data)", ARG3, ARG4);
+}
+
+POST(sys_extattr_list_fd)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_extattr_list_file   438
+// ssize_t extattr_list_file(const char *path, int attrnamespace, void *data,
+//                           size_t nbytes);
+PRE(sys_extattr_list_file)
+{
+   PRINT("extattr_list_file ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(ssize_t, "extattr_list_file", const char *, path, int, attrnamespace, void *,data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_list_file(path)", ARG1);
+   PRE_MEM_WRITE("extattr_list_file(data)", ARG3, ARG4);
+}
+
+POST(sys_extattr_list_file)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_extattr_list_link   439
+// ssize_t extattr_get_link(const char *path, int attrnamespace,
+//                          const char *attrname, void *data, size_t nbytes);
+PRE(sys_extattr_list_link)
+{
+   PRINT("extattr_list_link ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(ssize_t, "extattr_list_link", const char *, path, int, attrnamespace, void *,data, size_t, nbytes);
+   PRE_MEM_RASCIIZ("extattr_list_link(path)", ARG1);
+   PRE_MEM_WRITE("extattr_list_link(data)", ARG3, ARG4);
+}
+
+POST(sys_extattr_list_link)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_ksem_timedwait   441
+// @todo
+
+// SYS_thr_suspend   442
+// int thr_suspend(struct timespec *timeout);
+PRE(sys_thr_suspend)
+{
+   PRINT("sys_thr_suspend ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "thr_suspend", struct timespec *, timeout);
+   PRE_MEM_READ("thr_suspend(timeout)", ARG1, sizeof(struct vki_timespec));
+
+   VG_(message)(Vg_UserMsg, "thr_supend() not implemented");
+   VG_(unimplemented)("Valgrind does not support thr_suspend().");
+
+   SET_STATUS_Failure(VKI_ENOSYS);
+}
+
+// SYS_thr_wake   443
+// int thr_wake(long id);
+PRE(sys_thr_wake)
+{
+   PRINT("sys_thr_wake ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(long, "thr_wake", long, id);
+   /*
+      if (VG_(is_valid_tid)(ARG1)) {
+         VG_(threads)[ARG1].status = VgTs_Runnable;
+      } else {
+         SET_STATUS_Failure( VKI_ESRCH );
+      }
+   */
+}
+
+// SYS_kldunloadf 444
+// int kldunloadf(int fileid, int flags);
+PRE(sys_kldunloadf)
+{
+   PRINT("sys_kldunloadf ( %" FMT_REGWORD "d, %" FMT_REGWORD "d )", SARG1, SARG2);
+   PRE_REG_READ2(int, "kldunloadf", int, fileid, int, flags);
+}
+
+// SYS_audit   445
+// int audit(const char *record, u_int length);
+// @todo
+
+// SYS_auditon 446
+// int auditon(int cmd, void *data, u_int length);
+// @todo
+
+// SYS_getauid 447
+// int getauid(au_id_t *auid);
+// @todo
+
+// SYS_setauid 448
+// int setauid(au_id_t *auid);
+// @todo
+
+// SYS_getaudit   449
+//  int getaudit(auditinfo_t *auditinfo);
+// @todo
+
+// SYS_setaudit   450
+// int setaudit(auditinfo_t *auditinfo);
+// @todo
+
+// SYS_getaudit_addr 451
+// int getaudit_addr(auditinfo_addr_t *auditinfo_addr, u_int length);
+// @todo
+
+// SYS_setaudit_addr 452
+// int setaudit_addr(auditinfo_addr_t *auditinfo_addr, u_int length);
+// @todo
+
+// SYS_auditctl   453
+// @todo
+
+// SYS__umtx_op   454
+// int _umtx_op(void *obj, int op, u_long val, void *uaddr, void *uaddr2);
+PRE(sys__umtx_op)
+{
+   /* 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 ( %#" FMT_REGWORD "x, LOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_lock",
+                    struct umtx *, obj, int, op, unsigned long, id,
+                    size_t, timeout_size, 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, ARG4 );
+      PRE_MEM_WRITE( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) );
+      *flags |= SfMayBlock;
+      break;
+   case VKI_UMTX_OP_UNLOCK:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, UNLOCK, %" FMT_REGWORD "u)", 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 ( %#" FMT_REGWORD "x, WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_wait",
+                    long *, obj, int, op, unsigned long, val,
+                    size_t, timeout_size, struct vki_timespec *, timeout);
+      if (ARG1) {
+         PRE_MEM_READ( "_umtx_op_wait(val)", ARG1, sizeof(long) );
+         if (*(long*)ARG1 == (long)ARG3) {
+            *flags |= SfMayBlock;
+         }
+      }
+
+      if (ARG5) {
+         PRE_MEM_READ( "_umtx_op_wait(timeout)", ARG5, ARG4 );
+      }
+
+      break;
+   case VKI_UMTX_OP_WAKE:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, WAKE, %" FMT_REGWORD "u)", ARG1, ARG3);
+      PRE_REG_READ3(long, "_umtx_op_wake",
+                    struct umtx *, obj, int, op, unsigned long, val);
+      PRE_MEM_READ( "_umtx_op_wake(mtx)", ARG1, sizeof(struct vki_umtx) );
+      break;
+   case VKI_UMTX_OP_MUTEX_TRYLOCK:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_TRYLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_mutex_trylock",
+                    struct umutex *, obj, int, op, unsigned long, noid,
+                    size_t, timeout_size, 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, ARG4 );
+      PRE_MEM_WRITE( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) );
+      break;
+   case VKI_UMTX_OP_MUTEX_LOCK:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, MUTEX_LOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_mutex_lock",
+                    struct umutex *, obj, int, op, unsigned long, noid,
+                    size_t, timeout_size, 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, ARG4 );
+      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 ( %#" FMT_REGWORD "x, 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 ( %#" FMT_REGWORD "x, SET_CEILING, %" FMT_REGWORD "u, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, CV_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, 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 ( %#" FMT_REGWORD "x, CV_BROADCAST, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, CV_WAIT_UINT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_wait_uint",
+                    int *, obj, int, op, unsigned long, id,
+                    size_t, timeout_wait, struct vki_timespec *, timeout);
+      PRE_MEM_READ( "_umtx_op_wait(uint)", ARG1, sizeof(int) );
+      if (ARG5)
+         PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, ARG4 );
+      *flags |= SfMayBlock;
+      break;
+   case VKI_UMTX_OP_RW_RDLOCK:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, RW_RDLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, RW_WRLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, RW_UNLOCK, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, CV_WAIT_UINT_PRIVATE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_wait_uint_private",
+                    int *, obj, int, op, unsigned long, id,
+                    size_t, timeout_size, 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, ARG4 );
+      *flags |= SfMayBlock;
+      break;
+   case VKI_UMTX_OP_WAKE_PRIVATE:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, CV_WAKE_PRIVATE, %" FMT_REGWORD "u)", 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 ( %#" FMT_REGWORD "x, MUTEX_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, MUTEX_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, SEM_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ5(long, "_umtx_op_sem_wait",
+                    struct usem *, obj, int, op, unsigned long, id,
+                    size_t, timeout_size, 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, ARG4 );
+      *flags |= SfMayBlock;
+      break;
+   case VKI_UMTX_OP_SEM_WAKE:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, NWAKE_PRIVATE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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 ( %#" FMT_REGWORD "x, MUTEX_WAKE2, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", 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;
+   case VKI_UMTX_OP_SEM2_WAIT:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM2_WAIT, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ3(long, "_umtx_op_sem2_wake",
+                    struct _usem2 *, obj, int, op, unsigned long, flags);
+      PRE_MEM_READ( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) );
+      PRE_MEM_WRITE( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) );
+      *flags |= SfMayBlock;
+      break;
+   case VKI_UMTX_OP_SEM2_WAKE:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SEM2_WAKE, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ3(long, "_umtx_op_sem2_wake",
+                    struct _usem2 *, obj, int, op, unsigned long, flags);
+      PRE_MEM_READ( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) );
+      PRE_MEM_WRITE( "_umtx_op_sem2_wait(mutex)", ARG1, sizeof(struct vki_usem2) );
+      break;
+   case VKI_UMTX_OP_SHM:
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, SHM, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ4(long, "_umtx_op_shm",
+                    void *, obj, int, op, unsigned long, val, void*, uaddr);
+      break;
+   case VKI_UMTX_OP_ROBUST_LISTS:
+      // val (ARG2) ought to be the same as sizeof(struct vki_umtx_robust_lists_params)
+      // then the structure contains a pointer to mutex structures
+      if (ARG1 != sizeof(struct vki_umtx_robust_lists_params))
+         SET_STATUS_Failure( VKI_ENOSYS );
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, ROBUST_LISTS, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x)", ARG1, ARG3, ARG4, ARG5);
+      PRE_REG_READ3(long, "_umtx_op_robust_lists",
+                    struct umtx_robust_lists_params *, obj, int, op, unsigned long, flags);
+      PRE_MEM_READ( "_umtx_op_robust_lists(mutex)", ARG3, sizeof(struct vki_umtx_robust_lists_params) );
+      break;
+   default:
+      VG_(umsg)("WARNING: _umtx_op unsupported value.\n");
+      PRINT( "sys__umtx_op ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u(UNKNOWN), %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3, ARG4, ARG5);
+      break;
+   }
+}
+
+POST(sys__umtx_op)
+{
+   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;
+   case VKI_UMTX_OP_SEM2_WAIT:
+   case VKI_UMTX_OP_SEM2_WAKE:
+      if (SUCCESS) {
+         POST_MEM_WRITE( ARG1, sizeof(struct vki_usem2) );
+      }
+      break;
+   case VKI_UMTX_OP_SHM:
+   case VKI_UMTX_OP_ROBUST_LISTS:
+   default:
+      break;
+   }
+}
+
+// SYS_thr_new 455
+// x86/amd64
+
+// SYS_sigqueue   456
+// int sigqueue(pid_t pid, int signo, const union sigval value);
+PRE(sys_sigqueue)
+{
+   PRINT("sys_sigqueue ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",
+         SARG1,SARG2,ARG3);
+   PRE_REG_READ3(int, "sigqueue", vki_pid_t, pid, int, signo, const union vki_sigval, value);
+}
+
+// SYS_kmq_open   457
+// mqd_t mq_open(const char *name, int oflag, ...);
+// int kmq_open(_In_z_ const char *path, int flags, mode_t mode, _In_opt_ const struct mq_attr *attr);
+PRE(sys_kmq_open)
+{
+   if (ARG2 & VKI_O_CREAT) {
+      PRINT("sys_kmq_open( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu, %#" FMT_REGWORD "x )",
+            ARG1,(char *)ARG1,ARG2,(vki_mode_t)ARG3,ARG4);
+      PRE_REG_READ4(long, "mq_open",
+                    const char *, name, int, oflag, vki_mode_t, mode,
+                    struct mq_attr *, attr);
+   } else {
+      PRINT("sys_kmq_open( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu)",
+            ARG1,(char *)ARG1,ARG2,(vki_mode_t)ARG3);
+      PRE_REG_READ3(long, "mq_open",
+                    const char *, name, int, oflag, vki_mode_t, mode);
+   }
+   PRE_MEM_RASCIIZ( "mq_open(name)", ARG1 );
+   if (ARG2 & VKI_O_CREAT) {
+      PRE_MEM_READ("mq_open(attr)", ARG4, sizeof(struct vki_mq_attr));
+      if (ML_(safe_to_deref)((struct vki_mq_attr *)ARG4, sizeof(struct vki_mq_attr))) {
+         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_kmq_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, (const HChar*)ARG1);
+   }
+}
+
+// SYS_kmq_setattr   458
+// int mq_setattr(mqd_t mqdes, const struct mq_attr *restrict mqstat,
+//                struct mq_attr *restrict omqstat);
+PRE(sys_kmq_setattr)
+{
+   PRINT("sys_kmq_getattr( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1,ARG2,ARG3 );
+   PRE_REG_READ3(int, "mq_setattr",
+                 vki_mqd_t, mqdes, const struct mq_attr *, mqstat,
+                 struct mq_attr *, omqstat);
+   if (!ML_(fd_allowed)(ARG1, "mq_getattr", tid, False)) {
+      SET_STATUS_Failure( VKI_EBADF );
+   } else {
+      if (ML_(safe_to_deref)((struct vki_mq_attr *)ARG2, sizeof(struct vki_mq_attr))) {
+         const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG2;
+         PRE_MEM_READ( "mq_setattr(mqstat->mq_flags)",
+                       (Addr)&attr->mq_flags, sizeof(attr->mq_flags) );
+      }
+      PRE_MEM_WRITE( "mq_setattr(omqstat)", ARG3,
+                     sizeof(struct vki_mq_attr) );
+   }
+}
+
+// SYS_kmq_timedreceive 459
+// ssize_t mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
+//                         unsigned *msg_prio, const struct timespec *abs_timeout);
+PRE(sys_kmq_timedreceive)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_kmq_timedreceive( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %llu, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         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_kmq_timedreceive)
+{
+   POST_MEM_WRITE( ARG2, ARG3 );
+   if (ARG4 != 0)
+      POST_MEM_WRITE( ARG4, sizeof(unsigned int) );
+}
+
+// SYS_kmq_timedsend 460
+// int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
+//                  unsigned msg_prio, const struct timespec *abs_timeout);
+PRE(sys_kmq_timedsend)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_kmq_timedsend ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
+         ARG1,ARG2,(ULong)ARG3,ARG4,ARG5);
+   PRE_REG_READ5(int, "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) );
+   }
+}
+
+// SYS_kmq_notify 461
+// int mq_notify(mqd_t mqdes, const struct sigevent *notification);
+PRE(sys_kmq_notify)
+{
+   PRINT("sys_kmq_notify( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1,ARG2 );
+   PRE_REG_READ2(int, "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) );
+}
+
+// SYS_kmq_unlink 462
+// int kmq_unlink(const char *path);
+PRE(sys_kmq_unlink)
+{
+   PRINT("sys_kmq_unlink ( %#" FMT_REGWORD "x(%s) )", ARG1,(char *)ARG1);
+   PRE_REG_READ1(int, "mq_unlink", const char *, name);
+   PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 );
+}
+
+// SYS_abort2  463
+// void abort2(const char *why, int nargs, void **args);
+PRE(sys_abort2)
+{
+   PRINT( "sys_abort2 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", ARG1, SARG2, ARG3 );
+   PRE_REG_READ3(void, "abort2", const char *, why, int, nargs, void **, args);
+   // max length of 'why' is 128
+   PRE_MEM_RASCIIZ( "abort2(why)", ARG2);
+   // max val for nargs is 16
+   PRE_MEM_READ("abort2(args", ARG3, ARG2*sizeof(void*));
+}
+
+// SYS_thr_set_name  464
+// int thr_set_name(long id, const char *name);
+PRE(sys_thr_set_name)
+{
+   PRINT( "sys_thr_set_name ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2 );
+   PRE_REG_READ2(int, "thr_set_name", long, id, const char *, name);
+   PRE_MEM_RASCIIZ( "thr_set_name(name)", ARG2);
+
+   if (ML_(safe_to_deref)((void*)ARG2, 1)) {
+      const HChar* new_name = (const HChar*) (Addr)ARG2;
+      ThreadState* tst = VG_(get_ThreadState)(tid);
+      SizeT new_len = VG_(strnlen)(new_name, VKI_MAXCOMLEN+1);
+      tst->thread_name = VG_(realloc)("syswrap.thr_set_name", tst->thread_name, new_len + 1);
+      VG_(strlcpy)(tst->thread_name, new_name, new_len + 1);
+   }
+}
+
+// SYS_aio_fsync  465
+// int aio_fsync(int op, struct aiocb *iocb);
+PRE(sys_aio_fsync)
+{
+   PRINT("aio_fsync ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,ARG2);
+   PRE_REG_READ2(int, "aio_fsync", int, op, struct vki_aiocb *, iocb);
+   PRE_MEM_READ( "aio_fsync(iocb)", ARG2, sizeof(struct vki_aiocb) );
+}
+
+// SYS_rtprio_thread 466
+// int rtprio_thread(int function, lwpid_t lwpid, struct rtprio *rtp);
+PRE(sys_rtprio_thread)
+{
+   PRINT( "sys_rtprio_thread ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", ARG1, ARG2, ARG3 );
+   PRE_REG_READ3(int, "rtprio_thread",
+                 int, function, __vki_lwpid_t, lwpid, struct vki_rtprio *, rtp);
+   if (ARG1 == VKI_RTP_SET) {
+      PRE_MEM_READ( "rtprio_thread(rtp#set)", ARG3, sizeof(struct vki_rtprio));
+   } else if (ARG1 == VKI_RTP_LOOKUP) {
+      PRE_MEM_WRITE( "rtprio_thread(rtp#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));
+}
+
+// SYS_sctp_peeloff  471
+// int sctp_peeloff(int s, sctp_assoc_t id);
+// @todo
+
+// SYS_sctp_generic_sendmsg   472
+// int sctp_generic_sendmsg(int s, void *msg, int msglen, struct sockaddr *to,
+//                          socklen_t len, struct sctp_sndrcvinfo *sinfo, int flags);
+// @tdo
+
+
+// SYS_sctp_generic_sendmsg_iov  473
+// int sctp_generic_sendmsg_iov(int s, struct iovec *iov, int iovlen,
+//                              struct sockaddr *to, struct sctp_sndrcvinfo *sinfo, int flags);
+// @todo
+
+// SYS_sctp_generic_recvmsg   474
+// int sctp_generic_recvmsg(int s, struct iovec *iov, int iovlen,
+//                          struct sockaddr *from, socklen_t *fromlen,
+//                          struct sctp_sndrcvinfo *sinfo, int *msgflags);
+// @todo
+
+// SYS_pread   475
+// x86/amd64
+
+// SYS_pwrite  476
+// x86/amd64
+
+// SYS_mmap 477
+// x86/amd64
+
+// SYS_lseek   478
+// x86/amd64
+
+//SYS_truncate 479
+// x86/amd64
+
+// SYS_ftruncate  480
+// x86/amd64
+
+// SYS_thr_kill2  481
+// int thr_kill2(pid_t pid, long id, int sig);
+PRE(sys_thr_kill2)
+{
+   PRINT("sys_thr_kill2 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "thr_kill2", pid_t, 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 %lu to pid %lu/%lu\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 %lu to pid %lu/%lu\n",
+                   ARG3, ARG1, ARG2);
+}
+
+// SYS_shm_open   482
+// int shm_open(const char *path, int flags, mode_t mode);
+PRE(sys_shm_open)
+{
+   PRE_REG_READ3(int, "shm_open",
+                 const char *, path, int, flags, vki_mode_t, mode);
+   if (ARG1 == VKI_SHM_ANON) {
+      PRINT("sys_shm_open(%#" FMT_REGWORD "x(SHM_ANON), %" FMT_REGWORD "u, %hu)", ARG1, ARG2, (vki_mode_t)ARG3);
+   } else {
+      PRINT("sys_shm_open(%#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %hu)", ARG1, (HChar *)ARG1, ARG2, (vki_mode_t)ARG3);
+      PRE_MEM_RASCIIZ( "shm_open(path)", 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);
+   }
+}
+
+// SYS_shm_unlink 483
+// int shm_unlink(const char *path);
+PRE(sys_shm_unlink)
+{
+   PRINT("sys_shm_unlink(%#" FMT_REGWORD "x(%s))", ARG1, (char *)ARG1);
+   PRE_REG_READ1(int, "shm_unlink",
+                 const char *, path);
+
+   PRE_MEM_RASCIIZ( "shm_unlink(path)", ARG1 );
+
+   *flags |= SfMayBlock;
+}
+
+// SYS_cpuset  484
+// int cpuset(cpusetid_t *setid);
+PRE(sys_cpuset)
+{
+   PRINT("sys_cpuset ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "cpuset", vki_cpusetid_t *, setid);
+   PRE_MEM_WRITE("cpuset(setid)", ARG1, sizeof(vki_cpusetid_t));
+}
+
+POST(sys_cpuset)
+{
+   POST_MEM_WRITE(ARG1, sizeof(vki_cpusetid_t));
+}
+
+// SYS_cpuset_setid  485
+// amd64 / x86
+
+// SYS_cpuset_getid  486
+// amd64 / x86
+
+// SYS_cpuset_getaffinity  487
+// amd64 / x86
+
+// SYS_cpuset_setaffinity  488
+// amd64 / x86
+
+// SYS_faccessat  489
+// int faccessat(int fd, const char *path, int mode, int flag);
+PRE(sys_faccessat)
+{
+   PRINT("sys_faccessat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ3(int, "faccessat",
+                 int, fd, const char *, path, int, flag);
+   PRE_MEM_RASCIIZ( "faccessat(path)", ARG2 );
+}
+
+// SYS_fchmodat   490
+// int fchmodat(int fd, const char *path, mode_t mode, int flag);
+PRE(sys_fchmodat)
+{
+   PRINT("sys_fchmodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ4(int, "fchmodat",
+                 int, fd, const char *, path, vki_mode_t, mode, int, flag);
+   PRE_MEM_RASCIIZ( "fchmodat(path)", ARG2 );
+}
+
+// SYS_fchownat   491
+// int fchownat(int fd, const char *path, uid_t owner, gid_t group, int flag);
+PRE(sys_fchownat)
+{
+   PRINT("sys_fchownat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         ARG1,ARG2,(char*)ARG2,ARG3,ARG4, SARG5);
+   PRE_REG_READ5(int, "fchownat",
+                 int, fd, const char *, path,
+                 vki_uid_t, owner, vki_gid_t, group, int, flag);
+   PRE_MEM_RASCIIZ( "fchownat(path)", ARG2 );
+}
+
+// SYS_fexecve 492
+// int fexecve(int fd, char *const argv[], char *const envp[]);
+PRE(sys_fexecve)
+{
+   PRINT("sys_fexecve ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1,ARG2,ARG3);
+   PRE_REG_READ3(long, "fexecve",
+                 int, fd, char * const *, argv,
+                 char * const *, envp);
+   PRE_MEM_RASCIIZ( "fexecve(argv)", ARG2 );
+   PRE_MEM_RASCIIZ( "fexecve(envp)", ARG3 );
+}
+
+// SYS_freebsd11_fstatat   493
+// int fstatat(int fd, const char *path, struct stat *sb, int flag);
+#if (FREEBSD_VERS >= FREEBSD_12)
+PRE(sys_freebsd11_fstatat)
+{
+   PRINT("sys_freebsd11_fstatat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ4(int, "fstatat",
+                 int, fd, const char *, path, struct freebsd11_stat *, buf, int, flag);
+   PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 );
+   PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_freebsd11_fstatat)
+{
+   POST_MEM_WRITE( ARG3, sizeof(struct vki_freebsd11_stat) );
+}
+#else
+PRE(sys_fstatat)
+{
+   PRINT("sys_fstatat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ4(int, "fstatat",
+                 int, fd, const char *, path, struct stat *, buf, int, flag);
+   PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 );
+   PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_freebsd11_stat) );
+}
+
+POST(sys_fstatat)
+{
+   POST_MEM_WRITE( ARG3, sizeof(struct vki_freebsd11_stat) );
+}
+#endif
+
+// SYS_futimesat  494
+// int futimesat(int fd, const char *path, const struct timeval times[2]);
+PRE(sys_futimesat)
+{
+   PRINT("sys_futimesat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ3(int, "futimesat",
+                 int, fd, const char *, path, struct timeval *, times);
+   if (ARG2 != 0)
+      PRE_MEM_RASCIIZ( "futimesat(path)", ARG2 );
+   if (ARG3 != 0)
+      PRE_MEM_READ( "futimesat(times)", ARG3, 2 * sizeof(struct vki_timeval) );
+}
+
+// SYS_linkat  495
+// int linkat(int fd1, const char *name1, int fd2, const char *name2, int flag);
+PRE(sys_linkat)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_linkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4,ARG5);
+   PRE_REG_READ5(int, "linkat",
+                 int, fd1, const char *, name1,
+                 int, fd2, const char *, name2,
+                 int, flag);
+   PRE_MEM_RASCIIZ( "linkat(name1)", ARG2);
+   PRE_MEM_RASCIIZ( "linkat(name2)", ARG4);
+}
+
+// SYS_mkdirat 496
+// int mkdirat(int fd, const char *path, mode_t mode);
+PRE(sys_mkdirat)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_mkdirat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )", ARG1,ARG2,(char*)ARG2,ARG3);
+   PRE_REG_READ3(int, "mkdirat",
+                 int, fd, const char *, path, int, mode);
+   PRE_MEM_RASCIIZ( "mkdirat(path)", ARG2 );
+}
+
+// SYS_mkfifoat   497
+// int mkfifoat(int fd, const char *path, mode_t mode);
+PRE(sys_mkfifoat)
+{
+   PRINT("sys_mkfifoat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x )",
+         SARG1,ARG2,(HChar*)ARG2,ARG3 );
+   PRE_REG_READ3(int, "mkfifoat",
+                 int, fd, const char *, path, vki_mode_t, mode);
+   PRE_MEM_RASCIIZ( "mkfifoat(path)", ARG2 );
+}
+
+// SYS_freebsd11_mknodat   498
+// int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
+#if (FREEBSD_VERS >= FREEBSD_12)
+PRE(sys_freebsd11_mknodat)
+{
+   PRINT("sys_freebsd11_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", 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 );
+}
+#else
+PRE(sys_mknodat)
+{
+   PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", 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 );
+}
+#endif
+
+// SYS_openat  499
+// int openat(int fd, const char *path, int flags, ...);
+PRE(sys_openat)
+{
+
+   if (ARG3 & VKI_O_CREAT) {
+      // 4-arg version
+      PRINT("sys_openat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "openat",
+                    int, fd, const char *, path, int, flags, vki_mode_t, mode);
+   } else {
+      // 3-arg version
+      PRINT("sys_openat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u )",ARG1,ARG2,(char*)ARG2,ARG3);
+      PRE_REG_READ3(int, "openat",
+                    int, fd, const char *, path, 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(path)", 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);
+   }
+}
+
+// SYS_readlinkat 500
+// ssize_t readlinkat(int fd, const char *restrict path, char *restrict buf,
+//                    size_t bufsize);
+PRE(sys_readlinkat)
+{
+   HChar name[25];
+   Word  saved = SYSNO;
+
+   PRINT("sys_readlinkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %llu )", ARG1,ARG2,(char*)ARG2,ARG3,(ULong)ARG4);
+   PRE_REG_READ4(ssize_t, "readlinkat",
+                 int, fd, const char *, path, char *, buf, int, bufsize);
+   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/<pid>/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));
+   }
+}
+
+POST(sys_readlinkat)
+{
+   POST_MEM_WRITE( ARG3, RES );
+}
+
+// SYS_renameat   501
+// int renameat(int fromfd, const char *from, int tofd, const char *to);
+PRE(sys_renameat)
+{
+   PRINT("sys_renameat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4);
+   PRE_REG_READ4(int, "renameat",
+                 int, fromfd, const char *, from,
+                 int, tofd, const char *, to);
+   PRE_MEM_RASCIIZ( "renameat(oldpath)", ARG2 );
+   PRE_MEM_RASCIIZ( "renameat(newpath)", ARG4 );
+}
+
+// SYS_symlinkat  502
+// int symlinkat(const char *name1, int fd, const char *name2);
+PRE(sys_symlinkat)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_symlinkat ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )",ARG1,(char*)ARG1,ARG2,ARG3,(char*)ARG3);
+   PRE_REG_READ3(int, "symlinkat",
+                 const char *, name1, int, fd, const char *, name2);
+   PRE_MEM_RASCIIZ( "symlinkat(name1)", ARG1 );
+   PRE_MEM_RASCIIZ( "symlinkat(name2)", ARG3 );
+}
+
+// SYS_unlinkat   503
+// int unlinkat(int fd, const char *path, int flag);
+PRE(sys_unlinkat)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_unlinkat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s) )", ARG1,ARG2,(char*)ARG2);
+   PRE_REG_READ3(int, "unlinkat", int, fd, const char *, path, int, flag);
+   PRE_MEM_RASCIIZ( "unlinkat(path)", ARG2 );
+}
+
+// SYS_posix_openpt  504
+// int posix_openpt(int oflag);
+PRE(sys_posix_openpt)
+{
+   PRINT("sys_posix_openpt ( %" FMT_REGWORD "d )", SARG2);
+   PRE_REG_READ1(int, "posix_openpt", int, oflag);
+
+}
+
+// SYS_gssd_syscall  505
+// @todo
+// see https://www.freebsd.org/cgi/man.cgi?format=html&query=gssapi(3)
+// syscalls.master says ; 505 is initialised by the kgssapi code, if present.
+
+// SYS_jail_get   506
+// int jail_get(struct iovec *iov, u_int niov, int flags);
+PRE(sys_jail_get)
+{
+   PRINT("sys_jail_get ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "jail_get", struct vki_iovec *, iov, unsigned int,
+                 niov, int, flags);
+   PRE_MEM_READ("jail_get(iov)", ARG1, ARG2 * sizeof(struct vki_iovec));
+}
+
+// SYS_jail_set   507
+// int jail_set(struct iovec *iov, u_int niov, int flags);
+PRE(sys_jail_set)
+{
+   PRINT("sys_jail_set ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "jail_set", struct vki_iovec *, iov, unsigned int,
+                 niov, int, flags);
+   PRE_MEM_READ("jail_set(iovs)", ARG1, ARG2 * sizeof(struct vki_iovec));
+}
+
+// SYS_jail_remove   508
+// int jail_remove(int jid);
+PRE(sys_jail_remove)
+{
+   PRINT("sys_jail_remove ( %" FMT_REGWORD "d )", SARG1);
+   PRE_REG_READ1(int, "jail_remove", int, jid);
+}
+
+// SYS_closefrom  509
+// void closefrom(int lowfd);
+PRE(sys_closefrom)
+{
+   PRINT("sys_closefrom ( %" FMT_REGWORD "dx  )", SARG1);
+   PRE_REG_READ1(int, "closefrom", int, lowfd);
+
+   /*
+    * Can't pass this on to the kernel otherwise it will close
+    * all of the host files like the log
+    */
+
+   for (int i = ARG1; i < VG_(fd_soft_limit); ++i) {
+      VG_(close)(i);
+   }
+
+   SET_STATUS_Success(0);
+}
+
+// SYS___semctl   510
+// int semctl(int semid, int semnum, int cmd, ...);
+// int __semctl(int semid, int semnum, int cmd, _Inout_ union semun *arg);
+PRE(sys___semctl)
+{
+   switch (ARG3) {
+   case VKI_IPC_INFO:
+   case VKI_SEM_INFO:
+      PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(int, "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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",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 ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",ARG1,ARG2,ARG3,ARG4);
+      PRE_REG_READ4(long, "semctl",
+                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
+      break;
+   default:
+      PRINT("sys_semctl ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",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);
+}
+
+// SYS_msgctl  511
+// int msgctl(int msqid, int cmd, struct msqid_ds *buf);
+PRE(sys_msgctl)
+{
+   PRINT("sys_msgctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1,SARG2,ARG3 );
+
+   PRE_REG_READ3(int, "msgctl", int, msqid, int, cmd, struct msqid_ds *, buf);
+
+   switch (ARG2 /* cmd */) {
+   case VKI_IPC_STAT:
+      PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)",
+                     ARG3, sizeof(struct vki_msqid_ds) );
+      break;
+   case VKI_IPC_SET:
+      PRE_MEM_READ( "msgctl(IPC_SET, buf)",
+                    ARG3, sizeof(struct vki_msqid_ds) );
+      break;
+   }
+}
+
+POST(sys_msgctl)
+{
+   switch (ARG2 /* cmd */) {
+   case VKI_IPC_STAT:
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_msqid_ds) );
+      break;
+   }
+}
+
+
+// SYS_shmctl  512
+// int shmctl(int shmid, int cmd, struct shmid_ds *buf);
+PRE(sys_shmctl)
+{
+   PRINT("sys_shmctl ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,SARG2,ARG3);
+   PRE_REG_READ3(int, "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;
+   }
+}
+
+POST(sys_shmctl)
+{
+   if (ARG2 == VKI_IPC_STAT) {
+      POST_MEM_WRITE( ARG3, sizeof(struct vki_shmid_ds) );
+   }
+}
+
+// SYS_lpathconf  513
+// long lpathconf(const char *path, int name);
+PRE(sys_lpathconf)
+{
+   PRINT("sys_lpathconf ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d)", ARG1, SARG2);
+   PRE_REG_READ2(long, "lpathconf", const char *, path, int, name);
+   PRE_MEM_RASCIIZ("lpathconf(path)", ARG1);
+}
+
+// SYS___cap_rights_get 515
+// note extra 1st argument for the internal function which is not present
+// in the public interface
+// int __cap_rights_get(int version, int fd, cap_rights_t *rights);
+PRE(sys_cap_rights_get)
+{
+   PRINT("sys_cap_rights_get ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, SARG2, ARG3);
+   PRE_REG_READ3(long, "cap_rights_get", int, version, int, fd, vki_cap_rights_t*, rights);
+   PRE_MEM_WRITE("cap_rights_get(rights)", ARG3, sizeof(vki_cap_rights_t));
+}
+
+POST(sys_cap_rights_get)
+{
+   POST_MEM_WRITE(ARG2, sizeof(vki_cap_rights_t));
+}
+
+// SYS_cap_enter  516
+// int cap_enter(void);
+PRE(sys_cap_enter)
+{
+   PRINT("%s", "sys_cap_enter ( )");
+   PRE_REG_READ0(int, "cap_enter");
+   static Bool warning_given = False;
+   if (!warning_given) {
+      warning_given = True;
+      capabiltyMode = True;
+      VG_(umsg)(
+         "WARNING: Valgrind may not operate correctly in capability mode.\n"
+         "         Please consider disabling capability by using the RUNNING_ON_VALGRIND mechanism.\n"
+         "         See http://valgrind.org/docs/manual/manual-core-adv.html#manual-core-adv.clientreq\n");
+   }
+}
+
+// SYS_cap_getmode   517
+// int cap_getmode(u_int *modep);
+PRE(sys_cap_getmode)
+{
+   PRINT("sys_cap_getmode ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "cap_getmode", u_int*, modep);
+   PRE_MEM_WRITE("cap_getmode(modep)", ARG1, sizeof(u_int));
+}
+
+POST(sys_cap_getmode)
+{
+   POST_MEM_WRITE(ARG1, sizeof(u_int));
+}
+
+static vki_sigset_t pdfork_saved_mask;
+
+// SYS_pdfork  518
+// pid_t pdfork(int *fdp, int flags);
+PRE(sys_pdfork)
+{
+   Bool is_child;
+   Int child_pid;
+   vki_sigset_t mask;
+
+   PRINT("sys_pdfork ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2);
+   PRE_REG_READ2(pid_t, "pdfork", int*, fdp, int, flags);
+
+   /* 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, &pdfork_saved_mask);
+
+   VG_(do_atfork_pre)(tid);
+
+   SET_STATUS_from_SysRes( VG_(do_syscall2)(__NR_pdfork, ARG1, ARG2) );
+
+   if (!SUCCESS) return;
+
+   // 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 );
+
+   if (is_child) {
+      VG_(do_atfork_child)(tid);
+
+      /* restore signal mask */
+      VG_(sigprocmask)(VKI_SIG_SETMASK, &pdfork_saved_mask, NULL);
+   } else {
+      VG_(do_atfork_parent)(tid);
+
+      PRINT("   fork: process %d created child %d\n", VG_(getpid)(), child_pid);
+
+      /* restore signal mask */
+      VG_(sigprocmask)(VKI_SIG_SETMASK, &pdfork_saved_mask, NULL);
+   }
+
+   if (ARG1) {
+      PRE_MEM_WRITE( "pdfork(fdp)", ARG1, sizeof(int) );
+   }
+}
+
+POST(sys_pdfork)
+{
+   if (ARG1) {
+      POST_MEM_WRITE( ARG1, sizeof(int) );
+   }
+}
+
+// pdkill   519
+//int pdkill(int fd, int signum)
+PRE(sys_pdkill)
+{
+   PRINT("sys_pdkill ( %" FMT_REGWORD "u, %" FMT_REGWORD "d )", ARG1, SARG2);
+   PRE_REG_READ2(int, "pdkill", int, fd, int, signum);
+
+   if (!ML_(client_signal_OK)(ARG2)) {
+      SET_STATUS_Failure( VKI_EINVAL );
+      return;
+   }
+
+   /* If we're sending SIGKILL, check to see if the target is one of
+      our threads and handle it specially. */
+   if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1))
+      SET_STATUS_Success(0);
+
+   if (VG_(clo_trace_signals))
+      VG_(message)(Vg_DebugMsg, "pdkill: sent signal %ld to fd %ld\n",
+                   SARG2, SARG1);
+
+   /* This kill might have given us a pending signal.  Ask for a check once
+      the syscall is done. */
+   *flags |= SfPollAfter;
+
+}
+
+// SYS_pdgetpid   520
+// int pdgetpid(int fd, pid_t *pidp);
+PRE(sys_pdgetpid)
+{
+   PRINT("pdgetpid ( %" FMT_REGWORD "d, %#lx )", SARG1, ARG2);
+   PRE_REG_READ2(int, "pdgetpid",
+                 int, fd, pid_t*, pidp);
+   PRE_MEM_WRITE( "pdgetpid(pidp))", ARG2, sizeof(vki_pid_t) );
+}
+
+POST(sys_pdgetpid)
+{
+   POST_MEM_WRITE( ARG2, sizeof(vki_pid_t) );
+}
+
+// SYS_pselect 522
+
+// int pselect(int nfds, fd_set * restrict readfds, fd_set * restrict writefds,
+//             fd_set * restrict exceptfds,
+//             const struct timespec * restrict timeout,
+//             const sigset_t * restrict newsigmask);
+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(int, "pselect",
+                 int, nfds, vki_fd_set *, readfds, vki_fd_set *, writefds,
+                 vki_fd_set *, exceptfds, struct vki_timespec *, timeout,
+                 const sigset_t *, newsigmask);
+   // 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) {
+      PRE_MEM_READ( "pselect(sig)", ARG6, sizeof(vki_sigset_t) );
+      ARG6 = ML_(make_safe_mask)("syswrap.pselect.1", (Addr)ARG6);
+   }
+}
+
+POST(sys_pselect)
+{
+   ML_(free_safe_mask) ( (Addr)ARG6 );
+}
+
+// SYS_getloginclass 523
+// int getloginclass(char *name, size_t len);
+PRE(sys_getloginclass)
+{
+   PRINT("sys_getloginclass ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u  )", ARG1, ARG2);
+   PRE_REG_READ2(int, "getloginclass", char *, name, size_t, len);
+   // The buffer should be at least MAXLOGNAME bytes in length.
+   PRE_MEM_WRITE("getloginclass(name)", ARG1, ARG2);
+}
+
+POST(sys_getloginclass)
+{
+   POST_MEM_WRITE(ARG1, ARG2);
+}
+
+// SYS_setloginclass 524
+// int setloginclass(const char *name);
+PRE(sys_setloginclass)
+{
+   PRINT("sys_setloginclass ( %#" FMT_REGWORD "x(%s) )", ARG1, (HChar*)ARG1);
+   PRE_REG_READ1(int, "setloginclass", const char *, name);
+   PRE_MEM_RASCIIZ("rctl_setloginclass(name)", ARG1);
+}
+
+// SYS_rctl_get_racct   525
+// int rctl_get_racct(const char *inbufp, size_t inbuflen, char *outbufp,
+//                    size_t outbuflen);
+PRE(sys_rctl_get_racct)
+{
+   PRINT("sys_rctl_get_racct ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "rctl_get_racct", const char *, inbufp, size_t, inbuflen, char *, outbufp,
+                 size_t, outbuflen);
+   PRE_MEM_READ("rctl_get_racct(inbufp)", ARG1, ARG2);
+   PRE_MEM_WRITE("rctl_get_racct(outbufp)", ARG3, ARG4);
+}
+
+POST(sys_rctl_get_racct)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_rctl_get_rules   526
+// int rctl_get_rules(const char *inbufp, size_t inbuflen, char *outbufp,
+//                    size_t outbuflen);
+PRE(sys_rctl_get_rules)
+{
+   PRINT("sys_rctl_get_rules ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "rctl_get_rules", const char *, inbufp, size_t, inbuflen, char *, outbufp,
+                 size_t, outbuflen);
+   PRE_MEM_READ("rctl_get_rules(inbufp)", ARG1, ARG2);
+   PRE_MEM_WRITE("rctl_get_rules(outbufp)", ARG3, ARG4);
+}
+
+POST(sys_rctl_get_rules)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_rctl_get_limits  527
+// int rctl_get_limits(const char *inbufp, size_t inbuflen, char *outbufp,
+//                     size_t outbuflen);
+PRE(sys_rctl_get_limits)
+{
+   PRINT("sys_rctl_get_limits ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "rctl_get_limits", const char *, inbufp, size_t, inbuflen, char *, outbufp,
+                 size_t, outbuflen);
+   PRE_MEM_READ("rctl_get_limits(inbufp)", ARG1, ARG2);
+   PRE_MEM_WRITE("rctl_get_limits(outbufp)", ARG3, ARG4);
+}
+
+POST(sys_rctl_get_limits)
+{
+   POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_rctl_add_rule 528
+// int rctl_add_rule(const char *inbufp, size_t inbuflen, char *outbufp,
+//                   size_t outbuflen);
+PRE(sys_rctl_add_rule)
+{
+   PRINT("sys_rctl_add_rule ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ2(int, "rctl_add_rule", const char *, inbufp, size_t, inbuflen);
+   PRE_MEM_READ("rctl_add_rule(inbufp)", ARG1, ARG2);
+   // man page says
+   // The outbufp and outbuflen arguments are unused
+   //PRE_MEM_WRITE("rctl_add_rule(outbufp)", ARG3, ARG4);
+}
+
+POST(sys_rctl_add_rule)
+{
+   //POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_rctl_remove_rule 529
+// int rctl_remove_rule(const char *inbufp, size_t inbuflen, char *outbufp,
+//          size_t outbuflen);
+PRE(sys_rctl_remove_rule)
+{
+   PRINT("sys_rctl_remove_rule ( %#" FMT_REGWORD "xd, %" FMT_REGWORD "u, %#" FMT_REGWORD "xd, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4);
+   PRE_REG_READ2(int, "rctl_remove_rule", const char *, inbufp, size_t, inbuflen);
+   PRE_MEM_READ("rctl_remove_rule(inbufp)", ARG1, ARG2);
+   // man page says
+   // The outbufp and outbuflen arguments are unused
+   //PRE_MEM_WRITE("rctl_remove_rule(outbufp)", ARG3, ARG4);
+}
+
+POST(sys_rctl_remove_rule)
+{
+   //POST_MEM_WRITE(ARG3, ARG4);
+}
+
+// SYS_posix_fallocate  530
+// x86/amd64
+
+// SYS_posix_fadvise 531
+// x86/amd64
+
+// SYS_wait6   532
+// amd64 / x86
+
+// SYS_cap_rights_limit 533
+//int cap_rights_limit(int fd, const cap_rights_t *rights);
+PRE(sys_cap_rights_limit)
+{
+   PRINT("sys_cap_rights_limit ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "cap_rights_limit",
+                 int, fd, const cap_rights_t *, rights);
+   PRE_MEM_READ( "cap_rights_limit(rights)", ARG2, sizeof(struct vki_cap_rights) );
+}
+
+// SYS_cap_ioctls_limit 534
+// int cap_ioctls_limit(int fd, const unsigned long *cmds, size_t ncmds);
+PRE(sys_cap_ioctls_limit)
+{
+   PRINT("cap_ioctls_limit ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "cap_ioctls_limit",
+                 int, fd, unsigned long*, rights, vki_size_t, ncmds);
+   // "can be up to 256" taking that to not be inclusive
+   if (ARG3 < 256 ) {
+      PRE_MEM_READ( "cap_ioctls_limit(cmds))", ARG2, ARG3*sizeof(unsigned long) );
+   }
+   // else fail?
+}
+
+// SYS_cap_ioctls_get   535
+// int cap_ioctls_get(int fd, unsigned long *cmds, size_t maxcmds);
+PRE(sys_cap_ioctls_get)
+{
+   PRINT("sys_cap_ioctls_get ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", SARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "cap_ioctls_get", int, fd, unsigned long *, cmds, size_t, maxcmds);
+   if (ARG3 < 256) {
+      PRE_MEM_WRITE("cap_ioctls_get(cmds)", ARG2, ARG3*sizeof(unsigned long));
+   }
+}
+
+POST(sys_cap_ioctls_get)
+{
+   if (ARG3 < 256) {
+      POST_MEM_WRITE(ARG2, ARG3*sizeof(unsigned long));
+   }
+}
+
+
+// SYS_cap_fcntls_limit 536
+//int cap_fcntls_limit(int fd, uint32_t fcntlrights);
+PRE(sys_cap_fcntls_limit)
+{
+   PRINT("cap_fcntls_limit ( %" FMT_REGWORD "d, %" FMT_REGWORD "u )", SARG1, ARG2);
+   PRE_REG_READ2(long, "cap_fcntls_limit",
+                 int, fd, vki_uint32_t, fcntlrights);
+}
+
+// SYS_cap_fcntls_get   537
+// int cap_fcntls_get(int fd, uint32_t *fcntlrightsp);
+PRE(sys_cap_fcntls_get)
+{
+   PRINT("sys_cap_fcntls_get ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "cap_fcntls_get", int, fd, uint32_t *, fcntlrightsp);
+   PRE_MEM_WRITE("cap_fcntls_get(fcntlrightsp)", ARG2, sizeof(uint32_t));
+}
+
+POST(sys_cap_fcntls_get)
+{
+   POST_MEM_WRITE(ARG2, sizeof(uint32_t));
+}
+
+// SYS_bindat  538
+// int bindat(int fd, int s, const struct sockaddr *addr, socklen_t addrlen);
+PRE(sys_bindat)
+{
+   PRINT("sys_bindat ( %" FMT_REGWORD "d, %" FMT_REGWORD "dx, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
+         SARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "bindat", int, fd, int, s, const struct vki_sockaddr *, name, vki_socklen_t, namelen);
+   PRE_MEM_READ("bindat(name)", ARG3, ARG4);
+}
+
+// SYS_connectat  539
+// int connectat(int fd, int s, const struct sockaddr *name, socklen_t namelen);
+PRE(sys_connectat)
+{
+   PRINT("sys_connectat ( %" FMT_REGWORD "d, %" FMT_REGWORD "dx, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",
+         SARG1, SARG2, ARG3, ARG4);
+   PRE_REG_READ4(int, "connectat", int, fd, int, s, const struct vki_sockaddr *, name, vki_socklen_t, namelen);
+   PRE_MEM_READ("connectat(name)", ARG3, ARG4);
+}
+
+// SYS_chflagsat  540
+// int chflagsat(int fd, const char *path, unsigned long flags, int atflag);
+PRE(sys_chflagsat)
+{
+   PRINT("sys_chglagsat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "d )",
+         SARG1, ARG2, ARG3, SARG4);
+   PRE_REG_READ4(int, "chflagsat", int, fd, const char *, path, unsigned long, flags, int, atflag);
+   PRE_MEM_RASCIIZ("chflagsat(path)", ARG2);
+}
+
+// SYS_accept4 541
+// int accept4(int s, struct sockaddr * restrict addr,
+//             socklen_t * restrict addrlen, int flags);
+PRE(sys_accept4)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_accept4 ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u)",ARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(int, "accept4",
+                 int, s, struct sockaddr *, addr, int, *addrlen, int, flags);
+   ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
+}
+
+POST(sys_accept4)
+{
+   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);
+}
+
+// SYS_pipe2   542
+// int pipe2(int fildes[2], int flags);
+PRE(sys_pipe2)
+{
+   PRINT("sys_pipe2 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1, ARG2);
+   PRE_REG_READ2(int, "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]);
+   }
+}
+
+// SYS_aio_mlock  543
+// int aio_mlock(struct aiocb *iocb);
+PRE(sys_aio_mlock)
+{
+   PRINT("sys_aio_mlock ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "aio_mlock", struct vki_aiocb *, iocb);
+   PRE_MEM_READ("aio_mlock(iocb", ARG1, sizeof(struct vki_aiocb));
+   // this locks memory into RAM, don't think that we need to do
+   // anything extra
+}
+
+// SYS_procctl 544
+// amd64 / x86
+
+// SYS_ppoll   545
+// int ppoll(struct pollfd fds[], nfds_t nfds,
+//           const struct timespec * restrict timeout,
+//           const sigset_t * restrict newsigmask);
+PRE(sys_ppoll)
+{
+   PRINT("sys_ppoll ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD
+         "x, %#" FMT_REGWORD "x )",
+         ARG1, ARG2, ARG3, ARG4);
+   UInt i;
+   struct vki_pollfd* fds = (struct vki_pollfd *)(Addr)ARG1;
+   *flags |= SfMayBlock | SfPostOnFail;
+   PRE_REG_READ4(long, "ppoll",
+                 struct vki_pollfd *, fds, unsigned int, nfds,
+                 struct vki_timespec *, timeout, vki_sigset_t *, newsigmask);
+
+   if (ML_(safe_to_deref)(fds, ARG2*sizeof(struct vki_pollfd))) {
+      for (i = 0; i < ARG2; i++) {
+         PRE_MEM_READ( "ppoll(fds.fd)",
+                       (Addr)(&fds[i].fd), sizeof(fds[i].fd) );
+         PRE_MEM_READ( "ppoll(fds.events)",
+                       (Addr)(&fds[i].events), sizeof(fds[i].events) );
+         PRE_MEM_WRITE( "ppoll(fds.revents)",
+                        (Addr)(&fds[i].revents), sizeof(fds[i].revents) );
+      }
+   }
+
+   if (ARG3) {
+      PRE_MEM_READ( "ppoll(timeout)", ARG3,
+                    sizeof(struct vki_timespec) );
+   }
+   if (ARG4) {
+      PRE_MEM_READ( "ppoll(newsigmask)", ARG4, sizeof(vki_sigset_t));
+      ARG4 = ML_(make_safe_mask)("syswrap.ppoll.1", (Addr)ARG4);
+   }
+}
+
+POST(sys_ppoll)
+{
+   if (SUCCESS && ((Word)RES != -1)) {
+      UInt i;
+      struct vki_pollfd* ufds = (struct vki_pollfd *)(Addr)ARG1;
+      for (i = 0; i < ARG2; i++)
+         POST_MEM_WRITE( (Addr)(&ufds[i].revents), sizeof(ufds[i].revents) );
+   }
+   ML_(free_safe_mask) ( (Addr)ARG4 );
+}
+
+// SYS_futimens   546
+// int futimens(int fd, const struct timespec times[2]);
+PRE(sys_futimens)
+{
+   PRINT("sys_futimens ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )", SARG1, ARG2);
+   PRE_REG_READ2(int, "futimens", int, fd, const struct timespec *, times);
+   PRE_MEM_READ("futimens(times)", ARG2, 2*sizeof(struct vki_timespec));
+}
+
+// SYS_utimensat  547
+// int utimensat(int fd, const char *path, const struct timespec times[2],
+//               int flag);
+PRE(sys_utimensat)
+{
+   PRINT("sys_utimensat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         SARG1, ARG2, ARG3, SARG4);
+   PRE_REG_READ4(int, "utimensat", int, fd, const char *,path, const struct timespec *, times,
+                 int, flag);
+   PRE_MEM_RASCIIZ("utimensat(path)", ARG2);
+   PRE_MEM_READ("utimensat(times)", ARG3, 2*sizeof(struct vki_timespec));
+}
+
+// SYS_fdatasync  550
+// int fdatasync(int fd);
+PRE(sys_fdatasync)
+{
+   PRINT("sys_fdatasync ( %" FMT_REGWORD "d )",SARG1);
+   PRE_REG_READ1(int, "fdatasync", int, fd);
+}
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+// SYS_fstat   551
+// int fstat(int fd, struct stat *sb);
+PRE(sys_fstat)
+{
+   PRINT("sys_fstat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2);
+   PRE_REG_READ2(int, "fstat", int, fd, struct stat *, sb);
+   PRE_MEM_WRITE( "fstat(sb)", ARG2, sizeof(struct vki_stat) );
+}
+
+POST(sys_fstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
+}
+
+// SYS_fstatat 552
+// int fstatat(int fd, const char *path, struct stat *sb, int flag);
+PRE(sys_fstatat)
+{
+   PRINT("sys_fstatat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %" FMT_REGWORD "d )", SARG1,ARG2,(char*)ARG2,ARG3,SARG4);
+   PRE_REG_READ4(int, "fstatat",
+                 int, fd, const char *, path, struct stat *, sb, int, flag);
+   PRE_MEM_RASCIIZ( "fstatat(path)", ARG2 );
+   PRE_MEM_WRITE( "fstatat(sb)", ARG3, sizeof(struct vki_stat) );
+}
+
+POST(sys_fstatat)
+{
+   POST_MEM_WRITE( ARG3, sizeof(struct vki_stat) );
+}
+// SYS_fhstat  553
+// int fhstat(const fhandle_t *fhp, struct stat *sb);
+PRE(sys_fhstat)
+{
+   PRINT("sys_fhstat ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",ARG1,ARG2);
+   PRE_REG_READ2(long, "fhstat", const vki_fhandle_t *, fhp, struct stat *, sb);
+   PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) );
+   PRE_MEM_WRITE( "fhstat(sb)", ARG2, sizeof(struct vki_stat) );
+}
+
+POST(sys_fhstat)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
+}
+
+// SYS_getdirentries 554
+// ssize_t getdirentries(int fd, char *buf, size_t nbytes, off_t *basep);
+PRE(sys_getdirentries)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_getdirentries ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", SARG1,ARG2,ARG3,ARG4);
+   PRE_REG_READ4(ssize_t, "getdirentries",
+                 int, fd, char *, buf,
+                 size_t, nbytes,
+                 off_t *, basep);
+   PRE_MEM_WRITE( "getdirentries(buf)", ARG2, ARG3 );
+   if (ARG4)
+      PRE_MEM_WRITE("getdirentries(basep)", ARG4, sizeof (vki_off_t));
+}
+
+POST(sys_getdirentries)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0) {
+      POST_MEM_WRITE( ARG2, RES );
+      if ( ARG4 != 0 )
+         POST_MEM_WRITE( ARG4, sizeof (vki_off_t));
+   }
+}
+
+// SYS_statfs  555
+// int statfs(const char *path, struct statfs *buf);
+PRE(sys_statfs)
+{
+   PRINT("sys_statfs ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x )",ARG1,(char *)ARG1,ARG2);
+   PRE_REG_READ2(int, "statfs", const char *, path, struct statfs *, buf);
+   PRE_MEM_RASCIIZ( "statfs(path)", ARG1 );
+   PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_statfs) );
+}
+
+POST(sys_statfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) );
+}
+
+// SYS_fstatfs 556
+// int fstatfs(int fd, struct statfs *buf);
+PRE(sys_fstatfs)
+{
+   PRINT("sys_fstatfs ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x )",SARG1,ARG2);
+   PRE_REG_READ2(int, "fstatfs",
+                 int, fd, struct vki_statfs *, buf);
+   PRE_MEM_WRITE( "fstatfs(buf)", ARG2, sizeof(struct vki_statfs) );
+}
+
+POST(sys_fstatfs)
+{
+   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) );
+}
+
+// SYS_getfsstat  557
+// int getfsstat(struct statfs *buf, long bufsize, int mode);
+PRE(sys_getfsstat)
+{
+   PRINT("sys_getfsstat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )",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 ((Word)RES != -1) {
+      POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_statfs) );
+   }
+}
+
+// SYS_fhstatfs   558
+// int fhstatfs(const fhandle_t *fhp, struct statfs *buf);
+PRE(sys_fhstatfs)
+{
+   PRINT("sys_fhstatfs ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",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) );
+}
+
+// SYS_mknodat 559
+// int mknodat(int fd, const char *path, mode_t mode, dev_t dev);
+PRE(sys_mknodat)
+{
+   PRINT("sys_mknodat ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x(%s), 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 );
+   PRE_REG_READ4(long, "mknodat",
+                 int, fd, const char *, path, vki_mode_t, mode, vki_dev_t, dev);
+   PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 );
+}
+
+// SYS_kevent  560
+// int kevent(int kq, const struct kevent *changelist, int nchanges,
+//            struct kevent *eventlist, int nevents,
+//            const struct timespec *timeout);
+PRE(sys_kevent)
+{
+   PRINT("sys_kevent ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
+   PRE_REG_READ6(int, "kevent",
+                 int, kq, struct vki_kevent *, changelist, int, nchanges,
+                 struct vki_kevent *, eventlist, int, nevents,
+                 struct timespec *, timeout);
+   if (ARG2 != 0 && ARG3 != 0)
+      PRE_MEM_READ( "kevent(changelist)", ARG2, sizeof(struct vki_kevent)*ARG3 );
+   if (ARG4 != 0 && ARG5 != 0)
+      PRE_MEM_WRITE( "kevent(eventlist)", ARG4, sizeof(struct vki_kevent)*ARG5);
+   if (ARG5 != 0)
+      *flags |= SfMayBlock;
+   if (ARG6 != 0)
+      PRE_MEM_READ( "kevent(timeout)",
+                    ARG6, sizeof(struct vki_timespec));
+}
+
+POST(sys_kevent)
+{
+   vg_assert(SUCCESS);
+   if ((Word)RES != -1) {
+      if (ARG4 != 0)
+         POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent)*RES) ;
+   }
+}
+
+// SYS_cpuset_getdomain 561
+// x86 / amd64
+
+// SYS_cpuset_setdomain 562
+// x86 / amd64
+
+// SYS_getrandom  563
+// ssize_t  getrandom(void *buf, size_t buflen, unsigned int flags);
+PRE(sys_getrandom)
+{
+   PRINT("sys_getrandom ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(ssize_t, "getrandom",
+                 void *, buf, vki_size_t, buflen, unsigned int, flags);
+   PRE_MEM_WRITE( "getrandom(buf)", ARG1, ARG2 );
+   if ((ARG3 & VKI_GRND_NONBLOCK) == 0) {
+      *flags |= SfMayBlock;
+   }
+}
+
+POST(sys_getrandom)
+{
+   POST_MEM_WRITE( ARG1, ARG2 );
+}
+
+// SYS_getfhat 564
+// int getfhat(int fd, const char *path, fhandle_t *fhp, int flag);
+PRE(sys_getfhat)
+{
+   PRINT("sys_getfhat ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %" FMT_REGWORD "x, %" FMT_REGWORD "d ", SARG1, ARG2, ARG3, SARG4);
+   PRE_REG_READ4(int, "getfhat", int, fd, const char*, path, vki_fhandle_t*, fhp, int, flag);
+   PRE_MEM_RASCIIZ( "getfhat(path)", ARG2 );
+   PRE_MEM_WRITE("getfhat(fhp)", ARG3, sizeof(vki_fhandle_t));
+}
+
+POST(sys_getfhat)
+{
+   POST_MEM_WRITE(ARG3, sizeof(vki_fhandle_t));
+}
+
+// SYS_fhlink  565
+// int fhlink(fhandle_t *fhp, const char *to);
+PRE(sys_fhlink)
+{
+   PRINT("sys_fhlink ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", ARG1, ARG2);
+   PRE_REG_READ2(int, "fhlink", vki_fhandle_t *, fhp, const char *, to);
+   PRE_MEM_READ( "fhlink(fhp)", ARG1, sizeof(vki_fhandle_t));
+   PRE_MEM_RASCIIZ("fhlink(buf)", ARG2);
+}
+
+// SYS_fhlinkat   566
+// int fhlinkat(fhandle_t *fhp, int tofd, const char *to);
+PRE(sys_fhlinkat)
+{
+   PRINT("sys_fhlinkat ( %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "xu ", ARG1, SARG2, ARG3);
+   PRE_REG_READ3(int, "fhlinkat", vki_fhandle_t *, fhp, int, tofd, const char *, to);
+   PRE_MEM_READ( "fhlinkat(fhp)", ARG1, sizeof(vki_fhandle_t));
+   PRE_MEM_RASCIIZ("fhreadlink(to)", ARG3);
+}
+
+// SYS_fhreadlink 567
+// int fhreadlink(fhandle_t *fhp, char *buf, size_t bufsize);
+PRE(sys_fhreadlink)
+{
+   PRINT("sys_fhreadlink ( %#" FMT_REGWORD "x, %" FMT_REGWORD "x, %" FMT_REGWORD "u ", ARG1, ARG2, ARG3);
+   PRE_REG_READ3(int, "fhreadlink", vki_fhandle_t *, fhp, char *, buf, size_t, bufsize);
+   PRE_MEM_READ( "fhreadlink(fhp)", ARG1, sizeof(vki_fhandle_t));
+   PRE_MEM_WRITE("fhreadlink(buf)", ARG2, ARG3);
+}
+
+POST(sys_fhreadlink)
+{
+   POST_MEM_WRITE(ARG2, ARG3);
+}
+
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_12_2)
+
+// SYS___sysctlbyname
+// int sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
+//                  const void *newp, size_t newlen);
+// syscalls.master:
+// int __sysctlbyname(_In_reads_(namelen) const char *name, size_t namelen,
+//                    _Out_writes_bytes_opt_(*oldlenp) void *old,
+//                    _Inout_opt_ size_t *oldlenp, _In_reads_bytes_opt_(newlen) void *new,
+//                    size_t newlen );
+PRE(sys___sysctlbyname)
+{
+   // this is very much like SYS___sysctl, instead of having an OID with length
+   // here threre is an ascii string with length
+   // @todo PJF factor out the common functionality of the two
+   PRINT("sys___sysctlbyname ( %#" FMT_REGWORD "x(%s), %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "u )", ARG1,(const char*)ARG1,ARG2,ARG3,ARG4,ARG5 );
+   PRE_REG_READ6(int, "__sysctlbyname", const char *, name, vki_size_t, namelen,
+                 void *, oldp, vki_size_t *, oldlenp,
+                 void *, newp, vki_size_t, newlen);
+   // read number of ints specified in ARG2 from mem pointed to by ARG1
+   PRE_MEM_READ("__sysctlbyname(name)", (Addr)ARG1, ARG2 * sizeof(int));
+
+   // if 'newp' is not NULL can read namelen bytes from that addess
+   if (ARG5 != (UWord)NULL)
+      PRE_MEM_READ("__sysctlbyname(newp)", (Addr)ARG5, ARG6);
+
+   // there are two scenarios for oldlenp/oldp
+   // 1. oldval is NULL and oldlenp is non-NULL
+   //    this is a query of oldlenp so oldlenp will be written
+   // 2. Both are non-NULL
+   //    this is a query of oldp, oldlenp will be read and oldp will
+   //    be written
+
+   // is oldlenp is not NULL, can write
+   if (ARG4 != (UWord)NULL) {
+      if (ARG3 != (UWord)NULL) {
+         // case 2 above
+         PRE_MEM_READ("__sysctlbyname(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
+         if (ML_(safe_to_deref)((void*)(Addr)ARG4, sizeof(vki_size_t))) {
+            PRE_MEM_WRITE("__sysctlbyname(oldp)", (Addr)ARG3, *(vki_size_t *)ARG4);
+         } else {
+            VG_(dmsg)("Warning: Bad oldlenp address %p in sysctl\n",
+                      (void *)(Addr)ARG4);
+            SET_STATUS_Failure ( VKI_EFAULT );
+         }
+      } else {
+         // case 1 above
+         PRE_MEM_WRITE("__sysctlbyname(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
+      }
+   }
+}
+
+POST(sys___sysctlbyname)
+{
+   if (ARG4 != (UWord)NULL) {
+      if (ARG3 != (UWord)NULL) {
+         //POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t));
+         POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4);
+      } else
+         POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t));
+   }
+}
+
+#endif
+
+#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_freebsd11_mknod,  sys_mknod),             // 14
+   GENX_(__NR_chmod,            sys_chmod),             // 15
+
+   GENX_(__NR_chown,            sys_chown),             // 16
+   GENX_(__NR_break,            sys_brk),               // 17
+   // freebsd 4 getfsstat                                  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_freebsd10_pipe,   sys_pipe),              // 42
+   GENX_(__NR_getegid,          sys_getegid),           // 43
+
+   GENX_(__NR_profil,           sys_ni_syscall),        // 44
+   GENX_(__NR_ktrace,           sys_ni_syscall),        // 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_vfork),             // 66
+   // obsol vread                                          67
+
+   // obsol vwrite                                         68
+   BSDX_(__NR_sbrk,             sys_sbrk),              // 69
+   // not implemented in OS sstk                           70
+   // 4.3 mmap                                             71
+
+   // freebsd11 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
+
+   BSDXY(__NR_fcntl,            sys_fcntl),             // 92
+   GENX_(__NR_select,           sys_select),            // 93
+   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
+
+   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
+
+   // no idea what the following syscall does
+   // unimp SYS_nlm_syscall                                154
+
+   // a somewhat complicated NFS API
+   // takes a flag and a void* that can point to one of
+   // three different types of struct depending on the flag
+   // unimp SYS_nfssvc                                     155
+
+   // 4.3 getdirentries                                    156
+   // freebsd 4 statfs                                     157
+   // freebsd 4 fstatfs                                    158
+
+   BSDXY(__NR_lgetfh,           sys_lgetfh),            // 160
+   BSDXY(__NR_getfh,            sys_getfh),             // 161
+#if (FREEBSD_VERS <= FREEBSD_10)
+   BSDXY(__NR_freebsd4_getdomainname, sys_freebsd4_getdomainname), // 162
+   BSDX_(__NR_freebsd4_setdomainname, sys_freebsd4_setdomainname), // 163
+   BSDXY(__NR_freebsd4_uname,   sys_freebsd4_uname),    // 164
+#endif
+   BSDXY(__NR_sysarch,          sys_sysarch),           // 165
+   BSDXY(__NR_rtprio,           sys_rtprio),            // 166
+
+   // the following 3 seem only to be defines in a header
+   // semsys                                               169
+   // msgsys                                               170
+   // shmsys                                               171
+
+#if (FREEBSD_VERS <= FREEBSD_10)
+   BSDXY(__NR_freebsd6_pread,   sys_freebsd6_pread),    // 173
+   BSDX_(__NR_freebsd6_pwrite,  sys_freebsd6_pwrite),   // 174
+#endif
+   BSDX_(__NR_setfib,           sys_setfib),            // 175
+
+   // @todo PJF this exists on Darwin and Solaris as well
+   // and it isn't implememented on either
+   // looking at the manpage there is a rather fearsome
+   // timex struct with a mixture of ro and rw fields
+   // BSDXY(__NR_ntp_adjtime,   sys_ntp_adjtime),       // 176
+
+   // bsd/os sfork                                         177
+   // bsd/os getdescriptor                                 178
+   // bsd/os setdescriptor                                 179
+
+   GENX_(__NR_setgid,           sys_setgid),            // 181
+   BSDX_(__NR_setegid,          sys_setegid),           // 182
+   BSDX_(__NR_seteuid,          sys_seteuid),           // 183
+
+   // obs lfs_bmapv                                        184
+   // obs lfs_markv                                        185
+   // obs lfs_segclean                                     186
+   // obs lfs_segwait                                      187
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_stat,   sys_freebsd11_stat),    // 188
+   BSDXY(__NR_freebsd11_fstat,  sys_freebsd11_fstat),   // 189
+   BSDXY(__NR_freebsd11_lstat,  sys_freebsd11_lstat),   // 190
+#else
+   BSDXY(__NR_stat,             sys_stat),              // 188
+   BSDXY(__NR_fstat,            sys_fstat),             // 189
+   BSDXY(__NR_lstat,            sys_lstat),             // 190
+#endif
+   BSDX_(__NR_pathconf,         sys_pathconf),          // 191
+   BSDX_(__NR_fpathconf,        sys_fpathconf),         // 192
+   GENXY(__NR_getrlimit,        sys_getrlimit),         // 194
+   GENX_(__NR_setrlimit,        sys_setrlimit),         // 195
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_getdirentries, sys_freebsd11_getdirentries), // 196
+#else
+   BSDXY(__NR_getdirentries,    sys_getdirentries),     // 196
+#endif
+#if (FREEBSD_VERS <= FREEBSD_10)
+   BSDX_(__NR_freebsd6_mmap,    sys_freebsd6_mmap),     // 197
+#endif
+   // __syscall (handled specially)                     // 198
+#if (FREEBSD_VERS <= FREEBSD_10)
+   BSDX_(__NR_freebsd6_lseek,   sys_freebsd6_lseek),   // 199
+   BSDX_(__NR_freebsd6_truncate, sys_freebsd6_truncate), // 200
+   BSDX_(__NR_freebsd6_ftruncate, sys_freebsd6_ftruncate), // 201
+#endif
+   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
+
+   BSDXY(__NR_freebsd7___semctl, sys_freebsd7___semctl), // 220
+   BSDX_(__NR_semget,           sys_semget),            // 221
+   BSDX_(__NR_semop,            sys_semop),             // 222
+   // obs semconfig                                        223
+
+   BSDXY(__NR_freebsd7_msgctl,  sys_freebsd7_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_freebsd7_shmctl,  sys_freebsd7_shmctl),   // 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
+   BSDXY(__NR_ktimer_create,    sys_timer_create),      // 235
+   BSDX_(__NR_ktimer_delete,    sys_timer_delete),      // 236
+   BSDXY(__NR_ktimer_settime,   sys_timer_settime),     // 237
+   BSDXY(__NR_ktimer_gettime,   sys_timer_gettime),     // 238
+   BSDX_(__NR_ktimer_getoverrun, sys_timer_getoverrun), // 239
+
+   GENXY(__NR_nanosleep,        sys_nanosleep),         // 240
+   // unimpl SYS_ffclock_getcounter                        241
+   // unimpl SYS_ffclock_setestimate                       242
+   // unimpl SYS_ffclock_getestimate                       243
+
+   BSDXY(__NR_clock_nanosleep,  sys_clock_nanosleep),   // 244
+   // unimpl SYS_clock_getcpuclockid2                      247
+
+   // unimpl SYS_ntp_gettime                               248
+   BSDXY(__NR_minherit,         sys_minherit),          // 250
+   BSDX_(__NR_rfork,            sys_rfork),             // 251
+
+   // openbsd_poll                                      // 252
+   BSDX_(__NR_issetugid,        sys_issetugid),         // 253
+   GENX_(__NR_lchown,           sys_lchown),            // 254
+   BSDXY(__NR_aio_read,         sys_aio_read),          // 255
+   BSDXY(__NR_aio_write,        sys_aio_write),         // 256
+   BSDX_(__NR_lio_listio,       sys_lio_listio),        // 257
+
+   GENXY(__NR_freebsd11_getdents, sys_getdents),        // 272
+   BSDX_(__NR_lchmod,           sys_lchmod),            // 274
+   // netbsd_lchown                                     // 275
+
+   BSDX_(__NR_lutimes,          sys_lutimes),           // 276
+   // netbsd msync                                         277
+   // unimpl SYS_freebsd11_nstat                           278
+   // unimpl SYS_freebsd11_nfstat                          279
+
+   // unimpl SYS_freebsd11_nlstat                          280
+
+   BSDXY(__NR_preadv,           sys_preadv),            // 289
+   BSDX_(__NR_pwritev,          sys_pwritev),           // 290
+
+   // freebsd 4 fhstatfs                                   297
+   BSDXY(__NR_fhopen,           sys_fhopen),            // 298
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_fhstat, sys_freebsd11_fhstat),  // 299
+#else
+   BSDXY(__NR_fhstat,           sys_fhstat),            // 299
+#endif
+
+   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
+   BSDX_(__NR_aio_return,       sys_aio_return),        // 314
+   BSDX_(__NR_aio_suspend,      sys_aio_suspend),       // 315
+
+   BSDX_(__NR_aio_cancel,       sys_aio_cancel),        // 316
+   BSDX_(__NR_aio_error,        sys_aio_error),         // 317
+   // freebsd 6 aio_read                                   318
+   // freebsd 6 aio_write                                  319
+   // freebsd 6 lio_listio                                 320
+   BSDX_(__NR_yield,            sys_yield),             // 321
+   // obs thr_sleep                                        322
+   // obs thr_wakeup                                       323
+
+   GENX_(__NR_mlockall,         sys_mlockall),          // 324
+   BSDX_(__NR_munlockall,       sys_munlockall),        // 325
+   BSDXY(__NR___getcwd,         sys___getcwd),          // 326
+   BSDX_(__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
+
+   // freebsd 4 sendfile                                   336
+   BSDXY(__NR_kldsym,           sys_kldsym),            // 337
+   BSDX_(__NR_jail,             sys_jail),              // 338
+   // unimpl SYS_nnpfs_syscall                             339
+
+   BSDXY(__NR_sigprocmask,      sys_sigprocmask),       // 340
+   BSDXY(__NR_sigsuspend,       sys_sigsuspend),        // 341
+   // freebsd 4 sigaction                                  342
+   BSDXY(__NR_sigpending,       sys_sigpending),        // 343
+
+   // freebsd 4 sigreturn                                  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
+   BSDX_(__NR_extattrctl,       sys_extattrctl),        // 355
+   BSDX_(__NR_extattr_set_file, sys_extattr_set_file),  // 356
+   BSDXY(__NR_extattr_get_file, sys_extattr_get_file),  // 357
+   BSDX_(__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
+   BSDXY(__NR_kqueue,           sys_kqueue),            // 362
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_kevent, sys_freebsd11_kevent),  // 363
+#else
+   BSDXY(__NR_kevent,           sys_kevent),            // 363
+#endif
+   // obs __cap_get_proc                                   364
+   // obs __cap_set_proc                                   365
+   // obs __cap_get_fd                                     366
+   // obs __cap_get_file                                   367
+   // obs __cap_set_fd                                     368
+   // obs __cap_set_file                                   369
+
+   BSDX_(__NR_extattr_set_fd,   sys_extattr_set_fd),    // 371
+   BSDXY(__NR_extattr_get_fd,   sys_extattr_get_fd),    // 372
+   BSDX_(__NR_extattr_delete_fd, sys_extattr_delete_fd), // 373
+   BSDX_(__NR___setugid,        sys___setugid),         // 374
+   // obs nfsclnt                                          375
+
+   BSDX_(__NR_eaccess,          sys_eaccess),           // 376
+   // unimpl afs3_syscall                                  377
+   BSDX_(__NR_nmount,           sys_nmount),           //  378
+   // obs kse_exit                                         379
+   // obs kse_wakeup                                       380
+   // obs kse_create                                       381
+   // obs kse_thr_interrupt                                382
+   // obs kse_release                                      383
+
+   // unimpl __mac_get_proc                                384
+   // unimpl __mac_set_proc                                385
+   // unimpl __mac_get_fd                                  386
+   // unimpl __mac_get_file                                387
+   // unimpl __mac_set_fd                                  388
+   // unimpl __mac_set_file                                389
+   BSDXY(__NR_kenv,             sys_kenv),              // 390
+   BSDX_(__NR_lchflags,         sys_lchflags),          // 391
+
+   BSDXY(__NR_uuidgen,          sys_uuidgen),           // 392
+   BSDXY(__NR_sendfile,         sys_sendfile),          // 393
+   // unimpl mac_syscall                                   394
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_getfsstat, sys_freebsd11_getfsstat), // 395
+   BSDXY(__NR_freebsd11_statfs, sys_statfs),            // 396
+   BSDXY(__NR_freebsd11_fstatfs, sys_fstatfs),          // 397
+   BSDXY(__NR_freebsd11_fhstatfs, sys_fhstatfs),        // 398
+#else
+   BSDXY(__NR_getfsstat,        sys_getfsstat),         // 395
+   BSDXY(__NR_statfs,           sys_statfs),            // 396
+   BSDXY(__NR_fstatfs,          sys_fstatfs),           // 397
+   BSDXY(__NR_fhstatfs,         sys_fhstatfs),          // 398
+#endif
+
+   // unimpl ksem_close                                    400
+   // unimpl ksem_post                                     401
+   // unimpl ksem_wait                                     402
+   // unimpl ksem_trywait                                  403
+
+   // unimpl ksem_init                                     404
+   // unimpl ksem_open                                     405
+   // unimpl ksem_unlink                                   406
+   // unimpl ksem_getvalue                                 407
+
+   // unimpl ksem_destroy                                  408
+   // unimpl __mac_get_pid                                 409
+   // unimpl __mac_get_link                                410
+   // unimpl __mac_set_link                                411
+
+   BSDX_(__NR_extattr_set_link, sys_extattr_set_link),  // 412
+   BSDXY(__NR_extattr_get_link, sys_extattr_get_link),  // 413
+   BSDX_(__NR_extattr_delete_link, sys_extattr_delete_link), // 414
+   // unimpl __mac_execve                                  415
+
+   BSDXY(__NR_sigaction,        sys_sigaction),         // 416
+   BSDX_(__NR_sigreturn,        sys_sigreturn),         // 417
+
+   BSDXY(__NR_getcontext,       sys_getcontext),        // 421
+   BSDX_(__NR_setcontext,       sys_setcontext),        // 422
+   BSDXY(__NR_swapcontext,      sys_swapcontext),       // 423
+
+   BSDX_(__NR_swapoff,          sys_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
+   BSDXY(__NR_sigwait,          sys_sigwait),           // 429
+   BSDX_(__NR_thr_create,       sys_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
+#if (FREEBSD_VERS <= FREEBSD_10)
+   BSDXY(__NR__umtx_lock,       sys__umtx_lock),        // 434
+   BSDXY(__NR__umtx_unlock,     sys__umtx_unlock),      // 435
+#endif
+
+   BSDX_(__NR_jail_attach,      sys_jail_attach),       // 436
+   BSDXY(__NR_extattr_list_fd,  sys_extattr_list_fd),   // 437
+   BSDXY(__NR_extattr_list_file, sys_extattr_list_file), // 438
+   BSDXY(__NR_extattr_list_link, sys_extattr_list_link), // 439
+
+   // obs kse_switchin                                     440
+   // unimpl ksem_timedwait                                441
+   BSDX_(__NR_thr_suspend,      sys_thr_suspend),       // 442
+   BSDX_(__NR_thr_wake,         sys_thr_wake),          // 443
+   BSDX_(__NR_kldunloadf,       sys_kldunloadf),        // 444
+   // unimpl audit                                         445
+   // unimpl auditon                                       446
+   // unimpl getauid                                       447
+
+   // unimpl setauid                                       448
+   // unimpl getaudit                                      449
+   // unimpl setaudit                                      450
+   // unimpl getaudit_addr                                 451
+   // unimpl setaudit_addr                                 452
+   // unimpl auditctl                                      453
+   BSDXY(__NR__umtx_op,         sys__umtx_op),          // 454
+   BSDX_(__NR_thr_new,          sys_thr_new),           // 455
+
+   BSDX_(__NR_sigqueue,         sys_sigqueue),          // 456
+   BSDXY(__NR_kmq_open,         sys_kmq_open),          // 457
+   BSDX_(__NR_kmq_setattr,      sys_kmq_setattr),       // 458
+   BSDXY(__NR_kmq_timedreceive, sys_kmq_timedreceive),  // 459
+
+   BSDX_(__NR_kmq_timedsend,    sys_kmq_timedsend),     // 460
+   BSDX_(__NR_kmq_notify,       sys_kmq_notify),        // 461
+   BSDX_(__NR_kmq_unlink,       sys_kmq_unlink),        // 462
+   BSDX_(__NR_abort2,           sys_abort2),            // 463
+
+   BSDX_(__NR_thr_set_name,     sys_thr_set_name),      // 464
+   BSDX_(__NR_aio_fsync,        sys_aio_fsync),         // 465
+   BSDXY(__NR_rtprio_thread,    sys_rtprio_thread),     // 466
+
+   // unimpl sctp_peeloff                                  471
+
+   // unimpl sctp_generic_sendmsg                          472
+   // unimpl sctp_generic_sendmsg_iov                      473
+   // unimpl sctp_generic_recvmsg                          474
+   BSDXY(__NR_pread,            sys_pread),             // 475
+
+   BSDX_(__NR_pwrite,           sys_pwrite),            // 476
+   BSDX_(__NR_mmap,             sys_mmap),              // 477
+   BSDX_(__NR_lseek,            sys_lseek),             // 478
+   BSDX_(__NR_truncate,         sys_truncate),          // 479
+   BSDX_(__NR_ftruncate,        sys_ftruncate),         // 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
+
+   BSDXY(__NR_cpuset,           sys_cpuset),            // 484
+   BSDX_(__NR_cpuset_setid,     sys_cpuset_setid),      // 485
+   BSDXY(__NR_cpuset_getid,     sys_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
+
+   BSDX_(__NR_fexecve,          sys_fexecve),           // 492
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_freebsd11_fstatat, sys_freebsd11_fstatat), // 493
+#else
+   BSDXY(__NR_fstatat,          sys_fstatat),           // 493
+#endif
+   BSDX_(__NR_futimesat,        sys_futimesat),         // 494
+   BSDX_(__NR_linkat,           sys_linkat),            // 495
+
+   BSDX_(__NR_mkdirat,          sys_mkdirat),           // 496
+   BSDX_(__NR_mkfifoat,         sys_mkfifoat),          // 497
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDX_(__NR_freebsd11_mknodat, sys_freebsd11_mknodat), // 498
+#else
+   BSDX_(__NR_mknodat,          sys_mknodat),           // 498
+#endif
+
+   BSDXY(__NR_openat,           sys_openat),            // 499
+
+   BSDXY(__NR_readlinkat,       sys_readlinkat),        // 500
+   BSDX_(__NR_renameat,         sys_renameat),          // 501
+   BSDX_(__NR_symlinkat,        sys_symlinkat),         // 502
+   BSDX_(__NR_unlinkat,         sys_unlinkat),          // 503
+
+   BSDX_(__NR_posix_openpt,     sys_posix_openpt),      // 504
+   // unimp gssd_syscall                                   505
+   BSDX_(__NR_jail_get,         sys_jail_get),          // 506
+   BSDX_(__NR_jail_set,         sys_jail_set),          // 507
+   BSDX_(__NR_jail_remove,      sys_jail_remove),       // 508
+   BSDX_(__NR_closefrom,        sys_closefrom),         // 509
+   BSDXY(__NR___semctl,         sys___semctl),          // 510
+   BSDXY(__NR_msgctl,           sys_msgctl),            // 511
+   BSDXY(__NR_shmctl,           sys_shmctl),            // 512
+   BSDX_(__NR_lpathconf,        sys_lpathconf),         // 513
+   /* 514 is obsolete cap_new */
+   BSDXY(__NR___cap_rights_get, sys_cap_rights_get),    // 515
+   BSDX_(__NR_cap_enter,        sys_cap_enter),         // 516
+   BSDXY(__NR_cap_getmode,      sys_cap_getmode),       // 517
+   BSDXY(__NR_pdfork,           sys_pdfork),            // 518
+   BSDX_(__NR_pdkill,           sys_pdkill),            // 519
+   BSDXY(__NR_pdgetpid,         sys_pdgetpid),          // 520
+   BSDXY(__NR_pselect,          sys_pselect),           // 522
+   BSDXY(__NR_getloginclass,    sys_getloginclass),     // 523
+   BSDX_(__NR_setloginclass,    sys_setloginclass),     // 524
+   BSDXY(__NR_rctl_get_racct,   sys_rctl_get_racct),    // 525
+   BSDXY(__NR_rctl_get_rules,   sys_rctl_get_rules),    // 526
+   BSDXY(__NR_rctl_get_limits,  sys_rctl_get_limits),   // 527
+   BSDXY(__NR_rctl_add_rule,    sys_rctl_add_rule),     // 528
+   BSDXY(__NR_rctl_remove_rule, sys_rctl_remove_rule),  // 529
+   BSDX_(__NR_posix_fallocate,  sys_posix_fallocate),   // 530
+   BSDX_(__NR_posix_fadvise,    sys_posix_fadvise),     // 531
+   BSDXY(__NR_wait6,            sys_wait6),             // 532
+   BSDX_(__NR_cap_rights_limit, sys_cap_rights_limit),  // 533
+   BSDX_(__NR_cap_ioctls_limit, sys_cap_ioctls_limit),  // 534
+   BSDXY(__NR_cap_ioctls_get,   sys_cap_ioctls_get),    // 535
+   BSDX_(__NR_cap_fcntls_limit, sys_cap_fcntls_limit),  // 536
+   BSDXY(__NR_cap_fcntls_get,   sys_cap_fcntls_get),    // 537
+   BSDX_(__NR_bindat,           sys_bindat),            // 538
+   BSDX_(__NR_connectat,        sys_connectat),         // 539
+   BSDX_(__NR_chflagsat,        sys_chflagsat),         // 540
+   BSDXY(__NR_accept4,          sys_accept4),           // 541
+   BSDXY(__NR_pipe2,            sys_pipe2),             // 542
+   BSDX_(__NR_aio_mlock,        sys_aio_mlock),         // 543
+   BSDXY(__NR_procctl,          sys_procctl),           // 544
+
+   // 544 is the highest syscall on FreeBSD 9
+
+#if (FREEBSD_VERS >= FREEBSD_10)
+
+   BSDXY(__NR_ppoll,            sys_ppoll),             // 545
+   BSDX_(__NR_futimens,         sys_futimens),          // 546
+   BSDX_(__NR_utimensat,        sys_utimensat),         // 547
+
+#endif // FREEBSD_VERS >= FREEBSD_10
+
+#if (FREEBSD_VERS >= FREEBSD_11)
+
+   /* 548 is obsolete numa_getaffinity */
+   /* 549 is obsolete numa_setaffinity */
+   BSDX_(__NR_fdatasync,        sys_fdatasync),         // 550
+
+#endif // FREEBSD_VERS >= FREEBSD_11
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+   BSDXY(__NR_fstat,            sys_fstat),             // 551
+   BSDXY(__NR_fstatat,          sys_fstatat),           // 552
+   BSDXY(__NR_fhstat,           sys_fhstat),            // 553
+   BSDXY(__NR_getdirentries,    sys_getdirentries),     // 554
+   BSDXY(__NR_statfs,           sys_statfs),            // 555
+   BSDXY(__NR_fstatfs,          sys_fstatfs),           // 556
+   BSDXY(__NR_getfsstat,        sys_getfsstat),         // 557
+   BSDXY(__NR_fhstatfs,         sys_fhstatfs),          // 558
+   BSDX_(__NR_mknodat,          sys_mknodat),           // 559
+   BSDXY(__NR_kevent,           sys_kevent),            // 560
+   BSDXY(__NR_cpuset_getdomain, sys_cpuset_getdomain),  // 561
+   BSDX_(__NR_cpuset_setdomain, sys_cpuset_setdomain),  // 562
+   BSDXY(__NR_getrandom,        sys_getrandom),         // 563
+   BSDXY(__NR_getfhat,          sys_getfhat),           // 564
+   BSDX_(__NR_fhlink,           sys_fhlink),            // 565
+   BSDX_(__NR_fhlinkat,         sys_fhlinkat),          // 566
+   BSDXY(__NR_fhreadlink,       sys_fhreadlink),        // 567
+#endif // FREEBSD_VERS >= FREEBSD_12
+
+#if (FREEBSD_VERS >= FREEBSD_12_2)
+   // unimpl __NR_funlinkat           568
+   // unimpl __NR_copy_file_range     569
+   BSDXY(__NR___sysctlbyname,   sys___sysctlbyname),    // 570
+   // unimpl __NR_shm_open2           571
+   // unimpl __NR_shm_rename          572
+   // unimpl __NR_sigfastblock        573
+   // unimpl __NR___realpathat        574
+   // unimpl __NR_close_range         575
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_13)
+   // unimpl __NR_rpctls_syscall      576
+#endif
+
+#if (FREEBSD_VERS >= FREEBSD_14)
+   // unimpl __NR___specialfd         577
+   // unimpl __NR_aio_writev          578
+   // unimpl __NR_aio_readv           579
+#endif
+
+   BSDX_(__NR_fake_sigreturn,   sys_fake_sigreturn),    // 1000, fake sigreturn
+
+};
+
+const SyscallTableEntry* ML_(get_freebsd_syscall_entry) ( UInt sysno )
+{
+   const UInt syscall_table_size
+      = sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);
+
+   /* Is it in the contiguous initial section of the table? */
+   if (sysno < syscall_table_size) {
+      const SyscallTableEntry* sys = &ML_(syscall_table)[sysno];
+      if (sys->before == NULL)
+         return NULL; /* no entry */
+      else
+         return sys;
+   }
+
+   /* Can't find a wrapper */
+   return NULL;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/
+
+#endif // defined(VGO_freebsd)
diff --git a/coregrind/m_syswrap/syswrap-x86-freebsd.c b/coregrind/m_syswrap/syswrap-x86-freebsd.c
new file mode 100644 (file)
index 0000000..d65d010
--- /dev/null
@@ -0,0 +1,1517 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Platform-specific syscalls stuff.        syswrap-x86-freebsd.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2008 Nicholas Nethercote
+      njn@valgrind.org
+   Copyright (C) 2018-2021 Paul Floyd
+      pjfloyd@wanadoo.fr
+
+   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, see <http://www.gnu.org/licenses/>.
+
+   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;
+
+      ctst->os_state.stk_id = 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 )
+{
+}
+
+
+/* ---------------------------------------------------------------------
+   PRE/POST wrappers for x86/FreeBSD-specific syscalls
+   ------------------------------------------------------------------ */
+
+#define PRE(name)       DEFN_PRE_TEMPLATE(freebsd, name)
+#define POST(name)      DEFN_POST_TEMPLATE(freebsd, name)
+
+// SYS_sysarch 165
+// int sysarch(int number, void *args);
+PRE(sys_sysarch)
+{
+   ThreadState *tst;
+   Int idx;
+   void **p;
+
+   PRINT("sys_sysarch ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x )", 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);
+
+      if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) {
+         /* 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 ) );
+      } else {
+         // ????
+         SET_STATUS_Failure( VKI_EINVAL );
+      }
+
+      break;
+   case VKI_I386_GET_GSBASE:
+      PRINT("sys_i386_get_gsbase ( %#lx )", ARG2);
+      PRE_MEM_WRITE( "i386_get_gsbase(basep)", ARG2, sizeof(void *) );
+      if (ML_(safe_to_deref)((void**)ARG2, sizeof(void*))) {
+         /* "do" the syscall ourselves; the kernel never sees it */
+         SET_STATUS_from_SysRes( sys_get_thread_area( tid, 2, (void **)ARG2 ) );
+      } else {
+         SET_STATUS_Failure( VKI_EINVAL );
+      }
+      break;
+   case VKI_I386_GET_XFPUSTATE:
+      PRINT("sys_i386_get_xfpustate ( %#lx )", ARG2);
+      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] );
+      break;
+   default:
+      VG_(message) (Vg_UserMsg, "unhandled sysarch cmd %lu", ARG1);
+      VG_(unimplemented) ("unhandled sysarch cmd");
+      break;
+   }
+}
+
+POST(sys_sysarch)
+{
+   switch (ARG1) {
+   case VKI_AMD64_SET_FSBASE:
+      break;
+   case VKI_AMD64_GET_FSBASE:
+      POST_MEM_WRITE( ARG2, sizeof(void *) );
+      break;
+   case VKI_AMD64_GET_XFPUSTATE:
+      POST_MEM_WRITE( ARG2, sizeof(void *) );
+      break;
+   default:
+      break;
+   }
+}
+
+// freebsd6_pread 173
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_pread)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_freebsd6_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6);
+   PRE_REG_READ6(ssize_t, "pread",
+                 unsigned int, fd, char *, buf, vki_size_t, count,
+                 int, pad, unsigned int, off_low, unsigned int, off_high);
+
+   if (!ML_(fd_allowed)(ARG1, "freebsd6_pread", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+   else
+      PRE_MEM_WRITE( "freebsd6_pread(buf)", ARG2, ARG3 );
+}
+
+POST(sys_freebsd6_pread)
+{
+   vg_assert(SUCCESS);
+   POST_MEM_WRITE( ARG2, RES );
+}
+#endif
+
+// freebsd6_pwrite 174
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_pwrite)
+{
+   Bool ok;
+   *flags |= SfMayBlock;
+   PRINT("sys_freebsd6_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG5, ARG6);
+   PRE_REG_READ6(ssize_t, "freebsd6_pwrite",
+                 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, "freebsd6_pwrite", 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( "freebsd6_write(buf)", ARG2, ARG3 );
+}
+#endif
+
+// SYS_freebsd6_mmap 197
+#if (FREEBSD_VERS <= FREEBSD_10)
+/* 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_freebsd6_mmap)
+{
+   SysRes r;
+
+   PRINT("sys_freebsd6_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, pad%" FMT_REGWORD "u, lo0x%" FMT_REGWORD "x hi0x%" FMT_REGWORD "x)",
+         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, MERGE64(ARG7,ARG8) );
+   SET_STATUS_from_SysRes(r);
+}
+#endif
+
+// freebsd6_lseek 199
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_lseek)
+{
+   PRINT("sys_freebsd6_lseek ( %" FMT_REGWORD "u, 0x%" FMT_REGWORD "x, 0x%" FMT_REGWORD "x, %" FMT_REGWORD "u )", 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);
+}
+#endif
+
+// freebsd6_truncate 200
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_truncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %" FMT_REGWORD "u, %" FMT_REGWORD "u )", 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 );
+}
+#endif
+
+// freebsd6_ftruncate 201
+#if (FREEBSD_VERS <= FREEBSD_10)
+PRE(sys_freebsd6_ftruncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_ftruncate ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1,ARG3,ARG4);
+   PRE_REG_READ4(long, "ftruncate", unsigned int, fd, int, pad,
+                 unsigned int, length_low, unsigned int, length_high);
+}
+#endif
+
+// SYS_rfork 251
+// pid_t rfork(int flags);
+PRE(sys_rfork)
+{
+   PRINT("sys_rfork ( %" FMT_REGWORD "x )",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, "fork() not implemented");
+   VG_(unimplemented)("Valgrind does not support rfork() yet.");
+   SET_STATUS_Failure( VKI_ENOSYS );
+#endif
+}
+
+// SYS_preadv  289
+// ssize_t preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+PRE(sys_preadv)
+{
+   Int i;
+   struct vki_iovec * vec;
+   *flags |= SfMayBlock;
+   PRINT("sys_preadv ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
+         FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
+   PRE_REG_READ5(ssize_t, "preadv",
+                 int, fd, const struct iovec *, iovr,
+                 int, iovcnt, vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset));
+   if (!ML_(fd_allowed)(ARG1, "preadv", tid, False)) {
+      SET_STATUS_Failure( VKI_EBADF );
+   } else {
+      if ((Int)ARG3 >= 0)
+         PRE_MEM_READ( "preadv(iov)", ARG2, ARG3 * sizeof(struct vki_iovec) );
+
+      if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
+         vec = (struct vki_iovec *)(Addr)ARG2;
+         for (i = 0; i < (Int)ARG3; i++)
+            PRE_MEM_WRITE( "preadv(iov[...])",
+                           (Addr)vec[i].iov_base, vec[i].iov_len );
+      }
+   }
+}
+
+POST(sys_preadv)
+{
+   vg_assert(SUCCESS);
+   if (RES > 0) {
+      Int i;
+      struct vki_iovec * vec = (struct vki_iovec *)(Addr)ARG2;
+      Int remains = RES;
+
+      /* RES holds the number of bytes read. */
+      for (i = 0; i < (Int)ARG3; i++) {
+         Int nReadThisBuf = vec[i].iov_len;
+         if (nReadThisBuf > remains) nReadThisBuf = remains;
+         POST_MEM_WRITE( (Addr)vec[i].iov_base, nReadThisBuf );
+         remains -= nReadThisBuf;
+         if (remains < 0) VG_(core_panic)("preadv: remains < 0");
+      }
+   }
+}
+
+// SYS_pwritev 290
+// ssize_t pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+PRE(sys_pwritev)
+{
+   Int i;
+   struct vki_iovec * vec;
+   *flags |= SfMayBlock;
+   PRINT("sys_pwritev ( %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %"
+         FMT_REGWORD "d, %llu )", SARG1, ARG2, SARG3, MERGE64(ARG4,ARG5));
+
+   PRE_REG_READ5(ssize_t, "pwritev",
+                 int, fd, const struct iovec *, iov,
+                 int, iovcnt,
+                 vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset));
+   if (!ML_(fd_allowed)(ARG1, "pwritev", tid, False)) {
+      SET_STATUS_Failure( VKI_EBADF );
+   } else {
+      if ((Int)ARG3 >= 0)
+         PRE_MEM_READ( "pwritev(vector)", ARG2, ARG3 * sizeof(struct vki_iovec) );
+      if (ML_(safe_to_deref)((struct vki_iovec *)ARG2, ARG3 * sizeof(struct vki_iovec))) {
+         vec = (struct vki_iovec *)(Addr)ARG2;
+         for (i = 0; i < (Int)ARG3; i++)
+            PRE_MEM_READ( "pwritev(iov[...])",
+                          (Addr)vec[i].iov_base, vec[i].iov_len );
+      }
+   }
+}
+
+// SYS_sendfile   393
+// int sendfile(int fd, int s, off_t offset, size_t nbytes,
+//         struct sf_hdtr *hdtr, off_t *sbytes, int flags);
+PRE(sys_sendfile)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_sendfile ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         SARG1,SARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,SARG8);
+   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);
+
+   if (ARG6 != 0)
+      PRE_MEM_READ("sendfile(hdtr)", ARG6, sizeof(struct vki_sf_hdtr));
+
+   if (ARG7 != 0)
+      PRE_MEM_WRITE( "sendfile(sbytes)", ARG7, sizeof(vki_off_t) );
+}
+
+POST(sys_sendfile)
+{
+   if (ARG7 != 0 ) {
+      POST_MEM_WRITE( ARG7, sizeof( vki_off_t ) );
+   }
+}
+
+// SYS_sigreturn  417
+// int sigreturn(const ucontext_t *scp);
+PRE(sys_sigreturn)
+{
+   PRINT("sys_sigreturn ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "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) );
+}
+
+
+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));
+}
+
+// SYS_getcontext 421
+// int getcontext(ucontext_t *ucp);
+PRE(sys_getcontext)
+{
+   ThreadState* tst;
+   struct vki_ucontext *uc;
+
+   PRINT("sys_getcontext ( %#" FMT_REGWORD "x )", ARG1);
+   PRE_REG_READ1(int, "getcontext",
+                 struct vki_ucontext *, ucp);
+   PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
+   uc = (struct vki_ucontext *)ARG1;
+   if (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext))) {
+      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);
+}
+
+// SYS_setcontext 422
+// int setcontext(const ucontext_t *ucp);
+PRE(sys_setcontext)
+{
+   ThreadState* tst;
+   struct vki_ucontext *uc;
+
+   PRINT("sys_setcontext ( %#" FMT_REGWORD "x )", 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 (!ML_(safe_to_deref)(uc, sizeof(struct vki_ucontext)) || 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;
+   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;
+}
+
+// SYS_swapcontext   423
+// int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);
+PRE(sys_swapcontext)
+{
+   struct vki_ucontext *ucp, *oucp;
+   ThreadState* tst;
+
+   PRINT("sys_swapcontext ( %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )", 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 (!ML_(safe_to_deref)(oucp, sizeof(struct vki_ucontext)) ||
+         !ML_(safe_to_deref)(ucp, sizeof(struct vki_ucontext)) ||
+         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;
+   tst->tmp_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;
+}
+
+// SYS_thr_new 455
+// int thr_new(struct thr_param *param, int param_size);
+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 ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u )",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 */
+   ctst->client_stack_highest_byte = (Addr)tp.stack_base + tp.stack_size;
+   ctst->client_stack_szB = tp.stack_size;
+   ctst->os_state.stk_id = 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);
+}
+
+// SYS_pread 475
+// ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset);
+PRE(sys_pread)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_pread ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", ARG1, ARG2, ARG3, ARG4, ARG5);
+   PRE_REG_READ5(ssize_t, "pread",
+                 unsigned int, fd, char *, buf, vki_size_t, count,
+                 unsigned int, off_low, unsigned int, off_high);
+
+   if (!ML_(fd_allowed)(ARG1, "pread", tid, False))
+      SET_STATUS_Failure( VKI_EBADF );
+   else
+      PRE_MEM_WRITE( "pread(buf)", ARG2, ARG3 );
+}
+
+POST(sys_pread)
+{
+   vg_assert(SUCCESS);
+   POST_MEM_WRITE( ARG2, RES );
+}
+
+// SYS_pwrite  476
+// ssize_t pwrite(int fd, const void *buf, size_t nbytes, off_t offset);
+PRE(sys_pwrite)
+{
+   Bool ok;
+   *flags |= SfMayBlock;
+   PRINT("sys_pwrite ( %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %llu )", ARG1, ARG2, ARG3, MERGE64(ARG4, ARG5));
+   PRE_REG_READ5(ssize_t, "pwrite",
+                 unsigned int, fd, const char *, buf, vki_size_t, count,
+                 vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset));
+   /* 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, "pwrite", 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( "pwrite(buf)", ARG2, ARG3 );
+}
+
+// SYS_mmap 477
+// void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
+PRE(sys_mmap)
+{
+   SysRes r;
+
+   PRINT("sys_mmap ( %#" FMT_REGWORD "x, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu )",
+         ARG1, (UWord)ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6, ARG7) );
+   PRE_REG_READ7(void *, "mmap",
+                 void *, addr, size_t, len, int, prot,  int, flags, int, fd,
+                 vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset));
+
+   r = ML_(generic_PRE_sys_mmap)( tid, ARG1, ARG2, ARG3, ARG4, ARG5, MERGE64(ARG6,ARG7) );
+   SET_STATUS_from_SysRes(r);
+}
+
+// SYS_lseek 478
+// off_t lseek(int fildes, off_t offset, int whence);
+PRE(sys_lseek)
+{
+   PRINT("sys_lseek ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "d )", SARG1,MERGE64(ARG2,ARG3),SARG4);
+   PRE_REG_READ4(long, "lseek",
+                 unsigned int, fd,
+                 vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset),
+                 unsigned int, whence);
+}
+
+// SYS_truncate 479
+// int truncate(const char *path, off_t length);
+PRE(sys_truncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_truncate ( %#" FMT_REGWORD "x(%s), %llu )", ARG1,(char *)ARG1,MERGE64(ARG2,ARG3));
+   PRE_REG_READ3(long, "truncate",
+                 const char *, path,
+                 vki_uint32_t, MERGE64_FIRST(length),
+                 vki_uint32_t, MERGE64_SECOND(length));
+   PRE_MEM_RASCIIZ( "truncate(path)", ARG1 );
+}
+
+// SYS_ftruncate  480
+// int ftruncate(int fd, off_t length);
+PRE(sys_ftruncate)
+{
+   *flags |= SfMayBlock;
+   PRINT("sys_ftruncate ( %" FMT_REGWORD "d, %" FMT_REGWORD "u, %" FMT_REGWORD "u )", SARG1,ARG2,ARG3);
+   PRE_REG_READ3(int, "ftruncate", int, fd,
+                 vki_uint32_t, MERGE64_FIRST(length),
+                 vki_uint32_t, MERGE64_SECOND(length));
+}
+
+// SYS_cpuset_setid  485
+// int cpuset_setid(cpuwhich_t which, id_t id, cpusetid_t setid);
+PRE(sys_cpuset_setid)
+{
+   PRINT("sys_cpuset_setid ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
+         SARG1, MERGE64(ARG2,ARG3), ARG4);
+   PRE_REG_READ4(int, "cpuset_setid", vki_cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 vki_cpusetid_t,setid);
+}
+
+// SYS_cpuset_getid  486
+// int cpuset_getid(cpulevel_t level, cpuwhich_t which, id_t id,
+//                  cpusetid_t *setid);
+PRE(sys_cpuset_getid)
+{
+   PRINT("sys_cpuset_getid ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5);
+   PRE_REG_READ5(int, "cpuset_getid", vki_cpulevel_t, level,
+                 vki_cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 vki_cpusetid_t *,setid);
+   PRE_MEM_WRITE("cpuset_getid(setid)", ARG4, sizeof(vki_cpusetid_t));
+}
+
+POST(sys_cpuset_getid)
+{
+   POST_MEM_WRITE(ARG5, sizeof(vki_cpusetid_t));
+}
+
+// SYS_cpuset_getaffinity  487
+// int cpuset_getaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
+//                        size_t setsize, cpuset_t *mask);
+PRE(sys_cpuset_getaffinity)
+{
+   PRINT("sys_cpuset_getaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %lld, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
+         ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6);
+   PRE_REG_READ6(int, "cpuset_getaffinity",
+                 vki_cpulevel_t, level, vki_cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 size_t, setsize, void *, mask);
+   PRE_MEM_WRITE("cpuset_getaffinity", ARG6, ARG5);
+}
+
+POST(sys_cpuset_getaffinity)
+{
+   vg_assert(SUCCESS);
+   if (RES == 0)
+      POST_MEM_WRITE( ARG6, ARG5 );
+}
+
+// SYS_cpuset_setaffinity  488
+// int cpuset_setaffinity(cpulevel_t level, cpuwhich_t which, id_t id,
+//                        size_t setsize, const cpuset_t *mask);
+PRE(sys_cpuset_setaffinity)
+{
+
+   PRINT("sys_cpuset_setaffinity ( %" FMT_REGWORD "u, %" FMT_REGWORD "u, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x )",
+         ARG1, ARG2, MERGE64(ARG3, ARG4), ARG5, ARG6);
+   PRE_REG_READ6(int, "cpuset_setaffinity",
+                 vki_cpulevel_t, level, vki_cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 size_t, setsize, void *, mask);
+   PRE_MEM_READ("cpuset_setaffinity", ARG6, ARG5);
+}
+
+// SYS_posix_fallocate 530
+// int posix_fallocate(int fd, off_t offset, off_t len);
+PRE(sys_posix_fallocate)
+{
+   PRINT("sys_posix_fallocate ( %" FMT_REGWORD "d, %llu, %llu )",
+         SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4, ARG5));
+   PRE_REG_READ5(long, "posix_fallocate",
+                 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset),
+                 vki_uint32_t, MERGE64_FIRST(len),
+                 vki_uint32_t, MERGE64_SECOND(len));
+}
+
+// SYS_posix_fadvise 531
+// int posix_fadvise(int fd, off_t offset, off_t len, int advice);
+PRE(sys_posix_fadvise)
+{
+   PRINT("sys_posix_fadvise ( %" FMT_REGWORD "d, %llu, %llu, %" FMT_REGWORD "d )",
+         SARG1, MERGE64(ARG2,ARG3), MERGE64(ARG4,ARG5), SARG6);
+   PRE_REG_READ6(long, "posix_fadvise",
+                 int, fd, vki_uint32_t, MERGE64_FIRST(offset),
+                 vki_uint32_t, MERGE64_SECOND(offset),
+                 vki_uint32_t, MERGE64_FIRST(len),
+                 vki_uint32_t, MERGE64_SECOND(len),
+                 int, advice);
+}
+
+// SYS_wait6   532
+// pid_t wait6(idtype_t idtype, id_t id, int *status, int options,
+//             struct __wrusage *wrusage, siginfo_t *infop);
+PRE(sys_wait6)
+{
+   PRINT("sys_wait6 ( %" FMT_REGWORD "d, %llu, %#" FMT_REGWORD "x, %" FMT_REGWORD "d, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1, MERGE64(ARG2, ARG3), ARG4, SARG5, ARG6, ARG7);
+   PRE_REG_READ7(pid_t, "wait6", vki_idtype_t, idtype,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 int *, status, int, options,
+                 struct vki___wrusage *, wrusage, vki_siginfo_t *,infop);
+   PRE_MEM_WRITE("wait6(status)", ARG4, sizeof(int));
+   if (ARG6) {
+      PRE_MEM_WRITE("wait6(wrusage)", ARG6, sizeof(struct vki___wrusage));
+   }
+   if (ARG7) {
+      PRE_MEM_WRITE("wait6(infop)", ARG7, sizeof(vki_siginfo_t));
+   }
+}
+
+POST(sys_wait6)
+{
+   POST_MEM_WRITE(ARG4, sizeof(int));
+   if (ARG6) {
+      POST_MEM_WRITE(ARG6, sizeof(struct vki___wrusage));
+   }
+
+   if (ARG7) {
+      POST_MEM_WRITE(ARG7, sizeof(vki_siginfo_t));
+   }
+}
+
+// the man page is inconsistent for the last argument
+// See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=247386
+// will stick to 'arg' for simplicity
+
+// SYS_procctl 544
+// int procctl(idtype_t idtype, id_t id, int cmd, void *arg);
+PRE(sys_procctl)
+{
+   PRINT("sys_procctl ( %" FMT_REGWORD "d, %llu, %" FMT_REGWORD"d, %#" FMT_REGWORD "x )",
+         SARG1, MERGE64(ARG2, ARG3), SARG4, ARG5);
+   PRE_REG_READ5(int, "procctl", vki_idtype_t, idtype,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 int, cmd, void *, arg);
+   switch (ARG4) {
+   case PROC_ASLR_CTL:
+   case PROC_SPROTECT:
+   case PROC_TRACE_CTL:
+   case PROC_TRAPCAP_CTL:
+   case PROC_PDEATHSIG_CTL:
+   case PROC_STACKGAP_CTL:
+      PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int));
+      break;
+   case PROC_REAP_STATUS:
+      PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_status));
+      break;
+   case PROC_REAP_GETPIDS:
+      PRE_MEM_READ("procctl(arg)", ARG5, sizeof(struct vki_procctl_reaper_pids));
+      break;
+   case PROC_REAP_KILL:
+      /* The first three fields are reads
+       * int rk_sig;
+       * u_int rk_flags;
+       * pid_t rk_subtree;
+       *
+       * The last two fields are writes
+       * u_int rk_killed;
+       * pid_t rk_fpid;
+       *
+       * There is also a pad field
+       */
+      PRE_MEM_READ("procctl(arg)", ARG5, sizeof(int) + sizeof(u_int) + sizeof(vki_pid_t));
+      PRE_MEM_WRITE("procctl(arg)", ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
+      break;
+   case PROC_ASLR_STATUS:
+   case PROC_PDEATHSIG_STATUS:
+   case PROC_STACKGAP_STATUS:
+   case PROC_TRAPCAP_STATUS:
+   case PROC_TRACE_STATUS:
+      PRE_MEM_WRITE("procctl(arg)", ARG5, sizeof(int));
+   case PROC_REAP_ACQUIRE:
+   case PROC_REAP_RELEASE:
+   default:
+      break;
+   }
+}
+
+POST(sys_procctl)
+{
+   switch (ARG4) {
+   case PROC_REAP_KILL:
+      POST_MEM_WRITE(ARG5+offsetof(struct vki_procctl_reaper_kill, rk_killed), sizeof(u_int) + sizeof(vki_pid_t));
+      break;
+   case PROC_ASLR_STATUS:
+   case PROC_PDEATHSIG_STATUS:
+   case PROC_STACKGAP_STATUS:
+   case PROC_TRAPCAP_STATUS:
+   case PROC_TRACE_STATUS:
+      POST_MEM_WRITE(ARG5, sizeof(int));
+   default:
+      break;
+   }
+}
+
+#if (FREEBSD_VERS >= FREEBSD_12)
+
+// SYS_cpuset_getdomain 561
+// int cpuset_getdomain(cpulevel_t level, cpuwhich_t which, id_t id,
+//                      size_t setsize, domainset_t *mask, int *policy);
+PRE(sys_cpuset_getdomain)
+{
+   PRINT("sys_cpuset_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %#" FMT_REGWORD "x )",
+         SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, ARG7);
+   PRE_REG_READ7(int, "cpuset_getdomain",
+                 cpulevel_t, level, cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 size_t, setsize, vki_domainset_t *, mask, int *, policy);
+   // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
+   PRE_MEM_WRITE( "cpuset_getdomain(mask)", ARG6, ARG5 );
+   PRE_MEM_WRITE( "cpuset_getdomain(policy)", ARG7, sizeof(int) );
+}
+
+POST(sys_cpuset_getdomain)
+{
+   POST_MEM_WRITE(ARG5, ARG4 );
+   POST_MEM_WRITE(ARG6, sizeof(int) );
+}
+
+// SYS_cpuset_setdomain 562
+// int cuset_setdomain(cpulevel_t level, cpuwhich_t which, id_t id,
+//                     size_t setsize, const domainset_t *mask, int policy);
+PRE(sys_cpuset_setdomain)
+{
+   PRINT("sys_cpuget_getdomain ( %" FMT_REGWORD "d, %" FMT_REGWORD "d, %llu, %" FMT_REGWORD "u, %#" FMT_REGWORD "x, %" FMT_REGWORD "d )",
+         SARG1, SARG2, MERGE64(ARG3, ARG4), ARG5, ARG6, SARG7);
+   PRE_REG_READ7(int, "cpuset_getdomain",
+                 cpulevel_t, level, cpuwhich_t, which,
+                 vki_uint32_t, MERGE64_FIRST(id),
+                 vki_uint32_t, MERGE64_SECOND(id),
+                 size_t, setsize, vki_domainset_t *, mask, int, policy);
+   // man page says that setsize (ARG4) "is usually provided by calling sizeof(mask)"
+   PRE_MEM_READ( "cpuset_getdomain(mask)", ARG6, ARG5 );
+}
+
+#endif
+
+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 ( %#" FMT_REGWORD "x )", 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_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);
+
+   /* 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). */
+   int eflags = LibVEX_GuestX86_get_eflags(&tst->arch.vex);
+   SET_STATUS_from_SysRes( VG_(mk_SysRes_x86_freebsd)( tst->arch.vex.guest_EAX,
+                           tst->arch.vex.guest_EDX, (eflags & 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 any signals arose as a result of this. */
+   *flags |= SfPollAfter;
+}
+
+#undef PRE
+#undef POST
+
+
+#endif /* defined(VGP_x86_freebsd) */
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                                          ---*/
+/*--------------------------------------------------------------------*/