
/*--------------------------------------------------------------------*/
/*--- Linux-specific syscalls, etc.                syswrap-linux.c ---*/
/*--------------------------------------------------------------------*/

/*
   This file is part of Valgrind, a dynamic binary instrumentation
   framework.

   Copyright (C) 2000-2008 Nicholas Nethercote
      njn@valgrind.org

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.

   The GNU General Public License is contained in the file COPYING.
*/

#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_syscall.h"
#include "pub_core_syswrap.h"

#include "priv_types_n_macros.h"
#include "priv_syswrap-generic.h"
#include "priv_syswrap-freebsd.h"


// Run a thread from beginning to end and return the thread's
// scheduler-return-code.
static VgSchedReturnCode thread_wrapper(Word /*ThreadId*/ tidW)
{
   VgSchedReturnCode ret;
   ThreadId     tid = (ThreadId)tidW;
   ThreadState* tst = VG_(get_ThreadState)(tid);

   VG_(debugLog)(1, "syswrap-freebsd", 
                    "thread_wrapper(tid=%lld): entry\n", 
                    (ULong)tidW);

   vg_assert(tst->status == VgTs_Init);

   /* make sure we get the CPU lock before doing anything significant */
   VG_(acquire_BigLock)(tid, "thread_wrapper(starting new thread)");

   if (0)
      VG_(printf)("thread tid %d started: stack = %p\n",
		  tid, &tid);

   VG_TRACK(pre_thread_first_insn, tid);

   tst->os_state.lwpid = VG_(gettid)();
   tst->os_state.threadgroup = VG_(getpid)();

   /* Thread created with all signals blocked; scheduler will set the
      appropriate mask */

   ret = VG_(scheduler)(tid);

   vg_assert(VG_(is_exiting)(tid));
   
   vg_assert(tst->status == VgTs_Runnable);
   vg_assert(VG_(is_running_thread)(tid));

   VG_(debugLog)(1, "syswrap-freebsd", 
                    "thread_wrapper(tid=%lld): exit\n", 
                    (ULong)tidW);

   /* Return to caller, still holding the lock. */
   return ret;
}


/* ---------------------------------------------------------------------
   clone-related stuff
   ------------------------------------------------------------------ */

/* Run a thread all the way to the end, then do appropriate exit actions
   (this is the last-one-out-turn-off-the-lights bit).  */
static void run_a_thread_NORETURN ( Word tidW )
{
   ThreadId          tid = (ThreadId)tidW;
   VgSchedReturnCode src;
   Int               c;

   VG_(debugLog)(1, "syswrap-freebsd", 
                    "run_a_thread_NORETURN(tid=%lld): pre-thread_wrapper\n",
                    (ULong)tidW);

   /* Run the thread all the way through. */
   src = thread_wrapper(tid);  

   VG_(debugLog)(1, "syswrap-freebsd", 
                    "run_a_thread_NORETURN(tid=%lld): post-thread_wrapper\n",
                    (ULong)tidW);

   c = VG_(count_living_threads)();
   vg_assert(c >= 1); /* stay sane */

   // Tell the tool this thread is exiting
   VG_TRACK( pre_thread_ll_exit, tid );

   if (c == 1) {

      VG_(debugLog)(1, "syswrap-freebsd", 
                       "run_a_thread_NORETURN(tid=%lld): "
                          "last one standing\n",
                          (ULong)tidW);

      /* We are the last one standing.  Keep hold of the lock and
         carry on to show final tool results, then exit the entire system. 
         Use the continuation pointer set at startup in m_main. */
      ( * VG_(address_of_m_main_shutdown_actions_NORETURN) ) (tid, src);

   } else {

      ThreadState *tst;

      VG_(debugLog)(1, "syswrap-freebsd", 
                       "run_a_thread_NORETURN(tid=%lld): "
                          "not last one standing\n",
                          (ULong)tidW);

      /* OK, thread is dead, but others still exist.  Just exit. */
      tst = VG_(get_ThreadState)(tid);

      /* This releases the run lock */
      VG_(exit_thread)(tid);
      vg_assert(tst->status == VgTs_Zombie);

      /* We have to use this sequence to terminate the thread to
         prevent a subtle race.  If VG_(exit_thread)() had left the
         ThreadState as Empty, then it could have been reallocated,
         reusing the stack while we're doing these last cleanups.
         Instead, VG_(exit_thread) leaves it as Zombie to prevent
         reallocation.  We need to make sure we don't touch the stack
         between marking it Empty and exiting.  Hence the
         assembler. */
#if defined(VGP_x86_freebsd)	/* FreeBSD has args on the stack */
      asm volatile (
         "movl	%1, %0\n"	/* set tst->status = VgTs_Empty */
         "movl	%2, %%eax\n"    /* set %eax = __NR_hr_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));
#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));
#else
# error Unknown platform
#endif

      VG_(core_panic)("Thread exit failed?\n");
   }

   /*NOTREACHED*/
   vg_assert(0);
}

Word ML_(start_thread_NORETURN) ( void* arg )
{
   ThreadState* tst = (ThreadState*)arg;
   ThreadId     tid = tst->tid;

   run_a_thread_NORETURN ( (Word)tid );
   /*NOTREACHED*/
   vg_assert(0);
}

/* Allocate a stack for this thread, if it doesn't already have one.
   They're allocated lazily, and never freed.  Returns the initial stack
   pointer value to use, or 0 if allocation failed. */
Addr ML_(allocstack)(ThreadId tid)
{
   ThreadState* tst = VG_(get_ThreadState)(tid);
   VgStack*     stack;
   Addr         initial_SP;

   /* Either the stack_base and stack_init_SP are both zero (in which
      case a stack hasn't been allocated) or they are both non-zero,
      in which case it has. */

   if (tst->os_state.valgrind_stack_base == 0)
      vg_assert(tst->os_state.valgrind_stack_init_SP == 0);

   if (tst->os_state.valgrind_stack_base != 0)
      vg_assert(tst->os_state.valgrind_stack_init_SP != 0);

   /* If no stack is present, allocate one. */

   if (tst->os_state.valgrind_stack_base == 0) {
      stack = VG_(am_alloc_VgStack)( &initial_SP );
      if (stack) {
         tst->os_state.valgrind_stack_base    = (Addr)stack;
         tst->os_state.valgrind_stack_init_SP = initial_SP;
      }
   }

   if (0)
      VG_(printf)( "stack for tid %d at %p; init_SP=%p\n",
                   tid, 
                   (void*)tst->os_state.valgrind_stack_base, 
                   (void*)tst->os_state.valgrind_stack_init_SP );
                  
   return tst->os_state.valgrind_stack_init_SP;
}

/* Allocate a stack for the main thread, and run it all the way to the
   end.  Although we already have a working VgStack
   (VG_(interim_stack)) it's better to allocate a new one, so that
   overflow detection works uniformly for all threads.
*/
void VG_(main_thread_wrapper_NORETURN)(ThreadId tid)
{
   Addr sp;
   VG_(debugLog)(1, "syswrap-freebsd", 
                    "entering VG_(main_thread_wrapper_NORETURN)\n");

   sp = ML_(allocstack)(tid);

/* QQQ keep for amd64 redzone stuff */
#if defined(VGP_ppc32_linux)
   /* make a stack frame */
   sp -= 16;
   sp &= ~0xF;
   *(UWord *)sp = 0;
#elif defined(VGP_ppc64_linux)
   /* make a stack frame */
   sp -= 112;
   sp &= ~((Addr)0xF);
   *(UWord *)sp = 0;
#endif

   /* If we can't even allocate the first thread's stack, we're hosed.
      Give up. */
   vg_assert2(sp != 0, "Cannot allocate main thread's stack.");

   /* shouldn't be any other threads around yet */
   vg_assert( VG_(count_living_threads)() == 1 );

   ML_(call_on_new_stack_0_1)( 
      (Addr)sp,               /* stack */
      0,                      /* bogus return address */
      run_a_thread_NORETURN,  /* fn to call */
      (Word)tid               /* arg to give it */
   );

   /*NOTREACHED*/
   vg_assert(0);
}


/* Do a fork() */
SysRes ML_(do_fork) ( ThreadId tid )
{
   vki_sigset_t fork_saved_mask;
   vki_sigset_t mask;
   SysRes       res;

   /* Block all signals during fork, so that we can fix things up in
      the child without being interrupted. */
   VG_(sigfillset)(&mask);
   VG_(sigprocmask)(VKI_SIG_SETMASK, &mask, &fork_saved_mask);

   VG_(do_atfork_pre)(tid);

   res = VG_(do_syscall0)( __NR_fork );

   if (!sr_isError(res) && sr_Res(res) == 0) {
      /* child */
      VG_(do_atfork_child)(tid);

      /* restore signal mask */
      VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);

   } 
   else 
   if (!sr_isError(res) && sr_Res(res) == 0) {
      /* parent */
      VG_(do_atfork_parent)(tid);

      if (VG_(clo_trace_syscalls))
	  VG_(printf)("   clone(fork): process %d created child %ld\n",
                      VG_(getpid)(), sr_Res(res));

      /* restore signal mask */
      VG_(sigprocmask)(VKI_SIG_SETMASK, &fork_saved_mask, NULL);
   }

   return res;
}


/* ---------------------------------------------------------------------
   PRE/POST wrappers for arch-generic, Linux-specific syscalls
   ------------------------------------------------------------------ */

// Nb: See the comment above the generic PRE/POST wrappers in
// m_syswrap/syswrap-generic.c for notes about how they work.

#define PRE(name)       DEFN_PRE_TEMPLATE(freebsd, name)
#define POST(name)      DEFN_POST_TEMPLATE(freebsd, name)

// Combine two 32-bit values into a 64-bit value
#define LOHI64(lo,hi)   ( (lo) | ((ULong)(hi) << 32) )

PRE(sys_fork)
{
   PRINT("sys_fork ()");
   PRE_REG_READ0(int, "fork");

   SET_STATUS_from_SysRes( ML_(do_fork)(tid) );
   if (SUCCESS) {
      /* Thread creation was successful; let the child have the chance
         to run */
      *flags |= SfYieldAfter;
   }
}

PRE(sys_vfork)
{
   PRINT("sys_vfork ()");
   PRE_REG_READ0(int, "vfork");

   /* Pretend vfork == fork. Not true, but will have to do. */
   SET_STATUS_from_SysRes( ML_(do_fork)(tid) );
   if (SUCCESS) {
      /* Thread creation was successful; let the child have the chance
         to run */
      *flags |= SfYieldAfter;
   }
}

PRE(sys_socket)
{
   PRINT("sys_socket ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "socket", int, domain, int, type, int, protocol);
}
POST(sys_socket)
{
   SysRes r;
   vg_assert(SUCCESS);
   r = ML_(generic_POST_sys_socket)(tid, VG_(mk_SysRes_Success)(RES));
   SET_STATUS_from_SysRes(r);
}

PRE(sys_setsockopt)
{
   PRINT("sys_setsockopt ( %ld, %ld, %ld, %#lx, %ld )",ARG1,ARG2,ARG3,ARG4,ARG5);
   PRE_REG_READ5(long, "setsockopt",
                 int, s, int, level, int, optname,
                 const void *, optval, int, optlen);
   ML_(generic_PRE_sys_setsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
}

PRE(sys_getsockopt)
{
   PRINT("sys_getsockopt ( %ld, %ld, %ld, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5);
   PRE_REG_READ5(long, "getsockopt",
                 int, s, int, level, int, optname,
                 void *, optval, int, *optlen);
// XXX: ML_(generic_PRE_sys_getsockopt)(tid, ARG1,ARG2,ARG3,ARG4,ARG5);
}
POST(sys_getsockopt)
{
   vg_assert(SUCCESS);
//   ML_(generic_POST_sys_getsockopt)(tid, VG_(mk_SysRes_Success)(RES),
//XXX:                                         ARG1,ARG2,ARG3,ARG4,ARG5);
}

PRE(sys_connect)
{
   *flags |= SfMayBlock;
   PRINT("sys_connect ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "connect",
                 int, sockfd, struct sockaddr *, serv_addr, int, addrlen);
   ML_(generic_PRE_sys_connect)(tid, ARG1,ARG2,ARG3);
}

PRE(sys_accept)
{
   *flags |= SfMayBlock;
   PRINT("sys_accept ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "accept",
                 int, s, struct sockaddr *, addr, int, *addrlen);
   ML_(generic_PRE_sys_accept)(tid, ARG1,ARG2,ARG3);
}
POST(sys_accept)
{
   SysRes r;
   vg_assert(SUCCESS);
   r = ML_(generic_POST_sys_accept)(tid, VG_(mk_SysRes_Success)(RES),
                                         ARG1,ARG2,ARG3);
   SET_STATUS_from_SysRes(r);
}

PRE(sys_sendto)
{
   *flags |= SfMayBlock;
   PRINT("sys_sendto ( %ld, %#lx, %ld, %lu, %#lx, %ld )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
   PRE_REG_READ6(long, "sendto",
                 int, s, const void *, msg, int, len, 
                 unsigned int, flags, 
                 const struct sockaddr *, to, int, tolen);
   ML_(generic_PRE_sys_sendto)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
}

PRE(sys_recvfrom)
{
   *flags |= SfMayBlock;
   PRINT("sys_recvfrom ( %ld, %#lx, %ld, %lu, %#lx, %#lx )",ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
   PRE_REG_READ6(long, "recvfrom",
                 int, s, void *, buf, int, len, unsigned int, flags,
                 struct sockaddr *, from, int *, fromlen);
   ML_(generic_PRE_sys_recvfrom)(tid, ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
}
POST(sys_recvfrom)
{
   vg_assert(SUCCESS);
   ML_(generic_POST_sys_recvfrom)(tid, VG_(mk_SysRes_Success)(RES),
                                       ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
}

PRE(sys_sendmsg)
{
   *flags |= SfMayBlock;
   PRINT("sys_sendmsg ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sendmsg",
                 int, s, const struct msghdr *, msg, int, flags);
   ML_(generic_PRE_sys_sendmsg)(tid, ARG1,ARG2);
}

PRE(sys_recvmsg)
{
   *flags |= SfMayBlock;
   PRINT("sys_recvmsg ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "recvmsg", int, s, struct msghdr *, msg, int, flags);
   ML_(generic_PRE_sys_recvmsg)(tid, ARG1,ARG2);
}
POST(sys_recvmsg)
{
   ML_(generic_POST_sys_recvmsg)(tid, ARG1,ARG2);
}

PRE(sys_shutdown)
{
   *flags |= SfMayBlock;
   PRINT("sys_shutdown ( %ld, %ld )",ARG1,ARG2);
   PRE_REG_READ2(int, "shutdown", int, s, int, how);
}

PRE(sys_bind)
{
   PRINT("sys_bind ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "bind",
                 int, sockfd, struct sockaddr *, my_addr, int, addrlen);
   ML_(generic_PRE_sys_bind)(tid, ARG1,ARG2,ARG3);
}

PRE(sys_listen)
{
   PRINT("sys_listen ( %ld, %ld )",ARG1,ARG2);
   PRE_REG_READ2(long, "listen", int, s, int, backlog);
}

PRE(sys_getsockname)
{
   PRINT("sys_getsockname ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getsockname",
                 int, s, struct sockaddr *, name, int *, namelen);
   ML_(generic_PRE_sys_getsockname)(tid, ARG1,ARG2,ARG3);
}
POST(sys_getsockname)
{
   vg_assert(SUCCESS);
   ML_(generic_POST_sys_getsockname)(tid, VG_(mk_SysRes_Success)(RES),
                                          ARG1,ARG2,ARG3);
}

PRE(sys_getpeername)
{
   PRINT("sys_getpeername ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getpeername",
                 int, s, struct sockaddr *, name, int *, namelen);
   ML_(generic_PRE_sys_getpeername)(tid, ARG1,ARG2,ARG3);
}
POST(sys_getpeername)
{
   vg_assert(SUCCESS);
   ML_(generic_POST_sys_getpeername)(tid, VG_(mk_SysRes_Success)(RES),
                                          ARG1,ARG2,ARG3);
}

PRE(sys_socketpair)
{
   PRINT("sys_socketpair ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
   PRE_REG_READ4(long, "socketpair",
                 int, d, int, type, int, protocol, int *, sv);
   ML_(generic_PRE_sys_socketpair)(tid, ARG1,ARG2,ARG3,ARG4);
}
POST(sys_socketpair)
{
   vg_assert(SUCCESS);
   ML_(generic_POST_sys_socketpair)(tid, VG_(mk_SysRes_Success)(RES),
                                         ARG1,ARG2,ARG3,ARG4);
}

/* ---------------------------------------------------------------------
   *mount wrappers
   ------------------------------------------------------------------ */

PRE(sys_mount)
{
   // Nb: depending on 'flags', the 'type' and 'data' args may be ignored.
   // We are conservative and check everything, except the memory pointed to
   // by 'data'.
   *flags |= SfMayBlock;
   PRINT( "sys_mount( %#lx, %#lx, %ld, %#lx )" ,ARG1,ARG2,ARG3,ARG4);
   PRE_REG_READ4(long, "mount",
                 char *, type, char *, path, int, flags,
                 void *, data);
   PRE_MEM_RASCIIZ( "mount(type)", ARG1);
   PRE_MEM_RASCIIZ( "mount(path)", ARG2);
}

PRE(sys_unmount)
{
   PRINT("sys_umount( %#lx, %ld )", ARG1, ARG2);
   PRE_REG_READ2(long, "unmount", char *, path, int, flags);
   PRE_MEM_RASCIIZ( "unmount(path)", ARG1);
}

/* ---------------------------------------------------------------------
   16- and 32-bit uid/gid wrappers
   ------------------------------------------------------------------ */

#if 0
PRE(sys_setfsuid)
{
   PRINT("sys_setfsuid ( %ld )", ARG1);
   PRE_REG_READ1(long, "setfsuid", vki_uid_t, uid);
}

PRE(sys_setfsgid)
{
   PRINT("sys_setfsgid ( %ld )", ARG1);
   PRE_REG_READ1(long, "setfsgid", vki_gid_t, gid);
}
#endif

PRE(sys_setresuid)
{
   PRINT("sys_setresuid ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
   PRE_REG_READ3(long, "setresuid",
                 vki_uid_t, ruid, vki_uid_t, euid, vki_uid_t, suid);
}

PRE(sys_getresuid)
{
   PRINT("sys_getresuid ( %#lx, %#lx, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getresuid", 
                 vki_uid_t *, ruid, vki_uid_t *, euid, vki_uid_t *, suid);
   PRE_MEM_WRITE( "getresuid(ruid)", ARG1, sizeof(vki_uid_t) );
   PRE_MEM_WRITE( "getresuid(euid)", ARG2, sizeof(vki_uid_t) );
   PRE_MEM_WRITE( "getresuid(suid)", ARG3, sizeof(vki_uid_t) );
}

POST(sys_getresuid)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG1, sizeof(vki_uid_t) );
      POST_MEM_WRITE( ARG2, sizeof(vki_uid_t) );
      POST_MEM_WRITE( ARG3, sizeof(vki_uid_t) );
   }
}

PRE(sys_setresgid)
{
   PRINT("sys_setresgid ( %ld, %ld, %ld )", ARG1, ARG2, ARG3);
   PRE_REG_READ3(long, "setresgid",
                 vki_gid_t, rgid, vki_gid_t, egid, vki_gid_t, sgid);
}

PRE(sys_getresgid)
{
   PRINT("sys_getresgid ( %#lx, %#lx, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getresgid", 
                 vki_gid_t *, rgid, vki_gid_t *, egid, vki_gid_t *, sgid);
   PRE_MEM_WRITE( "getresgid(rgid)", ARG1, sizeof(vki_gid_t) );
   PRE_MEM_WRITE( "getresgid(egid)", ARG2, sizeof(vki_gid_t) );
   PRE_MEM_WRITE( "getresgid(sgid)", ARG3, sizeof(vki_gid_t) );
}

POST(sys_getresgid)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG1, sizeof(vki_gid_t) );
      POST_MEM_WRITE( ARG2, sizeof(vki_gid_t) );
      POST_MEM_WRITE( ARG3, sizeof(vki_gid_t) );
   }
}

/* ---------------------------------------------------------------------
   miscellaneous wrappers
   ------------------------------------------------------------------ */

#if 0
PRE(sys_exit_group)
{
   ThreadId     t;
   ThreadState* tst;

   PRINT("exit_group( %ld )", ARG1);
   PRE_REG_READ1(void, "exit_group", int, exit_code);

   tst = VG_(get_ThreadState)(tid);

   /* A little complex; find all the threads with the same threadgroup
      as this one (including this one), and mark them to exit */
   for (t = 1; t < VG_N_THREADS; t++) {
      if ( /* not alive */
           VG_(threads)[t].status == VgTs_Empty 
           ||
	   /* not our group */
           VG_(threads)[t].os_state.threadgroup != tst->os_state.threadgroup
         )
         continue;

      VG_(threads)[t].exitreason = VgSrc_ExitSyscall;
      VG_(threads)[t].os_state.exitcode = ARG1;

      if (t != tid)
	 VG_(get_thread_out_of_syscall)(t);	/* unblock it, if blocked */
   }

   /* We have to claim the syscall already succeeded. */
   SET_STATUS_Success(0);
}
#endif

/* On FreeBSD, if any thread calls exit(2), then they are all shut down, pretty
 * much like linux's exit_group().
 */
PRE(sys_exit)
{
   ThreadId     t;
   ThreadState* tst;

   PRINT("exit( %ld )", ARG1);
   PRE_REG_READ1(void, "exit", int, status);
   tst = VG_(get_ThreadState)(tid);

   /* Mark all threads (including this one) to exit. */
   for (t = 1; t < VG_N_THREADS; t++) {
      if ( /* not alive */ VG_(threads)[t].status == VgTs_Empty )
         continue;

      VG_(threads)[t].exitreason = VgSrc_ExitThread;
      VG_(threads)[t].os_state.exitcode = ARG1;

      if (t != tid)
	 VG_(get_thread_out_of_syscall)(t);	/* unblock it, if blocked */
   }

   /* We have to claim the syscall already succeeded. */
   SET_STATUS_Success(0);
}


PRE(sys_getlogin)
{
   PRINT("sys_getlogin ( %#lx, %ld )",ARG1,ARG2);
   PRE_REG_READ2(long, "getlogin",
                 char *, buf, int, len);
   PRE_MEM_WRITE( "getlogin(buf, len)", ARG1, ARG2 );
}
POST(sys_getlogin)
{
   if (ARG1 != 0) {
      POST_MEM_WRITE( ARG1, ARG2 );
   }
}
PRE(sys_setlogin)
{
   PRINT("sys_setlogin ( %#lx )",ARG1);
   PRE_REG_READ1(long, "setlogin", char *, buf);
   PRE_MEM_RASCIIZ( "setlogin(buf)", ARG1 );
}
PRE(sys_mkfifo)
{
   PRINT("sys_mkfifo ( %#lx(%s), 0x%lx, 0x%lx )", ARG1, (char *)ARG1, ARG2, ARG3 );
   PRE_REG_READ2(long, "mkfifo", const char *, pathname, int, mode);
   PRE_MEM_RASCIIZ( "mkfifo(pathname)", ARG1 );
}

/* int quotactl(const char *path, int cmd, int id, void *addr); */

PRE(sys_quotactl)
{
   PRINT("sys_quotactl (%#lx, %ld, %ld, %#lx )", ARG1,ARG2,ARG3, ARG4);
   PRE_REG_READ4(long, "quotactl",
                 const char *, path, int, cmd, int, id,
                 void *, addr);
   PRE_MEM_RASCIIZ( "quotactl(path)", ARG1 );
}

/* int getdomainname(char *domainname, int len); */
PRE(sys_getdomainname)
{
   PRINT("sys_getdomainname ( %#lx, %ld )",ARG1,ARG2);
   PRE_REG_READ2(long, "getdomainname",
                 char *, buf, int, len);
   PRE_MEM_WRITE( "getdomainname(buf, len)", ARG1, ARG2 );
}
POST(sys_getdomainname)
{
   if (ARG1 != 0) {
      POST_MEM_WRITE( ARG1, ARG2 );
   }
}
/* int setdomainname(char *domainname, int len); */
PRE(sys_setdomainname)
{
   PRINT("sys_setdomainname ( %#lx )",ARG1);
   PRE_REG_READ1(long, "setdomainname", char *, buf);
   PRE_MEM_RASCIIZ( "setdomainname(buf)", ARG1 );
}

PRE(sys_uname)
{
   PRINT("sys_uname ( %#lx )", ARG1);
   PRE_REG_READ1(long, "uname", struct utsname *, buf);
   PRE_MEM_WRITE( "uname(buf)", ARG1, sizeof(struct vki_utsname) );
}

POST(sys_uname)
{
   if (ARG1 != 0) {
      POST_MEM_WRITE( ARG1, sizeof(struct vki_utsname) );
   }
}

PRE(sys_lstat)
{
   PRINT("sys_lstat ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "lstat", char *, file_name, struct stat *, buf);
   PRE_MEM_RASCIIZ( "lstat(file_name)", ARG1 );
   PRE_MEM_WRITE( "lstat(buf)", ARG2, sizeof(struct vki_stat) );
}

POST(sys_lstat)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
   }
}

PRE(sys_stat)
{
   PRINT("sys_stat ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "stat", char *, file_name, struct stat *, buf);
   PRE_MEM_RASCIIZ( "stat(file_name)", ARG1 );
   PRE_MEM_WRITE( "stat(buf)", ARG2, sizeof(struct vki_stat) );
}

POST(sys_stat)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
}

PRE(sys_fstat)
{
   PRINT("sys_fstat ( %ld, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "fstat", unsigned long, fd, struct stat *, buf);
   PRE_MEM_WRITE( "fstat(buf)", ARG2, sizeof(struct vki_stat) );
}

POST(sys_fstat)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
}

PRE(sys_pathconf)
{
   PRINT("sys_pathconf ( %#lx(%s), %ld )",ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "pathconf", char *, file_name, int, name);
   PRE_MEM_RASCIIZ( "pathconf(file_name)", ARG1 );
}

PRE(sys_fpathconf)
{
   PRINT("sys_fpathconf ( %ld, %ld )",ARG1,ARG2);
   PRE_REG_READ2(long, "fpathconf", int, fd, int, name);
}

PRE(sys_lchmod)
{
   PRINT("sys_lchmod ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "lchmod", const char *, path, vki_mode_t, mode);
   PRE_MEM_RASCIIZ( "lchmod(path)", ARG1 );
}

PRE(sys_issetugid)
{
   PRINT("sys_issetugid ()");
   PRE_REG_READ0(long, "issetugid");
}

PRE(sys_revoke)
{
   PRINT("sys_vhangup ( )");
   PRE_REG_READ0(long, "vhangup");
}
PRE(sys_undelete)
{
   *flags |= SfMayBlock;
   PRINT("sys_undelete ( %#lx(%s) )", ARG1,(char *)ARG1);
   PRE_REG_READ1(long, "undelete", const char *, pathname);
   PRE_MEM_RASCIIZ( "undelete(pathname)", ARG1 );
}
PRE(sys_yield)
{
   *flags |= SfMayBlock;
   PRINT("yield()");
   PRE_REG_READ0(long, "yield");
}

PRE(sys_sched_yield)
{
   PRINT("sched_yield()");
}

#if 0
PRE(sys_sysinfo)
{
   PRINT("sys_sysinfo ( %#lx )",ARG1);
   PRE_REG_READ1(long, "sysinfo", struct sysinfo *, info);
   PRE_MEM_WRITE( "sysinfo(info)", ARG1, sizeof(struct vki_sysinfo) );
}

POST(sys_sysinfo)
{
   POST_MEM_WRITE( ARG1, sizeof(struct vki_sysinfo) );
}
#endif

/* int __sysctl(int *name, u_int namelen, void *old, size_t *oldlenp, void *new, size_t newlen); */
/*               ARG1        ARG2          ARG3         ARG4           ARG5        ARG6 */

PRE(sys___sysctl)
{
   PRINT("sys_sysctl ( %#lx, %ld, %#lx, %#lx, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6 );
   PRE_REG_READ6(long, "__sysctl", int *, name, unsigned int, namelen, void *, old,
		 vki_size_t *, oldlenp, void *, new, vki_size_t, newlen);
   PRE_MEM_READ("sysctl(name)", ARG1, ARG2 * sizeof(int));
   if (ARG5 != (UWord)NULL)
      PRE_MEM_READ("sysctl(new)", (Addr)ARG5, ARG6);
   if (ARG4 != (UWord)NULL) {
      if (ARG3 != (UWord)NULL) {
         PRE_MEM_READ("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
         PRE_MEM_WRITE("sysctl(oldval)", (Addr)ARG3, *(vki_size_t *)ARG4);
      }
      PRE_MEM_WRITE("sysctl(oldlenp)", (Addr)ARG4, sizeof(vki_size_t));
   }
}
POST(sys___sysctl)
{
   if (ARG4 != (UWord)NULL) {
      POST_MEM_WRITE((Addr)ARG4, sizeof(vki_size_t));
      if (ARG3 != (UWord)NULL)
         POST_MEM_WRITE((Addr)ARG3, *(vki_size_t *)ARG4);
   }
}

PRE(sys_sendfile)
{
   *flags |= SfMayBlock;
#if defined(VGP_x86_freebsd)
   PRINT("sys_sendfile ( %ld, %ld, %llu, %ld, %#lx, %#lx, %lu )", ARG1,ARG2,LOHI64(ARG3,ARG4),ARG5,ARG6,ARG7,ARG8);
#elif defined(VGP_amd64_freebsd)
   PRINT("sys_sendfile ( %ld, %ld, %lu, %ld, %#lx, %#lx, %lu )", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6,ARG7);
#else
#  error Unknown platform
#endif
   PRE_REG_READ7(ssize_t, "sendfile",
                 int, fd, int, s, unsigned int, offset_low,
		 unsigned int, offset_high,
                 void *, hdtr, vki_off_t *, sbytes, int, flags);
   if (ARG3 != 0)
      PRE_MEM_WRITE( "sendfile(offset)", ARG3, sizeof(vki_off_t) );
}
POST(sys_sendfile)
{
   if (ARG3 != 0 ) {
      POST_MEM_WRITE( ARG3, sizeof( vki_off_t ) );
   }
}

/* int getdirentries(int fd, char *buf, u_int count, long *basep); */
PRE(sys_getdirentries)
{
   *flags |= SfMayBlock;
   PRINT("sys_getdents ( %ld, %#lx, %ld )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getdirentries",
                 unsigned int, fd, struct dirent *, dirp,
                 unsigned int, count);
   PRE_MEM_WRITE( "getdirentries(dirp)", ARG2, ARG3 );
}

POST(sys_getdirentries)
{
   vg_assert(SUCCESS);
   if (RES > 0) {
      POST_MEM_WRITE( ARG2, RES );
      if ( ARG4 != 0 )
	 POST_MEM_WRITE( ARG4, sizeof (long));
   }
}

PRE(sys_seteuid)
{
   PRINT("sys_seteuid ( %ld )", ARG1);
   PRE_REG_READ1(long, "seteuid", vki_uid_t, uid);
}

PRE(sys_setegid)
{
   PRINT("sys_setegid ( %ld )", ARG1);
   PRE_REG_READ1(long, "setegid", vki_gid_t, gid);
}

PRE(sys_lutimes)
{
   PRINT("sys_lutimes ( %#lx(%s), %#lx )", ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "lutimes", char *, filename, struct timeval *, tvp);
   PRE_MEM_RASCIIZ( "lutimes(filename)", ARG1 );
   if (ARG2 != 0)
      PRE_MEM_READ( "lutimes(tvp)", ARG2, sizeof(struct vki_timeval) );
}

PRE(sys_futimes)
{
   PRINT("sys_lutimes ( %ld, %#lx )", ARG1,ARG2);
   PRE_REG_READ2(long, "futimes", int, fd, struct timeval *, tvp);
   if (ARG2 != 0)
      PRE_MEM_READ( "futimes(tvp)", ARG2, sizeof(struct vki_timeval) );
}

PRE(sys_utrace)
{
   PRINT("sys_utrace ( %#lx, %lu )", ARG1, ARG2);
   PRE_REG_READ2(long, "utrace", const void *, buf, vki_size_t, len);
   PRE_MEM_READ( "utrace(buf,len)", ARG2, ARG3 );
}

PRE(sys_getdtablesize)
{
   PRINT("sys_getdtablesize ( )");
   PRE_REG_READ0(long, "getdtablesize");
}

PRE(sys_kqueue)
{
   PRINT("sys_kqueue ()");
}
POST(sys_kqueue)
{
   if (!ML_(fd_allowed)(RES, "kqueue", tid, True)) {
      VG_(close)(RES);
      SET_STATUS_Failure( VKI_EMFILE );
   } else {
      if (VG_(clo_track_fds)) {
         ML_(record_fd_open_nameless)(tid, RES);
      }
   }
}

PRE(sys_kevent)
{
   /* struct kevent {
        uintptr_t ident;  -- identifier for this event
	short     filter; -- filter for event
	u_short   flags;  -- action flags for kqueue
	u_int     fflags; -- filter flag value
	intptr_t  data;   -- filter data value
	void      *udata; -- opaque user data identifier
      };
      int kevent(int kq, const struct kevent *changelist, int nchanges,
                 struct kevent *eventlist, int nevents,
                 const struct timespec *timeout);
   */
   *flags |= SfMayBlock;
   PRINT("sys_kevent ( %ld, %#lx, %ld, %#lx, %ld, %#lx )\n", ARG1,ARG2,ARG3,ARG4,ARG5,ARG6);
   PRE_REG_READ6(long, "kevent",
                 int, fd, struct vki_kevent *, newev, int, num_newev,
		 struct vki_kevent *, ret_ev, int, num_retev,
		 struct timespec *, timeout);
   if (ARG2 != 0 && ARG3 != 0)
      PRE_MEM_READ( "kevent(changeevent)", ARG2, sizeof(struct vki_kevent)*ARG3 );
   if (ARG4 != 0 && ARG5 != 0)
      PRE_MEM_WRITE( "kevent(events)", ARG4, sizeof(struct vki_kevent)*ARG5);
   if (ARG6 != 0)
      PRE_MEM_READ( "kevent(timeout)",
                    ARG6, sizeof(struct vki_timespec));
}

POST(sys_kevent)
{
   vg_assert(SUCCESS);
   if (RES > 0) {
      if (ARG4 != 0)
         POST_MEM_WRITE( ARG4, sizeof(struct vki_kevent)*RES) ;
   }
}

PRE(sys___getcwd)
{
   PRINT("sys___getcwd ( %#lx, %lu )", ARG1,ARG2);
   PRE_REG_READ2(long, "__getcwd", char *, buf, unsigned int, size);
   PRE_MEM_WRITE( "__getcwd(buf)", ARG1, ARG2 );
}

POST(sys___getcwd)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      // QQQ it is unclear if this is legal or not, but the
      // QQQ kernel just wrote it there...
      // QQQ Why oh why didn't phk return the length from __getcwd()?
      UInt len = VG_(strlen) ( (char *)ARG1 ) + 1;
      POST_MEM_WRITE( ARG1, len );
   }
}

// getfsstat() takes a length in bytes, but returns the number of structures
// returned, not a length.
PRE(sys_getfsstat)
{
   PRINT("sys_getfsstat ( %#lx, %ld, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "getfsstat", struct statfs *, buf, long, len, int, flags);
   PRE_MEM_WRITE( "getfsstat(buf)", ARG1, ARG2 );
}
POST(sys_getfsstat)
{
   vg_assert(SUCCESS);
   if (RES > 0) {
      POST_MEM_WRITE( ARG1, RES * sizeof(struct vki_statfs) );
   }
}

PRE(sys_fhopen)
{
   PRINT("sys_open ( %#lx, %ld )",ARG1,ARG2);
   PRE_REG_READ2(long, "open",
                 struct fhandle *, fhp, int, flags);
   PRE_MEM_READ( "fhopen(fhp)", ARG1, sizeof(struct vki_fhandle) );

   /* Otherwise handle normally */
   *flags |= SfMayBlock;
}

POST(sys_fhopen)
{
   vg_assert(SUCCESS);
   if (!ML_(fd_allowed)(RES, "fhopen", tid, True)) {
      VG_(close)(RES);
      SET_STATUS_Failure( VKI_EMFILE );
   } else {
      if (VG_(clo_track_fds))
         ML_(record_fd_open_nameless)(tid, RES);
   }
}

PRE(sys_fhstat)
{
   PRINT("sys_fhstat ( %#lx, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "fhstat", struct fhandle *, fhp, struct stat *, buf);
   PRE_MEM_READ( "fhstat(fhp)", ARG1, sizeof(struct vki_fhandle) );
   PRE_MEM_WRITE( "fhstat(buf)", ARG2, sizeof(struct vki_stat) );
}

POST(sys_fhstat)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_stat) );
}

PRE(sys_fhstatfs)
{
   PRINT("sys_fstatfs ( %#lx, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "fhstatfs",
                 struct fhandle *, fhp, struct statfs *, buf);
   PRE_MEM_READ( "fhstatfs(fhp)", ARG1, sizeof(struct vki_fhandle) );
   PRE_MEM_WRITE( "fhstatfs(buf)", ARG2, sizeof(struct vki_statfs) );
}

POST(sys_fhstatfs)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs) );
}

PRE(sys_fhstatfs6)
{
   PRINT("sys_fstatfs6 ( %#lx, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "fhstatfs6",
                 struct fhandle *, fhp, struct statfs *, buf);
   PRE_MEM_READ( "fhstatfs6(fhp)", ARG1, sizeof(struct vki_fhandle) );
   PRE_MEM_WRITE( "fhstatfs6(buf)", ARG2, sizeof(struct vki_statfs6) );
}

POST(sys_fhstatfs6)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) );
}

PRE(sys_fstatfs6)
{
   PRINT("sys_fstatfs6 ( %ld, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "fstatfs6",
                 unsigned int, fd, struct statfs *, buf);
   PRE_MEM_WRITE( "fstatfs6(buf)", ARG2, sizeof(struct vki_statfs6) );
}

POST(sys_fstatfs6)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) );
}

PRE(sys_statfs6)
{
   PRINT("sys_statfs6 ( %#lx(%s), %#lx )",ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "statfs6", const char *, path, struct statfs *, buf);
   PRE_MEM_RASCIIZ( "statfs6(path)", ARG1 );
   PRE_MEM_WRITE( "statfs(buf)", ARG2, sizeof(struct vki_statfs6) );
}
POST(sys_statfs6)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_statfs6) );
}


#if 0
/* ---------------------------------------------------------------------
   aio_* wrappers
   ------------------------------------------------------------------ */

// Nb: this wrapper has to pad/unpad memory around the syscall itself,
// and this allows us to control exactly the code that gets run while
// the padding is in place.

PRE(sys_io_setup)
{
   PRINT("sys_io_setup ( %lu, %#lx )", ARG1,ARG2);
   PRE_REG_READ2(long, "io_setup",
                 unsigned, nr_events, vki_aio_context_t *, ctxp);
   PRE_MEM_WRITE( "io_setup(ctxp)", ARG2, sizeof(vki_aio_context_t) );
}

POST(sys_io_setup)
{
   SizeT size;
   struct vki_aio_ring *r;
           
   size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) +
                       ARG1*sizeof(struct vki_io_event));
   r = *(struct vki_aio_ring **)ARG2;
   vg_assert(ML_(valid_client_addr)((Addr)r, size, tid, "io_setup"));

   ML_(notify_aspacem_and_tool_of_mmap)( (Addr)r, size,
                                         VKI_PROT_READ | VKI_PROT_WRITE,
                                         VKI_MAP_ANONYMOUS, -1, 0 );

   POST_MEM_WRITE( ARG2, sizeof(vki_aio_context_t) );
}

// Nb: This wrapper is "Special" because we need 'size' to do the unmap
// after the syscall.  We must get 'size' from the aio_ring structure,
// before the syscall, while the aio_ring structure still exists.  (And we
// know that we must look at the aio_ring structure because Tom inspected the
// kernel and glibc sources to see what they do, yuk.)
//
// XXX This segment can be implicitly unmapped when aio
// file-descriptors are closed...
PRE(sys_io_destroy)
{
   struct vki_aio_ring *r;
   SizeT size;
      
   PRINT("sys_io_destroy ( %llu )", (ULong)ARG1);
   PRE_REG_READ1(long, "io_destroy", vki_aio_context_t, ctx);

   // If we are going to seg fault (due to a bogus ARG1) do it as late as
   // possible...
   r = (struct vki_aio_ring *)ARG1;
   size = VG_PGROUNDUP(sizeof(struct vki_aio_ring) + 
                       r->nr*sizeof(struct vki_io_event));

   SET_STATUS_from_SysRes( VG_(do_syscall1)(SYSNO, ARG1) );

   if (SUCCESS && RES == 0) { 
      Bool d = VG_(am_notify_munmap)( ARG1, size );
      VG_TRACK( die_mem_munmap, ARG1, size );
      if (d)
         VG_(discard_translations)( (Addr64)ARG1, (ULong)size, 
                                    "PRE(sys_io_destroy)" );
   }  
}  

PRE(sys_io_getevents)
{
   *flags |= SfMayBlock;
   PRINT("sys_io_getevents ( %llu, %lld, %lld, %#lx, %#lx )",
         (ULong)ARG1,(Long)ARG2,(Long)ARG3,ARG4,ARG5);
   PRE_REG_READ5(long, "io_getevents",
                 vki_aio_context_t, ctx_id, long, min_nr, long, nr,
                 struct io_event *, events,
                 struct timespec *, timeout);
   if (ARG3 > 0)
      PRE_MEM_WRITE( "io_getevents(events)",
                     ARG4, sizeof(struct vki_io_event)*ARG3 );
   if (ARG5 != 0)
      PRE_MEM_READ( "io_getevents(timeout)",
                    ARG5, sizeof(struct vki_timespec));
}
POST(sys_io_getevents)
{
   Int i;
   vg_assert(SUCCESS);
   if (RES > 0) {
      POST_MEM_WRITE( ARG4, sizeof(struct vki_io_event)*RES );
      for (i = 0; i < RES; i++) {
         const struct vki_io_event *vev = ((struct vki_io_event *)ARG4) + i;
         const struct vki_iocb *cb = (struct vki_iocb *)(Addr)vev->obj;

         switch (cb->aio_lio_opcode) {
         case VKI_IOCB_CMD_PREAD:
            if (vev->result > 0)
               POST_MEM_WRITE( cb->aio_buf, vev->result );
            break;
            
         case VKI_IOCB_CMD_PWRITE:
            break;
           
         default:
            VG_(message)(Vg_DebugMsg,
                        "Warning: unhandled io_getevents opcode: %u\n",
                        cb->aio_lio_opcode);
            break;
         }
      }
   }
}

PRE(sys_io_submit)
{
   Int i;

   PRINT("sys_io_submit ( %llu, %ld, %#lx )", (ULong)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "io_submit",
                 vki_aio_context_t, ctx_id, long, nr,
                 struct iocb **, iocbpp);
   PRE_MEM_READ( "io_submit(iocbpp)", ARG3, ARG2*sizeof(struct vki_iocb *) );
   if (ARG3 != 0) {
      for (i = 0; i < ARG2; i++) {
         struct vki_iocb *cb = ((struct vki_iocb **)ARG3)[i];
         PRE_MEM_READ( "io_submit(iocb)", (Addr)cb, sizeof(struct vki_iocb) );
         switch (cb->aio_lio_opcode) {
         case VKI_IOCB_CMD_PREAD:
            PRE_MEM_WRITE( "io_submit(PREAD)", cb->aio_buf, cb->aio_nbytes );
            break;

         case VKI_IOCB_CMD_PWRITE:
            PRE_MEM_READ( "io_submit(PWRITE)", cb->aio_buf, cb->aio_nbytes );
            break;
           
         default:
            VG_(message)(Vg_DebugMsg,"Warning: unhandled io_submit opcode: %u\n",
                         cb->aio_lio_opcode);
            break;
         }
      }
   }
}

PRE(sys_io_cancel)
{
   PRINT("sys_io_cancel ( %llu, %#lx, %#lx )", (ULong)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "io_cancel",
                 vki_aio_context_t, ctx_id, struct iocb *, iocb,
                 struct io_event *, result);
   PRE_MEM_READ( "io_cancel(iocb)", ARG2, sizeof(struct vki_iocb) );
   PRE_MEM_WRITE( "io_cancel(result)", ARG3, sizeof(struct vki_io_event) );
}
POST(sys_io_cancel)
{
   POST_MEM_WRITE( ARG3, sizeof(struct vki_io_event) );
}

/* ---------------------------------------------------------------------
   inotify_* wrappers
   ------------------------------------------------------------------ */

PRE(sys_inotify_init)
{
   PRINT("sys_inotify_init ( )");
   PRE_REG_READ0(long, "inotify_init");
}
POST(sys_inotify_init)
{
   vg_assert(SUCCESS);
   if (!ML_(fd_allowed)(RES, "inotify_init", tid, True)) {
      VG_(close)(RES);
      SET_STATUS_Failure( VKI_EMFILE );
   } else {
      if (VG_(clo_track_fds))
         ML_(record_fd_open_nameless) (tid, RES);
   }
}

PRE(sys_inotify_add_watch)
{
   PRINT( "sys_inotify_add_watch ( %ld, %#lx, %lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "inotify_add_watch", int, fd, char *, path, int, mask);
   PRE_MEM_RASCIIZ( "inotify_add_watch(path)", ARG2 );
}

PRE(sys_inotify_rm_watch)
{
   PRINT( "sys_inotify_rm_watch ( %ld, %lx )", ARG1,ARG2);
   PRE_REG_READ2(long, "inotify_rm_watch", int, fd, int, wd);
}

/* ---------------------------------------------------------------------
   mq_* wrappers
   ------------------------------------------------------------------ */

PRE(sys_mq_open)
{
   PRINT("sys_mq_open( %#lx(%s), %ld, %lld, %#lx )",
         ARG1,(char *)ARG1,ARG2,(ULong)ARG3,ARG4);
   PRE_REG_READ4(long, "mq_open",
                 const char *, name, int, oflag, vki_mode_t, mode,
                 struct mq_attr *, attr);
   PRE_MEM_RASCIIZ( "mq_open(name)", ARG1 );
   if ((ARG2 & VKI_O_CREAT) != 0 && ARG4 != 0) {
      const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG4;
      PRE_MEM_READ( "mq_open(attr->mq_maxmsg)",
                     (Addr)&attr->mq_maxmsg, sizeof(attr->mq_maxmsg) );
      PRE_MEM_READ( "mq_open(attr->mq_msgsize)",
                     (Addr)&attr->mq_msgsize, sizeof(attr->mq_msgsize) );
   }
}
POST(sys_mq_open)
{
   vg_assert(SUCCESS);
   if (!ML_(fd_allowed)(RES, "mq_open", tid, True)) {
      VG_(close)(RES);
      SET_STATUS_Failure( VKI_EMFILE );
   } else {
      if (VG_(clo_track_fds))
         ML_(record_fd_open_with_given_name)(tid, RES, (Char*)ARG1);
   }
}

PRE(sys_mq_unlink)
{
   PRINT("sys_mq_unlink ( %#lx(%s) )", ARG1,(char *)ARG1);
   PRE_REG_READ1(long, "mq_unlink", const char *, name);
   PRE_MEM_RASCIIZ( "mq_unlink(name)", ARG1 );
}

PRE(sys_mq_timedsend)
{
   *flags |= SfMayBlock;
   PRINT("sys_mq_timedsend ( %ld, %#lx, %llu, %ld, %#lx )",
         ARG1,ARG2,(ULong)ARG3,ARG4,ARG5);
   PRE_REG_READ5(long, "mq_timedsend",
                 vki_mqd_t, mqdes, const char *, msg_ptr, vki_size_t, msg_len,
                 unsigned int, msg_prio, const struct timespec *, abs_timeout);
   if (!ML_(fd_allowed)(ARG1, "mq_timedsend", tid, False)) {
      SET_STATUS_Failure( VKI_EBADF );
   } else {
      PRE_MEM_READ( "mq_timedsend(msg_ptr)", ARG2, ARG3 );
      if (ARG5 != 0)
         PRE_MEM_READ( "mq_timedsend(abs_timeout)", ARG5,
                        sizeof(struct vki_timespec) );
   }
}

PRE(sys_mq_timedreceive)
{
   *flags |= SfMayBlock;
   PRINT("sys_mq_timedreceive( %ld, %#lx, %llu, %#lx, %#lx )",
         ARG1,ARG2,(ULong)ARG3,ARG4,ARG5);
   PRE_REG_READ5(ssize_t, "mq_timedreceive",
                 vki_mqd_t, mqdes, char *, msg_ptr, vki_size_t, msg_len,
                 unsigned int *, msg_prio,
                 const struct timespec *, abs_timeout);
   if (!ML_(fd_allowed)(ARG1, "mq_timedreceive", tid, False)) {
      SET_STATUS_Failure( VKI_EBADF );
   } else {
      PRE_MEM_WRITE( "mq_timedreceive(msg_ptr)", ARG2, ARG3 );
      if (ARG4 != 0)
         PRE_MEM_WRITE( "mq_timedreceive(msg_prio)",
                        ARG4, sizeof(unsigned int) );
      if (ARG5 != 0)
         PRE_MEM_READ( "mq_timedreceive(abs_timeout)",
                        ARG5, sizeof(struct vki_timespec) );
   }
}
POST(sys_mq_timedreceive)
{
   POST_MEM_WRITE( ARG2, ARG3 );
   if (ARG4 != 0)
      POST_MEM_WRITE( ARG4, sizeof(unsigned int) );
}

PRE(sys_mq_notify)
{
   PRINT("sys_mq_notify( %ld, %#lx )", ARG1,ARG2 );
   PRE_REG_READ2(long, "mq_notify",
                 vki_mqd_t, mqdes, const struct sigevent *, notification);
   if (!ML_(fd_allowed)(ARG1, "mq_notify", tid, False))
      SET_STATUS_Failure( VKI_EBADF );
   else if (ARG2 != 0)
      PRE_MEM_READ( "mq_notify(notification)",
                    ARG2, sizeof(struct vki_sigevent) );
}

PRE(sys_mq_getsetattr)
{
   PRINT("sys_mq_getsetattr( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3 );
   PRE_REG_READ3(long, "mq_getsetattr",
                 vki_mqd_t, mqdes, const struct mq_attr *, mqstat,
                 struct mq_attr *, omqstat);
   if (!ML_(fd_allowed)(ARG1, "mq_getsetattr", tid, False)) {
      SET_STATUS_Failure( VKI_EBADF );
   } else {
      if (ARG2 != 0) {
         const struct vki_mq_attr *attr = (struct vki_mq_attr *)ARG2;
         PRE_MEM_READ( "mq_getsetattr(mqstat->mq_flags)",
                        (Addr)&attr->mq_flags, sizeof(attr->mq_flags) );
      }
      if (ARG3 != 0)
         PRE_MEM_WRITE( "mq_getsetattr(omqstat)", ARG3,
                        sizeof(struct vki_mq_attr) );
   }   
}
POST(sys_mq_getsetattr)
{
   if (ARG3 != 0)
      POST_MEM_WRITE( ARG3, sizeof(struct vki_mq_attr) );
}

#endif

/* ---------------------------------------------------------------------
   clock_* wrappers
   ------------------------------------------------------------------ */

PRE(sys_clock_settime)
{
   PRINT("sys_clock_settime( %ld, %#lx )", ARG1,ARG2);
   PRE_REG_READ2(long, "clock_settime", 
                 vki_clockid_t, clk_id, const struct timespec *, tp);
   PRE_MEM_READ( "clock_settime(tp)", ARG2, sizeof(struct vki_timespec) );
}

PRE(sys_clock_gettime)
{
   PRINT("sys_clock_gettime( %ld, %#lx )" , ARG1,ARG2);
   PRE_REG_READ2(long, "clock_gettime", 
                 vki_clockid_t, clk_id, struct timespec *, tp);
   PRE_MEM_WRITE( "clock_gettime(tp)", ARG2, sizeof(struct vki_timespec) );
}
POST(sys_clock_gettime)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) );
}

PRE(sys_clock_getres)
{
   PRINT("sys_clock_getres( %ld, %#lx )" , ARG1,ARG2);
   // Nb: we can't use "RES" as the param name because that's a macro
   // defined above!
   PRE_REG_READ2(long, "clock_getres", 
                 vki_clockid_t, clk_id, struct timespec *, res);
   if (ARG2 != 0)
      PRE_MEM_WRITE( "clock_getres(res)", ARG2, sizeof(struct vki_timespec) );
}
POST(sys_clock_getres)
{
   if (ARG2 != 0)
      POST_MEM_WRITE( ARG2, sizeof(struct vki_timespec) );
}

#if 0
PRE(sys_clock_nanosleep)
{
   *flags |= SfMayBlock|SfPostOnFail;
   PRINT("sys_clock_nanosleep( %ld, %ld, %#lx, %#lx )", ARG1,ARG2,ARG3,ARG4);
   PRE_REG_READ4(int32_t, "clock_nanosleep",
                 vki_clockid_t, clkid, int, flags,
                 const struct timespec *, rqtp, struct timespec *, rmtp);
   PRE_MEM_READ( "clock_nanosleep(rqtp)", ARG3, sizeof(struct vki_timespec) );
   if (ARG4 != 0)
      PRE_MEM_WRITE( "clock_nanosleep(rmtp)", ARG4, sizeof(struct vki_timespec) );
}
POST(sys_clock_nanosleep)
{
   if (ARG4 != 0 && FAILURE && RES_unchecked == VKI_EINTR)
      POST_MEM_WRITE( ARG4, sizeof(struct vki_timespec) );
}

/* ---------------------------------------------------------------------
   timer_* wrappers
   ------------------------------------------------------------------ */

PRE(sys_timer_create)
{
   PRINT("sys_timer_create( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "timer_create",
                 vki_clockid_t, clockid, struct sigevent *, evp,
                 vki_timer_t *, timerid);
   if (ARG2 != 0)
      PRE_MEM_READ( "timer_create(evp)", ARG2, sizeof(struct vki_sigevent) );
   PRE_MEM_WRITE( "timer_create(timerid)", ARG3, sizeof(vki_timer_t) );
}
POST(sys_timer_create)
{
   POST_MEM_WRITE( ARG3, sizeof(vki_timer_t) );
}

PRE(sys_timer_settime)
{
   PRINT("sys_timer_settime( %lld, %ld, %#lx, %#lx )", (ULong)ARG1,ARG2,ARG3,ARG4);
   PRE_REG_READ4(long, "timer_settime", 
                 vki_timer_t, timerid, int, flags,
                 const struct itimerspec *, value,
                 struct itimerspec *, ovalue);
   PRE_MEM_READ( "timer_settime(value)", ARG3,
                  sizeof(struct vki_itimerspec) );
   if (ARG4 != 0)
       PRE_MEM_WRITE( "timer_settime(ovalue)", ARG4,
                      sizeof(struct vki_itimerspec) );
}
POST(sys_timer_settime)
{
   if (ARG4 != 0)
      POST_MEM_WRITE( ARG4, sizeof(struct vki_itimerspec) );
}

PRE(sys_timer_gettime)
{
   PRINT("sys_timer_gettime( %lld, %#lx )", (ULong)ARG1,ARG2);
   PRE_REG_READ2(long, "timer_gettime", 
                 vki_timer_t, timerid, struct itimerspec *, value);
   PRE_MEM_WRITE( "timer_gettime(value)", ARG2,
                  sizeof(struct vki_itimerspec));
}
POST(sys_timer_gettime)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_itimerspec) );
}

PRE(sys_timer_getoverrun)
{
   PRINT("sys_timer_getoverrun( %#lx )", ARG1);
   PRE_REG_READ1(long, "timer_getoverrun", vki_timer_t, timerid);
}

PRE(sys_timer_delete)
{
   PRINT("sys_timer_delete( %#lx )", ARG1);
   PRE_REG_READ1(long, "timer_delete", vki_timer_t, timerid);
}

/* ---------------------------------------------------------------------
   sched_* wrappers
   ------------------------------------------------------------------ */

PRE(sys_sched_setparam)
{
   PRINT("sched_setparam ( %ld, %#lx )", ARG1, ARG2 );
   PRE_REG_READ2(long, "sched_setparam", 
                 vki_pid_t, pid, struct sched_param *, p);
   PRE_MEM_READ( "sched_setparam(p)", ARG2, sizeof(struct vki_sched_param) );
}
POST(sys_sched_setparam)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) );
}

PRE(sys_sched_getparam)
{
   PRINT("sched_getparam ( %ld, %#lx )", ARG1, ARG2 );
   PRE_REG_READ2(long, "sched_getparam", 
                 vki_pid_t, pid, struct sched_param *, p);
   PRE_MEM_WRITE( "sched_getparam(p)", ARG2, sizeof(struct vki_sched_param) );
}
POST(sys_sched_getparam)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_sched_param) );
}

PRE(sys_sched_getscheduler)
{
   PRINT("sys_sched_getscheduler ( %ld )", ARG1);
   PRE_REG_READ1(long, "sched_getscheduler", vki_pid_t, pid);
}

PRE(sys_sched_setscheduler)
{
   PRINT("sys_sched_setscheduler ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sched_setscheduler", 
                 vki_pid_t, pid, int, policy, struct sched_param *, p);
   if (ARG3 != 0)
      PRE_MEM_READ( "sched_setscheduler(p)", 
		    ARG3, sizeof(struct vki_sched_param));
}

PRE(sys_sched_yield)
{
   *flags |= SfMayBlock;
   PRINT("sched_yield()");
   PRE_REG_READ0(long, "sched_yield");
}


PRE(sys_sched_get_priority_max)
{
   PRINT("sched_get_priority_max ( %ld )", ARG1);
   PRE_REG_READ1(long, "sched_get_priority_max", int, policy);
}

PRE(sys_sched_get_priority_min)
{
   PRINT("sched_get_priority_min ( %ld )", ARG1);
   PRE_REG_READ1(long, "sched_get_priority_min", int, policy);
}

PRE(sys_sched_setaffinity)
{
   PRINT("sched_setaffinity ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
   PRE_REG_READ3(long, "sched_setaffinity", 
                 vki_pid_t, pid, unsigned int, len, unsigned long *, mask);
   PRE_MEM_READ( "sched_setaffinity(mask)", ARG3, ARG2);
}

PRE(sys_sched_getaffinity)
{
   PRINT("sched_getaffinity ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3);
   PRE_REG_READ3(long, "sched_getaffinity", 
                 vki_pid_t, pid, unsigned int, len, unsigned long *, mask);
   PRE_MEM_WRITE( "sched_getaffinity(mask)", ARG3, ARG2);
}
POST(sys_sched_getaffinity)
{
   POST_MEM_WRITE(ARG3, ARG2);
}

#endif

/* ---------------------------------------------------------------------
   miscellaneous wrappers
   ------------------------------------------------------------------ */

PRE(sys_munlockall)
{
   *flags |= SfMayBlock;
   PRINT("sys_munlockall ( )");
   PRE_REG_READ0(long, "munlockall");
}

// Pipe on freebsd doesn't have args, and uses dual returns!
PRE(sys_pipe)
{
   PRINT("sys_pipe ()");
}
POST(sys_pipe)
{
   if (!ML_(fd_allowed)(RES, "pipe", tid, True) ||
       !ML_(fd_allowed)(RESHI, "pipe", tid, True)) {
      VG_(close)(RES);
      VG_(close)(RESHI);
      SET_STATUS_Failure( VKI_EMFILE );
   } else {
      if (VG_(clo_track_fds)) {
         ML_(record_fd_open_nameless)(tid, RES);
         ML_(record_fd_open_nameless)(tid, RESHI);
      }
   }
}

#if 0
PRE(sys_quotactl)
{
   PRINT("sys_quotactl (0x%lx, %#lx, 0x%lx, 0x%lx )", ARG1,ARG2,ARG3, ARG4);
   PRE_REG_READ4(long, "quotactl",
                 unsigned int, cmd, const char *, special, vki_qid_t, id,
                 void *, addr);
   PRE_MEM_RASCIIZ( "quotactl(special)", ARG2 );
}

PRE(sys_waitid)
{
   *flags |= SfMayBlock;
   PRINT("sys_waitid( %ld, %ld, %#lx, %ld, %#lx )", ARG1,ARG2,ARG3,ARG4,ARG5);
   PRE_REG_READ5(int32_t, "sys_waitid",
                 int, which, vki_pid_t, pid, struct vki_siginfo *, infop,
                 int, options, struct vki_rusage *, ru);
   PRE_MEM_WRITE( "waitid(infop)", ARG3, sizeof(struct vki_siginfo) );
   if (ARG5 != 0)
      PRE_MEM_WRITE( "waitid(ru)", ARG5, sizeof(struct vki_rusage) );
}
POST(sys_waitid)
{
   POST_MEM_WRITE( ARG3, sizeof(struct vki_siginfo) );
   if (ARG5 != 0)
      POST_MEM_WRITE( ARG5, sizeof(struct vki_rusage) );
}

/* ---------------------------------------------------------------------
   utime wrapper
   ------------------------------------------------------------------ */

PRE(sys_utime)
{
   *flags |= SfMayBlock;
   PRINT("sys_utime ( %#lx, %#lx )", ARG1,ARG2);
   PRE_REG_READ2(long, "utime", char *, filename, struct utimbuf *, buf);
   PRE_MEM_RASCIIZ( "utime(filename)", ARG1 );
   if (ARG2 != 0)
      PRE_MEM_READ( "utime(buf)", ARG2, sizeof(struct vki_utimbuf) );
}

#endif

/* ---------------------------------------------------------------------
   thr* wrappers
   ------------------------------------------------------------------ */

PRE(sys_thr_self)
{
   PRINT( "sys_thr_self ( %#lx )", ARG1 );
   PRE_REG_READ1(long, "thr_self", long *, "id");
   PRE_MEM_WRITE( "thr_self()", ARG1, sizeof(long));
}
POST(sys_thr_self)
{
   POST_MEM_WRITE( ARG1, sizeof(long));
}

PRE(sys_thr_exit)
{
   ThreadState *tst;

   PRINT( "sys_thr_exit ( %#lx )", ARG1 );
   PRE_REG_READ1(long, "thr_exit", long *, "status");

   if (ARG1)
      PRE_MEM_WRITE( "thr_exit(status)", ARG1, sizeof(long) );
   tst = VG_(get_ThreadState)(tid);
   tst->exitreason = VgSrc_ExitThread;
   tst->os_state.exitcode = ARG1;
   SET_STATUS_Success(0);
}

PRE(sys_thr_set_name)
{
   PRINT( "sys_thr_set_name ( %ld, %#lx )", ARG1, ARG2 );
   PRE_REG_READ2(long, "thr_set_name", long, "id", const char *, "name");
   PRE_MEM_RASCIIZ( "sys_thr_set_name(threadname)", ARG2);
}

PRE(sys_thr_kill)
{
   PRINT("sys_thr_kill ( %ld, %ld )", ARG1,ARG2);
   PRE_REG_READ2(long, "thr_kill", long, id, int, sig);
   if (!ML_(client_signal_OK)(ARG2)) {
      SET_STATUS_Failure( VKI_EINVAL );
      return;
   }

   /* Check to see if this kill gave us a pending signal */
   *flags |= SfPollAfter;

   if (VG_(clo_trace_signals))
      VG_(message)(Vg_DebugMsg, "thr_kill: sending signal %ld to tid %ld",
                   ARG2, ARG1);

   /* If we're sending SIGKILL, check to see if the target is one of
      our threads and handle it specially. */
   if (ARG2 == VKI_SIGKILL && ML_(do_sigkill)(ARG1, -1)) {
      SET_STATUS_Success(0);
      return;
   }

   /* Ask to handle this syscall via the slow route, since that's the
      only one that sets tst->status to VgTs_WaitSys.  If the result
      of doing the syscall is an immediate run of
      async_signalhandler() in m_signals, then we need the thread to
      be properly tidied away.  I have the impression the previous
      version of this wrapper worked on x86/amd64 only because the
      kernel did not immediately deliver the async signal to this
      thread (on ppc it did, which broke the assertion re tst->status
      at the top of async_signalhandler()). */
   *flags |= SfMayBlock;
}
POST(sys_thr_kill)
{
   if (VG_(clo_trace_signals))
      VG_(message)(Vg_DebugMsg, "thr_kill: sent signal %ld to tid %ld",
                   ARG2, ARG1);
}
PRE(sys_thr_kill2)
{
   PRINT("sys_thr_kill2 ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "tgkill", int, pid, long, tid, int, sig);
   if (!ML_(client_signal_OK)(ARG3)) {
      SET_STATUS_Failure( VKI_EINVAL );
      return;
   }

   /* Check to see if this kill gave us a pending signal */
   *flags |= SfPollAfter;

   if (VG_(clo_trace_signals))
      VG_(message)(Vg_DebugMsg, "thr_kill2: sending signal %ld to pid %ld/%ld",
                   ARG3, ARG1, ARG2);

   /* If we're sending SIGKILL, check to see if the target is one of
      our threads and handle it specially. */
   if (ARG3 == VKI_SIGKILL && ML_(do_sigkill)(ARG2, ARG1)) {
      SET_STATUS_Success(0);
      return;
   }

   /* Ask to handle this syscall via the slow route, since that's the
      only one that sets tst->status to VgTs_WaitSys.  If the result
      of doing the syscall is an immediate run of
      async_signalhandler() in m_signals, then we need the thread to
      be properly tidied away.  I have the impression the previous
      version of this wrapper worked on x86/amd64 only because the
      kernel did not immediately deliver the async signal to this
      thread (on ppc it did, which broke the assertion re tst->status
      at the top of async_signalhandler()). */
   *flags |= SfMayBlock;
}
POST(sys_thr_kill2)
{
   if (VG_(clo_trace_signals))
      VG_(message)(Vg_DebugMsg, "thr_kill2: sent signal %ld to pid %ld/%ld",
                   ARG3, ARG1, ARG2);
}

/* ---------------------------------------------------------------------
   umtx* wrappers
   ------------------------------------------------------------------ */

PRE(sys__umtx_op)
{
// ThreadState *tst;

   /* 5 args are always passed through.  The last two can vary, but
      they're always pointers.  They may not be used though. */
   switch(ARG2) {
   case VKI_UMTX_OP_LOCK:
      PRINT( "sys__umtx_op ( %#lx, LOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_lock",
                    struct umtx *, obj, int, op, unsigned long, id,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_lock(timespec)", ARG5, sizeof(struct vki_timespec) );
      PRE_MEM_WRITE( "_umtx_op_lock(mtx)", ARG1, sizeof(struct vki_umtx) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_UNLOCK:
      PRINT( "sys__umtx_op ( %#lx, UNLOCK, %ld)", ARG1, ARG3);
      PRE_REG_READ3(long, "_umtx_op_unlock",
                    struct umtx *, obj, int, op, unsigned long, id);
      PRE_MEM_READ( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) );
      PRE_MEM_WRITE( "_umtx_op_unlock(mtx)", ARG1, sizeof(struct vki_umtx) );
      break;
   case VKI_UMTX_OP_WAIT:
      PRINT( "sys__umtx_op ( %#lx, WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_wait",
                    struct umtx *, obj, int, op, unsigned long, id,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_wait(mtx)", ARG1, sizeof(struct vki_umtx) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, sizeof(struct vki_timespec) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_WAKE:
      PRINT( "sys__umtx_op ( %#lx, WAKE, %ld)", ARG1, ARG3);
      PRE_REG_READ3(long, "_umtx_op_wake",
                    struct umtx *, obj, int, op, unsigned long, id);
      PRE_MEM_READ( "_umtx_op_wake(mtx)", ARG1, sizeof(struct vki_umtx) );
      break;
   case VKI_UMTX_OP_MUTEX_TRYLOCK:
      PRINT( "sys__umtx_op ( %#lx, MUTEX_TRYLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_mutex_trylock",
                    struct umutex *, obj, int, op, unsigned long, noid,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_mutex_trylock(timespec)", ARG5, sizeof(struct vki_timespec) );
      PRE_MEM_WRITE( "_umtx_op_mutex_trylock(mutex)", ARG1, sizeof(struct vki_umutex) );
      break;
   case VKI_UMTX_OP_MUTEX_LOCK:
      PRINT( "sys__umtx_op ( %#lx, MUTEX_LOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_mutex_lock",
                    struct umutex *, obj, int, op, unsigned long, noid,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_mutex_lock(timespec)", ARG5, sizeof(struct vki_timespec) );
      PRE_MEM_WRITE( "_umtx_op_mutex_lock(mutex)", ARG1, sizeof(struct vki_umutex) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_MUTEX_UNLOCK:
      PRINT( "sys__umtx_op ( %#lx, MUTEX_UNLOCK)", ARG1);
      PRE_REG_READ2(long, "_umtx_op_mutex_unlock",
                    struct umutex *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) );
      PRE_MEM_WRITE( "_umtx_op_mutex_unlock(mutex)", ARG1, sizeof(struct vki_umutex) );
      break;
   case VKI_UMTX_OP_SET_CEILING:
      PRINT( "sys__umtx_op ( %#lx, SET_CEILING, %ld, %#lx)", ARG1, ARG3, ARG4);
      PRE_REG_READ4(long, "_umtx_op_set_ceiling",
                    struct umutex *, obj, int, op, unsigned int, ceiling,
                    unsigned int *, old_ceiling);
      PRE_MEM_READ( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) );
      PRE_MEM_WRITE( "_umtx_op_set_ceiling(mutex)", ARG1, sizeof(struct vki_umutex) );
      if (ARG4)
         PRE_MEM_WRITE( "_umtx_op_set_ceiling(old_ceiling)", ARG4, sizeof(vki_uint32_t) );
      break;
   case VKI_UMTX_OP_CV_WAIT:
      PRINT( "sys__umtx_op ( %#lx, CV_WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_cv_wait",
                    struct ucond *, obj, int, op, unsigned long, wflags,
                    struct umutex *, umtx, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) );
      PRE_MEM_WRITE( "_umtx_op_cv_wait(cond)", ARG1, sizeof(struct vki_ucond) );
      PRE_MEM_READ( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) );
      PRE_MEM_WRITE( "_umtx_op_cv_wait(mutex)", ARG4, sizeof(struct vki_umutex) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_cv_wait(timespec)", ARG5, sizeof(struct vki_timespec) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_CV_SIGNAL:
      PRINT( "sys__umtx_op ( %#lx, CV_SIGNAL)", ARG1);
      PRE_REG_READ2(long, "_umtx_op_cv_signal",
                    struct ucond *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) );
      PRE_MEM_WRITE( "_umtx_op_cv_signal(cond)", ARG1, sizeof(struct vki_ucond) );
      break;
   case VKI_UMTX_OP_CV_BROADCAST:
      PRINT( "sys__umtx_op ( %#lx, CV_BROADCAST, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ2(long, "_umtx_op_cv_broadcast",
                    struct ucond *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) );
      PRE_MEM_WRITE( "_umtx_op_cv_broadcast(cond)", ARG1, sizeof(struct vki_ucond) );
      break;
   case VKI_UMTX_OP_WAIT_UINT:
      PRINT( "sys__umtx_op ( %#lx, CV_WAIT_UINT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_wait_uint",
                    int *, obj, int, op, unsigned long, id,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_wait(uint)", ARG1, sizeof(int) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_wait(timespec)", ARG5, sizeof(struct vki_timespec) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_RW_RDLOCK:
      PRINT( "sys__umtx_op ( %#lx, RW_RDLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_rw_rdlock",
                    struct urwlock *, obj, int, op, unsigned long, noid,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      PRE_MEM_WRITE( "_umtx_op_rw_rdlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_RW_WRLOCK:
      PRINT( "sys__umtx_op ( %#lx, RW_WRLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_rw_wrlock",
                    struct urwlock *, obj, int, op, unsigned long, noid,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      PRE_MEM_WRITE( "_umtx_op_rw_wrlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_RW_UNLOCK:
      PRINT( "sys__umtx_op ( %#lx, RW_UNLOCK, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ2(long, "_umtx_op_rw_unlock",
                    struct urwlock *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      PRE_MEM_WRITE( "_umtx_op_rw_unlock(rw)", ARG1, sizeof(struct vki_urwlock) );
      break;
   case VKI_UMTX_OP_WAIT_UINT_PRIVATE:
      PRINT( "sys__umtx_op ( %#lx, CV_WAIT_UINT_PRIVATE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ5(long, "_umtx_op_wait_uint_private",
                    int *, obj, int, op, unsigned long, id,
                    void *, zero, struct vki_timespec *, timeout);
      PRE_MEM_READ( "_umtx_op_wait_private(uint)", ARG1, sizeof(int) );
      if (ARG5)
	 PRE_MEM_READ( "_umtx_op_wait_private(timespec)", ARG5, sizeof(struct vki_timespec) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_WAKE_PRIVATE:
      PRINT( "sys__umtx_op ( %#lx, CV_WAKE_PRIVATE, %ld)", ARG1, ARG3);
      PRE_REG_READ3(long, "_umtx_op_wake_private",
                    struct umtx *, obj, int, op, unsigned long, id);
      PRE_MEM_READ( "_umtx_op_wake_private(mtx)", ARG1, sizeof(struct vki_umtx) );
      break;
   case VKI_UMTX_OP_MUTEX_WAIT:
      PRINT( "sys__umtx_op ( %#lx, MUTEX_WAIT, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ2(long, "_umtx_op_mutex_wait",
                    struct umutex *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) );
      PRE_MEM_WRITE( "_umtx_op_mutex_wait(mutex)", ARG1, sizeof(struct vki_umutex) );
      *flags |= SfMayBlock;
      break;
   case VKI_UMTX_OP_MUTEX_WAKE:
      PRINT( "sys__umtx_op ( %#lx, MUTEX_WAKE, %ld, %#lx, %#lx)", ARG1, ARG3, ARG4, ARG5);
      PRE_REG_READ2(long, "_umtx_op_mutex_wake",
                    struct umutex *, obj, int, op);
      PRE_MEM_READ( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) );
      PRE_MEM_WRITE( "_umtx_op_mutex_wake(mutex)", ARG1, sizeof(struct vki_umutex) );
      break;
   default:
      PRINT( "sys__umtx_op ( %#lx, %ld(UNKNOWN), %ld, %#lx, %#lx )", ARG1, ARG2, ARG3, ARG4, ARG5);
      break;
   }
//   tst = VG_(get_ThreadState)(tid);
//PRINT(" [[ UMTX_OP: me=%d arg1 %#lx = %#lx (%ld) ]]", tst->os_state.lwpid, ARG1, *(UWord *)ARG1, *(UWord *)ARG1 & 0x7fffffff);
}

POST(sys__umtx_op)
{
//VG_(printf)("[[ POST_UMTX_OP: arg1 %#lx = %#lx (%ld) ]]\n", ARG1, *(UWord *)ARG1, *(UWord *)ARG1 & 0x7fffffff);
   switch(ARG2) {
   case VKI_UMTX_OP_LOCK:
      if (SUCCESS)
         POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) );
      break;
   case VKI_UMTX_OP_UNLOCK:
      if (SUCCESS)
         POST_MEM_WRITE( ARG1, sizeof(struct vki_umtx) );
      break;
   case VKI_UMTX_OP_WAIT:
   case VKI_UMTX_OP_WAKE:
   case VKI_UMTX_OP_WAIT_UINT:
   case VKI_UMTX_OP_WAIT_UINT_PRIVATE:
   case VKI_UMTX_OP_WAKE_PRIVATE:
      break;
   case VKI_UMTX_OP_MUTEX_TRYLOCK:
   case VKI_UMTX_OP_MUTEX_LOCK:
   case VKI_UMTX_OP_MUTEX_UNLOCK:
   case VKI_UMTX_OP_MUTEX_WAIT:		/* Sets/clears contested bits */
   case VKI_UMTX_OP_MUTEX_WAKE:		/* Sets/clears contested bits */
      if (SUCCESS)
         POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) );
      break;
   case VKI_UMTX_OP_SET_CEILING:
      if (SUCCESS) {
         POST_MEM_WRITE( ARG1, sizeof(struct vki_umutex) );
	 if (ARG4)
            POST_MEM_WRITE( ARG4, sizeof(vki_uint32_t) );
      }
      break;
   case VKI_UMTX_OP_CV_WAIT:
      if (SUCCESS) {
         POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) );
         POST_MEM_WRITE( ARG4, sizeof(struct vki_umutex) );
      }
      break;
   case VKI_UMTX_OP_CV_SIGNAL:
      if (SUCCESS) {
         POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) );
      }
      break;
   case VKI_UMTX_OP_CV_BROADCAST:
      if (SUCCESS) {
         POST_MEM_WRITE( ARG1, sizeof(struct vki_ucond) );
      }
      break;
   case VKI_UMTX_OP_RW_RDLOCK:
   case VKI_UMTX_OP_RW_WRLOCK:
   case VKI_UMTX_OP_RW_UNLOCK:
      if (SUCCESS) {
         POST_MEM_WRITE( ARG1, sizeof(struct vki_urwlock) );
      }
      break;
   default:
      break;
   }
}

PRE(sys__umtx_lock)
{
   PRINT( "sys__umtx_lock ( %#lx )", ARG1);
   PRE_REG_READ1(long, "_umtx_lock", struct vki_umtx *, umtx);
   PRE_MEM_READ( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) );
   PRE_MEM_WRITE( "_umtx_lock(mtx)", ARG1, sizeof(struct vki_umtx) );
}

POST(sys__umtx_lock)
{
   if (SUCCESS)
       POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx));
}

PRE(sys__umtx_unlock)
{
   PRINT( "sys__umtx_unlock ( %#lx )", ARG1);
   PRE_REG_READ1(long, "_umtx_unlock", struct vki_umtx *, umtx);
   PRE_MEM_READ( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) );
   PRE_MEM_WRITE( "_umtx_unlock(mtx)", ARG1, sizeof(struct vki_umtx) );
}

POST(sys__umtx_unlock)
{
   if (SUCCESS)
      POST_MEM_WRITE(ARG1, sizeof(struct vki_umtx));
}

PRE(sys_rtprio_thread)
{
   PRINT( "sys_rtprio_thread ( %ld, %ld, %#lx )", ARG1, ARG2, ARG3 );
   PRE_REG_READ3(long, "rtprio_thread",
      int, "function", __vki_lwpid_t, "lwpid", struct vki_rtprio *, "rtp");
   if (ARG1 == VKI_RTP_SET) {
      PRE_MEM_READ( "rtprio_thread(set)", ARG3, sizeof(struct vki_rtprio));
   } else if (ARG1 == VKI_RTP_LOOKUP) {
      PRE_MEM_WRITE( "rtprio_thread(lookup)", ARG3, sizeof(struct vki_rtprio));
   } else {
	/* PHK ?? */
   }
}
POST(sys_rtprio_thread)
{
   if (ARG1 == VKI_RTP_LOOKUP && RES == 0)
      POST_MEM_WRITE( ARG3, sizeof(struct vki_rtprio));
}

/* ---------------------------------------------------------------------
   sig* wrappers
   ------------------------------------------------------------------ */

PRE(sys_sigpending)
{
   PRINT( "sys_sigpending ( %#lx )", ARG1 );
   PRE_REG_READ1(long, "sigpending", vki_sigset_t *, set);
   PRE_MEM_WRITE( "sigpending(set)", ARG1, sizeof(vki_sigset_t));
}
POST(sys_sigpending)
{
   POST_MEM_WRITE( ARG1, sizeof(vki_sigset_t) ) ;
}

/* ---------------------------------------------------------------------
   rt_sig* wrappers
   ------------------------------------------------------------------ */

static int sigformat[_VKI_NSIG];

PRE(sys_sigaction4)
{
   PRINT("sys_sigaction ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sigaction",
                 int, signum, const struct sigaction *, act,
                 struct sigaction *, oldact);

   if (ARG2 != 0) {
      struct vki_sigaction *sa = (struct vki_sigaction *)ARG2;
      PRE_MEM_READ( "sigaction(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
      PRE_MEM_READ( "sigaction(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
      PRE_MEM_READ( "sigaction(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
      if (ARG1 < _VKI_NSIG)
	 sigformat[ARG1] = 4;
   }
   if (ARG3 != 0)
      PRE_MEM_WRITE( "sigaction(oldact)", ARG3, sizeof(struct vki_sigaction));

   /* process the signal immediately. */
   SET_STATUS_from_SysRes(
      VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t *)ARG2,
                            (vki_sigaction_fromK_t *)ARG3)
   );
}
POST(sys_sigaction4)
{
   vg_assert(SUCCESS);
   if (RES == 0 && ARG3 != 0)
      POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction));
}

/* Identical, but warns the signal handler to expect the different sigframe */
PRE(sys_sigaction)
{
   PRINT("sys_sigaction6 ( %ld, %#lx, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sigaction6",
                 int, signum, const struct sigaction *, act,
                 struct sigaction *, oldact);

   if (ARG2 != 0) {
      struct vki_sigaction *sa = (struct vki_sigaction *)ARG2;
      PRE_MEM_READ( "sigaction6(act->sa_handler)", (Addr)&sa->ksa_handler, sizeof(sa->ksa_handler));
      PRE_MEM_READ( "sigaction6(act->sa_mask)", (Addr)&sa->sa_mask, sizeof(sa->sa_mask));
      PRE_MEM_READ( "sigaction6(act->sa_flags)", (Addr)&sa->sa_flags, sizeof(sa->sa_flags));
      if (ARG1 < _VKI_NSIG)
	 sigformat[ARG1] = 6;
   }
   if (ARG3 != 0)
      PRE_MEM_WRITE( "sigaction6(oldact)", ARG3, sizeof(struct vki_sigaction));

   SET_STATUS_from_SysRes(
      VG_(do_sys_sigaction)(ARG1, (const vki_sigaction_toK_t *)ARG2,
                            (vki_sigaction_fromK_t *)ARG3)
   );
}
POST(sys_sigaction)
{
   vg_assert(SUCCESS);
   if (RES == 0 && ARG3 != 0)
      POST_MEM_WRITE( ARG3, sizeof(struct vki_sigaction));
}


PRE(sys_sigprocmask)
{
   PRINT("sys_sigprocmask ( %ld, %#lx, %#lx )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sigprocmask", 
                 int, how, vki_sigset_t *, set, vki_sigset_t *, oldset);
   if (ARG2 != 0)
      PRE_MEM_READ( "sigprocmask(set)", ARG2, sizeof(vki_sigset_t));
   if (ARG3 != 0)
      PRE_MEM_WRITE( "sigprocmask(oldset)", ARG3, sizeof(vki_sigset_t));

   SET_STATUS_from_SysRes( 
	       VG_(do_sys_sigprocmask) ( tid, ARG1 /*how*/, 
					 (vki_sigset_t*) ARG2,
					 (vki_sigset_t*) ARG3 )
   );

   if (SUCCESS)
      *flags |= SfPollAfter;
}
POST(sys_sigprocmask)
{
   vg_assert(SUCCESS);
   if (RES == 0 && ARG3 != 0)
      POST_MEM_WRITE( ARG3, sizeof(vki_sigset_t));
}

/* Not in 4.x */
PRE(sys_sigtimedwait)
{
   *flags |= SfMayBlock;
   PRINT("sys_sigtimedwait ( %#lx, %#lx, %#lx )",
         ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "sigtimedwait", 
                 const vki_sigset_t *, set, vki_siginfo_t *, info,
                 const struct timespec *, timeout);
   if (ARG1 != 0) 
      PRE_MEM_READ(  "sigtimedwait(set)",  ARG1, sizeof(vki_sigset_t));
   if (ARG2 != 0)
      PRE_MEM_WRITE( "sigtimedwait(info)", ARG2, sizeof(vki_siginfo_t) );
   if (ARG3 != 0)
      PRE_MEM_READ( "sigtimedwait(timeout)",
                    ARG3, sizeof(struct vki_timespec) );
}
POST(sys_sigtimedwait)
{
   if (ARG2 != 0)
      POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) );
}

/* Not in 4.x */
PRE(sys_sigwaitinfo)
{
   *flags |= SfMayBlock;
   PRINT("sys_sigwaitinfo ( %#lx, %#lx )",
         ARG1,ARG2);
   PRE_REG_READ2(long, "sigwaitinfo", 
                 const vki_sigset_t *, set, vki_siginfo_t *, info);
   if (ARG1 != 0) 
      PRE_MEM_READ(  "sigwaitinfo(set)",  ARG1, sizeof(vki_sigset_t));
   if (ARG2 != 0)
      PRE_MEM_WRITE( "sigwaitinfo(info)", ARG2, sizeof(vki_siginfo_t) );
}
POST(sys_sigwaitinfo)
{
   if (ARG2 != 0)
      POST_MEM_WRITE( ARG2, sizeof(vki_siginfo_t) );
}

#if 0	/* not on freebsd 4.x */
PRE(sys_rt_sigqueueinfo)
{
   PRINT("sys_rt_sigqueueinfo(%ld, %ld, %#lx)", ARG1, ARG2, ARG3);
   PRE_REG_READ3(long, "rt_sigqueueinfo", 
                 int, pid, int, sig, vki_siginfo_t *, uinfo);
   if (ARG2 != 0)
      PRE_MEM_READ( "rt_sigqueueinfo(uinfo)", ARG3, sizeof(vki_siginfo_t) );
}
POST(sys_rt_sigqueueinfo)
{
   if (!ML_(client_signal_OK)(ARG2))
      SET_STATUS_Failure( VKI_EINVAL );
}
#endif

PRE(sys_sigsuspend)
{
   *flags |= SfMayBlock;
   PRINT("sys_sigsuspend ( %#lx )", ARG1 );
   PRE_REG_READ1(int, "rt_sigsuspend", vki_sigset_t *, mask)
   if (ARG1 != (Addr)NULL) {
      PRE_MEM_READ( "rt_sigsuspend(mask)", ARG1, sizeof(vki_sigset_t) );
   }
}

#if 0
/* ---------------------------------------------------------------------
   linux msg* wrapper helpers
   ------------------------------------------------------------------ */

void
ML_(linux_PRE_sys_msgsnd) ( ThreadId tid,
                            UWord arg0, UWord arg1, UWord arg2, UWord arg3 )
{
   /* int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); */
   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
   PRE_MEM_READ( "msgsnd(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
   PRE_MEM_READ( "msgsnd(msgp->mtext)", (Addr)&msgp->mtext, arg2 );
}

void
ML_(linux_PRE_sys_msgrcv) ( ThreadId tid,
                            UWord arg0, UWord arg1, UWord arg2,
                            UWord arg3, UWord arg4 )
{
   /* ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz,
                     long msgtyp, int msgflg); */
   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
   PRE_MEM_WRITE( "msgrcv(msgp->mtype)", (Addr)&msgp->mtype, sizeof(msgp->mtype) );
   PRE_MEM_WRITE( "msgrcv(msgp->mtext)", (Addr)&msgp->mtext, arg2 );
}
void
ML_(linux_POST_sys_msgrcv) ( ThreadId tid,
                             UWord res,
                             UWord arg0, UWord arg1, UWord arg2,
                             UWord arg3, UWord arg4 )
{
   struct vki_msgbuf *msgp = (struct vki_msgbuf *)arg1;
   POST_MEM_WRITE( (Addr)&msgp->mtype, sizeof(msgp->mtype) );
   POST_MEM_WRITE( (Addr)&msgp->mtext, res );
}

void
ML_(linux_PRE_sys_msgctl) ( ThreadId tid,
                            UWord arg0, UWord arg1, UWord arg2 )
{
   /* int msgctl(int msqid, int cmd, struct msqid_ds *buf); */
   switch (arg1 /* cmd */) {
   case VKI_IPC_INFO:
   case VKI_MSG_INFO:
   case VKI_IPC_INFO|VKI_IPC_64:
   case VKI_MSG_INFO|VKI_IPC_64:
      PRE_MEM_WRITE( "msgctl(IPC_INFO, buf)",
                     arg2, sizeof(struct vki_msginfo) );
      break;
   case VKI_IPC_STAT:
   case VKI_MSG_STAT:
      PRE_MEM_WRITE( "msgctl(IPC_STAT, buf)",
                     arg2, sizeof(struct vki_msqid_ds) );
      break;
   case VKI_IPC_STAT|VKI_IPC_64:
   case VKI_MSG_STAT|VKI_IPC_64:
      PRE_MEM_WRITE( "msgctl(IPC_STAT, arg.buf)",
                     arg2, sizeof(struct vki_msqid64_ds) );
      break;
   case VKI_IPC_SET:
      PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)",
                    arg2, sizeof(struct vki_msqid_ds) );
      break;
   case VKI_IPC_SET|VKI_IPC_64:
      PRE_MEM_READ( "msgctl(IPC_SET, arg.buf)",
                    arg2, sizeof(struct vki_msqid64_ds) );
      break;
   }
}
void
ML_(linux_POST_sys_msgctl) ( ThreadId tid,
                             UWord res,
                             UWord arg0, UWord arg1, UWord arg2 )
{
   switch (arg1 /* cmd */) {
   case VKI_IPC_INFO:
   case VKI_MSG_INFO:
   case VKI_IPC_INFO|VKI_IPC_64:
   case VKI_MSG_INFO|VKI_IPC_64:
      POST_MEM_WRITE( arg2, sizeof(struct vki_msginfo) );
      break;
   case VKI_IPC_STAT:
   case VKI_MSG_STAT:
      POST_MEM_WRITE( arg2, sizeof(struct vki_msqid_ds) );
      break;
   case VKI_IPC_STAT|VKI_IPC_64:
   case VKI_MSG_STAT|VKI_IPC_64:
      POST_MEM_WRITE( arg2, sizeof(struct vki_msqid64_ds) );
      break;
   }
}

#endif

PRE(sys_chflags)
{
   PRINT("sys_chflags ( %#lx(%s), 0x%lx )", ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "chown",
                 const char *, path, vki_int32_t, flags);
   PRE_MEM_RASCIIZ( "chflags(path)", ARG1 );
}

PRE(sys_fchflags)
{
   PRINT("sys_fchflags ( %ld, %ld )", ARG1,ARG2);
   PRE_REG_READ2(long, "fchflags", unsigned int, fildes, vki_int32_t, flags);
}


PRE(sys_modfind)
{
   PRINT("sys_modfind ( %#lx )",ARG1);
   PRE_REG_READ1(long, "modfind", char *, modname);
   PRE_MEM_RASCIIZ( "modfind(modname)", ARG1 );
}

PRE(sys_modstat)
{
   PRINT("sys_modstat ( %ld, %#lx )",ARG1,ARG2);
   PRE_REG_READ2(long, "modstat", int, modid, struct module_stat *, buf);
   PRE_MEM_WRITE( "modstat(buf)", ARG2, sizeof(struct vki_module_stat) );
}

POST(sys_modstat)
{
   POST_MEM_WRITE( ARG2, sizeof(struct vki_module_stat) );
}

PRE(sys_lkmnosys0)
{
   PRINT("sys_lkmnosys0 ()");
   PRE_REG_READ0(long, "lkmnosys0");
}

PRE(sys_lkmnosys1)
{
   PRINT("sys_lkmnosys1 ()");
   PRE_REG_READ0(long, "lkmnosys1");
}

PRE(sys_lkmnosys2)
{
   PRINT("sys_lkmnosys2 ()");
   PRE_REG_READ0(long, "lkmnosys2");
}

PRE(sys_lkmnosys3)
{
   PRINT("sys_lkmnosys3 ()");
   PRE_REG_READ0(long, "lkmnosys3");
}

PRE(sys_lkmnosys4)
{
   PRINT("sys_lkmnosys4 ()");
   PRE_REG_READ0(long, "lkmnosys4");
}

PRE(sys_lkmnosys5)
{
   PRINT("sys_lkmnosys5 ()");
   PRE_REG_READ0(long, "lkmnosys5");
}

PRE(sys_lkmnosys6)
{
   PRINT("sys_lkmnosys6 ()");
   PRE_REG_READ0(long, "lkmnosys6");
}

PRE(sys_lkmnosys7)
{
   PRINT("sys_lkmnosys7 ()");
   PRE_REG_READ0(long, "lkmnosys7");
}

PRE(sys_lkmnosys8)
{
   PRINT("sys_lkmnosys8 ()");
   PRE_REG_READ0(long, "lkmnosys8");
}

PRE(sys_kenv)
{
   PRINT("sys_kenv ( %ld, %#lx, %#lx, %ld )", ARG1,ARG2,ARG3,ARG4);
   PRE_REG_READ4(long, "kenv",
                 int, action, const char *, name, char *, value, int, len);
   switch (ARG1) {
   case VKI_KENV_GET:
   case VKI_KENV_SET:
   case VKI_KENV_UNSET:
      PRE_MEM_RASCIIZ("kenv(name)", ARG2);
      /* FALLTHROUGH */
   case VKI_KENV_DUMP:
      break;
   default:
      I_die_here;
   }
}

POST(sys_kenv)
{
   if (SUCCESS) {
      switch (ARG1) {
      case VKI_KENV_GET:
         POST_MEM_WRITE(ARG3, ARG4);
         break;
      case VKI_KENV_DUMP:
         if (ARG3 != (Addr)NULL)
            POST_MEM_WRITE(ARG3, ARG4);
         break;
      }
   }
}

PRE(sys_uuidgen)
{
   PRINT("sys_uuidgen ( %#lx, %ld )", ARG1,ARG2);
   PRE_REG_READ2(long, "uuidgen",
		 struct vki_uuid *, store, int, count);
   PRE_MEM_WRITE( "uuidgen(store)", ARG1, ARG2 * sizeof(struct vki_uuid));
}

POST(sys_uuidgen)
{
   if (SUCCESS)
      POST_MEM_WRITE( ARG1, ARG2 * sizeof(struct vki_uuid) );
}


PRE(sys_shmget)
{
   PRINT("sys_shmget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "shmget", vki_key_t, key, vki_size_t, size, int, shmflg);
}

PRE(sys_shmat)
{
   UWord arg2tmp;
   PRINT("sys_shmat ( %ld, %#lx, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "shmat",
                 int, shmid, const void *, shmaddr, int, shmflg);
   arg2tmp = ML_(generic_PRE_sys_shmat)(tid, ARG1,ARG2,ARG3);
   if (arg2tmp == 0)
      SET_STATUS_Failure( VKI_EINVAL );
   else
      ARG2 = arg2tmp;
}

POST(sys_shmat)
{
   ML_(generic_POST_sys_shmat)(tid, RES,ARG1,ARG2,ARG3);
}

PRE(sys_shmdt)
{
   PRINT("sys_shmdt ( %#lx )",ARG1);
   PRE_REG_READ1(long, "shmdt", const void *, shmaddr);
   if (!ML_(generic_PRE_sys_shmdt)(tid, ARG1))
      SET_STATUS_Failure( VKI_EINVAL );
}

POST(sys_shmdt)
{
   ML_(generic_POST_sys_shmdt)(tid, RES,ARG1);
}

PRE(sys_shmctl)
{
   PRINT("sys_shmctl ( %ld, %ld, %#lx )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "shmctl",
                 int, shmid, int, cmd, struct shmid_ds *, buf);
   ML_(generic_PRE_sys_shmctl)(tid, ARG1,ARG2,ARG3);
}

POST(sys_shmctl)
{
   ML_(generic_POST_sys_shmctl)(tid, RES,ARG1,ARG2,ARG3);
}

PRE(sys_semget)
{
   PRINT("sys_semget ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "semget", vki_key_t, key, int, nsems, int, semflg);
}

PRE(sys_semop)
{
   *flags |= SfMayBlock;
   PRINT("sys_semop ( %ld, %#lx, %lu )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "semop",
                 int, semid, struct sembuf *, sops, unsigned, nsoops);
   ML_(generic_PRE_sys_semop)(tid, ARG1,ARG2,ARG3);
}

struct ipc_perm7 {
	unsigned short	cuid;	/* creator user id */
	unsigned short	cgid;	/* creator group id */
	unsigned short	uid;	/* user id */
	unsigned short	gid;	/* group id */
	unsigned short	mode;	/* r/w permission */
	unsigned short	seq;	/* sequence # (to generate unique ipcid) */
	vki_key_t	key;	/* user specified msg/sem/shm key */
};

struct semid_ds7 {
	struct ipc_perm7 sem_perm;	/* operation permission struct */
	struct sem	*sem_base;	/* pointer to first semaphore in set */
	unsigned short	sem_nsems;	/* number of sems in set */
	vki_time_t	sem_otime;	/* last operation time */
	long		sem_pad1;	/* SVABI/386 says I need this here */
	vki_time_t	sem_ctime;	/* last change time */
    					/* Times measured in secs since */
    					/* 00:00:00 GMT, Jan. 1, 1970 */
	long		sem_pad2;	/* SVABI/386 says I need this here */
	long		sem_pad3[4];	/* SVABI/386 says I need this here */
};

PRE(sys___semctl7)
{
   switch (ARG3) {
   case VKI_IPC_INFO:
   case VKI_SEM_INFO:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, struct seminfo *, arg);
      break;
   case VKI_IPC_STAT:
   case VKI_SEM_STAT:
   case VKI_IPC_SET:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, struct semid_ds7 *, arg);
      break;
   case VKI_GETALL:
   case VKI_SETALL:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
      break;
   default:
      PRINT("sys_semctl ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
      PRE_REG_READ3(long, "semctl",
                    int, semid, int, semnum, int, cmd);
      break;
   }
   ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
}

POST(sys___semctl7)
{
   ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
}

PRE(sys___semctl)
{
   switch (ARG3) {
   case VKI_IPC_INFO:
   case VKI_SEM_INFO:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, struct seminfo *, arg);
      break;
   case VKI_IPC_STAT:
   case VKI_SEM_STAT:
   case VKI_IPC_SET:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, struct semid_ds *, arg);
      break;
   case VKI_GETALL:
   case VKI_SETALL:
      PRINT("sys_semctl ( %ld, %ld, %ld, %#lx )",ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "semctl",
                    int, semid, int, semnum, int, cmd, unsigned short *, arg);
      break;
   default:
      PRINT("sys_semctl ( %ld, %ld, %ld )",ARG1,ARG2,ARG3);
      PRE_REG_READ3(long, "semctl",
                    int, semid, int, semnum, int, cmd);
      break;
   }
   ML_(generic_PRE_sys_semctl)(tid, ARG1,ARG2,ARG3,ARG4);
}

POST(sys___semctl)
{
   ML_(generic_POST_sys_semctl)(tid, RES,ARG1,ARG2,ARG3,ARG4);
}

PRE(sys_eaccess)
{
   PRINT("sys_eaccess ( %#lx(%s), %ld )", ARG1,(char*)ARG1,ARG2);
   PRE_REG_READ2(long, "eaccess", const char *, pathname, int, mode);
   PRE_MEM_RASCIIZ( "eaccess(pathname)", ARG1 );
}


/* ---------------------------------------------------------------------
   *at wrappers
   ------------------------------------------------------------------ */

PRE(sys_openat)
{
   HChar  name[30];
   SysRes sres;

   if (ARG3 & VKI_O_CREAT) {
      // 4-arg version
      PRINT("sys_openat ( %ld, %#lx(%s), %ld, %ld )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "openat",
                    int, dfd, const char *, filename, int, flags, int, mode);
   } else {
      // 3-arg version
      PRINT("sys_openat ( %ld, %#lx(%s), %ld )",ARG1,ARG2,(char*)ARG2,ARG3);
      PRE_REG_READ3(long, "openat",
                    int, dfd, const char *, filename, int, flags);
   }

   if (ARG1 != VKI_AT_FDCWD && !ML_(fd_allowed)(ARG1, "openat", tid, False))
      SET_STATUS_Failure( VKI_EBADF );
   else
      PRE_MEM_RASCIIZ( "openat(filename)", ARG2 );

   /* Handle the case where the open is of /proc/curproc/cmdline or
      /proc/<pid>/cmdline, and just give it a copy of the fd for the
      fake file we cooked up at startup (in m_main).  Also, seek the
      cloned fd back to the start. */

   VG_(sprintf)(name, "/proc/%d/cmdline", VG_(getpid)());
   if (ML_(safe_to_deref)( (void*)ARG2, 1 )
       && (VG_(strcmp)((Char *)ARG2, name) == 0 
           || VG_(strcmp)((Char *)ARG2, "/proc/curproc/cmdline") == 0)) {
      sres = VG_(dup)( VG_(cl_cmdline_fd) );
      SET_STATUS_from_SysRes( sres );
      if (!sr_isError(sres)) {
         OffT off = VG_(lseek)( sr_Res(sres), 0, VKI_SEEK_SET );
         if (off < 0)
            SET_STATUS_Failure( VKI_EMFILE );
      }
      return;
   }

   /* 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, (Char*)ARG2);
   }
}

PRE(sys_mkdirat)
{
   *flags |= SfMayBlock;
   PRINT("sys_mkdirat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3);
   PRE_REG_READ3(long, "mkdirat",
                 int, dfd, const char *, pathname, int, mode);
   PRE_MEM_RASCIIZ( "mkdirat(pathname)", ARG2 );
}

PRE(sys_mkfifoat)
{
  PRINT("sys_mkfifoat ( %ld, %#lx(%s), 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3 );
   PRE_REG_READ3(long, "mkfifoat",
                 int, dfd, const char *, pathname, int, mode);
   PRE_MEM_RASCIIZ( "mkfifoat(pathname)", ARG2 );
}

PRE(sys_mknodat)
{
  PRINT("sys_mknodat ( %ld, %#lx(%s), 0x%lx, 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4 );
   PRE_REG_READ4(long, "mknodat",
                 int, dfd, const char *, pathname, int, mode, unsigned, dev);
   PRE_MEM_RASCIIZ( "mknodat(pathname)", ARG2 );
}

PRE(sys_fchownat)
{
   PRINT("sys_fchownat ( %ld, %#lx(%s), 0x%lx, 0x%lx )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4);
   PRE_REG_READ4(long, "fchownat",
                 int, dfd, const char *, path,
                 vki_uid_t, owner, vki_gid_t, group);
   PRE_MEM_RASCIIZ( "fchownat(path)", ARG2 );
}

PRE(sys_futimesat)
{
   PRINT("sys_futimesat ( %ld, %#lx(%s), %#lx )", ARG1,ARG2,(char*)ARG2,ARG3);
   PRE_REG_READ3(long, "futimesat",
                 int, dfd, char *, filename, struct timeval *, tvp);
   if (ARG2 != 0)
      PRE_MEM_RASCIIZ( "futimesat(filename)", ARG2 );
   if (ARG3 != 0)
      PRE_MEM_READ( "futimesat(tvp)", ARG3, 2 * sizeof(struct vki_timeval) );
}

PRE(sys_fstatat)
{
   PRINT("sys_fstatat ( %ld, %#lx(%s), %#lx )", ARG1,ARG2,(char*)ARG2,ARG3);
   PRE_REG_READ3(long, "fstatat",
                 int, dfd, char *, file_name, struct stat *, buf);
   PRE_MEM_RASCIIZ( "fstatat(file_name)", ARG2 );
   PRE_MEM_WRITE( "fstatat(buf)", ARG3, sizeof(struct vki_stat) );
}

POST(sys_fstatat)
{
   POST_MEM_WRITE( ARG3, sizeof(struct vki_stat) );
}

PRE(sys_unlinkat)
{
   *flags |= SfMayBlock;
   PRINT("sys_unlinkat ( %ld, %#lx(%s) )", ARG1,ARG2,(char*)ARG2);
   PRE_REG_READ2(long, "unlinkat", int, dfd, const char *, pathname);
   PRE_MEM_RASCIIZ( "unlinkat(pathname)", ARG2 );
}

PRE(sys_renameat)
{
   PRINT("sys_renameat ( %ld, %#lx(%s), %ld, %#lx(%s) )", ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4);
   PRE_REG_READ4(long, "renameat",
                 int, olddfd, const char *, oldpath,
                 int, newdfd, const char *, newpath);
   PRE_MEM_RASCIIZ( "renameat(oldpath)", ARG2 );
   PRE_MEM_RASCIIZ( "renameat(newpath)", ARG4 );
}

PRE(sys_linkat)
{
   *flags |= SfMayBlock;
   PRINT("sys_linkat ( %ld, %#lx(%s), %ld, %#lx(%s), %ld )",ARG1,ARG2,(char*)ARG2,ARG3,ARG4,(char*)ARG4,ARG5);
   PRE_REG_READ5(long, "linkat",
                 int, olddfd, const char *, oldpath,
                 int, newdfd, const char *, newpath,
                 int, flags);
   PRE_MEM_RASCIIZ( "linkat(oldpath)", ARG2);
   PRE_MEM_RASCIIZ( "linkat(newpath)", ARG4);
}

PRE(sys_symlinkat)
{
   *flags |= SfMayBlock;
   PRINT("sys_symlinkat ( %#lx(%s), %ld, %#lx(%s) )",ARG1,(char*)ARG1,ARG2,ARG3,(char*)ARG3);
   PRE_REG_READ3(long, "symlinkat",
                 const char *, oldpath, int, newdfd, const char *, newpath);
   PRE_MEM_RASCIIZ( "symlinkat(oldpath)", ARG1 );
   PRE_MEM_RASCIIZ( "symlinkat(newpath)", ARG3 );
}

PRE(sys_readlinkat)
{
   HChar name[25];
   Word  saved = SYSNO;

   PRINT("sys_readlinkat ( %ld, %#lx(%s), %#lx, %llu )", ARG1,ARG2,(char*)ARG2,ARG3,(ULong)ARG4);
   PRE_REG_READ4(long, "readlinkat",
                 int, dfd, const char *, path, char *, buf, int, bufsiz);
   PRE_MEM_RASCIIZ( "readlinkat(path)", ARG2 );
   PRE_MEM_WRITE( "readlinkat(buf)", ARG3,ARG4 );

   /*
    * Handle the case where readlinkat is looking at /proc/curproc/file or
    * /proc/<pid>/file.
    */
   VG_(sprintf)(name, "/proc/%d/file", VG_(getpid)());
   if (ML_(safe_to_deref)((void*)ARG2, 1)
       && (VG_(strcmp)((Char *)ARG2, name) == 0 
           || VG_(strcmp)((Char *)ARG2, "/proc/curproc/file") == 0)) {
      VG_(sprintf)(name, "/proc/self/fd/%d", VG_(cl_exec_fd));
      SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, (UWord)name, 
                                                      ARG3, ARG4));
   } else {
      /* Normal case */
      SET_STATUS_from_SysRes( VG_(do_syscall4)(saved, ARG1, ARG2, ARG3, ARG4));
   }

   if (SUCCESS && RES > 0)
      POST_MEM_WRITE( ARG3, RES );
}

PRE(sys_fchmodat)
{
   PRINT("sys_fchmodat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3);
   PRE_REG_READ3(long, "fchmodat",
                 int, dfd, const char *, path, vki_mode_t, mode);
   PRE_MEM_RASCIIZ( "fchmodat(path)", ARG2 );
}

PRE(sys_faccessat)
{
   PRINT("sys_faccessat ( %ld, %#lx(%s), %ld )", ARG1,ARG2,(char*)ARG2,ARG3);
   PRE_REG_READ3(long, "faccessat",
                 int, dfd, const char *, pathname, int, mode);
   PRE_MEM_RASCIIZ( "faccessat(pathname)", ARG2 );
}

/* ---------------------------------------------------------------------
   __acl* wrappers
   ------------------------------------------------------------------ */

PRE(sys___acl_get_file)
{
   PRINT("sys___acl_get_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_get_file",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_WRITE( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) );
}

POST(sys___acl_get_file)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) );
   }
}

PRE(sys___acl_set_file)
{
   PRINT("sys___acl_set_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_set_file",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_set_file(aclp)", ARG3, sizeof(struct vki_acl) );
}

PRE(sys___acl_get_fd)
{
   PRINT("sys___acl_get_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_get_fd",
                 int, fd, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_WRITE( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) );
}

POST(sys___acl_get_fd)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) );
   }
}

PRE(sys___acl_set_fd)
{
   PRINT("sys___acl_set_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_set_fd",
                 int, fd, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_get_file(aclp)", ARG3, sizeof(struct vki_acl) );
}

PRE(sys___acl_delete_file)
{
   PRINT("sys___acl_delete_file ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "__acl_delete_file",
                 const char *, path, int, acltype);
}

PRE(sys___acl_delete_fd)
{
   PRINT("sys___acl_delete_fd ( %ld, %ld )", ARG1,ARG2);
   PRE_REG_READ2(long, "__acl_delete_fd",
                 int, fd, int, acltype);
}

PRE(sys___acl_aclcheck_file)
{
   PRINT("sys___acl_aclcheck_file ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_aclcheck_file",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_aclcheck_file(aclp)", ARG3, sizeof(struct vki_acl) );
}

PRE(sys___acl_aclcheck_fd)
{
   PRINT("sys___acl_aclcheck_fd ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_aclcheck_fd",
                 int, fd, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_aclcheck_fd(aclp)", ARG3, sizeof(struct vki_acl) );
}

PRE(sys___acl_get_link)
{
   PRINT("sys___acl_get_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_get_link",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_WRITE( "__acl_get_link(aclp)", ARG3, sizeof(struct vki_acl) );
}

POST(sys___acl_get_link)
{
   vg_assert(SUCCESS);
   if (RES == 0) {
      POST_MEM_WRITE( ARG3, sizeof(struct vki_acl) );
   }
}

PRE(sys___acl_set_link)
{
   PRINT("sys___acl_set_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_set_link",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_set_link(aclp)", ARG3, sizeof(struct vki_acl) );
}

PRE(sys___acl_delete_link)
{
   PRINT("sys___acl_delete_link ( %#lx(%s), %ld )", ARG1,(char *)ARG1,ARG2);
   PRE_REG_READ2(long, "__acl_delete_link",
                 const char *, path, int, acltype);
}

PRE(sys___acl_aclcheck_link)
{
   PRINT("sys___acl_aclcheck_link ( %#lx(%s), %ld, %#lx )", ARG1,(char *)ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "__acl_aclcheck_link",
                 const char *, path, int, acltype, struct vki_acl *, aclp);
   PRE_MEM_READ( "__acl_aclcheck_link(aclp)", ARG3, sizeof(struct vki_acl) );
}

/* The *_context() wrappers aren't really safe.  They clobber registers not
   preserved by the calling convention.  The kernel doesn't do this.  However,
   in realtity it doesn't matter because we call these from C rather than asm. */
PRE(sys_getcontext)
{
   PRINT("sys_getcontext ( %#lx )", ARG1);
   PRE_REG_READ1(long, "getcontext",
                 struct vki_ucontext *, ucp);
   PRE_MEM_WRITE( "getcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
}

POST(sys_getcontext)
{
   POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) );
}

PRE(sys_setcontext)
{
   PRINT("sys_setcontext ( %#lx )", ARG1);
   PRE_REG_READ1(long, "setcontext",
                 struct vki_ucontext *, ucp);

   PRE_MEM_READ( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
   PRE_MEM_WRITE( "setcontext(ucp)", ARG1, sizeof(struct vki_ucontext) );
}

POST(sys_setcontext)
{
   /* changes uc_link etc */
   POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) );
}

PRE(sys_swapcontext)
{
   PRINT("sys_swapcontext ( %#lx, %#lx )", ARG1, ARG2);
   PRE_REG_READ2(long, "swapcontext",
                 struct vki_ucontext *, oucp, struct vki_ucontext *, ucp);

   PRE_MEM_READ( "swapcontext(ucp)", ARG2, sizeof(struct vki_ucontext) );
   PRE_MEM_WRITE( "swapcontext(oucp)", ARG1, sizeof(struct vki_ucontext) );
}

POST(sys_swapcontext)
{
   if (SUCCESS)
      POST_MEM_WRITE( ARG1, sizeof(struct vki_ucontext) );
}

PRE(sys_fcntl)
{
   switch (ARG2) {
   // These ones ignore ARG3.
   case VKI_F_GETFD:
   case VKI_F_GETFL:
   case VKI_F_GETOWN:
      PRINT("sys_fcntl ( %ld, %ld )", ARG1,ARG2);
      PRE_REG_READ2(long, "fcntl", unsigned int, fd, unsigned int, cmd);
      break;

   // These ones use ARG3 as "arg".
   case VKI_F_DUPFD:
   case VKI_F_SETFD:
   case VKI_F_SETFL:
   case VKI_F_SETOWN:
      PRINT("sys_fcntl[ARG3=='arg'] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
      PRE_REG_READ3(long, "fcntl",
                    unsigned int, fd, unsigned int, cmd, unsigned long, arg);
      break;

   // These ones use ARG3 as "lock" - obsolete.
   case VKI_F_OSETLKW:
      *flags |= SfMayBlock;
      /* FALLTHROUGH */
   case VKI_F_OGETLK:
   case VKI_F_OSETLK:
      PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
      PRE_REG_READ3(long, "fcntl",
                    unsigned int, fd, unsigned int, cmd,
                    struct oflock *, lock);
      break;

   // This one uses ARG3 as "oldd" and ARG4 as "newd".
   case VKI_F_DUP2FD:
      PRINT("sys_fcntl[ARG3=='oldd', ARG4=='newd'] ( %ld, %ld, %ld, %ld )",
         ARG1,ARG2,ARG3,ARG4);
      PRE_REG_READ4(long, "fcntl",
                    unsigned int, fd, unsigned int, cmd,
                    unsigned long, oldd, unsigned long, newd);
      break;

   // These ones use ARG3 as "lock".
   case VKI_F_SETLKW:
      *flags |= SfMayBlock;
      /* FALLTHROUGH */
   case VKI_F_GETLK:
   case VKI_F_SETLK:
   case VKI_F_SETLK_REMOTE:
      PRINT("sys_fcntl[ARG3=='lock'] ( %ld, %ld, %#lx )", ARG1,ARG2,ARG3);
      PRE_REG_READ3(long, "fcntl",
                    unsigned int, fd, unsigned int, cmd,
                    struct flock *, lock);
      break;

   default:
      PRINT("sys_fcntl[UNKNOWN] ( %ld, %ld, %ld )", ARG1,ARG2,ARG3);
      I_die_here;
      break;
   }
}

POST(sys_fcntl)
{
   vg_assert(SUCCESS);
   if (ARG2 == VKI_F_DUPFD) {
      if (!ML_(fd_allowed)(RES, "fcntl(DUPFD)", tid, True)) {
         VG_(close)(RES);
         SET_STATUS_Failure( VKI_EMFILE );
      } else {
         if (VG_(clo_track_fds))
            ML_(record_fd_open_named)(tid, RES);
      }
   }
}

PRE(sys_ioctl)
{
   UInt dir  = _VKI_IOC_DIR(ARG2);
   UInt size = _VKI_IOC_SIZE(ARG2);
   *flags |= SfMayBlock;
   PRINT("sys_ioctl ( %ld, 0x%lx, %#lx )",ARG1,ARG2,ARG3);
   PRE_REG_READ3(long, "ioctl",
                 unsigned int, fd, unsigned int, request, unsigned long, arg);

/* On FreeBSD, ALL ioctl's are IOR/IOW encoded.  Just use the default decoder */
   if (VG_(strstr)(VG_(clo_sim_hints), "lax-ioctls") != NULL) {
      /* 
      * Be very lax about ioctl handling; the only
      * assumption is that the size is correct. Doesn't
      * require the full buffer to be initialized when
      * writing.  Without this, using some device
      * drivers with a large number of strange ioctl
      * commands becomes very tiresome.
      */
   } else if (/* size == 0 || */ dir == _VKI_IOC_NONE) {
	 static Int moans = 3;
	 if (moans > 0 && !VG_(clo_xml)) {
	    moans--;
	    VG_(message)(Vg_UserMsg, 
			 "Warning: noted but unhandled ioctl 0x%lx"
			 " with no size/direction hints",
			 ARG2); 
	    VG_(message)(Vg_UserMsg, 
			 "   This could cause spurious value errors"
			 " to appear.");
	    VG_(message)(Vg_UserMsg, 
			 "   See README_MISSING_SYSCALL_OR_IOCTL for "
			 "guidance on writing a proper wrapper." );
	 }
   } else {
	 if ((dir & _VKI_IOC_WRITE) && size > 0)
	    PRE_MEM_READ( "ioctl(generic)", ARG3, size);
	 if ((dir & _VKI_IOC_READ) && size > 0)
	    PRE_MEM_WRITE( "ioctl(generic)", ARG3, size);
   }
}

POST(sys_ioctl)
{
  UInt dir  = _VKI_IOC_DIR(ARG2);
  UInt size = _VKI_IOC_SIZE(ARG2);
  vg_assert(SUCCESS);
  if (size > 0 && (dir & _VKI_IOC_READ)
     && RES == 0 && ARG3 != (Addr)NULL)
	 POST_MEM_WRITE(ARG3, size);
}

#undef PRE
#undef POST

const SyscallTableEntry ML_(syscall_table)[] = {
   // syscall (handled specially)					// 0
   BSDX_(__NR_exit,			sys_exit),			// 1
   BSDX_(__NR_fork,			sys_fork),			// 2
   GENXY(__NR_read,			sys_read),			// 3

   GENX_(__NR_write,			sys_write),			// 4
   GENXY(__NR_open,			sys_open),			// 5
   GENXY(__NR_close,			sys_close),			// 6
   GENXY(__NR_wait4,			sys_wait4),			// 7

   // 4.3 creat								   8
   GENX_(__NR_link,			sys_link),			// 9
   GENX_(__NR_unlink,			sys_unlink),			// 10
   // obsol execv							   11

   GENX_(__NR_chdir,			sys_chdir),			// 12
   GENX_(__NR_fchdir,			sys_fchdir),			// 13
   GENX_(__NR_mknod,			sys_mknod),			// 14
   GENX_(__NR_chmod,			sys_chmod),			// 15

   GENX_(__NR_chown,			sys_chown),			// 16
   GENX_(__NR_break,			sys_brk),			// 17
   BSDXY(__NR_getfsstat,		sys_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_pipe,			sys_pipe),			// 42
   GENX_(__NR_getegid,			sys_getegid),			// 43

   // GENX_(__NR_profil,		sys_profil),			// 44
// BSDX_(__NR_ktrace,			sys_ktrace),			// 45
   // 4.3 sigaction							   46
   GENX_(__NR_getgid,			sys_getgid),			// 47

   // 4.3 sigaction (int sigset)					   48
   BSDXY(__NR_getlogin,			sys_getlogin),			// 49
   BSDX_(__NR_setlogin,			sys_setlogin),			// 50
   GENX_(__NR_acct,			sys_acct),			// 51

   // 4.3 sigpending							   52
   GENXY(__NR_sigaltstack,		sys_sigaltstack),		// 53
   BSDXY(__NR_ioctl,			sys_ioctl),			// 54
// BSDX_(__NR_reboot,			sys_reboot),			// 55

   BSDX_(__NR_revoke,			sys_revoke),			// 56
   GENX_(__NR_symlink,			sys_symlink),			// 57
   GENX_(__NR_readlink,			sys_readlink),			// 58
   GENX_(__NR_execve,			sys_execve),			// 59

   GENX_(__NR_umask,			sys_umask),			// 60
   GENX_(__NR_chroot,			sys_chroot),			// 61
   // 4.3 fstat								   62
   // 4.3 getgerninfo							   63

   // 4.3 getpagesize							   64
   GENX_(__NR_msync,			sys_msync),			// 65
   BSDX_(__NR_vfork,			sys_fork),			// 66
   // obsol vread							   67

   // obsol vwrite							   68
   // BSDX_(__NR_sbrk,			sys_sbrk),			// 69
   // BSDX_(__NR_sstk,			sys_sstk),			// 70
   // 4.3 mmap								   71

   // 4.2 vadvise							   72
   GENXY(__NR_munmap,			sys_munmap),			// 73
   GENXY(__NR_mprotect,			sys_mprotect),			// 74
   GENX_(__NR_madvise,			sys_madvise),			// 75

   // obsol vhangup							   76
   // obsol vlimit							   77
   GENXY(__NR_mincore,			sys_mincore),			// 78
   GENXY(__NR_getgroups,		sys_getgroups),			// 79

   GENX_(__NR_setgroups,		sys_setgroups),			// 80
   GENX_(__NR_getpgrp,			sys_getpgrp),			// 81
   GENX_(__NR_setpgid,			sys_setpgid),			// 82
   GENXY(__NR_setitimer,		sys_setitimer),			// 83

   // 4.3 wait								   84
// BSDX_(__NR_swapon,			sys_swapon),			// 85
   GENXY(__NR_getitimer,		sys_getitimer),			// 86
   // 4.3 gethostname							   87

   // 4.3 sethostname							   88
   BSDX_(__NR_getdtablesize,		sys_getdtablesize),		// 89
   GENXY(__NR_dup2,			sys_dup2),			// 90
   // unimpl getdopt							   91

   BSDXY(__NR_fcntl,			sys_fcntl),			// 92
   GENX_(__NR_select,			sys_select),			// 93
   // unimpl setdopt							   94
   GENX_(__NR_fsync,			sys_fsync),			// 95

   GENX_(__NR_setpriority,		sys_setpriority),		// 96
   BSDXY(__NR_socket,			sys_socket),			// 97
   BSDX_(__NR_connect,			sys_connect),			// 98
   // 4.3 accept							   99

   GENX_(__NR_getpriority,		sys_getpriority),		// 100
   // 4.3 send								   101
   // 4.3 recv								   102
   // 4.3 sigreturn							   103

   BSDX_(__NR_bind,			sys_bind),			// 104
   BSDX_(__NR_setsockopt,		sys_setsockopt),		// 105
   BSDX_(__NR_listen,			sys_listen),			// 106
   // obsol vtimes							   107

   // 4.3 sigvec							   108
   // 4.3 sigblock							   109
   // 4.3 sigsetmask							   110
   // 4.3 sigsuspend							   111

   // 4.3 sigstack							   112
   // 4.3 recvmsg							   113
   // 4.3 sendmsg							   114
   // 4.3 vtrace							   115

   GENXY(__NR_gettimeofday,		sys_gettimeofday),		// 116
   GENXY(__NR_getrusage,		sys_getrusage),			// 117
   BSDXY(__NR_getsockopt,		sys_getsockopt),		// 118
   // unimpl resuba							   119

   GENXY(__NR_readv,			sys_readv),			// 120
   GENX_(__NR_writev,			sys_writev),			// 121
   GENX_(__NR_settimeofday,		sys_settimeofday),		// 122
   GENX_(__NR_fchown,			sys_fchown),			// 123

   GENX_(__NR_fchmod,			sys_fchmod),			// 124
   // 4.3 recvfrom							   125
   GENX_(__NR_setreuid,			sys_setreuid),			// 126
   GENX_(__NR_setregid,			sys_setregid),			// 127

   GENX_(__NR_rename,			sys_rename),			// 128
   // 4.3 truncate							   129
   // 4.3 ftruncate							   130
   GENX_(__NR_flock,			sys_flock),			// 131

   BSDX_(__NR_mkfifo,			sys_mkfifo),			// 132
   BSDX_(__NR_sendto,			sys_sendto),			// 133
   BSDX_(__NR_shutdown,			sys_shutdown),			// 134
   BSDXY(__NR_socketpair,		sys_socketpair),		// 135

   GENX_(__NR_mkdir,			sys_mkdir),			// 136
   GENX_(__NR_rmdir,			sys_rmdir),			// 137
   GENX_(__NR_utimes,			sys_utimes),			// 138
   // 4.2 sigreturn							   139

// BSDXY(__NR_adjtime,			sys_adjtime),			// 140
   // 4.3 getpeername							   141
   // 4.3 gethostid							   142
   // 4.3 sethostid							   143

   // 4.3 getrlimit							   144
   // 4.3 setrlimit							   145
   // 4.3 killpg							   146
   GENX_(__NR_setsid,			sys_setsid),			// 147

   BSDX_(__NR_quotactl,			sys_quotactl),			// 148
   // 4.3 quota								   149
   // 4.3 getsockname							   150
   // bsd/os sem_lock							   151

   // bsd/os sem_wakeup							   152
   // bsd/os asyncdaemon						   153
   // nosys								   154
   // BSDXY(__NR_nfssvc,		sys_nfssvc),			// 155

   // 4.3 getdirentries							   156
   GENXY(__NR_statfs,			sys_statfs),			// 157
   GENXY(__NR_fstatfs,			sys_fstatfs),			// 158
   // nosys								   159

// BSDXY(__NR_lgetfh,			sys_lgetfh),			// 160
// BSDXY(__NR_getfh,			sys_getfh),			// 161
   BSDXY(__NR_getdomainname,		sys_getdomainname),		// 162
   BSDX_(__NR_setdomainname,		sys_setdomainname),		// 163

   BSDXY(__NR_uname,			sys_uname),			// 164
   BSDX_(__NR_sysarch,			sys_sysarch),			// 165
// BSDXY(__NR_rtprio,			sys_rtprio),			// 166
   // nosys								   167

   // nosys								   168
// BSDXY(__NR_semsys,			sys_semsys),			// 169
// BSDXY(__NR_msgsys,			sys_msgsys),			// 170
// BSDXY(__NR_shmsys,			sys_shmsys),			// 171

   // nosys								   172
   BSDXY(__NR_pread,			sys_pread),			// 173
   BSDX_(__NR_pwrite,			sys_pwrite),			// 174
   // nosys								   175

// BSDXY(__NR_ntp_adjtime,		sys_ntp_adjtime),		// 176
   // bsd/os sfork							   177
   // bsd/os getdescriptor						   178
   // bsd/os setdescriptor						   179

   // nosys								   180
   GENX_(__NR_setgid,			sys_setgid),			// 181
   BSDX_(__NR_setegid,			sys_setegid),			// 182
   BSDX_(__NR_seteuid,			sys_seteuid),			// 183

   // unimpl lfs_bmapv							   184
   // unimpl lfs_markv							   185
   // unimpl lfs_segclean						   186
   // unimpl lfs_segwait						   187

   BSDXY(__NR_stat,			sys_stat),			// 188
   BSDXY(__NR_fstat,			sys_fstat),			// 189
   BSDXY(__NR_lstat,			sys_lstat),			// 190
   BSDX_(__NR_pathconf,			sys_pathconf),			// 191

   BSDX_(__NR_fpathconf,		sys_fpathconf),			// 192
   // nosys								   193
   GENXY(__NR_getrlimit,		sys_getrlimit),			// 194
   GENX_(__NR_setrlimit,		sys_setrlimit),			// 195

   BSDXY(__NR_getdirentries,		sys_getdirentries),		// 196
   BSDX_(__NR_mmap,			sys_mmap7),			// 197
   // __syscall (handled specially)					// 198
   BSDX_(__NR_lseek6,			sys_lseek),			// 199

   BSDX_(__NR_truncate,			sys_truncate),			// 200
   BSDX_(__NR_ftruncate,		sys_ftruncate),			// 201
   BSDXY(__NR___sysctl,			sys___sysctl),			// 202
   GENX_(__NR_mlock,			sys_mlock),			// 203

   GENX_(__NR_munlock,			sys_munlock),			// 204
   BSDX_(__NR_undelete,			sys_undelete),			// 205
   BSDX_(__NR_futimes,			sys_futimes),			// 206
   GENX_(__NR_getpgid,			sys_getpgid),			// 207

   // netbsd newreboot							   208
   GENXY(__NR_poll,			sys_poll),			// 209
   BSDX_(__NR_lkmnosys0,		sys_lkmnosys0),			// 210
   BSDX_(__NR_lkmnosys1,		sys_lkmnosys1),			// 211

   BSDX_(__NR_lkmnosys2,		sys_lkmnosys2),			// 212
   BSDX_(__NR_lkmnosys3,		sys_lkmnosys3),			// 213
   BSDX_(__NR_lkmnosys4,		sys_lkmnosys4),			// 214
   BSDX_(__NR_lkmnosys5,		sys_lkmnosys5),			// 215

   BSDX_(__NR_lkmnosys6,		sys_lkmnosys6),			// 216
   BSDX_(__NR_lkmnosys7,		sys_lkmnosys7),			// 217
   BSDX_(__NR_lkmnosys8,		sys_lkmnosys8),			// 218
// BSDXY(__NR_nfs_fhopen,		sys_nfs_fhopen),		// 219

   BSDXY(__NR___semctl7,		sys___semctl7),			// 220
   BSDX_(__NR_semget,			sys_semget),			// 221
   BSDX_(__NR_semop,			sys_semop),			// 222
   // unimpl semconfig							   223

// BSDXY(__NR_msgctl,			sys_msgctl),			// 224
// BSDX_(__NR_msgget,			sys_msgget),			// 225
// BSDX_(__NR_msgsnd,			sys_msgsnd),			// 226
// BSDXY(__NR_msgrcv,			sys_msgrcv),			// 227

   BSDXY(__NR_shmat,			sys_shmat),				// 228
   BSDXY(__NR_shmctl,			sys_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
   // unimpl timer_create						   235

   // unimpl timer_delete						   236
   // unimpl timer_settime						   237
   // unimpl timer_gettime						   238
   // unimpl timer_getoverrun						   239

   GENXY(__NR_nanosleep,		sys_nanosleep),			// 240
   // nosys								   241
   // nosys								   242
   // nosys								   243

   // nosys								   244
   // nosys								   245
   // nosys								   246
   // nosys								   247

// BSDXY(__NR_ntp_gettime,		sys_ntp_gettime),		// 248
   // nosys								   249
// BSDXY(__NR_minherit,			sys_minherit),			// 250
   BSDX_(__NR_rfork,			sys_rfork),			// 251

   GENXY(__NR_openbsd_poll,		sys_poll),			// 252
   BSDX_(__NR_issetugid,		sys_issetugid),			// 253
   GENX_(__NR_lchown,			sys_lchown),			// 254
   // nosys								   255

   // nosys								   256
   // nosys								   257
   // nosys								   258
   // nosys								   259
 
   // nosys								   260
   // nosys								   261
   // nosys								   262
   // nosys								   263

   // nosys								   264
   // nosys								   265
   // nosys								   266
   // nosys								   267

   // nosys								   268
   // nosys								   269
   // nosys								   270
   // nosys								   271

   GENXY(__NR_getdents,			sys_getdents),			// 272
   // nosys								   273
   BSDX_(__NR_lchmod,			sys_lchmod),			// 274
   GENX_(__NR_netbsd_lchown,		sys_lchown),			// 275

   BSDX_(__NR_lutimes,			sys_lutimes),			// 276
   // netbsd msync							   277
   // netbsd stat							   278
   // netbsd fstat							   279

   // netbsd lstat 							   280
   // nosys								   281
   // nosys								   282
   // nosys								   283

   // nosys								   284
   // nosys								   285
   // nosys								   286
   // nosys								   287

   // nosys								   288
   // nosys								   289
   // nosys								   290
   // nosys								   291

   // nosys								   292
   // nosys								   293
   // nosys								   294
   // nosys								   295

   // nosys								   296
   BSDXY(__NR_fhstatfs,			sys_fhstatfs),			// 297
   BSDXY(__NR_fhopen,			sys_fhopen),			// 298
   BSDXY(__NR_fhstat,			sys_fhstat),			// 299

// BSDX_(__NR_modnext,			sys_modnext),			// 300
   BSDXY(__NR_modstat,			sys_modstat),			// 301
// BSDX_(__NR_modfnext,			sys_modfnext),			// 302
   BSDX_(__NR_modfind,			sys_modfind),			// 303

// BSDX_(__NR_kldload,			sys_kldload),			// 304
// BSDX_(__NR_kldunload,		sys_kldunload),			// 305
// BSDX_(__NR_kldfind,			sys_kldfind),			// 306
// BSDX_(__NR_kldnext,			sys_kldnext),			// 307

// BSDXY(__NR_kldstat,			sys_kldstat),			// 308
// BSDX_(__NR_kldfirstmod,		sys_kldfirstmod),		// 309
   GENX_(__NR_getsid,			sys_getsid),			// 310
   BSDX_(__NR_setresuid,		sys_setresuid),			// 311

   BSDX_(__NR_setresgid,		sys_setresgid),			// 312
   // obsol signanosleep						   313
   // BSDXY(__NR_aio_return,		sys_aio_return),		// 314
   // BSDXY(__NR_aio_suspend,		sys_aio_suspend),		// 315

   // BSDXY(__NR_aio_cancel,		sys_aio_cancel),		// 316
   // BSDXY(__NR_aio_error,		sys_aio_error),			// 317
   // BSDXY(__NR_aio_read,		sys_aio_read),			// 318
   // BSDXY(__NR_aio_write,		sys_aio_write),			// 319

   // BSDXY(__NR_lio_listio,		sys_lio_listio),		// 320
   BSDX_(__NR_yield,			sys_yield),			// 321
   // nosys								   322
   // nosys								   323

   GENX_(__NR_mlockall,			sys_mlockall),			// 324
   BSDX_(__NR_munlockall,		sys_munlockall),		// 325
   BSDXY(__NR___getcwd,			sys___getcwd),			// 326
// BSDXY(__NR_sched_setparam,		sys_sched_setparam),		// 327

// BSDXY(__NR_sched_getparam,		sys_sched_getparam),		// 328
// BSDX_(__NR_sched_setscheduler,	sys_sched_setscheduler),	// 329
// BSDX_(__NR_sched_getscheduler,	sys_sched_getscheduler),	// 330
   BSDX_(__NR_sched_yield,		sys_sched_yield),		// 331

// BSDX_(__NR_sched_get_priority_max,	sys_sched_get_priority_max),	// 332
// BSDX_(__NR_sched_get_priority_min,	sys_sched_get_priority_min),	// 333
// BSDXY(__NR_sched_rr_get_interval,	sys_sched_rr_get_interval),	// 334
   BSDX_(__NR_utrace,			sys_utrace),			// 335

   // compat3 sendfile							   336
// BSDXY(__NR_kldsym,			sys_kldsym),			// 337
// BSDX_(__NR_jail,			sys_jail),			// 338
   // unimpl pioctl							   339

   BSDXY(__NR_sigprocmask,		sys_sigprocmask),		// 340
   BSDX_(__NR_sigsuspend,		sys_sigsuspend),		// 341
   BSDXY(__NR_sigaction4,		sys_sigaction4),		// 342
   BSDXY(__NR_sigpending,		sys_sigpending),		// 343

   BSDX_(__NR_sigreturn,		sys_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
   // BSDXY(__NR_extattrctl,		sys_extattrctl),		// 355

   // BSDXY(__NR_extattr_set_file,	sys_extattr_set_file),		// 356
   // BSDXY(__NR_extattr_get_file,	sys_extattr_get_file),		// 357
   // BSDXY(__NR_extattr_delete_file,	sys_extattr_delete_file),	// 358
   // BSDXY(__NR_aio_waitcomplete,	sys_aio_waitcomplete),		// 359

   BSDXY(__NR_getresuid,		sys_getresuid),			// 360
   BSDXY(__NR_getresgid,		sys_getresgid),			// 361
   BSDX_(__NR_kqueue,			sys_kqueue),			// 362
   BSDXY(__NR_kevent,			sys_kevent),			// 363

   // nosys								   364
   // nosys								   365
   // nosys								   366
   // nosys								   367

   // nosys								   368
   // nosys								   369
   // lkmressys								   370
   // extattr_set_fd							   371

   // extattr_get_fd							   372
   // extattr_delete_fd							   373
   // __setugid								   374
   // nfsclnt								   375

   BSDX_(__NR_eaccess,			sys_eaccess),			// 376
   // afs_syscall							   377
   // nmount								   378
   // kse_exit								   379

   // kse_wakeup							   380
   // kse_create							   381
   // kse_thr_interrupt							   382
   // kse_release							   383

   // __mac_get_proc							   384
   // __mac_set_proc							   385
   // __mac_get_fd							   386
   // __mac_get_file							   387

   // __mac_set_fd							   388
   // __mac_set_file							   389
   BSDXY(__NR_kenv,                     sys_kenv),                      // 390
   // lchflags								   391

   BSDXY(__NR_uuidgen,			sys_uuidgen),			// 392
   BSDXY(__NR_sendfile,			sys_sendfile),			// 393
   // mac_syscall							   394
   // getfsstat								   395

   BSDXY(__NR_statfs6,			sys_statfs6),			// 396
   BSDXY(__NR_fstatfs6,			sys_fstatfs6),			// 397
   BSDXY(__NR_fhstatfs6,		sys_fhstatfs6),			// 398
   // nosys								   399

   // ksem_close							   400
   // ksem_post								   401
   // ksem_wait								   402
   // ksem_trywait							   403

   // ksem_init								   404
   // ksem_open								   405
   // ksem_unlink							   406
   // ksem_getvalue							   407

   // ksem_destroy							   408
   // __mac_get_pid							   409
   // __mac_get_link							   410
   // __mac_set_link							   411

   // extattr_set_link							   412
   // extattr_get_link							   413
   // extattr_delete_link						   414
   // __mac_execve							   415

   BSDXY(__NR_sigaction,		sys_sigaction),			// 416
   //!sigreturn								   417
   // __xstat								   418
   // __xfstat								   419

   // __xlstat								   420
   BSDXY(__NR_getcontext,		sys_getcontext),		// 421
   BSDXY(__NR_setcontext,		sys_setcontext),		// 422
   BSDXY(__NR_swapcontext,		sys_swapcontext),		// 423

   // swapoff								   424
   BSDXY(__NR___acl_get_link,		sys___acl_get_link),		// 425
   BSDX_(__NR___acl_set_link,		sys___acl_set_link),		// 426
   BSDX_(__NR___acl_delete_link,	sys___acl_delete_link),		// 427

   BSDX_(__NR___acl_aclcheck_link,	sys___acl_aclcheck_link),	// 428
   //!sigwait								   429
   // thr_create							   430
   BSDX_(__NR_thr_exit,			sys_thr_exit),			// 431

   BSDXY(__NR_thr_self, 		sys_thr_self),			// 432
   BSDXY(__NR_thr_kill,                 sys_thr_kill),			// 433
   BSDXY(__NR__umtx_lock,		sys__umtx_lock),		// 434
   BSDXY(__NR__umtx_unlock,		sys__umtx_unlock),		// 435

   // jail_attach							   436
   // extattr_list_fd							   437
   // extattr_list_file							   438
   // extattr_list_link							   439

   // kse_switchin							   440
   // ksem_timedwait							   441
   // thr_suspend							   442
   // thr_wake								   443

   // kldunloadf							   444
   // audit								   445
   // auditon								   446
   // getauid								   447

   // setauid								   448
   // getaudit								   449
   // setaudit								   450
   // getaudit_addr							   451

   // setaudit_addr							   452
   // auditctl								   453
   BSDXY(__NR__umtx_op,			sys__umtx_op),			// 454
   BSDX_(__NR_thr_new,			sys_thr_new),			// 455

   // sigqueue								   456
   // kmq_open								   457
   // kmq_setattr							   458
   // kmq_timedreceive							   459

   // kmq_timedsend							   460
   // kmq_notify							   461
   // kmq_unlink							   462
   // abort2								   463

   BSDX_(__NR_thr_set_name,		sys_thr_set_name),		// 464
   // aio_fsync								   465
   BSDXY(__NR_rtprio_thread,		sys_rtprio_thread),		// 466
   // nosys								   467

   // nosys								   468
   // __getpath_fromfd							   469
   // __getpath_fromaddr						   470
   // sctp_peeloff							   471

   // sctp_generic_sendmsg						   472
   // sctp_generic_sendmsg_iov						   473
   // sctp_generic_recvmsg						   474
   BSDXY(__NR_pread7,			sys_pread7),			// 475

   BSDX_(__NR_pwrite7,			sys_pwrite7),			// 476
   BSDX_(__NR_mmap,			sys_mmap7),			// 477
   BSDX_(__NR_lseek,			sys_lseek7),			// 478
   BSDX_(__NR_truncate7,		sys_truncate7),			// 479

   BSDX_(__NR_ftruncate7,		sys_ftruncate7),		// 480
   BSDXY(__NR_thr_kill2,                sys_thr_kill2),			// 481
   // shm_open								   482
   // shm_unlink							   483

   // cpuset								   484
   // cpuset_setid							   485
   // cpuset_getid							   486
   // cpuset_getaffinity						   487

   // cpuset_setaffinity						   488
   BSDX_(__NR_faccessat,		sys_faccessat),			// 489
   BSDX_(__NR_fchmodat,			sys_fchmodat),			// 490
   BSDX_(__NR_fchownat,			sys_fchownat),			// 491

   // fexecve								   492
   BSDXY(__NR_fstatat,			sys_fstatat),			// 493
   BSDX_(__NR_futimesat,		sys_futimesat),			// 494
   BSDX_(__NR_linkat,			sys_linkat),			// 495

   BSDX_(__NR_mkdirat,			sys_mkdirat),			// 496
   BSDX_(__NR_mkfifoat,			sys_mkfifoat),			// 497
   BSDX_(__NR_mknodat,			sys_mknodat),			// 498
   BSDXY(__NR_openat,			sys_openat),			// 499

   BSDX_(__NR_readlinkat,		sys_readlinkat),		// 500
   BSDX_(__NR_renameat,			sys_renameat),			// 501
   BSDX_(__NR_symlinkat,		sys_symlinkat),			// 502
   BSDX_(__NR_unlinkat,			sys_unlinkat),			// 503

   // posix_openpt							   504

   BSDXY(__NR___semctl,			sys___semctl),			// 510


};

const UInt ML_(syscall_table_size) =
	    sizeof(ML_(syscall_table)) / sizeof(ML_(syscall_table)[0]);

/*--------------------------------------------------------------------*/
/*--- end                                                          ---*/
/*--------------------------------------------------------------------*/
